@abtnode/core 1.8.30 → 1.8.32

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.
package/lib/index.js CHANGED
@@ -11,7 +11,6 @@ const { listProviders } = require('@abtnode/router-provider');
11
11
  const { DEFAULT_CERTIFICATE_EMAIL, EVENTS } = require('@abtnode/constant');
12
12
 
13
13
  const RoutingSnapshot = require('./states/routing-snapshot');
14
- const BlockletRegistry = require('./blocklet/registry');
15
14
  const BlockletManager = require('./blocklet/manager/disk');
16
15
  const RouterManager = require('./router/manager');
17
16
  const getRouterHelpers = require('./router/helper');
@@ -27,6 +26,7 @@ const DomainStatus = require('./util/domain-status');
27
26
  const Upgrade = require('./util/upgrade');
28
27
  const resetNode = require('./util/reset-node');
29
28
  const DiskMonitor = require('./util/disk-monitor');
29
+ const StoreUtil = require('./util/store');
30
30
  const createQueue = require('./queue');
31
31
  const createEvents = require('./event');
32
32
  const pm2Events = require('./blocklet/manager/pm2-events');
@@ -123,15 +123,12 @@ function ABTNode(options) {
123
123
  },
124
124
  });
125
125
 
126
- const blockletRegistry = new BlockletRegistry();
127
-
128
126
  const teamManager = new TeamManager({ nodeDid: options.nodeDid, dataDirs, states });
129
127
 
130
128
  const blockletManager = new BlockletManager({
131
129
  dataDirs,
132
130
  startQueue,
133
131
  installQueue,
134
- registry: blockletRegistry,
135
132
  daemon: options.daemon,
136
133
  teamManager,
137
134
  });
@@ -207,6 +204,7 @@ function ABTNode(options) {
207
204
  upgradeComponents: blockletManager.updateChildren.bind(blockletManager),
208
205
  getLatestBlockletVersion: blockletManager.getLatestBlockletVersion.bind(blockletManager),
209
206
  getBlockletMetaFromUrl: blockletManager.getMetaFromUrl.bind(blockletManager),
207
+ getBlockletByBundle: blockletManager.getBlockletByBundle.bind(blockletManager),
210
208
  resetBlocklet: blockletManager.reset.bind(blockletManager),
211
209
  deleteBlockletProcess: blockletManager.deleteProcess.bind(blockletManager),
212
210
  configPublicToStore: blockletManager.configPublicToStore.bind(blockletManager),
@@ -226,9 +224,9 @@ function ABTNode(options) {
226
224
  updateAllBlockletEnvironment: blockletManager.updateAllBlockletEnvironment.bind(blockletManager),
227
225
  setBlockletInitialized: blockletManager.setInitialized.bind(blockletManager),
228
226
 
229
- // Registry
230
- getBlockletMeta: blockletRegistry.getBlockletMeta.bind(blockletRegistry),
231
- getRegistryMeta: BlockletRegistry.getRegistryMeta,
227
+ // Store
228
+ getBlockletMeta: StoreUtil.getBlockletMeta,
229
+ getRegistryMeta: StoreUtil.getRegistryMeta,
232
230
 
233
231
  // Node State
234
232
  getNodeInfo: nodeAPI.getInfo.bind(nodeAPI),
@@ -33,3 +33,6 @@ All Blocklet Server states are managed by files in this folder.
33
33
  - `children`: component of app, same structure as parent, can be nested
34
34
  - `mountPoint` mount path of web site. _component only_
35
35
  - `dynamic` is dynamically added. _component only_
36
+ - `controller`
37
+ - `tokens`
38
+ - `downloadTokenList`
@@ -23,6 +23,7 @@ const logger = require('@abtnode/logger')('state-blocklet');
23
23
  const BaseState = require('./base');
24
24
  const { checkDuplicateComponents, ensureMeta } = require('../util/blocklet');
25
25
  const { validateBlockletMeta } = require('../util');
26
+ const { validateBlockletController } = require('../validators/blocklet');
26
27
 
27
28
  const lock = new Lock('blocklet-port-assign-lock');
28
29
 
@@ -180,11 +181,12 @@ class BlockletState extends BaseState {
180
181
  deployedFrom = '',
181
182
  mode = BLOCKLET_MODES.PRODUCTION,
182
183
  children: rawChildren = [],
184
+ controller,
183
185
  } = {}) {
184
186
  return this.getBlocklet(meta.did).then(
185
- (doc) =>
187
+ (exist) =>
186
188
  new Promise(async (resolve, reject) => {
187
- if (doc) {
189
+ if (exist) {
188
190
  reject(new Error('Blocklet already added'));
189
191
  return;
190
192
  }
@@ -208,29 +210,33 @@ class BlockletState extends BaseState {
208
210
 
209
211
  fixChildren(children);
210
212
 
213
+ const data = {
214
+ appDid: null, // will updated later when updating blocklet environments
215
+ mode,
216
+ meta: sanitized,
217
+ status,
218
+ source,
219
+ deployedFrom,
220
+ ports,
221
+ environments: [],
222
+ children,
223
+ controller,
224
+ };
225
+
226
+ if (controller) {
227
+ data.controller = await validateBlockletController(controller);
228
+ }
229
+
211
230
  // add to db
212
- this.insert(
213
- {
214
- appDid: null, // will updated later when updating blocklet environments
215
- mode,
216
- meta: sanitized,
217
- status,
218
- source,
219
- deployedFrom,
220
- ports,
221
- environments: [],
222
- children,
223
- },
224
- (err, newDoc) => {
225
- lock.release();
226
- if (err) {
227
- return reject(err);
228
- }
229
-
230
- this.emit('add', newDoc);
231
- return resolve(newDoc);
231
+ this.insert(data, (err, doc) => {
232
+ lock.release();
233
+ if (err) {
234
+ return reject(err);
232
235
  }
233
- );
236
+
237
+ this.emit('add', doc);
238
+ return resolve(doc);
239
+ });
234
240
  } catch (err) {
235
241
  lock.release();
236
242
  reject(err);
@@ -124,6 +124,22 @@ class User extends BaseState {
124
124
  };
125
125
  }
126
126
 
127
+ async getUsersByDids({ dids, query } = {}) {
128
+ const { approved } = query || {};
129
+ const didList = dids || [];
130
+
131
+ const queryParam = {
132
+ did: { $in: didList },
133
+ };
134
+
135
+ if (!isNullOrUndefined(approved)) {
136
+ queryParam.approved = !!approved;
137
+ }
138
+
139
+ // get data
140
+ return this.find(queryParam);
141
+ }
142
+
127
143
  async getUser(did) {
128
144
  const doc = await this.findOne({ did });
129
145
  return doc;
@@ -328,8 +328,8 @@ class TeamManager extends EventEmitter {
328
328
  if (this.cache[did].session) {
329
329
  await closeDatabase(this.cache[did].session.db);
330
330
  }
331
- } catch (err) {
332
- logger.error('Failed to close database', { did, err });
331
+ } catch (error) {
332
+ logger.error('Failed to close database', { did, error });
333
333
  }
334
334
  }
335
335
 
@@ -23,6 +23,7 @@ const normalizePathPrefix = require('@abtnode/util/lib/normalize-path-prefix');
23
23
  const hashFiles = require('@abtnode/util/lib/hash-files');
24
24
  const isPathPrefixEqual = require('@abtnode/util/lib/is-path-prefix-equal');
25
25
  const { BLOCKLET_MAX_MEM_LIMIT_IN_MB } = require('@abtnode/constant');
26
+ const formatBackSlash = require('@abtnode/util/lib/format-back-slash');
26
27
 
27
28
  const SCRIPT_ENGINES_WHITE_LIST = ['npm', 'npx', 'pnpm', 'yarn'];
28
29
 
@@ -259,8 +260,7 @@ const getAppSystemEnvironments = (blocklet, nodeInfo) => {
259
260
  const appName = title || name || result.name;
260
261
  const appDescription = description || result.description;
261
262
 
262
- // FIXME: we should use https here when possible, eg, when did-gateway is available
263
- const appUrl = `http://${getDidDomainForBlocklet({ name, daemonDid: nodeInfo.did, didDomain: nodeInfo.didDomain })}`;
263
+ const appUrl = `https://${getDidDomainForBlocklet({ name, daemonDid: nodeInfo.did, didDomain: nodeInfo.didDomain })}`;
264
264
 
265
265
  return {
266
266
  BLOCKLET_DID: did,
@@ -946,7 +946,7 @@ const pruneBlockletBundle = async ({ blocklets, installDir, blockletSettings })
946
946
  const fillAppDirs = async (dir, level = 'root') => {
947
947
  if (level === 'version') {
948
948
  appDirs.push({
949
- key: path.relative(installDir, dir),
949
+ key: formatBackSlash(path.relative(installDir, dir)),
950
950
  dir,
951
951
  });
952
952
 
@@ -974,7 +974,7 @@ const pruneBlockletBundle = async ({ blocklets, installDir, blockletSettings })
974
974
 
975
975
  const ensureBundleDirRemoved = async (dir) => {
976
976
  const relativeDir = path.relative(installDir, dir);
977
- const arr = relativeDir.split('/').filter(Boolean);
977
+ const arr = relativeDir.split(path.sep).filter(Boolean);
978
978
  const { length } = arr;
979
979
  const bundleName = arr[length - 2];
980
980
  const scopeName = length > 2 ? arr[length - 3] : '';
@@ -1,8 +1,10 @@
1
1
  const semver = require('semver');
2
2
 
3
- let { version: actualVersion } = require('../../package.json');
3
+ let { version: actualServerVersion } = require('../../package.json');
4
4
 
5
- const defaults = { abtnode: '>= 1.1.0', os: '*', cpu: '*' };
5
+ const { version: actualNodejsVersion } = process;
6
+
7
+ const defaults = { abtnode: '>= 1.1.0', os: '*', cpu: '*', nodejs: '*' };
6
8
 
7
9
  const isSatisfied = (requirements, throwOnUnsatisfied = true) => {
8
10
  if (!requirements || typeof requirements !== 'object') {
@@ -10,15 +12,23 @@ const isSatisfied = (requirements, throwOnUnsatisfied = true) => {
10
12
  }
11
13
 
12
14
  const { platform: actualOs, arch: actualCpu } = process;
13
- const { os: expectedOs, cpu: expectedCpu, abtnode, server } = Object.assign(defaults, requirements);
14
- const expectedVersion = server || abtnode;
15
+ const {
16
+ os: expectedOs,
17
+ cpu: expectedCpu,
18
+ abtnode,
19
+ server,
20
+ nodejs: expectedNodejsVersion,
21
+ } = Object.assign(defaults, requirements);
22
+ const expectedServerVersion = server || abtnode;
15
23
 
16
24
  const isOsSatisfied =
17
25
  expectedOs === '*' || expectedOs === actualOs || (Array.isArray(expectedOs) && expectedOs.includes(actualOs));
18
26
  const isCpuSatisfied =
19
27
  expectedCpu === '*' || expectedCpu === actualCpu || (Array.isArray(expectedCpu) && expectedCpu.includes(actualCpu));
20
28
 
21
- const isVersionSatisfied = semver.satisfies(semver.coerce(actualVersion), expectedVersion);
29
+ const isServerVersionSatisfied = semver.satisfies(semver.coerce(actualServerVersion), expectedServerVersion);
30
+
31
+ const isNodejsVersionSatisfied = semver.satisfies(semver.coerce(actualNodejsVersion), expectedNodejsVersion);
22
32
 
23
33
  if (throwOnUnsatisfied) {
24
34
  if (isOsSatisfied === false) {
@@ -27,19 +37,25 @@ const isSatisfied = (requirements, throwOnUnsatisfied = true) => {
27
37
  if (isCpuSatisfied === false) {
28
38
  throw new Error(`Your blocklet is not supported on architecture ${actualCpu}`);
29
39
  }
30
- if (isVersionSatisfied === false) {
40
+ if (isServerVersionSatisfied === false) {
41
+ throw new Error(
42
+ `Expected server version for the blocklet is ${expectedServerVersion}, but your server version is ${actualServerVersion}, please upgrade or downgrade your server to continue.`
43
+ );
44
+ }
45
+ if (isNodejsVersionSatisfied === false) {
31
46
  throw new Error(
32
- `Expected server version for the blocklet is ${expectedVersion}, but your server version is ${actualVersion}, please upgrade or downgrade your server to continue.`
47
+ `Expected Nodejs version for the blocklet is ${expectedNodejsVersion}, but your Nodejs version is ${actualNodejsVersion}, please upgrade or downgrade Nodejs and restart your server.`
33
48
  );
34
49
  }
35
50
  }
36
51
 
37
- return isOsSatisfied && isCpuSatisfied && isVersionSatisfied;
52
+ return isOsSatisfied && isCpuSatisfied && isServerVersionSatisfied;
38
53
  };
39
54
 
40
55
  // Just for test
41
- isSatisfied._setActualVersion = (d) => {
42
- actualVersion = d;
56
+ isSatisfied._setActualServerVersion = (d) => {
57
+ actualServerVersion = d;
43
58
  };
59
+ isSatisfied._actualNodejsVersion = actualNodejsVersion;
44
60
 
45
61
  module.exports = isSatisfied;
@@ -8,6 +8,7 @@ const { name } = require('../../package.json');
8
8
  const logger = require('@abtnode/logger')(`${name}:util:registry`); // eslint-disable-line
9
9
 
10
10
  const request = require('./request');
11
+ const { fixAndVerifyMetaFromStore } = require('./blocklet');
11
12
 
12
13
  const validateRegistryURL = async (registry) => {
13
14
  const url = joinURL(registry, BLOCKLET_STORE_API_PREFIX, `/blocklets.json?__t__=${Date.now()}`);
@@ -83,8 +84,58 @@ const parseSourceUrl = async (url) => {
83
84
  };
84
85
  };
85
86
 
87
+ const resolveTarballURL = async ({ did, tarball = '', registryUrl = '' }) => {
88
+ if (!tarball) {
89
+ return '';
90
+ }
91
+
92
+ if (tarball.startsWith('file://')) {
93
+ return decodeURIComponent(tarball);
94
+ }
95
+
96
+ if (tarball.startsWith('http://') || tarball.startsWith('https://')) {
97
+ return tarball;
98
+ }
99
+
100
+ if (!registryUrl) {
101
+ return '';
102
+ }
103
+
104
+ if (!did) {
105
+ return '';
106
+ }
107
+
108
+ return joinURL(registryUrl, 'api', 'blocklets', did, tarball);
109
+ };
110
+
111
+ const getBlockletMeta = async ({ did, registryUrl }) => {
112
+ const url = joinURL(registryUrl, BLOCKLET_STORE_API_PREFIX, `/blocklets/${did}/blocklet.json?__t__=${Date.now()}`);
113
+
114
+ const { data } = await request.get(url);
115
+ try {
116
+ if (data.did !== did) {
117
+ throw new Error('Invalid blocklet meta: did does not match');
118
+ }
119
+
120
+ const meta = fixAndVerifyMetaFromStore(data);
121
+
122
+ meta.dist.tarball = await resolveTarballURL({
123
+ did,
124
+ tarball: meta.dist.tarball,
125
+ registryUrl,
126
+ });
127
+
128
+ return meta;
129
+ } catch (err) {
130
+ logger.error('failed to get blocklet meta', { did, data, error: err });
131
+ throw err;
132
+ }
133
+ };
134
+
86
135
  module.exports = {
87
136
  validateRegistryURL,
88
137
  getRegistryMeta,
89
138
  parseSourceUrl,
139
+ getBlockletMeta,
140
+ resolveTarballURL,
90
141
  };
@@ -0,0 +1,15 @@
1
+ const JOI = require('joi');
2
+ const { didExtension } = require('@blocklet/meta/lib/extension');
3
+
4
+ const Joi = JOI.extend(didExtension);
5
+
6
+ const blockletController = Joi.object({
7
+ id: Joi.DID().required(), // userDid
8
+ vcId: Joi.DID().required(),
9
+ appMaxCount: Joi.number().required().min(1),
10
+ expireDate: Joi.date(),
11
+ }).options({ stripUnknown: true });
12
+
13
+ module.exports = {
14
+ validateBlockletController: (entity) => blockletController.validateAsync(entity),
15
+ };
package/package.json CHANGED
@@ -3,7 +3,7 @@
3
3
  "publishConfig": {
4
4
  "access": "public"
5
5
  },
6
- "version": "1.8.30",
6
+ "version": "1.8.32",
7
7
  "description": "",
8
8
  "main": "lib/index.js",
9
9
  "files": [
@@ -19,32 +19,32 @@
19
19
  "author": "wangshijun <wangshijun2010@gmail.com> (http://github.com/wangshijun)",
20
20
  "license": "MIT",
21
21
  "dependencies": {
22
- "@abtnode/auth": "1.8.30",
23
- "@abtnode/certificate-manager": "1.8.30",
24
- "@abtnode/constant": "1.8.30",
25
- "@abtnode/cron": "1.8.30",
26
- "@abtnode/db": "1.8.30",
27
- "@abtnode/logger": "1.8.30",
28
- "@abtnode/queue": "1.8.30",
29
- "@abtnode/rbac": "1.8.30",
30
- "@abtnode/router-provider": "1.8.30",
31
- "@abtnode/static-server": "1.8.30",
32
- "@abtnode/timemachine": "1.8.30",
33
- "@abtnode/util": "1.8.30",
34
- "@arcblock/did": "1.17.23",
22
+ "@abtnode/auth": "1.8.32",
23
+ "@abtnode/certificate-manager": "1.8.32",
24
+ "@abtnode/constant": "1.8.32",
25
+ "@abtnode/cron": "1.8.32",
26
+ "@abtnode/db": "1.8.32",
27
+ "@abtnode/logger": "1.8.32",
28
+ "@abtnode/queue": "1.8.32",
29
+ "@abtnode/rbac": "1.8.32",
30
+ "@abtnode/router-provider": "1.8.32",
31
+ "@abtnode/static-server": "1.8.32",
32
+ "@abtnode/timemachine": "1.8.32",
33
+ "@abtnode/util": "1.8.32",
34
+ "@arcblock/did": "1.18.1",
35
35
  "@arcblock/did-motif": "^1.1.10",
36
- "@arcblock/did-util": "1.17.23",
37
- "@arcblock/event-hub": "1.17.23",
38
- "@arcblock/jwt": "^1.17.23",
36
+ "@arcblock/did-util": "1.18.1",
37
+ "@arcblock/event-hub": "1.18.1",
38
+ "@arcblock/jwt": "^1.18.1",
39
39
  "@arcblock/pm2-events": "^0.0.5",
40
- "@arcblock/vc": "1.17.23",
41
- "@blocklet/constant": "1.8.30",
42
- "@blocklet/meta": "1.8.30",
43
- "@blocklet/sdk": "1.8.30",
40
+ "@arcblock/vc": "1.18.1",
41
+ "@blocklet/constant": "1.8.32",
42
+ "@blocklet/meta": "1.8.32",
43
+ "@blocklet/sdk": "1.8.32",
44
44
  "@fidm/x509": "^1.2.1",
45
- "@ocap/mcrypto": "1.17.23",
46
- "@ocap/util": "1.17.23",
47
- "@ocap/wallet": "1.17.23",
45
+ "@ocap/mcrypto": "1.18.1",
46
+ "@ocap/util": "1.18.1",
47
+ "@ocap/wallet": "1.18.1",
48
48
  "@slack/webhook": "^5.0.4",
49
49
  "axios": "^0.27.2",
50
50
  "axon": "^2.0.3",
@@ -57,7 +57,7 @@
57
57
  "is-base64": "^1.1.0",
58
58
  "is-ip": "^3.1.0",
59
59
  "is-url": "^1.2.4",
60
- "joi": "^17.6.2",
60
+ "joi": "17.6.3",
61
61
  "js-yaml": "^4.1.0",
62
62
  "lodash": "^4.17.21",
63
63
  "lru-cache": "^6.0.0",
@@ -81,5 +81,5 @@
81
81
  "express": "^4.18.2",
82
82
  "jest": "^27.5.1"
83
83
  },
84
- "gitHead": "cb294f4ee7382c6ef7692b6c2c33ad080fced13e"
84
+ "gitHead": "8502244aeda5926b3433c1dd9142e63233e3c23c"
85
85
  }
@@ -1,74 +0,0 @@
1
- const joinURL = require('url-join');
2
- const { BLOCKLET_STORE_API_PREFIX } = require('@abtnode/constant');
3
-
4
- const { name } = require('../../package.json');
5
-
6
- const logger = require('@abtnode/logger')(`${name}:blocklet:registry`); // eslint-disable-line
7
-
8
- const request = require('../util/request');
9
-
10
- const states = require('../states');
11
- const { fixAndVerifyMetaFromStore } = require('../util/blocklet');
12
- const { validateRegistryURL, getRegistryMeta } = require('../util/registry');
13
-
14
- class BlockletRegistry {
15
- constructor() {
16
- this.blocklets = [];
17
- this.cacheId = '';
18
- }
19
-
20
- getBlocklet(id, registryUrl) {
21
- return this.getBlockletMeta({ did: id, registryUrl });
22
- }
23
-
24
- // eslint-disable-next-line no-unused-vars
25
- async getBlockletMeta({ did, registryUrl }, context) {
26
- const defaultRegistryUrl = await states.node.getBlockletRegistry();
27
-
28
- const url = joinURL(
29
- registryUrl || defaultRegistryUrl,
30
- BLOCKLET_STORE_API_PREFIX,
31
- `/blocklets/${did}/blocklet.json?__t__=${Date.now()}`
32
- );
33
-
34
- const { data } = await request.get(url);
35
- try {
36
- if (data.did !== did) {
37
- throw new Error('Invalid blocklet meta: did does not match');
38
- }
39
-
40
- return fixAndVerifyMetaFromStore(data);
41
- } catch (err) {
42
- logger.error('failed to get blocklet meta', { did, data, error: err });
43
- throw err;
44
- }
45
- }
46
-
47
- async resolveTarballURL({ did, tarball = '', registryUrl = '' }) {
48
- if (!tarball) {
49
- return '';
50
- }
51
-
52
- if (tarball.startsWith('file://')) {
53
- return decodeURIComponent(tarball);
54
- }
55
-
56
- if (tarball.startsWith('http://') || tarball.startsWith('https://')) {
57
- return tarball;
58
- }
59
-
60
- const defaultRegistryUrl = await states.node.getBlockletRegistry();
61
- return joinURL(registryUrl || defaultRegistryUrl, 'api', 'blocklets', did, tarball);
62
- }
63
-
64
- clearCache() {
65
- this.cacheId = '';
66
- this.blocklets = [];
67
- }
68
- }
69
-
70
- BlockletRegistry.validateRegistryURL = validateRegistryURL;
71
-
72
- BlockletRegistry.getRegistryMeta = getRegistryMeta;
73
-
74
- module.exports = BlockletRegistry;