Skip to content

Commit 68967a7

Browse files
committed
[otp] separate package from the auth
1 parent 7ebb0c7 commit 68967a7

File tree

16 files changed

+221
-68
lines changed

16 files changed

+221
-68
lines changed

api/mobile.http

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,8 @@ Authorization: Bearer {{mobileToken}}
99

1010
###
1111
GET {{baseUrl}}/user/code HTTP/1.1
12-
Authorization: Bearer {{mobileToken}}
12+
Authorization: Basic {{credentials}}
13+
# Authorization: Bearer {{mobileToken}}
1314

1415
###
1516
POST {{baseUrl}}/device HTTP/1.1

configs/config.example.yml

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -38,6 +38,9 @@ cache: # cache config
3838
url: memory:// # cache url (memory:// or redis://) [CACHE__URL]
3939
pubsub: # pubsub config
4040
url: memory:// # pubsub url (memory:// or redis://) [PUBSUB__URL]
41+
otp: # otp config
42+
ttl: 300 # otp ttl in seconds [OTP__TTL]
43+
retries: 3 # otp generation retries [OTP__RETRIES]
4144

4245
## Worker Config ##
4346

internal/config/config.go

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@ type Config struct {
1717
Messages Messages `yaml:"messages"` // messages config
1818
Cache Cache `yaml:"cache"` // cache (memory or redis) config
1919
PubSub PubSub `yaml:"pubsub"` // pubsub (memory or redis) config
20+
OTP OTP `yaml:"otp"` // one-time password config
2021
}
2122

2223
type Gateway struct {
@@ -85,6 +86,11 @@ type PubSub struct {
8586
URL string `yaml:"url" envconfig:"PUBSUB__URL"`
8687
}
8788

89+
type OTP struct {
90+
TTL uint16 `yaml:"ttl" envconfig:"OTP__TTL"`
91+
Retries uint8 `yaml:"retries" envconfig:"OTP__RETRIES"`
92+
}
93+
8894
var defaultConfig = Config{
8995
Gateway: Gateway{Mode: GatewayModePublic},
9096
HTTP: HTTP{
@@ -119,4 +125,8 @@ var defaultConfig = Config{
119125
PubSub: PubSub{
120126
URL: "memory://",
121127
},
128+
OTP: OTP{
129+
TTL: 300,
130+
Retries: 3,
131+
},
122132
}

internal/config/module.go

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@ import (
1111
"github.com/android-sms-gateway/server/internal/sms-gateway/modules/messages"
1212
"github.com/android-sms-gateway/server/internal/sms-gateway/modules/push"
1313
"github.com/android-sms-gateway/server/internal/sms-gateway/modules/sse"
14+
"github.com/android-sms-gateway/server/internal/sms-gateway/otp"
1415
"github.com/android-sms-gateway/server/internal/sms-gateway/pubsub"
1516
"github.com/capcom6/go-infra-fx/config"
1617
"github.com/capcom6/go-infra-fx/db"
@@ -124,4 +125,10 @@ var Module = fx.Module(
124125
BufferSize: 128,
125126
}
126127
}),
128+
fx.Provide(func(cfg Config) otp.Config {
129+
return otp.Config{
130+
TTL: time.Duration(cfg.OTP.TTL) * time.Second,
131+
Retries: int(cfg.OTP.Retries),
132+
}
133+
}),
127134
)

internal/sms-gateway/app.go

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@ import (
1919
"github.com/android-sms-gateway/server/internal/sms-gateway/modules/webhooks"
2020
"github.com/android-sms-gateway/server/internal/sms-gateway/online"
2121
"github.com/android-sms-gateway/server/internal/sms-gateway/openapi"
22+
"github.com/android-sms-gateway/server/internal/sms-gateway/otp"
2223
"github.com/android-sms-gateway/server/internal/sms-gateway/pubsub"
2324
"github.com/android-sms-gateway/server/pkg/health"
2425
"github.com/capcom6/go-infra-fx/cli"
@@ -53,6 +54,7 @@ var Module = fx.Module(
5354
metrics.Module,
5455
sse.Module,
5556
online.Module(),
57+
otp.Module(),
5658
)
5759

5860
func Run() {

internal/sms-gateway/handlers/middlewares/userauth/userauth.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -72,7 +72,7 @@ func NewCode(authSvc *auth.Service) fiber.Handler {
7272
// Get the code
7373
code := auth[5:]
7474

75-
user, err := authSvc.AuthorizeUserByCode(code)
75+
user, err := authSvc.AuthorizeUserByCode(c.Context(), code)
7676
if err != nil {
7777
return fiber.ErrUnauthorized
7878
}

internal/sms-gateway/handlers/mobile.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -176,7 +176,7 @@ func (h *mobileHandler) patchDevice(device models.Device, c *fiber.Ctx) error {
176176
//
177177
// Get user code
178178
func (h *mobileHandler) getUserCode(user models.User, c *fiber.Ctx) error {
179-
code, err := h.authSvc.GenerateUserCode(user.ID)
179+
code, err := h.authSvc.GenerateUserCode(c.Context(), user.ID)
180180
if err != nil {
181181
return err
182182
}

internal/sms-gateway/modules/auth/module.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -12,8 +12,8 @@ var Module = fx.Module(
1212
fx.Decorate(func(log *zap.Logger) *zap.Logger {
1313
return log.Named("auth")
1414
}),
15-
fx.Provide(New),
1615
fx.Provide(newRepository, fx.Private),
16+
fx.Provide(New),
1717
fx.Invoke(func(lc fx.Lifecycle, svc *Service) {
1818
ctx, cancel := context.WithCancel(context.Background())
1919
lc.Append(fx.Hook{

internal/sms-gateway/modules/auth/service.go

Lines changed: 32 additions & 54 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,6 @@ package auth
22

33
import (
44
"context"
5-
"crypto/rand"
65
"crypto/sha256"
76
"crypto/subtle"
87
"encoding/hex"
@@ -12,10 +11,10 @@ import (
1211
"github.com/android-sms-gateway/server/internal/sms-gateway/models"
1312
"github.com/android-sms-gateway/server/internal/sms-gateway/modules/devices"
1413
"github.com/android-sms-gateway/server/internal/sms-gateway/online"
14+
"github.com/android-sms-gateway/server/internal/sms-gateway/otp"
1515
"github.com/android-sms-gateway/server/pkg/crypto"
1616
"github.com/capcom6/go-helpers/cache"
1717
"github.com/jaevor/go-nanoid"
18-
"go.uber.org/fx"
1918
"go.uber.org/zap"
2019
)
2120

@@ -24,75 +23,55 @@ type Config struct {
2423
PrivateToken string
2524
}
2625

27-
type Params struct {
28-
fx.In
29-
30-
Config Config
31-
32-
Users *repository
33-
DevicesSvc *devices.Service
34-
OnlineSvc online.Service
35-
36-
Logger *zap.Logger
37-
}
38-
3926
type Service struct {
4027
config Config
4128

42-
users *repository
43-
codesCache *cache.Cache[string]
44-
usersCache *cache.Cache[models.User]
29+
users *repository
4530

31+
otpSvc *otp.Service
4632
devicesSvc *devices.Service
4733
onlineSvc online.Service
4834

4935
logger *zap.Logger
5036

51-
idgen func() string
37+
idgen func() string
38+
usersCache *cache.Cache[models.User]
5239
}
5340

54-
func New(params Params) *Service {
41+
func New(
42+
config Config,
43+
users *repository,
44+
otpSvc *otp.Service,
45+
devicesSvc *devices.Service,
46+
onlineSvc online.Service,
47+
logger *zap.Logger,
48+
) *Service {
5549
idgen, _ := nanoid.Standard(21)
5650

5751
return &Service{
58-
config: params.Config,
59-
users: params.Users,
60-
devicesSvc: params.DevicesSvc,
61-
onlineSvc: params.OnlineSvc,
62-
logger: params.Logger,
63-
idgen: idgen,
52+
config: config,
6453

65-
codesCache: cache.New[string](cache.Config{}),
66-
usersCache: cache.New[models.User](cache.Config{TTL: 1 * time.Hour}),
67-
}
68-
}
54+
users: users,
6955

70-
// GenerateUserCode generates a unique one-time user authorization code
71-
func (s *Service) GenerateUserCode(userID string) (AuthCode, error) {
72-
var code string
73-
var err error
74-
75-
b := make([]byte, 3)
76-
validUntil := time.Now().Add(codeTTL)
77-
for range 3 {
78-
if _, err = rand.Read(b); err != nil {
79-
continue
80-
}
81-
num := (int(b[0]) << 16) | (int(b[1]) << 8) | int(b[2])
82-
code = fmt.Sprintf("%06d", num%1000000)
56+
otpSvc: otpSvc,
57+
devicesSvc: devicesSvc,
58+
onlineSvc: onlineSvc,
8359

84-
if err = s.codesCache.SetOrFail(code, userID, cache.WithValidUntil(validUntil)); err != nil {
85-
continue
86-
}
60+
logger: logger,
8761

88-
break
62+
idgen: idgen,
63+
usersCache: cache.New[models.User](cache.Config{TTL: 1 * time.Hour}),
8964
}
65+
}
9066

67+
// GenerateUserCode generates a unique one-time user authorization code
68+
func (s *Service) GenerateUserCode(ctx context.Context, userID string) (*otp.Code, error) {
69+
code, err := s.otpSvc.Generate(context.Background(), userID)
9170
if err != nil {
92-
return AuthCode{}, fmt.Errorf("can't generate code: %w", err)
71+
return nil, fmt.Errorf("failed to generate code: %w", err)
9372
}
9473

95-
return AuthCode{Code: code, ValidUntil: validUntil}, nil
74+
return code, nil
9675
}
9776

9877
func (s *Service) RegisterUser(login, password string) (models.User, error) {
@@ -180,18 +159,18 @@ func (s *Service) AuthorizeUser(username, password string) (models.User, error)
180159
}
181160

182161
// AuthorizeUserByCode authorizes a user by one-time code.
183-
func (s *Service) AuthorizeUserByCode(code string) (models.User, error) {
184-
userID, err := s.codesCache.GetAndDelete(code)
162+
func (s *Service) AuthorizeUserByCode(ctx context.Context, code string) (*models.User, error) {
163+
userID, err := s.otpSvc.Validate(ctx, code)
185164
if err != nil {
186-
return models.User{}, err
165+
return nil, fmt.Errorf("failed to validate code: %w", err)
187166
}
188167

189168
user, err := s.users.GetByID(userID)
190169
if err != nil {
191-
return models.User{}, err
170+
return nil, fmt.Errorf("failed to get user: %w", err)
192171
}
193172

194-
return user, nil
173+
return &user, nil
195174
}
196175

197176
func (s *Service) ChangePassword(userID string, currentPassword string, newPassword string) error {
@@ -240,6 +219,5 @@ func (s *Service) Run(ctx context.Context) {
240219
}
241220

242221
func (s *Service) clean(_ context.Context) {
243-
s.codesCache.Cleanup()
244222
s.usersCache.Cleanup()
245223
}
Lines changed: 0 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -1,18 +1,8 @@
11
package auth
22

3-
import "time"
4-
5-
const codeTTL = 5 * time.Minute
6-
73
type Mode string
84

95
const (
106
ModePublic Mode = "public"
117
ModePrivate Mode = "private"
128
)
13-
14-
// AuthCode is a one-time user authorization code
15-
type AuthCode struct {
16-
Code string
17-
ValidUntil time.Time
18-
}

0 commit comments

Comments
 (0)