Initialize repository snapshot

This commit is contained in:
Vault Sovereign
2025-12-27 00:10:32 +00:00
commit 110d644e10
281 changed files with 40331 additions and 0 deletions

View File

@@ -0,0 +1,11 @@
[package]
name = "vaultmesh-identity"
version = "0.1.0"
edition = "2021"
[dependencies]
chrono = { version = "0.4", features = ["serde"] }
serde = { version = "1", features = ["derive"] }
serde_json = "1"
vaultmesh-core = { path = "../vaultmesh-core" }

View File

@@ -0,0 +1,284 @@
//! vaultmesh-identity - Identity engine for DID management and receipts.
use chrono::Utc;
use serde::{Deserialize, Serialize};
use std::collections::HashMap;
use vaultmesh_core::{
Did,
DidType,
Receipt,
ReceiptHeader,
ReceiptMeta,
Scroll,
VmHash,
};
/// DID Document based on W3C DID Core with a VaultMesh extension namespace.
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct DidDocument {
#[serde(rename = "@context")]
pub context: Vec<String>,
pub id: Did,
pub controller: Option<Did>,
#[serde(rename = "verificationMethod")]
pub verification_method: Vec<VerificationMethod>,
pub authentication: Vec<String>,
#[serde(rename = "assertionMethod")]
pub assertion_method: Vec<String>,
pub service: Vec<Service>,
/// Optional human-facing display name.
pub display_name: Option<String>,
/// Optional role / purpose (e.g. "portal", "guardian", "skill", "human").
pub role: Option<String>,
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct VerificationMethod {
pub id: String,
#[serde(rename = "type")]
pub method_type: String,
pub controller: Did,
#[serde(rename = "publicKeyMultibase")]
pub public_key_multibase: String,
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct Service {
pub id: String,
#[serde(rename = "type")]
pub service_type: String,
#[serde(rename = "serviceEndpoint")]
pub service_endpoint: String,
}
/// Receipt body for `identity_did_create` events.
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct DidCreateReceipt {
/// Newly created DID.
pub did: Did,
/// DID type as string (e.g. "portal", "guardian", "human").
pub did_type: String,
/// Optional controller DID.
pub controller: Option<Did>,
/// Actor who created this DID.
pub created_by: Did,
/// Human-friendly label.
pub display_name: Option<String>,
/// Logical role (portal, guardian, skill, human, etc.).
pub role: Option<String>,
/// Verification key type (e.g. Ed25519VerificationKey2020).
pub public_key_type: String,
/// Multibase-encoded public key.
pub public_key_multibase: String,
/// IDs of initial keys attached to the DID document.
pub initial_keys: Vec<String>,
/// Hash of the full DID Document JSON (blake3:...).
pub did_document_hash: String,
}
/// Minimal Identity engine: manages DIDs + emits receipts.
pub struct IdentityEngine {
did_documents: HashMap<Did, DidDocument>,
}
impl Default for IdentityEngine {
fn default() -> Self {
Self::new()
}
}
impl IdentityEngine {
/// Create a new, empty IdentityEngine.
pub fn new() -> Self {
IdentityEngine {
did_documents: HashMap::new(),
}
}
/// Create a DID with a single Ed25519 key and emit an `identity_did_create` receipt.
///
/// This does NOT persist anything to disk; it just returns the receipt +
/// DID Document so the caller (CLI / service) can:
/// - store the keypair safely
/// - append the receipt to `receipts/identity/identity_events.jsonl`
pub fn create_did(
&mut self,
did_type: DidType,
name: &str,
controller: Option<Did>,
display_name: Option<String>,
role: Option<String>,
public_key_multibase: String,
created_by: Did,
) -> Result<(Receipt<DidCreateReceipt>, DidDocument), IdentityError> {
// did:vm:{type}:{name}
let did = Did::new(did_type, name);
if self.did_documents.contains_key(&did) {
return Err(IdentityError::DidExists);
}
let key_id = format!("{}#key-1", did.as_str());
let doc = DidDocument {
context: vec![
"https://www.w3.org/ns/did/v1".to_string(),
"https://vaultmesh.io/ns/did/v1".to_string(),
],
id: did.clone(),
controller: controller.clone(),
verification_method: vec![VerificationMethod {
id: key_id.clone(),
method_type: "Ed25519VerificationKey2020".to_string(),
controller: did.clone(),
public_key_multibase: public_key_multibase.clone(),
}],
authentication: vec![key_id.clone()],
assertion_method: vec![key_id.clone()],
service: vec![],
display_name: display_name.clone(),
role: role.clone(),
};
// Hash of DID Document JSON for did_document_hash.
let doc_hash = VmHash::from_json(&doc)
.map_err(|_| IdentityError::SerializationError)?;
self.did_documents.insert(did.clone(), doc);
let receipt_body = DidCreateReceipt {
did: did.clone(),
did_type: did_type.as_str().to_string(),
controller,
created_by,
display_name,
role,
public_key_type: "Ed25519VerificationKey2020".to_string(),
public_key_multibase,
initial_keys: vec![key_id],
did_document_hash: doc_hash.as_str().to_string(),
};
// Root hash over the receipt body.
let root_hash = VmHash::from_json(&receipt_body)
.map_err(|_| IdentityError::SerializationError)?;
let receipt = Receipt {
header: ReceiptHeader {
receipt_type: "identity_did_create".to_string(),
timestamp: Utc::now(),
root_hash: root_hash.as_str().to_string(),
tags: vec![
"identity".to_string(),
"did".to_string(),
"create".to_string(),
receipt_body.did_type.clone(), // e.g. "portal"
],
},
meta: ReceiptMeta {
scroll: Scroll::Identity,
sequence: 0, // to be filled by append layer
anchor_epoch: None, // to be filled by Guardian
proof_path: None,
},
body: receipt_body,
};
// We just inserted it, so unwrap is safe.
let stored_doc = self.did_documents.get(&did).unwrap().clone();
Ok((receipt, stored_doc))
}
/// Resolve a DID into its document, if present.
pub fn resolve_did(&self, did: &Did) -> Option<&DidDocument> {
self.did_documents.get(did)
}
/// Check if a DID exists in the engine.
pub fn has_did(&self, did: &Did) -> bool {
self.did_documents.contains_key(did)
}
/// Get all DIDs in the engine.
pub fn list_dids(&self) -> Vec<&Did> {
self.did_documents.keys().collect()
}
}
/// Errors that can occur in the Identity engine.
#[derive(Debug)]
pub enum IdentityError {
DidExists,
SerializationError,
}
impl std::fmt::Display for IdentityError {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
match self {
IdentityError::DidExists => write!(f, "DID already exists"),
IdentityError::SerializationError => write!(f, "Serialization error"),
}
}
}
impl std::error::Error for IdentityError {}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_create_did() {
let mut engine = IdentityEngine::new();
let created_by = Did::new(DidType::Human, "karol");
let result = engine.create_did(
DidType::Portal,
"shield",
None,
Some("VaultMesh Auditor Portal (shield)".to_string()),
Some("portal".to_string()),
"z6MkhaXgBZDvotDkL5257faiztiGiC2QtKLGpbnnEGta2doK".to_string(),
created_by,
);
assert!(result.is_ok());
let (receipt, doc) = result.unwrap();
assert_eq!(doc.id.as_str(), "did:vm:portal:shield");
assert_eq!(receipt.header.receipt_type, "identity_did_create");
assert_eq!(receipt.body.did_type, "portal");
assert!(receipt.header.tags.contains(&"portal".to_string()));
}
#[test]
fn test_duplicate_did_error() {
let mut engine = IdentityEngine::new();
let created_by = Did::new(DidType::Human, "karol");
// First creation should succeed
let _ = engine.create_did(
DidType::Guardian,
"local",
None,
None,
None,
"z6Mktest".to_string(),
created_by.clone(),
);
// Second creation with same DID should fail
let result = engine.create_did(
DidType::Guardian,
"local",
None,
None,
None,
"z6MkotherKey".to_string(),
created_by,
);
assert!(matches!(result, Err(IdentityError::DidExists)));
}
}