mirror of
https://github.com/Rain-kl/OpenFlare.git
synced 2026-09-29 14:06:36 +08:00
339 lines
9.8 KiB
Go
339 lines
9.8 KiB
Go
// Copyright 2026 Arctel.net
|
|
// SPDX-License-Identifier: Apache-2.0
|
|
|
|
package auth
|
|
|
|
import (
|
|
"Wavelet/core/contracts"
|
|
"Wavelet/plugins/domain/auth/consts"
|
|
"Wavelet/plugins/domain/auth/controller"
|
|
"Wavelet/plugins/domain/auth/dao"
|
|
"Wavelet/plugins/domain/auth/model/do"
|
|
"Wavelet/plugins/domain/auth/model/dto"
|
|
"Wavelet/plugins/domain/auth/model/entity"
|
|
"Wavelet/plugins/domain/auth/service"
|
|
"context"
|
|
"net/http"
|
|
"sync"
|
|
|
|
"github.com/gin-contrib/sessions"
|
|
"github.com/gin-gonic/gin"
|
|
)
|
|
|
|
// Exported Type Aliases for Backward Compatibility
|
|
//
|
|
//nolint:revive // backward compatibility type aliases with legacy naming
|
|
type (
|
|
AuthSource = entity.AuthSource
|
|
ExternalAccount = entity.ExternalAccount
|
|
CachedToken = do.CachedToken
|
|
CapRuntimeSettings = do.CapRuntimeSettings
|
|
AuthSourceView = dto.AuthSourceView
|
|
BasicUserInfo = dto.BasicUserInfo
|
|
OAuthAuthorizeResponse = dto.OAuthAuthorizeResponse
|
|
OAuthCallbackResult = dto.OAuthCallbackResult
|
|
CallbackRequest = dto.CallbackRequest
|
|
ChallengeResponse = dto.ChallengeResponse
|
|
RedeemResponse = dto.RedeemResponse
|
|
CaptchaManager = service.CaptchaManager
|
|
)
|
|
|
|
// Exported Constant Aliases for Backward Compatibility
|
|
const (
|
|
UserNameKey = consts.UserNameKey
|
|
UserIDKey = consts.UserIDKey
|
|
UserObjKey = consts.UserObjKey
|
|
TokenAuthKey = consts.TokenAuthKey
|
|
TokenAdminKey = consts.TokenAdminKey
|
|
SessionTokenKey = consts.SessionTokenKey
|
|
PasswordHashKey = consts.PasswordHashKey
|
|
SystemUsername = consts.SystemUsername
|
|
|
|
OAuthStateCacheKeyFormat = consts.OAuthStateCacheKeyFormat
|
|
OAuthStateCacheKeyExpiration = consts.OAuthStateCacheKeyExpiration
|
|
OAuthPurposeLogin = consts.OAuthPurposeLogin
|
|
OAuthPurposeBind = consts.OAuthPurposeBind
|
|
AuthSourceTypeOIDC = consts.AuthSourceTypeOIDC
|
|
|
|
ErrTokenAuthNotAllowed = consts.ErrTokenAuthNotAllowed
|
|
)
|
|
|
|
var (
|
|
defaultMu sync.RWMutex
|
|
defaultDAO = dao.New(nil, nil, nil)
|
|
defaultService = service.New(defaultDAO, SessionConfig{SessionCookieName: "wavelet_session", SessionAge: 86400, SessionHTTPOnly: true}, nil)
|
|
defaultCtrl = controller.New(defaultService)
|
|
)
|
|
|
|
func setDefaultRuntime(d *dao.DAO, s *service.Service, c *controller.Controller) {
|
|
defaultMu.Lock()
|
|
defer defaultMu.Unlock()
|
|
defaultDAO = d
|
|
defaultService = s
|
|
defaultCtrl = c
|
|
}
|
|
|
|
func getDefaultRuntime() (*dao.DAO, *service.Service, *controller.Controller) {
|
|
defaultMu.RLock()
|
|
defer defaultMu.RUnlock()
|
|
return defaultDAO, defaultService, defaultCtrl
|
|
}
|
|
|
|
// ParseUserID parses a string, int, or float64 user ID representation.
|
|
func ParseUserID(v any) uint64 {
|
|
return dto.ParseUserID(v)
|
|
}
|
|
|
|
// BuildBasicUserInfo converts UserDTO to BasicUserInfo.
|
|
func BuildBasicUserInfo(user *contracts.UserDTO, needChange bool) BasicUserInfo {
|
|
return dto.BuildBasicUserInfo(user, needChange)
|
|
}
|
|
|
|
// SetSessionConfig updates the active session configuration.
|
|
func SetSessionConfig(cfg SessionConfig) {
|
|
_, s, _ := getDefaultRuntime()
|
|
s.Session.SetConfig(cfg)
|
|
}
|
|
|
|
// GetSessionConfig returns the active session configuration.
|
|
func GetSessionConfig() SessionConfig {
|
|
_, s, _ := getDefaultRuntime()
|
|
return s.Session.Config()
|
|
}
|
|
|
|
// GetSessionOptions builds session cookie options based on config and maxAge.
|
|
func GetSessionOptions(maxAge int) sessions.Options {
|
|
_, s, _ := getDefaultRuntime()
|
|
return s.Session.GetSessionOptions(maxAge)
|
|
}
|
|
|
|
// StripCookieMaxAgeAndExpires removes max-age and expires from cookie header.
|
|
func StripCookieMaxAgeAndExpires(header http.Header, cookieName string) {
|
|
_, s, _ := getDefaultRuntime()
|
|
s.Session.StripCookieMaxAgeAndExpires(header, cookieName)
|
|
}
|
|
|
|
// GetUserIDFromSession extracts user ID from session.
|
|
func GetUserIDFromSession(s sessions.Session) uint64 {
|
|
return controller.GetUserIDFromSession(s)
|
|
}
|
|
|
|
// GetUserIDFromContext extracts user ID from Gin context.
|
|
func GetUserIDFromContext(c *gin.Context) uint64 {
|
|
return controller.GetUserIDFromContext(c)
|
|
}
|
|
|
|
// SetLoginSession sets the login session for the authenticated user.
|
|
func SetLoginSession(ctx context.Context, c *gin.Context, user *contracts.UserDTO, extras ...map[string]any) error {
|
|
_, s, _ := getDefaultRuntime()
|
|
session := sessions.Default(c)
|
|
isSessionCookie, err := s.Session.ApplyLoginSession(ctx, session, user, extras...)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
if isSessionCookie {
|
|
s.Session.StripCookieMaxAgeAndExpires(c.Writer.Header(), s.Session.Config().SessionCookieName)
|
|
}
|
|
return nil
|
|
}
|
|
|
|
// RegisterWhitelist adds whitelist path patterns.
|
|
func RegisterWhitelist(patterns ...string) {
|
|
_, _, c := getDefaultRuntime()
|
|
c.RegisterWhitelist(patterns...)
|
|
}
|
|
|
|
// IsWhitelisted checks if the path matches the auth whitelist.
|
|
func IsWhitelisted(path string) bool {
|
|
_, _, c := getDefaultRuntime()
|
|
if wl := c.Whitelist(); wl != nil {
|
|
return wl.Match(path)
|
|
}
|
|
return false
|
|
}
|
|
|
|
// GetUserFromRequest extracts user from Request (Token or Session).
|
|
func GetUserFromRequest(c *gin.Context) (*contracts.UserDTO, error) {
|
|
d, _, _ := getDefaultRuntime()
|
|
return controller.GetUserFromRequest(c, d)
|
|
}
|
|
|
|
// LoginRequired returns authentication required middleware.
|
|
func LoginRequired() gin.HandlerFunc {
|
|
_, _, c := getDefaultRuntime()
|
|
return c.LoginRequired()
|
|
}
|
|
|
|
// AdminRequired returns admin authorization middleware.
|
|
func AdminRequired() gin.HandlerFunc {
|
|
_, _, c := getDefaultRuntime()
|
|
return c.AdminRequired()
|
|
}
|
|
|
|
// LoginAdminRequired alias for AdminRequired.
|
|
func LoginAdminRequired() gin.HandlerFunc {
|
|
return AdminRequired()
|
|
}
|
|
|
|
// DisallowTokenAuth returns middleware rejecting access token requests.
|
|
func DisallowTokenAuth() gin.HandlerFunc {
|
|
return controller.DisallowTokenAuth()
|
|
}
|
|
|
|
// GetCachedToken reads cached access token.
|
|
func GetCachedToken(ctx context.Context, tokenHash string) (*CachedToken, error) {
|
|
d, _, _ := getDefaultRuntime()
|
|
return d.GetCachedToken(ctx, tokenHash)
|
|
}
|
|
|
|
// SetCachedToken stores access token into cache.
|
|
func SetCachedToken(ctx context.Context, tokenHash string, token *CachedToken) {
|
|
d, _, _ := getDefaultRuntime()
|
|
d.SetCachedToken(ctx, tokenHash, token)
|
|
}
|
|
|
|
// InvalidateCachedToken invalidates access token cache.
|
|
func InvalidateCachedToken(ctx context.Context, tokenHash string) {
|
|
d, _, _ := getDefaultRuntime()
|
|
d.InvalidateCachedToken(ctx, tokenHash)
|
|
}
|
|
|
|
// GetCachedUser reads cached user.
|
|
func GetCachedUser(ctx context.Context, userID uint64) (*contracts.UserDTO, error) {
|
|
d, _, _ := getDefaultRuntime()
|
|
return d.GetCachedUser(ctx, userID)
|
|
}
|
|
|
|
// SetCachedUser stores user into cache.
|
|
func SetCachedUser(ctx context.Context, userID uint64, u *contracts.UserDTO) {
|
|
d, _, _ := getDefaultRuntime()
|
|
d.SetCachedUser(ctx, userID, u)
|
|
}
|
|
|
|
// InvalidateCachedUser invalidates user cache.
|
|
func InvalidateCachedUser(ctx context.Context, userID uint64) {
|
|
d, _, _ := getDefaultRuntime()
|
|
d.InvalidateCachedUser(ctx, userID)
|
|
}
|
|
|
|
// ResetAuthRAMCacheForTest clears RAM caches.
|
|
func ResetAuthRAMCacheForTest() {
|
|
dao.ResetRAMCacheForTest()
|
|
}
|
|
|
|
// StopAuthCacheListener compatibility stub.
|
|
func StopAuthCacheListener() {}
|
|
|
|
// SetCapSecret sets CAPTCHA secret.
|
|
func SetCapSecret(secret []byte) {
|
|
_, s, _ := getDefaultRuntime()
|
|
s.CapManager.SetSecret(secret)
|
|
}
|
|
|
|
// GetDefaultCapManager returns the singleton CAPTCHA manager.
|
|
func GetDefaultCapManager() *CaptchaManager {
|
|
_, s, _ := getDefaultRuntime()
|
|
return s.CapManager
|
|
}
|
|
|
|
// CurrentCapSettings returns current CAPTCHA runtime settings.
|
|
func CurrentCapSettings(ctx context.Context) (CapRuntimeSettings, error) {
|
|
_, s, _ := getDefaultRuntime()
|
|
return s.CapSettings.Current(ctx)
|
|
}
|
|
|
|
// CapProtectionEnabled checks if CAPTCHA is enabled.
|
|
func CapProtectionEnabled(ctx context.Context) bool {
|
|
_, s, _ := getDefaultRuntime()
|
|
return s.CapSettings.CapProtectionEnabled(ctx)
|
|
}
|
|
|
|
// InvalidateCapRuntimeSettings invalidates runtime CAPTCHA settings cache.
|
|
func InvalidateCapRuntimeSettings() {
|
|
_, s, _ := getDefaultRuntime()
|
|
s.CapSettings.Invalidate()
|
|
}
|
|
|
|
// ResetCapRuntimeSettingsForTest clears test CAPTCHA settings.
|
|
func ResetCapRuntimeSettingsForTest() {
|
|
InvalidateCapRuntimeSettings()
|
|
}
|
|
|
|
// InstallCapTestRuntimeSettings installs a test snapshot.
|
|
func InstallCapTestRuntimeSettings(settings CapRuntimeSettings) func() {
|
|
_, s, _ := getDefaultRuntime()
|
|
return s.CapSettings.InstallTestSnapshot(settings)
|
|
}
|
|
|
|
// VerifyCaptchaMiddleware returns captcha verification middleware.
|
|
func VerifyCaptchaMiddleware(mgr *service.CaptchaManager, scope string) gin.HandlerFunc {
|
|
_, s, _ := getDefaultRuntime()
|
|
return controller.VerifyCaptchaMiddleware(mgr, s.CapSettings, scope)
|
|
}
|
|
|
|
// Challenge HTTP handler.
|
|
func Challenge(c *gin.Context) {
|
|
_, _, ctrl := getDefaultRuntime()
|
|
ctrl.Captcha.Challenge(c)
|
|
}
|
|
|
|
// Redeem HTTP handler.
|
|
func Redeem(c *gin.Context) {
|
|
_, _, ctrl := getDefaultRuntime()
|
|
ctrl.Captcha.Redeem(c)
|
|
}
|
|
|
|
// GetLoginSources HTTP handler.
|
|
func GetLoginSources(c *gin.Context) {
|
|
_, _, ctrl := getDefaultRuntime()
|
|
ctrl.OAuth.GetLoginSources(c)
|
|
}
|
|
|
|
// GetLoginURL HTTP handler.
|
|
func GetLoginURL(c *gin.Context) {
|
|
_, _, ctrl := getDefaultRuntime()
|
|
ctrl.OAuth.GetLoginURL(c)
|
|
}
|
|
|
|
// Authorize HTTP handler.
|
|
func Authorize(c *gin.Context) {
|
|
_, _, ctrl := getDefaultRuntime()
|
|
ctrl.OAuth.Authorize(c)
|
|
}
|
|
|
|
// Callback HTTP handler.
|
|
func Callback(c *gin.Context) {
|
|
_, _, ctrl := getDefaultRuntime()
|
|
ctrl.OAuth.Callback(c)
|
|
}
|
|
|
|
// Logout HTTP handler.
|
|
func Logout(c *gin.Context) {
|
|
_, _, ctrl := getDefaultRuntime()
|
|
ctrl.OAuth.Logout(c)
|
|
}
|
|
|
|
// UserInfo HTTP handler.
|
|
func UserInfo(c *gin.Context) {
|
|
_, _, ctrl := getDefaultRuntime()
|
|
ctrl.UserInfo.UserInfo(c)
|
|
}
|
|
|
|
// ListExternalAccounts HTTP handler.
|
|
func ListExternalAccounts(c *gin.Context) {
|
|
_, _, ctrl := getDefaultRuntime()
|
|
ctrl.OAuth.ListExternalAccounts(c)
|
|
}
|
|
|
|
// DeleteExternalAccount HTTP handler.
|
|
func DeleteExternalAccount(c *gin.Context) {
|
|
_, _, ctrl := getDefaultRuntime()
|
|
ctrl.OAuth.DeleteExternalAccount(c)
|
|
}
|
|
|
|
// InvalidateOIDCProviderCache invalidates OIDC provider cache entry.
|
|
func InvalidateOIDCProviderCache(issuer string) {
|
|
_, s, _ := getDefaultRuntime()
|
|
s.OIDCProviderCache.Invalidate(issuer)
|
|
}
|