Spaces:
Runtime error
Runtime error
RyZ commited on
Commit ·
f7fe55b
1
Parent(s): 75af2b7
fix: fixing auth logic
Browse files- config/env_config.go +6 -0
- controllers/admin_controller.go +41 -0
- controllers/auth_controller.go +16 -12
- controllers/chat_controller.go +0 -1
- controllers/connection_controller.go +0 -1
- docs/docs.go +36 -17
- docs/swagger.json +35 -17
- docs/swagger.yaml +22 -13
- middleware/auth_middleware.go +0 -6
- models/dto/auth_dto.go +16 -3
- models/entity/entity.go +5 -8
- models/error/error.go +1 -0
- provider/provider.go +1 -1
- provider/services_provider.go +2 -2
- repositories/auth_repository.go +26 -17
- router/admin_router.go +2 -0
- router/auth_router.go +3 -2
- services/admin_service.go +20 -3
- services/auth_service.go +30 -7
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.
|
| 56 |
-
ctx.SetCookie("RefreshToken", resp.RefreshToken, 3600*24*7, "/
|
| 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.
|
| 85 |
-
ctx.SetCookie("RefreshToken", resp.RefreshToken, 3600*24*7, "/
|
| 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.
|
| 116 |
-
ctx.
|
| 117 |
-
|
| 118 |
-
|
|
|
|
| 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, "/
|
| 139 |
utils.SendResponse[any, any](ctx, nil, nil, err)
|
| 140 |
return
|
| 141 |
}
|
| 142 |
|
| 143 |
-
|
| 144 |
-
|
|
|
|
|
|
|
|
|
|
| 145 |
|
| 146 |
utils.SendResponse[dto.AuthResponse, any](ctx, nil, dto.AuthResponse{
|
| 147 |
-
|
| 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/
|
| 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 |
-
"
|
|
|
|
|
|
|
|
|
|
| 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: "
|
| 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/
|
| 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 |
-
"
|
|
|
|
|
|
|
|
|
|
| 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 |
-
|
|
|
|
|
|
|
| 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/
|
| 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 |
-
|
|
|
|
| 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
|
| 52 |
-
ID
|
| 53 |
-
|
| 54 |
-
RevokedAt time.Time `json:"revoked_at"`
|
| 55 |
-
ExpiresAt time.Time `json:"expires_at"`
|
| 56 |
}
|
| 57 |
|
| 58 |
-
func (
|
| 59 |
-
return "
|
| 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",
|
| 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
|
|
|
|
| 21 |
}
|
| 22 |
|
| 23 |
-
func NewAdminService(authRepo repositories.AuthRepository) AdminService {
|
| 24 |
return &adminService{
|
| 25 |
-
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 |
-
|
|
|
|
| 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 |
-
|
|
|
|
| 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 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 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 {
|