Added tests and security hardening
This commit is contained in:
parent
a8a6d544e3
commit
f29e06254d
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");',
|
||||||
|
},
|
||||||
|
);
|
||||||
|
});
|
51
server.ts
51
server.ts
|
@ -1,31 +1,56 @@
|
||||||
#!/usr/bin/env -S deno run --allow-run --allow-net
|
#!/usr/bin/env -S deno run --allow-run --allow-net
|
||||||
// Automated bundle server
|
// 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 { 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(
|
||||||
const listen = { hostname: "0.0.0.0", port: 8000 };
|
req: ServerRequest,
|
||||||
const server = serve(listen);
|
runner = Deno.run,
|
||||||
console.log(`Serving bundles on ${listen.hostname}:${listen.port} ...`);
|
): Promise<Response> {
|
||||||
for await (const req of server) {
|
|
||||||
const params = req.url.split("/").filter(bool);
|
const params = req.url.split("/").filter(bool);
|
||||||
const lib = params[0] || "all";
|
const lib = params[0] || "all";
|
||||||
const version = params[1] || "master";
|
const version = params[1] || "master";
|
||||||
const file = params.length > 2 ? params.slice(2).join("/") : "all";
|
const file = params.length > 2 ? params.slice(2).join("/") : "all";
|
||||||
const path =
|
const path =
|
||||||
`https://code.thunderk.net/typescript/${lib}/raw/${version}/${file}.ts`;
|
`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}");`,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
try {
|
const process = runner({
|
||||||
const process = Deno.run({
|
|
||||||
cmd: ["deno", "bundle", path],
|
cmd: ["deno", "bundle", path],
|
||||||
stdout: "piped",
|
stdout: "piped",
|
||||||
});
|
});
|
||||||
req.respond({ body: await process.output() });
|
const output = await process.output();
|
||||||
} catch {
|
const status = await process.status();
|
||||||
req.respond({ body: `console.error("Failed to bundle ${path}");` });
|
if (status.success) {
|
||||||
}
|
return { body: output };
|
||||||
|
} else {
|
||||||
|
return {
|
||||||
|
status: 500,
|
||||||
|
body: `console.error("bundler error - Failed to bundle ${path}");`,
|
||||||
|
};
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
await serveBundles();
|
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 response = await processRequest(req);
|
||||||
|
await req.respond(response);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (import.meta.main) {
|
||||||
|
await serveBundles();
|
||||||
|
}
|
||||||
|
|
Loading…
Reference in a new issue