matrix-sdk: Initial import of the rust-sdk crypto layer.
This commit is contained in:
parent
fa710ff601
commit
de5a02b02a
@ -90,6 +90,20 @@ android {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
android.libraryVariants.all { variant ->
|
||||||
|
def t = tasks.register("generate${variant.name.capitalize()}UniffiBindings", Exec) {
|
||||||
|
// Runs the bindings generation, note that you must have uniffi-bindgen installed
|
||||||
|
// and in your PATH environment variable
|
||||||
|
commandLine 'uniffi-bindgen', 'generate', '../rust-sdk/src/olm.udl',
|
||||||
|
'--language', 'kotlin',
|
||||||
|
'--out-dir', "${buildDir}/generated/source/uniffi/${variant.name}/java"
|
||||||
|
}
|
||||||
|
|
||||||
|
variant.javaCompileProvider.get().dependsOn(t)
|
||||||
|
def sourceSet = variant.sourceSets.find { it.name == variant.name }
|
||||||
|
sourceSet.java.srcDir new File(buildDir, "generated/source/uniffi/${variant.name}/java")
|
||||||
|
}
|
||||||
|
|
||||||
static def gitRevision() {
|
static def gitRevision() {
|
||||||
def cmd = "git rev-parse --short=8 HEAD"
|
def cmd = "git rev-parse --short=8 HEAD"
|
||||||
return cmd.execute().text.trim()
|
return cmd.execute().text.trim()
|
||||||
@ -116,6 +130,8 @@ dependencies {
|
|||||||
def work_version = '2.4.0'
|
def work_version = '2.4.0'
|
||||||
def retrofit_version = '2.6.2'
|
def retrofit_version = '2.6.2'
|
||||||
|
|
||||||
|
implementation 'net.java.dev.jna:jna:5.6.0@aar'
|
||||||
|
|
||||||
implementation "org.jetbrains.kotlin:kotlin-stdlib-jdk7:$kotlin_version"
|
implementation "org.jetbrains.kotlin:kotlin-stdlib-jdk7:$kotlin_version"
|
||||||
implementation "org.jetbrains.kotlinx:kotlinx-coroutines-core:$kotlin_coroutines_version"
|
implementation "org.jetbrains.kotlinx:kotlinx-coroutines-core:$kotlin_coroutines_version"
|
||||||
implementation "org.jetbrains.kotlinx:kotlinx-coroutines-android:$kotlin_coroutines_version"
|
implementation "org.jetbrains.kotlinx:kotlinx-coroutines-android:$kotlin_coroutines_version"
|
||||||
|
@ -50,6 +50,7 @@ import org.matrix.android.sdk.api.session.room.model.Membership
|
|||||||
import org.matrix.android.sdk.api.session.room.model.RoomHistoryVisibility
|
import org.matrix.android.sdk.api.session.room.model.RoomHistoryVisibility
|
||||||
import org.matrix.android.sdk.api.session.room.model.RoomHistoryVisibilityContent
|
import org.matrix.android.sdk.api.session.room.model.RoomHistoryVisibilityContent
|
||||||
import org.matrix.android.sdk.api.session.room.model.RoomMemberContent
|
import org.matrix.android.sdk.api.session.room.model.RoomMemberContent
|
||||||
|
import org.matrix.android.sdk.internal.OlmMachine
|
||||||
import org.matrix.android.sdk.internal.crypto.actions.MegolmSessionDataImporter
|
import org.matrix.android.sdk.internal.crypto.actions.MegolmSessionDataImporter
|
||||||
import org.matrix.android.sdk.internal.crypto.actions.SetDeviceVerificationAction
|
import org.matrix.android.sdk.internal.crypto.actions.SetDeviceVerificationAction
|
||||||
import org.matrix.android.sdk.internal.crypto.algorithms.IMXEncrypting
|
import org.matrix.android.sdk.internal.crypto.algorithms.IMXEncrypting
|
||||||
@ -362,6 +363,14 @@ internal class DefaultCryptoService @Inject constructor(
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
isStarting.set(true)
|
isStarting.set(true)
|
||||||
|
try {
|
||||||
|
val dataDir = "/data/data/im.vector.app.debug/files"
|
||||||
|
val olmMachine = OlmMachine("@example:localhost", "DEVICEID", dataDir)
|
||||||
|
Timber.v("HELLLO WORLD STARTING CRYPTO ${olmMachine.identityKeys()}")
|
||||||
|
} catch (throwable: Throwable) {
|
||||||
|
Timber.v("HELLLO WORLD FAILED CRYPTO $throwable")
|
||||||
|
}
|
||||||
|
Timber.v("HELLLO WORLD STARTING CRYPTO")
|
||||||
|
|
||||||
// Open the store
|
// Open the store
|
||||||
cryptoStore.open()
|
cryptoStore.open()
|
||||||
|
@ -0,0 +1,72 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (c) 2021 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 org.matrix.android.sdk.internal
|
||||||
|
|
||||||
|
import kotlinx.coroutines.withContext
|
||||||
|
import kotlinx.coroutines.Dispatchers
|
||||||
|
|
||||||
|
import uniffi.olm.OlmMachine as InnerMachine
|
||||||
|
import uniffi.olm.Device as InnerDevice
|
||||||
|
import uniffi.olm.Sas as InnerSas
|
||||||
|
|
||||||
|
class Device(inner: InnerDevice, machine: InnerMachine) {
|
||||||
|
private val machine: InnerMachine = machine
|
||||||
|
private val inner: InnerDevice = inner
|
||||||
|
|
||||||
|
fun userId(): String {
|
||||||
|
return this.inner.userId
|
||||||
|
}
|
||||||
|
|
||||||
|
fun deviceId(): String {
|
||||||
|
return this.inner.deviceId
|
||||||
|
}
|
||||||
|
|
||||||
|
fun keys(): Map<String, String> {
|
||||||
|
return this.inner.keys
|
||||||
|
}
|
||||||
|
|
||||||
|
fun startVerification(): InnerSas {
|
||||||
|
return this.machine.startVerification(this.inner)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
class OlmMachine(user_id: String, device_id: String, path: String) {
|
||||||
|
private val inner: InnerMachine = InnerMachine(user_id, device_id, path)
|
||||||
|
|
||||||
|
fun userId(): String {
|
||||||
|
return this.inner.userId()
|
||||||
|
}
|
||||||
|
|
||||||
|
fun deviceId(): String {
|
||||||
|
return this.inner.deviceId()
|
||||||
|
}
|
||||||
|
|
||||||
|
fun identityKeys(): Map<String, String> {
|
||||||
|
return this.inner.identityKeys()
|
||||||
|
}
|
||||||
|
|
||||||
|
suspend fun slowUserId(): String = withContext(Dispatchers.Default) {
|
||||||
|
inner.slowUserId()
|
||||||
|
}
|
||||||
|
|
||||||
|
suspend fun getDevice(user_id: String, device_id: String): Device? = withContext(Dispatchers.IO) {
|
||||||
|
when (val device: InnerDevice? = inner.getDevice(user_id, device_id)) {
|
||||||
|
null -> null
|
||||||
|
else -> Device(device, inner)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
25
rust-sdk/Cargo.toml
Normal file
25
rust-sdk/Cargo.toml
Normal file
@ -0,0 +1,25 @@
|
|||||||
|
[package]
|
||||||
|
name = "matrix-crypto-bindings"
|
||||||
|
version = "0.1.0"
|
||||||
|
authors = ["Damir Jelić <poljar@termina.org.uk>"]
|
||||||
|
edition = "2018"
|
||||||
|
|
||||||
|
[lib]
|
||||||
|
crate-type = ["cdylib", "lib"]
|
||||||
|
name = "matrix_crypto"
|
||||||
|
|
||||||
|
[dependencies]
|
||||||
|
matrix-sdk-crypto = { git = "https://github.com/matrix-org/matrix-rust-sdk/", features = ["sled_cryptostore"] }
|
||||||
|
matrix-sdk-common = { git = "https://github.com/matrix-org/matrix-rust-sdk/"}
|
||||||
|
futures = { version = "0.3.12", default_features = false, features = ["executor"] }
|
||||||
|
tokio = { version = "1.1.1", default_features = false, features = ["rt-multi-thread", "time"] }
|
||||||
|
serde_json = "1.0.61"
|
||||||
|
thiserror = "1.0.23"
|
||||||
|
http = "0.2.3"
|
||||||
|
uniffi = "0.7.0"
|
||||||
|
|
||||||
|
[build-dependencies]
|
||||||
|
uniffi_build = "0.7.0"
|
||||||
|
|
||||||
|
[patch.crates-io]
|
||||||
|
olm-sys = { git = "https://gitlab.gnome.org/poljar/olm-sys/", branch = "android-cross" }
|
3
rust-sdk/build.rs
Normal file
3
rust-sdk/build.rs
Normal file
@ -0,0 +1,3 @@
|
|||||||
|
fn main() {
|
||||||
|
uniffi_build::generate_scaffolding("./src/olm.udl").unwrap();
|
||||||
|
}
|
178
rust-sdk/src/lib.rs
Normal file
178
rust-sdk/src/lib.rs
Normal file
@ -0,0 +1,178 @@
|
|||||||
|
use std::{collections::HashMap, convert::TryFrom, time::Duration};
|
||||||
|
|
||||||
|
use futures::{
|
||||||
|
executor::block_on,
|
||||||
|
future::{abortable, AbortHandle, Aborted},
|
||||||
|
Future,
|
||||||
|
};
|
||||||
|
use http::Response;
|
||||||
|
use tokio::{runtime::Runtime, time::sleep};
|
||||||
|
|
||||||
|
use matrix_sdk_common::{
|
||||||
|
api::r0::sync::sync_events::Response as SyncResponse,
|
||||||
|
api::r0::to_device::send_event_to_device::METADATA,
|
||||||
|
identifiers::{Error as RumaIdentifierError, UserId},
|
||||||
|
};
|
||||||
|
use matrix_sdk_crypto::{
|
||||||
|
store::CryptoStoreError as InnerStoreError, OlmMachine as InnerMachine, ToDeviceRequest,
|
||||||
|
};
|
||||||
|
|
||||||
|
pub struct OlmMachine {
|
||||||
|
inner: InnerMachine,
|
||||||
|
runtime: Runtime,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Debug, thiserror::Error)]
|
||||||
|
pub enum MachineCreationError {
|
||||||
|
#[error(transparent)]
|
||||||
|
Identifier(#[from] RumaIdentifierError),
|
||||||
|
#[error(transparent)]
|
||||||
|
CryptoStore(#[from] InnerStoreError),
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Debug, thiserror::Error)]
|
||||||
|
pub enum CryptoStoreError {
|
||||||
|
#[error(transparent)]
|
||||||
|
CryptoStore(#[from] InnerStoreError),
|
||||||
|
}
|
||||||
|
|
||||||
|
pub enum RequestType {
|
||||||
|
KeysQuery,
|
||||||
|
KeysUpload,
|
||||||
|
ToDevice,
|
||||||
|
}
|
||||||
|
|
||||||
|
pub struct Device {
|
||||||
|
pub user_id: String,
|
||||||
|
pub device_id: String,
|
||||||
|
pub keys: HashMap<String, String>,
|
||||||
|
}
|
||||||
|
|
||||||
|
pub struct Sas {
|
||||||
|
pub other_user_id: String,
|
||||||
|
pub other_device_id: String,
|
||||||
|
pub flow_id: String,
|
||||||
|
pub request: Request,
|
||||||
|
}
|
||||||
|
|
||||||
|
pub struct Request {
|
||||||
|
pub request_id: String,
|
||||||
|
pub request_type: RequestType,
|
||||||
|
pub request_body: String,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl From<ToDeviceRequest> for Request {
|
||||||
|
fn from(r: ToDeviceRequest) -> Self {
|
||||||
|
Request {
|
||||||
|
request_id: r.txn_id_string(),
|
||||||
|
request_type: RequestType::ToDevice,
|
||||||
|
request_body: serde_json::to_string(&r.messages).unwrap(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn response_from_string(body: &str) -> Response<Vec<u8>> {
|
||||||
|
Response::builder()
|
||||||
|
.status(200)
|
||||||
|
.body(body.as_bytes().to_vec())
|
||||||
|
.expect("Can't create HTTP response")
|
||||||
|
}
|
||||||
|
|
||||||
|
impl OlmMachine {
|
||||||
|
pub fn new(user_id: &str, device_id: &str, path: &str) -> Result<Self, MachineCreationError> {
|
||||||
|
let user_id = UserId::try_from(user_id)?;
|
||||||
|
let device_id = device_id.into();
|
||||||
|
|
||||||
|
Ok(OlmMachine {
|
||||||
|
inner: block_on(InnerMachine::new_with_default_store(
|
||||||
|
&user_id,
|
||||||
|
device_id,
|
||||||
|
path,
|
||||||
|
Some("DEFAULT_PASSPHRASE"),
|
||||||
|
))?,
|
||||||
|
runtime: Runtime::new().unwrap(),
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn user_id(&self) -> String {
|
||||||
|
self.inner.user_id().to_string()
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn device_id(&self) -> String {
|
||||||
|
self.inner.device_id().to_string()
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn get_device(&self, user_id: &str, device_id: &str) -> Option<Device> {
|
||||||
|
let user_id = UserId::try_from(user_id).unwrap();
|
||||||
|
|
||||||
|
block_on(self.inner.get_device(&user_id, device_id.into()))
|
||||||
|
.unwrap()
|
||||||
|
.map(|d| Device {
|
||||||
|
user_id: d.user_id().to_string(),
|
||||||
|
device_id: d.device_id().to_string(),
|
||||||
|
keys: d
|
||||||
|
.keys()
|
||||||
|
.iter()
|
||||||
|
.map(|(k, v)| (k.to_string(), v.to_string()))
|
||||||
|
.collect(),
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn get_user_devices(&self, user_id: &str) -> Vec<Device> {
|
||||||
|
let user_id = UserId::try_from(user_id).unwrap();
|
||||||
|
block_on(self.inner.get_user_devices(&user_id))
|
||||||
|
.unwrap()
|
||||||
|
.devices()
|
||||||
|
.map(|d| Device {
|
||||||
|
user_id: d.user_id().to_string(),
|
||||||
|
device_id: d.device_id().to_string(),
|
||||||
|
keys: d
|
||||||
|
.keys()
|
||||||
|
.iter()
|
||||||
|
.map(|(k, v)| (k.to_string(), v.to_string()))
|
||||||
|
.collect(),
|
||||||
|
})
|
||||||
|
.collect()
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn identity_keys(&self) -> HashMap<String, String> {
|
||||||
|
self.inner
|
||||||
|
.identity_keys()
|
||||||
|
.iter()
|
||||||
|
.map(|(k, v)| (k.to_owned(), v.to_owned()))
|
||||||
|
.collect()
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn slow_user_id(&self) -> String {
|
||||||
|
let machine = self.inner.clone();
|
||||||
|
|
||||||
|
self.runtime.block_on(async {
|
||||||
|
sleep(Duration::from_secs(10)).await;
|
||||||
|
machine.user_id().to_string()
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn start_verification(&self, device: &Device) -> Result<Sas, CryptoStoreError> {
|
||||||
|
let user_id = UserId::try_from(device.user_id.clone()).unwrap();
|
||||||
|
let device_id = device.device_id.as_str().into();
|
||||||
|
let device = block_on(self.inner.get_device(&user_id, device_id))?.unwrap();
|
||||||
|
|
||||||
|
let (sas, request) = block_on(device.start_verification())?;
|
||||||
|
|
||||||
|
Ok(Sas {
|
||||||
|
other_user_id: sas.other_user_id().to_string(),
|
||||||
|
other_device_id: sas.other_device_id().to_string(),
|
||||||
|
flow_id: sas.flow_id().as_str().to_owned(),
|
||||||
|
request: request.into(),
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn receive_sync_response(&self, response: &str) {
|
||||||
|
let response = response_from_string(response);
|
||||||
|
let mut response = SyncResponse::try_from(response).expect("Can't parse response");
|
||||||
|
|
||||||
|
block_on(self.inner.receive_sync_response(&mut response)).unwrap();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
include!(concat!(env!("OUT_DIR"), "/olm.uniffi.rs"));
|
56
rust-sdk/src/olm.udl
Normal file
56
rust-sdk/src/olm.udl
Normal file
@ -0,0 +1,56 @@
|
|||||||
|
namespace olm {};
|
||||||
|
|
||||||
|
[Error]
|
||||||
|
enum MachineCreationError {
|
||||||
|
"Identifier",
|
||||||
|
"CryptoStore",
|
||||||
|
};
|
||||||
|
|
||||||
|
[Error]
|
||||||
|
enum CryptoStoreError {
|
||||||
|
"CryptoStore",
|
||||||
|
};
|
||||||
|
|
||||||
|
dictionary Device {
|
||||||
|
string user_id;
|
||||||
|
string device_id;
|
||||||
|
record<DOMString, string> keys;
|
||||||
|
};
|
||||||
|
|
||||||
|
dictionary Sas {
|
||||||
|
string other_user_id;
|
||||||
|
string other_device_id;
|
||||||
|
string flow_id;
|
||||||
|
Request request;
|
||||||
|
};
|
||||||
|
|
||||||
|
dictionary Request {
|
||||||
|
string request_id;
|
||||||
|
RequestType request_type;
|
||||||
|
string request_body;
|
||||||
|
};
|
||||||
|
|
||||||
|
enum RequestType {
|
||||||
|
"KeysQuery",
|
||||||
|
"KeysUpload",
|
||||||
|
"ToDevice",
|
||||||
|
};
|
||||||
|
|
||||||
|
interface OlmMachine {
|
||||||
|
[Throws=MachineCreationError]
|
||||||
|
constructor([ByRef] string user_id, [ByRef] string device_id, [ByRef] string path);
|
||||||
|
|
||||||
|
void receive_sync_response([ByRef] string response);
|
||||||
|
|
||||||
|
record<DOMString, string> identity_keys();
|
||||||
|
|
||||||
|
string user_id();
|
||||||
|
string slow_user_id();
|
||||||
|
string device_id();
|
||||||
|
|
||||||
|
Device? get_device([ByRef] string user_id, [ByRef] string device_id);
|
||||||
|
sequence<Device> get_user_devices([ByRef] string user_id);
|
||||||
|
|
||||||
|
[Throws=CryptoStoreError]
|
||||||
|
Sas start_verification([ByRef] Device device);
|
||||||
|
};
|
Loading…
Reference in New Issue
Block a user