@river-build/sdk
Version:
For more details, visit the following resources:
101 lines • 4.77 kB
JavaScript
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