mirror of
https://github.com/Nheko-Reborn/nheko.git
synced 2024-11-22 19:08:58 +03:00
Add self verification after login
This commit is contained in:
parent
7a9c69cbd0
commit
5688b2647e
9 changed files with 285 additions and 72 deletions
|
@ -93,6 +93,7 @@ Item {
|
||||||
columns: 2
|
columns: 2
|
||||||
rowSpacing: 0
|
rowSpacing: 0
|
||||||
columnSpacing: 0
|
columnSpacing: 0
|
||||||
|
z: 1
|
||||||
|
|
||||||
Label {
|
Label {
|
||||||
Layout.margins: Nheko.paddingMedium
|
Layout.margins: Nheko.paddingMedium
|
||||||
|
@ -220,15 +221,53 @@ Item {
|
||||||
MainWindowDialog {
|
MainWindowDialog {
|
||||||
id: verifyMasterKey
|
id: verifyMasterKey
|
||||||
|
|
||||||
onAccepted: SelfVerificationStatus.verifyMasterKey()
|
standardButtons: Dialog.Cancel
|
||||||
|
|
||||||
GridLayout {
|
GridLayout {
|
||||||
id: masterGrid
|
id: masterGrid
|
||||||
|
|
||||||
width: verifyMasterKey.useableWidth
|
width: verifyMasterKey.useableWidth
|
||||||
columns: 2
|
columns: 1
|
||||||
rowSpacing: 0
|
z: 1
|
||||||
columnSpacing: 0
|
|
||||||
|
Label {
|
||||||
|
Layout.margins: Nheko.paddingMedium
|
||||||
|
Layout.alignment: Qt.AlignHCenter
|
||||||
|
//Layout.columnSpan: 2
|
||||||
|
font.pointSize: fontMetrics.font.pointSize * 2
|
||||||
|
text: qsTr("Activate Encryption")
|
||||||
|
color: Nheko.colors.text
|
||||||
|
wrapMode: Text.Wrap
|
||||||
|
}
|
||||||
|
|
||||||
|
Label {
|
||||||
|
Layout.margins: Nheko.paddingMedium
|
||||||
|
Layout.alignment: Qt.AlignLeft
|
||||||
|
//Layout.columnSpan: 2
|
||||||
|
Layout.maximumWidth: grid.width - Nheko.paddingMedium * 2
|
||||||
|
text: qsTr("It seems like you have encryption already configured for this account. To be able to access your encrypted messages and make this device appear as trusted, you can either verify an existing device or (if you have one) enter your recovery passphrase. Please select one of the options below.\nIf you choose verify, you need to have the other device available. If you choose \"enter passphrase\", you will need your recovery key or passphrase. If you click cancel, you can choose to verify yourself at a later point.")
|
||||||
|
color: Nheko.colors.text
|
||||||
|
wrapMode: Text.Wrap
|
||||||
|
}
|
||||||
|
|
||||||
|
FlatButton {
|
||||||
|
Layout.alignment: Qt.AlignHCenter
|
||||||
|
text: qsTr("verify")
|
||||||
|
onClicked: {
|
||||||
|
console.log("AAAAA");
|
||||||
|
SelfVerificationStatus.verifyMasterKey();
|
||||||
|
verifyMasterKey.close();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
FlatButton {
|
||||||
|
visible: SelfVerificationStatus.hasSSSS
|
||||||
|
Layout.alignment: Qt.AlignHCenter
|
||||||
|
text: qsTr("enter passphrase")
|
||||||
|
onClicked: {
|
||||||
|
SelfVerificationStatus.verifyMasterKeyWithPassphrase()
|
||||||
|
verifyMasterKey.close();
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -237,8 +276,8 @@ Item {
|
||||||
console.log("STATUS CHANGED: " + SelfVerificationStatus.status);
|
console.log("STATUS CHANGED: " + SelfVerificationStatus.status);
|
||||||
if (SelfVerificationStatus.status == SelfVerificationStatus.NoMasterKey)
|
if (SelfVerificationStatus.status == SelfVerificationStatus.NoMasterKey)
|
||||||
bootstrapCrosssigning.open();
|
bootstrapCrosssigning.open();
|
||||||
// else if (SelfVerificationStatus.status == SelfVerificationStatus.UnverifiedMasterKey)
|
else if (SelfVerificationStatus.status == SelfVerificationStatus.UnverifiedMasterKey)
|
||||||
// verifyMasterKey.open();
|
verifyMasterKey.open();
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -1131,11 +1131,71 @@ ChatPage::decryptDownloadedSecrets(mtx::secret_storage::AesHmacSha2KeyDescriptio
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
auto deviceKeys = cache::client()->userKeys(http::client()->user_id().to_string());
|
||||||
|
mtx::requests::KeySignaturesUpload req;
|
||||||
|
|
||||||
for (const auto &[secretName, encryptedSecret] : secrets) {
|
for (const auto &[secretName, encryptedSecret] : secrets) {
|
||||||
auto decrypted = mtx::crypto::decrypt(encryptedSecret, *decryptionKey, secretName);
|
auto decrypted = mtx::crypto::decrypt(encryptedSecret, *decryptionKey, secretName);
|
||||||
if (!decrypted.empty())
|
if (!decrypted.empty()) {
|
||||||
cache::storeSecret(secretName, decrypted);
|
cache::storeSecret(secretName, decrypted);
|
||||||
|
|
||||||
|
if (deviceKeys &&
|
||||||
|
secretName == mtx::secret_storage::secrets::cross_signing_self_signing) {
|
||||||
|
auto myKey = deviceKeys->device_keys.at(http::client()->device_id());
|
||||||
|
if (myKey.user_id == http::client()->user_id().to_string() &&
|
||||||
|
myKey.device_id == http::client()->device_id() &&
|
||||||
|
myKey.keys["ed25519:" + http::client()->device_id()] ==
|
||||||
|
olm::client()->identity_keys().ed25519 &&
|
||||||
|
myKey.keys["curve25519:" + http::client()->device_id()] ==
|
||||||
|
olm::client()->identity_keys().curve25519) {
|
||||||
|
json j = myKey;
|
||||||
|
j.erase("signatures");
|
||||||
|
j.erase("unsigned");
|
||||||
|
|
||||||
|
auto ssk = mtx::crypto::PkSigning::from_seed(decrypted);
|
||||||
|
myKey.signatures[http::client()->user_id().to_string()]
|
||||||
|
["ed25519:" + ssk.public_key()] = ssk.sign(j.dump());
|
||||||
|
req.signatures[http::client()->user_id().to_string()]
|
||||||
|
[http::client()->device_id()] = myKey;
|
||||||
|
}
|
||||||
|
} else if (deviceKeys &&
|
||||||
|
secretName == mtx::secret_storage::secrets::cross_signing_master) {
|
||||||
|
auto mk = mtx::crypto::PkSigning::from_seed(decrypted);
|
||||||
|
|
||||||
|
if (deviceKeys->master_keys.user_id == http::client()->user_id().to_string() &&
|
||||||
|
deviceKeys->master_keys.keys["ed25519:" + mk.public_key()] == mk.public_key()) {
|
||||||
|
json j = deviceKeys->master_keys;
|
||||||
|
j.erase("signatures");
|
||||||
|
j.erase("unsigned");
|
||||||
|
mtx::crypto::CrossSigningKeys master_key = j;
|
||||||
|
master_key.signatures[http::client()->user_id().to_string()]
|
||||||
|
["ed25519:" + http::client()->device_id()] =
|
||||||
|
olm::client()->sign_message(j.dump());
|
||||||
|
req.signatures[http::client()->user_id().to_string()][mk.public_key()] =
|
||||||
|
master_key;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (!req.signatures.empty())
|
||||||
|
http::client()->keys_signatures_upload(
|
||||||
|
req, [](const mtx::responses::KeySignaturesUpload &res, mtx::http::RequestErr err) {
|
||||||
|
if (err) {
|
||||||
|
nhlog::net()->error("failed to upload signatures: {},{}",
|
||||||
|
mtx::errors::to_string(err->matrix_error.errcode),
|
||||||
|
static_cast<int>(err->status_code));
|
||||||
|
}
|
||||||
|
|
||||||
|
for (const auto &[user_id, tmp] : res.errors)
|
||||||
|
for (const auto &[key_id, e] : tmp)
|
||||||
|
nhlog::net()->error("signature error for user '{}' and key "
|
||||||
|
"id {}: {}, {}",
|
||||||
|
user_id,
|
||||||
|
key_id,
|
||||||
|
mtx::errors::to_string(e.errcode),
|
||||||
|
e.error);
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
|
|
|
@ -32,12 +32,15 @@ DeviceVerificationFlow::DeviceVerificationFlow(QObject *,
|
||||||
DeviceVerificationFlow::Type flow_type,
|
DeviceVerificationFlow::Type flow_type,
|
||||||
TimelineModel *model,
|
TimelineModel *model,
|
||||||
QString userID,
|
QString userID,
|
||||||
QString deviceId_)
|
std::vector<QString> deviceIds_)
|
||||||
: sender(false)
|
: sender(false)
|
||||||
, type(flow_type)
|
, type(flow_type)
|
||||||
, deviceId(deviceId_)
|
, deviceIds(std::move(deviceIds_))
|
||||||
, model_(model)
|
, model_(model)
|
||||||
{
|
{
|
||||||
|
if (deviceIds.size() == 1)
|
||||||
|
deviceId = deviceIds.front();
|
||||||
|
|
||||||
timeout = new QTimer(this);
|
timeout = new QTimer(this);
|
||||||
timeout->setSingleShot(true);
|
timeout->setSingleShot(true);
|
||||||
this->sas = olm::client()->sas_init();
|
this->sas = olm::client()->sas_init();
|
||||||
|
@ -346,33 +349,62 @@ DeviceVerificationFlow::DeviceVerificationFlow(QObject *,
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
connect(ChatPage::instance(),
|
connect(
|
||||||
&ChatPage::receivedDeviceVerificationReady,
|
ChatPage::instance(),
|
||||||
this,
|
&ChatPage::receivedDeviceVerificationReady,
|
||||||
[this](const mtx::events::msg::KeyVerificationReady &msg) {
|
this,
|
||||||
nhlog::crypto()->info("verification: received ready");
|
[this](const mtx::events::msg::KeyVerificationReady &msg) {
|
||||||
if (!sender) {
|
nhlog::crypto()->info("verification: received ready");
|
||||||
if (msg.from_device != http::client()->device_id()) {
|
if (!sender) {
|
||||||
error_ = User;
|
if (msg.from_device != http::client()->device_id()) {
|
||||||
emit errorChanged();
|
error_ = User;
|
||||||
setState(Failed);
|
emit errorChanged();
|
||||||
}
|
setState(Failed);
|
||||||
|
}
|
||||||
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (msg.transaction_id.has_value()) {
|
if (msg.transaction_id.has_value()) {
|
||||||
if (msg.transaction_id.value() != this->transaction_id)
|
if (msg.transaction_id.value() != this->transaction_id)
|
||||||
return;
|
return;
|
||||||
} else if (msg.relations.references()) {
|
|
||||||
if (msg.relations.references() != this->relation.event_id)
|
if (this->deviceId.isEmpty() && this->deviceIds.size() > 1) {
|
||||||
return;
|
auto from = QString::fromStdString(msg.from_device);
|
||||||
else {
|
if (std::find(deviceIds.begin(), deviceIds.end(), from) != deviceIds.end()) {
|
||||||
this->deviceId = QString::fromStdString(msg.from_device);
|
mtx::events::msg::KeyVerificationCancel req{};
|
||||||
}
|
req.code = "m.user";
|
||||||
}
|
req.reason = "accepted by other device";
|
||||||
this->startVerificationRequest();
|
req.transaction_id = this->transaction_id;
|
||||||
});
|
mtx::requests::ToDeviceMessages<mtx::events::msg::KeyVerificationCancel> body;
|
||||||
|
|
||||||
|
for (const auto &d : this->deviceIds) {
|
||||||
|
if (d != from)
|
||||||
|
body[this->toClient][d.toStdString()] = req;
|
||||||
|
}
|
||||||
|
|
||||||
|
http::client()->send_to_device(
|
||||||
|
http::client()->generate_txn_id(), body, [](mtx::http::RequestErr err) {
|
||||||
|
if (err)
|
||||||
|
nhlog::net()->warn(
|
||||||
|
"failed to send verification to_device message: {} {}",
|
||||||
|
err->matrix_error.error,
|
||||||
|
static_cast<int>(err->status_code));
|
||||||
|
});
|
||||||
|
|
||||||
|
this->deviceId = from;
|
||||||
|
this->deviceIds = {from};
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else if (msg.relations.references()) {
|
||||||
|
if (msg.relations.references() != this->relation.event_id)
|
||||||
|
return;
|
||||||
|
else {
|
||||||
|
this->deviceId = QString::fromStdString(msg.from_device);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
this->startVerificationRequest();
|
||||||
|
});
|
||||||
|
|
||||||
connect(ChatPage::instance(),
|
connect(ChatPage::instance(),
|
||||||
&ChatPage::receivedDeviceVerificationDone,
|
&ChatPage::receivedDeviceVerificationDone,
|
||||||
|
@ -782,7 +814,7 @@ DeviceVerificationFlow::NewInRoomVerification(QObject *parent_,
|
||||||
Type::RoomMsg,
|
Type::RoomMsg,
|
||||||
timelineModel_,
|
timelineModel_,
|
||||||
other_user_,
|
other_user_,
|
||||||
QString::fromStdString(msg.from_device)));
|
{QString::fromStdString(msg.from_device)}));
|
||||||
|
|
||||||
flow->setEventId(event_id_.toStdString());
|
flow->setEventId(event_id_.toStdString());
|
||||||
|
|
||||||
|
@ -801,7 +833,7 @@ DeviceVerificationFlow::NewToDeviceVerification(QObject *parent_,
|
||||||
QString txn_id_)
|
QString txn_id_)
|
||||||
{
|
{
|
||||||
QSharedPointer<DeviceVerificationFlow> flow(new DeviceVerificationFlow(
|
QSharedPointer<DeviceVerificationFlow> flow(new DeviceVerificationFlow(
|
||||||
parent_, Type::ToDevice, nullptr, other_user_, QString::fromStdString(msg.from_device)));
|
parent_, Type::ToDevice, nullptr, other_user_, {QString::fromStdString(msg.from_device)}));
|
||||||
flow->transaction_id = txn_id_.toStdString();
|
flow->transaction_id = txn_id_.toStdString();
|
||||||
|
|
||||||
if (std::find(msg.methods.begin(),
|
if (std::find(msg.methods.begin(),
|
||||||
|
@ -819,7 +851,7 @@ DeviceVerificationFlow::NewToDeviceVerification(QObject *parent_,
|
||||||
QString txn_id_)
|
QString txn_id_)
|
||||||
{
|
{
|
||||||
QSharedPointer<DeviceVerificationFlow> flow(new DeviceVerificationFlow(
|
QSharedPointer<DeviceVerificationFlow> flow(new DeviceVerificationFlow(
|
||||||
parent_, Type::ToDevice, nullptr, other_user_, QString::fromStdString(msg.from_device)));
|
parent_, Type::ToDevice, nullptr, other_user_, {QString::fromStdString(msg.from_device)}));
|
||||||
flow->transaction_id = txn_id_.toStdString();
|
flow->transaction_id = txn_id_.toStdString();
|
||||||
|
|
||||||
flow->handleStartMessage(msg, "");
|
flow->handleStartMessage(msg, "");
|
||||||
|
@ -832,15 +864,19 @@ DeviceVerificationFlow::InitiateUserVerification(QObject *parent_,
|
||||||
QString userid)
|
QString userid)
|
||||||
{
|
{
|
||||||
QSharedPointer<DeviceVerificationFlow> flow(
|
QSharedPointer<DeviceVerificationFlow> flow(
|
||||||
new DeviceVerificationFlow(parent_, Type::RoomMsg, timelineModel_, userid, ""));
|
new DeviceVerificationFlow(parent_, Type::RoomMsg, timelineModel_, userid, {}));
|
||||||
flow->sender = true;
|
flow->sender = true;
|
||||||
return flow;
|
return flow;
|
||||||
}
|
}
|
||||||
QSharedPointer<DeviceVerificationFlow>
|
QSharedPointer<DeviceVerificationFlow>
|
||||||
DeviceVerificationFlow::InitiateDeviceVerification(QObject *parent_, QString userid, QString device)
|
DeviceVerificationFlow::InitiateDeviceVerification(QObject *parent_,
|
||||||
|
QString userid,
|
||||||
|
std::vector<QString> devices)
|
||||||
{
|
{
|
||||||
|
assert(!devices.empty());
|
||||||
|
|
||||||
QSharedPointer<DeviceVerificationFlow> flow(
|
QSharedPointer<DeviceVerificationFlow> flow(
|
||||||
new DeviceVerificationFlow(parent_, Type::ToDevice, nullptr, userid, device));
|
new DeviceVerificationFlow(parent_, Type::ToDevice, nullptr, userid, devices));
|
||||||
|
|
||||||
flow->sender = true;
|
flow->sender = true;
|
||||||
flow->transaction_id = http::client()->generate_txn_id();
|
flow->transaction_id = http::client()->generate_txn_id();
|
||||||
|
|
|
@ -120,9 +120,8 @@ public:
|
||||||
QString txn_id_);
|
QString txn_id_);
|
||||||
static QSharedPointer<DeviceVerificationFlow>
|
static QSharedPointer<DeviceVerificationFlow>
|
||||||
InitiateUserVerification(QObject *parent_, TimelineModel *timelineModel_, QString userid);
|
InitiateUserVerification(QObject *parent_, TimelineModel *timelineModel_, QString userid);
|
||||||
static QSharedPointer<DeviceVerificationFlow> InitiateDeviceVerification(QObject *parent,
|
static QSharedPointer<DeviceVerificationFlow>
|
||||||
QString userid,
|
InitiateDeviceVerification(QObject *parent, QString userid, std::vector<QString> devices);
|
||||||
QString device);
|
|
||||||
|
|
||||||
// getters
|
// getters
|
||||||
QString state();
|
QString state();
|
||||||
|
@ -161,7 +160,7 @@ private:
|
||||||
DeviceVerificationFlow::Type flow_type,
|
DeviceVerificationFlow::Type flow_type,
|
||||||
TimelineModel *model,
|
TimelineModel *model,
|
||||||
QString userID,
|
QString userID,
|
||||||
QString deviceId_);
|
std::vector<QString> deviceIds_);
|
||||||
void setState(State state)
|
void setState(State state)
|
||||||
{
|
{
|
||||||
if (state != state_) {
|
if (state != state_) {
|
||||||
|
@ -196,6 +195,7 @@ private:
|
||||||
Type type;
|
Type type;
|
||||||
mtx::identifiers::User toClient;
|
mtx::identifiers::User toClient;
|
||||||
QString deviceId;
|
QString deviceId;
|
||||||
|
std::vector<QString> deviceIds;
|
||||||
|
|
||||||
// public part of our master key, when trusted or empty
|
// public part of our master key, when trusted or empty
|
||||||
std::string our_trusted_master_key;
|
std::string our_trusted_master_key;
|
||||||
|
@ -222,11 +222,12 @@ private:
|
||||||
{
|
{
|
||||||
if (this->type == DeviceVerificationFlow::Type::ToDevice) {
|
if (this->type == DeviceVerificationFlow::Type::ToDevice) {
|
||||||
mtx::requests::ToDeviceMessages<T> body;
|
mtx::requests::ToDeviceMessages<T> body;
|
||||||
msg.transaction_id = this->transaction_id;
|
msg.transaction_id = this->transaction_id;
|
||||||
body[this->toClient][deviceId.toStdString()] = msg;
|
for (const auto &d : deviceIds)
|
||||||
|
body[this->toClient][d.toStdString()] = msg;
|
||||||
|
|
||||||
http::client()->send_to_device<T>(
|
http::client()->send_to_device<T>(
|
||||||
this->transaction_id, body, [](mtx::http::RequestErr err) {
|
http::client()->generate_txn_id(), body, [](mtx::http::RequestErr err) {
|
||||||
if (err)
|
if (err)
|
||||||
nhlog::net()->warn("failed to send verification to_device message: {} {}",
|
nhlog::net()->warn("failed to send verification to_device message: {} {}",
|
||||||
err->matrix_error.error,
|
err->matrix_error.error,
|
||||||
|
|
|
@ -1540,6 +1540,7 @@ request_cross_signing_keys()
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
|
request(mtx::secret_storage::secrets::cross_signing_master);
|
||||||
request(mtx::secret_storage::secrets::cross_signing_self_signing);
|
request(mtx::secret_storage::secrets::cross_signing_self_signing);
|
||||||
request(mtx::secret_storage::secrets::cross_signing_user_signing);
|
request(mtx::secret_storage::secrets::cross_signing_user_signing);
|
||||||
request(mtx::secret_storage::secrets::megolm_backup_v1);
|
request(mtx::secret_storage::secrets::megolm_backup_v1);
|
||||||
|
@ -1574,36 +1575,52 @@ download_cross_signing_keys()
|
||||||
backup_key = secret;
|
backup_key = secret;
|
||||||
|
|
||||||
http::client()->secret_storage_secret(
|
http::client()->secret_storage_secret(
|
||||||
secrets::cross_signing_self_signing,
|
secrets::cross_signing_master, [backup_key](Secret secret, mtx::http::RequestErr err) {
|
||||||
[backup_key](Secret secret, mtx::http::RequestErr err) {
|
std::optional<Secret> master_key;
|
||||||
std::optional<Secret> self_signing_key;
|
|
||||||
if (!err)
|
if (!err)
|
||||||
self_signing_key = secret;
|
master_key = secret;
|
||||||
|
|
||||||
http::client()->secret_storage_secret(
|
http::client()->secret_storage_secret(
|
||||||
secrets::cross_signing_user_signing,
|
secrets::cross_signing_self_signing,
|
||||||
[backup_key, self_signing_key](Secret secret, mtx::http::RequestErr err) {
|
[backup_key, master_key](Secret secret, mtx::http::RequestErr err) {
|
||||||
std::optional<Secret> user_signing_key;
|
std::optional<Secret> self_signing_key;
|
||||||
if (!err)
|
if (!err)
|
||||||
user_signing_key = secret;
|
self_signing_key = secret;
|
||||||
|
|
||||||
std::map<std::string, std::map<std::string, AesHmacSha2EncryptedData>>
|
http::client()->secret_storage_secret(
|
||||||
secrets;
|
secrets::cross_signing_user_signing,
|
||||||
|
[backup_key, self_signing_key, master_key](Secret secret,
|
||||||
|
mtx::http::RequestErr err) {
|
||||||
|
std::optional<Secret> user_signing_key;
|
||||||
|
if (!err)
|
||||||
|
user_signing_key = secret;
|
||||||
|
|
||||||
if (backup_key && !backup_key->encrypted.empty())
|
std::map<std::string, std::map<std::string, AesHmacSha2EncryptedData>>
|
||||||
secrets[backup_key->encrypted.begin()->first][secrets::megolm_backup_v1] =
|
secrets;
|
||||||
backup_key->encrypted.begin()->second;
|
|
||||||
if (self_signing_key && !self_signing_key->encrypted.empty())
|
|
||||||
secrets[self_signing_key->encrypted.begin()->first]
|
|
||||||
[secrets::cross_signing_self_signing] =
|
|
||||||
self_signing_key->encrypted.begin()->second;
|
|
||||||
if (user_signing_key && !user_signing_key->encrypted.empty())
|
|
||||||
secrets[user_signing_key->encrypted.begin()->first]
|
|
||||||
[secrets::cross_signing_user_signing] =
|
|
||||||
user_signing_key->encrypted.begin()->second;
|
|
||||||
|
|
||||||
for (const auto &[key, secrets] : secrets)
|
if (backup_key && !backup_key->encrypted.empty())
|
||||||
unlock_secrets(key, secrets);
|
secrets[backup_key->encrypted.begin()->first]
|
||||||
|
[secrets::megolm_backup_v1] =
|
||||||
|
backup_key->encrypted.begin()->second;
|
||||||
|
|
||||||
|
if (master_key && !master_key->encrypted.empty())
|
||||||
|
secrets[master_key->encrypted.begin()->first]
|
||||||
|
[secrets::cross_signing_master] =
|
||||||
|
master_key->encrypted.begin()->second;
|
||||||
|
|
||||||
|
if (self_signing_key && !self_signing_key->encrypted.empty())
|
||||||
|
secrets[self_signing_key->encrypted.begin()->first]
|
||||||
|
[secrets::cross_signing_self_signing] =
|
||||||
|
self_signing_key->encrypted.begin()->second;
|
||||||
|
|
||||||
|
if (user_signing_key && !user_signing_key->encrypted.empty())
|
||||||
|
secrets[user_signing_key->encrypted.begin()->first]
|
||||||
|
[secrets::cross_signing_user_signing] =
|
||||||
|
user_signing_key->encrypted.begin()->second;
|
||||||
|
|
||||||
|
for (const auto &[key, secrets] : secrets)
|
||||||
|
unlock_secrets(key, secrets);
|
||||||
|
});
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
|
@ -5,10 +5,12 @@
|
||||||
#include "SelfVerificationStatus.h"
|
#include "SelfVerificationStatus.h"
|
||||||
|
|
||||||
#include "Cache_p.h"
|
#include "Cache_p.h"
|
||||||
|
#include "ChatPage.h"
|
||||||
#include "Logging.h"
|
#include "Logging.h"
|
||||||
#include "MainWindow.h"
|
#include "MainWindow.h"
|
||||||
#include "MatrixClient.h"
|
#include "MatrixClient.h"
|
||||||
#include "Olm.h"
|
#include "Olm.h"
|
||||||
|
#include "timeline/TimelineViewManager.h"
|
||||||
#include "ui/UIA.h"
|
#include "ui/UIA.h"
|
||||||
|
|
||||||
#include <mtx/responses/common.hpp>
|
#include <mtx/responses/common.hpp>
|
||||||
|
@ -196,6 +198,35 @@ void
|
||||||
SelfVerificationStatus::verifyMasterKey()
|
SelfVerificationStatus::verifyMasterKey()
|
||||||
{
|
{
|
||||||
nhlog::db()->info("Clicked verify master key");
|
nhlog::db()->info("Clicked verify master key");
|
||||||
|
|
||||||
|
const auto this_user = http::client()->user_id().to_string();
|
||||||
|
|
||||||
|
auto keys = cache::client()->userKeys(this_user);
|
||||||
|
const auto &sigs = keys->master_keys.signatures[this_user];
|
||||||
|
|
||||||
|
std::vector<QString> devices;
|
||||||
|
for (const auto &[dev, sig] : sigs) {
|
||||||
|
(void)sig;
|
||||||
|
|
||||||
|
auto d = QString::fromStdString(dev);
|
||||||
|
if (d.startsWith("ed25519:")) {
|
||||||
|
d.remove("ed25519:");
|
||||||
|
|
||||||
|
if (keys->device_keys.count(d.toStdString()))
|
||||||
|
devices.push_back(std::move(d));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!devices.empty())
|
||||||
|
ChatPage::instance()->timelineManager()->verificationManager()->verifyOneOfDevices(
|
||||||
|
QString::fromStdString(this_user), std::move(devices));
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
SelfVerificationStatus::verifyMasterKeyWithPassphrase()
|
||||||
|
{
|
||||||
|
nhlog::db()->info("Clicked verify master key with passphrase");
|
||||||
|
olm::download_cross_signing_keys();
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
|
@ -207,9 +238,15 @@ SelfVerificationStatus::verifyUnverifiedDevices()
|
||||||
void
|
void
|
||||||
SelfVerificationStatus::invalidate()
|
SelfVerificationStatus::invalidate()
|
||||||
{
|
{
|
||||||
|
using namespace mtx::secret_storage;
|
||||||
|
|
||||||
nhlog::db()->info("Invalidating self verification status");
|
nhlog::db()->info("Invalidating self verification status");
|
||||||
|
this->hasSSSS_ = false;
|
||||||
|
emit hasSSSSChanged();
|
||||||
|
|
||||||
auto keys = cache::client()->userKeys(http::client()->user_id().to_string());
|
auto keys = cache::client()->userKeys(http::client()->user_id().to_string());
|
||||||
if (!keys) {
|
if (!keys || keys->device_keys.find(http::client()->device_id()) == keys->device_keys.end()) {
|
||||||
|
cache::client()->markUserKeysOutOfDate({http::client()->user_id().to_string()});
|
||||||
cache::client()->query_keys(http::client()->user_id().to_string(),
|
cache::client()->query_keys(http::client()->user_id().to_string(),
|
||||||
[](const UserKeyCache &, mtx::http::RequestErr) {});
|
[](const UserKeyCache &, mtx::http::RequestErr) {});
|
||||||
return;
|
return;
|
||||||
|
@ -223,6 +260,14 @@ SelfVerificationStatus::invalidate()
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
http::client()->secret_storage_secret(secrets::cross_signing_self_signing,
|
||||||
|
[this](Secret secret, mtx::http::RequestErr err) {
|
||||||
|
if (!err && !secret.encrypted.empty()) {
|
||||||
|
this->hasSSSS_ = true;
|
||||||
|
emit hasSSSSChanged();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
auto verifStatus = cache::client()->verificationStatus(http::client()->user_id().to_string());
|
auto verifStatus = cache::client()->verificationStatus(http::client()->user_id().to_string());
|
||||||
|
|
||||||
if (!verifStatus.user_verified) {
|
if (!verifStatus.user_verified) {
|
||||||
|
|
|
@ -11,6 +11,7 @@ class SelfVerificationStatus : public QObject
|
||||||
Q_OBJECT
|
Q_OBJECT
|
||||||
|
|
||||||
Q_PROPERTY(Status status READ status NOTIFY statusChanged)
|
Q_PROPERTY(Status status READ status NOTIFY statusChanged)
|
||||||
|
Q_PROPERTY(bool hasSSSS READ hasSSSS NOTIFY hasSSSSChanged)
|
||||||
|
|
||||||
public:
|
public:
|
||||||
SelfVerificationStatus(QObject *o = nullptr);
|
SelfVerificationStatus(QObject *o = nullptr);
|
||||||
|
@ -25,12 +26,15 @@ public:
|
||||||
|
|
||||||
Q_INVOKABLE void setupCrosssigning(bool useSSSS, QString password, bool useOnlineKeyBackup);
|
Q_INVOKABLE void setupCrosssigning(bool useSSSS, QString password, bool useOnlineKeyBackup);
|
||||||
Q_INVOKABLE void verifyMasterKey();
|
Q_INVOKABLE void verifyMasterKey();
|
||||||
|
Q_INVOKABLE void verifyMasterKeyWithPassphrase();
|
||||||
Q_INVOKABLE void verifyUnverifiedDevices();
|
Q_INVOKABLE void verifyUnverifiedDevices();
|
||||||
|
|
||||||
Status status() const { return status_; }
|
Status status() const { return status_; }
|
||||||
|
bool hasSSSS() const { return hasSSSS_; }
|
||||||
|
|
||||||
signals:
|
signals:
|
||||||
void statusChanged();
|
void statusChanged();
|
||||||
|
void hasSSSSChanged();
|
||||||
void setupCompleted();
|
void setupCompleted();
|
||||||
void showRecoveryKey(QString key);
|
void showRecoveryKey(QString key);
|
||||||
void setupFailed(QString message);
|
void setupFailed(QString message);
|
||||||
|
@ -40,4 +44,5 @@ public slots:
|
||||||
|
|
||||||
private:
|
private:
|
||||||
Status status_ = AllVerified;
|
Status status_ = AllVerified;
|
||||||
|
bool hasSSSS_ = true;
|
||||||
};
|
};
|
||||||
|
|
|
@ -120,7 +120,16 @@ VerificationManager::removeVerificationFlow(DeviceVerificationFlow *flow)
|
||||||
void
|
void
|
||||||
VerificationManager::verifyDevice(QString userid, QString deviceid)
|
VerificationManager::verifyDevice(QString userid, QString deviceid)
|
||||||
{
|
{
|
||||||
auto flow = DeviceVerificationFlow::InitiateDeviceVerification(this, userid, deviceid);
|
auto flow = DeviceVerificationFlow::InitiateDeviceVerification(this, userid, {deviceid});
|
||||||
|
this->dvList[flow->transactionId()] = flow;
|
||||||
|
emit newDeviceVerificationRequest(flow.data());
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
VerificationManager::verifyOneOfDevices(QString userid, std::vector<QString> deviceids)
|
||||||
|
{
|
||||||
|
auto flow =
|
||||||
|
DeviceVerificationFlow::InitiateDeviceVerification(this, userid, std::move(deviceids));
|
||||||
this->dvList[flow->transactionId()] = flow;
|
this->dvList[flow->transactionId()] = flow;
|
||||||
emit newDeviceVerificationRequest(flow.data());
|
emit newDeviceVerificationRequest(flow.data());
|
||||||
}
|
}
|
||||||
|
|
|
@ -27,6 +27,7 @@ public:
|
||||||
Q_INVOKABLE void removeVerificationFlow(DeviceVerificationFlow *flow);
|
Q_INVOKABLE void removeVerificationFlow(DeviceVerificationFlow *flow);
|
||||||
void verifyUser(QString userid);
|
void verifyUser(QString userid);
|
||||||
void verifyDevice(QString userid, QString deviceid);
|
void verifyDevice(QString userid, QString deviceid);
|
||||||
|
void verifyOneOfDevices(QString userid, std::vector<QString> deviceids);
|
||||||
|
|
||||||
signals:
|
signals:
|
||||||
void newDeviceVerificationRequest(DeviceVerificationFlow *flow);
|
void newDeviceVerificationRequest(DeviceVerificationFlow *flow);
|
||||||
|
|
Loading…
Reference in a new issue