diff --git a/internal/dis/component/auth/panel/panel.go b/internal/dis/component/auth/panel/panel.go
index 96395e4..fc2c4ee 100644
--- a/internal/dis/component/auth/panel/panel.go
+++ b/internal/dis/component/auth/panel/panel.go
@@ -30,6 +30,7 @@ type UserPanel struct {
var (
_ component.Routeable = (*UserPanel)(nil)
+ _ component.Menuable = (*UserPanel)(nil)
)
func (panel *UserPanel) Routes() component.Routes {
@@ -37,9 +38,18 @@ func (panel *UserPanel) Routes() component.Routes {
Prefix: "/user/",
CSRF: true,
Decorator: panel.Dependencies.Auth.Require(nil),
+ }
+}
- MenuPriority: component.MenuUser,
- MenuTitle: "User",
+func (panel *UserPanel) Menu(r *http.Request) []component.MenuItem {
+ title := "Login"
+
+ user, err := panel.Dependencies.Auth.UserOf(r)
+ if user != nil && err == nil {
+ title = user.User.User
+ }
+ return []component.MenuItem{
+ {Title: title, Priority: component.MenuUser, Path: "/user/"},
}
}
diff --git a/internal/dis/component/auth/panel/templates/user.html b/internal/dis/component/auth/panel/templates/user.html
index b266052..00932d3 100644
--- a/internal/dis/component/auth/panel/templates/user.html
+++ b/internal/dis/component/auth/panel/templates/user.html
@@ -1,10 +1,11 @@
{{ template "_base.html" . }}
-{{ define "title" }}User{{ end }}
+{{ define "title" }}{{ .User.User }}{{ end }}
{{ define "content" }}
+ - Username:
{{ .User.User }}
{{ if .User.IsAdmin }}
- Role: Administrator
{{ else }}
diff --git a/internal/dis/component/control/admin/admin.go b/internal/dis/component/control/admin/admin.go
index 06b80b8..b5d8241 100644
--- a/internal/dis/component/control/admin/admin.go
+++ b/internal/dis/component/control/admin/admin.go
@@ -109,6 +109,8 @@ func (admin *Admin) HandleRoute(ctx context.Context, route string) (handler http
router.Handler(http.MethodPost, route+"users/disabletotp", admin.usersDisableTOTPHandler(ctx))
router.Handler(http.MethodPost, route+"users/password", admin.usersPasswordHandler(ctx))
router.Handler(http.MethodPost, route+"users/toggleadmin", admin.usersToggleAdmin(ctx))
+ router.Handler(http.MethodPost, route+"users/impersonate", admin.usersImpersonateHandler(ctx))
+ router.Handler(http.MethodPost, route+"users/unsetpassword", admin.usersUnsetPasswordHandler(ctx))
// add a handler for the component page
router.Handler(http.MethodGet, route+"components", httpx.HTMLHandler[componentContext]{
diff --git a/internal/dis/component/control/admin/html/users.html b/internal/dis/component/control/admin/html/users.html
index 6ecb9cb..3ea1d2a 100644
--- a/internal/dis/component/control/admin/html/users.html
+++ b/internal/dis/component/control/admin/html/users.html
@@ -25,6 +25,9 @@
Enabled
|
+
+ Has Password
+ |
Admin
|
@@ -44,8 +47,10 @@
{{ .User.User }}
- {{ .User.IsEnabled }}
-
+ {{ .User.IsEnabled }}
+ |
+
+ {{ .User.HasPassword }}
|
{{ .User.IsAdmin }}
@@ -66,6 +71,11 @@
{{ $csrf }}
+
+
|
diff --git a/internal/dis/component/control/admin/users.go b/internal/dis/component/control/admin/users.go
index 575d813..af565d7 100644
--- a/internal/dis/component/control/admin/users.go
+++ b/internal/dis/component/control/admin/users.go
@@ -219,3 +219,40 @@ func (admin *Admin) usersPasswordHandler(ctx context.Context) http.Handler {
return user.SetPassword(r.Context(), []byte(password))
})
}
+
+func (admin *Admin) usersUnsetPasswordHandler(ctx context.Context) http.Handler {
+ return admin.useraction(ctx, "unset password", func(r *http.Request, user *auth.AuthUser) error {
+ user.PasswordHash = nil
+ return user.Save(r.Context())
+ })
+}
+
+func (admin *Admin) usersImpersonateHandler(ctx context.Context) http.Handler {
+ logger := zerolog.Ctx(ctx)
+
+ return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
+ if err := r.ParseForm(); err != nil {
+ logger.Err(err).Str("action", "impersonate").Msg("failed to parse form")
+ httpx.HTMLInterceptor.Fallback.ServeHTTP(w, r)
+ return
+ }
+
+ username := r.PostFormValue("user")
+ user, err := admin.Dependencies.Auth.User(r.Context(), username)
+ if err != nil {
+ logger.Err(err).Str("action", "impersonate").Msg("failed to get user")
+ httpx.HTMLInterceptor.Fallback.ServeHTTP(w, r)
+ return
+ }
+
+ // login the user into the session of the provided user
+ if err := admin.Dependencies.Auth.Login(w, r, user); err != nil {
+ logger.Err(err).Str("action", "impersonate").Msg("failed to login user")
+ httpx.HTMLInterceptor.Fallback.ServeHTTP(w, r)
+ return
+ }
+
+ // and go there
+ http.Redirect(w, r, "/user/", http.StatusSeeOther)
+ })
+}
diff --git a/internal/models/user.go b/internal/models/user.go
index 8c80215..8105c8f 100644
--- a/internal/models/user.go
+++ b/internal/models/user.go
@@ -17,6 +17,10 @@ type User struct {
Admin *bool `gorm:"column:admin;not null"`
}
+func (user *User) HasPassword() bool {
+ return len(user.PasswordHash) != 0
+}
+
func (user *User) IsAdmin() bool {
return user.Admin != nil && *user.Admin
}