Chromium Code Reviews| OLD | NEW |
|---|---|
| 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 Loading... | |
| 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 Loading... | |
| 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 ®ister_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 |
| OLD | NEW |