RyZ commited on
Commit
f7fe55b
·
1 Parent(s): 75af2b7

fix: fixing auth logic

Browse files
config/env_config.go CHANGED
@@ -23,6 +23,7 @@ type EnvConfig interface {
23
  GetSupabaseURL() string
24
  GetSupabaseKey() string
25
  GetSupabaseBucket() string
 
26
  }
27
 
28
  type envConfig struct {
@@ -105,3 +106,8 @@ func (e *envConfig) GetSupabaseKey() string {
105
  func (e *envConfig) GetSupabaseBucket() string {
106
  return strings.TrimSpace(os.Getenv("SUPABASE_BUCKET_NAME"))
107
  }
 
 
 
 
 
 
23
  GetSupabaseURL() string
24
  GetSupabaseKey() string
25
  GetSupabaseBucket() string
26
+ GetRegisterEnabled() bool
27
  }
28
 
29
  type envConfig struct {
 
106
  func (e *envConfig) GetSupabaseBucket() string {
107
  return strings.TrimSpace(os.Getenv("SUPABASE_BUCKET_NAME"))
108
  }
109
+
110
+ func (e *envConfig) GetRegisterEnabled() bool {
111
+ val := os.Getenv("REGISTER_ENABLED")
112
+ return val == "true" || val == "1"
113
+ }
controllers/admin_controller.go CHANGED
@@ -14,6 +14,8 @@ type AdminController interface {
14
  CreateUser(ctx *gin.Context)
15
  UpdateUser(ctx *gin.Context)
16
  DeleteUser(ctx *gin.Context)
 
 
17
  }
18
 
19
  type adminController struct {
@@ -109,3 +111,42 @@ func (c *adminController) DeleteUser(ctx *gin.Context) {
109
  }
110
  utils.SendResponse[any, any](ctx, nil, nil, nil)
111
  }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
14
  CreateUser(ctx *gin.Context)
15
  UpdateUser(ctx *gin.Context)
16
  DeleteUser(ctx *gin.Context)
17
+ RegisterEnabled(ctx *gin.Context)
18
+ SetRegistrationEnabled(ctx *gin.Context)
19
  }
20
 
21
  type adminController struct {
 
111
  }
112
  utils.SendResponse[any, any](ctx, nil, nil, nil)
113
  }
114
+
115
+ // RegisterEnabled godoc
116
+ // @Summary Check if registration is enabled
117
+ // @Description Check if user registration is enabled
118
+ // @Tags admin
119
+ // @Security BearerAuth
120
+ // @Success 200 {object} dto.RegisterEnabledResponse
121
+ // @Router /admin/register_enabled [get]
122
+ func (c *adminController) RegisterEnabled(ctx *gin.Context) {
123
+ utils.SendResponse[dto.RegisterEnabledResponse, any](ctx, nil, dto.RegisterEnabledResponse{
124
+ Register: c.adminService.IsRegisterEnabled(),
125
+ }, nil)
126
+ }
127
+
128
+ // SetRegistrationEnabled godoc
129
+ // @Summary Toggle registration enabled
130
+ // @Description Enable or disable user registration
131
+ // @Tags admin
132
+ // @Security BearerAuth
133
+ // @Accept json
134
+ // @Param request body dto.SetRegistrationRequest true "Set Registration Request"
135
+ // @Success 200 {object} dto.RegisterEnabledResponse
136
+ // @Router /admin/set_registration [post]
137
+ func (c *adminController) SetRegistrationEnabled(ctx *gin.Context) {
138
+ var req dto.SetRegistrationRequest
139
+ if err := ctx.ShouldBindJSON(&req); err != nil {
140
+ utils.SendResponse[any, any](ctx, nil, nil, err)
141
+ return
142
+ }
143
+
144
+ if err := c.adminService.SetRegistrationEnabled(req.Enabled); err != nil {
145
+ utils.SendResponse[any, any](ctx, nil, nil, err)
146
+ return
147
+ }
148
+
149
+ utils.SendResponse[dto.RegisterEnabledResponse, any](ctx, nil, dto.RegisterEnabledResponse{
150
+ Register: req.Enabled,
151
+ }, nil)
152
+ }
controllers/auth_controller.go CHANGED
@@ -52,8 +52,8 @@ func (c *authController) Register(ctx *gin.Context) {
52
  return
53
  }
54
 
55
- ctx.SetSameSite(http.SameSiteNoneMode)
56
- ctx.SetCookie("RefreshToken", resp.RefreshToken, 3600*24*7, "/api/auth", "", true, true)
57
 
58
  utils.SendResponse[dto.AuthResponse, any](ctx, nil, *resp, nil)
59
  }
@@ -81,8 +81,8 @@ func (c *authController) Login(ctx *gin.Context) {
81
  return
82
  }
83
 
84
- ctx.SetSameSite(http.SameSiteNoneMode)
85
- ctx.SetCookie("RefreshToken", resp.RefreshToken, 3600*24*7, "/api/auth", "", true, true)
86
 
87
  utils.SendResponse[dto.AuthResponse, any](ctx, nil, *resp, nil)
88
  }
@@ -112,10 +112,11 @@ func (c *authController) Logout(ctx *gin.Context) {
112
  _ = c.authService.Logout(tokenString, refreshToken)
113
  }
114
 
115
- ctx.SetSameSite(http.SameSiteNoneMode)
116
- ctx.SetSameSite(http.SameSiteNoneMode)
117
- ctx.SetCookie("RefreshToken", "", -1, "/api/auth", "", true, true)
118
- utils.SendResponse[any, any](ctx, nil, nil, nil)
 
119
  }
120
 
121
  // RefreshToken godoc
@@ -135,16 +136,19 @@ func (c *authController) RefreshToken(ctx *gin.Context) {
135
 
136
  newAccessToken, newRefreshToken, err := c.authService.RefreshToken(refreshToken)
137
  if err != nil {
138
- ctx.SetCookie("RefreshToken", "", -1, "/api/auth", "", true, true)
139
  utils.SendResponse[any, any](ctx, nil, nil, err)
140
  return
141
  }
142
 
143
- ctx.SetSameSite(http.SameSiteNoneMode)
144
- ctx.SetCookie("RefreshToken", newRefreshToken, 3600*24*7, "/api/auth", "", true, true)
 
 
 
145
 
146
  utils.SendResponse[dto.AuthResponse, any](ctx, nil, dto.AuthResponse{
147
- Token: newAccessToken,
148
  }, nil)
149
  }
150
 
 
52
  return
53
  }
54
 
55
+ ctx.SetSameSite(http.SameSiteLaxMode)
56
+ ctx.SetCookie("RefreshToken", resp.RefreshToken, 3600*24*7, "/", "", false, true)
57
 
58
  utils.SendResponse[dto.AuthResponse, any](ctx, nil, *resp, nil)
59
  }
 
81
  return
82
  }
83
 
84
+ ctx.SetSameSite(http.SameSiteLaxMode)
85
+ ctx.SetCookie("RefreshToken", resp.RefreshToken, 3600*24*7, "/", "", false, true)
86
 
87
  utils.SendResponse[dto.AuthResponse, any](ctx, nil, *resp, nil)
88
  }
 
112
  _ = c.authService.Logout(tokenString, refreshToken)
113
  }
114
 
115
+ ctx.SetSameSite(http.SameSiteLaxMode)
116
+ ctx.SetCookie("RefreshToken", "", -1, "/", "", false, true)
117
+ utils.SendResponse[dto.LogoutResponse, any](ctx, nil, dto.LogoutResponse{
118
+ SuccessMsg: "Logout successful",
119
+ }, nil)
120
  }
121
 
122
  // RefreshToken godoc
 
136
 
137
  newAccessToken, newRefreshToken, err := c.authService.RefreshToken(refreshToken)
138
  if err != nil {
139
+ ctx.SetCookie("RefreshToken", "", -1, "/", "", false, true)
140
  utils.SendResponse[any, any](ctx, nil, nil, err)
141
  return
142
  }
143
 
144
+ // Only set refresh token cookie if a new one was issued
145
+ if newRefreshToken != "" {
146
+ ctx.SetSameSite(http.SameSiteLaxMode)
147
+ ctx.SetCookie("RefreshToken", newRefreshToken, 3600*24*7, "/", "", false, true)
148
+ }
149
 
150
  utils.SendResponse[dto.AuthResponse, any](ctx, nil, dto.AuthResponse{
151
+ AccessToken: newAccessToken,
152
  }, nil)
153
  }
154
 
controllers/chat_controller.go CHANGED
@@ -64,7 +64,6 @@ func (c *chatController) FetchContacts(ctx *gin.Context) {
64
  // @Accept json
65
  // @Produce json
66
  // @Param request body dto.SendMessageRequest true "Send Message Request"
67
- // @Param X-CSRF-Token header string true "CSRF Protection Token"
68
  // @Success 200 {object} dto.SendMessageResponse
69
  // @Failure 401 {object} dto.ErrorResponse
70
  // @Failure 400 {object} dto.ErrorResponse
 
64
  // @Accept json
65
  // @Produce json
66
  // @Param request body dto.SendMessageRequest true "Send Message Request"
 
67
  // @Success 200 {object} dto.SendMessageResponse
68
  // @Failure 401 {object} dto.ErrorResponse
69
  // @Failure 400 {object} dto.ErrorResponse
controllers/connection_controller.go CHANGED
@@ -33,7 +33,6 @@ func NewConnectionController(connectionService services.ConnectionService) Conne
33
  // @Accept json
34
  // @Produce json
35
  // @Param request body dto.ConnectRequest true "Connect Request"
36
- // @Param X-CSRF-Token header string true "CSRF Protection Token"
37
  // @Success 200 {object} dto.ConnectResponse
38
  // @Failure 401 {object} dto.ErrorResponse
39
  // @Failure 500 {object} dto.ErrorResponse
 
33
  // @Accept json
34
  // @Produce json
35
  // @Param request body dto.ConnectRequest true "Connect Request"
 
36
  // @Success 200 {object} dto.ConnectResponse
37
  // @Failure 401 {object} dto.ErrorResponse
38
  // @Failure 500 {object} dto.ErrorResponse
docs/docs.go CHANGED
@@ -103,6 +103,28 @@ const docTemplate = `{
103
  }
104
  }
105
  },
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
106
  "/admin/update": {
107
  "post": {
108
  "security": [
@@ -345,7 +367,7 @@ const docTemplate = `{
345
  }
346
  }
347
  },
348
- "/chat/fetch": {
349
  "get": {
350
  "security": [
351
  {
@@ -412,13 +434,6 @@ const docTemplate = `{
412
  "schema": {
413
  "$ref": "#/definitions/dto.SendMessageRequest"
414
  }
415
- },
416
- {
417
- "type": "string",
418
- "description": "CSRF Protection Token",
419
- "name": "X-CSRF-Token",
420
- "in": "header",
421
- "required": true
422
  }
423
  ],
424
  "responses": {
@@ -470,13 +485,6 @@ const docTemplate = `{
470
  "schema": {
471
  "$ref": "#/definitions/dto.ConnectRequest"
472
  }
473
- },
474
- {
475
- "type": "string",
476
- "description": "CSRF Protection Token",
477
- "name": "X-CSRF-Token",
478
- "in": "header",
479
- "required": true
480
  }
481
  ],
482
  "responses": {
@@ -561,7 +569,10 @@ const docTemplate = `{
561
  "dto.AuthResponse": {
562
  "type": "object",
563
  "properties": {
564
- "token": {
 
 
 
565
  "type": "string"
566
  },
567
  "user_id": {
@@ -712,6 +723,14 @@ const docTemplate = `{
712
  }
713
  }
714
  },
 
 
 
 
 
 
 
 
715
  "dto.RegisterRequest": {
716
  "type": "object",
717
  "required": [
@@ -808,7 +827,7 @@ const docTemplate = `{
808
  // SwaggerInfo holds exported Swagger Info so clients can modify it
809
  var SwaggerInfo = &swag.Spec{
810
  Version: "1.0",
811
- Host: "localhost:8080",
812
  BasePath: "/api",
813
  Schemes: []string{},
814
  Title: "Whatsapp Backend API",
 
103
  }
104
  }
105
  },
106
+ "/admin/register_enabled": {
107
+ "get": {
108
+ "security": [
109
+ {
110
+ "BearerAuth": []
111
+ }
112
+ ],
113
+ "description": "Check if user registration is enabled",
114
+ "tags": [
115
+ "admin"
116
+ ],
117
+ "summary": "Check if registration is enabled",
118
+ "responses": {
119
+ "200": {
120
+ "description": "OK",
121
+ "schema": {
122
+ "$ref": "#/definitions/dto.RegisterEnabledResponse"
123
+ }
124
+ }
125
+ }
126
+ }
127
+ },
128
  "/admin/update": {
129
  "post": {
130
  "security": [
 
367
  }
368
  }
369
  },
370
+ "/chat/contacts": {
371
  "get": {
372
  "security": [
373
  {
 
434
  "schema": {
435
  "$ref": "#/definitions/dto.SendMessageRequest"
436
  }
 
 
 
 
 
 
 
437
  }
438
  ],
439
  "responses": {
 
485
  "schema": {
486
  "$ref": "#/definitions/dto.ConnectRequest"
487
  }
 
 
 
 
 
 
 
488
  }
489
  ],
490
  "responses": {
 
569
  "dto.AuthResponse": {
570
  "type": "object",
571
  "properties": {
572
+ "access_token": {
573
+ "type": "string"
574
+ },
575
+ "success_msg": {
576
  "type": "string"
577
  },
578
  "user_id": {
 
723
  }
724
  }
725
  },
726
+ "dto.RegisterEnabledResponse": {
727
+ "type": "object",
728
+ "properties": {
729
+ "register": {
730
+ "type": "boolean"
731
+ }
732
+ }
733
+ },
734
  "dto.RegisterRequest": {
735
  "type": "object",
736
  "required": [
 
827
  // SwaggerInfo holds exported Swagger Info so clients can modify it
828
  var SwaggerInfo = &swag.Spec{
829
  Version: "1.0",
830
+ Host: "",
831
  BasePath: "/api",
832
  Schemes: []string{},
833
  Title: "Whatsapp Backend API",
docs/swagger.json CHANGED
@@ -15,7 +15,6 @@
15
  },
16
  "version": "1.0"
17
  },
18
- "host": "localhost:8080",
19
  "basePath": "/api",
20
  "paths": {
21
  "/admin/create": {
@@ -97,6 +96,28 @@
97
  }
98
  }
99
  },
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
100
  "/admin/update": {
101
  "post": {
102
  "security": [
@@ -339,7 +360,7 @@
339
  }
340
  }
341
  },
342
- "/chat/fetch": {
343
  "get": {
344
  "security": [
345
  {
@@ -406,13 +427,6 @@
406
  "schema": {
407
  "$ref": "#/definitions/dto.SendMessageRequest"
408
  }
409
- },
410
- {
411
- "type": "string",
412
- "description": "CSRF Protection Token",
413
- "name": "X-CSRF-Token",
414
- "in": "header",
415
- "required": true
416
  }
417
  ],
418
  "responses": {
@@ -464,13 +478,6 @@
464
  "schema": {
465
  "$ref": "#/definitions/dto.ConnectRequest"
466
  }
467
- },
468
- {
469
- "type": "string",
470
- "description": "CSRF Protection Token",
471
- "name": "X-CSRF-Token",
472
- "in": "header",
473
- "required": true
474
  }
475
  ],
476
  "responses": {
@@ -555,7 +562,10 @@
555
  "dto.AuthResponse": {
556
  "type": "object",
557
  "properties": {
558
- "token": {
 
 
 
559
  "type": "string"
560
  },
561
  "user_id": {
@@ -706,6 +716,14 @@
706
  }
707
  }
708
  },
 
 
 
 
 
 
 
 
709
  "dto.RegisterRequest": {
710
  "type": "object",
711
  "required": [
 
15
  },
16
  "version": "1.0"
17
  },
 
18
  "basePath": "/api",
19
  "paths": {
20
  "/admin/create": {
 
96
  }
97
  }
98
  },
99
+ "/admin/register_enabled": {
100
+ "get": {
101
+ "security": [
102
+ {
103
+ "BearerAuth": []
104
+ }
105
+ ],
106
+ "description": "Check if user registration is enabled",
107
+ "tags": [
108
+ "admin"
109
+ ],
110
+ "summary": "Check if registration is enabled",
111
+ "responses": {
112
+ "200": {
113
+ "description": "OK",
114
+ "schema": {
115
+ "$ref": "#/definitions/dto.RegisterEnabledResponse"
116
+ }
117
+ }
118
+ }
119
+ }
120
+ },
121
  "/admin/update": {
122
  "post": {
123
  "security": [
 
360
  }
361
  }
362
  },
363
+ "/chat/contacts": {
364
  "get": {
365
  "security": [
366
  {
 
427
  "schema": {
428
  "$ref": "#/definitions/dto.SendMessageRequest"
429
  }
 
 
 
 
 
 
 
430
  }
431
  ],
432
  "responses": {
 
478
  "schema": {
479
  "$ref": "#/definitions/dto.ConnectRequest"
480
  }
 
 
 
 
 
 
 
481
  }
482
  ],
483
  "responses": {
 
562
  "dto.AuthResponse": {
563
  "type": "object",
564
  "properties": {
565
+ "access_token": {
566
+ "type": "string"
567
+ },
568
+ "success_msg": {
569
  "type": "string"
570
  },
571
  "user_id": {
 
716
  }
717
  }
718
  },
719
+ "dto.RegisterEnabledResponse": {
720
+ "type": "object",
721
+ "properties": {
722
+ "register": {
723
+ "type": "boolean"
724
+ }
725
+ }
726
+ },
727
  "dto.RegisterRequest": {
728
  "type": "object",
729
  "required": [
docs/swagger.yaml CHANGED
@@ -12,7 +12,9 @@ definitions:
12
  type: object
13
  dto.AuthResponse:
14
  properties:
15
- token:
 
 
16
  type: string
17
  user_id:
18
  type: string
@@ -112,6 +114,11 @@ definitions:
112
  username:
113
  type: string
114
  type: object
 
 
 
 
 
115
  dto.RegisterRequest:
116
  properties:
117
  password:
@@ -168,7 +175,6 @@ definitions:
168
  username:
169
  type: string
170
  type: object
171
- host: localhost:8080
172
  info:
173
  contact:
174
  email: support@swagger.io
@@ -231,6 +237,19 @@ paths:
231
  summary: Delete a user (Admin)
232
  tags:
233
  - admin
 
 
 
 
 
 
 
 
 
 
 
 
 
234
  /admin/update:
235
  post:
236
  consumes:
@@ -382,7 +401,7 @@ paths:
382
  summary: Register a new user
383
  tags:
384
  - auth
385
- /chat/fetch:
386
  get:
387
  consumes:
388
  - application/json
@@ -419,11 +438,6 @@ paths:
419
  required: true
420
  schema:
421
  $ref: '#/definitions/dto.SendMessageRequest'
422
- - description: CSRF Protection Token
423
- in: header
424
- name: X-CSRF-Token
425
- required: true
426
- type: string
427
  produces:
428
  - application/json
429
  responses:
@@ -457,11 +471,6 @@ paths:
457
  required: true
458
  schema:
459
  $ref: '#/definitions/dto.ConnectRequest'
460
- - description: CSRF Protection Token
461
- in: header
462
- name: X-CSRF-Token
463
- required: true
464
- type: string
465
  produces:
466
  - application/json
467
  responses:
 
12
  type: object
13
  dto.AuthResponse:
14
  properties:
15
+ access_token:
16
+ type: string
17
+ success_msg:
18
  type: string
19
  user_id:
20
  type: string
 
114
  username:
115
  type: string
116
  type: object
117
+ dto.RegisterEnabledResponse:
118
+ properties:
119
+ register:
120
+ type: boolean
121
+ type: object
122
  dto.RegisterRequest:
123
  properties:
124
  password:
 
175
  username:
176
  type: string
177
  type: object
 
178
  info:
179
  contact:
180
  email: support@swagger.io
 
237
  summary: Delete a user (Admin)
238
  tags:
239
  - admin
240
+ /admin/register_enabled:
241
+ get:
242
+ description: Check if user registration is enabled
243
+ responses:
244
+ "200":
245
+ description: OK
246
+ schema:
247
+ $ref: '#/definitions/dto.RegisterEnabledResponse'
248
+ security:
249
+ - BearerAuth: []
250
+ summary: Check if registration is enabled
251
+ tags:
252
+ - admin
253
  /admin/update:
254
  post:
255
  consumes:
 
401
  summary: Register a new user
402
  tags:
403
  - auth
404
+ /chat/contacts:
405
  get:
406
  consumes:
407
  - application/json
 
438
  required: true
439
  schema:
440
  $ref: '#/definitions/dto.SendMessageRequest'
 
 
 
 
 
441
  produces:
442
  - application/json
443
  responses:
 
471
  required: true
472
  schema:
473
  $ref: '#/definitions/dto.ConnectRequest'
 
 
 
 
 
474
  produces:
475
  - application/json
476
  responses:
middleware/auth_middleware.go CHANGED
@@ -44,12 +44,6 @@ func (m *authMiddleware) RequireAuth() gin.HandlerFunc {
44
  return
45
  }
46
 
47
- if m.authRepo.IsTokenRevoked(tokenString) {
48
- utils.SendResponse[any, any](ctx, nil, nil, http_error.UNAUTHORIZED)
49
- ctx.Abort()
50
- return
51
- }
52
-
53
  token, err := jwt.ParseWithClaims(tokenString, &utils.JWTClaims{}, func(token *jwt.Token) (interface{}, error) {
54
  return []byte(m.jwtConfig.GetSecretKey()), nil
55
  })
 
44
  return
45
  }
46
 
 
 
 
 
 
 
47
  token, err := jwt.ParseWithClaims(tokenString, &utils.JWTClaims{}, func(token *jwt.Token) (interface{}, error) {
48
  return []byte(m.jwtConfig.GetSecretKey()), nil
49
  })
models/dto/auth_dto.go CHANGED
@@ -13,10 +13,23 @@ type LoginRequest struct {
13
  }
14
 
15
  type AuthResponse struct {
16
- Token string `json:"token,omitempty"`
 
17
  RefreshToken string `json:"-"`
18
- UserID uuid.UUID `json:"user_id"`
19
- Username string `json:"username"`
 
 
 
 
 
 
 
 
 
 
 
 
20
  }
21
 
22
  type MeResponse struct {
 
13
  }
14
 
15
  type AuthResponse struct {
16
+ AccessToken string `json:"access_token,omitempty"`
17
+ SuccessMsg string `json:"success_msg,omitempty"`
18
  RefreshToken string `json:"-"`
19
+ UserID uuid.UUID `json:"user_id,omitempty"`
20
+ Username string `json:"username,omitempty"`
21
+ }
22
+
23
+ type RegisterEnabledResponse struct {
24
+ Register bool `json:"register"`
25
+ }
26
+
27
+ type LogoutResponse struct {
28
+ SuccessMsg string `json:"success_msg"`
29
+ }
30
+
31
+ type SetRegistrationRequest struct {
32
+ Enabled bool `json:"enabled"`
33
  }
34
 
35
  type MeResponse struct {
models/entity/entity.go CHANGED
@@ -31,7 +31,6 @@ type User struct {
31
  DeletedAt gorm.DeletedAt `gorm:"index" json:"deleted_at"`
32
  }
33
 
34
-
35
  func (User) TableName() string {
36
  return "users"
37
  }
@@ -48,13 +47,11 @@ func (RefreshToken) TableName() string {
48
  return "refresh_tokens"
49
  }
50
 
51
- type RevokedToken struct {
52
- ID uuid.UUID `gorm:"primaryKey;type:uuid;default:gen_random_uuid()" json:"id"`
53
- Token string `gorm:"uniqueIndex;not null" json:"token"`
54
- RevokedAt time.Time `json:"revoked_at"`
55
- ExpiresAt time.Time `json:"expires_at"`
56
  }
57
 
58
- func (RevokedToken) TableName() string {
59
- return "revoked_tokens"
60
  }
 
31
  DeletedAt gorm.DeletedAt `gorm:"index" json:"deleted_at"`
32
  }
33
 
 
34
  func (User) TableName() string {
35
  return "users"
36
  }
 
47
  return "refresh_tokens"
48
  }
49
 
50
+ type Settings struct {
51
+ ID uint `gorm:"primaryKey" json:"id"`
52
+ RegistrationEnabled bool `gorm:"default:true" json:"registration_enabled"`
 
 
53
  }
54
 
55
+ func (Settings) TableName() string {
56
+ return "settings"
57
  }
models/error/error.go CHANGED
@@ -32,6 +32,7 @@ var (
32
  ERR_TOKEN_GENERATION_FAILED = errors.New("Failed to generate token")
33
  ERR_USER_NOT_FOUND = errors.New("User not found")
34
  ERR_WRONG_PASSWORD = errors.New("Wrong password")
 
35
 
36
  // WhatsApp Connection Errors
37
  ERR_INVALID_ACCOUNT_ID = errors.New("Invalid account ID format")
 
32
  ERR_TOKEN_GENERATION_FAILED = errors.New("Failed to generate token")
33
  ERR_USER_NOT_FOUND = errors.New("User not found")
34
  ERR_WRONG_PASSWORD = errors.New("Wrong password")
35
+ ERR_REGISTRATION_DISABLED = errors.New("Registration is currently disabled")
36
 
37
  // WhatsApp Connection Errors
38
  ERR_INVALID_ACCOUNT_ID = errors.New("Invalid account ID format")
provider/provider.go CHANGED
@@ -35,8 +35,8 @@ func NewAppProvider() AppProvider {
35
  _ = configProvider.ProvideDatabaseConfig().AutoMigrateAll(
36
  &entity.WhatsAppAccount{},
37
  &entity.User{},
38
- &entity.RevokedToken{},
39
  &entity.RefreshToken{},
 
40
  )
41
 
42
  return &appProvider{
 
35
  _ = configProvider.ProvideDatabaseConfig().AutoMigrateAll(
36
  &entity.WhatsAppAccount{},
37
  &entity.User{},
 
38
  &entity.RefreshToken{},
39
+ &entity.Settings{},
40
  )
41
 
42
  return &appProvider{
provider/services_provider.go CHANGED
@@ -18,9 +18,9 @@ type servicesProvider struct {
18
 
19
  func NewServicesProvider(repoProvider RepositoriesProvider, configProvider ConfigProvider) ServicesProvider {
20
  connectionService := services.NewConnectionService(repoProvider.ProvideConnectionRepository())
21
- authService := services.NewAuthService(repoProvider.ProvideAuthRepository(), repoProvider.ProvideConnectionRepository(), configProvider.ProvideJWTConfig())
22
  chatService := services.NewChatService(connectionService, repoProvider.ProvideChatRepository())
23
- adminService := services.NewAdminService(repoProvider.ProvideAuthRepository())
24
 
25
  return &servicesProvider{
26
  connectionService: connectionService,
 
18
 
19
  func NewServicesProvider(repoProvider RepositoriesProvider, configProvider ConfigProvider) ServicesProvider {
20
  connectionService := services.NewConnectionService(repoProvider.ProvideConnectionRepository())
21
+ authService := services.NewAuthService(repoProvider.ProvideAuthRepository(), repoProvider.ProvideConnectionRepository(), configProvider.ProvideJWTConfig(), configProvider.ProvideEnvConfig())
22
  chatService := services.NewChatService(connectionService, repoProvider.ProvideChatRepository())
23
+ adminService := services.NewAdminService(repoProvider.ProvideAuthRepository(), configProvider.ProvideEnvConfig())
24
 
25
  return &servicesProvider{
26
  connectionService: connectionService,
repositories/auth_repository.go CHANGED
@@ -12,13 +12,14 @@ type AuthRepository interface {
12
  CreateUser(user *entity.User) error
13
  FindUserByUsername(username string) (*entity.User, error)
14
  FindUserByID(id uuid.UUID) (*entity.User, error)
15
- RevokeToken(token string, expiresAt time.Time) error
16
- IsTokenRevoked(token string) bool
17
  StoreRefreshToken(userID uuid.UUID, token string, expiresAt time.Time) error
18
  GetRefreshToken(token string) (*entity.RefreshToken, error)
19
  RevokeRefreshToken(token string) error
 
20
  UpdateUser(user *entity.User) error
21
  DeleteUser(id uuid.UUID) error
 
 
22
  }
23
 
24
  type authRepository struct {
@@ -49,21 +50,6 @@ func (r *authRepository) FindUserByID(id uuid.UUID) (*entity.User, error) {
49
  return &user, nil
50
  }
51
 
52
- func (r *authRepository) RevokeToken(token string, expiresAt time.Time) error {
53
- revokedToken := entity.RevokedToken{
54
- Token: token,
55
- RevokedAt: time.Now(),
56
- ExpiresAt: expiresAt,
57
- }
58
- return r.db.Create(&revokedToken).Error
59
- }
60
-
61
- func (r *authRepository) IsTokenRevoked(token string) bool {
62
- var count int64
63
- r.db.Model(&entity.RevokedToken{}).Where("token = ?", token).Count(&count)
64
- return count > 0
65
- }
66
-
67
  func (r *authRepository) StoreRefreshToken(userID uuid.UUID, token string, expiresAt time.Time) error {
68
  refreshToken := entity.RefreshToken{
69
  UserID: userID,
@@ -86,6 +72,10 @@ func (r *authRepository) RevokeRefreshToken(token string) error {
86
  return r.db.Where("token = ?", token).Delete(&entity.RefreshToken{}).Error
87
  }
88
 
 
 
 
 
89
  func (r *authRepository) UpdateUser(user *entity.User) error {
90
  return r.db.Save(user).Error
91
  }
@@ -93,3 +83,22 @@ func (r *authRepository) UpdateUser(user *entity.User) error {
93
  func (r *authRepository) DeleteUser(id uuid.UUID) error {
94
  return r.db.Delete(&entity.User{}, id).Error
95
  }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
12
  CreateUser(user *entity.User) error
13
  FindUserByUsername(username string) (*entity.User, error)
14
  FindUserByID(id uuid.UUID) (*entity.User, error)
 
 
15
  StoreRefreshToken(userID uuid.UUID, token string, expiresAt time.Time) error
16
  GetRefreshToken(token string) (*entity.RefreshToken, error)
17
  RevokeRefreshToken(token string) error
18
+ RevokeAllUserRefreshTokens(userID uuid.UUID) error
19
  UpdateUser(user *entity.User) error
20
  DeleteUser(id uuid.UUID) error
21
+ GetSettings() (*entity.Settings, error)
22
+ SetRegistrationEnabled(enabled bool) error
23
  }
24
 
25
  type authRepository struct {
 
50
  return &user, nil
51
  }
52
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
53
  func (r *authRepository) StoreRefreshToken(userID uuid.UUID, token string, expiresAt time.Time) error {
54
  refreshToken := entity.RefreshToken{
55
  UserID: userID,
 
72
  return r.db.Where("token = ?", token).Delete(&entity.RefreshToken{}).Error
73
  }
74
 
75
+ func (r *authRepository) RevokeAllUserRefreshTokens(userID uuid.UUID) error {
76
+ return r.db.Where("user_id = ?", userID).Delete(&entity.RefreshToken{}).Error
77
+ }
78
+
79
  func (r *authRepository) UpdateUser(user *entity.User) error {
80
  return r.db.Save(user).Error
81
  }
 
83
  func (r *authRepository) DeleteUser(id uuid.UUID) error {
84
  return r.db.Delete(&entity.User{}, id).Error
85
  }
86
+
87
+ func (r *authRepository) GetSettings() (*entity.Settings, error) {
88
+ var settings entity.Settings
89
+ if err := r.db.First(&settings).Error; err != nil {
90
+ settings = entity.Settings{ID: 1, RegistrationEnabled: true}
91
+ r.db.Create(&settings)
92
+ }
93
+ return &settings, nil
94
+ }
95
+
96
+ func (r *authRepository) SetRegistrationEnabled(enabled bool) error {
97
+ var settings entity.Settings
98
+ if err := r.db.First(&settings).Error; err != nil {
99
+ settings = entity.Settings{ID: 1, RegistrationEnabled: enabled}
100
+ return r.db.Create(&settings).Error
101
+ }
102
+ settings.RegistrationEnabled = enabled
103
+ return r.db.Save(&settings).Error
104
+ }
router/admin_router.go CHANGED
@@ -18,5 +18,7 @@ func AdminRouter(router *gin.Engine, controller provider.ControllerProvider, mid
18
  routerGroup.POST("/create", adminController.CreateUser)
19
  routerGroup.POST("/update", adminController.UpdateUser)
20
  routerGroup.POST("/delete", adminController.DeleteUser)
 
 
21
  }
22
  }
 
18
  routerGroup.POST("/create", adminController.CreateUser)
19
  routerGroup.POST("/update", adminController.UpdateUser)
20
  routerGroup.POST("/delete", adminController.DeleteUser)
21
+ routerGroup.GET("/register_enabled", adminController.RegisterEnabled)
22
+ routerGroup.POST("/set_registration", adminController.SetRegistrationEnabled)
23
  }
24
  }
router/auth_router.go CHANGED
@@ -1,8 +1,9 @@
1
  package router
2
 
3
  import (
4
- "whatsapp-backend/provider"
5
  models "whatsapp-backend/models/entity"
 
 
6
  "github.com/gin-contrib/gzip"
7
  "github.com/gin-gonic/gin"
8
  )
@@ -15,7 +16,7 @@ func AuthRouter(router *gin.Engine, controller provider.ControllerProvider, midd
15
  routerGroup.POST("/register", authController.Register)
16
  routerGroup.POST("/login", authController.Login)
17
  routerGroup.POST("/logout", middleware.ProvideAuthMiddleware().RequireAuth(), authController.Logout)
18
- routerGroup.POST("/refresh", middleware.ProvideAuthMiddleware().RequireAuth(), authController.RefreshToken)
19
  routerGroup.GET("/me", middleware.ProvideAuthMiddleware().RequireAuth(), authController.Me)
20
  routerGroup.POST("/assign", middleware.ProvideAuthMiddleware().RequireAuth(), middleware.ProvideAuthMiddleware().RequireRole(models.RoleSuperAdmin), authController.AssignRole)
21
  }
 
1
  package router
2
 
3
  import (
 
4
  models "whatsapp-backend/models/entity"
5
+ "whatsapp-backend/provider"
6
+
7
  "github.com/gin-contrib/gzip"
8
  "github.com/gin-gonic/gin"
9
  )
 
16
  routerGroup.POST("/register", authController.Register)
17
  routerGroup.POST("/login", authController.Login)
18
  routerGroup.POST("/logout", middleware.ProvideAuthMiddleware().RequireAuth(), authController.Logout)
19
+ routerGroup.POST("/refresh", authController.RefreshToken)
20
  routerGroup.GET("/me", middleware.ProvideAuthMiddleware().RequireAuth(), authController.Me)
21
  routerGroup.POST("/assign", middleware.ProvideAuthMiddleware().RequireAuth(), middleware.ProvideAuthMiddleware().RequireRole(models.RoleSuperAdmin), authController.AssignRole)
22
  }
services/admin_service.go CHANGED
@@ -1,6 +1,7 @@
1
  package services
2
 
3
  import (
 
4
  "whatsapp-backend/models/dto"
5
  entity "whatsapp-backend/models/entity"
6
  http_error "whatsapp-backend/models/error"
@@ -14,15 +15,19 @@ type AdminService interface {
14
  CreateUser(req dto.CreateUserRequest) (*dto.UserResponse, error)
15
  UpdateUser(req dto.UpdateUserRequest) (*dto.UserResponse, error)
16
  DeleteUser(userID uuid.UUID) error
 
 
17
  }
18
 
19
  type adminService struct {
20
- authRepo repositories.AuthRepository
 
21
  }
22
 
23
- func NewAdminService(authRepo repositories.AuthRepository) AdminService {
24
  return &adminService{
25
- authRepo: authRepo,
 
26
  }
27
  }
28
 
@@ -88,3 +93,15 @@ func (s *adminService) DeleteUser(userID uuid.UUID) error {
88
  }
89
  return s.authRepo.DeleteUser(userID)
90
  }
 
 
 
 
 
 
 
 
 
 
 
 
 
1
  package services
2
 
3
  import (
4
+ "whatsapp-backend/config"
5
  "whatsapp-backend/models/dto"
6
  entity "whatsapp-backend/models/entity"
7
  http_error "whatsapp-backend/models/error"
 
15
  CreateUser(req dto.CreateUserRequest) (*dto.UserResponse, error)
16
  UpdateUser(req dto.UpdateUserRequest) (*dto.UserResponse, error)
17
  DeleteUser(userID uuid.UUID) error
18
+ IsRegisterEnabled() bool
19
+ SetRegistrationEnabled(enabled bool) error
20
  }
21
 
22
  type adminService struct {
23
+ authRepo repositories.AuthRepository
24
+ envConfig config.EnvConfig
25
  }
26
 
27
+ func NewAdminService(authRepo repositories.AuthRepository, envConfig config.EnvConfig) AdminService {
28
  return &adminService{
29
+ authRepo: authRepo,
30
+ envConfig: envConfig,
31
  }
32
  }
33
 
 
93
  }
94
  return s.authRepo.DeleteUser(userID)
95
  }
96
+
97
+ func (s *adminService) IsRegisterEnabled() bool {
98
+ settings, _ := s.authRepo.GetSettings()
99
+ if settings == nil {
100
+ return true
101
+ }
102
+ return settings.RegistrationEnabled
103
+ }
104
+
105
+ func (s *adminService) SetRegistrationEnabled(enabled bool) error {
106
+ return s.authRepo.SetRegistrationEnabled(enabled)
107
+ }
services/auth_service.go CHANGED
@@ -26,17 +26,25 @@ type authService struct {
26
  authRepo repositories.AuthRepository
27
  connectionRepo repositories.ConnectionRepository
28
  jwtConfig config.JWTConfig
 
29
  }
30
 
31
- func NewAuthService(authRepo repositories.AuthRepository, connectionRepo repositories.ConnectionRepository, jwtConfig config.JWTConfig) AuthService {
32
  return &authService{
33
  authRepo: authRepo,
34
  connectionRepo: connectionRepo,
35
  jwtConfig: jwtConfig,
 
36
  }
37
  }
38
 
39
  func (s *authService) Register(req dto.RegisterRequest) (*dto.AuthResponse, error) {
 
 
 
 
 
 
40
  if _, err := s.authRepo.FindUserByUsername(req.Username); err == nil {
41
  return nil, http_error.ERR_USER_ALREADY_EXISTS
42
  }
@@ -66,12 +74,16 @@ func (s *authService) Register(req dto.RegisterRequest) (*dto.AuthResponse, erro
66
  return nil, http_error.ERR_TOKEN_GENERATION_FAILED
67
  }
68
 
 
 
 
69
  if err := s.authRepo.StoreRefreshToken(user.ID, refreshToken, time.Now().Add(time.Hour*24*7)); err != nil {
70
  return nil, err
71
  }
72
 
73
  return &dto.AuthResponse{
74
- Token: accessToken,
 
75
  RefreshToken: refreshToken,
76
  UserID: user.ID,
77
  Username: user.Username,
@@ -98,12 +110,16 @@ func (s *authService) Login(req dto.LoginRequest) (*dto.AuthResponse, error) {
98
  return nil, http_error.ERR_TOKEN_GENERATION_FAILED
99
  }
100
 
 
 
 
101
  if err := s.authRepo.StoreRefreshToken(user.ID, refreshToken, time.Now().Add(time.Hour*24*7)); err != nil {
102
  return nil, err
103
  }
104
 
105
  return &dto.AuthResponse{
106
- Token: accessToken,
 
107
  RefreshToken: refreshToken,
108
  UserID: user.ID,
109
  Username: user.Username,
@@ -141,9 +157,6 @@ func (s *authService) GetMe(userID uuid.UUID) (*dto.MeResponse, error) {
141
  }
142
 
143
  func (s *authService) Logout(token, refreshToken string) error {
144
- accessExpiresAt := time.Now().Add(time.Minute * 15)
145
- _ = s.authRepo.RevokeToken(token, accessExpiresAt)
146
-
147
  if refreshToken != "" {
148
  return s.authRepo.RevokeRefreshToken(refreshToken)
149
  }
@@ -166,7 +179,17 @@ func (s *authService) RefreshToken(refreshToken string) (string, string, error)
166
  return "", "", http_error.ERR_TOKEN_GENERATION_FAILED
167
  }
168
 
169
- return newAccessToken, refreshToken, nil
 
 
 
 
 
 
 
 
 
 
170
  }
171
 
172
  func (s *authService) AssignRole(userID uuid.UUID, role string) error {
 
26
  authRepo repositories.AuthRepository
27
  connectionRepo repositories.ConnectionRepository
28
  jwtConfig config.JWTConfig
29
+ envConfig config.EnvConfig
30
  }
31
 
32
+ func NewAuthService(authRepo repositories.AuthRepository, connectionRepo repositories.ConnectionRepository, jwtConfig config.JWTConfig, envConfig config.EnvConfig) AuthService {
33
  return &authService{
34
  authRepo: authRepo,
35
  connectionRepo: connectionRepo,
36
  jwtConfig: jwtConfig,
37
+ envConfig: envConfig,
38
  }
39
  }
40
 
41
  func (s *authService) Register(req dto.RegisterRequest) (*dto.AuthResponse, error) {
42
+ // Check if registration is enabled
43
+ settings, _ := s.authRepo.GetSettings()
44
+ if settings != nil && !settings.RegistrationEnabled {
45
+ return nil, http_error.ERR_REGISTRATION_DISABLED
46
+ }
47
+
48
  if _, err := s.authRepo.FindUserByUsername(req.Username); err == nil {
49
  return nil, http_error.ERR_USER_ALREADY_EXISTS
50
  }
 
74
  return nil, http_error.ERR_TOKEN_GENERATION_FAILED
75
  }
76
 
77
+ // Revoke any existing refresh tokens for this user
78
+ _ = s.authRepo.RevokeAllUserRefreshTokens(user.ID)
79
+
80
  if err := s.authRepo.StoreRefreshToken(user.ID, refreshToken, time.Now().Add(time.Hour*24*7)); err != nil {
81
  return nil, err
82
  }
83
 
84
  return &dto.AuthResponse{
85
+ AccessToken: accessToken,
86
+ SuccessMsg: "Registration successful",
87
  RefreshToken: refreshToken,
88
  UserID: user.ID,
89
  Username: user.Username,
 
110
  return nil, http_error.ERR_TOKEN_GENERATION_FAILED
111
  }
112
 
113
+ // Revoke any existing refresh tokens for this user
114
+ _ = s.authRepo.RevokeAllUserRefreshTokens(user.ID)
115
+
116
  if err := s.authRepo.StoreRefreshToken(user.ID, refreshToken, time.Now().Add(time.Hour*24*7)); err != nil {
117
  return nil, err
118
  }
119
 
120
  return &dto.AuthResponse{
121
+ AccessToken: accessToken,
122
+ SuccessMsg: "Login successful",
123
  RefreshToken: refreshToken,
124
  UserID: user.ID,
125
  Username: user.Username,
 
157
  }
158
 
159
  func (s *authService) Logout(token, refreshToken string) error {
 
 
 
160
  if refreshToken != "" {
161
  return s.authRepo.RevokeRefreshToken(refreshToken)
162
  }
 
179
  return "", "", http_error.ERR_TOKEN_GENERATION_FAILED
180
  }
181
 
182
+ // Only rotate refresh token if it's close to expiring (within 1 day)
183
+ newRefreshToken := ""
184
+ if time.Until(storedToken.ExpiresAt) < 24*time.Hour {
185
+ newRefreshToken, _ = utils.GenerateRefreshToken()
186
+ if newRefreshToken != "" {
187
+ _ = s.authRepo.RevokeRefreshToken(refreshToken)
188
+ _ = s.authRepo.StoreRefreshToken(user.ID, newRefreshToken, time.Now().Add(time.Hour*24*7))
189
+ }
190
+ }
191
+
192
+ return newAccessToken, newRefreshToken, nil
193
  }
194
 
195
  func (s *authService) AssignRole(userID uuid.UUID, role string) error {