Merge remote-tracking branch 'weave/master' into 'weave/aosp-master' 37994f4 Fix some of compiler warnings. ebde3c1 Rename *BlackList* into *Revocation* efbd66b Remove unused constants 5a1990f Implement revocation list check when validating auth token 51dcfad Add revocationTimestamp parameter into revocation entry 4846c44 Remove AccessBlackListManager::Unblock 958a359 Revert "debian: add debian packaging files" 7f2a5dc daemon: register device after component init 89b3495 Removing legacy API from libweave 1054d3e Move minimalRole constants from schema_constants.h to a local .cc file 9e9023e daemon/light: fix light trait def 6da60ad Fix use-after-free detected by ASAN c23ea22 Replace expirationTimeoutSec with expirationTime 7c0ea69 Rename _accessControlBlackList into _accessRevocationList 012cd98 Move mock_component_manager.h into test/ dir c6d99bb Move MockAccessBlackListManager into separate file b612e3c Reset access token secret on new black list entry d1d52e7 Add AccessBlackListManager::AddEntryAddedCallback 7fc5434 debian: add debian packaging files 634c408 Remove property from json added by mistake Change-Id: I69380e60cf9888999224fdf11a5bc35f0bc7bda2
diff --git a/Makefile b/Makefile index 9810dd0..70f7ee7 100644 --- a/Makefile +++ b/Makefile
@@ -28,13 +28,8 @@ -Wextra \ -Wformat=2 \ -Wl,--exclude-libs,ALL \ - -Wno-char-subscripts \ -Wno-missing-field-initializers \ - -Wno-unused-local-typedefs \ -Wno-unused-parameter \ - -Wpacked \ - -Wpointer-arith \ - -Wwrite-strings CFLAGS_Debug := \ -O0 \ @@ -56,7 +51,6 @@ CFLAGS := $(filter-out -Wl$(comma)--exclude-libs$(comma)ALL,$(CFLAGS)) CFLAGS += \ -fno-omit-frame-pointer \ - -Wno-deprecated-register \ -Wno-inconsistent-missing-override ifeq (Debug, $(BUILD_MODE)) CFLAGS += \
diff --git a/examples/daemon/common/daemon.h b/examples/daemon/common/daemon.h index 0b3c25a..22591a2 100644 --- a/examples/daemon/common/daemon.h +++ b/examples/daemon/common/daemon.h
@@ -92,16 +92,18 @@ http_client_.get(), network_.get(), dns_sd_.get(), http_server_.get(), wifi_.get(), bluetooth_.get()); - if (!opts.registration_ticket.empty()) { - weave::RegistrationData data; - data.ticket_id = opts.registration_ticket; - data.service_url = opts.service_url; - device_->Register(data, base::Bind(&OnRegisterDeviceDone, device_.get())); + registration_data_.ticket_id = opts.registration_ticket; + registration_data_.service_url = opts.service_url; } } - void Run() { task_runner_->Run(); } + void Run() { + if (!registration_data_.ticket_id.empty()) { + device_->Register(registration_data_, base::Bind(&OnRegisterDeviceDone, device_.get())); + } + task_runner_->Run(); + } weave::Device* GetDevice() const { return device_.get(); } @@ -127,4 +129,5 @@ std::unique_ptr<weave::examples::HttpServerImpl> http_server_; std::unique_ptr<weave::examples::WifiImpl> wifi_; std::unique_ptr<weave::Device> device_; + weave::RegistrationData registration_data_; };
diff --git a/examples/daemon/light/light.cc b/examples/daemon/light/light.cc index 4cbf9b4..07c0231 100644 --- a/examples/daemon/light/light.cc +++ b/examples/daemon/light/light.cc
@@ -19,7 +19,7 @@ "parameters": { "state": { "type": "string", - "enum": [ "on", "standby" ] + "enum": [ "on", "off" ] } } } @@ -27,7 +27,7 @@ "state": { "state": { "type": "string", - "enum": [ "on", "standby" ], + "enum": [ "on", "off" ], "isRequired": true } } @@ -38,23 +38,23 @@ "minimalRole": "user", "parameters": { "brightness": { - "type": "integer", - "minimum": 0, - "maximum": 100 + "type": "number", + "minimum": 0.0, + "maximum": 1.0 } } } }, "state": { "brightness": { - "type": "integer", + "type": "number", "isRequired": true, - "minimum": 0, - "maximum": 100 + "minimum": 0.0, + "maximum": 1.0 } } }, - "colorXY": { + "colorXy": { "commands": { "setConfig": { "minimalRole": "user", @@ -157,7 +157,7 @@ })"; const char kDefaultState[] = R"({ - "colorXY": { + "colorXy": { "colorSetting": {"colorX": 0, "colorY": 0}, "colorCapRed": {"colorX": 0.674, "colorY": 0.322}, "colorCapGreen":{"colorX": 0.408, "colorY": 0.517}, @@ -178,7 +178,7 @@ device_ = device; device->AddTraitDefinitionsFromJson(kTraits); - CHECK(device->AddComponent(kComponent, {"onOff", "brightness", "colorXY"}, + CHECK(device->AddComponent(kComponent, {"onOff", "brightness", "colorXy"}, nullptr)); CHECK( device->SetStatePropertiesFromJson(kComponent, kDefaultState, nullptr)); @@ -190,7 +190,7 @@ device->AddCommandHandler(kComponent, "brightness.setConfig", base::Bind(&LightHandler::OnBrightnessSetConfig, weak_ptr_factory_.GetWeakPtr())); - device->AddCommandHandler(kComponent, "colorXY.setConfig", + device->AddCommandHandler(kComponent, "colorXy.setConfig", base::Bind(&LightHandler::OnColorXYSetConfig, weak_ptr_factory_.GetWeakPtr())); } @@ -252,17 +252,17 @@ return; LOG(INFO) << "received command: " << cmd->GetName(); const auto& params = cmd->GetParameters(); - const base::DictionaryValue* colorXY = nullptr; - if (params.GetDictionary("colorSetting", &colorXY)) { + const base::DictionaryValue* colorXy = nullptr; + if (params.GetDictionary("colorSetting", &colorXy)) { bool updateState = false; double X = 0.0; double Y = 0.0; - if (colorXY->GetDouble("colorX", &X)) { + if (colorXy->GetDouble("colorX", &X)) { color_X_ = X; updateState = true; } - if (colorXY->GetDouble("colorY", &Y)) { + if (colorXy->GetDouble("colorY", &Y)) { color_Y_ = Y; updateState = true; } @@ -282,13 +282,13 @@ void UpdateLightState() { base::DictionaryValue state; - state.SetString("onOff.state", light_status_ ? "on" : "standby"); + state.SetString("onOff.state", light_status_ ? "on" : "off"); state.SetInteger("brightness.brightness", brightness_state_); - std::unique_ptr<base::DictionaryValue> colorXY(new base::DictionaryValue()); - colorXY->SetDouble("colorX", color_X_); - colorXY->SetDouble("colorY", color_Y_); - state.Set("colorXY.colorSetting", colorXY.release()); + std::unique_ptr<base::DictionaryValue> colorXy(new base::DictionaryValue()); + colorXy->SetDouble("colorX", color_X_); + colorXy->SetDouble("colorY", color_Y_); + state.Set("colorXy.colorSetting", colorXy.release()); device_->SetStateProperties(kComponent, state, nullptr); }
diff --git a/examples/provider/wifi_manager.cc b/examples/provider/wifi_manager.cc index 7597e47..9337d23 100644 --- a/examples/provider/wifi_manager.cc +++ b/examples/provider/wifi_manager.cc
@@ -46,20 +46,21 @@ return status; } +struct DirCloser { + void operator()(DIR* dir) { closedir(dir); } +}; + std::string FindWirelessInterface() { std::string sysfs_net{"/sys/class/net"}; - DIR* net_dir = opendir(sysfs_net.c_str()); + std::unique_ptr<DIR, DirCloser> net_dir{opendir(sysfs_net.c_str())}; + CHECK(net_dir); dirent* iface; - while ((iface = readdir(net_dir))) { + while ((iface = readdir(net_dir.get()))) { auto path = sysfs_net + "/" + iface->d_name + "/wireless"; - DIR* wireless_dir = opendir(path.c_str()); - if (wireless_dir != nullptr) { - closedir(net_dir); - closedir(wireless_dir); + std::unique_ptr<DIR, DirCloser> wireless_dir{opendir(path.c_str())}; + if (wireless_dir) return iface->d_name; - } } - closedir(net_dir); return ""; }
diff --git a/file_lists.mk b/file_lists.mk index 9a015e2..e13553f 100644 --- a/file_lists.mk +++ b/file_lists.mk
@@ -4,7 +4,7 @@ WEAVE_SRC_FILES := \ src/access_api_handler.cc \ - src/access_black_list_manager_impl.cc \ + src/access_revocation_manager_impl.cc \ src/backoff_entry.cc \ src/base_api_handler.cc \ src/commands/cloud_command_proxy.cc \ @@ -51,7 +51,7 @@ WEAVE_UNITTEST_SRC_FILES := \ src/access_api_handler_unittest.cc \ - src/access_black_list_manager_impl_unittest.cc \ + src/access_revocation_manager_impl_unittest.cc \ src/backoff_entry_unittest.cc \ src/base_api_handler_unittest.cc \ src/commands/cloud_command_proxy_unittest.cc \
diff --git a/include/weave/device.h b/include/weave/device.h index 9a29574..b79e6a3 100644 --- a/include/weave/device.h +++ b/include/weave/device.h
@@ -193,68 +193,6 @@ provider::HttpServer* http_server, provider::Wifi* wifi, provider::Bluetooth* bluetooth_provider); - - //========================== Deprecated APIs ========================= - - // Adds provided commands definitions. Can be called multiple times with - // condition that definitions do not conflict. - // Invalid value is fatal. - // DO NOT USE IN YOUR CODE: use AddTraitDefinitions() instead. - LIBWEAVE_DEPRECATED virtual void AddCommandDefinitionsFromJson( - const std::string& json) = 0; - LIBWEAVE_DEPRECATED virtual void AddCommandDefinitions( - const base::DictionaryValue& dict) = 0; - - // Sets handler for new commands added to the queue. - // |command_name| is the full command name of the command to handle. e.g. - // "base.reboot". Each command can have no more than one handler. - // Empty |command_name| sets default handler for all unhanded commands. - // No new command handlers can be set after default handler was set. - // DO NOT USE IN YOUR CODE: use AddCommandHandler() with component parameter. - LIBWEAVE_DEPRECATED virtual void AddCommandHandler( - const std::string& command_name, - const CommandHandlerCallback& callback) = 0; - - // Adds provided state definitions. Can be called multiple times with - // condition that definitions do not conflict. - // Invalid value is fatal. - // DO NOT USE IN YOUR CODE: use AddTraitDefinitions() instead. - LIBWEAVE_DEPRECATED virtual void AddStateDefinitionsFromJson( - const std::string& json) = 0; - LIBWEAVE_DEPRECATED virtual void AddStateDefinitions( - const base::DictionaryValue& dict) = 0; - - // Sets value of multiple properties of the state. - // It's recommended to call this to initialize state defined by - // AddStateDefinitions. - // Example: - // device->SetStatePropertiesFromJson("{'base':{'firmwareVersion':'123'}}") - // Method completely replaces properties included |json| or |dict|. - // Properties of the state not included |json| or |dict| will stay unchanged. - // DO NOT USE IN YOUR CODE: use SetStateProperties() with component parameter. - LIBWEAVE_DEPRECATED virtual bool SetStatePropertiesFromJson( - const std::string& json, - ErrorPtr* error) = 0; - LIBWEAVE_DEPRECATED virtual bool SetStateProperties( - const base::DictionaryValue& dict, - ErrorPtr* error) = 0; - - // Returns value of the single property. - // |name| is full property name, including package name. e.g. "base.network". - // DO NOT USE IN YOUR CODE: use GetStateProperty() with component parameter. - LIBWEAVE_DEPRECATED virtual const base::Value* GetStateProperty( - const std::string& name) const = 0; - - // Sets value of the single property. - // |name| is full property name, including package name. e.g. "base.network". - // DO NOT USE IN YOUR CODE: use SetStateProperty() with component parameter. - LIBWEAVE_DEPRECATED virtual bool SetStateProperty(const std::string& name, - const base::Value& value, - ErrorPtr* error) = 0; - - // Returns aggregated state properties across all registered packages. - // DO NOT USE IN YOUR CODE: use GetComponents() instead. - LIBWEAVE_DEPRECATED virtual const base::DictionaryValue& GetState() const = 0; }; } // namespace weave
diff --git a/src/access_api_handler.cc b/src/access_api_handler.cc index 7c39b20..dcfae45 100644 --- a/src/access_api_handler.cc +++ b/src/access_api_handler.cc
@@ -7,23 +7,24 @@ #include <base/bind.h> #include <weave/device.h> -#include "src/access_black_list_manager.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[] = "_accessControlBlackList"; -const char kStateSize[] = "_accessControlBlackList.size"; -const char kStateCapacity[] = "_accessControlBlackList.capacity"; +const char kTrait[] = "_accessRevocationList"; +const char kStateCapacity[] = "_accessRevocationList.capacity"; const char kUserId[] = "userId"; const char kApplicationId[] = "applicationId"; -const char kExpirationTimeout[] = "expirationTimeoutSec"; -const char kBlackList[] = "blackList"; +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, @@ -51,12 +52,12 @@ } // namespace AccessApiHandler::AccessApiHandler(Device* device, - AccessBlackListManager* manager) + AccessRevocationManager* manager) : device_{device}, manager_{manager} { device_->AddTraitDefinitionsFromJson(R"({ - "_accessControlBlackList": { + "_accessRevocationList": { "commands": { - "block": { + "revoke": { "minimalRole": "owner", "parameters": { "userId": { @@ -65,19 +66,11 @@ "applicationId": { "type": "string" }, - "expirationTimeoutSec": { + "revocationTimestamp": { "type": "integer" - } - } - }, - "unblock": { - "minimalRole": "owner", - "parameters": { - "userId": { - "type": "string" }, - "applicationId": { - "type": "string" + "expirationTime": { + "type": "integer" } } }, @@ -85,7 +78,7 @@ "minimalRole": "owner", "parameters": {}, "results": { - "blackList": { + "revocationEntriesList": { "type": "array", "items": { "type": "object", @@ -95,6 +88,12 @@ }, "applicationId": { "type": "string" + }, + "revocationTimestamp": { + "type": "integer" + }, + "expirationTime": { + "type": "integer" } }, "additionalProperties": false @@ -104,10 +103,6 @@ } }, "state": { - "size": { - "type": "integer", - "isRequired": true - }, "capacity": { "type": "integer", "isRequired": true @@ -119,13 +114,10 @@ UpdateState(); device_->AddCommandHandler( - kComponent, "_accessControlBlackList.block", + kComponent, "_accessRevocationList.revoke", base::Bind(&AccessApiHandler::Block, weak_ptr_factory_.GetWeakPtr())); device_->AddCommandHandler( - kComponent, "_accessControlBlackList.unblock", - base::Bind(&AccessApiHandler::Unblock, weak_ptr_factory_.GetWeakPtr())); - device_->AddCommandHandler( - kComponent, "_accessControlBlackList.list", + kComponent, "_accessRevocationList.list", base::Bind(&AccessApiHandler::List, weak_ptr_factory_.GetWeakPtr())); } @@ -147,38 +139,27 @@ return; } - int timeout_sec = 0; - parameters.GetInteger(kExpirationTimeout, &timeout_sec); - - base::Time expiration = - base::Time::Now() + base::TimeDelta::FromSeconds(timeout_sec); - - manager_->Block(user_id, app_id, expiration, - base::Bind(&AccessApiHandler::OnCommandDone, - weak_ptr_factory_.GetWeakPtr(), cmd)); -} - -void AccessApiHandler::Unblock(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)) { + 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; } - manager_->Unblock(user_id, app_id, - base::Bind(&AccessApiHandler::OnCommandDone, - weak_ptr_factory_.GetWeakPtr(), cmd)); + 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) { @@ -199,7 +180,7 @@ } base::DictionaryValue result; - result.Set(kBlackList, entries.release()); + result.Set(kRevocationList, entries.release()); command->Complete(result, nullptr); } @@ -219,7 +200,6 @@ void AccessApiHandler::UpdateState() { base::DictionaryValue state; - state.SetInteger(kStateSize, manager_->GetSize()); state.SetInteger(kStateCapacity, manager_->GetCapacity()); device_->SetStateProperties(kComponent, state, nullptr); }
diff --git a/src/access_api_handler.h b/src/access_api_handler.h index 821ce02..16eaa6f 100644 --- a/src/access_api_handler.h +++ b/src/access_api_handler.h
@@ -12,31 +12,29 @@ namespace weave { -class AccessBlackListManager; +class AccessRevocationManager; class Command; class Device; -// Handles commands for 'accessControlBlackList' trait. +// Handles commands for '_accessRevocationList' trait. // Objects of the class subscribe for notification from CommandManager and // execute incoming commands. // Handled commands: -// accessControlBlackList.block -// accessControlBlackList.unblock -// accessControlBlackList.list +// _accessRevocationList.revoke +// _accessRevocationList.list class AccessApiHandler final { public: - AccessApiHandler(Device* device, AccessBlackListManager* manager); + AccessApiHandler(Device* device, AccessRevocationManager* manager); private: void Block(const std::weak_ptr<Command>& command); - void Unblock(const std::weak_ptr<Command>& command); void List(const std::weak_ptr<Command>& command); void UpdateState(); void OnCommandDone(const std::weak_ptr<Command>& command, ErrorPtr error); Device* device_{nullptr}; - AccessBlackListManager* manager_{nullptr}; + AccessRevocationManager* manager_{nullptr}; base::WeakPtrFactory<AccessApiHandler> weak_ptr_factory_{this}; DISALLOW_COPY_AND_ASSIGN(AccessApiHandler);
diff --git a/src/access_api_handler_unittest.cc b/src/access_api_handler_unittest.cc index 3e7f5d7..fda0748 100644 --- a/src/access_api_handler_unittest.cc +++ b/src/access_api_handler_unittest.cc
@@ -9,9 +9,10 @@ #include <weave/test/mock_device.h> #include <weave/test/unittest_utils.h> +#include "src/access_revocation_manager.h" #include "src/component_manager_impl.h" -#include "src/access_black_list_manager.h" #include "src/data_encoding.h" +#include "src/test/mock_access_revocation_manager.h" using testing::_; using testing::AnyOf; @@ -22,25 +23,6 @@ namespace weave { -class MockAccessBlackListManager : public AccessBlackListManager { - public: - MOCK_METHOD4(Block, - void(const std::vector<uint8_t>&, - const std::vector<uint8_t>&, - const base::Time&, - const DoneCallback&)); - MOCK_METHOD3(Unblock, - void(const std::vector<uint8_t>&, - const std::vector<uint8_t>&, - const DoneCallback&)); - MOCK_CONST_METHOD2(IsBlocked, - bool(const std::vector<uint8_t>&, - const std::vector<uint8_t>&)); - MOCK_CONST_METHOD0(GetEntries, std::vector<Entry>()); - MOCK_CONST_METHOD0(GetSize, size_t()); - MOCK_CONST_METHOD0(GetCapacity, size_t()); -}; - class AccessApiHandlerTest : public ::testing::Test { protected: void SetUp() override { @@ -62,9 +44,8 @@ })); EXPECT_CALL(device_, - AddCommandHandler(_, AnyOf("_accessControlBlackList.block", - "_accessControlBlackList.unblock", - "_accessControlBlackList.list"), + AddCommandHandler(_, AnyOf("_accessRevocationList.revoke", + "_accessRevocationList.list"), _)) .WillRepeatedly( Invoke(&component_manager_, &ComponentManager::AddCommandHandler)); @@ -90,31 +71,31 @@ std::unique_ptr<base::DictionaryValue> GetState() { std::string path = - component_manager_.FindComponentWithTrait("_accessControlBlackList"); + component_manager_.FindComponentWithTrait("_accessRevocationList"); EXPECT_FALSE(path.empty()); const auto* component = component_manager_.FindComponent(path, nullptr); EXPECT_TRUE(component); const base::DictionaryValue* state = nullptr; EXPECT_TRUE( - component->GetDictionary("state._accessControlBlackList", &state)); + component->GetDictionary("state._accessRevocationList", &state)); return std::unique_ptr<base::DictionaryValue>{state->DeepCopy()}; } StrictMock<provider::test::FakeTaskRunner> task_runner_; ComponentManagerImpl component_manager_{&task_runner_}; StrictMock<test::MockDevice> device_; - StrictMock<MockAccessBlackListManager> access_manager_; + StrictMock<test::MockAccessRevocationManager> access_manager_; std::unique_ptr<AccessApiHandler> handler_; }; TEST_F(AccessApiHandlerTest, Initialization) { const base::DictionaryValue* trait = nullptr; ASSERT_TRUE(component_manager_.GetTraits().GetDictionary( - "_accessControlBlackList", &trait)); + "_accessRevocationList", &trait)); auto expected = R"({ "commands": { - "block": { + "revoke": { "minimalRole": "owner", "parameters": { "userId": { @@ -123,19 +104,11 @@ "applicationId": { "type": "string" }, - "expirationTimeoutSec": { + "revocationTimestamp": { "type": "integer" - } - } - }, - "unblock": { - "minimalRole": "owner", - "parameters": { - "userId": { - "type": "string" }, - "applicationId": { - "type": "string" + "expirationTime": { + "type": "integer" } } }, @@ -143,7 +116,7 @@ "minimalRole": "owner", "parameters": {}, "results": { - "blackList": { + "revocationEntriesList": { "type": "array", "items": { "type": "object", @@ -153,6 +126,12 @@ }, "applicationId": { "type": "string" + }, + "revocationTimestamp": { + "type": "integer" + }, + "expirationTime": { + "type": "integer" } }, "additionalProperties": false @@ -162,10 +141,6 @@ } }, "state": { - "size": { - "type": "integer", - "isRequired": true - }, "capacity": { "type": "integer", "isRequired": true @@ -175,70 +150,56 @@ EXPECT_JSON_EQ(expected, *trait); expected = R"({ - "capacity": 10, - "size": 0 + "capacity": 10 })"; EXPECT_JSON_EQ(expected, *GetState()); } -TEST_F(AccessApiHandlerTest, Block) { - EXPECT_CALL(access_manager_, Block(std::vector<uint8_t>{1, 2, 3}, - std::vector<uint8_t>{3, 4, 5}, _, _)) - .WillOnce(WithArgs<3>( +TEST_F(AccessApiHandlerTest, Revoke) { + EXPECT_CALL( + access_manager_, + Block(AccessRevocationManager::Entry{std::vector<uint8_t>{1, 2, 3}, + std::vector<uint8_t>{3, 4, 5}, + base::Time::FromTimeT(946686034), + base::Time::FromTimeT(946692690)}, + _)) + .WillOnce(WithArgs<1>( Invoke([](const DoneCallback& callback) { callback.Run(nullptr); }))); EXPECT_CALL(access_manager_, GetSize()).WillRepeatedly(Return(1)); AddCommand(R"({ - 'name' : '_accessControlBlackList.block', + 'name' : '_accessRevocationList.revoke', 'component': 'accessControl', 'parameters': { 'userId': 'AQID', 'applicationId': 'AwQF', - 'expirationTimeoutSec': 1234 + 'expirationTime': 7890, + 'revocationTimestamp': 1234 } })"); auto expected = R"({ - "capacity": 10, - "size": 1 - })"; - EXPECT_JSON_EQ(expected, *GetState()); -} - -TEST_F(AccessApiHandlerTest, Unblock) { - EXPECT_CALL(access_manager_, Unblock(std::vector<uint8_t>{1, 2, 3}, - std::vector<uint8_t>{3, 4, 5}, _)) - .WillOnce(WithArgs<2>( - Invoke([](const DoneCallback& callback) { callback.Run(nullptr); }))); - EXPECT_CALL(access_manager_, GetSize()).WillRepeatedly(Return(4)); - - AddCommand(R"({ - 'name' : '_accessControlBlackList.unblock', - 'component': 'accessControl', - 'parameters': { - 'userId': 'AQID', - 'applicationId': 'AwQF', - 'expirationTimeoutSec': 1234 - } - })"); - - auto expected = R"({ - "capacity": 10, - "size": 4 + "capacity": 10 })"; EXPECT_JSON_EQ(expected, *GetState()); } TEST_F(AccessApiHandlerTest, List) { - std::vector<AccessBlackListManager::Entry> entries{ - {{11, 12, 13}, {21, 22, 23}, base::Time::FromTimeT(1410000000)}, - {{31, 32, 33}, {41, 42, 43}, base::Time::FromTimeT(1420000000)}, + std::vector<AccessRevocationManager::Entry> entries{ + {{11, 12, 13}, + {21, 22, 23}, + base::Time::FromTimeT(1310000000), + base::Time::FromTimeT(1410000000)}, + {{31, 32, 33}, + {41, 42, 43}, + base::Time::FromTimeT(1300000000), + base::Time::FromTimeT(1420000000)}, }; EXPECT_CALL(access_manager_, GetEntries()).WillOnce(Return(entries)); EXPECT_CALL(access_manager_, GetSize()).WillRepeatedly(Return(4)); auto expected = R"({ - "blackList": [ { + "revocationListEntries": [ { "applicationId": "FRYX", "userId": "CwwN" }, { @@ -248,7 +209,7 @@ })"; const auto& results = AddCommand(R"({ - 'name' : '_accessControlBlackList.list', + 'name' : '_accessRevocationList.list', 'component': 'accessControl', 'parameters': { }
diff --git a/src/access_black_list_manager.h b/src/access_black_list_manager.h deleted file mode 100644 index b56226a..0000000 --- a/src/access_black_list_manager.h +++ /dev/null
@@ -1,56 +0,0 @@ -// 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. - -#ifndef LIBWEAVE_SRC_ACCESS_BLACK_LIST_H_ -#define LIBWEAVE_SRC_ACCESS_BLACK_LIST_H_ - -#include <vector> - -#include <base/time/time.h> - -namespace weave { - -class AccessBlackListManager { - public: - struct Entry { - // user_id is empty, app_id is empty: block everything. - // user_id is not empty, app_id is empty: block if user_id matches. - // user_id is empty, app_id is not empty: block if app_id matches. - // user_id is not empty, app_id is not empty: block if both match. - std::vector<uint8_t> user_id; - std::vector<uint8_t> app_id; - - // Time after which to discard the rule. - base::Time expiration; - }; - virtual ~AccessBlackListManager() = default; - - virtual void Block(const std::vector<uint8_t>& user_id, - const std::vector<uint8_t>& app_id, - const base::Time& expiration, - const DoneCallback& callback) = 0; - virtual void Unblock(const std::vector<uint8_t>& user_id, - const std::vector<uint8_t>& app_id, - const DoneCallback& callback) = 0; - virtual bool IsBlocked(const std::vector<uint8_t>& user_id, - const std::vector<uint8_t>& app_id) const = 0; - virtual std::vector<Entry> GetEntries() const = 0; - virtual size_t GetSize() const = 0; - virtual size_t GetCapacity() const = 0; -}; - -inline bool operator==(const AccessBlackListManager::Entry& l, - const AccessBlackListManager::Entry& r) { - return l.user_id == r.user_id && l.app_id == r.app_id && - l.expiration == r.expiration; -} - -inline bool operator!=(const AccessBlackListManager::Entry& l, - const AccessBlackListManager::Entry& r) { - return !(l == r); -} - -} // namespace weave - -#endif // LIBWEAVE_SRC_ACCESS_BLACK_LIST_H_
diff --git a/src/access_black_list_manager_impl.cc b/src/access_black_list_manager_impl.cc deleted file mode 100644 index 992a680..0000000 --- a/src/access_black_list_manager_impl.cc +++ /dev/null
@@ -1,163 +0,0 @@ -// 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_black_list_manager_impl.h" - -#include <base/json/json_reader.h> -#include <base/json/json_writer.h> -#include <base/values.h> - -#include "src/commands/schema_constants.h" -#include "src/data_encoding.h" - -namespace weave { - -namespace { -const char kConfigFileName[] = "black_list"; - -const char kUser[] = "user"; -const char kApp[] = "app"; -const char kExpiration[] = "expiration"; -} - -AccessBlackListManagerImpl::AccessBlackListManagerImpl( - provider::ConfigStore* store, - size_t capacity, - base::Clock* clock) - : capacity_{capacity}, clock_{clock}, store_{store} { - Load(); -} - -void AccessBlackListManagerImpl::Load() { - if (!store_) - return; - if (auto list = base::ListValue::From( - base::JSONReader::Read(store_->LoadSettings(kConfigFileName)))) { - for (const auto& e : *list) { - const base::DictionaryValue* entry{nullptr}; - std::string user; - std::string app; - decltype(entries_)::key_type key; - int expiration; - if (e->GetAsDictionary(&entry) && entry->GetString(kUser, &user) && - Base64Decode(user, &key.first) && entry->GetString(kApp, &app) && - Base64Decode(app, &key.second) && - entry->GetInteger(kExpiration, &expiration)) { - base::Time expiration_time = base::Time::FromTimeT(expiration); - if (expiration_time > clock_->Now()) - entries_[key] = expiration_time; - } - } - if (entries_.size() < list->GetSize()) { - // Save some storage space by saving without expired entries. - Save({}); - } - } -} - -void AccessBlackListManagerImpl::Save(const DoneCallback& callback) { - if (!store_) { - if (!callback.is_null()) - callback.Run(nullptr); - return; - } - - base::ListValue list; - for (const auto& e : entries_) { - scoped_ptr<base::DictionaryValue> entry{new base::DictionaryValue}; - entry->SetString(kUser, Base64Encode(e.first.first)); - entry->SetString(kApp, Base64Encode(e.first.second)); - entry->SetInteger(kExpiration, e.second.ToTimeT()); - list.Append(std::move(entry)); - } - - std::string json; - base::JSONWriter::Write(list, &json); - store_->SaveSettings(kConfigFileName, json, callback); -} - -void AccessBlackListManagerImpl::RemoveExpired() { - for (auto i = begin(entries_); i != end(entries_);) { - if (i->second <= clock_->Now()) - i = entries_.erase(i); - else - ++i; - } -} - -void AccessBlackListManagerImpl::Block(const std::vector<uint8_t>& user_id, - const std::vector<uint8_t>& app_id, - const base::Time& expiration, - const DoneCallback& callback) { - // Iterating is OK as Save below is more expensive. - RemoveExpired(); - if (expiration <= clock_->Now()) { - if (!callback.is_null()) { - ErrorPtr error; - Error::AddTo(&error, FROM_HERE, "aleady_expired", - "Entry already expired"); - callback.Run(std::move(error)); - } - return; - } - if (entries_.size() >= capacity_) { - if (!callback.is_null()) { - ErrorPtr error; - Error::AddTo(&error, FROM_HERE, "blacklist_is_full", - "Unable to store more entries"); - callback.Run(std::move(error)); - } - return; - } - auto& value = entries_[std::make_pair(user_id, app_id)]; - value = std::max(value, expiration); - Save(callback); -} - -void AccessBlackListManagerImpl::Unblock(const std::vector<uint8_t>& user_id, - const std::vector<uint8_t>& app_id, - const DoneCallback& callback) { - if (!entries_.erase(std::make_pair(user_id, app_id))) { - if (!callback.is_null()) { - ErrorPtr error; - Error::AddTo(&error, FROM_HERE, "entry_not_found", "Unknown entry"); - callback.Run(std::move(error)); - } - return; - } - // Iterating is OK as Save below is more expensive. - RemoveExpired(); - Save(callback); -} - -bool AccessBlackListManagerImpl::IsBlocked( - const std::vector<uint8_t>& user_id, - const std::vector<uint8_t>& app_id) const { - for (const auto& user : {{}, user_id}) { - for (const auto& app : {{}, app_id}) { - auto both = entries_.find(std::make_pair(user, app)); - if (both != end(entries_) && both->second > clock_->Now()) - return true; - } - } - return false; -} - -std::vector<AccessBlackListManager::Entry> -AccessBlackListManagerImpl::GetEntries() const { - std::vector<Entry> result; - for (const auto& e : entries_) - result.push_back({e.first.first, e.first.second, e.second}); - return result; -} - -size_t AccessBlackListManagerImpl::GetSize() const { - return entries_.size(); -} - -size_t AccessBlackListManagerImpl::GetCapacity() const { - return capacity_; -} - -} // namespace weave
diff --git a/src/access_black_list_manager_impl.h b/src/access_black_list_manager_impl.h deleted file mode 100644 index 1c175db..0000000 --- a/src/access_black_list_manager_impl.h +++ /dev/null
@@ -1,58 +0,0 @@ -// 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. - -#ifndef LIBWEAVE_SRC_ACCESS_BLACK_LIST_IMPL_H_ -#define LIBWEAVE_SRC_ACCESS_BLACK_LIST_IMPL_H_ - -#include <map> -#include <utility> - -#include <base/time/default_clock.h> -#include <base/time/time.h> -#include <weave/error.h> -#include <weave/provider/config_store.h> - -#include "src/access_black_list_manager.h" - -namespace weave { - -class AccessBlackListManagerImpl : public AccessBlackListManager { - public: - explicit AccessBlackListManagerImpl(provider::ConfigStore* store, - size_t capacity = 1024, - base::Clock* clock = nullptr); - - // AccessBlackListManager implementation. - void Block(const std::vector<uint8_t>& user_id, - const std::vector<uint8_t>& app_id, - const base::Time& expiration, - const DoneCallback& callback) override; - void Unblock(const std::vector<uint8_t>& user_id, - const std::vector<uint8_t>& app_id, - const DoneCallback& callback) override; - bool IsBlocked(const std::vector<uint8_t>& user_id, - const std::vector<uint8_t>& app_id) const override; - std::vector<Entry> GetEntries() const override; - size_t GetSize() const override; - size_t GetCapacity() const override; - - private: - void Load(); - void Save(const DoneCallback& callback); - void RemoveExpired(); - - const size_t capacity_{0}; - base::DefaultClock default_clock_; - base::Clock* clock_{&default_clock_}; - - provider::ConfigStore* store_{nullptr}; - std::map<std::pair<std::vector<uint8_t>, std::vector<uint8_t>>, base::Time> - entries_; - - DISALLOW_COPY_AND_ASSIGN(AccessBlackListManagerImpl); -}; - -} // namespace weave - -#endif // LIBWEAVE_SRC_ACCESS_BLACK_LIST_IMPL_H_
diff --git a/src/access_black_list_manager_impl_unittest.cc b/src/access_black_list_manager_impl_unittest.cc deleted file mode 100644 index fd9f226..0000000 --- a/src/access_black_list_manager_impl_unittest.cc +++ /dev/null
@@ -1,165 +0,0 @@ -// 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_black_list_manager_impl.h" - -#include <gmock/gmock.h> -#include <gtest/gtest.h> -#include <weave/provider/test/mock_config_store.h> -#include <weave/test/unittest_utils.h> - -#include "src/test/mock_clock.h" -#include "src/bind_lambda.h" - -using testing::_; -using testing::Return; -using testing::StrictMock; - -namespace weave { - -class AccessBlackListManagerImplTest : public testing::Test { - protected: - void SetUp() { - std::string to_load = R"([{ - "user": "BQID", - "app": "BwQF", - "expiration": 1410000000 - }, { - "user": "AQID", - "app": "AwQF", - "expiration": 1419999999 - }])"; - - EXPECT_CALL(config_store_, LoadSettings("black_list")) - .WillOnce(Return(to_load)); - - EXPECT_CALL(config_store_, SaveSettings("black_list", _, _)) - .WillOnce(testing::WithArgs<1, 2>(testing::Invoke( - [](const std::string& json, const DoneCallback& callback) { - std::string to_save = R"([{ - "user": "AQID", - "app": "AwQF", - "expiration": 1419999999 - }])"; - EXPECT_JSON_EQ(to_save, *test::CreateValue(json)); - if (!callback.is_null()) - callback.Run(nullptr); - }))); - - EXPECT_CALL(clock_, Now()) - .WillRepeatedly(Return(base::Time::FromTimeT(1412121212))); - manager_.reset(new AccessBlackListManagerImpl{&config_store_, 10, &clock_}); - } - StrictMock<test::MockClock> clock_; - StrictMock<provider::test::MockConfigStore> config_store_{false}; - std::unique_ptr<AccessBlackListManagerImpl> manager_; -}; - -TEST_F(AccessBlackListManagerImplTest, Init) { - EXPECT_EQ(1u, manager_->GetSize()); - EXPECT_EQ(10u, manager_->GetCapacity()); - EXPECT_EQ((std::vector<AccessBlackListManagerImpl::Entry>{{ - {1, 2, 3}, {3, 4, 5}, base::Time::FromTimeT(1419999999), - }}), - manager_->GetEntries()); -} - -TEST_F(AccessBlackListManagerImplTest, Block) { - EXPECT_CALL(config_store_, SaveSettings("black_list", _, _)) - .WillOnce(testing::WithArgs<1, 2>(testing::Invoke( - [](const std::string& json, const DoneCallback& callback) { - std::string to_save = R"([{ - "user": "AQID", - "app": "AwQF", - "expiration": 1419999999 - }, { - "app": "CAgI", - "user": "BwcH", - "expiration": 1419990000 - }])"; - EXPECT_JSON_EQ(to_save, *test::CreateValue(json)); - if (!callback.is_null()) - callback.Run(nullptr); - }))); - manager_->Block({7, 7, 7}, {8, 8, 8}, base::Time::FromTimeT(1419990000), {}); -} - -TEST_F(AccessBlackListManagerImplTest, BlockExpired) { - manager_->Block({}, {}, base::Time::FromTimeT(1400000000), - base::Bind([](ErrorPtr error) { - EXPECT_TRUE(error->HasError("aleady_expired")); - })); -} - -TEST_F(AccessBlackListManagerImplTest, BlockListIsFull) { - EXPECT_CALL(config_store_, SaveSettings("black_list", _, _)) - .WillRepeatedly(testing::WithArgs<1, 2>(testing::Invoke( - [](const std::string& json, const DoneCallback& callback) { - if (!callback.is_null()) - callback.Run(nullptr); - }))); - for (size_t i = manager_->GetSize(); i < manager_->GetCapacity(); ++i) { - manager_->Block( - {99, static_cast<uint8_t>(i / 256), static_cast<uint8_t>(i % 256)}, - {8, 8, 8}, base::Time::FromTimeT(1419990000), {}); - EXPECT_EQ(i + 1, manager_->GetSize()); - } - manager_->Block({99}, {8, 8, 8}, base::Time::FromTimeT(1419990000), - base::Bind([](ErrorPtr error) { - EXPECT_TRUE(error->HasError("blacklist_is_full")); - })); -} - -TEST_F(AccessBlackListManagerImplTest, Unblock) { - EXPECT_CALL(config_store_, SaveSettings("black_list", _, _)) - .WillOnce(testing::WithArgs<1, 2>(testing::Invoke( - [](const std::string& json, const DoneCallback& callback) { - EXPECT_JSON_EQ("[]", *test::CreateValue(json)); - if (!callback.is_null()) - callback.Run(nullptr); - }))); - manager_->Unblock({1, 2, 3}, {3, 4, 5}, {}); -} - -TEST_F(AccessBlackListManagerImplTest, UnblockNotFound) { - manager_->Unblock({5, 2, 3}, {5, 4, 5}, base::Bind([](ErrorPtr error) { - EXPECT_TRUE(error->HasError("entry_not_found")); - })); -} - -TEST_F(AccessBlackListManagerImplTest, IsBlockedFalse) { - EXPECT_FALSE(manager_->IsBlocked({7, 7, 7}, {8, 8, 8})); -} - -class AccessBlackListManagerImplIsBlockedTest - : public AccessBlackListManagerImplTest, - public testing::WithParamInterface< - std::tuple<std::vector<uint8_t>, std::vector<uint8_t>>> { - public: - void SetUp() override { - AccessBlackListManagerImplTest::SetUp(); - EXPECT_CALL(config_store_, SaveSettings("black_list", _, _)) - .WillOnce(testing::WithArgs<2>( - testing::Invoke([](const DoneCallback& callback) { - if (!callback.is_null()) - callback.Run(nullptr); - }))); - manager_->Block(std::get<0>(GetParam()), std::get<1>(GetParam()), - base::Time::FromTimeT(1419990000), {}); - } -}; - -TEST_P(AccessBlackListManagerImplIsBlockedTest, IsBlocked) { - EXPECT_TRUE(manager_->IsBlocked({7, 7, 7}, {8, 8, 8})); -} - -INSTANTIATE_TEST_CASE_P( - Filters, - AccessBlackListManagerImplIsBlockedTest, - testing::Combine(testing::Values(std::vector<uint8_t>{}, - std::vector<uint8_t>{7, 7, 7}), - testing::Values(std::vector<uint8_t>{}, - std::vector<uint8_t>{8, 8, 8}))); - -} // namespace weave
diff --git a/src/access_revocation_manager.h b/src/access_revocation_manager.h new file mode 100644 index 0000000..6d5bf7b --- /dev/null +++ b/src/access_revocation_manager.h
@@ -0,0 +1,66 @@ +// 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. + +#ifndef LIBWEAVE_SRC_ACCESS_REVOCATION_MANAGER_H_ +#define LIBWEAVE_SRC_ACCESS_REVOCATION_MANAGER_H_ + +#include <vector> + +#include <base/time/time.h> + +namespace weave { + +class AccessRevocationManager { + public: + struct Entry { + Entry() = default; + + Entry(const std::vector<uint8_t>& user, + const std::vector<uint8_t>& app, + base::Time revocation_ts, + base::Time expiration_ts) + : user_id{user}, + app_id{app}, + revocation{revocation_ts}, + expiration{expiration_ts} {} + // user_id is empty, app_id is empty: block everything. + // user_id is not empty, app_id is empty: block if user_id matches. + // user_id is empty, app_id is not empty: block if app_id matches. + // user_id is not empty, app_id is not empty: block if both match. + std::vector<uint8_t> user_id; + std::vector<uint8_t> app_id; + + // Revoke matching entries if |revocation| is not less than + // delegation timestamp. + base::Time revocation; + + // Time after which to discard the rule. + base::Time expiration; + }; + virtual ~AccessRevocationManager() = default; + + virtual void AddEntryAddedCallback(const base::Closure& callback) = 0; + virtual void Block(const Entry& entry, const DoneCallback& callback) = 0; + virtual bool IsBlocked(const std::vector<uint8_t>& user_id, + const std::vector<uint8_t>& app_id, + base::Time timestamp) const = 0; + virtual std::vector<Entry> GetEntries() const = 0; + virtual size_t GetSize() const = 0; + virtual size_t GetCapacity() const = 0; +}; + +inline bool operator==(const AccessRevocationManager::Entry& l, + const AccessRevocationManager::Entry& r) { + return l.revocation == r.revocation && l.expiration == r.expiration && + l.user_id == r.user_id && l.app_id == r.app_id; +} + +inline bool operator!=(const AccessRevocationManager::Entry& l, + const AccessRevocationManager::Entry& r) { + return !(l == r); +} + +} // namespace weave + +#endif // LIBWEAVE_SRC_ACCESS_REVOCATION_MANAGER_H_
diff --git a/src/access_revocation_manager_impl.cc b/src/access_revocation_manager_impl.cc new file mode 100644 index 0000000..f039114 --- /dev/null +++ b/src/access_revocation_manager_impl.cc
@@ -0,0 +1,171 @@ +// 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_revocation_manager_impl.h" + +#include <base/json/json_reader.h> +#include <base/json/json_writer.h> +#include <base/values.h> + +#include "src/commands/schema_constants.h" +#include "src/data_encoding.h" +#include "src/utils.h" + +namespace weave { + +namespace { +const char kConfigFileName[] = "black_list"; + +const char kUser[] = "user"; +const char kApp[] = "app"; +const char kExpiration[] = "expiration"; +const char kRevocation[] = "revocation"; +} + +AccessRevocationManagerImpl::AccessRevocationManagerImpl( + provider::ConfigStore* store, + size_t capacity, + base::Clock* clock) + : capacity_{capacity}, clock_{clock}, store_{store} { + Load(); +} + +void AccessRevocationManagerImpl::Load() { + if (!store_) + return; + if (auto list = base::ListValue::From( + base::JSONReader::Read(store_->LoadSettings(kConfigFileName)))) { + for (const auto& value : *list) { + const base::DictionaryValue* entry{nullptr}; + std::string user; + std::string app; + Entry e; + int revocation = 0; + int expiration = 0; + if (value->GetAsDictionary(&entry) && entry->GetString(kUser, &user) && + Base64Decode(user, &e.user_id) && entry->GetString(kApp, &app) && + Base64Decode(app, &e.app_id) && + entry->GetInteger(kRevocation, &revocation) && + entry->GetInteger(kExpiration, &expiration)) { + e.revocation = FromJ2000Time(revocation); + e.expiration = FromJ2000Time(expiration); + if (e.expiration > clock_->Now()) + entries_.insert(e); + } + } + if (entries_.size() < list->GetSize()) { + // Save some storage space by saving without expired entries. + Save({}); + } + } +} + +void AccessRevocationManagerImpl::Save(const DoneCallback& callback) { + if (!store_) { + if (!callback.is_null()) + callback.Run(nullptr); + return; + } + + base::ListValue list; + for (const auto& e : entries_) { + scoped_ptr<base::DictionaryValue> entry{new base::DictionaryValue}; + entry->SetString(kUser, Base64Encode(e.user_id)); + entry->SetString(kApp, Base64Encode(e.app_id)); + entry->SetInteger(kRevocation, ToJ2000Time(e.revocation)); + entry->SetInteger(kExpiration, ToJ2000Time(e.expiration)); + list.Append(std::move(entry)); + } + + std::string json; + base::JSONWriter::Write(list, &json); + store_->SaveSettings(kConfigFileName, json, callback); +} + +void AccessRevocationManagerImpl::RemoveExpired() { + for (auto i = begin(entries_); i != end(entries_);) { + if (i->expiration <= clock_->Now()) + i = entries_.erase(i); + else + ++i; + } +} + +void AccessRevocationManagerImpl::AddEntryAddedCallback( + const base::Closure& callback) { + on_entry_added_callbacks_.push_back(callback); +} + +void AccessRevocationManagerImpl::Block(const Entry& entry, + const DoneCallback& callback) { + // Iterating is OK as Save below is more expensive. + RemoveExpired(); + if (entry.expiration <= clock_->Now()) { + if (!callback.is_null()) { + ErrorPtr error; + Error::AddTo(&error, FROM_HERE, "aleady_expired", + "Entry already expired"); + callback.Run(std::move(error)); + } + return; + } + if (entries_.size() >= capacity_) { + if (!callback.is_null()) { + ErrorPtr error; + Error::AddTo(&error, FROM_HERE, "blacklist_is_full", + "Unable to store more entries"); + callback.Run(std::move(error)); + } + return; + } + + auto existing = entries_.find(entry); + if (existing != entries_.end()) { + Entry new_entry = entry; + new_entry.expiration = std::max(entry.expiration, existing->expiration); + new_entry.revocation = std::max(entry.revocation, existing->revocation); + entries_.erase(existing); + entries_.insert(new_entry); + } else { + entries_.insert(entry); + } + + for (const auto& cb : on_entry_added_callbacks_) + cb.Run(); + + Save(callback); +} + +bool AccessRevocationManagerImpl::IsBlocked(const std::vector<uint8_t>& user_id, + const std::vector<uint8_t>& app_id, + base::Time timestamp) const { + Entry entry_to_find; + for (const auto& user : {{}, user_id}) { + for (const auto& app : {{}, app_id}) { + entry_to_find.user_id = user; + entry_to_find.app_id = app; + auto match = entries_.find(entry_to_find); + if (match != end(entries_) && match->expiration > clock_->Now() && + match->revocation >= timestamp) { + return true; + } + } + } + return false; +} + +std::vector<AccessRevocationManager::Entry> +AccessRevocationManagerImpl::GetEntries() const { + return {begin(entries_), end(entries_)}; +} + +size_t AccessRevocationManagerImpl::GetSize() const { + return entries_.size(); +} + +size_t AccessRevocationManagerImpl::GetCapacity() const { + return capacity_; +} + +} // namespace weave
diff --git a/src/access_revocation_manager_impl.h b/src/access_revocation_manager_impl.h new file mode 100644 index 0000000..a911128 --- /dev/null +++ b/src/access_revocation_manager_impl.h
@@ -0,0 +1,64 @@ +// 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. + +#ifndef LIBWEAVE_SRC_ACCESS_REVOCATION_MANAGER_IMPL_H_ +#define LIBWEAVE_SRC_ACCESS_REVOCATION_MANAGER_IMPL_H_ + +#include <set> +#include <utility> + +#include <base/time/default_clock.h> +#include <base/time/time.h> +#include <weave/error.h> +#include <weave/provider/config_store.h> + +#include "src/access_revocation_manager.h" + +namespace weave { + +class AccessRevocationManagerImpl : public AccessRevocationManager { + public: + explicit AccessRevocationManagerImpl(provider::ConfigStore* store, + size_t capacity = 1024, + base::Clock* clock = nullptr); + + // AccessRevocationManager implementation. + void AddEntryAddedCallback(const base::Closure& callback) override; + void Block(const Entry& entry, const DoneCallback& callback) override; + bool IsBlocked(const std::vector<uint8_t>& user_id, + const std::vector<uint8_t>& app_id, + base::Time timestamp) const override; + std::vector<Entry> GetEntries() const override; + size_t GetSize() const override; + size_t GetCapacity() const override; + + private: + void Load(); + void Save(const DoneCallback& callback); + void RemoveExpired(); + + struct EntryIdsLess { + bool operator()(const Entry& l, const Entry& r) const { + if (l.user_id < r.user_id) + return true; + if (l.user_id > r.user_id) + return false; + return l.app_id < r.app_id; + } + }; + + const size_t capacity_{0}; + base::DefaultClock default_clock_; + base::Clock* clock_{&default_clock_}; + + provider::ConfigStore* store_{nullptr}; + std::set<Entry, EntryIdsLess> entries_; + std::vector<base::Closure> on_entry_added_callbacks_; + + DISALLOW_COPY_AND_ASSIGN(AccessRevocationManagerImpl); +}; + +} // namespace weave + +#endif // LIBWEAVE_SRC_ACCESS_REVOCATION_MANAGER_IMPL_H_
diff --git a/src/access_revocation_manager_impl_unittest.cc b/src/access_revocation_manager_impl_unittest.cc new file mode 100644 index 0000000..b0b774b --- /dev/null +++ b/src/access_revocation_manager_impl_unittest.cc
@@ -0,0 +1,183 @@ +// 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_revocation_manager_impl.h" + +#include <gmock/gmock.h> +#include <gtest/gtest.h> +#include <weave/provider/test/mock_config_store.h> +#include <weave/test/unittest_utils.h> + +#include "src/test/mock_clock.h" +#include "src/bind_lambda.h" + +using testing::_; +using testing::Return; +using testing::StrictMock; + +namespace weave { + +class AccessRevocationManagerImplTest : public testing::Test { + protected: + void SetUp() { + std::string to_load = R"([{ + "user": "BQID", + "app": "BwQF", + "expiration": 463315200, + "revocation": 463314200 + }, { + "user": "AQID", + "app": "AwQF", + "expiration": 473315199, + "revocation": 473313199 + }])"; + + EXPECT_CALL(config_store_, LoadSettings("black_list")) + .WillOnce(Return(to_load)); + + EXPECT_CALL(config_store_, SaveSettings("black_list", _, _)) + .WillOnce(testing::WithArgs<1, 2>(testing::Invoke( + [](const std::string& json, const DoneCallback& callback) { + std::string to_save = R"([{ + "user": "AQID", + "app": "AwQF", + "expiration": 473315199, + "revocation": 473313199 + }])"; + EXPECT_JSON_EQ(to_save, *test::CreateValue(json)); + if (!callback.is_null()) + callback.Run(nullptr); + }))); + + EXPECT_CALL(clock_, Now()) + .WillRepeatedly(Return(base::Time::FromTimeT(1412121212))); + manager_.reset( + new AccessRevocationManagerImpl{&config_store_, 10, &clock_}); + } + StrictMock<test::MockClock> clock_; + StrictMock<provider::test::MockConfigStore> config_store_{false}; + std::unique_ptr<AccessRevocationManagerImpl> manager_; +}; + +TEST_F(AccessRevocationManagerImplTest, Init) { + EXPECT_EQ(1u, manager_->GetSize()); + EXPECT_EQ(10u, manager_->GetCapacity()); + EXPECT_EQ((std::vector<AccessRevocationManagerImpl::Entry>{{ + {1, 2, 3}, + {3, 4, 5}, + base::Time::FromTimeT(1419997999), + base::Time::FromTimeT(1419999999), + }}), + manager_->GetEntries()); +} + +TEST_F(AccessRevocationManagerImplTest, Block) { + bool callback_called = false; + manager_->AddEntryAddedCallback( + base::Bind([&callback_called]() { callback_called = true; })); + EXPECT_CALL(config_store_, SaveSettings("black_list", _, _)) + .WillOnce(testing::WithArgs<1, 2>(testing::Invoke( + [](const std::string& json, const DoneCallback& callback) { + std::string to_save = R"([{ + "user": "AQID", + "app": "AwQF", + "expiration": 473315199, + "revocation": 473313199 + }, { + "app": "CAgI", + "user": "BwcH", + "expiration": 473305200, + "revocation": 473295200 + }])"; + EXPECT_JSON_EQ(to_save, *test::CreateValue(json)); + if (!callback.is_null()) + callback.Run(nullptr); + }))); + manager_->Block({{7, 7, 7}, + {8, 8, 8}, + base::Time::FromTimeT(1419980000), + base::Time::FromTimeT(1419990000)}, + {}); + EXPECT_TRUE(callback_called); +} + +TEST_F(AccessRevocationManagerImplTest, BlockExpired) { + manager_->Block({{}, + {}, + base::Time::FromTimeT(1300000000), + base::Time::FromTimeT(1400000000)}, + base::Bind([](ErrorPtr error) { + EXPECT_TRUE(error->HasError("aleady_expired")); + })); +} + +TEST_F(AccessRevocationManagerImplTest, BlockListIsFull) { + EXPECT_CALL(config_store_, SaveSettings("black_list", _, _)) + .WillRepeatedly(testing::WithArgs<1, 2>(testing::Invoke( + [](const std::string& json, const DoneCallback& callback) { + if (!callback.is_null()) + callback.Run(nullptr); + }))); + for (size_t i = manager_->GetSize(); i < manager_->GetCapacity(); ++i) { + manager_->Block( + {{99, static_cast<uint8_t>(i / 256), static_cast<uint8_t>(i % 256)}, + {8, 8, 8}, + base::Time::FromTimeT(1419970000), + base::Time::FromTimeT(1419990000)}, + {}); + EXPECT_EQ(i + 1, manager_->GetSize()); + } + manager_->Block({{99}, + {8, 8, 8}, + base::Time::FromTimeT(1419970000), + base::Time::FromTimeT(1419990000)}, + base::Bind([](ErrorPtr error) { + EXPECT_TRUE(error->HasError("blacklist_is_full")); + })); +} + +TEST_F(AccessRevocationManagerImplTest, IsBlockedIdsNotMacth) { + EXPECT_FALSE(manager_->IsBlocked({7, 7, 7}, {8, 8, 8}, {})); +} + +TEST_F(AccessRevocationManagerImplTest, IsBlockedRevocationIsOld) { + // Ids match but delegation time is newer than revocation time. + EXPECT_FALSE(manager_->IsBlocked({1, 2, 3}, {3, 4, 5}, + base::Time::FromTimeT(1429997999))); +} + +class AccessRevocationManagerImplIsBlockedTest + : public AccessRevocationManagerImplTest, + public testing::WithParamInterface< + std::tuple<std::vector<uint8_t>, std::vector<uint8_t>>> { + public: + void SetUp() override { + AccessRevocationManagerImplTest::SetUp(); + EXPECT_CALL(config_store_, SaveSettings("black_list", _, _)) + .WillOnce(testing::WithArgs<2>( + testing::Invoke([](const DoneCallback& callback) { + if (!callback.is_null()) + callback.Run(nullptr); + }))); + manager_->Block({std::get<0>(GetParam()), + std::get<1>(GetParam()), + {}, + base::Time::FromTimeT(1419990000)}, + {}); + } +}; + +TEST_P(AccessRevocationManagerImplIsBlockedTest, IsBlocked) { + EXPECT_TRUE(manager_->IsBlocked({7, 7, 7}, {8, 8, 8}, {})); +} + +INSTANTIATE_TEST_CASE_P( + Filters, + AccessRevocationManagerImplIsBlockedTest, + testing::Combine(testing::Values(std::vector<uint8_t>{}, + std::vector<uint8_t>{7, 7, 7}), + testing::Values(std::vector<uint8_t>{}, + std::vector<uint8_t>{8, 8, 8}))); + +} // namespace weave
diff --git a/src/commands/cloud_command_proxy_unittest.cc b/src/commands/cloud_command_proxy_unittest.cc index 0de67fe..e0bd4fc 100644 --- a/src/commands/cloud_command_proxy_unittest.cc +++ b/src/commands/cloud_command_proxy_unittest.cc
@@ -14,7 +14,7 @@ #include <weave/test/unittest_utils.h> #include "src/commands/command_instance.h" -#include "src/mock_component_manager.h" +#include "src/test/mock_component_manager.h" using testing::_; using testing::AnyNumber; @@ -141,7 +141,7 @@ ComponentManager::UpdateID current_state_update_id_{0}; base::CallbackList<void(ComponentManager::UpdateID)> callbacks_; testing::StrictMock<MockCloudCommandUpdateInterface> cloud_updater_; - testing::StrictMock<MockComponentManager> component_manager_; + testing::StrictMock<test::MockComponentManager> component_manager_; testing::StrictMock<provider::test::FakeTaskRunner> task_runner_; std::queue<base::Closure> task_queue_; std::unique_ptr<CommandInstance> command_instance_;
diff --git a/src/commands/schema_constants.cc b/src/commands/schema_constants.cc index 732cf44..37bee4c 100644 --- a/src/commands/schema_constants.cc +++ b/src/commands/schema_constants.cc
@@ -32,12 +32,6 @@ const char kCommand_State[] = "state"; const char kCommand_Error[] = "error"; -const char kCommand_Role[] = "minimalRole"; -const char kCommand_Role_Manager[] = "manager"; -const char kCommand_Role_Owner[] = "owner"; -const char kCommand_Role_User[] = "user"; -const char kCommand_Role_Viewer[] = "viewer"; - } // namespace attributes } // namespace commands
diff --git a/src/commands/schema_constants.h b/src/commands/schema_constants.h index 360079a..623fec3 100644 --- a/src/commands/schema_constants.h +++ b/src/commands/schema_constants.h
@@ -34,12 +34,6 @@ extern const char kCommand_State[]; extern const char kCommand_Error[]; -extern const char kCommand_Role[]; -extern const char kCommand_Role_Manager[]; -extern const char kCommand_Role_Owner[]; -extern const char kCommand_Role_User[]; -extern const char kCommand_Role_Viewer[]; - } // namespace attributes } // namespace commands
diff --git a/src/component_manager.h b/src/component_manager.h index 832b274..cea5569 100644 --- a/src/component_manager.h +++ b/src/component_manager.h
@@ -209,17 +209,6 @@ virtual std::string FindComponentWithTrait( const std::string& trait) const = 0; - // Support for legacy APIs. Setting command and state definitions. - // This translates into modifying a trait definition. - virtual bool AddLegacyCommandDefinitions(const base::DictionaryValue& dict, - ErrorPtr* error) = 0; - virtual bool AddLegacyStateDefinitions(const base::DictionaryValue& dict, - ErrorPtr* error) = 0; - // Returns device state for legacy APIs. - virtual const base::DictionaryValue& GetLegacyState() const = 0; - // Returns command definitions for legacy APIs. - virtual const base::DictionaryValue& GetLegacyCommandDefinitions() const = 0; - DISALLOW_COPY_AND_ASSIGN(ComponentManager); };
diff --git a/src/component_manager_impl.cc b/src/component_manager_impl.cc index dec4a48..3ea1f46 100644 --- a/src/component_manager_impl.cc +++ b/src/component_manager_impl.cc
@@ -19,11 +19,13 @@ // Max of 100 state update events should be enough in the queue. const size_t kMaxStateChangeQueueSize = 100; +const char kMinimalRole[] = "minimalRole"; + const EnumToStringMap<UserRole>::Map kMap[] = { - {UserRole::kViewer, commands::attributes::kCommand_Role_Viewer}, - {UserRole::kUser, commands::attributes::kCommand_Role_User}, - {UserRole::kOwner, commands::attributes::kCommand_Role_Owner}, - {UserRole::kManager, commands::attributes::kCommand_Role_Manager}, + {UserRole::kViewer, "viewer"}, + {UserRole::kUser, "user"}, + {UserRole::kOwner, "owner"}, + {UserRole::kManager, "manager"}, }; } // anonymous namespace @@ -356,7 +358,7 @@ std::string value; // The JSON definition has been pre-validated already in LoadCommands, so // just using CHECKs here. - CHECK(command->GetString(commands::attributes::kCommand_Role, &value)); + CHECK(command->GetString(kMinimalRole, &value)); CHECK(StringToEnum(value, minimal_role)); return true; } @@ -504,140 +506,6 @@ return std::string{}; } -bool ComponentManagerImpl::AddLegacyCommandDefinitions( - const base::DictionaryValue& dict, - ErrorPtr* error) { - bool result = true; - bool modified = false; - for (base::DictionaryValue::Iterator it(dict); !it.IsAtEnd(); it.Advance()) { - const base::DictionaryValue* command_dict = nullptr; - if (!it.value().GetAsDictionary(&command_dict)) { - Error::AddToPrintf(error, FROM_HERE, errors::commands::kTypeMismatch, - "Package '%s' must be an object", it.key().c_str()); - result = false; - continue; - } - AddTraitToLegacyComponent(it.key()); - for (base::DictionaryValue::Iterator it_def(*command_dict); - !it_def.IsAtEnd(); it_def.Advance()) { - std::string key = base::StringPrintf("%s.commands.%s", it.key().c_str(), - it_def.key().c_str()); - if (traits_.GetDictionary(key, nullptr)) { - Error::AddToPrintf(error, FROM_HERE, - errors::commands::kInvalidPropValue, - "Redefining command '%s.%s'", it.key().c_str(), - it_def.key().c_str()); - result = false; - continue; - } - traits_.Set(key, it_def.value().DeepCopy()); - modified = true; - } - } - - if (modified) { - for (const auto& cb : on_trait_changed_) - cb.Run(); - } - return result; -} - -bool ComponentManagerImpl::AddLegacyStateDefinitions( - const base::DictionaryValue& dict, - ErrorPtr* error) { - bool result = true; - bool modified = false; - for (base::DictionaryValue::Iterator it(dict); !it.IsAtEnd(); it.Advance()) { - const base::DictionaryValue* state_dict = nullptr; - if (!it.value().GetAsDictionary(&state_dict)) { - Error::AddToPrintf(error, FROM_HERE, errors::commands::kTypeMismatch, - "Package '%s' must be an object", it.key().c_str()); - result = false; - continue; - } - AddTraitToLegacyComponent(it.key()); - for (base::DictionaryValue::Iterator it_def(*state_dict); !it_def.IsAtEnd(); - it_def.Advance()) { - std::string key = base::StringPrintf("%s.state.%s", it.key().c_str(), - it_def.key().c_str()); - if (traits_.GetDictionary(key, nullptr)) { - Error::AddToPrintf(error, FROM_HERE, - errors::commands::kInvalidPropValue, - "Redefining state property '%s.%s'", - it.key().c_str(), it_def.key().c_str()); - result = false; - continue; - } - traits_.Set(key, it_def.value().DeepCopy()); - modified = true; - } - } - - if (modified) { - for (const auto& cb : on_trait_changed_) - cb.Run(); - } - return result; -} - -const base::DictionaryValue& ComponentManagerImpl::GetLegacyState() const { - legacy_state_.Clear(); - // Build state from components. - for (base::DictionaryValue::Iterator it(components_); !it.IsAtEnd(); - it.Advance()) { - const base::DictionaryValue* component_dict = nullptr; - const base::DictionaryValue* component_state = nullptr; - if (it.value().GetAsDictionary(&component_dict) && - component_dict->GetDictionary("state", &component_state)) { - legacy_state_.MergeDictionary(component_state); - } - } - return legacy_state_; -} - -const base::DictionaryValue& ComponentManagerImpl::GetLegacyCommandDefinitions() - const { - legacy_command_defs_.Clear(); - // Build commandDefs from traits. - for (base::DictionaryValue::Iterator it(traits_); !it.IsAtEnd(); - it.Advance()) { - const base::DictionaryValue* trait_dict = nullptr; - const base::DictionaryValue* trait_commands = nullptr; - if (it.value().GetAsDictionary(&trait_dict) && - trait_dict->GetDictionary("commands", &trait_commands)) { - base::DictionaryValue dict; - dict.Set(it.key(), trait_commands->DeepCopy()); - legacy_command_defs_.MergeDictionary(&dict); - } - } - return legacy_command_defs_; -} - -void ComponentManagerImpl::AddTraitToLegacyComponent(const std::string& trait) { - // First check if we already have a component supporting this trait. - if (!FindComponentWithTrait(trait).empty()) - return; - - // If not, add this trait to the first component available. - base::DictionaryValue* component = nullptr; - base::DictionaryValue::Iterator it(components_); - if (it.IsAtEnd()) { - // No components at all. Create a new one with dummy name. - // This normally wouldn't happen since libweave creates its own component - // at startup. - component = new base::DictionaryValue; - components_.Set("__weave__", component); - } else { - CHECK(components_.GetDictionary(it.key(), &component)); - } - base::ListValue* traits = nullptr; - if (!component->GetList("traits", &traits)) { - traits = new base::ListValue; - component->Set("traits", traits); - } - traits->AppendString(trait); -} - base::DictionaryValue* ComponentManagerImpl::FindComponentGraftNode( const std::string& path, ErrorPtr* error) {
diff --git a/src/component_manager_impl.h b/src/component_manager_impl.h index f3c5451..5b8201a 100644 --- a/src/component_manager_impl.h +++ b/src/component_manager_impl.h
@@ -174,17 +174,6 @@ // tree. No sub-components are searched. std::string FindComponentWithTrait(const std::string& trait) const override; - // Support for legacy APIs. Setting command and state definitions. - // This translates into modifying a trait definition. - bool AddLegacyCommandDefinitions(const base::DictionaryValue& dict, - ErrorPtr* error) override; - bool AddLegacyStateDefinitions(const base::DictionaryValue& dict, - ErrorPtr* error) override; - // Returns device state for legacy APIs. - const base::DictionaryValue& GetLegacyState() const override; - // Returns command definitions for legacy APIs. - const base::DictionaryValue& GetLegacyCommandDefinitions() const override; - private: // A helper method to find a JSON element of component at |path| to add new // sub-components to. @@ -193,12 +182,6 @@ base::DictionaryValue* FindMutableComponent(const std::string& path, ErrorPtr* error); - // Legacy API support: Helper function to support state/command definitions. - // Adds the given trait to at least one component. - // Searches for available components and if none of them already supports this - // trait, it adds it to the first available component. - void AddTraitToLegacyComponent(const std::string& trait); - // Helper method to find a sub-component given a root node and a relative path // from the root to the target component. static const base::DictionaryValue* FindComponentAt( @@ -225,10 +208,6 @@ uint32_t next_command_id_{0}; std::map<std::string, std::unique_ptr<StateChangeQueue>> state_change_queues_; - // Legacy API support. - mutable base::DictionaryValue legacy_state_; // Device state. - mutable base::DictionaryValue legacy_command_defs_; // Command definitions. - DISALLOW_COPY_AND_ASSIGN(ComponentManagerImpl); };
diff --git a/src/component_manager_unittest.cc b/src/component_manager_unittest.cc index 97dc00d..291ace8 100644 --- a/src/component_manager_unittest.cc +++ b/src/component_manager_unittest.cc
@@ -12,7 +12,7 @@ #include "src/bind_lambda.h" #include "src/commands/schema_constants.h" -#include "src/mock_component_manager.h" +#include "src/test/mock_component_manager.h" #include "src/test/mock_clock.h" namespace weave { @@ -1262,226 +1262,9 @@ EXPECT_EQ("", manager_.FindComponentWithTrait("trait4")); } -TEST_F(ComponentManagerTest, AddLegacyCommandAndStateDefinitions) { - const char kCommandDefs1[] = R"({ - "package1": { - "command1": { - "minimalRole": "user", - "parameters": {"height": {"type": "integer"}} - }, - "command2": { - "minimalRole": "owner", - "parameters": {} - } - }, - "package2": { - "command1": { "minimalRole": "user" }, - "command2": { "minimalRole": "owner" } - } - })"; - auto json = CreateDictionaryValue(kCommandDefs1); - EXPECT_TRUE(manager_.AddLegacyCommandDefinitions(*json, nullptr)); - const char kExpected1[] = R"({ - "package1": { - "commands": { - "command1": { - "minimalRole": "user", - "parameters": {"height": {"type": "integer"}} - }, - "command2": { - "minimalRole": "owner", - "parameters": {} - } - } - }, - "package2": { - "commands": { - "command1": { "minimalRole": "user" }, - "command2": { "minimalRole": "owner" } - } - } - })"; - EXPECT_JSON_EQ(kExpected1, manager_.GetTraits()); - const char kExpectedComponents1[] = R"({ - "__weave__": { "traits": ["package1", "package2"] } - })"; - EXPECT_JSON_EQ(kExpectedComponents1, manager_.GetComponents()); - - const char kCommandDefs2[] = R"({ - "package2": { - "command3": { "minimalRole": "user" } - }, - "package3": { - "command1": { "minimalRole": "user" }, - "command2": { "minimalRole": "owner" } - } - })"; - json = CreateDictionaryValue(kCommandDefs2); - EXPECT_TRUE(manager_.AddLegacyCommandDefinitions(*json, nullptr)); - const char kExpected2[] = R"({ - "package1": { - "commands": { - "command1": { - "minimalRole": "user", - "parameters": {"height": {"type": "integer"}} - }, - "command2": { - "minimalRole": "owner", - "parameters": {} - } - } - }, - "package2": { - "commands": { - "command1": { "minimalRole": "user" }, - "command2": { "minimalRole": "owner" }, - "command3": { "minimalRole": "user" } - } - }, - "package3": { - "commands": { - "command1": { "minimalRole": "user" }, - "command2": { "minimalRole": "owner" } - } - } - })"; - EXPECT_JSON_EQ(kExpected2, manager_.GetTraits()); - const char kExpectedComponents2[] = R"({ - "__weave__": { "traits": ["package1", "package2", "package3"] } - })"; - EXPECT_JSON_EQ(kExpectedComponents2, manager_.GetComponents()); - - // Redefining existing commands. - EXPECT_FALSE(manager_.AddLegacyCommandDefinitions(*json, nullptr)); - - const char kStateDefs1[] = R"({ - "package1": { - "prop1": { "type": "string" }, - "prop2": { "type": "string" } - }, - "package4": { - "prop3": { "type": "string" }, - "prop4": { "type": "string" } - } - })"; - json = CreateDictionaryValue(kStateDefs1); - EXPECT_TRUE(manager_.AddLegacyStateDefinitions(*json, nullptr)); - const char kExpectedComponents3[] = R"({ - "__weave__": { "traits": ["package1", "package2", "package3", "package4"] } - })"; - EXPECT_JSON_EQ(kExpectedComponents3, manager_.GetComponents()); - - const char kExpected3[] = R"({ - "package1": { - "commands": { - "command1": { - "minimalRole": "user", - "parameters": {"height": {"type": "integer"}} - }, - "command2": { - "minimalRole": "owner", - "parameters": {} - } - }, - "state": { - "prop1": { "type": "string" }, - "prop2": { "type": "string" } - } - }, - "package2": { - "commands": { - "command1": { "minimalRole": "user" }, - "command2": { "minimalRole": "owner" }, - "command3": { "minimalRole": "user" } - } - }, - "package3": { - "commands": { - "command1": { "minimalRole": "user" }, - "command2": { "minimalRole": "owner" } - } - }, - "package4": { - "state": { - "prop3": { "type": "string" }, - "prop4": { "type": "string" } - } - } - })"; - EXPECT_JSON_EQ(kExpected3, manager_.GetTraits()); - const char kExpectedComponents4[] = R"({ - "__weave__": { "traits": ["package1", "package2", "package3", "package4"] } - })"; - EXPECT_JSON_EQ(kExpectedComponents4, manager_.GetComponents()); - - // Redefining existing commands. - EXPECT_FALSE(manager_.AddLegacyStateDefinitions(*json, nullptr)); - - const char kExpected4[] = R"({ - "package1": { - "command1": { - "minimalRole": "user", - "parameters": {"height": {"type": "integer"}} - }, - "command2": { - "minimalRole": "owner", - "parameters": {} - } - }, - "package2": { - "command1": { "minimalRole": "user" }, - "command2": { "minimalRole": "owner" }, - "command3": { "minimalRole": "user" } - }, - "package3": { - "command1": { "minimalRole": "user" }, - "command2": { "minimalRole": "owner" } - } - })"; - EXPECT_JSON_EQ(kExpected4, manager_.GetLegacyCommandDefinitions()); -} - -TEST_F(ComponentManagerTest, GetLegacyState) { - const char kTraits[] = R"({ - "trait1": { - "state": { - "prop1": { "type": "string" }, - "prop2": { "type": "string" } - } - }, - "trait2": { - "state": { - "prop3": { "type": "string" }, - "prop4": { "type": "string" } - } - } - })"; - auto traits = CreateDictionaryValue(kTraits); - ASSERT_TRUE(manager_.LoadTraits(*traits, nullptr)); - ASSERT_TRUE(manager_.AddComponent("", "comp1", {"trait1"}, nullptr)); - ASSERT_TRUE(manager_.AddComponent("", "comp2", {"trait2"}, nullptr)); - - ASSERT_TRUE(manager_.SetStatePropertiesFromJson( - "comp1", R"({"trait1": {"prop1": "foo", "prop2": "bar"}})", nullptr)); - ASSERT_TRUE(manager_.SetStatePropertiesFromJson( - "comp2", R"({"trait2": {"prop3": "baz", "prop4": "quux"}})", nullptr)); - - const char kExpected[] = R"({ - "trait1": { - "prop1": "foo", - "prop2": "bar" - }, - "trait2": { - "prop3": "baz", - "prop4": "quux" - } - })"; - EXPECT_JSON_EQ(kExpected, manager_.GetLegacyState()); -} - TEST_F(ComponentManagerTest, TestMockComponentManager) { // Check that all the virtual methods are mocked out. - MockComponentManager mock; + test::MockComponentManager mock; } } // namespace weave
diff --git a/src/device_manager.cc b/src/device_manager.cc index 4c0d3ee..b6b91a9 100644 --- a/src/device_manager.cc +++ b/src/device_manager.cc
@@ -9,7 +9,7 @@ #include <base/bind.h> #include "src/access_api_handler.h" -#include "src/access_black_list_manager_impl.h" +#include "src/access_revocation_manager_impl.h" #include "src/base_api_handler.h" #include "src/commands/schema_constants.h" #include "src/component_manager_impl.h" @@ -33,8 +33,13 @@ : config_{new Config{config_store}}, component_manager_{new ComponentManagerImpl{task_runner}} { if (http_server) { - auth_manager_.reset(new privet::AuthManager( - config_.get(), http_server->GetHttpsCertificateFingerprint())); + access_revocation_manager_.reset( + new AccessRevocationManagerImpl{config_store}); + auth_manager_.reset( + new privet::AuthManager(config_.get(), access_revocation_manager_.get(), + http_server->GetHttpsCertificateFingerprint())); + access_api_handler_.reset( + new AccessApiHandler{this, access_revocation_manager_.get()}); } device_info_.reset(new DeviceRegistrationInfo( @@ -42,10 +47,6 @@ network, auth_manager_.get())); base_api_handler_.reset(new BaseApiHandler{device_info_.get(), this}); - black_list_manager_.reset(new AccessBlackListManagerImpl{config_store}); - access_api_handler_.reset( - new AccessApiHandler{this, black_list_manager_.get()}); - device_info_->Start(); if (http_server) { @@ -156,16 +157,6 @@ component_manager_->AddCommandHandler(component, command_name, callback); } -void DeviceManager::AddCommandDefinitionsFromJson(const std::string& json) { - auto dict = LoadJsonDict(json, nullptr); - CHECK(dict); - AddCommandDefinitions(*dict); -} - -void DeviceManager::AddCommandDefinitions(const base::DictionaryValue& dict) { - CHECK(component_manager_->AddLegacyCommandDefinitions(dict, nullptr)); -} - bool DeviceManager::AddCommand(const base::DictionaryValue& command, std::string* id, ErrorPtr* error) { @@ -181,87 +172,10 @@ return component_manager_->FindCommand(id); } -void DeviceManager::AddCommandHandler(const std::string& command_name, - const CommandHandlerCallback& callback) { - if (command_name.empty()) - return component_manager_->AddCommandHandler("", "", callback); - - auto trait = SplitAtFirst(command_name, ".", true).first; - std::string component = component_manager_->FindComponentWithTrait(trait); - CHECK(!component.empty()); - component_manager_->AddCommandHandler(component, command_name, callback); -} - void DeviceManager::AddStateChangedCallback(const base::Closure& callback) { component_manager_->AddStateChangedCallback(callback); } -void DeviceManager::AddStateDefinitionsFromJson(const std::string& json) { - auto dict = LoadJsonDict(json, nullptr); - CHECK(dict); - AddStateDefinitions(*dict); -} - -void DeviceManager::AddStateDefinitions(const base::DictionaryValue& dict) { - CHECK(component_manager_->AddLegacyStateDefinitions(dict, nullptr)); -} - -bool DeviceManager::SetStatePropertiesFromJson(const std::string& json, - ErrorPtr* error) { - auto dict = LoadJsonDict(json, error); - return dict && SetStateProperties(*dict, error); -} - -bool DeviceManager::SetStateProperties(const base::DictionaryValue& dict, - ErrorPtr* error) { - for (base::DictionaryValue::Iterator it(dict); !it.IsAtEnd(); it.Advance()) { - std::string component = - component_manager_->FindComponentWithTrait(it.key()); - if (component.empty()) { - Error::AddToPrintf(error, FROM_HERE, "unrouted_state", - "Unable to set property value because there is no " - "component supporting " - "trait '%s'", - it.key().c_str()); - return false; - } - base::DictionaryValue trait_state; - trait_state.Set(it.key(), it.value().DeepCopy()); - if (!component_manager_->SetStateProperties(component, trait_state, error)) - return false; - } - return true; -} - -const base::Value* DeviceManager::GetStateProperty( - const std::string& name) const { - auto trait = SplitAtFirst(name, ".", true).first; - std::string component = component_manager_->FindComponentWithTrait(trait); - if (component.empty()) - return nullptr; - return component_manager_->GetStateProperty(component, name, nullptr); -} - -bool DeviceManager::SetStateProperty(const std::string& name, - const base::Value& value, - ErrorPtr* error) { - auto trait = SplitAtFirst(name, ".", true).first; - std::string component = component_manager_->FindComponentWithTrait(trait); - if (component.empty()) { - Error::AddToPrintf( - error, FROM_HERE, "unrouted_state", - "Unable set value of state property '%s' because there is no component " - "supporting trait '%s'", - name.c_str(), trait.c_str()); - return false; - } - return component_manager_->SetStateProperty(component, name, value, error); -} - -const base::DictionaryValue& DeviceManager::GetState() const { - return component_manager_->GetLegacyState(); -} - void DeviceManager::Register(const RegistrationData& registration_data, const DoneCallback& callback) { device_info_->RegisterDevice(registration_data, callback);
diff --git a/src/device_manager.h b/src/device_manager.h index f0ad464..545f293 100644 --- a/src/device_manager.h +++ b/src/device_manager.h
@@ -11,7 +11,7 @@ namespace weave { class AccessApiHandler; -class AccessBlackListManager; +class AccessRevocationManager; class BaseApiHandler; class Config; class ComponentManager; @@ -78,22 +78,6 @@ const PairingBeginCallback& begin_callback, const PairingEndCallback& end_callback) override; - void AddCommandDefinitionsFromJson(const std::string& json) override; - void AddCommandDefinitions(const base::DictionaryValue& dict) override; - void AddCommandHandler(const std::string& command_name, - const CommandHandlerCallback& callback) override; - void AddStateDefinitionsFromJson(const std::string& json) override; - void AddStateDefinitions(const base::DictionaryValue& dict) override; - bool SetStatePropertiesFromJson(const std::string& json, - ErrorPtr* error) override; - bool SetStateProperties(const base::DictionaryValue& dict, - ErrorPtr* error) override; - const base::Value* GetStateProperty(const std::string& name) const override; - bool SetStateProperty(const std::string& name, - const base::Value& value, - ErrorPtr* error) override; - const base::DictionaryValue& GetState() const override; - Config* GetConfig(); private: @@ -109,7 +93,7 @@ std::unique_ptr<ComponentManager> component_manager_; std::unique_ptr<DeviceRegistrationInfo> device_info_; std::unique_ptr<BaseApiHandler> base_api_handler_; - std::unique_ptr<AccessBlackListManager> black_list_manager_; + std::unique_ptr<AccessRevocationManager> access_revocation_manager_; std::unique_ptr<AccessApiHandler> access_api_handler_; std::unique_ptr<privet::Manager> privet_;
diff --git a/src/privet/auth_manager.cc b/src/privet/auth_manager.cc index 027ad5a..d905a45 100644 --- a/src/privet/auth_manager.cc +++ b/src/privet/auth_manager.cc
@@ -6,15 +6,18 @@ #include <algorithm> +#include <base/bind.h> #include <base/guid.h> #include <base/rand_util.h> #include <base/strings/string_number_conversions.h> +#include "src/access_revocation_manager.h" #include "src/config.h" #include "src/data_encoding.h" #include "src/privet/constants.h" #include "src/privet/openssl_utils.h" #include "src/string_utils.h" +#include "src/utils.h" extern "C" { #include "third_party/libuweave/src/macaroon.h" @@ -26,20 +29,11 @@ namespace { -const time_t kJ2000ToTimeT = 946684800; const size_t kMaxMacaroonSize = 1024; const size_t kMaxPendingClaims = 10; const char kInvalidTokenError[] = "invalid_token"; const int kSessionIdTtlMinutes = 1; -uint32_t ToJ2000Time(const base::Time& time) { - return std::max(time.ToTimeT(), kJ2000ToTimeT) - kJ2000ToTimeT; -} - -base::Time FromJ2000Time(uint32_t time) { - return base::Time::FromTimeT(time + kJ2000ToTimeT); -} - template <class T> void AppendToArray(T value, std::vector<uint8_t>* array) { auto begin = reinterpret_cast<const uint8_t*>(&value); @@ -275,10 +269,16 @@ } // namespace AuthManager::AuthManager(Config* config, + AccessRevocationManager* black_list, const std::vector<uint8_t>& certificate_fingerprint) : config_{config}, + black_list_{black_list}, certificate_fingerprint_{certificate_fingerprint}, access_secret_{CreateSecret()} { + if (black_list_) { + black_list_->AddEntryAddedCallback(base::Bind( + &AuthManager::ResetAccessSecret, weak_ptr_factory_.GetWeakPtr())); + } if (config_) { SetAuthSecret(config_->GetSettings().secret, config_->GetSettings().root_client_token_owner); @@ -290,8 +290,9 @@ AuthManager::AuthManager(const std::vector<uint8_t>& auth_secret, const std::vector<uint8_t>& certificate_fingerprint, const std::vector<uint8_t>& access_secret, - base::Clock* clock) - : AuthManager(nullptr, certificate_fingerprint) { + base::Clock* clock, + AccessRevocationManager* black_list) + : AuthManager(nullptr, black_list, certificate_fingerprint) { access_secret_ = access_secret.size() == kSha256OutputSize ? access_secret : CreateSecret(); SetAuthSecret(auth_secret, RootClientTokenOwner::kNone); @@ -401,7 +402,8 @@ }; pending_claims_.push_back(std::make_pair( - std::unique_ptr<AuthManager>{new AuthManager{nullptr, {}}}, owner)); + std::unique_ptr<AuthManager>{new AuthManager{nullptr, nullptr, {}}}, + owner)); if (pending_claims_.size() > kMaxPendingClaims) pending_claims_.pop_front(); return pending_claims_.back().first->GetRootClientAuthToken(owner); @@ -511,6 +513,28 @@ "Invalid session id"); } + if (black_list_) { + std::vector<uint8_t> user_id; + std::vector<uint8_t> app_id; + for (size_t i = 0; i < result.num_delegatees; ++i) { + if (result.delegatees[i].type == kUwMacaroonDelegateeTypeUser) { + user_id.assign(result.delegatees[i].id, + result.delegatees[i].id + result.delegatees[i].id_len); + } else if (result.delegatees[i].type == kUwMacaroonDelegateeTypeApp) { + app_id.assign(result.delegatees[i].id, + result.delegatees[i].id + result.delegatees[i].id_len); + } else { + // Do not block by other types of delegatees. + continue; + } + if (black_list_->IsBlocked( + user_id, app_id, FromJ2000Time(result.delegatees[i].timestamp))) { + return Error::AddTo(error, FROM_HERE, errors::kInvalidAuthCode, + "Auth token is revoked"); + } + } + } + CHECK_GE(FromJ2000Time(result.expiration_time), now); if (!access_token) @@ -547,6 +571,12 @@ ssid_time <= Now(); } +void AuthManager::ResetAccessSecret() { + auto new_secret = CreateSecret(); + CHECK(new_secret != access_secret_); + access_secret_.swap(new_secret); +} + std::vector<uint8_t> AuthManager::DelegateToUser( const std::vector<uint8_t>& token, base::TimeDelta ttl,
diff --git a/src/privet/auth_manager.h b/src/privet/auth_manager.h index f0a5761..d8174f6 100644 --- a/src/privet/auth_manager.h +++ b/src/privet/auth_manager.h
@@ -10,6 +10,7 @@ #include <vector> #include <base/gtest_prod_util.h> +#include <base/memory/weak_ptr.h> #include <base/time/default_clock.h> #include <base/time/time.h> #include <weave/error.h> @@ -18,6 +19,7 @@ namespace weave { +class AccessRevocationManager; class Config; enum class RootClientTokenOwner; @@ -26,13 +28,15 @@ class AuthManager { public: AuthManager(Config* config, + AccessRevocationManager* black_list, const std::vector<uint8_t>& certificate_fingerprint); // Constructor for tests. AuthManager(const std::vector<uint8_t>& auth_secret, const std::vector<uint8_t>& certificate_fingerprint, const std::vector<uint8_t>& access_secret, - base::Clock* clock = nullptr); + base::Clock* clock = nullptr, + AccessRevocationManager* black_list = nullptr); ~AuthManager(); std::vector<uint8_t> CreateAccessToken(const UserInfo& user_info, @@ -74,12 +78,15 @@ private: friend class AuthManagerTest; + void ResetAccessSecret(); + // Test helpers. Device does not need to implement delegation. std::vector<uint8_t> DelegateToUser(const std::vector<uint8_t>& token, base::TimeDelta ttl, const UserInfo& user_info) const; Config* config_{nullptr}; // Can be nullptr for tests. + AccessRevocationManager* black_list_{nullptr}; base::DefaultClock default_clock_; base::Clock* clock_{&default_clock_}; mutable uint32_t session_counter_{0}; @@ -91,6 +98,7 @@ std::deque<std::pair<std::unique_ptr<AuthManager>, RootClientTokenOwner>> pending_claims_; + base::WeakPtrFactory<AuthManager> weak_ptr_factory_{this}; DISALLOW_COPY_AND_ASSIGN(AuthManager); };
diff --git a/src/privet/auth_manager_unittest.cc b/src/privet/auth_manager_unittest.cc index 3e5aeab..648027d 100644 --- a/src/privet/auth_manager_unittest.cc +++ b/src/privet/auth_manager_unittest.cc
@@ -11,13 +11,28 @@ #include "src/config.h" #include "src/data_encoding.h" #include "src/privet/mock_delegates.h" +#include "src/test/mock_access_revocation_manager.h" #include "src/test/mock_clock.h" +using testing::_; using testing::Return; +using testing::SaveArg; +using testing::StrictMock; namespace weave { namespace privet { +class MockAccessRevocationManager : public test::MockAccessRevocationManager { + public: + MockAccessRevocationManager() { + EXPECT_CALL(*this, AddEntryAddedCallback(_)) + .WillOnce(SaveArg<0>(&changed_callback_)); + EXPECT_CALL(*this, IsBlocked(_, _, _)).WillRepeatedly(Return(false)); + } + + base::Closure changed_callback_; +}; + class AuthManagerTest : public testing::Test { public: void SetUp() override { @@ -46,7 +61,8 @@ 60, 62, 10, 18, 82, 35, 88, 100, 30, 45, 7, 46, 67, 84, 58, 85}; test::MockClock clock_; - AuthManager auth_{kSecret1, kFingerprint, kSecret2, &clock_}; + StrictMock<MockAccessRevocationManager> black_list_; + AuthManager auth_{kSecret1, kFingerprint, kSecret2, &clock_, &black_list_}; }; TEST_F(AuthManagerTest, RandomSecret) { @@ -152,8 +168,9 @@ TEST_F(AuthManagerTest, CreateTokenDifferentInstance) { EXPECT_NE(auth_.CreateAccessToken( UserInfo{AuthScope::kUser, TestUserId{"123"}}, {}), - AuthManager({}, {}).CreateAccessToken( - UserInfo{AuthScope::kUser, TestUserId{"123"}}, {})); + AuthManager({}, nullptr, {}) + .CreateAccessToken( + UserInfo{AuthScope::kUser, TestUserId{"123"}}, {})); } TEST_F(AuthManagerTest, ParseAccessToken) { @@ -189,6 +206,22 @@ } } +TEST_F(AuthManagerTest, AccessTokenAfterReset) { + UserInfo user_info; + auto token1 = auth_.CreateAccessToken( + UserInfo{AuthScope::kViewer, TestUserId{"555"}}, {}); + EXPECT_TRUE(auth_.ParseAccessToken(token1, &user_info, nullptr)); + + black_list_.changed_callback_.Run(); + + auto token2 = auth_.CreateAccessToken( + UserInfo{AuthScope::kViewer, TestUserId{"555"}}, {}); + + EXPECT_NE(token1, token2); + EXPECT_FALSE(auth_.ParseAccessToken(token1, &user_info, nullptr)); + EXPECT_TRUE(auth_.ParseAccessToken(token2, &user_info, nullptr)); +} + TEST_F(AuthManagerTest, GetRootClientAuthToken) { EXPECT_EQ("WCCDQxkgAUYIGhudoQBCDABQX3fPR5zsPnrs9aOSvS7/eQ==", Base64Encode( @@ -319,6 +352,21 @@ EXPECT_TRUE(error->HasError("invalidAuthCode")); } +TEST_F(AuthManagerTest, CreateAccessTokenFromAuthRevoked) { + TestUserId user{"234"}; + EXPECT_CALL(black_list_, IsBlocked(user.user, _, clock_.Now())) + .WillOnce(Return(true)); + std::vector<uint8_t> access_token; + auto root = auth_.GetRootClientAuthToken(RootClientTokenOwner::kCloud); + auto extended = DelegateToUser(root, base::TimeDelta::FromSeconds(1000), + UserInfo{AuthScope::kUser, user}); + ErrorPtr error; + EXPECT_FALSE( + auth_.CreateAccessTokenFromAuth(extended, base::TimeDelta::FromDays(1), + nullptr, nullptr, nullptr, &error)); + EXPECT_TRUE(error->HasError("invalidAuthCode")); +} + class AuthManagerClaimTest : public testing::Test { public: void SetUp() override { EXPECT_EQ(auth_.GetAuthSecret().size(), 32u); } @@ -332,7 +380,7 @@ protected: Config config_{nullptr}; - AuthManager auth_{&config_, {}}; + AuthManager auth_{&config_, nullptr, {}}; }; TEST_F(AuthManagerClaimTest, WithPreviosOwner) {
diff --git a/src/privet/cloud_delegate.cc b/src/privet/cloud_delegate.cc index 0b4400f..f565687 100644 --- a/src/privet/cloud_delegate.cc +++ b/src/privet/cloud_delegate.cc
@@ -151,14 +151,6 @@ return device_->GetSettings().xmpp_endpoint; } - const base::DictionaryValue& GetLegacyCommandDef() const override { - return component_manager_->GetLegacyCommandDefinitions(); - } - - const base::DictionaryValue& GetLegacyState() const override { - return component_manager_->GetLegacyState(); - } - const base::DictionaryValue& GetComponents() const override { return component_manager_->GetComponents(); }
diff --git a/src/privet/cloud_delegate.h b/src/privet/cloud_delegate.h index 37ed723..43b8904 100644 --- a/src/privet/cloud_delegate.h +++ b/src/privet/cloud_delegate.h
@@ -100,12 +100,6 @@ virtual std::string GetServiceUrl() const = 0; virtual std::string GetXmppEndpoint() const = 0; - // Returns dictionary with device state (for legacy APIs). - virtual const base::DictionaryValue& GetLegacyState() const = 0; - - // Returns dictionary with commands definitions (for legacy APIs). - virtual const base::DictionaryValue& GetLegacyCommandDef() const = 0; - // Returns dictionary with component tree. virtual const base::DictionaryValue& GetComponents() const = 0;
diff --git a/src/privet/mock_delegates.h b/src/privet/mock_delegates.h index 108e450..f04fb37 100644 --- a/src/privet/mock_delegates.h +++ b/src/privet/mock_delegates.h
@@ -188,8 +188,6 @@ MOCK_CONST_METHOD0(GetOAuthUrl, std::string()); MOCK_CONST_METHOD0(GetServiceUrl, std::string()); MOCK_CONST_METHOD0(GetXmppEndpoint, std::string()); - MOCK_CONST_METHOD0(GetLegacyState, const base::DictionaryValue&()); - MOCK_CONST_METHOD0(GetLegacyCommandDef, const base::DictionaryValue&()); MOCK_CONST_METHOD0(GetComponents, const base::DictionaryValue&()); MOCK_CONST_METHOD2(FindComponent, const base::DictionaryValue*(const std::string& path, @@ -229,9 +227,6 @@ EXPECT_CALL(*this, GetSetupState()).WillRepeatedly(ReturnRef(setup_state_)); EXPECT_CALL(*this, GetCloudId()).WillRepeatedly(Return("TestCloudId")); test_dict_.Set("test", new base::DictionaryValue); - EXPECT_CALL(*this, GetLegacyState()).WillRepeatedly(ReturnRef(test_dict_)); - EXPECT_CALL(*this, GetLegacyCommandDef()) - .WillRepeatedly(ReturnRef(test_dict_)); EXPECT_CALL(*this, GetTraits()).WillRepeatedly(ReturnRef(test_dict_)); EXPECT_CALL(*this, GetComponents()).WillRepeatedly(ReturnRef(test_dict_)); EXPECT_CALL(*this, FindComponent(_, _)).Times(0);
diff --git a/src/privet/privet_handler.cc b/src/privet/privet_handler.cc index 05b6e0a..83d5ef3 100644 --- a/src/privet/privet_handler.cc +++ b/src/privet/privet_handler.cc
@@ -114,8 +114,6 @@ std::string xmpp_endpoint; const char kFingerprintKey[] = "fingerprint"; -const char kStateKey[] = "state"; -const char kCommandsKey[] = "commands"; const char kTraitsKey[] = "traits"; const char kComponentsKey[] = "components"; const char kCommandsIdKey[] = "id"; @@ -421,10 +419,6 @@ AuthScope::kManager); AddSecureHandler("/privet/v3/setup/status", &PrivetHandler::HandleSetupStatus, AuthScope::kManager); - AddSecureHandler("/privet/v3/state", &PrivetHandler::HandleState, - AuthScope::kViewer); - AddSecureHandler("/privet/v3/commandDefs", &PrivetHandler::HandleCommandDefs, - AuthScope::kViewer); AddSecureHandler("/privet/v3/commands/execute", &PrivetHandler::HandleCommandsExecute, AuthScope::kViewer); AddSecureHandler("/privet/v3/commands/status", @@ -875,16 +869,6 @@ callback.Run(http::kOk, output); } -void PrivetHandler::HandleState(const base::DictionaryValue& input, - const UserInfo& user_info, - const RequestCallback& callback) { - base::DictionaryValue output; - output.Set(kStateKey, cloud_->GetLegacyState().DeepCopy()); - output.SetString(kFingerprintKey, std::to_string(state_fingerprint_)); - - callback.Run(http::kOk, output); -} - void PrivetHandler::HandleTraits(const base::DictionaryValue& input, const UserInfo& user_info, const RequestCallback& callback) { @@ -931,18 +915,6 @@ callback.Run(http::kOk, output); } -void PrivetHandler::HandleCommandDefs(const base::DictionaryValue& input, - const UserInfo& user_info, - const RequestCallback& callback) { - base::DictionaryValue output; - output.Set(kCommandsKey, cloud_->GetLegacyCommandDef().DeepCopy()); - // Use traits fingerprint since right now we treat traits and command defs - // as being equivalent. - output.SetString(kFingerprintKey, std::to_string(traits_fingerprint_)); - - callback.Run(http::kOk, output); -} - void PrivetHandler::HandleCommandsExecute(const base::DictionaryValue& input, const UserInfo& user_info, const RequestCallback& callback) {
diff --git a/src/privet/privet_handler_unittest.cc b/src/privet/privet_handler_unittest.cc index 3c72242..ecf4797 100644 --- a/src/privet/privet_handler_unittest.cc +++ b/src/privet/privet_handler_unittest.cc
@@ -674,7 +674,6 @@ "client_secret": "test_client_secret", "oauth_url": "https://oauths/", "service_url": "https://service/", - "status": "success", "xmpp_endpoint": "xmpp:678", "ticketId": "testTicket", "user": "testUser" @@ -728,26 +727,6 @@ R"({"clientToken": "DerivedClientAuthToken"})")); } -TEST_F(PrivetHandlerTestWithAuth, State) { - EXPECT_JSON_EQ(R"({"state": {"test": {}}, "fingerprint": "1"})", - HandleRequest("/privet/v3/state", "{}")); - - cloud_.NotifyOnStateChanged(); - - EXPECT_JSON_EQ(R"({"state": {"test": {}}, "fingerprint": "2"})", - HandleRequest("/privet/v3/state", "{}")); -} - -TEST_F(PrivetHandlerTestWithAuth, CommandsDefs) { - EXPECT_JSON_EQ(R"({"commands": {"test":{}}, "fingerprint": "1"})", - HandleRequest("/privet/v3/commandDefs", "{}")); - - cloud_.NotifyOnTraitDefsChanged(); - - EXPECT_JSON_EQ(R"({"commands": {"test":{}}, "fingerprint": "2"})", - HandleRequest("/privet/v3/commandDefs", "{}")); -} - TEST_F(PrivetHandlerTestWithAuth, Traits) { EXPECT_JSON_EQ(R"({"traits": {"test": {}}, "fingerprint": "1"})", HandleRequest("/privet/v3/traits", "{}"));
diff --git a/src/test/mock_access_revocation_manager.h b/src/test/mock_access_revocation_manager.h new file mode 100644 index 0000000..29e3721 --- /dev/null +++ b/src/test/mock_access_revocation_manager.h
@@ -0,0 +1,33 @@ +// 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. + +#ifndef LIBWEAVE_SRC_MOCK_ACCESS_REVOCATION_MANAGER_H_ +#define LIBWEAVE_SRC_MOCK_ACCESS_REVOCATION_MANAGER_H_ + +#include <gmock/gmock.h> + +#include "src/access_revocation_manager.h" + +namespace weave { + +namespace test { + +class MockAccessRevocationManager : public AccessRevocationManager { + public: + MOCK_METHOD1(AddEntryAddedCallback, void(const base::Closure&)); + MOCK_METHOD2(Block, void(const Entry&, const DoneCallback&)); + MOCK_CONST_METHOD3(IsBlocked, + bool(const std::vector<uint8_t>&, + const std::vector<uint8_t>&, + base::Time)); + MOCK_CONST_METHOD0(GetEntries, std::vector<Entry>()); + MOCK_CONST_METHOD0(GetSize, size_t()); + MOCK_CONST_METHOD0(GetCapacity, size_t()); +}; + +} // namespace test + +} // namespace weave + +#endif // LIBWEAVE_SRC_MOCK_ACCESS_REVOCATION_MANAGER_H_
diff --git a/src/mock_component_manager.h b/src/test/mock_component_manager.h similarity index 92% rename from src/mock_component_manager.h rename to src/test/mock_component_manager.h index addd6f0..2c1d695 100644 --- a/src/mock_component_manager.h +++ b/src/test/mock_component_manager.h
@@ -11,6 +11,8 @@ namespace weave { +namespace test { + class MockComponentManager : public ComponentManager { public: ~MockComponentManager() override {} @@ -95,13 +97,6 @@ const base::Callback<void(UpdateID)>& callback)); MOCK_CONST_METHOD1(FindComponentWithTrait, std::string(const std::string& trait)); - MOCK_METHOD2(AddLegacyCommandDefinitions, - bool(const base::DictionaryValue& dict, ErrorPtr* error)); - MOCK_METHOD2(AddLegacyStateDefinitions, - bool(const base::DictionaryValue& dict, ErrorPtr* error)); - MOCK_CONST_METHOD0(GetLegacyState, const base::DictionaryValue&()); - MOCK_CONST_METHOD0(GetLegacyCommandDefinitions, - const base::DictionaryValue&()); private: void AddCommand(std::unique_ptr<CommandInstance> command_instance) override { @@ -125,6 +120,8 @@ } }; +} // namespace test + } // namespace weave #endif // LIBWEAVE_SRC_COMPONENT_MANAGER_H_
diff --git a/src/utils.cc b/src/utils.cc index 28828d7..5d1c3e3 100644 --- a/src/utils.cc +++ b/src/utils.cc
@@ -26,6 +26,8 @@ const char kErrorCodeKey[] = "code"; const char kErrorMessageKey[] = "message"; +const time_t kJ2000ToTimeT = 946684800; + } // anonymous namespace namespace errors { @@ -69,4 +71,12 @@ return output; } +uint32_t ToJ2000Time(const base::Time& time) { + return std::max(time.ToTimeT(), kJ2000ToTimeT) - kJ2000ToTimeT; +} + +base::Time FromJ2000Time(uint32_t time) { + return base::Time::FromTimeT(time + kJ2000ToTimeT); +} + } // namespace weave
diff --git a/src/utils.h b/src/utils.h index 99d7bda..40c76b4 100644 --- a/src/utils.h +++ b/src/utils.h
@@ -8,6 +8,7 @@ #include <memory> #include <string> +#include <base/time/time.h> #include <base/values.h> #include <weave/error.h> @@ -31,6 +32,9 @@ std::unique_ptr<base::DictionaryValue> ErrorInfoToJson(const Error& error); +uint32_t ToJ2000Time(const base::Time& time); +base::Time FromJ2000Time(uint32_t time); + } // namespace weave #endif // LIBWEAVE_SRC_UTILS_H_
diff --git a/src/weave_unittest.cc b/src/weave_unittest.cc index 452ac78..3b28001 100644 --- a/src/weave_unittest.cc +++ b/src/weave_unittest.cc
@@ -294,7 +294,6 @@ "/privet/v3/accessControl/confirm", "/privet/v3/auth", "/privet/v3/checkForUpdates", - "/privet/v3/commandDefs", "/privet/v3/commands/cancel", "/privet/v3/commands/execute", "/privet/v3/commands/list", @@ -305,7 +304,6 @@ "/privet/v3/pairing/start", "/privet/v3/setup/start", "/privet/v3/setup/status", - "/privet/v3/state", "/privet/v3/traits", // clang-format on }),
diff --git a/third_party/chromium/base/third_party/dmg_fp/dtoa.cc b/third_party/chromium/base/third_party/dmg_fp/dtoa.cc index 502c16c..c06219c 100644 --- a/third_party/chromium/base/third_party/dmg_fp/dtoa.cc +++ b/third_party/chromium/base/third_party/dmg_fp/dtoa.cc
@@ -59,6 +59,7 @@ * 4. Because of 3., we don't need a large table of powers of 10 * for ten-to-e (just some small tables, e.g. of 10^k * for 0 <= k <= 22). + * 5. Fixed -Wchar-subscripts warning in "if (!hexdig['0'])" */ /* @@ -1572,7 +1573,7 @@ CONST char *s; int c1, havedig, udx0, xshift; - if (!hexdig['0']) + if (!hexdig[0 + '0']) hexdig_init(); x[0] = x[1] = 0; havedig = xshift = 0;
diff --git a/third_party/chromium/base/third_party/dmg_fp/g_fmt.cc b/third_party/chromium/base/third_party/dmg_fp/g_fmt.cc index bfa358d..67c9f57 100644 --- a/third_party/chromium/base/third_party/dmg_fp/g_fmt.cc +++ b/third_party/chromium/base/third_party/dmg_fp/g_fmt.cc
@@ -27,10 +27,10 @@ namespace dmg_fp { char * -g_fmt(register char *b, double x) +g_fmt(char *b, double x) { - register int i, k; - register char *s; + int i, k; + char *s; int decpt, j, sign; char *b0, *s0, *se;