@abtnode/blocklet-services 1.16.16-beta-740ea329 → 1.16.16-beta-d6c5ed65

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 (55) hide show
  1. package/api/libs/auth/utils.js +2 -1
  2. package/api/libs/connect/session.js +75 -30
  3. package/api/libs/connect/shared.js +4 -5
  4. package/api/libs/connect/v1.js +7 -9
  5. package/api/routes/federated.js +84 -11
  6. package/api/routes/oauth.js +140 -37
  7. package/api/routes/user.js +7 -2
  8. package/api/services/auth/connect/switch-passport.js +5 -5
  9. package/api/util/blocklet-utils.js +2 -3
  10. package/build/asset-manifest.json +55 -55
  11. package/build/index.html +1 -1
  12. package/build/service-worker.js +1 -1
  13. package/build/service-worker.js.map +1 -1
  14. package/build/static/js/1480.36129849.chunk.js +2 -0
  15. package/build/static/js/{1565.a6f98c38.chunk.js → 1565.ad002b88.chunk.js} +2 -2
  16. package/build/static/js/{1660.5c8ade93.chunk.js → 1660.9fb17942.chunk.js} +2 -2
  17. package/build/static/js/{1760.95d0c320.chunk.js → 1760.71e0c151.chunk.js} +2 -2
  18. package/build/static/js/{2653.11a1ad57.chunk.js → 2653.6f37e8a0.chunk.js} +2 -2
  19. package/build/static/js/2686.7ae70bfd.chunk.js +2 -0
  20. package/build/static/js/4023.4be0c818.chunk.js +2 -0
  21. package/build/static/js/{4716.47aa133c.chunk.js → 4716.17a45b6a.chunk.js} +2 -2
  22. package/build/static/js/{4802.63425dd4.chunk.js → 4802.b7fa8e82.chunk.js} +2 -2
  23. package/build/static/js/50.cbaa5a4e.chunk.js +3 -0
  24. package/build/static/js/{5176.42904a22.chunk.js → 5176.53f7f419.chunk.js} +2 -2
  25. package/build/static/js/{5628.773a32da.chunk.js → 5628.aa14b1a7.chunk.js} +2 -2
  26. package/build/static/js/5662.522d3713.chunk.js +2 -0
  27. package/build/static/js/5683.7e5d47f1.chunk.js +2 -0
  28. package/build/static/js/6186.6462ea21.chunk.js +2 -0
  29. package/build/static/js/{6452.b1899621.chunk.js → 6452.4226209b.chunk.js} +2 -2
  30. package/build/static/js/{6629.36e61c26.chunk.js → 6629.785fe237.chunk.js} +3 -3
  31. package/build/static/js/{6640.53cdcb95.chunk.js → 6640.e453c619.chunk.js} +2 -2
  32. package/build/static/js/6737.7fe9f13a.chunk.js +2 -0
  33. package/build/static/js/{6771.735ebd3f.chunk.js → 6771.1e778542.chunk.js} +3 -3
  34. package/build/static/js/{6856.e5c166e6.chunk.js → 6856.9aaf692c.chunk.js} +2 -2
  35. package/build/static/js/{7006.9a53f7ed.chunk.js → 7006.b72aff66.chunk.js} +2 -2
  36. package/build/static/js/{7465.ba1027a7.chunk.js → 7465.999f0039.chunk.js} +3 -3
  37. package/build/static/js/{9409.befe72b4.chunk.js → 9409.fe4a0af0.chunk.js} +2 -2
  38. package/build/static/js/{9620.59bc85b8.chunk.js → 9620.db1568ef.chunk.js} +2 -2
  39. package/build/static/js/{9899.c8ff588e.chunk.js → 9899.92626f0a.chunk.js} +2 -2
  40. package/build/static/js/main.85d66eb2.js +3 -0
  41. package/build/static/js/{main.3ba3901e.js.LICENSE.txt → main.85d66eb2.js.LICENSE.txt} +1 -1
  42. package/package.json +23 -23
  43. package/build/static/js/1480.30b94380.chunk.js +0 -2
  44. package/build/static/js/2307.2e451912.chunk.js +0 -2
  45. package/build/static/js/2686.07687254.chunk.js +0 -2
  46. package/build/static/js/4023.0f348986.chunk.js +0 -2
  47. package/build/static/js/5683.3bdd2338.chunk.js +0 -2
  48. package/build/static/js/6186.61596c22.chunk.js +0 -2
  49. package/build/static/js/6606.9f17eaa6.chunk.js +0 -3
  50. package/build/static/js/6737.5f735a29.chunk.js +0 -2
  51. package/build/static/js/main.3ba3901e.js +0 -3
  52. /package/build/static/js/{6606.9f17eaa6.chunk.js.LICENSE.txt → 50.cbaa5a4e.chunk.js.LICENSE.txt} +0 -0
  53. /package/build/static/js/{6629.36e61c26.chunk.js.LICENSE.txt → 6629.785fe237.chunk.js.LICENSE.txt} +0 -0
  54. /package/build/static/js/{6771.735ebd3f.chunk.js.LICENSE.txt → 6771.1e778542.chunk.js.LICENSE.txt} +0 -0
  55. /package/build/static/js/{7465.ba1027a7.chunk.js.LICENSE.txt → 7465.999f0039.chunk.js.LICENSE.txt} +0 -0
@@ -6,6 +6,7 @@ const { getBlockletAppIdList } = require('@blocklet/meta/lib/util');
6
6
  const pick = require('lodash/pick');
7
7
  const uniq = require('lodash/uniq');
8
8
  const uniqBy = require('lodash/uniqBy');
9
+ const { LOGIN_PROVIDER } = require('@blocklet/constant');
9
10
 
10
11
  const { sendToUser } = require('../notification');
11
12
 
@@ -125,7 +126,7 @@ async function transferPassport(fromUser, toUser, { req, teamDid, node, nodeInfo
125
126
  const revokePendingList = waitPassportList
126
127
  .filter((item) => item.id)
127
128
  .map((item) => {
128
- if (fromUser.sourceProvider === 'auth0') {
129
+ if (fromUser.sourceProvider === LOGIN_PROVIDER.AUTH0) {
129
130
  return node.removeUserPassport({ teamDid, userDid: fromUser.did, passportId: item.id });
130
131
  }
131
132
  return node.revokeUserPassport({ teamDid, userDid: fromUser.did, passportId: item.id });
@@ -41,7 +41,7 @@ const pick = require('lodash/pick');
41
41
  const createTranslator = require('@abtnode/util/lib/translate');
42
42
 
43
43
  const { getRolesFromAuthConfig, getBlockletAppIdList } = require('@blocklet/meta/lib/util');
44
- const { getLoginProvider } = require('@blocklet/sdk/lib/util/login');
44
+ const { getSourceAppPid, getLoginProvider } = require('@blocklet/sdk/lib/util/login');
45
45
 
46
46
  const logger = require('@abtnode/logger')(require('../../../package.json').name);
47
47
 
@@ -54,8 +54,8 @@ const { api } = require('../api');
54
54
 
55
55
  const vcTypes = [VC_TYPE_GENERAL_PASSPORT, VC_TYPE_NODE_PASSPORT];
56
56
 
57
- const getPassportVc = async ({ blocklet, claims, challenge, locale, provider }) => {
58
- const trustedIssuers = await getTrustedIssuers(blocklet, { provider });
57
+ const getPassportVc = async ({ blocklet, claims, challenge, locale, sourceAppPid }) => {
58
+ const trustedIssuers = await getTrustedIssuers(blocklet, { sourceAppPid });
59
59
  const { vc } = await getVCFromClaims({
60
60
  claims,
61
61
  challenge,
@@ -67,7 +67,7 @@ const getPassportVc = async ({ blocklet, claims, challenge, locale, provider })
67
67
  return vc;
68
68
  };
69
69
 
70
- const getRoleFromVC = async ({ vc, node, locale, blocklet, teamDid, provider }) => {
70
+ const getRoleFromVC = async ({ vc, node, locale, blocklet, teamDid, sourceAppPid }) => {
71
71
  let role = ROLES.GUEST;
72
72
  if (vc) {
73
73
  await validatePassport(get(vc, 'credentialSubject.passport'));
@@ -77,8 +77,7 @@ const getRoleFromVC = async ({ vc, node, locale, blocklet, teamDid, provider })
77
77
  role = getRoleFromLocalPassport(get(vc, 'credentialSubject.passport'));
78
78
  } else {
79
79
  // MEMO: 如果是 federated,需要将 actualIssuer 做一个转换
80
- const actualIssuerList =
81
- provider === LOGIN_PROVIDER.FEDERATED ? await getFederatedTrustedIssuers(blocklet) : [actualIssuer];
80
+ const actualIssuerList = sourceAppPid ? await getFederatedTrustedIssuers(blocklet) : [actualIssuer];
82
81
  // map external passport to local role
83
82
  const { mappings = [] } =
84
83
  (blocklet.trustedPassports || []).find((x) => actualIssuerList.includes(x.issuerDid)) || {};
@@ -146,7 +145,7 @@ module.exports = {
146
145
  const blocklet = await request.getBlocklet();
147
146
  const config = await request.getServiceConfig(NODE_SERVICES.AUTH, { componentId });
148
147
  const { did: teamDid, wallet: blockletWallet } = await request.getBlockletInfo();
149
- const provider = getLoginProvider(request);
148
+ const sourceAppPid = getSourceAppPid(request);
150
149
 
151
150
  const profileFields = get(config, 'profileFields');
152
151
 
@@ -160,7 +159,7 @@ module.exports = {
160
159
  if (action === 'login') {
161
160
  const [invitedUserOnly] = config ? await isInvitedUserOnly(config, node, teamDid) : [false];
162
161
 
163
- const trustedIssuers = await getTrustedIssuers(blocklet, { provider });
162
+ const trustedIssuers = await getTrustedIssuers(blocklet, { sourceAppPid });
164
163
  claims.verifiableCredential = {
165
164
  type: 'verifiableCredential',
166
165
  description: messages.requestPassport[locale],
@@ -246,11 +245,12 @@ module.exports = {
246
245
  let defaultTtlPolicy = 'never';
247
246
  let issuePassport = false;
248
247
 
248
+ const sourceAppPid = getSourceAppPid(request);
249
249
  const provider = getLoginProvider(request);
250
250
 
251
251
  // Get passport vc
252
252
  if (action === 'login') {
253
- vc = await getPassportVc({ blocklet, claims, challenge, locale, provider });
253
+ vc = await getPassportVc({ blocklet, claims, challenge, locale, sourceAppPid });
254
254
  [invitedUserOnly, defaultRole, issuePassport] = await isInvitedUserOnly(authConfig, node, teamDid);
255
255
  if (invitedUserOnly && !vc) {
256
256
  throw new Error(messages.missingCredentialClaim[locale]);
@@ -323,7 +323,7 @@ module.exports = {
323
323
  }
324
324
 
325
325
  // Get role
326
- const role = await getRoleFromVC({ vc, node, locale, blocklet, teamDid, provider });
326
+ const role = await getRoleFromVC({ vc, node, locale, blocklet, teamDid, sourceAppPid });
327
327
  await validateRole({ role, authConfig, locale, node, teamDid });
328
328
 
329
329
  checkAppOwner({ role, blocklet, userDid, locale });
@@ -347,14 +347,10 @@ module.exports = {
347
347
  const passportForLog = passport || { name: 'Guest', role: 'guest' };
348
348
 
349
349
  const masterSite = getFederatedMaster(blocklet);
350
- let connectAccount = { provider, did: userDid, pk: userPk };
350
+ const connectAccount = { provider, did: userDid, pk: userPk };
351
351
 
352
352
  let updatedUser;
353
353
  if (user) {
354
- // Update user
355
- if (masterSite && provider === LOGIN_PROVIDER.FEDERATED) {
356
- connectAccount = { provider, did: userDid, pk: userPk, id: masterSite.appPid };
357
- }
358
354
  updatedUser = await node.loginUser({
359
355
  teamDid,
360
356
  user: {
@@ -362,6 +358,7 @@ module.exports = {
362
358
  pk: user.pk,
363
359
  locale,
364
360
  passport,
361
+ sourceAppPid,
365
362
  lastLoginIp: get(request, 'headers[x-real-ip]') || '',
366
363
  connectedAccount: [connectAccount, connectedNft],
367
364
  },
@@ -369,7 +366,7 @@ module.exports = {
369
366
  await node.createAuditLog(
370
367
  {
371
368
  action,
372
- args: { teamDid, userDid: realDid, passport: passportForLog, provider },
369
+ args: { teamDid, userDid: realDid, passport: passportForLog, provider, sourceAppPid },
373
370
  context: formatContext(Object.assign(request, { user: updatedUser })),
374
371
  result: updatedUser,
375
372
  },
@@ -380,10 +377,6 @@ module.exports = {
380
377
  const profile = claims.find((x) => x.type === 'profile');
381
378
  fullName = profile.fullName;
382
379
 
383
- if (masterSite && provider === LOGIN_PROVIDER.FEDERATED) {
384
- connectAccount = { provider, did: userDid, pk: userPk, id: masterSite.appPid };
385
- }
386
-
387
380
  updatedUser = await node.loginUser({
388
381
  teamDid,
389
382
  user: {
@@ -395,6 +388,7 @@ module.exports = {
395
388
  pk: realPk,
396
389
  locale,
397
390
  passport,
391
+ sourceAppPid,
398
392
  lastLoginIp: get(request, 'headers[x-real-ip]') || '',
399
393
  connectedAccount: [connectAccount, connectedNft],
400
394
  },
@@ -402,7 +396,13 @@ module.exports = {
402
396
  await node.createAuditLog(
403
397
  {
404
398
  action: 'addUser',
405
- args: { teamDid, userDid: realDid, reason: `first login as ${passportForLog.role}` },
399
+ args: {
400
+ teamDid,
401
+ userDid: realDid,
402
+ sourceAppPid,
403
+ provider,
404
+ reason: `first login as ${passportForLog.role}`,
405
+ },
406
406
  context: formatContext(Object.assign(request, { user: updatedUser })),
407
407
  result: updatedUser,
408
408
  },
@@ -410,6 +410,24 @@ module.exports = {
410
410
  );
411
411
  }
412
412
 
413
+ // NOTICE: 采用异步来更新,不阻塞接口的正常响应
414
+ node.syncFederated({
415
+ did: teamDid,
416
+ data: {
417
+ users: [
418
+ {
419
+ did: updatedUser.did,
420
+ pk: updatedUser.pk,
421
+ fullName: updatedUser.fullName,
422
+ email: updatedUser.email || '',
423
+ avatar: getUserAvatarUrl(updatedUser.avatar, blocklet),
424
+ connectedAccount: [connectAccount, connectedNft],
425
+ action: 'connectAccount',
426
+ },
427
+ ],
428
+ },
429
+ });
430
+
413
431
  // Generate new session token that client can save to localStorage
414
432
  const createToken = createTokenFn(createSessionToken);
415
433
  const sessionConfig = blocklet.settings?.session || {};
@@ -441,8 +459,8 @@ module.exports = {
441
459
 
442
460
  let federatedSessionToken;
443
461
  let federatedRefreshToken;
444
- // member 使用 deferated login 时,总是会让 Master 自动登录
445
- if (masterSite && provider === LOGIN_PROVIDER.FEDERATED) {
462
+ // member 使用 federated login 时,总是会让 Master 自动登录
463
+ if (masterSite && sourceAppPid) {
446
464
  const postUser = pick(updatedUser, ['did', 'pk', 'fullName', 'locale']);
447
465
  postUser.lastLoginAt = get(request, 'headers[x-real-ip]') || '';
448
466
 
@@ -574,6 +592,18 @@ module.exports = {
574
592
  },
575
593
  node
576
594
  );
595
+
596
+ const syncUserData = pick(doc, ['did', 'pk', 'fullName', 'avatar', 'email']);
597
+ if (syncUserData.avatar) {
598
+ syncUserData.avatar = getUserAvatarUrl(syncUserData.avatar, blocklet);
599
+ }
600
+ // NOTICE: 采用异步来更新,不阻塞接口的正常响应
601
+ node.syncFederated({
602
+ did: teamDid,
603
+ data: {
604
+ users: [{ ...syncUserData, action: 'switchProfile' }],
605
+ },
606
+ });
577
607
  },
578
608
  },
579
609
 
@@ -606,8 +636,8 @@ module.exports = {
606
636
  const [invitedUserOnly] = await isInvitedUserOnly(config, node, teamDid);
607
637
 
608
638
  const blocklet = await request.getBlocklet();
609
- const provider = getLoginProvider(request);
610
- const trustedIssuers = await getTrustedIssuers(blocklet, { provider });
639
+ const sourceAppPid = getSourceAppPid(request);
640
+ const trustedIssuers = await getTrustedIssuers(blocklet, { sourceAppPid });
611
641
 
612
642
  return {
613
643
  verifiableCredential: {
@@ -629,7 +659,7 @@ module.exports = {
629
659
  userDid,
630
660
  createSessionToken,
631
661
  componentId,
632
- provider,
662
+ sourceAppPid,
633
663
  }) => {
634
664
  const blocklet = await request.getBlocklet();
635
665
  const { name, did: teamDid, secret } = await request.getBlockletInfo();
@@ -660,7 +690,7 @@ module.exports = {
660
690
  claims: [verifiableCredential],
661
691
  challenge,
662
692
  locale,
663
- provider,
693
+ sourceAppPid,
664
694
  });
665
695
 
666
696
  // Validate passport required
@@ -676,7 +706,7 @@ module.exports = {
676
706
  }
677
707
 
678
708
  // Get role
679
- const role = await getRoleFromVC({ vc, node, locale, blocklet, teamDid, provider });
709
+ const role = await getRoleFromVC({ vc, node, locale, blocklet, teamDid, sourceAppPid });
680
710
  await validateRole({ role, authConfig, locale, node, teamDid });
681
711
 
682
712
  checkAppOwner({ role, blocklet, userDid, locale });
@@ -701,7 +731,7 @@ module.exports = {
701
731
  await node.createAuditLog(
702
732
  {
703
733
  action: 'switchPassport',
704
- args: { teamDid, userDid, passport: passportForLog, provider },
734
+ args: { teamDid, userDid, passport: passportForLog, sourceAppPid },
705
735
  context: formatContext(Object.assign(request, { user })),
706
736
  result: {},
707
737
  },
@@ -713,7 +743,7 @@ module.exports = {
713
743
  const sessionConfig = blocklet.settings?.session || {};
714
744
  const { sessionToken, refreshToken } = createToken(
715
745
  userDid,
716
- { secret, passport, role, fullName: user.fullName, provider },
746
+ { secret, passport, role, fullName: user.fullName, sourceAppPid },
717
747
  { ...sessionConfig, didConnectVersion: getDidConnectVersion(request) }
718
748
  );
719
749
  return { sessionToken, refreshToken };
@@ -875,6 +905,21 @@ module.exports = {
875
905
  passports: mergePassport,
876
906
  },
877
907
  });
908
+ // NOTICE: 采用异步来更新,不阻塞接口的正常响应
909
+ node.syncFederated({
910
+ did: teamDid,
911
+ data: {
912
+ users: [
913
+ {
914
+ did: oauthUser.did,
915
+ pk: oauthUser.pk,
916
+ ...mergeProfile,
917
+ connectedAccount: [connectedAccount],
918
+ action: 'connectAccount',
919
+ },
920
+ ],
921
+ },
922
+ });
878
923
 
879
924
  if (!bindUser) {
880
925
  bindUser = {
@@ -2,11 +2,10 @@ const get = require('lodash/get');
2
2
  const joinUrl = require('url-join');
3
3
  const { getConnectAppUrl, getChainInfo } = require('@blocklet/meta/lib/util');
4
4
  const { WELLKNOWN_SERVICE_PATH_PREFIX } = require('@abtnode/constant');
5
- const { LOGIN_PROVIDER } = require('@blocklet/constant');
6
- const { getLoginProvider } = require('@blocklet/sdk/lib/util/login');
5
+ const { getSourceAppPid } = require('@blocklet/sdk/lib/util/login');
7
6
 
8
7
  module.exports = {
9
- appInfo: async ({ request, baseUrl, extraParams }) => {
8
+ appInfo: async ({ request, baseUrl }) => {
10
9
  const groupPathPrefix = request.headers['x-group-path-prefix'] || '/';
11
10
 
12
11
  const [blocklet, meta, info] = await Promise.all([
@@ -16,9 +15,9 @@ module.exports = {
16
15
  ]);
17
16
  // 对于 ux 来说, 要展示的始终是 pid,所以这个给 agentDid 的赋值也需要是 pid
18
17
  let agentDid;
19
- const provider = getLoginProvider(request, extraParams);
18
+ const sourceAppPid = getSourceAppPid(request);
20
19
  // federated 登录模式下,需要告知原有的 blocklet-did
21
- if (provider === LOGIN_PROVIDER.FEDERATED) {
20
+ if (sourceAppPid) {
22
21
  agentDid = blocklet.appPid;
23
22
  }
24
23
 
@@ -10,8 +10,7 @@ const { sendToUser, sendToRelay } = require('@blocklet/sdk/lib/util/send-notific
10
10
  const { WELLKNOWN_SERVICE_PATH_PREFIX, NODE_SERVICES_PREFIX } = require('@abtnode/constant');
11
11
  const DynamicStorage = require('@abtnode/connect-storage');
12
12
  const { fromPublicKey } = require('@ocap/wallet');
13
- const { LOGIN_PROVIDER } = require('@blocklet/constant');
14
- const { getLoginProvider } = require('@blocklet/sdk/lib/util/login');
13
+ const { getSourceAppPid } = require('@blocklet/sdk/lib/util/login');
15
14
 
16
15
  const cache = require('../../cache');
17
16
  const { appInfo, chainInfo } = require('./shared');
@@ -24,11 +23,11 @@ module.exports = (node, opts) => {
24
23
  const { wallet } = await request.getBlockletInfo();
25
24
  return wallet.toJSON();
26
25
  },
27
- delegator: async ({ request, extraParams }) => {
28
- const provider = getLoginProvider(request, extraParams);
26
+ delegator: async ({ request }) => {
27
+ const sourceAppPid = getSourceAppPid(request);
29
28
 
30
29
  const blocklet = await request.getBlocklet();
31
- if (provider === LOGIN_PROVIDER.FEDERATED) {
30
+ if (sourceAppPid) {
32
31
  const pk = get(blocklet, 'settings.federated.sites[0].pk');
33
32
 
34
33
  // NOTE: 这里的 type 参数必须保持跟生成 blocklet 时使用的是一致的
@@ -39,7 +38,6 @@ module.exports = (node, opts) => {
39
38
  address: types.EncodingType.BASE58,
40
39
  };
41
40
  const delegator = fromPublicKey(pk, type);
42
- delegator.provider = LOGIN_PROVIDER.FEDERATED;
43
41
  return delegator;
44
42
  }
45
43
 
@@ -49,10 +47,10 @@ module.exports = (node, opts) => {
49
47
  }
50
48
  return null;
51
49
  },
52
- delegation: async ({ request, extraParams }) => {
50
+ delegation: async ({ request }) => {
53
51
  const { wallet: delegatee, permanentWallet: delegator } = await request.getBlockletInfo();
54
- const provider = getLoginProvider(request, extraParams);
55
- if (provider === LOGIN_PROVIDER.FEDERATED) {
52
+ const sourceAppPid = getSourceAppPid(request);
53
+ if (sourceAppPid) {
56
54
  const blocklet = await request.getBlocklet();
57
55
  const delegation = get(blocklet, 'settings.federated.config.delegation');
58
56
  return delegation;
@@ -3,6 +3,7 @@ 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 isNil = require('lodash/isNil');
6
7
  const pLimit = require('p-limit');
7
8
  const pRetry = require('p-retry');
8
9
 
@@ -29,8 +30,52 @@ const PREFIX = WELLKNOWN_SERVICE_PATH_PREFIX;
29
30
  const prefix = `${PREFIX}/api/federated`;
30
31
  const limitSync = pLimit(1);
31
32
 
33
+ async function syncSwitchProfile(user, { node, teamDid, dataDir }) {
34
+ const tempUser = pick(user, ['did', 'pk', 'avatar', 'fullName', 'email']);
35
+
36
+ // 处理 avatar
37
+ if (tempUser.avatar) {
38
+ try {
39
+ tempUser.avatar = await getAvatarByUrl(tempUser.avatar);
40
+ tempUser.avatar = await extractUserAvatar(tempUser.avatar, { dataDir });
41
+ } catch (err) {
42
+ logger.error('Failed to convert user avatar', { error: err });
43
+ }
44
+ }
45
+
46
+ await node.updateUser({
47
+ teamDid,
48
+ user: tempUser,
49
+ });
50
+ }
51
+
52
+ async function syncConnectAccount(user, { node, teamDid, dataDir }) {
53
+ const tempUser = pick(user, ['did', 'pk', 'avatar', 'fullName', 'email', 'connectedAccount']);
54
+
55
+ // 处理 avatar
56
+ if (tempUser.avatar) {
57
+ try {
58
+ tempUser.avatar = await getAvatarByUrl(tempUser.avatar);
59
+ tempUser.avatar = await extractUserAvatar(tempUser.avatar, { dataDir });
60
+ } catch (err) {
61
+ logger.error('Failed to convert user avatar', { error: err });
62
+ }
63
+ }
64
+
65
+ await node.loginUser({
66
+ teamDid,
67
+ user: tempUser,
68
+ });
69
+ }
70
+
71
+ const syncFnMaps = {
72
+ switchProfile: syncSwitchProfile,
73
+ connectAccount: syncConnectAccount,
74
+ };
75
+
32
76
  module.exports = {
33
77
  preInit(server) {
78
+ // 这几个 route 是在前端跨域调用的,所以需要单独配置 cors
34
79
  server.options(`${prefix}/prelogin`, cors({ credentials: true, origin: true }));
35
80
  server.options(`${prefix}/login`, cors({ credentials: true, origin: true }));
36
81
  server.options(`${prefix}/logout`, cors({ credentials: true, origin: true }));
@@ -200,16 +245,42 @@ module.exports = {
200
245
 
201
246
  // step 3 同步站点群信息(master 向 member 广播站点群信息,广播请求在 manager/disk.js 文件中 class FederatedBlockletManager 发起 )
202
247
  // 该路由为 member 接受响应的 api(只允许 master 调用)
203
- server.post(`${prefix}/sync`, ensureBlocklet(), verifyFederatedCall({ isMaster: true }), async (req, res) => {
204
- const { sites } = req.body.verifyData;
248
+ server.post(`${prefix}/sync`, ensureBlocklet(), verifyFederatedCall(), async (req, res) => {
205
249
  const { blocklet } = req;
206
- const federated = cloneDeep(blocklet.settings.federated || {});
207
- federated.sites = sites;
208
- await node.setFederated({
209
- did: blocklet.appPid,
210
- config: federated,
211
- });
212
- res.json(federated);
250
+ const teamDid = blocklet.appPid;
251
+ const { users = null, sites = null } = req.body.verifyData;
252
+
253
+ // FIXME: @zhanghan 校验 users 和 sites 数据合法性
254
+ const pendingList = [];
255
+ if (!isNil(sites)) {
256
+ const federated = cloneDeep(blocklet.settings.federated || {});
257
+ federated.sites = sites;
258
+ pendingList.push(
259
+ limitSync(async () => {
260
+ await node.setFederated({
261
+ did: blocklet.appPid,
262
+ config: federated,
263
+ });
264
+ })
265
+ );
266
+ }
267
+
268
+ if (!isNil(users)) {
269
+ if (Array.isArray(users)) {
270
+ const nodeInfo = await req.getNodeInfo();
271
+ const { dataDir } = await getApplicationInfo({ node, nodeInfo, teamDid });
272
+ for (const user of users) {
273
+ pendingList.push(
274
+ limitSync(async () => {
275
+ await syncFnMaps[user.action]?.(user, { node, teamDid, dataDir });
276
+ })
277
+ );
278
+ }
279
+ }
280
+ }
281
+
282
+ await Promise.all(pendingList);
283
+ res.json({});
213
284
  });
214
285
 
215
286
  // step 4 检测自动登录条件(member 向 master 发起请求)
@@ -365,8 +436,9 @@ module.exports = {
365
436
  avatar,
366
437
  // HACK: @zhanghan 这里会将 passport 插入到当前用户的 passport 列表中,federated 登录不应该插入 passport
367
438
  // passport: findMapping ? targetPassport : null,
439
+ sourceAppPid: masterPid,
368
440
  connectedAccount: {
369
- provider: LOGIN_PROVIDER.FEDERATED,
441
+ provider: LOGIN_PROVIDER.WALLET,
370
442
  id: masterPid,
371
443
  did: user.did,
372
444
  pk: user.pk,
@@ -380,7 +452,7 @@ module.exports = {
380
452
  role: targetPassport.role,
381
453
  passport: targetPassport,
382
454
  fullName: doc.fullName,
383
- provider: LOGIN_PROVIDER.FEDERATED,
455
+ provider: LOGIN_PROVIDER.WALLET,
384
456
  },
385
457
  {
386
458
  ...sessionConfig,
@@ -439,6 +511,7 @@ module.exports = {
439
511
  }
440
512
  const realDid = prevUser?.did || user.did;
441
513
  const realPk = prevUser?.pk || user.pk;
514
+ // NOTICE: 这里是 Master 登录,不需要 sourceAppPid 字段
442
515
  const newUser = await node.loginUser({
443
516
  teamDid,
444
517
  user: {