@abtnode/auth 1.8.67-beta-794a8082 → 1.8.67
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 +3 -15
- package/lib/server.js +82 -169
- package/package.json +14 -15
package/lib/auth.js
CHANGED
|
@@ -156,18 +156,6 @@ const messages = {
|
|
|
156
156
|
en: 'Invalid Params',
|
|
157
157
|
zh: '无效的参数',
|
|
158
158
|
},
|
|
159
|
-
missingKeyPair: {
|
|
160
|
-
en: 'Missing app key pair',
|
|
161
|
-
zh: '缺少应用钥匙对',
|
|
162
|
-
},
|
|
163
|
-
missingBlockletUrl: {
|
|
164
|
-
en: 'Missing blocklet url',
|
|
165
|
-
zh: '缺少应用下载地址',
|
|
166
|
-
},
|
|
167
|
-
missingChainHost: {
|
|
168
|
-
en: 'Missing chain host',
|
|
169
|
-
zh: '缺少链的端点地址',
|
|
170
|
-
},
|
|
171
159
|
invalidBlocklet: {
|
|
172
160
|
en: 'Invalid Blocklet',
|
|
173
161
|
zh: '无效的 Blocklet',
|
|
@@ -821,9 +809,9 @@ const handleIssuePassportResponse = async ({
|
|
|
821
809
|
};
|
|
822
810
|
|
|
823
811
|
const getVCFromClaims = async ({ claims, challenge, trustedIssuers, vcTypes, locale = 'en', vcId }) => {
|
|
824
|
-
const credential = claims
|
|
825
|
-
|
|
826
|
-
|
|
812
|
+
const credential = claims.find(
|
|
813
|
+
(x) => x.type === 'verifiableCredential' && vcTypes.some((item) => x.item.includes(item))
|
|
814
|
+
);
|
|
827
815
|
|
|
828
816
|
if (!credential || !credential.presentation) {
|
|
829
817
|
return {};
|
package/lib/server.js
CHANGED
|
@@ -1,14 +1,11 @@
|
|
|
1
1
|
const get = require('lodash/get');
|
|
2
|
-
const pick = require('lodash/pick');
|
|
3
2
|
const isEmpty = require('lodash/isEmpty');
|
|
4
3
|
const last = require('lodash/last');
|
|
5
4
|
const { isNFTExpired, isNFTConsumed } = require('@abtnode/util/lib/nft');
|
|
6
5
|
const Client = require('@ocap/client');
|
|
7
6
|
const { fromPublicKey } = require('@ocap/wallet');
|
|
8
|
-
const { fromBase58, toAddress
|
|
7
|
+
const { fromBase58, toAddress } = require('@ocap/util');
|
|
9
8
|
const { toTypeInfo, isFromPublicKey } = require('@arcblock/did');
|
|
10
|
-
const urlFriendly = require('@blocklet/meta/lib/url-friendly').default;
|
|
11
|
-
const { slugify } = require('transliteration');
|
|
12
9
|
const formatContext = require('@abtnode/util/lib/format-context');
|
|
13
10
|
const {
|
|
14
11
|
ROLES,
|
|
@@ -222,15 +219,6 @@ const authenticateByNFT = async ({ node, claims, userDid, challenge, locale, isA
|
|
|
222
219
|
return { role: ROLES.OWNER, teamDid: info.did, nft: state, user, passport: null, ownerDid, ownerNFT: address };
|
|
223
220
|
};
|
|
224
221
|
|
|
225
|
-
const authenticateBySession = async ({ node, userDid }) => {
|
|
226
|
-
const info = await node.getNodeInfo();
|
|
227
|
-
const user = await getUser(node, info.did, userDid);
|
|
228
|
-
const passport = (user.passports || []).find(
|
|
229
|
-
(x) => x.status === 'valid' && ['owner', 'admin', 'member'].includes(x.role)
|
|
230
|
-
);
|
|
231
|
-
return { role: passport ? passport.role : ROLES.GUEST, teamDid: info.did, user, passport: null };
|
|
232
|
-
};
|
|
233
|
-
|
|
234
222
|
const getAuthVcClaim =
|
|
235
223
|
({ node, launchBlocklet, blocklet, options }) =>
|
|
236
224
|
async ({ extraParams: { locale, passportId }, context: { didwallet } }) => {
|
|
@@ -285,57 +273,28 @@ const getAuthNFTClaim =
|
|
|
285
273
|
return getOwnershipNFTClaim(node, locale);
|
|
286
274
|
};
|
|
287
275
|
|
|
288
|
-
const getKeyPairClaim =
|
|
289
|
-
() =>
|
|
290
|
-
async ({ extraParams: { locale, title }, context: { didwallet } }) => {
|
|
291
|
-
checkWalletVersion({ didwallet, locale });
|
|
292
|
-
|
|
293
|
-
const description = {
|
|
294
|
-
en: 'Please generate a new key-pair for this application',
|
|
295
|
-
zh: '请为应用创建新的钥匙对',
|
|
296
|
-
};
|
|
297
|
-
|
|
298
|
-
return {
|
|
299
|
-
mfa: !process.env.DID_CONNECT_MFA_DISABLED,
|
|
300
|
-
description: description[locale] || description.en,
|
|
301
|
-
moniker: (urlFriendly(slugify(title)) || 'application').toLowerCase(),
|
|
302
|
-
targetType: {
|
|
303
|
-
role: 'application',
|
|
304
|
-
hash: 'sha3',
|
|
305
|
-
key: 'ed25519',
|
|
306
|
-
encoding: 'base58',
|
|
307
|
-
},
|
|
308
|
-
};
|
|
309
|
-
};
|
|
310
|
-
|
|
311
276
|
const getLaunchBlockletClaims = (node, authMethod) => {
|
|
312
|
-
const claims = {
|
|
313
|
-
blockletAppKeypair: ['keyPair', getKeyPairClaim()],
|
|
314
|
-
};
|
|
315
|
-
|
|
316
277
|
if (authMethod === 'vc') {
|
|
317
|
-
|
|
318
|
-
|
|
319
|
-
|
|
320
|
-
if (authMethod === 'nft') {
|
|
321
|
-
claims.serverNFT = ['asset', getAuthNFTClaim({ node })];
|
|
278
|
+
return {
|
|
279
|
+
serverPassport: ['verifiableCredential', getAuthVcClaim({ node, launchBlocklet: true })],
|
|
280
|
+
};
|
|
322
281
|
}
|
|
323
282
|
|
|
324
|
-
return
|
|
283
|
+
return {
|
|
284
|
+
serverNFT: ['asset', getAuthNFTClaim({ node })],
|
|
285
|
+
};
|
|
325
286
|
};
|
|
326
287
|
|
|
327
|
-
// FIXME: @wangshijun should be changed to blocklet appSK owner claim?
|
|
328
288
|
const getSetupBlockletClaims = (node, authMethod, blocklet) => {
|
|
329
|
-
const claims = {};
|
|
330
|
-
|
|
331
289
|
if (authMethod === 'vc') {
|
|
332
|
-
|
|
333
|
-
|
|
334
|
-
|
|
335
|
-
claims.serverNFT = ['asset', getAuthNFTClaim({ node })];
|
|
290
|
+
return {
|
|
291
|
+
serverPassport: ['verifiableCredential', getAuthVcClaim({ node, blocklet })],
|
|
292
|
+
};
|
|
336
293
|
}
|
|
337
294
|
|
|
338
|
-
return
|
|
295
|
+
return {
|
|
296
|
+
serverNFT: ['asset', getAuthNFTClaim({ node })],
|
|
297
|
+
};
|
|
339
298
|
};
|
|
340
299
|
|
|
341
300
|
const getOwnershipNFTClaim = async (node, locale) => {
|
|
@@ -402,7 +361,7 @@ const ensureBlockletPermission = async ({
|
|
|
402
361
|
launchBlocklet: true,
|
|
403
362
|
blocklet,
|
|
404
363
|
});
|
|
405
|
-
} else
|
|
364
|
+
} else {
|
|
406
365
|
result = await authenticateByNFT({
|
|
407
366
|
node,
|
|
408
367
|
locale,
|
|
@@ -412,14 +371,9 @@ const ensureBlockletPermission = async ({
|
|
|
412
371
|
isAuth,
|
|
413
372
|
chainHost,
|
|
414
373
|
});
|
|
415
|
-
} else {
|
|
416
|
-
result = await authenticateBySession({
|
|
417
|
-
node,
|
|
418
|
-
userDid,
|
|
419
|
-
});
|
|
420
374
|
}
|
|
421
|
-
|
|
422
375
|
const { teamDid, role } = result;
|
|
376
|
+
|
|
423
377
|
const permissions = await node.getPermissionsByRole({ teamDid, role: { name: role } });
|
|
424
378
|
if (!permissions.some((item) => ['mutate_blocklets'].includes(item.name))) {
|
|
425
379
|
throw new Error(messages.notAuthorized[locale]);
|
|
@@ -431,38 +385,17 @@ const ensureBlockletPermission = async ({
|
|
|
431
385
|
const createLaunchBlockletHandler =
|
|
432
386
|
(node, authMethod) =>
|
|
433
387
|
async ({ claims, challenge, userDid, updateSession, req, extraParams }) => {
|
|
434
|
-
const { locale, blockletMetaUrl,
|
|
388
|
+
const { locale, blockletMetaUrl, chainHost } = extraParams;
|
|
435
389
|
logger.info('createLaunchBlockletHandler', extraParams);
|
|
436
390
|
|
|
437
|
-
|
|
438
|
-
|
|
439
|
-
|
|
440
|
-
throw new Error(messages.missingKeyPair[locale]);
|
|
441
|
-
}
|
|
442
|
-
|
|
443
|
-
if (!blockletMetaUrl && !title && !description) {
|
|
444
|
-
logger.error('blockletMetaUrl | title + description must be provided');
|
|
445
|
-
throw new Error(messages.missingBlockletUrl[locale]);
|
|
391
|
+
if (!blockletMetaUrl) {
|
|
392
|
+
logger.error('blockletMetaUrl must be provided');
|
|
393
|
+
throw new Error(messages.invalidParams[locale]);
|
|
446
394
|
}
|
|
447
395
|
|
|
448
396
|
if (authMethod === 'nft' && !chainHost) {
|
|
449
397
|
logger.error('chainHost must be provided');
|
|
450
|
-
throw new Error(messages.
|
|
451
|
-
}
|
|
452
|
-
|
|
453
|
-
let blocklet;
|
|
454
|
-
if (blockletMetaUrl) {
|
|
455
|
-
blocklet = await node.getBlockletMetaFromUrl({ url: blockletMetaUrl, checkPrice: true });
|
|
456
|
-
if (!blocklet.meta) {
|
|
457
|
-
throw new Error(messages.invalidBlocklet[locale]);
|
|
458
|
-
}
|
|
459
|
-
|
|
460
|
-
if (!blocklet.isFree) {
|
|
461
|
-
if (isEmpty(extraParams?.previousWorkflowData?.downloadTokenList)) {
|
|
462
|
-
logger.error('downloadTokenList must be provided');
|
|
463
|
-
throw new Error(messages.invalidParams[locale]);
|
|
464
|
-
}
|
|
465
|
-
}
|
|
398
|
+
throw new Error(messages.invalidParams[locale]);
|
|
466
399
|
}
|
|
467
400
|
|
|
468
401
|
const { role, passport, user, extra, nft } = await ensureBlockletPermission({
|
|
@@ -474,9 +407,22 @@ const createLaunchBlockletHandler =
|
|
|
474
407
|
locale,
|
|
475
408
|
isAuth: false,
|
|
476
409
|
chainHost,
|
|
477
|
-
blocklet,
|
|
478
410
|
});
|
|
479
411
|
|
|
412
|
+
const blocklet = await node.getBlockletMetaFromUrl({ url: blockletMetaUrl, checkPrice: true });
|
|
413
|
+
if (!blocklet.meta) {
|
|
414
|
+
throw new Error(messages.invalidBlocklet[locale]);
|
|
415
|
+
}
|
|
416
|
+
|
|
417
|
+
if (!blocklet.isFree) {
|
|
418
|
+
if (isEmpty(extraParams?.previousWorkflowData?.downloadTokenList)) {
|
|
419
|
+
logger.error('downloadTokenList must be provided');
|
|
420
|
+
throw new Error(messages.invalidParams[locale]);
|
|
421
|
+
}
|
|
422
|
+
}
|
|
423
|
+
|
|
424
|
+
const { did } = blocklet.meta;
|
|
425
|
+
|
|
480
426
|
let controller;
|
|
481
427
|
|
|
482
428
|
let sessionToken = '';
|
|
@@ -488,109 +434,76 @@ const createLaunchBlockletHandler =
|
|
|
488
434
|
secret,
|
|
489
435
|
expiresIn: LAUNCH_BLOCKLET_TOKEN_EXPIRE,
|
|
490
436
|
});
|
|
491
|
-
}
|
|
492
|
-
|
|
493
|
-
|
|
494
|
-
|
|
495
|
-
|
|
496
|
-
|
|
497
|
-
|
|
498
|
-
|
|
499
|
-
|
|
500
|
-
|
|
501
|
-
|
|
502
|
-
|
|
503
|
-
|
|
504
|
-
|
|
505
|
-
|
|
506
|
-
|
|
507
|
-
expiresIn: LAUNCH_BLOCKLET_TOKEN_EXPIRE,
|
|
508
|
-
});
|
|
509
|
-
}
|
|
437
|
+
} else if (role === SERVER_ROLES.EXTERNAL_BLOCKLET_CONTROLLER) {
|
|
438
|
+
controller = extra.controller;
|
|
439
|
+
sessionToken = createBlockletControllerAuthToken({
|
|
440
|
+
did: userDid,
|
|
441
|
+
role,
|
|
442
|
+
controller,
|
|
443
|
+
secret,
|
|
444
|
+
expiresIn: EXTERNAL_LAUNCH_BLOCKLET_TOKEN_EXPIRE,
|
|
445
|
+
});
|
|
446
|
+
} else {
|
|
447
|
+
sessionToken = createAuthTokenByOwnershipNFT({
|
|
448
|
+
did: userDid,
|
|
449
|
+
role,
|
|
450
|
+
secret,
|
|
451
|
+
expiresIn: LAUNCH_BLOCKLET_TOKEN_EXPIRE,
|
|
452
|
+
});
|
|
510
453
|
}
|
|
511
454
|
|
|
512
|
-
|
|
513
|
-
await updateSession({ sessionToken }, true);
|
|
514
|
-
}
|
|
455
|
+
await updateSession({ sessionToken }, true);
|
|
515
456
|
|
|
516
|
-
|
|
517
|
-
|
|
518
|
-
|
|
519
|
-
|
|
520
|
-
: blocklet.meta.did;
|
|
457
|
+
const blockletDid =
|
|
458
|
+
role === SERVER_ROLES.EXTERNAL_BLOCKLET_CONTROLLER
|
|
459
|
+
? toExternalBlocklet(blocklet.meta.name, controller.nftId, { didOnly: true })
|
|
460
|
+
: blocklet.meta.did;
|
|
521
461
|
|
|
522
|
-
|
|
462
|
+
await updateSession({
|
|
463
|
+
blockletDid,
|
|
464
|
+
});
|
|
523
465
|
|
|
524
|
-
|
|
525
|
-
|
|
466
|
+
// 检查是否已安装,这里不做升级的处理
|
|
467
|
+
const existedBlocklet = await node.getBlocklet({ did: blockletDid, attachRuntimeInfo: false });
|
|
526
468
|
|
|
527
|
-
|
|
528
|
-
|
|
529
|
-
|
|
530
|
-
|
|
469
|
+
// 如果是 serverless, 并且已经消费过了,但是没有安装,则抛出异常
|
|
470
|
+
if (!existedBlocklet && role === SERVER_ROLES.EXTERNAL_BLOCKLET_CONTROLLER && isNFTConsumed(nft)) {
|
|
471
|
+
throw new Error(messages.nftAlreadyConsume[locale]);
|
|
472
|
+
}
|
|
531
473
|
|
|
532
|
-
|
|
533
|
-
|
|
534
|
-
|
|
535
|
-
|
|
536
|
-
}
|
|
474
|
+
if (existedBlocklet) {
|
|
475
|
+
await updateSession({ isInstalled: true });
|
|
476
|
+
logger.info('blocklet already exists', { blockletDid });
|
|
477
|
+
return;
|
|
537
478
|
}
|
|
538
479
|
|
|
539
|
-
|
|
540
|
-
|
|
480
|
+
const tmp = await node.installBlocklet({
|
|
481
|
+
url: blockletMetaUrl,
|
|
482
|
+
delay: 1000 * 4, // delay 4 seconds to download, wait for ws connection from frontend
|
|
483
|
+
downloadTokenList: extraParams?.previousWorkflowData?.downloadTokenList,
|
|
484
|
+
controller: role === SERVER_ROLES.EXTERNAL_BLOCKLET_CONTROLLER ? controller : null,
|
|
485
|
+
});
|
|
486
|
+
|
|
487
|
+
await node.createAuditLog(
|
|
541
488
|
{
|
|
542
|
-
|
|
543
|
-
|
|
544
|
-
|
|
545
|
-
|
|
546
|
-
delay: 1000 * 4, // delay 4 seconds to download, wait for ws connection from frontend
|
|
547
|
-
downloadTokenList: extraParams?.previousWorkflowData?.downloadTokenList,
|
|
548
|
-
controller: role === SERVER_ROLES.EXTERNAL_BLOCKLET_CONTROLLER ? controller : null,
|
|
489
|
+
action: 'installBlocklet',
|
|
490
|
+
args: { url: blockletMetaUrl },
|
|
491
|
+
context: formatContext(Object.assign(req, { user })),
|
|
492
|
+
result: tmp,
|
|
549
493
|
},
|
|
550
|
-
|
|
494
|
+
node
|
|
551
495
|
);
|
|
552
|
-
|
|
553
|
-
await updateSession({ blockletDid: tmp.meta.did });
|
|
554
|
-
};
|
|
555
|
-
|
|
556
|
-
const getBlockletPermissionChecker =
|
|
557
|
-
(node) =>
|
|
558
|
-
async ({ userDid, extraParams }) => {
|
|
559
|
-
const { locale = 'en', connectedDid } = extraParams;
|
|
560
|
-
|
|
561
|
-
if (!connectedDid || userDid !== connectedDid) {
|
|
562
|
-
throw new Error(
|
|
563
|
-
{
|
|
564
|
-
en: 'Please use current connected wallet to install blocklet',
|
|
565
|
-
zh: '请使用当前登录的钱包来安装应用',
|
|
566
|
-
}[locale]
|
|
567
|
-
);
|
|
568
|
-
}
|
|
569
|
-
|
|
570
|
-
const info = await node.getNodeInfo();
|
|
571
|
-
const user = await getUser(node, info.did, userDid);
|
|
572
|
-
const passport = (user.passports || []).find((x) => x.status === 'valid' && ['owner', 'admin'].includes(x.role));
|
|
573
|
-
if (!passport) {
|
|
574
|
-
throw new Error(
|
|
575
|
-
{
|
|
576
|
-
en: 'You do not have permission to install blocklets on this server',
|
|
577
|
-
zh: '你无权在此节点上安装应用',
|
|
578
|
-
}[locale]
|
|
579
|
-
);
|
|
580
|
-
}
|
|
496
|
+
logger.info('start install blocklet', { blockletDid, bundleDid: did });
|
|
581
497
|
};
|
|
582
498
|
|
|
583
499
|
module.exports = {
|
|
584
500
|
getAuthVcClaim,
|
|
585
|
-
getKeyPairClaim,
|
|
586
501
|
authenticateByVc,
|
|
587
502
|
authenticateByNFT,
|
|
588
|
-
authenticateBySession,
|
|
589
503
|
getOwnershipNFTClaim,
|
|
590
504
|
getLaunchBlockletClaims,
|
|
591
505
|
createLaunchBlockletHandler,
|
|
592
506
|
ensureBlockletPermission,
|
|
593
|
-
getBlockletPermissionChecker,
|
|
594
507
|
getSetupBlockletClaims,
|
|
595
508
|
getTrustedIssuers,
|
|
596
509
|
getServerlessNFTClaim,
|
package/package.json
CHANGED
|
@@ -3,7 +3,7 @@
|
|
|
3
3
|
"publishConfig": {
|
|
4
4
|
"access": "public"
|
|
5
5
|
},
|
|
6
|
-
"version": "1.8.67
|
|
6
|
+
"version": "1.8.67",
|
|
7
7
|
"description": "Simple lib to manage auth in ABT Node",
|
|
8
8
|
"main": "lib/index.js",
|
|
9
9
|
"files": [
|
|
@@ -20,28 +20,27 @@
|
|
|
20
20
|
"author": "linchen <linchen1987@foxmail.com> (http://github.com/linchen1987)",
|
|
21
21
|
"license": "MIT",
|
|
22
22
|
"dependencies": {
|
|
23
|
-
"@abtnode/constant": "1.8.67
|
|
24
|
-
"@abtnode/logger": "1.8.67
|
|
25
|
-
"@abtnode/util": "1.8.67
|
|
26
|
-
"@arcblock/did": "1.18.
|
|
27
|
-
"@arcblock/jwt": "^1.18.
|
|
28
|
-
"@arcblock/vc": "1.18.
|
|
29
|
-
"@blocklet/constant": "1.8.67
|
|
30
|
-
"@blocklet/meta": "1.8.67
|
|
31
|
-
"@ocap/client": "1.18.
|
|
32
|
-
"@ocap/mcrypto": "1.18.
|
|
33
|
-
"@ocap/util": "1.18.
|
|
34
|
-
"@ocap/wallet": "1.18.
|
|
23
|
+
"@abtnode/constant": "1.8.67",
|
|
24
|
+
"@abtnode/logger": "1.8.67",
|
|
25
|
+
"@abtnode/util": "1.8.67",
|
|
26
|
+
"@arcblock/did": "1.18.42",
|
|
27
|
+
"@arcblock/jwt": "^1.18.42",
|
|
28
|
+
"@arcblock/vc": "1.18.42",
|
|
29
|
+
"@blocklet/constant": "1.8.67",
|
|
30
|
+
"@blocklet/meta": "1.8.67",
|
|
31
|
+
"@ocap/client": "1.18.42",
|
|
32
|
+
"@ocap/mcrypto": "1.18.42",
|
|
33
|
+
"@ocap/util": "1.18.42",
|
|
34
|
+
"@ocap/wallet": "1.18.42",
|
|
35
35
|
"axios": "^0.27.2",
|
|
36
36
|
"joi": "17.7.0",
|
|
37
37
|
"jsonwebtoken": "^9.0.0",
|
|
38
38
|
"lodash": "^4.17.21",
|
|
39
39
|
"semver": "^7.3.8",
|
|
40
|
-
"transliteration": "^2.3.5",
|
|
41
40
|
"url-join": "^4.0.1"
|
|
42
41
|
},
|
|
43
42
|
"devDependencies": {
|
|
44
43
|
"jest": "^27.5.1"
|
|
45
44
|
},
|
|
46
|
-
"gitHead": "
|
|
45
|
+
"gitHead": "543dbadffd29dc4f096261e136a2a306885d6508"
|
|
47
46
|
}
|