Source code
Revision control
Copy as Markdown
Other Tools
/* -*- 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
/*
* 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 = 13;
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) const;
/*
* 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