Allow downloading keys from key backup
This commit is contained in:
parent
e5dea361c0
commit
56db0dbc7d
@ -381,7 +381,7 @@ if(USE_BUNDLED_MTXCLIENT)
|
|||||||
FetchContent_Declare(
|
FetchContent_Declare(
|
||||||
MatrixClient
|
MatrixClient
|
||||||
GIT_REPOSITORY https://github.com/Nheko-Reborn/mtxclient.git
|
GIT_REPOSITORY https://github.com/Nheko-Reborn/mtxclient.git
|
||||||
GIT_TAG deb51ef1d6df870098069312f0a1999550e1eb85
|
GIT_TAG 513196f520733e2f70576168aff7aaf16e0df180
|
||||||
)
|
)
|
||||||
set(BUILD_LIB_EXAMPLES OFF CACHE INTERNAL "")
|
set(BUILD_LIB_EXAMPLES OFF CACHE INTERNAL "")
|
||||||
set(BUILD_LIB_TESTS OFF CACHE INTERNAL "")
|
set(BUILD_LIB_TESTS OFF CACHE INTERNAL "")
|
||||||
|
@ -163,7 +163,7 @@ modules:
|
|||||||
buildsystem: cmake-ninja
|
buildsystem: cmake-ninja
|
||||||
name: mtxclient
|
name: mtxclient
|
||||||
sources:
|
sources:
|
||||||
- commit: deb51ef1d6df870098069312f0a1999550e1eb85
|
- commit: 513196f520733e2f70576168aff7aaf16e0df180
|
||||||
type: git
|
type: git
|
||||||
url: https://github.com/Nheko-Reborn/mtxclient.git
|
url: https://github.com/Nheko-Reborn/mtxclient.git
|
||||||
- config-opts:
|
- config-opts:
|
||||||
|
@ -39,7 +39,7 @@ Image {
|
|||||||
case Crypto.TOFU:
|
case Crypto.TOFU:
|
||||||
return qsTr("Encrypted by an unverified device, but you have trusted that user so far.");
|
return qsTr("Encrypted by an unverified device, but you have trusted that user so far.");
|
||||||
default:
|
default:
|
||||||
return qsTr("Encrypted by an unverified device");
|
return qsTr("Encrypted by an unverified device or the key is from an untrusted source like the key backup.");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -42,6 +42,7 @@ static const std::string SECRET("secret");
|
|||||||
static const std::string_view NEXT_BATCH_KEY("next_batch");
|
static const std::string_view NEXT_BATCH_KEY("next_batch");
|
||||||
static const std::string_view OLM_ACCOUNT_KEY("olm_account");
|
static const std::string_view OLM_ACCOUNT_KEY("olm_account");
|
||||||
static const std::string_view CACHE_FORMAT_VERSION_KEY("cache_format_version");
|
static const std::string_view CACHE_FORMAT_VERSION_KEY("cache_format_version");
|
||||||
|
static const std::string_view CURRENT_ONLINE_BACKUP_VERSION("current_online_backup_version");
|
||||||
|
|
||||||
constexpr size_t MAX_RESTORED_MESSAGES = 30'000;
|
constexpr size_t MAX_RESTORED_MESSAGES = 30'000;
|
||||||
|
|
||||||
@ -723,6 +724,36 @@ Cache::restoreOlmAccount()
|
|||||||
return std::string(pickled.data(), pickled.size());
|
return std::string(pickled.data(), pickled.size());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
Cache::saveBackupVersion(const OnlineBackupVersion &data)
|
||||||
|
{
|
||||||
|
auto txn = lmdb::txn::begin(env_);
|
||||||
|
syncStateDb_.put(txn, CURRENT_ONLINE_BACKUP_VERSION, nlohmann::json(data).dump());
|
||||||
|
txn.commit();
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
Cache::deleteBackupVersion()
|
||||||
|
{
|
||||||
|
auto txn = lmdb::txn::begin(env_);
|
||||||
|
syncStateDb_.del(txn, CURRENT_ONLINE_BACKUP_VERSION);
|
||||||
|
txn.commit();
|
||||||
|
}
|
||||||
|
|
||||||
|
std::optional<OnlineBackupVersion>
|
||||||
|
Cache::backupVersion()
|
||||||
|
{
|
||||||
|
try {
|
||||||
|
auto txn = ro_txn(env_);
|
||||||
|
std::string_view v;
|
||||||
|
syncStateDb_.get(txn, CURRENT_ONLINE_BACKUP_VERSION, v);
|
||||||
|
|
||||||
|
return nlohmann::json::parse(v).get<OnlineBackupVersion>();
|
||||||
|
} catch (...) {
|
||||||
|
return std::nullopt;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
Cache::storeSecret(const std::string name, const std::string secret)
|
Cache::storeSecret(const std::string name, const std::string secret)
|
||||||
{
|
{
|
||||||
@ -4114,6 +4145,20 @@ from_json(const json &j, VerificationCache &info)
|
|||||||
info.device_blocked = j.at("device_blocked").get<std::set<std::string>>();
|
info.device_blocked = j.at("device_blocked").get<std::set<std::string>>();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
to_json(json &j, const OnlineBackupVersion &info)
|
||||||
|
{
|
||||||
|
j["v"] = info.version;
|
||||||
|
j["a"] = info.algorithm;
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
from_json(const json &j, OnlineBackupVersion &info)
|
||||||
|
{
|
||||||
|
info.version = j.at("v").get<std::string>();
|
||||||
|
info.algorithm = j.at("a").get<std::string>();
|
||||||
|
}
|
||||||
|
|
||||||
std::optional<VerificationCache>
|
std::optional<VerificationCache>
|
||||||
Cache::verificationCache(const std::string &user_id, lmdb::txn &txn)
|
Cache::verificationCache(const std::string &user_id, lmdb::txn &txn)
|
||||||
{
|
{
|
||||||
@ -4461,6 +4506,7 @@ to_json(nlohmann::json &obj, const GroupSessionData &msg)
|
|||||||
{
|
{
|
||||||
obj["message_index"] = msg.message_index;
|
obj["message_index"] = msg.message_index;
|
||||||
obj["ts"] = msg.timestamp;
|
obj["ts"] = msg.timestamp;
|
||||||
|
obj["trust"] = msg.trusted;
|
||||||
|
|
||||||
obj["sender_claimed_ed25519_key"] = msg.sender_claimed_ed25519_key;
|
obj["sender_claimed_ed25519_key"] = msg.sender_claimed_ed25519_key;
|
||||||
obj["forwarding_curve25519_key_chain"] = msg.forwarding_curve25519_key_chain;
|
obj["forwarding_curve25519_key_chain"] = msg.forwarding_curve25519_key_chain;
|
||||||
@ -4475,6 +4521,7 @@ from_json(const nlohmann::json &obj, GroupSessionData &msg)
|
|||||||
{
|
{
|
||||||
msg.message_index = obj.at("message_index");
|
msg.message_index = obj.at("message_index");
|
||||||
msg.timestamp = obj.value("ts", 0ULL);
|
msg.timestamp = obj.value("ts", 0ULL);
|
||||||
|
msg.trusted = obj.value("trust", true);
|
||||||
|
|
||||||
msg.sender_claimed_ed25519_key = obj.value("sender_claimed_ed25519_key", "");
|
msg.sender_claimed_ed25519_key = obj.value("sender_claimed_ed25519_key", "");
|
||||||
msg.forwarding_curve25519_key_chain =
|
msg.forwarding_curve25519_key_chain =
|
||||||
|
@ -47,6 +47,11 @@ struct GroupSessionData
|
|||||||
uint64_t message_index = 0;
|
uint64_t message_index = 0;
|
||||||
uint64_t timestamp = 0;
|
uint64_t timestamp = 0;
|
||||||
|
|
||||||
|
// If we got the session via key sharing or forwarding, we can usually trust it.
|
||||||
|
// If it came from asymmetric key backup, it is not trusted.
|
||||||
|
// TODO(Nico): What about forwards? They might come from key backup?
|
||||||
|
bool trusted = true;
|
||||||
|
|
||||||
std::string sender_claimed_ed25519_key;
|
std::string sender_claimed_ed25519_key;
|
||||||
std::vector<std::string> forwarding_curve25519_key_chain;
|
std::vector<std::string> forwarding_curve25519_key_chain;
|
||||||
|
|
||||||
@ -83,6 +88,13 @@ from_json(const nlohmann::json &obj, DevicePublicKeys &msg);
|
|||||||
//! Represents a unique megolm session identifier.
|
//! Represents a unique megolm session identifier.
|
||||||
struct MegolmSessionIndex
|
struct MegolmSessionIndex
|
||||||
{
|
{
|
||||||
|
MegolmSessionIndex() = default;
|
||||||
|
MegolmSessionIndex(std::string room_id_, const mtx::events::msg::Encrypted &e)
|
||||||
|
: room_id(std::move(room_id_))
|
||||||
|
, session_id(e.session_id)
|
||||||
|
, sender_key(e.sender_key)
|
||||||
|
{}
|
||||||
|
|
||||||
//! The room in which this session exists.
|
//! The room in which this session exists.
|
||||||
std::string room_id;
|
std::string room_id;
|
||||||
//! The session_id of the megolm session.
|
//! The session_id of the megolm session.
|
||||||
@ -167,3 +179,16 @@ void
|
|||||||
to_json(nlohmann::json &j, const VerificationCache &info);
|
to_json(nlohmann::json &j, const VerificationCache &info);
|
||||||
void
|
void
|
||||||
from_json(const nlohmann::json &j, VerificationCache &info);
|
from_json(const nlohmann::json &j, VerificationCache &info);
|
||||||
|
|
||||||
|
struct OnlineBackupVersion
|
||||||
|
{
|
||||||
|
//! the version of the online backup currently enabled
|
||||||
|
std::string version;
|
||||||
|
//! the algorithm used by the backup
|
||||||
|
std::string algorithm;
|
||||||
|
};
|
||||||
|
|
||||||
|
void
|
||||||
|
to_json(nlohmann::json &j, const OnlineBackupVersion &info);
|
||||||
|
void
|
||||||
|
from_json(const nlohmann::json &j, OnlineBackupVersion &info);
|
||||||
|
@ -287,6 +287,10 @@ public:
|
|||||||
void saveOlmAccount(const std::string &pickled);
|
void saveOlmAccount(const std::string &pickled);
|
||||||
std::string restoreOlmAccount();
|
std::string restoreOlmAccount();
|
||||||
|
|
||||||
|
void saveBackupVersion(const OnlineBackupVersion &data);
|
||||||
|
void deleteBackupVersion();
|
||||||
|
std::optional<OnlineBackupVersion> backupVersion();
|
||||||
|
|
||||||
void storeSecret(const std::string name, const std::string secret);
|
void storeSecret(const std::string name, const std::string secret);
|
||||||
void deleteSecret(const std::string name);
|
void deleteSecret(const std::string name);
|
||||||
std::optional<std::string> secret(const std::string name);
|
std::optional<std::string> secret(const std::string name);
|
||||||
|
100
src/ChatPage.cpp
100
src/ChatPage.cpp
@ -385,6 +385,7 @@ ChatPage::bootstrap(QString userid, QString homeserver, QString token)
|
|||||||
}
|
}
|
||||||
|
|
||||||
getProfileInfo();
|
getProfileInfo();
|
||||||
|
getBackupVersion();
|
||||||
tryInitialSync();
|
tryInitialSync();
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -418,6 +419,7 @@ ChatPage::loadStateFromCache()
|
|||||||
nhlog::crypto()->info("curve25519: {}", olm::client()->identity_keys().curve25519);
|
nhlog::crypto()->info("curve25519: {}", olm::client()->identity_keys().curve25519);
|
||||||
|
|
||||||
getProfileInfo();
|
getProfileInfo();
|
||||||
|
getBackupVersion();
|
||||||
|
|
||||||
emit contentLoaded();
|
emit contentLoaded();
|
||||||
|
|
||||||
@ -974,6 +976,104 @@ ChatPage::getProfileInfo()
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
ChatPage::getBackupVersion()
|
||||||
|
{
|
||||||
|
if (!UserSettings::instance()->useOnlineKeyBackup()) {
|
||||||
|
nhlog::crypto()->info("Online key backup disabled.");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
http::client()->backup_version(
|
||||||
|
[this](const mtx::responses::backup::BackupVersion &res, mtx::http::RequestErr err) {
|
||||||
|
if (err) {
|
||||||
|
nhlog::net()->warn("Failed to retrieve backup version");
|
||||||
|
if (err->status_code == 404)
|
||||||
|
cache::client()->deleteBackupVersion();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// switch to UI thread for secrets stuff
|
||||||
|
QTimer::singleShot(0, this, [this, res] {
|
||||||
|
auto auth_data = nlohmann::json::parse(res.auth_data);
|
||||||
|
|
||||||
|
if (res.algorithm == "m.megolm_backup.v1.curve25519-aes-sha2") {
|
||||||
|
auto key =
|
||||||
|
cache::secret(mtx::secret_storage::secrets::megolm_backup_v1);
|
||||||
|
if (!key) {
|
||||||
|
nhlog::crypto()->info("No key for online key backup.");
|
||||||
|
cache::client()->deleteBackupVersion();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
using namespace mtx::crypto;
|
||||||
|
auto pubkey = CURVE25519_public_key_from_private(
|
||||||
|
to_binary_buf(base642bin(*key)));
|
||||||
|
|
||||||
|
if (auth_data["public_key"].get<std::string>() != pubkey) {
|
||||||
|
nhlog::crypto()->info(
|
||||||
|
"Our backup key {} does not match the one "
|
||||||
|
"used in the online backup {}",
|
||||||
|
pubkey,
|
||||||
|
auth_data["public_key"]);
|
||||||
|
cache::client()->deleteBackupVersion();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
nhlog::crypto()->info("Using online key backup.");
|
||||||
|
OnlineBackupVersion data{};
|
||||||
|
data.algorithm = res.algorithm;
|
||||||
|
data.version = res.version;
|
||||||
|
cache::client()->saveBackupVersion(data);
|
||||||
|
|
||||||
|
// We really don't need to add our signature.
|
||||||
|
// if (!auth_data["signatures"]
|
||||||
|
// [http::client()->user_id().to_string()]
|
||||||
|
// .contains("ed25519:" +
|
||||||
|
// http::client()->device_id())) {
|
||||||
|
// // add our signature
|
||||||
|
// // This is not strictly necessary, but some Element
|
||||||
|
// // clients rely on it. We assume the master_key
|
||||||
|
// signature
|
||||||
|
// // already exists and add our device signature just to
|
||||||
|
// be
|
||||||
|
// // safe, even though just the master signature is
|
||||||
|
// enough,
|
||||||
|
// // if cross-signing is used.
|
||||||
|
// auto signatures = auth_data["signatures"];
|
||||||
|
// auth_data.erase("signatures");
|
||||||
|
// auth_data.erase("unsigned");
|
||||||
|
// signatures[http::client()->user_id().to_string()]
|
||||||
|
// ["ed25519:" + http::client()->device_id()] =
|
||||||
|
// olm::client()->sign_message(auth_data.dump());
|
||||||
|
// auth_data["signatures"] = signatures;
|
||||||
|
|
||||||
|
// auto copy = res;
|
||||||
|
// copy.auth_data = auth_data.dump();
|
||||||
|
// http::client()->update_backup_version(
|
||||||
|
// res.version, copy, [](mtx::http::RequestErr e) {
|
||||||
|
// if (e) {
|
||||||
|
// nhlog::crypto()->error(
|
||||||
|
// "Failed to update online backup "
|
||||||
|
// "signatures: {} - {}",
|
||||||
|
// mtx::errors::to_string(
|
||||||
|
// e->matrix_error.errcode),
|
||||||
|
// e->matrix_error.error);
|
||||||
|
// } else {
|
||||||
|
// nhlog::crypto()->info(
|
||||||
|
// "Updated key backup signatures");
|
||||||
|
// }
|
||||||
|
// });
|
||||||
|
//}
|
||||||
|
} else {
|
||||||
|
nhlog::crypto()->info("Unsupported key backup algorithm: {}",
|
||||||
|
res.algorithm);
|
||||||
|
cache::client()->deleteBackupVersion();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
ChatPage::initiateLogout()
|
ChatPage::initiateLogout()
|
||||||
{
|
{
|
||||||
|
@ -182,6 +182,7 @@ private:
|
|||||||
void trySync();
|
void trySync();
|
||||||
void ensureOneTimeKeyCount(const std::map<std::string, uint16_t> &counts);
|
void ensureOneTimeKeyCount(const std::map<std::string, uint16_t> &counts);
|
||||||
void getProfileInfo();
|
void getProfileInfo();
|
||||||
|
void getBackupVersion();
|
||||||
|
|
||||||
//! Check if the given room is currently open.
|
//! Check if the given room is currently open.
|
||||||
bool isRoomActive(const QString &room_id);
|
bool isRoomActive(const QString &room_id);
|
||||||
|
@ -130,26 +130,29 @@ MainWindow::MainWindow(QWidget *parent)
|
|||||||
|
|
||||||
trayIcon_->setVisible(userSettings_->tray());
|
trayIcon_->setVisible(userSettings_->tray());
|
||||||
|
|
||||||
if (hasActiveUser()) {
|
// load cache on event loop
|
||||||
QString token = userSettings_->accessToken();
|
QTimer::singleShot(0, this, [this] {
|
||||||
QString home_server = userSettings_->homeserver();
|
if (hasActiveUser()) {
|
||||||
QString user_id = userSettings_->userId();
|
QString token = userSettings_->accessToken();
|
||||||
QString device_id = userSettings_->deviceId();
|
QString home_server = userSettings_->homeserver();
|
||||||
|
QString user_id = userSettings_->userId();
|
||||||
|
QString device_id = userSettings_->deviceId();
|
||||||
|
|
||||||
http::client()->set_access_token(token.toStdString());
|
http::client()->set_access_token(token.toStdString());
|
||||||
http::client()->set_server(home_server.toStdString());
|
http::client()->set_server(home_server.toStdString());
|
||||||
http::client()->set_device_id(device_id.toStdString());
|
http::client()->set_device_id(device_id.toStdString());
|
||||||
|
|
||||||
try {
|
try {
|
||||||
using namespace mtx::identifiers;
|
using namespace mtx::identifiers;
|
||||||
http::client()->set_user(parse<User>(user_id.toStdString()));
|
http::client()->set_user(parse<User>(user_id.toStdString()));
|
||||||
} catch (const std::invalid_argument &) {
|
} catch (const std::invalid_argument &) {
|
||||||
nhlog::ui()->critical("bootstrapped with invalid user_id: {}",
|
nhlog::ui()->critical("bootstrapped with invalid user_id: {}",
|
||||||
user_id.toStdString());
|
user_id.toStdString());
|
||||||
|
}
|
||||||
|
|
||||||
|
showChatPage();
|
||||||
}
|
}
|
||||||
|
});
|
||||||
showChatPage();
|
|
||||||
}
|
|
||||||
|
|
||||||
if (loadJdenticonPlugin()) {
|
if (loadJdenticonPlugin()) {
|
||||||
nhlog::ui()->info("loaded jdenticon.");
|
nhlog::ui()->info("loaded jdenticon.");
|
||||||
|
104
src/Olm.cpp
104
src/Olm.cpp
@ -833,6 +833,8 @@ import_inbound_megolm_session(
|
|||||||
data.forwarding_curve25519_key_chain =
|
data.forwarding_curve25519_key_chain =
|
||||||
roomKey.content.forwarding_curve25519_key_chain;
|
roomKey.content.forwarding_curve25519_key_chain;
|
||||||
data.sender_claimed_ed25519_key = roomKey.content.sender_claimed_ed25519_key;
|
data.sender_claimed_ed25519_key = roomKey.content.sender_claimed_ed25519_key;
|
||||||
|
// may have come from online key backup, so we can't trust it...
|
||||||
|
data.trusted = false;
|
||||||
|
|
||||||
cache::saveInboundMegolmSession(index, std::move(megolm_session), data);
|
cache::saveInboundMegolmSession(index, std::move(megolm_session), data);
|
||||||
} catch (const lmdb::error &e) {
|
} catch (const lmdb::error &e) {
|
||||||
@ -856,6 +858,97 @@ mark_keys_as_published()
|
|||||||
cache::saveOlmAccount(olm::client()->save(STORAGE_SECRET_KEY));
|
cache::saveOlmAccount(olm::client()->save(STORAGE_SECRET_KEY));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
lookup_keybackup(const std::string room, const std::string session_id)
|
||||||
|
{
|
||||||
|
if (!UserSettings::instance()->useOnlineKeyBackup()) {
|
||||||
|
// Online key backup disabled
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
auto backupVersion = cache::client()->backupVersion();
|
||||||
|
if (!backupVersion) {
|
||||||
|
// no trusted OKB
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
using namespace mtx::crypto;
|
||||||
|
|
||||||
|
auto decryptedSecret = cache::secret(mtx::secret_storage::secrets::megolm_backup_v1);
|
||||||
|
if (!decryptedSecret) {
|
||||||
|
// no backup key available
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
auto sessionDecryptionKey = to_binary_buf(base642bin(*decryptedSecret));
|
||||||
|
|
||||||
|
http::client()->room_keys(
|
||||||
|
backupVersion->version,
|
||||||
|
room,
|
||||||
|
session_id,
|
||||||
|
[room, session_id, sessionDecryptionKey](const mtx::responses::backup::SessionBackup &bk,
|
||||||
|
mtx::http::RequestErr err) {
|
||||||
|
if (err) {
|
||||||
|
if (err->status_code != 404)
|
||||||
|
nhlog::crypto()->error(
|
||||||
|
"Failed to dowload key {}:{}: {} - {}",
|
||||||
|
room,
|
||||||
|
session_id,
|
||||||
|
mtx::errors::to_string(err->matrix_error.errcode),
|
||||||
|
err->matrix_error.error);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
try {
|
||||||
|
auto session = decrypt_session(bk.session_data, sessionDecryptionKey);
|
||||||
|
|
||||||
|
if (session.algorithm != mtx::crypto::MEGOLM_ALGO)
|
||||||
|
// don't know this algorithm
|
||||||
|
return;
|
||||||
|
|
||||||
|
MegolmSessionIndex index;
|
||||||
|
index.room_id = room;
|
||||||
|
index.session_id = session_id;
|
||||||
|
index.sender_key = session.sender_key;
|
||||||
|
|
||||||
|
GroupSessionData data{};
|
||||||
|
data.forwarding_curve25519_key_chain =
|
||||||
|
session.forwarding_curve25519_key_chain;
|
||||||
|
data.sender_claimed_ed25519_key = session.sender_claimed_keys["ed25519"];
|
||||||
|
// online key backup can't be trusted, because anyone can upload to it.
|
||||||
|
data.trusted = false;
|
||||||
|
|
||||||
|
auto megolm_session =
|
||||||
|
olm::client()->import_inbound_group_session(session.session_key);
|
||||||
|
|
||||||
|
if (!cache::inboundMegolmSessionExists(index) ||
|
||||||
|
olm_inbound_group_session_first_known_index(megolm_session.get()) <
|
||||||
|
olm_inbound_group_session_first_known_index(
|
||||||
|
cache::getInboundMegolmSession(index).get())) {
|
||||||
|
cache::saveInboundMegolmSession(
|
||||||
|
index, std::move(megolm_session), data);
|
||||||
|
|
||||||
|
nhlog::crypto()->info("imported inbound megolm session "
|
||||||
|
"from key backup ({}, {})",
|
||||||
|
room,
|
||||||
|
session_id);
|
||||||
|
|
||||||
|
// call on UI thread
|
||||||
|
QTimer::singleShot(0, ChatPage::instance(), [index] {
|
||||||
|
ChatPage::instance()->receivedSessionKey(
|
||||||
|
index.room_id, index.session_id);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
} catch (const lmdb::error &e) {
|
||||||
|
nhlog::crypto()->critical("failed to save inbound megolm session: {}",
|
||||||
|
e.what());
|
||||||
|
return;
|
||||||
|
} catch (const mtx::crypto::olm_exception &e) {
|
||||||
|
nhlog::crypto()->critical("failed to import inbound megolm session: {}",
|
||||||
|
e.what());
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
send_key_request_for(mtx::events::EncryptedEvent<mtx::events::msg::Encrypted> e,
|
send_key_request_for(mtx::events::EncryptedEvent<mtx::events::msg::Encrypted> e,
|
||||||
const std::string &request_id,
|
const std::string &request_id,
|
||||||
@ -898,6 +991,8 @@ send_key_request_for(mtx::events::EncryptedEvent<mtx::events::msg::Encrypted> e,
|
|||||||
e.sender,
|
e.sender,
|
||||||
e.content.device_id);
|
e.content.device_id);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
// http::client()->room_keys
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
@ -1095,12 +1190,15 @@ decryptEvent(const MegolmSessionIndex &index,
|
|||||||
}
|
}
|
||||||
|
|
||||||
crypto::Trust
|
crypto::Trust
|
||||||
calculate_trust(const std::string &user_id, const std::string &curve25519)
|
calculate_trust(const std::string &user_id, const MegolmSessionIndex &index)
|
||||||
{
|
{
|
||||||
auto status = cache::client()->verificationStatus(user_id);
|
auto status = cache::client()->verificationStatus(user_id);
|
||||||
|
auto megolmData = cache::client()->getMegolmSessionData(index);
|
||||||
crypto::Trust trustlevel = crypto::Trust::Unverified;
|
crypto::Trust trustlevel = crypto::Trust::Unverified;
|
||||||
if (status.verified_device_keys.count(curve25519))
|
|
||||||
trustlevel = status.verified_device_keys.at(curve25519);
|
if (megolmData && megolmData->trusted &&
|
||||||
|
status.verified_device_keys.count(index.sender_key))
|
||||||
|
trustlevel = status.verified_device_keys.at(index.sender_key);
|
||||||
|
|
||||||
return trustlevel;
|
return trustlevel;
|
||||||
}
|
}
|
||||||
|
@ -70,6 +70,8 @@ create_inbound_megolm_session(const mtx::events::DeviceEvent<mtx::events::msg::R
|
|||||||
void
|
void
|
||||||
import_inbound_megolm_session(
|
import_inbound_megolm_session(
|
||||||
const mtx::events::DeviceEvent<mtx::events::msg::ForwardedRoomKey> &roomKey);
|
const mtx::events::DeviceEvent<mtx::events::msg::ForwardedRoomKey> &roomKey);
|
||||||
|
void
|
||||||
|
lookup_keybackup(const std::string room, const std::string session_id);
|
||||||
|
|
||||||
nlohmann::json
|
nlohmann::json
|
||||||
handle_pre_key_olm_message(const std::string &sender,
|
handle_pre_key_olm_message(const std::string &sender,
|
||||||
@ -87,7 +89,7 @@ decryptEvent(const MegolmSessionIndex &index,
|
|||||||
const mtx::events::EncryptedEvent<mtx::events::msg::Encrypted> &event,
|
const mtx::events::EncryptedEvent<mtx::events::msg::Encrypted> &event,
|
||||||
bool dont_write_db = false);
|
bool dont_write_db = false);
|
||||||
crypto::Trust
|
crypto::Trust
|
||||||
calculate_trust(const std::string &user_id, const std::string &curve25519);
|
calculate_trust(const std::string &user_id, const MegolmSessionIndex &index);
|
||||||
|
|
||||||
void
|
void
|
||||||
mark_keys_as_published();
|
mark_keys_as_published();
|
||||||
|
@ -124,6 +124,7 @@ UserSettings::load(std::optional<QString> profile)
|
|||||||
.toBool();
|
.toBool();
|
||||||
onlyShareKeysWithVerifiedUsers_ =
|
onlyShareKeysWithVerifiedUsers_ =
|
||||||
settings.value(prefix + "user/only_share_keys_with_verified_users", false).toBool();
|
settings.value(prefix + "user/only_share_keys_with_verified_users", false).toBool();
|
||||||
|
useOnlineKeyBackup_ = settings.value(prefix + "user/online_key_backup", true).toBool();
|
||||||
|
|
||||||
disableCertificateValidation_ =
|
disableCertificateValidation_ =
|
||||||
settings.value("disable_certificate_validation", false).toBool();
|
settings.value("disable_certificate_validation", false).toBool();
|
||||||
@ -425,6 +426,17 @@ UserSettings::setShareKeysWithTrustedUsers(bool shareKeys)
|
|||||||
save();
|
save();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
UserSettings::setUseOnlineKeyBackup(bool useBackup)
|
||||||
|
{
|
||||||
|
if (useBackup == useOnlineKeyBackup_)
|
||||||
|
return;
|
||||||
|
|
||||||
|
useOnlineKeyBackup_ = useBackup;
|
||||||
|
emit useOnlineKeyBackupChanged(useBackup);
|
||||||
|
save();
|
||||||
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
UserSettings::setRingtone(QString ringtone)
|
UserSettings::setRingtone(QString ringtone)
|
||||||
{
|
{
|
||||||
@ -664,6 +676,7 @@ UserSettings::save()
|
|||||||
shareKeysWithTrustedUsers_);
|
shareKeysWithTrustedUsers_);
|
||||||
settings.setValue(prefix + "user/only_share_keys_with_verified_users",
|
settings.setValue(prefix + "user/only_share_keys_with_verified_users",
|
||||||
onlyShareKeysWithVerifiedUsers_);
|
onlyShareKeysWithVerifiedUsers_);
|
||||||
|
settings.setValue(prefix + "user/online_key_backup", useOnlineKeyBackup_);
|
||||||
|
|
||||||
settings.setValue("disable_certificate_validation", disableCertificateValidation_);
|
settings.setValue("disable_certificate_validation", disableCertificateValidation_);
|
||||||
|
|
||||||
@ -725,6 +738,7 @@ UserSettingsPage::UserSettingsPage(QSharedPointer<UserSettings> settings, QWidge
|
|||||||
privacyScreen_ = new Toggle{this};
|
privacyScreen_ = new Toggle{this};
|
||||||
onlyShareKeysWithVerifiedUsers_ = new Toggle(this);
|
onlyShareKeysWithVerifiedUsers_ = new Toggle(this);
|
||||||
shareKeysWithTrustedUsers_ = new Toggle(this);
|
shareKeysWithTrustedUsers_ = new Toggle(this);
|
||||||
|
useOnlineKeyBackup_ = new Toggle(this);
|
||||||
groupViewToggle_ = new Toggle{this};
|
groupViewToggle_ = new Toggle{this};
|
||||||
timelineButtonsToggle_ = new Toggle{this};
|
timelineButtonsToggle_ = new Toggle{this};
|
||||||
typingNotifications_ = new Toggle{this};
|
typingNotifications_ = new Toggle{this};
|
||||||
@ -756,6 +770,7 @@ UserSettingsPage::UserSettingsPage(QSharedPointer<UserSettings> settings, QWidge
|
|||||||
privacyScreen_->setChecked(settings_->privacyScreen());
|
privacyScreen_->setChecked(settings_->privacyScreen());
|
||||||
onlyShareKeysWithVerifiedUsers_->setChecked(settings_->onlyShareKeysWithVerifiedUsers());
|
onlyShareKeysWithVerifiedUsers_->setChecked(settings_->onlyShareKeysWithVerifiedUsers());
|
||||||
shareKeysWithTrustedUsers_->setChecked(settings_->shareKeysWithTrustedUsers());
|
shareKeysWithTrustedUsers_->setChecked(settings_->shareKeysWithTrustedUsers());
|
||||||
|
useOnlineKeyBackup_->setChecked(settings_->useOnlineKeyBackup());
|
||||||
groupViewToggle_->setChecked(settings_->groupView());
|
groupViewToggle_->setChecked(settings_->groupView());
|
||||||
timelineButtonsToggle_->setChecked(settings_->buttonsInTimeline());
|
timelineButtonsToggle_->setChecked(settings_->buttonsInTimeline());
|
||||||
typingNotifications_->setChecked(settings_->typingNotifications());
|
typingNotifications_->setChecked(settings_->typingNotifications());
|
||||||
@ -1033,6 +1048,10 @@ UserSettingsPage::UserSettingsPage(QSharedPointer<UserSettings> settings, QWidge
|
|||||||
shareKeysWithTrustedUsers_,
|
shareKeysWithTrustedUsers_,
|
||||||
tr("Automatically replies to key requests from other users, if they are verified, "
|
tr("Automatically replies to key requests from other users, if they are verified, "
|
||||||
"even if that device shouldn't have access to those keys otherwise."));
|
"even if that device shouldn't have access to those keys otherwise."));
|
||||||
|
boxWrap(tr("Online Key Backup"),
|
||||||
|
useOnlineKeyBackup_,
|
||||||
|
tr("Download message encryption keys from and upload to the encrypted online key "
|
||||||
|
"backup."));
|
||||||
formLayout_->addRow(new HorizontalLine{this});
|
formLayout_->addRow(new HorizontalLine{this});
|
||||||
formLayout_->addRow(sessionKeysLabel, sessionKeysLayout);
|
formLayout_->addRow(sessionKeysLabel, sessionKeysLayout);
|
||||||
formLayout_->addRow(crossSigningKeysLabel, crossSigningKeysLayout);
|
formLayout_->addRow(crossSigningKeysLabel, crossSigningKeysLayout);
|
||||||
@ -1208,6 +1227,10 @@ UserSettingsPage::UserSettingsPage(QSharedPointer<UserSettings> settings, QWidge
|
|||||||
settings_->setShareKeysWithTrustedUsers(enabled);
|
settings_->setShareKeysWithTrustedUsers(enabled);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
connect(useOnlineKeyBackup_, &Toggle::toggled, this, [this](bool enabled) {
|
||||||
|
settings_->setUseOnlineKeyBackup(enabled);
|
||||||
|
});
|
||||||
|
|
||||||
connect(avatarCircles_, &Toggle::toggled, this, [this](bool enabled) {
|
connect(avatarCircles_, &Toggle::toggled, this, [this](bool enabled) {
|
||||||
settings_->setAvatarCircles(enabled);
|
settings_->setAvatarCircles(enabled);
|
||||||
});
|
});
|
||||||
@ -1298,6 +1321,7 @@ UserSettingsPage::showEvent(QShowEvent *)
|
|||||||
privacyScreen_->setState(settings_->privacyScreen());
|
privacyScreen_->setState(settings_->privacyScreen());
|
||||||
onlyShareKeysWithVerifiedUsers_->setState(settings_->onlyShareKeysWithVerifiedUsers());
|
onlyShareKeysWithVerifiedUsers_->setState(settings_->onlyShareKeysWithVerifiedUsers());
|
||||||
shareKeysWithTrustedUsers_->setState(settings_->shareKeysWithTrustedUsers());
|
shareKeysWithTrustedUsers_->setState(settings_->shareKeysWithTrustedUsers());
|
||||||
|
useOnlineKeyBackup_->setState(settings_->useOnlineKeyBackup());
|
||||||
avatarCircles_->setState(settings_->avatarCircles());
|
avatarCircles_->setState(settings_->avatarCircles());
|
||||||
typingNotifications_->setState(settings_->typingNotifications());
|
typingNotifications_->setState(settings_->typingNotifications());
|
||||||
sortByImportance_->setState(settings_->sortByImportance());
|
sortByImportance_->setState(settings_->sortByImportance());
|
||||||
|
@ -93,6 +93,8 @@ class UserSettings : public QObject
|
|||||||
setOnlyShareKeysWithVerifiedUsers NOTIFY onlyShareKeysWithVerifiedUsersChanged)
|
setOnlyShareKeysWithVerifiedUsers NOTIFY onlyShareKeysWithVerifiedUsersChanged)
|
||||||
Q_PROPERTY(bool shareKeysWithTrustedUsers READ shareKeysWithTrustedUsers WRITE
|
Q_PROPERTY(bool shareKeysWithTrustedUsers READ shareKeysWithTrustedUsers WRITE
|
||||||
setShareKeysWithTrustedUsers NOTIFY shareKeysWithTrustedUsersChanged)
|
setShareKeysWithTrustedUsers NOTIFY shareKeysWithTrustedUsersChanged)
|
||||||
|
Q_PROPERTY(bool useOnlineKeyBackup READ useOnlineKeyBackup WRITE setUseOnlineKeyBackup
|
||||||
|
NOTIFY useOnlineKeyBackupChanged)
|
||||||
Q_PROPERTY(QString profile READ profile WRITE setProfile NOTIFY profileChanged)
|
Q_PROPERTY(QString profile READ profile WRITE setProfile NOTIFY profileChanged)
|
||||||
Q_PROPERTY(QString userId READ userId WRITE setUserId NOTIFY userIdChanged)
|
Q_PROPERTY(QString userId READ userId WRITE setUserId NOTIFY userIdChanged)
|
||||||
Q_PROPERTY(
|
Q_PROPERTY(
|
||||||
@ -159,6 +161,7 @@ public:
|
|||||||
void setUseStunServer(bool state);
|
void setUseStunServer(bool state);
|
||||||
void setOnlyShareKeysWithVerifiedUsers(bool state);
|
void setOnlyShareKeysWithVerifiedUsers(bool state);
|
||||||
void setShareKeysWithTrustedUsers(bool state);
|
void setShareKeysWithTrustedUsers(bool state);
|
||||||
|
void setUseOnlineKeyBackup(bool state);
|
||||||
void setProfile(QString profile);
|
void setProfile(QString profile);
|
||||||
void setUserId(QString userId);
|
void setUserId(QString userId);
|
||||||
void setAccessToken(QString accessToken);
|
void setAccessToken(QString accessToken);
|
||||||
@ -215,6 +218,7 @@ public:
|
|||||||
bool useStunServer() const { return useStunServer_; }
|
bool useStunServer() const { return useStunServer_; }
|
||||||
bool shareKeysWithTrustedUsers() const { return shareKeysWithTrustedUsers_; }
|
bool shareKeysWithTrustedUsers() const { return shareKeysWithTrustedUsers_; }
|
||||||
bool onlyShareKeysWithVerifiedUsers() const { return onlyShareKeysWithVerifiedUsers_; }
|
bool onlyShareKeysWithVerifiedUsers() const { return onlyShareKeysWithVerifiedUsers_; }
|
||||||
|
bool useOnlineKeyBackup() const { return useOnlineKeyBackup_; }
|
||||||
QString profile() const { return profile_; }
|
QString profile() const { return profile_; }
|
||||||
QString userId() const { return userId_; }
|
QString userId() const { return userId_; }
|
||||||
QString accessToken() const { return accessToken_; }
|
QString accessToken() const { return accessToken_; }
|
||||||
@ -261,6 +265,7 @@ signals:
|
|||||||
void useStunServerChanged(bool state);
|
void useStunServerChanged(bool state);
|
||||||
void onlyShareKeysWithVerifiedUsersChanged(bool state);
|
void onlyShareKeysWithVerifiedUsersChanged(bool state);
|
||||||
void shareKeysWithTrustedUsersChanged(bool state);
|
void shareKeysWithTrustedUsersChanged(bool state);
|
||||||
|
void useOnlineKeyBackupChanged(bool state);
|
||||||
void profileChanged(QString profile);
|
void profileChanged(QString profile);
|
||||||
void userIdChanged(QString userId);
|
void userIdChanged(QString userId);
|
||||||
void accessTokenChanged(QString accessToken);
|
void accessTokenChanged(QString accessToken);
|
||||||
@ -293,6 +298,7 @@ private:
|
|||||||
int privacyScreenTimeout_;
|
int privacyScreenTimeout_;
|
||||||
bool shareKeysWithTrustedUsers_;
|
bool shareKeysWithTrustedUsers_;
|
||||||
bool onlyShareKeysWithVerifiedUsers_;
|
bool onlyShareKeysWithVerifiedUsers_;
|
||||||
|
bool useOnlineKeyBackup_;
|
||||||
bool mobileMode_;
|
bool mobileMode_;
|
||||||
int timelineMaxWidth_;
|
int timelineMaxWidth_;
|
||||||
int roomListWidth_;
|
int roomListWidth_;
|
||||||
@ -384,6 +390,7 @@ private:
|
|||||||
QSpinBox *privacyScreenTimeout_;
|
QSpinBox *privacyScreenTimeout_;
|
||||||
Toggle *shareKeysWithTrustedUsers_;
|
Toggle *shareKeysWithTrustedUsers_;
|
||||||
Toggle *onlyShareKeysWithVerifiedUsers_;
|
Toggle *onlyShareKeysWithVerifiedUsers_;
|
||||||
|
Toggle *useOnlineKeyBackup_;
|
||||||
Toggle *mobileMode_;
|
Toggle *mobileMode_;
|
||||||
QLabel *deviceFingerprintValue_;
|
QLabel *deviceFingerprintValue_;
|
||||||
QLabel *deviceIdValue_;
|
QLabel *deviceIdValue_;
|
||||||
|
@ -643,10 +643,7 @@ EventStore::decryptEvent(const IdIndex &idx,
|
|||||||
if (auto cachedEvent = decryptedEvents_.object(idx))
|
if (auto cachedEvent = decryptedEvents_.object(idx))
|
||||||
return cachedEvent;
|
return cachedEvent;
|
||||||
|
|
||||||
MegolmSessionIndex index;
|
MegolmSessionIndex index(room_id_, e.content);
|
||||||
index.room_id = room_id_;
|
|
||||||
index.session_id = e.content.session_id;
|
|
||||||
index.sender_key = e.content.sender_key;
|
|
||||||
|
|
||||||
auto asCacheEntry = [&idx](olm::DecryptionResult &&event) {
|
auto asCacheEntry = [&idx](olm::DecryptionResult &&event) {
|
||||||
auto event_ptr = new olm::DecryptionResult(std::move(event));
|
auto event_ptr = new olm::DecryptionResult(std::move(event));
|
||||||
@ -726,6 +723,7 @@ EventStore::requestSession(const mtx::events::EncryptedEvent<mtx::events::msg::E
|
|||||||
qint64 delay = manual ? 60 : (60 * 10);
|
qint64 delay = manual ? 60 : (60 * 10);
|
||||||
if (r.requested_at + delay < QDateTime::currentSecsSinceEpoch()) {
|
if (r.requested_at + delay < QDateTime::currentSecsSinceEpoch()) {
|
||||||
r.requested_at = QDateTime::currentSecsSinceEpoch();
|
r.requested_at = QDateTime::currentSecsSinceEpoch();
|
||||||
|
olm::lookup_keybackup(room_id_, ev.content.session_id);
|
||||||
olm::send_key_request_for(copy, r.request_id);
|
olm::send_key_request_for(copy, r.request_id);
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
@ -733,6 +731,7 @@ EventStore::requestSession(const mtx::events::EncryptedEvent<mtx::events::msg::E
|
|||||||
request.request_id = "key_request." + http::client()->generate_txn_id();
|
request.request_id = "key_request." + http::client()->generate_txn_id();
|
||||||
request.requested_at = QDateTime::currentSecsSinceEpoch();
|
request.requested_at = QDateTime::currentSecsSinceEpoch();
|
||||||
request.events.push_back(copy);
|
request.events.push_back(copy);
|
||||||
|
olm::lookup_keybackup(room_id_, ev.content.session_id);
|
||||||
olm::send_key_request_for(copy, request.request_id);
|
olm::send_key_request_for(copy, request.request_id);
|
||||||
pending_key_requests[ev.content.session_id] = request;
|
pending_key_requests[ev.content.session_id] = request;
|
||||||
}
|
}
|
||||||
|
@ -641,8 +641,9 @@ TimelineModel::data(const mtx::events::collections::TimelineEvents &event, int r
|
|||||||
if (auto encrypted =
|
if (auto encrypted =
|
||||||
std::get_if<mtx::events::EncryptedEvent<mtx::events::msg::Encrypted>>(
|
std::get_if<mtx::events::EncryptedEvent<mtx::events::msg::Encrypted>>(
|
||||||
&*encrypted_event)) {
|
&*encrypted_event)) {
|
||||||
return olm::calculate_trust(encrypted->sender,
|
return olm::calculate_trust(
|
||||||
encrypted->content.sender_key);
|
encrypted->sender,
|
||||||
|
MegolmSessionIndex(room_id_.toStdString(), encrypted->content));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return crypto::Trust::Unverified;
|
return crypto::Trust::Unverified;
|
||||||
@ -840,10 +841,7 @@ TimelineModel::addEvents(const mtx::responses::Timeline &timeline)
|
|||||||
|
|
||||||
for (auto e : timeline.events) {
|
for (auto e : timeline.events) {
|
||||||
if (auto encryptedEvent = std::get_if<EncryptedEvent<msg::Encrypted>>(&e)) {
|
if (auto encryptedEvent = std::get_if<EncryptedEvent<msg::Encrypted>>(&e)) {
|
||||||
MegolmSessionIndex index;
|
MegolmSessionIndex index(room_id_.toStdString(), encryptedEvent->content);
|
||||||
index.room_id = room_id_.toStdString();
|
|
||||||
index.session_id = encryptedEvent->content.session_id;
|
|
||||||
index.sender_key = encryptedEvent->content.sender_key;
|
|
||||||
|
|
||||||
auto result = olm::decryptEvent(index, *encryptedEvent);
|
auto result = olm::decryptEvent(index, *encryptedEvent);
|
||||||
if (result.event)
|
if (result.event)
|
||||||
|
Loading…
Reference in New Issue
Block a user