凭据提供者协议

本文档描述了构建 Cargo 凭据提供者的相关信息。有关设置或使用凭据提供者的信息,请参阅 注册表身份验证

当使用外部凭据提供者时,Cargo 使用通过标准输入/输出传递的单行 JSON 消息与凭据提供者进行通信。

Cargo 始终使用 --cargo-plugin 参数执行凭据提供者。这使凭据提供者可执行文件除了 Cargo 需要的功能外,还具有其他功能。额外的参数通过 args 字段包含在 JSON 中。

JSON 消息

本文档中的 JSON 消息为了便于阅读添加了换行符。实际的消息不能包含换行符。

凭据 Hello

  • 发送者:凭据提供者
  • 目的:用于在进程启动时标识支持的协议
{
    "v":[1]
}

Cargo 发送的请求将包含一个 v 字段,该字段设置为此处列出的版本之一。如果 Cargo 不支持凭据提供者提供的任何版本,它将发出错误并关闭凭据进程。

注册表信息

  • 发送者:Cargo 本身不是消息。作为 registry 字段包含在 Cargo 发送的所有消息中。
{
    // Index URL of the registry
    "index-url":"https://github.com/rust-lang/crates.io-index",
    // Name of the registry in configuration (optional)
    "name": "crates-io",
    // HTTP headers received from attempting to access an authenticated registry (optional)
    "headers": ["WWW-Authenticate: cargo"]
}

登录请求

  • 发送者:Cargo
  • 目的:收集并存储凭据
{
    // Protocol version
    "v":1,
    // Action to perform: login
    "kind":"login",
    // Registry information (see Registry information)
    "registry":{"index-url":"sparse+https://registry-url/index/", "name": "my-registry"},
    // User-specified token from stdin or command line (optional)
    "token": "<the token value>",
    // URL that the user could visit to get a token (optional)
    "login-url": "http://registry-url/login",
    // Additional command-line args (optional)
    "args":[]
}

如果设置了 token 字段,则凭据提供者应使用提供的令牌。如果未设置 token,则凭据提供者应提示用户输入令牌。

除了可以在配置中传递给凭据提供者的参数之外,cargo login 还支持通过 cargo login -- <其他参数> 传递其他命令行参数。这些额外的参数将包含在 args 字段中,位于 Cargo 配置中的任何参数之后。

读取请求

  • 发送者:Cargo
  • 目的:获取用于读取 crate 信息的凭据
{
    // Protocol version
    "v":1,
    // Request kind: get credentials
    "kind":"get",
    // Action to perform: read crate information
    "operation":"read",
    // Registry information (see Registry information)
    "registry":{"index-url":"sparse+https://registry-url/index/", "name": "my-registry"},
    // Additional command-line args (optional)
    "args":[]
}

发布请求

  • 发送者:Cargo
  • 目的:获取用于发布 crate 的凭据
{
    // Protocol version
    "v":1,
    // Request kind: get credentials
    "kind":"get",
    // Action to perform: publish crate
    "operation":"publish",
    // Crate name
    "name":"sample",
    // Crate version
    "vers":"0.1.0",
    // Crate checksum
    "cksum":"...",
    // Registry information (see Registry information)
    "registry":{"index-url":"sparse+https://registry-url/index/", "name": "my-registry"},
    // Additional command-line args (optional)
    "args":[]
}

获取成功响应

  • 发送者:凭据提供者
  • 目的:将凭据提供给 Cargo
{"Ok":{
    // Response kind: this was a get request
    "kind":"get",
    // Token to send to the registry
    "token":"...",
    // Cache control. Can be one of the following:
    // * "never": do not cache
    // * "session": cache for the current cargo session
    // * "expires": cache for the current cargo session until expiration
    "cache":"expires",
    // Unix timestamp (only for "cache": "expires")
    "expiration":1693942857,
    // Is the token operation independent?
    "operation_independent":true
}}

token 将作为 Authorization HTTP 标头的值发送到注册表。

operation_independent 指示令牌是否可以在不同的操作(例如发布或获取)之间缓存。通常,这应为 true,除非提供者想要生成特定操作范围的令牌。

登录成功响应

  • 发送者:凭据提供者
  • 目的:指示登录成功
{"Ok":{
    // Response kind: this was a login request
    "kind":"login"
}}

注销成功响应

  • 发送者:凭据提供者
  • 目的:指示注销成功
{"Ok":{
    // Response kind: this was a logout request
    "kind":"logout"
}}

失败响应(不支持 URL)

  • 发送者:凭据提供者
  • 目的:向 Cargo 提供错误信息
{"Err":{
    "kind":"url-not-supported"
}}

如果凭据提供者设计为仅处理特定的注册表 URL,并且给定的 URL 不受支持,则发送此消息。如果可用,Cargo 将尝试另一个提供者。

失败响应(未找到)

  • 发送者:凭据提供者
  • 目的:向 Cargo 提供错误信息
{"Err":{
    // Error: The credential could not be found in the provider.
    "kind":"not-found"
}}

如果找不到凭据则发送此消息。对于 get 请求(其中凭据不可用)或 logout 请求(其中未找到要删除的内容),这是预期的。

失败响应(不支持操作)

  • 发送者:凭据提供者
  • 目的:向 Cargo 提供错误信息
{"Err":{
    // Error: The credential could not be found in the provider.
    "kind":"operation-not-supported"
}}

如果凭据提供者不支持请求的操作,则发送此消息。如果提供者仅支持 get,并且请求 login,则提供者应使用此错误进行响应。

失败响应(其他)

  • 发送者:凭据提供者
  • 目的:向 Cargo 提供错误信息
{"Err":{
    // Error: something else has failed
    "kind":"other",
    // Error message string to be displayed
    "message": "free form string error message",
    // Detailed cause chain for the error (optional)
    "caused-by": ["cause 1", "cause 2"]
}}

请求读取令牌的通信示例

  1. Cargo 生成凭据进程,捕获标准输入和标准输出。
  2. 凭据进程将 Hello 消息发送到 Cargo
    { "v": [1] }
    
  3. Cargo 将 CredentialRequest 消息发送到凭据进程(为了便于阅读添加了换行符)。
    {
        "v": 1,
        "kind": "get",
        "operation": "read",
        "registry":{"index-url":"sparse+https://registry-url/index/"}
    }
    
  4. 凭据进程将 CredentialResponse 发送到 Cargo(为了便于阅读添加了换行符)。
    {
        "token": "...",
        "cache": "session",
        "operation_independent": true
    }
    
  5. Cargo 关闭到凭据提供者的标准输入管道,并且它退出。
  6. 在与此注册表交互时,Cargo 在会话的剩余时间内(直到 Cargo 退出)使用该令牌。