use crate::didcomm_bridge::DIDCommBridge;
use crate::error::AppError;
use crate::webvh_client::RequestUriResponse;
const TASK_DID_CHECK_NAME: &str = "https://trusttasks.org/spec/did-management/did/check-name/0.1";
const TASK_DID_CHECK_NAME_RESPONSE: &str =
"https://trusttasks.org/spec/did-management/did/check-name/0.1#response";
const TASK_DID_PUBLISH: &str = "https://trusttasks.org/spec/did-management/did/publish/0.1";
const TASK_DID_PUBLISH_RESPONSE: &str =
"https://trusttasks.org/spec/did-management/did/publish/0.1#response";
const TASK_DID_REGISTER: &str = "https://trusttasks.org/spec/did-management/did/register/0.1";
const TASK_DID_REGISTER_RESPONSE: &str =
"https://trusttasks.org/spec/did-management/did/register/0.1#response";
const TASK_DID_DELETE: &str = "https://trusttasks.org/spec/did-management/did/delete/0.1";
const TASK_DID_DELETE_RESPONSE: &str =
"https://trusttasks.org/spec/did-management/did/delete/0.1#response";
const TASK_DID_PROBLEM_REPORT: &str =
"https://trusttasks.org/spec/did-management/did/problem-report/0.1";
pub struct WebvhDIDCommClient<'a> {
bridge: &'a DIDCommBridge,
server_did: &'a str,
}
impl<'a> WebvhDIDCommClient<'a> {
pub fn new(bridge: &'a DIDCommBridge, server_did: &'a str) -> Self {
Self { bridge, server_did }
}
pub async fn request_uri(
&self,
path: Option<&str>,
domain: Option<&str>,
) -> Result<RequestUriResponse, AppError> {
let mut body = serde_json::Map::new();
body.insert(
"path".to_string(),
serde_json::Value::String(path.unwrap_or("").to_string()),
);
body.insert("reserve".to_string(), serde_json::Value::Bool(true));
if let Some(d) = domain {
body.insert(
"domain".to_string(),
serde_json::Value::String(d.to_string()),
);
}
let response = self
.bridge
.send_and_wait(
self.server_did,
TASK_DID_CHECK_NAME,
serde_json::Value::Object(body),
TASK_DID_CHECK_NAME_RESPONSE,
TASK_DID_PROBLEM_REPORT,
30,
)
.await?;
let body: serde_json::Value = response.body;
let reserved = body
.get("reserved")
.and_then(|v| v.as_bool())
.unwrap_or(false);
if !reserved {
let available = body
.get("available")
.and_then(|v| v.as_bool())
.unwrap_or(false);
return Err(AppError::Internal(format!(
"remote refused reservation (available={available}); \
check-name with reserve=true expected to succeed"
)));
}
let mnemonic = body
.get("mnemonic")
.and_then(|v| v.as_str())
.ok_or_else(|| {
AppError::Internal("check-name response missing `mnemonic`".to_string())
})?
.to_string();
let did_url = body
.get("didUrl")
.or_else(|| body.get("did_url"))
.and_then(|v| v.as_str())
.ok_or_else(|| AppError::Internal("check-name response missing `didUrl`".to_string()))?
.to_string();
Ok(RequestUriResponse { mnemonic, did_url })
}
pub async fn register_did_atomic(
&self,
path: &str,
did_log: &str,
force: bool,
domain: Option<&str>,
) -> Result<RequestUriResponse, AppError> {
let mut body = serde_json::Map::new();
body.insert(
"path".to_string(),
serde_json::Value::String(path.to_string()),
);
body.insert(
"method".to_string(),
serde_json::Value::String("webvh".to_string()),
);
body.insert(
"didData".to_string(),
serde_json::Value::String(did_log.to_string()),
);
body.insert("force".to_string(), serde_json::Value::Bool(force));
if let Some(d) = domain {
body.insert(
"domain".to_string(),
serde_json::Value::String(d.to_string()),
);
}
let response = self
.bridge
.send_and_wait(
self.server_did,
TASK_DID_REGISTER,
serde_json::Value::Object(body),
TASK_DID_REGISTER_RESPONSE,
TASK_DID_PROBLEM_REPORT,
30,
)
.await?;
let record = response
.body
.get("record")
.cloned()
.or_else(|| {
Some(response.body.clone())
})
.unwrap_or(serde_json::Value::Null);
let mnemonic = record
.get("mnemonic")
.and_then(|v| v.as_str())
.ok_or_else(|| AppError::Internal("register response missing `mnemonic`".to_string()))?
.to_string();
let did_url = record
.get("didUrl")
.or_else(|| record.get("did_url"))
.and_then(|v| v.as_str())
.ok_or_else(|| AppError::Internal("register response missing `didUrl`".to_string()))?
.to_string();
Ok(RequestUriResponse { mnemonic, did_url })
}
pub async fn publish_did(
&self,
mnemonic: &str,
log_content: &str,
domain: Option<&str>,
) -> Result<(), AppError> {
let mut body = serde_json::Map::new();
body.insert(
"mnemonic".to_string(),
serde_json::Value::String(mnemonic.to_string()),
);
body.insert(
"method".to_string(),
serde_json::Value::String("webvh".to_string()),
);
body.insert(
"didData".to_string(),
serde_json::Value::String(log_content.to_string()),
);
if let Some(d) = domain {
body.insert(
"domain".to_string(),
serde_json::Value::String(d.to_string()),
);
}
self.bridge
.send_and_wait(
self.server_did,
TASK_DID_PUBLISH,
serde_json::Value::Object(body),
TASK_DID_PUBLISH_RESPONSE,
TASK_DID_PROBLEM_REPORT,
30,
)
.await?;
Ok(())
}
pub async fn delete_did(&self, mnemonic: &str, domain: Option<&str>) -> Result<(), AppError> {
let mut body = serde_json::Map::new();
body.insert(
"mnemonic".to_string(),
serde_json::Value::String(mnemonic.to_string()),
);
if let Some(d) = domain {
body.insert(
"domain".to_string(),
serde_json::Value::String(d.to_string()),
);
}
self.bridge
.send_and_wait(
self.server_did,
TASK_DID_DELETE,
serde_json::Value::Object(body),
TASK_DID_DELETE_RESPONSE,
TASK_DID_PROBLEM_REPORT,
30,
)
.await?;
Ok(())
}
}