blob: dcfae45e8947de368ffe74e74b38959853df0280 [file] [log] [blame]
// 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[] = "revocationListEntries";
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": {
"revoke": {
"minimalRole": "owner",
"parameters": {
"userId": {
"type": "string"
},
"applicationId": {
"type": "string"
},
"revocationTimestamp": {
"type": "integer"
},
"expirationTime": {
"type": "integer"
}
}
},
"list": {
"minimalRole": "owner",
"parameters": {},
"results": {
"revocationEntriesList": {
"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.revoke",
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