1 // Copyright 2018 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 #include "extensions/common/cors_util.h"
6
7 #include <utility>
8
9 #include "base/strings/string_number_conversions.h"
10 #include "build/chromeos_buildflags.h"
11 #include "content/public/common/url_constants.h"
12 #include "extensions/common/constants.h"
13 #include "extensions/common/extension.h"
14 #include "extensions/common/extension_urls.h"
15 #include "extensions/common/permissions/permissions_data.h"
16 #include "extensions/common/url_pattern_set.h"
17
18 namespace extensions {
19
20 namespace {
21
GetEffectivePort(const std::string & port_string)22 uint16_t GetEffectivePort(const std::string& port_string) {
23 int port_int = 0;
24 bool success = base::StringToInt(port_string, &port_int);
25 // The URLPattern should verify that |port| is a number or "*", so conversion
26 // should never fail.
27 DCHECK(success) << port_string;
28 return port_int;
29 }
30
AddURLPatternSetToList(const URLPatternSet & pattern_set,std::vector<network::mojom::CorsOriginPatternPtr> * list,network::mojom::CorsOriginAccessMatchPriority priority)31 void AddURLPatternSetToList(
32 const URLPatternSet& pattern_set,
33 std::vector<network::mojom::CorsOriginPatternPtr>* list,
34 network::mojom::CorsOriginAccessMatchPriority priority) {
35 static const char* const kSchemes[] = {
36 content::kChromeUIScheme,
37 #if BUILDFLAG(IS_CHROMEOS_ASH)
38 content::kExternalFileScheme,
39 #endif
40 extensions::kExtensionScheme,
41 url::kFileScheme,
42 url::kFtpScheme,
43 url::kHttpScheme,
44 url::kHttpsScheme,
45 };
46 for (const URLPattern& pattern : pattern_set) {
47 for (const char* const scheme : kSchemes) {
48 if (!pattern.MatchesScheme(scheme))
49 continue;
50 network::mojom::CorsDomainMatchMode domain_match_mode =
51 pattern.match_subdomains()
52 ? network::mojom::CorsDomainMatchMode::kAllowSubdomains
53 : network::mojom::CorsDomainMatchMode::kDisallowSubdomains;
54 network::mojom::CorsPortMatchMode port_match_mode =
55 (pattern.port() == "*")
56 ? network::mojom::CorsPortMatchMode::kAllowAnyPort
57 : network::mojom::CorsPortMatchMode::kAllowOnlySpecifiedPort;
58 uint16_t port =
59 (port_match_mode ==
60 network::mojom::CorsPortMatchMode::kAllowOnlySpecifiedPort)
61 ? GetEffectivePort(pattern.port())
62 : 0u;
63 list->push_back(network::mojom::CorsOriginPattern::New(
64 scheme, pattern.host(), port, domain_match_mode, port_match_mode,
65 priority));
66 }
67 }
68 }
69
70 } // namespace
71
72 std::vector<network::mojom::CorsOriginPatternPtr>
CreateCorsOriginAccessAllowList(const Extension & extension,PermissionsData::EffectiveHostPermissionsMode mode)73 CreateCorsOriginAccessAllowList(
74 const Extension& extension,
75 PermissionsData::EffectiveHostPermissionsMode mode) {
76 std::vector<network::mojom::CorsOriginPatternPtr> allow_list;
77
78 // Permissions declared by the extension.
79 URLPatternSet origin_permissions =
80 extension.permissions_data()->GetEffectiveHostPermissions(mode);
81 AddURLPatternSetToList(
82 origin_permissions, &allow_list,
83 network::mojom::CorsOriginAccessMatchPriority::kDefaultPriority);
84
85 // Hosts exempted from the enterprise policy blocklist.
86 // This set intersection is necessary to prevent an enterprise policy from
87 // granting a host permission the extension didn't ask for.
88 URLPatternSet policy_allowed_host_patterns =
89 URLPatternSet::CreateIntersection(
90 extension.permissions_data()->policy_allowed_hosts(),
91 origin_permissions, URLPatternSet::IntersectionBehavior::kDetailed);
92 AddURLPatternSetToList(
93 policy_allowed_host_patterns, &allow_list,
94 network::mojom::CorsOriginAccessMatchPriority::kMediumPriority);
95
96 return allow_list;
97 }
98
99 std::vector<network::mojom::CorsOriginPatternPtr>
CreateCorsOriginAccessBlockList(const Extension & extension)100 CreateCorsOriginAccessBlockList(const Extension& extension) {
101 std::vector<network::mojom::CorsOriginPatternPtr> block_list;
102
103 // Hosts blocked by enterprise policy.
104 AddURLPatternSetToList(
105 extension.permissions_data()->policy_blocked_hosts(), &block_list,
106 network::mojom::CorsOriginAccessMatchPriority::kLowPriority);
107
108 GURL webstore_launch_url = extension_urls::GetWebstoreLaunchURL();
109 block_list.push_back(network::mojom::CorsOriginPattern::New(
110 webstore_launch_url.scheme(), webstore_launch_url.host(), /*port=*/0,
111 network::mojom::CorsDomainMatchMode::kAllowSubdomains,
112 network::mojom::CorsPortMatchMode::kAllowAnyPort,
113 network::mojom::CorsOriginAccessMatchPriority::kHighPriority));
114
115 // TODO(devlin): Should we also block the webstore update URL here? See
116 // https://crbug.com/826946 for a related instance.
117 return block_list;
118 }
119
120 } // namespace extensions
121