toolkit/mozapps/extensions/amInstallTrigger.js

Wed, 31 Dec 2014 06:09:35 +0100

author
Michael Schloh von Bennewitz <michael@schloh.com>
date
Wed, 31 Dec 2014 06:09:35 +0100
changeset 0
6474c204b198
permissions
-rw-r--r--

Cloned upstream origin tor-browser at tor-browser-31.3.0esr-4.5-1-build1
revision ID fc1c9ff7c1b2defdbc039f12214767608f46423f for hacking purpose.

     1 /* This Source Code Form is subject to the terms of the Mozilla Public
     2  * License, v. 2.0. If a copy of the MPL was not distributed with this
     3  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
     5 "use strict";
     7 const {classes: Cc, interfaces: Ci, utils: Cu} = Components;
     9 Cu.import("resource://gre/modules/XPCOMUtils.jsm");
    10 Cu.import("resource://gre/modules/Services.jsm");
    11 Cu.import("resource://gre/modules/Preferences.jsm");
    12 Cu.import("resource://gre/modules/Log.jsm");
    14 const XPINSTALL_MIMETYPE   = "application/x-xpinstall";
    16 const MSG_INSTALL_ENABLED  = "WebInstallerIsInstallEnabled";
    17 const MSG_INSTALL_ADDONS   = "WebInstallerInstallAddonsFromWebpage";
    18 const MSG_INSTALL_CALLBACK = "WebInstallerInstallCallback";
    21 let log = Log.repository.getLogger("AddonManager.InstallTrigger");
    22 log.level = Log.Level[Preferences.get("extensions.logging.enabled", false) ? "Warn" : "Trace"];
    24 function CallbackObject(id, callback, urls, mediator) {
    25   this.id = id;
    26   this.callback = callback;
    27   this.urls = new Set(urls);
    28   this.callCallback = function(url, status) {
    29     try {
    30       this.callback(url, status);
    31     }
    32     catch (e) {
    33       log.warn("InstallTrigger callback threw an exception: " + e);
    34     }
    36     this.urls.delete(url);
    37     if (this.urls.size == 0)
    38       mediator._callbacks.delete(id);
    39   };
    40 }
    42 function RemoteMediator(windowID) {
    43   this._windowID = windowID;
    44   this._lastCallbackID = 0;
    45   this._callbacks = new Map();
    46   this.mm = Cc["@mozilla.org/childprocessmessagemanager;1"]
    47             .getService(Ci.nsISyncMessageSender);
    48   this.mm.addWeakMessageListener(MSG_INSTALL_CALLBACK, this);
    49 }
    51 RemoteMediator.prototype = {
    52   receiveMessage: function(message) {
    53     if (message.name == MSG_INSTALL_CALLBACK) {
    54       let payload = message.data;
    55       let callbackHandler = this._callbacks.get(payload.callbackID);
    56       if (callbackHandler) {
    57         callbackHandler.callCallback(payload.url, payload.status);
    58       }
    59     }
    60   },
    62   enabled: function(url) {
    63     let params = {
    64       referer: url,
    65       mimetype: XPINSTALL_MIMETYPE
    66     };
    67     return this.mm.sendSyncMessage(MSG_INSTALL_ENABLED, params)[0];
    68   },
    70   install: function(installs, referer, callback, window) {
    71     let callbackID = this._addCallback(callback, installs.uris);
    73     installs.mimetype = XPINSTALL_MIMETYPE;
    74     installs.referer = referer;
    75     installs.callbackID = callbackID;
    77     return this.mm.sendSyncMessage(MSG_INSTALL_ADDONS, installs, {win: window})[0];
    78   },
    80   _addCallback: function(callback, urls) {
    81     if (!callback || typeof callback != "function")
    82       return -1;
    84     let callbackID = this._windowID + "-" + ++this._lastCallbackID;
    85     let callbackObject = new CallbackObject(callbackID, callback, urls, this);
    86     this._callbacks.set(callbackID, callbackObject);
    87     return callbackID;
    88   },
    90   QueryInterface: XPCOMUtils.generateQI([Ci.nsISupportsWeakReference])
    91 };
    94 function InstallTrigger() {
    95 }
    97 InstallTrigger.prototype = {
    98   // Here be magic. We've declared ourselves as providing the
    99   // nsIDOMGlobalPropertyInitializer interface, and are registered in the
   100   // "JavaScript-global-property" category in the XPCOM category manager. This
   101   // means that for newly created windows, XPCOM will createinstance this
   102   // object, and then call init, passing in the window for which we need to
   103   // provide an instance. We then initialize ourselves and return the webidl
   104   // version of this object using the webidl-provided _create method, which
   105   // XPCOM will then duly expose as a property value on the window. All this
   106   // indirection is necessary because webidl does not (yet) support statics
   107   // (bug 863952). See bug 926712 for more details about this implementation.
   108   init: function(window) {
   109     this._window = window;
   110     this._principal = window.document.nodePrincipal;
   111     this._url = window.document.documentURIObject;
   113     window.QueryInterface(Components.interfaces.nsIInterfaceRequestor);
   114     let utils = window.getInterface(Components.interfaces.nsIDOMWindowUtils);
   115     this._mediator = new RemoteMediator(utils.currentInnerWindowID);
   117     return window.InstallTriggerImpl._create(window, this);
   118   },
   120   enabled: function() {
   121     return this._mediator.enabled(this._url.spec);
   122   },
   124   updateEnabled: function() {
   125     return this.enabled();
   126   },
   128   install: function(installs, callback) {
   129     let installData = {
   130       uris: [],
   131       hashes: [],
   132       names: [],
   133       icons: [],
   134     };
   136     for (let name of Object.keys(installs)) {
   137       let item = installs[name];
   138       if (typeof item === "string") {
   139         item = { URL: item };
   140       }
   141       if (!item.URL) {
   142         throw new this._window.DOMError("Error", "Missing URL property for '" + name + "'");
   143       }
   145       let url = this._resolveURL(item.URL);
   146       if (!this._checkLoadURIFromScript(url)) {
   147         throw new this._window.DOMError("SecurityError", "Insufficient permissions to install: " + url.spec);
   148       }
   150       let iconUrl = null;
   151       if (item.IconURL) {
   152         iconUrl = this._resolveURL(item.IconURL);
   153         if (!this._checkLoadURIFromScript(iconUrl)) {
   154           iconUrl = null; // If page can't load the icon, just ignore it
   155         }
   156       }
   158       installData.uris.push(url.spec);
   159       installData.hashes.push(item.Hash || null);
   160       installData.names.push(name);
   161       installData.icons.push(iconUrl ? iconUrl.spec : null);
   162     }
   164     return this._mediator.install(installData, this._url.spec, callback, this._window);
   165   },
   167   startSoftwareUpdate: function(url, flags) {
   168     let filename = Services.io.newURI(url, null, null)
   169                               .QueryInterface(Ci.nsIURL)
   170                               .filename;
   171     let args = {};
   172     args[filename] = { "URL": url };
   173     return this.install(args);
   174   },
   176   installChrome: function(type, url, skin) {
   177     return this.startSoftwareUpdate(url);
   178   },
   180   _resolveURL: function (url) {
   181     return Services.io.newURI(url, null, this._url);
   182   },
   184   _checkLoadURIFromScript: function(uri) {
   185     let secman = Services.scriptSecurityManager;
   186     try {
   187       secman.checkLoadURIWithPrincipal(this._principal,
   188                                        uri,
   189                                        secman.DISALLOW_INHERIT_PRINCIPAL);
   190       return true;
   191     }
   192     catch(e) {
   193       return false;
   194     }
   195   },
   197   classID: Components.ID("{9df8ef2b-94da-45c9-ab9f-132eb55fddf1}"),
   198   contractID: "@mozilla.org/addons/installtrigger;1",
   199   QueryInterface: XPCOMUtils.generateQI([Ci.nsISupports, Ci.nsIDOMGlobalPropertyInitializer])
   200 };
   204 this.NSGetFactory = XPCOMUtils.generateNSGetFactory([InstallTrigger]);

mercurial