UserUpdate updates fields on a user
(w http.ResponseWriter, r *http.Request)
| 80 | |
| 81 | // UserUpdate updates fields on a user |
| 82 | func (a *API) UserUpdate(w http.ResponseWriter, r *http.Request) error { |
| 83 | ctx := r.Context() |
| 84 | db := a.db.WithContext(ctx) |
| 85 | config := a.config |
| 86 | aud := a.requestAud(ctx, r) |
| 87 | |
| 88 | params := &UserUpdateParams{} |
| 89 | if err := retrieveRequestParams(r, params); err != nil { |
| 90 | return err |
| 91 | } |
| 92 | |
| 93 | user := getUser(ctx) |
| 94 | session := getSession(ctx) |
| 95 | |
| 96 | if err := a.validateUserUpdateParams(ctx, params); err != nil { |
| 97 | return err |
| 98 | } |
| 99 | |
| 100 | if params.AppData != nil && !isAdmin(user, config) { |
| 101 | if !isAdmin(user, config) { |
| 102 | return apierrors.NewForbiddenError(apierrors.ErrorCodeNotAdmin, "Updating app_metadata requires admin privileges") |
| 103 | } |
| 104 | } |
| 105 | |
| 106 | if user.HasMFAEnabled() && !session.IsAAL2() { |
| 107 | if (params.Password != nil && *params.Password != "") || (params.Email != "" && user.GetEmail() != params.Email) || (params.Phone != "" && user.GetPhone() != params.Phone) { |
| 108 | return apierrors.NewHTTPError(http.StatusUnauthorized, apierrors.ErrorCodeInsufficientAAL, "AAL2 session is required to update email or password when MFA is enabled.") |
| 109 | } |
| 110 | } |
| 111 | |
| 112 | if user.IsAnonymous { |
| 113 | if params.Password != nil && *params.Password != "" { |
| 114 | if params.Email == "" && params.Phone == "" { |
| 115 | return apierrors.NewUnprocessableEntityError(apierrors.ErrorCodeValidationFailed, "Updating password of an anonymous user without an email or phone is not allowed") |
| 116 | } |
| 117 | } |
| 118 | } |
| 119 | |
| 120 | // TODO: Check if a user is SSO via rows in identities table, not via this flag. |
| 121 | if user.IsSSOUser { |
| 122 | updatingForbiddenFields := false |
| 123 | |
| 124 | updatingForbiddenFields = updatingForbiddenFields || (params.Password != nil && *params.Password != "") |
| 125 | updatingForbiddenFields = updatingForbiddenFields || (params.Email != "" && params.Email != user.GetEmail()) |
| 126 | updatingForbiddenFields = updatingForbiddenFields || (params.Phone != "" && params.Phone != user.GetPhone()) |
| 127 | updatingForbiddenFields = updatingForbiddenFields || (params.Nonce != "") |
| 128 | |
| 129 | if updatingForbiddenFields { |
| 130 | return apierrors.NewUnprocessableEntityError(apierrors.ErrorCodeUserSSOManaged, "Updating email, phone, password of a SSO account only possible via SSO") |
| 131 | } |
| 132 | } |
| 133 | |
| 134 | if params.Email != "" && user.GetEmail() != params.Email { |
| 135 | if duplicateUser, err := models.IsDuplicatedEmail(db, params.Email, aud, user, config.Experimental.ProvidersWithOwnLinkingDomain); err != nil { |
| 136 | return apierrors.NewInternalServerError("Database error checking email").WithInternalError(err) |
| 137 | } else if duplicateUser != nil { |
| 138 | return apierrors.NewUnprocessableEntityError(apierrors.ErrorCodeEmailExists, DuplicateEmailMsg) |
| 139 | } |
nothing calls this directly
no test coverage detected