Skip to content

dev: Scam file purge helper - #3629

Open
isTravis wants to merge 7 commits into
mainfrom
tr/purge-helper
Open

dev: Scam file purge helper#3629
isTravis wants to merge 7 commits into
mainfrom
tr/purge-helper

Conversation

@isTravis

@isTravisisTravis commented Jun 4, 2026

Copy link
Copy Markdown
Member

Adds a new Scam Files tab to the superadmin dashboard for handling phishing/malware reports on assets.pubpub.org. Previously, responding to these reports required manually running S3 commands and CDN purge API calls. This tab provides a guided workflow with status verification at each step.

I have only tested this locally, where there aren't the same spam files that are being reported from prod. This will likely need a couple iterations to work out bugs that we'll only find once deployed.

Workflow

  1. Paste the reported URL directly from the email (defanged formats like hxxps://assets.pubpub[.]org/... are handled automatically)
  2. Copy the file to the reported-scams S3 bucket (preserving the key as an archive)
  3. Delete the file from assets.pubpub.org
  4. Purge Fastly cache (single-URL purge, not zone-wide)
  5. Purge Cloudflare cache (single-URL purge, gated until Fastly is confirmed clear)

A Check Status button queries each layer independently — S3 via HeadObject (bypasses CDN), and a HEAD request to the CDN URL to inspect cf-cache-status, x-cache, and other headers — so you can verify the file is fully gone before and after each step.

The check also searches User and Community image fields for references to the asset key. If an associated account is found, it displays the current spam status and provides quick Mark Spam / Mark Not Spam buttons (using the existing spamTags API).

New env var required

CLOUDFLARE_CACHE_PURGE_API_TOKEN — a Cloudflare API token with Zone > Cache Purge > Edit permission. The tab warns if this isn't set but doesn't block the other steps.

@isTravis
isTravis requested a review from tefkahJune 4, 2026 02:18

CopilotAI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Pull request overview

Adds a new “Scam Files” workflow to the SuperAdmin dashboard to streamline responding to phishing/malware reports targeting assets.pubpub.org, including S3 archive/copy + delete and CDN cache purges (Fastly + Cloudflare), with a status-check endpoint/UI.

Changes:

  • Adds a new scamFiles SuperAdmin tab and React UI for a guided removal workflow + status checks.
  • Introduces server-side APIs to copy/delete S3 objects and purge Fastly/Cloudflare caches for a single asset URL.
  • Extends env/schema + infra envs for Cloudflare cache purge token configuration.

Reviewed changes

Copilot reviewed 13 out of 13 changed files in this pull request and generated 7 comments.

Show a summary per file
FileDescription
utils/superAdmin.tsRegisters new scamFiles tab kind.
server/utils/s3.tsAdds S3 delete/copy helpers and a reported-scams client.
server/utils/fastlyPurge.tsNew helper to purge Fastly by URL.
server/utils/cloudflareCachePurge.tsNew helper to purge Cloudflare cache by URL list + config check.
server/routes/superAdminDashboard.tsxAdds Scam Files API routes (copy/delete/purge/check) and SSR tab props.
server/envSchema.tsAdds CLOUDFLARE_CACHE_PURGE_API_TOKEN to env validation.
infra/.env.local.encAdds encrypted Cloudflare cache purge token.
infra/.env.encAdds encrypted Cloudflare cache purge token.
infra/.env.dev.encAdds encrypted Cloudflare cache purge token.
client/containers/SuperAdminDashboard/tabs.tsxRegisters “Scam Files” tab in client tab map.
client/containers/SuperAdminDashboard/ScamFiles/ScamFiles.tsxNew UI for parsing URL, running steps, checking status, and marking spam.
client/containers/SuperAdminDashboard/ScamFiles/scamFiles.scssStyles for the new Scam Files UI.
client/containers/SuperAdminDashboard/ScamFiles/index.tsBarrel export for the new tab component.

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment threadserver/utils/fastlyPurge.ts Outdated
Comment on lines +3 to +16
export async function purgeByUrl(url: string) {
const res = await fetch(`https://api.fastly.com/purge/${url}`, {
method: 'POST',
headers: {
'Fastly-Key': env.FASTLY_PURGE_TOKEN,
Accept: 'application/json',
},
});
const json = await res.json();
if (!res.ok) {
throw new Error(`Fastly purge failed: ${json?.msg || res.statusText}`);
}
return json;
}
Comment threadserver/utils/s3.ts
Comment on lines +192 to +200
const copyObjectTo = async (key: string, destBucket: string) => {
await s3Client.send(
new CopyObjectCommand({
Bucket: destBucket,
Key: key,
CopySource: `${bucket}/${key}`,
}),
);
};
Comment on lines +699 to +703
// Keys follow the pattern: c{communityId}/p{pubId}/u{userId}/filename
// The /p{pubId} segment is optional.
const parseIdsFromKey = (key: string) => {
const communityMatch = key.match(/^(?:_testing\/)?c([0-9a-f-]{36})\//i);
const userMatch = key.match(/\/u([0-9a-f-]{36})\//i);
Comment threadserver/utils/cloudflareCachePurge.ts Outdated
Comment on lines +18 to +33
const res = await fetch(`${CF_API_BASE}/zones/${zoneId}/purge_cache`, {
method: 'POST',
headers: {
Authorization: `Bearer ${apiToken}`,
'Content-Type': 'application/json',
},
body: JSON.stringify({ files: urls }),
});

const json = await res.json();
if (!json.success) {
const msgs = (json.errors ?? []).map((e: any) => e.message).join('; ');
throw new Error(`Cloudflare cache purge failed: ${msgs || res.statusText}`);
}
return json;
}
Comment threadserver/routes/superAdminDashboard.tsx Outdated
Sign up for freeto 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.

3 participants

@isTravis@tefkah