@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.
Files changed (198) hide show
  1. package/blocklet.yml +6 -3
  2. package/build/asset-manifest.json +93 -0
  3. package/build/favicon.ico +0 -0
  4. package/build/icons/css/all.css +5919 -0
  5. package/build/icons/css/brands.css +14 -0
  6. package/build/icons/css/brands.min.css +12 -0
  7. package/build/icons/css/fontawesome.css +7816 -0
  8. package/build/icons/css/fontawesome.min.css +5864 -0
  9. package/build/icons/css/light.css +15 -0
  10. package/build/icons/css/light.min.css +13 -0
  11. package/build/icons/webfonts/fa-brands-400.eot +0 -0
  12. package/build/icons/webfonts/fa-brands-400.svg +1256 -0
  13. package/build/icons/webfonts/fa-brands-400.ttf +0 -0
  14. package/build/icons/webfonts/fa-brands-400.woff +0 -0
  15. package/build/icons/webfonts/fa-brands-400.woff2 +0 -0
  16. package/build/icons/webfonts/fa-light-300.eot +0 -0
  17. package/build/icons/webfonts/fa-light-300.svg +4445 -0
  18. package/build/icons/webfonts/fa-light-300.ttf +0 -0
  19. package/build/icons/webfonts/fa-light-300.woff +0 -0
  20. package/build/icons/webfonts/fa-light-300.woff2 +0 -0
  21. package/build/images/blocklet.png +0 -0
  22. package/build/images/blocklets-00c2c4.png +0 -0
  23. package/build/images/blocklets-222222.png +0 -0
  24. package/build/images/celebrate.png +0 -0
  25. package/build/images/community.svg +6 -0
  26. package/build/images/console-00c2c4.png +0 -0
  27. package/build/images/console-222222.png +0 -0
  28. package/build/images/dashboard-00c2c4.png +0 -0
  29. package/build/images/dashboard-222222.png +0 -0
  30. package/build/images/doc-222222.png +0 -0
  31. package/build/images/hourglass-222222.png +0 -0
  32. package/build/images/https-certificate-icon.png +0 -0
  33. package/build/images/labs-00c2c4.png +0 -0
  34. package/build/images/labs-222222.png +0 -0
  35. package/build/images/log-00c2c4.png +0 -0
  36. package/build/images/log-222222.png +0 -0
  37. package/build/images/member-222222.png +0 -0
  38. package/build/images/node.png +0 -0
  39. package/build/images/official.svg +1 -0
  40. package/build/images/private-222222.png +0 -0
  41. package/build/images/public-222222.png +0 -0
  42. package/build/images/public_avatar.png +0 -0
  43. package/build/images/router-00c2c4.png +0 -0
  44. package/build/images/router-222222.png +0 -0
  45. package/build/images/settings-00c2c4.png +0 -0
  46. package/build/images/settings-222222.png +0 -0
  47. package/build/images/slack.png +0 -0
  48. package/build/images/storage-222222.png +0 -0
  49. package/build/images/store-00c2c4.png +0 -0
  50. package/build/images/store-222222.png +0 -0
  51. package/build/images/team-00c2c4.png +0 -0
  52. package/build/images/team-222222.png +0 -0
  53. package/build/images/time-222222.png +0 -0
  54. package/build/images/upgrade.png +0 -0
  55. package/build/index.html +1 -0
  56. package/build/manifest.json +15 -0
  57. package/build/static/css/4381.5ade355d.chunk.css +1 -0
  58. package/build/static/css/4691.56c2f951.chunk.css +1 -0
  59. package/build/static/css/5245.5d6e9197.chunk.css +1 -0
  60. package/build/static/css/8213.f696fdbf.chunk.css +1 -0
  61. package/build/static/css/9779.f696fdbf.chunk.css +1 -0
  62. package/build/static/css/main.c9e90622.css +1 -0
  63. package/build/static/images/logo.png +0 -0
  64. package/build/static/js/1057.8280393f.chunk.js +1 -0
  65. package/build/static/js/1361.85e46159.chunk.js +1 -0
  66. package/build/static/js/1366.2f174c9b.chunk.js +2 -0
  67. package/build/static/js/1366.2f174c9b.chunk.js.LICENSE.txt +37 -0
  68. package/build/static/js/154.94956824.chunk.js +1 -0
  69. package/build/static/js/1826.07c285de.chunk.js +1 -0
  70. package/build/static/js/2129.120e36ae.chunk.js +1 -0
  71. package/build/static/js/2308.b65bc299.chunk.js +1 -0
  72. package/build/static/js/2564.eef717f3.chunk.js +1 -0
  73. package/build/static/js/2657.d3c62d57.chunk.js +1 -0
  74. package/build/static/js/2720.26eb1788.chunk.js +1 -0
  75. package/build/static/js/2828.4f318970.chunk.js +1 -0
  76. package/build/static/js/2878.5626558d.chunk.js +1 -0
  77. package/build/static/js/3111.84e02823.chunk.js +1 -0
  78. package/build/static/js/3476.c0b3411b.chunk.js +1 -0
  79. package/build/static/js/3633.8c7cf02d.chunk.js +1 -0
  80. package/build/static/js/3732.f5d8b39b.chunk.js +1 -0
  81. package/build/static/js/3776.1490b0f7.chunk.js +1 -0
  82. package/build/static/js/3829.b6d6cf45.chunk.js +1 -0
  83. package/build/static/js/4074.19db40ec.chunk.js +1 -0
  84. package/build/static/js/4104.b47ae0e1.chunk.js +1 -0
  85. package/build/static/js/4241.83e4f741.chunk.js +1 -0
  86. package/build/static/js/4274.e18ffddd.chunk.js +1 -0
  87. package/build/static/js/4349.7c2f6507.chunk.js +1 -0
  88. package/build/static/js/4381.631ef61d.chunk.js +2 -0
  89. package/build/static/js/4381.631ef61d.chunk.js.LICENSE.txt +22 -0
  90. package/build/static/js/4557.3907550e.chunk.js +1 -0
  91. package/build/static/js/4590.5a14012c.chunk.js +1 -0
  92. package/build/static/js/4633.9f946ed5.chunk.js +1 -0
  93. package/build/static/js/4691.550fcb40.chunk.js +2 -0
  94. package/build/static/js/4691.550fcb40.chunk.js.LICENSE.txt +8 -0
  95. package/build/static/js/5074.9ea094a9.chunk.js +1 -0
  96. package/build/static/js/5082.18d16cb9.chunk.js +1 -0
  97. package/build/static/js/519.adae6e43.chunk.js +1 -0
  98. package/build/static/js/556.381dcbd8.chunk.js +1 -0
  99. package/build/static/js/5984.25af6288.chunk.js +1 -0
  100. package/build/static/js/6158.8a43296d.chunk.js +1 -0
  101. package/build/static/js/6189.d6d74d14.chunk.js +1 -0
  102. package/build/static/js/6239.5a873a03.chunk.js +2 -0
  103. package/build/static/js/6239.5a873a03.chunk.js.LICENSE.txt +14 -0
  104. package/build/static/js/629.1a7f2553.chunk.js +1 -0
  105. package/build/static/js/6413.ab4a8e01.chunk.js +1 -0
  106. package/build/static/js/6602.c417a217.chunk.js +1 -0
  107. package/build/static/js/6780.64314507.chunk.js +1 -0
  108. package/build/static/js/6830.88b993a0.chunk.js +1 -0
  109. package/build/static/js/6866.2131ea60.chunk.js +2 -0
  110. package/build/static/js/6866.2131ea60.chunk.js.LICENSE.txt +8 -0
  111. package/build/static/js/6898.6fe0c32d.chunk.js +2 -0
  112. package/build/static/js/6898.6fe0c32d.chunk.js.LICENSE.txt +5 -0
  113. package/build/static/js/7016.835958ef.chunk.js +1 -0
  114. package/build/static/js/7298.a7286c09.chunk.js +1 -0
  115. package/build/static/js/7327.56a5e016.chunk.js +1 -0
  116. package/build/static/js/744.8b656dd2.chunk.js +1 -0
  117. package/build/static/js/7652.722b9180.chunk.js +1 -0
  118. package/build/static/js/8034.c4dcdeff.chunk.js +1 -0
  119. package/build/static/js/8058.0b2d4727.chunk.js +1 -0
  120. package/build/static/js/8213.09f25083.chunk.js +1 -0
  121. package/build/static/js/8235.add24931.chunk.js +1 -0
  122. package/build/static/js/8249.63c55b3a.chunk.js +1 -0
  123. package/build/static/js/8262.869cc799.chunk.js +1 -0
  124. package/build/static/js/8352.b57b0e44.chunk.js +1 -0
  125. package/build/static/js/8464.b4b82828.chunk.js +1 -0
  126. package/build/static/js/8606.66db67e2.chunk.js +1 -0
  127. package/build/static/js/9038.2908c176.chunk.js +1 -0
  128. package/build/static/js/9076.c77366bc.chunk.js +1 -0
  129. package/build/static/js/9301.a65db324.chunk.js +2 -0
  130. package/build/static/js/9301.a65db324.chunk.js.LICENSE.txt +8 -0
  131. package/build/static/js/9575.36f3de5b.chunk.js +2 -0
  132. package/build/static/js/9575.36f3de5b.chunk.js.LICENSE.txt +194 -0
  133. package/build/static/js/9779.bbf0dd81.chunk.js +1 -0
  134. package/build/static/js/main.cb5d8d67.js +2 -0
  135. package/build/static/js/main.cb5d8d67.js.LICENSE.txt +159 -0
  136. package/build/static/media/iconify.32b54549e843e448ee9b.cjs +2 -0
  137. package/build/static/media/iconify.32b54549e843e448ee9b.cjs.LICENSE.txt +13 -0
  138. package/build/static/media/lato-all-400-normal.3dc1eff492ab1f598560.woff +0 -0
  139. package/build/static/media/lato-all-700-normal.1e7707c9ec98d9b97e7f.woff +0 -0
  140. package/build/static/media/lato-latin-400-normal.be36596da218e1eec01c.woff2 +0 -0
  141. package/build/static/media/lato-latin-700-normal.8f28e0e1fdb195149f1c.woff2 +0 -0
  142. package/build/static/media/lato-latin-ext-400-normal.361f3dbb9db6a5980326.woff2 +0 -0
  143. package/build/static/media/lato-latin-ext-700-normal.9c8812eaec45956201e1.woff2 +0 -0
  144. package/build/static/media/logo.60f66bbe1ce9674a4df4e374c9d97fc4.svg +16 -0
  145. package/build/static/media/ubuntu-mono-all-400-normal.c879328bc62e9c68268f.woff +0 -0
  146. package/build/static/media/ubuntu-mono-cyrillic-400-normal.c367f416832eb8f1b846.woff2 +0 -0
  147. package/build/static/media/ubuntu-mono-cyrillic-ext-400-normal.eda1c4946b1f7bf58386.woff2 +0 -0
  148. package/build/static/media/ubuntu-mono-greek-400-normal.22f3bfc91f79c342bdf4.woff2 +0 -0
  149. package/build/static/media/ubuntu-mono-greek-ext-400-normal.b3459900ea8a25d1f7c2.woff2 +0 -0
  150. package/build/static/media/ubuntu-mono-latin-400-normal.18e32d9d743af28f913e.woff2 +0 -0
  151. package/build/static/media/ubuntu-mono-latin-ext-400-normal.b56e2315611d10838ad5.woff2 +0 -0
  152. package/package.json +1 -1
  153. package/api/gql/config.js +0 -392
  154. package/api/gql/index.js +0 -102
  155. package/api/gql/middlewares/create-audit-log.js +0 -3
  156. package/api/gql/middlewares/get-blocklet-list.js +0 -14
  157. package/api/gql/middlewares/install-blocklet.js +0 -13
  158. package/api/gql/middlewares/verify-blocklet.js +0 -21
  159. package/api/gql/middlewares/verify-team.js +0 -9
  160. package/api/index.js +0 -249
  161. package/api/libs/auth.js +0 -78
  162. package/api/libs/env.js +0 -3
  163. package/api/libs/login.js +0 -212
  164. package/api/libs/security.js +0 -90
  165. package/api/libs/storage.js +0 -69
  166. package/api/middlewares/mutate-blocklet-permission.js +0 -18
  167. package/api/routes/auth/accept-server.js +0 -28
  168. package/api/routes/auth/connect-owner.js +0 -143
  169. package/api/routes/auth/delegate-transfer-owner-nft.js +0 -86
  170. package/api/routes/auth/invite.js +0 -93
  171. package/api/routes/auth/issue-passport.js +0 -61
  172. package/api/routes/auth/launch-free-blocklet-by-nft.js +0 -9
  173. package/api/routes/auth/launch-free-blocklet.js +0 -9
  174. package/api/routes/auth/launch-paid-blocklet-by-nft.js +0 -9
  175. package/api/routes/auth/launch-paid-blocklet.js +0 -9
  176. package/api/routes/auth/login.js +0 -63
  177. package/api/routes/auth/lost-passport-issue.js +0 -5
  178. package/api/routes/auth/lost-passport-list.js +0 -5
  179. package/api/routes/auth/switch-passport.js +0 -47
  180. package/api/routes/auth/switch-profile.js +0 -69
  181. package/api/routes/auth/util.js +0 -135
  182. package/api/routes/auth/verify-owner.js +0 -39
  183. package/api/routes/auth/verify-purchase.js +0 -185
  184. package/api/routes/blocklet-info.js +0 -246
  185. package/api/routes/blocklet-preference.js +0 -161
  186. package/api/routes/blocklet-proxy.js +0 -220
  187. package/api/routes/did-resolver.js +0 -38
  188. package/api/routes/dns-resolver.js +0 -73
  189. package/api/routes/log.js +0 -31
  190. package/api/routes/passport.js +0 -19
  191. package/api/routes/session.js +0 -61
  192. package/api/routes/user.js +0 -38
  193. package/api/util/find-routing-rule.js +0 -95
  194. package/api/util/get-configs.js +0 -31
  195. package/api/util/index.js +0 -5
  196. package/api/util/navigation.js +0 -84
  197. package/api/webpack.blocklet.js +0 -43
  198. 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
- };
@@ -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
- };