@abtnode/core 1.15.17 → 1.16.0-beta-b16cb035
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/node.js +67 -69
- package/lib/api/team.js +386 -55
- package/lib/blocklet/downloader/blocklet-downloader.js +226 -0
- package/lib/blocklet/downloader/bundle-downloader.js +272 -0
- package/lib/blocklet/downloader/constants.js +3 -0
- package/lib/blocklet/downloader/resolve-download.js +199 -0
- package/lib/blocklet/extras.js +83 -26
- package/lib/blocklet/hooks.js +18 -65
- package/lib/blocklet/manager/base.js +10 -16
- package/lib/blocklet/manager/disk.js +1679 -1566
- package/lib/blocklet/manager/helper/install-application-from-backup.js +177 -0
- package/lib/blocklet/manager/helper/install-application-from-dev.js +94 -0
- package/lib/blocklet/manager/helper/install-application-from-general.js +188 -0
- package/lib/blocklet/manager/helper/install-component-from-dev.js +84 -0
- package/lib/blocklet/manager/helper/install-component-from-upload.js +181 -0
- package/lib/blocklet/manager/helper/install-component-from-url.js +173 -0
- package/lib/blocklet/manager/helper/migrate-application-to-struct-v2.js +450 -0
- package/lib/blocklet/manager/helper/rollback-cache.js +41 -0
- package/lib/blocklet/manager/helper/upgrade-components.js +152 -0
- package/lib/blocklet/migration.js +30 -52
- package/lib/blocklet/storage/backup/audit-log.js +27 -0
- package/lib/blocklet/storage/backup/base.js +62 -0
- package/lib/blocklet/storage/backup/blocklet-extras.js +92 -0
- package/lib/blocklet/storage/backup/blocklet.js +70 -0
- package/lib/blocklet/storage/backup/blocklets.js +74 -0
- package/lib/blocklet/storage/backup/data.js +19 -0
- package/lib/blocklet/storage/backup/logs.js +24 -0
- package/lib/blocklet/storage/backup/routing-rule.js +19 -0
- package/lib/blocklet/storage/backup/spaces.js +240 -0
- package/lib/blocklet/storage/restore/base.js +67 -0
- package/lib/blocklet/storage/restore/blocklet-extras.js +86 -0
- package/lib/blocklet/storage/restore/blocklet.js +56 -0
- package/lib/blocklet/storage/restore/blocklets.js +43 -0
- package/lib/blocklet/storage/restore/logs.js +21 -0
- package/lib/blocklet/storage/restore/spaces.js +156 -0
- package/lib/blocklet/storage/utils/hash.js +51 -0
- package/lib/blocklet/storage/utils/zip.js +43 -0
- package/lib/cert.js +206 -0
- package/lib/event.js +237 -64
- package/lib/index.js +191 -83
- package/lib/migrations/1.0.21-update-config.js +1 -1
- package/lib/migrations/1.0.22-max-memory.js +1 -1
- package/lib/migrations/1.0.25.js +1 -1
- package/lib/migrations/1.0.32-update-config.js +1 -1
- package/lib/migrations/1.0.33-blocklets.js +1 -1
- package/lib/migrations/1.5.20-registry.js +15 -0
- package/lib/migrations/1.6.17-blocklet-children.js +48 -0
- package/lib/migrations/1.6.21-rename-ip-echo-domain.js +35 -0
- package/lib/migrations/1.6.4-security.js +59 -0
- package/lib/migrations/1.6.5-security.js +60 -0
- package/lib/migrations/1.6.9-update-node-info-and-certificate.js +38 -0
- package/lib/migrations/1.7.1-blocklet-setup.js +18 -0
- package/lib/migrations/1.7.12-blocklet-meta.js +51 -0
- package/lib/migrations/1.7.15-blocklet-bundle-source.js +42 -0
- package/lib/migrations/1.7.20-blocklet-component.js +41 -0
- package/lib/migrations/1.8.33-blocklet-mem-limit.js +20 -0
- package/lib/migrations/README.md +1 -1
- package/lib/migrations/index.js +6 -2
- package/lib/monitor/blocklet-runtime-monitor.js +200 -0
- package/lib/monitor/get-history-list.js +37 -0
- package/lib/monitor/node-runtime-monitor.js +228 -0
- package/lib/router/helper.js +572 -497
- package/lib/router/index.js +85 -21
- package/lib/router/manager.js +146 -187
- package/lib/states/README.md +36 -1
- package/lib/states/access-key.js +39 -17
- package/lib/states/audit-log.js +462 -0
- package/lib/states/base.js +4 -213
- package/lib/states/blocklet-extras.js +194 -138
- package/lib/states/blocklet.js +361 -104
- package/lib/states/cache.js +8 -6
- package/lib/states/challenge.js +5 -5
- package/lib/states/index.js +19 -36
- package/lib/states/migration.js +4 -4
- package/lib/states/node.js +135 -46
- package/lib/states/notification.js +22 -35
- package/lib/states/session.js +17 -9
- package/lib/states/site.js +50 -25
- package/lib/states/user.js +74 -20
- package/lib/states/webhook.js +10 -6
- package/lib/team/manager.js +124 -7
- package/lib/util/blocklet.js +1223 -246
- package/lib/util/chain.js +1 -1
- package/lib/util/default-node-config.js +5 -23
- package/lib/util/disk-monitor.js +13 -10
- package/lib/util/domain-status.js +84 -15
- package/lib/util/get-accessible-external-node-ip.js +2 -2
- package/lib/util/get-domain-for-blocklet.js +13 -0
- package/lib/util/get-meta-from-url.js +33 -0
- package/lib/util/index.js +207 -272
- package/lib/util/ip.js +6 -0
- package/lib/util/maintain.js +233 -0
- package/lib/util/public-to-store.js +85 -0
- package/lib/util/ready.js +1 -1
- package/lib/util/requirement.js +28 -9
- package/lib/util/reset-node.js +22 -7
- package/lib/util/router.js +13 -0
- package/lib/util/rpc.js +16 -0
- package/lib/util/store.js +179 -0
- package/lib/util/sysinfo.js +44 -0
- package/lib/util/ua.js +54 -0
- package/lib/validators/blocklet-extra.js +24 -0
- package/lib/validators/node.js +25 -12
- package/lib/validators/permission.js +16 -1
- package/lib/validators/role.js +17 -3
- package/lib/validators/router.js +40 -20
- package/lib/validators/trusted-passport.js +1 -0
- package/lib/validators/util.js +22 -5
- package/lib/webhook/index.js +45 -35
- package/lib/webhook/sender/index.js +5 -0
- package/lib/webhook/sender/slack/index.js +1 -1
- package/lib/webhook/sender/wallet/index.js +48 -0
- package/package.json +54 -36
- package/lib/blocklet/registry.js +0 -205
- package/lib/states/https-cert.js +0 -67
- package/lib/util/get-ip-dns-domain-for-blocklet.js +0 -19
- package/lib/util/service.js +0 -66
- package/lib/util/upgrade.js +0 -178
- /package/lib/{queue.js → util/queue.js} +0 -0
package/lib/states/access-key.js
CHANGED
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
const get = require('lodash/get');
|
|
1
2
|
const { fromRandom } = require('@ocap/wallet');
|
|
2
3
|
const { toBase58 } = require('@ocap/util');
|
|
3
4
|
const logger = require('@abtnode/logger')('@abtnode/core:access-key');
|
|
@@ -15,20 +16,23 @@ const validatePassport = (passport) => {
|
|
|
15
16
|
}
|
|
16
17
|
};
|
|
17
18
|
|
|
18
|
-
|
|
19
|
-
constructor(baseDir, options = {}) {
|
|
20
|
-
super(baseDir, { filename: 'access_key.db', ...options });
|
|
19
|
+
const getUserName = (context) => get(context, 'user.fullName', '');
|
|
21
20
|
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
21
|
+
class AccessKeyState extends BaseState {
|
|
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
|
+
});
|
|
26
31
|
});
|
|
27
32
|
}
|
|
28
33
|
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
const { remark, passport } = input;
|
|
34
|
+
async create(input, context) {
|
|
35
|
+
const { remark, passport, tag } = input || {};
|
|
32
36
|
|
|
33
37
|
validateRemark(remark);
|
|
34
38
|
validatePassport(passport);
|
|
@@ -39,16 +43,33 @@ class AccessKeyState extends BaseState {
|
|
|
39
43
|
accessKeyPublic: wallet.publicKey,
|
|
40
44
|
passport,
|
|
41
45
|
};
|
|
46
|
+
|
|
42
47
|
if (remark) {
|
|
43
48
|
data.remark = remark;
|
|
44
49
|
}
|
|
45
|
-
|
|
50
|
+
|
|
51
|
+
if (tag) {
|
|
52
|
+
data.tag = tag;
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
data.createdBy = getUserName(context);
|
|
56
|
+
data.updatedBy = getUserName(context);
|
|
57
|
+
|
|
58
|
+
const doc = await this.insert(data);
|
|
46
59
|
return {
|
|
47
60
|
...doc,
|
|
48
61
|
accessKeySecret: toBase58(wallet.secretKey),
|
|
49
62
|
};
|
|
50
63
|
}
|
|
51
64
|
|
|
65
|
+
async getAccessKeyByTag({ tag } = {}) {
|
|
66
|
+
if (!tag) {
|
|
67
|
+
throw new Error('tag should not be empty');
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
return this.findOne({ tag });
|
|
71
|
+
}
|
|
72
|
+
|
|
52
73
|
// eslint-disable-next-line no-unused-vars
|
|
53
74
|
async list(params, context) {
|
|
54
75
|
const res = await this.paginate({}, { createdAt: -1 }, { pageSize: 100 });
|
|
@@ -61,7 +82,7 @@ class AccessKeyState extends BaseState {
|
|
|
61
82
|
if (!accessKeyId) {
|
|
62
83
|
throw new Error('accessKeyId should not be empty');
|
|
63
84
|
}
|
|
64
|
-
const doc = await this.
|
|
85
|
+
const doc = await this.findOne({ accessKeyId });
|
|
65
86
|
return doc;
|
|
66
87
|
}
|
|
67
88
|
|
|
@@ -76,7 +97,7 @@ class AccessKeyState extends BaseState {
|
|
|
76
97
|
if (!accessKeyId) {
|
|
77
98
|
throw new Error('accessKeyId should not be empty');
|
|
78
99
|
}
|
|
79
|
-
const doc = await this.
|
|
100
|
+
const doc = await this.findOne({ accessKeyId });
|
|
80
101
|
if (!doc) {
|
|
81
102
|
throw new Error(`Access Key Id ${accessKeyId} does not exist`);
|
|
82
103
|
}
|
|
@@ -84,8 +105,9 @@ class AccessKeyState extends BaseState {
|
|
|
84
105
|
doc.remark = remark;
|
|
85
106
|
}
|
|
86
107
|
doc.passport = passport;
|
|
108
|
+
doc.updatedBy = getUserName(context);
|
|
87
109
|
|
|
88
|
-
await
|
|
110
|
+
await super.update({ accessKeyId }, { $set: doc });
|
|
89
111
|
return doc;
|
|
90
112
|
}
|
|
91
113
|
|
|
@@ -94,12 +116,12 @@ class AccessKeyState extends BaseState {
|
|
|
94
116
|
if (!accessKeyId) {
|
|
95
117
|
throw new Error('accessKeyId should not be empty');
|
|
96
118
|
}
|
|
97
|
-
const doc = await this.
|
|
119
|
+
const doc = await this.findOne({ accessKeyId });
|
|
98
120
|
if (!doc) {
|
|
99
121
|
throw new Error(`Access Key Id ${accessKeyId} does not exist`);
|
|
100
122
|
}
|
|
101
123
|
doc.lastUsedAt = new Date();
|
|
102
|
-
await
|
|
124
|
+
await super.update({ accessKeyId }, { $set: doc });
|
|
103
125
|
return doc;
|
|
104
126
|
}
|
|
105
127
|
|
|
@@ -109,7 +131,7 @@ class AccessKeyState extends BaseState {
|
|
|
109
131
|
if (!accessKeyId) {
|
|
110
132
|
throw new Error('accessKeyId should not be empty');
|
|
111
133
|
}
|
|
112
|
-
const num = await
|
|
134
|
+
const num = await super.remove({ accessKeyId });
|
|
113
135
|
if (num <= 0) {
|
|
114
136
|
throw new Error(`Access Key Id ${accessKeyId} does not exist`);
|
|
115
137
|
}
|
|
@@ -0,0 +1,462 @@
|
|
|
1
|
+
/* eslint-disable no-async-promise-executor */
|
|
2
|
+
const pick = require('lodash/pick');
|
|
3
|
+
const get = require('lodash/get');
|
|
4
|
+
const joinUrl = require('url-join');
|
|
5
|
+
const { getDisplayName } = require('@blocklet/meta/lib/util');
|
|
6
|
+
const { BLOCKLET_SITE_GROUP_SUFFIX, NODE_SERVICES } = require('@abtnode/constant');
|
|
7
|
+
const logger = require('@abtnode/logger')('@abtnode/core:states:audit-log');
|
|
8
|
+
|
|
9
|
+
const BaseState = require('./base');
|
|
10
|
+
|
|
11
|
+
const { parse } = require('../util/ua');
|
|
12
|
+
|
|
13
|
+
const getServerInfo = (info) => `[${info.name}](${joinUrl(info.routing.adminPath, '/settings/about')})`;
|
|
14
|
+
const getBlockletInfo = (blocklet, info) => `[${getDisplayName(blocklet)} v${blocklet.meta.version}](${joinUrl(info.routing.adminPath, '/blocklets/', blocklet.meta.did, '/overview')})`; // prettier-ignore
|
|
15
|
+
const expandTeam = async (teamDid, info, node) => {
|
|
16
|
+
if (!teamDid) {
|
|
17
|
+
return '';
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
if (teamDid === info.did) {
|
|
21
|
+
return getServerInfo(info);
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
const { blocklet } = node.states;
|
|
25
|
+
const doc = await blocklet.getBlocklet(teamDid);
|
|
26
|
+
return doc ? getBlockletInfo(doc, info) : '';
|
|
27
|
+
};
|
|
28
|
+
const expandSite = async (siteId, info, node) => {
|
|
29
|
+
if (!siteId) {
|
|
30
|
+
return '';
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
const { blocklet, site } = node.states;
|
|
34
|
+
const doc = await site.findOne({ _id: siteId });
|
|
35
|
+
if (!doc) {
|
|
36
|
+
return '';
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
if (doc.domain === '*') {
|
|
40
|
+
return 'default site';
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
if (doc.domain === '') {
|
|
44
|
+
return getServerInfo(info);
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
if (doc.domain.endsWith(BLOCKLET_SITE_GROUP_SUFFIX)) {
|
|
48
|
+
const tmp = await blocklet.getBlocklet(doc.domain.replace(BLOCKLET_SITE_GROUP_SUFFIX, ''));
|
|
49
|
+
return tmp ? getBlockletInfo(tmp, info) : '';
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
return '';
|
|
53
|
+
};
|
|
54
|
+
const expandUser = async (teamDid, userDid, passportId, info, node) => {
|
|
55
|
+
if (!teamDid || !userDid) {
|
|
56
|
+
return ['', ''];
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
const user = await node.getUser({ teamDid, user: { did: userDid } });
|
|
60
|
+
if (!user) {
|
|
61
|
+
return ['', ''];
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
const passport = user.passports.find((x) => x.id === passportId);
|
|
65
|
+
|
|
66
|
+
if (teamDid === info.did) {
|
|
67
|
+
return [`[${user.fullName}](${joinUrl(info.routing.adminPath, '/team/members')})`, passport ? passport.name : ''];
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
return [`[${user.fullName}](${joinUrl(info.routing.adminPath, '/blocklets/', teamDid, '/members')})`, passport ? passport.name : '']; // prettier-ignore
|
|
71
|
+
};
|
|
72
|
+
|
|
73
|
+
/**
|
|
74
|
+
* Create log content in markdown format
|
|
75
|
+
*
|
|
76
|
+
* @param {string} action - GraphQL query/mutation name
|
|
77
|
+
* @param {object} args - GraphQL arguments
|
|
78
|
+
* @param {object} context - request context: user, ip, user-agent, etc.
|
|
79
|
+
* @param {object} result - GraphQL resolve result
|
|
80
|
+
* @param {object} info - server info
|
|
81
|
+
* @param {object} node - server instance
|
|
82
|
+
* @return {string} the generated markdown source
|
|
83
|
+
*/
|
|
84
|
+
const getLogContent = async (action, args, context, result, info, node) => {
|
|
85
|
+
const [team, site, [user, passport]] = await Promise.all([
|
|
86
|
+
expandTeam(args.teamDid, info, node),
|
|
87
|
+
expandSite(args.id, info, node),
|
|
88
|
+
expandUser(args.teamDid, args.userDid || get(args, 'user.did') || args.ownerDid, args.passportId, info, node),
|
|
89
|
+
]);
|
|
90
|
+
|
|
91
|
+
switch (action) {
|
|
92
|
+
// blocklets
|
|
93
|
+
case 'installBlocklet':
|
|
94
|
+
return `installed blocklet ${getBlockletInfo(result, info)} from ${result.deployedFrom}`;
|
|
95
|
+
case 'startBlocklet':
|
|
96
|
+
return `started blocklet ${getBlockletInfo(result, info)} ${args.reason || ''}`;
|
|
97
|
+
case 'restartBlocklet':
|
|
98
|
+
return `restarted blocklet ${getBlockletInfo(result, info)}`;
|
|
99
|
+
case 'reloadBlocklet':
|
|
100
|
+
return `reloaded blocklet ${getBlockletInfo(result, info)}`;
|
|
101
|
+
case 'stopBlocklet':
|
|
102
|
+
return `stopped blocklet ${getBlockletInfo(result, info)}`;
|
|
103
|
+
case 'resetBlocklet':
|
|
104
|
+
return `reset blocklet ${getBlockletInfo(result, info)} data and config`;
|
|
105
|
+
case 'deleteBlocklet':
|
|
106
|
+
return `removed blocklet ${getBlockletInfo(result, info)} ${args.keepData ? 'but kept its data and config' : 'and its data and config'}`; // prettier-ignore
|
|
107
|
+
case 'installComponent':
|
|
108
|
+
return `added component from ${args.file ? 'Upload' : args.url} at **${args.mountPoint}** to ${getBlockletInfo(result, info)}`; // prettier-ignore
|
|
109
|
+
case 'deleteComponent':
|
|
110
|
+
return `removed component ${args.did} from blocklet ${getBlockletInfo(result, info)}`;
|
|
111
|
+
case 'configBlocklet':
|
|
112
|
+
return `updated following config for blocklet ${getBlockletInfo(result, info)}:\n${args.configs.map(x => `- ${x.key}: ${x.value}\n`)}`; // prettier-ignore
|
|
113
|
+
case 'upgradeBlocklet':
|
|
114
|
+
if (result.resultStatus === 'failed') {
|
|
115
|
+
return `upgrade blocklet failed: ${getBlockletInfo(result, info)}`;
|
|
116
|
+
}
|
|
117
|
+
return `upgraded blocklet ${getBlockletInfo(result, info)} to v${result.meta.version}`;
|
|
118
|
+
case 'upgradeComponents':
|
|
119
|
+
return `upgraded components for blocklet ${getBlockletInfo(result, info)}`;
|
|
120
|
+
case 'configPublicToStore':
|
|
121
|
+
if (args.publicToStore) {
|
|
122
|
+
return `set publicToStore to true for blocklet ${getBlockletInfo(result, info)}`;
|
|
123
|
+
}
|
|
124
|
+
return `set publicToStore to false for blocklet ${getBlockletInfo(result, info)}`;
|
|
125
|
+
case 'configNavigations':
|
|
126
|
+
// eslint-disable-next-line prettier/prettier
|
|
127
|
+
return `updated following navigations for blocklet ${getBlockletInfo(result, info)}:\n${args.navigations.map(
|
|
128
|
+
(x) => `- ${x.title}: ${x.link}\n`
|
|
129
|
+
)}`;
|
|
130
|
+
case 'updateComponentTitle':
|
|
131
|
+
return `update component title to **${args.title}** for blocklet ${getBlockletInfo(result, info)}`;
|
|
132
|
+
case 'updateComponentMountPoint':
|
|
133
|
+
return `update component mount point to **${args.mountPoint}** for blocklet ${getBlockletInfo(result, info)}`;
|
|
134
|
+
// store
|
|
135
|
+
case 'addBlockletStore':
|
|
136
|
+
return `added blocklet store ${args.url}`;
|
|
137
|
+
case 'deleteBlockletStore':
|
|
138
|
+
return `removed blocklet store ${args.url}`;
|
|
139
|
+
case 'selectBlockletStore':
|
|
140
|
+
return `selected blocklet store ${args.url}`;
|
|
141
|
+
|
|
142
|
+
// teams: members/passports
|
|
143
|
+
case 'addUser':
|
|
144
|
+
if (args.passport) {
|
|
145
|
+
return `${args.reason} and received **${args.passport.name}** passport from ${team}`;
|
|
146
|
+
}
|
|
147
|
+
return `joined team ${team} by ${args.reason}`;
|
|
148
|
+
case 'updateUser':
|
|
149
|
+
return `${args.reason} and received **${args.passport.name}** passport from ${team}`;
|
|
150
|
+
case 'switchProfile':
|
|
151
|
+
return `switched profile to ${args.profile.fullName} for ${team}`;
|
|
152
|
+
case 'switchPassport':
|
|
153
|
+
return `switched passport to ${args.passport.name} for ${team}`;
|
|
154
|
+
case 'login':
|
|
155
|
+
return `${user} logged in to ${team} with passport ${args.passport.name}`;
|
|
156
|
+
case 'updateWhoCanAccess':
|
|
157
|
+
return `updated access control policy to **${args.whoCanAccess}**`;
|
|
158
|
+
case 'configPassportIssuance':
|
|
159
|
+
return `${args.enabled ? 'enabled' : 'disabled'} passport issuance for ${team}`;
|
|
160
|
+
case 'createPassportIssuance':
|
|
161
|
+
return `issued **${args.name}** passport to ${user} for ${team}, issuance id: ${result.id}`;
|
|
162
|
+
case 'processPassportIssuance':
|
|
163
|
+
return `claimed passport **${args.name}** from ${team}, issuance id: ${args.sessionId}`;
|
|
164
|
+
case 'revokeUserPassport':
|
|
165
|
+
return `revoked **${passport}** passport of user ${user} for ${team}`;
|
|
166
|
+
case 'enableUserPassport':
|
|
167
|
+
return `enabled **${passport}** passport of user ${user} for ${team}`;
|
|
168
|
+
case 'updateUserApproval':
|
|
169
|
+
return `${args.user.approved ? 'enabled' : 'disabled'} user ${user} for ${team}`;
|
|
170
|
+
case 'deletePassportIssuance':
|
|
171
|
+
return `removed passport issuance ${args.sessionId} from ${team}`;
|
|
172
|
+
case 'createMemberInvitation':
|
|
173
|
+
return `created member invitation(${result.inviteId}: ${args.remark}) with **${args.role}** passport for ${team}`; // prettier-ignore
|
|
174
|
+
case 'deleteInvitation':
|
|
175
|
+
return `removed unused member invitation(${args.inviteId}) from ${team}`;
|
|
176
|
+
case 'createRole':
|
|
177
|
+
return `created passport ${args.name}(${args.title}) for ${team}`;
|
|
178
|
+
case 'updateRole':
|
|
179
|
+
return `updated passport ${args.role.name}(${args.role.title}) for ${team}`;
|
|
180
|
+
case 'updatePermissionsForRole':
|
|
181
|
+
return `granted following permissions to passport ${args.roleName} for ${team}: \n${args.grantNames.map(x => `- ${x}`).join('\n')}`; // prettier-ignore
|
|
182
|
+
case 'configTrustedPassports':
|
|
183
|
+
if (args.trustedPassports.length === 0) {
|
|
184
|
+
return `removed all trusted passport issuers for ${team}`;
|
|
185
|
+
}
|
|
186
|
+
return `updated trusted passport issuers to following for ${team}: \n${args.trustedPassports.map(x => `- ${x.remark}: ${x.issuerDid}`).join('\n')}`; // prettier-ignore
|
|
187
|
+
case 'delegateTransferNFT':
|
|
188
|
+
return `${args.owner} ${args.reason}`;
|
|
189
|
+
case 'issuePassportToUser':
|
|
190
|
+
return `issued **${args.role}** passport to ${user}`;
|
|
191
|
+
|
|
192
|
+
// accessKeys
|
|
193
|
+
case 'createAccessKey':
|
|
194
|
+
return `created access key ${result.accessKeyId} with passport ${args.passport}: ${args.remark}`;
|
|
195
|
+
case 'updateAccessKey':
|
|
196
|
+
return `updated access key ${result.accessKeyId} with following changes:\n - passport: ${args.passport}\n - remark: ${args.remark}`; // prettier-ignore
|
|
197
|
+
case 'deleteAccessKey':
|
|
198
|
+
return `deleted access key ${args.accessKeyId}`; // prettier-ignore
|
|
199
|
+
|
|
200
|
+
// integrations
|
|
201
|
+
case 'createWebHook':
|
|
202
|
+
return `added integration ${result._id}: \n- type: ${args.type}\n${args.params.map(x => `- ${x.name}: ${x.value}`).join('\n')}`; // prettier-ignore
|
|
203
|
+
case 'deleteWebHook':
|
|
204
|
+
return `deleted integration ${args.id}`;
|
|
205
|
+
|
|
206
|
+
// server
|
|
207
|
+
case 'updateNodeInfo':
|
|
208
|
+
return `updated basic server settings: \n${Object.keys(args).map(x => `- ${x}: ${args[x]}`).join('\n')}`; // prettier-ignore
|
|
209
|
+
case 'upgradeNodeVersion':
|
|
210
|
+
return `upgrade server to ${info.nextVersion}`;
|
|
211
|
+
case 'restartServer':
|
|
212
|
+
return 'server was restarted';
|
|
213
|
+
case 'startServer':
|
|
214
|
+
return 'server was started';
|
|
215
|
+
case 'stopServer':
|
|
216
|
+
return 'server was stopped';
|
|
217
|
+
|
|
218
|
+
// certificates
|
|
219
|
+
case 'addCertificate':
|
|
220
|
+
return `added certificate #${args.id}, domain ${result.domain}`;
|
|
221
|
+
case 'deleteCertificate':
|
|
222
|
+
return `deleted certificate #${args.id}`;
|
|
223
|
+
case 'updateCertificate':
|
|
224
|
+
return `updated certificate #${args.id}`;
|
|
225
|
+
case 'issueLetsEncryptCert':
|
|
226
|
+
return `tried to issue lets encrypt certificate for domain **${args.domain}**, ticket: ${result._id}`;
|
|
227
|
+
|
|
228
|
+
// router
|
|
229
|
+
case 'addDomainAlias':
|
|
230
|
+
return `added extra domain **${args.domainAlias}** to ${site}`; // prettier-ignore
|
|
231
|
+
case 'deleteDomainAlias':
|
|
232
|
+
return `removed extra domain **${args.domainAlias}** from ${site}`; // prettier-ignore
|
|
233
|
+
case 'updateRoutingSite':
|
|
234
|
+
return `updated site from ${site}`; // prettier-ignore
|
|
235
|
+
case 'addRoutingRule':
|
|
236
|
+
return `added routing rule **${args.rule?.from?.pathPrefix}** from ${site}`; // prettier-ignore
|
|
237
|
+
case 'updateRoutingRule':
|
|
238
|
+
return `updated routing rule **${args.rule?.from?.pathPrefix}** from ${site}`; // prettier-ignore
|
|
239
|
+
case 'deleteRoutingRule':
|
|
240
|
+
return `deleted routing rule from ${site}`; // prettier-ignore
|
|
241
|
+
case 'updateGateway': {
|
|
242
|
+
const changes = [
|
|
243
|
+
args.requestLimit.enabled ? `rate limit: enabled, rate: ${args.requestLimit.rate}` : 'rate limit: disabled',
|
|
244
|
+
args.cacheEnabled ? `global cache: enabled, rate: ${args.cacheEnabled}` : 'global cache: disabled',
|
|
245
|
+
];
|
|
246
|
+
const message = `update gateway: ${changes.join('; ')}`;
|
|
247
|
+
return message;
|
|
248
|
+
}
|
|
249
|
+
case 'createTransferInvitation':
|
|
250
|
+
return `created a transfer node invitation(${result.inviteId})`;
|
|
251
|
+
|
|
252
|
+
default:
|
|
253
|
+
return action;
|
|
254
|
+
}
|
|
255
|
+
};
|
|
256
|
+
|
|
257
|
+
const getLogCategory = (action) => {
|
|
258
|
+
switch (action) {
|
|
259
|
+
// blocklets
|
|
260
|
+
case 'installBlocklet':
|
|
261
|
+
case 'installComponent':
|
|
262
|
+
case 'startBlocklet':
|
|
263
|
+
case 'restartBlocklet':
|
|
264
|
+
case 'reloadBlocklet':
|
|
265
|
+
case 'stopBlocklet':
|
|
266
|
+
case 'resetBlocklet':
|
|
267
|
+
case 'deleteBlocklet':
|
|
268
|
+
case 'deleteComponent':
|
|
269
|
+
case 'configBlocklet':
|
|
270
|
+
case 'upgradeBlocklet':
|
|
271
|
+
case 'upgradeComponents':
|
|
272
|
+
case 'configPublicToStore':
|
|
273
|
+
case 'configNavigations':
|
|
274
|
+
case 'updateComponentTitle':
|
|
275
|
+
case 'updateComponentMountPoint':
|
|
276
|
+
return 'blocklet';
|
|
277
|
+
|
|
278
|
+
// store
|
|
279
|
+
case 'addBlockletStore':
|
|
280
|
+
case 'deleteBlockletStore':
|
|
281
|
+
case 'selectBlockletStore':
|
|
282
|
+
return 'server';
|
|
283
|
+
|
|
284
|
+
// teams: members/passports
|
|
285
|
+
case 'addUser':
|
|
286
|
+
case 'updateUser':
|
|
287
|
+
case 'switchProfile':
|
|
288
|
+
case 'switchPassport':
|
|
289
|
+
case 'login':
|
|
290
|
+
case 'configWhoCanAccess':
|
|
291
|
+
case 'processPassportIssuance':
|
|
292
|
+
case 'configPassportIssuance':
|
|
293
|
+
case 'createPassportIssuance':
|
|
294
|
+
case 'deletePassportIssuance':
|
|
295
|
+
case 'revokeUserPassport':
|
|
296
|
+
case 'enableUserPassport':
|
|
297
|
+
case 'updateUserApproval':
|
|
298
|
+
case 'createMemberInvitation':
|
|
299
|
+
case 'deleteInvitation':
|
|
300
|
+
case 'createRole':
|
|
301
|
+
case 'updateRole':
|
|
302
|
+
case 'updatePermissionsForRole':
|
|
303
|
+
case 'configTrustedPassports':
|
|
304
|
+
case 'delegateTransferNFT':
|
|
305
|
+
case 'createTransferInvitation':
|
|
306
|
+
return 'team';
|
|
307
|
+
|
|
308
|
+
// accessKeys
|
|
309
|
+
case 'createAccessKey':
|
|
310
|
+
case 'updateAccessKey':
|
|
311
|
+
case 'deleteAccessKey':
|
|
312
|
+
return 'security';
|
|
313
|
+
|
|
314
|
+
// integrations
|
|
315
|
+
case 'createWebHook':
|
|
316
|
+
case 'deleteWebHook':
|
|
317
|
+
return 'integrations';
|
|
318
|
+
|
|
319
|
+
// server
|
|
320
|
+
case 'updateNodeInfo':
|
|
321
|
+
case 'upgradeNodeVersion':
|
|
322
|
+
case 'startServer':
|
|
323
|
+
case 'stopServer':
|
|
324
|
+
return 'server';
|
|
325
|
+
|
|
326
|
+
// certificates
|
|
327
|
+
case 'addCertificate':
|
|
328
|
+
case 'deleteCertificate':
|
|
329
|
+
case 'updateCertificate':
|
|
330
|
+
case 'issueLetsEncryptCert':
|
|
331
|
+
return 'certificates';
|
|
332
|
+
|
|
333
|
+
case 'updateGateway':
|
|
334
|
+
return 'gateway';
|
|
335
|
+
|
|
336
|
+
default:
|
|
337
|
+
return '';
|
|
338
|
+
}
|
|
339
|
+
};
|
|
340
|
+
|
|
341
|
+
const getScope = (args = {}) => {
|
|
342
|
+
// this param usually means mutating an application (server or blocklet)
|
|
343
|
+
if (args.teamDid) {
|
|
344
|
+
return args.teamDid;
|
|
345
|
+
}
|
|
346
|
+
|
|
347
|
+
// this param usually means mutating a child component
|
|
348
|
+
if (args.rootDid) {
|
|
349
|
+
return args.rootDid;
|
|
350
|
+
}
|
|
351
|
+
|
|
352
|
+
// this param usually means mutating an blockle application
|
|
353
|
+
if (args.did) {
|
|
354
|
+
// this param usually means mutating a nested child component
|
|
355
|
+
if (Array.isArray(args.did)) {
|
|
356
|
+
return args.did[0];
|
|
357
|
+
}
|
|
358
|
+
|
|
359
|
+
return args.did;
|
|
360
|
+
}
|
|
361
|
+
|
|
362
|
+
return null;
|
|
363
|
+
};
|
|
364
|
+
|
|
365
|
+
const fixActor = (actor) => {
|
|
366
|
+
if ([NODE_SERVICES.AUTH_SERVICE, 'blocklet'].includes(actor?.role)) {
|
|
367
|
+
actor.role = '';
|
|
368
|
+
}
|
|
369
|
+
};
|
|
370
|
+
|
|
371
|
+
class AuditLogState extends BaseState {
|
|
372
|
+
constructor(baseDir, config = {}) {
|
|
373
|
+
super(baseDir, { filename: 'audit-log.db', ...config });
|
|
374
|
+
}
|
|
375
|
+
|
|
376
|
+
/**
|
|
377
|
+
* Create new audit log
|
|
378
|
+
*
|
|
379
|
+
* @param {string} action the api name
|
|
380
|
+
* @param {object} args the api args
|
|
381
|
+
* @param {object} result the api result
|
|
382
|
+
* @param {object} context the log context
|
|
383
|
+
* {
|
|
384
|
+
protocol: 'http',
|
|
385
|
+
user: {
|
|
386
|
+
meta: 'profile',
|
|
387
|
+
fullName: 'wangshijun',
|
|
388
|
+
email: 'shijun@arcblock.io',
|
|
389
|
+
type: 'profile',
|
|
390
|
+
did: 'z1jq5bGF64wnZiy29EbRyuQqUxmRHmSdt1Q',
|
|
391
|
+
pk: 'zHTcKwgi9DK8US8QQY9K7wQ3qF79CtrWYn6BYAgTQUeVQ',
|
|
392
|
+
passports: [ [Object] ],
|
|
393
|
+
approved: true,
|
|
394
|
+
locale: 'en',
|
|
395
|
+
firstLoginAt: '2022-04-27T22:55:51.788Z',
|
|
396
|
+
lastLoginAt: '2022-04-27T22:55:51.788Z',
|
|
397
|
+
_id: 'dvOIJJVUJHGxnWBU',
|
|
398
|
+
createdAt: '2022-04-27T22:55:51.789Z',
|
|
399
|
+
updatedAt: '2022-04-27T22:55:51.789Z',
|
|
400
|
+
role: 'owner',
|
|
401
|
+
passportId: 'z2iTzSDhwGQFtYXeya8kqCyXro1tRkwUuwN6K'
|
|
402
|
+
},
|
|
403
|
+
url: '/api/gql?locale=en',
|
|
404
|
+
query: { locale: 'en' },
|
|
405
|
+
hostname: '192.168.123.236',
|
|
406
|
+
port: 0,
|
|
407
|
+
ip: '127.0.0.1'
|
|
408
|
+
}
|
|
409
|
+
* @return {object} new doc
|
|
410
|
+
*/
|
|
411
|
+
create({ action, args = {}, context = {}, result = {} }, node) {
|
|
412
|
+
return new Promise(async (resolve) => {
|
|
413
|
+
// Do not store secure configs in audit log
|
|
414
|
+
if (Array.isArray(args.configs)) {
|
|
415
|
+
args.configs.forEach((x) => {
|
|
416
|
+
if (x.secure) {
|
|
417
|
+
x.value = '******';
|
|
418
|
+
}
|
|
419
|
+
});
|
|
420
|
+
}
|
|
421
|
+
|
|
422
|
+
try {
|
|
423
|
+
const { ip, ua, user = {} } = context;
|
|
424
|
+
const [info, uaInfo] = await Promise.all([node.states.node.read(), parse(ua)]);
|
|
425
|
+
|
|
426
|
+
fixActor(user);
|
|
427
|
+
|
|
428
|
+
const data = await this.insert({
|
|
429
|
+
scope: getScope(args) || info.did, // server or blocklet did
|
|
430
|
+
action,
|
|
431
|
+
category: await getLogCategory(action, args, context, result, info, node),
|
|
432
|
+
content: (await getLogContent(action, args, context, result, info, node)).trim(),
|
|
433
|
+
actor: pick(user.actual || user, ['did', 'fullName', 'role']),
|
|
434
|
+
extra: args,
|
|
435
|
+
env: pick(uaInfo, ['browser', 'os', 'device']),
|
|
436
|
+
ip,
|
|
437
|
+
ua,
|
|
438
|
+
});
|
|
439
|
+
|
|
440
|
+
logger.info('create', data);
|
|
441
|
+
return resolve(data);
|
|
442
|
+
} catch (err) {
|
|
443
|
+
logger.error('create error', { error: err, action, args, context });
|
|
444
|
+
return resolve(null);
|
|
445
|
+
}
|
|
446
|
+
});
|
|
447
|
+
}
|
|
448
|
+
|
|
449
|
+
async findPaginated({ scope, category, paging } = {}) {
|
|
450
|
+
const conditions = {};
|
|
451
|
+
if (scope) {
|
|
452
|
+
conditions.scope = scope;
|
|
453
|
+
}
|
|
454
|
+
if (category) {
|
|
455
|
+
conditions.category = category;
|
|
456
|
+
}
|
|
457
|
+
|
|
458
|
+
return super.paginate(conditions, { createdAt: -1 }, { pageSize: 20, ...paging });
|
|
459
|
+
}
|
|
460
|
+
}
|
|
461
|
+
|
|
462
|
+
module.exports = AuditLogState;
|