feat: implement peers_only and specific availability access control for content

- PeersOnly access now checks X-Federation-DID header against known federation nodes
- Specific availability restricts content to named peer DIDs only
- Anonymous/unknown DID requests get 403 Forbidden
- Free content remains accessible to everyone
- Paid content still returns 402 with price info

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
Dorian
2026-03-13 02:27:38 +00:00
co-authored by Claude Opus 4.6
parent fc8e3f2d39
commit 18e8a178a3
3 changed files with 40 additions and 5 deletions
+23 -4
View File
@@ -187,16 +187,20 @@ pub enum ServeResult {
},
/// Payment required — includes price in sats.
PaymentRequired(u64),
/// Access forbidden — peer not authorized.
Forbidden,
/// Content not found.
NotFound,
}
/// Serve a content item by ID with access control and optional range request.
/// If the content is paid, checks for a valid payment token in the header.
/// `peer_did` is the DID from the X-Federation-DID header (if present).
pub async fn serve_content(
data_dir: &Path,
id: &str,
payment_token: Option<&str>,
peer_did: Option<&str>,
range: Option<ByteRange>,
) -> Result<ServeResult> {
let catalog = load_catalog(data_dir).await?;
@@ -205,13 +209,26 @@ pub async fn serve_content(
None => return Ok(ServeResult::NotFound),
};
// Load known federation peers for access checks
let is_known_peer = if peer_did.is_some() {
let nodes = crate::federation::load_nodes(data_dir).await.unwrap_or_default();
nodes.iter().any(|n| Some(n.did.as_str()) == peer_did)
} else {
false
};
// Check availability
match &item.availability {
Availability::Nobody => return Ok(ServeResult::NotFound),
Availability::Specific { peers } => {
// In a real implementation, we'd check the requester's identity
// For now, log that peer-specific availability is set
debug!("Content '{}' restricted to {} specific peers", id, peers.len());
if let Some(did) = peer_did {
if !peers.iter().any(|p| p == did) {
debug!("Content '{}' not available to peer {}", id, did);
return Ok(ServeResult::Forbidden);
}
} else {
return Ok(ServeResult::Forbidden);
}
}
Availability::AllPeers => {}
}
@@ -229,7 +246,9 @@ pub async fn serve_content(
}
}
AccessControl::PeersOnly => {
// For now, allow all requests (peer auth is at the Tor level)
if !is_known_peer {
return Ok(ServeResult::Forbidden);
}
}
AccessControl::Free => {}
}