feat: make url signing optional

This commit is contained in:
shiftinv 2022-09-04 14:39:03 +02:00
parent 533ab24b2a
commit ff98d3c9a0
4 changed files with 33 additions and 15 deletions

View File

@ -13,7 +13,7 @@ export default {
debug: parseBool(get("DEBUG", "0")), debug: parseBool(get("DEBUG", "0")),
hostname: get("HOSTNAME", "127.0.0.1"), hostname: get("HOSTNAME", "127.0.0.1"),
port: parseInt(get("PORT", "8080")), port: parseInt(get("PORT", "8080")),
signKey: get("SIGN_KEY"), signKey: get("SIGN_KEY", null),
maxWebhookRetries: parseInt(get("MAX_RETRIES", "3")), maxWebhookRetries: parseInt(get("MAX_RETRIES", "3")),
maxWebhookRetryMs: parseInt(get("MAX_RETRY_MS", "30000")), maxWebhookRetryMs: parseInt(get("MAX_RETRY_MS", "30000")),
}; };

View File

@ -1,24 +1,37 @@
import config from "./config.ts"; import config from "./config.ts";
import { hex } from "../deps.ts"; import { hex } from "../deps.ts";
const signKey = await crypto.subtle.importKey( export const hasKey = !!config.signKey;
"raw",
hex.decode(new TextEncoder().encode(config.signKey)),
{ name: "HMAC", hash: "SHA-256" },
false,
["sign", "verify"],
);
const encoder = new TextEncoder(); const encoder = new TextEncoder();
let _signKey: CryptoKey | undefined = undefined;
async function getKey(): Promise<CryptoKey> {
if (_signKey === undefined) {
if (!config.signKey) throw new Error("Signature requested but no key configured");
_signKey = await crypto.subtle.importKey(
"raw",
hex.decode(new TextEncoder().encode(config.signKey)),
{ name: "HMAC", hash: "SHA-256" },
false,
["sign", "verify"],
);
}
return _signKey;
}
export async function sign(input: string): Promise<string> { export async function sign(input: string): Promise<string> {
const key = await getKey();
const inputData = encoder.encode(input); const inputData = encoder.encode(input);
const sig = await crypto.subtle.sign("HMAC", signKey, inputData); const sig = await crypto.subtle.sign("HMAC", key, inputData);
return new TextDecoder().decode(hex.encode(new Uint8Array(sig))); return new TextDecoder().decode(hex.encode(new Uint8Array(sig)));
} }
export async function verify(input: string, signature: string): Promise<boolean> { export async function verify(input: string, signature: string): Promise<boolean> {
const key = await getKey();
const signatureData = hex.decode(encoder.encode(signature)); const signatureData = hex.decode(encoder.encode(signature));
const inputData = encoder.encode(input); const inputData = encoder.encode(input);
return await crypto.subtle.verify("HMAC", signKey, signatureData, inputData); return await crypto.subtle.verify("HMAC", key, signatureData, inputData);
} }

View File

@ -1,5 +1,5 @@
import { http, log } from "../deps.ts"; import { http, log } from "../deps.ts";
import { verify } from "./crypto.ts"; import { hasKey, verify } from "./crypto.ts";
import filterWebhook from "./filter.ts"; import filterWebhook from "./filter.ts";
import { UrlConfig } from "./types.d.ts"; import { UrlConfig } from "./types.d.ts";
import { parseBool } from "./util.ts"; import { parseBool } from "./util.ts";
@ -13,14 +13,15 @@ export default async function handle(req: Request): Promise<Response> {
// split url into parts // split url into parts
const url = new URL(req.url); const url = new URL(req.url);
const [, id, token] = url.pathname.split("/"); const [, id, token] = url.pathname.split("/");
const signature = url.searchParams.get("sig"); if (!id || !token) {
if (!id || !token || !signature) {
throw http.createHttpError(400); throw http.createHttpError(400);
} }
// verify signature // verify signature
if (!(await verify(`${id}/${token}`, signature))) { if (hasKey) {
throw http.createHttpError(403); const signature = url.searchParams.get("sig");
if (!signature) throw http.createHttpError(400);
if (!(await verify(`${id}/${token}`, signature))) throw http.createHttpError(403);
} }
// extract data // extract data

View File

@ -44,6 +44,10 @@ async function handleRequest(req: Request, connInfo: http.ConnInfo): Promise<Res
if (import.meta.main) { if (import.meta.main) {
setupLogs(); setupLogs();
if (!config.signKey) {
log.warning("url signing disabled");
}
log.info(`starting webserver on ${config.hostname}:${config.port}`); log.info(`starting webserver on ${config.hostname}:${config.port}`);
http.serve(handleRequest, { http.serve(handleRequest, {
hostname: config.hostname, hostname: config.hostname,