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/app_window.h"
10 #include "apps/app_window_registry.h"
11 #include "apps/saved_files_service.h"
12 #include "base/base64.h"
13 #include "base/bind.h"
14 #include "base/command_line.h"
15 #include "base/file_util.h"
16 #include "base/files/file_enumerator.h"
17 #include "base/i18n/file_util_icu.h"
18 #include "base/lazy_instance.h"
19 #include "base/strings/string_number_conversions.h"
20 #include "base/strings/utf_string_conversions.h"
21 #include "base/values.h"
22 #include "chrome/browser/chrome_notification_types.h"
23 #include "chrome/browser/devtools/devtools_window.h"
24 #include "chrome/browser/extensions/api/developer_private/entry_picker.h"
25 #include "chrome/browser/extensions/api/extension_action/extension_action_api.h"
26 #include "chrome/browser/extensions/api/file_handlers/app_file_handler_util.h"
27 #include "chrome/browser/extensions/devtools_util.h"
28 #include "chrome/browser/extensions/extension_disabled_ui.h"
29 #include "chrome/browser/extensions/extension_error_reporter.h"
30 #include "chrome/browser/extensions/extension_service.h"
31 #include "chrome/browser/extensions/extension_ui_util.h"
32 #include "chrome/browser/extensions/extension_util.h"
33 #include "chrome/browser/extensions/unpacked_installer.h"
34 #include "chrome/browser/extensions/updater/extension_updater.h"
35 #include "chrome/browser/platform_util.h"
36 #include "chrome/browser/profiles/profile.h"
37 #include "chrome/browser/sync_file_system/drive_backend_v1/drive_file_sync_service.h"
38 #include "chrome/browser/sync_file_system/syncable_file_system_util.h"
39 #include "chrome/browser/ui/chrome_select_file_policy.h"
40 #include "chrome/browser/ui/webui/extensions/extension_error_ui_util.h"
41 #include "chrome/browser/ui/webui/extensions/extension_icon_source.h"
42 #include "chrome/common/extensions/api/developer_private.h"
43 #include "chrome/common/extensions/manifest_handlers/app_launch_info.h"
44 #include "chrome/common/extensions/manifest_url_handler.h"
45 #include "chrome/common/url_constants.h"
46 #include "content/public/browser/browser_thread.h"
47 #include "content/public/browser/notification_service.h"
48 #include "content/public/browser/render_process_host.h"
49 #include "content/public/browser/render_view_host.h"
50 #include "content/public/browser/site_instance.h"
51 #include "content/public/browser/storage_partition.h"
52 #include "content/public/browser/web_contents.h"
53 #include "extensions/browser/extension_error.h"
54 #include "extensions/browser/extension_prefs.h"
55 #include "extensions/browser/extension_registry.h"
56 #include "extensions/browser/extension_system.h"
57 #include "extensions/browser/management_policy.h"
58 #include "extensions/browser/view_type_utils.h"
59 #include "extensions/common/constants.h"
60 #include "extensions/common/extension_resource.h"
61 #include "extensions/common/extension_set.h"
62 #include "extensions/common/install_warning.h"
63 #include "extensions/common/manifest.h"
64 #include "extensions/common/manifest_handlers/background_info.h"
65 #include "extensions/common/manifest_handlers/icons_handler.h"
66 #include "extensions/common/manifest_handlers/incognito_info.h"
67 #include "extensions/common/manifest_handlers/offline_enabled_info.h"
68 #include "extensions/common/permissions/permissions_data.h"
69 #include "extensions/common/switches.h"
70 #include "grit/chromium_strings.h"
71 #include "grit/generated_resources.h"
72 #include "grit/theme_resources.h"
73 #include "net/base/net_util.h"
74 #include "ui/base/l10n/l10n_util.h"
75 #include "ui/base/resource/resource_bundle.h"
76 #include "ui/base/webui/web_ui_util.h"
77 #include "webkit/browser/fileapi/external_mount_points.h"
78 #include "webkit/browser/fileapi/file_system_context.h"
79 #include "webkit/browser/fileapi/file_system_operation.h"
80 #include "webkit/browser/fileapi/file_system_operation_runner.h"
81 #include "webkit/common/blob/shareable_file_reference.h"
82
83 using apps::AppWindow;
84 using apps::AppWindowRegistry;
85 using content::RenderViewHost;
86
87 namespace extensions {
88
89 namespace developer_private = api::developer_private;
90
91 namespace {
92
93 const base::FilePath::CharType kUnpackedAppsFolder[]
94 = FILE_PATH_LITERAL("apps_target");
95
GetExtensionUpdater(Profile * profile)96 ExtensionUpdater* GetExtensionUpdater(Profile* profile) {
97 return profile->GetExtensionService()->updater();
98 }
99
GetImageURLFromData(const std::string & contents)100 GURL GetImageURLFromData(const std::string& contents) {
101 std::string contents_base64;
102 base::Base64Encode(contents, &contents_base64);
103
104 // TODO(dvh): make use of content::kDataScheme. Filed as crbug/297301.
105 const char kDataURLPrefix[] = "data:;base64,";
106 return GURL(kDataURLPrefix + contents_base64);
107 }
108
GetDefaultImageURL(developer_private::ItemType type)109 GURL GetDefaultImageURL(developer_private::ItemType type) {
110 int icon_resource_id;
111 switch (type) {
112 case developer::ITEM_TYPE_LEGACY_PACKAGED_APP:
113 case developer::ITEM_TYPE_HOSTED_APP:
114 case developer::ITEM_TYPE_PACKAGED_APP:
115 icon_resource_id = IDR_APP_DEFAULT_ICON;
116 break;
117 default:
118 icon_resource_id = IDR_EXTENSION_DEFAULT_ICON;
119 break;
120 }
121
122 return GetImageURLFromData(
123 ResourceBundle::GetSharedInstance().GetRawDataResourceForScale(
124 icon_resource_id, ui::SCALE_FACTOR_100P).as_string());
125 }
126
127 // TODO(dvh): This code should be refactored and moved to
128 // extensions::ImageLoader. Also a resize should be performed to avoid
129 // potential huge URLs: crbug/297298.
ToDataURL(const base::FilePath & path,developer_private::ItemType type)130 GURL ToDataURL(const base::FilePath& path, developer_private::ItemType type) {
131 std::string contents;
132 if (path.empty() || !base::ReadFileToString(path, &contents))
133 return GetDefaultImageURL(type);
134
135 return GetImageURLFromData(contents);
136 }
137
GetExtensionID(const RenderViewHost * render_view_host)138 std::string GetExtensionID(const RenderViewHost* render_view_host) {
139 if (!render_view_host->GetSiteInstance())
140 return std::string();
141
142 return render_view_host->GetSiteInstance()->GetSiteURL().host();
143 }
144
BroadcastItemStateChanged(content::BrowserContext * browser_context,developer::EventType event_type,const std::string & item_id)145 void BroadcastItemStateChanged(content::BrowserContext* browser_context,
146 developer::EventType event_type,
147 const std::string& item_id) {
148 developer::EventData event_data;
149 event_data.event_type = event_type;
150 event_data.item_id = item_id;
151
152 scoped_ptr<base::ListValue> args(new base::ListValue());
153 args->Append(event_data.ToValue().release());
154 scoped_ptr<Event> event(new Event(
155 developer_private::OnItemStateChanged::kEventName, args.Pass()));
156 EventRouter::Get(browser_context)->BroadcastEvent(event.Pass());
157 }
158
159 } // namespace
160
161 namespace AllowFileAccess = api::developer_private::AllowFileAccess;
162 namespace AllowIncognito = api::developer_private::AllowIncognito;
163 namespace ChoosePath = api::developer_private::ChoosePath;
164 namespace Enable = api::developer_private::Enable;
165 namespace GetItemsInfo = api::developer_private::GetItemsInfo;
166 namespace Inspect = api::developer_private::Inspect;
167 namespace PackDirectory = api::developer_private::PackDirectory;
168 namespace Reload = api::developer_private::Reload;
169
170 static base::LazyInstance<BrowserContextKeyedAPIFactory<DeveloperPrivateAPI> >
171 g_factory = LAZY_INSTANCE_INITIALIZER;
172
173 // static
174 BrowserContextKeyedAPIFactory<DeveloperPrivateAPI>*
GetFactoryInstance()175 DeveloperPrivateAPI::GetFactoryInstance() {
176 return g_factory.Pointer();
177 }
178
179 // static
Get(content::BrowserContext * context)180 DeveloperPrivateAPI* DeveloperPrivateAPI::Get(
181 content::BrowserContext* context) {
182 return GetFactoryInstance()->Get(context);
183 }
184
DeveloperPrivateAPI(content::BrowserContext * context)185 DeveloperPrivateAPI::DeveloperPrivateAPI(content::BrowserContext* context)
186 : profile_(Profile::FromBrowserContext(context)) {
187 RegisterNotifications();
188 }
189
DeveloperPrivateEventRouter(Profile * profile)190 DeveloperPrivateEventRouter::DeveloperPrivateEventRouter(Profile* profile)
191 : extension_registry_observer_(this), profile_(profile) {
192 registrar_.Add(this,
193 chrome::NOTIFICATION_EXTENSION_VIEW_REGISTERED,
194 content::Source<Profile>(profile_));
195 registrar_.Add(this,
196 chrome::NOTIFICATION_EXTENSION_VIEW_UNREGISTERED,
197 content::Source<Profile>(profile_));
198
199 // TODO(limasdf): Use scoped_observer instead.
200 ErrorConsole::Get(profile)->AddObserver(this);
201
202 extension_registry_observer_.Add(ExtensionRegistry::Get(profile_));
203 }
204
~DeveloperPrivateEventRouter()205 DeveloperPrivateEventRouter::~DeveloperPrivateEventRouter() {
206 ErrorConsole::Get(profile_)->RemoveObserver(this);
207 }
208
AddExtensionId(const std::string & extension_id)209 void DeveloperPrivateEventRouter::AddExtensionId(
210 const std::string& extension_id) {
211 extension_ids_.insert(extension_id);
212 }
213
RemoveExtensionId(const std::string & extension_id)214 void DeveloperPrivateEventRouter::RemoveExtensionId(
215 const std::string& extension_id) {
216 extension_ids_.erase(extension_id);
217 }
218
Observe(int type,const content::NotificationSource & source,const content::NotificationDetails & details)219 void DeveloperPrivateEventRouter::Observe(
220 int type,
221 const content::NotificationSource& source,
222 const content::NotificationDetails& details) {
223 Profile* profile = content::Source<Profile>(source).ptr();
224 CHECK(profile);
225 CHECK(profile_->IsSameProfile(profile));
226 developer::EventData event_data;
227
228 switch (type) {
229 case chrome::NOTIFICATION_EXTENSION_VIEW_UNREGISTERED: {
230 event_data.event_type = developer::EVENT_TYPE_VIEW_UNREGISTERED;
231 event_data.item_id = GetExtensionID(
232 content::Details<const RenderViewHost>(details).ptr());
233 break;
234 }
235 case chrome::NOTIFICATION_EXTENSION_VIEW_REGISTERED: {
236 event_data.event_type = developer::EVENT_TYPE_VIEW_REGISTERED;
237 event_data.item_id = GetExtensionID(
238 content::Details<const RenderViewHost>(details).ptr());
239 break;
240 }
241 default:
242 NOTREACHED();
243 return;
244 }
245
246 BroadcastItemStateChanged(profile, event_data.event_type, event_data.item_id);
247 }
248
OnExtensionLoaded(content::BrowserContext * browser_context,const Extension * extension)249 void DeveloperPrivateEventRouter::OnExtensionLoaded(
250 content::BrowserContext* browser_context,
251 const Extension* extension) {
252 DCHECK(profile_->IsSameProfile(Profile::FromBrowserContext(browser_context)));
253 BroadcastItemStateChanged(
254 browser_context, developer::EVENT_TYPE_LOADED, extension->id());
255 }
256
OnExtensionUnloaded(content::BrowserContext * browser_context,const Extension * extension,UnloadedExtensionInfo::Reason reason)257 void DeveloperPrivateEventRouter::OnExtensionUnloaded(
258 content::BrowserContext* browser_context,
259 const Extension* extension,
260 UnloadedExtensionInfo::Reason reason) {
261 DCHECK(profile_->IsSameProfile(Profile::FromBrowserContext(browser_context)));
262 BroadcastItemStateChanged(
263 browser_context, developer::EVENT_TYPE_UNLOADED, extension->id());
264 }
265
OnExtensionWillBeInstalled(content::BrowserContext * browser_context,const Extension * extension,bool is_update,bool from_ephemeral,const std::string & old_name)266 void DeveloperPrivateEventRouter::OnExtensionWillBeInstalled(
267 content::BrowserContext* browser_context,
268 const Extension* extension,
269 bool is_update,
270 bool from_ephemeral,
271 const std::string& old_name) {
272 DCHECK(profile_->IsSameProfile(Profile::FromBrowserContext(browser_context)));
273 BroadcastItemStateChanged(
274 browser_context, developer::EVENT_TYPE_INSTALLED, extension->id());
275 }
276
OnExtensionUninstalled(content::BrowserContext * browser_context,const Extension * extension)277 void DeveloperPrivateEventRouter::OnExtensionUninstalled(
278 content::BrowserContext* browser_context,
279 const Extension* extension) {
280 DCHECK(profile_->IsSameProfile(Profile::FromBrowserContext(browser_context)));
281 BroadcastItemStateChanged(
282 browser_context, developer::EVENT_TYPE_UNINSTALLED, extension->id());
283 }
284
OnErrorAdded(const ExtensionError * error)285 void DeveloperPrivateEventRouter::OnErrorAdded(const ExtensionError* error) {
286 // We don't want to handle errors thrown by extensions subscribed to these
287 // events (currently only the Apps Developer Tool), because doing so risks
288 // entering a loop.
289 if (extension_ids_.find(error->extension_id()) != extension_ids_.end())
290 return;
291
292 BroadcastItemStateChanged(
293 profile_, developer::EVENT_TYPE_ERROR_ADDED, error->extension_id());
294 }
295
SetLastUnpackedDirectory(const base::FilePath & path)296 void DeveloperPrivateAPI::SetLastUnpackedDirectory(const base::FilePath& path) {
297 last_unpacked_directory_ = path;
298 }
299
RegisterNotifications()300 void DeveloperPrivateAPI::RegisterNotifications() {
301 EventRouter::Get(profile_)->RegisterObserver(
302 this, developer_private::OnItemStateChanged::kEventName);
303 }
304
~DeveloperPrivateAPI()305 DeveloperPrivateAPI::~DeveloperPrivateAPI() {}
306
Shutdown()307 void DeveloperPrivateAPI::Shutdown() {}
308
OnListenerAdded(const EventListenerInfo & details)309 void DeveloperPrivateAPI::OnListenerAdded(
310 const EventListenerInfo& details) {
311 if (!developer_private_event_router_) {
312 developer_private_event_router_.reset(
313 new DeveloperPrivateEventRouter(profile_));
314 }
315
316 developer_private_event_router_->AddExtensionId(details.extension_id);
317 }
318
OnListenerRemoved(const EventListenerInfo & details)319 void DeveloperPrivateAPI::OnListenerRemoved(
320 const EventListenerInfo& details) {
321 if (!EventRouter::Get(profile_)->HasEventListener(
322 developer_private::OnItemStateChanged::kEventName)) {
323 developer_private_event_router_.reset(NULL);
324 } else {
325 developer_private_event_router_->RemoveExtensionId(details.extension_id);
326 }
327 }
328
329 namespace api {
330
RunSync()331 bool DeveloperPrivateAutoUpdateFunction::RunSync() {
332 ExtensionUpdater* updater = GetExtensionUpdater(GetProfile());
333 if (updater)
334 updater->CheckNow(ExtensionUpdater::CheckParams());
335 SetResult(new base::FundamentalValue(true));
336 return true;
337 }
338
~DeveloperPrivateAutoUpdateFunction()339 DeveloperPrivateAutoUpdateFunction::~DeveloperPrivateAutoUpdateFunction() {}
340
341 scoped_ptr<developer::ItemInfo>
CreateItemInfo(const Extension & item,bool item_is_enabled)342 DeveloperPrivateGetItemsInfoFunction::CreateItemInfo(const Extension& item,
343 bool item_is_enabled) {
344 scoped_ptr<developer::ItemInfo> info(new developer::ItemInfo());
345
346 ExtensionSystem* system = ExtensionSystem::Get(GetProfile());
347 ExtensionService* service = system->extension_service();
348 ExtensionRegistry* registry = ExtensionRegistry::Get(GetProfile());
349
350 info->id = item.id();
351 info->name = item.name();
352 info->enabled = service->IsExtensionEnabled(info->id);
353 info->offline_enabled = OfflineEnabledInfo::IsOfflineEnabled(&item);
354 info->version = item.VersionString();
355 info->description = item.description();
356
357 if (item.is_app()) {
358 if (item.is_legacy_packaged_app())
359 info->type = developer::ITEM_TYPE_LEGACY_PACKAGED_APP;
360 else if (item.is_hosted_app())
361 info->type = developer::ITEM_TYPE_HOSTED_APP;
362 else if (item.is_platform_app())
363 info->type = developer::ITEM_TYPE_PACKAGED_APP;
364 else
365 NOTREACHED();
366 } else if (item.is_theme()) {
367 info->type = developer::ITEM_TYPE_THEME;
368 } else if (item.is_extension()) {
369 info->type = developer::ITEM_TYPE_EXTENSION;
370 } else {
371 NOTREACHED();
372 }
373
374 if (Manifest::IsUnpackedLocation(item.location())) {
375 info->path.reset(
376 new std::string(base::UTF16ToUTF8(item.path().LossyDisplayName())));
377 // If the ErrorConsole is enabled and the extension is unpacked, use the
378 // more detailed errors from the ErrorConsole. Otherwise, use the install
379 // warnings (using both is redundant).
380 ErrorConsole* error_console = ErrorConsole::Get(GetProfile());
381 if (error_console->IsEnabledForAppsDeveloperTools() &&
382 item.location() == Manifest::UNPACKED) {
383 const ErrorList& errors = error_console->GetErrorsForExtension(item.id());
384 if (!errors.empty()) {
385 for (ErrorList::const_iterator iter = errors.begin();
386 iter != errors.end();
387 ++iter) {
388 switch ((*iter)->type()) {
389 case ExtensionError::MANIFEST_ERROR:
390 info->manifest_errors.push_back(
391 make_linked_ptr((*iter)->ToValue().release()));
392 break;
393 case ExtensionError::RUNTIME_ERROR: {
394 const RuntimeError* error =
395 static_cast<const RuntimeError*>(*iter);
396 scoped_ptr<base::DictionaryValue> value = error->ToValue();
397 bool can_inspect = content::RenderViewHost::FromID(
398 error->render_process_id(),
399 error->render_view_id()) != NULL;
400 value->SetBoolean("canInspect", can_inspect);
401 info->runtime_errors.push_back(make_linked_ptr(value.release()));
402 break;
403 }
404 case ExtensionError::NUM_ERROR_TYPES:
405 NOTREACHED();
406 break;
407 }
408 }
409 }
410 } else {
411 for (std::vector<InstallWarning>::const_iterator it =
412 item.install_warnings().begin();
413 it != item.install_warnings().end();
414 ++it) {
415 scoped_ptr<developer::InstallWarning> warning(
416 new developer::InstallWarning);
417 warning->message = it->message;
418 info->install_warnings.push_back(make_linked_ptr(warning.release()));
419 }
420 }
421 }
422
423 info->incognito_enabled = util::IsIncognitoEnabled(item.id(), GetProfile());
424 info->wants_file_access = item.wants_file_access();
425 info->allow_file_access = util::AllowFileAccess(item.id(), GetProfile());
426 info->allow_reload = Manifest::IsUnpackedLocation(item.location());
427 info->is_unpacked = Manifest::IsUnpackedLocation(item.location());
428 info->terminated = registry->terminated_extensions().Contains(item.id());
429 info->allow_incognito = item.can_be_incognito_enabled();
430
431 info->homepage_url.reset(new std::string(
432 ManifestURL::GetHomepageURL(&item).spec()));
433 if (!ManifestURL::GetOptionsPage(&item).is_empty()) {
434 info->options_url.reset(
435 new std::string(ManifestURL::GetOptionsPage(&item).spec()));
436 }
437
438 if (!ManifestURL::GetUpdateURL(&item).is_empty()) {
439 info->update_url.reset(
440 new std::string(ManifestURL::GetUpdateURL(&item).spec()));
441 }
442
443 if (item.is_app()) {
444 info->app_launch_url.reset(
445 new std::string(AppLaunchInfo::GetFullLaunchURL(&item).spec()));
446 }
447
448 info->may_disable = system->management_policy()->
449 UserMayModifySettings(&item, NULL);
450 info->is_app = item.is_app();
451 info->views = GetInspectablePagesForExtension(&item, item_is_enabled);
452
453 return info.Pass();
454 }
455
GetIconsOnFileThread(ItemInfoList item_list,const std::map<std::string,ExtensionResource> idToIcon)456 void DeveloperPrivateGetItemsInfoFunction::GetIconsOnFileThread(
457 ItemInfoList item_list,
458 const std::map<std::string, ExtensionResource> idToIcon) {
459 for (ItemInfoList::iterator iter = item_list.begin();
460 iter != item_list.end(); ++iter) {
461 developer_private::ItemInfo* info = iter->get();
462 std::map<std::string, ExtensionResource>::const_iterator resource_ptr
463 = idToIcon.find(info->id);
464 if (resource_ptr != idToIcon.end()) {
465 info->icon_url =
466 ToDataURL(resource_ptr->second.GetFilePath(), info->type).spec();
467 }
468 }
469
470 results_ = developer::GetItemsInfo::Results::Create(item_list);
471 content::BrowserThread::PostTask(content::BrowserThread::UI, FROM_HERE,
472 base::Bind(&DeveloperPrivateGetItemsInfoFunction::SendResponse,
473 this,
474 true));
475 }
476
477 void DeveloperPrivateGetItemsInfoFunction::
GetInspectablePagesForExtensionProcess(const Extension * extension,const std::set<content::RenderViewHost * > & views,ItemInspectViewList * result)478 GetInspectablePagesForExtensionProcess(
479 const Extension* extension,
480 const std::set<content::RenderViewHost*>& views,
481 ItemInspectViewList* result) {
482 bool has_generated_background_page =
483 BackgroundInfo::HasGeneratedBackgroundPage(extension);
484 for (std::set<content::RenderViewHost*>::const_iterator iter = views.begin();
485 iter != views.end(); ++iter) {
486 content::RenderViewHost* host = *iter;
487 content::WebContents* web_contents =
488 content::WebContents::FromRenderViewHost(host);
489 ViewType host_type = GetViewType(web_contents);
490 if (VIEW_TYPE_EXTENSION_POPUP == host_type ||
491 VIEW_TYPE_EXTENSION_DIALOG == host_type)
492 continue;
493
494 content::RenderProcessHost* process = host->GetProcess();
495 bool is_background_page =
496 (web_contents->GetURL() == BackgroundInfo::GetBackgroundURL(extension));
497 result->push_back(constructInspectView(
498 web_contents->GetURL(),
499 process->GetID(),
500 host->GetRoutingID(),
501 process->GetBrowserContext()->IsOffTheRecord(),
502 is_background_page && has_generated_background_page));
503 }
504 }
505
GetAppWindowPagesForExtensionProfile(const Extension * extension,ItemInspectViewList * result)506 void DeveloperPrivateGetItemsInfoFunction::GetAppWindowPagesForExtensionProfile(
507 const Extension* extension,
508 ItemInspectViewList* result) {
509 AppWindowRegistry* registry = AppWindowRegistry::Get(GetProfile());
510 if (!registry) return;
511
512 const AppWindowRegistry::AppWindowList windows =
513 registry->GetAppWindowsForApp(extension->id());
514
515 bool has_generated_background_page =
516 BackgroundInfo::HasGeneratedBackgroundPage(extension);
517 for (AppWindowRegistry::const_iterator it = windows.begin();
518 it != windows.end();
519 ++it) {
520 content::WebContents* web_contents = (*it)->web_contents();
521 RenderViewHost* host = web_contents->GetRenderViewHost();
522 content::RenderProcessHost* process = host->GetProcess();
523 bool is_background_page =
524 (web_contents->GetURL() == BackgroundInfo::GetBackgroundURL(extension));
525 result->push_back(constructInspectView(
526 web_contents->GetURL(),
527 process->GetID(),
528 host->GetRoutingID(),
529 process->GetBrowserContext()->IsOffTheRecord(),
530 is_background_page && has_generated_background_page));
531 }
532 }
533
534 linked_ptr<developer::ItemInspectView> DeveloperPrivateGetItemsInfoFunction::
constructInspectView(const GURL & url,int render_process_id,int render_view_id,bool incognito,bool generated_background_page)535 constructInspectView(
536 const GURL& url,
537 int render_process_id,
538 int render_view_id,
539 bool incognito,
540 bool generated_background_page) {
541 linked_ptr<developer::ItemInspectView> view(new developer::ItemInspectView());
542
543 if (url.scheme() == kExtensionScheme) {
544 // No leading slash.
545 view->path = url.path().substr(1);
546 } else {
547 // For live pages, use the full URL.
548 view->path = url.spec();
549 }
550
551 view->render_process_id = render_process_id;
552 view->render_view_id = render_view_id;
553 view->incognito = incognito;
554 view->generated_background_page = generated_background_page;
555 return view;
556 }
557
558 ItemInspectViewList DeveloperPrivateGetItemsInfoFunction::
GetInspectablePagesForExtension(const Extension * extension,bool extension_is_enabled)559 GetInspectablePagesForExtension(
560 const Extension* extension,
561 bool extension_is_enabled) {
562 ItemInspectViewList result;
563 // Get the extension process's active views.
564 ProcessManager* process_manager =
565 ExtensionSystem::Get(GetProfile())->process_manager();
566 GetInspectablePagesForExtensionProcess(
567 extension,
568 process_manager->GetRenderViewHostsForExtension(extension->id()),
569 &result);
570
571 // Get app window views.
572 GetAppWindowPagesForExtensionProfile(extension, &result);
573
574 // Include a link to start the lazy background page, if applicable.
575 if (BackgroundInfo::HasLazyBackgroundPage(extension) &&
576 extension_is_enabled &&
577 !process_manager->GetBackgroundHostForExtension(extension->id())) {
578 result.push_back(constructInspectView(
579 BackgroundInfo::GetBackgroundURL(extension),
580 -1,
581 -1,
582 false,
583 BackgroundInfo::HasGeneratedBackgroundPage(extension)));
584 }
585
586 ExtensionService* service = GetProfile()->GetExtensionService();
587 // Repeat for the incognito process, if applicable. Don't try to get
588 // app windows for incognito process.
589 if (service->profile()->HasOffTheRecordProfile() &&
590 IncognitoInfo::IsSplitMode(extension)) {
591 process_manager = ExtensionSystem::Get(
592 service->profile()->GetOffTheRecordProfile())->process_manager();
593 GetInspectablePagesForExtensionProcess(
594 extension,
595 process_manager->GetRenderViewHostsForExtension(extension->id()),
596 &result);
597
598 if (BackgroundInfo::HasLazyBackgroundPage(extension) &&
599 extension_is_enabled &&
600 !process_manager->GetBackgroundHostForExtension(extension->id())) {
601 result.push_back(constructInspectView(
602 BackgroundInfo::GetBackgroundURL(extension),
603 -1,
604 -1,
605 false,
606 BackgroundInfo::HasGeneratedBackgroundPage(extension)));
607 }
608 }
609
610 return result;
611 }
612
RunAsync()613 bool DeveloperPrivateGetItemsInfoFunction::RunAsync() {
614 scoped_ptr<developer::GetItemsInfo::Params> params(
615 developer::GetItemsInfo::Params::Create(*args_));
616 EXTENSION_FUNCTION_VALIDATE(params.get() != NULL);
617
618 bool include_disabled = params->include_disabled;
619 bool include_terminated = params->include_terminated;
620
621 ExtensionSet items;
622
623 ExtensionRegistry* registry = ExtensionRegistry::Get(GetProfile());
624
625 items.InsertAll(registry->enabled_extensions());
626
627 if (include_disabled) {
628 items.InsertAll(registry->disabled_extensions());
629 }
630
631 if (include_terminated) {
632 items.InsertAll(registry->terminated_extensions());
633 }
634
635 ExtensionService* service =
636 ExtensionSystem::Get(GetProfile())->extension_service();
637 std::map<std::string, ExtensionResource> id_to_icon;
638 ItemInfoList item_list;
639
640 for (ExtensionSet::const_iterator iter = items.begin(); iter != items.end();
641 ++iter) {
642 const Extension& item = *iter->get();
643
644 ExtensionResource item_resource =
645 IconsInfo::GetIconResource(&item,
646 extension_misc::EXTENSION_ICON_MEDIUM,
647 ExtensionIconSet::MATCH_BIGGER);
648 id_to_icon[item.id()] = item_resource;
649
650 // Don't show component extensions and invisible apps.
651 if (ui_util::ShouldNotBeVisible(&item, GetProfile()))
652 continue;
653
654 item_list.push_back(make_linked_ptr<developer::ItemInfo>(
655 CreateItemInfo(
656 item, service->IsExtensionEnabled(item.id())).release()));
657 }
658
659 content::BrowserThread::PostTask(content::BrowserThread::FILE, FROM_HERE,
660 base::Bind(&DeveloperPrivateGetItemsInfoFunction::GetIconsOnFileThread,
661 this,
662 item_list,
663 id_to_icon));
664
665 return true;
666 }
667
~DeveloperPrivateGetItemsInfoFunction()668 DeveloperPrivateGetItemsInfoFunction::~DeveloperPrivateGetItemsInfoFunction() {}
669
RunSync()670 bool DeveloperPrivateAllowFileAccessFunction::RunSync() {
671 scoped_ptr<AllowFileAccess::Params> params(
672 AllowFileAccess::Params::Create(*args_));
673 EXTENSION_FUNCTION_VALIDATE(params.get());
674
675 EXTENSION_FUNCTION_VALIDATE(user_gesture_);
676
677 ExtensionSystem* system = ExtensionSystem::Get(GetProfile());
678 ManagementPolicy* management_policy = system->management_policy();
679 const Extension* extension =
680 ExtensionRegistry::Get(GetProfile())
681 ->GetExtensionById(params->item_id, ExtensionRegistry::EVERYTHING);
682 bool result = true;
683
684 if (!extension) {
685 result = false;
686 } else if (!management_policy->UserMayModifySettings(extension, NULL)) {
687 LOG(ERROR) << "Attempt to change allow file access of an extension that "
688 << "non-usermanagable was made. Extension id : "
689 << extension->id();
690 result = false;
691 } else {
692 util::SetAllowFileAccess(extension->id(), GetProfile(), params->allow);
693 result = true;
694 }
695
696 return result;
697 }
698
699 DeveloperPrivateAllowFileAccessFunction::
~DeveloperPrivateAllowFileAccessFunction()700 ~DeveloperPrivateAllowFileAccessFunction() {}
701
RunSync()702 bool DeveloperPrivateAllowIncognitoFunction::RunSync() {
703 scoped_ptr<AllowIncognito::Params> params(
704 AllowIncognito::Params::Create(*args_));
705 EXTENSION_FUNCTION_VALIDATE(params.get());
706
707 const Extension* extension =
708 ExtensionRegistry::Get(GetProfile())
709 ->GetExtensionById(params->item_id, ExtensionRegistry::EVERYTHING);
710 bool result = true;
711
712 if (!extension)
713 result = false;
714 else
715 util::SetIsIncognitoEnabled(extension->id(), GetProfile(), params->allow);
716
717 return result;
718 }
719
720 DeveloperPrivateAllowIncognitoFunction::
~DeveloperPrivateAllowIncognitoFunction()721 ~DeveloperPrivateAllowIncognitoFunction() {}
722
RunSync()723 bool DeveloperPrivateReloadFunction::RunSync() {
724 scoped_ptr<Reload::Params> params(Reload::Params::Create(*args_));
725 EXTENSION_FUNCTION_VALIDATE(params.get());
726
727 ExtensionService* service = GetProfile()->GetExtensionService();
728 CHECK(!params->item_id.empty());
729 service->ReloadExtension(params->item_id);
730 return true;
731 }
732
RunSync()733 bool DeveloperPrivateShowPermissionsDialogFunction::RunSync() {
734 EXTENSION_FUNCTION_VALIDATE(args_->GetString(0, &extension_id_));
735 CHECK(!extension_id_.empty());
736 AppWindowRegistry* registry = AppWindowRegistry::Get(GetProfile());
737 DCHECK(registry);
738 AppWindow* app_window =
739 registry->GetAppWindowForRenderViewHost(render_view_host());
740 prompt_.reset(new ExtensionInstallPrompt(app_window->web_contents()));
741 const Extension* extension =
742 ExtensionRegistry::Get(GetProfile())
743 ->GetExtensionById(extension_id_, ExtensionRegistry::EVERYTHING);
744
745 if (!extension)
746 return false;
747
748 // Released by InstallUIAbort or InstallUIProceed.
749 AddRef();
750 std::vector<base::FilePath> retained_file_paths;
751 if (extension->permissions_data()->HasAPIPermission(
752 APIPermission::kFileSystem)) {
753 std::vector<apps::SavedFileEntry> retained_file_entries =
754 apps::SavedFilesService::Get(GetProfile())
755 ->GetAllFileEntries(extension_id_);
756 for (size_t i = 0; i < retained_file_entries.size(); i++) {
757 retained_file_paths.push_back(retained_file_entries[i].path);
758 }
759 }
760 prompt_->ReviewPermissions(this, extension, retained_file_paths);
761 return true;
762 }
763
~DeveloperPrivateReloadFunction()764 DeveloperPrivateReloadFunction::~DeveloperPrivateReloadFunction() {}
765
766 // This is called when the user clicks "Revoke File Access."
InstallUIProceed()767 void DeveloperPrivateShowPermissionsDialogFunction::InstallUIProceed() {
768 apps::SavedFilesService::Get(GetProfile())
769 ->ClearQueue(GetProfile()->GetExtensionService()->GetExtensionById(
770 extension_id_, true));
771 if (apps::AppRestoreService::Get(GetProfile())
772 ->IsAppRestorable(extension_id_))
773 apps::AppLoadService::Get(GetProfile())->RestartApplication(extension_id_);
774 SendResponse(true);
775 Release();
776 }
777
InstallUIAbort(bool user_initiated)778 void DeveloperPrivateShowPermissionsDialogFunction::InstallUIAbort(
779 bool user_initiated) {
780 SendResponse(true);
781 Release();
782 }
783
784 DeveloperPrivateShowPermissionsDialogFunction::
DeveloperPrivateShowPermissionsDialogFunction()785 DeveloperPrivateShowPermissionsDialogFunction() {}
786
787 DeveloperPrivateShowPermissionsDialogFunction::
~DeveloperPrivateShowPermissionsDialogFunction()788 ~DeveloperPrivateShowPermissionsDialogFunction() {}
789
DeveloperPrivateEnableFunction()790 DeveloperPrivateEnableFunction::DeveloperPrivateEnableFunction() {}
791
RunSync()792 bool DeveloperPrivateEnableFunction::RunSync() {
793 scoped_ptr<Enable::Params> params(Enable::Params::Create(*args_));
794 EXTENSION_FUNCTION_VALIDATE(params.get());
795
796 std::string extension_id = params->item_id;
797
798 const Extension* extension =
799 ExtensionRegistry::Get(GetProfile())
800 ->GetExtensionById(extension_id, ExtensionRegistry::EVERYTHING);
801 if (!extension) {
802 LOG(ERROR) << "Did not find extension with id " << extension_id;
803 return false;
804 }
805 ExtensionSystem* system = ExtensionSystem::Get(GetProfile());
806 ManagementPolicy* policy = system->management_policy();
807 bool enable = params->enable;
808 if (!policy->UserMayModifySettings(extension, NULL) ||
809 (!enable && policy->MustRemainEnabled(extension, NULL)) ||
810 (enable && policy->MustRemainDisabled(extension, NULL, NULL))) {
811 LOG(ERROR) << "Attempt to change enable state denied by management policy. "
812 << "Extension id: " << extension_id.c_str();
813 return false;
814 }
815
816 ExtensionService* service = system->extension_service();
817 if (enable) {
818 ExtensionPrefs* prefs = ExtensionPrefs::Get(GetProfile());
819 if (prefs->DidExtensionEscalatePermissions(extension_id)) {
820 AppWindowRegistry* registry = AppWindowRegistry::Get(GetProfile());
821 CHECK(registry);
822 AppWindow* app_window =
823 registry->GetAppWindowForRenderViewHost(render_view_host());
824 if (!app_window) {
825 return false;
826 }
827
828 ShowExtensionDisabledDialog(
829 service, app_window->web_contents(), extension);
830 } else if ((prefs->GetDisableReasons(extension_id) &
831 Extension::DISABLE_UNSUPPORTED_REQUIREMENT) &&
832 !requirements_checker_.get()) {
833 // Recheck the requirements.
834 scoped_refptr<const Extension> extension =
835 service->GetExtensionById(extension_id, true);
836 requirements_checker_.reset(new RequirementsChecker);
837 // Released by OnRequirementsChecked.
838 AddRef();
839 requirements_checker_->Check(
840 extension,
841 base::Bind(&DeveloperPrivateEnableFunction::OnRequirementsChecked,
842 this, extension_id));
843 } else {
844 service->EnableExtension(extension_id);
845
846 // Make sure any browser action contained within it is not hidden.
847 ExtensionActionAPI::SetBrowserActionVisibility(
848 prefs, extension->id(), true);
849 }
850 } else {
851 service->DisableExtension(extension_id, Extension::DISABLE_USER_ACTION);
852 }
853 return true;
854 }
855
OnRequirementsChecked(const std::string & extension_id,std::vector<std::string> requirements_errors)856 void DeveloperPrivateEnableFunction::OnRequirementsChecked(
857 const std::string& extension_id,
858 std::vector<std::string> requirements_errors) {
859 if (requirements_errors.empty()) {
860 ExtensionService* service = GetProfile()->GetExtensionService();
861 service->EnableExtension(extension_id);
862 } else {
863 ExtensionErrorReporter::GetInstance()->ReportError(
864 base::UTF8ToUTF16(JoinString(requirements_errors, ' ')),
865 true); // Be noisy.
866 }
867 Release();
868 }
869
~DeveloperPrivateEnableFunction()870 DeveloperPrivateEnableFunction::~DeveloperPrivateEnableFunction() {}
871
RunSync()872 bool DeveloperPrivateInspectFunction::RunSync() {
873 scoped_ptr<developer::Inspect::Params> params(
874 developer::Inspect::Params::Create(*args_));
875 EXTENSION_FUNCTION_VALIDATE(params.get() != NULL);
876 const developer::InspectOptions& options = params->options;
877
878 int render_process_id;
879 base::StringToInt(options.render_process_id, &render_process_id);
880
881 if (render_process_id == -1) {
882 // This is a lazy background page. Identify if it is a normal
883 // or incognito background page.
884 ExtensionService* service = GetProfile()->GetExtensionService();
885 if (options.incognito)
886 service = ExtensionSystem::Get(
887 service->profile()->GetOffTheRecordProfile())->extension_service();
888 const Extension* extension = service->extensions()->GetByID(
889 options.extension_id);
890 DCHECK(extension);
891 // Wakes up the background page and opens the inspect window.
892 devtools_util::InspectBackgroundPage(extension, GetProfile());
893 return false;
894 }
895
896 int render_view_id;
897 base::StringToInt(options.render_view_id, &render_view_id);
898 content::RenderViewHost* host = content::RenderViewHost::FromID(
899 render_process_id, render_view_id);
900
901 if (!host) {
902 // This can happen if the host has gone away since the page was displayed.
903 return false;
904 }
905
906 DevToolsWindow::OpenDevToolsWindow(host);
907 return true;
908 }
909
~DeveloperPrivateInspectFunction()910 DeveloperPrivateInspectFunction::~DeveloperPrivateInspectFunction() {}
911
RunAsync()912 bool DeveloperPrivateLoadUnpackedFunction::RunAsync() {
913 base::string16 select_title =
914 l10n_util::GetStringUTF16(IDS_EXTENSION_LOAD_FROM_DIRECTORY);
915
916 // Balanced in FileSelected / FileSelectionCanceled.
917 AddRef();
918 bool result = ShowPicker(
919 ui::SelectFileDialog::SELECT_FOLDER,
920 DeveloperPrivateAPI::Get(GetProfile())->GetLastUnpackedDirectory(),
921 select_title,
922 ui::SelectFileDialog::FileTypeInfo(),
923 0);
924 return result;
925 }
926
FileSelected(const base::FilePath & path)927 void DeveloperPrivateLoadUnpackedFunction::FileSelected(
928 const base::FilePath& path) {
929 ExtensionService* service = GetProfile()->GetExtensionService();
930 UnpackedInstaller::Create(service)->Load(path);
931 DeveloperPrivateAPI::Get(GetProfile())->SetLastUnpackedDirectory(path);
932 SendResponse(true);
933 Release();
934 }
935
FileSelectionCanceled()936 void DeveloperPrivateLoadUnpackedFunction::FileSelectionCanceled() {
937 SendResponse(false);
938 Release();
939 }
940
ShowPicker(ui::SelectFileDialog::Type picker_type,const base::FilePath & last_directory,const base::string16 & select_title,const ui::SelectFileDialog::FileTypeInfo & info,int file_type_index)941 bool DeveloperPrivateChooseEntryFunction::ShowPicker(
942 ui::SelectFileDialog::Type picker_type,
943 const base::FilePath& last_directory,
944 const base::string16& select_title,
945 const ui::SelectFileDialog::FileTypeInfo& info,
946 int file_type_index) {
947 AppWindowRegistry* registry = AppWindowRegistry::Get(GetProfile());
948 DCHECK(registry);
949 AppWindow* app_window =
950 registry->GetAppWindowForRenderViewHost(render_view_host());
951 if (!app_window) {
952 return false;
953 }
954
955 // The entry picker will hold a reference to this function instance,
956 // and subsequent sending of the function response) until the user has
957 // selected a file or cancelled the picker. At that point, the picker will
958 // delete itself.
959 new EntryPicker(this,
960 app_window->web_contents(),
961 picker_type,
962 last_directory,
963 select_title,
964 info,
965 file_type_index);
966 return true;
967 }
968
RunAsync()969 bool DeveloperPrivateChooseEntryFunction::RunAsync() {
970 return false;
971 }
972
~DeveloperPrivateChooseEntryFunction()973 DeveloperPrivateChooseEntryFunction::~DeveloperPrivateChooseEntryFunction() {}
974
OnPackSuccess(const base::FilePath & crx_file,const base::FilePath & pem_file)975 void DeveloperPrivatePackDirectoryFunction::OnPackSuccess(
976 const base::FilePath& crx_file,
977 const base::FilePath& pem_file) {
978 developer::PackDirectoryResponse response;
979 response.message = base::UTF16ToUTF8(
980 PackExtensionJob::StandardSuccessMessage(crx_file, pem_file));
981 response.status = developer::PACK_STATUS_SUCCESS;
982 results_ = developer::PackDirectory::Results::Create(response);
983 SendResponse(true);
984 Release();
985 }
986
OnPackFailure(const std::string & error,ExtensionCreator::ErrorType error_type)987 void DeveloperPrivatePackDirectoryFunction::OnPackFailure(
988 const std::string& error,
989 ExtensionCreator::ErrorType error_type) {
990 developer::PackDirectoryResponse response;
991 response.message = error;
992 if (error_type == ExtensionCreator::kCRXExists) {
993 response.item_path = item_path_str_;
994 response.pem_path = key_path_str_;
995 response.override_flags = ExtensionCreator::kOverwriteCRX;
996 response.status = developer::PACK_STATUS_WARNING;
997 } else {
998 response.status = developer::PACK_STATUS_ERROR;
999 }
1000 results_ = developer::PackDirectory::Results::Create(response);
1001 SendResponse(true);
1002 Release();
1003 }
1004
RunAsync()1005 bool DeveloperPrivatePackDirectoryFunction::RunAsync() {
1006 scoped_ptr<PackDirectory::Params> params(
1007 PackDirectory::Params::Create(*args_));
1008 EXTENSION_FUNCTION_VALIDATE(params.get());
1009
1010 int flags = params->flags;
1011 item_path_str_ = params->path;
1012 key_path_str_ = params->private_key_path;
1013
1014 base::FilePath root_directory =
1015 base::FilePath::FromUTF8Unsafe(item_path_str_);
1016
1017 base::FilePath key_file = base::FilePath::FromUTF8Unsafe(key_path_str_);
1018
1019 developer::PackDirectoryResponse response;
1020 if (root_directory.empty()) {
1021 if (item_path_str_.empty())
1022 response.message = l10n_util::GetStringUTF8(
1023 IDS_EXTENSION_PACK_DIALOG_ERROR_ROOT_REQUIRED);
1024 else
1025 response.message = l10n_util::GetStringUTF8(
1026 IDS_EXTENSION_PACK_DIALOG_ERROR_ROOT_INVALID);
1027
1028 response.status = developer::PACK_STATUS_ERROR;
1029 results_ = developer::PackDirectory::Results::Create(response);
1030 SendResponse(true);
1031 return true;
1032 }
1033
1034 if (!key_path_str_.empty() && key_file.empty()) {
1035 response.message = l10n_util::GetStringUTF8(
1036 IDS_EXTENSION_PACK_DIALOG_ERROR_KEY_INVALID);
1037 response.status = developer::PACK_STATUS_ERROR;
1038 results_ = developer::PackDirectory::Results::Create(response);
1039 SendResponse(true);
1040 return true;
1041 }
1042
1043 // Balanced in OnPackSuccess / OnPackFailure.
1044 AddRef();
1045
1046 pack_job_ = new PackExtensionJob(this, root_directory, key_file, flags);
1047 pack_job_->Start();
1048 return true;
1049 }
1050
DeveloperPrivatePackDirectoryFunction()1051 DeveloperPrivatePackDirectoryFunction::DeveloperPrivatePackDirectoryFunction()
1052 {}
1053
~DeveloperPrivatePackDirectoryFunction()1054 DeveloperPrivatePackDirectoryFunction::~DeveloperPrivatePackDirectoryFunction()
1055 {}
1056
~DeveloperPrivateLoadUnpackedFunction()1057 DeveloperPrivateLoadUnpackedFunction::~DeveloperPrivateLoadUnpackedFunction() {}
1058
RunAsync()1059 bool DeveloperPrivateLoadDirectoryFunction::RunAsync() {
1060 // TODO(grv) : add unittests.
1061 std::string directory_url_str;
1062 std::string filesystem_name;
1063 std::string filesystem_path;
1064
1065 EXTENSION_FUNCTION_VALIDATE(args_->GetString(0, &filesystem_name));
1066 EXTENSION_FUNCTION_VALIDATE(args_->GetString(1, &filesystem_path));
1067 EXTENSION_FUNCTION_VALIDATE(args_->GetString(2, &directory_url_str));
1068
1069 // Directory url is non empty only for syncfilesystem.
1070 if (directory_url_str != "") {
1071 context_ = content::BrowserContext::GetStoragePartition(
1072 GetProfile(), render_view_host()->GetSiteInstance())
1073 ->GetFileSystemContext();
1074
1075 fileapi::FileSystemURL directory_url =
1076 context_->CrackURL(GURL(directory_url_str));
1077
1078 if (!directory_url.is_valid() && directory_url.type() ==
1079 fileapi::kFileSystemTypeSyncable) {
1080 SetError("DirectoryEntry of unsupported filesystem.");
1081 return false;
1082 }
1083
1084 size_t pos = 0;
1085 // Parse the project directory name from the project url. The project url is
1086 // expected to have project name as the suffix.
1087 if ((pos = directory_url_str.rfind("/")) == std::string::npos) {
1088 SetError("Invalid Directory entry.");
1089 return false;
1090 }
1091
1092 std::string project_name;
1093 project_name = directory_url_str.substr(pos + 1);
1094 project_base_url_ = directory_url_str.substr(0, pos + 1);
1095
1096 base::FilePath project_path(GetProfile()->GetPath());
1097 project_path = project_path.Append(kUnpackedAppsFolder);
1098 project_path = project_path.Append(
1099 base::FilePath::FromUTF8Unsafe(project_name));
1100
1101 project_base_path_ = project_path;
1102
1103 content::BrowserThread::PostTask(content::BrowserThread::FILE, FROM_HERE,
1104 base::Bind(&DeveloperPrivateLoadDirectoryFunction::
1105 ClearExistingDirectoryContent,
1106 this,
1107 project_base_path_));
1108 } else {
1109 // Check if the DirecotryEntry is the instance of chrome filesystem.
1110 if (!app_file_handler_util::ValidateFileEntryAndGetPath(filesystem_name,
1111 filesystem_path,
1112 render_view_host_,
1113 &project_base_path_,
1114 &error_))
1115 return false;
1116
1117 Load();
1118 }
1119
1120 return true;
1121 }
1122
Load()1123 void DeveloperPrivateLoadDirectoryFunction::Load() {
1124 ExtensionService* service = GetProfile()->GetExtensionService();
1125 UnpackedInstaller::Create(service)->Load(project_base_path_);
1126
1127 // TODO(grv) : The unpacked installer should fire an event when complete
1128 // and return the extension_id.
1129 SetResult(new base::StringValue("-1"));
1130 SendResponse(true);
1131 }
1132
ClearExistingDirectoryContent(const base::FilePath & project_path)1133 void DeveloperPrivateLoadDirectoryFunction::ClearExistingDirectoryContent(
1134 const base::FilePath& project_path) {
1135
1136 // Clear the project directory before copying new files.
1137 base::DeleteFile(project_path, true/*recursive*/);
1138
1139 pending_copy_operations_count_ = 1;
1140
1141 content::BrowserThread::PostTask(content::BrowserThread::IO, FROM_HERE,
1142 base::Bind(&DeveloperPrivateLoadDirectoryFunction::
1143 ReadSyncFileSystemDirectory,
1144 this, project_path, project_path.BaseName()));
1145 }
1146
ReadSyncFileSystemDirectory(const base::FilePath & project_path,const base::FilePath & destination_path)1147 void DeveloperPrivateLoadDirectoryFunction::ReadSyncFileSystemDirectory(
1148 const base::FilePath& project_path,
1149 const base::FilePath& destination_path) {
1150
1151 current_path_ = context_->CrackURL(GURL(project_base_url_)).path();
1152
1153 GURL project_url = GURL(project_base_url_ + destination_path.MaybeAsASCII());
1154
1155 fileapi::FileSystemURL url = context_->CrackURL(project_url);
1156
1157 context_->operation_runner()->ReadDirectory(
1158 url, base::Bind(&DeveloperPrivateLoadDirectoryFunction::
1159 ReadSyncFileSystemDirectoryCb,
1160 this, project_path, destination_path));
1161 }
1162
ReadSyncFileSystemDirectoryCb(const base::FilePath & project_path,const base::FilePath & destination_path,base::File::Error status,const fileapi::FileSystemOperation::FileEntryList & file_list,bool has_more)1163 void DeveloperPrivateLoadDirectoryFunction::ReadSyncFileSystemDirectoryCb(
1164 const base::FilePath& project_path,
1165 const base::FilePath& destination_path,
1166 base::File::Error status,
1167 const fileapi::FileSystemOperation::FileEntryList& file_list,
1168 bool has_more) {
1169
1170 if (status != base::File::FILE_OK) {
1171 DLOG(ERROR) << "Error in copying files from sync filesystem.";
1172 return;
1173 }
1174
1175 // We add 1 to the pending copy operations for both files and directories. We
1176 // release the directory copy operation once all the files under the directory
1177 // are added for copying. We do that to ensure that pendingCopyOperationsCount
1178 // does not become zero before all copy operations are finished.
1179 // In case the directory happens to be executing the last copy operation it
1180 // will call SendResponse to send the response to the API. The pending copy
1181 // operations of files are released by the CopyFile function.
1182 pending_copy_operations_count_ += file_list.size();
1183
1184 for (size_t i = 0; i < file_list.size(); ++i) {
1185 if (file_list[i].is_directory) {
1186 ReadSyncFileSystemDirectory(project_path.Append(file_list[i].name),
1187 destination_path.Append(file_list[i].name));
1188 continue;
1189 }
1190
1191 std::string origin_url(
1192 Extension::GetBaseURLFromExtensionId(extension_id()).spec());
1193 fileapi::FileSystemURL url(sync_file_system::CreateSyncableFileSystemURL(
1194 GURL(origin_url),
1195 current_path_.Append(destination_path.Append(file_list[i].name))));
1196 base::FilePath target_path = project_path;
1197 target_path = target_path.Append(file_list[i].name);
1198
1199 context_->operation_runner()->CreateSnapshotFile(
1200 url,
1201 base::Bind(&DeveloperPrivateLoadDirectoryFunction::SnapshotFileCallback,
1202 this,
1203 target_path));
1204 }
1205
1206 if (!has_more) {
1207 // Directory copy operation released here.
1208 pending_copy_operations_count_--;
1209
1210 if (!pending_copy_operations_count_) {
1211 content::BrowserThread::PostTask(
1212 content::BrowserThread::UI, FROM_HERE,
1213 base::Bind(&DeveloperPrivateLoadDirectoryFunction::SendResponse,
1214 this,
1215 success_));
1216 }
1217 }
1218 }
1219
SnapshotFileCallback(const base::FilePath & target_path,base::File::Error result,const base::File::Info & file_info,const base::FilePath & src_path,const scoped_refptr<webkit_blob::ShareableFileReference> & file_ref)1220 void DeveloperPrivateLoadDirectoryFunction::SnapshotFileCallback(
1221 const base::FilePath& target_path,
1222 base::File::Error result,
1223 const base::File::Info& file_info,
1224 const base::FilePath& src_path,
1225 const scoped_refptr<webkit_blob::ShareableFileReference>& file_ref) {
1226 if (result != base::File::FILE_OK) {
1227 SetError("Error in copying files from sync filesystem.");
1228 success_ = false;
1229 return;
1230 }
1231
1232 content::BrowserThread::PostTask(content::BrowserThread::FILE, FROM_HERE,
1233 base::Bind(&DeveloperPrivateLoadDirectoryFunction::CopyFile,
1234 this,
1235 src_path,
1236 target_path));
1237 }
1238
CopyFile(const base::FilePath & src_path,const base::FilePath & target_path)1239 void DeveloperPrivateLoadDirectoryFunction::CopyFile(
1240 const base::FilePath& src_path,
1241 const base::FilePath& target_path) {
1242 if (!base::CreateDirectory(target_path.DirName())) {
1243 SetError("Error in copying files from sync filesystem.");
1244 success_ = false;
1245 }
1246
1247 if (success_)
1248 base::CopyFile(src_path, target_path);
1249
1250 CHECK(pending_copy_operations_count_ > 0);
1251 pending_copy_operations_count_--;
1252
1253 if (!pending_copy_operations_count_) {
1254 content::BrowserThread::PostTask(content::BrowserThread::UI, FROM_HERE,
1255 base::Bind(&DeveloperPrivateLoadDirectoryFunction::Load,
1256 this));
1257 }
1258 }
1259
DeveloperPrivateLoadDirectoryFunction()1260 DeveloperPrivateLoadDirectoryFunction::DeveloperPrivateLoadDirectoryFunction()
1261 : pending_copy_operations_count_(0), success_(true) {}
1262
~DeveloperPrivateLoadDirectoryFunction()1263 DeveloperPrivateLoadDirectoryFunction::~DeveloperPrivateLoadDirectoryFunction()
1264 {}
1265
RunAsync()1266 bool DeveloperPrivateChoosePathFunction::RunAsync() {
1267 scoped_ptr<developer::ChoosePath::Params> params(
1268 developer::ChoosePath::Params::Create(*args_));
1269 EXTENSION_FUNCTION_VALIDATE(params.get() != NULL);
1270
1271 ui::SelectFileDialog::Type type = ui::SelectFileDialog::SELECT_FOLDER;
1272 ui::SelectFileDialog::FileTypeInfo info;
1273 if (params->select_type == developer::SELECT_TYPE_FILE) {
1274 type = ui::SelectFileDialog::SELECT_OPEN_FILE;
1275 }
1276 base::string16 select_title;
1277
1278 int file_type_index = 0;
1279 if (params->file_type == developer::FILE_TYPE_LOAD) {
1280 select_title = l10n_util::GetStringUTF16(IDS_EXTENSION_LOAD_FROM_DIRECTORY);
1281 } else if (params->file_type == developer::FILE_TYPE_PEM) {
1282 select_title = l10n_util::GetStringUTF16(
1283 IDS_EXTENSION_PACK_DIALOG_SELECT_KEY);
1284 info.extensions.push_back(std::vector<base::FilePath::StringType>());
1285 info.extensions.front().push_back(FILE_PATH_LITERAL("pem"));
1286 info.extension_description_overrides.push_back(
1287 l10n_util::GetStringUTF16(
1288 IDS_EXTENSION_PACK_DIALOG_KEY_FILE_TYPE_DESCRIPTION));
1289 info.include_all_files = true;
1290 file_type_index = 1;
1291 } else {
1292 NOTREACHED();
1293 }
1294
1295 // Balanced by FileSelected / FileSelectionCanceled.
1296 AddRef();
1297 bool result = ShowPicker(
1298 type,
1299 DeveloperPrivateAPI::Get(GetProfile())->GetLastUnpackedDirectory(),
1300 select_title,
1301 info,
1302 file_type_index);
1303 return result;
1304 }
1305
FileSelected(const base::FilePath & path)1306 void DeveloperPrivateChoosePathFunction::FileSelected(
1307 const base::FilePath& path) {
1308 SetResult(new base::StringValue(base::UTF16ToUTF8(path.LossyDisplayName())));
1309 SendResponse(true);
1310 Release();
1311 }
1312
FileSelectionCanceled()1313 void DeveloperPrivateChoosePathFunction::FileSelectionCanceled() {
1314 SendResponse(false);
1315 Release();
1316 }
1317
~DeveloperPrivateChoosePathFunction()1318 DeveloperPrivateChoosePathFunction::~DeveloperPrivateChoosePathFunction() {}
1319
RunSync()1320 bool DeveloperPrivateIsProfileManagedFunction::RunSync() {
1321 SetResult(new base::FundamentalValue(GetProfile()->IsSupervised()));
1322 return true;
1323 }
1324
1325 DeveloperPrivateIsProfileManagedFunction::
~DeveloperPrivateIsProfileManagedFunction()1326 ~DeveloperPrivateIsProfileManagedFunction() {
1327 }
1328
1329 DeveloperPrivateRequestFileSourceFunction::
DeveloperPrivateRequestFileSourceFunction()1330 DeveloperPrivateRequestFileSourceFunction() {}
1331
1332 DeveloperPrivateRequestFileSourceFunction::
~DeveloperPrivateRequestFileSourceFunction()1333 ~DeveloperPrivateRequestFileSourceFunction() {}
1334
RunAsync()1335 bool DeveloperPrivateRequestFileSourceFunction::RunAsync() {
1336 scoped_ptr<developer::RequestFileSource::Params> params(
1337 developer::RequestFileSource::Params::Create(*args_));
1338 EXTENSION_FUNCTION_VALIDATE(params.get() != NULL);
1339
1340 base::DictionaryValue* dict = NULL;
1341 if (!params->dict->GetAsDictionary(&dict)) {
1342 NOTREACHED();
1343 return false;
1344 }
1345
1346 AddRef(); // Balanced in LaunchCallback().
1347 error_ui_util::HandleRequestFileSource(
1348 dict,
1349 GetProfile(),
1350 base::Bind(&DeveloperPrivateRequestFileSourceFunction::LaunchCallback,
1351 base::Unretained(this)));
1352 return true;
1353 }
1354
LaunchCallback(const base::DictionaryValue & results)1355 void DeveloperPrivateRequestFileSourceFunction::LaunchCallback(
1356 const base::DictionaryValue& results) {
1357 SetResult(results.DeepCopy());
1358 SendResponse(true);
1359 Release(); // Balanced in RunAsync().
1360 }
1361
DeveloperPrivateOpenDevToolsFunction()1362 DeveloperPrivateOpenDevToolsFunction::DeveloperPrivateOpenDevToolsFunction() {}
~DeveloperPrivateOpenDevToolsFunction()1363 DeveloperPrivateOpenDevToolsFunction::~DeveloperPrivateOpenDevToolsFunction() {}
1364
RunAsync()1365 bool DeveloperPrivateOpenDevToolsFunction::RunAsync() {
1366 scoped_ptr<developer::OpenDevTools::Params> params(
1367 developer::OpenDevTools::Params::Create(*args_));
1368 EXTENSION_FUNCTION_VALIDATE(params.get() != NULL);
1369
1370 base::DictionaryValue* dict = NULL;
1371 if (!params->dict->GetAsDictionary(&dict)) {
1372 NOTREACHED();
1373 return false;
1374 }
1375
1376 error_ui_util::HandleOpenDevTools(dict);
1377
1378 return true;
1379 }
1380
1381 } // namespace api
1382
1383 } // namespace extensions
1384