From 6c0d0610239581ffeb98b7372feb4b3af61d6f01 Mon Sep 17 00:00:00 2001 From: Joseph Date: Thu, 31 Oct 2024 17:05:05 +0000 Subject: [PATCH] Upload files to "api/src" --- api/src/index.ts | 211 +++++++++++++++++++++++++++++++++++++++++++++++ api/src/types.ts | 33 ++++++++ api/src/utils.ts | 45 ++++++++++ 3 files changed, 289 insertions(+) create mode 100644 api/src/index.ts create mode 100644 api/src/types.ts create mode 100644 api/src/utils.ts diff --git a/api/src/index.ts b/api/src/index.ts new file mode 100644 index 0000000..d79d683 --- /dev/null +++ b/api/src/index.ts @@ -0,0 +1,211 @@ +import { Router, IRequest } from "itty-router"; +import { StoredRequest, RequestBin, ReturnedRequest } from "./types"; +import { mapRequest, randomString, json } from "./utils"; + +export interface Env { + DB: D1Database; +} + +const router = Router(); + +router.post("/create", async (req, env: Env) => { + const id = randomString(10); + + const result = await env.DB.prepare("INSERT INTO bins (id) values (?)").bind(id).run(); + + if (!result.success) { + return json({ + success: false, + message: "An unknown error occurred" + }, { status: 500 }); + } + + return json({ + success: true, + bin: { + id + } + }); +}); +router.all("/-/:id/*", async (request, env: Env) => { + const { params, method, headers, url } = request; + const { id } = params; + + const result = await env.DB.prepare("SELECT * FROM bins WHERE id = ?").bind(id).first("id"); + + if (!result) { + return json({ + success: false, + message: "A request bin could not be found with the ID provided" + }, { status: 404 }); + } + + const headersObject: {[k: string]: string} = {}; + let ip = ""; + + for (const [key, value] of headers) { + headersObject[key] = value; + + if (key === "cf-connecting-ip") + ip = value; + } + + const requestId = randomString(10); + const body = await request.arrayBuffer(); + + const insertResult = await env.DB + .prepare("INSERT INTO requests (id, ip, method, url, timestamp, headers, body, bin_id) VALUES (?, ?, ?, ?, ?, ?, ?, ?)") + .bind(requestId, ip, method, url, Date.now(), JSON.stringify(headersObject), body, id) + .run(); + + if (!insertResult.success) { + return json({ + success: false, + message: "An unknown error occurred" + }, { status: 500 }); + } + + return json({ success: true }); +}); +router.delete("/:id", async ({ params }, env: Env) => { + const { id } = params; + + let result = await env.DB.prepare("DELETE FROM requests WHERE bin_id = ?").bind(id).run(); + + if (!result.success) { + return json({ + success: false, + message: "An unknown error occurred" + }, { status: 500 }); + } + + result = await env.DB.prepare("DELETE FROM bins WHERE id = ?").bind(id).run(); + + if (!result.success) { + return json({ + success: false, + message: "An unknown error occurred" + }, { status: 500 }); + } + + return json({ success: true }); +}); +router.delete("/:id/all", async ({ params }, env: Env) => { + const { id } = params; + + const binResult = await env.DB.prepare("SELECT * FROM bins WHERE id = ?").bind(id).first("id"); + + if (!binResult) { + return json({ + success: false, + message: "A request bin could not be found with the ID provided" + }, { status: 404 }); + } + + const result = await env.DB.prepare("DELETE FROM requests WHERE bin_id = ?").bind(id).run(); + + if (!result.success) { + return json({ + success: false, + message: "An unknown error occurred" + }, { status: 500 }); + } + + return json({ success: true }); +}); +router.delete("/:id/:requestId", async ({ params }, env: Env) => { + const { id, requestId } = params; + + const binResult = await env.DB.prepare("SELECT * FROM bins WHERE id = ?").bind(id).first("id"); + + if (!binResult) { + return json({ + success: false, + message: "A request bin could not be found with the ID provided" + }, { status: 404 }); + } + + const result = await env.DB.prepare("DELETE FROM requests WHERE bin_id = ? AND id = ?").bind(id, requestId).run(); + + if (!result.success) { + return json({ + success: false, + message: "An unknown error occurred" + }, { status: 500 }); + } + + return json({ success: true }); +}); +router.get("/:id", async ({ params }, env: Env) => { + const { id } = params; + + const result = await env.DB.prepare("SELECT * FROM bins WHERE id = ?").bind(id).first("id"); + + if (!result) { + return json({ + success: false, + message: "A request bin could not be found with the ID provided" + }, { status: 404 }); + } + + const requestsResult = await env.DB.prepare("SELECT * FROM requests WHERE bin_id = ?").bind(id).all(); + + if (!requestsResult.success) { + return json({ + success: false, + message: "An unknown error occurred" + }, { status: 500 }); + } + + const requestMap: {[key: string]: ReturnedRequest} = {}; + + for (const r of requestsResult.results) + requestMap[r.id] = mapRequest(r); + + return json({ + success: true, + bin: { + id, + requests: requestMap + } + }); +}); +router.get("/:id/:requestId", async ({ params }, env: Env) => { + const { id, requestId } = params; + + const result = await env.DB.prepare("SELECT * FROM bins WHERE id = ?").bind(id).first("id"); + + if (!result) { + return json({ + success: false, + message: "A request bin could not be found with the ID provided" + }, { status: 404 }); + } + + const request = await env.DB.prepare("SELECT * FROM requests WHERE bin_id = ? AND id = ?").bind(id, requestId).first(); + + if (!request) { + return json({ + success: false, + message: "A request could not be found in this bin with the ID provided" + }, { status: 404 }); + } + + return json({ success: true, request: mapRequest(request) }); +}); +router.all("*", () => { + return json({ success: false, message: "Endpoint not found" }, { status: 404 }); +}); + +export default { + fetch(req: Request, env: Env, ctx: ExecutionContext) { + return router.handle(req, env, ctx).catch(e => { + console.error(e); + + return json({ + success: false, + message: "An unknown error occurred" + }, { status: 500 }); + }); + } +}; diff --git a/api/src/types.ts b/api/src/types.ts new file mode 100644 index 0000000..6fab4b5 --- /dev/null +++ b/api/src/types.ts @@ -0,0 +1,33 @@ +export interface Headers { + [key: string]: string +} + +export interface StoredRequest { + id: string; + bin_id: string + ip: string + method: string + url: string + timestamp: number + headers: string + body?: ArrayBuffer +} + +export interface ReturnedRequest { + id: string + ip: string + method: string + url: string + timestamp: number + headers: Headers + body?: ArrayBuffer +} + +export interface Requests { + [key: string]: ReturnedRequest +} + +export interface RequestBin { + id: string + requests: Requests +} diff --git a/api/src/utils.ts b/api/src/utils.ts new file mode 100644 index 0000000..f23cd22 --- /dev/null +++ b/api/src/utils.ts @@ -0,0 +1,45 @@ +import { Headers, ReturnedRequest, StoredRequest } from "./types"; + +const DEFAULT_CHARACTERS = "0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ"; + +export const randomString = (length: number, characters?: string): string => { + let charactersToUse = DEFAULT_CHARACTERS; + + if (characters) + charactersToUse = characters; + + let result = ""; + + for (let i = 0; i < length; i++) + result += charactersToUse.charAt(Math.floor(Math.random() * charactersToUse.length)); + + return result; +}; + +export const mapRequest = (storedRequest: StoredRequest): ReturnedRequest => { + return { + id: storedRequest.id, + method: storedRequest.method, + ip: storedRequest.ip, + url: storedRequest.url, + timestamp: storedRequest.timestamp, + headers: JSON.parse(storedRequest.headers) as Headers, + body: storedRequest.body + }; +}; + +export const json = (body: object, options: ResponseInit = {}): Response => { + const { headers = {}, ...rest } = options; + + return new Response(JSON.stringify(body), { + headers: { + "Content-Type": "application/json", + "Access-Control-Allow-Origin": "*", + "Access-Control-Allow-Headers": "*", + "Access-Control-Allow-Methods": "GET,POST,PUT,PATCH,HEAD,TRACE,CONNECT,OPTIONS", + ...headers + }, + ...rest + }); +}; +