mirror of
https://github.com/vector-im/element-android.git
synced 2024-11-16 02:05:06 +08:00
Migrate to QrCode v2 - TODO: cleanup
This commit is contained in:
parent
e00d3ef63d
commit
859b9e4f8e
@ -65,8 +65,9 @@ import im.vector.matrix.android.internal.crypto.model.rest.VERIFICATION_METHOD_S
|
||||
import im.vector.matrix.android.internal.crypto.model.rest.toValue
|
||||
import im.vector.matrix.android.internal.crypto.store.IMXCryptoStore
|
||||
import im.vector.matrix.android.internal.crypto.verification.qrcode.DefaultQrCodeVerificationTransaction
|
||||
import im.vector.matrix.android.internal.crypto.verification.qrcode.QrCodeData
|
||||
import im.vector.matrix.android.internal.crypto.verification.qrcode.QrCodeDataV2
|
||||
import im.vector.matrix.android.internal.crypto.verification.qrcode.generateSharedSecret
|
||||
import im.vector.matrix.android.internal.crypto.verification.qrcode.generateSharedSecretV2
|
||||
import im.vector.matrix.android.internal.di.DeviceId
|
||||
import im.vector.matrix.android.internal.di.UserId
|
||||
import im.vector.matrix.android.internal.session.SessionScope
|
||||
@ -788,7 +789,7 @@ internal class DefaultVerificationService @Inject constructor(
|
||||
))
|
||||
}
|
||||
|
||||
private fun createQrCodeData(requestId: String?, otherUserId: String, otherDeviceId: String?): QrCodeData? {
|
||||
private fun createQrCodeData(requestId: String?, otherUserId: String, otherDeviceId: String?): QrCodeDataV2? {
|
||||
requestId ?: run {
|
||||
Timber.w("## Unknown requestId")
|
||||
return null
|
||||
@ -796,17 +797,17 @@ internal class DefaultVerificationService @Inject constructor(
|
||||
|
||||
return when {
|
||||
userId != otherUserId ->
|
||||
createQrCodeDataForDistinctUser(requestId, otherUserId, otherDeviceId)
|
||||
createQrCodeDataForDistinctUser(requestId, otherUserId /*, otherDeviceId*/)
|
||||
crossSigningService.isCrossSigningVerified() ->
|
||||
// This is a self verification and I am the old device (Osborne2)
|
||||
createQrCodeDataForVerifiedDevice(requestId, otherDeviceId)
|
||||
else ->
|
||||
// This is a self verification and I am the new device (Dynabook)
|
||||
createQrCodeDataForUnVerifiedDevice(requestId, otherDeviceId)
|
||||
createQrCodeDataForUnVerifiedDevice(requestId/*, otherDeviceId*/)
|
||||
}
|
||||
}
|
||||
|
||||
private fun createQrCodeDataForDistinctUser(requestId: String, otherUserId: String, otherDeviceId: String?): QrCodeData? {
|
||||
private fun createQrCodeDataForDistinctUser(requestId: String, otherUserId: String /*, otherDeviceId: String?*/): QrCodeDataV2.VerifyingAnotherUser? {
|
||||
val myMasterKey = crossSigningService.getMyCrossSigningKeys()
|
||||
?.masterKey()
|
||||
?.unpaddedBase64PublicKey
|
||||
@ -823,6 +824,7 @@ internal class DefaultVerificationService @Inject constructor(
|
||||
return null
|
||||
}
|
||||
|
||||
/* TODO Cleanup
|
||||
val myDeviceId = deviceId
|
||||
?: run {
|
||||
Timber.w("## Unable to get my deviceId")
|
||||
@ -839,23 +841,18 @@ internal class DefaultVerificationService @Inject constructor(
|
||||
?.let {
|
||||
cryptoStore.getUserDevice(userId, otherDeviceId)?.fingerprint()
|
||||
}
|
||||
*/
|
||||
|
||||
return QrCodeData(
|
||||
userId = userId,
|
||||
requestId = requestId,
|
||||
action = QrCodeData.ACTION_VERIFY,
|
||||
keys = hashMapOf(
|
||||
myMasterKey to myMasterKey,
|
||||
myDeviceId to myDeviceKey
|
||||
),
|
||||
sharedSecret = generateSharedSecret(),
|
||||
otherUserKey = otherUserMasterKey,
|
||||
otherDeviceKey = otherDeviceKey
|
||||
return QrCodeDataV2.VerifyingAnotherUser(
|
||||
transactionId = requestId,
|
||||
userMasterCrossSigningPublicKey = myMasterKey,
|
||||
otherUserMasterCrossSigningPublicKey = otherUserMasterKey,
|
||||
sharedSecret = generateSharedSecretV2()
|
||||
)
|
||||
}
|
||||
|
||||
// Create a QR code to display on the old device (Osborne2)
|
||||
private fun createQrCodeDataForVerifiedDevice(requestId: String, otherDeviceId: String?): QrCodeData? {
|
||||
private fun createQrCodeDataForVerifiedDevice(requestId: String, otherDeviceId: String?): QrCodeDataV2.SelfVerifyingMasterKeyTrusted? {
|
||||
val myMasterKey = crossSigningService.getMyCrossSigningKeys()
|
||||
?.masterKey()
|
||||
?.unpaddedBase64PublicKey
|
||||
@ -873,6 +870,7 @@ internal class DefaultVerificationService @Inject constructor(
|
||||
return null
|
||||
}
|
||||
|
||||
/* TODO Cleanup
|
||||
val myDeviceId = deviceId
|
||||
?: run {
|
||||
Timber.w("## Unable to get my deviceId")
|
||||
@ -884,23 +882,18 @@ internal class DefaultVerificationService @Inject constructor(
|
||||
Timber.w("## Unable to get my fingerprint")
|
||||
return null
|
||||
}
|
||||
*/
|
||||
|
||||
return QrCodeData(
|
||||
userId = userId,
|
||||
requestId = requestId,
|
||||
action = QrCodeData.ACTION_VERIFY,
|
||||
keys = hashMapOf(
|
||||
myMasterKey to myMasterKey,
|
||||
myDeviceId to myDeviceKey
|
||||
),
|
||||
sharedSecret = generateSharedSecret(),
|
||||
otherUserKey = null,
|
||||
otherDeviceKey = otherDeviceKey
|
||||
return QrCodeDataV2.SelfVerifyingMasterKeyTrusted(
|
||||
transactionId = requestId,
|
||||
userMasterCrossSigningPublicKey = myMasterKey,
|
||||
otherDeviceKey = otherDeviceKey,
|
||||
sharedSecret = generateSharedSecretV2()
|
||||
)
|
||||
}
|
||||
|
||||
// Create a QR code to display on the new device (Dynabook)
|
||||
private fun createQrCodeDataForUnVerifiedDevice(requestId: String, otherDeviceId: String?): QrCodeData? {
|
||||
private fun createQrCodeDataForUnVerifiedDevice(requestId: String/*, otherDeviceId: String?*/): QrCodeDataV2.SelfVerifyingMasterKeyNotTrusted? {
|
||||
val myMasterKey = crossSigningService.getMyCrossSigningKeys()
|
||||
?.masterKey()
|
||||
?.unpaddedBase64PublicKey
|
||||
@ -909,11 +902,13 @@ internal class DefaultVerificationService @Inject constructor(
|
||||
return null
|
||||
}
|
||||
|
||||
/* TODO Cleanup
|
||||
val myDeviceId = deviceId
|
||||
?: run {
|
||||
Timber.w("## Unable to get my deviceId")
|
||||
return null
|
||||
}
|
||||
*/
|
||||
|
||||
val myDeviceKey = myDeviceInfoHolder.get().myDevice.fingerprint()
|
||||
?: run {
|
||||
@ -921,22 +916,18 @@ internal class DefaultVerificationService @Inject constructor(
|
||||
return null
|
||||
}
|
||||
|
||||
/* TODO Cleanup
|
||||
val otherDeviceKey = otherDeviceId
|
||||
?.let {
|
||||
cryptoStore.getUserDevice(userId, otherDeviceId)?.fingerprint()
|
||||
}
|
||||
*/
|
||||
|
||||
return QrCodeData(
|
||||
userId = userId,
|
||||
requestId = requestId,
|
||||
action = QrCodeData.ACTION_VERIFY,
|
||||
keys = hashMapOf(
|
||||
// Note: no master key here
|
||||
myDeviceId to myDeviceKey
|
||||
),
|
||||
sharedSecret = generateSharedSecret(),
|
||||
otherUserKey = myMasterKey,
|
||||
otherDeviceKey = otherDeviceKey
|
||||
return QrCodeDataV2.SelfVerifyingMasterKeyNotTrusted(
|
||||
transactionId = requestId,
|
||||
deviceKey = myDeviceKey,
|
||||
userMasterCrossSigningPublicKey = myMasterKey,
|
||||
sharedSecret = generateSharedSecretV2()
|
||||
)
|
||||
}
|
||||
|
||||
|
@ -28,7 +28,7 @@ import im.vector.matrix.android.internal.crypto.store.IMXCryptoStore
|
||||
import im.vector.matrix.android.internal.crypto.verification.DefaultVerificationTransaction
|
||||
import im.vector.matrix.android.internal.crypto.verification.VerificationInfo
|
||||
import im.vector.matrix.android.internal.crypto.verification.VerificationInfoStart
|
||||
import im.vector.matrix.android.internal.util.withoutPrefix
|
||||
import im.vector.matrix.android.internal.util.exhaustive
|
||||
import timber.log.Timber
|
||||
|
||||
internal class DefaultQrCodeVerificationTransaction(
|
||||
@ -39,14 +39,14 @@ internal class DefaultQrCodeVerificationTransaction(
|
||||
private val crossSigningService: CrossSigningService,
|
||||
private val cryptoStore: IMXCryptoStore,
|
||||
// Not null only if other user is able to scan QR code
|
||||
private val qrCodeData: QrCodeData?,
|
||||
private val qrCodeData: QrCodeDataV2?,
|
||||
val userId: String,
|
||||
val deviceId: String,
|
||||
override val isIncoming: Boolean
|
||||
) : DefaultVerificationTransaction(transactionId, otherUserId, otherDeviceId, isIncoming), QrCodeVerificationTransaction {
|
||||
|
||||
override val qrCodeText: String?
|
||||
get() = qrCodeData?.toUrl()
|
||||
get() = qrCodeData?.toEncodedString()
|
||||
|
||||
override var state: VerificationTxState = VerificationTxState.None
|
||||
set(newState) {
|
||||
@ -62,96 +62,77 @@ internal class DefaultQrCodeVerificationTransaction(
|
||||
}
|
||||
|
||||
override fun userHasScannedOtherQrCode(otherQrCodeText: String) {
|
||||
val otherQrCodeData = otherQrCodeText.toQrCodeData() ?: run {
|
||||
val otherQrCodeData = otherQrCodeText.toQrCodeDataV2() ?: run {
|
||||
Timber.d("## Verification QR: Invalid QR Code Data")
|
||||
cancel(CancelCode.QrCodeInvalid)
|
||||
return
|
||||
}
|
||||
|
||||
// Perform some checks
|
||||
if (otherQrCodeData.action != QrCodeData.ACTION_VERIFY) {
|
||||
Timber.d("## Verification QR: Invalid action ${otherQrCodeData.action}")
|
||||
cancel(CancelCode.QrCodeInvalid)
|
||||
return
|
||||
}
|
||||
|
||||
if (otherQrCodeData.userId != otherUserId) {
|
||||
Timber.d("## Verification QR: Mismatched user ${otherQrCodeData.userId}")
|
||||
cancel(CancelCode.MismatchedUser)
|
||||
return
|
||||
}
|
||||
|
||||
if (otherQrCodeData.requestId != transactionId) {
|
||||
Timber.d("## Verification QR: Invalid transaction actual ${otherQrCodeData.requestId} expected:$transactionId")
|
||||
if (otherQrCodeData.transactionId != transactionId) {
|
||||
Timber.d("## Verification QR: Invalid transaction actual ${otherQrCodeData.transactionId} expected:$transactionId")
|
||||
cancel(CancelCode.QrCodeInvalid)
|
||||
return
|
||||
}
|
||||
|
||||
// check master key
|
||||
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}")
|
||||
cancel(CancelCode.MismatchedKeys)
|
||||
return
|
||||
}
|
||||
|
||||
// Check device key if available
|
||||
if (otherQrCodeData.otherDeviceKey != null
|
||||
&& otherQrCodeData.otherDeviceKey != cryptoStore.getUserDevice(userId, deviceId)?.fingerprint()) {
|
||||
Timber.d("## Verification QR: Invalid other device key")
|
||||
cancel(CancelCode.MismatchedKeys)
|
||||
return
|
||||
}
|
||||
when (otherQrCodeData) {
|
||||
is QrCodeDataV2.VerifyingAnotherUser -> {
|
||||
if (otherQrCodeData.otherUserMasterCrossSigningPublicKey != crossSigningService.getUserCrossSigningKeys(userId)?.masterKey()?.unpaddedBase64PublicKey) {
|
||||
Timber.d("## Verification QR: Invalid other master key ${otherQrCodeData.otherUserMasterCrossSigningPublicKey}")
|
||||
cancel(CancelCode.MismatchedKeys)
|
||||
return
|
||||
} else Unit
|
||||
}
|
||||
is QrCodeDataV2.SelfVerifyingMasterKeyTrusted -> {
|
||||
if (otherQrCodeData.userMasterCrossSigningPublicKey != crossSigningService.getUserCrossSigningKeys(userId)?.masterKey()?.unpaddedBase64PublicKey) {
|
||||
Timber.d("## Verification QR: Invalid other master key ${otherQrCodeData.userMasterCrossSigningPublicKey}")
|
||||
cancel(CancelCode.MismatchedKeys)
|
||||
return
|
||||
} else Unit
|
||||
}
|
||||
is QrCodeDataV2.SelfVerifyingMasterKeyNotTrusted -> {
|
||||
if (otherQrCodeData.userMasterCrossSigningPublicKey != crossSigningService.getUserCrossSigningKeys(userId)?.masterKey()?.unpaddedBase64PublicKey) {
|
||||
Timber.d("## Verification QR: Invalid other master key ${otherQrCodeData.userMasterCrossSigningPublicKey}")
|
||||
cancel(CancelCode.MismatchedKeys)
|
||||
return
|
||||
} else Unit
|
||||
}
|
||||
}.exhaustive
|
||||
|
||||
val toVerifyDeviceIds = mutableListOf<String>()
|
||||
var canTrustOtherUserMasterKey = false
|
||||
|
||||
val otherDevices = cryptoStore.getUserDevices(otherUserId)
|
||||
otherQrCodeData.keys.keys.forEach { key ->
|
||||
Timber.w("## Verification QR: Checking key $key")
|
||||
|
||||
when (val keyNoPrefix = key.withoutPrefix("ed25519:")) {
|
||||
otherQrCodeData.keys[key] -> {
|
||||
// Maybe master key?
|
||||
if (otherQrCodeData.keys[key] == crossSigningService.getUserCrossSigningKeys(otherUserId)?.masterKey()?.unpaddedBase64PublicKey) {
|
||||
canTrustOtherUserMasterKey = true
|
||||
} else {
|
||||
cancel(CancelCode.MismatchedKeys)
|
||||
return
|
||||
}
|
||||
}
|
||||
else -> {
|
||||
when (val otherDevice = otherDevices?.get(keyNoPrefix)) {
|
||||
null -> {
|
||||
// Unknown device, ignore
|
||||
}
|
||||
else -> {
|
||||
when (otherDevice.fingerprint()) {
|
||||
null -> {
|
||||
// Ignore
|
||||
}
|
||||
otherQrCodeData.keys[key] -> {
|
||||
// Store the deviceId to verify after
|
||||
toVerifyDeviceIds.add(key)
|
||||
}
|
||||
else -> {
|
||||
cancel(CancelCode.MismatchedKeys)
|
||||
return
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
// Check device key if available
|
||||
when (otherQrCodeData) {
|
||||
is QrCodeDataV2.VerifyingAnotherUser -> {
|
||||
if (otherQrCodeData.userMasterCrossSigningPublicKey != crossSigningService.getUserCrossSigningKeys(otherUserId)?.masterKey()?.unpaddedBase64PublicKey) {
|
||||
Timber.d("## Verification QR: Invalid user master key ${otherQrCodeData.userMasterCrossSigningPublicKey}")
|
||||
cancel(CancelCode.MismatchedKeys)
|
||||
return
|
||||
} else {
|
||||
canTrustOtherUserMasterKey = true
|
||||
Unit
|
||||
}
|
||||
}
|
||||
}
|
||||
is QrCodeDataV2.SelfVerifyingMasterKeyTrusted -> {
|
||||
if (otherQrCodeData.otherDeviceKey != cryptoStore.getUserDevice(userId, deviceId)?.fingerprint()) {
|
||||
Timber.d("## Verification QR: Invalid other device key ${otherQrCodeData.otherDeviceKey}")
|
||||
cancel(CancelCode.MismatchedKeys)
|
||||
return
|
||||
} else Unit
|
||||
}
|
||||
is QrCodeDataV2.SelfVerifyingMasterKeyNotTrusted -> {
|
||||
if (otherQrCodeData.deviceKey != cryptoStore.getUserDevice(otherUserId, otherDeviceId ?: "")?.fingerprint()) {
|
||||
Timber.d("## Verification QR: Invalid device key ${otherQrCodeData.deviceKey}")
|
||||
cancel(CancelCode.MismatchedKeys)
|
||||
return
|
||||
} else {
|
||||
toVerifyDeviceIds.add(otherQrCodeData.deviceKey)
|
||||
Unit
|
||||
}
|
||||
}
|
||||
}.exhaustive
|
||||
|
||||
if (!canTrustOtherUserMasterKey && toVerifyDeviceIds.isEmpty()) {
|
||||
// Nothing to verify
|
||||
@ -164,13 +145,6 @@ internal class DefaultQrCodeVerificationTransaction(
|
||||
// qrCodeData.sharedSecret will be used to send the start request
|
||||
start(otherQrCodeData.sharedSecret)
|
||||
|
||||
val safeOtherDeviceId = otherDeviceId
|
||||
if (!otherQrCodeData.otherDeviceKey.isNullOrBlank()
|
||||
&& safeOtherDeviceId != null) {
|
||||
// Locally verify the device
|
||||
toVerifyDeviceIds.add(safeOtherDeviceId)
|
||||
}
|
||||
|
||||
// Trust the other user
|
||||
trust(canTrustOtherUserMasterKey, toVerifyDeviceIds.distinct())
|
||||
}
|
||||
@ -264,8 +238,8 @@ internal class DefaultQrCodeVerificationTransaction(
|
||||
|
||||
// TODO what if the otherDevice is not in this list? and should we
|
||||
toVerifyDeviceIds.forEach {
|
||||
setDeviceVerified(otherUserId, it)
|
||||
}
|
||||
setDeviceVerified(otherUserId, it)
|
||||
}
|
||||
transport.done(transactionId)
|
||||
state = VerificationTxState.Verified
|
||||
}
|
||||
|
@ -0,0 +1,20 @@
|
||||
/*
|
||||
* Copyright (c) 2020 New Vector Ltd
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package im.vector.matrix.android.internal.util
|
||||
|
||||
// Trick to ensure that when block is exhaustive
|
||||
internal val <T> T.exhaustive: T get() = this
|
Loading…
Reference in New Issue
Block a user