code review for #3474, #2823: simplify management of "web accessible resources"

This commit is contained in:
Raymond Hill 2018-02-16 09:07:20 -05:00
parent 47152560af
commit 287f04b47e
No known key found for this signature in database
GPG key ID: 25E1490B761470C2
5 changed files with 68 additions and 71 deletions

View file

@ -29,78 +29,44 @@
/******************************************************************************/
var warResolve = (function() {
var timer;
var toResolve = new Set();
var toProcess = new Set();
var reMimeParser = /^[^/]+\/([^\s;]+)/;
var warPairs = [];
var replacer = function(s) {
if ( s === '+' ) { return '-'; }
if ( s === '/' ) { return '_'; }
if ( s === '=' ) { return ''; }
return s;
};
var filenameFromToken = function(token, mime) {
var name = btoa(token).replace(/[+/=]/g, replacer);
var match = reMimeParser.exec(mime);
if ( match !== null ) {
name += '.' + match[1];
}
return name;
};
var onResolved = function(success, token, url) {
var onPairsReady = function() {
var reng = µBlock.redirectEngine;
this.onload = this.onerror = null;
var resource = reng.resources.get(token);
if ( resource !== undefined && success ) {
resource.warURL = url;
}
toProcess.delete(token);
if ( toResolve.size === 0 && toProcess.size === 0 ) {
reng.selfieFromResources();
}
};
var resolvePending = function() {
timer = undefined;
var reng = µBlock.redirectEngine,
resources = reng.resources,
n = 8; // max number of xhr at once
for ( var token of toResolve ) {
var resource = resources.get(token);
toResolve.delete(token);
for ( var i = 0; i < warPairs.length; i += 2 ) {
var resource = reng.resources.get(warPairs[i+0]);
if ( resource === undefined ) { continue; }
toProcess.add(token);
var url = vAPI.getURL(
'/web_accessible_resources/' +
filenameFromToken(token, resource.mime)
resource.warURL = vAPI.getURL(
'/web_accessible_resources/' + warPairs[i+1]
);
var xhr = new XMLHttpRequest();
xhr.timeout = 1000;
xhr.open('head', url + '?secret=' + vAPI.warSecret);
xhr.onload = onResolved.bind(this, true, token, url);
xhr.onerror = onResolved.bind(this, false, token, url);
xhr.responseType = 'text';
xhr.send();
n -= 1;
if ( n === 0 ) { break; }
}
if ( toResolve.size !== 0 ) {
timer = vAPI.setTimeout(resolvePending, 5);
} else if ( toProcess.size === 0 ) {
reng.selfieFromResources();
}
reng.selfieFromResources();
};
return function(token) {
if ( vAPI.warSecret !== undefined ) {
toResolve.add(token);
}
if ( timer === undefined ) {
timer = vAPI.setTimeout(resolvePending, 1);
return function() {
if ( vAPI.warSecret === undefined || warPairs.length !== 0 ) {
return onPairsReady();
}
var onPairsLoaded = function(details) {
var marker = '>>>>>';
var pos = details.content.indexOf(marker);
if ( pos === -1 ) { return; }
var pairs = details.content.slice(pos + marker.length)
.trim()
.split('\n');
if ( (pairs.length & 1) !== 0 ) { return; }
for ( var i = 0; i < pairs.length; i++ ) {
pairs[i] = pairs[i].trim();
}
warPairs = pairs;
onPairsReady();
};
µBlock.assets.fetchText(
'/web_accessible_resources/imported.txt?secret=' + vAPI.warSecret,
onPairsLoaded
);
};
})();
@ -500,7 +466,6 @@ RedirectEngine.prototype.resourcesFromString = function(text) {
// No more data, add the resource.
this.resources.set(fields[0], RedirectEntry.fromFields(fields[1], fields.slice(2)));
warResolve(fields[0]);
fields = undefined;
}
@ -508,13 +473,14 @@ RedirectEngine.prototype.resourcesFromString = function(text) {
// Process pending resource data.
if ( fields !== undefined ) {
this.resources.set(fields[0], RedirectEntry.fromFields(fields[1], fields.slice(2)));
warResolve(fields[0]);
}
warResolve();
};
/******************************************************************************/
var resourcesSelfieVersion = 1;
var resourcesSelfieVersion = 2;
RedirectEngine.prototype.selfieFromResources = function() {
vAPI.cacheStorage.set({

View file

@ -0,0 +1,11 @@
IMPORTANT
Content of this folder cannot be accessed without the internal secret token
created each time uBlock Origin launched.
Any fetch operation made without uBlock Origin's internal secret will result
in failure. This means that despite the content of the folder here declared as
"web accessible resources", it still cannot be seen by the outside world.
Only uBlock Origin knows the secret token at runtime and hence only
uBlock Origin can see the content of this folder.

View file

@ -0,0 +1,7 @@
# List of resources imported as "web accessible resources".
#
# To ensure valid filename characters on any platform OS, the filenames are
# constructed using the md5 hash of the respective tokens.
#
# DO NOT REMOVE THIS LINE >>>>>

View file

@ -11,9 +11,8 @@
# page to use one of these "web accessible resource" to directly
# detect the presence of uBO.
#
# To ensure valid filename on any platform OS, the resource tokens are
# converted to base64 (https://tools.ietf.org/html/rfc7515#appendix-C),
# and the result is used as filename.
# To ensure valid filename characters on any platform OS, the filenames are
# constructed using the md5 hash of the respective tokens.
#
# In case uBO redirects to a resource which has not been converted into
# a "web accessible resource", the redirection code will fall back to

View file

@ -1,6 +1,7 @@
#!/usr/bin/env python3
import base64
import hashlib
import os
import re
import sys
@ -19,6 +20,8 @@ with open('./src/web_accessible_resources/to-import.txt', 'r') as f:
if len(line) != 0 and line[0] != '#':
to_import.add(line)
imported = []
# scan the file until a resource to import is found
def find_next_resource(f):
for line in f:
@ -31,7 +34,9 @@ def find_next_resource(f):
return ('', '')
def safe_filename_from_token(token, mime):
name = str(base64.b64encode(bytes(token, 'utf-8'), b'-_'), 'utf-8').strip('=')
h = hashlib.md5()
h.update(bytes(token, 'utf-8'))
name = h.hexdigest()
# extract file extension from mime
match = re.search('^[^/]+/([^\s;]+)', mime)
if match:
@ -58,6 +63,7 @@ def import_resource(f, token, mime):
filedata = bytes(filedata, 'utf-8')
with open(filepath, 'wb') as fo:
fo.write(filedata)
imported.append(token + '\n\t' + filename)
# Read content of the resources to convert
# - At this point, it is assumed resources.txt has been imported into the
@ -70,3 +76,11 @@ with open(resources_filename, 'r') as f:
break
import_resource(f, token, mime)
# Output associations
content = ''
with open('./src/web_accessible_resources/imported.txt', 'r') as f:
content = f.read() + '\n'.join(imported)
filename = os.path.join(build_dir, 'web_accessible_resources/imported.txt')
with open(filename, 'w') as f:
f.write(content)