Files
RedditBot/extensions/reddit-session-exporter/service-worker.js
T

93 lines
3.3 KiB
JavaScript

import {
assertMatchingSessionIdentity,
createSessionExportDownload,
} 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) {
throw new Error('Open Reddit Chat, wait for it to load, then click the extension again.');
}
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.');
}
});