1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
//! Engagement tracking primitives.
//!
//! Reusable building blocks for any microapp / extension that
//! needs **open + click tracking** on outbound channel content
//! (email today, push notifications + SMS later). Three layers:
//!
//! - [`token`] — HMAC-signed URL tokens. Operator stamps a
//! per-tenant secret at boot; the signer mints a tag for the
//! `(tenant_id, msg_id, link_id?)` triple, the ingest route
//! verifies in constant time. Forged URLs are 401, replayed
//! URLs hit the (caller-owned) idempotency layer.
//! - [`html`] — Pure-rust HTML helpers: `inject_pixel(html,
//! pixel_url)` appends the 1×1 GIF tag before `</body>`;
//! `rewrite_links(html, ...)` swaps every `<a href="X">` for
//! the click-redirector URL and yields the `(link_id ↔ X)`
//! mapping the caller persists.
//! - [`types`] — Newtype wrappers (`MsgId`, `LinkId`) +
//! event records (`OpenEvent`, `ClickEvent`) + the 1×1
//! transparent GIF blob the ingest route serves.
//!
//! ## Threat model
//!
//! Tags are **HMAC-SHA256 truncated to 16 bytes**, base64url
//! encoded — 2¹²⁸ forgery search space. Constant-time compare
//! via [`subtle`] guards against timing oracles. The signer's
//! input domain is `b"\x01" || tenant_id || b"\x00" || msg_id
//! || b"\x00" || link_id?`; the leading byte is a version
//! prefix so future format changes can be migrated cleanly.
//!
//! Cross-tenant replay is impossible — `tenant_id` is part of
//! the signed payload, so tenant A cannot bind a tag from
//! tenant B's secret. Cross-microapp replay is impossible —
//! every microapp picks its own secret at boot.
//!
//! ## Crate-level zero-cost when unused
//!
//! Everything in this module is gated behind the `tracking`
//! feature. Microapps that don't need engagement tracking pay
//! zero dep cost (no `hmac`, no `sha2`, no `regex`).
pub use ;
pub use ;
pub use ;
pub use ;