use std::sync::Arc;
use auths_core::storage::keychain::{KeyAlias, extract_public_key_bytes};
use auths_id::keri::delegation::{
DelegatedRole, incept_delegated_device, list_delegated_devices as id_list_delegated_devices,
revoke_delegated_device,
};
use auths_id::keri::parse_did_keri;
use crate::context::AuthsContext;
use crate::domains::device::error::DeviceError;
pub struct DeviceDelegationResult {
pub device_did: String,
pub device_prefix: String,
}
pub fn add_device(
ctx: &AuthsContext,
root_alias: &KeyAlias,
device_alias: &KeyAlias,
device_curve: auths_crypto::CurveType,
) -> Result<DeviceDelegationResult, DeviceError> {
let managed =
ctx.identity_storage
.load_identity()
.map_err(|e| DeviceError::IdentityNotFound {
did: format!("identity load failed: {e}"),
})?;
let root_prefix = parse_did_keri(managed.controller_did.as_str()).map_err(|e| {
DeviceError::IdentityNotFound {
did: format!("invalid root did:keri: {e}"),
}
})?;
let (_pk, root_curve) = extract_public_key_bytes(
ctx.key_storage.as_ref(),
root_alias,
ctx.passphrase_provider.as_ref(),
)
.map_err(DeviceError::CryptoError)?;
let dev = incept_delegated_device(
Arc::clone(&ctx.registry),
&root_prefix,
root_alias,
root_curve,
device_alias,
device_curve,
ctx.passphrase_provider.as_ref(),
ctx.key_storage.as_ref(),
)
.map_err(DeviceError::DelegationError)?;
Ok(DeviceDelegationResult {
device_did: dev.device_did.as_str().to_string(),
device_prefix: dev.device_prefix.as_str().to_string(),
})
}
pub fn remove_device(
ctx: &AuthsContext,
root_alias: &KeyAlias,
device_did: &str,
) -> Result<(), DeviceError> {
let managed =
ctx.identity_storage
.load_identity()
.map_err(|e| DeviceError::IdentityNotFound {
did: format!("identity load failed: {e}"),
})?;
let root_prefix = parse_did_keri(managed.controller_did.as_str()).map_err(|e| {
DeviceError::IdentityNotFound {
did: format!("invalid root did:keri: {e}"),
}
})?;
let device_prefix = parse_did_keri(device_did).map_err(|e| DeviceError::DeviceNotFound {
did: format!("invalid device did:keri: {e}"),
})?;
let (_pk, root_curve) = extract_public_key_bytes(
ctx.key_storage.as_ref(),
root_alias,
ctx.passphrase_provider.as_ref(),
)
.map_err(DeviceError::CryptoError)?;
revoke_delegated_device(
ctx.registry.as_ref(),
&root_prefix,
root_alias,
root_curve,
&device_prefix,
ctx.passphrase_provider.as_ref(),
ctx.key_storage.as_ref(),
)
.map_err(DeviceError::DelegationError)
}
pub struct DeviceDelegationInfo {
pub device_did: String,
pub revoked: bool,
}
pub fn list_delegated_devices(
ctx: &AuthsContext,
) -> Result<Vec<DeviceDelegationInfo>, DeviceError> {
let managed =
ctx.identity_storage
.load_identity()
.map_err(|e| DeviceError::IdentityNotFound {
did: format!("identity load failed: {e}"),
})?;
let root_prefix = parse_did_keri(managed.controller_did.as_str()).map_err(|e| {
DeviceError::IdentityNotFound {
did: format!("invalid root did:keri: {e}"),
}
})?;
let devices = id_list_delegated_devices(ctx.registry.as_ref(), &root_prefix)
.map_err(DeviceError::DelegationError)?;
Ok(devices
.into_iter()
.filter(|d| d.role == DelegatedRole::Device)
.map(|d| DeviceDelegationInfo {
device_did: format!("did:keri:{}", d.device_prefix),
revoked: d.revoked,
})
.collect())
}