1 // Copyright 2013 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/chromeos/extensions/file_manager/private_api_misc.h"
7 #include "apps/app_window.h"
8 #include "apps/app_window_registry.h"
9 #include "ash/frame/frame_util.h"
10 #include "base/files/file_path.h"
11 #include "base/prefs/pref_service.h"
12 #include "base/strings/stringprintf.h"
13 #include "base/strings/utf_string_conversions.h"
14 #include "chrome/browser/browser_process.h"
15 #include "chrome/browser/chromeos/drive/file_system_util.h"
16 #include "chrome/browser/chromeos/extensions/file_manager/event_router.h"
17 #include "chrome/browser/chromeos/extensions/file_manager/file_browser_private_api.h"
18 #include "chrome/browser/chromeos/extensions/file_manager/private_api_util.h"
19 #include "chrome/browser/chromeos/file_manager/app_installer.h"
20 #include "chrome/browser/chromeos/file_manager/zip_file_creator.h"
21 #include "chrome/browser/chromeos/profiles/profile_helper.h"
22 #include "chrome/browser/chromeos/settings/cros_settings.h"
23 #include "chrome/browser/devtools/devtools_window.h"
24 #include "chrome/browser/drive/event_logger.h"
25 #include "chrome/browser/extensions/devtools_util.h"
26 #include "chrome/browser/lifetime/application_lifetime.h"
27 #include "chrome/browser/profiles/profile.h"
28 #include "chrome/browser/profiles/profile_manager.h"
29 #include "chrome/browser/profiles/profiles_state.h"
30 #include "chrome/browser/signin/profile_oauth2_token_service_factory.h"
31 #include "chrome/browser/signin/signin_manager_factory.h"
32 #include "chrome/browser/ui/ash/multi_user/multi_user_util.h"
33 #include "chrome/browser/ui/ash/multi_user/multi_user_window_manager.h"
34 #include "chrome/common/extensions/api/file_browser_private.h"
35 #include "chrome/common/pref_names.h"
36 #include "components/signin/core/browser/profile_oauth2_token_service.h"
37 #include "components/signin/core/browser/signin_manager.h"
38 #include "components/user_manager/user_manager.h"
39 #include "content/public/browser/render_view_host.h"
40 #include "content/public/browser/web_contents.h"
41 #include "content/public/common/page_zoom.h"
42 #include "google_apis/drive/auth_service.h"
43 #include "ui/base/webui/web_ui_util.h"
46 namespace extensions {
49 const char kCWSScope[] = "https://www.googleapis.com/auth/chromewebstore";
50 const char kGoogleCastApiExtensionId[] = "mafeflapfdfljijmlienjedomfjfmhpd";
52 // Obtains the current app window.
53 apps::AppWindow* GetCurrentAppWindow(ChromeSyncExtensionFunction* function) {
54 apps::AppWindowRegistry* const app_window_registry =
55 apps::AppWindowRegistry::Get(function->GetProfile());
56 content::WebContents* const contents = function->GetAssociatedWebContents();
57 content::RenderViewHost* const render_view_host =
58 contents ? contents->GetRenderViewHost() : NULL;
59 return render_view_host ? app_window_registry->GetAppWindowForRenderViewHost(
64 std::vector<linked_ptr<api::file_browser_private::ProfileInfo> >
65 GetLoggedInProfileInfoList(content::WebContents* contents) {
66 DCHECK(user_manager::UserManager::IsInitialized());
67 const std::vector<Profile*>& profiles =
68 g_browser_process->profile_manager()->GetLoadedProfiles();
69 std::set<Profile*> original_profiles;
70 std::vector<linked_ptr<api::file_browser_private::ProfileInfo> >
73 for (size_t i = 0; i < profiles.size(); ++i) {
74 // Filter the profile.
75 Profile* const profile = profiles[i]->GetOriginalProfile();
76 if (original_profiles.count(profile))
78 original_profiles.insert(profile);
79 const user_manager::User* const user =
80 chromeos::ProfileHelper::Get()->GetUserByProfile(profile);
81 if (!user || !user->is_logged_in())
84 // Make a ProfileInfo.
85 linked_ptr<api::file_browser_private::ProfileInfo> profile_info(
86 new api::file_browser_private::ProfileInfo());
87 profile_info->profile_id = multi_user_util::GetUserIDFromProfile(profile);
88 profile_info->display_name = UTF16ToUTF8(user->GetDisplayName());
89 // TODO(hirono): Remove the property from the profile_info.
90 profile_info->is_current_profile = true;
92 // Make an icon URL of the profile.
94 const gfx::Image& image =
95 ash::GetAvatarImageForContext(contents->GetBrowserContext());
96 const gfx::ImageSkia& skia = image.AsImageSkia();
97 profile_info->profile_image.reset(
98 new api::file_browser_private::ImageSet);
99 profile_info->profile_image->scale1x_url =
100 webui::GetBitmapDataUrl(skia.GetRepresentation(1.0f).sk_bitmap());
101 profile_info->profile_image->scale2x_url =
102 webui::GetBitmapDataUrl(skia.GetRepresentation(2.0f).sk_bitmap());
104 result_profiles.push_back(profile_info);
107 return result_profiles;
111 bool FileBrowserPrivateLogoutUserForReauthenticationFunction::RunSync() {
112 user_manager::User* user =
113 chromeos::ProfileHelper::Get()->GetUserByProfile(GetProfile());
115 user_manager::UserManager::Get()->SaveUserOAuthStatus(
116 user->email(), user_manager::User::OAUTH2_TOKEN_STATUS_INVALID);
119 chrome::AttemptUserExit();
123 bool FileBrowserPrivateGetPreferencesFunction::RunSync() {
124 api::file_browser_private::Preferences result;
125 const PrefService* const service = GetProfile()->GetPrefs();
127 result.drive_enabled = drive::util::IsDriveEnabledForProfile(GetProfile());
128 result.cellular_disabled =
129 service->GetBoolean(prefs::kDisableDriveOverCellular);
130 result.hosted_files_disabled =
131 service->GetBoolean(prefs::kDisableDriveHostedFiles);
132 result.use24hour_clock = service->GetBoolean(prefs::kUse24HourClock);
133 result.allow_redeem_offers = true;
134 if (!chromeos::CrosSettings::Get()->GetBoolean(
135 chromeos::kAllowRedeemChromeOsRegistrationOffers,
136 &result.allow_redeem_offers)) {
137 result.allow_redeem_offers = true;
140 SetResult(result.ToValue().release());
142 drive::EventLogger* logger = file_manager::util::GetLogger(GetProfile());
144 logger->Log(logging::LOG_INFO, "%s succeeded.", name().c_str());
148 bool FileBrowserPrivateSetPreferencesFunction::RunSync() {
149 using extensions::api::file_browser_private::SetPreferences::Params;
150 const scoped_ptr<Params> params(Params::Create(*args_));
151 EXTENSION_FUNCTION_VALIDATE(params);
153 PrefService* const service = GetProfile()->GetPrefs();
155 if (params->change_info.cellular_disabled)
156 service->SetBoolean(prefs::kDisableDriveOverCellular,
157 *params->change_info.cellular_disabled);
159 if (params->change_info.hosted_files_disabled)
160 service->SetBoolean(prefs::kDisableDriveHostedFiles,
161 *params->change_info.hosted_files_disabled);
163 drive::EventLogger* logger = file_manager::util::GetLogger(GetProfile());
165 logger->Log(logging::LOG_INFO, "%s succeeded.", name().c_str());
169 FileBrowserPrivateZipSelectionFunction::
170 FileBrowserPrivateZipSelectionFunction() {}
172 FileBrowserPrivateZipSelectionFunction::
173 ~FileBrowserPrivateZipSelectionFunction() {}
175 bool FileBrowserPrivateZipSelectionFunction::RunAsync() {
176 using extensions::api::file_browser_private::ZipSelection::Params;
177 const scoped_ptr<Params> params(Params::Create(*args_));
178 EXTENSION_FUNCTION_VALIDATE(params);
180 // First param is the source directory URL.
181 if (params->dir_url.empty())
184 base::FilePath src_dir = file_manager::util::GetLocalPathFromURL(
185 render_view_host(), GetProfile(), GURL(params->dir_url));
189 // Second param is the list of selected file URLs.
190 if (params->selection_urls.empty())
193 std::vector<base::FilePath> files;
194 for (size_t i = 0; i < params->selection_urls.size(); ++i) {
195 base::FilePath path = file_manager::util::GetLocalPathFromURL(
196 render_view_host(), GetProfile(), GURL(params->selection_urls[i]));
199 files.push_back(path);
202 // Third param is the name of the output zip file.
203 if (params->dest_name.empty())
206 // Check if the dir path is under Drive mount point.
207 // TODO(hshi): support create zip file on Drive (crbug.com/158690).
208 if (drive::util::IsUnderDriveMountPoint(src_dir))
211 base::FilePath dest_file = src_dir.Append(params->dest_name);
212 std::vector<base::FilePath> src_relative_paths;
213 for (size_t i = 0; i != files.size(); ++i) {
214 const base::FilePath& file_path = files[i];
216 // Obtain the relative path of |file_path| under |src_dir|.
217 base::FilePath relative_path;
218 if (!src_dir.AppendRelativePath(file_path, &relative_path))
220 src_relative_paths.push_back(relative_path);
223 (new file_manager::ZipFileCreator(
224 base::Bind(&FileBrowserPrivateZipSelectionFunction::OnZipDone, this),
227 dest_file))->Start();
231 void FileBrowserPrivateZipSelectionFunction::OnZipDone(bool success) {
232 SetResult(new base::FundamentalValue(success));
236 bool FileBrowserPrivateZoomFunction::RunSync() {
237 using extensions::api::file_browser_private::Zoom::Params;
238 const scoped_ptr<Params> params(Params::Create(*args_));
239 EXTENSION_FUNCTION_VALIDATE(params);
241 content::PageZoom zoom_type;
242 switch (params->operation) {
243 case api::file_browser_private::ZOOM_OPERATION_TYPE_IN:
244 zoom_type = content::PAGE_ZOOM_IN;
246 case api::file_browser_private::ZOOM_OPERATION_TYPE_OUT:
247 zoom_type = content::PAGE_ZOOM_OUT;
249 case api::file_browser_private::ZOOM_OPERATION_TYPE_RESET:
250 zoom_type = content::PAGE_ZOOM_RESET;
256 render_view_host()->Zoom(zoom_type);
260 bool FileBrowserPrivateInstallWebstoreItemFunction::RunAsync() {
261 using extensions::api::file_browser_private::InstallWebstoreItem::Params;
262 const scoped_ptr<Params> params(Params::Create(*args_));
263 EXTENSION_FUNCTION_VALIDATE(params);
265 if (params->item_id.empty())
268 const extensions::WebstoreStandaloneInstaller::Callback callback =
270 &FileBrowserPrivateInstallWebstoreItemFunction::OnInstallComplete,
273 // Only GoogleCastAPI extension can use silent installation.
274 if (params->silent_installation &&
275 params->item_id != kGoogleCastApiExtensionId) {
276 SetError("Only whitelisted items can do silent installation.");
280 scoped_refptr<file_manager::AppInstaller> installer(
281 new file_manager::AppInstaller(GetAssociatedWebContents(),
284 params->silent_installation,
286 // installer will be AddRef()'d in BeginInstall().
287 installer->BeginInstall();
291 void FileBrowserPrivateInstallWebstoreItemFunction::OnInstallComplete(
293 const std::string& error,
294 extensions::webstore_install::Result result) {
295 drive::EventLogger* logger = file_manager::util::GetLogger(GetProfile());
298 logger->Log(logging::LOG_INFO,
299 "App install succeeded. (item id: %s)",
300 webstore_item_id_.c_str());
304 logger->Log(logging::LOG_ERROR,
305 "App install failed. (item id: %s, reason: %s)",
306 webstore_item_id_.c_str(),
312 SendResponse(success);
315 FileBrowserPrivateRequestWebStoreAccessTokenFunction::
316 FileBrowserPrivateRequestWebStoreAccessTokenFunction() {
319 FileBrowserPrivateRequestWebStoreAccessTokenFunction::
320 ~FileBrowserPrivateRequestWebStoreAccessTokenFunction() {
323 bool FileBrowserPrivateRequestWebStoreAccessTokenFunction::RunAsync() {
324 std::vector<std::string> scopes;
325 scopes.push_back(kCWSScope);
327 ProfileOAuth2TokenService* oauth_service =
328 ProfileOAuth2TokenServiceFactory::GetForProfile(GetProfile());
329 net::URLRequestContextGetter* url_request_context_getter =
330 g_browser_process->system_request_context();
332 if (!oauth_service) {
333 drive::EventLogger* logger = file_manager::util::GetLogger(GetProfile());
335 logger->Log(logging::LOG_ERROR,
336 "CWS OAuth token fetch failed. OAuth2TokenService can't "
339 SetResult(base::Value::CreateNullValue());
343 SigninManagerBase* signin_manager =
344 SigninManagerFactory::GetForProfile(GetProfile());
345 auth_service_.reset(new google_apis::AuthService(
347 signin_manager->GetAuthenticatedAccountId(),
348 url_request_context_getter,
350 auth_service_->StartAuthentication(base::Bind(
351 &FileBrowserPrivateRequestWebStoreAccessTokenFunction::
352 OnAccessTokenFetched,
358 void FileBrowserPrivateRequestWebStoreAccessTokenFunction::OnAccessTokenFetched(
359 google_apis::GDataErrorCode code,
360 const std::string& access_token) {
361 drive::EventLogger* logger = file_manager::util::GetLogger(GetProfile());
363 if (code == google_apis::HTTP_SUCCESS) {
364 DCHECK(auth_service_->HasAccessToken());
365 DCHECK(access_token == auth_service_->access_token());
367 logger->Log(logging::LOG_INFO, "CWS OAuth token fetch succeeded.");
368 SetResult(new base::StringValue(access_token));
372 logger->Log(logging::LOG_ERROR,
373 "CWS OAuth token fetch failed. (GDataErrorCode: %s)",
374 google_apis::GDataErrorCodeToString(code).c_str());
376 SetResult(base::Value::CreateNullValue());
381 bool FileBrowserPrivateGetProfilesFunction::RunSync() {
382 const std::vector<linked_ptr<api::file_browser_private::ProfileInfo> >&
383 profiles = GetLoggedInProfileInfoList(GetAssociatedWebContents());
385 // Obtains the display profile ID.
386 apps::AppWindow* const app_window = GetCurrentAppWindow(this);
387 chrome::MultiUserWindowManager* const window_manager =
388 chrome::MultiUserWindowManager::GetInstance();
389 const std::string current_profile_id =
390 multi_user_util::GetUserIDFromProfile(GetProfile());
391 const std::string display_profile_id =
392 window_manager && app_window ? window_manager->GetUserPresentingWindow(
393 app_window->GetNativeWindow())
396 results_ = api::file_browser_private::GetProfiles::Results::Create(
399 display_profile_id.empty() ? current_profile_id : display_profile_id);
403 bool FileBrowserPrivateVisitDesktopFunction::RunSync() {
404 using api::file_browser_private::VisitDesktop::Params;
405 const scoped_ptr<Params> params(Params::Create(*args_));
406 const std::vector<linked_ptr<api::file_browser_private::ProfileInfo> >&
407 profiles = GetLoggedInProfileInfoList(GetAssociatedWebContents());
409 chrome::MultiUserWindowManager* const window_manager =
410 chrome::MultiUserWindowManager::GetInstance();
411 DCHECK(window_manager);
413 // Check if the target user is logged-in or not.
414 bool logged_in = false;
415 for (size_t i = 0; i < profiles.size(); ++i) {
416 if (profiles[i]->profile_id == params->profile_id) {
422 SetError("The user is not logged-in now.");
426 // Look for the current app window.
427 apps::AppWindow* const app_window = GetCurrentAppWindow(this);
429 SetError("Target window is not found.");
433 // Observe owner changes of windows.
434 file_manager::EventRouter* const event_router =
435 file_manager::FileBrowserPrivateAPI::Get(GetProfile())->event_router();
436 event_router->RegisterMultiUserWindowManagerObserver();
438 // Move the window to the user's desktop.
439 window_manager->ShowWindowForUser(app_window->GetNativeWindow(),
443 if (!window_manager->IsWindowOnDesktopOfUser(app_window->GetNativeWindow(),
444 params->profile_id)) {
445 SetError("The window cannot visit the desktop.");
452 bool FileBrowserPrivateOpenInspectorFunction::RunSync() {
453 using extensions::api::file_browser_private::OpenInspector::Params;
454 const scoped_ptr<Params> params(Params::Create(*args_));
455 EXTENSION_FUNCTION_VALIDATE(params);
457 switch (params->type) {
458 case extensions::api::file_browser_private::INSPECTION_TYPE_NORMAL:
459 // Open inspector for foreground page.
460 DevToolsWindow::OpenDevToolsWindow(
461 content::WebContents::FromRenderViewHost(render_view_host()));
463 case extensions::api::file_browser_private::INSPECTION_TYPE_CONSOLE:
464 // Open inspector for foreground page and bring focus to the console.
465 DevToolsWindow::OpenDevToolsWindow(
466 content::WebContents::FromRenderViewHost(render_view_host()),
467 DevToolsToggleAction::ShowConsole());
469 case extensions::api::file_browser_private::INSPECTION_TYPE_ELEMENT:
470 // Open inspector for foreground page in inspect element mode.
471 DevToolsWindow::OpenDevToolsWindow(
472 content::WebContents::FromRenderViewHost(render_view_host()),
473 DevToolsToggleAction::Inspect());
475 case extensions::api::file_browser_private::INSPECTION_TYPE_BACKGROUND:
476 // Open inspector for background page.
477 extensions::devtools_util::InspectBackgroundPage(extension(),
483 base::StringPrintf("Unexpected inspection type(%d) is specified.",
484 static_cast<int>(params->type)));
490 } // namespace extensions