UNPKG

@stacks/auth

Version:

Authentication for Stacks apps.

105 lines 4.52 kB
import { bytesToHex, bytesToUtf8, getGlobalObject, hexToBytes, makeUUID4, nextMonth, utf8ToBytes, } from '@stacks/common'; import { decryptECIES, encryptECIES, makeECPrivateKey, publicKeyToBtcAddress, } from '@stacks/encryption'; import { SECP256K1Client, TokenSigner } from 'jsontokens'; import { DEFAULT_SCOPE } from './constants'; import { makeDIDFromAddress } from './dids'; const VERSION = '1.4.0'; export function generateTransitKey() { const transitKey = makeECPrivateKey(); return transitKey; } export const makeAuthRequest = makeAuthRequestToken; export function makeAuthRequestToken(transitPrivateKey, redirectURI, manifestURI, scopes = DEFAULT_SCOPE.slice(), appDomain, expiresAt = nextMonth().getTime(), extraParams = {}) { const getWindowOrigin = (paramName) => { const location = getGlobalObject('location', { throwIfUnavailable: true, usageDesc: `makeAuthRequest([${paramName}=undefined])`, }); return location?.origin; }; if (!redirectURI) { redirectURI = `${getWindowOrigin('redirectURI')}/`; } if (!manifestURI) { manifestURI = `${getWindowOrigin('manifestURI')}/manifest.json`; } if (!appDomain) { appDomain = getWindowOrigin('appDomain'); } const payload = Object.assign({}, extraParams, { jti: makeUUID4(), iat: Math.floor(new Date().getTime() / 1000), exp: Math.floor(expiresAt / 1000), iss: null, public_keys: [], domain_name: appDomain, manifest_uri: manifestURI, redirect_uri: redirectURI, version: VERSION, do_not_include_profile: true, supports_hub_url: true, scopes, }); const publicKey = SECP256K1Client.derivePublicKey(transitPrivateKey); payload.public_keys = [publicKey]; const address = publicKeyToBtcAddress(publicKey); payload.iss = makeDIDFromAddress(address); const tokenSigner = new TokenSigner('ES256k', transitPrivateKey); const token = tokenSigner.sign(payload); return token; } export async function encryptPrivateKey(publicKey, privateKey) { const encryptedObj = await encryptECIES(publicKey, utf8ToBytes(privateKey), true); const encryptedJSON = JSON.stringify(encryptedObj); return bytesToHex(utf8ToBytes(encryptedJSON)); } export async function decryptPrivateKey(privateKey, hexedEncrypted) { const unhexedString = bytesToUtf8(hexToBytes(hexedEncrypted)); const encryptedObj = JSON.parse(unhexedString); const decrypted = await decryptECIES(privateKey, encryptedObj); if (typeof decrypted !== 'string') { throw new Error('Unable to correctly decrypt private key'); } else { return decrypted; } } export async function makeAuthResponse(privateKey, profile = {}, metadata, coreToken = null, appPrivateKey = null, expiresAt = nextMonth().getTime(), transitPublicKey = null, hubUrl = null, blockstackAPIUrl = null, associationToken = null, appPrivateKeyFromWalletSalt = null) { const publicKey = SECP256K1Client.derivePublicKey(privateKey); const address = publicKeyToBtcAddress(publicKey); let privateKeyPayload = appPrivateKey; let coreTokenPayload = coreToken; let additionalProperties = {}; if (appPrivateKey !== undefined && appPrivateKey !== null) { if (transitPublicKey !== undefined && transitPublicKey !== null) { privateKeyPayload = await encryptPrivateKey(transitPublicKey, appPrivateKey); if (coreToken !== undefined && coreToken !== null) { coreTokenPayload = await encryptPrivateKey(transitPublicKey, coreToken); } } additionalProperties = { email: metadata?.email ? metadata.email : null, profile_url: metadata?.profileUrl ? metadata.profileUrl : null, hubUrl, blockstackAPIUrl, associationToken, version: VERSION, }; } else { } const payload = Object.assign({}, { jti: makeUUID4(), iat: Math.floor(new Date().getTime() / 1000), exp: Math.floor(expiresAt / 1000), iss: makeDIDFromAddress(address), private_key: privateKeyPayload, public_keys: [publicKey], appPrivateKeyFromWalletSalt, profile, core_token: coreTokenPayload, }, additionalProperties); const tokenSigner = new TokenSigner('ES256k', privateKey); return tokenSigner.sign(payload); } //# sourceMappingURL=messages.js.map