//! Generated by `trust-tasks-codegen` — do not edit by hand.
//!
//! Spec slug: `auth/step-up/approve-request`. Version: `0.4`.
#[allow(unused_imports)]
use serde::{Deserialize, Serialize};
/// Error types.
pub mod error {
/// Error from a `TryFrom` or `FromStr` implementation.
pub struct ConversionError(::std::borrow::Cow<'static, str>);
impl ::std::error::Error for ConversionError {}
impl ::std::fmt::Display for ConversionError {
fn fmt(&self, f: &mut ::std::fmt::Formatter<'_>) -> Result<(), ::std::fmt::Error> {
::std::fmt::Display::fmt(&self.0, f)
}
}
impl ::std::fmt::Debug for ConversionError {
fn fmt(&self, f: &mut ::std::fmt::Formatter<'_>) -> Result<(), ::std::fmt::Error> {
::std::fmt::Debug::fmt(&self.0, f)
}
}
impl From<&'static str> for ConversionError {
fn from(value: &'static str) -> Self {
Self(value.into())
}
}
impl From<String> for ConversionError {
fn from(value: String) -> Self {
Self(value.into())
}
}
}
///A step-up approver, as an Ed25519 `did:key` (`z6Mk…`). `did:key` only, because its document is a function of the key and resolves with no network, so verifying an approver's statement never depends on a fetch, and a key whose DID document could be rewritten after enrolment would not be the key that was enrolled. Distinct from the subject's DID, from every verification method in the subject's DID document, and from every key the subject can sign operations with at the relying party.
///
/// <details><summary>JSON schema</summary>
///
/// ```json
///{
/// "title": "ApproverDid",
/// "description": "A step-up approver, as an Ed25519 `did:key` (`z6Mk…`). `did:key` only, because its document is a function of the key and resolves with no network, so verifying an approver's statement never depends on a fetch, and a key whose DID document could be rewritten after enrolment would not be the key that was enrolled. Distinct from the subject's DID, from every verification method in the subject's DID document, and from every key the subject can sign operations with at the relying party.",
/// "type": "string",
/// "maxLength": 128,
/// "minLength": 16,
/// "pattern": "^did:key:z6Mk[1-9A-HJ-NP-Za-km-z]+$"
///}
/// ```
/// </details>
#[derive(::serde::Serialize, Clone, Debug, Eq, Hash, Ord, PartialEq, PartialOrd)]
#[serde(transparent)]
pub struct ApproverDid(::std::string::String);
impl ::std::ops::Deref for ApproverDid {
type Target = ::std::string::String;
fn deref(&self) -> &::std::string::String {
&self.0
}
}
impl ::std::convert::From<ApproverDid> for ::std::string::String {
fn from(value: ApproverDid) -> Self {
value.0
}
}
impl ::std::str::FromStr for ApproverDid {
type Err = self::error::ConversionError;
fn from_str(value: &str) -> ::std::result::Result<Self, self::error::ConversionError> {
if value.chars().count() > 128usize {
return Err("longer than 128 characters".into());
}
if value.chars().count() < 16usize {
return Err("shorter than 16 characters".into());
}
static PATTERN: ::std::sync::LazyLock<::regress::Regex> =
::std::sync::LazyLock::new(|| {
::regress::Regex::new("^did:key:z6Mk[1-9A-HJ-NP-Za-km-z]+$").unwrap()
});
if PATTERN.find(value).is_none() {
return Err("doesn't match pattern \"^did:key:z6Mk[1-9A-HJ-NP-Za-km-z]+$\"".into());
}
Ok(Self(value.to_string()))
}
}
impl ::std::convert::TryFrom<&str> for ApproverDid {
type Error = self::error::ConversionError;
fn try_from(value: &str) -> ::std::result::Result<Self, self::error::ConversionError> {
value.parse()
}
}
impl ::std::convert::TryFrom<&::std::string::String> for ApproverDid {
type Error = self::error::ConversionError;
fn try_from(
value: &::std::string::String,
) -> ::std::result::Result<Self, self::error::ConversionError> {
value.parse()
}
}
impl ::std::convert::TryFrom<::std::string::String> for ApproverDid {
type Error = self::error::ConversionError;
fn try_from(
value: ::std::string::String,
) -> ::std::result::Result<Self, self::error::ConversionError> {
value.parse()
}
}
impl<'de> ::serde::Deserialize<'de> for ApproverDid {
fn deserialize<D>(deserializer: D) -> ::std::result::Result<Self, D::Error>
where
D: ::serde::Deserializer<'de>,
{
::std::string::String::deserialize(deserializer)?
.parse()
.map_err(|e: self::error::ConversionError| {
<D::Error as ::serde::de::Error>::custom(e.to_string())
})
}
}
///`CredentialDescriptor`
///
/// <details><summary>JSON schema</summary>
///
/// ```json
///{
/// "title": "PublicKeyCredentialDescriptor",
/// "type": "object",
/// "required": [
/// "id",
/// "type"
/// ],
/// "properties": {
/// "id": {
/// "description": "base64url-encoded credential id.",
/// "type": "string"
/// },
/// "transports": {
/// "type": "array",
/// "items": {
/// "enum": [
/// "usb",
/// "nfc",
/// "ble",
/// "internal",
/// "hybrid"
/// ]
/// }
/// },
/// "type": {
/// "const": "public-key"
/// }
/// },
/// "additionalProperties": false,
/// "$anchor": "credentialDescriptor"
///}
/// ```
/// </details>
#[derive(::serde::Deserialize, ::serde::Serialize, Clone, Debug)]
#[serde(deny_unknown_fields)]
#[non_exhaustive]
pub struct CredentialDescriptor {
///base64url-encoded credential id.
pub id: ::std::string::String,
#[serde(default, skip_serializing_if = "::std::vec::Vec::is_empty")]
pub transports: ::std::vec::Vec<CredentialDescriptorTransportsItem>,
#[serde(rename = "type")]
pub type_: ::serde_json::Value,
}
impl CredentialDescriptor {
pub fn builder() -> builder::CredentialDescriptor {
Default::default()
}
}
///`CredentialDescriptorTransportsItem`
///
/// <details><summary>JSON schema</summary>
///
/// ```json
///{
/// "enum": [
/// "usb",
/// "nfc",
/// "ble",
/// "internal",
/// "hybrid"
/// ]
///}
/// ```
/// </details>
#[derive(
::serde::Deserialize,
::serde::Serialize,
Clone,
Copy,
Debug,
Eq,
Hash,
Ord,
PartialEq,
PartialOrd,
)]
#[non_exhaustive]
pub enum CredentialDescriptorTransportsItem {
#[serde(rename = "usb")]
Usb,
#[serde(rename = "nfc")]
Nfc,
#[serde(rename = "ble")]
Ble,
#[serde(rename = "internal")]
Internal,
#[serde(rename = "hybrid")]
Hybrid,
}
impl ::std::fmt::Display for CredentialDescriptorTransportsItem {
fn fmt(&self, f: &mut ::std::fmt::Formatter<'_>) -> ::std::fmt::Result {
match *self {
Self::Usb => f.write_str("usb"),
Self::Nfc => f.write_str("nfc"),
Self::Ble => f.write_str("ble"),
Self::Internal => f.write_str("internal"),
Self::Hybrid => f.write_str("hybrid"),
}
}
}
impl ::std::str::FromStr for CredentialDescriptorTransportsItem {
type Err = self::error::ConversionError;
fn from_str(value: &str) -> ::std::result::Result<Self, self::error::ConversionError> {
match value {
"usb" => Ok(Self::Usb),
"nfc" => Ok(Self::Nfc),
"ble" => Ok(Self::Ble),
"internal" => Ok(Self::Internal),
"hybrid" => Ok(Self::Hybrid),
_ => Err("invalid value".into()),
}
}
}
impl ::std::convert::TryFrom<&str> for CredentialDescriptorTransportsItem {
type Error = self::error::ConversionError;
fn try_from(value: &str) -> ::std::result::Result<Self, self::error::ConversionError> {
value.parse()
}
}
impl ::std::convert::TryFrom<&::std::string::String> for CredentialDescriptorTransportsItem {
type Error = self::error::ConversionError;
fn try_from(
value: &::std::string::String,
) -> ::std::result::Result<Self, self::error::ConversionError> {
value.parse()
}
}
impl ::std::convert::TryFrom<::std::string::String> for CredentialDescriptorTransportsItem {
type Error = self::error::ConversionError;
fn try_from(
value: ::std::string::String,
) -> ::std::result::Result<Self, self::error::ConversionError> {
value.parse()
}
}
///Server-issued options for `navigator.credentials.get({ publicKey: ... })`.
///
/// <details><summary>JSON schema</summary>
///
/// ```json
///{
/// "title": "PublicKeyCredentialRequestOptions",
/// "description": "Server-issued options for `navigator.credentials.get({ publicKey: ... })`.",
/// "type": "object",
/// "required": [
/// "challenge"
/// ],
/// "properties": {
/// "allowCredentials": {
/// "type": "array",
/// "items": {
/// "$ref": "#/definitions/CredentialDescriptor"
/// }
/// },
/// "challenge": {
/// "description": "base64url-encoded one-time nonce.",
/// "type": "string"
/// },
/// "extensions": {
/// "description": "Client extension inputs, per the WebAuthn Level 2 `AuthenticationExtensionsClientInputs` dictionary.\n\nThis component states that it mirrors the W3C dictionary, and that dictionary defines `extensions`. Omitting it while closing the object with `additionalProperties: false` made the two claims contradict each other: a server emitting standard WebAuthn options could not conform, and the widely-used server libraries emit this member by default.\n\nStructure is deliberately unconstrained. The set of extensions is open and registered outside this framework, so enumerating them here would date the schema against a registry it does not own — and a closed list would reproduce the original defect one revision later.",
/// "type": "object"
/// },
/// "rpId": {
/// "type": "string",
/// "minLength": 1
/// },
/// "timeout": {
/// "type": "integer",
/// "minimum": 1.0
/// },
/// "userVerification": {
/// "enum": [
/// "discouraged",
/// "preferred",
/// "required"
/// ]
/// }
/// },
/// "additionalProperties": false,
/// "$anchor": "credentialRequestOptions"
///}
/// ```
/// </details>
#[derive(::serde::Deserialize, ::serde::Serialize, Clone, Debug)]
#[serde(deny_unknown_fields)]
#[non_exhaustive]
pub struct CredentialRequestOptions {
#[serde(
rename = "allowCredentials",
default,
skip_serializing_if = "::std::vec::Vec::is_empty"
)]
pub allow_credentials: ::std::vec::Vec<CredentialDescriptor>,
///base64url-encoded one-time nonce.
pub challenge: ::std::string::String,
/**
Client extension inputs, per the WebAuthn Level 2 `AuthenticationExtensionsClientInputs` dictionary.
This component states that it mirrors the W3C dictionary, and that dictionary defines `extensions`. Omitting it while closing the object with `additionalProperties: false` made the two claims contradict each other: a server emitting standard WebAuthn options could not conform, and the widely-used server libraries emit this member by default.
Structure is deliberately unconstrained. The set of extensions is open and registered outside this framework, so enumerating them here would date the schema against a registry it does not own — and a closed list would reproduce the original defect one revision later.*/
#[serde(default, skip_serializing_if = "::serde_json::Map::is_empty")]
pub extensions: ::serde_json::Map<::std::string::String, ::serde_json::Value>,
#[serde(
rename = "rpId",
default,
skip_serializing_if = "::std::option::Option::is_none"
)]
pub rp_id: ::std::option::Option<CredentialRequestOptionsRpId>,
#[serde(default, skip_serializing_if = "::std::option::Option::is_none")]
pub timeout: ::std::option::Option<::std::num::NonZeroU64>,
#[serde(
rename = "userVerification",
default,
skip_serializing_if = "::std::option::Option::is_none"
)]
pub user_verification: ::std::option::Option<CredentialRequestOptionsUserVerification>,
}
impl CredentialRequestOptions {
pub fn builder() -> builder::CredentialRequestOptions {
Default::default()
}
}
///`CredentialRequestOptionsRpId`
///
/// <details><summary>JSON schema</summary>
///
/// ```json
///{
/// "type": "string",
/// "minLength": 1
///}
/// ```
/// </details>
#[derive(::serde::Serialize, Clone, Debug, Eq, Hash, Ord, PartialEq, PartialOrd)]
#[serde(transparent)]
pub struct CredentialRequestOptionsRpId(::std::string::String);
impl ::std::ops::Deref for CredentialRequestOptionsRpId {
type Target = ::std::string::String;
fn deref(&self) -> &::std::string::String {
&self.0
}
}
impl ::std::convert::From<CredentialRequestOptionsRpId> for ::std::string::String {
fn from(value: CredentialRequestOptionsRpId) -> Self {
value.0
}
}
impl ::std::str::FromStr for CredentialRequestOptionsRpId {
type Err = self::error::ConversionError;
fn from_str(value: &str) -> ::std::result::Result<Self, self::error::ConversionError> {
if value.chars().count() < 1usize {
return Err("shorter than 1 characters".into());
}
Ok(Self(value.to_string()))
}
}
impl ::std::convert::TryFrom<&str> for CredentialRequestOptionsRpId {
type Error = self::error::ConversionError;
fn try_from(value: &str) -> ::std::result::Result<Self, self::error::ConversionError> {
value.parse()
}
}
impl ::std::convert::TryFrom<&::std::string::String> for CredentialRequestOptionsRpId {
type Error = self::error::ConversionError;
fn try_from(
value: &::std::string::String,
) -> ::std::result::Result<Self, self::error::ConversionError> {
value.parse()
}
}
impl ::std::convert::TryFrom<::std::string::String> for CredentialRequestOptionsRpId {
type Error = self::error::ConversionError;
fn try_from(
value: ::std::string::String,
) -> ::std::result::Result<Self, self::error::ConversionError> {
value.parse()
}
}
impl<'de> ::serde::Deserialize<'de> for CredentialRequestOptionsRpId {
fn deserialize<D>(deserializer: D) -> ::std::result::Result<Self, D::Error>
where
D: ::serde::Deserializer<'de>,
{
::std::string::String::deserialize(deserializer)?
.parse()
.map_err(|e: self::error::ConversionError| {
<D::Error as ::serde::de::Error>::custom(e.to_string())
})
}
}
///`CredentialRequestOptionsUserVerification`
///
/// <details><summary>JSON schema</summary>
///
/// ```json
///{
/// "enum": [
/// "discouraged",
/// "preferred",
/// "required"
/// ]
///}
/// ```
/// </details>
#[derive(
::serde::Deserialize,
::serde::Serialize,
Clone,
Copy,
Debug,
Eq,
Hash,
Ord,
PartialEq,
PartialOrd,
)]
#[non_exhaustive]
pub enum CredentialRequestOptionsUserVerification {
#[serde(rename = "discouraged")]
Discouraged,
#[serde(rename = "preferred")]
Preferred,
#[serde(rename = "required")]
Required,
}
impl ::std::fmt::Display for CredentialRequestOptionsUserVerification {
fn fmt(&self, f: &mut ::std::fmt::Formatter<'_>) -> ::std::fmt::Result {
match *self {
Self::Discouraged => f.write_str("discouraged"),
Self::Preferred => f.write_str("preferred"),
Self::Required => f.write_str("required"),
}
}
}
impl ::std::str::FromStr for CredentialRequestOptionsUserVerification {
type Err = self::error::ConversionError;
fn from_str(value: &str) -> ::std::result::Result<Self, self::error::ConversionError> {
match value {
"discouraged" => Ok(Self::Discouraged),
"preferred" => Ok(Self::Preferred),
"required" => Ok(Self::Required),
_ => Err("invalid value".into()),
}
}
}
impl ::std::convert::TryFrom<&str> for CredentialRequestOptionsUserVerification {
type Error = self::error::ConversionError;
fn try_from(value: &str) -> ::std::result::Result<Self, self::error::ConversionError> {
value.parse()
}
}
impl ::std::convert::TryFrom<&::std::string::String> for CredentialRequestOptionsUserVerification {
type Error = self::error::ConversionError;
fn try_from(
value: &::std::string::String,
) -> ::std::result::Result<Self, self::error::ConversionError> {
value.parse()
}
}
impl ::std::convert::TryFrom<::std::string::String> for CredentialRequestOptionsUserVerification {
type Error = self::error::ConversionError;
fn try_from(
value: ::std::string::String,
) -> ::std::result::Result<Self, self::error::ConversionError> {
value.parse()
}
}
///Vendor-namespaced extension object per SPEC.md §4.5.1. Each immediate key MUST be a reverse-DNS namespace; structure under each namespace is opaque to the framework.
///
/// <details><summary>JSON schema</summary>
///
/// ```json
///{
/// "title": "Ext",
/// "description": "Vendor-namespaced extension object per SPEC.md §4.5.1. Each immediate key MUST be a reverse-DNS namespace; structure under each namespace is opaque to the framework.",
/// "type": "object",
/// "minProperties": 1,
/// "additionalProperties": true,
/// "propertyNames": {
/// "pattern": "^[a-z][a-z0-9-]*(\\.[a-z0-9-]+)+$"
/// }
///}
/// ```
/// </details>
#[derive(::serde::Deserialize, ::serde::Serialize, Clone, Debug)]
#[serde(transparent)]
pub struct Ext(pub ::std::collections::HashMap<ExtKey, ::serde_json::Value>);
impl ::std::ops::Deref for Ext {
type Target = ::std::collections::HashMap<ExtKey, ::serde_json::Value>;
fn deref(&self) -> &::std::collections::HashMap<ExtKey, ::serde_json::Value> {
&self.0
}
}
impl ::std::convert::From<Ext> for ::std::collections::HashMap<ExtKey, ::serde_json::Value> {
fn from(value: Ext) -> Self {
value.0
}
}
impl ::std::convert::From<::std::collections::HashMap<ExtKey, ::serde_json::Value>> for Ext {
fn from(value: ::std::collections::HashMap<ExtKey, ::serde_json::Value>) -> Self {
Self(value)
}
}
///`ExtKey`
///
/// <details><summary>JSON schema</summary>
///
/// ```json
///{
/// "type": "string",
/// "pattern": "^[a-z][a-z0-9-]*(\\.[a-z0-9-]+)+$"
///}
/// ```
/// </details>
#[derive(::serde::Serialize, Clone, Debug, Eq, Hash, Ord, PartialEq, PartialOrd)]
#[serde(transparent)]
pub struct ExtKey(::std::string::String);
impl ::std::ops::Deref for ExtKey {
type Target = ::std::string::String;
fn deref(&self) -> &::std::string::String {
&self.0
}
}
impl ::std::convert::From<ExtKey> for ::std::string::String {
fn from(value: ExtKey) -> Self {
value.0
}
}
impl ::std::str::FromStr for ExtKey {
type Err = self::error::ConversionError;
fn from_str(value: &str) -> ::std::result::Result<Self, self::error::ConversionError> {
static PATTERN: ::std::sync::LazyLock<::regress::Regex> =
::std::sync::LazyLock::new(|| {
::regress::Regex::new("^[a-z][a-z0-9-]*(\\.[a-z0-9-]+)+$").unwrap()
});
if PATTERN.find(value).is_none() {
return Err("doesn't match pattern \"^[a-z][a-z0-9-]*(\\.[a-z0-9-]+)+$\"".into());
}
Ok(Self(value.to_string()))
}
}
impl ::std::convert::TryFrom<&str> for ExtKey {
type Error = self::error::ConversionError;
fn try_from(value: &str) -> ::std::result::Result<Self, self::error::ConversionError> {
value.parse()
}
}
impl ::std::convert::TryFrom<&::std::string::String> for ExtKey {
type Error = self::error::ConversionError;
fn try_from(
value: &::std::string::String,
) -> ::std::result::Result<Self, self::error::ConversionError> {
value.parse()
}
}
impl ::std::convert::TryFrom<::std::string::String> for ExtKey {
type Error = self::error::ConversionError;
fn try_from(
value: ::std::string::String,
) -> ::std::result::Result<Self, self::error::ConversionError> {
value.parse()
}
}
impl<'de> ::serde::Deserialize<'de> for ExtKey {
fn deserialize<D>(deserializer: D) -> ::std::result::Result<Self, D::Error>
where
D: ::serde::Deserializer<'de>,
{
::std::string::String::deserialize(deserializer)?
.parse()
.map_err(|e: self::error::ConversionError| {
<D::Error as ::serde::de::Error>::custom(e.to_string())
})
}
}
///A relying party asks an approver (typically a wallet or a VTA) to ratify an AAL elevation for a subject's session, or — bound to one operation — to approve that one act without elevating any session, and states which kinds of evidence it will accept, including a statement by one of the subject's bound step-up approvers.
///
/// <details><summary>JSON schema</summary>
///
/// ```json
///{
/// "$id": "https://trusttasks.org/spec/auth/step-up/approve-request/0.4",
/// "title": "Payload",
/// "description": "A relying party asks an approver (typically a wallet or a VTA) to ratify an AAL elevation for a subject's session, or — bound to one operation — to approve that one act without elevating any session, and states which kinds of evidence it will accept, including a statement by one of the subject's bound step-up approvers.",
/// "type": "object",
/// "required": [
/// "accepts",
/// "challenge",
/// "reason",
/// "subject"
/// ],
/// "properties": {
/// "accepts": {
/// "description": "Every approve-response evidence kind the relying party will accept for this step-up, and no other (see auth/step-up/approve-response/0.6 `evidence`). Replaces 0.3's optional `acceptableEvidence`. An approver that can satisfy none of them SHOULD refuse with `methodUnsupported`.",
/// "type": "array",
/// "items": {
/// "type": "string",
/// "enum": [
/// "webauthn",
/// "approverSigned",
/// "didSigned"
/// ]
/// },
/// "minItems": 1,
/// "uniqueItems": true
/// },
/// "approvers": {
/// "description": "The step-up approvers bound to `subject` that the relying party will accept a statement from (auth/step-up/approver/attest/0.1, purpose `stepUp`). Present exactly when `accepts` lists `approverSigned`. Names factors, not authorities: an approver confers nothing, and the relying party re-checks the binding when the statement arrives.",
/// "type": "array",
/// "items": {
/// "$ref": "#/definitions/ApproverDid"
/// },
/// "maxItems": 5,
/// "minItems": 1,
/// "uniqueItems": true
/// },
/// "boundTo": {
/// "description": "Present when the step-up authorizes exactly one operation rather than raising a session's assurance level. An opaque relying-party identifier for that operation — for an operation that arrived as a signed document, a digest of its type and payload salted with `challenge`. Copied into a step-up approver's statement, and echoed by a `recorded` approve-response acknowledgement. Not a capability: the binding is the relying party's own state.",
/// "type": "string",
/// "maxLength": 256,
/// "minLength": 1
/// },
/// "challenge": {
/// "description": "base64url-encoded nonce the approver will include in the approve-response signature, the WebAuthn assertion, or the step-up approver's statement. ≥128 bits entropy.",
/// "type": "string",
/// "minLength": 16
/// },
/// "ext": {
/// "$ref": "#/definitions/Ext"
/// },
/// "reason": {
/// "description": "Human-readable explanation of WHY the relying party is asking (e.g. \"confirm transfer of 1000 USD to bob.example\"). Surfaced to the user by the approver for consent. SHOULD be specific enough that a user can refuse intelligently.",
/// "type": "string",
/// "maxLength": 500,
/// "minLength": 1
/// },
/// "sessionId": {
/// "description": "The session the relying party wants elevated. Opaque to the approver. Absent only when the step-up is bound to one operation that arrived without a session (a signed Trust Task document, for instance); see `boundTo`.",
/// "type": "string",
/// "minLength": 1
/// },
/// "subject": {
/// "description": "The VID whose session is being elevated, or — for a step-up bound to one operation — the VID whose act that operation is. The approver MUST verify this is a VID it can speak for.",
/// "type": "string",
/// "minLength": 1
/// },
/// "targetAcr": {
/// "description": "The acr the relying party expects on the elevated session. Approvers MAY refuse if they cannot deliver this level.",
/// "type": "string"
/// },
/// "ttl": {
/// "description": "Seconds within which the relying party expects the approve-response. Approvers SHOULD treat as advisory — the relying party's own expiry policy is authoritative.",
/// "type": "integer",
/// "minimum": 1.0
/// },
/// "webauthn": {
/// "description": "WebAuthn `PublicKeyCredentialRequestOptions` the approver passes to the platform passkey API when producing `webauthn` evidence. Present exactly when `accepts` lists `webauthn`. Its `challenge` MUST equal `payload.challenge` so the resulting assertion binds the same nonce the relying party bound server-side.",
/// "$ref": "#/definitions/CredentialRequestOptions"
/// }
/// },
/// "additionalProperties": false
///}
/// ```
/// </details>
#[derive(::serde::Deserialize, ::serde::Serialize, Clone, Debug)]
#[serde(deny_unknown_fields)]
#[non_exhaustive]
pub struct Payload {
///Every approve-response evidence kind the relying party will accept for this step-up, and no other (see auth/step-up/approve-response/0.6 `evidence`). Replaces 0.3's optional `acceptableEvidence`. An approver that can satisfy none of them SHOULD refuse with `methodUnsupported`.
pub accepts: Vec<PayloadAcceptsItem>,
///The step-up approvers bound to `subject` that the relying party will accept a statement from (auth/step-up/approver/attest/0.1, purpose `stepUp`). Present exactly when `accepts` lists `approverSigned`. Names factors, not authorities: an approver confers nothing, and the relying party re-checks the binding when the statement arrives.
#[serde(default, skip_serializing_if = "::std::option::Option::is_none")]
pub approvers: ::std::option::Option<Vec<ApproverDid>>,
///Present when the step-up authorizes exactly one operation rather than raising a session's assurance level. An opaque relying-party identifier for that operation — for an operation that arrived as a signed document, a digest of its type and payload salted with `challenge`. Copied into a step-up approver's statement, and echoed by a `recorded` approve-response acknowledgement. Not a capability: the binding is the relying party's own state.
#[serde(
rename = "boundTo",
default,
skip_serializing_if = "::std::option::Option::is_none"
)]
pub bound_to: ::std::option::Option<PayloadBoundTo>,
///base64url-encoded nonce the approver will include in the approve-response signature, the WebAuthn assertion, or the step-up approver's statement. ≥128 bits entropy.
pub challenge: PayloadChallenge,
#[serde(default, skip_serializing_if = "::std::option::Option::is_none")]
pub ext: ::std::option::Option<Ext>,
///Human-readable explanation of WHY the relying party is asking (e.g. "confirm transfer of 1000 USD to bob.example"). Surfaced to the user by the approver for consent. SHOULD be specific enough that a user can refuse intelligently.
pub reason: PayloadReason,
///The session the relying party wants elevated. Opaque to the approver. Absent only when the step-up is bound to one operation that arrived without a session (a signed Trust Task document, for instance); see `boundTo`.
#[serde(
rename = "sessionId",
default,
skip_serializing_if = "::std::option::Option::is_none"
)]
pub session_id: ::std::option::Option<PayloadSessionId>,
///The VID whose session is being elevated, or — for a step-up bound to one operation — the VID whose act that operation is. The approver MUST verify this is a VID it can speak for.
pub subject: PayloadSubject,
///The acr the relying party expects on the elevated session. Approvers MAY refuse if they cannot deliver this level.
#[serde(
rename = "targetAcr",
default,
skip_serializing_if = "::std::option::Option::is_none"
)]
pub target_acr: ::std::option::Option<::std::string::String>,
///Seconds within which the relying party expects the approve-response. Approvers SHOULD treat as advisory — the relying party's own expiry policy is authoritative.
#[serde(default, skip_serializing_if = "::std::option::Option::is_none")]
pub ttl: ::std::option::Option<::std::num::NonZeroU64>,
///WebAuthn `PublicKeyCredentialRequestOptions` the approver passes to the platform passkey API when producing `webauthn` evidence. Present exactly when `accepts` lists `webauthn`. Its `challenge` MUST equal `payload.challenge` so the resulting assertion binds the same nonce the relying party bound server-side.
#[serde(default, skip_serializing_if = "::std::option::Option::is_none")]
pub webauthn: ::std::option::Option<CredentialRequestOptions>,
}
impl Payload {
pub fn builder() -> builder::Payload {
Default::default()
}
}
///`PayloadAcceptsItem`
///
/// <details><summary>JSON schema</summary>
///
/// ```json
///{
/// "type": "string",
/// "enum": [
/// "webauthn",
/// "approverSigned",
/// "didSigned"
/// ]
///}
/// ```
/// </details>
#[derive(
::serde::Deserialize,
::serde::Serialize,
Clone,
Copy,
Debug,
Eq,
Hash,
Ord,
PartialEq,
PartialOrd,
)]
#[non_exhaustive]
pub enum PayloadAcceptsItem {
#[serde(rename = "webauthn")]
Webauthn,
#[serde(rename = "approverSigned")]
ApproverSigned,
#[serde(rename = "didSigned")]
DidSigned,
}
impl ::std::fmt::Display for PayloadAcceptsItem {
fn fmt(&self, f: &mut ::std::fmt::Formatter<'_>) -> ::std::fmt::Result {
match *self {
Self::Webauthn => f.write_str("webauthn"),
Self::ApproverSigned => f.write_str("approverSigned"),
Self::DidSigned => f.write_str("didSigned"),
}
}
}
impl ::std::str::FromStr for PayloadAcceptsItem {
type Err = self::error::ConversionError;
fn from_str(value: &str) -> ::std::result::Result<Self, self::error::ConversionError> {
match value {
"webauthn" => Ok(Self::Webauthn),
"approverSigned" => Ok(Self::ApproverSigned),
"didSigned" => Ok(Self::DidSigned),
_ => Err("invalid value".into()),
}
}
}
impl ::std::convert::TryFrom<&str> for PayloadAcceptsItem {
type Error = self::error::ConversionError;
fn try_from(value: &str) -> ::std::result::Result<Self, self::error::ConversionError> {
value.parse()
}
}
impl ::std::convert::TryFrom<&::std::string::String> for PayloadAcceptsItem {
type Error = self::error::ConversionError;
fn try_from(
value: &::std::string::String,
) -> ::std::result::Result<Self, self::error::ConversionError> {
value.parse()
}
}
impl ::std::convert::TryFrom<::std::string::String> for PayloadAcceptsItem {
type Error = self::error::ConversionError;
fn try_from(
value: ::std::string::String,
) -> ::std::result::Result<Self, self::error::ConversionError> {
value.parse()
}
}
///Present when the step-up authorizes exactly one operation rather than raising a session's assurance level. An opaque relying-party identifier for that operation — for an operation that arrived as a signed document, a digest of its type and payload salted with `challenge`. Copied into a step-up approver's statement, and echoed by a `recorded` approve-response acknowledgement. Not a capability: the binding is the relying party's own state.
///
/// <details><summary>JSON schema</summary>
///
/// ```json
///{
/// "description": "Present when the step-up authorizes exactly one operation rather than raising a session's assurance level. An opaque relying-party identifier for that operation — for an operation that arrived as a signed document, a digest of its type and payload salted with `challenge`. Copied into a step-up approver's statement, and echoed by a `recorded` approve-response acknowledgement. Not a capability: the binding is the relying party's own state.",
/// "type": "string",
/// "maxLength": 256,
/// "minLength": 1
///}
/// ```
/// </details>
#[derive(::serde::Serialize, Clone, Debug, Eq, Hash, Ord, PartialEq, PartialOrd)]
#[serde(transparent)]
pub struct PayloadBoundTo(::std::string::String);
impl ::std::ops::Deref for PayloadBoundTo {
type Target = ::std::string::String;
fn deref(&self) -> &::std::string::String {
&self.0
}
}
impl ::std::convert::From<PayloadBoundTo> for ::std::string::String {
fn from(value: PayloadBoundTo) -> Self {
value.0
}
}
impl ::std::str::FromStr for PayloadBoundTo {
type Err = self::error::ConversionError;
fn from_str(value: &str) -> ::std::result::Result<Self, self::error::ConversionError> {
if value.chars().count() > 256usize {
return Err("longer than 256 characters".into());
}
if value.chars().count() < 1usize {
return Err("shorter than 1 characters".into());
}
Ok(Self(value.to_string()))
}
}
impl ::std::convert::TryFrom<&str> for PayloadBoundTo {
type Error = self::error::ConversionError;
fn try_from(value: &str) -> ::std::result::Result<Self, self::error::ConversionError> {
value.parse()
}
}
impl ::std::convert::TryFrom<&::std::string::String> for PayloadBoundTo {
type Error = self::error::ConversionError;
fn try_from(
value: &::std::string::String,
) -> ::std::result::Result<Self, self::error::ConversionError> {
value.parse()
}
}
impl ::std::convert::TryFrom<::std::string::String> for PayloadBoundTo {
type Error = self::error::ConversionError;
fn try_from(
value: ::std::string::String,
) -> ::std::result::Result<Self, self::error::ConversionError> {
value.parse()
}
}
impl<'de> ::serde::Deserialize<'de> for PayloadBoundTo {
fn deserialize<D>(deserializer: D) -> ::std::result::Result<Self, D::Error>
where
D: ::serde::Deserializer<'de>,
{
::std::string::String::deserialize(deserializer)?
.parse()
.map_err(|e: self::error::ConversionError| {
<D::Error as ::serde::de::Error>::custom(e.to_string())
})
}
}
///base64url-encoded nonce the approver will include in the approve-response signature, the WebAuthn assertion, or the step-up approver's statement. ≥128 bits entropy.
///
/// <details><summary>JSON schema</summary>
///
/// ```json
///{
/// "description": "base64url-encoded nonce the approver will include in the approve-response signature, the WebAuthn assertion, or the step-up approver's statement. ≥128 bits entropy.",
/// "type": "string",
/// "minLength": 16
///}
/// ```
/// </details>
#[derive(::serde::Serialize, Clone, Debug, Eq, Hash, Ord, PartialEq, PartialOrd)]
#[serde(transparent)]
pub struct PayloadChallenge(::std::string::String);
impl ::std::ops::Deref for PayloadChallenge {
type Target = ::std::string::String;
fn deref(&self) -> &::std::string::String {
&self.0
}
}
impl ::std::convert::From<PayloadChallenge> for ::std::string::String {
fn from(value: PayloadChallenge) -> Self {
value.0
}
}
impl ::std::str::FromStr for PayloadChallenge {
type Err = self::error::ConversionError;
fn from_str(value: &str) -> ::std::result::Result<Self, self::error::ConversionError> {
if value.chars().count() < 16usize {
return Err("shorter than 16 characters".into());
}
Ok(Self(value.to_string()))
}
}
impl ::std::convert::TryFrom<&str> for PayloadChallenge {
type Error = self::error::ConversionError;
fn try_from(value: &str) -> ::std::result::Result<Self, self::error::ConversionError> {
value.parse()
}
}
impl ::std::convert::TryFrom<&::std::string::String> for PayloadChallenge {
type Error = self::error::ConversionError;
fn try_from(
value: &::std::string::String,
) -> ::std::result::Result<Self, self::error::ConversionError> {
value.parse()
}
}
impl ::std::convert::TryFrom<::std::string::String> for PayloadChallenge {
type Error = self::error::ConversionError;
fn try_from(
value: ::std::string::String,
) -> ::std::result::Result<Self, self::error::ConversionError> {
value.parse()
}
}
impl<'de> ::serde::Deserialize<'de> for PayloadChallenge {
fn deserialize<D>(deserializer: D) -> ::std::result::Result<Self, D::Error>
where
D: ::serde::Deserializer<'de>,
{
::std::string::String::deserialize(deserializer)?
.parse()
.map_err(|e: self::error::ConversionError| {
<D::Error as ::serde::de::Error>::custom(e.to_string())
})
}
}
///Human-readable explanation of WHY the relying party is asking (e.g. "confirm transfer of 1000 USD to bob.example"). Surfaced to the user by the approver for consent. SHOULD be specific enough that a user can refuse intelligently.
///
/// <details><summary>JSON schema</summary>
///
/// ```json
///{
/// "description": "Human-readable explanation of WHY the relying party is asking (e.g. \"confirm transfer of 1000 USD to bob.example\"). Surfaced to the user by the approver for consent. SHOULD be specific enough that a user can refuse intelligently.",
/// "type": "string",
/// "maxLength": 500,
/// "minLength": 1
///}
/// ```
/// </details>
#[derive(::serde::Serialize, Clone, Debug, Eq, Hash, Ord, PartialEq, PartialOrd)]
#[serde(transparent)]
pub struct PayloadReason(::std::string::String);
impl ::std::ops::Deref for PayloadReason {
type Target = ::std::string::String;
fn deref(&self) -> &::std::string::String {
&self.0
}
}
impl ::std::convert::From<PayloadReason> for ::std::string::String {
fn from(value: PayloadReason) -> Self {
value.0
}
}
impl ::std::str::FromStr for PayloadReason {
type Err = self::error::ConversionError;
fn from_str(value: &str) -> ::std::result::Result<Self, self::error::ConversionError> {
if value.chars().count() > 500usize {
return Err("longer than 500 characters".into());
}
if value.chars().count() < 1usize {
return Err("shorter than 1 characters".into());
}
Ok(Self(value.to_string()))
}
}
impl ::std::convert::TryFrom<&str> for PayloadReason {
type Error = self::error::ConversionError;
fn try_from(value: &str) -> ::std::result::Result<Self, self::error::ConversionError> {
value.parse()
}
}
impl ::std::convert::TryFrom<&::std::string::String> for PayloadReason {
type Error = self::error::ConversionError;
fn try_from(
value: &::std::string::String,
) -> ::std::result::Result<Self, self::error::ConversionError> {
value.parse()
}
}
impl ::std::convert::TryFrom<::std::string::String> for PayloadReason {
type Error = self::error::ConversionError;
fn try_from(
value: ::std::string::String,
) -> ::std::result::Result<Self, self::error::ConversionError> {
value.parse()
}
}
impl<'de> ::serde::Deserialize<'de> for PayloadReason {
fn deserialize<D>(deserializer: D) -> ::std::result::Result<Self, D::Error>
where
D: ::serde::Deserializer<'de>,
{
::std::string::String::deserialize(deserializer)?
.parse()
.map_err(|e: self::error::ConversionError| {
<D::Error as ::serde::de::Error>::custom(e.to_string())
})
}
}
///The session the relying party wants elevated. Opaque to the approver. Absent only when the step-up is bound to one operation that arrived without a session (a signed Trust Task document, for instance); see `boundTo`.
///
/// <details><summary>JSON schema</summary>
///
/// ```json
///{
/// "description": "The session the relying party wants elevated. Opaque to the approver. Absent only when the step-up is bound to one operation that arrived without a session (a signed Trust Task document, for instance); see `boundTo`.",
/// "type": "string",
/// "minLength": 1
///}
/// ```
/// </details>
#[derive(::serde::Serialize, Clone, Debug, Eq, Hash, Ord, PartialEq, PartialOrd)]
#[serde(transparent)]
pub struct PayloadSessionId(::std::string::String);
impl ::std::ops::Deref for PayloadSessionId {
type Target = ::std::string::String;
fn deref(&self) -> &::std::string::String {
&self.0
}
}
impl ::std::convert::From<PayloadSessionId> for ::std::string::String {
fn from(value: PayloadSessionId) -> Self {
value.0
}
}
impl ::std::str::FromStr for PayloadSessionId {
type Err = self::error::ConversionError;
fn from_str(value: &str) -> ::std::result::Result<Self, self::error::ConversionError> {
if value.chars().count() < 1usize {
return Err("shorter than 1 characters".into());
}
Ok(Self(value.to_string()))
}
}
impl ::std::convert::TryFrom<&str> for PayloadSessionId {
type Error = self::error::ConversionError;
fn try_from(value: &str) -> ::std::result::Result<Self, self::error::ConversionError> {
value.parse()
}
}
impl ::std::convert::TryFrom<&::std::string::String> for PayloadSessionId {
type Error = self::error::ConversionError;
fn try_from(
value: &::std::string::String,
) -> ::std::result::Result<Self, self::error::ConversionError> {
value.parse()
}
}
impl ::std::convert::TryFrom<::std::string::String> for PayloadSessionId {
type Error = self::error::ConversionError;
fn try_from(
value: ::std::string::String,
) -> ::std::result::Result<Self, self::error::ConversionError> {
value.parse()
}
}
impl<'de> ::serde::Deserialize<'de> for PayloadSessionId {
fn deserialize<D>(deserializer: D) -> ::std::result::Result<Self, D::Error>
where
D: ::serde::Deserializer<'de>,
{
::std::string::String::deserialize(deserializer)?
.parse()
.map_err(|e: self::error::ConversionError| {
<D::Error as ::serde::de::Error>::custom(e.to_string())
})
}
}
///The VID whose session is being elevated, or — for a step-up bound to one operation — the VID whose act that operation is. The approver MUST verify this is a VID it can speak for.
///
/// <details><summary>JSON schema</summary>
///
/// ```json
///{
/// "description": "The VID whose session is being elevated, or — for a step-up bound to one operation — the VID whose act that operation is. The approver MUST verify this is a VID it can speak for.",
/// "type": "string",
/// "minLength": 1
///}
/// ```
/// </details>
#[derive(::serde::Serialize, Clone, Debug, Eq, Hash, Ord, PartialEq, PartialOrd)]
#[serde(transparent)]
pub struct PayloadSubject(::std::string::String);
impl ::std::ops::Deref for PayloadSubject {
type Target = ::std::string::String;
fn deref(&self) -> &::std::string::String {
&self.0
}
}
impl ::std::convert::From<PayloadSubject> for ::std::string::String {
fn from(value: PayloadSubject) -> Self {
value.0
}
}
impl ::std::str::FromStr for PayloadSubject {
type Err = self::error::ConversionError;
fn from_str(value: &str) -> ::std::result::Result<Self, self::error::ConversionError> {
if value.chars().count() < 1usize {
return Err("shorter than 1 characters".into());
}
Ok(Self(value.to_string()))
}
}
impl ::std::convert::TryFrom<&str> for PayloadSubject {
type Error = self::error::ConversionError;
fn try_from(value: &str) -> ::std::result::Result<Self, self::error::ConversionError> {
value.parse()
}
}
impl ::std::convert::TryFrom<&::std::string::String> for PayloadSubject {
type Error = self::error::ConversionError;
fn try_from(
value: &::std::string::String,
) -> ::std::result::Result<Self, self::error::ConversionError> {
value.parse()
}
}
impl ::std::convert::TryFrom<::std::string::String> for PayloadSubject {
type Error = self::error::ConversionError;
fn try_from(
value: ::std::string::String,
) -> ::std::result::Result<Self, self::error::ConversionError> {
value.parse()
}
}
impl<'de> ::serde::Deserialize<'de> for PayloadSubject {
fn deserialize<D>(deserializer: D) -> ::std::result::Result<Self, D::Error>
where
D: ::serde::Deserializer<'de>,
{
::std::string::String::deserialize(deserializer)?
.parse()
.map_err(|e: self::error::ConversionError| {
<D::Error as ::serde::de::Error>::custom(e.to_string())
})
}
}
///Synchronous ack from the approver acknowledging it received the request and will (or will not) deliver an approve-response. Carried in a Trust Task document whose type is https://trusttasks.org/spec/auth/step-up/approve-request/0.4#response.
///
/// <details><summary>JSON schema</summary>
///
/// ```json
///{
/// "title": "Response",
/// "description": "Synchronous ack from the approver acknowledging it received the request and will (or will not) deliver an approve-response. Carried in a Trust Task document whose type is https://trusttasks.org/spec/auth/step-up/approve-request/0.4#response.",
/// "type": "object",
/// "required": [
/// "status"
/// ],
/// "properties": {
/// "ext": {
/// "$ref": "#/definitions/Ext"
/// },
/// "reason": {
/// "description": "Required when status is `refused`.",
/// "type": "string",
/// "maxLength": 1024
/// },
/// "status": {
/// "description": "`accepted` means the approver received the request and will return an approve-response (typically via DIDComm). `refused` means it will not — `reason` MUST be set.",
/// "type": "string",
/// "enum": [
/// "accepted",
/// "refused"
/// ]
/// }
/// },
/// "additionalProperties": false,
/// "$anchor": "response"
///}
/// ```
/// </details>
#[derive(::serde::Deserialize, ::serde::Serialize, Clone, Debug)]
#[serde(deny_unknown_fields)]
#[non_exhaustive]
pub struct Response {
#[serde(default, skip_serializing_if = "::std::option::Option::is_none")]
pub ext: ::std::option::Option<Ext>,
///Required when status is `refused`.
#[serde(default, skip_serializing_if = "::std::option::Option::is_none")]
pub reason: ::std::option::Option<ResponseReason>,
///`accepted` means the approver received the request and will return an approve-response (typically via DIDComm). `refused` means it will not — `reason` MUST be set.
pub status: ResponseStatus,
}
impl Response {
pub fn builder() -> builder::Response {
Default::default()
}
}
///Required when status is `refused`.
///
/// <details><summary>JSON schema</summary>
///
/// ```json
///{
/// "description": "Required when status is `refused`.",
/// "type": "string",
/// "maxLength": 1024
///}
/// ```
/// </details>
#[derive(::serde::Serialize, Clone, Debug, Eq, Hash, Ord, PartialEq, PartialOrd)]
#[serde(transparent)]
pub struct ResponseReason(::std::string::String);
impl ::std::ops::Deref for ResponseReason {
type Target = ::std::string::String;
fn deref(&self) -> &::std::string::String {
&self.0
}
}
impl ::std::convert::From<ResponseReason> for ::std::string::String {
fn from(value: ResponseReason) -> Self {
value.0
}
}
impl ::std::str::FromStr for ResponseReason {
type Err = self::error::ConversionError;
fn from_str(value: &str) -> ::std::result::Result<Self, self::error::ConversionError> {
if value.chars().count() > 1024usize {
return Err("longer than 1024 characters".into());
}
Ok(Self(value.to_string()))
}
}
impl ::std::convert::TryFrom<&str> for ResponseReason {
type Error = self::error::ConversionError;
fn try_from(value: &str) -> ::std::result::Result<Self, self::error::ConversionError> {
value.parse()
}
}
impl ::std::convert::TryFrom<&::std::string::String> for ResponseReason {
type Error = self::error::ConversionError;
fn try_from(
value: &::std::string::String,
) -> ::std::result::Result<Self, self::error::ConversionError> {
value.parse()
}
}
impl ::std::convert::TryFrom<::std::string::String> for ResponseReason {
type Error = self::error::ConversionError;
fn try_from(
value: ::std::string::String,
) -> ::std::result::Result<Self, self::error::ConversionError> {
value.parse()
}
}
impl<'de> ::serde::Deserialize<'de> for ResponseReason {
fn deserialize<D>(deserializer: D) -> ::std::result::Result<Self, D::Error>
where
D: ::serde::Deserializer<'de>,
{
::std::string::String::deserialize(deserializer)?
.parse()
.map_err(|e: self::error::ConversionError| {
<D::Error as ::serde::de::Error>::custom(e.to_string())
})
}
}
///`accepted` means the approver received the request and will return an approve-response (typically via DIDComm). `refused` means it will not — `reason` MUST be set.
///
/// <details><summary>JSON schema</summary>
///
/// ```json
///{
/// "description": "`accepted` means the approver received the request and will return an approve-response (typically via DIDComm). `refused` means it will not — `reason` MUST be set.",
/// "type": "string",
/// "enum": [
/// "accepted",
/// "refused"
/// ]
///}
/// ```
/// </details>
#[derive(
::serde::Deserialize,
::serde::Serialize,
Clone,
Copy,
Debug,
Eq,
Hash,
Ord,
PartialEq,
PartialOrd,
)]
#[non_exhaustive]
pub enum ResponseStatus {
#[serde(rename = "accepted")]
Accepted,
#[serde(rename = "refused")]
Refused,
}
impl ::std::fmt::Display for ResponseStatus {
fn fmt(&self, f: &mut ::std::fmt::Formatter<'_>) -> ::std::fmt::Result {
match *self {
Self::Accepted => f.write_str("accepted"),
Self::Refused => f.write_str("refused"),
}
}
}
impl ::std::str::FromStr for ResponseStatus {
type Err = self::error::ConversionError;
fn from_str(value: &str) -> ::std::result::Result<Self, self::error::ConversionError> {
match value {
"accepted" => Ok(Self::Accepted),
"refused" => Ok(Self::Refused),
_ => Err("invalid value".into()),
}
}
}
impl ::std::convert::TryFrom<&str> for ResponseStatus {
type Error = self::error::ConversionError;
fn try_from(value: &str) -> ::std::result::Result<Self, self::error::ConversionError> {
value.parse()
}
}
impl ::std::convert::TryFrom<&::std::string::String> for ResponseStatus {
type Error = self::error::ConversionError;
fn try_from(
value: &::std::string::String,
) -> ::std::result::Result<Self, self::error::ConversionError> {
value.parse()
}
}
impl ::std::convert::TryFrom<::std::string::String> for ResponseStatus {
type Error = self::error::ConversionError;
fn try_from(
value: ::std::string::String,
) -> ::std::result::Result<Self, self::error::ConversionError> {
value.parse()
}
}
/// Types for composing complex structures.
pub mod builder {
#[derive(Clone, Debug)]
pub struct CredentialDescriptor {
id: ::std::result::Result<::std::string::String, ::std::string::String>,
transports: ::std::result::Result<
::std::vec::Vec<super::CredentialDescriptorTransportsItem>,
::std::string::String,
>,
type_: ::std::result::Result<::serde_json::Value, ::std::string::String>,
}
impl ::std::default::Default for CredentialDescriptor {
fn default() -> Self {
Self {
id: Err("no value supplied for id".to_string()),
transports: Ok(Default::default()),
type_: Err("no value supplied for type_".to_string()),
}
}
}
impl CredentialDescriptor {
pub fn id<T>(mut self, value: T) -> Self
where
T: ::std::convert::TryInto<::std::string::String>,
T::Error: ::std::fmt::Display,
{
self.id = value
.try_into()
.map_err(|e| format!("error converting supplied value for id: {e}"));
self
}
pub fn transports<T>(mut self, value: T) -> Self
where
T: ::std::convert::TryInto<::std::vec::Vec<super::CredentialDescriptorTransportsItem>>,
T::Error: ::std::fmt::Display,
{
self.transports = value
.try_into()
.map_err(|e| format!("error converting supplied value for transports: {e}"));
self
}
pub fn type_<T>(mut self, value: T) -> Self
where
T: ::std::convert::TryInto<::serde_json::Value>,
T::Error: ::std::fmt::Display,
{
self.type_ = value
.try_into()
.map_err(|e| format!("error converting supplied value for type_: {e}"));
self
}
}
impl ::std::convert::TryFrom<CredentialDescriptor> for super::CredentialDescriptor {
type Error = super::error::ConversionError;
fn try_from(
value: CredentialDescriptor,
) -> ::std::result::Result<Self, super::error::ConversionError> {
Ok(Self {
id: value.id?,
transports: value.transports?,
type_: value.type_?,
})
}
}
impl ::std::convert::From<super::CredentialDescriptor> for CredentialDescriptor {
fn from(value: super::CredentialDescriptor) -> Self {
Self {
id: Ok(value.id),
transports: Ok(value.transports),
type_: Ok(value.type_),
}
}
}
#[derive(Clone, Debug)]
pub struct CredentialRequestOptions {
allow_credentials: ::std::result::Result<
::std::vec::Vec<super::CredentialDescriptor>,
::std::string::String,
>,
challenge: ::std::result::Result<::std::string::String, ::std::string::String>,
extensions: ::std::result::Result<
::serde_json::Map<::std::string::String, ::serde_json::Value>,
::std::string::String,
>,
rp_id: ::std::result::Result<
::std::option::Option<super::CredentialRequestOptionsRpId>,
::std::string::String,
>,
timeout: ::std::result::Result<
::std::option::Option<::std::num::NonZeroU64>,
::std::string::String,
>,
user_verification: ::std::result::Result<
::std::option::Option<super::CredentialRequestOptionsUserVerification>,
::std::string::String,
>,
}
impl ::std::default::Default for CredentialRequestOptions {
fn default() -> Self {
Self {
allow_credentials: Ok(Default::default()),
challenge: Err("no value supplied for challenge".to_string()),
extensions: Ok(Default::default()),
rp_id: Ok(Default::default()),
timeout: Ok(Default::default()),
user_verification: Ok(Default::default()),
}
}
}
impl CredentialRequestOptions {
pub fn allow_credentials<T>(mut self, value: T) -> Self
where
T: ::std::convert::TryInto<::std::vec::Vec<super::CredentialDescriptor>>,
T::Error: ::std::fmt::Display,
{
self.allow_credentials = value
.try_into()
.map_err(|e| format!("error converting supplied value for allow_credentials: {e}"));
self
}
pub fn challenge<T>(mut self, value: T) -> Self
where
T: ::std::convert::TryInto<::std::string::String>,
T::Error: ::std::fmt::Display,
{
self.challenge = value
.try_into()
.map_err(|e| format!("error converting supplied value for challenge: {e}"));
self
}
pub fn extensions<T>(mut self, value: T) -> Self
where
T: ::std::convert::TryInto<
::serde_json::Map<::std::string::String, ::serde_json::Value>,
>,
T::Error: ::std::fmt::Display,
{
self.extensions = value
.try_into()
.map_err(|e| format!("error converting supplied value for extensions: {e}"));
self
}
pub fn rp_id<T>(mut self, value: T) -> Self
where
T: ::std::convert::TryInto<::std::option::Option<super::CredentialRequestOptionsRpId>>,
T::Error: ::std::fmt::Display,
{
self.rp_id = value
.try_into()
.map_err(|e| format!("error converting supplied value for rp_id: {e}"));
self
}
pub fn timeout<T>(mut self, value: T) -> Self
where
T: ::std::convert::TryInto<::std::option::Option<::std::num::NonZeroU64>>,
T::Error: ::std::fmt::Display,
{
self.timeout = value
.try_into()
.map_err(|e| format!("error converting supplied value for timeout: {e}"));
self
}
pub fn user_verification<T>(mut self, value: T) -> Self
where
T: ::std::convert::TryInto<
::std::option::Option<super::CredentialRequestOptionsUserVerification>,
>,
T::Error: ::std::fmt::Display,
{
self.user_verification = value
.try_into()
.map_err(|e| format!("error converting supplied value for user_verification: {e}"));
self
}
}
impl ::std::convert::TryFrom<CredentialRequestOptions> for super::CredentialRequestOptions {
type Error = super::error::ConversionError;
fn try_from(
value: CredentialRequestOptions,
) -> ::std::result::Result<Self, super::error::ConversionError> {
Ok(Self {
allow_credentials: value.allow_credentials?,
challenge: value.challenge?,
extensions: value.extensions?,
rp_id: value.rp_id?,
timeout: value.timeout?,
user_verification: value.user_verification?,
})
}
}
impl ::std::convert::From<super::CredentialRequestOptions> for CredentialRequestOptions {
fn from(value: super::CredentialRequestOptions) -> Self {
Self {
allow_credentials: Ok(value.allow_credentials),
challenge: Ok(value.challenge),
extensions: Ok(value.extensions),
rp_id: Ok(value.rp_id),
timeout: Ok(value.timeout),
user_verification: Ok(value.user_verification),
}
}
}
#[derive(Clone, Debug)]
pub struct Payload {
accepts: ::std::result::Result<Vec<super::PayloadAcceptsItem>, ::std::string::String>,
approvers: ::std::result::Result<
::std::option::Option<Vec<super::ApproverDid>>,
::std::string::String,
>,
bound_to: ::std::result::Result<
::std::option::Option<super::PayloadBoundTo>,
::std::string::String,
>,
challenge: ::std::result::Result<super::PayloadChallenge, ::std::string::String>,
ext: ::std::result::Result<::std::option::Option<super::Ext>, ::std::string::String>,
reason: ::std::result::Result<super::PayloadReason, ::std::string::String>,
session_id: ::std::result::Result<
::std::option::Option<super::PayloadSessionId>,
::std::string::String,
>,
subject: ::std::result::Result<super::PayloadSubject, ::std::string::String>,
target_acr: ::std::result::Result<
::std::option::Option<::std::string::String>,
::std::string::String,
>,
ttl: ::std::result::Result<
::std::option::Option<::std::num::NonZeroU64>,
::std::string::String,
>,
webauthn: ::std::result::Result<
::std::option::Option<super::CredentialRequestOptions>,
::std::string::String,
>,
}
impl ::std::default::Default for Payload {
fn default() -> Self {
Self {
accepts: Err("no value supplied for accepts".to_string()),
approvers: Ok(Default::default()),
bound_to: Ok(Default::default()),
challenge: Err("no value supplied for challenge".to_string()),
ext: Ok(Default::default()),
reason: Err("no value supplied for reason".to_string()),
session_id: Ok(Default::default()),
subject: Err("no value supplied for subject".to_string()),
target_acr: Ok(Default::default()),
ttl: Ok(Default::default()),
webauthn: Ok(Default::default()),
}
}
}
impl Payload {
pub fn accepts<T>(mut self, value: T) -> Self
where
T: ::std::convert::TryInto<Vec<super::PayloadAcceptsItem>>,
T::Error: ::std::fmt::Display,
{
self.accepts = value
.try_into()
.map_err(|e| format!("error converting supplied value for accepts: {e}"));
self
}
pub fn approvers<T>(mut self, value: T) -> Self
where
T: ::std::convert::TryInto<::std::option::Option<Vec<super::ApproverDid>>>,
T::Error: ::std::fmt::Display,
{
self.approvers = value
.try_into()
.map_err(|e| format!("error converting supplied value for approvers: {e}"));
self
}
pub fn bound_to<T>(mut self, value: T) -> Self
where
T: ::std::convert::TryInto<::std::option::Option<super::PayloadBoundTo>>,
T::Error: ::std::fmt::Display,
{
self.bound_to = value
.try_into()
.map_err(|e| format!("error converting supplied value for bound_to: {e}"));
self
}
pub fn challenge<T>(mut self, value: T) -> Self
where
T: ::std::convert::TryInto<super::PayloadChallenge>,
T::Error: ::std::fmt::Display,
{
self.challenge = value
.try_into()
.map_err(|e| format!("error converting supplied value for challenge: {e}"));
self
}
pub fn ext<T>(mut self, value: T) -> Self
where
T: ::std::convert::TryInto<::std::option::Option<super::Ext>>,
T::Error: ::std::fmt::Display,
{
self.ext = value
.try_into()
.map_err(|e| format!("error converting supplied value for ext: {e}"));
self
}
pub fn reason<T>(mut self, value: T) -> Self
where
T: ::std::convert::TryInto<super::PayloadReason>,
T::Error: ::std::fmt::Display,
{
self.reason = value
.try_into()
.map_err(|e| format!("error converting supplied value for reason: {e}"));
self
}
pub fn session_id<T>(mut self, value: T) -> Self
where
T: ::std::convert::TryInto<::std::option::Option<super::PayloadSessionId>>,
T::Error: ::std::fmt::Display,
{
self.session_id = value
.try_into()
.map_err(|e| format!("error converting supplied value for session_id: {e}"));
self
}
pub fn subject<T>(mut self, value: T) -> Self
where
T: ::std::convert::TryInto<super::PayloadSubject>,
T::Error: ::std::fmt::Display,
{
self.subject = value
.try_into()
.map_err(|e| format!("error converting supplied value for subject: {e}"));
self
}
pub fn target_acr<T>(mut self, value: T) -> Self
where
T: ::std::convert::TryInto<::std::option::Option<::std::string::String>>,
T::Error: ::std::fmt::Display,
{
self.target_acr = value
.try_into()
.map_err(|e| format!("error converting supplied value for target_acr: {e}"));
self
}
pub fn ttl<T>(mut self, value: T) -> Self
where
T: ::std::convert::TryInto<::std::option::Option<::std::num::NonZeroU64>>,
T::Error: ::std::fmt::Display,
{
self.ttl = value
.try_into()
.map_err(|e| format!("error converting supplied value for ttl: {e}"));
self
}
pub fn webauthn<T>(mut self, value: T) -> Self
where
T: ::std::convert::TryInto<::std::option::Option<super::CredentialRequestOptions>>,
T::Error: ::std::fmt::Display,
{
self.webauthn = value
.try_into()
.map_err(|e| format!("error converting supplied value for webauthn: {e}"));
self
}
}
impl ::std::convert::TryFrom<Payload> for super::Payload {
type Error = super::error::ConversionError;
fn try_from(value: Payload) -> ::std::result::Result<Self, super::error::ConversionError> {
Ok(Self {
accepts: value.accepts?,
approvers: value.approvers?,
bound_to: value.bound_to?,
challenge: value.challenge?,
ext: value.ext?,
reason: value.reason?,
session_id: value.session_id?,
subject: value.subject?,
target_acr: value.target_acr?,
ttl: value.ttl?,
webauthn: value.webauthn?,
})
}
}
impl ::std::convert::From<super::Payload> for Payload {
fn from(value: super::Payload) -> Self {
Self {
accepts: Ok(value.accepts),
approvers: Ok(value.approvers),
bound_to: Ok(value.bound_to),
challenge: Ok(value.challenge),
ext: Ok(value.ext),
reason: Ok(value.reason),
session_id: Ok(value.session_id),
subject: Ok(value.subject),
target_acr: Ok(value.target_acr),
ttl: Ok(value.ttl),
webauthn: Ok(value.webauthn),
}
}
}
#[derive(Clone, Debug)]
pub struct Response {
ext: ::std::result::Result<::std::option::Option<super::Ext>, ::std::string::String>,
reason: ::std::result::Result<
::std::option::Option<super::ResponseReason>,
::std::string::String,
>,
status: ::std::result::Result<super::ResponseStatus, ::std::string::String>,
}
impl ::std::default::Default for Response {
fn default() -> Self {
Self {
ext: Ok(Default::default()),
reason: Ok(Default::default()),
status: Err("no value supplied for status".to_string()),
}
}
}
impl Response {
pub fn ext<T>(mut self, value: T) -> Self
where
T: ::std::convert::TryInto<::std::option::Option<super::Ext>>,
T::Error: ::std::fmt::Display,
{
self.ext = value
.try_into()
.map_err(|e| format!("error converting supplied value for ext: {e}"));
self
}
pub fn reason<T>(mut self, value: T) -> Self
where
T: ::std::convert::TryInto<::std::option::Option<super::ResponseReason>>,
T::Error: ::std::fmt::Display,
{
self.reason = value
.try_into()
.map_err(|e| format!("error converting supplied value for reason: {e}"));
self
}
pub fn status<T>(mut self, value: T) -> Self
where
T: ::std::convert::TryInto<super::ResponseStatus>,
T::Error: ::std::fmt::Display,
{
self.status = value
.try_into()
.map_err(|e| format!("error converting supplied value for status: {e}"));
self
}
}
impl ::std::convert::TryFrom<Response> for super::Response {
type Error = super::error::ConversionError;
fn try_from(value: Response) -> ::std::result::Result<Self, super::error::ConversionError> {
Ok(Self {
ext: value.ext?,
reason: value.reason?,
status: value.status?,
})
}
}
impl ::std::convert::From<super::Response> for Response {
fn from(value: super::Response) -> Self {
Self {
ext: Ok(value.ext),
reason: Ok(value.reason),
status: Ok(value.status),
}
}
}
}
impl crate::Payload for Payload {
const TYPE_URI: &'static str = "https://trusttasks.org/spec/auth/step-up/approve-request/0.4";
const IS_PROOF_REQUIRED: bool = true;
const IS_RECIPIENT_REQUIRED: bool = true;
const PAYLOAD_SCHEMA: Option<&'static str> = Some(
"{\n \"$defs\": {\n \"ApproverDid\": {\n \"description\": \"A step-up approver, as an Ed25519 `did:key` (`z6Mk…`). `did:key` only, because its document is a function of the key and resolves with no network, so verifying an approver's statement never depends on a fetch, and a key whose DID document could be rewritten after enrolment would not be the key that was enrolled. Distinct from the subject's DID, from every verification method in the subject's DID document, and from every key the subject can sign operations with at the relying party.\",\n \"maxLength\": 128,\n \"minLength\": 16,\n \"pattern\": \"^did:key:z6Mk[1-9A-HJ-NP-Za-km-z]+$\",\n \"title\": \"ApproverDid\",\n \"type\": \"string\"\n },\n \"CredentialDescriptor\": {\n \"$anchor\": \"credentialDescriptor\",\n \"additionalProperties\": false,\n \"properties\": {\n \"id\": {\n \"description\": \"base64url-encoded credential id.\",\n \"type\": \"string\"\n },\n \"transports\": {\n \"items\": {\n \"enum\": [\n \"usb\",\n \"nfc\",\n \"ble\",\n \"internal\",\n \"hybrid\"\n ]\n },\n \"type\": \"array\"\n },\n \"type\": {\n \"const\": \"public-key\"\n }\n },\n \"required\": [\n \"type\",\n \"id\"\n ],\n \"title\": \"PublicKeyCredentialDescriptor\",\n \"type\": \"object\"\n },\n \"CredentialRequestOptions\": {\n \"$anchor\": \"credentialRequestOptions\",\n \"additionalProperties\": false,\n \"description\": \"Server-issued options for `navigator.credentials.get({ publicKey: ... })`.\",\n \"properties\": {\n \"allowCredentials\": {\n \"items\": {\n \"$ref\": \"#/$defs/CredentialDescriptor\"\n },\n \"type\": \"array\"\n },\n \"challenge\": {\n \"description\": \"base64url-encoded one-time nonce.\",\n \"type\": \"string\"\n },\n \"extensions\": {\n \"description\": \"Client extension inputs, per the WebAuthn Level 2 `AuthenticationExtensionsClientInputs` dictionary.\\n\\nThis component states that it mirrors the W3C dictionary, and that dictionary defines `extensions`. Omitting it while closing the object with `additionalProperties: false` made the two claims contradict each other: a server emitting standard WebAuthn options could not conform, and the widely-used server libraries emit this member by default.\\n\\nStructure is deliberately unconstrained. The set of extensions is open and registered outside this framework, so enumerating them here would date the schema against a registry it does not own — and a closed list would reproduce the original defect one revision later.\",\n \"type\": \"object\"\n },\n \"rpId\": {\n \"minLength\": 1,\n \"type\": \"string\"\n },\n \"timeout\": {\n \"minimum\": 1,\n \"type\": \"integer\"\n },\n \"userVerification\": {\n \"enum\": [\n \"discouraged\",\n \"preferred\",\n \"required\"\n ]\n }\n },\n \"required\": [\n \"challenge\"\n ],\n \"title\": \"PublicKeyCredentialRequestOptions\",\n \"type\": \"object\"\n },\n \"Ext\": {\n \"additionalProperties\": true,\n \"description\": \"Vendor-namespaced extension object per SPEC.md §4.5.1. Each immediate key MUST be a reverse-DNS namespace; structure under each namespace is opaque to the framework.\",\n \"minProperties\": 1,\n \"propertyNames\": {\n \"pattern\": \"^[a-z][a-z0-9-]*(\\\\.[a-z0-9-]+)+$\"\n },\n \"title\": \"Ext\",\n \"type\": \"object\"\n },\n \"Response\": {\n \"$anchor\": \"response\",\n \"additionalProperties\": false,\n \"description\": \"Synchronous ack from the approver acknowledging it received the request and will (or will not) deliver an approve-response. Carried in a Trust Task document whose type is https://trusttasks.org/spec/auth/step-up/approve-request/0.4#response.\",\n \"properties\": {\n \"ext\": {\n \"$ref\": \"#/$defs/Ext\"\n },\n \"reason\": {\n \"description\": \"Required when status is `refused`.\",\n \"maxLength\": 1024,\n \"type\": \"string\"\n },\n \"status\": {\n \"description\": \"`accepted` means the approver received the request and will return an approve-response (typically via DIDComm). `refused` means it will not — `reason` MUST be set.\",\n \"enum\": [\n \"accepted\",\n \"refused\"\n ],\n \"type\": \"string\"\n }\n },\n \"required\": [\n \"status\"\n ],\n \"title\": \"Auth Step-up Approve Request — response payload\",\n \"type\": \"object\"\n }\n },\n \"$id\": \"https://trusttasks.org/spec/auth/step-up/approve-request/0.4\",\n \"$schema\": \"https://json-schema.org/draft/2020-12/schema\",\n \"additionalProperties\": false,\n \"description\": \"A relying party asks an approver (typically a wallet or a VTA) to ratify an AAL elevation for a subject's session, or — bound to one operation — to approve that one act without elevating any session, and states which kinds of evidence it will accept, including a statement by one of the subject's bound step-up approvers.\",\n \"properties\": {\n \"accepts\": {\n \"description\": \"Every approve-response evidence kind the relying party will accept for this step-up, and no other (see auth/step-up/approve-response/0.6 `evidence`). Replaces 0.3's optional `acceptableEvidence`. An approver that can satisfy none of them SHOULD refuse with `methodUnsupported`.\",\n \"items\": {\n \"enum\": [\n \"webauthn\",\n \"approverSigned\",\n \"didSigned\"\n ],\n \"type\": \"string\"\n },\n \"minItems\": 1,\n \"type\": \"array\",\n \"uniqueItems\": true\n },\n \"approvers\": {\n \"description\": \"The step-up approvers bound to `subject` that the relying party will accept a statement from (auth/step-up/approver/attest/0.1, purpose `stepUp`). Present exactly when `accepts` lists `approverSigned`. Names factors, not authorities: an approver confers nothing, and the relying party re-checks the binding when the statement arrives.\",\n \"items\": {\n \"$ref\": \"#/$defs/ApproverDid\"\n },\n \"maxItems\": 5,\n \"minItems\": 1,\n \"type\": \"array\",\n \"uniqueItems\": true\n },\n \"boundTo\": {\n \"description\": \"Present when the step-up authorizes exactly one operation rather than raising a session's assurance level. An opaque relying-party identifier for that operation — for an operation that arrived as a signed document, a digest of its type and payload salted with `challenge`. Copied into a step-up approver's statement, and echoed by a `recorded` approve-response acknowledgement. Not a capability: the binding is the relying party's own state.\",\n \"maxLength\": 256,\n \"minLength\": 1,\n \"type\": \"string\"\n },\n \"challenge\": {\n \"description\": \"base64url-encoded nonce the approver will include in the approve-response signature, the WebAuthn assertion, or the step-up approver's statement. ≥128 bits entropy.\",\n \"minLength\": 16,\n \"type\": \"string\"\n },\n \"ext\": {\n \"$ref\": \"#/$defs/Ext\"\n },\n \"reason\": {\n \"description\": \"Human-readable explanation of WHY the relying party is asking (e.g. \\\"confirm transfer of 1000 USD to bob.example\\\"). Surfaced to the user by the approver for consent. SHOULD be specific enough that a user can refuse intelligently.\",\n \"maxLength\": 500,\n \"minLength\": 1,\n \"type\": \"string\"\n },\n \"sessionId\": {\n \"description\": \"The session the relying party wants elevated. Opaque to the approver. Absent only when the step-up is bound to one operation that arrived without a session (a signed Trust Task document, for instance); see `boundTo`.\",\n \"minLength\": 1,\n \"type\": \"string\"\n },\n \"subject\": {\n \"description\": \"The VID whose session is being elevated, or — for a step-up bound to one operation — the VID whose act that operation is. The approver MUST verify this is a VID it can speak for.\",\n \"minLength\": 1,\n \"type\": \"string\"\n },\n \"targetAcr\": {\n \"description\": \"The acr the relying party expects on the elevated session. Approvers MAY refuse if they cannot deliver this level.\",\n \"type\": \"string\"\n },\n \"ttl\": {\n \"description\": \"Seconds within which the relying party expects the approve-response. Approvers SHOULD treat as advisory — the relying party's own expiry policy is authoritative.\",\n \"minimum\": 1,\n \"type\": \"integer\"\n },\n \"webauthn\": {\n \"$ref\": \"#/$defs/CredentialRequestOptions\",\n \"description\": \"WebAuthn `PublicKeyCredentialRequestOptions` the approver passes to the platform passkey API when producing `webauthn` evidence. Present exactly when `accepts` lists `webauthn`. Its `challenge` MUST equal `payload.challenge` so the resulting assertion binds the same nonce the relying party bound server-side.\"\n }\n },\n \"required\": [\n \"subject\",\n \"challenge\",\n \"reason\",\n \"accepts\"\n ],\n \"title\": \"Auth — Step-up Approve Request\",\n \"type\": \"object\"\n}\n",
);
}
impl crate::Payload for Response {
const TYPE_URI: &'static str =
"https://trusttasks.org/spec/auth/step-up/approve-request/0.4#response";
const IS_PROOF_REQUIRED: bool = true;
const IS_RECIPIENT_REQUIRED: bool = true;
const PAYLOAD_SCHEMA: Option<&'static str> = Some(
"{\n \"$defs\": {\n \"ApproverDid\": {\n \"description\": \"A step-up approver, as an Ed25519 `did:key` (`z6Mk…`). `did:key` only, because its document is a function of the key and resolves with no network, so verifying an approver's statement never depends on a fetch, and a key whose DID document could be rewritten after enrolment would not be the key that was enrolled. Distinct from the subject's DID, from every verification method in the subject's DID document, and from every key the subject can sign operations with at the relying party.\",\n \"maxLength\": 128,\n \"minLength\": 16,\n \"pattern\": \"^did:key:z6Mk[1-9A-HJ-NP-Za-km-z]+$\",\n \"title\": \"ApproverDid\",\n \"type\": \"string\"\n },\n \"CredentialDescriptor\": {\n \"$anchor\": \"credentialDescriptor\",\n \"additionalProperties\": false,\n \"properties\": {\n \"id\": {\n \"description\": \"base64url-encoded credential id.\",\n \"type\": \"string\"\n },\n \"transports\": {\n \"items\": {\n \"enum\": [\n \"usb\",\n \"nfc\",\n \"ble\",\n \"internal\",\n \"hybrid\"\n ]\n },\n \"type\": \"array\"\n },\n \"type\": {\n \"const\": \"public-key\"\n }\n },\n \"required\": [\n \"type\",\n \"id\"\n ],\n \"title\": \"PublicKeyCredentialDescriptor\",\n \"type\": \"object\"\n },\n \"CredentialRequestOptions\": {\n \"$anchor\": \"credentialRequestOptions\",\n \"additionalProperties\": false,\n \"description\": \"Server-issued options for `navigator.credentials.get({ publicKey: ... })`.\",\n \"properties\": {\n \"allowCredentials\": {\n \"items\": {\n \"$ref\": \"#/$defs/CredentialDescriptor\"\n },\n \"type\": \"array\"\n },\n \"challenge\": {\n \"description\": \"base64url-encoded one-time nonce.\",\n \"type\": \"string\"\n },\n \"extensions\": {\n \"description\": \"Client extension inputs, per the WebAuthn Level 2 `AuthenticationExtensionsClientInputs` dictionary.\\n\\nThis component states that it mirrors the W3C dictionary, and that dictionary defines `extensions`. Omitting it while closing the object with `additionalProperties: false` made the two claims contradict each other: a server emitting standard WebAuthn options could not conform, and the widely-used server libraries emit this member by default.\\n\\nStructure is deliberately unconstrained. The set of extensions is open and registered outside this framework, so enumerating them here would date the schema against a registry it does not own — and a closed list would reproduce the original defect one revision later.\",\n \"type\": \"object\"\n },\n \"rpId\": {\n \"minLength\": 1,\n \"type\": \"string\"\n },\n \"timeout\": {\n \"minimum\": 1,\n \"type\": \"integer\"\n },\n \"userVerification\": {\n \"enum\": [\n \"discouraged\",\n \"preferred\",\n \"required\"\n ]\n }\n },\n \"required\": [\n \"challenge\"\n ],\n \"title\": \"PublicKeyCredentialRequestOptions\",\n \"type\": \"object\"\n },\n \"Ext\": {\n \"additionalProperties\": true,\n \"description\": \"Vendor-namespaced extension object per SPEC.md §4.5.1. Each immediate key MUST be a reverse-DNS namespace; structure under each namespace is opaque to the framework.\",\n \"minProperties\": 1,\n \"propertyNames\": {\n \"pattern\": \"^[a-z][a-z0-9-]*(\\\\.[a-z0-9-]+)+$\"\n },\n \"title\": \"Ext\",\n \"type\": \"object\"\n },\n \"Response\": {\n \"$anchor\": \"response\",\n \"additionalProperties\": false,\n \"description\": \"Synchronous ack from the approver acknowledging it received the request and will (or will not) deliver an approve-response. Carried in a Trust Task document whose type is https://trusttasks.org/spec/auth/step-up/approve-request/0.4#response.\",\n \"properties\": {\n \"ext\": {\n \"$ref\": \"#/$defs/Ext\"\n },\n \"reason\": {\n \"description\": \"Required when status is `refused`.\",\n \"maxLength\": 1024,\n \"type\": \"string\"\n },\n \"status\": {\n \"description\": \"`accepted` means the approver received the request and will return an approve-response (typically via DIDComm). `refused` means it will not — `reason` MUST be set.\",\n \"enum\": [\n \"accepted\",\n \"refused\"\n ],\n \"type\": \"string\"\n }\n },\n \"required\": [\n \"status\"\n ],\n \"title\": \"Auth Step-up Approve Request — response payload\",\n \"type\": \"object\"\n }\n },\n \"$ref\": \"#/$defs/Response\",\n \"$schema\": \"https://json-schema.org/draft/2020-12/schema\"\n}\n",
);
}
impl crate::RequestPayload for Payload {
type Response = Response;
}
/// The extended error codes this specification declares (SPEC §7.3 item 9,
/// §8.5), in declaration order. Empty when it declares none.
pub const ERROR_CODES: &[crate::DeclaredErrorCode] = &[
error_codes::SUBJECT_UNKNOWN,
error_codes::METHOD_UNSUPPORTED,
error_codes::USER_DECLINED,
error_codes::RATE_LIMITED,
];
/// One constant per extended error code this specification declares
/// (SPEC §7.3 item 9), named for its local part.
///
/// Emit these rather than a string literal: the code is read from the
/// specification, so it cannot name a code the specification never
/// declared.
pub mod error_codes {
/// `auth/step-up/approve-request:subjectUnknown`
///
/// The approver does not speak for the named subject.
///
/// Declared `retryable: false`.
pub const SUBJECT_UNKNOWN: crate::DeclaredErrorCode = crate::DeclaredErrorCode {
code: "auth/step-up/approve-request:subjectUnknown",
retryable: false,
details_schema: ::core::option::Option::None,
};
/// `auth/step-up/approve-request:methodUnsupported`
///
/// The approver cannot deliver an approve-response carrying any of the evidence kinds in `accepts` (e.g. the wallet has no passkey for the subject and holds none of the listed approvers, or does not support the requested AAL).
///
/// Declared `retryable: false`.
pub const METHOD_UNSUPPORTED: crate::DeclaredErrorCode = crate::DeclaredErrorCode {
code: "auth/step-up/approve-request:methodUnsupported",
retryable: false,
details_schema: ::core::option::Option::None,
};
/// `auth/step-up/approve-request:userDeclined`
///
/// The user reviewed the request and declined consent.
///
/// Declared `retryable: false`.
pub const USER_DECLINED: crate::DeclaredErrorCode = crate::DeclaredErrorCode {
code: "auth/step-up/approve-request:userDeclined",
retryable: false,
details_schema: ::core::option::Option::None,
};
/// `auth/step-up/approve-request:rateLimited`
///
/// The relying party has exceeded the approver's request budget.
///
/// Declared `retryable: true`.
pub const RATE_LIMITED: crate::DeclaredErrorCode = crate::DeclaredErrorCode {
code: "auth/step-up/approve-request:rateLimited",
retryable: true,
details_schema: ::core::option::Option::None,
};
}