Add new debug option for http

This commit is contained in:
Tom Wiesing 2023-11-22 17:28:46 +01:00
parent 0ba34fe80f
commit 0290a42d07
No known key found for this signature in database
39 changed files with 293 additions and 189 deletions

View file

@ -11,25 +11,29 @@ import (
"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/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/ssh2"
"github.com/FAU-CDI/wisski-distillery/internal/dis/component/ssh2/sshkeys"
"github.com/FAU-CDI/wisski-distillery/internal/models"
"github.com/julienschmidt/httprouter"
"github.com/tkw1536/pkglib/httpx"
"github.com/tkw1536/pkglib/httpx/form"
)
type UserPanel struct {
component.Base
dependencies struct {
Auth *auth.Auth
Auth *auth.Auth
Handling *handling.Handling
Templating *templating.Templating
Policy *policy.Policy
Tokens *tokens.Tokens
Instances *instances.Instances
Next *next.Next
Keys *sshkeys.SSHKeys
SSH2 *ssh2.SSH2
Policy *policy.Policy
Tokens *tokens.Tokens
Instances *instances.Instances
Next *next.Next
Keys *sshkeys.SSHKeys
SSH2 *ssh2.SSH2
}
}
@ -142,12 +146,12 @@ func (panel *UserPanel) HandleRoute(ctx context.Context, route string) (http.Han
type userFormContext struct {
templating.RuntimeFlags
httpx.FormContext
form.FormContext
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 {
// append the last menu item, and prepend the menuUser one!
flags.Crumbs = append(flags.Crumbs, last, last)
@ -156,7 +160,7 @@ func (panel *UserPanel) UserFormContext(tpl *templating.Template[userFormContext
return flags
})
return func(ctx httpx.FormContext, r *http.Request) any {
return func(ctx form.FormContext, r *http.Request) any {
uctx := userFormContext{FormContext: ctx}
if user, err := panel.dependencies.Auth.UserOfSession(r); err == nil {
uctx.User = &user.User

View file

@ -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/templating"
"github.com/tkw1536/pkglib/httpx"
"github.com/tkw1536/pkglib/httpx/field"
"github.com/tkw1536/pkglib/httpx/form"
"github.com/tkw1536/pkglib/httpx/form/field"
)
//go:embed "templates/password.html"
var passwordHTML []byte
var passwordTemplate = templating.Parse[userFormContext](
"password.html", passwordHTML, httpx.FormTemplate,
"password.html", passwordHTML, form.FormTemplate,
templating.Title("Change Password"),
templating.Assets(assets.AssetsUser),
@ -34,17 +34,17 @@ var (
func (panel *UserPanel) routePassword(ctx context.Context) http.Handler {
tpl := passwordTemplate.Prepare(panel.dependencies.Templating)
return &httpx.Form[struct{}]{
return &form.Form[struct{}]{
Fields: []field.Field{
{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: "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)"},
},
FieldTemplate: field.PureCSSFieldTemplate,
FieldTemplate: assets.PureCSSFieldTemplate,
RenderTemplate: tpl.Template(),
RenderTemplateContext: panel.UserFormContext(tpl, menuChangePassword),
Template: tpl.Template(),
TemplateContext: panel.UserFormContext(tpl, menuChangePassword),
Validate: func(r *http.Request, values map[string]string) (struct{}, error) {
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
},
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
},
}

View file

@ -13,7 +13,8 @@ import (
"github.com/gliderlabs/ssh"
"github.com/rs/zerolog"
"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"
@ -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)
if err != nil {
return sc, err
@ -129,7 +130,7 @@ func (panel *UserPanel) sshDeleteRoute(ctx context.Context) http.Handler {
//go:embed "templates/ssh_add.html"
var sshAddHTML []byte
var sshAddTemplate = templating.ParseForm(
"ssh_add.html", sshAddHTML, httpx.FormTemplate,
"ssh_add.html", sshAddHTML, form.FormTemplate,
templating.Title("Add SSH Key"),
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{
{Name: "comment", Type: field.Text, Label: "Comment"},
{Name: "key", Type: field.Textarea, Label: "Key in authorized_keys format"}, // has hacked css!
},
FieldTemplate: field.PureCSSFieldTemplate,
FieldTemplate: assets.PureCSSFieldTemplate,
RenderTemplate: tpl.Template(),
RenderTemplateContext: templating.FormTemplateContext(tpl),
Template: tpl.Template(),
TemplateContext: templating.FormTemplateContext(tpl),
Validate: func(r *http.Request, values map[string]string) (ak addKeyResult, err error) {
ak.User, err = panel.dependencies.Auth.UserOfSession(r)
@ -181,7 +182,7 @@ func (panel *UserPanel) sshAddRoute(ctx context.Context) http.Handler {
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
if err := panel.dependencies.Keys.Add(r.Context(), ak.User.User.User, ak.Comment, ak.Key); err != nil {
return errAddKey

View file

@ -11,7 +11,8 @@ import (
"github.com/FAU-CDI/wisski-distillery/internal/models"
"github.com/rs/zerolog"
"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"
)
@ -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
user, err := panel.dependencies.Auth.UserOfSession(r)
if err != nil || user == nil {
@ -94,7 +95,7 @@ func (panel *UserPanel) tokensDeleteRoute(ctx context.Context) http.Handler {
//go:embed "templates/tokens_add.html"
var tokensAddHTML []byte
var tokensAddTemplate = templating.ParseForm(
"tokens_add.html", tokensAddHTML, httpx.FormTemplate,
"tokens_add.html", tokensAddHTML, form.FormTemplate,
templating.Title("Add Token"),
templating.Assets(assets.AssetsUser),
)
@ -108,7 +109,7 @@ type addTokenResult struct {
//go:embed "templates/token_created.html"
var tokenCreatedHTML []byte
var tokenCreateTemplate = templating.Parse[TokenCreateContext](
"token_created.html", tokenCreatedHTML, httpx.FormTemplate,
"token_created.html", tokenCreatedHTML, form.FormTemplate,
templating.Title("Add Token"),
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{
{Name: "description", Type: field.Text, Label: "Description"},
},
FieldTemplate: field.PureCSSFieldTemplate,
FieldTemplate: assets.PureCSSFieldTemplate,
RenderTemplate: tplForm.Template(),
RenderTemplateContext: templating.FormTemplateContext(tplForm),
Template: tplForm.Template(),
TemplateContext: templating.FormTemplateContext(tplForm),
Validate: func(r *http.Request, values map[string]string) (at addTokenResult, err error) {
at.User, err = panel.dependencies.Auth.UserOfSession(r)
@ -164,7 +165,7 @@ func (panel *UserPanel) tokensAddRoute(ctx context.Context) http.Handler {
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
tok, err := panel.dependencies.Tokens.Add(r.Context(), at.User.User.User, at.Description, at.Scopes)
if err != nil {
@ -175,10 +176,16 @@ func (panel *UserPanel) tokensAddRoute(ctx context.Context) http.Handler {
}
// render the created context
return httpx.WriteHTML(tplDone.Context(r, TokenCreateContext{
Domain: template.URL(panel.Config.HTTP.JoinPath().String()),
Token: tok,
}), nil, tplDone.Template(), "", w, r)
return panel.dependencies.Handling.WriteHTML(
tplDone.Context(r, TokenCreateContext{
Domain: template.URL(panel.Config.HTTP.JoinPath().String()),
Token: tok,
}),
nil,
tplDone.Template(),
w,
r,
)
},
}
}

View file

@ -8,8 +8,8 @@ import (
"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/templating"
"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"
)
@ -17,7 +17,7 @@ import (
//go:embed "templates/totp_enable.html"
var totpEnableHTML []byte
var totpEnable = templating.Parse[userFormContext](
"totp_enable.html", totpEnableHTML, httpx.FormTemplate,
"totp_enable.html", totpEnableHTML, form.FormTemplate,
templating.Title("Enable TOTP"),
templating.Assets(assets.AssetsUser),
@ -26,19 +26,19 @@ var totpEnable = templating.Parse[userFormContext](
func (panel *UserPanel) routeTOTPEnable(ctx context.Context) http.Handler {
tpl := totpEnable.Prepare(panel.dependencies.Templating)
return &httpx.Form[struct{}]{
return &form.Form[struct{}]{
Fields: []field.Field{
{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)
return struct{}{}, err == nil && user != nil && user.IsTOTPEnabled()
},
RenderTemplate: tpl.Template(),
RenderTemplateContext: panel.UserFormContext(tpl, menuTOTPEnable),
Template: tpl.Template(),
TemplateContext: panel.UserFormContext(tpl, menuTOTPEnable),
Validate: func(r *http.Request, values map[string]string) (struct{}, error) {
password := values["password"]
@ -64,7 +64,7 @@ func (panel *UserPanel) routeTOTPEnable(ctx context.Context) http.Handler {
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)
return nil
},
@ -74,7 +74,7 @@ func (panel *UserPanel) routeTOTPEnable(ctx context.Context) http.Handler {
//go:embed "templates/totp_enroll.html"
var totpEnrollHTML []byte
var totpEnrollTemplate = templating.Parse[totpEnrollContext](
"totp_enroll.html", totpEnrollHTML, httpx.FormTemplate,
"totp_enroll.html", totpEnrollHTML, form.FormTemplate,
templating.Title("Enable TOTP"),
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{
{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"},
},
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)
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)
ctx := totpEnrollContext{
@ -131,7 +133,6 @@ func (panel *UserPanel) routeTOTPEnroll(ctx context.Context) http.Handler {
return tpl.Context(r, ctx)
},
RenderTemplate: tpl.Template(),
Validate: func(r *http.Request, values map[string]string) (struct{}, error) {
password, otp := values["password"], values["otp"]
@ -157,7 +158,7 @@ func (panel *UserPanel) routeTOTPEnroll(ctx context.Context) http.Handler {
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)
return nil
},
@ -167,7 +168,7 @@ func (panel *UserPanel) routeTOTPEnroll(ctx context.Context) http.Handler {
//go:embed "templates/totp_disable.html"
var totpDisableHTML []byte
var totpDisableTemplate = templating.Parse[userFormContext](
"totp_disable.html", totpDisableHTML, httpx.FormTemplate,
"totp_disable.html", totpDisableHTML, form.FormTemplate,
templating.Title("Disable TOTP"),
templating.Assets(assets.AssetsUser),
@ -176,19 +177,20 @@ var totpDisableTemplate = templating.Parse[userFormContext](
func (panel *UserPanel) routeTOTPDisable(ctx context.Context) http.Handler {
tpl := totpDisableTemplate.Prepare(panel.dependencies.Templating)
return &httpx.Form[struct{}]{
return &form.Form[struct{}]{
Fields: []field.Field{
{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"},
},
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)
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) {
password, otp := values["password"], values["otp"]
@ -214,7 +216,7 @@ func (panel *UserPanel) routeTOTPDisable(ctx context.Context) http.Handler {
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)
return nil
},

View file

@ -59,7 +59,7 @@ func (panel *UserPanel) routeUser(ctx context.Context) http.Handler {
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
uc.AuthUser, err = panel.dependencies.Auth.UserOfSession(r)
if err != nil || uc.AuthUser == nil {