diff --git a/src/dashboard/api.js b/src/dashboard/api.js index bb468b6..9ba6646 100644 --- a/src/dashboard/api.js +++ b/src/dashboard/api.js @@ -295,6 +295,23 @@ export async function handleDashboardApi(method, subpath, body, req, res) { } else { return json(res, 400, { error: 'Provide api_key or token' }); } + + // Handle optional proxy configuration + if (body.proxy) { + const parsed = parseProxyUrl(body.proxy); + if (!parsed) { + return json(res, 400, { error: 'ERR_PROXY_FORMAT_INVALID' }); + } + // Validate proxy host (respect ALLOW_PRIVATE_PROXY_HOSTS config) + if (config.allowPrivateProxyHosts) { + await validateHostFormat(parsed.host); + } else { + await assertPublicUrlHost(parsed.host); + } + setAccountProxy(account.id, parsed); + ensureLsForAccount(account.id).catch(e => log.warn(`LS ensure failed: ${e.message}`)); + } + // Fire-and-forget probe so the UI gets tier info shortly after add probeAccount(account.id).catch(e => log.warn(`Auto-probe failed: ${e.message}`)); return json(res, 200, { diff --git a/src/dashboard/i18n/en.json b/src/dashboard/i18n/en.json index c0bd56f..b1e00e7 100644 --- a/src/dashboard/i18n/en.json +++ b/src/dashboard/i18n/en.json @@ -356,6 +356,11 @@ "label": "Label", "placeholder": "Optional" }, + "proxy": { + "label": "Proxy", + "placeholder": "http://proxy:8080 or socks5://user:pass@host:port (optional)", + "hint": "Leave empty to use global proxy settings" + }, "batchInput": { "label": "Batch Import", "hint": "One account per line. Format: [proxy] email password. Proxy is optional, supports http/socks5. Proxy will be automatically bound to corresponding account." @@ -872,6 +877,7 @@ "ERR_FORMAT_INVALID": "Invalid format. Expected: [proxy] email password", "ERR_IDTOKEN_REQUIRED": "ID token is required", "ERR_PROXY_PRIVATE_IP": "Proxy cannot point to private/local address", + "ERR_PROXY_FORMAT_INVALID": "Invalid proxy format. Expected: protocol://[user:pass@]host:port", "ERR_PROXY_HTTP_ERROR": "Proxy returned HTTP error", "ERR_PROXY_PRIVATE_HOST": "Private/local host is not allowed", "ERR_CONNECTION_FAILED": "Connection failed", diff --git a/src/dashboard/i18n/zh-CN.json b/src/dashboard/i18n/zh-CN.json index b716e71..d4828e0 100644 --- a/src/dashboard/i18n/zh-CN.json +++ b/src/dashboard/i18n/zh-CN.json @@ -339,6 +339,11 @@ "label": "标签", "placeholder": "可选" }, + "proxy": { + "label": "代理", + "placeholder": "http://proxy:8080 或 socks5://user:pass@host:port(可选)", + "hint": "留空则使用全局代理设置" + }, "batchInput": { "label": "批量导入", "hint": "每行一个账号。格式:[代理] 邮箱 密码。代理可选,支持 http/socks5。会自动绑定代理到对应账号。" @@ -872,6 +877,7 @@ "ERR_FORMAT_INVALID": "格式错误 需要 [proxy] email password", "ERR_IDTOKEN_REQUIRED": "缺少 idToken", "ERR_PROXY_PRIVATE_IP": "代理地址不能指向内网/本机", + "ERR_PROXY_FORMAT_INVALID": "代理格式错误,应为:protocol://[user:pass@]host:port", "ERR_PROXY_HTTP_ERROR": "代理返回 HTTP 错误", "ERR_PROXY_PRIVATE_HOST": "内网/本地主机不允许", "ERR_CONNECTION_FAILED": "连接失败", diff --git a/src/dashboard/index.html b/src/dashboard/index.html index 3e74925..5f921fb 100644 --- a/src/dashboard/index.html +++ b/src/dashboard/index.html @@ -1764,6 +1764,13 @@