@abtnode/core 1.15.17 → 1.16.0-beta-8ee536d7
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 +1680 -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 +576 -500
- 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 +195 -138
- package/lib/states/blocklet.js +371 -110
- 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/util/index.js
CHANGED
|
@@ -6,40 +6,33 @@ const unzipper = require('unzipper');
|
|
|
6
6
|
const crypto = require('crypto');
|
|
7
7
|
const shell = require('shelljs');
|
|
8
8
|
const get = require('lodash/get');
|
|
9
|
-
const uniqBy = require('lodash/uniqBy');
|
|
10
9
|
const pickBy = require('lodash/pickBy');
|
|
11
10
|
const { isFromPublicKey } = require('@arcblock/did');
|
|
12
11
|
const joinUrl = require('url-join');
|
|
13
12
|
const { Certificate } = require('@fidm/x509');
|
|
14
13
|
const getPortLib = require('get-port');
|
|
15
|
-
const isIp = require('is-ip');
|
|
16
14
|
const v8 = require('v8');
|
|
17
15
|
const normalizePathPrefix = require('@abtnode/util/lib/normalize-path-prefix');
|
|
16
|
+
const axios = require('@abtnode/util/lib/axios');
|
|
17
|
+
const { encode: encodeBase32 } = require('@abtnode/util/lib/base32');
|
|
18
18
|
const parseBlockletMeta = require('@blocklet/meta/lib/parse');
|
|
19
|
-
const {
|
|
20
|
-
const {
|
|
19
|
+
const { BlockletStatus } = require('@blocklet/constant');
|
|
20
|
+
const { replaceSlotToIp } = require('@blocklet/meta/lib/util');
|
|
21
21
|
const {
|
|
22
22
|
StatusCode,
|
|
23
|
-
ROUTER_PROVIDER_NONE,
|
|
24
23
|
DOMAIN_FOR_DEFAULT_SITE,
|
|
25
24
|
DOMAIN_FOR_IP_SITE,
|
|
26
25
|
DOMAIN_FOR_IP_SITE_REGEXP,
|
|
27
26
|
DEFAULT_HTTP_PORT,
|
|
28
27
|
DEFAULT_HTTPS_PORT,
|
|
29
|
-
ROUTING_RULE_TYPES,
|
|
30
28
|
SLOT_FOR_IP_DNS_SITE,
|
|
31
|
-
|
|
32
|
-
BLOCKLET_SITE_GROUP_SUFFIX,
|
|
29
|
+
NODE_MODES,
|
|
33
30
|
} = require('@abtnode/constant');
|
|
34
|
-
const { BLOCKLET_INTERFACE_TYPE_WEB } = require('@blocklet/meta/lib/constants');
|
|
35
31
|
|
|
36
32
|
const DEFAULT_WELLKNOWN_PORT = 8088;
|
|
37
33
|
|
|
38
34
|
const logger = require('@abtnode/logger')('@abtnode/core:util');
|
|
39
35
|
|
|
40
|
-
const { getServices, getServicesFromBlockletInterface } = require('./service');
|
|
41
|
-
const request = require('./request');
|
|
42
|
-
|
|
43
36
|
const validateOwner = (owner) => {
|
|
44
37
|
try {
|
|
45
38
|
return owner && owner.did && owner.pk && isFromPublicKey(owner.did, owner.pk);
|
|
@@ -54,27 +47,21 @@ const fromStatus = (v) => {
|
|
|
54
47
|
return match ? match[0] : 'unknown';
|
|
55
48
|
};
|
|
56
49
|
|
|
57
|
-
const
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
if (version) {
|
|
70
|
-
params.set('__bv__', version);
|
|
50
|
+
const replaceDomainSlot = ({ domain, context = {}, nodeIp }) => {
|
|
51
|
+
let processed = domain;
|
|
52
|
+
if (processed.includes(SLOT_FOR_IP_DNS_SITE)) {
|
|
53
|
+
const ipRegex = /\d+[-.]\d+[-.]\d+[-.]\d+/;
|
|
54
|
+
const match = ipRegex.exec(context.hostname);
|
|
55
|
+
if (match) {
|
|
56
|
+
const ip = match[0];
|
|
57
|
+
processed = replaceSlotToIp(processed, ip);
|
|
58
|
+
} else if (nodeIp) {
|
|
59
|
+
processed = replaceSlotToIp(processed, nodeIp);
|
|
60
|
+
}
|
|
71
61
|
}
|
|
72
|
-
|
|
73
|
-
return parsed.href;
|
|
62
|
+
return processed;
|
|
74
63
|
};
|
|
75
64
|
|
|
76
|
-
const trimSlash = (str = '') => str.replace(/^\/+/, '').replace(/\/+$/, '');
|
|
77
|
-
|
|
78
65
|
const getBlockletHost = ({ domain, context, nodeIp }) => {
|
|
79
66
|
const { protocol, port } = context || {};
|
|
80
67
|
|
|
@@ -87,16 +74,7 @@ const getBlockletHost = ({ domain, context, nodeIp }) => {
|
|
|
87
74
|
tmpDomain = context.hostname || '';
|
|
88
75
|
}
|
|
89
76
|
|
|
90
|
-
|
|
91
|
-
const ipRegex = /\d+[-.]\d+[-.]\d+[-.]\d+/;
|
|
92
|
-
const match = ipRegex.exec(context.hostname);
|
|
93
|
-
if (match) {
|
|
94
|
-
const ip = match[0].replace(/\./g, '-');
|
|
95
|
-
tmpDomain = tmpDomain.replace(SLOT_FOR_IP_DNS_SITE, ip);
|
|
96
|
-
} else if (nodeIp) {
|
|
97
|
-
tmpDomain = tmpDomain.replace(SLOT_FOR_IP_DNS_SITE, nodeIp.replace(/\./g, '-'));
|
|
98
|
-
}
|
|
99
|
-
}
|
|
77
|
+
tmpDomain = replaceDomainSlot({ domain: tmpDomain, context, nodeIp });
|
|
100
78
|
|
|
101
79
|
if (!port) {
|
|
102
80
|
return tmpDomain;
|
|
@@ -113,136 +91,7 @@ const getBlockletHost = ({ domain, context, nodeIp }) => {
|
|
|
113
91
|
return `${tmpDomain}:${port}`;
|
|
114
92
|
};
|
|
115
93
|
|
|
116
|
-
|
|
117
|
-
* Get config of auth service of blocklet component specified the routing rule
|
|
118
|
-
* @param {*} rule routing rule
|
|
119
|
-
* @param {*} blocklet
|
|
120
|
-
* @returns
|
|
121
|
-
*/
|
|
122
|
-
const getAuthConfig = (rule, blocklet) => {
|
|
123
|
-
if (!blocklet || !rule || rule.to.type !== ROUTING_RULE_TYPES.BLOCKLET || rule.to.did !== blocklet.meta.did) {
|
|
124
|
-
return null;
|
|
125
|
-
}
|
|
126
|
-
|
|
127
|
-
// find blocklet component
|
|
128
|
-
const isRootRule = rule.to.did === rule.to.realDid;
|
|
129
|
-
let _blocklet;
|
|
130
|
-
if (isRootRule) {
|
|
131
|
-
_blocklet = blocklet;
|
|
132
|
-
} else {
|
|
133
|
-
_blocklet = (blocklet.children || []).find((x) => x.meta.did === rule.to.realDid);
|
|
134
|
-
}
|
|
135
|
-
if (!_blocklet) {
|
|
136
|
-
return null;
|
|
137
|
-
}
|
|
138
|
-
|
|
139
|
-
// find interface in meta
|
|
140
|
-
const interfaceName = rule.to.realInterfaceName;
|
|
141
|
-
const { interfaces } = _blocklet.meta;
|
|
142
|
-
const _interface = interfaces.find((x) => x.type === BLOCKLET_INTERFACE_TYPE_WEB && x.name === interfaceName);
|
|
143
|
-
|
|
144
|
-
if (!_interface) {
|
|
145
|
-
return null;
|
|
146
|
-
}
|
|
147
|
-
|
|
148
|
-
// find auth service
|
|
149
|
-
const auth = getServicesFromBlockletInterface(_interface, { stringifyConfig: false }).find(
|
|
150
|
-
(x) => x.name === '@abtnode/auth-service'
|
|
151
|
-
);
|
|
152
|
-
|
|
153
|
-
if (!auth) {
|
|
154
|
-
return null;
|
|
155
|
-
}
|
|
156
|
-
|
|
157
|
-
return auth.config;
|
|
158
|
-
};
|
|
159
|
-
|
|
160
|
-
const getBlockletBaseUrls = ({ routingEnabled = false, port, rules = [], context = {}, blocklet, nodeIp }) => {
|
|
161
|
-
let baseUrls = [];
|
|
162
|
-
|
|
163
|
-
if (routingEnabled && Array.isArray(rules) && rules.length > 0) {
|
|
164
|
-
baseUrls = rules
|
|
165
|
-
.filter((rule) => !(rule.from.domain || '').endsWith(BLOCKLET_SITE_GROUP_SUFFIX))
|
|
166
|
-
.map((rule) => {
|
|
167
|
-
const host = getBlockletHost({ domain: rule.from.domain, context, nodeIp });
|
|
168
|
-
if (host) {
|
|
169
|
-
let protocol = 'http'; // TODO: 这里固定为 http, 因为判断 url 是不是 https 和证书相关,这里实现的话比较复杂
|
|
170
|
-
if (host.includes(DEFAULT_IP_DNS_DOMAIN_SUFFIX)) {
|
|
171
|
-
protocol = 'https';
|
|
172
|
-
}
|
|
173
|
-
|
|
174
|
-
return {
|
|
175
|
-
ruleId: rule.id,
|
|
176
|
-
baseUrl: `${protocol}://${host}/${trimSlash(rule.from.pathPrefix)}`,
|
|
177
|
-
interfaceName: get(rule, 'to.interfaceName', ''),
|
|
178
|
-
authConfig: getAuthConfig(rule, blocklet),
|
|
179
|
-
};
|
|
180
|
-
}
|
|
181
|
-
|
|
182
|
-
return null;
|
|
183
|
-
})
|
|
184
|
-
.filter(Boolean);
|
|
185
|
-
}
|
|
186
|
-
|
|
187
|
-
if (!baseUrls.length && isIp(context.hostname)) {
|
|
188
|
-
baseUrls = [{ baseUrl: `http://${context.hostname}:${port}` }];
|
|
189
|
-
}
|
|
190
|
-
|
|
191
|
-
return baseUrls;
|
|
192
|
-
};
|
|
193
|
-
|
|
194
|
-
const getBlockletInterfaces = ({ blocklet, context, nodeInfo, routingRules, nodeIp }) => {
|
|
195
|
-
const interfaces = [];
|
|
196
|
-
(blocklet.meta.interfaces || []).forEach((x) => {
|
|
197
|
-
if (x.port && x.port.external) {
|
|
198
|
-
// If an interface was exposed through external port, path is not appended
|
|
199
|
-
const baseUrls = getBlockletBaseUrls({
|
|
200
|
-
routingEnabled: false,
|
|
201
|
-
port: x.port.external,
|
|
202
|
-
rules: [],
|
|
203
|
-
context,
|
|
204
|
-
});
|
|
205
|
-
baseUrls.forEach(({ baseUrl }) => interfaces.push({ type: x.type, name: x.name, url: baseUrl }));
|
|
206
|
-
} else {
|
|
207
|
-
// Otherwise, the url is composed with routing rules
|
|
208
|
-
const port = x.port && x.port.internal ? blocklet.ports[x.port.internal] : blocklet.ports[x.port];
|
|
209
|
-
const baseUrls = getBlockletBaseUrls({
|
|
210
|
-
routingEnabled: isRoutingEnabled(nodeInfo.routing),
|
|
211
|
-
port,
|
|
212
|
-
rules: (routingRules || []).filter((r) => {
|
|
213
|
-
return (
|
|
214
|
-
// don't show wellknown interface
|
|
215
|
-
r.to.type !== ROUTING_RULE_TYPES.GENERAL_PROXY &&
|
|
216
|
-
// LEGACY don't show wellknown interface
|
|
217
|
-
r.to.interfaceName !== BLOCKLET_INTERFACE_WELLKNOWN &&
|
|
218
|
-
// don't show child blocklet interface
|
|
219
|
-
(!r.from.groupPathPrefix || r.from.pathPrefix === r.from.groupPathPrefix)
|
|
220
|
-
);
|
|
221
|
-
}),
|
|
222
|
-
context,
|
|
223
|
-
blocklet,
|
|
224
|
-
nodeIp,
|
|
225
|
-
});
|
|
226
|
-
|
|
227
|
-
baseUrls.forEach(({ baseUrl, ruleId, interfaceName, authConfig }) => {
|
|
228
|
-
if (interfaceName && interfaceName !== x.name) {
|
|
229
|
-
return;
|
|
230
|
-
}
|
|
231
|
-
interfaces.push({
|
|
232
|
-
ruleId,
|
|
233
|
-
type: x.type,
|
|
234
|
-
name: x.name,
|
|
235
|
-
url: getInterfaceUrl({ baseUrl, url: '/', version: blocklet.meta.version }),
|
|
236
|
-
authConfig,
|
|
237
|
-
});
|
|
238
|
-
});
|
|
239
|
-
}
|
|
240
|
-
});
|
|
241
|
-
|
|
242
|
-
return uniqBy(interfaces, 'url');
|
|
243
|
-
};
|
|
244
|
-
|
|
245
|
-
const isRoutingEnabled = (routing) => !!routing && !!routing.provider && routing.provider !== ROUTER_PROVIDER_NONE;
|
|
94
|
+
const isRoutingEnabled = (routing) => !!routing && !!routing.provider;
|
|
246
95
|
|
|
247
96
|
const isInProgress = (status) =>
|
|
248
97
|
[
|
|
@@ -283,7 +132,7 @@ const asyncExec = (command, options) =>
|
|
|
283
132
|
});
|
|
284
133
|
});
|
|
285
134
|
|
|
286
|
-
const getProviderFromNodeInfo = (
|
|
135
|
+
const getProviderFromNodeInfo = (info) => get(info, 'routing.provider', 'default');
|
|
287
136
|
|
|
288
137
|
const isCLI = () => !process.env.ABT_NODE_SK;
|
|
289
138
|
|
|
@@ -315,7 +164,6 @@ const getHttpsCertInfo = (certificate) => {
|
|
|
315
164
|
validFrom,
|
|
316
165
|
validTo,
|
|
317
166
|
issuer,
|
|
318
|
-
serialNumber: info.serialNumber,
|
|
319
167
|
sans: info.dnsNames,
|
|
320
168
|
validityPeriod: info.validTo - info.validFrom,
|
|
321
169
|
fingerprintAlg: 'SHA256',
|
|
@@ -332,6 +180,8 @@ const getDataDirs = (dataDir) => ({
|
|
|
332
180
|
tmp: path.join(dataDir, 'tmp'),
|
|
333
181
|
blocklets: path.join(dataDir, 'blocklets'),
|
|
334
182
|
services: path.join(dataDir, 'services'),
|
|
183
|
+
modules: path.join(dataDir, 'modules'),
|
|
184
|
+
certManagerModule: path.join(dataDir, 'modules', 'certificate-manager'),
|
|
335
185
|
});
|
|
336
186
|
|
|
337
187
|
// Ensure data dir for Blocklet Server exists
|
|
@@ -356,39 +206,52 @@ const formatEnvironments = (environments) => Object.keys(environments).map((x) =
|
|
|
356
206
|
const transformIPToDomain = (ip) => ip.split('.').join('-');
|
|
357
207
|
|
|
358
208
|
const getBaseUrls = async (node, ips) => {
|
|
359
|
-
const ipTypes = {
|
|
360
|
-
internal: 'private',
|
|
361
|
-
external: 'public',
|
|
362
|
-
};
|
|
363
209
|
const info = await node.getNodeInfo();
|
|
364
210
|
const { https, httpPort, httpsPort } = info.routing;
|
|
365
|
-
const ipKeys = Object.keys(ips).filter((x) => ips[x]);
|
|
366
211
|
const getPort = (port, defaultPort) => (port && port !== defaultPort ? `:${port}` : '');
|
|
212
|
+
const availableIps = ips.filter(Boolean);
|
|
367
213
|
|
|
368
|
-
|
|
369
|
-
const
|
|
214
|
+
const getHttpInfo = async (domain) => {
|
|
215
|
+
const certificate = https ? await node.certManager.getNormalByDomain(domain) : null;
|
|
216
|
+
const protocol = certificate ? 'https' : 'http';
|
|
217
|
+
const port = certificate ? getPort(httpsPort, DEFAULT_HTTPS_PORT) : getPort(httpPort, DEFAULT_HTTP_PORT);
|
|
370
218
|
|
|
371
|
-
|
|
219
|
+
return { protocol, port };
|
|
220
|
+
};
|
|
221
|
+
|
|
222
|
+
if (info.routing.provider && info.routing.snapshotHash && info.routing.adminPath) {
|
|
223
|
+
const sites = await node.getSitesFromSnapshot();
|
|
224
|
+
const { ipWildcardDomain } = info.routing;
|
|
372
225
|
const adminPath = normalizePathPrefix(info.routing.adminPath);
|
|
373
|
-
const
|
|
374
|
-
|
|
226
|
+
const tmpHttpPort = getPort(httpPort, DEFAULT_HTTP_PORT);
|
|
227
|
+
|
|
228
|
+
const httpUrls = availableIps.map((ip) => {
|
|
375
229
|
return {
|
|
376
|
-
url: `http://${
|
|
377
|
-
type: ipTypes[x],
|
|
230
|
+
url: `http://${ip}${tmpHttpPort}${adminPath}`,
|
|
378
231
|
};
|
|
379
232
|
});
|
|
380
233
|
|
|
381
|
-
if (
|
|
382
|
-
const site = sites.find((c) => (c.domainAliases || []).find((item) => item.value ===
|
|
234
|
+
if (ipWildcardDomain) {
|
|
235
|
+
const site = sites.find((c) => (c.domainAliases || []).find((item) => item.value === ipWildcardDomain));
|
|
383
236
|
if (site) {
|
|
384
|
-
const
|
|
385
|
-
const
|
|
386
|
-
|
|
387
|
-
|
|
388
|
-
|
|
389
|
-
type: ipTypes[x],
|
|
237
|
+
const httpInfo = await getHttpInfo(ipWildcardDomain);
|
|
238
|
+
const httpsUrls = availableIps.map((ip) => ({
|
|
239
|
+
url: `${httpInfo.protocol}://${transformIPToDomain(ip)}.${ipWildcardDomain.substring(2)}${
|
|
240
|
+
httpInfo.port
|
|
241
|
+
}${adminPath}`,
|
|
390
242
|
}));
|
|
391
243
|
|
|
244
|
+
// add did domain access url
|
|
245
|
+
const didDomainAlias = site.domainAliases.find((item) => item.value.endsWith(info.didDomain));
|
|
246
|
+
if (didDomainAlias) {
|
|
247
|
+
const didDomain = didDomainAlias.value;
|
|
248
|
+
const didDomainHttpInfo = await getHttpInfo(didDomain);
|
|
249
|
+
|
|
250
|
+
httpsUrls.push({
|
|
251
|
+
url: `${didDomainHttpInfo.protocol}://${didDomain}${didDomainHttpInfo.port}${adminPath}`,
|
|
252
|
+
});
|
|
253
|
+
}
|
|
254
|
+
|
|
392
255
|
return httpUrls.concat(httpsUrls);
|
|
393
256
|
}
|
|
394
257
|
}
|
|
@@ -397,73 +260,11 @@ const getBaseUrls = async (node, ips) => {
|
|
|
397
260
|
}
|
|
398
261
|
|
|
399
262
|
// port urls
|
|
400
|
-
return
|
|
401
|
-
url: `http://${
|
|
402
|
-
type: ipTypes[x],
|
|
263
|
+
return availableIps.map((ip) => ({
|
|
264
|
+
url: `http://${ip}:${info.port}`,
|
|
403
265
|
}));
|
|
404
266
|
};
|
|
405
267
|
|
|
406
|
-
const getBlockletMetaByUrl = async (url) => {
|
|
407
|
-
const { protocol, pathname } = new URL(url);
|
|
408
|
-
|
|
409
|
-
if (protocol.startsWith('file')) {
|
|
410
|
-
const decoded = decodeURIComponent(pathname);
|
|
411
|
-
if (!fs.existsSync(decoded)) {
|
|
412
|
-
throw new Error(`File does not exist: ${decoded}`);
|
|
413
|
-
}
|
|
414
|
-
const d = await fs.promises.readFile(decoded);
|
|
415
|
-
const meta = JSON.parse(d);
|
|
416
|
-
return meta;
|
|
417
|
-
}
|
|
418
|
-
|
|
419
|
-
if (protocol.startsWith('http')) {
|
|
420
|
-
try {
|
|
421
|
-
const { data: meta } = await request({ url, method: 'GET', timeout: 1000 * 20 });
|
|
422
|
-
if (Object.prototype.toString.call(meta) !== '[object Object]') {
|
|
423
|
-
throw new Error('Url is not valid');
|
|
424
|
-
}
|
|
425
|
-
return meta;
|
|
426
|
-
} catch (err) {
|
|
427
|
-
throw new Error(`Failed to get blocklet meta from ${url}: ${err.message}`);
|
|
428
|
-
}
|
|
429
|
-
}
|
|
430
|
-
|
|
431
|
-
throw new Error(`Invalid url protocol: ${protocol.replace(/:$/, '')}`);
|
|
432
|
-
};
|
|
433
|
-
|
|
434
|
-
const validateUrl = async (url, expectedHttpResTypes = ['application/json', 'text/plain']) => {
|
|
435
|
-
const parsed = new URL(url);
|
|
436
|
-
const { protocol, pathname } = parsed;
|
|
437
|
-
|
|
438
|
-
// file
|
|
439
|
-
if (protocol.startsWith('file')) {
|
|
440
|
-
const decoded = decodeURIComponent(pathname);
|
|
441
|
-
if (!fs.existsSync(decoded)) {
|
|
442
|
-
throw new Error(`File does not exist: ${decoded}`);
|
|
443
|
-
}
|
|
444
|
-
return true;
|
|
445
|
-
}
|
|
446
|
-
|
|
447
|
-
// http(s)
|
|
448
|
-
if (protocol.startsWith('http')) {
|
|
449
|
-
let res;
|
|
450
|
-
|
|
451
|
-
try {
|
|
452
|
-
res = await request({ url, method: 'HEAD', timeout: 1000 * 10 });
|
|
453
|
-
} catch (err) {
|
|
454
|
-
throw new Error(`Cannot get content-type from ${url}: ${err.message}`);
|
|
455
|
-
}
|
|
456
|
-
|
|
457
|
-
if (expectedHttpResTypes.some((x) => res.headers['content-type'].includes(x)) === false) {
|
|
458
|
-
throw new Error(`Unexpected content-type from ${url}: ${res.headers['content-type']}`);
|
|
459
|
-
}
|
|
460
|
-
|
|
461
|
-
return true;
|
|
462
|
-
}
|
|
463
|
-
|
|
464
|
-
throw new Error(`Invalid url protocol: ${protocol.replace(/:$/, '')}`);
|
|
465
|
-
};
|
|
466
|
-
|
|
467
268
|
const expandBundle = (bundlePath, destDir) =>
|
|
468
269
|
unzipper.Open.file(bundlePath).then((d) => d.extract({ path: destDir, concurrency: 20 }));
|
|
469
270
|
|
|
@@ -527,12 +328,151 @@ const getQueueConcurrencyByMem = () => {
|
|
|
527
328
|
|
|
528
329
|
const getSafeEnv = (inputEnv, processEnv = process.env) => {
|
|
529
330
|
const whiteList = ['ABT_NODE', 'ABT_NODE_DID', 'ABT_NODE_PK', 'ABT_NODE_PORT', 'ABT_NODE_SERVICE_PORT'];
|
|
331
|
+
const blackList = { ABT_NODE_SK: '' };
|
|
530
332
|
// 此处需要保留 process.env 中的环境变量,只移除和 ABT_NODE 相关的环境变量(否则丢失了 process.env.SHELL 变量可能会造成无法使用 nodejs 的情况)
|
|
531
333
|
const filterProcessEnv = pickBy(processEnv, (value, key) => !key.startsWith('ABT_NODE') || whiteList.includes(key));
|
|
532
|
-
const mergedEnv = { ...filterProcessEnv, ...inputEnv };
|
|
334
|
+
const mergedEnv = { ...filterProcessEnv, ...inputEnv, ...blackList };
|
|
533
335
|
return mergedEnv;
|
|
534
336
|
};
|
|
535
337
|
|
|
338
|
+
// For performance sake, we only support 1 param here, and the cache is flushed every minute
|
|
339
|
+
const memoizeAsync = (fn, flushInterval = 60000) => {
|
|
340
|
+
const cache = new Map();
|
|
341
|
+
setInterval(() => cache.clear(), flushInterval);
|
|
342
|
+
|
|
343
|
+
return (arg) => {
|
|
344
|
+
if (cache.has(arg)) {
|
|
345
|
+
return cache.get(arg);
|
|
346
|
+
}
|
|
347
|
+
|
|
348
|
+
// eslint-disable-next-line prefer-spread
|
|
349
|
+
const result = fn.apply(null, [arg]);
|
|
350
|
+
cache.set(arg, result);
|
|
351
|
+
|
|
352
|
+
return result;
|
|
353
|
+
};
|
|
354
|
+
};
|
|
355
|
+
|
|
356
|
+
const getStateCrons = (states) => [
|
|
357
|
+
{
|
|
358
|
+
name: 'cleanup-audit-logs',
|
|
359
|
+
time: '0 0 6 * * *', // cleanup old logs every day at 6am
|
|
360
|
+
// time: '0 */5 * * * *', // cleanup every 5 minutes
|
|
361
|
+
options: { runOnInit: false },
|
|
362
|
+
fn: async () => {
|
|
363
|
+
const removed = await states.auditLog.remove({
|
|
364
|
+
createdAt: { $lt: new Date(Date.now() - 1000 * 60 * 60 * 24 * 90) },
|
|
365
|
+
});
|
|
366
|
+
logger.info(`Removed ${removed} audit logs`);
|
|
367
|
+
},
|
|
368
|
+
},
|
|
369
|
+
];
|
|
370
|
+
|
|
371
|
+
const getDelegateState = async (chainHost, address) => {
|
|
372
|
+
const result = await axios.post(
|
|
373
|
+
joinUrl(chainHost, '/gql/'),
|
|
374
|
+
JSON.stringify({
|
|
375
|
+
query: `{
|
|
376
|
+
getDelegateState(address: "${address}") {
|
|
377
|
+
state {
|
|
378
|
+
address
|
|
379
|
+
ops {
|
|
380
|
+
key
|
|
381
|
+
}
|
|
382
|
+
}
|
|
383
|
+
}
|
|
384
|
+
}`,
|
|
385
|
+
}),
|
|
386
|
+
{
|
|
387
|
+
headers: {
|
|
388
|
+
'Content-Type': 'application/json',
|
|
389
|
+
Accept: 'application/json',
|
|
390
|
+
},
|
|
391
|
+
timeout: 60 * 1000,
|
|
392
|
+
}
|
|
393
|
+
);
|
|
394
|
+
|
|
395
|
+
return get(result.data, 'data.getDelegateState.state');
|
|
396
|
+
};
|
|
397
|
+
|
|
398
|
+
const getNFTState = async (chainHost, nftId) => {
|
|
399
|
+
const url = joinUrl(new URL(chainHost).origin, '/api/gql/');
|
|
400
|
+
|
|
401
|
+
const result = await axios.post(
|
|
402
|
+
url,
|
|
403
|
+
JSON.stringify({
|
|
404
|
+
query: `{
|
|
405
|
+
getAssetState(address: "${nftId}") {
|
|
406
|
+
state {
|
|
407
|
+
address
|
|
408
|
+
data {
|
|
409
|
+
typeUrl
|
|
410
|
+
value
|
|
411
|
+
}
|
|
412
|
+
display {
|
|
413
|
+
type
|
|
414
|
+
content
|
|
415
|
+
}
|
|
416
|
+
issuer
|
|
417
|
+
owner
|
|
418
|
+
parent
|
|
419
|
+
tags
|
|
420
|
+
}
|
|
421
|
+
}
|
|
422
|
+
}`,
|
|
423
|
+
}),
|
|
424
|
+
{
|
|
425
|
+
headers: {
|
|
426
|
+
'Content-Type': 'application/json',
|
|
427
|
+
Accept: 'application/json',
|
|
428
|
+
},
|
|
429
|
+
timeout: 60 * 1000,
|
|
430
|
+
}
|
|
431
|
+
);
|
|
432
|
+
|
|
433
|
+
const state = get(result, 'data.data.getAssetState.state');
|
|
434
|
+
if (state && state.data.typeUrl === 'json') {
|
|
435
|
+
state.data.value = JSON.parse(state.data.value);
|
|
436
|
+
}
|
|
437
|
+
|
|
438
|
+
return state;
|
|
439
|
+
};
|
|
440
|
+
|
|
441
|
+
const getServerDidDomain = (nodeInfo) => `${encodeBase32(nodeInfo.did)}.${nodeInfo.didDomain}`;
|
|
442
|
+
|
|
443
|
+
const prettyURL = (url, isHttps = true) => {
|
|
444
|
+
if (typeof url !== 'string') {
|
|
445
|
+
return url;
|
|
446
|
+
}
|
|
447
|
+
|
|
448
|
+
if (url.toLowerCase().startsWith('http')) {
|
|
449
|
+
return url;
|
|
450
|
+
}
|
|
451
|
+
|
|
452
|
+
return isHttps ? `https://${url}` : `http://${url}`;
|
|
453
|
+
};
|
|
454
|
+
|
|
455
|
+
const templateReplace = (str, vars = {}) => {
|
|
456
|
+
if (typeof str === 'string') {
|
|
457
|
+
return str.replace(/{([.\w]+)}/g, (m, key) => get(vars, key));
|
|
458
|
+
}
|
|
459
|
+
|
|
460
|
+
return str;
|
|
461
|
+
};
|
|
462
|
+
|
|
463
|
+
const isGatewayCacheEnabled = (info) => {
|
|
464
|
+
if (info.mode === NODE_MODES.DEBUG) {
|
|
465
|
+
return false;
|
|
466
|
+
}
|
|
467
|
+
|
|
468
|
+
const cacheEnabled = get(info, 'routing.cacheEnabled');
|
|
469
|
+
if (typeof cacheEnabled === 'boolean') {
|
|
470
|
+
return cacheEnabled;
|
|
471
|
+
}
|
|
472
|
+
|
|
473
|
+
return true;
|
|
474
|
+
};
|
|
475
|
+
|
|
536
476
|
const lib = {
|
|
537
477
|
validateOwner,
|
|
538
478
|
getProviderFromNodeInfo,
|
|
@@ -541,30 +481,17 @@ const lib = {
|
|
|
541
481
|
formatEnvironments,
|
|
542
482
|
isInProgress,
|
|
543
483
|
isBeforeInstalled,
|
|
544
|
-
|
|
545
|
-
getBlockletBaseUrls,
|
|
484
|
+
replaceDomainSlot,
|
|
546
485
|
getBlockletHost,
|
|
547
|
-
getBlockletInterfaces,
|
|
548
486
|
isRoutingEnabled,
|
|
549
487
|
checkDomainDNS,
|
|
550
488
|
asyncExec,
|
|
551
|
-
trimSlash,
|
|
552
489
|
isCLI,
|
|
553
490
|
getHttpsCertInfo,
|
|
554
491
|
ensureDataDirs,
|
|
555
492
|
getDataDirs,
|
|
556
493
|
getBaseUrls,
|
|
557
|
-
getBlockletMeta:
|
|
558
|
-
parseBlockletMeta(dir, {
|
|
559
|
-
serviceMetas: getServices(),
|
|
560
|
-
...opts,
|
|
561
|
-
}),
|
|
562
|
-
validateBlockletMeta: (meta, opts = {}) => {
|
|
563
|
-
fixAndValidateService(meta, getServices(), opts.fix);
|
|
564
|
-
return validateMeta(meta, opts);
|
|
565
|
-
},
|
|
566
|
-
getBlockletMetaByUrl,
|
|
567
|
-
validateUrl,
|
|
494
|
+
getBlockletMeta: parseBlockletMeta,
|
|
568
495
|
expandBundle,
|
|
569
496
|
findInterfaceByName,
|
|
570
497
|
findInterfacePortByName,
|
|
@@ -573,6 +500,14 @@ const lib = {
|
|
|
573
500
|
transformIPToDomain,
|
|
574
501
|
getQueueConcurrencyByMem,
|
|
575
502
|
getSafeEnv,
|
|
503
|
+
memoizeAsync,
|
|
504
|
+
getStateCrons,
|
|
505
|
+
getDelegateState,
|
|
506
|
+
getNFTState,
|
|
507
|
+
getServerDidDomain,
|
|
508
|
+
prettyURL,
|
|
509
|
+
templateReplace,
|
|
510
|
+
isGatewayCacheEnabled,
|
|
576
511
|
};
|
|
577
512
|
|
|
578
513
|
module.exports = lib;
|
package/lib/util/ip.js
CHANGED
|
@@ -1,6 +1,9 @@
|
|
|
1
1
|
const getIp = require('@abtnode/util/lib/get-ip');
|
|
2
2
|
const logger = require('@abtnode/logger')('@abtnode/core:ip');
|
|
3
3
|
|
|
4
|
+
const doRpc = require('./rpc');
|
|
5
|
+
const { memoizeAsync } = require('./index');
|
|
6
|
+
|
|
4
7
|
let cache = null;
|
|
5
8
|
const fetch = async () => {
|
|
6
9
|
try {
|
|
@@ -22,6 +25,9 @@ const cron = {
|
|
|
22
25
|
fn: fetch,
|
|
23
26
|
};
|
|
24
27
|
|
|
28
|
+
const lookup = memoizeAsync((ip) => doRpc({ command: 'lookup', ip }));
|
|
29
|
+
|
|
25
30
|
module.exports.fetch = fetch;
|
|
26
31
|
module.exports.get = get;
|
|
27
32
|
module.exports.cron = cron;
|
|
33
|
+
module.exports.lookup = lookup;
|