developer_private_api.cc revision ba5b9a6411cb1792fd21f0a078d7a25cd1ceec16
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 69using apps::ShellWindow; 70using apps::ShellWindowRegistry; 71using content::RenderViewHost; 72 73namespace extensions { 74 75namespace events = event_names; 76 77namespace { 78 79const base::FilePath::CharType kUnpackedAppsFolder[] 80 = FILE_PATH_LITERAL("apps_target"); 81 82ExtensionUpdater* GetExtensionUpdater(Profile* profile) { 83 return profile->GetExtensionService()->updater(); 84} 85 86std::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 98bool 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 104const 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 115std::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 124namespace AllowFileAccess = api::developer_private::AllowFileAccess; 125namespace AllowIncognito = api::developer_private::AllowIncognito; 126namespace ChoosePath = api::developer_private::ChoosePath; 127namespace Enable = api::developer_private::Enable; 128namespace GetItemsInfo = api::developer_private::GetItemsInfo; 129namespace Inspect = api::developer_private::Inspect; 130namespace PackDirectory = api::developer_private::PackDirectory; 131namespace Reload = api::developer_private::Reload; 132namespace Restart = api::developer_private::Restart; 133 134DeveloperPrivateAPI* DeveloperPrivateAPI::Get(Profile* profile) { 135 return DeveloperPrivateAPIFactory::GetForProfile(profile); 136} 137 138DeveloperPrivateAPI::DeveloperPrivateAPI(Profile* profile) : profile_(profile) { 139 RegisterNotifications(); 140} 141 142DeveloperPrivateEventRouter::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 162DeveloperPrivateEventRouter::~DeveloperPrivateEventRouter() {} 163 164void 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 220void DeveloperPrivateAPI::SetLastUnpackedDirectory(const base::FilePath& path) { 221 last_unpacked_directory_ = path; 222} 223 224void DeveloperPrivateAPI::RegisterNotifications() { 225 ExtensionSystem::Get(profile_)->event_router()->RegisterObserver( 226 this, events::kDeveloperPrivateOnItemStateChanged); 227} 228 229DeveloperPrivateAPI::~DeveloperPrivateAPI() {} 230 231void DeveloperPrivateAPI::Shutdown() {} 232 233void DeveloperPrivateAPI::OnListenerAdded( 234 const EventListenerInfo& details) { 235 if (!developer_private_event_router_) 236 developer_private_event_router_.reset( 237 new DeveloperPrivateEventRouter(profile_)); 238} 239 240void 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 247namespace api { 248 249bool 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 257DeveloperPrivateAutoUpdateFunction::~DeveloperPrivateAutoUpdateFunction() {} 258 259scoped_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 346void 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 369void 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 392linked_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 414ItemInspectViewList 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 460bool 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 because they are only extensions as an 489 // implementation detail of Chrome. 490 if (item.location() == Manifest::COMPONENT && 491 !CommandLine::ForCurrentProcess()->HasSwitch( 492 switches::kShowComponentExtensionOptions)) { 493 continue; 494 } 495 496 // Don't show apps that aren't visible in either launcher or ntp. 497 if (item.is_app() && !item.ShouldDisplayInAppLauncher() && 498 !item.ShouldDisplayInNewTabPage() && 499 !Manifest::IsUnpackedLocation(item.location())) { 500 continue; 501 } 502 503 item_list.push_back(make_linked_ptr<developer::ItemInfo>( 504 CreateItemInfo( 505 item, service->IsExtensionEnabled(item.id())).release())); 506 } 507 508 results_ = developer::GetItemsInfo::Results::Create(item_list); 509 SendResponse(true); 510 511 return true; 512} 513 514DeveloperPrivateGetItemsInfoFunction::~DeveloperPrivateGetItemsInfoFunction() {} 515 516bool DeveloperPrivateAllowFileAccessFunction::RunImpl() { 517 scoped_ptr<AllowFileAccess::Params> params( 518 AllowFileAccess::Params::Create(*args_)); 519 EXTENSION_FUNCTION_VALIDATE(params.get()); 520 521 EXTENSION_FUNCTION_VALIDATE(user_gesture_); 522 523 ExtensionSystem* system = ExtensionSystem::Get(profile()); 524 ManagementPolicy* management_policy = system->management_policy(); 525 ExtensionService* service = profile()->GetExtensionService(); 526 const Extension* extension = service->GetInstalledExtension(params->item_id); 527 bool result = true; 528 529 if (!extension) { 530 result = false; 531 } else if (!management_policy->UserMayModifySettings(extension, NULL)) { 532 LOG(ERROR) << "Attempt to change allow file access of an extension that " 533 << "non-usermanagable was made. Extension id : " 534 << extension->id(); 535 result = false; 536 } else { 537 service->SetAllowFileAccess(extension, params->allow); 538 result = true; 539 } 540 541 return result; 542} 543 544DeveloperPrivateAllowFileAccessFunction:: 545 ~DeveloperPrivateAllowFileAccessFunction() {} 546 547bool DeveloperPrivateAllowIncognitoFunction::RunImpl() { 548 scoped_ptr<AllowIncognito::Params> params( 549 AllowIncognito::Params::Create(*args_)); 550 EXTENSION_FUNCTION_VALIDATE(params.get()); 551 552 ExtensionService* service = profile()->GetExtensionService(); 553 const Extension* extension = service->GetInstalledExtension(params->item_id); 554 bool result = true; 555 556 if (!extension) 557 result = false; 558 else 559 service->SetIsIncognitoEnabled(extension->id(), params->allow); 560 561 return result; 562} 563 564DeveloperPrivateAllowIncognitoFunction:: 565 ~DeveloperPrivateAllowIncognitoFunction() {} 566 567 568bool DeveloperPrivateReloadFunction::RunImpl() { 569 scoped_ptr<Reload::Params> params(Reload::Params::Create(*args_)); 570 EXTENSION_FUNCTION_VALIDATE(params.get()); 571 572 ExtensionService* service = profile()->GetExtensionService(); 573 CHECK(!params->item_id.empty()); 574 service->ReloadExtension(params->item_id); 575 return true; 576} 577 578bool DeveloperPrivateShowPermissionsDialogFunction::RunImpl() { 579 EXTENSION_FUNCTION_VALIDATE(args_->GetString(0, &extension_id_)); 580 ExtensionService* service = profile()->GetExtensionService(); 581 CHECK(!extension_id_.empty()); 582 ShellWindowRegistry* registry = ShellWindowRegistry::Get(profile()); 583 DCHECK(registry); 584 ShellWindow* shell_window = registry->GetShellWindowForRenderViewHost( 585 render_view_host()); 586 prompt_.reset(new ExtensionInstallPrompt(shell_window->web_contents())); 587 const Extension* extension = service->GetInstalledExtension(extension_id_); 588 589 if (!extension) 590 return false; 591 592 // Released by InstallUIAbort or InstallUIProceed. 593 AddRef(); 594 std::vector<base::FilePath> retained_file_paths; 595 if (extension->HasAPIPermission(extensions::APIPermission::kFileSystem)) { 596 std::vector<apps::SavedFileEntry> retained_file_entries = 597 apps::SavedFilesService::Get(profile())->GetAllFileEntries( 598 extension_id_); 599 for (size_t i = 0; i < retained_file_entries.size(); i++) { 600 retained_file_paths.push_back(retained_file_entries[i].path); 601 } 602 } 603 prompt_->ReviewPermissions(this, extension, retained_file_paths); 604 return true; 605} 606 607DeveloperPrivateReloadFunction::~DeveloperPrivateReloadFunction() {} 608 609// This is called when the user clicks "Revoke File Access." 610void DeveloperPrivateShowPermissionsDialogFunction::InstallUIProceed() { 611 apps::SavedFilesService::Get(profile())->ClearQueue( 612 profile()->GetExtensionService()->GetExtensionById(extension_id_, true)); 613 if (apps::AppRestoreService::Get(profile())->IsAppRestorable(extension_id_)) 614 apps::AppLoadService::Get(profile())->RestartApplication(extension_id_); 615 SendResponse(true); 616 Release(); 617} 618 619void DeveloperPrivateShowPermissionsDialogFunction::InstallUIAbort( 620 bool user_initiated) { 621 SendResponse(true); 622 Release(); 623} 624 625DeveloperPrivateShowPermissionsDialogFunction:: 626 DeveloperPrivateShowPermissionsDialogFunction() {} 627 628DeveloperPrivateShowPermissionsDialogFunction:: 629 ~DeveloperPrivateShowPermissionsDialogFunction() {} 630 631bool DeveloperPrivateRestartFunction::RunImpl() { 632 scoped_ptr<Restart::Params> params(Restart::Params::Create(*args_)); 633 EXTENSION_FUNCTION_VALIDATE(params.get()); 634 635 apps::AppLoadService* service = apps::AppLoadService::Get(profile()); 636 EXTENSION_FUNCTION_VALIDATE(!params->item_id.empty()); 637 ExtensionService* extension_service = profile()->GetExtensionService(); 638 // Don't restart disabled applications. 639 if (!extension_service->IsExtensionEnabled(params->item_id)) 640 return false; 641 642 service->RestartApplication(params->item_id); 643 return true; 644} 645 646DeveloperPrivateRestartFunction::~DeveloperPrivateRestartFunction() {} 647 648DeveloperPrivateEnableFunction::DeveloperPrivateEnableFunction() {} 649 650bool DeveloperPrivateEnableFunction::RunImpl() { 651 scoped_ptr<Enable::Params> params(Enable::Params::Create(*args_)); 652 EXTENSION_FUNCTION_VALIDATE(params.get()); 653 654 std::string extension_id = params->item_id; 655 656 ExtensionSystem* system = ExtensionSystem::Get(profile()); 657 ManagementPolicy* management_policy = system->management_policy(); 658 ExtensionService* service = profile()->GetExtensionService(); 659 660 const Extension* extension = service->GetInstalledExtension(extension_id); 661 if (!extension || 662 !management_policy->UserMayModifySettings(extension, NULL)) { 663 LOG(ERROR) << "Attempt to enable an extension that is non-usermanagable " 664 "was made. Extension id: " << extension->id(); 665 return false; 666 } 667 668 if (params->enable) { 669 ExtensionPrefs* prefs = service->extension_prefs(); 670 if (prefs->DidExtensionEscalatePermissions(extension_id)) { 671 ShellWindowRegistry* registry = ShellWindowRegistry::Get(profile()); 672 CHECK(registry); 673 ShellWindow* shell_window = registry->GetShellWindowForRenderViewHost( 674 render_view_host()); 675 if (!shell_window) { 676 return false; 677 } 678 679 ShowExtensionDisabledDialog( 680 service, shell_window->web_contents(), extension); 681 } else if ((prefs->GetDisableReasons(extension_id) & 682 Extension::DISABLE_UNSUPPORTED_REQUIREMENT) && 683 !requirements_checker_.get()) { 684 // Recheck the requirements. 685 scoped_refptr<const Extension> extension = 686 service->GetExtensionById(extension_id, 687 true );// include_disabled 688 requirements_checker_.reset(new RequirementsChecker); 689 // Released by OnRequirementsChecked. 690 AddRef(); 691 requirements_checker_->Check( 692 extension, 693 base::Bind(&DeveloperPrivateEnableFunction::OnRequirementsChecked, 694 this, extension_id)); 695 } else { 696 service->EnableExtension(extension_id); 697 698 // Make sure any browser action contained within it is not hidden. 699 ExtensionActionAPI::SetBrowserActionVisibility( 700 prefs, extension->id(), true); 701 } 702 } else { 703 service->DisableExtension(extension_id, Extension::DISABLE_USER_ACTION); 704 } 705 return true; 706} 707 708void DeveloperPrivateEnableFunction::OnRequirementsChecked( 709 std::string extension_id, 710 std::vector<std::string> requirements_errors) { 711 if (requirements_errors.empty()) { 712 ExtensionService* service = profile()->GetExtensionService(); 713 service->EnableExtension(extension_id); 714 } else { 715 ExtensionErrorReporter::GetInstance()->ReportError( 716 UTF8ToUTF16(JoinString(requirements_errors, ' ')), 717 true /* be noisy */); 718 } 719 Release(); 720} 721 722DeveloperPrivateEnableFunction::~DeveloperPrivateEnableFunction() {} 723 724bool DeveloperPrivateInspectFunction::RunImpl() { 725 scoped_ptr<developer::Inspect::Params> params( 726 developer::Inspect::Params::Create(*args_)); 727 EXTENSION_FUNCTION_VALIDATE(params.get() != NULL); 728 const developer::InspectOptions& options = params->options; 729 730 int render_process_id; 731 base::StringToInt(options.render_process_id, &render_process_id); 732 733 if (render_process_id == -1) { 734 // This is a lazy background page. Identify if it is a normal 735 // or incognito background page. 736 ExtensionService* service = profile()->GetExtensionService(); 737 if (options.incognito) 738 service = ExtensionSystem::Get( 739 service->profile()->GetOffTheRecordProfile())->extension_service(); 740 const Extension* extension = service->extensions()->GetByID( 741 options.extension_id); 742 DCHECK(extension); 743 // Wakes up the background page and opens the inspect window. 744 service->InspectBackgroundPage(extension); 745 return false; 746 } 747 748 int render_view_id; 749 base::StringToInt(options.render_view_id, &render_view_id); 750 content::RenderViewHost* host = content::RenderViewHost::FromID( 751 render_process_id, render_view_id); 752 753 if (!host) { 754 // This can happen if the host has gone away since the page was displayed. 755 return false; 756 } 757 758 DevToolsWindow::OpenDevToolsWindow(host); 759 return true; 760} 761 762DeveloperPrivateInspectFunction::~DeveloperPrivateInspectFunction() {} 763 764bool DeveloperPrivateLoadUnpackedFunction::RunImpl() { 765 string16 select_title = 766 l10n_util::GetStringUTF16(IDS_EXTENSION_LOAD_FROM_DIRECTORY); 767 768 // Balanced in FileSelected / FileSelectionCanceled. 769 AddRef(); 770 bool result = ShowPicker( 771 ui::SelectFileDialog::SELECT_FOLDER, 772 DeveloperPrivateAPI::Get(profile())->GetLastUnpackedDirectory(), 773 select_title, 774 ui::SelectFileDialog::FileTypeInfo(), 775 0); 776 return result; 777} 778 779void DeveloperPrivateLoadUnpackedFunction::FileSelected( 780 const base::FilePath& path) { 781 ExtensionService* service = profile()->GetExtensionService(); 782 UnpackedInstaller::Create(service)->Load(path); 783 DeveloperPrivateAPI::Get(profile())->SetLastUnpackedDirectory(path); 784 SendResponse(true); 785 Release(); 786} 787 788void DeveloperPrivateLoadUnpackedFunction::FileSelectionCanceled() { 789 SendResponse(false); 790 Release(); 791} 792 793bool DeveloperPrivateChooseEntryFunction::ShowPicker( 794 ui::SelectFileDialog::Type picker_type, 795 const base::FilePath& last_directory, 796 const string16& select_title, 797 const ui::SelectFileDialog::FileTypeInfo& info, 798 int file_type_index) { 799 ShellWindowRegistry* registry = ShellWindowRegistry::Get(profile()); 800 DCHECK(registry); 801 ShellWindow* shell_window = registry->GetShellWindowForRenderViewHost( 802 render_view_host()); 803 if (!shell_window) { 804 return false; 805 } 806 807 // The entry picker will hold a reference to this function instance, 808 // and subsequent sending of the function response) until the user has 809 // selected a file or cancelled the picker. At that point, the picker will 810 // delete itself. 811 new EntryPicker(this, shell_window->web_contents(), picker_type, 812 last_directory, select_title, info, file_type_index); 813 return true; 814} 815 816bool DeveloperPrivateChooseEntryFunction::RunImpl() { return false; } 817 818DeveloperPrivateChooseEntryFunction::~DeveloperPrivateChooseEntryFunction() {} 819 820void DeveloperPrivatePackDirectoryFunction::OnPackSuccess( 821 const base::FilePath& crx_file, 822 const base::FilePath& pem_file) { 823 developer::PackDirectoryResponse response; 824 response.message = 825 UTF16ToUTF8(PackExtensionJob::StandardSuccessMessage(crx_file, pem_file)); 826 response.status = developer::PACK_STATUS_SUCCESS; 827 results_ = developer::PackDirectory::Results::Create(response); 828 SendResponse(true); 829 Release(); 830} 831 832void DeveloperPrivatePackDirectoryFunction::OnPackFailure( 833 const std::string& error, 834 ExtensionCreator::ErrorType error_type) { 835 developer::PackDirectoryResponse response; 836 response.message = error; 837 if (error_type == ExtensionCreator::kCRXExists) { 838 response.item_path = item_path_str_; 839 response.pem_path = key_path_str_; 840 response.override_flags = ExtensionCreator::kOverwriteCRX; 841 response.status = developer::PACK_STATUS_WARNING; 842 } else { 843 response.status = developer::PACK_STATUS_ERROR; 844 } 845 results_ = developer::PackDirectory::Results::Create(response); 846 SendResponse(true); 847 Release(); 848} 849 850bool DeveloperPrivatePackDirectoryFunction::RunImpl() { 851 scoped_ptr<PackDirectory::Params> params( 852 PackDirectory::Params::Create(*args_)); 853 EXTENSION_FUNCTION_VALIDATE(params.get()); 854 855 int flags = params->flags; 856 item_path_str_ = params->path; 857 key_path_str_ = params->private_key_path; 858 859 base::FilePath root_directory = 860 base::FilePath::FromWStringHack(UTF8ToWide(item_path_str_)); 861 862 base::FilePath key_file = 863 base::FilePath::FromWStringHack(UTF8ToWide(key_path_str_)); 864 865 developer::PackDirectoryResponse response; 866 if (root_directory.empty()) { 867 if (item_path_str_.empty()) 868 response.message = l10n_util::GetStringUTF8( 869 IDS_EXTENSION_PACK_DIALOG_ERROR_ROOT_REQUIRED); 870 else 871 response.message = l10n_util::GetStringUTF8( 872 IDS_EXTENSION_PACK_DIALOG_ERROR_ROOT_INVALID); 873 874 response.status = developer::PACK_STATUS_ERROR; 875 results_ = developer::PackDirectory::Results::Create(response); 876 SendResponse(true); 877 return true; 878 } 879 880 if (!key_path_str_.empty() && key_file.empty()) { 881 response.message = l10n_util::GetStringUTF8( 882 IDS_EXTENSION_PACK_DIALOG_ERROR_KEY_INVALID); 883 response.status = developer::PACK_STATUS_ERROR; 884 results_ = developer::PackDirectory::Results::Create(response); 885 SendResponse(true); 886 return true; 887 } 888 889 // Balanced in OnPackSuccess / OnPackFailure. 890 AddRef(); 891 892 pack_job_ = new PackExtensionJob(this, root_directory, key_file, flags); 893 pack_job_->Start(); 894 return true; 895} 896 897DeveloperPrivatePackDirectoryFunction::DeveloperPrivatePackDirectoryFunction() 898{} 899 900DeveloperPrivatePackDirectoryFunction::~DeveloperPrivatePackDirectoryFunction() 901{} 902 903DeveloperPrivateLoadUnpackedFunction::~DeveloperPrivateLoadUnpackedFunction() {} 904 905bool DeveloperPrivateExportSyncfsFolderToLocalfsFunction::RunImpl() { 906 // TODO(grv) : add unittests. 907 base::FilePath::StringType project_name; 908 EXTENSION_FUNCTION_VALIDATE(args_->GetString(0, &project_name)); 909 if (!ValidateFolderName(project_name)) { 910 DLOG(INFO) << "Invalid project_name : [" << project_name << "]"; 911 return false; 912 } 913 914 context_ = content::BrowserContext::GetStoragePartition(profile(), 915 render_view_host()->GetSiteInstance())->GetFileSystemContext(); 916 917 base::FilePath project_path(profile()->GetPath()); 918 project_path = project_path.Append(kUnpackedAppsFolder); 919 project_path = project_path.Append(project_name); 920 921 content::BrowserThread::PostTask(content::BrowserThread::FILE, FROM_HERE, 922 base::Bind(&DeveloperPrivateExportSyncfsFolderToLocalfsFunction:: 923 ClearPrexistingDirectoryContent, 924 this, 925 project_path)); 926 927 return true; 928} 929 930void DeveloperPrivateExportSyncfsFolderToLocalfsFunction:: 931 ClearPrexistingDirectoryContent(const base::FilePath& project_path) { 932 933 // Clear the project directory before copying new files. 934 base::DeleteFile(project_path, true/*recursive*/); 935 936 pendingCopyOperationsCount_ = 1; 937 938 content::BrowserThread::PostTask(content::BrowserThread::IO, FROM_HERE, 939 base::Bind(&DeveloperPrivateExportSyncfsFolderToLocalfsFunction:: 940 ReadSyncFileSystemDirectory, 941 this, project_path, project_path.BaseName())); 942} 943 944void DeveloperPrivateExportSyncfsFolderToLocalfsFunction:: 945 ReadSyncFileSystemDirectory(const base::FilePath& project_path, 946 const base::FilePath& destination_path) { 947 std::string origin_url( 948 Extension::GetBaseURLFromExtensionId(extension_id()).spec()); 949 fileapi::FileSystemURL url(sync_file_system::CreateSyncableFileSystemURL( 950 GURL(origin_url), 951 destination_path)); 952 953 context_->operation_runner()->ReadDirectory( 954 url, base::Bind(&DeveloperPrivateExportSyncfsFolderToLocalfsFunction:: 955 ReadSyncFileSystemDirectoryCb, 956 this, project_path, destination_path)); 957} 958 959void DeveloperPrivateExportSyncfsFolderToLocalfsFunction:: 960 ReadSyncFileSystemDirectoryCb( 961 const base::FilePath& project_path, 962 const base::FilePath& destination_path, 963 base::PlatformFileError status, 964 const fileapi::FileSystemOperation::FileEntryList& file_list, 965 bool has_more) { 966 967 if (status != base::PLATFORM_FILE_OK) { 968 DLOG(ERROR) << "Error in copying files from sync filesystem."; 969 return; 970 } 971 972 // We add 1 to the pending copy operations for both files and directories. We 973 // release the directory copy operation once all the files under the directory 974 // are added for copying. We do that to ensure that pendingCopyOperationsCount 975 // does not become zero before all copy operations are finished. 976 // In case the directory happens to be executing the last copy operation it 977 // will call SendResponse to send the response to the API. The pending copy 978 // operations of files are released by the CopyFile function. 979 pendingCopyOperationsCount_ += file_list.size(); 980 981 for (size_t i = 0; i < file_list.size(); ++i) { 982 if (file_list[i].is_directory) { 983 ReadSyncFileSystemDirectory(project_path.Append(file_list[i].name), 984 destination_path.Append(file_list[i].name)); 985 continue; 986 } 987 988 std::string origin_url( 989 Extension::GetBaseURLFromExtensionId(extension_id()).spec()); 990 fileapi::FileSystemURL url(sync_file_system::CreateSyncableFileSystemURL( 991 GURL(origin_url), 992 destination_path.Append(file_list[i].name))); 993 base::FilePath target_path = project_path; 994 target_path = target_path.Append(file_list[i].name); 995 996 context_->operation_runner()->CreateSnapshotFile( 997 url, 998 base::Bind( 999 &DeveloperPrivateExportSyncfsFolderToLocalfsFunction:: 1000 SnapshotFileCallback, 1001 this, 1002 target_path)); 1003 1004 } 1005 1006 // Directory copy operation released here. 1007 pendingCopyOperationsCount_--; 1008 1009 if (!pendingCopyOperationsCount_) { 1010 content::BrowserThread::PostTask(content::BrowserThread::UI, FROM_HERE, 1011 base::Bind(&DeveloperPrivateExportSyncfsFolderToLocalfsFunction:: 1012 SendResponse, 1013 this, 1014 success_)); 1015 } 1016} 1017 1018void DeveloperPrivateExportSyncfsFolderToLocalfsFunction::SnapshotFileCallback( 1019 const base::FilePath& target_path, 1020 base::PlatformFileError result, 1021 const base::PlatformFileInfo& file_info, 1022 const base::FilePath& src_path, 1023 const scoped_refptr<webkit_blob::ShareableFileReference>& file_ref) { 1024 if (result != base::PLATFORM_FILE_OK) { 1025 SetError("Error in copying files from sync filesystem."); 1026 success_ = false; 1027 return; 1028 } 1029 1030 content::BrowserThread::PostTask(content::BrowserThread::FILE, FROM_HERE, 1031 base::Bind(&DeveloperPrivateExportSyncfsFolderToLocalfsFunction::CopyFile, 1032 this, 1033 src_path, 1034 target_path)); 1035} 1036 1037void DeveloperPrivateExportSyncfsFolderToLocalfsFunction::CopyFile( 1038 const base::FilePath& src_path, 1039 const base::FilePath& target_path) { 1040 if (!file_util::CreateDirectory(target_path.DirName())) { 1041 SetError("Error in copying files from sync filesystem."); 1042 success_ = false; 1043 } 1044 1045 if (success_) 1046 base::CopyFile(src_path, target_path); 1047 1048 CHECK(pendingCopyOperationsCount_ > 0); 1049 pendingCopyOperationsCount_--; 1050 1051 if (!pendingCopyOperationsCount_) { 1052 content::BrowserThread::PostTask(content::BrowserThread::UI, FROM_HERE, 1053 base::Bind(&DeveloperPrivateExportSyncfsFolderToLocalfsFunction:: 1054 SendResponse, 1055 this, 1056 success_)); 1057 } 1058} 1059 1060DeveloperPrivateExportSyncfsFolderToLocalfsFunction:: 1061 DeveloperPrivateExportSyncfsFolderToLocalfsFunction() 1062 : pendingCopyOperationsCount_(0), success_(true) {} 1063 1064DeveloperPrivateExportSyncfsFolderToLocalfsFunction:: 1065 ~DeveloperPrivateExportSyncfsFolderToLocalfsFunction() {} 1066 1067bool DeveloperPrivateLoadProjectFunction::RunImpl() { 1068 // TODO(grv) : add unit tests. 1069 base::FilePath::StringType project_name; 1070 EXTENSION_FUNCTION_VALIDATE(args_->GetString(0, &project_name)); 1071 if (!ValidateFolderName(project_name)) { 1072 DLOG(INFO) << "Invalid project_name : [" << project_name << "]"; 1073 return false; 1074 } 1075 1076 base::FilePath path(profile()->GetPath()); 1077 path = path.Append(kUnpackedAppsFolder); 1078 // TODO(grv) : Sanitize / check project_name. 1079 path = path.Append(project_name); 1080 ExtensionService* service = profile()->GetExtensionService(); 1081 UnpackedInstaller::Create(service)->Load(path); 1082 1083 const ExtensionSet* extensions = service->extensions(); 1084 // Released by GetUnpackedExtension. 1085 AddRef(); 1086 content::BrowserThread::PostTask(content::BrowserThread::FILE, FROM_HERE, 1087 base::Bind(&DeveloperPrivateLoadProjectFunction::GetUnpackedExtension, 1088 this, path, extensions)); 1089 return true; 1090} 1091 1092void DeveloperPrivateLoadProjectFunction::GetUnpackedExtension( 1093 const base::FilePath& path, 1094 const ExtensionSet* extensions) { 1095 const Extension* extension = GetExtensionByPath(extensions, path); 1096 bool success = true; 1097 if (extension) { 1098 SetResult(base::Value::CreateStringValue(extension->id())); 1099 } else { 1100 SetError("unable to load the project"); 1101 success = false; 1102 } 1103 content::BrowserThread::PostTask(content::BrowserThread::UI, FROM_HERE, 1104 base::Bind(&DeveloperPrivateLoadProjectFunction::SendResponse, 1105 this, 1106 success)); 1107 Release(); 1108} 1109 1110DeveloperPrivateLoadProjectFunction::DeveloperPrivateLoadProjectFunction() {} 1111 1112DeveloperPrivateLoadProjectFunction::~DeveloperPrivateLoadProjectFunction() {} 1113 1114bool DeveloperPrivateChoosePathFunction::RunImpl() { 1115 1116 scoped_ptr<developer::ChoosePath::Params> params( 1117 developer::ChoosePath::Params::Create(*args_)); 1118 EXTENSION_FUNCTION_VALIDATE(params.get() != NULL); 1119 1120 ui::SelectFileDialog::Type type = ui::SelectFileDialog::SELECT_FOLDER; 1121 ui::SelectFileDialog::FileTypeInfo info; 1122 if (params->select_type == developer::SELECT_TYPE_FILE) { 1123 type = ui::SelectFileDialog::SELECT_OPEN_FILE; 1124 } 1125 string16 select_title; 1126 1127 int file_type_index = 0; 1128 if (params->file_type == developer::FILE_TYPE_LOAD) 1129 select_title = l10n_util::GetStringUTF16(IDS_EXTENSION_LOAD_FROM_DIRECTORY); 1130 else if (params->file_type== developer::FILE_TYPE_PEM) { 1131 select_title = l10n_util::GetStringUTF16( 1132 IDS_EXTENSION_PACK_DIALOG_SELECT_KEY); 1133 info.extensions.push_back(std::vector<base::FilePath::StringType>()); 1134 info.extensions.front().push_back(FILE_PATH_LITERAL("pem")); 1135 info.extension_description_overrides.push_back( 1136 l10n_util::GetStringUTF16( 1137 IDS_EXTENSION_PACK_DIALOG_KEY_FILE_TYPE_DESCRIPTION)); 1138 info.include_all_files = true; 1139 file_type_index = 1; 1140 } else { 1141 NOTREACHED(); 1142 } 1143 1144 // Balanced by FileSelected / FileSelectionCanceled. 1145 AddRef(); 1146 bool result = ShowPicker( 1147 type, 1148 DeveloperPrivateAPI::Get(profile())->GetLastUnpackedDirectory(), 1149 select_title, 1150 info, 1151 file_type_index); 1152 return result; 1153} 1154 1155void DeveloperPrivateChoosePathFunction::FileSelected( 1156 const base::FilePath& path) { 1157 SetResult(base::Value::CreateStringValue( 1158 UTF16ToUTF8(path.LossyDisplayName()))); 1159 SendResponse(true); 1160 Release(); 1161} 1162 1163void DeveloperPrivateChoosePathFunction::FileSelectionCanceled() { 1164 SendResponse(false); 1165 Release(); 1166} 1167 1168DeveloperPrivateChoosePathFunction::~DeveloperPrivateChoosePathFunction() {} 1169 1170bool DeveloperPrivateGetStringsFunction::RunImpl() { 1171 base::DictionaryValue* dict = new base::DictionaryValue(); 1172 SetResult(dict); 1173 1174 webui::SetFontAndTextDirection(dict); 1175 1176 #define SET_STRING(id, idr) \ 1177 dict->SetString(id, l10n_util::GetStringUTF16(idr)) 1178 SET_STRING("extensionSettings", IDS_MANAGE_EXTENSIONS_SETTING_WINDOWS_TITLE); 1179 1180 SET_STRING("appsDevtoolSearch", IDS_APPS_DEVTOOL_SEARCH); 1181 SET_STRING("appsDevtoolApps", IDS_APPS_DEVTOOL_APPS_INSTALLED); 1182 SET_STRING("appsDevtoolExtensions", IDS_APPS_DEVTOOL_EXTENSIONS_INSTALLED); 1183 SET_STRING("appsDevtoolNoExtensions", IDS_EXTENSIONS_NONE_INSTALLED); 1184 SET_STRING("appsDevtoolUnpacked", IDS_APPS_DEVTOOL_UNPACKED_INSTALLED); 1185 SET_STRING("appsDevtoolInstalled", IDS_APPS_DEVTOOL_INSTALLED); 1186 SET_STRING("appsDevtoolNoPackedApps", IDS_APPS_DEVTOOL_NO_PACKED_APPS); 1187 SET_STRING("appsDevtoolNoUnpackedApps", IDS_APPS_DEVTOOL_NO_UNPACKED_APPS); 1188 SET_STRING("appsDevtoolNoPackedExtensions", 1189 IDS_APPS_DEVTOOL_NO_PACKED_EXTENSIONS); 1190 SET_STRING("appsDevtoolNoUnpackedExtensions", 1191 IDS_APPS_DEVTOOL_NO_UNPACKED_EXTENSIONS); 1192 SET_STRING("appsDevtoolUpdating", IDS_APPS_DEVTOOL_UPDATING); 1193 SET_STRING("extensionSettingsGetMoreExtensions", IDS_GET_MORE_EXTENSIONS); 1194 SET_STRING("extensionSettingsExtensionId", IDS_EXTENSIONS_ID); 1195 SET_STRING("extensionSettingsExtensionPath", IDS_EXTENSIONS_PATH); 1196 SET_STRING("extensionSettingsInspectViews", IDS_EXTENSIONS_INSPECT_VIEWS); 1197 SET_STRING("extensionSettingsInstallWarnings", 1198 IDS_EXTENSIONS_INSTALL_WARNINGS); 1199 SET_STRING("viewIncognito", IDS_EXTENSIONS_VIEW_INCOGNITO); 1200 SET_STRING("viewInactive", IDS_EXTENSIONS_VIEW_INACTIVE); 1201 SET_STRING("extensionSettingsEnable", IDS_EXTENSIONS_ENABLE); 1202 SET_STRING("extensionSettingsEnabled", IDS_EXTENSIONS_ENABLED); 1203 SET_STRING("extensionSettingsRemove", IDS_EXTENSIONS_REMOVE); 1204 SET_STRING("extensionSettingsEnableIncognito", 1205 IDS_EXTENSIONS_ENABLE_INCOGNITO); 1206 SET_STRING("extensionSettingsAllowFileAccess", 1207 IDS_EXTENSIONS_ALLOW_FILE_ACCESS); 1208 SET_STRING("extensionSettingsReloadTerminated", 1209 IDS_EXTENSIONS_RELOAD_TERMINATED); 1210 SET_STRING("extensionSettingsReloadUnpacked", IDS_EXTENSIONS_RELOAD_UNPACKED); 1211 SET_STRING("extensionSettingsLaunch", IDS_EXTENSIONS_LAUNCH); 1212 SET_STRING("extensionSettingsRestart", IDS_EXTENSIONS_RESTART); 1213 SET_STRING("extensionSettingsOptions", IDS_EXTENSIONS_OPTIONS_LINK); 1214 SET_STRING("extensionSettingsPermissions", IDS_EXTENSIONS_PERMISSIONS_LINK); 1215 SET_STRING("extensionSettingsVisitWebsite", IDS_EXTENSIONS_VISIT_WEBSITE); 1216 SET_STRING("extensionSettingsVisitWebStore", IDS_EXTENSIONS_VISIT_WEBSTORE); 1217 SET_STRING("extensionSettingsPolicyControlled", 1218 IDS_EXTENSIONS_POLICY_CONTROLLED); 1219 SET_STRING("extensionSettingsManagedMode", 1220 IDS_EXTENSIONS_LOCKED_MANAGED_USER); 1221 SET_STRING("extensionSettingsShowButton", IDS_EXTENSIONS_SHOW_BUTTON); 1222 SET_STRING("appsDevtoolLoadUnpackedButton", 1223 IDS_APPS_DEVTOOL_LOAD_UNPACKED_BUTTON); 1224 SET_STRING("appsDevtoolPackButton", IDS_APPS_DEVTOOL_PACK_BUTTON); 1225 SET_STRING("extensionSettingsCommandsLink", 1226 IDS_EXTENSIONS_COMMANDS_CONFIGURE); 1227 SET_STRING("appsDevtoolUpdateButton", IDS_APPS_DEVTOOL_UPDATE_BUTTON); 1228 SET_STRING("extensionSettingsWarningsTitle", IDS_EXTENSION_WARNINGS_TITLE); 1229 SET_STRING("extensionSettingsShowDetails", IDS_EXTENSIONS_SHOW_DETAILS); 1230 SET_STRING("extensionSettingsHideDetails", IDS_EXTENSIONS_HIDE_DETAILS); 1231 SET_STRING("extensionUninstall", IDS_EXTENSIONS_UNINSTALL); 1232 SET_STRING("extensionsPermissionsHeading", 1233 IDS_EXTENSIONS_PERMISSIONS_HEADING); 1234 SET_STRING("extensionsPermissionsClose", IDS_EXTENSIONS_PERMISSIONS_CLOSE); 1235 SET_STRING("extensionDisabled", IDS_EXTENSIONS_DISABLED); 1236 SET_STRING("extensionSettingsShowLogsButton", IDS_EXTENSIONS_SHOW_LOGS); 1237 SET_STRING("extensionSettingsMoreDetailsButton", IDS_EXTENSIONS_MORE_DETAILS); 1238 SET_STRING("extensionSettingsVersion", IDS_EXTENSIONS_VERSION); 1239 SET_STRING("extensionSettingsDelete", IDS_EXTENSIONS_DELETE); 1240 SET_STRING("extensionSettingsPack", IDS_EXTENSIONS_PACK); 1241 1242// Pack Extension strings 1243 SET_STRING("packExtensionOverlay", IDS_EXTENSION_PACK_DIALOG_TITLE); 1244 SET_STRING("packExtensionHeading", IDS_EXTENSION_ADT_PACK_DIALOG_HEADING); 1245 SET_STRING("packExtensionCommit", IDS_EXTENSION_PACK_BUTTON); 1246 SET_STRING("ok", IDS_OK); 1247 SET_STRING("cancel", IDS_CANCEL); 1248 SET_STRING("packExtensionRootDir", 1249 IDS_EXTENSION_PACK_DIALOG_ROOT_DIRECTORY_LABEL); 1250 SET_STRING("packExtensionPrivateKey", 1251 IDS_EXTENSION_PACK_DIALOG_PRIVATE_KEY_LABEL); 1252 SET_STRING("packExtensionBrowseButton", IDS_EXTENSION_PACK_DIALOG_BROWSE); 1253 SET_STRING("packExtensionProceedAnyway", IDS_EXTENSION_PROCEED_ANYWAY); 1254 SET_STRING("packExtensionWarningTitle", IDS_EXTENSION_PACK_WARNING_TITLE); 1255 SET_STRING("packExtensionErrorTitle", IDS_EXTENSION_PACK_ERROR_TITLE); 1256 1257// Delete confirmation dialog. 1258 SET_STRING("deleteConfirmationDeleteButton", 1259 IDS_APPS_DEVTOOL_DELETE_CONFIRMATION_BUTTON); 1260 SET_STRING("deleteConfirmationTitle", 1261 IDS_APPS_DEVTOOL_DELETE_CONFIRMATION_TITLE); 1262 SET_STRING("deleteConfirmationMessageApp", 1263 IDS_APPS_DEVTOOL_DELETE_CONFIRMATION_MESSAGE_APP); 1264 SET_STRING("deleteConfirmationMessageExtension", 1265 IDS_APPS_DEVTOOL_DELETE_CONFIRMATION_MESSAGE_EXTENSION); 1266 1267 #undef SET_STRING 1268 return true; 1269} 1270 1271DeveloperPrivateGetStringsFunction::~DeveloperPrivateGetStringsFunction() {} 1272 1273} // namespace api 1274 1275} // namespace extensions 1276