1 // 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
5 #include "src/access_api_handler.h"
6
7 #include <base/bind.h>
8 #include <weave/device.h>
9
10 #include "src/access_black_list_manager.h"
11 #include "src/commands/schema_constants.h"
12 #include "src/data_encoding.h"
13 #include "src/json_error_codes.h"
14
15 namespace weave {
16
17 namespace {
18
19 const char kComponent[] = "accessControl";
20 const char kTrait[] = "_accessControlBlackList";
21 const char kStateSize[] = "_accessControlBlackList.size";
22 const char kStateCapacity[] = "_accessControlBlackList.capacity";
23 const char kUserId[] = "userId";
24 const char kApplicationId[] = "applicationId";
25 const char kExpirationTimeout[] = "expirationTimeoutSec";
26 const char kBlackList[] = "blackList";
27
GetIds(const base::DictionaryValue & parameters,std::vector<uint8_t> * user_id_decoded,std::vector<uint8_t> * app_id_decoded,ErrorPtr * error)28 bool GetIds(const base::DictionaryValue& parameters,
29 std::vector<uint8_t>* user_id_decoded,
30 std::vector<uint8_t>* app_id_decoded,
31 ErrorPtr* error) {
32 std::string user_id;
33 parameters.GetString(kUserId, &user_id);
34 if (!Base64Decode(user_id, user_id_decoded)) {
35 Error::AddToPrintf(error, FROM_HERE, errors::commands::kInvalidPropValue,
36 "Invalid user id '%s'", user_id.c_str());
37 return false;
38 }
39
40 std::string app_id;
41 parameters.GetString(kApplicationId, &app_id);
42 if (!Base64Decode(app_id, app_id_decoded)) {
43 Error::AddToPrintf(error, FROM_HERE, errors::commands::kInvalidPropValue,
44 "Invalid app id '%s'", user_id.c_str());
45 return false;
46 }
47
48 return true;
49 }
50
51 } // namespace
52
AccessApiHandler(Device * device,AccessBlackListManager * manager)53 AccessApiHandler::AccessApiHandler(Device* device,
54 AccessBlackListManager* manager)
55 : device_{device}, manager_{manager} {
56 device_->AddTraitDefinitionsFromJson(R"({
57 "_accessControlBlackList": {
58 "commands": {
59 "block": {
60 "minimalRole": "owner",
61 "parameters": {
62 "userId": {
63 "type": "string"
64 },
65 "applicationId": {
66 "type": "string"
67 },
68 "expirationTimeoutSec": {
69 "type": "integer"
70 }
71 }
72 },
73 "unblock": {
74 "minimalRole": "owner",
75 "parameters": {
76 "userId": {
77 "type": "string"
78 },
79 "applicationId": {
80 "type": "string"
81 }
82 }
83 },
84 "list": {
85 "minimalRole": "owner",
86 "parameters": {},
87 "results": {
88 "blackList": {
89 "type": "array",
90 "items": {
91 "type": "object",
92 "properties": {
93 "userId": {
94 "type": "string"
95 },
96 "applicationId": {
97 "type": "string"
98 }
99 },
100 "additionalProperties": false
101 }
102 }
103 }
104 }
105 },
106 "state": {
107 "size": {
108 "type": "integer",
109 "isRequired": true
110 },
111 "capacity": {
112 "type": "integer",
113 "isRequired": true
114 }
115 }
116 }
117 })");
118 CHECK(device_->AddComponent(kComponent, {kTrait}, nullptr));
119 UpdateState();
120
121 device_->AddCommandHandler(
122 kComponent, "_accessControlBlackList.block",
123 base::Bind(&AccessApiHandler::Block, weak_ptr_factory_.GetWeakPtr()));
124 device_->AddCommandHandler(
125 kComponent, "_accessControlBlackList.unblock",
126 base::Bind(&AccessApiHandler::Unblock, weak_ptr_factory_.GetWeakPtr()));
127 device_->AddCommandHandler(
128 kComponent, "_accessControlBlackList.list",
129 base::Bind(&AccessApiHandler::List, weak_ptr_factory_.GetWeakPtr()));
130 }
131
Block(const std::weak_ptr<Command> & cmd)132 void AccessApiHandler::Block(const std::weak_ptr<Command>& cmd) {
133 auto command = cmd.lock();
134 if (!command)
135 return;
136
137 CHECK(command->GetState() == Command::State::kQueued)
138 << EnumToString(command->GetState());
139 command->SetProgress(base::DictionaryValue{}, nullptr);
140
141 const auto& parameters = command->GetParameters();
142 std::vector<uint8_t> user_id;
143 std::vector<uint8_t> app_id;
144 ErrorPtr error;
145 if (!GetIds(parameters, &user_id, &app_id, &error)) {
146 command->Abort(error.get(), nullptr);
147 return;
148 }
149
150 int timeout_sec = 0;
151 parameters.GetInteger(kExpirationTimeout, &timeout_sec);
152
153 base::Time expiration =
154 base::Time::Now() + base::TimeDelta::FromSeconds(timeout_sec);
155
156 manager_->Block(user_id, app_id, expiration,
157 base::Bind(&AccessApiHandler::OnCommandDone,
158 weak_ptr_factory_.GetWeakPtr(), cmd));
159 }
160
Unblock(const std::weak_ptr<Command> & cmd)161 void AccessApiHandler::Unblock(const std::weak_ptr<Command>& cmd) {
162 auto command = cmd.lock();
163 if (!command)
164 return;
165
166 CHECK(command->GetState() == Command::State::kQueued)
167 << EnumToString(command->GetState());
168 command->SetProgress(base::DictionaryValue{}, nullptr);
169
170 const auto& parameters = command->GetParameters();
171 std::vector<uint8_t> user_id;
172 std::vector<uint8_t> app_id;
173 ErrorPtr error;
174 if (!GetIds(parameters, &user_id, &app_id, &error)) {
175 command->Abort(error.get(), nullptr);
176 return;
177 }
178
179 manager_->Unblock(user_id, app_id,
180 base::Bind(&AccessApiHandler::OnCommandDone,
181 weak_ptr_factory_.GetWeakPtr(), cmd));
182 }
183
List(const std::weak_ptr<Command> & cmd)184 void AccessApiHandler::List(const std::weak_ptr<Command>& cmd) {
185 auto command = cmd.lock();
186 if (!command)
187 return;
188
189 CHECK(command->GetState() == Command::State::kQueued)
190 << EnumToString(command->GetState());
191 command->SetProgress(base::DictionaryValue{}, nullptr);
192
193 std::unique_ptr<base::ListValue> entries{new base::ListValue};
194 for (const auto& e : manager_->GetEntries()) {
195 std::unique_ptr<base::DictionaryValue> entry{new base::DictionaryValue};
196 entry->SetString(kUserId, Base64Encode(e.user_id));
197 entry->SetString(kApplicationId, Base64Encode(e.app_id));
198 entries->Append(entry.release());
199 }
200
201 base::DictionaryValue result;
202 result.Set(kBlackList, entries.release());
203
204 command->Complete(result, nullptr);
205 }
206
OnCommandDone(const std::weak_ptr<Command> & cmd,ErrorPtr error)207 void AccessApiHandler::OnCommandDone(const std::weak_ptr<Command>& cmd,
208 ErrorPtr error) {
209 auto command = cmd.lock();
210 if (!command)
211 return;
212 UpdateState();
213 if (error) {
214 command->Abort(error.get(), nullptr);
215 return;
216 }
217 command->Complete({}, nullptr);
218 }
219
UpdateState()220 void AccessApiHandler::UpdateState() {
221 base::DictionaryValue state;
222 state.SetInteger(kStateSize, manager_->GetSize());
223 state.SetInteger(kStateCapacity, manager_->GetCapacity());
224 device_->SetStateProperties(kComponent, state, nullptr);
225 }
226
227 } // namespace weave
228