// --- Backend API Logic --- /** * Handles CORS preflight requests. * @returns {Response} */ function handleOptions() { return new Response(null, { headers: getCorsHeaders(), }); } /** * Creates a JSON response with appropriate headers. * @param {object} body - The response body. * @param {number} status - The HTTP status code. * @returns {Response} */ function createJsonResponse(body, status) { return new Response(JSON.stringify(body, null, 2), { status: status, headers: { 'Content-Type': 'application/json', ...getCorsHeaders(), }, }); } /** * Gets the required CORS headers. * @returns {object} */ function getCorsHeaders() { return { 'Access-Control-Allow-Origin': '*', 'Access-Control-Allow-Methods': 'POST, OPTIONS', 'Access-Control-Allow-Headers': 'Content-Type', }; } /** * Handles the token acquisition request from the frontend. * It exchanges the authorization code for an access token and refresh token. * @param {Request} request - The incoming request. * @returns {Promise} */ async function handleTokenRequest(request) { const { code, redirect_uri, cloud_env, client_id, client_secret } = await request.json(); if (!code || !redirect_uri || !cloud_env || !client_id || !client_secret) { return createJsonResponse({ error: '请求体中缺少必要参数。' }, 400); } const tokenUrl = cloud_env === 'china' ? 'https://login.chinacloudapi.cn/common/oauth2/v2.0/token' : 'https://login.microsoftonline.com/common/oauth2/v2.0/token'; const body = new URLSearchParams({ client_id: client_id, client_secret: client_secret, code: code, redirect_uri: redirect_uri, grant_type: 'authorization_code', scope: 'offline_access Files.ReadWrite.All Sites.Read.All', }); try { const tokenResponse = await fetch(tokenUrl, { method: 'POST', headers: { 'Content-Type': 'application/x-www-form-urlencoded' }, body: body, }); const tokenData = await tokenResponse.json(); if (!tokenResponse.ok) { return createJsonResponse(tokenData, tokenResponse.status); } return createJsonResponse(tokenData, 200); } catch (error) { return createJsonResponse({ error: '从微软获取令牌失败。', details: error.message }, 500); } } /** * Handles the SharePoint Site ID request from the frontend. * It uses the provided access token to query the Microsoft Graph API. * @param {Request} request - The incoming request. * @returns {Promise} */ async function handleSiteIdRequest(request) { const { accessToken, cloudEnv, hostname, sitePath } = await request.json(); if (!accessToken || !cloudEnv || !hostname) { return createJsonResponse({ error: '查询 Site ID 的请求体中缺少必要参数。' }, 400); } const graphEndpoint = cloudEnv === 'china' ? 'https://microsoftgraph.chinacloudapi.cn' : 'https://graph.microsoft.com'; // Construct the URL for the Graph API call const relativePath = sitePath && sitePath !== '/' ? `:${sitePath}` : ''; const siteUrl = `${graphEndpoint}/v1.0/sites/${hostname}${relativePath}`; try { const siteResponse = await fetch(siteUrl, { method: 'GET', headers: { 'Authorization': `Bearer ${accessToken}`, }, }); const siteData = await siteResponse.json(); if (!siteResponse.ok) { return createJsonResponse(siteData, siteResponse.status); } return createJsonResponse(siteData, 200); } catch (error) { return createJsonResponse({ error: '从微软 Graph 获取 Site ID 失败。', details: error.message }, 500); } } // --- Frontend HTML & JS --- /** * Generates the full HTML content for the tool's UI. * @returns {string} - The HTML content as a string. */ function getHtmlContent() { return ` 一体化 OneDrive & SharePoint 工具

一体化 OneDrive & SharePoint 工具

一键获取刷新令牌和 SharePoint Site ID

步骤 1: 应用配置 & 获取令牌

将此URL复制到您Azure应用的Web平台重定向URI中。

`; } // --- Worker Main Logic & Router --- export default { async fetch(request) { const url = new URL(request.url); // Handle API routes if (url.pathname.startsWith('/api/')) { if (request.method === 'OPTIONS') { return handleOptions(); } if (url.pathname === '/api/token' && request.method === 'POST') { return handleTokenRequest(request); } if (url.pathname === '/api/site-id' && request.method === 'POST') { return handleSiteIdRequest(request); } } // Serve HTML for the root path if (url.pathname === '/' && request.method === 'GET') { return new Response(getHtmlContent(), { headers: { 'Content-Type': 'text/html;charset=utf-8' }, }); } return new Response('未找到', { status: 404 }); }, };