forked from baron/baron-sso
로그인 전 계정조회
This commit is contained in:
@@ -516,9 +516,35 @@ func (h *AuthHandler) InitEnchantedLink(c *fiber.Ctx) error {
|
||||
loginID := strings.ReplaceAll(req.LoginID, "-", "")
|
||||
loginID = strings.ReplaceAll(loginID, " ", "")
|
||||
|
||||
// Generate secure tokens
|
||||
token := GenerateSecureToken(32)
|
||||
pendingRef := GenerateSecureToken(16)
|
||||
// [New] Check if user exists before sending link
|
||||
if h.DescopeClient != nil {
|
||||
user, err := h.DescopeClient.Management.User().Load(context.Background(), loginID)
|
||||
if err != nil || user == nil {
|
||||
// Try searching by phone if not found by LoginID
|
||||
searchPhone := loginID
|
||||
if !strings.Contains(searchPhone, "@") {
|
||||
if strings.HasPrefix(searchPhone, "010") {
|
||||
searchPhone = "+82" + searchPhone[1:]
|
||||
} else if strings.HasPrefix(searchPhone, "82") {
|
||||
searchPhone = "+" + searchPhone
|
||||
}
|
||||
}
|
||||
searchOptions := &descope.UserSearchOptions{
|
||||
Phones: []string{searchPhone},
|
||||
Limit: 1,
|
||||
}
|
||||
users, _, errSearch := h.DescopeClient.Management.User().SearchAll(context.Background(), searchOptions)
|
||||
if errSearch != nil || len(users) == 0 {
|
||||
slog.Warn("[Enchanted] User not found", "loginID", loginID)
|
||||
return c.Status(fiber.StatusNotFound).JSON(fiber.Map{"error": "User not registered"})
|
||||
}
|
||||
// 검색 결과가 있더라도 loginID는 사용자가 입력한 원래 값을 유지 (발송 수단 결정을 위해)
|
||||
}
|
||||
}
|
||||
|
||||
// [Changed] 토큰 길이를 사용자의 요청에 맞춰 6글자(3바이트)로, pendingRef를 8글자(4바이트)로 조정
|
||||
token := GenerateSecureToken(3)
|
||||
pendingRef := GenerateSecureToken(3)
|
||||
|
||||
slog.Info("[Enchanted] Initiating enchanted link", "loginID", loginID, "token", token, "pendingRef", pendingRef)
|
||||
|
||||
@@ -665,41 +691,16 @@ func (h *AuthHandler) VerifyMagicLink(c *fiber.Ctx) error {
|
||||
targetLoginID = users[0].UserID
|
||||
}
|
||||
} else {
|
||||
// Not found, or search error. Fallback to using the phone as LoginID.
|
||||
// Use the normalized phone number to ensure consistency (+82...)
|
||||
targetLoginID = searchPhone
|
||||
slog.Info("[Verify] User not found by phone, will use/create", "loginID", targetLoginID)
|
||||
// [Changed] If not found, do NOT auto-create. Return error.
|
||||
slog.Warn("[Verify] User not found by phone", "loginID", searchPhone)
|
||||
return c.Status(fiber.StatusNotFound).JSON(fiber.Map{"error": "User not registered"})
|
||||
}
|
||||
|
||||
slog.Info("[Verify] Generating embedded link", "loginID", targetLoginID)
|
||||
embeddedToken, err := h.DescopeClient.Management.User().GenerateEmbeddedLink(context.Background(), targetLoginID, nil, 0)
|
||||
if err != nil {
|
||||
if strings.Contains(err.Error(), "User not found") || strings.Contains(err.Error(), "E062108") {
|
||||
slog.Info("[Verify] User not found, creating...", "loginID", targetLoginID)
|
||||
|
||||
// Create User with Explicit Phone Attribute
|
||||
userObj := &descope.UserRequest{}
|
||||
if strings.Contains(targetLoginID, "@") {
|
||||
userObj.Email = targetLoginID
|
||||
} else {
|
||||
userObj.Phone = targetLoginID // Must be E.164
|
||||
}
|
||||
|
||||
_, errCreate := h.DescopeClient.Management.User().Create(context.Background(), targetLoginID, userObj)
|
||||
if errCreate != nil {
|
||||
slog.Error("[Verify] Failed to create user", "error", errCreate)
|
||||
return c.Status(fiber.StatusInternalServerError).JSON(fiber.Map{"error": "Failed to create new user"})
|
||||
}
|
||||
|
||||
embeddedToken, err = h.DescopeClient.Management.User().GenerateEmbeddedLink(context.Background(), targetLoginID, nil, 0)
|
||||
if err != nil {
|
||||
slog.Error("[Verify] Failed to generate token after creation", "error", err)
|
||||
return c.Status(fiber.StatusInternalServerError).JSON(fiber.Map{"error": "Failed to generate upstream token"})
|
||||
}
|
||||
} else {
|
||||
slog.Error("[Verify] Descope Error", "error", err)
|
||||
return c.Status(fiber.StatusInternalServerError).JSON(fiber.Map{"error": "Failed to generate upstream token"})
|
||||
}
|
||||
slog.Error("[Verify] Descope Error", "error", err)
|
||||
return c.Status(fiber.StatusInternalServerError).JSON(fiber.Map{"error": "Failed to generate upstream token"})
|
||||
}
|
||||
|
||||
slog.Info("[Verify] Exchanging embedded token for session JWT")
|
||||
@@ -749,44 +750,6 @@ func (h *AuthHandler) PasswordLogin(c *fiber.Ctx) error {
|
||||
|
||||
ale.Log(slog.LevelInfo, "Attempting to login")
|
||||
|
||||
// Validate password complexity before sending to Descope
|
||||
password := req.Password
|
||||
if len(password) < 8 {
|
||||
ale.Status = fiber.StatusBadRequest
|
||||
ale.LatencyMs = time.Since(startTime)
|
||||
ale.DescopeError = "Password must be at least 8 characters long"
|
||||
ale.Log(slog.LevelWarn, "Validation failed: password too short")
|
||||
return c.Status(fiber.StatusBadRequest).JSON(fiber.Map{"error": "Password must be at least 8 characters long"})
|
||||
}
|
||||
if ok, _ := regexp.MatchString(`[a-z]`, password); !ok {
|
||||
ale.Status = fiber.StatusBadRequest
|
||||
ale.LatencyMs = time.Since(startTime)
|
||||
ale.DescopeError = "Password must contain at least one lowercase letter"
|
||||
ale.Log(slog.LevelWarn, "Validation failed: no lowercase letter")
|
||||
return c.Status(fiber.StatusBadRequest).JSON(fiber.Map{"error": "Password must contain at least one lowercase letter"})
|
||||
}
|
||||
if ok, _ := regexp.MatchString(`[A-Z]`, password); !ok {
|
||||
ale.Status = fiber.StatusBadRequest
|
||||
ale.LatencyMs = time.Since(startTime)
|
||||
ale.DescopeError = "Password must contain at least one uppercase letter"
|
||||
ale.Log(slog.LevelWarn, "Validation failed: no uppercase letter")
|
||||
return c.Status(fiber.StatusBadRequest).JSON(fiber.Map{"error": "Password must contain at least one uppercase letter"})
|
||||
}
|
||||
if ok, _ := regexp.MatchString(`[0-9]`, password); !ok {
|
||||
ale.Status = fiber.StatusBadRequest
|
||||
ale.LatencyMs = time.Since(startTime)
|
||||
ale.DescopeError = "Password must contain at least one number"
|
||||
ale.Log(slog.LevelWarn, "Validation failed: no number")
|
||||
return c.Status(fiber.StatusBadRequest).JSON(fiber.Map{"error": "Password must contain at least one number"})
|
||||
}
|
||||
if ok, _ := regexp.MatchString(`[\W_]`, password); !ok {
|
||||
ale.Status = fiber.StatusBadRequest
|
||||
ale.LatencyMs = time.Since(startTime)
|
||||
ale.DescopeError = "Password must contain at least one special character"
|
||||
ale.Log(slog.LevelWarn, "Validation failed: no special character")
|
||||
return c.Status(fiber.StatusBadRequest).JSON(fiber.Map{"error": "Password must contain at least one special character"})
|
||||
}
|
||||
|
||||
if h.DescopeClient == nil {
|
||||
ale.Status = fiber.StatusInternalServerError
|
||||
ale.LatencyMs = time.Since(startTime)
|
||||
@@ -802,7 +765,12 @@ func (h *AuthHandler) PasswordLogin(c *fiber.Ctx) error {
|
||||
ale.LatencyMs = time.Since(startTime)
|
||||
ale.DescopeError = err.Error()
|
||||
ale.Log(slog.LevelWarn, "Descope sign-in failed")
|
||||
// It's good practice to return a generic error message for security.
|
||||
|
||||
// [Changed] Check if it's a "User not found" error to be more specific
|
||||
if strings.Contains(err.Error(), "E062107") || strings.Contains(err.Error(), "not found") {
|
||||
return c.Status(fiber.StatusNotFound).JSON(fiber.Map{"error": "User not registered"})
|
||||
}
|
||||
|
||||
return c.Status(fiber.StatusUnauthorized).JSON(fiber.Map{"error": "Invalid credentials"})
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user