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 "chrome/browser/chromeos/app_mode/kiosk_app_manager.h" | |
| 61 #include "chrome/browser/chromeos/file_manager/filesystem_api_util.h" | 62 #include "chrome/browser/chromeos/file_manager/filesystem_api_util.h" |
| 63 #include "chrome/browser/chromeos/file_manager/volume_manager.h" | |
| 64 #include "components/user_manager/user_manager.h" | |
| 65 #include "extensions/common/manifest_handlers/kiosk_mode_info.h" | |
| 62 #endif | 66 #endif |
| 63 | 67 |
| 64 using apps::SavedFileEntry; | 68 using apps::SavedFileEntry; |
| 65 using apps::SavedFilesService; | 69 using apps::SavedFilesService; |
| 66 using storage::IsolatedContext; | 70 using storage::IsolatedContext; |
| 67 | 71 |
| 68 const char kInvalidCallingPage[] = "Invalid calling page. This function can't " | 72 const char kInvalidCallingPage[] = "Invalid calling page. This function can't " |
| 69 "be called from a background page."; | 73 "be called from a background page."; |
| 70 const char kUserCancelled[] = "User cancelled"; | 74 const char kUserCancelled[] = "User cancelled"; |
| 71 const char kWritableFileErrorFormat[] = "Error opening %s"; | 75 const char kWritableFileErrorFormat[] = "Error opening %s"; |
| 72 const char kRequiresFileSystemWriteError[] = | 76 const char kRequiresFileSystemWriteError[] = |
| 73 "Operation requires fileSystem.write permission"; | 77 "Operation requires fileSystem.write permission"; |
| 74 const char kRequiresFileSystemDirectoryError[] = | 78 const char kRequiresFileSystemDirectoryError[] = |
| 75 "Operation requires fileSystem.directory permission"; | 79 "Operation requires fileSystem.directory permission"; |
| 76 const char kMultipleUnsupportedError[] = | 80 const char kMultipleUnsupportedError[] = |
| 77 "acceptsMultiple: true is not supported for 'saveFile'"; | 81 "acceptsMultiple: true is not supported for 'saveFile'"; |
| 78 const char kUnknownIdError[] = "Unknown id"; | 82 const char kUnknownIdError[] = "Unknown id"; |
| 83 const char kVolumeNotFoundError[] = "Volume not found."; | |
| 84 const char kSecurityError[] = "Security error."; | |
| 85 const char kNotSupportedError[] = "Operation not supported."; | |
| 79 | 86 |
| 80 namespace file_system = extensions::api::file_system; | 87 namespace file_system = extensions::api::file_system; |
| 81 namespace ChooseEntry = file_system::ChooseEntry; | 88 namespace ChooseEntry = file_system::ChooseEntry; |
| 82 | 89 |
| 83 namespace { | 90 namespace { |
| 84 | 91 |
| 85 bool g_skip_picker_for_test = false; | 92 bool g_skip_picker_for_test = false; |
| 86 bool g_use_suggested_path_for_test = false; | 93 bool g_use_suggested_path_for_test = false; |
| 87 base::FilePath* g_path_to_be_picked_for_test; | 94 base::FilePath* g_path_to_be_picked_for_test; |
| 88 std::vector<base::FilePath>* g_paths_to_be_picked_for_test; | 95 std::vector<base::FilePath>* g_paths_to_be_picked_for_test; |
| (...skipping 898 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 987 error_ = kUnknownIdError; | 994 error_ = kUnknownIdError; |
| 988 return false; | 995 return false; |
| 989 } | 996 } |
| 990 | 997 |
| 991 bool FileSystemGetObservedEntriesFunction::RunSync() { | 998 bool FileSystemGetObservedEntriesFunction::RunSync() { |
| 992 NOTIMPLEMENTED(); | 999 NOTIMPLEMENTED(); |
| 993 error_ = kUnknownIdError; | 1000 error_ = kUnknownIdError; |
| 994 return false; | 1001 return false; |
| 995 } | 1002 } |
| 996 | 1003 |
| 1004 FileSystemRequestFileSystemFunction::FileSystemRequestFileSystemFunction() | |
| 1005 : chrome_details_(this) { | |
| 1006 } | |
| 1007 | |
| 1008 ExtensionFunction::ResponseAction FileSystemRequestFileSystemFunction::Run() { | |
| 1009 using extensions::api::file_system::RequestFileSystem::Params; | |
| 1010 const scoped_ptr<Params> params(Params::Create(*args_)); | |
| 1011 EXTENSION_FUNCTION_VALIDATE(params); | |
| 1012 | |
| 1013 #if !defined(OS_CHROMEOS) | |
| 1014 NOTIMPLEMENTED(); | |
| 1015 return RespondNow(Error(kNotSupportedError)); | |
| 1016 | |
| 1017 #else | |
| 1018 using file_manager::VolumeManager; | |
| 1019 using file_manager::VolumeInfo; | |
| 1020 VolumeManager* const volume_manager = | |
| 1021 VolumeManager::Get(chrome_details_.GetProfile()); | |
| 1022 DCHECK(volume_manager); | |
| 1023 | |
| 1024 const bool writable = | |
| 1025 params->options.writable.get() && *params->options.writable.get(); | |
| 1026 LOG(ERROR) << params->options.volume_id << ": " << writable; | |
|
hirono
2015/03/18 03:41:05
nit: Debug log.
mtomasz
2015/03/19 01:17:20
Done.
| |
| 1027 | |
| 1028 // Only kiosk apps in kiosk sessions can use this API. Additionally component | |
| 1029 // extensions and apps, which is not documented though. | |
| 1030 if ((!user_manager::UserManager::Get()->IsLoggedInAsKioskApp() || | |
| 1031 !KioskModeInfo::IsKioskEnabled(extension())) && | |
| 1032 extension()->location() != Manifest::COMPONENT) { | |
| 1033 return RespondNow(Error(kNotSupportedError)); | |
| 1034 } | |
| 1035 | |
| 1036 if (writable && | |
| 1037 !app_file_handler_util::HasFileSystemWritePermission(extension_.get())) { | |
| 1038 return RespondNow(Error(kRequiresFileSystemWriteError)); | |
| 1039 } | |
| 1040 | |
| 1041 VolumeInfo volume_info; | |
| 1042 if (!volume_manager->FindVolumeInfoById(params->options.volume_id, | |
| 1043 &volume_info)) { | |
| 1044 return RespondNow(Error(kVolumeNotFoundError)); | |
| 1045 } | |
| 1046 | |
| 1047 const GURL site = extensions::util::GetSiteForExtensionId( | |
| 1048 extension_id(), chrome_details_.GetProfile()); | |
| 1049 scoped_refptr<storage::FileSystemContext> file_system_context = | |
| 1050 content::BrowserContext::GetStoragePartitionForSite( | |
| 1051 chrome_details_.GetProfile(), site)->GetFileSystemContext(); | |
| 1052 storage::ExternalFileSystemBackend* const backend = | |
| 1053 file_system_context->external_backend(); | |
| 1054 DCHECK(backend); | |
| 1055 | |
| 1056 base::FilePath virtual_path; | |
| 1057 if (!backend->GetVirtualPath(volume_info.mount_path, &virtual_path)) | |
| 1058 return RespondNow(Error(kSecurityError)); | |
| 1059 | |
| 1060 if (writable && (volume_info.is_read_only)) | |
| 1061 return RespondNow(Error(kSecurityError)); | |
| 1062 | |
| 1063 const bool requires_consent = | |
| 1064 !chromeos::KioskAppManager::Get()->IsAutoLaunchEnabled() && | |
| 1065 extension()->location() != Manifest::COMPONENT; | |
| 1066 if (!requires_consent) { | |
| 1067 OnConsentReceived(volume_info.volume_id, writable, | |
|
hirono
2015/03/18 03:41:05
Just confirmation, if OnConsentRecived called dire
mtomasz
2015/03/19 01:17:20
Good catch. It works as RespondLater() simply retu
| |
| 1068 true); // Grant without user consent. | |
| 1069 } else { | |
| 1070 // TODO(mtomasz): Create a better display name, which is the most meaningful | |
| 1071 // to the user. | |
| 1072 const std::string display_name = !volume_info.volume_label.empty() | |
| 1073 ? volume_info.volume_label | |
| 1074 : volume_info.volume_id; | |
| 1075 RequestConsent( | |
| 1076 display_name, writable, | |
| 1077 base::Bind(&FileSystemRequestFileSystemFunction::OnConsentReceived, | |
| 1078 this, volume_info.volume_id, writable)); | |
| 1079 } | |
| 1080 | |
| 1081 return RespondLater(); | |
| 1082 #endif | |
| 1083 } | |
| 1084 | |
| 1085 void FileSystemRequestFileSystemFunction::RequestConsent( | |
| 1086 const std::string& display_name, | |
| 1087 bool writable, | |
| 1088 const base::Callback<void(bool)>& callback) { | |
| 1089 // TODO(mtomasz): Implement the consent dialog. | |
| 1090 callback.Run(false); | |
| 1091 } | |
| 1092 | |
| 1093 void FileSystemRequestFileSystemFunction::OnConsentReceived( | |
| 1094 const std::string& volume_id, | |
| 1095 bool writable, | |
| 1096 bool granted) { | |
| 1097 if (!granted) { | |
| 1098 SetError(kSecurityError); | |
| 1099 return; | |
| 1100 } | |
| 1101 | |
| 1102 #if defined(OS_CHROMEOS) | |
|
hirono
2015/03/18 03:41:05
How about enclosing entire RequsetContext and OnCo
mtomasz
2015/03/19 01:17:20
Done.
| |
| 1103 using file_manager::VolumeManager; | |
| 1104 using file_manager::VolumeInfo; | |
| 1105 | |
| 1106 // Fetch the volume again, in case it's gone by the time the permission is | |
| 1107 // granted. | |
| 1108 VolumeManager* const volume_manager = | |
| 1109 VolumeManager::Get(chrome_details_.GetProfile()); | |
| 1110 DCHECK(volume_manager); | |
| 1111 | |
| 1112 VolumeInfo volume_info; | |
| 1113 if (!volume_manager->FindVolumeInfoById(volume_id, &volume_info)) { | |
| 1114 SetError(kVolumeNotFoundError); | |
| 1115 SendResponse(false); | |
| 1116 return; | |
| 1117 } | |
| 1118 | |
| 1119 const GURL site = extensions::util::GetSiteForExtensionId( | |
| 1120 extension_id(), chrome_details_.GetProfile()); | |
| 1121 scoped_refptr<storage::FileSystemContext> file_system_context = | |
| 1122 content::BrowserContext::GetStoragePartitionForSite( | |
| 1123 chrome_details_.GetProfile(), site)->GetFileSystemContext(); | |
| 1124 storage::ExternalFileSystemBackend* const backend = | |
| 1125 file_system_context->external_backend(); | |
| 1126 DCHECK(backend); | |
| 1127 | |
| 1128 // The volume may be unmounted and remounted by the time we reach this logic. | |
| 1129 // TODO(mtomasz): Add a unique identifier to VolumeInfo to guarantee that the | |
| 1130 // permissions are granted to exactly that volume which was plugged in when | |
| 1131 // the dialog was shown. | |
| 1132 base::FilePath virtual_path; | |
| 1133 if (!backend->GetVirtualPath(volume_info.mount_path, &virtual_path)) { | |
| 1134 SetError(kSecurityError); | |
| 1135 SendResponse(false); | |
| 1136 return; | |
| 1137 } | |
| 1138 | |
| 1139 storage::IsolatedContext* const isolated_context = | |
| 1140 storage::IsolatedContext::GetInstance(); | |
| 1141 DCHECK(isolated_context); | |
| 1142 | |
| 1143 const storage::FileSystemURL original_url = | |
| 1144 file_system_context->CreateCrackedFileSystemURL( | |
| 1145 GURL("chrome-extension://" + extension_id()), | |
| 1146 storage::kFileSystemTypeExternal, virtual_path); | |
| 1147 | |
| 1148 std::string register_name = "fs"; | |
|
hirono
2015/03/18 03:41:05
Do we need to assign "fs"?
mtomasz
2015/03/19 01:17:20
Without it we would leak the mount point path, we
| |
| 1149 const std::string file_system_id = | |
| 1150 isolated_context->RegisterFileSystemForPath( | |
| 1151 storage::kFileSystemTypeNativeForPlatformApp, | |
| 1152 std::string() /* file_system_id */, original_url.path(), | |
| 1153 ®ister_name); | |
| 1154 if (file_system_id.empty()) { | |
| 1155 SetError(kSecurityError); | |
| 1156 SendResponse(false); | |
| 1157 return; | |
| 1158 } | |
| 1159 | |
| 1160 backend->GrantFileAccessToExtension(extension_->id(), virtual_path); | |
| 1161 | |
| 1162 // Grant file permissions to the renderer hosting component. | |
| 1163 content::ChildProcessSecurityPolicy* policy = | |
| 1164 content::ChildProcessSecurityPolicy::GetInstance(); | |
| 1165 DCHECK(policy); | |
| 1166 | |
| 1167 // Read-only permisisons. | |
| 1168 policy->GrantReadFile(render_view_host()->GetProcess()->GetID(), | |
| 1169 volume_info.mount_path); | |
| 1170 policy->GrantReadFileSystem(render_view_host()->GetProcess()->GetID(), | |
| 1171 file_system_id); | |
| 1172 | |
| 1173 // Additional write permissions. | |
| 1174 if (writable) { | |
| 1175 policy->GrantCreateReadWriteFile(render_view_host()->GetProcess()->GetID(), | |
| 1176 volume_info.mount_path); | |
| 1177 policy->GrantCopyInto(render_view_host()->GetProcess()->GetID(), | |
| 1178 volume_info.mount_path); | |
| 1179 policy->GrantWriteFileSystem(render_view_host()->GetProcess()->GetID(), | |
| 1180 file_system_id); | |
| 1181 policy->GrantDeleteFromFileSystem(render_view_host()->GetProcess()->GetID(), | |
| 1182 file_system_id); | |
| 1183 policy->GrantCreateFileForFileSystem( | |
| 1184 render_view_host()->GetProcess()->GetID(), file_system_id); | |
| 1185 } | |
| 1186 | |
| 1187 base::DictionaryValue* const dict = new base::DictionaryValue(); | |
| 1188 dict->SetString("file_system_id", file_system_id); | |
| 1189 dict->SetString("file_system_path", register_name); | |
| 1190 | |
| 1191 SetResult(dict); | |
| 1192 SendResponse(true); | |
| 1193 #endif | |
| 1194 } | |
| 1195 | |
| 997 } // namespace extensions | 1196 } // namespace extensions |
| OLD | NEW |