{"version":3,"file":"vapid.mjs","names":[],"sources":["../src/vapid.ts"],"sourcesContent":["import { SignJWT, importPKCS8 } from 'jose';\n\nimport { base64UrlToUint8Array, uint8ArrayToBase64Url, validateBase64Url } from './base64url.ts';\n\nconst DEFAULT_EXPIRATION_SECONDS = 12 * 60 * 60;\nconst RAW_PRIVATE_KEY_LENGTH = 32;\n\nfunction importPrivateKey(\n\tdecodedPrivateKey: Uint8Array<ArrayBuffer>,\n\tdecodedPublicKey: Uint8Array<ArrayBuffer>,\n): Promise<CryptoKey> {\n\tif (decodedPrivateKey.length === RAW_PRIVATE_KEY_LENGTH) {\n\t\tconst x = uint8ArrayToBase64Url(decodedPublicKey.slice(1, 33));\n\t\tconst y = uint8ArrayToBase64Url(decodedPublicKey.slice(33, 65));\n\t\tconst d = uint8ArrayToBase64Url(decodedPrivateKey);\n\t\treturn crypto.subtle.importKey(\n\t\t\t'jwk',\n\t\t\t{ kty: 'EC', crv: 'P-256', x, y, d },\n\t\t\t{ name: 'ECDSA', namedCurve: 'P-256' },\n\t\t\tfalse,\n\t\t\t['sign'],\n\t\t);\n\t}\n\n\tconst pemBase64 = btoa(String.fromCharCode(...decodedPrivateKey));\n\treturn importPKCS8(\n\t\t`-----BEGIN PRIVATE KEY-----\\n${pemBase64}\\n-----END PRIVATE KEY-----`,\n\t\t'ES256',\n\t);\n}\n\nexport async function generateVAPIDKeys(): Promise<{\n\tpublicKey: string;\n\tprivateKey: string;\n}> {\n\tconst keyPair = await crypto.subtle.generateKey({ name: 'ECDSA', namedCurve: 'P-256' }, true, [\n\t\t'sign',\n\t]);\n\n\tconst publicKeyRaw = new Uint8Array(await crypto.subtle.exportKey('raw', keyPair.publicKey));\n\tconst privateKeyPkcs8 = new Uint8Array(\n\t\tawait crypto.subtle.exportKey('pkcs8', keyPair.privateKey),\n\t);\n\n\treturn {\n\t\tpublicKey: uint8ArrayToBase64Url(publicKeyRaw),\n\t\tprivateKey: uint8ArrayToBase64Url(privateKeyPkcs8),\n\t};\n}\n\nexport function validateSubject(subject: string): void {\n\tif (typeof subject !== 'string' || subject.length === 0) {\n\t\tthrow new Error(\n\t\t\t'The subject value must be a string containing an https: URL or mailto: address.',\n\t\t);\n\t}\n\n\tlet parsed: URL;\n\ttry {\n\t\tparsed = new URL(subject);\n\t} catch {\n\t\tthrow new Error(`Vapid subject is not a valid URL. ${subject}`);\n\t}\n\n\tif (parsed.protocol !== 'https:' && parsed.protocol !== 'mailto:') {\n\t\tthrow new Error(`Vapid subject is not an https: or mailto: URL. ${subject}`);\n\t}\n}\n\nexport function validatePublicKey(publicKey: string): void {\n\tif (typeof publicKey !== 'string' || publicKey.length === 0) {\n\t\tthrow new Error('Vapid public key must be a URL-safe Base64 encoded string.');\n\t}\n\n\tif (!validateBase64Url(publicKey)) {\n\t\tthrow new Error('Vapid public key must be URL-safe Base64 (without \"=\").');\n\t}\n\n\tconst decoded = base64UrlToUint8Array(publicKey);\n\tif (decoded.length !== 65) {\n\t\tthrow new Error('Vapid public key should be 65 bytes long when decoded.');\n\t}\n}\n\nexport function validatePrivateKey(privateKey: string): void {\n\tif (typeof privateKey !== 'string' || privateKey.length === 0) {\n\t\tthrow new Error('Vapid private key must be a URL-safe Base64 encoded string.');\n\t}\n\n\tif (!validateBase64Url(privateKey)) {\n\t\tthrow new Error('Vapid private key must be URL-safe Base64 (without \"=\").');\n\t}\n}\n\nexport async function createVapidAuthHeader(\n\tendpoint: string,\n\tpublicKey: string,\n\tprivateKey: string,\n\tsubject: string,\n\texpiration?: number,\n): Promise<string> {\n\tconst url = new URL(endpoint);\n\tconst audience = `${url.protocol}//${url.host}`;\n\n\tconst decodedPrivateKey = base64UrlToUint8Array(privateKey);\n\tconst key = await importPrivateKey(decodedPrivateKey, base64UrlToUint8Array(publicKey));\n\n\tconst exp = expiration ?? Math.floor(Date.now() / 1000) + DEFAULT_EXPIRATION_SECONDS;\n\n\tconst jwt = await new SignJWT({ aud: audience, sub: subject })\n\t\t.setProtectedHeader({ alg: 'ES256' })\n\t\t.setExpirationTime(exp)\n\t\t.sign(key);\n\n\treturn `vapid t=${jwt},k=${publicKey}`;\n}\n"],"mappings":";;;AAIA,MAAM,6BAA6B,MAAU;AAC7C,MAAM,yBAAyB;AAE/B,SAAS,iBACR,mBACA,kBACqB;AACrB,KAAI,kBAAkB,WAAW,wBAAwB;EACxD,MAAM,IAAI,sBAAsB,iBAAiB,MAAM,GAAG,GAAG,CAAC;EAC9D,MAAM,IAAI,sBAAsB,iBAAiB,MAAM,IAAI,GAAG,CAAC;EAC/D,MAAM,IAAI,sBAAsB,kBAAkB;AAClD,SAAO,OAAO,OAAO,UACpB,OACA;GAAE,KAAK;GAAM,KAAK;GAAS;GAAG;GAAG;GAAG,EACpC;GAAE,MAAM;GAAS,YAAY;GAAS,EACtC,OACA,CAAC,OAAO,CACR;;AAIF,QAAO,YACN,gCAFiB,KAAK,OAAO,aAAa,GAAG,kBAAkB,CAAC,CAEtB,8BAC1C,QACA;;AAGF,eAAsB,oBAGnB;CACF,MAAM,UAAU,MAAM,OAAO,OAAO,YAAY;EAAE,MAAM;EAAS,YAAY;EAAS,EAAE,MAAM,CAC7F,OACA,CAAC;CAEF,MAAM,eAAe,IAAI,WAAW,MAAM,OAAO,OAAO,UAAU,OAAO,QAAQ,UAAU,CAAC;CAC5F,MAAM,kBAAkB,IAAI,WAC3B,MAAM,OAAO,OAAO,UAAU,SAAS,QAAQ,WAAW,CAC1D;AAED,QAAO;EACN,WAAW,sBAAsB,aAAa;EAC9C,YAAY,sBAAsB,gBAAgB;EAClD;;AAGF,SAAgB,gBAAgB,SAAuB;AACtD,KAAI,OAAO,YAAY,YAAY,QAAQ,WAAW,EACrD,OAAM,IAAI,MACT,kFACA;CAGF,IAAI;AACJ,KAAI;AACH,WAAS,IAAI,IAAI,QAAQ;SAClB;AACP,QAAM,IAAI,MAAM,qCAAqC,UAAU;;AAGhE,KAAI,OAAO,aAAa,YAAY,OAAO,aAAa,UACvD,OAAM,IAAI,MAAM,kDAAkD,UAAU;;AAI9E,SAAgB,kBAAkB,WAAyB;AAC1D,KAAI,OAAO,cAAc,YAAY,UAAU,WAAW,EACzD,OAAM,IAAI,MAAM,6DAA6D;AAG9E,KAAI,CAAC,kBAAkB,UAAU,CAChC,OAAM,IAAI,MAAM,4DAA0D;AAI3E,KADgB,sBAAsB,UAAU,CACpC,WAAW,GACtB,OAAM,IAAI,MAAM,yDAAyD;;AAI3E,SAAgB,mBAAmB,YAA0B;AAC5D,KAAI,OAAO,eAAe,YAAY,WAAW,WAAW,EAC3D,OAAM,IAAI,MAAM,8DAA8D;AAG/E,KAAI,CAAC,kBAAkB,WAAW,CACjC,OAAM,IAAI,MAAM,6DAA2D;;AAI7E,eAAsB,sBACrB,UACA,WACA,YACA,SACA,YACkB;CAClB,MAAM,MAAM,IAAI,IAAI,SAAS;CAC7B,MAAM,WAAW,GAAG,IAAI,SAAS,IAAI,IAAI;CAGzC,MAAM,MAAM,MAAM,iBADQ,sBAAsB,WAAW,EACL,sBAAsB,UAAU,CAAC;CAEvF,MAAM,MAAM,cAAc,KAAK,MAAM,KAAK,KAAK,GAAG,IAAK,GAAG;AAO1D,QAAO,WALK,MAAM,IAAI,QAAQ;EAAE,KAAK;EAAU,KAAK;EAAS,CAAC,CAC5D,mBAAmB,EAAE,KAAK,SAAS,CAAC,CACpC,kBAAkB,IAAI,CACtB,KAAK,IAAI,CAEW,KAAK"}