@crawlee/browser-pool 3.13.6-beta.0 → 4.0.0-beta.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/abstract-classes/browser-controller.d.ts +4 -4
- package/abstract-classes/browser-controller.d.ts.map +1 -1
- package/abstract-classes/browser-controller.js +43 -117
- package/abstract-classes/browser-controller.js.map +1 -1
- package/abstract-classes/browser-plugin.d.ts +5 -16
- package/abstract-classes/browser-plugin.d.ts.map +1 -1
- package/abstract-classes/browser-plugin.js +19 -71
- package/abstract-classes/browser-plugin.js.map +1 -1
- package/anonymize-proxy.js +4 -8
- package/anonymize-proxy.js.map +1 -1
- package/browser-pool.d.ts +6 -6
- package/browser-pool.d.ts.map +1 -1
- package/browser-pool.js +77 -209
- package/browser-pool.js.map +1 -1
- package/container-proxy-server.js +3 -6
- package/container-proxy-server.js.map +1 -1
- package/events.js +4 -7
- package/events.js.map +1 -1
- package/fingerprinting/hooks.d.ts +3 -3
- package/fingerprinting/hooks.d.ts.map +1 -1
- package/fingerprinting/hooks.js +13 -18
- package/fingerprinting/hooks.js.map +1 -1
- package/fingerprinting/types.js +6 -9
- package/fingerprinting/types.js.map +1 -1
- package/fingerprinting/utils.d.ts +2 -2
- package/fingerprinting/utils.d.ts.map +1 -1
- package/fingerprinting/utils.js +9 -13
- package/fingerprinting/utils.js.map +1 -1
- package/index.d.ts +13 -13
- package/index.d.ts.map +1 -1
- package/index.js +11 -26
- package/index.js.map +1 -1
- package/launch-context.d.ts +2 -9
- package/launch-context.d.ts.map +1 -1
- package/launch-context.js +12 -73
- package/launch-context.js.map +1 -1
- package/logger.js +2 -6
- package/logger.js.map +1 -1
- package/package.json +19 -25
- package/playwright/playwright-browser.js +6 -30
- package/playwright/playwright-browser.js.map +1 -1
- package/playwright/playwright-controller.d.ts +2 -2
- package/playwright/playwright-controller.d.ts.map +1 -1
- package/playwright/playwright-controller.js +9 -75
- package/playwright/playwright-controller.js.map +1 -1
- package/playwright/playwright-plugin.d.ts +6 -6
- package/playwright/playwright-plugin.d.ts.map +1 -1
- package/playwright/playwright-plugin.js +19 -106
- package/playwright/playwright-plugin.js.map +1 -1
- package/proxy-server.js +3 -6
- package/proxy-server.js.map +1 -1
- package/puppeteer/puppeteer-controller.d.ts +1 -1
- package/puppeteer/puppeteer-controller.d.ts.map +1 -1
- package/puppeteer/puppeteer-controller.js +13 -17
- package/puppeteer/puppeteer-controller.js.map +1 -1
- package/puppeteer/puppeteer-plugin.d.ts +5 -5
- package/puppeteer/puppeteer-plugin.d.ts.map +1 -1
- package/puppeteer/puppeteer-plugin.js +16 -23
- package/puppeteer/puppeteer-plugin.js.map +1 -1
- package/tsconfig.build.tsbuildinfo +1 -1
- package/utils.d.ts +3 -3
- package/utils.d.ts.map +1 -1
- package/utils.js +1 -4
- package/utils.js.map +1 -1
- package/index.mjs +0 -19
- package/playwright/load-firefox-addon.d.ts +0 -2
- package/playwright/load-firefox-addon.d.ts.map +0 -1
- package/playwright/load-firefox-addon.js +0 -86
- package/playwright/load-firefox-addon.js.map +0 -1
- package/tab-as-a-container/background.js +0 -433
- package/tab-as-a-container/content.js +0 -611
- package/tab-as-a-container/manifest.json +0 -21
package/utils.d.ts
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
|
-
import type { BrowserPlugin } from './abstract-classes/browser-plugin';
|
|
2
|
-
import type { PlaywrightPlugin } from './playwright/playwright-plugin';
|
|
3
|
-
import type { PuppeteerPlugin } from './puppeteer/puppeteer-plugin';
|
|
1
|
+
import type { BrowserPlugin } from './abstract-classes/browser-plugin.js';
|
|
2
|
+
import type { PlaywrightPlugin } from './playwright/playwright-plugin.js';
|
|
3
|
+
import type { PuppeteerPlugin } from './puppeteer/puppeteer-plugin.js';
|
|
4
4
|
export type UnwrapPromise<T> = T extends PromiseLike<infer R> ? UnwrapPromise<R> : T;
|
|
5
5
|
export declare function noop(..._args: unknown[]): void;
|
|
6
6
|
/**
|
package/utils.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"utils.d.ts","sourceRoot":"","sources":["../src/utils.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,
|
|
1
|
+
{"version":3,"file":"utils.d.ts","sourceRoot":"","sources":["../src/utils.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,sCAAsC,CAAC;AAC1E,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,mCAAmC,CAAC;AAC1E,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,iCAAiC,CAAC;AAEvE,MAAM,MAAM,aAAa,CAAC,CAAC,IAAI,CAAC,SAAS,WAAW,CAAC,MAAM,CAAC,CAAC,GAAG,aAAa,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC;AAErF,wBAAgB,IAAI,CAAC,GAAG,KAAK,EAAE,OAAO,EAAE,GAAG,IAAI,CAAG;AAElD;;;GAGG;AACH,MAAM,MAAM,cAAc,CAAC,CAAC,SAAS,CAAC,GAAG,IAAI,EAAE,GAAG,KAAK,GAAG,IAAI,OAAO,EAAE,SAAS,UAAU,CAAC,CAAC,CAAC,GAAG,GAAG,GAAG,UAAU,CAAC,CAAC,CAAC,CAAC;AAEpH,MAAM,MAAM,uBAAuB,CAE/B,KAAK,SAAS,SAAS,OAAO,EAAE,EAEhC,MAAM,SAAS,aAAa,EAAE,GAAG,EAAE,IACnC,KAAK,SAAS,SAAS,CAAC,MAAM,UAAU,EAAE,GAAG,MAAM,IAAI,CAAC,GAAG,CAAC,MAAM,UAAU,EAAE,GAAG,MAAM,IAAI,CAAC,GAE1F,UAAU,SAAS,gBAAgB,GAE/B,uBAAuB,CAAC,IAAI,EAAE,CAAC,GAAG,MAAM,EAAE,gBAAgB,CAAC,CAAC,GAE5D,UAAU,SAAS,eAAe,GAEhC,uBAAuB,CAAC,IAAI,EAAE,CAAC,GAAG,MAAM,EAAE,eAAe,CAAC,CAAC,GAE3D,KAAK,GAEX,KAAK,SAAS,EAAE,GAEd,MAAM,GAEN,KAAK,SAAS,SAAS,CAAC,MAAM,CAAC,CAAC,EAAE,GAEhC;IAAC,CAAC;CAAC,SAAS,CAAC,eAAe,GAAG,gBAAgB,CAAC,GAE5C,CAAC,EAAE,GAEH,KAAK,GAET,MAAM,CAAC"}
|
package/utils.js
CHANGED
package/utils.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"utils.js","sourceRoot":"","sources":["../src/utils.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"utils.js","sourceRoot":"","sources":["../src/utils.ts"],"names":[],"mappings":"AAMA,MAAM,UAAU,IAAI,CAAC,GAAG,KAAgB,IAAS,CAAC"}
|
package/index.mjs
DELETED
|
@@ -1,19 +0,0 @@
|
|
|
1
|
-
import mod from "./index.js";
|
|
2
|
-
|
|
3
|
-
export default mod;
|
|
4
|
-
export const BROWSER_CONTROLLER_EVENTS = mod.BROWSER_CONTROLLER_EVENTS;
|
|
5
|
-
export const BROWSER_POOL_EVENTS = mod.BROWSER_POOL_EVENTS;
|
|
6
|
-
export const BrowserController = mod.BrowserController;
|
|
7
|
-
export const BrowserLaunchError = mod.BrowserLaunchError;
|
|
8
|
-
export const BrowserName = mod.BrowserName;
|
|
9
|
-
export const BrowserPlugin = mod.BrowserPlugin;
|
|
10
|
-
export const BrowserPool = mod.BrowserPool;
|
|
11
|
-
export const DEFAULT_USER_AGENT = mod.DEFAULT_USER_AGENT;
|
|
12
|
-
export const DeviceCategory = mod.DeviceCategory;
|
|
13
|
-
export const LaunchContext = mod.LaunchContext;
|
|
14
|
-
export const OperatingSystemsName = mod.OperatingSystemsName;
|
|
15
|
-
export const PlaywrightBrowser = mod.PlaywrightBrowser;
|
|
16
|
-
export const PlaywrightController = mod.PlaywrightController;
|
|
17
|
-
export const PlaywrightPlugin = mod.PlaywrightPlugin;
|
|
18
|
-
export const PuppeteerController = mod.PuppeteerController;
|
|
19
|
-
export const PuppeteerPlugin = mod.PuppeteerPlugin;
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"load-firefox-addon.d.ts","sourceRoot":"","sources":["../../src/playwright/load-firefox-addon.ts"],"names":[],"mappings":"AAGA,eAAO,MAAM,gBAAgB,GAAU,MAAM,MAAM,EAAE,MAAM,MAAM,EAAE,WAAW,MAAM,qBAoGnF,CAAC"}
|
|
@@ -1,86 +0,0 @@
|
|
|
1
|
-
"use strict";
|
|
2
|
-
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
-
exports.loadFirefoxAddon = void 0;
|
|
4
|
-
const tslib_1 = require("tslib");
|
|
5
|
-
const node_buffer_1 = require("node:buffer");
|
|
6
|
-
const node_net_1 = tslib_1.__importDefault(require("node:net"));
|
|
7
|
-
const loadFirefoxAddon = async (port, host, addonPath) => {
|
|
8
|
-
return new Promise((resolve) => {
|
|
9
|
-
const socket = node_net_1.default.connect({
|
|
10
|
-
port,
|
|
11
|
-
host,
|
|
12
|
-
});
|
|
13
|
-
let success = false;
|
|
14
|
-
socket.once('error', () => { });
|
|
15
|
-
socket.once('close', () => {
|
|
16
|
-
resolve(success);
|
|
17
|
-
});
|
|
18
|
-
const send = (data) => {
|
|
19
|
-
const raw = node_buffer_1.Buffer.from(JSON.stringify(data));
|
|
20
|
-
socket.write(`${raw.length}`);
|
|
21
|
-
socket.write(':');
|
|
22
|
-
socket.write(raw);
|
|
23
|
-
};
|
|
24
|
-
send({
|
|
25
|
-
to: 'root',
|
|
26
|
-
type: 'getRoot',
|
|
27
|
-
});
|
|
28
|
-
const onMessage = (message) => {
|
|
29
|
-
if (message.addonsActor) {
|
|
30
|
-
send({
|
|
31
|
-
to: message.addonsActor,
|
|
32
|
-
type: 'installTemporaryAddon',
|
|
33
|
-
addonPath,
|
|
34
|
-
});
|
|
35
|
-
}
|
|
36
|
-
if (message.addon) {
|
|
37
|
-
success = true;
|
|
38
|
-
socket.end();
|
|
39
|
-
}
|
|
40
|
-
if (message.error) {
|
|
41
|
-
socket.end();
|
|
42
|
-
}
|
|
43
|
-
};
|
|
44
|
-
const buffers = [];
|
|
45
|
-
let remainingBytes = 0;
|
|
46
|
-
socket.on('data', (data) => {
|
|
47
|
-
while (true) {
|
|
48
|
-
if (remainingBytes === 0) {
|
|
49
|
-
const index = data.indexOf(':');
|
|
50
|
-
buffers.push(data);
|
|
51
|
-
if (index === -1) {
|
|
52
|
-
return;
|
|
53
|
-
}
|
|
54
|
-
const buffer = node_buffer_1.Buffer.concat(buffers);
|
|
55
|
-
const bufferIndex = buffer.indexOf(':');
|
|
56
|
-
buffers.length = 0;
|
|
57
|
-
remainingBytes = Number(buffer.subarray(0, bufferIndex).toString());
|
|
58
|
-
if (!Number.isFinite(remainingBytes)) {
|
|
59
|
-
throw new Error('Invalid state');
|
|
60
|
-
}
|
|
61
|
-
data = buffer.subarray(bufferIndex + 1);
|
|
62
|
-
}
|
|
63
|
-
if (data.length < remainingBytes) {
|
|
64
|
-
remainingBytes -= data.length;
|
|
65
|
-
buffers.push(data);
|
|
66
|
-
break;
|
|
67
|
-
}
|
|
68
|
-
buffers.push(data.subarray(0, remainingBytes));
|
|
69
|
-
const buffer = node_buffer_1.Buffer.concat(buffers);
|
|
70
|
-
buffers.length = 0;
|
|
71
|
-
const json = JSON.parse(buffer.toString());
|
|
72
|
-
queueMicrotask(() => {
|
|
73
|
-
onMessage(json);
|
|
74
|
-
});
|
|
75
|
-
const remainder = data.subarray(remainingBytes);
|
|
76
|
-
remainingBytes = 0;
|
|
77
|
-
if (remainder.length === 0) {
|
|
78
|
-
break;
|
|
79
|
-
}
|
|
80
|
-
data = remainder;
|
|
81
|
-
}
|
|
82
|
-
});
|
|
83
|
-
});
|
|
84
|
-
};
|
|
85
|
-
exports.loadFirefoxAddon = loadFirefoxAddon;
|
|
86
|
-
//# sourceMappingURL=load-firefox-addon.js.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"load-firefox-addon.js","sourceRoot":"","sources":["../../src/playwright/load-firefox-addon.ts"],"names":[],"mappings":"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"}
|
|
@@ -1,433 +0,0 @@
|
|
|
1
|
-
'use strict';
|
|
2
|
-
|
|
3
|
-
/* eslint-disable no-undef */
|
|
4
|
-
|
|
5
|
-
const isFirefox = navigator.userAgent.includes('Firefox');
|
|
6
|
-
|
|
7
|
-
const webRequestPermissions = {
|
|
8
|
-
blockingRequest: isFirefox ? ['blocking', 'requestHeaders'] : ['blocking', 'requestHeaders', 'extraHeaders'],
|
|
9
|
-
blockingResponse: isFirefox ? ['blocking', 'responseHeaders'] : ['blocking', 'responseHeaders', 'extraHeaders'],
|
|
10
|
-
};
|
|
11
|
-
|
|
12
|
-
chrome.privacy.network.networkPredictionEnabled.set({ value: false });
|
|
13
|
-
|
|
14
|
-
const translator = new Map();
|
|
15
|
-
const counter = new Map();
|
|
16
|
-
|
|
17
|
-
const getOpenerId = (id) => {
|
|
18
|
-
if (typeof id !== 'number' || !Number.isFinite(id)) {
|
|
19
|
-
throw new Error('Expected `id` to be a number');
|
|
20
|
-
}
|
|
21
|
-
|
|
22
|
-
if (translator.has(id)) {
|
|
23
|
-
const opener = translator.get(id);
|
|
24
|
-
|
|
25
|
-
if (translator.has(opener)) {
|
|
26
|
-
throw new Error('Opener is not the most ascendent');
|
|
27
|
-
}
|
|
28
|
-
|
|
29
|
-
// console.log(`getopener ${id} -> ${opener}`);
|
|
30
|
-
return opener;
|
|
31
|
-
}
|
|
32
|
-
|
|
33
|
-
return id;
|
|
34
|
-
};
|
|
35
|
-
|
|
36
|
-
const keyFromTabId = (tabId) => `.${tabId}.`;
|
|
37
|
-
|
|
38
|
-
const getCookieURL = (cookie) => {
|
|
39
|
-
const protocol = cookie.secure ? 'https:' : 'http:';
|
|
40
|
-
const fixedDomain = cookie.domain[0] === '.' ? cookie.domain.slice(1) : cookie.domain;
|
|
41
|
-
const url = `${protocol}//${fixedDomain}${cookie.path}`;
|
|
42
|
-
|
|
43
|
-
return url;
|
|
44
|
-
};
|
|
45
|
-
|
|
46
|
-
// Rewrite cookies that were programmatically set to tabId instead of openerId.
|
|
47
|
-
// This is required because we cannot reliably get openerId inside Playwright.
|
|
48
|
-
chrome.cookies.onChanged.addListener(async (changeInfo) => {
|
|
49
|
-
if (!changeInfo.removed) {
|
|
50
|
-
const { cookie } = changeInfo;
|
|
51
|
-
|
|
52
|
-
if (cookie.name[0] !== '.') {
|
|
53
|
-
return;
|
|
54
|
-
}
|
|
55
|
-
|
|
56
|
-
const dotIndex = cookie.name.indexOf('.', 1);
|
|
57
|
-
if (dotIndex === -1) {
|
|
58
|
-
return;
|
|
59
|
-
}
|
|
60
|
-
|
|
61
|
-
const tabId = Number(cookie.name.slice(1, dotIndex));
|
|
62
|
-
|
|
63
|
-
if (!Number.isFinite(tabId)) {
|
|
64
|
-
return;
|
|
65
|
-
}
|
|
66
|
-
|
|
67
|
-
const realCookieName = cookie.name.slice(dotIndex + 1);
|
|
68
|
-
const opener = getOpenerId(tabId);
|
|
69
|
-
|
|
70
|
-
if (tabId !== opener) {
|
|
71
|
-
console.log(`${realCookieName} -> ${keyFromTabId(opener)}`);
|
|
72
|
-
|
|
73
|
-
await chrome.cookies.remove({
|
|
74
|
-
name: cookie.name,
|
|
75
|
-
url: getCookieURL(cookie),
|
|
76
|
-
storeId: cookie.storeId,
|
|
77
|
-
});
|
|
78
|
-
|
|
79
|
-
delete cookie.hostOnly;
|
|
80
|
-
delete cookie.session;
|
|
81
|
-
|
|
82
|
-
await chrome.cookies.set({
|
|
83
|
-
...cookie,
|
|
84
|
-
name: `${keyFromTabId(opener)}${realCookieName}`,
|
|
85
|
-
url: getCookieURL(cookie),
|
|
86
|
-
});
|
|
87
|
-
}
|
|
88
|
-
}
|
|
89
|
-
});
|
|
90
|
-
|
|
91
|
-
chrome.webRequest.onBeforeSendHeaders.addListener(
|
|
92
|
-
(details) => {
|
|
93
|
-
for (const header of details.requestHeaders) {
|
|
94
|
-
if (header.name.toLowerCase() === 'cookie') {
|
|
95
|
-
const id = keyFromTabId(getOpenerId(details.tabId));
|
|
96
|
-
|
|
97
|
-
const fixedCookies = header.value
|
|
98
|
-
.split('; ')
|
|
99
|
-
.filter((x) => x.startsWith(id))
|
|
100
|
-
.map((x) => x.slice(id.length))
|
|
101
|
-
.join('; ');
|
|
102
|
-
header.value = fixedCookies;
|
|
103
|
-
}
|
|
104
|
-
|
|
105
|
-
// Sometimes Chrome makes a request on a ghost tab.
|
|
106
|
-
// We don't want these in order to prevent cluttering cookies.
|
|
107
|
-
// Yes, `webNavigation.onCommitted` is emitted and `webNavigation.onCreatedNavigationTarget` is not.
|
|
108
|
-
if (header.name.toLowerCase() === 'purpose' && header.value === 'prefetch' && !counter.has(details.tabId)) {
|
|
109
|
-
console.log(details);
|
|
110
|
-
return {
|
|
111
|
-
cancel: true,
|
|
112
|
-
};
|
|
113
|
-
}
|
|
114
|
-
|
|
115
|
-
// This one is for Firefox
|
|
116
|
-
if (header.name.toLowerCase() === 'x-moz' && header.value === 'prefetch' && !counter.has(details.tabId)) {
|
|
117
|
-
console.log(details);
|
|
118
|
-
return {
|
|
119
|
-
cancel: true,
|
|
120
|
-
};
|
|
121
|
-
}
|
|
122
|
-
|
|
123
|
-
if (['beacon', 'csp_report', 'ping', 'speculative'].includes(details.type)) {
|
|
124
|
-
console.log(details);
|
|
125
|
-
return {
|
|
126
|
-
cancel: true,
|
|
127
|
-
};
|
|
128
|
-
}
|
|
129
|
-
|
|
130
|
-
if (details.tabId === -1) {
|
|
131
|
-
console.log(details);
|
|
132
|
-
}
|
|
133
|
-
}
|
|
134
|
-
|
|
135
|
-
return {
|
|
136
|
-
requestHeaders: details.requestHeaders.filter(
|
|
137
|
-
(header) => header.name.toLowerCase() !== 'cookie' || header.value !== '',
|
|
138
|
-
),
|
|
139
|
-
};
|
|
140
|
-
},
|
|
141
|
-
{ urls: ['<all_urls>'] },
|
|
142
|
-
webRequestPermissions.blockingRequest,
|
|
143
|
-
);
|
|
144
|
-
|
|
145
|
-
// Firefox Bug: doesn't catch https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Content-Security-Policy/report-uri
|
|
146
|
-
chrome.webRequest.onHeadersReceived.addListener(
|
|
147
|
-
(details) => {
|
|
148
|
-
for (const header of details.responseHeaders) {
|
|
149
|
-
if (header.name.toLowerCase() === 'set-cookie') {
|
|
150
|
-
const parts = header.value.split('\n');
|
|
151
|
-
|
|
152
|
-
// `details.tabId` === -1 when Chrome is making internal requests, such downloading a service worker.
|
|
153
|
-
|
|
154
|
-
const openerId = getOpenerId(details.tabId);
|
|
155
|
-
|
|
156
|
-
header.value = parts
|
|
157
|
-
.map((part) => {
|
|
158
|
-
const equalsIndex = part.indexOf('=');
|
|
159
|
-
if (equalsIndex === -1) {
|
|
160
|
-
return `${keyFromTabId(openerId)}=${part.trimStart()}`;
|
|
161
|
-
}
|
|
162
|
-
return keyFromTabId(openerId) + part.trimStart();
|
|
163
|
-
})
|
|
164
|
-
.join('\n');
|
|
165
|
-
}
|
|
166
|
-
}
|
|
167
|
-
|
|
168
|
-
return {
|
|
169
|
-
responseHeaders: details.responseHeaders,
|
|
170
|
-
};
|
|
171
|
-
},
|
|
172
|
-
{ urls: ['<all_urls>'] },
|
|
173
|
-
webRequestPermissions.blockingResponse,
|
|
174
|
-
);
|
|
175
|
-
|
|
176
|
-
chrome.tabs.onRemoved.addListener(async (tabId) => {
|
|
177
|
-
const opener = getOpenerId(tabId);
|
|
178
|
-
translator.delete(tabId);
|
|
179
|
-
|
|
180
|
-
if (counter.has(opener)) {
|
|
181
|
-
counter.set(opener, counter.get(opener) - 1);
|
|
182
|
-
|
|
183
|
-
if (counter.get(opener) < 1) {
|
|
184
|
-
counter.delete(opener);
|
|
185
|
-
} else {
|
|
186
|
-
return;
|
|
187
|
-
}
|
|
188
|
-
}
|
|
189
|
-
|
|
190
|
-
const id = keyFromTabId(opener);
|
|
191
|
-
|
|
192
|
-
chrome.cookies.getAll({}, async (cookies) => {
|
|
193
|
-
await Promise.allSettled(
|
|
194
|
-
cookies
|
|
195
|
-
.filter((cookie) => cookie.name.startsWith(id))
|
|
196
|
-
.map((cookie) => {
|
|
197
|
-
return chrome.cookies.remove({
|
|
198
|
-
name: cookie.name,
|
|
199
|
-
url: getCookieURL(cookie),
|
|
200
|
-
storeId: cookie.storeId,
|
|
201
|
-
});
|
|
202
|
-
}),
|
|
203
|
-
);
|
|
204
|
-
});
|
|
205
|
-
});
|
|
206
|
-
|
|
207
|
-
// Proxy per tab
|
|
208
|
-
const getProxyConfiguration = (scheme, host, port) => {
|
|
209
|
-
return {
|
|
210
|
-
mode: 'fixed_servers',
|
|
211
|
-
rules: {
|
|
212
|
-
proxyForHttp: {
|
|
213
|
-
scheme,
|
|
214
|
-
host,
|
|
215
|
-
port,
|
|
216
|
-
},
|
|
217
|
-
proxyForHttps: {
|
|
218
|
-
scheme,
|
|
219
|
-
host,
|
|
220
|
-
port,
|
|
221
|
-
},
|
|
222
|
-
},
|
|
223
|
-
};
|
|
224
|
-
};
|
|
225
|
-
|
|
226
|
-
const localhostIpCache = new Map();
|
|
227
|
-
const localHostIp = [127, 0, 0, 1];
|
|
228
|
-
const getNextLocalhostIp = (openerId) => {
|
|
229
|
-
if (localhostIpCache.has(openerId)) {
|
|
230
|
-
return localhostIpCache.get(openerId);
|
|
231
|
-
}
|
|
232
|
-
|
|
233
|
-
const result = localHostIp.join('.');
|
|
234
|
-
|
|
235
|
-
localhostIpCache.set(openerId, result);
|
|
236
|
-
|
|
237
|
-
if (localHostIp[3] === 254) {
|
|
238
|
-
if (localHostIp[2] === 255) {
|
|
239
|
-
if (localHostIp[1] === 255) {
|
|
240
|
-
localHostIp[1] = 0;
|
|
241
|
-
} else {
|
|
242
|
-
localHostIp[1]++;
|
|
243
|
-
}
|
|
244
|
-
|
|
245
|
-
localHostIp[2] = 0;
|
|
246
|
-
} else {
|
|
247
|
-
localHostIp[2]++;
|
|
248
|
-
}
|
|
249
|
-
|
|
250
|
-
localHostIp[3] = 1;
|
|
251
|
-
} else {
|
|
252
|
-
localHostIp[3]++;
|
|
253
|
-
}
|
|
254
|
-
|
|
255
|
-
// [127.0.0.1 - 127.255.255.254] = 1 * 255 * 255 * 254 = 16 516 350
|
|
256
|
-
while (localhostIpCache.length >= 1 * 255 * 255 * 254) {
|
|
257
|
-
localhostIpCache.delete(localhostIpCache.keys().next().value);
|
|
258
|
-
}
|
|
259
|
-
|
|
260
|
-
return result;
|
|
261
|
-
};
|
|
262
|
-
|
|
263
|
-
let proxyPort;
|
|
264
|
-
|
|
265
|
-
// Clear extension's proxy settings on reload
|
|
266
|
-
if (isFirefox) {
|
|
267
|
-
browser.proxy.settings.clear({});
|
|
268
|
-
} else {
|
|
269
|
-
chrome.proxy.settings.clear({});
|
|
270
|
-
}
|
|
271
|
-
|
|
272
|
-
// Proxy per tab
|
|
273
|
-
if (isFirefox) {
|
|
274
|
-
// On Firefox, we could use the `dns` permission to enforce DoH
|
|
275
|
-
// but then the extension would not be compatible with Chrome.
|
|
276
|
-
// Therefore users need to manually set the DNS settings.
|
|
277
|
-
|
|
278
|
-
browser.proxy.onRequest.addListener(
|
|
279
|
-
(details) => {
|
|
280
|
-
const openerId = getOpenerId(details.tabId);
|
|
281
|
-
|
|
282
|
-
if (typeof proxyPort === 'number') {
|
|
283
|
-
return {
|
|
284
|
-
type: 'http',
|
|
285
|
-
host: getNextLocalhostIp(openerId),
|
|
286
|
-
port: proxyPort,
|
|
287
|
-
};
|
|
288
|
-
}
|
|
289
|
-
return {
|
|
290
|
-
type: 'direct',
|
|
291
|
-
};
|
|
292
|
-
},
|
|
293
|
-
{ urls: ['<all_urls>'] },
|
|
294
|
-
);
|
|
295
|
-
} else {
|
|
296
|
-
// The connection is not yet created with `onBeforeSendHeaders`, but is with `onSendHeaders`.
|
|
297
|
-
chrome.webRequest.onBeforeSendHeaders.addListener(
|
|
298
|
-
(details) => {
|
|
299
|
-
const openerId = getOpenerId(details.tabId);
|
|
300
|
-
|
|
301
|
-
if (typeof proxyPort === 'number') {
|
|
302
|
-
chrome.proxy.settings.set({
|
|
303
|
-
value: getProxyConfiguration('http', getNextLocalhostIp(openerId), proxyPort),
|
|
304
|
-
scope: 'regular',
|
|
305
|
-
});
|
|
306
|
-
} else {
|
|
307
|
-
chrome.proxy.settings.clear({});
|
|
308
|
-
}
|
|
309
|
-
},
|
|
310
|
-
{ urls: ['<all_urls>'] },
|
|
311
|
-
webRequestPermissions.blockingRequest,
|
|
312
|
-
);
|
|
313
|
-
}
|
|
314
|
-
|
|
315
|
-
// External communication. Note: the JSON keys are lowercased by the browser.
|
|
316
|
-
const routes = Object.assign(Object.create(null), {
|
|
317
|
-
async tabid(details) {
|
|
318
|
-
return { tabid: details.tabId, proxyip: getNextLocalhostIp(details.tabId) };
|
|
319
|
-
},
|
|
320
|
-
async proxy(details, body) {
|
|
321
|
-
proxyPort = body.port;
|
|
322
|
-
|
|
323
|
-
return '';
|
|
324
|
-
},
|
|
325
|
-
});
|
|
326
|
-
|
|
327
|
-
const onCompleted = async (details) => {
|
|
328
|
-
const textPlain = 'data:text/plain,';
|
|
329
|
-
|
|
330
|
-
if (details.frameId === 0 && details.url.startsWith(textPlain)) {
|
|
331
|
-
try {
|
|
332
|
-
const url = new URL(details.url);
|
|
333
|
-
const route = url.pathname.slice('text/plain,'.length);
|
|
334
|
-
|
|
335
|
-
if (route in routes) {
|
|
336
|
-
const hash = url.hash.slice(1);
|
|
337
|
-
|
|
338
|
-
let body = {};
|
|
339
|
-
|
|
340
|
-
if (hash !== '') {
|
|
341
|
-
try {
|
|
342
|
-
body = JSON.parse(decodeURIComponent(hash));
|
|
343
|
-
} catch {
|
|
344
|
-
// Empty on purpose.
|
|
345
|
-
}
|
|
346
|
-
}
|
|
347
|
-
|
|
348
|
-
// Different protocols are required, otherwise `onCompleted` won't be emitted.
|
|
349
|
-
const result = await routes[route](details, body);
|
|
350
|
-
if (result !== undefined) {
|
|
351
|
-
await chrome.tabs.update(details.tabId, {
|
|
352
|
-
url: `about:blank#${encodeURIComponent(JSON.stringify(result))}`,
|
|
353
|
-
});
|
|
354
|
-
}
|
|
355
|
-
}
|
|
356
|
-
} catch {
|
|
357
|
-
// Invalid URL, ignore.
|
|
358
|
-
}
|
|
359
|
-
}
|
|
360
|
-
};
|
|
361
|
-
|
|
362
|
-
chrome.webNavigation.onCompleted.addListener(onCompleted);
|
|
363
|
-
|
|
364
|
-
// Load content scripts.
|
|
365
|
-
void (async () => {
|
|
366
|
-
const contentResponse = await fetch(chrome.runtime.getURL('content.js'));
|
|
367
|
-
const contentText = await contentResponse.text();
|
|
368
|
-
|
|
369
|
-
// `tabs.onCreated` doesn't work here when manually creating new tabs,
|
|
370
|
-
// because the opener is the current tab active.
|
|
371
|
-
//
|
|
372
|
-
// This events only fires when the page opens something.
|
|
373
|
-
chrome.webNavigation.onCreatedNavigationTarget.addListener((details) => {
|
|
374
|
-
translator.set(details.tabId, getOpenerId(details.sourceTabId));
|
|
375
|
-
|
|
376
|
-
const opener = getOpenerId(details.tabId);
|
|
377
|
-
|
|
378
|
-
if (counter.has(opener)) {
|
|
379
|
-
counter.set(opener, counter.get(opener) + 1);
|
|
380
|
-
} else {
|
|
381
|
-
counter.set(opener, 2); // the current one + opener = 2
|
|
382
|
-
}
|
|
383
|
-
});
|
|
384
|
-
|
|
385
|
-
chrome.webNavigation.onCommitted.addListener(async (details) => {
|
|
386
|
-
if (details.url.startsWith('chrome')) {
|
|
387
|
-
return;
|
|
388
|
-
}
|
|
389
|
-
|
|
390
|
-
const executeCodeInPageContext = `
|
|
391
|
-
const script = document.createElement('script');
|
|
392
|
-
script.textContent = code;
|
|
393
|
-
|
|
394
|
-
const destination = document.head ?? document.documentElement;
|
|
395
|
-
|
|
396
|
-
if (document instanceof HTMLDocument) {
|
|
397
|
-
destination.append(script);
|
|
398
|
-
script.remove();
|
|
399
|
-
}
|
|
400
|
-
`;
|
|
401
|
-
|
|
402
|
-
// Race condition: website scripts may run first
|
|
403
|
-
await chrome.tabs.executeScript(details.tabId, {
|
|
404
|
-
code: `'use strict';
|
|
405
|
-
(() => {
|
|
406
|
-
if (window.totallyRandomString) {
|
|
407
|
-
return;
|
|
408
|
-
}
|
|
409
|
-
|
|
410
|
-
window.totallyRandomString = true;
|
|
411
|
-
|
|
412
|
-
const code = "'use strict'; const tabId = '${getOpenerId(
|
|
413
|
-
details.tabId,
|
|
414
|
-
)}'; (() => {\\n" + ${JSON.stringify(contentText)} + "\\n})();\\n";
|
|
415
|
-
${executeCodeInPageContext}
|
|
416
|
-
})();
|
|
417
|
-
`,
|
|
418
|
-
matchAboutBlank: true,
|
|
419
|
-
allFrames: true,
|
|
420
|
-
runAt: 'document_start',
|
|
421
|
-
});
|
|
422
|
-
});
|
|
423
|
-
|
|
424
|
-
chrome.tabs.query({}, async (tabs) => {
|
|
425
|
-
for (const tab of tabs) {
|
|
426
|
-
await onCompleted({
|
|
427
|
-
frameId: 0,
|
|
428
|
-
url: tab.url,
|
|
429
|
-
tabId: tab.id,
|
|
430
|
-
});
|
|
431
|
-
}
|
|
432
|
-
});
|
|
433
|
-
})();
|