Commit 6e8a84c2 authored by Liang-Heng Chen's avatar Liang-Heng Chen Committed by Matthew Finkel
Browse files

Bug 1330467 - part 2. Add SitePermissions APIs functions to accept principal; r=johannh

Differential Revision: https://phabricator.services.mozilla.com/D19923

--HG--
extra : moz-landing-system : lando
parent edd87e4a
Loading
Loading
Loading
Loading
+116 −15
Original line number Diff line number Diff line
@@ -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.
   *
@@ -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();

@@ -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;
    }

@@ -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.
@@ -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.
   *
@@ -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
        );
@@ -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
@@ -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(
@@ -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;
      }
    }
@@ -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
@@ -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;
@@ -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.
@@ -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)) {