From 2699c1fcb9d592ba9c606dd8238ede54d11e4412 Mon Sep 17 00:00:00 2001 From: Samuel Gbafa Date: Mon, 8 Jun 2026 14:30:30 -0400 Subject: [PATCH] chore: align owner DID terminology --- .../src/encryption_network/network_id.rs | 42 +++++----- .../src/encryption_network/protocol.rs | 4 +- .../src/encryption_network/service.rs | 32 ++++---- .../src/encryption_network/tests.rs | 82 +++++++++---------- .../src/encryption_network/types.rs | 3 +- .../m20260601_000000_encryption_networks.rs | 2 +- tinycloud-core/src/models/delegation.rs | 2 +- .../src/models/encryption_network.rs | 3 +- tinycloud-core/src/models/invocation.rs | 2 +- .../src/routes/encryption.rs | 27 +++--- 10 files changed, 104 insertions(+), 95 deletions(-) diff --git a/tinycloud-core/src/encryption_network/network_id.rs b/tinycloud-core/src/encryption_network/network_id.rs index ae11745..7ff5fe4 100644 --- a/tinycloud-core/src/encryption_network/network_id.rs +++ b/tinycloud-core/src/encryption_network/network_id.rs @@ -1,7 +1,7 @@ -//! Parsing for `urn:tinycloud:encryption::` network identifiers. +//! Parsing for `urn:tinycloud:encryption::` network identifiers. //! -//! The principal is the root authority for the network. The network name disambiguates -//! multiple networks owned by the same principal. +//! The owner DID is the root authority for the network. The network name disambiguates +//! multiple networks owned by the same owner. use serde::{Deserialize, Serialize}; use std::fmt; @@ -14,11 +14,11 @@ const NETWORK_ID_PREFIX: &str = "urn:tinycloud:encryption:"; pub enum NetworkIdError { #[error("missing urn:tinycloud:encryption: prefix")] MissingPrefix, - #[error("empty principal")] - EmptyPrincipal, + #[error("empty owner DID")] + EmptyOwnerDid, #[error("empty network name")] EmptyName, - #[error("missing principal/name separator")] + #[error("missing owner DID/name separator")] MissingSeparator, #[error("network name may not contain ':' or '/'")] InvalidName, @@ -28,19 +28,19 @@ pub enum NetworkIdError { #[derive(Clone, PartialEq, Eq, Hash, Serialize, Deserialize)] #[serde(try_from = "String", into = "String")] pub struct NetworkId { - principal: String, + owner_did: String, name: String, } impl NetworkId { pub fn new( - principal: impl Into, + owner_did: impl Into, name: impl Into, ) -> Result { - let principal = principal.into(); + let owner_did = owner_did.into(); let name = name.into(); - if principal.is_empty() { - return Err(NetworkIdError::EmptyPrincipal); + if owner_did.is_empty() { + return Err(NetworkIdError::EmptyOwnerDid); } if name.is_empty() { return Err(NetworkIdError::EmptyName); @@ -48,11 +48,11 @@ impl NetworkId { if name.contains(':') || name.contains('/') { return Err(NetworkIdError::InvalidName); } - Ok(Self { principal, name }) + Ok(Self { owner_did, name }) } - pub fn principal(&self) -> &str { - &self.principal + pub fn owner_did(&self) -> &str { + &self.owner_did } pub fn name(&self) -> &str { @@ -62,7 +62,7 @@ impl NetworkId { impl fmt::Display for NetworkId { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - write!(f, "{NETWORK_ID_PREFIX}{}:{}", self.principal, self.name) + write!(f, "{NETWORK_ID_PREFIX}{}:{}", self.owner_did, self.name) } } @@ -79,13 +79,13 @@ impl FromStr for NetworkId { let rest = s .strip_prefix(NETWORK_ID_PREFIX) .ok_or(NetworkIdError::MissingPrefix)?; - // The principal itself is a DID-like value that may contain colons + // The owner DID itself may contain colons // (e.g. did:key:z6Mk...). The network name is the final colon-delimited // segment, which is constrained to contain no further ':' or '/'. - let (principal, name) = rest + let (owner_did, name) = rest .rsplit_once(':') .ok_or(NetworkIdError::MissingSeparator)?; - Self::new(principal.to_string(), name.to_string()) + Self::new(owner_did.to_string(), name.to_string()) } } @@ -112,7 +112,7 @@ mod tests { let id: NetworkId = "urn:tinycloud:encryption:did:key:z6MkExampleAbcd:default" .parse() .unwrap(); - assert_eq!(id.principal(), "did:key:z6MkExampleAbcd"); + assert_eq!(id.owner_did(), "did:key:z6MkExampleAbcd"); assert_eq!(id.name(), "default"); assert_eq!( id.to_string(), @@ -133,9 +133,9 @@ mod tests { } #[test] - fn rejects_empty_principal_with_explicit_name() { + fn rejects_empty_owner_did_with_explicit_name() { let err: Result = "urn:tinycloud:encryption::default".parse(); - assert_eq!(err.unwrap_err(), NetworkIdError::EmptyPrincipal); + assert_eq!(err.unwrap_err(), NetworkIdError::EmptyOwnerDid); } #[test] diff --git a/tinycloud-core/src/encryption_network/protocol.rs b/tinycloud-core/src/encryption_network/protocol.rs index f26f446..89ad991 100644 --- a/tinycloud-core/src/encryption_network/protocol.rs +++ b/tinycloud-core/src/encryption_network/protocol.rs @@ -77,7 +77,7 @@ pub struct DecryptResponseBody { /// /// `issuer` is the requester session DID. `audience` MUST equal the serving /// node's DID. `proof_cid` references the delegation chain that authorizes the -/// decrypt action; verification rooted in the principal embedded in +/// decrypt action; verification rooted in the owner DID embedded in /// `network_id` is performed by [`crate::encryption_network::service`]. #[derive(Debug, Clone, Serialize, Deserialize)] pub struct DecryptInvocation { @@ -207,7 +207,7 @@ mod tests { use serde_json::json; fn sample_invocation() -> DecryptInvocation { - let net: NetworkId = "urn:tinycloud:encryption:did:key:z6MkPrincipal:default" + let net: NetworkId = "urn:tinycloud:encryption:did:key:z6MkOwner:default" .parse() .unwrap(); DecryptInvocation { diff --git a/tinycloud-core/src/encryption_network/service.rs b/tinycloud-core/src/encryption_network/service.rs index f827d14..9996f26 100644 --- a/tinycloud-core/src/encryption_network/service.rs +++ b/tinycloud-core/src/encryption_network/service.rs @@ -58,8 +58,8 @@ pub enum EncryptionServiceError { AudienceMismatch, #[error("invocation target node does not match this node")] TargetNodeMismatch, - #[error("invocation root principal does not match network principal")] - PrincipalMismatch, + #[error("invocation root owner DID does not match network owner DID")] + OwnerMismatch, #[error("invocation references a different network")] NetworkMismatch, #[error("invocation expired")] @@ -97,7 +97,7 @@ pub struct EncryptionService { #[derive(Debug, Clone)] pub struct CreateNetworkRequest { pub name: String, - pub principal: String, + pub owner_did: String, pub threshold: Threshold, } @@ -147,7 +147,7 @@ impl EncryptionService { &self, req: CreateNetworkRequest, ) -> Result { - let network_id = NetworkId::new(req.principal.clone(), req.name.clone()) + let network_id = NetworkId::new(req.owner_did.clone(), req.name.clone()) .map_err(|e| EncryptionServiceError::InvalidBody(format!("invalid network id: {e}")))?; // Reject duplicates up-front so callers see a clear error instead of a @@ -181,7 +181,7 @@ impl EncryptionService { let model = encryption_network::ActiveModel { network_id: Set(network_id.to_string()), - principal: Set(req.principal.clone()), + owner_did: Set(req.owner_did.clone()), name: Set(req.name.clone()), alg: Set(generated.alg.clone()), key_version: Set(1), @@ -219,7 +219,7 @@ impl EncryptionService { Ok(NetworkDescriptor { network_id, - principal: req.principal, + owner_did: req.owner_did, name: req.name, members: vec![NetworkMemberDescriptor { node_id: self.node_did.clone(), @@ -264,7 +264,7 @@ impl EncryptionService { Ok(NetworkDescriptor { network_id: network_id.clone(), - principal: model.principal, + owner_did: model.owner_did, name: model.name, members, threshold: Threshold { @@ -284,11 +284,11 @@ impl EncryptionService { pub async fn get_network_by_name( &self, name: &str, - principal: Option<&str>, + owner_did: Option<&str>, ) -> Result { - if let Some(principal) = principal { + if let Some(owner_did) = owner_did { let network_id = - NetworkId::new(principal.to_string(), name.to_string()).map_err(|e| { + NetworkId::new(owner_did.to_string(), name.to_string()).map_err(|e| { EncryptionServiceError::InvalidBody(format!("invalid network id: {e}")) })?; return self.get_network(&network_id).await; @@ -352,8 +352,8 @@ impl EncryptionService { if cap.with != network_id.to_string() { return Err(EncryptionServiceError::NetworkMismatch); } - if invocation.issuer != network_id.principal() { - return Err(EncryptionServiceError::PrincipalMismatch); + if invocation.issuer != network_id.owner_did() { + return Err(EncryptionServiceError::OwnerMismatch); } let expected_body_hash = canonical_hash(body_value); if expected_body_hash != invocation.facts.body_hash { @@ -460,8 +460,8 @@ impl EncryptionService { if cap.with != network_id.to_string() { return Err(EncryptionServiceError::NetworkMismatch); } - if invocation.issuer != network_id.principal() { - return Err(EncryptionServiceError::PrincipalMismatch); + if invocation.issuer != network_id.owner_did() { + return Err(EncryptionServiceError::OwnerMismatch); } // ---- Network state ---- @@ -964,7 +964,7 @@ fn native_invocation_cid(invocation: &InvocationInfo) -> Result for WellKnownRecord { fn from(d: &NetworkDescriptor) -> Self { Self { network_id: d.network_id.to_string(), - principal: d.principal.clone(), + owner_did: d.owner_did.clone(), name: d.name.clone(), alg: d.alg.clone(), key_version: d.key_version, diff --git a/tinycloud-core/src/encryption_network/tests.rs b/tinycloud-core/src/encryption_network/tests.rs index 69ff2c7..8599e94 100644 --- a/tinycloud-core/src/encryption_network/tests.rs +++ b/tinycloud-core/src/encryption_network/tests.rs @@ -60,9 +60,9 @@ fn make_service(db: DatabaseConnection) -> EncryptionService { EncryptionService::new(db, NODE_DID.to_string(), backend) } -fn principal_keypair() -> Keypair { +fn owner_keypair() -> Keypair { NodeStaticSecret::new(vec![0x11; 32]) - .expect("static principal secret") + .expect("static owner secret") .node_keypair() } @@ -76,12 +76,12 @@ fn did_for(keypair: &Keypair) -> String { public_key_to_did_key(keypair.public()) } -fn principal_did() -> String { - did_for(&principal_keypair()) +fn owner_did() -> String { + did_for(&owner_keypair()) } fn network_id() -> NetworkId { - NetworkId::new(principal_did(), NETWORK_NAME.to_string()).unwrap() + NetworkId::new(owner_did(), NETWORK_NAME.to_string()).unwrap() } struct ClientCtx { @@ -130,7 +130,7 @@ fn build_invocation( ) -> DecryptInvocation { let now = OffsetDateTime::now_utc().unix_timestamp(); let mut inv = DecryptInvocation { - issuer: principal_did(), + issuer: owner_did(), audience: NODE_DID.to_string(), att: vec![InvocationCapability { with: net.to_string(), @@ -158,7 +158,7 @@ fn build_invocation( sig: String::new(), }; overrides(&mut inv); - sign_invocation(&mut inv, &principal_keypair()); + sign_invocation(&mut inv, &owner_keypair()); inv } @@ -233,7 +233,7 @@ async fn create_one_of_one_network_initializes_active_state() { let descriptor = svc .create_one_of_one_network(CreateNetworkRequest { name: NETWORK_NAME.to_string(), - principal: principal_did(), + owner_did: owner_did(), threshold: Threshold::one_of_one(), }) .await @@ -268,7 +268,7 @@ async fn create_network_rejects_duplicate() { let svc = make_service(fresh_db().await); svc.create_one_of_one_network(CreateNetworkRequest { name: NETWORK_NAME.to_string(), - principal: principal_did(), + owner_did: owner_did(), threshold: Threshold::one_of_one(), }) .await @@ -276,7 +276,7 @@ async fn create_network_rejects_duplicate() { let err = svc .create_one_of_one_network(CreateNetworkRequest { name: NETWORK_NAME.to_string(), - principal: principal_did(), + owner_did: owner_did(), threshold: Threshold::one_of_one(), }) .await @@ -291,7 +291,7 @@ async fn get_network_returns_descriptor() { let net = network_id(); svc.create_one_of_one_network(CreateNetworkRequest { name: NETWORK_NAME.to_string(), - principal: principal_did(), + owner_did: owner_did(), threshold: Threshold::one_of_one(), }) .await @@ -299,7 +299,7 @@ async fn get_network_returns_descriptor() { let fetched = svc.get_network(&net).await.unwrap(); assert_eq!(fetched.network_id, net); - assert_eq!(fetched.principal, principal_did()); + assert_eq!(fetched.owner_did, owner_did()); assert_eq!(fetched.state, NetworkState::Active); } @@ -311,19 +311,19 @@ async fn get_network_by_name_returns_discovery_view() { let descriptor = svc .create_one_of_one_network(CreateNetworkRequest { name: NETWORK_NAME.to_string(), - principal: principal_did(), + owner_did: owner_did(), threshold: Threshold::one_of_one(), }) .await .unwrap(); - let by_principal = svc - .get_network_by_name(NETWORK_NAME, Some(&principal_did())) + let by_owner = svc + .get_network_by_name(NETWORK_NAME, Some(&owner_did())) .await .unwrap(); let by_name = svc.get_network_by_name(NETWORK_NAME, None).await.unwrap(); - assert_eq!(by_principal.network_id, net); + assert_eq!(by_owner.network_id, net); assert_eq!(by_name.network_id, net); let well_known = WellKnownRecord::from(&descriptor); @@ -343,7 +343,7 @@ async fn network_admin_authorized_accepts_session_invoker() { let net = network_id(); let body_value = serde_json::json!({ "name": NETWORK_NAME, - "principal": principal_did(), + "ownerDid": owner_did(), "threshold": { "n": 1, "t": 1 } }); let facts = serde_json::to_value(NetworkAdminFacts { @@ -360,7 +360,7 @@ async fn network_admin_authorized_accepts_session_invoker() { svc.verify_network_admin_authorized(&net, NETWORK_CREATE_ACTION, &invocation, &body_value) .await .unwrap(); - assert_ne!(invocation.invoker, principal_did()); + assert_ne!(invocation.invoker, owner_did()); } #[tokio::test] @@ -370,7 +370,7 @@ async fn decrypt_round_trip_returns_rewrapped_key() { let descriptor = svc .create_one_of_one_network(CreateNetworkRequest { name: NETWORK_NAME.to_string(), - principal: principal_did(), + owner_did: owner_did(), threshold: Threshold::one_of_one(), }) .await @@ -398,7 +398,7 @@ async fn decrypt_authorized_accepts_session_invoker() { let descriptor = svc .create_one_of_one_network(CreateNetworkRequest { name: NETWORK_NAME.to_string(), - principal: principal_did(), + owner_did: owner_did(), threshold: Threshold::one_of_one(), }) .await @@ -431,7 +431,7 @@ async fn decrypt_authorized_accepts_session_invoker() { .expect("base64 wrapped key"); let recovered = unwrap_with_secret(&ctx.receiver_secret, &rewrapped); assert_eq!(recovered, ctx.symmetric); - assert_ne!(invocation.invoker, principal_did()); + assert_ne!(invocation.invoker, owner_did()); } #[tokio::test] @@ -441,7 +441,7 @@ async fn decrypt_authorized_rejects_audience_mismatch() { let descriptor = svc .create_one_of_one_network(CreateNetworkRequest { name: NETWORK_NAME.to_string(), - principal: principal_did(), + owner_did: owner_did(), threshold: Threshold::one_of_one(), }) .await @@ -484,7 +484,7 @@ async fn decrypt_rejects_audience_mismatch() { let descriptor = svc .create_one_of_one_network(CreateNetworkRequest { name: NETWORK_NAME.to_string(), - principal: principal_did(), + owner_did: owner_did(), threshold: Threshold::one_of_one(), }) .await @@ -505,7 +505,7 @@ async fn decrypt_rejects_target_node_mismatch_in_body() { let descriptor = svc .create_one_of_one_network(CreateNetworkRequest { name: NETWORK_NAME.to_string(), - principal: principal_did(), + owner_did: owner_did(), threshold: Threshold::one_of_one(), }) .await @@ -526,7 +526,7 @@ async fn decrypt_rejects_target_node_mismatch_in_invocation() { let descriptor = svc .create_one_of_one_network(CreateNetworkRequest { name: NETWORK_NAME.to_string(), - principal: principal_did(), + owner_did: owner_did(), threshold: Threshold::one_of_one(), }) .await @@ -546,7 +546,7 @@ async fn decrypt_rejects_body_hash_mismatch() { let descriptor = svc .create_one_of_one_network(CreateNetworkRequest { name: NETWORK_NAME.to_string(), - principal: principal_did(), + owner_did: owner_did(), threshold: Threshold::one_of_one(), }) .await @@ -570,7 +570,7 @@ async fn decrypt_rejects_receiver_public_key_substitution() { let descriptor = svc .create_one_of_one_network(CreateNetworkRequest { name: NETWORK_NAME.to_string(), - principal: principal_did(), + owner_did: owner_did(), threshold: Threshold::one_of_one(), }) .await @@ -597,7 +597,7 @@ async fn decrypt_rejects_encrypted_key_substitution() { let descriptor = svc .create_one_of_one_network(CreateNetworkRequest { name: NETWORK_NAME.to_string(), - principal: principal_did(), + owner_did: owner_did(), threshold: Threshold::one_of_one(), }) .await @@ -623,12 +623,12 @@ async fn decrypt_rejects_wrong_network() { let descriptor = svc .create_one_of_one_network(CreateNetworkRequest { name: NETWORK_NAME.to_string(), - principal: principal_did(), + owner_did: owner_did(), threshold: Threshold::one_of_one(), }) .await .unwrap(); - let other_net = NetworkId::new(principal_did(), "wrong".to_string()).unwrap(); + let other_net = NetworkId::new(owner_did(), "wrong".to_string()).unwrap(); let ctx = make_client_request(&descriptor.public_encryption_key); let (_, body_value) = build_body(&ctx, &net); let inv = build_invocation(&net, &body_value, &ctx, |_| {}); @@ -646,14 +646,14 @@ async fn decrypt_rejects_invocation_network_mismatch() { let descriptor = svc .create_one_of_one_network(CreateNetworkRequest { name: NETWORK_NAME.to_string(), - principal: principal_did(), + owner_did: owner_did(), threshold: Threshold::one_of_one(), }) .await .unwrap(); let ctx = make_client_request(&descriptor.public_encryption_key); let (_, body_value) = build_body(&ctx, &net); - let other_net = NetworkId::new(principal_did(), "wrong".to_string()).unwrap(); + let other_net = NetworkId::new(owner_did(), "wrong".to_string()).unwrap(); let mut inv = build_invocation(&net, &body_value, &ctx, |_| {}); inv.facts.network_id = other_net; let err = svc.decrypt(&net, &inv, &body_value).await.unwrap_err(); @@ -661,13 +661,13 @@ async fn decrypt_rejects_invocation_network_mismatch() { } #[tokio::test] -async fn decrypt_rejects_wrong_principal() { +async fn decrypt_rejects_wrong_owner() { let svc = make_service(fresh_db().await); let net = network_id(); let descriptor = svc .create_one_of_one_network(CreateNetworkRequest { name: NETWORK_NAME.to_string(), - principal: principal_did(), + owner_did: owner_did(), threshold: Threshold::one_of_one(), }) .await @@ -681,7 +681,7 @@ async fn decrypt_rejects_wrong_principal() { }); sign_invocation(&mut inv, &attacker); let err = svc.decrypt(&net, &inv, &body_value).await.unwrap_err(); - assert!(matches!(err, EncryptionServiceError::PrincipalMismatch)); + assert!(matches!(err, EncryptionServiceError::OwnerMismatch)); } #[tokio::test] @@ -691,7 +691,7 @@ async fn decrypt_rejects_signature_mismatch() { let descriptor = svc .create_one_of_one_network(CreateNetworkRequest { name: NETWORK_NAME.to_string(), - principal: principal_did(), + owner_did: owner_did(), threshold: Threshold::one_of_one(), }) .await @@ -711,7 +711,7 @@ async fn decrypt_rejects_replay() { let descriptor = svc .create_one_of_one_network(CreateNetworkRequest { name: NETWORK_NAME.to_string(), - principal: principal_did(), + owner_did: owner_did(), threshold: Threshold::one_of_one(), }) .await @@ -731,7 +731,7 @@ async fn decrypt_rejects_expired_invocation() { let descriptor = svc .create_one_of_one_network(CreateNetworkRequest { name: NETWORK_NAME.to_string(), - principal: principal_did(), + owner_did: owner_did(), threshold: Threshold::one_of_one(), }) .await @@ -752,7 +752,7 @@ async fn decrypt_rejects_wrong_capability_action() { let descriptor = svc .create_one_of_one_network(CreateNetworkRequest { name: NETWORK_NAME.to_string(), - principal: principal_did(), + owner_did: owner_did(), threshold: Threshold::one_of_one(), }) .await @@ -773,7 +773,7 @@ async fn revoked_network_refuses_decrypt() { let descriptor = svc .create_one_of_one_network(CreateNetworkRequest { name: NETWORK_NAME.to_string(), - principal: principal_did(), + owner_did: owner_did(), threshold: Threshold::one_of_one(), }) .await @@ -801,7 +801,7 @@ async fn unique_request_hashes_per_decrypt() { let descriptor = svc .create_one_of_one_network(CreateNetworkRequest { name: NETWORK_NAME.to_string(), - principal: principal_did(), + owner_did: owner_did(), threshold: Threshold::one_of_one(), }) .await diff --git a/tinycloud-core/src/encryption_network/types.rs b/tinycloud-core/src/encryption_network/types.rs index 4882c57..890f7da 100644 --- a/tinycloud-core/src/encryption_network/types.rs +++ b/tinycloud-core/src/encryption_network/types.rs @@ -97,7 +97,8 @@ pub struct NetworkMemberDescriptor { pub struct NetworkDescriptor { #[serde(rename = "networkId")] pub network_id: NetworkId, - pub principal: String, + #[serde(rename = "ownerDid")] + pub owner_did: String, pub name: String, pub members: Vec, pub threshold: Threshold, diff --git a/tinycloud-core/src/migrations/m20260601_000000_encryption_networks.rs b/tinycloud-core/src/migrations/m20260601_000000_encryption_networks.rs index e6863ef..de2d0dd 100644 --- a/tinycloud-core/src/migrations/m20260601_000000_encryption_networks.rs +++ b/tinycloud-core/src/migrations/m20260601_000000_encryption_networks.rs @@ -22,7 +22,7 @@ impl MigrationTrait for Migration { .not_null(), ) .col( - ColumnDef::new(encryption_network::Column::Principal) + ColumnDef::new(encryption_network::Column::OwnerDid) .string() .not_null(), ) diff --git a/tinycloud-core/src/models/delegation.rs b/tinycloud-core/src/models/delegation.rs index d4f616b..f83f49f 100644 --- a/tinycloud-core/src/models/delegation.rs +++ b/tinycloud-core/src/models/delegation.rs @@ -274,7 +274,7 @@ fn is_root_authority(cap: &util::Capability, delegator: &str) -> bool { Resource::Other(uri) => uri .as_str() .parse::() - .map(|network_id| network_id.principal() == delegator) + .map(|network_id| network_id.owner_did() == delegator) .unwrap_or(false), Resource::TinyCloud(_) => false, } diff --git a/tinycloud-core/src/models/encryption_network.rs b/tinycloud-core/src/models/encryption_network.rs index 50fce26..4fa5042 100644 --- a/tinycloud-core/src/models/encryption_network.rs +++ b/tinycloud-core/src/models/encryption_network.rs @@ -5,7 +5,8 @@ use sea_orm::entity::prelude::*; pub struct Model { #[sea_orm(primary_key, auto_increment = false, unique)] pub network_id: String, - pub principal: String, + #[sea_orm(column_name = "principal")] + pub owner_did: String, pub name: String, pub alg: String, pub key_version: i64, diff --git a/tinycloud-core/src/models/invocation.rs b/tinycloud-core/src/models/invocation.rs index d992ea8..e49ac25 100644 --- a/tinycloud-core/src/models/invocation.rs +++ b/tinycloud-core/src/models/invocation.rs @@ -196,7 +196,7 @@ fn is_root_authority(cap: &util::Capability, invoker: &str) -> bool { Resource::Other(uri) => uri .as_str() .parse::() - .map(|network_id| network_id.principal() == invoker) + .map(|network_id| network_id.owner_did() == invoker) .unwrap_or(false), Resource::TinyCloud(_) => false, } diff --git a/tinycloud-node-server/src/routes/encryption.rs b/tinycloud-node-server/src/routes/encryption.rs index 8f0e270..6389bd2 100644 --- a/tinycloud-node-server/src/routes/encryption.rs +++ b/tinycloud-node-server/src/routes/encryption.rs @@ -7,7 +7,7 @@ //! - `POST /encryption/networks//decrypt` — UCAN-style decrypt invocation //! - `POST /encryption/networks//revoke` — admin revoke (placeholder) -use rocket::{http::Status, serde::json::Json, State}; +use rocket::{form::FromForm, http::Status, serde::json::Json, State}; use serde::{Deserialize, Serialize}; use std::collections::HashMap; @@ -22,7 +22,8 @@ use tinycloud_core::{events::Invocation, util::InvocationInfo}; #[derive(Debug, Deserialize)] pub struct CreateNetworkBody { pub name: String, - pub principal: String, + #[serde(rename = "ownerDid")] + pub owner_did: String, #[serde(default = "default_threshold")] pub threshold: Threshold, } @@ -36,6 +37,12 @@ pub struct DescriptorView { pub descriptor: NetworkDescriptor, } +#[derive(Debug, FromForm)] +pub struct WellKnownNetworkQuery { + #[field(name = "ownerDid")] + pub owner_did: Option, +} + #[post("/encryption/networks", format = "json", data = "")] pub async fn create_network( authorization: AuthHeaderGetter, @@ -50,7 +57,7 @@ pub async fn create_network( let body_value = body.into_inner(); let body: CreateNetworkBody = serde_json::from_value(body_value.clone()) .map_err(|err| (Status::BadRequest, err.to_string()))?; - let network_id = NetworkId::new(body.principal.clone(), body.name.clone()) + let network_id = NetworkId::new(body.owner_did.clone(), body.name.clone()) .map_err(|err| (Status::BadRequest, err.to_string()))?; service .verify_network_admin_authorized( @@ -63,7 +70,7 @@ pub async fn create_network( .map_err(map_service_err)?; let req = CreateNetworkRequest { name: body.name, - principal: body.principal, + owner_did: body.owner_did, threshold: body.threshold, }; let descriptor = service @@ -91,16 +98,16 @@ pub async fn get_network( /// Discovery record published as `.well-known/encryption/network/`. /// Authoritative state still lives in the node DB; this endpoint just renders a /// cache-friendly view of the active network for the given name. -#[get("/.well-known/encryption/network/?")] +#[get("/.well-known/encryption/network/?")] pub async fn well_known_network( name: &str, - principal: Option<&str>, + query: WellKnownNetworkQuery, service: &State, ) -> Result, (Status, String)> { - // V1 supports principal-qualified discovery when the caller has it, and a - // name-only fallback for single-principal nodes. + // V1 supports owner-qualified discovery when the caller has it, and a + // name-only fallback for single-owner nodes. let descriptor = service - .get_network_by_name(name, principal) + .get_network_by_name(name, query.owner_did.as_deref()) .await .map_err(map_service_err)?; Ok(Json(WellKnownRecord::from(&descriptor))) @@ -192,7 +199,7 @@ fn map_service_err(err: EncryptionServiceError) -> (Status, String) { EncryptionServiceError::Signing(_) => Status::InternalServerError, EncryptionServiceError::AudienceMismatch | EncryptionServiceError::TargetNodeMismatch - | EncryptionServiceError::PrincipalMismatch + | EncryptionServiceError::OwnerMismatch | EncryptionServiceError::NetworkMismatch | EncryptionServiceError::Unauthorized | EncryptionServiceError::NetworkRevoked