@abtnode/auth 1.16.14-beta-a898bfcb → 1.16.14-beta-d802cd3c
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 +41 -24
- package/lib/invitation.js +8 -14
- package/lib/launcher.js +2 -2
- package/lib/lost-passport.js +24 -30
- package/lib/passport.js +3 -0
- package/lib/util/create-passport-svg.js +33 -57
- package/package.json +13 -12
- package/lib/util/passport-color.js +0 -147
package/lib/auth.js
CHANGED
|
@@ -21,7 +21,8 @@ const {
|
|
|
21
21
|
WELLKNOWN_BLOCKLET_ADMIN_PATH,
|
|
22
22
|
} = require('@abtnode/constant');
|
|
23
23
|
const axios = require('@abtnode/util/lib/axios');
|
|
24
|
-
const { extractUserAvatar,
|
|
24
|
+
const { extractUserAvatar, getUserAvatarUrl, getAppAvatarUrl, getServerAvatarUrl } = require('@abtnode/util/lib/user');
|
|
25
|
+
const { LOGIN_PROVIDER } = require('@blocklet/constant');
|
|
25
26
|
|
|
26
27
|
const logger = require('./logger');
|
|
27
28
|
const verifySignature = require('./util/verify-signature');
|
|
@@ -327,7 +328,7 @@ const getRandomMessage = (len = 16) => {
|
|
|
327
328
|
return hex.replace(/^0x/, '').toUpperCase();
|
|
328
329
|
};
|
|
329
330
|
|
|
330
|
-
const getApplicationInfo = async ({ node, nodeInfo = {}, teamDid }) => {
|
|
331
|
+
const getApplicationInfo = async ({ node, nodeInfo = {}, teamDid, baseUrl = '' }) => {
|
|
331
332
|
let type;
|
|
332
333
|
let name;
|
|
333
334
|
let wallet;
|
|
@@ -337,6 +338,7 @@ const getApplicationInfo = async ({ node, nodeInfo = {}, teamDid }) => {
|
|
|
337
338
|
let owner;
|
|
338
339
|
let dataDir;
|
|
339
340
|
let secret;
|
|
341
|
+
let logo;
|
|
340
342
|
|
|
341
343
|
if (teamDid === nodeInfo.did) {
|
|
342
344
|
name = nodeInfo.name;
|
|
@@ -349,6 +351,7 @@ const getApplicationInfo = async ({ node, nodeInfo = {}, teamDid }) => {
|
|
|
349
351
|
owner = nodeInfo.nodeOwner;
|
|
350
352
|
dataDir = path.join(node.dataDirs.data, NODE_DATA_DIR_NAME);
|
|
351
353
|
secret = Hasher.SHA3.hash256(Buffer.concat([_wallet.secretKey, _wallet.address].map(Buffer.from)));
|
|
354
|
+
logo = getServerAvatarUrl(baseUrl, nodeInfo);
|
|
352
355
|
} else {
|
|
353
356
|
const blocklet = await node.getBlocklet({ did: teamDid });
|
|
354
357
|
const blockletInfo = getBlockletInfo(blocklet, nodeInfo.sk);
|
|
@@ -361,6 +364,7 @@ const getApplicationInfo = async ({ node, nodeInfo = {}, teamDid }) => {
|
|
|
361
364
|
owner = get(blocklet, 'settings.owner');
|
|
362
365
|
dataDir = blocklet.env.dataDir;
|
|
363
366
|
secret = blockletInfo.secret;
|
|
367
|
+
logo = getAppAvatarUrl(baseUrl);
|
|
364
368
|
}
|
|
365
369
|
|
|
366
370
|
return {
|
|
@@ -373,14 +377,25 @@ const getApplicationInfo = async ({ node, nodeInfo = {}, teamDid }) => {
|
|
|
373
377
|
owner,
|
|
374
378
|
dataDir,
|
|
375
379
|
secret,
|
|
380
|
+
logo,
|
|
376
381
|
};
|
|
377
382
|
};
|
|
378
383
|
|
|
379
|
-
const createAuthToken = ({
|
|
384
|
+
const createAuthToken = ({
|
|
385
|
+
did,
|
|
386
|
+
passport,
|
|
387
|
+
role,
|
|
388
|
+
secret,
|
|
389
|
+
expiresIn,
|
|
390
|
+
fullName,
|
|
391
|
+
tokenType,
|
|
392
|
+
provider = LOGIN_PROVIDER.WALLET,
|
|
393
|
+
} = {}) => {
|
|
380
394
|
const payload = {
|
|
381
395
|
type: 'user',
|
|
382
396
|
did,
|
|
383
397
|
role,
|
|
398
|
+
provider,
|
|
384
399
|
};
|
|
385
400
|
|
|
386
401
|
if (passport) {
|
|
@@ -442,7 +457,7 @@ const beforeInvitationRequest = async ({ node, teamDid, inviteId, locale = 'en'
|
|
|
442
457
|
}
|
|
443
458
|
};
|
|
444
459
|
|
|
445
|
-
const createInvitationRequest = async ({ node, nodeInfo, teamDid, inviteId, locale = 'en' }) => {
|
|
460
|
+
const createInvitationRequest = async ({ node, nodeInfo, teamDid, inviteId, baseUrl, locale = 'en' }) => {
|
|
446
461
|
// verify invite id
|
|
447
462
|
await node.checkInvitation({ teamDid, inviteId });
|
|
448
463
|
const inviteInfo = await node.getInvitation({ teamDid, inviteId });
|
|
@@ -451,7 +466,8 @@ const createInvitationRequest = async ({ node, nodeInfo, teamDid, inviteId, loca
|
|
|
451
466
|
name: issuerName,
|
|
452
467
|
wallet: issuerWallet,
|
|
453
468
|
passportColor,
|
|
454
|
-
|
|
469
|
+
logo,
|
|
470
|
+
} = await getApplicationInfo({ node, nodeInfo, teamDid, baseUrl });
|
|
455
471
|
|
|
456
472
|
const passport = await createPassport({
|
|
457
473
|
name: inviteInfo.role,
|
|
@@ -470,7 +486,9 @@ const createInvitationRequest = async ({ node, nodeInfo, teamDid, inviteId, loca
|
|
|
470
486
|
issuer: issuerName,
|
|
471
487
|
title: passport.title,
|
|
472
488
|
issuerDid: issuerWallet.address,
|
|
489
|
+
issuerAvatarUrl: logo,
|
|
473
490
|
ownerName: 'Your Name',
|
|
491
|
+
ownerDid: teamDid,
|
|
474
492
|
preferredColor: passportColor,
|
|
475
493
|
}),
|
|
476
494
|
}),
|
|
@@ -531,13 +549,15 @@ const handleInvitationReceive = async ({
|
|
|
531
549
|
type: issuerType,
|
|
532
550
|
passportColor,
|
|
533
551
|
dataDir,
|
|
534
|
-
|
|
552
|
+
logo,
|
|
553
|
+
} = await getApplicationInfo({ node, nodeInfo, teamDid, baseUrl: endpoint });
|
|
535
554
|
|
|
536
555
|
const { remark } = inviteInfo;
|
|
537
556
|
|
|
538
557
|
const vcParams = {
|
|
539
558
|
issuerName,
|
|
540
559
|
issuerWallet,
|
|
560
|
+
issuerAvatarUrl: logo,
|
|
541
561
|
ownerDid: userDid,
|
|
542
562
|
passport: await createPassport({
|
|
543
563
|
name: inviteInfo.role,
|
|
@@ -734,7 +754,7 @@ const beforeIssuePassportRequest = async ({ node, teamDid, id, locale = 'en' })
|
|
|
734
754
|
}
|
|
735
755
|
};
|
|
736
756
|
|
|
737
|
-
const createIssuePassportRequest = async ({ node, nodeInfo, teamDid, id, locale = 'en' }) => {
|
|
757
|
+
const createIssuePassportRequest = async ({ node, nodeInfo, teamDid, id, baseUrl, locale = 'en' }) => {
|
|
738
758
|
if (!id) {
|
|
739
759
|
throw new Error('The issuance id does not exist');
|
|
740
760
|
}
|
|
@@ -749,8 +769,8 @@ const createIssuePassportRequest = async ({ node, nodeInfo, teamDid, id, locale
|
|
|
749
769
|
wallet: issuerWallet,
|
|
750
770
|
passportColor,
|
|
751
771
|
owner: teamOwner,
|
|
752
|
-
|
|
753
|
-
} = await getApplicationInfo({ node, nodeInfo, teamDid });
|
|
772
|
+
logo,
|
|
773
|
+
} = await getApplicationInfo({ node, nodeInfo, teamDid, baseUrl });
|
|
754
774
|
|
|
755
775
|
if (issuanceInfo.name === ROLES.OWNER && !!teamOwner) {
|
|
756
776
|
throw new Error('Cannot receive owner passport because the owner already exists');
|
|
@@ -759,12 +779,8 @@ const createIssuePassportRequest = async ({ node, nodeInfo, teamDid, id, locale
|
|
|
759
779
|
// NOTICE: 这里是给指定用户颁发 passport,绑定的 did 无需查询 connectedAccount
|
|
760
780
|
const user = await getUser(node, teamDid, issuanceInfo.ownerDid);
|
|
761
781
|
|
|
762
|
-
const passport = await createPassport({
|
|
763
|
-
|
|
764
|
-
node,
|
|
765
|
-
teamDid,
|
|
766
|
-
locale,
|
|
767
|
-
});
|
|
782
|
+
const passport = await createPassport({ name: issuanceInfo.name, node, teamDid, locale });
|
|
783
|
+
const ownerAvatarUrl = getUserAvatarUrl(baseUrl, user.avatar, nodeInfo, teamDid === nodeInfo.did);
|
|
768
784
|
|
|
769
785
|
return {
|
|
770
786
|
description: messages.receivePassport[locale],
|
|
@@ -776,8 +792,10 @@ const createIssuePassportRequest = async ({ node, nodeInfo, teamDid, id, locale
|
|
|
776
792
|
issuer: issuerName,
|
|
777
793
|
title: passport.title,
|
|
778
794
|
issuerDid: issuerWallet.address,
|
|
795
|
+
issuerAvatarUrl: logo,
|
|
796
|
+
ownerDid: user.did,
|
|
779
797
|
ownerName: get(user, 'fullName', 'Your Name'),
|
|
780
|
-
ownerAvatarUrl
|
|
798
|
+
ownerAvatarUrl,
|
|
781
799
|
preferredColor: passportColor,
|
|
782
800
|
}),
|
|
783
801
|
}),
|
|
@@ -806,16 +824,14 @@ const handleIssuePassportResponse = async ({
|
|
|
806
824
|
const claim = claims.find((x) => x.type === 'signature');
|
|
807
825
|
verifySignature(claim, userDid, userPk, locale);
|
|
808
826
|
|
|
809
|
-
const user = await getUser(node, teamDid, userDid, {
|
|
810
|
-
enableConnectedAccount: true,
|
|
811
|
-
});
|
|
827
|
+
const user = await getUser(node, teamDid, userDid, { enableConnectedAccount: true });
|
|
812
828
|
const realDid = user.did || userDid;
|
|
813
829
|
const realPk = user.pk || userPk;
|
|
814
830
|
if (user && !user.approved) {
|
|
815
831
|
throw new Error(
|
|
816
832
|
{
|
|
817
|
-
zh: '
|
|
818
|
-
en: 'You are not allowed to access this
|
|
833
|
+
zh: '你没有权限访问该应用',
|
|
834
|
+
en: 'You are not allowed to access this app',
|
|
819
835
|
}[locale]
|
|
820
836
|
);
|
|
821
837
|
}
|
|
@@ -826,8 +842,8 @@ const handleIssuePassportResponse = async ({
|
|
|
826
842
|
type: issuerType,
|
|
827
843
|
passportColor,
|
|
828
844
|
owner: teamOwner,
|
|
829
|
-
|
|
830
|
-
} = await getApplicationInfo({ node, nodeInfo, teamDid });
|
|
845
|
+
logo,
|
|
846
|
+
} = await getApplicationInfo({ node, nodeInfo, teamDid, baseUrl: endpoint });
|
|
831
847
|
|
|
832
848
|
// get issuanceInfo from session
|
|
833
849
|
const list = await node.getPassportIssuances({ teamDid });
|
|
@@ -843,12 +859,13 @@ const handleIssuePassportResponse = async ({
|
|
|
843
859
|
}
|
|
844
860
|
|
|
845
861
|
if (user) {
|
|
846
|
-
user.avatar =
|
|
862
|
+
user.avatar = getUserAvatarUrl(endpoint, user.avatar, nodeInfo, teamDid === nodeInfo.did);
|
|
847
863
|
}
|
|
848
864
|
|
|
849
865
|
const vcParams = {
|
|
850
866
|
issuerName,
|
|
851
867
|
issuerWallet,
|
|
868
|
+
issuerAvatarUrl: logo,
|
|
852
869
|
ownerDid: userDid,
|
|
853
870
|
passport: await createPassport({
|
|
854
871
|
name,
|
package/lib/invitation.js
CHANGED
|
@@ -5,7 +5,7 @@ const { WELLKNOWN_SERVICE_PATH_PREFIX, NODE_DATA_DIR_NAME } = require('@abtnode/
|
|
|
5
5
|
const { BLOCKLET_CONFIGURABLE_KEY } = require('@blocklet/constant');
|
|
6
6
|
const { getDisplayName } = require('@blocklet/meta/lib/util');
|
|
7
7
|
const logger = require('@abtnode/logger')(require('../package.json').name);
|
|
8
|
-
const {
|
|
8
|
+
const { getUserAvatarUrl } = require('@abtnode/util/lib/user');
|
|
9
9
|
|
|
10
10
|
module.exports = {
|
|
11
11
|
init(server, node, { prefix, type } = {}) {
|
|
@@ -25,7 +25,6 @@ module.exports = {
|
|
|
25
25
|
name: getDisplayName(blockletInfo),
|
|
26
26
|
version: blockletInfo.meta.version,
|
|
27
27
|
logo: joinUrl(groupPathPrefix, WELLKNOWN_SERVICE_PATH_PREFIX, '/blocklet/logo'),
|
|
28
|
-
// TODO: 需要将 CHAIN_HOST 纳入标准
|
|
29
28
|
chainHost: blockletInfo.configObj.CHAIN_HOST,
|
|
30
29
|
passportColor: blockletInfo.configObj[BLOCKLET_CONFIGURABLE_KEY.BLOCKLET_PASSPORT_COLOR],
|
|
31
30
|
description: blockletInfo.meta.description,
|
|
@@ -54,10 +53,7 @@ module.exports = {
|
|
|
54
53
|
const roles = await node.getRoles({ teamDid });
|
|
55
54
|
const role = roles.find((v) => v.name === invitation.role);
|
|
56
55
|
try {
|
|
57
|
-
role.permissions = await node.getPermissionsByRole({
|
|
58
|
-
teamDid,
|
|
59
|
-
role: { name: role.name },
|
|
60
|
-
});
|
|
56
|
+
role.permissions = await node.getPermissionsByRole({ teamDid, role: { name: role.name } });
|
|
61
57
|
} catch (err) {
|
|
62
58
|
logger.error('failed to get role permission', { teamDid, role: role.name, error: err });
|
|
63
59
|
role.permissions = [];
|
|
@@ -65,15 +61,13 @@ module.exports = {
|
|
|
65
61
|
|
|
66
62
|
// NOTICE: 邀请人的 did 为永久 did,无需查询 connectedAccount
|
|
67
63
|
let user = await node.getUser({ teamDid: info.did, user: { did: invitation.inviter.did } });
|
|
68
|
-
let
|
|
69
|
-
|
|
70
|
-
// blocklet 邀请链接可能是 server 的 member
|
|
64
|
+
let baseUrl = info.url;
|
|
65
|
+
let isServer = type !== 'blocklet';
|
|
71
66
|
if (!user && type === 'blocklet') {
|
|
72
|
-
//
|
|
67
|
+
// 邀请人可能是 Server 的 Admin
|
|
73
68
|
user = await node.getUser({ teamDid: nodeInfo.did, user: { did: invitation.inviter.did } });
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
(await parseUserAvatar(user.avatar, { dataDir: path.join(node.dataDirs.data, NODE_DATA_DIR_NAME) }));
|
|
69
|
+
baseUrl = '/';
|
|
70
|
+
isServer = true;
|
|
77
71
|
}
|
|
78
72
|
|
|
79
73
|
const inviter = {
|
|
@@ -81,7 +75,7 @@ module.exports = {
|
|
|
81
75
|
email: invitation.inviter.email,
|
|
82
76
|
fullName: invitation.inviter.fullName || user?.fullName,
|
|
83
77
|
role: invitation.inviter.role,
|
|
84
|
-
avatar,
|
|
78
|
+
avatar: getUserAvatarUrl(baseUrl, user.avatar, nodeInfo, isServer),
|
|
85
79
|
};
|
|
86
80
|
|
|
87
81
|
res.json({
|
package/lib/launcher.js
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
const Joi = require('joi');
|
|
2
2
|
const axios = require('@abtnode/util/lib/axios');
|
|
3
|
-
const
|
|
3
|
+
const joinUrl = require('url-join');
|
|
4
4
|
const pRetry = require('p-retry');
|
|
5
5
|
const { stableStringify } = require('@arcblock/vc');
|
|
6
6
|
const { toBase58 } = require('@ocap/util');
|
|
@@ -25,7 +25,7 @@ const doRequest = async (serverSk, { launcherUrl, pathname, payload, method = 'p
|
|
|
25
25
|
const fn = async () => {
|
|
26
26
|
const { data } = await axios({
|
|
27
27
|
method,
|
|
28
|
-
url:
|
|
28
|
+
url: joinUrl(launcherUrl, pathname),
|
|
29
29
|
data: method !== 'get' ? payload : {},
|
|
30
30
|
params: method === 'get' ? payload : {},
|
|
31
31
|
headers: {
|
package/lib/lost-passport.js
CHANGED
|
@@ -9,7 +9,7 @@ const getNodeWallet = require('@abtnode/util/lib/get-app-wallet');
|
|
|
9
9
|
const { getDisplayName, getBlockletAppIdList } = require('@blocklet/meta/lib/util');
|
|
10
10
|
const { VC_TYPE_NODE_PASSPORT, PASSPORT_STATUS, NODE_DATA_DIR_NAME } = require('@abtnode/constant');
|
|
11
11
|
const get = require('lodash/get');
|
|
12
|
-
const {
|
|
12
|
+
const { getUserAvatarUrl, getAppAvatarUrl, getServerAvatarUrl } = require('@abtnode/util/lib/user');
|
|
13
13
|
const { getWalletDid } = require('@blocklet/meta/lib/did-utils');
|
|
14
14
|
|
|
15
15
|
const logger = require('./logger');
|
|
@@ -30,7 +30,7 @@ const TEAM_TYPES = {
|
|
|
30
30
|
NODE: 'node',
|
|
31
31
|
};
|
|
32
32
|
|
|
33
|
-
const getApplicationInfo = async ({ type, node, req }) => {
|
|
33
|
+
const getApplicationInfo = async ({ type, node, req, baseUrl = '' }) => {
|
|
34
34
|
let teamDid;
|
|
35
35
|
let issuerDid;
|
|
36
36
|
let issuerDidList;
|
|
@@ -38,6 +38,7 @@ const getApplicationInfo = async ({ type, node, req }) => {
|
|
|
38
38
|
let issuerWallet;
|
|
39
39
|
let passportColor;
|
|
40
40
|
let dataDir;
|
|
41
|
+
let issuerLogo;
|
|
41
42
|
|
|
42
43
|
const info = await node.getNodeInfo();
|
|
43
44
|
if (type === TEAM_TYPES.NODE) {
|
|
@@ -48,6 +49,7 @@ const getApplicationInfo = async ({ type, node, req }) => {
|
|
|
48
49
|
issuerWallet = getNodeWallet(info.sk);
|
|
49
50
|
passportColor = 'default';
|
|
50
51
|
dataDir = path.join(node.dataDirs.data, NODE_DATA_DIR_NAME);
|
|
52
|
+
issuerLogo = getServerAvatarUrl(baseUrl, info);
|
|
51
53
|
} else if (TEAM_TYPES.BLOCKLET) {
|
|
52
54
|
teamDid = req.headers['x-blocklet-did'];
|
|
53
55
|
const blocklet = await node.getBlocklet({ did: teamDid });
|
|
@@ -58,6 +60,7 @@ const getApplicationInfo = async ({ type, node, req }) => {
|
|
|
58
60
|
issuerWallet = blockletInfo.wallet;
|
|
59
61
|
passportColor = blockletInfo.passportColor;
|
|
60
62
|
dataDir = blocklet.env.dataDir;
|
|
63
|
+
issuerLogo = getAppAvatarUrl(baseUrl);
|
|
61
64
|
} else {
|
|
62
65
|
throw new Error('createLostPassportListRoute: unknown type');
|
|
63
66
|
}
|
|
@@ -68,8 +71,10 @@ const getApplicationInfo = async ({ type, node, req }) => {
|
|
|
68
71
|
issuerDidList,
|
|
69
72
|
issuerName,
|
|
70
73
|
issuerWallet,
|
|
74
|
+
issuerLogo,
|
|
71
75
|
passportColor,
|
|
72
76
|
dataDir,
|
|
77
|
+
info,
|
|
73
78
|
};
|
|
74
79
|
};
|
|
75
80
|
|
|
@@ -98,15 +103,13 @@ const createLostPassportListRoute = ({ node, type }) => ({
|
|
|
98
103
|
},
|
|
99
104
|
},
|
|
100
105
|
|
|
101
|
-
onAuth: async ({ userDid, extraParams, updateSession, req }) => {
|
|
106
|
+
onAuth: async ({ userDid, extraParams, updateSession, req, baseUrl }) => {
|
|
102
107
|
const { locale } = extraParams;
|
|
103
108
|
|
|
104
|
-
const { teamDid, issuerDidList,
|
|
109
|
+
const { teamDid, issuerDidList, info } = await getApplicationInfo({ node, req, type });
|
|
105
110
|
|
|
106
111
|
// check user approved
|
|
107
|
-
const user = await getUser(node, teamDid, userDid, {
|
|
108
|
-
enableConnectedAccount: true,
|
|
109
|
-
});
|
|
112
|
+
const user = await getUser(node, teamDid, userDid, { enableConnectedAccount: true });
|
|
110
113
|
|
|
111
114
|
if (!user) {
|
|
112
115
|
throw new Error(messages.userNotFound[locale]);
|
|
@@ -134,9 +137,9 @@ const createLostPassportListRoute = ({ node, type }) => ({
|
|
|
134
137
|
throw new Error(messages.passportNotFound[locale]);
|
|
135
138
|
}
|
|
136
139
|
|
|
137
|
-
logger.info('get passport type list', { userDid: user.did });
|
|
140
|
+
logger.info('get passport type list', { userDid: user.did, baseUrl });
|
|
138
141
|
|
|
139
|
-
user.avatar =
|
|
142
|
+
user.avatar = getUserAvatarUrl(baseUrl, user.avatar, info, info.did === teamDid);
|
|
140
143
|
|
|
141
144
|
await updateSession({ user });
|
|
142
145
|
},
|
|
@@ -169,25 +172,18 @@ const createLostPassportIssueRoute = ({ node, type, authServicePrefix }) => ({
|
|
|
169
172
|
},
|
|
170
173
|
},
|
|
171
174
|
{
|
|
172
|
-
signature: async ({ extraParams, context: { request, didwallet } }) => {
|
|
175
|
+
signature: async ({ extraParams, context: { baseUrl, request, didwallet } }) => {
|
|
173
176
|
const { locale, passportName, receiverDid } = extraParams;
|
|
174
177
|
checkWalletVersion({ didwallet, locale });
|
|
175
178
|
|
|
176
|
-
const { teamDid, issuerDid, issuerName, passportColor,
|
|
179
|
+
const { teamDid, issuerDid, issuerName, issuerLogo, passportColor, info } = await getApplicationInfo({
|
|
177
180
|
node,
|
|
178
181
|
req: request,
|
|
179
182
|
type,
|
|
183
|
+
baseUrl,
|
|
180
184
|
});
|
|
181
|
-
const user = await getUser(node, teamDid, receiverDid, {
|
|
182
|
-
|
|
183
|
-
});
|
|
184
|
-
|
|
185
|
-
const passport = await createPassport({
|
|
186
|
-
name: passportName,
|
|
187
|
-
node,
|
|
188
|
-
teamDid,
|
|
189
|
-
locale,
|
|
190
|
-
});
|
|
185
|
+
const user = await getUser(node, teamDid, receiverDid, { enableConnectedAccount: true });
|
|
186
|
+
const passport = await createPassport({ name: passportName, node, teamDid, locale });
|
|
191
187
|
|
|
192
188
|
return {
|
|
193
189
|
description: messages.receivePassport[locale],
|
|
@@ -199,8 +195,10 @@ const createLostPassportIssueRoute = ({ node, type, authServicePrefix }) => ({
|
|
|
199
195
|
issuer: issuerName,
|
|
200
196
|
title: passport.title,
|
|
201
197
|
issuerDid,
|
|
198
|
+
issuerAvatarUrl: issuerLogo,
|
|
199
|
+
ownerDid: receiverDid,
|
|
202
200
|
ownerName: user.fullName || '',
|
|
203
|
-
ownerAvatarUrl:
|
|
201
|
+
ownerAvatarUrl: getUserAvatarUrl(baseUrl, user.avatar, info, info.did === teamDid),
|
|
204
202
|
preferredColor: passportColor,
|
|
205
203
|
}),
|
|
206
204
|
}),
|
|
@@ -212,11 +210,8 @@ const createLostPassportIssueRoute = ({ node, type, authServicePrefix }) => ({
|
|
|
212
210
|
onAuth: async ({ claims, userDid, userPk, extraParams, updateSession, baseUrl, req }) => {
|
|
213
211
|
const { locale = 'en', receiverDid, passportName } = extraParams;
|
|
214
212
|
|
|
215
|
-
const { teamDid, issuerDidList, issuerName, issuerWallet, passportColor,
|
|
216
|
-
node,
|
|
217
|
-
req,
|
|
218
|
-
type,
|
|
219
|
-
});
|
|
213
|
+
const { teamDid, issuerDidList, issuerName, issuerLogo, issuerWallet, passportColor, info } =
|
|
214
|
+
await getApplicationInfo({ node, req, type, baseUrl });
|
|
220
215
|
const statusEndpointBaseUrl = getStatusEndpointBaseUrl(type, baseUrl, authServicePrefix);
|
|
221
216
|
|
|
222
217
|
// Verify signature
|
|
@@ -266,11 +261,10 @@ const createLostPassportIssueRoute = ({ node, type, authServicePrefix }) => ({
|
|
|
266
261
|
);
|
|
267
262
|
}
|
|
268
263
|
|
|
269
|
-
user.avatar = await parseUserAvatar(user.avatar, { dataDir });
|
|
270
|
-
|
|
271
264
|
const vcParams = {
|
|
272
265
|
issuerName,
|
|
273
266
|
issuerWallet,
|
|
267
|
+
issuerAvatarUrl: issuerLogo,
|
|
274
268
|
ownerDid: userDid,
|
|
275
269
|
passport: await createPassport({
|
|
276
270
|
name: passportName,
|
|
@@ -285,7 +279,7 @@ const createLostPassportIssueRoute = ({ node, type, authServicePrefix }) => ({
|
|
|
285
279
|
teamDid,
|
|
286
280
|
}),
|
|
287
281
|
types: [],
|
|
288
|
-
ownerProfile: user,
|
|
282
|
+
ownerProfile: { ...user, avatar: getUserAvatarUrl(baseUrl, user.avatar, info, info.did === teamDid) },
|
|
289
283
|
preferredColor: passportColor,
|
|
290
284
|
};
|
|
291
285
|
|
package/lib/passport.js
CHANGED
|
@@ -62,6 +62,7 @@ const createPassport = async ({ name, node, locale = 'en', teamDid, endpoint, ro
|
|
|
62
62
|
const createPassportVC = ({
|
|
63
63
|
issuerWallet,
|
|
64
64
|
issuerName,
|
|
65
|
+
issuerAvatarUrl,
|
|
65
66
|
ownerDid,
|
|
66
67
|
passport,
|
|
67
68
|
endpoint,
|
|
@@ -87,7 +88,9 @@ const createPassportVC = ({
|
|
|
87
88
|
content: createPassportSvg({
|
|
88
89
|
issuer: issuerName,
|
|
89
90
|
issuerDid: issuerWallet.address,
|
|
91
|
+
issuerAvatarUrl,
|
|
90
92
|
title: passport.title,
|
|
93
|
+
ownerDid,
|
|
91
94
|
ownerName: ownerProfile ? ownerProfile.fullName : '',
|
|
92
95
|
ownerAvatarUrl: ownerProfile ? ownerProfile.avatar : '',
|
|
93
96
|
preferredColor,
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
const { getNftBGColor,
|
|
1
|
+
const { getNftBGColor, DEFAULT_COLORS, getNftBGColorFromDid, getSvg } = require('@arcblock/nft-display');
|
|
2
2
|
|
|
3
3
|
/**
|
|
4
4
|
* Generate Passport SVG
|
|
@@ -8,11 +8,13 @@ const { getNftBGColor, DEFAULT_COLOR, getNftBGColorFromDid } = require('./passpo
|
|
|
8
8
|
* @param {string} params.issuer issuer name
|
|
9
9
|
* @param {string} params.issuerDid
|
|
10
10
|
* @param {string} params.ownerName
|
|
11
|
+
* @param {string} params.ownerDid
|
|
11
12
|
* @param {string} params.ownerAvatarUrl
|
|
12
13
|
* @param {string} [params.preferredColor]
|
|
13
14
|
* @param {string} [params.width]
|
|
14
15
|
* @param {string} [params.height]
|
|
15
|
-
* @param {
|
|
16
|
+
* @param {string} [params.ownerAvatarUrl]
|
|
17
|
+
* @param {string} [params.issuerAvatarUrl]
|
|
16
18
|
* @param {boolean} [params.revoked] 是否撤销
|
|
17
19
|
* @param {boolean} [params.isDataUrl] 返回生成 data url
|
|
18
20
|
* @returns {string} svg xml or image data url
|
|
@@ -21,6 +23,8 @@ const createPassportSvg = ({
|
|
|
21
23
|
issuer = '',
|
|
22
24
|
title = '',
|
|
23
25
|
issuerDid = '',
|
|
26
|
+
issuerAvatarUrl = '',
|
|
27
|
+
ownerDid = '',
|
|
24
28
|
ownerName = '',
|
|
25
29
|
ownerAvatarUrl = '',
|
|
26
30
|
preferredColor = 'default',
|
|
@@ -29,71 +33,43 @@ const createPassportSvg = ({
|
|
|
29
33
|
width = '100%',
|
|
30
34
|
height = '100%',
|
|
31
35
|
}) => {
|
|
32
|
-
let
|
|
36
|
+
let color;
|
|
33
37
|
if (preferredColor === 'default') {
|
|
34
|
-
|
|
38
|
+
color = DEFAULT_COLORS['app-passport'];
|
|
35
39
|
} else if (preferredColor === 'auto') {
|
|
36
|
-
|
|
40
|
+
color = getNftBGColorFromDid(issuerDid);
|
|
37
41
|
} else {
|
|
38
|
-
|
|
42
|
+
color = getNftBGColor(preferredColor);
|
|
39
43
|
}
|
|
40
44
|
|
|
41
|
-
const svgXML =
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
if (title.length >= 12) {
|
|
45
|
-
return 12;
|
|
46
|
-
}
|
|
45
|
+
const svgXML = getSvg({
|
|
46
|
+
width,
|
|
47
|
+
height,
|
|
47
48
|
|
|
48
|
-
|
|
49
|
-
return 14;
|
|
50
|
-
}
|
|
49
|
+
revoked,
|
|
51
50
|
|
|
52
|
-
|
|
53
|
-
return 18;
|
|
54
|
-
}
|
|
51
|
+
color,
|
|
55
52
|
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
53
|
+
did: ownerDid,
|
|
54
|
+
variant: 'app-passport' || ownerName,
|
|
55
|
+
verifiable: true,
|
|
59
56
|
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
if (issuer.length > 15) {
|
|
65
|
-
return 20;
|
|
66
|
-
}
|
|
57
|
+
issuer: {
|
|
58
|
+
name: issuer,
|
|
59
|
+
icon: issuerAvatarUrl,
|
|
60
|
+
},
|
|
67
61
|
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
</defs>
|
|
80
|
-
<text x="215" y="350" fill="white" xml:space="preserve" style="dominant-baseline:middle;text-anchor:middle;" font-family="Roboto,Helvetica" font-size="28" font-weight="500" letter-spacing="0px">${ownerName}</text>
|
|
81
|
-
<text opacity="0.4" fill="white" xml:space="preserve" style="white-space: pre" font-family="Roboto,Helvetica" font-size="18" font-weight="500" letter-spacing="0px"><tspan x="26" y="407.652">ISSUER DID</tspan></text>
|
|
82
|
-
<path fill-rule="evenodd" clip-rule="evenodd" d="M28.6722 423.313H45.3819C46.4294 423.313 47.2787 424.162 47.2787 425.21V433.79C47.2787 434.838 46.4294 435.687 45.3819 435.687H28.6722C27.9517 435.687 27.3249 435.285 27.0039 434.694H26.1167C26.4887 435.746 27.4924 436.5 28.6722 436.5H45.3819C46.8784 436.5 48.0916 435.287 48.0916 433.79V425.21C48.0916 423.713 46.8784 422.5 45.3819 422.5H28.6722C27.3296 422.5 26.215 423.477 26 424.758H26.8295C27.0321 423.929 27.7803 423.313 28.6722 423.313ZM27.8801 432.096C27.7831 432.089 27.6966 432.082 27.6204 432.075V427.526C27.7243 427.512 27.8351 427.505 27.9528 427.505C28.0705 427.498 28.1848 427.494 28.2955 427.494C29.1057 427.494 29.6978 427.688 30.0717 428.076C30.4457 428.464 30.6326 429.035 30.6326 429.79C30.6326 430.51 30.4353 431.074 30.0406 431.483C29.6528 431.892 29.0538 432.096 28.2436 432.096H27.8801ZM32.0141 431.421C32.208 430.957 32.305 430.413 32.305 429.79C32.305 429.139 32.208 428.582 32.0141 428.118C31.8202 427.654 31.5432 427.273 31.1832 426.975C30.8231 426.677 30.3903 426.459 29.8848 426.321C29.3862 426.182 28.8288 426.113 28.2125 426.113C27.9216 426.113 27.5719 426.127 27.1634 426.154C26.7617 426.175 26.3739 426.22 26 426.29V433.301C26.3739 433.377 26.7548 433.425 27.1426 433.446C27.5304 433.474 27.8697 433.488 28.1605 433.488C28.7976 433.488 29.3723 433.412 29.8848 433.259C30.3972 433.107 30.83 432.878 31.1832 432.574C31.5432 432.269 31.8202 431.885 32.0141 431.421ZM35.2788 426.196H33.6585V433.394H35.2788V426.196ZM38.5654 432.075C38.6416 432.082 38.7281 432.089 38.8251 432.096H39.1886C39.9988 432.096 40.5978 431.892 40.9856 431.483C41.3803 431.074 41.5776 430.51 41.5776 429.79C41.5776 429.035 41.3907 428.464 41.0167 428.076C40.6428 427.688 40.0507 427.494 39.2405 427.494C39.1298 427.494 39.0155 427.498 38.8978 427.505C38.7801 427.505 38.6693 427.512 38.5654 427.526V432.075ZM43.25 429.79C43.25 430.413 43.153 430.957 42.9591 431.421C42.7652 431.885 42.4882 432.269 42.1282 432.574C41.775 432.878 41.3422 433.107 40.8298 433.259C40.3173 433.412 39.7426 433.488 39.1055 433.488C38.8147 433.488 38.4754 433.474 38.0876 433.446C37.6998 433.425 37.3189 433.377 36.945 433.301V426.29C37.3189 426.22 37.7067 426.175 38.1084 426.154C38.5169 426.127 38.8666 426.113 39.1574 426.113C39.7738 426.113 40.3312 426.182 40.8298 426.321C41.3353 426.459 41.7681 426.677 42.1282 426.975C42.4882 427.273 42.7652 427.654 42.9591 428.118C43.153 428.582 43.25 429.139 43.25 429.79ZM45.1907 428.355C44.8209 428.355 44.5161 428.055 44.5161 427.686C44.5161 427.316 44.8209 427.016 45.1907 427.016C45.5604 427.016 45.8652 427.316 45.8652 427.686C45.8652 428.055 45.5604 428.355 45.1907 428.355ZM45.1907 431.855C44.8209 431.855 44.5161 431.555 44.5161 431.185C44.5161 430.815 44.8209 430.516 45.1907 430.516C45.5604 430.516 45.8652 430.815 45.8652 431.185C45.8652 431.555 45.5604 431.855 45.1907 431.855Z" fill="white"/>
|
|
83
|
-
<text fill="white" xml:space="preserve" style="white-space: pre" font-family="Roboto,Helvetica" font-size="15" font-weight="500" letter-spacing="0px"><tspan x="54.0916" y="434.969">${issuerDid}</tspan></text>
|
|
84
|
-
<rect x="1" y="1" width="422" height="562" rx="21" stroke="#F0F0F0" stroke-width="2"/>
|
|
85
|
-
<defs>
|
|
86
|
-
<linearGradient id="paint0_linear_6_342" x1="414.5" y1="562" x2="-116.166" y2="156.726" gradientUnits="userSpaceOnUse">
|
|
87
|
-
<stop stop-color="${colors.startColor}"/>
|
|
88
|
-
<stop offset="1" stop-color="${colors.endColor}"/>
|
|
89
|
-
</linearGradient>
|
|
90
|
-
</defs>
|
|
91
|
-
${
|
|
92
|
-
revoked
|
|
93
|
-
? '<circle cx="210" cy="250" r="120" stroke="rgba(255,0,0,0.5)" stroke-width="25" /><line x1="132" y1="168" x2="296" y2="323" stroke="rgba(255,0,0,0.5)" stroke-width="25" />'
|
|
94
|
-
: ''
|
|
95
|
-
}
|
|
96
|
-
</svg>`;
|
|
62
|
+
header: {
|
|
63
|
+
name: title,
|
|
64
|
+
icon: ownerAvatarUrl,
|
|
65
|
+
},
|
|
66
|
+
|
|
67
|
+
// FIXME: @wangshijun this should be dynamic
|
|
68
|
+
extra: {
|
|
69
|
+
key: 'Exp',
|
|
70
|
+
value: '2123-01-01',
|
|
71
|
+
},
|
|
72
|
+
});
|
|
97
73
|
|
|
98
74
|
if (isDataUrl) {
|
|
99
75
|
return `data:image/svg+xml;utf8,${encodeURIComponent(svgXML)}`;
|
package/package.json
CHANGED
|
@@ -3,7 +3,7 @@
|
|
|
3
3
|
"publishConfig": {
|
|
4
4
|
"access": "public"
|
|
5
5
|
},
|
|
6
|
-
"version": "1.16.14-beta-
|
|
6
|
+
"version": "1.16.14-beta-d802cd3c",
|
|
7
7
|
"description": "Simple lib to manage auth in ABT Node",
|
|
8
8
|
"main": "lib/index.js",
|
|
9
9
|
"files": [
|
|
@@ -20,16 +20,17 @@
|
|
|
20
20
|
"author": "linchen <linchen1987@foxmail.com> (http://github.com/linchen1987)",
|
|
21
21
|
"license": "Apache-2.0",
|
|
22
22
|
"dependencies": {
|
|
23
|
-
"@abtnode/constant": "1.16.14-beta-
|
|
24
|
-
"@abtnode/logger": "1.16.14-beta-
|
|
25
|
-
"@abtnode/util": "1.16.14-beta-
|
|
26
|
-
"@arcblock/did": "1.18.
|
|
27
|
-
"@arcblock/
|
|
28
|
-
"@
|
|
29
|
-
"@blocklet/
|
|
30
|
-
"@
|
|
31
|
-
"@ocap/
|
|
32
|
-
"@ocap/
|
|
23
|
+
"@abtnode/constant": "1.16.14-beta-d802cd3c",
|
|
24
|
+
"@abtnode/logger": "1.16.14-beta-d802cd3c",
|
|
25
|
+
"@abtnode/util": "1.16.14-beta-d802cd3c",
|
|
26
|
+
"@arcblock/did": "1.18.87",
|
|
27
|
+
"@arcblock/nft-display": "2.5.60",
|
|
28
|
+
"@arcblock/vc": "1.18.87",
|
|
29
|
+
"@blocklet/constant": "1.16.14-beta-d802cd3c",
|
|
30
|
+
"@blocklet/meta": "1.16.14-beta-d802cd3c",
|
|
31
|
+
"@ocap/mcrypto": "1.18.87",
|
|
32
|
+
"@ocap/util": "1.18.87",
|
|
33
|
+
"@ocap/wallet": "1.18.87",
|
|
33
34
|
"fs-extra": "^10.1.0",
|
|
34
35
|
"joi": "17.7.0",
|
|
35
36
|
"jsonwebtoken": "^9.0.0",
|
|
@@ -42,5 +43,5 @@
|
|
|
42
43
|
"devDependencies": {
|
|
43
44
|
"jest": "^27.5.1"
|
|
44
45
|
},
|
|
45
|
-
"gitHead": "
|
|
46
|
+
"gitHead": "f8e2dcefd8d6876e5dedee833ac976b4a0496b20"
|
|
46
47
|
}
|
|
@@ -1,147 +0,0 @@
|
|
|
1
|
-
const { toHex } = require('@ocap/util');
|
|
2
|
-
const { Hasher } = require('@ocap/mcrypto');
|
|
3
|
-
|
|
4
|
-
const DEFAULT_COLOR = {
|
|
5
|
-
startColor: '#2B3845',
|
|
6
|
-
endColor: '#5A7A8A',
|
|
7
|
-
};
|
|
8
|
-
|
|
9
|
-
/**
|
|
10
|
-
* 将单个颜色转换为可用 nft 两个渐变背景色
|
|
11
|
-
* @param {String} rgbString 背景色
|
|
12
|
-
* @returns {Object}
|
|
13
|
-
*/
|
|
14
|
-
const getNftBGColor = (rgbString) => {
|
|
15
|
-
if (rgbString) {
|
|
16
|
-
const hsldata = rgbToHsl(rgbString);
|
|
17
|
-
|
|
18
|
-
// 色相 h 随意
|
|
19
|
-
// 饱和度 s 不可超过 0.8
|
|
20
|
-
// 亮度 l 不可超过 0.6,0.3 以上
|
|
21
|
-
const newHsl = [hsldata[0]];
|
|
22
|
-
if (hsldata[1] > 0.7) {
|
|
23
|
-
newHsl.push(0.7);
|
|
24
|
-
} else {
|
|
25
|
-
newHsl.push(hsldata[1]);
|
|
26
|
-
}
|
|
27
|
-
|
|
28
|
-
if (hsldata[2] > 0.6) {
|
|
29
|
-
newHsl.push(0.6);
|
|
30
|
-
} else if (hsldata[2] < 0.3) {
|
|
31
|
-
newHsl.push(0.3);
|
|
32
|
-
} else {
|
|
33
|
-
newHsl.push(hsldata[2]);
|
|
34
|
-
}
|
|
35
|
-
|
|
36
|
-
const newRepeatHsl = [newHsl[0], newHsl[1], newHsl[2] - 0.1];
|
|
37
|
-
|
|
38
|
-
const newColor = hslToRgb(...newHsl);
|
|
39
|
-
const newRepeatColor = hslToRgb(...newRepeatHsl);
|
|
40
|
-
|
|
41
|
-
return {
|
|
42
|
-
startColor: newRepeatColor,
|
|
43
|
-
endColor: newColor,
|
|
44
|
-
};
|
|
45
|
-
}
|
|
46
|
-
|
|
47
|
-
return {
|
|
48
|
-
startColor: '#2B3845',
|
|
49
|
-
endColor: '#5A7A8A',
|
|
50
|
-
};
|
|
51
|
-
};
|
|
52
|
-
|
|
53
|
-
function getPassportColorFromDid(did) {
|
|
54
|
-
return `#${toHex(Hasher.SHA3.hash224(did)).slice(-6)}`;
|
|
55
|
-
}
|
|
56
|
-
|
|
57
|
-
function getNftBGColorFromDid(did) {
|
|
58
|
-
return getNftBGColor(getPassportColorFromDid(did));
|
|
59
|
-
}
|
|
60
|
-
|
|
61
|
-
/**
|
|
62
|
-
* RGB 转换为 HSL 颜色
|
|
63
|
-
*
|
|
64
|
-
* @param {String} rgbString rgb色值
|
|
65
|
-
* @return {Array} HSL色值
|
|
66
|
-
*/
|
|
67
|
-
function rgbToHsl(rgbString) {
|
|
68
|
-
const color = rgbString.replace('#', '');
|
|
69
|
-
const r = parseInt(color.slice(0, 2), 16) / 255;
|
|
70
|
-
const g = parseInt(color.slice(2, 4), 16) / 255;
|
|
71
|
-
const b = parseInt(color.slice(4, 6), 16) / 255;
|
|
72
|
-
const max = Math.max(r, g, b);
|
|
73
|
-
const min = Math.min(r, g, b);
|
|
74
|
-
let h;
|
|
75
|
-
let s;
|
|
76
|
-
const l = (max + min) / 2;
|
|
77
|
-
|
|
78
|
-
if (max === min) {
|
|
79
|
-
h = 0;
|
|
80
|
-
s = 0;
|
|
81
|
-
} else {
|
|
82
|
-
const d = max - min;
|
|
83
|
-
s = l > 0.5 ? d / (2 - max - min) : d / (max + min);
|
|
84
|
-
switch (max) {
|
|
85
|
-
case r:
|
|
86
|
-
h = (g - b) / d + (g < b ? 6 : 0);
|
|
87
|
-
break;
|
|
88
|
-
case g:
|
|
89
|
-
h = (b - r) / d + 2;
|
|
90
|
-
break;
|
|
91
|
-
case b:
|
|
92
|
-
h = (r - g) / d + 4;
|
|
93
|
-
break;
|
|
94
|
-
default:
|
|
95
|
-
}
|
|
96
|
-
h /= 6;
|
|
97
|
-
}
|
|
98
|
-
|
|
99
|
-
return [h, s, l];
|
|
100
|
-
}
|
|
101
|
-
|
|
102
|
-
/**
|
|
103
|
-
* HSL颜色值转换为RGB.
|
|
104
|
-
* h, s, 和 l 设定在 [0, 1] 之间
|
|
105
|
-
* @param {Number} h 色相
|
|
106
|
-
* @param {Number} s 饱和度
|
|
107
|
-
* @param {Number} l 亮度
|
|
108
|
-
* @returns rgb string
|
|
109
|
-
*/
|
|
110
|
-
function hslToRgb(h, s, l) {
|
|
111
|
-
let r;
|
|
112
|
-
let g;
|
|
113
|
-
let b;
|
|
114
|
-
|
|
115
|
-
if (s === 0) {
|
|
116
|
-
r = l;
|
|
117
|
-
g = l;
|
|
118
|
-
b = l;
|
|
119
|
-
} else {
|
|
120
|
-
const hue2rgb = (p, q, t2) => {
|
|
121
|
-
let t = t2;
|
|
122
|
-
if (t < 0) t += 1;
|
|
123
|
-
if (t > 1) t -= 1;
|
|
124
|
-
if (t < 1 / 6) return p + (q - p) * 6 * t;
|
|
125
|
-
if (t < 1 / 2) return q;
|
|
126
|
-
if (t < 2 / 3) return p + (q - p) * (2 / 3 - t) * 6;
|
|
127
|
-
return p;
|
|
128
|
-
};
|
|
129
|
-
|
|
130
|
-
const q = l < 0.5 ? l * (1 + s) : l + s - l * s;
|
|
131
|
-
const p = 2 * l - q;
|
|
132
|
-
r = hue2rgb(p, q, h + 1 / 3);
|
|
133
|
-
g = hue2rgb(p, q, h);
|
|
134
|
-
b = hue2rgb(p, q, h - 1 / 3);
|
|
135
|
-
}
|
|
136
|
-
|
|
137
|
-
return `#${[Math.round(r * 255), Math.round(g * 255), Math.round(b * 255)]
|
|
138
|
-
.map((e) => e.toString(16).padStart(2, 0))
|
|
139
|
-
.join('')}`;
|
|
140
|
-
}
|
|
141
|
-
|
|
142
|
-
module.exports = {
|
|
143
|
-
getNftBGColor,
|
|
144
|
-
getNftBGColorFromDid,
|
|
145
|
-
DEFAULT_COLOR,
|
|
146
|
-
getPassportColorFromDid,
|
|
147
|
-
};
|