@abtnode/core 1.8.15 → 1.8.18
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 +124 -2
- package/lib/blocklet/hooks.js +2 -1
- package/lib/blocklet/manager/base.js +2 -0
- package/lib/blocklet/manager/disk.js +15 -53
- package/lib/index.js +5 -4
- package/lib/states/access-key.js +16 -14
- package/lib/states/audit-log.js +16 -6
- package/lib/states/base.js +2 -2
- package/lib/states/blocklet-extras.js +10 -10
- package/lib/states/blocklet.js +20 -19
- package/lib/states/cache.js +8 -6
- package/lib/states/challenge.js +5 -5
- package/lib/states/index.js +13 -13
- package/lib/states/migration.js +4 -4
- package/lib/states/node.js +12 -12
- package/lib/states/notification.js +8 -8
- package/lib/states/session.js +16 -14
- package/lib/states/site.js +10 -22
- package/lib/states/user.js +11 -21
- package/lib/states/webhook.js +5 -5
- package/lib/util/blocklet.js +80 -4
- package/package.json +24 -25
package/lib/api/team.js
CHANGED
|
@@ -1,13 +1,35 @@
|
|
|
1
1
|
const { EventEmitter } = require('events');
|
|
2
2
|
const pick = require('lodash/pick');
|
|
3
|
+
const joinUrl = require('url-join');
|
|
4
|
+
|
|
3
5
|
const logger = require('@abtnode/logger')('@abtnode/core:api:team');
|
|
4
|
-
const {
|
|
6
|
+
const {
|
|
7
|
+
ROLES,
|
|
8
|
+
genPermissionName,
|
|
9
|
+
EVENTS,
|
|
10
|
+
WHO_CAN_ACCESS,
|
|
11
|
+
PASSPORT_STATUS,
|
|
12
|
+
WELLKNOWN_SERVICE_PATH_PREFIX,
|
|
13
|
+
} = require('@abtnode/constant');
|
|
5
14
|
const { isValid: isValidDid } = require('@arcblock/did');
|
|
6
15
|
const { BlockletEvents } = require('@blocklet/meta/lib/constants');
|
|
16
|
+
const { sendToUser } = require('@blocklet/sdk/lib/util/send-notification');
|
|
17
|
+
const {
|
|
18
|
+
createPassportVC,
|
|
19
|
+
createPassport,
|
|
20
|
+
upsertToPassports,
|
|
21
|
+
createUserPassport,
|
|
22
|
+
} = require('@abtnode/auth/lib/passport');
|
|
23
|
+
const { getPassportStatusEndpoint } = require('@abtnode/auth/lib/auth');
|
|
24
|
+
const getBlockletInfo = require('@blocklet/meta/lib/info');
|
|
25
|
+
const { parseUserAvatar } = require('@abtnode/util/lib/user-avatar');
|
|
26
|
+
|
|
7
27
|
const { validateTrustedPassportIssuers } = require('../validators/trusted-passport');
|
|
8
28
|
const { validateCreateRole, validateUpdateRole } = require('../validators/role');
|
|
9
29
|
const { validateCreatePermission, validateUpdatePermission } = require('../validators/permission');
|
|
10
30
|
|
|
31
|
+
const { getBlocklet } = require('../util/blocklet');
|
|
32
|
+
|
|
11
33
|
const MAX_USER_PAGE_SIZE = 100;
|
|
12
34
|
|
|
13
35
|
const validateReservedRole = (role) => {
|
|
@@ -17,19 +39,53 @@ const validateReservedRole = (role) => {
|
|
|
17
39
|
return true;
|
|
18
40
|
};
|
|
19
41
|
|
|
42
|
+
const sendPassportVcNotification = ({ userDid, appWallet: wallet, locale, vc }) => {
|
|
43
|
+
try {
|
|
44
|
+
const receiver = userDid;
|
|
45
|
+
const sender = { appDid: wallet.address, appSk: wallet.secretKey };
|
|
46
|
+
const message = {
|
|
47
|
+
title: {
|
|
48
|
+
en: 'Receive a Passport',
|
|
49
|
+
zh: '获得通行证',
|
|
50
|
+
}[locale],
|
|
51
|
+
body: {
|
|
52
|
+
en: 'You got a passport',
|
|
53
|
+
zh: '你获得了一张通行证',
|
|
54
|
+
}[locale],
|
|
55
|
+
attachments: [
|
|
56
|
+
{
|
|
57
|
+
type: 'vc',
|
|
58
|
+
data: {
|
|
59
|
+
credential: vc,
|
|
60
|
+
tag: vc.credentialSubject.passport.name,
|
|
61
|
+
},
|
|
62
|
+
},
|
|
63
|
+
],
|
|
64
|
+
};
|
|
65
|
+
|
|
66
|
+
sendToUser(receiver, message, sender, process.env.ABT_NODE_SERVICE_PORT).catch((error) => {
|
|
67
|
+
logger.error('Failed send passport vc to wallet', { error });
|
|
68
|
+
});
|
|
69
|
+
} catch (error) {
|
|
70
|
+
logger.error('Failed send passport vc to wallet', { error });
|
|
71
|
+
}
|
|
72
|
+
};
|
|
73
|
+
|
|
20
74
|
class TeamAPI extends EventEmitter {
|
|
21
75
|
/**
|
|
22
76
|
*
|
|
23
77
|
* @param {object} states abtnode core StateDB
|
|
24
78
|
*/
|
|
25
|
-
constructor({ teamManager, states }) {
|
|
79
|
+
constructor({ teamManager, states, dataDirs }) {
|
|
26
80
|
super();
|
|
27
81
|
|
|
28
82
|
this.notification = states.notification;
|
|
29
83
|
this.node = states.node;
|
|
84
|
+
this.states = states;
|
|
30
85
|
this.memberInviteExpireTime = 1000 * 3600 * 24 * 30; // 30 days
|
|
31
86
|
this.serverInviteExpireTime = 1000 * 3600; // 1 hour
|
|
32
87
|
this.teamManager = teamManager;
|
|
88
|
+
this.dataDirs = dataDirs;
|
|
33
89
|
}
|
|
34
90
|
|
|
35
91
|
// User && Invitation
|
|
@@ -223,6 +279,72 @@ class TeamAPI extends EventEmitter {
|
|
|
223
279
|
return doc;
|
|
224
280
|
}
|
|
225
281
|
|
|
282
|
+
async issuePassportToUser({ teamDid, userDid, role: roleName, notify = true }, context = {}) {
|
|
283
|
+
const { locale = 'en' } = context;
|
|
284
|
+
|
|
285
|
+
const userState = await this.getUserState(teamDid);
|
|
286
|
+
const user = await userState.getUser(userDid);
|
|
287
|
+
|
|
288
|
+
if (!user) {
|
|
289
|
+
throw new Error(`user does not exist: ${userDid}`);
|
|
290
|
+
}
|
|
291
|
+
|
|
292
|
+
if (!user.approved) {
|
|
293
|
+
throw new Error(`the user is revoked: ${userDid}`);
|
|
294
|
+
}
|
|
295
|
+
|
|
296
|
+
const rbac = await this.getRBAC(teamDid);
|
|
297
|
+
const role = await rbac.getRole(roleName);
|
|
298
|
+
|
|
299
|
+
if (!role) {
|
|
300
|
+
throw new Error(`passport does not exist: ${roleName}`);
|
|
301
|
+
}
|
|
302
|
+
|
|
303
|
+
// create vc
|
|
304
|
+
const blocklet = await getBlocklet({ did: teamDid, states: this.states, dataDirs: this.dataDirs });
|
|
305
|
+
const nodeInfo = await this.node.read();
|
|
306
|
+
const blockletInfo = getBlockletInfo(blocklet, nodeInfo.sk);
|
|
307
|
+
const { wallet, passportColor, appUrl, name: issuerName } = blockletInfo;
|
|
308
|
+
|
|
309
|
+
const vc = createPassportVC({
|
|
310
|
+
issuerName,
|
|
311
|
+
issuerWallet: wallet,
|
|
312
|
+
ownerDid: userDid,
|
|
313
|
+
passport: await createPassport({
|
|
314
|
+
role,
|
|
315
|
+
}),
|
|
316
|
+
endpoint: getPassportStatusEndpoint({
|
|
317
|
+
baseUrl: joinUrl(appUrl, WELLKNOWN_SERVICE_PATH_PREFIX),
|
|
318
|
+
userDid,
|
|
319
|
+
teamDid,
|
|
320
|
+
}),
|
|
321
|
+
ownerProfile: {
|
|
322
|
+
...user,
|
|
323
|
+
avatar: await parseUserAvatar(user.avatar, { dataDir: blocklet.env.dataDir }),
|
|
324
|
+
},
|
|
325
|
+
preferredColor: passportColor,
|
|
326
|
+
});
|
|
327
|
+
|
|
328
|
+
// write passport to db
|
|
329
|
+
const passport = createUserPassport(vc, { role: role.name });
|
|
330
|
+
user.passports = upsertToPassports(user.passports || [], passport);
|
|
331
|
+
await this.updateUser({
|
|
332
|
+
teamDid,
|
|
333
|
+
user: {
|
|
334
|
+
did: user.did,
|
|
335
|
+
pk: user.pk,
|
|
336
|
+
passports: user.passports,
|
|
337
|
+
},
|
|
338
|
+
});
|
|
339
|
+
|
|
340
|
+
// send vc to wallet
|
|
341
|
+
if (notify) {
|
|
342
|
+
sendPassportVcNotification({ userDid, appWallet: wallet, locale, vc });
|
|
343
|
+
}
|
|
344
|
+
|
|
345
|
+
return user;
|
|
346
|
+
}
|
|
347
|
+
|
|
226
348
|
async revokeUserPassport({ teamDid, userDid, passportId } = {}) {
|
|
227
349
|
if (!passportId) {
|
|
228
350
|
throw new Error('Revoked passport should not be empty');
|
package/lib/blocklet/hooks.js
CHANGED
|
@@ -56,7 +56,8 @@ const preStart = async (blocklet, options) => {
|
|
|
56
56
|
return runUserHook(blocklet.env.processId, 'pre-start', options);
|
|
57
57
|
};
|
|
58
58
|
|
|
59
|
+
const postStart = (processId, ...args) => runUserHook(processId, 'post-start', ...args);
|
|
59
60
|
const preUninstall = (processId, ...args) => runUserHook(processId, 'pre-uninstall', ...args);
|
|
60
61
|
const preStop = (processId, ...args) => runUserHook(processId, 'pre-stop', ...args);
|
|
61
62
|
|
|
62
|
-
module.exports = { preDeploy, preInstall, postInstall, preStart, preUninstall, preStop, preConfig };
|
|
63
|
+
module.exports = { preDeploy, preInstall, postInstall, preStart, postStart, preUninstall, preStop, preConfig };
|
|
@@ -8,6 +8,8 @@ class BaseBlockletManager extends EventEmitter {
|
|
|
8
8
|
constructor() {
|
|
9
9
|
super();
|
|
10
10
|
|
|
11
|
+
this.setMaxListeners(100);
|
|
12
|
+
|
|
11
13
|
// HACK: do not emit any events from CLI
|
|
12
14
|
if (isCLI() && process.env.NODE_ENV !== 'test') {
|
|
13
15
|
this.emit = (name) => logger.debug('stopped blocklet manager event in CLI', name);
|
|
@@ -36,7 +36,6 @@ const {
|
|
|
36
36
|
forEachBlocklet,
|
|
37
37
|
forEachChild,
|
|
38
38
|
getComponentId,
|
|
39
|
-
getComponentName,
|
|
40
39
|
getComponentBundleId,
|
|
41
40
|
} = require('@blocklet/meta/lib/util');
|
|
42
41
|
const getComponentProcessId = require('@blocklet/meta/lib/get-component-process-id');
|
|
@@ -73,9 +72,7 @@ const {
|
|
|
73
72
|
getFromCache: getAccessibleExternalNodeIp,
|
|
74
73
|
} = require('../../util/get-accessible-external-node-ip');
|
|
75
74
|
const {
|
|
76
|
-
getComponentDirs,
|
|
77
75
|
getBlockletMetaFromUrl,
|
|
78
|
-
fillBlockletConfigs,
|
|
79
76
|
ensureBlockletExpanded,
|
|
80
77
|
getAppSystemEnvironments,
|
|
81
78
|
getComponentSystemEnvironments,
|
|
@@ -104,6 +101,7 @@ const {
|
|
|
104
101
|
needBlockletDownload,
|
|
105
102
|
findAvailableDid,
|
|
106
103
|
ensureMeta,
|
|
104
|
+
getBlocklet,
|
|
107
105
|
} = require('../../util/blocklet');
|
|
108
106
|
const { parseSourceUrl } = require('../../util/registry');
|
|
109
107
|
const states = require('../../states');
|
|
@@ -387,17 +385,22 @@ class BlockletManager extends BaseBlockletManager {
|
|
|
387
385
|
fs.mkdirSync(logsDir, { recursive: true });
|
|
388
386
|
}
|
|
389
387
|
|
|
390
|
-
|
|
391
|
-
|
|
392
|
-
|
|
393
|
-
|
|
394
|
-
preStart: (b, { env }) =>
|
|
395
|
-
hooks.preStart(b, {
|
|
388
|
+
const getHookFn =
|
|
389
|
+
(hookName) =>
|
|
390
|
+
(b, { env }) =>
|
|
391
|
+
hooks[hookName](b, {
|
|
396
392
|
appDir: b.env.appDir,
|
|
397
393
|
hooks: Object.assign(b.meta.hooks || {}, b.meta.scripts || {}),
|
|
398
394
|
env,
|
|
399
395
|
did, // root blocklet did,
|
|
400
|
-
})
|
|
396
|
+
});
|
|
397
|
+
|
|
398
|
+
// start process
|
|
399
|
+
const nodeEnvironments = await states.node.getEnvironments();
|
|
400
|
+
await startBlockletProcess(blocklet, {
|
|
401
|
+
...context,
|
|
402
|
+
preStart: getHookFn('preStart'),
|
|
403
|
+
postStart: getHookFn('postStart'),
|
|
401
404
|
nodeEnvironments,
|
|
402
405
|
nodeInfo: await states.node.read(),
|
|
403
406
|
e2eMode,
|
|
@@ -1294,49 +1297,8 @@ class BlockletManager extends BaseBlockletManager {
|
|
|
1294
1297
|
return rootBlocklet;
|
|
1295
1298
|
}
|
|
1296
1299
|
|
|
1297
|
-
async ensureBlocklet(did,
|
|
1298
|
-
|
|
1299
|
-
throw new Error(`Blocklet did is invalid: ${did}`);
|
|
1300
|
-
}
|
|
1301
|
-
|
|
1302
|
-
const blocklet = await states.blocklet.getBlocklet(did);
|
|
1303
|
-
if (!blocklet) {
|
|
1304
|
-
if (throwOnNotExist) {
|
|
1305
|
-
throw new Error(`Can not find blocklet in database by did ${did}`);
|
|
1306
|
-
}
|
|
1307
|
-
return null;
|
|
1308
|
-
}
|
|
1309
|
-
|
|
1310
|
-
// app settings
|
|
1311
|
-
const settings = await states.blockletExtras.getSettings(blocklet.meta.did);
|
|
1312
|
-
blocklet.trustedPassports = get(settings, 'trustedPassports') || [];
|
|
1313
|
-
blocklet.enablePassportIssuance = get(settings, 'enablePassportIssuance', true);
|
|
1314
|
-
blocklet.settings = settings || {};
|
|
1315
|
-
|
|
1316
|
-
// app site
|
|
1317
|
-
blocklet.site = await this.getSiteByDid(blocklet.meta.did);
|
|
1318
|
-
|
|
1319
|
-
await forEachBlocklet(blocklet, async (component, { id, level, ancestors }) => {
|
|
1320
|
-
// component env
|
|
1321
|
-
component.env = {
|
|
1322
|
-
id,
|
|
1323
|
-
name: getComponentName(component, ancestors),
|
|
1324
|
-
processId: getComponentProcessId(component, ancestors),
|
|
1325
|
-
...getComponentDirs(component, {
|
|
1326
|
-
dataDirs: this.dataDirs,
|
|
1327
|
-
ensure: true,
|
|
1328
|
-
validate: validateEnv,
|
|
1329
|
-
ancestors,
|
|
1330
|
-
e2eMode: level === 0 ? e2eMode : false,
|
|
1331
|
-
}),
|
|
1332
|
-
};
|
|
1333
|
-
|
|
1334
|
-
// component config
|
|
1335
|
-
const configs = await states.blockletExtras.getConfigs([...ancestors.map((x) => x.meta.did), component.meta.did]);
|
|
1336
|
-
fillBlockletConfigs(component, configs);
|
|
1337
|
-
});
|
|
1338
|
-
|
|
1339
|
-
return blocklet;
|
|
1300
|
+
async ensureBlocklet(did, opts = {}) {
|
|
1301
|
+
return getBlocklet({ ...opts, states, dataDirs: this.dataDirs, did });
|
|
1340
1302
|
}
|
|
1341
1303
|
|
|
1342
1304
|
async hasBlocklet({ did }) {
|
package/lib/index.js
CHANGED
|
@@ -163,7 +163,7 @@ function ABTNode(options) {
|
|
|
163
163
|
} = getRouterHelpers({ dataDirs, routingSnapshot, routerManager, blockletManager, certManager });
|
|
164
164
|
|
|
165
165
|
const nodeAPI = new NodeAPI(states.node);
|
|
166
|
-
const teamAPI = new TeamAPI({ states, teamManager });
|
|
166
|
+
const teamAPI = new TeamAPI({ states, teamManager, dataDirs });
|
|
167
167
|
|
|
168
168
|
blockletManager.getRoutingRulesByDid = getRoutingRulesByDid;
|
|
169
169
|
blockletManager.getSiteByDid = getSiteByDid;
|
|
@@ -298,6 +298,8 @@ function ABTNode(options) {
|
|
|
298
298
|
// Passport
|
|
299
299
|
revokeUserPassport: teamAPI.revokeUserPassport.bind(teamAPI),
|
|
300
300
|
enableUserPassport: teamAPI.enableUserPassport.bind(teamAPI),
|
|
301
|
+
issuePassportToUser: teamAPI.issuePassportToUser.bind(teamAPI),
|
|
302
|
+
|
|
301
303
|
createPassportIssuance: teamAPI.createPassportIssuance.bind(teamAPI),
|
|
302
304
|
getPassportIssuances: teamAPI.getPassportIssuances.bind(teamAPI),
|
|
303
305
|
getPassportIssuance: teamAPI.getPassportIssuance.bind(teamAPI),
|
|
@@ -311,13 +313,13 @@ function ABTNode(options) {
|
|
|
311
313
|
verifyChallenge: states.challenge.verify.bind(states.challenge),
|
|
312
314
|
|
|
313
315
|
// Notifications
|
|
314
|
-
getNotifications: states.notification.
|
|
316
|
+
getNotifications: states.notification.findPaginated.bind(states.notification),
|
|
315
317
|
readNotifications: states.notification.read.bind(states.notification),
|
|
316
318
|
unreadNotifications: states.notification.unread.bind(states.notification),
|
|
317
319
|
|
|
318
320
|
// AuditLog
|
|
319
321
|
createAuditLog: (params) => states.auditLog.create(params, instance),
|
|
320
|
-
getAuditLogs: states.auditLog.
|
|
322
|
+
getAuditLogs: states.auditLog.findPaginated.bind(states.auditLog),
|
|
321
323
|
|
|
322
324
|
// Routing
|
|
323
325
|
routerManager,
|
|
@@ -392,7 +394,6 @@ function ABTNode(options) {
|
|
|
392
394
|
|
|
393
395
|
const events = createEvents({
|
|
394
396
|
blockletManager,
|
|
395
|
-
blockletRegistry,
|
|
396
397
|
ensureBlockletRouting,
|
|
397
398
|
ensureBlockletRoutingForUpgrade,
|
|
398
399
|
removeBlockletRouting,
|
package/lib/states/access-key.js
CHANGED
|
@@ -19,13 +19,15 @@ const validatePassport = (passport) => {
|
|
|
19
19
|
const getUserName = (context) => get(context, 'user.fullName', '');
|
|
20
20
|
|
|
21
21
|
class AccessKeyState extends BaseState {
|
|
22
|
-
constructor(baseDir,
|
|
23
|
-
super(baseDir, { filename: 'access_key.db', ...
|
|
24
|
-
|
|
25
|
-
this.
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
22
|
+
constructor(baseDir, config = {}) {
|
|
23
|
+
super(baseDir, { filename: 'access_key.db', ...config });
|
|
24
|
+
|
|
25
|
+
this.onReady(() => {
|
|
26
|
+
this.ensureIndex({ fieldName: 'accessKeyId', unique: true }, (error) => {
|
|
27
|
+
if (error) {
|
|
28
|
+
logger.error('ensure unique index failed', { error });
|
|
29
|
+
}
|
|
30
|
+
});
|
|
29
31
|
});
|
|
30
32
|
}
|
|
31
33
|
|
|
@@ -48,7 +50,7 @@ class AccessKeyState extends BaseState {
|
|
|
48
50
|
data.createdBy = getUserName(context);
|
|
49
51
|
data.updatedBy = getUserName(context);
|
|
50
52
|
|
|
51
|
-
const doc = await this.
|
|
53
|
+
const doc = await this.insert(data);
|
|
52
54
|
return {
|
|
53
55
|
...doc,
|
|
54
56
|
accessKeySecret: toBase58(wallet.secretKey),
|
|
@@ -67,7 +69,7 @@ class AccessKeyState extends BaseState {
|
|
|
67
69
|
if (!accessKeyId) {
|
|
68
70
|
throw new Error('accessKeyId should not be empty');
|
|
69
71
|
}
|
|
70
|
-
const doc = await this.
|
|
72
|
+
const doc = await this.findOne({ accessKeyId });
|
|
71
73
|
return doc;
|
|
72
74
|
}
|
|
73
75
|
|
|
@@ -82,7 +84,7 @@ class AccessKeyState extends BaseState {
|
|
|
82
84
|
if (!accessKeyId) {
|
|
83
85
|
throw new Error('accessKeyId should not be empty');
|
|
84
86
|
}
|
|
85
|
-
const doc = await this.
|
|
87
|
+
const doc = await this.findOne({ accessKeyId });
|
|
86
88
|
if (!doc) {
|
|
87
89
|
throw new Error(`Access Key Id ${accessKeyId} does not exist`);
|
|
88
90
|
}
|
|
@@ -92,7 +94,7 @@ class AccessKeyState extends BaseState {
|
|
|
92
94
|
doc.passport = passport;
|
|
93
95
|
doc.updatedBy = getUserName(context);
|
|
94
96
|
|
|
95
|
-
await
|
|
97
|
+
await super.update({ accessKeyId }, { $set: doc });
|
|
96
98
|
return doc;
|
|
97
99
|
}
|
|
98
100
|
|
|
@@ -101,12 +103,12 @@ class AccessKeyState extends BaseState {
|
|
|
101
103
|
if (!accessKeyId) {
|
|
102
104
|
throw new Error('accessKeyId should not be empty');
|
|
103
105
|
}
|
|
104
|
-
const doc = await this.
|
|
106
|
+
const doc = await this.findOne({ accessKeyId });
|
|
105
107
|
if (!doc) {
|
|
106
108
|
throw new Error(`Access Key Id ${accessKeyId} does not exist`);
|
|
107
109
|
}
|
|
108
110
|
doc.lastUsedAt = new Date();
|
|
109
|
-
await
|
|
111
|
+
await super.update({ accessKeyId }, { $set: doc });
|
|
110
112
|
return doc;
|
|
111
113
|
}
|
|
112
114
|
|
|
@@ -116,7 +118,7 @@ class AccessKeyState extends BaseState {
|
|
|
116
118
|
if (!accessKeyId) {
|
|
117
119
|
throw new Error('accessKeyId should not be empty');
|
|
118
120
|
}
|
|
119
|
-
const num = await
|
|
121
|
+
const num = await super.remove({ accessKeyId });
|
|
120
122
|
if (num <= 0) {
|
|
121
123
|
throw new Error(`Access Key Id ${accessKeyId} does not exist`);
|
|
122
124
|
}
|
package/lib/states/audit-log.js
CHANGED
|
@@ -3,7 +3,7 @@ const pick = require('lodash/pick');
|
|
|
3
3
|
const get = require('lodash/get');
|
|
4
4
|
const joinUrl = require('url-join');
|
|
5
5
|
const { getDisplayName } = require('@blocklet/meta/lib/util');
|
|
6
|
-
const { BLOCKLET_SITE_GROUP_SUFFIX } = require('@abtnode/constant');
|
|
6
|
+
const { BLOCKLET_SITE_GROUP_SUFFIX, NODE_SERVICES } = require('@abtnode/constant');
|
|
7
7
|
const logger = require('@abtnode/logger')('@abtnode/core:states:audit-log');
|
|
8
8
|
|
|
9
9
|
const BaseState = require('./base');
|
|
@@ -177,6 +177,8 @@ const getLogContent = async (action, args, context, result, info, node) => {
|
|
|
177
177
|
return `updated trusted passport issuers to following for ${team}: \n${args.trustedPassports.map(x => `- ${x.remark}: ${x.issuerDid}`).join('\n')}`; // prettier-ignore
|
|
178
178
|
case 'delegateTransferNFT':
|
|
179
179
|
return `${args.owner} ${args.reason}`;
|
|
180
|
+
case 'issuePassportToUser':
|
|
181
|
+
return `issued **${args.role}** passport to ${user}`;
|
|
180
182
|
|
|
181
183
|
// accessKeys
|
|
182
184
|
case 'createAccessKey':
|
|
@@ -344,9 +346,15 @@ const getScope = (args = {}) => {
|
|
|
344
346
|
return null;
|
|
345
347
|
};
|
|
346
348
|
|
|
349
|
+
const fixActor = (actor) => {
|
|
350
|
+
if ([NODE_SERVICES.AUTH_SERVICE, 'blocklet'].includes(actor?.role)) {
|
|
351
|
+
actor.role = '';
|
|
352
|
+
}
|
|
353
|
+
};
|
|
354
|
+
|
|
347
355
|
class AuditLogState extends BaseState {
|
|
348
|
-
constructor(baseDir,
|
|
349
|
-
super(baseDir, { filename: 'audit-log.db', ...
|
|
356
|
+
constructor(baseDir, config = {}) {
|
|
357
|
+
super(baseDir, { filename: 'audit-log.db', ...config });
|
|
350
358
|
}
|
|
351
359
|
|
|
352
360
|
/**
|
|
@@ -399,7 +407,9 @@ class AuditLogState extends BaseState {
|
|
|
399
407
|
const { ip, ua, user } = context;
|
|
400
408
|
const [info, uaInfo] = await Promise.all([node.states.node.read(), parse(ua)]);
|
|
401
409
|
|
|
402
|
-
|
|
410
|
+
fixActor(user);
|
|
411
|
+
|
|
412
|
+
const data = await this.insert({
|
|
403
413
|
scope: getScope(args) || info.did, // server or blocklet did
|
|
404
414
|
action,
|
|
405
415
|
category: await getLogCategory(action, args, context, result, info, node),
|
|
@@ -420,7 +430,7 @@ class AuditLogState extends BaseState {
|
|
|
420
430
|
});
|
|
421
431
|
}
|
|
422
432
|
|
|
423
|
-
async
|
|
433
|
+
async findPaginated({ scope, category, paging } = {}) {
|
|
424
434
|
const conditions = {};
|
|
425
435
|
if (scope) {
|
|
426
436
|
conditions.scope = scope;
|
|
@@ -429,7 +439,7 @@ class AuditLogState extends BaseState {
|
|
|
429
439
|
conditions.category = category;
|
|
430
440
|
}
|
|
431
441
|
|
|
432
|
-
return
|
|
442
|
+
return super.paginate(conditions, { createdAt: -1 }, { pageSize: 20, ...paging });
|
|
433
443
|
}
|
|
434
444
|
}
|
|
435
445
|
|
package/lib/states/base.js
CHANGED
|
@@ -4,8 +4,8 @@ const logger = require('@abtnode/logger')('@abtnode/core:states');
|
|
|
4
4
|
const { isCLI } = require('../util');
|
|
5
5
|
|
|
6
6
|
class BaseState extends DB {
|
|
7
|
-
constructor(baseDir,
|
|
8
|
-
super(baseDir,
|
|
7
|
+
constructor(baseDir, config) {
|
|
8
|
+
super(baseDir, config);
|
|
9
9
|
|
|
10
10
|
// HACK: do not emit any events from CLI
|
|
11
11
|
if (isCLI() && process.env.NODE_ENV !== 'test') {
|
|
@@ -12,8 +12,8 @@ const { mergeConfigs, parseConfigs } = require('../blocklet/extras');
|
|
|
12
12
|
const noop = (k) => (v) => v[k];
|
|
13
13
|
|
|
14
14
|
class BlockletExtrasState extends BaseState {
|
|
15
|
-
constructor(baseDir,
|
|
16
|
-
super(baseDir, { filename: 'blocklet_extras.db', ...
|
|
15
|
+
constructor(baseDir, config = {}) {
|
|
16
|
+
super(baseDir, { filename: 'blocklet_extras.db', ...config });
|
|
17
17
|
|
|
18
18
|
this.extras = [
|
|
19
19
|
// environment
|
|
@@ -82,10 +82,10 @@ class BlockletExtrasState extends BaseState {
|
|
|
82
82
|
// eslint-disable-next-line no-param-reassign
|
|
83
83
|
dids = [].concat(dids);
|
|
84
84
|
const [rootDid, ...childDids] = dids;
|
|
85
|
-
const { dek } = this.
|
|
85
|
+
const { dek } = this.config;
|
|
86
86
|
const { name, afterGet = noop('data') } = extra;
|
|
87
87
|
|
|
88
|
-
let item = await this.
|
|
88
|
+
let item = await this.findOne({ did: rootDid });
|
|
89
89
|
while (item && childDids.length) {
|
|
90
90
|
const did = childDids.shift();
|
|
91
91
|
item = (item.children || []).find((x) => x.did === did);
|
|
@@ -104,9 +104,9 @@ class BlockletExtrasState extends BaseState {
|
|
|
104
104
|
// eslint-disable-next-line no-param-reassign
|
|
105
105
|
dids = [].concat(dids);
|
|
106
106
|
const [rootDid, ...childDids] = dids;
|
|
107
|
-
const { dek } = this.
|
|
107
|
+
const { dek } = this.config;
|
|
108
108
|
const { name, beforeSet = noop('cur') } = extra;
|
|
109
|
-
const exist = await this.
|
|
109
|
+
const exist = await this.findOne({ did: rootDid });
|
|
110
110
|
|
|
111
111
|
const item = exist || { did: rootDid };
|
|
112
112
|
let component = item;
|
|
@@ -126,7 +126,7 @@ class BlockletExtrasState extends BaseState {
|
|
|
126
126
|
component[name] = newData;
|
|
127
127
|
|
|
128
128
|
if (!exist) {
|
|
129
|
-
await this.
|
|
129
|
+
await this.insert(item);
|
|
130
130
|
logger.info('create extra success', { name, dids });
|
|
131
131
|
} else {
|
|
132
132
|
await this.update(item._id, item);
|
|
@@ -143,7 +143,7 @@ class BlockletExtrasState extends BaseState {
|
|
|
143
143
|
dids = [].concat(dids);
|
|
144
144
|
const [rootDid, ...childDids] = dids;
|
|
145
145
|
const { name } = extra;
|
|
146
|
-
const item = await this.
|
|
146
|
+
const item = await this.findOne({ did: rootDid });
|
|
147
147
|
|
|
148
148
|
if (!item) {
|
|
149
149
|
return null;
|
|
@@ -170,9 +170,9 @@ class BlockletExtrasState extends BaseState {
|
|
|
170
170
|
|
|
171
171
|
generateListFn(extra) {
|
|
172
172
|
return async () => {
|
|
173
|
-
const { dek } = this.
|
|
173
|
+
const { dek } = this.config;
|
|
174
174
|
const { name, afterGet = noop('data') } = extra;
|
|
175
|
-
const docs = await this.
|
|
175
|
+
const docs = await this.find({});
|
|
176
176
|
const list = docs
|
|
177
177
|
.filter((x) => x[name])
|
|
178
178
|
.map((x) => ({
|
package/lib/states/blocklet.js
CHANGED
|
@@ -41,6 +41,7 @@ const formatBlocklet = (blocklet, phase, dek) => {
|
|
|
41
41
|
|
|
42
42
|
if (phase === 'onRead') {
|
|
43
43
|
b.children = b.children || [];
|
|
44
|
+
b.environments = b.environments || [];
|
|
44
45
|
}
|
|
45
46
|
|
|
46
47
|
if (!b.environments || !b.meta || !dek) {
|
|
@@ -78,14 +79,14 @@ class BlockletState extends BaseState {
|
|
|
78
79
|
/**
|
|
79
80
|
* Creates an instance of BlockletState
|
|
80
81
|
* @param {string} baseDir
|
|
81
|
-
* @param {object}
|
|
82
|
-
* @param {string}
|
|
82
|
+
* @param {object} config
|
|
83
|
+
* @param {string} config.blockletPort - from which port to start new blocklets
|
|
83
84
|
* @memberof BlockletState
|
|
84
85
|
*/
|
|
85
|
-
constructor(baseDir,
|
|
86
|
-
super(baseDir, { filename: 'blocklet.db', ...
|
|
86
|
+
constructor(baseDir, config = {}) {
|
|
87
|
+
super(baseDir, { filename: 'blocklet.db', ...config });
|
|
87
88
|
|
|
88
|
-
this.defaultPort =
|
|
89
|
+
this.defaultPort = config.blockletPort || 5555;
|
|
89
90
|
}
|
|
90
91
|
|
|
91
92
|
getBlocklet(did) {
|
|
@@ -94,12 +95,12 @@ class BlockletState extends BaseState {
|
|
|
94
95
|
resolve(null);
|
|
95
96
|
}
|
|
96
97
|
|
|
97
|
-
this.
|
|
98
|
+
this.findOne({ $or: [{ 'meta.did': did }, { appDid: did }] }, (err, doc) => {
|
|
98
99
|
if (err) {
|
|
99
100
|
return reject(err);
|
|
100
101
|
}
|
|
101
102
|
|
|
102
|
-
return resolve(doc ? formatBlocklet(doc, 'onRead', this.
|
|
103
|
+
return resolve(doc ? formatBlocklet(doc, 'onRead', this.config.dek) : null);
|
|
103
104
|
});
|
|
104
105
|
});
|
|
105
106
|
}
|
|
@@ -110,7 +111,7 @@ class BlockletState extends BaseState {
|
|
|
110
111
|
resolve(null);
|
|
111
112
|
}
|
|
112
113
|
|
|
113
|
-
this.
|
|
114
|
+
this.findOne({ $or: [{ 'meta.did': did }, { appDid: did }] }, { status: 1 }, (err, doc) => {
|
|
114
115
|
if (err) {
|
|
115
116
|
return reject(err);
|
|
116
117
|
}
|
|
@@ -126,7 +127,7 @@ class BlockletState extends BaseState {
|
|
|
126
127
|
resolve(false);
|
|
127
128
|
}
|
|
128
129
|
|
|
129
|
-
this.
|
|
130
|
+
this.count({ $or: [{ 'meta.did': did }, { appDid: did }] }, (err, count) => {
|
|
130
131
|
if (err) {
|
|
131
132
|
return reject(err);
|
|
132
133
|
}
|
|
@@ -138,15 +139,15 @@ class BlockletState extends BaseState {
|
|
|
138
139
|
|
|
139
140
|
getBlocklets(query = {}, projection) {
|
|
140
141
|
return new Promise((resolve, reject) => {
|
|
141
|
-
this.
|
|
142
|
-
.
|
|
143
|
-
.sort(
|
|
144
|
-
.exec((err, docs) => {
|
|
142
|
+
this.cursor(query)
|
|
143
|
+
.projection(projection)
|
|
144
|
+
.sort({ createdAt: -1 })
|
|
145
|
+
.exec((err, docs = []) => {
|
|
145
146
|
if (err) {
|
|
146
147
|
return reject(err);
|
|
147
148
|
}
|
|
148
149
|
|
|
149
|
-
return resolve(docs.filter(Boolean).map((doc) => formatBlocklet(doc, 'onRead', this.
|
|
150
|
+
return resolve(docs.filter(Boolean).map((doc) => formatBlocklet(doc, 'onRead', this.config.dek)));
|
|
150
151
|
});
|
|
151
152
|
});
|
|
152
153
|
}
|
|
@@ -160,13 +161,13 @@ class BlockletState extends BaseState {
|
|
|
160
161
|
return reject(new Error(`Try to remove non-existing blocklet ${did}`));
|
|
161
162
|
}
|
|
162
163
|
|
|
163
|
-
this.
|
|
164
|
+
this.remove({ _id: doc._id }, (err) => {
|
|
164
165
|
if (err) {
|
|
165
166
|
return reject(err);
|
|
166
167
|
}
|
|
167
168
|
|
|
168
169
|
this.emit('remove', doc);
|
|
169
|
-
return resolve(formatBlocklet(doc, 'onRead', this.
|
|
170
|
+
return resolve(formatBlocklet(doc, 'onRead', this.config.dek));
|
|
170
171
|
});
|
|
171
172
|
})
|
|
172
173
|
);
|
|
@@ -208,7 +209,7 @@ class BlockletState extends BaseState {
|
|
|
208
209
|
fixChildren(children);
|
|
209
210
|
|
|
210
211
|
// add to db
|
|
211
|
-
this.
|
|
212
|
+
this.insert(
|
|
212
213
|
{
|
|
213
214
|
appDid: null, // will updated later when updating blocklet environments
|
|
214
215
|
mode,
|
|
@@ -248,7 +249,7 @@ class BlockletState extends BaseState {
|
|
|
248
249
|
}
|
|
249
250
|
|
|
250
251
|
try {
|
|
251
|
-
const formatted = formatBlocklet(cloneDeep(updates), 'onUpdate', this.
|
|
252
|
+
const formatted = formatBlocklet(cloneDeep(updates), 'onUpdate', this.config.dek);
|
|
252
253
|
const newDoc = await this.updateById(doc._id, { $set: formatted });
|
|
253
254
|
resolve(newDoc);
|
|
254
255
|
} catch (err) {
|
|
@@ -455,7 +456,7 @@ class BlockletState extends BaseState {
|
|
|
455
456
|
|
|
456
457
|
const doc = await this.getBlocklet(did);
|
|
457
458
|
if (doc.status === status && !children) {
|
|
458
|
-
return formatBlocklet(doc, 'onRead', this.
|
|
459
|
+
return formatBlocklet(doc, 'onRead', this.config.dek);
|
|
459
460
|
}
|
|
460
461
|
|
|
461
462
|
const updates = { status, startedAt: undefined, stoppedAt: undefined };
|