@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
package/lib/index.js DELETED
@@ -1,443 +0,0 @@
1
- const path = require('path');
2
- const http = require('http');
3
- const get = require('lodash/get');
4
- const morgan = require('morgan');
5
- const express = require('express');
6
- require('express-async-errors');
7
- const cors = require('cors');
8
- const compression = require('compression');
9
- const cookieParser = require('cookie-parser');
10
- const bodyParser = require('body-parser');
11
- const RotatingFileStream = require('rotating-file-stream');
12
- const httpProxy = require('http-proxy');
13
- const serveStatic = require('serve-static');
14
- const moment = require('dayjs');
15
- const minimatch = require('minimatch');
16
- const { NODE_SERVICES } = require('@abtnode/constant');
17
- const { BlockletEvents } = require('@blocklet/meta/lib/constants');
18
- const normalizePathPrefix = require('@abtnode/util/lib/normalize-path-prefix');
19
- const eventHub =
20
- process.env.NODE_ENV === 'test' ? require('@arcblock/event-hub/single') : require('@arcblock/event-hub');
21
- const getBlockletInfo = require('@blocklet/meta/lib/info');
22
-
23
- const logger = require('@abtnode/logger')(require('../package.json').name);
24
-
25
- const authModule = require('../services/auth');
26
-
27
- const mount = require('./mount');
28
- const cache = require('./cache');
29
- const { ensureProxyUrl } = require('./util');
30
-
31
- const logFileGenerator = (time, index) => {
32
- if (!time) {
33
- return 'service.log';
34
- }
35
-
36
- let filename = `service-${moment(time).subtract(1, 'day').format('YYYY-MM-DD')}`; // prev date
37
-
38
- if (index > 1) {
39
- filename = `${filename}-${index}`;
40
- }
41
-
42
- return `${filename}.log.gz`;
43
- };
44
-
45
- const isProduction = process.env.NODE_ENV === 'production' || process.env.ABT_NODE_SERVICE_ENV === 'production';
46
- const isE2E = process.env.NODE_ENV === 'e2e';
47
-
48
- // Format context: https://github.com/graphql/express-graphql
49
- const formatContext = (ctx = {}) => {
50
- if (ctx && ctx.user) {
51
- delete ctx.user.avatar;
52
- }
53
-
54
- const port = isProduction ? get(ctx, 'headers[x-real-port]', '') : '';
55
- const hostname = get(ctx, 'headers[x-real-hostname]', ctx.hostname);
56
- const protocol = get(ctx, 'headers[x-real-protocol]', 'http').replace(/:$/, '');
57
-
58
- return {
59
- protocol,
60
- user: ctx.user || null,
61
- url: ctx.originalUrl,
62
- query: ctx.query,
63
- hostname,
64
- port: Number(port) === 80 ? '' : Number(port),
65
- };
66
- };
67
-
68
- // eslint-disable-next-line no-shadow
69
- const attachSharedUtils = (node, req, options) => {
70
- req.getBlockletUrl = () => req.headers['x-blocklet-url'] || get(options, 'blockletUrl', '');
71
- req.getBlockletDid = () => req.headers['x-blocklet-did'] || get(options, 'blockletDid', '');
72
- req.getBlockletRealDid = () => req.headers['x-blocklet-real-did'] || get(options, 'blockletRealDid', '');
73
- req.getRoutingRuleId = () => req.headers['x-routing-rule-id'] || get(options, 'routingRuleId', '');
74
-
75
- req.getServiceContext = () => formatContext(req);
76
-
77
- req.getRoutingRule = async () => {
78
- const ruleId = req.getRoutingRuleId(req);
79
- if (!ruleId) {
80
- return null;
81
- }
82
-
83
- let rule = cache.get(ruleId);
84
-
85
- if (!rule) {
86
- rule = await node.getRoutingRuleById(ruleId);
87
- cache.set(ruleId, rule);
88
- }
89
-
90
- return rule;
91
- };
92
-
93
- /**
94
- * @return obj | null
95
- */
96
- req.getServiceConfig = async (serviceName) => {
97
- const ruleId = req.getRoutingRuleId(req);
98
- const name = serviceName || get(req, 'service.current', '');
99
- if (!ruleId || !name) {
100
- return null;
101
- }
102
-
103
- const cacheKeys = {
104
- rule: cache.keyFns.routingRule(ruleId),
105
- config: cache.keyFns.serviceConfig(ruleId, name),
106
- };
107
-
108
- // Return cached config if exists
109
- const cached = cache.get(cacheKeys.config);
110
- if (cached) {
111
- return cached;
112
- }
113
-
114
- // Find rule
115
- let rule = cache.get(cacheKeys.rule);
116
- if (!rule) {
117
- rule = await node.getRoutingRuleById(ruleId);
118
- cache.set(cacheKeys.rule, rule);
119
- }
120
- if (!rule) {
121
- return null;
122
- }
123
-
124
- // if is auth service, get config from blocklet meta
125
- if (name === NODE_SERVICES.AUTH_SERVICE) {
126
- // find blocklet
127
- let blocklet = await req.getBlocklet();
128
- if (!blocklet) {
129
- return null;
130
- }
131
-
132
- const realDid = req.getBlockletRealDid();
133
- if (realDid && blocklet.meta.did !== realDid) {
134
- blocklet = (blocklet.children || []).find((x) => x.meta.did === realDid);
135
- }
136
- if (!blocklet) {
137
- return null;
138
- }
139
-
140
- // find interface
141
- let interfaceName = rule.to.realInterfaceName;
142
-
143
- // we should only use rule.to.realInterfaceName, rule.to.interfaceName is for backward compatible
144
- if (!interfaceName) {
145
- logger.error(
146
- `rule.to.realInterfaceName was not fround, please reInstall blocklet ${rule.to.did} to eliminate hidden bugs`
147
- );
148
- interfaceName = rule.to.interfaceName;
149
- }
150
-
151
- const _interface = blocklet.meta.interfaces.find((x) => x.name === interfaceName);
152
- if (!_interface) {
153
- return null;
154
- }
155
-
156
- // find service
157
- const service = (_interface.services || []).find((x) => x.name === NODE_SERVICES.AUTH_SERVICE);
158
- if (!service) {
159
- return null;
160
- }
161
-
162
- return service.config;
163
- }
164
-
165
- // Parse config from rule
166
- const services = rule.services || [];
167
- const service = services.find((x) => x.name === name);
168
- if (service) {
169
- let config = {};
170
- try {
171
- logger.info('service config deserialize', service);
172
- config = JSON.parse(service.config || '{}');
173
- cache.set(cacheKeys.config, config);
174
- } catch (err) {
175
- logger.error('service config deserialize error', { error: err });
176
- }
177
- return config;
178
- }
179
-
180
- return null;
181
- };
182
-
183
- req.getBlocklet = async () => {
184
- const did = req.getBlockletDid();
185
- if (!did) {
186
- return null;
187
- }
188
-
189
- const cacheKey = cache.keyFns.blocklet(did);
190
- let blocklet = cache.get(cacheKey);
191
- if (!blocklet) {
192
- const context = req.getServiceContext();
193
- blocklet = await node.getBlocklet({ did, attachRuntimeInfo: false }, context);
194
- if (blocklet) {
195
- cache.set(cacheKey, blocklet);
196
- }
197
- }
198
-
199
- return blocklet;
200
- };
201
-
202
- req.getNodeInfo = async () => {
203
- const cacheKey = cache.keyFns.node();
204
- let nodeInfo = cache.get(cacheKey);
205
- if (!nodeInfo) {
206
- nodeInfo = await node.states.node.read();
207
- cache.set(cacheKey, nodeInfo);
208
- }
209
-
210
- return nodeInfo;
211
- };
212
-
213
- req.getBlockletInfo = async () => {
214
- const [blocklet, info] = await Promise.all([req.getBlocklet(), req.getNodeInfo()]);
215
- if (!blocklet) {
216
- throw new Error('Blocklet does not exist');
217
- }
218
-
219
- return getBlockletInfo(blocklet, info.sk);
220
- };
221
-
222
- req.cache = cache;
223
- };
224
-
225
- const distDir = path.resolve(__dirname, '../build');
226
-
227
- module.exports = function createServer(node, serverOptions = {}, serviceModules = []) {
228
- const server = express();
229
- const proxy = httpProxy.createProxyServer({});
230
-
231
- // simple router, let each service handle the websocket connection
232
- const wsRoutingRules = [
233
- // final route: directly proxy all websocket request to target blocklet
234
- {
235
- path: '**',
236
- handle: async (req, socket, head) => {
237
- const { target } = ensureProxyUrl(req);
238
- if (target) {
239
- proxy.ws(req, socket, head, { target }, (error) => {
240
- if (error) {
241
- logger.error('socket proxy error', { error });
242
- }
243
- });
244
- } else {
245
- logger.error('socket proxy error: cannot find target service');
246
- socket.write('HTTP/1.1 404 Not Found\r\n\r\n');
247
- socket.destroy();
248
- }
249
- },
250
- },
251
- ];
252
- const wsRouter = {
253
- // eslint-disable-next-line no-shadow
254
- use(path, handler) {
255
- const finalRoute = wsRoutingRules.pop();
256
- wsRoutingRules.push({ path, handle: handler });
257
- wsRoutingRules.push(finalRoute);
258
- },
259
- };
260
-
261
- // eslint-disable-next-line no-unused-vars
262
- proxy.on('proxyReq', (proxyReq, req, res, options) => {
263
- if (req.rawBody) {
264
- // Since we already consumed request stream, we need to write req.rawBody to proxy request here
265
- proxyReq.write(req.rawBody);
266
- }
267
- });
268
-
269
- // Bust cache on events from daemon
270
- [BlockletEvents.updated, BlockletEvents.started, BlockletEvents.removed, BlockletEvents.statusChange].forEach(
271
- (name) => {
272
- eventHub.on(name, (data) => {
273
- const did = get(data, 'meta.did');
274
- if (did) {
275
- logger.info('delete blocklet cache on update', { did, pid: process.pid });
276
- cache.del(cache.keyFns.blocklet(did));
277
- }
278
- });
279
- }
280
- );
281
- eventHub.on('node.updated', () => {
282
- logger.info('node update', { pid: process.pid });
283
- cache.del(cache.keyFns.node());
284
- });
285
-
286
- logger.info('init params', { isProduction, serverOptions });
287
-
288
- server.set('trust proxy', 'loopback');
289
- server.disable('x-powered-by');
290
-
291
- server.use(compression());
292
- server.use(cookieParser());
293
-
294
- server.use(
295
- bodyParser.json({
296
- // We have to set a larger hard limit since
297
- limit: '2mb',
298
-
299
- // https://flaviocopes.com/express-get-raw-body/
300
- // Side effects: this will double the memory consumption
301
- verify: (req, res, buf) => {
302
- req.rawBody = buf;
303
- },
304
- })
305
- );
306
-
307
- // NOTE: will be overwrite by Blocklet Server in production
308
- server.use(cors());
309
-
310
- // Shared util functions on current request
311
- server.use((req, res, next) => {
312
- attachSharedUtils(node, req, serverOptions);
313
- next();
314
- });
315
-
316
- /* istanbul ignore if */
317
- if (isProduction) {
318
- const accessLogStream = RotatingFileStream.createStream(logFileGenerator, {
319
- interval: '1d',
320
- path: process.env.ABT_NODE_LOG_DIR,
321
- compress: 'gzip',
322
- });
323
- server.use(morgan('combined', { stream: accessLogStream }));
324
- /* istanbul ignore else */
325
- } else {
326
- server.use(
327
- morgan((tokens, req, res) => {
328
- const log = [
329
- tokens.method(req, res),
330
- tokens.url(req, res),
331
- tokens.status(req, res),
332
- tokens.res(req, res, 'content-length'),
333
- '-',
334
- tokens['response-time'](req, res),
335
- 'ms',
336
- ].join(' ');
337
-
338
- return log;
339
- })
340
- );
341
- }
342
-
343
- // Serve static assets from the service
344
- if (isProduction || isE2E) {
345
- server.use('/.service/@abtnode/auth-service', serveStatic(distDir, { index: false }));
346
- }
347
-
348
- // Mount services
349
- // Each service can mount any number of middleware function or api function
350
-
351
- // mount Auth Service
352
- if (process.env.NODE_ENV !== 'test') {
353
- mount({
354
- node,
355
- server,
356
- wsRouter,
357
- service: {
358
- options: Object.assign({}, serverOptions, {
359
- sessionSecret: process.env.ABT_NODE_SESSION_SECRET,
360
- sessionTtl: process.env.ABT_NODE_SESSION_TTL,
361
- }),
362
- name: NODE_SERVICES.AUTH_SERVICE,
363
- module: authModule,
364
- },
365
- });
366
- }
367
- serviceModules.forEach((serviceModule) => {
368
- mount({
369
- node,
370
- server,
371
- wsRouter,
372
- service: serviceModule,
373
- });
374
- });
375
-
376
- // After all service middleware, we can now safely pass all traffic to blocklets
377
- server.use((req, res, next) => {
378
- const { target } = ensureProxyUrl(req);
379
-
380
- if (target) {
381
- proxy.web(
382
- req,
383
- res,
384
- {
385
- target,
386
- },
387
- (error) => {
388
- if (error) {
389
- console.error(error);
390
- logger.error('http proxy error', { error });
391
- res.status(502).send(`Can not proxy to upstream blocklet: ${target}`);
392
- }
393
- }
394
- );
395
- } else {
396
- next();
397
- }
398
- });
399
-
400
- // Following handlers exist just in case
401
-
402
- // 404 handler
403
- server.use((req, res) => {
404
- res.status(404).send('Blocklet Service: You should not be here!');
405
- });
406
-
407
- // error handler
408
- // eslint-disable-next-line no-unused-vars
409
- server.use((err, req, res, next) => {
410
- console.error('service error', { error: err });
411
- res.status(500).send('Blocklet Service: Something broke!');
412
- });
413
-
414
- // handle websocket connect request like http
415
- const httpServer = http.createServer(server);
416
-
417
- httpServer.on('upgrade', async (req, socket, head) => {
418
- attachSharedUtils(node, req, serverOptions);
419
-
420
- // find matched handler registered by each service
421
- const { pathname } = new URL(req.url, `http://${req.headers.host || 'unknown'}`);
422
- const routes = wsRoutingRules.filter((x) => minimatch(normalizePathPrefix(pathname), normalizePathPrefix(x.path)));
423
-
424
- let routeIndex = 0;
425
- const next = () => {
426
- const route = routes[routeIndex];
427
- if (route) {
428
- routeIndex++;
429
- route.handle(req, socket, head, next);
430
- }
431
- };
432
-
433
- next();
434
- });
435
-
436
- server.listen = httpServer.listen.bind(httpServer);
437
-
438
- return server;
439
- };
440
-
441
- module.exports.formatContext = formatContext;
442
- module.exports.logFileGenerator = logFileGenerator;
443
- module.exports.attachSharedUtils = attachSharedUtils;
package/lib/mount.js DELETED
@@ -1,52 +0,0 @@
1
- /* eslint-disable global-require */
2
- /* eslint-disable import/no-dynamic-require */
3
- const fs = require('fs-extra');
4
- const path = require('path');
5
- const express = require('express');
6
- const set = require('lodash/set');
7
-
8
- const logger = require('@abtnode/logger')(require('../package.json').name);
9
-
10
- module.exports = function mount({ node, server, wsRouter, service }) {
11
- try {
12
- const serviceModule = service.module;
13
-
14
- const dataDir = path.join(node.dataDirs.services, service.name);
15
- if (!fs.pathExistsSync(dataDir)) {
16
- fs.mkdirpSync(dataDir);
17
- }
18
- const serviceOptions = { dataDir, ...service.options };
19
-
20
- let serviceObject = serviceModule;
21
- if (typeof serviceModule === 'function') {
22
- serviceObject = serviceModule(node, server, serviceOptions);
23
- }
24
- const { init, name, version } = serviceObject;
25
-
26
- // Create new router for each service
27
- const router = express.Router();
28
-
29
- // Set current service before current service runs
30
- router.use((req, res, next) => {
31
- set(req, 'service.current', name);
32
- next();
33
- });
34
-
35
- // Mount service middleware
36
- init({ node, httpRouter: server, serviceHttpRouter: router, wsRouter, options: serviceOptions });
37
-
38
- // Unset current service when all middleware is done
39
- router.use((req, res, next) => {
40
- set(req, 'service.current', '');
41
- next();
42
- });
43
-
44
- // Attach the service router to main application
45
- server.use(router);
46
-
47
- logger.info(`service ${name}@${version} mounted successfully`, { name, version });
48
- } catch (err) {
49
- logger.error(`service ${service.name} failed to mount due to ${err.message}`);
50
- throw err;
51
- }
52
- };
package/lib/util.js DELETED
@@ -1,17 +0,0 @@
1
- const ensureProxyUrl = (req) => {
2
- const target = req.headers['x-blocklet-url'];
3
-
4
- if (target) {
5
- const pathPrefix = req.headers['x-routing-rule-path-prefix'];
6
-
7
- if (pathPrefix && pathPrefix !== '/') {
8
- req.url = `${pathPrefix}${req.url}`;
9
- }
10
- }
11
-
12
- return { target };
13
- };
14
-
15
- module.exports = {
16
- ensureProxyUrl,
17
- };