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 |