Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
23 changes: 23 additions & 0 deletions crates/auths-crypto/src/hash256.rs
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,29 @@ impl Hash256 {
pub fn into_inner(self) -> [u8; 32] {
self.0
}

/// Parse a 64-character hex string (with an optional prefix such as `"sha256:"`) into a `Hash256`.
pub fn from_hex_prefixed(s: &str, expected_prefix: Option<&str>) -> Result<Self, String> {
let clean = match expected_prefix {
Some(prefix) => s
.strip_prefix(prefix)
.ok_or_else(|| format!("expected prefix '{prefix}'")),
None => {
if let Some(stripped) = s.strip_prefix("sha256:") {
Ok(stripped)
} else {
Ok(s)
}
}
}?;

let bytes = hex::decode(clean).map_err(|e| format!("invalid hex: {e}"))?;
let array: [u8; 32] = bytes
.try_into()
.map_err(|_| "hash digest must be exactly 32 bytes (64 hex characters)".to_string())?;

Ok(Self(array))
}
}

impl From<[u8; 32]> for Hash256 {
Expand Down
17 changes: 7 additions & 10 deletions crates/auths-evidence/src/attestation.rs
Original file line number Diff line number Diff line change
Expand Up @@ -93,10 +93,10 @@ pub fn activity_signing_bytes(doc: &ActivityV1) -> Result<Vec<u8>, EvidenceError
/// let seed = activity_seed_id(&doc);
/// ```
pub fn activity_seed_id(doc: &ActivityV1) -> auths_anchor::SeedId {
let agent_tail = doc
.subject
.agent
.strip_prefix("did:keri:")
let agent_did = auths_verifier::IdentityDID::parse(&doc.subject.agent).ok();
let agent_tail = agent_did
.as_ref()
.map(|d| d.prefix())
.unwrap_or(&doc.subject.agent);
auths_anchor::SeedId::derive(&doc.subject.root, &doc.subject.agent, agent_tail)
}
Expand Down Expand Up @@ -512,12 +512,9 @@ pub fn verify_activity_against_registry(

let backend =
GitRegistryBackend::from_config_unchecked(RegistryConfig::single_tenant(registry));
let agent_tail = doc
.subject
.agent
.strip_prefix("did:keri:")
.unwrap_or(&doc.subject.agent);
let prefix = Prefix::new(agent_tail.to_string())
let parsed_agent = auths_verifier::IdentityDID::parse(&doc.subject.agent)
.map_err(|e| EvidenceError::Input(format!("agent DID: {e}")))?;
let prefix = Prefix::new(parsed_agent.prefix().to_string())
.map_err(|e| EvidenceError::Input(format!("agent prefix: {e}")))?;
let state = backend
.get_key_state(&prefix)
Expand Down
11 changes: 6 additions & 5 deletions crates/auths-id/src/identity/rotate.rs
Original file line number Diff line number Diff line change
Expand Up @@ -100,9 +100,10 @@ pub fn rotate_keri_identity(
));
}

let prefix = did.as_str().strip_prefix("did:keri:").ok_or_else(|| {
let parsed_did = auths_verifier::IdentityDID::parse(did.as_str()).map_err(|_| {
InitError::InvalidData(format!("Invalid DID format, expected 'did:keri:': {}", did))
})?;
let prefix = parsed_did.prefix();

let kel = GitKel::new(&repo, prefix);
let events = kel
Expand Down Expand Up @@ -224,10 +225,10 @@ pub fn rotate_registry_identity(
));
}

let prefix_str = did.as_str().strip_prefix("did:keri:").ok_or_else(|| {
let parsed_did = auths_verifier::IdentityDID::parse(did.as_str()).map_err(|_| {
InitError::InvalidData(format!("Invalid DID format, expected 'did:keri:': {}", did))
})?;
let prefix = Prefix::new_unchecked(prefix_str.to_string());
let prefix = Prefix::new_unchecked(parsed_did.prefix().to_string());

let state = backend
.get_key_state(&prefix)
Expand Down Expand Up @@ -388,10 +389,10 @@ pub fn rotate_registry_identity_multi(
));
}

let prefix_str = did.as_str().strip_prefix("did:keri:").ok_or_else(|| {
let parsed_did = auths_verifier::IdentityDID::parse(did.as_str()).map_err(|_| {
InitError::InvalidData(format!("Invalid DID format, expected 'did:keri:': {}", did))
})?;
let prefix = Prefix::new_unchecked(prefix_str.to_string());
let prefix = Prefix::new_unchecked(parsed_did.prefix().to_string());

let state = backend
.get_key_state(&prefix)
Expand Down
5 changes: 3 additions & 2 deletions crates/auths-id/src/storage/layout.rs
Original file line number Diff line number Diff line change
Expand Up @@ -244,8 +244,9 @@ pub fn keri_credential_ref(issuer: &Prefix, credential_said: &Said) -> String {

/// Extracts the KERI prefix (AID) from a full `did:keri:` identifier string.
pub fn did_keri_to_prefix(did: &str) -> Option<Prefix> {
did.strip_prefix("did:keri:")
.map(|s| Prefix::new_unchecked(s.to_string()))
auths_verifier::IdentityDID::parse(did)
.ok()
.map(|d| Prefix::new_unchecked(d.prefix().to_string()))
}

// --- Configurable Layout (Primarily for did:key Identity & Attestations) ---
Expand Down
3 changes: 2 additions & 1 deletion crates/auths-mcp-core/src/audit.rs
Original file line number Diff line number Diff line change
Expand Up @@ -535,7 +535,8 @@ impl fmt::Display for LogReadError {
/// anything that is not `[A-Za-z0-9_-]` to `_` (defensive — a `did:keri:E…` tail is base64url and
/// already safe; this only guards a malformed key from escaping the directory).
fn safe_key(delegation: &str) -> String {
let tail = delegation.strip_prefix("did:keri:").unwrap_or(delegation);
let parsed = auths_verifier::IdentityDID::parse(delegation).ok();
let tail = parsed.as_ref().map(|d| d.prefix()).unwrap_or(delegation);
if tail.is_empty() || tail == "." || tail == ".." {
return "_".to_string();
}
Expand Down
3 changes: 2 additions & 1 deletion crates/auths-mcp-core/src/budget.rs
Original file line number Diff line number Diff line change
Expand Up @@ -579,7 +579,8 @@ impl CounterRef {
/// safe; we strip the scheme and reject anything that is not a safe single path
/// component (defensive — the same guard `usage_ledger.rs` applies to a SAID).
fn safe_key(delegation: &str) -> Result<String, BudgetError> {
let tail = delegation.strip_prefix("did:keri:").unwrap_or(delegation);
let parsed = auths_verifier::IdentityDID::parse(delegation).ok();
let tail = parsed.as_ref().map(|d| d.prefix()).unwrap_or(delegation);
let safe = !tail.is_empty()
&& tail != "."
&& tail != ".."
Expand Down
4 changes: 2 additions & 2 deletions crates/auths-sdk/src/domains/identity/local.rs
Original file line number Diff line number Diff line change
Expand Up @@ -198,9 +198,9 @@ fn is_local_signing_device(

/// The delegator (root) KEL tip sequence for `root_did`, or `None` if unreadable.
fn root_tip_seq(ctx: &AuthsContext, root_did: &str) -> Option<u128> {
let prefix = root_did.strip_prefix("did:keri:")?;
let parsed = auths_verifier::IdentityDID::parse(root_did).ok()?;
ctx.registry
.get_tip(&Prefix::new_unchecked(prefix.to_string()))
.get_tip(&Prefix::new_unchecked(parsed.prefix().to_string()))
.ok()
.map(|tip| tip.sequence)
}
4 changes: 3 additions & 1 deletion crates/auths-sdk/src/workflows/agent_provision.rs
Original file line number Diff line number Diff line change
Expand Up @@ -233,7 +233,9 @@ pub fn materialize_agent_machine_registry(
agent_registry: &Path,
agent_did: &str,
) -> Result<()> {
let agent_pfx = agent_did.strip_prefix("did:keri:").unwrap_or(agent_did);
let agent_pfx = auths_verifier::IdentityDID::parse(agent_did)
.map(|d| d.prefix().to_string())
.unwrap_or_else(|_| agent_did.to_string());

if agent_registry.exists() {
fs::remove_dir_all(agent_registry)?;
Expand Down
Loading