@abtnode/blocklet-services 1.16.14-beta-1936d3d0 → 1.16.14-beta-dd4f6a50

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.
@@ -47,15 +47,14 @@ const { isInvitedUserOnly, createTokenFn, getDidConnectVersion } = require('../.
47
47
  const { transferPassport } = require('../auth/utils');
48
48
  const { generateTranslate } = require('../translate');
49
49
  const { migrateAccount, declareAccount } = require('../../services/oauth');
50
- const { getTrustedIssuers, getLoginProvider } = require('../../util/blocklet-utils');
50
+ const { getTrustedIssuers, getLoginProvider, getFederatedTrustedIssuers } = require('../../util/blocklet-utils');
51
51
  const { getFederatedMaster, getUserAvatarUrl } = require('../../util/federated');
52
52
  const { api } = require('../api');
53
53
 
54
54
  const vcTypes = [VC_TYPE_GENERAL_PASSPORT, VC_TYPE_NODE_PASSPORT];
55
55
 
56
- const getPassportVc = async ({ blocklet, claims, challenge, locale }) => {
57
- const trustedPassports = (blocklet.trustedPassports || []).map((x) => x.issuerDid);
58
- const trustedIssuers = [...getBlockletAppIdList(blocklet), ...trustedPassports].filter(Boolean);
56
+ const getPassportVc = async ({ blocklet, claims, challenge, locale, provider }) => {
57
+ const trustedIssuers = await getTrustedIssuers(blocklet, { provider });
59
58
  const { vc } = await getVCFromClaims({
60
59
  claims,
61
60
  challenge,
@@ -67,7 +66,7 @@ const getPassportVc = async ({ blocklet, claims, challenge, locale }) => {
67
66
  return vc;
68
67
  };
69
68
 
70
- const getRoleFromVC = async ({ vc, node, locale, blocklet, teamDid }) => {
69
+ const getRoleFromVC = async ({ vc, node, locale, blocklet, teamDid, provider }) => {
71
70
  let role = ROLES.GUEST;
72
71
  if (vc) {
73
72
  await validatePassport(get(vc, 'credentialSubject.passport'));
@@ -76,8 +75,12 @@ const getRoleFromVC = async ({ vc, node, locale, blocklet, teamDid }) => {
76
75
  if (expectedIssuers.includes(actualIssuer)) {
77
76
  role = getRoleFromLocalPassport(get(vc, 'credentialSubject.passport'));
78
77
  } else {
78
+ // MEMO: 如果是 federated,需要将 actualIssuer 做一个转换
79
+ const actualIssuerList =
80
+ provider === LOGIN_PROVIDER.FEDERATED ? await getFederatedTrustedIssuers(blocklet) : [actualIssuer];
79
81
  // map external passport to local role
80
- const { mappings = [] } = (blocklet.trustedPassports || []).find((x) => x.issuerDid === actualIssuer) || {};
82
+ const { mappings = [] } =
83
+ (blocklet.trustedPassports || []).find((x) => actualIssuerList.includes(x.issuerDid)) || {};
81
84
  role = await getRoleFromExternalPassport({
82
85
  passport: get(vc, 'credentialSubject.passport'),
83
86
  node,
@@ -156,7 +159,7 @@ module.exports = {
156
159
  if (action === 'login') {
157
160
  const [invitedUserOnly] = config ? await isInvitedUserOnly(config, node, teamDid) : [false];
158
161
 
159
- const trustedIssuers = getTrustedIssuers(blocklet, { provider });
162
+ const trustedIssuers = await getTrustedIssuers(blocklet, { provider });
160
163
  claims.verifiableCredential = {
161
164
  type: 'verifiableCredential',
162
165
  description: messages.requestPassport[locale],
@@ -242,9 +245,11 @@ module.exports = {
242
245
  let defaultTtlPolicy = 'never';
243
246
  let issuePassport = false;
244
247
 
248
+ const provider = getLoginProvider(request);
249
+
245
250
  // Get passport vc
246
251
  if (action === 'login') {
247
- vc = await getPassportVc({ blocklet, claims, challenge, locale });
252
+ vc = await getPassportVc({ blocklet, claims, challenge, locale, provider });
248
253
  [invitedUserOnly, defaultRole, issuePassport] = await isInvitedUserOnly(authConfig, node, teamDid);
249
254
  if (invitedUserOnly && !vc) {
250
255
  throw new Error(messages.missingCredentialClaim[locale]);
@@ -317,7 +322,7 @@ module.exports = {
317
322
  }
318
323
 
319
324
  // Get role
320
- const role = await getRoleFromVC({ vc, node, locale, blocklet, teamDid });
325
+ const role = await getRoleFromVC({ vc, node, locale, blocklet, teamDid, provider });
321
326
  await validateRole({ role, authConfig, locale, node, teamDid });
322
327
 
323
328
  checkAppOwner({ role, blocklet, userDid, locale });
@@ -333,10 +338,16 @@ module.exports = {
333
338
  let fullName = user?.fullName;
334
339
  // Update profile
335
340
  const passportForLog = passport || { name: 'Guest', role: 'guest' };
336
- const provider = getLoginProvider(request);
341
+
342
+ const masterSite = getFederatedMaster(blocklet);
343
+ let connectAccount = { provider, did: realDid, pk: realPk };
344
+
337
345
  let updatedUser;
338
346
  if (user) {
339
347
  // Update user
348
+ if (masterSite && provider === LOGIN_PROVIDER.FEDERATED) {
349
+ connectAccount = { provider, did: realDid, pk: realPk, id: masterSite.appPid };
350
+ }
340
351
  updatedUser = await node.loginUser({
341
352
  teamDid,
342
353
  user: {
@@ -345,7 +356,7 @@ module.exports = {
345
356
  locale,
346
357
  passport,
347
358
  lastLoginIp: get(request, 'headers[x-real-ip]') || '',
348
- connectedAccount: [{ provider, did: realDid }, connectedNft],
359
+ connectedAccount: [connectAccount, connectedNft],
349
360
  },
350
361
  });
351
362
  await node.createAuditLog(
@@ -362,6 +373,10 @@ module.exports = {
362
373
  const profile = claims.find((x) => x.type === 'profile');
363
374
  fullName = profile.fullName;
364
375
 
376
+ if (masterSite && provider === LOGIN_PROVIDER.FEDERATED) {
377
+ connectAccount = { provider, did: realDid, pk: realPk, id: masterSite.appPid };
378
+ }
379
+
365
380
  updatedUser = await node.loginUser({
366
381
  teamDid,
367
382
  user: {
@@ -374,14 +389,7 @@ module.exports = {
374
389
  locale,
375
390
  passport,
376
391
  lastLoginIp: get(request, 'headers[x-real-ip]') || '',
377
- connectedAccount: [
378
- {
379
- provider,
380
- did: realDid,
381
- pk: realPk,
382
- },
383
- connectedNft,
384
- ],
392
+ connectedAccount: [connectAccount, connectedNft],
385
393
  },
386
394
  });
387
395
  await node.createAuditLog(
@@ -422,12 +430,12 @@ module.exports = {
422
430
  await node.setBlockletInitialized({ did: teamDid, owner: { did: realDid, pk: realPk } });
423
431
  }
424
432
 
425
- const { permanentWallet } = await request.getBlockletInfo();
433
+ const { permanentWallet } = blockletInfo;
426
434
 
427
- const masterSite = getFederatedMaster(blocklet);
428
435
  let federatedSessionToken;
429
436
  let federatedRefreshToken;
430
- if (masterSite) {
437
+ // member 使用 deferated login 时,总是会让 Master 自动登录
438
+ if (masterSite && provider === LOGIN_PROVIDER.FEDERATED) {
431
439
  const postUser = pick(updatedUser, ['did', 'pk', 'fullName', 'locale']);
432
440
  postUser.lastLoginAt = get(request, 'headers[x-real-ip]') || '';
433
441
 
@@ -444,7 +452,6 @@ module.exports = {
444
452
  signer: permanentWallet.address,
445
453
  data: signV2(permanentWallet.address, permanentWallet.secretKey, {
446
454
  user: postUser,
447
- appId: blocklet.did,
448
455
  passport,
449
456
  }),
450
457
  }
@@ -593,7 +600,7 @@ module.exports = {
593
600
 
594
601
  const blocklet = await request.getBlocklet();
595
602
  const provider = getLoginProvider(request);
596
- const trustedIssuers = getTrustedIssuers(blocklet, { provider });
603
+ const trustedIssuers = await getTrustedIssuers(blocklet, { provider });
597
604
 
598
605
  return {
599
606
  verifiableCredential: {
@@ -615,6 +622,7 @@ module.exports = {
615
622
  userDid,
616
623
  createSessionToken,
617
624
  componentId,
625
+ provider,
618
626
  }) => {
619
627
  const blocklet = await request.getBlocklet();
620
628
  const { name, did: teamDid, secret } = await request.getBlockletInfo();
@@ -645,6 +653,7 @@ module.exports = {
645
653
  claims: [verifiableCredential],
646
654
  challenge,
647
655
  locale,
656
+ provider,
648
657
  });
649
658
 
650
659
  // Validate passport required
@@ -660,7 +669,7 @@ module.exports = {
660
669
  }
661
670
 
662
671
  // Get role
663
- const role = await getRoleFromVC({ vc, node, locale, blocklet, teamDid });
672
+ const role = await getRoleFromVC({ vc, node, locale, blocklet, teamDid, provider });
664
673
  await validateRole({ role, authConfig, locale, node, teamDid });
665
674
 
666
675
  checkAppOwner({ role, blocklet, userDid, locale });
@@ -685,7 +694,7 @@ module.exports = {
685
694
  await node.createAuditLog(
686
695
  {
687
696
  action: 'switchPassport',
688
- args: { teamDid, userDid, passport: passportForLog, provider: LOGIN_PROVIDER.WALLET },
697
+ args: { teamDid, userDid, passport: passportForLog, provider },
689
698
  context: formatContext(Object.assign(request, { user })),
690
699
  result: {},
691
700
  },
@@ -697,7 +706,7 @@ module.exports = {
697
706
  const sessionConfig = blocklet.settings?.session || {};
698
707
  const { sessionToken, refreshToken } = createToken(
699
708
  userDid,
700
- { secret, passport, role, fullName: user.fullName },
709
+ { secret, passport, role, fullName: user.fullName, provider },
701
710
  { ...sessionConfig, didConnectVersion: getDidConnectVersion(request) }
702
711
  );
703
712
  return { sessionToken, refreshToken };
package/api/libs/jwt.js CHANGED
@@ -74,6 +74,7 @@ const initJwt = (node, options) => {
74
74
 
75
75
  user.role = role;
76
76
  user.passport = passport;
77
+ user.provider = provider;
77
78
  } else {
78
79
  user = { did, role, passport, fullName, provider };
79
80
  }
@@ -4,6 +4,7 @@ function checkFederatedCorsCall() {
4
4
  const { blocklet } = req;
5
5
  const federated = blocklet.settings.federated || {};
6
6
  const sites = federated?.sites || [];
7
+ // TODO: @zhanghan 增加 aliasAppUrl 判断
7
8
  if (sites.find((item) => item.appUrl === caller && item.status === 'approved')) {
8
9
  next();
9
10
  return;
@@ -3,10 +3,16 @@ const { signV2 } = require('@arcblock/jwt');
3
3
  const normalizePathPrefix = require('@abtnode/util/lib/normalize-path-prefix');
4
4
  const cloneDeep = require('lodash/cloneDeep');
5
5
  const get = require('lodash/get');
6
+ const pLimit = require('p-limit');
7
+ const pRetry = require('p-retry');
6
8
 
7
9
  const cors = require('cors');
8
10
  const { LOGIN_PROVIDER } = require('@blocklet/constant');
11
+ const { getAvatarByUrl, extractUserAvatar } = require('@abtnode/util/lib/user');
12
+ const { getApplicationInfo } = require('@abtnode/auth/lib/auth');
9
13
  const pick = require('lodash/pick');
14
+ const defaults = require('lodash/defaults');
15
+ const remove = require('lodash/remove');
10
16
 
11
17
  const { api } = require('../libs/api');
12
18
  const initJwt = require('../libs/jwt');
@@ -19,6 +25,7 @@ const { getUserAvatarUrl } = require('../util/federated');
19
25
  const PREFIX = WELLKNOWN_SERVICE_PATH_PREFIX;
20
26
 
21
27
  const prefix = `${PREFIX}/api/federated`;
28
+ const limitSync = pLimit(1);
22
29
 
23
30
  module.exports = {
24
31
  preInit(server) {
@@ -29,18 +36,24 @@ module.exports = {
29
36
  init(server, node, options) {
30
37
  // step 1 申请加入(member 向 master 申请)
31
38
  server.post(`${prefix}/join`, ensureBlocklet(), async (req, res) => {
39
+ // master blocklet
32
40
  const { blocklet } = req;
33
41
  const { site } = req.body;
34
42
 
35
- const federated = cloneDeep(blocklet.settings.federated || {});
36
- let sites = federated?.sites || [];
37
- if (sites.length === 0) {
43
+ const federated = defaults(cloneDeep(blocklet.settings.federated || {}), {
44
+ config: {
45
+ appId: blocklet.appDid,
46
+ appPid: blocklet.appPid,
47
+ },
48
+ sites: [],
49
+ });
50
+ if (federated.sites.length === 0) {
38
51
  const nodeInfo = await req.getNodeInfo();
39
52
  const blockletInfo = await req.getBlockletInfo();
40
53
  const masterSite = {
41
54
  appId: blockletInfo.wallet.address,
42
55
  appPid: blockletInfo.permanentWallet.address,
43
- migratedFrom: blocklet.migratedFrom || [],
56
+ aliasDid: (blocklet.migratedFrom || []).map((item) => item.appDid),
44
57
  appName: blockletInfo.name,
45
58
  appDescription: blockletInfo.description,
46
59
  appUrl: blockletInfo.appUrl,
@@ -49,24 +62,17 @@ module.exports = {
49
62
  normalizePathPrefix(`${WELLKNOWN_SERVICE_PATH_PREFIX}/blocklet/logo`) ||
50
63
  '/',
51
64
  appLogoRect: blocklet.environmentObj.BLOCKLET_APP_LOGO_RECT,
52
- did: blockletInfo.did,
65
+ did: blockletInfo.permanentWallet.address,
53
66
  pk: blockletInfo.permanentWallet.publicKey,
54
67
  serverId: nodeInfo.did,
55
68
  serverVersion: nodeInfo.version,
56
69
  version: blocklet.meta.version,
57
70
  };
58
- sites = [masterSite];
71
+ federated.sites = [masterSite];
59
72
  }
60
73
 
61
- let masterConfig = federated.config;
62
- if (!masterConfig) {
63
- masterConfig = {
64
- appId: blocklet.appDid,
65
- appPid: blocklet.appPid || blocklet.appDid,
66
- };
67
- }
68
74
  if (site) {
69
- sites.push({
75
+ federated.sites.push({
70
76
  ...site,
71
77
  appliedAt: new Date(),
72
78
  status: 'pending',
@@ -76,36 +82,81 @@ module.exports = {
76
82
  // member 申请后,将 member 展示在列表中
77
83
  // 更新的是自己
78
84
  await node.setFederated({
79
- did: blocklet.appDid,
80
- config: {
81
- config: masterConfig,
82
- sites,
83
- },
85
+ did: blocklet.appPid,
86
+ config: federated,
84
87
  });
85
88
 
86
89
  // 将新增的数据返回给 member
87
90
  res.json({
88
- sites,
91
+ sites: federated.sites,
92
+ });
93
+ });
94
+
95
+ // member 向 master 请求退出统一登录
96
+ server.post(`${prefix}/quit`, ensureBlocklet(), verifyFederatedCall(), async (req, res) => {
97
+ const { blocklet } = req;
98
+ const { memberPid } = req.body.verifyData;
99
+
100
+ const federated = defaults(cloneDeep(blocklet.settings.federated || {}), {
101
+ config: {
102
+ appId: blocklet.appDid,
103
+ appPid: blocklet.appPid,
104
+ },
105
+ sites: [],
106
+ });
107
+
108
+ remove(federated.sites, (item) => item.appPid === memberPid);
109
+
110
+ const { permanentWallet } = await req.getBlockletInfo();
111
+ const postData = {
112
+ signer: permanentWallet.address,
113
+ data: signV2(permanentWallet.address, permanentWallet.secretKey, { sites: federated.sites }),
114
+ };
115
+
116
+ const waitingList = federated.sites
117
+ .filter((item) => item.appId !== federated.config.appId)
118
+ .map((item) => {
119
+ return limitSync(() =>
120
+ pRetry(() => api.post(`${item.appUrl}/${WELLKNOWN_SERVICE_PATH_PREFIX}/api/federated/sync`, postData), {
121
+ retries: 3,
122
+ })
123
+ );
124
+ });
125
+ await Promise.all(waitingList);
126
+
127
+ await node.setFederated({
128
+ did: blocklet.appPid,
129
+ config: federated,
89
130
  });
131
+
132
+ res.json({});
90
133
  });
91
134
 
92
135
  // step 2 审批(master 申批 member)
93
136
  // core/state/lib/blocklet/manager/disk.js -> auditFederatedLogin
137
+ // audit-res 接受 master 的处理结果同步,保存 delegation
94
138
  server.post(`${prefix}/audit-res`, ensureBlocklet(), verifyFederatedCall(), async (req, res) => {
95
139
  const { blocklet } = req;
96
- const { delegation, roles, appId, status } = req.body.verifyData;
97
- const federated = cloneDeep(blocklet.settings.federated || {});
140
+ const { delegation, roles, masterPid, status } = req.body.verifyData;
141
+ const federated = defaults(cloneDeep(blocklet.settings.federated || {}), {
142
+ config: {
143
+ appId: blocklet.appDid,
144
+ appPid: blocklet.appPid,
145
+ isMaster: false,
146
+ },
147
+ sites: [],
148
+ });
98
149
  federated.config.delegation = delegation;
99
150
  if (status === 'approved') {
100
151
  const trustedPassports = blocklet.trustedPassports || [];
101
- const hasTrustedPassport = trustedPassports.find((item) => item.issuerDid === appId);
152
+ const hasTrustedPassport = trustedPassports.find((item) => item.issuerDid === masterPid);
102
153
  if (!hasTrustedPassport) {
103
154
  await node.configTrustedPassports({
104
- teamDid: blocklet.meta.did,
155
+ teamDid: blocklet.appPid,
105
156
  trustedPassports: [
106
157
  ...trustedPassports,
107
158
  {
108
- issuerDid: appId,
159
+ issuerDid: masterPid,
109
160
  remark: 'Generated on join federated login',
110
161
  mappings: roles.map((item) => {
111
162
  return {
@@ -120,7 +171,7 @@ module.exports = {
120
171
  }
121
172
 
122
173
  await node.setFederated({
123
- did: blocklet.meta.did,
174
+ did: blocklet.appPid,
124
175
  config: federated,
125
176
  });
126
177
  res.json(federated);
@@ -134,7 +185,7 @@ module.exports = {
134
185
  const federated = cloneDeep(blocklet.settings.federated || {});
135
186
  federated.sites = sites;
136
187
  await node.setFederated({
137
- did: blocklet.meta.did,
188
+ did: blocklet.appPid,
138
189
  config: federated,
139
190
  });
140
191
  res.json(federated);
@@ -149,7 +200,7 @@ module.exports = {
149
200
  async (req, res) => {
150
201
  const { blocklet } = req;
151
202
 
152
- const teamDid = blocklet.meta.did;
203
+ const teamDid = blocklet.appPid;
153
204
  let user = null;
154
205
  if (req.user) {
155
206
  user = { ...req.user };
@@ -166,8 +217,8 @@ module.exports = {
166
217
  }
167
218
  const blockletInfo = await req.getBlockletInfo();
168
219
  const site = {
169
- appId: blockletInfo.wallet.address,
170
- appPid: blockletInfo.permanentWallet.address,
220
+ appId: blocklet.appDid,
221
+ appPid: blocklet.appPid,
171
222
  appName: blockletInfo.name,
172
223
  appDescription: blockletInfo.description,
173
224
  appUrl: blockletInfo.appUrl,
@@ -176,7 +227,6 @@ module.exports = {
176
227
  normalizePathPrefix(`${WELLKNOWN_SERVICE_PATH_PREFIX}/blocklet/logo`) ||
177
228
  '/',
178
229
  appLogoRect: blocklet.environmentObj.BLOCKLET_APP_LOGO_RECT,
179
- did: blockletInfo.did,
180
230
  };
181
231
  res.json({ user, site });
182
232
  }
@@ -199,8 +249,9 @@ module.exports = {
199
249
  if (!onlyWriteCookie) {
200
250
  const { blocklet } = req;
201
251
  const { permanentWallet } = await req.getBlockletInfo();
202
- const teamDid = blocklet.meta.did;
252
+ const teamDid = blocklet.appPid;
203
253
  const federatedSites = blocklet.settings?.federated?.sites || [];
254
+ // TODO: @zhanghan 增加 aliasAppUrl 判断
204
255
  const loginSite = federatedSites.find((item) => item.appUrl === req.headers.origin);
205
256
 
206
257
  const currentUser = await node.getUser({
@@ -227,7 +278,7 @@ module.exports = {
227
278
  ({ data } = await api.post(`${loginSite.appUrl}${prefix}/token`, {
228
279
  signer: permanentWallet.address,
229
280
  data: signV2(permanentWallet.address, permanentWallet.secretKey, {
230
- appId: teamDid,
281
+ masterPid: teamDid,
231
282
  role: req.user.role,
232
283
  user,
233
284
  passport: req.user.passport,
@@ -251,16 +302,17 @@ module.exports = {
251
302
 
252
303
  // step 6 发放自动登录 token(master 向 member 发起生成 token 请求)
253
304
  server.post(`${prefix}/token`, ensureBlocklet(), verifyFederatedCall(), async (req, res) => {
254
- const { user, appId, role, passport } = req.body.verifyData;
305
+ const { user, masterPid, role, passport } = req.body.verifyData;
255
306
  const { createSessionToken } = initJwt(node, options);
256
307
  const createToken = createTokenFn(createSessionToken);
257
308
  const { secret } = await req.getBlockletInfo();
258
309
  const { blocklet } = req;
259
- const teamDid = blocklet.meta.did;
310
+ const teamDid = blocklet.appPid;
260
311
 
261
312
  const sessionConfig = blocklet.settings?.session || {};
262
313
  const trustedPassports = blocklet.trustedPassports || [];
263
- const masterPassport = trustedPassports.find((item) => item.issuerDid === appId);
314
+ // HACK: 这里只对比 pid,因为自动生成的数据只有 master-site pid
315
+ const masterPassport = trustedPassports.find((item) => item.issuerDid === masterPid);
264
316
  const findMapping = masterPassport ? masterPassport.mappings.find((item) => item.from.passport === role) : null;
265
317
  const targetPassport = findMapping
266
318
  ? {
@@ -269,15 +321,28 @@ module.exports = {
269
321
  id: passport?.id || '',
270
322
  }
271
323
  : { role: 'guest', name: 'Guest' };
324
+ let { avatar } = user || {};
325
+ if (avatar) {
326
+ try {
327
+ avatar = await getAvatarByUrl(user.avatar);
328
+ const nodeInfo = await req.getNodeInfo();
329
+
330
+ const { dataDir } = await getApplicationInfo({ node, nodeInfo, teamDid });
331
+ avatar = await extractUserAvatar(avatar, { dataDir });
332
+ } catch (err) {
333
+ console.error(err.response.status);
334
+ }
335
+ }
272
336
  const doc = await node.loginUser({
273
337
  teamDid,
274
338
  user: {
275
339
  ...user,
340
+ avatar,
276
341
  // HACK: @zhanghan 这里会将 passport 插入到当前用户的 passport 列表中,federated 登录不应该插入 passport
277
342
  // passport: findMapping ? targetPassport : null,
278
343
  connectedAccount: {
279
344
  provider: LOGIN_PROVIDER.FEDERATED,
280
- id: appId,
345
+ id: masterPid,
281
346
  did: user.did,
282
347
  pk: user.pk,
283
348
  },
@@ -314,14 +379,15 @@ module.exports = {
314
379
  );
315
380
 
316
381
  // member 主动调起 master 登录(实现登录 member 时,自动登录 master)
382
+ // member 传递过来的 user.did 和 user.pk 均为 master-site 与钱包生成的
317
383
 
318
384
  server.post(`${prefix}/loginByMember`, ensureBlocklet(), verifyFederatedCall(), async (req, res) => {
319
- const { user, appId, passport } = req.body.verifyData;
385
+ const { user, passport } = req.body.verifyData;
320
386
  const { createSessionToken } = initJwt(node, options);
321
387
  const createToken = createTokenFn(createSessionToken);
322
388
  const { secret } = await req.getBlockletInfo();
323
389
  const { blocklet } = req;
324
- const teamDid = blocklet.meta.did;
390
+ const teamDid = blocklet.appPid;
325
391
 
326
392
  const sessionConfig = blocklet.settings?.session || {};
327
393
  const prevUser = await node.getUser({
@@ -331,14 +397,29 @@ module.exports = {
331
397
  });
332
398
  // HACK: member 调用 master 时,将 passport 的 role 还原为 master 中原有的 role
333
399
  const targetPassport = passport?.id ? (prevUser?.passports || []).find((item) => item.id === passport.id) : null;
334
- const doc = await node.loginUser({
400
+
401
+ // HACK: 用户在 master 中存在时,不更新任何用户信息;不存在时,将新增一个用户
402
+ const filterUserInfo = prevUser ? {} : user;
403
+ if (filterUserInfo.avatar) {
404
+ let avatar = await getAvatarByUrl(filterUserInfo.avatar);
405
+ const nodeInfo = await req.getNodeInfo();
406
+
407
+ const { dataDir } = await getApplicationInfo({ node, nodeInfo, teamDid });
408
+ avatar = await extractUserAvatar(avatar, { dataDir });
409
+ filterUserInfo.avatar = avatar;
410
+ }
411
+ const realDid = prevUser?.did || user.did;
412
+ const realPk = prevUser?.pk || user.pk;
413
+ const newUser = await node.loginUser({
335
414
  teamDid,
336
415
  user: {
337
- ...user,
416
+ ...filterUserInfo,
417
+ did: realDid,
418
+ pk: realPk,
338
419
  passport: targetPassport,
339
420
  connectedAccount: {
421
+ // member 在使用 federated login 时,本质还是使用 wallet 来登录的,所以对 master-site 来说,登录的 provider 就是 wallet
340
422
  provider: LOGIN_PROVIDER.WALLET,
341
- id: appId,
342
423
  did: user.did,
343
424
  pk: user.pk,
344
425
  },
@@ -346,12 +427,12 @@ module.exports = {
346
427
  });
347
428
 
348
429
  const { sessionToken, refreshToken } = createToken(
349
- doc.did,
430
+ user.did,
350
431
  {
351
432
  secret,
352
433
  passport: targetPassport,
353
434
  role: targetPassport?.role || 'guest',
354
- fullName: doc.fullName,
435
+ fullName: newUser.fullName,
355
436
  },
356
437
  {
357
438
  ...sessionConfig,
@@ -386,6 +386,9 @@ module.exports = {
386
386
  res.send(oauthConfig);
387
387
  });
388
388
  server.get(`${prefix}/passports`, async (req, res) => {
389
+ if (!req.user) {
390
+ res.status(401).send('Unauthorized');
391
+ }
389
392
  const userDid = req.user.did;
390
393
  const blocklet = await req.getBlockletInfo();
391
394
  const nodeInfo = await req.getNodeInfo();
@@ -1,11 +1,13 @@
1
1
  const { switchPassport } = require('../../../libs/connect/session');
2
+ const { getLoginProvider } = require('../../../util/blocklet-utils');
2
3
 
3
4
  const { onConnect, onApprove } = switchPassport;
4
5
 
5
6
  module.exports = function createRoutes(node, authenticator, createSessionToken) {
6
7
  return {
7
8
  action: 'switch-passport',
8
- onConnect: ({ req, userDid, baseUrl, extraParams: { locale, connectedDid } }) => {
9
+ onConnect: ({ userDid, baseUrl, extraParams: { locale, connectedDid }, req, request }) => {
10
+ const provider = getLoginProvider(request);
9
11
  return onConnect({
10
12
  node,
11
13
  request: req,
@@ -13,10 +15,12 @@ module.exports = function createRoutes(node, authenticator, createSessionToken)
13
15
  userDid,
14
16
  previousUserDid: connectedDid,
15
17
  baseUrl,
18
+ provider,
16
19
  });
17
20
  },
18
21
 
19
- onAuth: async ({ claims, challenge, userDid, updateSession, extraParams, req }) => {
22
+ onAuth: async ({ claims, challenge, userDid, updateSession, extraParams, req, request }) => {
23
+ const provider = getLoginProvider(request);
20
24
  const { sessionToken, refreshToken } = await onApprove({
21
25
  node,
22
26
  request: req,
@@ -25,6 +29,7 @@ module.exports = function createRoutes(node, authenticator, createSessionToken)
25
29
  verifiableCredential: claims.find((x) => x.type === 'verifiableCredential'),
26
30
  userDid,
27
31
  createSessionToken,
32
+ provider,
28
33
  });
29
34
 
30
35
  await updateSession({ sessionToken, refreshToken }, true);