blob: 1dce3d03a2c81b40aefcaa73fc45634afb223897 [file] [log] [blame]
binjin81d7c552014-10-02 11:47:121// Copyright 2014 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 "chrome/browser/extensions/extension_management_internal.h"
6
dcheng1fc00f12015-12-26 22:18:037#include <utility>
8
binjin81d7c552014-10-02 11:47:129#include "base/logging.h"
10#include "base/values.h"
binjin8e3d0182014-12-04 16:44:2811#include "base/version.h"
binjin81d7c552014-10-02 11:47:1212#include "chrome/browser/extensions/extension_management_constants.h"
13#include "extensions/common/url_pattern_set.h"
14#include "url/gurl.h"
15
16namespace extensions {
17
18namespace internal {
19
20namespace {
21const char kMalformedPreferenceWarning[] =
22 "Malformed extension management preference.";
nrpeter2362e7e2017-05-10 17:21:2623
24// Maximum number of characters for a 'blocked_install_message' value.
25const int kBlockedInstallMessageMaxLength = 1000;
binjin81d7c552014-10-02 11:47:1226} // namespace
27
28IndividualSettings::IndividualSettings() {
29 Reset();
30}
31
binjin8e3d0182014-12-04 16:44:2832// Initializes from default settings.
33IndividualSettings::IndividualSettings(
34 const IndividualSettings* default_settings) {
35 installation_mode = default_settings->installation_mode;
Sergey Poromov7efa5c262019-05-21 14:47:5636 update_url = default_settings->update_url;
Devlin Cronin32708b02018-12-05 17:58:0437 blocked_permissions = default_settings->blocked_permissions.Clone();
binjin8e3d0182014-12-04 16:44:2838 // We are not initializing |minimum_version_required| from |default_settings|
39 // here since it's not applicable to default settings.
40}
41
binjin81d7c552014-10-02 11:47:1242IndividualSettings::~IndividualSettings() {
43}
44
45bool IndividualSettings::Parse(const base::DictionaryValue* dict,
46 ParsingScope scope) {
47 std::string installation_mode_str;
48 if (dict->GetStringWithoutPathExpansion(schema_constants::kInstallationMode,
49 &installation_mode_str)) {
50 if (installation_mode_str == schema_constants::kAllowed) {
51 installation_mode = ExtensionManagement::INSTALLATION_ALLOWED;
52 } else if (installation_mode_str == schema_constants::kBlocked) {
53 installation_mode = ExtensionManagement::INSTALLATION_BLOCKED;
54 } else if (installation_mode_str == schema_constants::kForceInstalled) {
55 installation_mode = ExtensionManagement::INSTALLATION_FORCED;
56 } else if (installation_mode_str == schema_constants::kNormalInstalled) {
57 installation_mode = ExtensionManagement::INSTALLATION_RECOMMENDED;
Kyle Spiersbb4b9f5f52019-05-02 17:17:1558 } else if (installation_mode_str == schema_constants::kRemoved) {
59 installation_mode = ExtensionManagement::INSTALLATION_REMOVED;
binjin81d7c552014-10-02 11:47:1260 } else {
61 // Invalid value for 'installation_mode'.
62 LOG(WARNING) << kMalformedPreferenceWarning;
63 return false;
64 }
65
66 // Only proceed to fetch update url if force or recommended install mode
67 // is set.
68 if (installation_mode == ExtensionManagement::INSTALLATION_FORCED ||
69 installation_mode == ExtensionManagement::INSTALLATION_RECOMMENDED) {
70 if (scope != SCOPE_INDIVIDUAL) {
71 // Only individual extensions are allowed to be automatically installed.
72 LOG(WARNING) << kMalformedPreferenceWarning;
73 return false;
74 }
75 std::string update_url_str;
76 if (dict->GetStringWithoutPathExpansion(schema_constants::kUpdateUrl,
77 &update_url_str) &&
78 GURL(update_url_str).is_valid()) {
79 update_url = update_url_str;
80 } else {
81 // No valid update URL for extension.
82 LOG(WARNING) << kMalformedPreferenceWarning;
83 return false;
84 }
85 }
86 }
87
binjine6b58b52014-10-31 01:55:5788 // Parses the blocked permission settings.
89 const base::ListValue* list_value = nullptr;
90 base::string16 error;
91
nrpeter40e16382017-04-13 17:34:5892 // Set default blocked permissions, or replace with extension specific blocks.
93 APIPermissionSet parsed_blocked_permissions;
94 APIPermissionSet explicitly_allowed_permissions;
95 if (dict->GetListWithoutPathExpansion(schema_constants::kAllowedPermissions,
binjine6b58b52014-10-31 01:55:5796 &list_value)) {
binjine6b58b52014-10-31 01:55:5797 if (!APIPermissionSet::ParseFromJSON(
nrpeter40e16382017-04-13 17:34:5898 list_value, APIPermissionSet::kDisallowInternalPermissions,
99 &explicitly_allowed_permissions, &error, nullptr)) {
binjine6b58b52014-10-31 01:55:57100 LOG(WARNING) << error;
101 }
binjine6b58b52014-10-31 01:55:57102 }
binjine6b58b52014-10-31 01:55:57103 if (dict->GetListWithoutPathExpansion(schema_constants::kBlockedPermissions,
104 &list_value)) {
binjine6b58b52014-10-31 01:55:57105 if (!APIPermissionSet::ParseFromJSON(
nrpeter40e16382017-04-13 17:34:58106 list_value, APIPermissionSet::kDisallowInternalPermissions,
107 &parsed_blocked_permissions, &error, nullptr)) {
binjine6b58b52014-10-31 01:55:57108 LOG(WARNING) << error;
109 }
binjine6b58b52014-10-31 01:55:57110 }
nrpeter40e16382017-04-13 17:34:58111 APIPermissionSet::Difference(parsed_blocked_permissions,
112 explicitly_allowed_permissions,
113 &blocked_permissions);
114
115 // Parses list of Match Patterns into a URLPatternSet.
116 auto parse_url_pattern_set = [](const base::DictionaryValue* dict,
117 const char key[], URLPatternSet* out_value) {
118 const base::ListValue* host_list_value = nullptr;
119
120 // Get the list of URLPatterns.
121 if (dict->GetListWithoutPathExpansion(key,
122 &host_list_value)) {
nrpetere33d2a5b2017-04-25 00:12:31123 if (host_list_value->GetSize() >
124 schema_constants::kMaxItemsURLPatternSet) {
125 LOG(WARNING) << "Exceeded maximum number of URL match patterns ("
126 << schema_constants::kMaxItemsURLPatternSet
127 << ") for attribute '" << key << "'";
nrpetere33d2a5b2017-04-25 00:12:31128 }
129
nrpeter40e16382017-04-13 17:34:58130 out_value->ClearPatterns();
131 const int extension_scheme_mask =
132 URLPattern::GetValidSchemeMaskForExtensions();
Yann Dagoee291902019-08-19 15:49:06133 auto numItems = std::min(host_list_value->GetSize(),
134 schema_constants::kMaxItemsURLPatternSet);
135 for (size_t i = 0; i < numItems; ++i) {
nrpeter40e16382017-04-13 17:34:58136 std::string unparsed_str;
137 host_list_value->GetString(i, &unparsed_str);
Nick Peterson6bdf5822017-06-01 20:42:45138 URLPattern pattern(extension_scheme_mask);
139 if (unparsed_str != URLPattern::kAllUrlsPattern)
140 unparsed_str.append("/*");
Devlin Cronin35f8e372019-08-16 19:15:38141 URLPattern::ParseResult parse_result = pattern.Parse(unparsed_str);
Devlin Croninbd7f2b5fa2018-09-05 17:41:18142 if (parse_result != URLPattern::ParseResult::kSuccess) {
nrpeter40e16382017-04-13 17:34:58143 LOG(WARNING) << kMalformedPreferenceWarning;
144 LOG(WARNING) << "Invalid URL pattern '" + unparsed_str +
145 "' for attribute " + key;
146 return false;
147 }
148 out_value->AddPattern(pattern);
149 }
150 }
151 return true;
152 };
153
Devlin Cronin7e0f41ff2018-05-16 17:19:36154 if (!parse_url_pattern_set(dict, schema_constants::kPolicyBlockedHosts,
155 &policy_blocked_hosts))
nrpeter40e16382017-04-13 17:34:58156 return false;
157
Devlin Cronin7e0f41ff2018-05-16 17:19:36158 if (!parse_url_pattern_set(dict, schema_constants::kPolicyAllowedHosts,
159 &policy_allowed_hosts))
nrpeter40e16382017-04-13 17:34:58160 return false;
binjine6b58b52014-10-31 01:55:57161
binjin8e3d0182014-12-04 16:44:28162 // Parses the minimum version settings.
163 std::string minimum_version_required_str;
164 if (scope == SCOPE_INDIVIDUAL &&
165 dict->GetStringWithoutPathExpansion(
166 schema_constants::kMinimumVersionRequired,
167 &minimum_version_required_str)) {
dchengc963c7142016-04-08 03:55:22168 std::unique_ptr<base::Version> version(
pwnallcbd73192016-08-22 18:59:17169 new base::Version(minimum_version_required_str));
binjin8e3d0182014-12-04 16:44:28170 // We accept a general version string here. Note that count of components in
171 // version string of extensions is limited to 4.
172 if (!version->IsValid())
173 LOG(WARNING) << kMalformedPreferenceWarning;
174 else
dcheng1fc00f12015-12-26 22:18:03175 minimum_version_required = std::move(version);
binjin8e3d0182014-12-04 16:44:28176 }
177
nrpeter2362e7e2017-05-10 17:21:26178 if (dict->GetStringWithoutPathExpansion(
179 schema_constants::kBlockedInstallMessage, &blocked_install_message)) {
180 if (blocked_install_message.length() > kBlockedInstallMessageMaxLength) {
181 LOG(WARNING) << "Truncated blocked install message to 1000 characters";
182 blocked_install_message.erase(kBlockedInstallMessageMaxLength,
183 std::string::npos);
184 }
185 }
186
binjin81d7c552014-10-02 11:47:12187 return true;
188}
189
190void IndividualSettings::Reset() {
191 installation_mode = ExtensionManagement::INSTALLATION_ALLOWED;
192 update_url.clear();
binjine6b58b52014-10-31 01:55:57193 blocked_permissions.clear();
Devlin Cronin7e0f41ff2018-05-16 17:19:36194 policy_blocked_hosts.ClearPatterns();
195 policy_allowed_hosts.ClearPatterns();
nrpeter2362e7e2017-05-10 17:21:26196 blocked_install_message.clear();
binjin81d7c552014-10-02 11:47:12197}
198
199GlobalSettings::GlobalSettings() {
200 Reset();
201}
202
203GlobalSettings::~GlobalSettings() {
204}
205
206void GlobalSettings::Reset() {
207 has_restricted_install_sources = false;
208 install_sources.ClearPatterns();
209 has_restricted_allowed_types = false;
210 allowed_types.clear();
211}
212
213} // namespace internal
214
215} // namespace extensions