@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.
- package/api/libs/connect/session.js +36 -27
- package/api/libs/jwt.js +1 -0
- package/api/middlewares/check-federated-cors-call.js +1 -0
- package/api/routes/federated.js +125 -44
- package/api/routes/oauth.js +3 -0
- package/api/services/auth/connect/switch-passport.js +7 -2
- package/api/services/auth/session.js +10 -36
- package/api/util/blocklet-utils.js +38 -4
- package/build/asset-manifest.json +9 -10
- package/build/index.html +1 -1
- package/build/service-worker.js +1 -1
- package/build/service-worker.js.map +1 -1
- package/build/static/js/{4603.ee59facc.chunk.js → 4603.c6657383.chunk.js} +2 -2
- package/build/static/js/8031.9944bf3c.chunk.js +2 -0
- package/build/static/js/8395.40dc877e.chunk.js +2 -0
- package/build/static/js/main.0757731a.js +3 -0
- package/package.json +27 -27
- package/build/static/js/8031.d9af3d84.chunk.js +0 -2
- package/build/static/js/8395.e5aa519c.chunk.js +0 -2
- package/build/static/js/main.f1826eac.js +0 -3
- package/build/static/media/index.20414a3fa1e6c5498a67.cjs +0 -1
- /package/build/static/js/{main.f1826eac.js.LICENSE.txt → main.0757731a.js.LICENSE.txt} +0 -0
|
@@ -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
|
|
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 = [] } =
|
|
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
|
-
|
|
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: [
|
|
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 } =
|
|
433
|
+
const { permanentWallet } = blockletInfo;
|
|
426
434
|
|
|
427
|
-
const masterSite = getFederatedMaster(blocklet);
|
|
428
435
|
let federatedSessionToken;
|
|
429
436
|
let federatedRefreshToken;
|
|
430
|
-
|
|
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
|
|
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
|
@@ -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;
|
package/api/routes/federated.js
CHANGED
|
@@ -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
|
-
|
|
37
|
-
|
|
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
|
-
|
|
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.
|
|
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.
|
|
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,
|
|
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 ===
|
|
152
|
+
const hasTrustedPassport = trustedPassports.find((item) => item.issuerDid === masterPid);
|
|
102
153
|
if (!hasTrustedPassport) {
|
|
103
154
|
await node.configTrustedPassports({
|
|
104
|
-
teamDid: blocklet.
|
|
155
|
+
teamDid: blocklet.appPid,
|
|
105
156
|
trustedPassports: [
|
|
106
157
|
...trustedPassports,
|
|
107
158
|
{
|
|
108
|
-
issuerDid:
|
|
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.
|
|
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.
|
|
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.
|
|
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:
|
|
170
|
-
appPid:
|
|
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.
|
|
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
|
-
|
|
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,
|
|
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.
|
|
310
|
+
const teamDid = blocklet.appPid;
|
|
260
311
|
|
|
261
312
|
const sessionConfig = blocklet.settings?.session || {};
|
|
262
313
|
const trustedPassports = blocklet.trustedPassports || [];
|
|
263
|
-
|
|
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:
|
|
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,
|
|
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.
|
|
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
|
-
|
|
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
|
-
...
|
|
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
|
-
|
|
430
|
+
user.did,
|
|
350
431
|
{
|
|
351
432
|
secret,
|
|
352
433
|
passport: targetPassport,
|
|
353
434
|
role: targetPassport?.role || 'guest',
|
|
354
|
-
fullName:
|
|
435
|
+
fullName: newUser.fullName,
|
|
355
436
|
},
|
|
356
437
|
{
|
|
357
438
|
...sessionConfig,
|
package/api/routes/oauth.js
CHANGED
|
@@ -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: ({
|
|
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);
|