Skip to content

Commit 9d84c0c

Browse files
committed
Auto merge of #7973 - ehuss:index-updates, r=alexcrichton
Several updates to token/index handling. This attempts to tighten up the usage of token/index handling, to prevent accidental leakage of the crates.io token. * Make `registry.index` config a hard error. This was deprecated 4 years ago in #2857, and removing it helps simplify things. * Don't allow both `--index` and `--registry` to be specified at the same time. Otherwise `--index` was being silently ignored. * `registry.token` is not allowed to be used with the `--index` flag. The intent here is to avoid possibly leaking a crates.io token to another host. * Added a warning if source replacement is used and the token is loaded from `registry.token`. Closes #6545
2 parents c374809 + 65274ea commit 9d84c0c

File tree

14 files changed

+293
-201
lines changed

14 files changed

+293
-201
lines changed

Cargo.toml

+1-1
Original file line numberDiff line numberDiff line change
@@ -22,7 +22,7 @@ path = "src/cargo/lib.rs"
2222
atty = "0.2"
2323
bytesize = "1.0"
2424
cargo-platform = { path = "crates/cargo-platform", version = "0.1.1" }
25-
crates-io = { path = "crates/crates-io", version = "0.31" }
25+
crates-io = { path = "crates/crates-io", version = "0.31.1" }
2626
crossbeam-utils = "0.7"
2727
crypto-hash = "0.3.1"
2828
curl = { version = "0.4.23", features = ["http2"] }

crates/crates-io/Cargo.toml

+1-1
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
[package]
22
name = "crates-io"
3-
version = "0.31.0"
3+
version = "0.31.1"
44
edition = "2018"
55
authors = ["Alex Crichton <[email protected]>"]
66
license = "MIT OR Apache-2.0"

crates/crates-io/lib.rs

+8-3
Original file line numberDiff line numberDiff line change
@@ -139,9 +139,7 @@ impl Registry {
139139
}
140140

141141
pub fn host_is_crates_io(&self) -> bool {
142-
Url::parse(self.host())
143-
.map(|u| u.host_str() == Some("crates.io"))
144-
.unwrap_or(false)
142+
is_url_crates_io(&self.host)
145143
}
146144

147145
pub fn add_owners(&mut self, krate: &str, owners: &[&str]) -> Result<String> {
@@ -420,3 +418,10 @@ fn reason(code: u32) -> &'static str {
420418
_ => "<unknown>",
421419
}
422420
}
421+
422+
/// Returns `true` if the host of the given URL is "crates.io".
423+
pub fn is_url_crates_io(url: &str) -> bool {
424+
Url::parse(url)
425+
.map(|u| u.host_str() == Some("crates.io"))
426+
.unwrap_or(false)
427+
}

src/cargo/core/source/source_id.rs

+2-19
Original file line numberDiff line numberDiff line change
@@ -4,8 +4,6 @@ use std::fmt::{self, Formatter};
44
use std::hash::{self, Hash};
55
use std::path::Path;
66
use std::ptr;
7-
use std::sync::atomic::AtomicBool;
8-
use std::sync::atomic::Ordering::SeqCst;
97
use std::sync::Mutex;
108

119
use log::trace;
@@ -14,7 +12,6 @@ use serde::ser;
1412
use url::Url;
1513

1614
use crate::core::PackageId;
17-
use crate::ops;
1815
use crate::sources::DirectorySource;
1916
use crate::sources::{GitSource, PathSource, RegistrySource, CRATES_IO_INDEX};
2017
use crate::util::{CanonicalUrl, CargoResult, Config, IntoUrl};
@@ -189,22 +186,8 @@ impl SourceId {
189186
/// a `.cargo/config`.
190187
pub fn crates_io(config: &Config) -> CargoResult<SourceId> {
191188
config.crates_io_source_id(|| {
192-
let cfg = ops::registry_configuration(config, None)?;
193-
let url = if let Some(ref index) = cfg.index {
194-
static WARNED: AtomicBool = AtomicBool::new(false);
195-
if !WARNED.swap(true, SeqCst) {
196-
config.shell().warn(
197-
"custom registry support via \
198-
the `registry.index` configuration is \
199-
being removed, this functionality \
200-
will not work in the future",
201-
)?;
202-
}
203-
&index[..]
204-
} else {
205-
CRATES_IO_INDEX
206-
};
207-
let url = url.into_url()?;
189+
config.check_registry_index_not_set()?;
190+
let url = CRATES_IO_INDEX.into_url().unwrap();
208191
SourceId::for_registry(&url)
209192
})
210193
}

src/cargo/ops/registry.rs

+81-15
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@ use std::time::Duration;
77
use std::{cmp, env};
88

99
use anyhow::{bail, format_err};
10-
use crates_io::{NewCrate, NewCrateDependency, Registry};
10+
use crates_io::{self, NewCrate, NewCrateDependency, Registry};
1111
use curl::easy::{Easy, InfoType, SslOpt, SslVersion};
1212
use log::{log, Level};
1313
use percent_encoding::{percent_encode, NON_ALPHANUMERIC};
@@ -25,8 +25,13 @@ use crate::util::IntoUrl;
2525
use crate::util::{paths, validate_package_name};
2626
use crate::version;
2727

28+
/// Registry settings loaded from config files.
29+
///
30+
/// This is loaded based on the `--registry` flag and the config settings.
2831
pub struct RegistryConfig {
32+
/// The index URL. If `None`, use crates.io.
2933
pub index: Option<String>,
34+
/// The authentication token.
3035
pub token: Option<String>,
3136
}
3237

@@ -316,10 +321,15 @@ fn transmit(
316321
}
317322
}
318323

324+
/// Returns the index and token from the config file for the given registry.
325+
///
326+
/// `registry` is typically the registry specified on the command-line. If
327+
/// `None`, `index` is set to `None` to indicate it should use crates.io.
319328
pub fn registry_configuration(
320329
config: &Config,
321330
registry: Option<String>,
322331
) -> CargoResult<RegistryConfig> {
332+
// `registry.default` is handled in command-line parsing.
323333
let (index, token) = match registry {
324334
Some(registry) => {
325335
validate_package_name(&registry, "registry name", "")?;
@@ -331,19 +341,26 @@ pub fn registry_configuration(
331341
)
332342
}
333343
None => {
334-
// Checking for default index and token
335-
(
336-
config
337-
.get_default_registry_index()?
338-
.map(|url| url.to_string()),
339-
config.get_string("registry.token")?.map(|p| p.val),
340-
)
344+
// Use crates.io default.
345+
config.check_registry_index_not_set()?;
346+
(None, config.get_string("registry.token")?.map(|p| p.val))
341347
}
342348
};
343349

344350
Ok(RegistryConfig { index, token })
345351
}
346352

353+
/// Returns the `Registry` and `Source` based on command-line and config settings.
354+
///
355+
/// * `token`: The token from the command-line. If not set, uses the token
356+
/// from the config.
357+
/// * `index`: The index URL from the command-line. This is ignored if
358+
/// `registry` is set.
359+
/// * `registry`: The registry name from the command-line. If neither
360+
/// `registry`, or `index` are set, then uses `crates-io`, honoring
361+
/// `[source]` replacement if defined.
362+
/// * `force_update`: If `true`, forces the index to be updated.
363+
/// * `validate_token`: If `true`, the token must be set.
347364
fn registry(
348365
config: &Config,
349366
token: Option<String>,
@@ -352,13 +369,17 @@ fn registry(
352369
force_update: bool,
353370
validate_token: bool,
354371
) -> CargoResult<(Registry, SourceId)> {
372+
if index.is_some() && registry.is_some() {
373+
// Otherwise we would silently ignore one or the other.
374+
bail!("both `--index` and `--registry` should not be set at the same time");
375+
}
355376
// Parse all configuration options
356377
let RegistryConfig {
357378
token: token_config,
358379
index: index_config,
359380
} = registry_configuration(config, registry.clone())?;
360-
let token = token.or(token_config);
361-
let sid = get_source_id(config, index_config.or(index), registry)?;
381+
let opt_index = index_config.as_ref().or(index.as_ref());
382+
let sid = get_source_id(config, opt_index, registry.as_ref())?;
362383
if !sid.is_remote_registry() {
363384
bail!(
364385
"{} does not support API commands.\n\
@@ -386,10 +407,51 @@ fn registry(
386407
cfg.and_then(|cfg| cfg.api)
387408
.ok_or_else(|| format_err!("{} does not support API commands", sid))?
388409
};
389-
let handle = http_handle(config)?;
390-
if validate_token && token.is_none() {
391-
bail!("no upload token found, please run `cargo login`");
410+
let token = match (&index, &token, &token_config) {
411+
// No token.
412+
(None, None, None) => {
413+
if validate_token {
414+
bail!("no upload token found, please run `cargo login` or pass `--token`");
415+
}
416+
None
417+
}
418+
// Token on command-line.
419+
(_, Some(_), _) => token,
420+
// Token in config, no --index, loading from config is OK for crates.io.
421+
(None, None, Some(_)) => {
422+
// Check `is_default_registry` so that the crates.io index can
423+
// change config.json's "api" value, and this won't affect most
424+
// people. It will affect those using source replacement, but
425+
// hopefully that's a relatively small set of users.
426+
if registry.is_none()
427+
&& !sid.is_default_registry()
428+
&& !crates_io::is_url_crates_io(&api_host)
429+
{
430+
if validate_token {
431+
config.shell().warn(
432+
"using `registry.token` config value with source \
433+
replacement is deprecated\n\
434+
This may become a hard error in the future; \
435+
see <https://github.com/rust-lang/cargo/issues/xxx>.\n\
436+
Use the --token command-line flag to remove this warning.",
437+
)?;
438+
token_config
439+
} else {
440+
None
441+
}
442+
} else {
443+
token_config
444+
}
445+
}
446+
// --index, no --token
447+
(Some(_), None, _) => {
448+
if validate_token {
449+
bail!("command-line argument --index requires --token to be specified")
450+
}
451+
None
452+
}
392453
};
454+
let handle = http_handle(config)?;
393455
Ok((Registry::new_handle(api_host, token, handle), sid))
394456
}
395457

@@ -739,10 +801,14 @@ pub fn yank(
739801
Ok(())
740802
}
741803

804+
/// Gets the SourceId for an index or registry setting.
805+
///
806+
/// The `index` and `reg` values are from the command-line or config settings.
807+
/// If both are None, returns the source for crates.io.
742808
fn get_source_id(
743809
config: &Config,
744-
index: Option<String>,
745-
reg: Option<String>,
810+
index: Option<&String>,
811+
reg: Option<&String>,
746812
) -> CargoResult<SourceId> {
747813
match (reg, index) {
748814
(Some(r), _) => SourceId::alt_registry(config, &r),

src/cargo/util/config/mod.rs

+9-6
Original file line numberDiff line numberDiff line change
@@ -1016,12 +1016,15 @@ impl Config {
10161016
)
10171017
}
10181018

1019-
/// Gets the index for the default registry.
1020-
pub fn get_default_registry_index(&self) -> CargoResult<Option<Url>> {
1021-
Ok(match self.get_string("registry.index")? {
1022-
Some(index) => Some(self.resolve_registry_index(index)?),
1023-
None => None,
1024-
})
1019+
/// Returns an error if `registry.index` is set.
1020+
pub fn check_registry_index_not_set(&self) -> CargoResult<()> {
1021+
if self.get_string("registry.index")?.is_some() {
1022+
bail!(
1023+
"the `registry.index` config value is no longer supported\n\
1024+
Use `[source]` replacement to alter the default index for crates.io."
1025+
);
1026+
}
1027+
Ok(())
10251028
}
10261029

10271030
fn resolve_registry_index(&self, index: Value<String>) -> CargoResult<Url> {

src/doc/src/reference/config.md

+1-1
Original file line numberDiff line numberDiff line change
@@ -686,7 +686,7 @@ specified.
686686

687687
##### `registry.index`
688688

689-
This value is deprecated and should not be used.
689+
This value is no longer accepted and should not be used.
690690

691691
##### `registry.default`
692692
* Type: string

0 commit comments

Comments
 (0)