Browse Source

make POST create user and PUT update user

Hunter Kehoe 9 months ago
parent
commit
fa48639517
4 changed files with 50 additions and 20 deletions
  1. 3 1
      server/server.go
  2. 39 10
      server/server_admin.go
  3. 7 7
      server/server_admin_test.go
  4. 1 2
      server/types.go

+ 3 - 1
server/server.go

@@ -446,8 +446,10 @@ func (s *Server) handleInternal(w http.ResponseWriter, r *http.Request, v *visit
 		return s.ensureWebPushEnabled(s.handleWebManifest)(w, r, v)
 	} else if r.Method == http.MethodGet && r.URL.Path == apiUsersPath {
 		return s.ensureAdmin(s.handleUsersGet)(w, r, v)
-	} else if r.Method == http.MethodPut && r.URL.Path == apiUsersPath {
+	} else if r.Method == http.MethodPost && r.URL.Path == apiUsersPath {
 		return s.ensureAdmin(s.handleUsersAdd)(w, r, v)
+	} else if r.Method == http.MethodPut && r.URL.Path == apiUsersPath {
+		return s.ensureAdmin(s.handleUsersUpdate)(w, r, v)
 	} else if r.Method == http.MethodDelete && r.URL.Path == apiUsersPath {
 		return s.ensureAdmin(s.handleUsersDelete)(w, r, v)
 	} else if (r.Method == http.MethodPut || r.Method == http.MethodPost) && r.URL.Path == apiUsersAccessPath {

+ 39 - 10
server/server_admin.go

@@ -39,7 +39,7 @@ func (s *Server) handleUsersGet(w http.ResponseWriter, r *http.Request, v *visit
 }
 
 func (s *Server) handleUsersAdd(w http.ResponseWriter, r *http.Request, v *visitor) error {
-	req, err := readJSONWithLimit[apiUserAddRequest](r.Body, jsonBodyBytesLimit, false)
+	req, err := readJSONWithLimit[apiUserAddOrUpdateRequest](r.Body, jsonBodyBytesLimit, false)
 	if err != nil {
 		return err
 	} else if !user.AllowedUsername(req.Username) || req.Password == "" {
@@ -49,15 +49,6 @@ func (s *Server) handleUsersAdd(w http.ResponseWriter, r *http.Request, v *visit
 	if err != nil && !errors.Is(err, user.ErrUserNotFound) {
 		return err
 	} else if u != nil {
-		if req.Force {
-			if u.IsAdmin() {
-				return errHTTPForbidden
-			}
-			if err := s.userManager.ChangePassword(req.Username, req.Password); err != nil {
-				return err
-			}
-			return s.writeJSON(w, newSuccessResponse())
-		}
 		return errHTTPConflictUserExists
 	}
 	var tier *user.Tier
@@ -79,6 +70,44 @@ func (s *Server) handleUsersAdd(w http.ResponseWriter, r *http.Request, v *visit
 	}
 	return s.writeJSON(w, newSuccessResponse())
 }
+func (s *Server) handleUsersUpdate(w http.ResponseWriter, r *http.Request, v *visitor) error {
+	req, err := readJSONWithLimit[apiUserAddOrUpdateRequest](r.Body, jsonBodyBytesLimit, false)
+	if err != nil {
+		return err
+	} else if !user.AllowedUsername(req.Username) || req.Password == "" {
+		return errHTTPBadRequest.Wrap("username invalid, or password missing")
+	}
+	u, err := s.userManager.User(req.Username)
+	if err != nil && !errors.Is(err, user.ErrUserNotFound) {
+		return err
+	} else if u != nil {
+		if u.IsAdmin() {
+			return errHTTPForbidden
+		}
+		if err := s.userManager.ChangePassword(req.Username, req.Password); err != nil {
+			return err
+		}
+		return s.writeJSON(w, newSuccessResponse())
+	}
+	var tier *user.Tier
+	if req.Tier != "" {
+		tier, err = s.userManager.Tier(req.Tier)
+		if errors.Is(err, user.ErrTierNotFound) {
+			return errHTTPBadRequestTierInvalid
+		} else if err != nil {
+			return err
+		}
+	}
+	if err := s.userManager.AddUser(req.Username, req.Password, user.RoleUser); err != nil {
+		return err
+	}
+	if tier != nil {
+		if err := s.userManager.ChangeTier(req.Username, req.Tier); err != nil {
+			return err
+		}
+	}
+	return s.writeJSON(w, newSuccessResponse())
+}
 
 func (s *Server) handleUsersDelete(w http.ResponseWriter, r *http.Request, v *visitor) error {
 	req, err := readJSONWithLimit[apiUserDeleteRequest](r.Body, jsonBodyBytesLimit, false)

+ 7 - 7
server/server_admin_test.go

@@ -20,7 +20,7 @@ func TestUser_AddRemove(t *testing.T) {
 	}))
 
 	// Create user via API
-	rr := request(t, s, "PUT", "/v1/users", `{"username": "ben", "password":"ben"}`, map[string]string{
+	rr := request(t, s, "POST", "/v1/users", `{"username": "ben", "password":"ben"}`, map[string]string{
 		"Authorization": util.BasicAuth("phil", "phil"),
 	})
 	require.Equal(t, 200, rr.Code)
@@ -67,7 +67,7 @@ func TestUser_ChangeUserPassword(t *testing.T) {
 	require.Nil(t, s.userManager.AddUser("phil", "phil", user.RoleAdmin))
 
 	// Create user via API
-	rr := request(t, s, "PUT", "/v1/users", `{"username": "ben", "password": "ben"}`, map[string]string{
+	rr := request(t, s, "POST", "/v1/users", `{"username": "ben", "password": "ben"}`, map[string]string{
 		"Authorization": util.BasicAuth("phil", "phil"),
 	})
 	require.Equal(t, 200, rr.Code)
@@ -79,7 +79,7 @@ func TestUser_ChangeUserPassword(t *testing.T) {
 	require.Equal(t, 200, rr.Code)
 
 	// Change password via API
-	rr = request(t, s, "PUT", "/v1/users", `{"username": "ben", "password": "ben-two", "force":true}`, map[string]string{
+	rr = request(t, s, "PUT", "/v1/users", `{"username": "ben", "password": "ben-two"}`, map[string]string{
 		"Authorization": util.BasicAuth("phil", "phil"),
 	})
 	require.Equal(t, 200, rr.Code)
@@ -106,7 +106,7 @@ func TestUser_DontChangeAdminPassword(t *testing.T) {
 	require.Nil(t, s.userManager.AddUser("admin", "admin", user.RoleAdmin))
 
 	// Try to change password via API
-	rr := request(t, s, "PUT", "/v1/users", `{"username": "admin", "password": "admin-new", "force":true}`, map[string]string{
+	rr := request(t, s, "PUT", "/v1/users", `{"username": "admin", "password": "admin-new"}`, map[string]string{
 		"Authorization": util.BasicAuth("phil", "phil"),
 	})
 	require.Equal(t, 403, rr.Code)
@@ -121,19 +121,19 @@ func TestUser_AddRemove_Failures(t *testing.T) {
 	require.Nil(t, s.userManager.AddUser("ben", "ben", user.RoleUser))
 
 	// Cannot create user with invalid username
-	rr := request(t, s, "PUT", "/v1/users", `{"username": "not valid", "password":"ben"}`, map[string]string{
+	rr := request(t, s, "POST", "/v1/users", `{"username": "not valid", "password":"ben"}`, map[string]string{
 		"Authorization": util.BasicAuth("phil", "phil"),
 	})
 	require.Equal(t, 400, rr.Code)
 
 	// Cannot create user if user already exists
-	rr = request(t, s, "PUT", "/v1/users", `{"username": "phil", "password":"phil"}`, map[string]string{
+	rr = request(t, s, "POST", "/v1/users", `{"username": "phil", "password":"phil"}`, map[string]string{
 		"Authorization": util.BasicAuth("phil", "phil"),
 	})
 	require.Equal(t, 40901, toHTTPError(t, rr.Body.String()).Code)
 
 	// Cannot create user with invalid tier
-	rr = request(t, s, "PUT", "/v1/users", `{"username": "emma", "password":"emma", "tier": "invalid"}`, map[string]string{
+	rr = request(t, s, "POST", "/v1/users", `{"username": "emma", "password":"emma", "tier": "invalid"}`, map[string]string{
 		"Authorization": util.BasicAuth("phil", "phil"),
 	})
 	require.Equal(t, 40030, toHTTPError(t, rr.Body.String()).Code)

+ 1 - 2
server/types.go

@@ -253,11 +253,10 @@ type apiStatsResponse struct {
 	MessagesRate float64 `json:"messages_rate"` // Average number of messages per second
 }
 
-type apiUserAddRequest struct {
+type apiUserAddOrUpdateRequest struct {
 	Username string `json:"username"`
 	Password string `json:"password"`
 	Tier     string `json:"tier"`
-	Force    bool   `json:"force"` // Used to change passwords/override existing user
 	// Do not add 'role' here. We don't want to add admins via the API.
 }