~aleteoryx/muditaos

ref: 52ca291b30c634cee5286a5fa2b3febd0685fec4 muditaos/module-bluetooth/Bluetooth/BtKeysStorage.cpp -rw-r--r-- 6.2 KiB
52ca291b — Lucjan Bryndza [EGD-5097] Fix minor issues with littlefs fuse 5 years ago
                                                                                
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
// Copyright (c) 2017-2020, Mudita Sp. z.o.o. All rights reserved.
// For licensing, see https://github.com/mudita/MuditaOS/LICENSE.md

#include <algorithm>
#include <cstdio>
#include <filesystem>
#include <purefs/filesystem_paths.hpp>
#include <gsl/gsl_util>

#include "BtKeysStorage.hpp"

json11::Json Bt::KeyStorage::fileJson = json11::Json();
btstack_link_key_db_t Bt::KeyStorage::keyStorage;
json11::Json::array Bt::KeyStorage::keys;
std::string Bt::KeyStorage::fileContent;

namespace Bt
{
    namespace
    {
        std::string loadFilesAsString(const std::filesystem::path &fileToLoad)
        {
            using namespace std::string_literals;
            static constexpr auto file_size_limit = 512LU * 1024LU;
            std::error_code ec;
            auto filesize = std::filesystem::file_size(fileToLoad, ec);
            if (ec || filesize > file_size_limit) {
                return ""s;
            }
            std::string contents(filesize, '\0');
            auto fp = fopen(fileToLoad.c_str(), "r");
            if (!fp) {
                return ""s;
            }
            auto cleanup      = gsl::finally([fp] { fclose(fp); });
            const auto nitems = std::fread(contents.data(), contents.size(), 1, fp);
            return (nitems == 1) ? contents : ""s;
        }

        bool replaceWithString(const std::filesystem::path &fileToModify, const std::string &stringToWrite)
        {
            auto fp = std::fopen(fileToModify.c_str(), "w");
            if (!fp)
                return false;
            auto cleanup       = gsl::finally([fp] { fclose(fp); });
            size_t dataWritten = std::fwrite(stringToWrite.data(), stringToWrite.size(), 1, fp);
            return dataWritten == 1;
        }
    } // namespace

    namespace strings
    {
        inline std::string keysFilename = purefs::dir::getUserDiskPath() / "btkeys.json";
        inline std::string keys         = "keys";
        inline std::string link_key     = "link_key";
        inline std::string bd_addr      = "bd_addr";
        inline std::string type         = "type";
    } // namespace strings

    auto KeyStorage::getKeyStorage() -> btstack_link_key_db_t *
    {
        keyStorage.open              = openStorage;
        keyStorage.set_local_bd_addr = set_local_bd_addr;
        keyStorage.close             = closeStorage;
        keyStorage.get_link_key      = getLinkKey;
        keyStorage.put_link_key      = putLinkKey;
        keyStorage.delete_link_key   = deleteLinkKey;
        keyStorage.iterator_init     = iterator_init;
        keyStorage.iterator_get_next = iterator_get_next;
        keyStorage.iterator_done     = iterator_done;

        return &keyStorage;
    }

    void KeyStorage::openStorage()
    {
        LOG_INFO("opening storage from API");
        fileContent.clear();
        fileContent = loadFilesAsString(strings::keysFilename);
        if (fileContent.empty()) {
            LOG_WARN("opening empty key file!");
            return;
        }

        std::string err;
        fileJson = json11::Json::parse(fileContent.c_str(), err);
        if (!err.empty()) {
            LOG_ERROR("Error while parsing json: %s", err.c_str());
            return;
        }

        keys = std::move(fileJson[strings::keys].array_items());
        LOG_INFO("Imported keys: %d", static_cast<unsigned int>(keys.size()));
    }

    void KeyStorage::closeStorage()
    {
        LOG_INFO("closing storage from API");
        writeToFile();
    }
    //
    auto KeyStorage::getLinkKey(uint8_t *bd_addr, link_key_t link_key, link_key_type_t *type) -> int
    {
        if (type != nullptr && bd_addr != nullptr) {
            LOG_INFO("getting key for address %s from API", bd_addr_to_str(bd_addr));
            if (keys.size() == 0) {
                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, foundLinkKey, sizeof(link_key_t));
                    *type = static_cast<link_key_type_t>(key[strings::type].int_value());

                    return 1;
                }
            }
        }
        return 0;
    }
    void KeyStorage::putLinkKey(uint8_t *bd_addr, uint8_t *link_key, link_key_type_t type)
    {
        LOG_INFO("putting key for address %s from API", bd_addr_to_str(bd_addr));
        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);
        writeToFile();
        LOG_INFO("keys written to the file");
        LOG_INFO("Keys in file: %d", (int)keys.size());
    }
    void KeyStorage::deleteLinkKey(uint8_t *bd_addr)
    {
        auto keysSize = keys.size();
        LOG_INFO("deleting key for address %s from API", bd_addr_to_str(bd_addr));
        auto end = std::remove_if(keys.begin(), keys.end(), [&](auto &key) {
            bd_addr_t addr;
            sscanf_bd_addr(key[strings::bd_addr].string_value().c_str(), addr);
            return bd_addr_cmp(addr, bd_addr) == 0;
        });

        keys.erase(end, keys.end());
        if (keysSize != keys.size()) {
            LOG_INFO("Key successfully deleted");
        }
        writeToFile();
    }
    //
    auto KeyStorage::iterator_init(btstack_link_key_iterator_t *it) -> int
    {
        return 0;
    }
    auto KeyStorage::iterator_get_next(btstack_link_key_iterator_t *it,
                                       uint8_t *bd_addr,
                                       uint8_t *link_key,
                                       link_key_type_t *type) -> int
    {
        return 0;
    }
    void KeyStorage::iterator_done(btstack_link_key_iterator_t *it)
    {}
    void KeyStorage::set_local_bd_addr(bd_addr_t bd_addr)
    {}
    void KeyStorage::writeToFile()
    {
        json11::Json finalJson = json11::Json::object{{strings::keys, keys}};
        fileContent            = finalJson.dump();
        replaceWithString(strings::keysFilename, fileContent);
    }

} // namespace Bt