Make steps in verification flow explicit
This commit is contained in:
parent
2a79cd2b6b
commit
bca29a4227
@ -106,19 +106,7 @@ Page {
|
|||||||
Connections {
|
Connections {
|
||||||
target: TimelineManager
|
target: TimelineManager
|
||||||
function onNewDeviceVerificationRequest(flow,transactionId,userId,deviceId,isRequest) {
|
function onNewDeviceVerificationRequest(flow,transactionId,userId,deviceId,isRequest) {
|
||||||
flow.userId = userId;
|
var dialog = deviceVerificationDialog.createObject(timelineRoot, {flow: flow});
|
||||||
flow.sender = false;
|
|
||||||
flow.deviceId = deviceId;
|
|
||||||
switch(flow.type){
|
|
||||||
case DeviceVerificationFlow.ToDevice:
|
|
||||||
flow.tranId = transactionId;
|
|
||||||
deviceVerificationList.add(flow.tranId);
|
|
||||||
break;
|
|
||||||
case DeviceVerificationFlow.RoomMsg:
|
|
||||||
deviceVerificationList.add(flow.tranId);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
var dialog = deviceVerificationDialog.createObject(timelineRoot, {flow: flow,isRequest: isRequest,tran_id: flow.tranId});
|
|
||||||
dialog.show();
|
dialog.show();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -15,24 +15,12 @@ ApplicationWindow{
|
|||||||
width: 420
|
width: 420
|
||||||
minimumHeight: 420
|
minimumHeight: 420
|
||||||
|
|
||||||
modality: Qt.WindowModal
|
|
||||||
palette: colors
|
palette: colors
|
||||||
|
|
||||||
Connections{
|
|
||||||
target: deviceVerificationList
|
|
||||||
function onUpdateProfile() {
|
|
||||||
profile.fetchDeviceList(profile.userid)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
Component {
|
Component {
|
||||||
id: deviceVerificationDialog
|
id: deviceVerificationDialog
|
||||||
DeviceVerification {}
|
DeviceVerification {}
|
||||||
}
|
}
|
||||||
Component{
|
|
||||||
id: deviceVerificationFlow
|
|
||||||
DeviceVerificationFlow {}
|
|
||||||
}
|
|
||||||
|
|
||||||
ColumnLayout{
|
ColumnLayout{
|
||||||
id: contentL
|
id: contentL
|
||||||
@ -73,14 +61,7 @@ ApplicationWindow{
|
|||||||
enabled: !profile.isUserVerified
|
enabled: !profile.isUserVerified
|
||||||
visible: !profile.isUserVerified
|
visible: !profile.isUserVerified
|
||||||
|
|
||||||
onClicked: {
|
onClicked: profile.verify()
|
||||||
var newFlow = profile.createFlow(true);
|
|
||||||
newFlow.userId = profile.userid;
|
|
||||||
newFlow.sender = true;
|
|
||||||
deviceVerificationList.add(newFlow.tranId);
|
|
||||||
var dialog = deviceVerificationDialog.createObject(userProfileDialog, {flow: newFlow,isRequest: true,tran_id: newFlow.tranId});
|
|
||||||
dialog.show();
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
RowLayout {
|
RowLayout {
|
||||||
@ -172,17 +153,11 @@ ApplicationWindow{
|
|||||||
id: verifyButton
|
id: verifyButton
|
||||||
text: (model.verificationStatus != VerificationStatus.VERIFIED)?"Verify":"Unverify"
|
text: (model.verificationStatus != VerificationStatus.VERIFIED)?"Verify":"Unverify"
|
||||||
onClicked: {
|
onClicked: {
|
||||||
var newFlow = profile.createFlow(false);
|
|
||||||
newFlow.userId = profile.userid;
|
|
||||||
newFlow.sender = true;
|
|
||||||
newFlow.deviceId = model.deviceId;
|
|
||||||
if(model.verificationStatus == VerificationStatus.VERIFIED){
|
if(model.verificationStatus == VerificationStatus.VERIFIED){
|
||||||
newFlow.unverify();
|
profile.unverify(model.deviceId)
|
||||||
deviceVerificationList.updateProfile(newFlow.userId);
|
deviceVerificationList.updateProfile(newFlow.userId);
|
||||||
}else{
|
}else{
|
||||||
deviceVerificationList.add(newFlow.tranId);
|
profile.verify(model.deviceId);
|
||||||
var dialog = deviceVerificationDialog.createObject(userProfileDialog, {flow: newFlow,isRequest:false,tran_id: newFlow.tranId});
|
|
||||||
dialog.show();
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,49 +0,0 @@
|
|||||||
import QtQuick 2.3
|
|
||||||
import QtQuick.Controls 2.10
|
|
||||||
import QtQuick.Layouts 1.10
|
|
||||||
|
|
||||||
import im.nheko 1.0
|
|
||||||
|
|
||||||
Pane {
|
|
||||||
property string title: qsTr("Recieving Device Verification Request")
|
|
||||||
Component {
|
|
||||||
id: awaitingVerificationRequestAccept
|
|
||||||
AwaitingVerificationRequest {}
|
|
||||||
}
|
|
||||||
ColumnLayout {
|
|
||||||
spacing: 16
|
|
||||||
Label {
|
|
||||||
Layout.maximumWidth: 400
|
|
||||||
Layout.fillHeight: true
|
|
||||||
Layout.fillWidth: true
|
|
||||||
wrapMode: Text.Wrap
|
|
||||||
text: qsTr("The device was requested to be verified")
|
|
||||||
color:colors.text
|
|
||||||
verticalAlignment: Text.AlignVCenter
|
|
||||||
}
|
|
||||||
RowLayout {
|
|
||||||
Button {
|
|
||||||
Layout.alignment: Qt.AlignLeft
|
|
||||||
text: qsTr("Deny")
|
|
||||||
|
|
||||||
onClicked: {
|
|
||||||
flow.cancelVerification(DeviceVerificationFlow.User);
|
|
||||||
deviceVerificationList.remove(tran_id);
|
|
||||||
dialog.destroy();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
Item {
|
|
||||||
Layout.fillWidth: true
|
|
||||||
}
|
|
||||||
Button {
|
|
||||||
Layout.alignment: Qt.AlignRight
|
|
||||||
text: qsTr("Accept")
|
|
||||||
|
|
||||||
onClicked: {
|
|
||||||
stack.replace(awaitingVerificationRequestAccept);
|
|
||||||
flow.sender ?flow.sendVerificationReady():flow.acceptVerificationRequest();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
@ -27,9 +27,8 @@ Pane {
|
|||||||
text: qsTr("Cancel")
|
text: qsTr("Cancel")
|
||||||
|
|
||||||
onClicked: {
|
onClicked: {
|
||||||
flow.cancelVerification(DeviceVerificationFlow.User);
|
flow.cancel();
|
||||||
deviceVerificationList.remove(tran_id);
|
dialog.close();
|
||||||
dialog.destroy();
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
Item {
|
Item {
|
||||||
|
@ -18,36 +18,31 @@ ApplicationWindow {
|
|||||||
height: stack.implicitHeight
|
height: stack.implicitHeight
|
||||||
width: stack.implicitWidth
|
width: stack.implicitWidth
|
||||||
|
|
||||||
|
StackView {
|
||||||
|
id: stack
|
||||||
|
initialItem: newVerificationRequest
|
||||||
|
implicitWidth: currentItem.implicitWidth
|
||||||
|
implicitHeight: currentItem.implicitHeight
|
||||||
|
}
|
||||||
|
|
||||||
Component{
|
Component{
|
||||||
id: newVerificationRequest
|
id: newVerificationRequest
|
||||||
NewVerificationRequest {}
|
NewVerificationRequest {}
|
||||||
}
|
}
|
||||||
|
|
||||||
Component {
|
Component {
|
||||||
id: acceptNewVerificationRequest
|
id: waiting
|
||||||
AcceptNewVerificationRequest {}
|
Waiting {}
|
||||||
}
|
|
||||||
|
|
||||||
StackView {
|
|
||||||
id: stack
|
|
||||||
initialItem: flow.sender == true?newVerificationRequest:acceptNewVerificationRequest
|
|
||||||
implicitWidth: currentItem.implicitWidth
|
|
||||||
implicitHeight: currentItem.implicitHeight
|
|
||||||
}
|
}
|
||||||
|
|
||||||
Component {
|
Component {
|
||||||
id: partnerAborted
|
id: success
|
||||||
PartnerAborted {}
|
Success {}
|
||||||
}
|
}
|
||||||
|
|
||||||
Component {
|
Component {
|
||||||
id: timedout
|
id: failed
|
||||||
TimedOut {}
|
Failed {}
|
||||||
}
|
|
||||||
|
|
||||||
Component {
|
|
||||||
id: verificationSuccess
|
|
||||||
VerificationSuccess {}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
Component {
|
Component {
|
||||||
@ -60,19 +55,42 @@ ApplicationWindow {
|
|||||||
EmojiVerification {}
|
EmojiVerification {}
|
||||||
}
|
}
|
||||||
|
|
||||||
Connections {
|
Item {
|
||||||
target: flow
|
state: flow.state
|
||||||
onVerificationCanceled: stack.replace(partnerAborted)
|
|
||||||
onTimedout: stack.replace(timedout)
|
|
||||||
onDeviceVerified: stack.replace(verificationSuccess)
|
|
||||||
|
|
||||||
onVerificationRequestAccepted: switch(method) {
|
states: [
|
||||||
case DeviceVerificationFlow.Decimal: stack.replace(digitVerification); break;
|
State {
|
||||||
case DeviceVerificationFlow.Emoji: stack.replace(emojiVerification); break;
|
name: "PromptStartVerification"
|
||||||
}
|
StateChangeScript { script: stack.replace(newVerificationRequest) }
|
||||||
|
},
|
||||||
onRefreshProfile: {
|
State {
|
||||||
deviceVerificationList.updateProfile(flow.userId);
|
name: "CompareEmoji"
|
||||||
|
StateChangeScript { script: stack.replace(emojiVerification) }
|
||||||
|
},
|
||||||
|
State {
|
||||||
|
name: "CompareNumber"
|
||||||
|
StateChangeScript { script: stack.replace(digitVerification) }
|
||||||
|
},
|
||||||
|
State {
|
||||||
|
name: "WaitingForKeys"
|
||||||
|
StateChangeScript { script: stack.replace(waiting) }
|
||||||
|
},
|
||||||
|
State {
|
||||||
|
name: "WaitingForOtherToAccept"
|
||||||
|
StateChangeScript { script: stack.replace(waiting) }
|
||||||
|
},
|
||||||
|
State {
|
||||||
|
name: "WaitingForMac"
|
||||||
|
StateChangeScript { script: stack.replace(waiting) }
|
||||||
|
},
|
||||||
|
State {
|
||||||
|
name: "Success"
|
||||||
|
StateChangeScript { script: stack.replace(success) }
|
||||||
|
},
|
||||||
|
State {
|
||||||
|
name: "Failed"
|
||||||
|
StateChangeScript { script: stack.replace(failed); }
|
||||||
}
|
}
|
||||||
|
]
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -6,10 +6,7 @@ import im.nheko 1.0
|
|||||||
|
|
||||||
Pane {
|
Pane {
|
||||||
property string title: qsTr("Verification Code")
|
property string title: qsTr("Verification Code")
|
||||||
Component {
|
|
||||||
id: awaitingVerificationConfirmation
|
|
||||||
AwaitingVerificationConfirmation {}
|
|
||||||
}
|
|
||||||
ColumnLayout {
|
ColumnLayout {
|
||||||
spacing: 16
|
spacing: 16
|
||||||
Label {
|
Label {
|
||||||
@ -45,9 +42,8 @@ Pane {
|
|||||||
text: qsTr("They do not match!")
|
text: qsTr("They do not match!")
|
||||||
|
|
||||||
onClicked: {
|
onClicked: {
|
||||||
flow.cancelVerification(DeviceVerificationFlow.MismatchedSAS);
|
flow.cancel();
|
||||||
deviceVerificationList.remove(tran_id);
|
dialog.close();
|
||||||
dialog.destroy();
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
Item {
|
Item {
|
||||||
@ -57,7 +53,7 @@ Pane {
|
|||||||
Layout.alignment: Qt.AlignRight
|
Layout.alignment: Qt.AlignRight
|
||||||
text: qsTr("They match!")
|
text: qsTr("They match!")
|
||||||
|
|
||||||
onClicked: { stack.replace(awaitingVerificationConfirmation); flow.sendVerificationMac(); }
|
onClicked: flow.next();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -6,10 +6,7 @@ import im.nheko 1.0
|
|||||||
|
|
||||||
Pane {
|
Pane {
|
||||||
property string title: qsTr("Verification Code")
|
property string title: qsTr("Verification Code")
|
||||||
Component {
|
|
||||||
id: awaitingVerificationConfirmation
|
|
||||||
AwaitingVerificationConfirmation{}
|
|
||||||
}
|
|
||||||
ColumnLayout {
|
ColumnLayout {
|
||||||
spacing: 16
|
spacing: 16
|
||||||
Label {
|
Label {
|
||||||
@ -125,9 +122,8 @@ Pane {
|
|||||||
text: qsTr("They do not match!")
|
text: qsTr("They do not match!")
|
||||||
|
|
||||||
onClicked: {
|
onClicked: {
|
||||||
flow.cancelVerification(DeviceVerificationFlow.MismatchedSAS);
|
flow.cancel();
|
||||||
deviceVerificationList.remove(tran_id);
|
dialog.close();
|
||||||
dialog.destroy();
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
Item {
|
Item {
|
||||||
@ -137,7 +133,7 @@ Pane {
|
|||||||
Layout.alignment: Qt.AlignRight
|
Layout.alignment: Qt.AlignRight
|
||||||
text: qsTr("They match!")
|
text: qsTr("They match!")
|
||||||
|
|
||||||
onClicked: { stack.replace(awaitingVerificationConfirmation); flow.sendVerificationMac(); }
|
onClicked: flow.next()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -12,7 +12,14 @@ Pane {
|
|||||||
Layout.fillWidth: true
|
Layout.fillWidth: true
|
||||||
wrapMode: Text.Wrap
|
wrapMode: Text.Wrap
|
||||||
id: content
|
id: content
|
||||||
text: qsTr("Device verification timed out.")
|
text: switch (flow.error) {
|
||||||
|
case VerificationStatus.UnknownMethod: return qsTr("Device verification timed out.")
|
||||||
|
case VerificationStatus.MismatchedCommitment: return qsTr("Device verification timed out.")
|
||||||
|
case VerificationStatus.MismatchedSAS: return qsTr("Device verification timed out.")
|
||||||
|
case VerificationStatus.KeyMismatch: return qsTr("Device verification timed out.")
|
||||||
|
case VerificationStatus.Timeout: return qsTr("Device verification timed out.")
|
||||||
|
case VerificationStatus.OutOfOrder: return qsTr("Device verification timed out.")
|
||||||
|
}
|
||||||
color:colors.text
|
color:colors.text
|
||||||
verticalAlignment: Text.AlignVCenter
|
verticalAlignment: Text.AlignVCenter
|
||||||
}
|
}
|
||||||
@ -27,7 +34,7 @@ Pane {
|
|||||||
onClicked: {
|
onClicked: {
|
||||||
deviceVerificationList.remove(tran_id);
|
deviceVerificationList.remove(tran_id);
|
||||||
flow.deleteFlow();
|
flow.deleteFlow();
|
||||||
dialog.destroy()
|
dialog.close()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
@ -2,12 +2,11 @@ import QtQuick 2.3
|
|||||||
import QtQuick.Controls 2.10
|
import QtQuick.Controls 2.10
|
||||||
import QtQuick.Layouts 1.10
|
import QtQuick.Layouts 1.10
|
||||||
|
|
||||||
|
import im.nheko 1.0
|
||||||
|
|
||||||
Pane {
|
Pane {
|
||||||
property string title: qsTr("Sending Device Verification Request")
|
property string title: flow.sender ? qsTr("Send Device Verification Request") : qsTr("Recieved Device Verification Request")
|
||||||
Component {
|
|
||||||
id: awaitingVerificationRequestAccept
|
|
||||||
AwaitingVerificationRequest {}
|
|
||||||
}
|
|
||||||
ColumnLayout {
|
ColumnLayout {
|
||||||
spacing: 16
|
spacing: 16
|
||||||
Label {
|
Label {
|
||||||
@ -15,28 +14,20 @@ Pane {
|
|||||||
Layout.fillHeight: true
|
Layout.fillHeight: true
|
||||||
Layout.fillWidth: true
|
Layout.fillWidth: true
|
||||||
wrapMode: Text.Wrap
|
wrapMode: Text.Wrap
|
||||||
text: qsTr("A new device was added.")
|
text: flow.sender ?
|
||||||
color:colors.text
|
qsTr("To ensure that no malicious user can eavesdrop on your encrypted communications, you can verify this device.")
|
||||||
verticalAlignment: Text.AlignVCenter
|
: qsTr("The device was requested to be verified")
|
||||||
}
|
|
||||||
Label {
|
|
||||||
Layout.maximumWidth: 400
|
|
||||||
Layout.fillHeight: true
|
|
||||||
Layout.fillWidth: true
|
|
||||||
wrapMode: Text.Wrap
|
|
||||||
text: qsTr("The device may have been added by you signing in from another client or physical device. To ensure that no malicious user can eavesdrop on your encrypted communications, you should verify the new device.")
|
|
||||||
color:colors.text
|
color:colors.text
|
||||||
verticalAlignment: Text.AlignVCenter
|
verticalAlignment: Text.AlignVCenter
|
||||||
}
|
}
|
||||||
RowLayout {
|
RowLayout {
|
||||||
Button {
|
Button {
|
||||||
Layout.alignment: Qt.AlignLeft
|
Layout.alignment: Qt.AlignLeft
|
||||||
text: qsTr("Cancel")
|
text: flow.sender ? qsTr("Cancel") : qsTr("Deny")
|
||||||
|
|
||||||
onClicked: {
|
onClicked: {
|
||||||
deviceVerificationList.remove(tran_id);
|
flow.cancel();
|
||||||
flow.deleteFlow();
|
dialog.close();
|
||||||
dialog.destroy();
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
Item {
|
Item {
|
||||||
@ -44,11 +35,9 @@ Pane {
|
|||||||
}
|
}
|
||||||
Button {
|
Button {
|
||||||
Layout.alignment: Qt.AlignRight
|
Layout.alignment: Qt.AlignRight
|
||||||
text: qsTr("Start verification")
|
text: flow.sender ? qsTr("Start verification") : qsTr("Accept")
|
||||||
|
|
||||||
onClicked: {
|
onClicked: flow.next();
|
||||||
stack.replace(awaitingVerificationRequestAccept);
|
|
||||||
flow.sender ?flow.sendVerificationRequest():flow.startVerificationRequest(); }
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,34 +0,0 @@
|
|||||||
import QtQuick 2.3
|
|
||||||
import QtQuick.Controls 2.10
|
|
||||||
import QtQuick.Layouts 1.10
|
|
||||||
|
|
||||||
Pane {
|
|
||||||
property string title: qsTr("Verification aborted!")
|
|
||||||
ColumnLayout {
|
|
||||||
spacing: 16
|
|
||||||
Label {
|
|
||||||
Layout.maximumWidth: 400
|
|
||||||
Layout.fillHeight: true
|
|
||||||
Layout.fillWidth: true
|
|
||||||
wrapMode: Text.Wrap
|
|
||||||
id: content
|
|
||||||
text: qsTr("Verification canceled by the other party!")
|
|
||||||
color:colors.text
|
|
||||||
verticalAlignment: Text.AlignVCenter
|
|
||||||
}
|
|
||||||
RowLayout {
|
|
||||||
Item {
|
|
||||||
Layout.fillWidth: true
|
|
||||||
}
|
|
||||||
Button {
|
|
||||||
Layout.alignment: Qt.AlignRight
|
|
||||||
text: qsTr("Close")
|
|
||||||
|
|
||||||
onClicked: {
|
|
||||||
deviceVerificationList.remove(tran_id);
|
|
||||||
dialog.destroy();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
@ -24,11 +24,7 @@ Pane {
|
|||||||
Layout.alignment: Qt.AlignRight
|
Layout.alignment: Qt.AlignRight
|
||||||
text: qsTr("Close")
|
text: qsTr("Close")
|
||||||
|
|
||||||
onClicked: {
|
onClicked: dialog.close();
|
||||||
deviceVerificationList.remove(tran_id);
|
|
||||||
if(flow) flow.deleteFlow();
|
|
||||||
dialog.destroy();
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
@ -14,12 +14,18 @@ Pane {
|
|||||||
Layout.fillWidth: true
|
Layout.fillWidth: true
|
||||||
wrapMode: Text.Wrap
|
wrapMode: Text.Wrap
|
||||||
id: content
|
id: content
|
||||||
text: qsTr("Waiting for other side to accept the verification request.")
|
text: switch (flow.state) {
|
||||||
|
case "WaitingForOtherToAccept": return qsTr("Waiting for other side to accept the verification request.")
|
||||||
|
case "WaitingForKeys": return qsTr("Waiting for other side to continue the verification request.")
|
||||||
|
case "WaitingForMac": return qsTr("Waiting for other side to complete the verification request.")
|
||||||
|
}
|
||||||
|
|
||||||
color:colors.text
|
color:colors.text
|
||||||
verticalAlignment: Text.AlignVCenter
|
verticalAlignment: Text.AlignVCenter
|
||||||
}
|
}
|
||||||
BusyIndicator {
|
BusyIndicator {
|
||||||
Layout.alignment: Qt.AlignHCenter
|
Layout.alignment: Qt.AlignHCenter
|
||||||
|
palette: color
|
||||||
}
|
}
|
||||||
RowLayout {
|
RowLayout {
|
||||||
Button {
|
Button {
|
||||||
@ -27,9 +33,8 @@ Pane {
|
|||||||
text: qsTr("Cancel")
|
text: qsTr("Cancel")
|
||||||
|
|
||||||
onClicked: {
|
onClicked: {
|
||||||
flow.cancelVerification(DeviceVerificationFlow.User);
|
flow.cancel();
|
||||||
deviceVerificationList.remove(tran_id);
|
dialog.close();
|
||||||
dialog.destroy();
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
Item {
|
Item {
|
@ -141,16 +141,13 @@
|
|||||||
<file>qml/delegates/Pill.qml</file>
|
<file>qml/delegates/Pill.qml</file>
|
||||||
<file>qml/delegates/Placeholder.qml</file>
|
<file>qml/delegates/Placeholder.qml</file>
|
||||||
<file>qml/delegates/Reply.qml</file>
|
<file>qml/delegates/Reply.qml</file>
|
||||||
<file>qml/device-verification/AcceptNewVerificationRequest.qml</file>
|
<file>qml/device-verification/Waiting.qml</file>
|
||||||
<file>qml/device-verification/AwaitingVerificationConfirmation.qml</file>
|
|
||||||
<file>qml/device-verification/AwaitingVerificationRequest.qml</file>
|
|
||||||
<file>qml/device-verification/DeviceVerification.qml</file>
|
<file>qml/device-verification/DeviceVerification.qml</file>
|
||||||
<file>qml/device-verification/DigitVerification.qml</file>
|
<file>qml/device-verification/DigitVerification.qml</file>
|
||||||
<file>qml/device-verification/EmojiVerification.qml</file>
|
<file>qml/device-verification/EmojiVerification.qml</file>
|
||||||
<file>qml/device-verification/NewVerificationRequest.qml</file>
|
<file>qml/device-verification/NewVerificationRequest.qml</file>
|
||||||
<file>qml/device-verification/PartnerAborted.qml</file>
|
<file>qml/device-verification/Failed.qml</file>
|
||||||
<file>qml/device-verification/TimedOut.qml</file>
|
<file>qml/device-verification/Success.qml</file>
|
||||||
<file>qml/device-verification/VerificationSuccess.qml</file>
|
|
||||||
</qresource>
|
</qresource>
|
||||||
<qresource prefix="/media">
|
<qresource prefix="/media">
|
||||||
<file>media/ring.ogg</file>
|
<file>media/ring.ogg</file>
|
||||||
|
@ -169,22 +169,22 @@ signals:
|
|||||||
void decryptSidebarChanged();
|
void decryptSidebarChanged();
|
||||||
|
|
||||||
//! Signals for device verificaiton
|
//! Signals for device verificaiton
|
||||||
void recievedDeviceVerificationAccept(
|
void receivedDeviceVerificationAccept(
|
||||||
const mtx::events::msg::KeyVerificationAccept &message);
|
const mtx::events::msg::KeyVerificationAccept &message);
|
||||||
void recievedDeviceVerificationRequest(
|
void receivedDeviceVerificationRequest(
|
||||||
const mtx::events::msg::KeyVerificationRequest &message,
|
const mtx::events::msg::KeyVerificationRequest &message,
|
||||||
std::string sender);
|
std::string sender);
|
||||||
void recievedRoomDeviceVerificationRequest(
|
void receivedRoomDeviceVerificationRequest(
|
||||||
const mtx::events::RoomEvent<mtx::events::msg::KeyVerificationRequest> &message,
|
const mtx::events::RoomEvent<mtx::events::msg::KeyVerificationRequest> &message,
|
||||||
TimelineModel *model);
|
TimelineModel *model);
|
||||||
void recievedDeviceVerificationCancel(
|
void receivedDeviceVerificationCancel(
|
||||||
const mtx::events::msg::KeyVerificationCancel &message);
|
const mtx::events::msg::KeyVerificationCancel &message);
|
||||||
void recievedDeviceVerificationKey(const mtx::events::msg::KeyVerificationKey &message);
|
void receivedDeviceVerificationKey(const mtx::events::msg::KeyVerificationKey &message);
|
||||||
void recievedDeviceVerificationMac(const mtx::events::msg::KeyVerificationMac &message);
|
void receivedDeviceVerificationMac(const mtx::events::msg::KeyVerificationMac &message);
|
||||||
void recievedDeviceVerificationStart(const mtx::events::msg::KeyVerificationStart &message,
|
void receivedDeviceVerificationStart(const mtx::events::msg::KeyVerificationStart &message,
|
||||||
std::string sender);
|
std::string sender);
|
||||||
void recievedDeviceVerificationReady(const mtx::events::msg::KeyVerificationReady &message);
|
void receivedDeviceVerificationReady(const mtx::events::msg::KeyVerificationReady &message);
|
||||||
void recievedDeviceVerificationDone(const mtx::events::msg::KeyVerificationDone &message);
|
void receivedDeviceVerificationDone(const mtx::events::msg::KeyVerificationDone &message);
|
||||||
|
|
||||||
private slots:
|
private slots:
|
||||||
void showUnreadMessageNotification(int count);
|
void showUnreadMessageNotification(int count);
|
||||||
|
@ -15,8 +15,12 @@ namespace msgs = mtx::events::msg;
|
|||||||
|
|
||||||
DeviceVerificationFlow::DeviceVerificationFlow(QObject *,
|
DeviceVerificationFlow::DeviceVerificationFlow(QObject *,
|
||||||
DeviceVerificationFlow::Type flow_type,
|
DeviceVerificationFlow::Type flow_type,
|
||||||
TimelineModel *model)
|
TimelineModel *model,
|
||||||
: type(flow_type)
|
QString userID,
|
||||||
|
QString deviceId_)
|
||||||
|
: sender(false)
|
||||||
|
, type(flow_type)
|
||||||
|
, deviceId(deviceId_)
|
||||||
, model_(model)
|
, model_(model)
|
||||||
{
|
{
|
||||||
timeout = new QTimer(this);
|
timeout = new QTimer(this);
|
||||||
@ -24,6 +28,30 @@ DeviceVerificationFlow::DeviceVerificationFlow(QObject *,
|
|||||||
this->sas = olm::client()->sas_init();
|
this->sas = olm::client()->sas_init();
|
||||||
this->isMacVerified = false;
|
this->isMacVerified = false;
|
||||||
|
|
||||||
|
auto user_id = userID.toStdString();
|
||||||
|
this->toClient = mtx::identifiers::parse<mtx::identifiers::User>(user_id);
|
||||||
|
ChatPage::instance()->query_keys(
|
||||||
|
user_id, [user_id, this](const UserKeyCache &res, mtx::http::RequestErr err) {
|
||||||
|
if (err) {
|
||||||
|
nhlog::net()->warn("failed to query device keys: {},{}",
|
||||||
|
err->matrix_error.errcode,
|
||||||
|
static_cast<int>(err->status_code));
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!this->deviceId.isEmpty() &&
|
||||||
|
(res.device_keys.find(deviceId.toStdString()) == res.device_keys.end())) {
|
||||||
|
nhlog::net()->warn("no devices retrieved {}", user_id);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
for (const auto &[algorithm, key] :
|
||||||
|
res.device_keys.at(deviceId.toStdString()).keys) {
|
||||||
|
// TODO: Verify Signatures
|
||||||
|
this->device_keys[algorithm] = key;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
if (model) {
|
if (model) {
|
||||||
connect(this->model_,
|
connect(this->model_,
|
||||||
&TimelineModel::updateFlowEventId,
|
&TimelineModel::updateFlowEventId,
|
||||||
@ -36,64 +64,15 @@ DeviceVerificationFlow::DeviceVerificationFlow(QObject *,
|
|||||||
}
|
}
|
||||||
|
|
||||||
connect(timeout, &QTimer::timeout, this, [this]() {
|
connect(timeout, &QTimer::timeout, this, [this]() {
|
||||||
emit timedout();
|
|
||||||
this->cancelVerification(DeviceVerificationFlow::Error::Timeout);
|
this->cancelVerification(DeviceVerificationFlow::Error::Timeout);
|
||||||
this->deleteLater();
|
|
||||||
});
|
|
||||||
|
|
||||||
connect(this, &DeviceVerificationFlow::deleteFlow, this, [this]() { this->deleteLater(); });
|
|
||||||
|
|
||||||
connect(
|
|
||||||
ChatPage::instance(),
|
|
||||||
&ChatPage::recievedDeviceVerificationStart,
|
|
||||||
this,
|
|
||||||
[this](const mtx::events::msg::KeyVerificationStart &msg, std::string) {
|
|
||||||
if (msg.transaction_id.has_value()) {
|
|
||||||
if (msg.transaction_id.value() != this->transaction_id)
|
|
||||||
return;
|
|
||||||
} else if (msg.relates_to.has_value()) {
|
|
||||||
if (msg.relates_to.value().event_id != this->relation.event_id)
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
if ((std::find(msg.key_agreement_protocols.begin(),
|
|
||||||
msg.key_agreement_protocols.end(),
|
|
||||||
"curve25519-hkdf-sha256") != msg.key_agreement_protocols.end()) &&
|
|
||||||
(std::find(msg.hashes.begin(), msg.hashes.end(), "sha256") !=
|
|
||||||
msg.hashes.end()) &&
|
|
||||||
(std::find(msg.message_authentication_codes.begin(),
|
|
||||||
msg.message_authentication_codes.end(),
|
|
||||||
"hkdf-hmac-sha256") != msg.message_authentication_codes.end())) {
|
|
||||||
if (std::find(msg.short_authentication_string.begin(),
|
|
||||||
msg.short_authentication_string.end(),
|
|
||||||
mtx::events::msg::SASMethods::Decimal) !=
|
|
||||||
msg.short_authentication_string.end()) {
|
|
||||||
this->method = DeviceVerificationFlow::Method::Emoji;
|
|
||||||
} else if (std::find(msg.short_authentication_string.begin(),
|
|
||||||
msg.short_authentication_string.end(),
|
|
||||||
mtx::events::msg::SASMethods::Emoji) !=
|
|
||||||
msg.short_authentication_string.end()) {
|
|
||||||
this->method = DeviceVerificationFlow::Method::Decimal;
|
|
||||||
} else {
|
|
||||||
this->cancelVerification(
|
|
||||||
DeviceVerificationFlow::Error::UnknownMethod);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
if (!sender)
|
|
||||||
this->canonical_json = nlohmann::json(msg);
|
|
||||||
else {
|
|
||||||
if (utils::localUser().toStdString() <
|
|
||||||
this->toClient.to_string()) {
|
|
||||||
this->canonical_json = nlohmann::json(msg);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
this->acceptVerificationRequest();
|
|
||||||
} else {
|
|
||||||
this->cancelVerification(DeviceVerificationFlow::Error::UnknownMethod);
|
|
||||||
}
|
|
||||||
});
|
});
|
||||||
|
|
||||||
connect(ChatPage::instance(),
|
connect(ChatPage::instance(),
|
||||||
&ChatPage::recievedDeviceVerificationAccept,
|
&ChatPage::receivedDeviceVerificationStart,
|
||||||
|
this,
|
||||||
|
&DeviceVerificationFlow::handleStartMessage);
|
||||||
|
connect(ChatPage::instance(),
|
||||||
|
&ChatPage::receivedDeviceVerificationAccept,
|
||||||
this,
|
this,
|
||||||
[this](const mtx::events::msg::KeyVerificationAccept &msg) {
|
[this](const mtx::events::msg::KeyVerificationAccept &msg) {
|
||||||
if (msg.transaction_id.has_value()) {
|
if (msg.transaction_id.has_value()) {
|
||||||
@ -111,9 +90,9 @@ DeviceVerificationFlow::DeviceVerificationFlow(QObject *,
|
|||||||
msg.short_authentication_string.end(),
|
msg.short_authentication_string.end(),
|
||||||
mtx::events::msg::SASMethods::Emoji) !=
|
mtx::events::msg::SASMethods::Emoji) !=
|
||||||
msg.short_authentication_string.end()) {
|
msg.short_authentication_string.end()) {
|
||||||
this->method = DeviceVerificationFlow::Method::Emoji;
|
this->method = mtx::events::msg::SASMethods::Emoji;
|
||||||
} else {
|
} else {
|
||||||
this->method = DeviceVerificationFlow::Method::Decimal;
|
this->method = mtx::events::msg::SASMethods::Decimal;
|
||||||
}
|
}
|
||||||
this->mac_method = msg.message_authentication_code;
|
this->mac_method = msg.message_authentication_code;
|
||||||
this->sendVerificationKey();
|
this->sendVerificationKey();
|
||||||
@ -124,7 +103,7 @@ DeviceVerificationFlow::DeviceVerificationFlow(QObject *,
|
|||||||
});
|
});
|
||||||
|
|
||||||
connect(ChatPage::instance(),
|
connect(ChatPage::instance(),
|
||||||
&ChatPage::recievedDeviceVerificationCancel,
|
&ChatPage::receivedDeviceVerificationCancel,
|
||||||
this,
|
this,
|
||||||
[this](const mtx::events::msg::KeyVerificationCancel &msg) {
|
[this](const mtx::events::msg::KeyVerificationCancel &msg) {
|
||||||
if (msg.transaction_id.has_value()) {
|
if (msg.transaction_id.has_value()) {
|
||||||
@ -134,12 +113,13 @@ DeviceVerificationFlow::DeviceVerificationFlow(QObject *,
|
|||||||
if (msg.relates_to.value().event_id != this->relation.event_id)
|
if (msg.relates_to.value().event_id != this->relation.event_id)
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
this->deleteLater();
|
error_ = User;
|
||||||
emit verificationCanceled();
|
emit errorChanged();
|
||||||
|
setState(Failed);
|
||||||
});
|
});
|
||||||
|
|
||||||
connect(ChatPage::instance(),
|
connect(ChatPage::instance(),
|
||||||
&ChatPage::recievedDeviceVerificationKey,
|
&ChatPage::receivedDeviceVerificationKey,
|
||||||
this,
|
this,
|
||||||
[this](const mtx::events::msg::KeyVerificationKey &msg) {
|
[this](const mtx::events::msg::KeyVerificationKey &msg) {
|
||||||
if (msg.transaction_id.has_value()) {
|
if (msg.transaction_id.has_value()) {
|
||||||
@ -149,6 +129,19 @@ DeviceVerificationFlow::DeviceVerificationFlow(QObject *,
|
|||||||
if (msg.relates_to.value().event_id != this->relation.event_id)
|
if (msg.relates_to.value().event_id != this->relation.event_id)
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (sender) {
|
||||||
|
if (state_ != WaitingForOtherToAccept) {
|
||||||
|
this->cancelVerification(OutOfOrder);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
if (state_ != WaitingForKeys) {
|
||||||
|
this->cancelVerification(OutOfOrder);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
this->sas->set_their_key(msg.key);
|
this->sas->set_their_key(msg.key);
|
||||||
std::string info;
|
std::string info;
|
||||||
if (this->sender == true) {
|
if (this->sender == true) {
|
||||||
@ -166,31 +159,30 @@ DeviceVerificationFlow::DeviceVerificationFlow(QObject *,
|
|||||||
"|" + this->transaction_id;
|
"|" + this->transaction_id;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (this->method == DeviceVerificationFlow::Method::Emoji) {
|
|
||||||
std::cout << info << std::endl;
|
|
||||||
this->sasList = this->sas->generate_bytes_emoji(info);
|
|
||||||
} else if (this->method == DeviceVerificationFlow::Method::Decimal) {
|
|
||||||
this->sasList = this->sas->generate_bytes_decimal(info);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (this->sender == false) {
|
if (this->sender == false) {
|
||||||
emit this->verificationRequestAccepted(this->method);
|
|
||||||
this->sendVerificationKey();
|
this->sendVerificationKey();
|
||||||
} else {
|
} else {
|
||||||
if (this->commitment ==
|
if (this->commitment !=
|
||||||
mtx::crypto::bin2base64_unpadded(
|
mtx::crypto::bin2base64_unpadded(
|
||||||
mtx::crypto::sha256(msg.key + this->canonical_json.dump()))) {
|
mtx::crypto::sha256(msg.key + this->canonical_json.dump()))) {
|
||||||
emit this->verificationRequestAccepted(this->method);
|
|
||||||
} else {
|
|
||||||
this->cancelVerification(
|
this->cancelVerification(
|
||||||
DeviceVerificationFlow::Error::MismatchedCommitment);
|
DeviceVerificationFlow::Error::MismatchedCommitment);
|
||||||
|
return;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (this->method == mtx::events::msg::SASMethods::Emoji) {
|
||||||
|
this->sasList = this->sas->generate_bytes_emoji(info);
|
||||||
|
setState(CompareEmoji);
|
||||||
|
} else if (this->method == mtx::events::msg::SASMethods::Decimal) {
|
||||||
|
this->sasList = this->sas->generate_bytes_decimal(info);
|
||||||
|
setState(CompareNumber);
|
||||||
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
connect(
|
connect(
|
||||||
ChatPage::instance(),
|
ChatPage::instance(),
|
||||||
&ChatPage::recievedDeviceVerificationMac,
|
&ChatPage::receivedDeviceVerificationMac,
|
||||||
this,
|
this,
|
||||||
[this](const mtx::events::msg::KeyVerificationMac &msg) {
|
[this](const mtx::events::msg::KeyVerificationMac &msg) {
|
||||||
if (msg.transaction_id.has_value()) {
|
if (msg.transaction_id.has_value()) {
|
||||||
@ -222,26 +214,22 @@ DeviceVerificationFlow::DeviceVerificationFlow(QObject *,
|
|||||||
}
|
}
|
||||||
key_string = key_string.substr(0, key_string.length() - 1);
|
key_string = key_string.substr(0, key_string.length() - 1);
|
||||||
if (msg.keys == this->sas->calculate_mac(key_string, info + "KEY_IDS")) {
|
if (msg.keys == this->sas->calculate_mac(key_string, info + "KEY_IDS")) {
|
||||||
// uncomment this in future to be compatible with the
|
|
||||||
// MSC2366 this->sendVerificationDone(); and remove the
|
|
||||||
// below line
|
|
||||||
if (this->isMacVerified == true) {
|
|
||||||
this->acceptDevice();
|
|
||||||
} else
|
|
||||||
this->isMacVerified = true;
|
this->isMacVerified = true;
|
||||||
|
this->acceptDevice();
|
||||||
} else {
|
} else {
|
||||||
this->cancelVerification(DeviceVerificationFlow::Error::KeyMismatch);
|
this->cancelVerification(DeviceVerificationFlow::Error::KeyMismatch);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
connect(ChatPage::instance(),
|
connect(ChatPage::instance(),
|
||||||
&ChatPage::recievedDeviceVerificationReady,
|
&ChatPage::receivedDeviceVerificationReady,
|
||||||
this,
|
this,
|
||||||
[this](const mtx::events::msg::KeyVerificationReady &msg) {
|
[this](const mtx::events::msg::KeyVerificationReady &msg) {
|
||||||
if (!sender) {
|
if (!sender) {
|
||||||
if (msg.from_device != http::client()->device_id()) {
|
if (msg.from_device != http::client()->device_id()) {
|
||||||
this->deleteLater();
|
error_ = User;
|
||||||
emit verificationCanceled();
|
emit errorChanged();
|
||||||
|
setState(Failed);
|
||||||
}
|
}
|
||||||
|
|
||||||
return;
|
return;
|
||||||
@ -261,7 +249,7 @@ DeviceVerificationFlow::DeviceVerificationFlow(QObject *,
|
|||||||
});
|
});
|
||||||
|
|
||||||
connect(ChatPage::instance(),
|
connect(ChatPage::instance(),
|
||||||
&ChatPage::recievedDeviceVerificationDone,
|
&ChatPage::receivedDeviceVerificationDone,
|
||||||
this,
|
this,
|
||||||
[this](const mtx::events::msg::KeyVerificationDone &msg) {
|
[this](const mtx::events::msg::KeyVerificationDone &msg) {
|
||||||
if (msg.transaction_id.has_value()) {
|
if (msg.transaction_id.has_value()) {
|
||||||
@ -271,22 +259,85 @@ DeviceVerificationFlow::DeviceVerificationFlow(QObject *,
|
|||||||
if (msg.relates_to.value().event_id != this->relation.event_id)
|
if (msg.relates_to.value().event_id != this->relation.event_id)
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
this->acceptDevice();
|
nhlog::ui()->info("Flow done on other side");
|
||||||
});
|
});
|
||||||
|
|
||||||
timeout->start(TIMEOUT);
|
timeout->start(TIMEOUT);
|
||||||
}
|
}
|
||||||
|
|
||||||
QString
|
QString
|
||||||
DeviceVerificationFlow::getTransactionId()
|
DeviceVerificationFlow::state()
|
||||||
{
|
{
|
||||||
return QString::fromStdString(this->transaction_id);
|
switch (state_) {
|
||||||
|
case PromptStartVerification:
|
||||||
|
return "PromptStartVerification";
|
||||||
|
case CompareEmoji:
|
||||||
|
return "CompareEmoji";
|
||||||
|
case CompareNumber:
|
||||||
|
return "CompareNumber";
|
||||||
|
case WaitingForKeys:
|
||||||
|
return "WaitingForKeys";
|
||||||
|
case WaitingForOtherToAccept:
|
||||||
|
return "WaitingForOtherToAccept";
|
||||||
|
case WaitingForMac:
|
||||||
|
return "WaitingForMac";
|
||||||
|
case Success:
|
||||||
|
return "Success";
|
||||||
|
case Failed:
|
||||||
|
return "Failed";
|
||||||
|
default:
|
||||||
|
return "";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
DeviceVerificationFlow::next()
|
||||||
|
{
|
||||||
|
if (sender) {
|
||||||
|
switch (state_) {
|
||||||
|
case PromptStartVerification:
|
||||||
|
sendVerificationRequest();
|
||||||
|
break;
|
||||||
|
case CompareEmoji:
|
||||||
|
case CompareNumber:
|
||||||
|
sendVerificationMac();
|
||||||
|
break;
|
||||||
|
case WaitingForKeys:
|
||||||
|
case WaitingForOtherToAccept:
|
||||||
|
case WaitingForMac:
|
||||||
|
case Success:
|
||||||
|
case Failed:
|
||||||
|
nhlog::db()->error("verification: Invalid state transition!");
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
switch (state_) {
|
||||||
|
case PromptStartVerification:
|
||||||
|
if (canonical_json.is_null())
|
||||||
|
sendVerificationReady();
|
||||||
|
else // legacy path without request and ready
|
||||||
|
acceptVerificationRequest();
|
||||||
|
break;
|
||||||
|
case CompareEmoji:
|
||||||
|
[[fallthrough]];
|
||||||
|
case CompareNumber:
|
||||||
|
sendVerificationMac();
|
||||||
|
break;
|
||||||
|
case WaitingForKeys:
|
||||||
|
case WaitingForOtherToAccept:
|
||||||
|
case WaitingForMac:
|
||||||
|
case Success:
|
||||||
|
case Failed:
|
||||||
|
nhlog::db()->error("verification: Invalid state transition!");
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
QString
|
QString
|
||||||
DeviceVerificationFlow::getUserId()
|
DeviceVerificationFlow::getUserId()
|
||||||
{
|
{
|
||||||
return this->userId;
|
return QString::fromStdString(this->toClient.to_string());
|
||||||
}
|
}
|
||||||
|
|
||||||
QString
|
QString
|
||||||
@ -295,18 +346,6 @@ DeviceVerificationFlow::getDeviceId()
|
|||||||
return this->deviceId;
|
return this->deviceId;
|
||||||
}
|
}
|
||||||
|
|
||||||
DeviceVerificationFlow::Method
|
|
||||||
DeviceVerificationFlow::getMethod()
|
|
||||||
{
|
|
||||||
return this->method;
|
|
||||||
}
|
|
||||||
|
|
||||||
DeviceVerificationFlow::Type
|
|
||||||
DeviceVerificationFlow::getType()
|
|
||||||
{
|
|
||||||
return this->type;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool
|
bool
|
||||||
DeviceVerificationFlow::getSender()
|
DeviceVerificationFlow::getSender()
|
||||||
{
|
{
|
||||||
@ -319,51 +358,6 @@ DeviceVerificationFlow::getSasList()
|
|||||||
return this->sasList;
|
return this->sasList;
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
|
||||||
DeviceVerificationFlow::setTransactionId(QString transaction_id_)
|
|
||||||
{
|
|
||||||
this->transaction_id = transaction_id_.toStdString();
|
|
||||||
}
|
|
||||||
|
|
||||||
void
|
|
||||||
DeviceVerificationFlow::setUserId(QString userID)
|
|
||||||
{
|
|
||||||
this->userId = userID;
|
|
||||||
this->toClient = mtx::identifiers::parse<mtx::identifiers::User>(userID.toStdString());
|
|
||||||
|
|
||||||
auto user_id = userID.toStdString();
|
|
||||||
ChatPage::instance()->query_keys(
|
|
||||||
user_id, [user_id, this](const UserKeyCache &res, mtx::http::RequestErr err) {
|
|
||||||
this->callback_fn(res, err, user_id);
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
void
|
|
||||||
DeviceVerificationFlow::setDeviceId(QString deviceID)
|
|
||||||
{
|
|
||||||
this->deviceId = deviceID;
|
|
||||||
}
|
|
||||||
|
|
||||||
void
|
|
||||||
DeviceVerificationFlow::setMethod(DeviceVerificationFlow::Method method_)
|
|
||||||
{
|
|
||||||
this->method = method_;
|
|
||||||
}
|
|
||||||
|
|
||||||
void
|
|
||||||
DeviceVerificationFlow::setType(Type type_)
|
|
||||||
{
|
|
||||||
this->type = type_;
|
|
||||||
}
|
|
||||||
|
|
||||||
void
|
|
||||||
DeviceVerificationFlow::setSender(bool sender_)
|
|
||||||
{
|
|
||||||
this->sender = sender_;
|
|
||||||
if (this->sender)
|
|
||||||
this->transaction_id = http::client()->generate_txn_id();
|
|
||||||
}
|
|
||||||
|
|
||||||
void
|
void
|
||||||
DeviceVerificationFlow::setEventId(std::string event_id_)
|
DeviceVerificationFlow::setEventId(std::string event_id_)
|
||||||
{
|
{
|
||||||
@ -372,6 +366,53 @@ DeviceVerificationFlow::setEventId(std::string event_id_)
|
|||||||
this->transaction_id = event_id_;
|
this->transaction_id = event_id_;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
DeviceVerificationFlow::handleStartMessage(const mtx::events::msg::KeyVerificationStart &msg,
|
||||||
|
std::string)
|
||||||
|
{
|
||||||
|
if (msg.transaction_id.has_value()) {
|
||||||
|
if (msg.transaction_id.value() != this->transaction_id)
|
||||||
|
return;
|
||||||
|
} else if (msg.relates_to.has_value()) {
|
||||||
|
if (msg.relates_to.value().event_id != this->relation.event_id)
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if ((std::find(msg.key_agreement_protocols.begin(),
|
||||||
|
msg.key_agreement_protocols.end(),
|
||||||
|
"curve25519-hkdf-sha256") != msg.key_agreement_protocols.end()) &&
|
||||||
|
(std::find(msg.hashes.begin(), msg.hashes.end(), "sha256") != msg.hashes.end()) &&
|
||||||
|
(std::find(msg.message_authentication_codes.begin(),
|
||||||
|
msg.message_authentication_codes.end(),
|
||||||
|
"hkdf-hmac-sha256") != msg.message_authentication_codes.end())) {
|
||||||
|
if (std::find(msg.short_authentication_string.begin(),
|
||||||
|
msg.short_authentication_string.end(),
|
||||||
|
mtx::events::msg::SASMethods::Emoji) !=
|
||||||
|
msg.short_authentication_string.end()) {
|
||||||
|
this->method = mtx::events::msg::SASMethods::Emoji;
|
||||||
|
} else if (std::find(msg.short_authentication_string.begin(),
|
||||||
|
msg.short_authentication_string.end(),
|
||||||
|
mtx::events::msg::SASMethods::Decimal) !=
|
||||||
|
msg.short_authentication_string.end()) {
|
||||||
|
this->method = mtx::events::msg::SASMethods::Decimal;
|
||||||
|
} else {
|
||||||
|
this->cancelVerification(DeviceVerificationFlow::Error::UnknownMethod);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (!sender)
|
||||||
|
this->canonical_json = nlohmann::json(msg);
|
||||||
|
else {
|
||||||
|
if (utils::localUser().toStdString() < this->toClient.to_string()) {
|
||||||
|
this->canonical_json = nlohmann::json(msg);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (state_ != PromptStartVerification)
|
||||||
|
this->acceptVerificationRequest();
|
||||||
|
} else {
|
||||||
|
this->cancelVerification(DeviceVerificationFlow::Error::UnknownMethod);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
//! accepts a verification
|
//! accepts a verification
|
||||||
void
|
void
|
||||||
DeviceVerificationFlow::acceptVerificationRequest()
|
DeviceVerificationFlow::acceptVerificationRequest()
|
||||||
@ -382,30 +423,15 @@ DeviceVerificationFlow::acceptVerificationRequest()
|
|||||||
req.key_agreement_protocol = "curve25519-hkdf-sha256";
|
req.key_agreement_protocol = "curve25519-hkdf-sha256";
|
||||||
req.hash = "sha256";
|
req.hash = "sha256";
|
||||||
req.message_authentication_code = "hkdf-hmac-sha256";
|
req.message_authentication_code = "hkdf-hmac-sha256";
|
||||||
if (this->method == DeviceVerificationFlow::Method::Emoji)
|
if (this->method == mtx::events::msg::SASMethods::Emoji)
|
||||||
req.short_authentication_string = {mtx::events::msg::SASMethods::Emoji};
|
req.short_authentication_string = {mtx::events::msg::SASMethods::Emoji};
|
||||||
else if (this->method == DeviceVerificationFlow::Method::Decimal)
|
else if (this->method == mtx::events::msg::SASMethods::Decimal)
|
||||||
req.short_authentication_string = {mtx::events::msg::SASMethods::Decimal};
|
req.short_authentication_string = {mtx::events::msg::SASMethods::Decimal};
|
||||||
req.commitment = mtx::crypto::bin2base64_unpadded(
|
req.commitment = mtx::crypto::bin2base64_unpadded(
|
||||||
mtx::crypto::sha256(this->sas->public_key() + this->canonical_json.dump()));
|
mtx::crypto::sha256(this->sas->public_key() + this->canonical_json.dump()));
|
||||||
|
|
||||||
if (this->type == DeviceVerificationFlow::Type::ToDevice) {
|
send(req);
|
||||||
mtx::requests::ToDeviceMessages<mtx::events::msg::KeyVerificationAccept> body;
|
setState(WaitingForKeys);
|
||||||
req.transaction_id = this->transaction_id;
|
|
||||||
|
|
||||||
body[this->toClient][this->deviceId.toStdString()] = req;
|
|
||||||
|
|
||||||
http::client()->send_to_device<mtx::events::msg::KeyVerificationAccept>(
|
|
||||||
this->transaction_id, body, [](mtx::http::RequestErr err) {
|
|
||||||
if (err)
|
|
||||||
nhlog::net()->warn("failed to accept verification request: {} {}",
|
|
||||||
err->matrix_error.error,
|
|
||||||
static_cast<int>(err->status_code));
|
|
||||||
});
|
|
||||||
} else if (this->type == DeviceVerificationFlow::Type::RoomMsg && model_) {
|
|
||||||
req.relates_to = this->relation;
|
|
||||||
(model_)->sendMessageEvent(req, mtx::events::EventType::KeyVerificationAccept);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
//! responds verification request
|
//! responds verification request
|
||||||
void
|
void
|
||||||
@ -416,23 +442,8 @@ DeviceVerificationFlow::sendVerificationReady()
|
|||||||
req.from_device = http::client()->device_id();
|
req.from_device = http::client()->device_id();
|
||||||
req.methods = {mtx::events::msg::VerificationMethods::SASv1};
|
req.methods = {mtx::events::msg::VerificationMethods::SASv1};
|
||||||
|
|
||||||
if (this->type == DeviceVerificationFlow::Type::ToDevice) {
|
send(req);
|
||||||
req.transaction_id = this->transaction_id;
|
setState(WaitingForKeys);
|
||||||
mtx::requests::ToDeviceMessages<mtx::events::msg::KeyVerificationReady> body;
|
|
||||||
|
|
||||||
body[this->toClient][this->deviceId.toStdString()] = req;
|
|
||||||
|
|
||||||
http::client()->send_to_device<mtx::events::msg::KeyVerificationReady>(
|
|
||||||
this->transaction_id, body, [](mtx::http::RequestErr err) {
|
|
||||||
if (err)
|
|
||||||
nhlog::net()->warn("failed to send verification ready: {} {}",
|
|
||||||
err->matrix_error.error,
|
|
||||||
static_cast<int>(err->status_code));
|
|
||||||
});
|
|
||||||
} else if (this->type == DeviceVerificationFlow::Type::RoomMsg && model_) {
|
|
||||||
req.relates_to = this->relation;
|
|
||||||
(model_)->sendMessageEvent(req, mtx::events::EventType::KeyVerificationReady);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
//! accepts a verification
|
//! accepts a verification
|
||||||
void
|
void
|
||||||
@ -440,23 +451,7 @@ DeviceVerificationFlow::sendVerificationDone()
|
|||||||
{
|
{
|
||||||
mtx::events::msg::KeyVerificationDone req;
|
mtx::events::msg::KeyVerificationDone req;
|
||||||
|
|
||||||
if (this->type == DeviceVerificationFlow::Type::ToDevice) {
|
send(req);
|
||||||
mtx::requests::ToDeviceMessages<mtx::events::msg::KeyVerificationDone> body;
|
|
||||||
req.transaction_id = this->transaction_id;
|
|
||||||
|
|
||||||
body[this->toClient][this->deviceId.toStdString()] = req;
|
|
||||||
|
|
||||||
http::client()->send_to_device<mtx::events::msg::KeyVerificationDone>(
|
|
||||||
this->transaction_id, body, [](mtx::http::RequestErr err) {
|
|
||||||
if (err)
|
|
||||||
nhlog::net()->warn("failed to send verification done: {} {}",
|
|
||||||
err->matrix_error.error,
|
|
||||||
static_cast<int>(err->status_code));
|
|
||||||
});
|
|
||||||
} else if (this->type == DeviceVerificationFlow::Type::RoomMsg && model_) {
|
|
||||||
req.relates_to = this->relation;
|
|
||||||
(model_)->sendMessageEvent(req, mtx::events::EventType::KeyVerificationDone);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
//! starts the verification flow
|
//! starts the verification flow
|
||||||
void
|
void
|
||||||
@ -476,20 +471,12 @@ DeviceVerificationFlow::startVerificationRequest()
|
|||||||
mtx::requests::ToDeviceMessages<mtx::events::msg::KeyVerificationStart> body;
|
mtx::requests::ToDeviceMessages<mtx::events::msg::KeyVerificationStart> body;
|
||||||
req.transaction_id = this->transaction_id;
|
req.transaction_id = this->transaction_id;
|
||||||
this->canonical_json = nlohmann::json(req);
|
this->canonical_json = nlohmann::json(req);
|
||||||
body[this->toClient][this->deviceId.toStdString()] = req;
|
|
||||||
|
|
||||||
http::client()->send_to_device<mtx::events::msg::KeyVerificationStart>(
|
|
||||||
this->transaction_id, body, [body](mtx::http::RequestErr err) {
|
|
||||||
if (err)
|
|
||||||
nhlog::net()->warn("failed to start verification request: {} {}",
|
|
||||||
err->matrix_error.error,
|
|
||||||
static_cast<int>(err->status_code));
|
|
||||||
});
|
|
||||||
} else if (this->type == DeviceVerificationFlow::Type::RoomMsg && model_) {
|
} else if (this->type == DeviceVerificationFlow::Type::RoomMsg && model_) {
|
||||||
req.relates_to = this->relation;
|
req.relates_to = this->relation;
|
||||||
this->canonical_json = nlohmann::json(req);
|
this->canonical_json = nlohmann::json(req);
|
||||||
(model_)->sendMessageEvent(req, mtx::events::EventType::KeyVerificationStart);
|
|
||||||
}
|
}
|
||||||
|
send(req);
|
||||||
|
setState(WaitingForOtherToAccept);
|
||||||
}
|
}
|
||||||
//! sends a verification request
|
//! sends a verification request
|
||||||
void
|
void
|
||||||
@ -503,28 +490,18 @@ DeviceVerificationFlow::sendVerificationRequest()
|
|||||||
if (this->type == DeviceVerificationFlow::Type::ToDevice) {
|
if (this->type == DeviceVerificationFlow::Type::ToDevice) {
|
||||||
QDateTime currentTime = QDateTime::currentDateTimeUtc();
|
QDateTime currentTime = QDateTime::currentDateTimeUtc();
|
||||||
|
|
||||||
req.transaction_id = this->transaction_id;
|
|
||||||
req.timestamp = (uint64_t)currentTime.toMSecsSinceEpoch();
|
req.timestamp = (uint64_t)currentTime.toMSecsSinceEpoch();
|
||||||
|
|
||||||
mtx::requests::ToDeviceMessages<mtx::events::msg::KeyVerificationRequest> body;
|
|
||||||
|
|
||||||
body[this->toClient][this->deviceId.toStdString()] = req;
|
|
||||||
|
|
||||||
http::client()->send_to_device<mtx::events::msg::KeyVerificationRequest>(
|
|
||||||
this->transaction_id, body, [](mtx::http::RequestErr err) {
|
|
||||||
if (err)
|
|
||||||
nhlog::net()->warn("failed to send verification request: {} {}",
|
|
||||||
err->matrix_error.error,
|
|
||||||
static_cast<int>(err->status_code));
|
|
||||||
});
|
|
||||||
} else if (this->type == DeviceVerificationFlow::Type::RoomMsg && model_) {
|
} else if (this->type == DeviceVerificationFlow::Type::RoomMsg && model_) {
|
||||||
req.to = this->userId.toStdString();
|
req.to = this->toClient.to_string();
|
||||||
req.msgtype = "m.key.verification.request";
|
req.msgtype = "m.key.verification.request";
|
||||||
req.body = "User is requesting to verify keys with you. However, your client does "
|
req.body = "User is requesting to verify keys with you. However, your client does "
|
||||||
"not support this method, so you will need to use the legacy method of "
|
"not support this method, so you will need to use the legacy method of "
|
||||||
"key verification.";
|
"key verification.";
|
||||||
(model_)->sendMessageEvent(req, mtx::events::EventType::KeyVerificationRequest);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
send(req);
|
||||||
|
setState(WaitingForOtherToAccept);
|
||||||
}
|
}
|
||||||
//! cancels a verification flow
|
//! cancels a verification flow
|
||||||
void
|
void
|
||||||
@ -534,7 +511,7 @@ DeviceVerificationFlow::cancelVerification(DeviceVerificationFlow::Error error_c
|
|||||||
|
|
||||||
if (error_code == DeviceVerificationFlow::Error::UnknownMethod) {
|
if (error_code == DeviceVerificationFlow::Error::UnknownMethod) {
|
||||||
req.code = "m.unknown_method";
|
req.code = "m.unknown_method";
|
||||||
req.reason = "unknown method recieved";
|
req.reason = "unknown method received";
|
||||||
} else if (error_code == DeviceVerificationFlow::Error::MismatchedCommitment) {
|
} else if (error_code == DeviceVerificationFlow::Error::MismatchedCommitment) {
|
||||||
req.code = "m.mismatched_commitment";
|
req.code = "m.mismatched_commitment";
|
||||||
req.reason = "commitment didn't match";
|
req.reason = "commitment didn't match";
|
||||||
@ -550,42 +527,16 @@ DeviceVerificationFlow::cancelVerification(DeviceVerificationFlow::Error error_c
|
|||||||
} else if (error_code == DeviceVerificationFlow::Error::User) {
|
} else if (error_code == DeviceVerificationFlow::Error::User) {
|
||||||
req.code = "m.user";
|
req.code = "m.user";
|
||||||
req.reason = "user cancelled the verification";
|
req.reason = "user cancelled the verification";
|
||||||
|
} else if (error_code == DeviceVerificationFlow::Error::OutOfOrder) {
|
||||||
|
req.code = "m.unexpected_message";
|
||||||
|
req.reason = "received messages out of order";
|
||||||
}
|
}
|
||||||
|
|
||||||
emit this->verificationCanceled();
|
this->error_ = error_code;
|
||||||
|
emit errorChanged();
|
||||||
|
this->setState(Failed);
|
||||||
|
|
||||||
if (this->type == DeviceVerificationFlow::Type::ToDevice) {
|
send(req);
|
||||||
req.transaction_id = this->transaction_id;
|
|
||||||
mtx::requests::ToDeviceMessages<mtx::events::msg::KeyVerificationCancel> body;
|
|
||||||
|
|
||||||
body[this->toClient][deviceId.toStdString()] = req;
|
|
||||||
|
|
||||||
http::client()->send_to_device<mtx::events::msg::KeyVerificationCancel>(
|
|
||||||
this->transaction_id, body, [this](mtx::http::RequestErr err) {
|
|
||||||
if (err)
|
|
||||||
nhlog::net()->warn("failed to cancel verification request: {} {}",
|
|
||||||
err->matrix_error.error,
|
|
||||||
static_cast<int>(err->status_code));
|
|
||||||
|
|
||||||
this->deleteLater();
|
|
||||||
});
|
|
||||||
} else if (this->type == DeviceVerificationFlow::Type::RoomMsg && model_) {
|
|
||||||
req.relates_to = this->relation;
|
|
||||||
(model_)->sendMessageEvent(req, mtx::events::EventType::KeyVerificationCancel);
|
|
||||||
this->deleteLater();
|
|
||||||
}
|
|
||||||
|
|
||||||
// TODO : Handle Blocking user better
|
|
||||||
// auto verified_cache = cache::getVerifiedCache(this->userId.toStdString());
|
|
||||||
// if (verified_cache.has_value()) {
|
|
||||||
// verified_cache->device_blocked.push_back(this->deviceId.toStdString());
|
|
||||||
// cache::setVerifiedCache(this->userId.toStdString(),
|
|
||||||
// verified_cache.value());
|
|
||||||
// } else {
|
|
||||||
// cache::setVerifiedCache(
|
|
||||||
// this->userId.toStdString(),
|
|
||||||
// DeviceVerifiedCache{{}, {}, {this->deviceId.toStdString()}});
|
|
||||||
// }
|
|
||||||
}
|
}
|
||||||
//! sends the verification key
|
//! sends the verification key
|
||||||
void
|
void
|
||||||
@ -595,23 +546,7 @@ DeviceVerificationFlow::sendVerificationKey()
|
|||||||
|
|
||||||
req.key = this->sas->public_key();
|
req.key = this->sas->public_key();
|
||||||
|
|
||||||
if (this->type == DeviceVerificationFlow::Type::ToDevice) {
|
send(req);
|
||||||
mtx::requests::ToDeviceMessages<mtx::events::msg::KeyVerificationKey> body;
|
|
||||||
req.transaction_id = this->transaction_id;
|
|
||||||
|
|
||||||
body[this->toClient][deviceId.toStdString()] = req;
|
|
||||||
|
|
||||||
http::client()->send_to_device<mtx::events::msg::KeyVerificationKey>(
|
|
||||||
this->transaction_id, body, [](mtx::http::RequestErr err) {
|
|
||||||
if (err)
|
|
||||||
nhlog::net()->warn("failed to send verification key: {} {}",
|
|
||||||
err->matrix_error.error,
|
|
||||||
static_cast<int>(err->status_code));
|
|
||||||
});
|
|
||||||
} else if (this->type == DeviceVerificationFlow::Type::RoomMsg && model_) {
|
|
||||||
req.relates_to = this->relation;
|
|
||||||
(model_)->sendMessageEvent(req, mtx::events::EventType::KeyVerificationKey);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
mtx::events::msg::KeyVerificationMac
|
mtx::events::msg::KeyVerificationMac
|
||||||
@ -660,68 +595,102 @@ DeviceVerificationFlow::sendVerificationMac()
|
|||||||
this->transaction_id,
|
this->transaction_id,
|
||||||
key_list);
|
key_list);
|
||||||
|
|
||||||
if (this->type == DeviceVerificationFlow::Type::ToDevice) {
|
send(req);
|
||||||
mtx::requests::ToDeviceMessages<mtx::events::msg::KeyVerificationMac> body;
|
|
||||||
req.transaction_id = this->transaction_id;
|
|
||||||
body[this->toClient][deviceId.toStdString()] = req;
|
|
||||||
|
|
||||||
http::client()->send_to_device<mtx::events::msg::KeyVerificationMac>(
|
setState(WaitingForMac);
|
||||||
this->transaction_id, body, [this](mtx::http::RequestErr err) {
|
acceptDevice();
|
||||||
if (err)
|
|
||||||
nhlog::net()->warn("failed to send verification MAC: {} {}",
|
|
||||||
err->matrix_error.error,
|
|
||||||
static_cast<int>(err->status_code));
|
|
||||||
|
|
||||||
if (this->isMacVerified == true)
|
|
||||||
this->acceptDevice();
|
|
||||||
else
|
|
||||||
this->isMacVerified = true;
|
|
||||||
});
|
|
||||||
} else if (this->type == DeviceVerificationFlow::Type::RoomMsg && model_) {
|
|
||||||
req.relates_to = this->relation;
|
|
||||||
(model_)->sendMessageEvent(req, mtx::events::EventType::KeyVerificationMac);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
//! Completes the verification flow
|
//! Completes the verification flow
|
||||||
void
|
void
|
||||||
DeviceVerificationFlow::acceptDevice()
|
DeviceVerificationFlow::acceptDevice()
|
||||||
{
|
{
|
||||||
cache::markDeviceVerified(this->userId.toStdString(), this->deviceId.toStdString());
|
if (!isMacVerified) {
|
||||||
|
setState(WaitingForMac);
|
||||||
emit deviceVerified();
|
} else if (state_ == WaitingForMac) {
|
||||||
emit refreshProfile();
|
cache::markDeviceVerified(this->toClient.to_string(), this->deviceId.toStdString());
|
||||||
this->deleteLater();
|
this->sendVerificationDone();
|
||||||
}
|
setState(Success);
|
||||||
|
|
||||||
//! callback function to keep track of devices
|
|
||||||
void
|
|
||||||
DeviceVerificationFlow::callback_fn(const UserKeyCache &res,
|
|
||||||
mtx::http::RequestErr err,
|
|
||||||
std::string user_id)
|
|
||||||
{
|
|
||||||
if (err) {
|
|
||||||
nhlog::net()->warn("failed to query device keys: {},{}",
|
|
||||||
err->matrix_error.errcode,
|
|
||||||
static_cast<int>(err->status_code));
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (res.device_keys.empty() ||
|
|
||||||
(res.device_keys.find(deviceId.toStdString()) == res.device_keys.end())) {
|
|
||||||
nhlog::net()->warn("no devices retrieved {}", user_id);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
for (const auto &[algorithm, key] : res.device_keys.at(deviceId.toStdString()).keys) {
|
|
||||||
// TODO: Verify Signatures
|
|
||||||
this->device_keys[algorithm] = key;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
DeviceVerificationFlow::unverify()
|
DeviceVerificationFlow::unverify()
|
||||||
{
|
{
|
||||||
cache::markDeviceUnverified(this->userId.toStdString(), this->deviceId.toStdString());
|
cache::markDeviceUnverified(this->toClient.to_string(), this->deviceId.toStdString());
|
||||||
|
|
||||||
emit refreshProfile();
|
emit refreshProfile();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
QSharedPointer<DeviceVerificationFlow>
|
||||||
|
DeviceVerificationFlow::NewInRoomVerification(QObject *parent_,
|
||||||
|
TimelineModel *timelineModel_,
|
||||||
|
const mtx::events::msg::KeyVerificationRequest &msg,
|
||||||
|
QString other_user_,
|
||||||
|
QString event_id_)
|
||||||
|
{
|
||||||
|
QSharedPointer<DeviceVerificationFlow> flow(
|
||||||
|
new DeviceVerificationFlow(parent_, Type::RoomMsg, timelineModel_, other_user_, ""));
|
||||||
|
|
||||||
|
flow->event_id = event_id_.toStdString();
|
||||||
|
|
||||||
|
if (std::find(msg.methods.begin(),
|
||||||
|
msg.methods.end(),
|
||||||
|
mtx::events::msg::VerificationMethods::SASv1) == msg.methods.end()) {
|
||||||
|
flow->cancelVerification(UnknownMethod);
|
||||||
|
}
|
||||||
|
|
||||||
|
return flow;
|
||||||
|
}
|
||||||
|
QSharedPointer<DeviceVerificationFlow>
|
||||||
|
DeviceVerificationFlow::NewToDeviceVerification(QObject *parent_,
|
||||||
|
const mtx::events::msg::KeyVerificationRequest &msg,
|
||||||
|
QString other_user_,
|
||||||
|
QString txn_id_)
|
||||||
|
{
|
||||||
|
QSharedPointer<DeviceVerificationFlow> flow(new DeviceVerificationFlow(
|
||||||
|
parent_, Type::ToDevice, nullptr, other_user_, QString::fromStdString(msg.from_device)));
|
||||||
|
flow->transaction_id = txn_id_.toStdString();
|
||||||
|
|
||||||
|
if (std::find(msg.methods.begin(),
|
||||||
|
msg.methods.end(),
|
||||||
|
mtx::events::msg::VerificationMethods::SASv1) == msg.methods.end()) {
|
||||||
|
flow->cancelVerification(UnknownMethod);
|
||||||
|
}
|
||||||
|
|
||||||
|
return flow;
|
||||||
|
}
|
||||||
|
QSharedPointer<DeviceVerificationFlow>
|
||||||
|
DeviceVerificationFlow::NewToDeviceVerification(QObject *parent_,
|
||||||
|
const mtx::events::msg::KeyVerificationStart &msg,
|
||||||
|
QString other_user_,
|
||||||
|
QString txn_id_)
|
||||||
|
{
|
||||||
|
QSharedPointer<DeviceVerificationFlow> flow(new DeviceVerificationFlow(
|
||||||
|
parent_, Type::ToDevice, nullptr, other_user_, QString::fromStdString(msg.from_device)));
|
||||||
|
flow->transaction_id = txn_id_.toStdString();
|
||||||
|
|
||||||
|
flow->handleStartMessage(msg, "");
|
||||||
|
|
||||||
|
return flow;
|
||||||
|
}
|
||||||
|
QSharedPointer<DeviceVerificationFlow>
|
||||||
|
DeviceVerificationFlow::InitiateUserVerification(QObject *parent_,
|
||||||
|
TimelineModel *timelineModel_,
|
||||||
|
QString userid)
|
||||||
|
{
|
||||||
|
QSharedPointer<DeviceVerificationFlow> flow(
|
||||||
|
new DeviceVerificationFlow(parent_, Type::RoomMsg, timelineModel_, userid, ""));
|
||||||
|
flow->sender = true;
|
||||||
|
return flow;
|
||||||
|
}
|
||||||
|
QSharedPointer<DeviceVerificationFlow>
|
||||||
|
DeviceVerificationFlow::InitiateDeviceVerification(QObject *parent_, QString userid, QString device)
|
||||||
|
{
|
||||||
|
QSharedPointer<DeviceVerificationFlow> flow(
|
||||||
|
new DeviceVerificationFlow(parent_, Type::ToDevice, nullptr, userid, device));
|
||||||
|
|
||||||
|
flow->sender = true;
|
||||||
|
flow->transaction_id = http::client()->generate_txn_id();
|
||||||
|
|
||||||
|
return flow;
|
||||||
|
}
|
||||||
|
@ -5,41 +5,84 @@
|
|||||||
#include <mtx/responses/crypto.hpp>
|
#include <mtx/responses/crypto.hpp>
|
||||||
|
|
||||||
#include "CacheCryptoStructs.h"
|
#include "CacheCryptoStructs.h"
|
||||||
|
#include "Logging.h"
|
||||||
#include "MatrixClient.h"
|
#include "MatrixClient.h"
|
||||||
#include "Olm.h"
|
#include "Olm.h"
|
||||||
|
#include "timeline/TimelineModel.h"
|
||||||
|
|
||||||
class QTimer;
|
class QTimer;
|
||||||
|
|
||||||
using sas_ptr = std::unique_ptr<mtx::crypto::SAS>;
|
using sas_ptr = std::unique_ptr<mtx::crypto::SAS>;
|
||||||
|
|
||||||
class TimelineModel;
|
// clang-format off
|
||||||
|
/*
|
||||||
|
* Stolen from fluffy chat :D
|
||||||
|
*
|
||||||
|
* State | +-------------+ +-----------+ |
|
||||||
|
* | | AliceDevice | | BobDevice | |
|
||||||
|
* | | (sender) | | | |
|
||||||
|
* | +-------------+ +-----------+ |
|
||||||
|
* promptStartVerify | | | |
|
||||||
|
* | o | (m.key.verification.request) | |
|
||||||
|
* | p |-------------------------------->| (ASK FOR VERIFICATION REQUEST) |
|
||||||
|
* waitForOtherAccept | t | | | promptStartVerify
|
||||||
|
* && | i | (m.key.verification.ready) | |
|
||||||
|
* no commitment | o |<--------------------------------| |
|
||||||
|
* && | n | | |
|
||||||
|
* no canonical_json | a | (m.key.verification.start) | | waitingForKeys
|
||||||
|
* | l |<--------------------------------| Not sending to prevent the glare resolve| && no commitment
|
||||||
|
* | | | | && no canonical_json
|
||||||
|
* | | m.key.verification.start | |
|
||||||
|
* waitForOtherAccept | |-------------------------------->| (IF NOT ALREADY ASKED, |
|
||||||
|
* && | | | ASK FOR VERIFICATION REQUEST) | promptStartVerify, if not accepted
|
||||||
|
* canonical_json | | m.key.verification.accept | |
|
||||||
|
* | |<--------------------------------| |
|
||||||
|
* waitForOtherAccept | | | | waitingForKeys
|
||||||
|
* && | | m.key.verification.key | | && canonical_json
|
||||||
|
* commitment | |-------------------------------->| | && commitment
|
||||||
|
* | | | |
|
||||||
|
* | | m.key.verification.key | |
|
||||||
|
* | |<--------------------------------| |
|
||||||
|
* compareEmoji/Number| | | | compareEmoji/Number
|
||||||
|
* | | COMPARE EMOJI / NUMBERS | |
|
||||||
|
* | | | |
|
||||||
|
* waitingForMac | | m.key.verification.mac | | waitingForMac
|
||||||
|
* | success |<------------------------------->| success |
|
||||||
|
* | | | |
|
||||||
|
* success/fail | | m.key.verification.done | | success/fail
|
||||||
|
* | |<------------------------------->| |
|
||||||
|
*/
|
||||||
|
// clang-format on
|
||||||
class DeviceVerificationFlow : public QObject
|
class DeviceVerificationFlow : public QObject
|
||||||
{
|
{
|
||||||
Q_OBJECT
|
Q_OBJECT
|
||||||
// Q_CLASSINFO("RegisterEnumClassesUnscoped", "false")
|
// Q_CLASSINFO("RegisterEnumClassesUnscoped", "false")
|
||||||
Q_PROPERTY(QString tranId READ getTransactionId WRITE setTransactionId)
|
Q_PROPERTY(QString state READ state NOTIFY stateChanged)
|
||||||
Q_PROPERTY(bool sender READ getSender WRITE setSender)
|
Q_PROPERTY(Error error READ error CONSTANT)
|
||||||
Q_PROPERTY(QString userId READ getUserId WRITE setUserId)
|
Q_PROPERTY(QString userId READ getUserId CONSTANT)
|
||||||
Q_PROPERTY(QString deviceId READ getDeviceId WRITE setDeviceId)
|
Q_PROPERTY(QString deviceId READ getDeviceId CONSTANT)
|
||||||
Q_PROPERTY(Method method READ getMethod WRITE setMethod)
|
Q_PROPERTY(bool sender READ getSender CONSTANT)
|
||||||
Q_PROPERTY(Type type READ getType WRITE setType)
|
|
||||||
Q_PROPERTY(std::vector<int> sasList READ getSasList CONSTANT)
|
Q_PROPERTY(std::vector<int> sasList READ getSasList CONSTANT)
|
||||||
|
|
||||||
public:
|
public:
|
||||||
|
enum State
|
||||||
|
{
|
||||||
|
PromptStartVerification,
|
||||||
|
WaitingForOtherToAccept,
|
||||||
|
WaitingForKeys,
|
||||||
|
CompareEmoji,
|
||||||
|
CompareNumber,
|
||||||
|
WaitingForMac,
|
||||||
|
Success,
|
||||||
|
Failed,
|
||||||
|
};
|
||||||
|
Q_ENUM(State)
|
||||||
|
|
||||||
enum Type
|
enum Type
|
||||||
{
|
{
|
||||||
ToDevice,
|
ToDevice,
|
||||||
RoomMsg
|
RoomMsg
|
||||||
};
|
};
|
||||||
Q_ENUM(Type)
|
|
||||||
|
|
||||||
enum Method
|
|
||||||
{
|
|
||||||
Decimal,
|
|
||||||
Emoji
|
|
||||||
};
|
|
||||||
Q_ENUM(Method)
|
|
||||||
|
|
||||||
enum Error
|
enum Error
|
||||||
{
|
{
|
||||||
@ -48,36 +91,75 @@ public:
|
|||||||
MismatchedSAS,
|
MismatchedSAS,
|
||||||
KeyMismatch,
|
KeyMismatch,
|
||||||
Timeout,
|
Timeout,
|
||||||
User
|
User,
|
||||||
|
OutOfOrder,
|
||||||
};
|
};
|
||||||
Q_ENUM(Error)
|
Q_ENUM(Error)
|
||||||
|
|
||||||
DeviceVerificationFlow(
|
static QSharedPointer<DeviceVerificationFlow> NewInRoomVerification(
|
||||||
QObject *parent = nullptr,
|
QObject *parent_,
|
||||||
DeviceVerificationFlow::Type = DeviceVerificationFlow::Type::ToDevice,
|
TimelineModel *timelineModel_,
|
||||||
TimelineModel *model = nullptr);
|
const mtx::events::msg::KeyVerificationRequest &msg,
|
||||||
|
QString other_user_,
|
||||||
|
QString event_id_);
|
||||||
|
static QSharedPointer<DeviceVerificationFlow> NewToDeviceVerification(
|
||||||
|
QObject *parent_,
|
||||||
|
const mtx::events::msg::KeyVerificationRequest &msg,
|
||||||
|
QString other_user_,
|
||||||
|
QString txn_id_);
|
||||||
|
static QSharedPointer<DeviceVerificationFlow> NewToDeviceVerification(
|
||||||
|
QObject *parent_,
|
||||||
|
const mtx::events::msg::KeyVerificationStart &msg,
|
||||||
|
QString other_user_,
|
||||||
|
QString txn_id_);
|
||||||
|
static QSharedPointer<DeviceVerificationFlow>
|
||||||
|
InitiateUserVerification(QObject *parent_, TimelineModel *timelineModel_, QString userid);
|
||||||
|
static QSharedPointer<DeviceVerificationFlow> InitiateDeviceVerification(QObject *parent,
|
||||||
|
QString userid,
|
||||||
|
QString device);
|
||||||
|
|
||||||
// getters
|
// getters
|
||||||
QString getTransactionId();
|
QString state();
|
||||||
|
Error error() { return error_; }
|
||||||
QString getUserId();
|
QString getUserId();
|
||||||
QString getDeviceId();
|
QString getDeviceId();
|
||||||
Method getMethod();
|
|
||||||
Type getType();
|
|
||||||
std::vector<int> getSasList();
|
|
||||||
bool getSender();
|
bool getSender();
|
||||||
|
std::vector<int> getSasList();
|
||||||
|
QString transactionId() { return QString::fromStdString(this->transaction_id); }
|
||||||
// setters
|
// setters
|
||||||
void setTransactionId(QString transaction_id_);
|
|
||||||
void setUserId(QString userID);
|
|
||||||
void setDeviceId(QString deviceID);
|
void setDeviceId(QString deviceID);
|
||||||
void setMethod(Method method_);
|
|
||||||
void setType(Type type_);
|
|
||||||
void setSender(bool sender_);
|
|
||||||
void setEventId(std::string event_id);
|
void setEventId(std::string event_id);
|
||||||
|
|
||||||
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);
|
||||||
|
|
||||||
nlohmann::json canonical_json;
|
|
||||||
|
|
||||||
public slots:
|
public slots:
|
||||||
|
//! unverifies a device
|
||||||
|
void unverify();
|
||||||
|
//! Continues the flow
|
||||||
|
void next();
|
||||||
|
//! Cancel the flow
|
||||||
|
void cancel() { cancelVerification(User); }
|
||||||
|
|
||||||
|
signals:
|
||||||
|
void refreshProfile();
|
||||||
|
void stateChanged();
|
||||||
|
void errorChanged();
|
||||||
|
|
||||||
|
private:
|
||||||
|
DeviceVerificationFlow(QObject *,
|
||||||
|
DeviceVerificationFlow::Type flow_type,
|
||||||
|
TimelineModel *model,
|
||||||
|
QString userID,
|
||||||
|
QString deviceId_);
|
||||||
|
void setState(State state)
|
||||||
|
{
|
||||||
|
if (state != state_) {
|
||||||
|
state_ = state;
|
||||||
|
emit stateChanged();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void handleStartMessage(const mtx::events::msg::KeyVerificationStart &msg, std::string);
|
||||||
//! sends a verification request
|
//! sends a verification request
|
||||||
void sendVerificationRequest();
|
void sendVerificationRequest();
|
||||||
//! accepts a verification request
|
//! accepts a verification request
|
||||||
@ -96,37 +178,60 @@ public slots:
|
|||||||
void sendVerificationMac();
|
void sendVerificationMac();
|
||||||
//! Completes the verification flow
|
//! Completes the verification flow
|
||||||
void acceptDevice();
|
void acceptDevice();
|
||||||
//! unverifies a device
|
|
||||||
void unverify();
|
|
||||||
|
|
||||||
signals:
|
|
||||||
void verificationRequestAccepted(Method method);
|
|
||||||
void deviceVerified();
|
|
||||||
void timedout();
|
|
||||||
void verificationCanceled();
|
|
||||||
void refreshProfile();
|
|
||||||
void deleteFlow();
|
|
||||||
|
|
||||||
private:
|
|
||||||
// general
|
|
||||||
QString userId;
|
|
||||||
QString deviceId;
|
|
||||||
Method method = Method::Emoji;
|
|
||||||
Type type;
|
|
||||||
bool sender;
|
|
||||||
QTimer *timeout = nullptr;
|
|
||||||
sas_ptr sas;
|
|
||||||
bool isMacVerified = false;
|
|
||||||
std::string mac_method;
|
|
||||||
std::string commitment;
|
|
||||||
mtx::identifiers::User toClient;
|
|
||||||
std::vector<int> sasList;
|
|
||||||
std::map<std::string, std::string> device_keys;
|
|
||||||
// for to_device messages
|
// for to_device messages
|
||||||
std::string transaction_id;
|
std::string transaction_id;
|
||||||
// for room messages
|
// for room messages
|
||||||
std::optional<std::string> room_id;
|
std::optional<std::string> room_id;
|
||||||
std::optional<std::string> event_id;
|
std::optional<std::string> event_id;
|
||||||
|
|
||||||
|
bool sender;
|
||||||
|
Type type;
|
||||||
|
mtx::identifiers::User toClient;
|
||||||
|
QString deviceId;
|
||||||
|
|
||||||
|
mtx::events::msg::SASMethods method = mtx::events::msg::SASMethods::Emoji;
|
||||||
|
QTimer *timeout = nullptr;
|
||||||
|
sas_ptr sas;
|
||||||
|
std::string mac_method;
|
||||||
|
std::string commitment;
|
||||||
|
nlohmann::json canonical_json;
|
||||||
|
|
||||||
|
std::vector<int> sasList;
|
||||||
|
std::map<std::string, std::string> device_keys;
|
||||||
TimelineModel *model_;
|
TimelineModel *model_;
|
||||||
mtx::common::RelatesTo relation;
|
mtx::common::RelatesTo relation;
|
||||||
|
|
||||||
|
State state_ = PromptStartVerification;
|
||||||
|
Error error_;
|
||||||
|
|
||||||
|
bool isMacVerified = false;
|
||||||
|
|
||||||
|
template<typename T>
|
||||||
|
void send(T msg)
|
||||||
|
{
|
||||||
|
if (this->type == DeviceVerificationFlow::Type::ToDevice) {
|
||||||
|
mtx::requests::ToDeviceMessages<T> body;
|
||||||
|
msg.transaction_id = this->transaction_id;
|
||||||
|
body[this->toClient][deviceId.toStdString()] = msg;
|
||||||
|
|
||||||
|
http::client()->send_to_device<T>(
|
||||||
|
this->transaction_id, body, [this](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));
|
||||||
|
});
|
||||||
|
} else if (this->type == DeviceVerificationFlow::Type::RoomMsg && model_) {
|
||||||
|
if constexpr (!std::is_same_v<T, mtx::events::msg::KeyVerificationRequest>)
|
||||||
|
msg.relates_to = this->relation;
|
||||||
|
(model_)->sendMessageEvent(msg, mtx::events::to_device_content_to_type<T>);
|
||||||
|
}
|
||||||
|
|
||||||
|
nhlog::net()->debug(
|
||||||
|
"Sent verification step: {} in state: {}",
|
||||||
|
mtx::events::to_string(mtx::events::to_device_content_to_type<T>),
|
||||||
|
state().toStdString());
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
32
src/Olm.cpp
32
src/Olm.cpp
@ -80,40 +80,40 @@ handle_to_device_messages(const std::vector<mtx::events::collections::DeviceEven
|
|||||||
} else if (msg_type == to_string(mtx::events::EventType::KeyVerificationAccept)) {
|
} else if (msg_type == to_string(mtx::events::EventType::KeyVerificationAccept)) {
|
||||||
auto message = std::get<
|
auto message = std::get<
|
||||||
mtx::events::DeviceEvent<mtx::events::msg::KeyVerificationAccept>>(msg);
|
mtx::events::DeviceEvent<mtx::events::msg::KeyVerificationAccept>>(msg);
|
||||||
ChatPage::instance()->recievedDeviceVerificationAccept(message.content);
|
ChatPage::instance()->receivedDeviceVerificationAccept(message.content);
|
||||||
} else if (msg_type == to_string(mtx::events::EventType::KeyVerificationRequest)) {
|
} else if (msg_type == to_string(mtx::events::EventType::KeyVerificationRequest)) {
|
||||||
auto message = std::get<
|
auto message = std::get<
|
||||||
mtx::events::DeviceEvent<mtx::events::msg::KeyVerificationRequest>>(msg);
|
mtx::events::DeviceEvent<mtx::events::msg::KeyVerificationRequest>>(msg);
|
||||||
ChatPage::instance()->recievedDeviceVerificationRequest(message.content,
|
ChatPage::instance()->receivedDeviceVerificationRequest(message.content,
|
||||||
message.sender);
|
message.sender);
|
||||||
} else if (msg_type == to_string(mtx::events::EventType::KeyVerificationCancel)) {
|
} else if (msg_type == to_string(mtx::events::EventType::KeyVerificationCancel)) {
|
||||||
auto message = std::get<
|
auto message = std::get<
|
||||||
mtx::events::DeviceEvent<mtx::events::msg::KeyVerificationCancel>>(msg);
|
mtx::events::DeviceEvent<mtx::events::msg::KeyVerificationCancel>>(msg);
|
||||||
ChatPage::instance()->recievedDeviceVerificationCancel(message.content);
|
ChatPage::instance()->receivedDeviceVerificationCancel(message.content);
|
||||||
} else if (msg_type == to_string(mtx::events::EventType::KeyVerificationKey)) {
|
} else if (msg_type == to_string(mtx::events::EventType::KeyVerificationKey)) {
|
||||||
auto message =
|
auto message =
|
||||||
std::get<mtx::events::DeviceEvent<mtx::events::msg::KeyVerificationKey>>(
|
std::get<mtx::events::DeviceEvent<mtx::events::msg::KeyVerificationKey>>(
|
||||||
msg);
|
msg);
|
||||||
ChatPage::instance()->recievedDeviceVerificationKey(message.content);
|
ChatPage::instance()->receivedDeviceVerificationKey(message.content);
|
||||||
} else if (msg_type == to_string(mtx::events::EventType::KeyVerificationMac)) {
|
} else if (msg_type == to_string(mtx::events::EventType::KeyVerificationMac)) {
|
||||||
auto message =
|
auto message =
|
||||||
std::get<mtx::events::DeviceEvent<mtx::events::msg::KeyVerificationMac>>(
|
std::get<mtx::events::DeviceEvent<mtx::events::msg::KeyVerificationMac>>(
|
||||||
msg);
|
msg);
|
||||||
ChatPage::instance()->recievedDeviceVerificationMac(message.content);
|
ChatPage::instance()->receivedDeviceVerificationMac(message.content);
|
||||||
} else if (msg_type == to_string(mtx::events::EventType::KeyVerificationStart)) {
|
} else if (msg_type == to_string(mtx::events::EventType::KeyVerificationStart)) {
|
||||||
auto message = std::get<
|
auto message = std::get<
|
||||||
mtx::events::DeviceEvent<mtx::events::msg::KeyVerificationStart>>(msg);
|
mtx::events::DeviceEvent<mtx::events::msg::KeyVerificationStart>>(msg);
|
||||||
ChatPage::instance()->recievedDeviceVerificationStart(message.content,
|
ChatPage::instance()->receivedDeviceVerificationStart(message.content,
|
||||||
message.sender);
|
message.sender);
|
||||||
} else if (msg_type == to_string(mtx::events::EventType::KeyVerificationReady)) {
|
} else if (msg_type == to_string(mtx::events::EventType::KeyVerificationReady)) {
|
||||||
auto message = std::get<
|
auto message = std::get<
|
||||||
mtx::events::DeviceEvent<mtx::events::msg::KeyVerificationReady>>(msg);
|
mtx::events::DeviceEvent<mtx::events::msg::KeyVerificationReady>>(msg);
|
||||||
ChatPage::instance()->recievedDeviceVerificationReady(message.content);
|
ChatPage::instance()->receivedDeviceVerificationReady(message.content);
|
||||||
} else if (msg_type == to_string(mtx::events::EventType::KeyVerificationDone)) {
|
} else if (msg_type == to_string(mtx::events::EventType::KeyVerificationDone)) {
|
||||||
auto message =
|
auto message =
|
||||||
std::get<mtx::events::DeviceEvent<mtx::events::msg::KeyVerificationDone>>(
|
std::get<mtx::events::DeviceEvent<mtx::events::msg::KeyVerificationDone>>(
|
||||||
msg);
|
msg);
|
||||||
ChatPage::instance()->recievedDeviceVerificationDone(message.content);
|
ChatPage::instance()->receivedDeviceVerificationDone(message.content);
|
||||||
} else {
|
} else {
|
||||||
nhlog::crypto()->warn("unhandled event: {}", j_msg.dump(2));
|
nhlog::crypto()->warn("unhandled event: {}", j_msg.dump(2));
|
||||||
}
|
}
|
||||||
@ -153,42 +153,42 @@ handle_olm_message(const OlmMessage &msg)
|
|||||||
std::string msg_type = payload["type"];
|
std::string msg_type = payload["type"];
|
||||||
|
|
||||||
if (msg_type == to_string(mtx::events::EventType::KeyVerificationAccept)) {
|
if (msg_type == to_string(mtx::events::EventType::KeyVerificationAccept)) {
|
||||||
ChatPage::instance()->recievedDeviceVerificationAccept(
|
ChatPage::instance()->receivedDeviceVerificationAccept(
|
||||||
payload["content"]);
|
payload["content"]);
|
||||||
return;
|
return;
|
||||||
} else if (msg_type ==
|
} else if (msg_type ==
|
||||||
to_string(mtx::events::EventType::KeyVerificationRequest)) {
|
to_string(mtx::events::EventType::KeyVerificationRequest)) {
|
||||||
ChatPage::instance()->recievedDeviceVerificationRequest(
|
ChatPage::instance()->receivedDeviceVerificationRequest(
|
||||||
payload["content"], payload["sender"]);
|
payload["content"], payload["sender"]);
|
||||||
return;
|
return;
|
||||||
} else if (msg_type ==
|
} else if (msg_type ==
|
||||||
to_string(mtx::events::EventType::KeyVerificationCancel)) {
|
to_string(mtx::events::EventType::KeyVerificationCancel)) {
|
||||||
ChatPage::instance()->recievedDeviceVerificationCancel(
|
ChatPage::instance()->receivedDeviceVerificationCancel(
|
||||||
payload["content"]);
|
payload["content"]);
|
||||||
return;
|
return;
|
||||||
} else if (msg_type ==
|
} else if (msg_type ==
|
||||||
to_string(mtx::events::EventType::KeyVerificationKey)) {
|
to_string(mtx::events::EventType::KeyVerificationKey)) {
|
||||||
ChatPage::instance()->recievedDeviceVerificationKey(
|
ChatPage::instance()->receivedDeviceVerificationKey(
|
||||||
payload["content"]);
|
payload["content"]);
|
||||||
return;
|
return;
|
||||||
} else if (msg_type ==
|
} else if (msg_type ==
|
||||||
to_string(mtx::events::EventType::KeyVerificationMac)) {
|
to_string(mtx::events::EventType::KeyVerificationMac)) {
|
||||||
ChatPage::instance()->recievedDeviceVerificationMac(
|
ChatPage::instance()->receivedDeviceVerificationMac(
|
||||||
payload["content"]);
|
payload["content"]);
|
||||||
return;
|
return;
|
||||||
} else if (msg_type ==
|
} else if (msg_type ==
|
||||||
to_string(mtx::events::EventType::KeyVerificationStart)) {
|
to_string(mtx::events::EventType::KeyVerificationStart)) {
|
||||||
ChatPage::instance()->recievedDeviceVerificationStart(
|
ChatPage::instance()->receivedDeviceVerificationStart(
|
||||||
payload["content"], payload["sender"]);
|
payload["content"], payload["sender"]);
|
||||||
return;
|
return;
|
||||||
} else if (msg_type ==
|
} else if (msg_type ==
|
||||||
to_string(mtx::events::EventType::KeyVerificationReady)) {
|
to_string(mtx::events::EventType::KeyVerificationReady)) {
|
||||||
ChatPage::instance()->recievedDeviceVerificationReady(
|
ChatPage::instance()->receivedDeviceVerificationReady(
|
||||||
payload["content"]);
|
payload["content"]);
|
||||||
return;
|
return;
|
||||||
} else if (msg_type ==
|
} else if (msg_type ==
|
||||||
to_string(mtx::events::EventType::KeyVerificationDone)) {
|
to_string(mtx::events::EventType::KeyVerificationDone)) {
|
||||||
ChatPage::instance()->recievedDeviceVerificationDone(
|
ChatPage::instance()->receivedDeviceVerificationDone(
|
||||||
payload["content"]);
|
payload["content"]);
|
||||||
return;
|
return;
|
||||||
} else if (msg_type == to_string(mtx::events::EventType::RoomKey)) {
|
} else if (msg_type == to_string(mtx::events::EventType::RoomKey)) {
|
||||||
|
@ -299,7 +299,7 @@ EventStore::handleSync(const mtx::responses::Timeline &events)
|
|||||||
mtx::events::msg::KeyVerificationReady>>(d_event)) {
|
mtx::events::msg::KeyVerificationReady>>(d_event)) {
|
||||||
auto msg = std::get_if<mtx::events::RoomEvent<
|
auto msg = std::get_if<mtx::events::RoomEvent<
|
||||||
mtx::events::msg::KeyVerificationReady>>(d_event);
|
mtx::events::msg::KeyVerificationReady>>(d_event);
|
||||||
ChatPage::instance()->recievedDeviceVerificationReady(
|
ChatPage::instance()->receivedDeviceVerificationReady(
|
||||||
msg->content);
|
msg->content);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -328,43 +328,43 @@ EventStore::handle_room_verification(mtx::events::collections::TimelineEvents ev
|
|||||||
auto msg =
|
auto msg =
|
||||||
std::get<mtx::events::RoomEvent<mtx::events::msg::KeyVerificationCancel>>(event);
|
std::get<mtx::events::RoomEvent<mtx::events::msg::KeyVerificationCancel>>(event);
|
||||||
last_verification_cancel_event = msg;
|
last_verification_cancel_event = msg;
|
||||||
ChatPage::instance()->recievedDeviceVerificationCancel(msg.content);
|
ChatPage::instance()->receivedDeviceVerificationCancel(msg.content);
|
||||||
return;
|
return;
|
||||||
} else if (std::get_if<mtx::events::RoomEvent<mtx::events::msg::KeyVerificationAccept>>(
|
} else if (std::get_if<mtx::events::RoomEvent<mtx::events::msg::KeyVerificationAccept>>(
|
||||||
&event)) {
|
&event)) {
|
||||||
auto msg =
|
auto msg =
|
||||||
std::get<mtx::events::RoomEvent<mtx::events::msg::KeyVerificationAccept>>(event);
|
std::get<mtx::events::RoomEvent<mtx::events::msg::KeyVerificationAccept>>(event);
|
||||||
ChatPage::instance()->recievedDeviceVerificationAccept(msg.content);
|
ChatPage::instance()->receivedDeviceVerificationAccept(msg.content);
|
||||||
return;
|
return;
|
||||||
} else if (std::get_if<mtx::events::RoomEvent<mtx::events::msg::KeyVerificationKey>>(
|
} else if (std::get_if<mtx::events::RoomEvent<mtx::events::msg::KeyVerificationKey>>(
|
||||||
&event)) {
|
&event)) {
|
||||||
auto msg =
|
auto msg =
|
||||||
std::get<mtx::events::RoomEvent<mtx::events::msg::KeyVerificationKey>>(event);
|
std::get<mtx::events::RoomEvent<mtx::events::msg::KeyVerificationKey>>(event);
|
||||||
ChatPage::instance()->recievedDeviceVerificationKey(msg.content);
|
ChatPage::instance()->receivedDeviceVerificationKey(msg.content);
|
||||||
return;
|
return;
|
||||||
} else if (std::get_if<mtx::events::RoomEvent<mtx::events::msg::KeyVerificationMac>>(
|
} else if (std::get_if<mtx::events::RoomEvent<mtx::events::msg::KeyVerificationMac>>(
|
||||||
&event)) {
|
&event)) {
|
||||||
auto msg =
|
auto msg =
|
||||||
std::get<mtx::events::RoomEvent<mtx::events::msg::KeyVerificationMac>>(event);
|
std::get<mtx::events::RoomEvent<mtx::events::msg::KeyVerificationMac>>(event);
|
||||||
ChatPage::instance()->recievedDeviceVerificationMac(msg.content);
|
ChatPage::instance()->receivedDeviceVerificationMac(msg.content);
|
||||||
return;
|
return;
|
||||||
} else if (std::get_if<mtx::events::RoomEvent<mtx::events::msg::KeyVerificationReady>>(
|
} else if (std::get_if<mtx::events::RoomEvent<mtx::events::msg::KeyVerificationReady>>(
|
||||||
&event)) {
|
&event)) {
|
||||||
auto msg =
|
auto msg =
|
||||||
std::get<mtx::events::RoomEvent<mtx::events::msg::KeyVerificationReady>>(event);
|
std::get<mtx::events::RoomEvent<mtx::events::msg::KeyVerificationReady>>(event);
|
||||||
ChatPage::instance()->recievedDeviceVerificationReady(msg.content);
|
ChatPage::instance()->receivedDeviceVerificationReady(msg.content);
|
||||||
return;
|
return;
|
||||||
} else if (std::get_if<mtx::events::RoomEvent<mtx::events::msg::KeyVerificationDone>>(
|
} else if (std::get_if<mtx::events::RoomEvent<mtx::events::msg::KeyVerificationDone>>(
|
||||||
&event)) {
|
&event)) {
|
||||||
auto msg =
|
auto msg =
|
||||||
std::get<mtx::events::RoomEvent<mtx::events::msg::KeyVerificationDone>>(event);
|
std::get<mtx::events::RoomEvent<mtx::events::msg::KeyVerificationDone>>(event);
|
||||||
ChatPage::instance()->recievedDeviceVerificationDone(msg.content);
|
ChatPage::instance()->receivedDeviceVerificationDone(msg.content);
|
||||||
return;
|
return;
|
||||||
} else if (std::get_if<mtx::events::RoomEvent<mtx::events::msg::KeyVerificationStart>>(
|
} else if (std::get_if<mtx::events::RoomEvent<mtx::events::msg::KeyVerificationStart>>(
|
||||||
&event)) {
|
&event)) {
|
||||||
auto msg =
|
auto msg =
|
||||||
std::get<mtx::events::RoomEvent<mtx::events::msg::KeyVerificationStart>>(event);
|
std::get<mtx::events::RoomEvent<mtx::events::msg::KeyVerificationStart>>(event);
|
||||||
ChatPage::instance()->recievedDeviceVerificationStart(msg.content, msg.sender);
|
ChatPage::instance()->receivedDeviceVerificationStart(msg.content, msg.sender);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -254,7 +254,7 @@ TimelineModel::TimelineModel(TimelineViewManager *manager, QString room_id, QObj
|
|||||||
&EventStore::startDMVerification,
|
&EventStore::startDMVerification,
|
||||||
this,
|
this,
|
||||||
[this](mtx::events::RoomEvent<mtx::events::msg::KeyVerificationRequest> msg) {
|
[this](mtx::events::RoomEvent<mtx::events::msg::KeyVerificationRequest> msg) {
|
||||||
ChatPage::instance()->recievedRoomDeviceVerificationRequest(msg, this);
|
ChatPage::instance()->receivedRoomDeviceVerificationRequest(msg, this);
|
||||||
});
|
});
|
||||||
connect(&events, &EventStore::updateFlowEventId, this, [this](std::string event_id) {
|
connect(&events, &EventStore::updateFlowEventId, this, [this](std::string event_id) {
|
||||||
this->updateFlowEventId(event_id);
|
this->updateFlowEventId(event_id);
|
||||||
@ -793,7 +793,7 @@ TimelineModel::viewDecryptedRawMessage(QString id) const
|
|||||||
void
|
void
|
||||||
TimelineModel::openUserProfile(QString userid)
|
TimelineModel::openUserProfile(QString userid)
|
||||||
{
|
{
|
||||||
emit openProfile(new UserProfile(room_id_, userid, this));
|
emit openProfile(new UserProfile(room_id_, userid, manager_, this));
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
|
@ -28,22 +28,6 @@ Q_DECLARE_METATYPE(std::vector<DeviceInfo>)
|
|||||||
|
|
||||||
namespace msgs = mtx::events::msg;
|
namespace msgs = mtx::events::msg;
|
||||||
|
|
||||||
void
|
|
||||||
DeviceVerificationList::add(QString tran_id)
|
|
||||||
{
|
|
||||||
this->deviceVerificationList.push_back(tran_id);
|
|
||||||
}
|
|
||||||
void
|
|
||||||
DeviceVerificationList::remove(QString tran_id)
|
|
||||||
{
|
|
||||||
this->deviceVerificationList.removeOne(tran_id);
|
|
||||||
}
|
|
||||||
bool
|
|
||||||
DeviceVerificationList::exist(QString tran_id)
|
|
||||||
{
|
|
||||||
return this->deviceVerificationList.contains(tran_id);
|
|
||||||
}
|
|
||||||
|
|
||||||
void
|
void
|
||||||
TimelineViewManager::updateEncryptedDescriptions()
|
TimelineViewManager::updateEncryptedDescriptions()
|
||||||
{
|
{
|
||||||
@ -134,7 +118,8 @@ TimelineViewManager::TimelineViewManager(QSharedPointer<UserSettings> userSettin
|
|||||||
|
|
||||||
qmlRegisterType<DelegateChoice>("im.nheko", 1, 0, "DelegateChoice");
|
qmlRegisterType<DelegateChoice>("im.nheko", 1, 0, "DelegateChoice");
|
||||||
qmlRegisterType<DelegateChooser>("im.nheko", 1, 0, "DelegateChooser");
|
qmlRegisterType<DelegateChooser>("im.nheko", 1, 0, "DelegateChooser");
|
||||||
qmlRegisterType<DeviceVerificationFlow>("im.nheko", 1, 0, "DeviceVerificationFlow");
|
qmlRegisterUncreatableType<DeviceVerificationFlow>(
|
||||||
|
"im.nheko", 1, 0, "DeviceVerificationFlow", "Can't create verification flow from QML!");
|
||||||
qmlRegisterUncreatableType<UserProfile>(
|
qmlRegisterUncreatableType<UserProfile>(
|
||||||
"im.nheko",
|
"im.nheko",
|
||||||
1,
|
1,
|
||||||
@ -163,7 +148,6 @@ TimelineViewManager::TimelineViewManager(QSharedPointer<UserSettings> userSettin
|
|||||||
0,
|
0,
|
||||||
"EmojiCategory",
|
"EmojiCategory",
|
||||||
"Error: Only enums");
|
"Error: Only enums");
|
||||||
this->dvList = new DeviceVerificationList;
|
|
||||||
|
|
||||||
#ifdef USE_QUICK_VIEW
|
#ifdef USE_QUICK_VIEW
|
||||||
view = new QQuickView();
|
view = new QQuickView();
|
||||||
@ -183,7 +167,6 @@ TimelineViewManager::TimelineViewManager(QSharedPointer<UserSettings> userSettin
|
|||||||
});
|
});
|
||||||
#endif
|
#endif
|
||||||
container->setMinimumSize(200, 200);
|
container->setMinimumSize(200, 200);
|
||||||
view->rootContext()->setContextProperty("deviceVerificationList", this->dvList);
|
|
||||||
updateColorPalette();
|
updateColorPalette();
|
||||||
view->engine()->addImageProvider("MxcImage", imgProvider);
|
view->engine()->addImageProvider("MxcImage", imgProvider);
|
||||||
view->engine()->addImageProvider("colorimage", colorImgProvider);
|
view->engine()->addImageProvider("colorimage", colorImgProvider);
|
||||||
@ -197,99 +180,52 @@ TimelineViewManager::TimelineViewManager(QSharedPointer<UserSettings> userSettin
|
|||||||
&TimelineViewManager::updateEncryptedDescriptions);
|
&TimelineViewManager::updateEncryptedDescriptions);
|
||||||
connect(
|
connect(
|
||||||
dynamic_cast<ChatPage *>(parent),
|
dynamic_cast<ChatPage *>(parent),
|
||||||
&ChatPage::recievedRoomDeviceVerificationRequest,
|
&ChatPage::receivedRoomDeviceVerificationRequest,
|
||||||
this,
|
this,
|
||||||
[this](const mtx::events::RoomEvent<mtx::events::msg::KeyVerificationRequest> &message,
|
[this](const mtx::events::RoomEvent<mtx::events::msg::KeyVerificationRequest> &message,
|
||||||
TimelineModel *model) {
|
TimelineModel *model) {
|
||||||
if (!(this->dvList->exist(QString::fromStdString(message.event_id)))) {
|
auto event_id = QString::fromStdString(message.event_id);
|
||||||
auto flow = new DeviceVerificationFlow(
|
if (!this->dvList.contains(event_id)) {
|
||||||
this, DeviceVerificationFlow::Type::RoomMsg, model);
|
if (auto flow = DeviceVerificationFlow::NewInRoomVerification(
|
||||||
if (std::find(message.content.methods.begin(),
|
this,
|
||||||
message.content.methods.end(),
|
model,
|
||||||
mtx::events::msg::VerificationMethods::SASv1) !=
|
message.content,
|
||||||
message.content.methods.end()) {
|
|
||||||
flow->setEventId(message.event_id);
|
|
||||||
emit newDeviceVerificationRequest(
|
|
||||||
std::move(flow),
|
|
||||||
QString::fromStdString(message.event_id),
|
|
||||||
QString::fromStdString(message.sender),
|
QString::fromStdString(message.sender),
|
||||||
QString::fromStdString(message.content.from_device),
|
event_id)) {
|
||||||
true);
|
dvList[event_id] = flow;
|
||||||
} else {
|
emit newDeviceVerificationRequest(flow.data());
|
||||||
flow->cancelVerification(
|
|
||||||
DeviceVerificationFlow::Error::UnknownMethod);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
connect(
|
connect(dynamic_cast<ChatPage *>(parent),
|
||||||
dynamic_cast<ChatPage *>(parent),
|
&ChatPage::receivedDeviceVerificationRequest,
|
||||||
&ChatPage::recievedDeviceVerificationRequest,
|
|
||||||
this,
|
this,
|
||||||
[this](const mtx::events::msg::KeyVerificationRequest &msg, std::string sender) {
|
[this](const mtx::events::msg::KeyVerificationRequest &msg, std::string sender) {
|
||||||
if (!(this->dvList->exist(QString::fromStdString(msg.transaction_id.value())))) {
|
if (!msg.transaction_id)
|
||||||
auto flow = new DeviceVerificationFlow(this);
|
return;
|
||||||
if (std::find(msg.methods.begin(),
|
|
||||||
msg.methods.end(),
|
auto txnid = QString::fromStdString(msg.transaction_id.value());
|
||||||
mtx::events::msg::VerificationMethods::SASv1) !=
|
if (!this->dvList.contains(txnid)) {
|
||||||
msg.methods.end()) {
|
if (auto flow = DeviceVerificationFlow::NewToDeviceVerification(
|
||||||
emit newDeviceVerificationRequest(
|
this, msg, QString::fromStdString(sender), txnid)) {
|
||||||
std::move(flow),
|
dvList[txnid] = flow;
|
||||||
QString::fromStdString(msg.transaction_id.value()),
|
emit newDeviceVerificationRequest(flow.data());
|
||||||
QString::fromStdString(sender),
|
|
||||||
QString::fromStdString(msg.from_device));
|
|
||||||
} else {
|
|
||||||
flow->cancelVerification(
|
|
||||||
DeviceVerificationFlow::Error::UnknownMethod);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
connect(
|
connect(dynamic_cast<ChatPage *>(parent),
|
||||||
dynamic_cast<ChatPage *>(parent),
|
&ChatPage::receivedDeviceVerificationStart,
|
||||||
&ChatPage::recievedDeviceVerificationStart,
|
|
||||||
this,
|
this,
|
||||||
[this](const mtx::events::msg::KeyVerificationStart &msg, std::string sender) {
|
[this](const mtx::events::msg::KeyVerificationStart &msg, std::string sender) {
|
||||||
if (msg.transaction_id.has_value()) {
|
if (!msg.transaction_id)
|
||||||
if (!(this->dvList->exist(
|
|
||||||
QString::fromStdString(msg.transaction_id.value())))) {
|
|
||||||
auto flow = new DeviceVerificationFlow(this);
|
|
||||||
flow->canonical_json = nlohmann::json(msg);
|
|
||||||
if ((std::find(msg.key_agreement_protocols.begin(),
|
|
||||||
msg.key_agreement_protocols.end(),
|
|
||||||
"curve25519-hkdf-sha256") !=
|
|
||||||
msg.key_agreement_protocols.end()) &&
|
|
||||||
(std::find(msg.hashes.begin(), msg.hashes.end(), "sha256") !=
|
|
||||||
msg.hashes.end()) &&
|
|
||||||
(std::find(msg.message_authentication_codes.begin(),
|
|
||||||
msg.message_authentication_codes.end(),
|
|
||||||
"hmac-sha256") !=
|
|
||||||
msg.message_authentication_codes.end())) {
|
|
||||||
if (std::find(msg.short_authentication_string.begin(),
|
|
||||||
msg.short_authentication_string.end(),
|
|
||||||
mtx::events::msg::SASMethods::Emoji) !=
|
|
||||||
msg.short_authentication_string.end()) {
|
|
||||||
flow->setMethod(
|
|
||||||
DeviceVerificationFlow::Method::Emoji);
|
|
||||||
} else if (std::find(
|
|
||||||
msg.short_authentication_string.begin(),
|
|
||||||
msg.short_authentication_string.end(),
|
|
||||||
mtx::events::msg::SASMethods::Decimal) !=
|
|
||||||
msg.short_authentication_string.end()) {
|
|
||||||
flow->setMethod(
|
|
||||||
DeviceVerificationFlow::Method::Decimal);
|
|
||||||
} else {
|
|
||||||
flow->cancelVerification(
|
|
||||||
DeviceVerificationFlow::Error::UnknownMethod);
|
|
||||||
return;
|
return;
|
||||||
}
|
|
||||||
emit newDeviceVerificationRequest(
|
auto txnid = QString::fromStdString(msg.transaction_id.value());
|
||||||
std::move(flow),
|
if (!this->dvList.contains(txnid)) {
|
||||||
QString::fromStdString(msg.transaction_id.value()),
|
if (auto flow = DeviceVerificationFlow::NewToDeviceVerification(
|
||||||
QString::fromStdString(sender),
|
this, msg, QString::fromStdString(sender), txnid)) {
|
||||||
QString::fromStdString(msg.from_device));
|
dvList[txnid] = flow;
|
||||||
} else {
|
emit newDeviceVerificationRequest(flow.data());
|
||||||
flow->cancelVerification(
|
|
||||||
DeviceVerificationFlow::Error::UnknownMethod);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
@ -428,6 +364,46 @@ TimelineViewManager::openRoomSettings() const
|
|||||||
MainWindow::instance()->openRoomSettings(timeline_->roomId());
|
MainWindow::instance()->openRoomSettings(timeline_->roomId());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
TimelineViewManager::verifyUser(QString userid)
|
||||||
|
{
|
||||||
|
auto joined_rooms = cache::joinedRooms();
|
||||||
|
auto room_infos = cache::getRoomInfo(joined_rooms);
|
||||||
|
|
||||||
|
for (std::string room_id : joined_rooms) {
|
||||||
|
if ((room_infos[QString::fromStdString(room_id)].member_count == 2) &&
|
||||||
|
cache::isRoomEncrypted(room_id)) {
|
||||||
|
auto room_members = cache::roomMembers(room_id);
|
||||||
|
if (std::find(room_members.begin(),
|
||||||
|
room_members.end(),
|
||||||
|
(userid).toStdString()) != room_members.end()) {
|
||||||
|
auto model = models.value(QString::fromStdString(room_id));
|
||||||
|
auto flow = DeviceVerificationFlow::InitiateUserVerification(
|
||||||
|
this, model.data(), userid);
|
||||||
|
connect(model.data(),
|
||||||
|
&TimelineModel::updateFlowEventId,
|
||||||
|
this,
|
||||||
|
[this, flow](std::string eventId) {
|
||||||
|
dvList[QString::fromStdString(eventId)] = flow;
|
||||||
|
});
|
||||||
|
emit newDeviceVerificationRequest(flow.data());
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
emit ChatPage::instance()->showNotification(
|
||||||
|
tr("No share room with this user found. Create an "
|
||||||
|
"encrypted room with this user and try again."));
|
||||||
|
}
|
||||||
|
void
|
||||||
|
TimelineViewManager::verifyDevice(QString userid, QString deviceid)
|
||||||
|
{
|
||||||
|
auto flow = DeviceVerificationFlow::InitiateDeviceVerification(this, userid, deviceid);
|
||||||
|
this->dvList[flow->transactionId()] = flow;
|
||||||
|
emit newDeviceVerificationRequest(flow.data());
|
||||||
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
TimelineViewManager::updateReadReceipts(const QString &room_id,
|
TimelineViewManager::updateReadReceipts(const QString &room_id,
|
||||||
const std::vector<QString> &event_ids)
|
const std::vector<QString> &event_ids)
|
||||||
|
@ -24,20 +24,6 @@ class ColorImageProvider;
|
|||||||
class UserSettings;
|
class UserSettings;
|
||||||
class ChatPage;
|
class ChatPage;
|
||||||
|
|
||||||
class DeviceVerificationList : public QObject
|
|
||||||
{
|
|
||||||
Q_OBJECT
|
|
||||||
public:
|
|
||||||
Q_INVOKABLE void add(QString tran_id);
|
|
||||||
Q_INVOKABLE void remove(QString tran_id);
|
|
||||||
Q_INVOKABLE bool exist(QString tran_id);
|
|
||||||
signals:
|
|
||||||
void updateProfile(QString userId);
|
|
||||||
|
|
||||||
private:
|
|
||||||
QVector<QString> deviceVerificationList;
|
|
||||||
};
|
|
||||||
|
|
||||||
class TimelineViewManager : public QObject
|
class TimelineViewManager : public QObject
|
||||||
{
|
{
|
||||||
Q_OBJECT
|
Q_OBJECT
|
||||||
@ -77,6 +63,9 @@ public:
|
|||||||
Q_INVOKABLE void openLeaveRoomDialog() const;
|
Q_INVOKABLE void openLeaveRoomDialog() const;
|
||||||
Q_INVOKABLE void openRoomSettings() const;
|
Q_INVOKABLE void openRoomSettings() const;
|
||||||
|
|
||||||
|
void verifyUser(QString userid);
|
||||||
|
void verifyDevice(QString userid, QString deviceid);
|
||||||
|
|
||||||
signals:
|
signals:
|
||||||
void clearRoomMessageCount(QString roomid);
|
void clearRoomMessageCount(QString roomid);
|
||||||
void updateRoomsLastMessage(QString roomid, const DescInfo &info);
|
void updateRoomsLastMessage(QString roomid, const DescInfo &info);
|
||||||
@ -84,11 +73,7 @@ signals:
|
|||||||
void initialSyncChanged(bool isInitialSync);
|
void initialSyncChanged(bool isInitialSync);
|
||||||
void replyingEventChanged(QString replyingEvent);
|
void replyingEventChanged(QString replyingEvent);
|
||||||
void replyClosed();
|
void replyClosed();
|
||||||
void newDeviceVerificationRequest(DeviceVerificationFlow *flow,
|
void newDeviceVerificationRequest(DeviceVerificationFlow *flow);
|
||||||
QString transactionId,
|
|
||||||
QString userId,
|
|
||||||
QString deviceId,
|
|
||||||
bool isRequest = false);
|
|
||||||
void inviteUsers(QStringList users);
|
void inviteUsers(QStringList users);
|
||||||
void showRoomList();
|
void showRoomList();
|
||||||
void narrowViewChanged();
|
void narrowViewChanged();
|
||||||
@ -180,7 +165,7 @@ private:
|
|||||||
QSharedPointer<UserSettings> settings;
|
QSharedPointer<UserSettings> settings;
|
||||||
QHash<QString, QColor> userColors;
|
QHash<QString, QColor> userColors;
|
||||||
|
|
||||||
DeviceVerificationList *dvList;
|
QHash<QString, QSharedPointer<DeviceVerificationFlow>> dvList;
|
||||||
};
|
};
|
||||||
Q_DECLARE_METATYPE(mtx::events::msg::KeyVerificationAccept)
|
Q_DECLARE_METATYPE(mtx::events::msg::KeyVerificationAccept)
|
||||||
Q_DECLARE_METATYPE(mtx::events::msg::KeyVerificationCancel)
|
Q_DECLARE_METATYPE(mtx::events::msg::KeyVerificationCancel)
|
||||||
|
@ -6,13 +6,18 @@
|
|||||||
#include "Utils.h"
|
#include "Utils.h"
|
||||||
#include "mtx/responses/crypto.hpp"
|
#include "mtx/responses/crypto.hpp"
|
||||||
#include "timeline/TimelineModel.h"
|
#include "timeline/TimelineModel.h"
|
||||||
|
#include "timeline/TimelineViewManager.h"
|
||||||
|
|
||||||
#include <iostream> // only for debugging
|
#include <iostream> // only for debugging
|
||||||
|
|
||||||
UserProfile::UserProfile(QString roomid, QString userid, TimelineModel *parent)
|
UserProfile::UserProfile(QString roomid,
|
||||||
|
QString userid,
|
||||||
|
TimelineViewManager *manager_,
|
||||||
|
TimelineModel *parent)
|
||||||
: QObject(parent)
|
: QObject(parent)
|
||||||
, roomid_(roomid)
|
, roomid_(roomid)
|
||||||
, userid_(userid)
|
, userid_(userid)
|
||||||
|
, manager(manager_)
|
||||||
, model(parent)
|
, model(parent)
|
||||||
{
|
{
|
||||||
fetchDeviceList(this->userid_);
|
fetchDeviceList(this->userid_);
|
||||||
@ -270,44 +275,18 @@ UserProfile::startChat()
|
|||||||
emit ChatPage::instance()->createRoom(req);
|
emit ChatPage::instance()->createRoom(req);
|
||||||
}
|
}
|
||||||
|
|
||||||
DeviceVerificationFlow *
|
void
|
||||||
UserProfile::createFlow(bool isVerifyUser)
|
UserProfile::verify(QString device)
|
||||||
{
|
{
|
||||||
if (!isVerifyUser)
|
if (!device.isEmpty())
|
||||||
return (new DeviceVerificationFlow(this, DeviceVerificationFlow::Type::ToDevice));
|
manager->verifyDevice(userid_, device);
|
||||||
else {
|
else {
|
||||||
std::cout << "CHECKING IF IT TO START ROOM_VERIFICATION OR TO_DEVICE VERIFICATION"
|
manager->verifyUser(userid_);
|
||||||
<< std::endl;
|
|
||||||
auto joined_rooms = cache::joinedRooms();
|
|
||||||
auto room_infos = cache::getRoomInfo(joined_rooms);
|
|
||||||
|
|
||||||
for (std::string room_id : joined_rooms) {
|
|
||||||
if ((room_infos[QString::fromStdString(room_id)].member_count == 2) &&
|
|
||||||
cache::isRoomEncrypted(room_id)) {
|
|
||||||
auto room_members = cache::roomMembers(room_id);
|
|
||||||
if (std::find(room_members.begin(),
|
|
||||||
room_members.end(),
|
|
||||||
(this->userid()).toStdString()) !=
|
|
||||||
room_members.end()) {
|
|
||||||
std::cout
|
|
||||||
<< "FOUND A ENCRYPTED ROOM WITH THIS USER : " << room_id
|
|
||||||
<< std::endl;
|
|
||||||
if (this->roomid_.toStdString() == room_id) {
|
|
||||||
auto newflow = new DeviceVerificationFlow(
|
|
||||||
this,
|
|
||||||
DeviceVerificationFlow::Type::RoomMsg,
|
|
||||||
this->model);
|
|
||||||
return (std::move(newflow));
|
|
||||||
} else {
|
|
||||||
std::cout << "FOUND A ENCRYPTED ROOM BUT CURRENTLY "
|
|
||||||
"NOT IN THAT ROOM : "
|
|
||||||
<< room_id << std::endl;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
std::cout << "DIDN'T FIND A ENCRYPTED ROOM WITH THIS USER" << std::endl;
|
void
|
||||||
return (new DeviceVerificationFlow(this, DeviceVerificationFlow::Type::ToDevice));
|
UserProfile::unverify(QString device)
|
||||||
}
|
{
|
||||||
|
cache::markDeviceUnverified(userid_.toStdString(), device.toStdString());
|
||||||
}
|
}
|
||||||
|
@ -21,6 +21,7 @@ Q_ENUM_NS(Status)
|
|||||||
|
|
||||||
class DeviceVerificationFlow;
|
class DeviceVerificationFlow;
|
||||||
class TimelineModel;
|
class TimelineModel;
|
||||||
|
class TimelineViewManager;
|
||||||
|
|
||||||
class DeviceInfo
|
class DeviceInfo
|
||||||
{
|
{
|
||||||
@ -84,7 +85,10 @@ class UserProfile : public QObject
|
|||||||
Q_PROPERTY(DeviceInfoModel *deviceList READ deviceList CONSTANT)
|
Q_PROPERTY(DeviceInfoModel *deviceList READ deviceList CONSTANT)
|
||||||
Q_PROPERTY(bool isUserVerified READ getUserStatus CONSTANT)
|
Q_PROPERTY(bool isUserVerified READ getUserStatus CONSTANT)
|
||||||
public:
|
public:
|
||||||
UserProfile(QString roomid, QString userid, TimelineModel *parent = nullptr);
|
UserProfile(QString roomid,
|
||||||
|
QString userid,
|
||||||
|
TimelineViewManager *manager_,
|
||||||
|
TimelineModel *parent = nullptr);
|
||||||
|
|
||||||
DeviceInfoModel *deviceList();
|
DeviceInfoModel *deviceList();
|
||||||
|
|
||||||
@ -93,7 +97,8 @@ public:
|
|||||||
QString avatarUrl();
|
QString avatarUrl();
|
||||||
bool getUserStatus();
|
bool getUserStatus();
|
||||||
|
|
||||||
Q_INVOKABLE DeviceVerificationFlow *createFlow(bool isVerifyUser);
|
Q_INVOKABLE void verify(QString device = "");
|
||||||
|
Q_INVOKABLE void unverify(QString device = "");
|
||||||
Q_INVOKABLE void fetchDeviceList(const QString &userID);
|
Q_INVOKABLE void fetchDeviceList(const QString &userID);
|
||||||
Q_INVOKABLE void banUser();
|
Q_INVOKABLE void banUser();
|
||||||
// Q_INVOKABLE void ignoreUser();
|
// Q_INVOKABLE void ignoreUser();
|
||||||
@ -105,6 +110,7 @@ private:
|
|||||||
std::optional<std::string> cross_verified;
|
std::optional<std::string> cross_verified;
|
||||||
DeviceInfoModel deviceList_;
|
DeviceInfoModel deviceList_;
|
||||||
bool isUserVerified = false;
|
bool isUserVerified = false;
|
||||||
|
TimelineViewManager *manager;
|
||||||
TimelineModel *model;
|
TimelineModel *model;
|
||||||
|
|
||||||
void callback_fn(const mtx::responses::QueryKeys &res,
|
void callback_fn(const mtx::responses::QueryKeys &res,
|
||||||
|
Loading…
Reference in New Issue
Block a user