spikes/apns-worker/test/apns.test.ts
25 lines · 1351 bytes
1 symbol in this file
1import assert from "node:assert/strict";
2import { test } from "node:test";
3import { importKey, providerToken } from "../src/apns.ts";
4
5function b64urlDecode(s: string): Uint8Array {
6 const b64 = s.replace(/-/g, "+").replace(/_/g, "/") + "=".repeat((4 - (s.length % 4)) % 4);
7 return Uint8Array.from(atob(b64), (c) => c.charCodeAt(0));
8}
9
10test("provider token is a valid ES256 JWT signed by the .p8 key", async () => {
11 const pair = await crypto.subtle.generateKey({ name: "ECDSA", namedCurve: "P-256" }, true, ["sign", "verify"]);
12 const der = new Uint8Array(await crypto.subtle.exportKey("pkcs8", pair.privateKey));
13 const pem = `-----BEGIN PRIVATE KEY-----\n${btoa(String.fromCharCode(...der)).replace(/(.{64})/g, "$1\n")}\n-----END PRIVATE KEY-----\n`;
14
15 const jwt = await providerToken("ABC123DEFG", "TEAM123456", await importKey(pem), 1_792_202_400);
16 const [h, c, s] = jwt.split(".");
17
18 assert.deepEqual(JSON.parse(new TextDecoder().decode(b64urlDecode(h))), { alg: "ES256", kid: "ABC123DEFG" });
19 assert.deepEqual(JSON.parse(new TextDecoder().decode(b64urlDecode(c))), { iss: "TEAM123456", iat: 1_792_202_400 });
20
21 const sig = b64urlDecode(s);
22 assert.equal(sig.length, 64);
23 const ok = await crypto.subtle.verify({ name: "ECDSA", hash: "SHA-256" }, pair.publicKey, sig, new TextEncoder().encode(`${h}.${c}`));
24 assert.ok(ok);
25});