@ledgerhq/ledger-key-ring-protocol 0.5.3 → 0.5.4-nightly.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/lib-es/sdk.js CHANGED
@@ -1,12 +1,3 @@
1
- var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
2
- function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
3
- return new (P || (P = Promise))(function (resolve, reject) {
4
- function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
5
- function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
6
- function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
7
- step((generator = generator.apply(thisArg, _arguments || [])).next());
8
- });
9
- };
10
1
  import { TrustchainResultType, } from "./types";
11
2
  import { crypto, Challenge, CommandStreamEncoder, StreamTree, Permissions, DerivationPath, SoftwareDevice, } from "@ledgerhq/hw-ledger-key-ring-protocol";
12
3
  import getApi from "./api";
@@ -15,14 +6,18 @@ import { LedgerAPI4xx } from "@ledgerhq/errors";
15
6
  import { TrustchainAlreadyInitialized, TrustchainAlreadyInitializedWithOtherSeed, TrustchainEjected, TrustchainNotAllowed, TrustchainOutdated, } from "./errors";
16
7
  import { genericWithJWT } from "./auth";
17
8
  export class SDK {
9
+ context;
10
+ hwDeviceProvider;
11
+ lifecycle;
12
+ api;
18
13
  constructor(context, hwDeviceProvider, lifecyle) {
19
- this.jwt = undefined;
20
- this.jwtHash = "";
21
14
  this.context = context;
22
15
  this.hwDeviceProvider = hwDeviceProvider;
23
16
  this.lifecycle = lifecyle;
24
17
  this.api = getApi(context.apiBaseUrl);
25
18
  }
19
+ jwt = undefined;
20
+ jwtHash = "";
26
21
  withAuth(trustchain, memberCredentials, job, policy, ignorePermissionsChecks) {
27
22
  const hash = trustchain.rootId + " " + memberCredentials.pubkey;
28
23
  if (this.jwtHash !== hash) {
@@ -44,267 +39,237 @@ export class SDK {
44
39
  return job(jwt);
45
40
  }, this.jwt, () => this.auth(trustchain, memberCredentials), jwt => this.api.refreshAuth(jwt), policy);
46
41
  }
47
- initMemberCredentials() {
48
- return __awaiter(this, void 0, void 0, function* () {
49
- const kp = crypto.randomKeypair();
50
- return convertKeyPairToLiveCredentials(kp);
51
- });
42
+ async initMemberCredentials() {
43
+ const kp = crypto.randomKeypair();
44
+ return convertKeyPairToLiveCredentials(kp);
52
45
  }
53
- getOrCreateTrustchain(deviceId, memberCredentials, callbacks, topic, currentTrustchain) {
54
- return __awaiter(this, void 0, void 0, function* () {
55
- var _a;
56
- this.invalidateJwt();
57
- let type = TrustchainResultType.restored;
58
- const withJwt = job => this.hwDeviceProvider.withJwt(deviceId, job, "cache", callbacks);
59
- const withHw = job => this.hwDeviceProvider.withHw(deviceId, job, callbacks);
60
- let trustchains = yield withJwt(this.api.getTrustchains);
61
- (_a = callbacks === null || callbacks === void 0 ? void 0 : callbacks.onInitialResponse) === null || _a === void 0 ? void 0 : _a.call(callbacks, trustchains);
62
- if (currentTrustchain) {
63
- yield this.restoreTrustchain(currentTrustchain, memberCredentials).then(() => {
64
- throw Object.keys(trustchains).includes(currentTrustchain.rootId)
65
- ? new TrustchainAlreadyInitialized()
66
- : new TrustchainAlreadyInitializedWithOtherSeed();
67
- }, () => {
68
- // The user was ejected from the trustchain therefore we can continue
69
- });
70
- }
71
- if (Object.keys(trustchains).length === 0) {
72
- log("trustchain", "getOrCreateTrustchain: no trustchain yet, let's create one");
73
- type = TrustchainResultType.created;
74
- const streamTree = yield this.hwDeviceProvider.withHw(deviceId, hw => StreamTree.createNewTree(hw, { topic }));
75
- yield streamTree.getRoot().resolve(); // double checks the signatures are correct before sending to the backend
76
- const commandStream = CommandStreamEncoder.encode(streamTree.getRoot().blocks);
77
- yield withJwt(jwt => this.api.postSeed(jwt, crypto.to_hex(commandStream)));
78
- // deviceJwt have changed, proactively refresh it
79
- yield this.hwDeviceProvider.refreshJwt(deviceId, callbacks);
80
- trustchains = yield withJwt(this.api.getTrustchains);
81
- }
82
- // we find our trustchain root id
83
- let trustchainRootId;
84
- const trustchainRootPath = "m/";
85
- for (const [trustchainId, info] of Object.entries(trustchains)) {
86
- for (const path in info) {
87
- if (path === trustchainRootPath) {
88
- trustchainRootId = trustchainId;
89
- }
46
+ async getOrCreateTrustchain(deviceId, memberCredentials, callbacks, topic, currentTrustchain) {
47
+ this.invalidateJwt();
48
+ let type = TrustchainResultType.restored;
49
+ const withJwt = job => this.hwDeviceProvider.withJwt(deviceId, job, "cache", callbacks);
50
+ const withHw = job => this.hwDeviceProvider.withHw(deviceId, job, callbacks);
51
+ let trustchains = await withJwt(this.api.getTrustchains);
52
+ callbacks?.onInitialResponse?.(trustchains);
53
+ if (currentTrustchain) {
54
+ await this.restoreTrustchain(currentTrustchain, memberCredentials).then(() => {
55
+ throw Object.keys(trustchains).includes(currentTrustchain.rootId)
56
+ ? new TrustchainAlreadyInitialized()
57
+ : new TrustchainAlreadyInitializedWithOtherSeed();
58
+ }, () => {
59
+ // The user was ejected from the trustchain therefore we can continue
60
+ });
61
+ }
62
+ if (Object.keys(trustchains).length === 0) {
63
+ log("trustchain", "getOrCreateTrustchain: no trustchain yet, let's create one");
64
+ type = TrustchainResultType.created;
65
+ const streamTree = await this.hwDeviceProvider.withHw(deviceId, hw => StreamTree.createNewTree(hw, { topic }));
66
+ await streamTree.getRoot().resolve(); // double checks the signatures are correct before sending to the backend
67
+ const commandStream = CommandStreamEncoder.encode(streamTree.getRoot().blocks);
68
+ await withJwt(jwt => this.api.postSeed(jwt, crypto.to_hex(commandStream)));
69
+ // deviceJwt have changed, proactively refresh it
70
+ await this.hwDeviceProvider.refreshJwt(deviceId, callbacks);
71
+ trustchains = await withJwt(this.api.getTrustchains);
72
+ }
73
+ // we find our trustchain root id
74
+ let trustchainRootId;
75
+ const trustchainRootPath = "m/";
76
+ for (const [trustchainId, info] of Object.entries(trustchains)) {
77
+ for (const path in info) {
78
+ if (path === trustchainRootPath) {
79
+ trustchainRootId = trustchainId;
90
80
  }
91
81
  }
92
- invariant(trustchainRootId, "trustchainRootId should be defined");
93
- log("trustchain", "getOrCreateTrustchain rootId=" + trustchainRootId);
94
- // make a stream tree from all the trustchains associated to this root id
95
- let { streamTree } = yield withJwt(jwt => this.fetchTrustchain(jwt, trustchainRootId));
96
- const path = streamTree.getApplicationRootPath(this.context.applicationId);
97
- const child = streamTree.getChild(path);
98
- let shouldShare = true;
99
- if (child) {
100
- const resolved = yield child.resolve();
101
- const members = resolved.getMembers();
102
- shouldShare = !members.some(m => crypto.to_hex(m) === memberCredentials.pubkey); // not already a member
103
- }
104
- if (shouldShare) {
105
- if (type === TrustchainResultType.restored)
106
- type = TrustchainResultType.updated;
107
- streamTree = yield this.pushMember(streamTree, path, trustchainRootId, withJwt, withHw, {
108
- id: memberCredentials.pubkey,
109
- name: this.context.name,
110
- permissions: Permissions.OWNER,
111
- });
112
- }
113
- const walletSyncEncryptionKey = yield extractEncryptionKey(streamTree, path, memberCredentials);
114
- const trustchain = {
115
- rootId: trustchainRootId,
116
- walletSyncEncryptionKey,
117
- applicationPath: path,
118
- };
119
- return { type, trustchain };
120
- });
121
- }
122
- restoreTrustchain(trustchain, memberCredentials) {
123
- return __awaiter(this, void 0, void 0, function* () {
124
- const { streamTree, applicationRootPath } = yield this.withAuth(trustchain, memberCredentials, jwt => this.fetchTrustchainAndResolve(jwt, trustchain.rootId, this.context.applicationId), "refresh", true);
125
- const walletSyncEncryptionKey = yield extractEncryptionKey(streamTree, applicationRootPath, memberCredentials);
126
- return {
127
- rootId: trustchain.rootId,
128
- walletSyncEncryptionKey,
129
- applicationPath: applicationRootPath,
130
- };
131
- });
132
- }
133
- getMembers(trustchain, memberCredentials) {
134
- return __awaiter(this, void 0, void 0, function* () {
135
- const { resolved } = yield this.withAuth(trustchain, memberCredentials, jwt => this.fetchTrustchainAndResolve(jwt, trustchain.rootId, this.context.applicationId));
136
- const members = resolved.getMembersData();
137
- if (!members.some(m => m.id === memberCredentials.pubkey)) {
138
- throw new TrustchainEjected("Not a member of trustchain");
139
- }
140
- return members;
141
- });
142
- }
143
- removeMember(deviceId, trustchain, memberCredentials, member, callbacks) {
144
- return __awaiter(this, void 0, void 0, function* () {
145
- var _a;
146
- this.invalidateJwt();
147
- const withJwt = job => this.hwDeviceProvider.withJwt(deviceId, job, "cache", callbacks);
148
- const withHw = job => this.hwDeviceProvider.withHw(deviceId, job, callbacks);
149
- // invariant because the sdk does not support this case, and the UI should not allows it.
150
- invariant(memberCredentials.pubkey !== member.id, "removeMember must not be used to remove the current member.");
151
- const afterRotation = yield ((_a = this.lifecycle) === null || _a === void 0 ? void 0 : _a.onTrustchainRotation(this, trustchain, memberCredentials));
152
- const applicationId = this.context.applicationId;
153
- const trustchainId = trustchain.rootId;
154
- // eslint-disable-next-line prefer-const
155
- let { resolved, streamTree, applicationRootPath } = yield withJwt(jwt => this.fetchTrustchainAndResolve(jwt, trustchainId, applicationId));
156
- const members = resolved.getMembersData();
157
- const withoutMember = members.filter(m => m.id !== member.id);
158
- invariant(withoutMember.length < members.length, "member not found"); // invariant because the UI should not allow this case.
159
- const withoutMemberOrMe = withoutMember.filter(m => m.id !== memberCredentials.pubkey);
160
- const softwareDevice = getSoftwareDevice(memberCredentials);
161
- const newPath = streamTree.getApplicationRootPath(applicationId, 1);
162
- // We close the current trustchain with the hardware wallet in order to get a user confirmation of the action
163
- const sendCloseStreamToAPI = yield this.closeStream(streamTree, applicationRootPath, trustchainId, withJwt, withHw);
164
- // derive a new branch of the tree on the new path
165
- streamTree = yield this.pushMember(streamTree, newPath, trustchainId, withJwt, withHw, {
82
+ }
83
+ invariant(trustchainRootId, "trustchainRootId should be defined");
84
+ log("trustchain", "getOrCreateTrustchain rootId=" + trustchainRootId);
85
+ // make a stream tree from all the trustchains associated to this root id
86
+ let { streamTree } = await withJwt(jwt => this.fetchTrustchain(jwt, trustchainRootId));
87
+ const path = streamTree.getApplicationRootPath(this.context.applicationId);
88
+ const child = streamTree.getChild(path);
89
+ let shouldShare = true;
90
+ if (child) {
91
+ const resolved = await child.resolve();
92
+ const members = resolved.getMembers();
93
+ shouldShare = !members.some(m => crypto.to_hex(m) === memberCredentials.pubkey); // not already a member
94
+ }
95
+ if (shouldShare) {
96
+ if (type === TrustchainResultType.restored)
97
+ type = TrustchainResultType.updated;
98
+ streamTree = await this.pushMember(streamTree, path, trustchainRootId, withJwt, withHw, {
166
99
  id: memberCredentials.pubkey,
167
100
  name: this.context.name,
168
101
  permissions: Permissions.OWNER,
169
102
  });
170
- // add the remaining members
171
- const withSw = (job) => job(softwareDevice);
172
- for (const m of withoutMemberOrMe) {
173
- streamTree = yield this.pushMember(streamTree, newPath, trustchainId, withJwt, withSw, m);
174
- }
175
- const walletSyncEncryptionKey = yield extractEncryptionKey(streamTree, newPath, memberCredentials);
176
- // we send the close stream to the API only after the new stream is created in case user cancelled the process in the middle.
177
- yield sendCloseStreamToAPI();
178
- // deviceJwt have changed, proactively refresh it
179
- yield this.hwDeviceProvider.refreshJwt(deviceId, callbacks);
180
- const newTrustchain = {
181
- rootId: trustchainId,
182
- walletSyncEncryptionKey,
183
- applicationPath: newPath,
184
- };
185
- if (afterRotation)
186
- yield afterRotation(newTrustchain);
187
- // refresh the jwt with the new trustchain
188
- this.jwt = yield this.withAuth(newTrustchain, memberCredentials, jwt => Promise.resolve(jwt), "refresh");
189
- return newTrustchain;
190
- });
103
+ }
104
+ const walletSyncEncryptionKey = await extractEncryptionKey(streamTree, path, memberCredentials);
105
+ const trustchain = {
106
+ rootId: trustchainRootId,
107
+ walletSyncEncryptionKey,
108
+ applicationPath: path,
109
+ };
110
+ return { type, trustchain };
191
111
  }
192
- addMember(trustchain, memberCredentials, member) {
193
- return __awaiter(this, void 0, void 0, function* () {
194
- const withJwt = f => this.withAuth(trustchain, memberCredentials, f);
195
- const { streamTree, applicationRootPath } = yield withJwt(jwt => this.fetchTrustchainAndResolve(jwt, trustchain.rootId, this.context.applicationId));
196
- const softwareDevice = getSoftwareDevice(memberCredentials);
197
- const withSw = (job) => job(softwareDevice);
198
- yield this.pushMember(streamTree, applicationRootPath, trustchain.rootId, withJwt, withSw, member);
112
+ async restoreTrustchain(trustchain, memberCredentials) {
113
+ const { streamTree, applicationRootPath } = await this.withAuth(trustchain, memberCredentials, jwt => this.fetchTrustchainAndResolve(jwt, trustchain.rootId, this.context.applicationId), "refresh", true);
114
+ const walletSyncEncryptionKey = await extractEncryptionKey(streamTree, applicationRootPath, memberCredentials);
115
+ return {
116
+ rootId: trustchain.rootId,
117
+ walletSyncEncryptionKey,
118
+ applicationPath: applicationRootPath,
119
+ };
120
+ }
121
+ async getMembers(trustchain, memberCredentials) {
122
+ const { resolved } = await this.withAuth(trustchain, memberCredentials, jwt => this.fetchTrustchainAndResolve(jwt, trustchain.rootId, this.context.applicationId));
123
+ const members = resolved.getMembersData();
124
+ if (!members.some(m => m.id === memberCredentials.pubkey)) {
125
+ throw new TrustchainEjected("Not a member of trustchain");
126
+ }
127
+ return members;
128
+ }
129
+ async removeMember(deviceId, trustchain, memberCredentials, member, callbacks) {
130
+ this.invalidateJwt();
131
+ const withJwt = job => this.hwDeviceProvider.withJwt(deviceId, job, "cache", callbacks);
132
+ const withHw = job => this.hwDeviceProvider.withHw(deviceId, job, callbacks);
133
+ // invariant because the sdk does not support this case, and the UI should not allows it.
134
+ invariant(memberCredentials.pubkey !== member.id, "removeMember must not be used to remove the current member.");
135
+ const afterRotation = await this.lifecycle?.onTrustchainRotation(this, trustchain, memberCredentials);
136
+ const applicationId = this.context.applicationId;
137
+ const trustchainId = trustchain.rootId;
138
+ // eslint-disable-next-line prefer-const
139
+ let { resolved, streamTree, applicationRootPath } = await withJwt(jwt => this.fetchTrustchainAndResolve(jwt, trustchainId, applicationId));
140
+ const members = resolved.getMembersData();
141
+ const withoutMember = members.filter(m => m.id !== member.id);
142
+ invariant(withoutMember.length < members.length, "member not found"); // invariant because the UI should not allow this case.
143
+ const withoutMemberOrMe = withoutMember.filter(m => m.id !== memberCredentials.pubkey);
144
+ const softwareDevice = getSoftwareDevice(memberCredentials);
145
+ const newPath = streamTree.getApplicationRootPath(applicationId, 1);
146
+ // We close the current trustchain with the hardware wallet in order to get a user confirmation of the action
147
+ const sendCloseStreamToAPI = await this.closeStream(streamTree, applicationRootPath, trustchainId, withJwt, withHw);
148
+ // derive a new branch of the tree on the new path
149
+ streamTree = await this.pushMember(streamTree, newPath, trustchainId, withJwt, withHw, {
150
+ id: memberCredentials.pubkey,
151
+ name: this.context.name,
152
+ permissions: Permissions.OWNER,
199
153
  });
154
+ // add the remaining members
155
+ const withSw = (job) => job(softwareDevice);
156
+ for (const m of withoutMemberOrMe) {
157
+ streamTree = await this.pushMember(streamTree, newPath, trustchainId, withJwt, withSw, m);
158
+ }
159
+ const walletSyncEncryptionKey = await extractEncryptionKey(streamTree, newPath, memberCredentials);
160
+ // we send the close stream to the API only after the new stream is created in case user cancelled the process in the middle.
161
+ await sendCloseStreamToAPI();
162
+ // deviceJwt have changed, proactively refresh it
163
+ await this.hwDeviceProvider.refreshJwt(deviceId, callbacks);
164
+ const newTrustchain = {
165
+ rootId: trustchainId,
166
+ walletSyncEncryptionKey,
167
+ applicationPath: newPath,
168
+ };
169
+ if (afterRotation)
170
+ await afterRotation(newTrustchain);
171
+ // refresh the jwt with the new trustchain
172
+ this.jwt = await this.withAuth(newTrustchain, memberCredentials, jwt => Promise.resolve(jwt), "refresh");
173
+ return newTrustchain;
174
+ }
175
+ async addMember(trustchain, memberCredentials, member) {
176
+ const withJwt = f => this.withAuth(trustchain, memberCredentials, f);
177
+ const { streamTree, applicationRootPath } = await withJwt(jwt => this.fetchTrustchainAndResolve(jwt, trustchain.rootId, this.context.applicationId));
178
+ const softwareDevice = getSoftwareDevice(memberCredentials);
179
+ const withSw = (job) => job(softwareDevice);
180
+ await this.pushMember(streamTree, applicationRootPath, trustchain.rootId, withJwt, withSw, member);
200
181
  }
201
182
  invalidateJwt() {
202
183
  this.jwt = undefined;
203
184
  this.hwDeviceProvider.clearJwt();
204
185
  }
205
- destroyTrustchain(trustchain, memberCredentials) {
206
- return __awaiter(this, void 0, void 0, function* () {
207
- yield this.withAuth(trustchain, memberCredentials, jwt => this.api.deleteTrustchain(jwt, trustchain.rootId));
208
- this.invalidateJwt();
209
- });
186
+ async destroyTrustchain(trustchain, memberCredentials) {
187
+ await this.withAuth(trustchain, memberCredentials, jwt => this.api.deleteTrustchain(jwt, trustchain.rootId));
188
+ this.invalidateJwt();
210
189
  }
211
- encryptUserData(trustchain, input) {
212
- return __awaiter(this, void 0, void 0, function* () {
213
- const key = crypto.from_hex(trustchain.walletSyncEncryptionKey);
214
- const encrypted = yield crypto.encryptUserData(key, input);
215
- return encrypted;
216
- });
190
+ async encryptUserData(trustchain, input) {
191
+ const key = crypto.from_hex(trustchain.walletSyncEncryptionKey);
192
+ const encrypted = await crypto.encryptUserData(key, input);
193
+ return encrypted;
217
194
  }
218
- decryptUserData(trustchain, data) {
219
- return __awaiter(this, void 0, void 0, function* () {
220
- const key = crypto.from_hex(trustchain.walletSyncEncryptionKey);
221
- const decrypted = yield crypto.decryptUserData(key, data);
222
- return decrypted;
223
- });
195
+ async decryptUserData(trustchain, data) {
196
+ const key = crypto.from_hex(trustchain.walletSyncEncryptionKey);
197
+ const decrypted = await crypto.decryptUserData(key, data);
198
+ return decrypted;
224
199
  }
225
- fetchTrustchain(jwt, trustchainId) {
226
- return __awaiter(this, void 0, void 0, function* () {
227
- const trustchainData = yield this.api.getTrustchain(jwt, trustchainId);
228
- const streamTree = StreamTree.deserialize(trustchainData);
229
- return { streamTree };
230
- });
200
+ async fetchTrustchain(jwt, trustchainId) {
201
+ const trustchainData = await this.api.getTrustchain(jwt, trustchainId);
202
+ const streamTree = StreamTree.deserialize(trustchainData);
203
+ return { streamTree };
231
204
  }
232
- fetchTrustchainAndResolve(jwt, trustchainId, applicationId) {
233
- return __awaiter(this, void 0, void 0, function* () {
234
- const { streamTree } = yield this.fetchTrustchain(jwt, trustchainId);
235
- const applicationRootPath = streamTree.getApplicationRootPath(applicationId);
236
- const applicationNode = streamTree.getChild(applicationRootPath);
237
- invariant(applicationNode, "could not find the application stream.");
238
- const resolved = yield applicationNode.resolve();
239
- return { resolved, streamTree, applicationRootPath, applicationNode };
240
- });
205
+ async fetchTrustchainAndResolve(jwt, trustchainId, applicationId) {
206
+ const { streamTree } = await this.fetchTrustchain(jwt, trustchainId);
207
+ const applicationRootPath = streamTree.getApplicationRootPath(applicationId);
208
+ const applicationNode = streamTree.getChild(applicationRootPath);
209
+ invariant(applicationNode, "could not find the application stream.");
210
+ const resolved = await applicationNode.resolve();
211
+ return { resolved, streamTree, applicationRootPath, applicationNode };
241
212
  }
242
- auth(trustchain, memberCredentials) {
243
- return __awaiter(this, void 0, void 0, function* () {
244
- const challenge = yield this.api.getAuthenticationChallenge();
245
- const data = crypto.from_hex(challenge.tlv);
246
- const [parsed, _] = Challenge.fromBytes(data);
247
- const hash = yield crypto.hash(parsed.getUnsignedTLV());
248
- const keypair = convertLiveCredentialsToKeyPair(memberCredentials);
249
- const response = yield this.api
250
- .postChallengeResponse({
251
- challenge: challenge.json,
252
- signature: {
253
- credential: credentialForPubKey(memberCredentials.pubkey),
254
- signature: crypto.to_hex(yield crypto.sign(hash, keypair)),
255
- attestation: crypto.to_hex(liveAuthentication(trustchain.rootId)),
256
- },
257
- })
258
- .catch(e => {
259
- if (e instanceof LedgerAPI4xx &&
260
- (e.message.includes("Not a member of trustchain") ||
261
- e.message.includes("You are not member"))) {
262
- throw new TrustchainEjected(e.message);
263
- }
264
- throw e;
265
- });
266
- return response;
267
- });
268
- }
269
- pushMember(streamTree, path, trustchainId, withJwt, withDevice, member) {
270
- return __awaiter(this, void 0, void 0, function* () {
271
- const isMemberAlreadyInStreamTree = yield isMemberInStreamTree(streamTree, path, member);
272
- if (isMemberAlreadyInStreamTree) {
273
- return streamTree;
274
- }
275
- const isNewDerivation = !streamTree.getChild(path);
276
- streamTree = yield withDevice(device => streamTree.share(path, device, crypto.from_hex(member.id), member.name, member.permissions));
277
- const child = streamTree.getChild(path);
278
- invariant(child, "StreamTree.share failed to create the child stream.");
279
- yield child.resolve(); // double checks the signatures are correct before sending to the backend
280
- if (isNewDerivation) {
281
- const commandStream = CommandStreamEncoder.encode(child.blocks);
282
- yield withJwt(jwt => this.api.postDerivation(jwt, trustchainId, crypto.to_hex(commandStream)));
283
- }
284
- else {
285
- const commandStream = CommandStreamEncoder.encode([child.blocks[child.blocks.length - 1]]);
286
- const request = {
287
- path,
288
- blocks: [crypto.to_hex(commandStream)],
289
- };
290
- yield withJwt(jwt => this.api.putCommands(jwt, trustchainId, request));
213
+ async auth(trustchain, memberCredentials) {
214
+ const challenge = await this.api.getAuthenticationChallenge();
215
+ const data = crypto.from_hex(challenge.tlv);
216
+ const [parsed, _] = Challenge.fromBytes(data);
217
+ const hash = await crypto.hash(parsed.getUnsignedTLV());
218
+ const keypair = convertLiveCredentialsToKeyPair(memberCredentials);
219
+ const response = await this.api
220
+ .postChallengeResponse({
221
+ challenge: challenge.json,
222
+ signature: {
223
+ credential: credentialForPubKey(memberCredentials.pubkey),
224
+ signature: crypto.to_hex(await crypto.sign(hash, keypair)),
225
+ attestation: crypto.to_hex(liveAuthentication(trustchain.rootId)),
226
+ },
227
+ })
228
+ .catch(e => {
229
+ if (e instanceof LedgerAPI4xx &&
230
+ (e.message.includes("Not a member of trustchain") ||
231
+ e.message.includes("You are not member"))) {
232
+ throw new TrustchainEjected(e.message);
291
233
  }
292
- return streamTree;
234
+ throw e;
293
235
  });
236
+ return response;
294
237
  }
295
- closeStream(streamTree, path, trustchainId, withJwt, withDevice) {
296
- return __awaiter(this, void 0, void 0, function* () {
297
- streamTree = yield withDevice(device => streamTree.close(path, device));
298
- const child = streamTree.getChild(path);
299
- invariant(child, "StreamTree.close failed to create the child stream.");
300
- yield child.resolve(); // double checks the signatures are correct before sending to the backend
238
+ async pushMember(streamTree, path, trustchainId, withJwt, withDevice, member) {
239
+ const isMemberAlreadyInStreamTree = await isMemberInStreamTree(streamTree, path, member);
240
+ if (isMemberAlreadyInStreamTree) {
241
+ return streamTree;
242
+ }
243
+ const isNewDerivation = !streamTree.getChild(path);
244
+ streamTree = await withDevice(device => streamTree.share(path, device, crypto.from_hex(member.id), member.name, member.permissions));
245
+ const child = streamTree.getChild(path);
246
+ invariant(child, "StreamTree.share failed to create the child stream.");
247
+ await child.resolve(); // double checks the signatures are correct before sending to the backend
248
+ if (isNewDerivation) {
249
+ const commandStream = CommandStreamEncoder.encode(child.blocks);
250
+ await withJwt(jwt => this.api.postDerivation(jwt, trustchainId, crypto.to_hex(commandStream)));
251
+ }
252
+ else {
301
253
  const commandStream = CommandStreamEncoder.encode([child.blocks[child.blocks.length - 1]]);
302
254
  const request = {
303
255
  path,
304
256
  blocks: [crypto.to_hex(commandStream)],
305
257
  };
306
- return () => withJwt(jwt => this.api.putCommands(jwt, trustchainId, request));
307
- });
258
+ await withJwt(jwt => this.api.putCommands(jwt, trustchainId, request));
259
+ }
260
+ return streamTree;
261
+ }
262
+ async closeStream(streamTree, path, trustchainId, withJwt, withDevice) {
263
+ streamTree = await withDevice(device => streamTree.close(path, device));
264
+ const child = streamTree.getChild(path);
265
+ invariant(child, "StreamTree.close failed to create the child stream.");
266
+ await child.resolve(); // double checks the signatures are correct before sending to the backend
267
+ const commandStream = CommandStreamEncoder.encode([child.blocks[child.blocks.length - 1]]);
268
+ const request = {
269
+ path,
270
+ blocks: [crypto.to_hex(commandStream)],
271
+ };
272
+ return () => withJwt(jwt => this.api.putCommands(jwt, trustchainId, request));
308
273
  }
309
274
  }
310
275
  export function convertKeyPairToLiveCredentials(keyPair) {
@@ -323,22 +288,20 @@ function getSoftwareDevice(memberCredentials) {
323
288
  const kp = convertLiveCredentialsToKeyPair(memberCredentials);
324
289
  return new SoftwareDevice(kp);
325
290
  }
326
- function extractEncryptionKey(streamTree, path, memberCredentials) {
327
- return __awaiter(this, void 0, void 0, function* () {
328
- const softwareDevice = getSoftwareDevice(memberCredentials);
329
- const pathNumbers = DerivationPath.toIndexArray(path);
330
- try {
331
- const key = yield softwareDevice.readKey(streamTree, pathNumbers);
332
- // private key is in the first 32 bytes
333
- return crypto.to_hex(key.slice(0, 32));
334
- }
335
- catch (e) {
336
- if (e instanceof Error) {
337
- throw new TrustchainEjected(e.message);
338
- }
339
- throw e;
291
+ async function extractEncryptionKey(streamTree, path, memberCredentials) {
292
+ const softwareDevice = getSoftwareDevice(memberCredentials);
293
+ const pathNumbers = DerivationPath.toIndexArray(path);
294
+ try {
295
+ const key = await softwareDevice.readKey(streamTree, pathNumbers);
296
+ // private key is in the first 32 bytes
297
+ return crypto.to_hex(key.slice(0, 32));
298
+ }
299
+ catch (e) {
300
+ if (e instanceof Error) {
301
+ throw new TrustchainEjected(e.message);
340
302
  }
341
- });
303
+ throw e;
304
+ }
342
305
  }
343
306
  // spec https://ledgerhq.atlassian.net/wiki/spaces/TA/pages/4335960138/ARCH+LedgerLive+Auth+specifications
344
307
  function liveAuthentication(rootId) {
@@ -357,15 +320,13 @@ function invariant(condition, message) {
357
320
  throw new Error(message);
358
321
  }
359
322
  }
360
- function isMemberInStreamTree(streamTree, path, member) {
361
- return __awaiter(this, void 0, void 0, function* () {
362
- const child = streamTree.getChild(path);
363
- if (!child) {
364
- return false;
365
- }
366
- const resolved = yield child.resolve();
367
- const members = resolved.getMembersData();
368
- return members.some(m => m.id === member.id);
369
- });
323
+ async function isMemberInStreamTree(streamTree, path, member) {
324
+ const child = streamTree.getChild(path);
325
+ if (!child) {
326
+ return false;
327
+ }
328
+ const resolved = await child.resolve();
329
+ const members = resolved.getMembersData();
330
+ return members.some(m => m.id === member.id);
370
331
  }
371
332
  //# sourceMappingURL=sdk.js.map