feat: publish sanitized custom.97 source

This commit is contained in:
cneicy committed 2026-10-27 20:43:39 +08:00
1 parent 8e6ed0317b
commit 86c0276156
1022 files changed
+69903 -19207

No files matched your search

+26 -40
View File
@@ -3,7 +3,6 @@ package controller
import (
"encoding/json"
"errors"
"fmt"
"net/http"
"slices"
"strconv"
@@ -38,16 +37,16 @@ type oauthFlowPayload struct {
Authorization *model.AuthFlowAuthorization `json:"authorization,omitempty"`
}
// providerParams returns map with Provider key for i18n templates
// providerParams returns the params of messages that name the OAuth provider.
func providerParams(name string) map[string]any {
return map[string]any{"Provider": name}
return map[string]any{"provider": name}
}
// GenerateOAuthCode generates a state code for OAuth CSRF protection
func GenerateOAuthCode(c *gin.Context) {
var request oauthStateRequest
if err := common.DecodeJson(c.Request.Body, &request); err != nil {
common.ApiErrorI18n(c, i18n.MsgInvalidParams)
common.ApiErrorT(c, "Invalid parameters")
return
}
request.Provider = strings.TrimSpace(request.Provider)
@@ -58,7 +57,7 @@ func GenerateOAuthCode(c *gin.Context) {
len(request.Aff) > 32 ||
(request.Intent != model.AuthFlowIntentLogin && request.Aff != "") ||
(request.Intent != model.AuthFlowIntentVerify && (request.Scope != "" || len(request.Context) != 0)) {
common.ApiErrorI18n(c, i18n.MsgInvalidParams)
common.ApiErrorT(c, "Invalid parameters")
return
}
userID := 0
@@ -76,7 +75,7 @@ func GenerateOAuthCode(c *gin.Context) {
if request.Intent == model.AuthFlowIntentBind || request.Intent == model.AuthFlowIntentVerify {
identity, ok := middleware.GetSessionAuthIdentity(c)
if !ok {
c.JSON(http.StatusUnauthorized, gin.H{"success": false, "message": "绑定操作需要登录"})
writeAccountStatusError(c, http.StatusUnauthorized, "Sign in to bind an account")
return
}
userID = identity.UserID
@@ -148,10 +147,7 @@ func HandleOAuth(c *gin.Context) {
providerName := c.Param("provider")
provider := oauth.GetProvider(providerName)
if provider == nil {
c.JSON(http.StatusBadRequest, gin.H{
"success": false,
"message": i18n.T(c, i18n.MsgOAuthUnknownProvider),
})
writeAccountStatusError(c, http.StatusBadRequest, "Unknown OAuth provider")
return
}
@@ -162,10 +158,7 @@ func HandleOAuth(c *gin.Context) {
Provider: providerName,
})
if err != nil {
c.JSON(http.StatusForbidden, gin.H{
"success": false,
"message": i18n.T(c, i18n.MsgOAuthStateInvalid),
})
writeAccountStatusError(c, http.StatusForbidden, "State parameter is empty or mismatched")
return
}
@@ -184,10 +177,7 @@ func HandleOAuth(c *gin.Context) {
if pendingFlow.Intent == model.AuthFlowIntentBind || pendingFlow.Intent == model.AuthFlowIntentVerify {
identity, ok := middleware.GetSessionAuthIdentity(c)
if !ok || identity.UserID != pendingFlow.UserId || identity.SessionID != pendingFlow.SessionId {
c.JSON(http.StatusForbidden, gin.H{
"success": false,
"message": i18n.T(c, i18n.MsgOAuthStateInvalid),
})
writeAccountStatusError(c, http.StatusForbidden, "State parameter is empty or mismatched")
return
}
consumeMatch.UserId = identity.UserID
@@ -209,7 +199,7 @@ func HandleOAuth(c *gin.Context) {
}
}
} else if pendingFlow.Intent != model.AuthFlowIntentLogin {
common.ApiErrorI18n(c, i18n.MsgInvalidParams)
common.ApiErrorT(c, "Invalid parameters")
return
}
@@ -238,7 +228,7 @@ func HandleOAuth(c *gin.Context) {
c.Set(oauth.TelegramOAuthFlowContextKey, telegramPayload.Telegram)
}
if !provider.IsEnabled() {
common.ApiErrorI18n(c, i18n.MsgOAuthNotEnabled, providerParams(provider.GetName()))
common.ApiErrorT(c, "{{provider}} login and registration has not been enabled by administrator", providerParams(provider.GetName()))
return
}
@@ -246,7 +236,7 @@ func HandleOAuth(c *gin.Context) {
errorCode := c.Query("error")
if errorCode != "" {
if _, err := model.ConsumeAuthFlow(state, consumeMatch); err != nil {
c.JSON(http.StatusForbidden, gin.H{"success": false, "message": i18n.T(c, i18n.MsgOAuthStateInvalid)})
writeAccountStatusError(c, http.StatusForbidden, "State parameter is empty or mismatched")
return
}
errorDescription := c.Query("error_description")
@@ -287,7 +277,7 @@ func HandleOAuth(c *gin.Context) {
}
flow, err := model.ConsumeAuthFlow(state, consumeMatch)
if err != nil {
c.JSON(http.StatusForbidden, gin.H{"success": false, "message": i18n.T(c, i18n.MsgOAuthStateInvalid)})
writeAccountStatusError(c, http.StatusForbidden, "State parameter is empty or mismatched")
return
}
@@ -325,18 +315,18 @@ func handleOAuthLogin(c *gin.Context, provider oauth.Provider, oauthUser *oauth.
user, migration, err := findOrCreateOAuthUser(c, provider, oauthUser, token, payload.AffiliateCode)
if err != nil {
if errors.Is(err, model.ErrEmailAlreadyTaken) {
common.ApiErrorI18n(c, i18n.MsgUserEmailAlreadyTaken)
common.ApiErrorT(c, "Email address is already in use")
return
}
switch err.(type) {
case *OAuthUserDeletedError:
common.ApiErrorI18n(c, i18n.MsgOAuthUserDeleted)
common.ApiErrorT(c, "User has been deleted")
case *OAuthRegistrationDisabledError:
common.ApiErrorI18n(c, i18n.MsgUserRegisterDisabled)
common.ApiErrorT(c, "New user registration has been disabled by administrator")
case *OAuthEmailAlreadyTakenError:
common.ApiErrorI18n(c, i18n.MsgUserEmailAlreadyTaken)
common.ApiErrorT(c, "Email address is already in use")
case *OAuthLegacyBindingNotConfirmedError:
common.ApiErrorI18n(c, i18n.MsgOAuthNotAutoLinked, providerParams(provider.GetName()))
common.ApiErrorT(c, "This {{provider}} account cannot be linked to an existing account automatically, please sign in or register another way and then link {{provider}} in account settings", providerParams(provider.GetName()))
default:
writeSecurityOperationError(c, err)
}
@@ -345,7 +335,7 @@ func handleOAuthLogin(c *gin.Context, provider oauth.Provider, oauthUser *oauth.
// 8. Check user status
if user.Status != common.UserStatusEnabled {
common.ApiErrorI18n(c, i18n.MsgOAuthUserBanned)
common.ApiErrorT(c, "User has been banned")
return
}
@@ -377,7 +367,7 @@ func handleOAuthBind(c *gin.Context, providerName string, provider oauth.Provide
return false, false
}
if provider.IsUserIDTaken(oauthUser.ProviderUserID) {
common.ApiErrorI18n(c, i18n.MsgOAuthAlreadyBound, providerParams(provider.GetName()))
common.ApiErrorT(c, "This {{provider}} account has already been bound", providerParams(provider.GetName()))
return false, false
}
_, err = model.ConsumeAuthFlowWithAction(state, match, func(tx *gorm.DB, _ *model.AuthFlow) error {
@@ -398,8 +388,8 @@ func handleOAuthBind(c *gin.Context, providerName string, provider oauth.Provide
writeSecurityOperationError(c, err)
return true, true
}
notificationFailed := service.NotifyAccountSecurityChange(user.Email, "Login account linked: "+provider.GetName()) != nil
common.ApiSuccessI18n(c, i18n.MsgOAuthBindSuccess, gin.H{"action": "bind", "notification_warning": notificationFailed})
notificationFailed := service.NotifyAccountSecurityChange(service.AccountMailLanguage(c, user.Id), user.Email, i18n.MsgSecurityEventLoginLinked, map[string]any{"Provider": provider.GetName()}) != nil
common.ApiSuccessT(c, "Binding successful", gin.H{"action": "bind", "notification_warning": notificationFailed})
return true, notificationFailed
}
@@ -454,7 +444,7 @@ func findOrCreateOAuthUser(c *gin.Context, provider oauth.Provider, oauthUser *o
if emailProvider, ok := provider.(oauth.VerifiedEmailProvider); ok && user.Email != "" {
emails, err := emailProvider.GetVerifiedEmails(c.Request.Context(), token)
if err != nil {
common.SysError(fmt.Sprintf("[OAuth] Failed to load verified emails for user %d: %s", user.Id, err.Error()))
common.SysError(common.LogText("[OAuth] Failed to load verified emails for user %d: %s", user.Id, err.Error()))
reason = "verified_emails_unavailable"
}
accountEmail := model.NormalizeEmail(user.Email)
@@ -475,7 +465,7 @@ func findOrCreateOAuthUser(c *gin.Context, provider oauth.Provider, oauthUser *o
}
if written {
user.GitHubId = oauthUser.ProviderUserID
notificationFailed := service.NotifyAccountSecurityChange(user.Email, "Login account linked: "+provider.GetName()) != nil
notificationFailed := service.NotifyAccountSecurityChange(service.AccountMailLanguage(c, user.Id), user.Email, i18n.MsgSecurityEventLoginLinked, map[string]any{"Provider": provider.GetName()}) != nil
recordLegacyGitHubBindingAudit(c, user, true, map[string]any{
"legacy_id": legacyID, "provider_user_id": oauthUser.ProviderUserID,
"verified_email_matched": true, "notification_failed": notificationFailed,
@@ -625,19 +615,15 @@ func (e *OAuthLegacyBindingNotConfirmedError) Error() string {
return "legacy binding was not confirmed"
}
// handleOAuthError handles OAuth errors and returns translated message
// handleOAuthError handles OAuth errors and returns a web console message
func handleOAuthError(c *gin.Context, err error) {
switch e := err.(type) {
case *oauth.OAuthError:
if e.Params != nil {
common.ApiErrorI18n(c, e.MsgKey, e.Params)
} else {
common.ApiErrorI18n(c, e.MsgKey)
}
common.ApiError(c, e.Message)
case *oauth.AccessDeniedError:
common.ApiErrorMsg(c, e.Message)
case *oauth.TrustLevelError:
common.ApiErrorI18n(c, i18n.MsgOAuthTrustLevelLow)
common.ApiErrorT(c, "Linux DO trust level does not meet the minimum required by administrator")
default:
writeSecurityOperationError(c, err)
}