@abtnode/blocklet-services 1.16.0-beta-1f8bf936 → 1.16.0-beta-58020de5

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.
@@ -30,6 +30,7 @@ async function getAvatarByEmail(email = '') {
30
30
  }
31
31
  }
32
32
 
33
+ // FIXME: @zhanghan 转移通行证目前只能颁发新的,会导致用户数据中产生多余的通行证
33
34
  async function transferPassport(fromUser, toUser, { req, teamDid, node, nodeInfo }) {
34
35
  const {
35
36
  name: issuerName,
@@ -33,7 +33,7 @@ const {
33
33
  } = require('@abtnode/auth/lib/passport');
34
34
  const { getKeyPairClaim } = require('@abtnode/auth/lib/server');
35
35
  const sortBy = require('lodash/sortBy');
36
- const head = require('lodash/head');
36
+ const last = require('lodash/last');
37
37
 
38
38
  const { getRolesFromAuthConfig, getBlockletAppIdList } = require('@blocklet/meta/lib/util');
39
39
 
@@ -41,6 +41,7 @@ const logger = require('@abtnode/logger')(require('../../../package.json').name)
41
41
 
42
42
  const { isInvitedUserOnly } = require('../../util');
43
43
  const { transferPassport } = require('../auth/utils');
44
+ const { generateTranslate } = require('../translate');
44
45
 
45
46
  const vcTypes = [VC_TYPE_GENERAL_PASSPORT, VC_TYPE_NODE_PASSPORT];
46
47
 
@@ -222,7 +223,7 @@ module.exports = {
222
223
  // Get user passport from vc
223
224
  let passport = vc ? createUserPassport(vc) : null;
224
225
  if (user && passport && isUserPassportRevoked(user, passport)) {
225
- throw new Error(messages.passportRevoked[locale](name));
226
+ throw new Error(messages.passportRevoked[locale](passport.title, name));
226
227
  }
227
228
 
228
229
  // Get role
@@ -469,7 +470,7 @@ module.exports = {
469
470
  // Get user passport from vc
470
471
  let passport = vc ? createUserPassport(vc) : null;
471
472
  if (passport && isUserPassportRevoked(user, passport)) {
472
- throw new Error(messages.passportRevoked[locale](name));
473
+ throw new Error(messages.passportRevoked[locale](passport.title, name));
473
474
  }
474
475
 
475
476
  // Get role
@@ -483,6 +484,7 @@ module.exports = {
483
484
  teamDid,
484
485
  user: {
485
486
  did: user.did,
487
+ pk: user.pk,
486
488
  passports: upsertToPassports(
487
489
  user.passports || [],
488
490
  passport && { ...passport, lastLoginAt: new Date().toISOString() }
@@ -525,6 +527,7 @@ module.exports = {
525
527
  alreadyBind: '该账户已绑定 OAuth 账户',
526
528
  },
527
529
  };
530
+ const t = generateTranslate({ translations });
528
531
  const blocklet = await request.getBlocklet();
529
532
  const config = await request.getServiceConfig(NODE_SERVICES.AUTH, { componentId });
530
533
  const { did: teamDid } = await request.getBlockletInfo();
@@ -532,17 +535,17 @@ module.exports = {
532
535
  const bindUser = await node.getUser({ teamDid: blocklet.meta.did, user: { did: userDid } });
533
536
 
534
537
  if (!oauthUser) {
535
- throw new Error(translations[locale].notFound);
538
+ throw new Error(t('notFound'));
536
539
  }
537
540
  if (oauthUser.source !== USER_TYPE.DERIVED) {
538
- throw new Error(translations[locale].notDerivedAccount);
541
+ throw new Error(t('notDerivedAccount'));
539
542
  }
540
543
  if (bindUser) {
541
544
  if (bindUser.source === USER_TYPE.DERIVED) {
542
- throw new Error(translations[locale].notWalletAccount);
545
+ throw new Error(t('notWalletAccount'));
543
546
  }
544
547
  if (bindUser.derivedAccount) {
545
- throw new Error(translations[locale].alreadyBind);
548
+ throw new Error(t('alreadyBind'));
546
549
  }
547
550
  }
548
551
 
@@ -590,7 +593,7 @@ module.exports = {
590
593
  // TODO: 获取当前登录使用的 passport(无法获取到 passport.id)
591
594
  // 使用最近一次使用的 passport 来代替
592
595
  const validPassports = oauthUser.passports.filter((item) => item.status === 'valid');
593
- const lastUsedPassport = head(sortBy(validPassports, 'lastLoginAt'));
596
+ const lastUsedPassport = last(sortBy(validPassports, 'lastLoginAt'));
594
597
  const passport = lastUsedPassport || { name: 'Guest', role: 'guest' };
595
598
  if (bindUser) {
596
599
  const mergePassport = (oauthUser.passports || []).reduce((sum, cur) => {
@@ -612,6 +615,7 @@ module.exports = {
612
615
  lastLoginAt: oauthUser.lastLoginAt,
613
616
  },
614
617
  ],
618
+ source: USER_TYPE.WALLET,
615
619
  did: userDid,
616
620
  pk: userPk,
617
621
  locale,
@@ -659,12 +663,13 @@ module.exports = {
659
663
  });
660
664
  bindUser = doc;
661
665
  // remove derived account (updateUser use did as key, so did can't be update)
662
- await node.removeUser({
663
- teamDid,
664
- user: {
665
- did: previousUserDid,
666
- },
667
- });
666
+ // FIXME: @zhanghan 将来是否需要移除 derived account
667
+ // await node.removeUser({
668
+ // teamDid,
669
+ // user: {
670
+ // did: previousUserDid,
671
+ // },
672
+ // });
668
673
  // TODO: @zhanghan 需要增加 auditLog
669
674
  }
670
675
 
@@ -0,0 +1,12 @@
1
+ const get = require('lodash/get');
2
+
3
+ function generateTranslate({ translations, defaultLocale = 'en' }) {
4
+ const languages = Object.keys(translations);
5
+
6
+ return (key, _locale = defaultLocale) => {
7
+ const locale = languages.includes(_locale) ? _locale : defaultLocale;
8
+ return get(translations[locale], key, key);
9
+ };
10
+ }
11
+
12
+ module.exports = { generateTranslate };
@@ -140,20 +140,34 @@ module.exports = {
140
140
  const { did: userDid, role } = req.user;
141
141
 
142
142
  // eslint-disable-next-line no-unreachable
143
- const doc = await node.startBlocklet({
144
- did: blocklet.meta.did,
145
- checkHealthImmediately: true,
146
- throwOnError: true,
147
- });
148
- await node.createAuditLog(
149
- {
150
- action: 'startBlocklet',
151
- args: { did: blocklet.meta.did },
152
- context: formatContext(req),
153
- result: doc,
154
- },
155
- node
156
- );
143
+
144
+ let startError;
145
+ let doc;
146
+ try {
147
+ doc = await node.startBlocklet({
148
+ did: blocklet.meta.did,
149
+ checkHealthImmediately: true,
150
+ throwOnError: true,
151
+ });
152
+ } catch (error) {
153
+ startError = error;
154
+ }
155
+
156
+ if (!startError) {
157
+ try {
158
+ await node.createAuditLog(
159
+ {
160
+ action: 'startBlocklet',
161
+ args: { did: blocklet.meta.did },
162
+ context: formatContext(req),
163
+ result: doc,
164
+ },
165
+ node
166
+ );
167
+ } catch (error) {
168
+ logger.error('create start-blocklet audit log failed', { error });
169
+ }
170
+ }
157
171
 
158
172
  if (fromSetup) {
159
173
  const teamDid = blocklet.meta.did;
@@ -169,7 +183,7 @@ module.exports = {
169
183
  // 调用 store 管理公开实例
170
184
  // 如果一个 blocklet 没有设置 公开实例,启动成功后不应给 store 发请求
171
185
  const { publicToStore } = blocklet.settings;
172
- if (publicToStore) {
186
+ if (publicToStore && !startError) {
173
187
  try {
174
188
  await handleInstanceInStore(blocklet, { userDid, publicToStore });
175
189
  } catch (error) {
@@ -219,35 +233,80 @@ module.exports = {
219
233
  node
220
234
  );
221
235
 
222
- // send vc to wallet
236
+ // send notification to wallet
223
237
  const receiver = userDid;
224
238
  const token = JWT.sign(wallet.address, wallet.secretKey);
225
- const data = {
226
- sender: { token, appDid: wallet.address },
227
- receiver,
228
- notification: {
239
+
240
+ if (!blocklet.settings.owner) {
241
+ // send owner vc
242
+ const notificationText = {
229
243
  title: {
230
- en: 'Up and Running',
231
- zh: '启动并运行',
244
+ en: 'You have become the application owner',
245
+ zh: '你已成为应用所有者',
232
246
  }[locale],
233
247
  body: {
234
- en: 'The application is up and running successfully',
235
- zh: '应用程序已启动并成功运行',
248
+ en: 'You have become the application owner',
249
+ zh: '你已成为应用所有者',
236
250
  }[locale],
237
- attachments: [
238
- {
239
- type: 'vc',
240
- data: {
241
- credential: vc,
242
- tag: role,
251
+ };
252
+
253
+ const data = {
254
+ sender: { token, appDid: wallet.address },
255
+ receiver,
256
+ notification: {
257
+ ...notificationText,
258
+ attachments: [
259
+ {
260
+ type: 'vc',
261
+ data: {
262
+ credential: vc,
263
+ tag: role,
264
+ },
243
265
  },
244
- },
245
- ],
266
+ ],
267
+ },
268
+ };
269
+ server.emit('sendToUser', data);
270
+ }
271
+
272
+ // send message
273
+ const notificationText = startError
274
+ ? {
275
+ title: {
276
+ en: 'Application start failed',
277
+ zh: '应用启动失败',
278
+ }[locale],
279
+ body: {
280
+ en: `Application start failed: ${startError.message}`,
281
+ zh: `应用启动失败: ${startError.message}`,
282
+ }[locale],
283
+ }
284
+ : {
285
+ title: {
286
+ en: 'Up and Running',
287
+ zh: '启动并运行',
288
+ }[locale],
289
+ body: {
290
+ en: 'The application is up and running successfully',
291
+ zh: '应用程序已启动并成功运行',
292
+ }[locale],
293
+ };
294
+
295
+ // send vc to wallet
296
+ const data = {
297
+ sender: { token, appDid: wallet.address },
298
+ receiver,
299
+ notification: {
300
+ ...notificationText,
246
301
  },
247
302
  };
248
303
  server.emit('sendToUser', data);
249
304
  }
250
305
 
306
+ if (startError) {
307
+ throw startError;
308
+ }
309
+
251
310
  return res.json(polishBlocklet(doc));
252
311
  });
253
312
 
@@ -5,7 +5,7 @@ const { parseUserAvatar, extractUserAvatar } = require('@abtnode/util/lib/user-a
5
5
  const { types } = require('@arcblock/did');
6
6
  const { fromAppDid } = require('@arcblock/did-ext');
7
7
  const get = require('lodash/get');
8
- const head = require('lodash/head');
8
+ const last = require('lodash/last');
9
9
  const pick = require('lodash/pick');
10
10
  const sortBy = require('lodash/sortBy');
11
11
  const joinUrl = require('url-join');
@@ -15,12 +15,23 @@ const { getAvatarByEmail, transferPassport } = require('../libs/auth/utils');
15
15
  const { getUser } = require('../libs/jwt');
16
16
  const initJwt = require('../libs/jwt');
17
17
  const { sendToUser } = require('../libs/notification');
18
+ const { generateTranslate } = require('../libs/translate');
18
19
  const { isInvitedUserOnly } = require('../util');
19
20
 
20
21
  const PREFIX = WELLKNOWN_SERVICE_PATH_PREFIX;
21
22
 
22
23
  const prefix = `${PREFIX}/oauth`;
23
24
 
25
+ const translations = {
26
+ zh: {
27
+ needInviteToLogin: '你需要被邀请才可以登录此应用',
28
+ },
29
+ en: {
30
+ needInviteToLogin: 'You need to be invited to sign in to this app',
31
+ },
32
+ };
33
+ const t = generateTranslate({ translations });
34
+
24
35
  async function getDerivedUser(derivedDid, { node, teamDid }) {
25
36
  const { users } = await node.getUsers({
26
37
  teamDid,
@@ -47,6 +58,8 @@ async function login(req, node, options) {
47
58
  });
48
59
  const { did: teamDid, wallet: blockletWallet } = await req.getBlockletInfo();
49
60
  const config = await req.getServiceConfig(NODE_SERVICES.AUTH, { componentId });
61
+ const nodeInfo = await req.getNodeInfo();
62
+ const { dataDir } = await getApplicationInfo({ node, nodeInfo, teamDid });
50
63
  const [invitedUserOnly] = await isInvitedUserOnly(config, node, teamDid);
51
64
  const userInfo = await authClient.getProfile(token);
52
65
  const userWallet = fromAppDid(userInfo.sub, blockletWallet.secretKey, types.RoleType.ROLE_ACCOUNT);
@@ -56,7 +69,7 @@ async function login(req, node, options) {
56
69
  // 当前 oauth 账户已经绑定了 wallet 账户
57
70
  if (currentUser) {
58
71
  const validPassports = currentUser.passports.filter((item) => item.status === 'valid');
59
- const lastUsedPassport = head(sortBy(validPassports, 'lastLoginAt'));
72
+ const lastUsedPassport = last(sortBy(validPassports, 'lastLoginAt'));
60
73
  if (lastUsedPassport) {
61
74
  passport = pick(lastUsedPassport, ['id', 'name', 'role']);
62
75
  }
@@ -81,12 +94,13 @@ async function login(req, node, options) {
81
94
  currentUser = {
82
95
  did: userWallet.address,
83
96
  };
84
- const avatar = await getAvatarByEmail(userInfo.email);
97
+ let avatar = await getAvatarByEmail(userInfo.email);
98
+ avatar = await extractUserAvatar(avatar, { dataDir });
85
99
  const currentUserInfo = await getUser(node, teamDid, userDid);
86
100
  // 当前 oauth 账户不存在,自动添加一个新用户
87
101
  if (!currentUserInfo) {
88
102
  if (invitedUserOnly) {
89
- throw new Error('Need invited to login');
103
+ throw new Error(t('needInviteToLogin', locale));
90
104
  }
91
105
  await node.addUser({
92
106
  teamDid,
@@ -110,7 +124,7 @@ async function login(req, node, options) {
110
124
  });
111
125
  } else {
112
126
  const validPassports = currentUserInfo.passports.filter((item) => item.status === 'valid');
113
- const lastUsedPassport = head(sortBy(validPassports, 'lastLoginAt'));
127
+ const lastUsedPassport = last(sortBy(validPassports, 'lastLoginAt'));
114
128
  if (lastUsedPassport) {
115
129
  passport = pick(lastUsedPassport, ['id', 'name', 'role']);
116
130
  }
@@ -225,6 +239,7 @@ async function invite(req, node, options) {
225
239
  teamDid,
226
240
  user: {
227
241
  did: bindUser.did,
242
+ pk: bindUser.pk,
228
243
  connectedAccounts: [
229
244
  {
230
245
  provider: 'auth0',
@@ -239,6 +254,7 @@ async function invite(req, node, options) {
239
254
  teamDid,
240
255
  user: {
241
256
  did: userDid,
257
+ pk: userPk,
242
258
  connectedAccounts: [
243
259
  {
244
260
  provider: 'auth0',
@@ -286,6 +302,7 @@ module.exports = {
286
302
  teamDid,
287
303
  user: {
288
304
  did: userDid,
305
+ pk: bindUser.pk,
289
306
  locale,
290
307
  source: USER_TYPE.WALLET,
291
308
  derivedAccount: {
@@ -1,14 +1,14 @@
1
1
  {
2
2
  "files": {
3
3
  "main.css": "/.blocklet/proxy/blocklet-service/static/css/main.632501d5.css",
4
- "main.js": "/.blocklet/proxy/blocklet-service/static/js/main.918ec6ce.js",
4
+ "main.js": "/.blocklet/proxy/blocklet-service/static/js/main.73c39561.js",
5
5
  "static/js/716.e1534c42.chunk.js": "/.blocklet/proxy/blocklet-service/static/js/716.e1534c42.chunk.js",
6
6
  "static/js/255.279b1bca.chunk.js": "/.blocklet/proxy/blocklet-service/static/js/255.279b1bca.chunk.js",
7
- "static/js/371.575d3b08.chunk.js": "/.blocklet/proxy/blocklet-service/static/js/371.575d3b08.chunk.js",
8
- "static/js/737.14f154ca.chunk.js": "/.blocklet/proxy/blocklet-service/static/js/737.14f154ca.chunk.js",
7
+ "static/js/371.88127b62.chunk.js": "/.blocklet/proxy/blocklet-service/static/js/371.88127b62.chunk.js",
8
+ "static/js/737.ed53dec5.chunk.js": "/.blocklet/proxy/blocklet-service/static/js/737.ed53dec5.chunk.js",
9
9
  "static/js/460.3026a774.chunk.js": "/.blocklet/proxy/blocklet-service/static/js/460.3026a774.chunk.js",
10
10
  "static/js/868.f2fac071.chunk.js": "/.blocklet/proxy/blocklet-service/static/js/868.f2fac071.chunk.js",
11
- "static/js/343.d41f9df4.chunk.js": "/.blocklet/proxy/blocklet-service/static/js/343.d41f9df4.chunk.js",
11
+ "static/js/343.087cec35.chunk.js": "/.blocklet/proxy/blocklet-service/static/js/343.087cec35.chunk.js",
12
12
  "static/js/682.c64ae291.chunk.js": "/.blocklet/proxy/blocklet-service/static/js/682.c64ae291.chunk.js",
13
13
  "static/js/711.6c22b7c7.chunk.js": "/.blocklet/proxy/blocklet-service/static/js/711.6c22b7c7.chunk.js",
14
14
  "static/js/437.d815f0c0.chunk.js": "/.blocklet/proxy/blocklet-service/static/js/437.d815f0c0.chunk.js",
@@ -42,14 +42,14 @@
42
42
  "router-template-styles/styles.css": "/.blocklet/proxy/blocklet-service/router-template-styles/styles.css",
43
43
  "index.html": "/.blocklet/proxy/blocklet-service/index.html",
44
44
  "main.632501d5.css.map": "/.blocklet/proxy/blocklet-service/static/css/main.632501d5.css.map",
45
- "main.918ec6ce.js.map": "/.blocklet/proxy/blocklet-service/static/js/main.918ec6ce.js.map",
45
+ "main.73c39561.js.map": "/.blocklet/proxy/blocklet-service/static/js/main.73c39561.js.map",
46
46
  "716.e1534c42.chunk.js.map": "/.blocklet/proxy/blocklet-service/static/js/716.e1534c42.chunk.js.map",
47
47
  "255.279b1bca.chunk.js.map": "/.blocklet/proxy/blocklet-service/static/js/255.279b1bca.chunk.js.map",
48
- "371.575d3b08.chunk.js.map": "/.blocklet/proxy/blocklet-service/static/js/371.575d3b08.chunk.js.map",
49
- "737.14f154ca.chunk.js.map": "/.blocklet/proxy/blocklet-service/static/js/737.14f154ca.chunk.js.map",
48
+ "371.88127b62.chunk.js.map": "/.blocklet/proxy/blocklet-service/static/js/371.88127b62.chunk.js.map",
49
+ "737.ed53dec5.chunk.js.map": "/.blocklet/proxy/blocklet-service/static/js/737.ed53dec5.chunk.js.map",
50
50
  "460.3026a774.chunk.js.map": "/.blocklet/proxy/blocklet-service/static/js/460.3026a774.chunk.js.map",
51
51
  "868.f2fac071.chunk.js.map": "/.blocklet/proxy/blocklet-service/static/js/868.f2fac071.chunk.js.map",
52
- "343.d41f9df4.chunk.js.map": "/.blocklet/proxy/blocklet-service/static/js/343.d41f9df4.chunk.js.map",
52
+ "343.087cec35.chunk.js.map": "/.blocklet/proxy/blocklet-service/static/js/343.087cec35.chunk.js.map",
53
53
  "682.c64ae291.chunk.js.map": "/.blocklet/proxy/blocklet-service/static/js/682.c64ae291.chunk.js.map",
54
54
  "711.6c22b7c7.chunk.js.map": "/.blocklet/proxy/blocklet-service/static/js/711.6c22b7c7.chunk.js.map",
55
55
  "437.d815f0c0.chunk.js.map": "/.blocklet/proxy/blocklet-service/static/js/437.d815f0c0.chunk.js.map",
@@ -64,6 +64,6 @@
64
64
  },
65
65
  "entrypoints": [
66
66
  "static/css/main.632501d5.css",
67
- "static/js/main.918ec6ce.js"
67
+ "static/js/main.73c39561.js"
68
68
  ]
69
69
  }
package/build/index.html CHANGED
@@ -1 +1 @@
1
- <!doctype html><html lang="en"><head><meta charset="utf-8"/><link rel="icon" href="/favicon.ico"/><meta name="viewport" content="width=device-width,initial-scale=1,maximum-scale=1,user-scalable=0"/><meta name="theme-color" content="#000000"/><title>Blocklet Service</title><script src=".well-known/service/api/env"></script><script src="/__blocklet__.js"></script><script defer="defer" src="/.blocklet/proxy/blocklet-service/static/js/main.918ec6ce.js"></script><link href="/.blocklet/proxy/blocklet-service/static/css/main.632501d5.css" rel="stylesheet"></head><body><noscript>You need to enable JavaScript to run this app.</noscript><div id="root"></div></body></html>
1
+ <!doctype html><html lang="en"><head><meta charset="utf-8"/><link rel="icon" href="/favicon.ico"/><meta name="viewport" content="width=device-width,initial-scale=1,maximum-scale=1,user-scalable=0"/><meta name="theme-color" content="#000000"/><title>Blocklet Service</title><script src=".well-known/service/api/env"></script><script src="/__blocklet__.js"></script><script defer="defer" src="/.blocklet/proxy/blocklet-service/static/js/main.73c39561.js"></script><link href="/.blocklet/proxy/blocklet-service/static/css/main.632501d5.css" rel="stylesheet"></head><body><noscript>You need to enable JavaScript to run this app.</noscript><div id="root"></div></body></html>