From 2cf253f6aa5d0447f5cb2741d0ccf05f8022ce7a Mon Sep 17 00:00:00 2001 From: oliver Date: Tue, 8 Sep 2026 08:06:54 +0800 Subject: [PATCH] Gate dsh-ops-cron APIs and UI behind UDS login. MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Reject anonymous /dsh-ops-cron requests after session validation, hide the 定时任务 chrome when logged out, and block client fetch to the cron HTTP API. Co-authored-by: Cursor --- uds-auth/lib/client.js | 22 ++++++++++++++++++++-- uds-auth/lib/dsh-acl.js | 16 ++++++++++++++++ 2 files changed, 36 insertions(+), 2 deletions(-) diff --git a/uds-auth/lib/client.js b/uds-auth/lib/client.js index d224e218..99f2e557 100644 --- a/uds-auth/lib/client.js +++ b/uds-auth/lib/client.js @@ -20,7 +20,7 @@ window.__ModuleLoader__.load({ const CSS = [ '.uds-auth-host{position:relative;display:inline-flex;align-items:center;height:32px;margin:0;flex-shrink:0;pointer-events:auto}.uds-auth-host.is-rail{justify-content:center;width:100%}[data-uds-auth-foot="row"]{display:flex!important;flex-direction:row!important;align-items:center!important;gap:8px;width:100%}[data-uds-auth-foot="row"]>*:nth-child(1){order:2;flex:none!important;width:auto!important;min-width:0;margin-left:auto!important}[data-uds-auth-foot="row"]>*:nth-child(2){order:1;flex:none!important;width:auto!important;min-width:0}', - 'html[data-uds-can-settings="0"] [data-uds-auth-foot="row"]>*:not(:has([data-uds-auth-host])){display:none!important}html[data-uds-can-create-ws="0"] button[aria-label="添加工作区"],html[data-uds-can-create-ws="0"] button[aria-label="Add workspace"]{display:none!important}', + 'html[data-uds-can-settings="0"] [data-uds-auth-foot="row"]>*:not(:has([data-uds-auth-host])){display:none!important}html[data-uds-can-create-ws="0"] button[aria-label="添加工作区"],html[data-uds-can-create-ws="0"] button[aria-label="Add workspace"]{display:none!important}html[data-uds-logged-in="0"] .dsh-ct-entry,html[data-uds-logged-in="0"] .dsh-ct-region,html[data-uds-logged-in="0"] .dsh-ct-main,html[data-uds-logged-in="0"] [data-dsh-ct-mode="on"] .dsh-ct-region{display:none!important}', '.uds-auth-badge{display:inline-flex;align-items:center;justify-content:center;gap:8px;max-width:min(180px,40vw);min-width:0;height:42px;padding:0 10px 0 8px;box-sizing:border-box;border:none;border-radius:12px;background:transparent;color:var(--dsw-alias-label-primary);font-family:inherit;font-size:14px;font-weight:400;line-height:22px;cursor:pointer;overflow:hidden}', '.uds-auth-badge:hover{background:var(--dsw-alias-interactive-bg-hover)}', '.uds-auth-host.is-rail .uds-auth-badge{width:36px;height:36px;padding:0;border-radius:50%;gap:0}', @@ -809,7 +809,25 @@ window.__ModuleLoader__.load({ let installedSessions = false const install = () => { - const connection = ctx.get('connection') + + // Block anonymous calls to dsh-ops-cron (定时任务) HTTP API. + if (!window.__udsAuthCronFetchGate) { + window.__udsAuthCronFetchGate = true + const origFetch = window.fetch.bind(window) + window.fetch = async function udsAuthFetch(input, init) { + const url = typeof input === 'string' ? input : (input && input.url) || '' + if (!getEmpNo() && String(url).includes('/dsh-ops-cron') && !String(url).includes('/dsh-ops-cron/health')) { + return new Response(JSON.stringify({ + ok: false, + error: 'login_required', + message: '登录后才能使用定时任务', + }), { status: 401, headers: { 'content-type': 'application/json' } }) + } + return origFetch(input, init) + } + } + + const connection = ctx.get('connection') const rpc = connection && connection.rpc if (!installedRpc && rpc && typeof rpc.call === 'function' && !rpc.__udsAuthListGate) { installedRpc = true diff --git a/uds-auth/lib/dsh-acl.js b/uds-auth/lib/dsh-acl.js index 5ffa449d..4f0e761e 100644 --- a/uds-auth/lib/dsh-acl.js +++ b/uds-auth/lib/dsh-acl.js @@ -71,6 +71,22 @@ export function patchWebServerWithIdentity(server, resolveIdentity) { if (typeof handler !== 'function' || handler.__udsWrapped) return handler const wrapped = async (req, res, ...rest) => { const identity = await resolveIdentity(req) + try { + const pathname = new URL(req.url || '/', 'http://x').pathname + if ( + pathname.startsWith('/dsh-ops-cron') + && pathname !== '/dsh-ops-cron/health' + && !identity?.empNo + ) { + res.writeHead(401, { 'content-type': 'application/json; charset=utf-8' }) + res.end(JSON.stringify({ + ok: false, + error: 'login_required', + message: '登录后才能使用定时任务', + })) + return + } + } catch { /* fall through to handler */ } return withUserContext(identity, () => handler(req, res, ...rest)) } wrapped.__udsWrapped = true