blob: f0391146bb439b4c97a41a080fbb649cf4fcfde5 [file] [log] [blame]
Vitaly Buka5a7c4f52016-01-21 15:09:34 -08001// Copyright 2016 The Weave Authors. All rights reserved.
2// Use of this source code is governed by a BSD-style license that can be
3// found in the LICENSE file.
4
Vitaly Bukaebde3c12016-02-23 18:50:42 -08005#include "src/access_revocation_manager_impl.h"
Vitaly Buka5a7c4f52016-01-21 15:09:34 -08006
7#include <base/json/json_reader.h>
8#include <base/json/json_writer.h>
9#include <base/values.h>
10
11#include "src/commands/schema_constants.h"
12#include "src/data_encoding.h"
Vitaly Buka51dcfad2016-02-23 17:52:46 -080013#include "src/utils.h"
Vitaly Buka5a7c4f52016-01-21 15:09:34 -080014
15namespace weave {
16
17namespace {
18const char kConfigFileName[] = "black_list";
19
20const char kUser[] = "user";
21const char kApp[] = "app";
22const char kExpiration[] = "expiration";
Vitaly Buka51dcfad2016-02-23 17:52:46 -080023const char kRevocation[] = "revocation";
Vitaly Buka5a7c4f52016-01-21 15:09:34 -080024}
25
Vitaly Bukaebde3c12016-02-23 18:50:42 -080026AccessRevocationManagerImpl::AccessRevocationManagerImpl(
Vitaly Buka5a7c4f52016-01-21 15:09:34 -080027 provider::ConfigStore* store,
28 size_t capacity,
29 base::Clock* clock)
30 : capacity_{capacity}, clock_{clock}, store_{store} {
31 Load();
32}
33
Vitaly Bukaebde3c12016-02-23 18:50:42 -080034void AccessRevocationManagerImpl::Load() {
Vitaly Buka5a7c4f52016-01-21 15:09:34 -080035 if (!store_)
36 return;
37 if (auto list = base::ListValue::From(
38 base::JSONReader::Read(store_->LoadSettings(kConfigFileName)))) {
Vitaly Buka51dcfad2016-02-23 17:52:46 -080039 for (const auto& value : *list) {
Vitaly Buka5a7c4f52016-01-21 15:09:34 -080040 const base::DictionaryValue* entry{nullptr};
41 std::string user;
42 std::string app;
Vitaly Buka51dcfad2016-02-23 17:52:46 -080043 Entry e;
44 int revocation = 0;
45 int expiration = 0;
46 if (value->GetAsDictionary(&entry) && entry->GetString(kUser, &user) &&
47 Base64Decode(user, &e.user_id) && entry->GetString(kApp, &app) &&
48 Base64Decode(app, &e.app_id) &&
49 entry->GetInteger(kRevocation, &revocation) &&
Vitaly Buka5a7c4f52016-01-21 15:09:34 -080050 entry->GetInteger(kExpiration, &expiration)) {
Vitaly Buka51dcfad2016-02-23 17:52:46 -080051 e.revocation = FromJ2000Time(revocation);
52 e.expiration = FromJ2000Time(expiration);
53 if (e.expiration > clock_->Now())
54 entries_.insert(e);
Vitaly Buka5a7c4f52016-01-21 15:09:34 -080055 }
56 }
57 if (entries_.size() < list->GetSize()) {
58 // Save some storage space by saving without expired entries.
59 Save({});
60 }
61 }
62}
63
Vitaly Bukaebde3c12016-02-23 18:50:42 -080064void AccessRevocationManagerImpl::Save(const DoneCallback& callback) {
Vitaly Buka5a7c4f52016-01-21 15:09:34 -080065 if (!store_) {
66 if (!callback.is_null())
67 callback.Run(nullptr);
68 return;
69 }
70
71 base::ListValue list;
72 for (const auto& e : entries_) {
73 scoped_ptr<base::DictionaryValue> entry{new base::DictionaryValue};
Vitaly Buka51dcfad2016-02-23 17:52:46 -080074 entry->SetString(kUser, Base64Encode(e.user_id));
75 entry->SetString(kApp, Base64Encode(e.app_id));
76 entry->SetInteger(kRevocation, ToJ2000Time(e.revocation));
77 entry->SetInteger(kExpiration, ToJ2000Time(e.expiration));
Vitaly Buka5a7c4f52016-01-21 15:09:34 -080078 list.Append(std::move(entry));
79 }
80
81 std::string json;
82 base::JSONWriter::Write(list, &json);
83 store_->SaveSettings(kConfigFileName, json, callback);
84}
85
Vitaly Bukaebde3c12016-02-23 18:50:42 -080086void AccessRevocationManagerImpl::RemoveExpired() {
Vitaly Buka5a7c4f52016-01-21 15:09:34 -080087 for (auto i = begin(entries_); i != end(entries_);) {
Vitaly Buka51dcfad2016-02-23 17:52:46 -080088 if (i->expiration <= clock_->Now())
Vitaly Buka5a7c4f52016-01-21 15:09:34 -080089 i = entries_.erase(i);
90 else
91 ++i;
92 }
93}
94
Vitaly Bukaebde3c12016-02-23 18:50:42 -080095void AccessRevocationManagerImpl::AddEntryAddedCallback(
Vitaly Bukad1d52e72016-02-22 16:36:54 -080096 const base::Closure& callback) {
97 on_entry_added_callbacks_.push_back(callback);
98}
99
Vitaly Bukaebde3c12016-02-23 18:50:42 -0800100void AccessRevocationManagerImpl::Block(const Entry& entry,
101 const DoneCallback& callback) {
Vitaly Buka5a7c4f52016-01-21 15:09:34 -0800102 // Iterating is OK as Save below is more expensive.
103 RemoveExpired();
Vitaly Buka51dcfad2016-02-23 17:52:46 -0800104 if (entry.expiration <= clock_->Now()) {
Vitaly Buka5a7c4f52016-01-21 15:09:34 -0800105 if (!callback.is_null()) {
106 ErrorPtr error;
Vitaly Buka1c833772016-01-26 14:05:01 -0800107 Error::AddTo(&error, FROM_HERE, "aleady_expired",
108 "Entry already expired");
Vitaly Buka5a7c4f52016-01-21 15:09:34 -0800109 callback.Run(std::move(error));
110 }
111 return;
112 }
113 if (entries_.size() >= capacity_) {
114 if (!callback.is_null()) {
115 ErrorPtr error;
Vitaly Buka1c833772016-01-26 14:05:01 -0800116 Error::AddTo(&error, FROM_HERE, "blacklist_is_full",
117 "Unable to store more entries");
Vitaly Buka5a7c4f52016-01-21 15:09:34 -0800118 callback.Run(std::move(error));
119 }
120 return;
121 }
Vitaly Bukad1d52e72016-02-22 16:36:54 -0800122
Vitaly Buka51dcfad2016-02-23 17:52:46 -0800123 auto existing = entries_.find(entry);
124 if (existing != entries_.end()) {
125 Entry new_entry = entry;
126 new_entry.expiration = std::max(entry.expiration, existing->expiration);
127 new_entry.revocation = std::max(entry.revocation, existing->revocation);
128 entries_.erase(existing);
129 entries_.insert(new_entry);
130 } else {
131 entries_.insert(entry);
132 }
133
Vitaly Bukad1d52e72016-02-22 16:36:54 -0800134 for (const auto& cb : on_entry_added_callbacks_)
135 cb.Run();
136
Vitaly Buka5a7c4f52016-01-21 15:09:34 -0800137 Save(callback);
138}
139
Vitaly Bukaebde3c12016-02-23 18:50:42 -0800140bool AccessRevocationManagerImpl::IsBlocked(const std::vector<uint8_t>& user_id,
141 const std::vector<uint8_t>& app_id,
142 base::Time timestamp) const {
Vitaly Buka51dcfad2016-02-23 17:52:46 -0800143 Entry entry_to_find;
Vitaly Buka5a7c4f52016-01-21 15:09:34 -0800144 for (const auto& user : {{}, user_id}) {
145 for (const auto& app : {{}, app_id}) {
Vitaly Buka51dcfad2016-02-23 17:52:46 -0800146 entry_to_find.user_id = user;
147 entry_to_find.app_id = app;
148 auto match = entries_.find(entry_to_find);
149 if (match != end(entries_) && match->expiration > clock_->Now() &&
150 match->revocation >= timestamp) {
Vitaly Buka5a7c4f52016-01-21 15:09:34 -0800151 return true;
Vitaly Buka51dcfad2016-02-23 17:52:46 -0800152 }
Vitaly Buka5a7c4f52016-01-21 15:09:34 -0800153 }
154 }
155 return false;
156}
157
Vitaly Bukaebde3c12016-02-23 18:50:42 -0800158std::vector<AccessRevocationManager::Entry>
159AccessRevocationManagerImpl::GetEntries() const {
Vitaly Buka51dcfad2016-02-23 17:52:46 -0800160 return {begin(entries_), end(entries_)};
Vitaly Buka5a7c4f52016-01-21 15:09:34 -0800161}
162
Vitaly Bukaebde3c12016-02-23 18:50:42 -0800163size_t AccessRevocationManagerImpl::GetSize() const {
Vitaly Buka5a7c4f52016-01-21 15:09:34 -0800164 return entries_.size();
165}
166
Vitaly Bukaebde3c12016-02-23 18:50:42 -0800167size_t AccessRevocationManagerImpl::GetCapacity() const {
Vitaly Buka5a7c4f52016-01-21 15:09:34 -0800168 return capacity_;
169}
170
171} // namespace weave