Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(273)

Side by Side Diff: chrome/browser/extensions/extension_management_api.cc

Issue 10750010: Add an installType property to the management API (Closed) Base URL: http://git.chromium.org/chromium/src.git@master
Patch Set: Forgot to remove param from LoadExtensionWithOptions (sorry) Created 8 years, 4 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
OLDNEW
(Empty)
1 // Copyright (c) 2012 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_api.h"
6
7 #include <map>
8 #include <string>
9
10 #include "base/basictypes.h"
11 #include "base/bind.h"
12 #include "base/json/json_writer.h"
13 #include "base/metrics/histogram.h"
14 #include "base/string_number_conversions.h"
15 #include "base/string_util.h"
16 #include "chrome/browser/extensions/event_names.h"
17 #include "chrome/browser/extensions/event_router.h"
18 #include "chrome/browser/extensions/extension_management_api_constants.h"
19 #include "chrome/browser/extensions/extension_service.h"
20 #include "chrome/browser/extensions/extension_system.h"
21 #include "chrome/browser/extensions/extension_uninstall_dialog.h"
22 #include "chrome/browser/extensions/management_policy.h"
23 #include "chrome/browser/profiles/profile.h"
24 #include "chrome/browser/ui/extensions/application_launch.h"
25 #include "chrome/browser/ui/webui/extensions/extension_icon_source.h"
26 #include "chrome/common/chrome_notification_types.h"
27 #include "chrome/common/chrome_utility_messages.h"
28 #include "chrome/common/extensions/extension.h"
29 #include "chrome/common/extensions/extension_constants.h"
30 #include "chrome/common/extensions/extension_error_utils.h"
31 #include "chrome/common/extensions/extension_icon_set.h"
32 #include "chrome/common/extensions/permissions/permission_set.h"
33 #include "chrome/common/extensions/url_pattern.h"
34 #include "content/public/browser/notification_details.h"
35 #include "content/public/browser/notification_source.h"
36 #include "content/public/browser/utility_process_host.h"
37 #include "content/public/browser/utility_process_host_client.h"
38
39 #if !defined(OS_ANDROID)
40 #include "chrome/browser/ui/webui/ntp/app_launcher_handler.h"
41 #endif
42
43 using base::IntToString;
44 using content::BrowserThread;
45 using content::UtilityProcessHost;
46 using content::UtilityProcessHostClient;
47 using extensions::Extension;
48 using extensions::PermissionMessages;
49
50 namespace events = extensions::event_names;
51 namespace keys = extension_management_api_constants;
52
53 namespace {
54
55 enum AutoConfirmForTest {
56 DO_NOT_SKIP = 0,
57 PROCEED,
58 ABORT
59 };
60
61 AutoConfirmForTest auto_confirm_for_test = DO_NOT_SKIP;
62
63 } // namespace
64
65 ExtensionService* ExtensionManagementFunction::service() {
66 return profile()->GetExtensionService();
67 }
68
69 ExtensionService* AsyncExtensionManagementFunction::service() {
70 return profile()->GetExtensionService();
71 }
72
73 static DictionaryValue* CreateExtensionInfo(const Extension& extension,
74 ExtensionService* service) {
75 DictionaryValue* info = new DictionaryValue();
76 bool enabled = service->IsExtensionEnabled(extension.id());
77 extension.GetBasicInfo(enabled, info);
78
79 const extensions::ManagementPolicy* policy = extensions::ExtensionSystem::Get(
80 service->profile())->management_policy();
81 info->SetBoolean(keys::kMayDisableKey,
82 policy->UserMayModifySettings(&extension, NULL));
83
84 info->SetBoolean(keys::kIsAppKey, extension.is_app());
85
86 if (!enabled) {
87 extensions::ExtensionPrefs* prefs = service->extension_prefs();
88 bool permissions_escalated =
89 prefs->DidExtensionEscalatePermissions(extension.id());
90 const char* reason = permissions_escalated ?
91 keys::kDisabledReasonPermissionsIncrease : keys::kDisabledReasonUnknown;
92 info->SetString(keys::kDisabledReasonKey, reason);
93 }
94
95 if (!extension.update_url().is_empty())
96 info->SetString(keys::kUpdateUrlKey,
97 extension.update_url().possibly_invalid_spec());
98 if (extension.is_app())
99 info->SetString(keys::kAppLaunchUrlKey,
100 extension.GetFullLaunchURL().possibly_invalid_spec());
101
102 const ExtensionIconSet::IconMap& icons = extension.icons().map();
103 if (!icons.empty()) {
104 ListValue* icon_list = new ListValue();
105 std::map<ExtensionIconSet::Icons, std::string>::const_iterator icon_iter;
106 for (icon_iter = icons.begin(); icon_iter != icons.end(); ++icon_iter) {
107 DictionaryValue* icon_info = new DictionaryValue();
108 ExtensionIconSet::Icons size = icon_iter->first;
109 GURL url = ExtensionIconSource::GetIconURL(
110 &extension, size, ExtensionIconSet::MATCH_EXACTLY, false, NULL);
111 icon_info->SetInteger(keys::kSizeKey, icon_iter->first);
112 icon_info->SetString(keys::kUrlKey, url.spec());
113 icon_list->Append(icon_info);
114 }
115 info->Set(keys::kIconsKey, icon_list);
116 }
117
118 const std::set<std::string> perms =
119 extension.GetActivePermissions()->GetAPIsAsStrings();
120 ListValue* permission_list = new ListValue();
121 if (!perms.empty()) {
122 std::set<std::string>::const_iterator perms_iter;
123 for (perms_iter = perms.begin(); perms_iter != perms.end(); ++perms_iter) {
124 StringValue* permission_name = new StringValue(*perms_iter);
125 permission_list->Append(permission_name);
126 }
127 }
128 info->Set(keys::kPermissionsKey, permission_list);
129
130 ListValue* host_permission_list = new ListValue();
131 if (!extension.is_hosted_app()) {
132 // Skip host permissions for hosted apps.
133 const URLPatternSet host_perms =
134 extension.GetActivePermissions()->explicit_hosts();
135 if (!host_perms.is_empty()) {
136 URLPatternSet::const_iterator host_perms_iter;
137 for (host_perms_iter = host_perms.begin();
138 host_perms_iter != host_perms.end();
139 ++host_perms_iter) {
140 StringValue* name = new StringValue(host_perms_iter->GetAsString());
141 host_permission_list->Append(name);
142 }
143 }
144 }
145 info->Set(keys::kHostPermissionsKey, host_permission_list);
146
147 return info;
148 }
149
150 static void AddExtensionInfo(ListValue* list,
151 const ExtensionSet& extensions,
152 ExtensionService* service) {
153 for (ExtensionSet::const_iterator i = extensions.begin();
154 i != extensions.end(); ++i) {
155 const Extension& extension = **i;
156
157 if (extension.location() == Extension::COMPONENT)
158 continue; // Skip built-in extensions.
159
160 list->Append(CreateExtensionInfo(extension, service));
161 }
162 }
163
164 bool GetAllExtensionsFunction::RunImpl() {
165 ListValue* result = new ListValue();
166 SetResult(result);
167
168 AddExtensionInfo(result, *service()->extensions(), service());
169 AddExtensionInfo(result, *service()->disabled_extensions(), service());
170
171 return true;
172 }
173
174 bool GetExtensionByIdFunction::RunImpl() {
175 std::string extension_id;
176 EXTENSION_FUNCTION_VALIDATE(args_->GetString(0, &extension_id));
177 const Extension* extension = service()->GetExtensionById(extension_id, true);
178 if (!extension) {
179 error_ = ExtensionErrorUtils::FormatErrorMessage(keys::kNoExtensionError,
180 extension_id);
181 return false;
182 }
183 DictionaryValue* result = CreateExtensionInfo(*extension, service());
184 SetResult(result);
185
186 return true;
187 }
188
189 bool GetPermissionWarningsByIdFunction::RunImpl() {
190 std::string ext_id;
191 EXTENSION_FUNCTION_VALIDATE(args_->GetString(0, &ext_id));
192
193 const Extension* extension = service()->GetExtensionById(ext_id, true);
194 if (!extension) {
195 error_ = ExtensionErrorUtils::FormatErrorMessage(keys::kNoExtensionError,
196 ext_id);
197 return false;
198 }
199
200 PermissionMessages warnings = extension->GetPermissionMessages();
201 ListValue* result = new ListValue();
202 for (PermissionMessages::const_iterator i = warnings.begin();
203 i < warnings.end(); ++i)
204 result->Append(Value::CreateStringValue(i->message()));
205 SetResult(result);
206 return true;
207 }
208
209 namespace {
210
211 // This class helps GetPermissionWarningsByManifestFunction manage
212 // sending manifest JSON strings to the utility process for parsing.
213 class SafeManifestJSONParser : public UtilityProcessHostClient {
214 public:
215 SafeManifestJSONParser(GetPermissionWarningsByManifestFunction* client,
216 const std::string& manifest)
217 : client_(client),
218 manifest_(manifest) {}
219
220 void Start() {
221 CHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
222 BrowserThread::PostTask(
223 BrowserThread::IO,
224 FROM_HERE,
225 base::Bind(&SafeManifestJSONParser::StartWorkOnIOThread, this));
226 }
227
228 void StartWorkOnIOThread() {
229 CHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
230 UtilityProcessHost* host =
231 UtilityProcessHost::Create(this, BrowserThread::IO);
232 host->EnableZygote();
233 host->Send(new ChromeUtilityMsg_ParseJSON(manifest_));
234 }
235
236 virtual bool OnMessageReceived(const IPC::Message& message) {
237 bool handled = true;
238 IPC_BEGIN_MESSAGE_MAP(SafeManifestJSONParser, message)
239 IPC_MESSAGE_HANDLER(ChromeUtilityHostMsg_ParseJSON_Succeeded,
240 OnJSONParseSucceeded)
241 IPC_MESSAGE_HANDLER(ChromeUtilityHostMsg_ParseJSON_Failed,
242 OnJSONParseFailed)
243 IPC_MESSAGE_UNHANDLED(handled = false)
244 IPC_END_MESSAGE_MAP()
245 return handled;
246 }
247
248 void OnJSONParseSucceeded(const ListValue& wrapper) {
249 CHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
250 Value* value = NULL;
251 CHECK(wrapper.Get(0, &value));
252 if (value->IsType(Value::TYPE_DICTIONARY))
253 parsed_manifest_.reset(static_cast<DictionaryValue*>(value)->DeepCopy());
254 else
255 error_ = keys::kManifestParseError;
256
257 BrowserThread::PostTask(
258 BrowserThread::UI,
259 FROM_HERE,
260 base::Bind(&SafeManifestJSONParser::ReportResultFromUIThread, this));
261 }
262
263 void OnJSONParseFailed(const std::string& error) {
264 CHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
265 error_ = error;
266 BrowserThread::PostTask(
267 BrowserThread::UI,
268 FROM_HERE,
269 base::Bind(&SafeManifestJSONParser::ReportResultFromUIThread, this));
270 }
271
272 void ReportResultFromUIThread() {
273 CHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
274 if (error_.empty() && parsed_manifest_.get())
275 client_->OnParseSuccess(parsed_manifest_.release());
276 else
277 client_->OnParseFailure(error_);
278 }
279
280 private:
281 ~SafeManifestJSONParser() {}
282
283 // The client who we'll report results back to.
284 GetPermissionWarningsByManifestFunction* client_;
285
286 // Data to parse.
287 std::string manifest_;
288
289 // Results of parsing.
290 scoped_ptr<DictionaryValue> parsed_manifest_;
291
292 std::string error_;
293 };
294
295 } // namespace
296
297 bool GetPermissionWarningsByManifestFunction::RunImpl() {
298 std::string manifest_str;
299 EXTENSION_FUNCTION_VALIDATE(args_->GetString(0, &manifest_str));
300
301 scoped_refptr<SafeManifestJSONParser> parser =
302 new SafeManifestJSONParser(this, manifest_str);
303 parser->Start();
304
305 // Matched with a Release() in OnParseSuccess/Failure().
306 AddRef();
307
308 // Response is sent async in OnParseSuccess/Failure().
309 return true;
310 }
311
312 void GetPermissionWarningsByManifestFunction::OnParseSuccess(
313 DictionaryValue* parsed_manifest) {
314 CHECK(parsed_manifest);
315
316 scoped_refptr<Extension> extension = Extension::Create(
317 FilePath(), Extension::INVALID, *parsed_manifest, Extension::NO_FLAGS,
318 &error_);
319 if (!extension.get()) {
320 OnParseFailure(keys::kExtensionCreateError);
321 return;
322 }
323
324 PermissionMessages warnings = extension->GetPermissionMessages();
325 ListValue* result = new ListValue();
326 for (PermissionMessages::const_iterator i = warnings.begin();
327 i < warnings.end(); ++i)
328 result->Append(Value::CreateStringValue(i->message()));
329 SetResult(result);
330 SendResponse(true);
331
332 // Matched with AddRef() in RunImpl().
333 Release();
334 }
335
336 void GetPermissionWarningsByManifestFunction::OnParseFailure(
337 const std::string& error) {
338 error_ = error;
339 SendResponse(false);
340
341 // Matched with AddRef() in RunImpl().
342 Release();
343 }
344
345 bool LaunchAppFunction::RunImpl() {
346 std::string extension_id;
347 EXTENSION_FUNCTION_VALIDATE(args_->GetString(0, &extension_id));
348 const Extension* extension = service()->GetExtensionById(extension_id, true);
349 if (!extension) {
350 error_ = ExtensionErrorUtils::FormatErrorMessage(keys::kNoExtensionError,
351 extension_id);
352 return false;
353 }
354 if (!extension->is_app()) {
355 error_ = ExtensionErrorUtils::FormatErrorMessage(keys::kNotAnAppError,
356 extension_id);
357 return false;
358 }
359
360 // Look at prefs to find the right launch container.
361 // |default_pref_value| is set to LAUNCH_REGULAR so that if
362 // the user has not set a preference, we open the app in a tab.
363 extension_misc::LaunchContainer launch_container =
364 service()->extension_prefs()->GetLaunchContainer(
365 extension, extensions::ExtensionPrefs::LAUNCH_DEFAULT);
366 application_launch::OpenApplication(application_launch::LaunchParams(
367 profile(), extension, launch_container, NEW_FOREGROUND_TAB));
368 #if !defined(OS_ANDROID)
369 AppLauncherHandler::RecordAppLaunchType(
370 extension_misc::APP_LAUNCH_EXTENSION_API);
371 #endif
372
373 return true;
374 }
375
376 SetEnabledFunction::SetEnabledFunction() {
377 }
378
379 SetEnabledFunction::~SetEnabledFunction() {
380 }
381
382 bool SetEnabledFunction::RunImpl() {
383 bool enable;
384 EXTENSION_FUNCTION_VALIDATE(args_->GetString(0, &extension_id_));
385 EXTENSION_FUNCTION_VALIDATE(args_->GetBoolean(1, &enable));
386
387 const Extension* extension = service()->GetExtensionById(extension_id_, true);
388 if (!extension) {
389 error_ = ExtensionErrorUtils::FormatErrorMessage(
390 keys::kNoExtensionError, extension_id_);
391 return false;
392 }
393
394 const extensions::ManagementPolicy* policy = extensions::ExtensionSystem::Get(
395 profile())->management_policy();
396 if (!policy->UserMayModifySettings(extension, NULL)) {
397 error_ = ExtensionErrorUtils::FormatErrorMessage(
398 keys::kUserCantModifyError, extension_id_);
399 return false;
400 }
401
402 bool currently_enabled = service()->IsExtensionEnabled(extension_id_);
403
404 if (!currently_enabled && enable) {
405 extensions::ExtensionPrefs* prefs = service()->extension_prefs();
406 if (prefs->DidExtensionEscalatePermissions(extension_id_)) {
407 if (!user_gesture()) {
408 error_ = keys::kGestureNeededForEscalationError;
409 return false;
410 }
411 AddRef(); // Matched in InstallUIProceed/InstallUIAbort
412 install_prompt_.reset(
413 chrome::CreateExtensionInstallPromptWithBrowser(GetCurrentBrowser()));
414 install_prompt_->ConfirmReEnable(this, extension);
415 return true;
416 }
417 service()->EnableExtension(extension_id_);
418 } else if (currently_enabled && !enable) {
419 service()->DisableExtension(extension_id_, Extension::DISABLE_USER_ACTION);
420 }
421
422 BrowserThread::PostTask(
423 BrowserThread::UI,
424 FROM_HERE,
425 base::Bind(&SetEnabledFunction::SendResponse, this, true));
426
427 return true;
428 }
429
430 void SetEnabledFunction::InstallUIProceed() {
431 service()->EnableExtension(extension_id_);
432 SendResponse(true);
433 Release();
434 }
435
436 void SetEnabledFunction::InstallUIAbort(bool user_initiated) {
437 error_ = keys::kUserDidNotReEnableError;
438 SendResponse(false);
439 Release();
440 }
441
442 UninstallFunction::UninstallFunction() {
443 }
444
445 UninstallFunction::~UninstallFunction() {
446 }
447
448 bool UninstallFunction::RunImpl() {
449 bool show_confirm_dialog = false;
450
451 EXTENSION_FUNCTION_VALIDATE(args_->GetString(0, &extension_id_));
452
453 if (HasOptionalArgument(1)) {
454 DictionaryValue* options = NULL;
455 EXTENSION_FUNCTION_VALIDATE(args_->GetDictionary(1, &options));
456
457 if (options->HasKey(keys::kShowConfirmDialogKey)) {
458 EXTENSION_FUNCTION_VALIDATE(options->GetBoolean(
459 keys::kShowConfirmDialogKey, &show_confirm_dialog));
460 }
461 }
462
463 const Extension* extension = service()->GetExtensionById(extension_id_, true);
464 if (!extension) {
465 error_ = ExtensionErrorUtils::FormatErrorMessage(
466 keys::kNoExtensionError, extension_id_);
467 return false;
468 }
469
470 if (!extensions::ExtensionSystem::Get(
471 profile())->management_policy()->UserMayModifySettings(extension, NULL)) {
472 error_ = ExtensionErrorUtils::FormatErrorMessage(
473 keys::kUserCantModifyError, extension_id_);
474 return false;
475 }
476
477 if (auto_confirm_for_test == DO_NOT_SKIP) {
478 if (show_confirm_dialog) {
479 AddRef(); // Balanced in ExtensionUninstallAccepted/Canceled
480 extension_uninstall_dialog_.reset(ExtensionUninstallDialog::Create(
481 GetCurrentBrowser(), this));
482 extension_uninstall_dialog_->ConfirmUninstall(extension);
483 } else {
484 Finish(true);
485 }
486 } else {
487 Finish(auto_confirm_for_test == PROCEED);
488 }
489
490 return true;
491 }
492
493 // static
494 void UninstallFunction::SetAutoConfirmForTest(bool should_proceed) {
495 auto_confirm_for_test = should_proceed ? PROCEED : ABORT;
496 }
497
498 void UninstallFunction::Finish(bool should_uninstall) {
499 if (should_uninstall) {
500 bool success = service()->UninstallExtension(
501 extension_id_,
502 false, /* external uninstall */
503 NULL);
504
505 // TODO set error_ if !success
506 SendResponse(success);
507 } else {
508 error_ = ExtensionErrorUtils::FormatErrorMessage(
509 keys::kUninstallCanceledError, extension_id_);
510 SendResponse(false);
511 }
512
513 }
514
515 void UninstallFunction::ExtensionUninstallAccepted() {
516 Finish(true);
517 Release();
518 }
519
520 void UninstallFunction::ExtensionUninstallCanceled() {
521 Finish(false);
522 Release();
523 }
524
525 ExtensionManagementEventRouter::ExtensionManagementEventRouter(Profile* profile)
526 : profile_(profile) {}
527
528 ExtensionManagementEventRouter::~ExtensionManagementEventRouter() {}
529
530 void ExtensionManagementEventRouter::Init() {
531 int types[] = {
532 chrome::NOTIFICATION_EXTENSION_INSTALLED,
533 chrome::NOTIFICATION_EXTENSION_UNINSTALLED,
534 chrome::NOTIFICATION_EXTENSION_LOADED,
535 chrome::NOTIFICATION_EXTENSION_UNLOADED
536 };
537
538 CHECK(registrar_.IsEmpty());
539 for (size_t i = 0; i < arraysize(types); i++) {
540 registrar_.Add(this,
541 types[i],
542 content::Source<Profile>(profile_));
543 }
544 }
545
546 void ExtensionManagementEventRouter::Observe(
547 int type,
548 const content::NotificationSource& source,
549 const content::NotificationDetails& details) {
550 const char* event_name = NULL;
551 Profile* profile = content::Source<Profile>(source).ptr();
552 CHECK(profile);
553 CHECK(profile_->IsSameProfile(profile));
554
555 switch (type) {
556 case chrome::NOTIFICATION_EXTENSION_INSTALLED:
557 event_name = events::kOnExtensionInstalled;
558 break;
559 case chrome::NOTIFICATION_EXTENSION_UNINSTALLED:
560 event_name = events::kOnExtensionUninstalled;
561 break;
562 case chrome::NOTIFICATION_EXTENSION_LOADED:
563 event_name = events::kOnExtensionEnabled;
564 break;
565 case chrome::NOTIFICATION_EXTENSION_UNLOADED:
566 event_name = events::kOnExtensionDisabled;
567 break;
568 default:
569 NOTREACHED();
570 return;
571 }
572
573 ListValue args;
574 if (event_name == events::kOnExtensionUninstalled) {
575 args.Append(Value::CreateStringValue(
576 content::Details<const extensions::Extension>(details).ptr()->id()));
577 } else {
578 const Extension* extension = NULL;
579 if (event_name == events::kOnExtensionDisabled) {
580 extension = content::Details<extensions::UnloadedExtensionInfo>(
581 details)->extension;
582 } else {
583 extension = content::Details<const Extension>(details).ptr();
584 }
585 CHECK(extension);
586 ExtensionService* service = profile->GetExtensionService();
587 args.Append(CreateExtensionInfo(*extension, service));
588 }
589
590 std::string args_json;
591 base::JSONWriter::Write(&args, &args_json);
592
593 profile->GetExtensionEventRouter()->DispatchEventToRenderers(
594 event_name, args_json, NULL, GURL(), extensions::EventFilteringInfo());
595 }
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698