QRCode: add other_device_key field and make it optional, along with other_user_key
This commit is contained in:
parent
6282f81bc4
commit
fb98d6ef42
|
@ -733,7 +733,7 @@ internal class DefaultVerificationService @Inject constructor(
|
||||||
// Check if other user is able to scan QR code
|
// Check if other user is able to scan QR code
|
||||||
?.takeIf { it.contains(VERIFICATION_METHOD_QR_CODE_SCAN) }
|
?.takeIf { it.contains(VERIFICATION_METHOD_QR_CODE_SCAN) }
|
||||||
?.let {
|
?.let {
|
||||||
createQrCodeData(existingRequest.transactionId, existingRequest.otherUserId)
|
createQrCodeData(existingRequest.transactionId, existingRequest.otherUserId, readyReq.fromDevice)
|
||||||
}
|
}
|
||||||
|
|
||||||
if (readyReq.methods.orEmpty().contains(VERIFICATION_METHOD_RECIPROCATE)) {
|
if (readyReq.methods.orEmpty().contains(VERIFICATION_METHOD_RECIPROCATE)) {
|
||||||
|
@ -760,13 +760,25 @@ internal class DefaultVerificationService @Inject constructor(
|
||||||
))
|
))
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun createQrCodeData(transactionId: String?, otherUserId: String): QrCodeData? {
|
private fun createQrCodeData(requestEventId: String?, otherUserId: String, otherDeviceId: String?): QrCodeData? {
|
||||||
// Build the QR code URL
|
requestEventId ?: run {
|
||||||
val requestEventId = transactionId ?: run {
|
|
||||||
Timber.w("## Unknown requestEventId")
|
Timber.w("## Unknown requestEventId")
|
||||||
return null
|
return null
|
||||||
}
|
}
|
||||||
|
|
||||||
|
return when {
|
||||||
|
userId != otherUserId ->
|
||||||
|
createQrCodeDataForDistinctUser(requestEventId, otherUserId, otherDeviceId)
|
||||||
|
crossSigningService.isCrossSigningVerified() ->
|
||||||
|
// This is a self verification and I am the old device (Osborne2)
|
||||||
|
createQrCodeDataForVerifiedDevice(requestEventId, otherDeviceId)
|
||||||
|
else ->
|
||||||
|
// This is a self verification and I am the new device (Dynabook)
|
||||||
|
createQrCodeDataForUnVerifiedDevice(requestEventId, otherDeviceId)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun createQrCodeDataForDistinctUser(requestEventId: String, otherUserId: String, otherDeviceId: String?): QrCodeData? {
|
||||||
val myMasterKey = crossSigningService.getMyCrossSigningKeys()
|
val myMasterKey = crossSigningService.getMyCrossSigningKeys()
|
||||||
?.masterKey()
|
?.masterKey()
|
||||||
?.unpaddedBase64PublicKey
|
?.unpaddedBase64PublicKey
|
||||||
|
@ -789,9 +801,17 @@ internal class DefaultVerificationService @Inject constructor(
|
||||||
return null
|
return null
|
||||||
}
|
}
|
||||||
|
|
||||||
val myDeviceKey = myDeviceInfoHolder.get().myDevice.fingerprint()!!
|
val myDeviceKey = myDeviceInfoHolder.get().myDevice.fingerprint()
|
||||||
|
?: run {
|
||||||
|
Timber.w("## Unable to get my fingerprint")
|
||||||
|
return null
|
||||||
|
}
|
||||||
|
|
||||||
|
val otherDeviceKey = otherDeviceId
|
||||||
|
?.let {
|
||||||
|
cryptoStore.getUserDevice(userId, otherDeviceId)?.fingerprint()
|
||||||
|
}
|
||||||
|
|
||||||
val generatedSharedSecret = generateSharedSecret()
|
|
||||||
return QrCodeData(
|
return QrCodeData(
|
||||||
userId = userId,
|
userId = userId,
|
||||||
requestEventId = requestEventId,
|
requestEventId = requestEventId,
|
||||||
|
@ -800,8 +820,95 @@ internal class DefaultVerificationService @Inject constructor(
|
||||||
myMasterKey to myMasterKey,
|
myMasterKey to myMasterKey,
|
||||||
myDeviceId to myDeviceKey
|
myDeviceId to myDeviceKey
|
||||||
),
|
),
|
||||||
sharedSecret = generatedSharedSecret,
|
sharedSecret = generateSharedSecret(),
|
||||||
otherUserKey = otherUserMasterKey
|
otherUserKey = otherUserMasterKey,
|
||||||
|
otherDeviceKey = otherDeviceKey
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Create a QR code to display on the old device (Osborne2)
|
||||||
|
private fun createQrCodeDataForVerifiedDevice(requestEventId: String, otherDeviceId: String?): QrCodeData? {
|
||||||
|
val myMasterKey = crossSigningService.getMyCrossSigningKeys()
|
||||||
|
?.masterKey()
|
||||||
|
?.unpaddedBase64PublicKey
|
||||||
|
?: run {
|
||||||
|
Timber.w("## Unable to get my master key")
|
||||||
|
return null
|
||||||
|
}
|
||||||
|
|
||||||
|
val otherDeviceKey = otherDeviceId
|
||||||
|
?.let {
|
||||||
|
cryptoStore.getUserDevice(userId, otherDeviceId)?.fingerprint()
|
||||||
|
}
|
||||||
|
?: run {
|
||||||
|
Timber.w("## Unable to get other device data")
|
||||||
|
return null
|
||||||
|
}
|
||||||
|
|
||||||
|
val myDeviceId = deviceId
|
||||||
|
?: run {
|
||||||
|
Timber.w("## Unable to get my deviceId")
|
||||||
|
return null
|
||||||
|
}
|
||||||
|
|
||||||
|
val myDeviceKey = myDeviceInfoHolder.get().myDevice.fingerprint()
|
||||||
|
?: run {
|
||||||
|
Timber.w("## Unable to get my fingerprint")
|
||||||
|
return null
|
||||||
|
}
|
||||||
|
|
||||||
|
return QrCodeData(
|
||||||
|
userId = userId,
|
||||||
|
requestEventId = requestEventId,
|
||||||
|
action = QrCodeData.ACTION_VERIFY,
|
||||||
|
keys = hashMapOf(
|
||||||
|
myMasterKey to myMasterKey,
|
||||||
|
myDeviceId to myDeviceKey
|
||||||
|
),
|
||||||
|
sharedSecret = generateSharedSecret(),
|
||||||
|
otherUserKey = null,
|
||||||
|
otherDeviceKey = otherDeviceKey
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Create a QR code to display on the new device (Dynabook)
|
||||||
|
private fun createQrCodeDataForUnVerifiedDevice(requestEventId: String, otherDeviceId: String?): QrCodeData? {
|
||||||
|
val myMasterKey = crossSigningService.getMyCrossSigningKeys()
|
||||||
|
?.masterKey()
|
||||||
|
?.unpaddedBase64PublicKey
|
||||||
|
?: run {
|
||||||
|
Timber.w("## Unable to get my master key")
|
||||||
|
return null
|
||||||
|
}
|
||||||
|
|
||||||
|
val myDeviceId = deviceId
|
||||||
|
?: run {
|
||||||
|
Timber.w("## Unable to get my deviceId")
|
||||||
|
return null
|
||||||
|
}
|
||||||
|
|
||||||
|
val myDeviceKey = myDeviceInfoHolder.get().myDevice.fingerprint()
|
||||||
|
?: run {
|
||||||
|
Timber.w("## Unable to get my fingerprint")
|
||||||
|
return null
|
||||||
|
}
|
||||||
|
|
||||||
|
val otherDeviceKey = otherDeviceId
|
||||||
|
?.let {
|
||||||
|
cryptoStore.getUserDevice(userId, otherDeviceId)?.fingerprint()
|
||||||
|
}
|
||||||
|
|
||||||
|
return QrCodeData(
|
||||||
|
userId = userId,
|
||||||
|
requestEventId = requestEventId,
|
||||||
|
action = QrCodeData.ACTION_VERIFY,
|
||||||
|
keys = hashMapOf(
|
||||||
|
// Note: no master key here
|
||||||
|
myDeviceId to myDeviceKey
|
||||||
|
),
|
||||||
|
sharedSecret = generateSharedSecret(),
|
||||||
|
otherUserKey = myMasterKey,
|
||||||
|
otherDeviceKey = otherDeviceKey
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1128,7 +1235,7 @@ internal class DefaultVerificationService @Inject constructor(
|
||||||
|
|
||||||
if (VERIFICATION_METHOD_QR_CODE_SCAN in otherUserMethods || VERIFICATION_METHOD_QR_CODE_SHOW in otherUserMethods) {
|
if (VERIFICATION_METHOD_QR_CODE_SCAN in otherUserMethods || VERIFICATION_METHOD_QR_CODE_SHOW in otherUserMethods) {
|
||||||
// Other user wants to verify using QR code. Cross-signing has to be setup
|
// Other user wants to verify using QR code. Cross-signing has to be setup
|
||||||
val qrCodeData = createQrCodeData(transactionId, otherUserId)
|
val qrCodeData = createQrCodeData(transactionId, otherUserId, otherDeviceId)
|
||||||
|
|
||||||
if (qrCodeData != null) {
|
if (qrCodeData != null) {
|
||||||
if (VERIFICATION_METHOD_QR_CODE_SCAN in otherUserMethods && VerificationMethod.QR_CODE_SHOW in methods) {
|
if (VERIFICATION_METHOD_QR_CODE_SCAN in otherUserMethods && VerificationMethod.QR_CODE_SHOW in methods) {
|
||||||
|
|
|
@ -88,12 +88,29 @@ internal class DefaultQrCodeVerificationTransaction(
|
||||||
}
|
}
|
||||||
|
|
||||||
// check master key
|
// check master key
|
||||||
if (otherQrCodeData.otherUserKey != crossSigningService.getUserCrossSigningKeys(userId)?.masterKey()?.unpaddedBase64PublicKey) {
|
if (otherQrCodeData.userId != userId
|
||||||
|
&& otherQrCodeData.otherUserKey == null) {
|
||||||
|
// Verification with other user, other_user_key is mandatory in this case
|
||||||
|
Timber.d("## Verification QR: Invalid, missing other_user_key")
|
||||||
|
cancel(CancelCode.QrCodeInvalid)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
if (otherQrCodeData.otherUserKey != null
|
||||||
|
&& otherQrCodeData.otherUserKey != crossSigningService.getUserCrossSigningKeys(userId)?.masterKey()?.unpaddedBase64PublicKey) {
|
||||||
Timber.d("## Verification QR: Invalid other master key ${otherQrCodeData.otherUserKey}")
|
Timber.d("## Verification QR: Invalid other master key ${otherQrCodeData.otherUserKey}")
|
||||||
cancel(CancelCode.MismatchedKeys)
|
cancel(CancelCode.MismatchedKeys)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Check device key if available
|
||||||
|
if (otherQrCodeData.otherDeviceKey != null
|
||||||
|
&& otherQrCodeData.otherDeviceKey != cryptoStore.getUserDevice(otherQrCodeData.userId, otherDeviceId ?: "")?.fingerprint()) {
|
||||||
|
Timber.d("## Verification QR: Invalid other device key")
|
||||||
|
cancel(CancelCode.MismatchedKeys)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
val toVerifyDeviceIds = mutableListOf<String>()
|
val toVerifyDeviceIds = mutableListOf<String>()
|
||||||
var canTrustOtherUserMasterKey = false
|
var canTrustOtherUserMasterKey = false
|
||||||
|
|
||||||
|
@ -147,8 +164,15 @@ internal class DefaultQrCodeVerificationTransaction(
|
||||||
// qrCodeData.sharedSecret will be used to send the start request
|
// qrCodeData.sharedSecret will be used to send the start request
|
||||||
start(otherQrCodeData.sharedSecret)
|
start(otherQrCodeData.sharedSecret)
|
||||||
|
|
||||||
|
val safeOtherDeviceId = otherDeviceId
|
||||||
|
if (!otherQrCodeData.otherDeviceKey.isNullOrBlank()
|
||||||
|
&& safeOtherDeviceId != null) {
|
||||||
|
// Locally verify the device
|
||||||
|
toVerifyDeviceIds.add(safeOtherDeviceId)
|
||||||
|
}
|
||||||
|
|
||||||
// Trust the other user
|
// Trust the other user
|
||||||
trust(canTrustOtherUserMasterKey, toVerifyDeviceIds)
|
trust(canTrustOtherUserMasterKey, toVerifyDeviceIds.distinct())
|
||||||
}
|
}
|
||||||
|
|
||||||
fun start(remoteSecret: String) {
|
fun start(remoteSecret: String) {
|
||||||
|
|
|
@ -32,6 +32,7 @@ private const val ENCODING = "utf-8"
|
||||||
* &key_<keyid>=<key-in-base64>...
|
* &key_<keyid>=<key-in-base64>...
|
||||||
* &secret=<shared_secret>
|
* &secret=<shared_secret>
|
||||||
* &other_user_key=<master-key-in-base64>
|
* &other_user_key=<master-key-in-base64>
|
||||||
|
* &other_device_key=<device-key-in-base64>
|
||||||
*
|
*
|
||||||
* Example:
|
* Example:
|
||||||
* https://matrix.to/#/@user:matrix.org?
|
* https://matrix.to/#/@user:matrix.org?
|
||||||
|
@ -40,7 +41,8 @@ private const val ENCODING = "utf-8"
|
||||||
* &key_VJEDVKUYTQ=DL7LWIw7Qp%2B4AREDACTEDOwy2BjygumSWAGfzaWY
|
* &key_VJEDVKUYTQ=DL7LWIw7Qp%2B4AREDACTEDOwy2BjygumSWAGfzaWY
|
||||||
* &key_fsh%2FfQ08N3xvh4ySXsINB%2BJ2hREDACTEDVcVOG4qqo=fsh%2FfQ08N3xvh4ySXsINB%2BJ2hREDACTEDVcVOG4qqo
|
* &key_fsh%2FfQ08N3xvh4ySXsINB%2BJ2hREDACTEDVcVOG4qqo=fsh%2FfQ08N3xvh4ySXsINB%2BJ2hREDACTEDVcVOG4qqo
|
||||||
* &secret=AjQqw51Fp6UBuPolZ2FAD5WnXc22ZhJG6iGslrVvIdw%3D
|
* &secret=AjQqw51Fp6UBuPolZ2FAD5WnXc22ZhJG6iGslrVvIdw%3D
|
||||||
* &other_user_key=WqSVLkBCS%2Fi5NqR%2F%2FymC8T7K9RPxBIuqK8Usl6Y3big
|
* &other_user_key=WqSVLkBCS%2Fi5NqRREDACTEDRPxBIuqK8Usl6Y3big
|
||||||
|
* &other_device_key=WqSVLkBREDACTEDBsfszdvsdBEvefqsdcsfBvsfcsFb
|
||||||
* </pre>
|
* </pre>
|
||||||
*/
|
*/
|
||||||
fun QrCodeData.toUrl(): String {
|
fun QrCodeData.toUrl(): String {
|
||||||
|
@ -58,9 +60,16 @@ fun QrCodeData.toUrl(): String {
|
||||||
|
|
||||||
append("&secret=")
|
append("&secret=")
|
||||||
append(URLEncoder.encode(sharedSecret, ENCODING))
|
append(URLEncoder.encode(sharedSecret, ENCODING))
|
||||||
|
|
||||||
|
if (!otherUserKey.isNullOrBlank()) {
|
||||||
append("&other_user_key=")
|
append("&other_user_key=")
|
||||||
append(URLEncoder.encode(otherUserKey, ENCODING))
|
append(URLEncoder.encode(otherUserKey, ENCODING))
|
||||||
}
|
}
|
||||||
|
if (!otherDeviceKey.isNullOrBlank()) {
|
||||||
|
append("&other_device_key=")
|
||||||
|
append(URLEncoder.encode(otherDeviceKey, ENCODING))
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fun String.toQrCodeData(): QrCodeData? {
|
fun String.toQrCodeData(): QrCodeData? {
|
||||||
|
@ -100,7 +109,8 @@ fun String.toQrCodeData(): QrCodeData? {
|
||||||
|
|
||||||
val requestEventId = keyValues["request"]?.takeIf { MatrixPatterns.isEventId(it) } ?: return null
|
val requestEventId = keyValues["request"]?.takeIf { MatrixPatterns.isEventId(it) } ?: return null
|
||||||
val sharedSecret = keyValues["secret"] ?: return null
|
val sharedSecret = keyValues["secret"] ?: return null
|
||||||
val otherUserKey = keyValues["other_user_key"] ?: return null
|
val otherUserKey = keyValues["other_user_key"]
|
||||||
|
val otherDeviceKey = keyValues["other_device_key"]
|
||||||
|
|
||||||
val keys = keyValues.keys
|
val keys = keyValues.keys
|
||||||
.filter { it.startsWith("key_") }
|
.filter { it.startsWith("key_") }
|
||||||
|
@ -115,6 +125,7 @@ fun String.toQrCodeData(): QrCodeData? {
|
||||||
action,
|
action,
|
||||||
keys,
|
keys,
|
||||||
sharedSecret,
|
sharedSecret,
|
||||||
otherUserKey
|
otherUserKey,
|
||||||
|
otherDeviceKey
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
|
@ -26,13 +26,18 @@ data class QrCodeData(
|
||||||
// The action
|
// The action
|
||||||
val action: String,
|
val action: String,
|
||||||
// key_<key_id>: each key that the user wants verified will have an entry of this form, where the value is the key in unpadded base64.
|
// key_<key_id>: each key that the user wants verified will have an entry of this form, where the value is the key in unpadded base64.
|
||||||
// The QR code should contain at least the user's master cross-signing key.
|
// The QR code should contain at least the user's master cross-signing key. In the case where a device does not have a cross-signing key
|
||||||
|
// (as in the case where a user logs in to a new device, and is verifying against another device), thin the QR code should contain at
|
||||||
|
// least the device's key.
|
||||||
val keys: Map<String, String>,
|
val keys: Map<String, String>,
|
||||||
// random single-use shared secret in unpadded base64. It must be at least 256-bits long (43 characters when base64-encoded).
|
// random single-use shared secret in unpadded base64. It must be at least 256-bits long (43 characters when base64-encoded).
|
||||||
val sharedSecret: String,
|
val sharedSecret: String,
|
||||||
// the other user's master cross-signing key, in unpadded base64. In other words, if Alice is displaying the QR code,
|
// the other user's master cross-signing key, in unpadded base64. In other words, if Alice is displaying the QR code,
|
||||||
// this would be the copy of Bob's master cross-signing key that Alice has.
|
// this would be the copy of Bob's master cross-signing key that Alice has.
|
||||||
val otherUserKey: String
|
val otherUserKey: String?,
|
||||||
|
// The other device's key, in unpadded base64
|
||||||
|
// This is only needed when a user is verifying their own devices, where the other device has not yet been signed with the cross-signing key.
|
||||||
|
val otherDeviceKey: String?
|
||||||
) {
|
) {
|
||||||
companion object {
|
companion object {
|
||||||
const val ACTION_VERIFY = "verify"
|
const val ACTION_VERIFY = "verify"
|
||||||
|
|
|
@ -16,6 +16,7 @@
|
||||||
|
|
||||||
package im.vector.matrix.android.internal.crypto.verification.qrcode
|
package im.vector.matrix.android.internal.crypto.verification.qrcode
|
||||||
|
|
||||||
|
import org.amshove.kluent.shouldBe
|
||||||
import org.amshove.kluent.shouldBeEqualTo
|
import org.amshove.kluent.shouldBeEqualTo
|
||||||
import org.amshove.kluent.shouldBeNull
|
import org.amshove.kluent.shouldBeNull
|
||||||
import org.amshove.kluent.shouldNotBeNull
|
import org.amshove.kluent.shouldNotBeNull
|
||||||
|
@ -36,10 +37,18 @@ class QrCodeTest {
|
||||||
"2" to "ghijql"
|
"2" to "ghijql"
|
||||||
),
|
),
|
||||||
sharedSecret = "sharedSecret",
|
sharedSecret = "sharedSecret",
|
||||||
otherUserKey = "otherUserKey"
|
otherUserKey = "otherUserKey",
|
||||||
|
otherDeviceKey = "otherDeviceKey"
|
||||||
)
|
)
|
||||||
|
|
||||||
private val basicUrl = "https://matrix.to/#/@benoit:matrix.org?request=%24azertyazerty&action=verify&key_1=abcdef&key_2=ghijql&secret=sharedSecret&other_user_key=otherUserKey"
|
private val basicUrl = "https://matrix.to/#/@benoit:matrix.org" +
|
||||||
|
"?request=%24azertyazerty" +
|
||||||
|
"&action=verify" +
|
||||||
|
"&key_1=abcdef" +
|
||||||
|
"&key_2=ghijql" +
|
||||||
|
"&secret=sharedSecret" +
|
||||||
|
"&other_user_key=otherUserKey" +
|
||||||
|
"&other_device_key=otherDeviceKey"
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
fun testNominalCase() {
|
fun testNominalCase() {
|
||||||
|
@ -56,7 +65,8 @@ class QrCodeTest {
|
||||||
decodedData.keys["1"]?.shouldBeEqualTo("abcdef")
|
decodedData.keys["1"]?.shouldBeEqualTo("abcdef")
|
||||||
decodedData.keys["2"]?.shouldBeEqualTo("ghijql")
|
decodedData.keys["2"]?.shouldBeEqualTo("ghijql")
|
||||||
decodedData.sharedSecret shouldBeEqualTo "sharedSecret"
|
decodedData.sharedSecret shouldBeEqualTo "sharedSecret"
|
||||||
decodedData.otherUserKey shouldBeEqualTo "otherUserKey"
|
decodedData.otherUserKey?.shouldBeEqualTo("otherUserKey")
|
||||||
|
decodedData.otherDeviceKey?.shouldBeEqualTo("otherDeviceKey")
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
|
@ -81,7 +91,56 @@ class QrCodeTest {
|
||||||
decodedData.keys["1"]?.shouldBeEqualTo("abcdef")
|
decodedData.keys["1"]?.shouldBeEqualTo("abcdef")
|
||||||
decodedData.keys["2"]?.shouldBeEqualTo("ghijql")
|
decodedData.keys["2"]?.shouldBeEqualTo("ghijql")
|
||||||
decodedData.sharedSecret shouldBeEqualTo "sharedSecret"
|
decodedData.sharedSecret shouldBeEqualTo "sharedSecret"
|
||||||
decodedData.otherUserKey shouldBeEqualTo "otherUserKey"
|
decodedData.otherUserKey!! shouldBeEqualTo "otherUserKey"
|
||||||
|
decodedData.otherDeviceKey!! shouldBeEqualTo "otherDeviceKey"
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
fun testNoOtherUserKey() {
|
||||||
|
val url = basicQrCodeData
|
||||||
|
.copy(
|
||||||
|
otherUserKey = null
|
||||||
|
)
|
||||||
|
.toUrl()
|
||||||
|
|
||||||
|
url shouldBeEqualTo basicUrl
|
||||||
|
.replace("&other_user_key=otherUserKey", "")
|
||||||
|
|
||||||
|
val decodedData = url.toQrCodeData()
|
||||||
|
|
||||||
|
decodedData.shouldNotBeNull()
|
||||||
|
|
||||||
|
decodedData.userId shouldBeEqualTo "@benoit:matrix.org"
|
||||||
|
decodedData.requestEventId shouldBeEqualTo "\$azertyazerty"
|
||||||
|
decodedData.keys["1"]?.shouldBeEqualTo("abcdef")
|
||||||
|
decodedData.keys["2"]?.shouldBeEqualTo("ghijql")
|
||||||
|
decodedData.sharedSecret shouldBeEqualTo "sharedSecret"
|
||||||
|
decodedData.otherUserKey shouldBe null
|
||||||
|
decodedData.otherDeviceKey?.shouldBeEqualTo("otherDeviceKey")
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
fun testNoOtherDeviceKey() {
|
||||||
|
val url = basicQrCodeData
|
||||||
|
.copy(
|
||||||
|
otherDeviceKey = null
|
||||||
|
)
|
||||||
|
.toUrl()
|
||||||
|
|
||||||
|
url shouldBeEqualTo basicUrl
|
||||||
|
.replace("&other_device_key=otherDeviceKey", "")
|
||||||
|
|
||||||
|
val decodedData = url.toQrCodeData()
|
||||||
|
|
||||||
|
decodedData.shouldNotBeNull()
|
||||||
|
|
||||||
|
decodedData.userId shouldBeEqualTo "@benoit:matrix.org"
|
||||||
|
decodedData.requestEventId shouldBeEqualTo "\$azertyazerty"
|
||||||
|
decodedData.keys["1"]?.shouldBeEqualTo("abcdef")
|
||||||
|
decodedData.keys["2"]?.shouldBeEqualTo("ghijql")
|
||||||
|
decodedData.sharedSecret shouldBeEqualTo "sharedSecret"
|
||||||
|
decodedData.otherUserKey?.shouldBeEqualTo("otherUserKey")
|
||||||
|
decodedData.otherDeviceKey shouldBe null
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
|
@ -149,11 +208,4 @@ class QrCodeTest {
|
||||||
.toQrCodeData()
|
.toQrCodeData()
|
||||||
.shouldBeNull()
|
.shouldBeNull()
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
|
||||||
fun testMissingOtherUserKey() {
|
|
||||||
basicUrl.replace("&other_user_key=otherUserKey", "")
|
|
||||||
.toQrCodeData()
|
|
||||||
.shouldBeNull()
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue