@abtnode/auth 1.16.42 → 1.16.43-beta-20250419-231352-c78ac93d
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/lib/lost-passport.js +3 -0
- package/lib/oauth.js +17 -11
- package/lib/passkey.js +88 -19
- package/lib/server.js +2 -0
- package/package.json +18 -18
package/lib/lost-passport.js
CHANGED
|
@@ -9,6 +9,7 @@ const formatContext = require('@abtnode/util/lib/format-context');
|
|
|
9
9
|
const getRandomMessage = require('@abtnode/util/lib/get-random-message');
|
|
10
10
|
const getNodeWallet = require('@abtnode/util/lib/get-app-wallet');
|
|
11
11
|
const CustomError = require('@abtnode/util/lib/custom-error');
|
|
12
|
+
const getOrigin = require('@abtnode/util/lib/get-origin');
|
|
12
13
|
const { getActivePassports } = require('@abtnode/util/lib/passport');
|
|
13
14
|
const { getDisplayName, getBlockletAppIdList } = require('@blocklet/meta/lib/util');
|
|
14
15
|
const {
|
|
@@ -433,6 +434,8 @@ const createLostPassportIssueRoute = ({ node, type, authServicePrefix, createTok
|
|
|
433
434
|
walletOS,
|
|
434
435
|
device: deviceData,
|
|
435
436
|
},
|
|
437
|
+
locale,
|
|
438
|
+
origin: await getOrigin({ req }),
|
|
436
439
|
});
|
|
437
440
|
|
|
438
441
|
if (shouldSyncFederated(sourceAppPid, blocklet)) {
|
package/lib/oauth.js
CHANGED
|
@@ -6,6 +6,7 @@ const { ROLES } = require('@abtnode/constant');
|
|
|
6
6
|
const formatContext = require('@abtnode/util/lib/format-context');
|
|
7
7
|
const { getBlockletAppIdList } = require('@blocklet/meta/lib/util');
|
|
8
8
|
const { LOGIN_PROVIDER } = require('@blocklet/constant');
|
|
9
|
+
const getOrigin = require('@abtnode/util/lib/get-origin');
|
|
9
10
|
|
|
10
11
|
const { getApplicationInfo } = require('./auth');
|
|
11
12
|
|
|
@@ -79,8 +80,9 @@ function createPassportSwitcher(node, createToken, mode = 'server') {
|
|
|
79
80
|
|
|
80
81
|
const { passportId } = req.body;
|
|
81
82
|
const userDid = req.user.did;
|
|
82
|
-
const
|
|
83
|
-
const
|
|
83
|
+
const isServer = mode === 'server';
|
|
84
|
+
const teamDid = isServer ? info.did : req.getBlockletDid();
|
|
85
|
+
const secret = isServer ? await node.getSessionSecret() : (await req.getBlockletInfo()).secret;
|
|
84
86
|
|
|
85
87
|
// NOTICE: 这里获取的 did 是当前登录用户的永久 did,无需查询 connectedAccount
|
|
86
88
|
const user = await node.getUser({ teamDid, user: { did: userDid } });
|
|
@@ -91,15 +93,19 @@ function createPassportSwitcher(node, createToken, mode = 'server') {
|
|
|
91
93
|
? passports.find((item) => item.id === passportId)
|
|
92
94
|
: { name: 'Guest', role: 'guest', scope: 'passport' };
|
|
93
95
|
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
96
|
+
if (!isServer) {
|
|
97
|
+
// 需要更新用户会话中记录的 passportId
|
|
98
|
+
await node.upsertUserSession({
|
|
99
|
+
teamDid,
|
|
100
|
+
userDid: user.did,
|
|
101
|
+
visitorId,
|
|
102
|
+
appPid: teamDid,
|
|
103
|
+
passportId: passport?.id ?? null,
|
|
104
|
+
status: 'online',
|
|
105
|
+
locale: req.blockletLocale,
|
|
106
|
+
origin: await getOrigin({ req }),
|
|
107
|
+
});
|
|
108
|
+
}
|
|
103
109
|
|
|
104
110
|
await node.createAuditLog(
|
|
105
111
|
{
|
package/lib/passkey.js
CHANGED
|
@@ -17,11 +17,13 @@ const {
|
|
|
17
17
|
verifyRegistrationResponse,
|
|
18
18
|
} = require('@simplewebauthn/server');
|
|
19
19
|
const { updateConnectedAccount, getAvatarByEmail, extractUserAvatar } = require('@abtnode/util/lib/user');
|
|
20
|
+
const getOrigin = require('@abtnode/util/lib/get-origin');
|
|
20
21
|
|
|
21
22
|
const { getApplicationInfo, handleInvitationReceive, canSessionBeElevated } = require('./auth');
|
|
22
23
|
const { validateVerifyDestroyRequest } = require('./server');
|
|
23
24
|
const { getLastUsedPassport } = require('./passport');
|
|
24
25
|
const { getSessionConfig, checkInvitedUserOnly } = require('./oauth');
|
|
26
|
+
const { findFederatedSite, getUserAvatarUrl } = require('./util/federated');
|
|
25
27
|
|
|
26
28
|
const PASSKEY_TIMEOUT = 60000;
|
|
27
29
|
const PASSKEY_ACTIONS = {
|
|
@@ -43,7 +45,7 @@ const shouldVerifyUser = (action) =>
|
|
|
43
45
|
|
|
44
46
|
const isRegisterAction = (action) => ['register', 'connect-owner'].includes(action);
|
|
45
47
|
|
|
46
|
-
const
|
|
48
|
+
const getDomain = (req) => req.get('host').split(':')[0];
|
|
47
49
|
const emailSchema = Joi.string().email().required();
|
|
48
50
|
const tryDecodeEmail = (encoded) => {
|
|
49
51
|
try {
|
|
@@ -78,6 +80,16 @@ const formatBuffersToBase64 = (obj) => {
|
|
|
78
80
|
return obj;
|
|
79
81
|
};
|
|
80
82
|
|
|
83
|
+
const getTrustOrigins = ({ blocklet, req }) => {
|
|
84
|
+
const result = [`https://${getDomain(req)}`];
|
|
85
|
+
if (blocklet) {
|
|
86
|
+
const trustOrigins = blocklet.configObj?.TRUST_ORIGINS;
|
|
87
|
+
if (trustOrigins) result.push(...trustOrigins.split(','));
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
return result;
|
|
91
|
+
};
|
|
92
|
+
|
|
81
93
|
function createPasskeyHandlers(node, mode, createToken) {
|
|
82
94
|
const ensurePasskeySession = async (req, res, next) => {
|
|
83
95
|
const { challenge } = req.query;
|
|
@@ -204,7 +216,7 @@ function createPasskeyHandlers(node, mode, createToken) {
|
|
|
204
216
|
data: {
|
|
205
217
|
...req.query,
|
|
206
218
|
user: user?.did,
|
|
207
|
-
origin:
|
|
219
|
+
origin: getDomain(req),
|
|
208
220
|
email,
|
|
209
221
|
userName,
|
|
210
222
|
},
|
|
@@ -225,7 +237,7 @@ function createPasskeyHandlers(node, mode, createToken) {
|
|
|
225
237
|
});
|
|
226
238
|
|
|
227
239
|
const options = {
|
|
228
|
-
rpID:
|
|
240
|
+
rpID: getDomain(req),
|
|
229
241
|
rpName: info.name,
|
|
230
242
|
userID: toBuffer(userID),
|
|
231
243
|
userName,
|
|
@@ -275,8 +287,8 @@ function createPasskeyHandlers(node, mode, createToken) {
|
|
|
275
287
|
const { verified, registrationInfo } = await verifyRegistrationResponse({
|
|
276
288
|
response: body,
|
|
277
289
|
expectedChallenge: toBase64(req.passkeySession.challenge),
|
|
278
|
-
expectedOrigin:
|
|
279
|
-
expectedRPID:
|
|
290
|
+
expectedOrigin: getTrustOrigins({ blocklet: req.blocklet, req }),
|
|
291
|
+
expectedRPID: getDomain(req),
|
|
280
292
|
requireUserVerification: shouldVerifyUser(action),
|
|
281
293
|
});
|
|
282
294
|
logger.info('passkey.register.verified', { teamDid, verified, registrationInfo });
|
|
@@ -445,7 +457,7 @@ function createPasskeyHandlers(node, mode, createToken) {
|
|
|
445
457
|
data: {
|
|
446
458
|
...req.query,
|
|
447
459
|
user: req.userExpanded?.did,
|
|
448
|
-
origin:
|
|
460
|
+
origin: getDomain(req),
|
|
449
461
|
},
|
|
450
462
|
},
|
|
451
463
|
});
|
|
@@ -464,7 +476,7 @@ function createPasskeyHandlers(node, mode, createToken) {
|
|
|
464
476
|
req.userExpanded = await node.getUser({ teamDid, user: { did: exist.userDid } });
|
|
465
477
|
}
|
|
466
478
|
|
|
467
|
-
const expectedRPID =
|
|
479
|
+
const expectedRPID = getDomain(req);
|
|
468
480
|
let allowedCredentials = [];
|
|
469
481
|
if (req.query.credentialId) {
|
|
470
482
|
allowedCredentials = (req.userExpanded?.connectedAccounts || [])
|
|
@@ -522,8 +534,8 @@ function createPasskeyHandlers(node, mode, createToken) {
|
|
|
522
534
|
const verification = await verifyAuthenticationResponse({
|
|
523
535
|
response: body,
|
|
524
536
|
expectedChallenge: toBase64(passkeySession.challenge),
|
|
525
|
-
expectedOrigin:
|
|
526
|
-
expectedRPID:
|
|
537
|
+
expectedOrigin: getTrustOrigins({ blocklet: req.blocklet, req }),
|
|
538
|
+
expectedRPID: getDomain(req),
|
|
527
539
|
credential: {
|
|
528
540
|
id: passkey.id,
|
|
529
541
|
publicKey: fromBase64(passkey.pk),
|
|
@@ -537,20 +549,40 @@ function createPasskeyHandlers(node, mode, createToken) {
|
|
|
537
549
|
}
|
|
538
550
|
logger.info('passkey.auth.verified', { verified, authenticationInfo });
|
|
539
551
|
|
|
540
|
-
const createUserSession = () =>
|
|
541
|
-
|
|
552
|
+
const createUserSession = async ({ targetAppPid } = {}) => {
|
|
553
|
+
const ua = req.get('user-agent');
|
|
554
|
+
const lastLoginIp = getRequestIP(req);
|
|
555
|
+
const userSessionDoc = await node.upsertUserSession({
|
|
542
556
|
teamDid,
|
|
543
557
|
userDid: user.did,
|
|
544
558
|
visitorId: req.get('x-blocklet-visitor-id'),
|
|
545
559
|
appPid: teamDid,
|
|
546
560
|
passportId: null,
|
|
547
561
|
status: 'online',
|
|
548
|
-
ua
|
|
562
|
+
ua,
|
|
549
563
|
lastLoginIp: getRequestIP(req),
|
|
550
564
|
extra: {
|
|
551
565
|
walletOS: 'passkey',
|
|
552
566
|
},
|
|
567
|
+
locale: getLocale(req),
|
|
568
|
+
origin: await getOrigin({ req }),
|
|
553
569
|
});
|
|
570
|
+
if (targetAppPid) {
|
|
571
|
+
node.syncUserSession({
|
|
572
|
+
teamDid,
|
|
573
|
+
userDid: userSessionDoc.userDid,
|
|
574
|
+
visitorId: userSessionDoc.visitorId,
|
|
575
|
+
passportId: null,
|
|
576
|
+
targetAppPid,
|
|
577
|
+
ua,
|
|
578
|
+
lastLoginIp,
|
|
579
|
+
extra: {
|
|
580
|
+
walletOS: 'passkey',
|
|
581
|
+
},
|
|
582
|
+
});
|
|
583
|
+
}
|
|
584
|
+
return userSessionDoc;
|
|
585
|
+
};
|
|
554
586
|
|
|
555
587
|
const createTokens = async (updated, passport, role, profile, result) => {
|
|
556
588
|
const { secret } = await getApplicationInfo({ node, nodeInfo: info, teamDid });
|
|
@@ -581,8 +613,8 @@ function createPasskeyHandlers(node, mode, createToken) {
|
|
|
581
613
|
return result;
|
|
582
614
|
};
|
|
583
615
|
|
|
584
|
-
const loginUser = () =>
|
|
585
|
-
node.loginUser({
|
|
616
|
+
const loginUser = async () => {
|
|
617
|
+
const _result = await node.loginUser({
|
|
586
618
|
teamDid,
|
|
587
619
|
user: {
|
|
588
620
|
did: user.did,
|
|
@@ -593,6 +625,8 @@ function createPasskeyHandlers(node, mode, createToken) {
|
|
|
593
625
|
},
|
|
594
626
|
},
|
|
595
627
|
});
|
|
628
|
+
return _result;
|
|
629
|
+
};
|
|
596
630
|
|
|
597
631
|
const result = { verified, userDid: user.did };
|
|
598
632
|
|
|
@@ -604,10 +638,45 @@ function createPasskeyHandlers(node, mode, createToken) {
|
|
|
604
638
|
PASSKEY_ACTIONS['connect-to-did-domain'],
|
|
605
639
|
].includes(passkeySession.data.action)
|
|
606
640
|
) {
|
|
607
|
-
const
|
|
608
|
-
|
|
609
|
-
|
|
610
|
-
|
|
641
|
+
const { targetAppPid } = req.query;
|
|
642
|
+
// FIXME: @zhanghan 这里目前只是一个 hack 的方式,passkey 和 federated 结合的流程需要重新梳理优化
|
|
643
|
+
const isFederatedHack = targetAppPid && targetAppPid !== teamDid;
|
|
644
|
+
if (mode === 'service' && isFederatedHack) {
|
|
645
|
+
const findMemberSite = findFederatedSite(req.blocklet, targetAppPid);
|
|
646
|
+
if (findMemberSite) {
|
|
647
|
+
const postUser = pick(user, ['did', 'pk', 'fullName', 'locale', 'inviter', 'generation']);
|
|
648
|
+
postUser.lastLoginAt = getRequestIP(req);
|
|
649
|
+
|
|
650
|
+
if (user.email) {
|
|
651
|
+
postUser.email = user.email;
|
|
652
|
+
}
|
|
653
|
+
if (user.avatar) {
|
|
654
|
+
postUser.avatar = getUserAvatarUrl(user.avatar, req.blocklet);
|
|
655
|
+
}
|
|
656
|
+
// 这里是为了在 member 上创建用户
|
|
657
|
+
const _result = await node.loginFederated({
|
|
658
|
+
did: teamDid,
|
|
659
|
+
data: {
|
|
660
|
+
user: postUser,
|
|
661
|
+
walletOS: 'passkey',
|
|
662
|
+
provider: LOGIN_PROVIDER.PASSKEY,
|
|
663
|
+
},
|
|
664
|
+
site: findMemberSite,
|
|
665
|
+
});
|
|
666
|
+
result.sessionToken = _result.sessionToken;
|
|
667
|
+
result.refreshToken = _result.refreshToken;
|
|
668
|
+
|
|
669
|
+
const session = await createUserSession({ targetAppPid });
|
|
670
|
+
result.visitorId = session.visitorId;
|
|
671
|
+
} else {
|
|
672
|
+
throw new Error('Target site not found');
|
|
673
|
+
}
|
|
674
|
+
} else {
|
|
675
|
+
const updated = await loginUser();
|
|
676
|
+
const passport = getLastUsedPassport(updated.passports);
|
|
677
|
+
await createTokens(updated, passport, passport.role, user, result);
|
|
678
|
+
logger.info('passkey.auth.loggedIn', { teamDid, userDid: user.did, passport });
|
|
679
|
+
}
|
|
611
680
|
}
|
|
612
681
|
|
|
613
682
|
if (passkeySession.data.action === 'disconnect') {
|
|
@@ -764,6 +833,6 @@ function createPasskeyHandlers(node, mode, createToken) {
|
|
|
764
833
|
module.exports = {
|
|
765
834
|
createPasskeyHandlers,
|
|
766
835
|
getSessionConfig,
|
|
767
|
-
|
|
836
|
+
getDomain,
|
|
768
837
|
formatBuffersToBase64,
|
|
769
838
|
};
|
package/lib/server.js
CHANGED
|
@@ -41,6 +41,7 @@ const {
|
|
|
41
41
|
} = require('@abtnode/constant');
|
|
42
42
|
const parseBooleanString = require('@abtnode/util/lib/parse-boolean-string');
|
|
43
43
|
const { getDeviceData } = require('@abtnode/util/lib/device');
|
|
44
|
+
const getOrigin = require('@abtnode/util/lib/get-origin');
|
|
44
45
|
|
|
45
46
|
const {
|
|
46
47
|
messages,
|
|
@@ -862,6 +863,7 @@ const createLaunchBlockletHandler =
|
|
|
862
863
|
walletOS: didwallet?.os,
|
|
863
864
|
userDid,
|
|
864
865
|
device: context ? deviceData : null,
|
|
866
|
+
origin: await getOrigin({ req }),
|
|
865
867
|
},
|
|
866
868
|
});
|
|
867
869
|
await updateSession({ setupToken: result.setupToken, visitorId: result.visitorId });
|
package/package.json
CHANGED
|
@@ -3,7 +3,7 @@
|
|
|
3
3
|
"publishConfig": {
|
|
4
4
|
"access": "public"
|
|
5
5
|
},
|
|
6
|
-
"version": "1.16.
|
|
6
|
+
"version": "1.16.43-beta-20250419-231352-c78ac93d",
|
|
7
7
|
"description": "Simple lib to manage auth in ABT Node",
|
|
8
8
|
"main": "lib/index.js",
|
|
9
9
|
"files": [
|
|
@@ -20,22 +20,22 @@
|
|
|
20
20
|
"author": "linchen <linchen1987@foxmail.com> (http://github.com/linchen1987)",
|
|
21
21
|
"license": "Apache-2.0",
|
|
22
22
|
"dependencies": {
|
|
23
|
-
"@abtnode/constant": "1.16.
|
|
24
|
-
"@abtnode/logger": "1.16.
|
|
25
|
-
"@abtnode/util": "1.16.
|
|
26
|
-
"@arcblock/did": "1.20.
|
|
27
|
-
"@arcblock/did-auth": "1.20.
|
|
28
|
-
"@arcblock/jwt": "^1.20.
|
|
29
|
-
"@arcblock/nft-display": "^2.13.
|
|
30
|
-
"@arcblock/validator": "^1.20.
|
|
31
|
-
"@arcblock/vc": "1.20.
|
|
32
|
-
"@blocklet/constant": "1.16.
|
|
33
|
-
"@blocklet/meta": "1.16.
|
|
34
|
-
"@blocklet/sdk": "1.16.
|
|
35
|
-
"@ocap/client": "^1.20.
|
|
36
|
-
"@ocap/mcrypto": "1.20.
|
|
37
|
-
"@ocap/util": "1.20.
|
|
38
|
-
"@ocap/wallet": "1.20.
|
|
23
|
+
"@abtnode/constant": "1.16.43-beta-20250419-231352-c78ac93d",
|
|
24
|
+
"@abtnode/logger": "1.16.43-beta-20250419-231352-c78ac93d",
|
|
25
|
+
"@abtnode/util": "1.16.43-beta-20250419-231352-c78ac93d",
|
|
26
|
+
"@arcblock/did": "1.20.1",
|
|
27
|
+
"@arcblock/did-auth": "1.20.1",
|
|
28
|
+
"@arcblock/jwt": "^1.20.1",
|
|
29
|
+
"@arcblock/nft-display": "^2.13.7",
|
|
30
|
+
"@arcblock/validator": "^1.20.1",
|
|
31
|
+
"@arcblock/vc": "1.20.1",
|
|
32
|
+
"@blocklet/constant": "1.16.43-beta-20250419-231352-c78ac93d",
|
|
33
|
+
"@blocklet/meta": "1.16.43-beta-20250419-231352-c78ac93d",
|
|
34
|
+
"@blocklet/sdk": "1.16.43-beta-20250419-231352-c78ac93d",
|
|
35
|
+
"@ocap/client": "^1.20.1",
|
|
36
|
+
"@ocap/mcrypto": "1.20.1",
|
|
37
|
+
"@ocap/util": "1.20.1",
|
|
38
|
+
"@ocap/wallet": "1.20.1",
|
|
39
39
|
"@simplewebauthn/server": "^13.0.0",
|
|
40
40
|
"axios": "^1.7.9",
|
|
41
41
|
"flat": "^5.0.2",
|
|
@@ -52,5 +52,5 @@
|
|
|
52
52
|
"devDependencies": {
|
|
53
53
|
"jest": "^29.7.0"
|
|
54
54
|
},
|
|
55
|
-
"gitHead": "
|
|
55
|
+
"gitHead": "207acad34e8ccf318cd7539c1ac717cee7951b53"
|
|
56
56
|
}
|