@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.
- package/api/index.js +1 -1
- package/api/libs/connect/session.js +96 -82
- package/api/libs/connect/shared.js +33 -12
- package/api/libs/jwt.js +5 -3
- package/api/routes/federated.js +65 -12
- package/api/routes/oauth.js +134 -76
- package/api/routes/user.js +1 -0
- package/api/services/auth/connect/invite.js +10 -1
- package/api/services/auth/connect/login.js +0 -2
- package/api/services/auth/connect/receive-transfer-app-owner.js +2 -1
- package/api/services/auth/connect/switch-passport.js +5 -1
- package/api/services/auth/session.js +14 -2
- package/api/util/federated.js +97 -0
- package/build/asset-manifest.json +53 -53
- package/build/index.html +1 -1
- package/build/service-worker.js +1 -1
- package/build/static/js/{1480.36129849.chunk.js → 1480.88c590c2.chunk.js} +2 -2
- package/build/static/js/{1565.ad002b88.chunk.js → 1565.6df974b9.chunk.js} +2 -2
- package/build/static/js/{1760.71e0c151.chunk.js → 1760.70492184.chunk.js} +2 -2
- package/build/static/js/{2653.6f37e8a0.chunk.js → 2653.5dc29ed5.chunk.js} +2 -2
- package/build/static/js/2836.f4b10b64.chunk.js +2 -0
- package/build/static/js/{4042.3c8e0025.chunk.js → 2838.6fa46760.chunk.js} +3 -3
- package/build/static/js/{1660.9fb17942.chunk.js → 3025.7dc2fe04.chunk.js} +2 -2
- package/build/static/js/{4023.4be0c818.chunk.js → 4023.202dcd9a.chunk.js} +2 -2
- package/build/static/js/{4706.df5b600d.chunk.js → 4706.212c92c8.chunk.js} +3 -3
- package/build/static/js/4716.88f32cf2.chunk.js +2 -0
- package/build/static/js/{4802.b7fa8e82.chunk.js → 4802.3b60e453.chunk.js} +2 -2
- package/build/static/js/{5176.53f7f419.chunk.js → 5176.7e91bc3b.chunk.js} +2 -2
- package/build/static/js/{5628.aa14b1a7.chunk.js → 5628.e46ecc79.chunk.js} +2 -2
- package/build/static/js/{6380.2b96be29.chunk.js → 5673.ab67c509.chunk.js} +2 -2
- package/build/static/js/{6186.6462ea21.chunk.js → 6186.ebbdb4b8.chunk.js} +2 -2
- package/build/static/js/{6452.4226209b.chunk.js → 6452.143af37a.chunk.js} +2 -2
- package/build/static/js/{6629.785fe237.chunk.js → 6629.376863d2.chunk.js} +3 -3
- package/build/static/js/{6640.e453c619.chunk.js → 6640.a4431c82.chunk.js} +2 -2
- package/build/static/js/{6737.7fe9f13a.chunk.js → 6737.7d135225.chunk.js} +2 -2
- package/build/static/js/{6856.9aaf692c.chunk.js → 6856.e185e317.chunk.js} +2 -2
- package/build/static/js/{8706.3d16907a.chunk.js → 7367.60cb10e0.chunk.js} +2 -2
- package/build/static/js/{7465.999f0039.chunk.js → 7465.2bb961d7.chunk.js} +3 -3
- package/build/static/js/{9409.fe4a0af0.chunk.js → 9409.62a2aee0.chunk.js} +2 -2
- package/build/static/js/{9620.db1568ef.chunk.js → 9620.301493bc.chunk.js} +2 -2
- package/build/static/js/{9899.92626f0a.chunk.js → 9899.b8d8a5ca.chunk.js} +2 -2
- package/build/static/js/main.a58f939e.js +3 -0
- package/package.json +34 -34
- package/build/static/js/4716.17a45b6a.chunk.js +0 -2
- package/build/static/js/5662.522d3713.chunk.js +0 -2
- package/build/static/js/main.85d66eb2.js +0 -3
- /package/build/static/js/{4042.3c8e0025.chunk.js.LICENSE.txt → 2838.6fa46760.chunk.js.LICENSE.txt} +0 -0
- /package/build/static/js/{4706.df5b600d.chunk.js.LICENSE.txt → 4706.212c92c8.chunk.js.LICENSE.txt} +0 -0
- /package/build/static/js/{6629.785fe237.chunk.js.LICENSE.txt → 6629.376863d2.chunk.js.LICENSE.txt} +0 -0
- /package/build/static/js/{7465.999f0039.chunk.js.LICENSE.txt → 7465.2bb961d7.chunk.js.LICENSE.txt} +0 -0
- /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: '
|
|
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,
|
|
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
|
-
|
|
415
|
-
|
|
416
|
-
|
|
417
|
-
|
|
418
|
-
|
|
419
|
-
|
|
420
|
-
|
|
421
|
-
|
|
422
|
-
|
|
423
|
-
|
|
424
|
-
|
|
425
|
-
|
|
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
|
-
|
|
602
|
-
|
|
603
|
-
|
|
604
|
-
|
|
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
|
-
{
|
|
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
|
|
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
|
-
|
|
910
|
-
|
|
911
|
-
|
|
912
|
-
|
|
913
|
-
|
|
914
|
-
|
|
915
|
-
|
|
916
|
-
|
|
917
|
-
|
|
918
|
-
|
|
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
|
-
|
|
943
|
-
|
|
944
|
-
|
|
945
|
-
|
|
946
|
-
|
|
947
|
-
|
|
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,
|
|
12
|
-
|
|
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);
|
package/api/routes/federated.js
CHANGED
|
@@ -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 =
|
|
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]?.(
|
|
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(
|
|
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
|
-
|
|
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
|
};
|