Add support for using declarativeNetRequest (#1127)

This commit is contained in:
toasted-nutbread 2020-12-18 17:18:00 -05:00 committed by GitHub
parent 05d4049f16
commit 2fa9b91515
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
3 changed files with 137 additions and 1 deletions

View File

@ -154,8 +154,10 @@
{"action": "move", "path": ["content_security_policy_old"], "newPath": ["content_security_policy", "extension_pages"]},
{"action": "move", "path": ["sandbox", "content_security_policy"], "newPath": ["content_security_policy", "sandbox"]},
{"action": "remove", "path": ["permissions"], "item": "<all_urls>"},
{"action": "remove", "path": ["permissions"], "item": "webRequest"},
{"action": "remove", "path": ["permissions"], "item": "webRequestBlocking"},
{"action": "add", "path": ["permissions"], "items": ["declarativeNetRequest", "scripting"]},
{"action": "set", "path": ["host_permissions"], "value": ["<all_urls>"], "after": "optional_permissions"},
{"action": "add", "path": ["permissions"], "items": ["scripting"]},
{"action": "move", "path": ["web_accessible_resources"], "newPath": ["web_accessible_resources_old"]},
{"action": "set", "path": ["web_accessible_resources"], "value": [{"resources": [], "matches": ["<all_urls>"]}], "after": "web_accessible_resources_old"},
{"action": "move", "path": ["web_accessible_resources_old"], "newPath": ["web_accessible_resources", 0, "resources"]}

View File

@ -187,6 +187,7 @@ class Backend {
yomichan.on('log', this._onLog.bind(this));
await this._requestBuilder.prepare();
await this._environment.prepare();
this._clipboardReader.browser = this._environment.getInfo().browser;

View File

@ -19,9 +19,22 @@ class RequestBuilder {
constructor() {
this._extraHeadersSupported = null;
this._onBeforeSendHeadersExtraInfoSpec = ['blocking', 'requestHeaders', 'extraHeaders'];
this._textEncoder = new TextEncoder();
this._ruleIds = new Set();
}
async prepare() {
try {
await this._clearDynamicRules();
} catch (e) {
// NOP
}
}
async fetchAnonymous(url, init) {
if (isObject(chrome.declarativeNetRequest)) {
return await this._fetchAnonymousDeclarative(url, init);
}
const originURL = this._getOriginURL(url);
const modifications = [
['cookie', null],
@ -130,4 +143,124 @@ class RequestBuilder {
}
}
}
async _clearDynamicRules() {
if (!isObject(chrome.declarativeNetRequest)) { return; }
const rules = this._getDynamicRules();
if (rules.length === 0) { return; }
const removeRuleIds = [];
for (const {id} of rules) {
removeRuleIds.push(id);
}
await this._updateDynamicRules({removeRuleIds});
}
async _fetchAnonymousDeclarative(url, init) {
const id = this._getNewRuleId();
const originUrl = this._getOriginURL(url);
url = encodeURI(decodeURI(url));
this._ruleIds.add(id);
try {
const addRules = [{
id,
priority: 1,
condition: {
urlFilter: `|${this._escapeDnrUrl(url)}|`,
resourceTypes: ['xmlhttprequest']
},
action: {
type: 'modifyHeaders',
requestHeaders: [
{
operation: 'remove',
header: 'Cookie'
},
{
operation: 'set',
header: 'Origin',
value: originUrl
}
],
responseHeaders: [
{
operation: 'remove',
header: 'Set-Cookie'
}
]
}
}];
await this._updateDynamicRules({addRules});
try {
return await fetch(url, init);
} finally {
await this._tryUpdateDynamicRules({removeRuleIds: [id]});
}
} finally {
this._ruleIds.delete(id);
}
}
_getDynamicRules() {
return new Promise((resolve, reject) => {
chrome.declarativeNetRequest.getDynamicRules((result) => {
const e = chrome.runtime.lastError;
if (e) {
reject(new Error(e.message));
} else {
resolve(result);
}
});
});
}
_updateDynamicRules(options) {
return new Promise((resolve, reject) => {
chrome.declarativeNetRequest.updateDynamicRules(options, () => {
const e = chrome.runtime.lastError;
if (e) {
reject(new Error(e.message));
} else {
resolve();
}
});
});
}
async _tryUpdateDynamicRules(options) {
try {
await this._updateDynamicRules(options);
return true;
} catch (e) {
return false;
}
}
_getNewRuleId() {
let id = 1;
while (this._ruleIds.has(id)) {
const pre = id;
++id;
if (id === pre) { throw new Error('Could not generate an id'); }
}
return id;
}
_escapeDnrUrl(url) {
return url.replace(/[|*^]/g, (char) => this._urlEncodeUtf8(char));
}
_urlEncodeUtf8(text) {
const array = this._textEncoder.encode(text);
let result = '';
for (const byte of array) {
result += `%${byte.toString(16).toUpperCase().padStart(2, '0')}`;
}
return result;
}
}