@abtnode/core 1.8.66 → 1.8.67-beta-f8b4c9ec
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/manager/disk.js +79 -48
- package/lib/blocklet/manager/helper/install-from-backup.js +4 -4
- package/lib/blocklet/storage/backup/spaces.js +3 -3
- package/lib/blocklet/storage/restore/blocklets.js +5 -2
- package/lib/blocklet/storage/restore/spaces.js +5 -5
- package/lib/event.js +2 -2
- package/lib/index.js +0 -1
- package/lib/router/helper.js +1 -1
- package/lib/router/index.js +27 -0
- package/lib/states/node.js +1 -1
- package/lib/util/blocklet.js +43 -8
- package/package.json +26 -27
|
@@ -15,20 +15,18 @@ const { isNFTExpired, getNftExpirationDate } = require('@abtnode/util/lib/nft');
|
|
|
15
15
|
const didDocument = require('@abtnode/util/lib/did-document');
|
|
16
16
|
const { sign } = require('@arcblock/jwt');
|
|
17
17
|
const { isValid: isValidDid } = require('@arcblock/did');
|
|
18
|
-
const { verifyPresentation } = require('@arcblock/vc');
|
|
19
18
|
const { toSvg: createDidLogo } =
|
|
20
19
|
process.env.NODE_ENV !== 'test' ? require('@arcblock/did-motif') : require('@arcblock/did-motif/dist/did-motif.cjs');
|
|
21
20
|
const getBlockletInfo = require('@blocklet/meta/lib/info');
|
|
22
21
|
const sleep = require('@abtnode/util/lib/sleep');
|
|
23
22
|
|
|
24
23
|
const logger = require('@abtnode/logger')('@abtnode/core:blocklet:manager');
|
|
25
|
-
const { getVcFromPresentation } = require('@abtnode/util/lib/vc');
|
|
26
24
|
const {
|
|
27
|
-
VC_TYPE_BLOCKLET_PURCHASE,
|
|
28
25
|
WHO_CAN_ACCESS,
|
|
29
26
|
SERVER_ROLES,
|
|
30
27
|
WHO_CAN_ACCESS_PREFIX_ROLES,
|
|
31
28
|
BLOCKLET_INSTALL_TYPE,
|
|
29
|
+
NODE_MODES,
|
|
32
30
|
} = require('@abtnode/constant');
|
|
33
31
|
|
|
34
32
|
const getBlockletEngine = require('@blocklet/meta/lib/engine');
|
|
@@ -49,7 +47,7 @@ const getComponentProcessId = require('@blocklet/meta/lib/get-component-process-
|
|
|
49
47
|
const toBlockletDid = require('@blocklet/meta/lib/did');
|
|
50
48
|
const { validateMeta } = require('@blocklet/meta/lib/validate');
|
|
51
49
|
const { update: updateMetaFile } = require('@blocklet/meta/lib/file');
|
|
52
|
-
const { titleSchema,
|
|
50
|
+
const { titleSchema, updateMountPointSchema, environmentNameSchema } = require('@blocklet/meta/lib/schema');
|
|
53
51
|
const hasReservedKey = require('@blocklet/meta/lib/has-reserved-key');
|
|
54
52
|
const Lock = require('@abtnode/util/lib/lock');
|
|
55
53
|
|
|
@@ -111,6 +109,8 @@ const {
|
|
|
111
109
|
validateAppConfig,
|
|
112
110
|
checkDuplicateAppSk,
|
|
113
111
|
checkDuplicateMountPoint,
|
|
112
|
+
validateStore,
|
|
113
|
+
validateInServerless,
|
|
114
114
|
} = require('../../util/blocklet');
|
|
115
115
|
const StoreUtil = require('../../util/store');
|
|
116
116
|
const states = require('../../states');
|
|
@@ -242,6 +242,8 @@ class BlockletManager extends BaseBlockletManager {
|
|
|
242
242
|
* did: string;
|
|
243
243
|
* title: string;
|
|
244
244
|
* description: string;
|
|
245
|
+
* storeUrl: string;
|
|
246
|
+
* appSk: string;
|
|
245
247
|
* sync: boolean = false; // download synchronously, not use queue
|
|
246
248
|
* delay: number; // push download task to queue after a delay
|
|
247
249
|
* downloadTokenList: Array<{did: string, token: string}>;
|
|
@@ -278,28 +280,31 @@ class BlockletManager extends BaseBlockletManager {
|
|
|
278
280
|
context.startImmediately = !!params.startImmediately;
|
|
279
281
|
}
|
|
280
282
|
|
|
283
|
+
const { appSk } = params;
|
|
284
|
+
|
|
281
285
|
if (type === BLOCKLET_INSTALL_TYPE.URL) {
|
|
282
286
|
const { url, controller, sync, delay } = params;
|
|
283
|
-
return this._installFromUrl({ url, controller, sync, delay }, context);
|
|
287
|
+
return this._installFromUrl({ url, controller, sync, delay, appSk }, context);
|
|
284
288
|
}
|
|
285
289
|
|
|
286
290
|
if (type === BLOCKLET_INSTALL_TYPE.UPLOAD) {
|
|
287
291
|
const { file, did, diffVersion, deleteSet } = params;
|
|
288
|
-
return this._installFromUpload({ file, did, diffVersion, deleteSet,
|
|
292
|
+
return this._installFromUpload({ file, did, diffVersion, deleteSet, appSk }, context);
|
|
289
293
|
}
|
|
290
294
|
|
|
291
295
|
if (type === BLOCKLET_INSTALL_TYPE.STORE) {
|
|
292
296
|
const { did, controller, sync, delay, storeUrl } = params;
|
|
293
|
-
return this._installFromStore({ did, controller, sync, delay, storeUrl }, context);
|
|
297
|
+
return this._installFromStore({ did, controller, sync, delay, storeUrl, appSk }, context);
|
|
294
298
|
}
|
|
295
299
|
|
|
296
300
|
if (type === BLOCKLET_INSTALL_TYPE.CREATE) {
|
|
297
|
-
|
|
301
|
+
const { title, description } = params;
|
|
302
|
+
return this._installFromCreate({ title, description, appSk }, context);
|
|
298
303
|
}
|
|
299
304
|
|
|
300
305
|
if (type === BLOCKLET_INSTALL_TYPE.RESTORE) {
|
|
301
|
-
const { url
|
|
302
|
-
return this._installFromBackup({ url,
|
|
306
|
+
const { url } = params;
|
|
307
|
+
return this._installFromBackup({ url, appSk }, context);
|
|
303
308
|
}
|
|
304
309
|
|
|
305
310
|
// should not be here
|
|
@@ -343,10 +348,16 @@ class BlockletManager extends BaseBlockletManager {
|
|
|
343
348
|
},
|
|
344
349
|
context = {}
|
|
345
350
|
) {
|
|
346
|
-
const mountPoint = await
|
|
351
|
+
const mountPoint = await updateMountPointSchema.validateAsync(tmpMountPoint);
|
|
347
352
|
logger.debug('start install component', { rootDid, mountPoint, url });
|
|
348
353
|
|
|
349
354
|
if (file) {
|
|
355
|
+
// TODO: 如何触发这种场景?
|
|
356
|
+
const info = await states.node.read();
|
|
357
|
+
if (info.mode === NODE_MODES.SERVERLESS) {
|
|
358
|
+
throw new Error("Can't install component in serverless-mode server via upload");
|
|
359
|
+
}
|
|
360
|
+
|
|
350
361
|
return this._installComponentFromUpload({
|
|
351
362
|
rootDid,
|
|
352
363
|
mountPoint,
|
|
@@ -360,6 +371,11 @@ class BlockletManager extends BaseBlockletManager {
|
|
|
360
371
|
}
|
|
361
372
|
|
|
362
373
|
if (url) {
|
|
374
|
+
const info = await states.node.read();
|
|
375
|
+
if (info.mode === NODE_MODES.SERVERLESS) {
|
|
376
|
+
validateStore(info, url);
|
|
377
|
+
}
|
|
378
|
+
|
|
363
379
|
return this._installComponentFromUrl({
|
|
364
380
|
rootDid,
|
|
365
381
|
mountPoint,
|
|
@@ -431,25 +447,6 @@ class BlockletManager extends BaseBlockletManager {
|
|
|
431
447
|
return { isInstalled: !!blocklet, isRunning, blockletDid, isExternal };
|
|
432
448
|
}
|
|
433
449
|
|
|
434
|
-
async installBlockletFromVc({ vcPresentation, challenge }, context) {
|
|
435
|
-
logger.info('Install from vc');
|
|
436
|
-
const vc = getVcFromPresentation(vcPresentation);
|
|
437
|
-
|
|
438
|
-
// FIXME: 这里的 trustedIssuers 相当于相信任何 VC,需要想更安全的方法
|
|
439
|
-
verifyPresentation({ presentation: vcPresentation, trustedIssuers: [get(vc, 'issuer.id')], challenge });
|
|
440
|
-
|
|
441
|
-
if (!vc.type.includes(VC_TYPE_BLOCKLET_PURCHASE)) {
|
|
442
|
-
throw new Error(`Expect ${VC_TYPE_BLOCKLET_PURCHASE} VC type`);
|
|
443
|
-
}
|
|
444
|
-
|
|
445
|
-
const blockletUrl = get(vc, 'credentialSubject.purchased.blocklet.url');
|
|
446
|
-
const urlObject = new URL(blockletUrl);
|
|
447
|
-
const did = get(vc, 'credentialSubject.purchased.blocklet.id');
|
|
448
|
-
const registry = urlObject.origin;
|
|
449
|
-
|
|
450
|
-
return this._installFromStore({ did, registry }, context);
|
|
451
|
-
}
|
|
452
|
-
|
|
453
450
|
async start({ did, throwOnError, checkHealthImmediately = false, e2eMode = false }, context) {
|
|
454
451
|
logger.info('start blocklet', { did });
|
|
455
452
|
// should check blocklet integrity
|
|
@@ -631,7 +628,7 @@ class BlockletManager extends BaseBlockletManager {
|
|
|
631
628
|
// FIXME: 需要改成队列执行,本次失败,下次还需要重试,页面刷新后也能知道最新的状态
|
|
632
629
|
await this._installFromBackup({
|
|
633
630
|
url: `file://${spacesRestore.blockletRestoreDir}`,
|
|
634
|
-
|
|
631
|
+
appSk: spacesRestore.blockletWallet.secretKey,
|
|
635
632
|
moveDir: true,
|
|
636
633
|
});
|
|
637
634
|
}
|
|
@@ -1004,7 +1001,7 @@ class BlockletManager extends BaseBlockletManager {
|
|
|
1004
1001
|
}
|
|
1005
1002
|
|
|
1006
1003
|
// eslint-disable-next-line no-unused-vars
|
|
1007
|
-
async config({ did, configs: newConfigs, skipHook }, context) {
|
|
1004
|
+
async config({ did, configs: newConfigs, skipHook, skipDidDocument }, context) {
|
|
1008
1005
|
if (!Array.isArray(newConfigs)) {
|
|
1009
1006
|
throw new Error('configs list is not an array');
|
|
1010
1007
|
}
|
|
@@ -1064,7 +1061,7 @@ class BlockletManager extends BaseBlockletManager {
|
|
|
1064
1061
|
[BLOCKLET_CONFIGURABLE_KEY.BLOCKLET_APP_SK, BLOCKLET_CONFIGURABLE_KEY.BLOCKLET_WALLET_TYPE].includes(item.key)
|
|
1065
1062
|
);
|
|
1066
1063
|
|
|
1067
|
-
if (isSkOrWalletTypeChanged) {
|
|
1064
|
+
if (isSkOrWalletTypeChanged && !skipDidDocument) {
|
|
1068
1065
|
await this._updateDidDocument(blocklet);
|
|
1069
1066
|
}
|
|
1070
1067
|
|
|
@@ -1198,7 +1195,7 @@ class BlockletManager extends BaseBlockletManager {
|
|
|
1198
1195
|
}
|
|
1199
1196
|
|
|
1200
1197
|
async updateComponentMountPoint({ did, rootDid: inputRootDid, mountPoint: tmpMountPoint }, context) {
|
|
1201
|
-
const mountPoint = await
|
|
1198
|
+
const mountPoint = await updateMountPointSchema.validateAsync(tmpMountPoint);
|
|
1202
1199
|
|
|
1203
1200
|
const blocklet = await states.blocklet.getBlocklet(inputRootDid);
|
|
1204
1201
|
|
|
@@ -1679,13 +1676,13 @@ class BlockletManager extends BaseBlockletManager {
|
|
|
1679
1676
|
* /blocklet.json
|
|
1680
1677
|
* /blocklet_extras.json
|
|
1681
1678
|
* @see Blocklet 端到端备份方案的设计与实现(一期) https://team.arcblock.io/comment/discussions/e62084d5-fafa-489e-91d5-defcd6e93223
|
|
1682
|
-
* @param {{ url: string,
|
|
1679
|
+
* @param {{ url: string, appSk: string, moveDir: boolean}} [{ url }={}]
|
|
1683
1680
|
* @param {Record<string, string>} [context={}]
|
|
1684
1681
|
* @return {Promise<any>}
|
|
1685
1682
|
* @memberof BlockletManager
|
|
1686
1683
|
*/
|
|
1687
|
-
async _installFromBackup({ url,
|
|
1688
|
-
return installFromBackup({ url,
|
|
1684
|
+
async _installFromBackup({ url, appSk, moveDir } = {}, context = {}) {
|
|
1685
|
+
return installFromBackup({ url, appSk, moveDir, context, manager: this, states });
|
|
1689
1686
|
}
|
|
1690
1687
|
|
|
1691
1688
|
async ensureBlocklet(did, opts = {}) {
|
|
@@ -2084,17 +2081,18 @@ class BlockletManager extends BaseBlockletManager {
|
|
|
2084
2081
|
*
|
|
2085
2082
|
* @param {{
|
|
2086
2083
|
* did: string;
|
|
2087
|
-
* registry: string;
|
|
2088
2084
|
* sync: boolean;
|
|
2089
2085
|
* delay: number;
|
|
2090
2086
|
* controller: Controller;
|
|
2087
|
+
* appSk: string;
|
|
2088
|
+
* storeUrl: string;
|
|
2091
2089
|
* }} params
|
|
2092
2090
|
* @param {*} context
|
|
2093
2091
|
* @return {*}
|
|
2094
2092
|
* @memberof BlockletManager
|
|
2095
2093
|
*/
|
|
2096
2094
|
async _installFromStore(params, context) {
|
|
2097
|
-
const { did, storeUrl, sync, delay, controller } = params;
|
|
2095
|
+
const { did, storeUrl, sync, delay, controller, appSk } = params;
|
|
2098
2096
|
|
|
2099
2097
|
logger.debug('start install blocklet', { did });
|
|
2100
2098
|
if (!isValidDid(did)) {
|
|
@@ -2138,6 +2136,7 @@ class BlockletManager extends BaseBlockletManager {
|
|
|
2138
2136
|
sync,
|
|
2139
2137
|
delay,
|
|
2140
2138
|
controller,
|
|
2139
|
+
appSk,
|
|
2141
2140
|
context,
|
|
2142
2141
|
});
|
|
2143
2142
|
}
|
|
@@ -2154,13 +2153,14 @@ class BlockletManager extends BaseBlockletManager {
|
|
|
2154
2153
|
* sync: boolean;
|
|
2155
2154
|
* delay: number;
|
|
2156
2155
|
* controller: Controller;
|
|
2156
|
+
* appSk: string;
|
|
2157
2157
|
* }} params
|
|
2158
2158
|
* @param {{}} context
|
|
2159
2159
|
* @return {*}
|
|
2160
2160
|
* @memberof BlockletManager
|
|
2161
2161
|
*/
|
|
2162
2162
|
async _installFromUrl(params, context) {
|
|
2163
|
-
const { url, sync, delay, controller } = params;
|
|
2163
|
+
const { url, sync, delay, controller, appSk } = params;
|
|
2164
2164
|
|
|
2165
2165
|
logger.debug('start install blocklet', { url });
|
|
2166
2166
|
|
|
@@ -2174,13 +2174,18 @@ class BlockletManager extends BaseBlockletManager {
|
|
|
2174
2174
|
|
|
2175
2175
|
// install from store if url is a store url
|
|
2176
2176
|
const { inStore, registryUrl, blockletDid: bundleDid } = await StoreUtil.parseSourceUrl(url, controller);
|
|
2177
|
+
|
|
2178
|
+
const nodeInfo = await states.node.read();
|
|
2179
|
+
|
|
2180
|
+
await validateStore(nodeInfo, registryUrl);
|
|
2181
|
+
|
|
2177
2182
|
if (inStore) {
|
|
2178
2183
|
const exist = await states.blocklet.getBlocklet(blockletDid);
|
|
2179
2184
|
if (exist) {
|
|
2180
2185
|
return this.upgrade({ did: blockletDid, storeUrl: registryUrl, sync, delay }, context);
|
|
2181
2186
|
}
|
|
2182
2187
|
|
|
2183
|
-
return this._installFromStore({ did: bundleDid, storeUrl: registryUrl, controller, sync, delay }, context);
|
|
2188
|
+
return this._installFromStore({ did: bundleDid, storeUrl: registryUrl, controller, sync, delay, appSk }, context);
|
|
2184
2189
|
}
|
|
2185
2190
|
|
|
2186
2191
|
const meta = ensureMeta(bundleMeta, { name: blockletName, did: blockletDid });
|
|
@@ -2206,6 +2211,7 @@ class BlockletManager extends BaseBlockletManager {
|
|
|
2206
2211
|
sync,
|
|
2207
2212
|
delay,
|
|
2208
2213
|
controller,
|
|
2214
|
+
appSk,
|
|
2209
2215
|
context,
|
|
2210
2216
|
});
|
|
2211
2217
|
}
|
|
@@ -2310,7 +2316,7 @@ class BlockletManager extends BaseBlockletManager {
|
|
|
2310
2316
|
);
|
|
2311
2317
|
}
|
|
2312
2318
|
|
|
2313
|
-
async _installFromCreate({ title, description }, context = {}) {
|
|
2319
|
+
async _installFromCreate({ title, description, appSk }, context = {}) {
|
|
2314
2320
|
logger.debug('create blocklet', { title, description });
|
|
2315
2321
|
|
|
2316
2322
|
await joi.string().label('title').max(20).required().validateAsync(title);
|
|
@@ -2338,11 +2344,9 @@ class BlockletManager extends BaseBlockletManager {
|
|
|
2338
2344
|
};
|
|
2339
2345
|
const meta = validateMeta(rawMeta);
|
|
2340
2346
|
|
|
2341
|
-
await states.blocklet.addBlocklet({
|
|
2342
|
-
meta,
|
|
2343
|
-
source: BlockletSource.custom,
|
|
2344
|
-
});
|
|
2347
|
+
await states.blocklet.addBlocklet({ meta, source: BlockletSource.custom });
|
|
2345
2348
|
await this._setConfigsFromMeta(did);
|
|
2349
|
+
await this._setAppSk(did, appSk);
|
|
2346
2350
|
|
|
2347
2351
|
// check duplicate appSk
|
|
2348
2352
|
await checkDuplicateAppSk({ did, states });
|
|
@@ -2382,7 +2386,7 @@ class BlockletManager extends BaseBlockletManager {
|
|
|
2382
2386
|
return { cwd, tarFile };
|
|
2383
2387
|
}
|
|
2384
2388
|
|
|
2385
|
-
async _installFromUpload({ file, did, diffVersion, deleteSet,
|
|
2389
|
+
async _installFromUpload({ file, did, diffVersion, deleteSet, appSk }, context) {
|
|
2386
2390
|
logger.info('install blocklet', { from: 'upload file' });
|
|
2387
2391
|
const { tarFile } = await this._downloadFromUpload(file);
|
|
2388
2392
|
|
|
@@ -2480,6 +2484,7 @@ class BlockletManager extends BaseBlockletManager {
|
|
|
2480
2484
|
const oldState = { extraState: oldExtraState };
|
|
2481
2485
|
try {
|
|
2482
2486
|
await this._setConfigsFromMeta(meta.did);
|
|
2487
|
+
await this._setAppSk(appSk);
|
|
2483
2488
|
await validateBlocklet(blocklet);
|
|
2484
2489
|
|
|
2485
2490
|
// check duplicate appSk
|
|
@@ -2776,6 +2781,7 @@ class BlockletManager extends BaseBlockletManager {
|
|
|
2776
2781
|
* meta: {}; // blocklet meta
|
|
2777
2782
|
* source: number; // example: BlockletSource.registry,
|
|
2778
2783
|
* deployedFrom: string;
|
|
2784
|
+
* appSk: string;
|
|
2779
2785
|
* context: {}
|
|
2780
2786
|
* sync: boolean = false;
|
|
2781
2787
|
* delay: number;
|
|
@@ -2785,10 +2791,15 @@ class BlockletManager extends BaseBlockletManager {
|
|
|
2785
2791
|
* @memberof BlockletManager
|
|
2786
2792
|
*/
|
|
2787
2793
|
async _install(params) {
|
|
2788
|
-
const { meta, source, deployedFrom, context, sync, delay, controller } = params;
|
|
2794
|
+
const { meta, source, deployedFrom, context, sync, delay, controller, appSk } = params;
|
|
2789
2795
|
|
|
2790
2796
|
validateBlockletMeta(meta, { ensureDist: true });
|
|
2791
2797
|
|
|
2798
|
+
const info = await states.node.read();
|
|
2799
|
+
if (info.mode === NODE_MODES.SERVERLESS) {
|
|
2800
|
+
validateInServerless({ blockletMeta: meta });
|
|
2801
|
+
}
|
|
2802
|
+
|
|
2792
2803
|
const { name, did, version } = meta;
|
|
2793
2804
|
|
|
2794
2805
|
const oldExtraState = await states.blockletExtras.findOne({ did: meta.did });
|
|
@@ -2808,6 +2819,7 @@ class BlockletManager extends BaseBlockletManager {
|
|
|
2808
2819
|
await states.blockletExtras.addMeta({ did, meta: { did, name }, controller });
|
|
2809
2820
|
|
|
2810
2821
|
await this._setConfigsFromMeta(did);
|
|
2822
|
+
await this._setAppSk(did, appSk);
|
|
2811
2823
|
|
|
2812
2824
|
// check duplicate appSk
|
|
2813
2825
|
await checkDuplicateAppSk({ did, states });
|
|
@@ -3405,12 +3417,31 @@ class BlockletManager extends BaseBlockletManager {
|
|
|
3405
3417
|
}
|
|
3406
3418
|
}
|
|
3407
3419
|
|
|
3420
|
+
async _setAppSk(did, appSk, context) {
|
|
3421
|
+
if (process.env.NODE_ENV === 'production' && !appSk) {
|
|
3422
|
+
throw new Error(`appSk for blocklet ${did} is required`);
|
|
3423
|
+
}
|
|
3424
|
+
|
|
3425
|
+
if (appSk) {
|
|
3426
|
+
await this.config(
|
|
3427
|
+
{
|
|
3428
|
+
did,
|
|
3429
|
+
configs: [{ key: 'BLOCKLET_APP_SK', value: appSk, secure: true }],
|
|
3430
|
+
skipHook: true,
|
|
3431
|
+
skipDidDocument: true,
|
|
3432
|
+
},
|
|
3433
|
+
context
|
|
3434
|
+
);
|
|
3435
|
+
}
|
|
3436
|
+
}
|
|
3437
|
+
|
|
3408
3438
|
async _findNextCustomBlockletName(leftTimes = 10) {
|
|
3409
3439
|
if (leftTimes <= 0) {
|
|
3410
3440
|
throw new Error('Generate custom blocklet did too many times');
|
|
3411
3441
|
}
|
|
3412
3442
|
const number = await states.node.increaseCustomBlockletNumber();
|
|
3413
3443
|
const name = `custom-${number}`;
|
|
3444
|
+
// MEMO: 空壳 APP可以保留原有的 did 生成逻辑
|
|
3414
3445
|
const did = toBlockletDid(name);
|
|
3415
3446
|
const blocklet = await states.blocklet.getBlocklet(did);
|
|
3416
3447
|
if (blocklet) {
|
|
@@ -19,7 +19,7 @@ const { validateBlocklet, checkDuplicateAppSk, getAppDirs } = require('../../../
|
|
|
19
19
|
* }} param0
|
|
20
20
|
* @returns
|
|
21
21
|
*/
|
|
22
|
-
module.exports = async ({ url,
|
|
22
|
+
module.exports = async ({ url, appSk, moveDir, context = {}, states, manager } = {}) => {
|
|
23
23
|
// TODO: support more url schema feature (http, did-spaces)
|
|
24
24
|
if (!url.startsWith('file://')) {
|
|
25
25
|
throw new Error('url must starts with file://');
|
|
@@ -71,17 +71,17 @@ module.exports = async ({ url, blockletSecretKey, moveDir, context = {}, states,
|
|
|
71
71
|
throw new Error('blocklet is already exist');
|
|
72
72
|
}
|
|
73
73
|
|
|
74
|
-
if (
|
|
74
|
+
if (appSk) {
|
|
75
75
|
extra.configs = extra.configs || [];
|
|
76
76
|
const skConfig = extra.configs.find((x) => x.key === BLOCKLET_CONFIGURABLE_KEY.BLOCKLET_APP_SK);
|
|
77
77
|
if (skConfig) {
|
|
78
|
-
skConfig.value =
|
|
78
|
+
skConfig.value = appSk;
|
|
79
79
|
skConfig.secure = true;
|
|
80
80
|
skConfig.shared = false;
|
|
81
81
|
} else {
|
|
82
82
|
extra.configs.push({
|
|
83
83
|
key: BLOCKLET_CONFIGURABLE_KEY.BLOCKLET_APP_SK,
|
|
84
|
-
value:
|
|
84
|
+
value: appSk,
|
|
85
85
|
secure: true,
|
|
86
86
|
shared: false,
|
|
87
87
|
});
|
|
@@ -150,10 +150,10 @@ class SpacesBackup {
|
|
|
150
150
|
const { errorCount } = await spaceClient.send(
|
|
151
151
|
new SyncFolderPushCommand({
|
|
152
152
|
source: join(this.blockletBackupDir, '/'),
|
|
153
|
-
target: join('.did-objects', this.blocklet.appDid),
|
|
153
|
+
target: join('.did-objects', this.blocklet.appDid, '/'),
|
|
154
154
|
debug: true,
|
|
155
|
-
concurrency:
|
|
156
|
-
retryCount:
|
|
155
|
+
concurrency: 32,
|
|
156
|
+
retryCount: 10,
|
|
157
157
|
filter: (object) => {
|
|
158
158
|
return object.name !== '.DS_Store';
|
|
159
159
|
},
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
const { existsSync, remove } = require('fs-extra');
|
|
1
|
+
const { existsSync, remove, ensureDirSync } = require('fs-extra');
|
|
2
2
|
const { join } = require('path');
|
|
3
3
|
const fg = require('fast-glob');
|
|
4
4
|
const { BaseRestore } = require('./base');
|
|
@@ -10,8 +10,11 @@ class BlockletsRestore extends BaseRestore {
|
|
|
10
10
|
async import() {
|
|
11
11
|
const blockletsDir = join(this.blockletRestoreDir, this.filename);
|
|
12
12
|
|
|
13
|
+
// blockletsDir 可以不存在, 因为还原的 blocklet 可能所有的组件都是来自 store 的
|
|
13
14
|
if (!existsSync(blockletsDir)) {
|
|
14
|
-
|
|
15
|
+
// FIXME: 如果文件夹不存在,需要创建文件夹,因为 installFromBackup 未做容错处理
|
|
16
|
+
ensureDirSync(blockletsDir);
|
|
17
|
+
return;
|
|
15
18
|
}
|
|
16
19
|
|
|
17
20
|
const paths = await fg('**/*.zip', {
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* @typedef {{
|
|
3
3
|
* endpoint: string;
|
|
4
|
-
*
|
|
4
|
+
* appSk: string;
|
|
5
5
|
* }} SpaceRestoreInput
|
|
6
6
|
*/
|
|
7
7
|
|
|
@@ -98,7 +98,7 @@ class SpacesRestore {
|
|
|
98
98
|
|
|
99
99
|
async getBlockletWallet() {
|
|
100
100
|
// @FIXME: blocklet 钱包类型如何得知呢?
|
|
101
|
-
const wallet = fromSecretKey(this.input.
|
|
101
|
+
const wallet = fromSecretKey(this.input.appSk, WalletType({ role: types.RoleType.ROLE_APPLICATION }));
|
|
102
102
|
|
|
103
103
|
return wallet;
|
|
104
104
|
}
|
|
@@ -115,10 +115,10 @@ class SpacesRestore {
|
|
|
115
115
|
const { errorCount } = await spaceClient.send(
|
|
116
116
|
new SyncFolderPullCommand({
|
|
117
117
|
source: join('.did-objects', this.blockletWallet.address, '/'),
|
|
118
|
-
target: this.blockletRestoreDir,
|
|
118
|
+
target: join(this.blockletRestoreDir, '/'),
|
|
119
119
|
debug: true,
|
|
120
|
-
concurrency:
|
|
121
|
-
retryCount:
|
|
120
|
+
concurrency: 32,
|
|
121
|
+
retryCount: 10,
|
|
122
122
|
})
|
|
123
123
|
);
|
|
124
124
|
|
package/lib/event.js
CHANGED
|
@@ -81,7 +81,7 @@ module.exports = ({
|
|
|
81
81
|
}
|
|
82
82
|
};
|
|
83
83
|
|
|
84
|
-
const
|
|
84
|
+
const handleBlockletInstall = async (name, { blocklet, context }) => {
|
|
85
85
|
try {
|
|
86
86
|
const changed = await ensureBlockletRouting(blocklet, context);
|
|
87
87
|
if (changed) {
|
|
@@ -173,7 +173,7 @@ module.exports = ({
|
|
|
173
173
|
const blocklet = payload.blocklet || payload;
|
|
174
174
|
|
|
175
175
|
if ([BlockletEvents.installed].includes(eventName)) {
|
|
176
|
-
await
|
|
176
|
+
await handleBlockletInstall(eventName, payload);
|
|
177
177
|
|
|
178
178
|
try {
|
|
179
179
|
await node.createAuditLog({
|
package/lib/index.js
CHANGED
|
@@ -192,7 +192,6 @@ function ABTNode(options) {
|
|
|
192
192
|
|
|
193
193
|
// Blocklet manager
|
|
194
194
|
installBlocklet: blockletManager.install.bind(blockletManager),
|
|
195
|
-
installBlockletFromVc: blockletManager.installBlockletFromVc.bind(blockletManager),
|
|
196
195
|
installComponent: blockletManager.installComponent.bind(blockletManager),
|
|
197
196
|
startBlocklet: blockletManager.start.bind(blockletManager),
|
|
198
197
|
stopBlocklet: blockletManager.stop.bind(blockletManager),
|
package/lib/router/helper.js
CHANGED
|
@@ -518,7 +518,7 @@ module.exports = function getRouterHelpers({ dataDirs, routingSnapshot, routerMa
|
|
|
518
518
|
|
|
519
519
|
const ensureDomainCert = async (domain, url) => {
|
|
520
520
|
const cert = await certManager.getByDomain(domain);
|
|
521
|
-
if (!cert) {
|
|
521
|
+
if (!cert || get(cert, 'meta.validTo') <= Date.now()) {
|
|
522
522
|
await downloadCert({
|
|
523
523
|
domain,
|
|
524
524
|
url,
|
package/lib/router/index.js
CHANGED
|
@@ -183,6 +183,10 @@ Router.formatSites = (sites = []) => {
|
|
|
183
183
|
result.forEach((site) => {
|
|
184
184
|
if (Array.isArray(site.rules) && site.rules.length > 0) {
|
|
185
185
|
const rules = cloneDeep(site.rules);
|
|
186
|
+
|
|
187
|
+
let hasRootPathBlockletRule = false;
|
|
188
|
+
let tmpBlockletRule;
|
|
189
|
+
|
|
186
190
|
rules.forEach((rule) => {
|
|
187
191
|
if ([ROUTING_RULE_TYPES.BLOCKLET].includes(rule.to.type) === false) {
|
|
188
192
|
return;
|
|
@@ -197,6 +201,11 @@ Router.formatSites = (sites = []) => {
|
|
|
197
201
|
}
|
|
198
202
|
|
|
199
203
|
if (daemonRule) {
|
|
204
|
+
if (rule.from.pathPrefix === '/') {
|
|
205
|
+
hasRootPathBlockletRule = true;
|
|
206
|
+
}
|
|
207
|
+
tmpBlockletRule = rule;
|
|
208
|
+
|
|
200
209
|
// Serve meta js: both prefix and suffix do not contain trailing slash
|
|
201
210
|
// NOTICE: 这里隐含了一个约定
|
|
202
211
|
// 如果安装的 blockletA 和 blockletB 都需要 __blocklet__.js
|
|
@@ -244,6 +253,24 @@ Router.formatSites = (sites = []) => {
|
|
|
244
253
|
});
|
|
245
254
|
}
|
|
246
255
|
});
|
|
256
|
+
|
|
257
|
+
// ensure /__blocklet__.js should be proxy to daemon
|
|
258
|
+
if (daemonRule && !hasRootPathBlockletRule && tmpBlockletRule) {
|
|
259
|
+
site.rules.push({
|
|
260
|
+
from: {
|
|
261
|
+
pathPrefix: '/',
|
|
262
|
+
groupPathPrefix: '/',
|
|
263
|
+
pathSuffix: '/__blocklet__.js',
|
|
264
|
+
},
|
|
265
|
+
to: {
|
|
266
|
+
type: ROUTING_RULE_TYPES.DAEMON,
|
|
267
|
+
port: daemonRule.to.port,
|
|
268
|
+
did: tmpBlockletRule.to.did,
|
|
269
|
+
componentId: tmpBlockletRule.to.did,
|
|
270
|
+
cacheGroup: site.mode === BLOCKLET_MODES.PRODUCTION ? 'blockletJs' : '',
|
|
271
|
+
},
|
|
272
|
+
});
|
|
273
|
+
}
|
|
247
274
|
}
|
|
248
275
|
});
|
|
249
276
|
|
package/lib/states/node.js
CHANGED
package/lib/util/blocklet.js
CHANGED
|
@@ -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 {
|
|
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'];
|
|
@@ -835,7 +840,7 @@ const parseChildrenFromMeta = async (src, context = {}) => {
|
|
|
835
840
|
};
|
|
836
841
|
|
|
837
842
|
const validateBlocklet = (blocklet) =>
|
|
838
|
-
forEachBlocklet(blocklet, (b) => {
|
|
843
|
+
forEachBlocklet(blocklet, async (b) => {
|
|
839
844
|
isRequirementsSatisfied(b.meta.requirements);
|
|
840
845
|
validateEngine(getBlockletEngineNameByPlatform(b.meta));
|
|
841
846
|
});
|
|
@@ -1400,12 +1405,14 @@ const getBlocklet = async ({
|
|
|
1400
1405
|
|
|
1401
1406
|
blocklet.settings.storeList = blocklet.settings.storeList || [];
|
|
1402
1407
|
|
|
1403
|
-
|
|
1404
|
-
blocklet.settings.storeList.
|
|
1405
|
-
|
|
1406
|
-
|
|
1407
|
-
|
|
1408
|
-
|
|
1408
|
+
[BLOCKLET_STORE_DEV, BLOCKLET_STORE].forEach((store) => {
|
|
1409
|
+
if (!blocklet.settings.storeList.find((x) => x.url === store.url)) {
|
|
1410
|
+
blocklet.settings.storeList.unshift({
|
|
1411
|
+
...store,
|
|
1412
|
+
protected: true,
|
|
1413
|
+
});
|
|
1414
|
+
}
|
|
1415
|
+
});
|
|
1409
1416
|
|
|
1410
1417
|
// app site
|
|
1411
1418
|
blocklet.site = await states.site.findOneByBlocklet(blocklet.meta.did);
|
|
@@ -1690,6 +1697,32 @@ const checkDuplicateMountPoint = (blocklet, mountPoint) => {
|
|
|
1690
1697
|
}
|
|
1691
1698
|
};
|
|
1692
1699
|
|
|
1700
|
+
const validateStore = (nodeInfo, storeUrl) => {
|
|
1701
|
+
if (nodeInfo.mode !== 'serverless') {
|
|
1702
|
+
return;
|
|
1703
|
+
}
|
|
1704
|
+
|
|
1705
|
+
const inStoreList = nodeInfo.blockletRegistryList.find((item) => {
|
|
1706
|
+
const itemURLObj = new URL(item.url);
|
|
1707
|
+
const storeUrlObj = new URL(storeUrl);
|
|
1708
|
+
|
|
1709
|
+
return itemURLObj.host === storeUrlObj.host;
|
|
1710
|
+
});
|
|
1711
|
+
|
|
1712
|
+
if (!inStoreList) {
|
|
1713
|
+
throw new Error('Must be installed from the compliant blocklet store list');
|
|
1714
|
+
}
|
|
1715
|
+
};
|
|
1716
|
+
|
|
1717
|
+
const validateInServerless = ({ blockletMeta }) => {
|
|
1718
|
+
const { interfaces } = blockletMeta;
|
|
1719
|
+
const externalPortInterfaces = (interfaces || []).filter((item) => !!item.port?.external);
|
|
1720
|
+
|
|
1721
|
+
if (externalPortInterfaces.length > 0) {
|
|
1722
|
+
throw new Error('Blocklets with exposed ports cannot be installed');
|
|
1723
|
+
}
|
|
1724
|
+
};
|
|
1725
|
+
|
|
1693
1726
|
module.exports = {
|
|
1694
1727
|
consumeServerlessNFT,
|
|
1695
1728
|
forEachBlocklet,
|
|
@@ -1737,4 +1770,6 @@ module.exports = {
|
|
|
1737
1770
|
validateAppConfig,
|
|
1738
1771
|
checkDuplicateAppSk,
|
|
1739
1772
|
checkDuplicateMountPoint,
|
|
1773
|
+
validateStore,
|
|
1774
|
+
validateInServerless,
|
|
1740
1775
|
};
|
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.67-beta-f8b4c9ec",
|
|
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.
|
|
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.
|
|
34
|
-
"@arcblock/did": "1.18.
|
|
22
|
+
"@abtnode/auth": "1.8.67-beta-f8b4c9ec",
|
|
23
|
+
"@abtnode/certificate-manager": "1.8.67-beta-f8b4c9ec",
|
|
24
|
+
"@abtnode/constant": "1.8.67-beta-f8b4c9ec",
|
|
25
|
+
"@abtnode/cron": "1.8.67-beta-f8b4c9ec",
|
|
26
|
+
"@abtnode/db": "1.8.67-beta-f8b4c9ec",
|
|
27
|
+
"@abtnode/logger": "1.8.67-beta-f8b4c9ec",
|
|
28
|
+
"@abtnode/queue": "1.8.67-beta-f8b4c9ec",
|
|
29
|
+
"@abtnode/rbac": "1.8.67-beta-f8b4c9ec",
|
|
30
|
+
"@abtnode/router-provider": "1.8.67-beta-f8b4c9ec",
|
|
31
|
+
"@abtnode/static-server": "1.8.67-beta-f8b4c9ec",
|
|
32
|
+
"@abtnode/timemachine": "1.8.67-beta-f8b4c9ec",
|
|
33
|
+
"@abtnode/util": "1.8.67-beta-f8b4c9ec",
|
|
34
|
+
"@arcblock/did": "1.18.54",
|
|
35
35
|
"@arcblock/did-motif": "^1.1.10",
|
|
36
|
-
"@arcblock/did-util": "1.18.
|
|
37
|
-
"@arcblock/event-hub": "1.18.
|
|
38
|
-
"@arcblock/jwt": "^1.18.
|
|
36
|
+
"@arcblock/did-util": "1.18.54",
|
|
37
|
+
"@arcblock/event-hub": "1.18.54",
|
|
38
|
+
"@arcblock/jwt": "^1.18.54",
|
|
39
39
|
"@arcblock/pm2-events": "^0.0.5",
|
|
40
|
-
"@arcblock/vc": "1.18.
|
|
41
|
-
"@blocklet/constant": "1.8.
|
|
42
|
-
"@blocklet/meta": "1.8.
|
|
43
|
-
"@blocklet/sdk": "1.8.
|
|
44
|
-
"@did-space/client": "^0.1.
|
|
40
|
+
"@arcblock/vc": "1.18.54",
|
|
41
|
+
"@blocklet/constant": "1.8.67-beta-f8b4c9ec",
|
|
42
|
+
"@blocklet/meta": "1.8.67-beta-f8b4c9ec",
|
|
43
|
+
"@blocklet/sdk": "1.8.67-beta-f8b4c9ec",
|
|
44
|
+
"@did-space/client": "^0.1.76",
|
|
45
45
|
"@fidm/x509": "^1.2.1",
|
|
46
|
-
"@ocap/mcrypto": "1.18.
|
|
47
|
-
"@ocap/util": "1.18.
|
|
48
|
-
"@ocap/wallet": "1.18.
|
|
46
|
+
"@ocap/mcrypto": "1.18.54",
|
|
47
|
+
"@ocap/util": "1.18.54",
|
|
48
|
+
"@ocap/wallet": "1.18.54",
|
|
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": "
|
|
92
|
+
"gitHead": "ebf19fcbc6d99fff0d214dc0680c4df81aa94d6d"
|
|
94
93
|
}
|