@abtnode/webapp 1.8.63-beta-a36b5e1a → 1.8.63
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/blocklet.yml +6 -3
- package/build/asset-manifest.json +93 -0
- package/build/favicon.ico +0 -0
- package/build/icons/css/all.css +5919 -0
- package/build/icons/css/brands.css +14 -0
- package/build/icons/css/brands.min.css +12 -0
- package/build/icons/css/fontawesome.css +7816 -0
- package/build/icons/css/fontawesome.min.css +5864 -0
- package/build/icons/css/light.css +15 -0
- package/build/icons/css/light.min.css +13 -0
- package/build/icons/webfonts/fa-brands-400.eot +0 -0
- package/build/icons/webfonts/fa-brands-400.svg +1256 -0
- package/build/icons/webfonts/fa-brands-400.ttf +0 -0
- package/build/icons/webfonts/fa-brands-400.woff +0 -0
- package/build/icons/webfonts/fa-brands-400.woff2 +0 -0
- package/build/icons/webfonts/fa-light-300.eot +0 -0
- package/build/icons/webfonts/fa-light-300.svg +4445 -0
- package/build/icons/webfonts/fa-light-300.ttf +0 -0
- package/build/icons/webfonts/fa-light-300.woff +0 -0
- package/build/icons/webfonts/fa-light-300.woff2 +0 -0
- package/build/images/blocklet.png +0 -0
- package/build/images/blocklets-00c2c4.png +0 -0
- package/build/images/blocklets-222222.png +0 -0
- package/build/images/celebrate.png +0 -0
- package/build/images/community.svg +6 -0
- package/build/images/console-00c2c4.png +0 -0
- package/build/images/console-222222.png +0 -0
- package/build/images/dashboard-00c2c4.png +0 -0
- package/build/images/dashboard-222222.png +0 -0
- package/build/images/doc-222222.png +0 -0
- package/build/images/hourglass-222222.png +0 -0
- package/build/images/https-certificate-icon.png +0 -0
- package/build/images/labs-00c2c4.png +0 -0
- package/build/images/labs-222222.png +0 -0
- package/build/images/log-00c2c4.png +0 -0
- package/build/images/log-222222.png +0 -0
- package/build/images/member-222222.png +0 -0
- package/build/images/node.png +0 -0
- package/build/images/official.svg +1 -0
- package/build/images/private-222222.png +0 -0
- package/build/images/public-222222.png +0 -0
- package/build/images/public_avatar.png +0 -0
- package/build/images/router-00c2c4.png +0 -0
- package/build/images/router-222222.png +0 -0
- package/build/images/settings-00c2c4.png +0 -0
- package/build/images/settings-222222.png +0 -0
- package/build/images/slack.png +0 -0
- package/build/images/storage-222222.png +0 -0
- package/build/images/store-00c2c4.png +0 -0
- package/build/images/store-222222.png +0 -0
- package/build/images/team-00c2c4.png +0 -0
- package/build/images/team-222222.png +0 -0
- package/build/images/time-222222.png +0 -0
- package/build/images/upgrade.png +0 -0
- package/build/index.html +1 -0
- package/build/manifest.json +15 -0
- package/build/static/css/4381.5ade355d.chunk.css +1 -0
- package/build/static/css/4691.56c2f951.chunk.css +1 -0
- package/build/static/css/5245.5d6e9197.chunk.css +1 -0
- package/build/static/css/8213.f696fdbf.chunk.css +1 -0
- package/build/static/css/9779.f696fdbf.chunk.css +1 -0
- package/build/static/css/main.c9e90622.css +1 -0
- package/build/static/images/logo.png +0 -0
- package/build/static/js/1057.8280393f.chunk.js +1 -0
- package/build/static/js/1361.85e46159.chunk.js +1 -0
- package/build/static/js/1366.2f174c9b.chunk.js +2 -0
- package/build/static/js/1366.2f174c9b.chunk.js.LICENSE.txt +37 -0
- package/build/static/js/154.94956824.chunk.js +1 -0
- package/build/static/js/1826.07c285de.chunk.js +1 -0
- package/build/static/js/2129.120e36ae.chunk.js +1 -0
- package/build/static/js/2308.b65bc299.chunk.js +1 -0
- package/build/static/js/2564.eef717f3.chunk.js +1 -0
- package/build/static/js/2657.d3c62d57.chunk.js +1 -0
- package/build/static/js/2720.26eb1788.chunk.js +1 -0
- package/build/static/js/2828.4f318970.chunk.js +1 -0
- package/build/static/js/2878.5626558d.chunk.js +1 -0
- package/build/static/js/3111.84e02823.chunk.js +1 -0
- package/build/static/js/3476.c0b3411b.chunk.js +1 -0
- package/build/static/js/3633.8c7cf02d.chunk.js +1 -0
- package/build/static/js/3732.f5d8b39b.chunk.js +1 -0
- package/build/static/js/3776.1490b0f7.chunk.js +1 -0
- package/build/static/js/3829.b6d6cf45.chunk.js +1 -0
- package/build/static/js/4074.19db40ec.chunk.js +1 -0
- package/build/static/js/4104.b47ae0e1.chunk.js +1 -0
- package/build/static/js/4241.83e4f741.chunk.js +1 -0
- package/build/static/js/4274.e18ffddd.chunk.js +1 -0
- package/build/static/js/4349.7c2f6507.chunk.js +1 -0
- package/build/static/js/4381.631ef61d.chunk.js +2 -0
- package/build/static/js/4381.631ef61d.chunk.js.LICENSE.txt +22 -0
- package/build/static/js/4557.3907550e.chunk.js +1 -0
- package/build/static/js/4590.5a14012c.chunk.js +1 -0
- package/build/static/js/4633.9f946ed5.chunk.js +1 -0
- package/build/static/js/4691.550fcb40.chunk.js +2 -0
- package/build/static/js/4691.550fcb40.chunk.js.LICENSE.txt +8 -0
- package/build/static/js/5074.9ea094a9.chunk.js +1 -0
- package/build/static/js/5082.18d16cb9.chunk.js +1 -0
- package/build/static/js/519.adae6e43.chunk.js +1 -0
- package/build/static/js/556.381dcbd8.chunk.js +1 -0
- package/build/static/js/5984.25af6288.chunk.js +1 -0
- package/build/static/js/6158.8a43296d.chunk.js +1 -0
- package/build/static/js/6189.d6d74d14.chunk.js +1 -0
- package/build/static/js/6239.5a873a03.chunk.js +2 -0
- package/build/static/js/6239.5a873a03.chunk.js.LICENSE.txt +14 -0
- package/build/static/js/629.1a7f2553.chunk.js +1 -0
- package/build/static/js/6413.ab4a8e01.chunk.js +1 -0
- package/build/static/js/6602.c417a217.chunk.js +1 -0
- package/build/static/js/6780.64314507.chunk.js +1 -0
- package/build/static/js/6830.88b993a0.chunk.js +1 -0
- package/build/static/js/6866.2131ea60.chunk.js +2 -0
- package/build/static/js/6866.2131ea60.chunk.js.LICENSE.txt +8 -0
- package/build/static/js/6898.6fe0c32d.chunk.js +2 -0
- package/build/static/js/6898.6fe0c32d.chunk.js.LICENSE.txt +5 -0
- package/build/static/js/7016.835958ef.chunk.js +1 -0
- package/build/static/js/7298.a7286c09.chunk.js +1 -0
- package/build/static/js/7327.56a5e016.chunk.js +1 -0
- package/build/static/js/744.8b656dd2.chunk.js +1 -0
- package/build/static/js/7652.722b9180.chunk.js +1 -0
- package/build/static/js/8034.c4dcdeff.chunk.js +1 -0
- package/build/static/js/8058.0b2d4727.chunk.js +1 -0
- package/build/static/js/8213.09f25083.chunk.js +1 -0
- package/build/static/js/8235.add24931.chunk.js +1 -0
- package/build/static/js/8249.63c55b3a.chunk.js +1 -0
- package/build/static/js/8262.869cc799.chunk.js +1 -0
- package/build/static/js/8352.b57b0e44.chunk.js +1 -0
- package/build/static/js/8464.b4b82828.chunk.js +1 -0
- package/build/static/js/8606.66db67e2.chunk.js +1 -0
- package/build/static/js/9038.2908c176.chunk.js +1 -0
- package/build/static/js/9076.c77366bc.chunk.js +1 -0
- package/build/static/js/9301.a65db324.chunk.js +2 -0
- package/build/static/js/9301.a65db324.chunk.js.LICENSE.txt +8 -0
- package/build/static/js/9575.36f3de5b.chunk.js +2 -0
- package/build/static/js/9575.36f3de5b.chunk.js.LICENSE.txt +194 -0
- package/build/static/js/9779.bbf0dd81.chunk.js +1 -0
- package/build/static/js/main.cb5d8d67.js +2 -0
- package/build/static/js/main.cb5d8d67.js.LICENSE.txt +159 -0
- package/build/static/media/iconify.32b54549e843e448ee9b.cjs +2 -0
- package/build/static/media/iconify.32b54549e843e448ee9b.cjs.LICENSE.txt +13 -0
- package/build/static/media/lato-all-400-normal.3dc1eff492ab1f598560.woff +0 -0
- package/build/static/media/lato-all-700-normal.1e7707c9ec98d9b97e7f.woff +0 -0
- package/build/static/media/lato-latin-400-normal.be36596da218e1eec01c.woff2 +0 -0
- package/build/static/media/lato-latin-700-normal.8f28e0e1fdb195149f1c.woff2 +0 -0
- package/build/static/media/lato-latin-ext-400-normal.361f3dbb9db6a5980326.woff2 +0 -0
- package/build/static/media/lato-latin-ext-700-normal.9c8812eaec45956201e1.woff2 +0 -0
- package/build/static/media/logo.60f66bbe1ce9674a4df4e374c9d97fc4.svg +16 -0
- package/build/static/media/ubuntu-mono-all-400-normal.c879328bc62e9c68268f.woff +0 -0
- package/build/static/media/ubuntu-mono-cyrillic-400-normal.c367f416832eb8f1b846.woff2 +0 -0
- package/build/static/media/ubuntu-mono-cyrillic-ext-400-normal.eda1c4946b1f7bf58386.woff2 +0 -0
- package/build/static/media/ubuntu-mono-greek-400-normal.22f3bfc91f79c342bdf4.woff2 +0 -0
- package/build/static/media/ubuntu-mono-greek-ext-400-normal.b3459900ea8a25d1f7c2.woff2 +0 -0
- package/build/static/media/ubuntu-mono-latin-400-normal.18e32d9d743af28f913e.woff2 +0 -0
- package/build/static/media/ubuntu-mono-latin-ext-400-normal.b56e2315611d10838ad5.woff2 +0 -0
- package/package.json +1 -1
- package/api/gql/config.js +0 -392
- package/api/gql/index.js +0 -102
- package/api/gql/middlewares/create-audit-log.js +0 -3
- package/api/gql/middlewares/get-blocklet-list.js +0 -14
- package/api/gql/middlewares/install-blocklet.js +0 -13
- package/api/gql/middlewares/verify-blocklet.js +0 -21
- package/api/gql/middlewares/verify-team.js +0 -9
- package/api/index.js +0 -249
- package/api/libs/auth.js +0 -78
- package/api/libs/env.js +0 -3
- package/api/libs/login.js +0 -212
- package/api/libs/security.js +0 -90
- package/api/libs/storage.js +0 -69
- package/api/middlewares/mutate-blocklet-permission.js +0 -18
- package/api/routes/auth/accept-server.js +0 -28
- package/api/routes/auth/connect-owner.js +0 -143
- package/api/routes/auth/delegate-transfer-owner-nft.js +0 -86
- package/api/routes/auth/invite.js +0 -93
- package/api/routes/auth/issue-passport.js +0 -61
- package/api/routes/auth/launch-free-blocklet-by-nft.js +0 -9
- package/api/routes/auth/launch-free-blocklet.js +0 -9
- package/api/routes/auth/launch-paid-blocklet-by-nft.js +0 -9
- package/api/routes/auth/launch-paid-blocklet.js +0 -9
- package/api/routes/auth/login.js +0 -63
- package/api/routes/auth/lost-passport-issue.js +0 -5
- package/api/routes/auth/lost-passport-list.js +0 -5
- package/api/routes/auth/switch-passport.js +0 -47
- package/api/routes/auth/switch-profile.js +0 -69
- package/api/routes/auth/util.js +0 -135
- package/api/routes/auth/verify-owner.js +0 -39
- package/api/routes/auth/verify-purchase.js +0 -185
- package/api/routes/blocklet-info.js +0 -246
- package/api/routes/blocklet-preference.js +0 -161
- package/api/routes/blocklet-proxy.js +0 -220
- package/api/routes/did-resolver.js +0 -38
- package/api/routes/dns-resolver.js +0 -73
- package/api/routes/log.js +0 -31
- package/api/routes/passport.js +0 -19
- package/api/routes/session.js +0 -61
- package/api/routes/user.js +0 -38
- package/api/util/find-routing-rule.js +0 -95
- package/api/util/get-configs.js +0 -31
- package/api/util/index.js +0 -5
- package/api/util/navigation.js +0 -84
- package/api/webpack.blocklet.js +0 -43
- package/api/ws/index.js +0 -146
|
@@ -1,69 +0,0 @@
|
|
|
1
|
-
const path = require('path');
|
|
2
|
-
const get = require('lodash/get');
|
|
3
|
-
|
|
4
|
-
const { messages } = require('@abtnode/auth/lib/auth');
|
|
5
|
-
const formatContext = require('@abtnode/util/lib/format-context');
|
|
6
|
-
const { extractUserAvatar } = require('@abtnode/util/lib/user-avatar');
|
|
7
|
-
const { NODE_DATA_DIR_NAME } = require('@abtnode/constant');
|
|
8
|
-
|
|
9
|
-
module.exports = function createRoutes(node) {
|
|
10
|
-
return {
|
|
11
|
-
action: 'switch-profile',
|
|
12
|
-
onConnect: async ({ userDid, extraParams: { locale, connectedDid } }) => {
|
|
13
|
-
if (userDid && connectedDid && userDid !== connectedDid) {
|
|
14
|
-
throw new Error(messages.userMismatch[locale]);
|
|
15
|
-
}
|
|
16
|
-
|
|
17
|
-
const info = await node.getNodeInfo();
|
|
18
|
-
const user = await node.getUser({ teamDid: info.did, user: { did: userDid } });
|
|
19
|
-
if (!user) {
|
|
20
|
-
throw new Error(messages.notAllowed[locale]);
|
|
21
|
-
}
|
|
22
|
-
if (!user.approved) {
|
|
23
|
-
throw new Error(messages.notAuthorized[locale]);
|
|
24
|
-
}
|
|
25
|
-
|
|
26
|
-
return {
|
|
27
|
-
profile: {
|
|
28
|
-
fields: ['fullName', 'email', 'avatar'],
|
|
29
|
-
description: messages.requestProfile[locale],
|
|
30
|
-
},
|
|
31
|
-
};
|
|
32
|
-
},
|
|
33
|
-
|
|
34
|
-
onAuth: async ({ claims, userDid, extraParams: { locale }, req }) => {
|
|
35
|
-
const info = await node.getNodeInfo();
|
|
36
|
-
const user = await node.getUser({ teamDid: info.did, user: { did: userDid } });
|
|
37
|
-
|
|
38
|
-
if (!user) {
|
|
39
|
-
throw new Error(messages.notAllowed[locale]);
|
|
40
|
-
}
|
|
41
|
-
if (!user.approved) {
|
|
42
|
-
throw new Error(messages.notAuthorized[locale]);
|
|
43
|
-
}
|
|
44
|
-
|
|
45
|
-
const profile = claims.find(x => x.type === 'profile');
|
|
46
|
-
|
|
47
|
-
const doc = await node.updateUser({
|
|
48
|
-
teamDid: info.did,
|
|
49
|
-
user: {
|
|
50
|
-
...user,
|
|
51
|
-
...profile,
|
|
52
|
-
avatar: await extractUserAvatar(get(profile, 'avatar'), {
|
|
53
|
-
dataDir: path.join(node.dataDirs.data, NODE_DATA_DIR_NAME),
|
|
54
|
-
}),
|
|
55
|
-
locale,
|
|
56
|
-
},
|
|
57
|
-
});
|
|
58
|
-
await node.createAuditLog(
|
|
59
|
-
{
|
|
60
|
-
action: 'switchProfile',
|
|
61
|
-
args: { teamDid: info.did, userDid, profile },
|
|
62
|
-
context: formatContext(Object.assign(req, { user })),
|
|
63
|
-
result: doc,
|
|
64
|
-
},
|
|
65
|
-
node
|
|
66
|
-
);
|
|
67
|
-
},
|
|
68
|
-
};
|
|
69
|
-
};
|
package/api/routes/auth/util.js
DELETED
|
@@ -1,135 +0,0 @@
|
|
|
1
|
-
const { createPassport, createPassportVC, createUserPassport } = require('@abtnode/auth/lib/passport');
|
|
2
|
-
const { ROLES, VC_TYPE_NODE_PASSPORT } = require('@abtnode/constant');
|
|
3
|
-
const formatContext = require('@abtnode/util/lib/format-context');
|
|
4
|
-
const { getPassportStatusEndpoint } = require('@abtnode/auth/lib/auth');
|
|
5
|
-
const { authenticateByNFT, getOwnershipNFTClaim } = require('@abtnode/auth/lib/server');
|
|
6
|
-
const getNodeWallet = require('@abtnode/util/lib/get-app-wallet');
|
|
7
|
-
const { messages } = require('@abtnode/auth/lib/auth');
|
|
8
|
-
|
|
9
|
-
const logger = require('@abtnode/logger')(require('../../../package.json').name);
|
|
10
|
-
const { createSessionToken } = require('../../libs/login');
|
|
11
|
-
|
|
12
|
-
const localMessages = {
|
|
13
|
-
requestProfile: {
|
|
14
|
-
en: 'This node has already been accepted, please login.',
|
|
15
|
-
zh: '请提供节点所有者信息',
|
|
16
|
-
},
|
|
17
|
-
alreadyAccepted: {
|
|
18
|
-
en: 'Already accepted, please login',
|
|
19
|
-
zh: '已经接受过该节点,请登录。',
|
|
20
|
-
},
|
|
21
|
-
};
|
|
22
|
-
|
|
23
|
-
const onAddNodeOwnerAuth = async ({
|
|
24
|
-
action,
|
|
25
|
-
req,
|
|
26
|
-
node,
|
|
27
|
-
baseUrl,
|
|
28
|
-
claims,
|
|
29
|
-
userDid,
|
|
30
|
-
locale,
|
|
31
|
-
challenge,
|
|
32
|
-
userPk,
|
|
33
|
-
updateSession,
|
|
34
|
-
}) => {
|
|
35
|
-
// get profile
|
|
36
|
-
const profile = claims.find(x => x.type === 'profile');
|
|
37
|
-
if (!profile) {
|
|
38
|
-
throw new Error(messages.missingProfileClaim[locale]);
|
|
39
|
-
}
|
|
40
|
-
|
|
41
|
-
const { teamDid, ownerDid, ownerNFT } = await authenticateByNFT({ node, claims, userDid, challenge, locale });
|
|
42
|
-
|
|
43
|
-
const info = await node.getNodeInfo();
|
|
44
|
-
|
|
45
|
-
const newOwnerInfo = { did: userDid, pk: userPk };
|
|
46
|
-
|
|
47
|
-
const ownerNft = info.ownerNft || {};
|
|
48
|
-
// 只有在 action 是 accept-server 时才需要更新 ownerNft
|
|
49
|
-
if (action === 'accept-server') {
|
|
50
|
-
// 更新 ownerNft holder
|
|
51
|
-
ownerNft.holder = ownerDid;
|
|
52
|
-
} else {
|
|
53
|
-
// 添加新用户
|
|
54
|
-
ownerNft.did = ownerNFT;
|
|
55
|
-
}
|
|
56
|
-
|
|
57
|
-
await node.updateNodeOwner({ nodeOwner: newOwnerInfo, ownerNft });
|
|
58
|
-
|
|
59
|
-
logger.info('verify owner to node', { userDid });
|
|
60
|
-
|
|
61
|
-
const passportVC = createPassportVC({
|
|
62
|
-
issuerName: info.name,
|
|
63
|
-
issuerWallet: getNodeWallet(info.sk),
|
|
64
|
-
ownerDid: userDid,
|
|
65
|
-
passport: await createPassport({
|
|
66
|
-
name: ROLES.OWNER,
|
|
67
|
-
node,
|
|
68
|
-
teamDid,
|
|
69
|
-
locale,
|
|
70
|
-
endpoint: baseUrl,
|
|
71
|
-
}),
|
|
72
|
-
endpoint: getPassportStatusEndpoint({
|
|
73
|
-
baseUrl,
|
|
74
|
-
userDid,
|
|
75
|
-
teamDid,
|
|
76
|
-
}),
|
|
77
|
-
types: [VC_TYPE_NODE_PASSPORT],
|
|
78
|
-
tag: info.did,
|
|
79
|
-
ownerProfile: profile,
|
|
80
|
-
preferredColor: 'default',
|
|
81
|
-
});
|
|
82
|
-
|
|
83
|
-
const role = ROLES.OWNER;
|
|
84
|
-
const passport = createUserPassport(passportVC, { role });
|
|
85
|
-
|
|
86
|
-
// Add owner as approved member
|
|
87
|
-
const doc = await node.addUser({
|
|
88
|
-
teamDid,
|
|
89
|
-
user: {
|
|
90
|
-
...profile,
|
|
91
|
-
did: userDid,
|
|
92
|
-
pk: userPk,
|
|
93
|
-
approved: true,
|
|
94
|
-
locale,
|
|
95
|
-
passports: [passport],
|
|
96
|
-
firstLoginAt: new Date().toISOString(),
|
|
97
|
-
lastLoginAt: new Date().toISOString(),
|
|
98
|
-
},
|
|
99
|
-
});
|
|
100
|
-
await node.createAuditLog(
|
|
101
|
-
{
|
|
102
|
-
action: 'addUser',
|
|
103
|
-
args: { teamDid, userDid, reason: 'claim server with server nft' },
|
|
104
|
-
context: formatContext(Object.assign(req, { user: doc })),
|
|
105
|
-
result: doc,
|
|
106
|
-
},
|
|
107
|
-
node
|
|
108
|
-
);
|
|
109
|
-
|
|
110
|
-
// Generate new session token that client can save to localStorage
|
|
111
|
-
const sessionToken = await createSessionToken(userDid, { passport, role });
|
|
112
|
-
await updateSession({ sessionToken }, true);
|
|
113
|
-
|
|
114
|
-
// Issue owner passport
|
|
115
|
-
return {
|
|
116
|
-
disposition: 'attachment',
|
|
117
|
-
type: 'VerifiableCredential',
|
|
118
|
-
data: passportVC,
|
|
119
|
-
};
|
|
120
|
-
};
|
|
121
|
-
|
|
122
|
-
const getAssetProfile =
|
|
123
|
-
node =>
|
|
124
|
-
({ extraParams: { locale } }) => {
|
|
125
|
-
return getOwnershipNFTClaim(node, locale);
|
|
126
|
-
};
|
|
127
|
-
|
|
128
|
-
const getProfileClaim = async locale => {
|
|
129
|
-
return {
|
|
130
|
-
fields: ['fullName', 'email', 'avatar'],
|
|
131
|
-
description: localMessages.requestProfile[locale],
|
|
132
|
-
};
|
|
133
|
-
};
|
|
134
|
-
|
|
135
|
-
module.exports = { getAssetProfile, getProfileClaim, onAddNodeOwnerAuth };
|
|
@@ -1,39 +0,0 @@
|
|
|
1
|
-
const { messages } = require('@abtnode/auth/lib/auth');
|
|
2
|
-
|
|
3
|
-
const { onAddNodeOwnerAuth, getProfileClaim, getAssetProfile } = require('./util');
|
|
4
|
-
|
|
5
|
-
module.exports = function createRoutes(node) {
|
|
6
|
-
return {
|
|
7
|
-
action: 'verify-owner',
|
|
8
|
-
onConnect: () => {
|
|
9
|
-
return {
|
|
10
|
-
asset: getAssetProfile(node),
|
|
11
|
-
profile: async ({ extraParams: { locale } }) => {
|
|
12
|
-
if (await node.isInitialized()) {
|
|
13
|
-
throw new Error(messages.alreadyInitiated[locale]);
|
|
14
|
-
}
|
|
15
|
-
|
|
16
|
-
return getProfileClaim(locale);
|
|
17
|
-
},
|
|
18
|
-
};
|
|
19
|
-
},
|
|
20
|
-
|
|
21
|
-
onAuth: async ({ claims, userDid, userPk, challenge, updateSession, extraParams: { locale }, req, baseUrl }) => {
|
|
22
|
-
if (await node.isInitialized()) {
|
|
23
|
-
throw new Error(messages.alreadyInitiated[locale]);
|
|
24
|
-
}
|
|
25
|
-
|
|
26
|
-
return onAddNodeOwnerAuth({
|
|
27
|
-
node,
|
|
28
|
-
req,
|
|
29
|
-
claims,
|
|
30
|
-
userDid,
|
|
31
|
-
userPk,
|
|
32
|
-
challenge,
|
|
33
|
-
updateSession,
|
|
34
|
-
locale,
|
|
35
|
-
baseUrl,
|
|
36
|
-
});
|
|
37
|
-
},
|
|
38
|
-
};
|
|
39
|
-
};
|
|
@@ -1,185 +0,0 @@
|
|
|
1
|
-
const get = require('lodash/get');
|
|
2
|
-
const { isFreeBlocklet } = require('@blocklet/meta/lib/util');
|
|
3
|
-
const { BlockletEvents } = require('@blocklet/constant');
|
|
4
|
-
const { VC_TYPE_BLOCKLET_PURCHASE } = require('@abtnode/constant');
|
|
5
|
-
const { messages: defaultMessages, getVCFromClaims } = require('@abtnode/auth/lib/auth');
|
|
6
|
-
const logger = require('@abtnode/logger')(require('../../../package.json').name);
|
|
7
|
-
|
|
8
|
-
const { getBlockletUrl } = require('../../util');
|
|
9
|
-
|
|
10
|
-
const messages = {
|
|
11
|
-
...defaultMessages,
|
|
12
|
-
requestCredential: {
|
|
13
|
-
en: 'Please provide blocklet purchase NFT',
|
|
14
|
-
zh: '请提供 Blocklet 购买凭证 NFT',
|
|
15
|
-
},
|
|
16
|
-
missingCredentialClaim: {
|
|
17
|
-
en: 'Blocklet purchase NFT not provided',
|
|
18
|
-
zh: '请提供 Blocklet 购买凭证 NFT',
|
|
19
|
-
},
|
|
20
|
-
missingChallenge: {
|
|
21
|
-
en: 'Purchase NFT presentation does not include valid challenge',
|
|
22
|
-
zh: '购买 NFT 中缺少正确的随机因子',
|
|
23
|
-
},
|
|
24
|
-
invalidCredentialType: {
|
|
25
|
-
en: `Invalid blocklet purchase NFT type, expect ${VC_TYPE_BLOCKLET_PURCHASE}`,
|
|
26
|
-
zh: `无效的 Blocklet 购买凭证 NFT 类型,必须是 ${VC_TYPE_BLOCKLET_PURCHASE}`,
|
|
27
|
-
},
|
|
28
|
-
blockletDidNotMatch: {
|
|
29
|
-
en: 'This NFT is for another blocklet',
|
|
30
|
-
zh: '购买凭证和要安装的 Blocklet 不匹配',
|
|
31
|
-
},
|
|
32
|
-
invalidCredentialProof: {
|
|
33
|
-
en: 'Invalid blocklet purchase NFT signature proof',
|
|
34
|
-
zh: '无效的购买凭证签名',
|
|
35
|
-
},
|
|
36
|
-
purchaseNotRequired: {
|
|
37
|
-
en: 'This blocklet is free and does not require any purchase',
|
|
38
|
-
zh: '该 Blocklet 可免费安装,不需要购买',
|
|
39
|
-
},
|
|
40
|
-
alreadyInstalled: {
|
|
41
|
-
en: 'This blocklet is already installed on this server',
|
|
42
|
-
zh: '该 Blocklet 已经安装,不需要购买',
|
|
43
|
-
},
|
|
44
|
-
rootBlockletNotInstalled: {
|
|
45
|
-
en: 'The blocklet cannot be mounted to a blocklet that is not installed',
|
|
46
|
-
zh: '该 Blocklet 无法挂载到未安装的 Blocklet',
|
|
47
|
-
},
|
|
48
|
-
sessionNotFound: {
|
|
49
|
-
en: 'Purchase session not found',
|
|
50
|
-
zh: '购买会话不存在',
|
|
51
|
-
},
|
|
52
|
-
};
|
|
53
|
-
|
|
54
|
-
const getTrustedIssuers = registryId => [registryId];
|
|
55
|
-
|
|
56
|
-
const vcTypes = [VC_TYPE_BLOCKLET_PURCHASE];
|
|
57
|
-
|
|
58
|
-
module.exports = function createRoutes(node) {
|
|
59
|
-
const { node: nodeState } = node.states;
|
|
60
|
-
return {
|
|
61
|
-
action: 'verify-purchase',
|
|
62
|
-
claims: {
|
|
63
|
-
verifiableCredential: async ({ extraParams: { locale, sid } }) => {
|
|
64
|
-
const session = await node.getSession({ id: sid });
|
|
65
|
-
if (!session) {
|
|
66
|
-
throw new Error(messages.sessionNotFound[locale]);
|
|
67
|
-
}
|
|
68
|
-
|
|
69
|
-
let exist;
|
|
70
|
-
let result;
|
|
71
|
-
let info;
|
|
72
|
-
|
|
73
|
-
if (session.type === 'component') {
|
|
74
|
-
let blocklet;
|
|
75
|
-
|
|
76
|
-
[blocklet, result, info] = await Promise.all([
|
|
77
|
-
node.getBlocklet({ did: session.rootDid, attachConfig: false }),
|
|
78
|
-
node.getBlockletMetaFromUrl({ url: session.url }),
|
|
79
|
-
// FIXME: session.url must be a meta url in a blocklet store
|
|
80
|
-
node.getRegistryMeta(new URL(session.url).origin),
|
|
81
|
-
]);
|
|
82
|
-
|
|
83
|
-
if (!blocklet) {
|
|
84
|
-
throw new Error(messages.rootBlockletNotInstalled[locale]);
|
|
85
|
-
}
|
|
86
|
-
|
|
87
|
-
exist = blocklet.children.find(x => x.meta.did === result.meta.did);
|
|
88
|
-
} else {
|
|
89
|
-
[exist, result, info] = await Promise.all([
|
|
90
|
-
node.getBlocklet({ did: session.blockletDid, attachConfig: false }),
|
|
91
|
-
node.getBlockletMetaFromUrl({ url: getBlockletUrl(session.registryUrl, session.blockletDid) }),
|
|
92
|
-
node.getRegistryMeta(session.registryUrl),
|
|
93
|
-
]);
|
|
94
|
-
}
|
|
95
|
-
|
|
96
|
-
if (exist) {
|
|
97
|
-
throw new Error(messages.alreadyInstalled[locale]);
|
|
98
|
-
}
|
|
99
|
-
|
|
100
|
-
if (isFreeBlocklet(result.meta) === true) {
|
|
101
|
-
throw new Error(messages.purchaseNotRequired[locale]);
|
|
102
|
-
}
|
|
103
|
-
|
|
104
|
-
return {
|
|
105
|
-
description: messages.requestCredential[locale],
|
|
106
|
-
item: vcTypes,
|
|
107
|
-
trustedIssuers: getTrustedIssuers(info.id),
|
|
108
|
-
tag: result.meta.did,
|
|
109
|
-
};
|
|
110
|
-
},
|
|
111
|
-
},
|
|
112
|
-
|
|
113
|
-
onError: async ({ err, extraParams: { sid } }) => {
|
|
114
|
-
const session = await node.updateSession({ id: sid, data: { status: 'error', message: err.message } });
|
|
115
|
-
nodeState.emit(BlockletEvents.purchaseChange, { did: session.blockletDid, session });
|
|
116
|
-
logger.error('emit blocklet purchase error event', session);
|
|
117
|
-
},
|
|
118
|
-
|
|
119
|
-
onDecline: async ({ extraParams: { sid } }) => {
|
|
120
|
-
const session = await node.updateSession({ id: sid, data: { status: 'declined' } });
|
|
121
|
-
nodeState.emit(BlockletEvents.purchaseChange, { did: session.blockletDid, session });
|
|
122
|
-
logger.info('emit blocklet purchase decline event', session);
|
|
123
|
-
},
|
|
124
|
-
|
|
125
|
-
onAuth: async ({ userDid, claims, challenge, extraParams: { sid, locale } }) => {
|
|
126
|
-
const session = await node.getSession({ id: sid });
|
|
127
|
-
if (!session) {
|
|
128
|
-
throw new Error(messages.sessionNotFound[locale]);
|
|
129
|
-
}
|
|
130
|
-
|
|
131
|
-
let info;
|
|
132
|
-
if (session.type === 'component') {
|
|
133
|
-
// FIXME: session.url must be a meta url in a blocklet store
|
|
134
|
-
info = await node.getRegistryMeta(new URL(session.url).origin);
|
|
135
|
-
} else {
|
|
136
|
-
info = await node.getRegistryMeta(session.registryUrl);
|
|
137
|
-
}
|
|
138
|
-
|
|
139
|
-
// get vc
|
|
140
|
-
const trustedIssuers = getTrustedIssuers(info.id);
|
|
141
|
-
const { vc } = await getVCFromClaims({
|
|
142
|
-
claims,
|
|
143
|
-
challenge,
|
|
144
|
-
trustedIssuers,
|
|
145
|
-
vcTypes,
|
|
146
|
-
locale,
|
|
147
|
-
});
|
|
148
|
-
|
|
149
|
-
if (!vc) {
|
|
150
|
-
throw new Error(messages.missingCredentialClaim[locale]);
|
|
151
|
-
}
|
|
152
|
-
|
|
153
|
-
const claim = get(vc, 'credentialSubject.purchased.blocklet') || get(vc, 'credentialSubject.purchased.blocklets');
|
|
154
|
-
const blocklets = Array.isArray(claim) ? claim : [claim];
|
|
155
|
-
if (!blocklets.find(x => x.id === session.blockletDid)) {
|
|
156
|
-
throw new Error(messages.blockletDidNotMatch[locale]);
|
|
157
|
-
}
|
|
158
|
-
|
|
159
|
-
const newSession = await node.updateSession({ id: sid, data: { status: 'confirmed' } });
|
|
160
|
-
nodeState.emit(BlockletEvents.purchaseChange, { did: session.blockletDid, session: newSession });
|
|
161
|
-
logger.info('emit blocklet purchase confirm event', newSession);
|
|
162
|
-
|
|
163
|
-
// trigger blocklet install if every check passed
|
|
164
|
-
const context = { user: { did: userDid } };
|
|
165
|
-
let api;
|
|
166
|
-
let params;
|
|
167
|
-
if (session.type === 'component') {
|
|
168
|
-
api = node.installComponent.bind(node);
|
|
169
|
-
const { rootDid, mountPoint, url, name, did, title } = session;
|
|
170
|
-
params = { rootDid, mountPoint, url, name, did, title };
|
|
171
|
-
} else {
|
|
172
|
-
api = node.installBlocklet.bind(node);
|
|
173
|
-
params = { did: session.blockletDid };
|
|
174
|
-
}
|
|
175
|
-
|
|
176
|
-
api(params, context)
|
|
177
|
-
.then(() => {
|
|
178
|
-
logger.info('install blocklet after verify purchase nft', session);
|
|
179
|
-
})
|
|
180
|
-
.catch(err => {
|
|
181
|
-
logger.error('install blocklet after verify purchase nft failed', { session, err });
|
|
182
|
-
});
|
|
183
|
-
},
|
|
184
|
-
};
|
|
185
|
-
};
|
|
@@ -1,246 +0,0 @@
|
|
|
1
|
-
/* eslint-disable no-console */
|
|
2
|
-
const path = require('path');
|
|
3
|
-
const LRU = require('lru-cache');
|
|
4
|
-
const get = require('lodash/get');
|
|
5
|
-
const cloneDeep = require('lodash/cloneDeep');
|
|
6
|
-
const md5 = require('@abtnode/util/lib/md5');
|
|
7
|
-
const { formatEnv } = require('@abtnode/util/lib/security');
|
|
8
|
-
const {
|
|
9
|
-
attachSendLogoContext,
|
|
10
|
-
ensureBlockletExist,
|
|
11
|
-
ensureCustomSquareLogo,
|
|
12
|
-
ensureBundleLogo,
|
|
13
|
-
fallbackLogo,
|
|
14
|
-
cacheError,
|
|
15
|
-
} = require('@abtnode/util/lib/logo-middleware');
|
|
16
|
-
const normalizePathPrefix = require('@abtnode/util/lib/normalize-path-prefix');
|
|
17
|
-
const { WELLKNOWN_SERVICE_PATH_PREFIX } = require('@abtnode/constant');
|
|
18
|
-
const { BlockletEvents, BLOCKLET_PREFERENCE_PREFIX } = require('@blocklet/constant');
|
|
19
|
-
const getBlockletInfo = require('@blocklet/meta/lib/info');
|
|
20
|
-
const { forEachBlocklet, isPreferenceKey, findComponentById } = require('@blocklet/meta/lib/util');
|
|
21
|
-
const {
|
|
22
|
-
joinLink,
|
|
23
|
-
parseNavigation,
|
|
24
|
-
filterNavigation,
|
|
25
|
-
cleanOrphanNavigation,
|
|
26
|
-
} = require('@blocklet/meta/lib/parse-navigation-from-blocklet');
|
|
27
|
-
const parseNavigationOld = require('@blocklet/meta/lib/parse-navigation');
|
|
28
|
-
|
|
29
|
-
const logger = require('@abtnode/logger')(require('../../package.json').name);
|
|
30
|
-
|
|
31
|
-
const getConfigs = require('../util/get-configs');
|
|
32
|
-
const { fillDashboardNavigation, ensureSessionManagerNavigation } = require('../util/navigation');
|
|
33
|
-
|
|
34
|
-
module.exports = {
|
|
35
|
-
init(app, node, { enableCache = false } = {}) {
|
|
36
|
-
const isDev = process.env.NODE_ENV === 'development';
|
|
37
|
-
// staticDir in development is ../../public
|
|
38
|
-
const staticDir = isDev ? path.resolve(__dirname, '../../public') : path.resolve(__dirname, './build');
|
|
39
|
-
|
|
40
|
-
const onSendFallbackLogo = ({ res, sendOptions }) => {
|
|
41
|
-
res.sendFile('/images/blocklet.png', { root: staticDir, ...sendOptions });
|
|
42
|
-
};
|
|
43
|
-
|
|
44
|
-
app.get(
|
|
45
|
-
'/blocklet/logo/:did',
|
|
46
|
-
attachSendLogoContext({
|
|
47
|
-
onSendFallbackLogo,
|
|
48
|
-
onGetBlocklet: ({ req }) => {
|
|
49
|
-
const { did } = req.params;
|
|
50
|
-
return node.ensureBlockletIntegrity(did);
|
|
51
|
-
},
|
|
52
|
-
}),
|
|
53
|
-
|
|
54
|
-
ensureBlockletExist,
|
|
55
|
-
ensureCustomSquareLogo,
|
|
56
|
-
ensureBundleLogo,
|
|
57
|
-
fallbackLogo,
|
|
58
|
-
cacheError
|
|
59
|
-
);
|
|
60
|
-
|
|
61
|
-
app.get(
|
|
62
|
-
'/blocklet/logo-bundle/**',
|
|
63
|
-
attachSendLogoContext({
|
|
64
|
-
onSendFallbackLogo,
|
|
65
|
-
onGetBlocklet: async ({ req }) => {
|
|
66
|
-
const dids = req.url.split('?')[0].replace('/blocklet/logo-bundle/', '').split('/').filter(Boolean);
|
|
67
|
-
const blocklet = await node.ensureBlockletIntegrity(dids[0]);
|
|
68
|
-
return findComponentById(blocklet, dids);
|
|
69
|
-
},
|
|
70
|
-
}),
|
|
71
|
-
|
|
72
|
-
ensureBlockletExist,
|
|
73
|
-
ensureBundleLogo,
|
|
74
|
-
fallbackLogo,
|
|
75
|
-
cacheError
|
|
76
|
-
);
|
|
77
|
-
|
|
78
|
-
// cache at most 50 and at most 5 minute
|
|
79
|
-
const metaCache = new LRU({ max: 50, maxAge: 5 * 60 * 1000 });
|
|
80
|
-
const getCacheKey = (did, childDid) => md5(`${did}-${childDid}-meta`);
|
|
81
|
-
|
|
82
|
-
[BlockletEvents.started, BlockletEvents.reloaded, BlockletEvents.updated].forEach(event => {
|
|
83
|
-
node.on(event, blocklet => {
|
|
84
|
-
const did = get(blocklet, 'meta.did');
|
|
85
|
-
forEachBlocklet(
|
|
86
|
-
blocklet,
|
|
87
|
-
b => {
|
|
88
|
-
const childDid = get(b, 'meta.did');
|
|
89
|
-
metaCache.del(getCacheKey(did, childDid));
|
|
90
|
-
},
|
|
91
|
-
{ sync: true }
|
|
92
|
-
);
|
|
93
|
-
});
|
|
94
|
-
});
|
|
95
|
-
|
|
96
|
-
app.get(/.*\/__(meta|blocklet)__\.js$/, async (req, res) => {
|
|
97
|
-
const did = req.headers['x-blocklet-did'] || '';
|
|
98
|
-
const componentId = req.headers['x-blocklet-component-id'] || '';
|
|
99
|
-
if (req.query.force) {
|
|
100
|
-
metaCache.del(getCacheKey(componentId));
|
|
101
|
-
}
|
|
102
|
-
|
|
103
|
-
let configs = [];
|
|
104
|
-
let blocklet = {};
|
|
105
|
-
let name;
|
|
106
|
-
let description;
|
|
107
|
-
let appId;
|
|
108
|
-
let appUrl;
|
|
109
|
-
let appLogo;
|
|
110
|
-
let appLogoRect;
|
|
111
|
-
|
|
112
|
-
const respond = env => {
|
|
113
|
-
if (req.query.type === 'json') {
|
|
114
|
-
return res.json(
|
|
115
|
-
env.reduce((acc, x) => {
|
|
116
|
-
acc[x.key] = x.value;
|
|
117
|
-
return acc;
|
|
118
|
-
}, {})
|
|
119
|
-
);
|
|
120
|
-
}
|
|
121
|
-
|
|
122
|
-
const envStr = env.map(x => `${x.key}: ${JSON.stringify(x.value)}`).join(',');
|
|
123
|
-
const jsStr = `window.blocklet = {${envStr}}`;
|
|
124
|
-
return res.type('js').send(jsStr);
|
|
125
|
-
};
|
|
126
|
-
|
|
127
|
-
const cacheKey = getCacheKey(componentId);
|
|
128
|
-
if (enableCache) {
|
|
129
|
-
const cache = metaCache.get(cacheKey);
|
|
130
|
-
if (cache) {
|
|
131
|
-
return respond(cache);
|
|
132
|
-
}
|
|
133
|
-
}
|
|
134
|
-
|
|
135
|
-
if (did) {
|
|
136
|
-
try {
|
|
137
|
-
blocklet = await node.ensureBlockletIntegrity(did);
|
|
138
|
-
configs = getConfigs(blocklet, componentId);
|
|
139
|
-
const info = getBlockletInfo(blocklet, null, { returnWallet: false });
|
|
140
|
-
name = info.name;
|
|
141
|
-
description = info.description;
|
|
142
|
-
appId = blocklet.appDid;
|
|
143
|
-
appUrl = blocklet.environmentObj.BLOCKLET_APP_URL;
|
|
144
|
-
appLogo = blocklet.environmentObj.BLOCKLET_APP_LOGO;
|
|
145
|
-
appLogoRect = blocklet.environmentObj.BLOCKLET_APP_LOGO_RECT;
|
|
146
|
-
} catch (error) {
|
|
147
|
-
logger.error('get __blocklet__.js failed', { did, componentId, error });
|
|
148
|
-
}
|
|
149
|
-
}
|
|
150
|
-
|
|
151
|
-
const nodeInfo = await node.getNodeInfo();
|
|
152
|
-
const groupPathPrefix = normalizePathPrefix(req.headers['x-group-path-prefix']) || '/';
|
|
153
|
-
|
|
154
|
-
const env = [
|
|
155
|
-
...configs.filter(x => !isPreferenceKey(x)),
|
|
156
|
-
|
|
157
|
-
// Unify with backend sdk
|
|
158
|
-
{ key: 'appId', value: appId },
|
|
159
|
-
{ key: 'appName', value: name },
|
|
160
|
-
{ key: 'name', value: name }, // deprecated
|
|
161
|
-
{ key: 'appDescription', value: description },
|
|
162
|
-
{ key: 'description', value: description }, // deprecated
|
|
163
|
-
{ key: 'appUrl', value: appUrl },
|
|
164
|
-
{ key: 'isComponent', value: did !== componentId },
|
|
165
|
-
|
|
166
|
-
// Web only
|
|
167
|
-
{ key: 'prefix', value: normalizePathPrefix(req.headers['x-path-prefix']) || '/' },
|
|
168
|
-
{ key: 'groupPrefix', value: groupPathPrefix },
|
|
169
|
-
{ key: 'version', value: get(blocklet, 'meta.version', '') },
|
|
170
|
-
{ key: 'componentId', value: componentId },
|
|
171
|
-
{ key: 'did', value: did }, // deprecated
|
|
172
|
-
{
|
|
173
|
-
key: 'appLogo',
|
|
174
|
-
value:
|
|
175
|
-
appLogo || normalizePathPrefix(`${groupPathPrefix}${WELLKNOWN_SERVICE_PATH_PREFIX}/blocklet/logo`) || '/',
|
|
176
|
-
},
|
|
177
|
-
{
|
|
178
|
-
key: 'appLogoRect',
|
|
179
|
-
value: appLogoRect || '',
|
|
180
|
-
},
|
|
181
|
-
{ key: 'webWalletUrl', value: nodeInfo.webWalletUrl },
|
|
182
|
-
|
|
183
|
-
{
|
|
184
|
-
key: 'preferences',
|
|
185
|
-
value: configs
|
|
186
|
-
.filter(x => x.key.startsWith(BLOCKLET_PREFERENCE_PREFIX))
|
|
187
|
-
.reduce((acc, x) => {
|
|
188
|
-
acc[x.key.replace(BLOCKLET_PREFERENCE_PREFIX, '')] = formatEnv(x.value, false);
|
|
189
|
-
return acc;
|
|
190
|
-
}, {}),
|
|
191
|
-
},
|
|
192
|
-
];
|
|
193
|
-
|
|
194
|
-
if (get(blocklet, 'meta.theme')) {
|
|
195
|
-
env.push({ key: 'theme', value: blocklet.meta.theme });
|
|
196
|
-
}
|
|
197
|
-
|
|
198
|
-
if (get(blocklet, 'meta.copyright')) {
|
|
199
|
-
env.push({ key: 'copyright', value: blocklet.meta.copyright });
|
|
200
|
-
}
|
|
201
|
-
|
|
202
|
-
const { navigationList, components } = parseNavigation(blocklet, {
|
|
203
|
-
beforeProcess(rawList) {
|
|
204
|
-
const copyList = cloneDeep(rawList);
|
|
205
|
-
fillDashboardNavigation(copyList);
|
|
206
|
-
if (!copyList.some(x => x.id && (x.section || []).includes('sessionManager'))) {
|
|
207
|
-
ensureSessionManagerNavigation(copyList);
|
|
208
|
-
}
|
|
209
|
-
return copyList;
|
|
210
|
-
},
|
|
211
|
-
});
|
|
212
|
-
let navigation = [];
|
|
213
|
-
|
|
214
|
-
// HACK: 如果新的方案未找到任何 navigations,则回滚回原有的方式找 navigation(新的方案需要每一个菜单都有 id,没有 id 的会自动过滤掉,此方案为一个过渡方案)
|
|
215
|
-
const cleanList = navigationList.filter(item => item.from !== 'tmpl');
|
|
216
|
-
if (cleanList.length === 0) {
|
|
217
|
-
navigation = parseNavigationOld(blocklet.meta?.navigation || [], blocklet, groupPathPrefix);
|
|
218
|
-
fillDashboardNavigation(navigation);
|
|
219
|
-
ensureSessionManagerNavigation(navigation);
|
|
220
|
-
} else {
|
|
221
|
-
navigation = filterNavigation(navigationList, components);
|
|
222
|
-
navigation = joinLink(navigation, components);
|
|
223
|
-
navigation = cleanOrphanNavigation(navigation);
|
|
224
|
-
}
|
|
225
|
-
|
|
226
|
-
env.push({ key: 'navigation', value: navigation });
|
|
227
|
-
|
|
228
|
-
const mountPoints = [];
|
|
229
|
-
for (const x of blocklet.children || []) {
|
|
230
|
-
mountPoints.push({
|
|
231
|
-
title: x.meta.title,
|
|
232
|
-
name: x.meta.bundleName,
|
|
233
|
-
did: x.meta.bundleDid,
|
|
234
|
-
mountPoint: x.mountPoint || '',
|
|
235
|
-
});
|
|
236
|
-
}
|
|
237
|
-
env.push({ key: 'componentMountPoints', value: mountPoints });
|
|
238
|
-
|
|
239
|
-
if (enableCache) {
|
|
240
|
-
metaCache.set(cacheKey, env);
|
|
241
|
-
}
|
|
242
|
-
|
|
243
|
-
return respond(env);
|
|
244
|
-
});
|
|
245
|
-
},
|
|
246
|
-
};
|