diff --git a/.env.example b/.env.example index 2355f35a..cd64fe4e 100644 --- a/.env.example +++ b/.env.example @@ -12,5 +12,3 @@ NOFX_FRONTEND_PORT=3000 # System timezone for container time synchronization NOFX_TIMEZONE=Asia/Shanghai -# Admin password when admin_mode=true -NOFX_ADMIN_PASSWORD=YOUR_PASS diff --git a/api/server.go b/api/server.go index 1ae567ec..d95782e9 100644 --- a/api/server.go +++ b/api/server.go @@ -75,7 +75,6 @@ func (s *Server) setupRoutes() { api.Any("/health", s.handleHealth) // 管理员登录(管理员模式下使用,公共) - api.POST("/admin-login", s.handleAdminLogin) // 系统支持的模型和交易所(无需认证) api.GET("/supported-models", s.handleGetSupportedModels) @@ -96,14 +95,11 @@ func (s *Server) setupRoutes() { api.POST("/equity-history-batch", s.handleEquityHistoryBatch) api.GET("/traders/:id/public-config", s.handleGetPublicTraderConfig) - // 仅在非管理员模式下的路由 - if !auth.IsAdminMode() { - // 认证相关路由(无需认证) - api.POST("/register", s.handleRegister) - api.POST("/login", s.handleLogin) - api.POST("/verify-otp", s.handleVerifyOTP) - api.POST("/complete-registration", s.handleCompleteRegistration) - } + // 认证相关路由(无需认证) + api.POST("/register", s.handleRegister) + api.POST("/login", s.handleLogin) + api.POST("/verify-otp", s.handleVerifyOTP) + api.POST("/complete-registration", s.handleCompleteRegistration) // 需要认证的路由 protected := api.Group("/", s.authMiddleware()) @@ -189,7 +185,6 @@ func (s *Server) handleGetSystemConfig(c *gin.Context) { betaMode := betaModeStr == "true" c.JSON(http.StatusOK, gin.H{ - "admin_mode": auth.IsAdminMode(), "beta_mode": betaMode, "default_coins": defaultCoins, "btc_eth_leverage": btcEthLeverage, @@ -381,6 +376,16 @@ type ModelConfig struct { CustomAPIURL string `json:"customApiUrl,omitempty"` } +// SafeModelConfig 安全的模型配置结构(不包含敏感信息) +type SafeModelConfig struct { + ID string `json:"id"` + Name string `json:"name"` + Provider string `json:"provider"` + Enabled bool `json:"enabled"` + CustomAPIURL string `json:"customApiUrl"` // 自定义API URL(通常不敏感) + CustomModelName string `json:"customModelName"` // 自定义模型名(不敏感) +} + type ExchangeConfig struct { ID string `json:"id"` Name string `json:"name"` @@ -391,6 +396,18 @@ type ExchangeConfig struct { Testnet bool `json:"testnet,omitempty"` } +// SafeExchangeConfig 安全的交易所配置结构(不包含敏感信息) +type SafeExchangeConfig struct { + ID string `json:"id"` + Name string `json:"name"` + Type string `json:"type"` // "cex" or "dex" + Enabled bool `json:"enabled"` + Testnet bool `json:"testnet,omitempty"` + HyperliquidWalletAddr string `json:"hyperliquid_wallet_addr"` // Hyperliquid钱包地址(不敏感) + AsterUser string `json:"aster_user"` // Aster用户名(不敏感) + AsterSigner string `json:"aster_signer"` // Aster签名者(不敏感) +} + type UpdateModelConfigRequest struct { Models map[string]struct { Enabled bool `json:"enabled"` @@ -971,7 +988,20 @@ func (s *Server) handleGetModelConfigs(c *gin.Context) { } log.Printf("✅ 找到 %d 个AI模型配置", len(models)) - c.JSON(http.StatusOK, models) + // 转换为安全的响应结构,移除敏感信息 + safeModels := make([]SafeModelConfig, len(models)) + for i, model := range models { + safeModels[i] = SafeModelConfig{ + ID: model.ID, + Name: model.Name, + Provider: model.Provider, + Enabled: model.Enabled, + CustomAPIURL: model.CustomAPIURL, + CustomModelName: model.CustomModelName, + } + } + + c.JSON(http.StatusOK, safeModels) } // handleUpdateModelConfigs 更新AI模型配置 @@ -1015,7 +1045,22 @@ func (s *Server) handleGetExchangeConfigs(c *gin.Context) { } log.Printf("✅ 找到 %d 个交易所配置", len(exchanges)) - c.JSON(http.StatusOK, exchanges) + // 转换为安全的响应结构,移除敏感信息 + safeExchanges := make([]SafeExchangeConfig, len(exchanges)) + for i, exchange := range exchanges { + safeExchanges[i] = SafeExchangeConfig{ + ID: exchange.ID, + Name: exchange.Name, + Type: exchange.Type, + Enabled: exchange.Enabled, + Testnet: exchange.Testnet, + HyperliquidWalletAddr: exchange.HyperliquidWalletAddr, + AsterUser: exchange.AsterUser, + AsterSigner: exchange.AsterSigner, + } + } + + c.JSON(http.StatusOK, safeExchanges) } // handleUpdateExchangeConfigs 更新交易所配置 @@ -1507,35 +1552,6 @@ func (s *Server) authMiddleware() gin.HandlerFunc { } } -// handleAdminLogin 管理员登录(密码仅来自环境变量) -func (s *Server) handleAdminLogin(c *gin.Context) { - if !auth.IsAdminMode() { - c.JSON(http.StatusForbidden, gin.H{"error": "仅管理员模式可用"}) - return - } - - // 简单的IP速率限制(5次/分钟 + 递增退避) - // 为简化,此处省略复杂实现,可在后续使用中间件或Redis增强 - - var req struct { - Password string `json:"password"` - } - if err := c.ShouldBindJSON(&req); err != nil || strings.TrimSpace(req.Password) == "" { - c.JSON(http.StatusBadRequest, gin.H{"error": "缺少密码"}) - return - } - if !auth.CheckAdminPassword(req.Password) { - c.JSON(http.StatusUnauthorized, gin.H{"error": "密码错误"}) - return - } - - token, err := auth.GenerateJWT("admin", "admin@localhost") - if err != nil { - c.JSON(http.StatusInternalServerError, gin.H{"error": "生成token失败"}) - return - } - c.JSON(http.StatusOK, gin.H{"token": token, "user_id": "admin", "email": "admin@localhost"}) -} // handleLogout 将当前token加入黑名单 func (s *Server) handleLogout(c *gin.Context) { @@ -1567,11 +1583,6 @@ func (s *Server) handleLogout(c *gin.Context) { // handleRegister 处理用户注册请求 func (s *Server) handleRegister(c *gin.Context) { - // 管理员模式下禁用注册 - if auth.IsAdminMode() { - c.JSON(http.StatusForbidden, gin.H{"error": "管理员模式下禁用注册"}) - return - } var req struct { Email string `json:"email" binding:"required,email"` @@ -1877,7 +1888,22 @@ func (s *Server) handleGetSupportedExchanges(c *gin.Context) { return } - c.JSON(http.StatusOK, exchanges) + // 转换为安全的响应结构,移除敏感信息 + safeExchanges := make([]SafeExchangeConfig, len(exchanges)) + for i, exchange := range exchanges { + safeExchanges[i] = SafeExchangeConfig{ + ID: exchange.ID, + Name: exchange.Name, + Type: exchange.Type, + Enabled: exchange.Enabled, + Testnet: exchange.Testnet, + HyperliquidWalletAddr: "", // 默认配置不包含钱包地址 + AsterUser: "", // 默认配置不包含用户信息 + AsterSigner: "", + } + } + + c.JSON(http.StatusOK, safeExchanges) } // Start 启动服务器 diff --git a/auth/auth.go b/auth/auth.go index ca23a4b9..c3c22bde 100644 --- a/auth/auth.go +++ b/auth/auth.go @@ -16,11 +16,6 @@ import ( // JWTSecret JWT密钥,将从配置中动态设置 var JWTSecret []byte -// AdminMode 管理员模式标志 -var AdminMode bool = false - -// adminPasswordHash 管理员密码哈希(仅内存) -var adminPasswordHash string // tokenBlacklist 用于登出后的token黑名单(仅内存,按过期时间清理) var tokenBlacklist = struct { @@ -39,33 +34,9 @@ func SetJWTSecret(secret string) { JWTSecret = []byte(secret) } -// SetAdminMode 设置管理员模式 -func SetAdminMode(enabled bool) { - AdminMode = enabled -} -// IsAdminMode 检查是否为管理员模式 -func IsAdminMode() bool { - return AdminMode -} -// SetAdminPasswordFromPlain 通过明文设置管理员密码(会使用bcrypt哈希,成本12) -func SetAdminPasswordFromPlain(plain string) error { - bytes, err := bcrypt.GenerateFromPassword([]byte(plain), 12) - if err != nil { - return err - } - adminPasswordHash = string(bytes) - return nil -} -// CheckAdminPassword 校验管理员密码 -func CheckAdminPassword(plain string) bool { - if adminPasswordHash == "" { - return false - } - return bcrypt.CompareHashAndPassword([]byte(adminPasswordHash), []byte(plain)) == nil -} // BlacklistToken 将token加入黑名单直到过期 func BlacklistToken(token string, exp time.Time) { diff --git a/config.json.example b/config.json.example index 820f39a7..1c7406d0 100644 --- a/config.json.example +++ b/config.json.example @@ -1,5 +1,4 @@ { - "admin_mode": true, "beta_mode": false, "leverage": { "btc_eth_leverage": 5, diff --git a/config/config.go b/config/config.go index 773a8d45..81ff3cea 100644 --- a/config/config.go +++ b/config/config.go @@ -29,7 +29,6 @@ type TelegramConfig struct { // Config 总配置 type Config struct { - AdminMode bool `json:"admin_mode"` BetaMode bool `json:"beta_mode"` APIServerPort int `json:"api_server_port"` UseDefaultCoins bool `json:"use_default_coins"` diff --git a/config/database.go b/config/database.go index 0ba3a4b6..9782408b 100644 --- a/config/database.go +++ b/config/database.go @@ -258,7 +258,6 @@ func (d *Database) initDefaultData() error { // 初始化系统配置 - 创建所有字段,设置默认值,后续由config.json同步更新 systemConfigs := map[string]string{ - "admin_mode": "true", // 默认开启管理员模式,便于首次使用 "beta_mode": "false", // 默认关闭内测模式 "api_server_port": "8080", // 默认API端口 "use_default_coins": "true", // 默认使用内置币种列表 diff --git a/docker-compose.yml b/docker-compose.yml index 075b6754..dc25bb44 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -18,7 +18,6 @@ services: environment: - TZ=${NOFX_TIMEZONE:-Asia/Shanghai} # Set timezone - AI_MAX_TOKENS=4000 # AI响应的最大token数(默认2000,建议4000-8000) - - NOFX_ADMIN_PASSWORD=${NOFX_ADMIN_PASSWORD} # Admin password when admin_mode=true networks: - nofx-network healthcheck: diff --git a/main.go b/main.go index cc3f4b09..2cb9f2da 100644 --- a/main.go +++ b/main.go @@ -22,7 +22,6 @@ import ( // ConfigFile 配置文件结构,只包含需要同步到数据库的字段 // TODO 现在与config.Config相同,未来会被替换, 现在为了兼容性不得不保留当前文件 type ConfigFile struct { - AdminMode bool `json:"admin_mode"` BetaMode bool `json:"beta_mode"` APIServerPort int `json:"api_server_port"` UseDefaultCoins bool `json:"use_default_coins"` @@ -71,7 +70,6 @@ func syncConfigToDatabase(database *config.Database, configFile *ConfigFile) err // 同步各配置项到数据库 configs := map[string]string{ - "admin_mode": fmt.Sprintf("%t", configFile.AdminMode), "beta_mode": fmt.Sprintf("%t", configFile.BetaMode), "api_server_port": strconv.Itoa(configFile.APIServerPort), "use_default_coins": fmt.Sprintf("%t", configFile.UseDefaultCoins), @@ -195,9 +193,6 @@ func main() { useDefaultCoins := useDefaultCoinsStr == "true" apiPortStr, _ := database.GetSystemConfig("api_server_port") - // 获取管理员模式配置 - adminModeStr, _ := database.GetSystemConfig("admin_mode") - adminMode := adminModeStr != "false" // 默认为true // 设置JWT密钥 jwtSecret, _ := database.GetSystemConfig("jwt_secret") @@ -208,17 +203,6 @@ func main() { auth.SetJWTSecret(jwtSecret) // 管理员模式下需要管理员密码,缺失则退出 - if adminMode { - adminPassword := os.Getenv("NOFX_ADMIN_PASSWORD") - if adminPassword == "" { - log.Fatalf("Admin mode is enabled but NOFX_ADMIN_PASSWORD is missing. Set NOFX_ADMIN_PASSWORD and restart.") - } - if err := auth.SetAdminPasswordFromPlain(adminPassword); err != nil { - log.Fatalf("Failed to set admin password: %v", err) - } - auth.SetAdminMode(true) - log.Printf("✓ Admin mode enabled. All API endpoints require admin authentication.") - } log.Printf("✓ 配置数据库初始化成功") fmt.Println() diff --git a/trader/hyperliquid_trader.go b/trader/hyperliquid_trader.go index 1d32d822..d0f80922 100644 --- a/trader/hyperliquid_trader.go +++ b/trader/hyperliquid_trader.go @@ -89,7 +89,7 @@ func NewHyperliquidTrader(privateKeyHex string, walletAddr string, testnet bool) // Only check if using separate Agent wallet (not when main wallet is used as agent) if !strings.EqualFold(walletAddr, agentAddr) { agentState, err := exchange.Info().UserState(ctx, agentAddr) - if err == nil && agentState != nil && agentState.CrossMarginSummary != nil { + if err == nil && agentState != nil && agentState.CrossMarginSummary.AccountValue != "" { // Parse Agent wallet balance agentBalance, _ := strconv.ParseFloat(agentState.CrossMarginSummary.AccountValue, 64) diff --git a/web/package-lock.json b/web/package-lock.json index f33e8d39..e1292d5d 100644 --- a/web/package-lock.json +++ b/web/package-lock.json @@ -116,7 +116,6 @@ "resolved": "https://registry.npmjs.org/@babel/core/-/core-7.28.5.tgz", "integrity": "sha512-e7jT4DxYvIDLk1ZHmU/m/mB19rex9sv0c2ftBtjSBv+kVM/902eh0fINUzD7UwLLNR+jU585GxUJ8/EBfAM5fw==", "dev": true, - "peer": true, "dependencies": { "@babel/code-frame": "^7.27.1", "@babel/generator": "^7.28.5", @@ -448,7 +447,6 @@ } ], "license": "MIT", - "peer": true, "engines": { "node": ">=18" }, @@ -472,7 +470,6 @@ } ], "license": "MIT", - "peer": true, "engines": { "node": ">=18" } @@ -1141,6 +1138,7 @@ "dev": true, "license": "MIT", "optional": true, + "peer": true, "engines": { "node": ">=18" } @@ -1152,6 +1150,7 @@ "dev": true, "license": "MIT", "optional": true, + "peer": true, "dependencies": { "@inquirer/core": "^10.3.0", "@inquirer/type": "^3.0.9" @@ -1175,6 +1174,7 @@ "dev": true, "license": "MIT", "optional": true, + "peer": true, "dependencies": { "@inquirer/ansi": "^1.0.1", "@inquirer/figures": "^1.0.14", @@ -1204,6 +1204,7 @@ "dev": true, "license": "MIT", "optional": true, + "peer": true, "engines": { "node": ">=8" } @@ -1215,6 +1216,7 @@ "dev": true, "license": "MIT", "optional": true, + "peer": true, "dependencies": { "color-convert": "^2.0.1" }, @@ -1231,7 +1233,8 @@ "integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==", "dev": true, "license": "MIT", - "optional": true + "optional": true, + "peer": true }, "node_modules/@inquirer/core/node_modules/string-width": { "version": "4.2.3", @@ -1240,6 +1243,7 @@ "dev": true, "license": "MIT", "optional": true, + "peer": true, "dependencies": { "emoji-regex": "^8.0.0", "is-fullwidth-code-point": "^3.0.0", @@ -1256,6 +1260,7 @@ "dev": true, "license": "MIT", "optional": true, + "peer": true, "dependencies": { "ansi-regex": "^5.0.1" }, @@ -1270,6 +1275,7 @@ "dev": true, "license": "MIT", "optional": true, + "peer": true, "dependencies": { "ansi-styles": "^4.0.0", "string-width": "^4.1.0", @@ -1286,6 +1292,7 @@ "dev": true, "license": "MIT", "optional": true, + "peer": true, "engines": { "node": ">=18" } @@ -1297,6 +1304,7 @@ "dev": true, "license": "MIT", "optional": true, + "peer": true, "engines": { "node": ">=18" }, @@ -1378,6 +1386,7 @@ "dev": true, "license": "MIT", "optional": true, + "peer": true, "dependencies": { "@open-draft/deferred-promise": "^2.2.0", "@open-draft/logger": "^0.3.0", @@ -1431,7 +1440,8 @@ "integrity": "sha512-CecwLWx3rhxVQF6V4bAgPS5t+So2sTbPgAzafKkVizyi7tlwpcFpdFqq+wqF2OwNBmqFuu6tOyouTuxgpMfzmA==", "dev": true, "license": "MIT", - "optional": true + "optional": true, + "peer": true }, "node_modules/@open-draft/logger": { "version": "0.3.0", @@ -1440,6 +1450,7 @@ "dev": true, "license": "MIT", "optional": true, + "peer": true, "dependencies": { "is-node-process": "^1.2.0", "outvariant": "^1.4.0" @@ -1451,7 +1462,8 @@ "integrity": "sha512-U69T3ItWHvLwGg5eJ0n3I62nWuE6ilHlmz7zM0npLBRvPRd7e6NYmg54vvRtP5mZG7kZqZCFVdsTWo7BPtBujg==", "dev": true, "license": "MIT", - "optional": true + "optional": true, + "peer": true }, "node_modules/@pkgjs/parseargs": { "version": "0.11.0", @@ -1882,7 +1894,8 @@ "resolved": "https://registry.npmjs.org/@types/aria-query/-/aria-query-5.0.4.tgz", "integrity": "sha512-rfT93uj5s0PRL7EzccGMs3brplhcrghnDoV26NqKhCAS1hVo+WdNsPvE/yb6ilfr5hi2MEk6d5EWJTKdxg8jVw==", "dev": true, - "license": "MIT" + "license": "MIT", + "peer": true }, "node_modules/@types/babel__core": { "version": "7.20.5", @@ -2003,7 +2016,6 @@ "resolved": "https://registry.npmjs.org/@types/react/-/react-18.3.26.tgz", "integrity": "sha512-RFA/bURkcKzx/X9oumPG9Vp3D3JUgus/d0b67KB0t5S/raciymilkOa66olh78MUI92QLbEJevO7rvqU/kjwKA==", "devOptional": true, - "peer": true, "dependencies": { "@types/prop-types": "*", "csstype": "^3.0.2" @@ -2014,7 +2026,6 @@ "resolved": "https://registry.npmjs.org/@types/react-dom/-/react-dom-18.3.7.tgz", "integrity": "sha512-MEe3UeoENYVFXzoXEWsvcpg6ZvlrFNlOQ7EOsvhI3CfAXwzPfO8Qwuxd40nepsYKqyyVQnTdEfv68q91yLcKrQ==", "dev": true, - "peer": true, "peerDependencies": { "@types/react": "^18.0.0" } @@ -2025,7 +2036,8 @@ "integrity": "sha512-xMAgYwceFhRA2zY+XbEA7mxYbA093wdiW8Vu6gZPGWy9cmOyU9XesH1tNcEWsKFd5Vzrqx5T3D38PWx1FIIXkA==", "dev": true, "license": "MIT", - "optional": true + "optional": true, + "peer": true }, "node_modules/@typescript-eslint/eslint-plugin": { "version": "8.46.3", @@ -2063,7 +2075,6 @@ "integrity": "sha512-6m1I5RmHBGTnUGS113G04DMu3CpSdxCAU/UvtjNWL4Nuf3MW9tQhiJqRlHzChIkhy6kZSAQmc+I1bcGjE3yNKg==", "dev": true, "license": "MIT", - "peer": true, "dependencies": { "@typescript-eslint/scope-manager": "8.46.3", "@typescript-eslint/types": "8.46.3", @@ -2388,7 +2399,6 @@ "integrity": "sha512-NZyJarBfL7nWwIq+FDL6Zp/yHEhePMNnnJ0y3qfieCrmNvYct8uvtiV41UvlSe6apAfk0fY1FbWx+NwfmpvtTg==", "dev": true, "license": "MIT", - "peer": true, "bin": { "acorn": "bin/acorn" }, @@ -2800,7 +2810,6 @@ "url": "https://github.com/sponsors/ai" } ], - "peer": true, "dependencies": { "baseline-browser-mapping": "^2.8.19", "caniuse-lite": "^1.0.30001751", @@ -3079,6 +3088,7 @@ "dev": true, "license": "ISC", "optional": true, + "peer": true, "engines": { "node": ">= 12" } @@ -3090,6 +3100,7 @@ "dev": true, "license": "ISC", "optional": true, + "peer": true, "dependencies": { "string-width": "^4.2.0", "strip-ansi": "^6.0.1", @@ -3106,6 +3117,7 @@ "dev": true, "license": "MIT", "optional": true, + "peer": true, "engines": { "node": ">=8" } @@ -3117,6 +3129,7 @@ "dev": true, "license": "MIT", "optional": true, + "peer": true, "dependencies": { "color-convert": "^2.0.1" }, @@ -3133,7 +3146,8 @@ "integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==", "dev": true, "license": "MIT", - "optional": true + "optional": true, + "peer": true }, "node_modules/cliui/node_modules/string-width": { "version": "4.2.3", @@ -3142,6 +3156,7 @@ "dev": true, "license": "MIT", "optional": true, + "peer": true, "dependencies": { "emoji-regex": "^8.0.0", "is-fullwidth-code-point": "^3.0.0", @@ -3158,6 +3173,7 @@ "dev": true, "license": "MIT", "optional": true, + "peer": true, "dependencies": { "ansi-regex": "^5.0.1" }, @@ -3172,6 +3188,7 @@ "dev": true, "license": "MIT", "optional": true, + "peer": true, "dependencies": { "ansi-styles": "^4.0.0", "string-width": "^4.1.0", @@ -3259,6 +3276,7 @@ "dev": true, "license": "MIT", "optional": true, + "peer": true, "engines": { "node": ">=18" } @@ -3639,7 +3657,8 @@ "resolved": "https://registry.npmjs.org/dom-accessibility-api/-/dom-accessibility-api-0.5.16.tgz", "integrity": "sha512-X7BJ2yElsnOJ30pZF4uIIDfBEVgF4XEBxL9Bxhy6dnrm5hkzqmsWHGTiHqRiITNhMyFLyAiWndIJP7Z1NTteDg==", "dev": true, - "license": "MIT" + "license": "MIT", + "peer": true }, "node_modules/dom-helpers": { "version": "5.2.1", @@ -3962,7 +3981,6 @@ "integrity": "sha512-BhHmn2yNOFA9H9JmmIVKJmd288g9hrVRDkdoIgRCRuSySRUHH7r/DI6aAXW9T1WwUuY3DFgrcaqB+deURBLR5g==", "dev": true, "license": "MIT", - "peer": true, "dependencies": { "@eslint-community/eslint-utils": "^4.8.0", "@eslint-community/regexpp": "^4.12.1", @@ -4023,7 +4041,6 @@ "integrity": "sha512-82GZUjRS0p/jganf6q1rEO25VSoHH0hKPCTrgillPjdI/3bgBhAE1QzHrHTizjpRvy6pGAvKjDJtk2pF9NDq8w==", "dev": true, "license": "MIT", - "peer": true, "bin": { "eslint-config-prettier": "bin/cli.js" }, @@ -4654,6 +4671,7 @@ "dev": true, "license": "ISC", "optional": true, + "peer": true, "engines": { "node": "6.* || 8.* || >= 10.*" } @@ -4817,6 +4835,7 @@ "dev": true, "license": "MIT", "optional": true, + "peer": true, "engines": { "node": "^12.22.0 || ^14.16.0 || ^16.0.0 || >=17.0.0" } @@ -4920,7 +4939,8 @@ "integrity": "sha512-IScLbePpkvO846sIwOtOTDjutRMWdXdJmXdMvk6gCBHxFO8d+QKOQedyZSxFTTFYRSmlgSTDtXqqq4pcenBXLQ==", "dev": true, "license": "MIT", - "optional": true + "optional": true, + "peer": true }, "node_modules/hermes-estree": { "version": "0.25.1", @@ -5323,7 +5343,8 @@ "integrity": "sha512-Vg4o6/fqPxIjtxgUH5QLJhwZ7gW5diGCVlXpuUfELC62CuxM1iHcRe51f2W1FDy04Ai4KJkagKjx3XaqyfRKXw==", "dev": true, "license": "MIT", - "optional": true + "optional": true, + "peer": true }, "node_modules/is-number": { "version": "7.0.0", @@ -5554,7 +5575,6 @@ "resolved": "https://registry.npmjs.org/jiti/-/jiti-1.21.7.tgz", "integrity": "sha512-/imKNG4EbWNrVjoNC/1H5/9GFy+tqjGBHCaSsN+P2RnPqjsLmv6UD3Ej+Kj8nBWaRAwyk7kK5ZUc+OEatnTR3A==", "dev": true, - "peer": true, "bin": { "jiti": "bin/jiti.js" } @@ -5583,7 +5603,6 @@ "integrity": "sha512-8i7LzZj7BF8uplX+ZyOlIz86V6TAsSs+np6m1kpW9u0JWi4z/1t+FzcK1aek+ybTnAC4KhBL4uXCNT0wcUIeCw==", "dev": true, "license": "MIT", - "peer": true, "dependencies": { "cssstyle": "^4.1.0", "data-urls": "^5.0.0", @@ -5958,6 +5977,7 @@ "integrity": "sha512-h5bgJWpxJNswbU7qCrV0tIKQCaS3blPDrqKWx+QxzuzL1zGUzij9XCWLrSLsJPu5t+eWA/ycetzYAO5IOMcWAQ==", "dev": true, "license": "MIT", + "peer": true, "bin": { "lz-string": "bin/bin.js" } @@ -6103,6 +6123,7 @@ "hasInstallScript": true, "license": "MIT", "optional": true, + "peer": true, "dependencies": { "@inquirer/confirm": "^5.0.0", "@mswjs/interceptors": "^0.40.0", @@ -6148,6 +6169,7 @@ "dev": true, "license": "MIT", "optional": true, + "peer": true, "dependencies": { "tldts-core": "^7.0.17" }, @@ -6161,7 +6183,8 @@ "integrity": "sha512-DieYoGrP78PWKsrXr8MZwtQ7GLCUeLxihtjC1jZsW1DnvSMdKPitJSe8OSYDM2u5H6g3kWJZpePqkp43TfLh0g==", "dev": true, "license": "MIT", - "optional": true + "optional": true, + "peer": true }, "node_modules/msw/node_modules/tough-cookie": { "version": "6.0.0", @@ -6170,6 +6193,7 @@ "dev": true, "license": "BSD-3-Clause", "optional": true, + "peer": true, "dependencies": { "tldts": "^7.0.5" }, @@ -6184,6 +6208,7 @@ "dev": true, "license": "ISC", "optional": true, + "peer": true, "engines": { "node": "^18.17.0 || >=20.5.0" } @@ -6423,7 +6448,8 @@ "integrity": "sha512-+Sl2UErvtsoajRDKCE5/dBz4DIvHXQQnAxtQTF04OJxY0+DyZXSo5P5Bb7XYWOh81syohlYL24hbDwxedPUJCA==", "dev": true, "license": "MIT", - "optional": true + "optional": true, + "peer": true }, "node_modules/own-keys": { "version": "1.0.1", @@ -6560,7 +6586,8 @@ "integrity": "sha512-Yhpw4T9C6hPpgPeA28us07OJeqZ5EzQTkbfwuhsUg0c237RomFoETJgmp2sa3F/41gfLE6G5cqcYwznmeEeOlQ==", "dev": true, "license": "MIT", - "optional": true + "optional": true, + "peer": true }, "node_modules/pathe": { "version": "1.1.2", @@ -6657,7 +6684,6 @@ "url": "https://github.com/sponsors/ai" } ], - "peer": true, "dependencies": { "nanoid": "^3.3.11", "picocolors": "^1.1.1", @@ -6811,7 +6837,6 @@ "integrity": "sha512-I7AIg5boAr5R0FFtJ6rCfD+LFsWHp81dolrFD8S79U9tb8Az2nGrJncnMSnys+bpQJfRUzqs9hnA81OAA3hCuQ==", "dev": true, "license": "MIT", - "peer": true, "bin": { "prettier": "bin/prettier.cjs" }, @@ -6841,6 +6866,7 @@ "integrity": "sha512-Qb1gy5OrP5+zDf2Bvnzdl3jsTf1qXVMazbvCoKhtKqVs4/YK4ozX4gKQJJVyNe+cajNPn0KoC0MC3FUmaHWEmQ==", "dev": true, "license": "MIT", + "peer": true, "dependencies": { "ansi-regex": "^5.0.1", "ansi-styles": "^5.0.0", @@ -6856,6 +6882,7 @@ "integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==", "dev": true, "license": "MIT", + "peer": true, "engines": { "node": ">=8" } @@ -6866,6 +6893,7 @@ "integrity": "sha512-Cxwpt2SfTzTtXcfOlzGEee8O+c+MmUgGrNiBcXnuWxuFJHe6a5Hz7qwhwe5OgaSYI0IJvkLqWX1ASG+cJOkEiA==", "dev": true, "license": "MIT", + "peer": true, "engines": { "node": ">=10" }, @@ -6878,7 +6906,8 @@ "resolved": "https://registry.npmjs.org/react-is/-/react-is-17.0.2.tgz", "integrity": "sha512-w2GsyukL62IJnlaff/nRegPQR94C/XXamvMWmSHRJ4y7Ts/4ocGRmTHvOs8PSE6pB3dWOrD/nueuU5sduBsQ4w==", "dev": true, - "license": "MIT" + "license": "MIT", + "peer": true }, "node_modules/prop-types": { "version": "15.8.1", @@ -6929,7 +6958,6 @@ "version": "18.3.1", "resolved": "https://registry.npmjs.org/react/-/react-18.3.1.tgz", "integrity": "sha512-wS+hAgJShR0KhEvPJArfuPVN1+Hz1t0Y6n5jLrGQbkb4urgPE/0Rve+1kMB1v/oWgHgm4WIcV+i7F2pTVj+2iQ==", - "peer": true, "dependencies": { "loose-envify": "^1.1.0" }, @@ -6941,7 +6969,6 @@ "version": "18.3.1", "resolved": "https://registry.npmjs.org/react-dom/-/react-dom-18.3.1.tgz", "integrity": "sha512-5m4nQKp+rZRb09LNH59GM4BxTh9251/ylbKIbpe7TpGxfJ+9kv6BLkLBXIjjspbgbnIBNqlI23tRnTWT0snUIw==", - "peer": true, "dependencies": { "loose-envify": "^1.1.0", "scheduler": "^0.23.2" @@ -7109,6 +7136,7 @@ "dev": true, "license": "MIT", "optional": true, + "peer": true, "engines": { "node": ">=0.10.0" } @@ -7166,7 +7194,8 @@ "integrity": "sha512-LPRKoHnLKd/r3dVxcwO7vhCW+orkOGj9ViueosEBK6ie89CijnfRlhaDhHq/3Hxu4CkWQtxwlBG0mzTQY6uQjw==", "dev": true, "license": "MIT", - "optional": true + "optional": true, + "peer": true }, "node_modules/reusify": { "version": "1.1.0", @@ -7569,6 +7598,7 @@ "dev": true, "license": "MIT", "optional": true, + "peer": true, "engines": { "node": ">= 0.8" } @@ -7600,7 +7630,8 @@ "integrity": "sha512-vMgjE/GGEPEFnhFub6pa4FmJBRBVOLpIII2hvCZ8Kzb7K0hlHo7mQv6xYrBvCL2LtAIBwFUK8wvuJgTVSQ5MFQ==", "dev": true, "license": "MIT", - "optional": true + "optional": true, + "peer": true }, "node_modules/string-argv": { "version": "0.3.2", @@ -8039,7 +8070,6 @@ "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-4.0.3.tgz", "integrity": "sha512-5gTmgEY/sqK6gFXLIsQNH19lWb4ebPDLA4SdLP7dsWkIXHWlG66oPuVvXSGFPppYZz8ZDZq0dYYrbHfBCVUb1Q==", "dev": true, - "peer": true, "engines": { "node": ">=12" }, @@ -8180,6 +8210,7 @@ "dev": true, "license": "(MIT OR CC0-1.0)", "optional": true, + "peer": true, "engines": { "node": ">=16" }, @@ -8270,7 +8301,6 @@ "resolved": "https://registry.npmjs.org/typescript/-/typescript-5.9.3.tgz", "integrity": "sha512-jl1vZzPDinLr9eUt3J/t7V6FgNEw9QjvBPdysz9KfQDD41fQrC2Y4vKQdiaUpFT4bXlb1RHhLpp8wtm6M5TgSw==", "dev": true, - "peer": true, "bin": { "tsc": "bin/tsc", "tsserver": "bin/tsserver" @@ -8305,6 +8335,7 @@ "dev": true, "license": "MIT", "optional": true, + "peer": true, "funding": { "url": "https://github.com/sponsors/kettanaito" } @@ -8389,7 +8420,6 @@ "resolved": "https://registry.npmjs.org/vite/-/vite-6.4.1.tgz", "integrity": "sha512-+Oxm7q9hDoLMyJOYfUYBuHQo+dkAloi33apOPP56pzj+vsdJDzr+j1NISE5pyaAuKL4A3UD34qd0lx5+kfKp2g==", "dev": true, - "peer": true, "dependencies": { "esbuild": "^0.25.0", "fdir": "^6.4.4", @@ -8994,7 +9024,6 @@ "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-4.0.3.tgz", "integrity": "sha512-5gTmgEY/sqK6gFXLIsQNH19lWb4ebPDLA4SdLP7dsWkIXHWlG66oPuVvXSGFPppYZz8ZDZq0dYYrbHfBCVUb1Q==", "dev": true, - "peer": true, "engines": { "node": ">=12" }, @@ -9531,7 +9560,6 @@ "integrity": "sha512-o5a9xKjbtuhY6Bi5S3+HvbRERmouabWbyUcpXXUA1u+GNUKoROi9byOJ8M0nHbHYHkYICiMlqxkg1KkYmm25Sw==", "dev": true, "license": "MIT", - "peer": true, "dependencies": { "esbuild": "^0.21.3", "postcss": "^8.4.43", @@ -9914,6 +9942,7 @@ "dev": true, "license": "ISC", "optional": true, + "peer": true, "engines": { "node": ">=10" } @@ -9944,6 +9973,7 @@ "dev": true, "license": "MIT", "optional": true, + "peer": true, "dependencies": { "cliui": "^8.0.1", "escalade": "^3.1.1", @@ -9964,6 +9994,7 @@ "dev": true, "license": "ISC", "optional": true, + "peer": true, "engines": { "node": ">=12" } @@ -9975,6 +10006,7 @@ "dev": true, "license": "MIT", "optional": true, + "peer": true, "engines": { "node": ">=8" } @@ -9985,7 +10017,8 @@ "integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==", "dev": true, "license": "MIT", - "optional": true + "optional": true, + "peer": true }, "node_modules/yargs/node_modules/string-width": { "version": "4.2.3", @@ -9994,6 +10027,7 @@ "dev": true, "license": "MIT", "optional": true, + "peer": true, "dependencies": { "emoji-regex": "^8.0.0", "is-fullwidth-code-point": "^3.0.0", @@ -10010,6 +10044,7 @@ "dev": true, "license": "MIT", "optional": true, + "peer": true, "dependencies": { "ansi-regex": "^5.0.1" }, @@ -10037,6 +10072,7 @@ "dev": true, "license": "MIT", "optional": true, + "peer": true, "engines": { "node": ">=18" }, @@ -10050,7 +10086,6 @@ "integrity": "sha512-JInaHOamG8pt5+Ey8kGmdcAcg3OL9reK8ltczgHTAwNhMys/6ThXHityHxVV2p3fkw/c+MAvBHFVYHFZDmjMCQ==", "dev": true, "license": "MIT", - "peer": true, "funding": { "url": "https://github.com/sponsors/colinhacks" } diff --git a/web/src/App.tsx b/web/src/App.tsx index ef7fff6a..b1ba097a 100644 --- a/web/src/App.tsx +++ b/web/src/App.tsx @@ -44,7 +44,7 @@ function getModelDisplayName(modelId: string): string { function App() { const { language, setLanguage } = useLanguage() const { user, token, logout, isLoading } = useAuth() - const { config: systemConfig, loading: configLoading } = useSystemConfig() + const { loading: configLoading } = useSystemConfig() const [route, setRoute] = useState(window.location.pathname) // 从URL路径读取初始页面状态(支持刷新保持页面) @@ -230,10 +230,6 @@ function App() { return } if (route === '/register') { - if (systemConfig?.admin_mode) { - window.history.pushState({}, '', '/login') - return - } return } if (route === '/faq') { @@ -255,8 +251,7 @@ function App() { onLanguageChange={setLanguage} user={user} onLogout={logout} - isAdminMode={systemConfig?.admin_mode} - onPageChange={(page) => { + onPageChange={(page) => { console.log('Competition page onPageChange called with:', page) console.log('Current route:', route, 'Current page:', currentPage) @@ -298,16 +293,11 @@ function App() { // Show landing page for root route if (route === '/' || route === '') { - return + return } - // In admin mode, require authentication for any protected routes - if (systemConfig?.admin_mode && (!user || !token)) { - return - } - - // Show main app for authenticated users on other routes (non-admin mode) - if (!systemConfig?.admin_mode && (!user || !token)) { + // Show main app for authenticated users on other routes + if (!user || !token) { // Default to landing page when not authenticated and no specific route return } @@ -324,8 +314,7 @@ function App() { onLanguageChange={setLanguage} user={user} onLogout={logout} - isAdminMode={systemConfig?.admin_mode} - onPageChange={(page) => { + onPageChange={(page) => { console.log('Main app onPageChange called with:', page) if (page === 'competition') { diff --git a/web/src/components/LoginPage.tsx b/web/src/components/LoginPage.tsx index 4f338bc0..b98690c1 100644 --- a/web/src/components/LoginPage.tsx +++ b/web/src/components/LoginPage.tsx @@ -1,9 +1,8 @@ -import React, { useEffect, useState } from 'react' +import React, { useState } from 'react' import { useAuth } from '../contexts/AuthContext' import { useLanguage } from '../contexts/LanguageContext' import { t } from '../i18n/translations' import HeaderBar from './landing/HeaderBar' -import { getSystemConfig } from '../lib/config' export function LoginPage() { const { language } = useLanguage() @@ -16,17 +15,8 @@ export function LoginPage() { const [error, setError] = useState('') const [loading, setLoading] = useState(false) const [adminPassword, setAdminPassword] = useState('') - const [adminMode, setAdminMode] = useState(null) + const adminMode = false - useEffect(() => { - getSystemConfig() - .then((cfg) => { - setAdminMode(!!cfg.admin_mode) - }) - .catch(() => { - setAdminMode(false) - }) - }, []) const handleAdminLogin = async (e: React.FormEvent) => { e.preventDefault() diff --git a/web/src/components/landing/HeaderBar.tsx b/web/src/components/landing/HeaderBar.tsx index 18c658c8..2b8e9845 100644 --- a/web/src/components/landing/HeaderBar.tsx +++ b/web/src/components/landing/HeaderBar.tsx @@ -12,7 +12,6 @@ interface HeaderBarProps { onLanguageChange?: (lang: Language) => void user?: { email: string } | null onLogout?: () => void - isAdminMode?: boolean onPageChange?: (page: string) => void } @@ -24,7 +23,6 @@ export default function HeaderBar({ onLanguageChange, user, onLogout, - isAdminMode = false, onPageChange, }: HeaderBarProps) { const [mobileMenuOpen, setMobileMenuOpen] = useState(false) @@ -476,7 +474,7 @@ export default function HeaderBar({ > {t('signIn', language)} - {!isAdminMode && ( + {true && ( {t('signIn', language)} - {!isAdminMode && ( + {true && ( { + onPageChange={(page) => { if (page === 'competition') { window.history.pushState({}, '', '/competition') window.location.href = '/competition' diff --git a/web/src/pages/LandingPage.tsx b/web/src/pages/LandingPage.tsx index 7d7774bb..4135ee60 100644 --- a/web/src/pages/LandingPage.tsx +++ b/web/src/pages/LandingPage.tsx @@ -14,11 +14,7 @@ import { useAuth } from '../contexts/AuthContext' import { useLanguage } from '../contexts/LanguageContext' import { t } from '../i18n/translations' -export function LandingPage({ - isAdminMode = false, -}: { - isAdminMode?: boolean -}) { +export function LandingPage() { const [showLoginModal, setShowLoginModal] = useState(false) const { user, logout } = useAuth() const { language, setLanguage } = useLanguage() @@ -35,7 +31,6 @@ export function LandingPage({ onLanguageChange={setLanguage} user={user} onLogout={logout} - isAdminMode={isAdminMode} onPageChange={(page) => { console.log('LandingPage onPageChange called with:', page) if (page === 'competition') {