package panel import ( "context" "net/http" "github.com/FAU-CDI/wisski-distillery/internal/dis/component" "github.com/FAU-CDI/wisski-distillery/internal/dis/component/auth" "github.com/FAU-CDI/wisski-distillery/internal/dis/component/auth/next" "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/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/form" ) type UserPanel struct { component.Base dependencies struct { 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 } } var ( _ component.Routeable = (*UserPanel)(nil) _ component.Menuable = (*UserPanel)(nil) ) func (panel *UserPanel) Routes() component.Routes { return component.Routes{ Prefix: "/user/", CSRF: true, Decorator: panel.dependencies.Auth.Require(false, scopes.ScopeUserValid, nil), } } func (panel *UserPanel) Menu(r *http.Request) []component.MenuItem { title := "Login" user, err := panel.dependencies.Auth.UserOfSession(r) if user != nil && err == nil { title = user.User.User } return []component.MenuItem{ {Title: title, Priority: component.MenuUser, Path: "/user/"}, } } var ( menuUser = component.MenuItem{Title: "User", Path: "/user/"} menuChangePassword = component.MenuItem{Title: "Change Password", Path: "/user/password/"} menuSSH = component.MenuItem{Title: "SSH Keys", Path: "/user/ssh/"} menuSSHAdd = component.MenuItem{Title: "Add New Key", Path: "/user/ssh/add/"} menuTokens = component.MenuItem{Title: "Tokens", Path: "/user/tokens/"} menuTokensAdd = component.MenuItem{Title: "Add New Token", Path: "/user/tokens/add/"} menuTOTPAction = component.DummyMenuItem() menuTOTPDisable = component.MenuItem{Title: "Disable Passcode (TOTP)", Path: "/user/totp/disable/"} menuTOTPEnable = component.MenuItem{Title: "Enable Passcode (TOTP)", Path: "/user/totp/enable/"} ) func (panel *UserPanel) HandleRoute(ctx context.Context, route string) (http.Handler, error) { router := httprouter.New() { user := panel.routeUser(ctx) router.Handler(http.MethodGet, route, user) } { password := panel.routePassword(ctx) router.Handler(http.MethodGet, route+"password", password) router.Handler(http.MethodPost, route+"password", password) } { totpenable := panel.routeTOTPEnable(ctx) router.Handler(http.MethodGet, route+"totp/enable", totpenable) router.Handler(http.MethodPost, route+"totp/enable", totpenable) } { totpenroll := panel.routeTOTPEnroll(ctx) router.Handler(http.MethodGet, route+"totp/enroll", totpenroll) router.Handler(http.MethodPost, route+"totp/enroll", totpenroll) } { totpdisable := panel.routeTOTPDisable(ctx) router.Handler(http.MethodGet, route+"totp/disable", totpdisable) router.Handler(http.MethodPost, route+"totp/disable", totpdisable) } { ssh := panel.sshRoute(ctx) router.Handler(http.MethodGet, route+"ssh", ssh) } { add := panel.sshAddRoute(ctx) router.Handler(http.MethodGet, route+"ssh/add", add) router.Handler(http.MethodPost, route+"ssh/add", add) } { delete := panel.sshDeleteRoute(ctx) router.Handler(http.MethodPost, route+"ssh/delete", delete) } { tokens := panel.tokensRoute(ctx) router.Handler(http.MethodGet, route+"tokens", tokens) } { add := panel.tokensAddRoute(ctx) router.Handler(http.MethodGet, route+"tokens/add", add) router.Handler(http.MethodPost, route+"tokens/add", add) } { delete := panel.tokensDeleteRoute(ctx) router.Handler(http.MethodPost, route+"tokens/delete", delete) } // ensure that the user is logged in! return panel.dependencies.Auth.Protect(router, false, scopes.ScopeUserValid, nil), nil } type userFormContext struct { templating.RuntimeFlags form.FormContext User *models.User } 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) copy(flags.Crumbs[1:], flags.Crumbs) flags.Crumbs[0] = menuUser return flags }) 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 } return tpl.Context(r, uctx, funcs...) } }