blob: 9dfea07172123fbd37651c1a65c0427fde2035db [file] [log] [blame]
// Copyright 2015 The Chromium OS 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 "settingsd/source.h"
#include <base/logging.h>
#include <base/values.h>
#include "settingsd/settings_document.h"
#include "settingsd/settings_keys.h"
#include "settingsd/settings_service.h"
namespace settingsd {
namespace {
// Setting status strings.
const char* const kSettingStatusStrings[] = {"active", "withdrawn", "invalid"};
} // namespace
SettingStatus SettingStatusFromString(const std::string& status_string) {
for (SettingStatus status :
{kSettingStatusActive, kSettingStatusWithdrawn, kSettingStatusInvalid}) {
CHECK_LT(status, sizeof(kSettingStatusStrings));
if (status_string == kSettingStatusStrings[status])
return status;
}
return kSettingStatusInvalid;
}
std::string SettingStatusToString(SettingStatus status) {
CHECK_LT(status, sizeof(kSettingStatusStrings));
return kSettingStatusStrings[status];
}
Key MakeSourceKey(const std::string& source_id) {
// TODO(mnissler): Handle nested sources properly.
return Key(keys::kSettingsdPrefix).Extend({keys::kSources, source_id});
}
Source::Source(const std::string& id)
: id_(id), delegate_(new DummySourceDelegate()) {}
Source::~Source() {}
bool Source::CheckAccess(const SettingsDocument* document,
SettingStatus threshold) const {
if (status_ > threshold)
return false;
const Key trust_config_area_begin(
Key(keys::kSettingsdPrefix).Extend({keys::kSources}));
const Key trust_config_area_end(MakeSourceKey(id_).PrefixUpperBound());
for (auto& key : document->GetKeys(Key())) {
if (trust_config_area_begin <= key && key < trust_config_area_end)
return false;
auto access_rule = FindMatchingAccessRule(key);
if (access_rule == access_.end() || access_rule->second > threshold)
return false;
}
for (auto& deletion : document->GetDeletions(Key())) {
if ((trust_config_area_begin <= deletion &&
deletion < trust_config_area_end) ||
deletion.IsPrefixOf(trust_config_area_begin)) {
return false;
}
auto access_rule = FindMatchingAccessRule(deletion);
if (access_rule == access_.end() || access_rule->second > threshold)
return false;
// Check all access rules within the set of deleted keys.
for (; access_rule != access_.end() &&
deletion.IsPrefixOf(access_rule->first);
++access_rule) {
if (access_rule->second > threshold)
return false;
}
}
return true;
}
bool Source::Update(
const SourceDelegateFactoryFunction& delegate_factory_function,
const SettingsService& settings) {
const base::Value* value;
bool has_config = false;
name_.clear();
value = settings.GetValue(MakeSourceKey(id_).Extend({keys::sources::kName}));
if (value)
has_config |= value->GetAsString(&name_);
value =
settings.GetValue(MakeSourceKey(id_).Extend({keys::sources::kStatus}));
std::string status_string;
if (value)
has_config |= value->GetAsString(&status_string);
status_ = SettingStatusFromString(status_string);
delegate_ = delegate_factory_function(id_, settings);
has_config |= !!delegate_;
if (!delegate_)
delegate_.reset(new DummySourceDelegate());
access_.clear();
const Key access_key_prefix(
MakeSourceKey(id_).Extend({keys::sources::kAccess}));
const std::set<Key> access_keys(settings.GetKeys(access_key_prefix));
for (Key access_key : access_keys) {
has_config = true;
status_string.clear();
value = settings.GetValue(access_key);
if (value)
value->GetAsString(&status_string);
Key suffix;
if (access_key.Suffix(access_key_prefix, &suffix))
access_[suffix] = SettingStatusFromString(status_string);
else
NOTREACHED() << "Invalid access key " << access_key.ToString();
}
blob_formats_.clear();
value = settings.GetValue(
MakeSourceKey(id_).Extend({keys::sources::kBlobFormat}));
const base::ListValue* list_value = nullptr;
if (value)
has_config |= value->GetAsList(&list_value);
if (list_value) {
for (const base::Value* entry : *list_value) {
std::string blob_format;
if (entry->GetAsString(&blob_format))
blob_formats_.push_back(blob_format);
}
}
return has_config;
}
Source::AccessRuleMap::const_iterator Source::FindMatchingAccessRule(
const Key& key) const {
Key lookup_key = key;
auto rule = access_.upper_bound(lookup_key);
while (rule != access_.begin()) {
--rule;
if (rule->first.IsPrefixOf(key))
return rule;
lookup_key = lookup_key.CommonPrefix(rule->first);
rule = access_.upper_bound(lookup_key);
}
return access_.end();
}
} // namespace settingsd