Loading browser/modules/SitePermissions.jsm +116 −15 Original line number Diff line number Diff line Loading @@ -275,6 +275,7 @@ var SitePermissions = { _defaultPrefBranch: Services.prefs.getBranch("permissions.default."), /** * Deprecated! Please use getAllByPrincipal(principal) instead. * Gets all custom permissions for a given URI. * Install addon permission is excluded, check bug 1303108. * Loading @@ -288,12 +289,28 @@ var SitePermissions = { if (!(uri instanceof Ci.nsIURI)) { throw new Error("uri parameter should be an nsIURI"); } let principal = uri ? Services.scriptSecurityManager.createCodebasePrincipal(uri, {}) : null; return this.getAllByPrincipal(principal); }, /** * Gets all custom permissions for a given principal. * Install addon permission is excluded, check bug 1303108. * * @return {Array} a list of objects with the keys: * - id: the permissionId of the permission * - scope: the scope of the permission (e.g. SitePermissions.SCOPE_TEMPORARY) * - state: a constant representing the current permission state * (e.g. SitePermissions.ALLOW) */ getAllByPrincipal(principal) { let result = []; if (!this.isSupportedURI(uri)) { if (!this.isSupportedPrincipal(principal)) { return result; } let permissions = Services.perms.getAllForURI(uri); let permissions = Services.perms.getAllForPrincipal(principal); while (permissions.hasMoreElements()) { let permission = permissions.getNext(); Loading Loading @@ -350,7 +367,7 @@ var SitePermissions = { permissions[permission.id] = permission; } for (let permission of this.getAllByURI(browser.currentURI)) { for (let permission of this.getAllByPrincipal(browser.contentPrincipal)) { permissions[permission.id] = permission; } Loading Loading @@ -382,6 +399,7 @@ var SitePermissions = { }, /** * Deprecated! Please use isSupportedPrincipal(principal) instead. * 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. Loading @@ -395,6 +413,21 @@ var SitePermissions = { return uri && ["http", "https", "moz-extension"].includes(uri.scheme); }, /** * Checks whether a UI for managing permissions should be exposed for a given * principal. This excludes file URIs, for instance, as they don't have a host, * even though nsIPermissionManager can still handle them. * * @param {nsIPrincipal} principal * The principal to check. * * @return {boolean} if the principal is supported. */ isSupportedPrincipal(principal) { return principal && principal.URI && ["http", "https", "moz-extension"].includes(principal.URI.scheme); }, /** * Gets an array of all permission IDs. * Loading Loading @@ -512,22 +545,47 @@ var SitePermissions = { "uri parameter should be an nsIURI or a browser parameter is needed" ); } let principal = uri ? Services.scriptSecurityManager.createCodebasePrincipal(uri, {}) : null; return this.getForPrincipal(principal, permissionID, browser); }, /** * Returns the state and scope of a particular permission for a given principal. * * This method will NOT dispatch a "PermissionStateChange" event on the specified * browser if a temporary permission was removed because it has expired. * * @param {nsIPrincipal} principal * The principal to check. * @param {String} permissionID * The id of the permission. * @param {Browser} browser (optional) * The browser object to check for temporary permissions. * * @return {Object} an object with the keys: * - state: The current state of the permission * (e.g. SitePermissions.ALLOW) * - scope: The scope of the permission * (e.g. SitePermissions.SCOPE_PERSISTENT) */ getForPrincipal(principal, permissionID, browser) { let defaultState = this.getDefault(permissionID); let result = { state: defaultState, scope: this.SCOPE_PERSISTENT }; if (this.isSupportedURI(uri)) { if (this.isSupportedPrincipal(principal)) { let permission = null; if ( permissionID in gPermissionObject && gPermissionObject[permissionID].exactHostMatch ) { permission = Services.perms.getPermissionObjectForURI( uri, permission = Services.perms.getPermissionObject( principal, permissionID, true ); } else { permission = Services.perms.getPermissionObjectForURI( uri, permission = Services.perms.getPermissionObject( principal, permissionID, false ); Loading Loading @@ -558,6 +616,7 @@ var SitePermissions = { }, /** * Deprecated! Use setForPrincipal(...) instead. * Sets the state of a particular permission for a given URI or browser. * This method will dispatch a "PermissionStateChange" event on the specified * browser if a temporary permission was set Loading @@ -581,6 +640,30 @@ var SitePermissions = { "uri parameter should be an nsIURI or a browser parameter is needed" ); } let principal = uri ? Services.scriptSecurityManager.createCodebasePrincipal(uri, {}) : null; return this.setForPrincipal(principal, permissionID, state, scope, browser); }, /** * Sets the state of a particular permission for a given principal or browser. * This method will dispatch a "PermissionStateChange" event on the specified * browser if a temporary permission was set * * @param {nsIPrincipal} principal * The principal to set the permission for. * Note that this will be ignored if the scope is set to SCOPE_TEMPORARY * @param {String} permissionID * The id of the permission. * @param {SitePermissions state} state * The state of the permission. * @param {SitePermissions scope} scope (optional) * The scope of the permission. Defaults to SCOPE_PERSISTENT. * @param {Browser} browser (optional) * The browser object to set temporary permissions on. * This needs to be provided if the scope is SCOPE_TEMPORARY! */ setForPrincipal(principal, permissionID, state, scope = this.SCOPE_PERSISTENT, browser = null) { if (scope == this.SCOPE_GLOBAL && state == this.BLOCK) { GloballyBlockedPermissions.set(browser, permissionID); browser.dispatchEvent( Loading @@ -594,7 +677,7 @@ var SitePermissions = { // correspond to the classical ALLOW/DENY/PROMPT model, we want to always // allow the user to add exceptions to their cookie rules without removing them. if (permissionID != "cookie") { this.remove(uri, permissionID, browser); this.removeFromPrincipal(principal, permissionID, browser); return; } } Loading @@ -610,7 +693,7 @@ var SitePermissions = { // We do not support setting temp ALLOW for security reasons. // In its current state, this permission could be exploited by subframes // on the same page. This is because for BLOCK we ignore the request // URI and only consider the current browser URI, to avoid notification spamming. // principal and only consider the current browser principal, to avoid notification spamming. // // If you ever consider removing this line, you likely want to implement // a more fine-grained TemporaryPermissions that temporarily blocks for the Loading @@ -632,7 +715,7 @@ var SitePermissions = { browser.dispatchEvent( new browser.ownerGlobal.CustomEvent("PermissionStateChange") ); } else if (this.isSupportedURI(uri)) { } else if (this.isSupportedPrincipal(principal)) { let perms_scope = Services.perms.EXPIRE_NEVER; if (scope == this.SCOPE_SESSION) { perms_scope = Services.perms.EXPIRE_SESSION; Loading @@ -640,11 +723,12 @@ var SitePermissions = { perms_scope = Services.perms.EXPIRE_POLICY; } Services.perms.add(uri, permissionID, state, perms_scope); Services.perms.addFromPrincipal(principal, permissionID, state, perms_scope); } }, /** * Deprecated! Please use removeFromPrincipal(principal, permissionID, browser). * Removes the saved state of a particular permission for a given URI and/or browser. * This method will dispatch a "PermissionStateChange" event on the specified * browser if a temporary permission was removed. Loading @@ -662,9 +746,26 @@ var SitePermissions = { "uri parameter should be an nsIURI or a browser parameter is needed" ); } if (this.isSupportedURI(uri)) { Services.perms.remove(uri, permissionID); } let principal = uri ? Services.scriptSecurityManager.createCodebasePrincipal(uri, {}) : null; return this.removeFromPrincipal(principal, permissionID, browser); }, /** * Removes the saved state of a particular permission for a given principal and/or browser. * This method will dispatch a "PermissionStateChange" event on the specified * browser if a temporary permission was removed. * * @param {nsIPrincipal} principal * The principal to remove the permission for. * @param {String} permissionID * The id of the permission. * @param {Browser} browser (optional) * The browser object to remove temporary permissions on. */ removeFromPrincipal(principal, permissionID, browser) { if (this.isSupportedPrincipal(principal)) Services.perms.removeFromPrincipal(principal, permissionID); // TemporaryPermissions.get() deletes expired permissions automatically, if (TemporaryPermissions.get(browser, permissionID)) { Loading Loading
browser/modules/SitePermissions.jsm +116 −15 Original line number Diff line number Diff line Loading @@ -275,6 +275,7 @@ var SitePermissions = { _defaultPrefBranch: Services.prefs.getBranch("permissions.default."), /** * Deprecated! Please use getAllByPrincipal(principal) instead. * Gets all custom permissions for a given URI. * Install addon permission is excluded, check bug 1303108. * Loading @@ -288,12 +289,28 @@ var SitePermissions = { if (!(uri instanceof Ci.nsIURI)) { throw new Error("uri parameter should be an nsIURI"); } let principal = uri ? Services.scriptSecurityManager.createCodebasePrincipal(uri, {}) : null; return this.getAllByPrincipal(principal); }, /** * Gets all custom permissions for a given principal. * Install addon permission is excluded, check bug 1303108. * * @return {Array} a list of objects with the keys: * - id: the permissionId of the permission * - scope: the scope of the permission (e.g. SitePermissions.SCOPE_TEMPORARY) * - state: a constant representing the current permission state * (e.g. SitePermissions.ALLOW) */ getAllByPrincipal(principal) { let result = []; if (!this.isSupportedURI(uri)) { if (!this.isSupportedPrincipal(principal)) { return result; } let permissions = Services.perms.getAllForURI(uri); let permissions = Services.perms.getAllForPrincipal(principal); while (permissions.hasMoreElements()) { let permission = permissions.getNext(); Loading Loading @@ -350,7 +367,7 @@ var SitePermissions = { permissions[permission.id] = permission; } for (let permission of this.getAllByURI(browser.currentURI)) { for (let permission of this.getAllByPrincipal(browser.contentPrincipal)) { permissions[permission.id] = permission; } Loading Loading @@ -382,6 +399,7 @@ var SitePermissions = { }, /** * Deprecated! Please use isSupportedPrincipal(principal) instead. * 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. Loading @@ -395,6 +413,21 @@ var SitePermissions = { return uri && ["http", "https", "moz-extension"].includes(uri.scheme); }, /** * Checks whether a UI for managing permissions should be exposed for a given * principal. This excludes file URIs, for instance, as they don't have a host, * even though nsIPermissionManager can still handle them. * * @param {nsIPrincipal} principal * The principal to check. * * @return {boolean} if the principal is supported. */ isSupportedPrincipal(principal) { return principal && principal.URI && ["http", "https", "moz-extension"].includes(principal.URI.scheme); }, /** * Gets an array of all permission IDs. * Loading Loading @@ -512,22 +545,47 @@ var SitePermissions = { "uri parameter should be an nsIURI or a browser parameter is needed" ); } let principal = uri ? Services.scriptSecurityManager.createCodebasePrincipal(uri, {}) : null; return this.getForPrincipal(principal, permissionID, browser); }, /** * Returns the state and scope of a particular permission for a given principal. * * This method will NOT dispatch a "PermissionStateChange" event on the specified * browser if a temporary permission was removed because it has expired. * * @param {nsIPrincipal} principal * The principal to check. * @param {String} permissionID * The id of the permission. * @param {Browser} browser (optional) * The browser object to check for temporary permissions. * * @return {Object} an object with the keys: * - state: The current state of the permission * (e.g. SitePermissions.ALLOW) * - scope: The scope of the permission * (e.g. SitePermissions.SCOPE_PERSISTENT) */ getForPrincipal(principal, permissionID, browser) { let defaultState = this.getDefault(permissionID); let result = { state: defaultState, scope: this.SCOPE_PERSISTENT }; if (this.isSupportedURI(uri)) { if (this.isSupportedPrincipal(principal)) { let permission = null; if ( permissionID in gPermissionObject && gPermissionObject[permissionID].exactHostMatch ) { permission = Services.perms.getPermissionObjectForURI( uri, permission = Services.perms.getPermissionObject( principal, permissionID, true ); } else { permission = Services.perms.getPermissionObjectForURI( uri, permission = Services.perms.getPermissionObject( principal, permissionID, false ); Loading Loading @@ -558,6 +616,7 @@ var SitePermissions = { }, /** * Deprecated! Use setForPrincipal(...) instead. * Sets the state of a particular permission for a given URI or browser. * This method will dispatch a "PermissionStateChange" event on the specified * browser if a temporary permission was set Loading @@ -581,6 +640,30 @@ var SitePermissions = { "uri parameter should be an nsIURI or a browser parameter is needed" ); } let principal = uri ? Services.scriptSecurityManager.createCodebasePrincipal(uri, {}) : null; return this.setForPrincipal(principal, permissionID, state, scope, browser); }, /** * Sets the state of a particular permission for a given principal or browser. * This method will dispatch a "PermissionStateChange" event on the specified * browser if a temporary permission was set * * @param {nsIPrincipal} principal * The principal to set the permission for. * Note that this will be ignored if the scope is set to SCOPE_TEMPORARY * @param {String} permissionID * The id of the permission. * @param {SitePermissions state} state * The state of the permission. * @param {SitePermissions scope} scope (optional) * The scope of the permission. Defaults to SCOPE_PERSISTENT. * @param {Browser} browser (optional) * The browser object to set temporary permissions on. * This needs to be provided if the scope is SCOPE_TEMPORARY! */ setForPrincipal(principal, permissionID, state, scope = this.SCOPE_PERSISTENT, browser = null) { if (scope == this.SCOPE_GLOBAL && state == this.BLOCK) { GloballyBlockedPermissions.set(browser, permissionID); browser.dispatchEvent( Loading @@ -594,7 +677,7 @@ var SitePermissions = { // correspond to the classical ALLOW/DENY/PROMPT model, we want to always // allow the user to add exceptions to their cookie rules without removing them. if (permissionID != "cookie") { this.remove(uri, permissionID, browser); this.removeFromPrincipal(principal, permissionID, browser); return; } } Loading @@ -610,7 +693,7 @@ var SitePermissions = { // We do not support setting temp ALLOW for security reasons. // In its current state, this permission could be exploited by subframes // on the same page. This is because for BLOCK we ignore the request // URI and only consider the current browser URI, to avoid notification spamming. // principal and only consider the current browser principal, to avoid notification spamming. // // If you ever consider removing this line, you likely want to implement // a more fine-grained TemporaryPermissions that temporarily blocks for the Loading @@ -632,7 +715,7 @@ var SitePermissions = { browser.dispatchEvent( new browser.ownerGlobal.CustomEvent("PermissionStateChange") ); } else if (this.isSupportedURI(uri)) { } else if (this.isSupportedPrincipal(principal)) { let perms_scope = Services.perms.EXPIRE_NEVER; if (scope == this.SCOPE_SESSION) { perms_scope = Services.perms.EXPIRE_SESSION; Loading @@ -640,11 +723,12 @@ var SitePermissions = { perms_scope = Services.perms.EXPIRE_POLICY; } Services.perms.add(uri, permissionID, state, perms_scope); Services.perms.addFromPrincipal(principal, permissionID, state, perms_scope); } }, /** * Deprecated! Please use removeFromPrincipal(principal, permissionID, browser). * Removes the saved state of a particular permission for a given URI and/or browser. * This method will dispatch a "PermissionStateChange" event on the specified * browser if a temporary permission was removed. Loading @@ -662,9 +746,26 @@ var SitePermissions = { "uri parameter should be an nsIURI or a browser parameter is needed" ); } if (this.isSupportedURI(uri)) { Services.perms.remove(uri, permissionID); } let principal = uri ? Services.scriptSecurityManager.createCodebasePrincipal(uri, {}) : null; return this.removeFromPrincipal(principal, permissionID, browser); }, /** * Removes the saved state of a particular permission for a given principal and/or browser. * This method will dispatch a "PermissionStateChange" event on the specified * browser if a temporary permission was removed. * * @param {nsIPrincipal} principal * The principal to remove the permission for. * @param {String} permissionID * The id of the permission. * @param {Browser} browser (optional) * The browser object to remove temporary permissions on. */ removeFromPrincipal(principal, permissionID, browser) { if (this.isSupportedPrincipal(principal)) Services.perms.removeFromPrincipal(principal, permissionID); // TemporaryPermissions.get() deletes expired permissions automatically, if (TemporaryPermissions.get(browser, permissionID)) { Loading