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.
5 #include "chrome/browser/extensions/api/developer_private/developer_private_api.h"
8 #include "base/files/file_util.h"
9 #include "base/lazy_instance.h"
10 #include "base/metrics/histogram_macros.h"
11 #include "base/strings/string_number_conversions.h"
12 #include "base/strings/stringprintf.h"
13 #include "base/strings/utf_string_conversions.h"
14 #include "chrome/browser/devtools/devtools_window.h"
15 #include "chrome/browser/extensions/api/developer_private/developer_private_mangle.h"
16 #include "chrome/browser/extensions/api/developer_private/entry_picker.h"
17 #include "chrome/browser/extensions/api/developer_private/extension_info_generator.h"
18 #include "chrome/browser/extensions/api/developer_private/show_permissions_dialog_helper.h"
19 #include "chrome/browser/extensions/api/extension_action/extension_action_api.h"
20 #include "chrome/browser/extensions/api/file_handlers/app_file_handler_util.h"
21 #include "chrome/browser/extensions/devtools_util.h"
22 #include "chrome/browser/extensions/extension_commands_global_registry.h"
23 #include "chrome/browser/extensions/extension_service.h"
24 #include "chrome/browser/extensions/extension_tab_util.h"
25 #include "chrome/browser/extensions/extension_ui_util.h"
26 #include "chrome/browser/extensions/extension_util.h"
27 #include "chrome/browser/extensions/install_verifier.h"
28 #include "chrome/browser/extensions/shared_module_service.h"
29 #include "chrome/browser/extensions/unpacked_installer.h"
30 #include "chrome/browser/extensions/updater/extension_updater.h"
31 #include "chrome/browser/extensions/webstore_reinstaller.h"
32 #include "chrome/browser/platform_util.h"
33 #include "chrome/browser/prefs/incognito_mode_prefs.h"
34 #include "chrome/browser/profiles/profile.h"
35 #include "chrome/browser/ui/apps/app_info_dialog.h"
36 #include "chrome/browser/ui/browser_finder.h"
37 #include "chrome/browser/ui/extensions/app_launch_params.h"
38 #include "chrome/browser/ui/extensions/application_launch.h"
39 #include "chrome/browser/ui/tabs/tab_strip_model.h"
40 #include "chrome/common/extensions/api/developer_private.h"
41 #include "chrome/common/extensions/manifest_handlers/app_launch_info.h"
42 #include "chrome/common/pref_names.h"
43 #include "chrome/common/url_constants.h"
44 #include "chrome/grit/generated_resources.h"
45 #include "content/public/browser/browser_thread.h"
46 #include "content/public/browser/notification_service.h"
47 #include "content/public/browser/render_frame_host.h"
48 #include "content/public/browser/render_process_host.h"
49 #include "content/public/browser/site_instance.h"
50 #include "content/public/browser/storage_partition.h"
51 #include "content/public/browser/web_contents.h"
52 #include "extensions/browser/app_window/app_window.h"
53 #include "extensions/browser/app_window/app_window_registry.h"
54 #include "extensions/browser/error_map.h"
55 #include "extensions/browser/extension_error.h"
56 #include "extensions/browser/extension_prefs.h"
57 #include "extensions/browser/extension_registry.h"
58 #include "extensions/browser/extension_system.h"
59 #include "extensions/browser/file_highlighter.h"
60 #include "extensions/browser/management_policy.h"
61 #include "extensions/browser/notification_types.h"
62 #include "extensions/browser/warning_service.h"
63 #include "extensions/common/constants.h"
64 #include "extensions/common/extension_set.h"
65 #include "extensions/common/feature_switch.h"
66 #include "extensions/common/install_warning.h"
67 #include "extensions/common/manifest.h"
68 #include "extensions/common/manifest_handlers/options_page_info.h"
69 #include "extensions/common/permissions/permissions_data.h"
70 #include "extensions/grit/extensions_browser_resources.h"
71 #include "storage/browser/fileapi/external_mount_points.h"
72 #include "storage/browser/fileapi/file_system_context.h"
73 #include "storage/browser/fileapi/file_system_operation.h"
74 #include "storage/browser/fileapi/file_system_operation_runner.h"
75 #include "storage/browser/fileapi/isolated_context.h"
76 #include "ui/base/l10n/l10n_util.h"
78 namespace extensions
{
80 namespace developer
= api::developer_private
;
84 const char kNoSuchExtensionError
[] = "No such extension.";
85 const char kCannotModifyPolicyExtensionError
[] =
86 "Cannot modify the extension by policy.";
87 const char kRequiresUserGestureError
[] =
88 "This action requires a user gesture.";
89 const char kCouldNotShowSelectFileDialogError
[] =
90 "Could not show a file chooser.";
91 const char kFileSelectionCanceled
[] =
92 "File selection was canceled.";
93 const char kNoSuchRendererError
[] = "No such renderer.";
94 const char kInvalidPathError
[] = "Invalid path.";
95 const char kManifestKeyIsRequiredError
[] =
96 "The 'manifestKey' argument is required for manifest files.";
97 const char kCouldNotFindWebContentsError
[] =
98 "Could not find a valid web contents.";
99 const char kCannotUpdateSupervisedProfileSettingsError
[] =
100 "Cannot change settings for a supervised profile.";
101 const char kNoOptionsPageForExtensionError
[] =
102 "Extension does not have an options page.";
104 const char kUnpackedAppsFolder
[] = "apps_target";
105 const char kManifestFile
[] = "manifest.json";
107 ExtensionService
* GetExtensionService(content::BrowserContext
* context
) {
108 return ExtensionSystem::Get(context
)->extension_service();
111 std::string
ReadFileToString(const base::FilePath
& path
) {
113 ignore_result(base::ReadFileToString(path
, &data
));
117 bool UserCanModifyExtensionConfiguration(
118 const Extension
* extension
,
119 content::BrowserContext
* browser_context
,
120 std::string
* error
) {
121 ManagementPolicy
* management_policy
=
122 ExtensionSystem::Get(browser_context
)->management_policy();
123 if (!management_policy
->UserMayModifySettings(extension
, nullptr)) {
124 LOG(ERROR
) << "Attempt to change settings of an extension that is "
125 << "non-usermanagable was made. Extension id : "
127 *error
= kCannotModifyPolicyExtensionError
;
134 // Runs the install verifier for all extensions that are enabled, disabled, or
136 void PerformVerificationCheck(content::BrowserContext
* context
) {
137 scoped_ptr
<ExtensionSet
> extensions
=
138 ExtensionRegistry::Get(context
)->GenerateInstalledExtensionsSet(
139 ExtensionRegistry::ENABLED
|
140 ExtensionRegistry::DISABLED
|
141 ExtensionRegistry::TERMINATED
);
142 ExtensionPrefs
* prefs
= ExtensionPrefs::Get(context
);
143 bool should_do_verification_check
= false;
144 for (const scoped_refptr
<const Extension
>& extension
: *extensions
) {
145 if (ui_util::ShouldDisplayInExtensionSettings(extension
.get(), context
) &&
146 ((prefs
->GetDisableReasons(extension
->id()) &
147 Extension::DISABLE_NOT_VERIFIED
) != 0)) {
148 should_do_verification_check
= true;
153 UMA_HISTOGRAM_BOOLEAN("ExtensionSettings.ShouldDoVerificationCheck",
154 should_do_verification_check
);
155 if (should_do_verification_check
)
156 InstallVerifier::Get(context
)->VerifyAllExtensions();
159 scoped_ptr
<developer::ProfileInfo
> CreateProfileInfo(Profile
* profile
) {
160 scoped_ptr
<developer::ProfileInfo
> info(new developer::ProfileInfo());
161 info
->is_supervised
= profile
->IsSupervised();
162 PrefService
* prefs
= profile
->GetPrefs();
163 info
->is_incognito_available
=
164 IncognitoModePrefs::GetAvailability(prefs
) !=
165 IncognitoModePrefs::DISABLED
;
166 info
->in_developer_mode
=
167 !info
->is_supervised
&&
168 prefs
->GetBoolean(prefs::kExtensionsUIDeveloperMode
);
169 info
->app_info_dialog_enabled
= CanShowAppInfoDialog();
170 info
->can_load_unpacked
=
171 !ExtensionManagementFactory::GetForBrowserContext(profile
)
172 ->BlacklistedByDefault();
178 namespace ChoosePath
= api::developer_private::ChoosePath
;
179 namespace GetItemsInfo
= api::developer_private::GetItemsInfo
;
180 namespace PackDirectory
= api::developer_private::PackDirectory
;
181 namespace Reload
= api::developer_private::Reload
;
183 static base::LazyInstance
<BrowserContextKeyedAPIFactory
<DeveloperPrivateAPI
> >
184 g_factory
= LAZY_INSTANCE_INITIALIZER
;
187 BrowserContextKeyedAPIFactory
<DeveloperPrivateAPI
>*
188 DeveloperPrivateAPI::GetFactoryInstance() {
189 return g_factory
.Pointer();
193 DeveloperPrivateAPI
* DeveloperPrivateAPI::Get(
194 content::BrowserContext
* context
) {
195 return GetFactoryInstance()->Get(context
);
198 DeveloperPrivateAPI::DeveloperPrivateAPI(content::BrowserContext
* context
)
199 : profile_(Profile::FromBrowserContext(context
)) {
200 RegisterNotifications();
203 DeveloperPrivateEventRouter::DeveloperPrivateEventRouter(Profile
* profile
)
204 : extension_registry_observer_(this),
205 error_console_observer_(this),
206 process_manager_observer_(this),
207 app_window_registry_observer_(this),
208 extension_action_api_observer_(this),
209 warning_service_observer_(this),
210 extension_prefs_observer_(this),
211 extension_management_observer_(this),
212 command_service_observer_(this),
214 event_router_(EventRouter::Get(profile_
)),
215 weak_factory_(this) {
216 extension_registry_observer_
.Add(ExtensionRegistry::Get(profile_
));
217 error_console_observer_
.Add(ErrorConsole::Get(profile
));
218 process_manager_observer_
.Add(ProcessManager::Get(profile
));
219 app_window_registry_observer_
.Add(AppWindowRegistry::Get(profile
));
220 extension_action_api_observer_
.Add(ExtensionActionAPI::Get(profile
));
221 warning_service_observer_
.Add(WarningService::Get(profile
));
222 extension_prefs_observer_
.Add(ExtensionPrefs::Get(profile
));
223 extension_management_observer_
.Add(
224 ExtensionManagementFactory::GetForBrowserContext(profile
));
225 command_service_observer_
.Add(CommandService::Get(profile
));
226 pref_change_registrar_
.Init(profile
->GetPrefs());
227 // The unretained is safe, since the PrefChangeRegistrar unregisters the
228 // callback on destruction.
229 pref_change_registrar_
.Add(
230 prefs::kExtensionsUIDeveloperMode
,
231 base::Bind(&DeveloperPrivateEventRouter::OnProfilePrefChanged
,
232 base::Unretained(this)));
235 DeveloperPrivateEventRouter::~DeveloperPrivateEventRouter() {
238 void DeveloperPrivateEventRouter::AddExtensionId(
239 const std::string
& extension_id
) {
240 extension_ids_
.insert(extension_id
);
243 void DeveloperPrivateEventRouter::RemoveExtensionId(
244 const std::string
& extension_id
) {
245 extension_ids_
.erase(extension_id
);
248 void DeveloperPrivateEventRouter::OnExtensionLoaded(
249 content::BrowserContext
* browser_context
,
250 const Extension
* extension
) {
251 DCHECK(profile_
->IsSameProfile(Profile::FromBrowserContext(browser_context
)));
252 BroadcastItemStateChanged(developer::EVENT_TYPE_LOADED
, extension
->id());
255 void DeveloperPrivateEventRouter::OnExtensionUnloaded(
256 content::BrowserContext
* browser_context
,
257 const Extension
* extension
,
258 UnloadedExtensionInfo::Reason reason
) {
259 DCHECK(profile_
->IsSameProfile(Profile::FromBrowserContext(browser_context
)));
260 BroadcastItemStateChanged(developer::EVENT_TYPE_UNLOADED
, extension
->id());
263 void DeveloperPrivateEventRouter::OnExtensionInstalled(
264 content::BrowserContext
* browser_context
,
265 const Extension
* extension
,
267 DCHECK(profile_
->IsSameProfile(Profile::FromBrowserContext(browser_context
)));
268 BroadcastItemStateChanged(developer::EVENT_TYPE_INSTALLED
, extension
->id());
271 void DeveloperPrivateEventRouter::OnExtensionUninstalled(
272 content::BrowserContext
* browser_context
,
273 const Extension
* extension
,
274 extensions::UninstallReason reason
) {
275 DCHECK(profile_
->IsSameProfile(Profile::FromBrowserContext(browser_context
)));
276 BroadcastItemStateChanged(developer::EVENT_TYPE_UNINSTALLED
, extension
->id());
279 void DeveloperPrivateEventRouter::OnErrorAdded(const ExtensionError
* error
) {
280 // We don't want to handle errors thrown by extensions subscribed to these
281 // events (currently only the Apps Developer Tool), because doing so risks
283 if (extension_ids_
.count(error
->extension_id()))
286 BroadcastItemStateChanged(developer::EVENT_TYPE_ERROR_ADDED
,
287 error
->extension_id());
290 void DeveloperPrivateEventRouter::OnErrorsRemoved(
291 const std::set
<std::string
>& removed_ids
) {
292 for (const std::string
& id
: removed_ids
) {
293 if (!extension_ids_
.count(id
))
294 BroadcastItemStateChanged(developer::EVENT_TYPE_ERRORS_REMOVED
, id
);
298 void DeveloperPrivateEventRouter::OnExtensionFrameRegistered(
299 const std::string
& extension_id
,
300 content::RenderFrameHost
* render_frame_host
) {
301 BroadcastItemStateChanged(developer::EVENT_TYPE_VIEW_REGISTERED
,
305 void DeveloperPrivateEventRouter::OnExtensionFrameUnregistered(
306 const std::string
& extension_id
,
307 content::RenderFrameHost
* render_frame_host
) {
308 BroadcastItemStateChanged(developer::EVENT_TYPE_VIEW_UNREGISTERED
,
312 void DeveloperPrivateEventRouter::OnAppWindowAdded(AppWindow
* window
) {
313 BroadcastItemStateChanged(developer::EVENT_TYPE_VIEW_REGISTERED
,
314 window
->extension_id());
317 void DeveloperPrivateEventRouter::OnAppWindowRemoved(AppWindow
* window
) {
318 BroadcastItemStateChanged(developer::EVENT_TYPE_VIEW_UNREGISTERED
,
319 window
->extension_id());
322 void DeveloperPrivateEventRouter::OnExtensionCommandAdded(
323 const std::string
& extension_id
,
324 const Command
& added_command
) {
325 BroadcastItemStateChanged(developer::EVENT_TYPE_PREFS_CHANGED
,
329 void DeveloperPrivateEventRouter::OnExtensionCommandRemoved(
330 const std::string
& extension_id
,
331 const Command
& removed_command
) {
332 BroadcastItemStateChanged(developer::EVENT_TYPE_PREFS_CHANGED
,
336 void DeveloperPrivateEventRouter::OnExtensionActionVisibilityChanged(
337 const std::string
& extension_id
,
338 bool is_now_visible
) {
339 BroadcastItemStateChanged(developer::EVENT_TYPE_PREFS_CHANGED
, extension_id
);
342 void DeveloperPrivateEventRouter::OnExtensionDisableReasonsChanged(
343 const std::string
& extension_id
, int disable_reasons
) {
344 BroadcastItemStateChanged(developer::EVENT_TYPE_PREFS_CHANGED
, extension_id
);
347 void DeveloperPrivateEventRouter::OnExtensionManagementSettingsChanged() {
348 scoped_ptr
<base::ListValue
> args(new base::ListValue());
349 args
->Append(CreateProfileInfo(profile_
)->ToValue());
350 scoped_ptr
<Event
> event(
351 new Event(events::DEVELOPER_PRIVATE_ON_PROFILE_STATE_CHANGED
,
352 developer::OnProfileStateChanged::kEventName
, args
.Pass()));
353 event_router_
->BroadcastEvent(event
.Pass());
356 void DeveloperPrivateEventRouter::ExtensionWarningsChanged(
357 const ExtensionIdSet
& affected_extensions
) {
358 for (const ExtensionId
& id
: affected_extensions
)
359 BroadcastItemStateChanged(developer::EVENT_TYPE_WARNINGS_CHANGED
, id
);
362 void DeveloperPrivateEventRouter::OnProfilePrefChanged() {
363 scoped_ptr
<base::ListValue
> args(new base::ListValue());
364 args
->Append(CreateProfileInfo(profile_
)->ToValue());
365 scoped_ptr
<Event
> event(
366 new Event(events::DEVELOPER_PRIVATE_ON_PROFILE_STATE_CHANGED
,
367 developer::OnProfileStateChanged::kEventName
, args
.Pass()));
368 event_router_
->BroadcastEvent(event
.Pass());
371 void DeveloperPrivateEventRouter::BroadcastItemStateChanged(
372 developer::EventType event_type
,
373 const std::string
& extension_id
) {
374 scoped_ptr
<ExtensionInfoGenerator
> info_generator(
375 new ExtensionInfoGenerator(profile_
));
376 ExtensionInfoGenerator
* info_generator_weak
= info_generator
.get();
377 info_generator_weak
->CreateExtensionInfo(
379 base::Bind(&DeveloperPrivateEventRouter::BroadcastItemStateChangedHelper
,
380 weak_factory_
.GetWeakPtr(),
383 base::Passed(info_generator
.Pass())));
386 void DeveloperPrivateEventRouter::BroadcastItemStateChangedHelper(
387 developer::EventType event_type
,
388 const std::string
& extension_id
,
389 scoped_ptr
<ExtensionInfoGenerator
> info_generator
,
390 const ExtensionInfoGenerator::ExtensionInfoList
& infos
) {
391 DCHECK_LE(infos
.size(), 1u);
393 developer::EventData event_data
;
394 event_data
.event_type
= event_type
;
395 event_data
.item_id
= extension_id
;
396 scoped_ptr
<base::DictionaryValue
> dict
= event_data
.ToValue();
398 if (!infos
.empty()) {
399 // Hack: Ideally, we would use event_data.extension_info to set the
400 // extension info, but since it's an optional field, it's implemented as a
401 // scoped ptr, and so ownership between that and the vector of linked ptrs
402 // here is, well, messy. Easier to just set it like this.
403 dict
->SetWithoutPathExpansion("extensionInfo",
404 infos
[0]->ToValue().release());
407 scoped_ptr
<base::ListValue
> args(new base::ListValue());
408 args
->Append(dict
.release());
409 scoped_ptr
<Event
> event(
410 new Event(events::DEVELOPER_PRIVATE_ON_ITEM_STATE_CHANGED
,
411 developer::OnItemStateChanged::kEventName
, args
.Pass()));
412 event_router_
->BroadcastEvent(event
.Pass());
415 void DeveloperPrivateAPI::SetLastUnpackedDirectory(const base::FilePath
& path
) {
416 last_unpacked_directory_
= path
;
419 void DeveloperPrivateAPI::RegisterNotifications() {
420 EventRouter::Get(profile_
)->RegisterObserver(
421 this, developer::OnItemStateChanged::kEventName
);
424 DeveloperPrivateAPI::~DeveloperPrivateAPI() {}
426 void DeveloperPrivateAPI::Shutdown() {}
428 void DeveloperPrivateAPI::OnListenerAdded(
429 const EventListenerInfo
& details
) {
430 if (!developer_private_event_router_
) {
431 developer_private_event_router_
.reset(
432 new DeveloperPrivateEventRouter(profile_
));
435 developer_private_event_router_
->AddExtensionId(details
.extension_id
);
438 void DeveloperPrivateAPI::OnListenerRemoved(
439 const EventListenerInfo
& details
) {
440 if (!EventRouter::Get(profile_
)->HasEventListener(
441 developer::OnItemStateChanged::kEventName
)) {
442 developer_private_event_router_
.reset(NULL
);
444 developer_private_event_router_
->RemoveExtensionId(details
.extension_id
);
450 DeveloperPrivateAPIFunction::~DeveloperPrivateAPIFunction() {
453 const Extension
* DeveloperPrivateAPIFunction::GetExtensionById(
454 const std::string
& id
) {
455 return ExtensionRegistry::Get(browser_context())->GetExtensionById(
456 id
, ExtensionRegistry::EVERYTHING
);
459 const Extension
* DeveloperPrivateAPIFunction::GetEnabledExtensionById(
460 const std::string
& id
) {
461 return ExtensionRegistry::Get(browser_context())->enabled_extensions().
465 DeveloperPrivateAutoUpdateFunction::~DeveloperPrivateAutoUpdateFunction() {}
467 ExtensionFunction::ResponseAction
DeveloperPrivateAutoUpdateFunction::Run() {
468 ExtensionUpdater
* updater
=
469 ExtensionSystem::Get(browser_context())->extension_service()->updater();
471 ExtensionUpdater::CheckParams params
;
472 params
.install_immediately
= true;
473 updater
->CheckNow(params
);
475 return RespondNow(NoArguments());
478 DeveloperPrivateGetExtensionsInfoFunction::
479 DeveloperPrivateGetExtensionsInfoFunction() {
482 DeveloperPrivateGetExtensionsInfoFunction::
483 ~DeveloperPrivateGetExtensionsInfoFunction() {
486 ExtensionFunction::ResponseAction
487 DeveloperPrivateGetExtensionsInfoFunction::Run() {
488 scoped_ptr
<developer::GetExtensionsInfo::Params
> params(
489 developer::GetExtensionsInfo::Params::Create(*args_
));
490 EXTENSION_FUNCTION_VALIDATE(params
);
492 bool include_disabled
= true;
493 bool include_terminated
= true;
494 if (params
->options
) {
495 if (params
->options
->include_disabled
)
496 include_disabled
= *params
->options
->include_disabled
;
497 if (params
->options
->include_terminated
)
498 include_terminated
= *params
->options
->include_terminated
;
501 info_generator_
.reset(new ExtensionInfoGenerator(browser_context()));
502 info_generator_
->CreateExtensionsInfo(
505 base::Bind(&DeveloperPrivateGetExtensionsInfoFunction::OnInfosGenerated
,
506 this /* refcounted */));
508 return RespondLater();
511 void DeveloperPrivateGetExtensionsInfoFunction::OnInfosGenerated(
512 const ExtensionInfoGenerator::ExtensionInfoList
& list
) {
513 Respond(ArgumentList(developer::GetExtensionsInfo::Results::Create(list
)));
516 DeveloperPrivateGetExtensionInfoFunction::
517 DeveloperPrivateGetExtensionInfoFunction() {
520 DeveloperPrivateGetExtensionInfoFunction::
521 ~DeveloperPrivateGetExtensionInfoFunction() {
524 ExtensionFunction::ResponseAction
525 DeveloperPrivateGetExtensionInfoFunction::Run() {
526 scoped_ptr
<developer::GetExtensionInfo::Params
> params(
527 developer::GetExtensionInfo::Params::Create(*args_
));
528 EXTENSION_FUNCTION_VALIDATE(params
);
530 info_generator_
.reset(new ExtensionInfoGenerator(browser_context()));
531 info_generator_
->CreateExtensionInfo(
533 base::Bind(&DeveloperPrivateGetExtensionInfoFunction::OnInfosGenerated
,
534 this /* refcounted */));
536 return RespondLater();
539 void DeveloperPrivateGetExtensionInfoFunction::OnInfosGenerated(
540 const ExtensionInfoGenerator::ExtensionInfoList
& list
) {
541 DCHECK_EQ(1u, list
.size());
542 const linked_ptr
<developer::ExtensionInfo
>& info
= list
[0];
543 Respond(info
.get() ? OneArgument(info
->ToValue()) :
544 Error(kNoSuchExtensionError
));
547 DeveloperPrivateGetItemsInfoFunction::DeveloperPrivateGetItemsInfoFunction() {}
548 DeveloperPrivateGetItemsInfoFunction::~DeveloperPrivateGetItemsInfoFunction() {}
550 ExtensionFunction::ResponseAction
DeveloperPrivateGetItemsInfoFunction::Run() {
551 scoped_ptr
<developer::GetItemsInfo::Params
> params(
552 developer::GetItemsInfo::Params::Create(*args_
));
553 EXTENSION_FUNCTION_VALIDATE(params
);
555 info_generator_
.reset(new ExtensionInfoGenerator(browser_context()));
556 info_generator_
->CreateExtensionsInfo(
557 params
->include_disabled
,
558 params
->include_terminated
,
559 base::Bind(&DeveloperPrivateGetItemsInfoFunction::OnInfosGenerated
,
560 this /* refcounted */));
562 return RespondLater();
565 void DeveloperPrivateGetItemsInfoFunction::OnInfosGenerated(
566 const ExtensionInfoGenerator::ExtensionInfoList
& list
) {
567 std::vector
<linked_ptr
<developer::ItemInfo
>> item_list
;
568 for (const linked_ptr
<developer::ExtensionInfo
>& info
: list
)
569 item_list
.push_back(developer_private_mangle::MangleExtensionInfo(*info
));
571 Respond(ArgumentList(developer::GetItemsInfo::Results::Create(item_list
)));
574 DeveloperPrivateGetProfileConfigurationFunction::
575 ~DeveloperPrivateGetProfileConfigurationFunction() {
578 ExtensionFunction::ResponseAction
579 DeveloperPrivateGetProfileConfigurationFunction::Run() {
580 scoped_ptr
<developer::ProfileInfo
> info
= CreateProfileInfo(GetProfile());
582 // If this is called from the chrome://extensions page, we use this as a
583 // heuristic that it's a good time to verify installs. We do this on startup,
584 // but there's a chance that it failed erroneously, so it's good to double-
586 if (source_context_type() == Feature::WEBUI_CONTEXT
)
587 PerformVerificationCheck(browser_context());
589 return RespondNow(OneArgument(info
->ToValue()));
592 DeveloperPrivateUpdateProfileConfigurationFunction::
593 ~DeveloperPrivateUpdateProfileConfigurationFunction() {
596 ExtensionFunction::ResponseAction
597 DeveloperPrivateUpdateProfileConfigurationFunction::Run() {
598 scoped_ptr
<developer::UpdateProfileConfiguration::Params
> params(
599 developer::UpdateProfileConfiguration::Params::Create(*args_
));
600 EXTENSION_FUNCTION_VALIDATE(params
);
602 const developer::ProfileConfigurationUpdate
& update
= params
->update
;
603 PrefService
* prefs
= GetProfile()->GetPrefs();
604 if (update
.in_developer_mode
) {
605 if (GetProfile()->IsSupervised())
606 return RespondNow(Error(kCannotUpdateSupervisedProfileSettingsError
));
607 prefs
->SetBoolean(prefs::kExtensionsUIDeveloperMode
,
608 *update
.in_developer_mode
);
611 return RespondNow(NoArguments());
614 DeveloperPrivateUpdateExtensionConfigurationFunction::
615 ~DeveloperPrivateUpdateExtensionConfigurationFunction() {}
617 ExtensionFunction::ResponseAction
618 DeveloperPrivateUpdateExtensionConfigurationFunction::Run() {
619 scoped_ptr
<developer::UpdateExtensionConfiguration::Params
> params(
620 developer::UpdateExtensionConfiguration::Params::Create(*args_
));
621 EXTENSION_FUNCTION_VALIDATE(params
);
623 const developer::ExtensionConfigurationUpdate
& update
= params
->update
;
625 const Extension
* extension
= GetExtensionById(update
.extension_id
);
627 return RespondNow(Error(kNoSuchExtensionError
));
629 return RespondNow(Error(kRequiresUserGestureError
));
631 if (update
.file_access
) {
633 if (!UserCanModifyExtensionConfiguration(extension
,
636 return RespondNow(Error(error
));
638 util::SetAllowFileAccess(
639 extension
->id(), browser_context(), *update
.file_access
);
641 if (update
.incognito_access
) {
642 util::SetIsIncognitoEnabled(
643 extension
->id(), browser_context(), *update
.incognito_access
);
645 if (update
.error_collection
) {
646 ErrorConsole::Get(browser_context())->SetReportingAllForExtension(
647 extension
->id(), *update
.error_collection
);
649 if (update
.run_on_all_urls
) {
650 util::SetAllowedScriptingOnAllUrls(
651 extension
->id(), browser_context(), *update
.run_on_all_urls
);
653 if (update
.show_action_button
) {
654 ExtensionActionAPI::Get(browser_context())->SetBrowserActionVisibility(
656 *update
.show_action_button
);
659 return RespondNow(NoArguments());
662 DeveloperPrivateReloadFunction::~DeveloperPrivateReloadFunction() {}
664 ExtensionFunction::ResponseAction
DeveloperPrivateReloadFunction::Run() {
665 scoped_ptr
<Reload::Params
> params(Reload::Params::Create(*args_
));
666 EXTENSION_FUNCTION_VALIDATE(params
.get());
668 const Extension
* extension
= GetExtensionById(params
->extension_id
);
670 return RespondNow(Error(kNoSuchExtensionError
));
672 bool fail_quietly
= params
->options
&&
673 params
->options
->fail_quietly
&&
674 *params
->options
->fail_quietly
;
676 ExtensionService
* service
= GetExtensionService(browser_context());
678 service
->ReloadExtensionWithQuietFailure(params
->extension_id
);
680 service
->ReloadExtension(params
->extension_id
);
682 // TODO(devlin): We shouldn't return until the extension has finished trying
683 // to reload (and then we could also return the error).
684 return RespondNow(NoArguments());
687 DeveloperPrivateShowPermissionsDialogFunction::
688 DeveloperPrivateShowPermissionsDialogFunction() {}
690 DeveloperPrivateShowPermissionsDialogFunction::
691 ~DeveloperPrivateShowPermissionsDialogFunction() {}
693 ExtensionFunction::ResponseAction
694 DeveloperPrivateShowPermissionsDialogFunction::Run() {
695 scoped_ptr
<developer::ShowPermissionsDialog::Params
> params(
696 developer::ShowPermissionsDialog::Params::Create(*args_
));
697 EXTENSION_FUNCTION_VALIDATE(params
);
699 const Extension
* target_extension
= GetExtensionById(params
->extension_id
);
700 if (!target_extension
)
701 return RespondNow(Error(kNoSuchExtensionError
));
703 content::WebContents
* web_contents
= GetSenderWebContents();
705 return RespondNow(Error(kCouldNotFindWebContentsError
));
707 ShowPermissionsDialogHelper::Show(
711 source_context_type() == Feature::WEBUI_CONTEXT
,
712 base::Bind(&DeveloperPrivateShowPermissionsDialogFunction::Finish
, this));
713 return RespondLater();
716 void DeveloperPrivateShowPermissionsDialogFunction::Finish() {
717 Respond(NoArguments());
720 DeveloperPrivateLoadUnpackedFunction::DeveloperPrivateLoadUnpackedFunction()
721 : fail_quietly_(false) {
724 ExtensionFunction::ResponseAction
DeveloperPrivateLoadUnpackedFunction::Run() {
725 scoped_ptr
<developer::LoadUnpacked::Params
> params(
726 developer::LoadUnpacked::Params::Create(*args_
));
727 EXTENSION_FUNCTION_VALIDATE(params
);
730 ui::SelectFileDialog::SELECT_FOLDER
,
731 l10n_util::GetStringUTF16(IDS_EXTENSION_LOAD_FROM_DIRECTORY
),
732 ui::SelectFileDialog::FileTypeInfo(),
733 0 /* file_type_index */)) {
734 return RespondNow(Error(kCouldNotShowSelectFileDialogError
));
737 fail_quietly_
= params
->options
&&
738 params
->options
->fail_quietly
&&
739 *params
->options
->fail_quietly
;
741 AddRef(); // Balanced in FileSelected / FileSelectionCanceled.
742 return RespondLater();
745 void DeveloperPrivateLoadUnpackedFunction::FileSelected(
746 const base::FilePath
& path
) {
747 scoped_refptr
<UnpackedInstaller
> installer(
748 UnpackedInstaller::Create(GetExtensionService(browser_context())));
749 installer
->set_be_noisy_on_failure(!fail_quietly_
);
750 installer
->set_completion_callback(
751 base::Bind(&DeveloperPrivateLoadUnpackedFunction::OnLoadComplete
, this));
752 installer
->Load(path
);
754 DeveloperPrivateAPI::Get(browser_context())->SetLastUnpackedDirectory(path
);
756 Release(); // Balanced in Run().
759 void DeveloperPrivateLoadUnpackedFunction::FileSelectionCanceled() {
760 // This isn't really an error, but we should keep it like this for
761 // backward compatability.
762 Respond(Error(kFileSelectionCanceled
));
763 Release(); // Balanced in Run().
766 void DeveloperPrivateLoadUnpackedFunction::OnLoadComplete(
767 const Extension
* extension
,
768 const base::FilePath
& file_path
,
769 const std::string
& error
) {
770 Respond(extension
? NoArguments() : Error(error
));
773 bool DeveloperPrivateChooseEntryFunction::ShowPicker(
774 ui::SelectFileDialog::Type picker_type
,
775 const base::string16
& select_title
,
776 const ui::SelectFileDialog::FileTypeInfo
& info
,
777 int file_type_index
) {
778 content::WebContents
* web_contents
= GetSenderWebContents();
782 // The entry picker will hold a reference to this function instance,
783 // and subsequent sending of the function response) until the user has
784 // selected a file or cancelled the picker. At that point, the picker will
786 new EntryPicker(this,
789 DeveloperPrivateAPI::Get(browser_context())->
790 GetLastUnpackedDirectory(),
797 DeveloperPrivateChooseEntryFunction::~DeveloperPrivateChooseEntryFunction() {}
799 void DeveloperPrivatePackDirectoryFunction::OnPackSuccess(
800 const base::FilePath
& crx_file
,
801 const base::FilePath
& pem_file
) {
802 developer::PackDirectoryResponse response
;
803 response
.message
= base::UTF16ToUTF8(
804 PackExtensionJob::StandardSuccessMessage(crx_file
, pem_file
));
805 response
.status
= developer::PACK_STATUS_SUCCESS
;
806 Respond(OneArgument(response
.ToValue()));
807 Release(); // Balanced in Run().
810 void DeveloperPrivatePackDirectoryFunction::OnPackFailure(
811 const std::string
& error
,
812 ExtensionCreator::ErrorType error_type
) {
813 developer::PackDirectoryResponse response
;
814 response
.message
= error
;
815 if (error_type
== ExtensionCreator::kCRXExists
) {
816 response
.item_path
= item_path_str_
;
817 response
.pem_path
= key_path_str_
;
818 response
.override_flags
= ExtensionCreator::kOverwriteCRX
;
819 response
.status
= developer::PACK_STATUS_WARNING
;
821 response
.status
= developer::PACK_STATUS_ERROR
;
823 Respond(OneArgument(response
.ToValue()));
824 Release(); // Balanced in Run().
827 ExtensionFunction::ResponseAction
DeveloperPrivatePackDirectoryFunction::Run() {
828 scoped_ptr
<PackDirectory::Params
> params(
829 PackDirectory::Params::Create(*args_
));
830 EXTENSION_FUNCTION_VALIDATE(params
);
832 int flags
= params
->flags
? *params
->flags
: 0;
833 item_path_str_
= params
->path
;
834 if (params
->private_key_path
)
835 key_path_str_
= *params
->private_key_path
;
837 base::FilePath root_directory
=
838 base::FilePath::FromUTF8Unsafe(item_path_str_
);
839 base::FilePath key_file
= base::FilePath::FromUTF8Unsafe(key_path_str_
);
841 developer::PackDirectoryResponse response
;
842 if (root_directory
.empty()) {
843 if (item_path_str_
.empty())
844 response
.message
= l10n_util::GetStringUTF8(
845 IDS_EXTENSION_PACK_DIALOG_ERROR_ROOT_REQUIRED
);
847 response
.message
= l10n_util::GetStringUTF8(
848 IDS_EXTENSION_PACK_DIALOG_ERROR_ROOT_INVALID
);
850 response
.status
= developer::PACK_STATUS_ERROR
;
851 return RespondNow(OneArgument(response
.ToValue()));
854 if (!key_path_str_
.empty() && key_file
.empty()) {
855 response
.message
= l10n_util::GetStringUTF8(
856 IDS_EXTENSION_PACK_DIALOG_ERROR_KEY_INVALID
);
857 response
.status
= developer::PACK_STATUS_ERROR
;
858 return RespondNow(OneArgument(response
.ToValue()));
861 AddRef(); // Balanced in OnPackSuccess / OnPackFailure.
863 // TODO(devlin): Why is PackExtensionJob ref-counted?
864 pack_job_
= new PackExtensionJob(this, root_directory
, key_file
, flags
);
866 return RespondLater();
869 DeveloperPrivatePackDirectoryFunction::DeveloperPrivatePackDirectoryFunction() {
872 DeveloperPrivatePackDirectoryFunction::
873 ~DeveloperPrivatePackDirectoryFunction() {}
875 DeveloperPrivateLoadUnpackedFunction::~DeveloperPrivateLoadUnpackedFunction() {}
877 bool DeveloperPrivateLoadDirectoryFunction::RunAsync() {
878 // TODO(grv) : add unittests.
879 std::string directory_url_str
;
880 std::string filesystem_name
;
881 std::string filesystem_path
;
883 EXTENSION_FUNCTION_VALIDATE(args_
->GetString(0, &filesystem_name
));
884 EXTENSION_FUNCTION_VALIDATE(args_
->GetString(1, &filesystem_path
));
885 EXTENSION_FUNCTION_VALIDATE(args_
->GetString(2, &directory_url_str
));
887 context_
= content::BrowserContext::GetStoragePartition(
888 GetProfile(), render_frame_host()->GetSiteInstance())
889 ->GetFileSystemContext();
891 // Directory url is non empty only for syncfilesystem.
892 if (!directory_url_str
.empty()) {
893 storage::FileSystemURL directory_url
=
894 context_
->CrackURL(GURL(directory_url_str
));
895 if (!directory_url
.is_valid() ||
896 directory_url
.type() != storage::kFileSystemTypeSyncable
) {
897 SetError("DirectoryEntry of unsupported filesystem.");
900 return LoadByFileSystemAPI(directory_url
);
902 // Check if the DirecotryEntry is the instance of chrome filesystem.
903 if (!app_file_handler_util::ValidateFileEntryAndGetPath(
904 filesystem_name
, filesystem_path
,
905 render_frame_host()->GetProcess()->GetID(), &project_base_path_
,
907 SetError("DirectoryEntry of unsupported filesystem.");
911 // Try to load using the FileSystem API backend, in case the filesystem
912 // points to a non-native local directory.
913 std::string filesystem_id
;
915 storage::CrackIsolatedFileSystemName(filesystem_name
, &filesystem_id
);
917 base::FilePath virtual_path
=
918 storage::IsolatedContext::GetInstance()
919 ->CreateVirtualRootPath(filesystem_id
)
920 .Append(base::FilePath::FromUTF8Unsafe(filesystem_path
));
921 storage::FileSystemURL directory_url
= context_
->CreateCrackedFileSystemURL(
922 extensions::Extension::GetBaseURLFromExtensionId(extension_id()),
923 storage::kFileSystemTypeIsolated
,
926 if (directory_url
.is_valid() &&
927 directory_url
.type() != storage::kFileSystemTypeNativeLocal
&&
928 directory_url
.type() != storage::kFileSystemTypeRestrictedNativeLocal
&&
929 directory_url
.type() != storage::kFileSystemTypeDragged
) {
930 return LoadByFileSystemAPI(directory_url
);
939 bool DeveloperPrivateLoadDirectoryFunction::LoadByFileSystemAPI(
940 const storage::FileSystemURL
& directory_url
) {
941 std::string directory_url_str
= directory_url
.ToGURL().spec();
944 // Parse the project directory name from the project url. The project url is
945 // expected to have project name as the suffix.
946 if ((pos
= directory_url_str
.rfind("/")) == std::string::npos
) {
947 SetError("Invalid Directory entry.");
951 std::string project_name
;
952 project_name
= directory_url_str
.substr(pos
+ 1);
953 project_base_url_
= directory_url_str
.substr(0, pos
+ 1);
955 base::FilePath
project_path(GetProfile()->GetPath());
956 project_path
= project_path
.AppendASCII(kUnpackedAppsFolder
);
957 project_path
= project_path
.Append(
958 base::FilePath::FromUTF8Unsafe(project_name
));
960 project_base_path_
= project_path
;
962 content::BrowserThread::PostTask(content::BrowserThread::FILE, FROM_HERE
,
963 base::Bind(&DeveloperPrivateLoadDirectoryFunction::
964 ClearExistingDirectoryContent
,
966 project_base_path_
));
970 void DeveloperPrivateLoadDirectoryFunction::Load() {
971 ExtensionService
* service
= GetExtensionService(GetProfile());
972 UnpackedInstaller::Create(service
)->Load(project_base_path_
);
974 // TODO(grv) : The unpacked installer should fire an event when complete
975 // and return the extension_id.
976 SetResult(new base::StringValue("-1"));
980 void DeveloperPrivateLoadDirectoryFunction::ClearExistingDirectoryContent(
981 const base::FilePath
& project_path
) {
983 // Clear the project directory before copying new files.
984 base::DeleteFile(project_path
, true /*recursive*/);
986 pending_copy_operations_count_
= 1;
988 content::BrowserThread::PostTask(content::BrowserThread::IO
, FROM_HERE
,
989 base::Bind(&DeveloperPrivateLoadDirectoryFunction::
990 ReadDirectoryByFileSystemAPI
,
991 this, project_path
, project_path
.BaseName()));
994 void DeveloperPrivateLoadDirectoryFunction::ReadDirectoryByFileSystemAPI(
995 const base::FilePath
& project_path
,
996 const base::FilePath
& destination_path
) {
997 GURL project_url
= GURL(project_base_url_
+ destination_path
.AsUTF8Unsafe());
998 storage::FileSystemURL url
= context_
->CrackURL(project_url
);
1000 context_
->operation_runner()->ReadDirectory(
1001 url
, base::Bind(&DeveloperPrivateLoadDirectoryFunction::
1002 ReadDirectoryByFileSystemAPICb
,
1003 this, project_path
, destination_path
));
1006 void DeveloperPrivateLoadDirectoryFunction::ReadDirectoryByFileSystemAPICb(
1007 const base::FilePath
& project_path
,
1008 const base::FilePath
& destination_path
,
1009 base::File::Error status
,
1010 const storage::FileSystemOperation::FileEntryList
& file_list
,
1012 if (status
!= base::File::FILE_OK
) {
1013 DLOG(ERROR
) << "Error in copying files from sync filesystem.";
1017 // We add 1 to the pending copy operations for both files and directories. We
1018 // release the directory copy operation once all the files under the directory
1019 // are added for copying. We do that to ensure that pendingCopyOperationsCount
1020 // does not become zero before all copy operations are finished.
1021 // In case the directory happens to be executing the last copy operation it
1022 // will call SendResponse to send the response to the API. The pending copy
1023 // operations of files are released by the CopyFile function.
1024 pending_copy_operations_count_
+= file_list
.size();
1026 for (size_t i
= 0; i
< file_list
.size(); ++i
) {
1027 if (file_list
[i
].is_directory
) {
1028 ReadDirectoryByFileSystemAPI(project_path
.Append(file_list
[i
].name
),
1029 destination_path
.Append(file_list
[i
].name
));
1033 GURL project_url
= GURL(project_base_url_
+
1034 destination_path
.Append(file_list
[i
].name
).AsUTF8Unsafe());
1035 storage::FileSystemURL url
= context_
->CrackURL(project_url
);
1037 base::FilePath target_path
= project_path
;
1038 target_path
= target_path
.Append(file_list
[i
].name
);
1040 context_
->operation_runner()->CreateSnapshotFile(
1042 base::Bind(&DeveloperPrivateLoadDirectoryFunction::SnapshotFileCallback
,
1048 // Directory copy operation released here.
1049 pending_copy_operations_count_
--;
1051 if (!pending_copy_operations_count_
) {
1052 content::BrowserThread::PostTask(
1053 content::BrowserThread::UI
, FROM_HERE
,
1054 base::Bind(&DeveloperPrivateLoadDirectoryFunction::SendResponse
,
1061 void DeveloperPrivateLoadDirectoryFunction::SnapshotFileCallback(
1062 const base::FilePath
& target_path
,
1063 base::File::Error result
,
1064 const base::File::Info
& file_info
,
1065 const base::FilePath
& src_path
,
1066 const scoped_refptr
<storage::ShareableFileReference
>& file_ref
) {
1067 if (result
!= base::File::FILE_OK
) {
1068 SetError("Error in copying files from sync filesystem.");
1073 content::BrowserThread::PostTask(content::BrowserThread::FILE, FROM_HERE
,
1074 base::Bind(&DeveloperPrivateLoadDirectoryFunction::CopyFile
,
1080 void DeveloperPrivateLoadDirectoryFunction::CopyFile(
1081 const base::FilePath
& src_path
,
1082 const base::FilePath
& target_path
) {
1083 if (!base::CreateDirectory(target_path
.DirName())) {
1084 SetError("Error in copying files from sync filesystem.");
1089 base::CopyFile(src_path
, target_path
);
1091 CHECK(pending_copy_operations_count_
> 0);
1092 pending_copy_operations_count_
--;
1094 if (!pending_copy_operations_count_
) {
1095 content::BrowserThread::PostTask(content::BrowserThread::UI
, FROM_HERE
,
1096 base::Bind(&DeveloperPrivateLoadDirectoryFunction::Load
,
1101 DeveloperPrivateLoadDirectoryFunction::DeveloperPrivateLoadDirectoryFunction()
1102 : pending_copy_operations_count_(0), success_(true) {}
1104 DeveloperPrivateLoadDirectoryFunction::~DeveloperPrivateLoadDirectoryFunction()
1107 ExtensionFunction::ResponseAction
DeveloperPrivateChoosePathFunction::Run() {
1108 scoped_ptr
<developer::ChoosePath::Params
> params(
1109 developer::ChoosePath::Params::Create(*args_
));
1110 EXTENSION_FUNCTION_VALIDATE(params
);
1112 ui::SelectFileDialog::Type type
= ui::SelectFileDialog::SELECT_FOLDER
;
1113 ui::SelectFileDialog::FileTypeInfo info
;
1115 if (params
->select_type
== developer::SELECT_TYPE_FILE
)
1116 type
= ui::SelectFileDialog::SELECT_OPEN_FILE
;
1117 base::string16 select_title
;
1119 int file_type_index
= 0;
1120 if (params
->file_type
== developer::FILE_TYPE_LOAD
) {
1121 select_title
= l10n_util::GetStringUTF16(IDS_EXTENSION_LOAD_FROM_DIRECTORY
);
1122 } else if (params
->file_type
== developer::FILE_TYPE_PEM
) {
1123 select_title
= l10n_util::GetStringUTF16(
1124 IDS_EXTENSION_PACK_DIALOG_SELECT_KEY
);
1125 info
.extensions
.push_back(std::vector
<base::FilePath::StringType
>(
1126 1, FILE_PATH_LITERAL("pem")));
1127 info
.extension_description_overrides
.push_back(
1128 l10n_util::GetStringUTF16(
1129 IDS_EXTENSION_PACK_DIALOG_KEY_FILE_TYPE_DESCRIPTION
));
1130 info
.include_all_files
= true;
1131 file_type_index
= 1;
1141 return RespondNow(Error(kCouldNotShowSelectFileDialogError
));
1144 AddRef(); // Balanced by FileSelected / FileSelectionCanceled.
1145 return RespondLater();
1148 void DeveloperPrivateChoosePathFunction::FileSelected(
1149 const base::FilePath
& path
) {
1150 Respond(OneArgument(new base::StringValue(path
.LossyDisplayName())));
1154 void DeveloperPrivateChoosePathFunction::FileSelectionCanceled() {
1155 // This isn't really an error, but we should keep it like this for
1156 // backward compatability.
1157 Respond(Error(kFileSelectionCanceled
));
1161 DeveloperPrivateChoosePathFunction::~DeveloperPrivateChoosePathFunction() {}
1163 bool DeveloperPrivateIsProfileManagedFunction::RunSync() {
1164 SetResult(new base::FundamentalValue(GetProfile()->IsSupervised()));
1168 DeveloperPrivateIsProfileManagedFunction::
1169 ~DeveloperPrivateIsProfileManagedFunction() {
1172 DeveloperPrivateRequestFileSourceFunction::
1173 DeveloperPrivateRequestFileSourceFunction() {}
1175 DeveloperPrivateRequestFileSourceFunction::
1176 ~DeveloperPrivateRequestFileSourceFunction() {}
1178 ExtensionFunction::ResponseAction
1179 DeveloperPrivateRequestFileSourceFunction::Run() {
1180 params_
= developer::RequestFileSource::Params::Create(*args_
);
1181 EXTENSION_FUNCTION_VALIDATE(params_
);
1183 const developer::RequestFileSourceProperties
& properties
=
1184 params_
->properties
;
1185 const Extension
* extension
= GetExtensionById(properties
.extension_id
);
1187 return RespondNow(Error(kNoSuchExtensionError
));
1189 // Under no circumstances should we ever need to reference a file outside of
1190 // the extension's directory. If it tries to, abort.
1191 base::FilePath path_suffix
=
1192 base::FilePath::FromUTF8Unsafe(properties
.path_suffix
);
1193 if (path_suffix
.empty() || path_suffix
.ReferencesParent())
1194 return RespondNow(Error(kInvalidPathError
));
1196 if (properties
.path_suffix
== kManifestFile
&& !properties
.manifest_key
)
1197 return RespondNow(Error(kManifestKeyIsRequiredError
));
1199 base::PostTaskAndReplyWithResult(
1200 content::BrowserThread::GetBlockingPool(),
1202 base::Bind(&ReadFileToString
, extension
->path().Append(path_suffix
)),
1203 base::Bind(&DeveloperPrivateRequestFileSourceFunction::Finish
, this));
1205 return RespondLater();
1208 void DeveloperPrivateRequestFileSourceFunction::Finish(
1209 const std::string
& file_contents
) {
1210 const developer::RequestFileSourceProperties
& properties
=
1211 params_
->properties
;
1212 const Extension
* extension
= GetExtensionById(properties
.extension_id
);
1214 Respond(Error(kNoSuchExtensionError
));
1218 developer::RequestFileSourceResponse response
;
1219 base::FilePath path_suffix
=
1220 base::FilePath::FromUTF8Unsafe(properties
.path_suffix
);
1221 base::FilePath path
= extension
->path().Append(path_suffix
);
1222 response
.title
= base::StringPrintf("%s: %s",
1223 extension
->name().c_str(),
1224 path
.BaseName().AsUTF8Unsafe().c_str());
1225 response
.message
= properties
.message
;
1227 scoped_ptr
<FileHighlighter
> highlighter
;
1228 if (properties
.path_suffix
== kManifestFile
) {
1229 highlighter
.reset(new ManifestHighlighter(
1231 *properties
.manifest_key
,
1232 properties
.manifest_specific
?
1233 *properties
.manifest_specific
: std::string()));
1235 highlighter
.reset(new SourceHighlighter(
1237 properties
.line_number
? *properties
.line_number
: 0));
1240 response
.before_highlight
= highlighter
->GetBeforeFeature();
1241 response
.highlight
= highlighter
->GetFeature();
1242 response
.after_highlight
= highlighter
->GetAfterFeature();
1244 Respond(OneArgument(response
.ToValue()));
1247 DeveloperPrivateOpenDevToolsFunction::DeveloperPrivateOpenDevToolsFunction() {}
1248 DeveloperPrivateOpenDevToolsFunction::~DeveloperPrivateOpenDevToolsFunction() {}
1250 ExtensionFunction::ResponseAction
1251 DeveloperPrivateOpenDevToolsFunction::Run() {
1252 scoped_ptr
<developer::OpenDevTools::Params
> params(
1253 developer::OpenDevTools::Params::Create(*args_
));
1254 EXTENSION_FUNCTION_VALIDATE(params
);
1255 const developer::OpenDevToolsProperties
& properties
= params
->properties
;
1257 if (properties
.render_process_id
== -1) {
1258 // This is a lazy background page.
1259 const Extension
* extension
= properties
.extension_id
?
1260 GetEnabledExtensionById(*properties
.extension_id
) : nullptr;
1262 return RespondNow(Error(kNoSuchExtensionError
));
1264 Profile
* profile
= GetProfile();
1265 if (properties
.incognito
&& *properties
.incognito
)
1266 profile
= profile
->GetOffTheRecordProfile();
1268 // Wakes up the background page and opens the inspect window.
1269 devtools_util::InspectBackgroundPage(extension
, profile
);
1270 return RespondNow(NoArguments());
1273 // NOTE(devlin): Even though the properties use "render_view_id", this
1274 // actually refers to a render frame.
1275 content::RenderFrameHost
* rfh
= content::RenderFrameHost::FromID(
1276 properties
.render_process_id
, properties
.render_view_id
);
1278 content::WebContents
* web_contents
=
1279 rfh
? content::WebContents::FromRenderFrameHost(rfh
) : nullptr;
1280 // It's possible that the render frame was closed since we last updated the
1281 // links. Handle this gracefully.
1283 return RespondNow(Error(kNoSuchRendererError
));
1285 // If we include a url, we should inspect it specifically (and not just the
1287 if (properties
.url
) {
1288 // Line/column numbers are reported in display-friendly 1-based numbers,
1289 // but are inspected in zero-based numbers.
1290 // Default to the first line/column.
1291 DevToolsWindow::OpenDevToolsWindow(
1293 DevToolsToggleAction::Reveal(
1294 base::UTF8ToUTF16(*properties
.url
),
1295 properties
.line_number
? *properties
.line_number
- 1 : 0,
1296 properties
.column_number
? *properties
.column_number
- 1 : 0));
1298 DevToolsWindow::OpenDevToolsWindow(web_contents
);
1301 // Once we open the inspector, we focus on the appropriate tab...
1302 Browser
* browser
= chrome::FindBrowserWithWebContents(web_contents
);
1304 // ... but some pages (popups and apps) don't have tabs, and some (background
1305 // pages) don't have an associated browser. For these, the inspector opens in
1306 // a new window, and our work is done.
1307 if (!browser
|| !browser
->is_type_tabbed())
1308 return RespondNow(NoArguments());
1310 TabStripModel
* tab_strip
= browser
->tab_strip_model();
1311 tab_strip
->ActivateTabAt(tab_strip
->GetIndexOfWebContents(web_contents
),
1312 false); // Not through direct user gesture.
1313 return RespondNow(NoArguments());
1316 DeveloperPrivateDeleteExtensionErrorsFunction::
1317 ~DeveloperPrivateDeleteExtensionErrorsFunction() {}
1319 ExtensionFunction::ResponseAction
1320 DeveloperPrivateDeleteExtensionErrorsFunction::Run() {
1321 scoped_ptr
<developer::DeleteExtensionErrors::Params
> params(
1322 developer::DeleteExtensionErrors::Params::Create(*args_
));
1323 EXTENSION_FUNCTION_VALIDATE(params
);
1324 const developer::DeleteExtensionErrorsProperties
& properties
=
1327 ErrorConsole
* error_console
= ErrorConsole::Get(GetProfile());
1329 if (properties
.type
!= developer::ERROR_TYPE_NONE
) {
1330 type
= properties
.type
== developer::ERROR_TYPE_MANIFEST
?
1331 ExtensionError::MANIFEST_ERROR
: ExtensionError::RUNTIME_ERROR
;
1333 std::set
<int> error_ids
;
1334 if (properties
.error_ids
) {
1335 error_ids
.insert(properties
.error_ids
->begin(),
1336 properties
.error_ids
->end());
1338 error_console
->RemoveErrors(ErrorMap::Filter(
1339 properties
.extension_id
, type
, error_ids
, false));
1341 return RespondNow(NoArguments());
1344 DeveloperPrivateRepairExtensionFunction::
1345 ~DeveloperPrivateRepairExtensionFunction() {}
1347 ExtensionFunction::ResponseAction
1348 DeveloperPrivateRepairExtensionFunction::Run() {
1349 scoped_ptr
<developer::RepairExtension::Params
> params(
1350 developer::RepairExtension::Params::Create(*args_
));
1351 EXTENSION_FUNCTION_VALIDATE(params
);
1352 const Extension
* extension
= GetExtensionById(params
->extension_id
);
1354 return RespondNow(Error(kNoSuchExtensionError
));
1356 content::WebContents
* web_contents
= GetSenderWebContents();
1358 return RespondNow(Error(kCouldNotFindWebContentsError
));
1360 scoped_refptr
<WebstoreReinstaller
> reinstaller(new WebstoreReinstaller(
1362 params
->extension_id
,
1363 base::Bind(&DeveloperPrivateRepairExtensionFunction::OnReinstallComplete
,
1365 reinstaller
->BeginReinstall();
1367 return RespondLater();
1370 void DeveloperPrivateRepairExtensionFunction::OnReinstallComplete(
1372 const std::string
& error
,
1373 webstore_install::Result result
) {
1374 Respond(success
? NoArguments() : Error(error
));
1377 DeveloperPrivateShowOptionsFunction::~DeveloperPrivateShowOptionsFunction() {}
1379 ExtensionFunction::ResponseAction
DeveloperPrivateShowOptionsFunction::Run() {
1380 scoped_ptr
<developer::ShowOptions::Params
> params(
1381 developer::ShowOptions::Params::Create(*args_
));
1382 EXTENSION_FUNCTION_VALIDATE(params
);
1383 const Extension
* extension
= GetEnabledExtensionById(params
->extension_id
);
1385 return RespondNow(Error(kNoSuchExtensionError
));
1387 if (OptionsPageInfo::GetOptionsPage(extension
).is_empty())
1388 return RespondNow(Error(kNoOptionsPageForExtensionError
));
1390 content::WebContents
* web_contents
= GetSenderWebContents();
1392 return RespondNow(Error(kCouldNotFindWebContentsError
));
1394 ExtensionTabUtil::OpenOptionsPage(
1396 chrome::FindBrowserWithWebContents(web_contents
));
1397 return RespondNow(NoArguments());
1400 DeveloperPrivateShowPathFunction::~DeveloperPrivateShowPathFunction() {}
1402 ExtensionFunction::ResponseAction
DeveloperPrivateShowPathFunction::Run() {
1403 scoped_ptr
<developer::ShowPath::Params
> params(
1404 developer::ShowPath::Params::Create(*args_
));
1405 EXTENSION_FUNCTION_VALIDATE(params
);
1406 const Extension
* extension
= GetExtensionById(params
->extension_id
);
1408 return RespondNow(Error(kNoSuchExtensionError
));
1410 // We explicitly show manifest.json in order to work around an issue in OSX
1411 // where opening the directory doesn't focus the Finder.
1412 platform_util::ShowItemInFolder(GetProfile(),
1413 extension
->path().Append(kManifestFilename
));
1414 return RespondNow(NoArguments());
1417 DeveloperPrivateSetShortcutHandlingSuspendedFunction::
1418 ~DeveloperPrivateSetShortcutHandlingSuspendedFunction() {}
1420 ExtensionFunction::ResponseAction
1421 DeveloperPrivateSetShortcutHandlingSuspendedFunction::Run() {
1422 scoped_ptr
<developer::SetShortcutHandlingSuspended::Params
> params(
1423 developer::SetShortcutHandlingSuspended::Params::Create(*args_
));
1424 EXTENSION_FUNCTION_VALIDATE(params
);
1425 ExtensionCommandsGlobalRegistry::Get(GetProfile())->
1426 SetShortcutHandlingSuspended(params
->is_suspended
);
1427 return RespondNow(NoArguments());
1430 DeveloperPrivateUpdateExtensionCommandFunction::
1431 ~DeveloperPrivateUpdateExtensionCommandFunction() {}
1433 ExtensionFunction::ResponseAction
1434 DeveloperPrivateUpdateExtensionCommandFunction::Run() {
1435 scoped_ptr
<developer::UpdateExtensionCommand::Params
> params(
1436 developer::UpdateExtensionCommand::Params::Create(*args_
));
1437 EXTENSION_FUNCTION_VALIDATE(params
);
1438 const developer::ExtensionCommandUpdate
& update
= params
->update
;
1440 CommandService
* command_service
= CommandService::Get(GetProfile());
1442 if (update
.scope
!= developer::COMMAND_SCOPE_NONE
) {
1443 command_service
->SetScope(update
.extension_id
, update
.command_name
,
1444 update
.scope
== developer::COMMAND_SCOPE_GLOBAL
);
1447 if (update
.keybinding
) {
1448 command_service
->UpdateKeybindingPrefs(
1449 update
.extension_id
, update
.command_name
, *update
.keybinding
);
1452 return RespondNow(NoArguments());
1458 } // namespace extensions