@abtnode/blocklet-services 1.16.0-beta-1d6c582e → 1.16.0-beta-62b42401
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 +4 -2
- package/api/libs/auth/adapters/auth0/authentication-client.js +16 -0
- package/api/libs/auth/adapters/auth0/index.js +7 -0
- package/api/libs/auth/adapters/auth0/management-client.js +36 -0
- package/api/libs/auth/utils.js +90 -0
- package/api/libs/connect/session.js +197 -22
- package/api/libs/notification.js +19 -0
- package/api/routes/oauth.js +346 -0
- package/api/services/auth/connect/bind-wallet.js +56 -0
- package/api/services/auth/index.js +2 -0
- package/api/util/index.js +23 -1
- package/build/asset-manifest.json +15 -15
- package/build/index.html +1 -1
- package/build/static/css/{25.4c069dc5.chunk.css → 943.60476cc0.chunk.css} +1 -1
- package/build/static/js/343.d41f9df4.chunk.js +2 -0
- package/build/static/js/{573.6d8891e3.chunk.js → 573.2687bb44.chunk.js} +2 -2
- package/build/static/js/716.e1534c42.chunk.js +2 -0
- package/build/static/js/{868.43103624.chunk.js → 868.f2fac071.chunk.js} +2 -2
- package/build/static/js/943.eee42740.chunk.js +3 -0
- package/build/static/js/main.918ec6ce.js +3 -0
- package/package.json +31 -27
- package/build/static/js/25.e23e1873.chunk.js +0 -3
- package/build/static/js/343.b10f00a4.chunk.js +0 -2
- package/build/static/js/560.4d01281e.chunk.js +0 -2
- package/build/static/js/main.26769a99.js +0 -3
- /package/build/static/js/{25.e23e1873.chunk.js.LICENSE.txt → 943.eee42740.chunk.js.LICENSE.txt} +0 -0
- /package/build/static/js/{main.26769a99.js.LICENSE.txt → main.918ec6ce.js.LICENSE.txt} +0 -0
package/api/index.js
CHANGED
|
@@ -8,7 +8,7 @@ const compression = require('compression');
|
|
|
8
8
|
const cookieParser = require('cookie-parser');
|
|
9
9
|
const bodyParser = require('body-parser');
|
|
10
10
|
const httpProxy = require('http-proxy');
|
|
11
|
-
const
|
|
11
|
+
const dayjs = require('dayjs');
|
|
12
12
|
const minimatch = require('minimatch');
|
|
13
13
|
|
|
14
14
|
const { getAccessLogStream } = require('@abtnode/logger');
|
|
@@ -33,6 +33,7 @@ const { init: initDashboard } = require('./services/dashboard');
|
|
|
33
33
|
const StaticService = require('./services/static');
|
|
34
34
|
const StudioService = require('./services/studio');
|
|
35
35
|
const createEnvRoutes = require('./routes/env');
|
|
36
|
+
const createOAuthRoutes = require('./routes/oauth');
|
|
36
37
|
const createBlockletRoutes = require('./routes/blocklet');
|
|
37
38
|
const createConnectRelayRoutes = require('./routes/connect/relay');
|
|
38
39
|
const createConnectSessionRoutes = require('./routes/connect/session');
|
|
@@ -48,7 +49,7 @@ const logFileGenerator = (time, index) => {
|
|
|
48
49
|
return 'service.log';
|
|
49
50
|
}
|
|
50
51
|
|
|
51
|
-
let filename = `service-${
|
|
52
|
+
let filename = `service-${dayjs(time).subtract(1, 'day').format('YYYY-MM-DD')}`; // prev date
|
|
52
53
|
|
|
53
54
|
if (index > 1) {
|
|
54
55
|
filename = `${filename}-${index}`;
|
|
@@ -220,6 +221,7 @@ module.exports = function createServer(node, serverOptions = {}) {
|
|
|
220
221
|
server.use(authMiddlewares.userInfo);
|
|
221
222
|
|
|
222
223
|
// API: auth
|
|
224
|
+
createOAuthRoutes.init(server, node, options);
|
|
223
225
|
createEnvRoutes.init(server, node, options);
|
|
224
226
|
createBlockletRoutes.init(server, node);
|
|
225
227
|
createConnectSessionRoutes.init(server, node, options);
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
const { AuthenticationClient: Auth0AuthenticationClient } = require('auth0');
|
|
2
|
+
|
|
3
|
+
class AuthenticationClient {
|
|
4
|
+
constructor(options) {
|
|
5
|
+
this.instance = new Auth0AuthenticationClient({
|
|
6
|
+
domain: options.domain,
|
|
7
|
+
clientId: options.clientId,
|
|
8
|
+
});
|
|
9
|
+
}
|
|
10
|
+
|
|
11
|
+
getProfile(...args) {
|
|
12
|
+
return this.instance.getProfile(...args);
|
|
13
|
+
}
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
module.exports = AuthenticationClient;
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
const { ManagementClient: Auth0ManagementClient } = require('auth0');
|
|
2
|
+
|
|
3
|
+
class ManagementClient {
|
|
4
|
+
constructor(options) {
|
|
5
|
+
this.config = {
|
|
6
|
+
domain: options.domain,
|
|
7
|
+
token: options.token,
|
|
8
|
+
};
|
|
9
|
+
this.instance = new Auth0ManagementClient({
|
|
10
|
+
domain: options.domain,
|
|
11
|
+
token: options.token,
|
|
12
|
+
});
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
async getClient(...args) {
|
|
16
|
+
return this.instance.getClient(...args);
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
getClients(...args) {
|
|
20
|
+
return this.instance.getClients(...args);
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
createClient(...args) {
|
|
24
|
+
return this.instance.createClient(...args);
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
updateClient(...args) {
|
|
28
|
+
return this.instance.updateClient(...args);
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
deleteClient(...args) {
|
|
32
|
+
return this.instance.deleteClient(...args);
|
|
33
|
+
}
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
module.exports = ManagementClient;
|
|
@@ -0,0 +1,90 @@
|
|
|
1
|
+
const md5 = require('md5');
|
|
2
|
+
const axios = require('axios');
|
|
3
|
+
const logger = require('@abtnode/auth/lib/logger');
|
|
4
|
+
const { getPassportStatusEndpoint, getApplicationInfo } = require('@abtnode/auth/lib/auth');
|
|
5
|
+
const { createPassportVC } = require('@abtnode/auth/lib/passport');
|
|
6
|
+
const { VC_TYPE_NODE_PASSPORT } = require('@abtnode/constant');
|
|
7
|
+
const { parseUserAvatar } = require('@abtnode/util/lib/user-avatar');
|
|
8
|
+
const pick = require('lodash/pick');
|
|
9
|
+
|
|
10
|
+
const { sendToUser } = require('../notification');
|
|
11
|
+
|
|
12
|
+
function getEmailHash(email = '') {
|
|
13
|
+
const cleanEmail = email.trim().toLowerCase();
|
|
14
|
+
return md5(cleanEmail);
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
async function getAvatarByEmail(email = '') {
|
|
18
|
+
try {
|
|
19
|
+
const emailHash = getEmailHash(email);
|
|
20
|
+
const gravatarUrl = `https://www.gravatar.com/avatar/${emailHash}`;
|
|
21
|
+
const { data } = await axios.get(gravatarUrl, {
|
|
22
|
+
responseType: 'arraybuffer',
|
|
23
|
+
});
|
|
24
|
+
const base64Content = Buffer.from(data, 'binary').toString('base64');
|
|
25
|
+
|
|
26
|
+
return `data:image/png;base64,${base64Content}`;
|
|
27
|
+
} catch {
|
|
28
|
+
logger.error(`Fetch gravatar failed: ${email}`);
|
|
29
|
+
return null;
|
|
30
|
+
}
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
async function transferPassport(fromUser, toUser, { req, teamDid, node, nodeInfo }) {
|
|
34
|
+
const {
|
|
35
|
+
name: issuerName,
|
|
36
|
+
wallet: issuerWallet,
|
|
37
|
+
passportColor,
|
|
38
|
+
dataDir,
|
|
39
|
+
} = await getApplicationInfo({ node, nodeInfo, teamDid });
|
|
40
|
+
|
|
41
|
+
const waitPassportList = fromUser.passports || [];
|
|
42
|
+
const attachments = await Promise.all(
|
|
43
|
+
waitPassportList.map(async (item) => {
|
|
44
|
+
const avatar = await parseUserAvatar(toUser.avatar, { dataDir });
|
|
45
|
+
const vcParams = {
|
|
46
|
+
issuerName,
|
|
47
|
+
issuerWallet,
|
|
48
|
+
ownerDid: toUser.did,
|
|
49
|
+
passport: pick(item, ['name', 'title', 'endpoint', 'specVersion']),
|
|
50
|
+
endpoint: getPassportStatusEndpoint({
|
|
51
|
+
baseUrl: item.endpoint,
|
|
52
|
+
userDid: toUser.did,
|
|
53
|
+
teamDid,
|
|
54
|
+
}),
|
|
55
|
+
types: teamDid === nodeInfo.did ? [VC_TYPE_NODE_PASSPORT] : [],
|
|
56
|
+
ownerProfile: {
|
|
57
|
+
email: toUser.email,
|
|
58
|
+
fullName: toUser.fullName,
|
|
59
|
+
avatar,
|
|
60
|
+
},
|
|
61
|
+
preferredColor: passportColor,
|
|
62
|
+
};
|
|
63
|
+
|
|
64
|
+
const vc = createPassportVC(vcParams);
|
|
65
|
+
return {
|
|
66
|
+
type: 'vc',
|
|
67
|
+
data: {
|
|
68
|
+
credential: vc,
|
|
69
|
+
tag: item.name,
|
|
70
|
+
},
|
|
71
|
+
};
|
|
72
|
+
})
|
|
73
|
+
);
|
|
74
|
+
|
|
75
|
+
await sendToUser(
|
|
76
|
+
toUser.did,
|
|
77
|
+
{
|
|
78
|
+
title: 'Transfer passports',
|
|
79
|
+
body: `Transfer ${fromUser.did}'s passports to ${toUser.did}`,
|
|
80
|
+
attachments,
|
|
81
|
+
},
|
|
82
|
+
{ req }
|
|
83
|
+
);
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
module.exports = {
|
|
87
|
+
getEmailHash,
|
|
88
|
+
getAvatarByEmail,
|
|
89
|
+
transferPassport,
|
|
90
|
+
};
|
|
@@ -9,6 +9,7 @@ const {
|
|
|
9
9
|
getVCFromClaims,
|
|
10
10
|
validatePassportStatus,
|
|
11
11
|
getPassportStatusEndpoint,
|
|
12
|
+
getApplicationInfo,
|
|
12
13
|
} = require('@abtnode/auth/lib/auth');
|
|
13
14
|
const {
|
|
14
15
|
NODE_SERVICES,
|
|
@@ -18,6 +19,7 @@ const {
|
|
|
18
19
|
VC_TYPE_NODE_PASSPORT,
|
|
19
20
|
WHO_CAN_ACCESS,
|
|
20
21
|
WHO_CAN_ACCESS_PREFIX_ROLES,
|
|
22
|
+
USER_TYPE,
|
|
21
23
|
} = require('@abtnode/constant');
|
|
22
24
|
const {
|
|
23
25
|
validatePassport,
|
|
@@ -30,33 +32,17 @@ const {
|
|
|
30
32
|
upsertToPassports,
|
|
31
33
|
} = require('@abtnode/auth/lib/passport');
|
|
32
34
|
const { getKeyPairClaim } = require('@abtnode/auth/lib/server');
|
|
35
|
+
const sortBy = require('lodash/sortBy');
|
|
36
|
+
const head = require('lodash/head');
|
|
33
37
|
|
|
34
38
|
const { getRolesFromAuthConfig, getBlockletAppIdList } = require('@blocklet/meta/lib/util');
|
|
35
39
|
|
|
36
40
|
const logger = require('@abtnode/logger')(require('../../../package.json').name);
|
|
37
41
|
|
|
38
|
-
const
|
|
39
|
-
|
|
40
|
-
/**
|
|
41
|
-
* @returns {Array} config
|
|
42
|
-
* @returns {Boolean} config[0] is invited user only
|
|
43
|
-
* @returns {String} config[1] default role
|
|
44
|
-
* @returns {Boolean} config[2] issue passport
|
|
45
|
-
*/
|
|
46
|
-
const isInvitedUserOnly = async (config, node, teamDid) => {
|
|
47
|
-
const count = await node.getUsersCount({ teamDid });
|
|
48
|
-
|
|
49
|
-
// issue owner passport for first login user
|
|
50
|
-
if (count === 0) {
|
|
51
|
-
return [false, ROLES.OWNER, true];
|
|
52
|
-
}
|
|
42
|
+
const { isInvitedUserOnly } = require('../../util');
|
|
43
|
+
const { transferPassport } = require('../auth/utils');
|
|
53
44
|
|
|
54
|
-
|
|
55
|
-
return [true];
|
|
56
|
-
}
|
|
57
|
-
|
|
58
|
-
return [false, ROLES.GUEST];
|
|
59
|
-
};
|
|
45
|
+
const vcTypes = [VC_TYPE_GENERAL_PASSPORT, VC_TYPE_NODE_PASSPORT];
|
|
60
46
|
|
|
61
47
|
const getPassportVc = async ({ blocklet, claims, challenge, locale }) => {
|
|
62
48
|
const trustedPassports = (blocklet.trustedPassports || []).map((x) => x.issuerDid);
|
|
@@ -256,7 +242,10 @@ module.exports = {
|
|
|
256
242
|
did: userDid,
|
|
257
243
|
pk: userPk,
|
|
258
244
|
locale,
|
|
259
|
-
passports: upsertToPassports(
|
|
245
|
+
passports: upsertToPassports(
|
|
246
|
+
user.passports || [],
|
|
247
|
+
passport && { ...passport, lastLoginAt: new Date().toISOString() }
|
|
248
|
+
).filter(Boolean),
|
|
260
249
|
lastLoginAt: new Date().toISOString(),
|
|
261
250
|
lastLoginIp: get(request, 'headers[x-real-ip]') || '',
|
|
262
251
|
},
|
|
@@ -490,6 +479,17 @@ module.exports = {
|
|
|
490
479
|
// Recreate passport with correct role
|
|
491
480
|
passport = vc ? createUserPassport(vc, { role }) : null;
|
|
492
481
|
|
|
482
|
+
await node.updateUser({
|
|
483
|
+
teamDid,
|
|
484
|
+
user: {
|
|
485
|
+
did: user.did,
|
|
486
|
+
passports: upsertToPassports(
|
|
487
|
+
user.passports || [],
|
|
488
|
+
passport && { ...passport, lastLoginAt: new Date().toISOString() }
|
|
489
|
+
),
|
|
490
|
+
},
|
|
491
|
+
});
|
|
492
|
+
|
|
493
493
|
// Audit log
|
|
494
494
|
const passportForLog = passport || { name: 'Guest', role: 'guest' };
|
|
495
495
|
await node.createAuditLog(
|
|
@@ -508,6 +508,181 @@ module.exports = {
|
|
|
508
508
|
},
|
|
509
509
|
},
|
|
510
510
|
|
|
511
|
+
// 基本流程与 login 一致,但在创建更新用户信息的逻辑不一样
|
|
512
|
+
bindWallet: {
|
|
513
|
+
onConnect: async ({ node, request, userDid, locale, passportId = '', componentId, previousUserDid }) => {
|
|
514
|
+
const translations = {
|
|
515
|
+
en: {
|
|
516
|
+
notFound: "Can't get bind account infomation",
|
|
517
|
+
notDerivedAccount: "Current account is not a derived account, can't bind a DID Wallet account",
|
|
518
|
+
notWalletAccount: "Bind account is a derived account, can't bind",
|
|
519
|
+
alreadyBind: 'Bind account already bind with another account',
|
|
520
|
+
},
|
|
521
|
+
zh: {
|
|
522
|
+
notFound: '获取绑定账户信息失败',
|
|
523
|
+
notDerivedAccount: '当前账户不是一个派生账号,无法绑定 DID Wallet 账户',
|
|
524
|
+
notWalletAccount: '绑定的账户是一个派生账号,无法绑定',
|
|
525
|
+
alreadyBind: '该账户已绑定 OAuth 账户',
|
|
526
|
+
},
|
|
527
|
+
};
|
|
528
|
+
const blocklet = await request.getBlocklet();
|
|
529
|
+
const config = await request.getServiceConfig(NODE_SERVICES.AUTH, { componentId });
|
|
530
|
+
const { did: teamDid } = await request.getBlockletInfo();
|
|
531
|
+
const oauthUser = await getUser(node, teamDid, previousUserDid);
|
|
532
|
+
const bindUser = await node.getUser({ teamDid: blocklet.meta.did, user: { did: userDid } });
|
|
533
|
+
|
|
534
|
+
if (!oauthUser) {
|
|
535
|
+
throw new Error(translations[locale].notFound);
|
|
536
|
+
}
|
|
537
|
+
if (oauthUser.source !== USER_TYPE.DERIVED) {
|
|
538
|
+
throw new Error(translations[locale].notDerivedAccount);
|
|
539
|
+
}
|
|
540
|
+
if (bindUser) {
|
|
541
|
+
if (bindUser.source === USER_TYPE.DERIVED) {
|
|
542
|
+
throw new Error(translations[locale].notWalletAccount);
|
|
543
|
+
}
|
|
544
|
+
if (bindUser.derivedAccount) {
|
|
545
|
+
throw new Error(translations[locale].alreadyBind);
|
|
546
|
+
}
|
|
547
|
+
}
|
|
548
|
+
|
|
549
|
+
const profileFields = get(config, 'profileFields');
|
|
550
|
+
const claims = {
|
|
551
|
+
profile: {
|
|
552
|
+
type: 'profile',
|
|
553
|
+
description: messages.description[locale],
|
|
554
|
+
items: profileFields || ['fullName', 'avatar'],
|
|
555
|
+
},
|
|
556
|
+
};
|
|
557
|
+
|
|
558
|
+
// 至少需要一个 claim
|
|
559
|
+
// if (oauthUser.avatar) {
|
|
560
|
+
// delete claims.profile;
|
|
561
|
+
// }
|
|
562
|
+
|
|
563
|
+
if (passportId) {
|
|
564
|
+
claims.verifiableCredential.target = passportId;
|
|
565
|
+
}
|
|
566
|
+
|
|
567
|
+
return claims;
|
|
568
|
+
},
|
|
569
|
+
onApprove: async ({ node, request, locale, userDid, userPk, claims, createSessionToken, previousUserDid }) => {
|
|
570
|
+
const { did: teamDid } = await request.getBlockletInfo();
|
|
571
|
+
|
|
572
|
+
const oauthUser = await getUser(node, teamDid, previousUserDid);
|
|
573
|
+
const nodeInfo = await request.getNodeInfo();
|
|
574
|
+
// Check user approved
|
|
575
|
+
let bindUser = await getUser(node, teamDid, userDid);
|
|
576
|
+
if (bindUser && !bindUser.approved) {
|
|
577
|
+
throw new Error(messages.notAllowed[locale]);
|
|
578
|
+
}
|
|
579
|
+
|
|
580
|
+
const { dataDir } = await getApplicationInfo({ node, nodeInfo, teamDid });
|
|
581
|
+
|
|
582
|
+
const profileold = claims.find((x) => x.type === 'profile') || { avatar: null };
|
|
583
|
+
const avatar = await extractUserAvatar(oauthUser.avatar || profileold.avatar, { dataDir });
|
|
584
|
+
const profile = {
|
|
585
|
+
fullName: oauthUser.fullName,
|
|
586
|
+
avatar,
|
|
587
|
+
email: oauthUser.email,
|
|
588
|
+
};
|
|
589
|
+
|
|
590
|
+
// TODO: 获取当前登录使用的 passport(无法获取到 passport.id)
|
|
591
|
+
// 使用最近一次使用的 passport 来代替
|
|
592
|
+
const validPassports = oauthUser.passports.filter((item) => item.status === 'valid');
|
|
593
|
+
const lastUsedPassport = head(sortBy(validPassports, 'lastLoginAt'));
|
|
594
|
+
const passport = lastUsedPassport || { name: 'Guest', role: 'guest' };
|
|
595
|
+
if (bindUser) {
|
|
596
|
+
const mergePassport = (oauthUser.passports || []).reduce((sum, cur) => {
|
|
597
|
+
return upsertToPassports(sum, cur);
|
|
598
|
+
}, bindUser.passports || []);
|
|
599
|
+
// Update bindUser account
|
|
600
|
+
await node.updateUser({
|
|
601
|
+
teamDid,
|
|
602
|
+
user: {
|
|
603
|
+
derivedAccount: {
|
|
604
|
+
provider: oauthUser.sourceProvider,
|
|
605
|
+
did: oauthUser.did,
|
|
606
|
+
pk: oauthUser.pk,
|
|
607
|
+
},
|
|
608
|
+
connectedAccounts: [
|
|
609
|
+
{
|
|
610
|
+
provider: oauthUser.sourceProvider,
|
|
611
|
+
id: oauthUser.sourceId,
|
|
612
|
+
lastLoginAt: oauthUser.lastLoginAt,
|
|
613
|
+
},
|
|
614
|
+
],
|
|
615
|
+
did: userDid,
|
|
616
|
+
pk: userPk,
|
|
617
|
+
locale,
|
|
618
|
+
passports: mergePassport,
|
|
619
|
+
lastLoginAt: new Date().toISOString(),
|
|
620
|
+
lastLoginIp: get(request, 'headers[x-real-ip]') || '',
|
|
621
|
+
},
|
|
622
|
+
});
|
|
623
|
+
// FIXME: @zhanghan 将来是否需要移除 derived account
|
|
624
|
+
// await node.removeUser({
|
|
625
|
+
// teamDid,
|
|
626
|
+
// user: {
|
|
627
|
+
// did: previousUserDid,
|
|
628
|
+
// },
|
|
629
|
+
// });
|
|
630
|
+
// TODO: @zhanghan 需要增加 auditLog
|
|
631
|
+
} else {
|
|
632
|
+
const doc = await node.addUser({
|
|
633
|
+
teamDid,
|
|
634
|
+
user: {
|
|
635
|
+
...profile,
|
|
636
|
+
source: USER_TYPE.WALLET,
|
|
637
|
+
derivedAccount: {
|
|
638
|
+
provider: oauthUser.sourceProvider,
|
|
639
|
+
did: oauthUser.did,
|
|
640
|
+
pk: oauthUser.pk,
|
|
641
|
+
},
|
|
642
|
+
connectedAccounts: [
|
|
643
|
+
{
|
|
644
|
+
provider: oauthUser.sourceProvider,
|
|
645
|
+
id: oauthUser.sourceId,
|
|
646
|
+
lastLoginAt: oauthUser.lastLoginAt,
|
|
647
|
+
},
|
|
648
|
+
],
|
|
649
|
+
avatar,
|
|
650
|
+
did: userDid,
|
|
651
|
+
pk: userPk,
|
|
652
|
+
approved: true,
|
|
653
|
+
locale,
|
|
654
|
+
passports: oauthUser.passports,
|
|
655
|
+
firstLoginAt: new Date().toISOString(),
|
|
656
|
+
lastLoginAt: new Date().toISOString(),
|
|
657
|
+
lastLoginIp: get(request, 'headers[x-real-ip]') || '',
|
|
658
|
+
},
|
|
659
|
+
});
|
|
660
|
+
bindUser = doc;
|
|
661
|
+
// remove derived account (updateUser use did as key, so did can't be update)
|
|
662
|
+
await node.removeUser({
|
|
663
|
+
teamDid,
|
|
664
|
+
user: {
|
|
665
|
+
did: previousUserDid,
|
|
666
|
+
},
|
|
667
|
+
});
|
|
668
|
+
// TODO: @zhanghan 需要增加 auditLog
|
|
669
|
+
}
|
|
670
|
+
|
|
671
|
+
await transferPassport(oauthUser, bindUser, { req: request, node, nodeInfo, teamDid });
|
|
672
|
+
|
|
673
|
+
// Generate new session token that client can save to localStorage
|
|
674
|
+
const sessionToken = await createSessionToken(userDid, { passport, role: passport.role });
|
|
675
|
+
logger.info('login.success', { userDid, role: passport.role });
|
|
676
|
+
|
|
677
|
+
return {
|
|
678
|
+
sessionToken,
|
|
679
|
+
nextWorkflowData: {
|
|
680
|
+
userDid,
|
|
681
|
+
},
|
|
682
|
+
};
|
|
683
|
+
},
|
|
684
|
+
},
|
|
685
|
+
|
|
511
686
|
migrateToStructV2: {
|
|
512
687
|
getClaims: ({ node }) => ({
|
|
513
688
|
verifiableCredential: async ({ extraParams: { locale }, context: { request } }) => {
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
const Notification = require('@blocklet/sdk/lib/util/send-notification');
|
|
2
|
+
|
|
3
|
+
async function sendToUser(userDid, notification, { req }) {
|
|
4
|
+
const { wallet } = await req.getBlockletInfo();
|
|
5
|
+
const notificationRes = await Notification.sendToUser(
|
|
6
|
+
userDid,
|
|
7
|
+
notification,
|
|
8
|
+
{
|
|
9
|
+
appDid: wallet.address,
|
|
10
|
+
appSk: wallet.secretKey,
|
|
11
|
+
},
|
|
12
|
+
process.env.ABT_NODE_SERVICE_PORT
|
|
13
|
+
);
|
|
14
|
+
return notificationRes;
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
module.exports = {
|
|
18
|
+
sendToUser,
|
|
19
|
+
};
|