// TODO: 替换为自己的盐 // 服务器接收来自 app 的请求的盐 const saltApp2End = "123321"; // 服务器发送数据到 app 的盐 const saltEnd2App = "123321"; addEventListener("fetch", (event) => { event.respondWith(handleRequest(event.request)); }); async function handleRequest(request) { let params; try { params = await request.json(); } catch (error) { return new Response(); } if (!params || Object.keys(params).length === 0) { return new Response(); } if (!(await _verifySignFromApp(params))) { return new Response(); } if (!_verifyTimestamp(params.date)) { return new Response(); } let responseData = {}; let sid = params.sid; //TODO: 判断 sid 是否是允许的用户 // 如果使用 cloudflare worker,可以使用 KV 存储 key: sid value:与用户定义的其它标识 例如邮箱 if (sid) { responseData.pass = true; } else { responseData.pass = false; } const signedResponse = await _signResponse2App( responseData, params.sessionId ); return new Response(JSON.stringify(signedResponse), { headers: { "Content-Type": "application/json" }, }); } async function _verifySignFromApp(params) { const { sign, ...otherParams } = params; if ( !sign || !otherParams.random || !otherParams.date || !otherParams.sessionId || !otherParams.sid ) return false; const sortedParams = Object.entries(otherParams) .sort((a, b) => b[0].localeCompare(a[0])) .map(([key, value]) => `${key}=${value}`) .join("&"); const salt = saltApp2End + otherParams.random.slice(-4) + otherParams.date.slice(-4); const signStr = salt + sortedParams; const calculatedSign = await _keyToSha256(signStr); return calculatedSign === sign; } async function _signResponse2App(data, sessionId) { const signMap = { ...data }; // 64位随机数 const random = crypto.randomUUID().slice(-64); const date = Date.now().toString(); signMap.random = random; signMap.date = date; signMap.sessionId = sessionId; const sortedParams = Object.entries(signMap) .sort((a, b) => b[0].localeCompare(a[0])) .map(([key, value]) => `${key}=${value}`) .join("&"); const salt = saltEnd2App + random.slice(-4) + date.slice(-4); const signStr = salt + sortedParams; signMap.sign = await _keyToSha256(signStr); return signMap; } async function _keyToSha256(input) { const encoder = new TextEncoder(); const data = encoder.encode(input); const hashBuffer = await crypto.subtle.digest("SHA-256", data); return Array.from(new Uint8Array(hashBuffer)) .map((b) => b.toString(16).padStart(2, "0")) .join(""); } // 验证时间戳 function _verifyTimestamp(timestamp) { // 时间为了保证任意时区都一致 所以使用格林威治时间 const currentTimeString = new Date().toISOString(); const currentTime = new Date(currentTimeString).getTime(); const requestTime = parseInt(timestamp); const timeDifference = Math.abs(currentTime - requestTime); // 检查时间差是否小于2分钟(120000毫秒) return timeDifference < 120000; }