refactor: update dependencies and remove unused code

- Added new dependencies: `adler2`, `crc32fast`, `flate2`, `miniz_oxide`, and `libredox`.
- Updated existing dependencies: `tokio-rustls` to version 0.26.4 and `filetime` to version 0.2.27.
- Removed the `backup.rs` file as it is no longer needed.
- Introduced tests for configuration and credential management.
- Enhanced the `identity` module to generate W3C compliant DID documents.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
Dorian
2026-03-12 00:19:30 +00:00
parent fd2a837bea
commit f07ce10b1a
347 changed files with 18703 additions and 46785 deletions

View File

@@ -105,6 +105,11 @@ impl NodeIdentity {
pub fn did_key(&self) -> String {
did_key_from_pubkey_hex(&self.pubkey_hex()).expect("pubkey_hex is valid")
}
/// Generate a W3C DID Core v1.0 compliant DID Document.
pub fn did_document(&self) -> serde_json::Value {
did_document_from_pubkey_hex(&self.pubkey_hex()).expect("pubkey_hex is valid")
}
}
/// Convert Ed25519 pubkey (hex) to did:key format.
@@ -121,6 +126,77 @@ pub fn did_key_from_pubkey_hex(pubkey_hex: &str) -> Result<String> {
Ok(format!("did:key:z{}", bs58::encode(multicodec_pubkey).into_string()))
}
/// Generate a W3C DID Core v1.0 compliant DID Document from an Ed25519 public key.
/// Follows: https://www.w3.org/TR/did-core/
/// Includes: verificationMethod, authentication, assertionMethod, keyAgreement contexts.
pub fn did_document_from_pubkey_hex(pubkey_hex: &str) -> Result<serde_json::Value> {
let did = did_key_from_pubkey_hex(pubkey_hex)?;
let pubkey_bytes = hex::decode(pubkey_hex).context("Invalid pubkey hex")?;
let pubkey_multibase = format!("z{}", bs58::encode(&pubkey_bytes).into_string());
let key_id = format!("{}#key-1", did);
// Build X25519 key agreement key from Ed25519 public key
// Ed25519 -> X25519 conversion (Montgomery form)
let ed_point = curve25519_dalek::edwards::CompressedEdwardsY(
pubkey_bytes
.as_slice()
.try_into()
.map_err(|_| anyhow::anyhow!("Invalid pubkey length"))?,
);
let x25519_key = if let Some(point) = ed_point.decompress() {
let montgomery = point.to_montgomery();
format!("z{}", bs58::encode(montgomery.as_bytes()).into_string())
} else {
// Fallback: use Ed25519 key if conversion fails
pubkey_multibase.clone()
};
let x25519_key_id = format!("{}#key-x25519-1", did);
Ok(serde_json::json!({
"@context": [
"https://www.w3.org/ns/did/v1",
"https://w3id.org/security/suites/ed25519-2020/v1",
"https://w3id.org/security/suites/x25519-2020/v1"
],
"id": did,
"verificationMethod": [
{
"id": key_id,
"type": "Ed25519VerificationKey2020",
"controller": did,
"publicKeyMultibase": pubkey_multibase
},
{
"id": x25519_key_id,
"type": "X25519KeyAgreementKey2020",
"controller": did,
"publicKeyMultibase": x25519_key
}
],
"authentication": [key_id],
"assertionMethod": [key_id],
"capabilityInvocation": [key_id],
"capabilityDelegation": [key_id],
"keyAgreement": [x25519_key_id]
}))
}
/// Extract the raw 32-byte Ed25519 public key from a did:key string.
pub fn pubkey_bytes_from_did_key(did: &str) -> Result<[u8; 32]> {
let multibase_str = did
.strip_prefix("did:key:z")
.ok_or_else(|| anyhow::anyhow!("Invalid did:key format"))?;
let decoded = bs58::decode(multibase_str)
.into_vec()
.context("Invalid base58 in did:key")?;
if decoded.len() != 34 || decoded[0] != 0xed || decoded[1] != 0x01 {
return Err(anyhow::anyhow!("Invalid Ed25519 multicodec prefix"));
}
let mut pubkey = [0u8; 32];
pubkey.copy_from_slice(&decoded[2..34]);
Ok(pubkey)
}
#[cfg(test)]
mod tests {
use super::*;
@@ -210,4 +286,60 @@ mod tests {
assert!(addr.starts_with("archipelago://abc123.onion#"));
assert!(addr.contains(&identity.pubkey_hex()));
}
#[tokio::test]
async fn test_did_document_w3c_structure() {
let dir = tempfile::tempdir().unwrap();
let identity = NodeIdentity::load_or_create(&dir.path().join("id")).await.unwrap();
let doc = identity.did_document();
let did = identity.did_key();
// Verify @context
let context = doc["@context"].as_array().unwrap();
assert_eq!(context[0], "https://www.w3.org/ns/did/v1");
// Verify id matches did:key
assert_eq!(doc["id"], did);
// Verify verificationMethod has Ed25519 and X25519 keys
let vms = doc["verificationMethod"].as_array().unwrap();
assert_eq!(vms.len(), 2);
assert_eq!(vms[0]["type"], "Ed25519VerificationKey2020");
assert_eq!(vms[1]["type"], "X25519KeyAgreementKey2020");
assert_eq!(vms[0]["controller"], did);
// Verify authentication references key-1
let auth = doc["authentication"].as_array().unwrap();
assert_eq!(auth[0], format!("{}#key-1", did));
// Verify assertionMethod
assert!(doc["assertionMethod"].as_array().is_some());
// Verify keyAgreement references x25519 key
let ka = doc["keyAgreement"].as_array().unwrap();
assert_eq!(ka[0], format!("{}#key-x25519-1", did));
}
#[test]
fn test_did_document_from_pubkey_hex() {
let hex = "d75a980182b10ab7d54bfed3c964073a0ee172f3daa3f4a18446b7e21e7e2c33";
let doc = did_document_from_pubkey_hex(hex).unwrap();
assert_eq!(doc["@context"].as_array().unwrap().len(), 3);
assert!(doc["id"].as_str().unwrap().starts_with("did:key:z"));
}
#[test]
fn test_pubkey_bytes_from_did_key_roundtrip() {
let hex = "d75a980182b10ab7d54bfed3c964073a0ee172f3daa3f4a18446b7e21e7e2c33";
let did = did_key_from_pubkey_hex(hex).unwrap();
let recovered = pubkey_bytes_from_did_key(&did).unwrap();
assert_eq!(hex::encode(recovered), hex);
}
#[test]
fn test_pubkey_bytes_from_invalid_did() {
assert!(pubkey_bytes_from_did_key("did:web:example.com").is_err());
assert!(pubkey_bytes_from_did_key("did:key:invalid").is_err());
}
}