Home | History | Annotate | Download | only in file_manager
      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 "ash/frame/frame_util.h"
      8 #include "base/files/file_path.h"
      9 #include "base/prefs/pref_service.h"
     10 #include "base/strings/stringprintf.h"
     11 #include "base/strings/utf_string_conversions.h"
     12 #include "chrome/browser/browser_process.h"
     13 #include "chrome/browser/chromeos/drive/file_system_util.h"
     14 #include "chrome/browser/chromeos/extensions/file_manager/private_api_util.h"
     15 #include "chrome/browser/chromeos/file_manager/app_installer.h"
     16 #include "chrome/browser/chromeos/file_manager/zip_file_creator.h"
     17 #include "chrome/browser/chromeos/profiles/profile_helper.h"
     18 #include "chrome/browser/chromeos/settings/cros_settings.h"
     19 #include "chrome/browser/devtools/devtools_window.h"
     20 #include "chrome/browser/drive/event_logger.h"
     21 #include "chrome/browser/extensions/devtools_util.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_manager_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 "components/user_manager/user_manager.h"
     35 #include "content/public/browser/render_view_host.h"
     36 #include "content/public/browser/web_contents.h"
     37 #include "content/public/common/page_zoom.h"
     38 #include "extensions/browser/app_window/app_window.h"
     39 #include "extensions/browser/app_window/app_window_registry.h"
     40 #include "google_apis/drive/auth_service.h"
     41 #include "ui/base/webui/web_ui_util.h"
     42 #include "url/gurl.h"
     43 
     44 namespace extensions {
     45 
     46 namespace {
     47 const char kCWSScope[] = "https://www.googleapis.com/auth/chromewebstore";
     48 const char kGoogleCastApiExtensionId[] = "mafeflapfdfljijmlienjedomfjfmhpd";
     49 
     50 // Obtains the current app window.
     51 AppWindow* GetCurrentAppWindow(ChromeSyncExtensionFunction* function) {
     52   AppWindowRegistry* const app_window_registry =
     53       AppWindowRegistry::Get(function->GetProfile());
     54   content::WebContents* const contents = function->GetAssociatedWebContents();
     55   content::RenderViewHost* const render_view_host =
     56       contents ? contents->GetRenderViewHost() : NULL;
     57   return render_view_host ? app_window_registry->GetAppWindowForRenderViewHost(
     58                                 render_view_host)
     59                           : NULL;
     60 }
     61 
     62 std::vector<linked_ptr<api::file_manager_private::ProfileInfo> >
     63 GetLoggedInProfileInfoList() {
     64   DCHECK(user_manager::UserManager::IsInitialized());
     65   const std::vector<Profile*>& profiles =
     66       g_browser_process->profile_manager()->GetLoadedProfiles();
     67   std::set<Profile*> original_profiles;
     68   std::vector<linked_ptr<api::file_manager_private::ProfileInfo> >
     69       result_profiles;
     70 
     71   for (size_t i = 0; i < profiles.size(); ++i) {
     72     // Filter the profile.
     73     Profile* const profile = profiles[i]->GetOriginalProfile();
     74     if (original_profiles.count(profile))
     75       continue;
     76     original_profiles.insert(profile);
     77     const user_manager::User* const user =
     78         chromeos::ProfileHelper::Get()->GetUserByProfile(profile);
     79     if (!user || !user->is_logged_in())
     80       continue;
     81 
     82     // Make a ProfileInfo.
     83     linked_ptr<api::file_manager_private::ProfileInfo> profile_info(
     84         new api::file_manager_private::ProfileInfo());
     85     profile_info->profile_id = multi_user_util::GetUserIDFromProfile(profile);
     86     profile_info->display_name = UTF16ToUTF8(user->GetDisplayName());
     87     // TODO(hirono): Remove the property from the profile_info.
     88     profile_info->is_current_profile = true;
     89 
     90     result_profiles.push_back(profile_info);
     91   }
     92 
     93   return result_profiles;
     94 }
     95 } // namespace
     96 
     97 bool FileManagerPrivateLogoutUserForReauthenticationFunction::RunSync() {
     98   user_manager::User* user =
     99       chromeos::ProfileHelper::Get()->GetUserByProfile(GetProfile());
    100   if (user) {
    101     user_manager::UserManager::Get()->SaveUserOAuthStatus(
    102         user->email(), user_manager::User::OAUTH2_TOKEN_STATUS_INVALID);
    103   }
    104 
    105   chrome::AttemptUserExit();
    106   return true;
    107 }
    108 
    109 bool FileManagerPrivateGetPreferencesFunction::RunSync() {
    110   api::file_manager_private::Preferences result;
    111   const PrefService* const service = GetProfile()->GetPrefs();
    112 
    113   result.drive_enabled = drive::util::IsDriveEnabledForProfile(GetProfile());
    114   result.cellular_disabled =
    115       service->GetBoolean(prefs::kDisableDriveOverCellular);
    116   result.hosted_files_disabled =
    117       service->GetBoolean(prefs::kDisableDriveHostedFiles);
    118   result.use24hour_clock = service->GetBoolean(prefs::kUse24HourClock);
    119   result.allow_redeem_offers = true;
    120   if (!chromeos::CrosSettings::Get()->GetBoolean(
    121           chromeos::kAllowRedeemChromeOsRegistrationOffers,
    122           &result.allow_redeem_offers)) {
    123     result.allow_redeem_offers = true;
    124   }
    125 
    126   SetResult(result.ToValue().release());
    127 
    128   drive::EventLogger* logger = file_manager::util::GetLogger(GetProfile());
    129   if (logger)
    130     logger->Log(logging::LOG_INFO, "%s succeeded.", name().c_str());
    131   return true;
    132 }
    133 
    134 bool FileManagerPrivateSetPreferencesFunction::RunSync() {
    135   using extensions::api::file_manager_private::SetPreferences::Params;
    136   const scoped_ptr<Params> params(Params::Create(*args_));
    137   EXTENSION_FUNCTION_VALIDATE(params);
    138 
    139   PrefService* const service = GetProfile()->GetPrefs();
    140 
    141   if (params->change_info.cellular_disabled)
    142     service->SetBoolean(prefs::kDisableDriveOverCellular,
    143                         *params->change_info.cellular_disabled);
    144 
    145   if (params->change_info.hosted_files_disabled)
    146     service->SetBoolean(prefs::kDisableDriveHostedFiles,
    147                         *params->change_info.hosted_files_disabled);
    148 
    149   drive::EventLogger* logger = file_manager::util::GetLogger(GetProfile());
    150   if (logger)
    151     logger->Log(logging::LOG_INFO, "%s succeeded.", name().c_str());
    152   return true;
    153 }
    154 
    155 FileManagerPrivateZipSelectionFunction::
    156     FileManagerPrivateZipSelectionFunction() {}
    157 
    158 FileManagerPrivateZipSelectionFunction::
    159     ~FileManagerPrivateZipSelectionFunction() {}
    160 
    161 bool FileManagerPrivateZipSelectionFunction::RunAsync() {
    162   using extensions::api::file_manager_private::ZipSelection::Params;
    163   const scoped_ptr<Params> params(Params::Create(*args_));
    164   EXTENSION_FUNCTION_VALIDATE(params);
    165 
    166   // First param is the source directory URL.
    167   if (params->dir_url.empty())
    168     return false;
    169 
    170   base::FilePath src_dir = file_manager::util::GetLocalPathFromURL(
    171       render_view_host(), GetProfile(), GURL(params->dir_url));
    172   if (src_dir.empty())
    173     return false;
    174 
    175   // Second param is the list of selected file URLs.
    176   if (params->selection_urls.empty())
    177     return false;
    178 
    179   std::vector<base::FilePath> files;
    180   for (size_t i = 0; i < params->selection_urls.size(); ++i) {
    181     base::FilePath path = file_manager::util::GetLocalPathFromURL(
    182         render_view_host(), GetProfile(), GURL(params->selection_urls[i]));
    183     if (path.empty())
    184       return false;
    185     files.push_back(path);
    186   }
    187 
    188   // Third param is the name of the output zip file.
    189   if (params->dest_name.empty())
    190     return false;
    191 
    192   // Check if the dir path is under Drive mount point.
    193   // TODO(hshi): support create zip file on Drive (crbug.com/158690).
    194   if (drive::util::IsUnderDriveMountPoint(src_dir))
    195     return false;
    196 
    197   base::FilePath dest_file = src_dir.Append(params->dest_name);
    198   std::vector<base::FilePath> src_relative_paths;
    199   for (size_t i = 0; i != files.size(); ++i) {
    200     const base::FilePath& file_path = files[i];
    201 
    202     // Obtain the relative path of |file_path| under |src_dir|.
    203     base::FilePath relative_path;
    204     if (!src_dir.AppendRelativePath(file_path, &relative_path))
    205       return false;
    206     src_relative_paths.push_back(relative_path);
    207   }
    208 
    209   (new file_manager::ZipFileCreator(
    210        base::Bind(&FileManagerPrivateZipSelectionFunction::OnZipDone, this),
    211        src_dir,
    212        src_relative_paths,
    213        dest_file))->Start();
    214   return true;
    215 }
    216 
    217 void FileManagerPrivateZipSelectionFunction::OnZipDone(bool success) {
    218   SetResult(new base::FundamentalValue(success));
    219   SendResponse(true);
    220 }
    221 
    222 bool FileManagerPrivateZoomFunction::RunSync() {
    223   using extensions::api::file_manager_private::Zoom::Params;
    224   const scoped_ptr<Params> params(Params::Create(*args_));
    225   EXTENSION_FUNCTION_VALIDATE(params);
    226 
    227   content::PageZoom zoom_type;
    228   switch (params->operation) {
    229     case api::file_manager_private::ZOOM_OPERATION_TYPE_IN:
    230       zoom_type = content::PAGE_ZOOM_IN;
    231       break;
    232     case api::file_manager_private::ZOOM_OPERATION_TYPE_OUT:
    233       zoom_type = content::PAGE_ZOOM_OUT;
    234       break;
    235     case api::file_manager_private::ZOOM_OPERATION_TYPE_RESET:
    236       zoom_type = content::PAGE_ZOOM_RESET;
    237       break;
    238     default:
    239       NOTREACHED();
    240       return false;
    241   }
    242   render_view_host()->Zoom(zoom_type);
    243   return true;
    244 }
    245 
    246 bool FileManagerPrivateInstallWebstoreItemFunction::RunAsync() {
    247   using extensions::api::file_manager_private::InstallWebstoreItem::Params;
    248   const scoped_ptr<Params> params(Params::Create(*args_));
    249   EXTENSION_FUNCTION_VALIDATE(params);
    250 
    251   if (params->item_id.empty())
    252     return false;
    253 
    254   const extensions::WebstoreStandaloneInstaller::Callback callback =
    255       base::Bind(
    256           &FileManagerPrivateInstallWebstoreItemFunction::OnInstallComplete,
    257           this);
    258 
    259   // Only GoogleCastAPI extension can use silent installation.
    260   if (params->silent_installation &&
    261       params->item_id != kGoogleCastApiExtensionId) {
    262     SetError("Only whitelisted items can do silent installation.");
    263     return false;
    264   }
    265 
    266   scoped_refptr<file_manager::AppInstaller> installer(
    267       new file_manager::AppInstaller(GetAssociatedWebContents(),
    268                                      params->item_id,
    269                                      GetProfile(),
    270                                      params->silent_installation,
    271                                      callback));
    272   // installer will be AddRef()'d in BeginInstall().
    273   installer->BeginInstall();
    274   return true;
    275 }
    276 
    277 void FileManagerPrivateInstallWebstoreItemFunction::OnInstallComplete(
    278     bool success,
    279     const std::string& error,
    280     extensions::webstore_install::Result result) {
    281   drive::EventLogger* logger = file_manager::util::GetLogger(GetProfile());
    282   if (success) {
    283     if (logger) {
    284       logger->Log(logging::LOG_INFO,
    285                   "App install succeeded. (item id: %s)",
    286                   webstore_item_id_.c_str());
    287     }
    288   } else {
    289     if (logger) {
    290       logger->Log(logging::LOG_ERROR,
    291                   "App install failed. (item id: %s, reason: %s)",
    292                   webstore_item_id_.c_str(),
    293                   error.c_str());
    294     }
    295     SetError(error);
    296   }
    297 
    298   SendResponse(success);
    299 }
    300 
    301 FileManagerPrivateRequestWebStoreAccessTokenFunction::
    302     FileManagerPrivateRequestWebStoreAccessTokenFunction() {
    303 }
    304 
    305 FileManagerPrivateRequestWebStoreAccessTokenFunction::
    306     ~FileManagerPrivateRequestWebStoreAccessTokenFunction() {
    307 }
    308 
    309 bool FileManagerPrivateRequestWebStoreAccessTokenFunction::RunAsync() {
    310   std::vector<std::string> scopes;
    311   scopes.push_back(kCWSScope);
    312 
    313   ProfileOAuth2TokenService* oauth_service =
    314       ProfileOAuth2TokenServiceFactory::GetForProfile(GetProfile());
    315   net::URLRequestContextGetter* url_request_context_getter =
    316       g_browser_process->system_request_context();
    317 
    318   if (!oauth_service) {
    319     drive::EventLogger* logger = file_manager::util::GetLogger(GetProfile());
    320     if (logger) {
    321       logger->Log(logging::LOG_ERROR,
    322                   "CWS OAuth token fetch failed. OAuth2TokenService can't "
    323                   "be retrieved.");
    324     }
    325     SetResult(base::Value::CreateNullValue());
    326     return false;
    327   }
    328 
    329   SigninManagerBase* signin_manager =
    330       SigninManagerFactory::GetForProfile(GetProfile());
    331   auth_service_.reset(new google_apis::AuthService(
    332       oauth_service,
    333       signin_manager->GetAuthenticatedAccountId(),
    334       url_request_context_getter,
    335       scopes));
    336   auth_service_->StartAuthentication(base::Bind(
    337       &FileManagerPrivateRequestWebStoreAccessTokenFunction::
    338           OnAccessTokenFetched,
    339       this));
    340 
    341   return true;
    342 }
    343 
    344 void FileManagerPrivateRequestWebStoreAccessTokenFunction::OnAccessTokenFetched(
    345     google_apis::GDataErrorCode code,
    346     const std::string& access_token) {
    347   drive::EventLogger* logger = file_manager::util::GetLogger(GetProfile());
    348 
    349   if (code == google_apis::HTTP_SUCCESS) {
    350     DCHECK(auth_service_->HasAccessToken());
    351     DCHECK(access_token == auth_service_->access_token());
    352     if (logger)
    353       logger->Log(logging::LOG_INFO, "CWS OAuth token fetch succeeded.");
    354     SetResult(new base::StringValue(access_token));
    355     SendResponse(true);
    356   } else {
    357     if (logger) {
    358       logger->Log(logging::LOG_ERROR,
    359                   "CWS OAuth token fetch failed. (GDataErrorCode: %s)",
    360                   google_apis::GDataErrorCodeToString(code).c_str());
    361     }
    362     SetResult(base::Value::CreateNullValue());
    363     SendResponse(false);
    364   }
    365 }
    366 
    367 bool FileManagerPrivateGetProfilesFunction::RunSync() {
    368 #if defined(USE_ATHENA)
    369   // TODO(oshima): Figure out what to do.
    370   return false;
    371 #endif
    372 
    373   const std::vector<linked_ptr<api::file_manager_private::ProfileInfo> >&
    374       profiles = GetLoggedInProfileInfoList();
    375 
    376   // Obtains the display profile ID.
    377   AppWindow* const app_window = GetCurrentAppWindow(this);
    378   chrome::MultiUserWindowManager* const window_manager =
    379       chrome::MultiUserWindowManager::GetInstance();
    380   const std::string current_profile_id =
    381       multi_user_util::GetUserIDFromProfile(GetProfile());
    382   const std::string display_profile_id =
    383       window_manager && app_window ? window_manager->GetUserPresentingWindow(
    384                                          app_window->GetNativeWindow())
    385                                    : "";
    386 
    387   results_ = api::file_manager_private::GetProfiles::Results::Create(
    388       profiles,
    389       current_profile_id,
    390       display_profile_id.empty() ? current_profile_id : display_profile_id);
    391   return true;
    392 }
    393 
    394 bool FileManagerPrivateVisitDesktopFunction::RunSync() {
    395   using api::file_manager_private::VisitDesktop::Params;
    396   const scoped_ptr<Params> params(Params::Create(*args_));
    397   const std::vector<linked_ptr<api::file_manager_private::ProfileInfo> >&
    398       profiles = GetLoggedInProfileInfoList();
    399 
    400   chrome::MultiUserWindowManager* const window_manager =
    401       chrome::MultiUserWindowManager::GetInstance();
    402   DCHECK(window_manager);
    403 
    404   // Check if the target user is logged-in or not.
    405   bool logged_in = false;
    406   for (size_t i = 0; i < profiles.size(); ++i) {
    407     if (profiles[i]->profile_id == params->profile_id) {
    408       logged_in = true;
    409       break;
    410     }
    411   }
    412   if (!logged_in) {
    413     SetError("The user is not logged-in now.");
    414     return false;
    415   }
    416 
    417   // Look for the current app window.
    418   AppWindow* const app_window = GetCurrentAppWindow(this);
    419   if (!app_window) {
    420     SetError("Target window is not found.");
    421     return false;
    422   }
    423 
    424   // Move the window to the user's desktop.
    425   window_manager->ShowWindowForUser(app_window->GetNativeWindow(),
    426                                     params->profile_id);
    427 
    428   // Check the result.
    429   if (!window_manager->IsWindowOnDesktopOfUser(app_window->GetNativeWindow(),
    430                                                params->profile_id)) {
    431     SetError("The window cannot visit the desktop.");
    432     return false;
    433   }
    434 
    435   return true;
    436 }
    437 
    438 bool FileManagerPrivateOpenInspectorFunction::RunSync() {
    439   using extensions::api::file_manager_private::OpenInspector::Params;
    440   const scoped_ptr<Params> params(Params::Create(*args_));
    441   EXTENSION_FUNCTION_VALIDATE(params);
    442 
    443   switch (params->type) {
    444     case extensions::api::file_manager_private::INSPECTION_TYPE_NORMAL:
    445       // Open inspector for foreground page.
    446       DevToolsWindow::OpenDevToolsWindow(
    447           content::WebContents::FromRenderViewHost(render_view_host()));
    448       break;
    449     case extensions::api::file_manager_private::INSPECTION_TYPE_CONSOLE:
    450       // Open inspector for foreground page and bring focus to the console.
    451       DevToolsWindow::OpenDevToolsWindow(
    452           content::WebContents::FromRenderViewHost(render_view_host()),
    453           DevToolsToggleAction::ShowConsole());
    454       break;
    455     case extensions::api::file_manager_private::INSPECTION_TYPE_ELEMENT:
    456       // Open inspector for foreground page in inspect element mode.
    457       DevToolsWindow::OpenDevToolsWindow(
    458           content::WebContents::FromRenderViewHost(render_view_host()),
    459           DevToolsToggleAction::Inspect());
    460       break;
    461     case extensions::api::file_manager_private::INSPECTION_TYPE_BACKGROUND:
    462       // Open inspector for background page.
    463       extensions::devtools_util::InspectBackgroundPage(extension(),
    464                                                        GetProfile());
    465       break;
    466     default:
    467       NOTREACHED();
    468       SetError(
    469           base::StringPrintf("Unexpected inspection type(%d) is specified.",
    470                              static_cast<int>(params->type)));
    471       return false;
    472   }
    473   return true;
    474 }
    475 
    476 }  // namespace extensions
    477