Ring Daemon
Loading...
Searching...
No Matches
accountarchive.cpp
Go to the documentation of this file.
1/*
2 * Copyright (C) 2004-2026 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;
57 } else if (key.compare(libjami::Account::ConfProperties::DHT_PROXY_LIST_URL) == 0) {
58 } else if (key.compare(libjami::Account::ConfProperties::AUTOANSWER) == 0) {
59 } else if (key.compare(libjami::Account::ConfProperties::PROXY_ENABLED) == 0) {
60 } else if (key.compare(libjami::Account::ConfProperties::PROXY_SERVER) == 0) {
61 } else if (key.compare(libjami::Account::ConfProperties::PROXY_PUSH_TOKEN) == 0) {
62 } else if (key.compare(Conf::RING_CA_KEY) == 0) {
63 ca_key = std::make_shared<dht::crypto::PrivateKey>(base64::decode(itr->asString()));
64 } else if (key.compare(Conf::RING_ACCOUNT_KEY) == 0) {
65 id.first = std::make_shared<dht::crypto::PrivateKey>(base64::decode(itr->asString()));
66 } else if (key.compare(Conf::RING_ACCOUNT_CERT) == 0) {
67 id.second = std::make_shared<dht::crypto::Certificate>(base64::decode(itr->asString()));
68 } else if (key.compare(Conf::RING_ACCOUNT_CONTACTS) == 0) {
69 for (Json::ValueIterator citr = itr->begin(); citr != itr->end(); citr++) {
70 dht::InfoHash h {citr.key().asString()};
71 if (h != dht::InfoHash {})
72 contacts.emplace(h, Contact {*citr});
73 }
74 } else if (key.compare(Conf::CONVERSATIONS_KEY) == 0) {
75 for (Json::ValueIterator citr = itr->begin(); citr != itr->end(); citr++) {
76 auto ci = ConvInfo(*citr);
77 conversations[ci.id] = std::move(ci);
78 }
79 } else if (key.compare(Conf::CONVERSATIONS_REQUESTS_KEY) == 0) {
80 for (Json::ValueIterator citr = itr->begin(); citr != itr->end(); citr++) {
81 conversationsRequests.emplace(citr.key().asString(), ConversationRequest(*citr));
82 }
83 } else if (key.compare(Conf::ETH_KEY) == 0) {
84 eth_key = base64::decode(itr->asString());
85 } else if (key.compare(Conf::RING_ACCOUNT_CRL) == 0) {
86 revoked = std::make_shared<dht::crypto::RevocationList>(base64::decode(itr->asString()));
87 } else {
88 config[key] = itr->asString();
89 }
90 } catch (const std::exception& ex) {
91 JAMI_ERR("Unable to parse JSON entry with value of type %d: %s", (unsigned) itr->type(), ex.what());
92 }
93 }
94 } catch (const std::exception& ex) {
95 JAMI_ERR("Unable to parse JSON: %s", ex.what());
96 }
97
98 if (not id.first) {
99 throw std::runtime_error("Archive doesn't include account private key");
100 }
101}
102
103std::string
104AccountArchive::serialize() const
105{
106 Json::Value root;
107
108 for (const auto& it : config)
109 root[it.first] = it.second;
110
111 if (ca_key and *ca_key)
112 root[Conf::RING_CA_KEY] = base64::encode(ca_key->serialize());
113
114 root[Conf::RING_ACCOUNT_KEY] = base64::encode(id.first->serialize());
115 root[Conf::RING_ACCOUNT_CERT] = base64::encode(id.second->getPacked());
116 root[Conf::ETH_KEY] = base64::encode(eth_key);
117
118 if (revoked)
119 root[Conf::RING_ACCOUNT_CRL] = base64::encode(revoked->getPacked());
120
121 if (not contacts.empty()) {
122 Json::Value& jsonContacts = root[Conf::RING_ACCOUNT_CONTACTS];
123 for (const auto& c : contacts)
124 jsonContacts[c.first.toString()] = c.second.toJson();
125 }
126
127 if (not conversations.empty()) {
128 Json::Value& jsonConversations = root[Conf::CONVERSATIONS_KEY];
129 for (const auto& [key, c] : conversations) {
130 jsonConversations[key] = c.toJson();
131 }
132 }
133
134 if (not conversationsRequests.empty()) {
135 Json::Value& jsonConversationsReqs = root[Conf::CONVERSATIONS_REQUESTS_KEY];
136 for (const auto& [key, value] : conversationsRequests) {
137 jsonConversationsReqs[key] = value.toJson();
138 }
139 }
140
141 return json::toString(root);
142}
143
144} // namespace jami
#define JAMI_ERR(...)
Definition logger.h:230
#define JAMI_DEBUG(formatstr,...)
Definition logger.h:238
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< unsigned char > decode(std::string_view str)
Definition base64.cpp:35
void emitSignal(Args... args)
Definition jami_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...