Skip to content

Commit

Permalink
login/out
Browse files Browse the repository at this point in the history
  • Loading branch information
Eh2406 committed Dec 12, 2022
1 parent d8df142 commit a917fa0
Show file tree
Hide file tree
Showing 3 changed files with 134 additions and 55 deletions.
114 changes: 78 additions & 36 deletions src/cargo/ops/registry.rs
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ use std::task::Poll;
use std::time::Duration;
use std::{cmp, env};

use anyhow::{bail, format_err, Context as _};
use anyhow::{anyhow, bail, format_err, Context as _};
use cargo_util::paths;
use crates_io::{self, NewCrate, NewCrateDependency, Registry};
use curl::easy::{Easy, InfoType, SslOpt, SslVersion};
Expand All @@ -27,7 +27,9 @@ use crate::core::{Package, SourceId, Workspace};
use crate::ops;
use crate::ops::Packages;
use crate::sources::{RegistrySource, SourceConfigMap, CRATES_IO_DOMAIN, CRATES_IO_REGISTRY};
use crate::util::auth::{self, AuthorizationError};
use crate::util::auth::{
check_format_like_paserk_secret, {self, AuthorizationError},
};
use crate::util::config::{Config, SslVersionConfig, SslVersionConfigRange};
use crate::util::errors::CargoResult;
use crate::util::important_paths::find_root_manifest_for_wd;
Expand All @@ -37,7 +39,7 @@ use crate::{drop_print, drop_println, version};
/// Registry settings loaded from config files.
///
/// This is loaded based on the `--registry` flag and the config settings.
#[derive(Debug)]
#[derive(Debug, PartialEq)]
pub enum RegistryCredentialConfig {
None,
/// The authentication token.
Expand Down Expand Up @@ -758,7 +760,7 @@ pub fn registry_login(
token: Option<&str>,
reg: Option<&str>,
generate_keypair: bool,
secret_key: bool,
secret_key_required: bool,
key_subject: Option<&str>,
) -> CargoResult<()> {
let source_ids = get_source_id(config, None, reg)?;
Expand All @@ -773,51 +775,91 @@ pub fn registry_login(
.map(|u| u.to_string()),
Err(e) => return Err(e),
};

assert!(!generate_keypair);
assert!(!secret_key);
assert!(key_subject.is_none());
let token = match token {
Some(token) => token.to_string(),
None => {
if let Some(login_url) = login_url {
drop_println!(
config,
"please paste the token found on {} below",
login_url
)
} else {
drop_println!(
config,
"please paste the token for {} below",
source_ids.original.display_registry_name()
)
let new_token;
if generate_keypair || secret_key_required || key_subject.is_some() {
if !config.cli_unstable().registry_auth {
panic!("-registry_auth required.");
}
assert!(token.is_none());
// we are dealing with asymmetric tokens
let (old_secret_key, old_key_subject) = match &reg_cfg {
RegistryCredentialConfig::AsymmetricKey((old_secret_key, old_key_subject)) => {
(Some(old_secret_key), old_key_subject.clone())
}

_ => (None, None),
};
let secret_key: String;
if generate_keypair {
assert!(!secret_key_required);
secret_key = "key".to_owned();
// todo!("PASETO: generate a keypair")
} else if secret_key_required {
assert!(!generate_keypair);
drop_println!(config, "please paste the API secret key below");
let mut line = String::new();
let input = io::stdin();
input
.lock()
.read_line(&mut line)
.with_context(|| "failed to read stdin")?;
// Automatically remove `cargo login` from an inputted token to
// allow direct pastes from `registry.host()`/me.
line.replace("cargo login", "").trim().to_string()
secret_key = line.trim().to_string();
} else {
secret_key = old_secret_key
.cloned()
.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");
}
new_token = RegistryCredentialConfig::AsymmetricKey((
secret_key,
match key_subject {
Some(key_subject) => Some(key_subject.to_string()),
None => old_key_subject,
},
));
} else {
new_token = RegistryCredentialConfig::Token(match token {
Some(token) => token.to_string(),
None => {
if let Some(login_url) = login_url {
drop_println!(
config,
"please paste the token found on {} below",
login_url
)
} else {
drop_println!(
config,
"please paste the token for {} below",
source_ids.original.display_registry_name()
)
}

if token.is_empty() {
bail!("please provide a non-empty token");
}
let mut line = String::new();
let input = io::stdin();
input
.lock()
.read_line(&mut line)
.with_context(|| "failed to read stdin")?;
// Automatically remove `cargo login` from an inputted token to
// allow direct pastes from `registry.host()`/me.
line.replace("cargo login", "").trim().to_string()
}
});

if let RegistryCredentialConfig::Token(old_token) = &reg_cfg {
if old_token == &token {
config.shell().status("Login", "already logged in")?;
return Ok(());
if let Some(tok) = new_token.as_token() {
if tok.is_empty() {
bail!("please provide a non-empty token");
}
}
}
if &reg_cfg == &new_token {
config.shell().status("Login", "already logged in")?;
return Ok(());
}

auth::login(config, &source_ids.original, token)?;
auth::login(config, &source_ids.original, new_token)?;

config.shell().status(
"Login",
Expand Down
13 changes: 11 additions & 2 deletions src/cargo/util/auth.rs
Original file line number Diff line number Diff line change
Expand Up @@ -328,7 +328,7 @@ fn auth_token_optional(config: &Config, sid: &SourceId) -> CargoResult<Option<St
run_command(config, &process, sid, Action::Get)?.unwrap()
}
RegistryCredentialConfig::AsymmetricKey((_secret_key, _secret_key_subject)) => {
todo!("sign the token")
todo!("PASETO: sign a read token")
}
};

Expand All @@ -343,9 +343,13 @@ enum Action {
}

/// Saves the given token.
pub fn login(config: &Config, sid: &SourceId, token: String) -> CargoResult<()> {
pub fn login(config: &Config, sid: &SourceId, token: RegistryCredentialConfig) -> CargoResult<()> {
match registry_credential_config(config, sid)? {
RegistryCredentialConfig::Process(process) => {
let token = token
.as_token()
.expect("credential_process can not use login with a secret_key")
.to_owned();
run_command(config, &process, sid, Action::Store(token))?;
}
_ => {
Expand All @@ -355,6 +359,11 @@ pub fn login(config: &Config, sid: &SourceId, token: String) -> CargoResult<()>
Ok(())
}

pub(crate) fn check_format_like_paserk_secret(_s: &str) -> bool {
// TODO: PASETO: check for valid PASERK secret format
true
}

/// Removes the token for the given registry.
pub fn logout(config: &Config, sid: &SourceId) -> CargoResult<()> {
match registry_credential_config(config, sid)? {
Expand Down
62 changes: 45 additions & 17 deletions src/cargo/util/config/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -69,7 +69,7 @@ use self::ConfigValue as CV;
use crate::core::compiler::rustdoc::RustdocExternMap;
use crate::core::shell::Verbosity;
use crate::core::{features, CliUnstable, Shell, SourceId, Workspace, WorkspaceRootConfig};
use crate::ops;
use crate::ops::{self, RegistryCredentialConfig};
use crate::util::errors::CargoResult;
use crate::util::validate_package_name;
use crate::util::CanonicalUrl;
Expand Down Expand Up @@ -2101,7 +2101,7 @@ pub fn homedir(cwd: &Path) -> Option<PathBuf> {

pub fn save_credentials(
cfg: &Config,
token: Option<String>,
token: Option<RegistryCredentialConfig>,
registry: &SourceId,
) -> CargoResult<()> {
let registry = if registry.is_crates_io() {
Expand Down Expand Up @@ -2151,26 +2151,50 @@ pub fn save_credentials(

if let Some(token) = token {
// login
let (key, mut value) = {
let key = "token".to_string();
let value = ConfigValue::String(token, Definition::Path(file.path().to_path_buf()));
let map = HashMap::from([(key, value)]);
let table = CV::Table(map, Definition::Path(file.path().to_path_buf()));

if let Some(registry) = registry {
let map = HashMap::from([(registry.to_string(), table)]);
(
"registries".into(),
CV::Table(map, Definition::Path(file.path().to_path_buf())),
)
} else {
("registry".into(), table)

let path_def = Definition::Path(file.path().to_path_buf());
let (key, mut value) = match token {
RegistryCredentialConfig::Token(token) => {
// login with token

let key = "token".to_string();
let value = ConfigValue::String(token, path_def.clone());
let map = HashMap::from([(key, value)]);
let table = CV::Table(map, path_def.clone());

if let Some(registry) = registry {
let map = HashMap::from([(registry.to_string(), table)]);
("registries".into(), CV::Table(map, path_def.clone()))
} else {
("registry".into(), table)
}
}
RegistryCredentialConfig::AsymmetricKey((secret_key, key_subject)) => {
// login with key

let key = "secret-key".to_string();
let value = ConfigValue::String(secret_key, path_def.clone());
let mut map = HashMap::from([(key, value)]);
if let Some(key_subject) = key_subject {
let key = "secret-key-subject".to_string();
let value = ConfigValue::String(key_subject, path_def.clone());
map.insert(key, value);
}
let table = CV::Table(map, path_def.clone());

if let Some(registry) = registry {
let map = HashMap::from([(registry.to_string(), table)]);
("registries".into(), CV::Table(map, path_def.clone()))
} else {
("registry".into(), table)
}
}
_ => unreachable!(),
};

if registry.is_some() {
if let Some(table) = toml.as_table_mut().unwrap().remove("registries") {
let v = CV::from_toml(Definition::Path(file.path().to_path_buf()), table)?;
let v = CV::from_toml(path_def, table)?;
value.merge(v, false)?;
}
}
Expand All @@ -2185,13 +2209,17 @@ pub fn save_credentials(
format_err!("expected `[registries.{}]` to be a table", registry)
})?;
rtable.remove("token");
rtable.remove("secret-key");
rtable.remove("secret-key-subject");
}
}
} else if let Some(registry) = table.get_mut("registry") {
let reg_table = registry
.as_table_mut()
.ok_or_else(|| format_err!("expected `[registry]` to be a table"))?;
reg_table.remove("token");
reg_table.remove("secret-key");
reg_table.remove("secret-key-subject");
}
}

Expand Down

0 comments on commit a917fa0

Please sign in to comment.