// Copyright 2016 The Weave 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 "src/access_black_list_manager_impl.h" #include #include #include #include "src/commands/schema_constants.h" #include "src/data_encoding.h" namespace weave { namespace { const char kConfigFileName[] = "black_list"; const char kUser[] = "user"; const char kApp[] = "app"; const char kExpiration[] = "expiration"; } AccessBlackListManagerImpl::AccessBlackListManagerImpl( provider::ConfigStore* store, size_t capacity, base::Clock* clock) : capacity_{capacity}, clock_{clock}, store_{store} { Load(); } void AccessBlackListManagerImpl::Load() { if (!store_) return; if (auto list = base::ListValue::From( base::JSONReader::Read(store_->LoadSettings(kConfigFileName)))) { for (const auto& e : *list) { const base::DictionaryValue* entry{nullptr}; std::string user; std::string app; decltype(entries_)::key_type key; int expiration; if (e->GetAsDictionary(&entry) && entry->GetString(kUser, &user) && Base64Decode(user, &key.first) && entry->GetString(kApp, &app) && Base64Decode(app, &key.second) && entry->GetInteger(kExpiration, &expiration)) { base::Time expiration_time = base::Time::FromTimeT(expiration); if (expiration_time > clock_->Now()) entries_[key] = expiration_time; } } if (entries_.size() < list->GetSize()) { // Save some storage space by saving without expired entries. Save({}); } } } void AccessBlackListManagerImpl::Save(const DoneCallback& callback) { if (!store_) { if (!callback.is_null()) callback.Run(nullptr); return; } base::ListValue list; for (const auto& e : entries_) { scoped_ptr entry{new base::DictionaryValue}; entry->SetString(kUser, Base64Encode(e.first.first)); entry->SetString(kApp, Base64Encode(e.first.second)); entry->SetInteger(kExpiration, e.second.ToTimeT()); list.Append(std::move(entry)); } std::string json; base::JSONWriter::Write(list, &json); store_->SaveSettings(kConfigFileName, json, callback); } void AccessBlackListManagerImpl::RemoveExpired() { for (auto i = begin(entries_); i != end(entries_);) { if (i->second <= clock_->Now()) i = entries_.erase(i); else ++i; } } void AccessBlackListManagerImpl::Block(const std::vector& user_id, const std::vector& app_id, const base::Time& expiration, const DoneCallback& callback) { // Iterating is OK as Save below is more expensive. RemoveExpired(); if (expiration <= clock_->Now()) { if (!callback.is_null()) { ErrorPtr error; Error::AddTo(&error, FROM_HERE, "aleady_expired", "Entry already expired"); callback.Run(std::move(error)); } return; } if (entries_.size() >= capacity_) { if (!callback.is_null()) { ErrorPtr error; Error::AddTo(&error, FROM_HERE, "blacklist_is_full", "Unable to store more entries"); callback.Run(std::move(error)); } return; } auto& value = entries_[std::make_pair(user_id, app_id)]; value = std::max(value, expiration); Save(callback); } void AccessBlackListManagerImpl::Unblock(const std::vector& user_id, const std::vector& app_id, const DoneCallback& callback) { if (!entries_.erase(std::make_pair(user_id, app_id))) { if (!callback.is_null()) { ErrorPtr error; Error::AddTo(&error, FROM_HERE, "entry_not_found", "Unknown entry"); callback.Run(std::move(error)); } return; } // Iterating is OK as Save below is more expensive. RemoveExpired(); Save(callback); } bool AccessBlackListManagerImpl::IsBlocked( const std::vector& user_id, const std::vector& app_id) const { for (const auto& user : {{}, user_id}) { for (const auto& app : {{}, app_id}) { auto both = entries_.find(std::make_pair(user, app)); if (both != end(entries_) && both->second > clock_->Now()) return true; } } return false; } std::vector AccessBlackListManagerImpl::GetEntries() const { std::vector result; for (const auto& e : entries_) result.push_back({e.first.first, e.first.second, e.second}); return result; } size_t AccessBlackListManagerImpl::GetSize() const { return entries_.size(); } size_t AccessBlackListManagerImpl::GetCapacity() const { return capacity_; } } // namespace weave