mirror of
https://github.com/router-for-me/CLIProxyAPI.git
synced 2026-05-20 09:17:43 +08:00
feat(api): add support for local management password validation and spoofed IP rejection
- Introduced `newTestServerWithOptions` to customize server initialization in tests. - Added `TestManagementLocalPasswordRejectsSpoofedForwardedFor` to validate security against spoofed `X-Forwarded-For` headers. - Enabled default WebSocket authentication (`ws-auth`) in `config.example.yaml`. - Disabled trusted proxy headers in Gin engine with appropriate logging to enhance security.
This commit is contained in:
@@ -143,7 +143,7 @@ routing:
|
||||
session-affinity-ttl: "1h"
|
||||
|
||||
# When true, enable authentication for the WebSocket API (/v1/ws).
|
||||
ws-auth: false
|
||||
ws-auth: true
|
||||
|
||||
# When true, enable Gemini CLI internal endpoints (/v1internal:*).
|
||||
# Default is false for safety.
|
||||
|
||||
@@ -217,6 +217,9 @@ func NewServer(cfg *config.Config, authManager *auth.Manager, accessManager *sdk
|
||||
|
||||
// Create gin engine
|
||||
engine := gin.New()
|
||||
if errSetTrustedProxies := engine.SetTrustedProxies(nil); errSetTrustedProxies != nil {
|
||||
log.Warnf("failed to disable trusted proxy headers: %v", errSetTrustedProxies)
|
||||
}
|
||||
if optionState.engineConfigurator != nil {
|
||||
optionState.engineConfigurator(engine)
|
||||
}
|
||||
|
||||
@@ -21,6 +21,10 @@ import (
|
||||
)
|
||||
|
||||
func newTestServer(t *testing.T) *Server {
|
||||
return newTestServerWithOptions(t)
|
||||
}
|
||||
|
||||
func newTestServerWithOptions(t *testing.T, opts ...ServerOption) *Server {
|
||||
t.Helper()
|
||||
|
||||
gin.SetMode(gin.TestMode)
|
||||
@@ -46,7 +50,7 @@ func newTestServer(t *testing.T) *Server {
|
||||
accessManager := sdkaccess.NewManager()
|
||||
|
||||
configPath := filepath.Join(tmpDir, "config.yaml")
|
||||
return NewServer(cfg, authManager, accessManager, configPath)
|
||||
return NewServer(cfg, authManager, accessManager, configPath, opts...)
|
||||
}
|
||||
|
||||
func TestHealthz(t *testing.T) {
|
||||
@@ -148,6 +152,26 @@ func TestManagementUsageRequiresManagementAuthAndPopsArray(t *testing.T) {
|
||||
}
|
||||
}
|
||||
|
||||
func TestManagementLocalPasswordRejectsSpoofedForwardedFor(t *testing.T) {
|
||||
t.Setenv("MANAGEMENT_PASSWORD", "")
|
||||
|
||||
server := newTestServerWithOptions(t, WithLocalManagementPassword("test-local-key"))
|
||||
|
||||
req := httptest.NewRequest(http.MethodGet, "/v0/management/config", nil)
|
||||
req.RemoteAddr = "203.0.113.10:45678"
|
||||
req.Header.Set("X-Forwarded-For", "127.0.0.1")
|
||||
req.Header.Set("Authorization", "Bearer test-local-key")
|
||||
|
||||
rr := httptest.NewRecorder()
|
||||
server.engine.ServeHTTP(rr, req)
|
||||
if rr.Code != http.StatusForbidden {
|
||||
t.Fatalf("status = %d, want %d body=%s", rr.Code, http.StatusForbidden, rr.Body.String())
|
||||
}
|
||||
if body := rr.Body.String(); !strings.Contains(body, "remote management disabled") {
|
||||
t.Fatalf("body = %q, want remote management disabled", body)
|
||||
}
|
||||
}
|
||||
|
||||
func TestHomeEnabledHidesManagementEndpointsAndControlPanel(t *testing.T) {
|
||||
t.Setenv("MANAGEMENT_PASSWORD", "test-management-key")
|
||||
|
||||
|
||||
Reference in New Issue
Block a user