mirror of
https://github.com/element-hq/element-android
synced 2024-12-21 08:54:12 +03:00
crypto: Allow verifications to be requested
This commit is contained in:
parent
d24c94d0f9
commit
33c2184c52
8 changed files with 182 additions and 49 deletions
|
@ -145,31 +145,31 @@ internal class RequestSender @Inject constructor(
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
suspend fun sendRoomMessage(request: OutgoingVerificationRequest.InRoom) {
|
suspend fun sendRoomMessage(request: OutgoingVerificationRequest.InRoom): String {
|
||||||
sendRoomMessage(request.eventType, request.roomId, request.content, request.requestId)
|
return sendRoomMessage(request.eventType, request.roomId, request.content, request.requestId)
|
||||||
}
|
}
|
||||||
|
|
||||||
suspend fun sendRoomMessage(request: Request.RoomMessage) {
|
suspend fun sendRoomMessage(request: Request.RoomMessage): String {
|
||||||
sendRoomMessage(request.eventType, request.roomId, request.content, request.requestId)
|
return sendRoomMessage(request.eventType, request.roomId, request.content, request.requestId)
|
||||||
}
|
}
|
||||||
|
|
||||||
suspend fun sendRoomMessage(eventType: String, roomId: String, content: String, transactionId: String) {
|
suspend fun sendRoomMessage(eventType: String, roomId: String, content: String, transactionId: String): String {
|
||||||
val adapter = MoshiProvider.providesMoshi().adapter<Content>(Map::class.java)
|
val adapter = MoshiProvider.providesMoshi().adapter<Content>(Map::class.java)
|
||||||
val jsonContent = adapter.fromJson(content)
|
val jsonContent = adapter.fromJson(content)
|
||||||
val event = Event(eventType, transactionId, jsonContent, roomId = roomId)
|
val event = Event(eventType, transactionId, jsonContent, roomId = roomId)
|
||||||
val params = SendVerificationMessageTask.Params(event)
|
val params = SendVerificationMessageTask.Params(event)
|
||||||
this.sendVerificationMessageTask.get().execute(params)
|
return this.sendVerificationMessageTask.get().execute(params)
|
||||||
}
|
}
|
||||||
|
|
||||||
suspend fun sendToDevice(request: Request.ToDevice) {
|
suspend fun sendToDevice(request: Request.ToDevice) {
|
||||||
sendToDevice(request.eventType, request.body)
|
sendToDevice(request.eventType, request.body, request.requestId)
|
||||||
}
|
}
|
||||||
|
|
||||||
suspend fun sendToDevice(request: OutgoingVerificationRequest.ToDevice) {
|
suspend fun sendToDevice(request: OutgoingVerificationRequest.ToDevice) {
|
||||||
sendToDevice(request.eventType, request.body)
|
sendToDevice(request.eventType, request.body, request.requestId)
|
||||||
}
|
}
|
||||||
|
|
||||||
suspend fun sendToDevice(eventType: String, body: String) {
|
suspend fun sendToDevice(eventType: String, body: String, transactionId: String) {
|
||||||
// TODO this produces floats for the Olm type fields, which are integers originally.
|
// TODO this produces floats for the Olm type fields, which are integers originally.
|
||||||
val adapter = MoshiProvider
|
val adapter = MoshiProvider
|
||||||
.providesMoshi()
|
.providesMoshi()
|
||||||
|
@ -179,7 +179,7 @@ internal class RequestSender @Inject constructor(
|
||||||
val userMap = MXUsersDevicesMap<Any>()
|
val userMap = MXUsersDevicesMap<Any>()
|
||||||
userMap.join(jsonBody)
|
userMap.join(jsonBody)
|
||||||
|
|
||||||
val sendToDeviceParams = SendToDeviceTask.Params(eventType, userMap)
|
val sendToDeviceParams = SendToDeviceTask.Params(eventType, userMap, transactionId)
|
||||||
sendToDeviceTask.execute(sendToDeviceParams)
|
sendToDeviceTask.execute(sendToDeviceParams)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -203,21 +203,20 @@ internal class QrCodeVerification(
|
||||||
override var state: VerificationTxState
|
override var state: VerificationTxState
|
||||||
get() {
|
get() {
|
||||||
refreshData()
|
refreshData()
|
||||||
val state = when {
|
|
||||||
this.inner.isDone -> VerificationTxState.Verified
|
return when {
|
||||||
this.inner.hasBeenConfirmed -> VerificationTxState.WaitingOtherReciprocateConfirm
|
inner.isDone -> VerificationTxState.Verified
|
||||||
this.inner.otherSideScanned -> VerificationTxState.QrScannedByOther
|
inner.hasBeenConfirmed -> VerificationTxState.WaitingOtherReciprocateConfirm
|
||||||
this.inner.isCancelled -> {
|
inner.otherSideScanned -> VerificationTxState.QrScannedByOther
|
||||||
val cancelCode = safeValueOf(this.inner.cancelCode)
|
inner.isCancelled -> {
|
||||||
val byMe = this.inner.cancelledByUs ?: false
|
val cancelCode = safeValueOf(inner.cancelCode)
|
||||||
|
val byMe = inner.cancelledByUs ?: false
|
||||||
VerificationTxState.Cancelled(cancelCode, byMe)
|
VerificationTxState.Cancelled(cancelCode, byMe)
|
||||||
}
|
}
|
||||||
else -> {
|
else -> {
|
||||||
VerificationTxState.None
|
VerificationTxState.None
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return state
|
|
||||||
}
|
}
|
||||||
@Suppress("UNUSED_PARAMETER")
|
@Suppress("UNUSED_PARAMETER")
|
||||||
set(value) {}
|
set(value) {}
|
||||||
|
|
|
@ -31,6 +31,7 @@ import org.matrix.android.sdk.internal.crypto.model.rest.VERIFICATION_METHOD_QR_
|
||||||
import org.matrix.android.sdk.internal.crypto.model.rest.VERIFICATION_METHOD_QR_CODE_SHOW
|
import org.matrix.android.sdk.internal.crypto.model.rest.VERIFICATION_METHOD_QR_CODE_SHOW
|
||||||
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 timber.log.Timber
|
import timber.log.Timber
|
||||||
import uniffi.olm.OlmMachine
|
import uniffi.olm.OlmMachine
|
||||||
import uniffi.olm.VerificationRequest
|
import uniffi.olm.VerificationRequest
|
||||||
|
@ -96,16 +97,7 @@ internal class VerificationRequest(
|
||||||
}
|
}
|
||||||
|
|
||||||
suspend fun acceptWithMethods(methods: List<VerificationMethod>) {
|
suspend fun acceptWithMethods(methods: List<VerificationMethod>) {
|
||||||
val stringMethods: MutableList<String> =
|
val stringMethods: MutableList<String> = methods.map { it.toValue() }.toMutableList()
|
||||||
methods
|
|
||||||
.map {
|
|
||||||
when (it) {
|
|
||||||
VerificationMethod.QR_CODE_SCAN -> VERIFICATION_METHOD_QR_CODE_SCAN
|
|
||||||
VerificationMethod.QR_CODE_SHOW -> VERIFICATION_METHOD_QR_CODE_SHOW
|
|
||||||
VerificationMethod.SAS -> VERIFICATION_METHOD_SAS
|
|
||||||
}
|
|
||||||
}
|
|
||||||
.toMutableList()
|
|
||||||
|
|
||||||
if (stringMethods.contains(VERIFICATION_METHOD_QR_CODE_SHOW) ||
|
if (stringMethods.contains(VERIFICATION_METHOD_QR_CODE_SHOW) ||
|
||||||
stringMethods.contains(VERIFICATION_METHOD_QR_CODE_SCAN)) {
|
stringMethods.contains(VERIFICATION_METHOD_QR_CODE_SCAN)) {
|
||||||
|
|
|
@ -38,6 +38,10 @@ import org.matrix.android.sdk.internal.crypto.QrCodeVerification
|
||||||
import org.matrix.android.sdk.internal.crypto.RequestSender
|
import org.matrix.android.sdk.internal.crypto.RequestSender
|
||||||
import org.matrix.android.sdk.internal.crypto.SasVerification
|
import org.matrix.android.sdk.internal.crypto.SasVerification
|
||||||
import org.matrix.android.sdk.internal.crypto.VerificationRequest
|
import org.matrix.android.sdk.internal.crypto.VerificationRequest
|
||||||
|
import org.matrix.android.sdk.internal.crypto.model.rest.VERIFICATION_METHOD_QR_CODE_SCAN
|
||||||
|
import org.matrix.android.sdk.internal.crypto.model.rest.VERIFICATION_METHOD_QR_CODE_SHOW
|
||||||
|
import org.matrix.android.sdk.internal.crypto.model.rest.VERIFICATION_METHOD_RECIPROCATE
|
||||||
|
import org.matrix.android.sdk.internal.crypto.model.rest.toValue
|
||||||
import org.matrix.android.sdk.internal.session.SessionScope
|
import org.matrix.android.sdk.internal.session.SessionScope
|
||||||
import timber.log.Timber
|
import timber.log.Timber
|
||||||
import uniffi.olm.Verification
|
import uniffi.olm.Verification
|
||||||
|
@ -258,7 +262,22 @@ internal class RustVerificationService(
|
||||||
tid: String?
|
tid: String?
|
||||||
): PendingVerificationRequest? {
|
): PendingVerificationRequest? {
|
||||||
// This is only used in `RoomDetailViewModel` to resume the verification.
|
// This is only used in `RoomDetailViewModel` to resume the verification.
|
||||||
// We don't support resuming in the rust-sdk, at least for now, so let's return null here.
|
//
|
||||||
|
// Is this actually useful? SAS and QR code verifications ephemeral nature
|
||||||
|
// due to the usage of ephemeral secrets. In the case of SAS verification, the
|
||||||
|
// ephemeral key can't be stored due to libolm missing support for it, I would
|
||||||
|
// argue that the ephemeral secret for QR verifications shouldn't be persisted either.
|
||||||
|
//
|
||||||
|
// This means that once we transition from a verification request into an actual
|
||||||
|
// verification flow (SAS/QR) we won't be able to resume. In other words resumption
|
||||||
|
// is only supported before both sides agree to verify.
|
||||||
|
//
|
||||||
|
// We would either need to remember if the request transitioned into a flow and only
|
||||||
|
// support resumption if we didn't, otherwise we would risk getting different emojis
|
||||||
|
// or secrets in the QR code, not to mention that the flows could be interrupted in
|
||||||
|
// any non-starting state.
|
||||||
|
//
|
||||||
|
// In any case, we don't support resuming in the rust-sdk, so let's return null here.
|
||||||
return null
|
return null
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -267,8 +286,19 @@ internal class RustVerificationService(
|
||||||
otherUserId: String,
|
otherUserId: String,
|
||||||
otherDevices: List<String>?
|
otherDevices: List<String>?
|
||||||
): PendingVerificationRequest {
|
): PendingVerificationRequest {
|
||||||
// This was mostly a copy paste of the InDMs method, do the same here
|
|
||||||
TODO()
|
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)
|
||||||
|
runBlocking {
|
||||||
|
requestSender.sendVerificationRequest(result!!.request)
|
||||||
|
}
|
||||||
|
|
||||||
|
return VerificationRequest(this.olmMachine.inner(), result!!.verification, this.requestSender, this.listeners).toPendingVerificationRequest()
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun requestKeyVerificationInDMs(
|
override fun requestKeyVerificationInDMs(
|
||||||
|
@ -278,10 +308,21 @@ 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()
|
||||||
|
|
||||||
// TODO cancel other active requests, create a new request here and
|
if (stringMethods.contains(VERIFICATION_METHOD_QR_CODE_SHOW) ||
|
||||||
// dispatch it
|
stringMethods.contains(VERIFICATION_METHOD_QR_CODE_SCAN)) {
|
||||||
TODO()
|
stringMethods.add(VERIFICATION_METHOD_RECIPROCATE)
|
||||||
|
}
|
||||||
|
|
||||||
|
val content = this.olmMachine.inner().verificationRequestContent(otherUserId, stringMethods)!!
|
||||||
|
|
||||||
|
val eventID = runBlocking {
|
||||||
|
requestSender.sendRoomMessage(EventType.MESSAGE, roomId, content, localId!!)
|
||||||
|
}
|
||||||
|
|
||||||
|
val innerRequest = this.olmMachine.inner().requestVerification(otherUserId, roomId, eventID, stringMethods)!!
|
||||||
|
return VerificationRequest(this.olmMachine.inner(), innerRequest, this.requestSender, this.listeners).toPendingVerificationRequest()
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun readyPendingVerification(
|
override fun readyPendingVerification(
|
||||||
|
@ -347,10 +388,10 @@ internal class RustVerificationService(
|
||||||
// DeviceListBottomSheetViewModel triggers this, interestingly the method that
|
// DeviceListBottomSheetViewModel triggers this, interestingly the method that
|
||||||
// triggers this is called `manuallyVerify()`
|
// triggers this is called `manuallyVerify()`
|
||||||
runBlocking {
|
runBlocking {
|
||||||
val sas = getDevice(otherUserId, otherDeviceId)?.startVerification()
|
val verification = getDevice(otherUserId, otherDeviceId)?.startVerification()
|
||||||
if (sas != null) {
|
if (verification != null) {
|
||||||
dispatchTxAdded(sas)
|
dispatchTxAdded(verification)
|
||||||
sas.transactionId
|
verification.transactionId
|
||||||
} else {
|
} else {
|
||||||
null
|
null
|
||||||
}
|
}
|
||||||
|
|
|
@ -25,11 +25,11 @@ features = ["lax_deserialize"]
|
||||||
|
|
||||||
[dependencies.matrix-sdk-common]
|
[dependencies.matrix-sdk-common]
|
||||||
git = "https://github.com/matrix-org/matrix-rust-sdk/"
|
git = "https://github.com/matrix-org/matrix-rust-sdk/"
|
||||||
rev = "9052843acbc762388f4ae59e6dad0d580914cf59"
|
rev = "c5df7c5356c2540ede95f41e3565e91ca7de5777"
|
||||||
|
|
||||||
[dependencies.matrix-sdk-crypto]
|
[dependencies.matrix-sdk-crypto]
|
||||||
git = "https://github.com/matrix-org/matrix-rust-sdk/"
|
git = "https://github.com/matrix-org/matrix-rust-sdk/"
|
||||||
rev = "9052843acbc762388f4ae59e6dad0d580914cf59"
|
rev = "c5df7c5356c2540ede95f41e3565e91ca7de5777"
|
||||||
features = ["sled_cryptostore"]
|
features = ["sled_cryptostore"]
|
||||||
|
|
||||||
[dependencies.tokio]
|
[dependencies.tokio]
|
||||||
|
|
|
@ -8,7 +8,8 @@ pub use device::Device;
|
||||||
pub use error::{CryptoStoreError, DecryptionError, KeyImportError, MachineCreationError};
|
pub use error::{CryptoStoreError, DecryptionError, KeyImportError, MachineCreationError};
|
||||||
pub use logger::{set_logger, Logger};
|
pub use logger::{set_logger, Logger};
|
||||||
pub use machine::{
|
pub use machine::{
|
||||||
KeyRequestPair, OlmMachine, QrCode, Sas, StartSasResult, Verification, VerificationRequest,
|
KeyRequestPair, OlmMachine, QrCode, RequestVerificationResult, Sas, StartSasResult,
|
||||||
|
Verification, VerificationRequest,
|
||||||
};
|
};
|
||||||
pub use responses::{
|
pub use responses::{
|
||||||
DeviceLists, KeysImportResult, OutgoingVerificationRequest, Request, RequestType,
|
DeviceLists, KeysImportResult, OutgoingVerificationRequest, Request, RequestType,
|
||||||
|
|
|
@ -22,7 +22,7 @@ use ruma::{
|
||||||
key::verification::VerificationMethod, room::encrypted::EncryptedEventContent,
|
key::verification::VerificationMethod, room::encrypted::EncryptedEventContent,
|
||||||
AnyMessageEventContent, EventContent, SyncMessageEvent,
|
AnyMessageEventContent, EventContent, SyncMessageEvent,
|
||||||
},
|
},
|
||||||
DeviceKeyAlgorithm, RoomId, UserId,
|
DeviceKeyAlgorithm, EventId, RoomId, UserId,
|
||||||
};
|
};
|
||||||
use serde::{Deserialize, Serialize};
|
use serde::{Deserialize, Serialize};
|
||||||
use serde_json::value::RawValue;
|
use serde_json::value::RawValue;
|
||||||
|
@ -128,6 +128,11 @@ impl From<InnerSas> for Sas {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub struct RequestVerificationResult {
|
||||||
|
pub verification: VerificationRequest,
|
||||||
|
pub request: OutgoingVerificationRequest,
|
||||||
|
}
|
||||||
|
|
||||||
pub struct VerificationRequest {
|
pub struct VerificationRequest {
|
||||||
pub other_user_id: String,
|
pub other_user_id: String,
|
||||||
pub other_device_id: Option<String>,
|
pub other_device_id: Option<String>,
|
||||||
|
@ -716,11 +721,6 @@ impl OlmMachine {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn request_verification(&self, user_id: &str) {
|
|
||||||
let _user_id = UserId::try_from(user_id).unwrap();
|
|
||||||
todo!("Requesting key verification isn't yet supported")
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn get_verification(&self, user_id: &str, flow_id: &str) -> Option<Verification> {
|
pub fn get_verification(&self, user_id: &str, flow_id: &str) -> Option<Verification> {
|
||||||
let user_id = UserId::try_from(user_id).ok()?;
|
let user_id = UserId::try_from(user_id).ok()?;
|
||||||
self.inner
|
self.inner
|
||||||
|
@ -758,6 +758,87 @@ impl OlmMachine {
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn request_verification(
|
||||||
|
&self,
|
||||||
|
user_id: &str,
|
||||||
|
room_id: &str,
|
||||||
|
event_id: &str,
|
||||||
|
methods: Vec<String>,
|
||||||
|
) -> Result<Option<VerificationRequest>, CryptoStoreError> {
|
||||||
|
let user_id = UserId::try_from(user_id)?;
|
||||||
|
let event_id = EventId::try_from(event_id)?;
|
||||||
|
let room_id = RoomId::try_from(room_id)?;
|
||||||
|
|
||||||
|
let identity = self.runtime.block_on(self.inner.get_identity(&user_id))?;
|
||||||
|
|
||||||
|
let methods = methods
|
||||||
|
.into_iter()
|
||||||
|
.map(|m| VerificationMethod::from(m))
|
||||||
|
.collect();
|
||||||
|
|
||||||
|
Ok(if let Some(identity) = identity.and_then(|i| i.other()) {
|
||||||
|
let request = self.runtime.block_on(identity.request_verification(
|
||||||
|
&room_id,
|
||||||
|
&event_id,
|
||||||
|
Some(methods),
|
||||||
|
));
|
||||||
|
|
||||||
|
Some(request.into())
|
||||||
|
} else {
|
||||||
|
None
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn verification_request_content(
|
||||||
|
&self,
|
||||||
|
user_id: &str,
|
||||||
|
methods: Vec<String>,
|
||||||
|
) -> Result<Option<String>, CryptoStoreError> {
|
||||||
|
let user_id = UserId::try_from(user_id)?;
|
||||||
|
|
||||||
|
let identity = self.runtime.block_on(self.inner.get_identity(&user_id))?;
|
||||||
|
|
||||||
|
let methods = methods
|
||||||
|
.into_iter()
|
||||||
|
.map(|m| VerificationMethod::from(m))
|
||||||
|
.collect();
|
||||||
|
|
||||||
|
Ok(if let Some(identity) = identity.and_then(|i| i.other()) {
|
||||||
|
let content = self
|
||||||
|
.runtime
|
||||||
|
.block_on(identity.verification_request_content(Some(methods)));
|
||||||
|
Some(serde_json::to_string(&content)?)
|
||||||
|
} else {
|
||||||
|
None
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn request_self_verification(
|
||||||
|
&self,
|
||||||
|
methods: Vec<String>,
|
||||||
|
) -> Result<Option<RequestVerificationResult>, CryptoStoreError> {
|
||||||
|
let identity = self
|
||||||
|
.runtime
|
||||||
|
.block_on(self.inner.get_identity(self.inner.user_id()))?;
|
||||||
|
|
||||||
|
let methods = methods
|
||||||
|
.into_iter()
|
||||||
|
.map(|m| VerificationMethod::from(m))
|
||||||
|
.collect();
|
||||||
|
|
||||||
|
Ok(if let Some(identity) = identity.and_then(|i| i.own()) {
|
||||||
|
let (verification, request) = self
|
||||||
|
.runtime
|
||||||
|
.block_on(identity.request_verification_with_methods(methods))?;
|
||||||
|
Some(RequestVerificationResult {
|
||||||
|
verification: verification.into(),
|
||||||
|
request: request.into(),
|
||||||
|
})
|
||||||
|
} else {
|
||||||
|
None
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
pub fn start_sas_with_device(
|
pub fn start_sas_with_device(
|
||||||
&self,
|
&self,
|
||||||
user_id: &str,
|
user_id: &str,
|
||||||
|
|
|
@ -117,6 +117,11 @@ dictionary VerificationRequest {
|
||||||
|
|
||||||
};
|
};
|
||||||
|
|
||||||
|
dictionary RequestVerificationResult {
|
||||||
|
VerificationRequest verification;
|
||||||
|
OutgoingVerificationRequest request;
|
||||||
|
};
|
||||||
|
|
||||||
[Enum]
|
[Enum]
|
||||||
interface Verification {
|
interface Verification {
|
||||||
SasV1(Sas sas);
|
SasV1(Sas sas);
|
||||||
|
@ -199,6 +204,20 @@ interface OlmMachine {
|
||||||
sequence<string> methods
|
sequence<string> methods
|
||||||
);
|
);
|
||||||
|
|
||||||
|
[Throws=CryptoStoreError]
|
||||||
|
VerificationRequest? request_verification(
|
||||||
|
[ByRef] string user_id,
|
||||||
|
[ByRef] string room_id,
|
||||||
|
[ByRef] string event_id,
|
||||||
|
sequence<string> methods
|
||||||
|
);
|
||||||
|
[Throws=CryptoStoreError]
|
||||||
|
string? verification_request_content(
|
||||||
|
[ByRef] string user_id,
|
||||||
|
sequence<string> methods
|
||||||
|
);
|
||||||
|
[Throws=CryptoStoreError]
|
||||||
|
RequestVerificationResult? request_self_verification(sequence<string> methods);
|
||||||
[Throws=CryptoStoreError]
|
[Throws=CryptoStoreError]
|
||||||
StartSasResult? start_sas_with_device([ByRef] string user_id, [ByRef] string device_id);
|
StartSasResult? start_sas_with_device([ByRef] string user_id, [ByRef] string device_id);
|
||||||
[Throws=CryptoStoreError]
|
[Throws=CryptoStoreError]
|
||||||
|
|
Loading…
Reference in a new issue