Commit graph

40 commits

Author SHA1 Message Date
f46697bd21
internal/ratelimit: prevent time drift in TokenBucket refills
The TokenBucket ratelimiter accumulated time drift over multiple refills
because I'm an idiot. We were using 'now' as base for lastFill calc. but
this could case rate limiting to become inaccurate over time. Now we
advance lastFill by *exact* periods from previous value.

Signed-off-by: NotAShelf <raf@notashelf.dev>
Change-Id: Ia3990b441ab6072f51dfdfa4a2511b5f6a6a6964
2026-03-02 22:38:23 +03:00
4e0b8f0d0a
interal/api: replace liner array scan with hashmap lookup in domain validation
Signed-off-by: NotAShelf <raf@notashelf.dev>
Change-Id: Iac969e7dc6e4ca3f93410fccac1995636a6a6964
2026-03-02 22:38:22 +03:00
987ddd92cc
internal/aggregate: make shutdown context-aware proper goroutine sync
Adds `WaitGroup` to track background goroutine and make Shutdown respect
context deadlines

Signed-off-by: NotAShelf <raf@notashelf.dev>
Change-Id: Ia7f074725717f037412dacb93e34105b6a6a6964
2026-03-02 22:38:21 +03:00
de959ec22b
nix: configure default formatter for nix fmt
Signed-off-by: NotAShelf <raf@notashelf.dev>
Change-Id: Ia75cd29276e4eed2d57a37e02281d48b6a6a6964
2026-03-02 22:38:20 +03:00
2ef2dabf93
internal/aggergate: make HLL state path configurable
Signed-off-by: NotAShelf <raf@notashelf.dev>
Change-Id: I8ff8ef25ad945aae918bea97ee39d7ea6a6a6964
2026-03-02 22:38:19 +03:00
f988174145
watchdog: migrate to Cobra and Viper for config management; search /etc for configs
Signed-off-by: NotAShelf <raf@notashelf.dev>
Change-Id: I65dbf466cb030dccc7025585d6282bd26a6a6964
2026-03-02 22:38:18 +03:00
951ed9c36f
docs: link to configuration document for overview
Signed-off-by: NotAShelf <raf@notashelf.dev>
Change-Id: Ie9f7132d784bf0b40e562f3190782fb36a6a6964
2026-03-02 22:38:17 +03:00
430219ee4c
docs: finalize project README
Signed-off-by: NotAShelf <raf@notashelf.dev>
Change-Id: Ib2e222bfc5e5433423186584b52d53cb6a6a6964
2026-03-02 22:38:16 +03:00
4fba5e5ea3
chore: update example configuration to patch validation schema
Signed-off-by: NotAShelf <raf@notashelf.dev>
Change-Id: Id7b0fde6295fe48e2e766b9d538d3fb06a6a6964
2026-03-02 22:38:15 +03:00
bf8390a916
chore: format with golines
Signed-off-by: NotAShelf <raf@notashelf.dev>
Change-Id: I11a2f3273abf08c8cf02e0c335e26d826a6a6964
2026-03-02 22:38:14 +03:00
214c992494
chore: update test data for multi-domain support
Signed-off-by: NotAShelf <raf@notashelf.dev>
Change-Id: I789eff29d033de4c25128e6bbc17a5966a6a6964
2026-03-02 22:38:13 +03:00
cf6a68477f
web: improve Javascript beacon for Plausible 'compatibility'
Some features from Plausible that I think I'll miss. Here are some of
the noteworthy ones:

- Configuration via data attributes (api, domain, hash-mode, etc.)
- Automatic localhost detection and path exclusions
- Hash-based routing for SPA support
- Custom referrer support for events
- Duplicate pageview detection

Signed-off-by: NotAShelf <raf@notashelf.dev>
Change-Id: I6d19378404d0cb9920f12e0cdd163a8e6a6a6964
2026-03-02 22:38:12 +03:00
18fe1a8234
internal/api: better multi-sites support; validate events against allowed domains
Signed-off-by: NotAShelf <raf@notashelf.dev>
Change-Id: Iff1ced4966b4d42cfd6dfefb0cfd97696a6a6964
2026-03-02 22:38:11 +03:00
16ace569a0
meta: provide systemd template files
Signed-off-by: NotAShelf <raf@notashelf.dev>
Change-Id: I2ed3bcfa3e0f58685a883a301c898ee86a6a6964
2026-03-02 22:38:10 +03:00
63fb5d4ada
nix: add nixosModules to the flake
Signed-off-by: NotAShelf <raf@notashelf.dev>
Change-Id: I4a63fdabe0bdee972fea926bf37d78906a6a6964
2026-03-02 22:38:09 +03:00
75018f69df
nix: initial nixos module; complete packaging
Signed-off-by: NotAShelf <raf@notashelf.dev>
Change-Id: I59ec5a4f67ddae2139e72ef4c0c113366a6a6964
2026-03-02 22:38:08 +03:00
da1fab4257
internal: fix the tests broken by hardening
Signed-off-by: NotAShelf <raf@notashelf.dev>
Change-Id: If95a5258a393542564f68b3a1ebc7ff66a6a6964
2026-03-02 22:38:07 +03:00
326cbbc68c
watchdog: more graceful shutdown; secure static file serving
Signed-off-by: NotAShelf <raf@notashelf.dev>
Change-Id: I2a55b2c4f380a1d78ec1ffa0391720256a6a6964
2026-03-02 22:38:06 +03:00
7e1ef845e8
internal/api: resolve IPv6 handling; prevent XFF spoofing & add rate limiting
Signed-off-by: NotAShelf <raf@notashelf.dev>
Change-Id: Ibe415a133bbc8bd533a21ed1ccd44cf36a6a6964
2026-03-02 22:38:05 +03:00
8187608b38
internal/api: centralize constants; improve validation & santize errors
Signed-off-by: NotAShelf <raf@notashelf.dev>
Change-Id: I3c3e4acb12a5a965bfaba950bf9aa5776a6a6964
2026-03-02 22:38:04 +03:00
8392992b41
internal/aggregate: optimize HyperLogLog to prevent O(16384) operations
Signed-off-by: NotAShelf <raf@notashelf.dev>
Change-Id: Ibc7e6d7a86e8679e299c46debee9683f6a6a6964
2026-03-02 22:38:03 +03:00
bb56df6423
internal/aggregate: optimize path registry for read-heavy workloads
Signed-off-by: NotAShelf <raf@notashelf.dev>
Change-Id: Ibc477830b471fe09838b7477fe73ffa56a6a6964
2026-03-02 22:38:02 +03:00
ffb4ab2295
internal/normalize: harden against possible attacks; optimize registry
Signed-off-by: NotAShelf <raf@notashelf.dev>
Change-Id: Iaf89cda3c480d6a8371e5f146ee95fcf6a6a6964
2026-03-02 22:38:01 +03:00
b2256183e1
config: add security and performance sections to sample config; validate
Signed-off-by: NotAShelf <raf@notashelf.dev>
Change-Id: Ieda42bcbd09014c45fb14bee579f829c6a6a6964
2026-03-02 22:38:01 +03:00
c3b77696aa
internal: centralize size/length constants; better DoS protection
...also adds a bounded custom event registry for cardinality control but
I ran out of space in the commit message. Praise be to the long
descriptions...

Signed-off-by: NotAShelf <raf@notashelf.dev>
Change-Id: Ic205f69804c7fb24c39fa84abdd9546b6a6a6964
2026-03-02 22:38:00 +03:00
371c5f3506
chore: bump deps; tidy
Signed-off-by: NotAShelf <raf@notashelf.dev>
Change-Id: I78644673019b40dffe3d5900cb7cba806a6a6964
2026-03-02 22:37:59 +03:00
993e47e603
internal/aggregate: add HyperLogLog unique visitor tracking
Extracts IP from X-Forwarded-For/X-Real-IP/RemoteAddr. Only active
when `config.Site.SaltRotation` is set.

Signed-off-by: NotAShelf <raf@notashelf.dev>
Change-Id: Ieef93b81e9894fc2e9e129451bf2dfdf6a6a6964
2026-03-02 22:37:58 +03:00
b6f2380a20
web: Javascript beacon for client-side tracking; custom event API
Signed-off-by: NotAShelf <raf@notashelf.dev>
Change-Id: I8e1f329ad3dfe7ba3f34ce450b1e1a0f6a6a6964
2026-03-02 22:37:57 +03:00
b894833ac7
various: HTTP server; migrate to cobra pattern for repository
Signed-off-by: NotAShelf <raf@notashelf.dev>
Change-Id: Ifac6e992b77dfaf92e3059944aa871f16a6a6964
2026-03-02 22:37:56 +03:00
e0ec475a81
internal/api: ingestion handler; wire normalization pipeline
Signed-off-by: NotAShelf <raf@notashelf.dev>
Change-Id: I1890a039b874fcc76ac4a545c2901d4e6a6a6964
2026-03-02 22:37:55 +03:00
c5109ace92
internal/api: add event model with validation
Supports both pageview and custom event types

Signed-off-by: NotAShelf <raf@notashelf.dev>
Change-Id: Iaf48291cd952865ea9ec21361ae33c746a6a6964
2026-03-02 22:37:54 +03:00
bc4d3fed53
internal: initial metrics aggregator
Signed-off-by: NotAShelf <raf@notashelf.dev>
Change-Id: I9cdd6e2b33bb65182568db9db4460bc46a6a6964
2026-03-02 22:37:53 +03:00
ce848ed6f0
internal: add bounded path registry to prevent cardinality explosion
"cardinality explosion" would make for an epic rock band name...

Signed-off-by: NotAShelf <raf@notashelf.dev>
Change-Id: I53cceb00ab9b17039b1fb1389977bf6b6a6a6964
2026-03-02 22:37:52 +03:00
be4534bac8
internal: add referrer classification
Signed-off-by: NotAShelf <raf@notashelf.dev>
Change-Id: Ibcaa09bfd4767876ea1cdd5b61c53b476a6a6964
2026-03-02 22:37:51 +03:00
0691e5ee34
internal: implement path normalization w/ configurable rules
Strips query strings and URL fragmenets, prevents unbounded Prometheus
metrics by normalizing paths like:

- `/users/12345/profile -> /users/:id/profile`
- `/page?utm_source=twitter -> /page`
- `/a/../b -> /b`

etc.

Signed-off-by: NotAShelf <raf@notashelf.dev>
Change-Id: I72f2fa2452f4666567143d052b5716476a6a6964
2026-03-02 22:37:50 +03:00
28abcf50e2
docs: improve introduction paragraph; tiny cleanup
Signed-off-by: NotAShelf <raf@notashelf.dev>
Change-Id: I2d331809c915f4695603b72ff52857cc6a6a6964
2026-03-02 22:37:49 +03:00
b4f3828895
meta: add direnv support
Signed-off-by: NotAShelf <raf@notashelf.dev>
Change-Id: I27df8e0c8b731759748fc6c1a734ded76a6a6964
2026-03-02 22:37:48 +03:00
4c84393286
config: data structures; basic tests
Signed-off-by: NotAShelf <raf@notashelf.dev>
Change-Id: Ia7d6f19a46ec8a4987ea429ec6502f676a6a6964
2026-03-02 22:37:47 +03:00
3fca34dd6f
nix: initial tooling
Signed-off-by: NotAShelf <raf@notashelf.dev>
Change-Id: Iabcad180d133f01d3c98e3d5fc9630b26a6a6964
2026-03-02 22:37:46 +03:00
7146a61326
initial commit
Signed-off-by: NotAShelf <raf@notashelf.dev>
Change-Id: Id13648d9d5579614595101592739fe2a6a6a6964
2026-03-02 22:37:45 +03:00