/** * Pinduoduo Cookie Sync Background Service Worker (Manifest V3) * 拼多多 Cookie 自动嗅探与加密保活后台服务 */ try { importScripts('crypto.js') } catch (e) { console.error('导入加密工具失败:', e) } const ALARM_NAME = 'pdd_cookie_sync_alarm' let debounceTimer = null // 设置扩展图标角标状态 function setExtensionBadge(text, color) { chrome.action.setBadgeText({ text }) if (color) { chrome.action.setBadgeBackgroundColor({ color }) } } // 获取拼多多全量 Cookie 字符串 async function getPddCookieString() { try { const cookies = await chrome.cookies.getAll({ domain: 'pinduoduo.com' }) if (!cookies || cookies.length === 0) { return '' } // 拼接成标准 Cookie 请求头格式 return cookies.map((c) => `${c.name}=${c.value}`).join('; ') } catch (err) { console.error('读取拼多多 Cookie 异常:', err) return '' } } // 核心同步逻辑 async function syncCookieToServer(isManual = false) { const config = await chrome.storage.local.get([ 'serverUrl', 'shopId', 'syncToken', 'lastCookieHash', 'lastSyncAt', ]) const serverUrl = String(config.serverUrl || '').trim().replace(/\/+$/, '') const shopId = String(config.shopId || '').trim() const syncToken = String(config.syncToken || '').trim() if (!serverUrl || !shopId || !syncToken) { setExtensionBadge('CFG', '#faad14') // 待配置 return { success: false, message: '请先打开插件弹窗完成服务器地址与店铺配对密钥配置', } } // 1. 读取当前 Cookie const cookieStr = await getPddCookieString() if (!cookieStr) { setExtensionBadge('OFF', '#8c8c8c') // 未登录 await chrome.storage.local.set({ lastStatus: 'offline', lastMessage: '未在浏览器中检测到拼多多商家后台登录 Cookie', }) return { success: false, message: '未检测到拼多多登录 Cookie,请先在当前浏览器中登录 mms.pinduoduo.com', } } // 2. 计算 Cookie 哈希并进行指纹去重 const currentHash = await computeSha256(cookieStr) const now = Date.now() const lastSyncTime = Number(config.lastSyncAt || 0) // 若非手动强制触发,且 Cookie 未变动,且距离上次同步不足 1 小时,跳过重复上报 if (!isManual && config.lastCookieHash === currentHash && now - lastSyncTime < 3600_000) { return { success: true, skipped: true, message: 'Cookie 无实质变动,无需重复上报', } } try { // 3. 请求服务端公钥 const pkUrl = `${serverUrl}/api/v1/pdd/extension/public-key` const pkResp = await fetch(pkUrl, { method: 'GET', headers: { Accept: 'application/json' }, }) if (!pkResp.ok) { throw new Error(`获取公钥失败 HTTP ${pkResp.status}`) } const pkJson = await pkResp.json() const serverPublicKeySpki = pkJson?.data?.publicKeySpki if (!serverPublicKeySpki) { throw new Error('服务端返回的 RSA 公钥格式异常') } // 4. 构建明文载荷(syncToken 在加密包内外双重保护) const payload = { shopId, syncToken, cookie: cookieStr, userAgent: navigator.userAgent, timestamp: Date.now(), nonce: 'ext_' + Math.random().toString(36).slice(2) + Date.now().toString(36), } // 5. 执行端到端混合信封加密 (RSA-OAEP + AES-256-GCM) const envelope = await encryptPayloadWithEnvelope(payload, serverPublicKeySpki) // 6. 安全回传至服务端 const syncUrl = `${serverUrl}/api/v1/pdd/extension/sync-cookie` const syncResp = await fetch(syncUrl, { method: 'POST', headers: { 'Content-Type': 'application/json', 'X-Shop-Token': syncToken, }, body: JSON.stringify({ envelope }), }) const syncJson = await syncResp.json() if (!syncResp.ok || syncJson.code !== 0) { const errMsg = syncJson?.message || `服务端返回错误 HTTP ${syncResp.status}` throw new Error(errMsg) } // 同步成功,更新持久化状态 await chrome.storage.local.set({ lastCookieHash: currentHash, lastSyncAt: now, lastStatus: 'ok', lastMessage: syncJson.message || '同步成功并已生效', totalOrders: syncJson.data?.totalOrders, }) setExtensionBadge('OK', '#52c41a') // 绿色成功 return { success: true, message: 'Cookie 同步成功!服务端已完成在线校验并持久化生效', totalOrders: syncJson.data?.totalOrders, } } catch (err) { const errMsg = err instanceof Error ? err.message : String(err) console.error('Cookie 自动同步失败:', errMsg) await chrome.storage.local.set({ lastStatus: 'error', lastMessage: errMsg, }) setExtensionBadge('ERR', '#ff4d4f') // 红色错误 return { success: false, message: errMsg, } } } // 监听拼多多 Cookie 实时变动事件(带防抖延时 3 秒) chrome.cookies.onChanged.addListener((changeInfo) => { const domain = changeInfo.cookie?.domain || '' if (domain.includes('pinduoduo.com')) { if (debounceTimer) { clearTimeout(debounceTimer) } debounceTimer = setTimeout(() => { syncCookieToServer(false).catch(() => null) }, 3000) } }) // 定时任务:每隔 30 分钟进行一次轻量巡检与必要保活上报 chrome.alarms.onAlarm.addListener((alarm) => { if (alarm.name === ALARM_NAME) { syncCookieToServer(false).catch(() => null) } }) // 扩展安装或更新时注册定时闹钟 chrome.runtime.onInstalled.addListener(() => { chrome.alarms.create(ALARM_NAME, { periodInMinutes: 30, }) // 首次运行尝试同步一次 syncCookieToServer(false).catch(() => null) }) // 响应来自 popup.js 的前端交互消息 chrome.runtime.onMessage.addListener((req, _sender, sendResponse) => { if (req.action === 'trigger_sync') { syncCookieToServer(true).then(sendResponse).catch((err) => { sendResponse({ success: false, message: String(err) }) }) return true // 保持异步通信通道 } if (req.action === 'get_status') { getPddCookieString().then((ck) => { chrome.storage.local.get(null).then((data) => { sendResponse({ hasCookie: Boolean(ck && ck.length > 20), cookieLength: ck ? ck.length : 0, storage: data, }) }) }) return true } })