Add new debug option for http
This commit is contained in:
parent
0ba34fe80f
commit
0290a42d07
39 changed files with 293 additions and 189 deletions
4
go.mod
4
go.mod
|
|
@ -10,13 +10,12 @@ require (
|
||||||
github.com/gliderlabs/ssh v0.3.5
|
github.com/gliderlabs/ssh v0.3.5
|
||||||
github.com/gorilla/csrf v1.7.2
|
github.com/gorilla/csrf v1.7.2
|
||||||
github.com/gorilla/sessions v1.2.2
|
github.com/gorilla/sessions v1.2.2
|
||||||
github.com/gorilla/websocket v1.5.1
|
|
||||||
github.com/julienschmidt/httprouter v1.3.0
|
github.com/julienschmidt/httprouter v1.3.0
|
||||||
github.com/pkg/errors v0.9.1
|
github.com/pkg/errors v0.9.1
|
||||||
github.com/pquerna/otp v1.4.0
|
github.com/pquerna/otp v1.4.0
|
||||||
github.com/rs/zerolog v1.31.0
|
github.com/rs/zerolog v1.31.0
|
||||||
github.com/tkw1536/goprogram v0.5.0
|
github.com/tkw1536/goprogram v0.5.0
|
||||||
github.com/tkw1536/pkglib v0.0.0-20231114141909-8837d3186025
|
github.com/tkw1536/pkglib v0.0.0-20231122155813-969c635025aa
|
||||||
github.com/yuin/goldmark v1.6.0
|
github.com/yuin/goldmark v1.6.0
|
||||||
github.com/yuin/goldmark-meta v1.1.0
|
github.com/yuin/goldmark-meta v1.1.0
|
||||||
golang.org/x/crypto v0.15.0
|
golang.org/x/crypto v0.15.0
|
||||||
|
|
@ -42,6 +41,7 @@ require (
|
||||||
github.com/go-sql-driver/mysql v1.7.1 // indirect
|
github.com/go-sql-driver/mysql v1.7.1 // indirect
|
||||||
github.com/gogo/protobuf v1.3.2 // indirect
|
github.com/gogo/protobuf v1.3.2 // indirect
|
||||||
github.com/gorilla/securecookie v1.1.2 // indirect
|
github.com/gorilla/securecookie v1.1.2 // indirect
|
||||||
|
github.com/gorilla/websocket v1.5.1 // indirect
|
||||||
github.com/gosuri/uilive v0.0.4 // indirect
|
github.com/gosuri/uilive v0.0.4 // indirect
|
||||||
github.com/imdario/mergo v0.3.16 // indirect
|
github.com/imdario/mergo v0.3.16 // indirect
|
||||||
github.com/jessevdk/go-flags v1.5.0 // indirect
|
github.com/jessevdk/go-flags v1.5.0 // indirect
|
||||||
|
|
|
||||||
29
go.sum
29
go.sum
|
|
@ -13,8 +13,6 @@ github.com/anmitsu/go-shlex v0.0.0-20200514113438-38f4b401e2be/go.mod h1:ySMOLuW
|
||||||
github.com/boombuler/barcode v1.0.1-0.20190219062509-6c824513bacc/go.mod h1:paBWMcWSl3LHKBqUq+rly7CNSldXjb2rDl3JlRe0mD8=
|
github.com/boombuler/barcode v1.0.1-0.20190219062509-6c824513bacc/go.mod h1:paBWMcWSl3LHKBqUq+rly7CNSldXjb2rDl3JlRe0mD8=
|
||||||
github.com/boombuler/barcode v1.0.1 h1:NDBbPmhS+EqABEs5Kg3n/5ZNjy73Pz7SIV+KCeqyXcs=
|
github.com/boombuler/barcode v1.0.1 h1:NDBbPmhS+EqABEs5Kg3n/5ZNjy73Pz7SIV+KCeqyXcs=
|
||||||
github.com/boombuler/barcode v1.0.1/go.mod h1:paBWMcWSl3LHKBqUq+rly7CNSldXjb2rDl3JlRe0mD8=
|
github.com/boombuler/barcode v1.0.1/go.mod h1:paBWMcWSl3LHKBqUq+rly7CNSldXjb2rDl3JlRe0mD8=
|
||||||
github.com/compose-spec/compose-go v1.20.0 h1:h4ZKOst1EF/DwZp7dWkb+wbTVE4nEyT9Lc89to84Ol4=
|
|
||||||
github.com/compose-spec/compose-go v1.20.0/go.mod h1:+MdqXV4RA7wdFsahh/Kb8U0pAJqkg7mr4PM9tFKU8RM=
|
|
||||||
github.com/compose-spec/compose-go v1.20.1 h1:I6gCMGLl96kEf8XZwaozeTwnNfxA2eVsO46W+5ciTEg=
|
github.com/compose-spec/compose-go v1.20.1 h1:I6gCMGLl96kEf8XZwaozeTwnNfxA2eVsO46W+5ciTEg=
|
||||||
github.com/compose-spec/compose-go v1.20.1/go.mod h1:+MdqXV4RA7wdFsahh/Kb8U0pAJqkg7mr4PM9tFKU8RM=
|
github.com/compose-spec/compose-go v1.20.1/go.mod h1:+MdqXV4RA7wdFsahh/Kb8U0pAJqkg7mr4PM9tFKU8RM=
|
||||||
github.com/coreos/go-systemd/v22 v22.5.0/go.mod h1:Y58oyj3AT4RCenI/lSvhwexgC+NSVTIJ3seZv2GcEnc=
|
github.com/coreos/go-systemd/v22 v22.5.0/go.mod h1:Y58oyj3AT4RCenI/lSvhwexgC+NSVTIJ3seZv2GcEnc=
|
||||||
|
|
@ -48,11 +46,8 @@ github.com/google/gofuzz v1.2.0 h1:xRy4A+RhZaiKjJ1bPfwQ8sedCA+YS2YcCHW6ec7JMi0=
|
||||||
github.com/google/gofuzz v1.2.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg=
|
github.com/google/gofuzz v1.2.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg=
|
||||||
github.com/gorilla/csrf v1.7.2 h1:oTUjx0vyf2T+wkrx09Trsev1TE+/EbDAeHtSTbtC2eI=
|
github.com/gorilla/csrf v1.7.2 h1:oTUjx0vyf2T+wkrx09Trsev1TE+/EbDAeHtSTbtC2eI=
|
||||||
github.com/gorilla/csrf v1.7.2/go.mod h1:F1Fj3KG23WYHE6gozCmBAezKookxbIvUJT+121wTuLk=
|
github.com/gorilla/csrf v1.7.2/go.mod h1:F1Fj3KG23WYHE6gozCmBAezKookxbIvUJT+121wTuLk=
|
||||||
github.com/gorilla/securecookie v1.1.1/go.mod h1:ra0sb63/xPlUeL+yeDciTfxMRAA+MP+HVt/4epWDjd4=
|
|
||||||
github.com/gorilla/securecookie v1.1.2 h1:YCIWL56dvtr73r6715mJs5ZvhtnY73hBvEF8kXD8ePA=
|
github.com/gorilla/securecookie v1.1.2 h1:YCIWL56dvtr73r6715mJs5ZvhtnY73hBvEF8kXD8ePA=
|
||||||
github.com/gorilla/securecookie v1.1.2/go.mod h1:NfCASbcHqRSY+3a8tlWJwsQap2VX5pwzwo4h3eOamfo=
|
github.com/gorilla/securecookie v1.1.2/go.mod h1:NfCASbcHqRSY+3a8tlWJwsQap2VX5pwzwo4h3eOamfo=
|
||||||
github.com/gorilla/sessions v1.2.1 h1:DHd3rPN5lE3Ts3D8rKkQ8x/0kqfeNmBAaiSi+o7FsgI=
|
|
||||||
github.com/gorilla/sessions v1.2.1/go.mod h1:dk2InVEVJ0sfLlnXv9EAgkf6ecYs/i80K/zI+bUmuGM=
|
|
||||||
github.com/gorilla/sessions v1.2.2 h1:lqzMYz6bOfvn2WriPUjNByzeXIlVzURcPmgMczkmTjY=
|
github.com/gorilla/sessions v1.2.2 h1:lqzMYz6bOfvn2WriPUjNByzeXIlVzURcPmgMczkmTjY=
|
||||||
github.com/gorilla/sessions v1.2.2/go.mod h1:ePLdVu+jbEgHH+KWw8I1z2wqd0BAdAQh/8LRvBeoNcQ=
|
github.com/gorilla/sessions v1.2.2/go.mod h1:ePLdVu+jbEgHH+KWw8I1z2wqd0BAdAQh/8LRvBeoNcQ=
|
||||||
github.com/gorilla/websocket v1.5.1 h1:gmztn0JnHVt9JZquRuzLw3g4wouNVzKL15iLr/zn/QY=
|
github.com/gorilla/websocket v1.5.1 h1:gmztn0JnHVt9JZquRuzLw3g4wouNVzKL15iLr/zn/QY=
|
||||||
|
|
@ -124,10 +119,10 @@ github.com/tdewolff/test v1.0.7 h1:8Vs0142DmPFW/bQeHRP3MV19m1gvndjUb1sn8yy74LM=
|
||||||
github.com/tdewolff/test v1.0.7/go.mod h1:6DAvZliBAAnD7rhVgwaM7DE5/d9NMOAJ09SqYqeK4QE=
|
github.com/tdewolff/test v1.0.7/go.mod h1:6DAvZliBAAnD7rhVgwaM7DE5/d9NMOAJ09SqYqeK4QE=
|
||||||
github.com/tkw1536/goprogram v0.5.0 h1:7vcIjmMdcZPJyRhgdlCaGfHAoOG3oYlFrno1pWXy1Bs=
|
github.com/tkw1536/goprogram v0.5.0 h1:7vcIjmMdcZPJyRhgdlCaGfHAoOG3oYlFrno1pWXy1Bs=
|
||||||
github.com/tkw1536/goprogram v0.5.0/go.mod h1:MDCwqLmvcc2QryMm6oSC9h/QAdE9PewZ2Mp2Lm7MmAg=
|
github.com/tkw1536/goprogram v0.5.0/go.mod h1:MDCwqLmvcc2QryMm6oSC9h/QAdE9PewZ2Mp2Lm7MmAg=
|
||||||
github.com/tkw1536/pkglib v0.0.0-20231110192201-b920fd9f7764 h1:rJStxc6PoFUQcsRRqoUNtaM80GZWT69WfWeA+EDbvXM=
|
github.com/tkw1536/pkglib v0.0.0-20231121123232-879eff5cea2d h1:J8EvqdNY/qJpn8qoYkxtHx+Uag6sbHxgXNClt6S3Zqc=
|
||||||
github.com/tkw1536/pkglib v0.0.0-20231110192201-b920fd9f7764/go.mod h1:Qi/vpuxuxo5D40O9jLUSmcUF01B5LmJqDxs8o8Lc6bg=
|
github.com/tkw1536/pkglib v0.0.0-20231121123232-879eff5cea2d/go.mod h1:Qi/vpuxuxo5D40O9jLUSmcUF01B5LmJqDxs8o8Lc6bg=
|
||||||
github.com/tkw1536/pkglib v0.0.0-20231114141909-8837d3186025 h1:t3ewoi0rdqQo0a8zFFpmtsUi+O4C+kCYoOM/QkXV7b0=
|
github.com/tkw1536/pkglib v0.0.0-20231122155813-969c635025aa h1:HQxorKzWcH3D0In/G6Y24IT9KVVcGjeJGcZzN0T3b30=
|
||||||
github.com/tkw1536/pkglib v0.0.0-20231114141909-8837d3186025/go.mod h1:Qi/vpuxuxo5D40O9jLUSmcUF01B5LmJqDxs8o8Lc6bg=
|
github.com/tkw1536/pkglib v0.0.0-20231122155813-969c635025aa/go.mod h1:Qi/vpuxuxo5D40O9jLUSmcUF01B5LmJqDxs8o8Lc6bg=
|
||||||
github.com/xeipuuv/gojsonpointer v0.0.0-20180127040702-4e3ac2762d5f/go.mod h1:N2zxlSyiKSe5eX1tZViRH5QA0qijqEDrYZiPEAiq3wU=
|
github.com/xeipuuv/gojsonpointer v0.0.0-20180127040702-4e3ac2762d5f/go.mod h1:N2zxlSyiKSe5eX1tZViRH5QA0qijqEDrYZiPEAiq3wU=
|
||||||
github.com/xeipuuv/gojsonpointer v0.0.0-20190905194746-02993c407bfb h1:zGWFAtiMcyryUHoUjUJX0/lt1H2+i2Ka2n+D3DImSNo=
|
github.com/xeipuuv/gojsonpointer v0.0.0-20190905194746-02993c407bfb h1:zGWFAtiMcyryUHoUjUJX0/lt1H2+i2Ka2n+D3DImSNo=
|
||||||
github.com/xeipuuv/gojsonpointer v0.0.0-20190905194746-02993c407bfb/go.mod h1:N2zxlSyiKSe5eX1tZViRH5QA0qijqEDrYZiPEAiq3wU=
|
github.com/xeipuuv/gojsonpointer v0.0.0-20190905194746-02993c407bfb/go.mod h1:N2zxlSyiKSe5eX1tZViRH5QA0qijqEDrYZiPEAiq3wU=
|
||||||
|
|
@ -145,18 +140,12 @@ golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACk
|
||||||
golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
|
golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
|
||||||
golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
|
golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
|
||||||
golang.org/x/crypto v0.0.0-20220826181053-bd7e27e6170d/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4=
|
golang.org/x/crypto v0.0.0-20220826181053-bd7e27e6170d/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4=
|
||||||
golang.org/x/crypto v0.14.0 h1:wBqGXzWJW6m1XrIKlAH0Hs1JJ7+9KBwnIO8v66Q9cHc=
|
|
||||||
golang.org/x/crypto v0.14.0/go.mod h1:MVFd36DqK4CsrnJYDkBA3VC4m2GkXAM0PvzMCn4JQf4=
|
|
||||||
golang.org/x/crypto v0.15.0 h1:frVn1TEaCEaZcn3Tmd7Y2b5KKPaZ+I32Q2OA3kYp5TA=
|
golang.org/x/crypto v0.15.0 h1:frVn1TEaCEaZcn3Tmd7Y2b5KKPaZ+I32Q2OA3kYp5TA=
|
||||||
golang.org/x/crypto v0.15.0/go.mod h1:4ChreQoLWfG3xLDer1WdlH5NdlQ3+mwnQq1YTKY+72g=
|
golang.org/x/crypto v0.15.0/go.mod h1:4ChreQoLWfG3xLDer1WdlH5NdlQ3+mwnQq1YTKY+72g=
|
||||||
golang.org/x/exp v0.0.0-20231006140011-7918f672742d h1:jtJma62tbqLibJ5sFQz8bKtEM8rJBtfilJ2qTU199MI=
|
|
||||||
golang.org/x/exp v0.0.0-20231006140011-7918f672742d/go.mod h1:ldy0pHrwJyGW56pPQzzkH36rKxoZW1tw7ZJpeKx+hdo=
|
|
||||||
golang.org/x/exp v0.0.0-20231110203233-9a3e6036ecaa h1:FRnLl4eNAQl8hwxVVC17teOw8kdjVDVAiFMtgUdTSRQ=
|
golang.org/x/exp v0.0.0-20231110203233-9a3e6036ecaa h1:FRnLl4eNAQl8hwxVVC17teOw8kdjVDVAiFMtgUdTSRQ=
|
||||||
golang.org/x/exp v0.0.0-20231110203233-9a3e6036ecaa/go.mod h1:zk2irFbV9DP96SEBUUAy67IdHUaZuSnrz1n472HUCLE=
|
golang.org/x/exp v0.0.0-20231110203233-9a3e6036ecaa/go.mod h1:zk2irFbV9DP96SEBUUAy67IdHUaZuSnrz1n472HUCLE=
|
||||||
golang.org/x/mod v0.2.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
|
golang.org/x/mod v0.2.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
|
||||||
golang.org/x/mod v0.3.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
|
golang.org/x/mod v0.3.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
|
||||||
golang.org/x/mod v0.13.0 h1:I/DsJXRlw/8l/0c24sM9yb0T4z9liZTduXvdAWYiysY=
|
|
||||||
golang.org/x/mod v0.13.0/go.mod h1:hTbmBsO62+eylJbnUtE2MGJUyE7QWk4xUqPFrRgJ+7c=
|
|
||||||
golang.org/x/mod v0.14.0 h1:dGoOF9QVLYng8IHTm7BAyWqCqSheQ5pYWGhzW00YJr0=
|
golang.org/x/mod v0.14.0 h1:dGoOF9QVLYng8IHTm7BAyWqCqSheQ5pYWGhzW00YJr0=
|
||||||
golang.org/x/mod v0.14.0/go.mod h1:hTbmBsO62+eylJbnUtE2MGJUyE7QWk4xUqPFrRgJ+7c=
|
golang.org/x/mod v0.14.0/go.mod h1:hTbmBsO62+eylJbnUtE2MGJUyE7QWk4xUqPFrRgJ+7c=
|
||||||
golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
|
golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
|
||||||
|
|
@ -165,15 +154,11 @@ golang.org/x/net v0.0.0-20200226121028-0de0cce0169b/go.mod h1:z5CRVTTTmAJ677TzLL
|
||||||
golang.org/x/net v0.0.0-20201021035429-f5854403a974/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU=
|
golang.org/x/net v0.0.0-20201021035429-f5854403a974/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU=
|
||||||
golang.org/x/net v0.0.0-20211112202133-69e39bad7dc2/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y=
|
golang.org/x/net v0.0.0-20211112202133-69e39bad7dc2/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y=
|
||||||
golang.org/x/net v0.0.0-20220826154423-83b083e8dc8b/go.mod h1:YDH+HFinaLZZlnHAfSS6ZXJJ9M9t4Dl22yv3iI2vPwk=
|
golang.org/x/net v0.0.0-20220826154423-83b083e8dc8b/go.mod h1:YDH+HFinaLZZlnHAfSS6ZXJJ9M9t4Dl22yv3iI2vPwk=
|
||||||
golang.org/x/net v0.17.0 h1:pVaXccu2ozPjCXewfr1S7xza/zcXTity9cCdXQYSjIM=
|
|
||||||
golang.org/x/net v0.17.0/go.mod h1:NxSsAGuq816PNPmqtQdLE42eU2Fs7NoRIZrHJAlaCOE=
|
|
||||||
golang.org/x/net v0.18.0 h1:mIYleuAkSbHh0tCv7RvjL3F6ZVbLjq4+R7zbOn3Kokg=
|
golang.org/x/net v0.18.0 h1:mIYleuAkSbHh0tCv7RvjL3F6ZVbLjq4+R7zbOn3Kokg=
|
||||||
golang.org/x/net v0.18.0/go.mod h1:/czyP5RqHAH4odGYxBJ1qz0+CE5WZ+2j1YgoEo8F2jQ=
|
golang.org/x/net v0.18.0/go.mod h1:/czyP5RqHAH4odGYxBJ1qz0+CE5WZ+2j1YgoEo8F2jQ=
|
||||||
golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||||
golang.org/x/sync v0.0.0-20190911185100-cd5d95a43a6e/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
golang.org/x/sync v0.0.0-20190911185100-cd5d95a43a6e/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||||
golang.org/x/sync v0.0.0-20201020160332-67f06af15bc9/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
golang.org/x/sync v0.0.0-20201020160332-67f06af15bc9/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||||
golang.org/x/sync v0.4.0 h1:zxkM55ReGkDlKSM+Fu41A+zmbZuaPVbGMzvvdUPznYQ=
|
|
||||||
golang.org/x/sync v0.4.0/go.mod h1:FU7BRWz2tNW+3quACPkgCx/L+uEAv1htQ0V83Z9Rj+Y=
|
|
||||||
golang.org/x/sync v0.5.0 h1:60k92dhOjHxJkrqnwsfl8KuaHbn/5dl0lUPUklKo3qE=
|
golang.org/x/sync v0.5.0 h1:60k92dhOjHxJkrqnwsfl8KuaHbn/5dl0lUPUklKo3qE=
|
||||||
golang.org/x/sync v0.5.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk=
|
golang.org/x/sync v0.5.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk=
|
||||||
golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
||||||
|
|
@ -194,16 +179,12 @@ golang.org/x/sys v0.14.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
|
||||||
golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo=
|
golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo=
|
||||||
golang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8=
|
golang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8=
|
||||||
golang.org/x/term v0.0.0-20220722155259-a9ba230a4035/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8=
|
golang.org/x/term v0.0.0-20220722155259-a9ba230a4035/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8=
|
||||||
golang.org/x/term v0.13.0 h1:bb+I9cTfFazGW51MZqBVmZy7+JEJMouUHTUSKVQLBek=
|
|
||||||
golang.org/x/term v0.13.0/go.mod h1:LTmsnFJwVN6bCy1rVCoS+qHT1HhALEFxKncY3WNNh4U=
|
|
||||||
golang.org/x/term v0.14.0 h1:LGK9IlZ8T9jvdy6cTdfKUCltatMFOehAQo9SRC46UQ8=
|
golang.org/x/term v0.14.0 h1:LGK9IlZ8T9jvdy6cTdfKUCltatMFOehAQo9SRC46UQ8=
|
||||||
golang.org/x/term v0.14.0/go.mod h1:TySc+nGkYR6qt8km8wUhuFRTVSMIX3XPR58y2lC8vww=
|
golang.org/x/term v0.14.0/go.mod h1:TySc+nGkYR6qt8km8wUhuFRTVSMIX3XPR58y2lC8vww=
|
||||||
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
|
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
|
||||||
golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
|
golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
|
||||||
golang.org/x/text v0.3.6/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
|
golang.org/x/text v0.3.6/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
|
||||||
golang.org/x/text v0.3.7/go.mod h1:u+2+/6zg+i71rQMx5EYifcz6MCKuco9NR6JIITiCfzQ=
|
golang.org/x/text v0.3.7/go.mod h1:u+2+/6zg+i71rQMx5EYifcz6MCKuco9NR6JIITiCfzQ=
|
||||||
golang.org/x/text v0.13.0 h1:ablQoSUd0tRdKxZewP80B+BaqeKJuVhuRxj/dkrun3k=
|
|
||||||
golang.org/x/text v0.13.0/go.mod h1:TvPlkZtksWOMsz7fbANvkp4WM8x/WCo/om8BMLbz+aE=
|
|
||||||
golang.org/x/text v0.14.0 h1:ScX5w1eTa3QqT8oi6+ziP7dTV1S2+ALU0bI+0zXKWiQ=
|
golang.org/x/text v0.14.0 h1:ScX5w1eTa3QqT8oi6+ziP7dTV1S2+ALU0bI+0zXKWiQ=
|
||||||
golang.org/x/text v0.14.0/go.mod h1:18ZOQIKpY8NJVqYksKHtTdi31H5itFRjB5/qKTNYzSU=
|
golang.org/x/text v0.14.0/go.mod h1:18ZOQIKpY8NJVqYksKHtTdi31H5itFRjB5/qKTNYzSU=
|
||||||
golang.org/x/time v0.3.0 h1:rg5rLMjNzMS1RkNLzCG38eapWhnYLFYXDXj2gOlr8j4=
|
golang.org/x/time v0.3.0 h1:rg5rLMjNzMS1RkNLzCG38eapWhnYLFYXDXj2gOlr8j4=
|
||||||
|
|
@ -212,8 +193,6 @@ golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGm
|
||||||
golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
|
golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
|
||||||
golang.org/x/tools v0.0.0-20200619180055-7c47624df98f/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE=
|
golang.org/x/tools v0.0.0-20200619180055-7c47624df98f/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE=
|
||||||
golang.org/x/tools v0.0.0-20210106214847-113979e3529a/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA=
|
golang.org/x/tools v0.0.0-20210106214847-113979e3529a/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA=
|
||||||
golang.org/x/tools v0.14.0 h1:jvNa2pY0M4r62jkRQ6RwEZZyPcymeL9XZMLBbV7U2nc=
|
|
||||||
golang.org/x/tools v0.14.0/go.mod h1:uYBEerGOWcJyEORxN+Ek8+TT266gXkNlHdJBwexUsBg=
|
|
||||||
golang.org/x/tools v0.15.0 h1:zdAyfUGbYmuVokhzVmghFl2ZJh5QhcfebBgmVPFYA+8=
|
golang.org/x/tools v0.15.0 h1:zdAyfUGbYmuVokhzVmghFl2ZJh5QhcfebBgmVPFYA+8=
|
||||||
golang.org/x/tools v0.15.0/go.mod h1:hpksKq4dtpQWS1uQ61JkdqWM3LscIS6Slf+VVkm+wQk=
|
golang.org/x/tools v0.15.0/go.mod h1:hpksKq4dtpQWS1uQ61JkdqWM3LscIS6Slf+VVkm+wQk=
|
||||||
golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
||||||
|
|
|
||||||
|
|
@ -39,6 +39,11 @@ http:
|
||||||
# This email address can be configured here.
|
# This email address can be configured here.
|
||||||
certbot_email: null
|
certbot_email: null
|
||||||
|
|
||||||
|
# Debug determines if error messages should be written as html pages with stack traces to http clients.
|
||||||
|
# This potentially exposes sensitive information and may cause certain API responses to be of content type 'text/html' unexpectedly.
|
||||||
|
# It is not recommended to use this on production systems.
|
||||||
|
debug: null
|
||||||
|
|
||||||
# Serve the panel also on the toplevel domain, and not only on the "panel" domain.
|
# Serve the panel also on the toplevel domain, and not only on the "panel" domain.
|
||||||
# Enabled by default.
|
# Enabled by default.
|
||||||
panel: null
|
panel: null
|
||||||
|
|
|
||||||
|
|
@ -25,6 +25,10 @@ type HTTPConfig struct {
|
||||||
// This email address can be configured here.
|
// This email address can be configured here.
|
||||||
CertbotEmail string `yaml:"certbot_email" validate:"email"`
|
CertbotEmail string `yaml:"certbot_email" validate:"email"`
|
||||||
|
|
||||||
|
// Debug determines if error messages should be written as html pages with stack traces to http clients.
|
||||||
|
// This potentially exposes sensitive information and may cause certain API responses to be of content type 'text/html' unexpectedly.
|
||||||
|
Debug validators.NullableBool `yaml:"debug" validate:"bool" default:"false"`
|
||||||
|
|
||||||
// Also serve the panel on the toplevel domain.
|
// Also serve the panel on the toplevel domain.
|
||||||
// Note that the panel is *always* servered under the "panel" domain.
|
// Note that the panel is *always* servered under the "panel" domain.
|
||||||
// Disabling this is not recommended.
|
// Disabling this is not recommended.
|
||||||
|
|
|
||||||
|
|
@ -10,6 +10,7 @@ import (
|
||||||
"github.com/FAU-CDI/wisski-distillery/internal/dis/component/auth/policy"
|
"github.com/FAU-CDI/wisski-distillery/internal/dis/component/auth/policy"
|
||||||
"github.com/FAU-CDI/wisski-distillery/internal/dis/component/auth/scopes"
|
"github.com/FAU-CDI/wisski-distillery/internal/dis/component/auth/scopes"
|
||||||
"github.com/FAU-CDI/wisski-distillery/internal/dis/component/instances"
|
"github.com/FAU-CDI/wisski-distillery/internal/dis/component/instances"
|
||||||
|
"github.com/FAU-CDI/wisski-distillery/internal/dis/component/server/handling"
|
||||||
"github.com/FAU-CDI/wisski-distillery/internal/wisski"
|
"github.com/FAU-CDI/wisski-distillery/internal/wisski"
|
||||||
"github.com/FAU-CDI/wisski-distillery/internal/wisski/ingredient/php/users"
|
"github.com/FAU-CDI/wisski-distillery/internal/wisski/ingredient/php/users"
|
||||||
"github.com/tkw1536/pkglib/httpx"
|
"github.com/tkw1536/pkglib/httpx"
|
||||||
|
|
@ -21,6 +22,7 @@ type Next struct {
|
||||||
Auth *auth.Auth
|
Auth *auth.Auth
|
||||||
Policy *policy.Policy
|
Policy *policy.Policy
|
||||||
Instances *instances.Instances
|
Instances *instances.Instances
|
||||||
|
Handleing *handling.Handling
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -72,7 +74,7 @@ func (next *Next) getInstance(r *http.Request) (wisski *wisski.WissKI, path stri
|
||||||
}
|
}
|
||||||
|
|
||||||
func (next *Next) HandleRoute(ctx context.Context, path string) (http.Handler, error) {
|
func (next *Next) HandleRoute(ctx context.Context, path string) (http.Handler, error) {
|
||||||
return httpx.RedirectHandler(func(r *http.Request) (string, int, error) {
|
return next.dependencies.Handleing.Redirect(func(r *http.Request) (string, int, error) {
|
||||||
// get the instance and the path
|
// get the instance and the path
|
||||||
instance, path, err := next.getInstance(r)
|
instance, path, err := next.getInstance(r)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
|
|
||||||
|
|
@ -11,19 +11,23 @@ import (
|
||||||
"github.com/FAU-CDI/wisski-distillery/internal/dis/component/auth/scopes"
|
"github.com/FAU-CDI/wisski-distillery/internal/dis/component/auth/scopes"
|
||||||
"github.com/FAU-CDI/wisski-distillery/internal/dis/component/auth/tokens"
|
"github.com/FAU-CDI/wisski-distillery/internal/dis/component/auth/tokens"
|
||||||
"github.com/FAU-CDI/wisski-distillery/internal/dis/component/instances"
|
"github.com/FAU-CDI/wisski-distillery/internal/dis/component/instances"
|
||||||
|
"github.com/FAU-CDI/wisski-distillery/internal/dis/component/server/handling"
|
||||||
"github.com/FAU-CDI/wisski-distillery/internal/dis/component/server/templating"
|
"github.com/FAU-CDI/wisski-distillery/internal/dis/component/server/templating"
|
||||||
"github.com/FAU-CDI/wisski-distillery/internal/dis/component/ssh2"
|
"github.com/FAU-CDI/wisski-distillery/internal/dis/component/ssh2"
|
||||||
"github.com/FAU-CDI/wisski-distillery/internal/dis/component/ssh2/sshkeys"
|
"github.com/FAU-CDI/wisski-distillery/internal/dis/component/ssh2/sshkeys"
|
||||||
"github.com/FAU-CDI/wisski-distillery/internal/models"
|
"github.com/FAU-CDI/wisski-distillery/internal/models"
|
||||||
"github.com/julienschmidt/httprouter"
|
"github.com/julienschmidt/httprouter"
|
||||||
"github.com/tkw1536/pkglib/httpx"
|
"github.com/tkw1536/pkglib/httpx/form"
|
||||||
)
|
)
|
||||||
|
|
||||||
type UserPanel struct {
|
type UserPanel struct {
|
||||||
component.Base
|
component.Base
|
||||||
dependencies struct {
|
dependencies struct {
|
||||||
Auth *auth.Auth
|
Auth *auth.Auth
|
||||||
|
|
||||||
|
Handling *handling.Handling
|
||||||
Templating *templating.Templating
|
Templating *templating.Templating
|
||||||
|
|
||||||
Policy *policy.Policy
|
Policy *policy.Policy
|
||||||
Tokens *tokens.Tokens
|
Tokens *tokens.Tokens
|
||||||
Instances *instances.Instances
|
Instances *instances.Instances
|
||||||
|
|
@ -142,12 +146,12 @@ func (panel *UserPanel) HandleRoute(ctx context.Context, route string) (http.Han
|
||||||
|
|
||||||
type userFormContext struct {
|
type userFormContext struct {
|
||||||
templating.RuntimeFlags
|
templating.RuntimeFlags
|
||||||
httpx.FormContext
|
form.FormContext
|
||||||
|
|
||||||
User *models.User
|
User *models.User
|
||||||
}
|
}
|
||||||
|
|
||||||
func (panel *UserPanel) UserFormContext(tpl *templating.Template[userFormContext], last component.MenuItem, funcs ...templating.FlagFunc) func(ctx httpx.FormContext, r *http.Request) any {
|
func (panel *UserPanel) UserFormContext(tpl *templating.Template[userFormContext], last component.MenuItem, funcs ...templating.FlagFunc) func(ctx form.FormContext, r *http.Request) any {
|
||||||
funcs = append(funcs, func(flags templating.Flags, r *http.Request) templating.Flags {
|
funcs = append(funcs, func(flags templating.Flags, r *http.Request) templating.Flags {
|
||||||
// append the last menu item, and prepend the menuUser one!
|
// append the last menu item, and prepend the menuUser one!
|
||||||
flags.Crumbs = append(flags.Crumbs, last, last)
|
flags.Crumbs = append(flags.Crumbs, last, last)
|
||||||
|
|
@ -156,7 +160,7 @@ func (panel *UserPanel) UserFormContext(tpl *templating.Template[userFormContext
|
||||||
return flags
|
return flags
|
||||||
})
|
})
|
||||||
|
|
||||||
return func(ctx httpx.FormContext, r *http.Request) any {
|
return func(ctx form.FormContext, r *http.Request) any {
|
||||||
uctx := userFormContext{FormContext: ctx}
|
uctx := userFormContext{FormContext: ctx}
|
||||||
if user, err := panel.dependencies.Auth.UserOfSession(r); err == nil {
|
if user, err := panel.dependencies.Auth.UserOfSession(r); err == nil {
|
||||||
uctx.User = &user.User
|
uctx.User = &user.User
|
||||||
|
|
|
||||||
|
|
@ -9,14 +9,14 @@ import (
|
||||||
|
|
||||||
"github.com/FAU-CDI/wisski-distillery/internal/dis/component/server/assets"
|
"github.com/FAU-CDI/wisski-distillery/internal/dis/component/server/assets"
|
||||||
"github.com/FAU-CDI/wisski-distillery/internal/dis/component/server/templating"
|
"github.com/FAU-CDI/wisski-distillery/internal/dis/component/server/templating"
|
||||||
"github.com/tkw1536/pkglib/httpx"
|
"github.com/tkw1536/pkglib/httpx/form"
|
||||||
"github.com/tkw1536/pkglib/httpx/field"
|
"github.com/tkw1536/pkglib/httpx/form/field"
|
||||||
)
|
)
|
||||||
|
|
||||||
//go:embed "templates/password.html"
|
//go:embed "templates/password.html"
|
||||||
var passwordHTML []byte
|
var passwordHTML []byte
|
||||||
var passwordTemplate = templating.Parse[userFormContext](
|
var passwordTemplate = templating.Parse[userFormContext](
|
||||||
"password.html", passwordHTML, httpx.FormTemplate,
|
"password.html", passwordHTML, form.FormTemplate,
|
||||||
|
|
||||||
templating.Title("Change Password"),
|
templating.Title("Change Password"),
|
||||||
templating.Assets(assets.AssetsUser),
|
templating.Assets(assets.AssetsUser),
|
||||||
|
|
@ -34,17 +34,17 @@ var (
|
||||||
func (panel *UserPanel) routePassword(ctx context.Context) http.Handler {
|
func (panel *UserPanel) routePassword(ctx context.Context) http.Handler {
|
||||||
tpl := passwordTemplate.Prepare(panel.dependencies.Templating)
|
tpl := passwordTemplate.Prepare(panel.dependencies.Templating)
|
||||||
|
|
||||||
return &httpx.Form[struct{}]{
|
return &form.Form[struct{}]{
|
||||||
Fields: []field.Field{
|
Fields: []field.Field{
|
||||||
{Name: "old", Type: field.Password, Autocomplete: field.CurrentPassword, EmptyOnError: true, Label: "Current Password"},
|
{Name: "old", Type: field.Password, Autocomplete: field.CurrentPassword, EmptyOnError: true, Label: "Current Password"},
|
||||||
{Name: "otp", Type: field.Text, Autocomplete: field.OneTimeCode, EmptyOnError: true, Label: "Current Passcode (optional)"},
|
{Name: "otp", Type: field.Text, Autocomplete: field.OneTimeCode, EmptyOnError: true, Label: "Current Passcode (optional)"},
|
||||||
{Name: "new", Type: field.Password, Autocomplete: field.NewPassword, EmptyOnError: true, Label: "New Password"},
|
{Name: "new", Type: field.Password, Autocomplete: field.NewPassword, EmptyOnError: true, Label: "New Password"},
|
||||||
{Name: "new2", Type: field.Password, Autocomplete: field.NewPassword, EmptyOnError: true, Label: "New Password (again)"},
|
{Name: "new2", Type: field.Password, Autocomplete: field.NewPassword, EmptyOnError: true, Label: "New Password (again)"},
|
||||||
},
|
},
|
||||||
FieldTemplate: field.PureCSSFieldTemplate,
|
FieldTemplate: assets.PureCSSFieldTemplate,
|
||||||
|
|
||||||
RenderTemplate: tpl.Template(),
|
Template: tpl.Template(),
|
||||||
RenderTemplateContext: panel.UserFormContext(tpl, menuChangePassword),
|
TemplateContext: panel.UserFormContext(tpl, menuChangePassword),
|
||||||
|
|
||||||
Validate: func(r *http.Request, values map[string]string) (struct{}, error) {
|
Validate: func(r *http.Request, values map[string]string) (struct{}, error) {
|
||||||
old, passcode, new, new2 := values["old"], values["otp"], values["new"], values["new2"]
|
old, passcode, new, new2 := values["old"], values["otp"], values["new"], values["new2"]
|
||||||
|
|
@ -82,7 +82,7 @@ func (panel *UserPanel) routePassword(ctx context.Context) http.Handler {
|
||||||
return struct{}{}, nil
|
return struct{}{}, nil
|
||||||
},
|
},
|
||||||
|
|
||||||
RenderSuccess: func(_ struct{}, values map[string]string, w http.ResponseWriter, r *http.Request) error {
|
Success: func(_ struct{}, values map[string]string, w http.ResponseWriter, r *http.Request) error {
|
||||||
return errPasswordSet
|
return errPasswordSet
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -13,7 +13,8 @@ import (
|
||||||
"github.com/gliderlabs/ssh"
|
"github.com/gliderlabs/ssh"
|
||||||
"github.com/rs/zerolog"
|
"github.com/rs/zerolog"
|
||||||
"github.com/tkw1536/pkglib/httpx"
|
"github.com/tkw1536/pkglib/httpx"
|
||||||
"github.com/tkw1536/pkglib/httpx/field"
|
"github.com/tkw1536/pkglib/httpx/form"
|
||||||
|
"github.com/tkw1536/pkglib/httpx/form/field"
|
||||||
|
|
||||||
gossh "golang.org/x/crypto/ssh"
|
gossh "golang.org/x/crypto/ssh"
|
||||||
|
|
||||||
|
|
@ -57,7 +58,7 @@ func (panel *UserPanel) sshRoute(ctx context.Context) http.Handler {
|
||||||
),
|
),
|
||||||
)
|
)
|
||||||
|
|
||||||
return tpl.HTMLHandler(func(r *http.Request) (sc SSHTemplateContext, err error) {
|
return tpl.HTMLHandler(panel.dependencies.Handling, func(r *http.Request) (sc SSHTemplateContext, err error) {
|
||||||
user, err := panel.dependencies.Auth.UserOfSession(r)
|
user, err := panel.dependencies.Auth.UserOfSession(r)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return sc, err
|
return sc, err
|
||||||
|
|
@ -129,7 +130,7 @@ func (panel *UserPanel) sshDeleteRoute(ctx context.Context) http.Handler {
|
||||||
//go:embed "templates/ssh_add.html"
|
//go:embed "templates/ssh_add.html"
|
||||||
var sshAddHTML []byte
|
var sshAddHTML []byte
|
||||||
var sshAddTemplate = templating.ParseForm(
|
var sshAddTemplate = templating.ParseForm(
|
||||||
"ssh_add.html", sshAddHTML, httpx.FormTemplate,
|
"ssh_add.html", sshAddHTML, form.FormTemplate,
|
||||||
templating.Title("Add SSH Key"),
|
templating.Title("Add SSH Key"),
|
||||||
templating.Assets(assets.AssetsUser),
|
templating.Assets(assets.AssetsUser),
|
||||||
)
|
)
|
||||||
|
|
@ -150,15 +151,15 @@ func (panel *UserPanel) sshAddRoute(ctx context.Context) http.Handler {
|
||||||
),
|
),
|
||||||
)
|
)
|
||||||
|
|
||||||
return &httpx.Form[addKeyResult]{
|
return &form.Form[addKeyResult]{
|
||||||
Fields: []field.Field{
|
Fields: []field.Field{
|
||||||
{Name: "comment", Type: field.Text, Label: "Comment"},
|
{Name: "comment", Type: field.Text, Label: "Comment"},
|
||||||
{Name: "key", Type: field.Textarea, Label: "Key in authorized_keys format"}, // has hacked css!
|
{Name: "key", Type: field.Textarea, Label: "Key in authorized_keys format"}, // has hacked css!
|
||||||
},
|
},
|
||||||
FieldTemplate: field.PureCSSFieldTemplate,
|
FieldTemplate: assets.PureCSSFieldTemplate,
|
||||||
|
|
||||||
RenderTemplate: tpl.Template(),
|
Template: tpl.Template(),
|
||||||
RenderTemplateContext: templating.FormTemplateContext(tpl),
|
TemplateContext: templating.FormTemplateContext(tpl),
|
||||||
|
|
||||||
Validate: func(r *http.Request, values map[string]string) (ak addKeyResult, err error) {
|
Validate: func(r *http.Request, values map[string]string) (ak addKeyResult, err error) {
|
||||||
ak.User, err = panel.dependencies.Auth.UserOfSession(r)
|
ak.User, err = panel.dependencies.Auth.UserOfSession(r)
|
||||||
|
|
@ -181,7 +182,7 @@ func (panel *UserPanel) sshAddRoute(ctx context.Context) http.Handler {
|
||||||
return ak, nil
|
return ak, nil
|
||||||
},
|
},
|
||||||
|
|
||||||
RenderSuccess: func(ak addKeyResult, values map[string]string, w http.ResponseWriter, r *http.Request) error {
|
Success: func(ak addKeyResult, values map[string]string, w http.ResponseWriter, r *http.Request) error {
|
||||||
// add the key to the user
|
// add the key to the user
|
||||||
if err := panel.dependencies.Keys.Add(r.Context(), ak.User.User.User, ak.Comment, ak.Key); err != nil {
|
if err := panel.dependencies.Keys.Add(r.Context(), ak.User.User.User, ak.Comment, ak.Key); err != nil {
|
||||||
return errAddKey
|
return errAddKey
|
||||||
|
|
|
||||||
|
|
@ -11,7 +11,8 @@ import (
|
||||||
"github.com/FAU-CDI/wisski-distillery/internal/models"
|
"github.com/FAU-CDI/wisski-distillery/internal/models"
|
||||||
"github.com/rs/zerolog"
|
"github.com/rs/zerolog"
|
||||||
"github.com/tkw1536/pkglib/httpx"
|
"github.com/tkw1536/pkglib/httpx"
|
||||||
"github.com/tkw1536/pkglib/httpx/field"
|
"github.com/tkw1536/pkglib/httpx/form"
|
||||||
|
"github.com/tkw1536/pkglib/httpx/form/field"
|
||||||
|
|
||||||
_ "embed"
|
_ "embed"
|
||||||
)
|
)
|
||||||
|
|
@ -44,7 +45,7 @@ func (panel *UserPanel) tokensRoute(ctx context.Context) http.Handler {
|
||||||
),
|
),
|
||||||
)
|
)
|
||||||
|
|
||||||
return tpl.HTMLHandler(func(r *http.Request) (tc TokenTemplateContext, err error) {
|
return tpl.HTMLHandler(panel.dependencies.Handling, func(r *http.Request) (tc TokenTemplateContext, err error) {
|
||||||
// list the user
|
// list the user
|
||||||
user, err := panel.dependencies.Auth.UserOfSession(r)
|
user, err := panel.dependencies.Auth.UserOfSession(r)
|
||||||
if err != nil || user == nil {
|
if err != nil || user == nil {
|
||||||
|
|
@ -94,7 +95,7 @@ func (panel *UserPanel) tokensDeleteRoute(ctx context.Context) http.Handler {
|
||||||
//go:embed "templates/tokens_add.html"
|
//go:embed "templates/tokens_add.html"
|
||||||
var tokensAddHTML []byte
|
var tokensAddHTML []byte
|
||||||
var tokensAddTemplate = templating.ParseForm(
|
var tokensAddTemplate = templating.ParseForm(
|
||||||
"tokens_add.html", tokensAddHTML, httpx.FormTemplate,
|
"tokens_add.html", tokensAddHTML, form.FormTemplate,
|
||||||
templating.Title("Add Token"),
|
templating.Title("Add Token"),
|
||||||
templating.Assets(assets.AssetsUser),
|
templating.Assets(assets.AssetsUser),
|
||||||
)
|
)
|
||||||
|
|
@ -108,7 +109,7 @@ type addTokenResult struct {
|
||||||
//go:embed "templates/token_created.html"
|
//go:embed "templates/token_created.html"
|
||||||
var tokenCreatedHTML []byte
|
var tokenCreatedHTML []byte
|
||||||
var tokenCreateTemplate = templating.Parse[TokenCreateContext](
|
var tokenCreateTemplate = templating.Parse[TokenCreateContext](
|
||||||
"token_created.html", tokenCreatedHTML, httpx.FormTemplate,
|
"token_created.html", tokenCreatedHTML, form.FormTemplate,
|
||||||
templating.Title("Add Token"),
|
templating.Title("Add Token"),
|
||||||
templating.Assets(assets.AssetsUser),
|
templating.Assets(assets.AssetsUser),
|
||||||
)
|
)
|
||||||
|
|
@ -139,14 +140,14 @@ func (panel *UserPanel) tokensAddRoute(ctx context.Context) http.Handler {
|
||||||
),
|
),
|
||||||
)
|
)
|
||||||
|
|
||||||
return &httpx.Form[addTokenResult]{
|
return &form.Form[addTokenResult]{
|
||||||
Fields: []field.Field{
|
Fields: []field.Field{
|
||||||
{Name: "description", Type: field.Text, Label: "Description"},
|
{Name: "description", Type: field.Text, Label: "Description"},
|
||||||
},
|
},
|
||||||
FieldTemplate: field.PureCSSFieldTemplate,
|
FieldTemplate: assets.PureCSSFieldTemplate,
|
||||||
|
|
||||||
RenderTemplate: tplForm.Template(),
|
Template: tplForm.Template(),
|
||||||
RenderTemplateContext: templating.FormTemplateContext(tplForm),
|
TemplateContext: templating.FormTemplateContext(tplForm),
|
||||||
|
|
||||||
Validate: func(r *http.Request, values map[string]string) (at addTokenResult, err error) {
|
Validate: func(r *http.Request, values map[string]string) (at addTokenResult, err error) {
|
||||||
at.User, err = panel.dependencies.Auth.UserOfSession(r)
|
at.User, err = panel.dependencies.Auth.UserOfSession(r)
|
||||||
|
|
@ -164,7 +165,7 @@ func (panel *UserPanel) tokensAddRoute(ctx context.Context) http.Handler {
|
||||||
return at, nil
|
return at, nil
|
||||||
},
|
},
|
||||||
|
|
||||||
RenderSuccess: func(at addTokenResult, values map[string]string, w http.ResponseWriter, r *http.Request) error {
|
Success: func(at addTokenResult, values map[string]string, w http.ResponseWriter, r *http.Request) error {
|
||||||
// add the key to the user
|
// add the key to the user
|
||||||
tok, err := panel.dependencies.Tokens.Add(r.Context(), at.User.User.User, at.Description, at.Scopes)
|
tok, err := panel.dependencies.Tokens.Add(r.Context(), at.User.User.User, at.Description, at.Scopes)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
|
@ -175,10 +176,16 @@ func (panel *UserPanel) tokensAddRoute(ctx context.Context) http.Handler {
|
||||||
}
|
}
|
||||||
|
|
||||||
// render the created context
|
// render the created context
|
||||||
return httpx.WriteHTML(tplDone.Context(r, TokenCreateContext{
|
return panel.dependencies.Handling.WriteHTML(
|
||||||
|
tplDone.Context(r, TokenCreateContext{
|
||||||
Domain: template.URL(panel.Config.HTTP.JoinPath().String()),
|
Domain: template.URL(panel.Config.HTTP.JoinPath().String()),
|
||||||
Token: tok,
|
Token: tok,
|
||||||
}), nil, tplDone.Template(), "", w, r)
|
}),
|
||||||
|
nil,
|
||||||
|
tplDone.Template(),
|
||||||
|
w,
|
||||||
|
r,
|
||||||
|
)
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -8,8 +8,8 @@ import (
|
||||||
"github.com/FAU-CDI/wisski-distillery/internal/dis/component/auth"
|
"github.com/FAU-CDI/wisski-distillery/internal/dis/component/auth"
|
||||||
"github.com/FAU-CDI/wisski-distillery/internal/dis/component/server/assets"
|
"github.com/FAU-CDI/wisski-distillery/internal/dis/component/server/assets"
|
||||||
"github.com/FAU-CDI/wisski-distillery/internal/dis/component/server/templating"
|
"github.com/FAU-CDI/wisski-distillery/internal/dis/component/server/templating"
|
||||||
"github.com/tkw1536/pkglib/httpx"
|
"github.com/tkw1536/pkglib/httpx/form"
|
||||||
"github.com/tkw1536/pkglib/httpx/field"
|
"github.com/tkw1536/pkglib/httpx/form/field"
|
||||||
|
|
||||||
_ "embed"
|
_ "embed"
|
||||||
)
|
)
|
||||||
|
|
@ -17,7 +17,7 @@ import (
|
||||||
//go:embed "templates/totp_enable.html"
|
//go:embed "templates/totp_enable.html"
|
||||||
var totpEnableHTML []byte
|
var totpEnableHTML []byte
|
||||||
var totpEnable = templating.Parse[userFormContext](
|
var totpEnable = templating.Parse[userFormContext](
|
||||||
"totp_enable.html", totpEnableHTML, httpx.FormTemplate,
|
"totp_enable.html", totpEnableHTML, form.FormTemplate,
|
||||||
|
|
||||||
templating.Title("Enable TOTP"),
|
templating.Title("Enable TOTP"),
|
||||||
templating.Assets(assets.AssetsUser),
|
templating.Assets(assets.AssetsUser),
|
||||||
|
|
@ -26,19 +26,19 @@ var totpEnable = templating.Parse[userFormContext](
|
||||||
func (panel *UserPanel) routeTOTPEnable(ctx context.Context) http.Handler {
|
func (panel *UserPanel) routeTOTPEnable(ctx context.Context) http.Handler {
|
||||||
tpl := totpEnable.Prepare(panel.dependencies.Templating)
|
tpl := totpEnable.Prepare(panel.dependencies.Templating)
|
||||||
|
|
||||||
return &httpx.Form[struct{}]{
|
return &form.Form[struct{}]{
|
||||||
Fields: []field.Field{
|
Fields: []field.Field{
|
||||||
{Name: "password", Type: field.Password, Autocomplete: field.CurrentPassword, EmptyOnError: true, Label: "Current Password"},
|
{Name: "password", Type: field.Password, Autocomplete: field.CurrentPassword, EmptyOnError: true, Label: "Current Password"},
|
||||||
},
|
},
|
||||||
FieldTemplate: field.PureCSSFieldTemplate,
|
FieldTemplate: assets.PureCSSFieldTemplate,
|
||||||
|
|
||||||
SkipForm: func(r *http.Request) (data struct{}, skip bool) {
|
Skip: func(r *http.Request) (data struct{}, skip bool) {
|
||||||
user, err := panel.dependencies.Auth.UserOfSession(r)
|
user, err := panel.dependencies.Auth.UserOfSession(r)
|
||||||
return struct{}{}, err == nil && user != nil && user.IsTOTPEnabled()
|
return struct{}{}, err == nil && user != nil && user.IsTOTPEnabled()
|
||||||
},
|
},
|
||||||
|
|
||||||
RenderTemplate: tpl.Template(),
|
Template: tpl.Template(),
|
||||||
RenderTemplateContext: panel.UserFormContext(tpl, menuTOTPEnable),
|
TemplateContext: panel.UserFormContext(tpl, menuTOTPEnable),
|
||||||
|
|
||||||
Validate: func(r *http.Request, values map[string]string) (struct{}, error) {
|
Validate: func(r *http.Request, values map[string]string) (struct{}, error) {
|
||||||
password := values["password"]
|
password := values["password"]
|
||||||
|
|
@ -64,7 +64,7 @@ func (panel *UserPanel) routeTOTPEnable(ctx context.Context) http.Handler {
|
||||||
return struct{}{}, nil
|
return struct{}{}, nil
|
||||||
},
|
},
|
||||||
|
|
||||||
RenderSuccess: func(_ struct{}, values map[string]string, w http.ResponseWriter, r *http.Request) error {
|
Success: func(_ struct{}, values map[string]string, w http.ResponseWriter, r *http.Request) error {
|
||||||
http.Redirect(w, r, "/user/totp/enroll", http.StatusSeeOther)
|
http.Redirect(w, r, "/user/totp/enroll", http.StatusSeeOther)
|
||||||
return nil
|
return nil
|
||||||
},
|
},
|
||||||
|
|
@ -74,7 +74,7 @@ func (panel *UserPanel) routeTOTPEnable(ctx context.Context) http.Handler {
|
||||||
//go:embed "templates/totp_enroll.html"
|
//go:embed "templates/totp_enroll.html"
|
||||||
var totpEnrollHTML []byte
|
var totpEnrollHTML []byte
|
||||||
var totpEnrollTemplate = templating.Parse[totpEnrollContext](
|
var totpEnrollTemplate = templating.Parse[totpEnrollContext](
|
||||||
"totp_enroll.html", totpEnrollHTML, httpx.FormTemplate,
|
"totp_enroll.html", totpEnrollHTML, form.FormTemplate,
|
||||||
|
|
||||||
templating.Title("Enable TOTP"),
|
templating.Title("Enable TOTP"),
|
||||||
templating.Assets(assets.AssetsUser),
|
templating.Assets(assets.AssetsUser),
|
||||||
|
|
@ -97,18 +97,20 @@ func (panel *UserPanel) routeTOTPEnroll(ctx context.Context) http.Handler {
|
||||||
),
|
),
|
||||||
)
|
)
|
||||||
|
|
||||||
return &httpx.Form[struct{}]{
|
return &form.Form[struct{}]{
|
||||||
Fields: []field.Field{
|
Fields: []field.Field{
|
||||||
{Name: "password", Type: field.Password, Autocomplete: field.CurrentPassword, EmptyOnError: true, Label: "Current Password"},
|
{Name: "password", Type: field.Password, Autocomplete: field.CurrentPassword, EmptyOnError: true, Label: "Current Password"},
|
||||||
{Name: "otp", Type: field.Text, Autocomplete: field.OneTimeCode, EmptyOnError: true, Label: "Passcode"},
|
{Name: "otp", Type: field.Text, Autocomplete: field.OneTimeCode, EmptyOnError: true, Label: "Passcode"},
|
||||||
},
|
},
|
||||||
FieldTemplate: field.PureCSSFieldTemplate,
|
FieldTemplate: assets.PureCSSFieldTemplate,
|
||||||
|
|
||||||
SkipForm: func(r *http.Request) (data struct{}, skip bool) {
|
Skip: func(r *http.Request) (data struct{}, skip bool) {
|
||||||
user, err := panel.dependencies.Auth.UserOfSession(r)
|
user, err := panel.dependencies.Auth.UserOfSession(r)
|
||||||
return struct{}{}, err == nil && user != nil && user.IsTOTPEnabled()
|
return struct{}{}, err == nil && user != nil && user.IsTOTPEnabled()
|
||||||
},
|
},
|
||||||
RenderTemplateContext: func(context httpx.FormContext, r *http.Request) any {
|
|
||||||
|
Template: tpl.Template(),
|
||||||
|
TemplateContext: func(context form.FormContext, r *http.Request) any {
|
||||||
user, err := panel.dependencies.Auth.UserOfSession(r)
|
user, err := panel.dependencies.Auth.UserOfSession(r)
|
||||||
|
|
||||||
ctx := totpEnrollContext{
|
ctx := totpEnrollContext{
|
||||||
|
|
@ -131,7 +133,6 @@ func (panel *UserPanel) routeTOTPEnroll(ctx context.Context) http.Handler {
|
||||||
|
|
||||||
return tpl.Context(r, ctx)
|
return tpl.Context(r, ctx)
|
||||||
},
|
},
|
||||||
RenderTemplate: tpl.Template(),
|
|
||||||
|
|
||||||
Validate: func(r *http.Request, values map[string]string) (struct{}, error) {
|
Validate: func(r *http.Request, values map[string]string) (struct{}, error) {
|
||||||
password, otp := values["password"], values["otp"]
|
password, otp := values["password"], values["otp"]
|
||||||
|
|
@ -157,7 +158,7 @@ func (panel *UserPanel) routeTOTPEnroll(ctx context.Context) http.Handler {
|
||||||
return struct{}{}, nil
|
return struct{}{}, nil
|
||||||
},
|
},
|
||||||
|
|
||||||
RenderSuccess: func(_ struct{}, values map[string]string, w http.ResponseWriter, r *http.Request) error {
|
Success: func(_ struct{}, values map[string]string, w http.ResponseWriter, r *http.Request) error {
|
||||||
http.Redirect(w, r, "/user/", http.StatusSeeOther)
|
http.Redirect(w, r, "/user/", http.StatusSeeOther)
|
||||||
return nil
|
return nil
|
||||||
},
|
},
|
||||||
|
|
@ -167,7 +168,7 @@ func (panel *UserPanel) routeTOTPEnroll(ctx context.Context) http.Handler {
|
||||||
//go:embed "templates/totp_disable.html"
|
//go:embed "templates/totp_disable.html"
|
||||||
var totpDisableHTML []byte
|
var totpDisableHTML []byte
|
||||||
var totpDisableTemplate = templating.Parse[userFormContext](
|
var totpDisableTemplate = templating.Parse[userFormContext](
|
||||||
"totp_disable.html", totpDisableHTML, httpx.FormTemplate,
|
"totp_disable.html", totpDisableHTML, form.FormTemplate,
|
||||||
|
|
||||||
templating.Title("Disable TOTP"),
|
templating.Title("Disable TOTP"),
|
||||||
templating.Assets(assets.AssetsUser),
|
templating.Assets(assets.AssetsUser),
|
||||||
|
|
@ -176,19 +177,20 @@ var totpDisableTemplate = templating.Parse[userFormContext](
|
||||||
func (panel *UserPanel) routeTOTPDisable(ctx context.Context) http.Handler {
|
func (panel *UserPanel) routeTOTPDisable(ctx context.Context) http.Handler {
|
||||||
tpl := totpDisableTemplate.Prepare(panel.dependencies.Templating)
|
tpl := totpDisableTemplate.Prepare(panel.dependencies.Templating)
|
||||||
|
|
||||||
return &httpx.Form[struct{}]{
|
return &form.Form[struct{}]{
|
||||||
Fields: []field.Field{
|
Fields: []field.Field{
|
||||||
{Name: "password", Type: field.Password, Autocomplete: field.CurrentPassword, EmptyOnError: true, Label: "Current Password"},
|
{Name: "password", Type: field.Password, Autocomplete: field.CurrentPassword, EmptyOnError: true, Label: "Current Password"},
|
||||||
{Name: "otp", Type: field.Text, Autocomplete: field.OneTimeCode, EmptyOnError: true, Label: "Current Passcode"},
|
{Name: "otp", Type: field.Text, Autocomplete: field.OneTimeCode, EmptyOnError: true, Label: "Current Passcode"},
|
||||||
},
|
},
|
||||||
FieldTemplate: field.PureCSSFieldTemplate,
|
FieldTemplate: assets.PureCSSFieldTemplate,
|
||||||
|
|
||||||
SkipForm: func(r *http.Request) (data struct{}, skip bool) {
|
Skip: func(r *http.Request) (data struct{}, skip bool) {
|
||||||
user, err := panel.dependencies.Auth.UserOfSession(r)
|
user, err := panel.dependencies.Auth.UserOfSession(r)
|
||||||
return struct{}{}, err == nil && user != nil && !user.IsTOTPEnabled()
|
return struct{}{}, err == nil && user != nil && !user.IsTOTPEnabled()
|
||||||
},
|
},
|
||||||
RenderTemplate: tpl.Template(),
|
|
||||||
RenderTemplateContext: panel.UserFormContext(tpl, menuTOTPDisable),
|
Template: tpl.Template(),
|
||||||
|
TemplateContext: panel.UserFormContext(tpl, menuTOTPDisable),
|
||||||
|
|
||||||
Validate: func(r *http.Request, values map[string]string) (struct{}, error) {
|
Validate: func(r *http.Request, values map[string]string) (struct{}, error) {
|
||||||
password, otp := values["password"], values["otp"]
|
password, otp := values["password"], values["otp"]
|
||||||
|
|
@ -214,7 +216,7 @@ func (panel *UserPanel) routeTOTPDisable(ctx context.Context) http.Handler {
|
||||||
return struct{}{}, nil
|
return struct{}{}, nil
|
||||||
},
|
},
|
||||||
|
|
||||||
RenderSuccess: func(_ struct{}, values map[string]string, w http.ResponseWriter, r *http.Request) error {
|
Success: func(_ struct{}, values map[string]string, w http.ResponseWriter, r *http.Request) error {
|
||||||
http.Redirect(w, r, "/user/", http.StatusSeeOther)
|
http.Redirect(w, r, "/user/", http.StatusSeeOther)
|
||||||
return nil
|
return nil
|
||||||
},
|
},
|
||||||
|
|
|
||||||
|
|
@ -59,7 +59,7 @@ func (panel *UserPanel) routeUser(ctx context.Context) http.Handler {
|
||||||
templating.Actions(actions...),
|
templating.Actions(actions...),
|
||||||
)
|
)
|
||||||
|
|
||||||
return tpl.HTMLHandlerWithFlags(func(r *http.Request) (uc userContext, funcs []templating.FlagFunc, err error) {
|
return tpl.HTMLHandlerWithFlags(panel.dependencies.Handling, func(r *http.Request) (uc userContext, funcs []templating.FlagFunc, err error) {
|
||||||
// find the user
|
// find the user
|
||||||
uc.AuthUser, err = panel.dependencies.Auth.UserOfSession(r)
|
uc.AuthUser, err = panel.dependencies.Auth.UserOfSession(r)
|
||||||
if err != nil || uc.AuthUser == nil {
|
if err != nil || uc.AuthUser == nil {
|
||||||
|
|
|
||||||
|
|
@ -10,8 +10,8 @@ import (
|
||||||
"github.com/FAU-CDI/wisski-distillery/internal/dis/component/server"
|
"github.com/FAU-CDI/wisski-distillery/internal/dis/component/server"
|
||||||
"github.com/FAU-CDI/wisski-distillery/internal/dis/component/server/assets"
|
"github.com/FAU-CDI/wisski-distillery/internal/dis/component/server/assets"
|
||||||
"github.com/FAU-CDI/wisski-distillery/internal/dis/component/server/templating"
|
"github.com/FAU-CDI/wisski-distillery/internal/dis/component/server/templating"
|
||||||
"github.com/tkw1536/pkglib/httpx"
|
"github.com/tkw1536/pkglib/httpx/form"
|
||||||
"github.com/tkw1536/pkglib/httpx/field"
|
"github.com/tkw1536/pkglib/httpx/form/field"
|
||||||
|
|
||||||
"github.com/gorilla/sessions"
|
"github.com/gorilla/sessions"
|
||||||
|
|
||||||
|
|
@ -162,7 +162,7 @@ func (auth *Auth) Logout(w http.ResponseWriter, r *http.Request) error {
|
||||||
//go:embed "login.html"
|
//go:embed "login.html"
|
||||||
var loginHTML []byte
|
var loginHTML []byte
|
||||||
var loginTemplate = templating.ParseForm(
|
var loginTemplate = templating.ParseForm(
|
||||||
"login.html", loginHTML, httpx.FormTemplate,
|
"login.html", loginHTML, form.FormTemplate,
|
||||||
|
|
||||||
templating.Title("Login Required"),
|
templating.Title("Login Required"),
|
||||||
templating.Assets(assets.AssetsUser),
|
templating.Assets(assets.AssetsUser),
|
||||||
|
|
@ -182,21 +182,21 @@ func (auth *Auth) authLogin(ctx context.Context) http.Handler {
|
||||||
},
|
},
|
||||||
)
|
)
|
||||||
|
|
||||||
return &httpx.Form[*AuthUser]{
|
return &form.Form[*AuthUser]{
|
||||||
Fields: []field.Field{
|
Fields: []field.Field{
|
||||||
{Name: "username", Type: field.Text, Autocomplete: field.Username, Label: "Username"},
|
{Name: "username", Type: field.Text, Autocomplete: field.Username, Label: "Username"},
|
||||||
{Name: "password", Type: field.Password, Autocomplete: field.CurrentPassword, EmptyOnError: true, Label: "Password"},
|
{Name: "password", Type: field.Password, Autocomplete: field.CurrentPassword, EmptyOnError: true, Label: "Password"},
|
||||||
{Name: "otp", Type: field.Text, Autocomplete: field.OneTimeCode, EmptyOnError: true, Label: "Passcode (optional)"},
|
{Name: "otp", Type: field.Text, Autocomplete: field.OneTimeCode, EmptyOnError: true, Label: "Passcode (optional)"},
|
||||||
},
|
},
|
||||||
FieldTemplate: field.PureCSSFieldTemplate,
|
FieldTemplate: assets.PureCSSFieldTemplate,
|
||||||
|
|
||||||
RenderTemplateContext: func(ctx httpx.FormContext, r *http.Request) any {
|
Template: tpl.Template(),
|
||||||
|
TemplateContext: func(ctx form.FormContext, r *http.Request) any {
|
||||||
if ctx.Err != nil {
|
if ctx.Err != nil {
|
||||||
ctx.Err = errLoginFailed
|
ctx.Err = errLoginFailed
|
||||||
}
|
}
|
||||||
return tpl.Context(r, templating.NewFormContext(ctx))
|
return tpl.Context(r, templating.NewFormContext(ctx))
|
||||||
},
|
},
|
||||||
RenderTemplate: tpl.Template(),
|
|
||||||
|
|
||||||
Validate: func(r *http.Request, values map[string]string) (*AuthUser, error) {
|
Validate: func(r *http.Request, values map[string]string) (*AuthUser, error) {
|
||||||
username, password, passcode := values["username"], values["password"], values["otp"]
|
username, password, passcode := values["username"], values["password"], values["otp"]
|
||||||
|
|
@ -215,12 +215,12 @@ func (auth *Auth) authLogin(ctx context.Context) http.Handler {
|
||||||
return user, nil
|
return user, nil
|
||||||
},
|
},
|
||||||
|
|
||||||
SkipForm: func(r *http.Request) (user *AuthUser, skip bool) {
|
Skip: func(r *http.Request) (user *AuthUser, skip bool) {
|
||||||
user, err := auth.UserOfSession(r)
|
user, err := auth.UserOfSession(r)
|
||||||
return user, err == nil && user != nil
|
return user, err == nil && user != nil
|
||||||
},
|
},
|
||||||
|
|
||||||
RenderSuccess: func(user *AuthUser, _ map[string]string, w http.ResponseWriter, r *http.Request) error {
|
Success: func(user *AuthUser, _ map[string]string, w http.ResponseWriter, r *http.Request) error {
|
||||||
if err := auth.Login(w, r, user); err != nil {
|
if err := auth.Login(w, r, user); err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -14,9 +14,9 @@ import (
|
||||||
"github.com/FAU-CDI/wisski-distillery/internal/dis/component/auth/scopes"
|
"github.com/FAU-CDI/wisski-distillery/internal/dis/component/auth/scopes"
|
||||||
"github.com/FAU-CDI/wisski-distillery/internal/dis/component/instances"
|
"github.com/FAU-CDI/wisski-distillery/internal/dis/component/instances"
|
||||||
"github.com/FAU-CDI/wisski-distillery/internal/dis/component/server/assets"
|
"github.com/FAU-CDI/wisski-distillery/internal/dis/component/server/assets"
|
||||||
|
"github.com/FAU-CDI/wisski-distillery/internal/dis/component/server/handling"
|
||||||
"github.com/FAU-CDI/wisski-distillery/internal/dis/component/server/templating"
|
"github.com/FAU-CDI/wisski-distillery/internal/dis/component/server/templating"
|
||||||
"github.com/rs/zerolog"
|
"github.com/rs/zerolog"
|
||||||
"github.com/tkw1536/pkglib/httpx"
|
|
||||||
"github.com/tkw1536/pkglib/lazy"
|
"github.com/tkw1536/pkglib/lazy"
|
||||||
|
|
||||||
_ "embed"
|
_ "embed"
|
||||||
|
|
@ -27,6 +27,7 @@ type Resolver struct {
|
||||||
dependencies struct {
|
dependencies struct {
|
||||||
Instances *instances.Instances
|
Instances *instances.Instances
|
||||||
Templating *templating.Templating
|
Templating *templating.Templating
|
||||||
|
Handling *handling.Handling
|
||||||
Auth *auth.Auth
|
Auth *auth.Auth
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -106,7 +107,7 @@ func (resolver *Resolver) HandleRoute(ctx context.Context, route string) (http.H
|
||||||
if resolver.dependencies.Auth.CheckScope("", scopes.ScopeUserValid, r) != nil {
|
if resolver.dependencies.Auth.CheckScope("", scopes.ScopeUserValid, r) != nil {
|
||||||
ctx.IndexContext.Prefixes = nil
|
ctx.IndexContext.Prefixes = nil
|
||||||
}
|
}
|
||||||
httpx.WriteHTML(tpl.Context(r, ctx), nil, t, "", w, r)
|
resolver.dependencies.Handling.WriteHTML(tpl.Context(r, ctx), nil, t, w, r)
|
||||||
},
|
},
|
||||||
|
|
||||||
Resolver: resolvers.InOrder{
|
Resolver: resolvers.InOrder{
|
||||||
|
|
|
||||||
|
|
@ -4,7 +4,7 @@ import (
|
||||||
"context"
|
"context"
|
||||||
"net/http"
|
"net/http"
|
||||||
|
|
||||||
"github.com/tkw1536/pkglib/mux"
|
"github.com/tkw1536/pkglib/httpx/mux"
|
||||||
)
|
)
|
||||||
|
|
||||||
// Routeable is a component that is servable
|
// Routeable is a component that is servable
|
||||||
|
|
@ -51,10 +51,29 @@ type Routes struct {
|
||||||
Decorator func(http.Handler) http.Handler
|
Decorator func(http.Handler) http.Handler
|
||||||
}
|
}
|
||||||
|
|
||||||
|
type routeContextTyp int
|
||||||
|
|
||||||
|
const routeContextKey routeContextTyp = 0
|
||||||
|
|
||||||
|
// RouteContext represents the context passed to a given route
|
||||||
type RouteContext struct {
|
type RouteContext struct {
|
||||||
DefaultDomain bool
|
DefaultDomain bool
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// WithRouteContext adds the given RouteContext to the context
|
||||||
|
func WithRouteContext(parent context.Context, value RouteContext) context.Context {
|
||||||
|
return context.WithValue(parent, routeContextKey, value)
|
||||||
|
}
|
||||||
|
|
||||||
|
// RouteContextOf returns the route context of the given context
|
||||||
|
func RouteContextOf(context context.Context) RouteContext {
|
||||||
|
ctx, ok := context.Value(routeContextKey).(RouteContext)
|
||||||
|
if !ok {
|
||||||
|
return RouteContext{}
|
||||||
|
}
|
||||||
|
return ctx
|
||||||
|
}
|
||||||
|
|
||||||
// Predicate returns the predicate corresponding to the given route
|
// Predicate returns the predicate corresponding to the given route
|
||||||
func (routes Routes) Predicate(context func(*http.Request) RouteContext) mux.Predicate {
|
func (routes Routes) Predicate(context func(*http.Request) RouteContext) mux.Predicate {
|
||||||
if routes.MatchAllDomains || routes.Internal {
|
if routes.MatchAllDomains || routes.Internal {
|
||||||
|
|
|
||||||
|
|
@ -9,6 +9,7 @@ import (
|
||||||
"github.com/FAU-CDI/wisski-distillery/internal/dis/component/auth/policy"
|
"github.com/FAU-CDI/wisski-distillery/internal/dis/component/auth/policy"
|
||||||
"github.com/FAU-CDI/wisski-distillery/internal/dis/component/auth/scopes"
|
"github.com/FAU-CDI/wisski-distillery/internal/dis/component/auth/scopes"
|
||||||
"github.com/FAU-CDI/wisski-distillery/internal/dis/component/server/admin/socket"
|
"github.com/FAU-CDI/wisski-distillery/internal/dis/component/server/admin/socket"
|
||||||
|
"github.com/FAU-CDI/wisski-distillery/internal/dis/component/server/handling"
|
||||||
"github.com/FAU-CDI/wisski-distillery/internal/dis/component/server/templating"
|
"github.com/FAU-CDI/wisski-distillery/internal/dis/component/server/templating"
|
||||||
"github.com/julienschmidt/httprouter"
|
"github.com/julienschmidt/httprouter"
|
||||||
"github.com/rs/zerolog"
|
"github.com/rs/zerolog"
|
||||||
|
|
@ -20,6 +21,7 @@ import (
|
||||||
type Admin struct {
|
type Admin struct {
|
||||||
component.Base
|
component.Base
|
||||||
dependencies struct {
|
dependencies struct {
|
||||||
|
Handling *handling.Handling
|
||||||
Fetchers []component.DistilleryFetcher
|
Fetchers []component.DistilleryFetcher
|
||||||
|
|
||||||
Instances *instances.Instances
|
Instances *instances.Instances
|
||||||
|
|
@ -178,7 +180,7 @@ func (admin *Admin) HandleRoute(ctx context.Context, route string) (handler http
|
||||||
func (admin *Admin) loginHandler(ctx context.Context) http.Handler {
|
func (admin *Admin) loginHandler(ctx context.Context) http.Handler {
|
||||||
logger := zerolog.Ctx(ctx)
|
logger := zerolog.Ctx(ctx)
|
||||||
|
|
||||||
return httpx.RedirectHandler(func(r *http.Request) (string, int, error) {
|
return admin.dependencies.Handling.Redirect(func(r *http.Request) (string, int, error) {
|
||||||
// parse the form
|
// parse the form
|
||||||
if err := r.ParseForm(); err != nil {
|
if err := r.ParseForm(); err != nil {
|
||||||
logger.Err(err).Msg("failed to parse admin login")
|
logger.Err(err).Msg("failed to parse admin login")
|
||||||
|
|
|
||||||
|
|
@ -120,7 +120,7 @@ func (admin *Admin) index(ctx context.Context) http.Handler {
|
||||||
),
|
),
|
||||||
)
|
)
|
||||||
|
|
||||||
return tpl.HTMLHandler(func(r *http.Request) (idx indexContext, err error) {
|
return tpl.HTMLHandler(admin.dependencies.Handling, func(r *http.Request) (idx indexContext, err error) {
|
||||||
idx.Distillery, idx.Instances, err = admin.Status(r.Context(), false)
|
idx.Distillery, idx.Instances, err = admin.Status(r.Context(), false)
|
||||||
return
|
return
|
||||||
})
|
})
|
||||||
|
|
@ -138,7 +138,7 @@ func (admin *Admin) instances(ctx context.Context) http.Handler {
|
||||||
),
|
),
|
||||||
)
|
)
|
||||||
|
|
||||||
return tpl.HTMLHandler(func(r *http.Request) (idx indexContext, err error) {
|
return tpl.HTMLHandler(admin.dependencies.Handling, func(r *http.Request) (idx indexContext, err error) {
|
||||||
idx.Distillery, idx.Instances, err = admin.Status(r.Context(), true)
|
idx.Distillery, idx.Instances, err = admin.Status(r.Context(), true)
|
||||||
return
|
return
|
||||||
})
|
})
|
||||||
|
|
|
||||||
|
|
@ -42,7 +42,7 @@ func (admin *Admin) instance(ctx context.Context) http.Handler {
|
||||||
),
|
),
|
||||||
)
|
)
|
||||||
|
|
||||||
return tpl.HTMLHandlerWithFlags(func(r *http.Request) (ic instanceContext, funcs []templating.FlagFunc, err error) {
|
return tpl.HTMLHandlerWithFlags(admin.dependencies.Handling, func(r *http.Request) (ic instanceContext, funcs []templating.FlagFunc, err error) {
|
||||||
slug := httprouter.ParamsFromContext(r.Context()).ByName("slug")
|
slug := httprouter.ParamsFromContext(r.Context()).ByName("slug")
|
||||||
|
|
||||||
// find the instance itself!
|
// find the instance itself!
|
||||||
|
|
|
||||||
|
|
@ -43,7 +43,7 @@ func (admin *Admin) instanceData(ctx context.Context) http.Handler {
|
||||||
),
|
),
|
||||||
)
|
)
|
||||||
|
|
||||||
return tpl.HTMLHandlerWithFlags(func(r *http.Request) (ctx instanceDataContext, funcs []templating.FlagFunc, err error) {
|
return tpl.HTMLHandlerWithFlags(admin.dependencies.Handling, func(r *http.Request) (ctx instanceDataContext, funcs []templating.FlagFunc, err error) {
|
||||||
slug := httprouter.ParamsFromContext(r.Context()).ByName("slug")
|
slug := httprouter.ParamsFromContext(r.Context()).ByName("slug")
|
||||||
|
|
||||||
// setup the context with just the instance
|
// setup the context with just the instance
|
||||||
|
|
|
||||||
|
|
@ -50,7 +50,7 @@ func (admin *Admin) instanceDrupal(ctx context.Context) http.Handler {
|
||||||
),
|
),
|
||||||
)
|
)
|
||||||
|
|
||||||
return tpl.HTMLHandlerWithFlags(func(r *http.Request) (ctx instanceDrupalContext, funcs []templating.FlagFunc, err error) {
|
return tpl.HTMLHandlerWithFlags(admin.dependencies.Handling, func(r *http.Request) (ctx instanceDrupalContext, funcs []templating.FlagFunc, err error) {
|
||||||
slug := httprouter.ParamsFromContext(r.Context()).ByName("slug")
|
slug := httprouter.ParamsFromContext(r.Context()).ByName("slug")
|
||||||
|
|
||||||
// setup the context with just the instance
|
// setup the context with just the instance
|
||||||
|
|
|
||||||
|
|
@ -26,7 +26,7 @@ func (admin *Admin) instanceProvision(ctx context.Context) http.Handler {
|
||||||
),
|
),
|
||||||
)
|
)
|
||||||
|
|
||||||
return tpl.HTMLHandler(func(r *http.Request) (ipc instanceSystemContext, err error) {
|
return tpl.HTMLHandler(admin.dependencies.Handling, func(r *http.Request) (ipc instanceSystemContext, err error) {
|
||||||
ipc.prepare(false)
|
ipc.prepare(false)
|
||||||
ipc.DefaultProfile = manager.DefaultProfile()
|
ipc.DefaultProfile = manager.DefaultProfile()
|
||||||
ipc.Profiles = collection.MapValues(manager.Profiles(), func(_ string, profile manager.Profile) string { return profile.Description })
|
ipc.Profiles = collection.MapValues(manager.Profiles(), func(_ string, profile manager.Profile) string { return profile.Description })
|
||||||
|
|
|
||||||
|
|
@ -40,7 +40,7 @@ func (admin *Admin) instancePurge(ctx context.Context) http.Handler {
|
||||||
),
|
),
|
||||||
)
|
)
|
||||||
|
|
||||||
return tpl.HTMLHandlerWithFlags(func(r *http.Request) (ctx instancePurgeContext, funcs []templating.FlagFunc, err error) {
|
return tpl.HTMLHandlerWithFlags(admin.dependencies.Handling, func(r *http.Request) (ctx instancePurgeContext, funcs []templating.FlagFunc, err error) {
|
||||||
slug := httprouter.ParamsFromContext(r.Context()).ByName("slug")
|
slug := httprouter.ParamsFromContext(r.Context()).ByName("slug")
|
||||||
|
|
||||||
// setup the context with just the instance
|
// setup the context with just the instance
|
||||||
|
|
|
||||||
|
|
@ -65,7 +65,7 @@ func (admin *Admin) instanceRebuild(ctx context.Context) http.Handler {
|
||||||
),
|
),
|
||||||
)
|
)
|
||||||
|
|
||||||
return tpl.HTMLHandlerWithFlags(func(r *http.Request) (isc instanceSystemContext, funcs []templating.FlagFunc, err error) {
|
return tpl.HTMLHandlerWithFlags(admin.dependencies.Handling, func(r *http.Request) (isc instanceSystemContext, funcs []templating.FlagFunc, err error) {
|
||||||
slug := httprouter.ParamsFromContext(r.Context()).ByName("slug")
|
slug := httprouter.ParamsFromContext(r.Context()).ByName("slug")
|
||||||
|
|
||||||
var instance *wisski.WissKI
|
var instance *wisski.WissKI
|
||||||
|
|
|
||||||
|
|
@ -42,7 +42,7 @@ func (admin *Admin) instanceSnapshots(ctx context.Context) http.Handler {
|
||||||
),
|
),
|
||||||
)
|
)
|
||||||
|
|
||||||
return tpl.HTMLHandlerWithFlags(func(r *http.Request) (ctx instanceSnapshotsContext, funcs []templating.FlagFunc, err error) {
|
return tpl.HTMLHandlerWithFlags(admin.dependencies.Handling, func(r *http.Request) (ctx instanceSnapshotsContext, funcs []templating.FlagFunc, err error) {
|
||||||
slug := httprouter.ParamsFromContext(r.Context()).ByName("slug")
|
slug := httprouter.ParamsFromContext(r.Context()).ByName("slug")
|
||||||
|
|
||||||
// setup the context with just the instance
|
// setup the context with just the instance
|
||||||
|
|
|
||||||
|
|
@ -47,7 +47,7 @@ func (admin *Admin) instanceSSH(ctx context.Context) http.Handler {
|
||||||
),
|
),
|
||||||
)
|
)
|
||||||
|
|
||||||
return tpl.HTMLHandlerWithFlags(func(r *http.Request) (ctx instanceSSHContext, funcs []templating.FlagFunc, err error) {
|
return tpl.HTMLHandlerWithFlags(admin.dependencies.Handling, func(r *http.Request) (ctx instanceSSHContext, funcs []templating.FlagFunc, err error) {
|
||||||
slug := httprouter.ParamsFromContext(r.Context()).ByName("slug")
|
slug := httprouter.ParamsFromContext(r.Context()).ByName("slug")
|
||||||
|
|
||||||
// setup the context with just the instance
|
// setup the context with just the instance
|
||||||
|
|
|
||||||
|
|
@ -42,7 +42,7 @@ func (admin *Admin) instanceStats(ctx context.Context) http.Handler {
|
||||||
),
|
),
|
||||||
)
|
)
|
||||||
|
|
||||||
return tpl.HTMLHandlerWithFlags(func(r *http.Request) (ctx instanceStatsContext, funcs []templating.FlagFunc, err error) {
|
return tpl.HTMLHandlerWithFlags(admin.dependencies.Handling, func(r *http.Request) (ctx instanceStatsContext, funcs []templating.FlagFunc, err error) {
|
||||||
slug := httprouter.ParamsFromContext(r.Context()).ByName("slug")
|
slug := httprouter.ParamsFromContext(r.Context()).ByName("slug")
|
||||||
|
|
||||||
// setup the context with just the instance
|
// setup the context with just the instance
|
||||||
|
|
|
||||||
|
|
@ -15,7 +15,7 @@ import (
|
||||||
"github.com/FAU-CDI/wisski-distillery/internal/status"
|
"github.com/FAU-CDI/wisski-distillery/internal/status"
|
||||||
"github.com/FAU-CDI/wisski-distillery/internal/wisski"
|
"github.com/FAU-CDI/wisski-distillery/internal/wisski"
|
||||||
"github.com/tkw1536/pkglib/httpx"
|
"github.com/tkw1536/pkglib/httpx"
|
||||||
"github.com/tkw1536/pkglib/httpx/field"
|
"github.com/tkw1536/pkglib/httpx/form/field"
|
||||||
|
|
||||||
"github.com/julienschmidt/httprouter"
|
"github.com/julienschmidt/httprouter"
|
||||||
"golang.org/x/exp/maps"
|
"golang.org/x/exp/maps"
|
||||||
|
|
@ -55,7 +55,7 @@ func (admin *Admin) instanceUsers(ctx context.Context) http.Handler {
|
||||||
),
|
),
|
||||||
)
|
)
|
||||||
|
|
||||||
return tpl.HTMLHandlerWithFlags(func(r *http.Request) (instanceUsersContext, []templating.FlagFunc, error) {
|
return tpl.HTMLHandlerWithFlags(admin.dependencies.Handling, func(r *http.Request) (instanceUsersContext, []templating.FlagFunc, error) {
|
||||||
if r.Method == http.MethodGet {
|
if r.Method == http.MethodGet {
|
||||||
return admin.getGrantsUsers(r)
|
return admin.getGrantsUsers(r)
|
||||||
} else {
|
} else {
|
||||||
|
|
|
||||||
|
|
@ -10,8 +10,7 @@ import (
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
"github.com/FAU-CDI/wisski-distillery/internal/dis/component/auth"
|
"github.com/FAU-CDI/wisski-distillery/internal/dis/component/auth"
|
||||||
"github.com/gorilla/websocket"
|
"github.com/tkw1536/pkglib/httpx/websocket"
|
||||||
"github.com/tkw1536/pkglib/httpx"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
// ActionMap handles a set of WebSocket actions
|
// ActionMap handles a set of WebSocket actions
|
||||||
|
|
@ -40,7 +39,7 @@ func (err errPanic) Error() string {
|
||||||
// Finally it will send a ResultMessage once handling is complete.
|
// Finally it will send a ResultMessage once handling is complete.
|
||||||
//
|
//
|
||||||
// A corresponding client implementation of this can be found in ..../remote/proto.ts
|
// A corresponding client implementation of this can be found in ..../remote/proto.ts
|
||||||
func (am ActionMap) Handle(auth *auth.Auth, conn httpx.WebSocketConnection) (name string, err error) {
|
func (am ActionMap) Handle(auth *auth.Auth, conn *websocket.Connection) (name string, err error) {
|
||||||
var wg sync.WaitGroup
|
var wg sync.WaitGroup
|
||||||
|
|
||||||
// once we have finished executing send a binary message (indicating success) to the client.
|
// once we have finished executing send a binary message (indicating success) to the client.
|
||||||
|
|
@ -67,7 +66,7 @@ func (am ActionMap) Handle(auth *auth.Auth, conn httpx.WebSocketConnection) (nam
|
||||||
}
|
}
|
||||||
|
|
||||||
// encode the result message to json!
|
// encode the result message to json!
|
||||||
var message httpx.WebSocketMessage
|
var message websocket.Message
|
||||||
message.Type = websocket.BinaryMessage
|
message.Type = websocket.BinaryMessage
|
||||||
message.Bytes, err = json.Marshal(result)
|
message.Bytes, err = json.Marshal(result)
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -14,7 +14,7 @@ import (
|
||||||
"github.com/FAU-CDI/wisski-distillery/internal/dis/component/server/admin/socket/actions"
|
"github.com/FAU-CDI/wisski-distillery/internal/dis/component/server/admin/socket/actions"
|
||||||
"github.com/FAU-CDI/wisski-distillery/internal/dis/component/server/admin/socket/proto"
|
"github.com/FAU-CDI/wisski-distillery/internal/dis/component/server/admin/socket/proto"
|
||||||
"github.com/rs/zerolog"
|
"github.com/rs/zerolog"
|
||||||
"github.com/tkw1536/pkglib/httpx"
|
"github.com/tkw1536/pkglib/httpx/websocket"
|
||||||
"github.com/tkw1536/pkglib/lazy"
|
"github.com/tkw1536/pkglib/lazy"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
@ -48,14 +48,14 @@ func (socket *Sockets) Routes() component.Routes {
|
||||||
}
|
}
|
||||||
|
|
||||||
func (sockets *Sockets) HandleRoute(ctx context.Context, path string) (http.Handler, error) {
|
func (sockets *Sockets) HandleRoute(ctx context.Context, path string) (http.Handler, error) {
|
||||||
return &httpx.WebSocket{
|
return &websocket.Server{
|
||||||
Context: ctx,
|
Context: ctx,
|
||||||
Handler: sockets.Serve,
|
Handler: sockets.Serve,
|
||||||
}, nil
|
}, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// Serve handles a connection to the websocket api
|
// Serve handles a connection to the websocket api
|
||||||
func (socket *Sockets) Serve(conn httpx.WebSocketConnection) {
|
func (socket *Sockets) Serve(conn *websocket.Connection) {
|
||||||
// handle the websocket connection!
|
// handle the websocket connection!
|
||||||
name, err := socket.actions.Get(func() proto.ActionMap { return socket.Actions(conn.Context()) }).Handle(socket.dependencies.Auth, conn)
|
name, err := socket.actions.Get(func() proto.ActionMap { return socket.Actions(conn.Context()) }).Handle(socket.dependencies.Auth, conn)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
|
|
||||||
|
|
@ -11,7 +11,8 @@ import (
|
||||||
"github.com/FAU-CDI/wisski-distillery/internal/dis/component/server/templating"
|
"github.com/FAU-CDI/wisski-distillery/internal/dis/component/server/templating"
|
||||||
"github.com/rs/zerolog"
|
"github.com/rs/zerolog"
|
||||||
"github.com/tkw1536/pkglib/httpx"
|
"github.com/tkw1536/pkglib/httpx"
|
||||||
"github.com/tkw1536/pkglib/httpx/field"
|
"github.com/tkw1536/pkglib/httpx/form"
|
||||||
|
"github.com/tkw1536/pkglib/httpx/form/field"
|
||||||
|
|
||||||
_ "embed"
|
_ "embed"
|
||||||
)
|
)
|
||||||
|
|
@ -43,7 +44,7 @@ func (admin *Admin) users(ctx context.Context) http.Handler {
|
||||||
),
|
),
|
||||||
)
|
)
|
||||||
|
|
||||||
return tpl.HTMLHandler(func(r *http.Request) (uc usersContext, err error) {
|
return tpl.HTMLHandler(admin.dependencies.Handling, func(r *http.Request) (uc usersContext, err error) {
|
||||||
uc.Error = r.URL.Query().Get("error")
|
uc.Error = r.URL.Query().Get("error")
|
||||||
uc.Users, err = admin.dependencies.Auth.Users(r.Context())
|
uc.Users, err = admin.dependencies.Auth.Users(r.Context())
|
||||||
return
|
return
|
||||||
|
|
@ -53,7 +54,7 @@ func (admin *Admin) users(ctx context.Context) http.Handler {
|
||||||
//go:embed "html/user_create.html"
|
//go:embed "html/user_create.html"
|
||||||
var userCreateHTML []byte
|
var userCreateHTML []byte
|
||||||
var userCreateTemplate = templating.ParseForm(
|
var userCreateTemplate = templating.ParseForm(
|
||||||
"user_create.html", userCreateHTML, httpx.FormTemplate,
|
"user_create.html", userCreateHTML, form.FormTemplate,
|
||||||
|
|
||||||
templating.Title("Create User"),
|
templating.Title("Create User"),
|
||||||
templating.Assets(assets.AssetsAdmin),
|
templating.Assets(assets.AssetsAdmin),
|
||||||
|
|
@ -80,16 +81,16 @@ func (admin *Admin) createUser(ctx context.Context) http.Handler {
|
||||||
),
|
),
|
||||||
)
|
)
|
||||||
|
|
||||||
return &httpx.Form[createUserResult]{
|
return &form.Form[createUserResult]{
|
||||||
Fields: []field.Field{
|
Fields: []field.Field{
|
||||||
{Name: "username", Type: field.Text, Autocomplete: field.Username, Label: "Username"},
|
{Name: "username", Type: field.Text, Autocomplete: field.Username, Label: "Username"},
|
||||||
{Name: "password", Type: field.Password, Autocomplete: field.NewPassword, Label: "Password"},
|
{Name: "password", Type: field.Password, Autocomplete: field.NewPassword, Label: "Password"},
|
||||||
{Name: "admin", Type: field.Checkbox, Label: "Distillery Administrator"},
|
{Name: "admin", Type: field.Checkbox, Label: "Distillery Administrator"},
|
||||||
},
|
},
|
||||||
FieldTemplate: field.PureCSSFieldTemplate,
|
FieldTemplate: assets.PureCSSFieldTemplate,
|
||||||
|
|
||||||
RenderTemplate: tpl.Template(),
|
Template: tpl.Template(),
|
||||||
RenderTemplateContext: templating.FormTemplateContext(tpl),
|
TemplateContext: templating.FormTemplateContext(tpl),
|
||||||
|
|
||||||
Validate: func(r *http.Request, values map[string]string) (cu createUserResult, err error) {
|
Validate: func(r *http.Request, values map[string]string) (cu createUserResult, err error) {
|
||||||
cu.User, cu.Passsword, cu.Admin = values["username"], values["password"], values["admin"] == field.CheckboxChecked
|
cu.User, cu.Passsword, cu.Admin = values["username"], values["password"], values["admin"] == field.CheckboxChecked
|
||||||
|
|
@ -110,7 +111,7 @@ func (admin *Admin) createUser(ctx context.Context) http.Handler {
|
||||||
return cu, nil
|
return cu, nil
|
||||||
},
|
},
|
||||||
|
|
||||||
RenderSuccess: func(cu createUserResult, values map[string]string, w http.ResponseWriter, r *http.Request) error {
|
Success: func(cu createUserResult, values map[string]string, w http.ResponseWriter, r *http.Request) error {
|
||||||
// create the user
|
// create the user
|
||||||
user, err := admin.dependencies.Auth.CreateUser(r.Context(), cu.User)
|
user, err := admin.dependencies.Auth.CreateUser(r.Context(), cu.User)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
|
|
||||||
|
|
@ -21,4 +21,14 @@ type Assets struct {
|
||||||
Styles template.HTML // <link> tags inserted by the asset
|
Styles template.HTML // <link> tags inserted by the asset
|
||||||
}
|
}
|
||||||
|
|
||||||
|
var PureCSSFieldTemplate = template.Must(template.New("").Parse(`
|
||||||
|
<div class="pure-control-group">
|
||||||
|
<label for="{{.Name}}">{{.Label}}</label>
|
||||||
|
{{ if (eq .Type "textarea" )}}
|
||||||
|
<textarea name="{{.Name}}" id="{{.Name}}" placeholder="{{.Placeholder}}"{{if .Autocomplete }} autocomplete="{{.Autocomplete}}" {{end}}>{{.Value}}</textarea>
|
||||||
|
{{ else }}
|
||||||
|
<input type="{{.Type}}" value="{{.Value}}" name="{{.Name}}" id="{{.Name}}" placeholder="{{.Placeholder}}"{{if .Autocomplete }} autocomplete="{{.Autocomplete}}" {{end}}>
|
||||||
|
{{ end }}
|
||||||
|
</div>`))
|
||||||
|
|
||||||
//go:generate node build.mjs Default User Admin AdminProvision AdminRebuild
|
//go:generate node build.mjs Default User Admin AdminProvision AdminRebuild
|
||||||
|
|
|
||||||
60
internal/dis/component/server/handling/handling.go
Normal file
60
internal/dis/component/server/handling/handling.go
Normal file
|
|
@ -0,0 +1,60 @@
|
||||||
|
package handling
|
||||||
|
|
||||||
|
import (
|
||||||
|
"html/template"
|
||||||
|
"net/http"
|
||||||
|
|
||||||
|
"github.com/FAU-CDI/wisski-distillery/internal/dis/component"
|
||||||
|
"github.com/rs/zerolog"
|
||||||
|
"github.com/tkw1536/pkglib/httpx"
|
||||||
|
"github.com/tkw1536/pkglib/httpx/content"
|
||||||
|
"github.com/tkw1536/pkglib/lazy"
|
||||||
|
)
|
||||||
|
|
||||||
|
type Handling struct {
|
||||||
|
component.Base
|
||||||
|
|
||||||
|
text lazy.Lazy[httpx.ErrInterceptor]
|
||||||
|
html lazy.Lazy[httpx.ErrInterceptor]
|
||||||
|
}
|
||||||
|
|
||||||
|
func (h *Handling) TextInterceptor() httpx.ErrInterceptor {
|
||||||
|
return h.text.Get(func() httpx.ErrInterceptor {
|
||||||
|
return h.interceptor(httpx.TextInterceptor)
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
func (h *Handling) HTMLInterceptor() httpx.ErrInterceptor {
|
||||||
|
return h.html.Get(func() httpx.ErrInterceptor {
|
||||||
|
return h.interceptor(httpx.TextInterceptor)
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
// Interceptor returns a copy of the parent interceptor with global distillery interceptor options enabled.
|
||||||
|
func (h *Handling) interceptor(parent httpx.ErrInterceptor) httpx.ErrInterceptor {
|
||||||
|
pf := parent.OnFallback
|
||||||
|
if pf == nil {
|
||||||
|
pf = func(r *http.Request, err error) {}
|
||||||
|
}
|
||||||
|
|
||||||
|
parent.RenderError = h.Config.HTTP.Debug.Set && h.Config.HTTP.Debug.Value
|
||||||
|
parent.OnFallback = func(r *http.Request, err error) {
|
||||||
|
pf(r, err)
|
||||||
|
|
||||||
|
zerolog.Ctx(r.Context()).
|
||||||
|
Err(err).
|
||||||
|
Str("path", r.URL.Path).
|
||||||
|
Msg("unknown error")
|
||||||
|
}
|
||||||
|
return parent
|
||||||
|
}
|
||||||
|
|
||||||
|
func (h *Handling) Redirect(Handler content.RedirectFunc) http.Handler {
|
||||||
|
r := content.Redirect(Handler)
|
||||||
|
r.Interceptor = h.TextInterceptor()
|
||||||
|
return r
|
||||||
|
}
|
||||||
|
|
||||||
|
func (h *Handling) WriteHTML(context any, err error, template *template.Template, w http.ResponseWriter, r *http.Request) error {
|
||||||
|
return content.WriteHTMLI(context, err, template, h.HTMLInterceptor(), w, r)
|
||||||
|
}
|
||||||
|
|
@ -6,6 +6,7 @@ import (
|
||||||
"net/http"
|
"net/http"
|
||||||
|
|
||||||
"github.com/FAU-CDI/wisski-distillery/internal/dis/component"
|
"github.com/FAU-CDI/wisski-distillery/internal/dis/component"
|
||||||
|
"github.com/FAU-CDI/wisski-distillery/internal/dis/component/server/handling"
|
||||||
"github.com/FAU-CDI/wisski-distillery/internal/dis/component/server/list"
|
"github.com/FAU-CDI/wisski-distillery/internal/dis/component/server/list"
|
||||||
"github.com/FAU-CDI/wisski-distillery/internal/dis/component/server/templating"
|
"github.com/FAU-CDI/wisski-distillery/internal/dis/component/server/templating"
|
||||||
)
|
)
|
||||||
|
|
@ -15,6 +16,7 @@ type Home struct {
|
||||||
dependencies struct {
|
dependencies struct {
|
||||||
ListInstances *list.ListInstances
|
ListInstances *list.ListInstances
|
||||||
Templating *templating.Templating
|
Templating *templating.Templating
|
||||||
|
Handling *handling.Handling
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -61,7 +61,7 @@ func (home *Home) publicHandler(ctx context.Context) http.Handler {
|
||||||
|
|
||||||
about := home.dependencies.Templating.GetCustomizable(aboutTemplate)
|
about := home.dependencies.Templating.GetCustomizable(aboutTemplate)
|
||||||
|
|
||||||
return tpl.HTMLHandler(func(r *http.Request) (pc publicContext, err error) {
|
return tpl.HTMLHandler(home.dependencies.Handling, func(r *http.Request) (pc publicContext, err error) {
|
||||||
// only act on the root path!
|
// only act on the root path!
|
||||||
if strings.TrimSuffix(r.URL.Path, "/") != "" {
|
if strings.TrimSuffix(r.URL.Path, "/") != "" {
|
||||||
return pc, httpx.ErrNotFound
|
return pc, httpx.ErrNotFound
|
||||||
|
|
|
||||||
|
|
@ -8,6 +8,7 @@ import (
|
||||||
"github.com/FAU-CDI/wisski-distillery/internal/dis/component"
|
"github.com/FAU-CDI/wisski-distillery/internal/dis/component"
|
||||||
"github.com/FAU-CDI/wisski-distillery/internal/dis/component/server"
|
"github.com/FAU-CDI/wisski-distillery/internal/dis/component/server"
|
||||||
"github.com/FAU-CDI/wisski-distillery/internal/dis/component/server/assets"
|
"github.com/FAU-CDI/wisski-distillery/internal/dis/component/server/assets"
|
||||||
|
"github.com/FAU-CDI/wisski-distillery/internal/dis/component/server/handling"
|
||||||
"github.com/FAU-CDI/wisski-distillery/internal/dis/component/server/templating"
|
"github.com/FAU-CDI/wisski-distillery/internal/dis/component/server/templating"
|
||||||
|
|
||||||
_ "embed"
|
_ "embed"
|
||||||
|
|
@ -18,6 +19,7 @@ type Legal struct {
|
||||||
dependencies struct {
|
dependencies struct {
|
||||||
Static *assets.Static
|
Static *assets.Static
|
||||||
Templating *templating.Templating
|
Templating *templating.Templating
|
||||||
|
Handling *handling.Handling
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -65,7 +67,7 @@ func (legal *Legal) HandleRoute(ctx context.Context, route string) (http.Handler
|
||||||
),
|
),
|
||||||
)
|
)
|
||||||
|
|
||||||
return tpl.HTMLHandler(func(r *http.Request) (lc legalContext, err error) {
|
return tpl.HTMLHandler(legal.dependencies.Handling, func(r *http.Request) (lc legalContext, err error) {
|
||||||
lc.LegalNotices = cli.LegalNotices
|
lc.LegalNotices = cli.LegalNotices
|
||||||
|
|
||||||
lc.CSRFCookie = server.CSRFCookie
|
lc.CSRFCookie = server.CSRFCookie
|
||||||
|
|
|
||||||
|
|
@ -11,6 +11,7 @@ import (
|
||||||
|
|
||||||
"github.com/FAU-CDI/wisski-distillery/internal/dis/component"
|
"github.com/FAU-CDI/wisski-distillery/internal/dis/component"
|
||||||
"github.com/FAU-CDI/wisski-distillery/internal/dis/component/server/assets"
|
"github.com/FAU-CDI/wisski-distillery/internal/dis/component/server/assets"
|
||||||
|
"github.com/FAU-CDI/wisski-distillery/internal/dis/component/server/handling"
|
||||||
"github.com/FAU-CDI/wisski-distillery/internal/dis/component/server/templating"
|
"github.com/FAU-CDI/wisski-distillery/internal/dis/component/server/templating"
|
||||||
"github.com/rs/zerolog"
|
"github.com/rs/zerolog"
|
||||||
"github.com/yuin/goldmark"
|
"github.com/yuin/goldmark"
|
||||||
|
|
@ -23,6 +24,7 @@ type News struct {
|
||||||
component.Base
|
component.Base
|
||||||
dependencies struct {
|
dependencies struct {
|
||||||
Templating *templating.Templating
|
Templating *templating.Templating
|
||||||
|
Handling *handling.Handling
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -143,7 +145,7 @@ func (news *News) HandleRoute(ctx context.Context, path string) (http.Handler, e
|
||||||
zerolog.Ctx(ctx).Err(itemsErr).Msg("Unable to load news items")
|
zerolog.Ctx(ctx).Err(itemsErr).Msg("Unable to load news items")
|
||||||
}
|
}
|
||||||
|
|
||||||
return tpl.HTMLHandler(func(r *http.Request) (nc newsContext, err error) {
|
return tpl.HTMLHandler(news.dependencies.Handling, func(r *http.Request) (nc newsContext, err error) {
|
||||||
nc.Items, err = items, itemsErr
|
nc.Items, err = items, itemsErr
|
||||||
return
|
return
|
||||||
}), nil
|
}), nil
|
||||||
|
|
|
||||||
|
|
@ -2,18 +2,17 @@ package server
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"context"
|
"context"
|
||||||
"fmt"
|
|
||||||
"io"
|
"io"
|
||||||
"net/http"
|
"net/http"
|
||||||
"runtime/debug"
|
|
||||||
|
|
||||||
"github.com/FAU-CDI/wisski-distillery/internal/dis/component"
|
"github.com/FAU-CDI/wisski-distillery/internal/dis/component"
|
||||||
|
"github.com/FAU-CDI/wisski-distillery/internal/dis/component/server/handling"
|
||||||
"github.com/FAU-CDI/wisski-distillery/internal/dis/component/server/templating"
|
"github.com/FAU-CDI/wisski-distillery/internal/dis/component/server/templating"
|
||||||
"github.com/FAU-CDI/wisski-distillery/internal/models"
|
"github.com/FAU-CDI/wisski-distillery/internal/models"
|
||||||
"github.com/tkw1536/pkglib/contextx"
|
"github.com/tkw1536/pkglib/contextx"
|
||||||
"github.com/tkw1536/pkglib/httpx"
|
"github.com/tkw1536/pkglib/httpx/mux"
|
||||||
"github.com/tkw1536/pkglib/httpx/timewrap"
|
"github.com/tkw1536/pkglib/httpx/wrap"
|
||||||
"github.com/tkw1536/pkglib/mux"
|
"github.com/tkw1536/pkglib/recovery"
|
||||||
|
|
||||||
"github.com/gorilla/csrf"
|
"github.com/gorilla/csrf"
|
||||||
"github.com/rs/zerolog"
|
"github.com/rs/zerolog"
|
||||||
|
|
@ -27,6 +26,7 @@ type Server struct {
|
||||||
Cronables []component.Cronable
|
Cronables []component.Cronable
|
||||||
|
|
||||||
Templating *templating.Templating
|
Templating *templating.Templating
|
||||||
|
Handleing *handling.Handling
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -39,30 +39,33 @@ var (
|
||||||
//
|
//
|
||||||
// Logging messages are directed to progress
|
// Logging messages are directed to progress
|
||||||
func (server *Server) Server(ctx context.Context, progress io.Writer) (public http.Handler, internal http.Handler, err error) {
|
func (server *Server) Server(ctx context.Context, progress io.Writer) (public http.Handler, internal http.Handler, err error) {
|
||||||
logger := zerolog.Ctx(ctx)
|
interceptor := server.dependencies.Handleing.TextInterceptor()
|
||||||
|
|
||||||
var publicM, internalM mux.Mux[component.RouteContext]
|
// wrapHandler wraps individual handlers for errors
|
||||||
publicM.Context = func(r *http.Request) component.RouteContext {
|
wrapHandler := func(h http.Handler) http.Handler {
|
||||||
|
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
||||||
|
// handle any panic()s that occur
|
||||||
|
defer func() {
|
||||||
|
// intercept any panic() that wasn't caught
|
||||||
|
if err := recovery.Recover(recover()); err != nil {
|
||||||
|
interceptor.Intercept(w, r, err)
|
||||||
|
}
|
||||||
|
}()
|
||||||
|
|
||||||
|
// determine if we are on a slug from a host
|
||||||
slug, ok := server.Config.HTTP.NormSlugFromHost(r.Host)
|
slug, ok := server.Config.HTTP.NormSlugFromHost(r.Host)
|
||||||
return component.RouteContext{
|
|
||||||
|
rctx := component.WithRouteContext(r.Context(), component.RouteContext{
|
||||||
DefaultDomain: slug == "" && ok,
|
DefaultDomain: slug == "" && ok,
|
||||||
}
|
})
|
||||||
}
|
ctx := contextx.WithValuesOf(rctx, ctx)
|
||||||
publicM.Panic = func(p any, stack []byte, w http.ResponseWriter, r *http.Request) {
|
|
||||||
// log the panic
|
|
||||||
logger.Error().
|
|
||||||
Str("panic", fmt.Sprint(p)).
|
|
||||||
Str("stack", string(stack)).
|
|
||||||
Str("path", r.URL.Path).
|
|
||||||
Msg("panic serving handler")
|
|
||||||
|
|
||||||
// and send an internal server error
|
// serve with the next context
|
||||||
httpx.TextInterceptor.Fallback.ServeHTTP(w, r)
|
h.ServeHTTP(w, r.WithContext(ctx))
|
||||||
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
// setup the internal server identically
|
var publicM, internalM mux.Mux
|
||||||
internalM.Panic = publicM.Panic
|
|
||||||
internalM.Context = publicM.Context
|
|
||||||
|
|
||||||
// create a csrf protector
|
// create a csrf protector
|
||||||
csrfProtector := server.csrf()
|
csrfProtector := server.csrf()
|
||||||
|
|
@ -95,7 +98,7 @@ func (server *Server) Server(ctx context.Context, progress io.Writer) (public ht
|
||||||
handler = routes.Decorate(handler, csrfProtector)
|
handler = routes.Decorate(handler, csrfProtector)
|
||||||
|
|
||||||
// determine the predicate
|
// determine the predicate
|
||||||
predicate := routes.Predicate(publicM.ContextOf)
|
predicate := routes.Predicate(func(r *http.Request) component.RouteContext { return component.RouteContextOf(r.Context()) })
|
||||||
|
|
||||||
// and add all the prefixes
|
// and add all the prefixes
|
||||||
for _, prefix := range append([]string{routes.Prefix}, routes.Aliases...) {
|
for _, prefix := range append([]string{routes.Prefix}, routes.Aliases...) {
|
||||||
|
|
@ -107,15 +110,15 @@ func (server *Server) Server(ctx context.Context, progress io.Writer) (public ht
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// apply the given context function
|
// wrap the handlers
|
||||||
public = httpx.WithContextWrapper(&publicM, func(rcontext context.Context) context.Context { return contextx.WithValuesOf(rcontext, ctx) })
|
public = wrapHandler(&publicM)
|
||||||
internal = httpx.WithContextWrapper(&internalM, func(rcontext context.Context) context.Context { return contextx.WithValuesOf(rcontext, ctx) })
|
internal = wrapHandler(&internalM)
|
||||||
|
|
||||||
// Add Content-Security-Policy
|
// Add Content-Security-Policy
|
||||||
public = WithCSP(public, models.ContentSecurityPolicyDistilery)
|
public = WithCSP(public, models.ContentSecurityPolicyDistilery)
|
||||||
internal = WithCSP(internal, models.ContentSecurityPolicyNothing)
|
internal = WithCSP(internal, models.ContentSecurityPolicyNothing)
|
||||||
|
|
||||||
public = timewrap.Wrap(public)
|
public = wrap.Time(public)
|
||||||
|
|
||||||
err = nil
|
err = nil
|
||||||
return
|
return
|
||||||
|
|
@ -141,10 +144,3 @@ func WithCSP(handler http.Handler, policy string) http.Handler {
|
||||||
handler.ServeHTTP(w, r)
|
handler.ServeHTTP(w, r)
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
func init() {
|
|
||||||
httpx.InterceptorOnFallback = func(req *http.Request, err error) {
|
|
||||||
stack := debug.Stack()
|
|
||||||
zerolog.Ctx(req.Context()).Err(err).Str("stack", string(stack)).Msg("unknown error intercepted")
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
|
||||||
|
|
@ -11,10 +11,12 @@ import (
|
||||||
"strings"
|
"strings"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
|
"github.com/FAU-CDI/wisski-distillery/internal/dis/component/server/handling"
|
||||||
"github.com/gorilla/csrf"
|
"github.com/gorilla/csrf"
|
||||||
"github.com/rs/zerolog"
|
"github.com/rs/zerolog"
|
||||||
"github.com/tkw1536/pkglib/httpx"
|
"github.com/tkw1536/pkglib/httpx/content"
|
||||||
"github.com/tkw1536/pkglib/httpx/timewrap"
|
"github.com/tkw1536/pkglib/httpx/form"
|
||||||
|
"github.com/tkw1536/pkglib/httpx/wrap"
|
||||||
)
|
)
|
||||||
|
|
||||||
//go:embed "src/base.html"
|
//go:embed "src/base.html"
|
||||||
|
|
@ -46,7 +48,7 @@ func (tpl *Template[C]) context(r *http.Request, funcs ...FlagFunc) (ctx *tConte
|
||||||
// setup the basic properties
|
// setup the basic properties
|
||||||
ctx.ctx = r.Context()
|
ctx.ctx = r.Context()
|
||||||
ctx.Runtime.RequestURI = r.URL.RequestURI()
|
ctx.Runtime.RequestURI = r.URL.RequestURI()
|
||||||
ctx.Runtime.StartedAt = timewrap.Start(r).UTC()
|
ctx.Runtime.StartedAt = wrap.TimeStart(r).UTC()
|
||||||
ctx.Runtime.GeneratedAt = time.Now().UTC()
|
ctx.Runtime.GeneratedAt = time.Now().UTC()
|
||||||
ctx.Runtime.CSRF = csrf.TemplateField(r)
|
ctx.Runtime.CSRF = csrf.TemplateField(r)
|
||||||
ctx.Runtime.Menu = tpl.templating.buildMenu(r)
|
ctx.Runtime.Menu = tpl.templating.buildMenu(r)
|
||||||
|
|
@ -70,19 +72,19 @@ func (tpl *Template[C]) context(r *http.Request, funcs ...FlagFunc) (ctx *tConte
|
||||||
var ParseForm = Parse[FormContext]
|
var ParseForm = Parse[FormContext]
|
||||||
|
|
||||||
type FormContext struct {
|
type FormContext struct {
|
||||||
httpx.FormContext
|
form.FormContext
|
||||||
RuntimeFlags
|
RuntimeFlags
|
||||||
}
|
}
|
||||||
|
|
||||||
// NewFormContext returns a new FormContext from an underlying context
|
// NewFormContext returns a new FormContext from an underlying context
|
||||||
func NewFormContext(context httpx.FormContext) FormContext {
|
func NewFormContext(context form.FormContext) FormContext {
|
||||||
return FormContext{FormContext: context}
|
return FormContext{FormContext: context}
|
||||||
}
|
}
|
||||||
|
|
||||||
// FormTemplateContext returns a new handler for a form with the given base context
|
// FormTemplateContext returns a new handler for a form with the given base context
|
||||||
func FormTemplateContext(tw *Template[FormContext]) func(ctx httpx.FormContext, r *http.Request) any {
|
func FormTemplateContext(tw *Template[FormContext]) func(ctx form.FormContext, r *http.Request) any {
|
||||||
// TODO: Is this needed?
|
// TODO: Is this needed?
|
||||||
return func(ctx httpx.FormContext, r *http.Request) any {
|
return func(ctx form.FormContext, r *http.Request) any {
|
||||||
return tw.Context(r, FormContext{FormContext: ctx})
|
return tw.Context(r, FormContext{FormContext: ctx})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -113,19 +115,21 @@ func (tw *Template[C]) HandlerWithFlags(worker func(r *http.Request) (C, []FlagF
|
||||||
|
|
||||||
// HTMLHandler creates a new httpx.HTMLHandler that calls tw.Handler(worker) and tw.Template.
|
// HTMLHandler creates a new httpx.HTMLHandler that calls tw.Handler(worker) and tw.Template.
|
||||||
// See also Handler.
|
// See also Handler.
|
||||||
func (tw *Template[C]) HTMLHandler(worker func(r *http.Request) (C, error)) httpx.HTMLHandler[any] {
|
func (tw *Template[C]) HTMLHandler(handling *handling.Handling, worker func(r *http.Request) (C, error)) content.HTMLHandler[any] {
|
||||||
return httpx.HTMLHandler[any]{
|
return content.HTMLHandler[any]{
|
||||||
Handler: tw.Handler(worker),
|
Handler: tw.Handler(worker),
|
||||||
Template: tw.Template(),
|
Template: tw.Template(),
|
||||||
|
Interceptor: handling.HTMLInterceptor(),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// HTMLHandlerWithFlags creates a new httpx.HTMLHandler that calls tw.HandlerWithFlags(worker) and tw.Template.
|
// HTMLHandlerWithFlags creates a new httpx.HTMLHandler that calls tw.HandlerWithFlags(worker) and tw.Template.
|
||||||
// See also HandlerWithFlags.
|
// See also HandlerWithFlags.
|
||||||
func (tw *Template[C]) HTMLHandlerWithFlags(worker func(r *http.Request) (C, []FlagFunc, error)) httpx.HTMLHandler[any] {
|
func (tw *Template[C]) HTMLHandlerWithFlags(handling *handling.Handling, worker func(r *http.Request) (C, []FlagFunc, error)) content.HTMLHandler[any] {
|
||||||
return httpx.HTMLHandler[any]{
|
return content.HTMLHandler[any]{
|
||||||
Handler: tw.HandlerWithFlags(worker),
|
Handler: tw.HandlerWithFlags(worker),
|
||||||
Template: tw.Template(),
|
Template: tw.Template(),
|
||||||
|
Interceptor: handling.HTMLInterceptor(),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -5,7 +5,7 @@ import (
|
||||||
"net/http"
|
"net/http"
|
||||||
|
|
||||||
"github.com/FAU-CDI/wisski-distillery/internal/dis/component"
|
"github.com/FAU-CDI/wisski-distillery/internal/dis/component"
|
||||||
"github.com/tkw1536/pkglib/mux"
|
"github.com/tkw1536/pkglib/httpx/mux"
|
||||||
"golang.org/x/exp/slices"
|
"golang.org/x/exp/slices"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -30,6 +30,7 @@ import (
|
||||||
"github.com/FAU-CDI/wisski-distillery/internal/dis/component/server/admin/socket/actions"
|
"github.com/FAU-CDI/wisski-distillery/internal/dis/component/server/admin/socket/actions"
|
||||||
"github.com/FAU-CDI/wisski-distillery/internal/dis/component/server/assets"
|
"github.com/FAU-CDI/wisski-distillery/internal/dis/component/server/assets"
|
||||||
"github.com/FAU-CDI/wisski-distillery/internal/dis/component/server/cron"
|
"github.com/FAU-CDI/wisski-distillery/internal/dis/component/server/cron"
|
||||||
|
handleing "github.com/FAU-CDI/wisski-distillery/internal/dis/component/server/handling"
|
||||||
"github.com/FAU-CDI/wisski-distillery/internal/dis/component/server/home"
|
"github.com/FAU-CDI/wisski-distillery/internal/dis/component/server/home"
|
||||||
"github.com/FAU-CDI/wisski-distillery/internal/dis/component/server/legal"
|
"github.com/FAU-CDI/wisski-distillery/internal/dis/component/server/legal"
|
||||||
"github.com/FAU-CDI/wisski-distillery/internal/dis/component/server/list"
|
"github.com/FAU-CDI/wisski-distillery/internal/dis/component/server/list"
|
||||||
|
|
@ -203,6 +204,7 @@ func (dis *Distillery) allComponents(context *lifetime.Registry[component.Compon
|
||||||
|
|
||||||
// Control server
|
// Control server
|
||||||
lifetime.Place[*server.Server](context)
|
lifetime.Place[*server.Server](context)
|
||||||
|
lifetime.Place[*handleing.Handling](context)
|
||||||
|
|
||||||
lifetime.Place[*home.Home](context)
|
lifetime.Place[*home.Home](context)
|
||||||
lifetime.Place[*list.ListInstances](context)
|
lifetime.Place[*list.ListInstances](context)
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue