@abtnode/blocklet-services 1.16.18 → 1.16.19-beta-e6aac665
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 +17 -19
- package/api/libs/connect/v1.js +5 -1
- package/api/libs/connect/v2.js +5 -4
- package/api/libs/image.js +2 -2
- package/api/routes/federated.js +108 -19
- package/api/routes/oauth.js +19 -26
- package/api/routes/user-session.js +5 -1
- package/api/routes/user.js +1 -0
- package/api/services/auth/connect/invite.js +8 -5
- package/api/util/federated.js +45 -0
- package/api/validators/login.js +1 -1
- package/build/asset-manifest.json +15 -15
- package/build/index.html +1 -1
- package/build/service-worker.js +1 -1
- package/build/static/js/4076.8055ce74.chunk.js +2 -0
- package/build/static/js/4461.f9a883d3.chunk.js +2 -0
- package/build/static/js/5468.21a861b9.chunk.js +2 -0
- package/build/static/js/5547.42b98889.chunk.js +3 -0
- package/build/static/js/8622.6aa0a4d4.chunk.js +2 -0
- package/build/static/js/8944.939de854.chunk.js +2 -0
- package/build/static/js/main.6f748ae5.js +3 -0
- package/package.json +24 -27
- package/build/static/js/4076.f5369a1d.chunk.js +0 -2
- package/build/static/js/4461.3cd698bf.chunk.js +0 -2
- package/build/static/js/5468.b54ce65b.chunk.js +0 -2
- package/build/static/js/5547.570ded36.chunk.js +0 -3
- package/build/static/js/8622.ebd44812.chunk.js +0 -2
- package/build/static/js/8944.559ade67.chunk.js +0 -2
- package/build/static/js/main.bf370e0c.js +0 -3
- /package/build/static/js/{5547.570ded36.chunk.js.LICENSE.txt → 5547.42b98889.chunk.js.LICENSE.txt} +0 -0
- /package/build/static/js/{main.bf370e0c.js.LICENSE.txt → main.6f748ae5.js.LICENSE.txt} +0 -0
|
@@ -48,7 +48,13 @@ const { isInvitedUserOnly, createTokenFn, getDidConnectVersion } = require('../.
|
|
|
48
48
|
const { transferPassport } = require('../auth/utils');
|
|
49
49
|
const { migrateAccount, declareAccount } = require('../../services/oauth');
|
|
50
50
|
const { getTrustedIssuers, getFederatedTrustedIssuers } = require('../../util/blocklet-utils');
|
|
51
|
-
const {
|
|
51
|
+
const {
|
|
52
|
+
getUserAvatarUrl,
|
|
53
|
+
migrateAuth0,
|
|
54
|
+
getFederatedMaster,
|
|
55
|
+
shouldSyncFederated,
|
|
56
|
+
getUserWithinFederated,
|
|
57
|
+
} = require('../../util/federated');
|
|
52
58
|
|
|
53
59
|
const vcTypes = [VC_TYPE_GENERAL_PASSPORT, VC_TYPE_NODE_PASSPORT];
|
|
54
60
|
|
|
@@ -215,23 +221,16 @@ module.exports = {
|
|
|
215
221
|
const blocklet = await request.getBlocklet();
|
|
216
222
|
const blockletInfo = await request.getBlockletInfo();
|
|
217
223
|
const { wallet, secret, name, passportColor, did: teamDid } = blockletInfo;
|
|
224
|
+
const sourceAppPid = getSourceAppPid(request);
|
|
218
225
|
|
|
219
226
|
// Check user approved
|
|
220
|
-
const
|
|
221
|
-
|
|
222
|
-
user: {
|
|
223
|
-
did: userDid,
|
|
224
|
-
},
|
|
225
|
-
options: {
|
|
226
|
-
enableConnectedAccount: true,
|
|
227
|
-
},
|
|
228
|
-
});
|
|
229
|
-
if (user && !user.approved) {
|
|
227
|
+
const currentUser = await getUserWithinFederated({ sourceAppPid, teamDid, userDid, userPk }, { node, blocklet });
|
|
228
|
+
if (currentUser && !currentUser.approved) {
|
|
230
229
|
throw new Error(messages.notAllowed[locale]);
|
|
231
230
|
}
|
|
232
231
|
|
|
233
|
-
const realDid =
|
|
234
|
-
const realPk =
|
|
232
|
+
const realDid = currentUser?.did || userDid;
|
|
233
|
+
const realPk = currentUser?.pk || userPk;
|
|
235
234
|
|
|
236
235
|
// Get auth config
|
|
237
236
|
const authConfig = (await request.getServiceConfig(NODE_SERVICES.AUTH, { componentId })) || {};
|
|
@@ -244,7 +243,6 @@ module.exports = {
|
|
|
244
243
|
let defaultTtlPolicy = 'never';
|
|
245
244
|
let issuePassport = false;
|
|
246
245
|
|
|
247
|
-
const sourceAppPid = getSourceAppPid(request);
|
|
248
246
|
const provider = getLoginProvider(request);
|
|
249
247
|
const masterSite = getFederatedMaster(blocklet);
|
|
250
248
|
|
|
@@ -318,7 +316,7 @@ module.exports = {
|
|
|
318
316
|
|
|
319
317
|
// Get user passport from vc
|
|
320
318
|
let passport = vc ? createUserPassport(vc) : null;
|
|
321
|
-
if (
|
|
319
|
+
if (currentUser && passport && isUserPassportRevoked(currentUser, passport)) {
|
|
322
320
|
throw new Error(messages.passportRevoked[locale](passport.title, name));
|
|
323
321
|
}
|
|
324
322
|
|
|
@@ -342,19 +340,19 @@ module.exports = {
|
|
|
342
340
|
}
|
|
343
341
|
: null;
|
|
344
342
|
|
|
345
|
-
let fullName =
|
|
343
|
+
let fullName = currentUser?.fullName;
|
|
346
344
|
// Update profile
|
|
347
345
|
const passportForLog = passport || { name: 'Guest', role: 'guest' };
|
|
348
346
|
|
|
349
347
|
const connectAccount = { provider, did: userDid, pk: userPk };
|
|
350
348
|
|
|
351
349
|
let updatedUser;
|
|
352
|
-
if (
|
|
350
|
+
if (currentUser) {
|
|
353
351
|
updatedUser = await node.loginUser({
|
|
354
352
|
teamDid,
|
|
355
353
|
user: {
|
|
356
|
-
did:
|
|
357
|
-
pk:
|
|
354
|
+
did: currentUser.did,
|
|
355
|
+
pk: currentUser.pk,
|
|
358
356
|
locale,
|
|
359
357
|
passport,
|
|
360
358
|
sourceAppPid,
|
package/api/libs/connect/v1.js
CHANGED
|
@@ -66,7 +66,11 @@ module.exports = (node, opts) => {
|
|
|
66
66
|
|
|
67
67
|
const handlerOpts = {
|
|
68
68
|
authenticator,
|
|
69
|
-
tokenStorage: new DynamicStorage({
|
|
69
|
+
tokenStorage: new DynamicStorage({
|
|
70
|
+
dbPath: path.join(opts.dataDir, 'connections.db'),
|
|
71
|
+
model: 'Connection',
|
|
72
|
+
primaryKey: 'token',
|
|
73
|
+
}),
|
|
70
74
|
sendNotificationFn: async (connectedDid, message, { req }) => {
|
|
71
75
|
const { wallet } = await req.getBlockletInfo();
|
|
72
76
|
return sendToUser(
|
package/api/libs/connect/v2.js
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
const path = require('path');
|
|
2
|
-
const
|
|
2
|
+
const DynamicStorage = require('@abtnode/connect-storage');
|
|
3
3
|
const { Authenticator } = require('@did-connect/authenticator');
|
|
4
4
|
const createHandlers = require('@blocklet/sdk/lib/connect/handler');
|
|
5
5
|
const { sendToUser } = require('@blocklet/sdk/lib/util/send-notification');
|
|
@@ -22,9 +22,10 @@ module.exports = (node, opts) => {
|
|
|
22
22
|
const handlers = createHandlers({
|
|
23
23
|
logger,
|
|
24
24
|
authenticator,
|
|
25
|
-
storage: new
|
|
26
|
-
|
|
27
|
-
|
|
25
|
+
storage: new DynamicStorage({
|
|
26
|
+
dbPath: path.join(opts.dataDir, 'connections.db'),
|
|
27
|
+
model: 'ConnectionV2',
|
|
28
|
+
primaryKey: 'sessionId',
|
|
28
29
|
}),
|
|
29
30
|
socketPathname: `${WELLKNOWN_SERVICE_PATH_PREFIX}/api/connect/relay/websocket`,
|
|
30
31
|
sendNotificationFn: async (connectedDid, message, { request }) => {
|
package/api/libs/image.js
CHANGED
|
@@ -235,7 +235,7 @@ const processImage = (src, extension, dest, params) => {
|
|
|
235
235
|
dimensions.height = height;
|
|
236
236
|
}
|
|
237
237
|
|
|
238
|
-
const pipeline = sharp({ animated: true }).timeout({ seconds:
|
|
238
|
+
const pipeline = sharp({ animated: true, limitInputPixels: 0 }).timeout({ seconds: 60 });
|
|
239
239
|
if (rotate) {
|
|
240
240
|
pipeline.rotate(rotate);
|
|
241
241
|
}
|
|
@@ -268,7 +268,7 @@ const processImage = (src, extension, dest, params) => {
|
|
|
268
268
|
pipeline.negate();
|
|
269
269
|
}
|
|
270
270
|
|
|
271
|
-
pipeline[format || EXTENSIONS[extension]]({ quality, progressive: !!progressive, force: true });
|
|
271
|
+
pipeline[format || EXTENSIONS[extension]]({ quality, progressive: !!progressive, dither: 0, force: true });
|
|
272
272
|
|
|
273
273
|
pipeline.on('error', (err) => {
|
|
274
274
|
reject(err);
|
package/api/routes/federated.js
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
const { WELLKNOWN_SERVICE_PATH_PREFIX } = require('@abtnode/constant');
|
|
1
|
+
const { WELLKNOWN_SERVICE_PATH_PREFIX, FEDERATED } = require('@abtnode/constant');
|
|
2
2
|
const { signV2 } = require('@arcblock/jwt');
|
|
3
3
|
const normalizePathPrefix = require('@abtnode/util/lib/normalize-path-prefix');
|
|
4
4
|
const cloneDeep = require('lodash/cloneDeep');
|
|
@@ -25,13 +25,12 @@ const { createTokenFn, getDidConnectVersion } = require('../util');
|
|
|
25
25
|
const ensureBlocklet = require('../middlewares/ensure-blocklet');
|
|
26
26
|
const verifyFederatedCall = require('../middlewares/verify-federated-call');
|
|
27
27
|
const checkFederatedCorsCall = require('../middlewares/check-federated-cors-call');
|
|
28
|
-
const { getUserAvatarUrl, getFederatedMaster } = require('../util/federated');
|
|
28
|
+
const { getUserAvatarUrl, getFederatedMaster, getUserWithinFederated } = require('../util/federated');
|
|
29
29
|
const { declareAccount, migrateAccount } = require('../services/oauth');
|
|
30
30
|
|
|
31
31
|
const PREFIX = WELLKNOWN_SERVICE_PATH_PREFIX;
|
|
32
32
|
|
|
33
33
|
const prefix = `${PREFIX}/api/federated`;
|
|
34
|
-
const limitSync = pLimit(1);
|
|
35
34
|
|
|
36
35
|
function getAuditLogActorByFederatedSite(blocklet) {
|
|
37
36
|
return {
|
|
@@ -60,8 +59,13 @@ async function syncSwitchProfile(user, { node, teamDid, dataDir }) {
|
|
|
60
59
|
});
|
|
61
60
|
}
|
|
62
61
|
|
|
63
|
-
|
|
62
|
+
/**
|
|
63
|
+
* 处理站点群中某一站点推送的同步 connectAccount 的请求
|
|
64
|
+
*/
|
|
65
|
+
|
|
66
|
+
async function syncConnectAccount(user, { node, teamDid, dataDir, blocklet }) {
|
|
64
67
|
const tempUser = pick(user, ['did', 'pk', 'avatar', 'fullName', 'email', 'connectedAccount', 'sourceAppPid']);
|
|
68
|
+
const masterSite = getFederatedMaster(blocklet);
|
|
65
69
|
|
|
66
70
|
// 处理 avatar
|
|
67
71
|
if (tempUser.avatar) {
|
|
@@ -73,15 +77,71 @@ async function syncConnectAccount(user, { node, teamDid, dataDir }) {
|
|
|
73
77
|
}
|
|
74
78
|
}
|
|
75
79
|
|
|
80
|
+
// NOTICE: 如果当前站点不是 master,就需要考虑该 member 需要向 master 请求同步一次指定账户,因为指定账户可能存在于站点群,而不存在于当前站点中的情况
|
|
81
|
+
if (masterSite.appPid !== teamDid) {
|
|
82
|
+
await getUserWithinFederated(
|
|
83
|
+
{
|
|
84
|
+
sourceAppPid: tempUser.sourceAppPid,
|
|
85
|
+
teamDid,
|
|
86
|
+
userDid: tempUser.did,
|
|
87
|
+
userPk: tempUser.pk,
|
|
88
|
+
},
|
|
89
|
+
{ blocklet, node }
|
|
90
|
+
);
|
|
91
|
+
}
|
|
92
|
+
|
|
76
93
|
await node.loginUser({
|
|
77
94
|
teamDid,
|
|
78
95
|
user: tempUser,
|
|
79
96
|
});
|
|
80
97
|
}
|
|
81
98
|
|
|
99
|
+
/**
|
|
100
|
+
* member 站点向 master 站点请求拉取一个用户信息
|
|
101
|
+
*/
|
|
102
|
+
async function pullUserAccount(user, { node, teamDid, blocklet }) {
|
|
103
|
+
const { did } = user;
|
|
104
|
+
const currentUser = await node.getUser({
|
|
105
|
+
teamDid,
|
|
106
|
+
user: {
|
|
107
|
+
did,
|
|
108
|
+
},
|
|
109
|
+
options: {
|
|
110
|
+
enableConnectedAccount: true,
|
|
111
|
+
},
|
|
112
|
+
});
|
|
113
|
+
|
|
114
|
+
if (!currentUser) return null;
|
|
115
|
+
|
|
116
|
+
const syncUser = pick(currentUser, [
|
|
117
|
+
'did',
|
|
118
|
+
'pk',
|
|
119
|
+
'fullName',
|
|
120
|
+
'email',
|
|
121
|
+
'remark',
|
|
122
|
+
'sourceProvider',
|
|
123
|
+
'locale',
|
|
124
|
+
'approved',
|
|
125
|
+
'extra',
|
|
126
|
+
'sourceAppPid',
|
|
127
|
+
]);
|
|
128
|
+
syncUser.avatar = getUserAvatarUrl(currentUser.avatar, blocklet);
|
|
129
|
+
syncUser.email = syncUser.email || '';
|
|
130
|
+
syncUser.connectedAccounts = currentUser.connectedAccounts.map((x) => {
|
|
131
|
+
const connectAccount = pick(x, ['did', 'pk', 'provider', 'id']);
|
|
132
|
+
if (!connectAccount.id) {
|
|
133
|
+
delete connectAccount.id;
|
|
134
|
+
}
|
|
135
|
+
return connectAccount;
|
|
136
|
+
});
|
|
137
|
+
|
|
138
|
+
return syncUser;
|
|
139
|
+
}
|
|
140
|
+
|
|
82
141
|
const syncFnMaps = {
|
|
83
142
|
switchProfile: syncSwitchProfile,
|
|
84
143
|
connectAccount: syncConnectAccount,
|
|
144
|
+
pullAccount: pullUserAccount,
|
|
85
145
|
};
|
|
86
146
|
|
|
87
147
|
module.exports = {
|
|
@@ -186,6 +246,7 @@ module.exports = {
|
|
|
186
246
|
signer: permanentWallet.address,
|
|
187
247
|
data: signV2(permanentWallet.address, permanentWallet.secretKey, { sites: federated.sites }),
|
|
188
248
|
};
|
|
249
|
+
const limitSync = pLimit(FEDERATED.SYNC_LIMIT);
|
|
189
250
|
|
|
190
251
|
const waitingList = federated.sites
|
|
191
252
|
.filter((item) => item.appId !== federated.config.appId)
|
|
@@ -313,9 +374,15 @@ module.exports = {
|
|
|
313
374
|
const { verifySite } = req.body;
|
|
314
375
|
const teamDid = blocklet.appPid;
|
|
315
376
|
const { users = null, sites = null, userSessions = null } = req.body.verifyData;
|
|
377
|
+
const resultData = {
|
|
378
|
+
users: [],
|
|
379
|
+
sites: [],
|
|
380
|
+
userSessions: [],
|
|
381
|
+
};
|
|
316
382
|
|
|
317
383
|
// FIXME: @zhanghan 校验 users 和 sites 数据合法性
|
|
318
384
|
if (!isNil(sites)) {
|
|
385
|
+
const limitSync = pLimit(FEDERATED.SYNC_LIMIT);
|
|
319
386
|
const pendingSiteList = [];
|
|
320
387
|
const federated = cloneDeep(blocklet.settings.federated || {});
|
|
321
388
|
federated.sites = sites;
|
|
@@ -327,34 +394,39 @@ module.exports = {
|
|
|
327
394
|
});
|
|
328
395
|
})
|
|
329
396
|
);
|
|
330
|
-
await Promise.all(pendingSiteList);
|
|
397
|
+
const resList = await Promise.all(pendingSiteList);
|
|
398
|
+
resultData.sites = resList;
|
|
331
399
|
}
|
|
332
400
|
|
|
333
401
|
if (!isNil(users)) {
|
|
334
402
|
if (Array.isArray(users)) {
|
|
403
|
+
const limitSync = pLimit(FEDERATED.SYNC_LIMIT);
|
|
335
404
|
const pendingUserList = [];
|
|
336
405
|
const nodeInfo = await req.getNodeInfo();
|
|
337
406
|
const { dataDir } = await getApplicationInfo({ node, nodeInfo, teamDid });
|
|
338
407
|
for (const user of users) {
|
|
339
408
|
pendingUserList.push(
|
|
340
409
|
limitSync(async () => {
|
|
341
|
-
await syncFnMaps[user.action]?.(
|
|
410
|
+
const result = await syncFnMaps[user.action]?.(
|
|
342
411
|
{
|
|
343
412
|
...user,
|
|
344
413
|
sourceAppPid: user.sourceAppPid === teamDid ? null : user.sourceAppPid,
|
|
345
414
|
},
|
|
346
|
-
{ node, teamDid, dataDir }
|
|
415
|
+
{ node, teamDid, dataDir, blocklet }
|
|
347
416
|
);
|
|
417
|
+
return result;
|
|
348
418
|
})
|
|
349
419
|
);
|
|
350
420
|
}
|
|
351
|
-
await Promise.all(pendingUserList);
|
|
421
|
+
const resList = await Promise.all(pendingUserList);
|
|
422
|
+
resultData.users = resList;
|
|
352
423
|
}
|
|
353
424
|
}
|
|
354
425
|
|
|
355
426
|
if (!isNil(userSessions)) {
|
|
356
427
|
if (Array.isArray(userSessions)) {
|
|
357
428
|
const pendingUserSessionList = [];
|
|
429
|
+
const limitSync = pLimit(FEDERATED.SYNC_LIMIT);
|
|
358
430
|
for (const userSession of userSessions) {
|
|
359
431
|
const { action, ...userSessionItem } = userSession;
|
|
360
432
|
pendingUserSessionList.push(
|
|
@@ -367,7 +439,8 @@ module.exports = {
|
|
|
367
439
|
})
|
|
368
440
|
);
|
|
369
441
|
}
|
|
370
|
-
await Promise.all(pendingUserSessionList);
|
|
442
|
+
const resList = await Promise.all(pendingUserSessionList);
|
|
443
|
+
resultData.userSessions = resList;
|
|
371
444
|
}
|
|
372
445
|
}
|
|
373
446
|
|
|
@@ -381,10 +454,13 @@ module.exports = {
|
|
|
381
454
|
},
|
|
382
455
|
node
|
|
383
456
|
);
|
|
384
|
-
res.json(
|
|
457
|
+
res.json(resultData);
|
|
385
458
|
});
|
|
386
459
|
|
|
387
|
-
|
|
460
|
+
/**
|
|
461
|
+
* @deprecated
|
|
462
|
+
* step 4 检测自动登录条件(member 向 master 发起请求)
|
|
463
|
+
*/
|
|
388
464
|
server.post(
|
|
389
465
|
`${prefix}/prelogin`,
|
|
390
466
|
cors({ credentials: true, origin: true }),
|
|
@@ -425,7 +501,10 @@ module.exports = {
|
|
|
425
501
|
}
|
|
426
502
|
);
|
|
427
503
|
|
|
428
|
-
|
|
504
|
+
/**
|
|
505
|
+
* @deprecated
|
|
506
|
+
* step 5 完成 member 的自动登录(member 向 master 请求)
|
|
507
|
+
*/
|
|
429
508
|
server.post(
|
|
430
509
|
`${prefix}/login`,
|
|
431
510
|
cors({ credentials: true, origin: true }),
|
|
@@ -591,7 +670,10 @@ module.exports = {
|
|
|
591
670
|
res.json({ sessionToken, refreshToken });
|
|
592
671
|
});
|
|
593
672
|
|
|
594
|
-
|
|
673
|
+
/**
|
|
674
|
+
* @deprecated
|
|
675
|
+
* member 要求 master 退出登录
|
|
676
|
+
*/
|
|
595
677
|
server.post(
|
|
596
678
|
`${prefix}/logout`,
|
|
597
679
|
cors({ credentials: true, origin: true }),
|
|
@@ -698,11 +780,18 @@ module.exports = {
|
|
|
698
780
|
const teamDid = blocklet.appPid;
|
|
699
781
|
|
|
700
782
|
const sessionConfig = blocklet.settings?.session || {};
|
|
701
|
-
const prevUser = await
|
|
702
|
-
|
|
703
|
-
|
|
704
|
-
|
|
705
|
-
|
|
783
|
+
const prevUser = await getUserWithinFederated(
|
|
784
|
+
{
|
|
785
|
+
teamDid,
|
|
786
|
+
sourceAppPid: verifySite.appPid,
|
|
787
|
+
userDid: user.did,
|
|
788
|
+
userPk: user.pk,
|
|
789
|
+
},
|
|
790
|
+
{
|
|
791
|
+
node,
|
|
792
|
+
blocklet,
|
|
793
|
+
}
|
|
794
|
+
);
|
|
706
795
|
// HACK: member 调用 master 时,将 passport 的 role 还原为 master 中原有的 role
|
|
707
796
|
const targetPassport = passport?.id ? (prevUser?.passports || []).find((item) => item.id === passport.id) : null;
|
|
708
797
|
|
|
@@ -718,7 +807,6 @@ module.exports = {
|
|
|
718
807
|
}
|
|
719
808
|
const realDid = prevUser?.did || user.did;
|
|
720
809
|
const realPk = prevUser?.pk || user.pk;
|
|
721
|
-
// NOTICE: 这里是 Master 登录,不需要 sourceAppPid 字段
|
|
722
810
|
const newUser = await node.loginUser({
|
|
723
811
|
teamDid,
|
|
724
812
|
user: {
|
|
@@ -726,6 +814,7 @@ module.exports = {
|
|
|
726
814
|
did: realDid,
|
|
727
815
|
pk: realPk,
|
|
728
816
|
passport: targetPassport,
|
|
817
|
+
sourceAppPid: verifySite.appPid,
|
|
729
818
|
connectedAccount: {
|
|
730
819
|
provider: provider || LOGIN_PROVIDER.WALLET,
|
|
731
820
|
did: user.did,
|
package/api/routes/oauth.js
CHANGED
|
@@ -23,7 +23,12 @@ const initJwt = require('../libs/jwt');
|
|
|
23
23
|
const { sendToUser } = require('../libs/notification');
|
|
24
24
|
const { isInvitedUserOnly, createTokenFn, getDidConnectVersion } = require('../util');
|
|
25
25
|
const { ApiError } = require('../util/error');
|
|
26
|
-
const {
|
|
26
|
+
const {
|
|
27
|
+
getFederatedMaster,
|
|
28
|
+
getOAuthUserInfo,
|
|
29
|
+
shouldSyncFederated,
|
|
30
|
+
getUserWithinFederated,
|
|
31
|
+
} = require('../util/federated');
|
|
27
32
|
|
|
28
33
|
const PREFIX = WELLKNOWN_SERVICE_PATH_PREFIX;
|
|
29
34
|
|
|
@@ -99,15 +104,7 @@ async function login(req, node, options) {
|
|
|
99
104
|
|
|
100
105
|
const lastLoginIp = get(req, 'headers[x-real-ip]') || '';
|
|
101
106
|
let passport = { name: 'Guest', role: 'guest' };
|
|
102
|
-
let currentUser = await
|
|
103
|
-
teamDid,
|
|
104
|
-
user: {
|
|
105
|
-
did: userDid,
|
|
106
|
-
},
|
|
107
|
-
options: {
|
|
108
|
-
enableConnectedAccount: true,
|
|
109
|
-
},
|
|
110
|
-
});
|
|
107
|
+
let currentUser = await getUserWithinFederated({ sourceAppPid, teamDid, userDid, userPk }, { node, blocklet });
|
|
111
108
|
let doc;
|
|
112
109
|
let passportForLog;
|
|
113
110
|
const fullName = currentUser?.fullName || oauthInfo?.nickname;
|
|
@@ -117,6 +114,7 @@ async function login(req, node, options) {
|
|
|
117
114
|
pk: userPk,
|
|
118
115
|
id: oauthInfo.sub,
|
|
119
116
|
};
|
|
117
|
+
const masterSite = getFederatedMaster(blocklet);
|
|
120
118
|
let profile;
|
|
121
119
|
// 当前账户已存在,更新账户信息
|
|
122
120
|
if (currentUser) {
|
|
@@ -156,6 +154,7 @@ async function login(req, node, options) {
|
|
|
156
154
|
if (invitedUserOnly) {
|
|
157
155
|
throw new ApiError(403, t('needInviteToLogin', locale));
|
|
158
156
|
}
|
|
157
|
+
|
|
159
158
|
passportForLog = { name: 'Guest', role: 'guest' };
|
|
160
159
|
profile = {
|
|
161
160
|
fullName: oauthInfo.nickname,
|
|
@@ -186,7 +185,6 @@ async function login(req, node, options) {
|
|
|
186
185
|
node
|
|
187
186
|
);
|
|
188
187
|
|
|
189
|
-
const masterSite = getFederatedMaster(blocklet);
|
|
190
188
|
const ua = req.headers['user-agent'];
|
|
191
189
|
const userSessionDoc = await node.upsertUserSession({
|
|
192
190
|
teamDid,
|
|
@@ -279,15 +277,16 @@ async function invite(req, node, options) {
|
|
|
279
277
|
|
|
280
278
|
// NOTICE: 如果是统一登录,则向 master 站点发起 oauth 登录请求,auth0 的账户信息必须由 master 来生成
|
|
281
279
|
if (sourceAppPid) {
|
|
282
|
-
const data = await
|
|
280
|
+
const data = await getOAuthUserInfo({
|
|
283
281
|
request: req,
|
|
284
282
|
blocklet,
|
|
285
|
-
locale,
|
|
286
283
|
provider,
|
|
287
284
|
token,
|
|
288
285
|
sourceAppPid,
|
|
286
|
+
locale,
|
|
289
287
|
});
|
|
290
|
-
|
|
288
|
+
userWallet = data.wallet;
|
|
289
|
+
oauthInfo = data.info;
|
|
291
290
|
} else {
|
|
292
291
|
const authClient = getAuthClient(blocklet, provider);
|
|
293
292
|
oauthInfo = await authClient.getProfile(token);
|
|
@@ -299,15 +298,9 @@ async function invite(req, node, options) {
|
|
|
299
298
|
let userPk = userWallet.publicKey;
|
|
300
299
|
|
|
301
300
|
let profile;
|
|
302
|
-
|
|
303
|
-
|
|
304
|
-
|
|
305
|
-
did: userDid,
|
|
306
|
-
},
|
|
307
|
-
options: {
|
|
308
|
-
enableConnectedAccount: true,
|
|
309
|
-
},
|
|
310
|
-
});
|
|
301
|
+
|
|
302
|
+
const currentUser = await getUserWithinFederated({ sourceAppPid, teamDid, userDid, userPk }, { node, blocklet });
|
|
303
|
+
|
|
311
304
|
const { dataDir, name: applicationName } = await getApplicationInfo({ node, nodeInfo, teamDid });
|
|
312
305
|
if (currentUser) {
|
|
313
306
|
profile = {
|
|
@@ -340,8 +333,8 @@ async function invite(req, node, options) {
|
|
|
340
333
|
profile,
|
|
341
334
|
statusEndpointBaseUrl,
|
|
342
335
|
teamDid,
|
|
343
|
-
userDid,
|
|
344
|
-
userPk,
|
|
336
|
+
userDid: userWallet.address,
|
|
337
|
+
userPk: userWallet.publicKey,
|
|
345
338
|
locale,
|
|
346
339
|
provider,
|
|
347
340
|
});
|
|
@@ -506,7 +499,7 @@ async function bind(req, node, options) {
|
|
|
506
499
|
if (!avatar) {
|
|
507
500
|
const nodeInfo = await req.getNodeInfo();
|
|
508
501
|
const { dataDir } = await getApplicationInfo({ node, nodeInfo, teamDid });
|
|
509
|
-
avatar = await getAvatarByEmail(userInfo.email);
|
|
502
|
+
avatar = userInfo.picture ? await getAvatarByUrl(userInfo.picture) : await getAvatarByEmail(userInfo.email);
|
|
510
503
|
avatar = await extractUserAvatar(avatar, { dataDir });
|
|
511
504
|
}
|
|
512
505
|
|
|
@@ -7,6 +7,7 @@ const defaults = require('lodash/defaults');
|
|
|
7
7
|
const cloneDeep = require('lodash/cloneDeep');
|
|
8
8
|
const pLimit = require('p-limit');
|
|
9
9
|
const logger = require('@abtnode/logger')('blocklet-services:user-session');
|
|
10
|
+
const { getSourceProvider } = require('@blocklet/meta/lib/did-utils');
|
|
10
11
|
|
|
11
12
|
const ensureBlocklet = require('../middlewares/ensure-blocklet');
|
|
12
13
|
const { getUserAvatarUrl } = require('../util/federated');
|
|
@@ -103,6 +104,9 @@ module.exports = {
|
|
|
103
104
|
},
|
|
104
105
|
sites: [],
|
|
105
106
|
});
|
|
107
|
+
const sourceProvider = getSourceProvider(user);
|
|
108
|
+
|
|
109
|
+
const provider = sourceProvider || LOGIN_PROVIDER.WALLET;
|
|
106
110
|
|
|
107
111
|
const memberSite = federated.sites.find((item) => item.appPid === appPid);
|
|
108
112
|
const postUser = pick(user, ['did', 'pk', 'fullName', 'locale']);
|
|
@@ -121,7 +125,7 @@ module.exports = {
|
|
|
121
125
|
user: postUser,
|
|
122
126
|
passport: passportId ? { id: passportId } : undefined,
|
|
123
127
|
walletOS: 'web',
|
|
124
|
-
provider
|
|
128
|
+
provider,
|
|
125
129
|
},
|
|
126
130
|
site: memberSite,
|
|
127
131
|
});
|
package/api/routes/user.js
CHANGED
|
@@ -175,6 +175,7 @@ async function loginOAuth(
|
|
|
175
175
|
throw new ApiError(400, error.message);
|
|
176
176
|
}
|
|
177
177
|
|
|
178
|
+
// FIXME: @zhanghan 如果有 sourceAppPid,则这里拿到的 userWallet 是不对的?
|
|
178
179
|
const userWallet = fromAppDid(id, blockletWallet.secretKey);
|
|
179
180
|
const userDid = userWallet.address;
|
|
180
181
|
const userPk = userWallet.publicKey;
|
|
@@ -13,6 +13,7 @@ const { LOGIN_PROVIDER } = require('@blocklet/constant');
|
|
|
13
13
|
const logger = require('@abtnode/logger')(require('../../../../package.json').name);
|
|
14
14
|
|
|
15
15
|
const { createTokenFn, getDidConnectVersion } = require('../../../util');
|
|
16
|
+
const { getUserWithinFederated } = require('../../../util/federated');
|
|
16
17
|
|
|
17
18
|
module.exports = function createRoutes(node, authenticator, createSessionToken) {
|
|
18
19
|
return {
|
|
@@ -65,7 +66,9 @@ module.exports = function createRoutes(node, authenticator, createSessionToken)
|
|
|
65
66
|
const statusEndpointBaseUrl = joinUrl(baseUrl, WELLKNOWN_SERVICE_PATH_PREFIX);
|
|
66
67
|
const endpoint = baseUrl;
|
|
67
68
|
|
|
68
|
-
|
|
69
|
+
await getUserWithinFederated({ sourceAppPid, teamDid, userDid, userPk }, { node, blocklet });
|
|
70
|
+
|
|
71
|
+
const { passport, response, role, profile, user } = await handleInvitationResponse({
|
|
69
72
|
req,
|
|
70
73
|
node,
|
|
71
74
|
nodeInfo,
|
|
@@ -85,7 +88,7 @@ module.exports = function createRoutes(node, authenticator, createSessionToken)
|
|
|
85
88
|
const createToken = createTokenFn(createSessionToken);
|
|
86
89
|
const sessionConfig = blocklet.settings?.session || {};
|
|
87
90
|
const { sessionToken, refreshToken } = createToken(
|
|
88
|
-
|
|
91
|
+
user.did,
|
|
89
92
|
{
|
|
90
93
|
secret,
|
|
91
94
|
passport,
|
|
@@ -102,7 +105,7 @@ module.exports = function createRoutes(node, authenticator, createSessionToken)
|
|
|
102
105
|
const userSessionDoc = await node.upsertUserSession({
|
|
103
106
|
teamDid,
|
|
104
107
|
visitorId,
|
|
105
|
-
userDid,
|
|
108
|
+
userDid: user.did,
|
|
106
109
|
appPid: teamDid,
|
|
107
110
|
passportId: response.data.id,
|
|
108
111
|
status: 'online',
|
|
@@ -111,7 +114,7 @@ module.exports = function createRoutes(node, authenticator, createSessionToken)
|
|
|
111
114
|
});
|
|
112
115
|
node.syncUserSession({
|
|
113
116
|
teamDid,
|
|
114
|
-
userDid,
|
|
117
|
+
userDid: user.did,
|
|
115
118
|
visitorId: userSessionDoc.visitorId,
|
|
116
119
|
passportId: passport?.id,
|
|
117
120
|
targetAppPid: sourceAppPid,
|
|
@@ -127,7 +130,7 @@ module.exports = function createRoutes(node, authenticator, createSessionToken)
|
|
|
127
130
|
true
|
|
128
131
|
);
|
|
129
132
|
await updateSession({ passportId: response.data.id });
|
|
130
|
-
logger.info('invite.success', { userDid });
|
|
133
|
+
logger.info('invite.success', { userDid: user.did });
|
|
131
134
|
|
|
132
135
|
return response;
|
|
133
136
|
},
|
package/api/util/federated.js
CHANGED
|
@@ -115,6 +115,50 @@ function shouldSyncFederated(sourceAppPid, blocklet) {
|
|
|
115
115
|
return false;
|
|
116
116
|
}
|
|
117
117
|
|
|
118
|
+
async function getUserWithinFederated({ userDid, userPk, teamDid, sourceAppPid }, { node, blocklet }) {
|
|
119
|
+
let currentUser = await node.getUser({
|
|
120
|
+
teamDid,
|
|
121
|
+
user: {
|
|
122
|
+
did: userDid,
|
|
123
|
+
},
|
|
124
|
+
options: {
|
|
125
|
+
enableConnectedAccount: true,
|
|
126
|
+
},
|
|
127
|
+
});
|
|
128
|
+
if (!currentUser && shouldSyncFederated(sourceAppPid, blocklet)) {
|
|
129
|
+
const masterSite = getFederatedMaster(blocklet);
|
|
130
|
+
const syncResults = await node.syncFederated({
|
|
131
|
+
did: teamDid,
|
|
132
|
+
data: {
|
|
133
|
+
users: [
|
|
134
|
+
{
|
|
135
|
+
did: userDid,
|
|
136
|
+
pk: userPk,
|
|
137
|
+
action: 'pullAccount',
|
|
138
|
+
},
|
|
139
|
+
],
|
|
140
|
+
},
|
|
141
|
+
syncSites: [masterSite],
|
|
142
|
+
});
|
|
143
|
+
const resultItem = syncResults.find((x) => x.site.appPid === masterSite.appPid);
|
|
144
|
+
if (resultItem) {
|
|
145
|
+
const { result } = resultItem;
|
|
146
|
+
const [pullUser] = result?.users || [];
|
|
147
|
+
if (pullUser) {
|
|
148
|
+
pullUser.sourceAppPid = masterSite.appPid;
|
|
149
|
+
pullUser.connectedAccount = pullUser.connectedAccounts;
|
|
150
|
+
delete pullUser.connectedAccounts;
|
|
151
|
+
currentUser = await node.loginUser({
|
|
152
|
+
teamDid,
|
|
153
|
+
user: pullUser,
|
|
154
|
+
});
|
|
155
|
+
}
|
|
156
|
+
}
|
|
157
|
+
}
|
|
158
|
+
|
|
159
|
+
return currentUser;
|
|
160
|
+
}
|
|
161
|
+
|
|
118
162
|
module.exports = {
|
|
119
163
|
isMaster,
|
|
120
164
|
shouldSyncFederated,
|
|
@@ -124,4 +168,5 @@ module.exports = {
|
|
|
124
168
|
migrateAuth0,
|
|
125
169
|
getOAuthUserInfo,
|
|
126
170
|
loginByMember,
|
|
171
|
+
getUserWithinFederated,
|
|
127
172
|
};
|
package/api/validators/login.js
CHANGED
|
@@ -25,7 +25,7 @@ const loginUserWalletSchema = Joi.object({
|
|
|
25
25
|
nonce: Joi.string().required(),
|
|
26
26
|
visitorId: Joi.string().optional(),
|
|
27
27
|
passportId: Joi.string().optional(),
|
|
28
|
-
sourceAppPid: Joi.DID().trim().
|
|
28
|
+
sourceAppPid: Joi.DID().trim().empty(null),
|
|
29
29
|
locale: Joi.string().optional(),
|
|
30
30
|
}).empty(null);
|
|
31
31
|
|