wasm_pkg_client/warg/
config.rsuse std::{fmt::Debug, path::PathBuf, sync::Arc};
use secrecy::{ExposeSecret, SecretString};
use serde::{Deserialize, Serialize, Serializer};
use warg_crypto::signing::PrivateKey;
use wasm_pkg_common::{config::RegistryConfig, Error};
#[derive(Clone, Default, Serialize)]
#[serde(into = "WargRegistryConfigToml")]
pub struct WargRegistryConfig {
pub client_config: warg_client::Config,
pub auth_token: Option<SecretString>,
pub signing_key: Option<Arc<PrivateKey>>,
pub config_file: Option<PathBuf>,
}
impl Debug for WargRegistryConfig {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
f.debug_struct("WargRegistryConfig")
.field("client_config", &self.client_config)
.field("auth_token", &self.auth_token)
.field("signing_key", &"[redacted]")
.field("config_file", &self.config_file)
.finish()
}
}
impl TryFrom<&RegistryConfig> for WargRegistryConfig {
type Error = Error;
fn try_from(registry_config: &RegistryConfig) -> Result<Self, Self::Error> {
let WargRegistryConfigToml {
auth_token,
signing_key,
config_file,
} = registry_config.backend_config("warg")?.unwrap_or_default();
let (client_config, config_file) = match config_file {
Some(path) => (
warg_client::Config::from_file(&path).map_err(Error::RegistryError)?,
Some(path),
),
None => {
(
warg_client::Config::from_default_file()
.map_err(Error::RegistryError)?
.unwrap_or_default(),
None,
)
}
};
Ok(Self {
client_config,
auth_token,
signing_key: signing_key
.map(|k| PrivateKey::decode(k).map(Arc::new))
.transpose()
.map_err(|e| {
Error::InvalidConfig(anyhow::anyhow!("invalid signing key in config file: {e}"))
})?,
config_file,
})
}
}
#[derive(Default, Deserialize, Serialize)]
struct WargRegistryConfigToml {
#[serde(skip_serializing_if = "Option::is_none")]
config_file: Option<PathBuf>,
#[serde(
skip_serializing_if = "Option::is_none",
serialize_with = "serialize_secret"
)]
auth_token: Option<SecretString>,
#[serde(
skip_serializing_if = "Option::is_none",
serialize_with = "serialize_secret"
)]
signing_key: Option<SecretString>,
}
impl From<WargRegistryConfig> for WargRegistryConfigToml {
fn from(value: WargRegistryConfig) -> Self {
WargRegistryConfigToml {
auth_token: value.auth_token,
config_file: value.config_file,
signing_key: value
.signing_key
.map(|k| SecretString::new(k.encode().to_string())),
}
}
}
fn serialize_secret<S: Serializer>(
secret: &Option<SecretString>,
serializer: S,
) -> Result<S::Ok, S::Error> {
if let Some(secret) = secret {
secret.expose_secret().serialize(serializer)
} else {
serializer.serialize_none()
}
}
#[cfg(test)]
mod tests {
use wasm_pkg_common::config::RegistryMapping;
use crate::warg::WargRegistryMetadata;
use super::*;
#[tokio::test]
async fn test_warg_config_roundtrip() {
let dir = tempfile::tempdir().expect("Unable to create tempdir");
let warg_config_path = dir.path().join("warg_config.json");
let (_, key) = warg_crypto::signing::generate_p256_pair();
let config = WargRegistryConfig {
client_config: warg_client::Config {
home_url: Some("https://example.com".to_owned()),
..Default::default()
},
auth_token: Some("imsecret".to_owned().into()),
signing_key: Some(Arc::new(key)),
config_file: Some(warg_config_path.clone()),
};
let mut conf = crate::Config::empty();
let registry: crate::Registry = "example.com:8080".parse().unwrap();
let reg_conf = conf.get_or_insert_registry_config_mut(®istry);
reg_conf
.set_backend_config("warg", &config)
.expect("Unable to set config");
let reg_conf = conf.registry_config(®istry).unwrap();
tokio::fs::write(
&warg_config_path,
serde_json::to_vec(&config.client_config).unwrap(),
)
.await
.unwrap();
let roundtripped = WargRegistryConfig::try_from(reg_conf).expect("Unable to load config");
assert_eq!(
roundtripped
.client_config
.home_url
.expect("Should have a home url set"),
config.client_config.home_url.unwrap(),
"Home url should be set to the right value"
);
assert_eq!(
roundtripped
.auth_token
.expect("Should have an auth token set")
.expose_secret(),
config.auth_token.unwrap().expose_secret(),
"Auth token should be set to the right value"
);
assert_eq!(
roundtripped
.signing_key
.expect("Should have a signing key set")
.encode(),
config.signing_key.unwrap().encode(),
"Signing key should be set to the right value"
);
}
#[test]
fn test_custom_namespace_config() {
let toml_config = toml::toml! {
[namespace_registries]
test = { registry = "localhost:1234", metadata = { preferredProtocol = "warg", "warg" = { url = "http://localhost:1234" } } }
};
let cfg = wasm_pkg_common::config::Config::from_toml(&toml_config.to_string())
.expect("Should be able to load config");
let ns_config = cfg
.namespace_registry(&"test".parse().unwrap())
.expect("Should have a namespace config");
let custom = match ns_config {
RegistryMapping::Custom(c) => c,
_ => panic!("Should have a custom namespace config"),
};
let map: WargRegistryMetadata = custom
.metadata
.protocol_config("warg")
.expect("Should be able to deserialize config")
.expect("protocol config should be present");
assert_eq!(
map.url,
Some("http://localhost:1234".into()),
"URL should be set to the right value"
);
}
}