also looking at this
A read-scoped site key, so a Stacks dashboard can read analytics without a person's credentials
#68
7 files
+550
-11
| @@ -0,0 +1,29 @@ | ||
| 1 | -- A read-scoped site key, so a machine can read this site's analytics without | |
| 2 | -- holding a person's credentials (stacksjs/analyticshq#67). | |
| 3 | -- | |
| 4 | -- NOTE ON STYLE: no semicolons in these comments. The migration runner splits | |
| 5 | -- the file on semicolons without first stripping comment lines. | |
| 6 | -- | |
| 7 | -- WHY NOW | |
| 8 | -- | |
| 9 | -- Every read here resolves a signed-in user, and the only issuable bearer | |
| 10 | -- belongs to a human. A Stacks dashboard reading a site server-to-server had | |
| 11 | -- nothing correct to hold, so selecting the hosted provider rendered empty. | |
| 12 | -- | |
| 13 | -- Unlike loghq and bughq there was no per-site credential to extend. The | |
| 14 | -- tracker is a public script beaconing to a site id, so this is a new | |
| 15 | -- credential rather than a second mode on an old one. | |
| 16 | -- | |
| 17 | -- This one returns data, so it is a secret. 256 bits, compared in constant | |
| 18 | -- time in app/Support/read-key.ts, and accepted only on the reads listed on | |
| 19 | -- that issue rather than on all forty-odd site routes. | |
| 20 | -- | |
| 21 | -- Both nullable because a key is issued on demand and revoking sets it back to | |
| 22 | -- NULL, which is also why uniqueness is a partial index: every site without a | |
| 23 | -- key would otherwise collide. | |
| 24 | -- | |
| 25 | -- read_key_last_used_at tells somebody whether a key is still in use before | |
| 26 | -- they revoke it. Written at most once a minute per key, not per request. | |
| 27 | ALTER TABLE "sites" ADD COLUMN IF NOT EXISTS "read_key" varchar(255); | |
| 28 | ALTER TABLE "sites" ADD COLUMN IF NOT EXISTS "read_key_last_used_at" varchar(255); | |
| 29 | CREATE UNIQUE INDEX IF NOT EXISTS "sites_read_key_unique" ON "sites" ("read_key") WHERE "read_key" IS NOT NULL; | |