summaryrefslogtreecommitdiffstats
path: root/src/tools/cargo/tests/testsuite/login.rs
diff options
context:
space:
mode:
Diffstat (limited to 'src/tools/cargo/tests/testsuite/login.rs')
-rw-r--r--src/tools/cargo/tests/testsuite/login.rs404
1 files changed, 404 insertions, 0 deletions
diff --git a/src/tools/cargo/tests/testsuite/login.rs b/src/tools/cargo/tests/testsuite/login.rs
new file mode 100644
index 000000000..85b299f28
--- /dev/null
+++ b/src/tools/cargo/tests/testsuite/login.rs
@@ -0,0 +1,404 @@
+//! Tests for the `cargo login` command.
+
+use cargo_test_support::cargo_process;
+use cargo_test_support::paths::{self, CargoPathExt};
+use cargo_test_support::registry::{self, RegistryBuilder};
+use cargo_test_support::t;
+use std::fs;
+use std::path::PathBuf;
+
+const TOKEN: &str = "test-token";
+const TOKEN2: &str = "test-token2";
+const ORIGINAL_TOKEN: &str = "api-token";
+
+fn credentials_toml() -> PathBuf {
+ paths::home().join(".cargo/credentials.toml")
+}
+
+fn setup_new_credentials() {
+ setup_new_credentials_at(credentials_toml());
+}
+
+fn setup_new_credentials_at(config: PathBuf) {
+ t!(fs::create_dir_all(config.parent().unwrap()));
+ t!(fs::write(
+ &config,
+ format!(r#"token = "{token}""#, token = ORIGINAL_TOKEN)
+ ));
+}
+
+/// Asserts whether or not the token is set to the given value for the given registry.
+pub fn check_token(expected_token: Option<&str>, registry: Option<&str>) {
+ let credentials = credentials_toml();
+ assert!(credentials.is_file());
+
+ let contents = fs::read_to_string(&credentials).unwrap();
+ let toml: toml::Table = contents.parse().unwrap();
+
+ let actual_token = match registry {
+ // A registry has been provided, so check that the token exists in a
+ // table for the registry.
+ Some(registry) => toml
+ .get("registries")
+ .and_then(|registries_table| registries_table.get(registry))
+ .and_then(|registry_table| match registry_table.get("token") {
+ Some(&toml::Value::String(ref token)) => Some(token.as_str().to_string()),
+ _ => None,
+ }),
+ // There is no registry provided, so check the global token instead.
+ None => toml
+ .get("registry")
+ .and_then(|registry_table| registry_table.get("token"))
+ .and_then(|v| match v {
+ toml::Value::String(ref token) => Some(token.as_str().to_string()),
+ _ => None,
+ }),
+ };
+
+ match (actual_token, expected_token) {
+ (None, None) => {}
+ (Some(actual), Some(expected)) => assert_eq!(actual, expected),
+ (None, Some(expected)) => {
+ panic!("expected `{registry:?}` to be `{expected}`, but was not set")
+ }
+ (Some(actual), None) => {
+ panic!("expected `{registry:?}` to be unset, but was set to `{actual}`")
+ }
+ }
+}
+
+#[cargo_test]
+fn registry_credentials() {
+ let _alternative = RegistryBuilder::new().alternative().build();
+ let _alternative2 = RegistryBuilder::new()
+ .alternative_named("alternative2")
+ .build();
+
+ setup_new_credentials();
+
+ let reg = "alternative";
+
+ cargo_process("login --registry").arg(reg).arg(TOKEN).run();
+
+ // Ensure that we have not updated the default token
+ check_token(Some(ORIGINAL_TOKEN), None);
+
+ // Also ensure that we get the new token for the registry
+ check_token(Some(TOKEN), Some(reg));
+
+ let reg2 = "alternative2";
+ cargo_process("login --registry")
+ .arg(reg2)
+ .arg(TOKEN2)
+ .run();
+
+ // Ensure not overwriting 1st alternate registry token with
+ // 2nd alternate registry token (see rust-lang/cargo#7701).
+ check_token(Some(ORIGINAL_TOKEN), None);
+ check_token(Some(TOKEN), Some(reg));
+ check_token(Some(TOKEN2), Some(reg2));
+}
+
+#[cargo_test]
+fn empty_login_token() {
+ let registry = RegistryBuilder::new()
+ .no_configure_registry()
+ .no_configure_token()
+ .build();
+ setup_new_credentials();
+
+ cargo_process("login")
+ .replace_crates_io(registry.index_url())
+ .with_stdout("please paste the token found on [..]/me below")
+ .with_stdin("\t\n")
+ .with_stderr(
+ "\
+[UPDATING] crates.io index
+[ERROR] please provide a non-empty token
+",
+ )
+ .with_status(101)
+ .run();
+
+ cargo_process("login")
+ .replace_crates_io(registry.index_url())
+ .arg("")
+ .with_stderr(
+ "\
+[ERROR] please provide a non-empty token
+",
+ )
+ .with_status(101)
+ .run();
+}
+
+#[cargo_test]
+fn invalid_login_token() {
+ let registry = RegistryBuilder::new()
+ .no_configure_registry()
+ .no_configure_token()
+ .build();
+ setup_new_credentials();
+
+ let check = |stdin: &str, stderr: &str, status: i32| {
+ cargo_process("login")
+ .replace_crates_io(registry.index_url())
+ .with_stdout("please paste the token found on [..]/me below")
+ .with_stdin(stdin)
+ .with_stderr(stderr)
+ .with_status(status)
+ .run();
+ };
+
+ let invalid = |stdin: &str| {
+ check(
+ stdin,
+ "[ERROR] token contains invalid characters.
+Only printable ISO-8859-1 characters are allowed as it is sent in a HTTPS header.",
+ 101,
+ )
+ };
+ let valid = |stdin: &str| check(stdin, "[LOGIN] token for `crates.io` saved", 0);
+
+ // Update config.json so that the rest of the tests don't need to care
+ // whether or not `Updating` is printed.
+ check(
+ "test",
+ "\
+[UPDATING] crates.io index
+[LOGIN] token for `crates.io` saved
+",
+ 0,
+ );
+
+ invalid("😄");
+ invalid("\u{0016}");
+ invalid("\u{0000}");
+ invalid("你好");
+ valid("foo\tbar");
+ valid("foo bar");
+ valid(
+ r##"!"#$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\]^_`abcdefghijklmnopqrstuvwxyz{|}~"##,
+ );
+}
+
+#[cargo_test]
+fn bad_asymmetric_token_args() {
+ // These cases are kept brief as the implementation is covered by clap, so this is only smoke testing that we have clap configured correctly.
+ cargo_process("login --key-subject=foo tok")
+ .with_stderr_contains(
+ "error: the argument '--key-subject <SUBJECT>' cannot be used with '[token]'",
+ )
+ .with_status(1)
+ .run();
+
+ cargo_process("login --generate-keypair tok")
+ .with_stderr_contains(
+ "error: the argument '--generate-keypair' cannot be used with '[token]'",
+ )
+ .with_status(1)
+ .run();
+
+ cargo_process("login --secret-key tok")
+ .with_stderr_contains("error: the argument '--secret-key' cannot be used with '[token]'")
+ .with_status(1)
+ .run();
+
+ cargo_process("login --generate-keypair --secret-key")
+ .with_stderr_contains(
+ "error: the argument '--generate-keypair' cannot be used with '--secret-key'",
+ )
+ .with_status(1)
+ .run();
+}
+
+#[cargo_test]
+fn asymmetric_requires_nightly() {
+ let registry = registry::init();
+ cargo_process("login --key-subject=foo")
+ .replace_crates_io(registry.index_url())
+ .with_status(101)
+ .with_stderr_contains("[ERROR] the `key-subject` flag is unstable, pass `-Z registry-auth` to enable it\n\
+ See https://github.com/rust-lang/cargo/issues/10519 for more information about the `key-subject` flag.")
+ .run();
+ cargo_process("login --generate-keypair")
+ .replace_crates_io(registry.index_url())
+ .with_status(101)
+ .with_stderr_contains("[ERROR] the `generate-keypair` flag is unstable, pass `-Z registry-auth` to enable it\n\
+ See https://github.com/rust-lang/cargo/issues/10519 for more information about the `generate-keypair` flag.")
+ .run();
+ cargo_process("login --secret-key")
+ .replace_crates_io(registry.index_url())
+ .with_status(101)
+ .with_stderr_contains("[ERROR] the `secret-key` flag is unstable, pass `-Z registry-auth` to enable it\n\
+ See https://github.com/rust-lang/cargo/issues/10519 for more information about the `secret-key` flag.")
+ .run();
+}
+
+#[cargo_test]
+fn login_with_no_cargo_dir() {
+ // Create a config in the root directory because `login` requires the
+ // index to be updated, and we don't want to hit crates.io.
+ let registry = registry::init();
+ fs::rename(paths::home().join(".cargo"), paths::root().join(".cargo")).unwrap();
+ paths::home().rm_rf();
+ cargo_process("login foo -v")
+ .replace_crates_io(registry.index_url())
+ .run();
+ let credentials = fs::read_to_string(credentials_toml()).unwrap();
+ assert_eq!(credentials, "[registry]\ntoken = \"foo\"\n");
+}
+
+#[cargo_test]
+fn login_with_differently_sized_token() {
+ // Verify that the configuration file gets properly truncated.
+ let registry = registry::init();
+ let credentials = credentials_toml();
+ fs::remove_file(&credentials).unwrap();
+ cargo_process("login lmaolmaolmao -v")
+ .replace_crates_io(registry.index_url())
+ .run();
+ cargo_process("login lmao -v")
+ .replace_crates_io(registry.index_url())
+ .run();
+ cargo_process("login lmaolmaolmao -v")
+ .replace_crates_io(registry.index_url())
+ .run();
+ let credentials = fs::read_to_string(&credentials).unwrap();
+ assert_eq!(credentials, "[registry]\ntoken = \"lmaolmaolmao\"\n");
+}
+
+#[cargo_test]
+fn login_with_token_on_stdin() {
+ let registry = registry::init();
+ let credentials = credentials_toml();
+ fs::remove_file(&credentials).unwrap();
+ cargo_process("login lmao -v")
+ .replace_crates_io(registry.index_url())
+ .run();
+ cargo_process("login")
+ .replace_crates_io(registry.index_url())
+ .with_stdout("please paste the token found on [..]/me below")
+ .with_stdin("some token")
+ .run();
+ let credentials = fs::read_to_string(&credentials).unwrap();
+ assert_eq!(credentials, "[registry]\ntoken = \"some token\"\n");
+}
+
+#[cargo_test]
+fn login_with_asymmetric_token_and_subject_on_stdin() {
+ let registry = registry::init();
+ let credentials = credentials_toml();
+ fs::remove_file(&credentials).unwrap();
+ cargo_process("login --key-subject=foo --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
+k3.public.AmDwjlyf8jAV3gm5Z7Kz9xAOcsKslt_Vwp5v-emjFzBHLCtcANzTaVEghTNEMj9PkQ",
+ )
+ .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 = \"k3.secret.fNYVuMvBgOlljt9TDohnaYLblghqaHoQquVZwgR6X12cBFHZLFsaU3q7X3k1Zn36\"\n"));
+}
+
+#[cargo_test]
+fn login_with_asymmetric_token_on_stdin() {
+ let registry = registry::init();
+ let credentials = credentials_toml();
+ fs::remove_file(&credentials).unwrap();
+ 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
+k3.public.AmDwjlyf8jAV3gm5Z7Kz9xAOcsKslt_Vwp5v-emjFzBHLCtcANzTaVEghTNEMj9PkQ",
+ )
+ .with_stdin("k3.secret.fNYVuMvBgOlljt9TDohnaYLblghqaHoQquVZwgR6X12cBFHZLFsaU3q7X3k1Zn36")
+ .run();
+ let credentials = fs::read_to_string(&credentials).unwrap();
+ assert_eq!(credentials, "[registry]\nsecret-key = \"k3.secret.fNYVuMvBgOlljt9TDohnaYLblghqaHoQquVZwgR6X12cBFHZLFsaU3q7X3k1Zn36\"\n");
+}
+
+#[cargo_test]
+fn login_with_asymmetric_key_subject_without_key() {
+ let registry = registry::init();
+ let credentials = credentials_toml();
+ fs::remove_file(&credentials).unwrap();
+ cargo_process("login --key-subject=foo -Z registry-auth")
+ .masquerade_as_nightly_cargo(&["registry-auth"])
+ .replace_crates_io(registry.index_url())
+ .with_stderr_contains("error: need a secret_key to set a key_subject")
+ .with_status(101)
+ .run();
+
+ // ok so add 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
+k3.public.AmDwjlyf8jAV3gm5Z7Kz9xAOcsKslt_Vwp5v-emjFzBHLCtcANzTaVEghTNEMj9PkQ",
+ )
+ .with_stdin("k3.secret.fNYVuMvBgOlljt9TDohnaYLblghqaHoQquVZwgR6X12cBFHZLFsaU3q7X3k1Zn36")
+ .run();
+
+ // and then it should 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 = credentials_toml();
+ 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())
+ .with_stdout("k3.public.[..]")
+ .run();
+ let credentials = fs::read_to_string(&credentials).unwrap();
+ assert!(credentials.contains("secret-key = \"k3.secret."));
+}
+
+#[cargo_test]
+fn default_registry_configured() {
+ // When registry.default is set, login should use that one when
+ // --registry is not used.
+ let _alternative = RegistryBuilder::new().alternative().build();
+ let cargo_home = paths::home().join(".cargo");
+ cargo_util::paths::append(
+ &cargo_home.join("config"),
+ br#"
+ [registry]
+ default = "alternative"
+ "#,
+ )
+ .unwrap();
+
+ cargo_process("login")
+ .arg("a-new-token")
+ .with_stderr(
+ "\
+[UPDATING] `alternative` index
+[LOGIN] token for `alternative` saved
+",
+ )
+ .run();
+
+ check_token(None, None);
+ check_token(Some("a-new-token"), Some("alternative"));
+}