import { assertMatchingSessionIdentity, createSessionExportDownload, REDDIT_CHAT_URL, } from './session-export.js'; const MATRIX_URLS = [ 'https://matrix.redditspace.com/*', 'https://matrix.reddit.com/*', ]; chrome.webRequest.onBeforeSendHeaders.addListener( async (details) => { const authorization = details.requestHeaders?.find( (header) => header.name.toLowerCase() === 'authorization', )?.value; if (!authorization?.toLowerCase().startsWith('bearer ')) return; const url = new URL(details.url); await chrome.storage.local.set({ matrixCapture: { homeserver: `${url.protocol}//${url.host}`, accessToken: authorization.slice('bearer '.length).trim(), capturedAt: Date.now(), }, }); await chrome.action.setBadgeText({ text: 'OK' }); await chrome.action.setBadgeBackgroundColor({ color: '#198754' }); }, { urls: MATRIX_URLS }, ['requestHeaders', 'extraHeaders'], ); chrome.cookies.onChanged.addListener(async ({ cookie }) => { if (!['reddit_session', 'token_v2'].includes(cookie.name)) return; await chrome.storage.local.remove('matrixCapture'); await chrome.action.setBadgeText({ text: '' }); await chrome.action.setTitle({ title: 'Reddit account changed. Open Reddit Chat before exporting.', }); }); async function getRedditIdentity() { const response = await fetch('https://www.reddit.com/api/me.json', { credentials: 'include', cache: 'no-store', }); if (!response.ok) throw new Error('Reddit cookies did not authenticate. Sign in and try again.'); const payload = await response.json(); const account = payload?.data ?? payload; if (!account?.name || !account?.id) { throw new Error('Reddit did not return an authenticated account identity.'); } return { username: account.name, accountId: account.id }; } async function showError(message) { await chrome.action.setBadgeText({ text: 'ERR' }); await chrome.action.setBadgeBackgroundColor({ color: '#dc3545' }); await chrome.action.setTitle({ title: `RedditBot export not ready: ${message}` }); } chrome.action.onClicked.addListener(async () => { try { const cookies = await chrome.cookies.getAll({ domain: 'reddit.com' }); const { matrixCapture } = await chrome.storage.local.get('matrixCapture'); if (!matrixCapture) { await chrome.tabs.create({ url: REDDIT_CHAT_URL }); await chrome.action.setBadgeText({ text: '...' }); await chrome.action.setBadgeBackgroundColor({ color: '#6c757d' }); await chrome.action.setTitle({ title: 'Reddit Chat opened. Wait for the badge to show OK, then click again.', }); return; } const whoami = await fetch(`${matrixCapture.homeserver}/_matrix/client/v3/account/whoami`, { headers: { Authorization: `Bearer ${matrixCapture.accessToken}` }, }); if (!whoami.ok) throw new Error('The captured Reddit Chat token has expired. Reload Reddit Chat and try again.'); const identity = await whoami.json(); if (!identity?.user_id) throw new Error('Reddit Chat did not return an account identity.'); const redditIdentity = await getRedditIdentity(); try { assertMatchingSessionIdentity(redditIdentity, identity.user_id); } catch (error) { await chrome.storage.local.remove('matrixCapture'); throw error; } await chrome.downloads.download({ ...createSessionExportDownload(cookies, { ...matrixCapture, userId: identity.user_id }), saveAs: true, }); } catch (error) { await showError(error instanceof Error ? error.message : 'Could not create the session dump.'); } });