|
@@ -0,0 +1,73 @@
|
|
|
|
|
+export default {
|
|
|
|
|
+ async fetch(request, env) {
|
|
|
|
|
+ const method = request.method;
|
|
|
|
|
+
|
|
|
|
|
+ // Allow only POST (upload) and DELETE
|
|
|
|
|
+ if (method !== "POST" && method !== "DELETE") {
|
|
|
|
|
+ return new Response("Method Not Allowed", { status: 405 });
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ const contentType = request.headers.get("content-type") || "";
|
|
|
|
|
+
|
|
|
|
|
+ let site, path, file;
|
|
|
|
|
+
|
|
|
|
|
+ // Handle DELETE
|
|
|
|
|
+ if (method === "DELETE") {
|
|
|
|
|
+ const url = new URL(request.url);
|
|
|
|
|
+ site = url.searchParams.get("site");
|
|
|
|
|
+ path = url.searchParams.get("path");
|
|
|
|
|
+
|
|
|
|
|
+ if (!site || !path) {
|
|
|
|
|
+ return new Response("Missing site or path", { status: 400 });
|
|
|
|
|
+ }
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ // Handle POST (upload)
|
|
|
|
|
+ if (method === "POST") {
|
|
|
|
|
+ if (!contentType.includes("multipart/form-data")) {
|
|
|
|
|
+ return new Response("Invalid Content-Type", { status: 400 });
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ const form = await request.formData();
|
|
|
|
|
+ site = form.get("site");
|
|
|
|
|
+ path = form.get("path");
|
|
|
|
|
+ file = form.get("file");
|
|
|
|
|
+
|
|
|
|
|
+ if (!site || !path || !file) {
|
|
|
|
|
+ return new Response("Missing site, path, or file", { status: 400 });
|
|
|
|
|
+ }
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ // Validate inputs
|
|
|
|
|
+ if (!isValidSite(site) || !isValidPath(path)) {
|
|
|
|
|
+ return new Response("Invalid site or path", { status: 400 });
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ const key = `site:${site}:${path}`;
|
|
|
|
|
+
|
|
|
|
|
+ // DELETE logic
|
|
|
|
|
+ if (method === "DELETE") {
|
|
|
|
|
+ await env.PAGES_KV.delete(key);
|
|
|
|
|
+ return new Response("Deleted", { status: 200 });
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ // POST logic (upload / redeploy)
|
|
|
|
|
+ const data = await file.arrayBuffer();
|
|
|
|
|
+ await env.PAGES_KV.put(key, data);
|
|
|
|
|
+
|
|
|
|
|
+ return new Response("Uploaded", { status: 200 });
|
|
|
|
|
+ },
|
|
|
|
|
+};
|
|
|
|
|
+
|
|
|
|
|
+function isValidSite(site) {
|
|
|
|
|
+ return /^[a-z0-9-]{1,50}$/.test(site);
|
|
|
|
|
+}
|
|
|
|
|
+
|
|
|
|
|
+function isValidPath(path) {
|
|
|
|
|
+ return (
|
|
|
|
|
+ typeof path === "string" &&
|
|
|
|
|
+ !path.includes("..") &&
|
|
|
|
|
+ !path.startsWith("/") &&
|
|
|
|
|
+ path.length <= 200
|
|
|
|
|
+ );
|
|
|
|
|
+}
|