69 lines
1.8 KiB
Go
69 lines
1.8 KiB
Go
package authService
|
|
|
|
import (
|
|
"context"
|
|
"fmt"
|
|
"time"
|
|
|
|
"git.farahty.com/nimer/go-mongo/app"
|
|
"git.farahty.com/nimer/go-mongo/models"
|
|
"github.com/redis/go-redis/v9"
|
|
"go.mongodb.org/mongo-driver/bson"
|
|
)
|
|
|
|
const maxAttempts = 5
|
|
const lockoutDuration = 15 * time.Minute
|
|
|
|
func Login(ctx context.Context, loginInput *models.LoginInput, redisClient redis.UniversalClient) (*models.LoginResponse, error) {
|
|
|
|
if locked, _ := isLockedOut(loginInput.Identity, redisClient); locked {
|
|
return nil, fmt.Errorf("too many failed attempts, please try again later")
|
|
}
|
|
|
|
filter := bson.D{
|
|
{
|
|
Key: "$or",
|
|
Value: bson.A{
|
|
bson.D{{Key: "phone", Value: loginInput.Identity}},
|
|
bson.D{{Key: "email", Value: loginInput.Identity}},
|
|
},
|
|
},
|
|
}
|
|
|
|
user, err := app.FindOne[models.User](ctx, "users", filter)
|
|
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
if !user.CheckPassword(loginInput.Password) {
|
|
logFailedLoginAttempt(ctx, loginInput.Identity, redisClient) // optional
|
|
return nil, fmt.Errorf("invalid identity or password")
|
|
|
|
}
|
|
|
|
clearFailedAttempts(ctx, loginInput.Identity, redisClient)
|
|
|
|
return successLogin(ctx, user)
|
|
}
|
|
|
|
func isLockedOut(identity string, redisClient redis.UniversalClient) (bool, error) {
|
|
key := fmt.Sprintf("login:fail:%s", identity)
|
|
attempts, err := redisClient.Get(context.Background(), key).Int()
|
|
if err != nil && err != redis.Nil {
|
|
return false, err
|
|
}
|
|
return attempts >= maxAttempts, nil
|
|
}
|
|
|
|
func logFailedLoginAttempt(ctx context.Context, identity string, redisClient redis.UniversalClient) {
|
|
key := fmt.Sprintf("login:fail:%s", identity)
|
|
redisClient.Incr(ctx, key)
|
|
redisClient.Expire(ctx, key, lockoutDuration)
|
|
}
|
|
|
|
func clearFailedAttempts(ctx context.Context, identity string, redisClient redis.UniversalClient) {
|
|
key := fmt.Sprintf("login:fail:%s", identity)
|
|
redisClient.Del(ctx, key)
|
|
}
|