diff --git a/api/api.go b/api/api.go
index 278e792..cec0175 100644
--- a/api/api.go
+++ b/api/api.go
@@ -157,6 +157,7 @@ func (api *API) registerWebAppRoutes(router *gin.Engine) {
router.GET("/admin/import", api.authWebAppMiddleware, api.authAdminWebAppMiddleware, api.appGetAdminImport)
router.POST("/admin/import", api.authWebAppMiddleware, api.authAdminWebAppMiddleware, api.appPerformAdminImport)
router.GET("/admin/users", api.authWebAppMiddleware, api.authAdminWebAppMiddleware, api.appGetAdminUsers)
+ router.POST("/admin/users", api.authWebAppMiddleware, api.authAdminWebAppMiddleware, api.appUpdateAdminUsers)
router.GET("/admin", api.authWebAppMiddleware, api.authAdminWebAppMiddleware, api.appGetAdmin)
router.POST("/admin", api.authWebAppMiddleware, api.authAdminWebAppMiddleware, api.appPerformAdminAction)
router.POST("/login", api.appAuthLogin)
diff --git a/api/app-admin-routes.go b/api/app-admin-routes.go
index 59211e2..22cf205 100644
--- a/api/app-admin-routes.go
+++ b/api/app-admin-routes.go
@@ -54,6 +54,20 @@ type requestAdminImport struct {
Type importType `form:"type"`
}
+type operationType string
+
+const (
+ opUpdate operationType = "UPDATE"
+ opCreate operationType = "CREATE"
+)
+
+type requestAdminUpdateUser struct {
+ User string `form:"user"`
+ Password string `form:"password"`
+ isAdmin bool `form:"is_admin"`
+ Operation operationType `form:"operation"`
+}
+
type requestAdminLogs struct {
Filter string `form:"filter"`
}
@@ -225,6 +239,45 @@ func (api *API) appGetAdminUsers(c *gin.Context) {
c.HTML(http.StatusOK, "page/admin-users", templateVars)
}
+func (api *API) appUpdateAdminUsers(c *gin.Context) {
+ templateVars, _ := api.getBaseTemplateVars("admin-users", c)
+
+ var rAdminUserUpdate requestAdminUpdateUser
+ if err := c.ShouldBind(&rAdminUserUpdate); err != nil {
+ log.Error("Invalid URI Bind")
+ appErrorPage(c, http.StatusNotFound, "Invalid user update")
+ return
+ }
+
+ var err error
+ switch rAdminUserUpdate.Operation {
+ case opCreate:
+ err = api.createUser(rAdminUserUpdate.User, rAdminUserUpdate.Password)
+ case opUpdate:
+ err = fmt.Errorf("unimplemented")
+ default:
+ appErrorPage(c, http.StatusNotFound, "Unknown user operation")
+ return
+
+ }
+
+ if err != nil {
+ appErrorPage(c, http.StatusInternalServerError, fmt.Sprintf("Unable to create user: %v", err))
+ return
+ }
+
+ users, err := api.db.Queries.GetUsers(api.db.Ctx)
+ if err != nil {
+ log.Error("GetUsers DB Error: ", err)
+ appErrorPage(c, http.StatusInternalServerError, fmt.Sprintf("GetUsers DB Error: %v", err))
+ return
+ }
+
+ templateVars["Data"] = users
+
+ c.HTML(http.StatusOK, "page/admin-users", templateVars)
+}
+
func (api *API) appGetAdminImport(c *gin.Context) {
templateVars, _ := api.getBaseTemplateVars("admin-import", c)
diff --git a/api/auth.go b/api/auth.go
index 68b01f7..63f8f4f 100644
--- a/api/auth.go
+++ b/api/auth.go
@@ -460,3 +460,55 @@ func (api *API) rotateAllAuthHashes() error {
return nil
}
+
+func (api *API) createUser(username string, rawPassword string) error {
+ password := fmt.Sprintf("%x", md5.Sum([]byte(rawPassword)))
+
+ if username == "" {
+ return fmt.Errorf("username can't be empty")
+ }
+
+ if rawPassword == "" {
+ return fmt.Errorf("password can't be empty")
+ }
+
+ hashedPassword, err := argon2.CreateHash(password, argon2.DefaultParams)
+ if err != nil {
+ return fmt.Errorf("unable to create hashed password")
+ }
+
+ // Generate auth hash
+ rawAuthHash, err := utils.GenerateToken(64)
+ if err != nil {
+ return fmt.Errorf("unable to create token for user")
+ }
+
+ // Get current users
+ currentUsers, err := api.db.Queries.GetUsers(api.db.Ctx)
+ if err != nil {
+ return fmt.Errorf("unable to get current users")
+ }
+
+ // Determine if we should be admin
+ isAdmin := false
+ if len(currentUsers) == 0 {
+ isAdmin = true
+ }
+
+ // Create user in DB
+ authHash := fmt.Sprintf("%x", rawAuthHash)
+ if rows, err := api.db.Queries.CreateUser(api.db.Ctx, database.CreateUserParams{
+ ID: username,
+ Pass: &hashedPassword,
+ AuthHash: &authHash,
+ Admin: isAdmin,
+ }); err != nil {
+ log.Error("CreateUser DB Error:", err)
+ return fmt.Errorf("unable to create user")
+ } else if rows == 0 {
+ log.Warn("User Already Exists:", username)
+ return fmt.Errorf("user already exists")
+ }
+
+ return nil
+}
diff --git a/templates/pages/admin-users.tmpl b/templates/pages/admin-users.tmpl
index 145d028..6e62e3d 100644
--- a/templates/pages/admin-users.tmpl
+++ b/templates/pages/admin-users.tmpl
@@ -9,8 +9,13 @@
action="./users"
class="flex flex-col gap-2 text-black dark:text-white text-sm">
+