3 files changed,
56 insertions(+),
15 deletions(-)
Author:
Smirnov Oleksandr
ss2316544@gmail.com
Committed by:
GitHub
noreply@github.com
Committed at:
2025-06-05 19:49:32 +0300
Parent:
9f5c654
M
e2e/apiv1_auth_test.go
··· 4 4 "net/http" 5 5 6 6 "github.com/gofrs/uuid/v5" 7 + "github.com/olexsmir/onasty/internal/hasher" 7 8 "github.com/olexsmir/onasty/internal/models" 8 9 ) 9 10 ··· 298 299 e.Empty(sessionDB.RefreshToken) 299 300 } 300 301 301 -type apiv1AtuhChangePasswordRequest struct { 302 +type apiv1AuthChangePasswordRequest struct { 302 303 CurrentPassword string `json:"current_password"` 303 304 NewPassword string `json:"new_password"` 304 305 } ··· 312 313 httpResp := e.httpRequest( 313 314 http.MethodPost, 314 315 "/api/v1/auth/change-password", 315 - e.jsonify(apiv1AtuhChangePasswordRequest{ 316 + e.jsonify(apiv1AuthChangePasswordRequest{ 316 317 CurrentPassword: password, 317 318 NewPassword: newPassword, 318 319 }), ··· 323 324 324 325 userDB := e.getUserByEmail(email) 325 326 e.NoError(e.hasher.Compare(userDB.Password, newPassword)) 327 +} 328 + 329 +func (e *AppTestSuite) TestAuthV1_ChangePassword_wrongPassword() { 330 + password := e.uuid() 331 + newPassword := e.uuid() 332 + email := e.uuid() + "@test.com" 333 + _, toks := e.createAndSingIn(email, password) 334 + 335 + httpResp := e.httpRequest( 336 + http.MethodPost, 337 + "/api/v1/auth/change-password", 338 + e.jsonify(apiv1AuthChangePasswordRequest{ 339 + CurrentPassword: e.uuid(), 340 + NewPassword: newPassword, 341 + }), 342 + toks.AccessToken, 343 + ) 344 + 345 + e.Equal(http.StatusBadRequest, httpResp.Code) 346 + 347 + userDB := e.getUserByEmail(email) 348 + 349 + err := e.hasher.Compare(userDB.Password, newPassword) 350 + e.ErrorIs(err, hasher.ErrMismatchedHashes) 326 351 } 327 352 328 353 type (
M
internal/service/usersrv/usersrv.go
··· 188 188 userID uuid.UUID, 189 189 inp dtos.ChangeUserPassword, 190 190 ) error { 191 - // TODO: compare current password with providede, and assert on mismatch 192 - 193 191 //nolint:exhaustruct 194 192 if err := (models.User{Password: inp.NewPassword}).ValidatePassword(); err != nil { 195 193 return err 196 194 } 197 195 198 - oldPass, err := u.hasher.Hash(inp.CurrentPassword) 196 + user, err := u.userstore.GetByID(ctx, userID) 199 197 if err != nil { 200 198 return err 201 199 } 202 200 201 + if err = u.hasher.Compare(user.Password, inp.CurrentPassword); err != nil { 202 + return errors.Join(err, models.ErrUserInvalidPassword) 203 + } 204 + 203 205 newPass, err := u.hasher.Hash(inp.NewPassword) 204 206 if err != nil { 205 207 return err 206 208 } 207 209 208 - if err := u.userstore.ChangePassword(ctx, userID, oldPass, newPass); err != nil { 210 + if err := u.userstore.ChangePassword(ctx, userID, newPass); err != nil { 209 211 return err 210 212 } 211 213
M
internal/store/psql/userepo/userepo.go
··· 14 14 type UserStorer interface { 15 15 Create(ctx context.Context, inp models.User) (uuid.UUID, error) 16 16 17 - // GetUserByCredentials returns user by email and password 17 + // GetByEmail returns user by email and password 18 18 // the password should be hashed 19 19 GetByEmail(ctx context.Context, email string) (models.User, error) 20 + GetUserIDByEmail(ctx context.Context, email string) (uuid.UUID, error) 21 + GetByID(ctx context.Context, userID uuid.UUID) (models.User, error) 20 22 21 - GetUserIDByEmail(ctx context.Context, email string) (uuid.UUID, error) 22 23 MarkUserAsActivated(ctx context.Context, id uuid.UUID) error 23 24 24 25 // ChangePassword changes user password from oldPassword to newPassword 25 26 // and oldPassword and newPassword should be hashed 26 - ChangePassword(ctx context.Context, userID uuid.UUID, oldPassword, newPassword string) error 27 + ChangePassword(ctx context.Context, userID uuid.UUID, newPassword string) error 27 28 28 29 // SetPassword sets new password for user by their id 29 30 // password should be hashed ··· 112 113 return id, err 113 114 } 114 115 116 +func (r *UserRepo) GetByID(ctx context.Context, userID uuid.UUID) (models.User, error) { 117 + query := `--sql 118 +select id, email, password, activated, created_at, last_login_at 119 +from users 120 +where id = $1` 121 + 122 + var user models.User 123 + err := r.db.QueryRow(ctx, query, userID). 124 + Scan(&user.ID, &user.Email, &user.Password, &user.Activated, &user.CreatedAt, &user.LastLoginAt) 125 + if errors.Is(err, pgx.ErrNoRows) { 126 + return models.User{}, models.ErrUserNotFound 127 + } 128 + 129 + return user, err 130 +} 131 + 115 132 func (r *UserRepo) GetByOAuthID( 116 133 ctx context.Context, 117 134 provider, providerID string, ··· 164 181 func (r *UserRepo) ChangePassword( 165 182 ctx context.Context, 166 183 userID uuid.UUID, 167 - oldPass, newPass string, 184 + newPasswd string, 168 185 ) error { 169 186 query, args, err := pgq. 170 187 Update("users"). 171 - Set("password", newPass). 172 - Where(pgq.Eq{ 173 - "id": userID.String(), 174 - "password": oldPass, 175 - }). 188 + Set("password", newPasswd). 189 + Where(pgq.Eq{"id": userID.String()}). 176 190 SQL() 177 191 if err != nil { 178 192 return err