init
This commit is contained in:
@@ -0,0 +1,57 @@
|
||||
package auth
|
||||
|
||||
import (
|
||||
"context"
|
||||
"crypto/rand"
|
||||
"database/sql"
|
||||
"errors"
|
||||
"math/big"
|
||||
"time"
|
||||
)
|
||||
|
||||
// OTPStore مدیریت کدهای OTP در جدول otp_tokens.
|
||||
type OTPStore struct {
|
||||
db *sql.DB
|
||||
ttl time.Duration
|
||||
}
|
||||
|
||||
func NewOTPStore(db *sql.DB, ttl time.Duration) *OTPStore {
|
||||
return &OTPStore{db: db, ttl: ttl}
|
||||
}
|
||||
|
||||
// Generate یک کد ۵ رقمی امن میسازد (مطابق rand(10000,99999) در Laravel).
|
||||
func Generate() string {
|
||||
n, err := rand.Int(rand.Reader, big.NewInt(90000))
|
||||
if err != nil {
|
||||
return "12345" // عملاً رخ نمیدهد
|
||||
}
|
||||
return big.NewInt(10000 + n.Int64()).String()
|
||||
}
|
||||
|
||||
// Create کد را برای کاربر ذخیره میکند.
|
||||
func (s *OTPStore) Create(ctx context.Context, userID int64, token string) error {
|
||||
_, err := s.db.ExecContext(ctx,
|
||||
`INSERT INTO otp_tokens (user_id, token) VALUES (?, ?)`, userID, token)
|
||||
return err
|
||||
}
|
||||
|
||||
var ErrInvalidOTP = errors.New("token not valid")
|
||||
|
||||
// Verify اعتبار کد را در بازه ttl بررسی و پس از مصرف حذف میکند.
|
||||
func (s *OTPStore) Verify(ctx context.Context, userID int64, token string) error {
|
||||
cutoff := time.Now().Add(-s.ttl).UTC().Format("2006-01-02 15:04:05")
|
||||
var id int64
|
||||
err := s.db.QueryRowContext(ctx,
|
||||
`SELECT id FROM otp_tokens
|
||||
WHERE user_id = ? AND token = ? AND created_at > ?
|
||||
ORDER BY id DESC LIMIT 1`, userID, token, cutoff).Scan(&id)
|
||||
if errors.Is(err, sql.ErrNoRows) {
|
||||
return ErrInvalidOTP
|
||||
}
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
// مصرف شد ⇒ حذف
|
||||
_, err = s.db.ExecContext(ctx, `DELETE FROM otp_tokens WHERE id = ?`, id)
|
||||
return err
|
||||
}
|
||||
Reference in New Issue
Block a user