115 lines
4.1 KiB
JavaScript
115 lines
4.1 KiB
JavaScript
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' });
|
|
await chrome.action.setTitle({ title: 'Reddit Chat token captured. Click to export.' });
|
|
},
|
|
{ urls: MATRIX_URLS },
|
|
['requestHeaders', 'extraHeaders'],
|
|
);
|
|
|
|
async function getRedditIdentity() {
|
|
const tabs = await chrome.tabs.query({
|
|
url: ['https://reddit.com/*', 'https://www.reddit.com/*'],
|
|
});
|
|
const tab = tabs.find((candidate) => candidate.active) ?? tabs[0];
|
|
if (tab?.id === undefined) {
|
|
throw new Error('Keep a signed-in www.reddit.com tab open while exporting.');
|
|
}
|
|
|
|
const [{ result } = {}] = await chrome.scripting.executeScript({
|
|
target: { tabId: tab.id },
|
|
world: 'MAIN',
|
|
func: async () => {
|
|
try {
|
|
const response = await fetch('https://www.reddit.com/api/me.json', {
|
|
credentials: 'include',
|
|
cache: 'no-store',
|
|
});
|
|
if (!response.ok) return { error: 'Reddit cookies did not authenticate. Sign in and try again.' };
|
|
return { payload: await response.json() };
|
|
} catch {
|
|
return { error: 'Could not read the current Reddit account. Reload Reddit and try again.' };
|
|
}
|
|
},
|
|
});
|
|
|
|
if (result?.error) throw new Error(result.error);
|
|
const payload = result?.payload;
|
|
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,
|
|
});
|
|
await chrome.action.setBadgeText({ text: 'OK' });
|
|
await chrome.action.setTitle({ title: 'RedditBot session export created.' });
|
|
} catch (error) {
|
|
await showError(error instanceof Error ? error.message : 'Could not create the session dump.');
|
|
}
|
|
});
|