@abtnode/core 1.8.65-beta-5405baf2 → 1.8.65-beta-bfcc12ce

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.
@@ -7,7 +7,7 @@ const get = require('lodash/get');
7
7
  const cloneDeep = require('lodash/cloneDeep');
8
8
  const isEqual = require('lodash/isEqual');
9
9
  const joinUrl = require('url-join');
10
- const { replaceSlotToIp } = require('@blocklet/meta/lib/util');
10
+ const { replaceSlotToIp, findComponentById, findWebInterface } = require('@blocklet/meta/lib/util');
11
11
  const { getProvider } = require('@abtnode/router-provider');
12
12
  const normalizePathPrefix = require('@abtnode/util/lib/normalize-path-prefix');
13
13
  const getTmpDir = require('@abtnode/util/lib/get-tmp-directory');
@@ -21,6 +21,7 @@ const {
21
21
  DOMAIN_FOR_INTERNAL_SITE,
22
22
  WELLKNOWN_PATH_PREFIX,
23
23
  WELLKNOWN_SERVICE_PATH_PREFIX,
24
+ USER_AVATAR_PATH_PREFIX,
24
25
  DOMAIN_FOR_IP_SITE,
25
26
  NAME_FOR_WELLKNOWN_SITE,
26
27
  DEFAULT_HTTP_PORT,
@@ -40,9 +41,11 @@ const {
40
41
  const {
41
42
  BLOCKLET_DYNAMIC_PATH_PREFIX,
42
43
  BLOCKLET_INTERFACE_TYPE_WEB,
44
+ BLOCKLET_INTERFACE_PUBLIC,
43
45
  BLOCKLET_INTERFACE_WELLKNOWN,
44
46
  BLOCKLET_INTERFACE_TYPE_WELLKNOWN,
45
47
  BlockletEvents,
48
+ BLOCKLET_MODES,
46
49
  } = require('@blocklet/constant');
47
50
 
48
51
  // eslint-disable-next-line global-require
@@ -205,11 +208,17 @@ const ensureLatestInterfaceInfo = async (sites = []) => {
205
208
  }
206
209
 
207
210
  site.rules = site.rules.map((rule) => {
211
+ if (rule.dynamic) {
212
+ return rule;
213
+ }
208
214
  // If a rule already has a target and target is WELLKNOWN_SERVICE_PATH_PREFIX, just return
209
215
  // Indicates that the rule id generated by the system for auth service
210
216
  if (rule.isProtected && rule.to.target === WELLKNOWN_SERVICE_PATH_PREFIX) {
211
217
  return rule;
212
218
  }
219
+ if (rule.isProtected && rule.to.target === joinUrl(WELLKNOWN_SERVICE_PATH_PREFIX, USER_AVATAR_PATH_PREFIX)) {
220
+ return rule;
221
+ }
213
222
 
214
223
  const { did, interfaceName } = rule.to;
215
224
  if (interfaces[did] && interfaces[did][interfaceName]) {
@@ -273,7 +282,21 @@ const ensureWellknownRule = async (sites) => {
273
282
  if (!site.rules.some((x) => x.from.pathPrefix === servicePathPrefix)) {
274
283
  const rule = cloneDeep(rootBlockletRule || blockletRules[0]);
275
284
  rule.from.pathPrefix = servicePathPrefix;
285
+ rule.to.target = servicePathPrefix;
276
286
  rule.isProtected = true;
287
+ rule.dynamic = true; // mark as dynamic to avoid redundant generated rules
288
+ site.rules.push(rule);
289
+ }
290
+
291
+ // Cache user avatar in nginx
292
+ const avatarPathPrefix = joinUrl(servicePathPrefix, USER_AVATAR_PATH_PREFIX);
293
+ if (!site.rules.some((x) => x.from.pathPrefix === avatarPathPrefix)) {
294
+ const rule = cloneDeep(rootBlockletRule || blockletRules[0]);
295
+ rule.from.pathPrefix = avatarPathPrefix;
296
+ rule.to.cacheGroup = 'blockletProxy';
297
+ rule.to.target = avatarPathPrefix;
298
+ rule.isProtected = true;
299
+ rule.dynamic = true; // mark as dynamic to avoid redundant generated rules
277
300
  site.rules.push(rule);
278
301
  }
279
302
  }
@@ -296,7 +319,7 @@ const ensureBlockletDid = async (sites) => {
296
319
  return site;
297
320
  }
298
321
 
299
- site.blockletDid = site.domain.replace(BLOCKLET_SITE_GROUP_SUFFIX, '');
322
+ site.blockletDid = getDidFromDomainGroupName(site.domain);
300
323
 
301
324
  return site;
302
325
  });
@@ -313,25 +336,76 @@ const ensureCorsForWebWallet = async (sites) => {
313
336
  return sites;
314
337
  };
315
338
 
316
- const filterSitesForRemovedBlocklets = async (sites = []) => {
317
- const blocklets = await states.blocklet.getBlocklets();
339
+ const filterSitesForRemovedBlocklets = async (sites = [], blocklets) => {
318
340
  return sites.filter((site) => {
319
341
  if (!site.domain.endsWith(BLOCKLET_SITE_GROUP_SUFFIX)) {
320
342
  return true;
321
343
  }
322
344
 
323
- const did = getDidFromDomainGroupName(site.domain);
324
- return blocklets.some((x) => x.meta.did === did);
345
+ const blocklet = blocklets.find((x) => x.meta.did === site.blockletDid);
346
+ return !!blocklet;
325
347
  });
326
348
  };
327
349
 
350
+ const ensureBlockletCache = async (sites = [], blocklets) => {
351
+ return sites
352
+ .map((site) => {
353
+ if (!site.domain.endsWith(BLOCKLET_SITE_GROUP_SUFFIX)) {
354
+ return site;
355
+ }
356
+
357
+ if (site.cacheableGenerated) {
358
+ return site;
359
+ }
360
+
361
+ // For each rule, get component, check cacheable, clone and push new rule
362
+ const blocklet = blocklets.find((x) => x.meta.did === site.blockletDid);
363
+ const cacheRules = [];
364
+ site.rules
365
+ .filter(
366
+ (x) =>
367
+ x.to.type === ROUTING_RULE_TYPES.BLOCKLET &&
368
+ x.to.interfaceName === BLOCKLET_INTERFACE_PUBLIC &&
369
+ x.from.pathPrefix.startsWith(WELLKNOWN_SERVICE_PATH_PREFIX) === false
370
+ )
371
+ .forEach((rule) => {
372
+ const component = findComponentById(blocklet, rule.to.componentId);
373
+ if (component.mode !== BLOCKLET_MODES.PRODUCTION) {
374
+ return;
375
+ }
376
+ const cacheable = get(findWebInterface(component), 'cacheable', []);
377
+ cacheable.forEach((cachePrefix) => {
378
+ const clone = cloneDeep(rule);
379
+ clone.from.pathPrefix = joinUrl(rule.from.pathPrefix, cachePrefix);
380
+ clone.to.cacheGroup = 'blockletProxy';
381
+ clone.to.target = cachePrefix;
382
+ clone.dynamic = true; // mark as dynamic to avoid redundant generated rules
383
+ cacheRules.push(clone);
384
+ });
385
+ });
386
+
387
+ site.rules = site.rules.concat(cacheRules);
388
+ site.mode = blocklet.mode;
389
+ site.cacheableGenerated = true;
390
+
391
+ return site;
392
+ })
393
+ .filter(Boolean);
394
+ };
395
+
328
396
  const ensureLatestInfo = async (sites = [], { withDefaultCors = true } = {}) => {
397
+ const blocklets = await states.blocklet.getBlocklets();
398
+
399
+ // CAUTION: following steps are very important, please do not change the order
329
400
  let result = await ensureLatestNodeInfo(sites, { withDefaultCors });
330
401
  result = await ensureBlockletDid(result);
402
+ result = await filterSitesForRemovedBlocklets(sites, blocklets);
403
+ result = await ensureBlockletCache(result, blocklets);
331
404
  result = await ensureWellknownRule(result);
332
405
  result = await ensureCorsForWebWallet(result);
406
+ result = await ensureLatestInterfaceInfo(result);
333
407
 
334
- return ensureLatestInterfaceInfo(result);
408
+ return result;
335
409
  };
336
410
 
337
411
  const decompressCertificates = async (source, dest) => {
@@ -1043,7 +1117,6 @@ module.exports = function getRouterHelpers({ dataDirs, routingSnapshot, routerMa
1043
1117
  try {
1044
1118
  const info = await nodeState.read();
1045
1119
  let { sites } = await readRoutingSites();
1046
- sites = await filterSitesForRemovedBlocklets(sites);
1047
1120
  sites = await ensureLatestInfo(sites);
1048
1121
  sites = await ensureServiceRule(sites);
1049
1122
  sites = await ensureRootRule(sites);
@@ -1125,7 +1198,7 @@ module.exports = function getRouterHelpers({ dataDirs, routingSnapshot, routerMa
1125
1198
  // Ensure we have system rules for blocklets
1126
1199
  const blocklets = await blockletState.getBlocklets();
1127
1200
  const ensureBlocklet = async (x) => {
1128
- const blocklet = await blockletManager.ensureBlocklet(x.meta.did);
1201
+ const blocklet = await blockletManager.getBlocklet(x.meta.did);
1129
1202
  return ensureBlockletRouting(blocklet, context);
1130
1203
  };
1131
1204
  const ensureBlockletResults = await Promise.all(blocklets.map((x) => ensureBlocklet(x)));
@@ -10,7 +10,7 @@ const {
10
10
  BLOCKLET_SITE_GROUP_SUFFIX,
11
11
  GATEWAY_REQ_LIMIT,
12
12
  } = require('@abtnode/constant');
13
- const { BLOCKLET_UI_INTERFACES } = require('@blocklet/constant');
13
+ const { BLOCKLET_UI_INTERFACES, BLOCKLET_MODES } = require('@blocklet/constant');
14
14
  const logger = require('@abtnode/logger')('@abtnode/core:router');
15
15
 
16
16
  const expandSites = (sites = []) => {
@@ -192,6 +192,10 @@ Router.formatSites = (sites = []) => {
192
192
  return;
193
193
  }
194
194
 
195
+ if (rule.dynamic) {
196
+ return;
197
+ }
198
+
195
199
  if (daemonRule) {
196
200
  // Serve meta js: both prefix and suffix do not contain trailing slash
197
201
  // NOTICE: 这里隐含了一个约定
@@ -208,6 +212,7 @@ Router.formatSites = (sites = []) => {
208
212
  port: daemonRule.to.port,
209
213
  did: rule.to.did,
210
214
  componentId: rule.to.componentId,
215
+ cacheGroup: site.mode === BLOCKLET_MODES.PRODUCTION ? 'blockletJs' : '',
211
216
  },
212
217
  });
213
218
  site.rules.push({
@@ -221,6 +226,7 @@ Router.formatSites = (sites = []) => {
221
226
  port: daemonRule.to.port,
222
227
  did: rule.to.did,
223
228
  componentId: rule.to.componentId,
229
+ cacheGroup: site.mode === BLOCKLET_MODES.PRODUCTION ? 'blockletJs' : '',
224
230
  },
225
231
  });
226
232
 
@@ -233,6 +239,7 @@ Router.formatSites = (sites = []) => {
233
239
  did: rule.to.did,
234
240
  type: ROUTING_RULE_TYPES.DAEMON,
235
241
  target: BLOCKLET_PROXY_PATH_PREFIX,
242
+ cacheGroup: site.mode === BLOCKLET_MODES.PRODUCTION ? 'blockletProxy' : '',
236
243
  },
237
244
  });
238
245
  }
@@ -53,6 +53,9 @@ const formatBlocklet = (blocklet, phase, dek) => {
53
53
  if (!env) {
54
54
  return;
55
55
  }
56
+ // salt in blocklet state is different from the salt in blocklet-extra state
57
+ // in blocklet-extra state, salt is app meta did in each component
58
+ // in blocklet state, salt is component meta did in each component
56
59
  if (phase === 'onUpdate' && isHex(env.value) === true) {
57
60
  env.value = security.encrypt(env.value, b.meta.did, dek);
58
61
  }
@@ -89,7 +92,7 @@ class BlockletState extends BaseState {
89
92
  this.defaultPort = config.blockletPort || 5555;
90
93
  }
91
94
 
92
- getBlocklet(did) {
95
+ getBlocklet(did, { decryptSk = true } = {}) {
93
96
  return new Promise((resolve, reject) => {
94
97
  if (!did) {
95
98
  resolve(null);
@@ -100,7 +103,7 @@ class BlockletState extends BaseState {
100
103
  return reject(err);
101
104
  }
102
105
 
103
- return resolve(doc ? formatBlocklet(doc, 'onRead', this.config.dek) : null);
106
+ return resolve(doc ? formatBlocklet(doc, 'onRead', decryptSk ? this.config.dek : null) : null);
104
107
  });
105
108
  });
106
109
  }
@@ -142,8 +142,9 @@ const PRIVATE_NODE_ENVS = [
142
142
  */
143
143
  const getComponentDirs = (
144
144
  component,
145
- { dataDirs, ensure = false, e2eMode = false, validate = true, ancestors = [] } = {}
145
+ { dataDirs, ensure = false, e2eMode = false, validate = false, ancestors = [] } = {}
146
146
  ) => {
147
+ // FIXME 这个函数做了太多的事
147
148
  // get data dirs
148
149
 
149
150
  const { name: appName } = ancestors.concat(component)[0].meta;
@@ -930,7 +931,7 @@ const verifyIntegrity = async ({ file, integrity: expected }) => {
930
931
 
931
932
  /**
932
933
  * @param {string} installDir
933
- * @returns {Array<{ key: <[scope/]name/version>, dir: appDir }>}
934
+ * @returns {Promise<Array<{ key: string, dir: string }>>} key is <[scope/]name/version>, dir is appDir
934
935
  */
935
936
  const getAppDirs = async (installDir) => {
936
937
  const appDirs = [];
@@ -1360,9 +1361,8 @@ const getBlocklet = async ({
1360
1361
  dataDirs,
1361
1362
  states,
1362
1363
  e2eMode = false,
1363
- validateEnv = true,
1364
1364
  throwOnNotExist = true,
1365
- ensureDirs = true,
1365
+ ensureIntegrity = false,
1366
1366
  } = {}) => {
1367
1367
  if (!did) {
1368
1368
  throw new Error('Blocklet did does not exist');
@@ -1381,7 +1381,7 @@ const getBlocklet = async ({
1381
1381
 
1382
1382
  const blocklet = await states.blocklet.getBlocklet(did);
1383
1383
  if (!blocklet) {
1384
- if (throwOnNotExist) {
1384
+ if (throwOnNotExist || ensureIntegrity) {
1385
1385
  throw new Error(`can not find blocklet in database by did ${did}`);
1386
1386
  }
1387
1387
  return null;
@@ -1418,8 +1418,8 @@ const getBlocklet = async ({
1418
1418
  processId: getComponentProcessId(component, ancestors),
1419
1419
  ...getComponentDirs(component, {
1420
1420
  dataDirs,
1421
- ensure: ensureDirs,
1422
- validate: validateEnv,
1421
+ ensure: ensureIntegrity,
1422
+ validate: ensureIntegrity,
1423
1423
  ancestors,
1424
1424
  e2eMode: level === 0 ? e2eMode : false,
1425
1425
  }),
@@ -1554,6 +1554,9 @@ const createDataArchive = (dataDir, fileName) => {
1554
1554
  const validateAppConfig = async (config, blockletDid, states) => {
1555
1555
  const x = config;
1556
1556
 
1557
+ // sk should be force secured while other app prop should not be secured
1558
+ config.secure = x.key === BLOCKLET_CONFIGURABLE_KEY.BLOCKLET_APP_SK;
1559
+
1557
1560
  if (x.key === BLOCKLET_CONFIGURABLE_KEY.BLOCKLET_APP_SK) {
1558
1561
  if (x.value) {
1559
1562
  try {
@@ -1,6 +1,6 @@
1
1
  /* eslint-disable newline-per-chained-call */
2
2
  const Joi = require('joi');
3
- const { DOMAIN_FOR_DEFAULT_SITE, ROUTING_RULE_TYPES } = require('@abtnode/constant');
3
+ const { DOMAIN_FOR_DEFAULT_SITE, ROUTING_RULE_TYPES, ROUTER_CACHE_GROUPS } = require('@abtnode/constant');
4
4
  const { getMultipleLangParams } = require('./util');
5
5
 
6
6
  const WILDCARD_DOMAIN_REGEX = /^\*.(?:[a-z0-9](?:[a-z0-9-]{0,61}[a-z0-9])?\.)+[a-z0-9][a-z0-9-]{0,61}[a-z0-9]/;
@@ -62,6 +62,12 @@ const ruleSchema = {
62
62
  then: Joi.required(),
63
63
  }),
64
64
  componentId: Joi.string().label('component id'), // component global id
65
+ // FUTURE: blocklets can register routing rules for provider cache
66
+ cacheGroup: Joi.string()
67
+ .label('cache group')
68
+ .valid(...Object.keys(ROUTER_CACHE_GROUPS))
69
+ .allow('')
70
+ .default(''),
65
71
  },
66
72
 
67
73
  // List of services that manipulate the request before the upstream blocklet
package/package.json CHANGED
@@ -3,7 +3,7 @@
3
3
  "publishConfig": {
4
4
  "access": "public"
5
5
  },
6
- "version": "1.8.65-beta-5405baf2",
6
+ "version": "1.8.65-beta-bfcc12ce",
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.65-beta-5405baf2",
23
- "@abtnode/certificate-manager": "1.8.65-beta-5405baf2",
24
- "@abtnode/constant": "1.8.65-beta-5405baf2",
25
- "@abtnode/cron": "1.8.65-beta-5405baf2",
26
- "@abtnode/db": "1.8.65-beta-5405baf2",
27
- "@abtnode/logger": "1.8.65-beta-5405baf2",
28
- "@abtnode/queue": "1.8.65-beta-5405baf2",
29
- "@abtnode/rbac": "1.8.65-beta-5405baf2",
30
- "@abtnode/router-provider": "1.8.65-beta-5405baf2",
31
- "@abtnode/static-server": "1.8.65-beta-5405baf2",
32
- "@abtnode/timemachine": "1.8.65-beta-5405baf2",
33
- "@abtnode/util": "1.8.65-beta-5405baf2",
34
- "@arcblock/did": "1.18.37",
22
+ "@abtnode/auth": "1.8.65-beta-bfcc12ce",
23
+ "@abtnode/certificate-manager": "1.8.65-beta-bfcc12ce",
24
+ "@abtnode/constant": "1.8.65-beta-bfcc12ce",
25
+ "@abtnode/cron": "1.8.65-beta-bfcc12ce",
26
+ "@abtnode/db": "1.8.65-beta-bfcc12ce",
27
+ "@abtnode/logger": "1.8.65-beta-bfcc12ce",
28
+ "@abtnode/queue": "1.8.65-beta-bfcc12ce",
29
+ "@abtnode/rbac": "1.8.65-beta-bfcc12ce",
30
+ "@abtnode/router-provider": "1.8.65-beta-bfcc12ce",
31
+ "@abtnode/static-server": "1.8.65-beta-bfcc12ce",
32
+ "@abtnode/timemachine": "1.8.65-beta-bfcc12ce",
33
+ "@abtnode/util": "1.8.65-beta-bfcc12ce",
34
+ "@arcblock/did": "1.18.42",
35
35
  "@arcblock/did-motif": "^1.1.10",
36
- "@arcblock/did-util": "1.18.37",
37
- "@arcblock/event-hub": "1.18.37",
38
- "@arcblock/jwt": "^1.18.37",
36
+ "@arcblock/did-util": "1.18.42",
37
+ "@arcblock/event-hub": "1.18.42",
38
+ "@arcblock/jwt": "^1.18.42",
39
39
  "@arcblock/pm2-events": "^0.0.5",
40
- "@arcblock/vc": "1.18.37",
41
- "@blocklet/constant": "1.8.65-beta-5405baf2",
42
- "@blocklet/meta": "1.8.65-beta-5405baf2",
43
- "@blocklet/sdk": "1.8.65-beta-5405baf2",
40
+ "@arcblock/vc": "1.18.42",
41
+ "@blocklet/constant": "1.8.65-beta-bfcc12ce",
42
+ "@blocklet/meta": "1.8.65-beta-bfcc12ce",
43
+ "@blocklet/sdk": "1.8.65-beta-bfcc12ce",
44
44
  "@did-space/client": "^0.1.66",
45
45
  "@fidm/x509": "^1.2.1",
46
- "@ocap/mcrypto": "1.18.37",
47
- "@ocap/util": "1.18.37",
48
- "@ocap/wallet": "1.18.37",
46
+ "@ocap/mcrypto": "1.18.42",
47
+ "@ocap/util": "1.18.42",
48
+ "@ocap/wallet": "1.18.42",
49
49
  "@slack/webhook": "^5.0.4",
50
50
  "archiver": "^5.3.1",
51
51
  "axios": "^0.27.2",
@@ -55,9 +55,11 @@
55
55
  "deep-diff": "^1.0.2",
56
56
  "detect-port": "^1.5.1",
57
57
  "escape-string-regexp": "^4.0.0",
58
+ "fast-glob": "^3.2.12",
58
59
  "flat": "^5.0.2",
59
60
  "fs-extra": "^11.1.0",
60
61
  "get-port": "^5.1.1",
62
+ "hasha": "^5.2.2",
61
63
  "is-base64": "^1.1.0",
62
64
  "is-ip": "^3.1.0",
63
65
  "is-url": "^1.2.4",
@@ -88,5 +90,5 @@
88
90
  "express": "^4.18.2",
89
91
  "jest": "^27.5.1"
90
92
  },
91
- "gitHead": "e5dc838baded7031096118462a604fd70d78ff1c"
93
+ "gitHead": "f6a56512275a55feecf2f3953542ea98777a08f2"
92
94
  }