Added tests and security hardening
This commit is contained in:
parent
a8a6d544e3
commit
f29e06254d
2 changed files with 117 additions and 19 deletions
73
server.test.ts
Normal file
73
server.test.ts
Normal file
|
@ -0,0 +1,73 @@
|
|||
import {
|
||||
expect,
|
||||
mockfn,
|
||||
test,
|
||||
} from "https://code.thunderk.net/typescript/devtools/raw/1.0.1/testing.ts";
|
||||
import { processRequest } from "./server.ts";
|
||||
|
||||
test("serveBundles standard", async () => {
|
||||
const mock_run = mockfn(() => {
|
||||
return {
|
||||
output: () => Promise.resolve(new TextEncoder().encode("abc")),
|
||||
status: () => Promise.resolve({ code: 0, success: true }),
|
||||
} as any;
|
||||
});
|
||||
|
||||
const response = await processRequest(
|
||||
{ url: "/greatlib/1.0.0/reader/" } as any,
|
||||
mock_run,
|
||||
);
|
||||
expect(response).toEqual({ body: new TextEncoder().encode("abc") });
|
||||
expect(mock_run).toHaveBeenCalledTimes(1);
|
||||
expect(mock_run).toHaveBeenCalledWith({
|
||||
cmd: [
|
||||
"deno",
|
||||
"bundle",
|
||||
"https://code.thunderk.net/typescript/greatlib/raw/1.0.0/reader.ts",
|
||||
],
|
||||
stdout: "piped",
|
||||
});
|
||||
});
|
||||
|
||||
test("serveBundles bad path", async () => {
|
||||
const mock_run = mockfn(() => {
|
||||
return {
|
||||
output: () => Promise.resolve(new TextEncoder().encode("abc")),
|
||||
status: () => Promise.resolve({ code: 0, success: true }),
|
||||
} as any;
|
||||
});
|
||||
|
||||
const response = await processRequest(
|
||||
{ url: "/greatlib/1.0.0/reader{}/" } as any,
|
||||
mock_run,
|
||||
);
|
||||
expect(response).toEqual(
|
||||
{
|
||||
status: 400,
|
||||
body:
|
||||
'console.error("bundler error - Invalid path https://code.thunderk.net/typescript/greatlib/raw/1.0.0/reader{}.ts");',
|
||||
},
|
||||
);
|
||||
expect(mock_run).toHaveBeenCalledTimes(0);
|
||||
});
|
||||
|
||||
test("serveBundles bundle fail", async () => {
|
||||
const mock_run = mockfn(() => {
|
||||
return {
|
||||
output: () => Promise.resolve(undefined),
|
||||
status: () => Promise.resolve({ code: 1, success: false }),
|
||||
} as any;
|
||||
});
|
||||
|
||||
const response = await processRequest(
|
||||
{ url: "/great_lib/1.0.0-dev1/reader/" } as any,
|
||||
mock_run,
|
||||
);
|
||||
expect(response).toEqual(
|
||||
{
|
||||
status: 500,
|
||||
body:
|
||||
'console.error("bundler error - Failed to bundle https://code.thunderk.net/typescript/great_lib/raw/1.0.0-dev1/reader.ts");',
|
||||
},
|
||||
);
|
||||
});
|
63
server.ts
63
server.ts
|
@ -1,31 +1,56 @@
|
|||
#!/usr/bin/env -S deno run --allow-run --allow-net
|
||||
// Automated bundle server
|
||||
|
||||
import { serve } from "https://deno.land/std/http/server.ts";
|
||||
import { bool } from "https://code.thunderk.net/typescript/functional/raw/1.0.0/all.ts";
|
||||
import {
|
||||
Response,
|
||||
serve,
|
||||
ServerRequest,
|
||||
} from "https://deno.land/std/http/server.ts";
|
||||
|
||||
async function serveBundles() {
|
||||
export async function processRequest(
|
||||
req: ServerRequest,
|
||||
runner = Deno.run,
|
||||
): Promise<Response> {
|
||||
const params = req.url.split("/").filter(bool);
|
||||
const lib = params[0] || "all";
|
||||
const version = params[1] || "master";
|
||||
const file = params.length > 2 ? params.slice(2).join("/") : "all";
|
||||
const path =
|
||||
`https://code.thunderk.net/typescript/${lib}/raw/${version}/${file}.ts`;
|
||||
if (!path.match(/^[a-z0-9\/\.\:-_]+$/)) {
|
||||
return {
|
||||
status: 400,
|
||||
body: `console.error("bundler error - Invalid path ${path}");`,
|
||||
};
|
||||
}
|
||||
|
||||
const process = runner({
|
||||
cmd: ["deno", "bundle", path],
|
||||
stdout: "piped",
|
||||
});
|
||||
const output = await process.output();
|
||||
const status = await process.status();
|
||||
if (status.success) {
|
||||
return { body: output };
|
||||
} else {
|
||||
return {
|
||||
status: 500,
|
||||
body: `console.error("bundler error - Failed to bundle ${path}");`,
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
export async function serveBundles() {
|
||||
const listen = { hostname: "0.0.0.0", port: 8000 };
|
||||
const server = serve(listen);
|
||||
console.log(`Serving bundles on ${listen.hostname}:${listen.port} ...`);
|
||||
for await (const req of server) {
|
||||
const params = req.url.split("/").filter(bool);
|
||||
const lib = params[0] || "all";
|
||||
const version = params[1] || "master";
|
||||
const file = params.length > 2 ? params.slice(2).join("/") : "all";
|
||||
const path =
|
||||
`https://code.thunderk.net/typescript/${lib}/raw/${version}/${file}.ts`;
|
||||
|
||||
try {
|
||||
const process = Deno.run({
|
||||
cmd: ["deno", "bundle", path],
|
||||
stdout: "piped",
|
||||
});
|
||||
req.respond({ body: await process.output() });
|
||||
} catch {
|
||||
req.respond({ body: `console.error("Failed to bundle ${path}");` });
|
||||
}
|
||||
const response = await processRequest(req);
|
||||
await req.respond(response);
|
||||
}
|
||||
}
|
||||
|
||||
await serveBundles();
|
||||
if (import.meta.main) {
|
||||
await serveBundles();
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue