Supervised user import: Listen for profile creation/deletion
[chromium-blink-merge.git] / chrome / common / extensions / manifest_handlers / automation.cc
blob03d83c4a3ea8aa5bbdf6757a69c886e3b8d6aa9f
1 // 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.
5 #include "chrome/common/extensions/manifest_handlers/automation.h"
7 #include "base/strings/utf_string_conversions.h"
8 #include "chrome/common/extensions/api/manifest_types.h"
9 #include "chrome/grit/generated_resources.h"
10 #include "extensions/common/error_utils.h"
11 #include "extensions/common/extensions_client.h"
12 #include "extensions/common/manifest_constants.h"
13 #include "extensions/common/permissions/api_permission_set.h"
14 #include "extensions/common/permissions/manifest_permission.h"
15 #include "extensions/common/permissions/permission_message.h"
16 #include "extensions/common/permissions/permission_message_util.h"
17 #include "extensions/common/permissions/permissions_data.h"
18 #include "extensions/common/url_pattern.h"
19 #include "ipc/ipc_message.h"
20 #include "ipc/ipc_message_utils.h"
21 #include "ui/base/l10n/l10n_util.h"
23 namespace extensions {
25 namespace automation_errors {
26 const char kErrorDesktopTrueInteractFalse[] =
27 "Cannot specify interactive=false if desktop=true is specified; "
28 "interactive=false will be ignored.";
29 const char kErrorDesktopTrueMatchesSpecified[] =
30 "Cannot specify matches for Automation if desktop=true is specified; "
31 "matches will be ignored.";
32 const char kErrorInvalidMatch[] = "Invalid match pattern '*': *";
33 const char kErrorNoMatchesProvided[] = "No valid match patterns provided.";
36 namespace errors = manifest_errors;
37 namespace keys = extensions::manifest_keys;
38 using api::manifest_types::Automation;
40 class AutomationManifestPermission : public ManifestPermission {
41 public:
42 explicit AutomationManifestPermission(
43 scoped_ptr<const AutomationInfo> automation_info)
44 : automation_info_(automation_info.Pass()) {}
46 // extensions::ManifestPermission overrides.
47 std::string name() const override;
49 std::string id() const override;
51 PermissionIDSet GetPermissions() const override;
53 bool HasMessages() const override;
55 PermissionMessages GetMessages() const override;
57 bool FromValue(const base::Value* value) override;
59 scoped_ptr<base::Value> ToValue() const override;
61 ManifestPermission* Diff(const ManifestPermission* rhs) const override;
63 ManifestPermission* Union(const ManifestPermission* rhs) const override;
65 ManifestPermission* Intersect(const ManifestPermission* rhs) const override;
67 private:
68 scoped_ptr<const AutomationInfo> automation_info_;
71 std::string AutomationManifestPermission::name() const {
72 return keys::kAutomation;
75 std::string AutomationManifestPermission::id() const {
76 return keys::kAutomation;
79 bool AutomationManifestPermission::HasMessages() const {
80 return GetMessages().size() > 0;
83 PermissionIDSet AutomationManifestPermission::GetPermissions() const {
84 // Meant to mimic the behavior of GetMessages().
85 PermissionIDSet permissions;
86 if (automation_info_->desktop) {
87 permissions.insert(APIPermission::kFullAccess);
88 } else if (automation_info_->matches.MatchesAllURLs()) {
89 if (automation_info_->interact) {
90 permissions.insert(APIPermission::kHostsAll);
91 } else {
92 permissions.insert(APIPermission::kHostsAllReadOnly);
94 } else {
95 // Check if we get any additional permissions from FilterHostPermissions.
96 URLPatternSet regular_hosts;
97 ExtensionsClient::Get()->FilterHostPermissions(
98 automation_info_->matches, &regular_hosts, &permissions);
99 std::set<std::string> hosts =
100 permission_message_util::GetDistinctHosts(regular_hosts, true, true);
101 if (!hosts.empty()) {
102 permission_message_util::AddHostPermissions(
103 &permissions, hosts, automation_info_->interact
104 ? permission_message_util::kReadWrite
105 : permission_message_util::kReadOnly);
108 return permissions;
111 PermissionMessages AutomationManifestPermission::GetMessages() const {
112 // When modifying this function, be careful to modify the functionality in
113 // GetPermissions() above as well.
114 PermissionMessages messages;
115 if (automation_info_->desktop) {
116 messages.push_back(PermissionMessage(
117 PermissionMessage::kFullAccess,
118 l10n_util::GetStringUTF16(IDS_EXTENSION_PROMPT_WARNING_FULL_ACCESS)));
119 } else if (automation_info_->matches.MatchesAllURLs()) {
120 if (automation_info_->interact) {
121 messages.push_back(PermissionMessage(
122 PermissionMessage::kHostsAll,
123 l10n_util::GetStringUTF16(IDS_EXTENSION_PROMPT_WARNING_ALL_HOSTS)));
124 } else {
125 messages.push_back(PermissionMessage(
126 PermissionMessage::kHostsAllReadOnly,
127 l10n_util::GetStringUTF16(
128 IDS_EXTENSION_PROMPT_WARNING_ALL_HOSTS_READ_ONLY)));
130 } else {
131 URLPatternSet regular_hosts;
132 std::set<PermissionMessage> message_set;
133 ExtensionsClient::Get()->FilterHostPermissions(
134 automation_info_->matches, &regular_hosts, &message_set);
135 messages.insert(messages.end(), message_set.begin(), message_set.end());
137 std::set<std::string> hosts =
138 permission_message_util::GetDistinctHosts(regular_hosts, true, true);
139 if (!hosts.empty()) {
140 messages.push_back(permission_message_util::CreateFromHostList(
141 hosts,
142 automation_info_->interact ? permission_message_util::kReadWrite
143 : permission_message_util::kReadOnly));
147 return messages;
150 bool AutomationManifestPermission::FromValue(const base::Value* value) {
151 base::string16 error;
152 automation_info_.reset(AutomationInfo::FromValue(*value,
153 NULL /* install_warnings */,
154 &error).release());
155 return error.empty();
158 scoped_ptr<base::Value> AutomationManifestPermission::ToValue() const {
159 return AutomationInfo::ToValue(*automation_info_).Pass();
162 ManifestPermission* AutomationManifestPermission::Diff(
163 const ManifestPermission* rhs) const {
164 const AutomationManifestPermission* other =
165 static_cast<const AutomationManifestPermission*>(rhs);
167 bool desktop = automation_info_->desktop && !other->automation_info_->desktop;
168 bool interact =
169 automation_info_->interact && !other->automation_info_->interact;
170 URLPatternSet matches;
171 URLPatternSet::CreateDifference(
172 automation_info_->matches, other->automation_info_->matches, &matches);
173 return new AutomationManifestPermission(
174 make_scoped_ptr(new const AutomationInfo(desktop, matches, interact)));
177 ManifestPermission* AutomationManifestPermission::Union(
178 const ManifestPermission* rhs) const {
179 const AutomationManifestPermission* other =
180 static_cast<const AutomationManifestPermission*>(rhs);
182 bool desktop = automation_info_->desktop || other->automation_info_->desktop;
183 bool interact =
184 automation_info_->interact || other->automation_info_->interact;
185 URLPatternSet matches;
186 URLPatternSet::CreateUnion(
187 automation_info_->matches, other->automation_info_->matches, &matches);
188 return new AutomationManifestPermission(
189 make_scoped_ptr(new const AutomationInfo(desktop, matches, interact)));
192 ManifestPermission* AutomationManifestPermission::Intersect(
193 const ManifestPermission* rhs) const {
194 const AutomationManifestPermission* other =
195 static_cast<const AutomationManifestPermission*>(rhs);
197 bool desktop = automation_info_->desktop && other->automation_info_->desktop;
198 bool interact =
199 automation_info_->interact && other->automation_info_->interact;
200 URLPatternSet matches;
201 URLPatternSet::CreateIntersection(
202 automation_info_->matches, other->automation_info_->matches, &matches);
203 return new AutomationManifestPermission(
204 make_scoped_ptr(new const AutomationInfo(desktop, matches, interact)));
207 AutomationHandler::AutomationHandler() {
210 AutomationHandler::~AutomationHandler() {
213 bool AutomationHandler::Parse(Extension* extension, base::string16* error) {
214 const base::Value* automation = NULL;
215 CHECK(extension->manifest()->Get(keys::kAutomation, &automation));
216 std::vector<InstallWarning> install_warnings;
217 scoped_ptr<AutomationInfo> info =
218 AutomationInfo::FromValue(*automation, &install_warnings, error);
219 if (!error->empty())
220 return false;
222 extension->AddInstallWarnings(install_warnings);
224 if (!info)
225 return true;
227 extension->SetManifestData(keys::kAutomation, info.release());
228 return true;
231 const std::vector<std::string> AutomationHandler::Keys() const {
232 return SingleKey(keys::kAutomation);
235 ManifestPermission* AutomationHandler::CreatePermission() {
236 return new AutomationManifestPermission(
237 make_scoped_ptr(new const AutomationInfo));
240 ManifestPermission* AutomationHandler::CreateInitialRequiredPermission(
241 const Extension* extension) {
242 const AutomationInfo* info = AutomationInfo::Get(extension);
243 if (info) {
244 return new AutomationManifestPermission(
245 make_scoped_ptr(new const AutomationInfo(
246 info->desktop, info->matches, info->interact)));
248 return NULL;
251 // static
252 const AutomationInfo* AutomationInfo::Get(const Extension* extension) {
253 return static_cast<AutomationInfo*>(
254 extension->GetManifestData(keys::kAutomation));
257 // static
258 scoped_ptr<AutomationInfo> AutomationInfo::FromValue(
259 const base::Value& value,
260 std::vector<InstallWarning>* install_warnings,
261 base::string16* error) {
262 scoped_ptr<Automation> automation = Automation::FromValue(value, error);
263 if (!automation)
264 return scoped_ptr<AutomationInfo>();
266 if (automation->as_boolean) {
267 if (*automation->as_boolean)
268 return make_scoped_ptr(new AutomationInfo());
269 return scoped_ptr<AutomationInfo>();
271 const Automation::Object& automation_object = *automation->as_object;
273 bool desktop = false;
274 bool interact = false;
275 if (automation_object.desktop && *automation_object.desktop) {
276 desktop = true;
277 interact = true;
278 if (automation_object.interact && !*automation_object.interact) {
279 // TODO(aboxhall): Do we want to allow this?
280 install_warnings->push_back(
281 InstallWarning(automation_errors::kErrorDesktopTrueInteractFalse));
283 } else if (automation_object.interact && *automation_object.interact) {
284 interact = true;
287 URLPatternSet matches;
288 bool specified_matches = false;
289 if (automation_object.matches) {
290 if (desktop) {
291 install_warnings->push_back(
292 InstallWarning(automation_errors::kErrorDesktopTrueMatchesSpecified));
293 } else {
294 specified_matches = true;
296 for (std::vector<std::string>::iterator it =
297 automation_object.matches->begin();
298 it != automation_object.matches->end();
299 ++it) {
300 // TODO(aboxhall): Refactor common logic from content_scripts_handler,
301 // manifest_url_handler and user_script.cc into a single location and
302 // re-use here.
303 URLPattern pattern(URLPattern::SCHEME_ALL &
304 ~URLPattern::SCHEME_CHROMEUI);
305 URLPattern::ParseResult parse_result = pattern.Parse(*it);
307 if (parse_result != URLPattern::PARSE_SUCCESS) {
308 install_warnings->push_back(
309 InstallWarning(ErrorUtils::FormatErrorMessage(
310 automation_errors::kErrorInvalidMatch,
311 *it,
312 URLPattern::GetParseResultString(parse_result))));
313 continue;
316 matches.AddPattern(pattern);
320 if (specified_matches && matches.is_empty()) {
321 install_warnings->push_back(
322 InstallWarning(automation_errors::kErrorNoMatchesProvided));
325 return make_scoped_ptr(new AutomationInfo(desktop, matches, interact));
328 // static
329 scoped_ptr<base::Value> AutomationInfo::ToValue(const AutomationInfo& info) {
330 return AsManifestType(info)->ToValue().Pass();
333 // static
334 scoped_ptr<Automation> AutomationInfo::AsManifestType(
335 const AutomationInfo& info) {
336 scoped_ptr<Automation> automation(new Automation);
337 if (!info.desktop && !info.interact && info.matches.size() == 0) {
338 automation->as_boolean.reset(new bool(true));
339 return automation.Pass();
342 Automation::Object* as_object = new Automation::Object;
343 as_object->desktop.reset(new bool(info.desktop));
344 as_object->interact.reset(new bool(info.interact));
345 if (info.matches.size() > 0) {
346 as_object->matches.reset(info.matches.ToStringVector().release());
348 automation->as_object.reset(as_object);
349 return automation.Pass();
352 AutomationInfo::AutomationInfo() : desktop(false), interact(false) {
355 AutomationInfo::AutomationInfo(bool desktop,
356 const URLPatternSet matches,
357 bool interact)
358 : desktop(desktop), matches(matches), interact(interact) {
361 AutomationInfo::~AutomationInfo() {
364 } // namespace extensions