Skip to content

Commit

Permalink
Allow using redis crypto store in command bot
Browse files Browse the repository at this point in the history
  • Loading branch information
andybalaam committed Dec 5, 2022
1 parent a003fbf commit 679cb67
Show file tree
Hide file tree
Showing 8 changed files with 131 additions and 11 deletions.
2 changes: 2 additions & 0 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 2 additions & 0 deletions crates/matrix-sdk-redis/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -26,13 +26,15 @@ async-trait = "0.1.53"
dashmap = "5.2.0"
futures-core = "0.3.21"
futures-util = { version = "0.3.21", default-features = false }
matrix-sdk-base = { version = "0.6.0", path = "../matrix-sdk-base", optional = true }
matrix-sdk-common = { version = "0.6.0", path = "../matrix-sdk-common" }
matrix-sdk-crypto = { version = "0.6.0", path = "../matrix-sdk-crypto", optional = true }
matrix-sdk-store-encryption = { version = "0.2.0", path = "../matrix-sdk-store-encryption" }
redis = { version = "0.21", features = ["tokio-comp"] }
ruma = { workspace = true }
serde = "1.0.136"
serde_json = "1.0.79"
thiserror = "1.0.30"

[dev-dependencies]
matrix-sdk-base = { path = "../matrix-sdk-base", features = ["testing"] }
Expand Down
80 changes: 80 additions & 0 deletions crates/matrix-sdk-redis/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -19,5 +19,85 @@ mod real_redis;
mod redis_crypto_store;
mod redis_shim;

#[cfg(any(feature = "state-store", feature = "crypto-store"))]
use matrix_sdk_base::store::StoreConfig;
#[cfg(feature = "state-store")]
use matrix_sdk_base::store::StoreError;
#[cfg(feature = "crypto-store")]
use matrix_sdk_crypto::store::CryptoStoreError;
use redis::RedisError;
use thiserror::Error;

#[cfg(feature = "crypto-store")]
pub use redis_crypto_store::RedisStore as CryptoStore;

use redis_crypto_store::RedisStore;

/// All the errors that can occur when opening a redis store.
#[derive(Error, Debug)]
#[non_exhaustive]
pub enum OpenStoreError {
/// An error occurred with the state store implementation.
#[cfg(feature = "state-store")]
#[error(transparent)]
State(#[from] StoreError),

/// An error occurred with the crypto store implementation.
#[cfg(feature = "crypto-store")]
#[error(transparent)]
Crypto(#[from] CryptoStoreError),

/// An error occurred with redis.
#[error(transparent)]
Redis(#[from] RedisError),
}

/// Create a [`StoreConfig`] with an opened [`RedisStateStore`] that uses the
/// given path and passphrase.
///
/// If the `e2e-encryption` Cargo feature is enabled, a [`RedisCryptoStore`] with
/// the same parameters is also opened.
///
/// [`StoreConfig`]: #StoreConfig
#[cfg(any(feature = "state-store", feature = "crypto-store"))]
pub async fn make_store_config(
redis_url: &str,
passphrase: Option<&str>,
redis_prefix: &str,
) -> Result<StoreConfig, OpenStoreError> {
use real_redis::RealRedisClient;

#[cfg(all(feature = "crypto-store", feature = "state-store"))]
{
panic!("Currently don't have a Redis state store!");

let underlying_client = redis::Client::open(redis_url).unwrap();
let client = RealRedisClient::from(underlying_client);
let crypto_store = RedisStore::open(client, passphrase, String::from(redis_prefix)).await?;
// TODO: state_store
Ok(StoreConfig::new().state_store(state_store).crypto_store(crypto_store))
}

#[cfg(all(feature = "crypto-store", not(feature = "state-store")))]
{
let underlying_client = redis::Client::open(redis_url).unwrap();
let client = RealRedisClient::from(underlying_client);
let crypto_store = RedisStore::open(client, passphrase, String::from(redis_prefix)).await?;
Ok(StoreConfig::new().crypto_store(crypto_store))
}

#[cfg(not(feature = "crypto-store"))]
{
panic!("Currently don't have a Redis state store!");

let mut store_builder = RedisStateStore::builder();
store_builder.path(path.as_ref().to_path_buf());

if let Some(passphrase) = passphrase {
store_builder.passphrase(passphrase.to_owned());
};
let state_store = store_builder.build().map_err(StoreError::backend)?;

Ok(StoreConfig::new().state_store(state_store))
}
}
2 changes: 0 additions & 2 deletions crates/matrix-sdk-redis/src/real_redis.rs
Original file line number Diff line number Diff line change
Expand Up @@ -103,8 +103,6 @@ pub struct RealRedisClient {
}

impl RealRedisClient {
#[cfg(feature = "real-redis-tests")]
#[cfg(test)]
pub fn from(client: redis::Client) -> Self {
Self { client }
}
Expand Down
5 changes: 3 additions & 2 deletions crates/matrix-sdk-redis/src/redis_crypto_store.rs
Original file line number Diff line number Diff line change
Expand Up @@ -155,9 +155,10 @@ where
C: RedisClientShim,
{
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
f.debug_struct("RedisStore")
.field("redis_url", &self.client.get_connection_info().redis)
f.debug_struct("RedisStore<C>")
.field("client.get_connection_info().redis", &self.client.get_connection_info().redis)
.field("key_prefix", &self.key_prefix)
.field("account_info", &self.account_info)
.finish()
}
}
Expand Down
16 changes: 16 additions & 0 deletions crates/matrix-sdk/src/client/builder.rs
Original file line number Diff line number Diff line change
Expand Up @@ -143,6 +143,22 @@ impl ClientBuilder {
self
}

/// Set up the store configuration for a redis store.
///
/// This is a shorthand for
/// <code>.[store_config](Self::store_config)([matrix_sdk_redis]::[make_store_config](matrix_sdk_redis::make_store_config)(path, passphrase)?)</code>.
#[cfg(feature = "redis")]
pub async fn redis_store(
self,
redis_url: &str,
passphrase: Option<&str>,
redis_prefix: &str,
) -> Result<Self, matrix_sdk_redis::OpenStoreError> {
let config =
matrix_sdk_redis::make_store_config(redis_url, passphrase, redis_prefix).await?;
Ok(self.store_config(config))
}

/// Set up the store configuration for a IndexedDB store.
///
/// This is the same as
Expand Down
6 changes: 6 additions & 0 deletions examples/command_bot/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -10,10 +10,16 @@ test = false

[dependencies]
anyhow = "1"
dirs = { version = "4.0.0", optional = true }
tokio = { version = "1.20.1", features = ["macros", "rt-multi-thread"] }
tracing-subscriber = "0.3.15"
url = "2.2.2"

[features]
default = []
redis = ["matrix-sdk/redis"]
sled = ["matrix-sdk/sled", "dep:dirs"]

[dependencies.matrix-sdk]
path = "../../crates/matrix-sdk"
version = "0.6.0"
29 changes: 22 additions & 7 deletions examples/command_bot/src/main.rs
Original file line number Diff line number Diff line change
Expand Up @@ -34,28 +34,39 @@ async fn login_and_sync(
homeserver_url: String,
username: String,
password: String,
device_id: Option<String>,
) -> anyhow::Result<()> {
#[allow(unused_mut)]
let mut client_builder = Client::builder().homeserver_url(homeserver_url);

// TODO: sled feature is not actually working!
#[cfg(feature = "sled")]
{
// The location to save files to
let home = dirs::home_dir().expect("no home directory found").join("party_bot");
client_builder = client_builder.sled_store(home, None)?;
}

#[cfg(feature = "redis")]
{
println!("Creating a Redis store on 127.0.0.1");
let redis_url = "redis://127.0.0.1/";
let redis_prefix = "party_bot";
client_builder = client_builder.redis_store(redis_url, None, redis_prefix).await?;
}

#[cfg(feature = "indexeddb")]
{
client_builder = client_builder.indexeddb_store("party_bot", None).await?;
}

let client = client_builder.build().await.unwrap();
client
.login_username(&username, &password)
.initial_device_display_name("command bot")
.send()
.await?;

let mut login = client.login_username(&username, &password);
if let Some(device_id) = &device_id {
login = login.device_id(device_id);
}
login.initial_device_display_name("command bot").send().await?;

println!("logged in as {username}");

Expand Down Expand Up @@ -86,13 +97,17 @@ async fn main() -> anyhow::Result<()> {
(Some(a), Some(b), Some(c)) => (a, b, c),
_ => {
eprintln!(
"Usage: {} <homeserver_url> <username> <password>",
"Usage: {} \
<homeserver_url> \
<username> \
<password> \
[<device_id>]",
env::args().next().unwrap()
);
exit(1)
}
};

login_and_sync(homeserver_url, username, password).await?;
login_and_sync(homeserver_url, username, password, env::args().nth(4)).await?;
Ok(())
}

0 comments on commit 679cb67

Please sign in to comment.