diff --git a/Cargo.toml b/Cargo.toml index d3352269b..99225e4ce 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -46,6 +46,7 @@ libgit2-sys = "0.14.0" memchr = "2.1.3" opener = "0.5" os_info = "3.5.0" +pasetors = { version = "0.6.4", features = ["v3", "paserk", "std", "serde"] } pathdiff = "0.2" percent-encoding = "2.0" rustfix = "0.6.0" diff --git a/src/cargo/ops/registry.rs b/src/cargo/ops/registry.rs index 25d06fc1d..c0e5943c4 100644 --- a/src/cargo/ops/registry.rs +++ b/src/cargo/ops/registry.rs @@ -13,6 +13,8 @@ use cargo_util::paths; use crates_io::{self, NewCrate, NewCrateDependency, Registry}; use curl::easy::{Easy, InfoType, SslOpt, SslVersion}; use log::{log, Level}; +use pasetors::keys::{AsymmetricKeyPair, Generate}; +use pasetors::paserk::FormatAsPaserk; use percent_encoding::{percent_encode, NON_ALPHANUMERIC}; use termcolor::Color::Green; use termcolor::ColorSpec; @@ -791,8 +793,10 @@ pub fn registry_login( let secret_key: String; if generate_keypair { assert!(!secret_key_required); - secret_key = "key".to_owned(); - // todo!("PASETO: generate a keypair") + let kp = AsymmetricKeyPair::::generate().unwrap(); + let mut key = String::new(); + FormatAsPaserk::fmt(&kp.secret, &mut key).unwrap(); + secret_key = key; } else if secret_key_required { assert!(!generate_keypair); drop_println!(config, "please paste the API secret key below"); @@ -809,7 +813,7 @@ pub fn registry_login( .ok_or_else(|| anyhow!("need a secret_key to set a key_subject"))?; } if !check_format_like_paserk_secret(&secret_key) { - panic!("not a validly formated PASERK secret key"); + bail!("not a validly formated PASERK secret key"); } new_token = RegistryCredentialConfig::AsymmetricKey(( secret_key, diff --git a/src/cargo/util/auth.rs b/src/cargo/util/auth.rs index a3f96d4b0..8e84446c1 100644 --- a/src/cargo/util/auth.rs +++ b/src/cargo/util/auth.rs @@ -4,6 +4,7 @@ use crate::util::{config, config::ConfigKey, CanonicalUrl, CargoResult, Config, use anyhow::{bail, format_err, Context as _}; use cargo_util::ProcessError; use core::fmt; +use pasetors::keys::AsymmetricSecretKey; use serde::Deserialize; use std::collections::HashMap; use std::error::Error; @@ -359,9 +360,9 @@ pub fn login(config: &Config, sid: &SourceId, token: RegistryCredentialConfig) - Ok(()) } -pub(crate) fn check_format_like_paserk_secret(_s: &str) -> bool { - // TODO: PASETO: check for valid PASERK secret format - true +pub(crate) fn check_format_like_paserk_secret(secret_key: &str) -> bool { + let key: Result, _> = secret_key.try_into(); + key.is_ok() } /// Removes the token for the given registry. diff --git a/tests/testsuite/registry.rs b/tests/testsuite/registry.rs index 1de19aa7a..7b3251501 100644 --- a/tests/testsuite/registry.rs +++ b/tests/testsuite/registry.rs @@ -1136,12 +1136,12 @@ fn login_with_asymmetric_token_and_subject_on_stdin() { .masquerade_as_nightly_cargo(&["registry-auth"]) .replace_crates_io(registry.index_url()) .with_stdout("please paste the API secret key below") - .with_stdin("some token") + .with_stdin("k3.secret.fNYVuMvBgOlljt9TDohnaYLblghqaHoQquVZwgR6X12cBFHZLFsaU3q7X3k1Zn36") .run(); let credentials = fs::read_to_string(&credentials).unwrap(); assert!(credentials.starts_with("[registry]\n")); assert!(credentials.contains("secret-key-subject = \"foo\"\n")); - assert!(credentials.contains("secret-key = \"some token\"\n")); + assert!(credentials.contains("secret-key = \"k3.secret.fNYVuMvBgOlljt9TDohnaYLblghqaHoQquVZwgR6X12cBFHZLFsaU3q7X3k1Zn36\"\n")); } #[cargo_test] @@ -1153,10 +1153,10 @@ fn login_with_asymmetric_token_on_stdin() { .masquerade_as_nightly_cargo(&["registry-auth"]) .replace_crates_io(registry.index_url()) .with_stdout("please paste the API secret key below") - .with_stdin("some token") + .with_stdin("k3.secret.fNYVuMvBgOlljt9TDohnaYLblghqaHoQquVZwgR6X12cBFHZLFsaU3q7X3k1Zn36") .run(); let credentials = fs::read_to_string(&credentials).unwrap(); - assert_eq!(credentials, "[registry]\nsecret-key = \"some token\"\n"); + assert_eq!(credentials, "[registry]\nsecret-key = \"k3.secret.fNYVuMvBgOlljt9TDohnaYLblghqaHoQquVZwgR6X12cBFHZLFsaU3q7X3k1Zn36\"\n"); } #[cargo_test] @@ -1170,6 +1170,38 @@ fn login_with_asymmetric_key_subject_without_key() { .with_stderr_contains("error: need a secret_key to set a key_subject") .with_status(101) .run(); + + // ok so ad a secret_key to the credentials + cargo_process("login --secret-key -v -Z registry-auth") + .masquerade_as_nightly_cargo(&["registry-auth"]) + .replace_crates_io(registry.index_url()) + .with_stdout("please paste the API secret key below") + .with_stdin("k3.secret.fNYVuMvBgOlljt9TDohnaYLblghqaHoQquVZwgR6X12cBFHZLFsaU3q7X3k1Zn36") + .run(); + + // and then it shuld work + cargo_process("login --key-subject=foo -Z registry-auth") + .masquerade_as_nightly_cargo(&["registry-auth"]) + .replace_crates_io(registry.index_url()) + .run(); + + let credentials = fs::read_to_string(&credentials).unwrap(); + assert!(credentials.starts_with("[registry]\n")); + assert!(credentials.contains("secret-key-subject = \"foo\"\n")); + assert!(credentials.contains("secret-key = \"k3.secret.fNYVuMvBgOlljt9TDohnaYLblghqaHoQquVZwgR6X12cBFHZLFsaU3q7X3k1Zn36\"\n")); +} + +#[cargo_test] +fn login_with_generate_asymmetric_token() { + let registry = registry::init(); + let credentials = paths::home().join(".cargo/credentials"); + fs::remove_file(&credentials).unwrap(); + cargo_process("login --generate-keypair -Z registry-auth") + .masquerade_as_nightly_cargo(&["registry-auth"]) + .replace_crates_io(registry.index_url()) + .run(); + let credentials = fs::read_to_string(&credentials).unwrap(); + assert!(credentials.contains("secret-key = \"k3.secret.")); } #[cargo_test]