| 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
|
|
|