~aleteoryx/muditaos

c2f38ad4f9d67a16484085bdfa758f01b418044c — Bartosz Cichocki 3 years ago 155edc3
[MOS-452] Fix BT keys duplicates

Due to possibility to have duplicated entries per BT address
BT stack was requesting pairing when wrong key has been provided.
Now, all previous key entries are deleted prior adding.
M module-bluetooth/Bluetooth/BtKeysStorage.cpp => module-bluetooth/Bluetooth/BtKeysStorage.cpp +39 -15
@@ 1,4 1,4 @@
// Copyright (c) 2017-2021, Mudita Sp. z.o.o. All rights reserved.
// Copyright (c) 2017-2022, Mudita Sp. z.o.o. All rights reserved.
// For licensing, see https://github.com/mudita/MuditaOS/LICENSE.md

#include <algorithm>


@@ 8,7 8,6 @@
json11::Json bluetooth::KeyStorage::keysJson = json11::Json();
btstack_link_key_db_t bluetooth::KeyStorage::keyStorage;
json11::Json::array bluetooth::KeyStorage::keys;
std::string bluetooth::KeyStorage::keysEntry;
std::shared_ptr<bluetooth::SettingsHolder> bluetooth::KeyStorage::settings = nullptr;

namespace bluetooth


@@ 39,6 38,7 @@ namespace bluetooth
    void KeyStorage::openStorage()
    {
        LOG_INFO("opening storage from API");
        std::string keysEntry;
        if (settings) {
            keysEntry = std::visit(bluetooth::StringVisitor(), settings->getValue(bluetooth::Settings::BtKeys));
        }


@@ 71,33 71,45 @@ namespace bluetooth
    {
        if (type != nullptr && bd_addr != nullptr) {
            LOG_INFO("getting key from API");

            json11::Json finalJson = json11::Json::object{{strings::keys, keys}};
            auto keysEntryDump     = finalJson.dump();
            LOG_INFO("Current keys state: %s", keysEntryDump.c_str());

            if (keys.empty()) {
                LOG_ERROR("Keys empty!");
                return 0;
            }
            for (auto key : keys) {
                bd_addr_t addr;
                sscanf_bd_addr(key[strings::bd_addr].string_value().c_str(), addr);

                if (bd_addr_cmp(addr, bd_addr) == 0) {
                    auto foundLinkKey = key[strings::link_key].string_value().c_str();
                    memcpy(link_key, reinterpret_cast<const uint8_t *>(foundLinkKey), sizeof(link_key_t));
                    LOG_INFO("Getting key: %s", foundLinkKey);
                    *type = static_cast<link_key_type_t>(key[strings::type].int_value());

                    return 1;
                }

            auto ret = processOnFoundKey(bd_addr, [&type, &link_key](const json11::Json &key, bd_addr_t) {
                auto foundLinkKey = key[strings::link_key].string_value().c_str();
                memcpy(link_key, reinterpret_cast<const uint8_t *>(foundLinkKey), sizeof(link_key_t));
                LOG_INFO("Getting key: %s", foundLinkKey);
                *type = static_cast<link_key_type_t>(key[strings::type].int_value());

                return 1;
            });
            if (ret == 0) {
                LOG_ERROR("Can't find key for this address!");
            }
            return ret;
        }
        return 0;
    }
    void KeyStorage::putLinkKey(uint8_t *bd_addr, uint8_t *link_key, link_key_type_t type)
    {

        processOnFoundKey(bd_addr, [](const json11::Json &, bd_addr_t bd_addr) {
            LOG_ERROR("Key already found in the key storage - deleting!");
            deleteLinkKey(bd_addr);
            return 1;
        });

        auto keyEntry = json11::Json::object{{strings::bd_addr, bd_addr_to_str(bd_addr)},
                                             {strings::link_key, std::string(reinterpret_cast<char *>(link_key))},
                                             {strings::type, type}};
        keys.emplace_back(keyEntry);

        if (settings->onLinkKeyAdded) {
            settings->onLinkKeyAdded(bd_addr_to_str(bd_addr));
        }


@@ 140,7 152,7 @@ namespace bluetooth
    void KeyStorage::writeSettings()
    {
        json11::Json finalJson = json11::Json::object{{strings::keys, keys}};
        keysEntry              = finalJson.dump();
        auto keysEntry         = finalJson.dump();
        if (settings) {
            settings->setValue(bluetooth::Settings::BtKeys, keysEntry);
        }


@@ 149,5 161,17 @@ namespace bluetooth
            return;
        }
    }
    auto KeyStorage::processOnFoundKey(bd_addr_t bd_addr, const std::function<int(json11::Json, bd_addr_t)> &fun) -> int
    {
        for (const auto &key : keys) {
            bd_addr_t addr;
            sscanf_bd_addr(key[strings::bd_addr].string_value().c_str(), addr);

            if (bd_addr_cmp(addr, bd_addr) == 0 && fun) {
                return fun(key, bd_addr);
            }
        }
        return 0;
    }

} // namespace bluetooth

M module-bluetooth/Bluetooth/BtKeysStorage.hpp => module-bluetooth/Bluetooth/BtKeysStorage.hpp +2 -3
@@ 1,4 1,4 @@
// Copyright (c) 2017-2021, Mudita Sp. z.o.o. All rights reserved.
// Copyright (c) 2017-2022, Mudita Sp. z.o.o. All rights reserved.
// For licensing, see https://github.com/mudita/MuditaOS/LICENSE.md

#pragma once


@@ 17,7 17,6 @@ namespace bluetooth
      public:
        static auto getKeyStorage() -> btstack_link_key_db_t *;
        static std::shared_ptr<bluetooth::SettingsHolder> settings;

      private:
        static void openStorage();
        static void closeStorage();


@@ 31,11 30,11 @@ namespace bluetooth
                                      link_key_type_t *type) -> int;
        static void iterator_done(btstack_link_key_iterator_t *it);
        static void set_local_bd_addr(bd_addr_t bd_addr);
        static auto processOnFoundKey(bd_addr_t bd_addr, const std::function<int(json11::Json, bd_addr_t)> &fun) -> int;
        static void writeSettings();
        static json11::Json keysJson;
        static btstack_link_key_db_t keyStorage;
        static json11::Json::array keys;
        static std::string keysEntry;
    };

} // namespace Bt

M module-bluetooth/tests/CMakeLists.txt => module-bluetooth/tests/CMakeLists.txt +4 -0
@@ 6,7 6,11 @@ add_catch2_executable(
        tests-BluetoothDevicesModel.cpp
        tests-Devicei.cpp
        tests-command.cpp
        tests-BTKeysStorage.cpp
    LIBS
        module-sys
        module-bluetooth
        service-bluetooth
)



A module-bluetooth/tests/tests-BTKeysStorage.cpp => module-bluetooth/tests/tests-BTKeysStorage.cpp +127 -0
@@ 0,0 1,127 @@
// Copyright (c) 2017-2022, Mudita Sp. z.o.o. All rights reserved.
// For licensing, see https://github.com/mudita/MuditaOS/LICENSE.md

#include <catch2/catch.hpp>
#include <service-bluetooth/SettingsHolder.hpp>
#include <BtKeysStorage.hpp>

namespace bluetooth
{
    class TestSettingsHolder : public SettingsHolder
    {
      public:
        std::string entryValue;
        Settings settingType;
        auto getValue(const Settings setting) -> SettingEntry override
        {
            if (setting == settingType) {
                return entryValue;
            }
            else {
                return std::string{};
            }
        }
        void setValue(const Settings &newSetting, const SettingEntry &value) override
        {
            settingType = newSetting;
            entryValue  = std::get<std::string>(value);
        }
    };

} // namespace bluetooth

using namespace bluetooth;

TEST_CASE("BT Keys storage")
{
    KeyStorage storage;
    auto settingHolder = std::make_shared<TestSettingsHolder>();

    storage.settings = settingHolder;

    auto btKeyStorage = storage.getKeyStorage();
    SECTION("put key to the storage")
    {
        bd_addr_t addr;
        sscanf_bd_addr("94:B2:CC:F1:92:B1", addr);
        link_key_t key       = "12345";
        link_key_type_t type = COMBINATION_KEY;
        btKeyStorage->put_link_key(addr, key, type);

        REQUIRE(settingHolder->settingType == Settings::BtKeys);
        REQUIRE(settingHolder->entryValue ==
                "{\"keys\": [{\"bd_addr\": \"94:B2:CC:F1:92:B1\", \"link_key\": \"12345\", \"type\": 0}]}");
    }
    SECTION("get key from the storage")
    {
        bd_addr_t addr;
        sscanf_bd_addr("94:B2:CC:F1:92:B1", addr);
        link_key_t key;
        link_key_type_t type;
        settingHolder->entryValue =
            "{\"keys\": [{\"bd_addr\": \"94:B2:CC:F1:92:B1\", \"link_key\": \"12345\", \"type\": 0}]}";

        btKeyStorage->open();
        auto ret = btKeyStorage->get_link_key(addr, key, &type);

        REQUIRE(std::string(reinterpret_cast<char *>(key)) == "12345");
        REQUIRE(type == COMBINATION_KEY);
        REQUIRE(ret == 1);
    }
    SECTION("get key from the storage when there's no key")
    {
        bd_addr_t addr;
        sscanf_bd_addr("94:B2:CC:F1:92:B1", addr);
        link_key_t key;
        link_key_type_t type;
        settingHolder->entryValue = "";
        btKeyStorage->open();
        btKeyStorage->delete_link_key(addr);
        auto ret = btKeyStorage->get_link_key(addr, key, &type);

        REQUIRE(ret != 1);
    }
    SECTION("put key to the storage few times")
    {
        bd_addr_t addr;
        sscanf_bd_addr("94:B2:CC:F1:92:B1", addr);
        link_key_t key       = "12345";
        link_key_type_t type = COMBINATION_KEY;

        btKeyStorage->open();
        btKeyStorage->put_link_key(addr, key, type);
        btKeyStorage->put_link_key(addr, key, type);
        btKeyStorage->put_link_key(addr, key, type);

        REQUIRE(settingHolder->settingType == Settings::BtKeys);
        REQUIRE(settingHolder->entryValue ==
                "{\"keys\": [{\"bd_addr\": \"94:B2:CC:F1:92:B1\", \"link_key\": \"12345\", \"type\": 0}]}");
    }
    SECTION("delete key from the storage")
    {
        bd_addr_t addr;
        sscanf_bd_addr("94:B2:CC:F1:92:B1", addr);
        settingHolder->entryValue =
            "{\"keys\": [{\"bd_addr\": \"94:B2:CC:F1:92:B1\", \"link_key\": \"12345\", \"type\": 0}]}";

        btKeyStorage->open();
        btKeyStorage->delete_link_key(addr);

        REQUIRE(settingHolder->settingType == Settings::BtKeys);
        REQUIRE(settingHolder->entryValue == "{\"keys\": []}");
    }
    SECTION("double-delete key from the storage")
    {
        bd_addr_t addr;
        sscanf_bd_addr("94:B2:CC:F1:92:B1", addr);
        settingHolder->entryValue =
            "{\"keys\": [{\"bd_addr\": \"94:B2:CC:F1:92:B1\", \"link_key\": \"12345\", \"type\": 0}]}";

        btKeyStorage->open();
        btKeyStorage->delete_link_key(addr);
        btKeyStorage->delete_link_key(addr);

        REQUIRE(settingHolder->settingType == Settings::BtKeys);
        REQUIRE(settingHolder->entryValue == "{\"keys\": []}");
    }
}

M module-services/service-bluetooth/service-bluetooth/SettingsHolder.hpp => module-services/service-bluetooth/service-bluetooth/SettingsHolder.hpp +5 -3
@@ 1,4 1,4 @@
// Copyright (c) 2017-2021, Mudita Sp. z.o.o. All rights reserved.
// Copyright (c) 2017-2022, Mudita Sp. z.o.o. All rights reserved.
// For licensing, see https://github.com/mudita/MuditaOS/LICENSE.md
#pragma once
#include <json11.hpp>


@@ 78,9 78,11 @@ namespace bluetooth
    class SettingsHolder
    {
      public:
        SettingsHolder()          = default;
        virtual ~SettingsHolder() = default;
        explicit SettingsHolder(std::unique_ptr<settings::Settings> settingsPtr);
        auto getValue(const Settings setting) -> SettingEntry;
        void setValue(const Settings &newSetting, const SettingEntry &value);
        virtual auto getValue(const Settings setting) -> SettingEntry;
        virtual void setValue(const Settings &newSetting, const SettingEntry &value);
        std::function<void()> onStateChange;
        std::function<void(const std::string &)> onLinkKeyAdded;
        void deinit();