mirror of
https://github.com/Nheko-Reborn/nheko.git
synced 2024-11-22 19:08:58 +03:00
Prompt user when there are unverified devices
This commit is contained in:
parent
5bd6208c43
commit
2aabe9dcac
9 changed files with 120 additions and 10 deletions
|
@ -502,6 +502,86 @@ Page {
|
||||||
Layout.fillWidth: true
|
Layout.fillWidth: true
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Rectangle {
|
||||||
|
id: unverifiedStuffBubble
|
||||||
|
color: Qt.lighter(Nheko.theme.orange, verifyButtonHovered.hovered ? 1.2 : 1.0)
|
||||||
|
Layout.fillWidth: true
|
||||||
|
implicitHeight: explanation.height + Nheko.paddingMedium * 2
|
||||||
|
visible: SelfVerificationStatus.status != SelfVerificationStatus.AllVerified
|
||||||
|
|
||||||
|
RowLayout {
|
||||||
|
id: unverifiedStuffBubbleContainer
|
||||||
|
width: parent.width
|
||||||
|
height: explanation.height + Nheko.paddingMedium * 2
|
||||||
|
spacing: 0
|
||||||
|
|
||||||
|
Label {
|
||||||
|
id: explanation
|
||||||
|
Layout.margins: Nheko.paddingMedium
|
||||||
|
Layout.rightMargin: Nheko.paddingSmall
|
||||||
|
color: Nheko.colors.buttonText
|
||||||
|
Layout.fillWidth: true
|
||||||
|
text: switch(SelfVerificationStatus.status) {
|
||||||
|
case SelfVerificationStatus.NoMasterKey:
|
||||||
|
//: Cross-signing setup has not run yet.
|
||||||
|
return qsTr("Encryption not set up");
|
||||||
|
case SelfVerificationStatus.UnverifiedMasterKey:
|
||||||
|
//: The user just signed in with this device and hasn't verified their master key.
|
||||||
|
return qsTr("Unverified login");
|
||||||
|
case SelfVerificationStatus.UnverifiedDevices:
|
||||||
|
//: There are unverified devices signed in to this account.
|
||||||
|
return qsTr("Please verify your other devices");
|
||||||
|
default:
|
||||||
|
return ""
|
||||||
|
}
|
||||||
|
textFormat: Text.PlainText
|
||||||
|
wrapMode: Text.Wrap
|
||||||
|
}
|
||||||
|
|
||||||
|
ImageButton {
|
||||||
|
id: closeUnverifiedBubble
|
||||||
|
|
||||||
|
Layout.rightMargin: Nheko.paddingMedium
|
||||||
|
Layout.topMargin: Nheko.paddingMedium
|
||||||
|
Layout.alignment: Qt.AlignRight | Qt.AlignTop
|
||||||
|
hoverEnabled: true
|
||||||
|
width: fontMetrics.font.pixelSize
|
||||||
|
height: fontMetrics.font.pixelSize
|
||||||
|
image: ":/icons/icons/ui/remove-symbol.png"
|
||||||
|
ToolTip.visible: closeUnverifiedBubble.hovered
|
||||||
|
ToolTip.text: qsTr("Close")
|
||||||
|
onClicked: unverifiedStuffBubble.visible = false
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
HoverHandler {
|
||||||
|
id: verifyButtonHovered
|
||||||
|
enabled: !closeUnverifiedBubble.hovered
|
||||||
|
|
||||||
|
acceptedDevices: PointerDevice.Mouse | PointerDevice.Stylus | PointerDevice.TouchPad
|
||||||
|
}
|
||||||
|
|
||||||
|
TapHandler {
|
||||||
|
enabled: !closeUnverifiedBubble.hovered
|
||||||
|
acceptedButtons: Qt.LeftButton
|
||||||
|
onSingleTapped: {
|
||||||
|
if (SelfVerificationStatus.status == SelfVerificationStatus.UnverifiedDevices) {
|
||||||
|
SelfVerificationStatus.verifyUnverifiedDevices();
|
||||||
|
} else {
|
||||||
|
SelfVerificationStatus.statusChanged();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Rectangle {
|
||||||
|
color: Nheko.theme.separator
|
||||||
|
height: 1
|
||||||
|
Layout.fillWidth: true
|
||||||
|
visible: unverifiedStuffBubble.visible
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
footer: ColumnLayout {
|
footer: ColumnLayout {
|
||||||
|
|
|
@ -277,6 +277,10 @@ Item {
|
||||||
bootstrapCrosssigning.open();
|
bootstrapCrosssigning.open();
|
||||||
else if (SelfVerificationStatus.status == SelfVerificationStatus.UnverifiedMasterKey)
|
else if (SelfVerificationStatus.status == SelfVerificationStatus.UnverifiedMasterKey)
|
||||||
verifyMasterKey.open();
|
verifyMasterKey.open();
|
||||||
|
else {
|
||||||
|
bootstrapCrosssigning.close();
|
||||||
|
verifyMasterKey.close();
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -23,6 +23,9 @@ Pane {
|
||||||
text: {
|
text: {
|
||||||
if (flow.sender) {
|
if (flow.sender) {
|
||||||
if (flow.isSelfVerification)
|
if (flow.isSelfVerification)
|
||||||
|
if (flow.isMultiDeviceVerification)
|
||||||
|
return qsTr("To allow other users to see, which of your devices actually belong to you, you can verify them. This also allows key backup to work automatically. Verify an unverified device now? (Please make sure you have one of those devices available.)");
|
||||||
|
else
|
||||||
return qsTr("To allow other users to see, which of your devices actually belong to you, you can verify them. This also allows key backup to work automatically. Verify %1 now?").arg(flow.deviceId);
|
return qsTr("To allow other users to see, which of your devices actually belong to you, you can verify them. This also allows key backup to work automatically. Verify %1 now?").arg(flow.deviceId);
|
||||||
else
|
else
|
||||||
return qsTr("To ensure that no malicious user can eavesdrop on your encrypted communications you can verify the other party.");
|
return qsTr("To ensure that no malicious user can eavesdrop on your encrypted communications you can verify the other party.");
|
||||||
|
|
|
@ -208,8 +208,7 @@ Cache::Cache(const QString &userId, QObject *parent)
|
||||||
[this](const std::string &u) {
|
[this](const std::string &u) {
|
||||||
if (u == localUserId_.toStdString()) {
|
if (u == localUserId_.toStdString()) {
|
||||||
auto status = verificationStatus(u);
|
auto status = verificationStatus(u);
|
||||||
if (status.unverified_device_count || !status.user_verified)
|
emit selfVerificationStatusChanged();
|
||||||
emit selfUnverified();
|
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
Qt::QueuedConnection);
|
Qt::QueuedConnection);
|
||||||
|
@ -4265,6 +4264,7 @@ Cache::markDeviceVerified(const std::string &user_id, const std::string &key)
|
||||||
std::unique_lock<std::mutex> lock(verification_storage.verification_storage_mtx);
|
std::unique_lock<std::mutex> lock(verification_storage.verification_storage_mtx);
|
||||||
if (user_id == local_user) {
|
if (user_id == local_user) {
|
||||||
std::swap(tmp, verification_storage.status);
|
std::swap(tmp, verification_storage.status);
|
||||||
|
verification_storage.status.clear();
|
||||||
} else {
|
} else {
|
||||||
verification_storage.status.erase(user_id);
|
verification_storage.status.erase(user_id);
|
||||||
}
|
}
|
||||||
|
@ -4274,9 +4274,8 @@ Cache::markDeviceVerified(const std::string &user_id, const std::string &key)
|
||||||
(void)status;
|
(void)status;
|
||||||
emit verificationStatusChanged(user);
|
emit verificationStatusChanged(user);
|
||||||
}
|
}
|
||||||
} else {
|
|
||||||
emit verificationStatusChanged(user_id);
|
|
||||||
}
|
}
|
||||||
|
emit verificationStatusChanged(user_id);
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
|
@ -4316,9 +4315,8 @@ Cache::markDeviceUnverified(const std::string &user_id, const std::string &key)
|
||||||
(void)status;
|
(void)status;
|
||||||
emit verificationStatusChanged(user);
|
emit verificationStatusChanged(user);
|
||||||
}
|
}
|
||||||
} else {
|
|
||||||
emit verificationStatusChanged(user_id);
|
|
||||||
}
|
}
|
||||||
|
emit verificationStatusChanged(user_id);
|
||||||
}
|
}
|
||||||
|
|
||||||
VerificationStatus
|
VerificationStatus
|
||||||
|
|
|
@ -310,7 +310,7 @@ signals:
|
||||||
void removeNotification(const QString &room_id, const QString &event_id);
|
void removeNotification(const QString &room_id, const QString &event_id);
|
||||||
void userKeysUpdate(const std::string &sync_token, const mtx::responses::QueryKeys &keyQuery);
|
void userKeysUpdate(const std::string &sync_token, const mtx::responses::QueryKeys &keyQuery);
|
||||||
void verificationStatusChanged(const std::string &userid);
|
void verificationStatusChanged(const std::string &userid);
|
||||||
void selfUnverified();
|
void selfVerificationStatusChanged();
|
||||||
void secretChanged(const std::string name);
|
void secretChanged(const std::string name);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
|
|
@ -69,6 +69,7 @@ class DeviceVerificationFlow : public QObject
|
||||||
Q_PROPERTY(std::vector<int> sasList READ getSasList CONSTANT)
|
Q_PROPERTY(std::vector<int> sasList READ getSasList CONSTANT)
|
||||||
Q_PROPERTY(bool isDeviceVerification READ isDeviceVerification CONSTANT)
|
Q_PROPERTY(bool isDeviceVerification READ isDeviceVerification CONSTANT)
|
||||||
Q_PROPERTY(bool isSelfVerification READ isSelfVerification CONSTANT)
|
Q_PROPERTY(bool isSelfVerification READ isSelfVerification CONSTANT)
|
||||||
|
Q_PROPERTY(bool isMultiDeviceVerification READ isMultiDeviceVerification CONSTANT)
|
||||||
|
|
||||||
public:
|
public:
|
||||||
enum State
|
enum State
|
||||||
|
@ -139,6 +140,7 @@ public:
|
||||||
return this->type == DeviceVerificationFlow::Type::ToDevice;
|
return this->type == DeviceVerificationFlow::Type::ToDevice;
|
||||||
}
|
}
|
||||||
bool isSelfVerification() const;
|
bool isSelfVerification() const;
|
||||||
|
bool isMultiDeviceVerification() const { return deviceIds.size() > 1; }
|
||||||
|
|
||||||
void callback_fn(const UserKeyCache &res, mtx::http::RequestErr err, std::string user_id);
|
void callback_fn(const UserKeyCache &res, mtx::http::RequestErr err, std::string user_id);
|
||||||
|
|
||||||
|
|
|
@ -20,7 +20,7 @@ SelfVerificationStatus::SelfVerificationStatus(QObject *o)
|
||||||
{
|
{
|
||||||
connect(MainWindow::instance(), &MainWindow::reload, this, [this] {
|
connect(MainWindow::instance(), &MainWindow::reload, this, [this] {
|
||||||
connect(cache::client(),
|
connect(cache::client(),
|
||||||
&Cache::selfUnverified,
|
&Cache::selfVerificationStatusChanged,
|
||||||
this,
|
this,
|
||||||
&SelfVerificationStatus::invalidate,
|
&SelfVerificationStatus::invalidate,
|
||||||
Qt::UniqueConnection);
|
Qt::UniqueConnection);
|
||||||
|
@ -233,6 +233,24 @@ void
|
||||||
SelfVerificationStatus::verifyUnverifiedDevices()
|
SelfVerificationStatus::verifyUnverifiedDevices()
|
||||||
{
|
{
|
||||||
nhlog::db()->info("Clicked verify unverified devices");
|
nhlog::db()->info("Clicked verify unverified devices");
|
||||||
|
const auto this_user = http::client()->user_id().to_string();
|
||||||
|
|
||||||
|
auto keys = cache::client()->userKeys(this_user);
|
||||||
|
auto verif = cache::client()->verificationStatus(this_user);
|
||||||
|
|
||||||
|
if (!keys)
|
||||||
|
return;
|
||||||
|
|
||||||
|
std::vector<QString> devices;
|
||||||
|
for (const auto &[device, keys] : keys->device_keys) {
|
||||||
|
(void)keys;
|
||||||
|
if (!verif.verified_devices.count(device))
|
||||||
|
devices.push_back(QString::fromStdString(device));
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!devices.empty())
|
||||||
|
ChatPage::instance()->timelineManager()->verificationManager()->verifyOneOfDevices(
|
||||||
|
QString::fromStdString(this_user), std::move(devices));
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
|
|
|
@ -62,13 +62,16 @@ Theme::Theme(std::string_view theme)
|
||||||
sidebarBackground_ = QColor("#233649");
|
sidebarBackground_ = QColor("#233649");
|
||||||
alternateButton_ = QColor("#ccc");
|
alternateButton_ = QColor("#ccc");
|
||||||
red_ = QColor("#a82353");
|
red_ = QColor("#a82353");
|
||||||
|
orange_ = QColor("#fcbe05");
|
||||||
} else if (theme == "dark") {
|
} else if (theme == "dark") {
|
||||||
sidebarBackground_ = QColor("#2d3139");
|
sidebarBackground_ = QColor("#2d3139");
|
||||||
alternateButton_ = QColor("#414A59");
|
alternateButton_ = QColor("#414A59");
|
||||||
red_ = QColor("#a82353");
|
red_ = QColor("#a82353");
|
||||||
|
orange_ = QColor("#fcc53a");
|
||||||
} else {
|
} else {
|
||||||
sidebarBackground_ = p.window().color();
|
sidebarBackground_ = p.window().color();
|
||||||
alternateButton_ = p.dark().color();
|
alternateButton_ = p.dark().color();
|
||||||
red_ = QColor("red");
|
red_ = QColor("red");
|
||||||
|
orange_ = QColor("orange");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -62,6 +62,7 @@ class Theme : public QPalette
|
||||||
Q_PROPERTY(QColor alternateButton READ alternateButton CONSTANT)
|
Q_PROPERTY(QColor alternateButton READ alternateButton CONSTANT)
|
||||||
Q_PROPERTY(QColor separator READ separator CONSTANT)
|
Q_PROPERTY(QColor separator READ separator CONSTANT)
|
||||||
Q_PROPERTY(QColor red READ red CONSTANT)
|
Q_PROPERTY(QColor red READ red CONSTANT)
|
||||||
|
Q_PROPERTY(QColor orange READ orange CONSTANT)
|
||||||
public:
|
public:
|
||||||
Theme() {}
|
Theme() {}
|
||||||
explicit Theme(std::string_view theme);
|
explicit Theme(std::string_view theme);
|
||||||
|
@ -71,7 +72,8 @@ public:
|
||||||
QColor alternateButton() const { return alternateButton_; }
|
QColor alternateButton() const { return alternateButton_; }
|
||||||
QColor separator() const { return separator_; }
|
QColor separator() const { return separator_; }
|
||||||
QColor red() const { return red_; }
|
QColor red() const { return red_; }
|
||||||
|
QColor orange() const { return orange_; }
|
||||||
|
|
||||||
private:
|
private:
|
||||||
QColor sidebarBackground_, separator_, red_, alternateButton_;
|
QColor sidebarBackground_, separator_, red_, orange_, alternateButton_;
|
||||||
};
|
};
|
||||||
|
|
Loading…
Reference in a new issue