@abtnode/auth 1.7.3 → 1.7.6
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/auth.js +2 -2
- package/lib/lost-passport.js +4 -6
- package/lib/server.js +373 -0
- package/lib/util/get-auth-method.js +21 -0
- package/package.json +12 -11
package/lib/auth.js
CHANGED
|
@@ -642,8 +642,8 @@ const getVCFromClaims = async ({ claims, challenge, trustedIssuers, vcTypes, loc
|
|
|
642
642
|
};
|
|
643
643
|
};
|
|
644
644
|
|
|
645
|
-
const checkWalletVersion = ({
|
|
646
|
-
const { os, version } =
|
|
645
|
+
const checkWalletVersion = ({ didwallet, locale = 'en' }) => {
|
|
646
|
+
const { os, version } = didwallet;
|
|
647
647
|
|
|
648
648
|
const defaultExpected = '3.0.0';
|
|
649
649
|
|
package/lib/lost-passport.js
CHANGED
|
@@ -85,7 +85,7 @@ const createLostPassportListRoute = ({ node, type }) => ({
|
|
|
85
85
|
},
|
|
86
86
|
},
|
|
87
87
|
|
|
88
|
-
onAuth: async ({ userDid, extraParams,
|
|
88
|
+
onAuth: async ({ userDid, extraParams, updateSession, req }) => {
|
|
89
89
|
const { locale } = extraParams;
|
|
90
90
|
|
|
91
91
|
const { teamDid, issuerDid } = await getTeamInfo({ node, req, type });
|
|
@@ -125,9 +125,7 @@ const createLostPassportListRoute = ({ node, type }) => ({
|
|
|
125
125
|
|
|
126
126
|
logger.info('get passport type list', { userDid });
|
|
127
127
|
|
|
128
|
-
await
|
|
129
|
-
user,
|
|
130
|
-
});
|
|
128
|
+
await updateSession({ user });
|
|
131
129
|
},
|
|
132
130
|
});
|
|
133
131
|
|
|
@@ -149,9 +147,9 @@ const createLostPassportIssueRoute = ({ node, type, authServicePrefix }) => ({
|
|
|
149
147
|
},
|
|
150
148
|
},
|
|
151
149
|
{
|
|
152
|
-
signature: async ({ extraParams, context: { request,
|
|
150
|
+
signature: async ({ extraParams, context: { request, didwallet } }) => {
|
|
153
151
|
const { locale, passportName, receiverDid } = extraParams;
|
|
154
|
-
checkWalletVersion({
|
|
152
|
+
checkWalletVersion({ didwallet, locale });
|
|
155
153
|
|
|
156
154
|
const { teamDid, issuerDid, issuerName, passportColor } = await getTeamInfo({ node, req: request, type });
|
|
157
155
|
const user = await getUser(node, teamDid, receiverDid);
|
package/lib/server.js
ADDED
|
@@ -0,0 +1,373 @@
|
|
|
1
|
+
const get = require('lodash/get');
|
|
2
|
+
const last = require('lodash/last');
|
|
3
|
+
const Client = require('@ocap/client');
|
|
4
|
+
const { fromPublicKey } = require('@ocap/wallet');
|
|
5
|
+
const { fromBase58, toAddress } = require('@ocap/util');
|
|
6
|
+
const { toTypeInfo, isFromPublicKey } = require('@arcblock/did');
|
|
7
|
+
const semver = require('semver');
|
|
8
|
+
const {
|
|
9
|
+
ROLES,
|
|
10
|
+
VC_TYPE_GENERAL_PASSPORT,
|
|
11
|
+
VC_TYPE_NODE_PASSPORT,
|
|
12
|
+
VC_TYPE_BLOCKLET_PURCHASE,
|
|
13
|
+
NFT_TYPE_SERVER_OWNERSHIP,
|
|
14
|
+
} = require('@abtnode/constant');
|
|
15
|
+
const {
|
|
16
|
+
messages,
|
|
17
|
+
getVCFromClaims,
|
|
18
|
+
getUser,
|
|
19
|
+
validatePassportStatus,
|
|
20
|
+
createAuthToken,
|
|
21
|
+
createAuthTokenByOwnershipNFT,
|
|
22
|
+
checkWalletVersion,
|
|
23
|
+
} = require('./auth');
|
|
24
|
+
const {
|
|
25
|
+
validatePassport,
|
|
26
|
+
isUserPassportRevoked,
|
|
27
|
+
getRoleFromLocalPassport,
|
|
28
|
+
getRoleFromExternalPassport,
|
|
29
|
+
createUserPassport,
|
|
30
|
+
} = require('./passport');
|
|
31
|
+
|
|
32
|
+
const logger = require('./logger');
|
|
33
|
+
|
|
34
|
+
const secret = process.env.ABT_NODE_SESSION_SECRET;
|
|
35
|
+
const LAUNCH_BLOCKLET_TOKEN_EXPIRE = '1d';
|
|
36
|
+
const abtnodeVcTypes = [VC_TYPE_GENERAL_PASSPORT, VC_TYPE_NODE_PASSPORT];
|
|
37
|
+
const blockletVcTypes = [VC_TYPE_BLOCKLET_PURCHASE];
|
|
38
|
+
|
|
39
|
+
const authenticateByVc = async ({ node, locale, userDid, claims, challenge, requireNodeInitialized = true }) => {
|
|
40
|
+
if (requireNodeInitialized) {
|
|
41
|
+
if ((await node.isInitialized()) === false) {
|
|
42
|
+
throw new Error(messages.notInitialized[locale]);
|
|
43
|
+
}
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
const info = await node.getNodeInfo();
|
|
47
|
+
const teamDid = info.did;
|
|
48
|
+
const { name } = info;
|
|
49
|
+
|
|
50
|
+
// check user approved
|
|
51
|
+
const user = await getUser(node, teamDid, userDid);
|
|
52
|
+
if (user && !user.approved) {
|
|
53
|
+
throw new Error(messages.notAllowed[locale]);
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
// Get passport
|
|
57
|
+
const trustedPassports = (info.trustedPassports || []).map((x) => x.issuerDid);
|
|
58
|
+
const trustedIssuers = [info.did, ...trustedPassports].filter(Boolean);
|
|
59
|
+
const { vc, types: passportTypes } = await getVCFromClaims({
|
|
60
|
+
claims,
|
|
61
|
+
challenge,
|
|
62
|
+
trustedIssuers,
|
|
63
|
+
vcTypes: abtnodeVcTypes,
|
|
64
|
+
locale,
|
|
65
|
+
});
|
|
66
|
+
|
|
67
|
+
if (!vc) {
|
|
68
|
+
throw new Error(messages.missingCredentialClaim[locale]);
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
// Get user passport from vc
|
|
72
|
+
let passport = createUserPassport(vc);
|
|
73
|
+
if (user && isUserPassportRevoked(user, passport)) {
|
|
74
|
+
throw new Error(messages.passportRevoked[locale](name));
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
// Get role from vc
|
|
78
|
+
let role;
|
|
79
|
+
if (passportTypes.some((x) => [VC_TYPE_GENERAL_PASSPORT].includes(x))) {
|
|
80
|
+
await validatePassport(get(vc, 'credentialSubject.passport'));
|
|
81
|
+
const issuerId = get(vc, 'issuer.id');
|
|
82
|
+
if (issuerId === teamDid) {
|
|
83
|
+
role = getRoleFromLocalPassport(get(vc, 'credentialSubject.passport'));
|
|
84
|
+
} else {
|
|
85
|
+
// map external passport to local role
|
|
86
|
+
const { mappings = [] } = (info.trustedPassports || []).find((x) => x.issuerDid === issuerId) || {};
|
|
87
|
+
role = await getRoleFromExternalPassport({
|
|
88
|
+
passport: get(vc, 'credentialSubject.passport'),
|
|
89
|
+
node,
|
|
90
|
+
teamDid,
|
|
91
|
+
locale,
|
|
92
|
+
mappings,
|
|
93
|
+
});
|
|
94
|
+
|
|
95
|
+
// check status of external passport if passport has an endpoint
|
|
96
|
+
const endpoint = get(vc, 'credentialStatus.id');
|
|
97
|
+
if (endpoint) {
|
|
98
|
+
if (endpoint) {
|
|
99
|
+
await validatePassportStatus({ vcId: vc.id, endpoint, locale });
|
|
100
|
+
}
|
|
101
|
+
}
|
|
102
|
+
}
|
|
103
|
+
} else if (passportTypes.some((x) => [NFT_TYPE_SERVER_OWNERSHIP].includes(x))) {
|
|
104
|
+
role = ROLES.OWNER;
|
|
105
|
+
} else {
|
|
106
|
+
logger.error('cannot get role from passport, use "guest" for default', { passportTypes, vcId: vc.id });
|
|
107
|
+
role = ROLES.GUEST;
|
|
108
|
+
}
|
|
109
|
+
|
|
110
|
+
// Recreate passport with correct role
|
|
111
|
+
passport = createUserPassport(vc, { role });
|
|
112
|
+
|
|
113
|
+
return { role, user, teamDid, passport };
|
|
114
|
+
};
|
|
115
|
+
|
|
116
|
+
const authenticateByNFT = async ({ node, claims, userDid, challenge, locale }) => {
|
|
117
|
+
const info = await node.getNodeInfo();
|
|
118
|
+
const client = new Client(info.launcher.chainHost);
|
|
119
|
+
|
|
120
|
+
const claim = claims.find((x) => x.type === 'asset');
|
|
121
|
+
if (!claim) {
|
|
122
|
+
throw new Error(messages.missingNftClaim[locale]);
|
|
123
|
+
}
|
|
124
|
+
|
|
125
|
+
const fields = ['asset', 'ownerProof', 'ownerPk', 'ownerDid'];
|
|
126
|
+
for (const field of fields) {
|
|
127
|
+
if (!claim[field]) {
|
|
128
|
+
throw new Error(messages.invalidNftClaim[locale]);
|
|
129
|
+
}
|
|
130
|
+
}
|
|
131
|
+
|
|
132
|
+
const address = claim.asset;
|
|
133
|
+
const ownerDid = toAddress(claim.ownerDid);
|
|
134
|
+
const ownerPk = fromBase58(claim.ownerPk);
|
|
135
|
+
const ownerProof = fromBase58(claim.ownerProof);
|
|
136
|
+
if (isFromPublicKey(ownerDid, ownerPk) === false) {
|
|
137
|
+
throw new Error(messages.invalidNftHolder[locale]);
|
|
138
|
+
}
|
|
139
|
+
|
|
140
|
+
const owner = fromPublicKey(ownerPk, toTypeInfo(ownerDid));
|
|
141
|
+
if (owner.verify(challenge, ownerProof) === false) {
|
|
142
|
+
throw new Error(messages.invalidNftProof[locale]);
|
|
143
|
+
}
|
|
144
|
+
|
|
145
|
+
const { state } = await client.getAssetState({ address }, { ignoreFields: ['context'] });
|
|
146
|
+
if (!state) {
|
|
147
|
+
throw new Error(messages.invalidNft[locale]);
|
|
148
|
+
}
|
|
149
|
+
if (state.owner !== ownerDid || state.owner !== info.ownerNft.holder) {
|
|
150
|
+
throw new Error(messages.invalidNftHolder[locale]);
|
|
151
|
+
}
|
|
152
|
+
if (state.issuer !== info.launcher.did) {
|
|
153
|
+
throw new Error(messages.invalidNftIssuer[locale]);
|
|
154
|
+
}
|
|
155
|
+
|
|
156
|
+
// enforce tag match
|
|
157
|
+
if (last(state.tags) !== info.launcher.tag) {
|
|
158
|
+
throw new Error(messages.tagNotMatch[locale]);
|
|
159
|
+
}
|
|
160
|
+
|
|
161
|
+
const user = await getUser(node, info.did, userDid);
|
|
162
|
+
return { role: ROLES.OWNER, teamDid: info.did, nft: state, user, passport: null };
|
|
163
|
+
};
|
|
164
|
+
|
|
165
|
+
const getAuthVcClaim =
|
|
166
|
+
(node) =>
|
|
167
|
+
async ({ extraParams: { locale }, context: { didwallet } }) => {
|
|
168
|
+
checkWalletVersion({ didwallet, locale });
|
|
169
|
+
const info = await node.getNodeInfo();
|
|
170
|
+
const trustedPassports = (info.trustedPassports || []).map((x) => x.issuerDid);
|
|
171
|
+
const trustedIssuers = [info.did, ...trustedPassports].filter(Boolean);
|
|
172
|
+
return {
|
|
173
|
+
description: messages.requestPassport[locale],
|
|
174
|
+
optional: false,
|
|
175
|
+
item: abtnodeVcTypes,
|
|
176
|
+
trustedIssuers,
|
|
177
|
+
};
|
|
178
|
+
};
|
|
179
|
+
|
|
180
|
+
const getLaunchFreeBlockletClaims = (node, authMethod) => {
|
|
181
|
+
if (authMethod === 'vc') {
|
|
182
|
+
return {
|
|
183
|
+
serverPassport: ['verifiableCredential', getAuthVcClaim(node)],
|
|
184
|
+
};
|
|
185
|
+
}
|
|
186
|
+
|
|
187
|
+
return {
|
|
188
|
+
serverNFT: [
|
|
189
|
+
'asset',
|
|
190
|
+
async ({ extraParams: { locale }, context: { didwallet } }) => {
|
|
191
|
+
checkWalletVersion({ didwallet, locale });
|
|
192
|
+
return getOwnershipNFTClaim(node, locale);
|
|
193
|
+
},
|
|
194
|
+
],
|
|
195
|
+
};
|
|
196
|
+
};
|
|
197
|
+
|
|
198
|
+
const getLaunchPaidBlockletClaims = (node, authMethod) => {
|
|
199
|
+
const claims = getLaunchFreeBlockletClaims(node, authMethod);
|
|
200
|
+
|
|
201
|
+
claims.blockletPurchaseNft = [
|
|
202
|
+
'verifiableCredential',
|
|
203
|
+
async ({ extraParams: { locale, blockletMetaUrl }, context: { didwallet } }) => {
|
|
204
|
+
checkWalletVersion({ didwallet, locale });
|
|
205
|
+
const registryUrl = new URL(blockletMetaUrl).origin;
|
|
206
|
+
const [registry, { meta }] = await Promise.all([
|
|
207
|
+
node.getRegistryMeta(registryUrl),
|
|
208
|
+
node.getBlockletMetaFromUrl({ url: blockletMetaUrl }),
|
|
209
|
+
]);
|
|
210
|
+
|
|
211
|
+
return {
|
|
212
|
+
description: messages.requestBlockletNft[locale],
|
|
213
|
+
item: blockletVcTypes,
|
|
214
|
+
trustedIssuers: [registry.id],
|
|
215
|
+
tag: meta.did,
|
|
216
|
+
};
|
|
217
|
+
},
|
|
218
|
+
];
|
|
219
|
+
|
|
220
|
+
return claims;
|
|
221
|
+
};
|
|
222
|
+
|
|
223
|
+
const getOwnershipNFTClaim = async (node, locale) => {
|
|
224
|
+
const info = await node.getNodeInfo();
|
|
225
|
+
if (!info.ownerNft && !info.ownerNft.holder && !info.ownerNft.issuer) {
|
|
226
|
+
throw new Error(messages.noNft[locale]);
|
|
227
|
+
}
|
|
228
|
+
|
|
229
|
+
const tag = get(info, 'launcher.tag', '');
|
|
230
|
+
const chainHost = get(info, 'launcher.chainHost', '');
|
|
231
|
+
if (!tag) {
|
|
232
|
+
throw new Error(messages.noTag[locale]);
|
|
233
|
+
}
|
|
234
|
+
if (!chainHost) {
|
|
235
|
+
throw new Error(messages.noChainHost[locale]);
|
|
236
|
+
}
|
|
237
|
+
|
|
238
|
+
return {
|
|
239
|
+
description: messages.requestNft[locale],
|
|
240
|
+
trustedIssuers: [info.ownerNft.issuer],
|
|
241
|
+
tag, // tag is an unique identifier for the server in launcher
|
|
242
|
+
};
|
|
243
|
+
};
|
|
244
|
+
|
|
245
|
+
const ensureBlockletPermission = async ({ authMethod, node, userDid, claims, challenge, locale }) => {
|
|
246
|
+
let result;
|
|
247
|
+
if (authMethod === 'vc') {
|
|
248
|
+
result = await authenticateByVc({
|
|
249
|
+
node,
|
|
250
|
+
userDid,
|
|
251
|
+
claims,
|
|
252
|
+
challenge,
|
|
253
|
+
requireNodeInitialized: false,
|
|
254
|
+
locale,
|
|
255
|
+
});
|
|
256
|
+
} else {
|
|
257
|
+
result = await authenticateByNFT({
|
|
258
|
+
node,
|
|
259
|
+
locale,
|
|
260
|
+
userDid,
|
|
261
|
+
claims,
|
|
262
|
+
challenge,
|
|
263
|
+
});
|
|
264
|
+
}
|
|
265
|
+
const { teamDid, role } = result;
|
|
266
|
+
|
|
267
|
+
const permissions = await node.getPermissionsByRole({ teamDid, role: { name: role } });
|
|
268
|
+
if (!permissions.some((item) => item.name === 'mutate_blocklet')) {
|
|
269
|
+
throw new Error(messages.notAuthorized[locale]);
|
|
270
|
+
}
|
|
271
|
+
|
|
272
|
+
return result;
|
|
273
|
+
};
|
|
274
|
+
|
|
275
|
+
const createLaunchBlockletHandler =
|
|
276
|
+
(node, authMethod) =>
|
|
277
|
+
async ({ claims, challenge, userDid, updateSession, extraParams: { locale, blockletMetaUrl } }) => {
|
|
278
|
+
if (!blockletMetaUrl) {
|
|
279
|
+
throw new Error(messages.invalidParams[locale]);
|
|
280
|
+
}
|
|
281
|
+
|
|
282
|
+
const { role, passport } = await ensureBlockletPermission({ authMethod, node, userDid, claims, challenge, locale });
|
|
283
|
+
|
|
284
|
+
const result = await node.getBlockletMetaFromUrl({ url: blockletMetaUrl, checkPrice: true });
|
|
285
|
+
if (!result.meta) {
|
|
286
|
+
throw new Error(messages.invalidBlocklet[locale]);
|
|
287
|
+
}
|
|
288
|
+
|
|
289
|
+
const { did } = result.meta;
|
|
290
|
+
|
|
291
|
+
let blockletPurchaseVerified;
|
|
292
|
+
if (!result.isFree) {
|
|
293
|
+
const registryUrl = new URL(blockletMetaUrl).origin;
|
|
294
|
+
const registryMeta = await node.getRegistryMeta(registryUrl);
|
|
295
|
+
|
|
296
|
+
const { vc: blockletVc } = await getVCFromClaims({
|
|
297
|
+
claims,
|
|
298
|
+
challenge,
|
|
299
|
+
trustedIssuers: [registryMeta.id],
|
|
300
|
+
vcTypes: blockletVcTypes,
|
|
301
|
+
locale,
|
|
302
|
+
});
|
|
303
|
+
|
|
304
|
+
if (!blockletVc) {
|
|
305
|
+
throw new Error(messages.missingBlockletCredentialClaim[locale]);
|
|
306
|
+
}
|
|
307
|
+
|
|
308
|
+
if (get(blockletVc, 'credentialSubject.purchased.blocklet.id') !== did) {
|
|
309
|
+
throw new Error(messages.invalidBlockletVc[locale]);
|
|
310
|
+
}
|
|
311
|
+
|
|
312
|
+
blockletPurchaseVerified = true;
|
|
313
|
+
}
|
|
314
|
+
|
|
315
|
+
let sessionToken = '';
|
|
316
|
+
if (authMethod === 'vc') {
|
|
317
|
+
sessionToken = createAuthToken({
|
|
318
|
+
did: userDid,
|
|
319
|
+
passport,
|
|
320
|
+
role,
|
|
321
|
+
secret,
|
|
322
|
+
expiresIn: LAUNCH_BLOCKLET_TOKEN_EXPIRE,
|
|
323
|
+
});
|
|
324
|
+
} else {
|
|
325
|
+
sessionToken = createAuthTokenByOwnershipNFT({
|
|
326
|
+
did: userDid,
|
|
327
|
+
role,
|
|
328
|
+
secret,
|
|
329
|
+
expiresIn: LAUNCH_BLOCKLET_TOKEN_EXPIRE,
|
|
330
|
+
});
|
|
331
|
+
}
|
|
332
|
+
|
|
333
|
+
// 检查是否已安装,这里不做升级的处理
|
|
334
|
+
const existedBlocklet = await node.getBlocklet({ did });
|
|
335
|
+
await updateSession({ sessionToken }, true);
|
|
336
|
+
|
|
337
|
+
if (existedBlocklet) {
|
|
338
|
+
const storageData = { did: userDid };
|
|
339
|
+
|
|
340
|
+
if (semver.gt(result.meta.version, existedBlocklet.meta.version)) {
|
|
341
|
+
const appDidEnv = existedBlocklet.environments.find((e) => e.key === 'BLOCKLET_APP_ID');
|
|
342
|
+
storageData.upgradeAvailable = {
|
|
343
|
+
appDid: appDidEnv ? appDidEnv.value : '',
|
|
344
|
+
did: existedBlocklet.meta.did,
|
|
345
|
+
currentVersion: existedBlocklet.meta.version,
|
|
346
|
+
version: result.meta.version,
|
|
347
|
+
};
|
|
348
|
+
}
|
|
349
|
+
|
|
350
|
+
await updateSession(storageData);
|
|
351
|
+
logger.info('blocklet already exists', { did });
|
|
352
|
+
return;
|
|
353
|
+
}
|
|
354
|
+
|
|
355
|
+
const context = {};
|
|
356
|
+
if (typeof blockletPurchaseVerified !== 'undefined') {
|
|
357
|
+
context.blockletPurchaseVerified = blockletPurchaseVerified;
|
|
358
|
+
}
|
|
359
|
+
|
|
360
|
+
await node.installBlocklet({ url: blockletMetaUrl }, context);
|
|
361
|
+
logger.info('start install blocklet', { did });
|
|
362
|
+
};
|
|
363
|
+
|
|
364
|
+
module.exports = {
|
|
365
|
+
getAuthVcClaim,
|
|
366
|
+
authenticateByVc,
|
|
367
|
+
authenticateByNFT,
|
|
368
|
+
getOwnershipNFTClaim,
|
|
369
|
+
getLaunchFreeBlockletClaims,
|
|
370
|
+
getLaunchPaidBlockletClaims,
|
|
371
|
+
createLaunchBlockletHandler,
|
|
372
|
+
ensureBlockletPermission,
|
|
373
|
+
};
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
const get = require('lodash/get');
|
|
2
|
+
|
|
3
|
+
const getServerAuthMethod = (info) => {
|
|
4
|
+
if (info.initialized) {
|
|
5
|
+
return 'vc';
|
|
6
|
+
}
|
|
7
|
+
|
|
8
|
+
if (
|
|
9
|
+
get(info, 'ownerNft.holder') &&
|
|
10
|
+
get(info, 'ownerNft.issuer') &&
|
|
11
|
+
get(info, 'launcher.tag') &&
|
|
12
|
+
get(info, 'launcher.chainHost') &&
|
|
13
|
+
get(info, 'launcher.did') === get(info, 'ownerNft.issuer')
|
|
14
|
+
) {
|
|
15
|
+
return 'nft';
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
return 'vc';
|
|
19
|
+
};
|
|
20
|
+
|
|
21
|
+
module.exports = { getServerAuthMethod };
|
package/package.json
CHANGED
|
@@ -3,7 +3,7 @@
|
|
|
3
3
|
"publishConfig": {
|
|
4
4
|
"access": "public"
|
|
5
5
|
},
|
|
6
|
-
"version": "1.7.
|
|
6
|
+
"version": "1.7.6",
|
|
7
7
|
"description": "Simple lib to manage auth in ABT Node",
|
|
8
8
|
"main": "lib/index.js",
|
|
9
9
|
"files": [
|
|
@@ -20,15 +20,16 @@
|
|
|
20
20
|
"author": "linchen <linchen1987@foxmail.com> (http://github.com/linchen1987)",
|
|
21
21
|
"license": "MIT",
|
|
22
22
|
"dependencies": {
|
|
23
|
-
"@abtnode/constant": "1.7.
|
|
24
|
-
"@abtnode/logger": "1.7.
|
|
25
|
-
"@abtnode/util": "1.7.
|
|
26
|
-
"@arcblock/did": "^1.
|
|
27
|
-
"@arcblock/vc": "^1.
|
|
28
|
-
"@blocklet/meta": "1.7.
|
|
29
|
-
"@ocap/
|
|
30
|
-
"@ocap/
|
|
31
|
-
"@ocap/
|
|
23
|
+
"@abtnode/constant": "1.7.6",
|
|
24
|
+
"@abtnode/logger": "1.7.6",
|
|
25
|
+
"@abtnode/util": "1.7.6",
|
|
26
|
+
"@arcblock/did": "^1.16.0",
|
|
27
|
+
"@arcblock/vc": "^1.16.0",
|
|
28
|
+
"@blocklet/meta": "1.7.6",
|
|
29
|
+
"@ocap/client": "1.16.0",
|
|
30
|
+
"@ocap/mcrypto": "^1.16.0",
|
|
31
|
+
"@ocap/util": "^1.16.0",
|
|
32
|
+
"@ocap/wallet": "^1.16.0",
|
|
32
33
|
"axios": "^0.25.0",
|
|
33
34
|
"joi": "^17.6.0",
|
|
34
35
|
"jsonwebtoken": "^8.5.1",
|
|
@@ -39,5 +40,5 @@
|
|
|
39
40
|
"devDependencies": {
|
|
40
41
|
"jest": "^27.4.5"
|
|
41
42
|
},
|
|
42
|
-
"gitHead": "
|
|
43
|
+
"gitHead": "47a9dbd6ea74419ff586336824ebb9b2fe7694aa"
|
|
43
44
|
}
|