12a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)// Copyright (c) 2013 The Chromium Authors. All rights reserved. 22a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)// Use of this source code is governed by a BSD-style license that can be 32a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)// found in the LICENSE file. 42a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 5a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)#include "components/policy/core/common/cloud/resource_cache.h" 62a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 7eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch#include "base/base64.h" 8f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)#include "base/callback.h" 9eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch#include "base/files/file_enumerator.h" 101320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci#include "base/files/file_util.h" 112a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#include "base/logging.h" 125d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)#include "base/numerics/safe_conversions.h" 13d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)#include "base/sequenced_task_runner.h" 14868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)#include "base/strings/string_util.h" 152a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 162a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)namespace policy { 172a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 18eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdochnamespace { 19eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch 20eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch// Verifies that |value| is not empty and encodes it into base64url format, 21eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch// which is safe to use as a file name on all platforms. 225c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liubool Base64UrlEncode(const std::string& value, std::string* encoded) { 23eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch DCHECK(!value.empty()); 24a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) if (value.empty()) 25eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch return false; 26a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) base::Base64Encode(value, encoded); 27a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) base::ReplaceChars(*encoded, "+", "-", encoded); 28a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) base::ReplaceChars(*encoded, "/", "_", encoded); 295c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu // Note: this encoding keeps the padding chars, though the "Baset64 with safe 305c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu // URL alphabet" encoding trims them. See Base64UrlDecode below. 31eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch return true; 32eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch} 33eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch 349ab5563a3196760eb381d102cbb2bc0f7abc6a50Ben Murdoch// Decodes all elements of |input| from base64url format and stores the decoded 359ab5563a3196760eb381d102cbb2bc0f7abc6a50Ben Murdoch// elements in |output|. 365c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liubool Base64UrlEncode(const std::set<std::string>& input, 375c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu std::set<std::string>* output) { 389ab5563a3196760eb381d102cbb2bc0f7abc6a50Ben Murdoch output->clear(); 399ab5563a3196760eb381d102cbb2bc0f7abc6a50Ben Murdoch for (std::set<std::string>::const_iterator it = input.begin(); 409ab5563a3196760eb381d102cbb2bc0f7abc6a50Ben Murdoch it != input.end(); ++it) { 419ab5563a3196760eb381d102cbb2bc0f7abc6a50Ben Murdoch std::string encoded; 425c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu if (!Base64UrlEncode(*it, &encoded)) { 439ab5563a3196760eb381d102cbb2bc0f7abc6a50Ben Murdoch output->clear(); 449ab5563a3196760eb381d102cbb2bc0f7abc6a50Ben Murdoch return false; 459ab5563a3196760eb381d102cbb2bc0f7abc6a50Ben Murdoch } 469ab5563a3196760eb381d102cbb2bc0f7abc6a50Ben Murdoch output->insert(encoded); 479ab5563a3196760eb381d102cbb2bc0f7abc6a50Ben Murdoch } 489ab5563a3196760eb381d102cbb2bc0f7abc6a50Ben Murdoch return true; 499ab5563a3196760eb381d102cbb2bc0f7abc6a50Ben Murdoch} 509ab5563a3196760eb381d102cbb2bc0f7abc6a50Ben Murdoch 51eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch// Decodes |encoded| from base64url format and verifies that the result is not 52eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch// emtpy. 535c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liubool Base64UrlDecode(const std::string& encoded, std::string* value) { 54eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch std::string buffer; 55a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) base::ReplaceChars(encoded, "-", "+", &buffer); 56a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) base::ReplaceChars(buffer, "_", "/", &buffer); 57eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch return base::Base64Decode(buffer, value) && !value->empty(); 58eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch} 59eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch 60eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch} // namespace 61eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch 62d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)ResourceCache::ResourceCache( 63d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles) const base::FilePath& cache_dir, 64d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles) scoped_refptr<base::SequencedTaskRunner> task_runner) 65d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles) : cache_dir_(cache_dir), 66d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles) task_runner_(task_runner) { 672a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)} 682a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 692a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)ResourceCache::~ResourceCache() { 70d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles) DCHECK(task_runner_->RunsTasksOnCurrentThread()); 712a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)} 722a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 732a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)bool ResourceCache::Store(const std::string& key, 742a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) const std::string& subkey, 752a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) const std::string& data) { 76d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles) DCHECK(task_runner_->RunsTasksOnCurrentThread()); 77eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch base::FilePath subkey_path; 78eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch // Delete the file before writing to it. This ensures that the write does not 79eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch // follow a symlink planted at |subkey_path|, clobbering a file outside the 80eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch // cache directory. The mechanism is meant to foil file-system-level attacks 81eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch // where a symlink is planted in the cache directory before Chrome has 82eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch // started. An attacker controlling a process running concurrently with Chrome 83eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch // would be able to race against the protection by re-creating the symlink 84eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch // between these two calls. There is nothing in file_util that could be used 85eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch // to protect against such races, especially as the cache is cross-platform 86eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch // and therefore cannot use any POSIX-only tricks. 875d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) int size = base::checked_cast<int>(data.size()); 88eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch return VerifyKeyPathAndGetSubkeyPath(key, true, subkey, &subkey_path) && 897dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch base::DeleteFile(subkey_path, false) && 90a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) (base::WriteFile(subkey_path, data.data(), size) == size); 912a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)} 922a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 932a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)bool ResourceCache::Load(const std::string& key, 942a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) const std::string& subkey, 952a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) std::string* data) { 96d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles) DCHECK(task_runner_->RunsTasksOnCurrentThread()); 97eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch base::FilePath subkey_path; 98eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch // Only read from |subkey_path| if it is not a symlink. 99eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch if (!VerifyKeyPathAndGetSubkeyPath(key, false, subkey, &subkey_path) || 100a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) base::IsLink(subkey_path)) { 1012a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) return false; 102eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch } 103eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch data->clear(); 10458537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles) return base::ReadFileToString(subkey_path, data); 1052a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)} 1062a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 1072a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)void ResourceCache::LoadAllSubkeys( 1082a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) const std::string& key, 1092a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) std::map<std::string, std::string>* contents) { 110d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles) DCHECK(task_runner_->RunsTasksOnCurrentThread()); 1112a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) contents->clear(); 112eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch base::FilePath key_path; 113eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch if (!VerifyKeyPath(key, false, &key_path)) 114eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch return; 1152a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 116eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch base::FileEnumerator enumerator(key_path, false, base::FileEnumerator::FILES); 117eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch for (base::FilePath path = enumerator.Next(); !path.empty(); 118eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch path = enumerator.Next()) { 119eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch const std::string encoded_subkey = path.BaseName().MaybeAsASCII(); 120eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch std::string subkey; 121eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch std::string data; 122eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch // Only read from |subkey_path| if it is not a symlink and its name is 123eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch // a base64-encoded string. 124a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) if (!base::IsLink(path) && 1255c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu Base64UrlDecode(encoded_subkey, &subkey) && 12658537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles) base::ReadFileToString(path, &data)) { 127eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch (*contents)[subkey].swap(data); 128eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch } 1292a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) } 1302a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)} 1312a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 1322a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)void ResourceCache::Delete(const std::string& key, const std::string& subkey) { 133d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles) DCHECK(task_runner_->RunsTasksOnCurrentThread()); 134eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch base::FilePath subkey_path; 135eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch if (VerifyKeyPathAndGetSubkeyPath(key, false, subkey, &subkey_path)) 1367dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch base::DeleteFile(subkey_path, false); 137eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch // Delete() does nothing if the directory given to it is not empty. Hence, the 138eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch // call below deletes the directory representing |key| if its last subkey was 139eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch // just removed and does nothing otherwise. 1407dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch base::DeleteFile(subkey_path.DirName(), false); 1412a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)} 1422a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 143f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)void ResourceCache::Clear(const std::string& key) { 144f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) DCHECK(task_runner_->RunsTasksOnCurrentThread()); 145f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) base::FilePath key_path; 146f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) if (VerifyKeyPath(key, false, &key_path)) 147f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) base::DeleteFile(key_path, true); 148f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)} 149f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) 150f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)void ResourceCache::FilterSubkeys(const std::string& key, 151f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) const SubkeyFilter& test) { 152f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) DCHECK(task_runner_->RunsTasksOnCurrentThread()); 153f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) 154f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) base::FilePath key_path; 155f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) if (!VerifyKeyPath(key, false, &key_path)) 156f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) return; 157f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) 158f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) base::FileEnumerator enumerator(key_path, false, base::FileEnumerator::FILES); 159f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) for (base::FilePath subkey_path = enumerator.Next(); 160f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) !subkey_path.empty(); subkey_path = enumerator.Next()) { 161f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) std::string subkey; 162f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) // Delete files with invalid names, and files whose subkey doesn't pass the 163f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) // filter. 1645c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu if (!Base64UrlDecode(subkey_path.BaseName().MaybeAsASCII(), &subkey) || 165f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) test.Run(subkey)) { 166f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) base::DeleteFile(subkey_path, true); 167f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) } 168f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) } 169f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) 170f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) // Delete() does nothing if the directory given to it is not empty. Hence, the 171f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) // call below deletes the directory representing |key| if all of its subkeys 172f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) // were just removed and does nothing otherwise. 173f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) base::DeleteFile(key_path, false); 174f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)} 175f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) 1769ab5563a3196760eb381d102cbb2bc0f7abc6a50Ben Murdochvoid ResourceCache::PurgeOtherKeys(const std::set<std::string>& keys_to_keep) { 177d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles) DCHECK(task_runner_->RunsTasksOnCurrentThread()); 1789ab5563a3196760eb381d102cbb2bc0f7abc6a50Ben Murdoch std::set<std::string> encoded_keys_to_keep; 1795c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu if (!Base64UrlEncode(keys_to_keep, &encoded_keys_to_keep)) 1809ab5563a3196760eb381d102cbb2bc0f7abc6a50Ben Murdoch return; 1819ab5563a3196760eb381d102cbb2bc0f7abc6a50Ben Murdoch 1829ab5563a3196760eb381d102cbb2bc0f7abc6a50Ben Murdoch base::FileEnumerator enumerator( 1839ab5563a3196760eb381d102cbb2bc0f7abc6a50Ben Murdoch cache_dir_, false, base::FileEnumerator::DIRECTORIES); 1849ab5563a3196760eb381d102cbb2bc0f7abc6a50Ben Murdoch for (base::FilePath path = enumerator.Next(); !path.empty(); 1859ab5563a3196760eb381d102cbb2bc0f7abc6a50Ben Murdoch path = enumerator.Next()) { 1869ab5563a3196760eb381d102cbb2bc0f7abc6a50Ben Murdoch const std::string name(path.BaseName().MaybeAsASCII()); 1879ab5563a3196760eb381d102cbb2bc0f7abc6a50Ben Murdoch if (encoded_keys_to_keep.find(name) == encoded_keys_to_keep.end()) 1889ab5563a3196760eb381d102cbb2bc0f7abc6a50Ben Murdoch base::DeleteFile(path, true); 1899ab5563a3196760eb381d102cbb2bc0f7abc6a50Ben Murdoch } 1909ab5563a3196760eb381d102cbb2bc0f7abc6a50Ben Murdoch} 1919ab5563a3196760eb381d102cbb2bc0f7abc6a50Ben Murdoch 1922a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)void ResourceCache::PurgeOtherSubkeys( 1932a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) const std::string& key, 1942a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) const std::set<std::string>& subkeys_to_keep) { 195d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles) DCHECK(task_runner_->RunsTasksOnCurrentThread()); 196eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch base::FilePath key_path; 197eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch if (!VerifyKeyPath(key, false, &key_path)) 1982a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) return; 1992a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 200eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch std::set<std::string> encoded_subkeys_to_keep; 2015c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu if (!Base64UrlEncode(subkeys_to_keep, &encoded_subkeys_to_keep)) 2029ab5563a3196760eb381d102cbb2bc0f7abc6a50Ben Murdoch return; 2032a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 204eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch base::FileEnumerator enumerator(key_path, false, base::FileEnumerator::FILES); 205eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch for (base::FilePath path = enumerator.Next(); !path.empty(); 206eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch path = enumerator.Next()) { 207eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch const std::string name(path.BaseName().MaybeAsASCII()); 208eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch if (encoded_subkeys_to_keep.find(name) == encoded_subkeys_to_keep.end()) 2097dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch base::DeleteFile(path, false); 2102a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) } 211eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch // Delete() does nothing if the directory given to it is not empty. Hence, the 212eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch // call below deletes the directory representing |key| if all of its subkeys 213eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch // were just removed and does nothing otherwise. 2147dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch base::DeleteFile(key_path, false); 2152a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)} 2162a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 217eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdochbool ResourceCache::VerifyKeyPath(const std::string& key, 218eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch bool allow_create, 219eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch base::FilePath* path) { 220eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch std::string encoded; 2215c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu if (!Base64UrlEncode(key, &encoded)) 222eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch return false; 223eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch *path = cache_dir_.AppendASCII(encoded); 224a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) return allow_create ? base::CreateDirectory(*path) : 2257dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch base::DirectoryExists(*path); 2262a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)} 2272a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 228eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdochbool ResourceCache::VerifyKeyPathAndGetSubkeyPath(const std::string& key, 229eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch bool allow_create_key, 230eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch const std::string& subkey, 231eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch base::FilePath* path) { 232eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch base::FilePath key_path; 233eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch std::string encoded; 234eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch if (!VerifyKeyPath(key, allow_create_key, &key_path) || 2355c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu !Base64UrlEncode(subkey, &encoded)) { 236eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch return false; 2372a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) } 238eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch *path = key_path.AppendASCII(encoded); 239eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch return true; 2402a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)} 2412a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 242eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch 2432a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)} // namespace policy 244