mirror of
https://github.com/NoFxAiOS/nofx.git
synced 2026-07-16 01:06:59 +08:00
fix(security): harden auth flows and lock down telegram bot tool
- config: require JWT_SECRET >=32 bytes and reject the historical default fallback; MustInit aborts startup under an insecure config - api: CORS now uses CORS_ALLOWED_ORIGINS allowlist with safe localhost defaults instead of returning Access-Control-Allow-Origin: * - api: /api/reset-password and /api/reset-account stay public so recovery still works, but require an explicit confirm phrase in the body to block accidental and drive-by triggers - api: drop adoptOrphanRecords so wiping the account no longer hands the next registrant the previous owner's wallet keys and exchange API credentials - api: getTraderFromQuery now does a soft ownership check; equity-history is restricted to traders with show_in_competition=true and GetOrderFills joins on trader_id - telegram: bot api_request tool uses a default-deny method+path allowlist so prompt injection cannot reach password, exchange key, AI provider or wallet endpoints - ci: drop @master / @main on trivy-action and trufflehog; pin to released versions with a TODO to move to SHA + Dependabot - web: reset flows send the required confirm phrase; "Forgot account" copy (en/zh/id) warns that wallet and exchange keys will be lost - docker-compose: keep ./.env mount for onboarding wallet persistence with an inline note on the tradeoff, drop the host-exposed pprof port
This commit is contained in:
@@ -1,13 +1,23 @@
|
||||
package config
|
||||
|
||||
import (
|
||||
"nofx/telemetry"
|
||||
"fmt"
|
||||
"nofx/mcp"
|
||||
"nofx/telemetry"
|
||||
"os"
|
||||
"strconv"
|
||||
"strings"
|
||||
)
|
||||
|
||||
// insecureDefaultJWTSecret is the historical fallback value. Refusing to boot when
|
||||
// JWT_SECRET matches it (or is missing) prevents the server from silently signing
|
||||
// tokens with a well-known secret.
|
||||
const insecureDefaultJWTSecret = "default-jwt-secret-change-in-production"
|
||||
|
||||
// minJWTSecretLength is the minimum byte length we accept for HS256 signing keys.
|
||||
// HS256 keys shorter than 32 bytes are brute-forceable.
|
||||
const minJWTSecretLength = 32
|
||||
|
||||
// Global configuration instance
|
||||
var global *Config
|
||||
|
||||
@@ -45,8 +55,24 @@ type Config struct {
|
||||
|
||||
}
|
||||
|
||||
// Init initializes global configuration (from .env)
|
||||
// MustInit initializes global configuration or panics. Use from main() so the
|
||||
// process refuses to start under an insecure config (e.g. default JWT secret).
|
||||
func MustInit() {
|
||||
if err := initConfig(); err != nil {
|
||||
panic(fmt.Sprintf("config: %v", err))
|
||||
}
|
||||
}
|
||||
|
||||
// Init initializes global configuration (from .env). Prefer MustInit from main.
|
||||
func Init() {
|
||||
if err := initConfig(); err != nil {
|
||||
// Preserve historical fail-soft behavior for non-main callers (tests, tools);
|
||||
// the process can still observe the error via Get() returning nil.
|
||||
fmt.Fprintf(os.Stderr, "config init failed: %v\n", err)
|
||||
}
|
||||
}
|
||||
|
||||
func initConfig() error {
|
||||
cfg := &Config{
|
||||
APIServerPort: 8080,
|
||||
ExperienceImprovement: true, // Default: enabled to help improve the product
|
||||
@@ -65,7 +91,13 @@ func Init() {
|
||||
cfg.JWTSecret = strings.TrimSpace(v)
|
||||
}
|
||||
if cfg.JWTSecret == "" {
|
||||
cfg.JWTSecret = "default-jwt-secret-change-in-production"
|
||||
return fmt.Errorf("JWT_SECRET is required (set a random %d+ byte value in .env)", minJWTSecretLength)
|
||||
}
|
||||
if cfg.JWTSecret == insecureDefaultJWTSecret {
|
||||
return fmt.Errorf("JWT_SECRET matches the insecure default; generate a fresh random value (e.g. `openssl rand -base64 48`)")
|
||||
}
|
||||
if len(cfg.JWTSecret) < minJWTSecretLength {
|
||||
return fmt.Errorf("JWT_SECRET must be at least %d bytes (got %d); generate via `openssl rand -base64 48`", minJWTSecretLength, len(cfg.JWTSecret))
|
||||
}
|
||||
|
||||
if v := os.Getenv("API_SERVER_PORT"); v != "" {
|
||||
@@ -134,6 +166,7 @@ func Init() {
|
||||
OutputTokens: usage.CompletionTokens,
|
||||
})
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// Get returns the global configuration
|
||||
|
||||
Reference in New Issue
Block a user