summaryrefslogtreecommitdiffstats
path: root/src/tools/cargo/credential
diff options
context:
space:
mode:
authorDaniel Baumann <daniel.baumann@progress-linux.org>2024-05-30 18:31:44 +0000
committerDaniel Baumann <daniel.baumann@progress-linux.org>2024-05-30 18:31:44 +0000
commitc23a457e72abe608715ac76f076f47dc42af07a5 (patch)
tree2772049aaf84b5c9d0ed12ec8d86812f7a7904b6 /src/tools/cargo/credential
parentReleasing progress-linux version 1.73.0+dfsg1-1~progress7.99u1. (diff)
downloadrustc-c23a457e72abe608715ac76f076f47dc42af07a5.tar.xz
rustc-c23a457e72abe608715ac76f076f47dc42af07a5.zip
Merging upstream version 1.74.1+dfsg1.
Signed-off-by: Daniel Baumann <daniel.baumann@progress-linux.org>
Diffstat (limited to 'src/tools/cargo/credential')
-rw-r--r--src/tools/cargo/credential/cargo-credential-1password/Cargo.toml2
-rw-r--r--src/tools/cargo/credential/cargo-credential-1password/README.md17
-rw-r--r--src/tools/cargo/credential/cargo-credential-1password/src/main.rs4
-rw-r--r--src/tools/cargo/credential/cargo-credential-libsecret/Cargo.toml2
-rw-r--r--src/tools/cargo/credential/cargo-credential-libsecret/README.md6
-rw-r--r--src/tools/cargo/credential/cargo-credential-libsecret/src/lib.rs10
-rw-r--r--src/tools/cargo/credential/cargo-credential-macos-keychain/Cargo.toml2
-rw-r--r--src/tools/cargo/credential/cargo-credential-macos-keychain/README.md7
-rw-r--r--src/tools/cargo/credential/cargo-credential-wincred/Cargo.toml2
-rw-r--r--src/tools/cargo/credential/cargo-credential-wincred/README.md6
-rw-r--r--src/tools/cargo/credential/cargo-credential-wincred/src/lib.rs4
-rw-r--r--src/tools/cargo/credential/cargo-credential/Cargo.toml3
-rw-r--r--src/tools/cargo/credential/cargo-credential/README.md4
-rw-r--r--src/tools/cargo/credential/cargo-credential/examples/file-provider.rs4
-rw-r--r--src/tools/cargo/credential/cargo-credential/examples/stdout-redirected.rs4
-rw-r--r--src/tools/cargo/credential/cargo-credential/src/error.rs4
-rw-r--r--src/tools/cargo/credential/cargo-credential/src/lib.rs204
17 files changed, 230 insertions, 55 deletions
diff --git a/src/tools/cargo/credential/cargo-credential-1password/Cargo.toml b/src/tools/cargo/credential/cargo-credential-1password/Cargo.toml
index a607e6da1..d7bd949d1 100644
--- a/src/tools/cargo/credential/cargo-credential-1password/Cargo.toml
+++ b/src/tools/cargo/credential/cargo-credential-1password/Cargo.toml
@@ -1,6 +1,6 @@
[package]
name = "cargo-credential-1password"
-version = "0.3.0"
+version = "0.4.0"
edition.workspace = true
license.workspace = true
repository = "https://github.com/rust-lang/cargo"
diff --git a/src/tools/cargo/credential/cargo-credential-1password/README.md b/src/tools/cargo/credential/cargo-credential-1password/README.md
index 7cc15e05b..3648efe4b 100644
--- a/src/tools/cargo/credential/cargo-credential-1password/README.md
+++ b/src/tools/cargo/credential/cargo-credential-1password/README.md
@@ -1,7 +1,18 @@
# cargo-credential-1password
-This is the implementation for the Cargo credential helper for [1password].
-See the [credential-process] documentation for how to use this.
+A Cargo [credential provider] for [1password].
+
+`cargo-credential-1password` uses the 1password `op` CLI to store the token. You must
+install the `op` CLI from the [1password
+website](https://1password.com/downloads/command-line/). You must run `op signin`
+at least once with the appropriate arguments (such as `op signin my.1password.com user@example.com`),
+unless you provide the sign-in-address and email arguments. The master password will be required on each request
+unless the appropriate `OP_SESSION` environment variable is set. It supports
+the following command-line arguments:
+* `--account`: The account shorthand name to use.
+* `--vault`: The vault name to use.
+* `--sign-in-address`: The sign-in-address, which is a web address such as `my.1password.com`.
+* `--email`: The email address to sign in with.
[1password]: https://1password.com/
-[credential-process]: https://doc.rust-lang.org/nightly/cargo/reference/unstable.html#credential-process
+[credential provider]: https://doc.rust-lang.org/nightly/cargo/reference/registry-authentication.html
diff --git a/src/tools/cargo/credential/cargo-credential-1password/src/main.rs b/src/tools/cargo/credential/cargo-credential-1password/src/main.rs
index a2607fd2f..921b52145 100644
--- a/src/tools/cargo/credential/cargo-credential-1password/src/main.rs
+++ b/src/tools/cargo/credential/cargo-credential-1password/src/main.rs
@@ -255,8 +255,8 @@ pub struct OnePasswordCredential {}
impl Credential for OnePasswordCredential {
fn perform(
&self,
- registry: &RegistryInfo,
- action: &Action,
+ registry: &RegistryInfo<'_>,
+ action: &Action<'_>,
args: &[&str],
) -> Result<CredentialResponse, Error> {
let op = OnePasswordKeychain::new(args)?;
diff --git a/src/tools/cargo/credential/cargo-credential-libsecret/Cargo.toml b/src/tools/cargo/credential/cargo-credential-libsecret/Cargo.toml
index 1bd4bb7d0..5bedad3b9 100644
--- a/src/tools/cargo/credential/cargo-credential-libsecret/Cargo.toml
+++ b/src/tools/cargo/credential/cargo-credential-libsecret/Cargo.toml
@@ -1,6 +1,6 @@
[package]
name = "cargo-credential-libsecret"
-version = "0.3.1"
+version = "0.3.2"
edition.workspace = true
license.workspace = true
repository = "https://github.com/rust-lang/cargo"
diff --git a/src/tools/cargo/credential/cargo-credential-libsecret/README.md b/src/tools/cargo/credential/cargo-credential-libsecret/README.md
index f169323e0..aaba2887f 100644
--- a/src/tools/cargo/credential/cargo-credential-libsecret/README.md
+++ b/src/tools/cargo/credential/cargo-credential-libsecret/README.md
@@ -1,7 +1,9 @@
# cargo-credential-libsecret
This is the implementation for the Cargo credential helper for [GNOME libsecret].
-See the [credential-process] documentation for how to use this.
+See the [credential-provider] documentation for how to use this.
+
+This credential provider is built-in to cargo as `cargo:libsecret`.
[GNOME libsecret]: https://wiki.gnome.org/Projects/Libsecret
-[credential-process]: https://doc.rust-lang.org/nightly/cargo/reference/unstable.html#credential-process
+[credential-provider]: https://doc.rust-lang.org/nightly/cargo/reference/registry-authentication.html
diff --git a/src/tools/cargo/credential/cargo-credential-libsecret/src/lib.rs b/src/tools/cargo/credential/cargo-credential-libsecret/src/lib.rs
index f83b424ee..ee1797605 100644
--- a/src/tools/cargo/credential/cargo-credential-libsecret/src/lib.rs
+++ b/src/tools/cargo/credential/cargo-credential-libsecret/src/lib.rs
@@ -104,16 +104,16 @@ mod linux {
impl Credential for LibSecretCredential {
fn perform(
&self,
- registry: &RegistryInfo,
- action: &Action,
+ registry: &RegistryInfo<'_>,
+ action: &Action<'_>,
_args: &[&str],
) -> Result<CredentialResponse, Error> {
// Dynamically load libsecret to avoid users needing to install
// additional -dev packages when building this provider.
let lib;
- let secret_password_lookup_sync: Symbol<SecretPasswordLookupSync>;
- let secret_password_store_sync: Symbol<SecretPasswordStoreSync>;
- let secret_password_clear_sync: Symbol<SecretPasswordClearSync>;
+ let secret_password_lookup_sync: Symbol<'_, SecretPasswordLookupSync>;
+ let secret_password_store_sync: Symbol<'_, SecretPasswordStoreSync>;
+ let secret_password_clear_sync: Symbol<'_, SecretPasswordClearSync>;
unsafe {
lib = Library::new("libsecret-1.so").context(
"failed to load libsecret: try installing the `libsecret` \
diff --git a/src/tools/cargo/credential/cargo-credential-macos-keychain/Cargo.toml b/src/tools/cargo/credential/cargo-credential-macos-keychain/Cargo.toml
index 342c771b5..172e9c10b 100644
--- a/src/tools/cargo/credential/cargo-credential-macos-keychain/Cargo.toml
+++ b/src/tools/cargo/credential/cargo-credential-macos-keychain/Cargo.toml
@@ -1,6 +1,6 @@
[package]
name = "cargo-credential-macos-keychain"
-version = "0.3.0"
+version = "0.3.1"
edition.workspace = true
license.workspace = true
repository = "https://github.com/rust-lang/cargo"
diff --git a/src/tools/cargo/credential/cargo-credential-macos-keychain/README.md b/src/tools/cargo/credential/cargo-credential-macos-keychain/README.md
index 554116b55..f5efe496b 100644
--- a/src/tools/cargo/credential/cargo-credential-macos-keychain/README.md
+++ b/src/tools/cargo/credential/cargo-credential-macos-keychain/README.md
@@ -1,7 +1,10 @@
# cargo-credential-macos-keychain
This is the implementation for the Cargo credential helper for [macOS Keychain].
-See the [credential-process] documentation for how to use this.
+See the [credential-provider] documentation for how to use this.
+
+This credential provider is built-in to cargo as `cargo:macos-keychain`.
[macOS Keychain]: https://support.apple.com/guide/keychain-access/welcome/mac
-[credential-process]: https://doc.rust-lang.org/nightly/cargo/reference/unstable.html#credential-process
+[credential-provider]: https://doc.rust-lang.org/nightly/cargo/reference/registry-authentication.html
+
diff --git a/src/tools/cargo/credential/cargo-credential-wincred/Cargo.toml b/src/tools/cargo/credential/cargo-credential-wincred/Cargo.toml
index 8c609dc4e..6da6578a5 100644
--- a/src/tools/cargo/credential/cargo-credential-wincred/Cargo.toml
+++ b/src/tools/cargo/credential/cargo-credential-wincred/Cargo.toml
@@ -1,6 +1,6 @@
[package]
name = "cargo-credential-wincred"
-version = "0.3.0"
+version = "0.3.1"
edition.workspace = true
license.workspace = true
repository = "https://github.com/rust-lang/cargo"
diff --git a/src/tools/cargo/credential/cargo-credential-wincred/README.md b/src/tools/cargo/credential/cargo-credential-wincred/README.md
index 8c8d18789..1995e9d76 100644
--- a/src/tools/cargo/credential/cargo-credential-wincred/README.md
+++ b/src/tools/cargo/credential/cargo-credential-wincred/README.md
@@ -1,7 +1,9 @@
# cargo-credential-wincred
This is the implementation for the Cargo credential helper for [Windows Credential Manager].
-See the [credential-process] documentation for how to use this.
+See the [credential-provider] documentation for how to use this.
+
+This credential provider is built-in to cargo as `cargo:wincred`.
[Windows Credential Manager]: https://support.microsoft.com/en-us/windows/accessing-credential-manager-1b5c916a-6a16-889f-8581-fc16e8165ac0
-[credential-process]: https://doc.rust-lang.org/nightly/cargo/reference/unstable.html#credential-process
+[credential-provider]: https://doc.rust-lang.org/nightly/cargo/reference/registry-authentication.html
diff --git a/src/tools/cargo/credential/cargo-credential-wincred/src/lib.rs b/src/tools/cargo/credential/cargo-credential-wincred/src/lib.rs
index 9200ca58f..24b072ee2 100644
--- a/src/tools/cargo/credential/cargo-credential-wincred/src/lib.rs
+++ b/src/tools/cargo/credential/cargo-credential-wincred/src/lib.rs
@@ -38,8 +38,8 @@ mod win {
impl Credential for WindowsCredential {
fn perform(
&self,
- registry: &RegistryInfo,
- action: &Action,
+ registry: &RegistryInfo<'_>,
+ action: &Action<'_>,
_args: &[&str],
) -> Result<CredentialResponse, Error> {
match action {
diff --git a/src/tools/cargo/credential/cargo-credential/Cargo.toml b/src/tools/cargo/credential/cargo-credential/Cargo.toml
index 8cd1348be..c8db996bf 100644
--- a/src/tools/cargo/credential/cargo-credential/Cargo.toml
+++ b/src/tools/cargo/credential/cargo-credential/Cargo.toml
@@ -1,8 +1,9 @@
[package]
name = "cargo-credential"
-version = "0.3.0"
+version = "0.4.0"
edition.workspace = true
license.workspace = true
+rust-version = "1.70.0"
repository = "https://github.com/rust-lang/cargo"
description = "A library to assist writing Cargo credential helpers."
diff --git a/src/tools/cargo/credential/cargo-credential/README.md b/src/tools/cargo/credential/cargo-credential/README.md
index 049b3ba55..d87d41bb8 100644
--- a/src/tools/cargo/credential/cargo-credential/README.md
+++ b/src/tools/cargo/credential/cargo-credential/README.md
@@ -5,7 +5,7 @@ provides an interface to store tokens for authorizing access to a registry
such as https://crates.io/.
Documentation about credential processes may be found at
-https://doc.rust-lang.org/nightly/cargo/reference/unstable.html#credential-process
+https://doc.rust-lang.org/nightly/cargo/reference/credential-provider-protocol.html
Example implementations may be found at
https://github.com/rust-lang/cargo/tree/master/credential
@@ -18,7 +18,7 @@ Create a Cargo project with this as a dependency:
# Add this to your Cargo.toml:
[dependencies]
-cargo-credential = "0.3"
+cargo-credential = "0.4"
```
And then include a `main.rs` binary which implements the `Credential` trait, and calls
diff --git a/src/tools/cargo/credential/cargo-credential/examples/file-provider.rs b/src/tools/cargo/credential/cargo-credential/examples/file-provider.rs
index d11958536..3ed312cb8 100644
--- a/src/tools/cargo/credential/cargo-credential/examples/file-provider.rs
+++ b/src/tools/cargo/credential/cargo-credential/examples/file-provider.rs
@@ -12,8 +12,8 @@ struct FileCredential;
impl Credential for FileCredential {
fn perform(
&self,
- registry: &RegistryInfo,
- action: &Action,
+ registry: &RegistryInfo<'_>,
+ action: &Action<'_>,
_args: &[&str],
) -> Result<CredentialResponse, cargo_credential::Error> {
if registry.index_url != "https://github.com/rust-lang/crates.io-index" {
diff --git a/src/tools/cargo/credential/cargo-credential/examples/stdout-redirected.rs b/src/tools/cargo/credential/cargo-credential/examples/stdout-redirected.rs
index 0b9bcc2f7..75a2d16d1 100644
--- a/src/tools/cargo/credential/cargo-credential/examples/stdout-redirected.rs
+++ b/src/tools/cargo/credential/cargo-credential/examples/stdout-redirected.rs
@@ -7,8 +7,8 @@ struct MyCredential;
impl Credential for MyCredential {
fn perform(
&self,
- _registry: &RegistryInfo,
- _action: &Action,
+ _registry: &RegistryInfo<'_>,
+ _action: &Action<'_>,
_args: &[&str],
) -> Result<CredentialResponse, Error> {
// Informational messages should be sent on stderr.
diff --git a/src/tools/cargo/credential/cargo-credential/src/error.rs b/src/tools/cargo/credential/cargo-credential/src/error.rs
index 2ebaf9977..8c5fe19e5 100644
--- a/src/tools/cargo/credential/cargo-credential/src/error.rs
+++ b/src/tools/cargo/credential/cargo-credential/src/error.rs
@@ -42,9 +42,9 @@ pub enum Error {
}
impl From<String> for Error {
- fn from(err: String) -> Self {
+ fn from(message: String) -> Self {
Box::new(StringTypedError {
- message: err.to_string(),
+ message,
source: None,
})
.into()
diff --git a/src/tools/cargo/credential/cargo-credential/src/lib.rs b/src/tools/cargo/credential/cargo-credential/src/lib.rs
index 0fb495ed3..60bce65be 100644
--- a/src/tools/cargo/credential/cargo-credential/src/lib.rs
+++ b/src/tools/cargo/credential/cargo-credential/src/lib.rs
@@ -50,7 +50,7 @@ pub use secret::Secret;
use stdio::stdin_stdout_to_console;
/// Message sent by the credential helper on startup
-#[derive(Serialize, Deserialize, Clone, Debug)]
+#[derive(Serialize, Deserialize, Clone, Debug, PartialEq, Eq)]
pub struct CredentialHello {
// Protocol versions supported by the credential process.
pub v: Vec<u32>,
@@ -61,8 +61,8 @@ pub struct UnsupportedCredential;
impl Credential for UnsupportedCredential {
fn perform(
&self,
- _registry: &RegistryInfo,
- _action: &Action,
+ _registry: &RegistryInfo<'_>,
+ _action: &Action<'_>,
_args: &[&str],
) -> Result<CredentialResponse, Error> {
Err(Error::UrlNotSupported)
@@ -70,7 +70,7 @@ impl Credential for UnsupportedCredential {
}
/// Message sent by Cargo to the credential helper after the hello
-#[derive(Serialize, Deserialize, Clone, Debug)]
+#[derive(Serialize, Deserialize, Clone, Debug, PartialEq, Eq)]
#[serde(rename_all = "kebab-case")]
pub struct CredentialRequest<'a> {
// Cargo will respond with the highest common protocol supported by both.
@@ -80,23 +80,25 @@ pub struct CredentialRequest<'a> {
#[serde(borrow, flatten)]
pub action: Action<'a>,
/// Additional command-line arguments passed to the credential provider.
+ #[serde(skip_serializing_if = "Vec::is_empty", default)]
pub args: Vec<&'a str>,
}
-#[derive(Serialize, Deserialize, Clone, Debug)]
+#[derive(Serialize, Deserialize, Clone, Debug, PartialEq, Eq)]
#[serde(rename_all = "kebab-case")]
pub struct RegistryInfo<'a> {
/// Registry index url
pub index_url: &'a str,
/// Name of the registry in configuration. May not be available.
/// The crates.io registry will be `crates-io` (`CRATES_IO_REGISTRY`).
+ #[serde(skip_serializing_if = "Option::is_none")]
pub name: Option<&'a str>,
/// Headers from attempting to access a registry that resulted in a HTTP 401.
#[serde(skip_serializing_if = "Vec::is_empty", default)]
pub headers: Vec<String>,
}
-#[derive(Serialize, Deserialize, Clone, Debug)]
+#[derive(Serialize, Deserialize, Clone, Debug, PartialEq, Eq)]
#[non_exhaustive]
#[serde(tag = "kind", rename_all = "kebab-case")]
pub enum Action<'a> {
@@ -119,17 +121,19 @@ impl<'a> Display for Action<'a> {
}
}
-#[derive(Serialize, Deserialize, Clone, Debug)]
+#[derive(Serialize, Deserialize, Clone, Debug, PartialEq, Eq)]
#[serde(rename_all = "kebab-case")]
pub struct LoginOptions<'a> {
/// Token passed on the command line via --token or from stdin
+ #[serde(skip_serializing_if = "Option::is_none")]
pub token: Option<Secret<&'a str>>,
/// Optional URL that the user can visit to log in to the registry
+ #[serde(skip_serializing_if = "Option::is_none")]
pub login_url: Option<&'a str>,
}
/// A record of what kind of operation is happening that we should generate a token for.
-#[derive(Serialize, Deserialize, Clone, Debug)]
+#[derive(Serialize, Deserialize, Clone, Debug, PartialEq, Eq)]
#[non_exhaustive]
#[serde(tag = "operation", rename_all = "kebab-case")]
pub enum Operation<'a> {
@@ -168,12 +172,13 @@ pub enum Operation<'a> {
}
/// Message sent by the credential helper
-#[derive(Serialize, Deserialize, Clone, Debug)]
+#[derive(Serialize, Deserialize, Clone, Debug, PartialEq, Eq)]
#[serde(tag = "kind", rename_all = "kebab-case")]
#[non_exhaustive]
pub enum CredentialResponse {
Get {
token: Secret<String>,
+ #[serde(flatten)]
cache: CacheControl,
operation_independent: bool,
},
@@ -183,30 +188,35 @@ pub enum CredentialResponse {
Unknown,
}
-#[derive(Serialize, Deserialize, Clone, Debug)]
-#[serde(rename_all = "kebab-case")]
+#[derive(Serialize, Deserialize, Clone, Debug, PartialEq, Eq)]
+#[serde(tag = "cache", rename_all = "kebab-case")]
#[non_exhaustive]
pub enum CacheControl {
/// Do not cache this result.
Never,
/// Cache this result and use it for subsequent requests in the current Cargo invocation until the specified time.
- Expires(#[serde(with = "time::serde::timestamp")] OffsetDateTime),
+ Expires {
+ #[serde(with = "time::serde::timestamp")]
+ expiration: OffsetDateTime,
+ },
/// Cache this result and use it for all subsequent requests in the current Cargo invocation.
Session,
#[serde(other)]
Unknown,
}
-/// Credential process JSON protocol version. Incrementing
-/// this version will prevent new credential providers
-/// from working with older versions of Cargo.
+/// Credential process JSON protocol version. If the protocol needs to make
+/// a breaking change, a new protocol version should be defined (`PROTOCOL_VERSION_2`).
+/// This library should offer support for both protocols if possible, by signaling
+/// in the `CredentialHello` message. Cargo will then choose which protocol to use,
+/// or it will error if there are no common protocol versions available.
pub const PROTOCOL_VERSION_1: u32 = 1;
pub trait Credential {
/// Retrieves a token for the given registry.
fn perform(
&self,
- registry: &RegistryInfo,
- action: &Action,
+ registry: &RegistryInfo<'_>,
+ action: &Action<'_>,
args: &[&str],
) -> Result<CredentialResponse, Error>;
}
@@ -236,11 +246,7 @@ fn doit(
if len == 0 {
return Ok(());
}
- let request: CredentialRequest = serde_json::from_str(&buffer)?;
- if request.v != PROTOCOL_VERSION_1 {
- return Err(format!("unsupported protocol version {}", request.v).into());
- }
-
+ let request = deserialize_request(&buffer)?;
let response = stdin_stdout_to_console(|| {
credential.perform(&request.registry, &request.action, &request.args)
})?;
@@ -250,6 +256,17 @@ fn doit(
}
}
+/// Deserialize a request from Cargo.
+fn deserialize_request(
+ value: &str,
+) -> Result<CredentialRequest<'_>, Box<dyn std::error::Error + Send + Sync>> {
+ let request: CredentialRequest<'_> = serde_json::from_str(&value)?;
+ if request.v != PROTOCOL_VERSION_1 {
+ return Err(format!("unsupported protocol version {}", request.v).into());
+ }
+ Ok(request)
+}
+
/// Read a line of text from stdin.
pub fn read_line() -> Result<String, io::Error> {
let mut buf = String::new();
@@ -259,8 +276,8 @@ pub fn read_line() -> Result<String, io::Error> {
/// Prompt the user for a token.
pub fn read_token(
- login_options: &LoginOptions,
- registry: &RegistryInfo,
+ login_options: &LoginOptions<'_>,
+ registry: &RegistryInfo<'_>,
) -> Result<Secret<String>, Error> {
if let Some(token) = &login_options.token {
return Ok(token.to_owned());
@@ -276,3 +293,142 @@ pub fn read_token(
Ok(Secret::from(read_line().map_err(Box::new)?))
}
+
+#[cfg(test)]
+mod tests {
+ use super::*;
+
+ #[test]
+ fn unsupported_version() {
+ // This shouldn't ever happen in practice, since the credential provider signals to Cargo which
+ // protocol versions it supports, and Cargo should only attempt to use one of those.
+ let msg = r#"{"v":999, "registry": {"index-url":""}, "args":[], "kind": "unexpected"}"#;
+ assert_eq!(
+ "unsupported protocol version 999",
+ deserialize_request(msg).unwrap_err().to_string()
+ );
+ }
+
+ #[test]
+ fn cache_control() {
+ let cc = CacheControl::Expires {
+ expiration: OffsetDateTime::from_unix_timestamp(1693928537).unwrap(),
+ };
+ let json = serde_json::to_string(&cc).unwrap();
+ assert_eq!(json, r#"{"cache":"expires","expiration":1693928537}"#);
+
+ let cc = CacheControl::Session;
+ let json = serde_json::to_string(&cc).unwrap();
+ assert_eq!(json, r#"{"cache":"session"}"#);
+
+ let cc: CacheControl = serde_json::from_str(r#"{"cache":"unknown-kind"}"#).unwrap();
+ assert_eq!(cc, CacheControl::Unknown);
+
+ assert_eq!(
+ "missing field `expiration`",
+ serde_json::from_str::<CacheControl>(r#"{"cache":"expires"}"#)
+ .unwrap_err()
+ .to_string()
+ );
+ }
+
+ #[test]
+ fn credential_response() {
+ let cr = CredentialResponse::Get {
+ cache: CacheControl::Never,
+ operation_independent: true,
+ token: Secret::from("value".to_string()),
+ };
+ let json = serde_json::to_string(&cr).unwrap();
+ assert_eq!(
+ json,
+ r#"{"kind":"get","token":"value","cache":"never","operation_independent":true}"#
+ );
+
+ let cr = CredentialResponse::Login;
+ let json = serde_json::to_string(&cr).unwrap();
+ assert_eq!(json, r#"{"kind":"login"}"#);
+
+ let cr: CredentialResponse =
+ serde_json::from_str(r#"{"kind":"unknown-kind","extra-data":true}"#).unwrap();
+ assert_eq!(cr, CredentialResponse::Unknown);
+
+ let cr: CredentialResponse =
+ serde_json::from_str(r#"{"kind":"login","extra-data":true}"#).unwrap();
+ assert_eq!(cr, CredentialResponse::Login);
+
+ let cr: CredentialResponse = serde_json::from_str(r#"{"kind":"get","token":"value","cache":"never","operation_independent":true,"extra-field-ignored":123}"#).unwrap();
+ assert_eq!(
+ cr,
+ CredentialResponse::Get {
+ cache: CacheControl::Never,
+ operation_independent: true,
+ token: Secret::from("value".to_string())
+ }
+ );
+ }
+
+ #[test]
+ fn credential_request() {
+ let get_oweners = CredentialRequest {
+ v: PROTOCOL_VERSION_1,
+ args: vec![],
+ registry: RegistryInfo {
+ index_url: "url",
+ name: None,
+ headers: vec![],
+ },
+ action: Action::Get(Operation::Owners { name: "pkg" }),
+ };
+
+ let json = serde_json::to_string(&get_oweners).unwrap();
+ assert_eq!(
+ json,
+ r#"{"v":1,"registry":{"index-url":"url"},"kind":"get","operation":"owners","name":"pkg"}"#
+ );
+
+ let cr: CredentialRequest<'_> =
+ serde_json::from_str(r#"{"extra-1":true,"v":1,"registry":{"index-url":"url","extra-2":true},"kind":"get","operation":"owners","name":"pkg","args":[]}"#).unwrap();
+ assert_eq!(cr, get_oweners);
+ }
+
+ #[test]
+ fn credential_request_logout() {
+ let unknown = CredentialRequest {
+ v: PROTOCOL_VERSION_1,
+ args: vec![],
+ registry: RegistryInfo {
+ index_url: "url",
+ name: None,
+ headers: vec![],
+ },
+ action: Action::Logout,
+ };
+
+ let cr: CredentialRequest<'_> = serde_json::from_str(
+ r#"{"v":1,"registry":{"index-url":"url"},"kind":"logout","extra-1":true,"args":[]}"#,
+ )
+ .unwrap();
+ assert_eq!(cr, unknown);
+ }
+
+ #[test]
+ fn credential_request_unknown() {
+ let unknown = CredentialRequest {
+ v: PROTOCOL_VERSION_1,
+ args: vec![],
+ registry: RegistryInfo {
+ index_url: "",
+ name: None,
+ headers: vec![],
+ },
+ action: Action::Unknown,
+ };
+
+ let cr: CredentialRequest<'_> = serde_json::from_str(
+ r#"{"v":1,"registry":{"index-url":""},"kind":"unexpected-1","extra-1":true,"args":[]}"#,
+ )
+ .unwrap();
+ assert_eq!(cr, unknown);
+ }
+}