diff --git a/examples/verification-workers/src/debug-html.ts b/examples/verification-workers/src/debug-html.ts new file mode 100644 index 0000000..8cfa281 --- /dev/null +++ b/examples/verification-workers/src/debug-html.ts @@ -0,0 +1,729 @@ +// Copyright 2025 Cloudflare, Inc. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +import { theme } from "./index-html"; + +const directoryPath = "/.well-known/http-message-signatures-directory"; + +function escapeAttribute(value: string): string { + return value.replaceAll("&", "&").replaceAll('"', """); +} + +function turnstileScript(siteKey: string): string { + return siteKey.length > 0 + ? '' + : ""; +} + +function turnstileWidget(siteKey: string): string { + return siteKey.length > 0 + ? `
` + : 'Turnstile is not configured for this deployment.
'; +} + +const debugStyle = ``; + +export const generateDebugHTML = (turnstileSiteKey: string) => ` + + + + ++ This page collects debugging tools for Web Bot Auth implementations. Start by validating the key directory. +
+ +
+ Paste the full HTTPS URL for a /.well-known/http-message-signatures-directory endpoint to check whether it returns a usable directory.
+
+ Paste a JWK to compute its RFC 7638 SHA-256 thumbprint for use as keyid.
+
+ Paste the signed request target, verification JWK, and HTTP Message Signature headers here. +
+ +- This website expose an endpoint dropping incoming request headers on /debug + Use the debug page to validate key directories and signature headers.
/.well-known/http-message-signatures-directory"
+ );
+ expect(body).toContain("Fetched directory");
+ expect(body).toContain("fillJWK(key)");
+ expect(body).not.toContain('data-sitekey=""');
+ });
+
+ it("renders section fragment tooling", async () => {
+ const request = new Request(`${sampleURL}/debug`);
+ const response = await SELF.fetch(request);
+ const body = await response.text();
+
+ expect(body).toContain("section-link");
+ expect(body).toContain('data-section="validate-directory"');
+ expect(body).toContain('data-section="get-jwk-keyid"');
+ expect(body).toContain('data-section="verify-request-headers"');
+ expect(body).toContain("fragmentParams");
+ expect(body).toContain('prefill("key-id-jwk", "key-id-jwk")');
+ expect(body).toContain('prefill("signature-jwk", "signature-jwk")');
+ expect(body).toContain('prefill("key-id-jwk", "jwk")');
+ expect(body).toContain('prefill("signature-jwk", "jwk")');
+ expect(body).toContain('["section", section]');
+ expect(body).toContain('["key-id-jwk", formValue("key-id-jwk")]');
+ expect(body).toContain('["signature-jwk", formValue("signature-jwk")]');
+ expect(body).toContain("currentSectionURL");
+ expect(body).toContain("updateSectionLink");
+ expect(body).toContain('link.addEventListener("pointerenter"');
+ expect(body).toContain('link.addEventListener("focus"');
+ expect(body).toContain("url.hash = params.toString()");
+ expect(body).toContain("history.pushState");
+ });
+
+ it("renders JWK keyid tools", async () => {
+ const request = new Request(`${sampleURL}/debug`);
+ const response = await SELF.fetch(request);
+ const body = await response.text();
+
+ expect(body).toContain("Get JWK keyid");
+ expect(body).toContain("key-id-calculator");
+ expect(body).toContain("computeJWKKeyID");
+ expect(body).toContain("signatureJWK.value");
+ });
+
+ it("renders signature header placeholders", async () => {
+ const request = new Request(`${sampleURL}/debug`);
+ const response = await SELF.fetch(request);
+ const body = await response.text();
+
+ expect(body).toContain("Verify request headers");
+ expect(body).toContain("signature-jwk");
+ expect(body).not.toContain("signature-directory-url");
+ expect(body).toContain("Method");
+ expect(body).toContain("URL");
+ expect(body).toContain("Signature");
+ expect(body).toContain("Signature-Agent");
+ expect(body).toContain("Signature-Input");
+ expect(body).toContain("Accepted forms:");
+ expect(body).toContain(
+ 'Signature-Agent must be "