mirror of
https://github.com/Nheko-Reborn/nheko.git
synced 2024-11-26 13:08:48 +03:00
Stop encrypting all sessions with secret
This commit is contained in:
parent
0f361151d7
commit
c80e253a24
4 changed files with 61 additions and 31 deletions
|
@ -36,8 +36,7 @@
|
||||||
|
|
||||||
//! Should be changed when a breaking change occurs in the cache format.
|
//! Should be changed when a breaking change occurs in the cache format.
|
||||||
//! This will reset client's data.
|
//! This will reset client's data.
|
||||||
static const std::string CURRENT_CACHE_FORMAT_VERSION("2021.08.22");
|
static const std::string CURRENT_CACHE_FORMAT_VERSION("2021.08.31");
|
||||||
static const std::string SECRET("secret");
|
|
||||||
|
|
||||||
//! Keys used for the DB
|
//! Keys used for the DB
|
||||||
static const std::string_view NEXT_BATCH_KEY("next_batch");
|
static const std::string_view NEXT_BATCH_KEY("next_batch");
|
||||||
|
@ -370,7 +369,8 @@ Cache::exportSessionKeys()
|
||||||
ExportedSession exported;
|
ExportedSession exported;
|
||||||
MegolmSessionIndex index;
|
MegolmSessionIndex index;
|
||||||
|
|
||||||
auto saved_session = unpickle<InboundSessionObject>(std::string(value), SECRET);
|
auto saved_session =
|
||||||
|
unpickle<InboundSessionObject>(std::string(value), pickle_secret_);
|
||||||
|
|
||||||
try {
|
try {
|
||||||
index = nlohmann::json::parse(key).get<MegolmSessionIndex>();
|
index = nlohmann::json::parse(key).get<MegolmSessionIndex>();
|
||||||
|
@ -424,13 +424,14 @@ Cache::saveInboundMegolmSession(const MegolmSessionIndex &index,
|
||||||
{
|
{
|
||||||
using namespace mtx::crypto;
|
using namespace mtx::crypto;
|
||||||
const auto key = json(index).dump();
|
const auto key = json(index).dump();
|
||||||
const auto pickled = pickle<InboundSessionObject>(session.get(), SECRET);
|
const auto pickled = pickle<InboundSessionObject>(session.get(), pickle_secret_);
|
||||||
|
|
||||||
auto txn = lmdb::txn::begin(env_);
|
auto txn = lmdb::txn::begin(env_);
|
||||||
|
|
||||||
std::string_view value;
|
std::string_view value;
|
||||||
if (inboundMegolmSessionDb_.get(txn, key, value)) {
|
if (inboundMegolmSessionDb_.get(txn, key, value)) {
|
||||||
auto oldSession = unpickle<InboundSessionObject>(std::string(value), SECRET);
|
auto oldSession =
|
||||||
|
unpickle<InboundSessionObject>(std::string(value), pickle_secret_);
|
||||||
if (olm_inbound_group_session_first_known_index(session.get()) >
|
if (olm_inbound_group_session_first_known_index(session.get()) >
|
||||||
olm_inbound_group_session_first_known_index(oldSession.get())) {
|
olm_inbound_group_session_first_known_index(oldSession.get())) {
|
||||||
nhlog::crypto()->warn(
|
nhlog::crypto()->warn(
|
||||||
|
@ -455,7 +456,8 @@ Cache::getInboundMegolmSession(const MegolmSessionIndex &index)
|
||||||
std::string_view value;
|
std::string_view value;
|
||||||
|
|
||||||
if (inboundMegolmSessionDb_.get(txn, key, value)) {
|
if (inboundMegolmSessionDb_.get(txn, key, value)) {
|
||||||
auto session = unpickle<InboundSessionObject>(std::string(value), SECRET);
|
auto session =
|
||||||
|
unpickle<InboundSessionObject>(std::string(value), pickle_secret_);
|
||||||
return session;
|
return session;
|
||||||
}
|
}
|
||||||
} catch (std::exception &e) {
|
} catch (std::exception &e) {
|
||||||
|
@ -502,7 +504,7 @@ Cache::updateOutboundMegolmSession(const std::string &room_id,
|
||||||
|
|
||||||
// Save the updated pickled data for the session.
|
// Save the updated pickled data for the session.
|
||||||
json j;
|
json j;
|
||||||
j["session"] = pickle<OutboundSessionObject>(ptr.get(), SECRET);
|
j["session"] = pickle<OutboundSessionObject>(ptr.get(), pickle_secret_);
|
||||||
|
|
||||||
auto txn = lmdb::txn::begin(env_);
|
auto txn = lmdb::txn::begin(env_);
|
||||||
outboundMegolmSessionDb_.put(txn, room_id, j.dump());
|
outboundMegolmSessionDb_.put(txn, room_id, j.dump());
|
||||||
|
@ -532,7 +534,7 @@ Cache::saveOutboundMegolmSession(const std::string &room_id,
|
||||||
mtx::crypto::OutboundGroupSessionPtr &session)
|
mtx::crypto::OutboundGroupSessionPtr &session)
|
||||||
{
|
{
|
||||||
using namespace mtx::crypto;
|
using namespace mtx::crypto;
|
||||||
const auto pickled = pickle<OutboundSessionObject>(session.get(), SECRET);
|
const auto pickled = pickle<OutboundSessionObject>(session.get(), pickle_secret_);
|
||||||
|
|
||||||
GroupSessionData data = data_;
|
GroupSessionData data = data_;
|
||||||
data.message_index = olm_outbound_group_session_message_index(session.get());
|
data.message_index = olm_outbound_group_session_message_index(session.get());
|
||||||
|
@ -575,7 +577,7 @@ Cache::getOutboundMegolmSession(const std::string &room_id)
|
||||||
auto obj = json::parse(value);
|
auto obj = json::parse(value);
|
||||||
|
|
||||||
OutboundGroupSessionDataRef ref{};
|
OutboundGroupSessionDataRef ref{};
|
||||||
ref.session = unpickle<OutboundSessionObject>(obj.at("session"), SECRET);
|
ref.session = unpickle<OutboundSessionObject>(obj.at("session"), pickle_secret_);
|
||||||
|
|
||||||
MegolmSessionIndex index;
|
MegolmSessionIndex index;
|
||||||
index.room_id = room_id;
|
index.room_id = room_id;
|
||||||
|
@ -626,7 +628,7 @@ Cache::saveOlmSession(const std::string &curve25519,
|
||||||
auto txn = lmdb::txn::begin(env_);
|
auto txn = lmdb::txn::begin(env_);
|
||||||
auto db = getOlmSessionsDb(txn, curve25519);
|
auto db = getOlmSessionsDb(txn, curve25519);
|
||||||
|
|
||||||
const auto pickled = pickle<SessionObject>(session.get(), SECRET);
|
const auto pickled = pickle<SessionObject>(session.get(), pickle_secret_);
|
||||||
const auto session_id = mtx::crypto::session_id(session.get());
|
const auto session_id = mtx::crypto::session_id(session.get());
|
||||||
|
|
||||||
StoredOlmSession stored_session;
|
StoredOlmSession stored_session;
|
||||||
|
@ -653,7 +655,7 @@ Cache::getOlmSession(const std::string &curve25519, const std::string &session_i
|
||||||
|
|
||||||
if (found) {
|
if (found) {
|
||||||
auto data = json::parse(pickled).get<StoredOlmSession>();
|
auto data = json::parse(pickled).get<StoredOlmSession>();
|
||||||
return unpickle<SessionObject>(data.pickled_session, SECRET);
|
return unpickle<SessionObject>(data.pickled_session, pickle_secret_);
|
||||||
}
|
}
|
||||||
|
|
||||||
return std::nullopt;
|
return std::nullopt;
|
||||||
|
@ -681,8 +683,8 @@ Cache::getLatestOlmSession(const std::string &curve25519)
|
||||||
|
|
||||||
txn.commit();
|
txn.commit();
|
||||||
|
|
||||||
return currentNewest
|
return currentNewest ? std::optional(unpickle<SessionObject>(currentNewest->pickled_session,
|
||||||
? std::optional(unpickle<SessionObject>(currentNewest->pickled_session, SECRET))
|
pickle_secret_))
|
||||||
: std::nullopt;
|
: std::nullopt;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -719,6 +721,7 @@ std::string
|
||||||
Cache::restoreOlmAccount()
|
Cache::restoreOlmAccount()
|
||||||
{
|
{
|
||||||
auto txn = ro_txn(env_);
|
auto txn = ro_txn(env_);
|
||||||
|
|
||||||
std::string_view pickled;
|
std::string_view pickled;
|
||||||
syncStateDb_.get(txn, OLM_ACCOUNT_KEY, pickled);
|
syncStateDb_.get(txn, OLM_ACCOUNT_KEY, pickled);
|
||||||
|
|
||||||
|
@ -774,7 +777,7 @@ fatalSecretError()
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
Cache::storeSecret(const std::string name, const std::string secret)
|
Cache::storeSecret(const std::string name, const std::string secret, bool internal)
|
||||||
{
|
{
|
||||||
auto settings = UserSettings::instance();
|
auto settings = UserSettings::instance();
|
||||||
auto job = new QKeychain::WritePasswordJob(QCoreApplication::applicationName());
|
auto job = new QKeychain::WritePasswordJob(QCoreApplication::applicationName());
|
||||||
|
@ -783,7 +786,7 @@ Cache::storeSecret(const std::string name, const std::string secret)
|
||||||
job->setSettings(UserSettings::instance()->qsettings());
|
job->setSettings(UserSettings::instance()->qsettings());
|
||||||
|
|
||||||
job->setKey(
|
job->setKey(
|
||||||
"matrix." +
|
(internal ? "nheko." : "matrix.") +
|
||||||
QString(QCryptographicHash::hash(settings->profile().toUtf8(), QCryptographicHash::Sha256)
|
QString(QCryptographicHash::hash(settings->profile().toUtf8(), QCryptographicHash::Sha256)
|
||||||
.toBase64()) +
|
.toBase64()) +
|
||||||
"." + QString::fromStdString(name));
|
"." + QString::fromStdString(name));
|
||||||
|
@ -812,7 +815,7 @@ Cache::storeSecret(const std::string name, const std::string secret)
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
Cache::deleteSecret(const std::string name)
|
Cache::deleteSecret(const std::string name, bool internal)
|
||||||
{
|
{
|
||||||
auto settings = UserSettings::instance();
|
auto settings = UserSettings::instance();
|
||||||
QKeychain::DeletePasswordJob job(QCoreApplication::applicationName());
|
QKeychain::DeletePasswordJob job(QCoreApplication::applicationName());
|
||||||
|
@ -821,7 +824,7 @@ Cache::deleteSecret(const std::string name)
|
||||||
job.setSettings(UserSettings::instance()->qsettings());
|
job.setSettings(UserSettings::instance()->qsettings());
|
||||||
|
|
||||||
job.setKey(
|
job.setKey(
|
||||||
"matrix." +
|
(internal ? "nheko." : "matrix.") +
|
||||||
QString(QCryptographicHash::hash(settings->profile().toUtf8(), QCryptographicHash::Sha256)
|
QString(QCryptographicHash::hash(settings->profile().toUtf8(), QCryptographicHash::Sha256)
|
||||||
.toBase64()) +
|
.toBase64()) +
|
||||||
"." + QString::fromStdString(name));
|
"." + QString::fromStdString(name));
|
||||||
|
@ -837,7 +840,7 @@ Cache::deleteSecret(const std::string name)
|
||||||
}
|
}
|
||||||
|
|
||||||
std::optional<std::string>
|
std::optional<std::string>
|
||||||
Cache::secret(const std::string name)
|
Cache::secret(const std::string name, bool internal)
|
||||||
{
|
{
|
||||||
auto settings = UserSettings::instance();
|
auto settings = UserSettings::instance();
|
||||||
QKeychain::ReadPasswordJob job(QCoreApplication::applicationName());
|
QKeychain::ReadPasswordJob job(QCoreApplication::applicationName());
|
||||||
|
@ -846,7 +849,7 @@ Cache::secret(const std::string name)
|
||||||
job.setSettings(UserSettings::instance()->qsettings());
|
job.setSettings(UserSettings::instance()->qsettings());
|
||||||
|
|
||||||
job.setKey(
|
job.setKey(
|
||||||
"matrix." +
|
(internal ? "nheko." : "matrix.") +
|
||||||
QString(QCryptographicHash::hash(settings->profile().toUtf8(), QCryptographicHash::Sha256)
|
QString(QCryptographicHash::hash(settings->profile().toUtf8(), QCryptographicHash::Sha256)
|
||||||
.toBase64()) +
|
.toBase64()) +
|
||||||
"." + QString::fromStdString(name));
|
"." + QString::fromStdString(name));
|
||||||
|
@ -878,6 +881,22 @@ Cache::secret(const std::string name)
|
||||||
return secret.toStdString();
|
return secret.toStdString();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
std::string
|
||||||
|
Cache::pickleSecret()
|
||||||
|
{
|
||||||
|
if (pickle_secret_.empty()) {
|
||||||
|
auto s = secret("pickle_secret", true);
|
||||||
|
if (!s) {
|
||||||
|
this->pickle_secret_ = mtx::client::utils::random_token(64, true);
|
||||||
|
storeSecret("pickle_secret", pickle_secret_, true);
|
||||||
|
} else {
|
||||||
|
this->pickle_secret_ = *s;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return pickle_secret_;
|
||||||
|
};
|
||||||
|
|
||||||
void
|
void
|
||||||
Cache::removeInvite(lmdb::txn &txn, const std::string &room_id)
|
Cache::removeInvite(lmdb::txn &txn, const std::string &room_id)
|
||||||
{
|
{
|
||||||
|
@ -979,6 +998,7 @@ Cache::deleteData()
|
||||||
deleteSecret(mtx::secret_storage::secrets::cross_signing_master);
|
deleteSecret(mtx::secret_storage::secrets::cross_signing_master);
|
||||||
deleteSecret(mtx::secret_storage::secrets::cross_signing_user_signing);
|
deleteSecret(mtx::secret_storage::secrets::cross_signing_user_signing);
|
||||||
deleteSecret(mtx::secret_storage::secrets::cross_signing_self_signing);
|
deleteSecret(mtx::secret_storage::secrets::cross_signing_self_signing);
|
||||||
|
deleteSecret("pickle_secret", true);
|
||||||
}
|
}
|
||||||
|
|
||||||
//! migrates db to the current format
|
//! migrates db to the current format
|
||||||
|
@ -1202,6 +1222,11 @@ Cache::runMigrations()
|
||||||
"Successfully cleared the cache. Will do a clean sync after startup.");
|
"Successfully cleared the cache. Will do a clean sync after startup.");
|
||||||
return true;
|
return true;
|
||||||
}},
|
}},
|
||||||
|
{"2021.08.31",
|
||||||
|
[this]() {
|
||||||
|
storeSecret("pickle_secret", "secret", true);
|
||||||
|
return true;
|
||||||
|
}},
|
||||||
};
|
};
|
||||||
|
|
||||||
nhlog::db()->info("Running migrations, this may take a while!");
|
nhlog::db()->info("Running migrations, this may take a while!");
|
||||||
|
|
|
@ -291,9 +291,11 @@ public:
|
||||||
void deleteBackupVersion();
|
void deleteBackupVersion();
|
||||||
std::optional<OnlineBackupVersion> backupVersion();
|
std::optional<OnlineBackupVersion> backupVersion();
|
||||||
|
|
||||||
void storeSecret(const std::string name, const std::string secret);
|
void storeSecret(const std::string name, const std::string secret, bool internal = false);
|
||||||
void deleteSecret(const std::string name);
|
void deleteSecret(const std::string name, bool internal = false);
|
||||||
std::optional<std::string> secret(const std::string name);
|
std::optional<std::string> secret(const std::string name, bool internal = false);
|
||||||
|
|
||||||
|
std::string pickleSecret();
|
||||||
|
|
||||||
template<class T>
|
template<class T>
|
||||||
constexpr static bool isStateEvent_ =
|
constexpr static bool isStateEvent_ =
|
||||||
|
@ -713,6 +715,8 @@ private:
|
||||||
QString localUserId_;
|
QString localUserId_;
|
||||||
QString cacheDirectory_;
|
QString cacheDirectory_;
|
||||||
|
|
||||||
|
std::string pickle_secret_;
|
||||||
|
|
||||||
VerificationStorage verification_storage;
|
VerificationStorage verification_storage;
|
||||||
|
|
||||||
bool databaseReady_ = false;
|
bool databaseReady_ = false;
|
||||||
|
|
|
@ -32,9 +32,6 @@
|
||||||
|
|
||||||
#include "blurhash.hpp"
|
#include "blurhash.hpp"
|
||||||
|
|
||||||
// TODO: Needs to be updated with an actual secret.
|
|
||||||
static const std::string STORAGE_SECRET_KEY("secret");
|
|
||||||
|
|
||||||
ChatPage *ChatPage::instance_ = nullptr;
|
ChatPage *ChatPage::instance_ = nullptr;
|
||||||
constexpr int CHECK_CONNECTIVITY_INTERVAL = 15'000;
|
constexpr int CHECK_CONNECTIVITY_INTERVAL = 15'000;
|
||||||
constexpr int RETRY_TIMEOUT = 5'000;
|
constexpr int RETRY_TIMEOUT = 5'000;
|
||||||
|
@ -372,7 +369,7 @@ ChatPage::bootstrap(QString userid, QString homeserver, QString token)
|
||||||
// There isn't a saved olm account to restore.
|
// There isn't a saved olm account to restore.
|
||||||
nhlog::crypto()->info("creating new olm account");
|
nhlog::crypto()->info("creating new olm account");
|
||||||
olm::client()->create_new_account();
|
olm::client()->create_new_account();
|
||||||
cache::saveOlmAccount(olm::client()->save(STORAGE_SECRET_KEY));
|
cache::saveOlmAccount(olm::client()->save(cache::client()->pickleSecret()));
|
||||||
} catch (const lmdb::error &e) {
|
} catch (const lmdb::error &e) {
|
||||||
nhlog::crypto()->critical("failed to save olm account {}", e.what());
|
nhlog::crypto()->critical("failed to save olm account {}", e.what());
|
||||||
emit dropToLoginPageCb(QString::fromStdString(e.what()));
|
emit dropToLoginPageCb(QString::fromStdString(e.what()));
|
||||||
|
@ -394,7 +391,7 @@ ChatPage::loadStateFromCache()
|
||||||
nhlog::db()->info("restoring state from cache");
|
nhlog::db()->info("restoring state from cache");
|
||||||
|
|
||||||
try {
|
try {
|
||||||
olm::client()->load(cache::restoreOlmAccount(), STORAGE_SECRET_KEY);
|
olm::client()->load(cache::restoreOlmAccount(), cache::client()->pickleSecret());
|
||||||
|
|
||||||
emit initializeEmptyViews();
|
emit initializeEmptyViews();
|
||||||
emit initializeMentions(cache::getTimelineMentions());
|
emit initializeMentions(cache::getTimelineMentions());
|
||||||
|
@ -411,6 +408,11 @@ ChatPage::loadStateFromCache()
|
||||||
return;
|
return;
|
||||||
} catch (const json::exception &e) {
|
} catch (const json::exception &e) {
|
||||||
nhlog::db()->critical("failed to parse cache data: {}", e.what());
|
nhlog::db()->critical("failed to parse cache data: {}", e.what());
|
||||||
|
emit dropToLoginPageCb(tr("Failed to restore save data. Please login again."));
|
||||||
|
return;
|
||||||
|
} catch (const std::exception &e) {
|
||||||
|
nhlog::db()->critical("failed to load cache data: {}", e.what());
|
||||||
|
emit dropToLoginPageCb(tr("Failed to restore save data. Please login again."));
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -27,7 +27,6 @@ auto client_ = std::make_unique<mtx::crypto::OlmClient>();
|
||||||
|
|
||||||
std::map<std::string, std::string> request_id_to_secret_name;
|
std::map<std::string, std::string> request_id_to_secret_name;
|
||||||
|
|
||||||
const std::string STORAGE_SECRET_KEY("secret");
|
|
||||||
constexpr auto MEGOLM_ALGO = "m.megolm.v1.aes-sha2";
|
constexpr auto MEGOLM_ALGO = "m.megolm.v1.aes-sha2";
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -483,7 +482,7 @@ handle_pre_key_olm_message(const std::string &sender,
|
||||||
|
|
||||||
// We also remove the one time key used to establish that
|
// We also remove the one time key used to establish that
|
||||||
// session so we'll have to update our copy of the account object.
|
// session so we'll have to update our copy of the account object.
|
||||||
cache::saveOlmAccount(olm::client()->save("secret"));
|
cache::saveOlmAccount(olm::client()->save(cache::client()->pickleSecret()));
|
||||||
} catch (const mtx::crypto::olm_exception &e) {
|
} catch (const mtx::crypto::olm_exception &e) {
|
||||||
nhlog::crypto()->critical(
|
nhlog::crypto()->critical(
|
||||||
"failed to create inbound session with {}: {}", sender, e.what());
|
"failed to create inbound session with {}: {}", sender, e.what());
|
||||||
|
@ -938,7 +937,7 @@ void
|
||||||
mark_keys_as_published()
|
mark_keys_as_published()
|
||||||
{
|
{
|
||||||
olm::client()->mark_keys_as_published();
|
olm::client()->mark_keys_as_published();
|
||||||
cache::saveOlmAccount(olm::client()->save(STORAGE_SECRET_KEY));
|
cache::saveOlmAccount(olm::client()->save(cache::client()->pickleSecret()));
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
|
|
Loading…
Reference in a new issue