@abtnode/core 1.4.12 → 1.5.1
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 +10 -14
- package/lib/blocklet/manager/disk.js +3 -1
- package/lib/index.js +0 -2
- package/lib/migrations/1.5.0-site.js +34 -0
- package/lib/router/helper.js +147 -165
- package/lib/router/index.js +21 -2
- package/lib/states/blocklet.js +9 -7
- package/lib/team/manager.js +8 -6
- package/lib/util/blocklet.js +23 -15
- package/lib/util/get-accessible-external-node-ip.js +41 -0
- package/lib/util/get-ip-dns-domain-for-blocklet.js +5 -2
- package/lib/util/index.js +33 -18
- package/lib/util/upgrade.js +5 -1
- package/package.json +18 -18
- package/lib/util/get-accessible-ip.js +0 -42
package/lib/api/team.js
CHANGED
|
@@ -601,24 +601,20 @@ class TeamAPI extends EventEmitter {
|
|
|
601
601
|
const rbac = await this.getRBAC(did);
|
|
602
602
|
|
|
603
603
|
const oldPermissions = await this.getPermissions({ teamDid: did });
|
|
604
|
-
await Promise.all(
|
|
605
|
-
(oldPermissions || []).map(async ({ name, isProtected }) => {
|
|
606
|
-
if (isProtected) {
|
|
607
|
-
await rbac.removePermission(name);
|
|
608
|
-
}
|
|
609
|
-
})
|
|
610
|
-
);
|
|
611
604
|
|
|
612
605
|
await Promise.all(
|
|
613
606
|
(interfaces || []).map(async ({ name, type }) => {
|
|
607
|
+
const permissionName = genPermissionName(name);
|
|
614
608
|
if (type === 'web') {
|
|
615
|
-
|
|
616
|
-
|
|
617
|
-
|
|
618
|
-
|
|
619
|
-
|
|
620
|
-
|
|
621
|
-
|
|
609
|
+
if (!oldPermissions.some((x) => x.name === permissionName)) {
|
|
610
|
+
await rbac.createPermission({
|
|
611
|
+
name: permissionName,
|
|
612
|
+
description: `Access resources under the ${name} interface`,
|
|
613
|
+
extra: {
|
|
614
|
+
isProtected: true,
|
|
615
|
+
},
|
|
616
|
+
});
|
|
617
|
+
}
|
|
622
618
|
}
|
|
623
619
|
})
|
|
624
620
|
);
|
|
@@ -34,6 +34,7 @@ const {
|
|
|
34
34
|
fromBlockletSource,
|
|
35
35
|
} = require('@blocklet/meta/lib/constants');
|
|
36
36
|
const util = require('../../util');
|
|
37
|
+
const getAccessibleExternalNodeIp = require('../../util/get-accessible-external-node-ip');
|
|
37
38
|
const {
|
|
38
39
|
forEachBlocklet,
|
|
39
40
|
getBlockletDirs,
|
|
@@ -900,7 +901,8 @@ class BlockletManager extends BaseBlockletManager {
|
|
|
900
901
|
// Put shorter url first
|
|
901
902
|
return a.from.pathPrefix.length < b.from.pathPrefix ? 1 : -1;
|
|
902
903
|
});
|
|
903
|
-
|
|
904
|
+
const nodeIp = await getAccessibleExternalNodeIp(nodeInfo);
|
|
905
|
+
blocklet.interfaces = getBlockletInterfaces({ blocklet, context, nodeInfo, sites: routingRules, nodeIp });
|
|
904
906
|
|
|
905
907
|
try {
|
|
906
908
|
const { appId } = blocklet.meta.group === BlockletGroup.gateway ? blocklet.children[0].env : blocklet.env;
|
package/lib/index.js
CHANGED
|
@@ -129,7 +129,6 @@ function ABTNode(options) {
|
|
|
129
129
|
getRoutingSites,
|
|
130
130
|
getSnapshotSites,
|
|
131
131
|
ensureDashboardRouting,
|
|
132
|
-
ensureIpDnsRouting,
|
|
133
132
|
ensureBlockletRouting,
|
|
134
133
|
ensureBlockletRoutingForUpgrade,
|
|
135
134
|
removeBlockletRouting,
|
|
@@ -305,7 +304,6 @@ function ABTNode(options) {
|
|
|
305
304
|
takeRoutingSnapshot,
|
|
306
305
|
getSitesFromSnapshot,
|
|
307
306
|
ensureDashboardRouting,
|
|
308
|
-
ensureIpDnsRouting,
|
|
309
307
|
|
|
310
308
|
addDomainAlias: routerManager.addDomainAlias.bind(routerManager),
|
|
311
309
|
deleteDomainAlias: routerManager.deleteDomainAlias.bind(routerManager),
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
const { SLOT_FOR_IP_DNS_SITE } = require('@abtnode/constant');
|
|
2
|
+
|
|
3
|
+
module.exports = async ({ states, node, printInfo }) => {
|
|
4
|
+
printInfo('Migrate ip dns site for blocklet...');
|
|
5
|
+
|
|
6
|
+
const sites = await states.site.getSites();
|
|
7
|
+
let changed = false;
|
|
8
|
+
|
|
9
|
+
// remove system blocklet site of ip-dns-domain if ip is not 888-888-888-888. e.g. static-demo-abc-192-168-3-28.ip.abtnet.io
|
|
10
|
+
// keep system blocklet site of ip-dns-domain only if ip is 888-888-888-888. e.g. static-demo-abc-888-888-888-888.ip.abtnet.io
|
|
11
|
+
for (const site of sites) {
|
|
12
|
+
if (site.isProtected) {
|
|
13
|
+
const ipRegex = /\w{3}-(\d+-\d+-\d+-\d+)\.ip\.abtnet\.io$/;
|
|
14
|
+
const match = ipRegex.exec(site.domain);
|
|
15
|
+
if (match) {
|
|
16
|
+
if (match[1] !== SLOT_FOR_IP_DNS_SITE) {
|
|
17
|
+
// eslint-disable-next-line no-await-in-loop
|
|
18
|
+
await states.site.remove({ _id: site.id });
|
|
19
|
+
printInfo(`Delete site: ${site.domain}`);
|
|
20
|
+
changed = true;
|
|
21
|
+
}
|
|
22
|
+
}
|
|
23
|
+
}
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
if (changed) {
|
|
27
|
+
await node.takeRoutingSnapshot({
|
|
28
|
+
message: 'Migrate ip dns site for blocklet',
|
|
29
|
+
dryRun: false,
|
|
30
|
+
handleRouting: false,
|
|
31
|
+
});
|
|
32
|
+
printInfo('Take routing snapshot');
|
|
33
|
+
}
|
|
34
|
+
};
|
package/lib/router/helper.js
CHANGED
|
@@ -24,7 +24,6 @@ const {
|
|
|
24
24
|
ROUTING_RULE_TYPES,
|
|
25
25
|
CERTIFICATE_EXPIRES_OFFSET,
|
|
26
26
|
CERTIFICATE_EXPIRES_WARNING_OFFSET,
|
|
27
|
-
DEFAULT_DASHBOARD_DOMAIN,
|
|
28
27
|
DEFAULT_DAEMON_PORT,
|
|
29
28
|
} = require('@abtnode/constant');
|
|
30
29
|
const {
|
|
@@ -45,7 +44,6 @@ const {
|
|
|
45
44
|
getWellknownSitePort,
|
|
46
45
|
} = require('../util');
|
|
47
46
|
const { getServicesFromBlockletInterface } = require('../util/service');
|
|
48
|
-
const { getAccessibleIp, getAccessibleIpDnsDomainForNode } = require('../util/get-accessible-ip');
|
|
49
47
|
const getIpDnsDomainForBlocklet = require('../util/get-ip-dns-domain-for-blocklet');
|
|
50
48
|
|
|
51
49
|
const Router = require('./index');
|
|
@@ -132,6 +130,27 @@ const attachInterfaceUrls = async ({ sites = [], context }) => {
|
|
|
132
130
|
});
|
|
133
131
|
};
|
|
134
132
|
|
|
133
|
+
const addCorsToSite = (site, rawUrl) => {
|
|
134
|
+
if (!site || !rawUrl) {
|
|
135
|
+
return;
|
|
136
|
+
}
|
|
137
|
+
try {
|
|
138
|
+
const url = new URL(rawUrl);
|
|
139
|
+
if (!Array.isArray(site.corsAllowedOrigins)) {
|
|
140
|
+
site.corsAllowedOrigins = [];
|
|
141
|
+
}
|
|
142
|
+
|
|
143
|
+
if (!site.corsAllowedOrigins.includes(url.hostname)) {
|
|
144
|
+
site.corsAllowedOrigins.push(url.hostname);
|
|
145
|
+
}
|
|
146
|
+
} catch (err) {
|
|
147
|
+
// Do nothing
|
|
148
|
+
}
|
|
149
|
+
};
|
|
150
|
+
|
|
151
|
+
const isBasicSite = (domain) =>
|
|
152
|
+
[DOMAIN_FOR_INTERNAL_SITE, DOMAIN_FOR_IP_SITE, DOMAIN_FOR_DEFAULT_SITE, DOMAIN_FOR_IP_SITE_REGEXP].includes(domain);
|
|
153
|
+
|
|
135
154
|
const ensureLatestNodeInfo = async (sites = [], { withDefaultCors = true } = {}) => {
|
|
136
155
|
const info = await states.node.read();
|
|
137
156
|
return sites.map((site) => {
|
|
@@ -152,26 +171,11 @@ const ensureLatestNodeInfo = async (sites = [], { withDefaultCors = true } = {})
|
|
|
152
171
|
site.domain = DOMAIN_FOR_IP_SITE_REGEXP;
|
|
153
172
|
|
|
154
173
|
if (withDefaultCors) {
|
|
155
|
-
const addDefaultCors = (rawUrl) => {
|
|
156
|
-
if (!rawUrl) {
|
|
157
|
-
return;
|
|
158
|
-
}
|
|
159
|
-
try {
|
|
160
|
-
const url = new URL(rawUrl);
|
|
161
|
-
if (!Array.isArray(site.corsAllowedOrigins)) {
|
|
162
|
-
site.corsAllowedOrigins = [];
|
|
163
|
-
}
|
|
164
|
-
|
|
165
|
-
site.corsAllowedOrigins.push(url.hostname);
|
|
166
|
-
} catch (err) {
|
|
167
|
-
// Do nothing
|
|
168
|
-
}
|
|
169
|
-
};
|
|
170
174
|
// Allow CORS from "Install on ABT Node"
|
|
171
|
-
|
|
175
|
+
addCorsToSite(site, info.registerUrl);
|
|
172
176
|
|
|
173
177
|
// Allow CORS from "Web Wallet"
|
|
174
|
-
|
|
178
|
+
addCorsToSite(site, info.webWalletUrl);
|
|
175
179
|
}
|
|
176
180
|
}
|
|
177
181
|
|
|
@@ -214,14 +218,7 @@ const ensureWellknownRule = async (sites) => {
|
|
|
214
218
|
|
|
215
219
|
for (const site of tempSites) {
|
|
216
220
|
// 不向 default site & ip site & wellknown site 添加 wellknown rule
|
|
217
|
-
|
|
218
|
-
DOMAIN_FOR_INTERNAL_SITE,
|
|
219
|
-
DOMAIN_FOR_IP_SITE,
|
|
220
|
-
DOMAIN_FOR_DEFAULT_SITE,
|
|
221
|
-
DOMAIN_FOR_IP_SITE_REGEXP,
|
|
222
|
-
].includes(site.domain);
|
|
223
|
-
|
|
224
|
-
if (!isBasicSite) {
|
|
221
|
+
if (!isBasicSite(site.domain)) {
|
|
225
222
|
const isExists = site.rules.find((x) => x.from.pathPrefix === WELLKNOWN_PATH_PREFIX);
|
|
226
223
|
|
|
227
224
|
if (!isExists) {
|
|
@@ -241,9 +238,21 @@ const ensureWellknownRule = async (sites) => {
|
|
|
241
238
|
return tempSites;
|
|
242
239
|
};
|
|
243
240
|
|
|
241
|
+
const ensureCorsForWebWallet = async (sites) => {
|
|
242
|
+
const info = await states.node.read();
|
|
243
|
+
for (const site of sites) {
|
|
244
|
+
if (!isBasicSite(site.domain)) {
|
|
245
|
+
// Allow CORS from "Web Wallet"
|
|
246
|
+
addCorsToSite(site, info.webWalletUrl);
|
|
247
|
+
}
|
|
248
|
+
}
|
|
249
|
+
return sites;
|
|
250
|
+
};
|
|
251
|
+
|
|
244
252
|
const ensureLatestInfo = async (sites = [], { withDefaultCors = true } = {}) => {
|
|
245
253
|
let result = await ensureLatestNodeInfo(sites, { withDefaultCors });
|
|
246
254
|
result = await ensureWellknownRule(result);
|
|
255
|
+
result = await ensureCorsForWebWallet(result);
|
|
247
256
|
return ensureLatestInterfaceInfo(result);
|
|
248
257
|
};
|
|
249
258
|
|
|
@@ -321,27 +330,6 @@ module.exports = function getRouterHelpers({ dataDirs, routingSnapshot, routerMa
|
|
|
321
330
|
const httpsCertState = states.certificate;
|
|
322
331
|
const notification = states.notification;
|
|
323
332
|
|
|
324
|
-
let _nodeDomainRequest = null; // singleton of node-domain-request
|
|
325
|
-
const _getIpDnsDomainForNode = ({ nodeInfo = {} } = {}) => {
|
|
326
|
-
const timeout = process.env.NODE_ENV === 'test' ? 500 : 5000;
|
|
327
|
-
if (_nodeDomainRequest) {
|
|
328
|
-
return _nodeDomainRequest;
|
|
329
|
-
}
|
|
330
|
-
|
|
331
|
-
const req = getAccessibleIpDnsDomainForNode({ nodeInfo, timeout });
|
|
332
|
-
_nodeDomainRequest = req;
|
|
333
|
-
|
|
334
|
-
req
|
|
335
|
-
.then(() => {
|
|
336
|
-
_nodeDomainRequest = null;
|
|
337
|
-
})
|
|
338
|
-
.catch(() => {
|
|
339
|
-
_nodeDomainRequest = null;
|
|
340
|
-
});
|
|
341
|
-
|
|
342
|
-
return req;
|
|
343
|
-
};
|
|
344
|
-
|
|
345
333
|
// site level duplication detection
|
|
346
334
|
const hasRuleByPrefix = (site, value) => site.rules.find((x) => x.isProtected && get(x, 'from.pathPrefix') === value);
|
|
347
335
|
|
|
@@ -580,13 +568,6 @@ module.exports = function getRouterHelpers({ dataDirs, routingSnapshot, routerMa
|
|
|
580
568
|
const _ensureBlockletSites = async (blocklet, sites, nodeInfo, context = {}) => {
|
|
581
569
|
const interfaces = (blocklet.meta.interfaces || []).filter((x) => x.type === BLOCKLET_INTERFACE_TYPE_WEB);
|
|
582
570
|
|
|
583
|
-
const nodeDomain = await _getIpDnsDomainForNode({ nodeInfo });
|
|
584
|
-
|
|
585
|
-
if (!nodeDomain) {
|
|
586
|
-
logger.error('IpDnsDomain of abtnode does not found');
|
|
587
|
-
return false;
|
|
588
|
-
}
|
|
589
|
-
|
|
590
571
|
const getPrefix = (str) => {
|
|
591
572
|
if (!str || str === '*') {
|
|
592
573
|
return '/';
|
|
@@ -596,34 +577,57 @@ module.exports = function getRouterHelpers({ dataDirs, routingSnapshot, routerMa
|
|
|
596
577
|
|
|
597
578
|
const changes = await Promise.all(
|
|
598
579
|
interfaces.map(async (x) => {
|
|
599
|
-
|
|
580
|
+
const domain = getIpDnsDomainForBlocklet(blocklet, x);
|
|
581
|
+
const pathPrefix = getPrefix(x.prefix);
|
|
582
|
+
const rule = {
|
|
583
|
+
from: { pathPrefix },
|
|
584
|
+
to: {
|
|
585
|
+
port: findInterfacePortByName(blocklet, x.name),
|
|
586
|
+
did: blocklet.meta.did,
|
|
587
|
+
type: ROUTING_RULE_TYPES.BLOCKLET,
|
|
588
|
+
interfaceName: x.name, // root blocklet interface
|
|
589
|
+
},
|
|
590
|
+
isProtected: true,
|
|
591
|
+
};
|
|
600
592
|
|
|
601
|
-
|
|
593
|
+
let changed = false; // if state db changed
|
|
602
594
|
|
|
603
|
-
|
|
595
|
+
const exist = await states.site.findOne({ domain });
|
|
596
|
+
if (!exist) {
|
|
604
597
|
await routerManager.addRoutingSite(
|
|
605
598
|
{
|
|
606
599
|
site: {
|
|
607
600
|
domain,
|
|
608
601
|
isProtected: true,
|
|
609
|
-
rules: [
|
|
610
|
-
{
|
|
611
|
-
from: { pathPrefix: getPrefix(x.prefix) },
|
|
612
|
-
to: {
|
|
613
|
-
port: findInterfacePortByName(blocklet, x.name),
|
|
614
|
-
did: blocklet.meta.did,
|
|
615
|
-
type: ROUTING_RULE_TYPES.BLOCKLET,
|
|
616
|
-
interfaceName: x.name, // root blocklet interface
|
|
617
|
-
},
|
|
618
|
-
isProtected: true,
|
|
619
|
-
},
|
|
620
|
-
],
|
|
602
|
+
rules: [rule],
|
|
621
603
|
},
|
|
622
604
|
skipCheckDynamicBlacklist: true,
|
|
623
605
|
},
|
|
624
606
|
context
|
|
625
607
|
);
|
|
608
|
+
logger.info('add routing site', { site: domain });
|
|
626
609
|
|
|
610
|
+
changed = true;
|
|
611
|
+
} else {
|
|
612
|
+
const existRule = (exist.rules || []).find((y) => get(y, 'from.pathPrefix') === pathPrefix);
|
|
613
|
+
if (existRule) {
|
|
614
|
+
await routerManager.updateRoutingRule({
|
|
615
|
+
id: exist.id,
|
|
616
|
+
rule: {
|
|
617
|
+
...rule,
|
|
618
|
+
id: exist.id,
|
|
619
|
+
},
|
|
620
|
+
skipProtectedRuleChecking: true,
|
|
621
|
+
});
|
|
622
|
+
logger.info('update routing rule for site', { site: domain });
|
|
623
|
+
} else {
|
|
624
|
+
await routerManager.addRoutingRule({
|
|
625
|
+
id: exist.id,
|
|
626
|
+
rule,
|
|
627
|
+
skipProtectedRuleChecking: true,
|
|
628
|
+
});
|
|
629
|
+
logger.info('add routing rule for site', { site: domain });
|
|
630
|
+
}
|
|
627
631
|
changed = true;
|
|
628
632
|
}
|
|
629
633
|
|
|
@@ -773,14 +777,13 @@ module.exports = function getRouterHelpers({ dataDirs, routingSnapshot, routerMa
|
|
|
773
777
|
};
|
|
774
778
|
|
|
775
779
|
const _removeBlockletSites = async (blocklet, nodeInfo, context = {}) => {
|
|
776
|
-
const nodeDomain = await _getIpDnsDomainForNode({ nodeInfo });
|
|
777
780
|
const interfaces = (blocklet.meta.interfaces || []).filter((x) => x.type === BLOCKLET_INTERFACE_TYPE_WEB);
|
|
778
781
|
|
|
779
782
|
const changes = await Promise.all(
|
|
780
783
|
interfaces.map(async (x) => {
|
|
781
784
|
let changed = false;
|
|
782
785
|
|
|
783
|
-
const domain = getIpDnsDomainForBlocklet(blocklet, x
|
|
786
|
+
const domain = getIpDnsDomainForBlocklet(blocklet, x);
|
|
784
787
|
|
|
785
788
|
const site = await states.site.findOne({ domain });
|
|
786
789
|
if (
|
|
@@ -824,46 +827,44 @@ module.exports = function getRouterHelpers({ dataDirs, routingSnapshot, routerMa
|
|
|
824
827
|
|
|
825
828
|
const sites = await siteState.getSites();
|
|
826
829
|
|
|
827
|
-
const
|
|
828
|
-
_ensureBlockletRulesForDashboardSite(blocklet, sites, nodeInfo, context),
|
|
830
|
+
const tasks = [
|
|
829
831
|
_ensureBlockletRulesForWellknownSite(blocklet, sites, context),
|
|
830
832
|
_ensureBlockletSites(blocklet, sites, nodeInfo, context),
|
|
831
|
-
]
|
|
833
|
+
];
|
|
834
|
+
|
|
835
|
+
if (nodeInfo.mode === NODE_MODES.DEBUG || ['e2e', 'test'].includes(process.env.NODE_ENV)) {
|
|
836
|
+
logger.info('Add blocklet endpoint in dashboard site', {
|
|
837
|
+
nodeMode: nodeInfo.mode,
|
|
838
|
+
NODE_ENV: process.env.NODE_ENV,
|
|
839
|
+
});
|
|
840
|
+
tasks.push(_ensureBlockletRulesForDashboardSite(blocklet, sites, nodeInfo, context));
|
|
841
|
+
}
|
|
842
|
+
|
|
843
|
+
const changes = await Promise.all(tasks);
|
|
832
844
|
|
|
833
845
|
return changes.some(Boolean);
|
|
834
846
|
};
|
|
835
847
|
|
|
836
848
|
/**
|
|
837
|
-
*
|
|
838
|
-
*
|
|
849
|
+
* remove custom rules of blocklet in old interface does not exist
|
|
850
|
+
* update custom rules of blocklet
|
|
839
851
|
*
|
|
840
852
|
* @returns {boolean} if routing changed
|
|
841
853
|
*/
|
|
842
|
-
const
|
|
843
|
-
const nodeInfo = await nodeState.read();
|
|
844
|
-
const provider = getProviderFromNodeInfo(nodeInfo);
|
|
845
|
-
if (provider === ROUTER_PROVIDER_NONE) {
|
|
846
|
-
return false;
|
|
847
|
-
}
|
|
848
|
-
|
|
854
|
+
const ensureBlockletCustomRouting = async (blocklet) => {
|
|
849
855
|
const interfaces = (blocklet.meta.interfaces || []).filter((x) => x.type === BLOCKLET_INTERFACE_TYPE_WEB);
|
|
850
856
|
const hasInterface = (name) => interfaces.some((x) => x.name === name);
|
|
851
|
-
|
|
852
|
-
// If no interfaces found, all routing rules should be removed, this rarely happens, but this logic is needed
|
|
853
|
-
if (interfaces.length === 0) {
|
|
854
|
-
return routerManager.deleteRoutingRulesItemByDid({ did: blocklet.meta.did }, context);
|
|
855
|
-
}
|
|
856
|
-
|
|
857
|
-
// First, we need ensure system rules for blocklet on dashboard site
|
|
858
|
-
let changed = await ensureBlockletRouting(blocklet, context);
|
|
859
|
-
|
|
860
|
-
// Then, we need to remove rules whose corresponding interface is not there any more
|
|
861
857
|
const sites = await siteState.getRulesByDid(blocklet.meta.did);
|
|
858
|
+
let changed = false;
|
|
859
|
+
|
|
862
860
|
for (const site of sites) {
|
|
863
861
|
const rulesToRemove = [];
|
|
864
862
|
const rulesToUpdate = [];
|
|
863
|
+
|
|
864
|
+
// get rule to remove and to update
|
|
865
865
|
for (const rule of site.rules) {
|
|
866
866
|
if (
|
|
867
|
+
rule.isProtected ||
|
|
867
868
|
rule.to.type !== ROUTING_RULE_TYPES.BLOCKLET ||
|
|
868
869
|
!rule.to.interfaceName ||
|
|
869
870
|
rule.to.did !== blocklet.meta.did
|
|
@@ -874,103 +875,77 @@ module.exports = function getRouterHelpers({ dataDirs, routingSnapshot, routerMa
|
|
|
874
875
|
|
|
875
876
|
if (hasInterface(rule.to.interfaceName) === false) {
|
|
876
877
|
rulesToRemove.push(rule.id);
|
|
877
|
-
}
|
|
878
|
-
|
|
879
|
-
if (rule.to.type === ROUTING_RULE_TYPES.BLOCKLET && rule.id === rule.groupId && !rule.isProtected) {
|
|
878
|
+
} else {
|
|
880
879
|
rulesToUpdate.push(rule);
|
|
881
880
|
}
|
|
882
881
|
}
|
|
883
882
|
|
|
883
|
+
// update rule
|
|
884
884
|
for (const rule of rulesToUpdate) {
|
|
885
885
|
// eslint-disable-next-line no-await-in-loop
|
|
886
886
|
await routerManager.updateRoutingRule({ id: site.id, rule });
|
|
887
887
|
changed = true;
|
|
888
888
|
}
|
|
889
889
|
|
|
890
|
-
|
|
891
|
-
|
|
892
|
-
|
|
893
|
-
|
|
894
|
-
|
|
895
|
-
|
|
896
|
-
|
|
897
|
-
|
|
898
|
-
|
|
899
|
-
|
|
900
|
-
)
|
|
901
|
-
|
|
902
|
-
|
|
903
|
-
|
|
904
|
-
|
|
905
|
-
|
|
906
|
-
|
|
907
|
-
error: err,
|
|
908
|
-
});
|
|
890
|
+
// delete rule
|
|
891
|
+
if (rulesToRemove.length > 0) {
|
|
892
|
+
try {
|
|
893
|
+
// eslint-disable-next-line no-await-in-loop
|
|
894
|
+
await states.site.update(
|
|
895
|
+
{ _id: site.id },
|
|
896
|
+
{ $set: { rules: site.rules.filter((x) => rulesToRemove.includes(x.id) === false) } }
|
|
897
|
+
);
|
|
898
|
+
changed = true;
|
|
899
|
+
logger.info('remove routing rule since interface does not exist', { rulesToRemove, did: blocklet.meta.did });
|
|
900
|
+
} catch (err) {
|
|
901
|
+
logger.error('failed to remove routing rule since interface does not exist', {
|
|
902
|
+
rulesToRemove,
|
|
903
|
+
did: blocklet.meta.did,
|
|
904
|
+
error: err,
|
|
905
|
+
});
|
|
906
|
+
}
|
|
909
907
|
}
|
|
910
908
|
}
|
|
911
909
|
|
|
912
|
-
await _removeBlockletSites(blocklet, nodeInfo, context);
|
|
913
|
-
|
|
914
910
|
return changed;
|
|
915
911
|
};
|
|
916
912
|
|
|
917
913
|
/**
|
|
918
|
-
*
|
|
914
|
+
* Update routing for blocklet when blocklet is upgraded
|
|
915
|
+
* This function should be called after `ensureDashboardRouting`
|
|
919
916
|
*
|
|
920
917
|
* @returns {boolean} if routing changed
|
|
921
918
|
*/
|
|
922
|
-
const
|
|
919
|
+
const ensureBlockletRoutingForUpgrade = async (blocklet, context = {}) => {
|
|
923
920
|
const nodeInfo = await nodeState.read();
|
|
921
|
+
const provider = getProviderFromNodeInfo(nodeInfo);
|
|
922
|
+
if (provider === ROUTER_PROVIDER_NONE) {
|
|
923
|
+
return false;
|
|
924
|
+
}
|
|
924
925
|
|
|
925
|
-
|
|
926
|
-
|
|
926
|
+
await routerManager.deleteRoutingRulesItemByDid(
|
|
927
|
+
{ did: blocklet.meta.did, ruleFilter: (x) => x.isProtected },
|
|
928
|
+
context
|
|
929
|
+
);
|
|
930
|
+
await ensureBlockletCustomRouting(blocklet, context);
|
|
931
|
+
await ensureBlockletRouting(blocklet, context);
|
|
927
932
|
|
|
928
|
-
return
|
|
933
|
+
// Always return true to trigger update of provider
|
|
934
|
+
return true;
|
|
929
935
|
};
|
|
930
936
|
|
|
931
937
|
/**
|
|
932
|
-
*
|
|
938
|
+
* Remove routing for blocklet
|
|
939
|
+
*
|
|
940
|
+
* @returns {boolean} if routing changed
|
|
933
941
|
*/
|
|
934
|
-
const
|
|
942
|
+
const removeBlockletRouting = async (blocklet, context = {}) => {
|
|
935
943
|
const nodeInfo = await nodeState.read();
|
|
936
|
-
const sites = await siteState.getSites();
|
|
937
|
-
|
|
938
|
-
const ip = await getAccessibleIp(nodeInfo);
|
|
939
|
-
if (!ip) {
|
|
940
|
-
logger.error('Cannot get get accessible ip for this node');
|
|
941
|
-
return false;
|
|
942
|
-
}
|
|
943
|
-
|
|
944
|
-
const formattedIp = ip.replace(/\./g, '-');
|
|
945
|
-
const suffix = DEFAULT_DASHBOARD_DOMAIN.replace(/^\*/, '');
|
|
946
|
-
const domainSuffixRegex = new RegExp(`(\\d+-\\d+-\\d+-\\d+)${suffix.replace(/\./g, '\\.')}$`); // xxx-xxx-xxx-xxx.ip.abtnet.io
|
|
947
|
-
const domainSuffix = `${formattedIp}${suffix}`;
|
|
948
|
-
|
|
949
|
-
const changes = [];
|
|
950
|
-
|
|
951
|
-
sites.forEach((x) => {
|
|
952
|
-
const match = domainSuffixRegex.exec(x.domain);
|
|
953
|
-
if (match && match[1] !== formattedIp) {
|
|
954
|
-
const domain = x.domain.replace(domainSuffixRegex, domainSuffix);
|
|
955
|
-
changes.push({ id: x.id, domain });
|
|
956
|
-
}
|
|
957
|
-
});
|
|
958
|
-
|
|
959
|
-
if (changes.length) {
|
|
960
|
-
for (const change of changes) {
|
|
961
|
-
// eslint-disable-next-line no-await-in-loop
|
|
962
|
-
await siteState.update({ _id: change.id }, { $set: { domain: change.domain } });
|
|
963
|
-
if (typeof output === 'function') {
|
|
964
|
-
output(`Blocklet endpoint was updated: ${change.domain}`);
|
|
965
|
-
}
|
|
966
|
-
}
|
|
967
944
|
|
|
968
|
-
|
|
969
|
-
|
|
970
|
-
return true;
|
|
971
|
-
}
|
|
945
|
+
const ruleChanged = await routerManager.deleteRoutingRulesItemByDid({ did: blocklet.meta.did }, context);
|
|
946
|
+
const siteChanged = await _removeBlockletSites(blocklet, nodeInfo, context);
|
|
972
947
|
|
|
973
|
-
return
|
|
948
|
+
return ruleChanged || siteChanged;
|
|
974
949
|
};
|
|
975
950
|
|
|
976
951
|
async function readRoutingSites() {
|
|
@@ -1138,8 +1113,14 @@ module.exports = function getRouterHelpers({ dataDirs, routingSnapshot, routerMa
|
|
|
1138
1113
|
return result;
|
|
1139
1114
|
};
|
|
1140
1115
|
|
|
1116
|
+
/**
|
|
1117
|
+
* @param {string} message
|
|
1118
|
+
* @param {boolean} dryRun
|
|
1119
|
+
* @param {boolean} handleRouting if NOT dryRun and handleRouting is true, will run handleRouting() after update routing
|
|
1120
|
+
* @returns
|
|
1121
|
+
*/
|
|
1141
1122
|
// eslint-disable-next-line no-unused-vars
|
|
1142
|
-
const takeRoutingSnapshot = async ({ message, dryRun = true }, context = {}) => {
|
|
1123
|
+
const takeRoutingSnapshot = async ({ message, dryRun = true, handleRouting: handle = true }, context = {}) => {
|
|
1143
1124
|
const msg = decodeURIComponent(message);
|
|
1144
1125
|
|
|
1145
1126
|
if (!msg) {
|
|
@@ -1158,8 +1139,10 @@ module.exports = function getRouterHelpers({ dataDirs, routingSnapshot, routerMa
|
|
|
1158
1139
|
if (!dryRun) {
|
|
1159
1140
|
const nodeInfo = await nodeState.read();
|
|
1160
1141
|
const result = await nodeState.updateNodeRouting({ ...nodeInfo.routing, snapshotHash: hash });
|
|
1161
|
-
|
|
1162
|
-
|
|
1142
|
+
if (handle) {
|
|
1143
|
+
await handleRouting(nodeInfo);
|
|
1144
|
+
}
|
|
1145
|
+
logger.debug('takeRoutingSnapshot', { dryRun, result, handleRouting: handle });
|
|
1163
1146
|
}
|
|
1164
1147
|
|
|
1165
1148
|
return hash;
|
|
@@ -1282,7 +1265,6 @@ module.exports = function getRouterHelpers({ dataDirs, routingSnapshot, routerMa
|
|
|
1282
1265
|
getCertificates,
|
|
1283
1266
|
getSitesFromSnapshot,
|
|
1284
1267
|
checkDomain,
|
|
1285
|
-
ensureIpDnsRouting,
|
|
1286
1268
|
|
|
1287
1269
|
getRoutingCrons: () => [
|
|
1288
1270
|
{
|
package/lib/router/index.js
CHANGED
|
@@ -48,6 +48,23 @@ const mergeAllowedOrigins = (domain, allowedOrigins) => {
|
|
|
48
48
|
return origins;
|
|
49
49
|
};
|
|
50
50
|
|
|
51
|
+
const getRoutingTable = ({ sites, nodeInfo }) => {
|
|
52
|
+
let routingTable = Router.formatSites(sites);
|
|
53
|
+
routingTable = expandSites(routingTable);
|
|
54
|
+
|
|
55
|
+
// put dashboardDomain to last, to let blockletDomain match first
|
|
56
|
+
// e.g.
|
|
57
|
+
// dashboardDomain: 192-168-3-2.ip.abtnet.io
|
|
58
|
+
// blockletDomain: static-demo-xxx-192-168-3-2.ip.abtnet.io
|
|
59
|
+
const dashboardDomain = get(nodeInfo, 'routing.dashboardDomain', '');
|
|
60
|
+
const index = routingTable.findIndex((x) => x.domain === dashboardDomain);
|
|
61
|
+
if (index > -1) {
|
|
62
|
+
routingTable.push(...routingTable.splice(index, 1));
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
return routingTable;
|
|
66
|
+
};
|
|
67
|
+
|
|
51
68
|
class Router {
|
|
52
69
|
/**
|
|
53
70
|
* Router
|
|
@@ -77,12 +94,13 @@ class Router {
|
|
|
77
94
|
|
|
78
95
|
logger.info('updateRoutingTable sites:', { sites });
|
|
79
96
|
|
|
80
|
-
this.routingTable =
|
|
97
|
+
this.routingTable = getRoutingTable({ sites, nodeInfo });
|
|
98
|
+
|
|
81
99
|
logger.info('updateRoutingTable routingTable:', { routingTable: this.routingTable });
|
|
82
100
|
logger.info('updateRoutingTable certificates:', { certificates: certificates.map((item) => item.domain) });
|
|
83
101
|
|
|
84
102
|
await this.provider.update({
|
|
85
|
-
routingTable:
|
|
103
|
+
routingTable: this.routingTable,
|
|
86
104
|
certificates,
|
|
87
105
|
globalHeaders: headers,
|
|
88
106
|
services,
|
|
@@ -218,5 +236,6 @@ Router.flattenSitesToRules = (sites = [], info = {}) => {
|
|
|
218
236
|
};
|
|
219
237
|
|
|
220
238
|
Router._expandSites = expandSites; // eslint-disable-line no-underscore-dangle
|
|
239
|
+
Router._getRoutingTable = getRoutingTable; // eslint-disable-line no-underscore-dangle
|
|
221
240
|
|
|
222
241
|
module.exports = Router;
|
package/lib/states/blocklet.js
CHANGED
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
/* eslint-disable no-await-in-loop */
|
|
2
2
|
/* eslint-disable function-paren-newline */
|
|
3
3
|
/* eslint-disable no-underscore-dangle */
|
|
4
|
+
const omit = require('lodash/omit');
|
|
4
5
|
const uniq = require('lodash/uniq');
|
|
5
6
|
const detectPort = require('detect-port');
|
|
6
7
|
const Lock = require('@abtnode/util/lib/lock');
|
|
@@ -128,8 +129,6 @@ class BlockletState extends BaseState {
|
|
|
128
129
|
// get ports
|
|
129
130
|
await lock.acquire();
|
|
130
131
|
|
|
131
|
-
delete meta.htmlAst;
|
|
132
|
-
|
|
133
132
|
const ports = await this.getBlockletPorts({ interfaces: sanitized.interfaces || [] });
|
|
134
133
|
|
|
135
134
|
const children = await this.fillChildrenPorts(this.getChildrenFromMetas(childrenMeta), {
|
|
@@ -140,7 +139,7 @@ class BlockletState extends BaseState {
|
|
|
140
139
|
this.db.insert(
|
|
141
140
|
{
|
|
142
141
|
mode,
|
|
143
|
-
meta: sanitized,
|
|
142
|
+
meta: omit(sanitized, ['htmlAst']),
|
|
144
143
|
status,
|
|
145
144
|
source,
|
|
146
145
|
deployedFrom,
|
|
@@ -177,13 +176,15 @@ class BlockletState extends BaseState {
|
|
|
177
176
|
}
|
|
178
177
|
|
|
179
178
|
try {
|
|
179
|
+
fixPerson(meta);
|
|
180
|
+
fixInterfaces(meta);
|
|
181
|
+
const sanitized = validateBlockletMeta(meta);
|
|
182
|
+
|
|
180
183
|
// get ports
|
|
181
184
|
await lock.acquire();
|
|
182
185
|
|
|
183
|
-
delete meta.htmlAst;
|
|
184
|
-
|
|
185
186
|
const ports = await this.getBlockletPorts({
|
|
186
|
-
interfaces:
|
|
187
|
+
interfaces: sanitized.interfaces || [],
|
|
187
188
|
skipOccupiedCheckPorts: getExternalPortsFromMeta(doc.meta),
|
|
188
189
|
});
|
|
189
190
|
Object.keys(ports).forEach((p) => {
|
|
@@ -197,7 +198,7 @@ class BlockletState extends BaseState {
|
|
|
197
198
|
// add to db
|
|
198
199
|
const newDoc = await this.updateById(doc._id, {
|
|
199
200
|
$set: {
|
|
200
|
-
meta,
|
|
201
|
+
meta: omit(sanitized, ['htmlAst']),
|
|
201
202
|
source,
|
|
202
203
|
deployedFrom,
|
|
203
204
|
children,
|
|
@@ -205,6 +206,7 @@ class BlockletState extends BaseState {
|
|
|
205
206
|
},
|
|
206
207
|
});
|
|
207
208
|
lock.release();
|
|
209
|
+
this.emit('upgrade', newDoc);
|
|
208
210
|
resolve(newDoc);
|
|
209
211
|
} catch (err) {
|
|
210
212
|
lock.release();
|
package/lib/team/manager.js
CHANGED
|
@@ -38,12 +38,14 @@ class TeamManager extends EventEmitter {
|
|
|
38
38
|
|
|
39
39
|
async init() {
|
|
40
40
|
// listen blocklet state
|
|
41
|
-
|
|
42
|
-
this.
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
41
|
+
['add', 'upgrade'].forEach((event) => {
|
|
42
|
+
this.states.blocklet.on(event, ({ meta: { did } }) => {
|
|
43
|
+
this.cache[did] = {
|
|
44
|
+
rbac: null,
|
|
45
|
+
user: null,
|
|
46
|
+
session: null,
|
|
47
|
+
};
|
|
48
|
+
});
|
|
47
49
|
});
|
|
48
50
|
|
|
49
51
|
this.states.blocklet.on('remove', ({ meta: { did } }) => {
|
package/lib/util/blocklet.js
CHANGED
|
@@ -223,25 +223,36 @@ const ensureBlockletExpanded = async (meta, appDir) => {
|
|
|
223
223
|
const getRootSystemEnvironments = (blocklet, nodeInfo) => {
|
|
224
224
|
const { did, name, title, description } = blocklet.meta;
|
|
225
225
|
let wallet;
|
|
226
|
-
let
|
|
227
|
-
let
|
|
226
|
+
let appSk;
|
|
227
|
+
let appId;
|
|
228
|
+
let appName = title || name;
|
|
229
|
+
let appDescription = description || '';
|
|
228
230
|
|
|
229
231
|
if (process.env.NODE_ENV !== 'test') {
|
|
230
|
-
const
|
|
232
|
+
const keys = Object.keys(BLOCKLET_CONFIGURABLE_KEY);
|
|
233
|
+
const result = getBlockletInfo(
|
|
234
|
+
{
|
|
235
|
+
meta: blocklet.meta,
|
|
236
|
+
environments: keys.map((key) => ({ key, value: blocklet.configObj[key] })).filter((x) => x.value),
|
|
237
|
+
},
|
|
238
|
+
nodeInfo.sk
|
|
239
|
+
);
|
|
231
240
|
wallet = result.wallet;
|
|
232
|
-
|
|
233
|
-
|
|
241
|
+
appSk = toHex(wallet.secretKey);
|
|
242
|
+
appId = wallet.toAddress();
|
|
243
|
+
appName = appName || result.name;
|
|
244
|
+
appDescription = appDescription || result.description;
|
|
234
245
|
} else {
|
|
235
|
-
|
|
236
|
-
|
|
246
|
+
appSk = 'AppSK:FIXME:WalletWorksFailedInJest';
|
|
247
|
+
appId = 'AppID:FIXME:WalletWorksFailedInJest';
|
|
237
248
|
}
|
|
238
249
|
|
|
239
250
|
return {
|
|
240
251
|
BLOCKLET_DID: did,
|
|
241
|
-
BLOCKLET_APP_SK:
|
|
242
|
-
BLOCKLET_APP_ID:
|
|
243
|
-
BLOCKLET_APP_NAME:
|
|
244
|
-
BLOCKLET_APP_DESCRIPTION:
|
|
252
|
+
BLOCKLET_APP_SK: appSk,
|
|
253
|
+
BLOCKLET_APP_ID: appId,
|
|
254
|
+
BLOCKLET_APP_NAME: appName,
|
|
255
|
+
BLOCKLET_APP_DESCRIPTION: appDescription,
|
|
245
256
|
};
|
|
246
257
|
};
|
|
247
258
|
|
|
@@ -269,10 +280,7 @@ const getOverwrittenEnvironments = (blocklet, nodeInfo) => {
|
|
|
269
280
|
const { wallet } = getBlockletInfo(
|
|
270
281
|
{
|
|
271
282
|
meta: blocklet.meta,
|
|
272
|
-
environments: keys.map((key) => ({
|
|
273
|
-
key,
|
|
274
|
-
value: blocklet.configObj[key] || blocklet.environmentObj[key],
|
|
275
|
-
})),
|
|
283
|
+
environments: keys.map((key) => ({ key, value: blocklet.configObj[key] })).filter((x) => x.value),
|
|
276
284
|
},
|
|
277
285
|
nodeInfo.sk
|
|
278
286
|
);
|
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
const joinUrl = require('url-join');
|
|
2
|
+
const axios = require('@abtnode/util/lib/axios');
|
|
3
|
+
const { DEFAULT_DASHBOARD_DOMAIN, DEFAULT_ADMIN_PATH } = require('@abtnode/constant');
|
|
4
|
+
const { get: getIp } = require('./ip');
|
|
5
|
+
|
|
6
|
+
const getNodeDomain = (ip) => (ip ? DEFAULT_DASHBOARD_DOMAIN.replace(/^\*/, ip.replace(/\./g, '-')) : '');
|
|
7
|
+
|
|
8
|
+
let accessibleIp = null; // cache
|
|
9
|
+
|
|
10
|
+
const timeout = process.env.NODE_ENV === 'test' ? 500 : 5000;
|
|
11
|
+
|
|
12
|
+
// check if node dashboard https endpoint return 2xx
|
|
13
|
+
// FIXME: check connected by wellknown endpoint
|
|
14
|
+
const checkConnected = async ({ ip, nodeInfo }) => {
|
|
15
|
+
const { adminPath = DEFAULT_ADMIN_PATH } = nodeInfo.routing || {};
|
|
16
|
+
const origin = `https://${getNodeDomain(ip)}`;
|
|
17
|
+
const endpoint = joinUrl(origin, adminPath);
|
|
18
|
+
await axios.get(endpoint, { timeout });
|
|
19
|
+
};
|
|
20
|
+
|
|
21
|
+
/**
|
|
22
|
+
* Get accessible external ip of abtnode
|
|
23
|
+
*/
|
|
24
|
+
const getAccessibleExternalNodeIp = async (nodeInfo) => {
|
|
25
|
+
const { external } = await getIp();
|
|
26
|
+
|
|
27
|
+
if (accessibleIp === external) {
|
|
28
|
+
return accessibleIp;
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
try {
|
|
32
|
+
await checkConnected({ ip: external, nodeInfo });
|
|
33
|
+
accessibleIp = external;
|
|
34
|
+
} catch {
|
|
35
|
+
accessibleIp = null;
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
return accessibleIp;
|
|
39
|
+
};
|
|
40
|
+
|
|
41
|
+
module.exports = getAccessibleExternalNodeIp;
|
|
@@ -1,14 +1,17 @@
|
|
|
1
1
|
const slugify = require('slugify');
|
|
2
|
+
const { DEFAULT_IP_DNS_DOMAIN_SUFFIX, SLOT_FOR_IP_DNS_SITE } = require('@abtnode/constant');
|
|
2
3
|
|
|
3
4
|
const formatName = (name) => slugify(name.replace(/^[@./-]/, '').replace(/[@./]/g, '-'));
|
|
4
5
|
|
|
5
6
|
const hiddenInterfaceNames = ['public', 'publicUrl'];
|
|
6
7
|
|
|
7
|
-
const getIpDnsDomainForBlocklet = (blocklet, blockletInterface
|
|
8
|
+
const getIpDnsDomainForBlocklet = (blocklet, blockletInterface) => {
|
|
8
9
|
const nameSuffix = blocklet.meta.did.slice(-3).toLowerCase();
|
|
9
10
|
const iName = hiddenInterfaceNames.includes(blockletInterface.name) ? '' : blockletInterface.name.toLowerCase();
|
|
10
11
|
|
|
11
|
-
return `${formatName(blocklet.meta.name)}-${nameSuffix}${
|
|
12
|
+
return `${formatName(blocklet.meta.name)}-${nameSuffix}${
|
|
13
|
+
iName ? '-' : ''
|
|
14
|
+
}${iName}-${SLOT_FOR_IP_DNS_SITE}.${DEFAULT_IP_DNS_DOMAIN_SUFFIX}`;
|
|
12
15
|
};
|
|
13
16
|
|
|
14
17
|
module.exports = getIpDnsDomainForBlocklet;
|
package/lib/util/index.js
CHANGED
|
@@ -27,6 +27,8 @@ const {
|
|
|
27
27
|
DEFAULT_HTTP_PORT,
|
|
28
28
|
DEFAULT_HTTPS_PORT,
|
|
29
29
|
ROUTING_RULE_TYPES,
|
|
30
|
+
SLOT_FOR_IP_DNS_SITE,
|
|
31
|
+
DEFAULT_IP_DNS_DOMAIN_SUFFIX,
|
|
30
32
|
} = require('@abtnode/constant');
|
|
31
33
|
|
|
32
34
|
const DEFAULT_WELLKNOWN_PORT = 8088;
|
|
@@ -71,34 +73,42 @@ const getInterfaceUrl = ({ baseUrl, url, version }) => {
|
|
|
71
73
|
|
|
72
74
|
const trimSlash = (str = '') => str.replace(/^\/+/, '').replace(/\/+$/, '');
|
|
73
75
|
|
|
74
|
-
const getBlockletHost = ({ domain, context }) => {
|
|
76
|
+
const getBlockletHost = ({ domain, context, nodeIp }) => {
|
|
77
|
+
const { protocol, port } = context || {};
|
|
78
|
+
|
|
75
79
|
if (domain === DOMAIN_FOR_DEFAULT_SITE) {
|
|
76
80
|
return '';
|
|
77
81
|
}
|
|
78
82
|
|
|
79
83
|
let tmpDomain = domain;
|
|
80
84
|
if ([DOMAIN_FOR_IP_SITE, DOMAIN_FOR_IP_SITE_REGEXP].includes(domain) || !domain) {
|
|
81
|
-
tmpDomain = context.hostname;
|
|
85
|
+
tmpDomain = context.hostname || '';
|
|
82
86
|
}
|
|
83
87
|
|
|
84
|
-
if (
|
|
85
|
-
|
|
88
|
+
if (tmpDomain.includes(SLOT_FOR_IP_DNS_SITE)) {
|
|
89
|
+
const ipRegex = /\d+[-.]\d+[-.]\d+[-.]\d+/;
|
|
90
|
+
const match = ipRegex.exec(context.hostname);
|
|
91
|
+
if (match) {
|
|
92
|
+
const ip = match[0].replace(/\./g, '-');
|
|
93
|
+
tmpDomain = tmpDomain.replace(SLOT_FOR_IP_DNS_SITE, ip);
|
|
94
|
+
} else if (nodeIp) {
|
|
95
|
+
tmpDomain = tmpDomain.replace(SLOT_FOR_IP_DNS_SITE, nodeIp.replace(/\./g, '-'));
|
|
96
|
+
}
|
|
86
97
|
}
|
|
87
98
|
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
return tmpDomain; // 不展示 https 中的 443 端口
|
|
92
|
-
}
|
|
99
|
+
if (!port) {
|
|
100
|
+
return tmpDomain;
|
|
101
|
+
}
|
|
93
102
|
|
|
94
|
-
|
|
103
|
+
if (protocol === 'https' && Number(port) === 443) {
|
|
104
|
+
return tmpDomain; // 不展示 https 中的 443 端口
|
|
95
105
|
}
|
|
96
106
|
|
|
97
|
-
if (
|
|
107
|
+
if (Number(port) === 80) {
|
|
98
108
|
return tmpDomain; // 不展示 http 中的 80 端
|
|
99
109
|
}
|
|
100
110
|
|
|
101
|
-
return `${tmpDomain}:${
|
|
111
|
+
return `${tmpDomain}:${port}`;
|
|
102
112
|
};
|
|
103
113
|
|
|
104
114
|
/**
|
|
@@ -145,15 +155,19 @@ const getAuthConfig = (rule, blocklet) => {
|
|
|
145
155
|
return auth.config;
|
|
146
156
|
};
|
|
147
157
|
|
|
148
|
-
const getBlockletBaseUrls = ({ routingEnabled = false, port, sites = [], context = {}, blocklet }) => {
|
|
149
|
-
const protocol = 'http'; // TODO: 这里固定为 http, 因为判断 url 是不是 https 和证书相关,这里实现的话比较复杂
|
|
158
|
+
const getBlockletBaseUrls = ({ routingEnabled = false, port, sites = [], context = {}, blocklet, nodeIp }) => {
|
|
150
159
|
let baseUrls = [];
|
|
151
160
|
|
|
152
161
|
if (routingEnabled && Array.isArray(sites) && sites.length > 0) {
|
|
153
162
|
baseUrls = sites
|
|
154
163
|
.map((site) => {
|
|
155
|
-
const host = getBlockletHost({ domain: site.from.domain, context });
|
|
164
|
+
const host = getBlockletHost({ domain: site.from.domain, context, nodeIp });
|
|
156
165
|
if (host) {
|
|
166
|
+
let protocol = 'http'; // TODO: 这里固定为 http, 因为判断 url 是不是 https 和证书相关,这里实现的话比较复杂
|
|
167
|
+
if (host.includes(DEFAULT_IP_DNS_DOMAIN_SUFFIX)) {
|
|
168
|
+
protocol = 'https';
|
|
169
|
+
}
|
|
170
|
+
|
|
157
171
|
return {
|
|
158
172
|
ruleId: site.id,
|
|
159
173
|
baseUrl: `${protocol}://${host}/${trimSlash(site.from.pathPrefix)}`,
|
|
@@ -167,14 +181,14 @@ const getBlockletBaseUrls = ({ routingEnabled = false, port, sites = [], context
|
|
|
167
181
|
.filter(Boolean);
|
|
168
182
|
}
|
|
169
183
|
|
|
170
|
-
if (!baseUrls.length && isIp(context.hostname)
|
|
171
|
-
baseUrls = [{ baseUrl:
|
|
184
|
+
if (!baseUrls.length && isIp(context.hostname)) {
|
|
185
|
+
baseUrls = [{ baseUrl: `http://${context.hostname}:${port}` }];
|
|
172
186
|
}
|
|
173
187
|
|
|
174
188
|
return baseUrls;
|
|
175
189
|
};
|
|
176
190
|
|
|
177
|
-
const getBlockletInterfaces = ({ blocklet, context, nodeInfo, sites }) => {
|
|
191
|
+
const getBlockletInterfaces = ({ blocklet, context, nodeInfo, sites, nodeIp }) => {
|
|
178
192
|
const interfaces = [];
|
|
179
193
|
(blocklet.meta.interfaces || []).forEach((x) => {
|
|
180
194
|
if (x.port && x.port.external) {
|
|
@@ -202,6 +216,7 @@ const getBlockletInterfaces = ({ blocklet, context, nodeInfo, sites }) => {
|
|
|
202
216
|
}),
|
|
203
217
|
context,
|
|
204
218
|
blocklet,
|
|
219
|
+
nodeIp,
|
|
205
220
|
});
|
|
206
221
|
|
|
207
222
|
baseUrls.forEach(({ baseUrl, ruleId, interfaceName, authConfig }) => {
|
package/lib/util/upgrade.js
CHANGED
|
@@ -140,7 +140,11 @@ const doUpgrade = async (session) => {
|
|
|
140
140
|
await goNextState(NODE_UPGRADE_PROGRESS.COMPLETE);
|
|
141
141
|
await sleep(5000);
|
|
142
142
|
await states.node.updateNodeInfo({ nextVersion: '', version: to, upgradeSessionId: '' });
|
|
143
|
-
|
|
143
|
+
try {
|
|
144
|
+
await states.node.exitMode(NODE_MODES.MAINTENANCE);
|
|
145
|
+
} catch (error) {
|
|
146
|
+
logger.error('Failed to exit maintenance mode', { error });
|
|
147
|
+
}
|
|
144
148
|
}
|
|
145
149
|
await lock.release();
|
|
146
150
|
};
|
package/package.json
CHANGED
|
@@ -3,7 +3,7 @@
|
|
|
3
3
|
"publishConfig": {
|
|
4
4
|
"access": "public"
|
|
5
5
|
},
|
|
6
|
-
"version": "1.
|
|
6
|
+
"version": "1.5.1",
|
|
7
7
|
"description": "",
|
|
8
8
|
"main": "lib/index.js",
|
|
9
9
|
"files": [
|
|
@@ -19,26 +19,26 @@
|
|
|
19
19
|
"author": "wangshijun <wangshijun2010@gmail.com> (http://github.com/wangshijun)",
|
|
20
20
|
"license": "MIT",
|
|
21
21
|
"dependencies": {
|
|
22
|
-
"@abtnode/constant": "1.
|
|
23
|
-
"@abtnode/cron": "1.
|
|
24
|
-
"@abtnode/event-hub": "1.
|
|
25
|
-
"@abtnode/logger": "1.
|
|
26
|
-
"@abtnode/queue": "1.
|
|
27
|
-
"@abtnode/rbac": "1.
|
|
28
|
-
"@abtnode/router-provider": "1.
|
|
29
|
-
"@abtnode/static-server": "1.
|
|
30
|
-
"@abtnode/timemachine": "1.
|
|
31
|
-
"@abtnode/util": "1.
|
|
32
|
-
"@arcblock/did": "^1.13.
|
|
22
|
+
"@abtnode/constant": "1.5.1",
|
|
23
|
+
"@abtnode/cron": "1.5.1",
|
|
24
|
+
"@abtnode/event-hub": "1.5.1",
|
|
25
|
+
"@abtnode/logger": "1.5.1",
|
|
26
|
+
"@abtnode/queue": "1.5.1",
|
|
27
|
+
"@abtnode/rbac": "1.5.1",
|
|
28
|
+
"@abtnode/router-provider": "1.5.1",
|
|
29
|
+
"@abtnode/static-server": "1.5.1",
|
|
30
|
+
"@abtnode/timemachine": "1.5.1",
|
|
31
|
+
"@abtnode/util": "1.5.1",
|
|
32
|
+
"@arcblock/did": "^1.13.20",
|
|
33
33
|
"@arcblock/pm2-events": "^0.0.5",
|
|
34
|
-
"@arcblock/vc": "^1.13.
|
|
35
|
-
"@blocklet/meta": "1.
|
|
34
|
+
"@arcblock/vc": "^1.13.20",
|
|
35
|
+
"@blocklet/meta": "1.5.1",
|
|
36
36
|
"@fidm/x509": "^1.2.1",
|
|
37
37
|
"@nedb/core": "^1.1.0",
|
|
38
38
|
"@nedb/multi": "^1.1.0",
|
|
39
|
-
"@ocap/mcrypto": "^1.13.
|
|
40
|
-
"@ocap/util": "^1.13.
|
|
41
|
-
"@ocap/wallet": "^1.13.
|
|
39
|
+
"@ocap/mcrypto": "^1.13.20",
|
|
40
|
+
"@ocap/util": "^1.13.20",
|
|
41
|
+
"@ocap/wallet": "^1.13.20",
|
|
42
42
|
"@slack/webhook": "^5.0.3",
|
|
43
43
|
"axios": "^0.21.4",
|
|
44
44
|
"axon": "^2.0.3",
|
|
@@ -72,5 +72,5 @@
|
|
|
72
72
|
"express": "^4.17.1",
|
|
73
73
|
"jest": "^26.4.2"
|
|
74
74
|
},
|
|
75
|
-
"gitHead": "
|
|
75
|
+
"gitHead": "8219f2128aaa199a52c100e6c90ea4a90d15ad15"
|
|
76
76
|
}
|
|
@@ -1,42 +0,0 @@
|
|
|
1
|
-
const joinUrl = require('url-join');
|
|
2
|
-
const axios = require('@abtnode/util/lib/axios');
|
|
3
|
-
const getIp = require('@abtnode/util/lib/get-ip');
|
|
4
|
-
const { DEFAULT_DASHBOARD_DOMAIN, DEFAULT_ADMIN_PATH } = require('@abtnode/constant');
|
|
5
|
-
|
|
6
|
-
const getNodeDomain = (ip) => (ip ? DEFAULT_DASHBOARD_DOMAIN.replace(/^\*/, ip.replace(/\./g, '-')) : '');
|
|
7
|
-
|
|
8
|
-
const getAccessibleIp = async ({ nodeInfo = {}, timeout = 5000 } = {}) => {
|
|
9
|
-
const { adminPath = DEFAULT_ADMIN_PATH } = nodeInfo.routing || {};
|
|
10
|
-
|
|
11
|
-
// check if node dashboard https endpoint return 2xx
|
|
12
|
-
// FIXME: check connected by wellknown endpoint
|
|
13
|
-
const checkConnected = async ({ ip }) => {
|
|
14
|
-
const origin = `https://${getNodeDomain(ip)}`;
|
|
15
|
-
const endpoint = joinUrl(origin, adminPath);
|
|
16
|
-
await axios.get(endpoint, { timeout });
|
|
17
|
-
};
|
|
18
|
-
|
|
19
|
-
const { internal, external } = await getIp({ timeout });
|
|
20
|
-
|
|
21
|
-
if (!external) {
|
|
22
|
-
return internal;
|
|
23
|
-
}
|
|
24
|
-
|
|
25
|
-
try {
|
|
26
|
-
await checkConnected({ ip: external });
|
|
27
|
-
return external;
|
|
28
|
-
} catch {
|
|
29
|
-
return internal;
|
|
30
|
-
}
|
|
31
|
-
};
|
|
32
|
-
|
|
33
|
-
const getAccessibleIpDnsDomainForNode = async ({ nodeInfo = {}, timeout = 5000 } = {}) => {
|
|
34
|
-
const accessibleIp = await getAccessibleIp({ nodeInfo, timeout });
|
|
35
|
-
|
|
36
|
-
return getNodeDomain(accessibleIp);
|
|
37
|
-
};
|
|
38
|
-
|
|
39
|
-
module.exports = {
|
|
40
|
-
getAccessibleIp,
|
|
41
|
-
getAccessibleIpDnsDomainForNode,
|
|
42
|
-
};
|