//! Generated by `trust-tasks-codegen` — do not edit by hand.
//!
//! Spec slug: `vetting/request`. Version: `0.1`.
#[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 cryptographic digest as a multibase-encoded multihash — the encoding the W3C Verifiable Credentials Data Model 2.0 defines for `digestMultibase`, and the one `did:webvh` uses for its SCID and entry hashes.
Multihash carries the hash algorithm in-band, so the value is self-describing and the wire format survives an algorithm change without a schema revision; multibase does the same for the base encoding, so a verifier never infers base58 from base64url by context. A bare hex string or a `sha-256:`-style prefix hard-codes one algorithm into the wire contract and is non-conforming here.
This definition constrains the *encoding only*. What the digest is computed over is stated by each referencing field, because it differs legitimately: a digest over a JSON document is taken over its RFC 8785 (JCS) canonicalization, while a digest over an opaque artifact is taken over its bytes. A field whose input is a JSON document and which does not name a canonicalization is not reproducible.
Restricted to the two multibase headers W3C Controlled Identifiers 1.0 §2.4 normatively requires — `z` (base58btc) and `u` (base64url-no-pad). CID permits others but states that "interoperability is not guaranteed between implementations using such values", and a registry whose purpose is interoperability should not mint digests a conforming verifier may be unable to read. The alphabets are enforced rather than assumed: base58btc excludes 0, O, I and l, and an earlier permissive pattern let three published examples carry digests that were not valid base58 at all. base58btc is RECOMMENDED, for consistency with `did:key` and `did:webvh`.*/
///
/// <details><summary>JSON schema</summary>
///
/// ```json
///{
/// "title": "DigestMultibase",
/// "description": "\nA cryptographic digest as a multibase-encoded multihash — the encoding the W3C Verifiable Credentials Data Model 2.0 defines for `digestMultibase`, and the one `did:webvh` uses for its SCID and entry hashes.\n\nMultihash carries the hash algorithm in-band, so the value is self-describing and the wire format survives an algorithm change without a schema revision; multibase does the same for the base encoding, so a verifier never infers base58 from base64url by context. A bare hex string or a `sha-256:`-style prefix hard-codes one algorithm into the wire contract and is non-conforming here.\n\nThis definition constrains the *encoding only*. What the digest is computed over is stated by each referencing field, because it differs legitimately: a digest over a JSON document is taken over its RFC 8785 (JCS) canonicalization, while a digest over an opaque artifact is taken over its bytes. A field whose input is a JSON document and which does not name a canonicalization is not reproducible.\n\nRestricted to the two multibase headers W3C Controlled Identifiers 1.0 §2.4 normatively requires — `z` (base58btc) and `u` (base64url-no-pad). CID permits others but states that \"interoperability is not guaranteed between implementations using such values\", and a registry whose purpose is interoperability should not mint digests a conforming verifier may be unable to read. The alphabets are enforced rather than assumed: base58btc excludes 0, O, I and l, and an earlier permissive pattern let three published examples carry digests that were not valid base58 at all. base58btc is RECOMMENDED, for consistency with `did:key` and `did:webvh`.",
/// "examples": [
/// "zQmbWqxBEKC3P8tqsKc98xmWNzrzDtRLMiMPL8wBuTGsMnR"
/// ],
/// "type": "string",
/// "minLength": 16,
/// "pattern": "^(z[1-9A-HJ-NP-Za-km-z]+|u[A-Za-z0-9_-]+)$"
///}
/// ```
/// </details>
#[derive(::serde::Serialize, Clone, Debug, Eq, Hash, Ord, PartialEq, PartialOrd)]
#[serde(transparent)]
pub struct DigestMultibase(::std::string::String);
impl ::std::ops::Deref for DigestMultibase {
type Target = ::std::string::String;
fn deref(&self) -> &::std::string::String {
&self.0
}
}
impl ::std::convert::From<DigestMultibase> for ::std::string::String {
fn from(value: DigestMultibase) -> Self {
value.0
}
}
impl ::std::str::FromStr for DigestMultibase {
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());
}
static PATTERN: ::std::sync::LazyLock<::regress::Regex> =
::std::sync::LazyLock::new(|| {
::regress::Regex::new("^(z[1-9A-HJ-NP-Za-km-z]+|u[A-Za-z0-9_-]+)$").unwrap()
});
if PATTERN.find(value).is_none() {
return Err(
"doesn't match pattern \"^(z[1-9A-HJ-NP-Za-km-z]+|u[A-Za-z0-9_-]+)$\"".into(),
);
}
Ok(Self(value.to_string()))
}
}
impl ::std::convert::TryFrom<&str> for DigestMultibase {
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 DigestMultibase {
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 DigestMultibase {
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 DigestMultibase {
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. A W3C Verifiable Presentation by which the vetter shows the applicant that it currently holds the community's vetter role. Bound to this request by `nonce` (the vetting/request document's `id`, which the applicant chose) and to this applicant by `domain` (its `joinDid`), so it cannot be replayed to another request or another applicant. The applicant's check is advisory; the community evaluates eligibility again, authoritatively, when it decides. Members other than those defined here are permitted, as the VC data model allows.
///
/// <details><summary>JSON schema</summary>
///
/// ```json
///{
/// "title": "EligibilityPresentation",
/// "description": "OPTIONAL. A W3C Verifiable Presentation by which the vetter shows the applicant that it currently holds the community's vetter role. Bound to this request by `nonce` (the vetting/request document's `id`, which the applicant chose) and to this applicant by `domain` (its `joinDid`), so it cannot be replayed to another request or another applicant. The applicant's check is advisory; the community evaluates eligibility again, authoritatively, when it decides. Members other than those defined here are permitted, as the VC data model allows.",
/// "type": "object",
/// "required": [
/// "@context",
/// "domain",
/// "holder",
/// "nonce",
/// "proof",
/// "type",
/// "verifiableCredential"
/// ],
/// "properties": {
/// "@context": {
/// "description": "JSON-LD contexts. The first item MUST be `https://www.w3.org/ns/credentials/v2` (stated here rather than as `prefixItems`, which the Rust generator cannot express).",
/// "type": "array",
/// "items": {
/// "type": "string",
/// "maxLength": 2048,
/// "minLength": 1
/// },
/// "minItems": 1
/// },
/// "domain": {
/// "description": "The applicant's `joinDid` from that request.",
/// "type": "string",
/// "pattern": "^did:"
/// },
/// "holder": {
/// "description": "The vetter's DID — the response's `issuer`.",
/// "type": "string",
/// "pattern": "^did:"
/// },
/// "nonce": {
/// "description": "The `id` of the vetting/request document this responds to.",
/// "type": "string",
/// "maxLength": 512,
/// "minLength": 1
/// },
/// "proof": {
/// "$ref": "#/definitions/EligibilityPresentationProof"
/// },
/// "type": {
/// "description": "MUST include `VerifiablePresentation` (stated here rather than as `contains`, which the Rust generator cannot express).",
/// "type": "array",
/// "items": {
/// "type": "string",
/// "maxLength": 128,
/// "minLength": 1
/// },
/// "minItems": 1,
/// "uniqueItems": true
/// },
/// "verifiableCredential": {
/// "description": "Credentials presented (opaque here). MUST include the community-issued `CommunityRole` endorsement credential naming `holder`, whose `endorsement.role` is the manifest's `eligibleVetters.role` — see vtc/vetting/vetters/grant/0.1. MAY include others, such as the membership credential.",
/// "type": "array",
/// "items": {
/// "type": "object"
/// },
/// "minItems": 1
/// }
/// },
/// "additionalProperties": true
///}
/// ```
/// </details>
#[derive(::serde::Deserialize, ::serde::Serialize, Clone, Debug)]
#[non_exhaustive]
pub struct EligibilityPresentation {
///JSON-LD contexts. The first item MUST be `https://www.w3.org/ns/credentials/v2` (stated here rather than as `prefixItems`, which the Rust generator cannot express).
#[serde(rename = "@context")]
pub context: ::std::vec::Vec<EligibilityPresentationContextItem>,
///The applicant's `joinDid` from that request.
pub domain: EligibilityPresentationDomain,
///The vetter's DID — the response's `issuer`.
pub holder: EligibilityPresentationHolder,
///The `id` of the vetting/request document this responds to.
pub nonce: EligibilityPresentationNonce,
pub proof: EligibilityPresentationProof,
///MUST include `VerifiablePresentation` (stated here rather than as `contains`, which the Rust generator cannot express).
#[serde(rename = "type")]
pub type_: Vec<EligibilityPresentationTypeItem>,
///Credentials presented (opaque here). MUST include the community-issued `CommunityRole` endorsement credential naming `holder`, whose `endorsement.role` is the manifest's `eligibleVetters.role` — see vtc/vetting/vetters/grant/0.1. MAY include others, such as the membership credential.
#[serde(rename = "verifiableCredential")]
pub verifiable_credential:
::std::vec::Vec<::serde_json::Map<::std::string::String, ::serde_json::Value>>,
}
impl EligibilityPresentation {
pub fn builder() -> builder::EligibilityPresentation {
Default::default()
}
}
///`EligibilityPresentationContextItem`
///
/// <details><summary>JSON schema</summary>
///
/// ```json
///{
/// "type": "string",
/// "maxLength": 2048,
/// "minLength": 1
///}
/// ```
/// </details>
#[derive(::serde::Serialize, Clone, Debug, Eq, Hash, Ord, PartialEq, PartialOrd)]
#[serde(transparent)]
pub struct EligibilityPresentationContextItem(::std::string::String);
impl ::std::ops::Deref for EligibilityPresentationContextItem {
type Target = ::std::string::String;
fn deref(&self) -> &::std::string::String {
&self.0
}
}
impl ::std::convert::From<EligibilityPresentationContextItem> for ::std::string::String {
fn from(value: EligibilityPresentationContextItem) -> Self {
value.0
}
}
impl ::std::str::FromStr for EligibilityPresentationContextItem {
type Err = self::error::ConversionError;
fn from_str(value: &str) -> ::std::result::Result<Self, self::error::ConversionError> {
if value.chars().count() > 2048usize {
return Err("longer than 2048 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 EligibilityPresentationContextItem {
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 EligibilityPresentationContextItem {
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 EligibilityPresentationContextItem {
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 EligibilityPresentationContextItem {
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 applicant's `joinDid` from that request.
///
/// <details><summary>JSON schema</summary>
///
/// ```json
///{
/// "description": "The applicant's `joinDid` from that request.",
/// "type": "string",
/// "pattern": "^did:"
///}
/// ```
/// </details>
#[derive(::serde::Serialize, Clone, Debug, Eq, Hash, Ord, PartialEq, PartialOrd)]
#[serde(transparent)]
pub struct EligibilityPresentationDomain(::std::string::String);
impl ::std::ops::Deref for EligibilityPresentationDomain {
type Target = ::std::string::String;
fn deref(&self) -> &::std::string::String {
&self.0
}
}
impl ::std::convert::From<EligibilityPresentationDomain> for ::std::string::String {
fn from(value: EligibilityPresentationDomain) -> Self {
value.0
}
}
impl ::std::str::FromStr for EligibilityPresentationDomain {
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("^did:").unwrap());
if PATTERN.find(value).is_none() {
return Err("doesn't match pattern \"^did:\"".into());
}
Ok(Self(value.to_string()))
}
}
impl ::std::convert::TryFrom<&str> for EligibilityPresentationDomain {
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 EligibilityPresentationDomain {
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 EligibilityPresentationDomain {
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 EligibilityPresentationDomain {
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 vetter's DID — the response's `issuer`.
///
/// <details><summary>JSON schema</summary>
///
/// ```json
///{
/// "description": "The vetter's DID — the response's `issuer`.",
/// "type": "string",
/// "pattern": "^did:"
///}
/// ```
/// </details>
#[derive(::serde::Serialize, Clone, Debug, Eq, Hash, Ord, PartialEq, PartialOrd)]
#[serde(transparent)]
pub struct EligibilityPresentationHolder(::std::string::String);
impl ::std::ops::Deref for EligibilityPresentationHolder {
type Target = ::std::string::String;
fn deref(&self) -> &::std::string::String {
&self.0
}
}
impl ::std::convert::From<EligibilityPresentationHolder> for ::std::string::String {
fn from(value: EligibilityPresentationHolder) -> Self {
value.0
}
}
impl ::std::str::FromStr for EligibilityPresentationHolder {
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("^did:").unwrap());
if PATTERN.find(value).is_none() {
return Err("doesn't match pattern \"^did:\"".into());
}
Ok(Self(value.to_string()))
}
}
impl ::std::convert::TryFrom<&str> for EligibilityPresentationHolder {
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 EligibilityPresentationHolder {
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 EligibilityPresentationHolder {
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 EligibilityPresentationHolder {
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 `id` of the vetting/request document this responds to.
///
/// <details><summary>JSON schema</summary>
///
/// ```json
///{
/// "description": "The `id` of the vetting/request document this responds to.",
/// "type": "string",
/// "maxLength": 512,
/// "minLength": 1
///}
/// ```
/// </details>
#[derive(::serde::Serialize, Clone, Debug, Eq, Hash, Ord, PartialEq, PartialOrd)]
#[serde(transparent)]
pub struct EligibilityPresentationNonce(::std::string::String);
impl ::std::ops::Deref for EligibilityPresentationNonce {
type Target = ::std::string::String;
fn deref(&self) -> &::std::string::String {
&self.0
}
}
impl ::std::convert::From<EligibilityPresentationNonce> for ::std::string::String {
fn from(value: EligibilityPresentationNonce) -> Self {
value.0
}
}
impl ::std::str::FromStr for EligibilityPresentationNonce {
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 EligibilityPresentationNonce {
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 EligibilityPresentationNonce {
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 EligibilityPresentationNonce {
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 EligibilityPresentationNonce {
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 W3C Data Integrity proof by `holder` over the presentation, `nonce` and `domain` included.
///
/// <details><summary>JSON schema</summary>
///
/// ```json
///{
/// "title": "EligibilityPresentationProof",
/// "description": "A W3C Data Integrity proof by `holder` over the presentation, `nonce` and `domain` included.",
/// "type": "object",
/// "required": [
/// "cryptosuite",
/// "proofPurpose",
/// "proofValue",
/// "type",
/// "verificationMethod"
/// ],
/// "properties": {
/// "created": {
/// "type": "string",
/// "format": "date-time"
/// },
/// "cryptosuite": {
/// "description": "e.g. `eddsa-jcs-2022`.",
/// "type": "string",
/// "maxLength": 64,
/// "minLength": 1,
/// "pattern": "^[a-z0-9-]+$"
/// },
/// "proofPurpose": {
/// "type": "string",
/// "const": "authentication"
/// },
/// "proofValue": {
/// "type": "string",
/// "pattern": "^z[1-9A-HJ-NP-Za-km-z]+$"
/// },
/// "type": {
/// "type": "string",
/// "const": "DataIntegrityProof"
/// },
/// "verificationMethod": {
/// "description": "A verification method of `holder`, authorized for `authentication`.",
/// "type": "string",
/// "pattern": "^did:"
/// }
/// },
/// "additionalProperties": true
///}
/// ```
/// </details>
#[derive(::serde::Deserialize, ::serde::Serialize, Clone, Debug)]
#[non_exhaustive]
pub struct EligibilityPresentationProof {
#[serde(default, skip_serializing_if = "::std::option::Option::is_none")]
pub created: ::std::option::Option<::chrono::DateTime<::chrono::offset::Utc>>,
///e.g. `eddsa-jcs-2022`.
pub cryptosuite: EligibilityPresentationProofCryptosuite,
#[serde(rename = "proofPurpose")]
pub proof_purpose: ::std::string::String,
#[serde(rename = "proofValue")]
pub proof_value: EligibilityPresentationProofProofValue,
#[serde(rename = "type")]
pub type_: ::std::string::String,
///A verification method of `holder`, authorized for `authentication`.
#[serde(rename = "verificationMethod")]
pub verification_method: EligibilityPresentationProofVerificationMethod,
}
impl EligibilityPresentationProof {
pub fn builder() -> builder::EligibilityPresentationProof {
Default::default()
}
}
///e.g. `eddsa-jcs-2022`.
///
/// <details><summary>JSON schema</summary>
///
/// ```json
///{
/// "description": "e.g. `eddsa-jcs-2022`.",
/// "type": "string",
/// "maxLength": 64,
/// "minLength": 1,
/// "pattern": "^[a-z0-9-]+$"
///}
/// ```
/// </details>
#[derive(::serde::Serialize, Clone, Debug, Eq, Hash, Ord, PartialEq, PartialOrd)]
#[serde(transparent)]
pub struct EligibilityPresentationProofCryptosuite(::std::string::String);
impl ::std::ops::Deref for EligibilityPresentationProofCryptosuite {
type Target = ::std::string::String;
fn deref(&self) -> &::std::string::String {
&self.0
}
}
impl ::std::convert::From<EligibilityPresentationProofCryptosuite> for ::std::string::String {
fn from(value: EligibilityPresentationProofCryptosuite) -> Self {
value.0
}
}
impl ::std::str::FromStr for EligibilityPresentationProofCryptosuite {
type Err = self::error::ConversionError;
fn from_str(value: &str) -> ::std::result::Result<Self, self::error::ConversionError> {
if value.chars().count() > 64usize {
return Err("longer than 64 characters".into());
}
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 EligibilityPresentationProofCryptosuite {
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 EligibilityPresentationProofCryptosuite {
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 EligibilityPresentationProofCryptosuite {
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 EligibilityPresentationProofCryptosuite {
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())
})
}
}
///`EligibilityPresentationProofProofValue`
///
/// <details><summary>JSON schema</summary>
///
/// ```json
///{
/// "type": "string",
/// "pattern": "^z[1-9A-HJ-NP-Za-km-z]+$"
///}
/// ```
/// </details>
#[derive(::serde::Serialize, Clone, Debug, Eq, Hash, Ord, PartialEq, PartialOrd)]
#[serde(transparent)]
pub struct EligibilityPresentationProofProofValue(::std::string::String);
impl ::std::ops::Deref for EligibilityPresentationProofProofValue {
type Target = ::std::string::String;
fn deref(&self) -> &::std::string::String {
&self.0
}
}
impl ::std::convert::From<EligibilityPresentationProofProofValue> for ::std::string::String {
fn from(value: EligibilityPresentationProofProofValue) -> Self {
value.0
}
}
impl ::std::str::FromStr for EligibilityPresentationProofProofValue {
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("^z[1-9A-HJ-NP-Za-km-z]+$").unwrap()
});
if PATTERN.find(value).is_none() {
return Err("doesn't match pattern \"^z[1-9A-HJ-NP-Za-km-z]+$\"".into());
}
Ok(Self(value.to_string()))
}
}
impl ::std::convert::TryFrom<&str> for EligibilityPresentationProofProofValue {
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 EligibilityPresentationProofProofValue {
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 EligibilityPresentationProofProofValue {
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 EligibilityPresentationProofProofValue {
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 verification method of `holder`, authorized for `authentication`.
///
/// <details><summary>JSON schema</summary>
///
/// ```json
///{
/// "description": "A verification method of `holder`, authorized for `authentication`.",
/// "type": "string",
/// "pattern": "^did:"
///}
/// ```
/// </details>
#[derive(::serde::Serialize, Clone, Debug, Eq, Hash, Ord, PartialEq, PartialOrd)]
#[serde(transparent)]
pub struct EligibilityPresentationProofVerificationMethod(::std::string::String);
impl ::std::ops::Deref for EligibilityPresentationProofVerificationMethod {
type Target = ::std::string::String;
fn deref(&self) -> &::std::string::String {
&self.0
}
}
impl ::std::convert::From<EligibilityPresentationProofVerificationMethod>
for ::std::string::String
{
fn from(value: EligibilityPresentationProofVerificationMethod) -> Self {
value.0
}
}
impl ::std::str::FromStr for EligibilityPresentationProofVerificationMethod {
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("^did:").unwrap());
if PATTERN.find(value).is_none() {
return Err("doesn't match pattern \"^did:\"".into());
}
Ok(Self(value.to_string()))
}
}
impl ::std::convert::TryFrom<&str> for EligibilityPresentationProofVerificationMethod {
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 EligibilityPresentationProofVerificationMethod
{
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 EligibilityPresentationProofVerificationMethod
{
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 EligibilityPresentationProofVerificationMethod {
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())
})
}
}
///`EligibilityPresentationTypeItem`
///
/// <details><summary>JSON schema</summary>
///
/// ```json
///{
/// "type": "string",
/// "maxLength": 128,
/// "minLength": 1
///}
/// ```
/// </details>
#[derive(::serde::Serialize, Clone, Debug, Eq, Hash, Ord, PartialEq, PartialOrd)]
#[serde(transparent)]
pub struct EligibilityPresentationTypeItem(::std::string::String);
impl ::std::ops::Deref for EligibilityPresentationTypeItem {
type Target = ::std::string::String;
fn deref(&self) -> &::std::string::String {
&self.0
}
}
impl ::std::convert::From<EligibilityPresentationTypeItem> for ::std::string::String {
fn from(value: EligibilityPresentationTypeItem) -> Self {
value.0
}
}
impl ::std::str::FromStr for EligibilityPresentationTypeItem {
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() < 1usize {
return Err("shorter than 1 characters".into());
}
Ok(Self(value.to_string()))
}
}
impl ::std::convert::TryFrom<&str> for EligibilityPresentationTypeItem {
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 EligibilityPresentationTypeItem {
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 EligibilityPresentationTypeItem {
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 EligibilityPresentationTypeItem {
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.
///
/// <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())
})
}
}
///An applicant asks one vetter to vet them for one community. The applicant is the document's issuer, and `joinDid` repeats that DID: it is the DID the applicant is applying with, and every card and statement that follows names it. Carries a ticket the vetter issued or an introduction, never both. The vetter's response accepts the request and proves the vetter is currently eligible to vet for that community.
///
/// <details><summary>JSON schema</summary>
///
/// ```json
///{
/// "$id": "https://trusttasks.org/spec/vetting/request/0.1",
/// "title": "Payload",
/// "description": "An applicant asks one vetter to vet them for one community. The applicant is the document's issuer, and `joinDid` repeats that DID: it is the DID the applicant is applying with, and every card and statement that follows names it. Carries a ticket the vetter issued or an introduction, never both. The vetter's response accepts the request and proves the vetter is currently eligible to vet for that community.",
/// "type": "object",
/// "required": [
/// "community",
/// "joinDid"
/// ],
/// "properties": {
/// "availability": {
/// "description": "OPTIONAL applicant-authored free text on when they can meet. Scheduling is out of band; this is a hint, attributed to the applicant.",
/// "type": "string",
/// "maxLength": 256,
/// "minLength": 1
/// },
/// "community": {
/// "description": "The community the applicant is applying to and asks to be vetted for.",
/// "type": "string",
/// "pattern": "^did:"
/// },
/// "ext": {
/// "$ref": "#/definitions/Ext"
/// },
/// "introduction": {
/// "description": "A verifiable invitation credential for `community` whose subject is the applicant's DID, issued by the community or a member (opaque here). An alternative to a ticket for vetters who accept introductions.",
/// "type": "object"
/// },
/// "joinDid": {
/// "description": "The DID the applicant will join the community with. MUST equal the document's `issuer`. Every card and statement this request leads to names it, and it is the holder of the presentation the applicant eventually submits.",
/// "type": "string",
/// "pattern": "^did:"
/// },
/// "languages": {
/// "description": "BCP 47 language tags the applicant can hold a session in, most preferred first.",
/// "type": "array",
/// "items": {
/// "type": "string",
/// "maxLength": 35,
/// "pattern": "^[A-Za-z]{2,3}(-[A-Za-z0-9]{1,8})*$"
/// },
/// "maxItems": 16,
/// "uniqueItems": true
/// },
/// "message": {
/// "description": "OPTIONAL applicant-authored text for the vetter — typically how they know each other. Untrusted: read by the vetter, attributed to the applicant on every surface that renders it, never shown to the community.",
/// "type": "string",
/// "maxLength": 1000,
/// "minLength": 1
/// },
/// "preferredMethod": {
/// "description": "The method the applicant would prefer. A preference: the vetter chooses the session's method.",
/// "$ref": "#/definitions/VettingMethod"
/// },
/// "requirementsDigest": {
/// "description": "The `requirementsDigest` of the community's manifest criterion the applicant is gathering for, recorded when the application started. RECOMMENDED; a community that publishes no digest leaves the applicant nothing to cite.",
/// "$ref": "#/definitions/DigestMultibase"
/// },
/// "ticket": {
/// "$ref": "#/definitions/Ticket"
/// }
/// },
/// "additionalProperties": false,
/// "dependentSchemas": {
/// "ticket": {
/// "not": {
/// "required": [
/// "introduction"
/// ]
/// }
/// }
/// }
///}
/// ```
/// </details>
#[derive(::serde::Deserialize, ::serde::Serialize, Clone, Debug)]
#[serde(deny_unknown_fields)]
#[non_exhaustive]
pub struct Payload {
///OPTIONAL applicant-authored free text on when they can meet. Scheduling is out of band; this is a hint, attributed to the applicant.
#[serde(default, skip_serializing_if = "::std::option::Option::is_none")]
pub availability: ::std::option::Option<PayloadAvailability>,
///The community the applicant is applying to and asks to be vetted for.
pub community: PayloadCommunity,
#[serde(default, skip_serializing_if = "::std::option::Option::is_none")]
pub ext: ::std::option::Option<Ext>,
///A verifiable invitation credential for `community` whose subject is the applicant's DID, issued by the community or a member (opaque here). An alternative to a ticket for vetters who accept introductions.
#[serde(default, skip_serializing_if = "::serde_json::Map::is_empty")]
pub introduction: ::serde_json::Map<::std::string::String, ::serde_json::Value>,
///The DID the applicant will join the community with. MUST equal the document's `issuer`. Every card and statement this request leads to names it, and it is the holder of the presentation the applicant eventually submits.
#[serde(rename = "joinDid")]
pub join_did: PayloadJoinDid,
///BCP 47 language tags the applicant can hold a session in, most preferred first.
#[serde(default, skip_serializing_if = "::std::option::Option::is_none")]
pub languages: ::std::option::Option<Vec<PayloadLanguagesItem>>,
///OPTIONAL applicant-authored text for the vetter — typically how they know each other. Untrusted: read by the vetter, attributed to the applicant on every surface that renders it, never shown to the community.
#[serde(default, skip_serializing_if = "::std::option::Option::is_none")]
pub message: ::std::option::Option<PayloadMessage>,
///The method the applicant would prefer. A preference: the vetter chooses the session's method.
#[serde(
rename = "preferredMethod",
default,
skip_serializing_if = "::std::option::Option::is_none"
)]
pub preferred_method: ::std::option::Option<VettingMethod>,
///The `requirementsDigest` of the community's manifest criterion the applicant is gathering for, recorded when the application started. RECOMMENDED; a community that publishes no digest leaves the applicant nothing to cite.
#[serde(
rename = "requirementsDigest",
default,
skip_serializing_if = "::std::option::Option::is_none"
)]
pub requirements_digest: ::std::option::Option<DigestMultibase>,
#[serde(default, skip_serializing_if = "::std::option::Option::is_none")]
pub ticket: ::std::option::Option<Ticket>,
}
impl Payload {
pub fn builder() -> builder::Payload {
Default::default()
}
}
///OPTIONAL applicant-authored free text on when they can meet. Scheduling is out of band; this is a hint, attributed to the applicant.
///
/// <details><summary>JSON schema</summary>
///
/// ```json
///{
/// "description": "OPTIONAL applicant-authored free text on when they can meet. Scheduling is out of band; this is a hint, attributed to the applicant.",
/// "type": "string",
/// "maxLength": 256,
/// "minLength": 1
///}
/// ```
/// </details>
#[derive(::serde::Serialize, Clone, Debug, Eq, Hash, Ord, PartialEq, PartialOrd)]
#[serde(transparent)]
pub struct PayloadAvailability(::std::string::String);
impl ::std::ops::Deref for PayloadAvailability {
type Target = ::std::string::String;
fn deref(&self) -> &::std::string::String {
&self.0
}
}
impl ::std::convert::From<PayloadAvailability> for ::std::string::String {
fn from(value: PayloadAvailability) -> Self {
value.0
}
}
impl ::std::str::FromStr for PayloadAvailability {
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 PayloadAvailability {
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 PayloadAvailability {
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 PayloadAvailability {
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 PayloadAvailability {
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 community the applicant is applying to and asks to be vetted for.
///
/// <details><summary>JSON schema</summary>
///
/// ```json
///{
/// "description": "The community the applicant is applying to and asks to be vetted for.",
/// "type": "string",
/// "pattern": "^did:"
///}
/// ```
/// </details>
#[derive(::serde::Serialize, Clone, Debug, Eq, Hash, Ord, PartialEq, PartialOrd)]
#[serde(transparent)]
pub struct PayloadCommunity(::std::string::String);
impl ::std::ops::Deref for PayloadCommunity {
type Target = ::std::string::String;
fn deref(&self) -> &::std::string::String {
&self.0
}
}
impl ::std::convert::From<PayloadCommunity> for ::std::string::String {
fn from(value: PayloadCommunity) -> Self {
value.0
}
}
impl ::std::str::FromStr for PayloadCommunity {
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("^did:").unwrap());
if PATTERN.find(value).is_none() {
return Err("doesn't match pattern \"^did:\"".into());
}
Ok(Self(value.to_string()))
}
}
impl ::std::convert::TryFrom<&str> for PayloadCommunity {
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 PayloadCommunity {
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 PayloadCommunity {
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 PayloadCommunity {
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 DID the applicant will join the community with. MUST equal the document's `issuer`. Every card and statement this request leads to names it, and it is the holder of the presentation the applicant eventually submits.
///
/// <details><summary>JSON schema</summary>
///
/// ```json
///{
/// "description": "The DID the applicant will join the community with. MUST equal the document's `issuer`. Every card and statement this request leads to names it, and it is the holder of the presentation the applicant eventually submits.",
/// "type": "string",
/// "pattern": "^did:"
///}
/// ```
/// </details>
#[derive(::serde::Serialize, Clone, Debug, Eq, Hash, Ord, PartialEq, PartialOrd)]
#[serde(transparent)]
pub struct PayloadJoinDid(::std::string::String);
impl ::std::ops::Deref for PayloadJoinDid {
type Target = ::std::string::String;
fn deref(&self) -> &::std::string::String {
&self.0
}
}
impl ::std::convert::From<PayloadJoinDid> for ::std::string::String {
fn from(value: PayloadJoinDid) -> Self {
value.0
}
}
impl ::std::str::FromStr for PayloadJoinDid {
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("^did:").unwrap());
if PATTERN.find(value).is_none() {
return Err("doesn't match pattern \"^did:\"".into());
}
Ok(Self(value.to_string()))
}
}
impl ::std::convert::TryFrom<&str> for PayloadJoinDid {
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 PayloadJoinDid {
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 PayloadJoinDid {
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 PayloadJoinDid {
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())
})
}
}
///`PayloadLanguagesItem`
///
/// <details><summary>JSON schema</summary>
///
/// ```json
///{
/// "type": "string",
/// "maxLength": 35,
/// "pattern": "^[A-Za-z]{2,3}(-[A-Za-z0-9]{1,8})*$"
///}
/// ```
/// </details>
#[derive(::serde::Serialize, Clone, Debug, Eq, Hash, Ord, PartialEq, PartialOrd)]
#[serde(transparent)]
pub struct PayloadLanguagesItem(::std::string::String);
impl ::std::ops::Deref for PayloadLanguagesItem {
type Target = ::std::string::String;
fn deref(&self) -> &::std::string::String {
&self.0
}
}
impl ::std::convert::From<PayloadLanguagesItem> for ::std::string::String {
fn from(value: PayloadLanguagesItem) -> Self {
value.0
}
}
impl ::std::str::FromStr for PayloadLanguagesItem {
type Err = self::error::ConversionError;
fn from_str(value: &str) -> ::std::result::Result<Self, self::error::ConversionError> {
if value.chars().count() > 35usize {
return Err("longer than 35 characters".into());
}
static PATTERN: ::std::sync::LazyLock<::regress::Regex> =
::std::sync::LazyLock::new(|| {
::regress::Regex::new("^[A-Za-z]{2,3}(-[A-Za-z0-9]{1,8})*$").unwrap()
});
if PATTERN.find(value).is_none() {
return Err("doesn't match pattern \"^[A-Za-z]{2,3}(-[A-Za-z0-9]{1,8})*$\"".into());
}
Ok(Self(value.to_string()))
}
}
impl ::std::convert::TryFrom<&str> for PayloadLanguagesItem {
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 PayloadLanguagesItem {
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 PayloadLanguagesItem {
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 PayloadLanguagesItem {
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 applicant-authored text for the vetter — typically how they know each other. Untrusted: read by the vetter, attributed to the applicant on every surface that renders it, never shown to the community.
///
/// <details><summary>JSON schema</summary>
///
/// ```json
///{
/// "description": "OPTIONAL applicant-authored text for the vetter — typically how they know each other. Untrusted: read by the vetter, attributed to the applicant on every surface that renders it, never shown to the community.",
/// "type": "string",
/// "maxLength": 1000,
/// "minLength": 1
///}
/// ```
/// </details>
#[derive(::serde::Serialize, Clone, Debug, Eq, Hash, Ord, PartialEq, PartialOrd)]
#[serde(transparent)]
pub struct PayloadMessage(::std::string::String);
impl ::std::ops::Deref for PayloadMessage {
type Target = ::std::string::String;
fn deref(&self) -> &::std::string::String {
&self.0
}
}
impl ::std::convert::From<PayloadMessage> for ::std::string::String {
fn from(value: PayloadMessage) -> Self {
value.0
}
}
impl ::std::str::FromStr for PayloadMessage {
type Err = self::error::ConversionError;
fn from_str(value: &str) -> ::std::result::Result<Self, self::error::ConversionError> {
if value.chars().count() > 1000usize {
return Err("longer than 1000 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 PayloadMessage {
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 PayloadMessage {
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 PayloadMessage {
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 PayloadMessage {
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())
})
}
}
///`QrTicket`
///
/// <details><summary>JSON schema</summary>
///
/// ```json
///{
/// "title": "QrTicket",
/// "type": "object",
/// "required": [
/// "secret",
/// "ticketId"
/// ],
/// "properties": {
/// "secret": {
/// "description": "32 random bytes, base64url without padding.",
/// "type": "string",
/// "pattern": "^[A-Za-z0-9_-]{43}$"
/// },
/// "ticketId": {
/// "type": "string",
/// "maxLength": 128,
/// "minLength": 1,
/// "pattern": "^[A-Za-z0-9._:-]+$"
/// }
/// },
/// "additionalProperties": false
///}
/// ```
/// </details>
#[derive(::serde::Deserialize, ::serde::Serialize, Clone, Debug)]
#[serde(deny_unknown_fields)]
#[non_exhaustive]
pub struct QrTicket {
///32 random bytes, base64url without padding.
pub secret: QrTicketSecret,
#[serde(rename = "ticketId")]
pub ticket_id: QrTicketTicketId,
}
impl QrTicket {
pub fn builder() -> builder::QrTicket {
Default::default()
}
}
///32 random bytes, base64url without padding.
///
/// <details><summary>JSON schema</summary>
///
/// ```json
///{
/// "description": "32 random bytes, base64url without padding.",
/// "type": "string",
/// "pattern": "^[A-Za-z0-9_-]{43}$"
///}
/// ```
/// </details>
#[derive(::serde::Serialize, Clone, Debug, Eq, Hash, Ord, PartialEq, PartialOrd)]
#[serde(transparent)]
pub struct QrTicketSecret(::std::string::String);
impl ::std::ops::Deref for QrTicketSecret {
type Target = ::std::string::String;
fn deref(&self) -> &::std::string::String {
&self.0
}
}
impl ::std::convert::From<QrTicketSecret> for ::std::string::String {
fn from(value: QrTicketSecret) -> Self {
value.0
}
}
impl ::std::str::FromStr for QrTicketSecret {
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-Za-z0-9_-]{43}$").unwrap());
if PATTERN.find(value).is_none() {
return Err("doesn't match pattern \"^[A-Za-z0-9_-]{43}$\"".into());
}
Ok(Self(value.to_string()))
}
}
impl ::std::convert::TryFrom<&str> for QrTicketSecret {
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 QrTicketSecret {
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 QrTicketSecret {
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 QrTicketSecret {
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())
})
}
}
///`QrTicketTicketId`
///
/// <details><summary>JSON schema</summary>
///
/// ```json
///{
/// "type": "string",
/// "maxLength": 128,
/// "minLength": 1,
/// "pattern": "^[A-Za-z0-9._:-]+$"
///}
/// ```
/// </details>
#[derive(::serde::Serialize, Clone, Debug, Eq, Hash, Ord, PartialEq, PartialOrd)]
#[serde(transparent)]
pub struct QrTicketTicketId(::std::string::String);
impl ::std::ops::Deref for QrTicketTicketId {
type Target = ::std::string::String;
fn deref(&self) -> &::std::string::String {
&self.0
}
}
impl ::std::convert::From<QrTicketTicketId> for ::std::string::String {
fn from(value: QrTicketTicketId) -> Self {
value.0
}
}
impl ::std::str::FromStr for QrTicketTicketId {
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() < 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 QrTicketTicketId {
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 QrTicketTicketId {
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 QrTicketTicketId {
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 QrTicketTicketId {
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 vetter accepts the request. A refusal is a trust-task-error, never a response document.
///
/// <details><summary>JSON schema</summary>
///
/// ```json
///{
/// "title": "Response",
/// "description": "The vetter accepts the request. A refusal is a trust-task-error, never a response document.",
/// "type": "object",
/// "required": [
/// "requestId"
/// ],
/// "properties": {
/// "acceptsDocumentation": {
/// "description": "RECOMMENDED. What this vetter will rely on, so the applicant brings it — the vetter's own choice. `none` means the vetter attests from prior acquaintance.",
/// "type": "array",
/// "items": {
/// "$ref": "#/definitions/VettingDocumentation"
/// },
/// "minItems": 1,
/// "uniqueItems": true
/// },
/// "eligibilityVp": {
/// "$ref": "#/definitions/EligibilityPresentation"
/// },
/// "ext": {
/// "$ref": "#/definitions/Ext"
/// },
/// "requestId": {
/// "description": "The vetter's handle for this accepted request, carried by the session and any decline.",
/// "type": "string",
/// "maxLength": 128,
/// "minLength": 1
/// },
/// "sessionHint": {
/// "description": "OPTIONAL vetter-authored free text on how and when the session will happen. Attributed to the vetter.",
/// "type": "string",
/// "maxLength": 500,
/// "minLength": 1
/// }
/// },
/// "additionalProperties": false,
/// "$anchor": "response"
///}
/// ```
/// </details>
#[derive(::serde::Deserialize, ::serde::Serialize, Clone, Debug)]
#[serde(deny_unknown_fields)]
#[non_exhaustive]
pub struct Response {
///RECOMMENDED. What this vetter will rely on, so the applicant brings it — the vetter's own choice. `none` means the vetter attests from prior acquaintance.
#[serde(
rename = "acceptsDocumentation",
default,
skip_serializing_if = "::std::option::Option::is_none"
)]
pub accepts_documentation: ::std::option::Option<Vec<VettingDocumentation>>,
#[serde(
rename = "eligibilityVp",
default,
skip_serializing_if = "::std::option::Option::is_none"
)]
pub eligibility_vp: ::std::option::Option<EligibilityPresentation>,
#[serde(default, skip_serializing_if = "::std::option::Option::is_none")]
pub ext: ::std::option::Option<Ext>,
///The vetter's handle for this accepted request, carried by the session and any decline.
#[serde(rename = "requestId")]
pub request_id: ResponseRequestId,
///OPTIONAL vetter-authored free text on how and when the session will happen. Attributed to the vetter.
#[serde(
rename = "sessionHint",
default,
skip_serializing_if = "::std::option::Option::is_none"
)]
pub session_hint: ::std::option::Option<ResponseSessionHint>,
}
impl Response {
pub fn builder() -> builder::Response {
Default::default()
}
}
///The vetter's handle for this accepted request, carried by the session and any decline.
///
/// <details><summary>JSON schema</summary>
///
/// ```json
///{
/// "description": "The vetter's handle for this accepted request, carried by the session and any decline.",
/// "type": "string",
/// "maxLength": 128,
/// "minLength": 1
///}
/// ```
/// </details>
#[derive(::serde::Serialize, Clone, Debug, Eq, Hash, Ord, PartialEq, PartialOrd)]
#[serde(transparent)]
pub struct ResponseRequestId(::std::string::String);
impl ::std::ops::Deref for ResponseRequestId {
type Target = ::std::string::String;
fn deref(&self) -> &::std::string::String {
&self.0
}
}
impl ::std::convert::From<ResponseRequestId> for ::std::string::String {
fn from(value: ResponseRequestId) -> Self {
value.0
}
}
impl ::std::str::FromStr for ResponseRequestId {
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() < 1usize {
return Err("shorter than 1 characters".into());
}
Ok(Self(value.to_string()))
}
}
impl ::std::convert::TryFrom<&str> for ResponseRequestId {
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 ResponseRequestId {
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 ResponseRequestId {
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 ResponseRequestId {
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 vetter-authored free text on how and when the session will happen. Attributed to the vetter.
///
/// <details><summary>JSON schema</summary>
///
/// ```json
///{
/// "description": "OPTIONAL vetter-authored free text on how and when the session will happen. Attributed to the vetter.",
/// "type": "string",
/// "maxLength": 500,
/// "minLength": 1
///}
/// ```
/// </details>
#[derive(::serde::Serialize, Clone, Debug, Eq, Hash, Ord, PartialEq, PartialOrd)]
#[serde(transparent)]
pub struct ResponseSessionHint(::std::string::String);
impl ::std::ops::Deref for ResponseSessionHint {
type Target = ::std::string::String;
fn deref(&self) -> &::std::string::String {
&self.0
}
}
impl ::std::convert::From<ResponseSessionHint> for ::std::string::String {
fn from(value: ResponseSessionHint) -> Self {
value.0
}
}
impl ::std::str::FromStr for ResponseSessionHint {
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 ResponseSessionHint {
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 ResponseSessionHint {
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 ResponseSessionHint {
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 ResponseSessionHint {
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())
})
}
}
///`ShortCodeTicket`
///
/// <details><summary>JSON schema</summary>
///
/// ```json
///{
/// "title": "ShortCodeTicket",
/// "type": "object",
/// "required": [
/// "code"
/// ],
/// "properties": {
/// "code": {
/// "description": "Eight Crockford base32 characters, grouped four and four (40 bits). A secret the vetter handed over; not derived from anything.",
/// "type": "string",
/// "pattern": "^[0-9A-HJKMNP-TV-Z]{4}-[0-9A-HJKMNP-TV-Z]{4}$"
/// }
/// },
/// "additionalProperties": false
///}
/// ```
/// </details>
#[derive(::serde::Deserialize, ::serde::Serialize, Clone, Debug)]
#[serde(deny_unknown_fields)]
#[non_exhaustive]
pub struct ShortCodeTicket {
///Eight Crockford base32 characters, grouped four and four (40 bits). A secret the vetter handed over; not derived from anything.
pub code: ShortCodeTicketCode,
}
impl ShortCodeTicket {
pub fn builder() -> builder::ShortCodeTicket {
Default::default()
}
}
///Eight Crockford base32 characters, grouped four and four (40 bits). A secret the vetter handed over; not derived from anything.
///
/// <details><summary>JSON schema</summary>
///
/// ```json
///{
/// "description": "Eight Crockford base32 characters, grouped four and four (40 bits). A secret the vetter handed over; not derived from anything.",
/// "type": "string",
/// "pattern": "^[0-9A-HJKMNP-TV-Z]{4}-[0-9A-HJKMNP-TV-Z]{4}$"
///}
/// ```
/// </details>
#[derive(::serde::Serialize, Clone, Debug, Eq, Hash, Ord, PartialEq, PartialOrd)]
#[serde(transparent)]
pub struct ShortCodeTicketCode(::std::string::String);
impl ::std::ops::Deref for ShortCodeTicketCode {
type Target = ::std::string::String;
fn deref(&self) -> &::std::string::String {
&self.0
}
}
impl ::std::convert::From<ShortCodeTicketCode> for ::std::string::String {
fn from(value: ShortCodeTicketCode) -> Self {
value.0
}
}
impl ::std::str::FromStr for ShortCodeTicketCode {
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-HJKMNP-TV-Z]{4}-[0-9A-HJKMNP-TV-Z]{4}$").unwrap()
});
if PATTERN.find(value).is_none() {
return Err(
"doesn't match pattern \"^[0-9A-HJKMNP-TV-Z]{4}-[0-9A-HJKMNP-TV-Z]{4}$\"".into(),
);
}
Ok(Self(value.to_string()))
}
}
impl ::std::convert::TryFrom<&str> for ShortCodeTicketCode {
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 ShortCodeTicketCode {
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 ShortCodeTicketCode {
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 ShortCodeTicketCode {
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 ticket the vetter issued: the short code a person reads or types, or the full-entropy QR form.
///
/// <details><summary>JSON schema</summary>
///
/// ```json
///{
/// "title": "Ticket",
/// "description": "A ticket the vetter issued: the short code a person reads or types, or the full-entropy QR form.",
/// "oneOf": [
/// {
/// "$ref": "#/definitions/ShortCodeTicket"
/// },
/// {
/// "$ref": "#/definitions/QrTicket"
/// }
/// ]
///}
/// ```
/// </details>
#[derive(::serde::Deserialize, ::serde::Serialize, Clone, Debug)]
#[serde(untagged)]
#[non_exhaustive]
pub enum Ticket {
ShortCodeTicket(ShortCodeTicket),
QrTicket(QrTicket),
}
impl ::std::convert::From<ShortCodeTicket> for Ticket {
fn from(value: ShortCodeTicket) -> Self {
Self::ShortCodeTicket(value)
}
}
impl ::std::convert::From<QrTicket> for Ticket {
fn from(value: QrTicket) -> Self {
Self::QrTicket(value)
}
}
///A class of documentation, named in lowerCamelCase. Open rather than enumerated, because what documentation a vetter accepts is each vetter's own choice. Well-known values: `passport`, `nationalId`, `driverLicence`, and `none` — the vetter will attest without a document, which is the `priorAcquaintance` case. Only the class ever travels — never a document number, an image, an issuing authority or an expiry date. `none` states a policy (what a vetter accepts); a record of what was relied on expresses 'no document' as an empty list instead.
///
/// <details><summary>JSON schema</summary>
///
/// ```json
///{
/// "title": "VettingDocumentation",
/// "description": "A class of documentation, named in lowerCamelCase. Open rather than enumerated, because what documentation a vetter accepts is each vetter's own choice. Well-known values: `passport`, `nationalId`, `driverLicence`, and `none` — the vetter will attest without a document, which is the `priorAcquaintance` case. Only the class ever travels — never a document number, an image, an issuing authority or an expiry date. `none` states a policy (what a vetter accepts); a record of what was relied on expresses 'no document' as an empty list instead.",
/// "type": "string",
/// "maxLength": 64,
/// "minLength": 1,
/// "pattern": "^[a-z][a-zA-Z0-9]*$"
///}
/// ```
/// </details>
#[derive(::serde::Serialize, Clone, Debug, Eq, Hash, Ord, PartialEq, PartialOrd)]
#[serde(transparent)]
pub struct VettingDocumentation(::std::string::String);
impl ::std::ops::Deref for VettingDocumentation {
type Target = ::std::string::String;
fn deref(&self) -> &::std::string::String {
&self.0
}
}
impl ::std::convert::From<VettingDocumentation> for ::std::string::String {
fn from(value: VettingDocumentation) -> Self {
value.0
}
}
impl ::std::str::FromStr for VettingDocumentation {
type Err = self::error::ConversionError;
fn from_str(value: &str) -> ::std::result::Result<Self, self::error::ConversionError> {
if value.chars().count() > 64usize {
return Err("longer than 64 characters".into());
}
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-z][a-zA-Z0-9]*$").unwrap());
if PATTERN.find(value).is_none() {
return Err("doesn't match pattern \"^[a-z][a-zA-Z0-9]*$\"".into());
}
Ok(Self(value.to_string()))
}
}
impl ::std::convert::TryFrom<&str> for VettingDocumentation {
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 VettingDocumentation {
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 VettingDocumentation {
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 VettingDocumentation {
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())
})
}
}
///How the vetter established that the person they checked is the person controlling the applicant's DID. `inPerson` — both people were physically together. `video` — a live, two-way video call. `priorAcquaintance` — the vetter has known or worked with this person over a period, and attests from that knowledge rather than from a document. A method is a description of what happened, not an assurance level: which methods count, and how many of each, is community policy.
///
/// <details><summary>JSON schema</summary>
///
/// ```json
///{
/// "title": "VettingMethod",
/// "description": "How the vetter established that the person they checked is the person controlling the applicant's DID. `inPerson` — both people were physically together. `video` — a live, two-way video call. `priorAcquaintance` — the vetter has known or worked with this person over a period, and attests from that knowledge rather than from a document. A method is a description of what happened, not an assurance level: which methods count, and how many of each, is community policy.",
/// "type": "string",
/// "enum": [
/// "inPerson",
/// "video",
/// "priorAcquaintance"
/// ]
///}
/// ```
/// </details>
#[derive(
::serde::Deserialize,
::serde::Serialize,
Clone,
Copy,
Debug,
Eq,
Hash,
Ord,
PartialEq,
PartialOrd,
)]
#[non_exhaustive]
pub enum VettingMethod {
#[serde(rename = "inPerson")]
InPerson,
#[serde(rename = "video")]
Video,
#[serde(rename = "priorAcquaintance")]
PriorAcquaintance,
}
impl ::std::fmt::Display for VettingMethod {
fn fmt(&self, f: &mut ::std::fmt::Formatter<'_>) -> ::std::fmt::Result {
match *self {
Self::InPerson => f.write_str("inPerson"),
Self::Video => f.write_str("video"),
Self::PriorAcquaintance => f.write_str("priorAcquaintance"),
}
}
}
impl ::std::str::FromStr for VettingMethod {
type Err = self::error::ConversionError;
fn from_str(value: &str) -> ::std::result::Result<Self, self::error::ConversionError> {
match value {
"inPerson" => Ok(Self::InPerson),
"video" => Ok(Self::Video),
"priorAcquaintance" => Ok(Self::PriorAcquaintance),
_ => Err("invalid value".into()),
}
}
}
impl ::std::convert::TryFrom<&str> for VettingMethod {
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 VettingMethod {
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 VettingMethod {
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 EligibilityPresentation {
context: ::std::result::Result<
::std::vec::Vec<super::EligibilityPresentationContextItem>,
::std::string::String,
>,
domain: ::std::result::Result<super::EligibilityPresentationDomain, ::std::string::String>,
holder: ::std::result::Result<super::EligibilityPresentationHolder, ::std::string::String>,
nonce: ::std::result::Result<super::EligibilityPresentationNonce, ::std::string::String>,
proof: ::std::result::Result<super::EligibilityPresentationProof, ::std::string::String>,
type_: ::std::result::Result<
Vec<super::EligibilityPresentationTypeItem>,
::std::string::String,
>,
verifiable_credential: ::std::result::Result<
::std::vec::Vec<::serde_json::Map<::std::string::String, ::serde_json::Value>>,
::std::string::String,
>,
}
impl ::std::default::Default for EligibilityPresentation {
fn default() -> Self {
Self {
context: Err("no value supplied for context".to_string()),
domain: Err("no value supplied for domain".to_string()),
holder: Err("no value supplied for holder".to_string()),
nonce: Err("no value supplied for nonce".to_string()),
proof: Err("no value supplied for proof".to_string()),
type_: Err("no value supplied for type_".to_string()),
verifiable_credential: Err(
"no value supplied for verifiable_credential".to_string()
),
}
}
}
impl EligibilityPresentation {
pub fn context<T>(mut self, value: T) -> Self
where
T: ::std::convert::TryInto<::std::vec::Vec<super::EligibilityPresentationContextItem>>,
T::Error: ::std::fmt::Display,
{
self.context = value
.try_into()
.map_err(|e| format!("error converting supplied value for context: {e}"));
self
}
pub fn domain<T>(mut self, value: T) -> Self
where
T: ::std::convert::TryInto<super::EligibilityPresentationDomain>,
T::Error: ::std::fmt::Display,
{
self.domain = value
.try_into()
.map_err(|e| format!("error converting supplied value for domain: {e}"));
self
}
pub fn holder<T>(mut self, value: T) -> Self
where
T: ::std::convert::TryInto<super::EligibilityPresentationHolder>,
T::Error: ::std::fmt::Display,
{
self.holder = value
.try_into()
.map_err(|e| format!("error converting supplied value for holder: {e}"));
self
}
pub fn nonce<T>(mut self, value: T) -> Self
where
T: ::std::convert::TryInto<super::EligibilityPresentationNonce>,
T::Error: ::std::fmt::Display,
{
self.nonce = value
.try_into()
.map_err(|e| format!("error converting supplied value for nonce: {e}"));
self
}
pub fn proof<T>(mut self, value: T) -> Self
where
T: ::std::convert::TryInto<super::EligibilityPresentationProof>,
T::Error: ::std::fmt::Display,
{
self.proof = value
.try_into()
.map_err(|e| format!("error converting supplied value for proof: {e}"));
self
}
pub fn type_<T>(mut self, value: T) -> Self
where
T: ::std::convert::TryInto<Vec<super::EligibilityPresentationTypeItem>>,
T::Error: ::std::fmt::Display,
{
self.type_ = value
.try_into()
.map_err(|e| format!("error converting supplied value for type_: {e}"));
self
}
pub fn verifiable_credential<T>(mut self, value: T) -> Self
where
T: ::std::convert::TryInto<
::std::vec::Vec<::serde_json::Map<::std::string::String, ::serde_json::Value>>,
>,
T::Error: ::std::fmt::Display,
{
self.verifiable_credential = value.try_into().map_err(|e| {
format!("error converting supplied value for verifiable_credential: {e}")
});
self
}
}
impl ::std::convert::TryFrom<EligibilityPresentation> for super::EligibilityPresentation {
type Error = super::error::ConversionError;
fn try_from(
value: EligibilityPresentation,
) -> ::std::result::Result<Self, super::error::ConversionError> {
Ok(Self {
context: value.context?,
domain: value.domain?,
holder: value.holder?,
nonce: value.nonce?,
proof: value.proof?,
type_: value.type_?,
verifiable_credential: value.verifiable_credential?,
})
}
}
impl ::std::convert::From<super::EligibilityPresentation> for EligibilityPresentation {
fn from(value: super::EligibilityPresentation) -> Self {
Self {
context: Ok(value.context),
domain: Ok(value.domain),
holder: Ok(value.holder),
nonce: Ok(value.nonce),
proof: Ok(value.proof),
type_: Ok(value.type_),
verifiable_credential: Ok(value.verifiable_credential),
}
}
}
#[derive(Clone, Debug)]
pub struct EligibilityPresentationProof {
created: ::std::result::Result<
::std::option::Option<::chrono::DateTime<::chrono::offset::Utc>>,
::std::string::String,
>,
cryptosuite: ::std::result::Result<
super::EligibilityPresentationProofCryptosuite,
::std::string::String,
>,
proof_purpose: ::std::result::Result<::std::string::String, ::std::string::String>,
proof_value: ::std::result::Result<
super::EligibilityPresentationProofProofValue,
::std::string::String,
>,
type_: ::std::result::Result<::std::string::String, ::std::string::String>,
verification_method: ::std::result::Result<
super::EligibilityPresentationProofVerificationMethod,
::std::string::String,
>,
}
impl ::std::default::Default for EligibilityPresentationProof {
fn default() -> Self {
Self {
created: Ok(Default::default()),
cryptosuite: Err("no value supplied for cryptosuite".to_string()),
proof_purpose: Err("no value supplied for proof_purpose".to_string()),
proof_value: Err("no value supplied for proof_value".to_string()),
type_: Err("no value supplied for type_".to_string()),
verification_method: Err("no value supplied for verification_method".to_string()),
}
}
}
impl EligibilityPresentationProof {
pub fn created<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.created = value
.try_into()
.map_err(|e| format!("error converting supplied value for created: {e}"));
self
}
pub fn cryptosuite<T>(mut self, value: T) -> Self
where
T: ::std::convert::TryInto<super::EligibilityPresentationProofCryptosuite>,
T::Error: ::std::fmt::Display,
{
self.cryptosuite = value
.try_into()
.map_err(|e| format!("error converting supplied value for cryptosuite: {e}"));
self
}
pub fn proof_purpose<T>(mut self, value: T) -> Self
where
T: ::std::convert::TryInto<::std::string::String>,
T::Error: ::std::fmt::Display,
{
self.proof_purpose = value
.try_into()
.map_err(|e| format!("error converting supplied value for proof_purpose: {e}"));
self
}
pub fn proof_value<T>(mut self, value: T) -> Self
where
T: ::std::convert::TryInto<super::EligibilityPresentationProofProofValue>,
T::Error: ::std::fmt::Display,
{
self.proof_value = value
.try_into()
.map_err(|e| format!("error converting supplied value for proof_value: {e}"));
self
}
pub fn type_<T>(mut self, value: T) -> Self
where
T: ::std::convert::TryInto<::std::string::String>,
T::Error: ::std::fmt::Display,
{
self.type_ = value
.try_into()
.map_err(|e| format!("error converting supplied value for type_: {e}"));
self
}
pub fn verification_method<T>(mut self, value: T) -> Self
where
T: ::std::convert::TryInto<super::EligibilityPresentationProofVerificationMethod>,
T::Error: ::std::fmt::Display,
{
self.verification_method = value.try_into().map_err(|e| {
format!("error converting supplied value for verification_method: {e}")
});
self
}
}
impl ::std::convert::TryFrom<EligibilityPresentationProof> for super::EligibilityPresentationProof {
type Error = super::error::ConversionError;
fn try_from(
value: EligibilityPresentationProof,
) -> ::std::result::Result<Self, super::error::ConversionError> {
Ok(Self {
created: value.created?,
cryptosuite: value.cryptosuite?,
proof_purpose: value.proof_purpose?,
proof_value: value.proof_value?,
type_: value.type_?,
verification_method: value.verification_method?,
})
}
}
impl ::std::convert::From<super::EligibilityPresentationProof> for EligibilityPresentationProof {
fn from(value: super::EligibilityPresentationProof) -> Self {
Self {
created: Ok(value.created),
cryptosuite: Ok(value.cryptosuite),
proof_purpose: Ok(value.proof_purpose),
proof_value: Ok(value.proof_value),
type_: Ok(value.type_),
verification_method: Ok(value.verification_method),
}
}
}
#[derive(Clone, Debug)]
pub struct Payload {
availability: ::std::result::Result<
::std::option::Option<super::PayloadAvailability>,
::std::string::String,
>,
community: ::std::result::Result<super::PayloadCommunity, ::std::string::String>,
ext: ::std::result::Result<::std::option::Option<super::Ext>, ::std::string::String>,
introduction: ::std::result::Result<
::serde_json::Map<::std::string::String, ::serde_json::Value>,
::std::string::String,
>,
join_did: ::std::result::Result<super::PayloadJoinDid, ::std::string::String>,
languages: ::std::result::Result<
::std::option::Option<Vec<super::PayloadLanguagesItem>>,
::std::string::String,
>,
message: ::std::result::Result<
::std::option::Option<super::PayloadMessage>,
::std::string::String,
>,
preferred_method: ::std::result::Result<
::std::option::Option<super::VettingMethod>,
::std::string::String,
>,
requirements_digest: ::std::result::Result<
::std::option::Option<super::DigestMultibase>,
::std::string::String,
>,
ticket: ::std::result::Result<::std::option::Option<super::Ticket>, ::std::string::String>,
}
impl ::std::default::Default for Payload {
fn default() -> Self {
Self {
availability: Ok(Default::default()),
community: Err("no value supplied for community".to_string()),
ext: Ok(Default::default()),
introduction: Ok(Default::default()),
join_did: Err("no value supplied for join_did".to_string()),
languages: Ok(Default::default()),
message: Ok(Default::default()),
preferred_method: Ok(Default::default()),
requirements_digest: Ok(Default::default()),
ticket: Ok(Default::default()),
}
}
}
impl Payload {
pub fn availability<T>(mut self, value: T) -> Self
where
T: ::std::convert::TryInto<::std::option::Option<super::PayloadAvailability>>,
T::Error: ::std::fmt::Display,
{
self.availability = value
.try_into()
.map_err(|e| format!("error converting supplied value for availability: {e}"));
self
}
pub fn community<T>(mut self, value: T) -> Self
where
T: ::std::convert::TryInto<super::PayloadCommunity>,
T::Error: ::std::fmt::Display,
{
self.community = value
.try_into()
.map_err(|e| format!("error converting supplied value for community: {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 introduction<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.introduction = value
.try_into()
.map_err(|e| format!("error converting supplied value for introduction: {e}"));
self
}
pub fn join_did<T>(mut self, value: T) -> Self
where
T: ::std::convert::TryInto<super::PayloadJoinDid>,
T::Error: ::std::fmt::Display,
{
self.join_did = value
.try_into()
.map_err(|e| format!("error converting supplied value for join_did: {e}"));
self
}
pub fn languages<T>(mut self, value: T) -> Self
where
T: ::std::convert::TryInto<::std::option::Option<Vec<super::PayloadLanguagesItem>>>,
T::Error: ::std::fmt::Display,
{
self.languages = value
.try_into()
.map_err(|e| format!("error converting supplied value for languages: {e}"));
self
}
pub fn message<T>(mut self, value: T) -> Self
where
T: ::std::convert::TryInto<::std::option::Option<super::PayloadMessage>>,
T::Error: ::std::fmt::Display,
{
self.message = value
.try_into()
.map_err(|e| format!("error converting supplied value for message: {e}"));
self
}
pub fn preferred_method<T>(mut self, value: T) -> Self
where
T: ::std::convert::TryInto<::std::option::Option<super::VettingMethod>>,
T::Error: ::std::fmt::Display,
{
self.preferred_method = value
.try_into()
.map_err(|e| format!("error converting supplied value for preferred_method: {e}"));
self
}
pub fn requirements_digest<T>(mut self, value: T) -> Self
where
T: ::std::convert::TryInto<::std::option::Option<super::DigestMultibase>>,
T::Error: ::std::fmt::Display,
{
self.requirements_digest = value.try_into().map_err(|e| {
format!("error converting supplied value for requirements_digest: {e}")
});
self
}
pub fn ticket<T>(mut self, value: T) -> Self
where
T: ::std::convert::TryInto<::std::option::Option<super::Ticket>>,
T::Error: ::std::fmt::Display,
{
self.ticket = value
.try_into()
.map_err(|e| format!("error converting supplied value for ticket: {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 {
availability: value.availability?,
community: value.community?,
ext: value.ext?,
introduction: value.introduction?,
join_did: value.join_did?,
languages: value.languages?,
message: value.message?,
preferred_method: value.preferred_method?,
requirements_digest: value.requirements_digest?,
ticket: value.ticket?,
})
}
}
impl ::std::convert::From<super::Payload> for Payload {
fn from(value: super::Payload) -> Self {
Self {
availability: Ok(value.availability),
community: Ok(value.community),
ext: Ok(value.ext),
introduction: Ok(value.introduction),
join_did: Ok(value.join_did),
languages: Ok(value.languages),
message: Ok(value.message),
preferred_method: Ok(value.preferred_method),
requirements_digest: Ok(value.requirements_digest),
ticket: Ok(value.ticket),
}
}
}
#[derive(Clone, Debug)]
pub struct QrTicket {
secret: ::std::result::Result<super::QrTicketSecret, ::std::string::String>,
ticket_id: ::std::result::Result<super::QrTicketTicketId, ::std::string::String>,
}
impl ::std::default::Default for QrTicket {
fn default() -> Self {
Self {
secret: Err("no value supplied for secret".to_string()),
ticket_id: Err("no value supplied for ticket_id".to_string()),
}
}
}
impl QrTicket {
pub fn secret<T>(mut self, value: T) -> Self
where
T: ::std::convert::TryInto<super::QrTicketSecret>,
T::Error: ::std::fmt::Display,
{
self.secret = value
.try_into()
.map_err(|e| format!("error converting supplied value for secret: {e}"));
self
}
pub fn ticket_id<T>(mut self, value: T) -> Self
where
T: ::std::convert::TryInto<super::QrTicketTicketId>,
T::Error: ::std::fmt::Display,
{
self.ticket_id = value
.try_into()
.map_err(|e| format!("error converting supplied value for ticket_id: {e}"));
self
}
}
impl ::std::convert::TryFrom<QrTicket> for super::QrTicket {
type Error = super::error::ConversionError;
fn try_from(value: QrTicket) -> ::std::result::Result<Self, super::error::ConversionError> {
Ok(Self {
secret: value.secret?,
ticket_id: value.ticket_id?,
})
}
}
impl ::std::convert::From<super::QrTicket> for QrTicket {
fn from(value: super::QrTicket) -> Self {
Self {
secret: Ok(value.secret),
ticket_id: Ok(value.ticket_id),
}
}
}
#[derive(Clone, Debug)]
pub struct Response {
accepts_documentation: ::std::result::Result<
::std::option::Option<Vec<super::VettingDocumentation>>,
::std::string::String,
>,
eligibility_vp: ::std::result::Result<
::std::option::Option<super::EligibilityPresentation>,
::std::string::String,
>,
ext: ::std::result::Result<::std::option::Option<super::Ext>, ::std::string::String>,
request_id: ::std::result::Result<super::ResponseRequestId, ::std::string::String>,
session_hint: ::std::result::Result<
::std::option::Option<super::ResponseSessionHint>,
::std::string::String,
>,
}
impl ::std::default::Default for Response {
fn default() -> Self {
Self {
accepts_documentation: Ok(Default::default()),
eligibility_vp: Ok(Default::default()),
ext: Ok(Default::default()),
request_id: Err("no value supplied for request_id".to_string()),
session_hint: Ok(Default::default()),
}
}
}
impl Response {
pub fn accepts_documentation<T>(mut self, value: T) -> Self
where
T: ::std::convert::TryInto<::std::option::Option<Vec<super::VettingDocumentation>>>,
T::Error: ::std::fmt::Display,
{
self.accepts_documentation = value.try_into().map_err(|e| {
format!("error converting supplied value for accepts_documentation: {e}")
});
self
}
pub fn eligibility_vp<T>(mut self, value: T) -> Self
where
T: ::std::convert::TryInto<::std::option::Option<super::EligibilityPresentation>>,
T::Error: ::std::fmt::Display,
{
self.eligibility_vp = value
.try_into()
.map_err(|e| format!("error converting supplied value for eligibility_vp: {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 request_id<T>(mut self, value: T) -> Self
where
T: ::std::convert::TryInto<super::ResponseRequestId>,
T::Error: ::std::fmt::Display,
{
self.request_id = value
.try_into()
.map_err(|e| format!("error converting supplied value for request_id: {e}"));
self
}
pub fn session_hint<T>(mut self, value: T) -> Self
where
T: ::std::convert::TryInto<::std::option::Option<super::ResponseSessionHint>>,
T::Error: ::std::fmt::Display,
{
self.session_hint = value
.try_into()
.map_err(|e| format!("error converting supplied value for session_hint: {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 {
accepts_documentation: value.accepts_documentation?,
eligibility_vp: value.eligibility_vp?,
ext: value.ext?,
request_id: value.request_id?,
session_hint: value.session_hint?,
})
}
}
impl ::std::convert::From<super::Response> for Response {
fn from(value: super::Response) -> Self {
Self {
accepts_documentation: Ok(value.accepts_documentation),
eligibility_vp: Ok(value.eligibility_vp),
ext: Ok(value.ext),
request_id: Ok(value.request_id),
session_hint: Ok(value.session_hint),
}
}
}
#[derive(Clone, Debug)]
pub struct ShortCodeTicket {
code: ::std::result::Result<super::ShortCodeTicketCode, ::std::string::String>,
}
impl ::std::default::Default for ShortCodeTicket {
fn default() -> Self {
Self {
code: Err("no value supplied for code".to_string()),
}
}
}
impl ShortCodeTicket {
pub fn code<T>(mut self, value: T) -> Self
where
T: ::std::convert::TryInto<super::ShortCodeTicketCode>,
T::Error: ::std::fmt::Display,
{
self.code = value
.try_into()
.map_err(|e| format!("error converting supplied value for code: {e}"));
self
}
}
impl ::std::convert::TryFrom<ShortCodeTicket> for super::ShortCodeTicket {
type Error = super::error::ConversionError;
fn try_from(
value: ShortCodeTicket,
) -> ::std::result::Result<Self, super::error::ConversionError> {
Ok(Self { code: value.code? })
}
}
impl ::std::convert::From<super::ShortCodeTicket> for ShortCodeTicket {
fn from(value: super::ShortCodeTicket) -> Self {
Self {
code: Ok(value.code),
}
}
}
}
impl crate::Payload for Payload {
const TYPE_URI: &'static str = "https://trusttasks.org/spec/vetting/request/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(
"{\n \"$defs\": {\n \"DigestMultibase\": {\n \"description\": \"A cryptographic digest as a multibase-encoded multihash — the encoding the W3C Verifiable Credentials Data Model 2.0 defines for `digestMultibase`, and the one `did:webvh` uses for its SCID and entry hashes.\\n\\nMultihash carries the hash algorithm in-band, so the value is self-describing and the wire format survives an algorithm change without a schema revision; multibase does the same for the base encoding, so a verifier never infers base58 from base64url by context. A bare hex string or a `sha-256:`-style prefix hard-codes one algorithm into the wire contract and is non-conforming here.\\n\\nThis definition constrains the *encoding only*. What the digest is computed over is stated by each referencing field, because it differs legitimately: a digest over a JSON document is taken over its RFC 8785 (JCS) canonicalization, while a digest over an opaque artifact is taken over its bytes. A field whose input is a JSON document and which does not name a canonicalization is not reproducible.\\n\\nRestricted to the two multibase headers W3C Controlled Identifiers 1.0 §2.4 normatively requires — `z` (base58btc) and `u` (base64url-no-pad). CID permits others but states that \\\"interoperability is not guaranteed between implementations using such values\\\", and a registry whose purpose is interoperability should not mint digests a conforming verifier may be unable to read. The alphabets are enforced rather than assumed: base58btc excludes 0, O, I and l, and an earlier permissive pattern let three published examples carry digests that were not valid base58 at all. base58btc is RECOMMENDED, for consistency with `did:key` and `did:webvh`.\",\n \"examples\": [\n \"zQmbWqxBEKC3P8tqsKc98xmWNzrzDtRLMiMPL8wBuTGsMnR\"\n ],\n \"minLength\": 16,\n \"pattern\": \"^(z[1-9A-HJ-NP-Za-km-z]+|u[A-Za-z0-9_-]+)$\",\n \"title\": \"DigestMultibase\",\n \"type\": \"string\"\n },\n \"EligibilityPresentation\": {\n \"additionalProperties\": true,\n \"description\": \"OPTIONAL. A W3C Verifiable Presentation by which the vetter shows the applicant that it currently holds the community's vetter role. Bound to this request by `nonce` (the vetting/request document's `id`, which the applicant chose) and to this applicant by `domain` (its `joinDid`), so it cannot be replayed to another request or another applicant. The applicant's check is advisory; the community evaluates eligibility again, authoritatively, when it decides. Members other than those defined here are permitted, as the VC data model allows.\",\n \"properties\": {\n \"@context\": {\n \"description\": \"JSON-LD contexts. The first item MUST be `https://www.w3.org/ns/credentials/v2` (stated here rather than as `prefixItems`, which the Rust generator cannot express).\",\n \"items\": {\n \"maxLength\": 2048,\n \"minLength\": 1,\n \"type\": \"string\"\n },\n \"minItems\": 1,\n \"type\": \"array\"\n },\n \"domain\": {\n \"description\": \"The applicant's `joinDid` from that request.\",\n \"pattern\": \"^did:\",\n \"type\": \"string\"\n },\n \"holder\": {\n \"description\": \"The vetter's DID — the response's `issuer`.\",\n \"pattern\": \"^did:\",\n \"type\": \"string\"\n },\n \"nonce\": {\n \"description\": \"The `id` of the vetting/request document this responds to.\",\n \"maxLength\": 512,\n \"minLength\": 1,\n \"type\": \"string\"\n },\n \"proof\": {\n \"$ref\": \"#/$defs/EligibilityPresentationProof\"\n },\n \"type\": {\n \"description\": \"MUST include `VerifiablePresentation` (stated here rather than as `contains`, which the Rust generator cannot express).\",\n \"items\": {\n \"maxLength\": 128,\n \"minLength\": 1,\n \"type\": \"string\"\n },\n \"minItems\": 1,\n \"type\": \"array\",\n \"uniqueItems\": true\n },\n \"verifiableCredential\": {\n \"description\": \"Credentials presented (opaque here). MUST include the community-issued `CommunityRole` endorsement credential naming `holder`, whose `endorsement.role` is the manifest's `eligibleVetters.role` — see vtc/vetting/vetters/grant/0.1. MAY include others, such as the membership credential.\",\n \"items\": {\n \"type\": \"object\"\n },\n \"minItems\": 1,\n \"type\": \"array\"\n }\n },\n \"required\": [\n \"@context\",\n \"type\",\n \"holder\",\n \"verifiableCredential\",\n \"nonce\",\n \"domain\",\n \"proof\"\n ],\n \"title\": \"EligibilityPresentation\",\n \"type\": \"object\"\n },\n \"EligibilityPresentationProof\": {\n \"additionalProperties\": true,\n \"description\": \"A W3C Data Integrity proof by `holder` over the presentation, `nonce` and `domain` included.\",\n \"properties\": {\n \"created\": {\n \"format\": \"date-time\",\n \"type\": \"string\"\n },\n \"cryptosuite\": {\n \"description\": \"e.g. `eddsa-jcs-2022`.\",\n \"maxLength\": 64,\n \"minLength\": 1,\n \"pattern\": \"^[a-z0-9-]+$\",\n \"type\": \"string\"\n },\n \"proofPurpose\": {\n \"const\": \"authentication\",\n \"type\": \"string\"\n },\n \"proofValue\": {\n \"pattern\": \"^z[1-9A-HJ-NP-Za-km-z]+$\",\n \"type\": \"string\"\n },\n \"type\": {\n \"const\": \"DataIntegrityProof\",\n \"type\": \"string\"\n },\n \"verificationMethod\": {\n \"description\": \"A verification method of `holder`, authorized for `authentication`.\",\n \"pattern\": \"^did:\",\n \"type\": \"string\"\n }\n },\n \"required\": [\n \"type\",\n \"cryptosuite\",\n \"verificationMethod\",\n \"proofPurpose\",\n \"proofValue\"\n ],\n \"title\": \"EligibilityPresentationProof\",\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 \"QrTicket\": {\n \"additionalProperties\": false,\n \"properties\": {\n \"secret\": {\n \"description\": \"32 random bytes, base64url without padding.\",\n \"pattern\": \"^[A-Za-z0-9_-]{43}$\",\n \"type\": \"string\"\n },\n \"ticketId\": {\n \"maxLength\": 128,\n \"minLength\": 1,\n \"pattern\": \"^[A-Za-z0-9._:-]+$\",\n \"type\": \"string\"\n }\n },\n \"required\": [\n \"ticketId\",\n \"secret\"\n ],\n \"title\": \"QrTicket\",\n \"type\": \"object\"\n },\n \"Response\": {\n \"$anchor\": \"response\",\n \"additionalProperties\": false,\n \"description\": \"The vetter accepts the request. A refusal is a trust-task-error, never a response document.\",\n \"properties\": {\n \"acceptsDocumentation\": {\n \"description\": \"RECOMMENDED. What this vetter will rely on, so the applicant brings it — the vetter's own choice. `none` means the vetter attests from prior acquaintance.\",\n \"items\": {\n \"$ref\": \"#/$defs/VettingDocumentation\"\n },\n \"minItems\": 1,\n \"type\": \"array\",\n \"uniqueItems\": true\n },\n \"eligibilityVp\": {\n \"$ref\": \"#/$defs/EligibilityPresentation\"\n },\n \"ext\": {\n \"$ref\": \"#/$defs/Ext\"\n },\n \"requestId\": {\n \"description\": \"The vetter's handle for this accepted request, carried by the session and any decline.\",\n \"maxLength\": 128,\n \"minLength\": 1,\n \"type\": \"string\"\n },\n \"sessionHint\": {\n \"description\": \"OPTIONAL vetter-authored free text on how and when the session will happen. Attributed to the vetter.\",\n \"maxLength\": 500,\n \"minLength\": 1,\n \"type\": \"string\"\n }\n },\n \"required\": [\n \"requestId\"\n ],\n \"title\": \"Vetting Request — response payload\",\n \"type\": \"object\"\n },\n \"ShortCodeTicket\": {\n \"additionalProperties\": false,\n \"properties\": {\n \"code\": {\n \"description\": \"Eight Crockford base32 characters, grouped four and four (40 bits). A secret the vetter handed over; not derived from anything.\",\n \"pattern\": \"^[0-9A-HJKMNP-TV-Z]{4}-[0-9A-HJKMNP-TV-Z]{4}$\",\n \"type\": \"string\"\n }\n },\n \"required\": [\n \"code\"\n ],\n \"title\": \"ShortCodeTicket\",\n \"type\": \"object\"\n },\n \"Ticket\": {\n \"description\": \"A ticket the vetter issued: the short code a person reads or types, or the full-entropy QR form.\",\n \"oneOf\": [\n {\n \"$ref\": \"#/$defs/ShortCodeTicket\"\n },\n {\n \"$ref\": \"#/$defs/QrTicket\"\n }\n ],\n \"title\": \"Ticket\"\n },\n \"VettingDocumentation\": {\n \"description\": \"A class of documentation, named in lowerCamelCase. Open rather than enumerated, because what documentation a vetter accepts is each vetter's own choice. Well-known values: `passport`, `nationalId`, `driverLicence`, and `none` — the vetter will attest without a document, which is the `priorAcquaintance` case. Only the class ever travels — never a document number, an image, an issuing authority or an expiry date. `none` states a policy (what a vetter accepts); a record of what was relied on expresses 'no document' as an empty list instead.\",\n \"maxLength\": 64,\n \"minLength\": 1,\n \"pattern\": \"^[a-z][a-zA-Z0-9]*$\",\n \"title\": \"VettingDocumentation\",\n \"type\": \"string\"\n },\n \"VettingMethod\": {\n \"description\": \"How the vetter established that the person they checked is the person controlling the applicant's DID. `inPerson` — both people were physically together. `video` — a live, two-way video call. `priorAcquaintance` — the vetter has known or worked with this person over a period, and attests from that knowledge rather than from a document. A method is a description of what happened, not an assurance level: which methods count, and how many of each, is community policy.\",\n \"enum\": [\n \"inPerson\",\n \"video\",\n \"priorAcquaintance\"\n ],\n \"title\": \"VettingMethod\",\n \"type\": \"string\"\n }\n },\n \"$id\": \"https://trusttasks.org/spec/vetting/request/0.1\",\n \"$schema\": \"https://json-schema.org/draft/2020-12/schema\",\n \"additionalProperties\": false,\n \"dependentSchemas\": {\n \"ticket\": {\n \"not\": {\n \"required\": [\n \"introduction\"\n ]\n }\n }\n },\n \"description\": \"An applicant asks one vetter to vet them for one community. The applicant is the document's issuer, and `joinDid` repeats that DID: it is the DID the applicant is applying with, and every card and statement that follows names it. Carries a ticket the vetter issued or an introduction, never both. The vetter's response accepts the request and proves the vetter is currently eligible to vet for that community.\",\n \"properties\": {\n \"availability\": {\n \"description\": \"OPTIONAL applicant-authored free text on when they can meet. Scheduling is out of band; this is a hint, attributed to the applicant.\",\n \"maxLength\": 256,\n \"minLength\": 1,\n \"type\": \"string\"\n },\n \"community\": {\n \"description\": \"The community the applicant is applying to and asks to be vetted for.\",\n \"pattern\": \"^did:\",\n \"type\": \"string\"\n },\n \"ext\": {\n \"$ref\": \"#/$defs/Ext\"\n },\n \"introduction\": {\n \"description\": \"A verifiable invitation credential for `community` whose subject is the applicant's DID, issued by the community or a member (opaque here). An alternative to a ticket for vetters who accept introductions.\",\n \"type\": \"object\"\n },\n \"joinDid\": {\n \"description\": \"The DID the applicant will join the community with. MUST equal the document's `issuer`. Every card and statement this request leads to names it, and it is the holder of the presentation the applicant eventually submits.\",\n \"pattern\": \"^did:\",\n \"type\": \"string\"\n },\n \"languages\": {\n \"description\": \"BCP 47 language tags the applicant can hold a session in, most preferred first.\",\n \"items\": {\n \"maxLength\": 35,\n \"pattern\": \"^[A-Za-z]{2,3}(-[A-Za-z0-9]{1,8})*$\",\n \"type\": \"string\"\n },\n \"maxItems\": 16,\n \"type\": \"array\",\n \"uniqueItems\": true\n },\n \"message\": {\n \"description\": \"OPTIONAL applicant-authored text for the vetter — typically how they know each other. Untrusted: read by the vetter, attributed to the applicant on every surface that renders it, never shown to the community.\",\n \"maxLength\": 1000,\n \"minLength\": 1,\n \"type\": \"string\"\n },\n \"preferredMethod\": {\n \"$ref\": \"#/$defs/VettingMethod\",\n \"description\": \"The method the applicant would prefer. A preference: the vetter chooses the session's method.\"\n },\n \"requirementsDigest\": {\n \"$ref\": \"#/$defs/DigestMultibase\",\n \"description\": \"The `requirementsDigest` of the community's manifest criterion the applicant is gathering for, recorded when the application started. RECOMMENDED; a community that publishes no digest leaves the applicant nothing to cite.\"\n },\n \"ticket\": {\n \"$ref\": \"#/$defs/Ticket\"\n }\n },\n \"required\": [\n \"community\",\n \"joinDid\"\n ],\n \"title\": \"Vetting Request — payload\",\n \"type\": \"object\"\n}\n",
);
}
impl crate::Payload for Response {
const TYPE_URI: &'static str = "https://trusttasks.org/spec/vetting/request/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(
"{\n \"$defs\": {\n \"DigestMultibase\": {\n \"description\": \"A cryptographic digest as a multibase-encoded multihash — the encoding the W3C Verifiable Credentials Data Model 2.0 defines for `digestMultibase`, and the one `did:webvh` uses for its SCID and entry hashes.\\n\\nMultihash carries the hash algorithm in-band, so the value is self-describing and the wire format survives an algorithm change without a schema revision; multibase does the same for the base encoding, so a verifier never infers base58 from base64url by context. A bare hex string or a `sha-256:`-style prefix hard-codes one algorithm into the wire contract and is non-conforming here.\\n\\nThis definition constrains the *encoding only*. What the digest is computed over is stated by each referencing field, because it differs legitimately: a digest over a JSON document is taken over its RFC 8785 (JCS) canonicalization, while a digest over an opaque artifact is taken over its bytes. A field whose input is a JSON document and which does not name a canonicalization is not reproducible.\\n\\nRestricted to the two multibase headers W3C Controlled Identifiers 1.0 §2.4 normatively requires — `z` (base58btc) and `u` (base64url-no-pad). CID permits others but states that \\\"interoperability is not guaranteed between implementations using such values\\\", and a registry whose purpose is interoperability should not mint digests a conforming verifier may be unable to read. The alphabets are enforced rather than assumed: base58btc excludes 0, O, I and l, and an earlier permissive pattern let three published examples carry digests that were not valid base58 at all. base58btc is RECOMMENDED, for consistency with `did:key` and `did:webvh`.\",\n \"examples\": [\n \"zQmbWqxBEKC3P8tqsKc98xmWNzrzDtRLMiMPL8wBuTGsMnR\"\n ],\n \"minLength\": 16,\n \"pattern\": \"^(z[1-9A-HJ-NP-Za-km-z]+|u[A-Za-z0-9_-]+)$\",\n \"title\": \"DigestMultibase\",\n \"type\": \"string\"\n },\n \"EligibilityPresentation\": {\n \"additionalProperties\": true,\n \"description\": \"OPTIONAL. A W3C Verifiable Presentation by which the vetter shows the applicant that it currently holds the community's vetter role. Bound to this request by `nonce` (the vetting/request document's `id`, which the applicant chose) and to this applicant by `domain` (its `joinDid`), so it cannot be replayed to another request or another applicant. The applicant's check is advisory; the community evaluates eligibility again, authoritatively, when it decides. Members other than those defined here are permitted, as the VC data model allows.\",\n \"properties\": {\n \"@context\": {\n \"description\": \"JSON-LD contexts. The first item MUST be `https://www.w3.org/ns/credentials/v2` (stated here rather than as `prefixItems`, which the Rust generator cannot express).\",\n \"items\": {\n \"maxLength\": 2048,\n \"minLength\": 1,\n \"type\": \"string\"\n },\n \"minItems\": 1,\n \"type\": \"array\"\n },\n \"domain\": {\n \"description\": \"The applicant's `joinDid` from that request.\",\n \"pattern\": \"^did:\",\n \"type\": \"string\"\n },\n \"holder\": {\n \"description\": \"The vetter's DID — the response's `issuer`.\",\n \"pattern\": \"^did:\",\n \"type\": \"string\"\n },\n \"nonce\": {\n \"description\": \"The `id` of the vetting/request document this responds to.\",\n \"maxLength\": 512,\n \"minLength\": 1,\n \"type\": \"string\"\n },\n \"proof\": {\n \"$ref\": \"#/$defs/EligibilityPresentationProof\"\n },\n \"type\": {\n \"description\": \"MUST include `VerifiablePresentation` (stated here rather than as `contains`, which the Rust generator cannot express).\",\n \"items\": {\n \"maxLength\": 128,\n \"minLength\": 1,\n \"type\": \"string\"\n },\n \"minItems\": 1,\n \"type\": \"array\",\n \"uniqueItems\": true\n },\n \"verifiableCredential\": {\n \"description\": \"Credentials presented (opaque here). MUST include the community-issued `CommunityRole` endorsement credential naming `holder`, whose `endorsement.role` is the manifest's `eligibleVetters.role` — see vtc/vetting/vetters/grant/0.1. MAY include others, such as the membership credential.\",\n \"items\": {\n \"type\": \"object\"\n },\n \"minItems\": 1,\n \"type\": \"array\"\n }\n },\n \"required\": [\n \"@context\",\n \"type\",\n \"holder\",\n \"verifiableCredential\",\n \"nonce\",\n \"domain\",\n \"proof\"\n ],\n \"title\": \"EligibilityPresentation\",\n \"type\": \"object\"\n },\n \"EligibilityPresentationProof\": {\n \"additionalProperties\": true,\n \"description\": \"A W3C Data Integrity proof by `holder` over the presentation, `nonce` and `domain` included.\",\n \"properties\": {\n \"created\": {\n \"format\": \"date-time\",\n \"type\": \"string\"\n },\n \"cryptosuite\": {\n \"description\": \"e.g. `eddsa-jcs-2022`.\",\n \"maxLength\": 64,\n \"minLength\": 1,\n \"pattern\": \"^[a-z0-9-]+$\",\n \"type\": \"string\"\n },\n \"proofPurpose\": {\n \"const\": \"authentication\",\n \"type\": \"string\"\n },\n \"proofValue\": {\n \"pattern\": \"^z[1-9A-HJ-NP-Za-km-z]+$\",\n \"type\": \"string\"\n },\n \"type\": {\n \"const\": \"DataIntegrityProof\",\n \"type\": \"string\"\n },\n \"verificationMethod\": {\n \"description\": \"A verification method of `holder`, authorized for `authentication`.\",\n \"pattern\": \"^did:\",\n \"type\": \"string\"\n }\n },\n \"required\": [\n \"type\",\n \"cryptosuite\",\n \"verificationMethod\",\n \"proofPurpose\",\n \"proofValue\"\n ],\n \"title\": \"EligibilityPresentationProof\",\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 \"QrTicket\": {\n \"additionalProperties\": false,\n \"properties\": {\n \"secret\": {\n \"description\": \"32 random bytes, base64url without padding.\",\n \"pattern\": \"^[A-Za-z0-9_-]{43}$\",\n \"type\": \"string\"\n },\n \"ticketId\": {\n \"maxLength\": 128,\n \"minLength\": 1,\n \"pattern\": \"^[A-Za-z0-9._:-]+$\",\n \"type\": \"string\"\n }\n },\n \"required\": [\n \"ticketId\",\n \"secret\"\n ],\n \"title\": \"QrTicket\",\n \"type\": \"object\"\n },\n \"Response\": {\n \"$anchor\": \"response\",\n \"additionalProperties\": false,\n \"description\": \"The vetter accepts the request. A refusal is a trust-task-error, never a response document.\",\n \"properties\": {\n \"acceptsDocumentation\": {\n \"description\": \"RECOMMENDED. What this vetter will rely on, so the applicant brings it — the vetter's own choice. `none` means the vetter attests from prior acquaintance.\",\n \"items\": {\n \"$ref\": \"#/$defs/VettingDocumentation\"\n },\n \"minItems\": 1,\n \"type\": \"array\",\n \"uniqueItems\": true\n },\n \"eligibilityVp\": {\n \"$ref\": \"#/$defs/EligibilityPresentation\"\n },\n \"ext\": {\n \"$ref\": \"#/$defs/Ext\"\n },\n \"requestId\": {\n \"description\": \"The vetter's handle for this accepted request, carried by the session and any decline.\",\n \"maxLength\": 128,\n \"minLength\": 1,\n \"type\": \"string\"\n },\n \"sessionHint\": {\n \"description\": \"OPTIONAL vetter-authored free text on how and when the session will happen. Attributed to the vetter.\",\n \"maxLength\": 500,\n \"minLength\": 1,\n \"type\": \"string\"\n }\n },\n \"required\": [\n \"requestId\"\n ],\n \"title\": \"Vetting Request — response payload\",\n \"type\": \"object\"\n },\n \"ShortCodeTicket\": {\n \"additionalProperties\": false,\n \"properties\": {\n \"code\": {\n \"description\": \"Eight Crockford base32 characters, grouped four and four (40 bits). A secret the vetter handed over; not derived from anything.\",\n \"pattern\": \"^[0-9A-HJKMNP-TV-Z]{4}-[0-9A-HJKMNP-TV-Z]{4}$\",\n \"type\": \"string\"\n }\n },\n \"required\": [\n \"code\"\n ],\n \"title\": \"ShortCodeTicket\",\n \"type\": \"object\"\n },\n \"Ticket\": {\n \"description\": \"A ticket the vetter issued: the short code a person reads or types, or the full-entropy QR form.\",\n \"oneOf\": [\n {\n \"$ref\": \"#/$defs/ShortCodeTicket\"\n },\n {\n \"$ref\": \"#/$defs/QrTicket\"\n }\n ],\n \"title\": \"Ticket\"\n },\n \"VettingDocumentation\": {\n \"description\": \"A class of documentation, named in lowerCamelCase. Open rather than enumerated, because what documentation a vetter accepts is each vetter's own choice. Well-known values: `passport`, `nationalId`, `driverLicence`, and `none` — the vetter will attest without a document, which is the `priorAcquaintance` case. Only the class ever travels — never a document number, an image, an issuing authority or an expiry date. `none` states a policy (what a vetter accepts); a record of what was relied on expresses 'no document' as an empty list instead.\",\n \"maxLength\": 64,\n \"minLength\": 1,\n \"pattern\": \"^[a-z][a-zA-Z0-9]*$\",\n \"title\": \"VettingDocumentation\",\n \"type\": \"string\"\n },\n \"VettingMethod\": {\n \"description\": \"How the vetter established that the person they checked is the person controlling the applicant's DID. `inPerson` — both people were physically together. `video` — a live, two-way video call. `priorAcquaintance` — the vetter has known or worked with this person over a period, and attests from that knowledge rather than from a document. A method is a description of what happened, not an assurance level: which methods count, and how many of each, is community policy.\",\n \"enum\": [\n \"inPerson\",\n \"video\",\n \"priorAcquaintance\"\n ],\n \"title\": \"VettingMethod\",\n \"type\": \"string\"\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;
}
#[cfg(test)]
mod conformance {
//! Round-trip tests harvested from the spec's `spec.md`,
//! plus a `rejects_invalid_examples` test for any fixtures
//! in `payload.invalid-examples.json` (validate feature).
#[test]
fn request_example_1() {
const JSON: &str = "{\n \"id\": \"urn:uuid:6f1c2b0a-3d4e-4f5a-8b6c-7d8e9f0a1b01\",\n \"type\": \"https://trusttasks.org/spec/vetting/request/0.1\",\n \"threadId\": \"urn:uuid:6f1c2b0a-3d4e-4f5a-8b6c-7d8e9f0a1b01\",\n \"issuer\": \"did:webvh:QmAliceScid1:alice.example\",\n \"recipient\": \"did:webvh:QmCarolScid1:kernel-vtc.example:carol\",\n \"issuedAt\": \"2026-09-14T09:00:00Z\",\n \"payload\": {\n \"community\": \"did:webvh:QmVtcScid:kernel-vtc.example\",\n \"requirementsDigest\": \"zQmYZQN9M169SXXg1sZdpNCDAjoVajkrPLaFhJ6A4mecQfC\",\n \"joinDid\": \"did:webvh:QmAliceScid1:alice.example\",\n \"ticket\": { \"code\": \"K7QF-2M9X\" },\n \"preferredMethod\": \"video\",\n \"languages\": [\"en\", \"de\"],\n \"message\": \"Hi Carol — we worked on the mm reclaim series together in 2025.\",\n \"availability\": \"Weekdays 14:00–18:00 UTC\"\n },\n \"proof\": {\n \"type\": \"DataIntegrityProof\",\n \"cryptosuite\": \"eddsa-jcs-2022\",\n \"verificationMethod\": \"did:webvh:QmAliceScid1:alice.example#key-1\",\n \"created\": \"2026-09-14T09:00:00Z\",\n \"proofPurpose\": \"assertionMethod\",\n \"proofValue\": \"z2RA8945kouBqzqifZqkbB8ZSrj1sfVLZPvr6wz4RvHSaYqXySHQoep9vM1fRYit6tNfmaTDThA2ibMPhBMFh8w3N\"\n }\n}\n";
let doc: crate::TrustTask<super::Payload> =
serde_json::from_str(JSON).expect("deserialize request example");
let rendered = serde_json::to_value(&doc).expect("re-serialize");
let expected: serde_json::Value = serde_json::from_str(JSON).expect("re-parse expected");
assert_eq!(rendered, expected, "request example failed round-trip");
}
#[test]
fn response_example_1() {
const JSON: &str = "{\n \"id\": \"urn:uuid:6f1c2b0a-3d4e-4f5a-8b6c-7d8e9f0a1b02\",\n \"type\": \"https://trusttasks.org/spec/vetting/request/0.1#response\",\n \"threadId\": \"urn:uuid:6f1c2b0a-3d4e-4f5a-8b6c-7d8e9f0a1b01\",\n \"issuer\": \"did:webvh:QmCarolScid1:kernel-vtc.example:carol\",\n \"recipient\": \"did:webvh:QmAliceScid1:alice.example\",\n \"issuedAt\": \"2026-09-14T09:05:00Z\",\n \"payload\": {\n \"requestId\": \"urn:uuid:4b2e8f10-7a6c-4d3b-9e21-0f5a6b7c8d01\",\n \"eligibilityVp\": {\n \"@context\": [\n \"https://www.w3.org/ns/credentials/v2\"\n ],\n \"type\": [\n \"VerifiablePresentation\"\n ],\n \"holder\": \"did:webvh:QmCarolScid1:kernel-vtc.example:carol\",\n \"nonce\": \"urn:uuid:6f1c2b0a-3d4e-4f5a-8b6c-7d8e9f0a1b01\",\n \"domain\": \"did:webvh:QmAliceScid1:alice.example\",\n \"verifiableCredential\": [\n {\n \"@context\": [\n \"https://www.w3.org/ns/credentials/v2\",\n \"https://firstperson.network/credentials/dtg/v1\"\n ],\n \"id\": \"urn:uuid:5c7e9a1b-3d5f-4b7c-9e1a-2c4e6a8b0d01\",\n \"type\": [\n \"VerifiableCredential\",\n \"DTGCredential\",\n \"EndorsementCredential\"\n ],\n \"issuer\": \"did:webvh:QmVtcScid:kernel-vtc.example\",\n \"validFrom\": \"2026-09-13T10:00:01Z\",\n \"validUntil\": \"2027-09-13T10:00:01Z\",\n \"credentialSubject\": {\n \"id\": \"did:webvh:QmCarolScid1:kernel-vtc.example:carol\",\n \"endorsement\": {\n \"type\": \"CommunityRole\",\n \"role\": \"vetter\",\n \"communityDid\": \"did:webvh:QmVtcScid:kernel-vtc.example\"\n }\n },\n \"credentialStatus\": {\n \"id\": \"https://kernel-vtc.example/status/revocation/1#4213\",\n \"type\": \"BitstringStatusListEntry\",\n \"statusPurpose\": \"revocation\",\n \"statusListIndex\": \"4213\",\n \"statusListCredential\": \"https://kernel-vtc.example/status/revocation/1\"\n },\n \"proof\": {\n \"type\": \"DataIntegrityProof\",\n \"cryptosuite\": \"eddsa-jcs-2022\",\n \"verificationMethod\": \"did:webvh:QmVtcScid:kernel-vtc.example#key-1\",\n \"created\": \"2026-09-13T10:00:01Z\",\n \"proofPurpose\": \"assertionMethod\",\n \"proofValue\": \"z63jiSzsVJshBfyZwcr6nUopHo5M1QnBnWJHtwTpdNEFeD7KoX5rezJcGeoY8AVuTSo5Q3uH2KqMoEZk68qqGu3AR\"\n }\n }\n ],\n \"proof\": {\n \"type\": \"DataIntegrityProof\",\n \"cryptosuite\": \"eddsa-jcs-2022\",\n \"verificationMethod\": \"did:webvh:QmCarolScid1:kernel-vtc.example:carol#key-1\",\n \"created\": \"2026-09-14T09:05:00Z\",\n \"proofPurpose\": \"authentication\",\n \"proofValue\": \"z5k2pxtz3XrdADnsNJ1XQiZ4oj7XHVqTamscwe3Wir6JjjNKp6mJZZTmynBW32NBmWCxjs5g8Xmjck9ZLfPKtU5G4\"\n }\n },\n \"acceptsDocumentation\": [\"passport\", \"nationalId\", \"none\"],\n \"sessionHint\": \"Video, Thursday 17 September at 15:00 UTC. I will email you a link.\"\n },\n \"proof\": {\n \"type\": \"DataIntegrityProof\",\n \"cryptosuite\": \"eddsa-jcs-2022\",\n \"verificationMethod\": \"did:webvh:QmCarolScid1:kernel-vtc.example:carol#key-1\",\n \"created\": \"2026-09-14T09:05:00Z\",\n \"proofPurpose\": \"assertionMethod\",\n \"proofValue\": \"z63jiSzsVJshBfyZwcr6nUopHo5M1QnBnWJHtwTpdNEFeD7KoX5rezJcGeoY8AVuTSo5Q3uH2KqMoEZk68qqGu3AR\"\n }\n}\n";
let doc: crate::TrustTask<super::Response> =
serde_json::from_str(JSON).expect("deserialize response example");
let rendered = serde_json::to_value(&doc).expect("re-serialize");
let expected: serde_json::Value = serde_json::from_str(JSON).expect("re-parse expected");
assert_eq!(rendered, expected, "response example failed round-trip");
}
/// Each fixture in `payload.invalid-examples.json` MUST be
/// rejected by at least one of: serde deserialization, or
/// JSON-Schema validation under the `validate` feature. The
/// fixture file documents the producer-side bug class that
/// each payload exemplifies; this generated test pins it.
#[cfg(feature = "validate")]
#[test]
fn rejects_invalid_examples() {
use crate::validate::ValidatedPayload;
let fixtures: &[(&str, &str)] = &[
(
"`community` and `joinDid` are required — a request that names no community cannot be checked against any vetter's eligibility, and one that names no join DID has no subject for the card and statements that follow.",
"{}",
),
(
"`joinDid` is required even though it repeats the issuer: it is what a vetter's client checks the document issuer against, so a request relayed under another identity is refused rather than silently re-attributed.",
"{\n \"community\": \"did:webvh:QmVtcScid:kernel-vtc.example\",\n \"requirementsDigest\": \"zQmYZQN9M169SXXg1sZdpNCDAjoVajkrPLaFhJ6A4mecQfC\"\n}",
),
(
"A ticket and an introduction are mutually exclusive: a request passes a vetter's gate on one ground, and carrying both leaves the vetter to guess which it is being asked to honour.",
"{\n \"community\": \"did:webvh:QmVtcScid:kernel-vtc.example\",\n \"introduction\": {\n \"type\": [\n \"VerifiableCredential\"\n ]\n },\n \"joinDid\": \"did:webvh:QmAliceScid1:alice.example\",\n \"ticket\": {\n \"code\": \"K7QF-2M9X\"\n }\n}",
),
(
"A short code is Crockford base32, which has no O (or I, L, U) — a code containing one was mistyped, and must be refused rather than normalised into a guess.",
"{\n \"community\": \"did:webvh:QmVtcScid:kernel-vtc.example\",\n \"joinDid\": \"did:webvh:QmAliceScid1:alice.example\",\n \"ticket\": {\n \"code\": \"K7QF-2MOX\"\n }\n}",
),
(
"A ticket is one form or the other. A short code arriving with a QR secret is not a stronger ticket; it is an ambiguous one.",
"{\n \"community\": \"did:webvh:QmVtcScid:kernel-vtc.example\",\n \"joinDid\": \"did:webvh:QmAliceScid1:alice.example\",\n \"ticket\": {\n \"code\": \"K7QF-2M9X\",\n \"secret\": \"Xq3v9bT0cN2mR8sLk4Jw7pYh1eZa6uGd5fQi0oVxWnE\",\n \"ticketId\": \"t-1\"\n }\n}",
),
(
"A scanned ticket's secret is 32 bytes (43 base64url characters). A shorter one is not full-entropy and would be subject to guessing.",
"{\n \"community\": \"did:webvh:QmVtcScid:kernel-vtc.example\",\n \"joinDid\": \"did:webvh:QmAliceScid1:alice.example\",\n \"ticket\": {\n \"secret\": \"short\",\n \"ticketId\": \"t-1\"\n }\n}",
),
(
"Methods are lowerCamelCase (SPEC §4.10): `inPerson`, not `in-person`.",
"{\n \"community\": \"did:webvh:QmVtcScid:kernel-vtc.example\",\n \"joinDid\": \"did:webvh:QmAliceScid1:alice.example\",\n \"preferredMethod\": \"in-person\"\n}",
),
(
"No document details on the request. A document number sent ahead 'to save time' is exactly the data vetting is designed never to transmit.",
"{\n \"community\": \"did:webvh:QmVtcScid:kernel-vtc.example\",\n \"documentNumber\": \"X1234567\",\n \"joinDid\": \"did:webvh:QmAliceScid1:alice.example\"\n}",
),
(
"`requirementsDigest` is a multibase multihash, not a bare hex SHA-256.",
"{\n \"community\": \"did:webvh:QmVtcScid:kernel-vtc.example\",\n \"joinDid\": \"did:webvh:QmAliceScid1:alice.example\",\n \"requirementsDigest\": \"015abd7f5cc57a2dd94b7590f04ad8084273905ee33ec5cebeae62276a97f862\"\n}",
),
(
"`ext` keys must be reverse-DNS namespaces (SPEC §4.5.1).",
"{\n \"community\": \"did:webvh:QmVtcScid:kernel-vtc.example\",\n \"ext\": {\n \"mine\": {\n \"a\": 1\n }\n },\n \"joinDid\": \"did:webvh:QmAliceScid1:alice.example\"\n}",
),
];
for (i, (note, raw)) in fixtures.iter().enumerate() {
let value: serde_json::Value = match serde_json::from_str(raw) {
Ok(v) => v,
Err(_) => continue,
};
let serde_ok = serde_json::from_value::<super::Payload>(value.clone()).is_ok();
let schema_ok = super::Payload::validate_value(&value).is_ok();
assert!(
!(serde_ok && schema_ok),
"invalid-example #{} ({:?}) was accepted by both serde and JSON Schema; \
the fixture's stated failure class is no longer caught:\n{}",
i + 1,
note,
raw
);
}
}
}