DXR is a code search and navigation tool aimed at making sense of large projects. It supports full-text and regex searches as well as structural queries.

Implementation

Mercurial (c68fe15a81fc)

VCS Links

Line Code
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203
/* -*- Mode: C++; tab-width: 2; 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/. */

/*
 * Permission delegate handler provides a policy of how top-level can
 * delegate permission to embedded iframes.
 *
 * This class includes a mechanism to delegate permission using feature
 * policy. Feature policy will assure that only cross-origin iframes which
 * have been explicitly granted access will have the opportunity to request
 * permission.
 *
 * For example if an iframe has not been granted access to geolocation by
 * Feature Policy, geolocation request from the iframe will be automatically
 * denied. if the top-level origin already has access to geolocation and the
 * iframe has been granted access to geolocation by Feature Policy, the iframe
 * will also have access to geolocation. If the top-level frame did not have
 * access to geolocation, and the iframe has been granted access to geolocation
 * by Feature Policy, a request from the cross-origin iframe would trigger a
 * prompt using of the top-level origin.
 */

#ifndef mozilla_PermissionDelegateHandler_h
#define mozilla_PermissionDelegateHandler_h

#include "mozilla/Array.h"
#include "nsCycleCollectionParticipant.h"
#include "nsISupports.h"
#include "nsIPermissionDelegateHandler.h"
#include "nsIPermissionManager.h"
#include "nsCOMPtr.h"

class nsIPrincipal;
class nsIContentPermissionRequest;

namespace mozilla {
namespace dom {
class Document;
class WindowContext;
}  // namespace dom

class PermissionDelegateHandler final : public nsIPermissionDelegateHandler {
 public:
  NS_DECL_CYCLE_COLLECTING_ISUPPORTS
  NS_DECL_CYCLE_COLLECTION_CLASS(PermissionDelegateHandler)

  NS_DECL_NSIPERMISSIONDELEGATEHANDLER

  explicit PermissionDelegateHandler() = default;
  explicit PermissionDelegateHandler(mozilla::dom::Document* aDocument);

  static constexpr size_t DELEGATED_PERMISSION_COUNT = 11;

  typedef struct DelegatedPermissionList {
    Array<uint32_t, DELEGATED_PERMISSION_COUNT> mPermissions;

    bool operator==(const DelegatedPermissionList& aOther) const {
      return mPermissions == aOther.mPermissions;
    }
  } DelegatedPermissionList;

  bool Initialize();

  /*
   * Indicates if we has the right to make permission request with aType
   */
  bool HasPermissionDelegated(const nsACString& aType);

  /*
   * Get permission state, which applied permission delegate policy.
   *
   * @param aType the permission type to get
   * @param aPermission out argument which will be a permission type that we
   *                    will return from this function.
   * @param aExactHostMatch whether to look for the exact host name or also for
   *                        subdomains that can have the same permission.
   */
  nsresult GetPermission(const nsACString& aType, uint32_t* aPermission,
                         bool aExactHostMatch);

  /*
   * Get permission state for permission api, which applied
   * permission delegate policy.
   *
   * @param aType the permission type to get
   * @param aExactHostMatch whether to look for the exact host name or also for
   *                        subdomains that can have the same permission.
   * @param aPermission out argument which will be a permission type that we
   *                    will return from this function.
   */
  nsresult GetPermissionForPermissionsAPI(const nsACString& aType,
                                          uint32_t* aPermission);

  enum PermissionDelegatePolicy {
    /* Always delegate permission from top level to iframe and the iframe
     * should use top level origin to get/set permission.*/
    eDelegateUseTopOrigin,

    /* Permission is delegated using Feature Policy. Permission is denied by
     * default in cross origin iframe and the iframe only could get/set
     * permission if there's allow attribute set in iframe. e.g allow =
     * "geolocation" */
    eDelegateUseFeaturePolicy,

    /* Persistent denied permissions in cross origin iframe */
    ePersistDeniedCrossOrigin,

    /* This is the old behavior of cross origin iframe permission. The
     * permission delegation should not have an effect on iframe. The cross
     * origin iframe get/set permissions by its origin */
    eDelegateUseIframeOrigin,
  };

  /*
   * Indicates matching between Feature Policy and Permissions name defined in
   * Permissions Manager, not DOM Permissions API. Permissions API exposed in
   * DOM only supports "geo" at the moment but Permissions Manager also supports
   * "camera", "microphone".
   */
  typedef struct {
    const char* mPermissionName;
    const char16_t* mFeatureName;
    PermissionDelegatePolicy mPolicy;
  } PermissionDelegateInfo;

  /**
   * The loader maintains a weak reference to the document with
   * which it is initialized. This call forces the reference to
   * be dropped.
   */
  void DropDocumentReference() { mDocument = nullptr; }

  /*
   * Helper function to return the delegate info value for aPermissionName.
   * @param aPermissionName the permission name to get
   */
  static const PermissionDelegateInfo* GetPermissionDelegateInfo(
      const nsAString& aPermissionName);

  /*
   * Helper function to return the delegate principal. This will return nullptr,
   * or request's principal or top level principal based on the delegate policy
   * will be applied for a given type.
   * We use this function when prompting, no need to perform permission check
   * (deny/allow).
   *
   * @param aType the permission type to get
   * @param aRequest  The request which the principal is get from.
   * @param aResult out argument which will be a principal that we
   *                will return from this function.
   */
  static nsresult GetDelegatePrincipal(const nsACString& aType,
                                       nsIContentPermissionRequest* aRequest,
                                       nsIPrincipal** aResult);

  /**
   * Populate all delegated permissions to the WindowContext of the associated
   * document. We only populate the permissions for the top-level content.
   */
  void PopulateAllDelegatedPermissions();

  /**
   * Update the given delegated permission to the WindowContext. We only
   * update it for the top-level content.
   */
  void UpdateDelegatedPermission(const nsACString& aType);

 private:
  ~PermissionDelegateHandler() = default;

  /*
   * Check whether the permission is blocked by FeaturePolicy directive.
   * Default allowlist for a featureName of permission used in permissions
   * delegate should be set to eSelf, to ensure that permission is denied by
   * default and only have the opportunity to request permission with allow
   * attribute.
   */
  bool HasFeaturePolicyAllowed(const PermissionDelegateInfo* info) const;

  /**
   * A helper function to test the permission and set the result to the given
   * list. It will return true if the permission is changed, otherwise false.
   */
  bool UpdateDelegatePermissionInternal(
      PermissionDelegateHandler::DelegatedPermissionList& aList,
      const nsACString& aType, size_t aIdx,
      nsresult (NS_STDCALL nsIPermissionManager::*aTestFunc)(nsIPrincipal*,
                                                             const nsACString&,
                                                             uint32_t*));

  // A weak pointer to our document. Nulled out by DropDocumentReference.
  mozilla::dom::Document* mDocument;

  nsCOMPtr<nsIPrincipal> mPrincipal;
  RefPtr<nsIPermissionManager> mPermissionManager;
};

}  // namespace mozilla

#endif  // mozilla_PermissionDelegateHandler_h