Home | History | Annotate | Download | only in src
      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