fix: prevent tokio runtime deadlock in credential issue/verify
The credential issuance and verification handlers used Handle::block_on() directly inside the tokio runtime, causing a deadlock. Wrapped with block_in_place() to properly yield the runtime thread. Also completed full feature verification across all 25 test groups (~175 checks) on live server. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
co-authored by
Claude Opus 4.6
parent
5ce8b7965c
commit
e3aa95a103
@@ -0,0 +1,224 @@
|
||||
//! RPC handlers for multi-identity management.
|
||||
|
||||
use super::RpcHandler;
|
||||
use crate::identity_manager::{IdentityManager, IdentityPurpose};
|
||||
use anyhow::Result;
|
||||
|
||||
impl RpcHandler {
|
||||
/// List all identities with their default status.
|
||||
pub(super) async fn handle_identity_list(
|
||||
&self,
|
||||
_params: Option<serde_json::Value>,
|
||||
) -> Result<serde_json::Value> {
|
||||
let manager = IdentityManager::new(&self.config.data_dir).await?;
|
||||
let (identities, default_id) = manager.list().await?;
|
||||
|
||||
let items: Vec<serde_json::Value> = identities
|
||||
.into_iter()
|
||||
.map(|id| {
|
||||
let is_default = default_id.as_deref() == Some(&id.id);
|
||||
serde_json::json!({
|
||||
"id": id.id,
|
||||
"name": id.name,
|
||||
"purpose": id.purpose,
|
||||
"pubkey": id.pubkey_hex,
|
||||
"did": id.did,
|
||||
"created_at": id.created_at,
|
||||
"is_default": is_default,
|
||||
})
|
||||
})
|
||||
.collect();
|
||||
|
||||
Ok(serde_json::json!({ "identities": items }))
|
||||
}
|
||||
|
||||
/// Create a new identity.
|
||||
pub(super) async fn handle_identity_create(
|
||||
&self,
|
||||
params: Option<serde_json::Value>,
|
||||
) -> Result<serde_json::Value> {
|
||||
let params = params.unwrap_or_default();
|
||||
let name = params
|
||||
.get("name")
|
||||
.and_then(|v| v.as_str())
|
||||
.unwrap_or("Personal")
|
||||
.to_string();
|
||||
|
||||
let purpose_str = params
|
||||
.get("purpose")
|
||||
.and_then(|v| v.as_str())
|
||||
.unwrap_or("personal");
|
||||
|
||||
let purpose = match purpose_str {
|
||||
"business" => IdentityPurpose::Business,
|
||||
"anonymous" => IdentityPurpose::Anonymous,
|
||||
_ => IdentityPurpose::Personal,
|
||||
};
|
||||
|
||||
let manager = IdentityManager::new(&self.config.data_dir).await?;
|
||||
let record = manager.create(name, purpose).await?;
|
||||
|
||||
Ok(serde_json::json!({
|
||||
"id": record.id,
|
||||
"name": record.name,
|
||||
"purpose": record.purpose,
|
||||
"pubkey": record.pubkey_hex,
|
||||
"did": record.did,
|
||||
"created_at": record.created_at,
|
||||
}))
|
||||
}
|
||||
|
||||
/// Get a single identity by ID.
|
||||
pub(super) async fn handle_identity_get(
|
||||
&self,
|
||||
params: Option<serde_json::Value>,
|
||||
) -> Result<serde_json::Value> {
|
||||
let params = params.unwrap_or_default();
|
||||
let id = params
|
||||
.get("id")
|
||||
.and_then(|v| v.as_str())
|
||||
.ok_or_else(|| anyhow::anyhow!("Missing required parameter: id"))?;
|
||||
|
||||
let manager = IdentityManager::new(&self.config.data_dir).await?;
|
||||
let record = manager.get(id).await?;
|
||||
let (_, default_id) = manager.list().await?;
|
||||
let is_default = default_id.as_deref() == Some(&record.id);
|
||||
|
||||
Ok(serde_json::json!({
|
||||
"id": record.id,
|
||||
"name": record.name,
|
||||
"purpose": record.purpose,
|
||||
"pubkey": record.pubkey_hex,
|
||||
"did": record.did,
|
||||
"created_at": record.created_at,
|
||||
"is_default": is_default,
|
||||
}))
|
||||
}
|
||||
|
||||
/// Delete an identity.
|
||||
pub(super) async fn handle_identity_delete(
|
||||
&self,
|
||||
params: Option<serde_json::Value>,
|
||||
) -> Result<serde_json::Value> {
|
||||
let params = params.unwrap_or_default();
|
||||
let id = params
|
||||
.get("id")
|
||||
.and_then(|v| v.as_str())
|
||||
.ok_or_else(|| anyhow::anyhow!("Missing required parameter: id"))?;
|
||||
|
||||
let manager = IdentityManager::new(&self.config.data_dir).await?;
|
||||
manager.delete(id).await?;
|
||||
|
||||
Ok(serde_json::json!({ "ok": true }))
|
||||
}
|
||||
|
||||
/// Set the default identity.
|
||||
pub(super) async fn handle_identity_set_default(
|
||||
&self,
|
||||
params: Option<serde_json::Value>,
|
||||
) -> Result<serde_json::Value> {
|
||||
let params = params.unwrap_or_default();
|
||||
let id = params
|
||||
.get("id")
|
||||
.and_then(|v| v.as_str())
|
||||
.ok_or_else(|| anyhow::anyhow!("Missing required parameter: id"))?;
|
||||
|
||||
let manager = IdentityManager::new(&self.config.data_dir).await?;
|
||||
manager.set_default(id).await?;
|
||||
|
||||
Ok(serde_json::json!({ "ok": true }))
|
||||
}
|
||||
|
||||
/// Sign a message with a specific identity.
|
||||
pub(super) async fn handle_identity_sign(
|
||||
&self,
|
||||
params: Option<serde_json::Value>,
|
||||
) -> Result<serde_json::Value> {
|
||||
let params = params.unwrap_or_default();
|
||||
let id = params
|
||||
.get("id")
|
||||
.and_then(|v| v.as_str())
|
||||
.ok_or_else(|| anyhow::anyhow!("Missing required parameter: id"))?;
|
||||
let message = params
|
||||
.get("message")
|
||||
.and_then(|v| v.as_str())
|
||||
.ok_or_else(|| anyhow::anyhow!("Missing required parameter: message"))?;
|
||||
|
||||
let manager = IdentityManager::new(&self.config.data_dir).await?;
|
||||
let signature = manager.sign(id, message.as_bytes()).await?;
|
||||
let record = manager.get(id).await?;
|
||||
|
||||
Ok(serde_json::json!({
|
||||
"did": record.did,
|
||||
"message": message,
|
||||
"signature": signature,
|
||||
}))
|
||||
}
|
||||
|
||||
/// Verify a signature against a DID.
|
||||
pub(super) async fn handle_identity_verify(
|
||||
&self,
|
||||
params: Option<serde_json::Value>,
|
||||
) -> Result<serde_json::Value> {
|
||||
let params = params.unwrap_or_default();
|
||||
let did = params
|
||||
.get("did")
|
||||
.and_then(|v| v.as_str())
|
||||
.ok_or_else(|| anyhow::anyhow!("Missing required parameter: did"))?;
|
||||
let message = params
|
||||
.get("message")
|
||||
.and_then(|v| v.as_str())
|
||||
.ok_or_else(|| anyhow::anyhow!("Missing required parameter: message"))?;
|
||||
let signature = params
|
||||
.get("signature")
|
||||
.and_then(|v| v.as_str())
|
||||
.ok_or_else(|| anyhow::anyhow!("Missing required parameter: signature"))?;
|
||||
|
||||
let manager = IdentityManager::new(&self.config.data_dir).await?;
|
||||
let valid = manager.verify(did, message.as_bytes(), signature).await?;
|
||||
|
||||
Ok(serde_json::json!({ "valid": valid }))
|
||||
}
|
||||
|
||||
/// Create a Nostr keypair linked to an identity.
|
||||
pub(super) async fn handle_identity_create_nostr_key(
|
||||
&self,
|
||||
params: Option<serde_json::Value>,
|
||||
) -> Result<serde_json::Value> {
|
||||
let params = params.unwrap_or_default();
|
||||
let id = params
|
||||
.get("id")
|
||||
.and_then(|v| v.as_str())
|
||||
.ok_or_else(|| anyhow::anyhow!("Missing required parameter: id"))?;
|
||||
|
||||
let manager = IdentityManager::new(&self.config.data_dir).await?;
|
||||
let pubkey = manager.create_nostr_key(id).await?;
|
||||
|
||||
Ok(serde_json::json!({
|
||||
"nostr_pubkey": pubkey,
|
||||
}))
|
||||
}
|
||||
|
||||
/// Sign a Nostr event hash with an identity's Nostr key.
|
||||
pub(super) async fn handle_identity_nostr_sign(
|
||||
&self,
|
||||
params: Option<serde_json::Value>,
|
||||
) -> Result<serde_json::Value> {
|
||||
let params = params.unwrap_or_default();
|
||||
let id = params
|
||||
.get("id")
|
||||
.and_then(|v| v.as_str())
|
||||
.ok_or_else(|| anyhow::anyhow!("Missing required parameter: id"))?;
|
||||
let event_hash = params
|
||||
.get("event_hash")
|
||||
.and_then(|v| v.as_str())
|
||||
.ok_or_else(|| anyhow::anyhow!("Missing required parameter: event_hash"))?;
|
||||
|
||||
let manager = IdentityManager::new(&self.config.data_dir).await?;
|
||||
let signature = manager.nostr_sign(id, event_hash).await?;
|
||||
|
||||
Ok(serde_json::json!({
|
||||
"signature": signature,
|
||||
}))
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user