summaryrefslogtreecommitdiffstats
path: root/b2g/components/ContentPermissionPrompt.js
diff options
context:
space:
mode:
Diffstat (limited to 'b2g/components/ContentPermissionPrompt.js')
-rw-r--r--b2g/components/ContentPermissionPrompt.js461
1 files changed, 0 insertions, 461 deletions
diff --git a/b2g/components/ContentPermissionPrompt.js b/b2g/components/ContentPermissionPrompt.js
deleted file mode 100644
index e11b1b458..000000000
--- a/b2g/components/ContentPermissionPrompt.js
+++ /dev/null
@@ -1,461 +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/. */
-
-"use strict"
-
-function debug(str) {
- //dump("-*- ContentPermissionPrompt: " + str + "\n");
-}
-
-const Ci = Components.interfaces;
-const Cr = Components.results;
-const Cu = Components.utils;
-const Cc = Components.classes;
-
-const PROMPT_FOR_UNKNOWN = ["audio-capture",
- "desktop-notification",
- "geolocation",
- "video-capture"];
-// Due to privary issue, permission requests like GetUserMedia should prompt
-// every time instead of providing session persistence.
-const PERMISSION_NO_SESSION = ["audio-capture", "video-capture"];
-const ALLOW_MULTIPLE_REQUESTS = ["audio-capture", "video-capture"];
-
-Cu.import("resource://gre/modules/XPCOMUtils.jsm");
-Cu.import("resource://gre/modules/Services.jsm");
-Cu.import("resource://gre/modules/AppsUtils.jsm");
-Cu.import("resource://gre/modules/PermissionsInstaller.jsm");
-Cu.import("resource://gre/modules/PermissionsTable.jsm");
-
-var permissionManager = Cc["@mozilla.org/permissionmanager;1"].getService(Ci.nsIPermissionManager);
-var secMan = Cc["@mozilla.org/scriptsecuritymanager;1"].getService(Ci.nsIScriptSecurityManager);
-
-var permissionSpecificChecker = {};
-
-XPCOMUtils.defineLazyModuleGetter(this, "SystemAppProxy",
- "resource://gre/modules/SystemAppProxy.jsm");
-
-/**
- * Determine if a permission should be prompt to user or not.
- *
- * @param aPerm requested permission
- * @param aAction the action according to principal
- * @return true if prompt is required
- */
-function shouldPrompt(aPerm, aAction) {
- return ((aAction == Ci.nsIPermissionManager.PROMPT_ACTION) ||
- (aAction == Ci.nsIPermissionManager.UNKNOWN_ACTION &&
- PROMPT_FOR_UNKNOWN.indexOf(aPerm) >= 0));
-}
-
-/**
- * Create the default choices for the requested permissions
- *
- * @param aTypesInfo requested permissions
- * @return the default choices for permissions with options, return
- * undefined if no option in all requested permissions.
- */
-function buildDefaultChoices(aTypesInfo) {
- let choices;
- for (let type of aTypesInfo) {
- if (type.options.length > 0) {
- if (!choices) {
- choices = {};
- }
- choices[type.access] = type.options[0];
- }
- }
- return choices;
-}
-
-/**
- * aTypesInfo is an array of {permission, access, action, deny} which keeps
- * the information of each permission. This arrary is initialized in
- * ContentPermissionPrompt.prompt and used among functions.
- *
- * aTypesInfo[].permission : permission name
- * aTypesInfo[].access : permission name + request.access
- * aTypesInfo[].action : the default action of this permission
- * aTypesInfo[].deny : true if security manager denied this app's origin
- * principal.
- * Note:
- * aTypesInfo[].permission will be sent to prompt only when
- * aTypesInfo[].action is PROMPT_ACTION and aTypesInfo[].deny is false.
- */
-function rememberPermission(aTypesInfo, aPrincipal, aSession)
-{
- function convertPermToAllow(aPerm, aPrincipal)
- {
- let type =
- permissionManager.testExactPermissionFromPrincipal(aPrincipal, aPerm);
- if (shouldPrompt(aPerm, type)) {
- debug("add " + aPerm + " to permission manager with ALLOW_ACTION");
- if (!aSession) {
- permissionManager.addFromPrincipal(aPrincipal,
- aPerm,
- Ci.nsIPermissionManager.ALLOW_ACTION);
- } else if (PERMISSION_NO_SESSION.indexOf(aPerm) < 0) {
- permissionManager.addFromPrincipal(aPrincipal,
- aPerm,
- Ci.nsIPermissionManager.ALLOW_ACTION,
- Ci.nsIPermissionManager.EXPIRE_SESSION, 0);
- }
- }
- }
-
- for (let i in aTypesInfo) {
- // Expand the permission to see if we have multiple access properties
- // to convert
- let perm = aTypesInfo[i].permission;
- let access = PermissionsTable[perm].access;
- if (access) {
- for (let idx in access) {
- convertPermToAllow(perm + "-" + access[idx], aPrincipal);
- }
- } else {
- convertPermToAllow(perm, aPrincipal);
- }
- }
-}
-
-function ContentPermissionPrompt() {}
-
-ContentPermissionPrompt.prototype = {
-
- handleExistingPermission: function handleExistingPermission(request,
- typesInfo) {
- typesInfo.forEach(function(type) {
- type.action =
- Services.perms.testExactPermissionFromPrincipal(request.principal,
- type.access);
- if (shouldPrompt(type.access, type.action)) {
- type.action = Ci.nsIPermissionManager.PROMPT_ACTION;
- }
- });
-
- // If all permissions are allowed already and no more than one option,
- // call allow() without prompting.
- let checkAllowPermission = function(type) {
- if (type.action == Ci.nsIPermissionManager.ALLOW_ACTION &&
- type.options.length <= 1) {
- return true;
- }
- return false;
- }
- if (typesInfo.every(checkAllowPermission)) {
- debug("all permission requests are allowed");
- request.allow(buildDefaultChoices(typesInfo));
- return true;
- }
-
- // If all permissions are DENY_ACTION or UNKNOWN_ACTION, call cancel()
- // without prompting.
- let checkDenyPermission = function(type) {
- if (type.action == Ci.nsIPermissionManager.DENY_ACTION ||
- type.action == Ci.nsIPermissionManager.UNKNOWN_ACTION) {
- return true;
- }
- return false;
- }
- if (typesInfo.every(checkDenyPermission)) {
- debug("all permission requests are denied");
- request.cancel();
- return true;
- }
- return false;
- },
-
- // multiple requests should be audio and video
- checkMultipleRequest: function checkMultipleRequest(typesInfo) {
- if (typesInfo.length == 1) {
- return true;
- } else if (typesInfo.length > 1) {
- let checkIfAllowMultiRequest = function(type) {
- return (ALLOW_MULTIPLE_REQUESTS.indexOf(type.access) !== -1);
- }
- if (typesInfo.every(checkIfAllowMultiRequest)) {
- debug("legal multiple requests");
- return true;
- }
- }
-
- return false;
- },
-
- handledByApp: function handledByApp(request, typesInfo) {
- if (request.principal.appId == Ci.nsIScriptSecurityManager.NO_APP_ID ||
- request.principal.appId == Ci.nsIScriptSecurityManager.UNKNOWN_APP_ID) {
- // This should not really happen
- request.cancel();
- return true;
- }
-
- let appsService = Cc["@mozilla.org/AppsService;1"]
- .getService(Ci.nsIAppsService);
- let app = appsService.getAppByLocalId(request.principal.appId);
-
- // Check each permission if it's denied by permission manager with app's
- // URL.
- let notDenyAppPrincipal = function(type) {
- let url = Services.io.newURI(app.origin, null, null);
- let principal =
- secMan.createCodebasePrincipal(url,
- {appId: request.principal.appId});
- let result = Services.perms.testExactPermissionFromPrincipal(principal,
- type.access);
-
- if (result == Ci.nsIPermissionManager.ALLOW_ACTION ||
- result == Ci.nsIPermissionManager.PROMPT_ACTION) {
- type.deny = false;
- }
- return !type.deny;
- }
- // Cancel the entire request if one of the requested permissions is denied
- if (!typesInfo.every(notDenyAppPrincipal)) {
- request.cancel();
- return true;
- }
-
- return false;
- },
-
- handledByPermissionType: function handledByPermissionType(request, typesInfo) {
- for (let i in typesInfo) {
- if (permissionSpecificChecker.hasOwnProperty(typesInfo[i].permission) &&
- permissionSpecificChecker[typesInfo[i].permission](request)) {
- return true;
- }
- }
-
- return false;
- },
-
- prompt: function(request) {
- // Initialize the typesInfo and set the default value.
- let typesInfo = [];
- let perms = request.types.QueryInterface(Ci.nsIArray);
- for (let idx = 0; idx < perms.length; idx++) {
- let perm = perms.queryElementAt(idx, Ci.nsIContentPermissionType);
- let tmp = {
- permission: perm.type,
- access: (perm.access && perm.access !== "unused") ?
- perm.type + "-" + perm.access : perm.type,
- options: [],
- deny: true,
- action: Ci.nsIPermissionManager.UNKNOWN_ACTION
- };
-
- // Append available options, if any.
- let options = perm.options.QueryInterface(Ci.nsIArray);
- for (let i = 0; i < options.length; i++) {
- let option = options.queryElementAt(i, Ci.nsISupportsString).data;
- tmp.options.push(option);
- }
- typesInfo.push(tmp);
- }
-
- if (secMan.isSystemPrincipal(request.principal)) {
- request.allow(buildDefaultChoices(typesInfo));
- return;
- }
-
-
- if (typesInfo.length == 0) {
- request.cancel();
- return;
- }
-
- if(!this.checkMultipleRequest(typesInfo)) {
- request.cancel();
- return;
- }
-
- if (this.handledByApp(request, typesInfo) ||
- this.handledByPermissionType(request, typesInfo)) {
- return;
- }
-
- // returns true if the request was handled
- if (this.handleExistingPermission(request, typesInfo)) {
- return;
- }
-
- // prompt PROMPT_ACTION request or request with options.
- typesInfo = typesInfo.filter(function(type) {
- return !type.deny && (type.action == Ci.nsIPermissionManager.PROMPT_ACTION || type.options.length > 0) ;
- });
-
- if (!request.element) {
- this.delegatePrompt(request, typesInfo);
- return;
- }
-
- var cancelRequest = function() {
- request.requester.onVisibilityChange = null;
- request.cancel();
- }
-
- var self = this;
-
- // If the request was initiated from a hidden iframe
- // we don't forward it to content and cancel it right away
- request.requester.getVisibility( {
- notifyVisibility: function(isVisible) {
- if (!isVisible) {
- cancelRequest();
- return;
- }
-
- // Monitor the frame visibility and cancel the request if the frame goes
- // away but the request is still here.
- request.requester.onVisibilityChange = {
- notifyVisibility: function(isVisible) {
- if (isVisible)
- return;
-
- self.cancelPrompt(request, typesInfo);
- cancelRequest();
- }
- }
-
- self.delegatePrompt(request, typesInfo, function onCallback() {
- request.requester.onVisibilityChange = null;
- });
- }
- });
-
- },
-
- cancelPrompt: function(request, typesInfo) {
- this.sendToBrowserWindow("cancel-permission-prompt", request,
- typesInfo);
- },
-
- delegatePrompt: function(request, typesInfo, callback) {
- this.sendToBrowserWindow("permission-prompt", request, typesInfo,
- function(type, remember, choices) {
- if (type == "permission-allow") {
- rememberPermission(typesInfo, request.principal, !remember);
- if (callback) {
- callback();
- }
- request.allow(choices);
- return;
- }
-
- let addDenyPermission = function(type) {
- debug("add " + type.permission +
- " to permission manager with DENY_ACTION");
- if (remember) {
- Services.perms.addFromPrincipal(request.principal, type.access,
- Ci.nsIPermissionManager.DENY_ACTION);
- } else if (PERMISSION_NO_SESSION.indexOf(type.access) < 0) {
- Services.perms.addFromPrincipal(request.principal, type.access,
- Ci.nsIPermissionManager.DENY_ACTION,
- Ci.nsIPermissionManager.EXPIRE_SESSION,
- 0);
- }
- }
- try {
- // This will trow if we are canceling because the remote process died.
- // Just eat the exception and call the callback that will cleanup the
- // visibility event listener.
- typesInfo.forEach(addDenyPermission);
- } catch(e) { }
-
- if (callback) {
- callback();
- }
-
- try {
- request.cancel();
- } catch(e) { }
- });
- },
-
- sendToBrowserWindow: function(type, request, typesInfo, callback) {
- let requestId = Cc["@mozilla.org/uuid-generator;1"]
- .getService(Ci.nsIUUIDGenerator).generateUUID().toString();
- if (callback) {
- SystemAppProxy.addEventListener("mozContentEvent", function contentEvent(evt) {
- let detail = evt.detail;
- if (detail.id != requestId)
- return;
- SystemAppProxy.removeEventListener("mozContentEvent", contentEvent);
-
- callback(detail.type, detail.remember, detail.choices);
- })
- }
-
- let principal = request.principal;
- let isApp = principal.appStatus != Ci.nsIPrincipal.APP_STATUS_NOT_INSTALLED;
- let remember = (principal.appStatus == Ci.nsIPrincipal.APP_STATUS_PRIVILEGED ||
- principal.appStatus == Ci.nsIPrincipal.APP_STATUS_CERTIFIED)
- ? true
- : request.remember;
- let isGranted = typesInfo.every(function(type) {
- return type.action == Ci.nsIPermissionManager.ALLOW_ACTION;
- });
- let permissions = {};
- for (let i in typesInfo) {
- debug("prompt " + typesInfo[i].permission);
- permissions[typesInfo[i].permission] = typesInfo[i].options;
- }
-
- let details = {
- type: type,
- permissions: permissions,
- id: requestId,
- // This system app uses the origin from permission events to
- // compare against the mozApp.origin of app windows, so we
- // are not concerned with origin suffixes here (appId, etc).
- origin: principal.originNoSuffix,
- isApp: isApp,
- remember: remember,
- isGranted: isGranted,
- };
-
- if (isApp) {
- details.manifestURL = DOMApplicationRegistry.getManifestURLByLocalId(principal.appId);
- }
-
- // request.element is defined for OOP content, while request.window
- // is defined for In-Process content.
- // In both cases the message needs to be dispatched to the top-level
- // <iframe mozbrowser> container in the system app.
- // So the above code iterates over window.realFrameElement in order
- // to crosss mozbrowser iframes boundaries and find the top-level
- // one in the system app.
- // window.realFrameElement will be |null| if the code try to cross
- // content -> chrome boundaries.
- let targetElement = request.element;
- let targetWindow = request.window || targetElement.ownerDocument.defaultView;
- while (targetWindow.realFrameElement) {
- targetElement = targetWindow.realFrameElement;
- targetWindow = targetElement.ownerDocument.defaultView;
- }
-
- SystemAppProxy.dispatchEvent(details, targetElement);
- },
-
- classID: Components.ID("{8c719f03-afe0-4aac-91ff-6c215895d467}"),
-
- QueryInterface: XPCOMUtils.generateQI([Ci.nsIContentPermissionPrompt])
-};
-
-(function() {
- // Do not allow GetUserMedia while in call.
- permissionSpecificChecker["audio-capture"] = function(request) {
- let forbid = false;
-
- if (forbid) {
- request.cancel();
- }
-
- return forbid;
- };
-})();
-
-//module initialization
-this.NSGetFactory = XPCOMUtils.generateNSGetFactory([ContentPermissionPrompt]);