Skip to content

Commit

Permalink
[auth] allow to change password from device
Browse files Browse the repository at this point in the history
  • Loading branch information
capcom6 committed Dec 3, 2024
1 parent a1f6067 commit cf6ceae
Show file tree
Hide file tree
Showing 10 changed files with 318 additions and 18 deletions.
2 changes: 1 addition & 1 deletion go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ go 1.22.0

require (
firebase.google.com/go/v4 v4.12.1
github.com/android-sms-gateway/client-go v1.1.0
github.com/android-sms-gateway/client-go v1.2.0
github.com/ansrivas/fiberprometheus/v2 v2.6.1
github.com/capcom6/go-helpers v0.0.0-20240521035631-865ee2879fa3
github.com/capcom6/go-infra-fx v0.2.0
Expand Down
10 changes: 4 additions & 6 deletions go.sum
Original file line number Diff line number Diff line change
Expand Up @@ -26,8 +26,10 @@ github.com/Microsoft/go-winio v0.6.1 h1:9/kr64B9VUZrLm5YYwbGtUJnMgqWVOdUAXu6Migc
github.com/Microsoft/go-winio v0.6.1/go.mod h1:LRdKpFKfdobln8UmuiYcKPot9D2v6svN5+sAH+4kjUM=
github.com/Nvveen/Gotty v0.0.0-20120604004816-cd527374f1e5 h1:TngWCqHvy9oXAN6lEVMRuU21PR1EtLVZJmdB18Gu3Rw=
github.com/Nvveen/Gotty v0.0.0-20120604004816-cd527374f1e5/go.mod h1:lmUJ/7eu/Q8D7ML55dXQrVaamCz2vxCfdQBasLZfHKk=
github.com/android-sms-gateway/client-go v1.1.0 h1:mAPsueRrY/qOdQAU5yO3uLQAb7Po+3jBxB1tiqyClvg=
github.com/android-sms-gateway/client-go v1.1.0/go.mod h1:DQsReciU1xcaVW3T5Z2bqslNdsAwCFCtghawmA6g6L4=
github.com/android-sms-gateway/client-go v1.1.1-0.20241130131931-31efddf9578d h1:8LYyHCkZP5y0Wsa+DhRUv5NCpS72IDwtvkF0+Qqy+SQ=
github.com/android-sms-gateway/client-go v1.1.1-0.20241130131931-31efddf9578d/go.mod h1:DQsReciU1xcaVW3T5Z2bqslNdsAwCFCtghawmA6g6L4=
github.com/android-sms-gateway/client-go v1.2.0 h1:P02e/Nm2XY6gpxVQVZiaxh1ZfInVkwfOLzz8Mp/1dy0=
github.com/android-sms-gateway/client-go v1.2.0/go.mod h1:DQsReciU1xcaVW3T5Z2bqslNdsAwCFCtghawmA6g6L4=
github.com/andybalholm/brotli v1.1.0 h1:eLKJA0d02Lf0mVpIDgYnqXcUn0GqVmEFny3VuID1U3M=
github.com/andybalholm/brotli v1.1.0/go.mod h1:sms7XGricyQI9K10gOSf56VKKWS4oLer58Q+mhRPtnY=
github.com/ansrivas/fiberprometheus/v2 v2.6.1 h1:wac3pXaE6BYYTF04AC6K0ktk6vCD+MnDOJZ3SK66kXM=
Expand All @@ -39,10 +41,6 @@ github.com/beorn7/perks v1.0.1 h1:VlbKKnNfV8bJzeqoa4cOKqO6bYr3WgKZxO8Z16+hsOM=
github.com/beorn7/perks v1.0.1/go.mod h1:G2ZrVWU2WbWT9wwq4/hrbKbnv/1ERSJQ0ibhJ6rlkpw=
github.com/capcom6/go-helpers v0.0.0-20240521035631-865ee2879fa3 h1:mq9rmBMCCzqGnZtbQqFSd+Ua3fahqUOYaTf26YFhWJc=
github.com/capcom6/go-helpers v0.0.0-20240521035631-865ee2879fa3/go.mod h1:WDqc7HZNqHxUTisArkYIBZtqUfJBVyPWeQI+FMwEzAw=
github.com/capcom6/go-infra-fx v0.0.2 h1:Vj2bHqCokDRa5qfHoPa4zVVKIo1QGzCPF+9EMQ9upQc=
github.com/capcom6/go-infra-fx v0.0.2/go.mod h1:Mc7KClD8Z5wMiUAF9rxifMc39E9mMrSrylpqHzVfPM4=
github.com/capcom6/go-infra-fx v0.1.0 h1:RZ0gxFtR2ehopDzSnXSCVJ8I2C4oBUaCz42sQQp75dM=
github.com/capcom6/go-infra-fx v0.1.0/go.mod h1:T/DnT1EDrF9F+44eZw/lZnmsz5Dry0w/CTk0FB1Nct0=
github.com/capcom6/go-infra-fx v0.2.0 h1:FrWtdFiG58unIK7xN7kMJn3LfOFecp20W/ZVgvN3bsM=
github.com/capcom6/go-infra-fx v0.2.0/go.mod h1:T/DnT1EDrF9F+44eZw/lZnmsz5Dry0w/CTk0FB1Nct0=
github.com/cenkalti/backoff/v4 v4.2.1 h1:y4OZtCnogmCPw98Zjyt5a6+QwPLGkiQsYW5oUqylYbM=
Expand Down
31 changes: 31 additions & 0 deletions internal/sms-gateway/handlers/mobile.go
Original file line number Diff line number Diff line change
Expand Up @@ -178,6 +178,35 @@ func (h *mobileHandler) patchMessage(device models.Device, c *fiber.Ctx) error {
return c.SendStatus(fiber.StatusNoContent)
}

// @Summary Change password
// @Description Changes the user's password
// @Security MobileToken
// @Tags Device
// @Accept json
// @Produce json
// @Param request body smsgateway.MobileChangePasswordRequest true "Password change request"
// @Success 204 {object} nil "Password changed successfully"
// @Failure 400 {object} smsgateway.ErrorResponse "Invalid request"
// @Failure 401 {object} smsgateway.ErrorResponse "Unauthorized"
// @Failure 500 {object} smsgateway.ErrorResponse "Internal server error"
// @Router /mobile/v1/user/password [patch]
//
// Change password
func (h *mobileHandler) changePassword(device models.Device, c *fiber.Ctx) error {
req := smsgateway.MobileChangePasswordRequest{}

if err := h.BodyParserValidator(c, &req); err != nil {
return fiber.NewError(fiber.StatusBadRequest, err.Error())
}

if err := h.authSvc.ChangePassword(device.UserID, req.CurrentPassword, req.NewPassword); err != nil {
h.Logger.Error("failed to change password", zap.Error(err))
return fiber.NewError(fiber.StatusUnauthorized, "Invalid current password")
}

return c.SendStatus(fiber.StatusNoContent)
}

func (h *mobileHandler) Register(router fiber.Router) {
router = router.Group("/mobile/v1")

Expand Down Expand Up @@ -226,6 +255,8 @@ func (h *mobileHandler) Register(router fiber.Router) {
router.Get("/message", auth.WithDevice(h.getMessage))
router.Patch("/message", auth.WithDevice(h.patchMessage))

router.Patch("/user/password", auth.WithDevice(h.changePassword))

h.webhooksCtrl.Register(router.Group("/webhooks"))
}

Expand Down
4 changes: 4 additions & 0 deletions internal/sms-gateway/modules/auth/repository.go
Original file line number Diff line number Diff line change
Expand Up @@ -24,3 +24,7 @@ func (r *repository) GetByLogin(login string) (models.User, error) {
func (r *repository) Insert(user *models.User) error {
return r.db.Create(user).Error
}

func (r *repository) UpdatePassword(userID string, passwordHash string) error {
return r.db.Model(&models.User{}).Where("id = ?", userID).Update("password_hash", passwordHash).Error
}
29 changes: 29 additions & 0 deletions internal/sms-gateway/modules/auth/service.go
Original file line number Diff line number Diff line change
Expand Up @@ -158,3 +158,32 @@ func (s *Service) AuthorizeUser(username, password string) (models.User, error)

return user, nil
}

func (s *Service) ChangePassword(userID string, currentPassword string, newPassword string) error {
user, err := s.users.GetByLogin(userID)
if err != nil {
return fmt.Errorf("failed to get user: %w", err)
}

if err := crypto.CompareBCryptHash(user.PasswordHash, currentPassword); err != nil {
return fmt.Errorf("current password is incorrect: %w", err)
}

newHash, err := crypto.MakeBCryptHash(newPassword)
if err != nil {
return fmt.Errorf("failed to hash new password: %w", err)
}

if err := s.users.UpdatePassword(userID, newHash); err != nil {
return fmt.Errorf("failed to update password: %w", err)
}

// Invalidate cache
hash := sha256.Sum256([]byte(userID + currentPassword))
cacheKey := hex.EncodeToString(hash[:])
if err := s.usersCache.Delete(cacheKey); err != nil {
s.logger.Error("can't invalidate user cache", zap.Error(err))
}

return nil
}
12 changes: 11 additions & 1 deletion pkg/swagger/docs/mobile.http
Original file line number Diff line number Diff line change
Expand Up @@ -44,4 +44,14 @@ Content-Type: application/json

###
GET {{baseUrl}}/webhooks HTTP/1.1
Authorization: Bearer {{mobileToken}}
Authorization: Bearer {{mobileToken}}

###
PATCH {{baseUrl}}/user/password HTTP/1.1
Authorization: Bearer {{mobileToken}}
Content-Type: application/json

{
"currentPassword": "wsmgz1akhoo24o",
"newPassword": "wsmgz1akhoo24o"
}
74 changes: 74 additions & 0 deletions pkg/swagger/docs/swagger.json
Original file line number Diff line number Diff line change
Expand Up @@ -641,6 +641,60 @@
}
}
},
"/mobile/v1/user/password": {
"patch": {
"security": [
{
"MobileToken": []
}
],
"description": "Changes the user's password",
"consumes": [
"application/json"
],
"produces": [
"application/json"
],
"tags": [
"Device"
],
"summary": "Change password",
"parameters": [
{
"description": "Password change request",
"name": "request",
"in": "body",
"required": true,
"schema": {
"$ref": "#/definitions/smsgateway.MobileChangePasswordRequest"
}
}
],
"responses": {
"204": {
"description": "Password changed successfully"
},
"400": {
"description": "Invalid request",
"schema": {
"$ref": "#/definitions/smsgateway.ErrorResponse"
}
},
"401": {
"description": "Unauthorized",
"schema": {
"$ref": "#/definitions/smsgateway.ErrorResponse"
}
},
"500": {
"description": "Internal server error",
"schema": {
"$ref": "#/definitions/smsgateway.ErrorResponse"
}
}
}
}
},
"/mobile/v1/webhooks": {
"get": {
"security": [
Expand Down Expand Up @@ -1021,6 +1075,26 @@
}
}
},
"smsgateway.MobileChangePasswordRequest": {
"type": "object",
"required": [
"currentPassword",
"newPassword"
],
"properties": {
"currentPassword": {
"description": "Current password",
"type": "string",
"example": "cp2pydvxd2zwpx"
},
"newPassword": {
"description": "New password, at least 14 characters",
"type": "string",
"minLength": 14,
"example": "cp2pydvxd2zwpx"
}
}
},
"smsgateway.MobileDeviceResponse": {
"type": "object",
"properties": {
Expand Down
49 changes: 49 additions & 0 deletions pkg/swagger/docs/swagger.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -211,6 +211,21 @@ definitions:
- recipients
- state
type: object
smsgateway.MobileChangePasswordRequest:
properties:
currentPassword:
description: Current password
example: cp2pydvxd2zwpx
type: string
newPassword:
description: New password, at least 14 characters
example: cp2pydvxd2zwpx
minLength: 14
type: string
required:
- currentPassword
- newPassword
type: object
smsgateway.MobileDeviceResponse:
properties:
device:
Expand Down Expand Up @@ -790,6 +805,40 @@ paths:
tags:
- Device
- Messages
/mobile/v1/user/password:
patch:
consumes:
- application/json
description: Changes the user's password
parameters:
- description: Password change request
in: body
name: request
required: true
schema:
$ref: '#/definitions/smsgateway.MobileChangePasswordRequest'
produces:
- application/json
responses:
"204":
description: Password changed successfully
"400":
description: Invalid request
schema:
$ref: '#/definitions/smsgateway.ErrorResponse'
"401":
description: Unauthorized
schema:
$ref: '#/definitions/smsgateway.ErrorResponse'
"500":
description: Internal server error
schema:
$ref: '#/definitions/smsgateway.ErrorResponse'
security:
- MobileToken: []
summary: Change password
tags:
- Device
/mobile/v1/webhooks:
get:
description: Returns list of registered webhooks for device
Expand Down
8 changes: 8 additions & 0 deletions pkg/types/cache/cache.go
Original file line number Diff line number Diff line change
Expand Up @@ -61,6 +61,14 @@ func (c *Cache[T]) Get(key string) (T, error) {
return item.value, nil
}

func (c *Cache[T]) Delete(key string) error {
c.mux.Lock()
delete(c.items, key)
c.mux.Unlock()

return nil
}

func (c *Cache[T]) Drain() map[string]T {
t := time.Now()

Expand Down
Loading

0 comments on commit cf6ceae

Please sign in to comment.