Browse Source

removing unsupported firefox/legacy platform

pull/2/head
Raymond Hill 6 years ago
parent
commit
a0c72fc302
No known key found for this signature in database GPG Key ID: 25E1490B761470C2
  1. 245
      platform/firefox/bootstrap.js
  2. 1
      platform/firefox/chrome.manifest
  3. 46
      platform/firefox/css/legacy-toolbar-button.css
  4. 356
      platform/firefox/frameModule.js
  5. 72
      platform/firefox/frameScript.js
  6. BIN
      platform/firefox/img/browsericons/icon19-19.png
  7. BIN
      platform/firefox/img/browsericons/icon19-off.png
  8. 45
      platform/firefox/install.rdf
  9. 9
      platform/firefox/options.xul
  10. 95
      platform/firefox/polyfill.js
  11. 3465
      platform/firefox/vapi-background.js
  12. 225
      platform/firefox/vapi-client.js
  13. 191
      platform/firefox/vapi-common.js
  14. 1
      platform/firefox/vapi-popup.js
  15. 120
      tools/make-firefox-meta.py
  16. 42
      tools/make-firefox.sh

245
platform/firefox/bootstrap.js

@ -1,245 +0,0 @@
/*******************************************************************************
uMatrix - a browser extension to block requests.
Copyright (C) 2014-2017 The uMatrix/uBlock Origin authors
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see {http://www.gnu.org/licenses/}.
Home: https://github.com/gorhill/uMatrix
*/
/* global ADDON_UNINSTALL, APP_SHUTDOWN */
/* exported startup, shutdown, install, uninstall */
'use strict';
/******************************************************************************/
const {classes: Cc, interfaces: Ci, utils: Cu} = Components;
// Accessing the context of the background page:
// var win = Services.appShell.hiddenDOMWindow.document.querySelector('iframe[src*=umatrix]').contentWindow;
let windowlessBrowser = null;
let windowlessBrowserPL = null;
let bgProcess = null;
let version;
const hostName = 'umatrix';
const restartListener = {
get messageManager() {
return Cc['@mozilla.org/parentprocessmessagemanager;1']
.getService(Ci.nsIMessageListenerManager);
},
receiveMessage: function() {
shutdown();
startup();
}
};
/******************************************************************************/
// https://github.com/gorhill/uBlock/issues/2493
// Fix by https://github.com/gijsk
// imported from https://github.com/gorhill/uBlock/pull/2497
function startup(data/*, reason*/) {
if ( data !== undefined ) {
version = data.version;
}
// Already started?
if ( bgProcess !== null ) {
return;
}
waitForHiddenWindow();
}
function createBgProcess(parentDocument) {
bgProcess = parentDocument.documentElement.appendChild(
parentDocument.createElementNS('http://www.w3.org/1999/xhtml', 'iframe')
);
bgProcess.setAttribute(
'src',
'chrome://' + hostName + '/content/background.html#' + version
);
// https://developer.mozilla.org/en-US/docs/Mozilla/Tech/XPCOM/Reference/Interface/nsIMessageListenerManager#addMessageListener%28%29
// "If the same listener registers twice for the same message, the
// "second registration is ignored."
restartListener.messageManager.addMessageListener(
hostName + '-restart',
restartListener
);
}
function getWindowlessBrowserFrame(appShell) {
windowlessBrowser = appShell.createWindowlessBrowser(true);
windowlessBrowser.QueryInterface(Ci.nsIInterfaceRequestor);
let webProgress = windowlessBrowser.getInterface(Ci.nsIWebProgress);
let XPCOMUtils = Cu.import('resource://gre/modules/XPCOMUtils.jsm', null).XPCOMUtils;
windowlessBrowserPL = {
QueryInterface: XPCOMUtils.generateQI([
Ci.nsIWebProgressListener,
Ci.nsIWebProgressListener2,
Ci.nsISupportsWeakReference
]),
onStateChange: function(wbp, request, stateFlags, status) {
if ( !request ) { return; }
if ( stateFlags & Ci.nsIWebProgressListener.STATE_STOP ) {
webProgress.removeProgressListener(windowlessBrowserPL);
windowlessBrowserPL = null;
createBgProcess(windowlessBrowser.document);
}
}
};
webProgress.addProgressListener(windowlessBrowserPL, Ci.nsIWebProgress.NOTIFY_STATE_DOCUMENT);
windowlessBrowser.document.location = "data:application/vnd.mozilla.xul+xml;charset=utf-8,<window%20id='" + hostName + "-win'/>";
}
function waitForHiddenWindow() {
let appShell = Cc['@mozilla.org/appshell/appShellService;1']
.getService(Ci.nsIAppShellService);
let isReady = function() {
var hiddenDoc;
try {
hiddenDoc = appShell.hiddenDOMWindow &&
appShell.hiddenDOMWindow.document;
} catch (ex) {
}
// Do not test against `loading`: it does appear `readyState` could be
// undefined if looked up too early.
if ( !hiddenDoc || hiddenDoc.readyState !== 'complete' ) {
return false;
}
// In theory, it should be possible to create a windowless browser
// immediately, without waiting for the hidden window to have loaded
// completely. However, in practice, on Windows this seems to lead
// to a broken Firefox appearance. To avoid this, we only create the
// windowless browser here. We'll use that rather than the hidden
// window for the actual background page (windowless browsers are
// also what the webextension implementation in Firefox uses for
// background pages).
let { Services } = Cu.import('resource://gre/modules/Services.jsm', null);
if ( Services.vc.compare(Services.appinfo.platformVersion, '27') >= 0 ) {
getWindowlessBrowserFrame(appShell);
} else {
createBgProcess(hiddenDoc);
}
return true;
};
if ( isReady() ) {
return;
}
// https://github.com/gorhill/uBlock/issues/749
// Poll until the proper environment is set up -- or give up eventually.
// We poll frequently early on but relax poll delay as time pass.
let tryDelay = 5;
let trySum = 0;
// https://trac.torproject.org/projects/tor/ticket/19438
// Try for a longer period.
let tryMax = 600011;
let timer = Cc['@mozilla.org/timer;1']
.createInstance(Ci.nsITimer);
let checkLater = function() {
trySum += tryDelay;
if ( trySum >= tryMax ) {
timer = null;
return;
}
timer.init(timerObserver, tryDelay, timer.TYPE_ONE_SHOT);
tryDelay *= 2;
if ( tryDelay > 503 ) {
tryDelay = 503;
}
};
var timerObserver = {
observe: function() {
timer.cancel();
if ( isReady() ) {
timer = null;
} else {
checkLater();
}
}
};
checkLater();
}
/******************************************************************************/
function shutdown(data, reason) {
if ( reason === APP_SHUTDOWN ) {
return;
}
if ( bgProcess !== null ) {
bgProcess.parentNode.removeChild(bgProcess);
bgProcess = null;
}
if ( windowlessBrowser !== null ) {
// close() does not exist for older versions of Firefox.
if ( typeof windowlessBrowser.close === 'function' ) {
windowlessBrowser.close();
}
windowlessBrowser = null;
windowlessBrowserPL = null;
}
if ( data === undefined ) {
return;
}
// Remove the restartObserver only when the extension is being disabled
restartListener.messageManager.removeMessageListener(
hostName + '-restart',
restartListener
);
}
/******************************************************************************/
function install() {
// https://bugzil.la/719376
Cc['@mozilla.org/intl/stringbundle;1']
.getService(Ci.nsIStringBundleService)
.flushBundles();
}
/******************************************************************************/
function uninstall(data, aReason) {
if ( aReason !== ADDON_UNINSTALL ) {
return;
}
// To cleanup vAPI.localStorage in vapi-common.js, aka
// "extensions.umatrix.*" in `about:config`.
Cu.import('resource://gre/modules/Services.jsm', null)
.Services.prefs.getBranch('extensions.' + hostName + '.')
.deleteBranch('');
}
/******************************************************************************/

1
platform/firefox/chrome.manifest

@ -1 +0,0 @@
content umatrix ./

46
platform/firefox/css/legacy-toolbar-button.css

@ -1,46 +0,0 @@
#umatrix-legacy-button {
list-style-image: url('../img/browsericons/icon19-19.png');
}
#umatrix-legacy-button.off {
list-style-image: url('../img/browsericons/icon19-off.png');
}
toolbar[iconsize="small"] #umatrix-legacy-button {
list-style-image: url('../img/browsericons/icon19-19.png');
}
toolbar[iconsize="small"] #umatrix-legacy-button.off {
list-style-image: url('../img/browsericons/icon19-off.png');
}
#umatrix-legacy-button[badge]::before {
background: #000;
color: #fff;
content: attr(badge);
font: bold 10px sans-serif;
margin-top: -2px;
padding: 0 2px;
position: fixed;
}
/* This hack required because if the before content changes it de-pops the
popup (without firing any events). So just hide it instead. Note, can't
actually *hide* it, or the same thing happens.
**/
#umatrix-legacy-button[badge=""]::before {
padding: 0;
}
/* Override off state when in palette */
toolbarpaletteitem #umatrix-legacy-button.off {
list-style-image: url('../img/browsericons/icon19-12.png');
}
/* Override badge when in palette */
toolbarpaletteitem #umatrix-legacy-button[badge]::before {
content: none;
}
/* Prevent pale moon from showing the arrow underneath the button */
/* https://github.com/chrisaljoudi/uBlock/issues/1449#issuecomment-112112761 */
#umatrix-legacy-button .toolbarbutton-menu-dropmarker {
display: none;
-moz-box-orient: horizontal;
}

356
platform/firefox/frameModule.js

@ -1,356 +0,0 @@
/*******************************************************************************
µBlock - a browser extension to block requests.
Copyright (C) 2014 The µBlock authors
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see {http://www.gnu.org/licenses/}.
Home: https://github.com/gorhill/uMatrix
*/
/* global Components */
'use strict';
/******************************************************************************/
// https://github.com/gorhill/uBlock/issues/800#issuecomment-146580443
this.EXPORTED_SYMBOLS = ['contentObserver', 'LocationChangeListener'];
const {interfaces: Ci, utils: Cu} = Components;
const {Services} = Cu.import('resource://gre/modules/Services.jsm', null);
const {XPCOMUtils} = Cu.import('resource://gre/modules/XPCOMUtils.jsm', null);
const hostName = Services.io.newURI(Components.stack.filename, null, null).host;
// Cu.import('resource://gre/modules/Console.jsm');
/******************************************************************************/
const getMessageManager = function(win) {
let iface = win
.QueryInterface(Ci.nsIInterfaceRequestor)
.getInterface(Ci.nsIDocShell)
.sameTypeRootTreeItem
.QueryInterface(Ci.nsIDocShell)
.QueryInterface(Ci.nsIInterfaceRequestor);
try {
return iface.getInterface(Ci.nsIContentFrameMessageManager);
} catch (ex) {
// This can throw. It appears `shouldLoad` can be called *after* a
// tab has been closed. For example, a case where this happens all
// the time (FF38):
// - Open twitter.com (assuming you have an account and are logged in)
// - Close twitter.com
// There will be an exception raised when `shouldLoad` is called
// to process a XMLHttpRequest with URL `https://twitter.com/i/jot`
// fired from `https://twitter.com/`, *after* the tab is closed.
// In such case, `win` is `about:blank`.
}
return null;
};
/******************************************************************************/
var contentObserver = {
classDescription: 'content-policy for ' + hostName,
classID: Components.ID('{c84283d4-9975-41b7-b1a4-f106af56b51d}'),
contractID: '@' + hostName + '/content-policy;1',
ACCEPT: Ci.nsIContentPolicy.ACCEPT,
MAIN_FRAME: Ci.nsIContentPolicy.TYPE_DOCUMENT,
contentBaseURI: 'chrome://' + hostName + '/content/js/',
cpMessageName: hostName + ':shouldLoad',
uniqueSandboxId: 1,
modernFirefox:
Services.vc.compare(Services.appinfo.platformVersion, '44') > 0 && (
Services.appinfo.ID === '{92650c4d-4b8e-4d2a-b7eb-24ecf4f6b63a}' ||
Services.appinfo.ID === '{ec8030f7-c20a-464f-9b0e-13a3a9e97384}'
),
get componentRegistrar() {
return Components.manager.QueryInterface(Ci.nsIComponentRegistrar);
},
get categoryManager() {
return Components.classes['@mozilla.org/categorymanager;1']
.getService(Ci.nsICategoryManager);
},
QueryInterface: XPCOMUtils.generateQI([
Ci.nsIFactory,
Ci.nsIObserver,
Ci.nsIContentPolicy,
Ci.nsISupportsWeakReference
]),
createInstance: function(outer, iid) {
if ( outer ) {
throw Components.results.NS_ERROR_NO_AGGREGATION;
}
return this.QueryInterface(iid);
},
register: function() {
Services.obs.addObserver(this, 'document-element-inserted', true);
if ( !this.modernFirefox ) {
this.componentRegistrar.registerFactory(
this.classID,
this.classDescription,
this.contractID,
this
);
this.categoryManager.addCategoryEntry(
'content-policy',
this.contractID,
this.contractID,
false,
true
);
}
},
unregister: function() {
Services.obs.removeObserver(this, 'document-element-inserted');
if ( !this.modernFirefox ) {
this.componentRegistrar.unregisterFactory(
this.classID,
this
);
this.categoryManager.deleteCategoryEntry(
'content-policy',
this.contractID,
false
);
}
},
// https://developer.mozilla.org/en-US/docs/Mozilla/Tech/XPCOM/Reference/Interface/nsIContentPolicy
// https://bugzil.la/612921
shouldLoad: function(type, location, origin, context) {
if ( Services === undefined || !context ) {
return this.ACCEPT;
}
if ( !location.schemeIs('http') && !location.schemeIs('https') ) {
return this.ACCEPT;
}
var contextWindow;
if ( type === this.MAIN_FRAME ) {
contextWindow = context.contentWindow || context;
} else if ( type === this.SUB_FRAME ) {
contextWindow = context.contentWindow;
} else {
contextWindow = (context.ownerDocument || context).defaultView;
}
// https://github.com/gorhill/uMatrix/issues/706
if ( !contextWindow ) {
return this.ACCEPT;
}
// The context for the toolbar popup is an iframe element here,
// so check context.top instead of context
if ( !contextWindow.top || !contextWindow.location ) {
return this.ACCEPT;
}
let messageManager = getMessageManager(contextWindow);
if ( messageManager === null ) {
return this.ACCEPT;
}
let details = {
rawType: type,
url: location.asciiSpec
};
if ( typeof messageManager.sendRpcMessage === 'function' ) {
// https://bugzil.la/1092216
messageManager.sendRpcMessage(this.cpMessageName, details);
} else {
// Compatibility for older versions
messageManager.sendSyncMessage(this.cpMessageName, details);
}
return this.ACCEPT;
},
initContentScripts: function(win, sandbox) {
let messager = getMessageManager(win);
let sandboxId = hostName + ':sb:' + this.uniqueSandboxId++;
if ( sandbox ) {
let sandboxName = [
win.location.href.slice(0, 100),
win.document.title.slice(0, 100)
].join(' | ');
// https://github.com/gorhill/uMatrix/issues/325
// "Pass sameZoneAs to sandbox constructor to make GCs cheaper"
sandbox = Cu.Sandbox([win], {
sameZoneAs: win.top,
sandboxName: sandboxId + '[' + sandboxName + ']',
sandboxPrototype: win,
wantComponents: false,
wantXHRConstructor: false
});
sandbox.injectScript = function(script) {
Services.scriptloader.loadSubScript(script, sandbox);
};
}
else {
sandbox = win;
}
sandbox._sandboxId_ = sandboxId;
sandbox.sendAsyncMessage = messager.sendAsyncMessage;
sandbox.addMessageListener = function(callback) {
if ( sandbox._messageListener_ ) {
sandbox.removeMessageListener();
}
sandbox._messageListener_ = function(message) {
callback(message.data);
};
messager.addMessageListener(
sandbox._sandboxId_,
sandbox._messageListener_
);
messager.addMessageListener(
hostName + ':broadcast',
sandbox._messageListener_
);
};
sandbox.removeMessageListener = function() {
try {
messager.removeMessageListener(
sandbox._sandboxId_,
sandbox._messageListener_
);
messager.removeMessageListener(
hostName + ':broadcast',
sandbox._messageListener_
);
} catch (ex) {
// It throws sometimes, mostly when the popup closes
}
sandbox._messageListener_ = null;
};
return sandbox;
},
observe: function(doc) {
let win = doc.defaultView;
if ( !win ) {
return;
}
let loc = win.location;
if ( !loc ) {
return;
}
// https://github.com/gorhill/uBlock/issues/260
// TODO: We may have to skip more types, for now let's be
// conservative, i.e. let's not test against `text/html`.
if ( doc.contentType.lastIndexOf('image/', 0) === 0 ) {
return;
}
if ( loc.protocol !== 'http:' && loc.protocol !== 'https:' && loc.protocol !== 'file:' ) {
if ( loc.protocol === 'chrome:' && loc.host === hostName ) {
this.initContentScripts(win);
}
// What about data: and about:blank?
return;
}
let lss = Services.scriptloader.loadSubScript;
let sandbox = this.initContentScripts(win, true);
// Can throw with attempts at injecting into non-HTML document.
// Example: https://a.pomf.se/avonjf.webm
try {
lss(this.contentBaseURI + 'vapi-client.js', sandbox);
lss(this.contentBaseURI + 'contentscript-start.js', sandbox);
} catch (ex) {
return; // don't further try to inject anything
}
let docReady = (e) => {
let doc = e.target;
doc.removeEventListener(e.type, docReady, true);
lss(this.contentBaseURI + 'contentscript-end.js', sandbox);
};
if ( doc.readyState === 'loading') {
doc.addEventListener('DOMContentLoaded', docReady, true);
} else {
docReady({ target: doc, type: 'DOMContentLoaded' });
}
}
};
/******************************************************************************/
const locationChangedMessageName = hostName + ':locationChanged';
var LocationChangeListener = function(docShell) {
if ( !docShell ) {
return;
}
var requestor = docShell.QueryInterface(Ci.nsIInterfaceRequestor);
var ds = requestor.getInterface(Ci.nsIWebProgress);
var mm = requestor.getInterface(Ci.nsIContentFrameMessageManager);
if ( ds && mm && typeof mm.sendAsyncMessage === 'function' ) {
this.docShell = ds;
this.messageManager = mm;
ds.addProgressListener(this, Ci.nsIWebProgress.NOTIFY_LOCATION);
}
};
LocationChangeListener.prototype.QueryInterface = XPCOMUtils.generateQI([
'nsIWebProgressListener',
'nsISupportsWeakReference'
]);
LocationChangeListener.prototype.onLocationChange = function(webProgress, request, location, flags) {
if ( !webProgress.isTopLevel ) {
return;
}
this.messageManager.sendAsyncMessage(locationChangedMessageName, {
url: location.asciiSpec,
flags: flags,
});
};
/******************************************************************************/
contentObserver.register();
/******************************************************************************/

72
platform/firefox/frameScript.js

@ -1,72 +0,0 @@
/*******************************************************************************
µBlock - a browser extension to block requests.
Copyright (C) 2014 The µBlock authors
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see {http://www.gnu.org/licenses/}.
Home: https://github.com/gorhill/uMatrix
*/
/******************************************************************************/
var locationChangeListener; // Keep alive while frameScript is alive
(function() {
'use strict';
/******************************************************************************/
let {contentObserver, LocationChangeListener} = Components.utils.import(
Components.stack.filename.replace('Script', 'Module'),
null
);
let injectContentScripts = function(win) {
if ( !win || !win.document ) {
return;
}
contentObserver.observe(win.document);
if ( win.frames && win.frames.length ) {
let i = win.frames.length;
while ( i-- ) {
injectContentScripts(win.frames[i]);
}
}
};
let onLoadCompleted = function() {
removeMessageListener('umatrix-load-completed', onLoadCompleted);
injectContentScripts(content);
};
addMessageListener('umatrix-load-completed', onLoadCompleted);
if ( docShell ) {
let Ci = Components.interfaces;
let wp = docShell.QueryInterface(Ci.nsIInterfaceRequestor).getInterface(Ci.nsIWebProgress);
let dw = wp.DOMWindow;
if ( dw === dw.top ) {
locationChangeListener = new LocationChangeListener(docShell);
}
}
/******************************************************************************/
})();
/******************************************************************************/

BIN
platform/firefox/img/browsericons/icon19-19.png

Before

Width: 19  |  Height: 19  |  Size: 750 B

BIN
platform/firefox/img/browsericons/icon19-off.png

Before

Width: 19  |  Height: 19  |  Size: 777 B

45
platform/firefox/install.rdf

@ -1,45 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<r:RDF xmlns:r="http://www.w3.org/1999/02/22-rdf-syntax-ns#" xmlns="http://www.mozilla.org/2004/em-rdf#">
<r:Description about="urn:mozilla:install-manifest">
<id>uMatrix@raymondhill.net</id>
<version>{version}</version>
<name>{name}</name>
<description>{description}</description>
<homepageURL>{homepage}</homepageURL>
<creator>{author}</creator>
<developer>Deathamns</developer>
<developer>Alex Vallat</developer>
<type>2</type>
<bootstrap>true</bootstrap>
<multiprocessCompatible>true</multiprocessCompatible>
<optionsType>2</optionsType>
{localized}
<!-- Firefox -->
<targetApplication>
<r:Description>
<id>{{ec8030f7-c20a-464f-9b0e-13a3a9e97384}}</id>
<minVersion>24.0</minVersion>
<maxVersion>56.*</maxVersion>
</r:Description>
</targetApplication>
<!-- SeaMonkey -->
<targetApplication>
<r:Description>
<id>{{92650c4d-4b8e-4d2a-b7eb-24ecf4f6b63a}}</id>
<minVersion>2.24</minVersion>
<maxVersion>*</maxVersion>
</r:Description>
</targetApplication>
<!-- Pale Moon -->
<targetApplication>
<r:Description>
<id>{{8de7fcbb-c55c-4fbe-bfc5-fc555c87dbc4}}</id>
<minVersion>26.0</minVersion>
<maxVersion>27.*</maxVersion>
</r:Description>
</targetApplication>
</r:Description>
</r:RDF>

9
platform/firefox/options.xul

@ -1,9 +0,0 @@
<?xml version="1.0" ?>
<vbox xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul">
<setting type="control">
<vbox>
<button id="showDashboardButton"/>
<button id="showLoggerButton"/>
</vbox>
</setting>
</vbox>

95
platform/firefox/polyfill.js

@ -1,95 +0,0 @@
/*******************************************************************************
uMatrix - a browser extension to block requests.
Copyright (C) 2017 Raymond Hill
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see {http://www.gnu.org/licenses/}.
Home: https://github.com/gorhill/uMatrix
This file has been originally imported from:
https://github.com/gorhill/uBlock/tree/master/platform/chromium
*/
// For background page or non-background pages
/* exported objectAssign */
'use strict';
/******************************************************************************/
/******************************************************************************/
// As per MDN, Object.assign appeared first in Firefox 34.
// https://developer.mozilla.org/en/docs/Web/JavaScript/Reference/Global_Objects/Object/assign#Browser_compatibility
var objectAssign = Object.assign || function(target, source) {
var keys = Object.keys(source);
for ( var i = 0, n = keys.length, key; i < n; i++ ) {
key = keys[i];
target[key] = source[key];
}
return target;
};
/******************************************************************************/
// Patching for Pale Moon which does not implement ES6 Set/Map.
// Test for non-ES6 Set/Map: check if property `iterator` is present.
// The code is strictly to satisfy uBO's core, not to be an accurate
// implementation of ES6.
if ( self.Set.prototype.iterator instanceof Function ) {
//console.log('Patching non-ES6 Set() to be more ES6-like.');
self.Set.prototype._values = self.Set.prototype.values;
self.Set.prototype.values = function() {
this._valueIter = this._values();
this.value = undefined;
this.done = false;
return this;
};
self.Set.prototype.next = function() {
try {
this.value = this._valueIter.next();
} catch (ex) {
this._valueIter = undefined;
this.value = undefined;
this.done = true;
}
return this;
};
}
if ( self.Map.prototype.iterator instanceof Function ) {
//console.log('Patching non-ES6 Map() to be more ES6-like.');
self.Map.prototype._entries = self.Map.prototype.entries;
self.Map.prototype.entries = function() {
this._entryIter = this._entries();
this.value = undefined;
this.done = false;
return this;
};
self.Map.prototype.next = function() {
try {
this.value = this._entryIter.next();
} catch (ex) {
this._entryIter = undefined;
this.value = undefined;
this.done = true;
}
return this;
};
}

3465
platform/firefox/vapi-background.js
File diff suppressed because it is too large
View File

225
platform/firefox/vapi-client.js

@ -1,225 +0,0 @@
/*******************************************************************************
uMatrix - a browser extension to block requests.
Copyright (C) 2014-2017 The uMatrix/uBlock Origin authors
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see {http://www.gnu.org/licenses/}.
Home: https://github.com/gorhill/uMatrix
*/
/* jshint esnext: true */
/* global addMessageListener, removeMessageListener, sendAsyncMessage */
// For non background pages
'use strict';
/******************************************************************************/
(function(self) {
/******************************************************************************/
// https://bugs.chromium.org/p/project-zero/issues/detail?id=1225&desc=6#c10
if ( self.vAPI === undefined || self.vAPI.uMatrix !== true ) {
self.vAPI = { uMatrix: true };
}
var vAPI = self.vAPI;
vAPI.firefox = true;
vAPI.sessionId = String.fromCharCode(Date.now() % 25 + 97) +
Math.random().toString(36).slice(2);
/******************************************************************************/
vAPI.setTimeout = vAPI.setTimeout || function(callback, delay) {
return setTimeout(function() { callback(); }, delay);
};
/******************************************************************************/
vAPI.shutdown = (function() {
var jobs = [];
var add = function(job) {
jobs.push(job);
};
var exec = function() {
//console.debug('Shutting down...');
var job;
while ( (job = jobs.pop()) ) {
job();
}
};
return {
add: add,
exec: exec
};
})();
/******************************************************************************/
vAPI.messaging = {
listeners: new Set(),
pending: new Map(),
requestId: 1,
connected: false,
setup: function() {
this.addListener(this.builtinListener);
if ( this.toggleListenerCallback === null ) {
this.toggleListenerCallback = this.toggleListener.bind(this);
}
window.addEventListener('pagehide', this.toggleListenerCallback, true);
window.addEventListener('pageshow', this.toggleListenerCallback, true);
},
shutdown: function() {
if ( this.toggleListenerCallback !== null ) {
window.removeEventListener('pagehide', this.toggleListenerCallback, true);
window.removeEventListener('pageshow', this.toggleListenerCallback, true);
}
this.removeAllListeners();
//service pending callbacks
var pending = this.pending;
this.pending.clear();
for ( var callback of pending.values() ) {
if ( typeof callback === 'function' ) {
callback(null);
}
}
},
connect: function() {
if ( !this.connected ) {
if ( this.messageListenerCallback === null ) {
this.messageListenerCallback = this.messageListener.bind(this);
}
addMessageListener(this.messageListenerCallback);
this.connected = true;
}
},
disconnect: function() {
if ( this.connected ) {
removeMessageListener();
this.connected = false;
}
},
messageListener: function(msg) {
var details = JSON.parse(msg);
if ( !details ) {
return;
}
if ( details.broadcast ) {
this.sendToListeners(details.msg);
return;
}
if ( details.requestId ) {
var listener = this.pending.get(details.requestId);
if ( listener !== undefined ) {
this.pending.delete(details.requestId);
listener(details.msg);
return;
}
}
},
messageListenerCallback: null,
builtinListener: function(msg) {
if ( typeof msg.cmd === 'string' && msg.cmd === 'injectScript' ) {
var details = msg.details;
if ( !details.allFrames && window !== window.top ) {
return;
}
self.injectScript(details.file);
}
},
send: function(channelName, message, callback) {
this.connect()
message = {
channelName: self._sandboxId_ + '|' + channelName,
msg: message
};
if ( callback ) {
message.requestId = this.requestId++;
this.pending.set(message.requestId, callback);
}
sendAsyncMessage('umatrix:background', message);
},
toggleListener: function({type, persisted}) {
if ( type === 'pagehide' && !persisted ) {
vAPI.shutdown.exec();
this.shutdown();
return;
}
if ( type === 'pagehide' ) {
this.disconnect();
} else /* if ( type === 'pageshow' ) */ {
this.connect();
}
},
toggleListenerCallback: null,
sendToListeners: function(msg) {
for ( var listener of this.listeners ) {
listener(msg);
}
},
addListener: function(listener) {
this.listeners.add(listener);
this.connect()
},
removeListener: function(listener) {
this.listeners.delete(listener);
},
removeAllListeners: function() {
this.disconnect();
this.listeners.clear();;
}
};
vAPI.messaging.setup()
/******************************************************************************/
// No need to have vAPI client linger around after shutdown if
// we are not a top window (because element picker can still
// be injected in top window).
if ( window !== window.top ) {
vAPI.shutdown.add(function() {
vAPI = null;
});
}
/******************************************************************************/
})(this);
/******************************************************************************/

191
platform/firefox/vapi-common.js

@ -1,191 +0,0 @@
/*******************************************************************************
uMatrix - a browser extension to block requests.
Copyright (C) 2014-2017 The uMatrix/uBlock Origin authors
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see {http://www.gnu.org/licenses/}.
Home: https://github.com/gorhill/uMatrix
*/
/* global sendAsyncMessage */
// For background page or non-background pages
'use strict';
/******************************************************************************/
(function(self) {
/******************************************************************************/
const {Services} = Components.utils.import(
'resource://gre/modules/Services.jsm',
null
);
// https://bugs.chromium.org/p/project-zero/issues/detail?id=1225&desc=6#c10
if ( self.vAPI === undefined || self.vAPI.uMatrix !== true ) {
self.vAPI = { uMatrix: true };
}
var vAPI = self.vAPI;
/******************************************************************************/
vAPI.setTimeout = vAPI.setTimeout || function(callback, delay, extra) {
return setTimeout(function(a) { callback(a); }, delay, extra);
};
/******************************************************************************/
// http://www.w3.org/International/questions/qa-scripts#directions
var setScriptDirection = function(language) {
document.body.setAttribute(
'dir',
['ar', 'he', 'fa', 'ps', 'ur'].indexOf(language) !== -1 ? 'rtl' : 'ltr'
);
};
/******************************************************************************/
vAPI.download = function(details) {
if ( !details.url ) {
return;
}
var a = document.createElement('a');
a.href = details.url;
a.setAttribute('download', details.filename || '');
a.dispatchEvent(new MouseEvent('click'));
};
/******************************************************************************/
vAPI.insertHTML = (function() {
const parser = Components.classes['@mozilla.org/parserutils;1']
.getService(Components.interfaces.nsIParserUtils);
// https://github.com/gorhill/uBlock/issues/845
// Apparently dashboard pages execute with `about:blank` principal.
return function(node, html) {
while ( node.firstChild ) {
node.removeChild(node.firstChild);
}
node.appendChild(parser.parseFragment(
html,
parser.SanitizerAllowStyle,
false,
Services.io.newURI('about:blank', null, null),
document.documentElement
));
};
})();
/******************************************************************************/
vAPI.getURL = function(path) {
return 'chrome://' + location.host + '/content/' + path.replace(/^\/+/, '');
};
/******************************************************************************/
vAPI.i18n = (function() {
var stringBundle = Services.strings.createBundle(
'chrome://' + location.host + '/locale/messages.properties'
);
return function(s) {
try {
return stringBundle.GetStringFromName(s);
} catch (ex) {
return '';
}
};
})();
setScriptDirection(navigator.language);
/******************************************************************************/
vAPI.closePopup = function() {
sendAsyncMessage(location.host + ':closePopup');
};
/******************************************************************************/
// A localStorage-like object which should be accessible from the
// background page or auxiliary pages.
// This storage is optional, but it is nice to have, for a more polished user
// experience.
vAPI.localStorage = {
pbName: '',
pb: null,
str: Components.classes['@mozilla.org/supports-string;1']
.createInstance(Components.interfaces.nsISupportsString),
init: function(pbName) {
this.pbName = pbName;
this.pb = Services.prefs.getBranch(pbName);
},
getItem: function(key) {
try {
return this.pb.getComplexValue(
key,
Components.interfaces.nsISupportsString
).data;
} catch (ex) {
return null;
}
},
setItem: function(key, value) {
this.str.data = value;
this.pb.setComplexValue(
key,
Components.interfaces.nsISupportsString,
this.str
);
},
getBool: function(key) {
try {
return this.pb.getBoolPref(key);
} catch (ex) {
return null;
}
},
setBool: function(key, value) {
this.pb.setBoolPref(key, value);
},
setDefaultBool: function(key, defaultValue) {
Services.prefs.getDefaultBranch(this.pbName).setBoolPref(key, defaultValue);
},
removeItem: function(key) {
this.pb.clearUserPref(key);
},
clear: function() {
this.pb.deleteBranch('');
}
};
vAPI.localStorage.init('extensions.' + location.host + '.');
/******************************************************************************/
})(this);
/******************************************************************************/

1
platform/firefox/vapi-popup.js

@ -1 +0,0 @@
/* Firefox: no platform-specific code */

120
tools/make-firefox-meta.py

@ -1,120 +0,0 @@
#!/usr/bin/env python3
import os
import json
import re
import sys
from io import open
from shutil import rmtree
from collections import OrderedDict
from xml.sax.saxutils import escape
if len(sys.argv) == 1 or not sys.argv[1]:
raise SystemExit('Build dir missing.')
def mkdirs(path):
try:
os.makedirs(path)
finally:
return os.path.exists(path)
pj = os.path.join
build_dir = os.path.abspath(sys.argv[1])
source_locale_dir = pj(build_dir, '_locales')
target_locale_dir = pj(build_dir, 'locale')
language_codes = []
descriptions = OrderedDict({})
title_case_strings = ['pickerContextMenuEntry']
for alpha2 in sorted(os.listdir(source_locale_dir)):
locale_path = pj(source_locale_dir, alpha2, 'messages.json')
with open(locale_path, encoding='utf-8') as f:
strings = json.load(f, object_pairs_hook=OrderedDict)
alpha2 = alpha2.replace('_', '-')
descriptions[alpha2] = strings['extShortDesc']['message']
del strings['extShortDesc']
language_codes.append(alpha2)
mkdirs(pj(target_locale_dir, alpha2))
locale_path = pj(target_locale_dir, alpha2, 'messages.properties')
with open(locale_path, 'wt', encoding='utf-8', newline='\n') as f:
for string_name in strings:
string = strings[string_name]['message']
if alpha2 == 'en' and string_name in title_case_strings:
string = string.title()
f.write(string_name)
f.write(u'=')
f.write(string.replace('\n', r'\n'))
f.write(u'\n')
# generate chrome.manifest file
chrome_manifest = pj(build_dir, 'chrome.manifest')
with open(chrome_manifest, 'at', encoding='utf-8', newline='\n') as f:
f.write(u'\nlocale umatrix en ./locale/en/\n')
for alpha2 in language_codes:
if alpha2 == 'en':
continue
f.write(u'locale umatrix ' + alpha2 + ' ./locale/' + alpha2 + '/\n')
rmtree(source_locale_dir)
# update install.rdf
proj_dir = pj(os.path.split(os.path.abspath(__file__))[0], '..')
chromium_manifest = pj(proj_dir, 'platform', 'chromium', 'manifest.json')
with open(chromium_manifest, encoding='utf-8') as m:
manifest = json.load(m)
# https://developer.mozilla.org/en-US/Add-ons/AMO/Policy/Maintenance#How_do_I_submit_a_Beta_add-on.3F
# "To create a beta channel [...] '(a|alpha|b|beta|pre|rc)\d*$' "
match = re.search('^(\d+\.\d+\.\d+)(\.\d+)$', manifest['version'])
if match:
buildtype = int(match.group(2)[1:])
if buildtype < 100:
builttype = 'b' + str(buildtype)
else:
builttype = 'rc' + str(buildtype - 100)
manifest['version'] = match.group(1) + builttype
manifest['homepage'] = 'https://github.com/gorhill/uMatrix'
manifest['description'] = escape(descriptions['en'])
del descriptions['en']
manifest['localized'] = []
t = ' '
t3 = 3 * t
for alpha2 in descriptions:
if alpha2 == 'en':
continue
manifest['localized'].append(
'\n' + t*2 + '<localized><r:Description>\n' +
t3 + '<locale>' + alpha2 + '</locale>\n' +
t3 + '<name>' + manifest['name'] + '</name>\n' +
t3 + '<description>' + escape(descriptions[alpha2]) + '</description>\n' +
t3 + '<creator>' + manifest['author'] + '</creator>\n' +
# t3 + '<translator>' + ??? + '</translator>\n' +
t3 + '<homepageURL>' + manifest['homepage'] + '</homepageURL>\n' +
t*2 + '</r:Description></localized>'
)
manifest['localized'] = '\n'.join(manifest['localized'])
install_rdf = pj(build_dir, 'install.rdf')
with open(install_rdf, 'r+t', encoding='utf-8', newline='\n') as f:
install_rdf = f.read()
f.seek(0)
f.write(install_rdf.format(**manifest))
f.truncate()

42
tools/make-firefox.sh

@ -1,42 +0,0 @@
#!/bin/bash
#
# This script assumes a linux environment
echo "*** uMatrix.firefox: Copying files"
DES=dist/build/uMatrix.firefox
rm -rf $DES
mkdir -p $DES
cp -R assets $DES/
cp -R src/* $DES/
mv $DES/img/icon_128.png $DES/icon.png
cp platform/firefox/css/* $DES/css/
cp platform/firefox/polyfill.js $DES/js/
cp platform/firefox/vapi-*.js $DES/js/
cp platform/firefox/bootstrap.js $DES/
cp platform/firefox/frame*.js $DES/
cp -R platform/chromium/img $DES/
cp platform/firefox/chrome.manifest $DES/
cp platform/firefox/install.rdf $DES/
cp platform/firefox/*.xul $DES/
cp LICENSE.txt $DES/
echo "*** uMatrix.firefox: Generating meta..."
python tools/make-firefox-meta.py $DES/
if [ "$1" = all ]; then
echo "*** uMatrix.firefox: Creating package..."
pushd $DES/
zip ../uMatrix.firefox.xpi -qr *
popd
fi
echo "*** uMatrix.firefox: Package done."
Loading…
Cancel
Save