@abtnode/blocklet-services 1.16.16-beta-d6c5ed65 → 1.16.16-beta-d11cb031

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 (51) hide show
  1. package/api/index.js +1 -1
  2. package/api/libs/connect/session.js +96 -82
  3. package/api/libs/connect/shared.js +33 -12
  4. package/api/libs/jwt.js +5 -3
  5. package/api/routes/federated.js +65 -12
  6. package/api/routes/oauth.js +134 -76
  7. package/api/routes/user.js +1 -0
  8. package/api/services/auth/connect/invite.js +10 -1
  9. package/api/services/auth/connect/login.js +0 -2
  10. package/api/services/auth/connect/receive-transfer-app-owner.js +2 -1
  11. package/api/services/auth/connect/switch-passport.js +5 -1
  12. package/api/services/auth/session.js +14 -2
  13. package/api/util/federated.js +97 -0
  14. package/build/asset-manifest.json +53 -53
  15. package/build/index.html +1 -1
  16. package/build/service-worker.js +1 -1
  17. package/build/static/js/{1480.36129849.chunk.js → 1480.88c590c2.chunk.js} +2 -2
  18. package/build/static/js/{1565.ad002b88.chunk.js → 1565.6df974b9.chunk.js} +2 -2
  19. package/build/static/js/{1760.71e0c151.chunk.js → 1760.70492184.chunk.js} +2 -2
  20. package/build/static/js/{2653.6f37e8a0.chunk.js → 2653.5dc29ed5.chunk.js} +2 -2
  21. package/build/static/js/2836.f4b10b64.chunk.js +2 -0
  22. package/build/static/js/{4042.3c8e0025.chunk.js → 2838.6fa46760.chunk.js} +3 -3
  23. package/build/static/js/{1660.9fb17942.chunk.js → 3025.7dc2fe04.chunk.js} +2 -2
  24. package/build/static/js/{4023.4be0c818.chunk.js → 4023.202dcd9a.chunk.js} +2 -2
  25. package/build/static/js/{4706.df5b600d.chunk.js → 4706.212c92c8.chunk.js} +3 -3
  26. package/build/static/js/4716.88f32cf2.chunk.js +2 -0
  27. package/build/static/js/{4802.b7fa8e82.chunk.js → 4802.3b60e453.chunk.js} +2 -2
  28. package/build/static/js/{5176.53f7f419.chunk.js → 5176.7e91bc3b.chunk.js} +2 -2
  29. package/build/static/js/{5628.aa14b1a7.chunk.js → 5628.e46ecc79.chunk.js} +2 -2
  30. package/build/static/js/{6380.2b96be29.chunk.js → 5673.ab67c509.chunk.js} +2 -2
  31. package/build/static/js/{6186.6462ea21.chunk.js → 6186.ebbdb4b8.chunk.js} +2 -2
  32. package/build/static/js/{6452.4226209b.chunk.js → 6452.143af37a.chunk.js} +2 -2
  33. package/build/static/js/{6629.785fe237.chunk.js → 6629.376863d2.chunk.js} +3 -3
  34. package/build/static/js/{6640.e453c619.chunk.js → 6640.a4431c82.chunk.js} +2 -2
  35. package/build/static/js/{6737.7fe9f13a.chunk.js → 6737.7d135225.chunk.js} +2 -2
  36. package/build/static/js/{6856.9aaf692c.chunk.js → 6856.e185e317.chunk.js} +2 -2
  37. package/build/static/js/{8706.3d16907a.chunk.js → 7367.60cb10e0.chunk.js} +2 -2
  38. package/build/static/js/{7465.999f0039.chunk.js → 7465.2bb961d7.chunk.js} +3 -3
  39. package/build/static/js/{9409.fe4a0af0.chunk.js → 9409.62a2aee0.chunk.js} +2 -2
  40. package/build/static/js/{9620.db1568ef.chunk.js → 9620.301493bc.chunk.js} +2 -2
  41. package/build/static/js/{9899.92626f0a.chunk.js → 9899.b8d8a5ca.chunk.js} +2 -2
  42. package/build/static/js/main.a58f939e.js +3 -0
  43. package/package.json +34 -34
  44. package/build/static/js/4716.17a45b6a.chunk.js +0 -2
  45. package/build/static/js/5662.522d3713.chunk.js +0 -2
  46. package/build/static/js/main.85d66eb2.js +0 -3
  47. /package/build/static/js/{4042.3c8e0025.chunk.js.LICENSE.txt → 2838.6fa46760.chunk.js.LICENSE.txt} +0 -0
  48. /package/build/static/js/{4706.df5b600d.chunk.js.LICENSE.txt → 4706.212c92c8.chunk.js.LICENSE.txt} +0 -0
  49. /package/build/static/js/{6629.785fe237.chunk.js.LICENSE.txt → 6629.376863d2.chunk.js.LICENSE.txt} +0 -0
  50. /package/build/static/js/{7465.999f0039.chunk.js.LICENSE.txt → 7465.2bb961d7.chunk.js.LICENSE.txt} +0 -0
  51. /package/build/static/js/{main.85d66eb2.js.LICENSE.txt → main.a58f939e.js.LICENSE.txt} +0 -0
package/api/index.js CHANGED
@@ -182,7 +182,7 @@ module.exports = function createServer(node, serverOptions = {}) {
182
182
  server.use(
183
183
  bodyParser.json({
184
184
  // We have to set a larger hard limit since
185
- limit: '2mb',
185
+ limit: '8mb',
186
186
 
187
187
  // https://flaviocopes.com/express-get-raw-body/
188
188
  // Side effects: this will double the memory consumption
@@ -36,7 +36,6 @@ const { getKeyPairClaim, getAuthPrincipalForMigrateAppToV2 } = require('@abtnode
36
36
  const merge = require('lodash/merge');
37
37
  const { fromAppDid } = require('@arcblock/did-ext');
38
38
  const { LOGIN_PROVIDER } = require('@blocklet/constant');
39
- const { signV2 } = require('@arcblock/jwt');
40
39
  const pick = require('lodash/pick');
41
40
  const createTranslator = require('@abtnode/util/lib/translate');
42
41
 
@@ -49,8 +48,7 @@ const { isInvitedUserOnly, createTokenFn, getDidConnectVersion } = require('../.
49
48
  const { transferPassport } = require('../auth/utils');
50
49
  const { migrateAccount, declareAccount } = require('../../services/oauth');
51
50
  const { getTrustedIssuers, getFederatedTrustedIssuers } = require('../../util/blocklet-utils');
52
- const { getFederatedMaster, getUserAvatarUrl } = require('../../util/federated');
53
- const { api } = require('../api');
51
+ const { getUserAvatarUrl, migrateAuth0, getFederatedMaster, shouldSyncFederated } = require('../../util/federated');
54
52
 
55
53
  const vcTypes = [VC_TYPE_GENERAL_PASSPORT, VC_TYPE_NODE_PASSPORT];
56
54
 
@@ -247,6 +245,7 @@ module.exports = {
247
245
 
248
246
  const sourceAppPid = getSourceAppPid(request);
249
247
  const provider = getLoginProvider(request);
248
+ const masterSite = getFederatedMaster(blocklet);
250
249
 
251
250
  // Get passport vc
252
251
  if (action === 'login') {
@@ -346,7 +345,6 @@ module.exports = {
346
345
  // Update profile
347
346
  const passportForLog = passport || { name: 'Guest', role: 'guest' };
348
347
 
349
- const masterSite = getFederatedMaster(blocklet);
350
348
  const connectAccount = { provider, did: userDid, pk: userPk };
351
349
 
352
350
  let updatedUser;
@@ -411,26 +409,32 @@ module.exports = {
411
409
  }
412
410
 
413
411
  // 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
- });
412
+ if (shouldSyncFederated(sourceAppPid, masterSite, blocklet)) {
413
+ node.syncFederated({
414
+ did: teamDid,
415
+ data: {
416
+ users: [
417
+ {
418
+ did: updatedUser.did,
419
+ pk: updatedUser.pk,
420
+ fullName: updatedUser.fullName,
421
+ email: updatedUser.email || '',
422
+ avatar: getUserAvatarUrl(updatedUser.avatar, blocklet),
423
+ connectedAccount: [connectAccount, connectedNft],
424
+ action: 'connectAccount',
425
+ sourceAppPid: sourceAppPid || masterSite.appPid,
426
+ },
427
+ ],
428
+ },
429
+ });
430
+ }
430
431
 
431
432
  // Generate new session token that client can save to localStorage
432
433
  const createToken = createTokenFn(createSessionToken);
433
434
  const sessionConfig = blocklet.settings?.session || {};
435
+
436
+ // request.context.store.connectedWallet
437
+ const walletOS = request.context.didwallet.os;
434
438
  const { sessionToken, refreshToken } = createToken(
435
439
  realDid,
436
440
  {
@@ -440,6 +444,7 @@ module.exports = {
440
444
  fullName,
441
445
  // NOTE: token 中存储当前的 login provider
442
446
  provider,
447
+ walletOS,
443
448
  },
444
449
  { ...sessionConfig, didConnectVersion: getDidConnectVersion(request) }
445
450
  );
@@ -455,36 +460,6 @@ module.exports = {
455
460
  await node.setBlockletInitialized({ did: teamDid, owner: { did: realDid, pk: realPk } });
456
461
  }
457
462
 
458
- const { permanentWallet } = blockletInfo;
459
-
460
- let federatedSessionToken;
461
- let federatedRefreshToken;
462
- // member 使用 federated login 时,总是会让 Master 自动登录
463
- if (masterSite && sourceAppPid) {
464
- const postUser = pick(updatedUser, ['did', 'pk', 'fullName', 'locale']);
465
- postUser.lastLoginAt = get(request, 'headers[x-real-ip]') || '';
466
-
467
- if (updatedUser.email) {
468
- postUser.email = updatedUser.email;
469
- }
470
- if (updatedUser.avatar) {
471
- postUser.avatar = getUserAvatarUrl(updatedUser.avatar, blocklet);
472
- }
473
-
474
- const { data } = await api.post(
475
- joinUrl(masterSite.appUrl, WELLKNOWN_SERVICE_PATH_PREFIX, '/api/federated/loginByMember'),
476
- {
477
- signer: permanentWallet.address,
478
- data: signV2(permanentWallet.address, permanentWallet.secretKey, {
479
- user: postUser,
480
- passport,
481
- }),
482
- }
483
- );
484
- federatedSessionToken = data.sessionToken;
485
- federatedRefreshToken = data.refreshToken;
486
- }
487
-
488
463
  // issue passport for the first login user in a invite-only team
489
464
  if (issuePassport) {
490
465
  return {
@@ -493,8 +468,6 @@ module.exports = {
493
468
  data: vc,
494
469
  sessionToken,
495
470
  refreshToken,
496
- federatedSessionToken,
497
- federatedRefreshToken,
498
471
  nextWorkflowData: {
499
472
  userDid: realDid,
500
473
  },
@@ -504,8 +477,6 @@ module.exports = {
504
477
  return {
505
478
  sessionToken,
506
479
  refreshToken,
507
- federatedSessionToken,
508
- federatedRefreshToken,
509
480
  nextWorkflowData: {
510
481
  userDid: realDid,
511
482
  },
@@ -597,13 +568,23 @@ module.exports = {
597
568
  if (syncUserData.avatar) {
598
569
  syncUserData.avatar = getUserAvatarUrl(syncUserData.avatar, blocklet);
599
570
  }
571
+ const sourceAppPid = getSourceAppPid(request);
572
+ const masterSite = getFederatedMaster(blocklet);
600
573
  // NOTICE: 采用异步来更新,不阻塞接口的正常响应
601
- node.syncFederated({
602
- did: teamDid,
603
- data: {
604
- users: [{ ...syncUserData, action: 'switchProfile' }],
605
- },
606
- });
574
+ if (shouldSyncFederated(sourceAppPid, masterSite, blocklet)) {
575
+ node.syncFederated({
576
+ did: teamDid,
577
+ data: {
578
+ users: [
579
+ {
580
+ ...syncUserData,
581
+ action: 'switchProfile',
582
+ sourceAppPid: sourceAppPid || masterSite.appPid,
583
+ },
584
+ ],
585
+ },
586
+ });
587
+ }
607
588
  },
608
589
  },
609
590
 
@@ -660,6 +641,7 @@ module.exports = {
660
641
  createSessionToken,
661
642
  componentId,
662
643
  sourceAppPid,
644
+ provider,
663
645
  }) => {
664
646
  const blocklet = await request.getBlocklet();
665
647
  const { name, did: teamDid, secret } = await request.getBlockletInfo();
@@ -743,7 +725,15 @@ module.exports = {
743
725
  const sessionConfig = blocklet.settings?.session || {};
744
726
  const { sessionToken, refreshToken } = createToken(
745
727
  userDid,
746
- { secret, passport, role, fullName: user.fullName, sourceAppPid },
728
+ {
729
+ secret,
730
+ passport,
731
+ role,
732
+ fullName: user.fullName,
733
+ provider,
734
+ // request.context.store.connectedWallet
735
+ walletOS: request.context.didwallet.os,
736
+ },
747
737
  { ...sessionConfig, didConnectVersion: getDidConnectVersion(request) }
748
738
  );
749
739
  return { sessionToken, refreshToken };
@@ -845,7 +835,9 @@ module.exports = {
845
835
  },
846
836
  onApprove: async ({ node, request, locale, userDid, userPk, claims, previousUserDid, baseUrl }) => {
847
837
  const blocklet = await request.getBlocklet();
848
- const { did: teamDid, wallet: blockletWallet } = await request.getBlockletInfo();
838
+ const sourceAppPid = getSourceAppPid(request);
839
+ const blockletInfo = await request.getBlockletInfo();
840
+ const { did: teamDid, wallet: blockletWallet } = blockletInfo;
849
841
 
850
842
  const oauthUser = await node.getUser({ teamDid, user: { did: previousUserDid } });
851
843
  const nodeInfo = await request.getNodeInfo();
@@ -905,21 +897,31 @@ module.exports = {
905
897
  passports: mergePassport,
906
898
  },
907
899
  });
900
+ const masterSite = getFederatedMaster(blocklet);
908
901
  // 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
- });
902
+ if (shouldSyncFederated(sourceAppPid, masterSite, blocklet)) {
903
+ const syncUserData = {
904
+ did: oauthUser.did,
905
+ pk: oauthUser.pk,
906
+ ...mergeProfile,
907
+ connectedAccount: [connectedAccount],
908
+ };
909
+ if (syncUserData.avatar) {
910
+ syncUserData.avatar = getUserAvatarUrl(syncUserData.avatar, blocklet);
911
+ }
912
+ node.syncFederated({
913
+ did: teamDid,
914
+ data: {
915
+ users: [
916
+ {
917
+ ...syncUserData,
918
+ action: 'connectAccount',
919
+ sourceAppPid: sourceAppPid || masterSite.appPid,
920
+ },
921
+ ],
922
+ },
923
+ });
924
+ }
923
925
 
924
926
  if (!bindUser) {
925
927
  bindUser = {
@@ -930,6 +932,7 @@ module.exports = {
930
932
  };
931
933
  }
932
934
 
935
+ // FIXME:@zhanghan 统一登录的 passport 相关问题后续统一处理
933
936
  await transferPassport(oauthUser, bindUser, {
934
937
  req: request,
935
938
  node,
@@ -939,12 +942,23 @@ module.exports = {
939
942
  revokePassport: true,
940
943
  });
941
944
 
942
- const connectedAccounts = oauthUser?.connectedAccounts || [];
943
- const sourceProvider = oauthUser?.sourceProvider;
944
- const oauthAccount = connectedAccounts.find((item) => item.provider === sourceProvider);
945
- const userWallet = fromAppDid(oauthAccount.id, blockletWallet.secretKey);
946
- await declareAccount({ wallet: userWallet, blocklet });
947
- await migrateAccount({ wallet: userWallet, blocklet, user: bindUser });
945
+ if (sourceAppPid) {
946
+ await migrateAuth0({
947
+ // 目前只允许未注册过的钱包绑定 auth0,所以直接传入钱包生成的 userDid userPk
948
+ toUserDid: userDid,
949
+ toUserPk: userPk,
950
+ fromUserDid: previousUserDid,
951
+ blockletInfo,
952
+ blocklet,
953
+ });
954
+ } else {
955
+ const connectedAccounts = oauthUser?.connectedAccounts || [];
956
+ const sourceProvider = oauthUser?.sourceProvider;
957
+ const oauthAccount = connectedAccounts.find((item) => item.provider === sourceProvider);
958
+ const userWallet = fromAppDid(oauthAccount.id, blockletWallet.secretKey);
959
+ await declareAccount({ wallet: userWallet, blocklet });
960
+ await migrateAccount({ wallet: userWallet, blocklet, user: bindUser });
961
+ }
948
962
 
949
963
  await node.createAuditLog(
950
964
  {
@@ -4,25 +4,47 @@ const { getConnectAppUrl, getChainInfo } = require('@blocklet/meta/lib/util');
4
4
  const { WELLKNOWN_SERVICE_PATH_PREFIX } = require('@abtnode/constant');
5
5
  const { getSourceAppPid } = require('@blocklet/sdk/lib/util/login');
6
6
 
7
+ function getFederatedMasterAppInfo({ blocklet, sourceAppPid, baseUrl, version, request, groupPathPrefix, nodeInfo }) {
8
+ const { federated } = blocklet.settings;
9
+ const master = federated.sites.find((x) => x.appPid === sourceAppPid);
10
+ // 对于 ux 来说,要展示的始终是 pid,所以这个给 agentDid 的赋值也需要是 pid
11
+ // federated 登录模式下,需要告知原有的 blocklet-did
12
+ const agentDid = blocklet.appPid;
13
+
14
+ return {
15
+ name: master.appName,
16
+ description: master.appescription || `Connect to ${master.appName}`,
17
+ icon: joinUrl(master.appUrl, WELLKNOWN_SERVICE_PATH_PREFIX, `/blocklet/logo?v=${version}`),
18
+ link: getConnectAppUrl({ request, baseUrl }),
19
+ updateSubEndpoint: true,
20
+ subscriptionEndpoint: joinUrl(groupPathPrefix, WELLKNOWN_SERVICE_PATH_PREFIX, 'websocket'),
21
+ nodeDid: nodeInfo.did,
22
+ agentDid,
23
+ };
24
+ }
25
+
7
26
  module.exports = {
8
27
  appInfo: async ({ request, baseUrl }) => {
9
28
  const groupPathPrefix = request.headers['x-group-path-prefix'] || '/';
10
29
 
11
- const [blocklet, meta, info] = await Promise.all([
12
- request.getBlocklet(),
13
- request.getBlockletInfo(),
14
- request.getNodeInfo(),
15
- ]);
16
- // 对于 ux 来说, 要展示的始终是 pid,所以这个给 agentDid 的赋值也需要是 pid
17
- let agentDid;
30
+ const [blocklet, info] = await Promise.all([request.getBlocklet(), request.getNodeInfo()]);
31
+
18
32
  const sourceAppPid = getSourceAppPid(request);
19
- // federated 登录模式下,需要告知原有的 blocklet-did
20
- if (sourceAppPid) {
21
- agentDid = blocklet.appPid;
22
- }
23
33
 
24
34
  const version = get(blocklet, 'meta.version', '');
25
35
 
36
+ if (sourceAppPid) {
37
+ return getFederatedMasterAppInfo({
38
+ blocklet,
39
+ sourceAppPid,
40
+ baseUrl,
41
+ version,
42
+ groupPathPrefix,
43
+ request,
44
+ nodeInfo: info,
45
+ });
46
+ }
47
+ const meta = await request.getBlockletInfo();
26
48
  return {
27
49
  name: meta.name,
28
50
  description: meta.description || `Connect to ${meta.name}`,
@@ -32,7 +54,6 @@ module.exports = {
32
54
  subscriptionEndpoint: joinUrl(groupPathPrefix, WELLKNOWN_SERVICE_PATH_PREFIX, 'websocket'),
33
55
  nodeDid: info.did,
34
56
  // NOTE: publisher 是 WalletAuthenticator 中自动添加的
35
- agentDid,
36
57
  };
37
58
  },
38
59
 
package/api/libs/jwt.js CHANGED
@@ -18,7 +18,7 @@ const initJwt = (node, options) => {
18
18
 
19
19
  const createSessionToken = (
20
20
  did,
21
- { role, secret, passport, expiresIn, tokenType, fullName, provider = LOGIN_PROVIDER.WALLET }
21
+ { role, secret, passport, expiresIn, tokenType, fullName, provider = LOGIN_PROVIDER.WALLET, walletOS }
22
22
  ) =>
23
23
  createAuthToken({
24
24
  did,
@@ -29,6 +29,7 @@ const initJwt = (node, options) => {
29
29
  tokenType,
30
30
  fullName,
31
31
  provider,
32
+ walletOS,
32
33
  });
33
34
 
34
35
  const verifySessionToken = (token, secret, { checkFromDb, teamDid, checkToken } = {}) =>
@@ -47,7 +48,7 @@ const initJwt = (node, options) => {
47
48
  }
48
49
  }
49
50
 
50
- const { did, role, passport, fullName, provider = LOGIN_PROVIDER.WALLET } = decoded;
51
+ const { did, role, passport, fullName, provider = LOGIN_PROVIDER.WALLET, walletOS } = decoded;
51
52
  let user;
52
53
  if (!did) {
53
54
  return reject(new Error('Invalid jwt token: invalid did'));
@@ -75,8 +76,9 @@ const initJwt = (node, options) => {
75
76
  user.role = role;
76
77
  user.passport = passport;
77
78
  user.provider = provider;
79
+ user.walletOS = walletOS;
78
80
  } else {
79
- user = { did, role, passport, fullName, provider };
81
+ user = { did, role, passport, fullName, provider, walletOS };
80
82
  }
81
83
 
82
84
  return resolve(user);
@@ -6,6 +6,7 @@ const get = require('lodash/get');
6
6
  const isNil = require('lodash/isNil');
7
7
  const pLimit = require('p-limit');
8
8
  const pRetry = require('p-retry');
9
+ const joinUrl = require('url-join');
9
10
 
10
11
  const cors = require('cors');
11
12
  const { LOGIN_PROVIDER } = require('@blocklet/constant');
@@ -14,16 +15,18 @@ const { getApplicationInfo } = require('@abtnode/auth/lib/auth');
14
15
  const pick = require('lodash/pick');
15
16
  const defaults = require('lodash/defaults');
16
17
  const remove = require('lodash/remove');
18
+ const { fromAppDid } = require('@arcblock/did-ext');
17
19
 
18
20
  const logger = require('@abtnode/logger')('blocklet-services:federated');
19
21
 
20
22
  const { api } = require('../libs/api');
21
23
  const initJwt = require('../libs/jwt');
22
24
  const { createTokenFn, getDidConnectVersion } = require('../util');
23
- const verifyFederatedCall = require('../middlewares/verify-federated-call');
24
25
  const ensureBlocklet = require('../middlewares/ensure-blocklet');
26
+ const verifyFederatedCall = require('../middlewares/verify-federated-call');
25
27
  const checkFederatedCorsCall = require('../middlewares/check-federated-cors-call');
26
- const { getUserAvatarUrl } = require('../util/federated');
28
+ const { getUserAvatarUrl, getFederatedMaster } = require('../util/federated');
29
+ const { declareAccount, migrateAccount } = require('../services/oauth');
27
30
 
28
31
  const PREFIX = WELLKNOWN_SERVICE_PATH_PREFIX;
29
32
 
@@ -50,7 +53,7 @@ async function syncSwitchProfile(user, { node, teamDid, dataDir }) {
50
53
  }
51
54
 
52
55
  async function syncConnectAccount(user, { node, teamDid, dataDir }) {
53
- const tempUser = pick(user, ['did', 'pk', 'avatar', 'fullName', 'email', 'connectedAccount']);
56
+ const tempUser = pick(user, ['did', 'pk', 'avatar', 'fullName', 'email', 'connectedAccount', 'sourceAppPid']);
54
57
 
55
58
  // 处理 avatar
56
59
  if (tempUser.avatar) {
@@ -166,7 +169,7 @@ module.exports = {
166
169
  .filter((item) => item.appId !== federated.config.appId)
167
170
  .map((item) => {
168
171
  return limitSync(async () => {
169
- const url = `${item.appUrl}/${WELLKNOWN_SERVICE_PATH_PREFIX}/api/federated/sync`;
172
+ const url = joinUrl(item.appUrl, WELLKNOWN_SERVICE_PATH_PREFIX, '/api/federated/sync');
170
173
  // NOTICE: 即使通知其他 member 失败了,也不影响来源 member 退出统一登录
171
174
  try {
172
175
  await pRetry(() => api.post(url, postData), {
@@ -272,7 +275,10 @@ module.exports = {
272
275
  for (const user of users) {
273
276
  pendingList.push(
274
277
  limitSync(async () => {
275
- await syncFnMaps[user.action]?.(user, { node, teamDid, dataDir });
278
+ await syncFnMaps[user.action]?.(
279
+ { ...user, sourceAppPid: user.sourceAppPid === teamDid ? undefined : user.sourceAppPid },
280
+ { node, teamDid, dataDir }
281
+ );
276
282
  })
277
283
  );
278
284
  }
@@ -370,13 +376,15 @@ module.exports = {
370
376
  }
371
377
 
372
378
  try {
373
- ({ data } = await api.post(`${loginSite.appUrl}${prefix}/token`, {
379
+ ({ data } = await api.post(joinUrl(loginSite.appUrl, prefix, 'token'), {
374
380
  signer: permanentWallet.address,
375
381
  data: signV2(permanentWallet.address, permanentWallet.secretKey, {
376
382
  masterPid: teamDid,
377
383
  role: req.user.role,
378
384
  user,
379
385
  passport: req.user.passport,
386
+ walletOS: req.user.walletOS,
387
+ provider: req.user.provider,
380
388
  }),
381
389
  }));
382
390
  } catch {
@@ -398,7 +406,7 @@ module.exports = {
398
406
 
399
407
  // step 6 发放自动登录 token(master 向 member 发起生成 token 请求)
400
408
  server.post(`${prefix}/token`, ensureBlocklet(), verifyFederatedCall(), async (req, res) => {
401
- const { user, masterPid, role, passport } = req.body.verifyData;
409
+ const { user, masterPid, role, passport, walletOS, provider } = req.body.verifyData;
402
410
  const { createSessionToken } = initJwt(node, options);
403
411
  const createToken = createTokenFn(createSessionToken);
404
412
  const { secret } = await req.getBlockletInfo();
@@ -438,7 +446,7 @@ module.exports = {
438
446
  // passport: findMapping ? targetPassport : null,
439
447
  sourceAppPid: masterPid,
440
448
  connectedAccount: {
441
- provider: LOGIN_PROVIDER.WALLET,
449
+ provider: provider || LOGIN_PROVIDER.WALLET,
442
450
  id: masterPid,
443
451
  did: user.did,
444
452
  pk: user.pk,
@@ -452,7 +460,8 @@ module.exports = {
452
460
  role: targetPassport.role,
453
461
  passport: targetPassport,
454
462
  fullName: doc.fullName,
455
- provider: LOGIN_PROVIDER.WALLET,
463
+ provider: provider || LOGIN_PROVIDER.WALLET,
464
+ walletOS,
456
465
  },
457
466
  {
458
467
  ...sessionConfig,
@@ -483,7 +492,7 @@ module.exports = {
483
492
  // member 传递过来的 user.did 和 user.pk 均为 master-site 与钱包生成的
484
493
 
485
494
  server.post(`${prefix}/loginByMember`, ensureBlocklet(), verifyFederatedCall(), async (req, res) => {
486
- const { user, passport } = req.body.verifyData;
495
+ const { user, passport, walletOS, provider } = req.body.verifyData;
487
496
  const { createSessionToken } = initJwt(node, options);
488
497
  const createToken = createTokenFn(createSessionToken);
489
498
  const { secret } = await req.getBlockletInfo();
@@ -520,8 +529,7 @@ module.exports = {
520
529
  pk: realPk,
521
530
  passport: targetPassport,
522
531
  connectedAccount: {
523
- // member 在使用 federated login 时,本质还是使用 wallet 来登录的,所以对 master-site 来说,登录的 provider 就是 wallet
524
- provider: LOGIN_PROVIDER.WALLET,
532
+ provider: provider || LOGIN_PROVIDER.WALLET,
525
533
  did: user.did,
526
534
  pk: user.pk,
527
535
  },
@@ -537,6 +545,7 @@ module.exports = {
537
545
  fullName: newUser.fullName,
538
546
  // 这里是 member 登录了 master 的账号,对于 master 来说,其实还是使用 wallet 来登录的
539
547
  provider: LOGIN_PROVIDER.WALLET,
548
+ walletOS,
540
549
  },
541
550
  {
542
551
  ...sessionConfig,
@@ -546,5 +555,49 @@ module.exports = {
546
555
 
547
556
  res.json({ sessionToken, refreshToken });
548
557
  });
558
+
559
+ server.post(`${prefix}/migrateAuth0`, ensureBlocklet(), verifyFederatedCall(), async (req, res) => {
560
+ const { blocklet } = req;
561
+ const { did: teamDid, wallet: blockletWallet } = await req.getBlockletInfo();
562
+ const { fromUserDid, toUserDid, toUserPk } = req.body.verifyData;
563
+ const oauthUser = await node.getUser({ teamDid, user: { did: fromUserDid } });
564
+ const connectedAccounts = oauthUser?.connectedAccounts || [];
565
+ const sourceProvider = oauthUser?.sourceProvider;
566
+ const oauthAccount = connectedAccounts.find((item) => item.provider === sourceProvider);
567
+ const userWallet = fromAppDid(oauthAccount.id, blockletWallet.secretKey);
568
+
569
+ const bindUser = {
570
+ did: toUserDid,
571
+ pk: toUserPk,
572
+ };
573
+ await declareAccount({ wallet: userWallet, blocklet });
574
+ await migrateAccount({ wallet: userWallet, blocklet, user: bindUser });
575
+ res.json({});
576
+ });
577
+
578
+ server.post(`${prefix}/loginMaster`, ensureBlocklet(), async (req, res) => {
579
+ if (!req.user) {
580
+ res.status(401).send('Unauthorized');
581
+ return;
582
+ }
583
+ const { blocklet } = req;
584
+ const masterSite = getFederatedMaster(blocklet);
585
+ if (!masterSite) {
586
+ res.status(400).send('No federated context found');
587
+ return;
588
+ }
589
+
590
+ const { did: teamDid, permanentWallet } = await req.getBlockletInfo();
591
+ const user = await node.getUser({ teamDid, user: { did: req.user.did } });
592
+ const { passport, walletOS, provider } = req.user;
593
+ const url = joinUrl(masterSite.appUrl, prefix, 'loginByMember');
594
+ const postData = {
595
+ signer: permanentWallet.address,
596
+ data: signV2(permanentWallet.address, permanentWallet.secretKey, { user, passport, walletOS, provider }),
597
+ };
598
+
599
+ const { data } = await api.post(url, postData);
600
+ res.json(data);
601
+ });
549
602
  },
550
603
  };