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/api/developer_private/developer_private_api.h" 6 7 #include "apps/app_load_service.h" 8 #include "apps/app_restore_service.h" 9 #include "apps/saved_files_service.h" 10 #include "apps/shell_window.h" 11 #include "apps/shell_window_registry.h" 12 #include "base/base64.h" 13 #include "base/command_line.h" 14 #include "base/file_util.h" 15 #include "base/files/file_enumerator.h" 16 #include "base/i18n/file_util_icu.h" 17 #include "base/strings/string_number_conversions.h" 18 #include "base/strings/utf_string_conversions.h" 19 #include "base/values.h" 20 #include "chrome/browser/chrome_notification_types.h" 21 #include "chrome/browser/devtools/devtools_window.h" 22 #include "chrome/browser/extensions/api/developer_private/developer_private_api_factory.h" 23 #include "chrome/browser/extensions/api/developer_private/entry_picker.h" 24 #include "chrome/browser/extensions/api/extension_action/extension_action_api.h" 25 #include "chrome/browser/extensions/event_names.h" 26 #include "chrome/browser/extensions/extension_disabled_ui.h" 27 #include "chrome/browser/extensions/extension_error_reporter.h" 28 #include "chrome/browser/extensions/extension_service.h" 29 #include "chrome/browser/extensions/extension_system.h" 30 #include "chrome/browser/extensions/management_policy.h" 31 #include "chrome/browser/extensions/unpacked_installer.h" 32 #include "chrome/browser/extensions/updater/extension_updater.h" 33 #include "chrome/browser/platform_util.h" 34 #include "chrome/browser/profiles/profile.h" 35 #include "chrome/browser/sync_file_system/drive_backend/drive_file_sync_service.h" 36 #include "chrome/browser/sync_file_system/syncable_file_system_util.h" 37 #include "chrome/browser/ui/chrome_select_file_policy.h" 38 #include "chrome/browser/ui/webui/extensions/extension_icon_source.h" 39 #include "chrome/common/extensions/api/developer_private.h" 40 #include "chrome/common/extensions/background_info.h" 41 #include "chrome/common/extensions/incognito_handler.h" 42 #include "chrome/common/extensions/manifest_handlers/app_launch_info.h" 43 #include "chrome/common/extensions/manifest_handlers/icons_handler.h" 44 #include "chrome/common/extensions/manifest_handlers/offline_enabled_info.h" 45 #include "chrome/common/extensions/manifest_url_handler.h" 46 #include "chrome/common/url_constants.h" 47 #include "content/public/browser/browser_thread.h" 48 #include "content/public/browser/notification_service.h" 49 #include "content/public/browser/render_process_host.h" 50 #include "content/public/browser/render_view_host.h" 51 #include "content/public/browser/site_instance.h" 52 #include "content/public/browser/storage_partition.h" 53 #include "content/public/browser/web_contents.h" 54 #include "extensions/browser/view_type_utils.h" 55 #include "extensions/common/constants.h" 56 #include "extensions/common/extension_resource.h" 57 #include "extensions/common/install_warning.h" 58 #include "extensions/common/switches.h" 59 #include "grit/chromium_strings.h" 60 #include "grit/generated_resources.h" 61 #include "net/base/net_util.h" 62 #include "ui/base/l10n/l10n_util.h" 63 #include "ui/webui/web_ui_util.h" 64 #include "webkit/browser/fileapi/file_system_context.h" 65 #include "webkit/browser/fileapi/file_system_operation.h" 66 #include "webkit/browser/fileapi/file_system_operation_runner.h" 67 #include "webkit/common/blob/shareable_file_reference.h" 68 69 using apps::ShellWindow; 70 using apps::ShellWindowRegistry; 71 using content::RenderViewHost; 72 73 namespace extensions { 74 75 namespace events = event_names; 76 77 namespace { 78 79 const base::FilePath::CharType kUnpackedAppsFolder[] 80 = FILE_PATH_LITERAL("apps_target"); 81 82 ExtensionUpdater* GetExtensionUpdater(Profile* profile) { 83 return profile->GetExtensionService()->updater(); 84 } 85 86 std::vector<base::FilePath> ListFolder(const base::FilePath path) { 87 base::FileEnumerator files(path, false, 88 base::FileEnumerator::DIRECTORIES | base::FileEnumerator::FILES); 89 std::vector<base::FilePath> paths; 90 91 for (base::FilePath current_path = files.Next(); !current_path.empty(); 92 current_path = files.Next()) { 93 paths.push_back(current_path); 94 } 95 return paths; 96 } 97 98 bool ValidateFolderName(const base::FilePath::StringType& name) { 99 base::FilePath::StringType name_sanitized(name); 100 file_util::ReplaceIllegalCharactersInPath(&name_sanitized, '_'); 101 return name == name_sanitized; 102 } 103 104 const Extension* GetExtensionByPath(const ExtensionSet* extensions, 105 const base::FilePath& path) { 106 base::FilePath extension_path = base::MakeAbsoluteFilePath(path); 107 for (ExtensionSet::const_iterator iter = extensions->begin(); 108 iter != extensions->end(); ++iter) { 109 if ((*iter)->path() == extension_path) 110 return iter->get(); 111 } 112 return NULL; 113 } 114 115 std::string GetExtensionID(const RenderViewHost* render_view_host) { 116 if (!render_view_host->GetSiteInstance()) 117 return std::string(); 118 119 return render_view_host->GetSiteInstance()->GetSiteURL().host(); 120 } 121 122 } // namespace 123 124 namespace AllowFileAccess = api::developer_private::AllowFileAccess; 125 namespace AllowIncognito = api::developer_private::AllowIncognito; 126 namespace ChoosePath = api::developer_private::ChoosePath; 127 namespace Enable = api::developer_private::Enable; 128 namespace GetItemsInfo = api::developer_private::GetItemsInfo; 129 namespace Inspect = api::developer_private::Inspect; 130 namespace PackDirectory = api::developer_private::PackDirectory; 131 namespace Reload = api::developer_private::Reload; 132 namespace Restart = api::developer_private::Restart; 133 134 DeveloperPrivateAPI* DeveloperPrivateAPI::Get(Profile* profile) { 135 return DeveloperPrivateAPIFactory::GetForProfile(profile); 136 } 137 138 DeveloperPrivateAPI::DeveloperPrivateAPI(Profile* profile) : profile_(profile) { 139 RegisterNotifications(); 140 } 141 142 DeveloperPrivateEventRouter::DeveloperPrivateEventRouter(Profile* profile) 143 : profile_(profile) { 144 int types[] = { 145 chrome::NOTIFICATION_EXTENSION_INSTALLED, 146 chrome::NOTIFICATION_EXTENSION_UNINSTALLED, 147 chrome::NOTIFICATION_EXTENSION_LOADED, 148 chrome::NOTIFICATION_EXTENSION_UNLOADED, 149 chrome::NOTIFICATION_EXTENSION_VIEW_REGISTERED, 150 chrome::NOTIFICATION_EXTENSION_VIEW_UNREGISTERED 151 }; 152 153 CHECK(registrar_.IsEmpty()); 154 for (size_t i = 0; i < arraysize(types); ++i) { 155 registrar_.Add(this, 156 types[i], 157 content::Source<Profile>(profile_)); 158 } 159 } 160 161 162 DeveloperPrivateEventRouter::~DeveloperPrivateEventRouter() {} 163 164 void DeveloperPrivateEventRouter::Observe( 165 int type, 166 const content::NotificationSource& source, 167 const content::NotificationDetails& details) { 168 const char* event_name = NULL; 169 Profile* profile = content::Source<Profile>(source).ptr(); 170 CHECK(profile); 171 CHECK(profile_->IsSameProfile(profile)); 172 developer::EventData event_data; 173 const Extension* extension = NULL; 174 175 switch (type) { 176 case chrome::NOTIFICATION_EXTENSION_INSTALLED: 177 event_data.event_type = developer::EVENT_TYPE_INSTALLED; 178 extension = 179 content::Details<const InstalledExtensionInfo>(details)->extension; 180 break; 181 case chrome::NOTIFICATION_EXTENSION_UNINSTALLED: 182 event_data.event_type = developer::EVENT_TYPE_UNINSTALLED; 183 extension = content::Details<const Extension>(details).ptr(); 184 break; 185 case chrome::NOTIFICATION_EXTENSION_LOADED: 186 event_data.event_type = developer::EVENT_TYPE_LOADED; 187 extension = content::Details<const Extension>(details).ptr(); 188 break; 189 case chrome::NOTIFICATION_EXTENSION_UNLOADED: 190 event_data.event_type = developer::EVENT_TYPE_UNLOADED; 191 extension = 192 content::Details<const UnloadedExtensionInfo>(details)->extension; 193 break; 194 case chrome::NOTIFICATION_EXTENSION_VIEW_UNREGISTERED: 195 event_data.event_type = developer::EVENT_TYPE_VIEW_UNREGISTERED; 196 event_data.item_id = GetExtensionID( 197 content::Details<const RenderViewHost>(details).ptr()); 198 break; 199 case chrome::NOTIFICATION_EXTENSION_VIEW_REGISTERED: 200 event_data.event_type = developer::EVENT_TYPE_VIEW_REGISTERED; 201 event_data.item_id = GetExtensionID( 202 content::Details<const RenderViewHost>(details).ptr()); 203 break; 204 default: 205 NOTREACHED(); 206 return; 207 } 208 209 if (extension) 210 event_data.item_id = extension->id(); 211 212 scoped_ptr<ListValue> args(new ListValue()); 213 args->Append(event_data.ToValue().release()); 214 215 event_name = events::kDeveloperPrivateOnItemStateChanged; 216 scoped_ptr<Event> event(new Event(event_name, args.Pass())); 217 ExtensionSystem::Get(profile)->event_router()->BroadcastEvent(event.Pass()); 218 } 219 220 void DeveloperPrivateAPI::SetLastUnpackedDirectory(const base::FilePath& path) { 221 last_unpacked_directory_ = path; 222 } 223 224 void DeveloperPrivateAPI::RegisterNotifications() { 225 ExtensionSystem::Get(profile_)->event_router()->RegisterObserver( 226 this, events::kDeveloperPrivateOnItemStateChanged); 227 } 228 229 DeveloperPrivateAPI::~DeveloperPrivateAPI() {} 230 231 void DeveloperPrivateAPI::Shutdown() {} 232 233 void DeveloperPrivateAPI::OnListenerAdded( 234 const EventListenerInfo& details) { 235 if (!developer_private_event_router_) 236 developer_private_event_router_.reset( 237 new DeveloperPrivateEventRouter(profile_)); 238 } 239 240 void DeveloperPrivateAPI::OnListenerRemoved( 241 const EventListenerInfo& details) { 242 if (!ExtensionSystem::Get(profile_)->event_router()->HasEventListener( 243 event_names::kDeveloperPrivateOnItemStateChanged)) 244 developer_private_event_router_.reset(NULL); 245 } 246 247 namespace api { 248 249 bool DeveloperPrivateAutoUpdateFunction::RunImpl() { 250 ExtensionUpdater* updater = GetExtensionUpdater(profile()); 251 if (updater) 252 updater->CheckNow(ExtensionUpdater::CheckParams()); 253 SetResult(Value::CreateBooleanValue(true)); 254 return true; 255 } 256 257 DeveloperPrivateAutoUpdateFunction::~DeveloperPrivateAutoUpdateFunction() {} 258 259 scoped_ptr<developer::ItemInfo> 260 DeveloperPrivateGetItemsInfoFunction::CreateItemInfo( 261 const Extension& item, 262 bool item_is_enabled) { 263 scoped_ptr<developer::ItemInfo> info(new developer::ItemInfo()); 264 265 ExtensionSystem* system = ExtensionSystem::Get(profile()); 266 ExtensionService* service = profile()->GetExtensionService(); 267 268 info->id = item.id(); 269 info->name = item.name(); 270 info->enabled = service->IsExtensionEnabled(info->id); 271 info->offline_enabled = OfflineEnabledInfo::IsOfflineEnabled(&item); 272 info->version = item.VersionString(); 273 info->description = item.description(); 274 275 GURL url = 276 ExtensionIconSource::GetIconURL(&item, 277 extension_misc::EXTENSION_ICON_MEDIUM, 278 ExtensionIconSet::MATCH_BIGGER, 279 false, 280 NULL); 281 info->icon_url = url.spec(); 282 283 if (item.is_app()) { 284 if (item.is_legacy_packaged_app()) 285 info->type = developer::ITEM_TYPE_LEGACY_PACKAGED_APP; 286 else if (item.is_hosted_app()) 287 info->type = developer::ITEM_TYPE_HOSTED_APP; 288 else if (item.is_platform_app()) 289 info->type = developer::ITEM_TYPE_PACKAGED_APP; 290 else 291 NOTREACHED(); 292 } else if (item.is_theme()) { 293 info->type = developer::ITEM_TYPE_THEME; 294 } else if (item.is_extension()) { 295 info->type = developer::ITEM_TYPE_EXTENSION; 296 } else { 297 NOTREACHED(); 298 } 299 300 if (Manifest::IsUnpackedLocation(item.location())) { 301 info->path.reset( 302 new std::string(UTF16ToUTF8(item.path().LossyDisplayName()))); 303 for (std::vector<extensions::InstallWarning>::const_iterator it = 304 item.install_warnings().begin(); 305 it != item.install_warnings().end(); ++it) { 306 developer::InstallWarning* warning = new developer::InstallWarning(); 307 warning->is_html = (it->format == InstallWarning::FORMAT_HTML); 308 warning->message = it->message; 309 info->install_warnings.push_back(make_linked_ptr(warning)); 310 } 311 } 312 313 info->incognito_enabled = service->IsIncognitoEnabled(item.id()); 314 info->wants_file_access = item.wants_file_access(); 315 info->allow_file_access = service->AllowFileAccess(&item); 316 info->allow_reload = Manifest::IsUnpackedLocation(item.location()); 317 info->is_unpacked = Manifest::IsUnpackedLocation(item.location()); 318 info->terminated = service->terminated_extensions()->Contains(item.id()); 319 info->allow_incognito = item.can_be_incognito_enabled(); 320 321 info->homepage_url.reset(new std::string( 322 ManifestURL::GetHomepageURL(&item).spec())); 323 if (!ManifestURL::GetOptionsPage(&item).is_empty()) { 324 info->options_url.reset( 325 new std::string(ManifestURL::GetOptionsPage(&item).spec())); 326 } 327 328 if (!ManifestURL::GetUpdateURL(&item).is_empty()) { 329 info->update_url.reset( 330 new std::string(ManifestURL::GetUpdateURL(&item).spec())); 331 } 332 333 if (item.is_app()) { 334 info->app_launch_url.reset(new std::string( 335 extensions::AppLaunchInfo::GetFullLaunchURL(&item).spec())); 336 } 337 338 info->may_disable = system->management_policy()-> 339 UserMayModifySettings(&item, NULL); 340 info->is_app = item.is_app(); 341 info->views = GetInspectablePagesForExtension(&item, item_is_enabled); 342 343 return info.Pass(); 344 } 345 346 void DeveloperPrivateGetItemsInfoFunction:: 347 GetInspectablePagesForExtensionProcess( 348 const std::set<content::RenderViewHost*>& views, 349 ItemInspectViewList* result) { 350 for (std::set<content::RenderViewHost*>::const_iterator iter = views.begin(); 351 iter != views.end(); ++iter) { 352 content::RenderViewHost* host = *iter; 353 content::WebContents* web_contents = 354 content::WebContents::FromRenderViewHost(host); 355 ViewType host_type = GetViewType(web_contents); 356 if (VIEW_TYPE_EXTENSION_POPUP == host_type || 357 VIEW_TYPE_EXTENSION_DIALOG == host_type) 358 continue; 359 360 content::RenderProcessHost* process = host->GetProcess(); 361 result->push_back( 362 constructInspectView(web_contents->GetURL(), 363 process->GetID(), 364 host->GetRoutingID(), 365 process->GetBrowserContext()->IsOffTheRecord())); 366 } 367 } 368 369 void DeveloperPrivateGetItemsInfoFunction:: 370 GetShellWindowPagesForExtensionProfile( 371 const Extension* extension, 372 ItemInspectViewList* result) { 373 ShellWindowRegistry* registry = ShellWindowRegistry::Get(profile()); 374 if (!registry) return; 375 376 const ShellWindowRegistry::ShellWindowList windows = 377 registry->GetShellWindowsForApp(extension->id()); 378 379 for (ShellWindowRegistry::const_iterator it = windows.begin(); 380 it != windows.end(); ++it) { 381 content::WebContents* web_contents = (*it)->web_contents(); 382 RenderViewHost* host = web_contents->GetRenderViewHost(); 383 content::RenderProcessHost* process = host->GetProcess(); 384 result->push_back( 385 constructInspectView(web_contents->GetURL(), 386 process->GetID(), 387 host->GetRoutingID(), 388 process->GetBrowserContext()->IsOffTheRecord())); 389 } 390 } 391 392 linked_ptr<developer::ItemInspectView> DeveloperPrivateGetItemsInfoFunction:: 393 constructInspectView( 394 const GURL& url, 395 int render_process_id, 396 int render_view_id, 397 bool incognito) { 398 linked_ptr<developer::ItemInspectView> view(new developer::ItemInspectView()); 399 400 if (url.scheme() == kExtensionScheme) { 401 // No leading slash. 402 view->path = url.path().substr(1); 403 } else { 404 // For live pages, use the full URL. 405 view->path = url.spec(); 406 } 407 408 view->render_process_id = render_process_id; 409 view->render_view_id = render_view_id; 410 view->incognito = incognito; 411 return view; 412 } 413 414 ItemInspectViewList DeveloperPrivateGetItemsInfoFunction:: 415 GetInspectablePagesForExtension( 416 const Extension* extension, 417 bool extension_is_enabled) { 418 419 ItemInspectViewList result; 420 // Get the extension process's active views. 421 ExtensionProcessManager* process_manager = 422 ExtensionSystem::Get(profile())->process_manager(); 423 GetInspectablePagesForExtensionProcess( 424 process_manager->GetRenderViewHostsForExtension(extension->id()), 425 &result); 426 427 // Get shell window views 428 GetShellWindowPagesForExtensionProfile(extension, &result); 429 430 // Include a link to start the lazy background page, if applicable. 431 if (BackgroundInfo::HasLazyBackgroundPage(extension) && 432 extension_is_enabled && 433 !process_manager->GetBackgroundHostForExtension(extension->id())) { 434 result.push_back(constructInspectView( 435 BackgroundInfo::GetBackgroundURL(extension), -1, -1, false)); 436 } 437 438 ExtensionService* service = profile()->GetExtensionService(); 439 // Repeat for the incognito process, if applicable. Don't try to get 440 // shell windows for incognito process. 441 if (service->profile()->HasOffTheRecordProfile() && 442 IncognitoInfo::IsSplitMode(extension)) { 443 process_manager = ExtensionSystem::Get( 444 service->profile()->GetOffTheRecordProfile())->process_manager(); 445 GetInspectablePagesForExtensionProcess( 446 process_manager->GetRenderViewHostsForExtension(extension->id()), 447 &result); 448 449 if (BackgroundInfo::HasLazyBackgroundPage(extension) && 450 extension_is_enabled && 451 !process_manager->GetBackgroundHostForExtension(extension->id())) { 452 result.push_back(constructInspectView( 453 BackgroundInfo::GetBackgroundURL(extension), -1, -1, false)); 454 } 455 } 456 457 return result; 458 } 459 460 bool DeveloperPrivateGetItemsInfoFunction::RunImpl() { 461 scoped_ptr<developer::GetItemsInfo::Params> params( 462 developer::GetItemsInfo::Params::Create(*args_)); 463 EXTENSION_FUNCTION_VALIDATE(params.get() != NULL); 464 465 bool include_disabled = params->include_disabled; 466 bool include_terminated = params->include_terminated; 467 468 ExtensionSet items; 469 470 ExtensionService* service = profile()->GetExtensionService(); 471 472 items.InsertAll(*service->extensions()); 473 474 if (include_disabled) { 475 items.InsertAll(*service->disabled_extensions()); 476 } 477 478 if (include_terminated) { 479 items.InsertAll(*service->terminated_extensions()); 480 } 481 482 ItemInfoList item_list; 483 484 for (ExtensionSet::const_iterator iter = items.begin(); 485 iter != items.end(); ++iter) { 486 const Extension& item = *iter->get(); 487 488 // Don't show component extensions and invisible apps. 489 if (item.ShouldNotBeVisible()) 490 continue; 491 492 item_list.push_back(make_linked_ptr<developer::ItemInfo>( 493 CreateItemInfo( 494 item, service->IsExtensionEnabled(item.id())).release())); 495 } 496 497 results_ = developer::GetItemsInfo::Results::Create(item_list); 498 SendResponse(true); 499 500 return true; 501 } 502 503 DeveloperPrivateGetItemsInfoFunction::~DeveloperPrivateGetItemsInfoFunction() {} 504 505 bool DeveloperPrivateAllowFileAccessFunction::RunImpl() { 506 scoped_ptr<AllowFileAccess::Params> params( 507 AllowFileAccess::Params::Create(*args_)); 508 EXTENSION_FUNCTION_VALIDATE(params.get()); 509 510 EXTENSION_FUNCTION_VALIDATE(user_gesture_); 511 512 ExtensionSystem* system = ExtensionSystem::Get(profile()); 513 ManagementPolicy* management_policy = system->management_policy(); 514 ExtensionService* service = profile()->GetExtensionService(); 515 const Extension* extension = service->GetInstalledExtension(params->item_id); 516 bool result = true; 517 518 if (!extension) { 519 result = false; 520 } else if (!management_policy->UserMayModifySettings(extension, NULL)) { 521 LOG(ERROR) << "Attempt to change allow file access of an extension that " 522 << "non-usermanagable was made. Extension id : " 523 << extension->id(); 524 result = false; 525 } else { 526 service->SetAllowFileAccess(extension, params->allow); 527 result = true; 528 } 529 530 return result; 531 } 532 533 DeveloperPrivateAllowFileAccessFunction:: 534 ~DeveloperPrivateAllowFileAccessFunction() {} 535 536 bool DeveloperPrivateAllowIncognitoFunction::RunImpl() { 537 scoped_ptr<AllowIncognito::Params> params( 538 AllowIncognito::Params::Create(*args_)); 539 EXTENSION_FUNCTION_VALIDATE(params.get()); 540 541 ExtensionService* service = profile()->GetExtensionService(); 542 const Extension* extension = service->GetInstalledExtension(params->item_id); 543 bool result = true; 544 545 if (!extension) 546 result = false; 547 else 548 service->SetIsIncognitoEnabled(extension->id(), params->allow); 549 550 return result; 551 } 552 553 DeveloperPrivateAllowIncognitoFunction:: 554 ~DeveloperPrivateAllowIncognitoFunction() {} 555 556 557 bool DeveloperPrivateReloadFunction::RunImpl() { 558 scoped_ptr<Reload::Params> params(Reload::Params::Create(*args_)); 559 EXTENSION_FUNCTION_VALIDATE(params.get()); 560 561 ExtensionService* service = profile()->GetExtensionService(); 562 CHECK(!params->item_id.empty()); 563 service->ReloadExtension(params->item_id); 564 return true; 565 } 566 567 bool DeveloperPrivateShowPermissionsDialogFunction::RunImpl() { 568 EXTENSION_FUNCTION_VALIDATE(args_->GetString(0, &extension_id_)); 569 ExtensionService* service = profile()->GetExtensionService(); 570 CHECK(!extension_id_.empty()); 571 ShellWindowRegistry* registry = ShellWindowRegistry::Get(profile()); 572 DCHECK(registry); 573 ShellWindow* shell_window = registry->GetShellWindowForRenderViewHost( 574 render_view_host()); 575 prompt_.reset(new ExtensionInstallPrompt(shell_window->web_contents())); 576 const Extension* extension = service->GetInstalledExtension(extension_id_); 577 578 if (!extension) 579 return false; 580 581 // Released by InstallUIAbort or InstallUIProceed. 582 AddRef(); 583 std::vector<base::FilePath> retained_file_paths; 584 if (extension->HasAPIPermission(extensions::APIPermission::kFileSystem)) { 585 std::vector<apps::SavedFileEntry> retained_file_entries = 586 apps::SavedFilesService::Get(profile())->GetAllFileEntries( 587 extension_id_); 588 for (size_t i = 0; i < retained_file_entries.size(); i++) { 589 retained_file_paths.push_back(retained_file_entries[i].path); 590 } 591 } 592 prompt_->ReviewPermissions(this, extension, retained_file_paths); 593 return true; 594 } 595 596 DeveloperPrivateReloadFunction::~DeveloperPrivateReloadFunction() {} 597 598 // This is called when the user clicks "Revoke File Access." 599 void DeveloperPrivateShowPermissionsDialogFunction::InstallUIProceed() { 600 apps::SavedFilesService::Get(profile())->ClearQueue( 601 profile()->GetExtensionService()->GetExtensionById(extension_id_, true)); 602 if (apps::AppRestoreService::Get(profile())->IsAppRestorable(extension_id_)) 603 apps::AppLoadService::Get(profile())->RestartApplication(extension_id_); 604 SendResponse(true); 605 Release(); 606 } 607 608 void DeveloperPrivateShowPermissionsDialogFunction::InstallUIAbort( 609 bool user_initiated) { 610 SendResponse(true); 611 Release(); 612 } 613 614 DeveloperPrivateShowPermissionsDialogFunction:: 615 DeveloperPrivateShowPermissionsDialogFunction() {} 616 617 DeveloperPrivateShowPermissionsDialogFunction:: 618 ~DeveloperPrivateShowPermissionsDialogFunction() {} 619 620 bool DeveloperPrivateRestartFunction::RunImpl() { 621 scoped_ptr<Restart::Params> params(Restart::Params::Create(*args_)); 622 EXTENSION_FUNCTION_VALIDATE(params.get()); 623 624 apps::AppLoadService* service = apps::AppLoadService::Get(profile()); 625 EXTENSION_FUNCTION_VALIDATE(!params->item_id.empty()); 626 ExtensionService* extension_service = profile()->GetExtensionService(); 627 // Don't restart disabled applications. 628 if (!extension_service->IsExtensionEnabled(params->item_id)) 629 return false; 630 631 service->RestartApplication(params->item_id); 632 return true; 633 } 634 635 DeveloperPrivateRestartFunction::~DeveloperPrivateRestartFunction() {} 636 637 DeveloperPrivateEnableFunction::DeveloperPrivateEnableFunction() {} 638 639 bool DeveloperPrivateEnableFunction::RunImpl() { 640 scoped_ptr<Enable::Params> params(Enable::Params::Create(*args_)); 641 EXTENSION_FUNCTION_VALIDATE(params.get()); 642 643 std::string extension_id = params->item_id; 644 645 ExtensionSystem* system = ExtensionSystem::Get(profile()); 646 ManagementPolicy* management_policy = system->management_policy(); 647 ExtensionService* service = profile()->GetExtensionService(); 648 649 const Extension* extension = service->GetInstalledExtension(extension_id); 650 if (!extension || 651 !management_policy->UserMayModifySettings(extension, NULL)) { 652 LOG(ERROR) << "Attempt to enable an extension that is non-usermanagable " 653 "was made. Extension id: " << extension->id(); 654 return false; 655 } 656 657 if (params->enable) { 658 ExtensionPrefs* prefs = service->extension_prefs(); 659 if (prefs->DidExtensionEscalatePermissions(extension_id)) { 660 ShellWindowRegistry* registry = ShellWindowRegistry::Get(profile()); 661 CHECK(registry); 662 ShellWindow* shell_window = registry->GetShellWindowForRenderViewHost( 663 render_view_host()); 664 if (!shell_window) { 665 return false; 666 } 667 668 ShowExtensionDisabledDialog( 669 service, shell_window->web_contents(), extension); 670 } else if ((prefs->GetDisableReasons(extension_id) & 671 Extension::DISABLE_UNSUPPORTED_REQUIREMENT) && 672 !requirements_checker_.get()) { 673 // Recheck the requirements. 674 scoped_refptr<const Extension> extension = 675 service->GetExtensionById(extension_id, 676 true );// include_disabled 677 requirements_checker_.reset(new RequirementsChecker); 678 // Released by OnRequirementsChecked. 679 AddRef(); 680 requirements_checker_->Check( 681 extension, 682 base::Bind(&DeveloperPrivateEnableFunction::OnRequirementsChecked, 683 this, extension_id)); 684 } else { 685 service->EnableExtension(extension_id); 686 687 // Make sure any browser action contained within it is not hidden. 688 ExtensionActionAPI::SetBrowserActionVisibility( 689 prefs, extension->id(), true); 690 } 691 } else { 692 service->DisableExtension(extension_id, Extension::DISABLE_USER_ACTION); 693 } 694 return true; 695 } 696 697 void DeveloperPrivateEnableFunction::OnRequirementsChecked( 698 std::string extension_id, 699 std::vector<std::string> requirements_errors) { 700 if (requirements_errors.empty()) { 701 ExtensionService* service = profile()->GetExtensionService(); 702 service->EnableExtension(extension_id); 703 } else { 704 ExtensionErrorReporter::GetInstance()->ReportError( 705 UTF8ToUTF16(JoinString(requirements_errors, ' ')), 706 true /* be noisy */); 707 } 708 Release(); 709 } 710 711 DeveloperPrivateEnableFunction::~DeveloperPrivateEnableFunction() {} 712 713 bool DeveloperPrivateInspectFunction::RunImpl() { 714 scoped_ptr<developer::Inspect::Params> params( 715 developer::Inspect::Params::Create(*args_)); 716 EXTENSION_FUNCTION_VALIDATE(params.get() != NULL); 717 const developer::InspectOptions& options = params->options; 718 719 int render_process_id; 720 base::StringToInt(options.render_process_id, &render_process_id); 721 722 if (render_process_id == -1) { 723 // This is a lazy background page. Identify if it is a normal 724 // or incognito background page. 725 ExtensionService* service = profile()->GetExtensionService(); 726 if (options.incognito) 727 service = ExtensionSystem::Get( 728 service->profile()->GetOffTheRecordProfile())->extension_service(); 729 const Extension* extension = service->extensions()->GetByID( 730 options.extension_id); 731 DCHECK(extension); 732 // Wakes up the background page and opens the inspect window. 733 service->InspectBackgroundPage(extension); 734 return false; 735 } 736 737 int render_view_id; 738 base::StringToInt(options.render_view_id, &render_view_id); 739 content::RenderViewHost* host = content::RenderViewHost::FromID( 740 render_process_id, render_view_id); 741 742 if (!host) { 743 // This can happen if the host has gone away since the page was displayed. 744 return false; 745 } 746 747 DevToolsWindow::OpenDevToolsWindow(host); 748 return true; 749 } 750 751 DeveloperPrivateInspectFunction::~DeveloperPrivateInspectFunction() {} 752 753 bool DeveloperPrivateLoadUnpackedFunction::RunImpl() { 754 string16 select_title = 755 l10n_util::GetStringUTF16(IDS_EXTENSION_LOAD_FROM_DIRECTORY); 756 757 // Balanced in FileSelected / FileSelectionCanceled. 758 AddRef(); 759 bool result = ShowPicker( 760 ui::SelectFileDialog::SELECT_FOLDER, 761 DeveloperPrivateAPI::Get(profile())->GetLastUnpackedDirectory(), 762 select_title, 763 ui::SelectFileDialog::FileTypeInfo(), 764 0); 765 return result; 766 } 767 768 void DeveloperPrivateLoadUnpackedFunction::FileSelected( 769 const base::FilePath& path) { 770 ExtensionService* service = profile()->GetExtensionService(); 771 UnpackedInstaller::Create(service)->Load(path); 772 DeveloperPrivateAPI::Get(profile())->SetLastUnpackedDirectory(path); 773 SendResponse(true); 774 Release(); 775 } 776 777 void DeveloperPrivateLoadUnpackedFunction::FileSelectionCanceled() { 778 SendResponse(false); 779 Release(); 780 } 781 782 bool DeveloperPrivateChooseEntryFunction::ShowPicker( 783 ui::SelectFileDialog::Type picker_type, 784 const base::FilePath& last_directory, 785 const string16& select_title, 786 const ui::SelectFileDialog::FileTypeInfo& info, 787 int file_type_index) { 788 ShellWindowRegistry* registry = ShellWindowRegistry::Get(profile()); 789 DCHECK(registry); 790 ShellWindow* shell_window = registry->GetShellWindowForRenderViewHost( 791 render_view_host()); 792 if (!shell_window) { 793 return false; 794 } 795 796 // The entry picker will hold a reference to this function instance, 797 // and subsequent sending of the function response) until the user has 798 // selected a file or cancelled the picker. At that point, the picker will 799 // delete itself. 800 new EntryPicker(this, shell_window->web_contents(), picker_type, 801 last_directory, select_title, info, file_type_index); 802 return true; 803 } 804 805 bool DeveloperPrivateChooseEntryFunction::RunImpl() { return false; } 806 807 DeveloperPrivateChooseEntryFunction::~DeveloperPrivateChooseEntryFunction() {} 808 809 void DeveloperPrivatePackDirectoryFunction::OnPackSuccess( 810 const base::FilePath& crx_file, 811 const base::FilePath& pem_file) { 812 developer::PackDirectoryResponse response; 813 response.message = 814 UTF16ToUTF8(PackExtensionJob::StandardSuccessMessage(crx_file, pem_file)); 815 response.status = developer::PACK_STATUS_SUCCESS; 816 results_ = developer::PackDirectory::Results::Create(response); 817 SendResponse(true); 818 Release(); 819 } 820 821 void DeveloperPrivatePackDirectoryFunction::OnPackFailure( 822 const std::string& error, 823 ExtensionCreator::ErrorType error_type) { 824 developer::PackDirectoryResponse response; 825 response.message = error; 826 if (error_type == ExtensionCreator::kCRXExists) { 827 response.item_path = item_path_str_; 828 response.pem_path = key_path_str_; 829 response.override_flags = ExtensionCreator::kOverwriteCRX; 830 response.status = developer::PACK_STATUS_WARNING; 831 } else { 832 response.status = developer::PACK_STATUS_ERROR; 833 } 834 results_ = developer::PackDirectory::Results::Create(response); 835 SendResponse(true); 836 Release(); 837 } 838 839 bool DeveloperPrivatePackDirectoryFunction::RunImpl() { 840 scoped_ptr<PackDirectory::Params> params( 841 PackDirectory::Params::Create(*args_)); 842 EXTENSION_FUNCTION_VALIDATE(params.get()); 843 844 int flags = params->flags; 845 item_path_str_ = params->path; 846 key_path_str_ = params->private_key_path; 847 848 base::FilePath root_directory = 849 base::FilePath::FromWStringHack(UTF8ToWide(item_path_str_)); 850 851 base::FilePath key_file = 852 base::FilePath::FromWStringHack(UTF8ToWide(key_path_str_)); 853 854 developer::PackDirectoryResponse response; 855 if (root_directory.empty()) { 856 if (item_path_str_.empty()) 857 response.message = l10n_util::GetStringUTF8( 858 IDS_EXTENSION_PACK_DIALOG_ERROR_ROOT_REQUIRED); 859 else 860 response.message = l10n_util::GetStringUTF8( 861 IDS_EXTENSION_PACK_DIALOG_ERROR_ROOT_INVALID); 862 863 response.status = developer::PACK_STATUS_ERROR; 864 results_ = developer::PackDirectory::Results::Create(response); 865 SendResponse(true); 866 return true; 867 } 868 869 if (!key_path_str_.empty() && key_file.empty()) { 870 response.message = l10n_util::GetStringUTF8( 871 IDS_EXTENSION_PACK_DIALOG_ERROR_KEY_INVALID); 872 response.status = developer::PACK_STATUS_ERROR; 873 results_ = developer::PackDirectory::Results::Create(response); 874 SendResponse(true); 875 return true; 876 } 877 878 // Balanced in OnPackSuccess / OnPackFailure. 879 AddRef(); 880 881 pack_job_ = new PackExtensionJob(this, root_directory, key_file, flags); 882 pack_job_->Start(); 883 return true; 884 } 885 886 DeveloperPrivatePackDirectoryFunction::DeveloperPrivatePackDirectoryFunction() 887 {} 888 889 DeveloperPrivatePackDirectoryFunction::~DeveloperPrivatePackDirectoryFunction() 890 {} 891 892 DeveloperPrivateLoadUnpackedFunction::~DeveloperPrivateLoadUnpackedFunction() {} 893 894 bool DeveloperPrivateExportSyncfsFolderToLocalfsFunction::RunImpl() { 895 // TODO(grv) : add unittests. 896 base::FilePath::StringType project_name; 897 EXTENSION_FUNCTION_VALIDATE(args_->GetString(0, &project_name)); 898 if (!ValidateFolderName(project_name)) { 899 DLOG(INFO) << "Invalid project_name : [" << project_name << "]"; 900 return false; 901 } 902 903 context_ = content::BrowserContext::GetStoragePartition(profile(), 904 render_view_host()->GetSiteInstance())->GetFileSystemContext(); 905 906 base::FilePath project_path(profile()->GetPath()); 907 project_path = project_path.Append(kUnpackedAppsFolder); 908 project_path = project_path.Append(project_name); 909 910 content::BrowserThread::PostTask(content::BrowserThread::FILE, FROM_HERE, 911 base::Bind(&DeveloperPrivateExportSyncfsFolderToLocalfsFunction:: 912 ClearPrexistingDirectoryContent, 913 this, 914 project_path)); 915 916 return true; 917 } 918 919 void DeveloperPrivateExportSyncfsFolderToLocalfsFunction:: 920 ClearPrexistingDirectoryContent(const base::FilePath& project_path) { 921 922 // Clear the project directory before copying new files. 923 base::DeleteFile(project_path, true/*recursive*/); 924 925 pendingCopyOperationsCount_ = 1; 926 927 content::BrowserThread::PostTask(content::BrowserThread::IO, FROM_HERE, 928 base::Bind(&DeveloperPrivateExportSyncfsFolderToLocalfsFunction:: 929 ReadSyncFileSystemDirectory, 930 this, project_path, project_path.BaseName())); 931 } 932 933 void DeveloperPrivateExportSyncfsFolderToLocalfsFunction:: 934 ReadSyncFileSystemDirectory(const base::FilePath& project_path, 935 const base::FilePath& destination_path) { 936 std::string origin_url( 937 Extension::GetBaseURLFromExtensionId(extension_id()).spec()); 938 fileapi::FileSystemURL url(sync_file_system::CreateSyncableFileSystemURL( 939 GURL(origin_url), 940 destination_path)); 941 942 context_->operation_runner()->ReadDirectory( 943 url, base::Bind(&DeveloperPrivateExportSyncfsFolderToLocalfsFunction:: 944 ReadSyncFileSystemDirectoryCb, 945 this, project_path, destination_path)); 946 } 947 948 void DeveloperPrivateExportSyncfsFolderToLocalfsFunction:: 949 ReadSyncFileSystemDirectoryCb( 950 const base::FilePath& project_path, 951 const base::FilePath& destination_path, 952 base::PlatformFileError status, 953 const fileapi::FileSystemOperation::FileEntryList& file_list, 954 bool has_more) { 955 956 if (status != base::PLATFORM_FILE_OK) { 957 DLOG(ERROR) << "Error in copying files from sync filesystem."; 958 return; 959 } 960 961 // We add 1 to the pending copy operations for both files and directories. We 962 // release the directory copy operation once all the files under the directory 963 // are added for copying. We do that to ensure that pendingCopyOperationsCount 964 // does not become zero before all copy operations are finished. 965 // In case the directory happens to be executing the last copy operation it 966 // will call SendResponse to send the response to the API. The pending copy 967 // operations of files are released by the CopyFile function. 968 pendingCopyOperationsCount_ += file_list.size(); 969 970 for (size_t i = 0; i < file_list.size(); ++i) { 971 if (file_list[i].is_directory) { 972 ReadSyncFileSystemDirectory(project_path.Append(file_list[i].name), 973 destination_path.Append(file_list[i].name)); 974 continue; 975 } 976 977 std::string origin_url( 978 Extension::GetBaseURLFromExtensionId(extension_id()).spec()); 979 fileapi::FileSystemURL url(sync_file_system::CreateSyncableFileSystemURL( 980 GURL(origin_url), 981 destination_path.Append(file_list[i].name))); 982 base::FilePath target_path = project_path; 983 target_path = target_path.Append(file_list[i].name); 984 985 context_->operation_runner()->CreateSnapshotFile( 986 url, 987 base::Bind( 988 &DeveloperPrivateExportSyncfsFolderToLocalfsFunction:: 989 SnapshotFileCallback, 990 this, 991 target_path)); 992 993 } 994 995 // Directory copy operation released here. 996 pendingCopyOperationsCount_--; 997 998 if (!pendingCopyOperationsCount_) { 999 content::BrowserThread::PostTask(content::BrowserThread::UI, FROM_HERE, 1000 base::Bind(&DeveloperPrivateExportSyncfsFolderToLocalfsFunction:: 1001 SendResponse, 1002 this, 1003 success_)); 1004 } 1005 } 1006 1007 void DeveloperPrivateExportSyncfsFolderToLocalfsFunction::SnapshotFileCallback( 1008 const base::FilePath& target_path, 1009 base::PlatformFileError result, 1010 const base::PlatformFileInfo& file_info, 1011 const base::FilePath& src_path, 1012 const scoped_refptr<webkit_blob::ShareableFileReference>& file_ref) { 1013 if (result != base::PLATFORM_FILE_OK) { 1014 SetError("Error in copying files from sync filesystem."); 1015 success_ = false; 1016 return; 1017 } 1018 1019 content::BrowserThread::PostTask(content::BrowserThread::FILE, FROM_HERE, 1020 base::Bind(&DeveloperPrivateExportSyncfsFolderToLocalfsFunction::CopyFile, 1021 this, 1022 src_path, 1023 target_path)); 1024 } 1025 1026 void DeveloperPrivateExportSyncfsFolderToLocalfsFunction::CopyFile( 1027 const base::FilePath& src_path, 1028 const base::FilePath& target_path) { 1029 if (!file_util::CreateDirectory(target_path.DirName())) { 1030 SetError("Error in copying files from sync filesystem."); 1031 success_ = false; 1032 } 1033 1034 if (success_) 1035 base::CopyFile(src_path, target_path); 1036 1037 CHECK(pendingCopyOperationsCount_ > 0); 1038 pendingCopyOperationsCount_--; 1039 1040 if (!pendingCopyOperationsCount_) { 1041 content::BrowserThread::PostTask(content::BrowserThread::UI, FROM_HERE, 1042 base::Bind(&DeveloperPrivateExportSyncfsFolderToLocalfsFunction:: 1043 SendResponse, 1044 this, 1045 success_)); 1046 } 1047 } 1048 1049 DeveloperPrivateExportSyncfsFolderToLocalfsFunction:: 1050 DeveloperPrivateExportSyncfsFolderToLocalfsFunction() 1051 : pendingCopyOperationsCount_(0), success_(true) {} 1052 1053 DeveloperPrivateExportSyncfsFolderToLocalfsFunction:: 1054 ~DeveloperPrivateExportSyncfsFolderToLocalfsFunction() {} 1055 1056 bool DeveloperPrivateLoadProjectFunction::RunImpl() { 1057 // TODO(grv) : add unit tests. 1058 base::FilePath::StringType project_name; 1059 EXTENSION_FUNCTION_VALIDATE(args_->GetString(0, &project_name)); 1060 if (!ValidateFolderName(project_name)) { 1061 DLOG(INFO) << "Invalid project_name : [" << project_name << "]"; 1062 return false; 1063 } 1064 1065 base::FilePath path(profile()->GetPath()); 1066 path = path.Append(kUnpackedAppsFolder); 1067 // TODO(grv) : Sanitize / check project_name. 1068 path = path.Append(project_name); 1069 ExtensionService* service = profile()->GetExtensionService(); 1070 UnpackedInstaller::Create(service)->Load(path); 1071 1072 const ExtensionSet* extensions = service->extensions(); 1073 // Released by GetUnpackedExtension. 1074 AddRef(); 1075 content::BrowserThread::PostTask(content::BrowserThread::FILE, FROM_HERE, 1076 base::Bind(&DeveloperPrivateLoadProjectFunction::GetUnpackedExtension, 1077 this, path, extensions)); 1078 return true; 1079 } 1080 1081 void DeveloperPrivateLoadProjectFunction::GetUnpackedExtension( 1082 const base::FilePath& path, 1083 const ExtensionSet* extensions) { 1084 const Extension* extension = GetExtensionByPath(extensions, path); 1085 bool success = true; 1086 if (extension) { 1087 SetResult(base::Value::CreateStringValue(extension->id())); 1088 } else { 1089 SetError("unable to load the project"); 1090 success = false; 1091 } 1092 content::BrowserThread::PostTask(content::BrowserThread::UI, FROM_HERE, 1093 base::Bind(&DeveloperPrivateLoadProjectFunction::SendResponse, 1094 this, 1095 success)); 1096 Release(); 1097 } 1098 1099 DeveloperPrivateLoadProjectFunction::DeveloperPrivateLoadProjectFunction() {} 1100 1101 DeveloperPrivateLoadProjectFunction::~DeveloperPrivateLoadProjectFunction() {} 1102 1103 bool DeveloperPrivateChoosePathFunction::RunImpl() { 1104 1105 scoped_ptr<developer::ChoosePath::Params> params( 1106 developer::ChoosePath::Params::Create(*args_)); 1107 EXTENSION_FUNCTION_VALIDATE(params.get() != NULL); 1108 1109 ui::SelectFileDialog::Type type = ui::SelectFileDialog::SELECT_FOLDER; 1110 ui::SelectFileDialog::FileTypeInfo info; 1111 if (params->select_type == developer::SELECT_TYPE_FILE) { 1112 type = ui::SelectFileDialog::SELECT_OPEN_FILE; 1113 } 1114 string16 select_title; 1115 1116 int file_type_index = 0; 1117 if (params->file_type == developer::FILE_TYPE_LOAD) 1118 select_title = l10n_util::GetStringUTF16(IDS_EXTENSION_LOAD_FROM_DIRECTORY); 1119 else if (params->file_type== developer::FILE_TYPE_PEM) { 1120 select_title = l10n_util::GetStringUTF16( 1121 IDS_EXTENSION_PACK_DIALOG_SELECT_KEY); 1122 info.extensions.push_back(std::vector<base::FilePath::StringType>()); 1123 info.extensions.front().push_back(FILE_PATH_LITERAL("pem")); 1124 info.extension_description_overrides.push_back( 1125 l10n_util::GetStringUTF16( 1126 IDS_EXTENSION_PACK_DIALOG_KEY_FILE_TYPE_DESCRIPTION)); 1127 info.include_all_files = true; 1128 file_type_index = 1; 1129 } else { 1130 NOTREACHED(); 1131 } 1132 1133 // Balanced by FileSelected / FileSelectionCanceled. 1134 AddRef(); 1135 bool result = ShowPicker( 1136 type, 1137 DeveloperPrivateAPI::Get(profile())->GetLastUnpackedDirectory(), 1138 select_title, 1139 info, 1140 file_type_index); 1141 return result; 1142 } 1143 1144 void DeveloperPrivateChoosePathFunction::FileSelected( 1145 const base::FilePath& path) { 1146 SetResult(base::Value::CreateStringValue( 1147 UTF16ToUTF8(path.LossyDisplayName()))); 1148 SendResponse(true); 1149 Release(); 1150 } 1151 1152 void DeveloperPrivateChoosePathFunction::FileSelectionCanceled() { 1153 SendResponse(false); 1154 Release(); 1155 } 1156 1157 DeveloperPrivateChoosePathFunction::~DeveloperPrivateChoosePathFunction() {} 1158 1159 bool DeveloperPrivateGetStringsFunction::RunImpl() { 1160 base::DictionaryValue* dict = new base::DictionaryValue(); 1161 SetResult(dict); 1162 1163 webui::SetFontAndTextDirection(dict); 1164 1165 #define SET_STRING(id, idr) \ 1166 dict->SetString(id, l10n_util::GetStringUTF16(idr)) 1167 SET_STRING("extensionSettings", IDS_MANAGE_EXTENSIONS_SETTING_WINDOWS_TITLE); 1168 1169 SET_STRING("appsDevtoolSearch", IDS_APPS_DEVTOOL_SEARCH); 1170 SET_STRING("appsDevtoolApps", IDS_APPS_DEVTOOL_APPS_INSTALLED); 1171 SET_STRING("appsDevtoolExtensions", IDS_APPS_DEVTOOL_EXTENSIONS_INSTALLED); 1172 SET_STRING("appsDevtoolNoExtensions", IDS_EXTENSIONS_NONE_INSTALLED); 1173 SET_STRING("appsDevtoolUnpacked", IDS_APPS_DEVTOOL_UNPACKED_INSTALLED); 1174 SET_STRING("appsDevtoolInstalled", IDS_APPS_DEVTOOL_INSTALLED); 1175 SET_STRING("appsDevtoolNoPackedApps", IDS_APPS_DEVTOOL_NO_PACKED_APPS); 1176 SET_STRING("appsDevtoolNoUnpackedApps", IDS_APPS_DEVTOOL_NO_UNPACKED_APPS); 1177 SET_STRING("appsDevtoolNoPackedExtensions", 1178 IDS_APPS_DEVTOOL_NO_PACKED_EXTENSIONS); 1179 SET_STRING("appsDevtoolNoUnpackedExtensions", 1180 IDS_APPS_DEVTOOL_NO_UNPACKED_EXTENSIONS); 1181 SET_STRING("appsDevtoolUpdating", IDS_APPS_DEVTOOL_UPDATING); 1182 SET_STRING("extensionSettingsGetMoreExtensions", IDS_GET_MORE_EXTENSIONS); 1183 SET_STRING("extensionSettingsExtensionId", IDS_EXTENSIONS_ID); 1184 SET_STRING("extensionSettingsExtensionPath", IDS_EXTENSIONS_PATH); 1185 SET_STRING("extensionSettingsInspectViews", IDS_EXTENSIONS_INSPECT_VIEWS); 1186 SET_STRING("extensionSettingsInstallWarnings", 1187 IDS_EXTENSIONS_INSTALL_WARNINGS); 1188 SET_STRING("viewIncognito", IDS_EXTENSIONS_VIEW_INCOGNITO); 1189 SET_STRING("viewInactive", IDS_EXTENSIONS_VIEW_INACTIVE); 1190 SET_STRING("extensionSettingsEnable", IDS_EXTENSIONS_ENABLE); 1191 SET_STRING("extensionSettingsEnabled", IDS_EXTENSIONS_ENABLED); 1192 SET_STRING("extensionSettingsRemove", IDS_EXTENSIONS_REMOVE); 1193 SET_STRING("extensionSettingsEnableIncognito", 1194 IDS_EXTENSIONS_ENABLE_INCOGNITO); 1195 SET_STRING("extensionSettingsAllowFileAccess", 1196 IDS_EXTENSIONS_ALLOW_FILE_ACCESS); 1197 SET_STRING("extensionSettingsReloadTerminated", 1198 IDS_EXTENSIONS_RELOAD_TERMINATED); 1199 SET_STRING("extensionSettingsReloadUnpacked", IDS_EXTENSIONS_RELOAD_UNPACKED); 1200 SET_STRING("extensionSettingsLaunch", IDS_EXTENSIONS_LAUNCH); 1201 SET_STRING("extensionSettingsRestart", IDS_EXTENSIONS_RESTART); 1202 SET_STRING("extensionSettingsOptions", IDS_EXTENSIONS_OPTIONS_LINK); 1203 SET_STRING("extensionSettingsPermissions", IDS_EXTENSIONS_PERMISSIONS_LINK); 1204 SET_STRING("extensionSettingsVisitWebsite", IDS_EXTENSIONS_VISIT_WEBSITE); 1205 SET_STRING("extensionSettingsVisitWebStore", IDS_EXTENSIONS_VISIT_WEBSTORE); 1206 SET_STRING("extensionSettingsPolicyControlled", 1207 IDS_EXTENSIONS_POLICY_CONTROLLED); 1208 SET_STRING("extensionSettingsManagedMode", 1209 IDS_EXTENSIONS_LOCKED_MANAGED_USER); 1210 SET_STRING("extensionSettingsShowButton", IDS_EXTENSIONS_SHOW_BUTTON); 1211 SET_STRING("appsDevtoolLoadUnpackedButton", 1212 IDS_APPS_DEVTOOL_LOAD_UNPACKED_BUTTON); 1213 SET_STRING("appsDevtoolPackButton", IDS_APPS_DEVTOOL_PACK_BUTTON); 1214 SET_STRING("extensionSettingsCommandsLink", 1215 IDS_EXTENSIONS_COMMANDS_CONFIGURE); 1216 SET_STRING("appsDevtoolUpdateButton", IDS_APPS_DEVTOOL_UPDATE_BUTTON); 1217 SET_STRING("extensionSettingsWarningsTitle", IDS_EXTENSION_WARNINGS_TITLE); 1218 SET_STRING("extensionSettingsShowDetails", IDS_EXTENSIONS_SHOW_DETAILS); 1219 SET_STRING("extensionSettingsHideDetails", IDS_EXTENSIONS_HIDE_DETAILS); 1220 SET_STRING("extensionUninstall", IDS_EXTENSIONS_UNINSTALL); 1221 SET_STRING("extensionsPermissionsHeading", 1222 IDS_EXTENSIONS_PERMISSIONS_HEADING); 1223 SET_STRING("extensionsPermissionsClose", IDS_EXTENSIONS_PERMISSIONS_CLOSE); 1224 SET_STRING("extensionDisabled", IDS_EXTENSIONS_DISABLED); 1225 SET_STRING("extensionSettingsShowLogsButton", IDS_EXTENSIONS_SHOW_LOGS); 1226 SET_STRING("extensionSettingsMoreDetailsButton", IDS_EXTENSIONS_MORE_DETAILS); 1227 SET_STRING("extensionSettingsVersion", IDS_EXTENSIONS_VERSION); 1228 SET_STRING("extensionSettingsDelete", IDS_EXTENSIONS_DELETE); 1229 SET_STRING("extensionSettingsPack", IDS_EXTENSIONS_PACK); 1230 1231 // Pack Extension strings 1232 SET_STRING("packExtensionOverlay", IDS_EXTENSION_PACK_DIALOG_TITLE); 1233 SET_STRING("packExtensionHeading", IDS_EXTENSION_ADT_PACK_DIALOG_HEADING); 1234 SET_STRING("packExtensionCommit", IDS_EXTENSION_PACK_BUTTON); 1235 SET_STRING("ok", IDS_OK); 1236 SET_STRING("cancel", IDS_CANCEL); 1237 SET_STRING("packExtensionRootDir", 1238 IDS_EXTENSION_PACK_DIALOG_ROOT_DIRECTORY_LABEL); 1239 SET_STRING("packExtensionPrivateKey", 1240 IDS_EXTENSION_PACK_DIALOG_PRIVATE_KEY_LABEL); 1241 SET_STRING("packExtensionBrowseButton", IDS_EXTENSION_PACK_DIALOG_BROWSE); 1242 SET_STRING("packExtensionProceedAnyway", IDS_EXTENSION_PROCEED_ANYWAY); 1243 SET_STRING("packExtensionWarningTitle", IDS_EXTENSION_PACK_WARNING_TITLE); 1244 SET_STRING("packExtensionErrorTitle", IDS_EXTENSION_PACK_ERROR_TITLE); 1245 1246 // Delete confirmation dialog. 1247 SET_STRING("deleteConfirmationDeleteButton", 1248 IDS_APPS_DEVTOOL_DELETE_CONFIRMATION_BUTTON); 1249 SET_STRING("deleteConfirmationTitle", 1250 IDS_APPS_DEVTOOL_DELETE_CONFIRMATION_TITLE); 1251 SET_STRING("deleteConfirmationMessageApp", 1252 IDS_APPS_DEVTOOL_DELETE_CONFIRMATION_MESSAGE_APP); 1253 SET_STRING("deleteConfirmationMessageExtension", 1254 IDS_APPS_DEVTOOL_DELETE_CONFIRMATION_MESSAGE_EXTENSION); 1255 1256 #undef SET_STRING 1257 return true; 1258 } 1259 1260 DeveloperPrivateGetStringsFunction::~DeveloperPrivateGetStringsFunction() {} 1261 1262 } // namespace api 1263 1264 } // namespace extensions 1265