UNPKG

@atproto/oauth-client

Version:

OAuth client for ATPROTO PDS. This package serves as common base for environment-specific implementations (NodeJS, Browser, React-Native).

121 lines 4.27 kB
"use strict"; Object.defineProperty(exports, "__esModule", { value: true }); exports.Runtime = void 0; const base64_1 = require("multiformats/bases/base64"); const lock_js_1 = require("./lock.js"); class Runtime { constructor(implementation) { Object.defineProperty(this, "implementation", { enumerable: true, configurable: true, writable: true, value: implementation }); Object.defineProperty(this, "hasImplementationLock", { enumerable: true, configurable: true, writable: true, value: void 0 }); Object.defineProperty(this, "usingLock", { enumerable: true, configurable: true, writable: true, value: void 0 }); const { requestLock } = implementation; this.hasImplementationLock = requestLock != null; this.usingLock = requestLock?.bind(implementation) || // Falling back to a local lock lock_js_1.requestLocalLock; } async generateKey(algs) { const algsSorted = Array.from(algs).sort(compareAlgos); return this.implementation.createKey(algsSorted); } async sha256(text) { const bytes = new TextEncoder().encode(text); const digest = await this.implementation.digest(bytes, { name: 'sha256' }); return base64_1.base64url.baseEncode(digest); } async generateNonce(length = 16) { const bytes = await this.implementation.getRandomValues(length); return base64_1.base64url.baseEncode(bytes); } async generatePKCE(byteLength) { const verifier = await this.generateVerifier(byteLength); return { verifier, challenge: await this.sha256(verifier), method: 'S256', }; } async calculateJwkThumbprint(jwk) { const components = extractJktComponents(jwk); const data = JSON.stringify(components); return this.sha256(data); } /** * @see {@link https://datatracker.ietf.org/doc/html/rfc7636#section-4.1} * @note It is RECOMMENDED that the output of a suitable random number generator * be used to create a 32-octet sequence. The octet sequence is then * base64url-encoded to produce a 43-octet URL safe string to use as the code * verifier. */ async generateVerifier(byteLength = 32) { if (byteLength < 32 || byteLength > 96) { throw new TypeError('Invalid code_verifier length'); } const bytes = await this.implementation.getRandomValues(byteLength); return base64_1.base64url.baseEncode(bytes); } } exports.Runtime = Runtime; function extractJktComponents(jwk) { const get = (field) => { const value = jwk[field]; if (typeof value !== 'string' || !value) { throw new TypeError(`"${field}" Parameter missing or invalid`); } return value; }; switch (jwk.kty) { case 'EC': return { crv: get('crv'), kty: get('kty'), x: get('x'), y: get('y') }; case 'OKP': return { crv: get('crv'), kty: get('kty'), x: get('x') }; case 'RSA': return { e: get('e'), kty: get('kty'), n: get('n') }; case 'oct': return { k: get('k'), kty: get('kty') }; default: throw new TypeError('"kty" (Key Type) Parameter missing or unsupported'); } } /** * 256K > ES (256 > 384 > 512) > PS (256 > 384 > 512) > RS (256 > 384 > 512) > other (in original order) */ function compareAlgos(a, b) { if (a === 'ES256K') return -1; if (b === 'ES256K') return 1; for (const prefix of ['ES', 'PS', 'RS']) { if (a.startsWith(prefix)) { if (b.startsWith(prefix)) { const aLen = parseInt(a.slice(2, 5)); const bLen = parseInt(b.slice(2, 5)); // Prefer shorter key lengths return aLen - bLen; } return -1; } else if (b.startsWith(prefix)) { return 1; } } // Don't know how to compare, keep original order return 0; } //# sourceMappingURL=runtime.js.map