feat: sync deployed v1.0.0-rc.38-custom.42

Sync production source including routing, billing, Astra detection and public uptime. Update custom build instructions and license packaging.
This commit is contained in:
cneicy committed 2026-09-26 04:49:11 +08:00
1 parent aa6c3f50f4
commit ceddfd3d6b
828 files changed
+122253 -13702

No files matched your search

+46
View File
@@ -37,6 +37,11 @@ type gitHubUser struct {
Email string `json:"email"`
}
type gitHubEmail struct {
Email string `json:"email"`
Verified bool `json:"verified"`
}
func (p *GitHubProvider) GetName() string {
return "GitHub"
}
@@ -158,6 +163,47 @@ func (p *GitHubProvider) GetUserInfo(ctx context.Context, token *OAuthToken) (*O
}, nil
}
// GetVerifiedEmails lists the addresses GitHub has confirmed for the signed-in
// account. The email field of the user endpoint carries no confirmation status
// and is not used for this.
func (p *GitHubProvider) GetVerifiedEmails(ctx context.Context, token *OAuthToken) ([]string, error) {
req, err := http.NewRequestWithContext(ctx, http.MethodGet, "https://api.github.com/user/emails", nil)
if err != nil {
return nil, err
}
req.Header.Set("Authorization", "Bearer "+token.AccessToken)
req.Header.Set("Accept", "application/vnd.github+json")
client := http.Client{
Timeout: 20 * time.Second,
}
res, err := client.Do(req)
if err != nil {
logger.LogError(ctx, fmt.Sprintf("[OAuth-GitHub] GetVerifiedEmails error: %s", err.Error()))
return nil, NewOAuthErrorWithRaw(i18n.MsgOAuthConnectFailed, map[string]any{"Provider": "GitHub"}, err.Error())
}
defer res.Body.Close()
if res.StatusCode != http.StatusOK {
logger.LogError(ctx, fmt.Sprintf("[OAuth-GitHub] GetVerifiedEmails failed: status=%d", res.StatusCode))
return nil, NewOAuthErrorWithRaw(i18n.MsgOAuthGetUserErr, map[string]any{"Provider": "GitHub"}, fmt.Sprintf("status %d", res.StatusCode))
}
var emails []gitHubEmail
if err := common.DecodeJson(res.Body, &emails); err != nil {
logger.LogError(ctx, fmt.Sprintf("[OAuth-GitHub] GetVerifiedEmails decode error: %s", err.Error()))
return nil, err
}
verified := make([]string, 0, len(emails))
for _, email := range emails {
if email.Verified && email.Email != "" {
verified = append(verified, email.Email)
}
}
logger.LogDebug(ctx, "[OAuth-GitHub] GetVerifiedEmails success: verified=%d", len(verified))
return verified, nil
}
func (p *GitHubProvider) IsUserIDTaken(providerUserID string) bool {
return model.IsGitHubIdAlreadyTaken(providerUserID)
}
+7
View File
@@ -40,3 +40,10 @@ type Provider interface {
// (e.g. the user_oauth_bindings table) return an empty string.
ProviderUserIDColumn() string
}
// VerifiedEmailProvider is implemented by providers that can list the email
// addresses they have confirmed for the signed-in account. The login flow uses
// it to match a provider account against an existing account's email.
type VerifiedEmailProvider interface {
GetVerifiedEmails(ctx context.Context, token *OAuthToken) ([]string, error)
}