From 5da3325a306dd45afe5bd7178e03fa829310ca3d Mon Sep 17 00:00:00 2001 From: Jlypx Date: Sun, 19 Jul 2026 21:42:12 +0800 Subject: [PATCH] =?UTF-8?q?feat:=20=E5=9C=A8=E5=AE=89=E5=85=A8=E8=AE=BE?= =?UTF-8?q?=E7=BD=AE=E4=B8=AD=E9=85=8D=E7=BD=AE=E5=AE=A2=E6=88=B7=E7=AB=AF?= =?UTF-8?q?=20IP=20=E6=A8=A1=E5=BC=8F?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Ultraworked with [Sisyphus](https://github.com/code-yeongyu/oh-my-openagent) Co-authored-by: Sisyphus --- .../src/i18n/locales/en/admin/settings.ts | 2 +- .../src/i18n/locales/zh/admin/settings.ts | 2 +- frontend/src/views/admin/SettingsView.vue | 2 +- .../admin/__tests__/SettingsView.spec.ts | 29 +++++++++++++++++++ 4 files changed, 32 insertions(+), 3 deletions(-) diff --git a/frontend/src/i18n/locales/en/admin/settings.ts b/frontend/src/i18n/locales/en/admin/settings.ts index 531769eec1..c08ca2ae52 100644 --- a/frontend/src/i18n/locales/en/admin/settings.ts +++ b/frontend/src/i18n/locales/en/admin/settings.ts @@ -153,7 +153,7 @@ export default { 'Choose which client IP is used by API Key allowlists/denylists, admin audit logs, and session IP/UA binding', trustForwardedIp: 'Trust forwarded client IP', trustForwardedIpHint: - 'Disabled by default. Enable only when the origin is reachable only through Cloudflare or Nginx reverse proxy. When enabled, API Key IP allowlists/denylists, admin audit logs, and session IP/UA binding use CF-Connecting-IP, X-Real-IP, or X-Forwarded-For, matching the request IP shown in usage records. Toggling this switch changes the IP fingerprint of existing sessions; with session binding enabled they must sign in again.' + 'Enabled by default for upgrade compatibility. When enabled, raw CF-Connecting-IP, X-Real-IP, or X-Forwarded-For values take over server.trusted_proxies for client-IP resolution. Disable it to enforce the Gin trusted-proxy chain configured by server.trusted_proxies. Only enable takeover mode when the origin cannot be reached directly. Changing this switch changes existing session IP fingerprints.' }, linuxdo: { title: 'LinuxDo Connect Login', diff --git a/frontend/src/i18n/locales/zh/admin/settings.ts b/frontend/src/i18n/locales/zh/admin/settings.ts index f656ac4886..bfd3f139d5 100644 --- a/frontend/src/i18n/locales/zh/admin/settings.ts +++ b/frontend/src/i18n/locales/zh/admin/settings.ts @@ -152,7 +152,7 @@ export default { description: '控制 API Key 白/黑名单、操作审计日志与会话 IP/UA 绑定使用哪个客户端 IP 判断', trustForwardedIp: '信任反代传递的客户端 IP', trustForwardedIpHint: - '默认关闭。仅在源站只允许 Cloudflare 或 Nginx 反代访问时开启;开启后 API Key IP 白/黑名单、操作审计日志与会话 IP/UA 绑定会使用 CF-Connecting-IP、X-Real-IP 或 X-Forwarded-For,与使用记录中的请求 IP 保持一致。切换本开关会改变已登录会话的 IP 指纹,开启会话绑定时现有会话需重新登录。' + '为保证升级兼容默认开启。开启后 CF-Connecting-IP、X-Real-IP 或 X-Forwarded-For 会直接接管客户端 IP 解析并覆盖 server.trusted_proxies;关闭后严格使用 server.trusted_proxies 配置的 Gin 可信代理链。仅在源站无法被直接访问时开启接管模式。切换会改变现有会话的 IP 指纹。' }, linuxdo: { title: 'LinuxDo Connect 登录', diff --git a/frontend/src/views/admin/SettingsView.vue b/frontend/src/views/admin/SettingsView.vue index b2b1c760c8..c5c898ee85 100644 --- a/frontend/src/views/admin/SettingsView.vue +++ b/frontend/src/views/admin/SettingsView.vue @@ -8393,7 +8393,7 @@ const form = reactive({ turnstile_site_key: "", turnstile_secret_key: "", turnstile_secret_key_configured: false, - api_key_acl_trust_forwarded_ip: false, + api_key_acl_trust_forwarded_ip: true, // LinuxDo Connect OAuth 登录 linuxdo_connect_enabled: false, linuxdo_connect_client_id: "", diff --git a/frontend/src/views/admin/__tests__/SettingsView.spec.ts b/frontend/src/views/admin/__tests__/SettingsView.spec.ts index 8f73963362..8b7ffb301c 100644 --- a/frontend/src/views/admin/__tests__/SettingsView.spec.ts +++ b/frontend/src/views/admin/__tests__/SettingsView.spec.ts @@ -367,6 +367,7 @@ const baseSettingsResponse = { turnstile_enabled: false, turnstile_site_key: "", turnstile_secret_key_configured: false, + api_key_acl_trust_forwarded_ip: true, linuxdo_connect_enabled: false, linuxdo_connect_client_id: "", linuxdo_connect_client_secret_configured: false, @@ -652,6 +653,34 @@ describe("admin SettingsView payment visible method controls", () => { expect(wrapper.text()).not.toContain("支付来源"); }); + it("loads and saves the forwarded client IP takeover switch", async () => { + getSettings.mockResolvedValueOnce({ + ...baseSettingsResponse, + api_key_acl_trust_forwarded_ip: false, + }); + const wrapper = mountView(); + + await flushPromises(); + await openSecurityTab(wrapper); + + const card = wrapper + .findAll(".card") + .find((node) => node.text().includes("admin.settings.apiKeyAcl.title")); + expect(card).toBeDefined(); + const toggle = card!.get('input[type="checkbox"]'); + expect((toggle.element as HTMLInputElement).checked).toBe(false); + + await toggle.setValue(true); + await wrapper.find("form").trigger("submit.prevent"); + await flushPromises(); + + expect(updateSettings).toHaveBeenCalledWith( + expect.objectContaining({ + api_key_acl_trust_forwarded_ip: true, + }), + ); + }); + it("links payment guidance to README sections instead of removed payment docs", async () => { const wrapper = mountView();