on 703ff86 help sign in
bridge/src/lib/authToken.ts
119 lines 3.7 kB history raw
1import { crypto } from 'bitcoinjs-lib';
2import { ecdsaSign } from 'secp256k1';
3import Web3 from 'web3';
4import { hexToBytes } from 'web3-utils';
5import { hashPersonalMessage } from '@ethereumjs/util';
6import { WALLET_TYPES } from './constants';
7import BridgeWallet from './types/BridgeWallet';
8import { Hash } from '@urbit/roller-api';
10const MESSAGE = 'Bridge Authentication Token';
12function signMessage(privateKey: Buffer, useLegacyTokenSigning = false) {
13 const msg = '\x19Ethereum Signed Message:\n' + MESSAGE.length + MESSAGE;
14 const hashed = useLegacyTokenSigning
15 ? crypto.sha256(Buffer.from(msg))
16 : hashPersonalMessage(Buffer.from(MESSAGE)); // msg prefix is handled by lib
18 const hashAry = new Uint8Array(hashed.buffer);
19 const { signature } = ecdsaSign(hashAry, privateKey);
21 // add key recovery parameter
22 const ethSignature = new Uint8Array(65);
23 ethSignature.set(signature);
25 // https://eips.ethereum.org/EIPS/eip-155
26 // This method for setting the recovery parameter is the "legacy" way of doing
27 // so; and in fact, does not match up with output of Metamask / Brave Wallet.
28 // MM uses 28 instead of 27.
29 // TODO: Should we bring this up to latest standard? The problem is, users
30 // who have set network keys or generated invites with an older token will
31 // not be able to rederive them
32 const v = (ethSignature[32] & 1) + 27;
33 ethSignature[64] = v;
35 return ethSignature;
38export function signTransactionHash(msg: Hash, prvKey: Buffer) {
39 // msg is a keccak-256 hash
40 //
41 const hashed = Buffer.from(hexToBytes(msg));
42 const { signature, recid } = ecdsaSign(hashed, prvKey);
43 // add key recovery parameter
44 const ethSignature = new Uint8Array(65);
45 ethSignature.set(signature);
46 ethSignature[64] = recid;
47 return `0x${Buffer.from(ethSignature).toString('hex')}`;
50type MetamaskAuthTokenArgs = {
51 address: string;
52 web3: Web3;
53 walletType: symbol;
54};
56type WalletConnectAuthTokenArgs = {
57 address: string;
58 signPersonalMessage: Function;
59 walletType: symbol;
60};
62type DefaultAuthTokenArgs = {
63 wallet: BridgeWallet;
64 walletType?: symbol;
65 useLegacyTokenSigning?: boolean;
66};
68type GetAuthTokenArgs =
69 | MetamaskAuthTokenArgs
70 | WalletConnectAuthTokenArgs
71 | DefaultAuthTokenArgs;
73const getMetamaskAuthToken = ({ address, web3 }: MetamaskAuthTokenArgs) => {
74 if (window.ethereum) {
75 //NOTE this doesn't _seem_ to be affected by #596,
76 // but web3.eth.personal.sign hits it semi-reliably?
77 // no idea what's going on, we should figure it out,
78 // but we apply this bandaid to hopefully stop the bleeding.
79 return window.ethereum.request({
80 method: 'personal_sign',
81 params: [MESSAGE, address],
82 from: address,
83 });
84 } else {
85 return web3.eth.personal.sign(MESSAGE, address, '');
86 }
87};
89const getWalletConnectAuthToken = async ({
90 address,
91 signPersonalMessage,
92}: WalletConnectAuthTokenArgs) => {
93 return await signPersonalMessage({ message: MESSAGE, address: address });
94};
96const getDefaultAuthToken = ({
97 wallet,
98 useLegacyTokenSigning = false,
99}: DefaultAuthTokenArgs) => {
100 const signature = signMessage(wallet.privateKey!, useLegacyTokenSigning);
102 const token = `0x${Buffer.from(signature).toString('hex')}`;
104 return token;
105};
107export const getAuthToken = async ({
108 walletType,
109 ...args
110}: GetAuthTokenArgs) => {
111 switch (walletType) {
112 case WALLET_TYPES.METAMASK:
113 return getMetamaskAuthToken(args as MetamaskAuthTokenArgs);
114 case WALLET_TYPES.WALLET_CONNECT:
115 return getWalletConnectAuthToken(args as WalletConnectAuthTokenArgs);
116 default:
117 return getDefaultAuthToken(args as DefaultAuthTokenArgs);
118 }
119};