0051_project_storage_share_links.sql 1.6 KB

12345678910111213141516171819202122232425262728293031
  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.
  12. CREATE 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
  23. DO $$ 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;
  25. EXCEPTION
  26. WHEN duplicate_object THEN null;
  27. END $$;
  28. --> statement-breakpoint
  29. CREATE UNIQUE INDEX IF NOT EXISTS "project_storage_share_links_token_idx" ON "project_storage_share_links" ("token");
  30. --> statement-breakpoint
  31. CREATE INDEX IF NOT EXISTS "project_storage_share_links_project_idx" ON "project_storage_share_links" ("project_id");