Index: chrome/browser/policy/cloud/resource_cache.cc |
diff --git a/chrome/browser/policy/cloud/resource_cache.cc b/chrome/browser/policy/cloud/resource_cache.cc |
deleted file mode 100644 |
index 0ee7e3a689eb017b92c6e2949649f64293919eb4..0000000000000000000000000000000000000000 |
--- a/chrome/browser/policy/cloud/resource_cache.cc |
+++ /dev/null |
@@ -1,240 +0,0 @@ |
-// Copyright (c) 2013 The Chromium Authors. All rights reserved. |
-// Use of this source code is governed by a BSD-style license that can be |
-// found in the LICENSE file. |
- |
-#include "chrome/browser/policy/cloud/resource_cache.h" |
- |
-#include "base/base64.h" |
-#include "base/callback.h" |
-#include "base/file_util.h" |
-#include "base/files/file_enumerator.h" |
-#include "base/logging.h" |
-#include "base/safe_numerics.h" |
-#include "base/sequenced_task_runner.h" |
-#include "base/strings/string_util.h" |
- |
-namespace policy { |
- |
-namespace { |
- |
-// Verifies that |value| is not empty and encodes it into base64url format, |
-// which is safe to use as a file name on all platforms. |
-bool Base64Encode(const std::string& value, std::string* encoded) { |
- DCHECK(!value.empty()); |
- if (value.empty() || !base::Base64Encode(value, encoded)) |
- return false; |
- base::ReplaceChars(*encoded, "+", "-", encoded); |
- base::ReplaceChars(*encoded, "/", "_", encoded); |
- return true; |
-} |
- |
-// Decodes all elements of |input| from base64url format and stores the decoded |
-// elements in |output|. |
-bool Base64Encode(const std::set<std::string>& input, |
- std::set<std::string>* output) { |
- output->clear(); |
- for (std::set<std::string>::const_iterator it = input.begin(); |
- it != input.end(); ++it) { |
- std::string encoded; |
- if (!Base64Encode(*it, &encoded)) { |
- output->clear(); |
- return false; |
- } |
- output->insert(encoded); |
- } |
- return true; |
-} |
- |
-// Decodes |encoded| from base64url format and verifies that the result is not |
-// emtpy. |
-bool Base64Decode(const std::string& encoded, std::string* value) { |
- std::string buffer; |
- base::ReplaceChars(encoded, "-", "+", &buffer); |
- base::ReplaceChars(buffer, "_", "/", &buffer); |
- return base::Base64Decode(buffer, value) && !value->empty(); |
-} |
- |
-} // namespace |
- |
-ResourceCache::ResourceCache( |
- const base::FilePath& cache_dir, |
- scoped_refptr<base::SequencedTaskRunner> task_runner) |
- : cache_dir_(cache_dir), |
- task_runner_(task_runner) { |
-} |
- |
-ResourceCache::~ResourceCache() { |
- DCHECK(task_runner_->RunsTasksOnCurrentThread()); |
-} |
- |
-bool ResourceCache::Store(const std::string& key, |
- const std::string& subkey, |
- const std::string& data) { |
- DCHECK(task_runner_->RunsTasksOnCurrentThread()); |
- base::FilePath subkey_path; |
- // Delete the file before writing to it. This ensures that the write does not |
- // follow a symlink planted at |subkey_path|, clobbering a file outside the |
- // cache directory. The mechanism is meant to foil file-system-level attacks |
- // where a symlink is planted in the cache directory before Chrome has |
- // started. An attacker controlling a process running concurrently with Chrome |
- // would be able to race against the protection by re-creating the symlink |
- // between these two calls. There is nothing in file_util that could be used |
- // to protect against such races, especially as the cache is cross-platform |
- // and therefore cannot use any POSIX-only tricks. |
- int size = base::checked_numeric_cast<int>(data.size()); |
- return VerifyKeyPathAndGetSubkeyPath(key, true, subkey, &subkey_path) && |
- base::DeleteFile(subkey_path, false) && |
- (file_util::WriteFile(subkey_path, data.data(), size) == size); |
-} |
- |
-bool ResourceCache::Load(const std::string& key, |
- const std::string& subkey, |
- std::string* data) { |
- DCHECK(task_runner_->RunsTasksOnCurrentThread()); |
- base::FilePath subkey_path; |
- // Only read from |subkey_path| if it is not a symlink. |
- if (!VerifyKeyPathAndGetSubkeyPath(key, false, subkey, &subkey_path) || |
- base::IsLink(subkey_path)) { |
- return false; |
- } |
- data->clear(); |
- return base::ReadFileToString(subkey_path, data); |
-} |
- |
-void ResourceCache::LoadAllSubkeys( |
- const std::string& key, |
- std::map<std::string, std::string>* contents) { |
- DCHECK(task_runner_->RunsTasksOnCurrentThread()); |
- contents->clear(); |
- base::FilePath key_path; |
- if (!VerifyKeyPath(key, false, &key_path)) |
- return; |
- |
- base::FileEnumerator enumerator(key_path, false, base::FileEnumerator::FILES); |
- for (base::FilePath path = enumerator.Next(); !path.empty(); |
- path = enumerator.Next()) { |
- const std::string encoded_subkey = path.BaseName().MaybeAsASCII(); |
- std::string subkey; |
- std::string data; |
- // Only read from |subkey_path| if it is not a symlink and its name is |
- // a base64-encoded string. |
- if (!base::IsLink(path) && |
- Base64Decode(encoded_subkey, &subkey) && |
- base::ReadFileToString(path, &data)) { |
- (*contents)[subkey].swap(data); |
- } |
- } |
-} |
- |
-void ResourceCache::Delete(const std::string& key, const std::string& subkey) { |
- DCHECK(task_runner_->RunsTasksOnCurrentThread()); |
- base::FilePath subkey_path; |
- if (VerifyKeyPathAndGetSubkeyPath(key, false, subkey, &subkey_path)) |
- base::DeleteFile(subkey_path, false); |
- // Delete() does nothing if the directory given to it is not empty. Hence, the |
- // call below deletes the directory representing |key| if its last subkey was |
- // just removed and does nothing otherwise. |
- base::DeleteFile(subkey_path.DirName(), false); |
-} |
- |
-void ResourceCache::Clear(const std::string& key) { |
- DCHECK(task_runner_->RunsTasksOnCurrentThread()); |
- base::FilePath key_path; |
- if (VerifyKeyPath(key, false, &key_path)) |
- base::DeleteFile(key_path, true); |
-} |
- |
-void ResourceCache::FilterSubkeys(const std::string& key, |
- const SubkeyFilter& test) { |
- DCHECK(task_runner_->RunsTasksOnCurrentThread()); |
- |
- base::FilePath key_path; |
- if (!VerifyKeyPath(key, false, &key_path)) |
- return; |
- |
- base::FileEnumerator enumerator(key_path, false, base::FileEnumerator::FILES); |
- for (base::FilePath subkey_path = enumerator.Next(); |
- !subkey_path.empty(); subkey_path = enumerator.Next()) { |
- std::string subkey; |
- // Delete files with invalid names, and files whose subkey doesn't pass the |
- // filter. |
- if (!Base64Decode(subkey_path.BaseName().MaybeAsASCII(), &subkey) || |
- test.Run(subkey)) { |
- base::DeleteFile(subkey_path, true); |
- } |
- } |
- |
- // Delete() does nothing if the directory given to it is not empty. Hence, the |
- // call below deletes the directory representing |key| if all of its subkeys |
- // were just removed and does nothing otherwise. |
- base::DeleteFile(key_path, false); |
-} |
- |
-void ResourceCache::PurgeOtherKeys(const std::set<std::string>& keys_to_keep) { |
- DCHECK(task_runner_->RunsTasksOnCurrentThread()); |
- std::set<std::string> encoded_keys_to_keep; |
- if (!Base64Encode(keys_to_keep, &encoded_keys_to_keep)) |
- return; |
- |
- base::FileEnumerator enumerator( |
- cache_dir_, false, base::FileEnumerator::DIRECTORIES); |
- for (base::FilePath path = enumerator.Next(); !path.empty(); |
- path = enumerator.Next()) { |
- const std::string name(path.BaseName().MaybeAsASCII()); |
- if (encoded_keys_to_keep.find(name) == encoded_keys_to_keep.end()) |
- base::DeleteFile(path, true); |
- } |
-} |
- |
-void ResourceCache::PurgeOtherSubkeys( |
- const std::string& key, |
- const std::set<std::string>& subkeys_to_keep) { |
- DCHECK(task_runner_->RunsTasksOnCurrentThread()); |
- base::FilePath key_path; |
- if (!VerifyKeyPath(key, false, &key_path)) |
- return; |
- |
- std::set<std::string> encoded_subkeys_to_keep; |
- if (!Base64Encode(subkeys_to_keep, &encoded_subkeys_to_keep)) |
- return; |
- |
- base::FileEnumerator enumerator(key_path, false, base::FileEnumerator::FILES); |
- for (base::FilePath path = enumerator.Next(); !path.empty(); |
- path = enumerator.Next()) { |
- const std::string name(path.BaseName().MaybeAsASCII()); |
- if (encoded_subkeys_to_keep.find(name) == encoded_subkeys_to_keep.end()) |
- base::DeleteFile(path, false); |
- } |
- // Delete() does nothing if the directory given to it is not empty. Hence, the |
- // call below deletes the directory representing |key| if all of its subkeys |
- // were just removed and does nothing otherwise. |
- base::DeleteFile(key_path, false); |
-} |
- |
-bool ResourceCache::VerifyKeyPath(const std::string& key, |
- bool allow_create, |
- base::FilePath* path) { |
- std::string encoded; |
- if (!Base64Encode(key, &encoded)) |
- return false; |
- *path = cache_dir_.AppendASCII(encoded); |
- return allow_create ? base::CreateDirectory(*path) : |
- base::DirectoryExists(*path); |
-} |
- |
-bool ResourceCache::VerifyKeyPathAndGetSubkeyPath(const std::string& key, |
- bool allow_create_key, |
- const std::string& subkey, |
- base::FilePath* path) { |
- base::FilePath key_path; |
- std::string encoded; |
- if (!VerifyKeyPath(key, allow_create_key, &key_path) || |
- !Base64Encode(subkey, &encoded)) { |
- return false; |
- } |
- *path = key_path.AppendASCII(encoded); |
- return true; |
-} |
- |
- |
-} // namespace policy |