Files
OpenFlare/backend/plugins/domain/auth/service/cap_settings.go
T

120 lines
3.2 KiB
Go

// Copyright 2026 Arctel.net
// SPDX-License-Identifier: Apache-2.0
// Package service implements domain business services and orchestration for the auth plugin.
package service
import (
"Wavelet/plugins/domain/auth/consts"
"Wavelet/plugins/domain/auth/dao"
"Wavelet/plugins/domain/auth/model/do"
"context"
"errors"
"sync/atomic"
"golang.org/x/sync/singleflight"
)
var capRuntimeConfigKeys = []string{
consts.ConfigKeyCapLoginEnabled,
consts.ConfigKeyCapChallengeCount,
consts.ConfigKeyCapChallengeSize,
consts.ConfigKeyCapChallengeDifficulty,
consts.ConfigKeyCapChallengeTTL,
consts.ConfigKeyCapTokenTTL,
}
var capRuntimeConfigKeySet = func() map[string]struct{} {
set := make(map[string]struct{}, len(capRuntimeConfigKeys))
for _, key := range capRuntimeConfigKeys {
set[key] = struct{}{}
}
return set
}()
// IsCapRuntimeConfigKey reports whether a system config key affects CAPTCHA runtime settings.
func IsCapRuntimeConfigKey(key string) bool {
_, ok := capRuntimeConfigKeySet[key]
return ok
}
// CapSettingsManager manages dynamic CAPTCHA configuration cache.
type CapSettingsManager struct {
dao *dao.DAO
snapshot atomic.Pointer[do.CapRuntimeSettings]
loadGroup singleflight.Group
}
// NewCapSettingsManager creates a new CapSettingsManager.
func NewCapSettingsManager(d *dao.DAO) *CapSettingsManager {
return &CapSettingsManager{
dao: d,
}
}
// Invalidate drops the in-process CAPTCHA settings snapshot.
func (m *CapSettingsManager) Invalidate() {
m.snapshot.Store(nil)
}
// Current returns the cached CAPTCHA runtime settings snapshot.
func (m *CapSettingsManager) Current(ctx context.Context) (do.CapRuntimeSettings, error) {
if snapshot := m.snapshot.Load(); snapshot != nil {
return *snapshot, nil
}
loaded, err, _ := m.loadGroup.Do("cap-runtime-settings", func() (any, error) {
if snapshot := m.snapshot.Load(); snapshot != nil {
return *snapshot, nil
}
settings, loadErr := m.loadSettings(ctx)
if loadErr != nil {
return do.CapRuntimeSettings{}, loadErr
}
m.snapshot.Store(&settings)
return settings, nil
})
if err != nil {
return do.CapRuntimeSettings{}, err
}
settings, ok := loaded.(do.CapRuntimeSettings)
if !ok {
return do.CapRuntimeSettings{}, errors.New("cap runtime settings loader returned unexpected type")
}
return settings, nil
}
// CapProtectionEnabled reports whether CAPTCHA verification is required for protected routes.
func (m *CapSettingsManager) CapProtectionEnabled(ctx context.Context) bool {
settings, err := m.Current(ctx)
if err != nil {
return false
}
return settings.LoginEnabled
}
// InstallTestSnapshot installs a fixed snapshot for unit tests.
func (m *CapSettingsManager) InstallTestSnapshot(settings do.CapRuntimeSettings) func() {
snapshot := settings
m.snapshot.Store(&snapshot)
return m.Invalidate
}
func (m *CapSettingsManager) loadSettings(ctx context.Context) (do.CapRuntimeSettings, error) {
if m.dao == nil {
return do.ParseCapRuntimeSettings(nil), nil
}
records, err := m.dao.ListSystemConfigsByKeys(ctx, capRuntimeConfigKeys)
if err != nil {
return do.CapRuntimeSettings{}, err
}
configs := make(map[string]string, len(records))
for _, r := range records {
configs[r.Key] = r.Value
}
return do.ParseCapRuntimeSettings(configs), nil
}