凭据提供程序协议

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

使用外部凭据提供程序时,Cargo 使用作为单行 JSON 传递的 stdin/stdout 消息与凭据提供程序进行通信。

Cargo 将始终使用 --cargo-plugin 参数执行凭据提供程序。这使得凭据提供程序可执行文件可以具有 Cargo 所需功能之外的其他功能。其他参数通过 args 字段包含在 JSON 中。

JSON 消息

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

凭据问候

  • 发送者:凭据提供程序
  • 目的:用于在进程启动时识别支持的协议
{
    "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 -- <additional args> 传递额外的命令行参数。这些附加参数将包含在 Cargo 配置中任何参数之后的 args 字段中。

读取请求

  • 发送者:Cargo
  • 目的:获取用于读取包信息的凭据
{
    // 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
  • 目的:获取用于发布包的凭据
{
    // 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 生成凭据进程,捕获 stdin 和 stdout。
  2. 凭据进程向 Cargo 发送 Hello 消息
    { "v": [1] }
    
  3. Cargo 向凭据进程发送 CredentialRequest 消息(为了便于阅读,添加了换行符)。
    {
        "v": 1,
        "kind": "get",
        "operation": "read",
        "registry":{"index-url":"sparse+https://registry-url/index/"}
    }
    
  4. 凭据进程向 Cargo 发送 CredentialResponse(为了便于阅读,添加了换行符)。
    {
        "token": "...",
        "cache": "session",
        "operation_independent": true
    }
    
  5. Cargo 关闭到凭据提供程序的 stdin 管道,然后退出。
  6. Cargo 在与该注册表交互时,会在剩余的会话时间(直到 Cargo 退出)使用该令牌。