private_api_misc.cc revision a02191e04bc25c4935f804f2c080ae28663d096d
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. 4 5#include "chrome/browser/chromeos/extensions/file_manager/private_api_misc.h" 6 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/utf_string_conversions.h" 13#include "chrome/browser/browser_process.h" 14#include "chrome/browser/chromeos/drive/file_system_util.h" 15#include "chrome/browser/chromeos/extensions/file_manager/event_router.h" 16#include "chrome/browser/chromeos/extensions/file_manager/file_browser_private_api.h" 17#include "chrome/browser/chromeos/extensions/file_manager/private_api_util.h" 18#include "chrome/browser/chromeos/file_manager/app_installer.h" 19#include "chrome/browser/chromeos/login/user_manager.h" 20#include "chrome/browser/chromeos/settings/cros_settings.h" 21#include "chrome/browser/drive/event_logger.h" 22#include "chrome/browser/lifetime/application_lifetime.h" 23#include "chrome/browser/profiles/profile.h" 24#include "chrome/browser/profiles/profile_manager.h" 25#include "chrome/browser/profiles/profiles_state.h" 26#include "chrome/browser/signin/profile_oauth2_token_service_factory.h" 27#include "chrome/browser/signin/signin_manager_factory.h" 28#include "chrome/browser/ui/ash/multi_user/multi_user_util.h" 29#include "chrome/browser/ui/ash/multi_user/multi_user_window_manager.h" 30#include "chrome/common/extensions/api/file_browser_private.h" 31#include "chrome/common/pref_names.h" 32#include "components/signin/core/browser/profile_oauth2_token_service.h" 33#include "components/signin/core/browser/signin_manager.h" 34#include "content/public/browser/render_view_host.h" 35#include "content/public/browser/web_contents.h" 36#include "content/public/common/page_zoom.h" 37#include "google_apis/drive/auth_service.h" 38#include "ui/base/webui/web_ui_util.h" 39#include "url/gurl.h" 40 41namespace extensions { 42 43namespace { 44const char kCWSScope[] = "https://www.googleapis.com/auth/chromewebstore"; 45 46// Obtains the current app window. 47apps::AppWindow* GetCurrentAppWindow(ChromeSyncExtensionFunction* function) { 48 apps::AppWindowRegistry* const app_window_registry = 49 apps::AppWindowRegistry::Get(function->GetProfile()); 50 content::WebContents* const contents = function->GetAssociatedWebContents(); 51 content::RenderViewHost* const render_view_host = 52 contents ? contents->GetRenderViewHost() : NULL; 53 return render_view_host ? app_window_registry->GetAppWindowForRenderViewHost( 54 render_view_host) 55 : NULL; 56} 57 58std::vector<linked_ptr<api::file_browser_private::ProfileInfo> > 59GetLoggedInProfileInfoList(content::WebContents* contents) { 60 DCHECK(chromeos::UserManager::IsInitialized()); 61 const std::vector<Profile*>& profiles = 62 g_browser_process->profile_manager()->GetLoadedProfiles(); 63 std::set<Profile*> original_profiles; 64 std::vector<linked_ptr<api::file_browser_private::ProfileInfo> > 65 result_profiles; 66 67 for (size_t i = 0; i < profiles.size(); ++i) { 68 // Filter the profile. 69 Profile* const profile = profiles[i]->GetOriginalProfile(); 70 if (original_profiles.count(profile)) 71 continue; 72 original_profiles.insert(profile); 73 const chromeos::User* const user = 74 chromeos::UserManager::Get()->GetUserByProfile(profile); 75 if (!user || !user->is_logged_in()) 76 continue; 77 78 // Make a ProfileInfo. 79 linked_ptr<api::file_browser_private::ProfileInfo> profile_info( 80 new api::file_browser_private::ProfileInfo()); 81 profile_info->profile_id = multi_user_util::GetUserIDFromProfile(profile); 82 profile_info->display_name = UTF16ToUTF8(user->GetDisplayName()); 83 // TODO(hirono): Remove the property from the profile_info. 84 profile_info->is_current_profile = true; 85 86 // Make an icon URL of the profile. 87 if (contents) { 88 const gfx::Image& image = 89 ash::GetAvatarImageForContext(contents->GetBrowserContext()); 90 const gfx::ImageSkia& skia = image.AsImageSkia(); 91 profile_info->profile_image.reset( 92 new api::file_browser_private::ImageSet); 93 profile_info->profile_image->scale1x_url = 94 webui::GetBitmapDataUrl(skia.GetRepresentation(1.0f).sk_bitmap()); 95 profile_info->profile_image->scale2x_url = 96 webui::GetBitmapDataUrl(skia.GetRepresentation(2.0f).sk_bitmap()); 97 } 98 result_profiles.push_back(profile_info); 99 } 100 101 return result_profiles; 102} 103} // namespace 104 105bool FileBrowserPrivateLogoutUserForReauthenticationFunction::RunImpl() { 106 chromeos::User* user = 107 chromeos::UserManager::Get()->GetUserByProfile(GetProfile()); 108 if (user) { 109 chromeos::UserManager::Get()->SaveUserOAuthStatus( 110 user->email(), 111 chromeos::User::OAUTH2_TOKEN_STATUS_INVALID); 112 } 113 114 chrome::AttemptUserExit(); 115 return true; 116} 117 118bool FileBrowserPrivateGetPreferencesFunction::RunImpl() { 119 api::file_browser_private::Preferences result; 120 const PrefService* const service = GetProfile()->GetPrefs(); 121 122 result.drive_enabled = drive::util::IsDriveEnabledForProfile(GetProfile()); 123 result.cellular_disabled = 124 service->GetBoolean(prefs::kDisableDriveOverCellular); 125 result.hosted_files_disabled = 126 service->GetBoolean(prefs::kDisableDriveHostedFiles); 127 result.use24hour_clock = service->GetBoolean(prefs::kUse24HourClock); 128 result.allow_redeem_offers = true; 129 if (!chromeos::CrosSettings::Get()->GetBoolean( 130 chromeos::kAllowRedeemChromeOsRegistrationOffers, 131 &result.allow_redeem_offers)) { 132 result.allow_redeem_offers = true; 133 } 134 135 SetResult(result.ToValue().release()); 136 137 drive::EventLogger* logger = file_manager::util::GetLogger(GetProfile()); 138 if (logger) 139 logger->Log(logging::LOG_INFO, "%s succeeded.", name().c_str()); 140 return true; 141} 142 143bool FileBrowserPrivateSetPreferencesFunction::RunImpl() { 144 using extensions::api::file_browser_private::SetPreferences::Params; 145 const scoped_ptr<Params> params(Params::Create(*args_)); 146 EXTENSION_FUNCTION_VALIDATE(params); 147 148 PrefService* const service = GetProfile()->GetPrefs(); 149 150 if (params->change_info.cellular_disabled) 151 service->SetBoolean(prefs::kDisableDriveOverCellular, 152 *params->change_info.cellular_disabled); 153 154 if (params->change_info.hosted_files_disabled) 155 service->SetBoolean(prefs::kDisableDriveHostedFiles, 156 *params->change_info.hosted_files_disabled); 157 158 drive::EventLogger* logger = file_manager::util::GetLogger(GetProfile()); 159 if (logger) 160 logger->Log(logging::LOG_INFO, "%s succeeded.", name().c_str()); 161 return true; 162} 163 164FileBrowserPrivateZipSelectionFunction:: 165 FileBrowserPrivateZipSelectionFunction() {} 166 167FileBrowserPrivateZipSelectionFunction:: 168 ~FileBrowserPrivateZipSelectionFunction() {} 169 170bool FileBrowserPrivateZipSelectionFunction::RunImpl() { 171 using extensions::api::file_browser_private::ZipSelection::Params; 172 const scoped_ptr<Params> params(Params::Create(*args_)); 173 EXTENSION_FUNCTION_VALIDATE(params); 174 175 // First param is the source directory URL. 176 if (params->dir_url.empty()) 177 return false; 178 179 base::FilePath src_dir = file_manager::util::GetLocalPathFromURL( 180 render_view_host(), GetProfile(), GURL(params->dir_url)); 181 if (src_dir.empty()) 182 return false; 183 184 // Second param is the list of selected file URLs. 185 if (params->selection_urls.empty()) 186 return false; 187 188 std::vector<base::FilePath> files; 189 for (size_t i = 0; i < params->selection_urls.size(); ++i) { 190 base::FilePath path = file_manager::util::GetLocalPathFromURL( 191 render_view_host(), GetProfile(), GURL(params->selection_urls[i])); 192 if (path.empty()) 193 return false; 194 files.push_back(path); 195 } 196 197 // Third param is the name of the output zip file. 198 if (params->dest_name.empty()) 199 return false; 200 201 // Check if the dir path is under Drive mount point. 202 // TODO(hshi): support create zip file on Drive (crbug.com/158690). 203 if (drive::util::IsUnderDriveMountPoint(src_dir)) 204 return false; 205 206 base::FilePath dest_file = src_dir.Append(params->dest_name); 207 std::vector<base::FilePath> src_relative_paths; 208 for (size_t i = 0; i != files.size(); ++i) { 209 const base::FilePath& file_path = files[i]; 210 211 // Obtain the relative path of |file_path| under |src_dir|. 212 base::FilePath relative_path; 213 if (!src_dir.AppendRelativePath(file_path, &relative_path)) 214 return false; 215 src_relative_paths.push_back(relative_path); 216 } 217 218 zip_file_creator_ = new file_manager::ZipFileCreator(this, 219 src_dir, 220 src_relative_paths, 221 dest_file); 222 223 // Keep the refcount until the zipping is complete on utility process. 224 AddRef(); 225 226 zip_file_creator_->Start(); 227 return true; 228} 229 230void FileBrowserPrivateZipSelectionFunction::OnZipDone(bool success) { 231 SetResult(new base::FundamentalValue(success)); 232 SendResponse(true); 233 Release(); 234} 235 236bool FileBrowserPrivateZoomFunction::RunImpl() { 237 using extensions::api::file_browser_private::Zoom::Params; 238 const scoped_ptr<Params> params(Params::Create(*args_)); 239 EXTENSION_FUNCTION_VALIDATE(params); 240 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; 245 break; 246 case api::file_browser_private::ZOOM_OPERATION_TYPE_OUT: 247 zoom_type = content::PAGE_ZOOM_OUT; 248 break; 249 case api::file_browser_private::ZOOM_OPERATION_TYPE_RESET: 250 zoom_type = content::PAGE_ZOOM_RESET; 251 break; 252 default: 253 NOTREACHED(); 254 return false; 255 } 256 render_view_host()->Zoom(zoom_type); 257 return true; 258} 259 260bool FileBrowserPrivateInstallWebstoreItemFunction::RunImpl() { 261 using extensions::api::file_browser_private::InstallWebstoreItem::Params; 262 const scoped_ptr<Params> params(Params::Create(*args_)); 263 EXTENSION_FUNCTION_VALIDATE(params); 264 265 if (params->item_id.empty()) 266 return false; 267 268 const extensions::WebstoreStandaloneInstaller::Callback callback = 269 base::Bind( 270 &FileBrowserPrivateInstallWebstoreItemFunction::OnInstallComplete, 271 this); 272 273 scoped_refptr<file_manager::AppInstaller> installer( 274 new file_manager::AppInstaller( 275 GetAssociatedWebContents(), 276 params->item_id, 277 GetProfile(), 278 callback)); 279 // installer will be AddRef()'d in BeginInstall(). 280 installer->BeginInstall(); 281 return true; 282} 283 284void FileBrowserPrivateInstallWebstoreItemFunction::OnInstallComplete( 285 bool success, 286 const std::string& error) { 287 drive::EventLogger* logger = file_manager::util::GetLogger(GetProfile()); 288 if (success) { 289 if (logger) { 290 logger->Log(logging::LOG_INFO, 291 "App install succeeded. (item id: %s)", 292 webstore_item_id_.c_str()); 293 } 294 } else { 295 if (logger) { 296 logger->Log(logging::LOG_ERROR, 297 "App install failed. (item id: %s, reason: %s)", 298 webstore_item_id_.c_str(), 299 error.c_str()); 300 } 301 SetError(error); 302 } 303 304 SendResponse(success); 305} 306 307FileBrowserPrivateRequestWebStoreAccessTokenFunction:: 308 FileBrowserPrivateRequestWebStoreAccessTokenFunction() { 309} 310 311FileBrowserPrivateRequestWebStoreAccessTokenFunction:: 312 ~FileBrowserPrivateRequestWebStoreAccessTokenFunction() { 313} 314 315bool FileBrowserPrivateRequestWebStoreAccessTokenFunction::RunImpl() { 316 std::vector<std::string> scopes; 317 scopes.push_back(kCWSScope); 318 319 ProfileOAuth2TokenService* oauth_service = 320 ProfileOAuth2TokenServiceFactory::GetForProfile(GetProfile()); 321 net::URLRequestContextGetter* url_request_context_getter = 322 g_browser_process->system_request_context(); 323 324 if (!oauth_service) { 325 drive::EventLogger* logger = file_manager::util::GetLogger(GetProfile()); 326 if (logger) { 327 logger->Log(logging::LOG_ERROR, 328 "CWS OAuth token fetch failed. OAuth2TokenService can't " 329 "be retrieved."); 330 } 331 SetResult(base::Value::CreateNullValue()); 332 return false; 333 } 334 335 SigninManagerBase* signin_manager = 336 SigninManagerFactory::GetForProfile(GetProfile()); 337 auth_service_.reset(new google_apis::AuthService( 338 oauth_service, 339 signin_manager->GetAuthenticatedAccountId(), 340 url_request_context_getter, 341 scopes)); 342 auth_service_->StartAuthentication(base::Bind( 343 &FileBrowserPrivateRequestWebStoreAccessTokenFunction:: 344 OnAccessTokenFetched, 345 this)); 346 347 return true; 348} 349 350void FileBrowserPrivateRequestWebStoreAccessTokenFunction::OnAccessTokenFetched( 351 google_apis::GDataErrorCode code, 352 const std::string& access_token) { 353 drive::EventLogger* logger = file_manager::util::GetLogger(GetProfile()); 354 355 if (code == google_apis::HTTP_SUCCESS) { 356 DCHECK(auth_service_->HasAccessToken()); 357 DCHECK(access_token == auth_service_->access_token()); 358 if (logger) 359 logger->Log(logging::LOG_INFO, "CWS OAuth token fetch succeeded."); 360 SetResult(new base::StringValue(access_token)); 361 SendResponse(true); 362 } else { 363 if (logger) { 364 logger->Log(logging::LOG_ERROR, 365 "CWS OAuth token fetch failed. (GDataErrorCode: %s)", 366 google_apis::GDataErrorCodeToString(code).c_str()); 367 } 368 SetResult(base::Value::CreateNullValue()); 369 SendResponse(false); 370 } 371} 372 373bool FileBrowserPrivateGetProfilesFunction::RunImpl() { 374 const std::vector<linked_ptr<api::file_browser_private::ProfileInfo> >& 375 profiles = GetLoggedInProfileInfoList(GetAssociatedWebContents()); 376 377 // Obtains the display profile ID. 378 apps::AppWindow* const app_window = GetCurrentAppWindow(this); 379 chrome::MultiUserWindowManager* const window_manager = 380 chrome::MultiUserWindowManager::GetInstance(); 381 const std::string current_profile_id = 382 multi_user_util::GetUserIDFromProfile(GetProfile()); 383 const std::string display_profile_id = 384 window_manager && app_window ? window_manager->GetUserPresentingWindow( 385 app_window->GetNativeWindow()) 386 : ""; 387 388 results_ = api::file_browser_private::GetProfiles::Results::Create( 389 profiles, 390 current_profile_id, 391 display_profile_id.empty() ? current_profile_id : display_profile_id); 392 return true; 393} 394 395bool FileBrowserPrivateVisitDesktopFunction::RunImpl() { 396 using api::file_browser_private::VisitDesktop::Params; 397 const scoped_ptr<Params> params(Params::Create(*args_)); 398 const std::vector<linked_ptr<api::file_browser_private::ProfileInfo> >& 399 profiles = GetLoggedInProfileInfoList(GetAssociatedWebContents()); 400 401 // Check the multi-profile support. 402 if (!profiles::IsMultipleProfilesEnabled()) { 403 SetError("Multi-profile support is not enabled."); 404 return false; 405 } 406 407 chrome::MultiUserWindowManager* const window_manager = 408 chrome::MultiUserWindowManager::GetInstance(); 409 DCHECK(window_manager); 410 411 // Check if the target user is logged-in or not. 412 bool logged_in = false; 413 for (size_t i = 0; i < profiles.size(); ++i) { 414 if (profiles[i]->profile_id == params->profile_id) { 415 logged_in = true; 416 break; 417 } 418 } 419 if (!logged_in) { 420 SetError("The user is not logged-in now."); 421 return false; 422 } 423 424 // Look for the current app window. 425 apps::AppWindow* const app_window = GetCurrentAppWindow(this); 426 if (!app_window) { 427 SetError("Target window is not found."); 428 return false; 429 } 430 431 // Observe owner changes of windows. 432 file_manager::EventRouter* const event_router = 433 file_manager::FileBrowserPrivateAPI::Get(GetProfile())->event_router(); 434 event_router->RegisterMultiUserWindowManagerObserver(); 435 436 // Move the window to the user's desktop. 437 window_manager->ShowWindowForUser(app_window->GetNativeWindow(), 438 params->profile_id); 439 440 // Check the result. 441 if (!window_manager->IsWindowOnDesktopOfUser(app_window->GetNativeWindow(), 442 params->profile_id)) { 443 SetError("The window cannot visit the desktop."); 444 return false; 445 } 446 447 return true; 448} 449 450} // namespace extensions 451