@abtnode/blocklet-services 1.16.52-beta-20250922-225859-f34775fa → 1.16.52-beta-20250924-093428-bd3f0d8c
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/middlewares/launcher-login.js +104 -89
- package/api/routes/user.js +31 -0
- package/package.json +23 -23
package/api/index.js
CHANGED
|
@@ -88,7 +88,7 @@ const createOpenComponentRoutes = require('./routes/opencomponent');
|
|
|
88
88
|
const createOpenEmbedRoutes = require('./routes/openembed');
|
|
89
89
|
const createAccessKeyRoutes = require('./routes/access-key');
|
|
90
90
|
const checkRunning = require('./middlewares/check-running');
|
|
91
|
-
const launcherLogin = require('./middlewares/launcher-login');
|
|
91
|
+
const { launcherLogin } = require('./middlewares/launcher-login');
|
|
92
92
|
const { checkMemberPermission, checkGuestPermission } = require('./middlewares/check-permission');
|
|
93
93
|
const ensureBlocklet = require('./middlewares/ensure-blocklet');
|
|
94
94
|
const proxyToDaemon = require('./middlewares/proxy-to-daemon');
|
|
@@ -9,6 +9,94 @@ const { createTokenFn } = require('../util');
|
|
|
9
9
|
const initJwt = require('../libs/jwt');
|
|
10
10
|
const logger = require('../libs/logger')('blocklet-services:launcher-login');
|
|
11
11
|
|
|
12
|
+
const doLauncherLogin = async (req, token, blocklet, node, options) => {
|
|
13
|
+
const decoded = JWT.decode(token);
|
|
14
|
+
const info = await req.getNodeInfo();
|
|
15
|
+
|
|
16
|
+
const isSameLauncher = isSameDid(decoded.iss, info.registerInfo?.appId);
|
|
17
|
+
const isSameOwner = isSameDid(decoded.oid, blocklet.settings?.owner?.did);
|
|
18
|
+
const isSameLauncherSessionId = decoded.lid === blocklet.controller.launcherSessionId;
|
|
19
|
+
const isSameBlocklet = [blocklet.appDid, blocklet.appPid].includes(decoded.aid);
|
|
20
|
+
|
|
21
|
+
logger.debug('Launcher login check', {
|
|
22
|
+
isSameLauncher,
|
|
23
|
+
isSameOwner,
|
|
24
|
+
isSameLauncherSessionId,
|
|
25
|
+
isSameBlocklet,
|
|
26
|
+
decoded,
|
|
27
|
+
owner: blocklet.settings?.owner,
|
|
28
|
+
launcher: info.registerInfo,
|
|
29
|
+
controller: blocklet.controller,
|
|
30
|
+
appDids: [blocklet.appDid, blocklet.appPid],
|
|
31
|
+
});
|
|
32
|
+
|
|
33
|
+
if (isSameLauncher && isSameOwner && isSameLauncherSessionId && isSameBlocklet) {
|
|
34
|
+
const verified = await JWT.verify(token, info.registerInfo?.appPk);
|
|
35
|
+
if (verified) {
|
|
36
|
+
const user = await node.getUser({
|
|
37
|
+
teamDid: blocklet.appPid,
|
|
38
|
+
user: { did: decoded.oid },
|
|
39
|
+
options: { enableConnectedAccount: true },
|
|
40
|
+
});
|
|
41
|
+
if (user?.approved) {
|
|
42
|
+
const { secret } = await req.getBlockletInfo();
|
|
43
|
+
const { createSessionToken } = initJwt(node, options);
|
|
44
|
+
const createToken = createTokenFn(createSessionToken);
|
|
45
|
+
const { sessionToken, refreshToken } = createToken(
|
|
46
|
+
user.did,
|
|
47
|
+
{
|
|
48
|
+
secret,
|
|
49
|
+
role: 'owner',
|
|
50
|
+
fullName: user.fullName,
|
|
51
|
+
provider: user.sourceProvider,
|
|
52
|
+
walletOS: user.walletOS,
|
|
53
|
+
emailVerified: !!user?.emailVerified,
|
|
54
|
+
phoneVerified: !!user?.phoneVerified,
|
|
55
|
+
elevated: true,
|
|
56
|
+
},
|
|
57
|
+
blocklet.settings?.session || {}
|
|
58
|
+
);
|
|
59
|
+
|
|
60
|
+
const visitorId = decoded.vid || req.cookies?.vid || generateId();
|
|
61
|
+
|
|
62
|
+
logger.info('done auto login for launcher user', {
|
|
63
|
+
appPid: blocklet.appPid,
|
|
64
|
+
userDid: user.did,
|
|
65
|
+
visitorId,
|
|
66
|
+
});
|
|
67
|
+
|
|
68
|
+
await node.upsertUserSession({
|
|
69
|
+
teamDid: blocklet.appPid,
|
|
70
|
+
userDid: user.did,
|
|
71
|
+
visitorId,
|
|
72
|
+
appPid: blocklet.appPid,
|
|
73
|
+
passportId: null,
|
|
74
|
+
status: 'online',
|
|
75
|
+
ua: req.get('user-agent'),
|
|
76
|
+
lastLoginIp: getRequestIP(req),
|
|
77
|
+
extra: {
|
|
78
|
+
walletOS: user.walletOS,
|
|
79
|
+
device: getDeviceData({ req }),
|
|
80
|
+
},
|
|
81
|
+
locale: req.blockletLocale,
|
|
82
|
+
origin: await getOrigin({ req }),
|
|
83
|
+
});
|
|
84
|
+
|
|
85
|
+
return {
|
|
86
|
+
sessionToken,
|
|
87
|
+
refreshToken,
|
|
88
|
+
visitorId,
|
|
89
|
+
};
|
|
90
|
+
}
|
|
91
|
+
logger.warn('Launcher login failed, user is revoked', { userDid: user?.did });
|
|
92
|
+
} else {
|
|
93
|
+
logger.warn('Launcher login failed, token is invalid', { token, verified });
|
|
94
|
+
}
|
|
95
|
+
}
|
|
96
|
+
|
|
97
|
+
return null;
|
|
98
|
+
};
|
|
99
|
+
|
|
12
100
|
// auto login from authenticated launcher users: will skip if user is already logged in
|
|
13
101
|
const launcherLogin = (node, options) => async (req, res, next) => {
|
|
14
102
|
if (!req.query.__lt) {
|
|
@@ -27,94 +115,18 @@ const launcherLogin = (node, options) => async (req, res, next) => {
|
|
|
27
115
|
|
|
28
116
|
try {
|
|
29
117
|
const token = req.query.__lt;
|
|
30
|
-
const
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
isSameBlocklet,
|
|
43
|
-
decoded,
|
|
44
|
-
owner: blocklet.settings?.owner,
|
|
45
|
-
launcher: info.registerInfo,
|
|
46
|
-
controller: blocklet.controller,
|
|
47
|
-
appDids: [blocklet.appDid, blocklet.appPid],
|
|
48
|
-
});
|
|
49
|
-
|
|
50
|
-
if (isSameLauncher && isSameOwner && isSameLauncherSessionId && isSameBlocklet) {
|
|
51
|
-
const verified = await JWT.verify(token, info.registerInfo?.appPk);
|
|
52
|
-
if (verified) {
|
|
53
|
-
const user = await node.getUser({
|
|
54
|
-
teamDid: blocklet.appPid,
|
|
55
|
-
user: { did: decoded.oid },
|
|
56
|
-
options: { enableConnectedAccount: true },
|
|
57
|
-
});
|
|
58
|
-
if (user?.approved) {
|
|
59
|
-
const { secret } = await req.getBlockletInfo();
|
|
60
|
-
const { createSessionToken } = initJwt(node, options);
|
|
61
|
-
const createToken = createTokenFn(createSessionToken);
|
|
62
|
-
const result = createToken(
|
|
63
|
-
user.did,
|
|
64
|
-
{
|
|
65
|
-
secret,
|
|
66
|
-
role: 'owner',
|
|
67
|
-
fullName: user.fullName,
|
|
68
|
-
provider: user.sourceProvider,
|
|
69
|
-
walletOS: user.walletOS,
|
|
70
|
-
emailVerified: !!user?.emailVerified,
|
|
71
|
-
phoneVerified: !!user?.phoneVerified,
|
|
72
|
-
elevated: true,
|
|
73
|
-
},
|
|
74
|
-
blocklet.settings?.session || {}
|
|
75
|
-
);
|
|
76
|
-
|
|
77
|
-
const visitorId = decoded.vid || req.cookies?.vid || generateId();
|
|
78
|
-
|
|
79
|
-
logger.info('done auto login for launcher user', {
|
|
80
|
-
appPid: blocklet.appPid,
|
|
81
|
-
userDid: user.did,
|
|
82
|
-
visitorId,
|
|
83
|
-
});
|
|
84
|
-
|
|
85
|
-
await node.upsertUserSession({
|
|
86
|
-
teamDid: blocklet.appPid,
|
|
87
|
-
userDid: user.did,
|
|
88
|
-
visitorId,
|
|
89
|
-
appPid: blocklet.appPid,
|
|
90
|
-
passportId: null,
|
|
91
|
-
status: 'online',
|
|
92
|
-
ua: req.get('user-agent'),
|
|
93
|
-
lastLoginIp: getRequestIP(req),
|
|
94
|
-
extra: {
|
|
95
|
-
walletOS: user.walletOS,
|
|
96
|
-
device: getDeviceData({ req }),
|
|
97
|
-
},
|
|
98
|
-
locale: req.blockletLocale,
|
|
99
|
-
origin: await getOrigin({ req }),
|
|
100
|
-
});
|
|
101
|
-
|
|
102
|
-
res.cookie('login_token', result.sessionToken, {
|
|
103
|
-
maxAge: 24 * 60 * 60 * 1000,
|
|
104
|
-
secure: true,
|
|
105
|
-
sameSite: 'lax',
|
|
106
|
-
});
|
|
107
|
-
res.cookie('vid', visitorId, {
|
|
108
|
-
maxAge: 365 * 24 * 60 * 60 * 1000,
|
|
109
|
-
secure: true,
|
|
110
|
-
sameSite: 'lax',
|
|
111
|
-
});
|
|
112
|
-
} else {
|
|
113
|
-
logger.warn('Launcher login failed, user is revoked', { userDid: user?.did });
|
|
114
|
-
}
|
|
115
|
-
} else {
|
|
116
|
-
logger.warn('Launcher login failed, token is invalid', { token, verified });
|
|
117
|
-
}
|
|
118
|
+
const result = await doLauncherLogin(req, token, blocklet, node, options);
|
|
119
|
+
if (result) {
|
|
120
|
+
res.cookie('login_token', result.sessionToken, {
|
|
121
|
+
maxAge: 24 * 60 * 60 * 1000,
|
|
122
|
+
secure: true,
|
|
123
|
+
sameSite: 'lax',
|
|
124
|
+
});
|
|
125
|
+
res.cookie('vid', result.visitorId, {
|
|
126
|
+
maxAge: 365 * 24 * 60 * 60 * 1000,
|
|
127
|
+
secure: true,
|
|
128
|
+
sameSite: 'lax',
|
|
129
|
+
});
|
|
118
130
|
}
|
|
119
131
|
} catch (err) {
|
|
120
132
|
logger.error('Failed to attach launcher token', { error: err });
|
|
@@ -123,4 +135,7 @@ const launcherLogin = (node, options) => async (req, res, next) => {
|
|
|
123
135
|
return next();
|
|
124
136
|
};
|
|
125
137
|
|
|
126
|
-
module.exports =
|
|
138
|
+
module.exports = {
|
|
139
|
+
launcherLogin,
|
|
140
|
+
doLauncherLogin,
|
|
141
|
+
};
|
package/api/routes/user.js
CHANGED
|
@@ -51,6 +51,7 @@ const { sendToUser } = require('../libs/notification');
|
|
|
51
51
|
const { createEmailLimiter } = require('../services/kyc');
|
|
52
52
|
const cache = require('../cache');
|
|
53
53
|
const { ensureUserExists, ensureUserEnabled, t } = require('../util/check-user');
|
|
54
|
+
const { doLauncherLogin } = require('../middlewares/launcher-login');
|
|
54
55
|
|
|
55
56
|
const validateUser = (user) => {
|
|
56
57
|
try {
|
|
@@ -870,6 +871,36 @@ module.exports = {
|
|
|
870
871
|
});
|
|
871
872
|
});
|
|
872
873
|
|
|
874
|
+
// Used by ArcSphere to login by launcher token
|
|
875
|
+
server.post(`${prefixApi}/loginByLauncher`, async (req, res) => {
|
|
876
|
+
const { token } = req.body;
|
|
877
|
+
if (!token) {
|
|
878
|
+
throw new CustomError(400, 'Launcher token is required');
|
|
879
|
+
}
|
|
880
|
+
|
|
881
|
+
const blocklet = await req.getBlocklet();
|
|
882
|
+
if (!blocklet.controller) {
|
|
883
|
+
logger.debug('Launcher login is not supported for this blocklet', { blockletDid: blocklet.appDid });
|
|
884
|
+
throw new CustomError(400, 'Launcher login is not supported for this blocklet');
|
|
885
|
+
}
|
|
886
|
+
|
|
887
|
+
try {
|
|
888
|
+
const result = await doLauncherLogin(req, token, blocklet, node, options);
|
|
889
|
+
if (result) {
|
|
890
|
+
res.json({
|
|
891
|
+
sessionToken: result.sessionToken,
|
|
892
|
+
refreshToken: result.refreshToken,
|
|
893
|
+
visitorId: result.visitorId,
|
|
894
|
+
});
|
|
895
|
+
} else {
|
|
896
|
+
throw new CustomError(400, 'Failed to login by launcher: not matched');
|
|
897
|
+
}
|
|
898
|
+
} catch (err) {
|
|
899
|
+
logger.error('Failed to login by launcher', { error: err });
|
|
900
|
+
throw new CustomError(500, 'Failed to login by launcher: internal error');
|
|
901
|
+
}
|
|
902
|
+
});
|
|
903
|
+
|
|
873
904
|
server.post(`${prefixApi}/checkUser`, async (req, res) => {
|
|
874
905
|
const { users = [], sourceAppPid } = req.body;
|
|
875
906
|
const { error } = checkUserSchema.validate({
|
package/package.json
CHANGED
|
@@ -3,7 +3,7 @@
|
|
|
3
3
|
"publishConfig": {
|
|
4
4
|
"access": "public"
|
|
5
5
|
},
|
|
6
|
-
"version": "1.16.52-beta-
|
|
6
|
+
"version": "1.16.52-beta-20250924-093428-bd3f0d8c",
|
|
7
7
|
"description": "Provide unified services for every blocklet",
|
|
8
8
|
"main": "api/index.js",
|
|
9
9
|
"files": [
|
|
@@ -34,17 +34,17 @@
|
|
|
34
34
|
"author": "wangshijun <wangshijun2010@gmail.com> (http://github.com/wangshijun)",
|
|
35
35
|
"license": "Apache-2.0",
|
|
36
36
|
"dependencies": {
|
|
37
|
-
"@abtnode/analytics": "1.16.52-beta-
|
|
38
|
-
"@abtnode/auth": "1.16.52-beta-
|
|
39
|
-
"@abtnode/connect-storage": "1.16.52-beta-
|
|
40
|
-
"@abtnode/constant": "1.16.52-beta-
|
|
41
|
-
"@abtnode/core": "1.16.52-beta-
|
|
42
|
-
"@abtnode/cron": "1.16.52-beta-
|
|
43
|
-
"@abtnode/db-cache": "1.16.52-beta-
|
|
44
|
-
"@abtnode/logger": "1.16.52-beta-
|
|
45
|
-
"@abtnode/models": "1.16.52-beta-
|
|
46
|
-
"@abtnode/router-templates": "1.16.52-beta-
|
|
47
|
-
"@abtnode/util": "1.16.52-beta-
|
|
37
|
+
"@abtnode/analytics": "1.16.52-beta-20250924-093428-bd3f0d8c",
|
|
38
|
+
"@abtnode/auth": "1.16.52-beta-20250924-093428-bd3f0d8c",
|
|
39
|
+
"@abtnode/connect-storage": "1.16.52-beta-20250924-093428-bd3f0d8c",
|
|
40
|
+
"@abtnode/constant": "1.16.52-beta-20250924-093428-bd3f0d8c",
|
|
41
|
+
"@abtnode/core": "1.16.52-beta-20250924-093428-bd3f0d8c",
|
|
42
|
+
"@abtnode/cron": "1.16.52-beta-20250924-093428-bd3f0d8c",
|
|
43
|
+
"@abtnode/db-cache": "1.16.52-beta-20250924-093428-bd3f0d8c",
|
|
44
|
+
"@abtnode/logger": "1.16.52-beta-20250924-093428-bd3f0d8c",
|
|
45
|
+
"@abtnode/models": "1.16.52-beta-20250924-093428-bd3f0d8c",
|
|
46
|
+
"@abtnode/router-templates": "1.16.52-beta-20250924-093428-bd3f0d8c",
|
|
47
|
+
"@abtnode/util": "1.16.52-beta-20250924-093428-bd3f0d8c",
|
|
48
48
|
"@arcblock/did": "1.24.0",
|
|
49
49
|
"@arcblock/did-connect-js": "1.24.0",
|
|
50
50
|
"@arcblock/did-ext": "1.24.0",
|
|
@@ -54,18 +54,18 @@
|
|
|
54
54
|
"@arcblock/jwt": "1.24.0",
|
|
55
55
|
"@arcblock/validator": "1.24.0",
|
|
56
56
|
"@arcblock/ws": "1.24.0",
|
|
57
|
-
"@blocklet/constant": "1.16.52-beta-
|
|
57
|
+
"@blocklet/constant": "1.16.52-beta-20250924-093428-bd3f0d8c",
|
|
58
58
|
"@blocklet/dbhub": "^0.2.9",
|
|
59
|
-
"@blocklet/env": "1.16.52-beta-
|
|
59
|
+
"@blocklet/env": "1.16.52-beta-20250924-093428-bd3f0d8c",
|
|
60
60
|
"@blocklet/error": "^0.2.5",
|
|
61
61
|
"@blocklet/form-builder": "^0.1.12",
|
|
62
62
|
"@blocklet/form-collector": "^0.1.8",
|
|
63
|
-
"@blocklet/images": "1.16.52-beta-
|
|
64
|
-
"@blocklet/js-sdk": "1.16.52-beta-
|
|
65
|
-
"@blocklet/meta": "1.16.52-beta-
|
|
66
|
-
"@blocklet/rate-limit": "1.16.52-beta-
|
|
67
|
-
"@blocklet/sdk": "1.16.52-beta-
|
|
68
|
-
"@blocklet/server-js": "1.16.52-beta-
|
|
63
|
+
"@blocklet/images": "1.16.52-beta-20250924-093428-bd3f0d8c",
|
|
64
|
+
"@blocklet/js-sdk": "1.16.52-beta-20250924-093428-bd3f0d8c",
|
|
65
|
+
"@blocklet/meta": "1.16.52-beta-20250924-093428-bd3f0d8c",
|
|
66
|
+
"@blocklet/rate-limit": "1.16.52-beta-20250924-093428-bd3f0d8c",
|
|
67
|
+
"@blocklet/sdk": "1.16.52-beta-20250924-093428-bd3f0d8c",
|
|
68
|
+
"@blocklet/server-js": "1.16.52-beta-20250924-093428-bd3f0d8c",
|
|
69
69
|
"@blocklet/theme": "^3.1.41",
|
|
70
70
|
"@blocklet/theme-builder": "0.4.6",
|
|
71
71
|
"@blocklet/uploader-server": "^0.2.11",
|
|
@@ -125,7 +125,7 @@
|
|
|
125
125
|
"whatwg-url": "14.0.0"
|
|
126
126
|
},
|
|
127
127
|
"devDependencies": {
|
|
128
|
-
"@abtnode/ux": "1.16.52-beta-
|
|
128
|
+
"@abtnode/ux": "1.16.52-beta-20250924-093428-bd3f0d8c",
|
|
129
129
|
"@arcblock/bridge": "^3.1.41",
|
|
130
130
|
"@arcblock/did-connect-react": "^3.1.41",
|
|
131
131
|
"@arcblock/icons": "^3.1.41",
|
|
@@ -135,7 +135,7 @@
|
|
|
135
135
|
"@blocklet/did-space-react": "^1.1.24",
|
|
136
136
|
"@blocklet/launcher-layout": "^3.1.41",
|
|
137
137
|
"@blocklet/payment-react": "^1.20.11",
|
|
138
|
-
"@blocklet/tracker": "1.16.52-beta-
|
|
138
|
+
"@blocklet/tracker": "1.16.52-beta-20250924-093428-bd3f0d8c",
|
|
139
139
|
"@blocklet/ui-react": "^3.1.41",
|
|
140
140
|
"@blocklet/uploader": "^0.2.11",
|
|
141
141
|
"@emotion/react": "^11.14.0",
|
|
@@ -215,5 +215,5 @@
|
|
|
215
215
|
"url": "https://github.com/ArcBlock/blocklet-server/issues",
|
|
216
216
|
"email": "shijun@arcblock.io"
|
|
217
217
|
},
|
|
218
|
-
"gitHead": "
|
|
218
|
+
"gitHead": "208aa87c8e036c9ff5d40e7f6d7a5e24bcc57833"
|
|
219
219
|
}
|