fix(auth): require explicit choice for third-party signup
This commit is contained in:
@@ -325,80 +325,18 @@ func (h *AuthHandler) LinuxDoOAuthCallback(c *gin.Context) {
|
||||
redirectOAuthError(c, frontendCallback, "session_error", infraerrors.Reason(err), infraerrors.Message(err))
|
||||
return
|
||||
}
|
||||
if compatEmailUser != nil {
|
||||
if err := h.createOAuthPendingSession(c, oauthPendingSessionPayload{
|
||||
Intent: "adopt_existing_user_by_email",
|
||||
Identity: identityKey,
|
||||
TargetUserID: &compatEmailUser.ID,
|
||||
ResolvedEmail: compatEmailUser.Email,
|
||||
RedirectTo: redirectTo,
|
||||
BrowserSessionKey: browserSessionKey,
|
||||
UpstreamIdentityClaims: upstreamClaims,
|
||||
CompletionResponse: map[string]any{
|
||||
"redirect": redirectTo,
|
||||
"step": "bind_login_required",
|
||||
"email": compatEmailUser.Email,
|
||||
},
|
||||
}); err != nil {
|
||||
redirectOAuthError(c, frontendCallback, "session_error", "failed to continue oauth login", "")
|
||||
return
|
||||
}
|
||||
redirectToFrontendCallback(c, frontendCallback)
|
||||
return
|
||||
}
|
||||
|
||||
if h.isForceEmailOnThirdPartySignup(c.Request.Context()) {
|
||||
if err := h.createOAuthEmailRequiredPendingSession(c, identityKey, redirectTo, browserSessionKey, upstreamClaims); err != nil {
|
||||
redirectOAuthError(c, frontendCallback, "session_error", "failed to continue oauth login", "")
|
||||
return
|
||||
}
|
||||
redirectToFrontendCallback(c, frontendCallback)
|
||||
return
|
||||
}
|
||||
|
||||
// 传入空邀请码;如果需要邀请码,服务层返回 ErrOAuthInvitationRequired
|
||||
tokenPair, user, err := h.authService.LoginOrRegisterOAuthWithTokenPair(c.Request.Context(), email, username, "")
|
||||
if err != nil {
|
||||
if errors.Is(err, service.ErrOAuthInvitationRequired) {
|
||||
if err := h.createOAuthPendingSession(c, oauthPendingSessionPayload{
|
||||
Intent: "login",
|
||||
Identity: identityKey,
|
||||
ResolvedEmail: email,
|
||||
RedirectTo: redirectTo,
|
||||
BrowserSessionKey: browserSessionKey,
|
||||
UpstreamIdentityClaims: upstreamClaims,
|
||||
CompletionResponse: map[string]any{
|
||||
"error": "invitation_required",
|
||||
"redirect": redirectTo,
|
||||
},
|
||||
}); err != nil {
|
||||
redirectOAuthError(c, frontendCallback, "session_error", "failed to continue oauth login", "")
|
||||
return
|
||||
}
|
||||
redirectToFrontendCallback(c, frontendCallback)
|
||||
return
|
||||
}
|
||||
// 避免把内部细节泄露给客户端;给前端保留结构化原因与提示信息即可。
|
||||
redirectOAuthError(c, frontendCallback, "login_failed", infraerrors.Reason(err), infraerrors.Message(err))
|
||||
return
|
||||
}
|
||||
|
||||
if err := h.createOAuthPendingSession(c, oauthPendingSessionPayload{
|
||||
Intent: "login",
|
||||
Identity: identityKey,
|
||||
TargetUserID: &user.ID,
|
||||
ResolvedEmail: email,
|
||||
RedirectTo: redirectTo,
|
||||
BrowserSessionKey: browserSessionKey,
|
||||
UpstreamIdentityClaims: upstreamClaims,
|
||||
CompletionResponse: map[string]any{
|
||||
"access_token": tokenPair.AccessToken,
|
||||
"refresh_token": tokenPair.RefreshToken,
|
||||
"expires_in": tokenPair.ExpiresIn,
|
||||
"token_type": "Bearer",
|
||||
"redirect": redirectTo,
|
||||
},
|
||||
}); err != nil {
|
||||
if err := h.createLinuxDoOAuthChoicePendingSession(
|
||||
c,
|
||||
identityKey,
|
||||
email,
|
||||
email,
|
||||
redirectTo,
|
||||
browserSessionKey,
|
||||
upstreamClaims,
|
||||
compatEmail,
|
||||
compatEmailUser,
|
||||
h.isForceEmailOnThirdPartySignup(c.Request.Context()),
|
||||
); err != nil {
|
||||
redirectOAuthError(c, frontendCallback, "session_error", "failed to continue oauth login", "")
|
||||
return
|
||||
}
|
||||
@@ -431,6 +369,62 @@ func (h *AuthHandler) findLinuxDoCompatEmailUser(ctx context.Context, email stri
|
||||
return userEntity, nil
|
||||
}
|
||||
|
||||
func (h *AuthHandler) createLinuxDoOAuthChoicePendingSession(
|
||||
c *gin.Context,
|
||||
identity service.PendingAuthIdentityKey,
|
||||
suggestedEmail string,
|
||||
resolvedEmail string,
|
||||
redirectTo string,
|
||||
browserSessionKey string,
|
||||
upstreamClaims map[string]any,
|
||||
compatEmail string,
|
||||
compatEmailUser *dbent.User,
|
||||
forceEmailOnSignup bool,
|
||||
) error {
|
||||
suggestionEmail := strings.TrimSpace(suggestedEmail)
|
||||
canonicalEmail := strings.TrimSpace(resolvedEmail)
|
||||
if suggestionEmail == "" {
|
||||
suggestionEmail = canonicalEmail
|
||||
}
|
||||
|
||||
completionResponse := map[string]any{
|
||||
"step": oauthPendingChoiceStep,
|
||||
"adoption_required": true,
|
||||
"redirect": strings.TrimSpace(redirectTo),
|
||||
"email": suggestionEmail,
|
||||
"resolved_email": canonicalEmail,
|
||||
"existing_account_email": "",
|
||||
"existing_account_bindable": false,
|
||||
"create_account_allowed": true,
|
||||
"force_email_on_signup": forceEmailOnSignup,
|
||||
"choice_reason": "third_party_signup",
|
||||
}
|
||||
if strings.TrimSpace(compatEmail) != "" {
|
||||
completionResponse["compat_email"] = strings.TrimSpace(compatEmail)
|
||||
}
|
||||
resolvedChoiceEmail := suggestionEmail
|
||||
if compatEmailUser != nil {
|
||||
completionResponse["email"] = strings.TrimSpace(compatEmailUser.Email)
|
||||
completionResponse["existing_account_email"] = strings.TrimSpace(compatEmailUser.Email)
|
||||
completionResponse["existing_account_bindable"] = true
|
||||
completionResponse["choice_reason"] = "compat_email_match"
|
||||
resolvedChoiceEmail = strings.TrimSpace(compatEmailUser.Email)
|
||||
}
|
||||
if forceEmailOnSignup && compatEmailUser == nil {
|
||||
completionResponse["choice_reason"] = "force_email_on_signup"
|
||||
}
|
||||
|
||||
return h.createOAuthPendingSession(c, oauthPendingSessionPayload{
|
||||
Intent: oauthIntentLogin,
|
||||
Identity: identity,
|
||||
ResolvedEmail: resolvedChoiceEmail,
|
||||
RedirectTo: redirectTo,
|
||||
BrowserSessionKey: browserSessionKey,
|
||||
UpstreamIdentityClaims: upstreamClaims,
|
||||
CompletionResponse: completionResponse,
|
||||
})
|
||||
}
|
||||
|
||||
type completeLinuxDoOAuthRequest struct {
|
||||
InvitationCode string `json:"invitation_code" binding:"required"`
|
||||
AdoptDisplayName *bool `json:"adopt_display_name,omitempty"`
|
||||
|
||||
Reference in New Issue
Block a user