diff --git a/b2g/chrome/content/shell.js b/b2g/chrome/content/shell.js index ea94ceb40f0..f29de04e91e 100644 --- a/b2g/chrome/content/shell.js +++ b/b2g/chrome/content/shell.js @@ -9,7 +9,6 @@ Cu.import('resource://gre/modules/SettingsChangeNotifier.jsm'); Cu.import('resource://gre/modules/DataStoreChangeNotifier.jsm'); Cu.import('resource://gre/modules/AlarmService.jsm'); Cu.import('resource://gre/modules/ActivitiesService.jsm'); -Cu.import('resource://gre/modules/PermissionPromptHelper.jsm'); Cu.import('resource://gre/modules/NotificationDB.jsm'); Cu.import('resource://gre/modules/Payment.jsm'); Cu.import("resource://gre/modules/AppsUtils.jsm"); diff --git a/dom/base/nsContentPermissionHelper.cpp b/dom/base/nsContentPermissionHelper.cpp index 5155841c5fe..98c35f49743 100644 --- a/dom/base/nsContentPermissionHelper.cpp +++ b/dom/base/nsContentPermissionHelper.cpp @@ -13,6 +13,7 @@ #include "mozilla/dom/PContentPermission.h" #include "mozilla/dom/PermissionMessageUtils.h" #include "mozilla/dom/PContentPermissionRequestParent.h" +#include "mozilla/dom/ScriptSettings.h" #include "mozilla/dom/TabParent.h" #include "mozilla/unused.h" #include "nsComponentManagerUtils.h" @@ -358,3 +359,129 @@ nsContentPermissionRequestProxy::Allow(JS::HandleValue aChoices) mParent = nullptr; return NS_OK; } + +// RemotePermissionRequest + +// static +uint32_t +RemotePermissionRequest::ConvertArrayToPermissionRequest( + nsIArray* aSrcArray, + nsTArray& aDesArray) +{ + uint32_t len = 0; + aSrcArray->GetLength(&len); + for (uint32_t i = 0; i < len; i++) { + nsCOMPtr cpt = do_QueryElementAt(aSrcArray, i); + nsAutoCString type; + nsAutoCString access; + cpt->GetType(type); + cpt->GetAccess(access); + + nsCOMPtr optionArray; + cpt->GetOptions(getter_AddRefs(optionArray)); + uint32_t optionsLength = 0; + if (optionArray) { + optionArray->GetLength(&optionsLength); + } + nsTArray options; + for (uint32_t j = 0; j < optionsLength; ++j) { + nsCOMPtr isupportsString = do_QueryElementAt(optionArray, j); + if (isupportsString) { + nsString option; + isupportsString->GetData(option); + options.AppendElement(option); + } + } + + aDesArray.AppendElement(PermissionRequest(type, access, options)); + } + return len; +} + +NS_IMPL_ISUPPORTS(RemotePermissionRequest, nsIContentPermissionRequest) + +RemotePermissionRequest::RemotePermissionRequest( + nsIContentPermissionRequest* aRequest, + nsPIDOMWindow* aWindow) + : mRequest(aRequest) + , mWindow(aWindow) +{ +} + +// nsIContentPermissionRequest methods +NS_IMETHODIMP +RemotePermissionRequest::GetTypes(nsIArray** aTypes) +{ + NS_ASSERTION(mRequest, "We need a request"); + return mRequest->GetTypes(aTypes); +} + +NS_IMETHODIMP +RemotePermissionRequest::GetPrincipal(nsIPrincipal **aRequestingPrincipal) +{ + NS_ENSURE_ARG_POINTER(aRequestingPrincipal); + + return mRequest->GetPrincipal(aRequestingPrincipal); +} + +NS_IMETHODIMP +RemotePermissionRequest::GetWindow(nsIDOMWindow** aRequestingWindow) +{ + NS_ENSURE_ARG_POINTER(aRequestingWindow); + + return mRequest->GetWindow(aRequestingWindow); +} + +NS_IMETHODIMP +RemotePermissionRequest::GetElement(nsIDOMElement** aRequestingElement) +{ + NS_ENSURE_ARG_POINTER(aRequestingElement); + *aRequestingElement = nullptr; + return NS_OK; +} + +NS_IMETHODIMP +RemotePermissionRequest::Cancel() +{ + NS_ASSERTION(mRequest, "We need a request"); + return mRequest->Cancel(); +} + +NS_IMETHODIMP +RemotePermissionRequest::Allow(JS::HandleValue aChoices) +{ + NS_ASSERTION(mRequest, "We need a request"); + return mRequest->Allow(aChoices); +} + +// PCOMContentPermissionRequestChild +bool +RemotePermissionRequest::Recv__delete__(const bool& aAllow, + const nsTArray& aChoices) +{ + if (aAllow && mWindow->IsCurrentInnerWindow()) { + // Convert choices to a JS val if any. + // {"type1": "choice1", "type2": "choiceA"} + AutoJSAPI jsapi; + if (NS_WARN_IF(!jsapi.Init(mWindow))) { + return true; // This is not an IPC error. + } + JSContext* cx = jsapi.cx(); + JS::Rooted obj(cx); + obj = JS_NewObject(cx, nullptr, JS::NullPtr(), JS::NullPtr()); + for (uint32_t i = 0; i < aChoices.Length(); ++i) { + const nsString& choice = aChoices[i].choice(); + const nsCString& type = aChoices[i].type(); + JS::Rooted jChoice(cx, JS_NewUCStringCopyN(cx, choice.get(), choice.Length())); + JS::Rooted vChoice(cx, StringValue(jChoice)); + if (!JS_SetProperty(cx, obj, type.get(), vChoice)) { + return false; + } + } + JS::RootedValue val(cx, JS::ObjectValue(*obj)); + (void) Allow(val); + } else { + (void) Cancel(); + } + return true; +} diff --git a/dom/base/nsContentPermissionHelper.h b/dom/base/nsContentPermissionHelper.h index b25e9a01974..c634aba01bd 100644 --- a/dom/base/nsContentPermissionHelper.h +++ b/dom/base/nsContentPermissionHelper.h @@ -8,7 +8,9 @@ #include "nsIContentPermissionPrompt.h" #include "nsTArray.h" #include "nsIMutableArray.h" +#include "PCOMContentPermissionRequestChild.h" +class nsPIDOMWindow; class nsContentPermissionRequestProxy; // Forward declare IPC::Principal here which is defined in @@ -83,4 +85,31 @@ class nsContentPermissionRequestProxy : public nsIContentPermissionRequest nsTArray mPermissionRequests; }; +/** + * RemotePermissionRequest will send a prompt ipdl request to b2g process. + */ +class RemotePermissionRequest : public nsIContentPermissionRequest + , public PCOMContentPermissionRequestChild +{ +public: + NS_DECL_ISUPPORTS + NS_DECL_NSICONTENTPERMISSIONREQUEST + + RemotePermissionRequest(nsIContentPermissionRequest* aRequest, + nsPIDOMWindow* aWindow); + virtual ~RemotePermissionRequest() {} + + // It will be called when prompt dismissed. + virtual bool Recv__delete__(const bool &aAllow, + const nsTArray& aChoices) MOZ_OVERRIDE; + virtual void IPDLRelease() MOZ_OVERRIDE { Release(); } + + static uint32_t ConvertArrayToPermissionRequest( + nsIArray* aSrcArray, + nsTArray& aDesArray); +private: + nsCOMPtr mRequest; + nsCOMPtr mWindow; +}; + #endif // nsContentPermissionHelper_h diff --git a/dom/base/nsDOMWindowUtils.cpp b/dom/base/nsDOMWindowUtils.cpp index 020cf2936e4..f269e8d0f0a 100644 --- a/dom/base/nsDOMWindowUtils.cpp +++ b/dom/base/nsDOMWindowUtils.cpp @@ -70,6 +70,7 @@ #include "mozilla/dom/indexedDB/IndexedDatabaseManager.h" #include "mozilla/dom/MutableFile.h" #include "mozilla/dom/MutableFileBinding.h" +#include "mozilla/dom/PermissionMessageUtils.h" #include "mozilla/dom/quota/PersistenceType.h" #include "mozilla/dom/quota/QuotaManager.h" #include "nsDOMBlobBuilder.h" @@ -88,6 +89,7 @@ #include "GeckoProfiler.h" #include "mozilla/Preferences.h" #include "nsIContentIterator.h" +#include "nsContentPermissionHelper.h" #ifdef XP_WIN #undef GetClassName @@ -3677,6 +3679,49 @@ nsDOMWindowUtils::XpconnectArgument(nsIDOMWindowUtils* aThis) return NS_OK; } +NS_IMETHODIMP +nsDOMWindowUtils::AskPermission(nsIContentPermissionRequest* aRequest) +{ + nsCOMPtr window = do_QueryReferent(mWindow); + nsRefPtr req = + new RemotePermissionRequest(aRequest, window->GetCurrentInnerWindow()); + + // for content process + if (XRE_GetProcessType() == GeckoProcessType_Content) { + MOZ_ASSERT(NS_IsMainThread()); // IPC can only be execute on main thread. + + dom::TabChild* child = dom::TabChild::GetFrom(window->GetDocShell()); + NS_ENSURE_TRUE(child, NS_ERROR_FAILURE); + + nsCOMPtr typeArray; + nsresult rv = req->GetTypes(getter_AddRefs(typeArray)); + NS_ENSURE_SUCCESS(rv, rv); + + nsTArray permArray; + RemotePermissionRequest::ConvertArrayToPermissionRequest(typeArray, permArray); + + nsCOMPtr principal; + rv = req->GetPrincipal(getter_AddRefs(principal)); + NS_ENSURE_SUCCESS(rv, rv); + + req->AddRef(); + child->SendPContentPermissionRequestConstructor(req, + permArray, + IPC::Principal(principal)); + + req->Sendprompt(); + return NS_OK; + } + + // for chrome process + nsCOMPtr prompt = + do_GetService(NS_CONTENT_PERMISSION_PROMPT_CONTRACTID); + if (prompt) { + prompt->Prompt(req); + } + return NS_OK; +} + NS_INTERFACE_MAP_BEGIN(nsTranslationNodeList) NS_INTERFACE_MAP_ENTRY(nsISupports) NS_INTERFACE_MAP_ENTRY(nsITranslationNodeList) diff --git a/dom/contacts/ContactManager.js b/dom/contacts/ContactManager.js index fbaaa027746..af3fd2c77f5 100644 --- a/dom/contacts/ContactManager.js +++ b/dom/contacts/ContactManager.js @@ -185,19 +185,6 @@ ContactManager.prototype = { Services.DOMRequest.fireError(req.cursor, msg.errorMsg); } break; - case "PermissionPromptHelper:AskPermission:OK": - if (DEBUG) debug("id: " + msg.requestID); - req = this.getRequest(msg.requestID); - if (!req) { - break; - } - - if (msg.result == Ci.nsIPermissionManager.ALLOW_ACTION) { - req.allow(); - } else { - req.cancel(); - } - break; case "Contact:Changed": // Fire oncontactchange event if (DEBUG) debug("Contacts:ContactChanged: " + msg.contactID + ", " + msg.reason); @@ -235,6 +222,7 @@ ContactManager.prototype = { askPermission: function (aAccess, aRequest, aAllowCallback, aCancelCallback) { if (DEBUG) debug("askPermission for contacts"); + let access; switch(aAccess) { case "create": @@ -255,38 +243,42 @@ ContactManager.prototype = { } // Shortcut for ALLOW_ACTION so we avoid a parent roundtrip + let principal = this._window.document.nodePrincipal; let type = "contacts-" + access; let permValue = - Services.perms.testExactPermissionFromPrincipal(this._window.document.nodePrincipal, type); + Services.perms.testExactPermissionFromPrincipal(principal, type); if (permValue == Ci.nsIPermissionManager.ALLOW_ACTION) { aAllowCallback(); return; + } else if (permValue == Ci.nsIPermissionManager.DENY_ACTION) { + aCancelCallback(); } - let requestID = this.getRequestId({ - request: aRequest, - allow: function() { - aAllowCallback(); - }.bind(this), - cancel : function() { - if (aCancelCallback) { - aCancelCallback() - } else if (aRequest) { - Services.DOMRequest.fireError(aRequest, "Not Allowed"); - } - }.bind(this) - }); - - let principal = this._window.document.nodePrincipal; - cpmm.sendAsyncMessage("PermissionPromptHelper:AskPermission", { + // Create an array with a single nsIContentPermissionType element. + let type = { type: "contacts", access: access, - requestID: requestID, - origin: principal.origin, - appID: principal.appId, - browserFlag: principal.isInBrowserElement, - windowID: this._window.QueryInterface(Ci.nsIInterfaceRequestor).getInterface(Ci.nsIDOMWindowUtils).outerWindowID - }); + options: null, + QueryInterface: XPCOMUtils.generateQI([Ci.nsIContentPermissionType]) + }; + let typeArray = Cc["@mozilla.org/array;1"].createInstance(Ci.nsIMutableArray); + typeArray.appendElement(type, false); + + // create a nsIContentPermissionRequest + let request = { + types: typeArray, + principal: principal, + QueryInterface: XPCOMUtils.generateQI([Ci.nsIContentPermissionRequest]), + allow: aAllowCallback, + cancel: aCancelCallback, + window: this._window + }; + + // Using askPermission from nsIDOMWindowUtils that takes care of the + // remoting if needed. + let windowUtils = this._window.QueryInterface(Ci.nsIInterfaceRequestor) + .getInterface(Ci.nsIDOMWindowUtils); + windowUtils.askPermission(request); }, save: function save(aContact) { @@ -464,7 +456,6 @@ ContactManager.prototype = { "Contact:Save:Return:OK", "Contact:Save:Return:KO", "Contact:Remove:Return:OK", "Contact:Remove:Return:KO", "Contact:Changed", - "PermissionPromptHelper:AskPermission:OK", "Contacts:GetAll:Next", "Contacts:GetAll:Return:KO", "Contacts:Count", "Contacts:Revision", "Contacts:GetRevision:Return:KO",]); diff --git a/dom/contacts/tests/shared.js b/dom/contacts/tests/shared.js index 893469ecef7..1fbf7dacd80 100644 --- a/dom/contacts/tests/shared.js +++ b/dom/contacts/tests/shared.js @@ -3,7 +3,6 @@ // Fix the environment to run Contacts tests if (SpecialPowers.isMainProcess()) { SpecialPowers.Cu.import("resource://gre/modules/ContactService.jsm"); - SpecialPowers.Cu.import("resource://gre/modules/PermissionPromptHelper.jsm"); } SpecialPowers.addPermission("contacts-write", true, document); diff --git a/dom/interfaces/base/nsIDOMWindowUtils.idl b/dom/interfaces/base/nsIDOMWindowUtils.idl index 2115e625831..9a88a6c2e3b 100644 --- a/dom/interfaces/base/nsIDOMWindowUtils.idl +++ b/dom/interfaces/base/nsIDOMWindowUtils.idl @@ -47,8 +47,9 @@ interface nsIDOMEventTarget; interface nsIRunnable; interface nsICompositionStringSynthesizer; interface nsITranslationNodeList; +interface nsIContentPermissionRequest; -[scriptable, uuid(46e3f206-9a8f-4d66-8248-7ec6a37de45a)] +[scriptable, uuid(ca202fa7-7b8f-4814-acc3-a8545f67320b)] interface nsIDOMWindowUtils : nsISupports { /** @@ -1663,6 +1664,12 @@ interface nsIDOMWindowUtils : nsISupports { * purpose of the test for bug 503926. */ void xpconnectArgument(in nsIDOMWindowUtils aThis); + + /** + * Helper for JS components that need to send permission requests with + * e10s support properly. + */ + void askPermission(in nsIContentPermissionRequest aRequest); }; [scriptable, uuid(c694e359-7227-4392-a138-33c0cc1f15a6)] diff --git a/dom/ipc/PCOMContentPermissionRequestChild.h b/dom/ipc/PCOMContentPermissionRequestChild.h index 9b8f87a63fd..22f92bad68e 100644 --- a/dom/ipc/PCOMContentPermissionRequestChild.h +++ b/dom/ipc/PCOMContentPermissionRequestChild.h @@ -10,6 +10,7 @@ // XXXbz Doing this in a header is a gigantic footgun. See // https://bugzilla.mozilla.org/show_bug.cgi?id=932421#c3 for why. #undef CreateEvent +#undef LoadImage /* PContentPermissionRequestChild implementations also are diff --git a/dom/media/MediaPermissionGonk.cpp b/dom/media/MediaPermissionGonk.cpp index 0ec8ac08653..8cab5e67e5c 100644 --- a/dom/media/MediaPermissionGonk.cpp +++ b/dom/media/MediaPermissionGonk.cpp @@ -35,38 +35,6 @@ namespace mozilla { static MediaPermissionManager *gMediaPermMgr = nullptr; -static uint32_t -ConvertArrayToPermissionRequest(nsIArray* aSrcArray, - nsTArray& aDesArray) -{ - uint32_t len = 0; - aSrcArray->GetLength(&len); - for (uint32_t i = 0; i < len; i++) { - nsCOMPtr cpt = do_QueryElementAt(aSrcArray, i); - nsAutoCString type; - nsAutoCString access; - cpt->GetType(type); - cpt->GetAccess(access); - - nsCOMPtr optionArray; - cpt->GetOptions(getter_AddRefs(optionArray)); - uint32_t optionsLength = 0; - optionArray->GetLength(&optionsLength); - nsTArray options; - for (uint32_t j = 0; j < optionsLength; ++j) { - nsCOMPtr isupportsString = do_QueryElementAt(optionArray, j); - if (isupportsString) { - nsString option; - isupportsString->GetData(option); - options.AppendElement(option); - } - } - - aDesArray.AppendElement(PermissionRequest(type, access, options)); - } - return len; -} - static void CreateDeviceNameList(nsTArray > &aDevices, nsTArray &aDeviceNameList) @@ -449,7 +417,7 @@ MediaDeviceSuccessCallback::DoPrompt(nsRefPtr &req) NS_ENSURE_SUCCESS(rv, rv); nsTArray permArray; - ConvertArrayToPermissionRequest(typeArray, permArray); + RemotePermissionRequest::ConvertArrayToPermissionRequest(typeArray, permArray); nsCOMPtr principal; rv = req->GetPrincipal(getter_AddRefs(principal)); diff --git a/dom/permission/PermissionPromptHelper.jsm b/dom/permission/PermissionPromptHelper.jsm deleted file mode 100644 index b47f88a324c..00000000000 --- a/dom/permission/PermissionPromptHelper.jsm +++ /dev/null @@ -1,146 +0,0 @@ -/* This Source Code Form is subject to the terms of the Mozilla Public - * License, v. 2.0. If a copy of the MPL was not distributed with this file, - * You can obtain one at http://mozilla.org/MPL/2.0/. */ - -/* PermissionPromptHelper checks the permissionDB for a given permission - * name and performs prompting if needed. - * Usage: send PermissionPromptHelper:AskPermission via the FrameMessageManager with: - * |origin|, |appID|, |browserFlag| -> used for getting the principal and - * |type| and |access| to call testExactPermissionFromPrincipal. - * Note that |access| isn't currently used. - * Other arugments are: - * requestID: ID that gets returned with the result message. - * - * Once the permission is checked, it returns with the message - * "PermissionPromptHelper:AskPermission:OK" - * The result contains the |result| e.g.Ci.nsIPermissionManager.ALLOW_ACTION - * and a requestID that - */ - -"use strict"; - -let DEBUG = 0; -let debug; -if (DEBUG) - debug = function (s) { dump("-*- Permission Prompt Helper component: " + s + "\n"); } -else - debug = function (s) {} - -const Cu = Components.utils; -const Cc = Components.classes; -const Ci = Components.interfaces; - -this.EXPORTED_SYMBOLS = ["PermissionPromptHelper"]; - -Cu.import("resource://gre/modules/XPCOMUtils.jsm"); -Cu.import("resource://gre/modules/Services.jsm"); - -XPCOMUtils.defineLazyServiceGetter(this, "ppmm", - "@mozilla.org/parentprocessmessagemanager;1", - "nsIMessageListenerManager"); - -XPCOMUtils.defineLazyServiceGetter(this, "permissionPromptService", - "@mozilla.org/permission-prompt-service;1", - "nsIPermissionPromptService"); - -let appsService = Cc["@mozilla.org/AppsService;1"].getService(Ci.nsIAppsService); - -this.PermissionPromptHelper = { - init: function init() { - debug("Init"); - ppmm.addMessageListener("PermissionPromptHelper:AskPermission", this); - Services.obs.addObserver(this, "profile-before-change", false); - }, - - askPermission: function askPermission(aMessage, aCallbacks) { - let msg = aMessage.json; - - let access = msg.type; - if (msg.access) { - access = access + "-" + msg.access; - } - - let uri = Services.io.newURI(msg.origin, null, null); - let principal = - Services.scriptSecurityManager.getAppCodebasePrincipal(uri, msg.appID, msg.browserFlag); - - let permValue = - Services.perms.testExactPermissionFromPrincipal(principal, access); - - if (permValue == Ci.nsIPermissionManager.DENY_ACTION || - permValue == Ci.nsIPermissionManager.UNKNOWN_ACTION) { - aCallbacks.cancel(); - return; - } - - if (permValue == Ci.nsIPermissionManager.PROMPT_ACTION) { - - // create the options from permission request. - let options = Cc["@mozilla.org/array;1"].createInstance(Ci.nsIMutableArray); - if (msg.options) { - for (let option of options) { - options.appendElement(option); - } - } - - // create an array with a nsIContentPermissionType element - let type = { - type: msg.type, - access: msg.access ? msg.access : "unused", - options: options, - QueryInterface: XPCOMUtils.generateQI([Ci.nsIContentPermissionType]) - }; - let typeArray = Cc["@mozilla.org/array;1"].createInstance(Ci.nsIMutableArray); - typeArray.appendElement(type, false); - - // create a nsIContentPermissionRequest - let request = { - types: typeArray, - principal: principal, - QueryInterface: XPCOMUtils.generateQI([Ci.nsIContentPermissionRequest]), - allow: aCallbacks.allow, - cancel: aCallbacks.cancel, - window: Services.wm.getOuterWindowWithId(msg.windowID) - }; - - permissionPromptService.getPermission(request); - return; - } - - if (permValue == Ci.nsIPermissionManager.ALLOW_ACTION) { - aCallbacks.allow(); - return; - } - }, - - observe: function observe(aSubject, aTopic, aData) { - ppmm.removeMessageListener("PermissionPromptHelper:AskPermission", this); - Services.obs.removeObserver(this, "profile-before-change"); - ppmm = null; - }, - - receiveMessage: function receiveMessage(aMessage) { - debug("PermissionPromptHelper::receiveMessage " + aMessage.name); - let mm = aMessage.target; - let msg = aMessage.data; - - let result; - if (aMessage.name == "PermissionPromptHelper:AskPermission") { - this.askPermission(aMessage, { - cancel: function() { - mm.sendAsyncMessage("PermissionPromptHelper:AskPermission:OK", - { result: Ci.nsIPermissionManager.DENY_ACTION, - requestID: msg.requestID }); - }, - allow: function(aChoice) { - mm.sendAsyncMessage("PermissionPromptHelper:AskPermission:OK", - { result: Ci.nsIPermissionManager.ALLOW_ACTION, - choice: aChoice, - requestID: msg.requestID }); - } - }); - } - } -} - -PermissionPromptHelper.init(); diff --git a/dom/permission/moz.build b/dom/permission/moz.build index c909ebac4fc..e428bbaf222 100644 --- a/dom/permission/moz.build +++ b/dom/permission/moz.build @@ -14,6 +14,5 @@ EXTRA_COMPONENTS += [ ] EXTRA_JS_MODULES += [ - 'PermissionPromptHelper.jsm', 'PermissionSettings.jsm', ] diff --git a/mobile/android/chrome/content/WebappRT.js b/mobile/android/chrome/content/WebappRT.js index 2a75bc1ef32..2b9791b5acd 100644 --- a/mobile/android/chrome/content/WebappRT.js +++ b/mobile/android/chrome/content/WebappRT.js @@ -9,7 +9,6 @@ Cu.import("resource://gre/modules/Services.jsm"); Cu.import("resource://gre/modules/FileUtils.jsm"); Cu.import("resource://gre/modules/NetUtil.jsm"); Cu.import("resource://gre/modules/PermissionsInstaller.jsm"); -Cu.import("resource://gre/modules/PermissionPromptHelper.jsm"); Cu.import("resource://gre/modules/ContactService.jsm"); Cu.import("resource://gre/modules/AppsUtils.jsm");