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() {
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 result_profiles.push_back(profile_info);
95 return result_profiles;
99 bool FileBrowserPrivateLogoutUserForReauthenticationFunction::RunSync() {
100 user_manager::User* user =
101 chromeos::ProfileHelper::Get()->GetUserByProfile(GetProfile());
103 user_manager::UserManager::Get()->SaveUserOAuthStatus(
104 user->email(), user_manager::User::OAUTH2_TOKEN_STATUS_INVALID);
107 chrome::AttemptUserExit();
111 bool FileBrowserPrivateGetPreferencesFunction::RunSync() {
112 api::file_browser_private::Preferences result;
113 const PrefService* const service = GetProfile()->GetPrefs();
115 result.drive_enabled = drive::util::IsDriveEnabledForProfile(GetProfile());
116 result.cellular_disabled =
117 service->GetBoolean(prefs::kDisableDriveOverCellular);
118 result.hosted_files_disabled =
119 service->GetBoolean(prefs::kDisableDriveHostedFiles);
120 result.use24hour_clock = service->GetBoolean(prefs::kUse24HourClock);
121 result.allow_redeem_offers = true;
122 if (!chromeos::CrosSettings::Get()->GetBoolean(
123 chromeos::kAllowRedeemChromeOsRegistrationOffers,
124 &result.allow_redeem_offers)) {
125 result.allow_redeem_offers = true;
128 SetResult(result.ToValue().release());
130 drive::EventLogger* logger = file_manager::util::GetLogger(GetProfile());
132 logger->Log(logging::LOG_INFO, "%s succeeded.", name().c_str());
136 bool FileBrowserPrivateSetPreferencesFunction::RunSync() {
137 using extensions::api::file_browser_private::SetPreferences::Params;
138 const scoped_ptr<Params> params(Params::Create(*args_));
139 EXTENSION_FUNCTION_VALIDATE(params);
141 PrefService* const service = GetProfile()->GetPrefs();
143 if (params->change_info.cellular_disabled)
144 service->SetBoolean(prefs::kDisableDriveOverCellular,
145 *params->change_info.cellular_disabled);
147 if (params->change_info.hosted_files_disabled)
148 service->SetBoolean(prefs::kDisableDriveHostedFiles,
149 *params->change_info.hosted_files_disabled);
151 drive::EventLogger* logger = file_manager::util::GetLogger(GetProfile());
153 logger->Log(logging::LOG_INFO, "%s succeeded.", name().c_str());
157 FileBrowserPrivateZipSelectionFunction::
158 FileBrowserPrivateZipSelectionFunction() {}
160 FileBrowserPrivateZipSelectionFunction::
161 ~FileBrowserPrivateZipSelectionFunction() {}
163 bool FileBrowserPrivateZipSelectionFunction::RunAsync() {
164 using extensions::api::file_browser_private::ZipSelection::Params;
165 const scoped_ptr<Params> params(Params::Create(*args_));
166 EXTENSION_FUNCTION_VALIDATE(params);
168 // First param is the source directory URL.
169 if (params->dir_url.empty())
172 base::FilePath src_dir = file_manager::util::GetLocalPathFromURL(
173 render_view_host(), GetProfile(), GURL(params->dir_url));
177 // Second param is the list of selected file URLs.
178 if (params->selection_urls.empty())
181 std::vector<base::FilePath> files;
182 for (size_t i = 0; i < params->selection_urls.size(); ++i) {
183 base::FilePath path = file_manager::util::GetLocalPathFromURL(
184 render_view_host(), GetProfile(), GURL(params->selection_urls[i]));
187 files.push_back(path);
190 // Third param is the name of the output zip file.
191 if (params->dest_name.empty())
194 // Check if the dir path is under Drive mount point.
195 // TODO(hshi): support create zip file on Drive (crbug.com/158690).
196 if (drive::util::IsUnderDriveMountPoint(src_dir))
199 base::FilePath dest_file = src_dir.Append(params->dest_name);
200 std::vector<base::FilePath> src_relative_paths;
201 for (size_t i = 0; i != files.size(); ++i) {
202 const base::FilePath& file_path = files[i];
204 // Obtain the relative path of |file_path| under |src_dir|.
205 base::FilePath relative_path;
206 if (!src_dir.AppendRelativePath(file_path, &relative_path))
208 src_relative_paths.push_back(relative_path);
211 (new file_manager::ZipFileCreator(
212 base::Bind(&FileBrowserPrivateZipSelectionFunction::OnZipDone, this),
215 dest_file))->Start();
219 void FileBrowserPrivateZipSelectionFunction::OnZipDone(bool success) {
220 SetResult(new base::FundamentalValue(success));
224 bool FileBrowserPrivateZoomFunction::RunSync() {
225 using extensions::api::file_browser_private::Zoom::Params;
226 const scoped_ptr<Params> params(Params::Create(*args_));
227 EXTENSION_FUNCTION_VALIDATE(params);
229 content::PageZoom zoom_type;
230 switch (params->operation) {
231 case api::file_browser_private::ZOOM_OPERATION_TYPE_IN:
232 zoom_type = content::PAGE_ZOOM_IN;
234 case api::file_browser_private::ZOOM_OPERATION_TYPE_OUT:
235 zoom_type = content::PAGE_ZOOM_OUT;
237 case api::file_browser_private::ZOOM_OPERATION_TYPE_RESET:
238 zoom_type = content::PAGE_ZOOM_RESET;
244 render_view_host()->Zoom(zoom_type);
248 bool FileBrowserPrivateInstallWebstoreItemFunction::RunAsync() {
249 using extensions::api::file_browser_private::InstallWebstoreItem::Params;
250 const scoped_ptr<Params> params(Params::Create(*args_));
251 EXTENSION_FUNCTION_VALIDATE(params);
253 if (params->item_id.empty())
256 const extensions::WebstoreStandaloneInstaller::Callback callback =
258 &FileBrowserPrivateInstallWebstoreItemFunction::OnInstallComplete,
261 // Only GoogleCastAPI extension can use silent installation.
262 if (params->silent_installation &&
263 params->item_id != kGoogleCastApiExtensionId) {
264 SetError("Only whitelisted items can do silent installation.");
268 scoped_refptr<file_manager::AppInstaller> installer(
269 new file_manager::AppInstaller(GetAssociatedWebContents(),
272 params->silent_installation,
274 // installer will be AddRef()'d in BeginInstall().
275 installer->BeginInstall();
279 void FileBrowserPrivateInstallWebstoreItemFunction::OnInstallComplete(
281 const std::string& error,
282 extensions::webstore_install::Result result) {
283 drive::EventLogger* logger = file_manager::util::GetLogger(GetProfile());
286 logger->Log(logging::LOG_INFO,
287 "App install succeeded. (item id: %s)",
288 webstore_item_id_.c_str());
292 logger->Log(logging::LOG_ERROR,
293 "App install failed. (item id: %s, reason: %s)",
294 webstore_item_id_.c_str(),
300 SendResponse(success);
303 FileBrowserPrivateRequestWebStoreAccessTokenFunction::
304 FileBrowserPrivateRequestWebStoreAccessTokenFunction() {
307 FileBrowserPrivateRequestWebStoreAccessTokenFunction::
308 ~FileBrowserPrivateRequestWebStoreAccessTokenFunction() {
311 bool FileBrowserPrivateRequestWebStoreAccessTokenFunction::RunAsync() {
312 std::vector<std::string> scopes;
313 scopes.push_back(kCWSScope);
315 ProfileOAuth2TokenService* oauth_service =
316 ProfileOAuth2TokenServiceFactory::GetForProfile(GetProfile());
317 net::URLRequestContextGetter* url_request_context_getter =
318 g_browser_process->system_request_context();
320 if (!oauth_service) {
321 drive::EventLogger* logger = file_manager::util::GetLogger(GetProfile());
323 logger->Log(logging::LOG_ERROR,
324 "CWS OAuth token fetch failed. OAuth2TokenService can't "
327 SetResult(base::Value::CreateNullValue());
331 SigninManagerBase* signin_manager =
332 SigninManagerFactory::GetForProfile(GetProfile());
333 auth_service_.reset(new google_apis::AuthService(
335 signin_manager->GetAuthenticatedAccountId(),
336 url_request_context_getter,
338 auth_service_->StartAuthentication(base::Bind(
339 &FileBrowserPrivateRequestWebStoreAccessTokenFunction::
340 OnAccessTokenFetched,
346 void FileBrowserPrivateRequestWebStoreAccessTokenFunction::OnAccessTokenFetched(
347 google_apis::GDataErrorCode code,
348 const std::string& access_token) {
349 drive::EventLogger* logger = file_manager::util::GetLogger(GetProfile());
351 if (code == google_apis::HTTP_SUCCESS) {
352 DCHECK(auth_service_->HasAccessToken());
353 DCHECK(access_token == auth_service_->access_token());
355 logger->Log(logging::LOG_INFO, "CWS OAuth token fetch succeeded.");
356 SetResult(new base::StringValue(access_token));
360 logger->Log(logging::LOG_ERROR,
361 "CWS OAuth token fetch failed. (GDataErrorCode: %s)",
362 google_apis::GDataErrorCodeToString(code).c_str());
364 SetResult(base::Value::CreateNullValue());
369 bool FileBrowserPrivateGetProfilesFunction::RunSync() {
370 const std::vector<linked_ptr<api::file_browser_private::ProfileInfo> >&
371 profiles = GetLoggedInProfileInfoList();
373 // Obtains the display profile ID.
374 apps::AppWindow* const app_window = GetCurrentAppWindow(this);
375 chrome::MultiUserWindowManager* const window_manager =
376 chrome::MultiUserWindowManager::GetInstance();
377 const std::string current_profile_id =
378 multi_user_util::GetUserIDFromProfile(GetProfile());
379 const std::string display_profile_id =
380 window_manager && app_window ? window_manager->GetUserPresentingWindow(
381 app_window->GetNativeWindow())
384 results_ = api::file_browser_private::GetProfiles::Results::Create(
387 display_profile_id.empty() ? current_profile_id : display_profile_id);
391 bool FileBrowserPrivateVisitDesktopFunction::RunSync() {
392 using api::file_browser_private::VisitDesktop::Params;
393 const scoped_ptr<Params> params(Params::Create(*args_));
394 const std::vector<linked_ptr<api::file_browser_private::ProfileInfo> >&
395 profiles = GetLoggedInProfileInfoList();
397 chrome::MultiUserWindowManager* const window_manager =
398 chrome::MultiUserWindowManager::GetInstance();
399 DCHECK(window_manager);
401 // Check if the target user is logged-in or not.
402 bool logged_in = false;
403 for (size_t i = 0; i < profiles.size(); ++i) {
404 if (profiles[i]->profile_id == params->profile_id) {
410 SetError("The user is not logged-in now.");
414 // Look for the current app window.
415 apps::AppWindow* const app_window = GetCurrentAppWindow(this);
417 SetError("Target window is not found.");
421 // Observe owner changes of windows.
422 file_manager::EventRouter* const event_router =
423 file_manager::FileBrowserPrivateAPI::Get(GetProfile())->event_router();
424 event_router->RegisterMultiUserWindowManagerObserver();
426 // Move the window to the user's desktop.
427 window_manager->ShowWindowForUser(app_window->GetNativeWindow(),
431 if (!window_manager->IsWindowOnDesktopOfUser(app_window->GetNativeWindow(),
432 params->profile_id)) {
433 SetError("The window cannot visit the desktop.");
440 bool FileBrowserPrivateOpenInspectorFunction::RunSync() {
441 using extensions::api::file_browser_private::OpenInspector::Params;
442 const scoped_ptr<Params> params(Params::Create(*args_));
443 EXTENSION_FUNCTION_VALIDATE(params);
445 switch (params->type) {
446 case extensions::api::file_browser_private::INSPECTION_TYPE_NORMAL:
447 // Open inspector for foreground page.
448 DevToolsWindow::OpenDevToolsWindow(
449 content::WebContents::FromRenderViewHost(render_view_host()));
451 case extensions::api::file_browser_private::INSPECTION_TYPE_CONSOLE:
452 // Open inspector for foreground page and bring focus to the console.
453 DevToolsWindow::OpenDevToolsWindow(
454 content::WebContents::FromRenderViewHost(render_view_host()),
455 DevToolsToggleAction::ShowConsole());
457 case extensions::api::file_browser_private::INSPECTION_TYPE_ELEMENT:
458 // Open inspector for foreground page in inspect element mode.
459 DevToolsWindow::OpenDevToolsWindow(
460 content::WebContents::FromRenderViewHost(render_view_host()),
461 DevToolsToggleAction::Inspect());
463 case extensions::api::file_browser_private::INSPECTION_TYPE_BACKGROUND:
464 // Open inspector for background page.
465 extensions::devtools_util::InspectBackgroundPage(extension(),
471 base::StringPrintf("Unexpected inspection type(%d) is specified.",
472 static_cast<int>(params->type)));
478 } // namespace extensions