合并 Grok SSO 多 flow 重构
吸收 Grok 注册与 webchat2api SSO Cookie 导出流程,并把 Kiro/Grok 验证码轮询统一到共享 flow 邮件轮询服务。保留 master 上 Kiro 页面恢复、active verify-otp 接管和重注入修复,补齐对应测试适配。
This commit is contained in:
@@ -14,43 +14,6 @@
|
||||
'https://app.kiro.dev/*',
|
||||
'https://kiro.dev/*',
|
||||
]);
|
||||
const KIRO_AWS_VERIFICATION_CODE_PATTERNS = Object.freeze([
|
||||
Object.freeze({
|
||||
source: '(?:verification\\s*code|验证码|Your code is|code is)[::\\s]*(\\d{6})',
|
||||
flags: 'gi',
|
||||
}),
|
||||
Object.freeze({
|
||||
source: '^\\s*(\\d{6})\\s*$',
|
||||
flags: 'gm',
|
||||
}),
|
||||
Object.freeze({
|
||||
source: '>\\s*(\\d{6})\\s*<',
|
||||
flags: 'g',
|
||||
}),
|
||||
]);
|
||||
const KIRO_AWS_SENDER_FILTERS = Object.freeze([
|
||||
'no-reply@signin.aws',
|
||||
'no-reply@login.awsapps.com',
|
||||
'noreply@amazon.com',
|
||||
'account-update@amazon.com',
|
||||
'no-reply@aws.amazon.com',
|
||||
'noreply@aws.amazon.com',
|
||||
'aws',
|
||||
]);
|
||||
const KIRO_AWS_SUBJECT_FILTERS = Object.freeze([
|
||||
'aws builder id',
|
||||
'verification',
|
||||
'验证码',
|
||||
'code',
|
||||
'aws',
|
||||
]);
|
||||
const KIRO_AWS_REQUIRED_KEYWORDS = Object.freeze([
|
||||
'verification',
|
||||
'验证码',
|
||||
'code',
|
||||
'aws',
|
||||
]);
|
||||
|
||||
function isPlainObject(value) {
|
||||
return Boolean(value) && typeof value === 'object' && !Array.isArray(value);
|
||||
}
|
||||
@@ -375,32 +338,17 @@
|
||||
chrome = (typeof globalThis !== 'undefined' ? globalThis.chrome : null),
|
||||
completeNodeFromBackground,
|
||||
ensureContentScriptReadyOnTab = null,
|
||||
ensureIcloudMailSession = null,
|
||||
ensureMail2925MailboxSession = null,
|
||||
fetchImpl = typeof fetch === 'function' ? fetch.bind(globalThis) : null,
|
||||
getMailConfig = null,
|
||||
getState = async () => ({}),
|
||||
getTabId = async () => null,
|
||||
HOTMAIL_PROVIDER = 'hotmail-api',
|
||||
LUCKMAIL_PROVIDER = 'luckmail-api',
|
||||
CLOUDFLARE_TEMP_EMAIL_PROVIDER = 'cloudflare-temp-email',
|
||||
CLOUD_MAIL_PROVIDER = 'cloudmail',
|
||||
YYDS_MAIL_PROVIDER = 'yyds-mail',
|
||||
MAIL_2925_VERIFICATION_INTERVAL_MS = 15000,
|
||||
MAIL_2925_VERIFICATION_MAX_ATTEMPTS = 15,
|
||||
isTabAlive = async () => false,
|
||||
maybeSubmitFlowContribution = async () => null,
|
||||
KIRO_REGISTER_INJECT_FILES = null,
|
||||
KIRO_DESKTOP_AUTHORIZE_INJECT_FILES = null,
|
||||
pollCloudflareTempEmailVerificationCode = null,
|
||||
pollCloudMailVerificationCode = null,
|
||||
pollHotmailVerificationCode = null,
|
||||
pollLuckmailVerificationCode = null,
|
||||
pollYydsMailVerificationCode = null,
|
||||
pollFlowVerificationCode = null,
|
||||
registerTab = async () => {},
|
||||
reuseOrCreateTab = async () => null,
|
||||
sendToContentScriptResilient = null,
|
||||
sendToMailContentScriptResilient = null,
|
||||
setState = async () => {},
|
||||
sleepWithStop = async (ms) => {
|
||||
await new Promise((resolve) => setTimeout(resolve, ms));
|
||||
@@ -658,44 +606,6 @@
|
||||
return password;
|
||||
}
|
||||
|
||||
function getExpectedMail2925MailboxEmail(state = {}) {
|
||||
if (Boolean(state?.mail2925UseAccountPool)) {
|
||||
const currentAccountId = String(state?.currentMail2925AccountId || '').trim();
|
||||
const accounts = Array.isArray(state?.mail2925Accounts) ? state.mail2925Accounts : [];
|
||||
const currentAccount = accounts.find((account) => String(account?.id || '') === currentAccountId) || null;
|
||||
const accountEmail = String(currentAccount?.email || '').trim().toLowerCase();
|
||||
if (accountEmail) {
|
||||
return accountEmail;
|
||||
}
|
||||
}
|
||||
return String(state?.mail2925BaseEmail || '').trim().toLowerCase();
|
||||
}
|
||||
|
||||
async function focusOrOpenMailTab(mail) {
|
||||
if (!mail?.source) {
|
||||
return;
|
||||
}
|
||||
const alive = await isTabAlive(mail.source);
|
||||
if (alive) {
|
||||
if (mail.navigateOnReuse) {
|
||||
await reuseOrCreateTab(mail.source, mail.url, {
|
||||
inject: mail.inject,
|
||||
injectSource: mail.injectSource,
|
||||
});
|
||||
return;
|
||||
}
|
||||
const tabId = await getTabId(mail.source);
|
||||
if (Number.isInteger(tabId)) {
|
||||
await activateTab(tabId);
|
||||
}
|
||||
return;
|
||||
}
|
||||
await reuseOrCreateTab(mail.source, mail.url, {
|
||||
inject: mail.inject,
|
||||
injectSource: mail.injectSource,
|
||||
});
|
||||
}
|
||||
|
||||
async function collectKiroWebSessionTabs(currentState = {}) {
|
||||
const runtimeState = readKiroRuntime(currentState);
|
||||
const candidates = [];
|
||||
@@ -901,131 +811,35 @@
|
||||
throw new Error(`Kiro Web 登录态尚未建立。请在自动打开的 Kiro 账号页登录后,从步骤 7 继续。${detail}`);
|
||||
}
|
||||
|
||||
function buildDesktopOtpPollPayload(step, state = {}, mail = {}, filterAfterTimestamp = 0) {
|
||||
const runtimeState = readKiroRuntime(state);
|
||||
const targetEmail = cleanString(runtimeState.register?.email || state?.email).toLowerCase();
|
||||
const targetEmailHints = targetEmail ? [targetEmail] : [];
|
||||
const isMail2925Provider = String(mail?.provider || '').trim().toLowerCase() === '2925';
|
||||
const normalizedProvider = String(mail?.provider || '').trim().toLowerCase();
|
||||
const maxAttempts = normalizedProvider === String(LUCKMAIL_PROVIDER || '').trim().toLowerCase()
|
||||
? 3
|
||||
: (isMail2925Provider ? MAIL_2925_VERIFICATION_MAX_ATTEMPTS : 5);
|
||||
const intervalMs = normalizedProvider === String(LUCKMAIL_PROVIDER || '').trim().toLowerCase()
|
||||
? 15000
|
||||
: (isMail2925Provider ? MAIL_2925_VERIFICATION_INTERVAL_MS : 3000);
|
||||
|
||||
return {
|
||||
flowId: 'kiro',
|
||||
step,
|
||||
targetEmail,
|
||||
targetEmailHints,
|
||||
filterAfterTimestamp,
|
||||
senderFilters: [...KIRO_AWS_SENDER_FILTERS],
|
||||
subjectFilters: [...KIRO_AWS_SUBJECT_FILTERS],
|
||||
requiredKeywords: [...KIRO_AWS_REQUIRED_KEYWORDS],
|
||||
codePatterns: [...KIRO_AWS_VERIFICATION_CODE_PATTERNS],
|
||||
mail2925MatchTargetEmail: isMail2925Provider
|
||||
&& String(state?.mail2925Mode || '').trim().toLowerCase() === 'receive',
|
||||
maxAttempts,
|
||||
intervalMs,
|
||||
};
|
||||
}
|
||||
|
||||
function getMailPollingResponseTimeoutMs(payload = {}) {
|
||||
const maxAttempts = Math.max(1, Math.floor(Number(payload?.maxAttempts) || 1));
|
||||
const intervalMs = Math.max(1, Number(payload?.intervalMs) || 3000);
|
||||
return Math.max(45000, maxAttempts * intervalMs + 25000);
|
||||
}
|
||||
|
||||
async function pollDesktopOtpCode(step, state = {}, nodeId = '') {
|
||||
if (typeof getMailConfig !== 'function') {
|
||||
throw new Error('Kiro 桌面授权验证码步骤缺少邮箱配置能力,无法继续执行。');
|
||||
}
|
||||
const mail = getMailConfig(state);
|
||||
if (mail?.error) {
|
||||
throw new Error(mail.error);
|
||||
if (typeof pollFlowVerificationCode !== 'function') {
|
||||
throw new Error('Kiro 桌面授权验证码步骤缺少共享邮件轮询能力,无法继续执行。');
|
||||
}
|
||||
|
||||
const runtimeState = readKiroRuntime(state);
|
||||
const requestedAt = Math.max(0, Number(runtimeState.desktopAuth?.otpRequestedAt) || Date.now());
|
||||
const filterAfterTimestamp = mail.provider === '2925'
|
||||
const mailProvider = cleanString(state?.mailProvider).toLowerCase();
|
||||
const filterAfterTimestamp = mailProvider === '2925'
|
||||
? Math.max(0, requestedAt - MAIL_2925_FILTER_LOOKBACK_MS)
|
||||
: requestedAt;
|
||||
const pollPayload = buildDesktopOtpPollPayload(step, state, mail, filterAfterTimestamp);
|
||||
|
||||
if (mail.source === 'icloud-mail' && typeof ensureIcloudMailSession === 'function') {
|
||||
await log(`步骤 ${step}:正在确认 ${mail.label || 'iCloud 邮箱'} 登录状态...`, 'info', nodeId);
|
||||
await ensureIcloudMailSession({
|
||||
state,
|
||||
step,
|
||||
actionLabel: `步骤 ${step}:确认 iCloud 邮箱登录状态`,
|
||||
});
|
||||
}
|
||||
|
||||
if (mail.provider === HOTMAIL_PROVIDER) {
|
||||
await log(`步骤 ${step}:正在通过 ${mail.label || 'Hotmail'} 轮询桌面授权验证码...`, 'info', nodeId);
|
||||
return pollHotmailVerificationCode(step, state, pollPayload);
|
||||
}
|
||||
if (mail.provider === LUCKMAIL_PROVIDER) {
|
||||
await log(`步骤 ${step}:正在通过 ${mail.label || 'LuckMail'} 轮询桌面授权验证码...`, 'info', nodeId);
|
||||
return pollLuckmailVerificationCode(step, state, pollPayload);
|
||||
}
|
||||
if (mail.provider === CLOUDFLARE_TEMP_EMAIL_PROVIDER) {
|
||||
await log(`步骤 ${step}:正在通过 ${mail.label || 'Cloudflare Temp Email'} 轮询桌面授权验证码...`, 'info', nodeId);
|
||||
return pollCloudflareTempEmailVerificationCode(step, state, pollPayload);
|
||||
}
|
||||
if (mail.provider === CLOUD_MAIL_PROVIDER) {
|
||||
await log(`步骤 ${step}:正在通过 ${mail.label || 'Cloud Mail'} 轮询桌面授权验证码...`, 'info', nodeId);
|
||||
return pollCloudMailVerificationCode(step, state, pollPayload);
|
||||
}
|
||||
if (mail.provider === YYDS_MAIL_PROVIDER) {
|
||||
await log(`步骤 ${step}:正在通过 ${mail.label || 'YYDS Mail'} 轮询桌面授权验证码...`, 'info', nodeId);
|
||||
return pollYydsMailVerificationCode(step, state, pollPayload);
|
||||
}
|
||||
|
||||
if (mail.provider === '2925' && typeof ensureMail2925MailboxSession === 'function') {
|
||||
await log(`步骤 ${step}:正在确认 ${mail.label || '2925 邮箱'} 登录状态...`, 'info', nodeId);
|
||||
await ensureMail2925MailboxSession({
|
||||
accountId: state.currentMail2925AccountId || null,
|
||||
forceRelogin: false,
|
||||
allowLoginWhenOnLoginPage: Boolean(state?.mail2925UseAccountPool),
|
||||
expectedMailboxEmail: getExpectedMail2925MailboxEmail(state),
|
||||
actionLabel: `步骤 ${step}:确认 2925 邮箱登录状态`,
|
||||
});
|
||||
} else {
|
||||
await log(`步骤 ${step}:正在打开 ${mail.label || '邮箱'}...`, 'info', nodeId);
|
||||
await focusOrOpenMailTab(mail);
|
||||
}
|
||||
|
||||
if (typeof sendToMailContentScriptResilient !== 'function') {
|
||||
throw new Error('Kiro 桌面授权验证码步骤缺少邮箱内容脚本通信能力,无法继续执行。');
|
||||
}
|
||||
|
||||
const responseTimeoutMs = getMailPollingResponseTimeoutMs(pollPayload);
|
||||
const result = await sendToMailContentScriptResilient(
|
||||
mail,
|
||||
{
|
||||
type: 'POLL_EMAIL',
|
||||
step,
|
||||
source: 'background',
|
||||
payload: pollPayload,
|
||||
return pollFlowVerificationCode({
|
||||
actionLabel: '桌面授权验证码',
|
||||
filterAfterTimestamp,
|
||||
flowId: 'kiro',
|
||||
logStep: step,
|
||||
logStepKey: 'kiro-complete-desktop-authorize',
|
||||
missingCapabilityMessage: 'Kiro 桌面授权验证码步骤缺少共享邮件轮询能力,无法继续执行。',
|
||||
nodeId: 'kiro-complete-desktop-authorize',
|
||||
notFoundMessage: `步骤 ${step}:邮箱轮询结束,但未获取到桌面授权验证码。`,
|
||||
state: {
|
||||
...state,
|
||||
activeFlowId: 'kiro',
|
||||
flowId: 'kiro',
|
||||
visibleStep: step,
|
||||
},
|
||||
{
|
||||
timeoutMs: responseTimeoutMs,
|
||||
responseTimeoutMs,
|
||||
maxRecoveryAttempts: 2,
|
||||
logStep: step,
|
||||
logStepKey: 'kiro-complete-desktop-authorize',
|
||||
}
|
||||
);
|
||||
|
||||
if (result?.error) {
|
||||
throw new Error(result.error);
|
||||
}
|
||||
if (!result?.code) {
|
||||
throw new Error(`步骤 ${step}:邮箱轮询结束,但未获取到桌面授权验证码。`);
|
||||
}
|
||||
return result;
|
||||
step,
|
||||
});
|
||||
}
|
||||
|
||||
async function executeKiroStartDesktopAuthorize(state = {}) {
|
||||
|
||||
@@ -32,42 +32,6 @@
|
||||
'https://profile.aws.amazon.com',
|
||||
]);
|
||||
const MAIL_2925_FILTER_LOOKBACK_MS = 10 * 60 * 1000;
|
||||
const KIRO_AWS_VERIFICATION_CODE_PATTERNS = Object.freeze([
|
||||
Object.freeze({
|
||||
source: '(?:verification\\s*code|验证码|Your code is|code is)[::\\s]*(\\d{6})',
|
||||
flags: 'gi',
|
||||
}),
|
||||
Object.freeze({
|
||||
source: '^\\s*(\\d{6})\\s*$',
|
||||
flags: 'gm',
|
||||
}),
|
||||
Object.freeze({
|
||||
source: '>\\s*(\\d{6})\\s*<',
|
||||
flags: 'g',
|
||||
}),
|
||||
]);
|
||||
const KIRO_AWS_SENDER_FILTERS = Object.freeze([
|
||||
'no-reply@signin.aws',
|
||||
'no-reply@login.awsapps.com',
|
||||
'noreply@amazon.com',
|
||||
'account-update@amazon.com',
|
||||
'no-reply@aws.amazon.com',
|
||||
'noreply@aws.amazon.com',
|
||||
'aws',
|
||||
]);
|
||||
const KIRO_AWS_SUBJECT_FILTERS = Object.freeze([
|
||||
'aws builder id',
|
||||
'verification',
|
||||
'验证码',
|
||||
'code',
|
||||
'aws',
|
||||
]);
|
||||
const KIRO_AWS_REQUIRED_KEYWORDS = Object.freeze([
|
||||
'verification',
|
||||
'验证码',
|
||||
'code',
|
||||
'aws',
|
||||
]);
|
||||
const KIRO_REGISTER_PAGE_STATES = Object.freeze([
|
||||
'kiro_signin_page',
|
||||
'email_entry',
|
||||
@@ -387,32 +351,17 @@
|
||||
chrome = (typeof globalThis !== 'undefined' ? globalThis.chrome : null),
|
||||
completeNodeFromBackground,
|
||||
ensureContentScriptReadyOnTab = null,
|
||||
ensureIcloudMailSession = null,
|
||||
ensureMail2925MailboxSession = null,
|
||||
generatePassword = null,
|
||||
generateRandomName = null,
|
||||
getMailConfig = null,
|
||||
getState = async () => ({}),
|
||||
getTabId = async () => null,
|
||||
HOTMAIL_PROVIDER = 'hotmail-api',
|
||||
LUCKMAIL_PROVIDER = 'luckmail-api',
|
||||
CLOUDFLARE_TEMP_EMAIL_PROVIDER = 'cloudflare-temp-email',
|
||||
CLOUD_MAIL_PROVIDER = 'cloudmail',
|
||||
YYDS_MAIL_PROVIDER = 'yyds-mail',
|
||||
MAIL_2925_VERIFICATION_INTERVAL_MS = 15000,
|
||||
MAIL_2925_VERIFICATION_MAX_ATTEMPTS = 15,
|
||||
isTabAlive = async () => false,
|
||||
KIRO_REGISTER_INJECT_FILES = null,
|
||||
pollCloudflareTempEmailVerificationCode = null,
|
||||
pollCloudMailVerificationCode = null,
|
||||
pollHotmailVerificationCode = null,
|
||||
pollLuckmailVerificationCode = null,
|
||||
pollYydsMailVerificationCode = null,
|
||||
pollFlowVerificationCode = null,
|
||||
registerTab = async () => {},
|
||||
resolveSignupEmailForFlow = null,
|
||||
reuseOrCreateTab = async () => null,
|
||||
sendToContentScriptResilient = null,
|
||||
sendToMailContentScriptResilient = null,
|
||||
setPasswordState = async () => {},
|
||||
setState = async () => {},
|
||||
sleepWithStop = async (ms) => {
|
||||
@@ -954,173 +903,36 @@
|
||||
};
|
||||
}
|
||||
|
||||
function getExpectedMail2925MailboxEmail(state = {}) {
|
||||
if (Boolean(state?.mail2925UseAccountPool)) {
|
||||
const currentAccountId = String(state?.currentMail2925AccountId || '').trim();
|
||||
const accounts = Array.isArray(state?.mail2925Accounts) ? state.mail2925Accounts : [];
|
||||
const currentAccount = accounts.find((account) => String(account?.id || '') === currentAccountId) || null;
|
||||
const accountEmail = String(currentAccount?.email || '').trim().toLowerCase();
|
||||
if (accountEmail) {
|
||||
return accountEmail;
|
||||
}
|
||||
}
|
||||
|
||||
return String(state?.mail2925BaseEmail || '').trim().toLowerCase();
|
||||
}
|
||||
|
||||
async function focusOrOpenMailTab(mail) {
|
||||
if (!mail?.source) {
|
||||
return;
|
||||
}
|
||||
const alive = await isTabAlive(mail.source);
|
||||
if (alive) {
|
||||
if (mail.navigateOnReuse) {
|
||||
await reuseOrCreateTab(mail.source, mail.url, {
|
||||
inject: mail.inject,
|
||||
injectSource: mail.injectSource,
|
||||
});
|
||||
return;
|
||||
}
|
||||
|
||||
const tabId = await getTabId(mail.source);
|
||||
if (Number.isInteger(tabId)) {
|
||||
await activateTab(tabId);
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
await reuseOrCreateTab(mail.source, mail.url, {
|
||||
inject: mail.inject,
|
||||
injectSource: mail.injectSource,
|
||||
});
|
||||
}
|
||||
|
||||
function buildKiroVerificationPollPayload(step, state = {}, mail = {}, filterAfterTimestamp = 0) {
|
||||
const targetEmail = resolveKiroRegisterEmail(state);
|
||||
const targetEmailHints = targetEmail ? [targetEmail] : [];
|
||||
const isMail2925Provider = String(mail?.provider || '').trim().toLowerCase() === '2925';
|
||||
const normalizedProvider = String(mail?.provider || '').trim().toLowerCase();
|
||||
const maxAttempts = normalizedProvider === String(LUCKMAIL_PROVIDER || '').trim().toLowerCase()
|
||||
? 3
|
||||
: (isMail2925Provider ? MAIL_2925_VERIFICATION_MAX_ATTEMPTS : 5);
|
||||
const intervalMs = normalizedProvider === String(LUCKMAIL_PROVIDER || '').trim().toLowerCase()
|
||||
? 15000
|
||||
: (isMail2925Provider ? MAIL_2925_VERIFICATION_INTERVAL_MS : 3000);
|
||||
|
||||
return {
|
||||
flowId: 'kiro',
|
||||
step,
|
||||
targetEmail,
|
||||
targetEmailHints,
|
||||
filterAfterTimestamp,
|
||||
senderFilters: [...KIRO_AWS_SENDER_FILTERS],
|
||||
subjectFilters: [...KIRO_AWS_SUBJECT_FILTERS],
|
||||
requiredKeywords: [...KIRO_AWS_REQUIRED_KEYWORDS],
|
||||
codePatterns: [...KIRO_AWS_VERIFICATION_CODE_PATTERNS],
|
||||
mail2925MatchTargetEmail: isMail2925Provider
|
||||
&& String(state?.mail2925Mode || '').trim().toLowerCase() === 'receive',
|
||||
maxAttempts,
|
||||
intervalMs,
|
||||
};
|
||||
}
|
||||
|
||||
function getMailPollingResponseTimeoutMs(payload = {}) {
|
||||
const maxAttempts = Math.max(1, Math.floor(Number(payload?.maxAttempts) || 1));
|
||||
const intervalMs = Math.max(1, Number(payload?.intervalMs) || 3000);
|
||||
return Math.max(45000, maxAttempts * intervalMs + 25000);
|
||||
}
|
||||
|
||||
async function pollKiroVerificationCode(step, state = {}, nodeId = '') {
|
||||
if (typeof getMailConfig !== 'function') {
|
||||
throw new Error('Kiro 验证码步骤缺少邮箱配置能力,无法继续执行。');
|
||||
}
|
||||
const mail = getMailConfig(state);
|
||||
if (mail?.error) {
|
||||
throw new Error(mail.error);
|
||||
if (typeof pollFlowVerificationCode !== 'function') {
|
||||
throw new Error('Kiro 验证码步骤缺少共享邮件轮询能力,无法继续执行。');
|
||||
}
|
||||
|
||||
const runtimeState = readKiroRuntime(state);
|
||||
const recordedRequestedAt = Math.max(0, Number(runtimeState.register?.verificationRequestedAt) || 0);
|
||||
const requestedAt = recordedRequestedAt || Math.max(0, Date.now() - MAIL_2925_FILTER_LOOKBACK_MS);
|
||||
const filterAfterTimestamp = mail.provider === '2925'
|
||||
const mailProvider = cleanString(state?.mailProvider).toLowerCase();
|
||||
const filterAfterTimestamp = mailProvider === '2925'
|
||||
? Math.max(0, requestedAt - MAIL_2925_FILTER_LOOKBACK_MS)
|
||||
: requestedAt;
|
||||
const pollPayload = buildKiroVerificationPollPayload(step, state, mail, filterAfterTimestamp);
|
||||
|
||||
if (mail.source === 'icloud-mail' && typeof ensureIcloudMailSession === 'function') {
|
||||
await log(`步骤 ${step}:正在确认 ${mail.label || 'iCloud 邮箱'} 登录状态...`, 'info', nodeId);
|
||||
await ensureIcloudMailSession({
|
||||
state,
|
||||
step,
|
||||
actionLabel: `步骤 ${step}:确认 iCloud 邮箱登录状态`,
|
||||
});
|
||||
}
|
||||
|
||||
throwIfStopped();
|
||||
if (mail.provider === HOTMAIL_PROVIDER) {
|
||||
await log(`步骤 ${step}:正在通过 ${mail.label || 'Hotmail'} 轮询验证码...`, 'info', nodeId);
|
||||
return pollHotmailVerificationCode(step, state, pollPayload);
|
||||
}
|
||||
if (mail.provider === LUCKMAIL_PROVIDER) {
|
||||
await log(`步骤 ${step}:正在通过 ${mail.label || 'LuckMail'} 轮询验证码...`, 'info', nodeId);
|
||||
return pollLuckmailVerificationCode(step, state, pollPayload);
|
||||
}
|
||||
if (mail.provider === CLOUDFLARE_TEMP_EMAIL_PROVIDER) {
|
||||
await log(`步骤 ${step}:正在通过 ${mail.label || 'Cloudflare Temp Email'} 轮询验证码...`, 'info', nodeId);
|
||||
return pollCloudflareTempEmailVerificationCode(step, state, pollPayload);
|
||||
}
|
||||
if (mail.provider === CLOUD_MAIL_PROVIDER) {
|
||||
await log(`步骤 ${step}:正在通过 ${mail.label || 'Cloud Mail'} 轮询验证码...`, 'info', nodeId);
|
||||
return pollCloudMailVerificationCode(step, state, pollPayload);
|
||||
}
|
||||
if (mail.provider === YYDS_MAIL_PROVIDER) {
|
||||
await log(`步骤 ${step}:正在通过 ${mail.label || 'YYDS Mail'} 轮询验证码...`, 'info', nodeId);
|
||||
return pollYydsMailVerificationCode(step, state, pollPayload);
|
||||
}
|
||||
|
||||
if (mail.provider === '2925' && typeof ensureMail2925MailboxSession === 'function') {
|
||||
await log(`步骤 ${step}:正在确认 ${mail.label || '2925 邮箱'} 登录状态...`, 'info', nodeId);
|
||||
await ensureMail2925MailboxSession({
|
||||
accountId: state.currentMail2925AccountId || null,
|
||||
forceRelogin: false,
|
||||
allowLoginWhenOnLoginPage: Boolean(state?.mail2925UseAccountPool),
|
||||
expectedMailboxEmail: getExpectedMail2925MailboxEmail(state),
|
||||
actionLabel: `步骤 ${step}:确认 2925 邮箱登录状态`,
|
||||
});
|
||||
} else {
|
||||
await log(`步骤 ${step}:正在打开 ${mail.label || '邮箱'}...`, 'info', nodeId);
|
||||
await focusOrOpenMailTab(mail);
|
||||
}
|
||||
|
||||
if (typeof sendToMailContentScriptResilient !== 'function') {
|
||||
throw new Error('Kiro 验证码步骤缺少邮箱内容脚本通信能力,无法继续执行。');
|
||||
}
|
||||
|
||||
const responseTimeoutMs = getMailPollingResponseTimeoutMs(pollPayload);
|
||||
const result = await sendToMailContentScriptResilient(
|
||||
mail,
|
||||
{
|
||||
type: 'POLL_EMAIL',
|
||||
step,
|
||||
source: 'background',
|
||||
payload: pollPayload,
|
||||
return pollFlowVerificationCode({
|
||||
actionLabel: 'Kiro 验证码',
|
||||
filterAfterTimestamp,
|
||||
flowId: 'kiro',
|
||||
logStep: step,
|
||||
logStepKey: 'kiro-submit-verification-code',
|
||||
missingCapabilityMessage: 'Kiro 验证码步骤缺少共享邮件轮询能力,无法继续执行。',
|
||||
nodeId: 'kiro-submit-verification-code',
|
||||
notFoundMessage: `步骤 ${step}:邮箱轮询结束,但未获取到 Kiro 验证码。`,
|
||||
state: {
|
||||
...state,
|
||||
activeFlowId: 'kiro',
|
||||
flowId: 'kiro',
|
||||
visibleStep: step,
|
||||
},
|
||||
{
|
||||
timeoutMs: responseTimeoutMs,
|
||||
responseTimeoutMs,
|
||||
maxRecoveryAttempts: 2,
|
||||
logStep: step,
|
||||
logStepKey: 'kiro-submit-verification-code',
|
||||
}
|
||||
);
|
||||
|
||||
if (result?.error) {
|
||||
throw new Error(result.error);
|
||||
}
|
||||
if (!result?.code) {
|
||||
throw new Error(`步骤 ${step}:邮箱轮询结束,但未获取到验证码。`);
|
||||
}
|
||||
return result;
|
||||
step,
|
||||
});
|
||||
}
|
||||
|
||||
async function executeKiroOpenRegisterPage(state = {}) {
|
||||
|
||||
@@ -0,0 +1,162 @@
|
||||
(function attachKiroMailRules(root, factory) {
|
||||
root.MultiPageKiroMailRules = factory(root);
|
||||
})(typeof self !== 'undefined' ? self : globalThis, function createKiroMailRulesModule(root) {
|
||||
const kiroStateApi = root.MultiPageBackgroundKiroState || null;
|
||||
const SUBMIT_VERIFICATION_CODE_RULE_ID = 'kiro-submit-verification-code';
|
||||
const DESKTOP_AUTHORIZE_CODE_RULE_ID = 'kiro-complete-desktop-authorize';
|
||||
const SUBMIT_VERIFICATION_CODE_NODE_ID = 'kiro-submit-verification-code';
|
||||
const DESKTOP_AUTHORIZE_NODE_ID = 'kiro-complete-desktop-authorize';
|
||||
const KIRO_AWS_VERIFICATION_CODE_PATTERNS = Object.freeze([
|
||||
Object.freeze({
|
||||
source: '(?:verification\\s*code|验证码|Your code is|code is)[::\\s]*(\\d{6})',
|
||||
flags: 'gi',
|
||||
}),
|
||||
Object.freeze({
|
||||
source: '^\\s*(\\d{6})\\s*$',
|
||||
flags: 'gm',
|
||||
}),
|
||||
Object.freeze({
|
||||
source: '>\\s*(\\d{6})\\s*<',
|
||||
flags: 'g',
|
||||
}),
|
||||
]);
|
||||
const KIRO_AWS_SENDER_FILTERS = Object.freeze([
|
||||
'no-reply@signin.aws',
|
||||
'no-reply@login.awsapps.com',
|
||||
'noreply@amazon.com',
|
||||
'account-update@amazon.com',
|
||||
'no-reply@aws.amazon.com',
|
||||
'noreply@aws.amazon.com',
|
||||
'aws',
|
||||
]);
|
||||
const KIRO_AWS_SUBJECT_FILTERS = Object.freeze([
|
||||
'aws builder id',
|
||||
'verification',
|
||||
'验证码',
|
||||
'code',
|
||||
'aws',
|
||||
]);
|
||||
const KIRO_AWS_REQUIRED_KEYWORDS = Object.freeze([
|
||||
'verification',
|
||||
'验证码',
|
||||
'code',
|
||||
'aws',
|
||||
]);
|
||||
|
||||
function cleanString(value = '') {
|
||||
return String(value ?? '').trim();
|
||||
}
|
||||
|
||||
function readKiroRuntime(state = {}) {
|
||||
if (typeof kiroStateApi?.ensureRuntimeState === 'function') {
|
||||
return kiroStateApi.ensureRuntimeState(state);
|
||||
}
|
||||
return state?.runtimeState?.flowState?.kiro || state?.flowState?.kiro || {};
|
||||
}
|
||||
|
||||
function buildTargetEmailHints(targetEmail = '') {
|
||||
const normalizedTarget = cleanString(targetEmail).toLowerCase();
|
||||
return normalizedTarget ? [normalizedTarget] : [];
|
||||
}
|
||||
|
||||
function resolveNodeId(input) {
|
||||
const directNodeId = cleanString(input?.nodeId || input);
|
||||
if (directNodeId === DESKTOP_AUTHORIZE_NODE_ID) {
|
||||
return DESKTOP_AUTHORIZE_NODE_ID;
|
||||
}
|
||||
return SUBMIT_VERIFICATION_CODE_NODE_ID;
|
||||
}
|
||||
|
||||
function getVisibleStepForNode(nodeId, state = {}) {
|
||||
const explicitStep = Number(state?.visibleStep || state?.step);
|
||||
if (Number.isInteger(explicitStep) && explicitStep > 0) {
|
||||
return explicitStep;
|
||||
}
|
||||
return nodeId === DESKTOP_AUTHORIZE_NODE_ID ? 8 : 4;
|
||||
}
|
||||
|
||||
function isMail2925Provider(state = {}) {
|
||||
return cleanString(state?.mailProvider).toLowerCase() === '2925';
|
||||
}
|
||||
|
||||
function shouldMatchMail2925TargetEmail(state = {}) {
|
||||
return isMail2925Provider(state)
|
||||
&& cleanString(state?.mail2925Mode).toLowerCase() === 'receive';
|
||||
}
|
||||
|
||||
function createKiroMailRules(deps = {}) {
|
||||
const {
|
||||
LUCKMAIL_PROVIDER = 'luckmail-api',
|
||||
MAIL_2925_VERIFICATION_INTERVAL_MS = 15000,
|
||||
MAIL_2925_VERIFICATION_MAX_ATTEMPTS = 15,
|
||||
} = deps;
|
||||
|
||||
function getRuleDefinition(input, state = {}) {
|
||||
const nodeId = resolveNodeId(input);
|
||||
const normalizedStep = getVisibleStepForNode(nodeId, state);
|
||||
const runtimeState = readKiroRuntime(state);
|
||||
const targetEmail = cleanString(runtimeState.register?.email || state?.email).toLowerCase();
|
||||
const normalizedProvider = cleanString(state?.mailProvider).toLowerCase();
|
||||
const mail2925Provider = isMail2925Provider(state);
|
||||
const luckmailProvider = normalizedProvider === cleanString(LUCKMAIL_PROVIDER).toLowerCase();
|
||||
|
||||
return {
|
||||
flowId: 'kiro',
|
||||
ruleId: nodeId === DESKTOP_AUTHORIZE_NODE_ID
|
||||
? DESKTOP_AUTHORIZE_CODE_RULE_ID
|
||||
: SUBMIT_VERIFICATION_CODE_RULE_ID,
|
||||
nodeId,
|
||||
step: normalizedStep,
|
||||
artifactType: 'code',
|
||||
codePatterns: KIRO_AWS_VERIFICATION_CODE_PATTERNS,
|
||||
filterAfterTimestamp: 0,
|
||||
requiredKeywords: KIRO_AWS_REQUIRED_KEYWORDS,
|
||||
senderFilters: KIRO_AWS_SENDER_FILTERS,
|
||||
subjectFilters: KIRO_AWS_SUBJECT_FILTERS,
|
||||
targetEmail,
|
||||
targetEmailHints: buildTargetEmailHints(targetEmail),
|
||||
mail2925MatchTargetEmail: shouldMatchMail2925TargetEmail(state),
|
||||
maxAttempts: luckmailProvider
|
||||
? 3
|
||||
: (mail2925Provider ? MAIL_2925_VERIFICATION_MAX_ATTEMPTS : 5),
|
||||
intervalMs: luckmailProvider
|
||||
? 15000
|
||||
: (mail2925Provider ? MAIL_2925_VERIFICATION_INTERVAL_MS : 3000),
|
||||
};
|
||||
}
|
||||
|
||||
function getRuleDefinitionForNode(nodeId, state = {}) {
|
||||
return getRuleDefinition({ nodeId }, state);
|
||||
}
|
||||
|
||||
function buildVerificationPollPayload(input, state = {}, overrides = {}) {
|
||||
return {
|
||||
...getRuleDefinition(input, state),
|
||||
...(overrides || {}),
|
||||
};
|
||||
}
|
||||
|
||||
function buildVerificationPollPayloadForNode(nodeId, state = {}, overrides = {}) {
|
||||
return buildVerificationPollPayload({ nodeId }, state, overrides);
|
||||
}
|
||||
|
||||
return {
|
||||
buildVerificationPollPayload,
|
||||
buildVerificationPollPayloadForNode,
|
||||
getRuleDefinition,
|
||||
getRuleDefinitionForNode,
|
||||
};
|
||||
}
|
||||
|
||||
return {
|
||||
DESKTOP_AUTHORIZE_CODE_RULE_ID,
|
||||
DESKTOP_AUTHORIZE_NODE_ID,
|
||||
KIRO_AWS_REQUIRED_KEYWORDS,
|
||||
KIRO_AWS_SENDER_FILTERS,
|
||||
KIRO_AWS_SUBJECT_FILTERS,
|
||||
KIRO_AWS_VERIFICATION_CODE_PATTERNS,
|
||||
SUBMIT_VERIFICATION_CODE_NODE_ID,
|
||||
SUBMIT_VERIFICATION_CODE_RULE_ID,
|
||||
createKiroMailRules,
|
||||
};
|
||||
});
|
||||
Reference in New Issue
Block a user