feat: add otp redis repo

This commit is contained in:
AmirMahdi Qiasvand 2025-09-15 13:03:48 +03:30
parent 75e1b5111e
commit 36cda3fd5a
6 changed files with 109 additions and 1 deletions

View File

@ -6,6 +6,7 @@ type Config struct {
DB DB `mapstructure:"db"` DB DB `mapstructure:"db"`
Redis Redis `mapstructure:"redis"` Redis Redis `mapstructure:"redis"`
KYCProvider KYC `mapstructure:"kyc"` KYCProvider KYC `mapstructure:"kyc"`
OTP OTP `mapstructure:"otp"`
} }
type Server struct { type Server struct {
Host string `mapstructure:"host"` Host string `mapstructure:"host"`
@ -36,3 +37,7 @@ type KYC struct {
APIKey string `mapstructure:"api_key"` APIKey string `mapstructure:"api_key"`
URL string `mapstructure:"url"` URL string `mapstructure:"url"`
} }
type OTP struct {
CodeExpMinutes uint `mapstructure:"code_exp_minutes"`
}

29
internal/domain/otp.go Normal file
View File

@ -0,0 +1,29 @@
package domain
import (
"backend/pkg/util"
"context"
"time"
"github.com/google/uuid"
)
type OTPRepo interface {
Create(ctx context.Context, phone string, otp *OTP) error
Delete(ctx context.Context, phone string) error
}
type OTP struct {
ID uuid.UUID
Code string
Phone string
ExpiredAt time.Time
}
func NewOTP(phone string) *OTP {
return &OTP{
ID: uuid.New(),
Code: util.GenOTPCode(),
Phone: phone,
}
}

53
internal/repository/cache/otp_repo.go vendored Normal file
View File

@ -0,0 +1,53 @@
package cache
import (
"backend/internal/domain"
"backend/pkg/cache"
"context"
"encoding/json"
"fmt"
"time"
)
type OTPRepository struct {
redis *cache.Redis
}
func NewOTPRepository(redis *cache.Redis) domain.OTPRepo {
return &OTPRepository{
redis: redis,
}
}
func (r *OTPRepository) Create(ctx context.Context, phone string, otp *domain.OTP) error {
key := r.getOTPKey(phone)
otpData, err := json.Marshal(otp)
if err != nil {
return fmt.Errorf("failed to marshal otp: %w", err)
}
ttl := time.Until(otp.ExpiredAt)
if ttl <= 0 {
return fmt.Errorf("OTP expired already")
}
if err := r.redis.Client().Set(ctx, key, otpData, ttl).Err(); err != nil {
return fmt.Errorf("failed to store otp in redis: %w", err)
}
return nil
}
func (r *OTPRepository) Delete(ctx context.Context, phone string) error {
key := r.getOTPKey(phone)
if err := r.redis.Client().Del(ctx, key).Err(); err != nil {
return fmt.Errorf("failed to del otp from redis")
}
return nil
}
func (r *OTPRepository) getOTPKey(phone string) string {
return fmt.Sprintf("challenge:%s", phone)
}

View File

@ -189,3 +189,7 @@ func (s *authService) VerifyKYC(ctx context.Context, userID, nationalID, birthDa
return fmt.Errorf("KYC verification failed - shahkar status: %d, identity status: %d", return fmt.Errorf("KYC verification failed - shahkar status: %d, identity status: %d",
shahkarResp.StatusCode, identityResp.StatusCode) shahkarResp.StatusCode, identityResp.StatusCode)
} }
func (*authService) SendOTPVerifaction(ctx context.Context, phone string) (string, error) {
return "", nil
}

14
pkg/util/otp.go Normal file
View File

@ -0,0 +1,14 @@
package util
import (
"math/rand"
"strconv"
"time"
)
func GenOTPCode() string {
newRand := rand.New(rand.NewSource(time.Now().UnixNano()))
minNum := 100000
maxNum := 999999
return strconv.Itoa(newRand.Intn(maxNum-minNum+1) + minNum)
}

View File

@ -21,3 +21,6 @@ jwt:
RPC: RPC:
url: "exmaple.com" url: "exmaple.com"
otp:
code_exp_minutes: 2