Delete chrome.mediaGalleriesPrivate because the functionality unique to it has since...
[chromium-blink-merge.git] / chrome / common / extensions / manifest_handlers / automation.cc
blob6f4aae50a668baec260c9bc90a53e81037725b71
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 // TODO(sashab): Add the rule
88 // kFullAccess -> IDS_EXTENSION_PROMPT_WARNING_FULL_ACCESS
89 // to ChromePermissionMessageProvider, when it exists.
90 permissions.insert(APIPermission::kFullAccess);
91 } else if (automation_info_->matches.MatchesAllURLs()) {
92 if (automation_info_->interact) {
93 permissions.insert(APIPermission::kHostsAll);
94 // TODO(sashab): Add the rule
95 // kHostsAll -> IDS_EXTENSION_PROMPT_WARNING_ALL_HOSTS
96 // to ChromePermissionMessageProvider, when it exists.
97 } else {
98 permissions.insert(APIPermission::kHostsAllReadOnly);
99 // TODO(sashab): Add the rule
100 // kHostsAllReadOnly -> IDS_EXTENSION_PROMPT_WARNING_ALL_HOSTS_READ_ONLY
101 // to ChromePermissionMessageProvider, when it exists.
103 } else {
104 // Check if we get any additional permissions from FilterHostPermissions.
105 URLPatternSet regular_hosts;
106 ExtensionsClient::Get()->FilterHostPermissions(
107 automation_info_->matches, &regular_hosts, &permissions);
108 std::set<std::string> hosts =
109 permission_message_util::GetDistinctHosts(regular_hosts, true, true);
110 if (!hosts.empty()) {
111 permission_message_util::AddHostPermissions(
112 &permissions, hosts, automation_info_->interact
113 ? permission_message_util::kReadWrite
114 : permission_message_util::kReadOnly);
117 return permissions;
120 PermissionMessages AutomationManifestPermission::GetMessages() const {
121 // When modifying this function, be careful to modify the functionality in
122 // GetPermissions() above as well.
123 PermissionMessages messages;
124 if (automation_info_->desktop) {
125 messages.push_back(PermissionMessage(
126 PermissionMessage::kFullAccess,
127 l10n_util::GetStringUTF16(IDS_EXTENSION_PROMPT_WARNING_FULL_ACCESS)));
128 } else if (automation_info_->matches.MatchesAllURLs()) {
129 if (automation_info_->interact) {
130 messages.push_back(PermissionMessage(
131 PermissionMessage::kHostsAll,
132 l10n_util::GetStringUTF16(IDS_EXTENSION_PROMPT_WARNING_ALL_HOSTS)));
133 } else {
134 messages.push_back(PermissionMessage(
135 PermissionMessage::kHostsAllReadOnly,
136 l10n_util::GetStringUTF16(
137 IDS_EXTENSION_PROMPT_WARNING_ALL_HOSTS_READ_ONLY)));
139 } else {
140 URLPatternSet regular_hosts;
141 std::set<PermissionMessage> message_set;
142 ExtensionsClient::Get()->FilterHostPermissions(
143 automation_info_->matches, &regular_hosts, &message_set);
144 messages.insert(messages.end(), message_set.begin(), message_set.end());
146 std::set<std::string> hosts =
147 permission_message_util::GetDistinctHosts(regular_hosts, true, true);
148 if (!hosts.empty()) {
149 messages.push_back(permission_message_util::CreateFromHostList(
150 hosts,
151 automation_info_->interact ? permission_message_util::kReadWrite
152 : permission_message_util::kReadOnly));
156 return messages;
159 bool AutomationManifestPermission::FromValue(const base::Value* value) {
160 base::string16 error;
161 automation_info_.reset(AutomationInfo::FromValue(*value,
162 NULL /* install_warnings */,
163 &error).release());
164 return error.empty();
167 scoped_ptr<base::Value> AutomationManifestPermission::ToValue() const {
168 return AutomationInfo::ToValue(*automation_info_).Pass();
171 ManifestPermission* AutomationManifestPermission::Diff(
172 const ManifestPermission* rhs) const {
173 const AutomationManifestPermission* other =
174 static_cast<const AutomationManifestPermission*>(rhs);
176 bool desktop = automation_info_->desktop && !other->automation_info_->desktop;
177 bool interact =
178 automation_info_->interact && !other->automation_info_->interact;
179 URLPatternSet matches;
180 URLPatternSet::CreateDifference(
181 automation_info_->matches, other->automation_info_->matches, &matches);
182 return new AutomationManifestPermission(
183 make_scoped_ptr(new const AutomationInfo(desktop, matches, interact)));
186 ManifestPermission* AutomationManifestPermission::Union(
187 const ManifestPermission* rhs) const {
188 const AutomationManifestPermission* other =
189 static_cast<const AutomationManifestPermission*>(rhs);
191 bool desktop = automation_info_->desktop || other->automation_info_->desktop;
192 bool interact =
193 automation_info_->interact || other->automation_info_->interact;
194 URLPatternSet matches;
195 URLPatternSet::CreateUnion(
196 automation_info_->matches, other->automation_info_->matches, &matches);
197 return new AutomationManifestPermission(
198 make_scoped_ptr(new const AutomationInfo(desktop, matches, interact)));
201 ManifestPermission* AutomationManifestPermission::Intersect(
202 const ManifestPermission* rhs) const {
203 const AutomationManifestPermission* other =
204 static_cast<const AutomationManifestPermission*>(rhs);
206 bool desktop = automation_info_->desktop && other->automation_info_->desktop;
207 bool interact =
208 automation_info_->interact && other->automation_info_->interact;
209 URLPatternSet matches;
210 URLPatternSet::CreateIntersection(
211 automation_info_->matches, other->automation_info_->matches, &matches);
212 return new AutomationManifestPermission(
213 make_scoped_ptr(new const AutomationInfo(desktop, matches, interact)));
216 AutomationHandler::AutomationHandler() {
219 AutomationHandler::~AutomationHandler() {
222 bool AutomationHandler::Parse(Extension* extension, base::string16* error) {
223 const base::Value* automation = NULL;
224 CHECK(extension->manifest()->Get(keys::kAutomation, &automation));
225 std::vector<InstallWarning> install_warnings;
226 scoped_ptr<AutomationInfo> info =
227 AutomationInfo::FromValue(*automation, &install_warnings, error);
228 if (!error->empty())
229 return false;
231 extension->AddInstallWarnings(install_warnings);
233 if (!info)
234 return true;
236 extension->SetManifestData(keys::kAutomation, info.release());
237 return true;
240 const std::vector<std::string> AutomationHandler::Keys() const {
241 return SingleKey(keys::kAutomation);
244 ManifestPermission* AutomationHandler::CreatePermission() {
245 return new AutomationManifestPermission(
246 make_scoped_ptr(new const AutomationInfo));
249 ManifestPermission* AutomationHandler::CreateInitialRequiredPermission(
250 const Extension* extension) {
251 const AutomationInfo* info = AutomationInfo::Get(extension);
252 if (info) {
253 return new AutomationManifestPermission(
254 make_scoped_ptr(new const AutomationInfo(
255 info->desktop, info->matches, info->interact)));
257 return NULL;
260 // static
261 const AutomationInfo* AutomationInfo::Get(const Extension* extension) {
262 return static_cast<AutomationInfo*>(
263 extension->GetManifestData(keys::kAutomation));
266 // static
267 scoped_ptr<AutomationInfo> AutomationInfo::FromValue(
268 const base::Value& value,
269 std::vector<InstallWarning>* install_warnings,
270 base::string16* error) {
271 scoped_ptr<Automation> automation = Automation::FromValue(value, error);
272 if (!automation)
273 return scoped_ptr<AutomationInfo>();
275 if (automation->as_boolean) {
276 if (*automation->as_boolean)
277 return make_scoped_ptr(new AutomationInfo());
278 return scoped_ptr<AutomationInfo>();
280 const Automation::Object& automation_object = *automation->as_object;
282 bool desktop = false;
283 bool interact = false;
284 if (automation_object.desktop && *automation_object.desktop) {
285 desktop = true;
286 interact = true;
287 if (automation_object.interact && !*automation_object.interact) {
288 // TODO(aboxhall): Do we want to allow this?
289 install_warnings->push_back(
290 InstallWarning(automation_errors::kErrorDesktopTrueInteractFalse));
292 } else if (automation_object.interact && *automation_object.interact) {
293 interact = true;
296 URLPatternSet matches;
297 bool specified_matches = false;
298 if (automation_object.matches) {
299 if (desktop) {
300 install_warnings->push_back(
301 InstallWarning(automation_errors::kErrorDesktopTrueMatchesSpecified));
302 } else {
303 specified_matches = true;
305 for (std::vector<std::string>::iterator it =
306 automation_object.matches->begin();
307 it != automation_object.matches->end();
308 ++it) {
309 // TODO(aboxhall): Refactor common logic from content_scripts_handler,
310 // manifest_url_handler and user_script.cc into a single location and
311 // re-use here.
312 URLPattern pattern(URLPattern::SCHEME_ALL &
313 ~URLPattern::SCHEME_CHROMEUI);
314 URLPattern::ParseResult parse_result = pattern.Parse(*it);
316 if (parse_result != URLPattern::PARSE_SUCCESS) {
317 install_warnings->push_back(
318 InstallWarning(ErrorUtils::FormatErrorMessage(
319 automation_errors::kErrorInvalidMatch,
320 *it,
321 URLPattern::GetParseResultString(parse_result))));
322 continue;
325 matches.AddPattern(pattern);
329 if (specified_matches && matches.is_empty()) {
330 install_warnings->push_back(
331 InstallWarning(automation_errors::kErrorNoMatchesProvided));
334 return make_scoped_ptr(new AutomationInfo(desktop, matches, interact));
337 // static
338 scoped_ptr<base::Value> AutomationInfo::ToValue(const AutomationInfo& info) {
339 return AsManifestType(info)->ToValue().Pass();
342 // static
343 scoped_ptr<Automation> AutomationInfo::AsManifestType(
344 const AutomationInfo& info) {
345 scoped_ptr<Automation> automation(new Automation);
346 if (!info.desktop && !info.interact && info.matches.size() == 0) {
347 automation->as_boolean.reset(new bool(true));
348 return automation.Pass();
351 Automation::Object* as_object = new Automation::Object;
352 as_object->desktop.reset(new bool(info.desktop));
353 as_object->interact.reset(new bool(info.interact));
354 if (info.matches.size() > 0) {
355 as_object->matches.reset(info.matches.ToStringVector().release());
357 automation->as_object.reset(as_object);
358 return automation.Pass();
361 AutomationInfo::AutomationInfo() : desktop(false), interact(false) {
364 AutomationInfo::AutomationInfo(bool desktop,
365 const URLPatternSet matches,
366 bool interact)
367 : desktop(desktop), matches(matches), interact(interact) {
370 AutomationInfo::~AutomationInfo() {
373 } // namespace extensions