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