//! Generated by `trust-tasks-codegen` — do not edit by hand.
//!
//! Spec slug: `vetting/session`. 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())
}
}
}
/**
The vocabulary token naming what a value IS — `name.legal`, `phone.mobile`, `address.postal`, `person.birthDate`. Dotted, most-general segment first, so that a consumer with no knowledge of the specific token can still group by its prefix.
The token is the maintainer's own; no external vocabulary is primary. External vocabularies (vCard/jCard, OIDC standard claims, schema.org) are mappings applied at PRESENTATION by a renderer, not at rest, so that a query written in any of them can be matched without the store having to live inside any one of them.
The `x:` prefix is an open extension namespace and is not decoration. The closest prior art — Windows CardSpace's self-issued card — supported exactly fifteen predefined claim types with no extensibility, and that is the specific way it failed the requirement a holder actually has. An `x:` attribute stores, composes, binds and discloses exactly like a known one; it renders generically and matches only an explicit query.*/
///
/// <details><summary>JSON schema</summary>
///
/// ```json
///{
/// "title": "ClaimType",
/// "description": "\nThe vocabulary token naming what a value IS — `name.legal`, `phone.mobile`, `address.postal`, `person.birthDate`. Dotted, most-general segment first, so that a consumer with no knowledge of the specific token can still group by its prefix.\n\nThe token is the maintainer's own; no external vocabulary is primary. External vocabularies (vCard/jCard, OIDC standard claims, schema.org) are mappings applied at PRESENTATION by a renderer, not at rest, so that a query written in any of them can be matched without the store having to live inside any one of them.\n\nThe `x:` prefix is an open extension namespace and is not decoration. The closest prior art — Windows CardSpace's self-issued card — supported exactly fifteen predefined claim types with no extensibility, and that is the specific way it failed the requirement a holder actually has. An `x:` attribute stores, composes, binds and discloses exactly like a known one; it renders generically and matches only an explicit query.",
/// "type": "string",
/// "maxLength": 128,
/// "minLength": 1,
/// "pattern": "^(x:)?[a-z][a-zA-Z0-9]*(\\.[a-z][a-zA-Z0-9]*)*$"
///}
/// ```
/// </details>
#[derive(::serde::Serialize, Clone, Debug, Eq, Hash, Ord, PartialEq, PartialOrd)]
#[serde(transparent)]
pub struct ClaimType(::std::string::String);
impl ::std::ops::Deref for ClaimType {
type Target = ::std::string::String;
fn deref(&self) -> &::std::string::String {
&self.0
}
}
impl ::std::convert::From<ClaimType> for ::std::string::String {
fn from(value: ClaimType) -> Self {
value.0
}
}
impl ::std::str::FromStr for ClaimType {
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("^(x:)?[a-z][a-zA-Z0-9]*(\\.[a-z][a-zA-Z0-9]*)*$").unwrap()
});
if PATTERN.find(value).is_none() {
return Err(
"doesn't match pattern \"^(x:)?[a-z][a-zA-Z0-9]*(\\.[a-z][a-zA-Z0-9]*)*$\"".into(),
);
}
Ok(Self(value.to_string()))
}
}
impl ::std::convert::TryFrom<&str> for ClaimType {
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 ClaimType {
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 ClaimType {
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 ClaimType {
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 the card's publisher. Additional Data Integrity members (e.g. `created`) are permitted and are covered as the cryptosuite defines.
///
/// <details><summary>JSON schema</summary>
///
/// ```json
///{
/// "title": "DataIntegrityProof",
/// "description": "A W3C Data Integrity proof by the card's publisher. Additional Data Integrity members (e.g. `created`) are permitted and are covered as the cryptosuite defines.",
/// "type": "object",
/// "required": [
/// "cryptosuite",
/// "proofPurpose",
/// "proofValue",
/// "type",
/// "verificationMethod"
/// ],
/// "properties": {
/// "cryptosuite": {
/// "description": "e.g. `eddsa-jcs-2022`.",
/// "type": "string",
/// "maxLength": 64,
/// "minLength": 1,
/// "pattern": "^[a-z0-9-]+$"
/// },
/// "proofPurpose": {
/// "type": "string",
/// "const": "assertionMethod"
/// },
/// "proofValue": {
/// "type": "string",
/// "pattern": "^z[1-9A-HJ-NP-Za-km-z]+$"
/// },
/// "type": {
/// "type": "string",
/// "const": "DataIntegrityProof"
/// },
/// "verificationMethod": {
/// "description": "A verification method of `publisher`, authorized for `assertionMethod`.",
/// "type": "string",
/// "pattern": "^did:"
/// }
/// },
/// "additionalProperties": true
///}
/// ```
/// </details>
#[derive(::serde::Deserialize, ::serde::Serialize, Clone, Debug)]
#[non_exhaustive]
pub struct DataIntegrityProof {
///e.g. `eddsa-jcs-2022`.
pub cryptosuite: DataIntegrityProofCryptosuite,
#[serde(rename = "proofPurpose")]
pub proof_purpose: ::std::string::String,
#[serde(rename = "proofValue")]
pub proof_value: DataIntegrityProofProofValue,
#[serde(rename = "type")]
pub type_: ::std::string::String,
///A verification method of `publisher`, authorized for `assertionMethod`.
#[serde(rename = "verificationMethod")]
pub verification_method: DataIntegrityProofVerificationMethod,
}
impl DataIntegrityProof {
pub fn builder() -> builder::DataIntegrityProof {
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 DataIntegrityProofCryptosuite(::std::string::String);
impl ::std::ops::Deref for DataIntegrityProofCryptosuite {
type Target = ::std::string::String;
fn deref(&self) -> &::std::string::String {
&self.0
}
}
impl ::std::convert::From<DataIntegrityProofCryptosuite> for ::std::string::String {
fn from(value: DataIntegrityProofCryptosuite) -> Self {
value.0
}
}
impl ::std::str::FromStr for DataIntegrityProofCryptosuite {
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 DataIntegrityProofCryptosuite {
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 DataIntegrityProofCryptosuite {
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 DataIntegrityProofCryptosuite {
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 DataIntegrityProofCryptosuite {
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())
})
}
}
///`DataIntegrityProofProofValue`
///
/// <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 DataIntegrityProofProofValue(::std::string::String);
impl ::std::ops::Deref for DataIntegrityProofProofValue {
type Target = ::std::string::String;
fn deref(&self) -> &::std::string::String {
&self.0
}
}
impl ::std::convert::From<DataIntegrityProofProofValue> for ::std::string::String {
fn from(value: DataIntegrityProofProofValue) -> Self {
value.0
}
}
impl ::std::str::FromStr for DataIntegrityProofProofValue {
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 DataIntegrityProofProofValue {
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 DataIntegrityProofProofValue {
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 DataIntegrityProofProofValue {
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 DataIntegrityProofProofValue {
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 `publisher`, authorized for `assertionMethod`.
///
/// <details><summary>JSON schema</summary>
///
/// ```json
///{
/// "description": "A verification method of `publisher`, authorized for `assertionMethod`.",
/// "type": "string",
/// "pattern": "^did:"
///}
/// ```
/// </details>
#[derive(::serde::Serialize, Clone, Debug, Eq, Hash, Ord, PartialEq, PartialOrd)]
#[serde(transparent)]
pub struct DataIntegrityProofVerificationMethod(::std::string::String);
impl ::std::ops::Deref for DataIntegrityProofVerificationMethod {
type Target = ::std::string::String;
fn deref(&self) -> &::std::string::String {
&self.0
}
}
impl ::std::convert::From<DataIntegrityProofVerificationMethod> for ::std::string::String {
fn from(value: DataIntegrityProofVerificationMethod) -> Self {
value.0
}
}
impl ::std::str::FromStr for DataIntegrityProofVerificationMethod {
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 DataIntegrityProofVerificationMethod {
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 DataIntegrityProofVerificationMethod {
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 DataIntegrityProofVerificationMethod {
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 DataIntegrityProofVerificationMethod {
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 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())
})
}
}
///Vendor-namespaced extension object per SPEC.md §4.5.1. Each immediate key MUST be a reverse-DNS namespace; structure under each namespace is opaque to the framework.
///
/// <details><summary>JSON schema</summary>
///
/// ```json
///{
/// "title": "Ext",
/// "description": "Vendor-namespaced extension object per SPEC.md §4.5.1. Each immediate key MUST be a reverse-DNS namespace; structure under each namespace is opaque to the framework.",
/// "type": "object",
/// "minProperties": 1,
/// "additionalProperties": true,
/// "propertyNames": {
/// "pattern": "^[a-z][a-z0-9-]*(\\.[a-z0-9-]+)+$"
/// }
///}
/// ```
/// </details>
#[derive(::serde::Deserialize, ::serde::Serialize, Clone, Debug)]
#[serde(transparent)]
pub struct Ext(pub ::std::collections::HashMap<ExtKey, ::serde_json::Value>);
impl ::std::ops::Deref for Ext {
type Target = ::std::collections::HashMap<ExtKey, ::serde_json::Value>;
fn deref(&self) -> &::std::collections::HashMap<ExtKey, ::serde_json::Value> {
&self.0
}
}
impl ::std::convert::From<Ext> for ::std::collections::HashMap<ExtKey, ::serde_json::Value> {
fn from(value: Ext) -> Self {
value.0
}
}
impl ::std::convert::From<::std::collections::HashMap<ExtKey, ::serde_json::Value>> for Ext {
fn from(value: ::std::collections::HashMap<ExtKey, ::serde_json::Value>) -> Self {
Self(value)
}
}
///`ExtKey`
///
/// <details><summary>JSON schema</summary>
///
/// ```json
///{
/// "type": "string",
/// "pattern": "^[a-z][a-z0-9-]*(\\.[a-z0-9-]+)+$"
///}
/// ```
/// </details>
#[derive(::serde::Serialize, Clone, Debug, Eq, Hash, Ord, PartialEq, PartialOrd)]
#[serde(transparent)]
pub struct ExtKey(::std::string::String);
impl ::std::ops::Deref for ExtKey {
type Target = ::std::string::String;
fn deref(&self) -> &::std::string::String {
&self.0
}
}
impl ::std::convert::From<ExtKey> for ::std::string::String {
fn from(value: ExtKey) -> Self {
value.0
}
}
impl ::std::str::FromStr for ExtKey {
type Err = self::error::ConversionError;
fn from_str(value: &str) -> ::std::result::Result<Self, self::error::ConversionError> {
static PATTERN: ::std::sync::LazyLock<::regress::Regex> =
::std::sync::LazyLock::new(|| {
::regress::Regex::new("^[a-z][a-z0-9-]*(\\.[a-z0-9-]+)+$").unwrap()
});
if PATTERN.find(value).is_none() {
return Err("doesn't match pattern \"^[a-z][a-z0-9-]*(\\.[a-z0-9-]+)+$\"".into());
}
Ok(Self(value.to_string()))
}
}
impl ::std::convert::TryFrom<&str> for ExtKey {
type Error = self::error::ConversionError;
fn try_from(value: &str) -> ::std::result::Result<Self, self::error::ConversionError> {
value.parse()
}
}
impl ::std::convert::TryFrom<&::std::string::String> for ExtKey {
type Error = self::error::ConversionError;
fn try_from(
value: &::std::string::String,
) -> ::std::result::Result<Self, self::error::ConversionError> {
value.parse()
}
}
impl ::std::convert::TryFrom<::std::string::String> for ExtKey {
type Error = self::error::ConversionError;
fn try_from(
value: ::std::string::String,
) -> ::std::result::Result<Self, self::error::ConversionError> {
value.parse()
}
}
impl<'de> ::serde::Deserialize<'de> for ExtKey {
fn deserialize<D>(deserializer: D) -> ::std::result::Result<Self, D::Error>
where
D: ::serde::Deserializer<'de>,
{
::std::string::String::deserialize(deserializer)?
.parse()
.map_err(|e: self::error::ConversionError| {
<D::Error as ::serde::de::Error>::custom(e.to_string())
})
}
}
///A vetter opens a vetting session with an applicant whose request it accepted, while the two are together in person or on a call. The request issues the session challenge and names the claims to present; the applicant's response is the signed Vetting Card. This document's `id` is the value the resulting Vetting Statement carries as `taskContext`, and its task digest is what binds the statement to it.
///
/// <details><summary>JSON schema</summary>
///
/// ```json
///{
/// "$id": "https://trusttasks.org/spec/vetting/session/0.1",
/// "title": "Payload",
/// "description": "A vetter opens a vetting session with an applicant whose request it accepted, while the two are together in person or on a call. The request issues the session challenge and names the claims to present; the applicant's response is the signed Vetting Card. This document's `id` is the value the resulting Vetting Statement carries as `taskContext`, and its task digest is what binds the statement to it.",
/// "type": "object",
/// "required": [
/// "challenge",
/// "domain",
/// "expiresAt",
/// "method",
/// "requestId",
/// "requiredClaims"
/// ],
/// "properties": {
/// "challenge": {
/// "description": "32 fresh random bytes, base64url without padding. The card binds to it. Never reused across sessions.",
/// "type": "string",
/// "pattern": "^[A-Za-z0-9_-]{43}$"
/// },
/// "domain": {
/// "description": "The community DID the applicant is being vetted for. The card binds to it alongside `challenge`.",
/// "type": "string",
/// "pattern": "^did:"
/// },
/// "expiresAt": {
/// "description": "When the session lapses: no card is accepted for it afterwards, and the card's own `expiresAt` may not be later.",
/// "type": "string",
/// "format": "date-time"
/// },
/// "ext": {
/// "$ref": "#/definitions/Ext"
/// },
/// "method": {
/// "description": "How this session is conducted.",
/// "$ref": "#/definitions/VettingMethod"
/// },
/// "optionalClaims": {
/// "description": "Claim types the applicant may add. Never part of the commitment.",
/// "type": "array",
/// "items": {
/// "not": {
/// "const": "person.portrait"
/// },
/// "$ref": "#/definitions/ClaimType"
/// },
/// "uniqueItems": true
/// },
/// "requestId": {
/// "description": "The `requestId` from the vetter's acceptance of the applicant's vetting request.",
/// "type": "string",
/// "maxLength": 128,
/// "minLength": 1
/// },
/// "requiredClaims": {
/// "description": "Claim types the card must carry. The community criterion's `requiredClaims`; the identity commitment is computed over exactly these.",
/// "type": "array",
/// "items": {
/// "not": {
/// "const": "person.portrait"
/// },
/// "$ref": "#/definitions/ClaimType"
/// },
/// "uniqueItems": true
/// }
/// },
/// "additionalProperties": false
///}
/// ```
/// </details>
#[derive(::serde::Deserialize, ::serde::Serialize, Clone, Debug)]
#[serde(deny_unknown_fields)]
#[non_exhaustive]
pub struct Payload {
///32 fresh random bytes, base64url without padding. The card binds to it. Never reused across sessions.
pub challenge: PayloadChallenge,
///The community DID the applicant is being vetted for. The card binds to it alongside `challenge`.
pub domain: PayloadDomain,
///When the session lapses: no card is accepted for it afterwards, and the card's own `expiresAt` may not be later.
#[serde(rename = "expiresAt")]
pub expires_at: ::chrono::DateTime<::chrono::offset::Utc>,
#[serde(default, skip_serializing_if = "::std::option::Option::is_none")]
pub ext: ::std::option::Option<Ext>,
///How this session is conducted.
pub method: VettingMethod,
///Claim types the applicant may add. Never part of the commitment.
#[serde(
rename = "optionalClaims",
default,
skip_serializing_if = "::std::option::Option::is_none"
)]
pub optional_claims: ::std::option::Option<Vec<PayloadOptionalClaimsItem>>,
///The `requestId` from the vetter's acceptance of the applicant's vetting request.
#[serde(rename = "requestId")]
pub request_id: PayloadRequestId,
///Claim types the card must carry. The community criterion's `requiredClaims`; the identity commitment is computed over exactly these.
#[serde(rename = "requiredClaims")]
pub required_claims: Vec<PayloadRequiredClaimsItem>,
}
impl Payload {
pub fn builder() -> builder::Payload {
Default::default()
}
}
///32 fresh random bytes, base64url without padding. The card binds to it. Never reused across sessions.
///
/// <details><summary>JSON schema</summary>
///
/// ```json
///{
/// "description": "32 fresh random bytes, base64url without padding. The card binds to it. Never reused across sessions.",
/// "type": "string",
/// "pattern": "^[A-Za-z0-9_-]{43}$"
///}
/// ```
/// </details>
#[derive(::serde::Serialize, Clone, Debug, Eq, Hash, Ord, PartialEq, PartialOrd)]
#[serde(transparent)]
pub struct PayloadChallenge(::std::string::String);
impl ::std::ops::Deref for PayloadChallenge {
type Target = ::std::string::String;
fn deref(&self) -> &::std::string::String {
&self.0
}
}
impl ::std::convert::From<PayloadChallenge> for ::std::string::String {
fn from(value: PayloadChallenge) -> Self {
value.0
}
}
impl ::std::str::FromStr for PayloadChallenge {
type Err = self::error::ConversionError;
fn from_str(value: &str) -> ::std::result::Result<Self, self::error::ConversionError> {
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 PayloadChallenge {
type Error = self::error::ConversionError;
fn try_from(value: &str) -> ::std::result::Result<Self, self::error::ConversionError> {
value.parse()
}
}
impl ::std::convert::TryFrom<&::std::string::String> for PayloadChallenge {
type Error = self::error::ConversionError;
fn try_from(
value: &::std::string::String,
) -> ::std::result::Result<Self, self::error::ConversionError> {
value.parse()
}
}
impl ::std::convert::TryFrom<::std::string::String> for PayloadChallenge {
type Error = self::error::ConversionError;
fn try_from(
value: ::std::string::String,
) -> ::std::result::Result<Self, self::error::ConversionError> {
value.parse()
}
}
impl<'de> ::serde::Deserialize<'de> for PayloadChallenge {
fn deserialize<D>(deserializer: D) -> ::std::result::Result<Self, D::Error>
where
D: ::serde::Deserializer<'de>,
{
::std::string::String::deserialize(deserializer)?
.parse()
.map_err(|e: self::error::ConversionError| {
<D::Error as ::serde::de::Error>::custom(e.to_string())
})
}
}
///The community DID the applicant is being vetted for. The card binds to it alongside `challenge`.
///
/// <details><summary>JSON schema</summary>
///
/// ```json
///{
/// "description": "The community DID the applicant is being vetted for. The card binds to it alongside `challenge`.",
/// "type": "string",
/// "pattern": "^did:"
///}
/// ```
/// </details>
#[derive(::serde::Serialize, Clone, Debug, Eq, Hash, Ord, PartialEq, PartialOrd)]
#[serde(transparent)]
pub struct PayloadDomain(::std::string::String);
impl ::std::ops::Deref for PayloadDomain {
type Target = ::std::string::String;
fn deref(&self) -> &::std::string::String {
&self.0
}
}
impl ::std::convert::From<PayloadDomain> for ::std::string::String {
fn from(value: PayloadDomain) -> Self {
value.0
}
}
impl ::std::str::FromStr for PayloadDomain {
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 PayloadDomain {
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 PayloadDomain {
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 PayloadDomain {
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 PayloadDomain {
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())
})
}
}
///`PayloadOptionalClaimsItem`
///
/// <details><summary>JSON schema</summary>
///
/// ```json
///{
/// "type": "string",
/// "maxLength": 128,
/// "minLength": 1,
/// "pattern": "^(x:)?[a-z][a-zA-Z0-9]*(\\.[a-z][a-zA-Z0-9]*)*$"
///}
/// ```
/// </details>
#[derive(::serde::Serialize, Clone, Debug, Eq, Hash, Ord, PartialEq, PartialOrd)]
#[serde(transparent)]
pub struct PayloadOptionalClaimsItem(::std::string::String);
impl ::std::ops::Deref for PayloadOptionalClaimsItem {
type Target = ::std::string::String;
fn deref(&self) -> &::std::string::String {
&self.0
}
}
impl ::std::convert::From<PayloadOptionalClaimsItem> for ::std::string::String {
fn from(value: PayloadOptionalClaimsItem) -> Self {
value.0
}
}
impl ::std::str::FromStr for PayloadOptionalClaimsItem {
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("^(x:)?[a-z][a-zA-Z0-9]*(\\.[a-z][a-zA-Z0-9]*)*$").unwrap()
});
if PATTERN.find(value).is_none() {
return Err(
"doesn't match pattern \"^(x:)?[a-z][a-zA-Z0-9]*(\\.[a-z][a-zA-Z0-9]*)*$\"".into(),
);
}
Ok(Self(value.to_string()))
}
}
impl ::std::convert::TryFrom<&str> for PayloadOptionalClaimsItem {
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 PayloadOptionalClaimsItem {
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 PayloadOptionalClaimsItem {
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 PayloadOptionalClaimsItem {
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 `requestId` from the vetter's acceptance of the applicant's vetting request.
///
/// <details><summary>JSON schema</summary>
///
/// ```json
///{
/// "description": "The `requestId` from the vetter's acceptance of the applicant's vetting request.",
/// "type": "string",
/// "maxLength": 128,
/// "minLength": 1
///}
/// ```
/// </details>
#[derive(::serde::Serialize, Clone, Debug, Eq, Hash, Ord, PartialEq, PartialOrd)]
#[serde(transparent)]
pub struct PayloadRequestId(::std::string::String);
impl ::std::ops::Deref for PayloadRequestId {
type Target = ::std::string::String;
fn deref(&self) -> &::std::string::String {
&self.0
}
}
impl ::std::convert::From<PayloadRequestId> for ::std::string::String {
fn from(value: PayloadRequestId) -> Self {
value.0
}
}
impl ::std::str::FromStr for PayloadRequestId {
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 PayloadRequestId {
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 PayloadRequestId {
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 PayloadRequestId {
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 PayloadRequestId {
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())
})
}
}
///`PayloadRequiredClaimsItem`
///
/// <details><summary>JSON schema</summary>
///
/// ```json
///{
/// "type": "string",
/// "maxLength": 128,
/// "minLength": 1,
/// "pattern": "^(x:)?[a-z][a-zA-Z0-9]*(\\.[a-z][a-zA-Z0-9]*)*$"
///}
/// ```
/// </details>
#[derive(::serde::Serialize, Clone, Debug, Eq, Hash, Ord, PartialEq, PartialOrd)]
#[serde(transparent)]
pub struct PayloadRequiredClaimsItem(::std::string::String);
impl ::std::ops::Deref for PayloadRequiredClaimsItem {
type Target = ::std::string::String;
fn deref(&self) -> &::std::string::String {
&self.0
}
}
impl ::std::convert::From<PayloadRequiredClaimsItem> for ::std::string::String {
fn from(value: PayloadRequiredClaimsItem) -> Self {
value.0
}
}
impl ::std::str::FromStr for PayloadRequiredClaimsItem {
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("^(x:)?[a-z][a-zA-Z0-9]*(\\.[a-z][a-zA-Z0-9]*)*$").unwrap()
});
if PATTERN.find(value).is_none() {
return Err(
"doesn't match pattern \"^(x:)?[a-z][a-zA-Z0-9]*(\\.[a-z][a-zA-Z0-9]*)*$\"".into(),
);
}
Ok(Self(value.to_string()))
}
}
impl ::std::convert::TryFrom<&str> for PayloadRequiredClaimsItem {
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 PayloadRequiredClaimsItem {
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 PayloadRequiredClaimsItem {
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 PayloadRequiredClaimsItem {
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 signed Vetting Card, bound to this session.
///
/// <details><summary>JSON schema</summary>
///
/// ```json
///{
/// "title": "Response",
/// "description": "The applicant's signed Vetting Card, bound to this session.",
/// "type": "object",
/// "required": [
/// "card"
/// ],
/// "properties": {
/// "card": {
/// "$ref": "#/definitions/VettingCard"
/// },
/// "ext": {
/// "$ref": "#/definitions/Ext"
/// }
/// },
/// "additionalProperties": false,
/// "$anchor": "response"
///}
/// ```
/// </details>
#[derive(::serde::Deserialize, ::serde::Serialize, Clone, Debug)]
#[serde(deny_unknown_fields)]
#[non_exhaustive]
pub struct Response {
pub card: VettingCard,
#[serde(default, skip_serializing_if = "::std::option::Option::is_none")]
pub ext: ::std::option::Option<Ext>,
}
impl Response {
pub fn builder() -> builder::Response {
Default::default()
}
}
///`VettingCard`
///
/// <details><summary>JSON schema</summary>
///
/// ```json
///{
/// "title": "VettingCard",
/// "type": "object",
/// "required": [
/// "audience",
/// "cardVersion",
/// "challenge",
/// "claims",
/// "commitmentSalt",
/// "community",
/// "domain",
/// "expiresAt",
/// "id",
/// "identityCommitment",
/// "issuedAt",
/// "proof",
/// "publisher",
/// "type"
/// ],
/// "properties": {
/// "audience": {
/// "description": "The vetter's DID — the issuer of the vetting session. A card addressed to anyone else is refused.",
/// "type": "string",
/// "pattern": "^did:"
/// },
/// "cardVersion": {
/// "type": "integer",
/// "minimum": 1.0
/// },
/// "challenge": {
/// "description": "The session's challenge, copied verbatim.",
/// "type": "string",
/// "pattern": "^[A-Za-z0-9_-]{43}$"
/// },
/// "claims": {
/// "type": "array",
/// "items": {
/// "$ref": "#/definitions/VettingCardClaim"
/// },
/// "minItems": 1
/// },
/// "commitmentSalt": {
/// "description": "32 random bytes, base64url without padding, generated once per application. Goes to vetters inside the card and to nobody else: a party holding the commitment without the salt cannot test guesses at the claimed name.",
/// "type": "string",
/// "pattern": "^[A-Za-z0-9_-]{43}$"
/// },
/// "community": {
/// "description": "The community the applicant is being vetted for.",
/// "type": "string",
/// "pattern": "^did:"
/// },
/// "domain": {
/// "description": "The session's domain, copied verbatim.",
/// "type": "string",
/// "pattern": "^did:"
/// },
/// "expiresAt": {
/// "description": "No later than the session's `expiresAt`.",
/// "type": "string",
/// "format": "date-time"
/// },
/// "id": {
/// "description": "Fresh per card. A card is never re-sent to a second session under the same id.",
/// "type": "string",
/// "pattern": "^urn:uuid:[0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[0-9a-fA-F]{4}-[0-9a-fA-F]{4}-[0-9a-fA-F]{12}$"
/// },
/// "identityCommitment": {
/// "description": "digestMultibase over the RFC 8785 canonicalization of `{ \"salt\": commitmentSalt, \"claims\": R }`, where R is `{ \"type\", \"value\" }` for every card claim whose type the session lists in `requiredClaims`, ordered by `type` then `value` (code-point order). SHA-256 RECOMMENDED. Because the applicant uses one salt per application, every vetter of that application sees the same value.",
/// "$ref": "#/definitions/DigestMultibase"
/// },
/// "issuedAt": {
/// "type": "string",
/// "format": "date-time"
/// },
/// "proof": {
/// "$ref": "#/definitions/DataIntegrityProof"
/// },
/// "publisher": {
/// "description": "The applicant's DID — the issuer of the vetting request and the subject every resulting statement names. The card is signed with this DID's assertion key.",
/// "type": "string",
/// "pattern": "^did:"
/// },
/// "type": {
/// "description": "Exactly `VerifiableDataStructure`, `RelationshipCard` and `VettingCard`, in any order.",
/// "type": "array",
/// "items": {
/// "type": "string",
/// "enum": [
/// "VerifiableDataStructure",
/// "RelationshipCard",
/// "VettingCard"
/// ]
/// },
/// "maxItems": 3,
/// "minItems": 3,
/// "uniqueItems": true
/// }
/// },
/// "additionalProperties": false
///}
/// ```
/// </details>
#[derive(::serde::Deserialize, ::serde::Serialize, Clone, Debug)]
#[serde(deny_unknown_fields)]
#[non_exhaustive]
pub struct VettingCard {
///The vetter's DID — the issuer of the vetting session. A card addressed to anyone else is refused.
pub audience: VettingCardAudience,
#[serde(rename = "cardVersion")]
pub card_version: ::std::num::NonZeroU64,
///The session's challenge, copied verbatim.
pub challenge: VettingCardChallenge,
pub claims: ::std::vec::Vec<VettingCardClaim>,
///32 random bytes, base64url without padding, generated once per application. Goes to vetters inside the card and to nobody else: a party holding the commitment without the salt cannot test guesses at the claimed name.
#[serde(rename = "commitmentSalt")]
pub commitment_salt: VettingCardCommitmentSalt,
///The community the applicant is being vetted for.
pub community: VettingCardCommunity,
///The session's domain, copied verbatim.
pub domain: VettingCardDomain,
///No later than the session's `expiresAt`.
#[serde(rename = "expiresAt")]
pub expires_at: ::chrono::DateTime<::chrono::offset::Utc>,
///Fresh per card. A card is never re-sent to a second session under the same id.
pub id: VettingCardId,
///digestMultibase over the RFC 8785 canonicalization of `{ "salt": commitmentSalt, "claims": R }`, where R is `{ "type", "value" }` for every card claim whose type the session lists in `requiredClaims`, ordered by `type` then `value` (code-point order). SHA-256 RECOMMENDED. Because the applicant uses one salt per application, every vetter of that application sees the same value.
#[serde(rename = "identityCommitment")]
pub identity_commitment: DigestMultibase,
#[serde(rename = "issuedAt")]
pub issued_at: ::chrono::DateTime<::chrono::offset::Utc>,
pub proof: DataIntegrityProof,
///The applicant's DID — the issuer of the vetting request and the subject every resulting statement names. The card is signed with this DID's assertion key.
pub publisher: VettingCardPublisher,
///Exactly `VerifiableDataStructure`, `RelationshipCard` and `VettingCard`, in any order.
#[serde(rename = "type")]
pub type_: Vec<VettingCardTypeItem>,
}
impl VettingCard {
pub fn builder() -> builder::VettingCard {
Default::default()
}
}
///The vetter's DID — the issuer of the vetting session. A card addressed to anyone else is refused.
///
/// <details><summary>JSON schema</summary>
///
/// ```json
///{
/// "description": "The vetter's DID — the issuer of the vetting session. A card addressed to anyone else is refused.",
/// "type": "string",
/// "pattern": "^did:"
///}
/// ```
/// </details>
#[derive(::serde::Serialize, Clone, Debug, Eq, Hash, Ord, PartialEq, PartialOrd)]
#[serde(transparent)]
pub struct VettingCardAudience(::std::string::String);
impl ::std::ops::Deref for VettingCardAudience {
type Target = ::std::string::String;
fn deref(&self) -> &::std::string::String {
&self.0
}
}
impl ::std::convert::From<VettingCardAudience> for ::std::string::String {
fn from(value: VettingCardAudience) -> Self {
value.0
}
}
impl ::std::str::FromStr for VettingCardAudience {
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 VettingCardAudience {
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 VettingCardAudience {
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 VettingCardAudience {
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 VettingCardAudience {
fn deserialize<D>(deserializer: D) -> ::std::result::Result<Self, D::Error>
where
D: ::serde::Deserializer<'de>,
{
::std::string::String::deserialize(deserializer)?
.parse()
.map_err(|e: self::error::ConversionError| {
<D::Error as ::serde::de::Error>::custom(e.to_string())
})
}
}
///The session's challenge, copied verbatim.
///
/// <details><summary>JSON schema</summary>
///
/// ```json
///{
/// "description": "The session's challenge, copied verbatim.",
/// "type": "string",
/// "pattern": "^[A-Za-z0-9_-]{43}$"
///}
/// ```
/// </details>
#[derive(::serde::Serialize, Clone, Debug, Eq, Hash, Ord, PartialEq, PartialOrd)]
#[serde(transparent)]
pub struct VettingCardChallenge(::std::string::String);
impl ::std::ops::Deref for VettingCardChallenge {
type Target = ::std::string::String;
fn deref(&self) -> &::std::string::String {
&self.0
}
}
impl ::std::convert::From<VettingCardChallenge> for ::std::string::String {
fn from(value: VettingCardChallenge) -> Self {
value.0
}
}
impl ::std::str::FromStr for VettingCardChallenge {
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 VettingCardChallenge {
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 VettingCardChallenge {
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 VettingCardChallenge {
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 VettingCardChallenge {
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())
})
}
}
///`VettingCardClaim`
///
/// <details><summary>JSON schema</summary>
///
/// ```json
///{
/// "title": "VettingCardClaim",
/// "type": "object",
/// "required": [
/// "provenance",
/// "type",
/// "value"
/// ],
/// "properties": {
/// "provenance": {
/// "description": "Where the value's assurance comes from. `selfAsserted` — the applicant says so, and the vetter's human check is the only assurance added — is the only value this version defines; a verifier MUST NOT treat any other value as adding assurance it does not understand.",
/// "type": "string",
/// "maxLength": 64,
/// "minLength": 1,
/// "pattern": "^[a-z][a-zA-Z0-9]*$"
/// },
/// "type": {
/// "description": "The claim type. `person.portrait` is refused: identity vetting works by a vetter looking at the person, not by transmitting their image.",
/// "not": {
/// "const": "person.portrait"
/// },
/// "$ref": "#/definitions/ClaimType"
/// },
/// "value": {
/// "description": "The claimed value, exactly as rendered from the applicant's persona — a string for most claim types, structured JSON for some (e.g. a postal address). Authored by the applicant and asserted under their signature; the vetter's check is what gives it any assurance."
/// }
/// },
/// "additionalProperties": false
///}
/// ```
/// </details>
#[derive(::serde::Deserialize, ::serde::Serialize, Clone, Debug)]
#[serde(deny_unknown_fields)]
#[non_exhaustive]
pub struct VettingCardClaim {
///Where the value's assurance comes from. `selfAsserted` — the applicant says so, and the vetter's human check is the only assurance added — is the only value this version defines; a verifier MUST NOT treat any other value as adding assurance it does not understand.
pub provenance: VettingCardClaimProvenance,
///The claim type. `person.portrait` is refused: identity vetting works by a vetter looking at the person, not by transmitting their image.
#[serde(rename = "type")]
pub type_: VettingCardClaimType,
///The claimed value, exactly as rendered from the applicant's persona — a string for most claim types, structured JSON for some (e.g. a postal address). Authored by the applicant and asserted under their signature; the vetter's check is what gives it any assurance.
pub value: ::serde_json::Value,
}
impl VettingCardClaim {
pub fn builder() -> builder::VettingCardClaim {
Default::default()
}
}
///Where the value's assurance comes from. `selfAsserted` — the applicant says so, and the vetter's human check is the only assurance added — is the only value this version defines; a verifier MUST NOT treat any other value as adding assurance it does not understand.
///
/// <details><summary>JSON schema</summary>
///
/// ```json
///{
/// "description": "Where the value's assurance comes from. `selfAsserted` — the applicant says so, and the vetter's human check is the only assurance added — is the only value this version defines; a verifier MUST NOT treat any other value as adding assurance it does not understand.",
/// "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 VettingCardClaimProvenance(::std::string::String);
impl ::std::ops::Deref for VettingCardClaimProvenance {
type Target = ::std::string::String;
fn deref(&self) -> &::std::string::String {
&self.0
}
}
impl ::std::convert::From<VettingCardClaimProvenance> for ::std::string::String {
fn from(value: VettingCardClaimProvenance) -> Self {
value.0
}
}
impl ::std::str::FromStr for VettingCardClaimProvenance {
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 VettingCardClaimProvenance {
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 VettingCardClaimProvenance {
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 VettingCardClaimProvenance {
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 VettingCardClaimProvenance {
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())
})
}
}
///`VettingCardClaimType`
///
/// <details><summary>JSON schema</summary>
///
/// ```json
///{
/// "type": "string",
/// "maxLength": 128,
/// "minLength": 1,
/// "pattern": "^(x:)?[a-z][a-zA-Z0-9]*(\\.[a-z][a-zA-Z0-9]*)*$"
///}
/// ```
/// </details>
#[derive(::serde::Serialize, Clone, Debug, Eq, Hash, Ord, PartialEq, PartialOrd)]
#[serde(transparent)]
pub struct VettingCardClaimType(::std::string::String);
impl ::std::ops::Deref for VettingCardClaimType {
type Target = ::std::string::String;
fn deref(&self) -> &::std::string::String {
&self.0
}
}
impl ::std::convert::From<VettingCardClaimType> for ::std::string::String {
fn from(value: VettingCardClaimType) -> Self {
value.0
}
}
impl ::std::str::FromStr for VettingCardClaimType {
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("^(x:)?[a-z][a-zA-Z0-9]*(\\.[a-z][a-zA-Z0-9]*)*$").unwrap()
});
if PATTERN.find(value).is_none() {
return Err(
"doesn't match pattern \"^(x:)?[a-z][a-zA-Z0-9]*(\\.[a-z][a-zA-Z0-9]*)*$\"".into(),
);
}
Ok(Self(value.to_string()))
}
}
impl ::std::convert::TryFrom<&str> for VettingCardClaimType {
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 VettingCardClaimType {
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 VettingCardClaimType {
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 VettingCardClaimType {
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())
})
}
}
///32 random bytes, base64url without padding, generated once per application. Goes to vetters inside the card and to nobody else: a party holding the commitment without the salt cannot test guesses at the claimed name.
///
/// <details><summary>JSON schema</summary>
///
/// ```json
///{
/// "description": "32 random bytes, base64url without padding, generated once per application. Goes to vetters inside the card and to nobody else: a party holding the commitment without the salt cannot test guesses at the claimed name.",
/// "type": "string",
/// "pattern": "^[A-Za-z0-9_-]{43}$"
///}
/// ```
/// </details>
#[derive(::serde::Serialize, Clone, Debug, Eq, Hash, Ord, PartialEq, PartialOrd)]
#[serde(transparent)]
pub struct VettingCardCommitmentSalt(::std::string::String);
impl ::std::ops::Deref for VettingCardCommitmentSalt {
type Target = ::std::string::String;
fn deref(&self) -> &::std::string::String {
&self.0
}
}
impl ::std::convert::From<VettingCardCommitmentSalt> for ::std::string::String {
fn from(value: VettingCardCommitmentSalt) -> Self {
value.0
}
}
impl ::std::str::FromStr for VettingCardCommitmentSalt {
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 VettingCardCommitmentSalt {
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 VettingCardCommitmentSalt {
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 VettingCardCommitmentSalt {
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 VettingCardCommitmentSalt {
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 being vetted for.
///
/// <details><summary>JSON schema</summary>
///
/// ```json
///{
/// "description": "The community the applicant is being vetted for.",
/// "type": "string",
/// "pattern": "^did:"
///}
/// ```
/// </details>
#[derive(::serde::Serialize, Clone, Debug, Eq, Hash, Ord, PartialEq, PartialOrd)]
#[serde(transparent)]
pub struct VettingCardCommunity(::std::string::String);
impl ::std::ops::Deref for VettingCardCommunity {
type Target = ::std::string::String;
fn deref(&self) -> &::std::string::String {
&self.0
}
}
impl ::std::convert::From<VettingCardCommunity> for ::std::string::String {
fn from(value: VettingCardCommunity) -> Self {
value.0
}
}
impl ::std::str::FromStr for VettingCardCommunity {
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 VettingCardCommunity {
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 VettingCardCommunity {
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 VettingCardCommunity {
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 VettingCardCommunity {
fn deserialize<D>(deserializer: D) -> ::std::result::Result<Self, D::Error>
where
D: ::serde::Deserializer<'de>,
{
::std::string::String::deserialize(deserializer)?
.parse()
.map_err(|e: self::error::ConversionError| {
<D::Error as ::serde::de::Error>::custom(e.to_string())
})
}
}
///The session's domain, copied verbatim.
///
/// <details><summary>JSON schema</summary>
///
/// ```json
///{
/// "description": "The session's domain, copied verbatim.",
/// "type": "string",
/// "pattern": "^did:"
///}
/// ```
/// </details>
#[derive(::serde::Serialize, Clone, Debug, Eq, Hash, Ord, PartialEq, PartialOrd)]
#[serde(transparent)]
pub struct VettingCardDomain(::std::string::String);
impl ::std::ops::Deref for VettingCardDomain {
type Target = ::std::string::String;
fn deref(&self) -> &::std::string::String {
&self.0
}
}
impl ::std::convert::From<VettingCardDomain> for ::std::string::String {
fn from(value: VettingCardDomain) -> Self {
value.0
}
}
impl ::std::str::FromStr for VettingCardDomain {
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 VettingCardDomain {
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 VettingCardDomain {
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 VettingCardDomain {
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 VettingCardDomain {
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())
})
}
}
///Fresh per card. A card is never re-sent to a second session under the same id.
///
/// <details><summary>JSON schema</summary>
///
/// ```json
///{
/// "description": "Fresh per card. A card is never re-sent to a second session under the same id.",
/// "type": "string",
/// "pattern": "^urn:uuid:[0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[0-9a-fA-F]{4}-[0-9a-fA-F]{4}-[0-9a-fA-F]{12}$"
///}
/// ```
/// </details>
#[derive(::serde::Serialize, Clone, Debug, Eq, Hash, Ord, PartialEq, PartialOrd)]
#[serde(transparent)]
pub struct VettingCardId(::std::string::String);
impl ::std::ops::Deref for VettingCardId {
type Target = ::std::string::String;
fn deref(&self) -> &::std::string::String {
&self.0
}
}
impl ::std::convert::From<VettingCardId> for ::std::string::String {
fn from(value: VettingCardId) -> Self {
value.0
}
}
impl ::std::str::FromStr for VettingCardId {
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(
"^urn:uuid:[0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[0-9a-fA-F]{4}-[0-9a-fA-F]{4}-[0-9a-fA-F]{12}$",
)
.unwrap()
},
);
if PATTERN.find(value).is_none() {
return Err(
"doesn't match pattern \"^urn:uuid:[0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[0-9a-fA-F]{4}-[0-9a-fA-F]{4}-[0-9a-fA-F]{12}$\""
.into(),
);
}
Ok(Self(value.to_string()))
}
}
impl ::std::convert::TryFrom<&str> for VettingCardId {
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 VettingCardId {
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 VettingCardId {
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 VettingCardId {
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 DID — the issuer of the vetting request and the subject every resulting statement names. The card is signed with this DID's assertion key.
///
/// <details><summary>JSON schema</summary>
///
/// ```json
///{
/// "description": "The applicant's DID — the issuer of the vetting request and the subject every resulting statement names. The card is signed with this DID's assertion key.",
/// "type": "string",
/// "pattern": "^did:"
///}
/// ```
/// </details>
#[derive(::serde::Serialize, Clone, Debug, Eq, Hash, Ord, PartialEq, PartialOrd)]
#[serde(transparent)]
pub struct VettingCardPublisher(::std::string::String);
impl ::std::ops::Deref for VettingCardPublisher {
type Target = ::std::string::String;
fn deref(&self) -> &::std::string::String {
&self.0
}
}
impl ::std::convert::From<VettingCardPublisher> for ::std::string::String {
fn from(value: VettingCardPublisher) -> Self {
value.0
}
}
impl ::std::str::FromStr for VettingCardPublisher {
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 VettingCardPublisher {
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 VettingCardPublisher {
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 VettingCardPublisher {
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 VettingCardPublisher {
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())
})
}
}
///`VettingCardTypeItem`
///
/// <details><summary>JSON schema</summary>
///
/// ```json
///{
/// "type": "string",
/// "enum": [
/// "VerifiableDataStructure",
/// "RelationshipCard",
/// "VettingCard"
/// ]
///}
/// ```
/// </details>
#[derive(
::serde::Deserialize,
::serde::Serialize,
Clone,
Copy,
Debug,
Eq,
Hash,
Ord,
PartialEq,
PartialOrd,
)]
#[non_exhaustive]
pub enum VettingCardTypeItem {
VerifiableDataStructure,
RelationshipCard,
VettingCard,
}
impl ::std::fmt::Display for VettingCardTypeItem {
fn fmt(&self, f: &mut ::std::fmt::Formatter<'_>) -> ::std::fmt::Result {
match *self {
Self::VerifiableDataStructure => f.write_str("VerifiableDataStructure"),
Self::RelationshipCard => f.write_str("RelationshipCard"),
Self::VettingCard => f.write_str("VettingCard"),
}
}
}
impl ::std::str::FromStr for VettingCardTypeItem {
type Err = self::error::ConversionError;
fn from_str(value: &str) -> ::std::result::Result<Self, self::error::ConversionError> {
match value {
"VerifiableDataStructure" => Ok(Self::VerifiableDataStructure),
"RelationshipCard" => Ok(Self::RelationshipCard),
"VettingCard" => Ok(Self::VettingCard),
_ => Err("invalid value".into()),
}
}
}
impl ::std::convert::TryFrom<&str> for VettingCardTypeItem {
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 VettingCardTypeItem {
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 VettingCardTypeItem {
type Error = self::error::ConversionError;
fn try_from(
value: ::std::string::String,
) -> ::std::result::Result<Self, self::error::ConversionError> {
value.parse()
}
}
///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 DataIntegrityProof {
cryptosuite:
::std::result::Result<super::DataIntegrityProofCryptosuite, ::std::string::String>,
proof_purpose: ::std::result::Result<::std::string::String, ::std::string::String>,
proof_value:
::std::result::Result<super::DataIntegrityProofProofValue, ::std::string::String>,
type_: ::std::result::Result<::std::string::String, ::std::string::String>,
verification_method: ::std::result::Result<
super::DataIntegrityProofVerificationMethod,
::std::string::String,
>,
}
impl ::std::default::Default for DataIntegrityProof {
fn default() -> Self {
Self {
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 DataIntegrityProof {
pub fn cryptosuite<T>(mut self, value: T) -> Self
where
T: ::std::convert::TryInto<super::DataIntegrityProofCryptosuite>,
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::DataIntegrityProofProofValue>,
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::DataIntegrityProofVerificationMethod>,
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<DataIntegrityProof> for super::DataIntegrityProof {
type Error = super::error::ConversionError;
fn try_from(
value: DataIntegrityProof,
) -> ::std::result::Result<Self, super::error::ConversionError> {
Ok(Self {
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::DataIntegrityProof> for DataIntegrityProof {
fn from(value: super::DataIntegrityProof) -> Self {
Self {
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 {
challenge: ::std::result::Result<super::PayloadChallenge, ::std::string::String>,
domain: ::std::result::Result<super::PayloadDomain, ::std::string::String>,
expires_at:
::std::result::Result<::chrono::DateTime<::chrono::offset::Utc>, ::std::string::String>,
ext: ::std::result::Result<::std::option::Option<super::Ext>, ::std::string::String>,
method: ::std::result::Result<super::VettingMethod, ::std::string::String>,
optional_claims: ::std::result::Result<
::std::option::Option<Vec<super::PayloadOptionalClaimsItem>>,
::std::string::String,
>,
request_id: ::std::result::Result<super::PayloadRequestId, ::std::string::String>,
required_claims:
::std::result::Result<Vec<super::PayloadRequiredClaimsItem>, ::std::string::String>,
}
impl ::std::default::Default for Payload {
fn default() -> Self {
Self {
challenge: Err("no value supplied for challenge".to_string()),
domain: Err("no value supplied for domain".to_string()),
expires_at: Err("no value supplied for expires_at".to_string()),
ext: Ok(Default::default()),
method: Err("no value supplied for method".to_string()),
optional_claims: Ok(Default::default()),
request_id: Err("no value supplied for request_id".to_string()),
required_claims: Err("no value supplied for required_claims".to_string()),
}
}
}
impl Payload {
pub fn challenge<T>(mut self, value: T) -> Self
where
T: ::std::convert::TryInto<super::PayloadChallenge>,
T::Error: ::std::fmt::Display,
{
self.challenge = value
.try_into()
.map_err(|e| format!("error converting supplied value for challenge: {e}"));
self
}
pub fn domain<T>(mut self, value: T) -> Self
where
T: ::std::convert::TryInto<super::PayloadDomain>,
T::Error: ::std::fmt::Display,
{
self.domain = value
.try_into()
.map_err(|e| format!("error converting supplied value for domain: {e}"));
self
}
pub fn expires_at<T>(mut self, value: T) -> Self
where
T: ::std::convert::TryInto<::chrono::DateTime<::chrono::offset::Utc>>,
T::Error: ::std::fmt::Display,
{
self.expires_at = value
.try_into()
.map_err(|e| format!("error converting supplied value for expires_at: {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 method<T>(mut self, value: T) -> Self
where
T: ::std::convert::TryInto<super::VettingMethod>,
T::Error: ::std::fmt::Display,
{
self.method = value
.try_into()
.map_err(|e| format!("error converting supplied value for method: {e}"));
self
}
pub fn optional_claims<T>(mut self, value: T) -> Self
where
T: ::std::convert::TryInto<
::std::option::Option<Vec<super::PayloadOptionalClaimsItem>>,
>,
T::Error: ::std::fmt::Display,
{
self.optional_claims = value
.try_into()
.map_err(|e| format!("error converting supplied value for optional_claims: {e}"));
self
}
pub fn request_id<T>(mut self, value: T) -> Self
where
T: ::std::convert::TryInto<super::PayloadRequestId>,
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 required_claims<T>(mut self, value: T) -> Self
where
T: ::std::convert::TryInto<Vec<super::PayloadRequiredClaimsItem>>,
T::Error: ::std::fmt::Display,
{
self.required_claims = value
.try_into()
.map_err(|e| format!("error converting supplied value for required_claims: {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 {
challenge: value.challenge?,
domain: value.domain?,
expires_at: value.expires_at?,
ext: value.ext?,
method: value.method?,
optional_claims: value.optional_claims?,
request_id: value.request_id?,
required_claims: value.required_claims?,
})
}
}
impl ::std::convert::From<super::Payload> for Payload {
fn from(value: super::Payload) -> Self {
Self {
challenge: Ok(value.challenge),
domain: Ok(value.domain),
expires_at: Ok(value.expires_at),
ext: Ok(value.ext),
method: Ok(value.method),
optional_claims: Ok(value.optional_claims),
request_id: Ok(value.request_id),
required_claims: Ok(value.required_claims),
}
}
}
#[derive(Clone, Debug)]
pub struct Response {
card: ::std::result::Result<super::VettingCard, ::std::string::String>,
ext: ::std::result::Result<::std::option::Option<super::Ext>, ::std::string::String>,
}
impl ::std::default::Default for Response {
fn default() -> Self {
Self {
card: Err("no value supplied for card".to_string()),
ext: Ok(Default::default()),
}
}
}
impl Response {
pub fn card<T>(mut self, value: T) -> Self
where
T: ::std::convert::TryInto<super::VettingCard>,
T::Error: ::std::fmt::Display,
{
self.card = value
.try_into()
.map_err(|e| format!("error converting supplied value for card: {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
}
}
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 {
card: value.card?,
ext: value.ext?,
})
}
}
impl ::std::convert::From<super::Response> for Response {
fn from(value: super::Response) -> Self {
Self {
card: Ok(value.card),
ext: Ok(value.ext),
}
}
}
#[derive(Clone, Debug)]
pub struct VettingCard {
audience: ::std::result::Result<super::VettingCardAudience, ::std::string::String>,
card_version: ::std::result::Result<::std::num::NonZeroU64, ::std::string::String>,
challenge: ::std::result::Result<super::VettingCardChallenge, ::std::string::String>,
claims:
::std::result::Result<::std::vec::Vec<super::VettingCardClaim>, ::std::string::String>,
commitment_salt:
::std::result::Result<super::VettingCardCommitmentSalt, ::std::string::String>,
community: ::std::result::Result<super::VettingCardCommunity, ::std::string::String>,
domain: ::std::result::Result<super::VettingCardDomain, ::std::string::String>,
expires_at:
::std::result::Result<::chrono::DateTime<::chrono::offset::Utc>, ::std::string::String>,
id: ::std::result::Result<super::VettingCardId, ::std::string::String>,
identity_commitment: ::std::result::Result<super::DigestMultibase, ::std::string::String>,
issued_at:
::std::result::Result<::chrono::DateTime<::chrono::offset::Utc>, ::std::string::String>,
proof: ::std::result::Result<super::DataIntegrityProof, ::std::string::String>,
publisher: ::std::result::Result<super::VettingCardPublisher, ::std::string::String>,
type_: ::std::result::Result<Vec<super::VettingCardTypeItem>, ::std::string::String>,
}
impl ::std::default::Default for VettingCard {
fn default() -> Self {
Self {
audience: Err("no value supplied for audience".to_string()),
card_version: Err("no value supplied for card_version".to_string()),
challenge: Err("no value supplied for challenge".to_string()),
claims: Err("no value supplied for claims".to_string()),
commitment_salt: Err("no value supplied for commitment_salt".to_string()),
community: Err("no value supplied for community".to_string()),
domain: Err("no value supplied for domain".to_string()),
expires_at: Err("no value supplied for expires_at".to_string()),
id: Err("no value supplied for id".to_string()),
identity_commitment: Err("no value supplied for identity_commitment".to_string()),
issued_at: Err("no value supplied for issued_at".to_string()),
proof: Err("no value supplied for proof".to_string()),
publisher: Err("no value supplied for publisher".to_string()),
type_: Err("no value supplied for type_".to_string()),
}
}
}
impl VettingCard {
pub fn audience<T>(mut self, value: T) -> Self
where
T: ::std::convert::TryInto<super::VettingCardAudience>,
T::Error: ::std::fmt::Display,
{
self.audience = value
.try_into()
.map_err(|e| format!("error converting supplied value for audience: {e}"));
self
}
pub fn card_version<T>(mut self, value: T) -> Self
where
T: ::std::convert::TryInto<::std::num::NonZeroU64>,
T::Error: ::std::fmt::Display,
{
self.card_version = value
.try_into()
.map_err(|e| format!("error converting supplied value for card_version: {e}"));
self
}
pub fn challenge<T>(mut self, value: T) -> Self
where
T: ::std::convert::TryInto<super::VettingCardChallenge>,
T::Error: ::std::fmt::Display,
{
self.challenge = value
.try_into()
.map_err(|e| format!("error converting supplied value for challenge: {e}"));
self
}
pub fn claims<T>(mut self, value: T) -> Self
where
T: ::std::convert::TryInto<::std::vec::Vec<super::VettingCardClaim>>,
T::Error: ::std::fmt::Display,
{
self.claims = value
.try_into()
.map_err(|e| format!("error converting supplied value for claims: {e}"));
self
}
pub fn commitment_salt<T>(mut self, value: T) -> Self
where
T: ::std::convert::TryInto<super::VettingCardCommitmentSalt>,
T::Error: ::std::fmt::Display,
{
self.commitment_salt = value
.try_into()
.map_err(|e| format!("error converting supplied value for commitment_salt: {e}"));
self
}
pub fn community<T>(mut self, value: T) -> Self
where
T: ::std::convert::TryInto<super::VettingCardCommunity>,
T::Error: ::std::fmt::Display,
{
self.community = value
.try_into()
.map_err(|e| format!("error converting supplied value for community: {e}"));
self
}
pub fn domain<T>(mut self, value: T) -> Self
where
T: ::std::convert::TryInto<super::VettingCardDomain>,
T::Error: ::std::fmt::Display,
{
self.domain = value
.try_into()
.map_err(|e| format!("error converting supplied value for domain: {e}"));
self
}
pub fn expires_at<T>(mut self, value: T) -> Self
where
T: ::std::convert::TryInto<::chrono::DateTime<::chrono::offset::Utc>>,
T::Error: ::std::fmt::Display,
{
self.expires_at = value
.try_into()
.map_err(|e| format!("error converting supplied value for expires_at: {e}"));
self
}
pub fn id<T>(mut self, value: T) -> Self
where
T: ::std::convert::TryInto<super::VettingCardId>,
T::Error: ::std::fmt::Display,
{
self.id = value
.try_into()
.map_err(|e| format!("error converting supplied value for id: {e}"));
self
}
pub fn identity_commitment<T>(mut self, value: T) -> Self
where
T: ::std::convert::TryInto<super::DigestMultibase>,
T::Error: ::std::fmt::Display,
{
self.identity_commitment = value.try_into().map_err(|e| {
format!("error converting supplied value for identity_commitment: {e}")
});
self
}
pub fn issued_at<T>(mut self, value: T) -> Self
where
T: ::std::convert::TryInto<::chrono::DateTime<::chrono::offset::Utc>>,
T::Error: ::std::fmt::Display,
{
self.issued_at = value
.try_into()
.map_err(|e| format!("error converting supplied value for issued_at: {e}"));
self
}
pub fn proof<T>(mut self, value: T) -> Self
where
T: ::std::convert::TryInto<super::DataIntegrityProof>,
T::Error: ::std::fmt::Display,
{
self.proof = value
.try_into()
.map_err(|e| format!("error converting supplied value for proof: {e}"));
self
}
pub fn publisher<T>(mut self, value: T) -> Self
where
T: ::std::convert::TryInto<super::VettingCardPublisher>,
T::Error: ::std::fmt::Display,
{
self.publisher = value
.try_into()
.map_err(|e| format!("error converting supplied value for publisher: {e}"));
self
}
pub fn type_<T>(mut self, value: T) -> Self
where
T: ::std::convert::TryInto<Vec<super::VettingCardTypeItem>>,
T::Error: ::std::fmt::Display,
{
self.type_ = value
.try_into()
.map_err(|e| format!("error converting supplied value for type_: {e}"));
self
}
}
impl ::std::convert::TryFrom<VettingCard> for super::VettingCard {
type Error = super::error::ConversionError;
fn try_from(
value: VettingCard,
) -> ::std::result::Result<Self, super::error::ConversionError> {
Ok(Self {
audience: value.audience?,
card_version: value.card_version?,
challenge: value.challenge?,
claims: value.claims?,
commitment_salt: value.commitment_salt?,
community: value.community?,
domain: value.domain?,
expires_at: value.expires_at?,
id: value.id?,
identity_commitment: value.identity_commitment?,
issued_at: value.issued_at?,
proof: value.proof?,
publisher: value.publisher?,
type_: value.type_?,
})
}
}
impl ::std::convert::From<super::VettingCard> for VettingCard {
fn from(value: super::VettingCard) -> Self {
Self {
audience: Ok(value.audience),
card_version: Ok(value.card_version),
challenge: Ok(value.challenge),
claims: Ok(value.claims),
commitment_salt: Ok(value.commitment_salt),
community: Ok(value.community),
domain: Ok(value.domain),
expires_at: Ok(value.expires_at),
id: Ok(value.id),
identity_commitment: Ok(value.identity_commitment),
issued_at: Ok(value.issued_at),
proof: Ok(value.proof),
publisher: Ok(value.publisher),
type_: Ok(value.type_),
}
}
}
#[derive(Clone, Debug)]
pub struct VettingCardClaim {
provenance: ::std::result::Result<super::VettingCardClaimProvenance, ::std::string::String>,
type_: ::std::result::Result<super::VettingCardClaimType, ::std::string::String>,
value: ::std::result::Result<::serde_json::Value, ::std::string::String>,
}
impl ::std::default::Default for VettingCardClaim {
fn default() -> Self {
Self {
provenance: Err("no value supplied for provenance".to_string()),
type_: Err("no value supplied for type_".to_string()),
value: Err("no value supplied for value".to_string()),
}
}
}
impl VettingCardClaim {
pub fn provenance<T>(mut self, value: T) -> Self
where
T: ::std::convert::TryInto<super::VettingCardClaimProvenance>,
T::Error: ::std::fmt::Display,
{
self.provenance = value
.try_into()
.map_err(|e| format!("error converting supplied value for provenance: {e}"));
self
}
pub fn type_<T>(mut self, value: T) -> Self
where
T: ::std::convert::TryInto<super::VettingCardClaimType>,
T::Error: ::std::fmt::Display,
{
self.type_ = value
.try_into()
.map_err(|e| format!("error converting supplied value for type_: {e}"));
self
}
pub fn value<T>(mut self, value: T) -> Self
where
T: ::std::convert::TryInto<::serde_json::Value>,
T::Error: ::std::fmt::Display,
{
self.value = value
.try_into()
.map_err(|e| format!("error converting supplied value for value: {e}"));
self
}
}
impl ::std::convert::TryFrom<VettingCardClaim> for super::VettingCardClaim {
type Error = super::error::ConversionError;
fn try_from(
value: VettingCardClaim,
) -> ::std::result::Result<Self, super::error::ConversionError> {
Ok(Self {
provenance: value.provenance?,
type_: value.type_?,
value: value.value?,
})
}
}
impl ::std::convert::From<super::VettingCardClaim> for VettingCardClaim {
fn from(value: super::VettingCardClaim) -> Self {
Self {
provenance: Ok(value.provenance),
type_: Ok(value.type_),
value: Ok(value.value),
}
}
}
}
impl crate::Payload for Payload {
const TYPE_URI: &'static str = "https://trusttasks.org/spec/vetting/session/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 \"ClaimType\": {\n \"description\": \"The vocabulary token naming what a value IS — `name.legal`, `phone.mobile`, `address.postal`, `person.birthDate`. Dotted, most-general segment first, so that a consumer with no knowledge of the specific token can still group by its prefix.\\n\\nThe token is the maintainer's own; no external vocabulary is primary. External vocabularies (vCard/jCard, OIDC standard claims, schema.org) are mappings applied at PRESENTATION by a renderer, not at rest, so that a query written in any of them can be matched without the store having to live inside any one of them.\\n\\nThe `x:` prefix is an open extension namespace and is not decoration. The closest prior art — Windows CardSpace's self-issued card — supported exactly fifteen predefined claim types with no extensibility, and that is the specific way it failed the requirement a holder actually has. An `x:` attribute stores, composes, binds and discloses exactly like a known one; it renders generically and matches only an explicit query.\",\n \"maxLength\": 128,\n \"minLength\": 1,\n \"pattern\": \"^(x:)?[a-z][a-zA-Z0-9]*(\\\\.[a-z][a-zA-Z0-9]*)*$\",\n \"title\": \"ClaimType\",\n \"type\": \"string\"\n },\n \"DataIntegrityProof\": {\n \"additionalProperties\": true,\n \"description\": \"A W3C Data Integrity proof by the card's publisher. Additional Data Integrity members (e.g. `created`) are permitted and are covered as the cryptosuite defines.\",\n \"properties\": {\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\": \"assertionMethod\",\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 `publisher`, authorized for `assertionMethod`.\",\n \"pattern\": \"^did:\",\n \"type\": \"string\"\n }\n },\n \"required\": [\n \"type\",\n \"cryptosuite\",\n \"verificationMethod\",\n \"proofPurpose\",\n \"proofValue\"\n ],\n \"title\": \"DataIntegrityProof\",\n \"type\": \"object\"\n },\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 \"Ext\": {\n \"additionalProperties\": true,\n \"description\": \"Vendor-namespaced extension object per SPEC.md §4.5.1. Each immediate key MUST be a reverse-DNS namespace; structure under each namespace is opaque to the framework.\",\n \"minProperties\": 1,\n \"propertyNames\": {\n \"pattern\": \"^[a-z][a-z0-9-]*(\\\\.[a-z0-9-]+)+$\"\n },\n \"title\": \"Ext\",\n \"type\": \"object\"\n },\n \"Response\": {\n \"$anchor\": \"response\",\n \"additionalProperties\": false,\n \"description\": \"The applicant's signed Vetting Card, bound to this session.\",\n \"properties\": {\n \"card\": {\n \"$ref\": \"#/$defs/VettingCard\"\n },\n \"ext\": {\n \"$ref\": \"#/$defs/Ext\"\n }\n },\n \"required\": [\n \"card\"\n ],\n \"title\": \"Vetting Session — response payload\",\n \"type\": \"object\"\n },\n \"VettingCard\": {\n \"additionalProperties\": false,\n \"properties\": {\n \"audience\": {\n \"description\": \"The vetter's DID — the issuer of the vetting session. A card addressed to anyone else is refused.\",\n \"pattern\": \"^did:\",\n \"type\": \"string\"\n },\n \"cardVersion\": {\n \"minimum\": 1,\n \"type\": \"integer\"\n },\n \"challenge\": {\n \"description\": \"The session's challenge, copied verbatim.\",\n \"pattern\": \"^[A-Za-z0-9_-]{43}$\",\n \"type\": \"string\"\n },\n \"claims\": {\n \"items\": {\n \"$ref\": \"#/$defs/VettingCardClaim\"\n },\n \"minItems\": 1,\n \"type\": \"array\"\n },\n \"commitmentSalt\": {\n \"description\": \"32 random bytes, base64url without padding, generated once per application. Goes to vetters inside the card and to nobody else: a party holding the commitment without the salt cannot test guesses at the claimed name.\",\n \"pattern\": \"^[A-Za-z0-9_-]{43}$\",\n \"type\": \"string\"\n },\n \"community\": {\n \"description\": \"The community the applicant is being vetted for.\",\n \"pattern\": \"^did:\",\n \"type\": \"string\"\n },\n \"domain\": {\n \"description\": \"The session's domain, copied verbatim.\",\n \"pattern\": \"^did:\",\n \"type\": \"string\"\n },\n \"expiresAt\": {\n \"description\": \"No later than the session's `expiresAt`.\",\n \"format\": \"date-time\",\n \"type\": \"string\"\n },\n \"id\": {\n \"description\": \"Fresh per card. A card is never re-sent to a second session under the same id.\",\n \"pattern\": \"^urn:uuid:[0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[0-9a-fA-F]{4}-[0-9a-fA-F]{4}-[0-9a-fA-F]{12}$\",\n \"type\": \"string\"\n },\n \"identityCommitment\": {\n \"$ref\": \"#/$defs/DigestMultibase\",\n \"description\": \"digestMultibase over the RFC 8785 canonicalization of `{ \\\"salt\\\": commitmentSalt, \\\"claims\\\": R }`, where R is `{ \\\"type\\\", \\\"value\\\" }` for every card claim whose type the session lists in `requiredClaims`, ordered by `type` then `value` (code-point order). SHA-256 RECOMMENDED. Because the applicant uses one salt per application, every vetter of that application sees the same value.\"\n },\n \"issuedAt\": {\n \"format\": \"date-time\",\n \"type\": \"string\"\n },\n \"proof\": {\n \"$ref\": \"#/$defs/DataIntegrityProof\"\n },\n \"publisher\": {\n \"description\": \"The applicant's DID — the issuer of the vetting request and the subject every resulting statement names. The card is signed with this DID's assertion key.\",\n \"pattern\": \"^did:\",\n \"type\": \"string\"\n },\n \"type\": {\n \"description\": \"Exactly `VerifiableDataStructure`, `RelationshipCard` and `VettingCard`, in any order.\",\n \"items\": {\n \"enum\": [\n \"VerifiableDataStructure\",\n \"RelationshipCard\",\n \"VettingCard\"\n ],\n \"type\": \"string\"\n },\n \"maxItems\": 3,\n \"minItems\": 3,\n \"type\": \"array\",\n \"uniqueItems\": true\n }\n },\n \"required\": [\n \"type\",\n \"id\",\n \"publisher\",\n \"cardVersion\",\n \"audience\",\n \"community\",\n \"challenge\",\n \"domain\",\n \"issuedAt\",\n \"expiresAt\",\n \"claims\",\n \"identityCommitment\",\n \"commitmentSalt\",\n \"proof\"\n ],\n \"title\": \"VettingCard\",\n \"type\": \"object\"\n },\n \"VettingCardClaim\": {\n \"additionalProperties\": false,\n \"properties\": {\n \"provenance\": {\n \"description\": \"Where the value's assurance comes from. `selfAsserted` — the applicant says so, and the vetter's human check is the only assurance added — is the only value this version defines; a verifier MUST NOT treat any other value as adding assurance it does not understand.\",\n \"maxLength\": 64,\n \"minLength\": 1,\n \"pattern\": \"^[a-z][a-zA-Z0-9]*$\",\n \"type\": \"string\"\n },\n \"type\": {\n \"$ref\": \"#/$defs/ClaimType\",\n \"description\": \"The claim type. `person.portrait` is refused: identity vetting works by a vetter looking at the person, not by transmitting their image.\",\n \"not\": {\n \"const\": \"person.portrait\"\n }\n },\n \"value\": {\n \"description\": \"The claimed value, exactly as rendered from the applicant's persona — a string for most claim types, structured JSON for some (e.g. a postal address). Authored by the applicant and asserted under their signature; the vetter's check is what gives it any assurance.\"\n }\n },\n \"required\": [\n \"type\",\n \"value\",\n \"provenance\"\n ],\n \"title\": \"VettingCardClaim\",\n \"type\": \"object\"\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/session/0.1\",\n \"$schema\": \"https://json-schema.org/draft/2020-12/schema\",\n \"additionalProperties\": false,\n \"description\": \"A vetter opens a vetting session with an applicant whose request it accepted, while the two are together in person or on a call. The request issues the session challenge and names the claims to present; the applicant's response is the signed Vetting Card. This document's `id` is the value the resulting Vetting Statement carries as `taskContext`, and its task digest is what binds the statement to it.\",\n \"properties\": {\n \"challenge\": {\n \"description\": \"32 fresh random bytes, base64url without padding. The card binds to it. Never reused across sessions.\",\n \"pattern\": \"^[A-Za-z0-9_-]{43}$\",\n \"type\": \"string\"\n },\n \"domain\": {\n \"description\": \"The community DID the applicant is being vetted for. The card binds to it alongside `challenge`.\",\n \"pattern\": \"^did:\",\n \"type\": \"string\"\n },\n \"expiresAt\": {\n \"description\": \"When the session lapses: no card is accepted for it afterwards, and the card's own `expiresAt` may not be later.\",\n \"format\": \"date-time\",\n \"type\": \"string\"\n },\n \"ext\": {\n \"$ref\": \"#/$defs/Ext\"\n },\n \"method\": {\n \"$ref\": \"#/$defs/VettingMethod\",\n \"description\": \"How this session is conducted.\"\n },\n \"optionalClaims\": {\n \"description\": \"Claim types the applicant may add. Never part of the commitment.\",\n \"items\": {\n \"$ref\": \"#/$defs/ClaimType\",\n \"not\": {\n \"const\": \"person.portrait\"\n }\n },\n \"type\": \"array\",\n \"uniqueItems\": true\n },\n \"requestId\": {\n \"description\": \"The `requestId` from the vetter's acceptance of the applicant's vetting request.\",\n \"maxLength\": 128,\n \"minLength\": 1,\n \"type\": \"string\"\n },\n \"requiredClaims\": {\n \"description\": \"Claim types the card must carry. The community criterion's `requiredClaims`; the identity commitment is computed over exactly these.\",\n \"items\": {\n \"$ref\": \"#/$defs/ClaimType\",\n \"not\": {\n \"const\": \"person.portrait\"\n }\n },\n \"type\": \"array\",\n \"uniqueItems\": true\n }\n },\n \"required\": [\n \"requestId\",\n \"challenge\",\n \"domain\",\n \"method\",\n \"requiredClaims\",\n \"expiresAt\"\n ],\n \"title\": \"Vetting Session — payload\",\n \"type\": \"object\"\n}\n",
);
}
impl crate::Payload for Response {
const TYPE_URI: &'static str = "https://trusttasks.org/spec/vetting/session/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 \"ClaimType\": {\n \"description\": \"The vocabulary token naming what a value IS — `name.legal`, `phone.mobile`, `address.postal`, `person.birthDate`. Dotted, most-general segment first, so that a consumer with no knowledge of the specific token can still group by its prefix.\\n\\nThe token is the maintainer's own; no external vocabulary is primary. External vocabularies (vCard/jCard, OIDC standard claims, schema.org) are mappings applied at PRESENTATION by a renderer, not at rest, so that a query written in any of them can be matched without the store having to live inside any one of them.\\n\\nThe `x:` prefix is an open extension namespace and is not decoration. The closest prior art — Windows CardSpace's self-issued card — supported exactly fifteen predefined claim types with no extensibility, and that is the specific way it failed the requirement a holder actually has. An `x:` attribute stores, composes, binds and discloses exactly like a known one; it renders generically and matches only an explicit query.\",\n \"maxLength\": 128,\n \"minLength\": 1,\n \"pattern\": \"^(x:)?[a-z][a-zA-Z0-9]*(\\\\.[a-z][a-zA-Z0-9]*)*$\",\n \"title\": \"ClaimType\",\n \"type\": \"string\"\n },\n \"DataIntegrityProof\": {\n \"additionalProperties\": true,\n \"description\": \"A W3C Data Integrity proof by the card's publisher. Additional Data Integrity members (e.g. `created`) are permitted and are covered as the cryptosuite defines.\",\n \"properties\": {\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\": \"assertionMethod\",\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 `publisher`, authorized for `assertionMethod`.\",\n \"pattern\": \"^did:\",\n \"type\": \"string\"\n }\n },\n \"required\": [\n \"type\",\n \"cryptosuite\",\n \"verificationMethod\",\n \"proofPurpose\",\n \"proofValue\"\n ],\n \"title\": \"DataIntegrityProof\",\n \"type\": \"object\"\n },\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 \"Ext\": {\n \"additionalProperties\": true,\n \"description\": \"Vendor-namespaced extension object per SPEC.md §4.5.1. Each immediate key MUST be a reverse-DNS namespace; structure under each namespace is opaque to the framework.\",\n \"minProperties\": 1,\n \"propertyNames\": {\n \"pattern\": \"^[a-z][a-z0-9-]*(\\\\.[a-z0-9-]+)+$\"\n },\n \"title\": \"Ext\",\n \"type\": \"object\"\n },\n \"Response\": {\n \"$anchor\": \"response\",\n \"additionalProperties\": false,\n \"description\": \"The applicant's signed Vetting Card, bound to this session.\",\n \"properties\": {\n \"card\": {\n \"$ref\": \"#/$defs/VettingCard\"\n },\n \"ext\": {\n \"$ref\": \"#/$defs/Ext\"\n }\n },\n \"required\": [\n \"card\"\n ],\n \"title\": \"Vetting Session — response payload\",\n \"type\": \"object\"\n },\n \"VettingCard\": {\n \"additionalProperties\": false,\n \"properties\": {\n \"audience\": {\n \"description\": \"The vetter's DID — the issuer of the vetting session. A card addressed to anyone else is refused.\",\n \"pattern\": \"^did:\",\n \"type\": \"string\"\n },\n \"cardVersion\": {\n \"minimum\": 1,\n \"type\": \"integer\"\n },\n \"challenge\": {\n \"description\": \"The session's challenge, copied verbatim.\",\n \"pattern\": \"^[A-Za-z0-9_-]{43}$\",\n \"type\": \"string\"\n },\n \"claims\": {\n \"items\": {\n \"$ref\": \"#/$defs/VettingCardClaim\"\n },\n \"minItems\": 1,\n \"type\": \"array\"\n },\n \"commitmentSalt\": {\n \"description\": \"32 random bytes, base64url without padding, generated once per application. Goes to vetters inside the card and to nobody else: a party holding the commitment without the salt cannot test guesses at the claimed name.\",\n \"pattern\": \"^[A-Za-z0-9_-]{43}$\",\n \"type\": \"string\"\n },\n \"community\": {\n \"description\": \"The community the applicant is being vetted for.\",\n \"pattern\": \"^did:\",\n \"type\": \"string\"\n },\n \"domain\": {\n \"description\": \"The session's domain, copied verbatim.\",\n \"pattern\": \"^did:\",\n \"type\": \"string\"\n },\n \"expiresAt\": {\n \"description\": \"No later than the session's `expiresAt`.\",\n \"format\": \"date-time\",\n \"type\": \"string\"\n },\n \"id\": {\n \"description\": \"Fresh per card. A card is never re-sent to a second session under the same id.\",\n \"pattern\": \"^urn:uuid:[0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[0-9a-fA-F]{4}-[0-9a-fA-F]{4}-[0-9a-fA-F]{12}$\",\n \"type\": \"string\"\n },\n \"identityCommitment\": {\n \"$ref\": \"#/$defs/DigestMultibase\",\n \"description\": \"digestMultibase over the RFC 8785 canonicalization of `{ \\\"salt\\\": commitmentSalt, \\\"claims\\\": R }`, where R is `{ \\\"type\\\", \\\"value\\\" }` for every card claim whose type the session lists in `requiredClaims`, ordered by `type` then `value` (code-point order). SHA-256 RECOMMENDED. Because the applicant uses one salt per application, every vetter of that application sees the same value.\"\n },\n \"issuedAt\": {\n \"format\": \"date-time\",\n \"type\": \"string\"\n },\n \"proof\": {\n \"$ref\": \"#/$defs/DataIntegrityProof\"\n },\n \"publisher\": {\n \"description\": \"The applicant's DID — the issuer of the vetting request and the subject every resulting statement names. The card is signed with this DID's assertion key.\",\n \"pattern\": \"^did:\",\n \"type\": \"string\"\n },\n \"type\": {\n \"description\": \"Exactly `VerifiableDataStructure`, `RelationshipCard` and `VettingCard`, in any order.\",\n \"items\": {\n \"enum\": [\n \"VerifiableDataStructure\",\n \"RelationshipCard\",\n \"VettingCard\"\n ],\n \"type\": \"string\"\n },\n \"maxItems\": 3,\n \"minItems\": 3,\n \"type\": \"array\",\n \"uniqueItems\": true\n }\n },\n \"required\": [\n \"type\",\n \"id\",\n \"publisher\",\n \"cardVersion\",\n \"audience\",\n \"community\",\n \"challenge\",\n \"domain\",\n \"issuedAt\",\n \"expiresAt\",\n \"claims\",\n \"identityCommitment\",\n \"commitmentSalt\",\n \"proof\"\n ],\n \"title\": \"VettingCard\",\n \"type\": \"object\"\n },\n \"VettingCardClaim\": {\n \"additionalProperties\": false,\n \"properties\": {\n \"provenance\": {\n \"description\": \"Where the value's assurance comes from. `selfAsserted` — the applicant says so, and the vetter's human check is the only assurance added — is the only value this version defines; a verifier MUST NOT treat any other value as adding assurance it does not understand.\",\n \"maxLength\": 64,\n \"minLength\": 1,\n \"pattern\": \"^[a-z][a-zA-Z0-9]*$\",\n \"type\": \"string\"\n },\n \"type\": {\n \"$ref\": \"#/$defs/ClaimType\",\n \"description\": \"The claim type. `person.portrait` is refused: identity vetting works by a vetter looking at the person, not by transmitting their image.\",\n \"not\": {\n \"const\": \"person.portrait\"\n }\n },\n \"value\": {\n \"description\": \"The claimed value, exactly as rendered from the applicant's persona — a string for most claim types, structured JSON for some (e.g. a postal address). Authored by the applicant and asserted under their signature; the vetter's check is what gives it any assurance.\"\n }\n },\n \"required\": [\n \"type\",\n \"value\",\n \"provenance\"\n ],\n \"title\": \"VettingCardClaim\",\n \"type\": \"object\"\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:9a7e4c21-5b3d-4e8f-a1c2-3d4e5f6a7b01\",\n \"type\": \"https://trusttasks.org/spec/vetting/session/0.1\",\n \"threadId\": \"urn:uuid:9a7e4c21-5b3d-4e8f-a1c2-3d4e5f6a7b01\",\n \"parentThreadId\": \"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-17T15:02:00Z\",\n \"payload\": {\n \"requestId\": \"urn:uuid:4b2e8f10-7a6c-4d3b-9e21-0f5a6b7c8d01\",\n \"challenge\": \"Xq3v9bT0cN2mR8sLk4Jw7pYh1eZa6uGd5fQi0oVxWnE\",\n \"domain\": \"did:webvh:QmVtcScid:kernel-vtc.example\",\n \"method\": \"video\",\n \"requiredClaims\": [\"name.legal\"],\n \"optionalClaims\": [\"account.handle\"],\n \"expiresAt\": \"2026-09-17T15:17:00Z\"\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-17T15:02:00Z\",\n \"proofPurpose\": \"assertionMethod\",\n \"proofValue\": \"z63jiSzsVJshBfyZwcr6nUopHo5M1QnBnWJHtwTpdNEFeD7KoX5rezJcGeoY8AVuTSo5Q3uH2KqMoEZk68qqGu3AR\"\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:9a7e4c21-5b3d-4e8f-a1c2-3d4e5f6a7b02\",\n \"type\": \"https://trusttasks.org/spec/vetting/session/0.1#response\",\n \"threadId\": \"urn:uuid:9a7e4c21-5b3d-4e8f-a1c2-3d4e5f6a7b01\",\n \"parentThreadId\": \"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-17T15:04:06Z\",\n \"payload\": {\n \"card\": {\n \"type\": [\"VerifiableDataStructure\", \"RelationshipCard\", \"VettingCard\"],\n \"id\": \"urn:uuid:d2c4e6f8-1a3b-4c5d-8e7f-9a0b1c2d3e01\",\n \"publisher\": \"did:webvh:QmAliceScid1:alice.example\",\n \"cardVersion\": 1,\n \"audience\": \"did:webvh:QmCarolScid1:kernel-vtc.example:carol\",\n \"community\": \"did:webvh:QmVtcScid:kernel-vtc.example\",\n \"challenge\": \"Xq3v9bT0cN2mR8sLk4Jw7pYh1eZa6uGd5fQi0oVxWnE\",\n \"domain\": \"did:webvh:QmVtcScid:kernel-vtc.example\",\n \"issuedAt\": \"2026-09-17T15:04:05Z\",\n \"expiresAt\": \"2026-09-17T15:17:00Z\",\n \"claims\": [\n { \"type\": \"name.legal\", \"value\": \"Alice Example\", \"provenance\": \"selfAsserted\" },\n { \"type\": \"account.handle\", \"value\": \"alice@example.org\", \"provenance\": \"selfAsserted\" }\n ],\n \"identityCommitment\": \"zQmT7GFcSjCY7YwuK5RP3TNNF8wp7fnCfMMYjMeatbbWo7b\",\n \"commitmentSalt\": \"mT7rK2pWq9Zc4Vb8Nx1Ls6Hd3Fg0Jy5Ra7Ue2Io4PkA\",\n \"proof\": {\n \"type\": \"DataIntegrityProof\",\n \"cryptosuite\": \"eddsa-jcs-2022\",\n \"verificationMethod\": \"did:webvh:QmAliceScid1:alice.example#key-1\",\n \"proofPurpose\": \"assertionMethod\",\n \"proofValue\": \"z46F4qaaxCkXUkQQMGK1gk1efa54xT3GDw9GByQu4cHZmr86Vw1frjBcGALCAQjPTua6J3YtcQQbgDFCuJnhczu3F\"\n }\n }\n },\n \"proof\": {\n \"type\": \"DataIntegrityProof\",\n \"cryptosuite\": \"eddsa-jcs-2022\",\n \"verificationMethod\": \"did:webvh:QmAliceScid1:alice.example#key-1\",\n \"created\": \"2026-09-17T15:04:06Z\",\n \"proofPurpose\": \"assertionMethod\",\n \"proofValue\": \"zuoTZbVpBUvRSPXq7An9rfxFFqnbWLSGZbLpkF3utZnGwyk6yNDqmuUQX2qQdre7PBBpHMWoatui2Y41nMCwuUqM\"\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)] = &[
(
"A session with no challenge gives the card nothing to bind to, so a card could be replayed into it from any other session.",
"{\n \"domain\": \"did:webvh:QmVtcScid:kernel-vtc.example\",\n \"expiresAt\": \"2026-09-17T15:17:00Z\",\n \"method\": \"video\",\n \"requestId\": \"urn:uuid:4b2e8f10-7a6c-4d3b-9e21-0f5a6b7c8d01\",\n \"requiredClaims\": [\n \"name.legal\"\n ]\n}",
),
(
"The challenge is 32 random bytes. A short value is guessable, and a card bound to a guessable challenge can be pre-computed.",
"{\n \"challenge\": \"abc123\",\n \"domain\": \"did:webvh:QmVtcScid:kernel-vtc.example\",\n \"expiresAt\": \"2026-09-17T15:17:00Z\",\n \"method\": \"video\",\n \"requestId\": \"urn:uuid:4b2e8f10-7a6c-4d3b-9e21-0f5a6b7c8d01\",\n \"requiredClaims\": [\n \"name.legal\"\n ]\n}",
),
(
"`domain` is the community DID the applicant is being vetted for, not a host name.",
"{\n \"challenge\": \"Xq3v9bT0cN2mR8sLk4Jw7pYh1eZa6uGd5fQi0oVxWnE\",\n \"domain\": \"kernel-vtc.example\",\n \"expiresAt\": \"2026-09-17T15:17:00Z\",\n \"method\": \"video\",\n \"requestId\": \"urn:uuid:4b2e8f10-7a6c-4d3b-9e21-0f5a6b7c8d01\",\n \"requiredClaims\": [\n \"name.legal\"\n ]\n}",
),
(
"A portrait is never requested. Vetting works by looking at the person, not by transmitting their image.",
"{\n \"challenge\": \"Xq3v9bT0cN2mR8sLk4Jw7pYh1eZa6uGd5fQi0oVxWnE\",\n \"domain\": \"did:webvh:QmVtcScid:kernel-vtc.example\",\n \"expiresAt\": \"2026-09-17T15:17:00Z\",\n \"method\": \"video\",\n \"requestId\": \"urn:uuid:4b2e8f10-7a6c-4d3b-9e21-0f5a6b7c8d01\",\n \"requiredClaims\": [\n \"name.legal\",\n \"person.portrait\"\n ]\n}",
),
(
"A session always lapses. Without `expiresAt` a card could be demanded for an old session long after the people left the call.",
"{\n \"challenge\": \"Xq3v9bT0cN2mR8sLk4Jw7pYh1eZa6uGd5fQi0oVxWnE\",\n \"domain\": \"did:webvh:QmVtcScid:kernel-vtc.example\",\n \"method\": \"video\",\n \"requestId\": \"urn:uuid:4b2e8f10-7a6c-4d3b-9e21-0f5a6b7c8d01\",\n \"requiredClaims\": [\n \"name.legal\"\n ]\n}",
),
(
"The session does not ask for documentation details. What a vetter looks at stays in the room; a `documentNumber` request member would move it onto the wire.",
"{\n \"challenge\": \"Xq3v9bT0cN2mR8sLk4Jw7pYh1eZa6uGd5fQi0oVxWnE\",\n \"documentNumber\": true,\n \"domain\": \"did:webvh:QmVtcScid:kernel-vtc.example\",\n \"expiresAt\": \"2026-09-17T15:17:00Z\",\n \"method\": \"video\",\n \"requestId\": \"urn:uuid:4b2e8f10-7a6c-4d3b-9e21-0f5a6b7c8d01\",\n \"requiredClaims\": [\n \"name.legal\"\n ]\n}",
),
(
"Methods are lowerCamelCase (SPEC §4.10): `priorAcquaintance`, not `prior-acquaintance`.",
"{\n \"challenge\": \"Xq3v9bT0cN2mR8sLk4Jw7pYh1eZa6uGd5fQi0oVxWnE\",\n \"domain\": \"did:webvh:QmVtcScid:kernel-vtc.example\",\n \"expiresAt\": \"2026-09-17T15:17:00Z\",\n \"method\": \"prior-acquaintance\",\n \"requestId\": \"urn:uuid:4b2e8f10-7a6c-4d3b-9e21-0f5a6b7c8d01\",\n \"requiredClaims\": [\n \"name.legal\"\n ]\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
);
}
}
}