Skip to content

feat: report link and staff takedown for Cap Infra videos - #4172

Merged
richiemcilroy merged 19 commits into
mainfrom
fix/infra-report-takedown
Nov 13, 2026
Merged

richiemcilroy merged 19 commits into
mainfrom
fix/infra-report-takedown

Conversation

@richiemcilroy

@richiemcilroy richiemcilroy commented Nov 13, 2026 •

Copy link
Copy Markdown
Member

Viewers of a Cap Infra video had no way to report abuse, and staff had no quick way to switch a single video off. This adds both.

What changes

  • Report link. The hosted page (/dev/{playbackId}) has a small "Report" link beside the title. The embed has one in its top corner that only shows while the pointer is over a player with its controls showing, or on keyboard focus. Both open an email to hello@cap.so with the subject Report video {playbackId}.
  • Takedown. A taken down video answers 410 Gone:
    • every file on /api/developer/playback/{playbackId}/{file} (master and rendition playlists, segments, video.mp4, poster.jpg, anything else) answers a plain 410 with Cache-Control: no-store. OPTIONS is unchanged.
    • the hosted and embed pages render one plain sentence ("This video is not available.") with nothing from the video: no player, poster, playback URLs, title or size, and noindex. The page itself answers 200, which is fine because nothing on it can play.
  • Developer API. GET /videos, GET /videos/{id}, GET /videos/{id}/status and the agent API add takenDown (false for every other video). While it is true, hlsUrl, mp4Url and posterUrl are null. status, metadata and every other field read as before. OpenAPI and the REST docs list the field.
  • Console. The owner sees the video as "Taken down", in the neutral style, with a note that it is still stored and billed, rather than as failed.

How it is stored

No migration. The flag lives under a reserved key in developer_videos.metadata, which only createUpload writes, and which now drops that key from anything a developer sends. Taking a video down wraps the developer's own metadata inside the marker, and restoring writes it back. Both rewrites run in SQL (JSON_OBJECT / JSON_EXTRACT), so metadata never passes through JSON.parse and large integers in it come back exactly. I checked the round trip on MySQL 8 with an object holding a 20 digit integer, {}, an array, JSON null and SQL NULL.

status is never touched, so storage billing (which groups by status) and the minimum charges read a taken down video exactly like before: a ready video stays billed as ready. The switch writes only the metadata column, which a test checks.

How to take a video down and restore it

CAP_SESSION_TOKEN=<staff next-auth.session-token cookie> \
  bun scripts/infra-video-takedown.ts down <playback id | video id | page or playback URL>

CAP_SESSION_TOKEN=... bun scripts/infra-video-takedown.ts restore <same>

The script calls POST /api/admin/developer-video-takedown, gated by the existing requireAdmin() staff check. Because the session cookie is SameSite=None, the route only accepts application/json with no Origin or a same-origin one. Playback answers the change on the next request; cached 200/302 answers from before a takedown expire within the existing 60 second cache.

Signed media links a player already loaded before the takedown keep working until they expire, at most 18 hours later, because the stored files are kept so a restore is exact. Revoking those would need a storage-level deny and is not part of this change. When content has to disappear at once, deleting the video purges its files.

Regular playback and share pages

Videos that were never taken down answer exactly as before (same redirects, headers and cache-control), proven by a test that snapshots every file before a takedown and compares after a restore. proxy.ts is not touched, so no request gains a database read; the page and playback route read the flag from the row they already load. Regular /s/ share pages do not share any of this code.

Tests

  • developer-video-takedown-playback.test.ts: 410 for every file, GET and HEAD, ahead of the out of credit pause; restore gives byte-identical responses with and without developer metadata.
  • developer-video-takedown.test.ts: marker, SQL, the switch (by playback id, video id and URLs; idempotent; only metadata written), the staff route (staff only, JSON only, cross-site refused), the script, the API fields and the console state.
  • developer-video-page.test.ts: the report links, and the unavailable view on both pages with no source URLs, title, size or links, and noindex.
  • Player, API, agent and console tests updated for the additive field.

Full web unit suite passes locally except share-stage-identity.test.ts, which fails on Node 26 (localStorage) on main too and passes in CI.

RetriggerView in GreptileConfidence Score: 5/5

The PR appears safe to merge; no new blocking issue was found.

Summary

Adds report links and a reversible staff takedown for Cap Infra videos.

  • Staff can take down or restore a video without changing its stored status.
  • New playback requests for a taken-down video receive a plain 410 response.
  • Video pages offer a report link and hide taken-down video details.
  • Developer video responses show when a video is taken down.
  • The owner’s console labels a taken-down video and explains its status.

Reviews (7) · Last reviewed commit: "Merge remote-tracking branch 'origin/mai..." · Reviewed by Greptile

Stores the flag under a reserved key in developer_videos.metadata, wrapping
the developer's own metadata so a restore writes it back exactly. Status is
untouched, so storage billing reads the video as before. No migration.

A staff-only route and scripts/infra-video-takedown.ts flip it.
Every playback file of a taken down video answers a plain 410 with no-store,
and the hosted and embed pages answer a short 410 page from the proxy. The
hosted page gets a quiet Report link and the embed one in its top corner,
both opening an email to the support address with the playback id.
GET /videos/{id}, /videos/{id}/status and the agent API add takenDown and
null the playback URLs while a video is taken down. The console shows the
video as Taken down rather than failed.

@capy-ai capy-ai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Capy found 2 potential issues (1 high, 1 medium).

View 1 other finding in Capy.

Open in Capy

@vercel
vercel Bot temporarily deployed to Preview – cap-status November 13, 2026 05:46 Inactive
@vercel

vercel Bot commented Nov 13, 2026 •

Copy link
Copy Markdown
Contributor

The latest updates on your projects. Learn more about Vercel for GitHub.

1 Skipped Deployment
Project Deployment Actions Updated
cap-status Skipped Skipped Nov 13, 2026 6:50am UTC

@sandchest-com

sandchest-com Bot commented Nov 13, 2026 •

Copy link
Copy Markdown

Sandchest

Sandchest reviewed 9dda488: nothing exploitable found in this change.

Sandchest reviews every change for vulnerabilities an attacker could use · 5 credits · Review details

@capy-ai capy-ai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Capy found no issues.

View 1 other finding in Capy.

Open in Capy

@vercel
vercel Bot temporarily deployed to Preview – cap-status November 13, 2026 05:51 Inactive
@richiemcilroy

Copy link
Copy Markdown
Member Author

hey @greptileai, please re-review the PR

@capy-ai capy-ai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Capy found 1 potential issue (1 medium).

View 1 other finding in Capy.

Open in Capy

Comment thread apps/web/content/docs/api/rest-api.mdx Resolved
@vercel
vercel Bot temporarily deployed to Preview – cap-status November 13, 2026 05:57 Inactive
@richiemcilroy

Copy link
Copy Markdown
Member Author

hey @greptileai, please re-review the PR

@capy-ai capy-ai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Capy found no issues.

Open in Capy

@vercel
vercel Bot temporarily deployed to Preview – cap-status November 13, 2026 06:04 Inactive

@capy-ai capy-ai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Capy found no issues.

Open in Capy

@richiemcilroy

Copy link
Copy Markdown
Member Author

hey @greptileai, please re-review the PR

@vercel
vercel Bot temporarily deployed to Preview – cap-status November 13, 2026 06:12 Inactive

@capy-ai capy-ai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Capy found no issues.

View 1 other finding in Capy.

Open in Capy

Comment thread apps/web/lib/developer-video-player.ts Resolved
@richiemcilroy

Copy link
Copy Markdown
Member Author

hey @greptileai, please re-review the PR

@vercel
vercel Bot temporarily deployed to Preview – cap-status November 13, 2026 06:20 Inactive

@capy-ai capy-ai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Capy found no issues.

View 1 other finding in Capy.

Open in Capy

@richiemcilroy

Copy link
Copy Markdown
Member Author

hey @greptileai, please re-review the PR

@vercel
vercel Bot temporarily deployed to Preview – cap-status November 13, 2026 06:31 Inactive

@capy-ai capy-ai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Capy found no issues.

View 1 other finding in Capy.

Open in Capy

@richiemcilroy

Copy link
Copy Markdown
Member Author

hey @greptileai, please re-review the PR

@vercel
vercel Bot temporarily deployed to Preview – cap-status November 13, 2026 06:43 Inactive

@capy-ai capy-ai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Capy found no issues.

View 1 other finding in Capy.

Open in Capy

@vercel
vercel Bot temporarily deployed to Preview – cap-status November 13, 2026 06:50 Inactive

@capy-ai capy-ai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Capy found no issues.

Open in Capy

@richiemcilroy
richiemcilroy merged commit 374865e into main Nov 13, 2026
41 checks passed

This branch was successfully deployed

1 active and 1 inactive deployments
Preview – cap-web — 9dda4884 Deployed Nov 13, 2026 by vercel[bot]
Preview – cap-status — 9dda4884 Deployed Nov 13, 2026 by vercel[bot]
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant