From 5f8de423f190bbb79a62f804151bc24824fa32d8 Mon Sep 17 00:00:00 2001 From: "Matt A. Tobin" Date: Fri, 2 Feb 2018 04:16:08 -0500 Subject: Add m-esr52 at 52.6.0 --- dom/permission/PermissionObserver.cpp | 131 ++++++++++++ dom/permission/PermissionObserver.h | 49 +++++ dom/permission/PermissionPromptService.js | 95 +++++++++ dom/permission/PermissionPromptService.manifest | 2 + dom/permission/PermissionSettings.js | 136 +++++++++++++ dom/permission/PermissionSettings.jsm | 200 ++++++++++++++++++ dom/permission/PermissionSettings.manifest | 2 + dom/permission/PermissionStatus.cpp | 129 ++++++++++++ dom/permission/PermissionStatus.h | 58 ++++++ dom/permission/PermissionUtils.cpp | 62 ++++++ dom/permission/PermissionUtils.h | 25 +++ dom/permission/Permissions.cpp | 181 +++++++++++++++++ dom/permission/Permissions.h | 56 ++++++ dom/permission/moz.build | 39 ++++ dom/permission/tests/file_empty.html | 2 + dom/permission/tests/file_framework.js | 224 +++++++++++++++++++++ dom/permission/tests/file_shim.html | 99 +++++++++ dom/permission/tests/mochitest-time.ini | 1 + dom/permission/tests/mochitest.ini | 31 +++ dom/permission/tests/test_browser.html | 49 +++++ dom/permission/tests/test_embed-apps.html | 61 ++++++ dom/permission/tests/test_idle.html | 46 +++++ dom/permission/tests/test_input-manage.html | 69 +++++++ dom/permission/tests/test_keyboard.html | 51 +++++ dom/permission/tests/test_networkstats-manage.html | 31 +++ dom/permission/tests/test_permissions.html | 31 +++ dom/permission/tests/test_permissions_api.html | 206 +++++++++++++++++++ dom/permission/tests/test_power.html | 30 +++ .../tests/test_presentation-device-manage.html | 38 ++++ dom/permission/tests/test_systemXHR.html | 38 ++++ dom/permission/tests/test_tcp-socket.html | 52 +++++ dom/permission/tests/test_time.html | 30 +++ dom/permission/tests/test_udp-socket.html | 47 +++++ dom/permission/tests/test_wifi-manage.html | 41 ++++ dom/permission/tests/unit/test_bug808734.js | 73 +++++++ dom/permission/tests/unit/xpcshell.ini | 5 + 36 files changed, 2420 insertions(+) create mode 100644 dom/permission/PermissionObserver.cpp create mode 100644 dom/permission/PermissionObserver.h create mode 100644 dom/permission/PermissionPromptService.js create mode 100644 dom/permission/PermissionPromptService.manifest create mode 100644 dom/permission/PermissionSettings.js create mode 100644 dom/permission/PermissionSettings.jsm create mode 100644 dom/permission/PermissionSettings.manifest create mode 100644 dom/permission/PermissionStatus.cpp create mode 100644 dom/permission/PermissionStatus.h create mode 100644 dom/permission/PermissionUtils.cpp create mode 100644 dom/permission/PermissionUtils.h create mode 100644 dom/permission/Permissions.cpp create mode 100644 dom/permission/Permissions.h create mode 100644 dom/permission/moz.build create mode 100644 dom/permission/tests/file_empty.html create mode 100644 dom/permission/tests/file_framework.js create mode 100644 dom/permission/tests/file_shim.html create mode 100644 dom/permission/tests/mochitest-time.ini create mode 100644 dom/permission/tests/mochitest.ini create mode 100644 dom/permission/tests/test_browser.html create mode 100644 dom/permission/tests/test_embed-apps.html create mode 100644 dom/permission/tests/test_idle.html create mode 100644 dom/permission/tests/test_input-manage.html create mode 100644 dom/permission/tests/test_keyboard.html create mode 100644 dom/permission/tests/test_networkstats-manage.html create mode 100644 dom/permission/tests/test_permissions.html create mode 100644 dom/permission/tests/test_permissions_api.html create mode 100644 dom/permission/tests/test_power.html create mode 100644 dom/permission/tests/test_presentation-device-manage.html create mode 100644 dom/permission/tests/test_systemXHR.html create mode 100644 dom/permission/tests/test_tcp-socket.html create mode 100644 dom/permission/tests/test_time.html create mode 100644 dom/permission/tests/test_udp-socket.html create mode 100644 dom/permission/tests/test_wifi-manage.html create mode 100644 dom/permission/tests/unit/test_bug808734.js create mode 100644 dom/permission/tests/unit/xpcshell.ini (limited to 'dom/permission') diff --git a/dom/permission/PermissionObserver.cpp b/dom/permission/PermissionObserver.cpp new file mode 100644 index 000000000..beda385e7 --- /dev/null +++ b/dom/permission/PermissionObserver.cpp @@ -0,0 +1,131 @@ +/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* vim: set ts=8 sts=2 et sw=2 tw=80: */ +/* 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/. */ + +#include "PermissionObserver.h" + +#include "mozilla/dom/PermissionStatus.h" +#include "mozilla/Services.h" +#include "mozilla/UniquePtr.h" +#include "nsIObserverService.h" +#include "nsIPermission.h" +#include "PermissionUtils.h" + +namespace mozilla { +namespace dom { + +namespace { +PermissionObserver* gInstance = nullptr; +} // namespace + +NS_IMPL_ISUPPORTS(PermissionObserver, + nsIObserver, + nsISupportsWeakReference) + +PermissionObserver::PermissionObserver() +{ + MOZ_ASSERT(!gInstance); +} + +PermissionObserver::~PermissionObserver() +{ + MOZ_ASSERT(mSinks.IsEmpty()); + MOZ_ASSERT(gInstance == this); + + gInstance = nullptr; +} + +/* static */ already_AddRefed +PermissionObserver::GetInstance() +{ + RefPtr instance = gInstance; + if (!instance) { + instance = new PermissionObserver(); + + nsCOMPtr obs = services::GetObserverService(); + if (NS_WARN_IF(!obs)) { + return nullptr; + } + + nsresult rv = obs->AddObserver(instance, "perm-changed", true); + if (NS_WARN_IF(NS_FAILED(rv))) { + return nullptr; + } + + gInstance = instance; + } + + return instance.forget(); +} + +void +PermissionObserver::AddSink(PermissionStatus* aSink) +{ + MOZ_ASSERT(aSink); + MOZ_ASSERT(!mSinks.Contains(aSink)); + + mSinks.AppendElement(aSink); +} + +void +PermissionObserver::RemoveSink(PermissionStatus* aSink) +{ + MOZ_ASSERT(aSink); + MOZ_ASSERT(mSinks.Contains(aSink)); + + mSinks.RemoveElement(aSink); +} + +void +PermissionObserver::Notify(PermissionName aName, nsIPrincipal& aPrincipal) +{ + for (auto* sink : mSinks) { + if (sink->mName != aName) { + continue; + } + + nsCOMPtr sinkPrincipal = sink->GetPrincipal(); + if (NS_WARN_IF(!sinkPrincipal) || !aPrincipal.Equals(sinkPrincipal)) { + continue; + } + + sink->PermissionChanged(); + } +} + +NS_IMETHODIMP +PermissionObserver::Observe(nsISupports* aSubject, + const char* aTopic, + const char16_t* aData) +{ + MOZ_ASSERT(!strcmp(aTopic, "perm-changed")); + + if (mSinks.IsEmpty()) { + return NS_OK; + } + + nsCOMPtr perm = do_QueryInterface(aSubject); + if (!perm) { + return NS_OK; + } + + nsCOMPtr principal; + perm->GetPrincipal(getter_AddRefs(principal)); + if (!principal) { + return NS_OK; + } + + nsAutoCString type; + perm->GetType(type); + Maybe permission = TypeToPermissionName(type.get()); + if (permission) { + Notify(permission.value(), *principal); + } + + return NS_OK; +} + +} // namespace dom +} // namespace mozilla diff --git a/dom/permission/PermissionObserver.h b/dom/permission/PermissionObserver.h new file mode 100644 index 000000000..e92452b8d --- /dev/null +++ b/dom/permission/PermissionObserver.h @@ -0,0 +1,49 @@ +/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* vim: set ts=8 sts=2 et sw=2 tw=80: */ +/* 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/. */ + +#ifndef mozilla_dom_PermissionObserver_h_ +#define mozilla_dom_PermissionObserver_h_ + +#include "mozilla/dom/PermissionsBinding.h" + +#include "nsIObserver.h" +#include "nsIPrincipal.h" +#include "nsTArray.h" +#include "nsWeakReference.h" + +namespace mozilla { +namespace dom { + +class PermissionStatus; + +// Singleton that watches for perm-changed notifications in order to notify +// PermissionStatus objects. +class PermissionObserver final + : public nsIObserver + , public nsSupportsWeakReference +{ +public: + NS_DECL_ISUPPORTS + NS_DECL_NSIOBSERVER + + static already_AddRefed GetInstance(); + + void AddSink(PermissionStatus* aObs); + void RemoveSink(PermissionStatus* aObs); + +private: + PermissionObserver(); + virtual ~PermissionObserver(); + + void Notify(PermissionName aName, nsIPrincipal& aPrincipal); + + nsTArray mSinks; +}; + +} // namespace dom +} // namespace mozilla + +#endif diff --git a/dom/permission/PermissionPromptService.js b/dom/permission/PermissionPromptService.js new file mode 100644 index 000000000..47418d5de --- /dev/null +++ b/dom/permission/PermissionPromptService.js @@ -0,0 +1,95 @@ +/* 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/. */ + +"use strict"; + +/* static functions */ +var DEBUG = 0; +var debug; +if (DEBUG) { + debug = function (s) { dump("-*- PermissionPromptService: " + s + "\n"); }; +} +else { + debug = function (s) {}; +} + +const Cc = Components.classes; +const Ci = Components.interfaces; +const Cu = Components.utils; + +Cu.import("resource://gre/modules/XPCOMUtils.jsm"); +Cu.import("resource://gre/modules/Services.jsm"); +Cu.import("resource://gre/modules/PermissionsInstaller.jsm"); + +const PERMISSIONPROMPTSERVICE_CONTRACTID = "@mozilla.org/permission-prompt-service;1"; +const PERMISSIONPROMPTSERVICE_CID = Components.ID("{e5f953b3-a6ca-444e-a88d-cdc81383741c}"); +const permissionPromptService = Ci.nsIPermissionPromptService; + +var permissionManager = Cc["@mozilla.org/permissionmanager;1"].getService(Ci.nsIPermissionManager); +var secMan = Cc["@mozilla.org/scriptsecuritymanager;1"].getService(Ci.nsIScriptSecurityManager); + +function makePrompt() +{ + return Cc["@mozilla.org/content-permission/prompt;1"].createInstance(Ci.nsIContentPermissionPrompt); +} + +function PermissionPromptService() +{ + debug("Constructor"); +} + +PermissionPromptService.prototype = { + + classID : PERMISSIONPROMPTSERVICE_CID, + + QueryInterface : XPCOMUtils.generateQI([permissionPromptService, Ci.nsIObserver]), + + classInfo : XPCOMUtils.generateCI({classID: PERMISSIONPROMPTSERVICE_CID, + contractID: PERMISSIONPROMPTSERVICE_CONTRACTID, + classDescription: "PermissionPromptService", + interfaces: [permissionPromptService] + }), + /** + * getPermission + * Ask for permission for an API, device, etc. + * @param nsIContentPermissionRequest aRequest + * @returns void + **/ + getPermission: function PS_getPermission(aRequest) + { + if (!(aRequest instanceof Ci.nsIContentPermissionRequest)) { + throw new Error("PermissionService.getPermission: " + + "2nd argument must be type 'nsIContentPermissionRequest'"); + } + + // Only allow exactly one permission request here. + let types = aRequest.types.QueryInterface(Ci.nsIArray); + if (types.length != 1) { + aRequest.cancel(); + return; + } + let reqType = types.queryElementAt(0, Ci.nsIContentPermissionType); + + let type = reqType.access !== "unused" ? reqType.type + "-" + reqType.access + : reqType.type; + let perm = + permissionManager.testExactPermissionFromPrincipal(aRequest.principal, type); + + switch (perm) { + case Ci.nsIPermissionManager.ALLOW_ACTION: + aRequest.allow(); + break; + case Ci.nsIPermissionManager.PROMPT_ACTION: + makePrompt().prompt(aRequest); + break; + case Ci.nsIPermissionManager.DENY_ACTION: + case Ci.nsIPermissionManager.UNKNOWN_ACTION: + default: + aRequest.cancel(); + break; + } + }, +}; + +this.NSGetFactory = XPCOMUtils.generateNSGetFactory([PermissionPromptService]); diff --git a/dom/permission/PermissionPromptService.manifest b/dom/permission/PermissionPromptService.manifest new file mode 100644 index 000000000..41ec0226c --- /dev/null +++ b/dom/permission/PermissionPromptService.manifest @@ -0,0 +1,2 @@ +component {e5f953b3-a6ca-444e-a88d-cdc81383741c} PermissionPromptService.js +contract @mozilla.org/permission-prompt-service;1 {e5f953b3-a6ca-444e-a88d-cdc81383741c} diff --git a/dom/permission/PermissionSettings.js b/dom/permission/PermissionSettings.js new file mode 100644 index 000000000..ed4f6a3d3 --- /dev/null +++ b/dom/permission/PermissionSettings.js @@ -0,0 +1,136 @@ +/* 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/. */ + +"use strict"; + +function debug(aMsg) { + //dump("-*- PermissionSettings.js: " + aMsg + "\n"); +} + +const Cc = Components.classes; +const Ci = Components.interfaces; +const Cu = Components.utils; + +Cu.import("resource://gre/modules/XPCOMUtils.jsm"); +Cu.import("resource://gre/modules/Services.jsm"); +Cu.import("resource://gre/modules/PermissionsTable.jsm"); + +var cpm = Cc["@mozilla.org/childprocessmessagemanager;1"].getService(Ci.nsISyncMessageSender); + +// PermissionSettings + +const PERMISSIONSETTINGS_CONTRACTID = "@mozilla.org/permissionSettings;1"; +const PERMISSIONSETTINGS_CID = Components.ID("{cd2cf7a1-f4c1-487b-8c1b-1a71c7097431}"); + +function PermissionSettings() +{ + debug("Constructor"); +} + +XPCOMUtils.defineLazyServiceGetter(this, + "appsService", + "@mozilla.org/AppsService;1", + "nsIAppsService"); + +PermissionSettings.prototype = { + get: function get(aPermName, aManifestURL, aOrigin, aBrowserFlag) { + // TODO: Bug 1196644 - Add signPKg parameter into PermissionSettings.js + debug("Get called with: " + aPermName + ", " + aManifestURL + ", " + aOrigin + ", " + aBrowserFlag); + let uri = Services.io.newURI(aOrigin, null, null); + let appID = appsService.getAppLocalIdByManifestURL(aManifestURL); + let principal = + Services.scriptSecurityManager.createCodebasePrincipal(uri, + {appId: appID, + inIsolatedMozBrowser: aBrowserFlag}); + let result = Services.perms.testExactPermanentPermission(principal, aPermName); + + switch (result) + { + case Ci.nsIPermissionManager.UNKNOWN_ACTION: + return "unknown"; + case Ci.nsIPermissionManager.ALLOW_ACTION: + return "allow"; + case Ci.nsIPermissionManager.DENY_ACTION: + return "deny"; + case Ci.nsIPermissionManager.PROMPT_ACTION: + return "prompt"; + default: + dump("Unsupported PermissionSettings Action!\n"); + return "unknown"; + } + }, + + isExplicit: function isExplicit(aPermName, aManifestURL, aOrigin, + aBrowserFlag) { + // TODO: Bug 1196644 - Add signPKg parameter into PermissionSettings.js + debug("isExplicit: " + aPermName + ", " + aManifestURL + ", " + aOrigin); + let uri = Services.io.newURI(aOrigin, null, null); + let app = appsService.getAppByManifestURL(aManifestURL); + let principal = Services.scriptSecurityManager + .createCodebasePrincipal(uri, {appId: app.localId, inIsolatedMozBrowser: aBrowserFlag}); + + return isExplicitInPermissionsTable(aPermName, + principal.appStatus); + }, + + set: function set(aPermName, aPermValue, aManifestURL, aOrigin, + aBrowserFlag) { + debug("Set called with: " + aPermName + ", " + aManifestURL + ", " + + aOrigin + ", " + aPermValue + ", " + aBrowserFlag); + let currentPermValue = this.get(aPermName, aManifestURL, aOrigin, + aBrowserFlag); + let action; + // Check for invalid calls so that we throw an exception rather than get + // killed by parent process + if (currentPermValue === "unknown" || + aPermValue === "unknown" || + !this.isExplicit(aPermName, aManifestURL, aOrigin, aBrowserFlag)) { + let errorMsg = "PermissionSettings.js: '" + aPermName + "'" + + " is an implicit permission for '" + aManifestURL + + "' or the permission isn't set"; + Cu.reportError(errorMsg); + throw new Components.Exception(errorMsg); + } + + cpm.sendSyncMessage("PermissionSettings:AddPermission", { + type: aPermName, + origin: aOrigin, + manifestURL: aManifestURL, + value: aPermValue, + browserFlag: aBrowserFlag + }); + }, + + remove: function remove(aPermName, aManifestURL, aOrigin) { + // TODO: Bug 1196644 - Add signPKg parameter into PermissionSettings.js + let uri = Services.io.newURI(aOrigin, null, null); + let appID = appsService.getAppLocalIdByManifestURL(aManifestURL); + let principal = + Services.scriptSecurityManager.createCodebasePrincipal(uri, + {appId: appID, + inIsolatedMozBrowser: true}); + + if (principal.appStatus !== Ci.nsIPrincipal.APP_STATUS_NOT_INSTALLED) { + let errorMsg = "PermissionSettings.js: '" + aOrigin + "'" + + " is installed or permission is implicit, cannot remove '" + + aPermName + "'."; + Cu.reportError(errorMsg); + throw new Components.Exception(errorMsg); + } + + // PermissionSettings.jsm handles delete when value is "unknown" + cpm.sendSyncMessage("PermissionSettings:AddPermission", { + type: aPermName, + origin: aOrigin, + manifestURL: aManifestURL, + value: "unknown", + browserFlag: true + }); + }, + + classID : PERMISSIONSETTINGS_CID, + QueryInterface : XPCOMUtils.generateQI([]) +} + +this.NSGetFactory = XPCOMUtils.generateNSGetFactory([PermissionSettings]) diff --git a/dom/permission/PermissionSettings.jsm b/dom/permission/PermissionSettings.jsm new file mode 100644 index 000000000..bfd37394d --- /dev/null +++ b/dom/permission/PermissionSettings.jsm @@ -0,0 +1,200 @@ +/* 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/. */ + +"use strict"; + +function debug(s) { + //dump("-*- PermissionSettings Module: " + s + "\n"); +} + +const Cu = Components.utils; +const Cc = Components.classes; +const Ci = Components.interfaces; + +this.EXPORTED_SYMBOLS = ["PermissionSettingsModule"]; + +Cu.import("resource://gre/modules/XPCOMUtils.jsm"); +Cu.import("resource://gre/modules/Services.jsm"); +Cu.import("resource://gre/modules/PermissionsTable.jsm"); + +XPCOMUtils.defineLazyServiceGetter(this, "ppmm", + "@mozilla.org/parentprocessmessagemanager;1", + "nsIMessageListenerManager"); + +XPCOMUtils.defineLazyServiceGetter(this, + "appsService", + "@mozilla.org/AppsService;1", + "nsIAppsService"); + +this.PermissionSettingsModule = { + init: function init() { + debug("Init"); + ppmm.addMessageListener("PermissionSettings:AddPermission", this); + Services.obs.addObserver(this, "profile-before-change", false); + }, + + + _isChangeAllowed: function(aPrincipal, aPermName, aAction) { + // Bug 812289: + // Change is allowed from a child process when all of the following + // conditions stand true: + // * the action isn't "unknown" (so the change isn't a delete) if the app + // is installed + // * the permission already exists on the database + // * the permission is marked as explicit on the permissions table + // Note that we *have* to check the first two conditions here because + // permissionManager doesn't know if it's being called as a result of + // a parent process or child process request. We could check + // if the permission is actually explicit (and thus modifiable) or not + // on permissionManager also but we currently don't. + let perm = + Services.perms.testExactPermissionFromPrincipal(aPrincipal,aPermName); + let isExplicit = isExplicitInPermissionsTable(aPermName, aPrincipal.appStatus); + + return (aAction === "unknown" && + aPrincipal.appStatus === Ci.nsIPrincipal.APP_STATUS_NOT_INSTALLED) || + (aAction !== "unknown" && + (perm !== Ci.nsIPermissionManager.UNKNOWN_ACTION) && + isExplicit); + }, + + addPermission: function addPermission(aData, aCallbacks) { + + this._internalAddPermission(aData, true, aCallbacks); + + }, + + + _internalAddPermission: function _internalAddPermission(aData, aAllowAllChanges, aCallbacks) { + // TODO: Bug 1196644 - Add signPKg parameter into PermissionSettings.jsm. + let app; + let principal; + // Test if app is cached (signed streamable package) or installed via DOMApplicationRegistry + if (aData.isCachedPackage) { + // If the app is from packaged web app, the origin includes origin attributes already. + principal = + Services.scriptSecurityManager.createCodebasePrincipalFromOrigin(aData.origin); + app = {localId: principal.appId}; + } else { + app = appsService.getAppByManifestURL(aData.manifestURL); + let uri = Services.io.newURI(aData.origin, null, null); + principal = + Services.scriptSecurityManager.createCodebasePrincipal(uri, + {appId: app.localId, + inIsolatedMozBrowser: aData.browserFlag}); + } + + let action; + switch (aData.value) + { + case "unknown": + action = Ci.nsIPermissionManager.UNKNOWN_ACTION; + break; + case "allow": + action = Ci.nsIPermissionManager.ALLOW_ACTION; + break; + case "deny": + action = Ci.nsIPermissionManager.DENY_ACTION; + break; + case "prompt": + action = Ci.nsIPermissionManager.PROMPT_ACTION; + break; + default: + dump("Unsupported PermisionSettings Action: " + aData.value +"\n"); + action = Ci.nsIPermissionManager.UNKNOWN_ACTION; + } + + if (aAllowAllChanges || + this._isChangeAllowed(principal, aData.type, aData.value)) { + debug("add: " + aData.origin + " " + app.localId + " " + action); + Services.perms.addFromPrincipal(principal, aData.type, action); + return true; + } else { + debug("add Failure: " + aData.origin + " " + app.localId + " " + action); + return false; // This isn't currently used, see comment on setPermission + } + }, + + getPermission: function getPermission(aPermName, aManifestURL, aOrigin, aBrowserFlag, aIsCachedPackage) { + // TODO: Bug 1196644 - Add signPKg parameter into PermissionSettings.jsm + debug("getPermission: " + aPermName + ", " + aManifestURL + ", " + aOrigin); + let principal; + // Test if app is cached (signed streamable package) or installed via DOMApplicationRegistry + if (aIsCachedPackage) { + // If the app is from packaged web app, the origin includes origin attributes already. + principal = + Services.scriptSecurityManager.createCodebasePrincipalFromOrigin(aOrigin); + } else { + let uri = Services.io.newURI(aOrigin, null, null); + let appID = appsService.getAppLocalIdByManifestURL(aManifestURL); + principal = + Services.scriptSecurityManager.createCodebasePrincipal(uri, + {appId: appID, + inIsolatedMozBrowser: aBrowserFlag}); + } + let result = Services.perms.testExactPermissionFromPrincipal(principal, aPermName); + switch (result) + { + case Ci.nsIPermissionManager.UNKNOWN_ACTION: + return "unknown"; + case Ci.nsIPermissionManager.ALLOW_ACTION: + return "allow"; + case Ci.nsIPermissionManager.DENY_ACTION: + return "deny"; + case Ci.nsIPermissionManager.PROMPT_ACTION: + return "prompt"; + default: + dump("Unsupported PermissionSettings Action!\n"); + return "unknown"; + } + }, + + removePermission: function removePermission(aPermName, aManifestURL, aOrigin, aBrowserFlag, aIsCachedPackage) { + let data = { + type: aPermName, + origin: aOrigin, + manifestURL: aManifestURL, + value: "unknown", + browserFlag: aBrowserFlag, + isCachedPackage: aIsCachedPackage + }; + this._internalAddPermission(data, true); + }, + + observe: function observe(aSubject, aTopic, aData) { + ppmm.removeMessageListener("PermissionSettings:AddPermission", this); + Services.obs.removeObserver(this, "profile-before-change"); + ppmm = null; + }, + + receiveMessage: function receiveMessage(aMessage) { + debug("PermissionSettings::receiveMessage " + aMessage.name); + let mm = aMessage.target; + let msg = aMessage.data; + + let result; + switch (aMessage.name) { + case "PermissionSettings:AddPermission": + let success = false; + let errorMsg = + " from a content process with no 'permissions' privileges."; + if (mm.assertPermission("permissions")) { + success = this._internalAddPermission(msg, false); + if (!success) { + // Just kill the calling process + mm.assertPermission("permissions-modify-implicit"); + errorMsg = " had an implicit permission change. Child process killed."; + } + } + + if (!success) { + Cu.reportError("PermissionSettings message " + msg.type + errorMsg); + return null; + } + break; + } + } +} + +PermissionSettingsModule.init(); diff --git a/dom/permission/PermissionSettings.manifest b/dom/permission/PermissionSettings.manifest new file mode 100644 index 000000000..eb53813ff --- /dev/null +++ b/dom/permission/PermissionSettings.manifest @@ -0,0 +1,2 @@ +component {cd2cf7a1-f4c1-487b-8c1b-1a71c7097431} PermissionSettings.js +contract @mozilla.org/permissionSettings;1 {cd2cf7a1-f4c1-487b-8c1b-1a71c7097431} diff --git a/dom/permission/PermissionStatus.cpp b/dom/permission/PermissionStatus.cpp new file mode 100644 index 000000000..680ece1d0 --- /dev/null +++ b/dom/permission/PermissionStatus.cpp @@ -0,0 +1,129 @@ +/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* vim: set ts=8 sts=2 et sw=2 tw=80: */ +/* 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/. */ + +#include "mozilla/dom/PermissionStatus.h" + +#include "mozilla/AsyncEventDispatcher.h" +#include "mozilla/Services.h" +#include "nsIPermissionManager.h" +#include "PermissionObserver.h" +#include "PermissionUtils.h" + +namespace mozilla { +namespace dom { + +/* static */ already_AddRefed +PermissionStatus::Create(nsPIDOMWindowInner* aWindow, + PermissionName aName, + ErrorResult& aRv) +{ + RefPtr status = new PermissionStatus(aWindow, aName); + aRv = status->Init(); + if (NS_WARN_IF(aRv.Failed())) { + return nullptr; + } + + return status.forget(); +} + +PermissionStatus::PermissionStatus(nsPIDOMWindowInner* aWindow, + PermissionName aName) + : DOMEventTargetHelper(aWindow) + , mName(aName) + , mState(PermissionState::Denied) +{ +} + +nsresult +PermissionStatus::Init() +{ + mObserver = PermissionObserver::GetInstance(); + if (NS_WARN_IF(!mObserver)) { + return NS_ERROR_FAILURE; + } + + mObserver->AddSink(this); + + nsresult rv = UpdateState(); + if (NS_WARN_IF(NS_FAILED(rv))) { + return rv; + } + + return NS_OK; +} + +PermissionStatus::~PermissionStatus() +{ + if (mObserver) { + mObserver->RemoveSink(this); + } +} + +JSObject* +PermissionStatus::WrapObject(JSContext* aCx, JS::Handle aGivenProto) +{ + return PermissionStatusBinding::Wrap(aCx, this, aGivenProto); +} + +nsresult +PermissionStatus::UpdateState() +{ + nsCOMPtr permMgr = services::GetPermissionManager(); + if (NS_WARN_IF(!permMgr)) { + return NS_ERROR_FAILURE; + } + + nsCOMPtr window = GetOwner(); + if (NS_WARN_IF(!window)) { + return NS_ERROR_FAILURE; + } + + uint32_t action = nsIPermissionManager::DENY_ACTION; + nsresult rv = permMgr->TestPermissionFromWindow(window, + PermissionNameToType(mName), + &action); + if (NS_WARN_IF(NS_FAILED(rv))) { + return rv; + } + + mState = ActionToPermissionState(action); + return NS_OK; +} + +already_AddRefed +PermissionStatus::GetPrincipal() const +{ + nsCOMPtr window = GetOwner(); + if (NS_WARN_IF(!window)) { + return nullptr; + } + + nsIDocument* doc = window->GetExtantDoc(); + if (NS_WARN_IF(!doc)) { + return nullptr; + } + + nsCOMPtr principal = + mozilla::BasePrincipal::Cast(doc->NodePrincipal())->CloneStrippingUserContextIdAndFirstPartyDomain(); + NS_ENSURE_TRUE(principal, nullptr); + + return principal.forget(); +} + +void +PermissionStatus::PermissionChanged() +{ + auto oldState = mState; + UpdateState(); + if (mState != oldState) { + RefPtr eventDispatcher = + new AsyncEventDispatcher(this, NS_LITERAL_STRING("change"), false); + eventDispatcher->PostDOMEvent(); + } +} + +} // namespace dom +} // namespace mozilla diff --git a/dom/permission/PermissionStatus.h b/dom/permission/PermissionStatus.h new file mode 100644 index 000000000..e10f86aaa --- /dev/null +++ b/dom/permission/PermissionStatus.h @@ -0,0 +1,58 @@ +/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* vim: set ts=8 sts=2 et sw=2 tw=80: */ +/* 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/. */ + +#ifndef mozilla_dom_PermissionStatus_h_ +#define mozilla_dom_PermissionStatus_h_ + +#include "mozilla/dom/PermissionsBinding.h" +#include "mozilla/dom/PermissionStatusBinding.h" +#include "mozilla/DOMEventTargetHelper.h" + +namespace mozilla { +namespace dom { + +class PermissionObserver; + +class PermissionStatus final + : public DOMEventTargetHelper +{ + friend class PermissionObserver; + +public: + static already_AddRefed Create(nsPIDOMWindowInner* aWindow, + PermissionName aName, + ErrorResult& aRv); + + JSObject* WrapObject(JSContext* aCx, + JS::Handle aGivenProto) override; + + PermissionState State() const { return mState; } + + IMPL_EVENT_HANDLER(change) + +private: + ~PermissionStatus(); + + PermissionStatus(nsPIDOMWindowInner* aWindow, PermissionName aName); + + nsresult Init(); + + nsresult UpdateState(); + + already_AddRefed GetPrincipal() const; + + void PermissionChanged(); + + PermissionName mName; + PermissionState mState; + + RefPtr mObserver; +}; + +} // namespace dom +} // namespace mozilla + +#endif // mozilla_dom_permissionstatus_h_ diff --git a/dom/permission/PermissionUtils.cpp b/dom/permission/PermissionUtils.cpp new file mode 100644 index 000000000..1bb1c1c0d --- /dev/null +++ b/dom/permission/PermissionUtils.cpp @@ -0,0 +1,62 @@ +/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* vim: set ts=8 sts=2 et sw=2 tw=80: */ +/* 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/. */ + +#include "PermissionUtils.h" + +namespace mozilla { +namespace dom { + +const char* kPermissionTypes[] = { + "geo", + "desktop-notification", + // Alias `push` to `desktop-notification`. + "desktop-notification" +}; + +// `-1` for the last null entry. +const size_t kPermissionNameCount = + MOZ_ARRAY_LENGTH(PermissionNameValues::strings) - 1; + +static_assert(MOZ_ARRAY_LENGTH(kPermissionTypes) == kPermissionNameCount, + "kPermissionTypes and PermissionName count should match"); + +const char* +PermissionNameToType(PermissionName aName) +{ + MOZ_ASSERT((size_t)aName < ArrayLength(kPermissionTypes)); + return kPermissionTypes[static_cast(aName)]; +} + +Maybe +TypeToPermissionName(const char* aType) +{ + for (size_t i = 0; i < ArrayLength(kPermissionTypes); ++i) { + if (!strcmp(aType, kPermissionTypes[i])) { + return Some(static_cast(i)); + } + } + + return Nothing(); +} + +PermissionState +ActionToPermissionState(uint32_t aAction) +{ + switch (aAction) { + case nsIPermissionManager::ALLOW_ACTION: + return PermissionState::Granted; + + case nsIPermissionManager::DENY_ACTION: + return PermissionState::Denied; + + default: + case nsIPermissionManager::PROMPT_ACTION: + return PermissionState::Prompt; + } +} + +} // namespace dom +} // namespace mozilla diff --git a/dom/permission/PermissionUtils.h b/dom/permission/PermissionUtils.h new file mode 100644 index 000000000..34bf7573d --- /dev/null +++ b/dom/permission/PermissionUtils.h @@ -0,0 +1,25 @@ +/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* vim: set ts=8 sts=2 et sw=2 tw=80: */ +/* 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/. */ + +#ifndef mozilla_dom_PermissionUtils_h_ +#define mozilla_dom_PermissionUtils_h_ + +#include "mozilla/dom/PermissionsBinding.h" +#include "mozilla/dom/PermissionStatusBinding.h" +#include "mozilla/Maybe.h" + +namespace mozilla { +namespace dom { + +const char* PermissionNameToType(PermissionName aName); +Maybe TypeToPermissionName(const char* aType); + +PermissionState ActionToPermissionState(uint32_t aAction); + +} // namespace dom +} // namespace mozilla + +#endif diff --git a/dom/permission/Permissions.cpp b/dom/permission/Permissions.cpp new file mode 100644 index 000000000..ddbfc5ffe --- /dev/null +++ b/dom/permission/Permissions.cpp @@ -0,0 +1,181 @@ +/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* vim: set ts=8 sts=2 et sw=2 tw=80: */ +/* 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/. */ + +#include "mozilla/dom/Permissions.h" + +#include "mozilla/dom/ContentChild.h" +#include "mozilla/dom/PermissionsBinding.h" +#include "mozilla/dom/Promise.h" +#include "mozilla/Services.h" +#include "nsIPermissionManager.h" +#include "PermissionUtils.h" + +namespace mozilla { +namespace dom { + +NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(Permissions) + NS_WRAPPERCACHE_INTERFACE_MAP_ENTRY + NS_INTERFACE_MAP_ENTRY(nsISupports) +NS_INTERFACE_MAP_END + +NS_IMPL_CYCLE_COLLECTING_ADDREF(Permissions) +NS_IMPL_CYCLE_COLLECTING_RELEASE(Permissions) + +NS_IMPL_CYCLE_COLLECTION_WRAPPERCACHE(Permissions, mWindow) + +Permissions::Permissions(nsPIDOMWindowInner* aWindow) + : mWindow(aWindow) +{ +} + +Permissions::~Permissions() +{ +} + +JSObject* +Permissions::WrapObject(JSContext* aCx, JS::Handle aGivenProto) +{ + return PermissionsBinding::Wrap(aCx, this, aGivenProto); +} + +namespace { + +already_AddRefed +CreatePermissionStatus(JSContext* aCx, + JS::Handle aPermission, + nsPIDOMWindowInner* aWindow, + ErrorResult& aRv) +{ + PermissionDescriptor permission; + JS::Rooted value(aCx, JS::ObjectOrNullValue(aPermission)); + if (NS_WARN_IF(!permission.Init(aCx, value))) { + aRv.NoteJSContextException(aCx); + return nullptr; + } + + switch (permission.mName) { + case PermissionName::Geolocation: + case PermissionName::Notifications: + case PermissionName::Push: + return PermissionStatus::Create(aWindow, permission.mName, aRv); + + default: + MOZ_ASSERT_UNREACHABLE("Unhandled type"); + aRv.Throw(NS_ERROR_NOT_IMPLEMENTED); + return nullptr; + } +} + +} // namespace + +already_AddRefed +Permissions::Query(JSContext* aCx, + JS::Handle aPermission, + ErrorResult& aRv) +{ + nsCOMPtr global = do_QueryInterface(mWindow); + if (!global) { + aRv.Throw(NS_ERROR_UNEXPECTED); + return nullptr; + } + + RefPtr status = + CreatePermissionStatus(aCx, aPermission, mWindow, aRv); + if (NS_WARN_IF(aRv.Failed())) { + MOZ_ASSERT(!status); + return nullptr; + } + + MOZ_ASSERT(status); + RefPtr promise = Promise::Create(global, aRv); + if (NS_WARN_IF(aRv.Failed())) { + return nullptr; + } + + promise->MaybeResolve(status); + return promise.forget(); +} + +/* static */ nsresult +Permissions::RemovePermission(nsIPrincipal* aPrincipal, const char* aPermissionType) +{ + MOZ_ASSERT(XRE_IsParentProcess()); + + nsCOMPtr permMgr = services::GetPermissionManager(); + if (NS_WARN_IF(!permMgr)) { + return NS_ERROR_FAILURE; + } + + return permMgr->RemoveFromPrincipal(aPrincipal, aPermissionType); +} + +already_AddRefed +Permissions::Revoke(JSContext* aCx, + JS::Handle aPermission, + ErrorResult& aRv) +{ + nsCOMPtr global = do_QueryInterface(mWindow); + if (!global) { + aRv.Throw(NS_ERROR_UNEXPECTED); + return nullptr; + } + + PermissionDescriptor permission; + JS::Rooted value(aCx, JS::ObjectOrNullValue(aPermission)); + if (NS_WARN_IF(!permission.Init(aCx, value))) { + aRv.NoteJSContextException(aCx); + return nullptr; + } + + RefPtr promise = Promise::Create(global, aRv); + if (NS_WARN_IF(aRv.Failed())) { + return nullptr; + } + + nsCOMPtr document = mWindow->GetExtantDoc(); + if (!document) { + promise->MaybeReject(NS_ERROR_UNEXPECTED); + return promise.forget(); + } + + nsCOMPtr permMgr = services::GetPermissionManager(); + if (NS_WARN_IF(!permMgr)) { + promise->MaybeReject(NS_ERROR_FAILURE); + return promise.forget(); + } + + const char* permissionType = PermissionNameToType(permission.mName); + + nsresult rv; + if (XRE_IsParentProcess()) { + rv = RemovePermission(document->NodePrincipal(), permissionType); + } else { + // Permissions can't be removed from the content process. Send a message + // to the parent; `ContentParent::RecvRemovePermission` will call + // `RemovePermission`. + ContentChild::GetSingleton()->SendRemovePermission( + IPC::Principal(document->NodePrincipal()), nsDependentCString(permissionType), &rv); + } + + if (NS_WARN_IF(NS_FAILED(rv))) { + promise->MaybeReject(rv); + return promise.forget(); + } + + RefPtr status = + CreatePermissionStatus(aCx, aPermission, mWindow, aRv); + if (NS_WARN_IF(aRv.Failed())) { + MOZ_ASSERT(!status); + return nullptr; + } + + MOZ_ASSERT(status); + promise->MaybeResolve(status); + return promise.forget(); +} + +} // namespace dom +} // namespace mozilla diff --git a/dom/permission/Permissions.h b/dom/permission/Permissions.h new file mode 100644 index 000000000..4fcaa5734 --- /dev/null +++ b/dom/permission/Permissions.h @@ -0,0 +1,56 @@ +/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* vim: set ts=8 sts=2 et sw=2 tw=80: */ +/* 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/. */ + +#ifndef mozilla_dom_Permissions_h_ +#define mozilla_dom_Permissions_h_ + +#include "nsISupports.h" +#include "nsPIDOMWindow.h" +#include "nsWrapperCache.h" + +namespace mozilla { + +class ErrorResult; + +namespace dom { + +class Promise; + +class Permissions final + : public nsISupports + , public nsWrapperCache +{ +public: + NS_DECL_CYCLE_COLLECTING_ISUPPORTS + NS_DECL_CYCLE_COLLECTION_SCRIPT_HOLDER_CLASS(Permissions) + + explicit Permissions(nsPIDOMWindowInner* aWindow); + + nsPIDOMWindowInner* GetParentObject() const { return mWindow; } + + JSObject* WrapObject(JSContext* aCx, + JS::Handle aGivenProto) override; + + already_AddRefed Query(JSContext* aCx, + JS::Handle aPermission, + ErrorResult& aRv); + + static nsresult RemovePermission(nsIPrincipal* aPrincipal, const char* aPermissionType); + + already_AddRefed Revoke(JSContext* aCx, + JS::Handle aPermission, + ErrorResult& aRv); + +private: + ~Permissions(); + + nsCOMPtr mWindow; +}; + +} // namespace dom +} // namespace mozilla + +#endif // mozilla_dom_permissions_h_ diff --git a/dom/permission/moz.build b/dom/permission/moz.build new file mode 100644 index 000000000..0be8a7535 --- /dev/null +++ b/dom/permission/moz.build @@ -0,0 +1,39 @@ +# -*- Mode: python; indent-tabs-mode: nil; tab-width: 40 -*- +# vim: set filetype=python: +# 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/. + +EXPORTS.mozilla.dom += [ + 'Permissions.h', + 'PermissionStatus.h', +] + +UNIFIED_SOURCES += [ + 'PermissionObserver.cpp', + 'Permissions.cpp', + 'PermissionStatus.cpp', + 'PermissionUtils.cpp', +] + +EXTRA_COMPONENTS += [ + 'PermissionPromptService.js', + 'PermissionPromptService.manifest', + 'PermissionSettings.js', + 'PermissionSettings.manifest', +] + +EXTRA_JS_MODULES += [ + 'PermissionSettings.jsm', +] + +XPCSHELL_TESTS_MANIFESTS += ['tests/unit/xpcshell.ini'] + +MOCHITEST_MANIFESTS += ['tests/mochitest.ini'] + +if CONFIG['MOZ_TIME_MANAGER']: + MOCHITEST_MANIFESTS += ['tests/mochitest-time.ini'] + +FINAL_LIBRARY = 'xul' + +include('/ipc/chromium/chromium-config.mozbuild') diff --git a/dom/permission/tests/file_empty.html b/dom/permission/tests/file_empty.html new file mode 100644 index 000000000..bc98b4d2e --- /dev/null +++ b/dom/permission/tests/file_empty.html @@ -0,0 +1,2 @@ +

I'm just a support file

+

I get loaded to do permission testing.

\ No newline at end of file diff --git a/dom/permission/tests/file_framework.js b/dom/permission/tests/file_framework.js new file mode 100644 index 000000000..27624f91e --- /dev/null +++ b/dom/permission/tests/file_framework.js @@ -0,0 +1,224 @@ +/** Test for Bug 815105 **/ +/* + * gData is an array of object that tests using this framework must pass in + * The current tests only pass in a single element array. Each test in + * gData is executed by the framework for a given file + * + * Fields in gData object + * perms (required) Array of Strings + * list of permissions that this test will need. See + * http://dxr.mozilla.org/mozilla-central/source/dom/apps/src/PermissionsTable.jsm + * These permissions are added after a sanity check and removed at + * test conclusion + * + * obj (required for default verifier) String + * The name of the window.navigator object used for accessing the + * WebAPI during the tests + * + * webidl (required for default verifier) String + * idl (required for default verifier) String + * Only one of webidl / idl is required + * The IDL describing the navigator object. The returned object + * during tests /must/ be an instanceof this + * + * skip (optional) Array of Strings + * A list of navigator.userAgent's to skip the second part of tests + * on. The tests still verify that you can't get obj on those + * platforms without permissions, however it is expected that adding + * the permission still won't allow access to those objects + * + * settings (optional) Array of preference tuples + * A list of settings that need to be set before this API is + * enabled. Note the settings are set before the sanity check is + * performed. If an API gates access only by preferences, then it + * will fail the initial test + * + * verifier (optional) Function + * A function used to test whether a WebAPI is accessible or not. + * The function takes a success and failure callback which both + * accept a msg argument. msg is surfaced up to the top level tests + * A default verifier is provided which only attempts to access + * the navigator object. + * + * needParentPerm (optional) Boolean + * Whether or not the parent frame requires these permissions as + * well. Otherwise the test process may be killed. + */ + +SimpleTest.waitForExplicitFinish(); +var expand = SpecialPowers.Cu.import("resource://gre/modules/PermissionsTable.jsm").expandPermissions; +const permTable = SpecialPowers.Cu.import("resource://gre/modules/PermissionsTable.jsm").PermissionsTable; + +const TEST_DOMAIN = "http://example.org"; +const SHIM_PATH = "/tests/dom/permission/tests/file_shim.html" +var gContent = document.getElementById('content'); + +//var gData; defined in external files +var gCurrentTest = 0; +var gRemainingTests; +var pendingTests = {}; + +function PermTest(aData) { + var self = this; + var skip = aData.skip || false; + this.step = 0; + this.data = aData; + this.isSkip = skip && + skip.some(function (el) { + return navigator. + userAgent.toLowerCase(). + indexOf(el.toLowerCase()) != -1; + }); + + this.setupParent = false; + this.perms = expandPermissions(aData.perm); + this.id = gCurrentTest++; + this.iframe = null; + + // keep a reference to this for eventhandler + pendingTests[this.id] = this; + + this.createFrame = function() { + if (self.iframe) { + gContent.removeChild(self.iframe); + } + var iframe = document.createElement('iframe'); + iframe.setAttribute('id', 'testframe' + self.step + self.perms) + iframe.setAttribute('remote', true); + iframe.src = TEST_DOMAIN + SHIM_PATH; + iframe.addEventListener('load', function _iframeLoad() { + iframe.removeEventListener('load', _iframeLoad); + + // check permissions are correct + var allow = (self.step == 0 ? false : true); + self.perms.forEach(function (el) { + try { + var res = SpecialPowers.hasPermission(el, SpecialPowers.wrap(iframe) + .contentDocument); + is(res, allow, (allow ? "Has " : "Doesn't have ") + el); + } catch(e) { + ok(false, "failed " + e); + } + }); + + var msg = { + id: self.id, + step: self.step++, + testdata: self.data, + } + // start the tests + iframe.contentWindow.postMessage(msg, "*"); + }); + + self.iframe = iframe; + gContent.appendChild(iframe); + } + + this.next = function () { + switch(self.step) { + case 0: + self.createFrame(); + break; + case 1: + // add permissions + addPermissions(self.perms, SpecialPowers. + wrap(self.iframe). + contentDocument, + self.createFrame.bind(self)); + break; + case 2: + if (self.iframe) { + gContent.removeChild(self.iframe); + } + checkFinish(); + break; + default: + ok(false, "Should not be reached"); + break + } + } + + this.start = function() { + // some permissions need parent to have permission as well + if (!self.setupParent && self.data.needParentPerm && + !SpecialPowers.isMainProcess()) { + self.setupParent = true; + addPermissions(self.perms, window.document, self.start.bind(self)); + } else if (self.data.settings && self.data.settings.length) { + SpecialPowers.pushPrefEnv({'set': self.data.settings.slice(0)}, + self.next.bind(self)); + } else { + self.next(); + } + } +} + +function addPermissions(aPerms, aDoc, aCallback) { + var permList = []; + aPerms.forEach(function (el) { + var obj = {'type': el, + 'allow': 1, + 'context': aDoc}; + permList.push(obj); + }); + SpecialPowers.pushPermissions(permList, aCallback); +} + +function expandPermissions(aPerms) { + var perms = []; + aPerms.forEach(function(el) { + var access = permTable[el].access ? "readwrite" : null; + var expanded = expand(el, access); + for (let i = 0; i < expanded.length; i++) { + perms.push(SpecialPowers.unwrap(expanded[i])); + } + }); + + return perms; +} + +function msgHandler(evt) { + var data = evt.data; + var test = pendingTests[data.id]; + + /* + * step 2 of tests should fail on + * platforms which are skipped + */ + if (test.isSkip && test.step == 2) { + todo(data.result, data.msg); + } else { + ok(data.result, data.msg); + } + + if (test) { + test.next(); + } else { + ok(false, "Received unknown id " + data.id); + checkFinish(); + } +} + +function checkFinish() { + if (--gRemainingTests) { + gTestRunner.next(); + } else { + window.removeEventListener('message', msgHandler); + SimpleTest.finish(); + } +} + +function runTest() { + gRemainingTests = Object.keys(gData).length; + + for (var test in gData) { + var test = new PermTest(gData[test]); + test.start(); + yield undefined; + } +} + +var gTestRunner = runTest(); + +window.addEventListener('load', function() { gTestRunner.next(); }, false); +window.addEventListener('message', msgHandler, false); diff --git a/dom/permission/tests/file_shim.html b/dom/permission/tests/file_shim.html new file mode 100644 index 000000000..7791eba65 --- /dev/null +++ b/dom/permission/tests/file_shim.html @@ -0,0 +1,99 @@ + + + + + + + + diff --git a/dom/permission/tests/mochitest-time.ini b/dom/permission/tests/mochitest-time.ini new file mode 100644 index 000000000..24f65b2a4 --- /dev/null +++ b/dom/permission/tests/mochitest-time.ini @@ -0,0 +1 @@ +[test_time.html] diff --git a/dom/permission/tests/mochitest.ini b/dom/permission/tests/mochitest.ini new file mode 100644 index 000000000..58fd048ca --- /dev/null +++ b/dom/permission/tests/mochitest.ini @@ -0,0 +1,31 @@ +[DEFAULT] +support-files = + file_framework.js + file_shim.html + file_empty.html + +[test_browser.html] +skip-if = true +[test_idle.html] +# skip-if = (toolkit == 'gonk' && debug) #debug-only failure +skip-if = true +[test_permissions.html] +skip-if = true +[test_permissions_api.html] +[test_power.html] +skip-if = true +[test_presentation-device-manage.html] +skip-if = true +[test_systemXHR.html] +[test_tcp-socket.html] +skip-if = true +[test_udp-socket.html] +skip-if = true +[test_keyboard.html] +# skip-if = toolkit == 'android' +skip-if = true +[test_input-manage.html] +# skip-if = toolkit == 'android' +skip-if = true +[test_wifi-manage.html] +skip-if = true diff --git a/dom/permission/tests/test_browser.html b/dom/permission/tests/test_browser.html new file mode 100644 index 000000000..0e6f44d58 --- /dev/null +++ b/dom/permission/tests/test_browser.html @@ -0,0 +1,49 @@ + + + + + + Test for Bug 815105 + + + + +Mozilla Bug 815105 +

+ +
+
+
+
+ + + diff --git a/dom/permission/tests/test_embed-apps.html b/dom/permission/tests/test_embed-apps.html new file mode 100644 index 000000000..69d4725c7 --- /dev/null +++ b/dom/permission/tests/test_embed-apps.html @@ -0,0 +1,61 @@ + + + + + + Test for Bug 815105 + + + + +Mozilla Bug 815105 +

+ +
+
+
+
+ + + diff --git a/dom/permission/tests/test_idle.html b/dom/permission/tests/test_idle.html new file mode 100644 index 000000000..ef37c3efd --- /dev/null +++ b/dom/permission/tests/test_idle.html @@ -0,0 +1,46 @@ + + + + + + Test for Bug 815105 + + + + +Mozilla Bug 815105 +

+ +
+
+
+
+ + + diff --git a/dom/permission/tests/test_input-manage.html b/dom/permission/tests/test_input-manage.html new file mode 100644 index 000000000..a60a19467 --- /dev/null +++ b/dom/permission/tests/test_input-manage.html @@ -0,0 +1,69 @@ + + + + + + Test for Bug 920977 + + + + +Mozilla Bug 920977 +

+ +
+
+
+
+ + + diff --git a/dom/permission/tests/test_keyboard.html b/dom/permission/tests/test_keyboard.html new file mode 100644 index 000000000..f7916afc6 --- /dev/null +++ b/dom/permission/tests/test_keyboard.html @@ -0,0 +1,51 @@ +- + + + + + Test for Bug 920977 + + + + +Mozilla Bug 920977 +

+ +
+
+
+
+ + + diff --git a/dom/permission/tests/test_networkstats-manage.html b/dom/permission/tests/test_networkstats-manage.html new file mode 100644 index 000000000..4fdc84771 --- /dev/null +++ b/dom/permission/tests/test_networkstats-manage.html @@ -0,0 +1,31 @@ + + + + + + Test for Bug 815105 + + + + +Mozilla Bug 815105 +

+ +
+
+
+
+ + + diff --git a/dom/permission/tests/test_permissions.html b/dom/permission/tests/test_permissions.html new file mode 100644 index 000000000..8d629c3da --- /dev/null +++ b/dom/permission/tests/test_permissions.html @@ -0,0 +1,31 @@ + + + + + + Test for Bug 815105 + + + + +Mozilla Bug 815105 +

+ +
+
+
+
+ + + diff --git a/dom/permission/tests/test_permissions_api.html b/dom/permission/tests/test_permissions_api.html new file mode 100644 index 000000000..ded74753c --- /dev/null +++ b/dom/permission/tests/test_permissions_api.html @@ -0,0 +1,206 @@ + + + + + + + Test for Permissions API + + + + + +

+  
+
+
+
diff --git a/dom/permission/tests/test_power.html b/dom/permission/tests/test_power.html
new file mode 100644
index 000000000..51c2e8b53
--- /dev/null
+++ b/dom/permission/tests/test_power.html
@@ -0,0 +1,30 @@
+
+
+
+
+  
+  Test for Bug 815105 
+  
+  
+
+
+Mozilla Bug 815105 
+

+ +
+
+
+
+ + + diff --git a/dom/permission/tests/test_presentation-device-manage.html b/dom/permission/tests/test_presentation-device-manage.html new file mode 100644 index 000000000..67904030a --- /dev/null +++ b/dom/permission/tests/test_presentation-device-manage.html @@ -0,0 +1,38 @@ + + + + + + Test for presentation-device-manage permission + + + + +test presentation-device-manage +

+ +
+
+
+
+ + + diff --git a/dom/permission/tests/test_systemXHR.html b/dom/permission/tests/test_systemXHR.html new file mode 100644 index 000000000..dd16fddfa --- /dev/null +++ b/dom/permission/tests/test_systemXHR.html @@ -0,0 +1,38 @@ + + + + + + Test for Bug 815105 + + + + +Mozilla Bug 815105 +

+ +
+
+
+
+ + + diff --git a/dom/permission/tests/test_tcp-socket.html b/dom/permission/tests/test_tcp-socket.html new file mode 100644 index 000000000..5a80cff85 --- /dev/null +++ b/dom/permission/tests/test_tcp-socket.html @@ -0,0 +1,52 @@ + + + + + + Test for Bug 815105 + + + + +Mozilla Bug 815105 +

+ +
+
+
+
+ + + diff --git a/dom/permission/tests/test_time.html b/dom/permission/tests/test_time.html new file mode 100644 index 000000000..d7fea7031 --- /dev/null +++ b/dom/permission/tests/test_time.html @@ -0,0 +1,30 @@ + + + + + + Test for Bug 815105 + + + + +Mozilla Bug 815105 +

+ +
+
+
+
+ + + diff --git a/dom/permission/tests/test_udp-socket.html b/dom/permission/tests/test_udp-socket.html new file mode 100644 index 000000000..566e7a876 --- /dev/null +++ b/dom/permission/tests/test_udp-socket.html @@ -0,0 +1,47 @@ + + + + + + Test for Bug 745283 + + + + +Mozilla Bug 745283 +

+ +
+
+
+
+ + + diff --git a/dom/permission/tests/test_wifi-manage.html b/dom/permission/tests/test_wifi-manage.html new file mode 100644 index 000000000..94d17b682 --- /dev/null +++ b/dom/permission/tests/test_wifi-manage.html @@ -0,0 +1,41 @@ + + + + + + Test for Bug 815105 + + + + +Mozilla Bug 815105 +

+ +
+
+
+
+ + + diff --git a/dom/permission/tests/unit/test_bug808734.js b/dom/permission/tests/unit/test_bug808734.js new file mode 100644 index 000000000..8dfbd9458 --- /dev/null +++ b/dom/permission/tests/unit/test_bug808734.js @@ -0,0 +1,73 @@ +var Cu = Components.utils; +const READWRITE = "readwrite"; +const UNKNOWN = "foobar"; + +var gData = [ +// test normal expansion +{ + permission: "contacts", + access: READWRITE, + expected: ["contacts-read", "contacts-create", + "contacts-write"] +}, +// test additional expansion and access not having read+create+write +{ + permission: "settings", + access: READWRITE, + expected: ["settings-read", "settings-write", + "settings-api-read", "settings-api-write", + "indexedDB-chrome-settings-read", + "indexedDB-chrome-settings-write"] +}, +// test unknown access +{ + permission: "contacts", + access: UNKNOWN, + expected: [] +}, +// test unknown permission +{ + permission: UNKNOWN, + access: READWRITE, + expected: [] +} +]; + +// check if 2 arrays contain the same elements +function do_check_set_eq(a1, a2) { + do_check_eq(a1.length, a2.length) + + Array.sort(a1); + Array.sort(a2); + + for (let i = 0; i < a1.length; ++i) { + do_check_eq(a1[i], a2[i]) + } +} + +function test_substitute_does_not_break_substituted(scope) { + const Ci = Components.interfaces; + + // geolocation-noprompt substitutes for geolocation ... + do_check_eq(scope.PermissionsTable["geolocation-noprompt"].substitute[0], + "geolocation"); + // ... and sets silent allow ... + do_check_eq(scope.PermissionsTable["geolocation-noprompt"].certified, + Ci.nsIPermissionManager.ALLOW_ACTION) + // ... which works ... + do_check_false(scope.isExplicitInPermissionsTable("geolocation-noprompt", Ci.nsIPrincipal.APP_STATUS_CERTIFIED)); + // ... but does not interfere with geolocation's PROMPT value + do_check_true(scope.isExplicitInPermissionsTable("geolocation", Ci.nsIPrincipal.APP_STATUS_CERTIFIED)); +} + +function run_test() { + var scope = {}; + Cu.import("resource://gre/modules/PermissionsTable.jsm", scope); + + for (var i = 0; i < gData.length; i++) { + var perms = scope.expandPermissions(gData[i].permission, + gData[i].access); + do_check_set_eq(perms, gData[i].expected); + } + test_substitute_does_not_break_substituted(scope); +} diff --git a/dom/permission/tests/unit/xpcshell.ini b/dom/permission/tests/unit/xpcshell.ini new file mode 100644 index 000000000..1c296a77c --- /dev/null +++ b/dom/permission/tests/unit/xpcshell.ini @@ -0,0 +1,5 @@ +[DEFAULT] +head = +tail = + +[test_bug808734.js] -- cgit v1.2.3