diff --git a/Cargo.toml b/Cargo.toml index 53de733e..4556a982 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,10 +1,10 @@ [workspace] members = [ - "crates/*", - "bindings/*", - "examples/*", - "tests/*", - "xtask", + "crates/*", + "bindings/*", + "examples/*", + "tests/*", + "xtask", ] default-members = ["crates/*"] resolver = "2" @@ -25,6 +25,7 @@ mime = "0.3" once_cell = "1.12" parking_lot = "0.12" pretty_assertions = "1.4" +secrecy = "0.8" serde = "1.0" serde_json = "1.0" sha1 = "0.10" @@ -38,7 +39,7 @@ tracing-log = "0.2.0" tracing-subscriber = "0.3" uniffi = "0.26" url = "2.3" -uuid = {version = "1.1", features=["v4", "fast-rng", "macro-diagnostics"]} +uuid = { version = "1.1", features = ["v4", "fast-rng", "macro-diagnostics"] } wasm-bindgen = { version = "0.2" } wasm-bindgen-futures = "0.4" minidom = { git = "https://gitlab.com/nesium/xmpp-rs", branch = "main" } diff --git a/bindings/prose-sdk-ffi/src/client.rs b/bindings/prose-sdk-ffi/src/client.rs index b61e45f9..77fadc6f 100644 --- a/bindings/prose-sdk-ffi/src/client.rs +++ b/bindings/prose-sdk-ffi/src/client.rs @@ -3,17 +3,18 @@ // Copyright: 2023, Marc Bauer // License: Mozilla Public License v2.0 (MPL v2.0) -use parking_lot::{Mutex, RwLock}; use std::fs; use std::path::{Path, PathBuf}; use std::sync::Arc; + +use parking_lot::{Mutex, RwLock}; use tracing::info; use prose_core_client::dtos::{Availability, Emoji, MessageId, UserProfile}; use prose_core_client::infra::encryption::EncryptionKeysRepository; use prose_core_client::{ open_store, Client as ProseClient, ClientDelegate as ProseClientDelegate, FsAvatarCache, - PlatformDriver, SignalServiceHandle, + PlatformDriver, Secret, SignalServiceHandle, }; use prose_xmpp::{connector, ConnectionError}; @@ -83,7 +84,7 @@ impl Client { self.client() .await .map_err(|e| ConnectionError::Generic { msg: e.to_string() })? - .connect(&self.jid.to_bare().unwrap().into(), password) + .connect(&self.jid.to_bare().unwrap().into(), Secret::new(password)) .await?; Ok(()) } diff --git a/bindings/prose-sdk-js/Cargo.toml b/bindings/prose-sdk-js/Cargo.toml index 502b67b8..d045afa5 100644 --- a/bindings/prose-sdk-js/Cargo.toml +++ b/bindings/prose-sdk-js/Cargo.toml @@ -25,6 +25,7 @@ mime = { workspace = true } minidom = { workspace = true } prose-core-client = { path = "../../crates/prose-core-client" } prose-xmpp = { path = "../../crates/prose-xmpp" } +secrecy = { workspace = true } serde = { workspace = true, features = ["derive"] } serde-wasm-bindgen = "0.5" serde_json = { workspace = true } @@ -36,4 +37,4 @@ url = { workspace = true } wasm-bindgen = { workspace = true } wasm-bindgen-derive = "0.2.0" wasm-bindgen-futures = { workspace = true } -web-sys = { version = "0.3", features = ["DomException"] } +web-sys = { version = "0.3", features = ["DomException"] } \ No newline at end of file diff --git a/bindings/prose-sdk-js/src/client.rs b/bindings/prose-sdk-js/src/client.rs index 8ce6e5d5..086f4510 100644 --- a/bindings/prose-sdk-js/src/client.rs +++ b/bindings/prose-sdk-js/src/client.rs @@ -15,7 +15,9 @@ use wasm_bindgen::prelude::*; use prose_core_client::dtos::{MucId, SoftwareVersion, UserStatus}; use prose_core_client::infra::encryption::EncryptionKeysRepository; -use prose_core_client::{open_store, Client as ProseClient, PlatformDriver, StoreAvatarCache}; +use prose_core_client::{ + open_store, Client as ProseClient, PlatformDriver, Secret, StoreAvatarCache, +}; use crate::connector::{Connector, ProseConnectionProvider}; use crate::delegate::{Delegate, JSDelegate}; @@ -189,7 +191,9 @@ impl Client { jid: &BareJid, password: &str, ) -> std::result::Result<(), ConnectionError> { - self.client.connect(&jid.into(), password).await?; + self.client + .connect(&jid.into(), Secret::new(password.to_string())) + .await?; Ok(()) } diff --git a/bindings/prose-sdk-js/src/connector/strophe_js.rs b/bindings/prose-sdk-js/src/connector/strophe_js.rs index b1d2ea46..6f04b991 100644 --- a/bindings/prose-sdk-js/src/connector/strophe_js.rs +++ b/bindings/prose-sdk-js/src/connector/strophe_js.rs @@ -11,6 +11,7 @@ use anyhow::Result; use async_trait::async_trait; use jid::FullJid; use minidom::Element; +use secrecy::{ExposeSecret, Secret}; use thiserror::Error; use wasm_bindgen::prelude::*; use wasm_bindgen_futures::spawn_local; @@ -97,7 +98,7 @@ impl ConnectorTrait for Connector { async fn connect( &self, jid: &FullJid, - password: &str, + password: Secret, event_handler: ConnectionEventHandler, ) -> Result, ConnectionError> { let client = Rc::new(self.provider.provide_connection(self.config.clone())); @@ -128,7 +129,9 @@ impl ConnectorTrait for Connector { handler: event_handler, }; client.set_event_handler(event_handler); - let result = client.connect(jid.to_string(), password.to_string()).await; + let result = client + .connect(jid.to_string(), password.expose_secret().to_string()) + .await; if let Err(err) = result { let Some(code) = err.as_f64().map(|code| code as i32) else { diff --git a/crates/prose-core-client/Cargo.toml b/crates/prose-core-client/Cargo.toml index 89a04b97..aa490d4d 100644 --- a/crates/prose-core-client/Cargo.toml +++ b/crates/prose-core-client/Cargo.toml @@ -34,6 +34,7 @@ prose-utils = { path = "../prose-utils" } prose-wasm-utils = { path = "../prose-wasm-utils" } prose-xmpp = { path = "../prose-xmpp" } rand = "0.8" +secrecy = { workspace = true } serde = { workspace = true, features = ["derive"] } sha1 = { workspace = true } strum = { workspace = true } diff --git a/crates/prose-core-client/src/app/services/connection_service.rs b/crates/prose-core-client/src/app/services/connection_service.rs index c0d72a72..6358bfe6 100644 --- a/crates/prose-core-client/src/app/services/connection_service.rs +++ b/crates/prose-core-client/src/app/services/connection_service.rs @@ -3,6 +3,7 @@ // Copyright: 2023, Marc Bauer // License: Mozilla Public License v2.0 (MPL v2.0) +use secrecy::Secret; use tracing::error; use prose_proc_macros::InjectDependencies; @@ -44,7 +45,7 @@ impl ConnectionService { pub async fn connect( &self, jid: &UserId, - password: impl AsRef, + password: Secret, ) -> Result<(), ConnectionError> { let settings = self.account_settings_repo @@ -67,10 +68,7 @@ impl ConnectionService { server_features: Default::default(), }); - let connection_result = self - .connection_service - .connect(&full_jid, password.as_ref()) - .await; + let connection_result = self.connection_service.connect(&full_jid, password).await; match connection_result { Ok(_) => (), Err(err) => { diff --git a/crates/prose-core-client/src/client.rs b/crates/prose-core-client/src/client.rs index f4bc0db6..6cd33a2f 100644 --- a/crates/prose-core-client/src/client.rs +++ b/crates/prose-core-client/src/client.rs @@ -7,6 +7,7 @@ use std::ops::Deref; use std::sync::Arc; use anyhow::Result; +use secrecy::Secret; use crate::app::deps::DynAppContext; use prose_wasm_utils::{SendUnlessWasm, SyncUnlessWasm}; @@ -72,7 +73,7 @@ impl Client { pub async fn connect( &self, id: &UserId, - password: impl AsRef, + password: Secret, ) -> Result<(), ConnectionError> { self.connection.connect(id, password).await } diff --git a/crates/prose-core-client/src/domain/connection/services/connection_service.rs b/crates/prose-core-client/src/domain/connection/services/connection_service.rs index 10fa1d92..a19026ee 100644 --- a/crates/prose-core-client/src/domain/connection/services/connection_service.rs +++ b/crates/prose-core-client/src/domain/connection/services/connection_service.rs @@ -6,6 +6,7 @@ use anyhow::Result; use async_trait::async_trait; use minidom::Element; +use secrecy::Secret; use prose_wasm_utils::{SendUnlessWasm, SyncUnlessWasm}; use prose_xmpp::ConnectionError; @@ -17,7 +18,11 @@ use crate::domain::shared::models::UserResourceId; #[async_trait] #[cfg_attr(feature = "test", mockall::automock)] pub trait ConnectionService: SendUnlessWasm + SyncUnlessWasm { - async fn connect(&self, jid: &UserResourceId, password: &str) -> Result<(), ConnectionError>; + async fn connect( + &self, + jid: &UserResourceId, + password: Secret, + ) -> Result<(), ConnectionError>; async fn disconnect(&self); async fn set_message_carbons_enabled(&self, is_enabled: bool) -> Result<()>; diff --git a/crates/prose-core-client/src/infra/connection/connection_service.rs b/crates/prose-core-client/src/infra/connection/connection_service.rs index 6746d8bd..11933a77 100644 --- a/crates/prose-core-client/src/infra/connection/connection_service.rs +++ b/crates/prose-core-client/src/infra/connection/connection_service.rs @@ -6,6 +6,7 @@ use anyhow::Result; use async_trait::async_trait; use minidom::Element; +use secrecy::Secret; use prose_xmpp::{mods, ns, ConnectionError}; @@ -17,7 +18,11 @@ use crate::infra::xmpp::XMPPClient; #[cfg_attr(target_arch = "wasm32", async_trait(? Send))] #[async_trait] impl ConnectionService for XMPPClient { - async fn connect(&self, jid: &UserResourceId, password: &str) -> Result<(), ConnectionError> { + async fn connect( + &self, + jid: &UserResourceId, + password: Secret, + ) -> Result<(), ConnectionError> { self.client.connect(jid.as_ref(), password).await } diff --git a/crates/prose-core-client/src/lib.rs b/crates/prose-core-client/src/lib.rs index 5a162812..0ef3d3cb 100644 --- a/crates/prose-core-client/src/lib.rs +++ b/crates/prose-core-client/src/lib.rs @@ -5,6 +5,8 @@ extern crate core; +pub use secrecy::Secret; + pub use app::deps::DynEncryptionKeysRepository; pub use app::{dtos, services}; pub use client::{Client, ClientDelegate}; diff --git a/crates/prose-core-client/tests/connection_service.rs b/crates/prose-core-client/tests/connection_service.rs index 940bde1b..2d0ee96e 100644 --- a/crates/prose-core-client/tests/connection_service.rs +++ b/crates/prose-core-client/tests/connection_service.rs @@ -7,6 +7,7 @@ use std::sync::{Arc, OnceLock}; use anyhow::Result; use mockall::predicate; +use secrecy::{ExposeSecret, Secret}; use prose_core_client::app::deps::DynAppContext; use prose_core_client::app::services::ConnectionService; @@ -38,7 +39,7 @@ async fn test_starts_available_and_generates_resource() -> Result<()> { .once() .with( predicate::eq(user_resource_id!("jane.doe@prose.org/resource-id")), - predicate::eq("my-password"), + predicate::function(|pw: &Secret| pw.expose_secret().as_str() == "my-password"), ) .return_once(|_, _| Box::pin(async { Ok(Default::default()) })); deps.contact_list_domain_service @@ -111,7 +112,10 @@ async fn test_starts_available_and_generates_resource() -> Result<()> { assert!(deps.ctx.muc_service().is_err()); service - .connect(&user_id!("jane.doe@prose.org"), "my-password") + .connect( + &user_id!("jane.doe@prose.org"), + Secret::new("my-password".to_string()), + ) .await?; assert_eq!( @@ -212,7 +216,10 @@ async fn test_restores_availability_and_resource() -> Result<()> { let service = ConnectionService::from(&deps); service - .connect(&user_id!("jane.doe@prose.org"), "my-password") + .connect( + &user_id!("jane.doe@prose.org"), + Secret::new("my-password".to_string()), + ) .await?; Ok(()) @@ -261,7 +268,10 @@ async fn test_connection_failure() -> Result<()> { assert!(deps.ctx.muc_service().is_err()); assert!(service - .connect(&user_id!("jane.doe@prose.org"), "my-password") + .connect( + &user_id!("jane.doe@prose.org"), + Secret::new("my-password".to_string()) + ) .await .is_err()); diff --git a/crates/prose-xmpp/Cargo.toml b/crates/prose-xmpp/Cargo.toml index 2faf70b4..33a370c4 100644 --- a/crates/prose-xmpp/Cargo.toml +++ b/crates/prose-xmpp/Cargo.toml @@ -25,6 +25,7 @@ parking_lot = { workspace = true } prose-proc-macros = { path = "../prose-proc-macros" } prose-utils = { path = "../prose-utils" } prose-wasm-utils = { path = "../prose-wasm-utils" } +secrecy = { workspace = true } serde = { workspace = true, features = ["derive"] } sha1 = { workspace = true } strum = { workspace = true } diff --git a/crates/prose-xmpp/src/client/builder.rs b/crates/prose-xmpp/src/client/builder.rs index 4318f9b3..55bb0b01 100644 --- a/crates/prose-xmpp/src/client/builder.rs +++ b/crates/prose-xmpp/src/client/builder.rs @@ -13,6 +13,7 @@ use jid::FullJid; use minidom::Element; use parking_lot::RwLock; use prose_wasm_utils::{PinnedFuture, SendUnlessWasm, SyncUnlessWasm}; +use secrecy::Secret; use crate::client::client::ClientInner; use crate::client::module_context::ModuleContextInner; @@ -146,7 +147,7 @@ impl Connector for UndefinedConnector { async fn connect( &self, _jid: &FullJid, - _password: &str, + _password: Secret, _event_handler: ConnectionEventHandler, ) -> Result, ConnectionError> { panic!("Client doesn't have a connector. Provide one before calling connect()") diff --git a/crates/prose-xmpp/src/client/client.rs b/crates/prose-xmpp/src/client/client.rs index b3e7d801..e90aed48 100644 --- a/crates/prose-xmpp/src/client/client.rs +++ b/crates/prose-xmpp/src/client/client.rs @@ -13,6 +13,7 @@ use std::time::{Duration, SystemTime}; use anyhow::Result; use jid::FullJid; use minidom::Element; +use secrecy::Secret; use tracing::{error, warn}; use prose_wasm_utils::PinnedFuture; @@ -45,7 +46,7 @@ impl Client { pub async fn connect( &self, jid: &FullJid, - password: impl AsRef, + password: Secret, ) -> Result<(), ConnectionError> { self.inner.clone().connect(jid, password).await } @@ -78,7 +79,7 @@ impl ClientInner { async fn connect( self: Arc, jid: &FullJid, - password: impl AsRef, + password: Secret, ) -> Result<(), ConnectionError> { self.disconnect(); @@ -89,7 +90,7 @@ impl ClientInner { let connection = (self.context.connector_provider)() .connect( jid, - password.as_ref(), + password, Box::new(move |_, event| { let inner = inner.clone(); diff --git a/crates/prose-xmpp/src/connector/connector.rs b/crates/prose-xmpp/src/connector/connector.rs index 823e1250..6b637bd1 100644 --- a/crates/prose-xmpp/src/connector/connector.rs +++ b/crates/prose-xmpp/src/connector/connector.rs @@ -8,6 +8,7 @@ use async_trait::async_trait; use jid::FullJid; use minidom::Element; use prose_wasm_utils::{PinnedFuture, SendUnlessWasm, SyncUnlessWasm}; +use secrecy::Secret; #[derive(Debug, thiserror::Error, Clone, PartialEq)] pub enum ConnectionError { @@ -31,7 +32,7 @@ pub trait Connector: SendUnlessWasm + SyncUnlessWasm { async fn connect( &self, jid: &FullJid, - password: &str, + password: Secret, event_handler: ConnectionEventHandler, ) -> Result, ConnectionError>; } diff --git a/crates/prose-xmpp/src/connector/xmpp_rs.rs b/crates/prose-xmpp/src/connector/xmpp_rs.rs index ec219999..8a758248 100644 --- a/crates/prose-xmpp/src/connector/xmpp_rs.rs +++ b/crates/prose-xmpp/src/connector/xmpp_rs.rs @@ -12,6 +12,7 @@ use futures::stream::StreamExt; use futures::SinkExt; use jid::FullJid; use minidom::Element; +use secrecy::{ExposeSecret, Secret}; use tokio::sync::mpsc; use tokio::sync::mpsc::UnboundedSender; use tokio::task::JoinHandle; @@ -39,14 +40,14 @@ impl ConnectorTrait for Connector { async fn connect( &self, jid: &FullJid, - password: &str, + password: Secret, event_handler: ConnectionEventHandler, ) -> Result, ConnectionError> { async fn connect( jid: &FullJid, - password: impl Into, + password: Secret, ) -> Result, ConnectionError> { - let mut client = AsyncClient::new(jid.clone(), password); + let mut client = AsyncClient::new(jid.clone(), password.expose_secret()); client.set_reconnect(false); while let Some(event) = client.next().await { diff --git a/crates/prose-xmpp/src/lib.rs b/crates/prose-xmpp/src/lib.rs index 8a1cd288..c4fb5176 100644 --- a/crates/prose-xmpp/src/lib.rs +++ b/crates/prose-xmpp/src/lib.rs @@ -3,6 +3,8 @@ // Copyright: 2023, Marc Bauer // License: Mozilla Public License v2.0 (MPL v2.0) +pub use secrecy::Secret; + pub use client::{Client, ClientBuilder}; pub use connector::{Connection, ConnectionError, Connector}; pub use deps::{IDProvider, SystemTimeProvider, TimeProvider, UUIDProvider}; diff --git a/crates/prose-xmpp/src/test/connected_client.rs b/crates/prose-xmpp/src/test/connected_client.rs index 8b7c6848..0d713455 100644 --- a/crates/prose-xmpp/src/test/connected_client.rs +++ b/crates/prose-xmpp/src/test/connected_client.rs @@ -10,6 +10,7 @@ use anyhow::Result; use async_trait::async_trait; use jid::{BareJid, FullJid}; use parking_lot::RwLock; +use secrecy::Secret; use crate::test::{BareJidTestAdditions, Connection, Connector, IncrementingIDProvider}; use crate::{Client, Event, IDProvider}; @@ -51,7 +52,7 @@ impl ClientTestAdditions for Client { })) .build(); - client.connect(&jid, "").await?; + client.connect(&jid, Secret::new("".to_string())).await?; id_provider.reset(); sent_events.write().clear(); diff --git a/crates/prose-xmpp/src/test/connector.rs b/crates/prose-xmpp/src/test/connector.rs index 7b9c6ea1..2136653b 100644 --- a/crates/prose-xmpp/src/test/connector.rs +++ b/crates/prose-xmpp/src/test/connector.rs @@ -10,6 +10,7 @@ use async_trait::async_trait; use jid::FullJid; use minidom::Element; use parking_lot::{Mutex, RwLock}; +use secrecy::Secret; use xmpp_parsers::disco::DiscoItemsResult; use xmpp_parsers::iq::Iq; @@ -38,7 +39,7 @@ impl ConnectorTrait for Connector { async fn connect( &self, _jid: &FullJid, - _password: &str, + _password: Secret, event_handler: ConnectionEventHandler, ) -> Result, ConnectionError> { *self.connection.inner.event_handler.write() = Some(event_handler); diff --git a/examples/prose-core-client-cli/src/main.rs b/examples/prose-core-client-cli/src/main.rs index 63e43b02..6933c499 100644 --- a/examples/prose-core-client-cli/src/main.rs +++ b/examples/prose-core-client-cli/src/main.rs @@ -37,7 +37,7 @@ use prose_core_client::{ open_store, Client, ClientDelegate, ClientEvent, ClientRoomEventType, PlatformDriver, SignalServiceHandle, }; -use prose_xmpp::connector; +use prose_xmpp::{connector, Secret}; use crate::type_display::{ ConnectedRoomEnvelope, DeviceInfoEnvelope, JidWithName, MessageEnvelope, ParticipantEnvelope, @@ -77,7 +77,7 @@ async fn configure_client() -> Result<(BareJid, Client)> { println!("Connecting to server as {}…", jid); client - .connect(&UserId::from(jid.to_bare()), password) + .connect(&UserId::from(jid.to_bare()), Secret::new(password)) .await?; println!("Connected."); diff --git a/examples/xmpp-client/src/main.rs b/examples/xmpp-client/src/main.rs index dd30ce09..bab4513f 100644 --- a/examples/xmpp-client/src/main.rs +++ b/examples/xmpp-client/src/main.rs @@ -10,7 +10,7 @@ use tracing::info; use common::{enable_debug_logging, load_credentials, Level}; use prose_xmpp::mods::{chat, Chat, Profile, Status}; use prose_xmpp::stanza::presence::Show; -use prose_xmpp::{connector, Client, Event}; +use prose_xmpp::{connector, Client, Event, Secret}; // This example starts a XMPP client and listens for messages. If a message is received it loads // the sender's vCard and response with a greeting and some text. @@ -27,7 +27,7 @@ async fn main() -> Result<()> { let (jid, password) = load_credentials(); info!("Connecting…"); - client.connect(&jid, password).await?; + client.connect(&jid, Secret::new(password)).await?; info!("Connected."); client diff --git a/tests/prose-core-integration-tests/src/tests/helpers/connector.rs b/tests/prose-core-integration-tests/src/tests/helpers/connector.rs index aeb57218..45e7cc84 100644 --- a/tests/prose-core-integration-tests/src/tests/helpers/connector.rs +++ b/tests/prose-core-integration-tests/src/tests/helpers/connector.rs @@ -10,6 +10,7 @@ use async_trait::async_trait; use jid::FullJid; use minidom::Element; use pretty_assertions::assert_eq; +use prose_core_client::Secret; use prose_xmpp::client::ConnectorProvider; use prose_xmpp::connector::{ @@ -41,7 +42,7 @@ impl ConnectorTrait for Connector { async fn connect( &self, _jid: &FullJid, - _password: &str, + _password: Secret, event_handler: ConnectionEventHandler, ) -> Result, ConnectionError> { Ok(Box::new(Connection { diff --git a/tests/prose-core-integration-tests/src/tests/helpers/test_client_login.rs b/tests/prose-core-integration-tests/src/tests/helpers/test_client_login.rs index 0a7b52a1..f35225cd 100644 --- a/tests/prose-core-integration-tests/src/tests/helpers/test_client_login.rs +++ b/tests/prose-core-integration-tests/src/tests/helpers/test_client_login.rs @@ -6,6 +6,7 @@ use anyhow::Result; use prose_core_client::dtos::UserId; +use prose_core_client::Secret; use prose_xmpp::ConnectionError; use super::TestClient; @@ -43,7 +44,8 @@ impl TestClient { self.perform_publish_device(); self.perform_publish_device_bundle(); - self.connect(&user, password).await + self.connect(&user, Secret::new(password.as_ref().to_string())) + .await } }