// Copyright 2016 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 "extensions/browser/value_store/legacy_value_store_factory.h" #include #include "base/files/file_enumerator.h" #include "base/files/file_util.h" #include "content/public/browser/browser_thread.h" #include "extensions/browser/value_store/leveldb_value_store.h" #include "extensions/common/constants.h" #include "extensions/common/extension.h" using base::AutoLock; using content::BrowserThread; namespace { // Statistics are logged to UMA with these strings as part of histogram name. // They can all be found under Extensions.Database.Open.. Changing this // needs to synchronize with histograms.xml, AND will also become incompatible // with older browsers still reporting the previous values. const char kSettingsDatabaseUMAClientName[] = "Settings"; const char kRulesDatabaseUMAClientName[] = "Rules"; const char kStateDatabaseUMAClientName[] = "State"; bool ValidDBExists(const base::FilePath& path) { // TODO(cmumford): Enhance to detect if dir contains valid database. return base::DirectoryExists(path); } } // namespace namespace extensions { // // ModelSettings // LegacyValueStoreFactory::ModelSettings::ModelSettings( const base::FilePath& data_path) : data_path_(data_path) {} base::FilePath LegacyValueStoreFactory::ModelSettings::GetDBPath( const ExtensionId& extension_id) const { return data_path_.AppendASCII(extension_id); } bool LegacyValueStoreFactory::ModelSettings::DeleteData( const ExtensionId& extension_id) { return base::DeleteFile(GetDBPath(extension_id), true /* recursive */); } bool LegacyValueStoreFactory::ModelSettings::DataExists( const ExtensionId& extension_id) const { return ValidDBExists(GetDBPath(extension_id)); } std::set LegacyValueStoreFactory::ModelSettings::GetKnownExtensionIDs() const { DCHECK_CURRENTLY_ON(BrowserThread::FILE); std::set result; // Leveldb databases are directories inside |base_path_|. base::FileEnumerator extension_dirs(data_path_, false, base::FileEnumerator::DIRECTORIES); while (!extension_dirs.Next().empty()) { base::FilePath extension_dir = extension_dirs.GetInfo().GetName(); DCHECK(!extension_dir.IsAbsolute()); // Extension ID's are 'a'..'p', so any directory within this folder will // either be ASCII, or created by some other application and safe to ignore. std::string maybe_as_ascii(extension_dir.MaybeAsASCII()); if (!maybe_as_ascii.empty()) { result.insert(maybe_as_ascii); } } return result; } // // SettingsRoot // LegacyValueStoreFactory::SettingsRoot::SettingsRoot( const base::FilePath& base_path, const std::string& extension_dirname, const std::string& app_dirname) { if (!extension_dirname.empty()) extensions_.reset( new ModelSettings(base_path.AppendASCII(extension_dirname))); if (!app_dirname.empty()) apps_.reset(new ModelSettings(base_path.AppendASCII(app_dirname))); } LegacyValueStoreFactory::SettingsRoot::~SettingsRoot() = default; const LegacyValueStoreFactory::ModelSettings* LegacyValueStoreFactory::SettingsRoot::GetModel(ModelType model_type) const { switch (model_type) { case ValueStoreFactory::ModelType::APP: DCHECK(apps_ != nullptr); return apps_.get(); case ValueStoreFactory::ModelType::EXTENSION: DCHECK(extensions_ != nullptr); return extensions_.get(); } NOTREACHED(); return nullptr; } LegacyValueStoreFactory::ModelSettings* LegacyValueStoreFactory::SettingsRoot::GetModel(ModelType model_type) { switch (model_type) { case ValueStoreFactory::ModelType::APP: DCHECK(apps_ != nullptr); return apps_.get(); case ValueStoreFactory::ModelType::EXTENSION: DCHECK(extensions_ != nullptr); return extensions_.get(); } NOTREACHED(); return nullptr; } std::set LegacyValueStoreFactory::SettingsRoot::GetKnownExtensionIDs( ModelType model_type) const { DCHECK_CURRENTLY_ON(BrowserThread::FILE); switch (model_type) { case ValueStoreFactory::ModelType::APP: DCHECK(apps_ != nullptr); return apps_->GetKnownExtensionIDs(); case ValueStoreFactory::ModelType::EXTENSION: DCHECK(extensions_ != nullptr); return extensions_->GetKnownExtensionIDs(); } NOTREACHED(); return std::set(); } // // LegacyValueStoreFactory // LegacyValueStoreFactory::LegacyValueStoreFactory( const base::FilePath& profile_path) : profile_path_(profile_path), local_settings_(profile_path, kLocalExtensionSettingsDirectoryName, kLocalAppSettingsDirectoryName), sync_settings_(profile_path, kSyncExtensionSettingsDirectoryName, kSyncAppSettingsDirectoryName), // Currently no such thing as a managed app - only an extension. managed_settings_(profile_path, kManagedSettingsDirectoryName, "") {} LegacyValueStoreFactory::~LegacyValueStoreFactory() = default; bool LegacyValueStoreFactory::RulesDBExists() const { return ValidDBExists(GetRulesDBPath()); } bool LegacyValueStoreFactory::StateDBExists() const { return ValidDBExists(GetStateDBPath()); } scoped_ptr LegacyValueStoreFactory::CreateRulesStore() { return make_scoped_ptr( new LeveldbValueStore(kRulesDatabaseUMAClientName, GetRulesDBPath())); } scoped_ptr LegacyValueStoreFactory::CreateStateStore() { return make_scoped_ptr( new LeveldbValueStore(kStateDatabaseUMAClientName, GetStateDBPath())); } scoped_ptr LegacyValueStoreFactory::CreateSettingsStore( settings_namespace::Namespace settings_namespace, ModelType model_type, const ExtensionId& extension_id) { const ModelSettings* settings_root = GetSettingsRoot(settings_namespace).GetModel(model_type); DCHECK(settings_root != nullptr); return make_scoped_ptr(new LeveldbValueStore( kSettingsDatabaseUMAClientName, settings_root->GetDBPath(extension_id))); } void LegacyValueStoreFactory::DeleteSettings( settings_namespace::Namespace settings_namespace, ModelType model_type, const ExtensionId& extension_id) { // TODO(cmumford): Verify that we always need to be called on FILE thread. DCHECK_CURRENTLY_ON(BrowserThread::FILE); ModelSettings* model_settings = GetSettingsRoot(settings_namespace).GetModel(model_type); if (model_settings == nullptr) { NOTREACHED(); return; } model_settings->DeleteData(extension_id); } bool LegacyValueStoreFactory::HasSettings( settings_namespace::Namespace settings_namespace, ModelType model_type, const ExtensionId& extension_id) { const ModelSettings* model_settings = GetSettingsRoot(settings_namespace).GetModel(model_type); if (model_settings == nullptr) return false; return model_settings->DataExists(extension_id); } std::set LegacyValueStoreFactory::GetKnownExtensionIDs( settings_namespace::Namespace settings_type, ModelType model_type) const { return GetSettingsRoot(settings_type).GetKnownExtensionIDs(model_type); } const LegacyValueStoreFactory::SettingsRoot& LegacyValueStoreFactory::GetSettingsRoot( settings_namespace::Namespace settings_namespace) const { switch (settings_namespace) { case settings_namespace::LOCAL: return local_settings_; case settings_namespace::SYNC: return sync_settings_; case settings_namespace::MANAGED: return managed_settings_; case settings_namespace::INVALID: break; } NOTREACHED(); return local_settings_; } LegacyValueStoreFactory::SettingsRoot& LegacyValueStoreFactory::GetSettingsRoot( settings_namespace::Namespace settings_namespace) { switch (settings_namespace) { case settings_namespace::LOCAL: return local_settings_; case settings_namespace::SYNC: return sync_settings_; case settings_namespace::MANAGED: return managed_settings_; case settings_namespace::INVALID: break; } NOTREACHED(); return local_settings_; } base::FilePath LegacyValueStoreFactory::GetRulesDBPath() const { return profile_path_.AppendASCII(kRulesStoreName); } base::FilePath LegacyValueStoreFactory::GetStateDBPath() const { return profile_path_.AppendASCII(kStateStoreName); } } // namespace extensions