matrix-sdk: Initial import of the rust-sdk crypto layer.

This commit is contained in:
Damir Jelić 2021-02-09 15:41:01 +01:00
parent fa710ff601
commit de5a02b02a
7 changed files with 359 additions and 0 deletions

View File

@ -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() {
def cmd = "git rev-parse --short=8 HEAD"
return cmd.execute().text.trim()
@ -116,6 +130,8 @@ dependencies {
def work_version = '2.4.0'
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.kotlinx:kotlinx-coroutines-core:$kotlin_coroutines_version"
implementation "org.jetbrains.kotlinx:kotlinx-coroutines-android:$kotlin_coroutines_version"

View File

@ -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.RoomHistoryVisibilityContent
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.SetDeviceVerificationAction
import org.matrix.android.sdk.internal.crypto.algorithms.IMXEncrypting
@ -362,6 +363,14 @@ internal class DefaultCryptoService @Inject constructor(
return
}
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
cryptoStore.open()

View File

@ -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
View 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
View File

@ -0,0 +1,3 @@
fn main() {
uniffi_build::generate_scaffolding("./src/olm.udl").unwrap();
}

178
rust-sdk/src/lib.rs Normal file
View 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
View 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);
};