| OLD | NEW |
| 1 // Copyright (c) 2013 The Chromium Authors. All rights reserved. | 1 // Copyright (c) 2013 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 "components/policy/core/common/cloud/resource_cache.h" | 5 #include "components/policy/core/common/cloud/resource_cache.h" |
| 6 | 6 |
| 7 #include "base/base64.h" | 7 #include "base/base64.h" |
| 8 #include "base/callback.h" | 8 #include "base/callback.h" |
| 9 #include "base/file_util.h" | 9 #include "base/file_util.h" |
| 10 #include "base/files/file_enumerator.h" | 10 #include "base/files/file_enumerator.h" |
| 11 #include "base/logging.h" | 11 #include "base/logging.h" |
| 12 #include "base/numerics/safe_conversions.h" | 12 #include "base/numerics/safe_conversions.h" |
| 13 #include "base/sequenced_task_runner.h" | 13 #include "base/sequenced_task_runner.h" |
| 14 #include "base/strings/string_util.h" | 14 #include "base/strings/string_util.h" |
| 15 | 15 |
| 16 namespace policy { | 16 namespace policy { |
| 17 | 17 |
| 18 namespace { | 18 namespace { |
| 19 | 19 |
| 20 // Verifies that |value| is not empty and encodes it into base64url format, | 20 // Verifies that |value| is not empty and encodes it into base64url format, |
| 21 // which is safe to use as a file name on all platforms. | 21 // which is safe to use as a file name on all platforms. |
| 22 bool Base64Encode(const std::string& value, std::string* encoded) { | 22 bool Base64UrlEncode(const std::string& value, std::string* encoded) { |
| 23 DCHECK(!value.empty()); | 23 DCHECK(!value.empty()); |
| 24 if (value.empty()) | 24 if (value.empty()) |
| 25 return false; | 25 return false; |
| 26 base::Base64Encode(value, encoded); | 26 base::Base64Encode(value, encoded); |
| 27 base::ReplaceChars(*encoded, "+", "-", encoded); | 27 base::ReplaceChars(*encoded, "+", "-", encoded); |
| 28 base::ReplaceChars(*encoded, "/", "_", encoded); | 28 base::ReplaceChars(*encoded, "/", "_", encoded); |
| 29 // Note: this encoding keeps the padding chars, though the "Baset64 with safe |
| 30 // URL alphabet" encoding trims them. See Base64UrlDecode below. |
| 29 return true; | 31 return true; |
| 30 } | 32 } |
| 31 | 33 |
| 32 // Decodes all elements of |input| from base64url format and stores the decoded | 34 // Decodes all elements of |input| from base64url format and stores the decoded |
| 33 // elements in |output|. | 35 // elements in |output|. |
| 34 bool Base64Encode(const std::set<std::string>& input, | 36 bool Base64UrlEncode(const std::set<std::string>& input, |
| 35 std::set<std::string>* output) { | 37 std::set<std::string>* output) { |
| 36 output->clear(); | 38 output->clear(); |
| 37 for (std::set<std::string>::const_iterator it = input.begin(); | 39 for (std::set<std::string>::const_iterator it = input.begin(); |
| 38 it != input.end(); ++it) { | 40 it != input.end(); ++it) { |
| 39 std::string encoded; | 41 std::string encoded; |
| 40 if (!Base64Encode(*it, &encoded)) { | 42 if (!Base64UrlEncode(*it, &encoded)) { |
| 41 output->clear(); | 43 output->clear(); |
| 42 return false; | 44 return false; |
| 43 } | 45 } |
| 44 output->insert(encoded); | 46 output->insert(encoded); |
| 45 } | 47 } |
| 46 return true; | 48 return true; |
| 47 } | 49 } |
| 48 | 50 |
| 49 // Decodes |encoded| from base64url format and verifies that the result is not | 51 // Decodes |encoded| from base64url format and verifies that the result is not |
| 50 // emtpy. | 52 // emtpy. |
| 51 bool Base64Decode(const std::string& encoded, std::string* value) { | 53 bool Base64UrlDecode(const std::string& encoded, std::string* value) { |
| 52 std::string buffer; | 54 std::string buffer; |
| 53 base::ReplaceChars(encoded, "-", "+", &buffer); | 55 base::ReplaceChars(encoded, "-", "+", &buffer); |
| 54 base::ReplaceChars(buffer, "_", "/", &buffer); | 56 base::ReplaceChars(buffer, "_", "/", &buffer); |
| 55 return base::Base64Decode(buffer, value) && !value->empty(); | 57 return base::Base64Decode(buffer, value) && !value->empty(); |
| 56 } | 58 } |
| 57 | 59 |
| 58 } // namespace | 60 } // namespace |
| 59 | 61 |
| 60 ResourceCache::ResourceCache( | 62 ResourceCache::ResourceCache( |
| 61 const base::FilePath& cache_dir, | 63 const base::FilePath& cache_dir, |
| (...skipping 51 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 113 | 115 |
| 114 base::FileEnumerator enumerator(key_path, false, base::FileEnumerator::FILES); | 116 base::FileEnumerator enumerator(key_path, false, base::FileEnumerator::FILES); |
| 115 for (base::FilePath path = enumerator.Next(); !path.empty(); | 117 for (base::FilePath path = enumerator.Next(); !path.empty(); |
| 116 path = enumerator.Next()) { | 118 path = enumerator.Next()) { |
| 117 const std::string encoded_subkey = path.BaseName().MaybeAsASCII(); | 119 const std::string encoded_subkey = path.BaseName().MaybeAsASCII(); |
| 118 std::string subkey; | 120 std::string subkey; |
| 119 std::string data; | 121 std::string data; |
| 120 // Only read from |subkey_path| if it is not a symlink and its name is | 122 // Only read from |subkey_path| if it is not a symlink and its name is |
| 121 // a base64-encoded string. | 123 // a base64-encoded string. |
| 122 if (!base::IsLink(path) && | 124 if (!base::IsLink(path) && |
| 123 Base64Decode(encoded_subkey, &subkey) && | 125 Base64UrlDecode(encoded_subkey, &subkey) && |
| 124 base::ReadFileToString(path, &data)) { | 126 base::ReadFileToString(path, &data)) { |
| 125 (*contents)[subkey].swap(data); | 127 (*contents)[subkey].swap(data); |
| 126 } | 128 } |
| 127 } | 129 } |
| 128 } | 130 } |
| 129 | 131 |
| 130 void ResourceCache::Delete(const std::string& key, const std::string& subkey) { | 132 void ResourceCache::Delete(const std::string& key, const std::string& subkey) { |
| 131 DCHECK(task_runner_->RunsTasksOnCurrentThread()); | 133 DCHECK(task_runner_->RunsTasksOnCurrentThread()); |
| 132 base::FilePath subkey_path; | 134 base::FilePath subkey_path; |
| 133 if (VerifyKeyPathAndGetSubkeyPath(key, false, subkey, &subkey_path)) | 135 if (VerifyKeyPathAndGetSubkeyPath(key, false, subkey, &subkey_path)) |
| (...skipping 18 matching lines...) Expand all Loading... |
| 152 base::FilePath key_path; | 154 base::FilePath key_path; |
| 153 if (!VerifyKeyPath(key, false, &key_path)) | 155 if (!VerifyKeyPath(key, false, &key_path)) |
| 154 return; | 156 return; |
| 155 | 157 |
| 156 base::FileEnumerator enumerator(key_path, false, base::FileEnumerator::FILES); | 158 base::FileEnumerator enumerator(key_path, false, base::FileEnumerator::FILES); |
| 157 for (base::FilePath subkey_path = enumerator.Next(); | 159 for (base::FilePath subkey_path = enumerator.Next(); |
| 158 !subkey_path.empty(); subkey_path = enumerator.Next()) { | 160 !subkey_path.empty(); subkey_path = enumerator.Next()) { |
| 159 std::string subkey; | 161 std::string subkey; |
| 160 // Delete files with invalid names, and files whose subkey doesn't pass the | 162 // Delete files with invalid names, and files whose subkey doesn't pass the |
| 161 // filter. | 163 // filter. |
| 162 if (!Base64Decode(subkey_path.BaseName().MaybeAsASCII(), &subkey) || | 164 if (!Base64UrlDecode(subkey_path.BaseName().MaybeAsASCII(), &subkey) || |
| 163 test.Run(subkey)) { | 165 test.Run(subkey)) { |
| 164 base::DeleteFile(subkey_path, true); | 166 base::DeleteFile(subkey_path, true); |
| 165 } | 167 } |
| 166 } | 168 } |
| 167 | 169 |
| 168 // Delete() does nothing if the directory given to it is not empty. Hence, the | 170 // Delete() does nothing if the directory given to it is not empty. Hence, the |
| 169 // call below deletes the directory representing |key| if all of its subkeys | 171 // call below deletes the directory representing |key| if all of its subkeys |
| 170 // were just removed and does nothing otherwise. | 172 // were just removed and does nothing otherwise. |
| 171 base::DeleteFile(key_path, false); | 173 base::DeleteFile(key_path, false); |
| 172 } | 174 } |
| 173 | 175 |
| 174 void ResourceCache::PurgeOtherKeys(const std::set<std::string>& keys_to_keep) { | 176 void ResourceCache::PurgeOtherKeys(const std::set<std::string>& keys_to_keep) { |
| 175 DCHECK(task_runner_->RunsTasksOnCurrentThread()); | 177 DCHECK(task_runner_->RunsTasksOnCurrentThread()); |
| 176 std::set<std::string> encoded_keys_to_keep; | 178 std::set<std::string> encoded_keys_to_keep; |
| 177 if (!Base64Encode(keys_to_keep, &encoded_keys_to_keep)) | 179 if (!Base64UrlEncode(keys_to_keep, &encoded_keys_to_keep)) |
| 178 return; | 180 return; |
| 179 | 181 |
| 180 base::FileEnumerator enumerator( | 182 base::FileEnumerator enumerator( |
| 181 cache_dir_, false, base::FileEnumerator::DIRECTORIES); | 183 cache_dir_, false, base::FileEnumerator::DIRECTORIES); |
| 182 for (base::FilePath path = enumerator.Next(); !path.empty(); | 184 for (base::FilePath path = enumerator.Next(); !path.empty(); |
| 183 path = enumerator.Next()) { | 185 path = enumerator.Next()) { |
| 184 const std::string name(path.BaseName().MaybeAsASCII()); | 186 const std::string name(path.BaseName().MaybeAsASCII()); |
| 185 if (encoded_keys_to_keep.find(name) == encoded_keys_to_keep.end()) | 187 if (encoded_keys_to_keep.find(name) == encoded_keys_to_keep.end()) |
| 186 base::DeleteFile(path, true); | 188 base::DeleteFile(path, true); |
| 187 } | 189 } |
| 188 } | 190 } |
| 189 | 191 |
| 190 void ResourceCache::PurgeOtherSubkeys( | 192 void ResourceCache::PurgeOtherSubkeys( |
| 191 const std::string& key, | 193 const std::string& key, |
| 192 const std::set<std::string>& subkeys_to_keep) { | 194 const std::set<std::string>& subkeys_to_keep) { |
| 193 DCHECK(task_runner_->RunsTasksOnCurrentThread()); | 195 DCHECK(task_runner_->RunsTasksOnCurrentThread()); |
| 194 base::FilePath key_path; | 196 base::FilePath key_path; |
| 195 if (!VerifyKeyPath(key, false, &key_path)) | 197 if (!VerifyKeyPath(key, false, &key_path)) |
| 196 return; | 198 return; |
| 197 | 199 |
| 198 std::set<std::string> encoded_subkeys_to_keep; | 200 std::set<std::string> encoded_subkeys_to_keep; |
| 199 if (!Base64Encode(subkeys_to_keep, &encoded_subkeys_to_keep)) | 201 if (!Base64UrlEncode(subkeys_to_keep, &encoded_subkeys_to_keep)) |
| 200 return; | 202 return; |
| 201 | 203 |
| 202 base::FileEnumerator enumerator(key_path, false, base::FileEnumerator::FILES); | 204 base::FileEnumerator enumerator(key_path, false, base::FileEnumerator::FILES); |
| 203 for (base::FilePath path = enumerator.Next(); !path.empty(); | 205 for (base::FilePath path = enumerator.Next(); !path.empty(); |
| 204 path = enumerator.Next()) { | 206 path = enumerator.Next()) { |
| 205 const std::string name(path.BaseName().MaybeAsASCII()); | 207 const std::string name(path.BaseName().MaybeAsASCII()); |
| 206 if (encoded_subkeys_to_keep.find(name) == encoded_subkeys_to_keep.end()) | 208 if (encoded_subkeys_to_keep.find(name) == encoded_subkeys_to_keep.end()) |
| 207 base::DeleteFile(path, false); | 209 base::DeleteFile(path, false); |
| 208 } | 210 } |
| 209 // Delete() does nothing if the directory given to it is not empty. Hence, the | 211 // Delete() does nothing if the directory given to it is not empty. Hence, the |
| 210 // call below deletes the directory representing |key| if all of its subkeys | 212 // call below deletes the directory representing |key| if all of its subkeys |
| 211 // were just removed and does nothing otherwise. | 213 // were just removed and does nothing otherwise. |
| 212 base::DeleteFile(key_path, false); | 214 base::DeleteFile(key_path, false); |
| 213 } | 215 } |
| 214 | 216 |
| 215 bool ResourceCache::VerifyKeyPath(const std::string& key, | 217 bool ResourceCache::VerifyKeyPath(const std::string& key, |
| 216 bool allow_create, | 218 bool allow_create, |
| 217 base::FilePath* path) { | 219 base::FilePath* path) { |
| 218 std::string encoded; | 220 std::string encoded; |
| 219 if (!Base64Encode(key, &encoded)) | 221 if (!Base64UrlEncode(key, &encoded)) |
| 220 return false; | 222 return false; |
| 221 *path = cache_dir_.AppendASCII(encoded); | 223 *path = cache_dir_.AppendASCII(encoded); |
| 222 return allow_create ? base::CreateDirectory(*path) : | 224 return allow_create ? base::CreateDirectory(*path) : |
| 223 base::DirectoryExists(*path); | 225 base::DirectoryExists(*path); |
| 224 } | 226 } |
| 225 | 227 |
| 226 bool ResourceCache::VerifyKeyPathAndGetSubkeyPath(const std::string& key, | 228 bool ResourceCache::VerifyKeyPathAndGetSubkeyPath(const std::string& key, |
| 227 bool allow_create_key, | 229 bool allow_create_key, |
| 228 const std::string& subkey, | 230 const std::string& subkey, |
| 229 base::FilePath* path) { | 231 base::FilePath* path) { |
| 230 base::FilePath key_path; | 232 base::FilePath key_path; |
| 231 std::string encoded; | 233 std::string encoded; |
| 232 if (!VerifyKeyPath(key, allow_create_key, &key_path) || | 234 if (!VerifyKeyPath(key, allow_create_key, &key_path) || |
| 233 !Base64Encode(subkey, &encoded)) { | 235 !Base64UrlEncode(subkey, &encoded)) { |
| 234 return false; | 236 return false; |
| 235 } | 237 } |
| 236 *path = key_path.AppendASCII(encoded); | 238 *path = key_path.AppendASCII(encoded); |
| 237 return true; | 239 return true; |
| 238 } | 240 } |
| 239 | 241 |
| 240 | 242 |
| 241 } // namespace policy | 243 } // namespace policy |
| OLD | NEW |