#[derive(Debug, Clone)]
pub struct BitwConfig {
pub api_url: String,
pub identity_url: String,
pub client_id: String,
pub client_secret: String,
}
impl BitwConfig {
pub fn new(
api_url: impl Into<String>,
identity_url: impl Into<String>,
client_id: impl Into<String>,
client_secret: impl Into<String>,
) -> Self {
Self {
api_url: api_url.into(),
identity_url: identity_url.into(),
client_id: client_id.into(),
client_secret: client_secret.into(),
}
}
pub fn from_env() -> Option<Self> {
let client_id = std::env::var("TSAFE_BW_CLIENT_ID")
.ok()
.filter(|s| !s.is_empty())?;
let client_secret = std::env::var("TSAFE_BW_CLIENT_SECRET")
.ok()
.filter(|s| !s.is_empty())?;
Some(Self {
api_url: std::env::var("TSAFE_BW_API_URL")
.unwrap_or_else(|_| "https://api.bitwarden.com".into()),
identity_url: std::env::var("TSAFE_BW_IDENTITY_URL")
.unwrap_or_else(|_| "https://identity.bitwarden.com".into()),
client_id,
client_secret,
})
}
pub fn default_api_url() -> &'static str {
"https://api.bitwarden.com"
}
pub fn default_identity_url() -> &'static str {
"https://identity.bitwarden.com"
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn new_stores_fields() {
let cfg = BitwConfig::new(
"https://api.example.com",
"https://identity.example.com",
"org.abc123",
"secret-xyz",
);
assert_eq!(cfg.api_url, "https://api.example.com");
assert_eq!(cfg.identity_url, "https://identity.example.com");
assert_eq!(cfg.client_id, "org.abc123");
assert_eq!(cfg.client_secret, "secret-xyz");
}
#[test]
fn from_env_returns_none_when_vars_absent() {
temp_env::with_vars(
[
("TSAFE_BW_CLIENT_ID", None::<&str>),
("TSAFE_BW_CLIENT_SECRET", None::<&str>),
],
|| {
assert!(BitwConfig::from_env().is_none());
},
);
}
#[test]
fn from_env_uses_client_id_and_secret() {
temp_env::with_vars(
[
("TSAFE_BW_CLIENT_ID", Some("org.testid")),
("TSAFE_BW_CLIENT_SECRET", Some("testsecret")),
("TSAFE_BW_API_URL", None::<&str>),
("TSAFE_BW_IDENTITY_URL", None::<&str>),
],
|| {
let cfg = BitwConfig::from_env().expect("should build from env");
assert_eq!(cfg.client_id, "org.testid");
assert_eq!(cfg.client_secret, "testsecret");
assert_eq!(cfg.api_url, "https://api.bitwarden.com");
assert_eq!(cfg.identity_url, "https://identity.bitwarden.com");
},
);
}
#[test]
fn from_env_uses_custom_urls_when_set() {
temp_env::with_vars(
[
("TSAFE_BW_CLIENT_ID", Some("myid")),
("TSAFE_BW_CLIENT_SECRET", Some("mysecret")),
("TSAFE_BW_API_URL", Some("https://vaultwarden.internal/api")),
(
"TSAFE_BW_IDENTITY_URL",
Some("https://vaultwarden.internal/identity"),
),
],
|| {
let cfg = BitwConfig::from_env().expect("should build from env");
assert_eq!(cfg.api_url, "https://vaultwarden.internal/api");
assert_eq!(cfg.identity_url, "https://vaultwarden.internal/identity");
},
);
}
}