@abtnode/core 1.7.25 → 1.8.0
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/api/team.js +54 -22
- package/lib/blocklet/manager/disk.js +333 -93
- package/lib/index.js +7 -1
- package/lib/router/index.js +2 -5
- package/lib/states/user.js +41 -5
- package/lib/team/manager.js +34 -4
- package/lib/util/blocklet.js +2 -17
- package/package.json +22 -21
package/lib/api/team.js
CHANGED
|
@@ -1,13 +1,15 @@
|
|
|
1
1
|
const { EventEmitter } = require('events');
|
|
2
2
|
const pick = require('lodash/pick');
|
|
3
3
|
const logger = require('@abtnode/logger')('@abtnode/core:api:team');
|
|
4
|
-
const { ROLES, genPermissionName, EVENTS, WHO_CAN_ACCESS } = require('@abtnode/constant');
|
|
4
|
+
const { ROLES, genPermissionName, EVENTS, WHO_CAN_ACCESS, PASSPORT_STATUS } = require('@abtnode/constant');
|
|
5
5
|
const { isValid: isValidDid } = require('@arcblock/did');
|
|
6
6
|
const { BlockletEvents } = require('@blocklet/meta/lib/constants');
|
|
7
7
|
const { validateTrustedPassportIssuers } = require('../validators/trusted-passport');
|
|
8
8
|
const { validateCreateRole, validateUpdateRole } = require('../validators/role');
|
|
9
9
|
const { validateCreatePermission, validateUpdatePermission } = require('../validators/permission');
|
|
10
10
|
|
|
11
|
+
const MAX_USER_PAGE_SIZE = 100;
|
|
12
|
+
|
|
11
13
|
const validateReservedRole = (role) => {
|
|
12
14
|
if (Object.values(ROLES).includes(role)) {
|
|
13
15
|
throw new Error(`The role ${role} is reserved`);
|
|
@@ -68,29 +70,37 @@ class TeamAPI extends EventEmitter {
|
|
|
68
70
|
return doc;
|
|
69
71
|
}
|
|
70
72
|
|
|
71
|
-
async getUsers({ teamDid }) {
|
|
73
|
+
async getUsers({ teamDid, query, paging: inputPaging, sort }) {
|
|
72
74
|
const state = await this.getUserState(teamDid);
|
|
73
75
|
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
76
|
+
if (inputPaging?.pageSize > MAX_USER_PAGE_SIZE) {
|
|
77
|
+
throw new Error(`Length of users should not exceed ${MAX_USER_PAGE_SIZE} per page`);
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
const { list, paging } = await state.getUsers({ query, sort, paging: { pageSize: 20, ...inputPaging } });
|
|
81
|
+
|
|
82
|
+
return {
|
|
83
|
+
users: list.map(
|
|
84
|
+
(d) =>
|
|
85
|
+
pick(d, [
|
|
86
|
+
'did',
|
|
87
|
+
'pk',
|
|
88
|
+
'role',
|
|
89
|
+
'email',
|
|
90
|
+
'fullName',
|
|
91
|
+
'approved',
|
|
92
|
+
'createdAt',
|
|
93
|
+
'updatedAt',
|
|
94
|
+
'passports',
|
|
95
|
+
'firstLoginAt',
|
|
96
|
+
'lastLoginAt',
|
|
97
|
+
'remark',
|
|
98
|
+
'avatar',
|
|
99
|
+
])
|
|
100
|
+
// eslint-disable-next-line function-paren-newline
|
|
101
|
+
),
|
|
102
|
+
paging,
|
|
103
|
+
};
|
|
94
104
|
}
|
|
95
105
|
|
|
96
106
|
async getUsersCount({ teamDid }) {
|
|
@@ -99,6 +109,28 @@ class TeamAPI extends EventEmitter {
|
|
|
99
109
|
return state.count();
|
|
100
110
|
}
|
|
101
111
|
|
|
112
|
+
async getUsersCountPerRole({ teamDid }) {
|
|
113
|
+
const roles = await this.getRoles({ teamDid });
|
|
114
|
+
|
|
115
|
+
const state = await this.getUserState(teamDid);
|
|
116
|
+
|
|
117
|
+
const res = [];
|
|
118
|
+
|
|
119
|
+
const all = await state.count();
|
|
120
|
+
res.push({ key: '$all', value: all });
|
|
121
|
+
|
|
122
|
+
for (const { name } of roles) {
|
|
123
|
+
// eslint-disable-next-line no-await-in-loop
|
|
124
|
+
const count = await state.count({ passports: { $elemMatch: { name, status: PASSPORT_STATUS.VALID } } });
|
|
125
|
+
res.push({ key: name, value: count });
|
|
126
|
+
}
|
|
127
|
+
|
|
128
|
+
const none = await state.count({ passports: { $size: 0 } });
|
|
129
|
+
res.push({ key: '$none', value: none });
|
|
130
|
+
|
|
131
|
+
return res;
|
|
132
|
+
}
|
|
133
|
+
|
|
102
134
|
async getUser({ teamDid, user }) {
|
|
103
135
|
const state = await this.getUserState(teamDid);
|
|
104
136
|
|
|
@@ -10,7 +10,7 @@ const capitalize = require('lodash/capitalize');
|
|
|
10
10
|
const { Throttle } = require('stream-throttle');
|
|
11
11
|
const LRU = require('lru-cache');
|
|
12
12
|
const joi = require('joi');
|
|
13
|
-
|
|
13
|
+
const { sign } = require('@arcblock/jwt');
|
|
14
14
|
const { isValid: isValidDid } = require('@arcblock/did');
|
|
15
15
|
const { verifyPresentation } = require('@arcblock/vc');
|
|
16
16
|
const { toBase58, isHex } = require('@ocap/util');
|
|
@@ -45,6 +45,7 @@ const toBlockletDid = require('@blocklet/meta/lib/did');
|
|
|
45
45
|
const { validateMeta } = require('@blocklet/meta/lib/validate');
|
|
46
46
|
const { update: updateMetaFile } = require('@blocklet/meta/lib/file');
|
|
47
47
|
const { titleSchema, descriptionSchema } = require('@blocklet/meta/lib/schema');
|
|
48
|
+
const hasReservedKey = require('@blocklet/meta/lib/has-reserved-key');
|
|
48
49
|
|
|
49
50
|
const {
|
|
50
51
|
BlockletStatus,
|
|
@@ -101,7 +102,6 @@ const {
|
|
|
101
102
|
getDiffFiles,
|
|
102
103
|
getBundleDir,
|
|
103
104
|
needBlockletDownload,
|
|
104
|
-
verifyPurchase,
|
|
105
105
|
findAvailableDid,
|
|
106
106
|
ensureMeta,
|
|
107
107
|
} = require('../../util/blocklet');
|
|
@@ -172,13 +172,15 @@ class BlockletManager extends BaseBlockletManager {
|
|
|
172
172
|
/**
|
|
173
173
|
* @param {*} dataDirs generate by ../../util:getDataDirs
|
|
174
174
|
*/
|
|
175
|
-
constructor({ dataDirs, registry, startQueue, installQueue, daemon = false }) {
|
|
175
|
+
constructor({ dataDirs, registry, startQueue, installQueue, daemon = false, teamManager }) {
|
|
176
176
|
super();
|
|
177
177
|
|
|
178
178
|
this.dataDirs = dataDirs;
|
|
179
179
|
this.installDir = dataDirs.blocklets;
|
|
180
180
|
this.startQueue = startQueue;
|
|
181
181
|
this.installQueue = installQueue;
|
|
182
|
+
this.teamManager = teamManager;
|
|
183
|
+
|
|
182
184
|
/**
|
|
183
185
|
* { did: Map({ <childDid>: <downloadFile.cancelCtrl> }) }
|
|
184
186
|
*/
|
|
@@ -209,9 +211,17 @@ class BlockletManager extends BaseBlockletManager {
|
|
|
209
211
|
// ============================================================================================
|
|
210
212
|
|
|
211
213
|
/**
|
|
212
|
-
*
|
|
213
|
-
*
|
|
214
|
-
* @param {
|
|
214
|
+
*
|
|
215
|
+
*
|
|
216
|
+
* @param {{
|
|
217
|
+
* url: string;
|
|
218
|
+
* sync: boolean = false;
|
|
219
|
+
* }} params
|
|
220
|
+
* @param {{
|
|
221
|
+
* [key: string]: any
|
|
222
|
+
* }} context
|
|
223
|
+
* @return {*}
|
|
224
|
+
* @memberof BlockletManager
|
|
215
225
|
*/
|
|
216
226
|
async install(params, context) {
|
|
217
227
|
logger.debug('install blocklet', { params, context });
|
|
@@ -245,7 +255,6 @@ class BlockletManager extends BaseBlockletManager {
|
|
|
245
255
|
/**
|
|
246
256
|
* @param {String} rootDid
|
|
247
257
|
* @param {String} mountPoint
|
|
248
|
-
* @param {Boolean} context.blockletPurchaseVerified
|
|
249
258
|
*
|
|
250
259
|
* installFromUrl
|
|
251
260
|
* @param {String} url
|
|
@@ -259,8 +268,13 @@ class BlockletManager extends BaseBlockletManager {
|
|
|
259
268
|
* Custom info
|
|
260
269
|
* @param {String} title custom component title
|
|
261
270
|
* @param {String} name custom component name
|
|
271
|
+
*
|
|
272
|
+
* @param {ConfigEntry} configs pre configs
|
|
262
273
|
*/
|
|
263
|
-
async installComponent(
|
|
274
|
+
async installComponent(
|
|
275
|
+
{ rootDid, mountPoint, url, file, did, diffVersion, deleteSet, title, name, configs, downloadToken },
|
|
276
|
+
context = {}
|
|
277
|
+
) {
|
|
264
278
|
logger.debug('start install component', { rootDid, mountPoint, url });
|
|
265
279
|
|
|
266
280
|
if (file) {
|
|
@@ -268,7 +282,17 @@ class BlockletManager extends BaseBlockletManager {
|
|
|
268
282
|
}
|
|
269
283
|
|
|
270
284
|
if (url) {
|
|
271
|
-
return this._installComponentFromUrl({
|
|
285
|
+
return this._installComponentFromUrl({
|
|
286
|
+
rootDid,
|
|
287
|
+
mountPoint,
|
|
288
|
+
url,
|
|
289
|
+
context,
|
|
290
|
+
title,
|
|
291
|
+
did,
|
|
292
|
+
name,
|
|
293
|
+
configs,
|
|
294
|
+
downloadToken,
|
|
295
|
+
});
|
|
272
296
|
}
|
|
273
297
|
|
|
274
298
|
// should not be here
|
|
@@ -317,7 +341,7 @@ class BlockletManager extends BaseBlockletManager {
|
|
|
317
341
|
const did = get(vc, 'credentialSubject.purchased.blocklet.id');
|
|
318
342
|
const registry = urlObject.origin;
|
|
319
343
|
|
|
320
|
-
return this._installFromStore({ did, registry },
|
|
344
|
+
return this._installFromStore({ did, registry }, context);
|
|
321
345
|
}
|
|
322
346
|
|
|
323
347
|
async start({ did, throwOnError, checkHealthImmediately = false, e2eMode = false }, context) {
|
|
@@ -684,7 +708,7 @@ class BlockletManager extends BaseBlockletManager {
|
|
|
684
708
|
|
|
685
709
|
if (!attachRuntimeInfo) {
|
|
686
710
|
try {
|
|
687
|
-
const blocklet = await this.ensureBlocklet(did);
|
|
711
|
+
const blocklet = await this.ensureBlocklet(did, { throwOnNotExist: false });
|
|
688
712
|
return blocklet;
|
|
689
713
|
} catch (e) {
|
|
690
714
|
logger.error('get blocklet detail error', { error: e.message });
|
|
@@ -833,6 +857,10 @@ class BlockletManager extends BaseBlockletManager {
|
|
|
833
857
|
async upgrade({ did, registryUrl, sync }, context) {
|
|
834
858
|
const blocklet = await states.blocklet.getBlocklet(did);
|
|
835
859
|
|
|
860
|
+
if (!registryUrl && blocklet.source === BlockletSource.url) {
|
|
861
|
+
return this._installFromUrl({ url: blocklet.deployedFrom }, context);
|
|
862
|
+
}
|
|
863
|
+
|
|
836
864
|
// TODO: 查看了下目前页面中的升级按钮,都是会传 registryUrl 过来的,这个函数里的逻辑感觉需要在以后做一个简化
|
|
837
865
|
if (!registryUrl && blocklet.source !== BlockletSource.registry) {
|
|
838
866
|
throw new Error('Wrong upgrade source, empty registryUrl or not installed from blocklet registry');
|
|
@@ -1202,14 +1230,17 @@ class BlockletManager extends BaseBlockletManager {
|
|
|
1202
1230
|
return rootBlocklet;
|
|
1203
1231
|
}
|
|
1204
1232
|
|
|
1205
|
-
async ensureBlocklet(did, { e2eMode = false, validateEnv = true } = {}) {
|
|
1233
|
+
async ensureBlocklet(did, { e2eMode = false, validateEnv = true, throwOnNotExist = true } = {}) {
|
|
1206
1234
|
if (!isValidDid(did)) {
|
|
1207
1235
|
throw new Error(`Blocklet did is invalid: ${did}`);
|
|
1208
1236
|
}
|
|
1209
1237
|
|
|
1210
1238
|
const blocklet = await states.blocklet.getBlocklet(did);
|
|
1211
1239
|
if (!blocklet) {
|
|
1212
|
-
|
|
1240
|
+
if (throwOnNotExist) {
|
|
1241
|
+
throw new Error(`Can not find blocklet in database by did ${did}`);
|
|
1242
|
+
}
|
|
1243
|
+
return null;
|
|
1213
1244
|
}
|
|
1214
1245
|
|
|
1215
1246
|
// app settings
|
|
@@ -1311,7 +1342,12 @@ class BlockletManager extends BaseBlockletManager {
|
|
|
1311
1342
|
}
|
|
1312
1343
|
|
|
1313
1344
|
try {
|
|
1314
|
-
let blocklet = await this.ensureBlocklet(did);
|
|
1345
|
+
let blocklet = await this.ensureBlocklet(did, { throwOnNotExist: false });
|
|
1346
|
+
|
|
1347
|
+
if (!blocklet) {
|
|
1348
|
+
return null;
|
|
1349
|
+
}
|
|
1350
|
+
|
|
1315
1351
|
const fromCache = !!cachedBlocklet;
|
|
1316
1352
|
|
|
1317
1353
|
// if from cached data, only use cache data of runtime info (engine, diskInfo, runtimeInfo...)
|
|
@@ -1408,7 +1444,21 @@ class BlockletManager extends BaseBlockletManager {
|
|
|
1408
1444
|
}
|
|
1409
1445
|
}
|
|
1410
1446
|
|
|
1411
|
-
|
|
1447
|
+
/**
|
|
1448
|
+
*
|
|
1449
|
+
*
|
|
1450
|
+
* @param {{
|
|
1451
|
+
* blocklet: {},
|
|
1452
|
+
* context: {},
|
|
1453
|
+
* postAction: 'install' | 'upgrade' | 'downgrade',
|
|
1454
|
+
* oldBlocklet: {},
|
|
1455
|
+
* throwOnError: Error
|
|
1456
|
+
* }} params
|
|
1457
|
+
* @return {*}
|
|
1458
|
+
* @memberof BlockletManager
|
|
1459
|
+
*/
|
|
1460
|
+
async onDownload(params) {
|
|
1461
|
+
const { blocklet, context, postAction, oldBlocklet, throwOnError } = params;
|
|
1412
1462
|
const { meta } = blocklet;
|
|
1413
1463
|
const { name, did, version } = meta;
|
|
1414
1464
|
|
|
@@ -1433,7 +1483,7 @@ class BlockletManager extends BaseBlockletManager {
|
|
|
1433
1483
|
|
|
1434
1484
|
preDownloadLock.release();
|
|
1435
1485
|
|
|
1436
|
-
const { isCancelled } = await this._downloadBlocklet(blocklet, oldBlocklet);
|
|
1486
|
+
const { isCancelled } = await this._downloadBlocklet(blocklet, oldBlocklet, context);
|
|
1437
1487
|
|
|
1438
1488
|
if (isCancelled) {
|
|
1439
1489
|
logger.info('Download was canceled manually', { name, did, version });
|
|
@@ -1624,7 +1674,21 @@ class BlockletManager extends BaseBlockletManager {
|
|
|
1624
1674
|
}
|
|
1625
1675
|
}
|
|
1626
1676
|
|
|
1627
|
-
|
|
1677
|
+
/**
|
|
1678
|
+
***
|
|
1679
|
+
*
|
|
1680
|
+
* @param {{
|
|
1681
|
+
* did: string;
|
|
1682
|
+
* registry: string;
|
|
1683
|
+
* sync: boolean;
|
|
1684
|
+
* }} params
|
|
1685
|
+
* @param {*} context
|
|
1686
|
+
* @return {*}
|
|
1687
|
+
* @memberof BlockletManager
|
|
1688
|
+
*/
|
|
1689
|
+
async _installFromStore(params, context) {
|
|
1690
|
+
const { did, registry, sync } = params;
|
|
1691
|
+
|
|
1628
1692
|
logger.debug('start install blocklet', { did });
|
|
1629
1693
|
if (!isValidDid(did)) {
|
|
1630
1694
|
throw new Error('Blocklet did is invalid');
|
|
@@ -1642,8 +1706,6 @@ class BlockletManager extends BaseBlockletManager {
|
|
|
1642
1706
|
throw new Error('Can not install an already installed blocklet');
|
|
1643
1707
|
}
|
|
1644
1708
|
|
|
1645
|
-
verifyPurchase(meta, context);
|
|
1646
|
-
|
|
1647
1709
|
// install
|
|
1648
1710
|
return this._install({
|
|
1649
1711
|
meta,
|
|
@@ -1654,7 +1716,20 @@ class BlockletManager extends BaseBlockletManager {
|
|
|
1654
1716
|
});
|
|
1655
1717
|
}
|
|
1656
1718
|
|
|
1657
|
-
|
|
1719
|
+
/**
|
|
1720
|
+
*
|
|
1721
|
+
*
|
|
1722
|
+
* @param {{
|
|
1723
|
+
* url: string;
|
|
1724
|
+
* sync: boolean;
|
|
1725
|
+
* }} params
|
|
1726
|
+
* @param {{}} context
|
|
1727
|
+
* @return {*}
|
|
1728
|
+
* @memberof BlockletManager
|
|
1729
|
+
*/
|
|
1730
|
+
async _installFromUrl(params, context) {
|
|
1731
|
+
const { url, sync } = params;
|
|
1732
|
+
|
|
1658
1733
|
logger.debug('start install blocklet', { url });
|
|
1659
1734
|
|
|
1660
1735
|
const { inStore, registryUrl, blockletDid } = await parseSourceUrl(url);
|
|
@@ -1695,7 +1770,17 @@ class BlockletManager extends BaseBlockletManager {
|
|
|
1695
1770
|
});
|
|
1696
1771
|
}
|
|
1697
1772
|
|
|
1698
|
-
async _installComponentFromUrl({
|
|
1773
|
+
async _installComponentFromUrl({
|
|
1774
|
+
rootDid,
|
|
1775
|
+
mountPoint,
|
|
1776
|
+
url,
|
|
1777
|
+
context,
|
|
1778
|
+
title,
|
|
1779
|
+
name: inputName,
|
|
1780
|
+
did: inputDid,
|
|
1781
|
+
configs,
|
|
1782
|
+
downloadToken,
|
|
1783
|
+
}) {
|
|
1699
1784
|
const blocklet = await this._getBlockletForInstallation(rootDid);
|
|
1700
1785
|
if (!blocklet) {
|
|
1701
1786
|
throw new Error('Root blocklet does not exist');
|
|
@@ -1703,12 +1788,28 @@ class BlockletManager extends BaseBlockletManager {
|
|
|
1703
1788
|
|
|
1704
1789
|
const meta = await getBlockletMetaFromUrl(url);
|
|
1705
1790
|
|
|
1791
|
+
// 如果是一个付费的blocklet,需要携带token才能下载成功
|
|
1792
|
+
if (!isFreeBlocklet(meta)) {
|
|
1793
|
+
const info = await states.node.read();
|
|
1794
|
+
|
|
1795
|
+
// eslint-disable-next-line no-param-reassign
|
|
1796
|
+
context = {
|
|
1797
|
+
...context,
|
|
1798
|
+
headers: {
|
|
1799
|
+
'x-server-did': info.did,
|
|
1800
|
+
'x-download-token': downloadToken,
|
|
1801
|
+
'x-server-publick-key': info.pk,
|
|
1802
|
+
'x-server-signature': sign(info.did, info.sk, {
|
|
1803
|
+
exp: (Date.now() + 5 * 60 * 1000) / 1000,
|
|
1804
|
+
}),
|
|
1805
|
+
},
|
|
1806
|
+
};
|
|
1807
|
+
}
|
|
1808
|
+
|
|
1706
1809
|
if (!isComponentBlocklet(meta)) {
|
|
1707
1810
|
throw new Error('The blocklet cannot be a component');
|
|
1708
1811
|
}
|
|
1709
1812
|
|
|
1710
|
-
verifyPurchase(meta, context);
|
|
1711
|
-
|
|
1712
1813
|
if (title) {
|
|
1713
1814
|
meta.title = await titleSchema.validateAsync(title);
|
|
1714
1815
|
}
|
|
@@ -1724,26 +1825,41 @@ class BlockletManager extends BaseBlockletManager {
|
|
|
1724
1825
|
did = found.did;
|
|
1725
1826
|
}
|
|
1726
1827
|
|
|
1727
|
-
const
|
|
1728
|
-
{
|
|
1729
|
-
|
|
1730
|
-
|
|
1731
|
-
|
|
1732
|
-
|
|
1733
|
-
|
|
1734
|
-
},
|
|
1735
|
-
];
|
|
1828
|
+
const newChild = {
|
|
1829
|
+
meta: ensureMeta(meta, { did, name }),
|
|
1830
|
+
mountPoint,
|
|
1831
|
+
bundleSource: { url },
|
|
1832
|
+
dynamic: true,
|
|
1833
|
+
children: await parseChildrenFromMeta(meta, { ...context, ancestors: [{ mountPoint }] }),
|
|
1834
|
+
};
|
|
1736
1835
|
|
|
1737
|
-
checkDuplicateComponents([...blocklet.children,
|
|
1836
|
+
checkDuplicateComponents([...blocklet.children, newChild]);
|
|
1738
1837
|
|
|
1739
|
-
|
|
1740
|
-
|
|
1741
|
-
|
|
1838
|
+
try {
|
|
1839
|
+
// add component to db
|
|
1840
|
+
await states.blocklet.addChildren(rootDid, [newChild]);
|
|
1841
|
+
|
|
1842
|
+
// update navigation
|
|
1843
|
+
await this._upsertDynamicNavigation(blocklet.meta.did, newChild);
|
|
1844
|
+
|
|
1845
|
+
// update configs
|
|
1846
|
+
if (Array.isArray(configs)) {
|
|
1847
|
+
if (hasReservedKey(configs)) {
|
|
1848
|
+
throw new Error('Component key of environments can not start with `ABT_NODE_` or `BLOCKLET_`');
|
|
1849
|
+
}
|
|
1850
|
+
|
|
1851
|
+
await states.blockletExtras.setConfigs([blocklet.meta.did, newChild.meta.did], configs);
|
|
1852
|
+
}
|
|
1853
|
+
} catch (err) {
|
|
1854
|
+
logger.error('Add component failed', err);
|
|
1855
|
+
await this._rollback('upgrade', rootDid, blocklet);
|
|
1856
|
+
throw err;
|
|
1857
|
+
}
|
|
1742
1858
|
|
|
1743
1859
|
return this.updateChildren(
|
|
1744
1860
|
{
|
|
1745
1861
|
did: rootDid,
|
|
1746
|
-
children: [...blocklet.children,
|
|
1862
|
+
children: [...blocklet.children, newChild],
|
|
1747
1863
|
oldBlocklet: blocklet,
|
|
1748
1864
|
},
|
|
1749
1865
|
context
|
|
@@ -2033,50 +2149,15 @@ class BlockletManager extends BaseBlockletManager {
|
|
|
2033
2149
|
throw new Error('the blocklet is not installed');
|
|
2034
2150
|
}
|
|
2035
2151
|
|
|
2036
|
-
const { bundleDid } = blocklet.meta;
|
|
2037
|
-
|
|
2038
|
-
let versions = this.cachedBlockletVersions.get(did);
|
|
2039
|
-
|
|
2040
|
-
if (!versions) {
|
|
2041
|
-
const { blockletRegistryList } = await states.node.read();
|
|
2042
|
-
const tasks = blockletRegistryList.map((registry) =>
|
|
2043
|
-
this.registry
|
|
2044
|
-
.getBlockletMeta({ did: bundleDid, registryUrl: registry.url })
|
|
2045
|
-
.then((item) => ({ did, version: item.version, registryUrl: registry.url }))
|
|
2046
|
-
.catch((error) => {
|
|
2047
|
-
if (error.response && error.response.status === 404) {
|
|
2048
|
-
return;
|
|
2049
|
-
}
|
|
2050
|
-
logger.error('get blocklet meta from registry failed', { did, error });
|
|
2051
|
-
})); // prettier-ignore
|
|
2052
|
-
|
|
2053
|
-
versions = await Promise.all(tasks);
|
|
2054
|
-
this.cachedBlockletVersions.set(did, versions);
|
|
2055
|
-
}
|
|
2056
|
-
|
|
2057
|
-
versions = versions.filter((item) => item && semver.gt(item.version, version));
|
|
2058
|
-
|
|
2059
|
-
if (versions.length === 0) {
|
|
2060
|
-
return null;
|
|
2061
|
-
}
|
|
2062
|
-
|
|
2063
|
-
// When new version found from the store where the blocklet was installed from, we should use that store first
|
|
2064
2152
|
if (blocklet.source === BlockletSource.registry && blocklet.deployedFrom) {
|
|
2065
|
-
|
|
2066
|
-
if (latestFromSameRegistry) {
|
|
2067
|
-
return latestFromSameRegistry;
|
|
2068
|
-
}
|
|
2153
|
+
return this._getLatestBlockletVersionFromStore({ blocklet, version });
|
|
2069
2154
|
}
|
|
2070
2155
|
|
|
2071
|
-
|
|
2072
|
-
|
|
2073
|
-
|
|
2074
|
-
if (semver.lt(latestBlockletVersion.version, item.version)) {
|
|
2075
|
-
latestBlockletVersion = item;
|
|
2076
|
-
}
|
|
2077
|
-
});
|
|
2156
|
+
if (blocklet.source === BlockletSource.url && blocklet.deployedFrom) {
|
|
2157
|
+
return this._getLatestBlockletVersionFromUrl({ blocklet, version });
|
|
2158
|
+
}
|
|
2078
2159
|
|
|
2079
|
-
return
|
|
2160
|
+
return null;
|
|
2080
2161
|
}
|
|
2081
2162
|
|
|
2082
2163
|
getCrons() {
|
|
@@ -2132,7 +2213,22 @@ class BlockletManager extends BaseBlockletManager {
|
|
|
2132
2213
|
.filter((x) => (skipDeleted ? x.status !== BlockletStatus.deleted : true));
|
|
2133
2214
|
}
|
|
2134
2215
|
|
|
2135
|
-
|
|
2216
|
+
/**
|
|
2217
|
+
*
|
|
2218
|
+
*
|
|
2219
|
+
* @param {{
|
|
2220
|
+
* meta: {}; // blocklet meta
|
|
2221
|
+
* source: number; // example: BlockletSource.registry,
|
|
2222
|
+
* deployedFrom: string;
|
|
2223
|
+
* context: {}
|
|
2224
|
+
* sync: boolean = false;
|
|
2225
|
+
* }} params
|
|
2226
|
+
* @return {*}
|
|
2227
|
+
* @memberof BlockletManager
|
|
2228
|
+
*/
|
|
2229
|
+
async _install(params) {
|
|
2230
|
+
const { meta, source, deployedFrom, context, sync } = params;
|
|
2231
|
+
|
|
2136
2232
|
validateBlockletMeta(meta, { ensureDist: true });
|
|
2137
2233
|
|
|
2138
2234
|
const { name, did, version } = meta;
|
|
@@ -2141,6 +2237,7 @@ class BlockletManager extends BaseBlockletManager {
|
|
|
2141
2237
|
|
|
2142
2238
|
const children = await this._getChildrenForInstallation(meta);
|
|
2143
2239
|
try {
|
|
2240
|
+
// 创建一个blocklet到database
|
|
2144
2241
|
const blocklet = await states.blocklet.addBlocklet({
|
|
2145
2242
|
meta,
|
|
2146
2243
|
source,
|
|
@@ -2157,7 +2254,15 @@ class BlockletManager extends BaseBlockletManager {
|
|
|
2157
2254
|
const blocklet1 = await states.blocklet.setBlockletStatus(did, BlockletStatus.waiting);
|
|
2158
2255
|
this.emit(BlockletEvents.added, blocklet1);
|
|
2159
2256
|
|
|
2160
|
-
|
|
2257
|
+
/** @type {{
|
|
2258
|
+
* blocklet: any;
|
|
2259
|
+
* oldBlocklet: {
|
|
2260
|
+
* children: any[];
|
|
2261
|
+
* extraState: any;
|
|
2262
|
+
* };
|
|
2263
|
+
* context: {};
|
|
2264
|
+
* postAction: string
|
|
2265
|
+
* }} */
|
|
2161
2266
|
const downloadParams = {
|
|
2162
2267
|
blocklet: { ...blocklet1 },
|
|
2163
2268
|
oldBlocklet: {
|
|
@@ -2220,6 +2325,13 @@ class BlockletManager extends BaseBlockletManager {
|
|
|
2220
2325
|
}
|
|
2221
2326
|
}
|
|
2222
2327
|
|
|
2328
|
+
/**
|
|
2329
|
+
*
|
|
2330
|
+
*
|
|
2331
|
+
* @param {{}} { meta, source, deployedFrom, context, sync }
|
|
2332
|
+
* @return {*}
|
|
2333
|
+
* @memberof BlockletManager
|
|
2334
|
+
*/
|
|
2223
2335
|
async _upgrade({ meta, source, deployedFrom, context, sync }) {
|
|
2224
2336
|
validateBlockletMeta(meta, { ensureDist: meta.group !== BlockletGroup.gateway });
|
|
2225
2337
|
|
|
@@ -2242,6 +2354,26 @@ class BlockletManager extends BaseBlockletManager {
|
|
|
2242
2354
|
|
|
2243
2355
|
this.emit(BlockletEvents.statusChange, newBlocklet);
|
|
2244
2356
|
|
|
2357
|
+
// 如果是一个付费的blocklet,需要携带token才能下载成功
|
|
2358
|
+
if (!isFreeBlocklet(meta)) {
|
|
2359
|
+
const blocklet = await states.blocklet.getBlocklet(did);
|
|
2360
|
+
|
|
2361
|
+
const info = await states.node.read();
|
|
2362
|
+
|
|
2363
|
+
// eslint-disable-next-line no-param-reassign
|
|
2364
|
+
context = {
|
|
2365
|
+
...context,
|
|
2366
|
+
headers: {
|
|
2367
|
+
'x-server-did': info.did,
|
|
2368
|
+
'x-download-token': blocklet?.tokens?.paidBlockletDownloadToken,
|
|
2369
|
+
'x-server-publick-key': info.pk,
|
|
2370
|
+
'x-server-signature': sign(info.did, info.sk, {
|
|
2371
|
+
exp: (Date.now() + 5 * 60 * 1000) / 1000,
|
|
2372
|
+
}),
|
|
2373
|
+
},
|
|
2374
|
+
};
|
|
2375
|
+
}
|
|
2376
|
+
|
|
2245
2377
|
// download
|
|
2246
2378
|
const downloadParams = {
|
|
2247
2379
|
oldBlocklet: { ...oldBlocklet },
|
|
@@ -2255,7 +2387,6 @@ class BlockletManager extends BaseBlockletManager {
|
|
|
2255
2387
|
await this.onDownload({ ...downloadParams, throwOnError: true });
|
|
2256
2388
|
return states.blocklet.getBlocklet(did);
|
|
2257
2389
|
}
|
|
2258
|
-
|
|
2259
2390
|
const ticket = this.installQueue.push(
|
|
2260
2391
|
{
|
|
2261
2392
|
entity: 'blocklet',
|
|
@@ -2469,6 +2600,14 @@ class BlockletManager extends BaseBlockletManager {
|
|
|
2469
2600
|
// Update dynamic component meta in blocklet settings
|
|
2470
2601
|
await this._ensureDynamicChildrenInSettings(blocklet);
|
|
2471
2602
|
|
|
2603
|
+
if (context?.headers?.['x-download-token']) {
|
|
2604
|
+
await states.blocklet.updateBlocklet(did, {
|
|
2605
|
+
tokens: {
|
|
2606
|
+
paidBlockletDownloadToken: context.headers['x-download-token'],
|
|
2607
|
+
},
|
|
2608
|
+
});
|
|
2609
|
+
}
|
|
2610
|
+
|
|
2472
2611
|
states.notification.create({
|
|
2473
2612
|
title: 'Blocklet Installed',
|
|
2474
2613
|
description: `Blocklet ${meta.name}@${meta.version} is installed successfully. (Source: ${
|
|
@@ -2657,11 +2796,23 @@ class BlockletManager extends BaseBlockletManager {
|
|
|
2657
2796
|
}
|
|
2658
2797
|
|
|
2659
2798
|
/**
|
|
2660
|
-
*
|
|
2661
|
-
*
|
|
2662
|
-
*
|
|
2799
|
+
*
|
|
2800
|
+
*
|
|
2801
|
+
* @param {{
|
|
2802
|
+
* url: string,
|
|
2803
|
+
* cwd: string,
|
|
2804
|
+
* tarball: string,
|
|
2805
|
+
* did: string,
|
|
2806
|
+
* integrity: string,
|
|
2807
|
+
* verify: boolean = true,
|
|
2808
|
+
* ctrlStore: {},
|
|
2809
|
+
* rootDid: string,
|
|
2810
|
+
* context: {} = {},
|
|
2811
|
+
* }} { url, cwd, tarball, did, integrity, verify = true, ctrlStore = {}, rootDid, context = {} }
|
|
2812
|
+
* @return {*}
|
|
2813
|
+
* @memberof BlockletManager
|
|
2663
2814
|
*/
|
|
2664
|
-
async _downloadTarball({ url, cwd, tarball, did, integrity, verify = true, ctrlStore = {}, rootDid }) {
|
|
2815
|
+
async _downloadTarball({ url, cwd, tarball, did, integrity, verify = true, ctrlStore = {}, rootDid, context = {} }) {
|
|
2665
2816
|
fs.mkdirSync(cwd, { recursive: true });
|
|
2666
2817
|
|
|
2667
2818
|
const tarballName = url.split('/').slice(-1)[0];
|
|
@@ -2673,7 +2824,7 @@ class BlockletManager extends BaseBlockletManager {
|
|
|
2673
2824
|
const cachedTarFile = await this._getCachedTarFile(integrity);
|
|
2674
2825
|
if (cachedTarFile) {
|
|
2675
2826
|
logger.info('found cache tarFile', { did, tarballName, integrity });
|
|
2676
|
-
await fs.move(cachedTarFile, tarballPath);
|
|
2827
|
+
await fs.move(cachedTarFile, tarballPath, { overwrite: true });
|
|
2677
2828
|
} else if (protocol.startsWith('file')) {
|
|
2678
2829
|
await fs.copy(decodeURIComponent(pathname), tarballPath);
|
|
2679
2830
|
} else {
|
|
@@ -2684,7 +2835,7 @@ class BlockletManager extends BaseBlockletManager {
|
|
|
2684
2835
|
}
|
|
2685
2836
|
ctrlStore[rootDid].set(did, cancelCtrl);
|
|
2686
2837
|
|
|
2687
|
-
await downloadFile(url, path.join(cwd, tarballName), { cancelCtrl });
|
|
2838
|
+
await downloadFile(url, path.join(cwd, tarballName), { cancelCtrl }, context);
|
|
2688
2839
|
|
|
2689
2840
|
if (ctrlStore[rootDid]) {
|
|
2690
2841
|
ctrlStore[rootDid].delete(did);
|
|
@@ -2773,12 +2924,16 @@ class BlockletManager extends BaseBlockletManager {
|
|
|
2773
2924
|
}
|
|
2774
2925
|
|
|
2775
2926
|
/**
|
|
2776
|
-
*
|
|
2777
|
-
*
|
|
2778
|
-
* @param {
|
|
2779
|
-
* @
|
|
2927
|
+
*
|
|
2928
|
+
*
|
|
2929
|
+
* @param {*} meta
|
|
2930
|
+
* @param {*} rootDid
|
|
2931
|
+
* @param {*} url
|
|
2932
|
+
* @param {{}} [context={}]
|
|
2933
|
+
* @return {*}
|
|
2934
|
+
* @memberof BlockletManager
|
|
2780
2935
|
*/
|
|
2781
|
-
async _downloadBundle(meta, rootDid, url) {
|
|
2936
|
+
async _downloadBundle(meta, rootDid, url, context = {}) {
|
|
2782
2937
|
const { bundleName: name, bundleDid: did, version, dist = {} } = meta;
|
|
2783
2938
|
const { tarball, integrity } = dist;
|
|
2784
2939
|
|
|
@@ -2806,6 +2961,7 @@ class BlockletManager extends BaseBlockletManager {
|
|
|
2806
2961
|
ctrlStore: this.downloadCtrls,
|
|
2807
2962
|
rootDid,
|
|
2808
2963
|
url,
|
|
2964
|
+
context,
|
|
2809
2965
|
});
|
|
2810
2966
|
logger.info('downloaded blocklet tar file', { name, version, tarballPath });
|
|
2811
2967
|
if (tarballPath === downloadFile.CANCEL) {
|
|
@@ -2826,7 +2982,16 @@ class BlockletManager extends BaseBlockletManager {
|
|
|
2826
2982
|
}
|
|
2827
2983
|
}
|
|
2828
2984
|
|
|
2829
|
-
|
|
2985
|
+
/**
|
|
2986
|
+
*
|
|
2987
|
+
*
|
|
2988
|
+
* @param {{}} blocklet
|
|
2989
|
+
* @param {{}} [oldBlocklet={}]
|
|
2990
|
+
* @param {{}} [context={}]
|
|
2991
|
+
* @return {*}
|
|
2992
|
+
* @memberof BlockletManager
|
|
2993
|
+
*/
|
|
2994
|
+
async _downloadBlocklet(blocklet, oldBlocklet = {}, context = {}) {
|
|
2830
2995
|
const {
|
|
2831
2996
|
meta: { name, did },
|
|
2832
2997
|
} = blocklet;
|
|
@@ -2880,7 +3045,7 @@ class BlockletManager extends BaseBlockletManager {
|
|
|
2880
3045
|
tarball: get(meta, 'dist.tarball'),
|
|
2881
3046
|
registryUrl: blocklet.source === BlockletSource.registry ? blocklet.deployedFrom : undefined,
|
|
2882
3047
|
});
|
|
2883
|
-
tasks.push(this._downloadBundle(meta, did, url));
|
|
3048
|
+
tasks.push(this._downloadBundle(meta, did, url, context));
|
|
2884
3049
|
}
|
|
2885
3050
|
const results = await Promise.all(tasks);
|
|
2886
3051
|
if (results.find((x) => x.isCancelled)) {
|
|
@@ -2976,6 +3141,9 @@ class BlockletManager extends BaseBlockletManager {
|
|
|
2976
3141
|
const logsDir = path.join(this.dataDirs.logs, name);
|
|
2977
3142
|
const cacheDir = path.join(this.dataDirs.cache, name);
|
|
2978
3143
|
|
|
3144
|
+
// Cleanup db
|
|
3145
|
+
await this.teamManager.deleteTeam(blocklet.meta.did);
|
|
3146
|
+
|
|
2979
3147
|
// Cleanup disk storage
|
|
2980
3148
|
fs.removeSync(cacheDir);
|
|
2981
3149
|
if (keepData === false) {
|
|
@@ -3068,6 +3236,78 @@ class BlockletManager extends BaseBlockletManager {
|
|
|
3068
3236
|
|
|
3069
3237
|
return blocklet;
|
|
3070
3238
|
}
|
|
3239
|
+
|
|
3240
|
+
async _getLatestBlockletVersionFromStore({ blocklet, version }) {
|
|
3241
|
+
const { did, bundleDid } = blocklet.meta;
|
|
3242
|
+
|
|
3243
|
+
let versions = this.cachedBlockletVersions.get(did);
|
|
3244
|
+
|
|
3245
|
+
if (!versions) {
|
|
3246
|
+
const { blockletRegistryList } = await states.node.read();
|
|
3247
|
+
const tasks = blockletRegistryList.map((registry) =>
|
|
3248
|
+
this.registry
|
|
3249
|
+
.getBlockletMeta({ did: bundleDid, registryUrl: registry.url })
|
|
3250
|
+
.then((item) => ({ did, version: item.version, registryUrl: registry.url }))
|
|
3251
|
+
.catch((error) => {
|
|
3252
|
+
if (error.response && error.response.status === 404) {
|
|
3253
|
+
return;
|
|
3254
|
+
}
|
|
3255
|
+
logger.error('get blocklet meta from registry failed', { did, error });
|
|
3256
|
+
})); // prettier-ignore
|
|
3257
|
+
|
|
3258
|
+
versions = await Promise.all(tasks);
|
|
3259
|
+
this.cachedBlockletVersions.set(did, versions);
|
|
3260
|
+
}
|
|
3261
|
+
|
|
3262
|
+
versions = versions.filter((item) => item && semver.gt(item.version, version));
|
|
3263
|
+
|
|
3264
|
+
if (versions.length === 0) {
|
|
3265
|
+
return null;
|
|
3266
|
+
}
|
|
3267
|
+
|
|
3268
|
+
// When new version found from the store where the blocklet was installed from, we should use that store first
|
|
3269
|
+
if (blocklet.source === BlockletSource.registry && blocklet.deployedFrom) {
|
|
3270
|
+
const latestFromSameRegistry = versions.find((x) => x.registryUrl === blocklet.deployedFrom);
|
|
3271
|
+
if (latestFromSameRegistry) {
|
|
3272
|
+
return latestFromSameRegistry;
|
|
3273
|
+
}
|
|
3274
|
+
}
|
|
3275
|
+
|
|
3276
|
+
// Otherwise try upgrading from other store
|
|
3277
|
+
let latestBlockletVersion = versions[0];
|
|
3278
|
+
versions.forEach((item) => {
|
|
3279
|
+
if (semver.lt(latestBlockletVersion.version, item.version)) {
|
|
3280
|
+
latestBlockletVersion = item;
|
|
3281
|
+
}
|
|
3282
|
+
});
|
|
3283
|
+
|
|
3284
|
+
return latestBlockletVersion;
|
|
3285
|
+
}
|
|
3286
|
+
|
|
3287
|
+
async _getLatestBlockletVersionFromUrl({ blocklet, version }) {
|
|
3288
|
+
const { did } = blocklet.meta;
|
|
3289
|
+
|
|
3290
|
+
let versions = this.cachedBlockletVersions.get(did);
|
|
3291
|
+
|
|
3292
|
+
if (!versions) {
|
|
3293
|
+
try {
|
|
3294
|
+
const item = await getBlockletMetaFromUrl(blocklet.deployedFrom);
|
|
3295
|
+
versions = [{ did, version: item.version }];
|
|
3296
|
+
} catch (error) {
|
|
3297
|
+
logger.error('get blocklet meta from url failed when checking latest version', { did, error });
|
|
3298
|
+
versions = [];
|
|
3299
|
+
}
|
|
3300
|
+
}
|
|
3301
|
+
|
|
3302
|
+
this.cachedBlockletVersions.set(did, versions);
|
|
3303
|
+
versions = versions.filter((item) => item && semver.gt(item.version, version));
|
|
3304
|
+
|
|
3305
|
+
if (versions.length === 0) {
|
|
3306
|
+
return null;
|
|
3307
|
+
}
|
|
3308
|
+
|
|
3309
|
+
return versions[0];
|
|
3310
|
+
}
|
|
3071
3311
|
}
|
|
3072
3312
|
|
|
3073
3313
|
module.exports = BlockletManager;
|
package/lib/index.js
CHANGED
|
@@ -117,6 +117,7 @@ function ABTNode(options) {
|
|
|
117
117
|
maintainerEmail: DEFAULT_CERTIFICATE_EMAIL,
|
|
118
118
|
dataDir: dataDirs.certManagerModule,
|
|
119
119
|
});
|
|
120
|
+
|
|
120
121
|
const routerManager = new RouterManager({ certManager });
|
|
121
122
|
const routingSnapshot = new RoutingSnapshot({
|
|
122
123
|
baseDir: dataDirs.core,
|
|
@@ -126,13 +127,18 @@ function ABTNode(options) {
|
|
|
126
127
|
return { sites };
|
|
127
128
|
},
|
|
128
129
|
});
|
|
130
|
+
|
|
129
131
|
const blockletRegistry = new BlockletRegistry();
|
|
132
|
+
|
|
133
|
+
const teamManager = new TeamManager({ nodeDid: options.nodeDid, dataDirs, states });
|
|
134
|
+
|
|
130
135
|
const blockletManager = new BlockletManager({
|
|
131
136
|
dataDirs,
|
|
132
137
|
startQueue,
|
|
133
138
|
installQueue,
|
|
134
139
|
registry: blockletRegistry,
|
|
135
140
|
daemon: options.daemon,
|
|
141
|
+
teamManager,
|
|
136
142
|
});
|
|
137
143
|
blockletManager.setMaxListeners(0);
|
|
138
144
|
|
|
@@ -156,7 +162,6 @@ function ABTNode(options) {
|
|
|
156
162
|
getRouterProvider,
|
|
157
163
|
} = getRouterHelpers({ dataDirs, routingSnapshot, routerManager, blockletManager, certManager });
|
|
158
164
|
|
|
159
|
-
const teamManager = new TeamManager({ nodeDid: options.nodeDid, dataDirs, states });
|
|
160
165
|
const nodeAPI = new NodeAPI(states.node, blockletRegistry);
|
|
161
166
|
const teamAPI = new TeamAPI({ states, teamManager });
|
|
162
167
|
|
|
@@ -272,6 +277,7 @@ function ABTNode(options) {
|
|
|
272
277
|
// Account
|
|
273
278
|
getUsers: teamAPI.getUsers.bind(teamAPI),
|
|
274
279
|
getUsersCount: teamAPI.getUsersCount.bind(teamAPI),
|
|
280
|
+
getUsersCountPerRole: teamAPI.getUsersCountPerRole.bind(teamAPI),
|
|
275
281
|
getUser: teamAPI.getUser.bind(teamAPI),
|
|
276
282
|
getOwner: teamAPI.getOwner.bind(teamAPI),
|
|
277
283
|
getNodeUsers: () => teamAPI.getUsers({ teamDid: options.nodeDid }),
|
package/lib/router/index.js
CHANGED
|
@@ -95,19 +95,16 @@ class Router {
|
|
|
95
95
|
}
|
|
96
96
|
|
|
97
97
|
async updateRoutingTable() {
|
|
98
|
+
logger.info('update routing table');
|
|
99
|
+
|
|
98
100
|
const { sites, certificates, headers = {}, services = [], nodeInfo = {} } = (await this.getRoutingParams()) || {};
|
|
99
101
|
if (!Array.isArray(sites)) {
|
|
100
102
|
logger.error('sites is not an array', { sites });
|
|
101
103
|
return;
|
|
102
104
|
}
|
|
103
105
|
|
|
104
|
-
logger.info('updateRoutingTable sites:', { sites });
|
|
105
|
-
|
|
106
106
|
this.routingTable = getRoutingTable({ sites, nodeInfo });
|
|
107
107
|
|
|
108
|
-
logger.info('updateRoutingTable routingTable:', { routingTable: this.routingTable });
|
|
109
|
-
logger.info('updateRoutingTable certificates:', { certificates: certificates.map((item) => item.domain) });
|
|
110
|
-
|
|
111
108
|
const requestLimit = nodeInfo.routing.requestLimit || { enable: false, rate: GATEWAY_REQ_LIMIT.min };
|
|
112
109
|
if (requestLimit.enabled) {
|
|
113
110
|
requestLimit.maxInstantRate = requestLimit.rate >= 20 ? 20 : requestLimit.rate + 20;
|
package/lib/states/user.js
CHANGED
|
@@ -1,3 +1,5 @@
|
|
|
1
|
+
const pickBy = require('lodash/pickBy');
|
|
2
|
+
|
|
1
3
|
const logger = require('@abtnode/logger')('@abtnode/core:states:user');
|
|
2
4
|
const { PASSPORT_STATUS } = require('@abtnode/constant');
|
|
3
5
|
const BaseState = require('./base');
|
|
@@ -7,6 +9,8 @@ const fixPassports = (doc) => {
|
|
|
7
9
|
doc.passports = (doc.passports || []).filter((x) => x.id);
|
|
8
10
|
};
|
|
9
11
|
|
|
12
|
+
const isNullOrUndefined = (x) => x === undefined || x === null;
|
|
13
|
+
|
|
10
14
|
class User extends BaseState {
|
|
11
15
|
constructor(baseDir, options = {}) {
|
|
12
16
|
super(baseDir, { filename: 'user.db', ...options });
|
|
@@ -85,13 +89,45 @@ class User extends BaseState {
|
|
|
85
89
|
return doc;
|
|
86
90
|
}
|
|
87
91
|
|
|
88
|
-
async getUsers() {
|
|
89
|
-
const
|
|
90
|
-
|
|
91
|
-
|
|
92
|
+
async getUsers({ query, sort, paging: inputPaging } = {}) {
|
|
93
|
+
const { approved, role, search } = query || {};
|
|
94
|
+
|
|
95
|
+
// make query param
|
|
96
|
+
const queryParam = {};
|
|
97
|
+
|
|
98
|
+
if (!isNullOrUndefined(approved)) {
|
|
99
|
+
queryParam.approved = !!approved;
|
|
100
|
+
}
|
|
101
|
+
|
|
102
|
+
if (search) {
|
|
103
|
+
queryParam.$or = [{ fullName: search }, { did: search }];
|
|
104
|
+
}
|
|
105
|
+
|
|
106
|
+
if (role && role !== '$all') {
|
|
107
|
+
if (role === '$none') {
|
|
108
|
+
queryParam.passports = { $size: 0 };
|
|
109
|
+
} else {
|
|
110
|
+
queryParam.passports = { $elemMatch: { name: role, status: PASSPORT_STATUS.VALID } };
|
|
111
|
+
}
|
|
112
|
+
}
|
|
113
|
+
|
|
114
|
+
const sortParam = pickBy(sort, (x) => !isNullOrUndefined(x));
|
|
115
|
+
|
|
116
|
+
if (!Object.keys(sortParam).length) {
|
|
117
|
+
sortParam.createdAt = -1;
|
|
118
|
+
}
|
|
119
|
+
|
|
120
|
+
// get data
|
|
121
|
+
const { list, paging } = await this.paginate(queryParam, sortParam, inputPaging);
|
|
122
|
+
|
|
123
|
+
if (list) {
|
|
124
|
+
list.forEach(fixPassports); // backward compatible
|
|
92
125
|
}
|
|
93
126
|
|
|
94
|
-
return
|
|
127
|
+
return {
|
|
128
|
+
list,
|
|
129
|
+
paging,
|
|
130
|
+
};
|
|
95
131
|
}
|
|
96
132
|
|
|
97
133
|
async getUser(did) {
|
package/lib/team/manager.js
CHANGED
|
@@ -17,6 +17,18 @@ const { isCLI } = require('../util');
|
|
|
17
17
|
|
|
18
18
|
const rbacCreationLock = new Lock('rbac-creation-lock');
|
|
19
19
|
|
|
20
|
+
const closeDatabase = async (db) =>
|
|
21
|
+
new Promise((resolve, reject) => {
|
|
22
|
+
db.closeDatabase((err) => {
|
|
23
|
+
if (err) {
|
|
24
|
+
reject(err);
|
|
25
|
+
return;
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
resolve();
|
|
29
|
+
});
|
|
30
|
+
});
|
|
31
|
+
|
|
20
32
|
class TeamManager extends EventEmitter {
|
|
21
33
|
constructor({ nodeDid, dataDirs, states }) {
|
|
22
34
|
super();
|
|
@@ -48,10 +60,6 @@ class TeamManager extends EventEmitter {
|
|
|
48
60
|
});
|
|
49
61
|
});
|
|
50
62
|
|
|
51
|
-
this.states.blocklet.on('remove', ({ meta: { did } }) => {
|
|
52
|
-
this.cache[did] = null;
|
|
53
|
-
});
|
|
54
|
-
|
|
55
63
|
// init blocklet
|
|
56
64
|
this.states.blocklet
|
|
57
65
|
.getBlocklets()
|
|
@@ -280,6 +288,28 @@ class TeamManager extends EventEmitter {
|
|
|
280
288
|
return owner;
|
|
281
289
|
}
|
|
282
290
|
|
|
291
|
+
async deleteTeam(did) {
|
|
292
|
+
if (this.cache[did]) {
|
|
293
|
+
try {
|
|
294
|
+
if (this.cache[did].rbac) {
|
|
295
|
+
await closeDatabase(this.cache[did].rbac.storage.db);
|
|
296
|
+
}
|
|
297
|
+
|
|
298
|
+
if (this.cache[did].user) {
|
|
299
|
+
await closeDatabase(this.cache[did].user.db);
|
|
300
|
+
}
|
|
301
|
+
|
|
302
|
+
if (this.cache[did].session) {
|
|
303
|
+
await closeDatabase(this.cache[did].session.db);
|
|
304
|
+
}
|
|
305
|
+
} catch (err) {
|
|
306
|
+
logger.error('Failed to close database', { did, err });
|
|
307
|
+
}
|
|
308
|
+
}
|
|
309
|
+
|
|
310
|
+
this.cache[did] = null;
|
|
311
|
+
}
|
|
312
|
+
|
|
283
313
|
// =======
|
|
284
314
|
// Private
|
|
285
315
|
// =======
|
package/lib/util/blocklet.js
CHANGED
|
@@ -44,7 +44,6 @@ const getBlockletInfo = require('@blocklet/meta/lib/info');
|
|
|
44
44
|
const { validateMeta, fixAndValidateService } = require('@blocklet/meta/lib/validate');
|
|
45
45
|
const {
|
|
46
46
|
forEachBlocklet,
|
|
47
|
-
isFreeBlocklet,
|
|
48
47
|
getDisplayName,
|
|
49
48
|
findWebInterface,
|
|
50
49
|
forEachBlockletSync,
|
|
@@ -338,7 +337,8 @@ const getRuntimeEnvironments = (blocklet, nodeEnvironments, ancestors) => {
|
|
|
338
337
|
};
|
|
339
338
|
};
|
|
340
339
|
|
|
341
|
-
const isUsefulError = (err) =>
|
|
340
|
+
const isUsefulError = (err) =>
|
|
341
|
+
err && err.message !== 'process or namespace not found' && !/^Process \d+ not found$/.test(err.message);
|
|
342
342
|
|
|
343
343
|
const getHealthyCheckTimeout = (blocklet, { checkHealthImmediately } = {}) => {
|
|
344
344
|
let minConsecutiveTime = 5000;
|
|
@@ -724,8 +724,6 @@ const parseChildrenFromMeta = async (src, context = {}) => {
|
|
|
724
724
|
|
|
725
725
|
validateBlockletMeta(m, { ensureDist: true });
|
|
726
726
|
|
|
727
|
-
verifyPurchase(m, context);
|
|
728
|
-
|
|
729
727
|
if (!isComponentBlocklet(m)) {
|
|
730
728
|
throw new Error(`The blocklet cannot be a component: ${m.title}`);
|
|
731
729
|
}
|
|
@@ -1227,18 +1225,6 @@ const needBlockletDownload = (blocklet, oldBlocklet) => {
|
|
|
1227
1225
|
return !(get(oldBlocklet, 'meta.dist.integrity') === get(blocklet, 'meta.dist.integrity'));
|
|
1228
1226
|
};
|
|
1229
1227
|
|
|
1230
|
-
const verifyPurchase = (meta, opts = {}) => {
|
|
1231
|
-
if (opts.blockletPurchaseVerified) {
|
|
1232
|
-
return true;
|
|
1233
|
-
}
|
|
1234
|
-
|
|
1235
|
-
if (isFreeBlocklet(meta)) {
|
|
1236
|
-
return true;
|
|
1237
|
-
}
|
|
1238
|
-
|
|
1239
|
-
throw new Error('Can not install a non-free blocklet directly');
|
|
1240
|
-
};
|
|
1241
|
-
|
|
1242
1228
|
const findAvailableDid = (meta, siblings) => {
|
|
1243
1229
|
const reg = /-(\d+)$/;
|
|
1244
1230
|
const match = reg.exec(meta.name);
|
|
@@ -1316,7 +1302,6 @@ module.exports = {
|
|
|
1316
1302
|
getDiffFiles,
|
|
1317
1303
|
getBundleDir,
|
|
1318
1304
|
needBlockletDownload,
|
|
1319
|
-
verifyPurchase,
|
|
1320
1305
|
findAvailableDid,
|
|
1321
1306
|
ensureMeta,
|
|
1322
1307
|
getSourceUrlsFromConfig,
|
package/package.json
CHANGED
|
@@ -3,7 +3,7 @@
|
|
|
3
3
|
"publishConfig": {
|
|
4
4
|
"access": "public"
|
|
5
5
|
},
|
|
6
|
-
"version": "1.
|
|
6
|
+
"version": "1.8.0",
|
|
7
7
|
"description": "",
|
|
8
8
|
"main": "lib/index.js",
|
|
9
9
|
"files": [
|
|
@@ -19,30 +19,31 @@
|
|
|
19
19
|
"author": "wangshijun <wangshijun2010@gmail.com> (http://github.com/wangshijun)",
|
|
20
20
|
"license": "MIT",
|
|
21
21
|
"dependencies": {
|
|
22
|
-
"@abtnode/certificate-manager": "1.
|
|
23
|
-
"@abtnode/constant": "1.
|
|
24
|
-
"@abtnode/cron": "1.
|
|
25
|
-
"@abtnode/db": "1.
|
|
26
|
-
"@abtnode/logger": "1.
|
|
27
|
-
"@abtnode/queue": "1.
|
|
28
|
-
"@abtnode/rbac": "1.
|
|
29
|
-
"@abtnode/router-provider": "1.
|
|
30
|
-
"@abtnode/static-server": "1.
|
|
31
|
-
"@abtnode/timemachine": "1.
|
|
32
|
-
"@abtnode/util": "1.
|
|
33
|
-
"@arcblock/did": "
|
|
22
|
+
"@abtnode/certificate-manager": "1.8.0",
|
|
23
|
+
"@abtnode/constant": "1.8.0",
|
|
24
|
+
"@abtnode/cron": "1.8.0",
|
|
25
|
+
"@abtnode/db": "1.8.0",
|
|
26
|
+
"@abtnode/logger": "1.8.0",
|
|
27
|
+
"@abtnode/queue": "1.8.0",
|
|
28
|
+
"@abtnode/rbac": "1.8.0",
|
|
29
|
+
"@abtnode/router-provider": "1.8.0",
|
|
30
|
+
"@abtnode/static-server": "1.8.0",
|
|
31
|
+
"@abtnode/timemachine": "1.8.0",
|
|
32
|
+
"@abtnode/util": "1.8.0",
|
|
33
|
+
"@arcblock/did": "1.17.0",
|
|
34
34
|
"@arcblock/did-motif": "^1.1.10",
|
|
35
|
-
"@arcblock/did-util": "
|
|
36
|
-
"@arcblock/event-hub": "1.
|
|
35
|
+
"@arcblock/did-util": "1.17.0",
|
|
36
|
+
"@arcblock/event-hub": "1.17.0",
|
|
37
|
+
"@arcblock/jwt": "^1.17.0",
|
|
37
38
|
"@arcblock/pm2-events": "^0.0.5",
|
|
38
|
-
"@arcblock/vc": "
|
|
39
|
-
"@blocklet/meta": "1.
|
|
39
|
+
"@arcblock/vc": "1.17.0",
|
|
40
|
+
"@blocklet/meta": "1.8.0",
|
|
40
41
|
"@fidm/x509": "^1.2.1",
|
|
41
42
|
"@nedb/core": "^1.2.2",
|
|
42
43
|
"@nedb/multi": "^1.2.2",
|
|
43
|
-
"@ocap/mcrypto": "
|
|
44
|
-
"@ocap/util": "
|
|
45
|
-
"@ocap/wallet": "
|
|
44
|
+
"@ocap/mcrypto": "1.17.0",
|
|
45
|
+
"@ocap/util": "1.17.0",
|
|
46
|
+
"@ocap/wallet": "1.17.0",
|
|
46
47
|
"@slack/webhook": "^5.0.3",
|
|
47
48
|
"axios": "^0.27.2",
|
|
48
49
|
"axon": "^2.0.3",
|
|
@@ -80,5 +81,5 @@
|
|
|
80
81
|
"express": "^4.17.1",
|
|
81
82
|
"jest": "^27.4.5"
|
|
82
83
|
},
|
|
83
|
-
"gitHead": "
|
|
84
|
+
"gitHead": "6446a85fb33721abc24bb1045d59158e6b96c241"
|
|
84
85
|
}
|