@abtnode/core 1.6.4 → 1.6.8

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.
@@ -70,8 +70,9 @@ const normalizeRedirectUrl = (url) => {
70
70
  };
71
71
 
72
72
  class RouterManager extends EventEmitter {
73
- constructor() {
73
+ constructor({ certManager }) {
74
74
  super();
75
+ this.certManager = certManager;
75
76
 
76
77
  // HACK: do not emit any events from CLI
77
78
  if (isCLI()) {
@@ -300,7 +301,10 @@ class RouterManager extends EventEmitter {
300
301
  await this.validateRouterConfig('updateRoutingRule', { id, rule });
301
302
 
302
303
  // update rules
303
- const newRules = [...dbSite.rules.filter((x) => x.groupId !== rule.id), ...(await this.getRules(rule))];
304
+ const newRules = [
305
+ ...dbSite.rules.filter((x) => x.groupId !== rule.id || x.id !== rule.id), // 有些路由没有 rule.groupId
306
+ ...(await this.getRules(rule)),
307
+ ];
304
308
 
305
309
  const updateResult = await states.site.update({ _id: id }, { $set: { rules: newRules } });
306
310
  logger.info('update result', { updateResult });
@@ -363,7 +367,7 @@ class RouterManager extends EventEmitter {
363
367
  domain,
364
368
  });
365
369
  logger.info('add certificate result', { domain: newCert.domain });
366
- this.emit('router.certificate.add', { type: 'nginx', data: newCert });
370
+ this.emit('cert.added', { type: 'nginx', data: newCert });
367
371
  }
368
372
 
369
373
  // eslint-disable-next-line no-unused-vars
@@ -376,7 +380,7 @@ class RouterManager extends EventEmitter {
376
380
  const removeResult = await states.certificate.remove({ _id: id });
377
381
 
378
382
  logger.info('delete certificate', { removeResult, domain: tmpCert.domain });
379
- this.emit('router.certificate.remove', { type: 'nginx', data: { domain: tmpCert.domain } });
383
+ this.emit('cert.removed', { type: 'nginx', data: { domain: tmpCert.domain } });
380
384
  return {};
381
385
  }
382
386
 
@@ -386,7 +390,7 @@ class RouterManager extends EventEmitter {
386
390
  this.fixCertificate(entity);
387
391
  this.validateCertificate(entity, entity.domain);
388
392
  const dbEntity = await states.certificate.upsert(entity);
389
- this.emit('router.certificate.updated', { type: 'nginx', data: dbEntity });
393
+ this.emit('cert.issued', { type: 'nginx', data: dbEntity });
390
394
  }
391
395
 
392
396
  findCertificateByDomain(domain) {
@@ -448,7 +452,7 @@ class RouterManager extends EventEmitter {
448
452
  }
449
453
 
450
454
  async getMatchedCert(domain) {
451
- const certs = await states.certificate.find();
455
+ const certs = await this.certManager.getAll();
452
456
  const matchedCert = certs.find((cert) => this.isCertMatchedDomain(cert, domain));
453
457
 
454
458
  if (matchedCert) {
@@ -1,226 +1,17 @@
1
- const fs = require('fs');
2
- const path = require('path');
3
- const util = require('util');
4
- const { EventEmitter } = require('events');
5
- const cloneDeep = require('lodash/cloneDeep');
6
- const DataStore =
7
- process.env.NODE_ENV === 'test' ? require('@nedb/core') : require('@nedb/multi')(Number(process.env.NEDB_MULTI_PORT));
1
+ const DB = require('@abtnode/db');
8
2
  const logger = require('@abtnode/logger')('@abtnode/core:states');
9
3
 
10
4
  const { isCLI } = require('../util');
11
5
 
12
- class BaseState extends EventEmitter {
6
+ class BaseState extends DB {
13
7
  constructor(baseDir, options) {
14
- super();
8
+ super(baseDir, options);
15
9
 
16
10
  // HACK: do not emit any events from CLI
17
11
  if (isCLI() && process.env.NODE_ENV !== 'test') {
18
12
  this.emit = (name) => logger.debug('stopped state db event in CLI', name);
19
13
  }
20
-
21
- const dbOptions = options.db || {};
22
- this.filename = path.join(baseDir, options.filename);
23
- this.options = Object.freeze(cloneDeep(options));
24
- this.db = new DataStore({
25
- filename: this.filename,
26
- timestampData: true,
27
- ...dbOptions,
28
- });
29
-
30
- logger.info('initialized', { filename: this.filename });
31
-
32
- this.ready = false;
33
- this.readyCallbacks = [];
34
- this.db.loadDatabase((err) => {
35
- if (err) {
36
- logger.error(`failed to load disk database ${this.filename}`, { error: err });
37
- console.error(err);
38
- } else {
39
- this.ready = true;
40
- if (this.readyCallbacks.length) {
41
- this.readyCallbacks.forEach((x) => x());
42
- }
43
- }
44
- });
45
-
46
- this.asyncDB = new Proxy(this.db, {
47
- get(target, property) {
48
- if (typeof target[property] === 'function') {
49
- return util
50
- .promisify((...args) => {
51
- const cb = args[args.length - 1];
52
- const rest = args.slice(0, args.length - 1);
53
-
54
- target[property](...rest, (err, ...result) => {
55
- if (err) {
56
- return cb(err);
57
- }
58
-
59
- if (result.length === 1) {
60
- return cb(null, result[0]);
61
- }
62
-
63
- return cb(null, result);
64
- });
65
- })
66
- .bind(target);
67
- }
68
-
69
- return target[property];
70
- },
71
- });
72
- }
73
-
74
- onReady(cb) {
75
- if (this.ready) {
76
- cb();
77
- } else {
78
- this.readyCallbacks.push(cb);
79
- }
80
- }
81
-
82
- createNotification(payload) {
83
- if (this.notification && typeof this.notification.create === 'function') {
84
- this.notification.create(payload);
85
- }
86
- }
87
-
88
- paginate(conditions, sort, paging) {
89
- const { pageSize: size = 20, page = 1 } = paging || {};
90
- const pageSize = Math.min(100, size);
91
-
92
- return new Promise((resolve, reject) => {
93
- this.db
94
- .find(conditions)
95
- .sort(sort)
96
- .exec((err, docs) => {
97
- if (err) {
98
- return reject(err);
99
- }
100
-
101
- const pageCount = Math.ceil(docs.length / pageSize);
102
- const total = docs.length;
103
- const skip = (page - 1) * pageSize;
104
- const list = docs.slice(skip, skip + pageSize);
105
-
106
- list.forEach((doc) => {
107
- // eslint-disable-next-line no-underscore-dangle
108
- doc.id = doc._id;
109
- });
110
-
111
- return resolve({
112
- list,
113
- paging: {
114
- total,
115
- pageSize,
116
- pageCount,
117
- page,
118
- },
119
- });
120
- });
121
- });
122
- }
123
-
124
- async updateById(id, updates, options = {}) {
125
- const [, doc] = await this.asyncDB.update({ _id: id }, updates, {
126
- multi: false,
127
- upsert: false,
128
- returnUpdatedDocs: true,
129
- ...options,
130
- });
131
-
132
- return doc;
133
- }
134
-
135
- update(...args) {
136
- if (args.length === 0) {
137
- throw new Error('param is required by update method');
138
- }
139
-
140
- if (typeof args[0] === 'string') {
141
- return this.updateById(...args);
142
- }
143
-
144
- return this.asyncDB.update(args[0], args[1], { returnUpdatedDocs: true, ...(args[2] || {}) });
145
- }
146
-
147
- count(conditions = {}) {
148
- return new Promise((resolve, reject) => {
149
- this.db.count(conditions, (err, num) => {
150
- if (err) {
151
- return reject(err);
152
- }
153
-
154
- return resolve(num);
155
- });
156
- });
157
- }
158
-
159
- remove(conditions = {}, options = { multi: false }) {
160
- return new Promise((resolve, reject) => {
161
- this.db.remove(conditions, options, (err, num) => {
162
- if (err) {
163
- return reject(err);
164
- }
165
-
166
- return resolve(num);
167
- });
168
- });
169
- }
170
-
171
- reset() {
172
- fs.unlinkSync(this.filename);
173
- }
174
-
175
- find(...args) {
176
- if (args.length === 0) {
177
- return this.asyncDB.find({});
178
- }
179
-
180
- return this.asyncDB.find(...args);
181
- }
182
-
183
- findOne(...args) {
184
- if (args.length === 0) {
185
- return this.asyncDB.findOne({});
186
- }
187
-
188
- return this.asyncDB.findOne(...args);
189
- }
190
-
191
- insert(...args) {
192
- return this.asyncDB.insert(...args);
193
14
  }
194
15
  }
195
16
 
196
- /**
197
- * Rename _id field name to id, this method has side effects
198
- * @param {object} entities
199
- */
200
- const renameIdFiledName = (entities, from = '_id', to = 'id') => {
201
- /* eslint-disable no-underscore-dangle, no-param-reassign */
202
-
203
- if (!entities) {
204
- return entities;
205
- }
206
-
207
- const mapEntity = (entity) => {
208
- if (entity[from]) {
209
- entity[to] = entity[from];
210
- delete entity[from];
211
- }
212
- };
213
-
214
- if (!Array.isArray(entities)) {
215
- mapEntity(entities);
216
- return entities;
217
- }
218
-
219
- entities.forEach(mapEntity);
220
-
221
- return entities;
222
- };
223
-
224
- BaseState.renameIdFiledName = renameIdFiledName;
225
-
226
17
  module.exports = BaseState;
@@ -1,3 +1,4 @@
1
+ /* eslint-disable no-async-promise-executor */
1
2
  /* eslint-disable no-await-in-loop */
2
3
  /* eslint-disable function-paren-newline */
3
4
  /* eslint-disable no-underscore-dangle */
@@ -5,6 +6,7 @@ const omit = require('lodash/omit');
5
6
  const uniq = require('lodash/uniq');
6
7
  const detectPort = require('detect-port');
7
8
  const Lock = require('@abtnode/util/lib/lock');
9
+ const security = require('@abtnode/util/lib/security');
8
10
  const { fixPerson, fixInterfaces } = require('@blocklet/meta/lib/fix');
9
11
  const {
10
12
  BlockletStatus,
@@ -27,6 +29,40 @@ const getMaxPort = (ports = {}) => Math.max(Object.values(ports).map(Number));
27
29
  const getExternalPortsFromMeta = (meta) =>
28
30
  (meta.interfaces || []).map((x) => x.port && x.port.external).filter(Boolean);
29
31
 
32
+ const formatBlocklet = (blocklet, phase, dek) => {
33
+ forEachBlocklet(
34
+ blocklet,
35
+ (b) => {
36
+ if (b.meta) {
37
+ fixPerson(b.meta);
38
+ fixInterfaces(b.meta);
39
+ }
40
+
41
+ b.children = b.children || [];
42
+
43
+ if (!b.environments || !b.meta || !dek) {
44
+ return;
45
+ }
46
+
47
+ ['BLOCKLET_APP_SK'].forEach((key) => {
48
+ const env = b.environments.find((x) => x.key === key);
49
+ if (!env) {
50
+ return;
51
+ }
52
+ if (phase === 'onUpdate' && env.value.indexOf('0x') === 0) {
53
+ env.value = security.encrypt(env.value, b.meta.did, dek);
54
+ }
55
+ if (phase === 'onRead' && env.value.indexOf('0x') === -1) {
56
+ env.value = security.decrypt(env.value, b.meta.did, dek);
57
+ }
58
+ });
59
+ },
60
+ { sync: true }
61
+ );
62
+
63
+ return blocklet;
64
+ };
65
+
30
66
  class BlockletState extends BaseState {
31
67
  /**
32
68
  * Creates an instance of BlockletState
@@ -48,14 +84,7 @@ class BlockletState extends BaseState {
48
84
  return reject(err);
49
85
  }
50
86
 
51
- if (doc) {
52
- // TODO: this only exists for backward compatible
53
- fixPerson(doc.meta);
54
- fixInterfaces(doc.meta);
55
- doc.children = doc.children || [];
56
- }
57
-
58
- return resolve(doc);
87
+ return resolve(doc ? formatBlocklet(doc, 'onRead', this.options.dek) : null);
59
88
  });
60
89
  });
61
90
  }
@@ -70,14 +99,7 @@ class BlockletState extends BaseState {
70
99
  return reject(err);
71
100
  }
72
101
 
73
- return resolve(
74
- docs.filter(Boolean).map((doc) => {
75
- // TODO: this only exists for backward compatible
76
- fixPerson(doc.meta);
77
- fixInterfaces(doc.meta);
78
- return doc;
79
- })
80
- );
102
+ return resolve(docs.filter(Boolean).map((doc) => formatBlocklet(doc, 'onRead', this.options.dek)));
81
103
  });
82
104
  });
83
105
  }
@@ -114,7 +136,6 @@ class BlockletState extends BaseState {
114
136
  } = {}) {
115
137
  return this.getBlocklet(did).then(
116
138
  (doc) =>
117
- // eslint-disable-next-line no-async-promise-executor
118
139
  new Promise(async (resolve, reject) => {
119
140
  if (doc) {
120
141
  reject(new Error('Blocklet already added'));
@@ -165,6 +186,26 @@ class BlockletState extends BaseState {
165
186
  );
166
187
  }
167
188
 
189
+ updateBlocklet(did, updates) {
190
+ return this.getBlocklet(did).then(
191
+ (doc) =>
192
+ new Promise(async (resolve, reject) => {
193
+ if (!doc) {
194
+ reject(new Error('Blocklet does not exist'));
195
+ return;
196
+ }
197
+
198
+ try {
199
+ const formatted = formatBlocklet(updates, 'onUpdate', this.options.dek);
200
+ const newDoc = await this.updateById(doc._id, { $set: formatted });
201
+ resolve(newDoc);
202
+ } catch (err) {
203
+ reject(err);
204
+ }
205
+ })
206
+ );
207
+ }
208
+
168
209
  upgradeBlocklet({ meta, source, deployedFrom, children } = {}) {
169
210
  return this.getBlocklet(meta.did).then(
170
211
  (doc) =>
@@ -1,4 +1,4 @@
1
- const BaseState = require('./base');
1
+ const stateFactory = require('@abtnode/db/lib/factory');
2
2
  const NodeState = require('./node');
3
3
  const ChallengeState = require('./challenge');
4
4
  const BlockletState = require('./blocklet');
@@ -12,8 +12,6 @@ const SessionState = require('./session');
12
12
  const ExtrasState = require('./blocklet-extras');
13
13
  const CacheState = require('./cache');
14
14
 
15
- const states = {};
16
-
17
15
  const init = (dataDirs, options) => {
18
16
  const notificationState = new NotificationState(dataDirs.core, options);
19
17
  const nodeState = new NodeState(dataDirs.core, options, dataDirs, notificationState);
@@ -28,7 +26,7 @@ const init = (dataDirs, options) => {
28
26
  const extrasState = new ExtrasState(dataDirs.core, options);
29
27
  const cacheState = new CacheState(dataDirs.core, options);
30
28
 
31
- Object.assign(states, {
29
+ return {
32
30
  node: nodeState,
33
31
  blocklet: blockletState,
34
32
  notification: notificationState,
@@ -41,22 +39,7 @@ const init = (dataDirs, options) => {
41
39
  session: sessionState,
42
40
  blockletExtras: extrasState,
43
41
  cache: cacheState,
44
- });
42
+ };
45
43
  };
46
44
 
47
- module.exports = new Proxy(
48
- {},
49
- {
50
- get(target, prop) {
51
- if (prop === 'init') {
52
- return init;
53
- }
54
-
55
- if (states[prop] instanceof BaseState) {
56
- return states[prop];
57
- }
58
-
59
- throw new Error(`State ${String(prop)} may not be initialized`);
60
- },
61
- }
62
- );
45
+ module.exports = stateFactory(init);
@@ -1,4 +1,5 @@
1
1
  /* eslint-disable no-underscore-dangle */
2
+ const semver = require('semver');
2
3
  const omit = require('lodash/omit');
3
4
  const isEqual = require('lodash/isEqual');
4
5
  const isEmpty = require('lodash/isEmpty');
@@ -163,7 +164,7 @@ class NodeState extends BaseState {
163
164
 
164
165
  cleanupDirtyUpgradeState() {
165
166
  return this.read().then((doc) => {
166
- if (doc.nextVersion === doc.version) {
167
+ if (doc.nextVersion && semver.lte(doc.nextVersion, doc.version)) {
167
168
  const updates = { nextVersion: '', upgradeSessionId: '' };
168
169
 
169
170
  // FIXME: this may cause the node exit some mode unexpectedly if it is not being upgraded
@@ -192,7 +192,6 @@ const fillBlockletConfigs = (blocklet, configs) => {
192
192
  acc[x.key] = x.value;
193
193
  return acc;
194
194
  }, {});
195
- blocklet.userEnvironments = blocklet.configObj; // deprecated
196
195
  blocklet.environmentObj = (blocklet.environments || []).reduce((acc, x) => {
197
196
  acc[x.key] = x.value;
198
197
  return acc;
@@ -308,6 +307,7 @@ const getRuntimeEnvironments = (blocklet, nodeEnvironments) => {
308
307
 
309
308
  return {
310
309
  ...blocklet.environmentObj,
310
+ ...blocklet.configObj,
311
311
  ...nodeEnvironments,
312
312
  ...safeNodeEnvironments,
313
313
  };
package/lib/util/index.js CHANGED
@@ -332,6 +332,8 @@ const getDataDirs = (dataDir) => ({
332
332
  tmp: path.join(dataDir, 'tmp'),
333
333
  blocklets: path.join(dataDir, 'blocklets'),
334
334
  services: path.join(dataDir, 'services'),
335
+ modules: path.join(dataDir, 'modules'),
336
+ certManagerModule: path.join(dataDir, 'modules', 'certificate-manager'),
335
337
  });
336
338
 
337
339
  // Ensure data dir for Blocklet Server exists
package/package.json CHANGED
@@ -3,7 +3,7 @@
3
3
  "publishConfig": {
4
4
  "access": "public"
5
5
  },
6
- "version": "1.6.4",
6
+ "version": "1.6.8",
7
7
  "description": "",
8
8
  "main": "lib/index.js",
9
9
  "files": [
@@ -19,26 +19,28 @@
19
19
  "author": "wangshijun <wangshijun2010@gmail.com> (http://github.com/wangshijun)",
20
20
  "license": "MIT",
21
21
  "dependencies": {
22
- "@abtnode/constant": "1.6.4",
23
- "@abtnode/cron": "1.6.4",
24
- "@abtnode/logger": "1.6.4",
25
- "@abtnode/queue": "1.6.4",
26
- "@abtnode/rbac": "1.6.4",
27
- "@abtnode/router-provider": "1.6.4",
28
- "@abtnode/static-server": "1.6.4",
29
- "@abtnode/timemachine": "1.6.4",
30
- "@abtnode/util": "1.6.4",
31
- "@arcblock/did": "^1.13.77",
32
- "@arcblock/event-hub": "1.13.77",
22
+ "@abtnode/certificate-manager": "1.6.8",
23
+ "@abtnode/constant": "1.6.8",
24
+ "@abtnode/cron": "1.6.8",
25
+ "@abtnode/db": "1.6.8",
26
+ "@abtnode/logger": "1.6.8",
27
+ "@abtnode/queue": "1.6.8",
28
+ "@abtnode/rbac": "1.6.8",
29
+ "@abtnode/router-provider": "1.6.8",
30
+ "@abtnode/static-server": "1.6.8",
31
+ "@abtnode/timemachine": "1.6.8",
32
+ "@abtnode/util": "1.6.8",
33
+ "@arcblock/did": "^1.13.79",
34
+ "@arcblock/event-hub": "1.13.79",
33
35
  "@arcblock/pm2-events": "^0.0.5",
34
- "@arcblock/vc": "^1.13.77",
35
- "@blocklet/meta": "1.6.4",
36
+ "@arcblock/vc": "^1.13.79",
37
+ "@blocklet/meta": "1.6.8",
36
38
  "@fidm/x509": "^1.2.1",
37
39
  "@nedb/core": "^1.2.2",
38
40
  "@nedb/multi": "^1.2.2",
39
- "@ocap/mcrypto": "^1.13.77",
40
- "@ocap/util": "^1.13.77",
41
- "@ocap/wallet": "^1.13.77",
41
+ "@ocap/mcrypto": "^1.13.79",
42
+ "@ocap/util": "^1.13.79",
43
+ "@ocap/wallet": "^1.13.79",
42
44
  "@slack/webhook": "^5.0.3",
43
45
  "axios": "^0.21.4",
44
46
  "axon": "^2.0.3",
@@ -51,7 +53,7 @@
51
53
  "is-base64": "^1.1.0",
52
54
  "is-ip": "^3.1.0",
53
55
  "is-url": "^1.2.4",
54
- "joi": "^17.4.0",
56
+ "joi": "^17.5.0",
55
57
  "js-yaml": "^3.14.0",
56
58
  "lodash": "^4.17.21",
57
59
  "lru-cache": "^6.0.0",
@@ -71,7 +73,7 @@
71
73
  "compression": "^1.7.4",
72
74
  "expand-tilde": "^2.0.2",
73
75
  "express": "^4.17.1",
74
- "jest": "^27.3.1"
76
+ "jest": "^27.4.5"
75
77
  },
76
- "gitHead": "1c144cb9fb9a9952bc92f25cabbdb47a378cbd24"
78
+ "gitHead": "f97ec3a44250e034ff4b5e3f088c1417f448a7bb"
77
79
  }