Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,7 @@
"rollup": "^2.56.3",
"ts-jest": "^29.0.0",
"tslib": "^2.5.0",
"typescript": "^5.2.2"
"typescript": "5.8.2"
},
"dependencies": {
"acorn": "^8.11.3",
Expand Down
29 changes: 19 additions & 10 deletions src/js/background/historyManager.ts
Original file line number Diff line number Diff line change
Expand Up @@ -38,16 +38,25 @@ export async function downloadHashSource(
.stream()
.pipeThrough(new DecompressionStream('gzip'));

const src = await new Response(decompressedStream).text();

const url = URL.createObjectURL(new Blob([src], {type: 'text/plain'}));
const a = document.createElement('a');
a.href = url;
a.download = `${tabID}-${hash}.txt`;
document.body.appendChild(a);
a.click();
document.body.removeChild(a);
URL.revokeObjectURL(url);
const fileName = `${tabID}-${hash}.txt`;

if ('showSaveFilePicker' in window) {
const fileHandle = await window.showSaveFilePicker({
suggestedName: fileName,
});
const writable = await fileHandle.createWritable();
await decompressedStream.pipeTo(writable);
} else {
const src = await new Response(decompressedStream).blob();
const url = URL.createObjectURL(src);
const a = document.createElement('a');
a.href = url;
a.download = fileName;
document.body.appendChild(a);
a.click();
document.body.removeChild(a);
URL.revokeObjectURL(url);
}
}

export async function upsertInvalidRecord(
Expand Down
4 changes: 0 additions & 4 deletions src/js/config.ts
Original file line number Diff line number Diff line change
Expand Up @@ -80,10 +80,6 @@ export const ORIGIN_TYPE = Object.freeze({

export type Origin = keyof typeof ORIGIN_TYPE;

// Firefox and Safari currently do not support CompressionStream/showSaveFilePicker
export const DOWNLOAD_SRC_ENABLED =
'CompressionStream' in window && 'showSaveFilePicker' in window;

export const MANIFEST_TIMEOUT = 45000;

export const DYNAMIC_STRING_MARKER = '/*BTDS*/';
5 changes: 2 additions & 3 deletions src/js/content.ts
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,6 @@ import './globals';

import {
MESSAGE_TYPE,
DOWNLOAD_SRC_ENABLED,
STATES,
Origin,
ORIGIN_TYPE,
Expand Down Expand Up @@ -456,7 +455,7 @@ export function startFor(origin: Origin, config: ContentScriptConfig): void {
}

chrome.runtime.onMessage.addListener(request => {
if (request.greeting === 'downloadSource' && DOWNLOAD_SRC_ENABLED) {
if (request.greeting === 'downloadSource') {
downloadSrc();
} else if (request.greeting === 'nocacheHeaderFound') {
updateCurrentState(
Expand Down Expand Up @@ -488,7 +487,7 @@ chrome.runtime.onMessage.addListener(request => {
});
ALL_FOUND_TAGS_URLS.add(request.response.url);
const uninitializedScripts = FOUND_ELEMENTS.get(
FOUND_ELEMENTS.keys().next().value,
FOUND_ELEMENTS.keys().next().value!,
);
if (uninitializedScripts) {
uninitializedScripts.push({
Expand Down
21 changes: 8 additions & 13 deletions src/js/content/contentUtils.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,13 +8,13 @@
import alertBackgroundOfImminentFetch from './alertBackgroundOfImminentFetch';

import {TagDetails} from '../content';
import {DOWNLOAD_SRC_ENABLED, MESSAGE_TYPE} from '../config';
import {MESSAGE_TYPE} from '../config';
import genSourceText from './genSourceText';
import {sendMessageToBackground} from '../shared/sendMessageToBackground';
import {getCurrentOrigin} from './updateCurrentState';
import downloadArchive from './downloadArchive';

const SOURCE_SCRIPTS_AND_STYLES = new Map();
const SOURCE_SCRIPTS_AND_STYLES = new Map<string, Response>();

async function processSrc(
tagDetails: TagDetails,
Expand All @@ -40,18 +40,13 @@ async function processSrc(
// If this is missing it will cause a cache miss, resulting in invalidation.
headers: isServiceWorker ? {'Service-Worker': 'script'} : undefined,
});
if (DOWNLOAD_SRC_ENABLED) {
const fileNameArr = url.split('/');
const fileName = fileNameArr[fileNameArr.length - 1].split('?')[0];
const responseBody = sourceResponse.clone().body;
if (!responseBody) {
throw new Error('Response for fetched script has no body');
}
SOURCE_SCRIPTS_AND_STYLES.set(
fileName,
responseBody.pipeThrough(new window.CompressionStream('gzip')),
);
const fileNameArr = url.split('/');
const fileName = fileNameArr[fileNameArr.length - 1].split('?')[0];
const responseBody = sourceResponse.clone();
if (!responseBody.body) {
throw new Error('Response for fetched script has no body');
}
SOURCE_SCRIPTS_AND_STYLES.set(fileName, responseBody);
const sourceText = await genSourceText(sourceResponse);

// split package up if necessary
Expand Down
55 changes: 36 additions & 19 deletions src/js/content/downloadArchive.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,28 +6,45 @@
*/

export default async function downloadArchive(
sourceScripts: Map<string, ReadableStream>,
sourceScripts: Map<string, Response>,
): Promise<void> {
const fileHandle = await window.showSaveFilePicker({
suggestedName: 'meta_source_files.gz',
});

const writableStream = await fileHandle.createWritable();
// delimiter between files
const delimPrefix = '\n********** new file: ';
const delimSuffix = ' **********\n';
// eslint-disable-next-line @typescript-eslint/no-explicit-any
const chunks: Array<any> = [];
const enc = new TextEncoder();
const compressionStream = new CompressionStream('gzip');

for (const [fileName, compressedStream] of sourceScripts.entries()) {
const delim = delimPrefix + fileName + delimSuffix;
const encodedDelim = enc.encode(delim);
const delimStream = new window.CompressionStream('gzip');
const writer = delimStream.writable.getWriter();
writer.write(encodedDelim);
writer.close();
await delimStream.readable.pipeTo(writableStream, {preventClose: true});
await compressedStream.pipeTo(writableStream, {preventClose: true});
for (const [fileName, response] of sourceScripts.entries()) {
const delim = `\n********** new file: ${fileName} **********\n`;
const chunk = await response.bytes();
chunks.push(enc.encode(delim), chunk);
}

writableStream.close();
const readableFromChunks = new ReadableStream({
start(controller) {
for (const chunk of chunks) {
controller.enqueue(chunk);
}
controller.close();
},
});

if ('showSaveFilePicker' in window) {
const fileHandle = await window.showSaveFilePicker({
suggestedName: 'meta_source_files.gz',
});
const fileStream = await fileHandle.createWritable();
readableFromChunks.pipeThrough(compressionStream).pipeTo(fileStream);
} else {
const src = await new Response(
readableFromChunks.pipeThrough(compressionStream),
).blob();
const url = URL.createObjectURL(src);
const a = document.createElement('a');
a.href = url;
a.download = `meta_source_files.gz`;
document.body.appendChild(a);
a.click();
document.body.removeChild(a);
URL.revokeObjectURL(url);
}
}
25 changes: 6 additions & 19 deletions src/js/popup/popup.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,12 +8,7 @@
import '../globals';

import type {Origin, State} from '../config';
import {
DOWNLOAD_SRC_ENABLED,
MESSAGE_TYPE,
ORIGIN_TYPE,
STATES,
} from '../config.js';
import {MESSAGE_TYPE, ORIGIN_TYPE, STATES} from '../config.js';

import './violation-list';

Expand Down Expand Up @@ -79,23 +74,19 @@ function attachMenuListeners(origin: Origin): void {

const menuRows = document.getElementsByClassName('menu_row');

menuRows[0].addEventListener('click', _evt => {
menuRows[0].addEventListener('click', () => {
chrome.tabs.create({url: ORIGIN_TO_LEARN_MORE_PAGES[origin].about});
});

menuRows[1].addEventListener('click', _evt => {
menuRows[1].addEventListener('click', () => {
updateDisplay('violation_list');
});

menuRows[3].addEventListener('click', _evt => {
menuRows[2].addEventListener('click', () => updateDisplay('download'));

menuRows[3].addEventListener('click', () => {
sendMessageToActiveTab('downloadReleaseSource');
});

if (DOWNLOAD_SRC_ENABLED) {
menuRows[2].addEventListener('click', () => updateDisplay('download'));
} else {
menuRows[2].remove();
}
}

function updateDisplay(state: State | PopupState): void {
Expand Down Expand Up @@ -280,10 +271,6 @@ const handleButtonAction = (
action: string,
id: string,
) => {
if (action === 'download' && !DOWNLOAD_SRC_ENABLED) {
button.remove();
return;
}
button?.addEventListener('click', () => {
if (action === 'retry') {
chrome.tabs.reload();
Expand Down
Loading