@livepeer/core
Version:
Livepeer UI Kit's core vanilla JS library.
1 lines • 10.9 kB
Source Map (JSON)
{"version":3,"sources":["../../src/crypto.ts","../../src/utils/string.ts","../../src/crypto/getSubtleCrypto.ts","../../src/crypto/ecdsa.ts","../../src/crypto/pkcs8.ts","../../src/crypto/jwt.ts"],"sourcesContent":["export { signAccessJwt, type SignAccessJwtOptions } from \"./crypto/jwt\";\nexport { importPKCS8 } from \"./crypto/pkcs8\";\n","export const b64Encode = (input: string): string | null => {\n try {\n if (typeof window !== \"undefined\" && \"btoa\" in window) {\n return window?.btoa?.(input) ?? null;\n }\n return Buffer?.from(input, \"binary\")?.toString(\"base64\") ?? null;\n } catch (e) {\n return null;\n }\n};\n\nexport const b64Decode = (input: string): string | null => {\n try {\n if (typeof window !== \"undefined\" && \"atob\" in window) {\n return window?.atob?.(input) ?? null;\n }\n return Buffer?.from(input, \"base64\")?.toString(\"binary\") ?? null;\n } catch (e) {\n return null;\n }\n};\n\nexport const b64UrlEncode = (input: string): string | null => {\n return escapeInput(b64Encode(input));\n};\n\nexport const b64UrlDecode = (input: string): string | null => {\n const unescaped = unescapeInput(input);\n if (unescaped) {\n return b64Decode(unescaped);\n }\n return null;\n};\n\nconst unescapeInput = (input: string | undefined | null) => {\n return input\n ? (input + \"===\".slice((input.length + 3) % 4))\n .replace(/-/g, \"+\")\n .replace(/_/g, \"/\")\n : null;\n};\n\nconst escapeInput = (input: string | undefined | null) => {\n return (\n input?.replace(/\\+/g, \"-\").replace(/\\//g, \"_\").replace(/=/g, \"\") ?? null\n );\n};\n","export const getSubtleCrypto = async () => {\n if (typeof crypto !== \"undefined\" && crypto?.subtle) {\n return crypto.subtle;\n }\n\n if (typeof globalThis?.crypto !== \"undefined\" && globalThis?.crypto?.subtle) {\n return globalThis.crypto.subtle;\n }\n\n try {\n const nodeCrypto = await import(\"node:crypto\");\n return nodeCrypto.webcrypto.subtle;\n } catch (error) {\n if (typeof window !== \"undefined\") {\n if (window?.crypto?.subtle) {\n return window.crypto.subtle;\n }\n\n throw new Error(\n \"Browser is not in a secure context (HTTPS), cannot use SubtleCrypto: https://developer.mozilla.org/en-US/docs/Web/API/SubtleCrypto\",\n );\n }\n\n throw new Error(\n `Failed to import Node.js crypto module: ${\n (error as Error)?.message ?? \"\"\n }`,\n );\n }\n};\n","import { getSubtleCrypto } from \"./getSubtleCrypto\";\n\nexport const signEcdsaSha256 = async (\n privateKey: CryptoKey,\n data: BufferSource,\n) => {\n const subtleCrypto = await getSubtleCrypto();\n\n return subtleCrypto.sign(\n {\n name: \"ECDSA\",\n hash: { name: \"SHA-256\" },\n },\n privateKey,\n data,\n );\n};\n","import { b64UrlDecode } from \"../utils/string\";\nimport { getSubtleCrypto } from \"./getSubtleCrypto\";\n\nexport const importPKCS8 = async (pkcs8: string): Promise<CryptoKey> => {\n if (\n typeof pkcs8 !== \"string\" ||\n pkcs8.indexOf(\"-----BEGIN PRIVATE KEY-----\") !== 0\n ) {\n throw new TypeError('\"pkcs8\" must be PKCS8 formatted string');\n }\n\n const privateKeyContents = b64UrlDecode(\n pkcs8.replace(/(?:-----(?:BEGIN|END) PRIVATE KEY-----|\\s)/g, \"\"),\n );\n\n if (!privateKeyContents) {\n throw new TypeError(\"Could not base64 decode private key contents.\");\n }\n\n const subtleCrypto = await getSubtleCrypto();\n\n return subtleCrypto.importKey(\n \"pkcs8\",\n new Uint8Array(privateKeyContents?.split(\"\").map((c) => c.charCodeAt(0))),\n {\n name: \"ECDSA\",\n namedCurve: \"P-256\",\n },\n false,\n [\"sign\"],\n );\n};\n","import { b64Decode, b64UrlEncode } from \"../utils/string\";\nimport { signEcdsaSha256 } from \"./ecdsa\";\nimport { importPKCS8 } from \"./pkcs8\";\n\nexport type JWTPayload = {\n /**\n * JWT Issuer\n *\n * @see [RFC7519#section-4.1.1](https://www.rfc-editor.org/rfc/rfc7519#section-4.1.1)\n */\n iss?: string;\n\n /**\n * JWT Subject\n *\n * @see [RFC7519#section-4.1.2](https://www.rfc-editor.org/rfc/rfc7519#section-4.1.2)\n */\n sub?: string;\n\n /** JWT Audience [RFC7519#section-4.1.3](https://www.rfc-editor.org/rfc/rfc7519#section-4.1.3). */\n aud?: string | string[];\n\n /**\n * JWT ID\n *\n * @see [RFC7519#section-4.1.7](https://www.rfc-editor.org/rfc/rfc7519#section-4.1.7)\n */\n jti?: string;\n\n /**\n * JWT Not Before\n *\n * @see [RFC7519#section-4.1.5](https://www.rfc-editor.org/rfc/rfc7519#section-4.1.5)\n */\n nbf?: number;\n\n /**\n * JWT Expiration Time\n *\n * @see [RFC7519#section-4.1.4](https://www.rfc-editor.org/rfc/rfc7519#section-4.1.4)\n */\n exp?: number;\n\n /**\n * JWT Issued At\n *\n * @see [RFC7519#section-4.1.6](https://www.rfc-editor.org/rfc/rfc7519#section-4.1.6)\n */\n iat?: number;\n\n /**\n * Allowed action for this token. `pull` is allowing playback. Custom claim.\n */\n action: \"pull\";\n\n /** Any other JWT Claim Set member. */\n [propName: string]: unknown;\n};\n\nexport type JWTHeader = {\n /** JWE \"alg\" (Algorithm) Header Parameter. */\n alg: \"ES256\";\n\n /** \"typ\" (Type) Header Parameter. */\n typ: \"JWT\";\n};\n\nexport type SignAccessJwtOptions = {\n /**\n * The private key used to sign the token. **This comes base64-encoded from the livepeer provider\n * - this should be kept as base64.**\n *\n * This can also be a CryptoKey if the key has already been imported on the client.\n */\n privateKey: CryptoKey | string;\n\n /**\n * The public key corresponding to the public key. **This comes\n * base64-encoded from the livepeer provider - this should be kept as base64.**\n */\n publicKey: string;\n\n /**\n * The playback ID which you would like to restrict access to (required).\n */\n playbackId: string;\n\n /**\n * The issuer of the token. Usually a string or URL identifying your app.\n */\n issuer: string;\n\n /**\n * The expiration of the token in seconds. Defaults to `86400` or one day in seconds.\n */\n expiration?: number;\n\n /**\n * Custom properties added to the token. These can be used across your app to hold token state (user ID, etc).\n */\n custom?: {\n [key: string]: unknown;\n };\n};\n/**\n * Signs a JSON Web Token which can be used to view access-restricted media.\n *\n * Throws if it cannot find SubtleCrypto in the environment.\n */\nexport const signAccessJwt = async (\n options: SignAccessJwtOptions,\n): Promise<string> => {\n // assume strings passed are PEM-encoded PKCS8 (or base64 encoded)\n // try to coerce the input from base64, or use as-is\n const privateKey =\n typeof options.privateKey === \"string\"\n ? await importPKCS8(b64Decode(options.privateKey) ?? options.privateKey)\n : options.privateKey;\n\n if (!privateKey) {\n throw new Error(\"Error importing private key.\");\n }\n\n const issuedAtSec = Date.now() / 1000;\n const expirationSec = issuedAtSec + (options.expiration ?? 86400);\n\n const payload: JWTPayload = {\n action: \"pull\",\n iss: options.issuer,\n pub: options.publicKey,\n sub: options.playbackId,\n video: \"none\",\n exp: Number(expirationSec.toFixed(0)),\n iat: Number(issuedAtSec.toFixed(0)),\n\n ...(options.custom\n ? {\n custom: {\n ...options.custom,\n },\n }\n : {}),\n };\n\n const header: JWTHeader = {\n alg: \"ES256\",\n typ: \"JWT\",\n };\n\n const base64Header = b64UrlEncode(JSON.stringify(header));\n const base64Payload = b64UrlEncode(JSON.stringify(payload));\n\n const body = `${base64Header}.${base64Payload}`;\n\n const signatureBuffer = await signEcdsaSha256(privateKey, Buffer.from(body));\n\n const signature = b64UrlEncode(\n String.fromCharCode(...new Uint8Array(signatureBuffer)),\n );\n\n return `${base64Header}.${base64Payload}.${signature}`;\n};\n"],"mappings":"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","names":[]}