matrix-sdk: Expose the import/export keys methods.
parent
618a58ba34
commit
ffd2843b0a
|
@ -34,6 +34,7 @@ serde_json = "1.0.57"
|
|||
thiserror = "1.0.20"
|
||||
tracing = "0.1.19"
|
||||
url = "2.1.1"
|
||||
zeroize = "1.1.0"
|
||||
|
||||
matrix-sdk-common-macros = { version = "0.1.0", path = "../matrix_sdk_common_macros" }
|
||||
matrix-sdk-common = { version = "0.1.0", path = "../matrix_sdk_common" }
|
||||
|
@ -55,6 +56,11 @@ features = ["std", "std-future"]
|
|||
[target.'cfg(not(target_arch = "wasm32"))'.dependencies]
|
||||
futures-timer = "3.0.2"
|
||||
|
||||
[target.'cfg(not(target_arch = "wasm32"))'.dependencies.tokio]
|
||||
version = "0.2.22"
|
||||
default-features = false
|
||||
features = ["fs", "blocking"]
|
||||
|
||||
[target.'cfg(target_arch = "wasm32")'.dependencies.futures-timer]
|
||||
version = "3.0.2"
|
||||
features = ["wasm-bindgen"]
|
||||
|
|
|
@ -22,12 +22,16 @@ use std::{
|
|||
result::Result as StdResult,
|
||||
sync::Arc,
|
||||
};
|
||||
#[cfg(feature = "encryption")]
|
||||
use std::{io::Write, path::PathBuf};
|
||||
|
||||
#[cfg(feature = "encryption")]
|
||||
use dashmap::DashMap;
|
||||
use futures_timer::Delay as sleep;
|
||||
use reqwest::header::{HeaderValue, InvalidHeaderValue};
|
||||
use url::Url;
|
||||
#[cfg(feature = "encryption")]
|
||||
use zeroize::Zeroizing;
|
||||
|
||||
#[cfg(feature = "encryption")]
|
||||
use tracing::{debug, warn};
|
||||
|
@ -36,7 +40,10 @@ use tracing::{error, info, instrument};
|
|||
use matrix_sdk_base::{BaseClient, BaseClientConfig, Room, Session, StateStore};
|
||||
|
||||
#[cfg(feature = "encryption")]
|
||||
use matrix_sdk_base::{CryptoStoreError, OutgoingRequests, ToDeviceRequest};
|
||||
use matrix_sdk_base::crypto::{
|
||||
decrypt_key_export, encrypt_key_export, olm::InboundGroupSession, store::CryptoStoreError,
|
||||
OutgoingRequests, ToDeviceRequest,
|
||||
};
|
||||
|
||||
use matrix_sdk_common::{
|
||||
api::r0::{
|
||||
|
@ -1479,7 +1486,6 @@ impl Client {
|
|||
///
|
||||
/// println!("{:?}", device.is_trusted());
|
||||
///
|
||||
///
|
||||
/// let verification = device.start_verification().await.unwrap();
|
||||
/// # });
|
||||
/// ```
|
||||
|
@ -1534,6 +1540,126 @@ impl Client {
|
|||
http_client: self.http_client.clone(),
|
||||
})
|
||||
}
|
||||
|
||||
/// Export E2EE keys that match the given predicate encrypting them with the
|
||||
/// given passphrase.
|
||||
///
|
||||
/// # Arguments
|
||||
///
|
||||
/// * `path` - The file path where the exported key file will be saved.
|
||||
///
|
||||
/// * `passphrase` - The passphrase that will be used to encrypt the exported
|
||||
/// room keys.
|
||||
///
|
||||
/// * `predicate` - A closure that will be called for every known
|
||||
/// `InboundGroupSession`, which represents a room key. If the closure
|
||||
/// returns `true` the `InboundGroupSessoin` will be included in the export,
|
||||
/// if the closure returns `false` it will not be included.
|
||||
///
|
||||
/// # Examples
|
||||
///
|
||||
/// ```no_run
|
||||
/// # use std::{path::PathBuf, time::Duration};
|
||||
/// # use matrix_sdk::{
|
||||
/// # Client, SyncSettings,
|
||||
/// # api::r0::typing::create_typing_event::Typing,
|
||||
/// # identifiers::room_id,
|
||||
/// # };
|
||||
/// # use futures::executor::block_on;
|
||||
/// # use url::Url;
|
||||
/// # block_on(async {
|
||||
/// # let homeserver = Url::parse("http://localhost:8080").unwrap();
|
||||
/// # let mut client = Client::new(homeserver).unwrap();
|
||||
/// let path = PathBuf::from("/home/example/e2e-keys.txt");
|
||||
/// // Export all room keys.
|
||||
/// client
|
||||
/// .export_keys(path, "secret-passphrase", |_| true)
|
||||
/// .await
|
||||
/// .expect("Can't export keys.");
|
||||
///
|
||||
/// // Export only the room keys for a certain room.
|
||||
/// let path = PathBuf::from("/home/example/e2e-room-keys.txt");
|
||||
/// let room_id = room_id!("!test:localhost");
|
||||
///
|
||||
/// client
|
||||
/// .export_keys(path, "secret-passphrase", |s| s.room_id() == &room_id)
|
||||
/// .await
|
||||
/// .expect("Can't export keys.");
|
||||
/// # });
|
||||
/// ```
|
||||
#[cfg(feature = "encryption")]
|
||||
#[cfg(not(target_arch = "wasm32"))]
|
||||
#[cfg_attr(feature = "docs", doc(cfg(encryption)))]
|
||||
pub async fn export_keys(
|
||||
&self,
|
||||
path: PathBuf,
|
||||
passphrase: &str,
|
||||
predicate: impl FnMut(&InboundGroupSession) -> bool,
|
||||
) -> Result<()> {
|
||||
let olm = self
|
||||
.base_client
|
||||
.olm_machine()
|
||||
.await
|
||||
.ok_or(Error::AuthenticationRequired)?;
|
||||
|
||||
let keys = olm.export_keys(predicate).await?;
|
||||
let passphrase = Zeroizing::new(passphrase.to_owned());
|
||||
|
||||
let encrypt = move || -> Result<()> {
|
||||
let export: String = encrypt_key_export(&keys, &passphrase, 500_000)?;
|
||||
let mut file = std::fs::File::create(path).unwrap();
|
||||
file.write_all(&export.into_bytes()).unwrap();
|
||||
Ok(())
|
||||
};
|
||||
|
||||
let task = tokio::task::spawn_blocking(encrypt);
|
||||
task.await.expect("Task join error")
|
||||
}
|
||||
|
||||
/// Import E2EE keys from the given file path.
|
||||
///
|
||||
/// ```no_run
|
||||
/// # use std::{path::PathBuf, time::Duration};
|
||||
/// # use matrix_sdk::{
|
||||
/// # Client, SyncSettings,
|
||||
/// # api::r0::typing::create_typing_event::Typing,
|
||||
/// # identifiers::room_id,
|
||||
/// # };
|
||||
/// # use futures::executor::block_on;
|
||||
/// # use url::Url;
|
||||
/// # block_on(async {
|
||||
/// # let homeserver = Url::parse("http://localhost:8080").unwrap();
|
||||
/// # let mut client = Client::new(homeserver).unwrap();
|
||||
/// let path = PathBuf::from("/home/example/e2e-keys.txt");
|
||||
/// client
|
||||
/// .import_keys(path, "secret-passphrase")
|
||||
/// .await
|
||||
/// .expect("Can't import keys");
|
||||
/// # });
|
||||
/// ```
|
||||
#[cfg(feature = "encryption")]
|
||||
#[cfg(not(target_arch = "wasm32"))]
|
||||
#[cfg_attr(feature = "docs", doc(cfg(encryption)))]
|
||||
pub async fn import_keys(&self, path: PathBuf, passphrase: &str) -> Result<()> {
|
||||
let olm = self
|
||||
.base_client
|
||||
.olm_machine()
|
||||
.await
|
||||
.ok_or(Error::AuthenticationRequired)?;
|
||||
let passphrase = Zeroizing::new(passphrase.to_owned());
|
||||
|
||||
let decrypt = move || {
|
||||
let file = std::fs::File::open(path)?;
|
||||
decrypt_key_export(file, &passphrase)
|
||||
};
|
||||
|
||||
let task = tokio::task::spawn_blocking(decrypt);
|
||||
let import = task.await.expect("Task join error").unwrap();
|
||||
|
||||
olm.import_keys(import).await.unwrap();
|
||||
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
|
|
|
@ -14,8 +14,8 @@
|
|||
|
||||
use std::{ops::Deref, result::Result as StdResult};
|
||||
|
||||
use matrix_sdk_base::{
|
||||
CryptoStoreError, Device as BaseDevice, LocalTrust, ReadOnlyDevice,
|
||||
use matrix_sdk_base::crypto::{
|
||||
store::CryptoStoreError, Device as BaseDevice, LocalTrust, ReadOnlyDevice,
|
||||
UserDevices as BaseUserDevices,
|
||||
};
|
||||
use matrix_sdk_common::{
|
||||
|
|
|
@ -24,7 +24,7 @@ use serde_json::Error as JsonError;
|
|||
use thiserror::Error;
|
||||
|
||||
#[cfg(feature = "encryption")]
|
||||
use matrix_sdk_base::CryptoStoreError;
|
||||
use matrix_sdk_base::crypto::store::CryptoStoreError;
|
||||
|
||||
/// Result type of the rust-sdk.
|
||||
pub type Result<T> = std::result::Result<T, Error>;
|
||||
|
|
|
@ -44,11 +44,11 @@ compile_error!("one of 'native-tls' or 'rustls-tls' features must be enabled");
|
|||
#[cfg(all(feature = "native-tls", feature = "rustls-tls",))]
|
||||
compile_error!("only one of 'native-tls' or 'rustls-tls' features can be enabled");
|
||||
|
||||
#[cfg(not(target_arch = "wasm32"))]
|
||||
pub use matrix_sdk_base::JsonStore;
|
||||
#[cfg(feature = "encryption")]
|
||||
#[cfg_attr(feature = "docs", doc(cfg(encryption)))]
|
||||
pub use matrix_sdk_base::LocalTrust;
|
||||
pub use matrix_sdk_base::crypto::LocalTrust;
|
||||
#[cfg(not(target_arch = "wasm32"))]
|
||||
pub use matrix_sdk_base::JsonStore;
|
||||
pub use matrix_sdk_base::{
|
||||
CustomEvent, Error as BaseError, EventEmitter, Room, RoomState, Session, StateStore, SyncRoom,
|
||||
};
|
||||
|
|
|
@ -12,7 +12,7 @@
|
|||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
use matrix_sdk_base::{ReadOnlyDevice, Sas as BaseSas};
|
||||
use matrix_sdk_base::crypto::{ReadOnlyDevice, Sas as BaseSas};
|
||||
use matrix_sdk_common::api::r0::to_device::send_event_to_device::Request as ToDeviceRequest;
|
||||
|
||||
use crate::{error::Result, http_client::HttpClient};
|
||||
|
|
|
@ -1860,6 +1860,12 @@ impl BaseClient {
|
|||
panic!("The client hasn't been logged in")
|
||||
}
|
||||
}
|
||||
|
||||
/// Get the olm machine.
|
||||
pub async fn olm_machine(&self) -> Option<OlmMachine> {
|
||||
let olm = self.olm.lock().await;
|
||||
olm.as_ref().cloned()
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
|
|
|
@ -56,10 +56,7 @@ pub use state::{AllRooms, ClientState};
|
|||
|
||||
#[cfg(feature = "encryption")]
|
||||
#[cfg_attr(feature = "docs", doc(cfg(encryption)))]
|
||||
pub use matrix_sdk_crypto::{
|
||||
store::CryptoStoreError, Device, IncomingResponse, LocalTrust, OutgoingRequest,
|
||||
OutgoingRequests, ReadOnlyDevice, Sas, ToDeviceRequest, UserDevices,
|
||||
};
|
||||
pub use matrix_sdk_crypto as crypto;
|
||||
|
||||
#[cfg(feature = "messages")]
|
||||
#[cfg_attr(feature = "docs", doc(cfg(messages)))]
|
||||
|
|
|
@ -14,5 +14,5 @@ version = "0.1.0"
|
|||
proc-macro = true
|
||||
|
||||
[dependencies]
|
||||
syn = "1.0.39"
|
||||
syn = "1.0.40"
|
||||
quote = "1.0.7"
|
||||
|
|
|
@ -26,7 +26,7 @@ matrix-sdk-common-macros = { version = "0.1.0", path = "../matrix_sdk_common_mac
|
|||
matrix-sdk-common = { version = "0.1.0", path = "../matrix_sdk_common" }
|
||||
|
||||
olm-rs = { version = "0.6.0", features = ["serde"] }
|
||||
getrandom = "0.1.14"
|
||||
getrandom = "0.2.0"
|
||||
serde = { version = "1.0.115", features = ["derive", "rc"] }
|
||||
serde_json = "1.0.57"
|
||||
cjson = "0.1.1"
|
||||
|
|
|
@ -40,6 +40,10 @@ pub use olm_rs::{
|
|||
use super::{ExportedGroupSessionKey, ExportedRoomKey, GroupSessionKey};
|
||||
use crate::error::{EventError, MegolmResult};
|
||||
|
||||
// TODO add creation times to the inbound grop sessions so we can export
|
||||
// sessions that were created between some time period, this should only be set
|
||||
// for non-imported sessoins.
|
||||
|
||||
/// Inbound group session.
|
||||
///
|
||||
/// Inbound group sessions are used to exchange room messages between a group of
|
||||
|
|
Loading…
Reference in New Issue