add Secret<T> to RegistryCredentialConfig

This commit is contained in:
Kyle Matsuda 2023-01-09 17:04:47 -07:00
parent 9e732c6d21
commit e69a18ec79
3 changed files with 35 additions and 24 deletions

View File

@ -30,7 +30,7 @@ use crate::ops;
use crate::ops::Packages; use crate::ops::Packages;
use crate::sources::{RegistrySource, SourceConfigMap, CRATES_IO_DOMAIN, CRATES_IO_REGISTRY}; use crate::sources::{RegistrySource, SourceConfigMap, CRATES_IO_DOMAIN, CRATES_IO_REGISTRY};
use crate::util::auth::{ use crate::util::auth::{
paserk_public_from_paserk_secret, {self, AuthorizationError}, paserk_public_from_paserk_secret, Secret, {self, AuthorizationError},
}; };
use crate::util::config::{Config, SslVersionConfig, SslVersionConfigRange}; use crate::util::config::{Config, SslVersionConfig, SslVersionConfigRange};
use crate::util::errors::CargoResult; use crate::util::errors::CargoResult;
@ -45,11 +45,11 @@ use crate::{drop_print, drop_println, version};
pub enum RegistryCredentialConfig { pub enum RegistryCredentialConfig {
None, None,
/// The authentication token. /// The authentication token.
Token(String), Token(Secret<String>),
/// Process used for fetching a token. /// Process used for fetching a token.
Process((PathBuf, Vec<String>)), Process((PathBuf, Vec<String>)),
/// Secret Key and subject for Asymmetric tokens. /// Secret Key and subject for Asymmetric tokens.
AsymmetricKey((String, Option<String>)), AsymmetricKey((Secret<String>, Option<String>)),
} }
impl RegistryCredentialConfig { impl RegistryCredentialConfig {
@ -71,9 +71,9 @@ impl RegistryCredentialConfig {
pub fn is_asymmetric_key(&self) -> bool { pub fn is_asymmetric_key(&self) -> bool {
matches!(self, Self::AsymmetricKey(..)) matches!(self, Self::AsymmetricKey(..))
} }
pub fn as_token(&self) -> Option<&str> { pub fn as_token(&self) -> Option<Secret<&str>> {
if let Self::Token(v) = self { if let Self::Token(v) = self {
Some(&*v) Some(v.as_deref())
} else { } else {
None None
} }
@ -85,7 +85,7 @@ impl RegistryCredentialConfig {
None None
} }
} }
pub fn as_asymmetric_key(&self) -> Option<&(String, Option<String>)> { pub fn as_asymmetric_key(&self) -> Option<&(Secret<String>, Option<String>)> {
if let Self::AsymmetricKey(v) = self { if let Self::AsymmetricKey(v) = self {
Some(v) Some(v)
} else { } else {
@ -830,13 +830,13 @@ pub fn registry_login(
} }
_ => (None, None), _ => (None, None),
}; };
let secret_key: String; let secret_key: Secret<String>;
if generate_keypair { if generate_keypair {
assert!(!secret_key_required); assert!(!secret_key_required);
let kp = AsymmetricKeyPair::<pasetors::version3::V3>::generate().unwrap(); let kp = AsymmetricKeyPair::<pasetors::version3::V3>::generate().unwrap();
let mut key = String::new(); let mut key = String::new();
FormatAsPaserk::fmt(&kp.secret, &mut key).unwrap(); FormatAsPaserk::fmt(&kp.secret, &mut key).unwrap();
secret_key = key; secret_key = Secret::from(key);
} else if secret_key_required { } else if secret_key_required {
assert!(!generate_keypair); assert!(!generate_keypair);
drop_println!(config, "please paste the API secret key below"); drop_println!(config, "please paste the API secret key below");
@ -846,13 +846,13 @@ pub fn registry_login(
.lock() .lock()
.read_line(&mut line) .read_line(&mut line)
.with_context(|| "failed to read stdin")?; .with_context(|| "failed to read stdin")?;
secret_key = line.trim().to_string(); secret_key = Secret::from(line.trim().to_string());
} else { } else {
secret_key = old_secret_key secret_key = old_secret_key
.cloned() .cloned()
.ok_or_else(|| anyhow!("need a secret_key to set a key_subject"))?; .ok_or_else(|| anyhow!("need a secret_key to set a key_subject"))?;
} }
if let Some(p) = paserk_public_from_paserk_secret(&secret_key) { if let Some(p) = paserk_public_from_paserk_secret(secret_key.as_deref()) {
drop_println!(config, "{}", &p); drop_println!(config, "{}", &p);
} else { } else {
bail!("not a validly formated PASERK secret key"); bail!("not a validly formated PASERK secret key");
@ -866,7 +866,7 @@ pub fn registry_login(
)); ));
} else { } else {
new_token = RegistryCredentialConfig::Token(match token { new_token = RegistryCredentialConfig::Token(match token {
Some(token) => token.to_string(), Some(token) => Secret::from(token.to_string()),
None => { None => {
if let Some(login_url) = login_url { if let Some(login_url) = login_url {
drop_println!( drop_println!(
@ -890,7 +890,7 @@ pub fn registry_login(
.with_context(|| "failed to read stdin")?; .with_context(|| "failed to read stdin")?;
// Automatically remove `cargo login` from an inputted token to // Automatically remove `cargo login` from an inputted token to
// allow direct pastes from `registry.host()`/me. // allow direct pastes from `registry.host()`/me.
line.replace("cargo login", "").trim().to_string() Secret::from(line.replace("cargo login", "").trim().to_string())
} }
}); });

View File

@ -281,13 +281,13 @@ fn registry_credential_config_inner(
registry registry
)); ));
} }
(Some(token), _, _, _) => RegistryCredentialConfig::Token(token), (Some(token), _, _, _) => RegistryCredentialConfig::Token(Secret::from(token)),
(_, Some(process), _, _) => RegistryCredentialConfig::Process(( (_, Some(process), _, _) => RegistryCredentialConfig::Process((
process.path.resolve_program(config), process.path.resolve_program(config),
process.args, process.args,
)), )),
(None, None, Some(key), subject) => { (None, None, Some(key), subject) => {
RegistryCredentialConfig::AsymmetricKey((key, subject)) RegistryCredentialConfig::AsymmetricKey((Secret::from(key), subject))
} }
(None, None, None, _) => { (None, None, None, _) => {
if !is_crates_io { if !is_crates_io {
@ -432,15 +432,19 @@ fn auth_token_optional(
let credential = registry_credential_config(config, sid)?; let credential = registry_credential_config(config, sid)?;
let (independent_of_endpoint, token) = match credential { let (independent_of_endpoint, token) = match credential {
RegistryCredentialConfig::None => return Ok(None), RegistryCredentialConfig::None => return Ok(None),
RegistryCredentialConfig::Token(config_token) => (true, config_token.to_string()), RegistryCredentialConfig::Token(config_token) => (true, config_token.expose()),
RegistryCredentialConfig::Process(process) => { RegistryCredentialConfig::Process(process) => {
// todo: PASETO with process // todo: PASETO with process
run_command(config, &process, sid, Action::Get)?.unwrap() run_command(config, &process, sid, Action::Get)?.unwrap()
} }
RegistryCredentialConfig::AsymmetricKey((secret_key, secret_key_subject)) => { RegistryCredentialConfig::AsymmetricKey((secret_key, secret_key_subject)) => {
let secret: AsymmetricSecretKey<pasetors::version3::V3> = let secret: Secret<AsymmetricSecretKey<pasetors::version3::V3>> =
secret_key.as_str().try_into()?; secret_key.map(|key| key.as_str().try_into()).transpose()?;
let public: AsymmetricPublicKey<pasetors::version3::V3> = (&secret).try_into()?; let public: AsymmetricPublicKey<pasetors::version3::V3> = secret
.as_ref()
.map(|key| key.try_into())
.transpose()?
.expose();
let kip: pasetors::paserk::Id = (&public).try_into()?; let kip: pasetors::paserk::Id = (&public).try_into()?;
let iat = OffsetDateTime::now_utc(); let iat = OffsetDateTime::now_utc();
@ -493,7 +497,7 @@ fn auth_token_optional(
( (
false, false,
pasetors::version3::PublicToken::sign( pasetors::version3::PublicToken::sign(
&secret, &secret.expose(),
serde_json::to_string(&message) serde_json::to_string(&message)
.expect("cannot serialize") .expect("cannot serialize")
.as_bytes(), .as_bytes(),
@ -598,6 +602,7 @@ pub fn login(config: &Config, sid: &SourceId, token: RegistryCredentialConfig) -
let token = token let token = token
.as_token() .as_token()
.expect("credential_process cannot use login with a secret_key") .expect("credential_process cannot use login with a secret_key")
.expose()
.to_owned(); .to_owned();
run_command(config, &process, sid, Action::Store(token))?; run_command(config, &process, sid, Action::Store(token))?;
} }
@ -609,9 +614,15 @@ pub fn login(config: &Config, sid: &SourceId, token: RegistryCredentialConfig) -
} }
/// Checks that a secret key is valid, and returns the associated public key in Paserk format. /// Checks that a secret key is valid, and returns the associated public key in Paserk format.
pub(crate) fn paserk_public_from_paserk_secret(secret_key: &str) -> Option<String> { pub(crate) fn paserk_public_from_paserk_secret(secret_key: Secret<&str>) -> Option<String> {
let secret: AsymmetricSecretKey<pasetors::version3::V3> = secret_key.try_into().ok()?; let secret: Secret<AsymmetricSecretKey<pasetors::version3::V3>> =
let public: AsymmetricPublicKey<pasetors::version3::V3> = (&secret).try_into().ok()?; secret_key.map(|key| key.try_into()).transpose().ok()?;
let public: AsymmetricPublicKey<pasetors::version3::V3> = secret
.as_ref()
.map(|key| key.try_into())
.transpose()
.ok()?
.expose();
let mut paserk_pub_key = String::new(); let mut paserk_pub_key = String::new();
FormatAsPaserk::fmt(&public, &mut paserk_pub_key).unwrap(); FormatAsPaserk::fmt(&public, &mut paserk_pub_key).unwrap();
Some(paserk_pub_key) Some(paserk_pub_key)

View File

@ -2179,7 +2179,7 @@ pub fn save_credentials(
// login with token // login with token
let key = "token".to_string(); let key = "token".to_string();
let value = ConfigValue::String(token, path_def.clone()); let value = ConfigValue::String(token.expose(), path_def.clone());
let map = HashMap::from([(key, value)]); let map = HashMap::from([(key, value)]);
let table = CV::Table(map, path_def.clone()); let table = CV::Table(map, path_def.clone());
@ -2194,7 +2194,7 @@ pub fn save_credentials(
// login with key // login with key
let key = "secret-key".to_string(); let key = "secret-key".to_string();
let value = ConfigValue::String(secret_key, path_def.clone()); let value = ConfigValue::String(secret_key.expose(), path_def.clone());
let mut map = HashMap::from([(key, value)]); let mut map = HashMap::from([(key, value)]);
if let Some(key_subject) = key_subject { if let Some(key_subject) = key_subject {
let key = "secret-key-subject".to_string(); let key = "secret-key-subject".to_string();