crypto: Export cross signing related methods from the Rust side
This commit is contained in:
parent
e2006f9dc6
commit
b012a0ff75
@ -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 = "3a8ff2f6b43f312b7582146ed712ff245ef9d5aa"
|
rev = "b2ff6cb6ae3d1983a510262021cba27a1bc70d77"
|
||||||
|
|
||||||
[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 = "3a8ff2f6b43f312b7582146ed712ff245ef9d5aa"
|
rev = "b2ff6cb6ae3d1983a510262021cba27a1bc70d77"
|
||||||
features = ["sled_cryptostore"]
|
features = ["sled_cryptostore"]
|
||||||
|
|
||||||
[dependencies.tokio]
|
[dependencies.tokio]
|
||||||
@ -38,8 +38,12 @@ default_features = false
|
|||||||
features = ["rt-multi-thread"]
|
features = ["rt-multi-thread"]
|
||||||
|
|
||||||
[dependencies.ruma]
|
[dependencies.ruma]
|
||||||
version = "0.2.0"
|
version = "0.3.0"
|
||||||
features = ["client-api"]
|
features = ["client-api"]
|
||||||
|
|
||||||
[build-dependencies]
|
[build-dependencies]
|
||||||
uniffi_build = "0.12.0"
|
uniffi_build = "0.12.0"
|
||||||
|
|
||||||
|
[patch.crates-io]
|
||||||
|
ruma = { git = "https://github.com/matrix-org/ruma/", branch = "secrets" }
|
||||||
|
ruma-identifiers = { git = "https://github.com/matrix-org/ruma", branch = "secrets" }
|
||||||
|
@ -2,17 +2,10 @@
|
|||||||
|
|
||||||
use matrix_sdk_crypto::{
|
use matrix_sdk_crypto::{
|
||||||
store::CryptoStoreError as InnerStoreError, KeyExportError, MegolmError, OlmError,
|
store::CryptoStoreError as InnerStoreError, KeyExportError, MegolmError, OlmError,
|
||||||
|
SignatureError as InnerSignatureError, SecretImportError as RustSecretImportError,
|
||||||
};
|
};
|
||||||
use ruma::identifiers::Error as RumaIdentifierError;
|
use ruma::identifiers::Error as RumaIdentifierError;
|
||||||
|
|
||||||
#[derive(Debug, thiserror::Error)]
|
|
||||||
pub enum MachineCreationError {
|
|
||||||
#[error(transparent)]
|
|
||||||
Identifier(#[from] RumaIdentifierError),
|
|
||||||
#[error(transparent)]
|
|
||||||
CryptoStore(#[from] InnerStoreError),
|
|
||||||
}
|
|
||||||
|
|
||||||
#[derive(Debug, thiserror::Error)]
|
#[derive(Debug, thiserror::Error)]
|
||||||
pub enum KeyImportError {
|
pub enum KeyImportError {
|
||||||
#[error(transparent)]
|
#[error(transparent)]
|
||||||
@ -21,6 +14,28 @@ pub enum KeyImportError {
|
|||||||
CryptoStore(#[from] InnerStoreError),
|
CryptoStore(#[from] InnerStoreError),
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[derive(Debug, thiserror::Error)]
|
||||||
|
pub enum SecretImportError {
|
||||||
|
#[error(transparent)]
|
||||||
|
CryptoStore(#[from] InnerStoreError),
|
||||||
|
#[error(transparent)]
|
||||||
|
Import(#[from] RustSecretImportError),
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Debug, thiserror::Error)]
|
||||||
|
pub enum SignatureError {
|
||||||
|
#[error(transparent)]
|
||||||
|
Signature(#[from] InnerSignatureError),
|
||||||
|
#[error(transparent)]
|
||||||
|
Identifier(#[from] RumaIdentifierError),
|
||||||
|
#[error(transparent)]
|
||||||
|
CryptoStore(#[from] InnerStoreError),
|
||||||
|
#[error("Unknown device {0} {1}")]
|
||||||
|
UnknownDevice(String, String),
|
||||||
|
#[error("Unknown user identity {0}")]
|
||||||
|
UnknownUserIdentity(String),
|
||||||
|
}
|
||||||
|
|
||||||
#[derive(Debug, thiserror::Error)]
|
#[derive(Debug, thiserror::Error)]
|
||||||
pub enum CryptoStoreError {
|
pub enum CryptoStoreError {
|
||||||
#[error(transparent)]
|
#[error(transparent)]
|
||||||
|
@ -15,15 +15,18 @@ mod error;
|
|||||||
mod logger;
|
mod logger;
|
||||||
mod machine;
|
mod machine;
|
||||||
mod responses;
|
mod responses;
|
||||||
|
mod users;
|
||||||
mod verification;
|
mod verification;
|
||||||
|
|
||||||
pub use device::Device;
|
pub use device::Device;
|
||||||
pub use error::{CryptoStoreError, DecryptionError, KeyImportError, MachineCreationError};
|
pub use error::{CryptoStoreError, DecryptionError, KeyImportError, SignatureError, SecretImportError};
|
||||||
pub use logger::{set_logger, Logger};
|
pub use logger::{set_logger, Logger};
|
||||||
pub use machine::{KeyRequestPair, OlmMachine};
|
pub use machine::{KeyRequestPair, OlmMachine};
|
||||||
pub use responses::{
|
pub use responses::{
|
||||||
DeviceLists, KeysImportResult, OutgoingVerificationRequest, Request, RequestType,
|
DeviceLists, KeysImportResult, OutgoingVerificationRequest, Request, RequestType, SignatureUploadRequest,
|
||||||
|
BootstrapCrossSigningResult, UploadSigningKeysRequest,
|
||||||
};
|
};
|
||||||
|
pub use users::UserIdentity;
|
||||||
pub use verification::{
|
pub use verification::{
|
||||||
CancelInfo, QrCode, RequestVerificationResult, Sas, ScanResult, StartSasResult, Verification,
|
CancelInfo, QrCode, RequestVerificationResult, Sas, ScanResult, StartSasResult, Verification,
|
||||||
VerificationRequest,
|
VerificationRequest,
|
||||||
@ -55,4 +58,59 @@ pub struct DecryptedEvent {
|
|||||||
pub forwarding_curve25519_chain: Vec<String>,
|
pub forwarding_curve25519_chain: Vec<String>,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Struct representing the state of our private cross signing keys, it shows
|
||||||
|
/// which private cross signing keys we have locally stored.
|
||||||
|
#[derive(Debug, Clone)]
|
||||||
|
pub struct CrossSigningStatus {
|
||||||
|
/// Do we have the master key.
|
||||||
|
pub has_master: bool,
|
||||||
|
/// Do we have the self signing key, this one is necessary to sign our own
|
||||||
|
/// devices.
|
||||||
|
pub has_self_signing: bool,
|
||||||
|
/// Do we have the user signing key, this one is necessary to sign other
|
||||||
|
/// users.
|
||||||
|
pub has_user_signing: bool,
|
||||||
|
}
|
||||||
|
|
||||||
|
/// A struct containing private cross signing keys that can be backed up or
|
||||||
|
/// uploaded to the secret store.
|
||||||
|
pub struct CrossSigningKeyExport {
|
||||||
|
/// The seed of the master key encoded as unpadded base64.
|
||||||
|
pub master_key: Option<String>,
|
||||||
|
/// The seed of the self signing key encoded as unpadded base64.
|
||||||
|
pub self_signing_key: Option<String>,
|
||||||
|
/// The seed of the user signing key encoded as unpadded base64.
|
||||||
|
pub user_signing_key: Option<String>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl From<matrix_sdk_crypto::CrossSigningKeyExport> for CrossSigningKeyExport {
|
||||||
|
fn from(e: matrix_sdk_crypto::CrossSigningKeyExport) -> Self {
|
||||||
|
Self {
|
||||||
|
master_key: e.master_key.clone(),
|
||||||
|
self_signing_key: e.self_signing_key.clone(),
|
||||||
|
user_signing_key: e.user_signing_key.clone(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Into<matrix_sdk_crypto::CrossSigningKeyExport> for CrossSigningKeyExport {
|
||||||
|
fn into(self) -> matrix_sdk_crypto::CrossSigningKeyExport {
|
||||||
|
matrix_sdk_crypto::CrossSigningKeyExport {
|
||||||
|
master_key: self.master_key,
|
||||||
|
self_signing_key: self.self_signing_key,
|
||||||
|
user_signing_key: self.user_signing_key,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl From<matrix_sdk_crypto::CrossSigningStatus> for CrossSigningStatus {
|
||||||
|
fn from(s: matrix_sdk_crypto::CrossSigningStatus) -> Self {
|
||||||
|
Self {
|
||||||
|
has_master: s.has_master,
|
||||||
|
has_self_signing: s.has_self_signing,
|
||||||
|
has_user_signing: s.has_user_signing,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
include!(concat!(env!("OUT_DIR"), "/olm.uniffi.rs"));
|
include!(concat!(env!("OUT_DIR"), "/olm.uniffi.rs"));
|
||||||
|
@ -12,6 +12,7 @@ use ruma::{
|
|||||||
keys::{
|
keys::{
|
||||||
claim_keys::Response as KeysClaimResponse, get_keys::Response as KeysQueryResponse,
|
claim_keys::Response as KeysClaimResponse, get_keys::Response as KeysQueryResponse,
|
||||||
upload_keys::Response as KeysUploadResponse,
|
upload_keys::Response as KeysUploadResponse,
|
||||||
|
upload_signatures::Response as SignatureUploadResponse,
|
||||||
},
|
},
|
||||||
sync::sync_events::{DeviceLists as RumaDeviceLists, ToDevice},
|
sync::sync_events::{DeviceLists as RumaDeviceLists, ToDevice},
|
||||||
to_device::send_event_to_device::Response as ToDeviceResponse,
|
to_device::send_event_to_device::Response as ToDeviceResponse,
|
||||||
@ -31,14 +32,15 @@ use tokio::runtime::Runtime;
|
|||||||
use matrix_sdk_common::{deserialized_responses::AlgorithmInfo, uuid::Uuid};
|
use matrix_sdk_common::{deserialized_responses::AlgorithmInfo, uuid::Uuid};
|
||||||
use matrix_sdk_crypto::{
|
use matrix_sdk_crypto::{
|
||||||
decrypt_key_export, encrypt_key_export, matrix_qrcode::QrVerificationData, EncryptionSettings,
|
decrypt_key_export, encrypt_key_export, matrix_qrcode::QrVerificationData, EncryptionSettings,
|
||||||
LocalTrust, OlmMachine as InnerMachine, Verification as RustVerification,
|
LocalTrust, OlmMachine as InnerMachine, UserIdentities, Verification as RustVerification,
|
||||||
};
|
};
|
||||||
|
|
||||||
use crate::{
|
use crate::{
|
||||||
error::{CryptoStoreError, DecryptionError, MachineCreationError},
|
error::{CryptoStoreError, DecryptionError, SecretImportError, SignatureError},
|
||||||
responses::{response_from_string, OutgoingVerificationRequest, OwnedResponse},
|
responses::{response_from_string, OutgoingVerificationRequest, OwnedResponse},
|
||||||
DecryptedEvent, Device, DeviceLists, KeyImportError, KeysImportResult, ProgressListener,
|
BootstrapCrossSigningResult, CrossSigningKeyExport, CrossSigningStatus, DecryptedEvent, Device,
|
||||||
QrCode, Request, RequestType, RequestVerificationResult, ScanResult, StartSasResult,
|
DeviceLists, KeyImportError, KeysImportResult, ProgressListener, QrCode, Request, RequestType,
|
||||||
|
RequestVerificationResult, ScanResult, SignatureUploadRequest, StartSasResult, UserIdentity,
|
||||||
Verification, VerificationRequest,
|
Verification, VerificationRequest,
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -68,7 +70,7 @@ impl OlmMachine {
|
|||||||
/// * `device_id` - The unique ID of the device that owns this machine.
|
/// * `device_id` - The unique ID of the device that owns this machine.
|
||||||
///
|
///
|
||||||
/// * `path` - The path where the state of the machine should be persisted.
|
/// * `path` - The path where the state of the machine should be persisted.
|
||||||
pub fn new(user_id: &str, device_id: &str, path: &str) -> Result<Self, MachineCreationError> {
|
pub fn new(user_id: &str, device_id: &str, path: &str) -> Result<Self, CryptoStoreError> {
|
||||||
let user_id = UserId::try_from(user_id)?;
|
let user_id = UserId::try_from(user_id)?;
|
||||||
let device_id = device_id.into();
|
let device_id = device_id.into();
|
||||||
let runtime = Runtime::new().unwrap();
|
let runtime = Runtime::new().unwrap();
|
||||||
@ -91,6 +93,67 @@ impl OlmMachine {
|
|||||||
self.inner.device_id().to_string()
|
self.inner.device_id().to_string()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Get the display name of our own device.
|
||||||
|
pub fn display_name(&self) -> Result<Option<String>, CryptoStoreError> {
|
||||||
|
Ok(self.runtime.block_on(self.inner.dislpay_name())?)
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Get a cross signing user identity for the given user ID.
|
||||||
|
pub fn get_identity(&self, user_id: &str) -> Result<Option<UserIdentity>, CryptoStoreError> {
|
||||||
|
let user_id = UserId::try_from(user_id)?;
|
||||||
|
|
||||||
|
Ok(
|
||||||
|
if let Some(identity) = self.runtime.block_on(self.inner.get_identity(&user_id))? {
|
||||||
|
Some(self.runtime.block_on(UserIdentity::from_rust(identity))?)
|
||||||
|
} else {
|
||||||
|
None
|
||||||
|
},
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Check if a user identity is considered to be verified by us.
|
||||||
|
pub fn is_identity_verified(&self, user_id: &str) -> Result<bool, CryptoStoreError> {
|
||||||
|
let user_id = UserId::try_from(user_id)?;
|
||||||
|
|
||||||
|
Ok(
|
||||||
|
if let Some(identity) = self.runtime.block_on(self.inner.get_identity(&user_id))? {
|
||||||
|
match identity {
|
||||||
|
UserIdentities::Own(i) => i.is_verified(),
|
||||||
|
UserIdentities::Other(i) => i.verified(),
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
false
|
||||||
|
},
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Manually the user with the given user ID.
|
||||||
|
///
|
||||||
|
/// This method will attempt to sign the user identity using either our
|
||||||
|
/// private cross signing key, for other user identities, or our device keys
|
||||||
|
/// for our own user identity.
|
||||||
|
///
|
||||||
|
/// This methid can fail if we don't have the private part of our user-signing
|
||||||
|
/// key.
|
||||||
|
///
|
||||||
|
/// Returns a request that needs to be sent out for the user identity to be
|
||||||
|
/// marked as verified.
|
||||||
|
pub fn verify_identity(&self, user_id: &str) -> Result<SignatureUploadRequest, SignatureError> {
|
||||||
|
let user_id = UserId::try_from(user_id)?;
|
||||||
|
|
||||||
|
let user_identity = self.runtime.block_on(self.inner.get_identity(&user_id))?;
|
||||||
|
|
||||||
|
if let Some(user_identity) = user_identity {
|
||||||
|
Ok(match user_identity {
|
||||||
|
UserIdentities::Own(i) => self.runtime.block_on(i.verify())?,
|
||||||
|
UserIdentities::Other(i) => self.runtime.block_on(i.verify())?,
|
||||||
|
}
|
||||||
|
.into())
|
||||||
|
} else {
|
||||||
|
Err(SignatureError::UnknownUserIdentity(user_id.to_string()))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/// Get a `Device` from the store.
|
/// Get a `Device` from the store.
|
||||||
///
|
///
|
||||||
/// # Arguments
|
/// # Arguments
|
||||||
@ -111,6 +174,39 @@ impl OlmMachine {
|
|||||||
.map(|d| d.into()))
|
.map(|d| d.into()))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Manually the device of the given user with the given device ID.
|
||||||
|
///
|
||||||
|
/// This method will attempt to sign the device using our private cross
|
||||||
|
/// signing key.
|
||||||
|
///
|
||||||
|
/// This method will always fail if the device belongs to someone else, we
|
||||||
|
/// can only sign our own devices.
|
||||||
|
///
|
||||||
|
/// It can also fail if we don't have the private part of our self-signing
|
||||||
|
/// key.
|
||||||
|
///
|
||||||
|
/// Returns a request that needs to be sent out for the device to be marked
|
||||||
|
/// as verified.
|
||||||
|
pub fn verify_device(
|
||||||
|
&self,
|
||||||
|
user_id: &str,
|
||||||
|
device_id: &str,
|
||||||
|
) -> Result<SignatureUploadRequest, SignatureError> {
|
||||||
|
let user_id = UserId::try_from(user_id)?;
|
||||||
|
let device = self
|
||||||
|
.runtime
|
||||||
|
.block_on(self.inner.get_device(&user_id, device_id.into()))?;
|
||||||
|
|
||||||
|
if let Some(device) = device {
|
||||||
|
Ok(self.runtime.block_on(device.verify())?.into())
|
||||||
|
} else {
|
||||||
|
Err(SignatureError::UnknownDevice(
|
||||||
|
user_id.to_string(),
|
||||||
|
device_id.to_string(),
|
||||||
|
))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/// Mark the device of the given user with the given device id as trusted.
|
/// Mark the device of the given user with the given device id as trusted.
|
||||||
pub fn mark_device_as_trusted(
|
pub fn mark_device_as_trusted(
|
||||||
&self,
|
&self,
|
||||||
@ -206,6 +302,9 @@ impl OlmMachine {
|
|||||||
RequestType::KeysClaim => {
|
RequestType::KeysClaim => {
|
||||||
KeysClaimResponse::try_from_http_response(response).map(Into::into)
|
KeysClaimResponse::try_from_http_response(response).map(Into::into)
|
||||||
}
|
}
|
||||||
|
RequestType::SignatureUpload => {
|
||||||
|
SignatureUploadResponse::try_from_http_response(response).map(Into::into)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
.expect("Can't convert json string to response");
|
.expect("Can't convert json string to response");
|
||||||
|
|
||||||
@ -305,21 +404,7 @@ impl OlmMachine {
|
|||||||
Ok(self
|
Ok(self
|
||||||
.runtime
|
.runtime
|
||||||
.block_on(self.inner.get_missing_sessions(users.iter()))?
|
.block_on(self.inner.get_missing_sessions(users.iter()))?
|
||||||
.map(|(request_id, request)| Request::KeysClaim {
|
.map(|r| r.into()))
|
||||||
request_id: request_id.to_string(),
|
|
||||||
one_time_keys: request
|
|
||||||
.one_time_keys
|
|
||||||
.into_iter()
|
|
||||||
.map(|(u, d)| {
|
|
||||||
(
|
|
||||||
u.to_string(),
|
|
||||||
d.into_iter()
|
|
||||||
.map(|(k, v)| (k.to_string(), v.to_string()))
|
|
||||||
.collect(),
|
|
||||||
)
|
|
||||||
})
|
|
||||||
.collect(),
|
|
||||||
}))
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Share a room key with the given list of users for the given room.
|
/// Share a room key with the given list of users for the given room.
|
||||||
@ -867,6 +952,8 @@ impl OlmMachine {
|
|||||||
if let Some(verification) = self.inner.get_verification(&user_id, flow_id) {
|
if let Some(verification) = self.inner.get_verification(&user_id, flow_id) {
|
||||||
match verification {
|
match verification {
|
||||||
RustVerification::SasV1(v) => {
|
RustVerification::SasV1(v) => {
|
||||||
|
// TODO there's a signature upload request here, we'll
|
||||||
|
// want to return that one as well.
|
||||||
self.runtime.block_on(v.confirm())?.0.map(|r| r.into())
|
self.runtime.block_on(v.confirm())?.0.map(|r| r.into())
|
||||||
}
|
}
|
||||||
RustVerification::QrV1(v) => v.confirm_scanning().map(|r| r.into()),
|
RustVerification::QrV1(v) => v.confirm_scanning().map(|r| r.into()),
|
||||||
@ -1114,4 +1201,49 @@ impl OlmMachine {
|
|||||||
})
|
})
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Create a new private cross signing identity and create a request to
|
||||||
|
/// upload the public part of it to the server.
|
||||||
|
pub fn bootstrap_cross_signing(&self) -> Result<BootstrapCrossSigningResult, CryptoStoreError> {
|
||||||
|
Ok(self
|
||||||
|
.runtime
|
||||||
|
.block_on(self.inner.bootstrap_cross_signing(true))?
|
||||||
|
.into())
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Get the status of the private cross signing keys.
|
||||||
|
///
|
||||||
|
/// This can be used to check which private cross signing keys we have
|
||||||
|
/// stored locally.
|
||||||
|
pub fn cross_signing_status(&self) -> CrossSigningStatus {
|
||||||
|
self.runtime
|
||||||
|
.block_on(self.inner.cross_signing_status())
|
||||||
|
.into()
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Export all our private cross signing keys.
|
||||||
|
///
|
||||||
|
/// The export will contain the seed for the ed25519 keys as a base64
|
||||||
|
/// encoded string.
|
||||||
|
///
|
||||||
|
/// This method returns `None` if we don't have any private cross signing keys.
|
||||||
|
pub fn export_cross_signing_keys(&self) -> Option<CrossSigningKeyExport> {
|
||||||
|
self.runtime
|
||||||
|
.block_on(self.inner.export_cross_signing_keys())
|
||||||
|
.map(|e| e.into())
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Import our private cross signing keys.
|
||||||
|
///
|
||||||
|
/// The export needs to contain the seed for the ed25519 keys as a base64
|
||||||
|
/// encoded string.
|
||||||
|
pub fn import_cross_signing_keys(
|
||||||
|
&self,
|
||||||
|
export: CrossSigningKeyExport,
|
||||||
|
) -> Result<(), SecretImportError> {
|
||||||
|
self.runtime
|
||||||
|
.block_on(self.inner.import_cross_signing_keys(export.into()))?;
|
||||||
|
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -10,18 +10,28 @@ callback interface ProgressListener {
|
|||||||
void on_progress(i32 progress, i32 total);
|
void on_progress(i32 progress, i32 total);
|
||||||
};
|
};
|
||||||
|
|
||||||
[Error]
|
|
||||||
enum MachineCreationError {
|
|
||||||
"Identifier",
|
|
||||||
"CryptoStore",
|
|
||||||
};
|
|
||||||
|
|
||||||
[Error]
|
[Error]
|
||||||
enum KeyImportError {
|
enum KeyImportError {
|
||||||
"Export",
|
"Export",
|
||||||
"CryptoStore",
|
"CryptoStore",
|
||||||
};
|
};
|
||||||
|
|
||||||
|
[Error]
|
||||||
|
enum SignatureError {
|
||||||
|
"Signature",
|
||||||
|
"Identifier",
|
||||||
|
"CryptoStore",
|
||||||
|
"UnknownDevice",
|
||||||
|
"UnknownUserIdentity",
|
||||||
|
};
|
||||||
|
|
||||||
|
[Error]
|
||||||
|
enum SecretImportError {
|
||||||
|
"Import",
|
||||||
|
"CryptoStore",
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
[Error]
|
[Error]
|
||||||
enum CryptoStoreError {
|
enum CryptoStoreError {
|
||||||
"CryptoStore",
|
"CryptoStore",
|
||||||
@ -65,6 +75,45 @@ dictionary Device {
|
|||||||
boolean cross_signing_trusted;
|
boolean cross_signing_trusted;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
[Enum]
|
||||||
|
interface UserIdentity {
|
||||||
|
Own(
|
||||||
|
string user_id,
|
||||||
|
boolean trusts_our_own_device,
|
||||||
|
string master_key,
|
||||||
|
string self_signing_key,
|
||||||
|
string user_signing_key
|
||||||
|
);
|
||||||
|
Other(
|
||||||
|
string user_id,
|
||||||
|
string master_key,
|
||||||
|
string self_signing_key
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
dictionary CrossSigningStatus {
|
||||||
|
boolean has_master;
|
||||||
|
boolean has_self_signing;
|
||||||
|
boolean has_user_signing;
|
||||||
|
};
|
||||||
|
|
||||||
|
dictionary CrossSigningKeyExport {
|
||||||
|
string? master_key;
|
||||||
|
string? self_signing_key;
|
||||||
|
string? user_signing_key;
|
||||||
|
};
|
||||||
|
|
||||||
|
dictionary UploadSigningKeysRequest {
|
||||||
|
string master_key;
|
||||||
|
string self_signing_key;
|
||||||
|
string user_signing_key;
|
||||||
|
};
|
||||||
|
|
||||||
|
dictionary BootstrapCrossSigningResult {
|
||||||
|
UploadSigningKeysRequest upload_signing_keys_request;
|
||||||
|
SignatureUploadRequest signature_request;
|
||||||
|
};
|
||||||
|
|
||||||
dictionary CancelInfo {
|
dictionary CancelInfo {
|
||||||
string cancel_code;
|
string cancel_code;
|
||||||
string reason;
|
string reason;
|
||||||
@ -155,6 +204,11 @@ interface Request {
|
|||||||
KeysQuery(string request_id, sequence<string> users);
|
KeysQuery(string request_id, sequence<string> users);
|
||||||
KeysClaim(string request_id, record<DOMString, record<DOMString, string>> one_time_keys);
|
KeysClaim(string request_id, record<DOMString, record<DOMString, string>> one_time_keys);
|
||||||
RoomMessage(string request_id, string room_id, string event_type, string content);
|
RoomMessage(string request_id, string room_id, string event_type, string content);
|
||||||
|
SignatureUpload(string request_id, string body);
|
||||||
|
};
|
||||||
|
|
||||||
|
dictionary SignatureUploadRequest {
|
||||||
|
string body;
|
||||||
};
|
};
|
||||||
|
|
||||||
enum RequestType {
|
enum RequestType {
|
||||||
@ -162,10 +216,11 @@ enum RequestType {
|
|||||||
"KeysClaim",
|
"KeysClaim",
|
||||||
"KeysUpload",
|
"KeysUpload",
|
||||||
"ToDevice",
|
"ToDevice",
|
||||||
|
"SignatureUpload",
|
||||||
};
|
};
|
||||||
|
|
||||||
interface OlmMachine {
|
interface OlmMachine {
|
||||||
[Throws=MachineCreationError]
|
[Throws=CryptoStoreError]
|
||||||
constructor([ByRef] string user_id, [ByRef] string device_id, [ByRef] string path);
|
constructor([ByRef] string user_id, [ByRef] string device_id, [ByRef] string path);
|
||||||
|
|
||||||
record<DOMString, string> identity_keys();
|
record<DOMString, string> identity_keys();
|
||||||
@ -190,10 +245,16 @@ interface OlmMachine {
|
|||||||
[Throws=CryptoStoreError]
|
[Throws=CryptoStoreError]
|
||||||
string encrypt([ByRef] string room_id, [ByRef] string event_type, [ByRef] string content);
|
string encrypt([ByRef] string room_id, [ByRef] string event_type, [ByRef] string content);
|
||||||
|
|
||||||
|
[Throws=CryptoStoreError]
|
||||||
|
UserIdentity? get_identity([ByRef] string user_id);
|
||||||
|
[Throws=SignatureError]
|
||||||
|
SignatureUploadRequest verify_identity([ByRef] string user_id);
|
||||||
[Throws=CryptoStoreError]
|
[Throws=CryptoStoreError]
|
||||||
Device? get_device([ByRef] string user_id, [ByRef] string device_id);
|
Device? get_device([ByRef] string user_id, [ByRef] string device_id);
|
||||||
[Throws=CryptoStoreError]
|
[Throws=CryptoStoreError]
|
||||||
void mark_device_as_trusted([ByRef] string user_id, [ByRef] string device_id);
|
void mark_device_as_trusted([ByRef] string user_id, [ByRef] string device_id);
|
||||||
|
[Throws=SignatureError]
|
||||||
|
SignatureUploadRequest verify_device([ByRef] string user_id, [ByRef] string device_id);
|
||||||
[Throws=CryptoStoreError]
|
[Throws=CryptoStoreError]
|
||||||
sequence<Device> get_user_devices([ByRef] string user_id);
|
sequence<Device> get_user_devices([ByRef] string user_id);
|
||||||
|
|
||||||
@ -268,4 +329,13 @@ interface OlmMachine {
|
|||||||
);
|
);
|
||||||
[Throws=CryptoStoreError]
|
[Throws=CryptoStoreError]
|
||||||
void discard_room_key([ByRef] string room_id);
|
void discard_room_key([ByRef] string room_id);
|
||||||
|
|
||||||
|
CrossSigningStatus cross_signing_status();
|
||||||
|
[Throws=CryptoStoreError]
|
||||||
|
BootstrapCrossSigningResult bootstrap_cross_signing();
|
||||||
|
CrossSigningKeyExport? export_cross_signing_keys();
|
||||||
|
[Throws=SecretImportError]
|
||||||
|
void import_cross_signing_keys(CrossSigningKeyExport export);
|
||||||
|
[Throws=CryptoStoreError]
|
||||||
|
boolean is_identity_verified([ByRef] string user_id);
|
||||||
};
|
};
|
||||||
|
@ -3,13 +3,18 @@
|
|||||||
use std::{collections::HashMap, convert::TryFrom};
|
use std::{collections::HashMap, convert::TryFrom};
|
||||||
|
|
||||||
use http::Response;
|
use http::Response;
|
||||||
|
use matrix_sdk_common::uuid::Uuid;
|
||||||
use serde_json::json;
|
use serde_json::json;
|
||||||
|
|
||||||
use ruma::{
|
use ruma::{
|
||||||
api::client::r0::{
|
api::client::r0::{
|
||||||
keys::{
|
keys::{
|
||||||
claim_keys::Response as KeysClaimResponse, get_keys::Response as KeysQueryResponse,
|
claim_keys::{Request as KeysClaimRequest, Response as KeysClaimResponse},
|
||||||
|
get_keys::Response as KeysQueryResponse,
|
||||||
upload_keys::Response as KeysUploadResponse,
|
upload_keys::Response as KeysUploadResponse,
|
||||||
|
upload_signatures::{
|
||||||
|
Request as RustSignatureUploadRequest, Response as SignatureUploadResponse,
|
||||||
|
},
|
||||||
},
|
},
|
||||||
sync::sync_events::DeviceLists as RumaDeviceLists,
|
sync::sync_events::DeviceLists as RumaDeviceLists,
|
||||||
to_device::send_event_to_device::Response as ToDeviceResponse,
|
to_device::send_event_to_device::Response as ToDeviceResponse,
|
||||||
@ -21,9 +26,65 @@ use ruma::{
|
|||||||
|
|
||||||
use matrix_sdk_crypto::{
|
use matrix_sdk_crypto::{
|
||||||
IncomingResponse, OutgoingRequest, OutgoingVerificationRequest as SdkVerificationRequest,
|
IncomingResponse, OutgoingRequest, OutgoingVerificationRequest as SdkVerificationRequest,
|
||||||
RoomMessageRequest, ToDeviceRequest,
|
RoomMessageRequest, ToDeviceRequest, UploadSigningKeysRequest as RustUploadSigningKeysRequest,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
pub struct SignatureUploadRequest {
|
||||||
|
pub body: String,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl From<RustSignatureUploadRequest> for SignatureUploadRequest {
|
||||||
|
fn from(r: RustSignatureUploadRequest) -> Self {
|
||||||
|
Self {
|
||||||
|
body: serde_json::to_string(&r.signed_keys)
|
||||||
|
.expect("Can't serialize signature upload request"),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub struct UploadSigningKeysRequest {
|
||||||
|
pub master_key: String,
|
||||||
|
pub self_signing_key: String,
|
||||||
|
pub user_signing_key: String,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl From<RustUploadSigningKeysRequest> for UploadSigningKeysRequest {
|
||||||
|
fn from(r: RustUploadSigningKeysRequest) -> Self {
|
||||||
|
Self {
|
||||||
|
master_key: serde_json::to_string(
|
||||||
|
&r.master_key.expect("Request didn't contain a master key"),
|
||||||
|
)
|
||||||
|
.expect("Can't serialize cross signing master key"),
|
||||||
|
self_signing_key: serde_json::to_string(
|
||||||
|
&r.self_signing_key
|
||||||
|
.expect("Request didn't contain a self-signing key"),
|
||||||
|
)
|
||||||
|
.expect("Can't serialize cross signing self-signing key"),
|
||||||
|
user_signing_key: serde_json::to_string(
|
||||||
|
&r.user_signing_key
|
||||||
|
.expect("Request didn't contain a user-signing key"),
|
||||||
|
)
|
||||||
|
.expect("Can't serialize cross signing user-signing key"),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub struct BootstrapCrossSigningResult {
|
||||||
|
pub upload_signing_keys_request: UploadSigningKeysRequest,
|
||||||
|
pub signature_request: SignatureUploadRequest,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl From<(RustUploadSigningKeysRequest, RustSignatureUploadRequest)>
|
||||||
|
for BootstrapCrossSigningResult
|
||||||
|
{
|
||||||
|
fn from(requests: (RustUploadSigningKeysRequest, RustSignatureUploadRequest)) -> Self {
|
||||||
|
Self {
|
||||||
|
upload_signing_keys_request: requests.0.into(),
|
||||||
|
signature_request: requests.1.into(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
pub enum OutgoingVerificationRequest {
|
pub enum OutgoingVerificationRequest {
|
||||||
ToDevice {
|
ToDevice {
|
||||||
request_id: String,
|
request_id: String,
|
||||||
@ -87,6 +148,10 @@ pub enum Request {
|
|||||||
event_type: String,
|
event_type: String,
|
||||||
content: String,
|
content: String,
|
||||||
},
|
},
|
||||||
|
SignatureUpload {
|
||||||
|
request_id: String,
|
||||||
|
body: String,
|
||||||
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
impl From<OutgoingRequest> for Request {
|
impl From<OutgoingRequest> for Request {
|
||||||
@ -114,8 +179,13 @@ impl From<OutgoingRequest> for Request {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
ToDeviceRequest(t) => Request::from(t),
|
ToDeviceRequest(t) => Request::from(t),
|
||||||
SignatureUpload(_) => todo!("Uploading signatures isn't yet supported"),
|
SignatureUpload(t) => Request::SignatureUpload {
|
||||||
|
request_id: r.request_id().to_string(),
|
||||||
|
body: serde_json::to_string(&t.signed_keys)
|
||||||
|
.expect("Can't serialize signature upload request"),
|
||||||
|
},
|
||||||
RoomMessage(r) => Request::from(r),
|
RoomMessage(r) => Request::from(r),
|
||||||
|
KeysClaim(c) => (*r.request_id(), c.clone()).into(),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -130,6 +200,28 @@ impl From<ToDeviceRequest> for Request {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl From<(Uuid, KeysClaimRequest)> for Request {
|
||||||
|
fn from(request_tuple: (Uuid, KeysClaimRequest)) -> Self {
|
||||||
|
let (request_id, request) = request_tuple;
|
||||||
|
|
||||||
|
Request::KeysClaim {
|
||||||
|
request_id: request_id.to_string(),
|
||||||
|
one_time_keys: request
|
||||||
|
.one_time_keys
|
||||||
|
.into_iter()
|
||||||
|
.map(|(u, d)| {
|
||||||
|
(
|
||||||
|
u.to_string(),
|
||||||
|
d.into_iter()
|
||||||
|
.map(|(k, v)| (k.to_string(), v.to_string()))
|
||||||
|
.collect(),
|
||||||
|
)
|
||||||
|
})
|
||||||
|
.collect(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
impl From<&ToDeviceRequest> for Request {
|
impl From<&ToDeviceRequest> for Request {
|
||||||
fn from(r: &ToDeviceRequest) -> Self {
|
fn from(r: &ToDeviceRequest) -> Self {
|
||||||
Request::ToDevice {
|
Request::ToDevice {
|
||||||
@ -163,6 +255,7 @@ pub enum RequestType {
|
|||||||
KeysClaim,
|
KeysClaim,
|
||||||
KeysUpload,
|
KeysUpload,
|
||||||
ToDevice,
|
ToDevice,
|
||||||
|
SignatureUpload,
|
||||||
}
|
}
|
||||||
|
|
||||||
pub struct DeviceLists {
|
pub struct DeviceLists {
|
||||||
@ -197,6 +290,7 @@ pub(crate) enum OwnedResponse {
|
|||||||
KeysUpload(KeysUploadResponse),
|
KeysUpload(KeysUploadResponse),
|
||||||
KeysQuery(KeysQueryResponse),
|
KeysQuery(KeysQueryResponse),
|
||||||
ToDevice(ToDeviceResponse),
|
ToDevice(ToDeviceResponse),
|
||||||
|
SignatureUpload(SignatureUploadResponse),
|
||||||
}
|
}
|
||||||
|
|
||||||
impl From<KeysClaimResponse> for OwnedResponse {
|
impl From<KeysClaimResponse> for OwnedResponse {
|
||||||
@ -223,6 +317,12 @@ impl From<ToDeviceResponse> for OwnedResponse {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl From<SignatureUploadResponse> for OwnedResponse {
|
||||||
|
fn from(response: SignatureUploadResponse) -> Self {
|
||||||
|
Self::SignatureUpload(response)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
impl<'a> Into<IncomingResponse<'a>> for &'a OwnedResponse {
|
impl<'a> Into<IncomingResponse<'a>> for &'a OwnedResponse {
|
||||||
fn into(self) -> IncomingResponse<'a> {
|
fn into(self) -> IncomingResponse<'a> {
|
||||||
match self {
|
match self {
|
||||||
@ -230,6 +330,7 @@ impl<'a> Into<IncomingResponse<'a>> for &'a OwnedResponse {
|
|||||||
OwnedResponse::KeysQuery(r) => IncomingResponse::KeysQuery(r),
|
OwnedResponse::KeysQuery(r) => IncomingResponse::KeysQuery(r),
|
||||||
OwnedResponse::KeysUpload(r) => IncomingResponse::KeysUpload(r),
|
OwnedResponse::KeysUpload(r) => IncomingResponse::KeysUpload(r),
|
||||||
OwnedResponse::ToDevice(r) => IncomingResponse::ToDevice(r),
|
OwnedResponse::ToDevice(r) => IncomingResponse::ToDevice(r),
|
||||||
|
OwnedResponse::SignatureUpload(r) => IncomingResponse::SignatureUpload(r),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
61
rust-sdk/src/users.rs
Normal file
61
rust-sdk/src/users.rs
Normal file
@ -0,0 +1,61 @@
|
|||||||
|
use matrix_sdk_crypto::UserIdentities;
|
||||||
|
use ruma::encryption::CrossSigningKey;
|
||||||
|
|
||||||
|
use crate::CryptoStoreError;
|
||||||
|
|
||||||
|
/// Enum representing cross signing identities of our own user or some other
|
||||||
|
/// user.
|
||||||
|
pub enum UserIdentity {
|
||||||
|
/// Our own user identity.
|
||||||
|
Own {
|
||||||
|
/// The unique id of our own user.
|
||||||
|
user_id: String,
|
||||||
|
/// Does our own user identity trust our own device.
|
||||||
|
trusts_our_own_device: bool,
|
||||||
|
/// The public master key of our identity.
|
||||||
|
master_key: String,
|
||||||
|
/// The public user-signing key of our identity.
|
||||||
|
user_signing_key: String,
|
||||||
|
/// The public self-signing key of our identity.
|
||||||
|
self_signing_key: String,
|
||||||
|
},
|
||||||
|
/// The user identity of other users.
|
||||||
|
Other {
|
||||||
|
/// The unique id of the user.
|
||||||
|
user_id: String,
|
||||||
|
/// The public master key of the identity.
|
||||||
|
master_key: String,
|
||||||
|
/// The public self-signing key of our identity.
|
||||||
|
self_signing_key: String,
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
impl UserIdentity {
|
||||||
|
pub(crate) async fn from_rust(i: UserIdentities) -> Result<Self, CryptoStoreError> {
|
||||||
|
Ok(match i {
|
||||||
|
UserIdentities::Own(i) => {
|
||||||
|
let master: CrossSigningKey = i.master_key().to_owned().into();
|
||||||
|
let user_signing: CrossSigningKey = i.user_signing_key().to_owned().into();
|
||||||
|
let self_signing: CrossSigningKey = i.self_signing_key().to_owned().into();
|
||||||
|
|
||||||
|
UserIdentity::Own {
|
||||||
|
user_id: i.user_id().to_string(),
|
||||||
|
trusts_our_own_device: i.trusts_our_own_device().await?,
|
||||||
|
master_key: serde_json::to_string(&master)?,
|
||||||
|
user_signing_key: serde_json::to_string(&user_signing)?,
|
||||||
|
self_signing_key: serde_json::to_string(&self_signing)?,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
UserIdentities::Other(i) => {
|
||||||
|
let master: CrossSigningKey = i.master_key().to_owned().into();
|
||||||
|
let self_signing: CrossSigningKey = i.self_signing_key().to_owned().into();
|
||||||
|
|
||||||
|
UserIdentity::Other {
|
||||||
|
user_id: i.user_id().to_string(),
|
||||||
|
master_key: serde_json::to_string(&master)?,
|
||||||
|
self_signing_key: serde_json::to_string(&self_signing)?,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
Loading…
Reference in New Issue
Block a user