crypto: Add proper scopes to our verification methods

This commit is contained in:
Damir Jelić 2021-07-20 16:35:50 +02:00
parent 2097f4e6c2
commit 93f36db43c
4 changed files with 117 additions and 131 deletions

View file

@ -156,7 +156,7 @@ internal class QrCodeVerification(
* This confirms that the other side has scanned our QR code. * This confirms that the other side has scanned our QR code.
*/ */
@Throws(CryptoStoreErrorException::class) @Throws(CryptoStoreErrorException::class)
suspend fun confirm() { private suspend fun confirm() {
val request = withContext(Dispatchers.IO) val request = withContext(Dispatchers.IO)
{ {
machine.confirmVerification(request.otherUser(), request.flowId()) machine.confirmVerification(request.otherUser(), request.flowId())
@ -167,14 +167,6 @@ internal class QrCodeVerification(
} }
} }
/** Send out a verification request in a blocking manner*/
private fun sendRequest(request: OutgoingVerificationRequest) {
runBlocking { sender.sendVerificationRequest(request) }
refreshData()
dispatchTxUpdated()
}
private fun cancelHelper(code: CancelCode) { private fun cancelHelper(code: CancelCode) {
val request = this.machine.cancelVerification(this.request.otherUser(), this.request.flowId(), code.value) val request = this.machine.cancelVerification(this.request.otherUser(), this.request.flowId(), code.value)
@ -183,6 +175,14 @@ internal class QrCodeVerification(
} }
} }
/** Send out a verification request in a blocking manner*/
private fun sendRequest(request: OutgoingVerificationRequest) {
runBlocking { sender.sendVerificationRequest(request) }
refreshData()
dispatchTxUpdated()
}
/** Fetch fetch data from the Rust side for our verification flow */ /** Fetch fetch data from the Rust side for our verification flow */
private fun refreshData() { private fun refreshData() {
when (val verification = this.machine.getVerification(this.request.otherUser(), this.request.flowId())) { when (val verification = this.machine.getVerification(this.request.otherUser(), this.request.flowId())) {

View file

@ -56,18 +56,6 @@ internal class SasVerification(
} }
} }
private fun refreshData() {
when (val verification = this.machine.getVerification(this.inner.otherUserId, this.inner.flowId)) {
is Verification.SasV1 -> {
this.inner = verification.sas
}
else -> {
}
}
return
}
override val isIncoming: Boolean override val isIncoming: Boolean
get() = !this.inner.weStarted get() = !this.inner.weStarted
@ -118,9 +106,8 @@ internal class SasVerification(
override fun supportsDecimal(): Boolean { override fun supportsDecimal(): Boolean {
// This is ignored anyways, throw it away? // This is ignored anyways, throw it away?
// The spec also mandates that devices support // The spec also mandates that devices support at least decimal and
// at least decimal and the rust-sdk cancels if // the rust-sdk cancels if devices don't support it
// devices don't support it
return true return true
} }
@ -130,15 +117,26 @@ internal class SasVerification(
} }
override fun userHasVerifiedShortCode() { override fun userHasVerifiedShortCode() {
val request = runBlocking { confirm() } ?: return runBlocking { confirm() }
sendRequest(request)
} }
override fun acceptVerification() { override fun acceptVerification() {
runBlocking { accept() } runBlocking { accept() }
} }
suspend fun accept() { override fun getDecimalCodeRepresentation(): String {
val decimals = this.machine.getDecimals(this.inner.otherUserId, this.inner.flowId)
return decimals?.joinToString(" ") ?: ""
}
override fun getEmojiCodeRepresentation(): List<EmojiRepresentation> {
val emojiIndex = this.machine.getEmojiIndex(this.inner.otherUserId, this.inner.flowId)
return emojiIndex?.map { getEmojiForCode(it) } ?: listOf()
}
internal suspend fun accept() {
val request = this.machine.acceptSasVerification(this.inner.otherUserId, inner.flowId) val request = this.machine.acceptSasVerification(this.inner.otherUserId, inner.flowId)
if (request != null) { if (request != null) {
@ -149,12 +147,16 @@ internal class SasVerification(
} }
@Throws(CryptoStoreErrorException::class) @Throws(CryptoStoreErrorException::class)
suspend fun confirm(): OutgoingVerificationRequest? = private suspend fun confirm() {
withContext(Dispatchers.IO) { val request = withContext(Dispatchers.IO) {
machine.confirmVerification(inner.otherUserId, inner.flowId) machine.confirmVerification(inner.otherUserId, inner.flowId)
} }
if (request != null) {
this.sender.sendVerificationRequest(request)
}
}
fun cancelHelper(code: CancelCode) { private fun cancelHelper(code: CancelCode) {
val request = this.machine.cancelVerification(this.inner.otherUserId, inner.flowId, code.value) val request = this.machine.cancelVerification(this.inner.otherUserId, inner.flowId, code.value)
if (request != null) { if (request != null) {
@ -162,24 +164,22 @@ internal class SasVerification(
} }
} }
override fun getEmojiCodeRepresentation(): List<EmojiRepresentation> { private fun sendRequest(request: OutgoingVerificationRequest) {
val emojiIndex = this.machine.getEmojiIndex(this.inner.otherUserId, this.inner.flowId) runBlocking { sender.sendVerificationRequest(request) }
return emojiIndex?.map { getEmojiForCode(it) } ?: listOf()
}
override fun getDecimalCodeRepresentation(): String {
val decimals = this.machine.getDecimals(this.inner.otherUserId, this.inner.flowId)
return decimals?.joinToString(" ") ?: ""
}
fun sendRequest(request: OutgoingVerificationRequest) {
runBlocking {
sender.sendVerificationRequest(request)
}
refreshData() refreshData()
dispatchTxUpdated() dispatchTxUpdated()
} }
private fun refreshData() {
when (val verification = this.machine.getVerification(this.inner.otherUserId, this.inner.flowId)) {
is Verification.SasV1 -> {
this.inner = verification.sas
}
else -> {
}
}
return
}
} }

View file

@ -34,6 +34,7 @@ import org.matrix.android.sdk.internal.crypto.model.rest.VERIFICATION_METHOD_QR_
import org.matrix.android.sdk.internal.crypto.model.rest.VERIFICATION_METHOD_RECIPROCATE import org.matrix.android.sdk.internal.crypto.model.rest.VERIFICATION_METHOD_RECIPROCATE
import org.matrix.android.sdk.internal.crypto.model.rest.VERIFICATION_METHOD_SAS import org.matrix.android.sdk.internal.crypto.model.rest.VERIFICATION_METHOD_SAS
import org.matrix.android.sdk.internal.crypto.model.rest.toValue import org.matrix.android.sdk.internal.crypto.model.rest.toValue
import org.matrix.android.sdk.internal.crypto.verification.prepareMethods
import timber.log.Timber import timber.log.Timber
import uniffi.olm.OlmMachine import uniffi.olm.OlmMachine
import uniffi.olm.VerificationRequest import uniffi.olm.VerificationRequest
@ -46,16 +47,6 @@ internal class VerificationRequest(
) { ) {
private val uiHandler = Handler(Looper.getMainLooper()) private val uiHandler = Handler(Looper.getMainLooper())
private fun refreshData() {
val request = this.machine.getVerificationRequest(this.inner.otherUserId, this.inner.flowId)
if (request != null) {
this.inner = request
}
return
}
internal fun dispatchRequestUpdated() { internal fun dispatchRequestUpdated() {
uiHandler.post { uiHandler.post {
listeners.forEach { listeners.forEach {
@ -68,42 +59,65 @@ internal class VerificationRequest(
} }
} }
fun isCanceled(): Boolean { internal fun flowId(): String {
refreshData()
return this.inner.isCancelled
}
fun isDone(): Boolean {
refreshData()
return this.inner.isDone
}
fun flowId(): String {
return this.inner.flowId return this.inner.flowId
} }
fun otherUser(): String { internal fun otherUser(): String {
return this.inner.otherUserId return this.inner.otherUserId
} }
fun otherDeviceId(): String? { internal fun otherDeviceId(): String? {
refreshData() refreshData()
return this.inner.otherDeviceId return this.inner.otherDeviceId
} }
fun weStarted(): Boolean { internal fun weStarted(): Boolean {
return this.inner.weStarted return this.inner.weStarted
} }
fun roomId(): String? { internal fun roomId(): String? {
return this.inner.roomId return this.inner.roomId
} }
fun isReady(): Boolean { internal fun isReady(): Boolean {
refreshData() refreshData()
return this.inner.isReady return this.inner.isReady
} }
internal fun canScanQrCodes(): Boolean {
refreshData()
return this.inner.ourMethods?.contains(VERIFICATION_METHOD_QR_CODE_SCAN) ?: false
}
suspend fun acceptWithMethods(methods: List<VerificationMethod>) {
val stringMethods = prepareMethods(methods)
val request = this.machine.acceptVerificationRequest(
this.inner.otherUserId,
this.inner.flowId,
stringMethods
)
if (request != null) {
this.sender.sendVerificationRequest(request)
this.dispatchRequestUpdated()
}
}
internal suspend fun startSasVerification(): SasVerification? {
return withContext(Dispatchers.IO) {
val result = machine.startSasVerification(inner.otherUserId, inner.flowId)
if (result != null) {
sender.sendVerificationRequest(result.request)
SasVerification(machine, result.sas, sender, listeners)
} else {
null
}
}
}
internal suspend fun scanQrCode(data: String): QrCodeVerification? { internal suspend fun scanQrCode(data: String): QrCodeVerification? {
// TODO again, what's the deal with ISO_8859_1? // TODO again, what's the deal with ISO_8859_1?
val byteArray = data.toByteArray(Charsets.ISO_8859_1) val byteArray = data.toByteArray(Charsets.ISO_8859_1)
@ -130,18 +144,11 @@ internal class VerificationRequest(
} }
} }
suspend fun acceptWithMethods(methods: List<VerificationMethod>) { internal suspend fun cancel() {
val stringMethods: MutableList<String> = methods.map { it.toValue() }.toMutableList() val request = this.machine.cancelVerification(
if (stringMethods.contains(VERIFICATION_METHOD_QR_CODE_SHOW) ||
stringMethods.contains(VERIFICATION_METHOD_QR_CODE_SCAN)) {
stringMethods.add(VERIFICATION_METHOD_RECIPROCATE)
}
val request = this.machine.acceptVerificationRequest(
this.inner.otherUserId, this.inner.otherUserId,
this.inner.flowId, this.inner.flowId,
stringMethods CancelCode.User.value
) )
if (request != null) { if (request != null) {
@ -150,35 +157,15 @@ internal class VerificationRequest(
} }
} }
suspend fun cancel() { private fun refreshData() {
val request = this.machine.cancelVerification(this.inner.otherUserId, this.inner.flowId, CancelCode.User.value) val request = this.machine.getVerificationRequest(this.inner.otherUserId, this.inner.flowId)
if (request != null) { if (request != null) {
this.sender.sendVerificationRequest(request) this.inner = request
this.dispatchRequestUpdated()
} }
} }
fun canScanQrCodes(): Boolean { internal fun toPendingVerificationRequest(): PendingVerificationRequest {
refreshData()
return this.inner.ourMethods?.contains(VERIFICATION_METHOD_QR_CODE_SCAN) ?: false
}
suspend fun startSasVerification(): SasVerification? {
refreshData()
return withContext(Dispatchers.IO) {
val result = machine.startSasVerification(inner.otherUserId, inner.flowId)
if (result != null) {
sender.sendVerificationRequest(result.request)
SasVerification(machine, result.sas, sender, listeners)
} else {
null
}
}
}
fun toPendingVerificationRequest(): PendingVerificationRequest {
refreshData() refreshData()
val cancelInfo = this.inner.cancelInfo val cancelInfo = this.inner.cancelInfo
val cancelCode = val cancelCode =

View file

@ -46,7 +46,7 @@ import timber.log.Timber
import uniffi.olm.Verification import uniffi.olm.Verification
@JsonClass(generateAdapter = true) @JsonClass(generateAdapter = true)
data class ToDeviceVerificationEvent( internal data class ToDeviceVerificationEvent(
@Json(name = "sender") val sender: String?, @Json(name = "sender") val sender: String?,
@Json(name = "transaction_id") val transactionId: String, @Json(name = "transaction_id") val transactionId: String,
) )
@ -61,6 +61,17 @@ private fun getFlowId(event: Event): String? {
} }
} }
internal fun prepareMethods(methods: List<VerificationMethod>): List<String> {
val stringMethods: MutableList<String> = methods.map { it.toValue() }.toMutableList()
if (stringMethods.contains(VERIFICATION_METHOD_QR_CODE_SHOW) ||
stringMethods.contains(VERIFICATION_METHOD_QR_CODE_SCAN)) {
stringMethods.add(VERIFICATION_METHOD_RECIPROCATE)
}
return stringMethods
}
internal class RustVerificationService( internal class RustVerificationService(
private val olmMachine: OlmMachine, private val olmMachine: OlmMachine,
private val requestSender: RequestSender, private val requestSender: RequestSender,
@ -117,7 +128,7 @@ internal class RustVerificationService(
} }
} }
suspend fun onEvent(event: Event) = when (event.getClearType()) { internal suspend fun onEvent(event: Event) = when (event.getClearType()) {
MessageType.MSGTYPE_VERIFICATION_REQUEST -> onRequest(event) MessageType.MSGTYPE_VERIFICATION_REQUEST -> onRequest(event)
EventType.KEY_VERIFICATION_START -> onStart(event) EventType.KEY_VERIFICATION_START -> onStart(event)
EventType.KEY_VERIFICATION_READY, EventType.KEY_VERIFICATION_READY,
@ -148,8 +159,8 @@ internal class RustVerificationService(
if (request != null && request.isReady()) { if (request != null && request.isReady()) {
// If this is a SAS verification originating from a `m.key.verification.request` // If this is a SAS verification originating from a `m.key.verification.request`
// event we auto-accept here considering that we either initiated the request or // event, we auto-accept here considering that we either initiated the request or
// accepted the request, otherwise it's a QR code verification, just dispatch an update. // accepted the request. If it's a QR code verification, just dispatch an update.
if (verification is SasVerification) { if (verification is SasVerification) {
// Accept dispatches an update, no need to do it twice. // Accept dispatches an update, no need to do it twice.
Timber.d("## Verification: Auto accepting SAS verification with $sender") Timber.d("## Verification: Auto accepting SAS verification with $sender")
@ -296,12 +307,7 @@ internal class RustVerificationService(
otherUserId: String, otherUserId: String,
otherDevices: List<String>? otherDevices: List<String>?
): PendingVerificationRequest { ): PendingVerificationRequest {
val stringMethods = prepareMethods(methods)
val stringMethods: MutableList<String> = methods.map { it.toValue() }.toMutableList()
if (stringMethods.contains(VERIFICATION_METHOD_QR_CODE_SHOW) ||
stringMethods.contains(VERIFICATION_METHOD_QR_CODE_SCAN)) {
stringMethods.add(VERIFICATION_METHOD_RECIPROCATE)
}
val result = this.olmMachine.inner().requestSelfVerification(stringMethods) val result = this.olmMachine.inner().requestSelfVerification(stringMethods)
runBlocking { runBlocking {
@ -318,13 +324,7 @@ internal class RustVerificationService(
localId: String? localId: String?
): PendingVerificationRequest { ): PendingVerificationRequest {
Timber.i("## SAS Requesting verification to user: $otherUserId in room $roomId") Timber.i("## SAS Requesting verification to user: $otherUserId in room $roomId")
val stringMethods: MutableList<String> = methods.map { it.toValue() }.toMutableList() val stringMethods = prepareMethods(methods)
if (stringMethods.contains(VERIFICATION_METHOD_QR_CODE_SHOW) ||
stringMethods.contains(VERIFICATION_METHOD_QR_CODE_SCAN)) {
stringMethods.add(VERIFICATION_METHOD_RECIPROCATE)
}
val content = this.olmMachine.inner().verificationRequestContent(otherUserId, stringMethods)!! val content = this.olmMachine.inner().verificationRequestContent(otherUserId, stringMethods)!!
val eventID = runBlocking { val eventID = runBlocking {
@ -376,7 +376,6 @@ internal class RustVerificationService(
otherDeviceId: String, otherDeviceId: String,
transactionId: String? transactionId: String?
): String? { ): String? {
// should check if already one (and cancel it)
return if (method == VerificationMethod.SAS) { return if (method == VerificationMethod.SAS) {
if (transactionId != null) { if (transactionId != null) {
val request = this.getVerificationRequest(otherUserId, transactionId) val request = this.getVerificationRequest(otherUserId, transactionId)