diff --git a/module.d.ts b/module.d.ts index f906b0b..ecfa99e 100644 --- a/module.d.ts +++ b/module.d.ts @@ -8,7 +8,7 @@ declare module "activitypub-http-signatures" { export class Sha256Signer { constructor(options: { publicKeyId: string, privateKey: string, headerNames?: string[] }); - sign: (options: { url: string, method: string, headers: any[] }) => string; + sign: (options: { url: string, method: string, headers: HeadersInit }) => string; }; type parse = (params: { url: string, method: string, headers: Record }) => { diff --git a/src/net.ts b/src/net.ts index 94d3042..f5fdc40 100644 --- a/src/net.ts +++ b/src/net.ts @@ -19,24 +19,22 @@ export interface SignedInit { // TODO: Handle redirects. export const signedFetch = async (url: string, init: RequestInit, signedInit: SignedInit): Promise => { - const signedHeaders: HeadersInit = [ - ["Date", new Date().toUTCString()] - ]; + const signedHeaders: HeadersInit = {}; const headerNames = ["(request-target)", "host", "date"]; if (init.method === "POST") { headerNames.push("content-type", "digest"); - signedHeaders.push(["Content-Type", `application/ld+json; profile="${CONTEXT}"`]); + signedHeaders["content-type"] = `application/ld+json; profile="${CONTEXT}"`; if (init.body) { if (signedInit.digest) { - signedHeaders.push(["Digest", signedInit.digest]); + signedHeaders["digest"] = signedInit.digest; } else { if (Buffer.isBuffer(init.body) || typeof init.body === "string") { - signedHeaders.push(["Digest", hashDigest(init.body)]); + signedHeaders["digest"] = hashDigest(init.body); } else throw "unsupported body type"; } @@ -53,19 +51,29 @@ export const signedFetch = async (url: string, init: RequestInit, signedInit: Si const signature = signer.sign({ url, method: init.method as string, - headers: [ - ["Host", new URL(url).host], - ...signedHeaders - ] + headers: signedHeaders }); + // Retain order for picky servers. + const newHeaders: HeadersInit = [ - ...signedHeaders, - ["Signature", signature] + ["date", signedHeaders.date], ] ; + if (signedHeaders["content-type"]) newHeaders.push([ + "content-type", + signedHeaders["content-type"] + ]); + + if (signedHeaders.digest) newHeaders.push([ + "digest", + signedHeaders.digest + ]); + + newHeaders.push(["signature", signature]); + if (Array.isArray(init.headers)) init.headers .filter((header) => Array.isArray(header))