Newer
Older
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
#include "Olm.hpp"
#include "Cache.h"
#include "Logging.hpp"
using namespace mtx::crypto;
namespace {
auto client_ = std::make_unique<mtx::crypto::OlmClient>();
}
namespace olm {
mtx::crypto::OlmClient *
client()
{
return client_.get();
}
void
handle_to_device_messages(const std::vector<nlohmann::json> &msgs)
{
if (msgs.empty())
return;
log::crypto()->info("received {} to_device messages", msgs.size());
for (const auto &msg : msgs) {
try {
OlmMessage olm_msg = msg;
handle_olm_message(std::move(olm_msg));
} catch (const nlohmann::json::exception &e) {
log::crypto()->warn(
"parsing error for olm message: {} {}", e.what(), msg.dump(2));
} catch (const std::invalid_argument &e) {
log::crypto()->warn(
"validation error for olm message: {} {}", e.what(), msg.dump(2));
}
}
}
void
handle_olm_message(const OlmMessage &msg)
{
log::crypto()->info("sender : {}", msg.sender);
log::crypto()->info("sender_key: {}", msg.sender_key);
const auto my_key = olm::client()->identity_keys().curve25519;
for (const auto &cipher : msg.ciphertext) {
// We skip messages not meant for the current device.
if (cipher.first != my_key)
continue;
const auto type = cipher.second.type;
log::crypto()->info("type: {}", type == 0 ? "OLM_PRE_KEY" : "OLM_MESSAGE");
if (type == OLM_MESSAGE_TYPE_PRE_KEY)
handle_pre_key_olm_message(msg.sender, msg.sender_key, cipher.second);
else
handle_olm_normal_message(msg.sender, msg.sender_key, cipher.second);
}
}
void
handle_pre_key_olm_message(const std::string &sender,
const std::string &sender_key,
const OlmCipherContent &content)
{
log::crypto()->info("opening olm session with {}", sender);
OlmSessionPtr inbound_session = nullptr;
try {
inbound_session = olm::client()->create_inbound_session(content.body);
} catch (const olm_exception &e) {
log::crypto()->critical(
"failed to create inbound session with {}: {}", sender, e.what());
return;
}
if (!matches_inbound_session_from(inbound_session.get(), sender_key, content.body)) {
log::crypto()->warn("inbound olm session doesn't match sender's key ({})", sender);
return;
}
mtx::crypto::BinaryBuf output;
try {
output = olm::client()->decrypt_message(
inbound_session.get(), OLM_MESSAGE_TYPE_PRE_KEY, content.body);
} catch (const olm_exception &e) {
log::crypto()->critical(
"failed to decrypt olm message {}: {}", content.body, e.what());
return;
}
auto plaintext = json::parse(std::string((char *)output.data(), output.size()));
log::crypto()->info("decrypted message: \n {}", plaintext.dump(2));
std::string room_id, session_id, session_key;
try {
room_id = plaintext.at("content").at("room_id");
session_id = plaintext.at("content").at("session_id");
session_key = plaintext.at("content").at("session_key");
} catch (const nlohmann::json::exception &e) {
log::crypto()->critical(
"failed to parse plaintext olm message: {} {}", e.what(), plaintext.dump(2));
return;
}
MegolmSessionIndex index;
index.room_id = room_id;
index.session_id = session_id;
index.sender_key = sender_key;
if (!cache::client()->inboundMegolmSessionExists(index)) {
auto megolm_session = olm::client()->init_inbound_group_session(session_key);
try {
cache::client()->saveInboundMegolmSession(index, std::move(megolm_session));
} catch (const lmdb::error &e) {
log::crypto()->critical("failed to save inbound megolm session: {}",
e.what());
return;
}
log::crypto()->info("established inbound megolm session ({}, {})", room_id, sender);
} else {
log::crypto()->warn(
"inbound megolm session already exists ({}, {})", room_id, sender);
}
}
void
handle_olm_normal_message(const std::string &, const std::string &, const OlmCipherContent &)
{
log::crypto()->warn("olm(1) not implemeted yet");
}
} // namespace olm