@abtnode/blocklet-services 1.6.27 → 1.6.30

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.
Files changed (81) hide show
  1. package/README.md +1 -5
  2. package/{lib → api}/cache.js +0 -0
  3. package/api/index.js +296 -0
  4. package/{services/auth → api}/libs/auth.js +24 -8
  5. package/api/libs/env.js +7 -0
  6. package/{services/auth → api}/libs/jwt.js +1 -0
  7. package/api/middlewares/check-admin-permission.js +15 -0
  8. package/api/middlewares/check-running.js +46 -0
  9. package/api/routes/blocklet.js +98 -0
  10. package/api/routes/env.js +27 -0
  11. package/{services/auth/routes → api/services/auth/connect}/invite.js +5 -4
  12. package/{services/auth/routes → api/services/auth/connect}/issue-passport.js +6 -2
  13. package/{services/auth/routes → api/services/auth/connect}/login.js +18 -10
  14. package/api/services/auth/connect/lost-passport-issue.js +10 -0
  15. package/{services/auth/routes → api/services/auth/connect}/lost-passport-list.js +1 -1
  16. package/api/services/auth/index.js +189 -0
  17. package/api/services/auth/passport.js +22 -0
  18. package/api/services/auth/session.js +31 -0
  19. package/{services/auth/routes/notification.js → api/services/notification/index.js} +25 -9
  20. package/api/services/static.js +76 -0
  21. package/{services/auth → api}/state/index.js +0 -0
  22. package/{services/auth → api}/state/message.js +0 -0
  23. package/api/util/attach-shared-utils.js +149 -0
  24. package/api/util/constants.js +10 -0
  25. package/api/util/format-context.js +24 -0
  26. package/{services/auth → api}/util/index.js +31 -1
  27. package/build/asset-manifest.json +32 -30
  28. package/build/index.html +1 -1
  29. package/build/precache-manifest.f8d516b676d205d1f6e2c4e869fbf297.js +154 -0
  30. package/build/service-worker.js +2 -2
  31. package/build/static/css/2.d49e994f.chunk.css +2 -0
  32. package/build/static/css/{2.cc9dc85c.chunk.css.map → 2.d49e994f.chunk.css.map} +1 -1
  33. package/build/static/js/2.ca22e0d7.chunk.js +3 -0
  34. package/build/static/js/{2.90523f87.chunk.js.LICENSE.txt → 2.ca22e0d7.chunk.js.LICENSE.txt} +0 -0
  35. package/build/static/js/2.ca22e0d7.chunk.js.map +1 -0
  36. package/build/static/js/3.38949d38.chunk.js +3 -0
  37. package/build/static/js/{3.e6540184.chunk.js.LICENSE.txt → 3.38949d38.chunk.js.LICENSE.txt} +0 -0
  38. package/build/static/js/3.38949d38.chunk.js.map +1 -0
  39. package/build/static/js/4.97f8d423.chunk.js +2 -0
  40. package/build/static/js/4.97f8d423.chunk.js.map +1 -0
  41. package/build/static/js/5.8149df59.chunk.js +2 -0
  42. package/build/static/js/5.8149df59.chunk.js.map +1 -0
  43. package/build/static/js/6.001b8434.chunk.js +2 -0
  44. package/build/static/js/6.001b8434.chunk.js.map +1 -0
  45. package/build/static/js/7.f30a5254.chunk.js +2 -0
  46. package/build/static/js/7.f30a5254.chunk.js.map +1 -0
  47. package/build/static/js/8.e354cbf1.chunk.js +2 -0
  48. package/build/static/js/8.e354cbf1.chunk.js.map +1 -0
  49. package/build/static/js/main.561b39e2.chunk.js +2 -0
  50. package/build/static/js/main.561b39e2.chunk.js.map +1 -0
  51. package/build/static/js/runtime-main.8ddd5828.js +2 -0
  52. package/build/static/js/runtime-main.8ddd5828.js.map +1 -0
  53. package/{services/auth/meta.json → configs/auth.json} +2 -2
  54. package/package.json +27 -24
  55. package/build/precache-manifest.f3419eb785f255da7655fa425fc775a1.js +0 -150
  56. package/build/static/css/2.cc9dc85c.chunk.css +0 -2
  57. package/build/static/js/2.90523f87.chunk.js +0 -3
  58. package/build/static/js/2.90523f87.chunk.js.map +0 -1
  59. package/build/static/js/3.e6540184.chunk.js +0 -3
  60. package/build/static/js/3.e6540184.chunk.js.map +0 -1
  61. package/build/static/js/4.4410aa8a.chunk.js +0 -2
  62. package/build/static/js/4.4410aa8a.chunk.js.map +0 -1
  63. package/build/static/js/5.967448ae.chunk.js +0 -2
  64. package/build/static/js/5.967448ae.chunk.js.map +0 -1
  65. package/build/static/js/6.1de827ed.chunk.js +0 -2
  66. package/build/static/js/6.1de827ed.chunk.js.map +0 -1
  67. package/build/static/js/7.cb386b54.chunk.js +0 -2
  68. package/build/static/js/7.cb386b54.chunk.js.map +0 -1
  69. package/build/static/js/main.c51a8d5b.chunk.js +0 -2
  70. package/build/static/js/main.c51a8d5b.chunk.js.map +0 -1
  71. package/build/static/js/runtime-main.24dfe4a3.js +0 -2
  72. package/build/static/js/runtime-main.24dfe4a3.js.map +0 -1
  73. package/lib/index.js +0 -443
  74. package/lib/mount.js +0 -52
  75. package/lib/util.js +0 -17
  76. package/services/auth/index.js +0 -290
  77. package/services/auth/routes/blocklet-info.js +0 -33
  78. package/services/auth/routes/env.js +0 -33
  79. package/services/auth/routes/lost-passport-issue.js +0 -5
  80. package/services/auth/routes/passport.js +0 -18
  81. 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 { ROLES, VC_TYPE_GENERAL_PASSPORT, VC_TYPE_NODE_PASSPORT } = require('@abtnode/constant');
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('../meta.json').name);
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
- if (invitedUserOnly === 'not-first') {
36
- return count > 0 ? [true] : [false, ROLES.OWNER, true];
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 (invitedUserOnly === true || invitedUserOnly === 'yes') {
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, opts) {
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, opts.prefix),
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, authenticator, login, opts) {
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('../meta.json').name}:notification`);
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('../state');
17
- const { getBlockletLogo } = require('../util');
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, httpRouter, wsRouter, opts) => {
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
- // mount
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, findService } = 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 = findService(_interface.services, serviceName);
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,10 @@
1
+ const { NODE_SERVICES_PREFIX, WELLKNOWN_SERVICE_PATH_PREFIX } = require('@abtnode/constant');
2
+
3
+ const PREFIXES = [
4
+ NODE_SERVICES_PREFIX.AUTH_SERVICE, // backward compatible
5
+ WELLKNOWN_SERVICE_PATH_PREFIX,
6
+ ];
7
+
8
+ module.exports = {
9
+ PREFIXES,
10
+ };
@@ -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;