@abtnode/core 1.8.62 → 1.8.63-beta-c51e554d
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/blocklet/extras.js +15 -0
- package/lib/blocklet/manager/disk.js +31 -10
- package/lib/blocklet/manager/helper/install-from-backup.js +160 -0
- package/lib/router/helper.js +21 -0
- package/lib/states/blocklet-extras.js +29 -1
- package/lib/util/blocklet.js +97 -68
- package/lib/validators/router.js +1 -1
- package/package.json +17 -17
package/lib/blocklet/extras.js
CHANGED
|
@@ -146,7 +146,22 @@ const parseConfigs = ({ data, did, dek }) => {
|
|
|
146
146
|
return data;
|
|
147
147
|
};
|
|
148
148
|
|
|
149
|
+
const encryptConfigs = ({ data, did, dek }) => {
|
|
150
|
+
const enableSecurity = dek && did;
|
|
151
|
+
|
|
152
|
+
if (enableSecurity && Array.isArray(data)) {
|
|
153
|
+
data.forEach((x) => {
|
|
154
|
+
if (x.secure) {
|
|
155
|
+
x.value = security.encrypt(x.value, did, dek);
|
|
156
|
+
}
|
|
157
|
+
});
|
|
158
|
+
}
|
|
159
|
+
|
|
160
|
+
return data;
|
|
161
|
+
};
|
|
162
|
+
|
|
149
163
|
module.exports = {
|
|
150
164
|
mergeConfigs,
|
|
151
165
|
parseConfigs,
|
|
166
|
+
encryptConfigs,
|
|
152
167
|
};
|
|
@@ -31,6 +31,7 @@ const {
|
|
|
31
31
|
WHO_CAN_ACCESS,
|
|
32
32
|
SERVER_ROLES,
|
|
33
33
|
WHO_CAN_ACCESS_PREFIX_ROLES,
|
|
34
|
+
BLOCKLET_INSTALL_TYPE,
|
|
34
35
|
} = require('@abtnode/constant');
|
|
35
36
|
|
|
36
37
|
const getBlockletEngine = require('@blocklet/meta/lib/engine');
|
|
@@ -104,7 +105,7 @@ const {
|
|
|
104
105
|
getDiskInfo,
|
|
105
106
|
getUpdateMetaList,
|
|
106
107
|
getRuntimeEnvironments,
|
|
107
|
-
|
|
108
|
+
getTypeFromInstallParams,
|
|
108
109
|
parseChildrenFromMeta,
|
|
109
110
|
checkDuplicateComponents,
|
|
110
111
|
getDiffFiles,
|
|
@@ -133,6 +134,7 @@ const handleInstanceInStore = require('../../util/public-to-store');
|
|
|
133
134
|
const { getNFTState, getServerDidDomain } = require('../../util');
|
|
134
135
|
const { BlockletRuntimeMonitor } = require('../../monitor/blocklet-runtime-monitor');
|
|
135
136
|
const getHistoryList = require('../../monitor/get-history-list');
|
|
137
|
+
const installFromBackup = require('./helper/install-from-backup');
|
|
136
138
|
|
|
137
139
|
const {
|
|
138
140
|
isInProgress,
|
|
@@ -253,6 +255,7 @@ class BlockletManager extends BaseBlockletManager {
|
|
|
253
255
|
* downloadTokenList: Array<{did: string, token: string}>;
|
|
254
256
|
* startImmediately: boolean;
|
|
255
257
|
* controller: Controller
|
|
258
|
+
* type: BLOCKLET_INSTALL_TYPE
|
|
256
259
|
* }} params
|
|
257
260
|
* @param {{
|
|
258
261
|
* [key: string]: any
|
|
@@ -274,32 +277,37 @@ class BlockletManager extends BaseBlockletManager {
|
|
|
274
277
|
});
|
|
275
278
|
context.downloadTokenList = params.downloadTokenList || [];
|
|
276
279
|
|
|
277
|
-
const
|
|
280
|
+
const type = getTypeFromInstallParams(params);
|
|
278
281
|
if (typeof context.startImmediately === 'undefined') {
|
|
279
282
|
context.startImmediately = !!params.startImmediately;
|
|
280
283
|
}
|
|
281
284
|
|
|
282
|
-
if (
|
|
285
|
+
if (type === BLOCKLET_INSTALL_TYPE.URL) {
|
|
283
286
|
const { url, controller, sync, delay } = params;
|
|
284
287
|
return this._installFromUrl({ url, controller, sync, delay }, context);
|
|
285
288
|
}
|
|
286
289
|
|
|
287
|
-
if (
|
|
290
|
+
if (type === BLOCKLET_INSTALL_TYPE.UPLOAD) {
|
|
288
291
|
const { file, did, diffVersion, deleteSet } = params;
|
|
289
292
|
return this._installFromUpload({ file, did, diffVersion, deleteSet, context });
|
|
290
293
|
}
|
|
291
294
|
|
|
292
|
-
if (
|
|
295
|
+
if (type === BLOCKLET_INSTALL_TYPE.STORE) {
|
|
293
296
|
const { did, controller, sync, delay, storeUrl } = params;
|
|
294
297
|
return this._installFromStore({ did, controller, sync, delay, storeUrl }, context);
|
|
295
298
|
}
|
|
296
299
|
|
|
297
|
-
if (
|
|
300
|
+
if (type === BLOCKLET_INSTALL_TYPE.CREATE) {
|
|
298
301
|
return this._installFromCreate({ title: params.title, description: params.description }, context);
|
|
299
302
|
}
|
|
300
303
|
|
|
304
|
+
if (type === BLOCKLET_INSTALL_TYPE.RESTORE) {
|
|
305
|
+
const { url, blockletSecretKey } = params;
|
|
306
|
+
return this._installFromBackup({ url, blockletSecretKey }, context);
|
|
307
|
+
}
|
|
308
|
+
|
|
301
309
|
// should not be here
|
|
302
|
-
throw new Error('Unknown
|
|
310
|
+
throw new Error('Unknown type');
|
|
303
311
|
}
|
|
304
312
|
|
|
305
313
|
/**
|
|
@@ -1601,6 +1609,19 @@ class BlockletManager extends BaseBlockletManager {
|
|
|
1601
1609
|
return blocklet;
|
|
1602
1610
|
}
|
|
1603
1611
|
|
|
1612
|
+
/**
|
|
1613
|
+
* backup 目录结构
|
|
1614
|
+
* /blocklets/<name1>version>
|
|
1615
|
+
* /blocklets/<name2>version>
|
|
1616
|
+
* /blocklets/<name3>version>
|
|
1617
|
+
* /data
|
|
1618
|
+
* /blocklet.json
|
|
1619
|
+
* /blocklet_extras.json
|
|
1620
|
+
*/
|
|
1621
|
+
async _installFromBackup({ url, blockletSecretKey, moveDir } = {}, context = {}) {
|
|
1622
|
+
return installFromBackup({ url, blockletSecretKey, moveDir, context, manager: this, states });
|
|
1623
|
+
}
|
|
1624
|
+
|
|
1604
1625
|
async ensureBlocklet(did, opts = {}) {
|
|
1605
1626
|
return getBlocklet({ ...opts, states, dataDirs: this.dataDirs, did });
|
|
1606
1627
|
}
|
|
@@ -1705,10 +1726,10 @@ class BlockletManager extends BaseBlockletManager {
|
|
|
1705
1726
|
}));
|
|
1706
1727
|
}
|
|
1707
1728
|
|
|
1708
|
-
|
|
1709
|
-
|
|
1710
|
-
blocklet.appRuntimeInfo = this.runtimeMonitor.getRuntimeInfo(blocklet.meta.did);
|
|
1729
|
+
// app runtime info, app status
|
|
1730
|
+
blocklet.appRuntimeInfo = this.runtimeMonitor.getRuntimeInfo(blocklet.meta.did);
|
|
1711
1731
|
|
|
1732
|
+
if (!fromCache) {
|
|
1712
1733
|
// app disk info, component runtime info, component status, component engine
|
|
1713
1734
|
await forEachBlocklet(blocklet, async (component, { level }) => {
|
|
1714
1735
|
component.engine = getEngine(getBlockletEngineNameByPlatform(component.meta)).describe();
|
|
@@ -0,0 +1,160 @@
|
|
|
1
|
+
const fs = require('fs-extra');
|
|
2
|
+
const path = require('path');
|
|
3
|
+
const omit = require('lodash/omit');
|
|
4
|
+
|
|
5
|
+
const { forEachBlockletSync } = require('@blocklet/meta/lib/util');
|
|
6
|
+
const getBlockletInfo = require('@blocklet/meta/lib/info');
|
|
7
|
+
|
|
8
|
+
const { BLOCKLET_CONFIGURABLE_KEY } = require('@blocklet/constant');
|
|
9
|
+
|
|
10
|
+
const logger = require('@abtnode/logger')('@abtnode/core:install-from-backup');
|
|
11
|
+
|
|
12
|
+
const { validateBlocklet, checkDuplicateAppSk, getAppDirs } = require('../../../util/blocklet');
|
|
13
|
+
|
|
14
|
+
module.exports = async ({ url, blockletSecretKey, moveDir, context = {}, states, manager } = {}) => {
|
|
15
|
+
// TODO: support more url schema feature (http, did-spaces)
|
|
16
|
+
if (!url.startsWith('file://')) {
|
|
17
|
+
throw new Error('url must starts with file://');
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
const dir = url.replace('file://', '');
|
|
21
|
+
|
|
22
|
+
if (!dir || !fs.existsSync(dir)) {
|
|
23
|
+
throw new Error(`dir(${dir}) does not exist`);
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
// parse data from source dir
|
|
27
|
+
|
|
28
|
+
const srcBundleDirs = await getAppDirs(path.join(dir, 'blocklets'));
|
|
29
|
+
if (!srcBundleDirs.length) {
|
|
30
|
+
throw new Error(`bundle dirs does not found in ${dir}`);
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
const srcDataDir = path.join(dir, 'data');
|
|
34
|
+
|
|
35
|
+
/** @type {import('@abtnode/client').BlockletState} */
|
|
36
|
+
const state = omit(fs.readJSONSync(path.join(dir, 'blocklet.json')), [
|
|
37
|
+
'_id',
|
|
38
|
+
'createdAt',
|
|
39
|
+
'updatedAt',
|
|
40
|
+
'installedAt',
|
|
41
|
+
'startedAt',
|
|
42
|
+
]);
|
|
43
|
+
|
|
44
|
+
const extra = omit(fs.readJSONSync(path.join(dir, 'blocklet-extras.json')), ['_id', 'createdAt', 'updatedAt']);
|
|
45
|
+
|
|
46
|
+
if (state.meta.did !== extra.did) {
|
|
47
|
+
throw new Error('did does not match in blocklet.json and blocklet_extra.json');
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
forEachBlockletSync(state, (component) => {
|
|
51
|
+
delete component.status;
|
|
52
|
+
delete component.ports;
|
|
53
|
+
delete component.environments;
|
|
54
|
+
});
|
|
55
|
+
|
|
56
|
+
const { meta } = state;
|
|
57
|
+
|
|
58
|
+
await validateBlocklet({ meta });
|
|
59
|
+
|
|
60
|
+
const { did, name: appName } = meta;
|
|
61
|
+
|
|
62
|
+
// FIXME: meta.did and meta.name should be dynamic created when installing multiple blocklet is supported
|
|
63
|
+
const existState = await states.blocklet.hasBlocklet(did);
|
|
64
|
+
if (existState) {
|
|
65
|
+
logger.error('blocklet is already exist', { did });
|
|
66
|
+
throw new Error('blocklet is already exist');
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
if (blockletSecretKey) {
|
|
70
|
+
extra.configs = extra.configs || [];
|
|
71
|
+
const skConfig = extra.configs.find((x) => x.key === BLOCKLET_CONFIGURABLE_KEY.BLOCKLET_APP_SK);
|
|
72
|
+
if (skConfig) {
|
|
73
|
+
skConfig.value = blockletSecretKey;
|
|
74
|
+
} else {
|
|
75
|
+
extra.configs.push({
|
|
76
|
+
key: BLOCKLET_CONFIGURABLE_KEY.BLOCKLET_APP_SK,
|
|
77
|
+
value: blockletSecretKey,
|
|
78
|
+
secure: true,
|
|
79
|
+
shared: false,
|
|
80
|
+
});
|
|
81
|
+
}
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
// validate appDid
|
|
85
|
+
const nodeInfo = await states.node.read();
|
|
86
|
+
const { wallet } = getBlockletInfo({ meta: state.meta, configs: extra.configs, environments: [] }, nodeInfo.sk);
|
|
87
|
+
if (state.appDid !== wallet.address) {
|
|
88
|
+
throw new Error('blocklet appDid is different from the previous one');
|
|
89
|
+
}
|
|
90
|
+
await checkDuplicateAppSk({ sk: wallet.secretKey, states });
|
|
91
|
+
|
|
92
|
+
states.blockletExtras.encryptSecurityData({ data: extra, rootDid: extra.did });
|
|
93
|
+
|
|
94
|
+
logger.info('installFromBackup', { srcBundleDirs, srcDataDir });
|
|
95
|
+
|
|
96
|
+
try {
|
|
97
|
+
// copy extra
|
|
98
|
+
const existExtra = await states.blockletExtras.find({ did });
|
|
99
|
+
if (existExtra) {
|
|
100
|
+
// 如果数据存在, 当前视为脏数据, 直接删除
|
|
101
|
+
// FIXME 另一个人的数据可能被删除. 修复方式: 动态生成 meta.did 或通过 blocklet sk 生成 meta.did
|
|
102
|
+
// FIXME 简单粗暴的删掉数据可能不是理想的方式,需要考虑旧数据存在时, 如何与新数据 merge
|
|
103
|
+
logger.error('old extra state exists and will be force removed', { existExtra });
|
|
104
|
+
await states.blockletExtras.remove({ did });
|
|
105
|
+
}
|
|
106
|
+
await states.blockletExtras.insert(extra);
|
|
107
|
+
logger.info('blocklet extra is copied successfully');
|
|
108
|
+
|
|
109
|
+
// add blocklet
|
|
110
|
+
await states.blocklet.addBlocklet(state);
|
|
111
|
+
logger.info('blocklet state is added successfully');
|
|
112
|
+
|
|
113
|
+
// copy bundle
|
|
114
|
+
// 假设相同名称的应用,肯定是同一个应用
|
|
115
|
+
// 假设版本号相同时, 应用不会变更
|
|
116
|
+
// FIXME: blocklet bundle name/did 不是唯一的. 修改 blocklet bundle name/did 生成方式 使 name/bundle 唯一
|
|
117
|
+
await Promise.all(
|
|
118
|
+
srcBundleDirs.map(async ({ key: bundleName, dir: srcDir }) => {
|
|
119
|
+
const installDir = path.join(manager.dataDirs.blocklets, bundleName);
|
|
120
|
+
if (fs.existsSync(installDir)) {
|
|
121
|
+
logger.info(`${bundleName} is already exist`);
|
|
122
|
+
return;
|
|
123
|
+
}
|
|
124
|
+
|
|
125
|
+
fs.mkdirSync(installDir, { recursive: true });
|
|
126
|
+
if (moveDir) {
|
|
127
|
+
await fs.move(srcDir, installDir, { overwrite: true });
|
|
128
|
+
} else {
|
|
129
|
+
await fs.copy(srcDir, installDir);
|
|
130
|
+
}
|
|
131
|
+
logger.info(`bundle is ${moveDir ? 'moved' : 'copied'} successfully`, { installDir });
|
|
132
|
+
})
|
|
133
|
+
);
|
|
134
|
+
|
|
135
|
+
// FIXME same as copy extra
|
|
136
|
+
const dataDir = path.join(manager.dataDirs.data, appName);
|
|
137
|
+
if (fs.existsSync(dataDir)) {
|
|
138
|
+
logger.error('old data exists and will be force removed', { dataDir });
|
|
139
|
+
await fs.remove(dataDir);
|
|
140
|
+
}
|
|
141
|
+
fs.mkdirSync(dataDir, { recursive: true });
|
|
142
|
+
if (fs.existsSync(srcDataDir)) {
|
|
143
|
+
if (moveDir) {
|
|
144
|
+
await fs.move(srcDataDir, dataDir, { overwrite: true });
|
|
145
|
+
} else {
|
|
146
|
+
await fs.copy(srcDataDir, dataDir);
|
|
147
|
+
}
|
|
148
|
+
logger.info(`data is ${moveDir ? 'moved' : 'copied'} successfully`);
|
|
149
|
+
}
|
|
150
|
+
} catch (error) {
|
|
151
|
+
logger.error('installFromBackup failed', { error });
|
|
152
|
+
|
|
153
|
+
await manager._rollback('install', did);
|
|
154
|
+
|
|
155
|
+
throw error;
|
|
156
|
+
}
|
|
157
|
+
|
|
158
|
+
logger.info('start install blocklet', { did });
|
|
159
|
+
return manager._installBlocklet({ did, context });
|
|
160
|
+
};
|
package/lib/router/helper.js
CHANGED
|
@@ -281,6 +281,25 @@ const ensureWellknownRule = async (sites) => {
|
|
|
281
281
|
return tempSites;
|
|
282
282
|
};
|
|
283
283
|
|
|
284
|
+
const ensureBlockletDid = async (sites) => {
|
|
285
|
+
const info = await states.node.read();
|
|
286
|
+
|
|
287
|
+
return (sites || []).map((site) => {
|
|
288
|
+
if (site.domain === DOMAIN_FOR_INTERNAL_SITE) {
|
|
289
|
+
return site;
|
|
290
|
+
}
|
|
291
|
+
|
|
292
|
+
if ([DOMAIN_FOR_IP_SITE, DOMAIN_FOR_DEFAULT_SITE, DOMAIN_FOR_IP_SITE_REGEXP].includes(site.domain)) {
|
|
293
|
+
site.blockletDid = info.did;
|
|
294
|
+
return site;
|
|
295
|
+
}
|
|
296
|
+
|
|
297
|
+
site.blockletDid = site.domain.replace(BLOCKLET_SITE_GROUP_SUFFIX, '');
|
|
298
|
+
|
|
299
|
+
return site;
|
|
300
|
+
});
|
|
301
|
+
};
|
|
302
|
+
|
|
284
303
|
const ensureCorsForWebWallet = async (sites) => {
|
|
285
304
|
const info = await states.node.read();
|
|
286
305
|
for (const site of sites) {
|
|
@@ -306,8 +325,10 @@ const filterSitesForRemovedBlocklets = async (sites = []) => {
|
|
|
306
325
|
|
|
307
326
|
const ensureLatestInfo = async (sites = [], { withDefaultCors = true } = {}) => {
|
|
308
327
|
let result = await ensureLatestNodeInfo(sites, { withDefaultCors });
|
|
328
|
+
result = await ensureBlockletDid(result);
|
|
309
329
|
result = await ensureWellknownRule(result);
|
|
310
330
|
result = await ensureCorsForWebWallet(result);
|
|
331
|
+
|
|
311
332
|
return ensureLatestInterfaceInfo(result);
|
|
312
333
|
};
|
|
313
334
|
|
|
@@ -9,7 +9,7 @@ const dayjs = require('dayjs');
|
|
|
9
9
|
|
|
10
10
|
const BaseState = require('./base');
|
|
11
11
|
|
|
12
|
-
const { mergeConfigs, parseConfigs } = require('../blocklet/extras');
|
|
12
|
+
const { mergeConfigs, parseConfigs, encryptConfigs } = require('../blocklet/extras');
|
|
13
13
|
const { validateAddMeta, validateExpiredInfo } = require('../validators/blocklet-extra');
|
|
14
14
|
|
|
15
15
|
const noop = (k) => (v) => v[k];
|
|
@@ -214,6 +214,34 @@ class BlockletExtrasState extends BaseState {
|
|
|
214
214
|
expiredAt: { $exists: true, $lte: now.subtract(EXPIRED_BLOCKLET_DATA_RETENTION_DAYS, 'days').toISOString() },
|
|
215
215
|
});
|
|
216
216
|
}
|
|
217
|
+
|
|
218
|
+
encryptSecurityData({ data, _rootDid } = {}) {
|
|
219
|
+
if (!data) {
|
|
220
|
+
return data;
|
|
221
|
+
}
|
|
222
|
+
|
|
223
|
+
const { dek } = this.config;
|
|
224
|
+
|
|
225
|
+
if (!dek) {
|
|
226
|
+
return data;
|
|
227
|
+
}
|
|
228
|
+
|
|
229
|
+
const did = _rootDid || data.did;
|
|
230
|
+
|
|
231
|
+
if (!did) {
|
|
232
|
+
throw new Error('data.did does not exist');
|
|
233
|
+
}
|
|
234
|
+
|
|
235
|
+
encryptConfigs({ data: data.configs, did, dek });
|
|
236
|
+
|
|
237
|
+
if (Array.isArray(data.children)) {
|
|
238
|
+
for (const child of data.children) {
|
|
239
|
+
this.encryptSecurityData({ data: child, _rootDid: did });
|
|
240
|
+
}
|
|
241
|
+
}
|
|
242
|
+
|
|
243
|
+
return data;
|
|
244
|
+
}
|
|
217
245
|
}
|
|
218
246
|
|
|
219
247
|
module.exports = BlockletExtrasState;
|
package/lib/util/blocklet.js
CHANGED
|
@@ -31,8 +31,7 @@ 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 } = require('@abtnode/constant');
|
|
35
|
-
const { BLOCKLET_PREFERENCE_FILE, BLOCKLET_PREFERENCE_PREFIX } = require('@blocklet/constant');
|
|
34
|
+
const { BLOCKLET_MAX_MEM_LIMIT_IN_MB, BLOCKLET_STORE, BLOCKLET_INSTALL_TYPE } = require('@abtnode/constant');
|
|
36
35
|
const formatBackSlash = require('@abtnode/util/lib/format-back-slash');
|
|
37
36
|
|
|
38
37
|
const SCRIPT_ENGINES_WHITE_LIST = ['npm', 'npx', 'pnpm', 'yarn'];
|
|
@@ -50,6 +49,8 @@ const {
|
|
|
50
49
|
BLOCKLET_CONFIGURABLE_KEY,
|
|
51
50
|
BLOCKLET_DYNAMIC_PATH_PREFIX,
|
|
52
51
|
fromBlockletStatus,
|
|
52
|
+
BLOCKLET_PREFERENCE_FILE,
|
|
53
|
+
BLOCKLET_PREFERENCE_PREFIX,
|
|
53
54
|
} = require('@blocklet/constant');
|
|
54
55
|
const verifyMultiSig = require('@blocklet/meta/lib/verify-multi-sig');
|
|
55
56
|
const validateBlockletEntry = require('@blocklet/meta/lib/entry');
|
|
@@ -926,6 +927,59 @@ const verifyIntegrity = async ({ file, integrity: expected }) => {
|
|
|
926
927
|
return true;
|
|
927
928
|
};
|
|
928
929
|
|
|
930
|
+
/**
|
|
931
|
+
* @param {string} installDir
|
|
932
|
+
* @returns {Array<{ key: <[scope/]name/version>, dir: appDir }>}
|
|
933
|
+
*/
|
|
934
|
+
const getAppDirs = async (installDir) => {
|
|
935
|
+
const appDirs = [];
|
|
936
|
+
|
|
937
|
+
const getNextLevel = (level, name) => {
|
|
938
|
+
if (level === 'root') {
|
|
939
|
+
if (name.startsWith('@')) {
|
|
940
|
+
return 'scope';
|
|
941
|
+
}
|
|
942
|
+
return 'name';
|
|
943
|
+
}
|
|
944
|
+
if (level === 'scope') {
|
|
945
|
+
return 'name';
|
|
946
|
+
}
|
|
947
|
+
if (level === 'name') {
|
|
948
|
+
return 'version';
|
|
949
|
+
}
|
|
950
|
+
throw new Error(`Invalid level ${level}`);
|
|
951
|
+
};
|
|
952
|
+
|
|
953
|
+
const fillAppDirs = async (dir, level = 'root') => {
|
|
954
|
+
if (level === 'version') {
|
|
955
|
+
appDirs.push({
|
|
956
|
+
key: formatBackSlash(path.relative(installDir, dir)),
|
|
957
|
+
dir,
|
|
958
|
+
});
|
|
959
|
+
|
|
960
|
+
return;
|
|
961
|
+
}
|
|
962
|
+
|
|
963
|
+
const nextDirs = [];
|
|
964
|
+
for (const x of await fs.promises.readdir(dir)) {
|
|
965
|
+
if (!fs.lstatSync(path.join(dir, x)).isDirectory()) {
|
|
966
|
+
logger.error('pruneBlockletBundle: invalid file in bundle storage', { dir, file: x });
|
|
967
|
+
// eslint-disable-next-line no-continue
|
|
968
|
+
continue;
|
|
969
|
+
}
|
|
970
|
+
nextDirs.push(x);
|
|
971
|
+
}
|
|
972
|
+
|
|
973
|
+
for (const x of nextDirs) {
|
|
974
|
+
await fillAppDirs(path.join(dir, x), getNextLevel(level, x));
|
|
975
|
+
}
|
|
976
|
+
};
|
|
977
|
+
|
|
978
|
+
await fillAppDirs(installDir, 'root');
|
|
979
|
+
|
|
980
|
+
return appDirs;
|
|
981
|
+
};
|
|
982
|
+
|
|
929
983
|
const pruneBlockletBundle = async ({ blocklets, installDir, blockletSettings }) => {
|
|
930
984
|
for (const blocklet of blocklets) {
|
|
931
985
|
if (
|
|
@@ -961,53 +1015,10 @@ const pruneBlockletBundle = async ({ blocklets, installDir, blockletSettings })
|
|
|
961
1015
|
}
|
|
962
1016
|
}
|
|
963
1017
|
|
|
964
|
-
// appDirs: [{ key: <[scope/]name/version>, dir: appDir }]
|
|
965
|
-
const appDirs = [];
|
|
966
|
-
|
|
967
1018
|
// fill appDirs
|
|
1019
|
+
let appDirs = [];
|
|
968
1020
|
try {
|
|
969
|
-
|
|
970
|
-
const getNextLevel = (level, name) => {
|
|
971
|
-
if (level === 'root') {
|
|
972
|
-
if (name.startsWith('@')) {
|
|
973
|
-
return 'scope';
|
|
974
|
-
}
|
|
975
|
-
return 'bundle';
|
|
976
|
-
}
|
|
977
|
-
if (level === 'scope') {
|
|
978
|
-
return 'bundle';
|
|
979
|
-
}
|
|
980
|
-
if (level === 'bundle') {
|
|
981
|
-
return 'version';
|
|
982
|
-
}
|
|
983
|
-
throw new Error(`Invalid level ${level}`);
|
|
984
|
-
};
|
|
985
|
-
|
|
986
|
-
const fillAppDirs = async (dir, level = 'root') => {
|
|
987
|
-
if (level === 'version') {
|
|
988
|
-
appDirs.push({
|
|
989
|
-
key: formatBackSlash(path.relative(installDir, dir)),
|
|
990
|
-
dir,
|
|
991
|
-
});
|
|
992
|
-
|
|
993
|
-
return;
|
|
994
|
-
}
|
|
995
|
-
|
|
996
|
-
const nextDirs = [];
|
|
997
|
-
for (const x of await fs.promises.readdir(dir)) {
|
|
998
|
-
if (!fs.lstatSync(path.join(dir, x)).isDirectory()) {
|
|
999
|
-
logger.error('pruneBlockletBundle: invalid file in bundle storage', { dir, file: x });
|
|
1000
|
-
// eslint-disable-next-line no-continue
|
|
1001
|
-
continue;
|
|
1002
|
-
}
|
|
1003
|
-
nextDirs.push(x);
|
|
1004
|
-
}
|
|
1005
|
-
|
|
1006
|
-
for (const x of nextDirs) {
|
|
1007
|
-
await fillAppDirs(path.join(dir, x), getNextLevel(level, x));
|
|
1008
|
-
}
|
|
1009
|
-
};
|
|
1010
|
-
await fillAppDirs(installDir, 'root');
|
|
1021
|
+
appDirs = await getAppDirs(installDir);
|
|
1011
1022
|
} catch (error) {
|
|
1012
1023
|
logger.error('fill app dirs failed', { error });
|
|
1013
1024
|
}
|
|
@@ -1197,24 +1208,34 @@ const getUpdateMetaList = (oldBlocklet = {}, newBlocklet = {}) => {
|
|
|
1197
1208
|
return res;
|
|
1198
1209
|
};
|
|
1199
1210
|
|
|
1200
|
-
|
|
1211
|
+
/**
|
|
1212
|
+
* @returns BLOCKLET_INSTALL_TYPE
|
|
1213
|
+
*/
|
|
1214
|
+
const getTypeFromInstallParams = (params) => {
|
|
1215
|
+
if (params.type) {
|
|
1216
|
+
if (!Object.values(BLOCKLET_INSTALL_TYPE).includes(params.type)) {
|
|
1217
|
+
throw new Error(`Can only install blocklet from ${Object.values(BLOCKLET_INSTALL_TYPE).join('/')}`);
|
|
1218
|
+
}
|
|
1219
|
+
return params.type;
|
|
1220
|
+
}
|
|
1221
|
+
|
|
1201
1222
|
if (params.url) {
|
|
1202
|
-
return
|
|
1223
|
+
return BLOCKLET_INSTALL_TYPE.URL;
|
|
1203
1224
|
}
|
|
1204
1225
|
|
|
1205
1226
|
if (params.file) {
|
|
1206
|
-
return
|
|
1227
|
+
return BLOCKLET_INSTALL_TYPE.UPLOAD;
|
|
1207
1228
|
}
|
|
1208
1229
|
|
|
1209
1230
|
if (params.did) {
|
|
1210
|
-
return
|
|
1231
|
+
return BLOCKLET_INSTALL_TYPE.STORE;
|
|
1211
1232
|
}
|
|
1212
1233
|
|
|
1213
1234
|
if (params.title && params.description) {
|
|
1214
|
-
return
|
|
1235
|
+
return BLOCKLET_INSTALL_TYPE.CREATE;
|
|
1215
1236
|
}
|
|
1216
1237
|
|
|
1217
|
-
throw new Error(
|
|
1238
|
+
throw new Error(`Can only install blocklet from ${Object.values(BLOCKLET_INSTALL_TYPE).join('/')}`);
|
|
1218
1239
|
};
|
|
1219
1240
|
|
|
1220
1241
|
const checkDuplicateComponents = (components = []) => {
|
|
@@ -1599,25 +1620,32 @@ const validateAppConfig = async (config, blockletDid, states) => {
|
|
|
1599
1620
|
}
|
|
1600
1621
|
};
|
|
1601
1622
|
|
|
1602
|
-
const checkDuplicateAppSk = async ({ did, states }) => {
|
|
1603
|
-
|
|
1604
|
-
|
|
1605
|
-
|
|
1606
|
-
const configs = await states.blockletExtras.getConfigs([did]);
|
|
1623
|
+
const checkDuplicateAppSk = async ({ sk, did, states }) => {
|
|
1624
|
+
if (!sk && !did) {
|
|
1625
|
+
throw new Error('sk and did is empty');
|
|
1626
|
+
}
|
|
1607
1627
|
|
|
1608
|
-
|
|
1609
|
-
|
|
1610
|
-
|
|
1611
|
-
|
|
1612
|
-
|
|
1613
|
-
|
|
1614
|
-
|
|
1628
|
+
let appSk = sk;
|
|
1629
|
+
if (!sk) {
|
|
1630
|
+
const nodeInfo = await states.node.read();
|
|
1631
|
+
const blocklet = await states.blocklet.getBlocklet(did);
|
|
1632
|
+
const configs = await states.blockletExtras.getConfigs([did]);
|
|
1633
|
+
const { wallet } = getBlockletInfo(
|
|
1634
|
+
{
|
|
1635
|
+
meta: blocklet.meta,
|
|
1636
|
+
environments: (configs || []).filter((x) => x.value),
|
|
1637
|
+
},
|
|
1638
|
+
nodeInfo.sk
|
|
1639
|
+
);
|
|
1640
|
+
appSk = wallet.secretKey;
|
|
1641
|
+
}
|
|
1615
1642
|
|
|
1616
|
-
const
|
|
1643
|
+
const blocklets = await states.blocklet.getBlocklets({});
|
|
1644
|
+
const others = did ? blocklets.filter((b) => b.meta.did !== did) : blocklets;
|
|
1617
1645
|
|
|
1618
1646
|
const exist = others.find((b) => {
|
|
1619
1647
|
const item = (b.environments || []).find((e) => e.key === BLOCKLET_CONFIGURABLE_KEY.BLOCKLET_APP_SK);
|
|
1620
|
-
return item?.value === toHex(
|
|
1648
|
+
return item?.value === toHex(appSk);
|
|
1621
1649
|
});
|
|
1622
1650
|
|
|
1623
1651
|
if (exist) {
|
|
@@ -1663,13 +1691,14 @@ module.exports = {
|
|
|
1663
1691
|
expandTarball,
|
|
1664
1692
|
verifyIntegrity,
|
|
1665
1693
|
statusMap,
|
|
1694
|
+
getAppDirs,
|
|
1666
1695
|
pruneBlockletBundle,
|
|
1667
1696
|
getDiskInfo,
|
|
1668
1697
|
getRuntimeInfo,
|
|
1669
1698
|
mergeMeta,
|
|
1670
1699
|
fixAndVerifyMetaFromStore,
|
|
1671
1700
|
getUpdateMetaList,
|
|
1672
|
-
|
|
1701
|
+
getTypeFromInstallParams,
|
|
1673
1702
|
findWebInterface,
|
|
1674
1703
|
checkDuplicateComponents,
|
|
1675
1704
|
getDiffFiles,
|
package/lib/validators/router.js
CHANGED
|
@@ -81,7 +81,7 @@ const ruleSchema = {
|
|
|
81
81
|
const corsSchema = Joi.array()
|
|
82
82
|
.items(
|
|
83
83
|
Joi.string().domain({ minDomainSegments: 1, tlds: false }),
|
|
84
|
-
Joi.string().valid(DOMAIN_FOR_DEFAULT_SITE),
|
|
84
|
+
Joi.string().valid(DOMAIN_FOR_DEFAULT_SITE, '__none__'),
|
|
85
85
|
Joi.string().ip()
|
|
86
86
|
)
|
|
87
87
|
.min(1)
|
package/package.json
CHANGED
|
@@ -3,7 +3,7 @@
|
|
|
3
3
|
"publishConfig": {
|
|
4
4
|
"access": "public"
|
|
5
5
|
},
|
|
6
|
-
"version": "1.8.
|
|
6
|
+
"version": "1.8.63-beta-c51e554d",
|
|
7
7
|
"description": "",
|
|
8
8
|
"main": "lib/index.js",
|
|
9
9
|
"files": [
|
|
@@ -19,18 +19,18 @@
|
|
|
19
19
|
"author": "wangshijun <wangshijun2010@gmail.com> (http://github.com/wangshijun)",
|
|
20
20
|
"license": "MIT",
|
|
21
21
|
"dependencies": {
|
|
22
|
-
"@abtnode/auth": "1.8.
|
|
23
|
-
"@abtnode/certificate-manager": "1.8.
|
|
24
|
-
"@abtnode/constant": "1.8.
|
|
25
|
-
"@abtnode/cron": "1.8.
|
|
26
|
-
"@abtnode/db": "1.8.
|
|
27
|
-
"@abtnode/logger": "1.8.
|
|
28
|
-
"@abtnode/queue": "1.8.
|
|
29
|
-
"@abtnode/rbac": "1.8.
|
|
30
|
-
"@abtnode/router-provider": "1.8.
|
|
31
|
-
"@abtnode/static-server": "1.8.
|
|
32
|
-
"@abtnode/timemachine": "1.8.
|
|
33
|
-
"@abtnode/util": "1.8.
|
|
22
|
+
"@abtnode/auth": "1.8.63-beta-c51e554d",
|
|
23
|
+
"@abtnode/certificate-manager": "1.8.63-beta-c51e554d",
|
|
24
|
+
"@abtnode/constant": "1.8.63-beta-c51e554d",
|
|
25
|
+
"@abtnode/cron": "1.8.63-beta-c51e554d",
|
|
26
|
+
"@abtnode/db": "1.8.63-beta-c51e554d",
|
|
27
|
+
"@abtnode/logger": "1.8.63-beta-c51e554d",
|
|
28
|
+
"@abtnode/queue": "1.8.63-beta-c51e554d",
|
|
29
|
+
"@abtnode/rbac": "1.8.63-beta-c51e554d",
|
|
30
|
+
"@abtnode/router-provider": "1.8.63-beta-c51e554d",
|
|
31
|
+
"@abtnode/static-server": "1.8.63-beta-c51e554d",
|
|
32
|
+
"@abtnode/timemachine": "1.8.63-beta-c51e554d",
|
|
33
|
+
"@abtnode/util": "1.8.63-beta-c51e554d",
|
|
34
34
|
"@arcblock/did": "1.18.36",
|
|
35
35
|
"@arcblock/did-motif": "^1.1.10",
|
|
36
36
|
"@arcblock/did-util": "1.18.36",
|
|
@@ -38,9 +38,9 @@
|
|
|
38
38
|
"@arcblock/jwt": "^1.18.36",
|
|
39
39
|
"@arcblock/pm2-events": "^0.0.5",
|
|
40
40
|
"@arcblock/vc": "1.18.36",
|
|
41
|
-
"@blocklet/constant": "1.8.
|
|
42
|
-
"@blocklet/meta": "1.8.
|
|
43
|
-
"@blocklet/sdk": "1.8.
|
|
41
|
+
"@blocklet/constant": "1.8.63-beta-c51e554d",
|
|
42
|
+
"@blocklet/meta": "1.8.63-beta-c51e554d",
|
|
43
|
+
"@blocklet/sdk": "1.8.63-beta-c51e554d",
|
|
44
44
|
"@fidm/x509": "^1.2.1",
|
|
45
45
|
"@ocap/mcrypto": "1.18.36",
|
|
46
46
|
"@ocap/util": "1.18.36",
|
|
@@ -85,5 +85,5 @@
|
|
|
85
85
|
"express": "^4.18.2",
|
|
86
86
|
"jest": "^27.5.1"
|
|
87
87
|
},
|
|
88
|
-
"gitHead": "
|
|
88
|
+
"gitHead": "9913ed7968dfab63d6549201a5a98f9819fcfac6"
|
|
89
89
|
}
|