( options: SignOptions<T>, )
| 818 | * @returns A new message with signature headers appended. |
| 819 | */ |
| 820 | export async function signMessage<T extends Request | Response>( |
| 821 | options: SignOptions<T>, |
| 822 | ): Promise<T> { |
| 823 | const { message, params, key, request } = options; |
| 824 | const label = params.label ?? "sig"; |
| 825 | |
| 826 | validateSignParams(params); |
| 827 | assertUniqueLabel(message.headers, label); |
| 828 | |
| 829 | const algorithm = params.algorithm ?? inferAlgorithm(key); |
| 830 | |
| 831 | const baseOpts: CreateSignatureBaseOptions = { message, params }; |
| 832 | if (request) baseOpts.request = request; |
| 833 | const base = createSignatureBase(baseOpts); |
| 834 | const baseBytes = UTF8_ENCODER.encode(base); |
| 835 | |
| 836 | const signParams = getSignParams(algorithm); |
| 837 | const signatureBytes: Uint8Array_ = new Uint8Array( |
| 838 | await crypto.subtle.sign(signParams, key, baseBytes), |
| 839 | ); |
| 840 | |
| 841 | // Build Signature-Input value |
| 842 | const components = params.components.map(normalizeIdentifier); |
| 843 | const sigParamsValue = buildSignatureParamsValue(components, params); |
| 844 | |
| 845 | // Build headers |
| 846 | const sigInputHeader = `${label}=${sigParamsValue}`; |
| 847 | const sigHeader = serializeDictionary( |
| 848 | new Map([[label, sfItem(binary(signatureBytes))]]), |
| 849 | ); |
| 850 | |
| 851 | // clone() preserves the concrete type at runtime |
| 852 | const clone = message.clone() as T; |
| 853 | appendHeader(clone.headers, "Signature-Input", sigInputHeader); |
| 854 | appendHeader(clone.headers, "Signature", sigHeader); |
| 855 | return clone; |
| 856 | } |
| 857 | |
| 858 | function appendHeader(headers: Headers, name: string, value: string): void { |
| 859 | const existing = headers.get(name); |
no test coverage detected