Ring Daemon 16.0.0
Loading...
Searching...
No Matches
accountarchive.cpp
Go to the documentation of this file.
1/*
2 * Copyright (C) 2004-2025 Savoir-faire Linux Inc.
3 *
4 * This program is free software: you can redistribute it and/or modify
5 * it under the terms of the GNU General Public License as published by
6 * the Free Software Foundation, either version 3 of the License, or
7 * (at your option) any later version.
8 *
9 * This program is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 * GNU General Public License for more details.
13 *
14 * You should have received a copy of the GNU General Public License
15 * along with this program. If not, see <https://www.gnu.org/licenses/>.
16 */
17
18#include "accountarchive.h"
19#include "account_const.h"
20#include "configkeys.h"
21#include "base64.h"
22#include "logger.h"
23
24#include <json_utils.h>
25
26namespace jami {
27
28void
29AccountArchive::deserialize(std::string_view dat, const std::vector<uint8_t>& salt)
30{
31 JAMI_DEBUG("Loading account archive ({:d} bytes)", dat.size());
32
33 password_salt = salt;
34
35 // Decode string
36 auto* char_data = dat.data(); // reinterpret_cast<const char*>(&dat[0]);
37 std::string err;
38 Json::Value value;
39 Json::CharReaderBuilder rbuilder;
40 Json::CharReaderBuilder::strictMode(&rbuilder.settings_);
41 auto reader = std::unique_ptr<Json::CharReader>(rbuilder.newCharReader());
42 if (!reader->parse(char_data, char_data + dat.size(), &value, &err)) {
43 JAMI_ERR() << "Archive JSON parsing error: " << err;
44 throw std::runtime_error("failed to parse JSON");
45 }
46
47 // Import content
48 try {
49 for (Json::ValueIterator itr = value.begin(); itr != value.end(); itr++) {
50 try {
51 const auto key = itr.key().asString();
52 if (key.empty())
53 continue;
56 == 0) {
58 == 0) {
59 } else if (key.compare(libjami::Account::ConfProperties::DHT_PROXY_LIST_URL) == 0) {
60 } else if (key.compare(libjami::Account::ConfProperties::AUTOANSWER) == 0) {
61 } else if (key.compare(libjami::Account::ConfProperties::PROXY_ENABLED) == 0) {
62 } else if (key.compare(libjami::Account::ConfProperties::PROXY_SERVER) == 0) {
63 } else if (key.compare(libjami::Account::ConfProperties::PROXY_PUSH_TOKEN) == 0) {
64 } else if (key.compare(Conf::RING_CA_KEY) == 0) {
65 ca_key = std::make_shared<dht::crypto::PrivateKey>(
66 base64::decode(itr->asString()));
67 } else if (key.compare(Conf::RING_ACCOUNT_KEY) == 0) {
68 id.first = std::make_shared<dht::crypto::PrivateKey>(
69 base64::decode(itr->asString()));
70 } else if (key.compare(Conf::RING_ACCOUNT_CERT) == 0) {
71 id.second = std::make_shared<dht::crypto::Certificate>(
72 base64::decode(itr->asString()));
73 } else if (key.compare(Conf::RING_ACCOUNT_CONTACTS) == 0) {
74 for (Json::ValueIterator citr = itr->begin(); citr != itr->end(); citr++) {
75 dht::InfoHash h {citr.key().asString()};
76 if (h != dht::InfoHash {})
77 contacts.emplace(h, Contact {*citr});
78 }
79 } else if (key.compare(Conf::CONVERSATIONS_KEY) == 0) {
80 for (Json::ValueIterator citr = itr->begin(); citr != itr->end(); citr++) {
81 auto ci = ConvInfo(*citr);
82 conversations[ci.id] = std::move(ci);
83 }
84 } else if (key.compare(Conf::CONVERSATIONS_REQUESTS_KEY) == 0) {
85 for (Json::ValueIterator citr = itr->begin(); citr != itr->end(); citr++) {
86 conversationsRequests.emplace(citr.key().asString(),
88 }
89 } else if (key.compare(Conf::ETH_KEY) == 0) {
90 eth_key = base64::decode(itr->asString());
91 } else if (key.compare(Conf::RING_ACCOUNT_CRL) == 0) {
92 revoked = std::make_shared<dht::crypto::RevocationList>(
93 base64::decode(itr->asString()));
94 } else {
95 config[key] = itr->asString();
96 }
97 } catch (const std::exception& ex) {
98 JAMI_ERR("Unable to parse JSON entry with value of type %d: %s",
99 (unsigned) itr->type(),
100 ex.what());
101 }
102 }
103 } catch (const std::exception& ex) {
104 JAMI_ERR("Unable to parse JSON: %s", ex.what());
105 }
106
107 if (not id.first) {
108 throw std::runtime_error("Archive doesn't include account private key");
109 }
110}
111
112std::string
113AccountArchive::serialize() const
114{
115 Json::Value root;
116
117 for (const auto& it : config)
118 root[it.first] = it.second;
119
120 if (ca_key and *ca_key)
121 root[Conf::RING_CA_KEY] = base64::encode(ca_key->serialize());
122
123 root[Conf::RING_ACCOUNT_KEY] = base64::encode(id.first->serialize());
124 root[Conf::RING_ACCOUNT_CERT] = base64::encode(id.second->getPacked());
125 root[Conf::ETH_KEY] = base64::encode(eth_key);
126
127 if (revoked)
128 root[Conf::RING_ACCOUNT_CRL] = base64::encode(revoked->getPacked());
129
130 if (not contacts.empty()) {
131 Json::Value& jsonContacts = root[Conf::RING_ACCOUNT_CONTACTS];
132 for (const auto& c : contacts)
133 jsonContacts[c.first.toString()] = c.second.toJson();
134 }
135
136 if (not conversations.empty()) {
137 Json::Value& jsonConversations = root[Conf::CONVERSATIONS_KEY];
138 for (const auto& [key, c] : conversations) {
139 jsonConversations[key] = c.toJson();
140 }
141 }
142
143 if (not conversationsRequests.empty()) {
144 Json::Value& jsonConversationsReqs = root[Conf::CONVERSATIONS_REQUESTS_KEY];
145 for (const auto& [key, value] : conversationsRequests) {
146 jsonConversationsReqs[key] = value.toJson();
147 }
148 }
149
150 return json::toString(root);
151}
152
153} // namespace jami
#define JAMI_ERR(...)
Definition logger.h:218
#define JAMI_DEBUG(formatstr,...)
Definition logger.h:226
constexpr const char *const RING_ACCOUNT_CRL
Definition configkeys.h:38
constexpr const char *const RING_ACCOUNT_KEY
Definition configkeys.h:34
constexpr const char *const RING_ACCOUNT_CONTACTS
Definition configkeys.h:39
constexpr const char *const RING_CA_KEY
Definition configkeys.h:33
constexpr const char *const ETH_KEY
Definition configkeys.h:30
constexpr const char *const CONVERSATIONS_KEY
Definition configkeys.h:40
constexpr const char *const RING_ACCOUNT_CERT
Definition configkeys.h:35
constexpr const char *const CONVERSATIONS_REQUESTS_KEY
Definition configkeys.h:41
std::vector< uint8_t > decode(std::string_view str)
Definition base64.cpp:47
void emitSignal(Args... args)
Definition ring_signal.h:64
static constexpr const char CA_LIST_FILE[]
static constexpr const char PRIVATE_KEY_FILE[]
static constexpr const char CERTIFICATE_FILE[]
static constexpr const char DHT_PROXY_LIST_URL[]
static constexpr const char PROXY_SERVER[]
static constexpr const char PROXY_ENABLED[]
static constexpr const char PROXY_PUSH_TOKEN[]
static constexpr const char AUTOANSWER[]
std::map< dht::InfoHash, Contact > contacts
Contacts.
void deserialize(std::string_view data, const std::vector< uint8_t > &salt)
Deserialize archive from memory.
std::map< std::string, ConversationRequest > conversationsRequests
std::shared_ptr< dht::crypto::RevocationList > revoked
Revoked devices.
std::shared_ptr< dht::crypto::PrivateKey > ca_key
Generated CA key (for self-signed certificates)
std::vector< uint8_t > password_salt
Salt for the archive encryption password.
std::map< std::string, ConvInfo > conversations
std::vector< uint8_t > eth_key
Ethereum private key.
std::map< std::string, std::string > config
Account configuration.
A ConversationRequest is a request which corresponds to a trust request, but for conversations It's s...