From ffa6ed76021009d5de6115e2946eee87addd6cd5 Mon Sep 17 00:00:00 2001 From: QLHazyCoder <2825305047@qq.com> Date: Fri, 22 May 2026 12:20:54 +0800 Subject: [PATCH] fix kiro verification active page adoption --- flows/kiro/background/register-runner.js | 57 ++++++++++++ ...ground-kiro-register-runner-module.test.js | 88 +++++++++++++++++++ 2 files changed, 145 insertions(+) diff --git a/flows/kiro/background/register-runner.js b/flows/kiro/background/register-runner.js index 1f29096..30b2150 100644 --- a/flows/kiro/background/register-runner.js +++ b/flows/kiro/background/register-runner.js @@ -444,6 +444,52 @@ return Boolean(await chrome.tabs.get(tabId).catch(() => null)); } + function isKiroRegisterCandidateUrl(rawUrl = '') { + let parsed = null; + try { + parsed = new URL(String(rawUrl || '').trim()); + } catch (_error) { + return false; + } + if (!['http:', 'https:'].includes(parsed.protocol)) { + return false; + } + const hostname = parsed.hostname.toLowerCase(); + return hostname === 'app.kiro.dev' + || hostname === 'kiro.dev' + || hostname === 'view.awsapps.com' + || hostname === 'login.awsapps.com' + || hostname === 'profile.aws.amazon.com' + || hostname === 'profile.aws' + || hostname.endsWith('.profile.aws.amazon.com') + || hostname.endsWith('.profile.aws') + || hostname === 'signin.aws.amazon.com' + || hostname === 'signin.aws' + || hostname.endsWith('.signin.aws.amazon.com') + || hostname.endsWith('.signin.aws'); + } + + async function getActiveKiroRegisterTabId() { + if (!chrome?.tabs?.query) { + return null; + } + const queryAttempts = [ + { active: true, lastFocusedWindow: true }, + { active: true, currentWindow: true }, + { active: true }, + ]; + for (const queryInfo of queryAttempts) { + const tabs = await chrome.tabs.query(queryInfo).catch(() => []); + const matchedTab = (Array.isArray(tabs) ? tabs : []).find((tab) => ( + Number.isInteger(tab?.id) && isKiroRegisterCandidateUrl(tab?.url) + )); + if (Number.isInteger(matchedTab?.id)) { + return matchedTab.id; + } + } + return null; + } + async function getExecutionState(state = {}) { if (state && typeof state === 'object' && !Array.isArray(state) && Object.keys(state).length) { return state; @@ -521,6 +567,17 @@ return tabId; } + const activeKiroTabId = await getActiveKiroRegisterTabId(); + if (Number.isInteger(activeKiroTabId)) { + await registerTab(KIRO_REGISTER_PAGE_SOURCE_ID, activeKiroTabId); + await setState(mergeRuntimePatch(state, { + session: { + registerTabId: activeKiroTabId, + }, + })); + return activeKiroTabId; + } + if (!loginUrl) { throw new Error(options.missingUrlMessage || '缺少 Kiro 注册页地址,请先执行步骤 1。'); } diff --git a/tests/background-kiro-register-runner-module.test.js b/tests/background-kiro-register-runner-module.test.js index 40d6ace..9707e73 100644 --- a/tests/background-kiro-register-runner-module.test.js +++ b/tests/background-kiro-register-runner-module.test.js @@ -276,6 +276,94 @@ test('kiro verification polling uses the registration email field instead of pag assert.equal(getKiroRuntime(completedPayload).register?.email, 'skater-twine-carve@duck.com'); }); +test('kiro verification step can adopt the active AWS verify-otp page without step 1 runtime', async () => { + const api = loadRegisterRunnerApi(); + const currentState = { + email: 'tmp3x58ft2ivc@edu.email.qlhazycoder.tech', + registrationEmailState: { + current: 'tmp3x58ft2ivc@edu.email.qlhazycoder.tech', + previous: 'tmp3x58ft2ivc@edu.email.qlhazycoder.tech', + source: 'manual', + updatedAt: Date.now(), + }, + }; + const sentMessages = []; + const statePatches = []; + const registeredTabs = []; + const pollPayloads = []; + let completedPayload = null; + const runner = api.createKiroRegisterRunner({ + addLog: async () => {}, + chrome: { + tabs: { + query: async () => [{ + id: 301, + active: true, + url: 'https://profile.aws.amazon.com/?workflowID=b4e8f9ff-3d60-40ce-90ec-d2113d951b08#/signup/verify-otp', + }], + update: async () => {}, + }, + }, + completeNodeFromBackground: async (_nodeId, payload) => { + completedPayload = payload; + }, + getMailConfig: () => ({ + provider: 'cloudflare-temp-email', + source: 'cloudflare-temp-email', + label: 'Cloudflare Temp Email', + }), + getState: async () => currentState, + getTabId: async () => null, + isTabAlive: async () => false, + pollCloudflareTempEmailVerificationCode: async (_step, _state, payload) => { + pollPayloads.push(payload); + return { code: '248680', emailTimestamp: 2000, mailId: 'mail-active' }; + }, + registerTab: async (source, tabId) => { + registeredTabs.push({ source, tabId }); + }, + sendToContentScriptResilient: async (_sourceId, message) => { + sentMessages.push(message); + if (message.type === 'ENSURE_KIRO_PAGE_STATE') { + return { + state: 'register_otp_page', + url: 'https://profile.aws.amazon.com/?workflowID=b4e8f9ff-3d60-40ce-90ec-d2113d951b08#/signup/verify-otp', + email: 'tmp3x58ft2ivc@edu.email.qlhazycoder.tech', + }; + } + if (message.type === 'EXECUTE_NODE') { + return { submitted: true, state: 'verification_submitted' }; + } + if (message.type === 'ENSURE_KIRO_STATE_CHANGE') { + return { + state: 'create_password_page', + url: 'https://profile.aws.amazon.com/?workflowID=b4e8f9ff-3d60-40ce-90ec-d2113d951b08#/signup/create-password', + email: 'tmp3x58ft2ivc@edu.email.qlhazycoder.tech', + }; + } + return {}; + }, + setState: async (patch) => { + statePatches.push(patch); + }, + }); + + await runner.executeKiroSubmitVerificationCode({ + nodeId: 'kiro-submit-verification-code', + ...currentState, + }); + + assert.deepEqual(registeredTabs, [{ source: 'kiro-register-page', tabId: 301 }]); + assert.equal(getKiroRuntime(statePatches[0]).session?.registerTabId, 301); + assert.equal(pollPayloads[0].targetEmail, 'tmp3x58ft2ivc@edu.email.qlhazycoder.tech'); + assert.equal(sentMessages.some((message) => ( + message.type === 'EXECUTE_NODE' + && message.nodeId === 'kiro-submit-verification-code' + && message.payload?.code === '248680' + )), true); + assert.equal(getKiroRuntime(completedPayload).register?.email, 'tmp3x58ft2ivc@edu.email.qlhazycoder.tech'); +}); + test('kiro submit-email reuses the step 1 register tab even when the source registry was reset', async () => { const api = loadRegisterRunnerApi(); const currentState = {