import { authApiToken, authMiddleware } from "../../utils/auth.js"; import { addCorsHeaders } from "../../utils/cors.js"; import { chromium } from 'playwright'; import { getVerificationCode } from '../../utils/emailVerification.js'; export const onRequest = async (context: RouteContext): Promise => { const request = context.request; const env: Env = context.env; // 验证权限 const authResponse = await authMiddleware(request, env); const apiResponse = await authApiToken(request, env); if (authResponse && apiResponse) { return addCorsHeaders(authResponse); } try { const { email } = await request.json() as any; if (!email) { throw new Error("Email is required"); } // 获取账户信息 const accountsStr = await env.KV.get("accounts"); const accounts: any[] = accountsStr ? JSON.parse(accountsStr) : []; const account = accounts.find(a => a.email === email); if (!account) { throw new Error("Account not found"); } const clientId = env.ENTRA_CLIENT_ID; const clientSecret = env.ENTRA_CLIENT_SECRET; const redirectUri = env.AUTH_REDIRECT_URI; let browser; let context; try { browser = await chromium.launch({ headless: true, args: [ '--no-sandbox', '--disable-setuid-sandbox', '--disable-dev-shm-usage', '--disable-blink-features=AutomationControlled', // 禁用自动化特征 '--disable-infobars', '--window-size=1920,1080' ], executablePath: process.env.PLAYWRIGHT_CHROMIUM_EXECUTABLE_PATH, // 使用系统 Chromium }); context = await browser.newContext(); const page = await context.newPage(); const authUrl = `https://login.microsoftonline.com/common/oauth2/v2.0/authorize?` + `client_id=${clientId}` + `&response_type=code` + `&redirect_uri=${encodeURIComponent(redirectUri)}` + `&response_mode=query` + `&scope=offline_access%20IMAP.AccessAsUser.All%20User.Read%20Mail.ReadWrite.Shared%20Mail.Send%20Mail.Read` + `&prompt=consent` + //强制显示权限确认窗口 `&state=${email}`; console.log(authUrl) //开始认证 await page.goto(authUrl); await page.fill('input[type="email"]', account.email); await page.click('input[type="submit"]'); try { await page.waitForSelector('#idA_PWD_SwitchToPassword', { timeout: 3000 }); await page.click('#idA_PWD_SwitchToPassword'); } catch (error) { console.log(`没有切换到密码登录,继续执行: ${error}`); } try { const timestamp = Math.floor(Date.now() / 1000); await page.waitForSelector('#idA_PWD_SwitchToCredPicker', { timeout: 3000 }); try { //处理email验证 const proof = [ { "suffix": "godgodgame.com", "apiUrl": "http://159.138.99.139:89/api/latest-email", "token": env.PROOF_GODGODGAME_TOKEN }, { "suffix": "igiven.com", "apiUrl": "http://159.138.99.139:90/api/latest-email", "token": env.PROOF_IGIVEN_TOKEN } ] const suffix = email.substring(email.indexOf('@') + 1); const proofConfig = proof.find(p => p.suffix === suffix)!; const verificationCode = await getVerificationCode(proofConfig.apiUrl, proofConfig.token!, account.proofEmail, timestamp); await page.fill('input[type="tel"]', verificationCode); await page.click('button[type="submit"]'); } catch (error) { throw new Error(`邮箱验证失败:${error}`) } await page.click('#idA_PWD_SwitchToCredPicker'); await page.click('#tileList > div:nth-child(2) Button'); } catch (error) { console.log(`没有直接发邮件验证,继续执行: ${error}`); } //输入密码 await page.waitForURL("https://login.live.com/**") await page.fill('input[type="password"]', account.password); await page.click('button[type="submit"]'); //确认登录 await page.waitForURL('https://login.live.com/ppsecure/**') await page.click('button[type="submit"]#acceptButton'); // 同意按钮 //同意授权 try { // 等待同意授权页面,如果超时5秒则跳过 await page.waitForURL("https://account.live.com/Consent/**", { timeout: 5000 }) await page.click('button[type="submit"][data-testid="appConsentPrimaryButton"]'); } catch (error) { // 如果超时或页面未出现,直接继续执行 console.log("Consent page not found or timeout, skipping..."); } await page.waitForURL((url)=>{ console.log(url) return url.href.startsWith(redirectUri); }) } finally { if (context) await context.close(); if (browser) await browser.close(); } // 等待回调处理完成,检查 KV 中是否有对应的 code let code = null; const maxRetries = 30; let retries = 0; while (!code && retries < maxRetries) { const codeKey = `code_${email}`; code = await env.KV.get(codeKey); if (!code) { await new Promise(resolve => setTimeout(resolve, 1000)); retries++; } } if (!code) { throw new Error("Authorization timeout"); } // 使用授权码获取刷新令牌 const tokenResponse = await fetch('https://login.microsoftonline.com/common/oauth2/v2.0/token', { method: 'POST', headers: { 'Content-Type': 'application/x-www-form-urlencoded' }, body: new URLSearchParams({ client_id: clientId, client_secret: clientSecret, code: code, redirect_uri: redirectUri, grant_type: 'authorization_code' }) }); const tokenData: any = await tokenResponse.json(); if (!tokenData.refresh_token) { throw new Error("Failed to get refresh token"); } if (!tokenData.expires_in) { throw new Error("Missing expires_in in token response"); } // 存储刷新令牌和时间戳 const tokenInfo = { ...tokenData, timestamp: Date.now() }; console.log(tokenInfo); await env.KV.put(`refresh_token_${email}`, JSON.stringify(tokenInfo)); // 删除临时授权码 await env.KV.delete(`code_${email}`); return new Response(JSON.stringify({ success: true }), { status: 200, headers: { 'Content-Type': 'application/json' } }); } catch (error: any) { return new Response( JSON.stringify({ error: error.message }), { status: 500 } ); } };