1
0
forked from baron/baron-sso

로그인 전 계정조회

This commit is contained in:
2026-01-27 17:16:36 +09:00
parent c914fad405
commit 1a0dc74cb5
3 changed files with 113 additions and 87 deletions

View File

@@ -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"})
}