@abtnode/blocklet-services 1.6.27 → 1.6.28
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/README.md +1 -5
- package/{lib → api}/cache.js +0 -0
- package/api/index.js +296 -0
- package/{services/auth → api}/libs/auth.js +24 -8
- package/api/libs/env.js +7 -0
- package/{services/auth → api}/libs/jwt.js +1 -0
- package/api/middlewares/check-admin-permission.js +15 -0
- package/api/middlewares/check-running.js +46 -0
- package/api/routes/blocklet.js +98 -0
- package/api/routes/env.js +27 -0
- package/{services/auth/routes → api/services/auth/connect}/invite.js +5 -4
- package/{services/auth/routes → api/services/auth/connect}/issue-passport.js +6 -2
- package/{services/auth/routes → api/services/auth/connect}/login.js +18 -10
- package/api/services/auth/connect/lost-passport-issue.js +10 -0
- package/{services/auth/routes → api/services/auth/connect}/lost-passport-list.js +1 -1
- package/api/services/auth/index.js +189 -0
- package/api/services/auth/passport.js +22 -0
- package/api/services/auth/session.js +31 -0
- package/{services/auth/routes/notification.js → api/services/notification/index.js} +25 -9
- package/api/services/static.js +76 -0
- package/{services/auth → api}/state/index.js +0 -0
- package/{services/auth → api}/state/message.js +0 -0
- package/api/util/attach-shared-utils.js +149 -0
- package/api/util/constants.js +10 -0
- package/api/util/format-context.js +24 -0
- package/{services/auth → api}/util/index.js +31 -1
- package/build/asset-manifest.json +32 -30
- package/build/index.html +1 -1
- package/build/precache-manifest.8fa5bc7546805566144fcf8af71f0904.js +154 -0
- package/build/service-worker.js +2 -2
- package/build/static/css/2.d49e994f.chunk.css +2 -0
- package/build/static/css/{2.cc9dc85c.chunk.css.map → 2.d49e994f.chunk.css.map} +1 -1
- package/build/static/js/2.1421337b.chunk.js +3 -0
- package/build/static/js/{2.90523f87.chunk.js.LICENSE.txt → 2.1421337b.chunk.js.LICENSE.txt} +0 -0
- package/build/static/js/2.1421337b.chunk.js.map +1 -0
- package/build/static/js/3.d701dfdf.chunk.js +3 -0
- package/build/static/js/{3.e6540184.chunk.js.LICENSE.txt → 3.d701dfdf.chunk.js.LICENSE.txt} +0 -0
- package/build/static/js/3.d701dfdf.chunk.js.map +1 -0
- package/build/static/js/4.22e700c7.chunk.js +2 -0
- package/build/static/js/4.22e700c7.chunk.js.map +1 -0
- package/build/static/js/5.10a35adf.chunk.js +2 -0
- package/build/static/js/5.10a35adf.chunk.js.map +1 -0
- package/build/static/js/6.2dcc3ced.chunk.js +2 -0
- package/build/static/js/6.2dcc3ced.chunk.js.map +1 -0
- package/build/static/js/7.e6b88c03.chunk.js +2 -0
- package/build/static/js/7.e6b88c03.chunk.js.map +1 -0
- package/build/static/js/8.2a01d8cd.chunk.js +2 -0
- package/build/static/js/8.2a01d8cd.chunk.js.map +1 -0
- package/build/static/js/main.ebd8fbea.chunk.js +2 -0
- package/build/static/js/main.ebd8fbea.chunk.js.map +1 -0
- package/build/static/js/runtime-main.b885fccc.js +2 -0
- package/build/static/js/runtime-main.b885fccc.js.map +1 -0
- package/{services/auth/meta.json → configs/auth.json} +2 -2
- package/package.json +22 -20
- package/build/precache-manifest.f3419eb785f255da7655fa425fc775a1.js +0 -150
- package/build/static/css/2.cc9dc85c.chunk.css +0 -2
- package/build/static/js/2.90523f87.chunk.js +0 -3
- package/build/static/js/2.90523f87.chunk.js.map +0 -1
- package/build/static/js/3.e6540184.chunk.js +0 -3
- package/build/static/js/3.e6540184.chunk.js.map +0 -1
- package/build/static/js/4.4410aa8a.chunk.js +0 -2
- package/build/static/js/4.4410aa8a.chunk.js.map +0 -1
- package/build/static/js/5.967448ae.chunk.js +0 -2
- package/build/static/js/5.967448ae.chunk.js.map +0 -1
- package/build/static/js/6.1de827ed.chunk.js +0 -2
- package/build/static/js/6.1de827ed.chunk.js.map +0 -1
- package/build/static/js/7.cb386b54.chunk.js +0 -2
- package/build/static/js/7.cb386b54.chunk.js.map +0 -1
- package/build/static/js/main.c51a8d5b.chunk.js +0 -2
- package/build/static/js/main.c51a8d5b.chunk.js.map +0 -1
- package/build/static/js/runtime-main.24dfe4a3.js +0 -2
- package/build/static/js/runtime-main.24dfe4a3.js.map +0 -1
- package/lib/index.js +0 -443
- package/lib/mount.js +0 -52
- package/lib/util.js +0 -17
- package/services/auth/index.js +0 -290
- package/services/auth/routes/blocklet-info.js +0 -33
- package/services/auth/routes/env.js +0 -33
- package/services/auth/routes/lost-passport-issue.js +0 -5
- package/services/auth/routes/passport.js +0 -18
- package/services/auth/routes/session.js +0 -27
|
@@ -9,7 +9,13 @@ const {
|
|
|
9
9
|
getPassportStatusEndpoint,
|
|
10
10
|
validatePassportStatus,
|
|
11
11
|
} = require('@abtnode/auth/lib/auth');
|
|
12
|
-
const {
|
|
12
|
+
const {
|
|
13
|
+
ROLES,
|
|
14
|
+
VC_TYPE_GENERAL_PASSPORT,
|
|
15
|
+
VC_TYPE_NODE_PASSPORT,
|
|
16
|
+
NODE_SERVICES,
|
|
17
|
+
WELLKNOWN_SERVICE_PATH_PREFIX,
|
|
18
|
+
} = require('@abtnode/constant');
|
|
13
19
|
const {
|
|
14
20
|
createPassportVC,
|
|
15
21
|
createPassport,
|
|
@@ -20,7 +26,7 @@ const {
|
|
|
20
26
|
getRoleFromExternalPassport,
|
|
21
27
|
createUserPassport,
|
|
22
28
|
} = require('@abtnode/auth/lib/passport');
|
|
23
|
-
const logger = require('@abtnode/logger')(require('
|
|
29
|
+
const logger = require('@abtnode/logger')(require('../../../../package.json').name);
|
|
24
30
|
|
|
25
31
|
const vcTypes = [VC_TYPE_GENERAL_PASSPORT, VC_TYPE_NODE_PASSPORT];
|
|
26
32
|
|
|
@@ -32,25 +38,27 @@ const vcTypes = [VC_TYPE_GENERAL_PASSPORT, VC_TYPE_NODE_PASSPORT];
|
|
|
32
38
|
*/
|
|
33
39
|
const isInvitedUserOnly = async (invitedUserOnly, node, teamDid) => {
|
|
34
40
|
const count = await node.getUsersCount({ teamDid });
|
|
35
|
-
|
|
36
|
-
|
|
41
|
+
|
|
42
|
+
// issue owner passport for first login user
|
|
43
|
+
if (count === 0) {
|
|
44
|
+
return [false, ROLES.OWNER, true];
|
|
37
45
|
}
|
|
38
46
|
|
|
39
|
-
if (
|
|
47
|
+
if ([true, 'yes', 'not-first'].includes(invitedUserOnly)) {
|
|
40
48
|
return [true];
|
|
41
49
|
}
|
|
42
50
|
|
|
43
51
|
return [false, ROLES.GUEST];
|
|
44
52
|
};
|
|
45
53
|
|
|
46
|
-
module.exports = function createRoutes(node, authenticator, login
|
|
54
|
+
module.exports = function createRoutes(node, authenticator, login) {
|
|
47
55
|
return {
|
|
48
56
|
action: 'login',
|
|
49
57
|
claims: {
|
|
50
58
|
profile: async ({ extraParams, context }) => {
|
|
51
59
|
const { locale } = extraParams;
|
|
52
60
|
|
|
53
|
-
const config = await context.request.getServiceConfig();
|
|
61
|
+
const config = await context.request.getServiceConfig(NODE_SERVICES.AUTH);
|
|
54
62
|
const profileFields = get(config, 'profileFields');
|
|
55
63
|
|
|
56
64
|
return {
|
|
@@ -69,7 +77,7 @@ module.exports = function createRoutes(node, authenticator, login, opts) {
|
|
|
69
77
|
const trustedPassports = (blocklet.trustedPassports || []).map((x) => x.issuerDid);
|
|
70
78
|
const trustedIssuers = [wallet.address, ...trustedPassports].filter(Boolean);
|
|
71
79
|
|
|
72
|
-
const config = (await request.getServiceConfig()) || {};
|
|
80
|
+
const config = (await request.getServiceConfig(NODE_SERVICES.AUTH)) || {};
|
|
73
81
|
const [invitedUserOnly] = await isInvitedUserOnly(config.invitedUserOnly, node, teamDid);
|
|
74
82
|
|
|
75
83
|
return {
|
|
@@ -105,7 +113,7 @@ module.exports = function createRoutes(node, authenticator, login, opts) {
|
|
|
105
113
|
locale,
|
|
106
114
|
});
|
|
107
115
|
|
|
108
|
-
const config = (await req.getServiceConfig()) || {};
|
|
116
|
+
const config = (await req.getServiceConfig(NODE_SERVICES.AUTH)) || {};
|
|
109
117
|
const [invitedUserOnly, defaultRole, issuePassport] = await isInvitedUserOnly(
|
|
110
118
|
config.invitedUserOnly,
|
|
111
119
|
node,
|
|
@@ -131,7 +139,7 @@ module.exports = function createRoutes(node, authenticator, login, opts) {
|
|
|
131
139
|
endpoint: baseUrl,
|
|
132
140
|
}),
|
|
133
141
|
endpoint: getPassportStatusEndpoint({
|
|
134
|
-
baseUrl: joinUrl(baseUrl,
|
|
142
|
+
baseUrl: joinUrl(baseUrl, WELLKNOWN_SERVICE_PATH_PREFIX),
|
|
135
143
|
userDid,
|
|
136
144
|
teamDid,
|
|
137
145
|
}),
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
const { createLostPassportIssueRoute, TEAM_TYPES } = require('@abtnode/auth/lib/lost-passport');
|
|
2
|
+
const { WELLKNOWN_SERVICE_PATH_PREFIX } = require('@abtnode/constant');
|
|
3
|
+
|
|
4
|
+
module.exports = function createRoutes(node) {
|
|
5
|
+
return createLostPassportIssueRoute({
|
|
6
|
+
node,
|
|
7
|
+
type: TEAM_TYPES.BLOCKLET,
|
|
8
|
+
authServicePrefix: WELLKNOWN_SERVICE_PATH_PREFIX,
|
|
9
|
+
});
|
|
10
|
+
};
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
const { createLostPassportListRoute } = require('@abtnode/auth/lib/lost-passport');
|
|
2
2
|
|
|
3
3
|
// eslint-disable-next-line no-unused-vars
|
|
4
|
-
module.exports = function createRoutes(node
|
|
4
|
+
module.exports = function createRoutes(node) {
|
|
5
5
|
return createLostPassportListRoute({ node, type: 'blocklet' });
|
|
6
6
|
};
|
|
@@ -0,0 +1,189 @@
|
|
|
1
|
+
/* eslint-disable arrow-parens */
|
|
2
|
+
const get = require('lodash/get');
|
|
3
|
+
const minimatch = require('minimatch');
|
|
4
|
+
const bearerToken = require('express-bearer-token');
|
|
5
|
+
const joinUrl = require('url-join');
|
|
6
|
+
|
|
7
|
+
const validators = require('@blocklet/sdk/lib/validators');
|
|
8
|
+
const { genPermissionName, NODE_SERVICES, WELLKNOWN_SERVICE_PATH_PREFIX } = require('@abtnode/constant');
|
|
9
|
+
const { BLOCKLET_MODES } = require('@blocklet/meta/lib/constants');
|
|
10
|
+
const { getBaseUrl } = require('@abtnode/router-adapter');
|
|
11
|
+
const { setUserInfoHeaders } = require('@abtnode/auth/lib/auth');
|
|
12
|
+
|
|
13
|
+
const initJwt = require('../../libs/jwt');
|
|
14
|
+
const initAuth = require('../../libs/auth');
|
|
15
|
+
|
|
16
|
+
const createLoginRoutes = require('./connect/login');
|
|
17
|
+
const createInviteRoutes = require('./connect/invite');
|
|
18
|
+
const createIssuePassportAuth = require('./connect/issue-passport');
|
|
19
|
+
const createLostPassportListAuth = require('./connect/lost-passport-list');
|
|
20
|
+
const createLostPassportIssueAuth = require('./connect/lost-passport-issue');
|
|
21
|
+
const createSessionRoutes = require('./session');
|
|
22
|
+
const createPassportRoutes = require('./passport');
|
|
23
|
+
|
|
24
|
+
const init = ({ node, options }) => {
|
|
25
|
+
/**
|
|
26
|
+
* set user info to req.user
|
|
27
|
+
*/
|
|
28
|
+
const ensureUser = async ({ req, token } = {}) => {
|
|
29
|
+
try {
|
|
30
|
+
if (token) {
|
|
31
|
+
const teamDid = req.getBlockletDid();
|
|
32
|
+
const result = await verify(token, teamDid);
|
|
33
|
+
req.user = result;
|
|
34
|
+
}
|
|
35
|
+
} catch {
|
|
36
|
+
// Do nothing
|
|
37
|
+
}
|
|
38
|
+
};
|
|
39
|
+
|
|
40
|
+
/**
|
|
41
|
+
* @returns {object} res
|
|
42
|
+
* {boolean} res.blocked
|
|
43
|
+
* {boolean} res.authenticated
|
|
44
|
+
* {boolean} res.authorized
|
|
45
|
+
*/
|
|
46
|
+
const checkAuth = async ({ req } = {}) => {
|
|
47
|
+
const config = (await req.getServiceConfig(NODE_SERVICES.AUTH)) || {};
|
|
48
|
+
|
|
49
|
+
const ignoreUrls = (get(config, 'ignoreUrls') || []).filter(Boolean);
|
|
50
|
+
|
|
51
|
+
const shouldIgnore = ignoreUrls.some((s) => minimatch(req.url, s));
|
|
52
|
+
if (shouldIgnore) {
|
|
53
|
+
return {};
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
if (config.blockUnauthenticated === false) {
|
|
57
|
+
return {};
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
if (!req.user) {
|
|
61
|
+
return { blocked: true, authenticated: false };
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
if (!config.blockUnauthorized) {
|
|
65
|
+
return {};
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
const rule = await req.getRoutingRule();
|
|
69
|
+
if (rule.to && rule.to.interfaceName) {
|
|
70
|
+
const permissionName = genPermissionName(rule.to.interfaceName);
|
|
71
|
+
const teamDid = req.getBlockletDid();
|
|
72
|
+
const rbac = await node.getRBAC(teamDid);
|
|
73
|
+
|
|
74
|
+
if (await rbac.can(req.user.role, ...permissionName.split('_'))) {
|
|
75
|
+
return {};
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
return { blocked: true, authenticated: true, authorized: false };
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
return {};
|
|
82
|
+
};
|
|
83
|
+
|
|
84
|
+
const { login, verify } = initJwt(node, options);
|
|
85
|
+
const { authenticator, handlers } = initAuth(node, options);
|
|
86
|
+
|
|
87
|
+
const middlewares = {};
|
|
88
|
+
const routes = {};
|
|
89
|
+
|
|
90
|
+
// auth middleware for http request
|
|
91
|
+
middlewares.bearerToken = bearerToken({
|
|
92
|
+
queryKey: options.loginTokenKey,
|
|
93
|
+
bodyKey: options.loginTokenKey,
|
|
94
|
+
headerKey: 'Bearer',
|
|
95
|
+
cookie: {
|
|
96
|
+
signed: true,
|
|
97
|
+
secret: options.sessionSecret,
|
|
98
|
+
key: options.loginTokenKey,
|
|
99
|
+
},
|
|
100
|
+
});
|
|
101
|
+
|
|
102
|
+
// set user info to req.user and req.headers
|
|
103
|
+
middlewares.userInfo = async (req, res, next) => {
|
|
104
|
+
const { token } = req;
|
|
105
|
+
await ensureUser({ req, token });
|
|
106
|
+
|
|
107
|
+
setUserInfoHeaders(req);
|
|
108
|
+
|
|
109
|
+
next();
|
|
110
|
+
};
|
|
111
|
+
|
|
112
|
+
// did-auth api
|
|
113
|
+
routes.attachDidAuthHandlers = (app) => {
|
|
114
|
+
handlers.forEach((handler) => {
|
|
115
|
+
handler.attach(Object.assign({ app }, createLoginRoutes(node, authenticator, login)));
|
|
116
|
+
handler.attach(Object.assign({ app }, createInviteRoutes(node, authenticator, login)));
|
|
117
|
+
handler.attach(Object.assign({ app }, createIssuePassportAuth(node, authenticator, login)));
|
|
118
|
+
handler.attach(Object.assign({ app }, createLostPassportListAuth(node, authenticator, login)));
|
|
119
|
+
handler.attach(Object.assign({ app }, createLostPassportIssueAuth(node, authenticator, login)));
|
|
120
|
+
});
|
|
121
|
+
};
|
|
122
|
+
|
|
123
|
+
// public http api
|
|
124
|
+
routes.createPassportRoutes = createPassportRoutes;
|
|
125
|
+
routes.createSessionRoutes = createSessionRoutes;
|
|
126
|
+
|
|
127
|
+
// auth middleware for websocket connect
|
|
128
|
+
middlewares.ensureWsAuth = async (req, socket, head, next) => {
|
|
129
|
+
const { searchParams } = new URL(req.url, `http://${req.headers.host || 'unknown'}`);
|
|
130
|
+
const token = searchParams.get('token');
|
|
131
|
+
|
|
132
|
+
// ignore some dev path in dev mode
|
|
133
|
+
const blocklet = await req.getBlocklet();
|
|
134
|
+
const devUrls = ['/sockjs-node'];
|
|
135
|
+
const mode = get(blocklet, 'mode');
|
|
136
|
+
if (mode === BLOCKLET_MODES.DEVELOPMENT && devUrls.includes(req.url)) {
|
|
137
|
+
next();
|
|
138
|
+
return;
|
|
139
|
+
}
|
|
140
|
+
|
|
141
|
+
await ensureUser({ req, token });
|
|
142
|
+
|
|
143
|
+
setUserInfoHeaders(req);
|
|
144
|
+
|
|
145
|
+
const { blocked, authenticated, authorized } = await checkAuth({ req });
|
|
146
|
+
if (blocked) {
|
|
147
|
+
let message = '401 Unauthorized';
|
|
148
|
+
if (authenticated && !authorized) {
|
|
149
|
+
message = '403 Forbidden';
|
|
150
|
+
}
|
|
151
|
+
socket.write(`HTTP/1.1 ${message}\r\n\r\n`);
|
|
152
|
+
socket.destroy();
|
|
153
|
+
return;
|
|
154
|
+
}
|
|
155
|
+
|
|
156
|
+
next();
|
|
157
|
+
};
|
|
158
|
+
|
|
159
|
+
middlewares.checkAuth = async (req, res, next) => {
|
|
160
|
+
const { blocked, authenticated, authorized } = await checkAuth({ req });
|
|
161
|
+
|
|
162
|
+
if (blocked) {
|
|
163
|
+
if (!authenticated) {
|
|
164
|
+
const baseUrl = getBaseUrl(req);
|
|
165
|
+
// redirect to target path after login
|
|
166
|
+
const redirect = encodeURIComponent(`${baseUrl.replace(/\/+$/, '')}/${req.url.replace(/^\/+/, '')}`);
|
|
167
|
+
res.redirect(joinUrl(baseUrl, WELLKNOWN_SERVICE_PATH_PREFIX, '/login', `/?redirect=${redirect}`));
|
|
168
|
+
return;
|
|
169
|
+
}
|
|
170
|
+
|
|
171
|
+
if (!authorized) {
|
|
172
|
+
res.status(403).json({ code: 'forbidden', error: 'not allowed' });
|
|
173
|
+
return;
|
|
174
|
+
}
|
|
175
|
+
}
|
|
176
|
+
|
|
177
|
+
next();
|
|
178
|
+
};
|
|
179
|
+
|
|
180
|
+
return {
|
|
181
|
+
middlewares,
|
|
182
|
+
routes,
|
|
183
|
+
};
|
|
184
|
+
};
|
|
185
|
+
|
|
186
|
+
module.exports = {
|
|
187
|
+
init,
|
|
188
|
+
validators,
|
|
189
|
+
};
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
const { getPassportStatus } = require('@abtnode/auth/lib/auth');
|
|
2
|
+
|
|
3
|
+
const { PREFIXES } = require('../../util/constants');
|
|
4
|
+
|
|
5
|
+
module.exports = {
|
|
6
|
+
init(server, node) {
|
|
7
|
+
PREFIXES.forEach((prefix) => {
|
|
8
|
+
server.get(`${prefix}/api/passport/status`, async (req, res) => {
|
|
9
|
+
const { vcId, userDid, locale } = req.query;
|
|
10
|
+
const teamDid = req.headers['x-blocklet-did'];
|
|
11
|
+
|
|
12
|
+
if (teamDid !== req.query.teamDid) {
|
|
13
|
+
throw new Error('teamDid is invalid');
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
const status = await getPassportStatus({ node, teamDid, userDid, vcId, locale });
|
|
17
|
+
|
|
18
|
+
res.json(status);
|
|
19
|
+
});
|
|
20
|
+
});
|
|
21
|
+
},
|
|
22
|
+
};
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
const nocache = require('nocache');
|
|
2
|
+
|
|
3
|
+
const { PREFIXES } = require('../../util/constants');
|
|
4
|
+
|
|
5
|
+
module.exports = {
|
|
6
|
+
init(server, node) {
|
|
7
|
+
PREFIXES.forEach((prefix) => {
|
|
8
|
+
const url = `${prefix}/api/did/session`;
|
|
9
|
+
|
|
10
|
+
const handler = async (req, res) => {
|
|
11
|
+
if (!req.user) {
|
|
12
|
+
res.json({ user: null });
|
|
13
|
+
return;
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
const user = { ...req.user };
|
|
17
|
+
if (user.role) {
|
|
18
|
+
const teamDid = req.getBlockletDid();
|
|
19
|
+
// FIXME: this code may have performance issue
|
|
20
|
+
const rbac = await node.getRBAC(teamDid);
|
|
21
|
+
user.permissions = await rbac.getScope(req.user.role);
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
res.json({ user });
|
|
25
|
+
};
|
|
26
|
+
|
|
27
|
+
server.get(url, nocache(), handler);
|
|
28
|
+
server.post(url, nocache(), handler);
|
|
29
|
+
});
|
|
30
|
+
},
|
|
31
|
+
};
|
|
@@ -9,15 +9,18 @@ const {
|
|
|
9
9
|
validateMessage,
|
|
10
10
|
} = require('@blocklet/sdk/lib/validators/notification');
|
|
11
11
|
// eslint-disable-next-line global-require
|
|
12
|
-
const logger = require('@abtnode/logger')(`${require('
|
|
12
|
+
const logger = require('@abtnode/logger')(`${require('../../../package.json').name}:notification`);
|
|
13
13
|
const { getTeamInfo } = require('@abtnode/auth/lib/auth');
|
|
14
14
|
const { NODE_MODES } = require('@abtnode/constant');
|
|
15
15
|
|
|
16
|
-
const states = require('
|
|
17
|
-
const { getBlockletLogo } = require('
|
|
16
|
+
const states = require('../../state');
|
|
17
|
+
const { getBlockletLogo } = require('../../util');
|
|
18
|
+
const { PREFIXES } = require('../../util/constants');
|
|
18
19
|
|
|
19
20
|
const getDid = (jwt) => jwt.iss.replace(/^did:abt:/, '');
|
|
20
21
|
|
|
22
|
+
// todo: move to notification dir
|
|
23
|
+
|
|
21
24
|
const authenticate = (req, cb) => {
|
|
22
25
|
const { searchParams } = new URL(req.url, `http://${req.headers.host || 'unknown'}`);
|
|
23
26
|
const token = searchParams.get('token');
|
|
@@ -204,7 +207,7 @@ const sendCachedMessages = async (wsServer, payload) => {
|
|
|
204
207
|
}
|
|
205
208
|
};
|
|
206
209
|
|
|
207
|
-
const init = (node
|
|
210
|
+
const init = ({ node }) => {
|
|
208
211
|
// Create ws server
|
|
209
212
|
const wsServer = new WsServer({
|
|
210
213
|
logger,
|
|
@@ -239,10 +242,7 @@ const init = (node, httpRouter, wsRouter, opts) => {
|
|
|
239
242
|
});
|
|
240
243
|
}
|
|
241
244
|
|
|
242
|
-
|
|
243
|
-
wsRouter.use(`${opts.prefix}/websocket`, wsServer.onConnect.bind(wsServer));
|
|
244
|
-
|
|
245
|
-
httpRouter.post(`${opts.prefix}/api/sendToUser`, async (req, res) => {
|
|
245
|
+
const sendToUser = async (req, res) => {
|
|
246
246
|
try {
|
|
247
247
|
await onSendToUser(node, req.body.data, wsServer);
|
|
248
248
|
res.status(200).send('');
|
|
@@ -251,7 +251,23 @@ const init = (node, httpRouter, wsRouter, opts) => {
|
|
|
251
251
|
res.statusMessage = error.message;
|
|
252
252
|
res.status(400).send(error.message);
|
|
253
253
|
}
|
|
254
|
-
}
|
|
254
|
+
};
|
|
255
|
+
|
|
256
|
+
// mount
|
|
257
|
+
return {
|
|
258
|
+
sendToUser: {
|
|
259
|
+
attach: (app) => {
|
|
260
|
+
PREFIXES.forEach((prefix) => {
|
|
261
|
+
app.post(`${prefix}/api/sendToUser`, sendToUser);
|
|
262
|
+
});
|
|
263
|
+
},
|
|
264
|
+
},
|
|
265
|
+
attach: (wsRouter) => {
|
|
266
|
+
PREFIXES.forEach((prefix) => {
|
|
267
|
+
wsRouter.use(`${prefix}/websocket`, wsServer.onConnect.bind(wsServer));
|
|
268
|
+
});
|
|
269
|
+
},
|
|
270
|
+
};
|
|
255
271
|
};
|
|
256
272
|
|
|
257
273
|
module.exports = { init };
|
|
@@ -0,0 +1,76 @@
|
|
|
1
|
+
const path = require('path');
|
|
2
|
+
const serveStatic = require('serve-static');
|
|
3
|
+
|
|
4
|
+
const { WELLKNOWN_SERVICE_PATH_PREFIX } = require('@abtnode/constant');
|
|
5
|
+
|
|
6
|
+
const isFeDevelopment = process.env.ABT_NODE_SERVICE_FE_PORT;
|
|
7
|
+
|
|
8
|
+
const distDir = path.resolve(__dirname, '../../build');
|
|
9
|
+
const devDir = path.resolve(__dirname, '../../public');
|
|
10
|
+
|
|
11
|
+
const attachUtils = ({ req, res, proxy }) => {
|
|
12
|
+
res.sendWebPage = () => {
|
|
13
|
+
if (isFeDevelopment) {
|
|
14
|
+
proxy.web(
|
|
15
|
+
req,
|
|
16
|
+
res,
|
|
17
|
+
{
|
|
18
|
+
target: `http://127.0.0.1:${process.env.ABT_NODE_SERVICE_FE_PORT}`,
|
|
19
|
+
},
|
|
20
|
+
(error) => {
|
|
21
|
+
if (error) {
|
|
22
|
+
console.error(error);
|
|
23
|
+
res.status(502).send(error.message);
|
|
24
|
+
}
|
|
25
|
+
}
|
|
26
|
+
);
|
|
27
|
+
} else {
|
|
28
|
+
res.sendFile(path.join(distDir, 'index.html'));
|
|
29
|
+
}
|
|
30
|
+
};
|
|
31
|
+
|
|
32
|
+
res.sendStaticFile = (file, sendOptions) => {
|
|
33
|
+
if (isFeDevelopment) {
|
|
34
|
+
res.sendFile(path.join(devDir, file), sendOptions);
|
|
35
|
+
} else {
|
|
36
|
+
res.sendFile(path.join(distDir, file), sendOptions);
|
|
37
|
+
}
|
|
38
|
+
};
|
|
39
|
+
};
|
|
40
|
+
|
|
41
|
+
const attachStaticResources = ({ app, proxy }) => {
|
|
42
|
+
if (isFeDevelopment) {
|
|
43
|
+
app.use('/static', (req, res) => {
|
|
44
|
+
proxy.web(
|
|
45
|
+
req,
|
|
46
|
+
res,
|
|
47
|
+
{
|
|
48
|
+
target: `http://127.0.0.1:${process.env.ABT_NODE_SERVICE_FE_PORT}/static`,
|
|
49
|
+
},
|
|
50
|
+
(error) => {
|
|
51
|
+
if (error) {
|
|
52
|
+
console.error(error);
|
|
53
|
+
res.status(502).send(error.message);
|
|
54
|
+
}
|
|
55
|
+
}
|
|
56
|
+
);
|
|
57
|
+
});
|
|
58
|
+
} else {
|
|
59
|
+
app.use(`${WELLKNOWN_SERVICE_PATH_PREFIX}/static`, serveStatic(distDir, { index: false }));
|
|
60
|
+
}
|
|
61
|
+
};
|
|
62
|
+
|
|
63
|
+
const attachDevProxy = ({ wsRouter, proxy }) => {
|
|
64
|
+
if (isFeDevelopment) {
|
|
65
|
+
wsRouter.use('/sockjs-node', async (req, socket, head) => {
|
|
66
|
+
const target = 'http://127.0.0.1:3040';
|
|
67
|
+
proxy.ws(req, socket, head, { target }, (error) => {
|
|
68
|
+
if (error) {
|
|
69
|
+
console.error('socket proxy error', { from: req.url, to: target, error });
|
|
70
|
+
}
|
|
71
|
+
});
|
|
72
|
+
});
|
|
73
|
+
}
|
|
74
|
+
};
|
|
75
|
+
|
|
76
|
+
module.exports = { attachUtils, attachStaticResources, attachDevProxy };
|
|
File without changes
|
|
File without changes
|
|
@@ -0,0 +1,149 @@
|
|
|
1
|
+
const get = require('lodash/get');
|
|
2
|
+
|
|
3
|
+
const getBlockletInfo = require('@blocklet/meta/lib/info');
|
|
4
|
+
const { getDefaultServiceConfig } = require('@abtnode/core/lib/util/service');
|
|
5
|
+
const logger = require('@abtnode/logger')(require('../../package.json').name);
|
|
6
|
+
const cache = require('../cache');
|
|
7
|
+
|
|
8
|
+
const formatContext = require('./format-context');
|
|
9
|
+
|
|
10
|
+
module.exports = ({ node, req, options }) => {
|
|
11
|
+
req.getBlockletUrl = () => req.headers['x-blocklet-url'] || get(options, 'blockletUrl', '');
|
|
12
|
+
req.getBlockletDid = () => req.headers['x-blocklet-did'] || get(options, 'blockletDid', '');
|
|
13
|
+
req.getBlockletRealDid = () => req.headers['x-blocklet-real-did'] || get(options, 'blockletRealDid', '');
|
|
14
|
+
req.getRoutingRuleId = () => req.headers['x-routing-rule-id'] || get(options, 'routingRuleId', '');
|
|
15
|
+
|
|
16
|
+
req.getServiceContext = () => formatContext(req);
|
|
17
|
+
|
|
18
|
+
req.getRoutingRule = async () => {
|
|
19
|
+
const ruleId = req.getRoutingRuleId(req);
|
|
20
|
+
if (!ruleId) {
|
|
21
|
+
return null;
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
let rule = cache.get(ruleId);
|
|
25
|
+
|
|
26
|
+
if (!rule) {
|
|
27
|
+
rule = await node.getRoutingRuleById(ruleId);
|
|
28
|
+
cache.set(ruleId, rule);
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
return rule;
|
|
32
|
+
};
|
|
33
|
+
|
|
34
|
+
/**
|
|
35
|
+
* @return obj | null
|
|
36
|
+
* @TODO get service config from routing rule
|
|
37
|
+
*/
|
|
38
|
+
req.getServiceConfig = async (serviceName) => {
|
|
39
|
+
const ruleId = req.getRoutingRuleId(req);
|
|
40
|
+
if (!ruleId || !serviceName) {
|
|
41
|
+
return null;
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
const cacheKeys = {
|
|
45
|
+
rule: cache.keyFns.routingRule(ruleId),
|
|
46
|
+
config: cache.keyFns.serviceConfig(ruleId, serviceName),
|
|
47
|
+
};
|
|
48
|
+
|
|
49
|
+
// Return cached config if exists
|
|
50
|
+
const cached = cache.get(cacheKeys.config);
|
|
51
|
+
if (cached) {
|
|
52
|
+
return cached;
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
// Find rule
|
|
56
|
+
let rule = cache.get(cacheKeys.rule);
|
|
57
|
+
if (!rule) {
|
|
58
|
+
rule = await node.getRoutingRuleById(ruleId);
|
|
59
|
+
cache.set(cacheKeys.rule, rule);
|
|
60
|
+
}
|
|
61
|
+
if (!rule) {
|
|
62
|
+
return null;
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
const defaultConfig = getDefaultServiceConfig(serviceName);
|
|
66
|
+
|
|
67
|
+
// find blocklet
|
|
68
|
+
let blocklet = await req.getBlocklet();
|
|
69
|
+
if (!blocklet) {
|
|
70
|
+
return defaultConfig;
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
const realDid = req.getBlockletRealDid();
|
|
74
|
+
if (realDid && blocklet.meta.did !== realDid) {
|
|
75
|
+
blocklet = (blocklet.children || []).find((x) => x.meta.did === realDid);
|
|
76
|
+
}
|
|
77
|
+
if (!blocklet) {
|
|
78
|
+
return defaultConfig;
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
// find interface
|
|
82
|
+
let interfaceName = rule.to.realInterfaceName;
|
|
83
|
+
|
|
84
|
+
// we should only use rule.to.realInterfaceName, rule.to.interfaceName is for backward compatible
|
|
85
|
+
if (!interfaceName) {
|
|
86
|
+
logger.error(
|
|
87
|
+
`rule.to.realInterfaceName was not fround, please reInstall blocklet ${rule.to.did} to eliminate hidden bugs`
|
|
88
|
+
);
|
|
89
|
+
interfaceName = rule.to.interfaceName;
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
const _interface = blocklet.meta.interfaces.find((x) => x.name === interfaceName);
|
|
93
|
+
if (!_interface) {
|
|
94
|
+
return defaultConfig;
|
|
95
|
+
}
|
|
96
|
+
|
|
97
|
+
// find service
|
|
98
|
+
const service = (_interface.services || []).find((x) => serviceName === x.name);
|
|
99
|
+
|
|
100
|
+
if (!service) {
|
|
101
|
+
return defaultConfig;
|
|
102
|
+
}
|
|
103
|
+
|
|
104
|
+
return service.config;
|
|
105
|
+
};
|
|
106
|
+
|
|
107
|
+
req.getBlocklet = async () => {
|
|
108
|
+
const did = req.getBlockletDid();
|
|
109
|
+
if (!did) {
|
|
110
|
+
return null;
|
|
111
|
+
}
|
|
112
|
+
|
|
113
|
+
const cacheKey = cache.keyFns.blocklet(did);
|
|
114
|
+
let blocklet = cache.get(cacheKey);
|
|
115
|
+
if (!blocklet) {
|
|
116
|
+
const context = req.getServiceContext();
|
|
117
|
+
blocklet = await node.getBlocklet({ did, attachRuntimeInfo: false }, context);
|
|
118
|
+
if (blocklet) {
|
|
119
|
+
cache.set(cacheKey, blocklet);
|
|
120
|
+
}
|
|
121
|
+
}
|
|
122
|
+
|
|
123
|
+
return blocklet;
|
|
124
|
+
};
|
|
125
|
+
|
|
126
|
+
req.getNodeInfo = async () => {
|
|
127
|
+
const cacheKey = cache.keyFns.node();
|
|
128
|
+
let nodeInfo = cache.get(cacheKey);
|
|
129
|
+
if (!nodeInfo) {
|
|
130
|
+
nodeInfo = await node.states.node.read();
|
|
131
|
+
cache.set(cacheKey, nodeInfo);
|
|
132
|
+
}
|
|
133
|
+
|
|
134
|
+
return nodeInfo;
|
|
135
|
+
};
|
|
136
|
+
|
|
137
|
+
req.getBlockletInfo = async () => {
|
|
138
|
+
const [blocklet, info] = await Promise.all([req.getBlocklet(), req.getNodeInfo()]);
|
|
139
|
+
if (!blocklet) {
|
|
140
|
+
throw new Error('Blocklet does not exist');
|
|
141
|
+
}
|
|
142
|
+
|
|
143
|
+
return getBlockletInfo(blocklet, info.sk);
|
|
144
|
+
};
|
|
145
|
+
|
|
146
|
+
req.cache = cache;
|
|
147
|
+
};
|
|
148
|
+
|
|
149
|
+
exports.formatContext = formatContext;
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
const get = require('lodash/get');
|
|
2
|
+
|
|
3
|
+
const { isProduction } = require('../libs/env');
|
|
4
|
+
|
|
5
|
+
const formatContext = (ctx = {}) => {
|
|
6
|
+
if (ctx && ctx.user) {
|
|
7
|
+
delete ctx.user.avatar;
|
|
8
|
+
}
|
|
9
|
+
|
|
10
|
+
const port = isProduction ? get(ctx, 'headers[x-real-port]', '') : '';
|
|
11
|
+
const hostname = get(ctx, 'headers[x-real-hostname]', ctx.hostname);
|
|
12
|
+
const protocol = get(ctx, 'headers[x-real-protocol]', 'http').replace(/:$/, '');
|
|
13
|
+
|
|
14
|
+
return {
|
|
15
|
+
protocol,
|
|
16
|
+
user: ctx.user || null,
|
|
17
|
+
url: ctx.originalUrl,
|
|
18
|
+
query: ctx.query,
|
|
19
|
+
hostname,
|
|
20
|
+
port: Number(port) === 80 ? '' : Number(port),
|
|
21
|
+
};
|
|
22
|
+
};
|
|
23
|
+
|
|
24
|
+
module.exports = formatContext;
|