// Helper used by `auth-flow.spec.ts` to forge a Connect-Web-shaped // `ExecuteCommandResponse` signed with the fixture gateway response // key. Lives next to the keypair fixture so the e2e file stays // focused on the UI flow. Connect-Web's default transport uses // JSON over HTTP/1.1, so the helper emits JSON bytes; the canonical // signing input is still the binary form defined in // `ui/core/canon/response.go`. import { create, toJson, toJsonString } from "@bufbuild/protobuf"; import { webcrypto } from "node:crypto"; import { ExecuteCommandResponseSchema } from "../../../src/proto/galaxy/gateway/v1/edge_gateway_pb"; import { FIXTURE_PRIVATE_KEY_PKCS8_BASE64, decodeBase64, } from "./gateway-key"; import { buildResponseSigningInput } from "./canon"; const PROTOCOL_VERSION = "v1"; export interface ForgedResponseInput { requestId: string; timestampMs: bigint; resultCode: string; payloadBytes: Uint8Array; } let cachedPrivateKey: CryptoKey | null = null; async function privateKey(): Promise { if (cachedPrivateKey !== null) { return cachedPrivateKey; } const pkcs8 = decodeBase64(FIXTURE_PRIVATE_KEY_PKCS8_BASE64); cachedPrivateKey = await webcrypto.subtle.importKey( "pkcs8", pkcs8, { name: "Ed25519" }, false, ["sign"], ); return cachedPrivateKey; } async function sha256(payload: Uint8Array): Promise { const digest = await webcrypto.subtle.digest("SHA-256", payload); return new Uint8Array(digest); } /** * forgeExecuteCommandResponseJson produces the JSON body of a * gateway response that `GalaxyClient.executeCommand` will accept * under the fixture public key, encoded the way Connect-Web's * default JSON transport expects to receive it. */ export async function forgeExecuteCommandResponseJson( input: ForgedResponseInput, ): Promise { const payloadHash = await sha256(input.payloadBytes); const canonical = buildResponseSigningInput({ protocolVersion: PROTOCOL_VERSION, requestId: input.requestId, timestampMs: input.timestampMs, resultCode: input.resultCode, payloadHash, }); const sig = await webcrypto.subtle.sign( { name: "Ed25519" }, await privateKey(), canonical, ); const message = create(ExecuteCommandResponseSchema, { protocolVersion: PROTOCOL_VERSION, requestId: input.requestId, timestampMs: input.timestampMs, resultCode: input.resultCode, payloadBytes: input.payloadBytes, payloadHash, signature: new Uint8Array(sig), }); return toJsonString(ExecuteCommandResponseSchema, message); } export { toJson };