mirror of
https://github.com/Rain-kl/OpenFlare.git
synced 2026-09-30 22:26:38 +08:00
455e2f8be5
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.
160 lines
4.2 KiB
Go
160 lines
4.2 KiB
Go
// Copyright 2026 Arctel.net
|
|
// SPDX-License-Identifier: Apache-2.0
|
|
|
|
package system
|
|
|
|
import (
|
|
"context"
|
|
"encoding/json"
|
|
"errors"
|
|
"net/http"
|
|
"net/http/httptest"
|
|
"strings"
|
|
"testing"
|
|
|
|
"Wavelet/core"
|
|
"Wavelet/core/contracts"
|
|
|
|
"github.com/gin-gonic/gin"
|
|
)
|
|
|
|
type stubPublic struct{ payload map[string]string }
|
|
|
|
func (s stubPublic) PublicConfig(context.Context) (map[string]string, error) {
|
|
return s.payload, nil
|
|
}
|
|
|
|
type errPublic struct{ err error }
|
|
|
|
func (s errPublic) PublicConfig(context.Context) (map[string]string, error) {
|
|
return nil, s.err
|
|
}
|
|
|
|
func TestPublicConfigUsesProviderWhenPresent(t *testing.T) {
|
|
gin.SetMode(gin.TestMode)
|
|
ctx := core.NewContext(context.Background())
|
|
core.Provide[contracts.PublicConfigProvider](ctx, stubPublic{payload: map[string]string{"k": "v"}})
|
|
if err := New().Apply(ctx); err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
body := invokePublicConfig(t, publicConfigHandler(t, ctx))
|
|
assertFlatKV(t, body)
|
|
}
|
|
|
|
func TestPublicConfigUsesProviderRegisteredAfterApply(t *testing.T) {
|
|
gin.SetMode(gin.TestMode)
|
|
ctx := core.NewContext(context.Background())
|
|
if err := New().Apply(ctx); err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
core.Provide[contracts.PublicConfigProvider](ctx, stubPublic{payload: map[string]string{"k": "v"}})
|
|
body := invokePublicConfig(t, publicConfigHandler(t, ctx))
|
|
assertFlatKV(t, body)
|
|
}
|
|
|
|
func TestPublicConfigDefaultWithoutProvider(t *testing.T) {
|
|
gin.SetMode(gin.TestMode)
|
|
ctx := core.NewContext(context.Background())
|
|
if err := New().Apply(ctx); err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
if !ctx.Router().IsWhitelisted("/api/v1/config/public") {
|
|
t.Fatal("GET /api/v1/config/public not whitelisted")
|
|
}
|
|
raw := invokePublicConfig(t, publicConfigHandler(t, ctx))
|
|
var data map[string]any
|
|
if err := json.Unmarshal(raw, &data); err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
if len(data) != 0 {
|
|
t.Fatalf("data = %s, want empty flat map", raw)
|
|
}
|
|
if _, ok := data["configs"]; ok {
|
|
t.Fatalf("data = %s, default payload must not wrap configs", raw)
|
|
}
|
|
if _, ok := data["app"]; ok {
|
|
t.Fatalf("data = %s, default payload must not wrap app", raw)
|
|
}
|
|
}
|
|
|
|
func TestPublicConfigProviderErrorAbortsInternal(t *testing.T) {
|
|
gin.SetMode(gin.TestMode)
|
|
ctx := core.NewContext(context.Background())
|
|
core.Provide[contracts.PublicConfigProvider](ctx, errPublic{err: errors.New("secret boom")})
|
|
if err := New().Apply(ctx); err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
|
|
w := httptest.NewRecorder()
|
|
c, _ := gin.CreateTestContext(w)
|
|
c.Request = httptest.NewRequest(http.MethodGet, "/api/v1/config/public", nil)
|
|
publicConfigHandler(t, ctx)(c)
|
|
|
|
if !c.IsAborted() {
|
|
t.Fatal("want request aborted on provider error")
|
|
}
|
|
if len(c.Errors) == 0 {
|
|
t.Fatal("want gin error on provider failure")
|
|
}
|
|
if got := c.Errors.Last().Error(); got != "public config unavailable" {
|
|
t.Fatalf("error = %q, want generic message", got)
|
|
}
|
|
if strings.Contains(w.Body.String(), "secret boom") {
|
|
t.Fatalf("leaked provider error: %s", w.Body.String())
|
|
}
|
|
}
|
|
|
|
func publicConfigHandler(t *testing.T, ctx *core.Context) gin.HandlerFunc {
|
|
t.Helper()
|
|
for _, rd := range ctx.Router().Routes() {
|
|
if rd.Method != "GET" || rd.Path != "/api/v1/config/public" {
|
|
continue
|
|
}
|
|
if len(rd.Handlers) == 0 {
|
|
break
|
|
}
|
|
switch h := rd.Handlers[0].(type) {
|
|
case gin.HandlerFunc:
|
|
return h
|
|
case func(*gin.Context):
|
|
return h
|
|
default:
|
|
t.Fatalf("unexpected handler type %T", rd.Handlers[0])
|
|
}
|
|
}
|
|
t.Fatal("public config route missing")
|
|
return nil
|
|
}
|
|
|
|
func invokePublicConfig(t *testing.T, handler gin.HandlerFunc) json.RawMessage {
|
|
t.Helper()
|
|
w := httptest.NewRecorder()
|
|
c, _ := gin.CreateTestContext(w)
|
|
c.Request = httptest.NewRequest(http.MethodGet, "/api/v1/config/public", nil)
|
|
handler(c)
|
|
var body struct {
|
|
Data json.RawMessage `json:"data"`
|
|
}
|
|
if err := json.Unmarshal(w.Body.Bytes(), &body); err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
return body.Data
|
|
}
|
|
|
|
func assertFlatKV(t *testing.T, raw json.RawMessage) {
|
|
t.Helper()
|
|
var data map[string]any
|
|
if err := json.Unmarshal(raw, &data); err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
if data["k"] != "v" {
|
|
t.Fatalf("data = %s, want flat map", raw)
|
|
}
|
|
if _, ok := data["configs"]; ok {
|
|
t.Fatalf("data = %s, want provider payload without default configs", raw)
|
|
}
|
|
if _, ok := data["app"]; ok {
|
|
t.Fatalf("data = %s, want provider payload without default app", raw)
|
|
}
|
|
}
|