mirror of
https://github.com/Rain-kl/OpenFlare.git
synced 2026-09-28 05:46:36 +08:00
b76f707c8b
Result: {"status":"keep","total_issues":74,"golint_canonicalheader":8,"golint_errname":1,"golint_errorlint":12,"golint_forcetypeassert":3,"golint_gosec":0,"golint_intrange":3,"golint_modernize":5,"golint_nilnil":3,"golint_perfsprint":18,"golint_prealloc":3,"golint_recvcheck":7,"golint_usestdlibvars":3,"golint_wastedassign":7,"golint_total":73,"eslint_problems":1,"eslint_errors":0,"eslint_warnings":1,"tsc_errors":0,"measure_s":38}
115 lines
3.4 KiB
Go
115 lines
3.4 KiB
Go
// Copyright 2026 Arctel.net
|
|
// SPDX-License-Identifier: Apache-2.0
|
|
|
|
package oauth
|
|
|
|
import (
|
|
"context"
|
|
"errors"
|
|
"slices"
|
|
"strings"
|
|
|
|
"github.com/Rain-kl/Wavelet/internal/model"
|
|
"github.com/Rain-kl/Wavelet/internal/repository"
|
|
"github.com/coreos/go-oidc/v3/oidc"
|
|
"golang.org/x/oauth2"
|
|
)
|
|
|
|
func isOIDCLoginEnabled(ctx context.Context) bool {
|
|
enabled, err := repository.GetBoolByKey(ctx, model.ConfigKeyOIDCLoginEnabled)
|
|
if err != nil {
|
|
return true
|
|
}
|
|
return enabled
|
|
}
|
|
|
|
func resolveAuthSource(ctx context.Context, sourceName string) (*model.AuthSource, error) {
|
|
name := strings.TrimSpace(strings.ToLower(sourceName))
|
|
if name == "" {
|
|
sources, err := repository.GetActiveAuthSourcesCached(ctx)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
if len(sources) == 0 {
|
|
return nil, errors.New(errNoActiveAuthSource)
|
|
}
|
|
return repository.GetAuthSourceByNameCached(ctx, sources[0].Name)
|
|
}
|
|
return repository.GetAuthSourceByNameCached(ctx, name)
|
|
}
|
|
|
|
func activeLoginSources(ctx context.Context) []AuthSourceView {
|
|
enabled, err := repository.GetBoolByKey(ctx, model.ConfigKeyOIDCLoginEnabled)
|
|
if err == nil && !enabled {
|
|
return nil
|
|
}
|
|
|
|
dbSources, err := repository.GetActiveAuthSourcesCached(ctx)
|
|
if err != nil {
|
|
return nil
|
|
}
|
|
sources := make([]AuthSourceView, 0, len(dbSources))
|
|
for _, source := range dbSources {
|
|
sources = append(sources, AuthSourceView{
|
|
ID: source.ID,
|
|
Name: source.Name,
|
|
Type: source.Type,
|
|
DisplayName: source.DisplayName,
|
|
IsActive: source.IsActive,
|
|
IconURL: source.IconURL,
|
|
ClientSecretConfigured: source.ClientSecretConfigured,
|
|
})
|
|
}
|
|
return sources
|
|
}
|
|
|
|
func getFrontendLoginRedirectURL(ctx context.Context) (string, error) {
|
|
sc, err := repository.GetSystemConfigByKey(ctx, model.ConfigKeyServerAddress)
|
|
if err != nil || strings.TrimSpace(sc.Value) == "" {
|
|
return "", errors.New(errServerAddressMissing)
|
|
}
|
|
return strings.TrimRight(sc.Value, "/") + "/login", nil
|
|
}
|
|
|
|
func buildOAuthConfig(ctx context.Context, source *model.AuthSource, redirectURL string) (*oauth2.Config, *oidc.IDTokenVerifier, error) {
|
|
if source == nil {
|
|
return nil, nil, errors.New(errAuthSourceRequired)
|
|
}
|
|
|
|
if source.OpenIDDiscoveryURL == "" {
|
|
return nil, nil, errors.New(errDiscoveryURLRequired)
|
|
}
|
|
|
|
// Clean the issuer URL (trim /.well-known/openid-configuration if configured by mistake)
|
|
issuer := strings.TrimSuffix(strings.TrimSpace(source.OpenIDDiscoveryURL), "/")
|
|
issuer = strings.TrimSuffix(issuer, "/.well-known/openid-configuration")
|
|
issuer = strings.TrimSuffix(issuer, "/.well-known/oauth-authorization-server")
|
|
|
|
// 使用进程级缓存获取 provider,避免每次调用都向 issuer 发起
|
|
// /.well-known/openid-configuration HTTP 请求。
|
|
provider, err := globalOIDCProviderCache.get(ctx, issuer)
|
|
if err != nil {
|
|
return nil, nil, err
|
|
}
|
|
verifier := provider.Verifier(&oidc.Config{ClientID: source.ClientID})
|
|
scopes := strings.Fields(source.Scopes)
|
|
if len(scopes) == 0 {
|
|
scopes = []string{oidc.ScopeOpenID, "profile", "email"}
|
|
}
|
|
if !containsScope(scopes, oidc.ScopeOpenID) {
|
|
scopes = append([]string{oidc.ScopeOpenID}, scopes...)
|
|
}
|
|
|
|
return &oauth2.Config{
|
|
ClientID: source.ClientID,
|
|
ClientSecret: source.ClientSecret,
|
|
RedirectURL: redirectURL,
|
|
Scopes: scopes,
|
|
Endpoint: provider.Endpoint(),
|
|
}, verifier, nil
|
|
}
|
|
|
|
func containsScope(scopes []string, scope string) bool {
|
|
return slices.Contains(scopes, scope)
|
|
}
|