| // 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_api_handler.h" | |
| #include <base/bind.h> | |
| #include <weave/device.h> | |
| #include "src/access_revocation_manager.h" | |
| #include "src/commands/schema_constants.h" | |
| #include "src/data_encoding.h" | |
| #include "src/json_error_codes.h" | |
| #include "src/utils.h" | |
| namespace weave { | |
| namespace { | |
| const char kComponent[] = "accessControl"; | |
| const char kTrait[] = "_accessRevocationList"; | |
| const char kStateCapacity[] = "_accessRevocationList.capacity"; | |
| const char kUserId[] = "userId"; | |
| const char kApplicationId[] = "applicationId"; | |
| const char kExpirationTime[] = "expirationTime"; | |
| const char kRevocationTimestamp[] = "revocationTimestamp"; | |
| const char kRevocationList[] = "revocationList"; | |
| bool GetIds(const base::DictionaryValue& parameters, | |
| std::vector<uint8_t>* user_id_decoded, | |
| std::vector<uint8_t>* app_id_decoded, | |
| ErrorPtr* error) { | |
| std::string user_id; | |
| parameters.GetString(kUserId, &user_id); | |
| if (!Base64Decode(user_id, user_id_decoded)) { | |
| Error::AddToPrintf(error, FROM_HERE, errors::commands::kInvalidPropValue, | |
| "Invalid user id '%s'", user_id.c_str()); | |
| return false; | |
| } | |
| std::string app_id; | |
| parameters.GetString(kApplicationId, &app_id); | |
| if (!Base64Decode(app_id, app_id_decoded)) { | |
| Error::AddToPrintf(error, FROM_HERE, errors::commands::kInvalidPropValue, | |
| "Invalid app id '%s'", user_id.c_str()); | |
| return false; | |
| } | |
| return true; | |
| } | |
| } // namespace | |
| AccessApiHandler::AccessApiHandler(Device* device, | |
| AccessRevocationManager* manager) | |
| : device_{device}, manager_{manager} { | |
| device_->AddTraitDefinitionsFromJson(R"({ | |
| "_accessRevocationList": { | |
| "commands": { | |
| "add": { | |
| "minimalRole": "owner", | |
| "parameters": { | |
| "userId": { | |
| "type": "string" | |
| }, | |
| "applicationId": { | |
| "type": "string" | |
| }, | |
| "revocationTimestamp": { | |
| "type": "integer" | |
| }, | |
| "expirationTime": { | |
| "type": "integer" | |
| } | |
| } | |
| }, | |
| "list": { | |
| "minimalRole": "owner", | |
| "parameters": {}, | |
| "results": { | |
| "revocationList": { | |
| "type": "array", | |
| "items": { | |
| "type": "object", | |
| "properties": { | |
| "userId": { | |
| "type": "string" | |
| }, | |
| "applicationId": { | |
| "type": "string" | |
| }, | |
| "revocationTimestamp": { | |
| "type": "integer" | |
| }, | |
| "expirationTime": { | |
| "type": "integer" | |
| } | |
| }, | |
| "additionalProperties": false | |
| } | |
| } | |
| } | |
| } | |
| }, | |
| "state": { | |
| "capacity": { | |
| "type": "integer", | |
| "isRequired": true | |
| } | |
| } | |
| } | |
| })"); | |
| CHECK(device_->AddComponent(kComponent, {kTrait}, nullptr)); | |
| UpdateState(); | |
| device_->AddCommandHandler( | |
| kComponent, "_accessRevocationList.add", | |
| base::Bind(&AccessApiHandler::Block, weak_ptr_factory_.GetWeakPtr())); | |
| device_->AddCommandHandler( | |
| kComponent, "_accessRevocationList.list", | |
| base::Bind(&AccessApiHandler::List, weak_ptr_factory_.GetWeakPtr())); | |
| } | |
| void AccessApiHandler::Block(const std::weak_ptr<Command>& cmd) { | |
| auto command = cmd.lock(); | |
| if (!command) | |
| return; | |
| CHECK(command->GetState() == Command::State::kQueued) | |
| << EnumToString(command->GetState()); | |
| command->SetProgress(base::DictionaryValue{}, nullptr); | |
| const auto& parameters = command->GetParameters(); | |
| std::vector<uint8_t> user_id; | |
| std::vector<uint8_t> app_id; | |
| ErrorPtr error; | |
| if (!GetIds(parameters, &user_id, &app_id, &error)) { | |
| command->Abort(error.get(), nullptr); | |
| return; | |
| } | |
| int expiration_j2k = 0; | |
| if (!parameters.GetInteger(kExpirationTime, &expiration_j2k)) { | |
| Error::AddToPrintf(&error, FROM_HERE, errors::commands::kInvalidPropValue, | |
| "Expiration time is missing"); | |
| command->Abort(error.get(), nullptr); | |
| return; | |
| } | |
| int revocation_j2k = 0; | |
| if (!parameters.GetInteger(kRevocationTimestamp, &revocation_j2k)) { | |
| Error::AddToPrintf(&error, FROM_HERE, errors::commands::kInvalidPropValue, | |
| "Revocation timestamp is missing"); | |
| command->Abort(error.get(), nullptr); | |
| return; | |
| } | |
| manager_->Block(AccessRevocationManager::Entry{user_id, app_id, | |
| FromJ2000Time(revocation_j2k), | |
| FromJ2000Time(expiration_j2k)}, | |
| base::Bind(&AccessApiHandler::OnCommandDone, | |
| weak_ptr_factory_.GetWeakPtr(), cmd)); | |
| } | |
| void AccessApiHandler::List(const std::weak_ptr<Command>& cmd) { | |
| auto command = cmd.lock(); | |
| if (!command) | |
| return; | |
| CHECK(command->GetState() == Command::State::kQueued) | |
| << EnumToString(command->GetState()); | |
| command->SetProgress(base::DictionaryValue{}, nullptr); | |
| std::unique_ptr<base::ListValue> entries{new base::ListValue}; | |
| for (const auto& e : manager_->GetEntries()) { | |
| std::unique_ptr<base::DictionaryValue> entry{new base::DictionaryValue}; | |
| entry->SetString(kUserId, Base64Encode(e.user_id)); | |
| entry->SetString(kApplicationId, Base64Encode(e.app_id)); | |
| entries->Append(entry.release()); | |
| } | |
| base::DictionaryValue result; | |
| result.Set(kRevocationList, entries.release()); | |
| command->Complete(result, nullptr); | |
| } | |
| void AccessApiHandler::OnCommandDone(const std::weak_ptr<Command>& cmd, | |
| ErrorPtr error) { | |
| auto command = cmd.lock(); | |
| if (!command) | |
| return; | |
| UpdateState(); | |
| if (error) { | |
| command->Abort(error.get(), nullptr); | |
| return; | |
| } | |
| command->Complete({}, nullptr); | |
| } | |
| void AccessApiHandler::UpdateState() { | |
| base::DictionaryValue state; | |
| state.SetInteger(kStateCapacity, manager_->GetCapacity()); | |
| device_->SetStateProperties(kComponent, state, nullptr); | |
| } | |
| } // namespace weave |