@abtnode/core 1.8.67 → 1.8.68-beta-500af7e5

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.
@@ -28,6 +28,7 @@ const lock = new Lock('blocklet-port-assign-lock');
28
28
 
29
29
  const isHex = (str) => /^0x[0-9a-f]+$/i.test(str);
30
30
  const getMaxPort = (ports = {}) => Math.max(Object.values(ports).map(Number));
31
+ const getConditions = (did) => [{ 'meta.did': did }, { appDid: did }, { appPid: did }];
31
32
 
32
33
  const getExternalPortsFromMeta = (meta) =>
33
34
  (meta.interfaces || []).map((x) => x.port && x.port.external).filter(Boolean);
@@ -48,7 +49,16 @@ const formatBlocklet = (blocklet, phase, dek) => {
48
49
  return;
49
50
  }
50
51
 
51
- ['BLOCKLET_APP_SK'].forEach((key) => {
52
+ (b.migratedFrom || []).forEach((x) => {
53
+ if (phase === 'onUpdate' && isHex(x.appSk) === true) {
54
+ x.appSk = security.encrypt(x.appSk, b.meta.did, dek);
55
+ }
56
+ if (phase === 'onRead' && isHex(x.appSk) === false) {
57
+ x.appSk = security.decrypt(x.appSk, b.meta.did, dek);
58
+ }
59
+ });
60
+
61
+ ['BLOCKLET_APP_SK', 'BLOCKLET_APP_PSK'].forEach((key) => {
52
62
  const env = b.environments.find((x) => x.key === key);
53
63
  if (!env) {
54
64
  return;
@@ -98,7 +108,7 @@ class BlockletState extends BaseState {
98
108
  resolve(null);
99
109
  }
100
110
 
101
- this.findOne({ $or: [{ 'meta.did': did }, { appDid: did }] }, (err, doc) => {
111
+ this.findOne({ $or: getConditions(did) }, (err, doc) => {
102
112
  if (err) {
103
113
  return reject(err);
104
114
  }
@@ -114,7 +124,7 @@ class BlockletState extends BaseState {
114
124
  resolve(null);
115
125
  }
116
126
 
117
- this.findOne({ $or: [{ 'meta.did': did }, { appDid: did }] }, (err, doc) => {
127
+ this.findOne({ $or: getConditions(did) }, (err, doc) => {
118
128
  if (err) {
119
129
  return reject(err);
120
130
  }
@@ -130,7 +140,7 @@ class BlockletState extends BaseState {
130
140
  resolve(null);
131
141
  }
132
142
 
133
- this.findOne({ $or: [{ 'meta.did': did }, { appDid: did }] }, { status: 1 }, (err, doc) => {
143
+ this.findOne({ $or: getConditions(did) }, { status: 1 }, (err, doc) => {
134
144
  if (err) {
135
145
  return reject(err);
136
146
  }
@@ -146,7 +156,7 @@ class BlockletState extends BaseState {
146
156
  resolve(false);
147
157
  }
148
158
 
149
- this.count({ $or: [{ 'meta.did': did }, { appDid: did }] }, (err, count) => {
159
+ this.count({ $or: getConditions(did) }, (err, count) => {
150
160
  if (err) {
151
161
  return reject(err);
152
162
  }
@@ -199,6 +209,9 @@ class BlockletState extends BaseState {
199
209
  deployedFrom = '',
200
210
  mode = BLOCKLET_MODES.PRODUCTION,
201
211
  children: rawChildren = [],
212
+ appPid = null, // the permanent appDid, which will not change after initial set
213
+ migratedFrom = [], // the complete migrate history
214
+ externalSk = false, // whether sk is managed by some party beside server, such as did-wallet
202
215
  } = {}) {
203
216
  return this.getBlocklet(meta.did).then(
204
217
  (exist) =>
@@ -229,6 +242,7 @@ class BlockletState extends BaseState {
229
242
 
230
243
  const data = {
231
244
  appDid: null, // will updated later when updating blocklet environments
245
+ appPid,
232
246
  mode,
233
247
  meta: sanitized,
234
248
  status,
@@ -237,6 +251,8 @@ class BlockletState extends BaseState {
237
251
  ports,
238
252
  environments: [],
239
253
  children,
254
+ migratedFrom,
255
+ externalSk,
240
256
  };
241
257
 
242
258
  // add to db
@@ -124,7 +124,7 @@ class NodeState extends BaseState {
124
124
  routing,
125
125
  docker,
126
126
  mode,
127
- enableWelcomePage: true,
127
+ enableWelcomePage: mode !== NODE_MODES.SERVERLESS,
128
128
  runtimeConfig,
129
129
  ownerNft,
130
130
  diskAlertThreshold: DISK_ALERT_THRESHOLD_PERCENT,
@@ -310,7 +310,10 @@ class NodeState extends BaseState {
310
310
  }
311
311
 
312
312
  async updateGateway(gateway) {
313
- const [, nodeInfo] = await this.update({}, { $set: { 'routing.requestLimit': gateway.requestLimit } });
313
+ const [, nodeInfo] = await this.update(
314
+ {},
315
+ { $set: { 'routing.requestLimit': gateway.requestLimit, 'routing.cacheEnabled': gateway.cacheEnabled } }
316
+ );
314
317
 
315
318
  this.emit(EVENTS.RELOAD_GATEWAY, nodeInfo);
316
319
 
@@ -31,7 +31,12 @@ const getFolderSize = require('@abtnode/util/lib/get-folder-size');
31
31
  const normalizePathPrefix = require('@abtnode/util/lib/normalize-path-prefix');
32
32
  const hashFiles = require('@abtnode/util/lib/hash-files');
33
33
  const isPathPrefixEqual = require('@abtnode/util/lib/is-path-prefix-equal');
34
- const { BLOCKLET_MAX_MEM_LIMIT_IN_MB, BLOCKLET_STORE, BLOCKLET_INSTALL_TYPE } = require('@abtnode/constant');
34
+ const {
35
+ BLOCKLET_MAX_MEM_LIMIT_IN_MB,
36
+ BLOCKLET_STORE,
37
+ BLOCKLET_INSTALL_TYPE,
38
+ BLOCKLET_STORE_DEV,
39
+ } = require('@abtnode/constant');
35
40
  const formatBackSlash = require('@abtnode/util/lib/format-back-slash');
36
41
 
37
42
  const SCRIPT_ENGINES_WHITE_LIST = ['npm', 'npx', 'pnpm', 'yarn'];
@@ -89,6 +94,7 @@ const {
89
94
  validateBlockletMeta,
90
95
  prettyURL,
91
96
  getNFTState,
97
+ templateReplace,
92
98
  } = require('./index');
93
99
 
94
100
  const getComponentConfig = (meta) => meta.components || meta.children;
@@ -235,12 +241,12 @@ const getComponentDirs = (
235
241
  const fillBlockletConfigs = (blocklet, configs) => {
236
242
  blocklet.configs = configs || [];
237
243
  blocklet.configObj = blocklet.configs.reduce((acc, x) => {
238
- acc[x.key] = x.value;
244
+ acc[x.key] = templateReplace(x.value, blocklet);
239
245
  return acc;
240
246
  }, {});
241
247
  blocklet.environments = blocklet.environments || [];
242
248
  blocklet.environmentObj = blocklet.environments.reduce((acc, x) => {
243
- acc[x.key] = x.value;
249
+ acc[x.key] = templateReplace(x.value, blocklet);
244
250
  return acc;
245
251
  }, {});
246
252
  };
@@ -299,10 +305,16 @@ const getAppSystemEnvironments = (blocklet, nodeInfo) => {
299
305
  })}`;
300
306
  }
301
307
 
308
+ const isMigrated = Array.isArray(blocklet.migratedFrom) && blocklet.migratedFrom.length > 0;
309
+ const appPid = blocklet.appPid || appId;
310
+ const appPsk = isMigrated ? blocklet.migratedFrom[0].appSk : appSk;
311
+
302
312
  return {
303
313
  BLOCKLET_DID: did,
304
314
  BLOCKLET_APP_SK: appSk,
305
315
  BLOCKLET_APP_ID: appId,
316
+ BLOCKLET_APP_PSK: appPsk, // permanent sk even the blocklet has been migrated
317
+ BLOCKLET_APP_PID: appPid, // permanent did even the blocklet has been migrated
306
318
  BLOCKLET_APP_NAME: appName,
307
319
  BLOCKLET_APP_DESCRIPTION: appDescription,
308
320
  BLOCKLET_APP_URL: appUrl,
@@ -835,7 +847,7 @@ const parseChildrenFromMeta = async (src, context = {}) => {
835
847
  };
836
848
 
837
849
  const validateBlocklet = (blocklet) =>
838
- forEachBlocklet(blocklet, (b) => {
850
+ forEachBlocklet(blocklet, async (b) => {
839
851
  isRequirementsSatisfied(b.meta.requirements);
840
852
  validateEngine(getBlockletEngineNameByPlatform(b.meta));
841
853
  });
@@ -1400,12 +1412,14 @@ const getBlocklet = async ({
1400
1412
 
1401
1413
  blocklet.settings.storeList = blocklet.settings.storeList || [];
1402
1414
 
1403
- if (!blocklet.settings.storeList.find((x) => x.url === BLOCKLET_STORE.url)) {
1404
- blocklet.settings.storeList.unshift({
1405
- ...BLOCKLET_STORE,
1406
- protected: true,
1407
- });
1408
- }
1415
+ [BLOCKLET_STORE_DEV, BLOCKLET_STORE].forEach((store) => {
1416
+ if (!blocklet.settings.storeList.find((x) => x.url === store.url)) {
1417
+ blocklet.settings.storeList.unshift({
1418
+ ...store,
1419
+ protected: true,
1420
+ });
1421
+ }
1422
+ });
1409
1423
 
1410
1424
  // app site
1411
1425
  blocklet.site = await states.site.findOneByBlocklet(blocklet.meta.did);
@@ -1547,11 +1561,63 @@ const createDataArchive = (dataDir, fileName) => {
1547
1561
  });
1548
1562
  };
1549
1563
 
1564
+ const isBlockletAppSkUsed = ({ environments, migratedFrom = [] }, appSk) => {
1565
+ const isUsedInEnv = environments.find((e) => e.key === BLOCKLET_CONFIGURABLE_KEY.BLOCKLET_APP_SK)?.value === appSk;
1566
+ const isUsedInHistory = migratedFrom.some((x) => x.appSk === appSk);
1567
+ return isUsedInEnv || isUsedInHistory;
1568
+ };
1569
+
1570
+ const isRotatingAppSk = (newConfigs, oldConfigs, externalSk) => {
1571
+ const newSk = newConfigs.find((x) => BLOCKLET_CONFIGURABLE_KEY.BLOCKLET_APP_SK === x.key);
1572
+ if (!newSk) {
1573
+ // If no newSk found, we are not rotating the appSk
1574
+ return false;
1575
+ }
1576
+
1577
+ const oldSk = oldConfigs.find((x) => BLOCKLET_CONFIGURABLE_KEY.BLOCKLET_APP_SK === x.key);
1578
+ if (!oldSk) {
1579
+ // If we have no oldSk, we are setting the initial appSk for external managed apps
1580
+ // If we have no oldSk, but we are not external managed apps, we are rotating the appSk
1581
+ return !externalSk;
1582
+ }
1583
+
1584
+ // Otherwise, we must be rotating the appSk
1585
+ // eslint-disable-next-line sonarjs/prefer-single-boolean-return
1586
+ if (oldSk.value !== newSk.value) {
1587
+ return true;
1588
+ }
1589
+
1590
+ return false;
1591
+ };
1592
+
1593
+ const isRotatingAppDid = (newConfigs, oldConfigs, externalSk) => {
1594
+ if (isRotatingAppSk(newConfigs, oldConfigs, externalSk)) {
1595
+ return true;
1596
+ }
1597
+
1598
+ const newType = newConfigs.find((x) => BLOCKLET_CONFIGURABLE_KEY.BLOCKLET_WALLET_TYPE === x.key);
1599
+ const oldType = oldConfigs.find((x) => BLOCKLET_CONFIGURABLE_KEY.BLOCKLET_WALLET_TYPE === x.key);
1600
+ if (!newType) {
1601
+ return false;
1602
+ }
1603
+
1604
+ if (!oldType) {
1605
+ return true;
1606
+ }
1607
+
1608
+ // eslint-disable-next-line sonarjs/prefer-single-boolean-return
1609
+ if (oldType !== newType) {
1610
+ return true;
1611
+ }
1612
+
1613
+ return false;
1614
+ };
1615
+
1550
1616
  /**
1551
1617
  * this function has side effect on config.value
1552
1618
  * @param {{ key: string, value?: string }} config
1553
1619
  */
1554
- const validateAppConfig = async (config, blockletDid, states) => {
1620
+ const validateAppConfig = async (config, states) => {
1555
1621
  const x = config;
1556
1622
 
1557
1623
  // sk should be force secured while other app prop should not be secured
@@ -1569,15 +1635,10 @@ const validateAppConfig = async (config, blockletDid, states) => {
1569
1635
  }
1570
1636
  }
1571
1637
 
1572
- // Ensure sk is not used by other blocklets, otherwise we may encounter appDid collision
1638
+ // Ensure sk is not used by existing blocklets, otherwise we may encounter appDid collision
1573
1639
  const blocklets = await states.blocklet.getBlocklets({});
1574
- const others = blocklets.filter((b) => b.meta.did !== blockletDid);
1575
- if (
1576
- others.some(
1577
- (b) => b.environments.find((e) => e.key === BLOCKLET_CONFIGURABLE_KEY.BLOCKLET_APP_SK).value === x.value
1578
- )
1579
- ) {
1580
- throw new Error('Invalid custom blocklet secret key: already used by another blocklet');
1640
+ if (blocklets.some((b) => isBlockletAppSkUsed(b, x.value))) {
1641
+ throw new Error('Invalid custom blocklet secret key: already used by existing blocklet');
1581
1642
  }
1582
1643
  } else {
1583
1644
  delete x.value;
@@ -1690,6 +1751,32 @@ const checkDuplicateMountPoint = (blocklet, mountPoint) => {
1690
1751
  }
1691
1752
  };
1692
1753
 
1754
+ const validateStore = (nodeInfo, storeUrl) => {
1755
+ if (nodeInfo.mode !== 'serverless') {
1756
+ return;
1757
+ }
1758
+
1759
+ const inStoreList = nodeInfo.blockletRegistryList.find((item) => {
1760
+ const itemURLObj = new URL(item.url);
1761
+ const storeUrlObj = new URL(storeUrl);
1762
+
1763
+ return itemURLObj.host === storeUrlObj.host;
1764
+ });
1765
+
1766
+ if (!inStoreList) {
1767
+ throw new Error('Must be installed from the compliant blocklet store list');
1768
+ }
1769
+ };
1770
+
1771
+ const validateInServerless = ({ blockletMeta }) => {
1772
+ const { interfaces } = blockletMeta;
1773
+ const externalPortInterfaces = (interfaces || []).filter((item) => !!item.port?.external);
1774
+
1775
+ if (externalPortInterfaces.length > 0) {
1776
+ throw new Error('Blocklets with exposed ports cannot be installed');
1777
+ }
1778
+ };
1779
+
1693
1780
  module.exports = {
1694
1781
  consumeServerlessNFT,
1695
1782
  forEachBlocklet,
@@ -1735,6 +1822,11 @@ module.exports = {
1735
1822
  getConfigFromPreferences,
1736
1823
  createDataArchive,
1737
1824
  validateAppConfig,
1825
+ isBlockletAppSkUsed,
1826
+ isRotatingAppSk,
1827
+ isRotatingAppDid,
1738
1828
  checkDuplicateAppSk,
1739
1829
  checkDuplicateMountPoint,
1830
+ validateStore,
1831
+ validateInServerless,
1740
1832
  };
package/lib/util/index.js CHANGED
@@ -27,6 +27,7 @@ const {
27
27
  DEFAULT_HTTP_PORT,
28
28
  DEFAULT_HTTPS_PORT,
29
29
  SLOT_FOR_IP_DNS_SITE,
30
+ NODE_MODES,
30
31
  } = require('@abtnode/constant');
31
32
 
32
33
  const DEFAULT_WELLKNOWN_PORT = 8088;
@@ -452,6 +453,27 @@ const prettyURL = (url, isHttps = true) => {
452
453
  return isHttps ? `https://${url}` : `http://${url}`;
453
454
  };
454
455
 
456
+ const templateReplace = (str, vars = {}) => {
457
+ if (typeof str === 'string') {
458
+ return str.replace(/{([.\w]+)}/g, (m, key) => get(vars, key));
459
+ }
460
+
461
+ return str;
462
+ };
463
+
464
+ const isGatewayCacheEnabled = (info) => {
465
+ if (info.mode === NODE_MODES.DEBUG) {
466
+ return false;
467
+ }
468
+
469
+ const cacheEnabled = get(info, 'routing.cacheEnabled');
470
+ if (typeof cacheEnabled === 'boolean') {
471
+ return cacheEnabled;
472
+ }
473
+
474
+ return true;
475
+ };
476
+
455
477
  const lib = {
456
478
  validateOwner,
457
479
  getProviderFromNodeInfo,
@@ -489,6 +511,8 @@ const lib = {
489
511
  getNFTState,
490
512
  getServerDidDomain,
491
513
  prettyURL,
514
+ templateReplace,
515
+ isGatewayCacheEnabled,
492
516
  };
493
517
 
494
518
  module.exports = lib;
@@ -52,6 +52,7 @@ const updateGatewaySchema = Joi.object({
52
52
  .when('requestLimit.enabled', { is: true, then: Joi.required() }),
53
53
  ipHeader: Joi.string().allow('').trim(),
54
54
  }),
55
+ cacheEnabled: Joi.bool().optional().default(true),
55
56
  });
56
57
 
57
58
  module.exports = {
@@ -5,7 +5,7 @@ const checkURLAccessible = require('@abtnode/util/lib/url-evaluation/check-acces
5
5
  const { EVENTS } = require('@abtnode/constant');
6
6
  const WebHookSender = require('./sender');
7
7
  const WalletSender = require('./sender/wallet');
8
- const createQueue = require('../queue');
8
+ const createQueue = require('../util/queue');
9
9
  const IP = require('../util/ip');
10
10
  const states = require('../states');
11
11
  const { getBaseUrls } = require('../util');
package/package.json CHANGED
@@ -3,7 +3,7 @@
3
3
  "publishConfig": {
4
4
  "access": "public"
5
5
  },
6
- "version": "1.8.67",
6
+ "version": "1.8.68-beta-500af7e5",
7
7
  "description": "",
8
8
  "main": "lib/index.js",
9
9
  "files": [
@@ -19,33 +19,33 @@
19
19
  "author": "wangshijun <wangshijun2010@gmail.com> (http://github.com/wangshijun)",
20
20
  "license": "MIT",
21
21
  "dependencies": {
22
- "@abtnode/auth": "1.8.67",
23
- "@abtnode/certificate-manager": "1.8.67",
24
- "@abtnode/constant": "1.8.67",
25
- "@abtnode/cron": "1.8.67",
26
- "@abtnode/db": "1.8.67",
27
- "@abtnode/logger": "1.8.67",
28
- "@abtnode/queue": "1.8.67",
29
- "@abtnode/rbac": "1.8.67",
30
- "@abtnode/router-provider": "1.8.67",
31
- "@abtnode/static-server": "1.8.67",
32
- "@abtnode/timemachine": "1.8.67",
33
- "@abtnode/util": "1.8.67",
34
- "@arcblock/did": "1.18.42",
22
+ "@abtnode/auth": "1.8.68-beta-500af7e5",
23
+ "@abtnode/certificate-manager": "1.8.68-beta-500af7e5",
24
+ "@abtnode/constant": "1.8.68-beta-500af7e5",
25
+ "@abtnode/cron": "1.8.68-beta-500af7e5",
26
+ "@abtnode/db": "1.8.68-beta-500af7e5",
27
+ "@abtnode/logger": "1.8.68-beta-500af7e5",
28
+ "@abtnode/queue": "1.8.68-beta-500af7e5",
29
+ "@abtnode/rbac": "1.8.68-beta-500af7e5",
30
+ "@abtnode/router-provider": "1.8.68-beta-500af7e5",
31
+ "@abtnode/static-server": "1.8.68-beta-500af7e5",
32
+ "@abtnode/timemachine": "1.8.68-beta-500af7e5",
33
+ "@abtnode/util": "1.8.68-beta-500af7e5",
34
+ "@arcblock/did": "1.18.57",
35
35
  "@arcblock/did-motif": "^1.1.10",
36
- "@arcblock/did-util": "1.18.42",
37
- "@arcblock/event-hub": "1.18.42",
38
- "@arcblock/jwt": "^1.18.42",
36
+ "@arcblock/did-util": "1.18.57",
37
+ "@arcblock/event-hub": "1.18.57",
38
+ "@arcblock/jwt": "^1.18.57",
39
39
  "@arcblock/pm2-events": "^0.0.5",
40
- "@arcblock/vc": "1.18.42",
41
- "@blocklet/constant": "1.8.67",
42
- "@blocklet/meta": "1.8.67",
43
- "@blocklet/sdk": "1.8.67",
44
- "@did-space/client": "^0.1.66",
40
+ "@arcblock/vc": "1.18.57",
41
+ "@blocklet/constant": "1.8.68-beta-500af7e5",
42
+ "@blocklet/meta": "1.8.68-beta-500af7e5",
43
+ "@blocklet/sdk": "1.8.68-beta-500af7e5",
44
+ "@did-space/client": "0.1.87-beta-1",
45
45
  "@fidm/x509": "^1.2.1",
46
- "@ocap/mcrypto": "1.18.42",
47
- "@ocap/util": "1.18.42",
48
- "@ocap/wallet": "1.18.42",
46
+ "@ocap/mcrypto": "1.18.57",
47
+ "@ocap/util": "1.18.57",
48
+ "@ocap/wallet": "1.18.57",
49
49
  "@slack/webhook": "^5.0.4",
50
50
  "archiver": "^5.3.1",
51
51
  "axios": "^0.27.2",
@@ -72,7 +72,6 @@
72
72
  "pm2": "^5.2.0",
73
73
  "semver": "^7.3.8",
74
74
  "shelljs": "^0.8.5",
75
- "slugify": "^1.6.5",
76
75
  "ssri": "^8.0.1",
77
76
  "stream-throttle": "^0.1.3",
78
77
  "stream-to-promise": "^3.0.0",
@@ -90,5 +89,5 @@
90
89
  "express": "^4.18.2",
91
90
  "jest": "^27.5.1"
92
91
  },
93
- "gitHead": "543dbadffd29dc4f096261e136a2a306885d6508"
92
+ "gitHead": "9070621373f317a10ff0d289323bf725e30d3521"
94
93
  }
File without changes