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 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 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 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 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 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 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 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