fix(config): serve public settings and enforce login CAP

Public config now comes from admin as a flat visibility=1 map instead of
a cross-plugin query that compared an integer column to "visible". Login
and register resolve CaptchaService per request so CAP is not skipped
when user applies before cap.
This commit is contained in:
ryan
2026-09-02 17:07:07 +08:00
parent 4f50f6a8f9
commit 455e2f8be5
17 changed files with 289 additions and 94 deletions
@@ -16,7 +16,7 @@ import (
// GetPublicConfig 获取公共配置
// @Summary 获取公共配置
// @Description 返回系统配置表中 visibility 为 1 的配置键值集合
// @Description 返回系统配置表中 visibility 为 1 的扁平键值集合(如 cap_login_enabled)
// @Tags config
// @Accept json
// @Produce json
+1
View File
@@ -92,6 +92,7 @@ func (p *Plugin) Apply(ctx *core.Context) error {
core.Bind[contracts.StorageService](ctx, service.SetStorageService)
core.Bind[contracts.RiskControlService](ctx, service.SetRiskControlService)
service.SetEventEmitter(ctx.Events().Emit)
core.Provide[contracts.PublicConfigProvider](ctx, service.PublicConfigAdapter{})
ctx.OnDispose(func() error {
service.ResetServices()
@@ -5,6 +5,7 @@ package admin_test
import (
"Wavelet/core"
"Wavelet/core/contracts"
"Wavelet/plugins/domain/admin"
"context"
"testing"
@@ -40,6 +41,10 @@ func TestAdminPluginUnit(t *testing.T) {
setting, ok := ctx.Settings().Get("admin.system_cleanup_cron")
require.True(t, ok)
assert.Equal(t, "0 4 * * *", setting.Default)
provider, err := core.Inject[contracts.PublicConfigProvider](ctx)
require.NoError(t, err)
require.NotNil(t, provider)
}
func TestAdminMigrationsIncludeTaskExecutionsAndSchedules(t *testing.T) {
@@ -18,6 +18,14 @@ import (
const maskedConfigValue = "******"
// PublicConfigAdapter exposes visibility=1 system configs as PublicConfigProvider.
type PublicConfigAdapter struct{}
// PublicConfig returns the unauthenticated public config map.
func (PublicConfigAdapter) PublicConfig(ctx context.Context) (map[string]string, error) {
return PublicSystemConfigs(ctx)
}
// PublicSystemConfigs returns the key/value map exposed to unauthenticated clients.
func PublicSystemConfigs(ctx context.Context) (map[string]string, error) {
configs, err := repository.ListVisibleSystemConfigs(ctx)
@@ -69,6 +69,51 @@ func setupSystemConfigTest(t *testing.T) (*gorm.DB, func()) {
return sqliteDB, cleanup
}
func TestPublicSystemConfigsExposesVisibleKeys(t *testing.T) {
dbConn, cleanup := setupSystemConfigTest(t)
defer cleanup()
repository.ResetSystemConfigRAMCacheForTest()
ctx := context.Background()
hidden := model.SystemConfig{
Key: "secret_key",
Value: "nope",
Type: "system",
Visibility: model.ConfigVisibilityHidden,
}
visible := model.SystemConfig{
Key: model.ConfigKeyCapLoginEnabled,
Value: "true",
Type: "system",
Visibility: model.ConfigVisibilityVisible,
}
if err := dbConn.Create(&hidden).Error; err != nil {
t.Fatalf("Create(hidden) error = %v", err)
}
if err := dbConn.Create(&visible).Error; err != nil {
t.Fatalf("Create(visible) error = %v", err)
}
got, err := service.PublicSystemConfigs(ctx)
if err != nil {
t.Fatalf("PublicSystemConfigs() error = %v", err)
}
if got[model.ConfigKeyCapLoginEnabled] != "true" {
t.Fatalf("PublicSystemConfigs()[%s] = %q, want %q", model.ConfigKeyCapLoginEnabled, got[model.ConfigKeyCapLoginEnabled], "true")
}
if _, ok := got["secret_key"]; ok {
t.Fatalf("PublicSystemConfigs() leaked hidden key secret_key")
}
viaProvider, err := service.PublicConfigAdapter{}.PublicConfig(ctx)
if err != nil {
t.Fatalf("PublicConfigAdapter.PublicConfig() error = %v", err)
}
if viaProvider[model.ConfigKeyCapLoginEnabled] != "true" {
t.Fatalf("PublicConfigAdapter.PublicConfig()[%s] = %q, want %q", model.ConfigKeyCapLoginEnabled, viaProvider[model.ConfigKeyCapLoginEnabled], "true")
}
}
func TestListSystemConfigsByKeys_EmptyKeys(t *testing.T) {
result, err := repository.ListSystemConfigsByKeys(context.Background(), nil)
if err != nil {