//! Generated by `trust-tasks-codegen` — do not edit by hand.
//!
//! Spec slug: `vault/proxy-login`. Version: `0.1`.
#![allow(deprecated)]
/// Why this specification version is deprecated (SPEC "Superseded and
/// Withdrawn Versions"), or `None` while it is current.
pub const DEPRECATION: Option<&str> = Some("superseded by vault/proxy-login/0.2");
#[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())
}
}
}
///`ConsumerContext`
///
#[derive(::serde::Deserialize, ::serde::Serialize, Clone, Debug)]
#[serde(deny_unknown_fields)]
#[non_exhaustive]
pub struct ConsumerContext {
///Device-binding id assigned at registration. The maintainer cross-checks this against the authenticated transport identity.
#[serde(
rename = "deviceId",
default,
skip_serializing_if = "::std::option::Option::is_none"
)]
pub device_id: ::std::option::Option<ConsumerContextDeviceId>,
///Most recent local user-verification on the consumer device (WebAuthn UV, biometric unlock). The maintainer's policy may require this to be within N seconds.
#[serde(
rename = "lastUserVerificationAt",
default,
skip_serializing_if = "::std::option::Option::is_none"
)]
pub last_user_verification_at: ::std::option::Option<::chrono::DateTime<::chrono::offset::Utc>>,
///Producer-supplied network classification. Advisory.
#[serde(
rename = "networkClass",
default,
skip_serializing_if = "::std::option::Option::is_none"
)]
pub network_class: ::std::option::Option<ConsumerContextNetworkClass>,
}
impl ::std::default::Default for ConsumerContext {
fn default() -> Self {
Self {
device_id: Default::default(),
last_user_verification_at: Default::default(),
network_class: Default::default(),
}
}
}
impl ConsumerContext {
pub fn builder() -> builder::ConsumerContext {
Default::default()
}
}
///Device-binding id assigned at registration. The maintainer cross-checks this against the authenticated transport identity.
///
#[derive(::serde::Serialize, Clone, Debug, Eq, Hash, Ord, PartialEq, PartialOrd)]
#[serde(transparent)]
pub struct ConsumerContextDeviceId(::std::string::String);
impl ::std::ops::Deref for ConsumerContextDeviceId {
type Target = ::std::string::String;
fn deref(&self) -> &::std::string::String {
&self.0
}
}
impl ::std::convert::From<ConsumerContextDeviceId> for ::std::string::String {
fn from(value: ConsumerContextDeviceId) -> Self {
value.0
}
}
impl ::std::str::FromStr for ConsumerContextDeviceId {
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 ConsumerContextDeviceId {
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 ConsumerContextDeviceId {
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 ConsumerContextDeviceId {
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 ConsumerContextDeviceId {
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())
})
}
}
///Producer-supplied network classification. Advisory.
///
#[derive(
::serde::Deserialize,
::serde::Serialize,
Clone,
Copy,
Debug,
Eq,
Hash,
Ord,
PartialEq,
PartialOrd,
)]
#[non_exhaustive]
pub enum ConsumerContextNetworkClass {
#[serde(rename = "unknown")]
Unknown,
#[serde(rename = "home")]
Home,
#[serde(rename = "corp")]
Corp,
#[serde(rename = "public")]
Public,
#[serde(rename = "vpn")]
Vpn,
}
impl ::std::fmt::Display for ConsumerContextNetworkClass {
fn fmt(&self, f: &mut ::std::fmt::Formatter<'_>) -> ::std::fmt::Result {
match *self {
Self::Unknown => f.write_str("unknown"),
Self::Home => f.write_str("home"),
Self::Corp => f.write_str("corp"),
Self::Public => f.write_str("public"),
Self::Vpn => f.write_str("vpn"),
}
}
}
impl ::std::str::FromStr for ConsumerContextNetworkClass {
type Err = self::error::ConversionError;
fn from_str(value: &str) -> ::std::result::Result<Self, self::error::ConversionError> {
match value {
"unknown" => Ok(Self::Unknown),
"home" => Ok(Self::Home),
"corp" => Ok(Self::Corp),
"public" => Ok(Self::Public),
"vpn" => Ok(Self::Vpn),
_ => Err("invalid value".into()),
}
}
}
impl ::std::convert::TryFrom<&str> for ConsumerContextNetworkClass {
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 ConsumerContextNetworkClass {
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 ConsumerContextNetworkClass {
type Error = self::error::ConversionError;
fn try_from(
value: ::std::string::String,
) -> ::std::result::Result<Self, self::error::ConversionError> {
value.parse()
}
}
/**
DIDComm v2 authcrypt JWE (ECDH-1PU + A256CBC-HS512, X25519/P-256 key agreement). Sender authentication is the JWE's `skid` — the producer's DID#keyAgreement. The maintainer's keyAgreement key is the recipient. Cleartext is JCS-canonical JSON of the variant's payload type.
M2A is the only implementation today; this is also the canonical default for new code.*/
///
#[derive(::serde::Deserialize, ::serde::Serialize, Clone, Debug)]
#[serde(deny_unknown_fields)]
#[non_exhaustive]
pub struct DidcommAuthcryptEnvelope {
pub envelope: ::serde_json::Value,
///Compact DIDComm v2 JWE (base64url-encoded, dot-separated). Unpacks via the framework's standard DIDComm machinery; cleartext is the payload-specific JSON.
pub jwe: DidcommAuthcryptEnvelopeJwe,
}
impl DidcommAuthcryptEnvelope {
pub fn builder() -> builder::DidcommAuthcryptEnvelope {
Default::default()
}
}
///Compact DIDComm v2 JWE (base64url-encoded, dot-separated). Unpacks via the framework's standard DIDComm machinery; cleartext is the payload-specific JSON.
///
#[derive(::serde::Serialize, Clone, Debug, Eq, Hash, Ord, PartialEq, PartialOrd)]
#[serde(transparent)]
pub struct DidcommAuthcryptEnvelopeJwe(::std::string::String);
impl ::std::ops::Deref for DidcommAuthcryptEnvelopeJwe {
type Target = ::std::string::String;
fn deref(&self) -> &::std::string::String {
&self.0
}
}
impl ::std::convert::From<DidcommAuthcryptEnvelopeJwe> for ::std::string::String {
fn from(value: DidcommAuthcryptEnvelopeJwe) -> Self {
value.0
}
}
impl ::std::str::FromStr for DidcommAuthcryptEnvelopeJwe {
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 DidcommAuthcryptEnvelopeJwe {
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 DidcommAuthcryptEnvelopeJwe {
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 DidcommAuthcryptEnvelopeJwe {
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 DidcommAuthcryptEnvelopeJwe {
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())
})
}
}
///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.
///
#[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`
///
#[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())
})
}
}
/**
OpenPGP-style ASCII-armored HPKE bundle — the existing OpenVTC sealed-transfer wire form (X25519-HKDF-SHA256 KEM + ChaCha20-Poly1305 AEAD, framed in armor with Bundle-Id / Digest-Algo headers and a CRC24 checksum). Producer assertion (`did-signed` / `attested` / `pinned-only`) is the integrity / authenticity anchor.
No open-source implementation reads this yet outside vta-sdk's `sealed_transfer` crate; new code SHOULD prefer the DIDComm variant. Defined here for parity with the existing offline-bundle / cross-VTA workflows that the design plan reserves for M5+.*/
///
#[derive(::serde::Deserialize, ::serde::Serialize, Clone, Debug)]
#[serde(deny_unknown_fields)]
#[non_exhaustive]
pub struct HpkeArmoredEnvelope {
///ASCII-armored bundle text. Multi-line base64 with framing headers + CRC24.
pub armored: HpkeArmoredEnvelopeArmored,
pub envelope: ::serde_json::Value,
///Producer-assertion mode per the sealed-transfer framework. `did-signed` = Ed25519 signature by issuer; `attested` = TEE attestation quote (e.g. Nitro); `pinned-only` = OOB SHA-256 digest only (dev/test, NOT for production).
#[serde(
rename = "producerAssertion",
default = "defaults::hpke_armored_envelope_producer_assertion"
)]
pub producer_assertion: HpkeArmoredEnvelopeProducerAssertion,
///did:key identifier of the X25519 public key the envelope was sealed to. The recipient uses this to select the matching private key.
#[serde(rename = "recipientKeyId")]
pub recipient_key_id: HpkeArmoredEnvelopeRecipientKeyId,
}
impl HpkeArmoredEnvelope {
pub fn builder() -> builder::HpkeArmoredEnvelope {
Default::default()
}
}
///ASCII-armored bundle text. Multi-line base64 with framing headers + CRC24.
///
#[derive(::serde::Serialize, Clone, Debug, Eq, Hash, Ord, PartialEq, PartialOrd)]
#[serde(transparent)]
pub struct HpkeArmoredEnvelopeArmored(::std::string::String);
impl ::std::ops::Deref for HpkeArmoredEnvelopeArmored {
type Target = ::std::string::String;
fn deref(&self) -> &::std::string::String {
&self.0
}
}
impl ::std::convert::From<HpkeArmoredEnvelopeArmored> for ::std::string::String {
fn from(value: HpkeArmoredEnvelopeArmored) -> Self {
value.0
}
}
impl ::std::str::FromStr for HpkeArmoredEnvelopeArmored {
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 HpkeArmoredEnvelopeArmored {
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 HpkeArmoredEnvelopeArmored {
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 HpkeArmoredEnvelopeArmored {
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 HpkeArmoredEnvelopeArmored {
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())
})
}
}
///Producer-assertion mode per the sealed-transfer framework. `did-signed` = Ed25519 signature by issuer; `attested` = TEE attestation quote (e.g. Nitro); `pinned-only` = OOB SHA-256 digest only (dev/test, NOT for production).
///
#[derive(
::serde::Deserialize,
::serde::Serialize,
Clone,
Copy,
Debug,
Eq,
Hash,
Ord,
PartialEq,
PartialOrd,
)]
#[non_exhaustive]
pub enum HpkeArmoredEnvelopeProducerAssertion {
#[serde(rename = "did-signed")]
DidSigned,
#[serde(rename = "attested")]
Attested,
#[serde(rename = "pinned-only")]
PinnedOnly,
}
impl ::std::fmt::Display for HpkeArmoredEnvelopeProducerAssertion {
fn fmt(&self, f: &mut ::std::fmt::Formatter<'_>) -> ::std::fmt::Result {
match *self {
Self::DidSigned => f.write_str("did-signed"),
Self::Attested => f.write_str("attested"),
Self::PinnedOnly => f.write_str("pinned-only"),
}
}
}
impl ::std::str::FromStr for HpkeArmoredEnvelopeProducerAssertion {
type Err = self::error::ConversionError;
fn from_str(value: &str) -> ::std::result::Result<Self, self::error::ConversionError> {
match value {
"did-signed" => Ok(Self::DidSigned),
"attested" => Ok(Self::Attested),
"pinned-only" => Ok(Self::PinnedOnly),
_ => Err("invalid value".into()),
}
}
}
impl ::std::convert::TryFrom<&str> for HpkeArmoredEnvelopeProducerAssertion {
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 HpkeArmoredEnvelopeProducerAssertion {
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 HpkeArmoredEnvelopeProducerAssertion {
type Error = self::error::ConversionError;
fn try_from(
value: ::std::string::String,
) -> ::std::result::Result<Self, self::error::ConversionError> {
value.parse()
}
}
impl ::std::default::Default for HpkeArmoredEnvelopeProducerAssertion {
fn default() -> Self {
HpkeArmoredEnvelopeProducerAssertion::DidSigned
}
}
///did:key identifier of the X25519 public key the envelope was sealed to. The recipient uses this to select the matching private key.
///
#[derive(::serde::Serialize, Clone, Debug, Eq, Hash, Ord, PartialEq, PartialOrd)]
#[serde(transparent)]
pub struct HpkeArmoredEnvelopeRecipientKeyId(::std::string::String);
impl ::std::ops::Deref for HpkeArmoredEnvelopeRecipientKeyId {
type Target = ::std::string::String;
fn deref(&self) -> &::std::string::String {
&self.0
}
}
impl ::std::convert::From<HpkeArmoredEnvelopeRecipientKeyId> for ::std::string::String {
fn from(value: HpkeArmoredEnvelopeRecipientKeyId) -> Self {
value.0
}
}
impl ::std::str::FromStr for HpkeArmoredEnvelopeRecipientKeyId {
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 HpkeArmoredEnvelopeRecipientKeyId {
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 HpkeArmoredEnvelopeRecipientKeyId {
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 HpkeArmoredEnvelopeRecipientKeyId {
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 HpkeArmoredEnvelopeRecipientKeyId {
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())
})
}
}
///Consumer requests that the vault maintainer perform a login at the bound third-party site on the consumer's behalf, using the entry's secret material WITHOUT releasing it to the consumer. The maintainer returns a SessionBlob in a pluggable cipher envelope (see vault/_shared/0.1/sealed-envelope) containing the resulting cookies/headers the consumer can use to operate the session — but never the long-term credential.
///
#[derive(::serde::Deserialize, ::serde::Serialize, Clone, Debug)]
#[serde(deny_unknown_fields)]
#[non_exhaustive]
#[deprecated(note = "superseded by vault/proxy-login/0.2")]
pub struct Payload {
///Caller's situational context — fed to the maintainer's policy engine to decide proxy vs fill, require step-up, etc. Producers populate what they can observe; fields are advisory and the maintainer MUST cross-check anything security-relevant against its own state.
#[serde(
rename = "consumerContext",
default,
skip_serializing_if = "::std::option::Option::is_none"
)]
pub consumer_context: ::std::option::Option<ConsumerContext>,
///Vault entry id to log in with.
#[serde(rename = "entryId")]
pub entry_id: PayloadEntryId,
#[serde(default, skip_serializing_if = "::std::option::Option::is_none")]
pub ext: ::std::option::Option<Ext>,
///Optional caller-supplied nonce the maintainer SHOULD embed verbatim in the resulting session credential when one applies — typically the relying party's challenge for SIOPv2-shaped flows, where the SIOP id_token's `nonce` claim MUST match the RP's authorization-request `nonce` for the RP to verify the token. When omitted, the maintainer generates its own nonce; that path is appropriate for flows where the consumer doesn't need to bind the credential to an external challenge (e.g. push-mode logins that don't pre-fetch a challenge). Drivers that have no nonce concept (Password POST, OAuth refresh) ignore this field.
#[serde(default, skip_serializing_if = "::std::option::Option::is_none")]
pub nonce: ::std::option::Option<PayloadNonce>,
///Optional — included on retry after a prior proxy-login attempt returned `stepUpRequired`.
#[serde(
rename = "stepUpProof",
default,
skip_serializing_if = "::std::option::Option::is_none"
)]
pub step_up_proof: ::std::option::Option<StepUpProof>,
///Optional — when an entry has multiple targets, names which one the consumer is acting against. The maintainer matches this against the entry's `targets[]`; if not supplied, the maintainer chooses the most specific target compatible with the requesting consumer's form factor (e.g. an iOS Companion gets the iOS-app target if one exists; otherwise the web-origin target).
#[serde(default, skip_serializing_if = "::std::option::Option::is_none")]
pub target: ::std::option::Option<SiteTarget>,
///Optional caller-preferred session TTL in seconds. The maintainer caps server-side per its policy; a higher hint MUST be silently truncated rather than rejected. Drivers that have a fixed-TTL bearer (e.g. SIOP id_tokens with their own `exp`) MUST NOT extend beyond the underlying credential's lifetime regardless of hint.
#[serde(
rename = "ttlSecondsHint",
default,
skip_serializing_if = "::std::option::Option::is_none"
)]
pub ttl_seconds_hint: ::std::option::Option<::std::num::NonZeroU64>,
}
impl Payload {
pub fn builder() -> builder::Payload {
Default::default()
}
}
///Vault entry id to log in with.
///
#[derive(::serde::Serialize, Clone, Debug, Eq, Hash, Ord, PartialEq, PartialOrd)]
#[serde(transparent)]
pub struct PayloadEntryId(::std::string::String);
impl ::std::ops::Deref for PayloadEntryId {
type Target = ::std::string::String;
fn deref(&self) -> &::std::string::String {
&self.0
}
}
impl ::std::convert::From<PayloadEntryId> for ::std::string::String {
fn from(value: PayloadEntryId) -> Self {
value.0
}
}
impl ::std::str::FromStr for PayloadEntryId {
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 PayloadEntryId {
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 PayloadEntryId {
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 PayloadEntryId {
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 PayloadEntryId {
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())
})
}
}
///Optional caller-supplied nonce the maintainer SHOULD embed verbatim in the resulting session credential when one applies — typically the relying party's challenge for SIOPv2-shaped flows, where the SIOP id_token's `nonce` claim MUST match the RP's authorization-request `nonce` for the RP to verify the token. When omitted, the maintainer generates its own nonce; that path is appropriate for flows where the consumer doesn't need to bind the credential to an external challenge (e.g. push-mode logins that don't pre-fetch a challenge). Drivers that have no nonce concept (Password POST, OAuth refresh) ignore this field.
///
#[derive(::serde::Serialize, Clone, Debug, Eq, Hash, Ord, PartialEq, PartialOrd)]
#[serde(transparent)]
pub struct PayloadNonce(::std::string::String);
impl ::std::ops::Deref for PayloadNonce {
type Target = ::std::string::String;
fn deref(&self) -> &::std::string::String {
&self.0
}
}
impl ::std::convert::From<PayloadNonce> for ::std::string::String {
fn from(value: PayloadNonce) -> Self {
value.0
}
}
impl ::std::str::FromStr for PayloadNonce {
type Err = self::error::ConversionError;
fn from_str(value: &str) -> ::std::result::Result<Self, self::error::ConversionError> {
if value.chars().count() > 512usize {
return Err("longer than 512 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 PayloadNonce {
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 PayloadNonce {
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 PayloadNonce {
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 PayloadNonce {
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())
})
}
}
///`Response`
///
#[derive(::serde::Deserialize, ::serde::Serialize, Clone, Debug)]
#[serde(deny_unknown_fields)]
#[non_exhaustive]
#[deprecated(note = "superseded by vault/proxy-login/0.2")]
pub struct Response {
#[serde(default, skip_serializing_if = "::std::option::Option::is_none")]
pub ext: ::std::option::Option<Ext>,
///Pluggable cipher envelope containing the SessionBlob cleartext (see `vault/_shared/0.1/session-blob`). The consumer unseals to recover cookies/headers, then injects into its browser session for the bound origin. Consumers reject envelope kinds they don't implement with `vault/proxy-login:envelopeUnsupported`.
#[serde(rename = "sealedSessionBlob")]
pub sealed_session_blob: SealedEnvelope,
}
impl Response {
pub fn builder() -> builder::Response {
Default::default()
}
}
///Discriminated by `envelope`. Exactly one variant matches per document.
///
#[derive(::serde::Deserialize, ::serde::Serialize, Clone, Debug)]
#[serde(untagged)]
#[non_exhaustive]
pub enum SealedEnvelope {
DidcommAuthcryptEnvelope(DidcommAuthcryptEnvelope),
HpkeArmoredEnvelope(HpkeArmoredEnvelope),
TspMessageEnvelope(TspMessageEnvelope),
}
impl ::std::convert::From<DidcommAuthcryptEnvelope> for SealedEnvelope {
fn from(value: DidcommAuthcryptEnvelope) -> Self {
Self::DidcommAuthcryptEnvelope(value)
}
}
impl ::std::convert::From<HpkeArmoredEnvelope> for SealedEnvelope {
fn from(value: HpkeArmoredEnvelope) -> Self {
Self::HpkeArmoredEnvelope(value)
}
}
impl ::std::convert::From<TspMessageEnvelope> for SealedEnvelope {
fn from(value: TspMessageEnvelope) -> Self {
Self::TspMessageEnvelope(value)
}
}
///A single binding target for a vault entry. Tagged union over the discriminator `kind`. A VaultEntry's `targets` array MAY mix any number of these.
///
#[derive(::serde::Deserialize, ::serde::Serialize, Clone, Debug)]
#[serde(tag = "kind", deny_unknown_fields)]
#[non_exhaustive]
pub enum SiteTarget {
///WebOrigin
#[serde(rename = "web-origin")]
WebOrigin {
///Web origin per RFC 6454 (scheme + host + optional port), e.g. "https://github.com". Compared by exact string equality after canonicalisation (lowercase host, default port elided). Consumers wanting subdomain coverage SHOULD add multiple targets, not encode a wildcard.
origin: ::std::string::String,
},
///Did
#[serde(rename = "did")]
Did {
///DID identifying the relying party (e.g. did:web:rp.example). The vault maintainer is responsible for any DID resolution required to act on this entry.
did: SiteTargetDid,
},
///IosApp
#[serde(rename = "ios-app")]
IosApp {
///iOS bundle identifier in reverse-DNS form (e.g. "com.github.stwalkerster.codehub"). Compared by exact string equality. Matches when an iOS Companion identifies the requesting app via its bundle id (typically via the OS Credential Manager integration).
#[serde(rename = "bundleId")]
bundle_id: SiteTargetBundleId,
///Optional Apple Developer Team identifier (10-character alphanumeric). When supplied, the maintainer SHOULD also verify the team id of the requesting app before matching — defense in depth against bundle-id squatting on jailbroken devices.
#[serde(
rename = "teamId",
default,
skip_serializing_if = "::std::option::Option::is_none"
)]
team_id: ::std::option::Option<SiteTargetTeamId>,
},
///AndroidApp
#[serde(rename = "android-app")]
AndroidApp {
///Android package name in reverse-DNS form (e.g. "com.github.android").
#[serde(rename = "packageName")]
package_name: SiteTargetPackageName,
///SHA-256 fingerprints of the app's signing certificates, in colon-separated hex (the format `apksigner` and the Play Console emit). At least one fingerprint MUST be present. The maintainer matches when ANY of the provided fingerprints matches the requesting app's signature — this supports apps signed by multiple keys (e.g. during certificate rotation via Play App Signing).
#[serde(rename = "sha256CertFingerprints")]
sha256_cert_fingerprints: Vec<SiteTargetSha256CertFingerprintsItem>,
},
}
///iOS bundle identifier in reverse-DNS form (e.g. "com.github.stwalkerster.codehub"). Compared by exact string equality. Matches when an iOS Companion identifies the requesting app via its bundle id (typically via the OS Credential Manager integration).
///
#[derive(::serde::Serialize, Clone, Debug, Eq, Hash, Ord, PartialEq, PartialOrd)]
#[serde(transparent)]
pub struct SiteTargetBundleId(::std::string::String);
impl ::std::ops::Deref for SiteTargetBundleId {
type Target = ::std::string::String;
fn deref(&self) -> &::std::string::String {
&self.0
}
}
impl ::std::convert::From<SiteTargetBundleId> for ::std::string::String {
fn from(value: SiteTargetBundleId) -> Self {
value.0
}
}
impl ::std::str::FromStr for SiteTargetBundleId {
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());
}
static PATTERN: ::std::sync::LazyLock<::regress::Regex> =
::std::sync::LazyLock::new(|| ::regress::Regex::new("^[A-Za-z0-9.-]+$").unwrap());
if PATTERN.find(value).is_none() {
return Err("doesn't match pattern \"^[A-Za-z0-9.-]+$\"".into());
}
Ok(Self(value.to_string()))
}
}
impl ::std::convert::TryFrom<&str> for SiteTargetBundleId {
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 SiteTargetBundleId {
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 SiteTargetBundleId {
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 SiteTargetBundleId {
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())
})
}
}
///DID identifying the relying party (e.g. did:web:rp.example). The vault maintainer is responsible for any DID resolution required to act on this entry.
///
#[derive(::serde::Serialize, Clone, Debug, Eq, Hash, Ord, PartialEq, PartialOrd)]
#[serde(transparent)]
pub struct SiteTargetDid(::std::string::String);
impl ::std::ops::Deref for SiteTargetDid {
type Target = ::std::string::String;
fn deref(&self) -> &::std::string::String {
&self.0
}
}
impl ::std::convert::From<SiteTargetDid> for ::std::string::String {
fn from(value: SiteTargetDid) -> Self {
value.0
}
}
impl ::std::str::FromStr for SiteTargetDid {
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 SiteTargetDid {
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 SiteTargetDid {
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 SiteTargetDid {
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 SiteTargetDid {
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())
})
}
}
///Android package name in reverse-DNS form (e.g. "com.github.android").
///
#[derive(::serde::Serialize, Clone, Debug, Eq, Hash, Ord, PartialEq, PartialOrd)]
#[serde(transparent)]
pub struct SiteTargetPackageName(::std::string::String);
impl ::std::ops::Deref for SiteTargetPackageName {
type Target = ::std::string::String;
fn deref(&self) -> &::std::string::String {
&self.0
}
}
impl ::std::convert::From<SiteTargetPackageName> for ::std::string::String {
fn from(value: SiteTargetPackageName) -> Self {
value.0
}
}
impl ::std::str::FromStr for SiteTargetPackageName {
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());
}
static PATTERN: ::std::sync::LazyLock<::regress::Regex> =
::std::sync::LazyLock::new(|| {
::regress::Regex::new("^[A-Za-z][A-Za-z0-9_]*(\\.[A-Za-z][A-Za-z0-9_]*)+$").unwrap()
});
if PATTERN.find(value).is_none() {
return Err(
"doesn't match pattern \"^[A-Za-z][A-Za-z0-9_]*(\\.[A-Za-z][A-Za-z0-9_]*)+$\""
.into(),
);
}
Ok(Self(value.to_string()))
}
}
impl ::std::convert::TryFrom<&str> for SiteTargetPackageName {
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 SiteTargetPackageName {
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 SiteTargetPackageName {
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 SiteTargetPackageName {
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())
})
}
}
///`SiteTargetSha256CertFingerprintsItem`
///
#[derive(::serde::Serialize, Clone, Debug, Eq, Hash, Ord, PartialEq, PartialOrd)]
#[serde(transparent)]
pub struct SiteTargetSha256CertFingerprintsItem(::std::string::String);
impl ::std::ops::Deref for SiteTargetSha256CertFingerprintsItem {
type Target = ::std::string::String;
fn deref(&self) -> &::std::string::String {
&self.0
}
}
impl ::std::convert::From<SiteTargetSha256CertFingerprintsItem> for ::std::string::String {
fn from(value: SiteTargetSha256CertFingerprintsItem) -> Self {
value.0
}
}
impl ::std::str::FromStr for SiteTargetSha256CertFingerprintsItem {
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("^[0-9A-F]{2}(:[0-9A-F]{2}){31}$").unwrap()
});
if PATTERN.find(value).is_none() {
return Err("doesn't match pattern \"^[0-9A-F]{2}(:[0-9A-F]{2}){31}$\"".into());
}
Ok(Self(value.to_string()))
}
}
impl ::std::convert::TryFrom<&str> for SiteTargetSha256CertFingerprintsItem {
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 SiteTargetSha256CertFingerprintsItem {
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 SiteTargetSha256CertFingerprintsItem {
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 SiteTargetSha256CertFingerprintsItem {
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())
})
}
}
///Optional Apple Developer Team identifier (10-character alphanumeric). When supplied, the maintainer SHOULD also verify the team id of the requesting app before matching — defense in depth against bundle-id squatting on jailbroken devices.
///
#[derive(::serde::Serialize, Clone, Debug, Eq, Hash, Ord, PartialEq, PartialOrd)]
#[serde(transparent)]
pub struct SiteTargetTeamId(::std::string::String);
impl ::std::ops::Deref for SiteTargetTeamId {
type Target = ::std::string::String;
fn deref(&self) -> &::std::string::String {
&self.0
}
}
impl ::std::convert::From<SiteTargetTeamId> for ::std::string::String {
fn from(value: SiteTargetTeamId) -> Self {
value.0
}
}
impl ::std::str::FromStr for SiteTargetTeamId {
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());
}
static PATTERN: ::std::sync::LazyLock<::regress::Regex> =
::std::sync::LazyLock::new(|| ::regress::Regex::new("^[A-Z0-9]+$").unwrap());
if PATTERN.find(value).is_none() {
return Err("doesn't match pattern \"^[A-Z0-9]+$\"".into());
}
Ok(Self(value.to_string()))
}
}
impl ::std::convert::TryFrom<&str> for SiteTargetTeamId {
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 SiteTargetTeamId {
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 SiteTargetTeamId {
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 SiteTargetTeamId {
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())
})
}
}
///`StepUpProof`
///
#[derive(::serde::Deserialize, ::serde::Serialize, Clone, Debug)]
#[serde(deny_unknown_fields)]
#[non_exhaustive]
pub struct StepUpProof {
///Maintainer-issued challenge id the proof responds to.
#[serde(rename = "challengeId")]
pub challenge_id: StepUpProofChallengeId,
pub kind: StepUpProofKind,
///Format depends on kind: WebAuthn assertion (base64url), DIDComm approval-response message id, or 6–8-digit TOTP code.
pub proof: ::std::string::String,
}
impl StepUpProof {
pub fn builder() -> builder::StepUpProof {
Default::default()
}
}
///Maintainer-issued challenge id the proof responds to.
///
#[derive(::serde::Serialize, Clone, Debug, Eq, Hash, Ord, PartialEq, PartialOrd)]
#[serde(transparent)]
pub struct StepUpProofChallengeId(::std::string::String);
impl ::std::ops::Deref for StepUpProofChallengeId {
type Target = ::std::string::String;
fn deref(&self) -> &::std::string::String {
&self.0
}
}
impl ::std::convert::From<StepUpProofChallengeId> for ::std::string::String {
fn from(value: StepUpProofChallengeId) -> Self {
value.0
}
}
impl ::std::str::FromStr for StepUpProofChallengeId {
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 StepUpProofChallengeId {
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 StepUpProofChallengeId {
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 StepUpProofChallengeId {
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 StepUpProofChallengeId {
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())
})
}
}
///`StepUpProofKind`
///
#[derive(
::serde::Deserialize,
::serde::Serialize,
Clone,
Copy,
Debug,
Eq,
Hash,
Ord,
PartialEq,
PartialOrd,
)]
#[non_exhaustive]
pub enum StepUpProofKind {
#[serde(rename = "webauthn-uv")]
WebauthnUv,
#[serde(rename = "push-approval")]
PushApproval,
#[serde(rename = "totp")]
Totp,
}
impl ::std::fmt::Display for StepUpProofKind {
fn fmt(&self, f: &mut ::std::fmt::Formatter<'_>) -> ::std::fmt::Result {
match *self {
Self::WebauthnUv => f.write_str("webauthn-uv"),
Self::PushApproval => f.write_str("push-approval"),
Self::Totp => f.write_str("totp"),
}
}
}
impl ::std::str::FromStr for StepUpProofKind {
type Err = self::error::ConversionError;
fn from_str(value: &str) -> ::std::result::Result<Self, self::error::ConversionError> {
match value {
"webauthn-uv" => Ok(Self::WebauthnUv),
"push-approval" => Ok(Self::PushApproval),
"totp" => Ok(Self::Totp),
_ => Err("invalid value".into()),
}
}
}
impl ::std::convert::TryFrom<&str> for StepUpProofKind {
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 StepUpProofKind {
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 StepUpProofKind {
type Error = self::error::ConversionError;
fn try_from(
value: ::std::string::String,
) -> ::std::result::Result<Self, self::error::ConversionError> {
value.parse()
}
}
///Trust Spanning Protocol message (https://trustoverip.github.io/tswg-tsp-specification/). Reserved variant; no OpenVTC component reads or emits this today. Listed in the union so implementations can declare intent to use TSP in discovery and so consumers reject `tsp-message` envelopes explicitly (`envelopeUnsupported`) until they're wired up — rather than silently failing in DIDComm parsing.
///
#[derive(::serde::Deserialize, ::serde::Serialize, Clone, Debug)]
#[serde(deny_unknown_fields)]
#[non_exhaustive]
pub struct TspMessageEnvelope {
pub envelope: ::serde_json::Value,
///Base64url-encoded TSP message bytes. Format reference: https://trustoverip.github.io/tswg-tsp-specification/#message-format
pub message: TspMessageEnvelopeMessage,
}
impl TspMessageEnvelope {
pub fn builder() -> builder::TspMessageEnvelope {
Default::default()
}
}
///Base64url-encoded TSP message bytes. Format reference: https://trustoverip.github.io/tswg-tsp-specification/#message-format
///
#[derive(::serde::Serialize, Clone, Debug, Eq, Hash, Ord, PartialEq, PartialOrd)]
#[serde(transparent)]
pub struct TspMessageEnvelopeMessage(::std::string::String);
impl ::std::ops::Deref for TspMessageEnvelopeMessage {
type Target = ::std::string::String;
fn deref(&self) -> &::std::string::String {
&self.0
}
}
impl ::std::convert::From<TspMessageEnvelopeMessage> for ::std::string::String {
fn from(value: TspMessageEnvelopeMessage) -> Self {
value.0
}
}
impl ::std::str::FromStr for TspMessageEnvelopeMessage {
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 TspMessageEnvelopeMessage {
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 TspMessageEnvelopeMessage {
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 TspMessageEnvelopeMessage {
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 TspMessageEnvelopeMessage {
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())
})
}
}
/// Types for composing complex structures.
pub mod builder {
#[derive(Clone, Debug)]
pub struct ConsumerContext {
device_id: ::std::result::Result<
::std::option::Option<super::ConsumerContextDeviceId>,
::std::string::String,
>,
last_user_verification_at: ::std::result::Result<
::std::option::Option<::chrono::DateTime<::chrono::offset::Utc>>,
::std::string::String,
>,
network_class: ::std::result::Result<
::std::option::Option<super::ConsumerContextNetworkClass>,
::std::string::String,
>,
}
impl ::std::default::Default for ConsumerContext {
fn default() -> Self {
Self {
device_id: Ok(Default::default()),
last_user_verification_at: Ok(Default::default()),
network_class: Ok(Default::default()),
}
}
}
impl ConsumerContext {
pub fn device_id<T>(mut self, value: T) -> Self
where
T: ::std::convert::TryInto<::std::option::Option<super::ConsumerContextDeviceId>>,
T::Error: ::std::fmt::Display,
{
self.device_id = value
.try_into()
.map_err(|e| format!("error converting supplied value for device_id: {e}"));
self
}
pub fn last_user_verification_at<T>(mut self, value: T) -> Self
where
T: ::std::convert::TryInto<
::std::option::Option<::chrono::DateTime<::chrono::offset::Utc>>,
>,
T::Error: ::std::fmt::Display,
{
self.last_user_verification_at = value.try_into().map_err(|e| {
format!("error converting supplied value for last_user_verification_at: {e}")
});
self
}
pub fn network_class<T>(mut self, value: T) -> Self
where
T: ::std::convert::TryInto<::std::option::Option<super::ConsumerContextNetworkClass>>,
T::Error: ::std::fmt::Display,
{
self.network_class = value
.try_into()
.map_err(|e| format!("error converting supplied value for network_class: {e}"));
self
}
}
impl ::std::convert::TryFrom<ConsumerContext> for super::ConsumerContext {
type Error = super::error::ConversionError;
fn try_from(
value: ConsumerContext,
) -> ::std::result::Result<Self, super::error::ConversionError> {
Ok(Self {
device_id: value.device_id?,
last_user_verification_at: value.last_user_verification_at?,
network_class: value.network_class?,
})
}
}
impl ::std::convert::From<super::ConsumerContext> for ConsumerContext {
fn from(value: super::ConsumerContext) -> Self {
Self {
device_id: Ok(value.device_id),
last_user_verification_at: Ok(value.last_user_verification_at),
network_class: Ok(value.network_class),
}
}
}
#[derive(Clone, Debug)]
pub struct DidcommAuthcryptEnvelope {
envelope: ::std::result::Result<::serde_json::Value, ::std::string::String>,
jwe: ::std::result::Result<super::DidcommAuthcryptEnvelopeJwe, ::std::string::String>,
}
impl ::std::default::Default for DidcommAuthcryptEnvelope {
fn default() -> Self {
Self {
envelope: Err("no value supplied for envelope".to_string()),
jwe: Err("no value supplied for jwe".to_string()),
}
}
}
impl DidcommAuthcryptEnvelope {
pub fn envelope<T>(mut self, value: T) -> Self
where
T: ::std::convert::TryInto<::serde_json::Value>,
T::Error: ::std::fmt::Display,
{
self.envelope = value
.try_into()
.map_err(|e| format!("error converting supplied value for envelope: {e}"));
self
}
pub fn jwe<T>(mut self, value: T) -> Self
where
T: ::std::convert::TryInto<super::DidcommAuthcryptEnvelopeJwe>,
T::Error: ::std::fmt::Display,
{
self.jwe = value
.try_into()
.map_err(|e| format!("error converting supplied value for jwe: {e}"));
self
}
}
impl ::std::convert::TryFrom<DidcommAuthcryptEnvelope> for super::DidcommAuthcryptEnvelope {
type Error = super::error::ConversionError;
fn try_from(
value: DidcommAuthcryptEnvelope,
) -> ::std::result::Result<Self, super::error::ConversionError> {
Ok(Self {
envelope: value.envelope?,
jwe: value.jwe?,
})
}
}
impl ::std::convert::From<super::DidcommAuthcryptEnvelope> for DidcommAuthcryptEnvelope {
fn from(value: super::DidcommAuthcryptEnvelope) -> Self {
Self {
envelope: Ok(value.envelope),
jwe: Ok(value.jwe),
}
}
}
#[derive(Clone, Debug)]
pub struct HpkeArmoredEnvelope {
armored: ::std::result::Result<super::HpkeArmoredEnvelopeArmored, ::std::string::String>,
envelope: ::std::result::Result<::serde_json::Value, ::std::string::String>,
producer_assertion: ::std::result::Result<
super::HpkeArmoredEnvelopeProducerAssertion,
::std::string::String,
>,
recipient_key_id:
::std::result::Result<super::HpkeArmoredEnvelopeRecipientKeyId, ::std::string::String>,
}
impl ::std::default::Default for HpkeArmoredEnvelope {
fn default() -> Self {
Self {
armored: Err("no value supplied for armored".to_string()),
envelope: Err("no value supplied for envelope".to_string()),
producer_assertion: Ok(super::defaults::hpke_armored_envelope_producer_assertion()),
recipient_key_id: Err("no value supplied for recipient_key_id".to_string()),
}
}
}
impl HpkeArmoredEnvelope {
pub fn armored<T>(mut self, value: T) -> Self
where
T: ::std::convert::TryInto<super::HpkeArmoredEnvelopeArmored>,
T::Error: ::std::fmt::Display,
{
self.armored = value
.try_into()
.map_err(|e| format!("error converting supplied value for armored: {e}"));
self
}
pub fn envelope<T>(mut self, value: T) -> Self
where
T: ::std::convert::TryInto<::serde_json::Value>,
T::Error: ::std::fmt::Display,
{
self.envelope = value
.try_into()
.map_err(|e| format!("error converting supplied value for envelope: {e}"));
self
}
pub fn producer_assertion<T>(mut self, value: T) -> Self
where
T: ::std::convert::TryInto<super::HpkeArmoredEnvelopeProducerAssertion>,
T::Error: ::std::fmt::Display,
{
self.producer_assertion = value.try_into().map_err(|e| {
format!("error converting supplied value for producer_assertion: {e}")
});
self
}
pub fn recipient_key_id<T>(mut self, value: T) -> Self
where
T: ::std::convert::TryInto<super::HpkeArmoredEnvelopeRecipientKeyId>,
T::Error: ::std::fmt::Display,
{
self.recipient_key_id = value
.try_into()
.map_err(|e| format!("error converting supplied value for recipient_key_id: {e}"));
self
}
}
impl ::std::convert::TryFrom<HpkeArmoredEnvelope> for super::HpkeArmoredEnvelope {
type Error = super::error::ConversionError;
fn try_from(
value: HpkeArmoredEnvelope,
) -> ::std::result::Result<Self, super::error::ConversionError> {
Ok(Self {
armored: value.armored?,
envelope: value.envelope?,
producer_assertion: value.producer_assertion?,
recipient_key_id: value.recipient_key_id?,
})
}
}
impl ::std::convert::From<super::HpkeArmoredEnvelope> for HpkeArmoredEnvelope {
fn from(value: super::HpkeArmoredEnvelope) -> Self {
Self {
armored: Ok(value.armored),
envelope: Ok(value.envelope),
producer_assertion: Ok(value.producer_assertion),
recipient_key_id: Ok(value.recipient_key_id),
}
}
}
#[derive(Clone, Debug)]
pub struct Payload {
consumer_context: ::std::result::Result<
::std::option::Option<super::ConsumerContext>,
::std::string::String,
>,
entry_id: ::std::result::Result<super::PayloadEntryId, ::std::string::String>,
ext: ::std::result::Result<::std::option::Option<super::Ext>, ::std::string::String>,
nonce: ::std::result::Result<
::std::option::Option<super::PayloadNonce>,
::std::string::String,
>,
step_up_proof:
::std::result::Result<::std::option::Option<super::StepUpProof>, ::std::string::String>,
target:
::std::result::Result<::std::option::Option<super::SiteTarget>, ::std::string::String>,
ttl_seconds_hint: ::std::result::Result<
::std::option::Option<::std::num::NonZeroU64>,
::std::string::String,
>,
}
impl ::std::default::Default for Payload {
fn default() -> Self {
Self {
consumer_context: Ok(Default::default()),
entry_id: Err("no value supplied for entry_id".to_string()),
ext: Ok(Default::default()),
nonce: Ok(Default::default()),
step_up_proof: Ok(Default::default()),
target: Ok(Default::default()),
ttl_seconds_hint: Ok(Default::default()),
}
}
}
impl Payload {
pub fn consumer_context<T>(mut self, value: T) -> Self
where
T: ::std::convert::TryInto<::std::option::Option<super::ConsumerContext>>,
T::Error: ::std::fmt::Display,
{
self.consumer_context = value
.try_into()
.map_err(|e| format!("error converting supplied value for consumer_context: {e}"));
self
}
pub fn entry_id<T>(mut self, value: T) -> Self
where
T: ::std::convert::TryInto<super::PayloadEntryId>,
T::Error: ::std::fmt::Display,
{
self.entry_id = value
.try_into()
.map_err(|e| format!("error converting supplied value for entry_id: {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 nonce<T>(mut self, value: T) -> Self
where
T: ::std::convert::TryInto<::std::option::Option<super::PayloadNonce>>,
T::Error: ::std::fmt::Display,
{
self.nonce = value
.try_into()
.map_err(|e| format!("error converting supplied value for nonce: {e}"));
self
}
pub fn step_up_proof<T>(mut self, value: T) -> Self
where
T: ::std::convert::TryInto<::std::option::Option<super::StepUpProof>>,
T::Error: ::std::fmt::Display,
{
self.step_up_proof = value
.try_into()
.map_err(|e| format!("error converting supplied value for step_up_proof: {e}"));
self
}
pub fn target<T>(mut self, value: T) -> Self
where
T: ::std::convert::TryInto<::std::option::Option<super::SiteTarget>>,
T::Error: ::std::fmt::Display,
{
self.target = value
.try_into()
.map_err(|e| format!("error converting supplied value for target: {e}"));
self
}
pub fn ttl_seconds_hint<T>(mut self, value: T) -> Self
where
T: ::std::convert::TryInto<::std::option::Option<::std::num::NonZeroU64>>,
T::Error: ::std::fmt::Display,
{
self.ttl_seconds_hint = value
.try_into()
.map_err(|e| format!("error converting supplied value for ttl_seconds_hint: {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 {
consumer_context: value.consumer_context?,
entry_id: value.entry_id?,
ext: value.ext?,
nonce: value.nonce?,
step_up_proof: value.step_up_proof?,
target: value.target?,
ttl_seconds_hint: value.ttl_seconds_hint?,
})
}
}
impl ::std::convert::From<super::Payload> for Payload {
fn from(value: super::Payload) -> Self {
Self {
consumer_context: Ok(value.consumer_context),
entry_id: Ok(value.entry_id),
ext: Ok(value.ext),
nonce: Ok(value.nonce),
step_up_proof: Ok(value.step_up_proof),
target: Ok(value.target),
ttl_seconds_hint: Ok(value.ttl_seconds_hint),
}
}
}
#[derive(Clone, Debug)]
pub struct Response {
ext: ::std::result::Result<::std::option::Option<super::Ext>, ::std::string::String>,
sealed_session_blob: ::std::result::Result<super::SealedEnvelope, ::std::string::String>,
}
impl ::std::default::Default for Response {
fn default() -> Self {
Self {
ext: Ok(Default::default()),
sealed_session_blob: Err("no value supplied for sealed_session_blob".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 sealed_session_blob<T>(mut self, value: T) -> Self
where
T: ::std::convert::TryInto<super::SealedEnvelope>,
T::Error: ::std::fmt::Display,
{
self.sealed_session_blob = value.try_into().map_err(|e| {
format!("error converting supplied value for sealed_session_blob: {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?,
sealed_session_blob: value.sealed_session_blob?,
})
}
}
impl ::std::convert::From<super::Response> for Response {
fn from(value: super::Response) -> Self {
Self {
ext: Ok(value.ext),
sealed_session_blob: Ok(value.sealed_session_blob),
}
}
}
#[derive(Clone, Debug)]
pub struct StepUpProof {
challenge_id: ::std::result::Result<super::StepUpProofChallengeId, ::std::string::String>,
kind: ::std::result::Result<super::StepUpProofKind, ::std::string::String>,
proof: ::std::result::Result<::std::string::String, ::std::string::String>,
}
impl ::std::default::Default for StepUpProof {
fn default() -> Self {
Self {
challenge_id: Err("no value supplied for challenge_id".to_string()),
kind: Err("no value supplied for kind".to_string()),
proof: Err("no value supplied for proof".to_string()),
}
}
}
impl StepUpProof {
pub fn challenge_id<T>(mut self, value: T) -> Self
where
T: ::std::convert::TryInto<super::StepUpProofChallengeId>,
T::Error: ::std::fmt::Display,
{
self.challenge_id = value
.try_into()
.map_err(|e| format!("error converting supplied value for challenge_id: {e}"));
self
}
pub fn kind<T>(mut self, value: T) -> Self
where
T: ::std::convert::TryInto<super::StepUpProofKind>,
T::Error: ::std::fmt::Display,
{
self.kind = value
.try_into()
.map_err(|e| format!("error converting supplied value for kind: {e}"));
self
}
pub fn proof<T>(mut self, value: T) -> Self
where
T: ::std::convert::TryInto<::std::string::String>,
T::Error: ::std::fmt::Display,
{
self.proof = value
.try_into()
.map_err(|e| format!("error converting supplied value for proof: {e}"));
self
}
}
impl ::std::convert::TryFrom<StepUpProof> for super::StepUpProof {
type Error = super::error::ConversionError;
fn try_from(
value: StepUpProof,
) -> ::std::result::Result<Self, super::error::ConversionError> {
Ok(Self {
challenge_id: value.challenge_id?,
kind: value.kind?,
proof: value.proof?,
})
}
}
impl ::std::convert::From<super::StepUpProof> for StepUpProof {
fn from(value: super::StepUpProof) -> Self {
Self {
challenge_id: Ok(value.challenge_id),
kind: Ok(value.kind),
proof: Ok(value.proof),
}
}
}
#[derive(Clone, Debug)]
pub struct TspMessageEnvelope {
envelope: ::std::result::Result<::serde_json::Value, ::std::string::String>,
message: ::std::result::Result<super::TspMessageEnvelopeMessage, ::std::string::String>,
}
impl ::std::default::Default for TspMessageEnvelope {
fn default() -> Self {
Self {
envelope: Err("no value supplied for envelope".to_string()),
message: Err("no value supplied for message".to_string()),
}
}
}
impl TspMessageEnvelope {
pub fn envelope<T>(mut self, value: T) -> Self
where
T: ::std::convert::TryInto<::serde_json::Value>,
T::Error: ::std::fmt::Display,
{
self.envelope = value
.try_into()
.map_err(|e| format!("error converting supplied value for envelope: {e}"));
self
}
pub fn message<T>(mut self, value: T) -> Self
where
T: ::std::convert::TryInto<super::TspMessageEnvelopeMessage>,
T::Error: ::std::fmt::Display,
{
self.message = value
.try_into()
.map_err(|e| format!("error converting supplied value for message: {e}"));
self
}
}
impl ::std::convert::TryFrom<TspMessageEnvelope> for super::TspMessageEnvelope {
type Error = super::error::ConversionError;
fn try_from(
value: TspMessageEnvelope,
) -> ::std::result::Result<Self, super::error::ConversionError> {
Ok(Self {
envelope: value.envelope?,
message: value.message?,
})
}
}
impl ::std::convert::From<super::TspMessageEnvelope> for TspMessageEnvelope {
fn from(value: super::TspMessageEnvelope) -> Self {
Self {
envelope: Ok(value.envelope),
message: Ok(value.message),
}
}
}
}
/// Generation of default values for serde.
pub mod defaults {
pub(super) fn hpke_armored_envelope_producer_assertion(
) -> super::HpkeArmoredEnvelopeProducerAssertion {
super::HpkeArmoredEnvelopeProducerAssertion::DidSigned
}
}
impl crate::Payload for Payload {
const TYPE_URI: &'static str = "https://trusttasks.org/spec/vault/proxy-login/0.1";
const IS_PROOF_REQUIRED: bool = true;
const IS_ISSUED_AT_REQUIRED: bool = true;
const IS_RECIPIENT_REQUIRED: bool = true;
const PAYLOAD_SCHEMA: Option<&'static str> = Some(
"{\"$defs\":{\"ConsumerContext\":{\"additionalProperties\":false,\"properties\":{\"deviceId\":{\"description\":\"Device-binding id assigned at registration. The maintainer cross-checks this against the authenticated transport identity.\",\"minLength\":1,\"type\":\"string\"},\"lastUserVerificationAt\":{\"description\":\"Most recent local user-verification on the consumer device (WebAuthn UV, biometric unlock). The maintainer's policy may require this to be within N seconds.\",\"format\":\"date-time\",\"type\":\"string\"},\"networkClass\":{\"description\":\"Producer-supplied network classification. Advisory.\",\"enum\":[\"unknown\",\"home\",\"corp\",\"public\",\"vpn\"],\"type\":\"string\"}},\"title\":\"ConsumerContext\",\"type\":\"object\"},\"DidcommAuthcryptEnvelope\":{\"additionalProperties\":false,\"description\":\"DIDComm v2 authcrypt JWE (ECDH-1PU + A256CBC-HS512, X25519/P-256 key agreement). Sender authentication is the JWE's `skid` — the producer's DID#keyAgreement. The maintainer's keyAgreement key is the recipient. Cleartext is JCS-canonical JSON of the variant's payload type.\\n\\nM2A is the only implementation today; this is also the canonical default for new code.\",\"properties\":{\"envelope\":{\"const\":\"didcomm-authcrypt\"},\"jwe\":{\"description\":\"Compact DIDComm v2 JWE (base64url-encoded, dot-separated). Unpacks via the framework's standard DIDComm machinery; cleartext is the payload-specific JSON.\",\"minLength\":1,\"type\":\"string\"}},\"required\":[\"envelope\",\"jwe\"],\"title\":\"DidcommAuthcryptEnvelope\",\"type\":\"object\"},\"Ext\":{\"additionalProperties\":true,\"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.\",\"minProperties\":1,\"propertyNames\":{\"pattern\":\"^[a-z][a-z0-9-]*(\\\\.[a-z0-9-]+)+$\"},\"title\":\"Ext\",\"type\":\"object\"},\"HpkeArmoredEnvelope\":{\"additionalProperties\":false,\"description\":\"OpenPGP-style ASCII-armored HPKE bundle — the existing OpenVTC sealed-transfer wire form (X25519-HKDF-SHA256 KEM + ChaCha20-Poly1305 AEAD, framed in armor with Bundle-Id / Digest-Algo headers and a CRC24 checksum). Producer assertion (`did-signed` / `attested` / `pinned-only`) is the integrity / authenticity anchor.\\n\\nNo open-source implementation reads this yet outside vta-sdk's `sealed_transfer` crate; new code SHOULD prefer the DIDComm variant. Defined here for parity with the existing offline-bundle / cross-VTA workflows that the design plan reserves for M5+.\",\"properties\":{\"armored\":{\"description\":\"ASCII-armored bundle text. Multi-line base64 with framing headers + CRC24.\",\"minLength\":1,\"type\":\"string\"},\"envelope\":{\"const\":\"hpke-armored\"},\"producerAssertion\":{\"default\":\"did-signed\",\"description\":\"Producer-assertion mode per the sealed-transfer framework. `did-signed` = Ed25519 signature by issuer; `attested` = TEE attestation quote (e.g. Nitro); `pinned-only` = OOB SHA-256 digest only (dev/test, NOT for production).\",\"enum\":[\"did-signed\",\"attested\",\"pinned-only\"],\"type\":\"string\"},\"recipientKeyId\":{\"description\":\"did:key identifier of the X25519 public key the envelope was sealed to. The recipient uses this to select the matching private key.\",\"minLength\":1,\"type\":\"string\"}},\"required\":[\"envelope\",\"armored\",\"recipientKeyId\"],\"title\":\"HpkeArmoredEnvelope\",\"type\":\"object\"},\"Response\":{\"$anchor\":\"response\",\"additionalProperties\":false,\"properties\":{\"ext\":{\"$ref\":\"#/$defs/Ext\"},\"sealedSessionBlob\":{\"$ref\":\"#/$defs/SealedEnvelope\",\"description\":\"Pluggable cipher envelope containing the SessionBlob cleartext (see `vault/_shared/0.1/session-blob`). The consumer unseals to recover cookies/headers, then injects into its browser session for the bound origin. Consumers reject envelope kinds they don't implement with `vault/proxy-login:envelopeUnsupported`.\"}},\"required\":[\"sealedSessionBlob\"],\"title\":\"Vault Proxy-Login — response payload\",\"type\":\"object\"},\"SealedEnvelope\":{\"description\":\"Discriminated by `envelope`. Exactly one variant matches per document.\",\"oneOf\":[{\"$ref\":\"#/$defs/DidcommAuthcryptEnvelope\"},{\"$ref\":\"#/$defs/HpkeArmoredEnvelope\"},{\"$ref\":\"#/$defs/TspMessageEnvelope\"}],\"title\":\"SealedEnvelope\"},\"SiteTarget\":{\"description\":\"A single binding target for a vault entry. Tagged union over the discriminator `kind`. A VaultEntry's `targets` array MAY mix any number of these.\",\"oneOf\":[{\"additionalProperties\":false,\"properties\":{\"kind\":{\"const\":\"web-origin\"},\"origin\":{\"description\":\"Web origin per RFC 6454 (scheme + host + optional port), e.g. \\\"https://github.com\\\". Compared by exact string equality after canonicalisation (lowercase host, default port elided). Consumers wanting subdomain coverage SHOULD add multiple targets, not encode a wildcard.\",\"format\":\"uri\",\"type\":\"string\"}},\"required\":[\"kind\",\"origin\"],\"title\":\"WebOrigin\",\"type\":\"object\"},{\"additionalProperties\":false,\"properties\":{\"did\":{\"description\":\"DID identifying the relying party (e.g. did:web:rp.example). The vault maintainer is responsible for any DID resolution required to act on this entry.\",\"minLength\":1,\"type\":\"string\"},\"kind\":{\"const\":\"did\"}},\"required\":[\"kind\",\"did\"],\"title\":\"Did\",\"type\":\"object\"},{\"additionalProperties\":false,\"properties\":{\"bundleId\":{\"description\":\"iOS bundle identifier in reverse-DNS form (e.g. \\\"com.github.stwalkerster.codehub\\\"). Compared by exact string equality. Matches when an iOS Companion identifies the requesting app via its bundle id (typically via the OS Credential Manager integration).\",\"minLength\":1,\"pattern\":\"^[A-Za-z0-9.-]+$\",\"type\":\"string\"},\"kind\":{\"const\":\"ios-app\"},\"teamId\":{\"description\":\"Optional Apple Developer Team identifier (10-character alphanumeric). When supplied, the maintainer SHOULD also verify the team id of the requesting app before matching — defense in depth against bundle-id squatting on jailbroken devices.\",\"minLength\":1,\"pattern\":\"^[A-Z0-9]+$\",\"type\":\"string\"}},\"required\":[\"kind\",\"bundleId\"],\"title\":\"IosApp\",\"type\":\"object\"},{\"additionalProperties\":false,\"properties\":{\"kind\":{\"const\":\"android-app\"},\"packageName\":{\"description\":\"Android package name in reverse-DNS form (e.g. \\\"com.github.android\\\").\",\"minLength\":1,\"pattern\":\"^[A-Za-z][A-Za-z0-9_]*(\\\\.[A-Za-z][A-Za-z0-9_]*)+$\",\"type\":\"string\"},\"sha256CertFingerprints\":{\"description\":\"SHA-256 fingerprints of the app's signing certificates, in colon-separated hex (the format `apksigner` and the Play Console emit). At least one fingerprint MUST be present. The maintainer matches when ANY of the provided fingerprints matches the requesting app's signature — this supports apps signed by multiple keys (e.g. during certificate rotation via Play App Signing).\",\"items\":{\"pattern\":\"^[0-9A-F]{2}(:[0-9A-F]{2}){31}$\",\"type\":\"string\"},\"minItems\":1,\"type\":\"array\",\"uniqueItems\":true}},\"required\":[\"kind\",\"packageName\",\"sha256CertFingerprints\"],\"title\":\"AndroidApp\",\"type\":\"object\"}],\"title\":\"SiteTarget\"},\"StepUpProof\":{\"additionalProperties\":false,\"properties\":{\"challengeId\":{\"description\":\"Maintainer-issued challenge id the proof responds to.\",\"minLength\":1,\"type\":\"string\"},\"kind\":{\"enum\":[\"webauthn-uv\",\"push-approval\",\"totp\"],\"type\":\"string\"},\"proof\":{\"description\":\"Format depends on kind: WebAuthn assertion (base64url), DIDComm approval-response message id, or 6–8-digit TOTP code.\",\"type\":\"string\"}},\"required\":[\"kind\",\"proof\",\"challengeId\"],\"title\":\"StepUpProof\",\"type\":\"object\"},\"TspMessageEnvelope\":{\"additionalProperties\":false,\"description\":\"Trust Spanning Protocol message (https://trustoverip.github.io/tswg-tsp-specification/). Reserved variant; no OpenVTC component reads or emits this today. Listed in the union so implementations can declare intent to use TSP in discovery and so consumers reject `tsp-message` envelopes explicitly (`envelopeUnsupported`) until they're wired up — rather than silently failing in DIDComm parsing.\",\"properties\":{\"envelope\":{\"const\":\"tsp-message\"},\"message\":{\"description\":\"Base64url-encoded TSP message bytes. Format reference: https://trustoverip.github.io/tswg-tsp-specification/#message-format\",\"minLength\":1,\"type\":\"string\"}},\"required\":[\"envelope\",\"message\"],\"title\":\"TspMessageEnvelope\",\"type\":\"object\"}},\"$id\":\"https://trusttasks.org/spec/vault/proxy-login/0.1\",\"$schema\":\"https://json-schema.org/draft/2020-12/schema\",\"additionalProperties\":false,\"description\":\"Consumer requests that the vault maintainer perform a login at the bound third-party site on the consumer's behalf, using the entry's secret material WITHOUT releasing it to the consumer. The maintainer returns a SessionBlob in a pluggable cipher envelope (see vault/_shared/0.1/sealed-envelope) containing the resulting cookies/headers the consumer can use to operate the session — but never the long-term credential.\",\"properties\":{\"consumerContext\":{\"$ref\":\"#/$defs/ConsumerContext\",\"description\":\"Caller's situational context — fed to the maintainer's policy engine to decide proxy vs fill, require step-up, etc. Producers populate what they can observe; fields are advisory and the maintainer MUST cross-check anything security-relevant against its own state.\"},\"entryId\":{\"description\":\"Vault entry id to log in with.\",\"minLength\":1,\"type\":\"string\"},\"ext\":{\"$ref\":\"#/$defs/Ext\"},\"nonce\":{\"description\":\"Optional caller-supplied nonce the maintainer SHOULD embed verbatim in the resulting session credential when one applies — typically the relying party's challenge for SIOPv2-shaped flows, where the SIOP id_token's `nonce` claim MUST match the RP's authorization-request `nonce` for the RP to verify the token. When omitted, the maintainer generates its own nonce; that path is appropriate for flows where the consumer doesn't need to bind the credential to an external challenge (e.g. push-mode logins that don't pre-fetch a challenge). Drivers that have no nonce concept (Password POST, OAuth refresh) ignore this field.\",\"maxLength\":512,\"minLength\":1,\"type\":\"string\"},\"stepUpProof\":{\"$ref\":\"#/$defs/StepUpProof\",\"description\":\"Optional — included on retry after a prior proxy-login attempt returned `stepUpRequired`.\"},\"target\":{\"$ref\":\"#/$defs/SiteTarget\",\"description\":\"Optional — when an entry has multiple targets, names which one the consumer is acting against. The maintainer matches this against the entry's `targets[]`; if not supplied, the maintainer chooses the most specific target compatible with the requesting consumer's form factor (e.g. an iOS Companion gets the iOS-app target if one exists; otherwise the web-origin target).\"},\"ttlSecondsHint\":{\"description\":\"Optional caller-preferred session TTL in seconds. The maintainer caps server-side per its policy; a higher hint MUST be silently truncated rather than rejected. Drivers that have a fixed-TTL bearer (e.g. SIOP id_tokens with their own `exp`) MUST NOT extend beyond the underlying credential's lifetime regardless of hint.\",\"maximum\":86400,\"minimum\":1,\"type\":\"integer\"}},\"required\":[\"entryId\"],\"title\":\"Vault Proxy-Login — payload\",\"type\":\"object\"}\n",
);
}
impl crate::Payload for Response {
const TYPE_URI: &'static str = "https://trusttasks.org/spec/vault/proxy-login/0.1#response";
const IS_PROOF_REQUIRED: bool = true;
const IS_ISSUED_AT_REQUIRED: bool = true;
const IS_RECIPIENT_REQUIRED: bool = true;
const PAYLOAD_SCHEMA: Option<&'static str> = Some(
"{\"$defs\":{\"ConsumerContext\":{\"additionalProperties\":false,\"properties\":{\"deviceId\":{\"description\":\"Device-binding id assigned at registration. The maintainer cross-checks this against the authenticated transport identity.\",\"minLength\":1,\"type\":\"string\"},\"lastUserVerificationAt\":{\"description\":\"Most recent local user-verification on the consumer device (WebAuthn UV, biometric unlock). The maintainer's policy may require this to be within N seconds.\",\"format\":\"date-time\",\"type\":\"string\"},\"networkClass\":{\"description\":\"Producer-supplied network classification. Advisory.\",\"enum\":[\"unknown\",\"home\",\"corp\",\"public\",\"vpn\"],\"type\":\"string\"}},\"title\":\"ConsumerContext\",\"type\":\"object\"},\"DidcommAuthcryptEnvelope\":{\"additionalProperties\":false,\"description\":\"DIDComm v2 authcrypt JWE (ECDH-1PU + A256CBC-HS512, X25519/P-256 key agreement). Sender authentication is the JWE's `skid` — the producer's DID#keyAgreement. The maintainer's keyAgreement key is the recipient. Cleartext is JCS-canonical JSON of the variant's payload type.\\n\\nM2A is the only implementation today; this is also the canonical default for new code.\",\"properties\":{\"envelope\":{\"const\":\"didcomm-authcrypt\"},\"jwe\":{\"description\":\"Compact DIDComm v2 JWE (base64url-encoded, dot-separated). Unpacks via the framework's standard DIDComm machinery; cleartext is the payload-specific JSON.\",\"minLength\":1,\"type\":\"string\"}},\"required\":[\"envelope\",\"jwe\"],\"title\":\"DidcommAuthcryptEnvelope\",\"type\":\"object\"},\"Ext\":{\"additionalProperties\":true,\"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.\",\"minProperties\":1,\"propertyNames\":{\"pattern\":\"^[a-z][a-z0-9-]*(\\\\.[a-z0-9-]+)+$\"},\"title\":\"Ext\",\"type\":\"object\"},\"HpkeArmoredEnvelope\":{\"additionalProperties\":false,\"description\":\"OpenPGP-style ASCII-armored HPKE bundle — the existing OpenVTC sealed-transfer wire form (X25519-HKDF-SHA256 KEM + ChaCha20-Poly1305 AEAD, framed in armor with Bundle-Id / Digest-Algo headers and a CRC24 checksum). Producer assertion (`did-signed` / `attested` / `pinned-only`) is the integrity / authenticity anchor.\\n\\nNo open-source implementation reads this yet outside vta-sdk's `sealed_transfer` crate; new code SHOULD prefer the DIDComm variant. Defined here for parity with the existing offline-bundle / cross-VTA workflows that the design plan reserves for M5+.\",\"properties\":{\"armored\":{\"description\":\"ASCII-armored bundle text. Multi-line base64 with framing headers + CRC24.\",\"minLength\":1,\"type\":\"string\"},\"envelope\":{\"const\":\"hpke-armored\"},\"producerAssertion\":{\"default\":\"did-signed\",\"description\":\"Producer-assertion mode per the sealed-transfer framework. `did-signed` = Ed25519 signature by issuer; `attested` = TEE attestation quote (e.g. Nitro); `pinned-only` = OOB SHA-256 digest only (dev/test, NOT for production).\",\"enum\":[\"did-signed\",\"attested\",\"pinned-only\"],\"type\":\"string\"},\"recipientKeyId\":{\"description\":\"did:key identifier of the X25519 public key the envelope was sealed to. The recipient uses this to select the matching private key.\",\"minLength\":1,\"type\":\"string\"}},\"required\":[\"envelope\",\"armored\",\"recipientKeyId\"],\"title\":\"HpkeArmoredEnvelope\",\"type\":\"object\"},\"Response\":{\"$anchor\":\"response\",\"additionalProperties\":false,\"properties\":{\"ext\":{\"$ref\":\"#/$defs/Ext\"},\"sealedSessionBlob\":{\"$ref\":\"#/$defs/SealedEnvelope\",\"description\":\"Pluggable cipher envelope containing the SessionBlob cleartext (see `vault/_shared/0.1/session-blob`). The consumer unseals to recover cookies/headers, then injects into its browser session for the bound origin. Consumers reject envelope kinds they don't implement with `vault/proxy-login:envelopeUnsupported`.\"}},\"required\":[\"sealedSessionBlob\"],\"title\":\"Vault Proxy-Login — response payload\",\"type\":\"object\"},\"SealedEnvelope\":{\"description\":\"Discriminated by `envelope`. Exactly one variant matches per document.\",\"oneOf\":[{\"$ref\":\"#/$defs/DidcommAuthcryptEnvelope\"},{\"$ref\":\"#/$defs/HpkeArmoredEnvelope\"},{\"$ref\":\"#/$defs/TspMessageEnvelope\"}],\"title\":\"SealedEnvelope\"},\"SiteTarget\":{\"description\":\"A single binding target for a vault entry. Tagged union over the discriminator `kind`. A VaultEntry's `targets` array MAY mix any number of these.\",\"oneOf\":[{\"additionalProperties\":false,\"properties\":{\"kind\":{\"const\":\"web-origin\"},\"origin\":{\"description\":\"Web origin per RFC 6454 (scheme + host + optional port), e.g. \\\"https://github.com\\\". Compared by exact string equality after canonicalisation (lowercase host, default port elided). Consumers wanting subdomain coverage SHOULD add multiple targets, not encode a wildcard.\",\"format\":\"uri\",\"type\":\"string\"}},\"required\":[\"kind\",\"origin\"],\"title\":\"WebOrigin\",\"type\":\"object\"},{\"additionalProperties\":false,\"properties\":{\"did\":{\"description\":\"DID identifying the relying party (e.g. did:web:rp.example). The vault maintainer is responsible for any DID resolution required to act on this entry.\",\"minLength\":1,\"type\":\"string\"},\"kind\":{\"const\":\"did\"}},\"required\":[\"kind\",\"did\"],\"title\":\"Did\",\"type\":\"object\"},{\"additionalProperties\":false,\"properties\":{\"bundleId\":{\"description\":\"iOS bundle identifier in reverse-DNS form (e.g. \\\"com.github.stwalkerster.codehub\\\"). Compared by exact string equality. Matches when an iOS Companion identifies the requesting app via its bundle id (typically via the OS Credential Manager integration).\",\"minLength\":1,\"pattern\":\"^[A-Za-z0-9.-]+$\",\"type\":\"string\"},\"kind\":{\"const\":\"ios-app\"},\"teamId\":{\"description\":\"Optional Apple Developer Team identifier (10-character alphanumeric). When supplied, the maintainer SHOULD also verify the team id of the requesting app before matching — defense in depth against bundle-id squatting on jailbroken devices.\",\"minLength\":1,\"pattern\":\"^[A-Z0-9]+$\",\"type\":\"string\"}},\"required\":[\"kind\",\"bundleId\"],\"title\":\"IosApp\",\"type\":\"object\"},{\"additionalProperties\":false,\"properties\":{\"kind\":{\"const\":\"android-app\"},\"packageName\":{\"description\":\"Android package name in reverse-DNS form (e.g. \\\"com.github.android\\\").\",\"minLength\":1,\"pattern\":\"^[A-Za-z][A-Za-z0-9_]*(\\\\.[A-Za-z][A-Za-z0-9_]*)+$\",\"type\":\"string\"},\"sha256CertFingerprints\":{\"description\":\"SHA-256 fingerprints of the app's signing certificates, in colon-separated hex (the format `apksigner` and the Play Console emit). At least one fingerprint MUST be present. The maintainer matches when ANY of the provided fingerprints matches the requesting app's signature — this supports apps signed by multiple keys (e.g. during certificate rotation via Play App Signing).\",\"items\":{\"pattern\":\"^[0-9A-F]{2}(:[0-9A-F]{2}){31}$\",\"type\":\"string\"},\"minItems\":1,\"type\":\"array\",\"uniqueItems\":true}},\"required\":[\"kind\",\"packageName\",\"sha256CertFingerprints\"],\"title\":\"AndroidApp\",\"type\":\"object\"}],\"title\":\"SiteTarget\"},\"StepUpProof\":{\"additionalProperties\":false,\"properties\":{\"challengeId\":{\"description\":\"Maintainer-issued challenge id the proof responds to.\",\"minLength\":1,\"type\":\"string\"},\"kind\":{\"enum\":[\"webauthn-uv\",\"push-approval\",\"totp\"],\"type\":\"string\"},\"proof\":{\"description\":\"Format depends on kind: WebAuthn assertion (base64url), DIDComm approval-response message id, or 6–8-digit TOTP code.\",\"type\":\"string\"}},\"required\":[\"kind\",\"proof\",\"challengeId\"],\"title\":\"StepUpProof\",\"type\":\"object\"},\"TspMessageEnvelope\":{\"additionalProperties\":false,\"description\":\"Trust Spanning Protocol message (https://trustoverip.github.io/tswg-tsp-specification/). Reserved variant; no OpenVTC component reads or emits this today. Listed in the union so implementations can declare intent to use TSP in discovery and so consumers reject `tsp-message` envelopes explicitly (`envelopeUnsupported`) until they're wired up — rather than silently failing in DIDComm parsing.\",\"properties\":{\"envelope\":{\"const\":\"tsp-message\"},\"message\":{\"description\":\"Base64url-encoded TSP message bytes. Format reference: https://trustoverip.github.io/tswg-tsp-specification/#message-format\",\"minLength\":1,\"type\":\"string\"}},\"required\":[\"envelope\",\"message\"],\"title\":\"TspMessageEnvelope\",\"type\":\"object\"}},\"$ref\":\"#/$defs/Response\",\"$schema\":\"https://json-schema.org/draft/2020-12/schema\"}\n",
);
}
impl crate::RequestPayload for Payload {
type Response = Response;
}
/// The earlier `MAJOR.MINOR` of this slug that this version declares it
/// extends (front matter `extends`, SPEC §5.2 "Declared extension"), or
/// `None`. Only the direct declaration; walk a chain with
/// [`crate::extension::extends_for`].
pub const EXTENDS: Option<&str> = None;
/// 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::NOT_FOUND,
error_codes::STEP_UP_REQUIRED,
error_codes::TARGET_UNREACHABLE,
error_codes::CREDENTIAL_REJECTED,
error_codes::NOT_PROXYABLE,
error_codes::POLICY_DENY,
error_codes::ENVELOPE_UNSUPPORTED,
];
/// 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 {
/// `vault/proxy-login:notFound`
///
/// No entry with this id exists in the consumer's scope.
///
/// Declared `retryable: false`.
pub const NOT_FOUND: crate::DeclaredErrorCode = crate::DeclaredErrorCode {
code: "vault/proxy-login:notFound",
retryable: false,
details_schema: ::core::option::Option::None,
};
/// `vault/proxy-login:stepUpRequired`
///
/// Policy demands a step-up proof before the login can proceed. Consumer retries with `stepUpProof` populated.
///
/// Declared `retryable: true`.
/// Declares a `detailsSchema` for the error's `details` member.
pub const STEP_UP_REQUIRED: crate::DeclaredErrorCode = crate::DeclaredErrorCode {
code: "vault/proxy-login:stepUpRequired",
retryable: true,
details_schema: ::core::option::Option::Some(
"{\"additionalProperties\":false,\"properties\":{\"challengeId\":{\"type\":\"string\"},\"method\":{\"enum\":[\"webauthn-uv\",\"push-approval\",\"totp\"],\"type\":\"string\"},\"ttlSeconds\":{\"minimum\":1,\"type\":\"integer\"}},\"required\":[\"method\",\"challengeId\"],\"type\":\"object\"}",
),
};
/// `vault/proxy-login:targetUnreachable`
///
/// The maintainer attempted the login at the third-party site but the site is unreachable, rate-limiting, or returned an unexpected response. Consumer SHOULD retry with backoff.
///
/// Declared `retryable: true`.
pub const TARGET_UNREACHABLE: crate::DeclaredErrorCode = crate::DeclaredErrorCode {
code: "vault/proxy-login:targetUnreachable",
retryable: true,
details_schema: ::core::option::Option::None,
};
/// `vault/proxy-login:credentialRejected`
///
/// The maintainer attempted the login but the third party rejected the credential (wrong password, expired token, revoked passkey). Consumer SHOULD prompt the user to update the entry via vault/upsert.
///
/// Declared `retryable: false`.
pub const CREDENTIAL_REJECTED: crate::DeclaredErrorCode = crate::DeclaredErrorCode {
code: "vault/proxy-login:credentialRejected",
retryable: false,
details_schema: ::core::option::Option::None,
};
/// `vault/proxy-login:notProxyable`
///
/// This entry cannot be proxy-logged-in (e.g. the site requires browser-bound channel binding). Consumer falls back to vault/release for a fill flow.
///
/// Declared `retryable: false`.
pub const NOT_PROXYABLE: crate::DeclaredErrorCode = crate::DeclaredErrorCode {
code: "vault/proxy-login:notProxyable",
retryable: false,
details_schema: ::core::option::Option::None,
};
/// `vault/proxy-login:policyDeny`
///
/// Policy denies proxy-login for this consumer + entry combination outright (no step-up will satisfy it).
///
/// Declared `retryable: false`.
pub const POLICY_DENY: crate::DeclaredErrorCode = crate::DeclaredErrorCode {
code: "vault/proxy-login:policyDeny",
retryable: false,
details_schema: ::core::option::Option::None,
};
/// `vault/proxy-login:envelopeUnsupported`
///
/// The maintainer cannot emit a `sealedSessionBlob` in any envelope kind the consumer accepts. Producers SHOULD consult `trust-task-discovery/0.1` for the maintainer's emit set.
///
/// Declared `retryable: false`.
/// Declares a `detailsSchema` for the error's `details` member.
pub const ENVELOPE_UNSUPPORTED: crate::DeclaredErrorCode = crate::DeclaredErrorCode {
code: "vault/proxy-login:envelopeUnsupported",
retryable: false,
details_schema: ::core::option::Option::Some(
"{\"additionalProperties\":false,\"properties\":{\"requestedEnvelope\":{\"type\":\"string\"},\"supportedEnvelopes\":{\"items\":{\"type\":\"string\"},\"type\":\"array\"}},\"type\":\"object\"}",
),
};
}