UNPKG

@river-build/sdk

Version:

For more details, visit the following resources:

101 lines 4.77 kB
import { ecrecover, fromRpcSig, hashPersonalMessage } from '@ethereumjs/util'; import { ethers } from 'ethers'; import { bin_equal, bin_fromHexString, bin_toHexString, check } from '@river-build/dlog'; import { publicKeyToAddress, publicKeyToUint8Array, riverDelegateHashSrc } from './sign'; import { BearerTokenSchema, Err } from '@river-build/proto'; import { create, fromBinary, toBinary } from '@bufbuild/protobuf'; export const checkDelegateSig = (params) => { const creatorAddress = typeof params.creatorAddress === 'string' ? publicKeyToUint8Array(params.creatorAddress) : params.creatorAddress; const recoveredCreatorAddress = recoverPublicKeyFromDelegateSig(params); check(bin_equal(recoveredCreatorAddress, creatorAddress), 'delegateSig does not match creatorAddress', Err.BAD_DELEGATE_SIG); }; export const recoverPublicKeyFromDelegateSig = (params) => { const { delegateSig, expiryEpochMs } = params; const delegatePubKey = typeof params.delegatePubKey === 'string' ? publicKeyToUint8Array(params.delegatePubKey) : params.delegatePubKey; const hashSource = riverDelegateHashSrc(delegatePubKey, expiryEpochMs); const hash = hashPersonalMessage(Buffer.from(hashSource)); const { v, r, s } = fromRpcSig('0x' + bin_toHexString(delegateSig)); const recoveredCreatorPubKey = ecrecover(hash, v, r, s); const recoveredCreatorAddress = Uint8Array.from(publicKeyToAddress(recoveredCreatorPubKey)); return recoveredCreatorAddress; }; async function makeRiverDelegateSig(primaryWallet, devicePubKey, expiryEpochMs) { if (typeof devicePubKey === 'string') { devicePubKey = publicKeyToUint8Array(devicePubKey); } check(devicePubKey.length === 65, 'Bad public key', Err.BAD_PUBLIC_KEY); const hashSrc = riverDelegateHashSrc(devicePubKey, expiryEpochMs); const delegateSig = bin_fromHexString(await primaryWallet.signMessage(hashSrc)); return delegateSig; } export async function makeSignerContext(primaryWallet, delegateWallet, inExpiryEpochMs) { const expiryEpochMs = inExpiryEpochMs ?? 0n; // todo make expiry required param once implemented down stream HNT-5213 const delegateExpiryEpochMs = typeof expiryEpochMs === 'bigint' ? expiryEpochMs : makeExpiryEpochMs(expiryEpochMs); const delegateSig = await makeRiverDelegateSig(primaryWallet, delegateWallet.publicKey, delegateExpiryEpochMs); const creatorAddress = await primaryWallet.getAddress(); return { signerPrivateKey: () => delegateWallet.privateKey.slice(2), // remove the 0x prefix creatorAddress: bin_fromHexString(creatorAddress), delegateSig, delegateExpiryEpochMs, }; } // make auth token export async function makeBearerToken(signer, expiry) { const delegate = await makeSignerDelegate(signer, expiry); const bearerToken = create(BearerTokenSchema, { delegatePrivateKey: delegate.delegateWallet.privateKey, delegateSig: delegate.signerContext.delegateSig, expiryEpochMs: delegate.signerContext.delegateExpiryEpochMs, }); return bin_toHexString(toBinary(BearerTokenSchema, bearerToken)); } export async function makeSignerContextFromBearerToken(bearerTokenStr) { const bearerToken = fromBinary(BearerTokenSchema, bin_fromHexString(bearerTokenStr)); const delegateWallet = new ethers.Wallet(bearerToken.delegatePrivateKey); const creatorAddress = recoverPublicKeyFromDelegateSig({ delegatePubKey: delegateWallet.publicKey, delegateSig: bearerToken.delegateSig, expiryEpochMs: bearerToken.expiryEpochMs, }); return { signerPrivateKey: () => bearerToken.delegatePrivateKey.slice(2), // remove the 0x prefix, creatorAddress, delegateSig: bearerToken.delegateSig, delegateExpiryEpochMs: bearerToken.expiryEpochMs, }; } export async function makeSignerDelegate(signer, expiry) { const delegateWallet = ethers.Wallet.createRandom(); const signerContext = await makeSignerContext(signer, delegateWallet, expiry); return { delegateWallet, signerContext, }; } function makeExpiryEpochMs({ days, hours, minutes, seconds, }) { const MS_PER_SECOND = 1000; const MS_PER_MINUTE = MS_PER_SECOND * 60; const MS_PER_HOUR = MS_PER_MINUTE * 60; const MS_PER_DAY = MS_PER_HOUR * 24; let delta = 0; if (days) { delta += MS_PER_DAY * days; } if (hours) { delta += MS_PER_HOUR * hours; } if (minutes) { delta += MS_PER_MINUTE * minutes; } if (seconds) { delta += MS_PER_SECOND * seconds; } check(delta != 0, 'Bad expiration, no values were set'); return BigInt(Date.now() + delta); } //# sourceMappingURL=signerContext.js.map