UNPKG

@stacks/keychain

Version:

A package for managing Stacks keychains

138 lines (123 loc) 3.93 kB
import { getPublicKeyFromPrivate, publicKeyToAddress } from '@stacks/encryption'; import { createFetchFn, FetchFn } from '@stacks/network'; import { GaiaHubConfig } from '@stacks/storage'; import { Json, TokenSigner } from 'jsontokens'; import randomBytes from 'randombytes'; export const DEFAULT_GAIA_HUB = 'https://gaia.blockstack.org/hub/'; interface HubInfo { challenge_text?: string; read_url_prefix: string; } /** @deprecated use `@stacks/storage` instead */ export const getHubInfo = async (hubUrl: string, fetchFn: FetchFn = createFetchFn()) => { const response = await fetchFn(`${hubUrl}/hub_info`); const data: HubInfo = await response.json(); return data; }; /** @deprecated use `@stacks/storage` instead */ export const makeGaiaAssociationToken = ( secretKeyHex: string, childPublicKeyHex: string ): string => { const LIFETIME_SECONDS = 365 * 24 * 3600; const signerKeyHex = secretKeyHex.slice(0, 64); const compressedPublicKeyHex = getPublicKeyFromPrivate(signerKeyHex); const salt = randomBytes(16).toString('hex'); const payload = { childToAssociate: childPublicKeyHex, iss: compressedPublicKeyHex, exp: LIFETIME_SECONDS + new Date().getTime() / 1000, iat: Date.now() / 1000, salt, }; const tokenSigner = new TokenSigner('ES256K', signerKeyHex); const token = tokenSigner.sign(payload); return token; }; interface ConnectToGaiaOptions { hubInfo: HubInfo; privateKey: string; gaiaHubUrl: string; } /** @deprecated use `@stacks/storage` instead */ export const connectToGaiaHubWithConfig = ({ hubInfo, privateKey, gaiaHubUrl, }: ConnectToGaiaOptions): GaiaHubConfig => { const readURL = hubInfo.read_url_prefix; const token = makeGaiaAuthToken({ hubInfo, privateKey, gaiaHubUrl }); const address = publicKeyToAddress(getPublicKeyFromPrivate(privateKey)); return { url_prefix: readURL, max_file_upload_size_megabytes: 100, address, token, server: gaiaHubUrl, }; }; interface ReadOnlyGaiaConfigOptions { readURL: string; privateKey: string; } /** * When you already know the Gaia read URL, make a Gaia config that doesn't have to fetch `/hub_info` * @deprecated use `@stacks/storage` instead */ export const makeReadOnlyGaiaConfig = ({ readURL, privateKey, }: ReadOnlyGaiaConfigOptions): GaiaHubConfig => { const address = publicKeyToAddress(getPublicKeyFromPrivate(privateKey)); return { url_prefix: readURL, max_file_upload_size_megabytes: 100, address, token: 'not_used', server: 'not_used', }; }; /** @deprecated use `@stacks/storage` instead */ interface GaiaAuthPayload { gaiaHubUrl: string; iss: string; salt: string; [key: string]: Json; } const makeGaiaAuthToken = ({ hubInfo, privateKey, gaiaHubUrl }: ConnectToGaiaOptions) => { const challengeText = hubInfo.challenge_text; const iss = getPublicKeyFromPrivate(privateKey); const salt = randomBytes(16).toString('hex'); const payload: GaiaAuthPayload = { gaiaHubUrl, iss, salt, }; if (challengeText) { payload.gaiaChallenge = challengeText; } const token = new TokenSigner('ES256K', privateKey).sign(payload); return `v1:${token}`; }; /** @deprecated use `@stacks/storage` instead */ export const uploadToGaiaHub = async ( filename: string, // eslint-disable-next-line node/prefer-global/buffer contents: Blob | Buffer | ArrayBufferView | string, hubConfig: GaiaHubConfig, fetchFn: FetchFn = createFetchFn() ): Promise<string> => { const contentType = 'application/json'; const response = await fetchFn(`${hubConfig.server}/store/${hubConfig.address}/${filename}`, { method: 'POST', headers: { 'Content-Type': contentType, Authorization: `bearer ${hubConfig.token}`, }, body: contents, referrer: 'no-referrer', referrerPolicy: 'no-referrer', }); const { publicURL } = await response.json(); return publicURL; };