mirror of
https://github.com/block/buzz.git
synced 2026-10-30 22:11:36 +00:00
Signed-off-by: tlongwell-block <109685178+tlongwell-block@users.noreply.github.com> Signed-off-by: npub1jh9wn95s0472h86ahapupaf7m6kx4v9sx2n0atj2hltcfer8k06s5n3pyf <95cae996907d7cab9f5dbf43c0f53edeac6ab0b032a6feae4abfd784e467b3f5@sprout-oss.stage.blox.sqprod.co> Signed-off-by: Tyler Longwell <tlongwell@block.xyz> Signed-off-by: npub1t2tgm7d8f995uqvmnm8h88sg3wnpp9a5xysjf6dg3tjmgt3ltulqdp8ehr <5a968df9a7494b4e019b9ecf739e088ba61097b4312124e9a88ae5b42e3f5f3e@sprout-oss.stage.blox.sqprod.co> Signed-off-by: npub17jjz49l9jjmhhk7cac63j8yt9z555n9cw8vk7v5jz4vzw4ppld5qgj57cc <f4a42a97e594b77bdbd8ee35191c8b28a94a4cb871d96f32921558275421fb68@sprout-oss.stage.blox.sqprod.co> Co-authored-by: Eva <011987e296fd5006292d2f930b574be47c7801048d1983c46c425d3c95f0cffd@sprout-oss.stage.blox.sqprod.co> Co-authored-by: Mari <95cae996907d7cab9f5dbf43c0f53edeac6ab0b032a6feae4abfd784e467b3f5@sprout-oss.stage.blox.sqprod.co> Co-authored-by: Sami <f4a42a97e594b77bdbd8ee35191c8b28a94a4cb871d96f32921558275421fb68@sprout-oss.stage.blox.sqprod.co> Co-authored-by: Max <d8473ee32b973aa31a21a65adddcc4b69cc2a8a4dee8121ecd51926e0cddbc02@sprout-oss.stage.blox.sqprod.co> Co-authored-by: Quinn <96f056ad5f2305c8ddf637dc65d048aa4c12d7daeb8867690e34fca46b0ef64c@sprout-oss.stage.blox.sqprod.co> Co-authored-by: Dawn <c6237ef84fa537c78dcee78efd2d4e59f728859c7f194da42ac51ededfa0be05@sprout-oss.stage.blox.sqprod.co> Co-authored-by: Tyler Longwell <tlongwell@block.xyz> Co-authored-by: Sami <sami@sprout-oss.stage.blox.sqprod.co> Co-authored-by: npub1t2tgm7d8f995uqvmnm8h88sg3wnpp9a5xysjf6dg3tjmgt3ltulqdp8ehr <5a968df9a7494b4e019b9ecf739e088ba61097b4312124e9a88ae5b42e3f5f3e@sprout-oss.stage.blox.sqprod.co>
73 lines
3.4 KiB
Rust
73 lines
3.4 KiB
Rust
use buzz_core::CommunityId;
|
|
use chrono::{DateTime, Utc};
|
|
use serde::{Deserialize, Serialize};
|
|
use uuid::Uuid;
|
|
|
|
use crate::action::AuditAction;
|
|
|
|
/// A materialised audit log entry as stored in `audit_log`.
|
|
///
|
|
/// Rows are keyed `(community_id, seq)`: `seq` is monotonic *within one
|
|
/// community*, and `prev_hash` chains to the previous entry *of the same
|
|
/// community*. The chain is independent per tenant.
|
|
#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
|
|
pub struct AuditEntry {
|
|
/// Server-resolved community this entry belongs to. Leads the primary key.
|
|
pub community_id: Uuid,
|
|
/// Sequence number, monotonic within `community_id` (starts at 1).
|
|
pub seq: i64,
|
|
/// SHA-256 of this entry's fields including `community_id` and `prev_hash`.
|
|
pub hash: Vec<u8>,
|
|
/// SHA-256 of the previous entry in *this community's* chain, or `None` for
|
|
/// the community's first entry (hashed as [`crate::hash::GENESIS_HASH`]).
|
|
pub prev_hash: Option<Vec<u8>>,
|
|
/// Action that was performed.
|
|
pub action: AuditAction,
|
|
/// Raw bytes of the actor's Nostr pubkey, if the action has one.
|
|
pub actor_pubkey: Option<Vec<u8>>,
|
|
/// Generic identifier of the object acted upon (event id hex, channel UUID,
|
|
/// media sha256, …), if any. The relay resolves it under `community_id`;
|
|
/// it never names an object in another community.
|
|
pub object_id: Option<String>,
|
|
/// Arbitrary JSON context. **Included in the hash** (serialized with sorted
|
|
/// keys for determinism) so tampering with it is detectable.
|
|
pub detail: serde_json::Value,
|
|
/// When the entry was recorded.
|
|
pub created_at: DateTime<Utc>,
|
|
}
|
|
|
|
/// Input for appending a new audit entry. `seq`, `prev_hash`, `hash`, and
|
|
/// `created_at` are assigned by [`crate::service::AuditService::log`].
|
|
///
|
|
/// `community_id` is the **server-resolved** tenant (from the request's
|
|
/// `TenantContext`), never a client-supplied value — the same provenance rule
|
|
/// the whole multi-tenant model rests on.
|
|
///
|
|
/// Not `Serialize`/`Deserialize`: this is an in-process input struct (consumed
|
|
/// by `AuditService::log`, threaded through the in-memory audit sink), never
|
|
/// crossing a wire or DB boundary as a whole. Keeping it non-deserializable
|
|
/// reinforces the fence — there is no path by which a client-supplied blob
|
|
/// becomes a `NewAuditEntry` (and thus a `CommunityId`).
|
|
#[derive(Debug, Clone, PartialEq, Eq)]
|
|
pub struct NewAuditEntry {
|
|
/// Server-resolved community this entry belongs to. Typed as [`CommunityId`]
|
|
/// (not a raw `Uuid`) so the provenance rule is visible in the signature:
|
|
/// the only ways to obtain one are host resolution or a server-scoped DB
|
|
/// row — never a value parsed from client input.
|
|
pub community_id: CommunityId,
|
|
/// Action that was performed.
|
|
pub action: AuditAction,
|
|
/// Raw bytes of the actor's Nostr pubkey, if the action has one.
|
|
pub actor_pubkey: Option<Vec<u8>>,
|
|
/// Generic identifier of the object acted upon, if any.
|
|
pub object_id: Option<String>,
|
|
/// Arbitrary JSON context included in the hash.
|
|
///
|
|
/// **Never bearer-token material.** This field is opaque to the audit
|
|
/// crate and persisted verbatim; callers must not write tokens, passwords,
|
|
/// or other secrets here. `AuthSuccess`/`AuthFailure` entries carry only
|
|
/// outcome metadata — the token has no slot in this type, and `detail` must
|
|
/// not become one.
|
|
pub detail: serde_json::Value,
|
|
}
|