Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(80)

Side by Side Diff: chrome/browser/extensions/api/file_system/file_system_api.cc

Issue 985533004: Implement chrome.fileSystem.requestFileSystem(). (Closed) Base URL: https://chromium.googlesource.com/chromium/src.git@master
Patch Set: Addressed comments + fixed tests. Created 5 years, 9 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
OLDNEW
1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. 1 // Copyright (c) 2012 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be 2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file. 3 // found in the LICENSE file.
4 4
5 #include "chrome/browser/extensions/api/file_system/file_system_api.h" 5 #include "chrome/browser/extensions/api/file_system/file_system_api.h"
6 6
7 #include <set> 7 #include <set>
8 8
9 #include "apps/saved_files_service.h" 9 #include "apps/saved_files_service.h"
10 #include "base/bind.h" 10 #include "base/bind.h"
(...skipping 40 matching lines...) Expand 10 before | Expand all | Expand 10 after
51 #include "ui/base/l10n/l10n_util.h" 51 #include "ui/base/l10n/l10n_util.h"
52 #include "ui/shell_dialogs/select_file_dialog.h" 52 #include "ui/shell_dialogs/select_file_dialog.h"
53 #include "ui/shell_dialogs/selected_file_info.h" 53 #include "ui/shell_dialogs/selected_file_info.h"
54 54
55 #if defined(OS_MACOSX) 55 #if defined(OS_MACOSX)
56 #include <CoreFoundation/CoreFoundation.h> 56 #include <CoreFoundation/CoreFoundation.h>
57 #include "base/mac/foundation_util.h" 57 #include "base/mac/foundation_util.h"
58 #endif 58 #endif
59 59
60 #if defined(OS_CHROMEOS) 60 #if defined(OS_CHROMEOS)
61 #include "base/thread_task_runner_handle.h"
62 #include "chrome/browser/chromeos/app_mode/kiosk_app_manager.h"
61 #include "chrome/browser/chromeos/file_manager/filesystem_api_util.h" 63 #include "chrome/browser/chromeos/file_manager/filesystem_api_util.h"
64 #include "chrome/browser/chromeos/file_manager/volume_manager.h"
65 #include "components/user_manager/user_manager.h"
66 #include "extensions/common/constants.h"
67 #include "extensions/common/manifest_handlers/kiosk_mode_info.h"
68 #include "url/url_constants.h"
62 #endif 69 #endif
63 70
64 using apps::SavedFileEntry; 71 using apps::SavedFileEntry;
65 using apps::SavedFilesService; 72 using apps::SavedFilesService;
66 using storage::IsolatedContext; 73 using storage::IsolatedContext;
67 74
68 const char kInvalidCallingPage[] = "Invalid calling page. This function can't " 75 const char kInvalidCallingPage[] = "Invalid calling page. This function can't "
69 "be called from a background page."; 76 "be called from a background page.";
70 const char kUserCancelled[] = "User cancelled"; 77 const char kUserCancelled[] = "User cancelled";
71 const char kWritableFileErrorFormat[] = "Error opening %s"; 78 const char kWritableFileErrorFormat[] = "Error opening %s";
72 const char kRequiresFileSystemWriteError[] = 79 const char kRequiresFileSystemWriteError[] =
73 "Operation requires fileSystem.write permission"; 80 "Operation requires fileSystem.write permission";
74 const char kRequiresFileSystemDirectoryError[] = 81 const char kRequiresFileSystemDirectoryError[] =
75 "Operation requires fileSystem.directory permission"; 82 "Operation requires fileSystem.directory permission";
76 const char kMultipleUnsupportedError[] = 83 const char kMultipleUnsupportedError[] =
77 "acceptsMultiple: true is not supported for 'saveFile'"; 84 "acceptsMultiple: true is not supported for 'saveFile'";
78 const char kUnknownIdError[] = "Unknown id"; 85 const char kUnknownIdError[] = "Unknown id";
79 86
87 #if !defined(OS_CHROMEOS)
88 const char kNotSupportedOnCurrentPlatformError[] =
89 "Operation not supported on the current platform.";
90 #else
91 const char kNotSupportedOnNonKioskSessionError[] =
92 "Operation only supported for kiosk apps running in a kiosk session.";
93 const char kVolumeNotFoundError[] = "Volume not found.";
94 const char kSecurityError[] = "Security error.";
95 #endif
96
80 namespace file_system = extensions::api::file_system; 97 namespace file_system = extensions::api::file_system;
81 namespace ChooseEntry = file_system::ChooseEntry; 98 namespace ChooseEntry = file_system::ChooseEntry;
82 99
83 namespace { 100 namespace {
84 101
85 bool g_skip_picker_for_test = false; 102 bool g_skip_picker_for_test = false;
86 bool g_use_suggested_path_for_test = false; 103 bool g_use_suggested_path_for_test = false;
87 base::FilePath* g_path_to_be_picked_for_test; 104 base::FilePath* g_path_to_be_picked_for_test;
88 std::vector<base::FilePath>* g_paths_to_be_picked_for_test; 105 std::vector<base::FilePath>* g_paths_to_be_picked_for_test;
89 bool g_skip_directory_confirmation_for_test = false; 106 bool g_skip_directory_confirmation_for_test = false;
(...skipping 897 matching lines...) Expand 10 before | Expand all | Expand 10 after
987 error_ = kUnknownIdError; 1004 error_ = kUnknownIdError;
988 return false; 1005 return false;
989 } 1006 }
990 1007
991 bool FileSystemGetObservedEntriesFunction::RunSync() { 1008 bool FileSystemGetObservedEntriesFunction::RunSync() {
992 NOTIMPLEMENTED(); 1009 NOTIMPLEMENTED();
993 error_ = kUnknownIdError; 1010 error_ = kUnknownIdError;
994 return false; 1011 return false;
995 } 1012 }
996 1013
1014 FileSystemRequestFileSystemFunction::FileSystemRequestFileSystemFunction()
1015 : chrome_details_(this) {
1016 }
1017
1018 ExtensionFunction::ResponseAction FileSystemRequestFileSystemFunction::Run() {
1019 using extensions::api::file_system::RequestFileSystem::Params;
1020 const scoped_ptr<Params> params(Params::Create(*args_));
1021 EXTENSION_FUNCTION_VALIDATE(params);
1022
1023 #if !defined(OS_CHROMEOS)
1024 NOTIMPLEMENTED();
1025 return RespondNow(Error(kNotSupportedOnCurrentPlatformError));
1026
1027 #else
1028 // Only kiosk apps in kiosk sessions can use this API. Additionally component
1029 // extensions and apps, which is not documented though.
benwells 2015/03/20 02:43:58 So the logic is, this can be used in kiosk mode OR
mtomasz 2015/03/20 03:26:23 It's used by Files app, Gallery app, Audio player,
benwells 2015/03/20 04:09:29 Could you add a whitelist for these apps? This is
1030 if ((!user_manager::UserManager::Get()->IsLoggedInAsKioskApp() ||
1031 !KioskModeInfo::IsKioskEnabled(extension())) &&
1032 extension()->location() != Manifest::COMPONENT) {
1033 return RespondNow(Error(kNotSupportedOnNonKioskSessionError));
1034 }
1035
1036 using file_manager::VolumeManager;
1037 using file_manager::VolumeInfo;
1038 VolumeManager* const volume_manager =
1039 VolumeManager::Get(chrome_details_.GetProfile());
1040 DCHECK(volume_manager);
1041
1042 const bool writable =
1043 params->options.writable.get() && *params->options.writable.get();
1044 if (writable &&
1045 !app_file_handler_util::HasFileSystemWritePermission(extension_.get())) {
1046 return RespondNow(Error(kRequiresFileSystemWriteError));
1047 }
1048
1049 VolumeInfo volume_info;
1050 if (!volume_manager->FindVolumeInfoById(params->options.volume_id,
1051 &volume_info)) {
1052 return RespondNow(Error(kVolumeNotFoundError));
1053 }
1054
1055 const GURL site = extensions::util::GetSiteForExtensionId(
1056 extension_id(), chrome_details_.GetProfile());
1057 scoped_refptr<storage::FileSystemContext> file_system_context =
1058 content::BrowserContext::GetStoragePartitionForSite(
1059 chrome_details_.GetProfile(), site)->GetFileSystemContext();
1060 storage::ExternalFileSystemBackend* const backend =
1061 file_system_context->external_backend();
1062 DCHECK(backend);
1063
1064 base::FilePath virtual_path;
1065 if (!backend->GetVirtualPath(volume_info.mount_path, &virtual_path))
1066 return RespondNow(Error(kSecurityError));
1067
1068 if (writable && (volume_info.is_read_only))
1069 return RespondNow(Error(kSecurityError));
1070
1071 const bool requires_consent =
1072 !chromeos::KioskAppManager::Get()->IsAutoLaunchEnabled() &&
xiyuan 2015/03/20 03:03:12 This name is a bit misleading. IsAutoLaunchEnabled
mtomasz 2015/03/20 03:26:23 Good catch. I like using KioskAppManager::Get()->G
1073 extension()->location() != Manifest::COMPONENT;
1074 if (!requires_consent) {
1075 // Grant the permission without showing the dialog.
1076 base::ThreadTaskRunnerHandle::Get()->PostTask(
1077 FROM_HERE,
1078 base::Bind(&FileSystemRequestFileSystemFunction::OnConsentReceived,
1079 this, volume_info.volume_id, writable, true /* granted */));
1080 } else {
1081 // TODO(mtomasz): Create a better display name, which is the most meaningful
1082 // to the user.
1083 const std::string display_name = !volume_info.volume_label.empty()
1084 ? volume_info.volume_label
1085 : volume_info.volume_id;
1086 RequestConsent(
1087 display_name, writable,
1088 base::Bind(&FileSystemRequestFileSystemFunction::OnConsentReceived,
1089 this, volume_info.volume_id, writable));
1090 }
1091
1092 return RespondLater();
1093 #endif
1094 }
1095
1096 #if defined(OS_CHROMEOS)
1097 void FileSystemRequestFileSystemFunction::RequestConsent(
1098 const std::string& display_name,
1099 bool writable,
1100 const base::Callback<void(bool)>& callback) {
1101 // TODO(mtomasz): Implement the consent dialog.
1102 base::ThreadTaskRunnerHandle::Get()->PostTask(FROM_HERE,
1103 base::Bind(callback, false));
1104 }
1105
1106 void FileSystemRequestFileSystemFunction::OnConsentReceived(
1107 const std::string& volume_id,
1108 bool writable,
1109 bool granted) {
1110 using file_manager::VolumeManager;
1111 using file_manager::VolumeInfo;
1112
1113 if (!granted) {
1114 SetError(kSecurityError);
1115 SendResponse(false);
1116 return;
1117 }
1118
1119 // The volume may be unmounted and remounted by the time we reach this logic.
1120 // As for now, fetch the volume again, in case it's gone by the time the
1121 // permission is granted.
1122 // TODO(mtomasz): Add a unique identifier to VolumeInfo to guarantee that the
1123 // permissions are granted to exactly that volume which was plugged in when
1124 // the dialog was shown.
1125 VolumeManager* const volume_manager =
1126 VolumeManager::Get(chrome_details_.GetProfile());
1127 DCHECK(volume_manager);
1128
1129 VolumeInfo volume_info;
1130 if (!volume_manager->FindVolumeInfoById(volume_id, &volume_info)) {
1131 SetError(kVolumeNotFoundError);
1132 SendResponse(false);
1133 return;
1134 }
1135
1136 const GURL site = extensions::util::GetSiteForExtensionId(
1137 extension_id(), chrome_details_.GetProfile());
1138 scoped_refptr<storage::FileSystemContext> file_system_context =
1139 content::BrowserContext::GetStoragePartitionForSite(
1140 chrome_details_.GetProfile(), site)->GetFileSystemContext();
1141 storage::ExternalFileSystemBackend* const backend =
1142 file_system_context->external_backend();
1143 DCHECK(backend);
1144
1145 base::FilePath virtual_path;
1146 if (!backend->GetVirtualPath(volume_info.mount_path, &virtual_path)) {
1147 SetError(kSecurityError);
1148 SendResponse(false);
1149 return;
1150 }
1151
1152 storage::IsolatedContext* const isolated_context =
1153 storage::IsolatedContext::GetInstance();
1154 DCHECK(isolated_context);
1155
1156 const storage::FileSystemURL original_url =
1157 file_system_context->CreateCrackedFileSystemURL(
1158 GURL(std::string(extensions::kExtensionScheme) +
1159 url::kStandardSchemeSeparator + extension_id()),
1160 storage::kFileSystemTypeExternal, virtual_path);
1161
1162 // Set a fixed register name, as the automatic one would leak the mount point
1163 // directory.
1164 std::string register_name = "fs";
1165 const std::string file_system_id =
1166 isolated_context->RegisterFileSystemForPath(
1167 storage::kFileSystemTypeNativeForPlatformApp,
1168 std::string() /* file_system_id */, original_url.path(),
1169 &register_name);
1170 if (file_system_id.empty()) {
1171 SetError(kSecurityError);
1172 SendResponse(false);
1173 return;
1174 }
1175
1176 backend->GrantFileAccessToExtension(extension_->id(), virtual_path);
1177
1178 // Grant file permissions to the renderer hosting component.
1179 content::ChildProcessSecurityPolicy* policy =
1180 content::ChildProcessSecurityPolicy::GetInstance();
1181 DCHECK(policy);
1182
1183 // Read-only permisisons.
1184 policy->GrantReadFile(render_view_host()->GetProcess()->GetID(),
1185 volume_info.mount_path);
1186 policy->GrantReadFileSystem(render_view_host()->GetProcess()->GetID(),
1187 file_system_id);
1188
1189 // Additional write permissions.
1190 if (writable) {
1191 policy->GrantCreateReadWriteFile(render_view_host()->GetProcess()->GetID(),
1192 volume_info.mount_path);
1193 policy->GrantCopyInto(render_view_host()->GetProcess()->GetID(),
1194 volume_info.mount_path);
1195 policy->GrantWriteFileSystem(render_view_host()->GetProcess()->GetID(),
1196 file_system_id);
1197 policy->GrantDeleteFromFileSystem(render_view_host()->GetProcess()->GetID(),
1198 file_system_id);
1199 policy->GrantCreateFileForFileSystem(
1200 render_view_host()->GetProcess()->GetID(), file_system_id);
1201 }
1202
1203 base::DictionaryValue* const dict = new base::DictionaryValue();
1204 dict->SetString("file_system_id", file_system_id);
1205 dict->SetString("file_system_path", register_name);
1206
1207 SetResult(dict);
1208 SendResponse(true);
1209 }
1210 #endif
1211
997 } // namespace extensions 1212 } // namespace extensions
OLDNEW
« no previous file with comments | « chrome/browser/extensions/api/file_system/file_system_api.h ('k') | chrome/common/extensions/api/_permission_features.json » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698