Skip to content
Draft
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
660 changes: 396 additions & 264 deletions Cargo.lock

Large diffs are not rendered by default.

70 changes: 70 additions & 0 deletions crates/buzz-auth/src/foundation.rs
Original file line number Diff line number Diff line change
Expand Up @@ -979,6 +979,32 @@ impl VerifiedFederatedAssertion {
pub const fn attested_event_author_pubkey(&self) -> Option<PublicKey> {
self.attested_event_author_pubkey
}

/// Transport and exact request, target, and context coordinates sealed by the verifier.
pub const fn request_binding(&self) -> (ProofTransport, &[u8; 32], &[u8; 32], &[u8; 32]) {
(
self.transport,
&self.request_fingerprint,
&self.target_fingerprint,
&self.transport_context_fingerprint,
)
}

/// SHA-256 fingerprint of the exact verified assertion bytes.
pub const fn assertion_fingerprint(&self) -> &[u8; 32] {
&self.assertion_fingerprint
}

/// Inclusive not-before and exclusive expiry bounds sealed by the verifier.
pub const fn time_bounds(&self) -> (DateTime<Utc>, DateTime<Utc>) {
(self.not_before, self.expires_at)
}

#[cfg(test)]
pub(crate) fn with_test_attested_event_author(mut self, author: PublicKey) -> Self {
self.attested_event_author_pubkey = Some(author);
self
}
}

impl fmt::Debug for VerifiedFederatedAssertion {
Expand Down Expand Up @@ -1487,6 +1513,9 @@ pub struct LocalBindingResolution(LocalBindingResolutionKind);

#[derive(Clone)]
enum LocalBindingResolutionKind {
BoundKey {
binding: ActiveLocalBinding,
},
Direct {
assertion: VerifiedFederatedAssertion,
binding: ActiveLocalBinding,
Expand All @@ -1502,6 +1531,14 @@ enum LocalBindingResolutionKind {
}

impl LocalBindingResolution {
/// Bind a transport-verified event author to its authoritative active row.
///
/// This assertion-free path is for operations whose exact signed request is
/// itself the proof. It never enrolls a key and never accepts delegation.
pub(crate) fn bound_key(binding: ActiveLocalBinding) -> Self {
Self(LocalBindingResolutionKind::BoundKey { binding })
}

/// Bind an origin-sealed direct assertion to an authoritative storage row.
pub fn direct(assertion: VerifiedFederatedAssertion, binding: ActiveLocalBinding) -> Self {
Self(LocalBindingResolutionKind::Direct { assertion, binding })
Expand All @@ -1527,6 +1564,7 @@ impl LocalBindingResolution {
impl fmt::Debug for LocalBindingResolution {
fn fmt(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result {
let name = match &self.0 {
LocalBindingResolutionKind::BoundKey { .. } => "BoundKey([REDACTED])",
LocalBindingResolutionKind::Direct { .. } => "Direct([REDACTED])",
LocalBindingResolutionKind::Enrollment { .. } => "Enrollment([REDACTED])",
LocalBindingResolutionKind::Delegated { .. } => "Delegated([REDACTED])",
Expand Down Expand Up @@ -1936,6 +1974,11 @@ pub struct PreparedAuthorization {
}

impl PreparedAuthorization {
/// Server-generated correlation identifier sealed into this preparation.
pub const fn correlation_id(&self) -> Uuid {
self.context.correlation_id()
}

/// Clone the exact dependency tuple that authoritative storage and the
/// verifier cache must recheck after all intervening I/O.
pub fn recheck_request(&self) -> PreparedAuthorizationRecheck {
Expand Down Expand Up @@ -2110,6 +2153,33 @@ impl AuthorizationFinalizer {
reason,
verifier_stamp,
) = match resolution.0 {
LocalBindingResolutionKind::BoundKey { binding } => {
if binding.authorization_domain != input.authorization_domain
|| binding.event_author_pubkey != input.proof.actor_pubkey
|| input.proof.bound_assertion_fingerprint.is_some()
|| input.proof.delegation_conditions_fingerprint.is_some()
{
return Err(AuthorizationError::BindingMismatch);
}
let expires_at = Self::effective_lease_upper_bound(
authoritative_now,
&[
Some(input.proof.expires_at),
binding.expires_at,
Some(policy.expires_at),
],
)?;
(
None,
binding.binding_id,
binding.binding_version,
None,
None,
expires_at,
AuthorizationReason::ExistingBinding,
None,
)
}
LocalBindingResolutionKind::Direct { assertion, binding } => {
if assertion.authorization_domain != input.authorization_domain
|| binding.authorization_domain != input.authorization_domain
Expand Down
7 changes: 6 additions & 1 deletion crates/buzz-auth/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -60,7 +60,12 @@ pub use nip42::{
generate_challenge, verify_nip42_authorization_proof, verify_nip42_event,
Nip42AuthorizationProofError,
};
pub use nip98::verify_nip98_event;
pub use nip98::{
verify_nip42_moderation_command_proof, verify_nip98_event, verify_nip98_invite_claim_proof,
verify_nip98_moderation_command_proof, Nip42ModerationCommandCoordinates,
Nip98InviteClaimCoordinates, Nip98ModerationCommandCoordinates, VerifiedModerationCommandProof,
VerifiedNip98InviteClaimProof,
};
pub use nip98_replay::{
nip98_replay_key, nip98_replay_key_for_scope, Nip98ReplayGuard, DEFAULT_REPLAY_TTL_SECS,
MAX_REPLAY_TTL_SECS,
Expand Down
Loading
Loading