1 // Copyright 2019 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4 
5 #ifndef THIRD_PARTY_BLINK_PUBLIC_COMMON_FEATURE_POLICY_DOCUMENT_POLICY_H_
6 #define THIRD_PARTY_BLINK_PUBLIC_COMMON_FEATURE_POLICY_DOCUMENT_POLICY_H_
7 
8 #include <memory>
9 
10 #include "base/containers/flat_map.h"
11 #include "base/macros.h"
12 #include "third_party/blink/public/common/common_export.h"
13 #include "third_party/blink/public/common/feature_policy/policy_value.h"
14 #include "third_party/blink/public/mojom/feature_policy/document_policy_feature.mojom.h"
15 #include "third_party/blink/public/mojom/feature_policy/policy_value.mojom.h"
16 
17 namespace blink {
18 
19 // Document Policy is a mechanism for controlling the behaviour of web platform
20 // features in a document, and for requesting such changes in embedded frames.
21 // (The specific changes which are made depend on the feature; see the
22 // specification for details).
23 //
24 // Policies can be defined in the HTTP header stream, with the |Document-Policy|
25 // HTTP header, or can be set by the |policy| attributes on the iframe element
26 // which embeds the document.
27 //
28 // See
29 // https://github.com/w3c/webappsec-feature-policy/blob/master/document-policy-explainer.md
30 //
31 // Key concepts:
32 //
33 // Features
34 // --------
35 // Features which can be controlled by policy are defined by instances of enum
36 // mojom::DocumentPolicyFeature, declared in |document_policy_feature.mojom|.
37 //
38 // Declarations
39 // ------------
40 // A document policy declaration is a mapping of a feature name to a policy
41 // value. A set of such declarations is a declared policy. The declared policy
42 // is attached to a document.
43 //
44 // Required Policy
45 // ----------------
46 // In addition to the declared policy (which may be empty), every frame has
47 // an required policy, which is set by the embedding document (or inherited
48 // from its parent). Any document loaded into a frame with a required policy
49 // must have a declared policy which is compatible with it. Frames may add new
50 // requirements to their own subframes, but cannot relax any existing ones.
51 //
52 // Advertised Policy
53 // -----------------
54 // If a frame has a non-empty required policy, the requirements will be
55 // advertised on the outgoing HTTP request for any document to be loaded in that
56 // frame, in the Sec-Required-Document-Policy HTTP header.
57 //
58 // Defaults
59 // --------
60 // Each defined feature has a default policy, which determines the threshold
61 // value to use when no policy has been declared.
62 
63 class BLINK_COMMON_EXPORT DocumentPolicy {
64  public:
65   using FeatureState =
66       base::flat_map<mojom::DocumentPolicyFeature, PolicyValue>;
67 
68   // Mapping of feature to endpoint group.
69   // https://w3c.github.io/reporting/#endpoint-group
70   using FeatureEndpointMap =
71       base::flat_map<mojom::DocumentPolicyFeature, std::string>;
72 
73   struct ParsedDocumentPolicy {
74     FeatureState feature_state;
75     FeatureEndpointMap endpoint_map;
76   };
77 
78   static std::unique_ptr<DocumentPolicy> CreateWithHeaderPolicy(
79       const ParsedDocumentPolicy& header_policy);
80 
81   // Returns true if the feature is unrestricted (has its default value for the
82   // platform)
83   bool IsFeatureEnabled(mojom::DocumentPolicyFeature feature) const;
84 
85   // Returns true if the feature is unrestricted, or is not restricted as much
86   // as the given threshold value.
87   bool IsFeatureEnabled(mojom::DocumentPolicyFeature feature,
88                         const PolicyValue& threshold_value) const;
89 
90   // Returns true if the feature is being migrated to document policy
91   // TODO(iclelland): remove this method when those features are fully
92   // migrated to document policy.
93   bool IsFeatureSupported(mojom::DocumentPolicyFeature feature) const;
94 
95   // Returns the value of the given feature on the given origin.
96   PolicyValue GetFeatureValue(mojom::DocumentPolicyFeature feature) const;
97 
98   // Returns the endpoint the given feature should report to.
99   // Returns base::nullopt if the endpoint is unspecified for given feature.
100   const base::Optional<std::string> GetFeatureEndpoint(
101       mojom::DocumentPolicyFeature feature) const;
102 
103   // Returns true if the incoming policy is compatible with the given required
104   // policy, i.e. incoming policy is at least as strict as required policy.
105   static bool IsPolicyCompatible(const FeatureState& required_policy,
106                                  const FeatureState& incoming_policy);
107 
108   // Serialize document policy according to http_structured_header.
109   // returns base::nullopt when http structured header serializer encounters
110   // problems, e.g. double value out of the range supported.
111   static base::Optional<std::string> Serialize(const FeatureState& policy);
112 
113 
114   // Merge two FeatureState map. Take stricter value when there is conflict.
115   static FeatureState MergeFeatureState(const FeatureState& policy1,
116                                         const FeatureState& policy2);
117 
118  private:
119   friend class DocumentPolicyTest;
120 
121   DocumentPolicy(const FeatureState& header_policy,
122                  const FeatureEndpointMap& endpoint_map,
123                  const FeatureState& defaults);
124   static std::unique_ptr<DocumentPolicy> CreateWithHeaderPolicy(
125       const FeatureState& header_policy,
126       const FeatureEndpointMap& endpoint_map,
127       const FeatureState& defaults);
128 
129   void UpdateFeatureState(const FeatureState& feature_state);
130 
131   // Internal feature state is represented as an array to avoid overhead
132   // in using container classes.
133   PolicyValue internal_feature_state_
134       [static_cast<size_t>(mojom::DocumentPolicyFeature::kMaxValue) + 1];
135 
136   FeatureEndpointMap endpoint_map_;
137 
138   DISALLOW_COPY_AND_ASSIGN(DocumentPolicy);
139 };
140 
141 bool inline operator==(const DocumentPolicy::ParsedDocumentPolicy& lhs,
142                        const DocumentPolicy::ParsedDocumentPolicy& rhs) {
143   return std::tie(lhs.feature_state, lhs.endpoint_map) ==
144          std::tie(rhs.feature_state, rhs.endpoint_map);
145 }
146 
147 }  // namespace blink
148 
149 #endif  // THIRD_PARTY_BLINK_PUBLIC_COMMON_FEATURE_POLICY_DOCUMENT_POLICY_H_
150