//! Generated by `trust-tasks-codegen` — do not edit by hand.
//!
//! Spec slug: `vtc/install/claim/start`. Version: `0.3`.
#[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())
}
}
}
///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())
})
}
}
///Begin claiming a fresh community under a DID the founder already controls: exchange the install token and its claim code for a challenge the founder's step-up approver will sign. The outer document members (id, type, issuer, recipient, issuedAt, expiresAt, proof) are owned by the framework — SPEC §6.3.
///
/// <details><summary>JSON schema</summary>
///
/// ```json
///{
/// "$id": "https://trusttasks.org/spec/vtc/install/claim/start/0.3",
/// "title": "Payload",
/// "description": "Begin claiming a fresh community under a DID the founder already controls: exchange the install token and its claim code for a challenge the founder's step-up approver will sign. The outer document members (id, type, issuer, recipient, issuedAt, expiresAt, proof) are owned by the framework — SPEC §6.3.",
/// "type": "object",
/// "required": [
/// "claimCode",
/// "token"
/// ],
/// "properties": {
/// "claimCode": {
/// "description": "The claim code the operator received out of band, through a different channel from the install URL. Required in 0.3. Compared with its stored hash; never logged.",
/// "type": "string",
/// "maxLength": 64,
/// "minLength": 1
/// },
/// "ext": {
/// "$ref": "#/definitions/Ext"
/// },
/// "token": {
/// "description": "The EdDSA-signed install JWT (aud=vtc-install) printed by vtc setup. In 0.3 it names the founder's DID.",
/// "type": "string",
/// "maxLength": 4096,
/// "minLength": 16
/// }
/// },
/// "additionalProperties": false
///}
/// ```
/// </details>
#[derive(::serde::Deserialize, ::serde::Serialize, Clone, Debug)]
#[serde(deny_unknown_fields)]
#[non_exhaustive]
pub struct Payload {
///The claim code the operator received out of band, through a different channel from the install URL. Required in 0.3. Compared with its stored hash; never logged.
#[serde(rename = "claimCode")]
pub claim_code: PayloadClaimCode,
#[serde(default, skip_serializing_if = "::std::option::Option::is_none")]
pub ext: ::std::option::Option<Ext>,
///The EdDSA-signed install JWT (aud=vtc-install) printed by vtc setup. In 0.3 it names the founder's DID.
pub token: PayloadToken,
}
impl Payload {
pub fn builder() -> builder::Payload {
Default::default()
}
}
///The claim code the operator received out of band, through a different channel from the install URL. Required in 0.3. Compared with its stored hash; never logged.
///
/// <details><summary>JSON schema</summary>
///
/// ```json
///{
/// "description": "The claim code the operator received out of band, through a different channel from the install URL. Required in 0.3. Compared with its stored hash; never logged.",
/// "type": "string",
/// "maxLength": 64,
/// "minLength": 1
///}
/// ```
/// </details>
#[derive(::serde::Serialize, Clone, Debug, Eq, Hash, Ord, PartialEq, PartialOrd)]
#[serde(transparent)]
pub struct PayloadClaimCode(::std::string::String);
impl ::std::ops::Deref for PayloadClaimCode {
type Target = ::std::string::String;
fn deref(&self) -> &::std::string::String {
&self.0
}
}
impl ::std::convert::From<PayloadClaimCode> for ::std::string::String {
fn from(value: PayloadClaimCode) -> Self {
value.0
}
}
impl ::std::str::FromStr for PayloadClaimCode {
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());
}
Ok(Self(value.to_string()))
}
}
impl ::std::convert::TryFrom<&str> for PayloadClaimCode {
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 PayloadClaimCode {
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 PayloadClaimCode {
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 PayloadClaimCode {
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 EdDSA-signed install JWT (aud=vtc-install) printed by vtc setup. In 0.3 it names the founder's DID.
///
/// <details><summary>JSON schema</summary>
///
/// ```json
///{
/// "description": "The EdDSA-signed install JWT (aud=vtc-install) printed by vtc setup. In 0.3 it names the founder's DID.",
/// "type": "string",
/// "maxLength": 4096,
/// "minLength": 16
///}
/// ```
/// </details>
#[derive(::serde::Serialize, Clone, Debug, Eq, Hash, Ord, PartialEq, PartialOrd)]
#[serde(transparent)]
pub struct PayloadToken(::std::string::String);
impl ::std::ops::Deref for PayloadToken {
type Target = ::std::string::String;
fn deref(&self) -> &::std::string::String {
&self.0
}
}
impl ::std::convert::From<PayloadToken> for ::std::string::String {
fn from(value: PayloadToken) -> Self {
value.0
}
}
impl ::std::str::FromStr for PayloadToken {
type Err = self::error::ConversionError;
fn from_str(value: &str) -> ::std::result::Result<Self, self::error::ConversionError> {
if value.chars().count() > 4096usize {
return Err("longer than 4096 characters".into());
}
if value.chars().count() < 16usize {
return Err("shorter than 16 characters".into());
}
Ok(Self(value.to_string()))
}
}
impl ::std::convert::TryFrom<&str> for PayloadToken {
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 PayloadToken {
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 PayloadToken {
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 PayloadToken {
fn deserialize<D>(deserializer: D) -> ::std::result::Result<Self, D::Error>
where
D: ::serde::Deserializer<'de>,
{
::std::string::String::deserialize(deserializer)?
.parse()
.map_err(|e: self::error::ConversionError| {
<D::Error as ::serde::de::Error>::custom(e.to_string())
})
}
}
///`Response`
///
/// <details><summary>JSON schema</summary>
///
/// ```json
///{
/// "title": "Response",
/// "type": "object",
/// "required": [
/// "adminDid",
/// "audience",
/// "challenge",
/// "claimId",
/// "expiresAt"
/// ],
/// "properties": {
/// "adminDid": {
/// "description": "The DID the install token names — the DID that must sign claim/finish and that becomes the first administrator. Returned so the installer need not decode the token.",
/// "type": "string",
/// "maxLength": 2048,
/// "minLength": 5,
/// "pattern": "^did:"
/// },
/// "audience": {
/// "description": "The community's DID, which the statement names as its `audience` and `recipient`, and to which claim/finish is addressed.",
/// "type": "string",
/// "maxLength": 2048,
/// "minLength": 5,
/// "pattern": "^did:"
/// },
/// "challenge": {
/// "description": "A fresh challenge (≥128 bits) the founder's step-up approver signs over in its auth/step-up/approver/attest/0.1 statement with `purpose: enrol`.",
/// "type": "string",
/// "maxLength": 512,
/// "minLength": 16
/// },
/// "claimId": {
/// "description": "Opaque, single-use handle for this claim. Echoed in claim/finish, and the `boundTo` of the approver's enrolment statement.",
/// "type": "string",
/// "maxLength": 256,
/// "minLength": 1
/// },
/// "expiresAt": {
/// "description": "When this claim ceremony lapses (not the install token).",
/// "type": "string",
/// "format": "date-time"
/// },
/// "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 {
///The DID the install token names — the DID that must sign claim/finish and that becomes the first administrator. Returned so the installer need not decode the token.
#[serde(rename = "adminDid")]
pub admin_did: ResponseAdminDid,
///The community's DID, which the statement names as its `audience` and `recipient`, and to which claim/finish is addressed.
pub audience: ResponseAudience,
///A fresh challenge (≥128 bits) the founder's step-up approver signs over in its auth/step-up/approver/attest/0.1 statement with `purpose: enrol`.
pub challenge: ResponseChallenge,
///Opaque, single-use handle for this claim. Echoed in claim/finish, and the `boundTo` of the approver's enrolment statement.
#[serde(rename = "claimId")]
pub claim_id: ResponseClaimId,
///When this claim ceremony lapses (not the install token).
#[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>,
}
impl Response {
pub fn builder() -> builder::Response {
Default::default()
}
}
///The DID the install token names — the DID that must sign claim/finish and that becomes the first administrator. Returned so the installer need not decode the token.
///
/// <details><summary>JSON schema</summary>
///
/// ```json
///{
/// "description": "The DID the install token names — the DID that must sign claim/finish and that becomes the first administrator. Returned so the installer need not decode the token.",
/// "type": "string",
/// "maxLength": 2048,
/// "minLength": 5,
/// "pattern": "^did:"
///}
/// ```
/// </details>
#[derive(::serde::Serialize, Clone, Debug, Eq, Hash, Ord, PartialEq, PartialOrd)]
#[serde(transparent)]
pub struct ResponseAdminDid(::std::string::String);
impl ::std::ops::Deref for ResponseAdminDid {
type Target = ::std::string::String;
fn deref(&self) -> &::std::string::String {
&self.0
}
}
impl ::std::convert::From<ResponseAdminDid> for ::std::string::String {
fn from(value: ResponseAdminDid) -> Self {
value.0
}
}
impl ::std::str::FromStr for ResponseAdminDid {
type Err = self::error::ConversionError;
fn from_str(value: &str) -> ::std::result::Result<Self, self::error::ConversionError> {
if value.chars().count() > 2048usize {
return Err("longer than 2048 characters".into());
}
if value.chars().count() < 5usize {
return Err("shorter than 5 characters".into());
}
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 ResponseAdminDid {
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 ResponseAdminDid {
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 ResponseAdminDid {
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 ResponseAdminDid {
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's DID, which the statement names as its `audience` and `recipient`, and to which claim/finish is addressed.
///
/// <details><summary>JSON schema</summary>
///
/// ```json
///{
/// "description": "The community's DID, which the statement names as its `audience` and `recipient`, and to which claim/finish is addressed.",
/// "type": "string",
/// "maxLength": 2048,
/// "minLength": 5,
/// "pattern": "^did:"
///}
/// ```
/// </details>
#[derive(::serde::Serialize, Clone, Debug, Eq, Hash, Ord, PartialEq, PartialOrd)]
#[serde(transparent)]
pub struct ResponseAudience(::std::string::String);
impl ::std::ops::Deref for ResponseAudience {
type Target = ::std::string::String;
fn deref(&self) -> &::std::string::String {
&self.0
}
}
impl ::std::convert::From<ResponseAudience> for ::std::string::String {
fn from(value: ResponseAudience) -> Self {
value.0
}
}
impl ::std::str::FromStr for ResponseAudience {
type Err = self::error::ConversionError;
fn from_str(value: &str) -> ::std::result::Result<Self, self::error::ConversionError> {
if value.chars().count() > 2048usize {
return Err("longer than 2048 characters".into());
}
if value.chars().count() < 5usize {
return Err("shorter than 5 characters".into());
}
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 ResponseAudience {
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 ResponseAudience {
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 ResponseAudience {
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 ResponseAudience {
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 fresh challenge (≥128 bits) the founder's step-up approver signs over in its auth/step-up/approver/attest/0.1 statement with `purpose: enrol`.
///
/// <details><summary>JSON schema</summary>
///
/// ```json
///{
/// "description": "A fresh challenge (≥128 bits) the founder's step-up approver signs over in its auth/step-up/approver/attest/0.1 statement with `purpose: enrol`.",
/// "type": "string",
/// "maxLength": 512,
/// "minLength": 16
///}
/// ```
/// </details>
#[derive(::serde::Serialize, Clone, Debug, Eq, Hash, Ord, PartialEq, PartialOrd)]
#[serde(transparent)]
pub struct ResponseChallenge(::std::string::String);
impl ::std::ops::Deref for ResponseChallenge {
type Target = ::std::string::String;
fn deref(&self) -> &::std::string::String {
&self.0
}
}
impl ::std::convert::From<ResponseChallenge> for ::std::string::String {
fn from(value: ResponseChallenge) -> Self {
value.0
}
}
impl ::std::str::FromStr for ResponseChallenge {
type Err = self::error::ConversionError;
fn from_str(value: &str) -> ::std::result::Result<Self, self::error::ConversionError> {
if value.chars().count() > 512usize {
return Err("longer than 512 characters".into());
}
if value.chars().count() < 16usize {
return Err("shorter than 16 characters".into());
}
Ok(Self(value.to_string()))
}
}
impl ::std::convert::TryFrom<&str> for ResponseChallenge {
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 ResponseChallenge {
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 ResponseChallenge {
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 ResponseChallenge {
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())
})
}
}
///Opaque, single-use handle for this claim. Echoed in claim/finish, and the `boundTo` of the approver's enrolment statement.
///
/// <details><summary>JSON schema</summary>
///
/// ```json
///{
/// "description": "Opaque, single-use handle for this claim. Echoed in claim/finish, and the `boundTo` of the approver's enrolment statement.",
/// "type": "string",
/// "maxLength": 256,
/// "minLength": 1
///}
/// ```
/// </details>
#[derive(::serde::Serialize, Clone, Debug, Eq, Hash, Ord, PartialEq, PartialOrd)]
#[serde(transparent)]
pub struct ResponseClaimId(::std::string::String);
impl ::std::ops::Deref for ResponseClaimId {
type Target = ::std::string::String;
fn deref(&self) -> &::std::string::String {
&self.0
}
}
impl ::std::convert::From<ResponseClaimId> for ::std::string::String {
fn from(value: ResponseClaimId) -> Self {
value.0
}
}
impl ::std::str::FromStr for ResponseClaimId {
type Err = self::error::ConversionError;
fn from_str(value: &str) -> ::std::result::Result<Self, self::error::ConversionError> {
if value.chars().count() > 256usize {
return Err("longer than 256 characters".into());
}
if value.chars().count() < 1usize {
return Err("shorter than 1 characters".into());
}
Ok(Self(value.to_string()))
}
}
impl ::std::convert::TryFrom<&str> for ResponseClaimId {
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 ResponseClaimId {
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 ResponseClaimId {
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 ResponseClaimId {
fn deserialize<D>(deserializer: D) -> ::std::result::Result<Self, D::Error>
where
D: ::serde::Deserializer<'de>,
{
::std::string::String::deserialize(deserializer)?
.parse()
.map_err(|e: self::error::ConversionError| {
<D::Error as ::serde::de::Error>::custom(e.to_string())
})
}
}
/// Types for composing complex structures.
pub mod builder {
#[derive(Clone, Debug)]
pub struct Payload {
claim_code: ::std::result::Result<super::PayloadClaimCode, ::std::string::String>,
ext: ::std::result::Result<::std::option::Option<super::Ext>, ::std::string::String>,
token: ::std::result::Result<super::PayloadToken, ::std::string::String>,
}
impl ::std::default::Default for Payload {
fn default() -> Self {
Self {
claim_code: Err("no value supplied for claim_code".to_string()),
ext: Ok(Default::default()),
token: Err("no value supplied for token".to_string()),
}
}
}
impl Payload {
pub fn claim_code<T>(mut self, value: T) -> Self
where
T: ::std::convert::TryInto<super::PayloadClaimCode>,
T::Error: ::std::fmt::Display,
{
self.claim_code = value
.try_into()
.map_err(|e| format!("error converting supplied value for claim_code: {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 token<T>(mut self, value: T) -> Self
where
T: ::std::convert::TryInto<super::PayloadToken>,
T::Error: ::std::fmt::Display,
{
self.token = value
.try_into()
.map_err(|e| format!("error converting supplied value for token: {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 {
claim_code: value.claim_code?,
ext: value.ext?,
token: value.token?,
})
}
}
impl ::std::convert::From<super::Payload> for Payload {
fn from(value: super::Payload) -> Self {
Self {
claim_code: Ok(value.claim_code),
ext: Ok(value.ext),
token: Ok(value.token),
}
}
}
#[derive(Clone, Debug)]
pub struct Response {
admin_did: ::std::result::Result<super::ResponseAdminDid, ::std::string::String>,
audience: ::std::result::Result<super::ResponseAudience, ::std::string::String>,
challenge: ::std::result::Result<super::ResponseChallenge, ::std::string::String>,
claim_id: ::std::result::Result<super::ResponseClaimId, ::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>,
}
impl ::std::default::Default for Response {
fn default() -> Self {
Self {
admin_did: Err("no value supplied for admin_did".to_string()),
audience: Err("no value supplied for audience".to_string()),
challenge: Err("no value supplied for challenge".to_string()),
claim_id: Err("no value supplied for claim_id".to_string()),
expires_at: Err("no value supplied for expires_at".to_string()),
ext: Ok(Default::default()),
}
}
}
impl Response {
pub fn admin_did<T>(mut self, value: T) -> Self
where
T: ::std::convert::TryInto<super::ResponseAdminDid>,
T::Error: ::std::fmt::Display,
{
self.admin_did = value
.try_into()
.map_err(|e| format!("error converting supplied value for admin_did: {e}"));
self
}
pub fn audience<T>(mut self, value: T) -> Self
where
T: ::std::convert::TryInto<super::ResponseAudience>,
T::Error: ::std::fmt::Display,
{
self.audience = value
.try_into()
.map_err(|e| format!("error converting supplied value for audience: {e}"));
self
}
pub fn challenge<T>(mut self, value: T) -> Self
where
T: ::std::convert::TryInto<super::ResponseChallenge>,
T::Error: ::std::fmt::Display,
{
self.challenge = value
.try_into()
.map_err(|e| format!("error converting supplied value for challenge: {e}"));
self
}
pub fn claim_id<T>(mut self, value: T) -> Self
where
T: ::std::convert::TryInto<super::ResponseClaimId>,
T::Error: ::std::fmt::Display,
{
self.claim_id = value
.try_into()
.map_err(|e| format!("error converting supplied value for claim_id: {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
}
}
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 {
admin_did: value.admin_did?,
audience: value.audience?,
challenge: value.challenge?,
claim_id: value.claim_id?,
expires_at: value.expires_at?,
ext: value.ext?,
})
}
}
impl ::std::convert::From<super::Response> for Response {
fn from(value: super::Response) -> Self {
Self {
admin_did: Ok(value.admin_did),
audience: Ok(value.audience),
challenge: Ok(value.challenge),
claim_id: Ok(value.claim_id),
expires_at: Ok(value.expires_at),
ext: Ok(value.ext),
}
}
}
}
impl crate::Payload for Payload {
const TYPE_URI: &'static str = "https://trusttasks.org/spec/vtc/install/claim/start/0.3";
const IS_ISSUED_AT_REQUIRED: bool = true;
const IS_RECIPIENT_REQUIRED: bool = true;
const PAYLOAD_SCHEMA: Option<&'static str> = Some(
"{\n \"$defs\": {\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 \"properties\": {\n \"adminDid\": {\n \"description\": \"The DID the install token names — the DID that must sign claim/finish and that becomes the first administrator. Returned so the installer need not decode the token.\",\n \"maxLength\": 2048,\n \"minLength\": 5,\n \"pattern\": \"^did:\",\n \"type\": \"string\"\n },\n \"audience\": {\n \"description\": \"The community's DID, which the statement names as its `audience` and `recipient`, and to which claim/finish is addressed.\",\n \"maxLength\": 2048,\n \"minLength\": 5,\n \"pattern\": \"^did:\",\n \"type\": \"string\"\n },\n \"challenge\": {\n \"description\": \"A fresh challenge (≥128 bits) the founder's step-up approver signs over in its auth/step-up/approver/attest/0.1 statement with `purpose: enrol`.\",\n \"maxLength\": 512,\n \"minLength\": 16,\n \"type\": \"string\"\n },\n \"claimId\": {\n \"description\": \"Opaque, single-use handle for this claim. Echoed in claim/finish, and the `boundTo` of the approver's enrolment statement.\",\n \"maxLength\": 256,\n \"minLength\": 1,\n \"type\": \"string\"\n },\n \"expiresAt\": {\n \"description\": \"When this claim ceremony lapses (not the install token).\",\n \"format\": \"date-time\",\n \"type\": \"string\"\n },\n \"ext\": {\n \"$ref\": \"#/$defs/Ext\"\n }\n },\n \"required\": [\n \"claimId\",\n \"adminDid\",\n \"challenge\",\n \"audience\",\n \"expiresAt\"\n ],\n \"title\": \"VTC Install Claim Start — response payload\",\n \"type\": \"object\"\n }\n },\n \"$id\": \"https://trusttasks.org/spec/vtc/install/claim/start/0.3\",\n \"$schema\": \"https://json-schema.org/draft/2020-12/schema\",\n \"additionalProperties\": false,\n \"description\": \"Begin claiming a fresh community under a DID the founder already controls: exchange the install token and its claim code for a challenge the founder's step-up approver will sign. The outer document members (id, type, issuer, recipient, issuedAt, expiresAt, proof) are owned by the framework — SPEC §6.3.\",\n \"properties\": {\n \"claimCode\": {\n \"description\": \"The claim code the operator received out of band, through a different channel from the install URL. Required in 0.3. Compared with its stored hash; never logged.\",\n \"maxLength\": 64,\n \"minLength\": 1,\n \"type\": \"string\"\n },\n \"ext\": {\n \"$ref\": \"#/$defs/Ext\"\n },\n \"token\": {\n \"description\": \"The EdDSA-signed install JWT (aud=vtc-install) printed by vtc setup. In 0.3 it names the founder's DID.\",\n \"maxLength\": 4096,\n \"minLength\": 16,\n \"type\": \"string\"\n }\n },\n \"required\": [\n \"token\",\n \"claimCode\"\n ],\n \"title\": \"VTC Install Claim Start — payload\",\n \"type\": \"object\"\n}\n",
);
}
impl crate::Payload for Response {
const TYPE_URI: &'static str =
"https://trusttasks.org/spec/vtc/install/claim/start/0.3#response";
const IS_ISSUED_AT_REQUIRED: bool = true;
const IS_RECIPIENT_REQUIRED: bool = true;
const PAYLOAD_SCHEMA: Option<&'static str> = Some(
"{\n \"$defs\": {\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 \"properties\": {\n \"adminDid\": {\n \"description\": \"The DID the install token names — the DID that must sign claim/finish and that becomes the first administrator. Returned so the installer need not decode the token.\",\n \"maxLength\": 2048,\n \"minLength\": 5,\n \"pattern\": \"^did:\",\n \"type\": \"string\"\n },\n \"audience\": {\n \"description\": \"The community's DID, which the statement names as its `audience` and `recipient`, and to which claim/finish is addressed.\",\n \"maxLength\": 2048,\n \"minLength\": 5,\n \"pattern\": \"^did:\",\n \"type\": \"string\"\n },\n \"challenge\": {\n \"description\": \"A fresh challenge (≥128 bits) the founder's step-up approver signs over in its auth/step-up/approver/attest/0.1 statement with `purpose: enrol`.\",\n \"maxLength\": 512,\n \"minLength\": 16,\n \"type\": \"string\"\n },\n \"claimId\": {\n \"description\": \"Opaque, single-use handle for this claim. Echoed in claim/finish, and the `boundTo` of the approver's enrolment statement.\",\n \"maxLength\": 256,\n \"minLength\": 1,\n \"type\": \"string\"\n },\n \"expiresAt\": {\n \"description\": \"When this claim ceremony lapses (not the install token).\",\n \"format\": \"date-time\",\n \"type\": \"string\"\n },\n \"ext\": {\n \"$ref\": \"#/$defs/Ext\"\n }\n },\n \"required\": [\n \"claimId\",\n \"adminDid\",\n \"challenge\",\n \"audience\",\n \"expiresAt\"\n ],\n \"title\": \"VTC Install Claim Start — response payload\",\n \"type\": \"object\"\n }\n },\n \"$ref\": \"#/$defs/Response\",\n \"$schema\": \"https://json-schema.org/draft/2020-12/schema\"\n}\n",
);
}
impl crate::RequestPayload for Payload {
type Response = Response;
}
/// The extended error codes this specification declares (SPEC §7.3 item 9,
/// §8.5), in declaration order. Empty when it declares none.
pub const ERROR_CODES: &[crate::DeclaredErrorCode] =
&[error_codes::INVALID_TOKEN, error_codes::TOKEN_NAMES_NO_DID];
/// One constant per extended error code this specification declares
/// (SPEC §7.3 item 9), named for its local part.
///
/// Emit these rather than a string literal: the code is read from the
/// specification, so it cannot name a code the specification never
/// declared.
pub mod error_codes {
/// `vtc/install/claim/start:invalidToken`
///
/// The install token is missing, malformed, expired or already consumed, or the claim code does not match it. Deliberately one code for all of these, so an unauthenticated start is no oracle for which half was wrong.
///
/// Declared `retryable: false`.
pub const INVALID_TOKEN: crate::DeclaredErrorCode = crate::DeclaredErrorCode {
code: "vtc/install/claim/start:invalidToken",
retryable: false,
details_schema: ::core::option::Option::None,
};
/// `vtc/install/claim/start:tokenNamesNoDid`
///
/// The install token was issued for a passkey claim and names no administrator DID. Claim it with vtc/install/claim/start 0.2, or have the operator issue a token naming the founder's DID.
///
/// Declared `retryable: false`.
pub const TOKEN_NAMES_NO_DID: crate::DeclaredErrorCode = crate::DeclaredErrorCode {
code: "vtc/install/claim/start:tokenNamesNoDid",
retryable: false,
details_schema: ::core::option::Option::None,
};
}