Chromium Code Reviews| Index: chrome/browser/extensions/api/file_system/chrome_file_system_delegate.cc |
| diff --git a/chrome/browser/extensions/api/file_system/file_system_api.cc b/chrome/browser/extensions/api/file_system/chrome_file_system_delegate.cc |
| similarity index 13% |
| copy from chrome/browser/extensions/api/file_system/file_system_api.cc |
| copy to chrome/browser/extensions/api/file_system/chrome_file_system_delegate.cc |
| index 8d5c628b3b36e0d2ba4dbdfb7cea602191b59580..6856fd88616e2628b32962298beddcbf09d811ae 100644 |
| --- a/chrome/browser/extensions/api/file_system/file_system_api.cc |
| +++ b/chrome/browser/extensions/api/file_system/chrome_file_system_delegate.cc |
| @@ -1,64 +1,46 @@ |
| -// Copyright (c) 2012 The Chromium Authors. All rights reserved. |
| +// Copyright 2017 The Chromium Authors. All rights reserved. |
| // Use of this source code is governed by a BSD-style license that can be |
| // found in the LICENSE file. |
| -#include "chrome/browser/extensions/api/file_system/file_system_api.h" |
| +#include "chrome/browser/extensions/api/file_system/chrome_file_system_delegate.h" |
| -#include <stddef.h> |
| - |
| -#include <memory> |
| -#include <set> |
| #include <utility> |
| #include <vector> |
| -#include "apps/saved_files_service.h" |
| +#include "apps/saved_files_service_delegate_impl.h" |
| #include "base/bind.h" |
| +#include "base/callback.h" |
| #include "base/files/file_path.h" |
| -#include "base/files/file_util.h" |
| -#include "base/macros.h" |
| +#include "base/logging.h" |
| #include "base/memory/ptr_util.h" |
| #include "base/path_service.h" |
| -#include "base/strings/string_util.h" |
| -#include "base/strings/stringprintf.h" |
| -#include "base/strings/sys_string_conversions.h" |
| -#include "base/strings/utf_string_conversions.h" |
| -#include "base/task_scheduler/post_task.h" |
| -#include "base/value_conversions.h" |
| -#include "base/values.h" |
| -#include "build/build_config.h" |
| +#include "base/strings/string16.h" |
| #include "chrome/browser/platform_util.h" |
| #include "chrome/browser/profiles/profile.h" |
| #include "chrome/browser/ui/apps/directory_access_confirmation_dialog.h" |
| #include "chrome/browser/ui/chrome_select_file_policy.h" |
| #include "chrome/common/chrome_paths.h" |
| -#include "chrome/common/extensions/api/file_system.h" |
| #include "chrome/grit/generated_resources.h" |
| -#include "content/public/browser/browser_thread.h" |
| +#include "content/public/browser/browser_context.h" |
| #include "content/public/browser/child_process_security_policy.h" |
| #include "content/public/browser/render_frame_host.h" |
| #include "content/public/browser/render_process_host.h" |
| #include "content/public/browser/storage_partition.h" |
| #include "content/public/browser/web_contents.h" |
| #include "extensions/browser/api/file_handlers/app_file_handler_util.h" |
| -#include "extensions/browser/app_window/app_window.h" |
| -#include "extensions/browser/app_window/app_window_registry.h" |
| +#include "extensions/browser/api/file_system/saved_files_service_delegate.h" |
| +#include "extensions/browser/extension_function.h" |
| #include "extensions/browser/extension_prefs.h" |
| #include "extensions/browser/extension_system.h" |
| #include "extensions/browser/extension_util.h" |
| -#include "extensions/browser/granted_file_entry.h" |
| -#include "extensions/browser/path_util.h" |
| -#include "extensions/common/permissions/api_permission.h" |
| -#include "extensions/common/permissions/permissions_data.h" |
| -#include "net/base/mime_util.h" |
| +#include "extensions/common/api/file_system.h" |
| +#include "extensions/common/extension.h" |
| #include "storage/browser/fileapi/external_mount_points.h" |
| -#include "storage/browser/fileapi/file_system_operation_runner.h" |
| #include "storage/browser/fileapi/isolated_context.h" |
| #include "storage/common/fileapi/file_system_types.h" |
| #include "storage/common/fileapi/file_system_util.h" |
| -#include "ui/base/l10n/l10n_util.h" |
| -#include "ui/base/ui_base_types.h" |
| #include "ui/shell_dialogs/select_file_dialog.h" |
| -#include "ui/shell_dialogs/selected_file_info.h" |
| +#include "ui/shell_dialogs/select_file_policy.h" |
| #if defined(OS_MACOSX) |
| #include <CoreFoundation/CoreFoundation.h> |
| @@ -66,8 +48,6 @@ |
| #endif |
| #if defined(OS_CHROMEOS) |
| -#include "base/strings/string16.h" |
| -#include "chrome/browser/chromeos/file_manager/filesystem_api_util.h" |
| #include "chrome/browser/chromeos/file_manager/volume_manager.h" |
| #include "extensions/browser/event_router.h" |
| #include "extensions/browser/extension_registry.h" |
| @@ -75,207 +55,61 @@ |
| #include "url/url_constants.h" |
| #endif |
| -using apps::SavedFileEntry; |
| -using apps::SavedFilesService; |
| -using storage::IsolatedContext; |
| - |
| -const char kInvalidCallingPage[] = |
| - "Invalid calling page. " |
| - "This function can't be called from a background page."; |
| -const char kUserCancelled[] = "User cancelled"; |
| -const char kWritableFileErrorFormat[] = "Error opening %s"; |
| -const char kRequiresFileSystemWriteError[] = |
| - "Operation requires fileSystem.write permission"; |
| -const char kRequiresFileSystemDirectoryError[] = |
| - "Operation requires fileSystem.directory permission"; |
| -const char kMultipleUnsupportedError[] = |
| - "acceptsMultiple: true is only supported for 'openFile'"; |
| -const char kUnknownIdError[] = "Unknown id"; |
| - |
| -#if !defined(OS_CHROMEOS) |
| -const char kNotSupportedOnCurrentPlatformError[] = |
| - "Operation not supported on the current platform."; |
| -#else |
| -const char kNotSupportedOnNonKioskSessionError[] = |
| - "Operation only supported for kiosk apps running in a kiosk session."; |
| -const char kVolumeNotFoundError[] = "Volume not found."; |
| -const char kSecurityError[] = "Security error."; |
| -const char kConsentImpossible[] = |
| - "Impossible to ask for user consent as there is no app window visible."; |
| -#endif |
| - |
| namespace extensions { |
| namespace file_system = api::file_system; |
| -namespace ChooseEntry = file_system::ChooseEntry; |
| - |
| -namespace { |
| - |
| -bool g_skip_picker_for_test = false; |
| -bool g_use_suggested_path_for_test = false; |
| -base::FilePath* g_path_to_be_picked_for_test; |
| -std::vector<base::FilePath>* g_paths_to_be_picked_for_test; |
| -bool g_skip_directory_confirmation_for_test = false; |
| -bool g_allow_directory_access_for_test = false; |
| - |
| -// Expand the mime-types and extensions provided in an AcceptOption, returning |
| -// them within the passed extension vector. Returns false if no valid types |
| -// were found. |
| -bool GetFileTypesFromAcceptOption( |
| - const file_system::AcceptOption& accept_option, |
| - std::vector<base::FilePath::StringType>* extensions, |
| - base::string16* description) { |
| - std::set<base::FilePath::StringType> extension_set; |
| - int description_id = 0; |
| - |
| - if (accept_option.mime_types.get()) { |
| - std::vector<std::string>* list = accept_option.mime_types.get(); |
| - bool valid_type = false; |
| - for (std::vector<std::string>::const_iterator iter = list->begin(); |
| - iter != list->end(); ++iter) { |
| - std::vector<base::FilePath::StringType> inner; |
| - std::string accept_type = base::ToLowerASCII(*iter); |
| - net::GetExtensionsForMimeType(accept_type, &inner); |
| - if (inner.empty()) |
| - continue; |
| - |
| - if (valid_type) |
| - description_id = 0; // We already have an accept type with label; if |
| - // we find another, give up and use the default. |
| - else if (accept_type == "image/*") |
| - description_id = IDS_IMAGE_FILES; |
| - else if (accept_type == "audio/*") |
| - description_id = IDS_AUDIO_FILES; |
| - else if (accept_type == "video/*") |
| - description_id = IDS_VIDEO_FILES; |
| - |
| - extension_set.insert(inner.begin(), inner.end()); |
| - valid_type = true; |
| - } |
| - } |
| - |
| - if (accept_option.extensions.get()) { |
| - std::vector<std::string>* list = accept_option.extensions.get(); |
| - for (std::vector<std::string>::const_iterator iter = list->begin(); |
| - iter != list->end(); ++iter) { |
| - std::string extension = base::ToLowerASCII(*iter); |
| -#if defined(OS_WIN) |
| - extension_set.insert(base::UTF8ToWide(*iter)); |
| -#else |
| - extension_set.insert(*iter); |
| -#endif |
| - } |
| - } |
| - |
| - extensions->assign(extension_set.begin(), extension_set.end()); |
| - if (extensions->empty()) |
| - return false; |
| - |
| - if (accept_option.description.get()) |
| - *description = base::UTF8ToUTF16(*accept_option.description); |
| - else if (description_id) |
| - *description = l10n_util::GetStringUTF16(description_id); |
| - |
| - return true; |
| -} |
| - |
| -// Key for the path of the directory of the file last chosen by the user in |
| -// response to a chrome.fileSystem.chooseEntry() call. |
| -const char kLastChooseEntryDirectory[] = "last_choose_file_directory"; |
| -const int kGraylistedPaths[] = { |
| - base::DIR_HOME, |
| -#if defined(OS_WIN) |
| - base::DIR_PROGRAM_FILES, base::DIR_PROGRAM_FILESX86, base::DIR_WINDOWS, |
| -#endif |
| -}; |
| - |
| -typedef base::Callback<void(std::unique_ptr<base::File::Info>)> |
| - FileInfoOptCallback; |
| +#if defined(OS_CHROMEOS) |
| +using file_system_api::ConsentProvider; |
| +using file_system_api::ConsentProviderDelegate; |
| -// Passes optional file info to the UI thread depending on |result| and |info|. |
| -void PassFileInfoToUIThread(const FileInfoOptCallback& callback, |
| - base::File::Error result, |
| - const base::File::Info& info) { |
| - DCHECK_CURRENTLY_ON(content::BrowserThread::IO); |
| - std::unique_ptr<base::File::Info> file_info( |
| - result == base::File::FILE_OK ? new base::File::Info(info) : NULL); |
| - content::BrowserThread::PostTask( |
| - content::BrowserThread::UI, FROM_HERE, |
| - base::BindOnce(callback, base::Passed(&file_info))); |
| -} |
| +namespace { |
| -// Gets a WebContents instance handle for a platform app hosted in |
| -// |render_frame_host|. If not found, then returns NULL. |
| -content::WebContents* GetWebContentsForRenderFrameHost( |
| - Profile* profile, |
| - content::RenderFrameHost* render_frame_host) { |
| - content::WebContents* web_contents = |
| - content::WebContents::FromRenderFrameHost(render_frame_host); |
| - // Check if there is an app window associated with the web contents; if not, |
| - // return null. |
| - return AppWindowRegistry::Get(profile)->GetAppWindowForWebContents( |
| - web_contents) |
| - ? web_contents |
| - : nullptr; |
| -} |
| +const char kConsentImpossible[] = |
| + "Impossible to ask for user consent as there is no app window visible."; |
| +const char kNotSupportedOnNonKioskSessionError[] = |
| + "Operation only supported for kiosk apps running in a kiosk session."; |
| +const char kRequiresFileSystemWriteError[] = |
| + "Operation requires fileSystem.write permission"; |
| +const char kSecurityError[] = "Security error."; |
| +const char kVolumeNotFoundError[] = "Volume not found."; |
| -#if defined(OS_CHROMEOS) |
| // Fills a list of volumes mounted in the system. |
| -void FillVolumeList(Profile* profile, |
| - std::vector<api::file_system::Volume>* result) { |
| +void FillVolumeList(content::BrowserContext* browser_context, |
| + std::vector<file_system::Volume>* result) { |
| file_manager::VolumeManager* const volume_manager = |
| - file_manager::VolumeManager::Get(profile); |
| + file_manager::VolumeManager::Get(browser_context); |
| DCHECK(volume_manager); |
| const auto& volume_list = volume_manager->GetVolumeList(); |
| // Convert volume_list to result_volume_list. |
| for (const auto& volume : volume_list) { |
| - api::file_system::Volume result_volume; |
| + file_system::Volume result_volume; |
| result_volume.volume_id = volume->volume_id(); |
| result_volume.writable = !volume->is_read_only(); |
| result->push_back(std::move(result_volume)); |
| } |
| } |
| -#endif |
| } // namespace |
| namespace file_system_api { |
| -base::FilePath GetLastChooseEntryDirectory(const ExtensionPrefs* prefs, |
| - const std::string& extension_id) { |
| - base::FilePath path; |
| - std::string string_path; |
| - if (prefs->ReadPrefAsString(extension_id, kLastChooseEntryDirectory, |
| - &string_path)) { |
| - path = base::FilePath::FromUTF8Unsafe(string_path); |
| - } |
| - return path; |
| -} |
| - |
| -void SetLastChooseEntryDirectory(ExtensionPrefs* prefs, |
| - const std::string& extension_id, |
| - const base::FilePath& path) { |
| - prefs->UpdateExtensionPref(extension_id, kLastChooseEntryDirectory, |
| - base::CreateFilePathValue(path)); |
| -} |
| - |
| -#if defined(OS_CHROMEOS) |
| -void DispatchVolumeListChangeEvent(Profile* profile) { |
| - DCHECK(profile); |
| - EventRouter* const event_router = EventRouter::Get(profile); |
| +void DispatchVolumeListChangeEvent(content::BrowserContext* browser_context) { |
| + DCHECK(browser_context); |
| + EventRouter* const event_router = EventRouter::Get(browser_context); |
| if (!event_router) // Possible on shutdown. |
| return; |
| - ExtensionRegistry* const registry = ExtensionRegistry::Get(profile); |
| + ExtensionRegistry* const registry = ExtensionRegistry::Get(browser_context); |
| if (!registry) // Possible on shutdown. |
| return; |
| - ConsentProviderDelegate consent_provider_delegate(profile, nullptr); |
| + ConsentProviderDelegate consent_provider_delegate( |
| + Profile::FromBrowserContext(browser_context)); |
| ConsentProvider consent_provider(&consent_provider_delegate); |
| - api::file_system::VolumeListChangedEvent event_args; |
| - FillVolumeList(profile, &event_args.volumes); |
| + file_system::VolumeListChangedEvent event_args; |
| + FillVolumeList(browser_context, &event_args.volumes); |
| for (const auto& extension : registry->enabled_extensions()) { |
| if (!consent_provider.IsGrantable(*extension.get())) |
| continue; |
| @@ -283,839 +117,168 @@ void DispatchVolumeListChangeEvent(Profile* profile) { |
| extension->id(), |
| base::MakeUnique<Event>( |
| events::FILE_SYSTEM_ON_VOLUME_LIST_CHANGED, |
| - api::file_system::OnVolumeListChanged::kEventName, |
| - api::file_system::OnVolumeListChanged::Create(event_args))); |
| + file_system::OnVolumeListChanged::kEventName, |
| + file_system::OnVolumeListChanged::Create(event_args))); |
| } |
| } |
| -#endif |
| } // namespace file_system_api |
| +#endif // defined(OS_CHROMEOS) |
| -#if defined(OS_CHROMEOS) |
| -using file_system_api::ConsentProvider; |
| -#endif |
| - |
| -ExtensionFunction::ResponseAction FileSystemGetDisplayPathFunction::Run() { |
| - std::string filesystem_name; |
| - std::string filesystem_path; |
| - EXTENSION_FUNCTION_VALIDATE(args_->GetString(0, &filesystem_name)); |
| - EXTENSION_FUNCTION_VALIDATE(args_->GetString(1, &filesystem_path)); |
| - |
| - base::FilePath file_path; |
| - std::string error; |
| - if (!app_file_handler_util::ValidateFileEntryAndGetPath( |
| - filesystem_name, filesystem_path, |
| - render_frame_host()->GetProcess()->GetID(), &file_path, &error)) { |
| - return RespondNow(Error(error)); |
| - } |
| - |
| - file_path = path_util::PrettifyPath(file_path); |
| - return RespondNow( |
| - OneArgument(base::MakeUnique<base::Value>(file_path.value()))); |
| -} |
| +ChromeFileSystemDelegate::ChromeFileSystemDelegate() {} |
| -FileSystemEntryFunction::FileSystemEntryFunction() |
| - : multiple_(false), is_directory_(false) {} |
| +ChromeFileSystemDelegate::~ChromeFileSystemDelegate() {} |
| -void FileSystemEntryFunction::PrepareFilesForWritableApp( |
| - const std::vector<base::FilePath>& paths) { |
| - DCHECK_CURRENTLY_ON(content::BrowserThread::UI); |
| - // TODO(cmihail): Path directory set should be initialized only with the |
| - // paths that are actually directories, but for now we will consider |
| - // all paths directories in case is_directory_ is true, otherwise |
| - // all paths files, as this was the previous logic. |
| - std::set<base::FilePath> path_directory_set_ = |
| - is_directory_ ? std::set<base::FilePath>(paths.begin(), paths.end()) |
| - : std::set<base::FilePath>{}; |
| - app_file_handler_util::PrepareFilesForWritableApp( |
| - paths, GetProfile(), path_directory_set_, |
| - base::Bind(&FileSystemEntryFunction::RegisterFileSystemsAndSendResponse, |
| - this, paths), |
| - base::Bind(&FileSystemEntryFunction::HandleWritableFileError, this)); |
| +base::FilePath ChromeFileSystemDelegate::GetDefaultDirectory() { |
| + base::FilePath documents_dir; |
| + PathService::Get(chrome::DIR_USER_DOCUMENTS, &documents_dir); |
| + return documents_dir; |
| } |
| -void FileSystemEntryFunction::RegisterFileSystemsAndSendResponse( |
| - const std::vector<base::FilePath>& paths) { |
| - DCHECK_CURRENTLY_ON(content::BrowserThread::UI); |
| - if (!render_frame_host()) |
| - return; |
| - |
| - std::unique_ptr<base::DictionaryValue> result = CreateResult(); |
| - for (const auto& path : paths) |
| - AddEntryToResult(path, std::string(), result.get()); |
| - SetResult(std::move(result)); |
| - SendResponse(true); |
| -} |
| - |
| -std::unique_ptr<base::DictionaryValue> FileSystemEntryFunction::CreateResult() { |
| - std::unique_ptr<base::DictionaryValue> result(new base::DictionaryValue()); |
| - result->Set("entries", base::MakeUnique<base::ListValue>()); |
| - result->SetBoolean("multiple", multiple_); |
| - return result; |
| -} |
| - |
| -void FileSystemEntryFunction::AddEntryToResult(const base::FilePath& path, |
| - const std::string& id_override, |
| - base::DictionaryValue* result) { |
| - GrantedFileEntry file_entry = app_file_handler_util::CreateFileEntry( |
| - GetProfile(), extension(), render_frame_host()->GetProcess()->GetID(), |
| - path, is_directory_); |
| - base::ListValue* entries; |
| - bool success = result->GetList("entries", &entries); |
| - DCHECK(success); |
| - |
| - std::unique_ptr<base::DictionaryValue> entry(new base::DictionaryValue()); |
| - entry->SetString("fileSystemId", file_entry.filesystem_id); |
| - entry->SetString("baseName", file_entry.registered_name); |
| - if (id_override.empty()) |
| - entry->SetString("id", file_entry.id); |
| +std::unique_ptr<ui::SelectFilePolicy> |
| +ChromeFileSystemDelegate::CreateSelectFilePolicy( |
| + content::WebContents* web_contents) { |
| + return base::MakeUnique<ChromeSelectFilePolicy>(web_contents); |
| +} |
| + |
| +scoped_refptr<ui::SelectFileDialog> |
| +ChromeFileSystemDelegate::CreateSelectFileDialog( |
| + ui::SelectFileDialog::Listener* listener, |
| + std::unique_ptr<ui::SelectFilePolicy> policy) { |
| + // SelectFileDialog will take ownership of |policy|. |
| + return ui::SelectFileDialog::Create(listener, policy.release()); |
| +} |
| + |
| +void ChromeFileSystemDelegate::ShowSelectFileDialogForWebContents( |
| + scoped_refptr<ui::SelectFileDialog> dialog, |
| + content::WebContents* web_contents, |
| + ui::SelectFileDialog::Type type, |
| + const base::FilePath& default_path, |
| + const ui::SelectFileDialog::FileTypeInfo* file_types) { |
| + gfx::NativeWindow owning_window = |
| + web_contents ? platform_util::GetTopLevel(web_contents->GetNativeView()) |
| + : nullptr; |
| + dialog->SelectFile(type, base::string16(), default_path, file_types, 0, |
| + base::FilePath::StringType(), owning_window, nullptr); |
| +} |
| + |
| +void ChromeFileSystemDelegate::ConfirmSensitiveDirectoryAccess( |
| + bool has_write_permission, |
| + const base::string16& app_name, |
| + content::WebContents* web_contents, |
| + const base::Closure& on_accept, |
| + const base::Closure& on_cancel) { |
| + CreateDirectoryAccessConfirmationDialog(has_write_permission, app_name, |
| + web_contents, on_accept, on_cancel); |
| +} |
| + |
| +bool ChromeFileSystemDelegate::GetDescriptionIdForAcceptType( |
| + const std::string& accept_type, |
| + int* description_id) { |
| + if (accept_type == "image/*") |
| + *description_id = IDS_IMAGE_FILES; |
| + else if (accept_type == "audio/*") |
| + *description_id = IDS_AUDIO_FILES; |
| + else if (accept_type == "video/*") |
| + *description_id = IDS_VIDEO_FILES; |
| else |
| - entry->SetString("id", id_override); |
| - entry->SetBoolean("isDirectory", is_directory_); |
| - entries->Append(std::move(entry)); |
| -} |
| - |
| -void FileSystemEntryFunction::HandleWritableFileError( |
| - const base::FilePath& error_path) { |
| - DCHECK_CURRENTLY_ON(content::BrowserThread::UI); |
| - error_ = base::StringPrintf(kWritableFileErrorFormat, |
| - error_path.BaseName().AsUTF8Unsafe().c_str()); |
| - SendResponse(false); |
| -} |
| - |
| -bool FileSystemGetWritableEntryFunction::RunAsync() { |
| - std::string filesystem_name; |
| - std::string filesystem_path; |
| - EXTENSION_FUNCTION_VALIDATE(args_->GetString(0, &filesystem_name)); |
| - EXTENSION_FUNCTION_VALIDATE(args_->GetString(1, &filesystem_path)); |
| - |
| - if (!app_file_handler_util::HasFileSystemWritePermission(extension_.get())) { |
| - error_ = kRequiresFileSystemWriteError; |
| - return false; |
| - } |
| - |
| - if (!app_file_handler_util::ValidateFileEntryAndGetPath( |
| - filesystem_name, filesystem_path, |
| - render_frame_host()->GetProcess()->GetID(), &path_, &error_)) |
| return false; |
| - |
| - base::PostTaskWithTraitsAndReply( |
| - FROM_HERE, {base::MayBlock(), base::TaskPriority::BACKGROUND}, |
| - base::BindOnce(&FileSystemGetWritableEntryFunction::SetIsDirectoryAsync, |
| - this), |
| - base::BindOnce( |
| - &FileSystemGetWritableEntryFunction::CheckPermissionAndSendResponse, |
| - this)); |
| return true; |
| } |
| -void FileSystemGetWritableEntryFunction::CheckPermissionAndSendResponse() { |
| - DCHECK_CURRENTLY_ON(content::BrowserThread::UI); |
| - if (is_directory_ && !extension_->permissions_data()->HasAPIPermission( |
| - APIPermission::kFileSystemDirectory)) { |
| - error_ = kRequiresFileSystemDirectoryError; |
| - SendResponse(false); |
| - } |
| - std::vector<base::FilePath> paths; |
| - paths.push_back(path_); |
| - PrepareFilesForWritableApp(paths); |
| -} |
| - |
| -void FileSystemGetWritableEntryFunction::SetIsDirectoryAsync() { |
| - if (base::DirectoryExists(path_)) { |
| - is_directory_ = true; |
| - } |
| -} |
| - |
| -ExtensionFunction::ResponseAction FileSystemIsWritableEntryFunction::Run() { |
| - std::string filesystem_name; |
| - std::string filesystem_path; |
| - EXTENSION_FUNCTION_VALIDATE(args_->GetString(0, &filesystem_name)); |
| - EXTENSION_FUNCTION_VALIDATE(args_->GetString(1, &filesystem_path)); |
| - |
| - std::string filesystem_id; |
| - if (!storage::CrackIsolatedFileSystemName(filesystem_name, &filesystem_id)) |
| - return RespondNow(Error(app_file_handler_util::kInvalidParameters)); |
| - |
| - content::ChildProcessSecurityPolicy* policy = |
| - content::ChildProcessSecurityPolicy::GetInstance(); |
| - int renderer_id = render_frame_host()->GetProcess()->GetID(); |
| - bool is_writable = policy->CanReadWriteFileSystem(renderer_id, filesystem_id); |
| - |
| - return RespondNow(OneArgument(base::MakeUnique<base::Value>(is_writable))); |
| -} |
| - |
| -// Handles showing a dialog to the user to ask for the filename for a file to |
| -// save or open. |
| -class FileSystemChooseEntryFunction::FilePicker |
| - : public ui::SelectFileDialog::Listener { |
| - public: |
| - FilePicker(FileSystemChooseEntryFunction* function, |
| - content::WebContents* web_contents, |
| - const base::FilePath& suggested_name, |
| - const ui::SelectFileDialog::FileTypeInfo& file_type_info, |
| - ui::SelectFileDialog::Type picker_type) |
| - : function_(function) { |
| - select_file_dialog_ = ui::SelectFileDialog::Create( |
| - this, new ChromeSelectFilePolicy(web_contents)); |
| - gfx::NativeWindow owning_window = |
| - web_contents ? platform_util::GetTopLevel(web_contents->GetNativeView()) |
| - : NULL; |
| - |
| - if (g_skip_picker_for_test) { |
| - if (g_use_suggested_path_for_test) { |
| - content::BrowserThread::PostTask( |
| - content::BrowserThread::UI, FROM_HERE, |
| - base::BindOnce( |
| - &FileSystemChooseEntryFunction::FilePicker::FileSelected, |
| - base::Unretained(this), suggested_name, 1, |
| - static_cast<void*>(NULL))); |
| - } else if (g_path_to_be_picked_for_test) { |
| - content::BrowserThread::PostTask( |
| - content::BrowserThread::UI, FROM_HERE, |
| - base::BindOnce( |
| - &FileSystemChooseEntryFunction::FilePicker::FileSelected, |
| - base::Unretained(this), *g_path_to_be_picked_for_test, 1, |
| - static_cast<void*>(NULL))); |
| - } else if (g_paths_to_be_picked_for_test) { |
| - content::BrowserThread::PostTask( |
| - content::BrowserThread::UI, FROM_HERE, |
| - base::BindOnce( |
| - &FileSystemChooseEntryFunction::FilePicker::MultiFilesSelected, |
| - base::Unretained(this), *g_paths_to_be_picked_for_test, |
| - static_cast<void*>(NULL))); |
| - } else { |
| - content::BrowserThread::PostTask( |
| - content::BrowserThread::UI, FROM_HERE, |
| - base::BindOnce(&FileSystemChooseEntryFunction::FilePicker:: |
| - FileSelectionCanceled, |
| - base::Unretained(this), static_cast<void*>(NULL))); |
| - } |
| - return; |
| - } |
| - |
| - select_file_dialog_->SelectFile( |
| - picker_type, base::string16(), suggested_name, &file_type_info, 0, |
| - base::FilePath::StringType(), owning_window, NULL); |
| - } |
| - |
| - ~FilePicker() override {} |
| - |
| - private: |
| - // ui::SelectFileDialog::Listener implementation. |
| - void FileSelected(const base::FilePath& path, |
| - int index, |
| - void* params) override { |
| - std::vector<base::FilePath> paths; |
| - paths.push_back(path); |
| - MultiFilesSelected(paths, params); |
| - } |
| - |
| - void FileSelectedWithExtraInfo(const ui::SelectedFileInfo& file, |
| - int index, |
| - void* params) override { |
| - // Normally, file.local_path is used because it is a native path to the |
| - // local read-only cached file in the case of remote file system like |
| - // Chrome OS's Google Drive integration. Here, however, |file.file_path| is |
| - // necessary because we need to create a FileEntry denoting the remote file, |
| - // not its cache. On other platforms than Chrome OS, they are the same. |
| - // |
| - // TODO(kinaba): remove this, once after the file picker implements proper |
| - // switch of the path treatment depending on the |allowed_paths|. |
| - FileSelected(file.file_path, index, params); |
| - } |
| - |
| - void MultiFilesSelected(const std::vector<base::FilePath>& files, |
| - void* params) override { |
| - function_->FilesSelected(files); |
| - delete this; |
| - } |
| - |
| - void MultiFilesSelectedWithExtraInfo( |
| - const std::vector<ui::SelectedFileInfo>& files, |
| - void* params) override { |
| - std::vector<base::FilePath> paths; |
| - for (std::vector<ui::SelectedFileInfo>::const_iterator it = files.begin(); |
| - it != files.end(); ++it) { |
| - paths.push_back(it->file_path); |
| - } |
| - MultiFilesSelected(paths, params); |
| - } |
| - |
| - void FileSelectionCanceled(void* params) override { |
| - function_->FileSelectionCanceled(); |
| - delete this; |
| - } |
| - |
| - scoped_refptr<ui::SelectFileDialog> select_file_dialog_; |
| - scoped_refptr<FileSystemChooseEntryFunction> function_; |
| - |
| - DISALLOW_COPY_AND_ASSIGN(FilePicker); |
| -}; |
| - |
| -void FileSystemChooseEntryFunction::ShowPicker( |
| - const ui::SelectFileDialog::FileTypeInfo& file_type_info, |
| - ui::SelectFileDialog::Type picker_type) { |
| - // TODO(asargent/benwells) - As a short term remediation for crbug.com/179010 |
| - // we're adding the ability for a whitelisted extension to use this API since |
| - // chrome.fileBrowserHandler.selectFile is ChromeOS-only. Eventually we'd |
| - // like a better solution and likely this code will go back to being |
| - // platform-app only. |
| - content::WebContents* const web_contents = |
| - extension_->is_platform_app() |
| - ? GetWebContentsForRenderFrameHost(GetProfile(), render_frame_host()) |
| - : GetAssociatedWebContents(); |
| - if (!web_contents) { |
| - error_ = kInvalidCallingPage; |
| - SendResponse(false); |
| - return; |
| - } |
| - |
| - // The file picker will hold a reference to this function instance, preventing |
| - // its destruction (and subsequent sending of the function response) until the |
| - // user has selected a file or cancelled the picker. At that point, the picker |
| - // will delete itself, which will also free the function instance. |
| - new FilePicker(this, web_contents, initial_path_, file_type_info, |
| - picker_type); |
| -} |
| - |
| -// static |
| -void FileSystemChooseEntryFunction::SkipPickerAndAlwaysSelectPathForTest( |
| - base::FilePath* path) { |
| - g_skip_picker_for_test = true; |
| - g_use_suggested_path_for_test = false; |
| - g_path_to_be_picked_for_test = path; |
| - g_paths_to_be_picked_for_test = NULL; |
| -} |
| - |
| -void FileSystemChooseEntryFunction::SkipPickerAndAlwaysSelectPathsForTest( |
| - std::vector<base::FilePath>* paths) { |
| - g_skip_picker_for_test = true; |
| - g_use_suggested_path_for_test = false; |
| - g_paths_to_be_picked_for_test = paths; |
| -} |
| - |
| -// static |
| -void FileSystemChooseEntryFunction::SkipPickerAndSelectSuggestedPathForTest() { |
| - g_skip_picker_for_test = true; |
| - g_use_suggested_path_for_test = true; |
| - g_path_to_be_picked_for_test = NULL; |
| - g_paths_to_be_picked_for_test = NULL; |
| -} |
| - |
| -// static |
| -void FileSystemChooseEntryFunction::SkipPickerAndAlwaysCancelForTest() { |
| - g_skip_picker_for_test = true; |
| - g_use_suggested_path_for_test = false; |
| - g_path_to_be_picked_for_test = NULL; |
| - g_paths_to_be_picked_for_test = NULL; |
| -} |
| - |
| -// static |
| -void FileSystemChooseEntryFunction::StopSkippingPickerForTest() { |
| - g_skip_picker_for_test = false; |
| -} |
| - |
| -// static |
| -void FileSystemChooseEntryFunction::SkipDirectoryConfirmationForTest() { |
| - g_skip_directory_confirmation_for_test = true; |
| - g_allow_directory_access_for_test = true; |
| -} |
| - |
| -// static |
| -void FileSystemChooseEntryFunction::AutoCancelDirectoryConfirmationForTest() { |
| - g_skip_directory_confirmation_for_test = true; |
| - g_allow_directory_access_for_test = false; |
| -} |
| - |
| -// static |
| -void FileSystemChooseEntryFunction::StopSkippingDirectoryConfirmationForTest() { |
| - g_skip_directory_confirmation_for_test = false; |
| -} |
| - |
| -// static |
| -void FileSystemChooseEntryFunction::RegisterTempExternalFileSystemForTest( |
| - const std::string& name, |
| - const base::FilePath& path) { |
| - // For testing on Chrome OS, where to deal with remote and local paths |
| - // smoothly, all accessed paths need to be registered in the list of |
| - // external mount points. |
| - storage::ExternalMountPoints::GetSystemInstance()->RegisterFileSystem( |
| - name, storage::kFileSystemTypeNativeLocal, |
| - storage::FileSystemMountOption(), path); |
| -} |
| - |
| -void FileSystemChooseEntryFunction::FilesSelected( |
| - const std::vector<base::FilePath>& paths) { |
| - DCHECK(!paths.empty()); |
| - base::FilePath last_choose_directory; |
| - if (is_directory_) { |
| - last_choose_directory = paths[0]; |
| - } else { |
| - last_choose_directory = paths[0].DirName(); |
| - } |
| - file_system_api::SetLastChooseEntryDirectory( |
| - ExtensionPrefs::Get(GetProfile()), extension()->id(), |
| - last_choose_directory); |
| - if (is_directory_) { |
| - // Get the WebContents for the app window to be the parent window of the |
| - // confirmation dialog if necessary. |
| - content::WebContents* const web_contents = |
| - GetWebContentsForRenderFrameHost(GetProfile(), render_frame_host()); |
| - if (!web_contents) { |
| - error_ = kInvalidCallingPage; |
| - SendResponse(false); |
| - return; |
| - } |
| - |
| - DCHECK_EQ(paths.size(), 1u); |
| - bool non_native_path = false; |
| #if defined(OS_CHROMEOS) |
| - non_native_path = |
| - file_manager::util::IsUnderNonNativeLocalPath(GetProfile(), paths[0]); |
| -#endif |
| - |
| - base::PostTaskWithTraits( |
| - FROM_HERE, {base::MayBlock(), base::TaskPriority::BACKGROUND}, |
| - base::BindOnce( |
| - &FileSystemChooseEntryFunction::ConfirmDirectoryAccessAsync, this, |
| - non_native_path, paths, web_contents)); |
| - return; |
| - } |
| - |
| - OnDirectoryAccessConfirmed(paths); |
| -} |
| - |
| -void FileSystemChooseEntryFunction::FileSelectionCanceled() { |
| - error_ = kUserCancelled; |
| - SendResponse(false); |
| -} |
| - |
| -void FileSystemChooseEntryFunction::ConfirmDirectoryAccessAsync( |
| - bool non_native_path, |
| - const std::vector<base::FilePath>& paths, |
| - content::WebContents* web_contents) { |
| - const base::FilePath check_path = |
| - non_native_path ? paths[0] : base::MakeAbsoluteFilePath(paths[0]); |
| - if (check_path.empty()) { |
| - content::BrowserThread::PostTask( |
| - content::BrowserThread::UI, FROM_HERE, |
| - base::BindOnce(&FileSystemChooseEntryFunction::FileSelectionCanceled, |
| - this)); |
| - return; |
| - } |
| - |
| - for (size_t i = 0; i < arraysize(kGraylistedPaths); i++) { |
| - base::FilePath graylisted_path; |
| - if (PathService::Get(kGraylistedPaths[i], &graylisted_path) && |
| - (check_path == graylisted_path || |
| - check_path.IsParent(graylisted_path))) { |
| - if (g_skip_directory_confirmation_for_test) { |
| - if (g_allow_directory_access_for_test) { |
| - break; |
| - } else { |
| - content::BrowserThread::PostTask( |
| - content::BrowserThread::UI, FROM_HERE, |
| - base::BindOnce( |
| - &FileSystemChooseEntryFunction::FileSelectionCanceled, this)); |
| - } |
| - return; |
| - } |
| - |
| - content::BrowserThread::PostTask( |
| - content::BrowserThread::UI, FROM_HERE, |
| - base::BindOnce( |
| - CreateDirectoryAccessConfirmationDialog, |
| - app_file_handler_util::HasFileSystemWritePermission( |
| - extension_.get()), |
| - base::UTF8ToUTF16(extension_->name()), web_contents, |
| - base::Bind( |
| - &FileSystemChooseEntryFunction::OnDirectoryAccessConfirmed, |
| - this, paths), |
| - base::Bind(&FileSystemChooseEntryFunction::FileSelectionCanceled, |
| - this))); |
| - return; |
| - } |
| - } |
| - |
| - content::BrowserThread::PostTask( |
| - content::BrowserThread::UI, FROM_HERE, |
| - base::BindOnce(&FileSystemChooseEntryFunction::OnDirectoryAccessConfirmed, |
| - this, paths)); |
| -} |
| - |
| -void FileSystemChooseEntryFunction::OnDirectoryAccessConfirmed( |
| - const std::vector<base::FilePath>& paths) { |
| - if (app_file_handler_util::HasFileSystemWritePermission(extension_.get())) { |
| - PrepareFilesForWritableApp(paths); |
| - return; |
| - } |
| - |
| - // Don't need to check the file, it's for reading. |
| - RegisterFileSystemsAndSendResponse(paths); |
| -} |
| - |
| -void FileSystemChooseEntryFunction::BuildFileTypeInfo( |
| - ui::SelectFileDialog::FileTypeInfo* file_type_info, |
| - const base::FilePath::StringType& suggested_extension, |
| - const AcceptOptions* accepts, |
| - const bool* acceptsAllTypes) { |
| - file_type_info->include_all_files = true; |
| - if (acceptsAllTypes) |
| - file_type_info->include_all_files = *acceptsAllTypes; |
| - |
| - bool need_suggestion = |
| - !file_type_info->include_all_files && !suggested_extension.empty(); |
| - |
| - if (accepts) { |
| - for (const file_system::AcceptOption& option : *accepts) { |
| - base::string16 description; |
| - std::vector<base::FilePath::StringType> extensions; |
| - |
| - if (!GetFileTypesFromAcceptOption(option, &extensions, &description)) |
| - continue; // No extensions were found. |
| - |
| - file_type_info->extensions.push_back(extensions); |
| - file_type_info->extension_description_overrides.push_back(description); |
| - |
| - // If we still need to find suggested_extension, hunt for it inside the |
| - // extensions returned from GetFileTypesFromAcceptOption. |
| - if (need_suggestion && |
| - std::find(extensions.begin(), extensions.end(), |
| - suggested_extension) != extensions.end()) { |
| - need_suggestion = false; |
| - } |
| - } |
| - } |
| - |
| - // If there's nothing in our accepted extension list or we couldn't find the |
| - // suggested extension required, then default to accepting all types. |
| - if (file_type_info->extensions.empty() || need_suggestion) |
| - file_type_info->include_all_files = true; |
| -} |
| - |
| -void FileSystemChooseEntryFunction::BuildSuggestion( |
| - const std::string* opt_name, |
| - base::FilePath* suggested_name, |
| - base::FilePath::StringType* suggested_extension) { |
| - if (opt_name) { |
| - *suggested_name = base::FilePath::FromUTF8Unsafe(*opt_name); |
| - |
| - // Don't allow any path components; shorten to the base name. This should |
| - // result in a relative path, but in some cases may not. Clear the |
| - // suggestion for safety if this is the case. |
| - *suggested_name = suggested_name->BaseName(); |
| - if (suggested_name->IsAbsolute()) |
| - *suggested_name = base::FilePath(); |
| - |
| - *suggested_extension = suggested_name->Extension(); |
| - if (!suggested_extension->empty()) |
| - suggested_extension->erase(suggested_extension->begin()); // drop the . |
| - } |
| -} |
| - |
| -void FileSystemChooseEntryFunction::SetInitialPathAndShowPicker( |
| - const base::FilePath& previous_path, |
| - const base::FilePath& suggested_name, |
| - const ui::SelectFileDialog::FileTypeInfo& file_type_info, |
| - ui::SelectFileDialog::Type picker_type, |
| - bool is_previous_path_directory) { |
| - DCHECK_CURRENTLY_ON(content::BrowserThread::UI); |
| - if (is_previous_path_directory) { |
| - initial_path_ = previous_path.Append(suggested_name); |
| - } else { |
| - base::FilePath documents_dir; |
| - if (PathService::Get(chrome::DIR_USER_DOCUMENTS, &documents_dir)) { |
| - initial_path_ = documents_dir.Append(suggested_name); |
| - } else { |
| - initial_path_ = suggested_name; |
| - } |
| - } |
| - ShowPicker(file_type_info, picker_type); |
| -} |
| - |
| -bool FileSystemChooseEntryFunction::RunAsync() { |
| - std::unique_ptr<ChooseEntry::Params> params( |
| - ChooseEntry::Params::Create(*args_)); |
| - EXTENSION_FUNCTION_VALIDATE(params.get()); |
| - |
| - base::FilePath suggested_name; |
| - ui::SelectFileDialog::FileTypeInfo file_type_info; |
| - ui::SelectFileDialog::Type picker_type = |
| - ui::SelectFileDialog::SELECT_OPEN_FILE; |
| - |
| - file_system::ChooseEntryOptions* options = params->options.get(); |
| - if (options) { |
| - multiple_ = options->accepts_multiple && *options->accepts_multiple; |
| - if (multiple_) |
| - picker_type = ui::SelectFileDialog::SELECT_OPEN_MULTI_FILE; |
| - |
| - if (options->type == file_system::CHOOSE_ENTRY_TYPE_OPENWRITABLEFILE && |
| - !app_file_handler_util::HasFileSystemWritePermission( |
| - extension_.get())) { |
| - error_ = kRequiresFileSystemWriteError; |
| - return false; |
| - } else if (options->type == file_system::CHOOSE_ENTRY_TYPE_SAVEFILE) { |
| - if (!app_file_handler_util::HasFileSystemWritePermission( |
| - extension_.get())) { |
| - error_ = kRequiresFileSystemWriteError; |
| - return false; |
| - } |
| - if (multiple_) { |
| - error_ = kMultipleUnsupportedError; |
| - return false; |
| - } |
| - picker_type = ui::SelectFileDialog::SELECT_SAVEAS_FILE; |
| - } else if (options->type == file_system::CHOOSE_ENTRY_TYPE_OPENDIRECTORY) { |
| - is_directory_ = true; |
| - if (!extension_->permissions_data()->HasAPIPermission( |
| - APIPermission::kFileSystemDirectory)) { |
| - error_ = kRequiresFileSystemDirectoryError; |
| - return false; |
| - } |
| - if (multiple_) { |
| - error_ = kMultipleUnsupportedError; |
| - return false; |
| - } |
| - picker_type = ui::SelectFileDialog::SELECT_FOLDER; |
| - } |
| - |
| - base::FilePath::StringType suggested_extension; |
| - BuildSuggestion(options->suggested_name.get(), &suggested_name, |
| - &suggested_extension); |
| - |
| - BuildFileTypeInfo(&file_type_info, suggested_extension, |
| - options->accepts.get(), options->accepts_all_types.get()); |
| - } |
| - |
| - file_type_info.allowed_paths = ui::SelectFileDialog::FileTypeInfo::ANY_PATH; |
| - |
| - base::FilePath previous_path = file_system_api::GetLastChooseEntryDirectory( |
| - ExtensionPrefs::Get(GetProfile()), extension()->id()); |
| - |
| - if (previous_path.empty()) { |
| - SetInitialPathAndShowPicker(previous_path, suggested_name, file_type_info, |
| - picker_type, false); |
| - return true; |
| - } |
| - |
| - base::Callback<void(bool)> set_initial_path_callback = base::Bind( |
| - &FileSystemChooseEntryFunction::SetInitialPathAndShowPicker, this, |
| - previous_path, suggested_name, file_type_info, picker_type); |
| - |
| -// Check whether the |previous_path| is a non-native directory. |
| -#if defined(OS_CHROMEOS) |
| - if (file_manager::util::IsUnderNonNativeLocalPath(GetProfile(), |
| - previous_path)) { |
| - file_manager::util::IsNonNativeLocalPathDirectory( |
| - GetProfile(), previous_path, set_initial_path_callback); |
| - return true; |
| - } |
| -#endif |
| - base::PostTaskWithTraitsAndReplyWithResult( |
| - FROM_HERE, {base::MayBlock(), base::TaskPriority::BACKGROUND}, |
| - base::Bind(&base::DirectoryExists, previous_path), |
| - set_initial_path_callback); |
| - |
| - return true; |
| +bool ChromeFileSystemDelegate::IsGrantable( |
| + content::BrowserContext* browser_context, |
| + content::RenderFrameHost* render_frame_host, |
| + const Extension& extension) { |
| + // Only kiosk apps in kiosk sessions can use this API. |
| + // Additionally it is enabled for whitelisted component extensions and apps. |
| + ConsentProviderDelegate consent_provider_delegate( |
| + Profile::FromBrowserContext(browser_context)); |
| + ConsentProvider consent_provider(&consent_provider_delegate); |
| + return consent_provider.IsGrantable(extension); |
|
Devlin
2017/06/21 14:53:30
optional nit: inlineable:
return ConsentProvider(&
michaelpg
2017/06/23 21:30:53
Done.
|
| } |
| -bool FileSystemRetainEntryFunction::RunAsync() { |
| - std::string entry_id; |
| - EXTENSION_FUNCTION_VALIDATE(args_->GetString(0, &entry_id)); |
| - SavedFilesService* saved_files_service = SavedFilesService::Get(GetProfile()); |
| - // Add the file to the retain list if it is not already on there. |
| - if (!saved_files_service->IsRegistered(extension_->id(), entry_id)) { |
| - std::string filesystem_name; |
| - std::string filesystem_path; |
| - base::FilePath path; |
| - EXTENSION_FUNCTION_VALIDATE(args_->GetString(1, &filesystem_name)); |
| - EXTENSION_FUNCTION_VALIDATE(args_->GetString(2, &filesystem_path)); |
| - if (!app_file_handler_util::ValidateFileEntryAndGetPath( |
| - filesystem_name, filesystem_path, |
| - render_frame_host()->GetProcess()->GetID(), &path, &error_)) { |
| - return false; |
| - } |
| - |
| - std::string filesystem_id; |
| - if (!storage::CrackIsolatedFileSystemName(filesystem_name, &filesystem_id)) |
| - return false; |
| - |
| - const GURL site = util::GetSiteForExtensionId(extension_id(), GetProfile()); |
| - storage::FileSystemContext* const context = |
| - content::BrowserContext::GetStoragePartitionForSite(GetProfile(), site) |
| - ->GetFileSystemContext(); |
| - const storage::FileSystemURL url = context->CreateCrackedFileSystemURL( |
| - site, storage::kFileSystemTypeIsolated, |
| - IsolatedContext::GetInstance() |
| - ->CreateVirtualRootPath(filesystem_id) |
| - .Append(base::FilePath::FromUTF8Unsafe(filesystem_path))); |
| - |
| - content::BrowserThread::PostTask( |
| - content::BrowserThread::IO, FROM_HERE, |
| - base::BindOnce( |
| - base::IgnoreResult( |
| - &storage::FileSystemOperationRunner::GetMetadata), |
| - context->operation_runner()->AsWeakPtr(), url, |
| - storage::FileSystemOperation::GET_METADATA_FIELD_IS_DIRECTORY, |
| - base::Bind( |
| - &PassFileInfoToUIThread, |
| - base::Bind(&FileSystemRetainEntryFunction::RetainFileEntry, |
| - this, entry_id, path)))); |
| - return true; |
| - } |
| - |
| - saved_files_service->EnqueueFileEntry(extension_->id(), entry_id); |
| - SendResponse(true); |
| - return true; |
| -} |
| +void ChromeFileSystemDelegate::RequestFileSystem( |
| + content::BrowserContext* browser_context, |
| + scoped_refptr<UIThreadExtensionFunction> requester, |
| + const Extension& extension, |
| + std::string volume_id, |
| + bool writable, |
| + const FileSystemCallback& success_callback, |
| + const ErrorCallback& error_callback) { |
| + ConsentProviderDelegate consent_provider_delegate( |
| + Profile::FromBrowserContext(browser_context)); |
| + ConsentProvider consent_provider(&consent_provider_delegate); |
| -void FileSystemRetainEntryFunction::RetainFileEntry( |
| - const std::string& entry_id, |
| - const base::FilePath& path, |
| - std::unique_ptr<base::File::Info> file_info) { |
| - if (!file_info) { |
| - SendResponse(false); |
| + if (!consent_provider.IsGrantable(extension)) { |
| + error_callback.Run(kNotSupportedOnNonKioskSessionError); |
| return; |
| } |
| - SavedFilesService* saved_files_service = SavedFilesService::Get(GetProfile()); |
| - saved_files_service->RegisterFileEntry(extension_->id(), entry_id, path, |
| - file_info->is_directory); |
| - saved_files_service->EnqueueFileEntry(extension_->id(), entry_id); |
| - SendResponse(true); |
| -} |
| - |
| -ExtensionFunction::ResponseAction FileSystemIsRestorableFunction::Run() { |
| - std::string entry_id; |
| - EXTENSION_FUNCTION_VALIDATE(args_->GetString(0, &entry_id)); |
| - return RespondNow(OneArgument(base::MakeUnique<base::Value>( |
| - SavedFilesService::Get(Profile::FromBrowserContext(browser_context())) |
| - ->IsRegistered(extension_->id(), entry_id)))); |
| -} |
| - |
| -bool FileSystemRestoreEntryFunction::RunAsync() { |
| - std::string entry_id; |
| - bool needs_new_entry; |
| - EXTENSION_FUNCTION_VALIDATE(args_->GetString(0, &entry_id)); |
| - EXTENSION_FUNCTION_VALIDATE(args_->GetBoolean(1, &needs_new_entry)); |
| - const SavedFileEntry* file_entry = |
| - SavedFilesService::Get(GetProfile()) |
| - ->GetFileEntry(extension_->id(), entry_id); |
| - if (!file_entry) { |
| - error_ = kUnknownIdError; |
| - return false; |
| - } |
| - |
| - SavedFilesService::Get(GetProfile()) |
| - ->EnqueueFileEntry(extension_->id(), entry_id); |
| - |
| - // Only create a new file entry if the renderer requests one. |
| - // |needs_new_entry| will be false if the renderer already has an Entry for |
| - // |entry_id|. |
| - if (needs_new_entry) { |
| - is_directory_ = file_entry->is_directory; |
| - std::unique_ptr<base::DictionaryValue> result = CreateResult(); |
| - AddEntryToResult(file_entry->path, file_entry->id, result.get()); |
| - SetResult(std::move(result)); |
| - } |
| - SendResponse(true); |
| - return true; |
| -} |
| - |
| -ExtensionFunction::ResponseAction FileSystemObserveDirectoryFunction::Run() { |
| - NOTIMPLEMENTED(); |
| - return RespondNow(Error(kUnknownIdError)); |
| -} |
| - |
| -ExtensionFunction::ResponseAction FileSystemUnobserveEntryFunction::Run() { |
| - NOTIMPLEMENTED(); |
| - return RespondNow(Error(kUnknownIdError)); |
| -} |
| - |
| -ExtensionFunction::ResponseAction FileSystemGetObservedEntriesFunction::Run() { |
| - NOTIMPLEMENTED(); |
| - return RespondNow(Error(kUnknownIdError)); |
| -} |
| - |
| -#if !defined(OS_CHROMEOS) |
| -ExtensionFunction::ResponseAction FileSystemRequestFileSystemFunction::Run() { |
| - using api::file_system::RequestFileSystem::Params; |
| - const std::unique_ptr<Params> params(Params::Create(*args_)); |
| - EXTENSION_FUNCTION_VALIDATE(params); |
| - |
| - NOTIMPLEMENTED(); |
| - return RespondNow(Error(kNotSupportedOnCurrentPlatformError)); |
| -} |
| - |
| -ExtensionFunction::ResponseAction FileSystemGetVolumeListFunction::Run() { |
| - NOTIMPLEMENTED(); |
| - return RespondNow(Error(kNotSupportedOnCurrentPlatformError)); |
| -} |
| -#else |
| - |
| -FileSystemRequestFileSystemFunction::FileSystemRequestFileSystemFunction() |
| - : chrome_details_(this) {} |
| - |
| -FileSystemRequestFileSystemFunction::~FileSystemRequestFileSystemFunction() {} |
| - |
| -ExtensionFunction::ResponseAction FileSystemRequestFileSystemFunction::Run() { |
| - using api::file_system::RequestFileSystem::Params; |
| - const std::unique_ptr<Params> params(Params::Create(*args_)); |
| - EXTENSION_FUNCTION_VALIDATE(params); |
| - |
| - // Only kiosk apps in kiosk sessions can use this API. |
| - // Additionally it is enabled for whitelisted component extensions and apps. |
| - file_system_api::ConsentProviderDelegate consent_provider_delegate( |
| - chrome_details_.GetProfile(), render_frame_host()); |
| - file_system_api::ConsentProvider consent_provider(&consent_provider_delegate); |
| - |
| - if (!consent_provider.IsGrantable(*extension())) |
| - return RespondNow(Error(kNotSupportedOnNonKioskSessionError)); |
| - |
| using file_manager::VolumeManager; |
| using file_manager::Volume; |
| - VolumeManager* const volume_manager = |
| - VolumeManager::Get(chrome_details_.GetProfile()); |
| + VolumeManager* const volume_manager = VolumeManager::Get(browser_context); |
| DCHECK(volume_manager); |
| - const bool writable = |
| - params->options.writable.get() && *params->options.writable.get(); |
| if (writable && |
| - !app_file_handler_util::HasFileSystemWritePermission(extension_.get())) { |
| - return RespondNow(Error(kRequiresFileSystemWriteError)); |
| + !app_file_handler_util::HasFileSystemWritePermission(&extension)) { |
| + error_callback.Run(kRequiresFileSystemWriteError); |
| + return; |
| } |
| base::WeakPtr<file_manager::Volume> volume = |
| - volume_manager->FindVolumeById(params->options.volume_id); |
| - if (!volume.get()) |
| - return RespondNow(Error(kVolumeNotFoundError)); |
| + volume_manager->FindVolumeById(volume_id); |
| + if (!volume.get()) { |
| + error_callback.Run(kVolumeNotFoundError); |
| + return; |
| + } |
| const GURL site = |
| - util::GetSiteForExtensionId(extension_id(), chrome_details_.GetProfile()); |
| + util::GetSiteForExtensionId(extension.id(), browser_context); |
| scoped_refptr<storage::FileSystemContext> file_system_context = |
| - content::BrowserContext::GetStoragePartitionForSite( |
| - chrome_details_.GetProfile(), site) |
| + content::BrowserContext::GetStoragePartitionForSite(browser_context, site) |
| ->GetFileSystemContext(); |
| storage::ExternalFileSystemBackend* const backend = |
| file_system_context->external_backend(); |
| DCHECK(backend); |
| base::FilePath virtual_path; |
| - if (!backend->GetVirtualPath(volume->mount_path(), &virtual_path)) |
| - return RespondNow(Error(kSecurityError)); |
| + if (!backend->GetVirtualPath(volume->mount_path(), &virtual_path)) { |
| + error_callback.Run(kSecurityError); |
| + return; |
| + } |
| + |
| + if (writable && (volume->is_read_only())) { |
| + error_callback.Run(kSecurityError); |
| + return; |
| + } |
| - if (writable && (volume->is_read_only())) |
| - return RespondNow(Error(kSecurityError)); |
| + const ConsentProvider::ConsentCallback& callback = base::Bind( |
| + &ChromeFileSystemDelegate::OnConsentReceived, base::Unretained(this), |
| + browser_context, requester, success_callback, error_callback, |
| + extension.id(), volume, writable); |
| - consent_provider.RequestConsent( |
| - *extension(), volume, writable, |
| - base::Bind(&FileSystemRequestFileSystemFunction::OnConsentReceived, this, |
| - volume, writable)); |
| - return RespondLater(); |
| + consent_provider.RequestConsent(extension, requester->render_frame_host(), |
| + volume, writable, callback); |
| } |
| -void FileSystemRequestFileSystemFunction::OnConsentReceived( |
| +void ChromeFileSystemDelegate::GetVolumeList( |
| + content::BrowserContext* browser_context, |
| + const VolumeListCallback& success_callback, |
| + const ErrorCallback& error_callback) { |
| + std::vector<file_system::Volume> result_volume_list; |
| + FillVolumeList(browser_context, &result_volume_list); |
| + |
| + success_callback.Run(result_volume_list); |
| +} |
| + |
| +void ChromeFileSystemDelegate::OnConsentReceived( |
| + content::BrowserContext* browser_context, |
| + scoped_refptr<UIThreadExtensionFunction> requester, |
| + const FileSystemCallback& success_callback, |
| + const ErrorCallback& error_callback, |
| + const std::string& extension_id, |
| const base::WeakPtr<file_manager::Volume>& volume, |
| bool writable, |
| ConsentProvider::Consent result) { |
| @@ -1123,18 +286,18 @@ void FileSystemRequestFileSystemFunction::OnConsentReceived( |
| using file_manager::Volume; |
| // Render frame host can be gone before this callback method is executed. |
| - if (!render_frame_host()) { |
| - Respond(Error("")); |
| + if (!requester->render_frame_host()) { |
| + error_callback.Run(std::string()); |
| return; |
| } |
| switch (result) { |
| case ConsentProvider::CONSENT_REJECTED: |
| - Respond(Error(kSecurityError)); |
| + error_callback.Run(kSecurityError); |
| return; |
| case ConsentProvider::CONSENT_IMPOSSIBLE: |
| - Respond(Error(kConsentImpossible)); |
| + error_callback.Run(kConsentImpossible); |
| return; |
| case ConsentProvider::CONSENT_GRANTED: |
| @@ -1142,15 +305,13 @@ void FileSystemRequestFileSystemFunction::OnConsentReceived( |
| } |
| if (!volume.get()) { |
| - Respond(Error(kVolumeNotFoundError)); |
| + error_callback.Run(kVolumeNotFoundError); |
| return; |
| } |
| - const GURL site = |
| - util::GetSiteForExtensionId(extension_id(), chrome_details_.GetProfile()); |
| + const GURL site = util::GetSiteForExtensionId(extension_id, browser_context); |
| scoped_refptr<storage::FileSystemContext> file_system_context = |
| - content::BrowserContext::GetStoragePartitionForSite( |
| - chrome_details_.GetProfile(), site) |
| + content::BrowserContext::GetStoragePartitionForSite(browser_context, site) |
| ->GetFileSystemContext(); |
| storage::ExternalFileSystemBackend* const backend = |
| file_system_context->external_backend(); |
| @@ -1158,7 +319,7 @@ void FileSystemRequestFileSystemFunction::OnConsentReceived( |
| base::FilePath virtual_path; |
| if (!backend->GetVirtualPath(volume->mount_path(), &virtual_path)) { |
| - Respond(Error(kSecurityError)); |
| + error_callback.Run(kSecurityError); |
| return; |
| } |
| @@ -1169,7 +330,7 @@ void FileSystemRequestFileSystemFunction::OnConsentReceived( |
| const storage::FileSystemURL original_url = |
| file_system_context->CreateCrackedFileSystemURL( |
| GURL(std::string(kExtensionScheme) + url::kStandardSchemeSeparator + |
| - extension_id()), |
| + extension_id), |
| storage::kFileSystemTypeExternal, virtual_path); |
| // Set a fixed register name, as the automatic one would leak the mount point |
| @@ -1181,64 +342,39 @@ void FileSystemRequestFileSystemFunction::OnConsentReceived( |
| std::string() /* file_system_id */, original_url.path(), |
| ®ister_name); |
| if (file_system_id.empty()) { |
| - Respond(Error(kSecurityError)); |
| + error_callback.Run(kSecurityError); |
| return; |
| } |
| - backend->GrantFileAccessToExtension(extension_->id(), virtual_path); |
| + backend->GrantFileAccessToExtension(extension_id, virtual_path); |
| // Grant file permissions to the renderer hosting component. |
| content::ChildProcessSecurityPolicy* policy = |
| content::ChildProcessSecurityPolicy::GetInstance(); |
| DCHECK(policy); |
| + const auto process_id = requester->render_frame_host()->GetProcess()->GetID(); |
| // Read-only permisisons. |
| - policy->GrantReadFile(render_frame_host()->GetProcess()->GetID(), |
| - volume->mount_path()); |
| - policy->GrantReadFileSystem(render_frame_host()->GetProcess()->GetID(), |
| - file_system_id); |
| + policy->GrantReadFile(process_id, volume->mount_path()); |
| + policy->GrantReadFileSystem(process_id, file_system_id); |
| // Additional write permissions. |
| if (writable) { |
| - policy->GrantCreateReadWriteFile(render_frame_host()->GetProcess()->GetID(), |
| - volume->mount_path()); |
| - policy->GrantCopyInto(render_frame_host()->GetProcess()->GetID(), |
| - volume->mount_path()); |
| - policy->GrantWriteFileSystem(render_frame_host()->GetProcess()->GetID(), |
| - file_system_id); |
| - policy->GrantDeleteFromFileSystem( |
| - render_frame_host()->GetProcess()->GetID(), file_system_id); |
| - policy->GrantCreateFileForFileSystem( |
| - render_frame_host()->GetProcess()->GetID(), file_system_id); |
| + policy->GrantCreateReadWriteFile(process_id, volume->mount_path()); |
| + policy->GrantCopyInto(process_id, volume->mount_path()); |
| + policy->GrantWriteFileSystem(process_id, file_system_id); |
| + policy->GrantDeleteFromFileSystem(process_id, file_system_id); |
| + policy->GrantCreateFileForFileSystem(process_id, file_system_id); |
| } |
| - std::unique_ptr<base::DictionaryValue> dict(new base::DictionaryValue()); |
| - dict->SetString("file_system_id", file_system_id); |
| - dict->SetString("file_system_path", register_name); |
| - |
| - Respond(OneArgument(std::move(dict))); |
| + success_callback.Run(file_system_id, register_name); |
| } |
| +#endif // defined(OS_CHROMEOS) |
| -FileSystemGetVolumeListFunction::FileSystemGetVolumeListFunction() |
| - : chrome_details_(this) {} |
| - |
| -FileSystemGetVolumeListFunction::~FileSystemGetVolumeListFunction() {} |
| - |
| -ExtensionFunction::ResponseAction FileSystemGetVolumeListFunction::Run() { |
| - // Only kiosk apps in kiosk sessions can use this API. |
| - // Additionally it is enabled for whitelisted component extensions and apps. |
| - file_system_api::ConsentProviderDelegate consent_provider_delegate( |
| - chrome_details_.GetProfile(), render_frame_host()); |
| - file_system_api::ConsentProvider consent_provider(&consent_provider_delegate); |
| - |
| - if (!consent_provider.IsGrantable(*extension())) |
| - return RespondNow(Error(kNotSupportedOnNonKioskSessionError)); |
| - std::vector<api::file_system::Volume> result_volume_list; |
| - FillVolumeList(chrome_details_.GetProfile(), &result_volume_list); |
| - |
| - return RespondNow(ArgumentList( |
| - api::file_system::GetVolumeList::Results::Create(result_volume_list))); |
| +std::unique_ptr<file_system_api::SavedFilesServiceDelegate> |
| +ChromeFileSystemDelegate::CreateSavedFilesServiceDelegate( |
| + content::BrowserContext* browser_context) { |
| + return base::MakeUnique<apps::SavedFilesServiceDelegateImpl>(browser_context); |
| } |
| -#endif |
| } // namespace extensions |