
      import { Temporal } from "@js-temporal/polyfill";
      import { URLPattern } from "urlpattern-polyfill";
      globalThis.addEventListener = () => {};
    
import { exportSpki } from "../type-BSR-vRXo.js";
import { assertEquals } from "../assert_equals-DSbWqCm3.js";
import { assert } from "../assert-MZs1qjMx.js";
import "../assert_instance_of-DHz7EHNU.js";
import "../lookup-q8DeFAjR.js";
import "../actor-By5NMImS.js";
import { exportJwk } from "../key-B057bXm0.js";
import { createRfc9421SignatureBase, doubleKnock, formatRfc9421Signature, formatRfc9421SignatureParameters, parseRfc9421Signature, parseRfc9421SignatureInput, signRequest, timingSafeEqual, verifyRequest } from "../http-CCydyMoV.js";
import { mockDocumentLoader, test } from "../testing-Cqwzq9nj.js";
import { assertExists, assertStringIncludes } from "../std__assert-X-_kMxKM.js";
import { assertFalse, assertRejects } from "../assert_rejects-DiIiJbZn.js";
import "../assert_is_error-BPGph1Jx.js";
import "../assert_not_equals-f3m3epl3.js";
import { assertThrows } from "../assert_throws-BOO88avQ.js";
import { rsaPrivateKey2, rsaPublicKey1, rsaPublicKey2, rsaPublicKey5 } from "../keys-Dz9o2VwW.js";
import { esm_default } from "../esm-CIFbziGC.js";
import { encodeBase64 } from "byte-encodings/base64";

//#region src/sig/http.test.ts
test("signRequest() [draft-cavage]", async () => {
	const request = new Request("https://example.com/", {
		method: "POST",
		body: "Hello, world!",
		headers: {
			"Content-Type": "text/plain; charset=utf-8",
			Accept: "text/plain"
		}
	});
	const signed = await signRequest(request, rsaPrivateKey2, new URL("https://example.com/key2"));
	assertEquals(await verifyRequest(signed, {
		contextLoader: mockDocumentLoader,
		documentLoader: mockDocumentLoader
	}), rsaPublicKey2);
});
test("verifyRequest() [draft-cavage]", async () => {
	const request = new Request("https://example.com/", {
		method: "POST",
		body: "Hello, world!",
		headers: {
			Accept: "text/plain",
			"Content-Type": "text/plain; charset=utf-8",
			Date: "Tue, 05 Mar 2024 07:49:44 GMT",
			Digest: "sha-256=MV9b23bQeMQ7isAGTkoBZGErH853yGk0W/yUx1iU7dM=",
			Signature: "keyId=\"https://example.com/key\",headers=\"(request-target) accept content-type date digest host\",signature=\"ZDeMzjBKPfJvkv4QaxAdOQxKCJ96pOzOCFhhGgGnlsw4N80oN4GEZ/n8nNKjpoW95Bcs8N0dZVSQHj3g08AReKIOXpun0tgmaWGKRcRT4kEhAW+uP1wVZPbuOIvVCEhMYv6+SbnttgX0GvN365BTZpxh7+gRrRC4mns5qV69cv45I5iJB0aw24GJW9u7lUAm6yDEh4N0aXfNqNRq3LHiuPqlDzSenfXbHr0UnAMaGuI4v9/uflu/jNi3hRX4Y/T+ngM1zvLvi/BjKK4I1rh520qnkrWpxz9ikLCjIMO7Dwh1nOsPzrZE2t43XHD3evdvm1RM5Ppes+M6DrfkfQuUBw==\""
		}
	});
	const cache = {};
	const options = {
		contextLoader: mockDocumentLoader,
		documentLoader: mockDocumentLoader,
		currentTime: Temporal.Instant.from("2024-03-05T07:49:44Z"),
		keyCache: {
			get(keyId) {
				return Promise.resolve(cache[keyId.href]);
			},
			set(keyId, key$1) {
				cache[keyId.href] = key$1;
				return Promise.resolve();
			}
		}
	};
	let key = await verifyRequest(request, options);
	assertEquals(key, rsaPublicKey1);
	assertEquals(cache, { "https://example.com/key": rsaPublicKey1 });
	cache["https://example.com/key"] = rsaPublicKey2;
	key = await verifyRequest(request, options);
	assertEquals(key, rsaPublicKey1);
	assertEquals(cache, { "https://example.com/key": rsaPublicKey1 });
	assertEquals(await verifyRequest(new Request("https://example.com/"), {
		documentLoader: mockDocumentLoader,
		contextLoader: mockDocumentLoader
	}), null);
	assertEquals(await verifyRequest(new Request("https://example.com/", { headers: { Date: "Tue, 05 Mar 2024 07:49:44 GMT" } }), {
		documentLoader: mockDocumentLoader,
		contextLoader: mockDocumentLoader
	}), null);
	assertEquals(await verifyRequest(new Request("https://example.com/", {
		method: "POST",
		headers: {
			Date: "Tue, 05 Mar 2024 07:49:44 GMT",
			Signature: "asdf"
		}
	}), {
		documentLoader: mockDocumentLoader,
		contextLoader: mockDocumentLoader
	}), null);
	assertEquals(await verifyRequest(new Request("https://example.com/", {
		method: "POST",
		headers: {
			Date: "Tue, 05 Mar 2024 07:49:44 GMT",
			Signature: "asdf",
			Digest: "invalid"
		},
		body: ""
	}), {
		documentLoader: mockDocumentLoader,
		contextLoader: mockDocumentLoader
	}), null);
	assertEquals(await verifyRequest(new Request("https://example.com/", {
		method: "POST",
		headers: {
			Date: "Tue, 05 Mar 2024 07:49:44 GMT",
			Signature: "asdf",
			Digest: "sha-256=MV9b23bQeMQ7isAGTkoBZGErH853yGk0W/yUx1iU7dM="
		},
		body: ""
	}), {
		documentLoader: mockDocumentLoader,
		contextLoader: mockDocumentLoader
	}), null);
	assertEquals(await verifyRequest(request, {
		documentLoader: mockDocumentLoader,
		contextLoader: mockDocumentLoader,
		currentTime: Temporal.Instant.from("2024-03-05T06:49:43.9999Z")
	}), null);
	assertEquals(await verifyRequest(request, {
		documentLoader: mockDocumentLoader,
		contextLoader: mockDocumentLoader,
		currentTime: Temporal.Instant.from("2024-03-05T07:49:13.9999Z"),
		timeWindow: { seconds: 30 }
	}), null);
	assertEquals(await verifyRequest(request, {
		documentLoader: mockDocumentLoader,
		contextLoader: mockDocumentLoader,
		currentTime: Temporal.Instant.from("2024-03-05T08:49:44.0001Z")
	}), null);
	assertEquals(await verifyRequest(request, {
		documentLoader: mockDocumentLoader,
		contextLoader: mockDocumentLoader,
		currentTime: Temporal.Instant.from("2024-03-05T07:50:14.0001Z"),
		timeWindow: { seconds: 30 }
	}), null);
	assertEquals(await verifyRequest(request, {
		documentLoader: mockDocumentLoader,
		contextLoader: mockDocumentLoader,
		currentTime: Temporal.Instant.from("2024-01-01T00:00:00.0000Z"),
		timeWindow: false
	}), rsaPublicKey1);
	assertEquals(await verifyRequest(request, {
		documentLoader: mockDocumentLoader,
		contextLoader: mockDocumentLoader,
		currentTime: Temporal.Instant.from("2025-01-01T00:00:00.0000Z"),
		timeWindow: false
	}), rsaPublicKey1);
	const request2 = new Request("https://c27a97f98d5f.ngrok.app/i/inbox", {
		method: "POST",
		body: "{\"@context\":[\"https://www.w3.org/ns/activitystreams\",\"https://w3id.org/security/v1\"],\"actor\":\"https://oeee.cafe/ap/users/3609fd4e-d51d-4db8-9f04-4189815864dd\",\"object\":{\"actor\":\"https://c27a97f98d5f.ngrok.app/i\",\"object\":\"https://oeee.cafe/ap/users/3609fd4e-d51d-4db8-9f04-4189815864dd\",\"type\":\"Follow\",\"id\":\"https://c27a97f98d5f.ngrok.app/i#follows/https://oeee.cafe/ap/users/3609fd4e-d51d-4db8-9f04-4189815864dd\"},\"type\":\"Accept\",\"id\":\"https://oeee.cafe/objects/0fc2608f-5660-4b91-b8c7-63c0c2ac2e20\"}",
		headers: {
			Host: "c27a97f98d5f.ngrok.app",
			"Content-Type": "application/activity+json",
			Date: "Mon, 25 Aug 2025 12:58:14 GMT",
			Digest: "SHA-256=YZyjeVQW5GwliJowASkteBJhFBTq3eQk/AMqRETc//A=",
			Signature: "keyId=\"https://oeee.cafe/ap/users/3609fd4e-d51d-4db8-9f04-4189815864dd#main-key\",algorithm=\"hs2019\",created=\"1756126694\",expires=\"1756130294\",headers=\"(request-target) (created) (expires) content-type date digest host\",signature=\"XFb0jl2uMhE7RhbneE9sK9Zls2qZec8iy6+9O8UgDQeBGJThORFLjXKlps4QO1WAf1YSVB/i5aV6yF+h73Lm3ZiuAJDx1h+00iLsxoYuIw1CZvF0V2jELoo3sQ2/ZzqeoO6H5TbK7tKnU+ulFAPTuJgjIvPwYl11OMRouVS34NiaHP9Yx9pU813TLv37thG/hUKanyq8kk0IJWtDWteY/zxDvzoe7VOkBXVBHslMyrNAI/5JGulVQAQp/E61dJAhTHHIyGxkc/7iutWFZuqFXIiPJ9KR2OuKDj/B32hEzlsf5xH/CjqOJPIg1qMK8FzDiALCq6zjiKIBEnW8HQc/hQ==\""
		}
	});
	const options2 = {
		...options,
		currentTime: Temporal.Instant.from("2025-08-25T12:58:14Z")
	};
	assert(await verifyRequest(request2, options2) != null);
});
test("signRequest() and verifyRequest() [rfc9421] implementation", async () => {
	const currentTimestamp = 1709626184;
	const currentTime = Temporal.Instant.from("2024-03-05T08:09:44Z");
	const requestBody = "Test content for signature verification";
	const request = new Request("https://example.com/api/resource", {
		method: "POST",
		body: requestBody,
		headers: {
			"Content-Type": "text/plain; charset=utf-8",
			"Accept": "application/json",
			"Host": "example.com",
			"Date": "Tue, 05 Mar 2024 07:49:44 GMT"
		}
	});
	const signed = await signRequest(request, rsaPrivateKey2, new URL("https://example.com/key2"), {
		spec: "rfc9421",
		currentTime
	});
	assertEquals(signed.headers.has("Signature-Input"), true);
	assertEquals(signed.headers.has("Signature"), true);
	const signatureInput = signed.headers.get("Signature-Input");
	assertExists(signatureInput);
	assertStringIncludes(signatureInput, "sig1=", "Should have a signature ID");
	assertStringIncludes(signatureInput, "keyid=\"https://example.com/key2\"", "Should contain the exact keyId");
	assertStringIncludes(signatureInput, "alg=\"rsa-v1_5-sha256\"", "Should specify the correct algorithm");
	assertStringIncludes(signatureInput, `created=${currentTimestamp}`, "Should contain the exact timestamp");
	const expectedComponents = [
		"@method",
		"@target-uri",
		"@authority",
		"host",
		"date",
		"content-digest"
	];
	for (const component of expectedComponents) assertStringIncludes(signatureInput, `"${component}"`, `Should include component: ${component}`);
	assertEquals(signed.headers.has("Content-Digest"), true, "Should include Content-Digest for POST with body");
	const contentDigest = signed.headers.get("Content-Digest");
	assertExists(contentDigest);
	assert(contentDigest.startsWith("sha-256=:"), "Content-Digest should use RFC 9421 format");
	const expectedDigest = await crypto.subtle.digest("SHA-256", new TextEncoder().encode(requestBody));
	const expectedDigestBase64 = encodeBase64(expectedDigest);
	assertEquals(contentDigest, `sha-256=:${expectedDigestBase64}:`, "Content-Digest should have correct value");
	const signature = signed.headers.get("Signature");
	assertExists(signature);
	const sigFormat = /^sig1=:([A-Za-z0-9+/]+=*):/;
	assert(sigFormat.test(signature), `Signature format (${signature}) should match RFC 9421 format`);
	const sigMatch = signature.match(sigFormat);
	assertExists(sigMatch);
	const sigValue = sigMatch[1];
	assert(sigValue.length > 10, "Signature value should be a substantial base64 string");
	const parsedInput = parseRfc9421SignatureInput(signatureInput);
	assertExists(parsedInput.sig1);
	assertEquals(parsedInput.sig1.keyId, "https://example.com/key2");
	assertEquals(parsedInput.sig1.alg, "rsa-v1_5-sha256");
	assertEquals(parsedInput.sig1.created, currentTimestamp);
	assertEquals(parsedInput.sig1.components.length, expectedComponents.length, "Should have all expected components");
	for (const component of expectedComponents) assert(parsedInput.sig1.components.includes(component), `Components should include ${component}`);
	const parsedSig = parseRfc9421Signature(signature);
	assertExists(parsedSig.sig1);
	assertEquals(parsedSig.sig1.byteLength > 0, true, "Signature value should be a non-empty Uint8Array");
	const verifyHeaders = new Headers();
	for (const [name, value] of signed.headers.entries()) if (name !== "Signature" && name !== "Signature-Input") verifyHeaders.set(name, value);
	const reconstructedRequest = new Request(request.url, {
		method: request.method,
		headers: verifyHeaders
	});
	const reconstructedBase = createRfc9421SignatureBase(reconstructedRequest, parsedInput.sig1.components, parsedInput.sig1.parameters);
	const signatureBytes = new Uint8Array(parsedSig.sig1);
	const signatureVerifies = await crypto.subtle.verify("RSASSA-PKCS1-v1_5", rsaPublicKey2.publicKey, signatureBytes, new TextEncoder().encode(reconstructedBase));
	assert(signatureVerifies, "Manual verification of signature should succeed");
});
test("createRfc9421SignatureBase()", () => {
	const request = new Request("https://example.com/path?query=value", {
		method: "POST",
		headers: {
			Host: "example.com",
			Date: "Tue, 05 Mar 2024 07:49:44 GMT",
			"Content-Type": "text/plain"
		}
	});
	const components = [
		"@method",
		"@target-uri",
		"host",
		"date"
	];
	const created = 1709626184;
	const signatureBase = createRfc9421SignatureBase(request, components, formatRfc9421SignatureParameters({
		algorithm: "rsa-v1_5-sha256",
		keyId: new URL("https://example.com/key"),
		created
	}));
	const expected = [
		`"@method": POST`,
		`"@target-uri": https://example.com/path?query=value`,
		`"host": example.com`,
		`"date": Tue, 05 Mar 2024 07:49:44 GMT`,
		`"@signature-params": ("@method" "@target-uri" "host" "date");alg="rsa-v1_5-sha256";keyid="https://example.com/key";created=1709626184`
	].join("\n");
	assertEquals(signatureBase, expected);
});
test("formatRfc9421Signature()", () => {
	const signature = new Uint8Array([
		1,
		2,
		3,
		4
	]);
	const keyId = new URL("https://example.com/key");
	const algorithm = "rsa-v1_5-sha256";
	const components = [
		"@method",
		"@target-uri",
		"host"
	];
	const created = 1709626184;
	const [signatureInput, signatureHeader] = formatRfc9421Signature(signature, components, formatRfc9421SignatureParameters({
		algorithm,
		keyId,
		created
	}));
	assertEquals(signatureInput, `sig1=("@method" "@target-uri" "host");alg="rsa-v1_5-sha256";keyid="https://example.com/key";created=1709626184`);
	assertEquals(signatureHeader, `sig1=:AQIDBA==:`);
});
test("parseRfc9421SignatureInput()", () => {
	const signatureInput = `sig1=("@method" "@target-uri" "host" "date");keyid="https://example.com/key";alg="rsa-v1_5-sha256";created=1709626184`;
	const parsed = parseRfc9421SignatureInput(signatureInput);
	assertEquals(parsed.sig1.keyId, "https://example.com/key");
	assertEquals(parsed.sig1.alg, "rsa-v1_5-sha256");
	assertEquals(parsed.sig1.created, 1709626184);
	assertEquals(parsed.sig1.components, [
		"@method",
		"@target-uri",
		"host",
		"date"
	]);
	assertEquals(parsed.sig1.parameters, "keyid=\"https://example.com/key\";alg=\"rsa-v1_5-sha256\";created=1709626184");
});
test("parseRfc9421Signature()", () => {
	const signature = `sig1=:AQIDBA==:,sig2=:Zm9vYmFy:`;
	const parsed = parseRfc9421Signature(signature);
	assertExists(parsed.sig1);
	assertExists(parsed.sig2);
	const sig1Bytes = new Uint8Array(parsed.sig1);
	assertEquals(sig1Bytes.length, 4);
	assertEquals(sig1Bytes[0], 1);
	assertEquals(sig1Bytes[1], 2);
	assertEquals(sig1Bytes[2], 3);
	assertEquals(sig1Bytes[3], 4);
	const sig2Text = new TextDecoder().decode(parsed.sig2);
	assertEquals(sig2Text, "foobar");
});
test("verifyRequest() [rfc9421] successful GET verification", async () => {
	const currentTimestamp = 1709626184;
	const currentTime = Temporal.Instant.from("2024-03-05T08:09:44Z");
	const validRequest = new Request("https://example.com/api/resource", {
		method: "GET",
		headers: {
			"Accept": "application/json",
			"Host": "example.com",
			"Date": "Tue, 05 Mar 2024 07:49:44 GMT"
		}
	});
	const signedRequest = await signRequest(validRequest, rsaPrivateKey2, new URL("https://example.com/key2"), {
		spec: "rfc9421",
		currentTime
	});
	const verifiedKey = await verifyRequest(signedRequest, {
		contextLoader: mockDocumentLoader,
		documentLoader: mockDocumentLoader,
		spec: "rfc9421",
		currentTime: Temporal.Instant.from(`${(/* @__PURE__ */ new Date(currentTimestamp * 1e3)).toISOString()}`)
	});
	assertEquals(verifiedKey, rsaPublicKey2, "Valid signature should verify to the correct public key");
});
test("verifyRequest() [rfc9421] manual POST verification", async () => {
	const currentTimestamp = 1709626184;
	const currentTime = Temporal.Instant.from("2024-03-05T08:09:44Z");
	const postBody = "Test content for signature verification";
	const postRequest = new Request("https://example.com/api/resource", {
		method: "POST",
		body: postBody,
		headers: {
			"Content-Type": "text/plain; charset=utf-8",
			"Accept": "application/json",
			"Host": "example.com",
			"Date": "Tue, 05 Mar 2024 07:49:44 GMT"
		}
	});
	const signedPostRequest = await signRequest(postRequest, rsaPrivateKey2, new URL("https://example.com/key2"), {
		spec: "rfc9421",
		currentTime
	});
	const signedKey = await verifyRequest(signedPostRequest, {
		spec: "rfc9421",
		documentLoader: mockDocumentLoader,
		contextLoader: mockDocumentLoader,
		currentTime
	});
	assertExists(signedKey);
	assertEquals(signedKey, rsaPublicKey2);
	assertExists(signedKey.publicKey);
	assertEquals(await exportJwk(signedKey.publicKey), await exportJwk(rsaPublicKey2.publicKey));
	const signatureInputHeader = signedPostRequest.headers.get("Signature-Input") || "";
	const signatureHeader = signedPostRequest.headers.get("Signature") || "";
	const parsedInput = parseRfc9421SignatureInput(signatureInputHeader);
	const parsedSignature = parseRfc9421Signature(signatureHeader);
	assertExists(parsedInput.sig1, "Should have a valid signature input");
	assertExists(parsedSignature.sig1, "Should have a valid signature value");
	assertEquals(parsedInput.sig1.keyId, "https://example.com/key2", "Signature should have the correct key ID");
	assertEquals(parsedInput.sig1.created, currentTimestamp, "Signature should have the correct timestamp");
	const manualRequest = new Request("https://example.com/api/resource", {
		method: "POST",
		body: postBody,
		headers: new Headers(signedPostRequest.headers)
	});
	const signatureBase = createRfc9421SignatureBase(manualRequest, parsedInput.sig1.components, parsedInput.sig1.parameters);
	const signatureVerified = await crypto.subtle.verify("RSASSA-PKCS1-v1_5", rsaPublicKey2.publicKey, parsedSignature.sig1.slice(), new TextEncoder().encode(signatureBase));
	assert(signatureVerified, "Manual verification of POST signature should succeed");
});
test("verifyRequest() [rfc9421] error cases and edge cases", async () => {
	const currentTimestamp = 1709626184;
	const currentTime = Temporal.Instant.from("2024-03-05T08:09:44Z");
	const validRequest = new Request("https://example.com/api/resource", {
		method: "GET",
		headers: {
			"Accept": "application/json",
			"Host": "example.com",
			"Date": "Tue, 05 Mar 2024 07:49:44 GMT"
		}
	});
	const signedRequest = await signRequest(validRequest, rsaPrivateKey2, new URL("https://example.com/key2"), {
		spec: "rfc9421",
		currentTime
	});
	const validSignatureInput = signedRequest.headers.get("Signature-Input") || "";
	const validSignature = signedRequest.headers.get("Signature") || "";
	const missingInputHeader = new Request("https://example.com/api/resource", {
		method: "GET",
		headers: new Headers({
			"Accept": "application/json",
			"Host": "example.com",
			"Signature": validSignature
		})
	});
	const missingInputResult = await verifyRequest(missingInputHeader, {
		contextLoader: mockDocumentLoader,
		documentLoader: mockDocumentLoader,
		spec: "rfc9421"
	});
	assertEquals(missingInputResult, null, "Should fail verification when Signature-Input header is missing");
	const missingSignatureHeader = new Request("https://example.com/api/resource", {
		method: "GET",
		headers: new Headers({
			"Accept": "application/json",
			"Host": "example.com",
			"Signature-Input": validSignatureInput
		})
	});
	const missingSignatureResult = await verifyRequest(missingSignatureHeader, {
		contextLoader: mockDocumentLoader,
		documentLoader: mockDocumentLoader,
		spec: "rfc9421"
	});
	assertEquals(missingSignatureResult, null, "Should fail verification when Signature header is missing");
	const tamperedRequest = new Request("https://example.com/api/resource", {
		method: "GET",
		headers: new Headers({
			"Accept": "application/json",
			"Host": "example.com",
			"Date": "Tue, 05 Mar 2024 07:49:44 GMT",
			"Signature-Input": validSignatureInput,
			"Signature": "sig1=:AAAAAA==:"
		})
	});
	const tamperedResult = await verifyRequest(tamperedRequest, {
		contextLoader: mockDocumentLoader,
		documentLoader: mockDocumentLoader,
		spec: "rfc9421"
	});
	assertEquals(tamperedResult, null, "Should fail verification when signature is tampered");
	const expiredRequest = new Request("https://example.com/api/resource", {
		method: "GET",
		headers: new Headers({
			"Accept": "application/json",
			"Host": "example.com",
			"Date": "Tue, 05 Mar 2024 07:49:44 GMT",
			"Signature-Input": validSignatureInput,
			"Signature": validSignature
		})
	});
	const expiredResult = await verifyRequest(expiredRequest, {
		contextLoader: mockDocumentLoader,
		documentLoader: mockDocumentLoader,
		spec: "rfc9421",
		currentTime: Temporal.Instant.from(`${(/* @__PURE__ */ new Date((currentTimestamp + 2592e3) * 1e3)).toISOString()}`),
		timeWindow: { hours: 1 }
	});
	assertEquals(expiredResult, null, "Should fail verification when signature timestamp is too old");
	const futureRequest = new Request("https://example.com/api/resource", {
		method: "GET",
		headers: new Headers({
			"Accept": "application/json",
			"Host": "example.com",
			"Date": "Tue, 05 Mar 2024 07:49:44 GMT",
			"Signature-Input": validSignatureInput,
			"Signature": validSignature
		})
	});
	const futureResult = await verifyRequest(futureRequest, {
		contextLoader: mockDocumentLoader,
		documentLoader: mockDocumentLoader,
		spec: "rfc9421",
		currentTime: Temporal.Instant.from(`${(/* @__PURE__ */ new Date((currentTimestamp - 2592e3) * 1e3)).toISOString()}`),
		timeWindow: { hours: 1 }
	});
	assertEquals(futureResult, null, "Should fail verification when signature timestamp is in the future");
	const timeCheckRequest = new Request("https://example.com/api/resource", {
		method: "GET",
		headers: new Headers({
			"Accept": "application/json",
			"Host": "example.com",
			"Date": "Tue, 05 Mar 2024 07:49:44 GMT",
			"Signature-Input": validSignatureInput,
			"Signature": validSignature
		})
	});
	const timeDisabledResult = await verifyRequest(timeCheckRequest, {
		contextLoader: mockDocumentLoader,
		documentLoader: mockDocumentLoader,
		spec: "rfc9421",
		currentTime: Temporal.Instant.from(`${(/* @__PURE__ */ new Date((currentTimestamp + 31536e3) * 1e3)).toISOString()}`),
		timeWindow: false
	});
	assertEquals(timeDisabledResult, rsaPublicKey2, "Should verify signature when time checking is disabled");
	const postRequest = new Request("https://example.com/api/resource", {
		method: "POST",
		body: "Test content for signature verification",
		headers: {
			"Content-Type": "text/plain; charset=utf-8",
			"Accept": "application/json",
			"Host": "example.com",
			"Date": "Tue, 05 Mar 2024 07:49:44 GMT"
		}
	});
	const freshSignedPostRequest = await signRequest(postRequest, rsaPrivateKey2, new URL("https://example.com/key2"), {
		spec: "rfc9421",
		currentTime
	});
	const postSignatureInput = freshSignedPostRequest.headers.get("Signature-Input") || "";
	const postSignature = freshSignedPostRequest.headers.get("Signature") || "";
	const postContentDigest = freshSignedPostRequest.headers.get("Content-Digest") || "";
	const tamperDigestRequest = new Request("https://example.com/api/resource", {
		method: "POST",
		body: "This content won't match the digest",
		headers: new Headers({
			"Accept": "application/json",
			"Host": "example.com",
			"Date": "Tue, 05 Mar 2024 07:49:44 GMT",
			"Signature-Input": postSignatureInput,
			"Signature": postSignature,
			"Content-Digest": postContentDigest
		})
	});
	const tamperDigestResult = await verifyRequest(tamperDigestRequest, {
		contextLoader: mockDocumentLoader,
		documentLoader: mockDocumentLoader,
		spec: "rfc9421",
		currentTime: Temporal.Instant.from(`${(/* @__PURE__ */ new Date(currentTimestamp * 1e3)).toISOString()}`)
	});
	assertEquals(tamperDigestResult, null, "Should fail verification with invalid Content-Digest");
	const testRequest = new Request("https://example.com/", { headers: new Headers({
		"Date": "Tue, 05 Mar 2024 07:49:44 GMT",
		"Host": "example.com",
		"Signature-Input": `sig1=("@method" "@target-uri" "host" "date");keyid="https://example.com/key";alg="rsa-v1_5-sha256";created=1709626184`,
		"Signature": `sig1=:YXNkZmprc2RmaGprc2RoZmprc2hkZmtqaHNkZg==:`
	}) });
	const signatureInput = testRequest.headers.get("Signature-Input") || "";
	const parsedInput = parseRfc9421SignatureInput(signatureInput);
	assertExists(parsedInput.sig1);
	assertEquals(parsedInput.sig1.keyId, "https://example.com/key");
	assertEquals(parsedInput.sig1.alg, "rsa-v1_5-sha256");
	assertEquals(parsedInput.sig1.created, 1709626184);
	assertEquals(parsedInput.sig1.components, [
		"@method",
		"@target-uri",
		"host",
		"date"
	]);
	const signature = testRequest.headers.get("Signature") || "";
	const parsedSig = parseRfc9421Signature(signature);
	assertExists(parsedSig.sig1);
	assert(new TextDecoder().decode(parsedSig.sig1).length > 0, "Signature base64 should decode to non-empty string");
	const complexSignatureInput = "sig1=(\"@method\" \"@target-uri\" \"host\" \"content-type\" \"value with \\\"quotes\\\" and spaces\");keyid=\"https://example.com/key with spaces\";alg=\"rsa-v1_5-sha256\";created=1709626184";
	const complexParsedInput = parseRfc9421SignatureInput(complexSignatureInput);
	assertExists(complexParsedInput.sig1);
	assertEquals(complexParsedInput.sig1.keyId, "https://example.com/key with spaces");
	assertEquals(complexParsedInput.sig1.alg, "rsa-v1_5-sha256");
	assertEquals(complexParsedInput.sig1.created, 1709626184);
	assert(complexParsedInput.sig1.components.includes("content-type"));
	assert(complexParsedInput.sig1.components.includes("value with \"quotes\" and spaces"));
	const multiSigRequest = new Request("https://example.com/", { headers: new Headers({
		"Signature-Input": `sig1=("@method");keyid="key1";alg="rsa-v1_5-sha256";created=1709626184,sig2=("@target-uri");keyid="key2";alg="rsa-pss-sha512";created=1709626185`,
		"Signature": `sig1=:AQIDBA==:,sig2=:Zm9vYmFy:`
	}) });
	const multiParsedInput = parseRfc9421SignatureInput(multiSigRequest.headers.get("Signature-Input") || "");
	assertEquals(Object.keys(multiParsedInput).length, 2, "Should parse multiple signatures");
	assertEquals(multiParsedInput.sig1.keyId, "key1");
	assertEquals(multiParsedInput.sig2.keyId, "key2");
	assertEquals(multiParsedInput.sig1.alg, "rsa-v1_5-sha256");
	assertEquals(multiParsedInput.sig2.alg, "rsa-pss-sha512");
	const multiParsedSig = parseRfc9421Signature(multiSigRequest.headers.get("Signature") || "");
	assertEquals(Object.keys(multiParsedSig).length, 2, "Should parse multiple signature values");
	const invalidInputFormat = "this is not a valid signature-input format";
	const parsedInvalidInput = parseRfc9421SignatureInput(invalidInputFormat);
	assertEquals(Object.keys(parsedInvalidInput).length, 0, "Should handle invalid Signature-Input format");
	const invalidSigFormat = "this is not a valid signature format";
	const parsedInvalidSig = parseRfc9421Signature(invalidSigFormat);
	assertEquals(Object.keys(parsedInvalidSig).length, 0, "Should handle invalid Signature format");
	const invalidBase64Sig = "sig1=:!@#$%%^&*():";
	const parsedInvalidBase64 = parseRfc9421Signature(invalidBase64Sig);
	assertEquals(Object.keys(parsedInvalidBase64).length, 0, "Should handle invalid base64 in signature");
	const mixedRequest = new Request("https://example.com/api/resource", {
		method: "GET",
		headers: new Headers({
			"Accept": "application/json",
			"Host": "example.com",
			"Date": "Tue, 05 Mar 2024 07:49:44 GMT",
			"Signature-Input": `${validSignatureInput},sig2=("@method" "@target-uri" "host" "date");keyid="https://example.com/invalid-key";alg="rsa-v1_5-sha256";created=${currentTimestamp}`,
			"Signature": `${validSignature},sig2=:AAAAAA==:`
		})
	});
	const mixedResult = await verifyRequest(mixedRequest, {
		contextLoader: mockDocumentLoader,
		documentLoader: mockDocumentLoader,
		spec: "rfc9421",
		currentTime: Temporal.Instant.from(`${(/* @__PURE__ */ new Date(currentTimestamp * 1e3)).toISOString()}`)
	});
	assertEquals(mixedResult, rsaPublicKey2, "Should verify when at least one signature is valid");
});
test("verifyRequest() [rfc9421] test vector from Mastodon", async () => {
	const signedRequest = new Request("https://www.example.com/activitypub/success", {
		method: "GET",
		headers: {
			Host: "www.example.com",
			"Signature-Input": "sig1=(\"@method\" \"@target-uri\");created=1703066400;keyid=\"https://remote.domain/users/bob#main-key\"",
			Signature: "sig1=:WfM6q/qBqhUyqPUDt9metjadJGtLLpmMTBzk/t+R3byKe4/TGAXC6vBB/M6NsD5qv8GCmQGtisCMQxJQO0IGODGzi+Jv+eqDJ50agMVXNV6nUOzY44c4/XTPoI98qyx1oEMa4Hefy3vSYKq96iDVAc+RDLCMTeGP3wn9wizjD1SNmU0RZI1bTB+eCkywMP9mM5zXzUOYF+Qkuf+WdEpPR1XUGPlnqfdvPalcKVfaI/VThBjI91D/lmUGoa69x4EBEHM+aJmW6086e7/dVh+FndKkdGfXslZXFZKi2flTGQZgEWLn948SqAaJQROkJg8B14Sb1NONS1qZBhK3Mum8Pg==:"
		}
	});
	const result = await verifyRequest(signedRequest, {
		contextLoader: mockDocumentLoader,
		documentLoader: mockDocumentLoader,
		currentTime: Temporal.Instant.from("2023-12-20T10:00:00.0000Z"),
		spec: "rfc9421"
	});
	assertExists(result);
	assertExists(result.publicKey);
	assertEquals(result, rsaPublicKey5);
	assertEquals(await exportSpki(result.publicKey), await exportSpki(rsaPublicKey5.publicKey));
	const result2 = await verifyRequest(signedRequest, {
		contextLoader: mockDocumentLoader,
		documentLoader: mockDocumentLoader,
		currentTime: Temporal.Instant.from("2023-12-20T10:00:00.0000Z")
	});
	assertExists(result2);
	assertExists(result2.publicKey);
	assertEquals(result2, rsaPublicKey5);
	assertEquals(await exportSpki(result2.publicKey), await exportSpki(rsaPublicKey5.publicKey));
});
test("doubleKnock() function with successful first attempt", async () => {
	esm_default.spyGlobal();
	let requestCount = 0;
	let firstRequestSpec = null;
	esm_default.post("https://example.com/inbox-accepts-rfc9421", (cl) => {
		requestCount++;
		const req = cl.request;
		const signatureInputHeader = req.headers.get("Signature-Input");
		const signatureHeader = req.headers.get("Signature");
		if (signatureInputHeader && signatureHeader) {
			firstRequestSpec = "rfc9421";
			return new Response("", { status: 202 });
		} else return new Response("Unauthorized", { status: 401 });
	});
	const request = new Request("https://example.com/inbox-accepts-rfc9421", {
		method: "POST",
		body: "Hello, world!",
		headers: { "Content-Type": "text/plain" }
	});
	const specDeterminer = {
		usedSpec: null,
		determineSpec(_origin) {
			return "rfc9421";
		},
		rememberSpec(_origin, spec) {
			this.usedSpec = spec;
		}
	};
	let loggedRequest;
	const logFunction = (req) => {
		loggedRequest = req;
	};
	const response = await doubleKnock(request, {
		keyId: rsaPublicKey2.id,
		privateKey: rsaPrivateKey2
	}, {
		specDeterminer,
		log: logFunction
	});
	assertEquals(response.status, 202, "Response status should be 202 Accepted");
	assertEquals(requestCount, 1, "Only one request should have been made");
	assertEquals(firstRequestSpec, "rfc9421", "First attempt should use RFC 9421");
	assertEquals(specDeterminer.usedSpec, "rfc9421", "Spec should be remembered");
	assertExists(loggedRequest, "Request should be logged");
	assert(loggedRequest?.headers.has("Signature-Input"), "Logged request should have RFC 9421 Signature-Input header");
	assert(loggedRequest?.headers.has("Signature"), "Logged request should have RFC 9421 Signature header");
	esm_default.hardReset();
});
test("doubleKnock() function with fallback to draft-cavage", async () => {
	esm_default.spyGlobal();
	let requestCount = 0;
	let firstSpec = null;
	let secondSpec = null;
	esm_default.post("https://example.com/inbox-accepts-draft-cavage", (cl) => {
		const req = cl.request;
		requestCount++;
		if (req.headers.has("Signature-Input")) {
			firstSpec = "rfc9421";
			return new Response("Not Authorized", { status: 401 });
		} else if (req.headers.has("Signature")) {
			secondSpec = "draft-cavage-http-signatures-12";
			return new Response("", { status: 202 });
		} else return new Response("Bad Request", { status: 400 });
	});
	const request = new Request("https://example.com/inbox-accepts-draft-cavage", {
		method: "POST",
		body: "Test message for double-knocking",
		headers: { "Content-Type": "text/plain" }
	});
	const specDeterminer = {
		rememberedOrigin: null,
		rememberedSpec: null,
		determineSpec(_origin) {
			return "rfc9421";
		},
		rememberSpec(origin, spec) {
			this.rememberedOrigin = origin;
			this.rememberedSpec = spec;
		}
	};
	const response = await doubleKnock(request, {
		keyId: rsaPublicKey2.id,
		privateKey: rsaPrivateKey2
	}, { specDeterminer });
	assertEquals(response.status, 202, "Response status should be 202 Accepted");
	assertEquals(requestCount, 2, "Two requests should have been made");
	assertEquals(firstSpec, "rfc9421", "First attempt should use RFC 9421");
	assertEquals(secondSpec, "draft-cavage-http-signatures-12", "Second attempt should use draft-cavage");
	assertEquals(specDeterminer.rememberedOrigin, "https://example.com", "Origin should be remembered");
	assertEquals(specDeterminer.rememberedSpec, "draft-cavage-http-signatures-12", "Successful spec should be remembered");
	esm_default.hardReset();
});
test("doubleKnock() function with redirect handling", async () => {
	esm_default.spyGlobal();
	const requestedUrls = [];
	const responseCodes = [];
	esm_default.post("https://example.com/redirect-endpoint", (cl) => {
		requestedUrls.push(cl.url);
		responseCodes.push(302);
		return Response.redirect("https://example.com/final-endpoint", 302);
	});
	esm_default.post("https://example.com/final-endpoint", (cl) => {
		requestedUrls.push(cl.url);
		responseCodes.push(202);
		return new Response("", { status: 202 });
	});
	const request = new Request("https://example.com/redirect-endpoint", {
		method: "POST",
		body: "Test message that will be redirected",
		headers: { "Content-Type": "text/plain" }
	});
	const response = await doubleKnock(request, {
		keyId: rsaPublicKey2.id,
		privateKey: rsaPrivateKey2
	});
	assertEquals(response.status, 202, "Final response status should be 202 Accepted");
	assertEquals(requestedUrls.length, 2, "Two URLs should have been requested");
	assertEquals(requestedUrls[0], "https://example.com/redirect-endpoint", "First request should be to redirect-endpoint");
	assertEquals(requestedUrls[1], "https://example.com/final-endpoint", "Second request should be to final-endpoint");
	assertEquals(responseCodes, [302, 202], "Response status codes should match expected sequence");
	esm_default.hardReset();
});
test("doubleKnock() function with both specs rejected", async () => {
	esm_default.spyGlobal();
	let requestCount = 0;
	const attempts = [];
	esm_default.post("https://example.com/inbox-rejects-all", (cl) => {
		const req = cl.request;
		requestCount++;
		if (req.headers.has("Signature-Input")) attempts.push("rfc9421");
		else if (req.headers.has("Signature")) attempts.push("draft-cavage");
		else attempts.push("unknown");
		return new Response("Unauthorized", { status: 401 });
	});
	const request = new Request("https://example.com/inbox-rejects-all", {
		method: "POST",
		body: "Test message that will be rejected regardless of signature format",
		headers: { "Content-Type": "text/plain" }
	});
	const response = await doubleKnock(request, {
		keyId: rsaPublicKey2.id,
		privateKey: rsaPrivateKey2
	});
	assertEquals(response.status, 401, "Final response status should be 401 Unauthorized");
	assertEquals(requestCount, 2, "Two requests should have been made");
	assertEquals(attempts.length, 2, "Two signature attempts should have been made");
	assertEquals(attempts[0], "rfc9421", "First attempt should use RFC 9421");
	assertEquals(attempts[1], "draft-cavage", "Second attempt should use draft-cavage");
	esm_default.hardReset();
});
test("doubleKnock() function with specDeterminer choosing draft-cavage first", async () => {
	esm_default.spyGlobal();
	let requestCount = 0;
	let firstSpec = null;
	esm_default.post("https://example.com/inbox-accepts-any", (cl) => {
		const req = cl.request;
		requestCount++;
		if (req.headers.has("Signature-Input")) firstSpec = "rfc9421";
		else if (req.headers.has("Signature")) firstSpec = "draft-cavage";
		return new Response("", { status: 202 });
	});
	const specDeterminer = {
		determineSpec(_origin) {
			return "draft-cavage-http-signatures-12";
		},
		rememberSpec(_origin, _spec) {}
	};
	const request = new Request("https://example.com/inbox-accepts-any", {
		method: "POST",
		body: "Test message with draft-cavage preference",
		headers: { "Content-Type": "text/plain" }
	});
	const response = await doubleKnock(request, {
		keyId: rsaPublicKey2.id,
		privateKey: rsaPrivateKey2
	}, { specDeterminer });
	assertEquals(response.status, 202, "Response status should be 202 Accepted");
	assertEquals(requestCount, 1, "Only one request should have been made");
	assertEquals(firstSpec, "draft-cavage", "First attempt should use draft-cavage");
	esm_default.hardReset();
});
test("doubleKnock() complex redirect chain test", async () => {
	esm_default.spyGlobal();
	const requestedUrls = [];
	esm_default.post("https://example.com/redirect1", (cl) => {
		requestedUrls.push(cl.url);
		return Response.redirect("https://example.com/redirect2", 302);
	});
	esm_default.post("https://example.com/redirect2", (cl) => {
		requestedUrls.push(cl.url);
		return Response.redirect("https://example.com/redirect3", 307);
	});
	esm_default.post("https://example.com/redirect3", (cl) => {
		requestedUrls.push(cl.url);
		return Response.redirect("https://example.com/final", 301);
	});
	esm_default.post("https://example.com/final", (cl) => {
		requestedUrls.push(cl.url);
		return new Response("Success", { status: 200 });
	});
	const request = new Request("https://example.com/redirect1", {
		method: "POST",
		body: "Test message for redirect chain",
		headers: { "Content-Type": "text/plain" }
	});
	const logs = [];
	const logFunction = (req) => {
		logs.push(req);
	};
	const response = await doubleKnock(request, {
		keyId: rsaPublicKey2.id,
		privateKey: rsaPrivateKey2
	}, { log: logFunction });
	assertEquals(response.status, 200, "Final response status should be 200 OK");
	assertEquals(await response.text(), "Success", "Response body should be 'Success'");
	assertEquals(requestedUrls.length, 4, "Four URLs should have been requested");
	assertEquals(requestedUrls[0], "https://example.com/redirect1", "First request should be to redirect1");
	assertEquals(requestedUrls[1], "https://example.com/redirect2", "Second request should be to redirect2");
	assertEquals(requestedUrls[2], "https://example.com/redirect3", "Third request should be to redirect3");
	assertEquals(requestedUrls[3], "https://example.com/final", "Fourth request should be to final");
	assertEquals(logs.length, 4, "Four requests should have been logged");
	for (const loggedReq of logs) assert(loggedReq.headers.has("Signature-Input") || loggedReq.headers.has("Signature"), "Each request should be signed with either RFC 9421 or draft-cavage");
	esm_default.hardReset();
});
test("doubleKnock() async specDeterminer test", async () => {
	esm_default.spyGlobal();
	let requestCount = 0;
	let specUsed = null;
	esm_default.post("https://example.com/inbox-async-determiner", (cl) => {
		const req = cl.request;
		requestCount++;
		if (req.headers.has("Signature-Input")) specUsed = "rfc9421";
		else if (req.headers.has("Signature")) specUsed = "draft-cavage-http-signatures-12";
		return new Response("", { status: 202 });
	});
	const specDeterminer = {
		async determineSpec(_origin) {
			await new Promise((resolve) => setTimeout(resolve, 10));
			return "draft-cavage-http-signatures-12";
		},
		async rememberSpec(_origin, _spec) {
			await new Promise((resolve) => setTimeout(resolve, 10));
		}
	};
	const request = new Request("https://example.com/inbox-async-determiner", {
		method: "POST",
		body: "Test message with async spec determiner",
		headers: { "Content-Type": "text/plain" }
	});
	const response = await doubleKnock(request, {
		keyId: rsaPublicKey2.id,
		privateKey: rsaPrivateKey2
	}, { specDeterminer });
	assertEquals(response.status, 202, "Response status should be 202 Accepted");
	assertEquals(requestCount, 1, "Only one request should have been made");
	assertEquals(specUsed, "draft-cavage-http-signatures-12", "Should use spec from async determiner");
	esm_default.hardReset();
});
test("timingSafeEqual()", async (t) => {
	await t.step("should return true for equal empty arrays", () => {
		const a = new Uint8Array([]);
		const b = new Uint8Array([]);
		assert(timingSafeEqual(a, b));
	});
	await t.step("should return true for equal non-empty arrays", async (t2) => {
		const testCases = [
			{
				a: [
					1,
					2,
					3
				],
				b: [
					1,
					2,
					3
				],
				name: "simple sequence"
			},
			{
				a: [
					0,
					0,
					0
				],
				b: [
					0,
					0,
					0
				],
				name: "sequence of zeros"
			},
			{
				a: [
					255,
					128,
					0,
					42
				],
				b: [
					255,
					128,
					0,
					42
				],
				name: "varied bytes"
			},
			{
				a: Array.from({ length: 100 }, (_, i) => i),
				b: Array.from({ length: 100 }, (_, i) => i),
				name: "longer sequence (0-99)"
			}
		];
		for (const tc of testCases) await t2.step(tc.name, () => {
			assert(timingSafeEqual(new Uint8Array(tc.a), new Uint8Array(tc.b)));
		});
	});
	await t.step("should return true for reference equality", () => {
		const arr = new Uint8Array([
			10,
			20,
			30,
			99,
			100,
			0
		]);
		assert(timingSafeEqual(arr, arr), "Array should be equal to itself by reference");
	});
	await t.step("should return false for arrays with same length but different content", async (t2) => {
		const testCases = [
			{
				a: [
					1,
					2,
					3
				],
				b: [
					0,
					2,
					3
				],
				name: "difference at start"
			},
			{
				a: [
					1,
					2,
					3
				],
				b: [
					1,
					0,
					3
				],
				name: "difference in middle"
			},
			{
				a: [
					1,
					2,
					3
				],
				b: [
					1,
					2,
					0
				],
				name: "difference at end"
			},
			{
				a: [0],
				b: [1],
				name: "single byte difference"
			},
			{
				a: [
					255,
					0,
					255
				],
				b: [
					255,
					1,
					255
				],
				name: "middle byte differs with edge values"
			}
		];
		for (const tc of testCases) await t2.step(tc.name, () => {
			assertFalse(timingSafeEqual(new Uint8Array(tc.a), new Uint8Array(tc.b)));
		});
	});
	await t.step("should return false for arrays with different lengths", async (t2) => {
		const testCases = [
			{
				a: [
					1,
					2,
					3
				],
				b: [1, 2],
				name: "b shorter"
			},
			{
				a: [1, 2],
				b: [
					1,
					2,
					3
				],
				name: "a shorter"
			},
			{
				a: [],
				b: [
					1,
					2,
					3
				],
				name: "a empty, b non-empty"
			},
			{
				a: [
					1,
					2,
					3
				],
				b: [],
				name: "a non-empty, b empty"
			}
		];
		for (const tc of testCases) await t2.step(tc.name, () => {
			assertFalse(timingSafeEqual(new Uint8Array(tc.a), new Uint8Array(tc.b)));
		});
	});
	await t.step("should return false where content matches up to shorter length", async (t2) => {
		const testCases = [
			{
				a: [1, 2],
				b: [
					1,
					2,
					0
				],
				name: "a is prefix, b has trailing zero"
			},
			{
				a: [
					1,
					2,
					0
				],
				b: [1, 2],
				name: "b is prefix, a has trailing zero"
			},
			{
				a: [0],
				b: [0, 0],
				name: "single zero vs two zeros"
			},
			{
				a: [0, 0],
				b: [0],
				name: "two zeros vs single zero"
			}
		];
		for (const tc of testCases) await t2.step(tc.name, () => {
			assertFalse(timingSafeEqual(new Uint8Array(tc.a), new Uint8Array(tc.b)));
		});
	});
	await t.step("should correctly handle comparisons involving padding bytes", async (t2) => {
		await t2.step("a=[1], b=[1,0] (b longer with trailing zero)", () => {
			const a1 = new Uint8Array([1]);
			const b1 = new Uint8Array([1, 0]);
			assertFalse(timingSafeEqual(a1, b1));
		});
		await t2.step("a=[1,0], b=[1] (a longer with trailing zero)", () => {
			const a2 = new Uint8Array([1, 0]);
			const b2 = new Uint8Array([1]);
			assertFalse(timingSafeEqual(a2, b2));
		});
	});
});
test("signRequest() [rfc9421] error handling for invalid signature base creation", async () => {
	const request = new Request("https://example.com/test", {
		method: "POST",
		body: "test body"
	});
	await assertThrows(() => {
		createRfc9421SignatureBase(request, ["@unsupported"], "alg=\"rsa-pss-sha256\";keyid=\"https://example.com/key2\";created=1234567890");
	}, Error, "Unsupported derived component: @unsupported");
	const signedRequest = await signRequest(request, rsaPrivateKey2, new URL("https://example.com/key2"), { spec: "rfc9421" });
	assertExists(signedRequest.headers.get("Signature-Input"));
	assertExists(signedRequest.headers.get("Signature"));
});
test("verifyRequest() [rfc9421] error handling for invalid signature base creation", async () => {
	const request = new Request("https://example.com/test", {
		method: "GET",
		headers: {
			"Accept": "application/json",
			"Signature-Input": "sig1=(\"@unsupported\");alg=\"rsa-pss-sha256\";keyid=\"https://example.com/key2\";created=1234567890",
			"Signature": "sig1=:invalid_signature_data:"
		}
	});
	const result = await verifyRequest(request, {
		spec: "rfc9421",
		documentLoader: mockDocumentLoader,
		contextLoader: mockDocumentLoader
	});
	assertEquals(result, null, "Verification should fail gracefully for malformed signature inputs");
});
test("doubleKnock() regression test for TypeError: unusable bug #294", async () => {
	esm_default.spyGlobal();
	let requestCount = 0;
	esm_default.post("https://example.com/inbox-retry-redirect", (_cl) => {
		requestCount++;
		if (requestCount === 1) return new Response("Unauthorized", { status: 401 });
		else if (requestCount === 2) return Response.redirect("https://example.com/final-destination", 302);
		return new Response("Should not reach here", { status: 500 });
	});
	esm_default.post("https://example.com/final-destination", () => {
		return new Response("Success", { status: 200 });
	});
	const request = new Request("https://example.com/inbox-retry-redirect", {
		method: "POST",
		body: "Test activity content",
		headers: { "Content-Type": "application/activity+json" }
	});
	const response = await doubleKnock(request, {
		keyId: rsaPublicKey2.id,
		privateKey: rsaPrivateKey2
	});
	assertEquals(response.status, 200);
	assertEquals(requestCount, 2, "Should make 2 requests before redirect");
	esm_default.hardReset();
});
test("doubleKnock() regression test for redirect handling bug", async () => {
	esm_default.spyGlobal();
	esm_default.post("https://example.com/inbox-retry-redirect", (_cl) => {
		return new Response(null, {
			status: 302,
			headers: { location: "/final-destination" }
		});
	});
	esm_default.post("https://example.com/final-destination", () => {
		return new Response("Success", { status: 200 });
	});
	const request = new Request("https://example.com/inbox-retry-redirect", {
		method: "POST",
		body: "Test activity content",
		headers: { "Content-Type": "application/activity+json" }
	});
	const response = await doubleKnock(request, {
		keyId: rsaPublicKey2.id,
		privateKey: rsaPrivateKey2
	});
	assertEquals(response.status, 200);
	esm_default.hardReset();
});
test("signRequest() and verifyRequest() cancellation", {
	sanitizeResources: false,
	sanitizeOps: false
}, async (t) => {
	esm_default.spyGlobal();
	await t.step("doubleKnock cancellation", async () => {
		esm_default.post("https://example.com/slow-endpoint", () => new Promise((resolve) => {
			setTimeout(() => {
				resolve(new Response("", { status: 202 }));
			}, 1e3);
		}));
		const request = new Request("https://example.com/slow-endpoint", {
			method: "POST",
			body: "Test message",
			headers: { "Content-Type": "text/plain" }
		});
		const controller = new AbortController();
		const promise = doubleKnock(request, {
			keyId: rsaPublicKey2.id,
			privateKey: rsaPrivateKey2
		}, { signal: controller.signal });
		controller.abort();
		await assertRejects(() => promise, Error);
	});
	await t.step("doubleKnock immediate cancellation", async () => {
		const request = new Request("https://example.com/", {
			method: "POST",
			body: "Hello, world!",
			headers: {
				"Content-Type": "text/plain; charset=utf-8",
				Accept: "text/plain"
			}
		});
		const controller = new AbortController();
		controller.abort();
		await assertRejects(() => doubleKnock(request, {
			keyId: rsaPublicKey2.id,
			privateKey: rsaPrivateKey2
		}, { signal: controller.signal }), Error);
	});
	esm_default.hardReset();
});

//#endregion