feat(admin): drizzle trade-lock + RCON sync and photo local purge
Co-authored-by: Cursor <[email protected]>
This commit is contained in:
1 parent
67656a9aad
commit
9854719cfd
7 files changed
+250
-45
No files matched your search
@@ -0,0 +1,39 @@
|
||||
import { unlink } from "node:fs/promises";
|
||||
import path from "node:path";
|
||||
|
||||
/**
|
||||
* Best-effort local file delete for camera photos hosted under /public.
|
||||
* External CDN URLs are left alone (no purge credentials in this CMS).
|
||||
*/
|
||||
export async function tryRemoveLocalPhotoFile(url: string): Promise<boolean> {
|
||||
if (!url?.trim()) return false;
|
||||
let pathname = url.trim();
|
||||
if (/^https?:\/\//i.test(pathname)) {
|
||||
try {
|
||||
const parsed = new URL(pathname);
|
||||
const app = (
|
||||
process.env.APP_URL ||
|
||||
process.env.NEXT_PUBLIC_APP_URL ||
|
||||
""
|
||||
).replace(/\/$/, "");
|
||||
if (!app || !pathname.startsWith(app)) return false;
|
||||
pathname = parsed.pathname;
|
||||
} catch {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
if (!pathname.startsWith("/")) return false;
|
||||
const rel = pathname.replace(/^\/+/, "");
|
||||
if (!rel || rel.includes("..")) return false;
|
||||
const publicRoot = path.resolve(process.cwd(), "public");
|
||||
const full = path.resolve(publicRoot, rel);
|
||||
if (!full.startsWith(publicRoot + path.sep) && full !== publicRoot) {
|
||||
return false;
|
||||
}
|
||||
try {
|
||||
await unlink(full);
|
||||
return true;
|
||||
} catch {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
Reference in new issue
Block a user