//! Generated by `trust-tasks-codegen` — do not edit by hand.
//!
//! Spec slug: `provision/integration`. 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())
}
}
}
///Admin-only mint. No integration DID is produced. Used by holders that bring (or will mint elsewhere) their own integration-side identity and only need an admin credential at this maintainer.
///
/// <details><summary>JSON schema</summary>
///
/// ```json
///{
/// "title": "AdminRotationAsk",
/// "description": "Admin-only mint. No integration DID is produced. Used by holders that bring (or will mint elsewhere) their own integration-side identity and only need an admin credential at this maintainer.",
/// "type": "object",
/// "required": [
/// "adminTemplate",
/// "type"
/// ],
/// "properties": {
/// "adminTemplate": {
/// "description": "Admin-DID template. MUST be registered at the maintainer and MUST declare `kind == \"admin\"`.",
/// "$ref": "#/definitions/DidTemplateRef"
/// },
/// "contextHint": {
/// "description": "Hint for the admin grant's target context. The wire `payload.context` is authoritative.",
/// "type": "string",
/// "minLength": 1
/// },
/// "note": {
/// "description": "Free-form operator note carried into the maintainer's audit log.",
/// "type": "string",
/// "maxLength": 1024,
/// "minLength": 1
/// },
/// "type": {
/// "const": "AdminRotation"
/// }
/// },
/// "additionalProperties": false,
/// "$anchor": "admin-rotation-ask"
///}
/// ```
/// </details>
#[derive(::serde::Deserialize, ::serde::Serialize, Clone, Debug)]
#[serde(deny_unknown_fields)]
pub struct AdminRotationAsk {
///Admin-DID template. MUST be registered at the maintainer and MUST declare `kind == "admin"`.
#[serde(rename = "adminTemplate")]
pub admin_template: DidTemplateRef,
///Hint for the admin grant's target context. The wire `payload.context` is authoritative.
#[serde(
rename = "contextHint",
default,
skip_serializing_if = "::std::option::Option::is_none"
)]
pub context_hint: ::std::option::Option<AdminRotationAskContextHint>,
///Free-form operator note carried into the maintainer's audit log.
#[serde(default, skip_serializing_if = "::std::option::Option::is_none")]
pub note: ::std::option::Option<AdminRotationAskNote>,
#[serde(rename = "type")]
pub type_: ::serde_json::Value,
}
impl ::std::convert::From<&AdminRotationAsk> for AdminRotationAsk {
fn from(value: &AdminRotationAsk) -> Self {
value.clone()
}
}
///Hint for the admin grant's target context. The wire `payload.context` is authoritative.
///
/// <details><summary>JSON schema</summary>
///
/// ```json
///{
/// "description": "Hint for the admin grant's target context. The wire `payload.context` is authoritative.",
/// "type": "string",
/// "minLength": 1
///}
/// ```
/// </details>
#[derive(::serde::Serialize, Clone, Debug, Eq, Hash, Ord, PartialEq, PartialOrd)]
#[serde(transparent)]
pub struct AdminRotationAskContextHint(::std::string::String);
impl ::std::ops::Deref for AdminRotationAskContextHint {
type Target = ::std::string::String;
fn deref(&self) -> &::std::string::String {
&self.0
}
}
impl ::std::convert::From<AdminRotationAskContextHint> for ::std::string::String {
fn from(value: AdminRotationAskContextHint) -> Self {
value.0
}
}
impl ::std::convert::From<&AdminRotationAskContextHint> for AdminRotationAskContextHint {
fn from(value: &AdminRotationAskContextHint) -> Self {
value.clone()
}
}
impl ::std::str::FromStr for AdminRotationAskContextHint {
type Err = self::error::ConversionError;
fn from_str(value: &str) -> ::std::result::Result<Self, self::error::ConversionError> {
if value.chars().count() < 1usize {
return Err("shorter than 1 characters".into());
}
Ok(Self(value.to_string()))
}
}
impl ::std::convert::TryFrom<&str> for AdminRotationAskContextHint {
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 AdminRotationAskContextHint {
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 AdminRotationAskContextHint {
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 AdminRotationAskContextHint {
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())
})
}
}
///Free-form operator note carried into the maintainer's audit log.
///
/// <details><summary>JSON schema</summary>
///
/// ```json
///{
/// "description": "Free-form operator note carried into the maintainer's audit log.",
/// "type": "string",
/// "maxLength": 1024,
/// "minLength": 1
///}
/// ```
/// </details>
#[derive(::serde::Serialize, Clone, Debug, Eq, Hash, Ord, PartialEq, PartialOrd)]
#[serde(transparent)]
pub struct AdminRotationAskNote(::std::string::String);
impl ::std::ops::Deref for AdminRotationAskNote {
type Target = ::std::string::String;
fn deref(&self) -> &::std::string::String {
&self.0
}
}
impl ::std::convert::From<AdminRotationAskNote> for ::std::string::String {
fn from(value: AdminRotationAskNote) -> Self {
value.0
}
}
impl ::std::convert::From<&AdminRotationAskNote> for AdminRotationAskNote {
fn from(value: &AdminRotationAskNote) -> Self {
value.clone()
}
}
impl ::std::str::FromStr for AdminRotationAskNote {
type Err = self::error::ConversionError;
fn from_str(value: &str) -> ::std::result::Result<Self, self::error::ConversionError> {
if value.chars().count() > 1024usize {
return Err("longer than 1024 characters".into());
}
if value.chars().count() < 1usize {
return Err("shorter than 1 characters".into());
}
Ok(Self(value.to_string()))
}
}
impl ::std::convert::TryFrom<&str> for AdminRotationAskNote {
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 AdminRotationAskNote {
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 AdminRotationAskNote {
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 AdminRotationAskNote {
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())
})
}
}
///Discriminated union of bootstrap intents. Extensible — future minor versions MAY add variants.
///
/// <details><summary>JSON schema</summary>
///
/// ```json
///{
/// "title": "BootstrapAsk",
/// "description": "Discriminated union of bootstrap intents. Extensible — future minor versions MAY add variants.",
/// "oneOf": [
/// {
/// "$ref": "#/definitions/TemplateBootstrapAsk"
/// },
/// {
/// "$ref": "#/definitions/AdminRotationAsk"
/// }
/// ],
/// "$anchor": "bootstrap-ask"
///}
/// ```
/// </details>
#[derive(::serde::Deserialize, ::serde::Serialize, Clone, Debug)]
#[serde(untagged)]
pub enum BootstrapAsk {
TemplateBootstrapAsk(TemplateBootstrapAsk),
AdminRotationAsk(AdminRotationAsk),
}
impl ::std::convert::From<&Self> for BootstrapAsk {
fn from(value: &BootstrapAsk) -> Self {
value.clone()
}
}
impl ::std::convert::From<TemplateBootstrapAsk> for BootstrapAsk {
fn from(value: TemplateBootstrapAsk) -> Self {
Self::TemplateBootstrapAsk(value)
}
}
impl ::std::convert::From<AdminRotationAsk> for BootstrapAsk {
fn from(value: AdminRotationAsk) -> Self {
Self::AdminRotationAsk(value)
}
}
///W3C Verifiable Presentation 2.0 (§6.1: VPs MAY omit `verifiableCredential`). Custom members `nonce`, `validUntil`, `label`, and `ask` sit alongside the standard VP fields and are covered by the same DataIntegrityProof.
///
/// <details><summary>JSON schema</summary>
///
/// ```json
///{
/// "title": "BootstrapRequest",
/// "description": "W3C Verifiable Presentation 2.0 (§6.1: VPs MAY omit `verifiableCredential`). Custom members `nonce`, `validUntil`, `label`, and `ask` sit alongside the standard VP fields and are covered by the same DataIntegrityProof.",
/// "type": "object",
/// "required": [
/// "@context",
/// "ask",
/// "holder",
/// "id",
/// "nonce",
/// "proof",
/// "type",
/// "validUntil"
/// ],
/// "properties": {
/// "@context": {
/// "description": "JSON-LD contexts. MUST contain both `https://www.w3.org/ns/credentials/v2` and `https://openvtc.org/contexts/bootstrap-v1`. Maintainers verifying the proof MAY refuse other shapes.",
/// "type": "array",
/// "items": {
/// "type": "string",
/// "format": "uri"
/// },
/// "minItems": 2
/// },
/// "ask": {
/// "description": "What the holder is asking the maintainer to do. Tagged on `type`; see `TemplateBootstrapAsk` and `AdminRotationAsk`.",
/// "$ref": "#/definitions/BootstrapAsk"
/// },
/// "holder": {
/// "description": "The integration's ephemeral did:key (Ed25519). Identifies the party the returned bundle is HPKE-sealed for; the VP proof verifies under this DID's verification method.",
/// "type": "string",
/// "minLength": 1,
/// "pattern": "^did:key:z[1-9A-HJ-NP-Za-km-z]+$"
/// },
/// "id": {
/// "description": "URN-shaped identifier for this presentation. `urn:uuid:<v4>` is RECOMMENDED.",
/// "type": "string",
/// "minLength": 1
/// },
/// "label": {
/// "description": "Optional human-readable label carried into the maintainer's audit log.",
/// "type": "string",
/// "maxLength": 256,
/// "minLength": 1
/// },
/// "nonce": {
/// "description": "16 random bytes encoded as base64url-no-pad (22 characters). The maintainer treats this as the sealed bundle's `bundleId` (decoded to hex, exposed in `summary.bundleIdHex`) and SHOULD enforce one-shot semantics — a second provisioning with the same nonce MUST be refused as a replay.",
/// "type": "string",
/// "pattern": "^[A-Za-z0-9_-]{22}$"
/// },
/// "proof": {
/// "description": "Data Integrity proof signed by the holder's Ed25519 key. Cryptosuite MUST equal `eddsa-jcs-2022`. `proofPurpose` MUST equal `authentication`. `verificationMethod` MUST resolve under `holder`. Signs the JCS canonicalisation of the VP with `proof` removed.",
/// "$ref": "#/definitions/DataIntegrityProof"
/// },
/// "type": {
/// "description": "VP types. MUST contain both `VerifiablePresentation` and `BootstrapRequest`. Additional task-specific types MAY be present.",
/// "type": "array",
/// "items": {
/// "type": "string",
/// "minLength": 1
/// },
/// "minItems": 2
/// },
/// "validUntil": {
/// "description": "Freshness bound for the VP. RFC 3339 UTC. Maintainers SHOULD allow ±5 minutes of clock skew.",
/// "type": "string",
/// "format": "date-time"
/// }
/// },
/// "additionalProperties": false,
/// "$anchor": "bootstrap-request"
///}
/// ```
/// </details>
#[derive(::serde::Deserialize, ::serde::Serialize, Clone, Debug)]
#[serde(deny_unknown_fields)]
pub struct BootstrapRequest {
///What the holder is asking the maintainer to do. Tagged on `type`; see `TemplateBootstrapAsk` and `AdminRotationAsk`.
pub ask: BootstrapAsk,
///JSON-LD contexts. MUST contain both `https://www.w3.org/ns/credentials/v2` and `https://openvtc.org/contexts/bootstrap-v1`. Maintainers verifying the proof MAY refuse other shapes.
#[serde(rename = "@context")]
pub context: ::std::vec::Vec<::std::string::String>,
///The integration's ephemeral did:key (Ed25519). Identifies the party the returned bundle is HPKE-sealed for; the VP proof verifies under this DID's verification method.
pub holder: BootstrapRequestHolder,
///URN-shaped identifier for this presentation. `urn:uuid:<v4>` is RECOMMENDED.
pub id: BootstrapRequestId,
///Optional human-readable label carried into the maintainer's audit log.
#[serde(default, skip_serializing_if = "::std::option::Option::is_none")]
pub label: ::std::option::Option<BootstrapRequestLabel>,
///16 random bytes encoded as base64url-no-pad (22 characters). The maintainer treats this as the sealed bundle's `bundleId` (decoded to hex, exposed in `summary.bundleIdHex`) and SHOULD enforce one-shot semantics — a second provisioning with the same nonce MUST be refused as a replay.
pub nonce: BootstrapRequestNonce,
///Data Integrity proof signed by the holder's Ed25519 key. Cryptosuite MUST equal `eddsa-jcs-2022`. `proofPurpose` MUST equal `authentication`. `verificationMethod` MUST resolve under `holder`. Signs the JCS canonicalisation of the VP with `proof` removed.
pub proof: DataIntegrityProof,
///VP types. MUST contain both `VerifiablePresentation` and `BootstrapRequest`. Additional task-specific types MAY be present.
#[serde(rename = "type")]
pub type_: ::std::vec::Vec<BootstrapRequestTypeItem>,
///Freshness bound for the VP. RFC 3339 UTC. Maintainers SHOULD allow ±5 minutes of clock skew.
#[serde(rename = "validUntil")]
pub valid_until: ::chrono::DateTime<::chrono::offset::Utc>,
}
impl ::std::convert::From<&BootstrapRequest> for BootstrapRequest {
fn from(value: &BootstrapRequest) -> Self {
value.clone()
}
}
///The integration's ephemeral did:key (Ed25519). Identifies the party the returned bundle is HPKE-sealed for; the VP proof verifies under this DID's verification method.
///
/// <details><summary>JSON schema</summary>
///
/// ```json
///{
/// "description": "The integration's ephemeral did:key (Ed25519). Identifies the party the returned bundle is HPKE-sealed for; the VP proof verifies under this DID's verification method.",
/// "type": "string",
/// "minLength": 1,
/// "pattern": "^did:key:z[1-9A-HJ-NP-Za-km-z]+$"
///}
/// ```
/// </details>
#[derive(::serde::Serialize, Clone, Debug, Eq, Hash, Ord, PartialEq, PartialOrd)]
#[serde(transparent)]
pub struct BootstrapRequestHolder(::std::string::String);
impl ::std::ops::Deref for BootstrapRequestHolder {
type Target = ::std::string::String;
fn deref(&self) -> &::std::string::String {
&self.0
}
}
impl ::std::convert::From<BootstrapRequestHolder> for ::std::string::String {
fn from(value: BootstrapRequestHolder) -> Self {
value.0
}
}
impl ::std::convert::From<&BootstrapRequestHolder> for BootstrapRequestHolder {
fn from(value: &BootstrapRequestHolder) -> Self {
value.clone()
}
}
impl ::std::str::FromStr for BootstrapRequestHolder {
type Err = self::error::ConversionError;
fn from_str(value: &str) -> ::std::result::Result<Self, self::error::ConversionError> {
if value.chars().count() < 1usize {
return Err("shorter than 1 characters".into());
}
static PATTERN: ::std::sync::LazyLock<::regress::Regex> =
::std::sync::LazyLock::new(|| {
::regress::Regex::new("^did:key:z[1-9A-HJ-NP-Za-km-z]+$").unwrap()
});
if PATTERN.find(value).is_none() {
return Err("doesn't match pattern \"^did:key:z[1-9A-HJ-NP-Za-km-z]+$\"".into());
}
Ok(Self(value.to_string()))
}
}
impl ::std::convert::TryFrom<&str> for BootstrapRequestHolder {
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 BootstrapRequestHolder {
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 BootstrapRequestHolder {
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 BootstrapRequestHolder {
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())
})
}
}
///URN-shaped identifier for this presentation. `urn:uuid:<v4>` is RECOMMENDED.
///
/// <details><summary>JSON schema</summary>
///
/// ```json
///{
/// "description": "URN-shaped identifier for this presentation. `urn:uuid:<v4>` is RECOMMENDED.",
/// "type": "string",
/// "minLength": 1
///}
/// ```
/// </details>
#[derive(::serde::Serialize, Clone, Debug, Eq, Hash, Ord, PartialEq, PartialOrd)]
#[serde(transparent)]
pub struct BootstrapRequestId(::std::string::String);
impl ::std::ops::Deref for BootstrapRequestId {
type Target = ::std::string::String;
fn deref(&self) -> &::std::string::String {
&self.0
}
}
impl ::std::convert::From<BootstrapRequestId> for ::std::string::String {
fn from(value: BootstrapRequestId) -> Self {
value.0
}
}
impl ::std::convert::From<&BootstrapRequestId> for BootstrapRequestId {
fn from(value: &BootstrapRequestId) -> Self {
value.clone()
}
}
impl ::std::str::FromStr for BootstrapRequestId {
type Err = self::error::ConversionError;
fn from_str(value: &str) -> ::std::result::Result<Self, self::error::ConversionError> {
if value.chars().count() < 1usize {
return Err("shorter than 1 characters".into());
}
Ok(Self(value.to_string()))
}
}
impl ::std::convert::TryFrom<&str> for BootstrapRequestId {
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 BootstrapRequestId {
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 BootstrapRequestId {
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 BootstrapRequestId {
fn deserialize<D>(deserializer: D) -> ::std::result::Result<Self, D::Error>
where
D: ::serde::Deserializer<'de>,
{
::std::string::String::deserialize(deserializer)?
.parse()
.map_err(|e: self::error::ConversionError| {
<D::Error as ::serde::de::Error>::custom(e.to_string())
})
}
}
///Optional human-readable label carried into the maintainer's audit log.
///
/// <details><summary>JSON schema</summary>
///
/// ```json
///{
/// "description": "Optional human-readable label carried into the maintainer's audit log.",
/// "type": "string",
/// "maxLength": 256,
/// "minLength": 1
///}
/// ```
/// </details>
#[derive(::serde::Serialize, Clone, Debug, Eq, Hash, Ord, PartialEq, PartialOrd)]
#[serde(transparent)]
pub struct BootstrapRequestLabel(::std::string::String);
impl ::std::ops::Deref for BootstrapRequestLabel {
type Target = ::std::string::String;
fn deref(&self) -> &::std::string::String {
&self.0
}
}
impl ::std::convert::From<BootstrapRequestLabel> for ::std::string::String {
fn from(value: BootstrapRequestLabel) -> Self {
value.0
}
}
impl ::std::convert::From<&BootstrapRequestLabel> for BootstrapRequestLabel {
fn from(value: &BootstrapRequestLabel) -> Self {
value.clone()
}
}
impl ::std::str::FromStr for BootstrapRequestLabel {
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 BootstrapRequestLabel {
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 BootstrapRequestLabel {
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 BootstrapRequestLabel {
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 BootstrapRequestLabel {
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())
})
}
}
///16 random bytes encoded as base64url-no-pad (22 characters). The maintainer treats this as the sealed bundle's `bundleId` (decoded to hex, exposed in `summary.bundleIdHex`) and SHOULD enforce one-shot semantics — a second provisioning with the same nonce MUST be refused as a replay.
///
/// <details><summary>JSON schema</summary>
///
/// ```json
///{
/// "description": "16 random bytes encoded as base64url-no-pad (22 characters). The maintainer treats this as the sealed bundle's `bundleId` (decoded to hex, exposed in `summary.bundleIdHex`) and SHOULD enforce one-shot semantics — a second provisioning with the same nonce MUST be refused as a replay.",
/// "type": "string",
/// "pattern": "^[A-Za-z0-9_-]{22}$"
///}
/// ```
/// </details>
#[derive(::serde::Serialize, Clone, Debug, Eq, Hash, Ord, PartialEq, PartialOrd)]
#[serde(transparent)]
pub struct BootstrapRequestNonce(::std::string::String);
impl ::std::ops::Deref for BootstrapRequestNonce {
type Target = ::std::string::String;
fn deref(&self) -> &::std::string::String {
&self.0
}
}
impl ::std::convert::From<BootstrapRequestNonce> for ::std::string::String {
fn from(value: BootstrapRequestNonce) -> Self {
value.0
}
}
impl ::std::convert::From<&BootstrapRequestNonce> for BootstrapRequestNonce {
fn from(value: &BootstrapRequestNonce) -> Self {
value.clone()
}
}
impl ::std::str::FromStr for BootstrapRequestNonce {
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_-]{22}$").unwrap());
if PATTERN.find(value).is_none() {
return Err("doesn't match pattern \"^[A-Za-z0-9_-]{22}$\"".into());
}
Ok(Self(value.to_string()))
}
}
impl ::std::convert::TryFrom<&str> for BootstrapRequestNonce {
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 BootstrapRequestNonce {
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 BootstrapRequestNonce {
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 BootstrapRequestNonce {
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())
})
}
}
///`BootstrapRequestTypeItem`
///
/// <details><summary>JSON schema</summary>
///
/// ```json
///{
/// "type": "string",
/// "minLength": 1
///}
/// ```
/// </details>
#[derive(::serde::Serialize, Clone, Debug, Eq, Hash, Ord, PartialEq, PartialOrd)]
#[serde(transparent)]
pub struct BootstrapRequestTypeItem(::std::string::String);
impl ::std::ops::Deref for BootstrapRequestTypeItem {
type Target = ::std::string::String;
fn deref(&self) -> &::std::string::String {
&self.0
}
}
impl ::std::convert::From<BootstrapRequestTypeItem> for ::std::string::String {
fn from(value: BootstrapRequestTypeItem) -> Self {
value.0
}
}
impl ::std::convert::From<&BootstrapRequestTypeItem> for BootstrapRequestTypeItem {
fn from(value: &BootstrapRequestTypeItem) -> Self {
value.clone()
}
}
impl ::std::str::FromStr for BootstrapRequestTypeItem {
type Err = self::error::ConversionError;
fn from_str(value: &str) -> ::std::result::Result<Self, self::error::ConversionError> {
if value.chars().count() < 1usize {
return Err("shorter than 1 characters".into());
}
Ok(Self(value.to_string()))
}
}
impl ::std::convert::TryFrom<&str> for BootstrapRequestTypeItem {
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 BootstrapRequestTypeItem {
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 BootstrapRequestTypeItem {
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 BootstrapRequestTypeItem {
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())
})
}
}
///W3C Data Integrity proof. Spec body pins cryptosuite and proofPurpose; this schema permits the standard property bag so future cryptosuites can ride the same shape.
///
/// <details><summary>JSON schema</summary>
///
/// ```json
///{
/// "title": "DataIntegrityProof",
/// "description": "W3C Data Integrity proof. Spec body pins cryptosuite and proofPurpose; this schema permits the standard property bag so future cryptosuites can ride the same shape.",
/// "type": "object",
/// "required": [
/// "cryptosuite",
/// "proofPurpose",
/// "proofValue",
/// "type",
/// "verificationMethod"
/// ],
/// "properties": {
/// "created": {
/// "type": "string",
/// "format": "date-time"
/// },
/// "cryptosuite": {
/// "description": "This version pins `eddsa-jcs-2022`. Maintainers MUST reject other values until a future minor extends the allowlist.",
/// "type": "string",
/// "minLength": 1
/// },
/// "proofPurpose": {
/// "const": "authentication"
/// },
/// "proofValue": {
/// "description": "Multibase-encoded Ed25519 signature.",
/// "type": "string",
/// "minLength": 1
/// },
/// "type": {
/// "const": "DataIntegrityProof"
/// },
/// "verificationMethod": {
/// "description": "DID URL with fragment. The DID portion (left of `#`) MUST equal `holder`.",
/// "type": "string",
/// "minLength": 1
/// }
/// },
/// "additionalProperties": true,
/// "$anchor": "data-integrity-proof"
///}
/// ```
/// </details>
#[derive(::serde::Deserialize, ::serde::Serialize, Clone, Debug)]
pub struct DataIntegrityProof {
#[serde(default, skip_serializing_if = "::std::option::Option::is_none")]
pub created: ::std::option::Option<::chrono::DateTime<::chrono::offset::Utc>>,
///This version pins `eddsa-jcs-2022`. Maintainers MUST reject other values until a future minor extends the allowlist.
pub cryptosuite: DataIntegrityProofCryptosuite,
#[serde(rename = "proofPurpose")]
pub proof_purpose: ::serde_json::Value,
///Multibase-encoded Ed25519 signature.
#[serde(rename = "proofValue")]
pub proof_value: DataIntegrityProofProofValue,
#[serde(rename = "type")]
pub type_: ::serde_json::Value,
///DID URL with fragment. The DID portion (left of `#`) MUST equal `holder`.
#[serde(rename = "verificationMethod")]
pub verification_method: DataIntegrityProofVerificationMethod,
}
impl ::std::convert::From<&DataIntegrityProof> for DataIntegrityProof {
fn from(value: &DataIntegrityProof) -> Self {
value.clone()
}
}
///This version pins `eddsa-jcs-2022`. Maintainers MUST reject other values until a future minor extends the allowlist.
///
/// <details><summary>JSON schema</summary>
///
/// ```json
///{
/// "description": "This version pins `eddsa-jcs-2022`. Maintainers MUST reject other values until a future minor extends the allowlist.",
/// "type": "string",
/// "minLength": 1
///}
/// ```
/// </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::convert::From<&DataIntegrityProofCryptosuite> for DataIntegrityProofCryptosuite {
fn from(value: &DataIntegrityProofCryptosuite) -> Self {
value.clone()
}
}
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() < 1usize {
return Err("shorter than 1 characters".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())
})
}
}
///Multibase-encoded Ed25519 signature.
///
/// <details><summary>JSON schema</summary>
///
/// ```json
///{
/// "description": "Multibase-encoded Ed25519 signature.",
/// "type": "string",
/// "minLength": 1
///}
/// ```
/// </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::convert::From<&DataIntegrityProofProofValue> for DataIntegrityProofProofValue {
fn from(value: &DataIntegrityProofProofValue) -> Self {
value.clone()
}
}
impl ::std::str::FromStr for DataIntegrityProofProofValue {
type Err = self::error::ConversionError;
fn from_str(value: &str) -> ::std::result::Result<Self, self::error::ConversionError> {
if value.chars().count() < 1usize {
return Err("shorter than 1 characters".into());
}
Ok(Self(value.to_string()))
}
}
impl ::std::convert::TryFrom<&str> for 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())
})
}
}
///DID URL with fragment. The DID portion (left of `#`) MUST equal `holder`.
///
/// <details><summary>JSON schema</summary>
///
/// ```json
///{
/// "description": "DID URL with fragment. The DID portion (left of `#`) MUST equal `holder`.",
/// "type": "string",
/// "minLength": 1
///}
/// ```
/// </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::convert::From<&DataIntegrityProofVerificationMethod>
for DataIntegrityProofVerificationMethod
{
fn from(value: &DataIntegrityProofVerificationMethod) -> Self {
value.clone()
}
}
impl ::std::str::FromStr for DataIntegrityProofVerificationMethod {
type Err = self::error::ConversionError;
fn from_str(value: &str) -> ::std::result::Result<Self, self::error::ConversionError> {
if value.chars().count() < 1usize {
return Err("shorter than 1 characters".into());
}
Ok(Self(value.to_string()))
}
}
impl ::std::convert::TryFrom<&str> for 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())
})
}
}
///Reference to a DID template already registered at the maintainer. Inline template definitions are deliberately not supported — templates must be uploaded out-of-band first (operator-authored or built-in) so the maintainer can validate `vars` against the template's declared schema.
///
/// <details><summary>JSON schema</summary>
///
/// ```json
///{
/// "title": "DidTemplateRef",
/// "description": "Reference to a DID template already registered at the maintainer. Inline template definitions are deliberately not supported — templates must be uploaded out-of-band first (operator-authored or built-in) so the maintainer can validate `vars` against the template's declared schema.",
/// "type": "object",
/// "required": [
/// "name"
/// ],
/// "properties": {
/// "name": {
/// "description": "Template name as registered at the maintainer (built-in or operator-uploaded). Examples of built-ins shipped with VTA deployments: `didcomm-mediator`, `vta-admin`, `did-hosting-control`, `did-hosting-daemon`, `did-hosting-server`.",
/// "type": "string",
/// "maxLength": 128,
/// "minLength": 1
/// },
/// "vars": {
/// "description": "Variable bindings the maintainer feeds to the template renderer. MUST satisfy the template's `requiredVars`; values for `optionalVars` MAY be supplied. Unknown vars are rejected with `provision/integration:template_vars_invalid`.",
/// "default": {},
/// "type": "object",
/// "additionalProperties": true
/// }
/// },
/// "additionalProperties": false,
/// "$anchor": "did-template-ref"
///}
/// ```
/// </details>
#[derive(::serde::Deserialize, ::serde::Serialize, Clone, Debug)]
#[serde(deny_unknown_fields)]
pub struct DidTemplateRef {
///Template name as registered at the maintainer (built-in or operator-uploaded). Examples of built-ins shipped with VTA deployments: `didcomm-mediator`, `vta-admin`, `did-hosting-control`, `did-hosting-daemon`, `did-hosting-server`.
pub name: DidTemplateRefName,
///Variable bindings the maintainer feeds to the template renderer. MUST satisfy the template's `requiredVars`; values for `optionalVars` MAY be supplied. Unknown vars are rejected with `provision/integration:template_vars_invalid`.
#[serde(default, skip_serializing_if = "::serde_json::Map::is_empty")]
pub vars: ::serde_json::Map<::std::string::String, ::serde_json::Value>,
}
impl ::std::convert::From<&DidTemplateRef> for DidTemplateRef {
fn from(value: &DidTemplateRef) -> Self {
value.clone()
}
}
///Template name as registered at the maintainer (built-in or operator-uploaded). Examples of built-ins shipped with VTA deployments: `didcomm-mediator`, `vta-admin`, `did-hosting-control`, `did-hosting-daemon`, `did-hosting-server`.
///
/// <details><summary>JSON schema</summary>
///
/// ```json
///{
/// "description": "Template name as registered at the maintainer (built-in or operator-uploaded). Examples of built-ins shipped with VTA deployments: `didcomm-mediator`, `vta-admin`, `did-hosting-control`, `did-hosting-daemon`, `did-hosting-server`.",
/// "type": "string",
/// "maxLength": 128,
/// "minLength": 1
///}
/// ```
/// </details>
#[derive(::serde::Serialize, Clone, Debug, Eq, Hash, Ord, PartialEq, PartialOrd)]
#[serde(transparent)]
pub struct DidTemplateRefName(::std::string::String);
impl ::std::ops::Deref for DidTemplateRefName {
type Target = ::std::string::String;
fn deref(&self) -> &::std::string::String {
&self.0
}
}
impl ::std::convert::From<DidTemplateRefName> for ::std::string::String {
fn from(value: DidTemplateRefName) -> Self {
value.0
}
}
impl ::std::convert::From<&DidTemplateRefName> for DidTemplateRefName {
fn from(value: &DidTemplateRefName) -> Self {
value.clone()
}
}
impl ::std::str::FromStr for DidTemplateRefName {
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 DidTemplateRefName {
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 DidTemplateRefName {
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 DidTemplateRefName {
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 DidTemplateRefName {
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<&Ext> for Ext {
fn from(value: &Ext) -> Self {
value.clone()
}
}
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::convert::From<&ExtKey> for ExtKey {
fn from(value: &ExtKey) -> Self {
value.clone()
}
}
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())
})
}
}
///Relayer presents a VP-signed bootstrap request from an integration holder; the maintainer mints the integration's DIDs and admin credential from a registered DID template and ships the material back HPKE-sealed to the holder's ephemeral did:key. Two ask variants are supported: TemplateBootstrap (mint integration DID + optional admin DID) and AdminRotation (mint only the long-term admin DID).
///
/// <details><summary>JSON schema</summary>
///
/// ```json
///{
/// "$id": "https://trusttasks.org/spec/provision/integration/0.1",
/// "title": "Payload",
/// "description": "Relayer presents a VP-signed bootstrap request from an integration holder; the maintainer mints the integration's DIDs and admin credential from a registered DID template and ships the material back HPKE-sealed to the holder's ephemeral did:key. Two ask variants are supported: TemplateBootstrap (mint integration DID + optional admin DID) and AdminRotation (mint only the long-term admin DID).",
/// "type": "object",
/// "required": [
/// "request"
/// ],
/// "properties": {
/// "assertion": {
/// "description": "Producer-assertion mode the maintainer should apply to the returned sealed bundle. `did-signed` (default) — Ed25519 signature over the bundle's domain-bound digest, verified by the holder against the maintainer's published key. `pinned-only` — holder pins the bundle's SHA-256 digest as the sole integrity anchor; for dev/test only. Maintainers MAY support additional modes (e.g. `attested` for TEE deployments) and respond with `provision/integration:assertion_unsupported` to unsupported requests.",
/// "default": "did-signed",
/// "type": "string",
/// "enum": [
/// "did-signed",
/// "pinned-only"
/// ]
/// },
/// "context": {
/// "description": "The maintainer's context identifier the integration is to be provisioned into. When present, authoritative — overrides any `contextHint` carried inside `request.ask`. When ABSENT, the maintainer infers the target context using these rules in order: (1) if the relayer's grant scopes to exactly one context, use that context; (2) if the relayer is a super-admin (Admin role with unrestricted scope) and the maintainer has exactly one context registered, use that context; (3) otherwise reject the request with `provision/integration:context_required`. Wallet-class consumers (browser plugins, mobile companions) that don't know the maintainer's context layout SHOULD omit this field; integration-class consumers (mediator, did-hosting) targeting a specific operational context SHOULD send it explicitly.",
/// "type": "string",
/// "minLength": 1
/// },
/// "createContext": {
/// "description": "When `true`, the maintainer provisions the target context inline if it does not already exist. Requires super-admin role on the maintainer; context-admin callers MUST receive `provision/integration:forbidden` against a missing context. Idempotent when the context already exists.",
/// "default": false,
/// "type": "boolean"
/// },
/// "ext": {
/// "description": "Ecosystem-defined extension members per SPEC.md §4.5.1.",
/// "$ref": "#/definitions/Ext"
/// },
/// "request": {
/// "description": "VP-framed bootstrap request signed by the holder's ephemeral did:key. The proof here is independent of, and additional to, the outer Trust Task envelope's proof — it authenticates the holder (the party the sealed bundle is encrypted for), whereas the envelope's proof authenticates the relayer (the party making the call). The two MAY be the same DID in the common case.",
/// "$ref": "#/definitions/BootstrapRequest"
/// },
/// "vcValiditySeconds": {
/// "description": "Caller-preferred validity window for the issued VtaAuthorizationCredential, in seconds. The maintainer's policy applies a floor and ceiling; values outside that range MAY be silently clamped. Defaults to the maintainer's policy default (typically 3600s).",
/// "type": "integer",
/// "maximum": 31536000.0,
/// "minimum": 1.0
/// }
/// },
/// "additionalProperties": false
///}
/// ```
/// </details>
#[derive(::serde::Deserialize, ::serde::Serialize, Clone, Debug)]
#[serde(deny_unknown_fields)]
pub struct Payload {
///Producer-assertion mode the maintainer should apply to the returned sealed bundle. `did-signed` (default) — Ed25519 signature over the bundle's domain-bound digest, verified by the holder against the maintainer's published key. `pinned-only` — holder pins the bundle's SHA-256 digest as the sole integrity anchor; for dev/test only. Maintainers MAY support additional modes (e.g. `attested` for TEE deployments) and respond with `provision/integration:assertion_unsupported` to unsupported requests.
#[serde(default = "defaults::payload_assertion")]
pub assertion: PayloadAssertion,
///The maintainer's context identifier the integration is to be provisioned into. When present, authoritative — overrides any `contextHint` carried inside `request.ask`. When ABSENT, the maintainer infers the target context using these rules in order: (1) if the relayer's grant scopes to exactly one context, use that context; (2) if the relayer is a super-admin (Admin role with unrestricted scope) and the maintainer has exactly one context registered, use that context; (3) otherwise reject the request with `provision/integration:context_required`. Wallet-class consumers (browser plugins, mobile companions) that don't know the maintainer's context layout SHOULD omit this field; integration-class consumers (mediator, did-hosting) targeting a specific operational context SHOULD send it explicitly.
#[serde(default, skip_serializing_if = "::std::option::Option::is_none")]
pub context: ::std::option::Option<PayloadContext>,
///When `true`, the maintainer provisions the target context inline if it does not already exist. Requires super-admin role on the maintainer; context-admin callers MUST receive `provision/integration:forbidden` against a missing context. Idempotent when the context already exists.
#[serde(rename = "createContext", default)]
pub create_context: bool,
///Ecosystem-defined extension members per SPEC.md §4.5.1.
#[serde(default, skip_serializing_if = "::std::option::Option::is_none")]
pub ext: ::std::option::Option<Ext>,
///VP-framed bootstrap request signed by the holder's ephemeral did:key. The proof here is independent of, and additional to, the outer Trust Task envelope's proof — it authenticates the holder (the party the sealed bundle is encrypted for), whereas the envelope's proof authenticates the relayer (the party making the call). The two MAY be the same DID in the common case.
pub request: BootstrapRequest,
///Caller-preferred validity window for the issued VtaAuthorizationCredential, in seconds. The maintainer's policy applies a floor and ceiling; values outside that range MAY be silently clamped. Defaults to the maintainer's policy default (typically 3600s).
#[serde(
rename = "vcValiditySeconds",
default,
skip_serializing_if = "::std::option::Option::is_none"
)]
pub vc_validity_seconds: ::std::option::Option<::std::num::NonZeroU64>,
}
impl ::std::convert::From<&Payload> for Payload {
fn from(value: &Payload) -> Self {
value.clone()
}
}
///Producer-assertion mode the maintainer should apply to the returned sealed bundle. `did-signed` (default) — Ed25519 signature over the bundle's domain-bound digest, verified by the holder against the maintainer's published key. `pinned-only` — holder pins the bundle's SHA-256 digest as the sole integrity anchor; for dev/test only. Maintainers MAY support additional modes (e.g. `attested` for TEE deployments) and respond with `provision/integration:assertion_unsupported` to unsupported requests.
///
/// <details><summary>JSON schema</summary>
///
/// ```json
///{
/// "description": "Producer-assertion mode the maintainer should apply to the returned sealed bundle. `did-signed` (default) — Ed25519 signature over the bundle's domain-bound digest, verified by the holder against the maintainer's published key. `pinned-only` — holder pins the bundle's SHA-256 digest as the sole integrity anchor; for dev/test only. Maintainers MAY support additional modes (e.g. `attested` for TEE deployments) and respond with `provision/integration:assertion_unsupported` to unsupported requests.",
/// "default": "did-signed",
/// "type": "string",
/// "enum": [
/// "did-signed",
/// "pinned-only"
/// ]
///}
/// ```
/// </details>
#[derive(
::serde::Deserialize,
::serde::Serialize,
Clone,
Copy,
Debug,
Eq,
Hash,
Ord,
PartialEq,
PartialOrd,
)]
pub enum PayloadAssertion {
#[serde(rename = "did-signed")]
DidSigned,
#[serde(rename = "pinned-only")]
PinnedOnly,
}
impl ::std::convert::From<&Self> for PayloadAssertion {
fn from(value: &PayloadAssertion) -> Self {
value.clone()
}
}
impl ::std::fmt::Display for PayloadAssertion {
fn fmt(&self, f: &mut ::std::fmt::Formatter<'_>) -> ::std::fmt::Result {
match *self {
Self::DidSigned => f.write_str("did-signed"),
Self::PinnedOnly => f.write_str("pinned-only"),
}
}
}
impl ::std::str::FromStr for PayloadAssertion {
type Err = self::error::ConversionError;
fn from_str(value: &str) -> ::std::result::Result<Self, self::error::ConversionError> {
match value {
"did-signed" => Ok(Self::DidSigned),
"pinned-only" => Ok(Self::PinnedOnly),
_ => Err("invalid value".into()),
}
}
}
impl ::std::convert::TryFrom<&str> for PayloadAssertion {
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 PayloadAssertion {
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 PayloadAssertion {
type Error = self::error::ConversionError;
fn try_from(
value: ::std::string::String,
) -> ::std::result::Result<Self, self::error::ConversionError> {
value.parse()
}
}
impl ::std::default::Default for PayloadAssertion {
fn default() -> Self {
PayloadAssertion::DidSigned
}
}
///The maintainer's context identifier the integration is to be provisioned into. When present, authoritative — overrides any `contextHint` carried inside `request.ask`. When ABSENT, the maintainer infers the target context using these rules in order: (1) if the relayer's grant scopes to exactly one context, use that context; (2) if the relayer is a super-admin (Admin role with unrestricted scope) and the maintainer has exactly one context registered, use that context; (3) otherwise reject the request with `provision/integration:context_required`. Wallet-class consumers (browser plugins, mobile companions) that don't know the maintainer's context layout SHOULD omit this field; integration-class consumers (mediator, did-hosting) targeting a specific operational context SHOULD send it explicitly.
///
/// <details><summary>JSON schema</summary>
///
/// ```json
///{
/// "description": "The maintainer's context identifier the integration is to be provisioned into. When present, authoritative — overrides any `contextHint` carried inside `request.ask`. When ABSENT, the maintainer infers the target context using these rules in order: (1) if the relayer's grant scopes to exactly one context, use that context; (2) if the relayer is a super-admin (Admin role with unrestricted scope) and the maintainer has exactly one context registered, use that context; (3) otherwise reject the request with `provision/integration:context_required`. Wallet-class consumers (browser plugins, mobile companions) that don't know the maintainer's context layout SHOULD omit this field; integration-class consumers (mediator, did-hosting) targeting a specific operational context SHOULD send it explicitly.",
/// "type": "string",
/// "minLength": 1
///}
/// ```
/// </details>
#[derive(::serde::Serialize, Clone, Debug, Eq, Hash, Ord, PartialEq, PartialOrd)]
#[serde(transparent)]
pub struct PayloadContext(::std::string::String);
impl ::std::ops::Deref for PayloadContext {
type Target = ::std::string::String;
fn deref(&self) -> &::std::string::String {
&self.0
}
}
impl ::std::convert::From<PayloadContext> for ::std::string::String {
fn from(value: PayloadContext) -> Self {
value.0
}
}
impl ::std::convert::From<&PayloadContext> for PayloadContext {
fn from(value: &PayloadContext) -> Self {
value.clone()
}
}
impl ::std::str::FromStr for PayloadContext {
type Err = self::error::ConversionError;
fn from_str(value: &str) -> ::std::result::Result<Self, self::error::ConversionError> {
if value.chars().count() < 1usize {
return Err("shorter than 1 characters".into());
}
Ok(Self(value.to_string()))
}
}
impl ::std::convert::TryFrom<&str> for PayloadContext {
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 PayloadContext {
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 PayloadContext {
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 PayloadContext {
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())
})
}
}
///Audit-grade metadata about the provisioning outcome. Mirrors the existing `vta_sdk::provision_integration::http::ProvisionSummary` Rust type but uses camelCase wire fields per Trust Task convention.
///
/// <details><summary>JSON schema</summary>
///
/// ```json
///{
/// "title": "ProvisionSummary",
/// "description": "Audit-grade metadata about the provisioning outcome. Mirrors the existing `vta_sdk::provision_integration::http::ProvisionSummary` Rust type but uses camelCase wire fields per Trust Task convention.",
/// "type": "object",
/// "required": [
/// "bundleIdHex",
/// "clientDid",
/// "outputCount",
/// "secretCount"
/// ],
/// "properties": {
/// "adminDid": {
/// "description": "Long-term admin DID after this provisioning. Equals `clientDid` when no admin rollover occurred (TemplateBootstrap with no `adminTemplate`); equals the freshly-minted admin DID when `adminTemplate` was used or when the ask was `AdminRotation`. Maintainers that pre-date admin rollover MAY omit this; consumers SHOULD default it to `clientDid` for backward compatibility.",
/// "type": "string",
/// "minLength": 1
/// },
/// "adminRolledOver": {
/// "description": "True when the maintainer minted a fresh long-term admin DID and bound the authorization VC + ACL row to it (i.e. `adminDid != clientDid`).",
/// "default": false,
/// "type": "boolean"
/// },
/// "adminTemplateName": {
/// "description": "Name of the admin template that was rendered. Present when an admin DID was minted (either via `TemplateBootstrap.adminTemplate` or `AdminRotation`).",
/// "type": "string",
/// "minLength": 1
/// },
/// "bundleIdHex": {
/// "description": "VP nonce as lowercase hex (32 characters = 16 bytes). MUST equal the `Bundle-Id` armor header of `bundle`. Cross-check anchor: a holder that decodes the VP nonce can verify the bundle they opened matches the one the maintainer minted for them.",
/// "type": "string",
/// "pattern": "^[0-9a-f]{32}$"
/// },
/// "clientDid": {
/// "description": "Ephemeral did:key the holder signed the VP with and opens the sealed bundle with. Echo of `request.holder`.",
/// "type": "string",
/// "minLength": 1
/// },
/// "contextCreated": {
/// "description": "True when `payload.createContext` was honoured and the maintainer provisioned the target context inline. False when the context already existed (or when `createContext` was omitted / false).",
/// "default": false,
/// "type": "boolean"
/// },
/// "integrationDid": {
/// "description": "DID rendered from the integration template. Absent for `AdminRotation` (no integration was rendered).",
/// "type": "string",
/// "minLength": 1
/// },
/// "outputCount": {
/// "description": "Number of template-declared side outputs the sealed bundle carries (`did.jsonl` logs, DIDComm service advertisements, etc.). Always 0 for `AdminRotation`.",
/// "type": "integer",
/// "minimum": 0.0
/// },
/// "secretCount": {
/// "description": "Number of DIDs the sealed bundle carries private key material for. `TemplateBootstrap` with no adminTemplate typically yields 1 (the integration DID's keys). `AdminRotation` yields 0 (the `admin` field is top-level, not under `secrets`).",
/// "type": "integer",
/// "minimum": 0.0
/// },
/// "templateKind": {
/// "description": "`kind` of the integration template (e.g. `mediator`, `did-hosting-control`, `app`). Absent for `AdminRotation`.",
/// "type": "string",
/// "minLength": 1
/// },
/// "templateName": {
/// "description": "Name of the integration template that was rendered. Absent for `AdminRotation`.",
/// "type": "string",
/// "minLength": 1
/// },
/// "webvhServerId": {
/// "description": "Identifier of the registered webvh hosting server the maintainer published the integration's `did.jsonl` to, if any. Absent when the integration is self-hosted or when the template did not declare a webvh server var.",
/// "type": "string",
/// "minLength": 1
/// }
/// },
/// "additionalProperties": false,
/// "$anchor": "provision-summary"
///}
/// ```
/// </details>
#[derive(::serde::Deserialize, ::serde::Serialize, Clone, Debug)]
#[serde(deny_unknown_fields)]
pub struct ProvisionSummary {
///Long-term admin DID after this provisioning. Equals `clientDid` when no admin rollover occurred (TemplateBootstrap with no `adminTemplate`); equals the freshly-minted admin DID when `adminTemplate` was used or when the ask was `AdminRotation`. Maintainers that pre-date admin rollover MAY omit this; consumers SHOULD default it to `clientDid` for backward compatibility.
#[serde(
rename = "adminDid",
default,
skip_serializing_if = "::std::option::Option::is_none"
)]
pub admin_did: ::std::option::Option<ProvisionSummaryAdminDid>,
///True when the maintainer minted a fresh long-term admin DID and bound the authorization VC + ACL row to it (i.e. `adminDid != clientDid`).
#[serde(rename = "adminRolledOver", default)]
pub admin_rolled_over: bool,
///Name of the admin template that was rendered. Present when an admin DID was minted (either via `TemplateBootstrap.adminTemplate` or `AdminRotation`).
#[serde(
rename = "adminTemplateName",
default,
skip_serializing_if = "::std::option::Option::is_none"
)]
pub admin_template_name: ::std::option::Option<ProvisionSummaryAdminTemplateName>,
///VP nonce as lowercase hex (32 characters = 16 bytes). MUST equal the `Bundle-Id` armor header of `bundle`. Cross-check anchor: a holder that decodes the VP nonce can verify the bundle they opened matches the one the maintainer minted for them.
#[serde(rename = "bundleIdHex")]
pub bundle_id_hex: ProvisionSummaryBundleIdHex,
///Ephemeral did:key the holder signed the VP with and opens the sealed bundle with. Echo of `request.holder`.
#[serde(rename = "clientDid")]
pub client_did: ProvisionSummaryClientDid,
///True when `payload.createContext` was honoured and the maintainer provisioned the target context inline. False when the context already existed (or when `createContext` was omitted / false).
#[serde(rename = "contextCreated", default)]
pub context_created: bool,
///DID rendered from the integration template. Absent for `AdminRotation` (no integration was rendered).
#[serde(
rename = "integrationDid",
default,
skip_serializing_if = "::std::option::Option::is_none"
)]
pub integration_did: ::std::option::Option<ProvisionSummaryIntegrationDid>,
///Number of template-declared side outputs the sealed bundle carries (`did.jsonl` logs, DIDComm service advertisements, etc.). Always 0 for `AdminRotation`.
#[serde(rename = "outputCount")]
pub output_count: u64,
///Number of DIDs the sealed bundle carries private key material for. `TemplateBootstrap` with no adminTemplate typically yields 1 (the integration DID's keys). `AdminRotation` yields 0 (the `admin` field is top-level, not under `secrets`).
#[serde(rename = "secretCount")]
pub secret_count: u64,
///`kind` of the integration template (e.g. `mediator`, `did-hosting-control`, `app`). Absent for `AdminRotation`.
#[serde(
rename = "templateKind",
default,
skip_serializing_if = "::std::option::Option::is_none"
)]
pub template_kind: ::std::option::Option<ProvisionSummaryTemplateKind>,
///Name of the integration template that was rendered. Absent for `AdminRotation`.
#[serde(
rename = "templateName",
default,
skip_serializing_if = "::std::option::Option::is_none"
)]
pub template_name: ::std::option::Option<ProvisionSummaryTemplateName>,
///Identifier of the registered webvh hosting server the maintainer published the integration's `did.jsonl` to, if any. Absent when the integration is self-hosted or when the template did not declare a webvh server var.
#[serde(
rename = "webvhServerId",
default,
skip_serializing_if = "::std::option::Option::is_none"
)]
pub webvh_server_id: ::std::option::Option<ProvisionSummaryWebvhServerId>,
}
impl ::std::convert::From<&ProvisionSummary> for ProvisionSummary {
fn from(value: &ProvisionSummary) -> Self {
value.clone()
}
}
///Long-term admin DID after this provisioning. Equals `clientDid` when no admin rollover occurred (TemplateBootstrap with no `adminTemplate`); equals the freshly-minted admin DID when `adminTemplate` was used or when the ask was `AdminRotation`. Maintainers that pre-date admin rollover MAY omit this; consumers SHOULD default it to `clientDid` for backward compatibility.
///
/// <details><summary>JSON schema</summary>
///
/// ```json
///{
/// "description": "Long-term admin DID after this provisioning. Equals `clientDid` when no admin rollover occurred (TemplateBootstrap with no `adminTemplate`); equals the freshly-minted admin DID when `adminTemplate` was used or when the ask was `AdminRotation`. Maintainers that pre-date admin rollover MAY omit this; consumers SHOULD default it to `clientDid` for backward compatibility.",
/// "type": "string",
/// "minLength": 1
///}
/// ```
/// </details>
#[derive(::serde::Serialize, Clone, Debug, Eq, Hash, Ord, PartialEq, PartialOrd)]
#[serde(transparent)]
pub struct ProvisionSummaryAdminDid(::std::string::String);
impl ::std::ops::Deref for ProvisionSummaryAdminDid {
type Target = ::std::string::String;
fn deref(&self) -> &::std::string::String {
&self.0
}
}
impl ::std::convert::From<ProvisionSummaryAdminDid> for ::std::string::String {
fn from(value: ProvisionSummaryAdminDid) -> Self {
value.0
}
}
impl ::std::convert::From<&ProvisionSummaryAdminDid> for ProvisionSummaryAdminDid {
fn from(value: &ProvisionSummaryAdminDid) -> Self {
value.clone()
}
}
impl ::std::str::FromStr for ProvisionSummaryAdminDid {
type Err = self::error::ConversionError;
fn from_str(value: &str) -> ::std::result::Result<Self, self::error::ConversionError> {
if value.chars().count() < 1usize {
return Err("shorter than 1 characters".into());
}
Ok(Self(value.to_string()))
}
}
impl ::std::convert::TryFrom<&str> for ProvisionSummaryAdminDid {
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 ProvisionSummaryAdminDid {
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 ProvisionSummaryAdminDid {
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 ProvisionSummaryAdminDid {
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())
})
}
}
///Name of the admin template that was rendered. Present when an admin DID was minted (either via `TemplateBootstrap.adminTemplate` or `AdminRotation`).
///
/// <details><summary>JSON schema</summary>
///
/// ```json
///{
/// "description": "Name of the admin template that was rendered. Present when an admin DID was minted (either via `TemplateBootstrap.adminTemplate` or `AdminRotation`).",
/// "type": "string",
/// "minLength": 1
///}
/// ```
/// </details>
#[derive(::serde::Serialize, Clone, Debug, Eq, Hash, Ord, PartialEq, PartialOrd)]
#[serde(transparent)]
pub struct ProvisionSummaryAdminTemplateName(::std::string::String);
impl ::std::ops::Deref for ProvisionSummaryAdminTemplateName {
type Target = ::std::string::String;
fn deref(&self) -> &::std::string::String {
&self.0
}
}
impl ::std::convert::From<ProvisionSummaryAdminTemplateName> for ::std::string::String {
fn from(value: ProvisionSummaryAdminTemplateName) -> Self {
value.0
}
}
impl ::std::convert::From<&ProvisionSummaryAdminTemplateName>
for ProvisionSummaryAdminTemplateName
{
fn from(value: &ProvisionSummaryAdminTemplateName) -> Self {
value.clone()
}
}
impl ::std::str::FromStr for ProvisionSummaryAdminTemplateName {
type Err = self::error::ConversionError;
fn from_str(value: &str) -> ::std::result::Result<Self, self::error::ConversionError> {
if value.chars().count() < 1usize {
return Err("shorter than 1 characters".into());
}
Ok(Self(value.to_string()))
}
}
impl ::std::convert::TryFrom<&str> for ProvisionSummaryAdminTemplateName {
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 ProvisionSummaryAdminTemplateName {
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 ProvisionSummaryAdminTemplateName {
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 ProvisionSummaryAdminTemplateName {
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())
})
}
}
///VP nonce as lowercase hex (32 characters = 16 bytes). MUST equal the `Bundle-Id` armor header of `bundle`. Cross-check anchor: a holder that decodes the VP nonce can verify the bundle they opened matches the one the maintainer minted for them.
///
/// <details><summary>JSON schema</summary>
///
/// ```json
///{
/// "description": "VP nonce as lowercase hex (32 characters = 16 bytes). MUST equal the `Bundle-Id` armor header of `bundle`. Cross-check anchor: a holder that decodes the VP nonce can verify the bundle they opened matches the one the maintainer minted for them.",
/// "type": "string",
/// "pattern": "^[0-9a-f]{32}$"
///}
/// ```
/// </details>
#[derive(::serde::Serialize, Clone, Debug, Eq, Hash, Ord, PartialEq, PartialOrd)]
#[serde(transparent)]
pub struct ProvisionSummaryBundleIdHex(::std::string::String);
impl ::std::ops::Deref for ProvisionSummaryBundleIdHex {
type Target = ::std::string::String;
fn deref(&self) -> &::std::string::String {
&self.0
}
}
impl ::std::convert::From<ProvisionSummaryBundleIdHex> for ::std::string::String {
fn from(value: ProvisionSummaryBundleIdHex) -> Self {
value.0
}
}
impl ::std::convert::From<&ProvisionSummaryBundleIdHex> for ProvisionSummaryBundleIdHex {
fn from(value: &ProvisionSummaryBundleIdHex) -> Self {
value.clone()
}
}
impl ::std::str::FromStr for ProvisionSummaryBundleIdHex {
type Err = self::error::ConversionError;
fn from_str(value: &str) -> ::std::result::Result<Self, self::error::ConversionError> {
static PATTERN: ::std::sync::LazyLock<::regress::Regex> =
::std::sync::LazyLock::new(|| ::regress::Regex::new("^[0-9a-f]{32}$").unwrap());
if PATTERN.find(value).is_none() {
return Err("doesn't match pattern \"^[0-9a-f]{32}$\"".into());
}
Ok(Self(value.to_string()))
}
}
impl ::std::convert::TryFrom<&str> for ProvisionSummaryBundleIdHex {
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 ProvisionSummaryBundleIdHex {
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 ProvisionSummaryBundleIdHex {
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 ProvisionSummaryBundleIdHex {
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())
})
}
}
///Ephemeral did:key the holder signed the VP with and opens the sealed bundle with. Echo of `request.holder`.
///
/// <details><summary>JSON schema</summary>
///
/// ```json
///{
/// "description": "Ephemeral did:key the holder signed the VP with and opens the sealed bundle with. Echo of `request.holder`.",
/// "type": "string",
/// "minLength": 1
///}
/// ```
/// </details>
#[derive(::serde::Serialize, Clone, Debug, Eq, Hash, Ord, PartialEq, PartialOrd)]
#[serde(transparent)]
pub struct ProvisionSummaryClientDid(::std::string::String);
impl ::std::ops::Deref for ProvisionSummaryClientDid {
type Target = ::std::string::String;
fn deref(&self) -> &::std::string::String {
&self.0
}
}
impl ::std::convert::From<ProvisionSummaryClientDid> for ::std::string::String {
fn from(value: ProvisionSummaryClientDid) -> Self {
value.0
}
}
impl ::std::convert::From<&ProvisionSummaryClientDid> for ProvisionSummaryClientDid {
fn from(value: &ProvisionSummaryClientDid) -> Self {
value.clone()
}
}
impl ::std::str::FromStr for ProvisionSummaryClientDid {
type Err = self::error::ConversionError;
fn from_str(value: &str) -> ::std::result::Result<Self, self::error::ConversionError> {
if value.chars().count() < 1usize {
return Err("shorter than 1 characters".into());
}
Ok(Self(value.to_string()))
}
}
impl ::std::convert::TryFrom<&str> for ProvisionSummaryClientDid {
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 ProvisionSummaryClientDid {
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 ProvisionSummaryClientDid {
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 ProvisionSummaryClientDid {
fn deserialize<D>(deserializer: D) -> ::std::result::Result<Self, D::Error>
where
D: ::serde::Deserializer<'de>,
{
::std::string::String::deserialize(deserializer)?
.parse()
.map_err(|e: self::error::ConversionError| {
<D::Error as ::serde::de::Error>::custom(e.to_string())
})
}
}
///DID rendered from the integration template. Absent for `AdminRotation` (no integration was rendered).
///
/// <details><summary>JSON schema</summary>
///
/// ```json
///{
/// "description": "DID rendered from the integration template. Absent for `AdminRotation` (no integration was rendered).",
/// "type": "string",
/// "minLength": 1
///}
/// ```
/// </details>
#[derive(::serde::Serialize, Clone, Debug, Eq, Hash, Ord, PartialEq, PartialOrd)]
#[serde(transparent)]
pub struct ProvisionSummaryIntegrationDid(::std::string::String);
impl ::std::ops::Deref for ProvisionSummaryIntegrationDid {
type Target = ::std::string::String;
fn deref(&self) -> &::std::string::String {
&self.0
}
}
impl ::std::convert::From<ProvisionSummaryIntegrationDid> for ::std::string::String {
fn from(value: ProvisionSummaryIntegrationDid) -> Self {
value.0
}
}
impl ::std::convert::From<&ProvisionSummaryIntegrationDid> for ProvisionSummaryIntegrationDid {
fn from(value: &ProvisionSummaryIntegrationDid) -> Self {
value.clone()
}
}
impl ::std::str::FromStr for ProvisionSummaryIntegrationDid {
type Err = self::error::ConversionError;
fn from_str(value: &str) -> ::std::result::Result<Self, self::error::ConversionError> {
if value.chars().count() < 1usize {
return Err("shorter than 1 characters".into());
}
Ok(Self(value.to_string()))
}
}
impl ::std::convert::TryFrom<&str> for ProvisionSummaryIntegrationDid {
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 ProvisionSummaryIntegrationDid {
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 ProvisionSummaryIntegrationDid {
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 ProvisionSummaryIntegrationDid {
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())
})
}
}
///`kind` of the integration template (e.g. `mediator`, `did-hosting-control`, `app`). Absent for `AdminRotation`.
///
/// <details><summary>JSON schema</summary>
///
/// ```json
///{
/// "description": "`kind` of the integration template (e.g. `mediator`, `did-hosting-control`, `app`). Absent for `AdminRotation`.",
/// "type": "string",
/// "minLength": 1
///}
/// ```
/// </details>
#[derive(::serde::Serialize, Clone, Debug, Eq, Hash, Ord, PartialEq, PartialOrd)]
#[serde(transparent)]
pub struct ProvisionSummaryTemplateKind(::std::string::String);
impl ::std::ops::Deref for ProvisionSummaryTemplateKind {
type Target = ::std::string::String;
fn deref(&self) -> &::std::string::String {
&self.0
}
}
impl ::std::convert::From<ProvisionSummaryTemplateKind> for ::std::string::String {
fn from(value: ProvisionSummaryTemplateKind) -> Self {
value.0
}
}
impl ::std::convert::From<&ProvisionSummaryTemplateKind> for ProvisionSummaryTemplateKind {
fn from(value: &ProvisionSummaryTemplateKind) -> Self {
value.clone()
}
}
impl ::std::str::FromStr for ProvisionSummaryTemplateKind {
type Err = self::error::ConversionError;
fn from_str(value: &str) -> ::std::result::Result<Self, self::error::ConversionError> {
if value.chars().count() < 1usize {
return Err("shorter than 1 characters".into());
}
Ok(Self(value.to_string()))
}
}
impl ::std::convert::TryFrom<&str> for ProvisionSummaryTemplateKind {
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 ProvisionSummaryTemplateKind {
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 ProvisionSummaryTemplateKind {
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 ProvisionSummaryTemplateKind {
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())
})
}
}
///Name of the integration template that was rendered. Absent for `AdminRotation`.
///
/// <details><summary>JSON schema</summary>
///
/// ```json
///{
/// "description": "Name of the integration template that was rendered. Absent for `AdminRotation`.",
/// "type": "string",
/// "minLength": 1
///}
/// ```
/// </details>
#[derive(::serde::Serialize, Clone, Debug, Eq, Hash, Ord, PartialEq, PartialOrd)]
#[serde(transparent)]
pub struct ProvisionSummaryTemplateName(::std::string::String);
impl ::std::ops::Deref for ProvisionSummaryTemplateName {
type Target = ::std::string::String;
fn deref(&self) -> &::std::string::String {
&self.0
}
}
impl ::std::convert::From<ProvisionSummaryTemplateName> for ::std::string::String {
fn from(value: ProvisionSummaryTemplateName) -> Self {
value.0
}
}
impl ::std::convert::From<&ProvisionSummaryTemplateName> for ProvisionSummaryTemplateName {
fn from(value: &ProvisionSummaryTemplateName) -> Self {
value.clone()
}
}
impl ::std::str::FromStr for ProvisionSummaryTemplateName {
type Err = self::error::ConversionError;
fn from_str(value: &str) -> ::std::result::Result<Self, self::error::ConversionError> {
if value.chars().count() < 1usize {
return Err("shorter than 1 characters".into());
}
Ok(Self(value.to_string()))
}
}
impl ::std::convert::TryFrom<&str> for ProvisionSummaryTemplateName {
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 ProvisionSummaryTemplateName {
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 ProvisionSummaryTemplateName {
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 ProvisionSummaryTemplateName {
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())
})
}
}
///Identifier of the registered webvh hosting server the maintainer published the integration's `did.jsonl` to, if any. Absent when the integration is self-hosted or when the template did not declare a webvh server var.
///
/// <details><summary>JSON schema</summary>
///
/// ```json
///{
/// "description": "Identifier of the registered webvh hosting server the maintainer published the integration's `did.jsonl` to, if any. Absent when the integration is self-hosted or when the template did not declare a webvh server var.",
/// "type": "string",
/// "minLength": 1
///}
/// ```
/// </details>
#[derive(::serde::Serialize, Clone, Debug, Eq, Hash, Ord, PartialEq, PartialOrd)]
#[serde(transparent)]
pub struct ProvisionSummaryWebvhServerId(::std::string::String);
impl ::std::ops::Deref for ProvisionSummaryWebvhServerId {
type Target = ::std::string::String;
fn deref(&self) -> &::std::string::String {
&self.0
}
}
impl ::std::convert::From<ProvisionSummaryWebvhServerId> for ::std::string::String {
fn from(value: ProvisionSummaryWebvhServerId) -> Self {
value.0
}
}
impl ::std::convert::From<&ProvisionSummaryWebvhServerId> for ProvisionSummaryWebvhServerId {
fn from(value: &ProvisionSummaryWebvhServerId) -> Self {
value.clone()
}
}
impl ::std::str::FromStr for ProvisionSummaryWebvhServerId {
type Err = self::error::ConversionError;
fn from_str(value: &str) -> ::std::result::Result<Self, self::error::ConversionError> {
if value.chars().count() < 1usize {
return Err("shorter than 1 characters".into());
}
Ok(Self(value.to_string()))
}
}
impl ::std::convert::TryFrom<&str> for ProvisionSummaryWebvhServerId {
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 ProvisionSummaryWebvhServerId {
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 ProvisionSummaryWebvhServerId {
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 ProvisionSummaryWebvhServerId {
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())
})
}
}
///Carried in a Trust Task document whose type is https://trusttasks.org/spec/provision/integration/0.1#response. The sealed `bundle` is the secret-bearing artefact; `summary` is non-secret audit metadata.
///
/// <details><summary>JSON schema</summary>
///
/// ```json
///{
/// "title": "Response",
/// "description": "Carried in a Trust Task document whose type is https://trusttasks.org/spec/provision/integration/0.1#response. The sealed `bundle` is the secret-bearing artefact; `summary` is non-secret audit metadata.",
/// "type": "object",
/// "required": [
/// "bundle",
/// "digest",
/// "summary"
/// ],
/// "properties": {
/// "bundle": {
/// "description": "OpenPGP-style ASCII-armored ciphertext of `SealedPayloadV1`. HPKE base mode, X25519-HKDF-SHA256 KEM, ChaCha20-Poly1305 AEAD, info string `vta-sealed-transfer/v1`. Recipient is the X25519 derivation of `request.holder`'s Ed25519 pubkey.",
/// "type": "string",
/// "minLength": 1
/// },
/// "digest": {
/// "description": "SHA-256 of the armored ciphertext, lowercase hex. Used by holders that pin the bundle out-of-band.",
/// "type": "string",
/// "pattern": "^[0-9a-f]{64}$"
/// },
/// "ext": {
/// "$ref": "#/definitions/Ext"
/// },
/// "summary": {
/// "description": "Non-secret audit metadata. MUST NOT include any private key material; the bundle is the only secret-bearing field.",
/// "$ref": "#/definitions/ProvisionSummary"
/// }
/// },
/// "additionalProperties": false,
/// "$anchor": "response"
///}
/// ```
/// </details>
#[derive(::serde::Deserialize, ::serde::Serialize, Clone, Debug)]
#[serde(deny_unknown_fields)]
pub struct Response {
///OpenPGP-style ASCII-armored ciphertext of `SealedPayloadV1`. HPKE base mode, X25519-HKDF-SHA256 KEM, ChaCha20-Poly1305 AEAD, info string `vta-sealed-transfer/v1`. Recipient is the X25519 derivation of `request.holder`'s Ed25519 pubkey.
pub bundle: ResponseBundle,
///SHA-256 of the armored ciphertext, lowercase hex. Used by holders that pin the bundle out-of-band.
pub digest: ResponseDigest,
#[serde(default, skip_serializing_if = "::std::option::Option::is_none")]
pub ext: ::std::option::Option<Ext>,
///Non-secret audit metadata. MUST NOT include any private key material; the bundle is the only secret-bearing field.
pub summary: ProvisionSummary,
}
impl ::std::convert::From<&Response> for Response {
fn from(value: &Response) -> Self {
value.clone()
}
}
///OpenPGP-style ASCII-armored ciphertext of `SealedPayloadV1`. HPKE base mode, X25519-HKDF-SHA256 KEM, ChaCha20-Poly1305 AEAD, info string `vta-sealed-transfer/v1`. Recipient is the X25519 derivation of `request.holder`'s Ed25519 pubkey.
///
/// <details><summary>JSON schema</summary>
///
/// ```json
///{
/// "description": "OpenPGP-style ASCII-armored ciphertext of `SealedPayloadV1`. HPKE base mode, X25519-HKDF-SHA256 KEM, ChaCha20-Poly1305 AEAD, info string `vta-sealed-transfer/v1`. Recipient is the X25519 derivation of `request.holder`'s Ed25519 pubkey.",
/// "type": "string",
/// "minLength": 1
///}
/// ```
/// </details>
#[derive(::serde::Serialize, Clone, Debug, Eq, Hash, Ord, PartialEq, PartialOrd)]
#[serde(transparent)]
pub struct ResponseBundle(::std::string::String);
impl ::std::ops::Deref for ResponseBundle {
type Target = ::std::string::String;
fn deref(&self) -> &::std::string::String {
&self.0
}
}
impl ::std::convert::From<ResponseBundle> for ::std::string::String {
fn from(value: ResponseBundle) -> Self {
value.0
}
}
impl ::std::convert::From<&ResponseBundle> for ResponseBundle {
fn from(value: &ResponseBundle) -> Self {
value.clone()
}
}
impl ::std::str::FromStr for ResponseBundle {
type Err = self::error::ConversionError;
fn from_str(value: &str) -> ::std::result::Result<Self, self::error::ConversionError> {
if value.chars().count() < 1usize {
return Err("shorter than 1 characters".into());
}
Ok(Self(value.to_string()))
}
}
impl ::std::convert::TryFrom<&str> for ResponseBundle {
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 ResponseBundle {
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 ResponseBundle {
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 ResponseBundle {
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())
})
}
}
///SHA-256 of the armored ciphertext, lowercase hex. Used by holders that pin the bundle out-of-band.
///
/// <details><summary>JSON schema</summary>
///
/// ```json
///{
/// "description": "SHA-256 of the armored ciphertext, lowercase hex. Used by holders that pin the bundle out-of-band.",
/// "type": "string",
/// "pattern": "^[0-9a-f]{64}$"
///}
/// ```
/// </details>
#[derive(::serde::Serialize, Clone, Debug, Eq, Hash, Ord, PartialEq, PartialOrd)]
#[serde(transparent)]
pub struct ResponseDigest(::std::string::String);
impl ::std::ops::Deref for ResponseDigest {
type Target = ::std::string::String;
fn deref(&self) -> &::std::string::String {
&self.0
}
}
impl ::std::convert::From<ResponseDigest> for ::std::string::String {
fn from(value: ResponseDigest) -> Self {
value.0
}
}
impl ::std::convert::From<&ResponseDigest> for ResponseDigest {
fn from(value: &ResponseDigest) -> Self {
value.clone()
}
}
impl ::std::str::FromStr for ResponseDigest {
type Err = self::error::ConversionError;
fn from_str(value: &str) -> ::std::result::Result<Self, self::error::ConversionError> {
static PATTERN: ::std::sync::LazyLock<::regress::Regex> =
::std::sync::LazyLock::new(|| ::regress::Regex::new("^[0-9a-f]{64}$").unwrap());
if PATTERN.find(value).is_none() {
return Err("doesn't match pattern \"^[0-9a-f]{64}$\"".into());
}
Ok(Self(value.to_string()))
}
}
impl ::std::convert::TryFrom<&str> for ResponseDigest {
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 ResponseDigest {
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 ResponseDigest {
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 ResponseDigest {
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())
})
}
}
///Mint an integration DID from `template`, and (when `adminTemplate` is present) atomically roll over the holder to a fresh long-term admin DID minted from `adminTemplate`.
///
/// <details><summary>JSON schema</summary>
///
/// ```json
///{
/// "title": "TemplateBootstrapAsk",
/// "description": "Mint an integration DID from `template`, and (when `adminTemplate` is present) atomically roll over the holder to a fresh long-term admin DID minted from `adminTemplate`.",
/// "type": "object",
/// "required": [
/// "template",
/// "type"
/// ],
/// "properties": {
/// "adminTemplate": {
/// "description": "Optional admin-DID template. When present, the maintainer mints a fresh long-term admin DID + keys, binds the authorization VC + ACL row to it, and rolls the holder over from the ephemeral did:key in the same transaction. When absent, the authorization VC's subject and ACL row are bound to the ephemeral `holder`, which the operator is expected to swap via `acl/swap-key/0.1` before steady-state operation. MUST declare `kind == \"admin\"` when present.",
/// "$ref": "#/definitions/DidTemplateRef"
/// },
/// "contextHint": {
/// "description": "Hint for the integration's target context. The wire `payload.context` is authoritative; this hint exists for documentation / cross-check only.",
/// "type": "string",
/// "minLength": 1
/// },
/// "note": {
/// "description": "Free-form operator note carried into the maintainer's audit log.",
/// "type": "string",
/// "maxLength": 1024,
/// "minLength": 1
/// },
/// "template": {
/// "description": "Integration template. MUST be registered at the maintainer; MUST declare a `kind` other than `\"admin\"`.",
/// "$ref": "#/definitions/DidTemplateRef"
/// },
/// "type": {
/// "const": "TemplateBootstrap"
/// }
/// },
/// "additionalProperties": false,
/// "$anchor": "template-bootstrap-ask"
///}
/// ```
/// </details>
#[derive(::serde::Deserialize, ::serde::Serialize, Clone, Debug)]
#[serde(deny_unknown_fields)]
pub struct TemplateBootstrapAsk {
///Optional admin-DID template. When present, the maintainer mints a fresh long-term admin DID + keys, binds the authorization VC + ACL row to it, and rolls the holder over from the ephemeral did:key in the same transaction. When absent, the authorization VC's subject and ACL row are bound to the ephemeral `holder`, which the operator is expected to swap via `acl/swap-key/0.1` before steady-state operation. MUST declare `kind == "admin"` when present.
#[serde(
rename = "adminTemplate",
default,
skip_serializing_if = "::std::option::Option::is_none"
)]
pub admin_template: ::std::option::Option<DidTemplateRef>,
///Hint for the integration's target context. The wire `payload.context` is authoritative; this hint exists for documentation / cross-check only.
#[serde(
rename = "contextHint",
default,
skip_serializing_if = "::std::option::Option::is_none"
)]
pub context_hint: ::std::option::Option<TemplateBootstrapAskContextHint>,
///Free-form operator note carried into the maintainer's audit log.
#[serde(default, skip_serializing_if = "::std::option::Option::is_none")]
pub note: ::std::option::Option<TemplateBootstrapAskNote>,
///Integration template. MUST be registered at the maintainer; MUST declare a `kind` other than `"admin"`.
pub template: DidTemplateRef,
#[serde(rename = "type")]
pub type_: ::serde_json::Value,
}
impl ::std::convert::From<&TemplateBootstrapAsk> for TemplateBootstrapAsk {
fn from(value: &TemplateBootstrapAsk) -> Self {
value.clone()
}
}
///Hint for the integration's target context. The wire `payload.context` is authoritative; this hint exists for documentation / cross-check only.
///
/// <details><summary>JSON schema</summary>
///
/// ```json
///{
/// "description": "Hint for the integration's target context. The wire `payload.context` is authoritative; this hint exists for documentation / cross-check only.",
/// "type": "string",
/// "minLength": 1
///}
/// ```
/// </details>
#[derive(::serde::Serialize, Clone, Debug, Eq, Hash, Ord, PartialEq, PartialOrd)]
#[serde(transparent)]
pub struct TemplateBootstrapAskContextHint(::std::string::String);
impl ::std::ops::Deref for TemplateBootstrapAskContextHint {
type Target = ::std::string::String;
fn deref(&self) -> &::std::string::String {
&self.0
}
}
impl ::std::convert::From<TemplateBootstrapAskContextHint> for ::std::string::String {
fn from(value: TemplateBootstrapAskContextHint) -> Self {
value.0
}
}
impl ::std::convert::From<&TemplateBootstrapAskContextHint> for TemplateBootstrapAskContextHint {
fn from(value: &TemplateBootstrapAskContextHint) -> Self {
value.clone()
}
}
impl ::std::str::FromStr for TemplateBootstrapAskContextHint {
type Err = self::error::ConversionError;
fn from_str(value: &str) -> ::std::result::Result<Self, self::error::ConversionError> {
if value.chars().count() < 1usize {
return Err("shorter than 1 characters".into());
}
Ok(Self(value.to_string()))
}
}
impl ::std::convert::TryFrom<&str> for TemplateBootstrapAskContextHint {
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 TemplateBootstrapAskContextHint {
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 TemplateBootstrapAskContextHint {
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 TemplateBootstrapAskContextHint {
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())
})
}
}
///Free-form operator note carried into the maintainer's audit log.
///
/// <details><summary>JSON schema</summary>
///
/// ```json
///{
/// "description": "Free-form operator note carried into the maintainer's audit log.",
/// "type": "string",
/// "maxLength": 1024,
/// "minLength": 1
///}
/// ```
/// </details>
#[derive(::serde::Serialize, Clone, Debug, Eq, Hash, Ord, PartialEq, PartialOrd)]
#[serde(transparent)]
pub struct TemplateBootstrapAskNote(::std::string::String);
impl ::std::ops::Deref for TemplateBootstrapAskNote {
type Target = ::std::string::String;
fn deref(&self) -> &::std::string::String {
&self.0
}
}
impl ::std::convert::From<TemplateBootstrapAskNote> for ::std::string::String {
fn from(value: TemplateBootstrapAskNote) -> Self {
value.0
}
}
impl ::std::convert::From<&TemplateBootstrapAskNote> for TemplateBootstrapAskNote {
fn from(value: &TemplateBootstrapAskNote) -> Self {
value.clone()
}
}
impl ::std::str::FromStr for TemplateBootstrapAskNote {
type Err = self::error::ConversionError;
fn from_str(value: &str) -> ::std::result::Result<Self, self::error::ConversionError> {
if value.chars().count() > 1024usize {
return Err("longer than 1024 characters".into());
}
if value.chars().count() < 1usize {
return Err("shorter than 1 characters".into());
}
Ok(Self(value.to_string()))
}
}
impl ::std::convert::TryFrom<&str> for TemplateBootstrapAskNote {
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 TemplateBootstrapAskNote {
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 TemplateBootstrapAskNote {
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 TemplateBootstrapAskNote {
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())
})
}
}
/// Generation of default values for serde.
pub mod defaults {
pub(super) fn payload_assertion() -> super::PayloadAssertion {
super::PayloadAssertion::DidSigned
}
}
impl crate::Payload for Payload {
const TYPE_URI: &'static str = "https://trusttasks.org/spec/provision/integration/0.1";
const IS_PROOF_REQUIRED: bool = true;
}
impl crate::Payload for Response {
const TYPE_URI: &'static str = "https://trusttasks.org/spec/provision/integration/0.1#response";
const IS_PROOF_REQUIRED: bool = true;
}
#[cfg(feature = "validate")]
impl crate::validate::ValidatedPayload for Payload {
const SCHEMA_JSON: &'static str = "{\n \"$defs\": {\n \"AdminRotationAsk\": {\n \"$anchor\": \"admin-rotation-ask\",\n \"additionalProperties\": false,\n \"description\": \"Admin-only mint. No integration DID is produced. Used by holders that bring (or will mint elsewhere) their own integration-side identity and only need an admin credential at this maintainer.\",\n \"properties\": {\n \"adminTemplate\": {\n \"$ref\": \"#/$defs/DidTemplateRef\",\n \"description\": \"Admin-DID template. MUST be registered at the maintainer and MUST declare `kind == \\\"admin\\\"`.\"\n },\n \"contextHint\": {\n \"description\": \"Hint for the admin grant's target context. The wire `payload.context` is authoritative.\",\n \"minLength\": 1,\n \"type\": \"string\"\n },\n \"note\": {\n \"description\": \"Free-form operator note carried into the maintainer's audit log.\",\n \"maxLength\": 1024,\n \"minLength\": 1,\n \"type\": \"string\"\n },\n \"type\": {\n \"const\": \"AdminRotation\"\n }\n },\n \"required\": [\n \"type\",\n \"adminTemplate\"\n ],\n \"title\": \"AdminRotationAsk\",\n \"type\": \"object\"\n },\n \"BootstrapAsk\": {\n \"$anchor\": \"bootstrap-ask\",\n \"description\": \"Discriminated union of bootstrap intents. Extensible — future minor versions MAY add variants.\",\n \"oneOf\": [\n {\n \"$ref\": \"#/$defs/TemplateBootstrapAsk\"\n },\n {\n \"$ref\": \"#/$defs/AdminRotationAsk\"\n }\n ],\n \"title\": \"BootstrapAsk\"\n },\n \"BootstrapRequest\": {\n \"$anchor\": \"bootstrap-request\",\n \"additionalProperties\": false,\n \"description\": \"W3C Verifiable Presentation 2.0 (§6.1: VPs MAY omit `verifiableCredential`). Custom members `nonce`, `validUntil`, `label`, and `ask` sit alongside the standard VP fields and are covered by the same DataIntegrityProof.\",\n \"properties\": {\n \"@context\": {\n \"description\": \"JSON-LD contexts. MUST contain both `https://www.w3.org/ns/credentials/v2` and `https://openvtc.org/contexts/bootstrap-v1`. Maintainers verifying the proof MAY refuse other shapes.\",\n \"items\": {\n \"format\": \"uri\",\n \"type\": \"string\"\n },\n \"minItems\": 2,\n \"type\": \"array\"\n },\n \"ask\": {\n \"$ref\": \"#/$defs/BootstrapAsk\",\n \"description\": \"What the holder is asking the maintainer to do. Tagged on `type`; see `TemplateBootstrapAsk` and `AdminRotationAsk`.\"\n },\n \"holder\": {\n \"description\": \"The integration's ephemeral did:key (Ed25519). Identifies the party the returned bundle is HPKE-sealed for; the VP proof verifies under this DID's verification method.\",\n \"minLength\": 1,\n \"pattern\": \"^did:key:z[1-9A-HJ-NP-Za-km-z]+$\",\n \"type\": \"string\"\n },\n \"id\": {\n \"description\": \"URN-shaped identifier for this presentation. `urn:uuid:<v4>` is RECOMMENDED.\",\n \"minLength\": 1,\n \"type\": \"string\"\n },\n \"label\": {\n \"description\": \"Optional human-readable label carried into the maintainer's audit log.\",\n \"maxLength\": 256,\n \"minLength\": 1,\n \"type\": \"string\"\n },\n \"nonce\": {\n \"description\": \"16 random bytes encoded as base64url-no-pad (22 characters). The maintainer treats this as the sealed bundle's `bundleId` (decoded to hex, exposed in `summary.bundleIdHex`) and SHOULD enforce one-shot semantics — a second provisioning with the same nonce MUST be refused as a replay.\",\n \"pattern\": \"^[A-Za-z0-9_-]{22}$\",\n \"type\": \"string\"\n },\n \"proof\": {\n \"$ref\": \"#/$defs/DataIntegrityProof\",\n \"description\": \"Data Integrity proof signed by the holder's Ed25519 key. Cryptosuite MUST equal `eddsa-jcs-2022`. `proofPurpose` MUST equal `authentication`. `verificationMethod` MUST resolve under `holder`. Signs the JCS canonicalisation of the VP with `proof` removed.\"\n },\n \"type\": {\n \"description\": \"VP types. MUST contain both `VerifiablePresentation` and `BootstrapRequest`. Additional task-specific types MAY be present.\",\n \"items\": {\n \"minLength\": 1,\n \"type\": \"string\"\n },\n \"minItems\": 2,\n \"type\": \"array\"\n },\n \"validUntil\": {\n \"description\": \"Freshness bound for the VP. RFC 3339 UTC. Maintainers SHOULD allow ±5 minutes of clock skew.\",\n \"format\": \"date-time\",\n \"type\": \"string\"\n }\n },\n \"required\": [\n \"@context\",\n \"type\",\n \"id\",\n \"holder\",\n \"nonce\",\n \"validUntil\",\n \"ask\",\n \"proof\"\n ],\n \"title\": \"BootstrapRequest\",\n \"type\": \"object\"\n },\n \"DataIntegrityProof\": {\n \"$anchor\": \"data-integrity-proof\",\n \"additionalProperties\": true,\n \"description\": \"W3C Data Integrity proof. Spec body pins cryptosuite and proofPurpose; this schema permits the standard property bag so future cryptosuites can ride the same shape.\",\n \"properties\": {\n \"created\": {\n \"format\": \"date-time\",\n \"type\": \"string\"\n },\n \"cryptosuite\": {\n \"description\": \"This version pins `eddsa-jcs-2022`. Maintainers MUST reject other values until a future minor extends the allowlist.\",\n \"minLength\": 1,\n \"type\": \"string\"\n },\n \"proofPurpose\": {\n \"const\": \"authentication\"\n },\n \"proofValue\": {\n \"description\": \"Multibase-encoded Ed25519 signature.\",\n \"minLength\": 1,\n \"type\": \"string\"\n },\n \"type\": {\n \"const\": \"DataIntegrityProof\"\n },\n \"verificationMethod\": {\n \"description\": \"DID URL with fragment. The DID portion (left of `#`) MUST equal `holder`.\",\n \"minLength\": 1,\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 \"DidTemplateRef\": {\n \"$anchor\": \"did-template-ref\",\n \"additionalProperties\": false,\n \"description\": \"Reference to a DID template already registered at the maintainer. Inline template definitions are deliberately not supported — templates must be uploaded out-of-band first (operator-authored or built-in) so the maintainer can validate `vars` against the template's declared schema.\",\n \"properties\": {\n \"name\": {\n \"description\": \"Template name as registered at the maintainer (built-in or operator-uploaded). Examples of built-ins shipped with VTA deployments: `didcomm-mediator`, `vta-admin`, `did-hosting-control`, `did-hosting-daemon`, `did-hosting-server`.\",\n \"maxLength\": 128,\n \"minLength\": 1,\n \"type\": \"string\"\n },\n \"vars\": {\n \"additionalProperties\": true,\n \"default\": {},\n \"description\": \"Variable bindings the maintainer feeds to the template renderer. MUST satisfy the template's `requiredVars`; values for `optionalVars` MAY be supplied. Unknown vars are rejected with `provision/integration:template_vars_invalid`.\",\n \"type\": \"object\"\n }\n },\n \"required\": [\n \"name\"\n ],\n \"title\": \"DidTemplateRef\",\n \"type\": \"object\"\n },\n \"Ext\": {\n \"additionalProperties\": true,\n \"description\": \"Vendor-namespaced extension object per SPEC.md §4.5.1. Each immediate key MUST be a reverse-DNS namespace; structure under each namespace is opaque to the framework.\",\n \"minProperties\": 1,\n \"propertyNames\": {\n \"pattern\": \"^[a-z][a-z0-9-]*(\\\\.[a-z0-9-]+)+$\"\n },\n \"title\": \"Ext\",\n \"type\": \"object\"\n },\n \"ProvisionSummary\": {\n \"$anchor\": \"provision-summary\",\n \"additionalProperties\": false,\n \"description\": \"Audit-grade metadata about the provisioning outcome. Mirrors the existing `vta_sdk::provision_integration::http::ProvisionSummary` Rust type but uses camelCase wire fields per Trust Task convention.\",\n \"properties\": {\n \"adminDid\": {\n \"description\": \"Long-term admin DID after this provisioning. Equals `clientDid` when no admin rollover occurred (TemplateBootstrap with no `adminTemplate`); equals the freshly-minted admin DID when `adminTemplate` was used or when the ask was `AdminRotation`. Maintainers that pre-date admin rollover MAY omit this; consumers SHOULD default it to `clientDid` for backward compatibility.\",\n \"minLength\": 1,\n \"type\": \"string\"\n },\n \"adminRolledOver\": {\n \"default\": false,\n \"description\": \"True when the maintainer minted a fresh long-term admin DID and bound the authorization VC + ACL row to it (i.e. `adminDid != clientDid`).\",\n \"type\": \"boolean\"\n },\n \"adminTemplateName\": {\n \"description\": \"Name of the admin template that was rendered. Present when an admin DID was minted (either via `TemplateBootstrap.adminTemplate` or `AdminRotation`).\",\n \"minLength\": 1,\n \"type\": \"string\"\n },\n \"bundleIdHex\": {\n \"description\": \"VP nonce as lowercase hex (32 characters = 16 bytes). MUST equal the `Bundle-Id` armor header of `bundle`. Cross-check anchor: a holder that decodes the VP nonce can verify the bundle they opened matches the one the maintainer minted for them.\",\n \"pattern\": \"^[0-9a-f]{32}$\",\n \"type\": \"string\"\n },\n \"clientDid\": {\n \"description\": \"Ephemeral did:key the holder signed the VP with and opens the sealed bundle with. Echo of `request.holder`.\",\n \"minLength\": 1,\n \"type\": \"string\"\n },\n \"contextCreated\": {\n \"default\": false,\n \"description\": \"True when `payload.createContext` was honoured and the maintainer provisioned the target context inline. False when the context already existed (or when `createContext` was omitted / false).\",\n \"type\": \"boolean\"\n },\n \"integrationDid\": {\n \"description\": \"DID rendered from the integration template. Absent for `AdminRotation` (no integration was rendered).\",\n \"minLength\": 1,\n \"type\": \"string\"\n },\n \"outputCount\": {\n \"description\": \"Number of template-declared side outputs the sealed bundle carries (`did.jsonl` logs, DIDComm service advertisements, etc.). Always 0 for `AdminRotation`.\",\n \"minimum\": 0,\n \"type\": \"integer\"\n },\n \"secretCount\": {\n \"description\": \"Number of DIDs the sealed bundle carries private key material for. `TemplateBootstrap` with no adminTemplate typically yields 1 (the integration DID's keys). `AdminRotation` yields 0 (the `admin` field is top-level, not under `secrets`).\",\n \"minimum\": 0,\n \"type\": \"integer\"\n },\n \"templateKind\": {\n \"description\": \"`kind` of the integration template (e.g. `mediator`, `did-hosting-control`, `app`). Absent for `AdminRotation`.\",\n \"minLength\": 1,\n \"type\": \"string\"\n },\n \"templateName\": {\n \"description\": \"Name of the integration template that was rendered. Absent for `AdminRotation`.\",\n \"minLength\": 1,\n \"type\": \"string\"\n },\n \"webvhServerId\": {\n \"description\": \"Identifier of the registered webvh hosting server the maintainer published the integration's `did.jsonl` to, if any. Absent when the integration is self-hosted or when the template did not declare a webvh server var.\",\n \"minLength\": 1,\n \"type\": \"string\"\n }\n },\n \"required\": [\n \"clientDid\",\n \"bundleIdHex\",\n \"secretCount\",\n \"outputCount\"\n ],\n \"title\": \"ProvisionSummary\",\n \"type\": \"object\"\n },\n \"Response\": {\n \"$anchor\": \"response\",\n \"additionalProperties\": false,\n \"description\": \"Carried in a Trust Task document whose type is https://trusttasks.org/spec/provision/integration/0.1#response. The sealed `bundle` is the secret-bearing artefact; `summary` is non-secret audit metadata.\",\n \"properties\": {\n \"bundle\": {\n \"description\": \"OpenPGP-style ASCII-armored ciphertext of `SealedPayloadV1`. HPKE base mode, X25519-HKDF-SHA256 KEM, ChaCha20-Poly1305 AEAD, info string `vta-sealed-transfer/v1`. Recipient is the X25519 derivation of `request.holder`'s Ed25519 pubkey.\",\n \"minLength\": 1,\n \"type\": \"string\"\n },\n \"digest\": {\n \"description\": \"SHA-256 of the armored ciphertext, lowercase hex. Used by holders that pin the bundle out-of-band.\",\n \"pattern\": \"^[0-9a-f]{64}$\",\n \"type\": \"string\"\n },\n \"ext\": {\n \"$ref\": \"#/$defs/Ext\"\n },\n \"summary\": {\n \"$ref\": \"#/$defs/ProvisionSummary\",\n \"description\": \"Non-secret audit metadata. MUST NOT include any private key material; the bundle is the only secret-bearing field.\"\n }\n },\n \"required\": [\n \"bundle\",\n \"digest\",\n \"summary\"\n ],\n \"title\": \"Provision Integration — response payload\",\n \"type\": \"object\"\n },\n \"TemplateBootstrapAsk\": {\n \"$anchor\": \"template-bootstrap-ask\",\n \"additionalProperties\": false,\n \"description\": \"Mint an integration DID from `template`, and (when `adminTemplate` is present) atomically roll over the holder to a fresh long-term admin DID minted from `adminTemplate`.\",\n \"properties\": {\n \"adminTemplate\": {\n \"$ref\": \"#/$defs/DidTemplateRef\",\n \"description\": \"Optional admin-DID template. When present, the maintainer mints a fresh long-term admin DID + keys, binds the authorization VC + ACL row to it, and rolls the holder over from the ephemeral did:key in the same transaction. When absent, the authorization VC's subject and ACL row are bound to the ephemeral `holder`, which the operator is expected to swap via `acl/swap-key/0.1` before steady-state operation. MUST declare `kind == \\\"admin\\\"` when present.\"\n },\n \"contextHint\": {\n \"description\": \"Hint for the integration's target context. The wire `payload.context` is authoritative; this hint exists for documentation / cross-check only.\",\n \"minLength\": 1,\n \"type\": \"string\"\n },\n \"note\": {\n \"description\": \"Free-form operator note carried into the maintainer's audit log.\",\n \"maxLength\": 1024,\n \"minLength\": 1,\n \"type\": \"string\"\n },\n \"template\": {\n \"$ref\": \"#/$defs/DidTemplateRef\",\n \"description\": \"Integration template. MUST be registered at the maintainer; MUST declare a `kind` other than `\\\"admin\\\"`.\"\n },\n \"type\": {\n \"const\": \"TemplateBootstrap\"\n }\n },\n \"required\": [\n \"type\",\n \"template\"\n ],\n \"title\": \"TemplateBootstrapAsk\",\n \"type\": \"object\"\n }\n },\n \"$id\": \"https://trusttasks.org/spec/provision/integration/0.1\",\n \"$schema\": \"https://json-schema.org/draft/2020-12/schema\",\n \"additionalProperties\": false,\n \"description\": \"Relayer presents a VP-signed bootstrap request from an integration holder; the maintainer mints the integration's DIDs and admin credential from a registered DID template and ships the material back HPKE-sealed to the holder's ephemeral did:key. Two ask variants are supported: TemplateBootstrap (mint integration DID + optional admin DID) and AdminRotation (mint only the long-term admin DID).\",\n \"properties\": {\n \"assertion\": {\n \"default\": \"did-signed\",\n \"description\": \"Producer-assertion mode the maintainer should apply to the returned sealed bundle. `did-signed` (default) — Ed25519 signature over the bundle's domain-bound digest, verified by the holder against the maintainer's published key. `pinned-only` — holder pins the bundle's SHA-256 digest as the sole integrity anchor; for dev/test only. Maintainers MAY support additional modes (e.g. `attested` for TEE deployments) and respond with `provision/integration:assertion_unsupported` to unsupported requests.\",\n \"enum\": [\n \"did-signed\",\n \"pinned-only\"\n ],\n \"type\": \"string\"\n },\n \"context\": {\n \"description\": \"The maintainer's context identifier the integration is to be provisioned into. When present, authoritative — overrides any `contextHint` carried inside `request.ask`. When ABSENT, the maintainer infers the target context using these rules in order: (1) if the relayer's grant scopes to exactly one context, use that context; (2) if the relayer is a super-admin (Admin role with unrestricted scope) and the maintainer has exactly one context registered, use that context; (3) otherwise reject the request with `provision/integration:context_required`. Wallet-class consumers (browser plugins, mobile companions) that don't know the maintainer's context layout SHOULD omit this field; integration-class consumers (mediator, did-hosting) targeting a specific operational context SHOULD send it explicitly.\",\n \"minLength\": 1,\n \"type\": \"string\"\n },\n \"createContext\": {\n \"default\": false,\n \"description\": \"When `true`, the maintainer provisions the target context inline if it does not already exist. Requires super-admin role on the maintainer; context-admin callers MUST receive `provision/integration:forbidden` against a missing context. Idempotent when the context already exists.\",\n \"type\": \"boolean\"\n },\n \"ext\": {\n \"$ref\": \"#/$defs/Ext\",\n \"description\": \"Ecosystem-defined extension members per SPEC.md §4.5.1.\"\n },\n \"request\": {\n \"$ref\": \"#/$defs/BootstrapRequest\",\n \"description\": \"VP-framed bootstrap request signed by the holder's ephemeral did:key. The proof here is independent of, and additional to, the outer Trust Task envelope's proof — it authenticates the holder (the party the sealed bundle is encrypted for), whereas the envelope's proof authenticates the relayer (the party making the call). The two MAY be the same DID in the common case.\"\n },\n \"vcValiditySeconds\": {\n \"description\": \"Caller-preferred validity window for the issued VtaAuthorizationCredential, in seconds. The maintainer's policy applies a floor and ceiling; values outside that range MAY be silently clamped. Defaults to the maintainer's policy default (typically 3600s).\",\n \"maximum\": 31536000,\n \"minimum\": 1,\n \"type\": \"integer\"\n }\n },\n \"required\": [\n \"request\"\n ],\n \"title\": \"Provision Integration — payload\",\n \"type\": \"object\"\n}\n";
}
#[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).
/// 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)] = &[
("Missing required request VP.", "{\n \"context\": \"default\"\n}"),
(
"Missing required context.",
"{\n \"request\": {\n \"@context\": [\n \"https://www.w3.org/ns/credentials/v2\",\n \"https://openvtc.org/contexts/bootstrap-v1\"\n ],\n \"ask\": {\n \"adminTemplate\": {\n \"name\": \"vta-admin\"\n },\n \"type\": \"AdminRotation\"\n },\n \"holder\": \"did:key:z6MkpTH1234567890123456789012345678901234567890\",\n \"id\": \"urn:uuid:0e1f2a-1111-2222-3333-444455556666\",\n \"nonce\": \"RmFrZU5vbmNlVmFsdWVYWFg\",\n \"proof\": {\n \"cryptosuite\": \"eddsa-jcs-2022\",\n \"proofPurpose\": \"authentication\",\n \"proofValue\": \"z3kg\",\n \"type\": \"DataIntegrityProof\",\n \"verificationMethod\": \"did:key:z6MkpTH1234567890123456789012345678901234567890#z6MkpTH1234567890123456789012345678901234567890\"\n },\n \"type\": [\n \"VerifiablePresentation\",\n \"BootstrapRequest\"\n ],\n \"validUntil\": \"2026-05-26T13:15:00Z\"\n }\n}",
),
(
"Unknown top-level payload member (additionalProperties: false catches `extras`).",
"{\n \"context\": \"default\",\n \"extras\": {\n \"anything\": \"here\"\n },\n \"request\": {\n \"@context\": [\n \"https://www.w3.org/ns/credentials/v2\",\n \"https://openvtc.org/contexts/bootstrap-v1\"\n ],\n \"ask\": {\n \"adminTemplate\": {\n \"name\": \"vta-admin\"\n },\n \"type\": \"AdminRotation\"\n },\n \"holder\": \"did:key:z6MkpTH1234567890123456789012345678901234567890\",\n \"id\": \"urn:uuid:0e1f2a-1111-2222-3333-444455556666\",\n \"nonce\": \"RmFrZU5vbmNlVmFsdWVYWFg\",\n \"proof\": {\n \"cryptosuite\": \"eddsa-jcs-2022\",\n \"proofPurpose\": \"authentication\",\n \"proofValue\": \"z3kg\",\n \"type\": \"DataIntegrityProof\",\n \"verificationMethod\": \"did:key:z6MkpTH1234567890123456789012345678901234567890#z6MkpTH1234567890123456789012345678901234567890\"\n },\n \"type\": [\n \"VerifiablePresentation\",\n \"BootstrapRequest\"\n ],\n \"validUntil\": \"2026-05-26T13:15:00Z\"\n }\n}",
),
(
"assertion outside the enum.",
"{\n \"assertion\": \"attested\",\n \"context\": \"default\",\n \"request\": {\n \"@context\": [\n \"https://www.w3.org/ns/credentials/v2\",\n \"https://openvtc.org/contexts/bootstrap-v1\"\n ],\n \"ask\": {\n \"adminTemplate\": {\n \"name\": \"vta-admin\"\n },\n \"type\": \"AdminRotation\"\n },\n \"holder\": \"did:key:z6MkpTH1234567890123456789012345678901234567890\",\n \"id\": \"urn:uuid:0e1f2a-1111-2222-3333-444455556666\",\n \"nonce\": \"RmFrZU5vbmNlVmFsdWVYWFg\",\n \"proof\": {\n \"cryptosuite\": \"eddsa-jcs-2022\",\n \"proofPurpose\": \"authentication\",\n \"proofValue\": \"z3kg\",\n \"type\": \"DataIntegrityProof\",\n \"verificationMethod\": \"did:key:z6MkpTH1234567890123456789012345678901234567890#z6MkpTH1234567890123456789012345678901234567890\"\n },\n \"type\": [\n \"VerifiablePresentation\",\n \"BootstrapRequest\"\n ],\n \"validUntil\": \"2026-05-26T13:15:00Z\"\n }\n}",
),
(
"BootstrapRequest.holder is not a did:key.",
"{\n \"context\": \"default\",\n \"request\": {\n \"@context\": [\n \"https://www.w3.org/ns/credentials/v2\",\n \"https://openvtc.org/contexts/bootstrap-v1\"\n ],\n \"ask\": {\n \"adminTemplate\": {\n \"name\": \"vta-admin\"\n },\n \"type\": \"AdminRotation\"\n },\n \"holder\": \"did:web:alice.example\",\n \"id\": \"urn:uuid:0e1f2a-1111-2222-3333-444455556666\",\n \"nonce\": \"RmFrZU5vbmNlVmFsdWVYWFg\",\n \"proof\": {\n \"cryptosuite\": \"eddsa-jcs-2022\",\n \"proofPurpose\": \"authentication\",\n \"proofValue\": \"z3kg\",\n \"type\": \"DataIntegrityProof\",\n \"verificationMethod\": \"did:web:alice.example#key-1\"\n },\n \"type\": [\n \"VerifiablePresentation\",\n \"BootstrapRequest\"\n ],\n \"validUntil\": \"2026-05-26T13:15:00Z\"\n }\n}",
),
(
"BootstrapRequest.nonce wrong length (base64url-no-pad of 16 bytes is exactly 22 chars).",
"{\n \"context\": \"default\",\n \"request\": {\n \"@context\": [\n \"https://www.w3.org/ns/credentials/v2\",\n \"https://openvtc.org/contexts/bootstrap-v1\"\n ],\n \"ask\": {\n \"adminTemplate\": {\n \"name\": \"vta-admin\"\n },\n \"type\": \"AdminRotation\"\n },\n \"holder\": \"did:key:z6MkpTH1234567890123456789012345678901234567890\",\n \"id\": \"urn:uuid:0e1f2a-1111-2222-3333-444455556666\",\n \"nonce\": \"short\",\n \"proof\": {\n \"cryptosuite\": \"eddsa-jcs-2022\",\n \"proofPurpose\": \"authentication\",\n \"proofValue\": \"z3kg\",\n \"type\": \"DataIntegrityProof\",\n \"verificationMethod\": \"did:key:z6MkpTH1234567890123456789012345678901234567890#z6MkpTH1234567890123456789012345678901234567890\"\n },\n \"type\": [\n \"VerifiablePresentation\",\n \"BootstrapRequest\"\n ],\n \"validUntil\": \"2026-05-26T13:15:00Z\"\n }\n}",
),
(
"ask.type unknown — discriminated union rejects.",
"{\n \"context\": \"default\",\n \"request\": {\n \"@context\": [\n \"https://www.w3.org/ns/credentials/v2\",\n \"https://openvtc.org/contexts/bootstrap-v1\"\n ],\n \"ask\": {\n \"adminTemplate\": {\n \"name\": \"vta-admin\"\n },\n \"type\": \"WildGuess\"\n },\n \"holder\": \"did:key:z6MkpTH1234567890123456789012345678901234567890\",\n \"id\": \"urn:uuid:0e1f2a-1111-2222-3333-444455556666\",\n \"nonce\": \"RmFrZU5vbmNlVmFsdWVYWFg\",\n \"proof\": {\n \"cryptosuite\": \"eddsa-jcs-2022\",\n \"proofPurpose\": \"authentication\",\n \"proofValue\": \"z3kg\",\n \"type\": \"DataIntegrityProof\",\n \"verificationMethod\": \"did:key:z6MkpTH1234567890123456789012345678901234567890#z6MkpTH1234567890123456789012345678901234567890\"\n },\n \"type\": [\n \"VerifiablePresentation\",\n \"BootstrapRequest\"\n ],\n \"validUntil\": \"2026-05-26T13:15:00Z\"\n }\n}",
),
(
"TemplateBootstrap ask missing required `template`.",
"{\n \"context\": \"default\",\n \"request\": {\n \"@context\": [\n \"https://www.w3.org/ns/credentials/v2\",\n \"https://openvtc.org/contexts/bootstrap-v1\"\n ],\n \"ask\": {\n \"adminTemplate\": {\n \"name\": \"vta-admin\"\n },\n \"type\": \"TemplateBootstrap\"\n },\n \"holder\": \"did:key:z6MkpTH1234567890123456789012345678901234567890\",\n \"id\": \"urn:uuid:0e1f2a-1111-2222-3333-444455556666\",\n \"nonce\": \"RmFrZU5vbmNlVmFsdWVYWFg\",\n \"proof\": {\n \"cryptosuite\": \"eddsa-jcs-2022\",\n \"proofPurpose\": \"authentication\",\n \"proofValue\": \"z3kg\",\n \"type\": \"DataIntegrityProof\",\n \"verificationMethod\": \"did:key:z6MkpTH1234567890123456789012345678901234567890#z6MkpTH1234567890123456789012345678901234567890\"\n },\n \"type\": [\n \"VerifiablePresentation\",\n \"BootstrapRequest\"\n ],\n \"validUntil\": \"2026-05-26T13:15:00Z\"\n }\n}",
),
(
"AdminRotation ask missing required `adminTemplate`.",
"{\n \"context\": \"default\",\n \"request\": {\n \"@context\": [\n \"https://www.w3.org/ns/credentials/v2\",\n \"https://openvtc.org/contexts/bootstrap-v1\"\n ],\n \"ask\": {\n \"type\": \"AdminRotation\"\n },\n \"holder\": \"did:key:z6MkpTH1234567890123456789012345678901234567890\",\n \"id\": \"urn:uuid:0e1f2a-1111-2222-3333-444455556666\",\n \"nonce\": \"RmFrZU5vbmNlVmFsdWVYWFg\",\n \"proof\": {\n \"cryptosuite\": \"eddsa-jcs-2022\",\n \"proofPurpose\": \"authentication\",\n \"proofValue\": \"z3kg\",\n \"type\": \"DataIntegrityProof\",\n \"verificationMethod\": \"did:key:z6MkpTH1234567890123456789012345678901234567890#z6MkpTH1234567890123456789012345678901234567890\"\n },\n \"type\": [\n \"VerifiablePresentation\",\n \"BootstrapRequest\"\n ],\n \"validUntil\": \"2026-05-26T13:15:00Z\"\n }\n}",
),
(
"DataIntegrityProof.proofPurpose must be `authentication`.",
"{\n \"context\": \"default\",\n \"request\": {\n \"@context\": [\n \"https://www.w3.org/ns/credentials/v2\",\n \"https://openvtc.org/contexts/bootstrap-v1\"\n ],\n \"ask\": {\n \"adminTemplate\": {\n \"name\": \"vta-admin\"\n },\n \"type\": \"AdminRotation\"\n },\n \"holder\": \"did:key:z6MkpTH1234567890123456789012345678901234567890\",\n \"id\": \"urn:uuid:0e1f2a-1111-2222-3333-444455556666\",\n \"nonce\": \"RmFrZU5vbmNlVmFsdWVYWFg\",\n \"proof\": {\n \"cryptosuite\": \"eddsa-jcs-2022\",\n \"proofPurpose\": \"assertionMethod\",\n \"proofValue\": \"z3kg\",\n \"type\": \"DataIntegrityProof\",\n \"verificationMethod\": \"did:key:z6MkpTH1234567890123456789012345678901234567890#z6MkpTH1234567890123456789012345678901234567890\"\n },\n \"type\": [\n \"VerifiablePresentation\",\n \"BootstrapRequest\"\n ],\n \"validUntil\": \"2026-05-26T13:15:00Z\"\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
);
}
}
}