1 /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ 2 /* vim: set ts=8 sts=2 et sw=2 tw=80: */ 3 /* This Source Code Form is subject to the terms of the Mozilla Public 4 * License, v. 2.0. If a copy of the MPL was not distributed with this 5 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ 6 7 #ifndef mozilla_dom_FeaturePolicy_h 8 #define mozilla_dom_FeaturePolicy_h 9 10 #include "mozilla/Attributes.h" 11 #include "mozilla/dom/BindingUtils.h" 12 #include "mozilla/dom/Feature.h" 13 #include "nsCycleCollectionParticipant.h" 14 #include "nsString.h" 15 #include "nsTArray.h" 16 #include "nsWrapperCache.h" 17 18 /** 19 * FeaturePolicy 20 * ~~~~~~~~~~~~~ 21 * 22 * Each document and each HTMLIFrameElement have a FeaturePolicy object which is 23 * used to allow or deny features in their contexts. FeaturePolicy is active 24 * when pref dom.security.featurePolicy.enabled is set to true. 25 * 26 * FeaturePolicy is composed by a set of directives configured by the 27 * 'Feature-Policy' HTTP Header and the 'allow' attribute in HTMLIFrameElements. 28 * Both header and attribute are parsed by FeaturePolicyParser which returns an 29 * array of Feature objects. Each Feature object has a feature name and one of 30 * these policies: 31 * - eNone - the feature is fully disabled. 32 * - eAll - the feature is allowed. 33 * - eAllowList - the feature is allowed for a list of origins. 34 * 35 * An interesting element of FeaturePolicy is the inheritance: each context 36 * inherits the feature-policy directives from the parent context, if it exists. 37 * When a context inherits a policy for feature X, it only knows if that feature 38 * is allowed or denied (it ignores the list of allowed origins for instance). 39 * This information is stored in an array of inherited feature strings because 40 * we care only to know when they are denied. 41 * 42 * FeaturePolicy can be reset if the 'allow' or 'src' attributes change in 43 * HTMLIFrameElements. 'src' attribute is important to compute correcly 44 * the features via FeaturePolicy 'src' keyword. 45 * 46 * When FeaturePolicy must decide if feature X is allowed or denied for the 47 * current origin, it checks if the parent context denied that feature. 48 * If not, it checks if there is a Feature object for that 49 * feature named X and if the origin is allowed or not. 50 * 51 * From a C++ point of view, use FeaturePolicyUtils to obtain the list of 52 * features and to check if they are allowed in the current context. 53 * 54 * dom.security.featurePolicy.header.enabled pref can be used to disable the 55 * HTTP header support. 56 **/ 57 58 class nsIHttpChannel; 59 class nsINode; 60 61 namespace mozilla { 62 namespace dom { 63 class Document; 64 65 class FeaturePolicyUtils; 66 67 class FeaturePolicy final : public nsISupports, public nsWrapperCache { 68 friend class FeaturePolicyUtils; 69 70 public: 71 NS_DECL_CYCLE_COLLECTING_ISUPPORTS 72 NS_DECL_CYCLE_COLLECTION_SCRIPT_HOLDER_CLASS(FeaturePolicy) 73 74 explicit FeaturePolicy(nsINode* aNode); 75 76 // A FeaturePolicy must have a default origin. 77 // This method must be called before any other exposed WebIDL method or before 78 // checking if a feature is allowed. SetDefaultOrigin(nsIPrincipal * aPrincipal)79 void SetDefaultOrigin(nsIPrincipal* aPrincipal) { 80 mDefaultOrigin = aPrincipal; 81 } 82 SetSrcOrigin(nsIPrincipal * aPrincipal)83 void SetSrcOrigin(nsIPrincipal* aPrincipal) { mSrcOrigin = aPrincipal; } 84 DefaultOrigin()85 nsIPrincipal* DefaultOrigin() const { return mDefaultOrigin; } 86 87 // Inherits the policy from the 'parent' context if it exists. 88 void InheritPolicy(FeaturePolicy* aParentFeaturePolicy); 89 90 // Sets the declarative part of the policy. This can be from the HTTP header 91 // or for the 'allow' HTML attribute. 92 void SetDeclaredPolicy(mozilla::dom::Document* aDocument, 93 const nsAString& aPolicyString, 94 nsIPrincipal* aSelfOrigin, nsIPrincipal* aSrcOrigin); 95 96 // This method creates a policy for aFeatureName allowing it to '*' if it 97 // doesn't exist yet. It's used by HTMLIFrameElement to enable features by 98 // attributes. 99 void MaybeSetAllowedPolicy(const nsAString& aFeatureName); 100 101 // Clears all the declarative policy directives. This is needed when the 102 // 'allow' attribute or the 'src' attribute change for HTMLIFrameElement's 103 // policy. 104 void ResetDeclaredPolicy(); 105 106 // This method appends a feature to in-chain declared allowlist. If the name's 107 // feature existed in the list, we only need to append the allowlist of new 108 // feature to the existed one. 109 void AppendToDeclaredAllowInAncestorChain(const Feature& aFeature); 110 111 // This method returns true if aFeatureName is declared as "*" (allow all) 112 // in parent. 113 bool HasFeatureUnsafeAllowsAll(const nsAString& aFeatureName) const; 114 115 // This method returns true if the aFeatureName is allowed for aOrigin 116 // explicitly in ancestor chain, 117 bool AllowsFeatureExplicitlyInAncestorChain(const nsAString& aFeatureName, 118 nsIPrincipal* aOrigin) const; 119 120 bool IsSameOriginAsSrc(nsIPrincipal* aPrincipal) const; 121 122 // WebIDL internal methods. 123 124 JSObject* WrapObject(JSContext* aCx, 125 JS::Handle<JSObject*> aGivenProto) override; 126 GetParentObject()127 nsINode* GetParentObject() const { return mParentNode; } 128 129 // WebIDL explosed methods. 130 131 bool AllowsFeature(const nsAString& aFeatureName, 132 const Optional<nsAString>& aOrigin) const; 133 134 void Features(nsTArray<nsString>& aFeatures); 135 136 void AllowedFeatures(nsTArray<nsString>& aAllowedFeatures); 137 138 void GetAllowlistForFeature(const nsAString& aFeatureName, 139 nsTArray<nsString>& aList) const; 140 GetInheritedDeniedFeatureNames(nsTArray<nsString> & aInheritedDeniedFeatureNames)141 void GetInheritedDeniedFeatureNames( 142 nsTArray<nsString>& aInheritedDeniedFeatureNames) { 143 aInheritedDeniedFeatureNames = mInheritedDeniedFeatureNames.Clone(); 144 } 145 SetInheritedDeniedFeatureNames(const nsTArray<nsString> & aInheritedDeniedFeatureNames)146 void SetInheritedDeniedFeatureNames( 147 const nsTArray<nsString>& aInheritedDeniedFeatureNames) { 148 mInheritedDeniedFeatureNames = aInheritedDeniedFeatureNames.Clone(); 149 } 150 GetDeclaredString(nsAString & aDeclaredString)151 void GetDeclaredString(nsAString& aDeclaredString) { 152 aDeclaredString = mDeclaredString; 153 } GetSelfOrigin()154 nsIPrincipal* GetSelfOrigin() const { return mSelfOrigin; } GetSrcOrigin()155 nsIPrincipal* GetSrcOrigin() const { return mSrcOrigin; } 156 157 private: 158 ~FeaturePolicy() = default; 159 160 // This method returns true if the aFeatureName is allowed for aOrigin, 161 // following the feature-policy directives. See the comment at the top of this 162 // file. 163 bool AllowsFeatureInternal(const nsAString& aFeatureName, 164 nsIPrincipal* aOrigin) const; 165 166 // Inherits a single denied feature from the parent context. 167 void SetInheritedDeniedFeature(const nsAString& aFeatureName); 168 169 bool HasInheritedDeniedFeature(const nsAString& aFeatureName) const; 170 171 // This returns true if we have a declared feature policy for aFeatureName. 172 bool HasDeclaredFeature(const nsAString& aFeatureName) const; 173 174 nsINode* mParentNode; 175 176 // This is set in sub-contexts when the parent blocks some feature for the 177 // current context. 178 nsTArray<nsString> mInheritedDeniedFeatureNames; 179 180 // This is set of feature names when the parent allows all for that feature. 181 nsTArray<nsString> mParentAllowedAllFeatures; 182 183 // The explicitly declared policy contains allowlist as a set of origins 184 // except 'none' and '*'. This set contains all explicitly declared policies 185 // in ancestor chain 186 nsTArray<Feature> mDeclaredFeaturesInAncestorChain; 187 188 // Feature policy for the current context. 189 nsTArray<Feature> mFeatures; 190 191 // Declared string represents Feature policy. 192 nsString mDeclaredString; 193 194 nsCOMPtr<nsIPrincipal> mDefaultOrigin; 195 nsCOMPtr<nsIPrincipal> mSelfOrigin; 196 nsCOMPtr<nsIPrincipal> mSrcOrigin; 197 }; 198 199 } // namespace dom 200 } // namespace mozilla 201 202 #endif // mozilla_dom_FeaturePolicy_h 203