@abtnode/blocklet-services 1.6.26 → 1.6.29

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/README.md CHANGED
@@ -5,7 +5,7 @@ Aggregator to mount all blocklet services and make them work together.
5
5
  ## Usage
6
6
 
7
7
  ```shell
8
- yarn add @abtnode/service-server
8
+ yarn add @abtnode/blocklet-service
9
9
  ```
10
10
 
11
11
  Then:
@@ -17,10 +17,6 @@ const ABTNode = require('@abtnode/core');
17
17
  const node = ABTNode({ ...nodeOptions });
18
18
  const server = createServer(node, { ...globalOptions });
19
19
 
20
- server.mountService('@abtnode/auth-service', { ...loginServiceOptions });
21
- server.mountService('@abtnode/acl-service', { ...aclServiceOptions });
22
- server.mountService('@abtnode/payment-service', { ...paymentServiceOptions });
23
-
24
20
  node.onReady(() => {
25
21
  server.listen(5000, () => {
26
22
  console.log('ABT Node Service server ready on port 5000');
File without changes
package/api/index.js ADDED
@@ -0,0 +1,296 @@
1
+ const http = require('http');
2
+ const get = require('lodash/get');
3
+ const morgan = require('morgan');
4
+ const express = require('express');
5
+ require('express-async-errors');
6
+ const cors = require('cors');
7
+ const compression = require('compression');
8
+ const cookieParser = require('cookie-parser');
9
+ const bodyParser = require('body-parser');
10
+ const RotatingFileStream = require('rotating-file-stream');
11
+ const httpProxy = require('http-proxy');
12
+ const moment = require('dayjs');
13
+ const minimatch = require('minimatch');
14
+
15
+ const { WELLKNOWN_SERVICE_PATH_PREFIX, NODE_SERVICES_PREFIX, EVENTS } = require('@abtnode/constant');
16
+ const { BlockletEvents } = require('@blocklet/meta/lib/constants');
17
+ const normalizePathPrefix = require('@abtnode/util/lib/normalize-path-prefix');
18
+ const eventHub =
19
+ process.env.NODE_ENV === 'test' ? require('@arcblock/event-hub/single') : require('@arcblock/event-hub');
20
+ const logger = require('@abtnode/logger')(require('../package.json').name);
21
+
22
+ const cache = require('./cache');
23
+ const { ensureProxyUrl } = require('./util');
24
+ const { isProduction, isE2E } = require('./libs/env');
25
+ const { init: initStates } = require('./state/index');
26
+
27
+ const { init: initNotification } = require('./services/notification');
28
+ const { init: initAuth } = require('./services/auth');
29
+ const StaticService = require('./services/static');
30
+ const createEnvRoutes = require('./routes/env');
31
+ const createBlockletRoutes = require('./routes/blocklet');
32
+ const checkRunning = require('./middlewares/check-running');
33
+ const attachSharedUtils = require('./util/attach-shared-utils');
34
+
35
+ const logFileGenerator = (time, index) => {
36
+ if (!time) {
37
+ return 'service.log';
38
+ }
39
+
40
+ let filename = `service-${moment(time).subtract(1, 'day').format('YYYY-MM-DD')}`; // prev date
41
+
42
+ if (index > 1) {
43
+ filename = `${filename}-${index}`;
44
+ }
45
+
46
+ return `${filename}.log.gz`;
47
+ };
48
+
49
+ module.exports = function createServer(node, serverOptions = {}) {
50
+ const options = {
51
+ dataDir: node.dataDirs.services,
52
+ sessionSecret: process.env.ABT_NODE_SESSION_SECRET,
53
+ sessionTtl: process.env.ABT_NODE_SESSION_TTL,
54
+ webWalletUrl: 'https://web.abtwallet.io',
55
+ loginTokenKey: 'login_token',
56
+ ...serverOptions,
57
+ isProduction,
58
+ isE2E,
59
+ };
60
+
61
+ if (!options.dataDir) {
62
+ throw new Error('Blocklet services requires dataDir to start');
63
+ }
64
+ if (!options.sessionSecret) {
65
+ throw new Error('Blocklet services requires sessionSecret to start');
66
+ }
67
+
68
+ logger.info('init blocklet service', { isProduction });
69
+
70
+ initStates(options.dataDir);
71
+
72
+ const { middlewares: authMiddlewares, routes: authRoutes } = initAuth({ node, options });
73
+ const notificationService = initNotification({ node, options });
74
+
75
+ // Proxy engine
76
+ const proxy = httpProxy.createProxyServer({});
77
+ // eslint-disable-next-line no-unused-vars
78
+ proxy.on('proxyReq', (proxyReq, req, res) => {
79
+ if (req.rawBody) {
80
+ // Since we already consumed request stream, we need to write req.rawBody to proxy request here
81
+ proxyReq.write(req.rawBody);
82
+ }
83
+ });
84
+
85
+ // Cross process events
86
+ [BlockletEvents.updated, BlockletEvents.started, BlockletEvents.removed, BlockletEvents.statusChange].forEach(
87
+ (name) => {
88
+ eventHub.on(name, (data) => {
89
+ const did = get(data, 'meta.did');
90
+ if (did) {
91
+ logger.info('delete blocklet cache on update', { did, pid: process.pid });
92
+ cache.del(cache.keyFns.blocklet(did));
93
+ }
94
+ });
95
+ }
96
+ );
97
+ eventHub.on(EVENTS.NODE_UPDATED, () => {
98
+ logger.info('node update', { pid: process.pid });
99
+ cache.del(cache.keyFns.node());
100
+ });
101
+
102
+ // Http server
103
+ const server = express();
104
+
105
+ server.set('trust proxy', 'loopback');
106
+ server.disable('x-powered-by');
107
+
108
+ server.use(compression());
109
+ server.use(cookieParser());
110
+
111
+ server.use(
112
+ bodyParser.json({
113
+ // We have to set a larger hard limit since
114
+ limit: '2mb',
115
+
116
+ // https://flaviocopes.com/express-get-raw-body/
117
+ // Side effects: this will double the memory consumption
118
+ verify: (req, res, buf) => {
119
+ req.rawBody = buf;
120
+ },
121
+ })
122
+ );
123
+
124
+ // NOTE: will be overwrite by Blocklet Server in production
125
+ server.use(cors());
126
+
127
+ // Shared util functions on current request
128
+ server.use((req, res, next) => {
129
+ attachSharedUtils({ node, req, options });
130
+ StaticService.attachUtils({ req, res, proxy });
131
+ next();
132
+ });
133
+
134
+ /* istanbul ignore if */
135
+ if (isProduction) {
136
+ const accessLogStream = RotatingFileStream.createStream(logFileGenerator, {
137
+ interval: '1d',
138
+ path: process.env.ABT_NODE_LOG_DIR,
139
+ compress: 'gzip',
140
+ });
141
+ server.use(morgan('combined', { stream: accessLogStream }));
142
+ /* istanbul ignore else */
143
+ } else {
144
+ server.use(
145
+ morgan((tokens, req, res) => {
146
+ const log = [
147
+ tokens.method(req, res),
148
+ tokens.url(req, res),
149
+ tokens.status(req, res),
150
+ tokens.res(req, res, 'content-length'),
151
+ '-',
152
+ tokens['response-time'](req, res),
153
+ 'ms',
154
+ ].join(' ');
155
+
156
+ return log;
157
+ })
158
+ );
159
+ }
160
+
161
+ // Static assets
162
+ StaticService.attachStaticResources({ app: server, proxy });
163
+
164
+ // API: notification
165
+ notificationService.sendToUser.attach(server);
166
+
167
+ // Middleware: auth info
168
+ server.use(authMiddlewares.bearerToken);
169
+ server.use(authMiddlewares.userInfo);
170
+
171
+ // API: auth
172
+ createEnvRoutes.init(server, node, options);
173
+ createBlockletRoutes.init(server, node, options);
174
+ authRoutes.attachDidAuthHandlers(server);
175
+ authRoutes.createPassportRoutes.init(server, node, options);
176
+ authRoutes.createSessionRoutes.init(server, node, options);
177
+
178
+ // Web Page
179
+ server.get(`${WELLKNOWN_SERVICE_PATH_PREFIX}/**`, (req, res) => {
180
+ res.sendWebPage();
181
+ });
182
+
183
+ // Middleware: check running
184
+ // Request would not arrive here before blocklet is installed, because there is no config in router provider(nginx)
185
+ server.use(checkRunning);
186
+
187
+ // Middleware: check auth
188
+ server.use(authMiddlewares.checkAuth);
189
+
190
+ // Block invalid path in reserved prefix
191
+ server.use((req, res, next) => {
192
+ if ([NODE_SERVICES_PREFIX.AUTH_SERVICE, WELLKNOWN_SERVICE_PATH_PREFIX].some((x) => req.path.startsWith(x))) {
193
+ res.status(400).send('Bad request');
194
+ return;
195
+ }
196
+
197
+ next();
198
+ });
199
+
200
+ // After all service middleware, we can now safely pass all traffic to blocklets
201
+ server.use((req, res, next) => {
202
+ const { target } = ensureProxyUrl(req);
203
+
204
+ if (target) {
205
+ proxy.web(
206
+ req,
207
+ res,
208
+ {
209
+ target,
210
+ },
211
+ (error) => {
212
+ if (error) {
213
+ console.error(error);
214
+ logger.error('http proxy error', { error });
215
+ res.status(502).send(`Can not proxy to upstream blocklet: ${target}`);
216
+ }
217
+ }
218
+ );
219
+ } else {
220
+ next();
221
+ }
222
+ });
223
+
224
+ // Following handlers exist just in case
225
+
226
+ // 404 handler
227
+ server.use((req, res) => {
228
+ res.status(404).send('Blocklet Service: You should not be here!');
229
+ });
230
+
231
+ // error handler
232
+ // eslint-disable-next-line no-unused-vars
233
+ server.use((err, req, res, next) => {
234
+ console.error('service error', { error: err });
235
+ res.status(500).send('Blocklet Service: Something broke!');
236
+ });
237
+
238
+ // Web socket server
239
+
240
+ // Simple websocket router like http router
241
+ const httpServer = http.createServer(server);
242
+ server.listen = httpServer.listen.bind(httpServer);
243
+ const wsRoutingRules = [];
244
+ httpServer.on('upgrade', async (req, socket, head) => {
245
+ attachSharedUtils({ node, req, options });
246
+
247
+ // find matched handler registered by each service
248
+ const { pathname } = new URL(req.url, `http://${req.headers.host || 'unknown'}`);
249
+ const routes = wsRoutingRules.filter((x) => minimatch(normalizePathPrefix(pathname), normalizePathPrefix(x.path)));
250
+
251
+ let routeIndex = 0;
252
+ const next = () => {
253
+ const route = routes[routeIndex];
254
+ if (route) {
255
+ routeIndex++;
256
+ route.handle(req, socket, head, next);
257
+ }
258
+ };
259
+
260
+ next();
261
+ });
262
+ const wsRouter = {
263
+ use(mountPoint, handler) {
264
+ wsRoutingRules.push({ path: mountPoint, handle: handler });
265
+ },
266
+ };
267
+
268
+ // Notification
269
+ notificationService.attach(wsRouter);
270
+
271
+ // Only for Development
272
+ StaticService.attachDevProxy({ wsRouter, proxy });
273
+
274
+ // Auth
275
+ wsRouter.use('**', authMiddlewares.ensureWsAuth);
276
+
277
+ // Final: directly proxy all websocket request to target blocklet
278
+ wsRouter.use('**', async (req, socket, head) => {
279
+ const { target } = ensureProxyUrl(req);
280
+ if (target) {
281
+ proxy.ws(req, socket, head, { target }, (error) => {
282
+ if (error) {
283
+ logger.error('socket proxy error', { from: req.url, to: target, error });
284
+ }
285
+ });
286
+ } else {
287
+ logger.error('socket proxy error: cannot find target service');
288
+ socket.write('HTTP/1.1 404 Not Found\r\n\r\n');
289
+ socket.destroy();
290
+ }
291
+ });
292
+
293
+ return server;
294
+ };
295
+
296
+ module.exports.logFileGenerator = logFileGenerator;
@@ -5,6 +5,7 @@ const DiskStorage = require('@arcblock/did-auth-storage-nedb');
5
5
  const { WalletAuthenticator } = require('@arcblock/did-auth');
6
6
  const WalletHandlers = require('@blocklet/sdk/lib/wallet-handler');
7
7
  const sendNotification = require('@blocklet/sdk/lib/util/send-notification');
8
+ const { WELLKNOWN_SERVICE_PATH_PREFIX, NODE_SERVICES_PREFIX } = require('@abtnode/constant');
8
9
 
9
10
  const { getBlockletLogo } = require('../util');
10
11
 
@@ -25,14 +26,18 @@ module.exports = (node, opts) => {
25
26
  ]);
26
27
 
27
28
  // logo
28
- const logo = getBlockletLogo({ baseUrl: joinUrl(baseUrl, opts.prefix), blocklet, nodeInfo: info });
29
+ const logo = getBlockletLogo({
30
+ baseUrl: joinUrl(baseUrl, WELLKNOWN_SERVICE_PATH_PREFIX),
31
+ blocklet,
32
+ nodeInfo: info,
33
+ });
29
34
 
30
35
  return {
31
36
  name: meta.name,
32
37
  description: meta.description || `Login to ${meta.name}`,
33
38
  icon: logo,
34
39
  updateSubEndpoint: true,
35
- subscriptionEndpoint: joinUrl(groupPathPrefix, opts.prefix, 'websocket'),
40
+ subscriptionEndpoint: joinUrl(groupPathPrefix, WELLKNOWN_SERVICE_PATH_PREFIX, 'websocket'),
36
41
  nodeDid: info.did,
37
42
  };
38
43
  },
@@ -48,12 +53,8 @@ module.exports = (node, opts) => {
48
53
  },
49
54
  });
50
55
 
51
- const handlers = new WalletHandlers({
56
+ const handlerOpts = {
52
57
  authenticator,
53
- options: {
54
- prefix: `${opts.prefix}/api/did`,
55
- },
56
- tokenGenerator: () => Date.now().toString(),
57
58
  tokenStorage: new DiskStorage({
58
59
  dbPath: path.join(opts.dataDir, 'auth.db'),
59
60
  dbPort: process.env.NODE_ENV === 'test' ? null : Number(process.env.NEDB_MULTI_PORT),
@@ -67,10 +68,25 @@ module.exports = (node, opts) => {
67
68
  };
68
69
  return sendNotification(connectedDid, message, sender, process.env.ABT_NODE_SERVICE_PORT);
69
70
  },
71
+ };
72
+
73
+ // backward compatible
74
+ const oldHandler = new WalletHandlers({
75
+ ...handlerOpts,
76
+ options: {
77
+ prefix: `${NODE_SERVICES_PREFIX.AUTH_SERVICE}/api/did`,
78
+ },
79
+ });
80
+
81
+ const handler = new WalletHandlers({
82
+ ...handlerOpts,
83
+ options: {
84
+ prefix: `${WELLKNOWN_SERVICE_PATH_PREFIX}/api/did`,
85
+ },
70
86
  });
71
87
 
72
88
  return {
73
89
  authenticator,
74
- handlers,
90
+ handlers: [handler, oldHandler],
75
91
  };
76
92
  };
@@ -0,0 +1,7 @@
1
+ const isProduction = process.env.NODE_ENV === 'production';
2
+ const isE2E = process.env.NODE_ENV === 'e2e';
3
+
4
+ module.exports = {
5
+ isProduction,
6
+ isE2E,
7
+ };
@@ -3,6 +3,7 @@ const jwt = require('jsonwebtoken');
3
3
  const { createAuthToken } = require('@abtnode/auth/lib/auth');
4
4
  const { isUserPassportRevoked } = require('@abtnode/auth/lib/passport');
5
5
 
6
+ // FIXME: we need to test performance for this code
6
7
  const getUser = async (node, teamDid, userDid) => {
7
8
  const user = await node.getUser({ teamDid, user: { did: userDid } });
8
9
  if (user && user.approved) {
@@ -0,0 +1,15 @@
1
+ const { ROLES } = require('@abtnode/constant');
2
+
3
+ module.exports = async (req, res, next) => {
4
+ if (!req.user) {
5
+ res.status(401).json({ code: 'forbidden', error: 'not authorized' });
6
+ return;
7
+ }
8
+
9
+ if (![ROLES.OWNER, ROLES.ADMIN].includes(req.user.role)) {
10
+ res.status(403).json({ code: 'forbidden', error: 'no permission' });
11
+ return;
12
+ }
13
+
14
+ next();
15
+ };
@@ -0,0 +1,46 @@
1
+ const joinUrl = require('url-join');
2
+
3
+ const { BlockletStatus } = require('@blocklet/meta/lib/constants');
4
+ const { WELLKNOWN_SERVICE_PATH_PREFIX } = require('@abtnode/constant');
5
+ const getBlockletNotRunningTemplate = require('@abtnode/router-templates/lib/blocklet-not-running');
6
+ const getBlockletMaintenanceTemplate = require('@abtnode/router-templates/lib/blocklet-maintenance');
7
+ const { getBaseUrl } = require('@abtnode/router-adapter');
8
+
9
+ const { shouldGotoStartPage } = require('../util');
10
+
11
+ const checkRunning = async (req, res, next) => {
12
+ const blocklet = await req.getBlocklet();
13
+ if (
14
+ ![
15
+ BlockletStatus.running,
16
+ // Waiting, Downloading should be allowed because blocklet is currently being upgrading
17
+ BlockletStatus.waiting,
18
+ BlockletStatus.downloading,
19
+ ].includes(blocklet.status)
20
+ ) {
21
+ if (shouldGotoStartPage(req)) {
22
+ const baseUrl = getBaseUrl(req);
23
+ const redirect = encodeURIComponent(
24
+ `${baseUrl.replace(/\/+$/, '')}/${req.url.replace(/^\/+/, '').replace('__start__=1', '')}`
25
+ );
26
+ res.redirect(joinUrl(baseUrl, WELLKNOWN_SERVICE_PATH_PREFIX, '/start', `/?redirect=${redirect}`));
27
+ return;
28
+ }
29
+
30
+ const nodeInfo = await req.getNodeInfo();
31
+ res.status(500);
32
+ // return json if json has high priority, e.g. "*/*,application/json"
33
+ if (req.accepts(['html', 'json']) === 'json') {
34
+ res.json({ code: 'error', error: 'blocklet is not running' });
35
+ } else if (blocklet.status === BlockletStatus.starting) {
36
+ res.send(getBlockletMaintenanceTemplate(blocklet, nodeInfo));
37
+ } else {
38
+ res.send(getBlockletNotRunningTemplate(blocklet, nodeInfo));
39
+ }
40
+ return;
41
+ }
42
+
43
+ next();
44
+ };
45
+
46
+ module.exports = checkRunning;
@@ -0,0 +1,98 @@
1
+ /* eslint-disable no-console */
2
+ const fs = require('fs');
3
+ const path = require('path');
4
+ const get = require('lodash/get');
5
+ const cloneDeep = require('lodash/cloneDeep');
6
+
7
+ const { fixBlockletStatus, wipeSensitiveData } = require('@blocklet/meta/lib/util');
8
+ const { WELLKNOWN_SERVICE_PATH_PREFIX } = require('@abtnode/constant');
9
+ const logger = require('@abtnode/logger')(require('../../package.json').name);
10
+
11
+ const checkAdminPermission = require('../middlewares/check-admin-permission');
12
+
13
+ const polishBlocklet = (doc) => {
14
+ const res = cloneDeep(doc);
15
+ fixBlockletStatus(res);
16
+ return wipeSensitiveData(res);
17
+ };
18
+
19
+ const prefix = WELLKNOWN_SERVICE_PATH_PREFIX;
20
+
21
+ module.exports = {
22
+ init(server, node) {
23
+ server.get(`${prefix}/blocklet/logo`, async (req, res) => {
24
+ const sendOptions = { maxAge: '1d' };
25
+
26
+ try {
27
+ const blocklet = await req.getBlocklet();
28
+
29
+ if (blocklet && get(blocklet, 'env.appDir') && blocklet.meta.logo) {
30
+ const logoFile = path.join(get(blocklet, 'env.appDir'), blocklet.meta.logo);
31
+
32
+ if (fs.existsSync(logoFile)) {
33
+ res.sendFile(logoFile, sendOptions);
34
+ return;
35
+ }
36
+ }
37
+
38
+ res.sendStaticFile('/images/blocklet.png', sendOptions);
39
+ } catch (err) {
40
+ logger.error('failed to send blocklet logo', { did: req.params.did, error: err });
41
+ res.sendStaticFile('/images/blocklet.png', sendOptions);
42
+ }
43
+ });
44
+
45
+ server.get(`${prefix}/api/blocklet/detail`, checkAdminPermission, async (req, res) => {
46
+ const blocklet = await req.getBlocklet();
47
+
48
+ res.json(polishBlocklet(blocklet));
49
+ });
50
+
51
+ server.post(`${prefix}/api/blocklet/config`, checkAdminPermission, async (req, res) => {
52
+ const blocklet = await req.getBlocklet();
53
+ const { configs, childDid } = req.body;
54
+ const doc = await node.configBlocklet({
55
+ did: blocklet.meta.did,
56
+ childDid,
57
+ configs,
58
+ });
59
+
60
+ res.json(polishBlocklet(doc));
61
+ });
62
+
63
+ server.post(`${prefix}/api/blocklet/start`, checkAdminPermission, async (req, res) => {
64
+ const blocklet = await req.getBlocklet();
65
+ const doc = await node.startBlocklet({
66
+ did: blocklet.meta.did,
67
+ checkHealthImmediately: true,
68
+ throwOnError: true,
69
+ });
70
+
71
+ res.json(polishBlocklet(doc));
72
+ });
73
+
74
+ // backward compatible
75
+ server.get(`${prefix}/blocklet/logo/:did`, async (req, res) => {
76
+ const sendOptions = { maxAge: '1d' };
77
+
78
+ let blocklet = null;
79
+ try {
80
+ blocklet = await node.ensureBlockletIntegrity(req.params.did);
81
+
82
+ if (blocklet && get(blocklet, 'env.appDir') && blocklet.meta.logo) {
83
+ const logoFile = path.join(get(blocklet, 'env.appDir'), blocklet.meta.logo);
84
+
85
+ if (fs.existsSync(logoFile)) {
86
+ res.sendFile(logoFile, sendOptions);
87
+ return;
88
+ }
89
+ }
90
+
91
+ res.sendStaticFile('/images/blocklet.png', sendOptions);
92
+ } catch (err) {
93
+ logger.error('failed to send blocklet logo', { did: req.params.did, error: err });
94
+ res.sendStaticFile('/images/blocklet.png', sendOptions);
95
+ }
96
+ });
97
+ },
98
+ };
@@ -0,0 +1,27 @@
1
+ const { NODE_SERVICES } = require('@abtnode/constant');
2
+ const { WELLKNOWN_SERVICE_PATH_PREFIX } = require('@abtnode/constant');
3
+
4
+ module.exports = {
5
+ init(server, node, opts) {
6
+ server.get(`**${WELLKNOWN_SERVICE_PATH_PREFIX}/api/env`, async (req, res) => {
7
+ res.type('js');
8
+
9
+ const [blocklet, config, info] = await Promise.all([
10
+ req.getBlockletInfo(),
11
+ req.getServiceConfig(NODE_SERVICES.AUTH),
12
+ req.getNodeInfo(),
13
+ ]);
14
+ const pathPrefix = req.headers['x-path-prefix'] || '/';
15
+ const groupPathPrefix = req.headers['x-group-path-prefix'];
16
+
17
+ res.send(`window.env = {
18
+ appId: "${blocklet.did}",
19
+ appName: "${blocklet.name}",
20
+ pathPrefix: "${pathPrefix}",
21
+ apiPrefix: "${pathPrefix.replace(/\/+$/, '')}${WELLKNOWN_SERVICE_PATH_PREFIX}",
22
+ ${groupPathPrefix ? `groupPathPrefix: "${groupPathPrefix}",` : ''}
23
+ webWalletUrl: "${info.webWalletUrl || config.webWalletUrl || opts.webWalletUrl}",
24
+ }`);
25
+ });
26
+ },
27
+ };
@@ -7,9 +7,10 @@ const {
7
7
  checkWalletVersion,
8
8
  beforeInvitationRequest,
9
9
  } = require('@abtnode/auth/lib/auth');
10
- const logger = require('@abtnode/logger')(require('../meta.json').name);
10
+ const { NODE_SERVICES, WELLKNOWN_SERVICE_PATH_PREFIX } = require('@abtnode/constant');
11
+ const logger = require('@abtnode/logger')(require('../../../../package.json').name);
11
12
 
12
- module.exports = function createRoutes(node, authenticator, login, opts) {
13
+ module.exports = function createRoutes(node, authenticator, login) {
13
14
  return {
14
15
  action: 'invite',
15
16
 
@@ -24,7 +25,7 @@ module.exports = function createRoutes(node, authenticator, login, opts) {
24
25
  profile: async ({ extraParams, context }) => {
25
26
  const { locale } = extraParams;
26
27
 
27
- const config = await context.request.getServiceConfig();
28
+ const config = await context.request.getServiceConfig(NODE_SERVICES.AUTH);
28
29
  const profileFields = get(config, 'profileFields');
29
30
 
30
31
  return {
@@ -53,7 +54,7 @@ module.exports = function createRoutes(node, authenticator, login, opts) {
53
54
  const { locale, inviteId } = extraParams;
54
55
  const nodeInfo = await req.getNodeInfo();
55
56
  const teamDid = req.headers['x-blocklet-did'];
56
- const statusEndpointBaseUrl = joinUrl(baseUrl, opts.prefix);
57
+ const statusEndpointBaseUrl = joinUrl(baseUrl, WELLKNOWN_SERVICE_PATH_PREFIX);
57
58
  const endpoint = baseUrl;
58
59
 
59
60
  const { passport, response, role } = await handleInvitationResponse({
@@ -6,7 +6,11 @@ const {
6
6
  beforeIssuePassportRequest,
7
7
  } = require('@abtnode/auth/lib/auth');
8
8
 
9
- module.exports = function createRoutes(node, authenticator, login, opts) {
9
+ const { WELLKNOWN_SERVICE_PATH_PREFIX } = require('@abtnode/constant');
10
+
11
+ // todo: move to connect dir
12
+
13
+ module.exports = function createRoutes(node) {
10
14
  return {
11
15
  action: 'issue-passport',
12
16
 
@@ -38,7 +42,7 @@ module.exports = function createRoutes(node, authenticator, login, opts) {
38
42
  const { locale, id } = extraParams;
39
43
  const nodeInfo = await node.getNodeInfo();
40
44
  const teamDid = req.headers['x-blocklet-did'];
41
- const statusEndpointBaseUrl = joinUrl(baseUrl, opts.prefix);
45
+ const statusEndpointBaseUrl = joinUrl(baseUrl, WELLKNOWN_SERVICE_PATH_PREFIX);
42
46
  const endpoint = baseUrl;
43
47
 
44
48
  return handleIssuePassportResponse({