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