use crate::keys::{KeyOrigin, KeyRecord, KeyStatus, KeyType};
use chrono::{DateTime, Utc};
use serde::{Deserialize, Serialize};
#[derive(Debug, Deserialize)]
#[allow(dead_code)]
pub struct HealthResponse {
pub status: String,
#[serde(default)]
pub version: Option<String>,
#[serde(default)]
pub mediator_url: Option<String>,
#[serde(default)]
pub mediator_did: Option<String>,
}
#[derive(Debug, Deserialize)]
#[non_exhaustive]
pub struct ConfigResponse {
#[serde(flatten)]
pub config: crate::protocols::vta_management::get_config::GetConfigResultBody,
}
impl ConfigResponse {
pub fn vta_did(&self) -> Option<&str> {
self.config.vta_did()
}
pub fn public_url(&self) -> Option<&str> {
self.config.get("public_url").and_then(|v| v.as_str())
}
pub fn vta_name(&self) -> Option<&str> {
self.config.get("vta_name").and_then(|v| v.as_str())
}
}
#[derive(Debug, Serialize)]
pub struct UpdateConfigRequest {
#[serde(flatten)]
pub patch: crate::protocols::vta_management::update_config::UpdateConfigBody,
}
#[derive(Serialize)]
#[must_use]
pub struct CreateKeyRequest {
pub key_type: KeyType,
#[serde(skip_serializing_if = "Option::is_none")]
pub derivation_path: Option<String>,
#[serde(skip_serializing_if = "Option::is_none")]
pub key_id: Option<String>,
#[serde(skip_serializing_if = "Option::is_none")]
pub mnemonic: Option<String>,
#[serde(skip_serializing_if = "Option::is_none")]
pub label: Option<String>,
#[serde(skip_serializing_if = "Option::is_none")]
pub context_id: Option<String>,
#[serde(skip_serializing_if = "Option::is_none")]
pub internal: Option<bool>,
}
impl std::fmt::Debug for CreateKeyRequest {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
f.debug_struct("CreateKeyRequest")
.field("key_type", &self.key_type)
.field("derivation_path", &self.derivation_path)
.field("key_id", &self.key_id)
.field("mnemonic", &self.mnemonic.as_ref().map(|_| "<redacted>"))
.field("label", &self.label)
.field("context_id", &self.context_id)
.field("internal", &self.internal)
.finish()
}
}
impl CreateKeyRequest {
pub fn new(key_type: KeyType) -> Self {
Self {
internal: None,
key_type,
derivation_path: None,
key_id: None,
mnemonic: None,
label: None,
context_id: None,
}
}
pub fn derivation_path(mut self, path: impl Into<String>) -> Self {
self.derivation_path = Some(path.into());
self
}
pub fn key_id(mut self, id: impl Into<String>) -> Self {
self.key_id = Some(id.into());
self
}
pub fn mnemonic(mut self, m: impl Into<String>) -> Self {
self.mnemonic = Some(m.into());
self
}
pub fn label(mut self, label: impl Into<String>) -> Self {
self.label = Some(label.into());
self
}
pub fn context(mut self, ctx: impl Into<String>) -> Self {
self.context_id = Some(ctx.into());
self
}
}
#[derive(Serialize)]
pub struct ImportKeyRequest {
pub key_type: KeyType,
#[serde(skip_serializing_if = "Option::is_none")]
pub private_key_sealed: Option<String>,
#[serde(skip_serializing_if = "Option::is_none")]
pub private_key_jwe: Option<String>,
#[serde(skip_serializing_if = "Option::is_none")]
pub private_key_multibase: Option<String>,
#[serde(skip_serializing_if = "Option::is_none")]
pub label: Option<String>,
#[serde(skip_serializing_if = "Option::is_none")]
pub context_id: Option<String>,
}
impl std::fmt::Debug for ImportKeyRequest {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
f.debug_struct("ImportKeyRequest")
.field("key_type", &self.key_type)
.field(
"private_key_sealed",
&self.private_key_sealed.as_ref().map(|_| "<redacted>"),
)
.field(
"private_key_jwe",
&self.private_key_jwe.as_ref().map(|_| "<redacted>"),
)
.field(
"private_key_multibase",
&self.private_key_multibase.as_ref().map(|_| "<redacted>"),
)
.field("label", &self.label)
.field("context_id", &self.context_id)
.finish()
}
}
#[derive(Debug, Deserialize)]
#[non_exhaustive]
pub struct ImportKeyResponse {
pub key_id: String,
pub key_type: KeyType,
pub public_key: String,
pub status: KeyStatus,
pub label: Option<String>,
pub origin: crate::keys::KeyOrigin,
pub created_at: chrono::DateTime<chrono::Utc>,
}
pub type WrappingKeyResponse = vti_specs::keys::import_wrapping_key::v0_1::Response;
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum RevokeSessions<'a> {
Session(&'a str),
AllMine,
Subject(&'a str),
}
#[derive(Debug, Serialize)]
#[must_use]
pub struct CreateContextRequest {
pub id: String,
pub name: String,
#[serde(skip_serializing_if = "Option::is_none")]
pub description: Option<String>,
#[serde(skip_serializing_if = "Option::is_none")]
pub parent: Option<String>,
}
impl CreateContextRequest {
pub fn new(id: impl Into<String>, name: impl Into<String>) -> Self {
Self {
id: id.into(),
name: name.into(),
description: None,
parent: None,
}
}
pub fn description(mut self, desc: impl Into<String>) -> Self {
self.description = Some(desc.into());
self
}
pub fn parent(mut self, parent: impl Into<String>) -> Self {
self.parent = Some(parent.into());
self
}
}
#[derive(Debug, Default, Serialize)]
#[serde(rename_all = "camelCase")]
pub struct UpdateContextRequest {
#[serde(skip_serializing_if = "Option::is_none")]
pub name: Option<String>,
#[serde(skip_serializing_if = "Option::is_none")]
pub did: Option<String>,
#[serde(skip_serializing_if = "Option::is_none")]
pub description: Option<String>,
#[serde(skip_serializing_if = "Option::is_none")]
pub context_policy: Option<crate::context_policy::ContextPolicy>,
}
#[derive(Debug, Serialize)]
pub struct UpdateContextDidRequest {
pub did: String,
}
pub use crate::protocols::context_management::create::CreateContextResultBody as ContextResponse;
pub use crate::protocols::context_management::list::ListContextsResultBody as ContextListResponse;
#[derive(Debug, Deserialize)]
pub struct CreateKeyResponse {
pub key_id: String,
pub key_type: KeyType,
pub derivation_path: String,
pub public_key: String,
pub status: KeyStatus,
pub label: Option<String>,
#[serde(default = "default_derived_origin")]
pub origin: KeyOrigin,
pub created_at: DateTime<Utc>,
}
fn default_derived_origin() -> KeyOrigin {
KeyOrigin::Derived
}
pub use crate::protocols::key_management::revoke::RevokeKeyResultBody as InvalidateKeyResponse;
#[derive(Debug, Serialize)]
pub struct RenameKeyRequest {
pub key_id: String,
}
pub use crate::protocols::key_management::rename::RenameKeyResultBody as RenameKeyResponse;
pub use crate::protocols::key_management::secret::GetKeySecretResultBody as GetKeySecretResponse;
pub use crate::protocols::key_management::sign::SignResultBody as SignResponse;
#[derive(Debug, Deserialize, Serialize)]
#[non_exhaustive]
pub struct ListKeysResponse {
pub keys: Vec<KeyRecord>,
#[serde(
default,
rename = "nextCursor",
skip_serializing_if = "Option::is_none"
)]
pub next_cursor: Option<String>,
}
#[derive(Debug, Deserialize)]
pub struct ErrorResponse {
pub error: String,
}
pub use crate::protocols::seed_management::list::SeedInfo as SeedInfoResponse;
pub use crate::protocols::seed_management::list::ListSeedsResultBody as ListSeedsResponse;
#[derive(Serialize)]
pub struct RotateSeedRequest {
#[serde(skip_serializing_if = "Option::is_none")]
pub mnemonic: Option<String>,
}
impl std::fmt::Debug for RotateSeedRequest {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
f.debug_struct("RotateSeedRequest")
.field("mnemonic", &self.mnemonic.as_ref().map(|_| "<redacted>"))
.finish()
}
}
pub use crate::protocols::seed_management::rotate::RotateSeedResultBody as RotateSeedResponse;
#[derive(Debug, Deserialize, Serialize)]
#[serde(rename_all = "camelCase", try_from = "WireAclEntry")]
pub struct AclEntryResponse {
#[serde(rename = "subject")]
pub did: String,
pub role: String,
#[serde(default)]
pub label: Option<String>,
#[serde(rename = "scopes", default)]
pub allowed_contexts: Vec<String>,
#[serde(default, serialize_with = "ser_epoch")]
pub created_at: u64,
#[serde(default)]
pub created_by: String,
#[serde(default, serialize_with = "ser_epoch_opt")]
pub expires_at: Option<u64>,
#[serde(
default,
rename = "allowedKeys",
skip_serializing_if = "Option::is_none"
)]
pub allowed_keys: Option<Vec<String>>,
#[serde(default, rename = "stepUp")]
step_up: Option<StepUpWire>,
#[serde(default)]
approve: Option<ApproveWire>,
#[serde(default, skip_serializing_if = "Option::is_none")]
ext: Option<serde_json::Value>,
#[serde(skip)]
act: crate::acl::ActScope,
}
#[derive(Deserialize)]
#[serde(untagged)]
enum WireAclEntry {
V02(crate::protocols::acl_management::v0_2::AclEntry),
V01(crate::protocols::acl_management::entry::AclEntry),
}
impl TryFrom<WireAclEntry> for AclEntryResponse {
type Error = String;
fn try_from(e: WireAclEntry) -> Result<Self, String> {
match e {
WireAclEntry::V02(e) => Self::try_from(e),
WireAclEntry::V01(e) => {
let admin = e.role == "admin";
let act = if !e.scopes.is_empty() {
crate::acl::ActScope::Contexts(e.scopes.clone())
} else if admin {
crate::acl::ActScope::All
} else {
crate::acl::ActScope::None
};
let epoch =
|t: chrono::DateTime<chrono::Utc>| u64::try_from(t.timestamp()).unwrap_or(0);
Ok(Self {
did: e.subject,
role: e.role,
label: e.label,
allowed_contexts: e.scopes,
created_at: e.created_at.map(epoch).unwrap_or(0),
created_by: e.created_by.unwrap_or_default(),
expires_at: e.expires_at.map(epoch),
allowed_keys: e.allowed_keys,
step_up: e.step_up.map(|s| StepUpWire {
approver: s.approver,
require: s.require,
}),
approve: e.approve.map(|a| ApproveWire {
all: a.all,
scopes: a.scopes,
}),
ext: e.ext,
act,
})
}
}
}
}
impl TryFrom<crate::protocols::acl_management::v0_2::AclEntry> for AclEntryResponse {
type Error = String;
fn try_from(e: crate::protocols::acl_management::v0_2::AclEntry) -> Result<Self, String> {
use crate::protocols::acl_management::entry::capabilities_into_ext;
use crate::protocols::acl_management::v0_2::{
ApproveCapabilityScope, AuthorityScope, CapabilityScope,
};
let admin = e.role == "admin";
let allowed_contexts = match &e.act {
AuthorityScope::Contexts { contexts } => contexts.clone(),
AuthorityScope::All if admin => Vec::new(),
AuthorityScope::None if !admin => Vec::new(),
other => {
return Err(format!(
"{}: act {other:?} on role {} has no form in a VTA's ACL model",
e.subject, e.role
));
}
};
let capabilities: Vec<String> = match &e.capabilities {
CapabilityScope::Ceiling => Vec::new(),
CapabilityScope::Listed { grants } => {
grants.iter().map(|g| g.capability.clone()).collect()
}
CapabilityScope::None => {
return Err(format!(
"{}: `capabilities: none` has no form in a VTA's ACL model",
e.subject
));
}
};
let approve_scope = match e.approve_capabilities {
Some(ApproveCapabilityScope::Ceiling) => e.approve_scope(),
_ => crate::acl::ApproveScope::None,
};
let approve = match &approve_scope {
crate::acl::ApproveScope::None => None,
crate::acl::ApproveScope::All => Some(ApproveWire {
all: true,
scopes: Vec::new(),
}),
crate::acl::ApproveScope::Contexts(cs) => Some(ApproveWire {
all: false,
scopes: cs.clone(),
}),
};
let epoch = |t: chrono::DateTime<chrono::Utc>| u64::try_from(t.timestamp()).unwrap_or(0);
Ok(Self {
did: e.subject,
role: e.role,
label: e.label,
allowed_contexts,
created_at: e.created_at.map(epoch).unwrap_or(0),
created_by: e.created_by.unwrap_or_default(),
expires_at: e.expires_at.map(epoch),
allowed_keys: e.keys.to_allowed_keys(),
step_up: e.step_up.map(|s| StepUpWire {
approver: s.approver,
require: s.require,
}),
approve,
ext: capabilities_into_ext(e.ext, &capabilities),
act: e.act.to_act_scope(),
})
}
}
impl AclEntryResponse {
pub fn act(&self) -> &crate::acl::ActScope {
&self.act
}
pub fn capabilities(&self) -> Vec<String> {
crate::protocols::acl_management::entry::capabilities_from_ext(self.ext.as_ref())
.ok()
.flatten()
.unwrap_or_default()
}
pub fn handoff(&self) -> bool {
crate::protocols::acl_management::entry::handoff_from_ext(self.ext.as_ref())
.unwrap_or(false)
}
}
#[derive(Debug, Default, Deserialize, Serialize)]
#[serde(rename_all = "camelCase")]
struct StepUpWire {
#[serde(default)]
approver: Option<String>,
#[serde(default)]
require: Option<String>,
}
#[derive(Debug, Default, Deserialize, Serialize)]
#[serde(rename_all = "camelCase")]
struct ApproveWire {
#[serde(default)]
all: bool,
#[serde(default)]
scopes: Vec<String>,
}
impl AclEntryResponse {
pub fn step_up_require(&self) -> Option<&str> {
self.step_up.as_ref().and_then(|s| s.require.as_deref())
}
pub fn step_up_approver(&self) -> Option<&str> {
self.step_up.as_ref().and_then(|s| s.approver.as_deref())
}
pub fn approve_all_contexts(&self) -> bool {
self.approve.as_ref().is_some_and(|a| a.all)
}
pub fn approve_contexts(&self) -> &[String] {
self.approve.as_ref().map_or(&[], |a| a.scopes.as_slice())
}
}
fn ser_epoch<S: serde::Serializer>(v: &u64, s: S) -> Result<S::Ok, S::Error> {
ser_epoch_opt(&Some(*v), s)
}
fn ser_epoch_opt<S: serde::Serializer>(v: &Option<u64>, s: S) -> Result<S::Ok, S::Error> {
use chrono::{TimeZone, Utc};
match v.and_then(|e| {
i64::try_from(e)
.ok()
.and_then(|x| Utc.timestamp_opt(x, 0).single())
}) {
Some(t) => s.serialize_str(&t.to_rfc3339()),
None => s.serialize_none(),
}
}
#[derive(Debug, Deserialize)]
pub(crate) struct AclEntryEnvelope {
pub entry: AclEntryResponse,
}
#[derive(Debug, Deserialize)]
pub struct AclListResponse {
pub entries: Vec<AclEntryResponse>,
}
#[derive(Debug, Deserialize)]
#[serde(rename_all = "camelCase")]
pub(crate) struct AclListPage {
pub entries: Vec<AclEntryResponse>,
#[serde(default)]
pub next_cursor: Option<String>,
}
#[derive(Debug, Deserialize)]
pub(crate) struct AclShowResponse {
pub entry: Option<AclEntryResponse>,
}
#[derive(Debug)]
#[must_use]
pub struct CreateAclRequest {
pub did: String,
pub role: String,
pub label: Option<String>,
pub allowed_contexts: Vec<String>,
pub expires_at: Option<u64>,
pub step_up_approver: Option<String>,
pub step_up_require: Option<String>,
pub approve_all_contexts: bool,
pub approve_contexts: Vec<String>,
pub allowed_keys: Option<Vec<String>>,
pub capabilities: Vec<String>,
pub handoff: bool,
}
impl CreateAclRequest {
pub fn to_entry_v0_2(&self) -> crate::protocols::acl_management::v0_2::AclEntry {
use crate::protocols::acl_management::entry::StepUp;
use crate::protocols::acl_management::v0_2::{
AclEntry, ApproveCapabilityScope, AuthorityScope, KeyScope,
};
use chrono::{TimeZone, Utc};
let act = act_for(&self.role, &self.allowed_contexts);
let mut entry = AclEntry::new(
self.did.clone(),
self.role.clone(),
act,
KeyScope::from_allowed_keys(self.allowed_keys.as_deref()),
capability_scope_for(&self.role, &self.capabilities),
);
entry.label = self.label.clone();
entry.expires_at = self.expires_at.and_then(|e| {
i64::try_from(e)
.ok()
.and_then(|s| Utc.timestamp_opt(s, 0).single())
});
let approve = if self.approve_all_contexts {
AuthorityScope::All
} else if self.approve_contexts.is_empty() {
AuthorityScope::None
} else {
AuthorityScope::Contexts {
contexts: self.approve_contexts.clone(),
}
};
if approve != AuthorityScope::None {
entry.approve_capabilities = Some(ApproveCapabilityScope::Ceiling);
}
entry.approve = Some(approve);
if self.step_up_approver.is_some() || self.step_up_require.is_some() {
entry.step_up = Some(StepUp {
approver: self.step_up_approver.clone(),
require: self.step_up_require.clone(),
});
}
entry.ext = crate::protocols::acl_management::entry::handoff_into_ext(None, self.handoff);
entry
}
}
pub(crate) fn act_for(
role: &str,
contexts: &[String],
) -> crate::protocols::acl_management::v0_2::AuthorityScope {
use crate::protocols::acl_management::v0_2::AuthorityScope;
if !contexts.is_empty() {
AuthorityScope::Contexts {
contexts: contexts.to_vec(),
}
} else if role == "admin" {
AuthorityScope::All
} else {
AuthorityScope::None
}
}
pub(crate) fn capability_scope_for(
role: &str,
names: &[String],
) -> crate::protocols::acl_management::v0_2::CapabilityScope {
use crate::protocols::acl_management::v0_2::{CapabilityGrant, CapabilityScope};
if names.is_empty() {
return CapabilityScope::Ceiling;
}
let additive = |n: &str| crate::acl::ADDITIVE_CAPABILITIES.contains(&n);
let mut grants: Vec<CapabilityGrant> = names
.iter()
.filter(|n| !additive(n))
.map(|n| CapabilityGrant::new(n.clone(), false))
.collect();
if grants.is_empty() {
grants = crate::acl::role_capability_ceiling(role)
.unwrap_or_default()
.iter()
.map(|n| CapabilityGrant::new(*n, false))
.collect();
}
grants.extend(
names
.iter()
.filter(|n| additive(n))
.map(|n| CapabilityGrant::new(n.clone(), true)),
);
CapabilityScope::Listed { grants }
}
impl serde::Serialize for CreateAclRequest {
fn serialize<S: serde::Serializer>(&self, s: S) -> Result<S::Ok, S::Error> {
crate::protocols::acl_management::v0_2::grant_payload(&self.to_entry_v0_2(), None, false)
.serialize(s)
}
}
impl CreateAclRequest {
pub fn new(did: impl Into<String>, role: impl Into<String>) -> Self {
Self {
did: did.into(),
role: role.into(),
label: None,
allowed_contexts: Vec::new(),
expires_at: None,
step_up_approver: None,
step_up_require: None,
approve_all_contexts: false,
approve_contexts: Vec::new(),
allowed_keys: None,
capabilities: Vec::new(),
handoff: false,
}
}
pub fn handoff(mut self) -> Self {
self.handoff = true;
self
}
pub fn label(mut self, label: impl Into<String>) -> Self {
self.label = Some(label.into());
self
}
pub fn contexts(mut self, contexts: Vec<String>) -> Self {
self.allowed_contexts = contexts;
self
}
pub fn expires_at(mut self, unix_secs: u64) -> Self {
self.expires_at = Some(unix_secs);
self
}
pub fn step_up_approver(mut self, approver: impl Into<String>) -> Self {
self.step_up_approver = Some(approver.into());
self
}
pub fn step_up_require(mut self, require: impl Into<String>) -> Self {
self.step_up_require = Some(require.into());
self
}
pub fn approve_all(mut self) -> Self {
self.approve_all_contexts = true;
self
}
pub fn approve_contexts(mut self, contexts: Vec<String>) -> Self {
self.approve_contexts = contexts;
self
}
pub fn allowed_keys(mut self, keys: Vec<String>) -> Self {
self.allowed_keys = Some(keys);
self
}
pub fn capabilities(mut self, capabilities: Vec<String>) -> Self {
self.capabilities = capabilities;
self
}
}
#[derive(Debug, Serialize)]
#[must_use]
pub struct SwapAclRequest {
pub presentation: String,
}
impl SwapAclRequest {
pub fn new(presentation: impl Into<String>) -> Self {
Self {
presentation: presentation.into(),
}
}
}
#[derive(Debug, Serialize)]
pub struct UpdateAclRequest {
#[serde(skip_serializing_if = "Option::is_none")]
pub label: Option<String>,
#[serde(skip_serializing_if = "Option::is_none")]
pub allowed_contexts: Option<Vec<String>>,
#[serde(skip_serializing_if = "Option::is_none")]
pub step_up_approver: Option<String>,
#[serde(skip_serializing_if = "Option::is_none")]
pub step_up_require: Option<String>,
#[serde(skip_serializing_if = "Option::is_none")]
pub approve_scope: Option<crate::acl::ApproveScope>,
#[serde(rename = "allowedKeys", skip_serializing_if = "Option::is_none")]
pub allowed_keys: Option<Option<Vec<String>>>,
#[serde(skip_serializing_if = "Option::is_none")]
pub capabilities: Option<Vec<String>>,
}
#[derive(Debug, Serialize)]
pub struct AddWebvhServerRequest {
pub id: String,
pub did: String,
#[serde(skip_serializing_if = "Option::is_none")]
pub label: Option<String>,
}
#[derive(Debug, Serialize)]
pub struct UpdateWebvhServerRequest {
#[serde(skip_serializing_if = "Option::is_none")]
pub label: Option<String>,
}
#[derive(Debug, Serialize)]
#[serde(rename_all = "camelCase")]
pub struct CreateDidWebvhRequest {
pub context_id: String,
#[serde(skip_serializing_if = "Option::is_none")]
pub server_id: Option<String>,
#[serde(skip_serializing_if = "Option::is_none")]
pub url: Option<String>,
#[serde(skip_serializing_if = "Option::is_none")]
pub path: Option<String>,
#[serde(skip_serializing_if = "Option::is_none")]
pub path_mode: Option<crate::protocols::did_management::create::WebvhPathMode>,
#[serde(skip_serializing_if = "Option::is_none")]
pub domain: Option<String>,
#[serde(skip_serializing_if = "Option::is_none")]
pub label: Option<String>,
pub portable: bool,
pub add_mediator_service: bool,
#[serde(skip_serializing_if = "std::ops::Not::not")]
pub add_tsp_service: bool,
#[serde(skip_serializing_if = "Option::is_none")]
pub additional_services: Option<Vec<serde_json::Value>>,
pub pre_rotation_count: u32,
#[serde(skip_serializing_if = "Option::is_none")]
pub did_document: Option<serde_json::Value>,
#[serde(skip_serializing_if = "Option::is_none")]
pub did_log: Option<String>,
pub set_primary: bool,
#[serde(skip_serializing_if = "Option::is_none")]
pub signing_key_id: Option<String>,
#[serde(skip_serializing_if = "Option::is_none")]
pub ka_key_id: Option<String>,
#[serde(skip_serializing_if = "Option::is_none")]
pub template: Option<String>,
#[serde(skip_serializing_if = "Option::is_none")]
pub template_context: Option<String>,
#[serde(default, skip_serializing_if = "std::collections::HashMap::is_empty")]
pub template_vars: std::collections::HashMap<String, serde_json::Value>,
}
#[derive(Debug, Clone, Copy, Default, PartialEq, Eq)]
#[non_exhaustive]
pub struct DidPresentation {
pub did_method: Option<crate::did_scid::DidMethod>,
pub scid_also_known_as: Option<bool>,
}
impl DidPresentation {
#[must_use]
pub fn did_method(mut self, method: crate::did_scid::DidMethod) -> Self {
self.did_method = Some(method);
self
}
#[must_use]
pub fn scid_also_known_as(mut self, listed: bool) -> Self {
self.scid_also_known_as = Some(listed);
self
}
pub fn is_stated(&self) -> bool {
self.did_method.is_some() || self.scid_also_known_as.is_some()
}
}
#[derive(Debug, Serialize)]
#[serde(rename_all = "camelCase")]
pub struct ChangeAclRoleRequest {
pub from_role: String,
pub to_role: String,
#[serde(skip_serializing_if = "Option::is_none")]
pub reason: Option<String>,
}
#[derive(Debug, Deserialize)]
#[non_exhaustive]
pub struct GetDidLogResponse {
pub did: String,
pub log: Option<String>,
}