@bitpay-labs/bitcore-wallet-service 11.10.14 → 11.11.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/package.json +5 -5
- package/src/config.ts +0 -20
- package/src/externalservices/banxa.ts +51 -10
- package/src/externalservices/changelly.ts +54 -6
- package/src/externalservices/moonpay.ts +85 -19
- package/src/externalservices/oneInch.ts +13 -5
- package/src/externalservices/ramp.ts +42 -8
- package/src/externalservices/sardine.ts +51 -10
- package/src/externalservices/simplex.ts +58 -11
- package/src/externalservices/thorswap.ts +46 -11
- package/src/externalservices/transak.ts +53 -11
- package/src/lib/common/constants.ts +1 -1
- package/src/lib/errors/errordefinitions.ts +8 -0
- package/src/lib/model/tsskeygen.ts +12 -4
- package/src/lib/routes/middleware/authRequest.ts +6 -16
- package/src/lib/routes/middleware/authTssRequest.ts +130 -26
- package/src/lib/routes/services.ts +0 -12
- package/src/lib/routes/tss.ts +21 -8
- package/src/lib/routes/wallets.ts +8 -9
- package/src/lib/server.ts +9 -20
- package/src/lib/storage.ts +55 -22
- package/src/lib/tss.ts +77 -1
- package/src/types/externalservices.d.ts +0 -1
- package/test/integration/externalservices/banxa.test.ts +95 -5
- package/test/integration/externalservices/changelly.test.ts +118 -6
- package/test/integration/externalservices/coinGecko.test.ts +4 -0
- package/test/integration/externalservices/moonpay.test.ts +178 -9
- package/test/integration/externalservices/oneInch.test.ts +28 -1
- package/test/integration/externalservices/ramp.test.ts +126 -4
- package/test/integration/externalservices/sardine.test.ts +95 -5
- package/test/integration/externalservices/simplex.test.ts +95 -5
- package/test/integration/externalservices/thorswap.test.ts +81 -5
- package/test/integration/externalservices/transak.test.ts +98 -6
- package/test/integration/helpers.ts +1 -1
- package/test/integration/server.test.ts +56 -88
- package/test/integration/tss.test.ts +706 -371
- package/test/storage.test.ts +6 -7
- package/ts_build/package.json +4 -4
- package/ts_build/src/config.d.ts.map +1 -1
- package/ts_build/src/config.js +0 -4
- package/ts_build/src/config.js.map +1 -1
- package/ts_build/src/externalservices/banxa.d.ts.map +1 -1
- package/ts_build/src/externalservices/banxa.js +51 -10
- package/ts_build/src/externalservices/banxa.js.map +1 -1
- package/ts_build/src/externalservices/changelly.d.ts.map +1 -1
- package/ts_build/src/externalservices/changelly.js +54 -6
- package/ts_build/src/externalservices/changelly.js.map +1 -1
- package/ts_build/src/externalservices/moonpay.d.ts.map +1 -1
- package/ts_build/src/externalservices/moonpay.js +85 -19
- package/ts_build/src/externalservices/moonpay.js.map +1 -1
- package/ts_build/src/externalservices/oneInch.d.ts.map +1 -1
- package/ts_build/src/externalservices/oneInch.js +13 -5
- package/ts_build/src/externalservices/oneInch.js.map +1 -1
- package/ts_build/src/externalservices/ramp.d.ts.map +1 -1
- package/ts_build/src/externalservices/ramp.js +42 -8
- package/ts_build/src/externalservices/ramp.js.map +1 -1
- package/ts_build/src/externalservices/sardine.d.ts.map +1 -1
- package/ts_build/src/externalservices/sardine.js +51 -10
- package/ts_build/src/externalservices/sardine.js.map +1 -1
- package/ts_build/src/externalservices/simplex.d.ts.map +1 -1
- package/ts_build/src/externalservices/simplex.js +55 -11
- package/ts_build/src/externalservices/simplex.js.map +1 -1
- package/ts_build/src/externalservices/thorswap.d.ts.map +1 -1
- package/ts_build/src/externalservices/thorswap.js +45 -11
- package/ts_build/src/externalservices/thorswap.js.map +1 -1
- package/ts_build/src/externalservices/transak.d.ts.map +1 -1
- package/ts_build/src/externalservices/transak.js +53 -11
- package/ts_build/src/externalservices/transak.js.map +1 -1
- package/ts_build/src/lib/common/constants.d.ts +1 -1
- package/ts_build/src/lib/common/constants.js +1 -1
- package/ts_build/src/lib/common/index.d.ts +1 -1
- package/ts_build/src/lib/errors/errordefinitions.d.ts +4 -0
- package/ts_build/src/lib/errors/errordefinitions.d.ts.map +1 -1
- package/ts_build/src/lib/errors/errordefinitions.js +4 -0
- package/ts_build/src/lib/errors/errordefinitions.js.map +1 -1
- package/ts_build/src/lib/model/tsskeygen.d.ts +2 -0
- package/ts_build/src/lib/model/tsskeygen.d.ts.map +1 -1
- package/ts_build/src/lib/model/tsskeygen.js +6 -2
- package/ts_build/src/lib/model/tsskeygen.js.map +1 -1
- package/ts_build/src/lib/routes/middleware/authRequest.d.ts.map +1 -1
- package/ts_build/src/lib/routes/middleware/authRequest.js +6 -16
- package/ts_build/src/lib/routes/middleware/authRequest.js.map +1 -1
- package/ts_build/src/lib/routes/middleware/authTssRequest.d.ts +2 -1
- package/ts_build/src/lib/routes/middleware/authTssRequest.d.ts.map +1 -1
- package/ts_build/src/lib/routes/middleware/authTssRequest.js +104 -24
- package/ts_build/src/lib/routes/middleware/authTssRequest.js.map +1 -1
- package/ts_build/src/lib/routes/services.d.ts.map +1 -1
- package/ts_build/src/lib/routes/services.js +0 -10
- package/ts_build/src/lib/routes/services.js.map +1 -1
- package/ts_build/src/lib/routes/tss.d.ts.map +1 -1
- package/ts_build/src/lib/routes/tss.js +19 -7
- package/ts_build/src/lib/routes/tss.js.map +1 -1
- package/ts_build/src/lib/routes/wallets.d.ts.map +1 -1
- package/ts_build/src/lib/routes/wallets.js +8 -9
- package/ts_build/src/lib/routes/wallets.js.map +1 -1
- package/ts_build/src/lib/server.d.ts +0 -2
- package/ts_build/src/lib/server.d.ts.map +1 -1
- package/ts_build/src/lib/server.js +8 -20
- package/ts_build/src/lib/server.js.map +1 -1
- package/ts_build/src/lib/storage.d.ts +9 -2
- package/ts_build/src/lib/storage.d.ts.map +1 -1
- package/ts_build/src/lib/storage.js +51 -20
- package/ts_build/src/lib/storage.js.map +1 -1
- package/ts_build/src/lib/tss.d.ts +8 -0
- package/ts_build/src/lib/tss.d.ts.map +1 -1
- package/ts_build/src/lib/tss.js +59 -1
- package/ts_build/src/lib/tss.js.map +1 -1
- package/ts_build/test/integration/externalservices/banxa.test.d.ts.map +1 -1
- package/ts_build/test/integration/externalservices/banxa.test.js +93 -5
- package/ts_build/test/integration/externalservices/banxa.test.js.map +1 -1
- package/ts_build/test/integration/externalservices/changelly.test.d.ts.map +1 -1
- package/ts_build/test/integration/externalservices/changelly.test.js +111 -6
- package/ts_build/test/integration/externalservices/changelly.test.js.map +1 -1
- package/ts_build/test/integration/externalservices/coinGecko.test.js +4 -0
- package/ts_build/test/integration/externalservices/coinGecko.test.js.map +1 -1
- package/ts_build/test/integration/externalservices/moonpay.test.d.ts.map +1 -1
- package/ts_build/test/integration/externalservices/moonpay.test.js +169 -9
- package/ts_build/test/integration/externalservices/moonpay.test.js.map +1 -1
- package/ts_build/test/integration/externalservices/oneInch.test.d.ts.map +1 -1
- package/ts_build/test/integration/externalservices/oneInch.test.js +26 -1
- package/ts_build/test/integration/externalservices/oneInch.test.js.map +1 -1
- package/ts_build/test/integration/externalservices/ramp.test.d.ts.map +1 -1
- package/ts_build/test/integration/externalservices/ramp.test.js +115 -4
- package/ts_build/test/integration/externalservices/ramp.test.js.map +1 -1
- package/ts_build/test/integration/externalservices/sardine.test.d.ts.map +1 -1
- package/ts_build/test/integration/externalservices/sardine.test.js +94 -5
- package/ts_build/test/integration/externalservices/sardine.test.js.map +1 -1
- package/ts_build/test/integration/externalservices/simplex.test.d.ts.map +1 -1
- package/ts_build/test/integration/externalservices/simplex.test.js +89 -5
- package/ts_build/test/integration/externalservices/simplex.test.js.map +1 -1
- package/ts_build/test/integration/externalservices/thorswap.test.d.ts.map +1 -1
- package/ts_build/test/integration/externalservices/thorswap.test.js +76 -5
- package/ts_build/test/integration/externalservices/thorswap.test.js.map +1 -1
- package/ts_build/test/integration/externalservices/transak.test.d.ts.map +1 -1
- package/ts_build/test/integration/externalservices/transak.test.js +93 -6
- package/ts_build/test/integration/externalservices/transak.test.js.map +1 -1
- package/ts_build/test/integration/helpers.js +1 -1
- package/ts_build/test/integration/helpers.js.map +1 -1
- package/ts_build/test/integration/server.test.js +44 -76
- package/ts_build/test/integration/server.test.js.map +1 -1
- package/ts_build/test/integration/tss.test.d.ts.map +1 -1
- package/ts_build/test/integration/tss.test.js +599 -357
- package/ts_build/test/integration/tss.test.js.map +1 -1
- package/ts_build/test/storage.test.js +6 -7
- package/ts_build/test/storage.test.js.map +1 -1
- package/src/externalservices/wyre.ts +0 -131
- package/test/integration/externalservices/wyre.test.ts +0 -270
- package/ts_build/src/externalservices/wyre.d.ts +0 -7
- package/ts_build/src/externalservices/wyre.d.ts.map +0 -1
- package/ts_build/src/externalservices/wyre.js +0 -144
- package/ts_build/src/externalservices/wyre.js.map +0 -1
- package/ts_build/test/integration/externalservices/wyre.test.d.ts +0 -2
- package/ts_build/test/integration/externalservices/wyre.test.d.ts.map +0 -1
- package/ts_build/test/integration/externalservices/wyre.test.js +0 -281
- package/ts_build/test/integration/externalservices/wyre.test.js.map +0 -1
|
@@ -5,15 +5,23 @@ import { Errors } from '../../errors/errordefinitions';
|
|
|
5
5
|
import { WalletService, checkRequired } from '../../server';
|
|
6
6
|
import { error } from '../helpers';
|
|
7
7
|
import { getCredentials, getMessage } from './authRequest';
|
|
8
|
-
import type { TssKeyGenModel } from '../../model/tsskeygen';
|
|
9
|
-
import type { TssSigGenModel } from '../../model/tsssign';
|
|
8
|
+
import type { ITssKeyMessageObject, TssKeyGenModel } from '../../model/tsskeygen';
|
|
9
|
+
import type { ITssSigMessageObject, TssSigGenModel } from '../../model/tsssign';
|
|
10
|
+
|
|
11
|
+
function verifyMessage(req: express.Request, signature: string, pubKey: string) {
|
|
12
|
+
const message = getMessage(req);
|
|
13
|
+
const isValid = !!Utils.verifyMessage(message, signature, pubKey);
|
|
14
|
+
if (!isValid) {
|
|
15
|
+
throw Errors.NOT_AUTHORIZED.withMessage('Invalid signature');
|
|
16
|
+
}
|
|
17
|
+
}
|
|
10
18
|
|
|
11
19
|
/**
|
|
12
|
-
* Middleware to authenticate TSS requests and attach the TSS session to the request.
|
|
20
|
+
* Middleware to authenticate TSS key generation requests and attach the TSS session to the request.
|
|
13
21
|
* It checks if the request has valid credentials, verifies the signature,
|
|
14
22
|
* and retrieves the TSS session based on the request path.
|
|
15
23
|
*/
|
|
16
|
-
export function
|
|
24
|
+
export function authTssKeyGenRequest(): express.RequestHandler {
|
|
17
25
|
return async function(req, res, next) {
|
|
18
26
|
try {
|
|
19
27
|
const storage = WalletService.getStorage();
|
|
@@ -28,37 +36,74 @@ export function authTssRequest(): express.RequestHandler {
|
|
|
28
36
|
} = credentials;
|
|
29
37
|
|
|
30
38
|
const { id } = req.params as { [key: string]: string };
|
|
39
|
+
const body = req.body as { message: ITssKeyMessageObject | undefined };
|
|
31
40
|
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
let pubKey = null;
|
|
35
|
-
if (req.path.includes('/tss/keygen/')) {
|
|
36
|
-
session = await storage.fetchTssKeyGenSession({ id });
|
|
37
|
-
partyId = session?.participants.indexOf(copayerId);
|
|
38
|
-
pubKey = partyId > -1 ? session.rounds[0].find(r => r.fromPartyId === partyId)?.messages.publicKey : null;
|
|
39
|
-
} else if (req.path.includes('/tss/sign/')) {
|
|
40
|
-
session = await storage.fetchTssSigSession({ id });
|
|
41
|
-
partyId = session?.participants.find(p => p.copayerId === copayerId)?.partyId;
|
|
42
|
-
pubKey = partyId == null ? null : session?.rounds[0]?.find(r => r.fromPartyId === partyId)?.messages.publicKey;
|
|
43
|
-
} else {
|
|
44
|
-
throw new Error('Unknown TSS request path: ' + req.path);
|
|
45
|
-
}
|
|
41
|
+
// Note: the copayer is not fetched from the db here bc it's not stored
|
|
42
|
+
// until the key generation session is done and the wallet gets created.
|
|
46
43
|
|
|
44
|
+
const session: TssKeyGenModel = await storage.fetchTssKeyGenSession({ id });
|
|
47
45
|
if (!session) {
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
46
|
+
// This is a brand new session. Caller should be party 0 with the initial round message.
|
|
47
|
+
if (body?.message?.round === 0 && body?.message?.partyId === 0) {
|
|
48
|
+
const pubKey = body?.message?.publicKey;
|
|
49
|
+
verifyMessage(req, signature, pubKey); // Self verification, but at least ensures that the caller owns the message's private key
|
|
50
|
+
return next();
|
|
51
|
+
} else {
|
|
52
|
+
// Session should have been initialized by the client already in BWC > TssKeyGen.newKey()
|
|
53
|
+
throw Errors.NOT_AUTHORIZED.withMessage('Session not found');
|
|
54
|
+
}
|
|
52
55
|
}
|
|
56
|
+
|
|
53
57
|
if (session.isExpired()) {
|
|
54
58
|
throw Errors.TSS_SESSION_EXPIRED;
|
|
55
59
|
}
|
|
56
60
|
|
|
57
|
-
const
|
|
58
|
-
const
|
|
59
|
-
|
|
60
|
-
|
|
61
|
+
const isRound0Msg = body?.message?.round === 0;
|
|
62
|
+
const awaitingJoiners = session.participants.some(p => !p); // session.participants is initiated with n slots (initally null) that get populated as participants join
|
|
63
|
+
const participantIdx = session.participants.indexOf(copayerId); // equals -1 if the copayer has not joined yet
|
|
64
|
+
if (participantIdx === -1 && session.schemeVersion >= 1.2) {
|
|
65
|
+
// Check session.authPublicKeys to ensure initiator registered this participant
|
|
66
|
+
const msgPubKey = body?.message?.publicKey;
|
|
67
|
+
if (!msgPubKey) {
|
|
68
|
+
throw Errors.NOT_AUTHORIZED;
|
|
69
|
+
}
|
|
70
|
+
const _participantIdx = session.authPublicKeys.indexOf(msgPubKey);
|
|
71
|
+
if (_participantIdx === -1) {
|
|
72
|
+
throw Errors.NOT_AUTHORIZED;
|
|
73
|
+
}
|
|
74
|
+
if (session.participants[_participantIdx]) {
|
|
75
|
+
throw Errors.NOT_AUTHORIZED;
|
|
76
|
+
}
|
|
77
|
+
}
|
|
78
|
+
const partyId = participantIdx > -1
|
|
79
|
+
? participantIdx
|
|
80
|
+
: (awaitingJoiners && isRound0Msg)
|
|
81
|
+
? body?.message?.partyId // if participant has not joined session yet, use the partyId from the initial round message (verified below)
|
|
82
|
+
: -1;
|
|
83
|
+
|
|
84
|
+
if (partyId < 0 || partyId >= session.n || !Number.isInteger(partyId)) {
|
|
85
|
+
throw Errors.NOT_AUTHORIZED.withMessage('Copayer not found in session');
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
let pubKey: string = null;
|
|
89
|
+
if (session?.schemeVersion <= 1.1) {
|
|
90
|
+
// session.authPublicKeys was not added until 1.2, so fetch public key from the first round messages instead (old way)
|
|
91
|
+
pubKey = session.rounds[0].find(r => r.fromPartyId === partyId)?.messages.publicKey;
|
|
92
|
+
if (!pubKey && participantIdx === -1) {
|
|
93
|
+
// Joining party hasn't submitted its round 0 message yet and legacy sessions have no registration,
|
|
94
|
+
// so use the joining message's public key (verifyTssMessage verifies the message's payload against it)
|
|
95
|
+
pubKey = body?.message?.publicKey;
|
|
96
|
+
}
|
|
97
|
+
} else {
|
|
98
|
+
// authPublicKeys is set by the session leader, so this will verify that the leader and the calling participant here are on the same page
|
|
99
|
+
pubKey = session?.authPublicKeys[partyId];
|
|
100
|
+
}
|
|
101
|
+
|
|
102
|
+
if (!pubKey) {
|
|
103
|
+
throw Errors.NOT_AUTHORIZED.withMessage('Copayer not found in session');
|
|
61
104
|
}
|
|
105
|
+
|
|
106
|
+
verifyMessage(req, signature, pubKey);
|
|
62
107
|
|
|
63
108
|
req.session = session;
|
|
64
109
|
return next();
|
|
@@ -69,4 +114,63 @@ export function authTssRequest(): express.RequestHandler {
|
|
|
69
114
|
return error.returnError(new ClientError({ code: 'INTERNAL_ERROR' }), res, req);
|
|
70
115
|
}
|
|
71
116
|
};
|
|
117
|
+
};
|
|
118
|
+
|
|
119
|
+
export function authTssSignRequest(): express.RequestHandler {
|
|
120
|
+
return async function(req, res, next) {
|
|
121
|
+
try {
|
|
122
|
+
const storage = WalletService.getStorage();
|
|
123
|
+
const credentials = getCredentials(req);
|
|
124
|
+
if (!checkRequired(credentials, ['copayerId', 'signature'])) {
|
|
125
|
+
throw Errors.NOT_AUTHORIZED;
|
|
126
|
+
}
|
|
127
|
+
|
|
128
|
+
const {
|
|
129
|
+
copayerId,
|
|
130
|
+
signature
|
|
131
|
+
} = credentials;
|
|
132
|
+
|
|
133
|
+
const { id } = req.params as { [key: string]: string };
|
|
134
|
+
const body = req.body as { message: ITssSigMessageObject | undefined };
|
|
135
|
+
// Only some requests carry a body.message (e.g. POST /store only sends the final signature).
|
|
136
|
+
// Omitting it is safe since routes that don't receive a message don't consume one.
|
|
137
|
+
const verifyMsg = !!body?.message;
|
|
138
|
+
|
|
139
|
+
const copayer = await storage.fetchCopayerLookup(copayerId);
|
|
140
|
+
if (!copayer) {
|
|
141
|
+
throw Errors.NOT_AUTHORIZED.withMessage('Copayer not found');
|
|
142
|
+
}
|
|
143
|
+
const pubKey = copayer.requestPubKeys[0].key;
|
|
144
|
+
if (verifyMsg && pubKey !== body?.message?.publicKey) {
|
|
145
|
+
throw Errors.NOT_AUTHORIZED.withMessage('Invalid public key');
|
|
146
|
+
}
|
|
147
|
+
|
|
148
|
+
const session: TssSigGenModel = await storage.fetchTssSigSession({ id });
|
|
149
|
+
// If !session, it needs to be initiated
|
|
150
|
+
if (session) {
|
|
151
|
+
if (session.isExpired()) {
|
|
152
|
+
throw Errors.TSS_SESSION_EXPIRED;
|
|
153
|
+
}
|
|
154
|
+
const party = session.participants.find(p => p.copayerId === copayerId);
|
|
155
|
+
if (!party) {
|
|
156
|
+
throw Errors.NOT_AUTHORIZED.withMessage('Copayer not found in session');
|
|
157
|
+
}
|
|
158
|
+
if (verifyMsg && party.partyId !== body?.message?.partyId) {
|
|
159
|
+
throw Errors.NOT_AUTHORIZED.withMessage('Copayer not found in session');
|
|
160
|
+
}
|
|
161
|
+
|
|
162
|
+
req.session = session;
|
|
163
|
+
} else if (body?.message?.round !== 0) {
|
|
164
|
+
throw Errors.TSS_SESSION_NOT_FOUND;
|
|
165
|
+
}
|
|
166
|
+
|
|
167
|
+
verifyMessage(req, signature, pubKey);
|
|
168
|
+
return next();
|
|
169
|
+
} catch (err) {
|
|
170
|
+
if (err instanceof ClientError) {
|
|
171
|
+
return error.returnError(err, res, req);
|
|
172
|
+
}
|
|
173
|
+
return error.returnError(new ClientError({ code: 'INTERNAL_ERROR' }), res, req);
|
|
174
|
+
}
|
|
175
|
+
};
|
|
72
176
|
};
|
|
@@ -459,18 +459,6 @@ export function registerServiceRoutes(router: express.Router, context: RouteCont
|
|
|
459
459
|
});
|
|
460
460
|
});
|
|
461
461
|
|
|
462
|
-
router.post('/v1/service/wyre/walletOrderQuotation', (req, res) => {
|
|
463
|
-
respondWithAuthServer(req, res, context, server => {
|
|
464
|
-
return server.externalServices.wyre.wyreWalletOrderQuotation(req);
|
|
465
|
-
});
|
|
466
|
-
});
|
|
467
|
-
|
|
468
|
-
router.post('/v1/service/wyre/walletOrderReservation', (req, res) => {
|
|
469
|
-
respondWithAuthServer(req, res, context, server => {
|
|
470
|
-
return server.externalServices.wyre.wyreWalletOrderReservation(req);
|
|
471
|
-
});
|
|
472
|
-
});
|
|
473
|
-
|
|
474
462
|
router.post('/v1/service/changelly/getCurrencies', (req, res) => {
|
|
475
463
|
respondWithPublicServer(req, res, context, server => {
|
|
476
464
|
return server.externalServices.changelly.changellyGetCurrencies(req);
|
package/src/lib/routes/tss.ts
CHANGED
|
@@ -2,7 +2,7 @@ import express from 'express';
|
|
|
2
2
|
import * as Types from '../../types/expressapp';
|
|
3
3
|
import { TssKeyGen, TssSign } from '../tss';
|
|
4
4
|
import { authRequest } from './middleware/authRequest';
|
|
5
|
-
import {
|
|
5
|
+
import { authTssKeyGenRequest, authTssSignRequest } from './middleware/authTssRequest';
|
|
6
6
|
import { createWalletLimiter } from './middleware/createWalletLimiter';
|
|
7
7
|
import { verifyTssMessage } from './middleware/verifyTssMessage';
|
|
8
8
|
|
|
@@ -23,7 +23,7 @@ export class TssRouter {
|
|
|
23
23
|
|
|
24
24
|
/** Key generation methods */
|
|
25
25
|
|
|
26
|
-
router.post('/v1/tss/keygen/:id', createWalletLimiter(opts), verifyTssMessage, async function(req, res) {
|
|
26
|
+
router.post('/v1/tss/keygen/:id', createWalletLimiter(opts), authTssKeyGenRequest(), verifyTssMessage, async function(req, res) {
|
|
27
27
|
try {
|
|
28
28
|
const id = req.params.id;
|
|
29
29
|
// version was not given by client until 1.1, so fallback to 1.0
|
|
@@ -36,7 +36,20 @@ export class TssRouter {
|
|
|
36
36
|
}
|
|
37
37
|
});
|
|
38
38
|
|
|
39
|
-
router.
|
|
39
|
+
router.post('/v1/tss/keygen/:id/register', authTssKeyGenRequest(), async function(req, res) {
|
|
40
|
+
try {
|
|
41
|
+
const id = req.params.id;
|
|
42
|
+
const copayerId = req.headers['x-identity'];
|
|
43
|
+
const data = req.body;
|
|
44
|
+
|
|
45
|
+
await TssKeyGen.registerParty({ id, copayerId, data });
|
|
46
|
+
return res.send();
|
|
47
|
+
} catch (err) {
|
|
48
|
+
return returnError(err ?? 'unknown', res, req);
|
|
49
|
+
}
|
|
50
|
+
});
|
|
51
|
+
|
|
52
|
+
router.get('/v1/tss/keygen/:id/:round', authTssKeyGenRequest(), async function(req, res) {
|
|
40
53
|
let interval: NodeJS.Timeout;
|
|
41
54
|
try {
|
|
42
55
|
const abort = new AbortController();
|
|
@@ -74,7 +87,7 @@ export class TssRouter {
|
|
|
74
87
|
}
|
|
75
88
|
});
|
|
76
89
|
|
|
77
|
-
router.post('/v1/tss/keygen/:id/store',
|
|
90
|
+
router.post('/v1/tss/keygen/:id/store', authTssKeyGenRequest(), async function(req, res) {
|
|
78
91
|
try {
|
|
79
92
|
const id = req.params.id;
|
|
80
93
|
const copayerId = req.headers['x-identity'];
|
|
@@ -87,7 +100,7 @@ export class TssRouter {
|
|
|
87
100
|
}
|
|
88
101
|
});
|
|
89
102
|
|
|
90
|
-
router.post('/v1/tss/keygen/:id/secret',
|
|
103
|
+
router.post('/v1/tss/keygen/:id/secret', authTssKeyGenRequest(), async function(req, res) {
|
|
91
104
|
try {
|
|
92
105
|
const id = req.params.id;
|
|
93
106
|
const { secret } = req.body;
|
|
@@ -99,7 +112,7 @@ export class TssRouter {
|
|
|
99
112
|
}
|
|
100
113
|
});
|
|
101
114
|
|
|
102
|
-
router.get('/v1/tss/keygen/:id/secret',
|
|
115
|
+
router.get('/v1/tss/keygen/:id/secret', authTssKeyGenRequest(), async function(req, res) {
|
|
103
116
|
try {
|
|
104
117
|
const id = req.params.id;
|
|
105
118
|
const copayerId = req.headers['x-identity'];
|
|
@@ -126,7 +139,7 @@ export class TssRouter {
|
|
|
126
139
|
}
|
|
127
140
|
});
|
|
128
141
|
|
|
129
|
-
router.get('/v1/tss/sign/:id/:round',
|
|
142
|
+
router.get('/v1/tss/sign/:id/:round', authTssSignRequest(), async function(req, res) {
|
|
130
143
|
let interval: NodeJS.Timeout;
|
|
131
144
|
try {
|
|
132
145
|
const abort = new AbortController();
|
|
@@ -161,7 +174,7 @@ export class TssRouter {
|
|
|
161
174
|
}
|
|
162
175
|
});
|
|
163
176
|
|
|
164
|
-
router.post('/v1/tss/sign/:id/store',
|
|
177
|
+
router.post('/v1/tss/sign/:id/store', authTssSignRequest(), async function(req, res) {
|
|
165
178
|
try {
|
|
166
179
|
const id = req.params.id;
|
|
167
180
|
const { signature } = req.body;
|
|
@@ -229,15 +229,14 @@ export function registerWalletRoutes(router: express.Router, context: RouteConte
|
|
|
229
229
|
}
|
|
230
230
|
|
|
231
231
|
const storage = WalletService.getStorage();
|
|
232
|
-
const existing = await Promise.all<{ copayerId: string; verified: boolean }>(copayers.map(c =>
|
|
233
|
-
storage.fetchCopayerLookup(c.copayerId
|
|
234
|
-
|
|
235
|
-
|
|
236
|
-
|
|
237
|
-
|
|
238
|
-
|
|
239
|
-
|
|
240
|
-
})));
|
|
232
|
+
const existing = await Promise.all<{ copayerId: string; verified: boolean }>(copayers.map(async c => {
|
|
233
|
+
const copayer = await storage.fetchCopayerLookup(c.copayerId).catch(() => null);
|
|
234
|
+
if (!copayer) {
|
|
235
|
+
return { copayerId: c.copayerId, verified: false };
|
|
236
|
+
}
|
|
237
|
+
const verified = copayer.requestPubKeys.some(pubkey => Utils.verifyMessage(c.copayerId, c.signature, pubkey.key));
|
|
238
|
+
return { copayerId: c.copayerId, verified };
|
|
239
|
+
}));
|
|
241
240
|
return res.json(existing.filter(e => e.verified).map(e => e.copayerId));
|
|
242
241
|
} catch (err) {
|
|
243
242
|
return returnError(err, res, req);
|
package/src/lib/server.ts
CHANGED
|
@@ -27,7 +27,6 @@ import { SardineService } from '../externalservices/sardine';
|
|
|
27
27
|
import { SimplexService } from '../externalservices/simplex';
|
|
28
28
|
import { ThorswapService } from '../externalservices/thorswap';
|
|
29
29
|
import { TransakService } from '../externalservices/transak';
|
|
30
|
-
import { WyreService } from '../externalservices/wyre';
|
|
31
30
|
import { serverMessages } from '../serverMessages';
|
|
32
31
|
import { BCHAddressTranslator } from './bchaddresstranslator';
|
|
33
32
|
import { BlockChainExplorer } from './blockchainexplorer';
|
|
@@ -160,7 +159,6 @@ export class WalletService implements IWalletService {
|
|
|
160
159
|
simplex: SimplexService;
|
|
161
160
|
thorswap: ThorswapService;
|
|
162
161
|
transak: TransakService;
|
|
163
|
-
wyre: WyreService;
|
|
164
162
|
coinGecko: CoinGeckoService;
|
|
165
163
|
};
|
|
166
164
|
|
|
@@ -190,7 +188,6 @@ export class WalletService implements IWalletService {
|
|
|
190
188
|
simplex: new SimplexService(),
|
|
191
189
|
thorswap: new ThorswapService(),
|
|
192
190
|
transak: new TransakService(),
|
|
193
|
-
wyre: new WyreService(),
|
|
194
191
|
coinGecko: new CoinGeckoService(this.storage),
|
|
195
192
|
};
|
|
196
193
|
}
|
|
@@ -394,10 +391,7 @@ export class WalletService implements IWalletService {
|
|
|
394
391
|
return cb(ex);
|
|
395
392
|
}
|
|
396
393
|
|
|
397
|
-
server.storage.fetchCopayerLookup(opts.copayerId
|
|
398
|
-
if (err) {
|
|
399
|
-
return cb(err);
|
|
400
|
-
}
|
|
394
|
+
server.storage.fetchCopayerLookup(opts.copayerId).then(copayer => {
|
|
401
395
|
if (!copayer) {
|
|
402
396
|
return cb(Errors.NOT_AUTHORIZED.withMessage('Copayer not found'));
|
|
403
397
|
}
|
|
@@ -420,7 +414,7 @@ export class WalletService implements IWalletService {
|
|
|
420
414
|
|
|
421
415
|
server.copayerId = opts.copayerId;
|
|
422
416
|
return cb(null, server);
|
|
423
|
-
});
|
|
417
|
+
}).catch(err => cb(err));
|
|
424
418
|
};
|
|
425
419
|
|
|
426
420
|
const withSession = cb => {
|
|
@@ -428,7 +422,7 @@ export class WalletService implements IWalletService {
|
|
|
428
422
|
return;
|
|
429
423
|
}
|
|
430
424
|
|
|
431
|
-
let server;
|
|
425
|
+
let server: WalletService;
|
|
432
426
|
try {
|
|
433
427
|
server = WalletService.getInstance(opts);
|
|
434
428
|
} catch (ex) {
|
|
@@ -445,10 +439,7 @@ export class WalletService implements IWalletService {
|
|
|
445
439
|
return cb(Errors.NOT_AUTHORIZED.withMessage('Session expired'));
|
|
446
440
|
}
|
|
447
441
|
|
|
448
|
-
server.storage.fetchCopayerLookup(opts.copayerId
|
|
449
|
-
if (err) {
|
|
450
|
-
return cb(err);
|
|
451
|
-
}
|
|
442
|
+
server.storage.fetchCopayerLookup(opts.copayerId).then(copayer => {
|
|
452
443
|
if (!copayer) {
|
|
453
444
|
return cb(Errors.NOT_AUTHORIZED.withMessage('Copayer not found'));
|
|
454
445
|
}
|
|
@@ -456,7 +447,7 @@ export class WalletService implements IWalletService {
|
|
|
456
447
|
server.copayerId = opts.copayerId;
|
|
457
448
|
server.walletId = copayer.walletId;
|
|
458
449
|
return cb(null, server);
|
|
459
|
-
});
|
|
450
|
+
}).catch(err => cb(err));
|
|
460
451
|
});
|
|
461
452
|
};
|
|
462
453
|
|
|
@@ -1060,8 +1051,7 @@ export class WalletService implements IWalletService {
|
|
|
1060
1051
|
derivationStrategy: wallet.derivationStrategy
|
|
1061
1052
|
});
|
|
1062
1053
|
|
|
1063
|
-
this.storage.fetchCopayerLookup(copayer.id
|
|
1064
|
-
if (err) return cb(err);
|
|
1054
|
+
this.storage.fetchCopayerLookup(copayer.id).then(res => {
|
|
1065
1055
|
if (res) return cb(Errors.COPAYER_REGISTERED);
|
|
1066
1056
|
|
|
1067
1057
|
if (opts.dryRun)
|
|
@@ -1113,7 +1103,7 @@ export class WalletService implements IWalletService {
|
|
|
1113
1103
|
}
|
|
1114
1104
|
);
|
|
1115
1105
|
});
|
|
1116
|
-
});
|
|
1106
|
+
}).catch(err => cb(err));
|
|
1117
1107
|
}
|
|
1118
1108
|
|
|
1119
1109
|
_addKeyToCopayer(wallet: Wallet, copayer: Copayer, opts, cb) {
|
|
@@ -1143,8 +1133,7 @@ export class WalletService implements IWalletService {
|
|
|
1143
1133
|
addAccess(opts, cb) {
|
|
1144
1134
|
if (!checkRequired(opts, ['copayerId', 'requestPubKey', 'signature'], cb)) return;
|
|
1145
1135
|
|
|
1146
|
-
this.storage.fetchCopayerLookup(opts.copayerId
|
|
1147
|
-
if (err) return cb(err);
|
|
1136
|
+
this.storage.fetchCopayerLookup(opts.copayerId).then(copayer => {
|
|
1148
1137
|
if (!copayer) return cb(Errors.NOT_AUTHORIZED);
|
|
1149
1138
|
this.storage.fetchWallet(copayer.walletId, (err, wallet) => {
|
|
1150
1139
|
if (err) return cb(err);
|
|
@@ -1164,7 +1153,7 @@ export class WalletService implements IWalletService {
|
|
|
1164
1153
|
|
|
1165
1154
|
this._addKeyToCopayer(wallet, copayer, opts, cb);
|
|
1166
1155
|
});
|
|
1167
|
-
});
|
|
1156
|
+
}).catch(err => cb(err));
|
|
1168
1157
|
}
|
|
1169
1158
|
|
|
1170
1159
|
_setClientVersion(version) {
|
package/src/lib/storage.ts
CHANGED
|
@@ -288,27 +288,19 @@ export class Storage {
|
|
|
288
288
|
);
|
|
289
289
|
}
|
|
290
290
|
|
|
291
|
-
fetchCopayerLookup(copayerId: string
|
|
292
|
-
this.db.collection(collections.COPAYERS_LOOKUP).findOne(
|
|
293
|
-
|
|
294
|
-
|
|
295
|
-
|
|
296
|
-
|
|
297
|
-
|
|
298
|
-
|
|
299
|
-
|
|
300
|
-
if (!result.requestPubKeys) {
|
|
301
|
-
result.requestPubKeys = [
|
|
302
|
-
{
|
|
303
|
-
key: result.requestPubKey,
|
|
304
|
-
signature: result.signature
|
|
305
|
-
}
|
|
306
|
-
];
|
|
291
|
+
async fetchCopayerLookup(copayerId: string): Promise<Copayer | undefined> {
|
|
292
|
+
const result = await this.db.collection(collections.COPAYERS_LOOKUP).findOne({ copayerId });
|
|
293
|
+
if (!result) return;
|
|
294
|
+
if (!result.requestPubKeys) {
|
|
295
|
+
result.requestPubKeys = [
|
|
296
|
+
{
|
|
297
|
+
key: result.requestPubKey,
|
|
298
|
+
signature: result.signature
|
|
307
299
|
}
|
|
300
|
+
];
|
|
301
|
+
}
|
|
308
302
|
|
|
309
|
-
|
|
310
|
-
}
|
|
311
|
-
);
|
|
303
|
+
return Copayer.fromObj(result);
|
|
312
304
|
}
|
|
313
305
|
|
|
314
306
|
// TODO: should be done client-side
|
|
@@ -1806,16 +1798,48 @@ export class Storage {
|
|
|
1806
1798
|
return this.db.collection(collections.TSS_KEYGEN).insertOne(doc);
|
|
1807
1799
|
}
|
|
1808
1800
|
|
|
1809
|
-
async
|
|
1810
|
-
|
|
1811
|
-
{ id },
|
|
1801
|
+
async storeTssKeyGenAuthPublicKey({ id, partyId, authPublicKey, __v }: { id: string; partyId: number; authPublicKey: string; __v: number }) {
|
|
1802
|
+
const result = await this.db.collection(collections.TSS_KEYGEN).updateOne(
|
|
1803
|
+
{ id, __v },
|
|
1804
|
+
{
|
|
1805
|
+
$set: {
|
|
1806
|
+
[`authPublicKeys.${partyId}`]: authPublicKey
|
|
1807
|
+
},
|
|
1808
|
+
$inc: {
|
|
1809
|
+
__v: 1
|
|
1810
|
+
}
|
|
1811
|
+
},
|
|
1812
|
+
{ upsert: false }
|
|
1813
|
+
);
|
|
1814
|
+
if (!result.matchedCount) {
|
|
1815
|
+
if ((await this.db.collection(collections.TSS_KEYGEN).countDocuments({ id })) === 0) {
|
|
1816
|
+
throw new Error('MONGO_DOC_NOT_FOUND: No document found for id ' + id);
|
|
1817
|
+
}
|
|
1818
|
+
throw new Error('MONGO_DOC_OUTDATED: No document found for version ' + __v);
|
|
1819
|
+
}
|
|
1820
|
+
return result;
|
|
1821
|
+
}
|
|
1822
|
+
|
|
1823
|
+
async storeTssKeyGenParticipant({ id, partyId, copayerId, __v }: { id: string; partyId: number; copayerId: string; __v: number }) {
|
|
1824
|
+
const result = await this.db.collection(collections.TSS_KEYGEN).updateOne(
|
|
1825
|
+
{ id, __v },
|
|
1812
1826
|
{
|
|
1813
1827
|
$set: {
|
|
1814
1828
|
[`participants.${partyId}`]: copayerId
|
|
1829
|
+
},
|
|
1830
|
+
$inc: {
|
|
1831
|
+
__v: 1
|
|
1815
1832
|
}
|
|
1816
1833
|
},
|
|
1817
1834
|
{ upsert: false }
|
|
1818
1835
|
);
|
|
1836
|
+
if (!result.matchedCount) {
|
|
1837
|
+
if ((await this.db.collection(collections.TSS_KEYGEN).countDocuments({ id })) === 0) {
|
|
1838
|
+
throw new Error('MONGO_DOC_NOT_FOUND: No document found for id ' + id);
|
|
1839
|
+
}
|
|
1840
|
+
throw new Error('MONGO_DOC_OUTDATED: No document found for version ' + __v);
|
|
1841
|
+
}
|
|
1842
|
+
return result;
|
|
1819
1843
|
}
|
|
1820
1844
|
|
|
1821
1845
|
async storeTssKeyGenMessage({ id, message, __v }: { id: string; message: ITssKeyMessageObject; __v: number }) {
|
|
@@ -1835,6 +1859,9 @@ export class Storage {
|
|
|
1835
1859
|
{ upsert: false }
|
|
1836
1860
|
);
|
|
1837
1861
|
if (!result.matchedCount) {
|
|
1862
|
+
if ((await this.db.collection(collections.TSS_KEYGEN).countDocuments({ id })) === 0) {
|
|
1863
|
+
throw new Error('MONGO_DOC_NOT_FOUND: No document found for id ' + id);
|
|
1864
|
+
}
|
|
1838
1865
|
throw new Error('MONGO_DOC_OUTDATED: No document found for version ' + __v);
|
|
1839
1866
|
}
|
|
1840
1867
|
return result;
|
|
@@ -1902,6 +1929,9 @@ export class Storage {
|
|
|
1902
1929
|
{ upsert: false }
|
|
1903
1930
|
);
|
|
1904
1931
|
if (!result.matchedCount) {
|
|
1932
|
+
if ((await this.db.collection(collections.TSS_SIGN).countDocuments({ id })) === 0) {
|
|
1933
|
+
throw new Error('MONGO_DOC_NOT_FOUND: No document found for id ' + id);
|
|
1934
|
+
}
|
|
1905
1935
|
throw new Error('MONGO_DOC_OUTDATED: No document found for version ' + __v);
|
|
1906
1936
|
}
|
|
1907
1937
|
return result;
|
|
@@ -1924,6 +1954,9 @@ export class Storage {
|
|
|
1924
1954
|
{ upsert: false }
|
|
1925
1955
|
);
|
|
1926
1956
|
if (!result.matchedCount) {
|
|
1957
|
+
if ((await this.db.collection(collections.TSS_SIGN).countDocuments({ id })) === 0) {
|
|
1958
|
+
throw new Error('MONGO_DOC_NOT_FOUND: No document found for id ' + id);
|
|
1959
|
+
}
|
|
1927
1960
|
throw new Error('MONGO_DOC_OUTDATED: No document found for version ' + __v);
|
|
1928
1961
|
}
|
|
1929
1962
|
return result;
|
package/src/lib/tss.ts
CHANGED
|
@@ -155,6 +155,57 @@ class TssKeyGenClass {
|
|
|
155
155
|
return session;
|
|
156
156
|
}
|
|
157
157
|
|
|
158
|
+
async registerParty(params: {
|
|
159
|
+
/** Session ID */
|
|
160
|
+
id: string;
|
|
161
|
+
/** Copayer ID of the requesting party */
|
|
162
|
+
copayerId: string;
|
|
163
|
+
/* Copayer data to register */
|
|
164
|
+
data: {
|
|
165
|
+
/** Party ID */
|
|
166
|
+
partyId: string | number;
|
|
167
|
+
/** Public key/Copayer ID of the party */
|
|
168
|
+
partyPubKey: string;
|
|
169
|
+
};
|
|
170
|
+
}) {
|
|
171
|
+
const { id, copayerId, data } = params;
|
|
172
|
+
|
|
173
|
+
const session = await this.getSessionForCopayer({ id, copayerId });
|
|
174
|
+
const reqPartyId = session.participants.indexOf(copayerId);
|
|
175
|
+
if (reqPartyId !== 0) {
|
|
176
|
+
throw Errors.TSS_NON_PARTICIPANT.withMessage('Only the first participant can register a party');
|
|
177
|
+
}
|
|
178
|
+
|
|
179
|
+
if (data.partyId == null || isNaN(data.partyId as number)) {
|
|
180
|
+
throw Errors.TSS_INVALID_PARTY_DATA.withMessage(`Invalid partyId: ${data.partyId}`);
|
|
181
|
+
}
|
|
182
|
+
|
|
183
|
+
const partyId = parseInt(data.partyId as string);
|
|
184
|
+
const pubKey = data.partyPubKey?.trim();
|
|
185
|
+
|
|
186
|
+
if (!(partyId > 0) || !pubKey || pubKey === copayerId || partyId >= session.n) {
|
|
187
|
+
throw Errors.TSS_INVALID_PARTY_DATA.withMessage(`Invalid data for party ${partyId} registration`);
|
|
188
|
+
}
|
|
189
|
+
|
|
190
|
+
if (session.authPublicKeys.includes(pubKey)) {
|
|
191
|
+
if (session.authPublicKeys.indexOf(pubKey) === partyId) {
|
|
192
|
+
// Already registered at partyId -> return idempotently
|
|
193
|
+
return;
|
|
194
|
+
} else {
|
|
195
|
+
// Trying to re-register a party that is already registered under a different party ID
|
|
196
|
+
throw Errors.TSS_PARTY_ALREADY_REGISTERED;
|
|
197
|
+
}
|
|
198
|
+
}
|
|
199
|
+
|
|
200
|
+
// Has party already submitted initial rounds message? (case when this is a re-register)
|
|
201
|
+
if (session.rounds?.[0]?.some(round => round.fromPartyId === partyId)) {
|
|
202
|
+
throw Errors.TSS_ROUNDS_ALREADY_STARTED.withMessage(`Party ${partyId} has already submitted an initial message. Cannot register a new party ${partyId}`);
|
|
203
|
+
}
|
|
204
|
+
|
|
205
|
+
const storage = WalletService.getStorage();
|
|
206
|
+
await storage.storeTssKeyGenAuthPublicKey({ id, partyId, authPublicKey: pubKey, __v: session.__v });
|
|
207
|
+
}
|
|
208
|
+
|
|
158
209
|
/**
|
|
159
210
|
* Get messages for a given party in a TSS keygen session.
|
|
160
211
|
* Only returns messages if all other parties have sent their messages for the round.
|
|
@@ -279,10 +330,29 @@ class TssKeyGenClass {
|
|
|
279
330
|
|
|
280
331
|
|
|
281
332
|
if (!session.participants[message.partyId]) {
|
|
333
|
+
if (session.participants.includes(copayerId)) {
|
|
334
|
+
throw Errors.TSS_PARTY_ALREADY_REGISTERED;
|
|
335
|
+
}
|
|
282
336
|
if (!this._checkPassword({ session, password })) {
|
|
283
337
|
throw Errors.TSS_INVALID_PASSWORD;
|
|
284
338
|
}
|
|
285
|
-
|
|
339
|
+
// Sanity check for the public key of the participant in the session
|
|
340
|
+
// session.authPublicKeys was not added until version 1.2
|
|
341
|
+
if (session.schemeVersion >= 1.2 && session.authPublicKeys[message.partyId] !== message.publicKey) {
|
|
342
|
+
throw Errors.NOT_AUTHORIZED;
|
|
343
|
+
}
|
|
344
|
+
try {
|
|
345
|
+
await storage.storeTssKeyGenParticipant({ id, partyId: message.partyId, copayerId, __v: session.__v });
|
|
346
|
+
} catch (e) {
|
|
347
|
+
if (e?.message?.startsWith('MONGO_DOC_OUTDATED')) {
|
|
348
|
+
return this.processMessage(params);
|
|
349
|
+
} else if (e?.message?.startsWith('MONGO_DOC_NOT_FOUND')) {
|
|
350
|
+
throw Errors.TSS_SESSION_NOT_FOUND;
|
|
351
|
+
}
|
|
352
|
+
throw e;
|
|
353
|
+
}
|
|
354
|
+
} else if (session.participants[message.partyId] !== copayerId) {
|
|
355
|
+
throw Errors.TSS_NON_PARTICIPANT.withMessage('Incorrect copayerId for this partyId');
|
|
286
356
|
}
|
|
287
357
|
|
|
288
358
|
let result = false;
|
|
@@ -427,6 +497,8 @@ class TssKeyGenClass {
|
|
|
427
497
|
} catch (e) {
|
|
428
498
|
if (e?.message?.startsWith('MONGO_DOC_OUTDATED')) {
|
|
429
499
|
return false;
|
|
500
|
+
} else if (e?.message?.startsWith('MONGO_DOC_NOT_FOUND')) {
|
|
501
|
+
throw Errors.TSS_SESSION_NOT_FOUND;
|
|
430
502
|
}
|
|
431
503
|
throw e;
|
|
432
504
|
}
|
|
@@ -694,6 +766,8 @@ class TssSignClass {
|
|
|
694
766
|
} catch (e) {
|
|
695
767
|
if (e?.message?.startsWith('MONGO_DOC_OUTDATED')) {
|
|
696
768
|
return this.processMessage(params);
|
|
769
|
+
} else if (e?.message?.startsWith('MONGO_DOC_NOT_FOUND')) {
|
|
770
|
+
throw Errors.TSS_SESSION_NOT_FOUND;
|
|
697
771
|
}
|
|
698
772
|
throw e;
|
|
699
773
|
}
|
|
@@ -814,6 +888,8 @@ class TssSignClass {
|
|
|
814
888
|
} catch (e) {
|
|
815
889
|
if (e?.message?.startsWith('MONGO_DOC_OUTDATED')) {
|
|
816
890
|
return false;
|
|
891
|
+
} else if (e?.message?.startsWith('MONGO_DOC_NOT_FOUND')) {
|
|
892
|
+
throw Errors.TSS_SESSION_NOT_FOUND;
|
|
817
893
|
}
|
|
818
894
|
throw e;
|
|
819
895
|
}
|