/* 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/. */ this.EXPORTED_SYMBOLS = [ "SitePermissions" ]; Components.utils.import("resource://gre/modules/Services.jsm"); var gStringBundle = Services.strings.createBundle("chrome://browser/locale/sitePermissions.properties"); this.SitePermissions = { UNKNOWN: Services.perms.UNKNOWN_ACTION, ALLOW: Services.perms.ALLOW_ACTION, BLOCK: Services.perms.DENY_ACTION, SESSION: Components.interfaces.nsICookiePermission.ACCESS_SESSION, /* Returns all custom permissions for a given URI, the return * type is a list of objects with the keys: * - id: the permissionId of the permission * - state: a constant representing the current permission state * (e.g. SitePermissions.ALLOW) * * To receive a more detailed, albeit less performant listing see * SitePermissions.getPermissionDetailsByURI(). * * install addon permission is excluded, check bug 1303108 */ getAllByURI: function (aURI) { let result = []; if (!this.isSupportedURI(aURI)) { return result; } let permissions = Services.perms.getAllForURI(aURI); while (permissions.hasMoreElements()) { let permission = permissions.getNext(); // filter out unknown permissions if (gPermissionObject[permission.type]) { // XXX Bug 1303108 - Control Center should only show non-default permissions if (permission.type == "install") { continue; } result.push({ id: permission.type, state: permission.capability, }); } } return result; }, /* Returns an object representing the aId permission. It contains the * following keys: * - id: the permissionID of the permission * - label: the localized label * - state: a constant representing the aState permission state * (e.g. SitePermissions.ALLOW), or the default if aState is omitted * - availableStates: an array of all available states for that permission, * represented as objects with the keys: * - id: the state constant * - label: the translated label of that state */ getPermissionItem: function (aId, aState) { let availableStates = this.getAvailableStates(aId).map(state => { return { id: state, label: this.getStateLabel(aId, state) }; }); if (aState == undefined) aState = this.getDefault(aId); return {id: aId, label: this.getPermissionLabel(aId), state: aState, availableStates}; }, /* Returns a list of objects representing all permissions that are currently * set for the given URI. See getPermissionItem for the content of each object. */ getPermissionDetailsByURI: function (aURI) { let permissions = []; for (let {state, id} of this.getAllByURI(aURI)) { permissions.push(this.getPermissionItem(id, state)); } return permissions; }, /* Checks whether a UI for managing permissions should be exposed for a given * URI. This excludes file URIs, for instance, as they don't have a host, * even though nsIPermissionManager can still handle them. */ isSupportedURI: function (aURI) { return aURI.schemeIs("http") || aURI.schemeIs("https"); }, /* Returns an array of all permission IDs. */ listPermissions: function () { return Object.keys(gPermissionObject); }, /* Returns an array of permission states to be exposed to the user for a * permission with the given ID. */ getAvailableStates: function (aPermissionID) { if (aPermissionID in gPermissionObject && gPermissionObject[aPermissionID].states) return gPermissionObject[aPermissionID].states; if (this.getDefault(aPermissionID) == this.UNKNOWN) return [ SitePermissions.UNKNOWN, SitePermissions.ALLOW, SitePermissions.BLOCK ]; return [ SitePermissions.ALLOW, SitePermissions.BLOCK ]; }, /* Returns the default state of a particular permission. */ getDefault: function (aPermissionID) { if (aPermissionID in gPermissionObject && gPermissionObject[aPermissionID].getDefault) return gPermissionObject[aPermissionID].getDefault(); return this.UNKNOWN; }, /* Returns the state of a particular permission for a given URI. */ get: function (aURI, aPermissionID) { if (!this.isSupportedURI(aURI)) return this.UNKNOWN; let state; if (aPermissionID in gPermissionObject && gPermissionObject[aPermissionID].exactHostMatch) state = Services.perms.testExactPermission(aURI, aPermissionID); else state = Services.perms.testPermission(aURI, aPermissionID); return state; }, /* Sets the state of a particular permission for a given URI. */ set: function (aURI, aPermissionID, aState) { if (!this.isSupportedURI(aURI)) return; if (aState == this.UNKNOWN) { this.remove(aURI, aPermissionID); return; } Services.perms.add(aURI, aPermissionID, aState); }, /* Removes the saved state of a particular permission for a given URI. */ remove: function (aURI, aPermissionID) { if (!this.isSupportedURI(aURI)) return; Services.perms.remove(aURI, aPermissionID); }, /* Returns the localized label for the permission with the given ID, to be * used in a UI for managing permissions. */ getPermissionLabel: function (aPermissionID) { let labelID = gPermissionObject[aPermissionID].labelID || aPermissionID; return gStringBundle.GetStringFromName("permission." + labelID + ".label"); }, /* Returns the localized label for the given permission state, to be used in * a UI for managing permissions. */ getStateLabel: function (aPermissionID, aState, aInUse = false) { switch (aState) { case this.UNKNOWN: if (aInUse) return gStringBundle.GetStringFromName("allowTemporarily"); return gStringBundle.GetStringFromName("alwaysAsk"); case this.ALLOW: return gStringBundle.GetStringFromName("allow"); case this.SESSION: return gStringBundle.GetStringFromName("allowForSession"); case this.BLOCK: return gStringBundle.GetStringFromName("block"); default: return null; } } }; var gPermissionObject = { /* Holds permission ID => options pairs. * * Supported options: * * - exactHostMatch * Allows sub domains to have their own permissions. * Defaults to false. * * - getDefault * Called to get the permission's default state. * Defaults to UNKNOWN, indicating that the user will be asked each time * a page asks for that permissions. * * - labelID * Use the given ID instead of the permission name for looking up strings. * e.g. "desktop-notification2" to use permission.desktop-notification2.label * * - states * Array of permission states to be exposed to the user. * Defaults to ALLOW, BLOCK and the default state (see getDefault). */ "image": { getDefault: function () { return Services.prefs.getIntPref("permissions.default.image") == 2 ? SitePermissions.BLOCK : SitePermissions.ALLOW; } }, "cookie": { states: [ SitePermissions.ALLOW, SitePermissions.SESSION, SitePermissions.BLOCK ], getDefault: function () { if (Services.prefs.getIntPref("network.cookie.cookieBehavior") == 2) return SitePermissions.BLOCK; if (Services.prefs.getIntPref("network.cookie.lifetimePolicy") == 2) return SitePermissions.SESSION; return SitePermissions.ALLOW; } }, "desktop-notification": { exactHostMatch: true, labelID: "desktop-notification2", }, "camera": {}, "microphone": {}, "screen": { states: [ SitePermissions.UNKNOWN, SitePermissions.BLOCK ], }, "popup": { getDefault: function () { return Services.prefs.getBoolPref("dom.disable_open_during_load") ? SitePermissions.BLOCK : SitePermissions.ALLOW; } }, "install": { getDefault: function () { return Services.prefs.getBoolPref("xpinstall.whitelist.required") ? SitePermissions.BLOCK : SitePermissions.ALLOW; } }, "geo": { exactHostMatch: true }, }; const kPermissionIDs = Object.keys(gPermissionObject);