@ledgerhq/revault-sdk 0.12.0
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/LICENSE.md +202 -0
- package/README.md +18 -0
- package/lib/bake.cjs +812 -0
- package/lib/bake.cjs.map +1 -0
- package/lib/bake.d.cts +2659 -0
- package/lib/bake.d.ts +2659 -0
- package/lib/bake.js +812 -0
- package/lib/bake.js.map +1 -0
- package/lib/chunk-DPHEFR6E.js +493 -0
- package/lib/chunk-DPHEFR6E.js.map +1 -0
- package/lib/chunk-QOP5LA3E.cjs +35 -0
- package/lib/chunk-QOP5LA3E.cjs.map +1 -0
- package/lib/chunk-VCAQTGQE.cjs +493 -0
- package/lib/chunk-VCAQTGQE.cjs.map +1 -0
- package/lib/chunk-VHZJP75X.js +35 -0
- package/lib/chunk-VHZJP75X.js.map +1 -0
- package/lib/device.cjs +13 -0
- package/lib/device.cjs.map +1 -0
- package/lib/device.d.cts +50 -0
- package/lib/device.d.ts +50 -0
- package/lib/device.js +13 -0
- package/lib/device.js.map +1 -0
- package/lib/engine.cjs +704 -0
- package/lib/engine.cjs.map +1 -0
- package/lib/engine.d.cts +18 -0
- package/lib/engine.d.ts +18 -0
- package/lib/engine.js +704 -0
- package/lib/engine.js.map +1 -0
- package/lib/index.cjs +1 -0
- package/lib/index.cjs.map +1 -0
- package/lib/index.d.cts +13 -0
- package/lib/index.d.ts +13 -0
- package/lib/index.js +1 -0
- package/lib/index.js.map +1 -0
- package/lib/onboarding.cjs +160 -0
- package/lib/onboarding.cjs.map +1 -0
- package/lib/onboarding.d.cts +1735 -0
- package/lib/onboarding.d.ts +1735 -0
- package/lib/onboarding.js +160 -0
- package/lib/onboarding.js.map +1 -0
- package/lib/types-BYNH6EdK.d.cts +199 -0
- package/lib/types-CsvE9Mlb.d.cts +159 -0
- package/lib/types-CsvE9Mlb.d.ts +159 -0
- package/lib/types-DHZzeq9X.d.ts +199 -0
- package/package.json +75 -0
package/lib/engine.cjs
ADDED
|
@@ -0,0 +1,704 @@
|
|
|
1
|
+
"use strict";Object.defineProperty(exports, "__esModule", {value: true}); function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; } function _nullishCoalesce(lhs, rhsFn) { if (lhs != null) { return lhs; } else { return rhsFn(); } } function _optionalChain(ops) { let lastAccessLHS = undefined; let value = ops[0]; let i = 1; while (i < ops.length) { const op = ops[i]; const fn = ops[i + 1]; i += 2; if ((op === 'optionalAccess' || op === 'optionalCall') && value == null) { return undefined; } if (op === 'access' || op === 'optionalAccess') { lastAccessLHS = value; value = fn(value); } else if (op === 'call' || op === 'optionalCall') { value = fn((...args) => value.call(lastAccessLHS, ...args)); lastAccessLHS = undefined; } } return value; }
|
|
2
|
+
|
|
3
|
+
var _chunkQOP5LA3Ecjs = require('./chunk-QOP5LA3E.cjs');
|
|
4
|
+
|
|
5
|
+
|
|
6
|
+
|
|
7
|
+
|
|
8
|
+
|
|
9
|
+
|
|
10
|
+
|
|
11
|
+
|
|
12
|
+
|
|
13
|
+
|
|
14
|
+
|
|
15
|
+
|
|
16
|
+
var _chunkVCAQTGQEcjs = require('./chunk-VCAQTGQE.cjs');
|
|
17
|
+
|
|
18
|
+
// src/engine/index.ts
|
|
19
|
+
var _invariant = require('invariant'); var _invariant2 = _interopRequireDefault(_invariant);
|
|
20
|
+
|
|
21
|
+
// src/device/real-device.ts
|
|
22
|
+
var _errors = require('@ledgerhq/errors');
|
|
23
|
+
|
|
24
|
+
var _rxjs = require('rxjs');
|
|
25
|
+
var MAX_CHUNK_LENGTH = 250;
|
|
26
|
+
var FIXME_NOT_IMPLEMENTED = (fnName) => async () => {
|
|
27
|
+
throw new Error(`Not implemented: ${fnName}`);
|
|
28
|
+
};
|
|
29
|
+
var getPathFromPathString = (pathString) => {
|
|
30
|
+
const parts = pathString.split("'/").map((part) => parseInt(part, 10));
|
|
31
|
+
return parts.map((part) => (part | 2147483648) >>> 0);
|
|
32
|
+
};
|
|
33
|
+
var splitChunks = (chunk, buffer) => {
|
|
34
|
+
const chunks = [];
|
|
35
|
+
for (let i = 0, size = chunk; i < buffer.length; i += size, size = chunk) {
|
|
36
|
+
chunks.push(buffer.slice(i, i + size));
|
|
37
|
+
}
|
|
38
|
+
return chunks;
|
|
39
|
+
};
|
|
40
|
+
var removeStatus = (result) => result.slice(0, result.length - _chunkVCAQTGQEcjs.STATUS_LENGTH);
|
|
41
|
+
var sendByChunk = async (transport, command, data, chunkSize = MAX_CHUNK_LENGTH) => {
|
|
42
|
+
const chunks = splitChunks(chunkSize, data);
|
|
43
|
+
let response = Buffer.from([]);
|
|
44
|
+
for (let i = 0; i < chunks.length; i++) {
|
|
45
|
+
const chunk = chunks[i];
|
|
46
|
+
const apdu = [...command];
|
|
47
|
+
apdu[2] = i && 128;
|
|
48
|
+
response = await transport.send(apdu[0], apdu[1], apdu[2], apdu[3], chunk, [
|
|
49
|
+
36864,
|
|
50
|
+
..._chunkVCAQTGQEcjs.PAGINATED_STATUS
|
|
51
|
+
]);
|
|
52
|
+
}
|
|
53
|
+
return response;
|
|
54
|
+
};
|
|
55
|
+
var buildAttestation = (params) => {
|
|
56
|
+
const sigBuffer = Buffer.from(params.handshakeAttestation.signature, "base64");
|
|
57
|
+
const sigLengthBuffer = Buffer.alloc(1);
|
|
58
|
+
sigLengthBuffer.writeUIntBE(sigBuffer.length, 0, 1);
|
|
59
|
+
const certBuffer = Buffer.from(params.handshakeAttestation.certificate, "base64");
|
|
60
|
+
const certLengthBuffer = Buffer.alloc(1);
|
|
61
|
+
certLengthBuffer.writeUIntBE(certBuffer.length, 0, 1);
|
|
62
|
+
const pubBuffer = Buffer.from(params.handshakeAttestation.attestationPub, "base64");
|
|
63
|
+
const certChainData = Buffer.concat([
|
|
64
|
+
sigLengthBuffer,
|
|
65
|
+
sigBuffer,
|
|
66
|
+
pubBuffer,
|
|
67
|
+
certLengthBuffer,
|
|
68
|
+
certBuffer
|
|
69
|
+
]);
|
|
70
|
+
const cliMsgBuffer = Buffer.from(params.handshake, "hex");
|
|
71
|
+
const cliMsgLengthBuffer = Buffer.alloc(1);
|
|
72
|
+
cliMsgLengthBuffer.writeUIntBE(cliMsgBuffer.length, 0, 1);
|
|
73
|
+
const pidBuffer = Buffer.from(params.partitionId, "hex");
|
|
74
|
+
const pidLengthBuffer = Buffer.alloc(1);
|
|
75
|
+
pidLengthBuffer.writeUIntBE(pidBuffer.length, 0, 1);
|
|
76
|
+
const certChainDataLengthBuff = Buffer.alloc(2);
|
|
77
|
+
certChainDataLengthBuff.writeUInt16BE(certChainData.length, 0);
|
|
78
|
+
const data = Buffer.concat([
|
|
79
|
+
cliMsgLengthBuffer,
|
|
80
|
+
cliMsgBuffer,
|
|
81
|
+
certChainDataLengthBuff,
|
|
82
|
+
certChainData,
|
|
83
|
+
pidLengthBuffer,
|
|
84
|
+
pidBuffer
|
|
85
|
+
]);
|
|
86
|
+
const totalLengthBuffer = Buffer.alloc(2);
|
|
87
|
+
totalLengthBuffer.writeUInt16BE(data.length, 0);
|
|
88
|
+
const toSend = Buffer.concat([totalLengthBuffer, data]);
|
|
89
|
+
return toSend;
|
|
90
|
+
};
|
|
91
|
+
var genericRetryOnError = (err) => {
|
|
92
|
+
if (err instanceof _errors.LockedDeviceError) return true;
|
|
93
|
+
if (_chunkVCAQTGQEcjs.isTransportStatusError.call(void 0, err) && err.statusCode === 27913) return true;
|
|
94
|
+
if (err instanceof _errors.DisconnectedDevice) return true;
|
|
95
|
+
return false;
|
|
96
|
+
};
|
|
97
|
+
function createRealDevice(options, logger) {
|
|
98
|
+
const { transportId } = options;
|
|
99
|
+
async function run(job, retryOnError = genericRetryOnError) {
|
|
100
|
+
return _rxjs.lastValueFrom.call(void 0,
|
|
101
|
+
_chunkVCAQTGQEcjs.withDevicePolling.call(void 0, transportId)((transport) => _rxjs.from.call(void 0, job(transport)), retryOnError)
|
|
102
|
+
);
|
|
103
|
+
}
|
|
104
|
+
const noRetry = () => false;
|
|
105
|
+
const poll = async () => {
|
|
106
|
+
await run(
|
|
107
|
+
// eslint-disable-next-line @typescript-eslint/no-empty-function
|
|
108
|
+
async (_transport) => {
|
|
109
|
+
},
|
|
110
|
+
() => true
|
|
111
|
+
);
|
|
112
|
+
try {
|
|
113
|
+
await getPublicKey(_chunkVCAQTGQEcjs.PATHS.U2F, { secp256k1: true, retryOnError: noRetry });
|
|
114
|
+
return { isAppOpened: true };
|
|
115
|
+
} catch (err) {
|
|
116
|
+
if (_chunkVCAQTGQEcjs.isTransportStatusError.call(void 0, err) && genericRetryOnError(err)) {
|
|
117
|
+
return { isAppOpened: false };
|
|
118
|
+
}
|
|
119
|
+
throw err;
|
|
120
|
+
}
|
|
121
|
+
};
|
|
122
|
+
const pollApp = async (appName) => {
|
|
123
|
+
const res = await run(
|
|
124
|
+
(transport) => transport.send(224, 216, 0, 0, Buffer.from(appName, "utf8"))
|
|
125
|
+
);
|
|
126
|
+
await new Promise((r) => setTimeout(r, 1e3));
|
|
127
|
+
return res.toString("hex");
|
|
128
|
+
};
|
|
129
|
+
const getPublicKey = async (pathString, { secp256k1, retryOnError }) => {
|
|
130
|
+
logger.info(`[device] getPublicKey (${pathString})`);
|
|
131
|
+
const path = getPathFromPathString(pathString);
|
|
132
|
+
const data = Buffer.concat([
|
|
133
|
+
Buffer.from([path.length]),
|
|
134
|
+
...path.map((derivation) => {
|
|
135
|
+
const buf = Buffer.alloc(4);
|
|
136
|
+
buf.writeUInt32BE(derivation, 0);
|
|
137
|
+
return buf;
|
|
138
|
+
})
|
|
139
|
+
]);
|
|
140
|
+
const curve = secp256k1 ? 1 : 2;
|
|
141
|
+
const response = await run(
|
|
142
|
+
(transport) => transport.send(224, 64, curve, 0, data),
|
|
143
|
+
_nullishCoalesce(retryOnError, () => ( genericRetryOnError))
|
|
144
|
+
);
|
|
145
|
+
const pubKeyLength = response.readInt8(0);
|
|
146
|
+
const pubKey = response.slice(1, pubKeyLength + 1).toString("hex").toUpperCase();
|
|
147
|
+
const signature = response.slice(pubKeyLength + 1, response.length - _chunkVCAQTGQEcjs.STATUS_LENGTH).toString("base64");
|
|
148
|
+
return { pubKey, signature };
|
|
149
|
+
};
|
|
150
|
+
const device = {
|
|
151
|
+
authenticate: async ({ challenge: { challenge, name, role, keyHandle }, workspaceName }) => {
|
|
152
|
+
logger.info(`[device] Authenticate`);
|
|
153
|
+
_invariant2.default.call(void 0, role !== "READ_ONLY_API_KEY", "Invalid role for authenticate: READ_ONLY_API_KEY");
|
|
154
|
+
const applicationBuffer = Buffer.from(_chunkVCAQTGQEcjs.APPID_VAULT_ADMINISTRATOR, "hex");
|
|
155
|
+
const nameBuffer = Buffer.from(name);
|
|
156
|
+
const workspaceBuffer = Buffer.from(workspaceName);
|
|
157
|
+
const keyHandleData = Buffer.concat([
|
|
158
|
+
Buffer.from(_chunkVCAQTGQEcjs.STR_ROLES[role], "hex"),
|
|
159
|
+
Buffer.from([nameBuffer.length]),
|
|
160
|
+
nameBuffer,
|
|
161
|
+
Buffer.from([workspaceBuffer.length]),
|
|
162
|
+
workspaceBuffer
|
|
163
|
+
]);
|
|
164
|
+
const keyHandleDataLength = Buffer.alloc(2);
|
|
165
|
+
keyHandleDataLength.writeUInt16BE(keyHandleData.length, 0);
|
|
166
|
+
const data = Buffer.concat([
|
|
167
|
+
Buffer.from(challenge, "base64"),
|
|
168
|
+
applicationBuffer,
|
|
169
|
+
Buffer.from([keyHandle.length]),
|
|
170
|
+
Buffer.from(keyHandle, "hex"),
|
|
171
|
+
keyHandleDataLength,
|
|
172
|
+
keyHandleData
|
|
173
|
+
]);
|
|
174
|
+
const authentication = await run(
|
|
175
|
+
(transport) => sendByChunk(transport, [224, 2, 0, 0], data)
|
|
176
|
+
);
|
|
177
|
+
return removeStatus(authentication).toString("hex");
|
|
178
|
+
},
|
|
179
|
+
finalizePairingHandshake: FIXME_NOT_IMPLEMENTED("finalizePairingHandshake"),
|
|
180
|
+
generateSeedFragment: FIXME_NOT_IMPLEMENTED("generateSeedFragment"),
|
|
181
|
+
generateWrappingKeyFragment: FIXME_NOT_IMPLEMENTED("generateWrappingKeyFragment"),
|
|
182
|
+
getAttestation: FIXME_NOT_IMPLEMENTED("getAttestation"),
|
|
183
|
+
getConfidentialityKey: async () => {
|
|
184
|
+
logger.info(`[device] getConfidentialityKey`);
|
|
185
|
+
const bufWithStatus = await run((transport) => transport.send(224, 77, 0, 0));
|
|
186
|
+
const buf = removeStatus(bufWithStatus);
|
|
187
|
+
const keyLength = buf[0];
|
|
188
|
+
const key = buf.slice(1, 1 + keyLength);
|
|
189
|
+
const sig = buf.slice(1 + keyLength + 1);
|
|
190
|
+
return {
|
|
191
|
+
confidentialityKeyCurve25519: key.toString("hex"),
|
|
192
|
+
confidentialityKeySignature: sig.toString("hex")
|
|
193
|
+
};
|
|
194
|
+
},
|
|
195
|
+
getConfidentialityPubKey: () => getPublicKey(_chunkVCAQTGQEcjs.PATHS.CONFIDENTIALITY, { secp256k1: true }),
|
|
196
|
+
getDeviceUserId: FIXME_NOT_IMPLEMENTED("getDeviceUserId"),
|
|
197
|
+
getU2FPubKey: () => getPublicKey(_chunkVCAQTGQEcjs.PATHS.U2F, { secp256k1: false }),
|
|
198
|
+
getValidationPubKey: () => getPublicKey(_chunkVCAQTGQEcjs.PATHS.VALIDATION, { secp256k1: true }),
|
|
199
|
+
hasPairing: async () => {
|
|
200
|
+
logger.info(`[device] hasPairing`);
|
|
201
|
+
const apdu = [224, 81, 0, 0, 181];
|
|
202
|
+
const res = await run((transport) => transport.exchange(Buffer.from(apdu)));
|
|
203
|
+
const hex = Buffer.from(res).toString("hex");
|
|
204
|
+
return hex !== "6f45" && hex !== "6a87";
|
|
205
|
+
},
|
|
206
|
+
initPairingHandshake: FIXME_NOT_IMPLEMENTED("initPairingHandshake"),
|
|
207
|
+
openSession: FIXME_NOT_IMPLEMENTED("openSession"),
|
|
208
|
+
register: FIXME_NOT_IMPLEMENTED("register"),
|
|
209
|
+
registerData: FIXME_NOT_IMPLEMENTED("registerData"),
|
|
210
|
+
setPairing: async ({ pairing }) => {
|
|
211
|
+
logger.info(`[device] setPairing`);
|
|
212
|
+
const psdPayload = Buffer.from(pairing.blob, "base64");
|
|
213
|
+
const length = Buffer.alloc(2);
|
|
214
|
+
length.writeUInt16BE(psdPayload.length, 0);
|
|
215
|
+
const final = Buffer.concat([length, psdPayload]);
|
|
216
|
+
await run((transport) => sendByChunk(transport, [224, 78, 0, 0], final));
|
|
217
|
+
},
|
|
218
|
+
startKKPatternAsResponder: FIXME_NOT_IMPLEMENTED("startKKPatternAsResponder"),
|
|
219
|
+
startKPatternAsResponder: async (params) => {
|
|
220
|
+
logger.info(`[device] startKPatternAsResponder`);
|
|
221
|
+
const data = buildAttestation(params);
|
|
222
|
+
await run(
|
|
223
|
+
(transport) => sendByChunk(transport, [224, 73, 0, _chunkVCAQTGQEcjs.SCRIPT_IDS.ACCOUNT_MANAGER_SESSION], data)
|
|
224
|
+
);
|
|
225
|
+
},
|
|
226
|
+
validateVaultOperation: async (params) => {
|
|
227
|
+
logger.info(`[device] validateVaultOperation`);
|
|
228
|
+
const path = getPathFromPathString(_chunkVCAQTGQEcjs.PATHS.VALIDATION);
|
|
229
|
+
const paths = Buffer.concat([
|
|
230
|
+
Buffer.from([path.length]),
|
|
231
|
+
...path.map((derivation) => {
|
|
232
|
+
const buf = Buffer.alloc(4);
|
|
233
|
+
buf.writeUInt32BE(derivation, 0);
|
|
234
|
+
return buf;
|
|
235
|
+
})
|
|
236
|
+
]);
|
|
237
|
+
let nextActionId = 1;
|
|
238
|
+
let finalResponse;
|
|
239
|
+
while (!finalResponse) {
|
|
240
|
+
const screen = Buffer.from(params.actions[nextActionId - 1], "base64");
|
|
241
|
+
const length = Buffer.alloc(2);
|
|
242
|
+
length.writeUInt16BE(screen.length, 0);
|
|
243
|
+
const data = Buffer.concat([paths, length, screen]);
|
|
244
|
+
const response = await run(
|
|
245
|
+
(transport) => sendByChunk(transport, [224, 69, 0, 0], data)
|
|
246
|
+
);
|
|
247
|
+
const responseType = response.readInt8(0);
|
|
248
|
+
let responseStatus = response.readUInt16BE(response.length - 2);
|
|
249
|
+
if (responseType === _chunkVCAQTGQEcjs.STREAMING_NEXT_ACTION) {
|
|
250
|
+
nextActionId = response.readUIntBE(1, 2);
|
|
251
|
+
} else if (responseType === _chunkVCAQTGQEcjs.STREAMING_RESPONSE) {
|
|
252
|
+
finalResponse = response.slice(3, response.length - 2);
|
|
253
|
+
while (responseStatus !== 36864) {
|
|
254
|
+
const resp = await run((transport) => transport.send(0, 192, 0, 0));
|
|
255
|
+
responseStatus = resp.readUInt16BE(resp.length - 2);
|
|
256
|
+
finalResponse = Buffer.concat([finalResponse, removeStatus(resp)]);
|
|
257
|
+
}
|
|
258
|
+
} else {
|
|
259
|
+
throw Error(`${responseType}`);
|
|
260
|
+
}
|
|
261
|
+
}
|
|
262
|
+
return finalResponse.toString("base64");
|
|
263
|
+
},
|
|
264
|
+
sendAPDU: async (apduCommand) => {
|
|
265
|
+
const res = await run((transport) => transport.exchange(Buffer.from(apduCommand, "hex")));
|
|
266
|
+
return Buffer.from(res).toString("hex");
|
|
267
|
+
},
|
|
268
|
+
poll,
|
|
269
|
+
pollApp
|
|
270
|
+
};
|
|
271
|
+
return device;
|
|
272
|
+
}
|
|
273
|
+
|
|
274
|
+
// src/trpc.ts
|
|
275
|
+
var _client = require('@trpc/client');
|
|
276
|
+
var _superjson = require('superjson'); var _superjson2 = _interopRequireDefault(_superjson);
|
|
277
|
+
var createClient = (options) => {
|
|
278
|
+
const trpc = _client.createTRPCClient.call(void 0, {
|
|
279
|
+
links: [
|
|
280
|
+
_client.httpBatchLink.call(void 0, {
|
|
281
|
+
url: `${options.baseUrl}/trpc`,
|
|
282
|
+
transformer: _superjson2.default,
|
|
283
|
+
headers() {
|
|
284
|
+
return {
|
|
285
|
+
...options.debugAuthToken ? { "x-revault-debug-auth-token": options.debugAuthToken } : {},
|
|
286
|
+
...options.rootAuthToken ? { "x-revault-root-auth-token": options.rootAuthToken } : {},
|
|
287
|
+
...options.psdAuth ? { Authorization: `PsdAuth ${options.psdAuth}` } : {}
|
|
288
|
+
};
|
|
289
|
+
}
|
|
290
|
+
})
|
|
291
|
+
]
|
|
292
|
+
});
|
|
293
|
+
return trpc;
|
|
294
|
+
};
|
|
295
|
+
|
|
296
|
+
// src/engine/index.ts
|
|
297
|
+
async function genericRegister({
|
|
298
|
+
device,
|
|
299
|
+
name,
|
|
300
|
+
role,
|
|
301
|
+
getChallenge,
|
|
302
|
+
submitChallenge
|
|
303
|
+
}) {
|
|
304
|
+
const [attestation, u2fPubKey, confidentialityKey] = await Promise.all([
|
|
305
|
+
device.getAttestation(),
|
|
306
|
+
device.getU2FPubKey(),
|
|
307
|
+
device.getConfidentialityPubKey()
|
|
308
|
+
]);
|
|
309
|
+
const ephemeralPubKey = await device.initPairingHandshake();
|
|
310
|
+
const deviceData = {
|
|
311
|
+
name,
|
|
312
|
+
pubKey: u2fPubKey.pubKey,
|
|
313
|
+
psdModel: "STAX",
|
|
314
|
+
confidentialityKey: confidentialityKey.pubKey,
|
|
315
|
+
psdEphemeralKey: ephemeralPubKey.pubKey,
|
|
316
|
+
psdEphemeralKeyAttestation: {
|
|
317
|
+
...attestation.attestation,
|
|
318
|
+
signature: ephemeralPubKey.signature
|
|
319
|
+
}
|
|
320
|
+
};
|
|
321
|
+
const challenge = await getChallenge({ pubKey: u2fPubKey.pubKey, deviceData });
|
|
322
|
+
const pairingPayload = await device.finalizePairingHandshake({
|
|
323
|
+
handshake: challenge.handshake,
|
|
324
|
+
ciphertext: challenge.ciphertext
|
|
325
|
+
});
|
|
326
|
+
const register = await device.register({
|
|
327
|
+
challenge: challenge.challenge,
|
|
328
|
+
u2fRegisterData: challenge.u2fRegisterData,
|
|
329
|
+
name,
|
|
330
|
+
role
|
|
331
|
+
});
|
|
332
|
+
const validationPubKey = await device.getValidationPubKey();
|
|
333
|
+
const registerData = await device.registerData({ challenge: challenge.challenge });
|
|
334
|
+
const attestationOffset = 67 + register.u2fRegister.readInt8(66);
|
|
335
|
+
const u2fRegister = Buffer.concat([
|
|
336
|
+
register.u2fRegister.slice(0, attestationOffset),
|
|
337
|
+
Buffer.from([attestation.buffer.length]),
|
|
338
|
+
attestation.buffer,
|
|
339
|
+
register.u2fRegister.slice(attestationOffset)
|
|
340
|
+
]).toString("hex");
|
|
341
|
+
const challengeResponse = {
|
|
342
|
+
registerData,
|
|
343
|
+
certificate: {
|
|
344
|
+
...attestation.attestation,
|
|
345
|
+
signature: validationPubKey.signature
|
|
346
|
+
},
|
|
347
|
+
u2fRegister,
|
|
348
|
+
u2fKeyHandle: register.keyHandle.toString("hex"),
|
|
349
|
+
validationKey: validationPubKey.pubKey,
|
|
350
|
+
pairingPayload
|
|
351
|
+
};
|
|
352
|
+
return submitChallenge({ pubKey: u2fPubKey.pubKey, challengeResponse });
|
|
353
|
+
}
|
|
354
|
+
function createEngine(options, logger) {
|
|
355
|
+
const clientOptions = {
|
|
356
|
+
baseUrl: options.baseUrl
|
|
357
|
+
};
|
|
358
|
+
const client = createClient(clientOptions);
|
|
359
|
+
const apiDevice = _chunkVCAQTGQEcjs.createApiDevice.call(void 0, options, logger);
|
|
360
|
+
const base = {
|
|
361
|
+
client,
|
|
362
|
+
createClient: (overrides) => createClient({ ...clientOptions, ...overrides })
|
|
363
|
+
};
|
|
364
|
+
const withDeviceIndex = function(deviceIndex) {
|
|
365
|
+
const device = apiDevice.with(deviceIndex);
|
|
366
|
+
const withPsd = { device };
|
|
367
|
+
return decorateEngine({ ...this, ...withPsd });
|
|
368
|
+
};
|
|
369
|
+
const withTransportId = function(transportId) {
|
|
370
|
+
const device = createRealDevice({ transportId }, logger);
|
|
371
|
+
const withPsd = { device };
|
|
372
|
+
return decorateEngine({ ...this, ...withPsd });
|
|
373
|
+
};
|
|
374
|
+
const withApiUser = function() {
|
|
375
|
+
const withApiUser2 = { __isApiUser: true };
|
|
376
|
+
return decorateEngine({ ...this, ...withApiUser2 });
|
|
377
|
+
};
|
|
378
|
+
const withWorkspace = function(workspaceName) {
|
|
379
|
+
const withWorkspace2 = { __workspaceName: workspaceName };
|
|
380
|
+
return decorateEngine({ ...this, ...withWorkspace2 });
|
|
381
|
+
};
|
|
382
|
+
const withOnboarding = function(onboardingId) {
|
|
383
|
+
const withOnboarding2 = { __onboardingId: onboardingId };
|
|
384
|
+
return decorateEngine({ ...this, ...withOnboarding2 });
|
|
385
|
+
};
|
|
386
|
+
function decorateEngine(engine) {
|
|
387
|
+
function decorate(decorator) {
|
|
388
|
+
Object.assign(engine, decorator(engine));
|
|
389
|
+
}
|
|
390
|
+
if (engine.device) {
|
|
391
|
+
decorate(
|
|
392
|
+
(engine2) => ({
|
|
393
|
+
getWorkspaces: async () => {
|
|
394
|
+
const { device, client: client2 } = engine2;
|
|
395
|
+
const { pubKey } = await device.getU2FPubKey();
|
|
396
|
+
const { workspaceNames } = await client2.auth.psd.findWorkspaceNames.query({ pubKey });
|
|
397
|
+
return workspaceNames;
|
|
398
|
+
}
|
|
399
|
+
})
|
|
400
|
+
);
|
|
401
|
+
}
|
|
402
|
+
if (engine.__workspaceName && !engine.__psdToken && !engine.__apiAuth) {
|
|
403
|
+
decorate((engine2) => {
|
|
404
|
+
const { __workspaceName } = engine2;
|
|
405
|
+
return {
|
|
406
|
+
withPsdToken: function(token) {
|
|
407
|
+
const withPsdAuth = { __psdToken: token };
|
|
408
|
+
const psdAuth = `${__workspaceName}:${token}`;
|
|
409
|
+
const client2 = engine2.createClient({ psdAuth });
|
|
410
|
+
return decorateEngine({ ...this, client: client2, ...withPsdAuth });
|
|
411
|
+
}
|
|
412
|
+
};
|
|
413
|
+
});
|
|
414
|
+
}
|
|
415
|
+
if (engine.device && engine.__onboardingId) {
|
|
416
|
+
decorate((engine2) => {
|
|
417
|
+
const { device, client: client2, __onboardingId } = engine2;
|
|
418
|
+
async function enforcePairing() {
|
|
419
|
+
if (await device.hasPairing()) return;
|
|
420
|
+
const [{ pubKey }, confidentialityKey] = await Promise.all([
|
|
421
|
+
device.getU2FPubKey(),
|
|
422
|
+
device.getConfidentialityKey()
|
|
423
|
+
]);
|
|
424
|
+
const pairing = await client2.onboarding.pairDevicePartition.mutate({
|
|
425
|
+
pubKey,
|
|
426
|
+
onboardingId: __onboardingId,
|
|
427
|
+
data: {
|
|
428
|
+
confidentialityKeyCurve25519: confidentialityKey.confidentialityKeyCurve25519,
|
|
429
|
+
confidentialityKeySignature: confidentialityKey.confidentialityKeySignature
|
|
430
|
+
}
|
|
431
|
+
});
|
|
432
|
+
await device.setPairing({ pairing });
|
|
433
|
+
}
|
|
434
|
+
return {
|
|
435
|
+
claimDevice: async (params) => {
|
|
436
|
+
const { role, deviceName } = params;
|
|
437
|
+
const [{ pubKey }, { pubKey: confidentialityKey }] = await Promise.all([
|
|
438
|
+
device.getU2FPubKey(),
|
|
439
|
+
device.getConfidentialityPubKey()
|
|
440
|
+
]);
|
|
441
|
+
await client2.onboarding.claimDevice.mutate({
|
|
442
|
+
onboardingId: __onboardingId,
|
|
443
|
+
claim: { role, pubKey, deviceName, confidentialityKey }
|
|
444
|
+
});
|
|
445
|
+
},
|
|
446
|
+
collectWrappingKeyFragment: async (wrappingKey) => {
|
|
447
|
+
const [{ pubKey }, confidentialityKey] = await Promise.all([
|
|
448
|
+
device.getU2FPubKey(),
|
|
449
|
+
device.getConfidentialityPubKey()
|
|
450
|
+
]);
|
|
451
|
+
await device.openSession({
|
|
452
|
+
secureChannel: {
|
|
453
|
+
pubKey: wrappingKey.ephemeralPubKey,
|
|
454
|
+
certificate: wrappingKey.ephemeralCertificate
|
|
455
|
+
}
|
|
456
|
+
});
|
|
457
|
+
const { attestation } = await device.getAttestation();
|
|
458
|
+
const blob = await device.generateWrappingKeyFragment();
|
|
459
|
+
await client2.onboarding.submitWrappingKeyFragment.mutate({
|
|
460
|
+
pubKey,
|
|
461
|
+
onboardingId: __onboardingId,
|
|
462
|
+
fragment: {
|
|
463
|
+
blob,
|
|
464
|
+
ephemeralPubKey: confidentialityKey.pubKey,
|
|
465
|
+
ephemeralCertificate: {
|
|
466
|
+
...attestation,
|
|
467
|
+
signature: confidentialityKey.signature
|
|
468
|
+
}
|
|
469
|
+
}
|
|
470
|
+
});
|
|
471
|
+
},
|
|
472
|
+
registerDevice: async (params) => {
|
|
473
|
+
const { role, name } = params;
|
|
474
|
+
const getChallengeMutation = role === "ADMIN" ? client2.onboarding.generateMasterAdminRegistrationChallenge : client2.onboarding.generateSharedOwnerRegistrationChallenge;
|
|
475
|
+
const submitChallengeMutation = role === "ADMIN" ? client2.onboarding.submitMasterAdminRegistration : client2.onboarding.submitSharedOwnerRegistration;
|
|
476
|
+
await genericRegister({
|
|
477
|
+
device,
|
|
478
|
+
name,
|
|
479
|
+
role,
|
|
480
|
+
getChallenge: ({ pubKey, deviceData }) => getChallengeMutation.mutate({
|
|
481
|
+
onboardingId: __onboardingId,
|
|
482
|
+
pubKey,
|
|
483
|
+
deviceData
|
|
484
|
+
}),
|
|
485
|
+
submitChallenge: ({ pubKey, challengeResponse }) => submitChallengeMutation.mutate({
|
|
486
|
+
onboardingId: engine2.__onboardingId,
|
|
487
|
+
pubKey,
|
|
488
|
+
// FIXME this should be renamed to `challengeResponse` on backend side
|
|
489
|
+
response: challengeResponse
|
|
490
|
+
})
|
|
491
|
+
});
|
|
492
|
+
},
|
|
493
|
+
reviewSharedOwner: async (challenge) => {
|
|
494
|
+
await enforcePairing();
|
|
495
|
+
const { pubKey } = await device.getU2FPubKey();
|
|
496
|
+
await device.startKPatternAsResponder({
|
|
497
|
+
handshake: challenge.handshake,
|
|
498
|
+
handshakeAttestation: challenge.handshakeAttestation,
|
|
499
|
+
partitionId: challenge.partitionId
|
|
500
|
+
});
|
|
501
|
+
const signature = await device.validateVaultOperation({
|
|
502
|
+
actions: challenge.wActions
|
|
503
|
+
});
|
|
504
|
+
await client2.onboarding.submitReviewByMasterAdminSignature.mutate({
|
|
505
|
+
onboardingId: __onboardingId,
|
|
506
|
+
pubKey,
|
|
507
|
+
signature
|
|
508
|
+
});
|
|
509
|
+
},
|
|
510
|
+
collectSeedFragment: async (challenge) => {
|
|
511
|
+
await enforcePairing();
|
|
512
|
+
const [{ pubKey }, { attestation }] = await Promise.all([
|
|
513
|
+
device.getU2FPubKey(),
|
|
514
|
+
device.getAttestation()
|
|
515
|
+
]);
|
|
516
|
+
await device.startKPatternAsResponder({
|
|
517
|
+
handshake: challenge.handshake,
|
|
518
|
+
handshakeAttestation: challenge.handshakeAttestation,
|
|
519
|
+
partitionId: challenge.partitionId
|
|
520
|
+
});
|
|
521
|
+
const challengeResponse = await device.validateVaultOperation({
|
|
522
|
+
actions: challenge.wActions
|
|
523
|
+
});
|
|
524
|
+
const kkPattern = await device.startKKPatternAsResponder({
|
|
525
|
+
partitionId: challenge.partitionId,
|
|
526
|
+
handshake: challenge.kkHandshake,
|
|
527
|
+
handshakeAttestation: challenge.kkHandshakeAttestation
|
|
528
|
+
});
|
|
529
|
+
const approverBlob = await device.generateSeedFragment();
|
|
530
|
+
await client2.onboarding.submitSeedFragment.mutate({
|
|
531
|
+
onboardingId: __onboardingId,
|
|
532
|
+
pubKey,
|
|
533
|
+
seedFragment: {
|
|
534
|
+
challengeResponse,
|
|
535
|
+
approverBlob,
|
|
536
|
+
handshake: kkPattern.handshake,
|
|
537
|
+
handshakeAttestation: {
|
|
538
|
+
...attestation,
|
|
539
|
+
signature: kkPattern.signature
|
|
540
|
+
}
|
|
541
|
+
}
|
|
542
|
+
});
|
|
543
|
+
}
|
|
544
|
+
};
|
|
545
|
+
});
|
|
546
|
+
}
|
|
547
|
+
if (engine.device && engine.__workspaceName && !engine.__psdToken) {
|
|
548
|
+
decorate(
|
|
549
|
+
(engine2) => {
|
|
550
|
+
const { device, client: client2, __workspaceName } = engine2;
|
|
551
|
+
return {
|
|
552
|
+
login: async function(opts) {
|
|
553
|
+
const { pubKey } = await device.getU2FPubKey();
|
|
554
|
+
const challenge = await client2.auth.psd.generateChallenge.mutate({
|
|
555
|
+
pubKey,
|
|
556
|
+
workspaceName: __workspaceName
|
|
557
|
+
});
|
|
558
|
+
_optionalChain([opts, 'optionalAccess', _ => _.onScreenDisplayed, 'optionalCall', _2 => _2()]);
|
|
559
|
+
const authentication = await device.authenticate({
|
|
560
|
+
challenge,
|
|
561
|
+
workspaceName: __workspaceName
|
|
562
|
+
});
|
|
563
|
+
const authPayload = {
|
|
564
|
+
workspaceName: __workspaceName,
|
|
565
|
+
pubKey,
|
|
566
|
+
authentication,
|
|
567
|
+
validityDurationSecs: _optionalChain([opts, 'optionalAccess', _3 => _3.validityDurationSecs])
|
|
568
|
+
};
|
|
569
|
+
const { token } = await client2.auth.psd.authenticate.mutate({ ...authPayload });
|
|
570
|
+
const withPsdAuth = {
|
|
571
|
+
__psdToken: token
|
|
572
|
+
};
|
|
573
|
+
const psdAuth = `${engine2.__workspaceName}:${token}`;
|
|
574
|
+
const __authClient = engine2.createClient({ psdAuth });
|
|
575
|
+
return decorateEngine({ ...this, client: __authClient, ...withPsdAuth });
|
|
576
|
+
},
|
|
577
|
+
register: (params) => {
|
|
578
|
+
const { requestId, role, name } = params;
|
|
579
|
+
return genericRegister({
|
|
580
|
+
device,
|
|
581
|
+
name,
|
|
582
|
+
role,
|
|
583
|
+
getChallenge: async ({ deviceData }) => {
|
|
584
|
+
const req = await client2.requests.generateRegistrationChallenge.mutate({
|
|
585
|
+
id: params.requestId,
|
|
586
|
+
workspaceName: __workspaceName,
|
|
587
|
+
deviceData
|
|
588
|
+
});
|
|
589
|
+
const registration = req.data.registration;
|
|
590
|
+
_invariant2.default.call(void 0,
|
|
591
|
+
registration.subState === "PENDING",
|
|
592
|
+
"Expected sub state to be PENDING"
|
|
593
|
+
);
|
|
594
|
+
return registration.challenge;
|
|
595
|
+
},
|
|
596
|
+
submitChallenge: ({ challengeResponse }) => client2.requests.confirmRegistrationChallenge.mutate({
|
|
597
|
+
workspaceName: __workspaceName,
|
|
598
|
+
id: requestId,
|
|
599
|
+
challengeResponse
|
|
600
|
+
})
|
|
601
|
+
});
|
|
602
|
+
}
|
|
603
|
+
};
|
|
604
|
+
}
|
|
605
|
+
);
|
|
606
|
+
}
|
|
607
|
+
if (engine.__workspaceName && engine.__isApiUser && !engine.__apiAuth) {
|
|
608
|
+
decorate(
|
|
609
|
+
(engine2) => {
|
|
610
|
+
const { client: client2, __workspaceName } = engine2;
|
|
611
|
+
return {
|
|
612
|
+
login: async function(credentials) {
|
|
613
|
+
const res = await client2.auth.authenticate.mutate({
|
|
614
|
+
apiKeyId: credentials.apiKeyId,
|
|
615
|
+
apiKeySecret: credentials.apiKeySecret,
|
|
616
|
+
workspace: __workspaceName
|
|
617
|
+
});
|
|
618
|
+
const withApiAuth = {
|
|
619
|
+
__apiAuth: res
|
|
620
|
+
};
|
|
621
|
+
const __authClient = engine2.createClient({ apiAccessToken: res.accessToken });
|
|
622
|
+
return decorateEngine({ ...this, client: __authClient, ...withApiAuth });
|
|
623
|
+
}
|
|
624
|
+
};
|
|
625
|
+
}
|
|
626
|
+
);
|
|
627
|
+
}
|
|
628
|
+
if (engine.device && engine.__workspaceName && engine.__psdToken) {
|
|
629
|
+
decorate((engine2) => {
|
|
630
|
+
const { client: client2, device } = engine2;
|
|
631
|
+
async function enforcePairing() {
|
|
632
|
+
if (await device.hasPairing()) return;
|
|
633
|
+
const confidentialityKey = await device.getConfidentialityKey();
|
|
634
|
+
const pairing = await client2.debug.pairDevicePartition.mutate({
|
|
635
|
+
confidentialityKeyCurve25519: confidentialityKey.confidentialityKeyCurve25519,
|
|
636
|
+
confidentialityKeySignature: confidentialityKey.confidentialityKeySignature
|
|
637
|
+
});
|
|
638
|
+
await device.setPairing({ pairing });
|
|
639
|
+
}
|
|
640
|
+
return {
|
|
641
|
+
approve: async (request, params) => {
|
|
642
|
+
const { challenge } = await client2.requests.getChallenge.query({ id: request.id });
|
|
643
|
+
_invariant2.default.call(void 0, challenge.challengeType === "PSD", "Challenge type must be PSD");
|
|
644
|
+
await enforcePairing();
|
|
645
|
+
await device.startKPatternAsResponder({
|
|
646
|
+
handshake: challenge.handshake,
|
|
647
|
+
handshakeAttestation: challenge.handshakeAttestation,
|
|
648
|
+
partitionId: challenge.partitionId
|
|
649
|
+
});
|
|
650
|
+
_optionalChain([params, 'optionalAccess', _4 => _4.onScreenDisplayed, 'optionalCall', _5 => _5()]);
|
|
651
|
+
const signature = await device.validateVaultOperation({
|
|
652
|
+
actions: challenge.wActions
|
|
653
|
+
});
|
|
654
|
+
return client2.requests.approve.mutate({
|
|
655
|
+
id: request.id,
|
|
656
|
+
data: { challengeType: "PSD", signature }
|
|
657
|
+
});
|
|
658
|
+
},
|
|
659
|
+
reject: (request) => {
|
|
660
|
+
return client2.requests.reject.mutate({ id: request.id, data: null });
|
|
661
|
+
}
|
|
662
|
+
};
|
|
663
|
+
});
|
|
664
|
+
}
|
|
665
|
+
if (engine.__workspaceName && engine.__apiAuth) {
|
|
666
|
+
decorate((engine2) => {
|
|
667
|
+
const { client: client2 } = engine2;
|
|
668
|
+
return {
|
|
669
|
+
getChallenge: async (request) => {
|
|
670
|
+
const { challenge } = await client2.requests.getChallenge.query({ id: request.id });
|
|
671
|
+
_invariant2.default.call(void 0, challenge.challengeType === "API", "Challenge type must be API");
|
|
672
|
+
return challenge.payload;
|
|
673
|
+
},
|
|
674
|
+
approve: (request, signature) => {
|
|
675
|
+
return client2.requests.approve.mutate({
|
|
676
|
+
id: request.id,
|
|
677
|
+
data: { challengeType: "API", signature }
|
|
678
|
+
});
|
|
679
|
+
},
|
|
680
|
+
reject: (request, signature) => {
|
|
681
|
+
return client2.requests.reject.mutate({
|
|
682
|
+
id: request.id,
|
|
683
|
+
data: { challengeType: "API", signature }
|
|
684
|
+
});
|
|
685
|
+
}
|
|
686
|
+
};
|
|
687
|
+
});
|
|
688
|
+
}
|
|
689
|
+
return engine;
|
|
690
|
+
}
|
|
691
|
+
return {
|
|
692
|
+
...base,
|
|
693
|
+
withDeviceIndex,
|
|
694
|
+
withTransportId,
|
|
695
|
+
withApiUser,
|
|
696
|
+
withWorkspace,
|
|
697
|
+
withOnboarding
|
|
698
|
+
};
|
|
699
|
+
}
|
|
700
|
+
|
|
701
|
+
|
|
702
|
+
|
|
703
|
+
exports.createEngine = createEngine; exports.fetchAll = _chunkQOP5LA3Ecjs.fetchAll;
|
|
704
|
+
//# sourceMappingURL=engine.cjs.map
|