Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Credentials for multiple hosts. #4206

Closed
wants to merge 1 commit into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
23 changes: 13 additions & 10 deletions src/bin/login.rs
Original file line number Diff line number Diff line change
Expand Up @@ -40,26 +40,29 @@ pub fn execute(options: Options, config: &Config) -> CliResult {
&options.flag_color,
options.flag_frozen,
options.flag_locked)?;
let token = match options.arg_token.clone() {
let token = match options.arg_token {
Some(token) => token,
None => {
let src = SourceId::crates_io(config)?;
let mut src = RegistrySource::remote(&src, config);
src.update()?;
let config = src.config()?.unwrap();
let host = options.flag_host.clone().unwrap_or(config.api);
let host = match options.flag_host {
Some(ref host) => host.clone(),
None => {
let src = SourceId::crates_io(config)?;
let mut src = RegistrySource::remote(&src, config);
src.update()?;
src.config()?.unwrap().api
}
};

println!("please visit {}me and paste the API Token below", host);
let mut line = String::new();
let input = io::stdin();
input.lock().read_line(&mut line).chain_err(|| {
"failed to read stdin"
})?;
line
line.trim().to_string()
}
};

let token = token.trim().to_string();
ops::registry_login(config, token)?;
ops::registry_login(config, token, options.flag_host)?;
Ok(())
}

2 changes: 1 addition & 1 deletion src/cargo/core/source.rs
Original file line number Diff line number Diff line change
Expand Up @@ -206,7 +206,7 @@ impl SourceId {
/// This is the main cargo registry by default, but it can be overridden in
/// a `.cargo/config`.
pub fn crates_io(config: &Config) -> CargoResult<SourceId> {
let cfg = ops::registry_configuration(config)?;
let cfg = ops::registry_configuration(config, None)?;
let url = if let Some(ref index) = cfg.index {
static WARNED: AtomicBool = ATOMIC_BOOL_INIT;
if !WARNED.swap(true, SeqCst) {
Expand Down
38 changes: 29 additions & 9 deletions src/cargo/ops/registry.rs
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ use core::dependency::Kind;
use core::manifest::ManifestMetadata;
use ops;
use sources::{RegistrySource};
use util::config::{self, Config};
use util::config::{self, Config, Value, Definition};
use util::paths;
use util::ToUrl;
use util::errors::{CargoError, CargoResult, CargoResultExt};
Expand Down Expand Up @@ -176,10 +176,24 @@ fn transmit(config: &Config,
}
}

pub fn registry_configuration(config: &Config) -> CargoResult<RegistryConfig> {
let index = config.get_string("registry.index")?.map(|p| p.val);
let token = config.get_string("registry.token")?.map(|p| p.val);
Ok(RegistryConfig { index: index, token: token })
pub fn registry_configuration(config: &Config,
host: Option<String>) -> CargoResult<RegistryConfig> {
let (index, token) = match host {
Some(host) => {
(Some(Value { val: host.clone(), definition: Definition::Environment }),
config.get_string(&format!("registry.{}.token", host))?)
}
None => {
// Checking out for default index and token
(config.get_string("registry.index")?,
config.get_string("registry.token")?)
}
};

Ok(RegistryConfig {
index: index.map(|p| p.val),
token: token.map(|p| p.val)
})
}

pub fn registry(config: &Config,
Expand All @@ -189,7 +203,7 @@ pub fn registry(config: &Config,
let RegistryConfig {
token: token_config,
index: _index_config,
} = registry_configuration(config)?;
} = registry_configuration(config, index.clone())?;
let token = token.or(token_config);
let sid = match index {
Some(index) => SourceId::for_registry(&index.to_url()?),
Expand Down Expand Up @@ -280,15 +294,21 @@ pub fn http_timeout(config: &Config) -> CargoResult<Option<i64>> {
Ok(env::var("HTTP_TIMEOUT").ok().and_then(|s| s.parse().ok()))
}

pub fn registry_login(config: &Config, token: String) -> CargoResult<()> {
let RegistryConfig { index: _, token: old_token } = registry_configuration(config)?;
pub fn registry_login(config: &Config,
token: String,
host: Option<String>) -> CargoResult<()> {
let RegistryConfig {
index: _,
token: old_token
} = registry_configuration(config, host.clone())?;

if let Some(old_token) = old_token {
if old_token == token {
return Ok(());
}
}

config::save_credentials(config, token)
config::save_credentials(config, token, host)
}

pub struct OwnersOptions {
Expand Down
25 changes: 19 additions & 6 deletions src/cargo/util/config.rs
Original file line number Diff line number Diff line change
Expand Up @@ -835,23 +835,36 @@ fn walk_tree<F>(pwd: &Path, mut walk: F) -> CargoResult<()>
}

pub fn save_credentials(cfg: &Config,
token: String) -> CargoResult<()> {
token: String,
host: Option<String>) -> CargoResult<()> {
let mut file = {
cfg.home_path.create_dir()?;
cfg.home_path.open_rw(Path::new("credentials"), cfg,
"credentials' config file")?
"credentials' config file")?
};

let (key, value) = {
let key = "token".to_string();
let value = ConfigValue::String(token, file.path().to_path_buf());

if let Some(host) = host {
let mut map = HashMap::new();
map.insert(key, value);
(host, CV::Table(map, file.path().to_path_buf()))
} else {
(key, value)
}
};

let mut contents = String::new();
file.read_to_string(&mut contents).chain_err(|| {
format!("failed to read configuration file `{}`",
file.path().display())
format!("failed to read configuration file `{}`", file.path().display())
})?;

let mut toml = cargo_toml::parse(&contents, file.path(), cfg)?;
toml.as_table_mut()
.unwrap()
.insert("token".to_string(),
ConfigValue::String(token, file.path().to_path_buf()).into_toml());
.insert(key, value.into_toml());

let contents = toml.to_string();
file.seek(SeekFrom::Start(0))?;
Expand Down
53 changes: 40 additions & 13 deletions tests/login.rs
Original file line number Diff line number Diff line change
Expand Up @@ -30,20 +30,35 @@ fn setup_old_credentials() {
fn setup_new_credentials() {
let config = cargo_home().join("credentials");
t!(fs::create_dir_all(config.parent().unwrap()));
t!(t!(File::create(&config)).write_all(br#"
t!(t!(File::create(&config)).write_all(format!(r#"
token = "api-token"
"#));

["{registry}"]
token = "api-token"
"#, registry = registry().to_string())
.as_bytes()));
}

fn check_host_token(toml: toml::Value) -> bool {
fn check_host_token(mut toml: toml::Value, host_key: &str) -> bool {
for &key in [host_key, "token"].into_iter() {
if key.is_empty() {
continue
}

match toml {
toml::Value::Table(table) => {
if let Some(v) = table.get(key) {
toml = v.clone();
} else {
return false;
}
}
_ => break,
}
}

match toml {
toml::Value::Table(table) => match table.get("token") {
Some(v) => match v {
&toml::Value::String(ref token) => (token.as_str() == TOKEN),
_ => false,
},
None => false,
},
toml::Value::String(token) => (&token == TOKEN),
_ => false,
}
}
Expand All @@ -68,7 +83,7 @@ fn login_with_old_credentials() {

contents.clear();
File::open(&credentials).unwrap().read_to_string(&mut contents).unwrap();
assert!(check_host_token(contents.parse().unwrap()));
assert!(check_host_token(contents.parse().unwrap(), &registry().to_string()));
}

#[test]
Expand All @@ -87,7 +102,7 @@ fn login_with_new_credentials() {

let mut contents = String::new();
File::open(&credentials).unwrap().read_to_string(&mut contents).unwrap();
assert!(check_host_token(contents.parse().unwrap()));
assert!(check_host_token(contents.parse().unwrap(), &registry().to_string()));
}

#[test]
Expand All @@ -101,6 +116,8 @@ fn login_without_credentials() {
assert_that(cargo_process().arg("login")
.arg("--host").arg(registry().to_string()).arg(TOKEN),
execs().with_status(0));
assert_that(cargo_process().arg("login").arg(TOKEN),
execs().with_status(0));

let config = cargo_home().join("config");
assert_that(&config, is_not(existing_file()));
Expand All @@ -110,19 +127,29 @@ fn login_without_credentials() {

let mut contents = String::new();
File::open(&credentials).unwrap().read_to_string(&mut contents).unwrap();
assert!(check_host_token(contents.parse().unwrap()));
let toml: toml::Value = contents.parse().unwrap();
assert!(check_host_token(toml.clone(), &registry().to_string()));
assert!(check_host_token(toml, ""));
}

#[test]
fn new_credentials_is_used_instead_old() {
setup_old_credentials();
setup_new_credentials();

assert_that(cargo_process().arg("login").arg(TOKEN),
execs().with_status(0));

assert_that(cargo_process().arg("login")
.arg("--host").arg(registry().to_string()).arg(TOKEN),
execs().with_status(0));

let config = Config::new(Shell::new(), cargo_home(), cargo_home());

let token = config.get_string("registry.token").unwrap().map(|p| p.val);
assert!(token.unwrap() == TOKEN);

let token_host = config.get_string(&format!(r#"registry.{}.token"#, registry().to_string()))
.unwrap().map(|p| p.val);
assert!(token_host.unwrap() == TOKEN);
}
12 changes: 10 additions & 2 deletions tests/publish.rs
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ use std::path::PathBuf;
use cargotest::support::git::repo;
use cargotest::support::paths;
use cargotest::support::{project, execs};
use cargotest::install::cargo_home;
use flate2::read::GzDecoder;
use hamcrest::assert_that;
use tar::Archive;
Expand All @@ -24,14 +25,21 @@ fn upload_path() -> PathBuf { paths::root().join("upload") }
fn upload() -> Url { Url::from_file_path(&*upload_path()).ok().unwrap() }

fn setup() {
let config = paths::root().join(".cargo/config");
let config = cargo_home().join("config");
t!(fs::create_dir_all(config.parent().unwrap()));
t!(t!(File::create(&config)).write_all(br#"
[registry]
token = "api-token"
token = "api-token"
"#));
t!(fs::create_dir_all(&upload_path().join("api/v1/crates")));

let credentials = cargo_home().join("credentials");
t!(t!(File::create(&credentials)).write_all(format!(r#"
["{registry}"]
token = "api-token"
"#, registry = registry().to_string())
.as_bytes()));

repo(&registry_path())
.file("config.json", &format!(r#"{{
"dl": "{0}",
Expand Down