0051_project_storage_share_links.sql31 lines · main
1-- 0051_project_storage_share_links — M5 S3 sprint (tokenized public share-links).
2--
3-- The public-link half of M5. A file OWNER mints a signed public link — a URL
4-- carrying a cryptographically-random token that ANYONE can open for a LIMITED
5-- TIME, with NO project/auth needed — and can revoke it at will. Unlike a grant
6-- (project→project), this exposes ONE file to the open internet.
7--
8-- Strict-deny by construction: a link resolves to its file ONLY when a row
9-- matches the exact token AND revoked_at IS NULL AND expires_at > now(). Revoke
10-- sets revoked_at (never deletes). The token is the only bearer credential and
11-- is never logged. Lands on the control DB (Postgres). Additive + idempotent.
12CREATE TABLE IF NOT EXISTS "project_storage_share_links" (
13 "id" text PRIMARY KEY NOT NULL,
14 "project_id" text NOT NULL,
15 "file_id" text NOT NULL,
16 "token" text NOT NULL,
17 "expires_at" timestamp with time zone NOT NULL,
18 "created_by" text,
19 "created_at" timestamp with time zone DEFAULT now() NOT NULL,
20 "revoked_at" timestamp with time zone
21);
22--> statement-breakpoint
23DO $$ BEGIN
24 ALTER TABLE "project_storage_share_links" ADD CONSTRAINT "project_storage_share_links_project_id_projects_id_fk" FOREIGN KEY ("project_id") REFERENCES "public"."projects"("id") ON DELETE cascade ON UPDATE no action;
25EXCEPTION
26 WHEN duplicate_object THEN null;
27END $$;
28--> statement-breakpoint
29CREATE UNIQUE INDEX IF NOT EXISTS "project_storage_share_links_token_idx" ON "project_storage_share_links" ("token");
30--> statement-breakpoint
31CREATE INDEX IF NOT EXISTS "project_storage_share_links_project_idx" ON "project_storage_share_links" ("project_id");