/* -*- Mode: C++; tab-width: 8; 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/. */ #ifndef mozilla_dom_FeaturePolicy_h #define mozilla_dom_FeaturePolicy_h #include "nsCycleCollectionParticipant.h" #include "nsIPrincipal.h" #include "nsStringFwd.h" #include "nsTArray.h" #include "nsWrapperCache.h" /** * FeaturePolicy * ~~~~~~~~~~~~~ * * Each document and each HTMLIFrameElement have a FeaturePolicy object which is * used to allow or deny features in their contexts. * * FeaturePolicy is composed by a set of directives configured by the * 'Feature-Policy' HTTP Header and the 'allow' attribute in HTMLIFrameElements. * Both header and attribute are parsed by FeaturePolicyParser which returns an * array of Feature objects. Each Feature object has a feature name and one of * these policies: * - eNone - the feature is fully disabled. * - eAll - the feature is allowed. * - eAllowList - the feature is allowed for a list of origins. * * An interesting element of FeaturePolicy is the inheritance: each context * inherits the feature-policy directives from the parent context, if it exists. * When a context inherits a policy for feature X, it only knows if that feature * is allowed or denied (it ignores the list of allowed origins for instance). * This information is stored in an array of inherited feature strings because * we care only to know when they are denied. * * FeaturePolicy can be reset if the 'allow' or 'src' attributes change in * HTMLIFrameElements. 'src' attribute is important to compute correcly * the features via FeaturePolicy 'src' keyword. * * When FeaturePolicy must decide if feature X is allowed or denied for the * current origin, it checks if the parent context denied that feature. * If not, it checks if there is a Feature object for that * feature named X and if the origin is allowed or not. * * From a C++ point of view, use FeaturePolicyUtils to obtain the list of * features and to check if they are allowed in the current context. * * dom.security.featurePolicy.header.enabled pref can be used to disable the * HTTP header support. **/ class nsINode; namespace mozilla::dom { class Document; class Feature; template class Optional; class FeaturePolicyUtils; class FeaturePolicy final : public nsISupports, public nsWrapperCache { friend class FeaturePolicyUtils; public: NS_DECL_CYCLE_COLLECTING_ISUPPORTS NS_DECL_CYCLE_COLLECTION_WRAPPERCACHE_CLASS(FeaturePolicy) explicit FeaturePolicy(nsINode* aNode); // A FeaturePolicy must have a default origin. // This method must be called before any other exposed WebIDL method or before // checking if a feature is allowed. void SetDefaultOrigin(nsIPrincipal* aPrincipal) { mDefaultOrigin = aPrincipal; } void SetSrcOrigin(nsIPrincipal* aPrincipal) { mSrcOrigin = aPrincipal; } nsIPrincipal* DefaultOrigin() const { return mDefaultOrigin; } // Inherits the policy from the 'parent' context if it exists. void InheritPolicy(FeaturePolicy* aParentFeaturePolicy); // Sets the declarative part of the policy. This can be from the HTTP header // or for the 'allow' HTML attribute. void SetDeclaredPolicy(mozilla::dom::Document* aDocument, const nsAString& aPolicyString, nsIPrincipal* aSelfOrigin, nsIPrincipal* aSrcOrigin); // This method creates a policy for aFeatureName allowing it to '*' if it // doesn't exist yet. It's used by HTMLIFrameElement to enable features by // attributes. void MaybeSetAllowedPolicy(const nsAString& aFeatureName); // Clears all the declarative policy directives. This is needed when the // 'allow' attribute or the 'src' attribute change for HTMLIFrameElement's // policy. void ResetDeclaredPolicy(); // This method appends a feature to in-chain declared allowlist. If the name's // feature existed in the list, we only need to append the allowlist of new // feature to the existed one. void AppendToDeclaredAllowInAncestorChain(const Feature& aFeature); // This method returns true if aFeatureName is declared as "*" (allow all) // in parent. bool HasFeatureUnsafeAllowsAll(const nsAString& aFeatureName) const; // This method returns true if the aFeatureName is allowed for aOrigin // explicitly in ancestor chain, bool AllowsFeatureExplicitlyInAncestorChain(const nsAString& aFeatureName, nsIPrincipal* aOrigin) const; bool IsSameOriginAsSrc(nsIPrincipal* aPrincipal) const; // WebIDL internal methods. JSObject* WrapObject(JSContext* aCx, JS::Handle aGivenProto) override; nsINode* GetParentObject() const { return mParentNode; } // WebIDL explosed methods. bool AllowsFeature(const nsAString& aFeatureName, const Optional& aOrigin) const; void Features(nsTArray& aFeatures); void AllowedFeatures(nsTArray& aAllowedFeatures); void GetAllowlistForFeature(const nsAString& aFeatureName, nsTArray& aList) const; const nsTArray& InheritedDeniedFeatureNames() const { return mInheritedDeniedFeatureNames; } const nsTArray& AttributeEnabledFeatureNames() const { return mAttributeEnabledFeatureNames; } void SetInheritedDeniedFeatureNames( const nsTArray& aInheritedDeniedFeatureNames) { mInheritedDeniedFeatureNames = aInheritedDeniedFeatureNames.Clone(); } const nsAString& DeclaredString() const { return mDeclaredString; } nsIPrincipal* GetSelfOrigin() const { return mSelfOrigin; } nsIPrincipal* GetSrcOrigin() const { return mSrcOrigin; } private: ~FeaturePolicy() = default; // This method returns true if the aFeatureName is allowed for aOrigin, // following the feature-policy directives. See the comment at the top of this // file. bool AllowsFeatureInternal(const nsAString& aFeatureName, nsIPrincipal* aOrigin) const; // Inherits a single denied feature from the parent context. void SetInheritedDeniedFeature(const nsAString& aFeatureName); bool HasInheritedDeniedFeature(const nsAString& aFeatureName) const; // This returns true if we have a declared feature policy for aFeatureName. bool HasDeclaredFeature(const nsAString& aFeatureName) const; nsINode* mParentNode; // This is set in sub-contexts when the parent blocks some feature for the // current context. nsTArray mInheritedDeniedFeatureNames; // The list of features that have been enabled via MaybeSetAllowedPolicy. nsTArray mAttributeEnabledFeatureNames; // This is set of feature names when the parent allows all for that feature. nsTArray mParentAllowedAllFeatures; // The explicitly declared policy contains allowlist as a set of origins // except 'none' and '*'. This set contains all explicitly declared policies // in ancestor chain nsTArray mDeclaredFeaturesInAncestorChain; // Feature policy for the current context. nsTArray mFeatures; // Declared string represents Feature policy. nsString mDeclaredString; nsCOMPtr mDefaultOrigin; nsCOMPtr mSelfOrigin; nsCOMPtr mSrcOrigin; }; } // namespace mozilla::dom #endif // mozilla_dom_FeaturePolicy_h