-
Notifications
You must be signed in to change notification settings - Fork 314
/
account.ts
132 lines (126 loc) · 3.87 KB
/
account.ts
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
import {
ecPairToAddress,
getPublicKeyFromPrivate,
hashCode,
hashSha256Sync,
} from '@stacks/encryption';
import { makeAuthResponse as _makeAuthResponse } from '@stacks/auth';
import { TransactionVersion, getAddressFromPrivateKey } from '@stacks/transactions';
import { fromBase58 } from 'bip32';
import {
DEFAULT_PROFILE,
fetchAccountProfileUrl,
fetchProfileFromUrl,
signAndUploadProfile,
} from './profile';
import { Account } from './common';
import { ECPair } from 'bitcoinjs-lib';
import { connectToGaiaHubWithConfig, getHubInfo, makeGaiaAssociationToken } from '../utils';
import { Buffer } from '@stacks/common';
export const getStxAddress = ({
account,
transactionVersion = TransactionVersion.Testnet,
}: {
account: Account;
transactionVersion?: TransactionVersion;
}): string => {
return getAddressFromPrivateKey(account.stxPrivateKey, transactionVersion);
};
/**
* Get the display name of an account.
*
* If the account has a username, it will return the first part of the username, so `myname.id` => `myname`, and
* `myname.blockstack.id` => `myname`.
*
* If the account has no username, it returns `Account ${acount.index}`
*
*/
export const getAccountDisplayName = (account: Account) => {
if (account.username) {
return account.username.split('.')[0];
}
return `Account ${account.index + 1}`;
};
export const getAppPrivateKey = ({
account,
appDomain,
}: {
account: Account;
appDomain: string;
}) => {
const hashBuffer = hashSha256Sync(Buffer.from(`${appDomain}${account.salt}`));
const hash = hashBuffer.toString('hex');
const appIndex = hashCode(hash);
const appsNode = fromBase58(account.appsKey);
const appKeychain = appsNode.deriveHardened(appIndex);
if (!appKeychain.privateKey) throw 'Needs private key';
return appKeychain.privateKey.toString('hex');
};
export const makeAuthResponse = async ({
account,
appDomain,
transitPublicKey,
scopes = [],
gaiaHubUrl,
appPrivateKeyFromWalletSalt = null,
}: {
account: Account;
appDomain: string;
transitPublicKey: string;
scopes?: string[];
gaiaHubUrl: string;
appPrivateKeyFromWalletSalt?: string | null;
}) => {
const appPrivateKey = getAppPrivateKey({ account, appDomain });
const hubInfo = await getHubInfo(gaiaHubUrl);
const profileUrl = await fetchAccountProfileUrl({ account, gaiaHubUrl: hubInfo.read_url_prefix });
const profile = (await fetchProfileFromUrl(profileUrl)) || DEFAULT_PROFILE;
if (scopes.includes('publish_data')) {
if (!profile.apps) {
profile.apps = {};
}
const challengeSigner = ECPair.fromPrivateKey(Buffer.from(appPrivateKey, 'hex'));
const storageUrl = `${hubInfo.read_url_prefix}${ecPairToAddress(challengeSigner)}/`;
profile.apps[appDomain] = storageUrl;
if (!profile.appsMeta) {
profile.appsMeta = {};
}
profile.appsMeta[appDomain] = {
storage: storageUrl,
publicKey: challengeSigner.publicKey.toString('hex'),
};
const gaiaHubConfig = connectToGaiaHubWithConfig({
hubInfo,
privateKey: account.dataPrivateKey,
gaiaHubUrl,
});
await signAndUploadProfile({ profile, account, gaiaHubUrl, gaiaHubConfig });
}
const compressedAppPublicKey = getPublicKeyFromPrivate(appPrivateKey.slice(0, 64));
const associationToken = makeGaiaAssociationToken({
privateKey: account.dataPrivateKey,
childPublicKeyHex: compressedAppPublicKey,
});
return _makeAuthResponse(
account.dataPrivateKey,
{
...(profile || {}),
stxAddress: {
testnet: getStxAddress({ account, transactionVersion: TransactionVersion.Testnet }),
mainnet: getStxAddress({ account, transactionVersion: TransactionVersion.Mainnet }),
},
},
account.username || '',
{
profileUrl,
},
undefined,
appPrivateKey,
undefined,
transitPublicKey,
gaiaHubUrl,
undefined,
associationToken,
appPrivateKeyFromWalletSalt
);
};