@abtnode/core 1.5.14 → 1.5.15
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/blocklet/extras.js +1 -1
- package/lib/blocklet/manager/disk.js +1 -1
- package/lib/blocklet/registry.js +5 -5
- package/lib/event.js +2 -2
- package/lib/migrations/1.5.15-site.js +184 -0
- package/lib/router/helper.js +124 -92
- package/lib/router/index.js +10 -2
- package/lib/router/manager.js +7 -7
- package/lib/states/site.js +1 -1
- package/lib/team/manager.js +1 -1
- package/lib/util/default-node-config.js +6 -6
- package/lib/util/index.js +19 -14
- package/lib/util/ready.js +5 -5
- package/lib/util/upgrade.js +4 -4
- package/lib/validators/router.js +13 -7
- package/lib/webhook/index.js +2 -2
- package/lib/webhook/sender/slack/index.js +1 -1
- package/package.json +18 -18
package/lib/blocklet/extras.js
CHANGED
|
@@ -26,7 +26,7 @@ const mergeConfigs = (oldConfigs, newConfigs = []) => {
|
|
|
26
26
|
// newConfig 为用户传的,也可以是从环境变量中去读的
|
|
27
27
|
const uniqConfigs = uniqBy(newConfigs, (x) => x.key || x.name);
|
|
28
28
|
|
|
29
|
-
// `BLOCKLET_*` and `ABT_NODE_*` vars can only be set by
|
|
29
|
+
// `BLOCKLET_*` and `ABT_NODE_*` vars can only be set by Blocklet Server Daemon with only a few exceptions.
|
|
30
30
|
const newConfig = uniqConfigs.filter((x) => {
|
|
31
31
|
const key = x.key || x.name;
|
|
32
32
|
|
|
@@ -955,7 +955,7 @@ class BlockletManager extends BaseBlockletManager {
|
|
|
955
955
|
return a.from.pathPrefix.length < b.from.pathPrefix ? 1 : -1;
|
|
956
956
|
});
|
|
957
957
|
const nodeIp = await getAccessibleExternalNodeIp(nodeInfo);
|
|
958
|
-
return getBlockletInterfaces({ blocklet, context, nodeInfo,
|
|
958
|
+
return getBlockletInterfaces({ blocklet, context, nodeInfo, routingRules, nodeIp });
|
|
959
959
|
}
|
|
960
960
|
|
|
961
961
|
async attachRuntimeInfo({ did, nodeInfo, diskInfo = true, context, cachedBlocklet }) {
|
package/lib/blocklet/registry.js
CHANGED
|
@@ -3,7 +3,7 @@ const { BlockletGroup } = require('@blocklet/meta/lib/constants');
|
|
|
3
3
|
const joinURL = require('url-join');
|
|
4
4
|
const get = require('lodash/get');
|
|
5
5
|
const pick = require('lodash/pick');
|
|
6
|
-
const {
|
|
6
|
+
const { BLOCKLET_STORE_API_PREFIX } = require('@abtnode/constant');
|
|
7
7
|
|
|
8
8
|
const { name } = require('../../package.json');
|
|
9
9
|
|
|
@@ -63,7 +63,7 @@ class BlockletRegistry {
|
|
|
63
63
|
|
|
64
64
|
const url = joinURL(
|
|
65
65
|
registryUrl || defaultRegistryUrl,
|
|
66
|
-
|
|
66
|
+
BLOCKLET_STORE_API_PREFIX,
|
|
67
67
|
`/blocklets/${did}/blocklet.json?__t__=${Date.now()}`
|
|
68
68
|
);
|
|
69
69
|
|
|
@@ -109,7 +109,7 @@ class BlockletRegistry {
|
|
|
109
109
|
|
|
110
110
|
async refreshBlocklets(context) {
|
|
111
111
|
const registryUrl = await states.node.getBlockletRegistry();
|
|
112
|
-
const url = joinURL(registryUrl,
|
|
112
|
+
const url = joinURL(registryUrl, BLOCKLET_STORE_API_PREFIX, '/blocklets.json');
|
|
113
113
|
try {
|
|
114
114
|
let res = await request.get(url, {
|
|
115
115
|
validateStatus: (status) => (status >= 200 && status < 300) || status === 304,
|
|
@@ -153,7 +153,7 @@ class BlockletRegistry {
|
|
|
153
153
|
}
|
|
154
154
|
|
|
155
155
|
BlockletRegistry.validateRegistryURL = async (registry) => {
|
|
156
|
-
const url = joinURL(registry,
|
|
156
|
+
const url = joinURL(registry, BLOCKLET_STORE_API_PREFIX, `/blocklets.json?__t__=${Date.now()}`);
|
|
157
157
|
try {
|
|
158
158
|
const res = await request.get(url);
|
|
159
159
|
if (Array.isArray(res.data)) {
|
|
@@ -170,7 +170,7 @@ BlockletRegistry.validateRegistryURL = async (registry) => {
|
|
|
170
170
|
|
|
171
171
|
BlockletRegistry.getRegistryMeta = async (registry) => {
|
|
172
172
|
try {
|
|
173
|
-
const url = joinURL(registry,
|
|
173
|
+
const url = joinURL(registry, BLOCKLET_STORE_API_PREFIX, `/registry.json?__t__=${Date.now()}`);
|
|
174
174
|
const { data } = await request.get(url);
|
|
175
175
|
|
|
176
176
|
if (!data) {
|
package/lib/event.js
CHANGED
|
@@ -128,8 +128,8 @@ module.exports = ({
|
|
|
128
128
|
const handleCLIEvent = (eventName) => {
|
|
129
129
|
const [, status] = eventName.split('.');
|
|
130
130
|
onEvent(eventName, {
|
|
131
|
-
title: `
|
|
132
|
-
description: `
|
|
131
|
+
title: `Blocklet Server ${status}`,
|
|
132
|
+
description: `Blocklet Server is ${status} successfully`,
|
|
133
133
|
entityType: 'node',
|
|
134
134
|
status: 'success',
|
|
135
135
|
});
|
|
@@ -0,0 +1,184 @@
|
|
|
1
|
+
/* eslint-disable no-continue */
|
|
2
|
+
/* eslint-disable no-await-in-loop */
|
|
3
|
+
const normalizePathPrefix = require('@abtnode/util/lib/normalize-path-prefix');
|
|
4
|
+
|
|
5
|
+
const findBlocklet = (site, blocklets) => {
|
|
6
|
+
// prefix = /
|
|
7
|
+
const rootRule = site.rules.find((x) => x.from.pathPrefix === '/' && x.to.type === 'blocklet');
|
|
8
|
+
if (rootRule) {
|
|
9
|
+
const blocklet = blocklets.find((x) => x.meta.did === rootRule.to.did);
|
|
10
|
+
if (blocklet) {
|
|
11
|
+
return blocklet;
|
|
12
|
+
}
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
for (const rule of site.rules) {
|
|
16
|
+
if (rule.to.type === 'blocklet') {
|
|
17
|
+
const blocklet = blocklets.find((x) => x.meta.did === rule.to.did);
|
|
18
|
+
if (blocklet) {
|
|
19
|
+
return blocklet;
|
|
20
|
+
}
|
|
21
|
+
}
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
return null;
|
|
25
|
+
};
|
|
26
|
+
|
|
27
|
+
const mergeSite = (newSite, oldSite) => {
|
|
28
|
+
const { domain, domainAliases = [], isProtected, rules, corsAllowedOrigins } = oldSite;
|
|
29
|
+
|
|
30
|
+
// merge domain
|
|
31
|
+
const domains = [
|
|
32
|
+
{
|
|
33
|
+
value: domain,
|
|
34
|
+
isProtected,
|
|
35
|
+
},
|
|
36
|
+
...(domainAliases || []).map((x) => (typeof x === 'string' ? { value: x, isProtected: false } : x)),
|
|
37
|
+
];
|
|
38
|
+
domains.forEach((x) => {
|
|
39
|
+
if (!newSite.domainAliases.some((y) => y.value === x.value)) {
|
|
40
|
+
newSite.domainAliases.push(x);
|
|
41
|
+
}
|
|
42
|
+
});
|
|
43
|
+
|
|
44
|
+
// merge cors
|
|
45
|
+
(corsAllowedOrigins || []).forEach((x) => {
|
|
46
|
+
if (!newSite.corsAllowedOrigins.includes(x)) {
|
|
47
|
+
newSite.corsAllowedOrigins.push(x);
|
|
48
|
+
}
|
|
49
|
+
});
|
|
50
|
+
|
|
51
|
+
// merge rules
|
|
52
|
+
(rules || []).forEach((x) => {
|
|
53
|
+
if (!newSite.rules.some((y) => normalizePathPrefix(y.from.pathPrefix) === normalizePathPrefix(x.from.pathPrefix))) {
|
|
54
|
+
newSite.rules.push(x);
|
|
55
|
+
}
|
|
56
|
+
});
|
|
57
|
+
};
|
|
58
|
+
|
|
59
|
+
module.exports = async ({ states, node, printInfo }) => {
|
|
60
|
+
printInfo('Migrate site to 2.0 version for router...\n');
|
|
61
|
+
|
|
62
|
+
const sites = await states.site.getSites();
|
|
63
|
+
const blocklets = await states.blocklet.getBlocklets();
|
|
64
|
+
printInfo(`Find blocklets: ${blocklets.length}`);
|
|
65
|
+
|
|
66
|
+
// blocklet site which ends with 888-888-888-888.ip.abtnet.io
|
|
67
|
+
const blockletSystemSites = [];
|
|
68
|
+
|
|
69
|
+
// custom site added by user
|
|
70
|
+
const customSites = [];
|
|
71
|
+
|
|
72
|
+
sites.forEach((site) => {
|
|
73
|
+
const { domain } = site;
|
|
74
|
+
|
|
75
|
+
// filter 3 default basic site
|
|
76
|
+
if (domain === '' || domain === '127.0.0.1' || domain === '*') {
|
|
77
|
+
return;
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
const blocklet = findBlocklet(site, blocklets);
|
|
81
|
+
|
|
82
|
+
if (domain.endsWith('888-888-888-888.ip.abtnet.io')) {
|
|
83
|
+
blockletSystemSites.push({
|
|
84
|
+
site,
|
|
85
|
+
blocklet,
|
|
86
|
+
});
|
|
87
|
+
} else {
|
|
88
|
+
customSites.push({
|
|
89
|
+
site,
|
|
90
|
+
blocklet,
|
|
91
|
+
});
|
|
92
|
+
}
|
|
93
|
+
});
|
|
94
|
+
|
|
95
|
+
printInfo(
|
|
96
|
+
`Find sites: ${sites.length}; blockletSystemSites: ${blockletSystemSites.length}; customSites: ${customSites.length}\n`
|
|
97
|
+
);
|
|
98
|
+
printInfo(`blockletSystemSites: ${blockletSystemSites.map((x) => x.site.domain).join(', ')}\n`);
|
|
99
|
+
printInfo(`customSites: ${customSites.map((x) => x.site.domain).join(', ')}\n`);
|
|
100
|
+
|
|
101
|
+
// generate new blocklet site for every installed blocklet
|
|
102
|
+
const newBlockletSites = {}; // <blockletDid>: <site>
|
|
103
|
+
for (const blocklet of blocklets) {
|
|
104
|
+
const domain = `${blocklet.meta.did}.blocklet-domain-group`;
|
|
105
|
+
newBlockletSites[blocklet.meta.did] = {
|
|
106
|
+
domain,
|
|
107
|
+
domainAliases: [],
|
|
108
|
+
isProtected: true,
|
|
109
|
+
rules: [],
|
|
110
|
+
corsAllowedOrigins: [],
|
|
111
|
+
};
|
|
112
|
+
}
|
|
113
|
+
printInfo(
|
|
114
|
+
`newBlockletSites: ${Object.values(newBlockletSites)
|
|
115
|
+
.map((x) => x.domain)
|
|
116
|
+
.join(', ')}\n`
|
|
117
|
+
);
|
|
118
|
+
|
|
119
|
+
printInfo('\n');
|
|
120
|
+
printInfo('Start merge blockletSystemSites to new sites');
|
|
121
|
+
for (const { site: oldSite, blocklet } of blockletSystemSites) {
|
|
122
|
+
// merge blockletSystemSite to new blocklet site
|
|
123
|
+
if (blocklet) {
|
|
124
|
+
const newSite = newBlockletSites[blocklet.meta.did];
|
|
125
|
+
mergeSite(newSite, oldSite);
|
|
126
|
+
printInfo(`Merge site from ${oldSite.domain} to ${newSite.domain}`);
|
|
127
|
+
}
|
|
128
|
+
}
|
|
129
|
+
|
|
130
|
+
printInfo('\n');
|
|
131
|
+
printInfo('Start merge customSites to new sites');
|
|
132
|
+
for (const { site: oldSite, blocklet } of customSites) {
|
|
133
|
+
// reserve custom site which not belong to any blocklet
|
|
134
|
+
if (!blocklet) {
|
|
135
|
+
printInfo(`Skip merge custom site: ${oldSite.domain}`);
|
|
136
|
+
oldSite.skip = true;
|
|
137
|
+
continue;
|
|
138
|
+
}
|
|
139
|
+
// merge custom site to new blocklet site
|
|
140
|
+
const newSite = newBlockletSites[blocklet.meta.did];
|
|
141
|
+
mergeSite(newSite, oldSite);
|
|
142
|
+
printInfo(`Merge site from ${oldSite.domain} to ${newSite.domain}`);
|
|
143
|
+
}
|
|
144
|
+
|
|
145
|
+
printInfo('\n');
|
|
146
|
+
printInfo('Start delete blockletSystemSites from db');
|
|
147
|
+
for (const { site: oldSite } of blockletSystemSites) {
|
|
148
|
+
if (oldSite.skip) {
|
|
149
|
+
printInfo(`Skip delete site from db: ${oldSite.domain}`);
|
|
150
|
+
continue;
|
|
151
|
+
}
|
|
152
|
+
// delete each blockletSystemSite
|
|
153
|
+
await states.site.remove({ _id: oldSite.id });
|
|
154
|
+
printInfo(`Delete site from db: ${oldSite.domain}`);
|
|
155
|
+
}
|
|
156
|
+
|
|
157
|
+
printInfo('\n');
|
|
158
|
+
printInfo('Start delete customSites from db');
|
|
159
|
+
for (const { site: oldSite } of customSites) {
|
|
160
|
+
if (oldSite.skip) {
|
|
161
|
+
printInfo(`Skip delete site from db: ${oldSite.domain}`);
|
|
162
|
+
continue;
|
|
163
|
+
}
|
|
164
|
+
// delete custom site which bind to a blocklet
|
|
165
|
+
await states.site.remove({ _id: oldSite.id });
|
|
166
|
+
printInfo(`Delete site from db: ${oldSite.domain}`);
|
|
167
|
+
}
|
|
168
|
+
|
|
169
|
+
// add new blocklet site to db
|
|
170
|
+
printInfo('\n');
|
|
171
|
+
printInfo('Start add new sites to db');
|
|
172
|
+
for (const site of Object.values(newBlockletSites)) {
|
|
173
|
+
await states.site.add(site);
|
|
174
|
+
printInfo(`Add site to db: ${site.domain}`);
|
|
175
|
+
}
|
|
176
|
+
|
|
177
|
+
await node.takeRoutingSnapshot({
|
|
178
|
+
message: 'Migrate site to 2.0 version for router',
|
|
179
|
+
dryRun: false,
|
|
180
|
+
handleRouting: false,
|
|
181
|
+
});
|
|
182
|
+
printInfo('\n');
|
|
183
|
+
printInfo('Take routing snapshot');
|
|
184
|
+
};
|
package/lib/router/helper.js
CHANGED
|
@@ -28,11 +28,14 @@ const {
|
|
|
28
28
|
CERTIFICATE_EXPIRES_WARNING_OFFSET,
|
|
29
29
|
DEFAULT_DAEMON_PORT,
|
|
30
30
|
DEFAULT_SERVICE_PATH,
|
|
31
|
+
SLOT_FOR_IP_DNS_SITE,
|
|
32
|
+
BLOCKLET_SITE_GROUP_SUFFIX,
|
|
31
33
|
} = require('@abtnode/constant');
|
|
32
34
|
const {
|
|
33
35
|
BLOCKLET_DYNAMIC_PATH_PREFIX,
|
|
34
36
|
BLOCKLET_INTERFACE_TYPE_WEB,
|
|
35
37
|
BLOCKLET_INTERFACE_WELLKNOWN,
|
|
38
|
+
BLOCKLET_INTERFACE_TYPE_WELLKNOWN,
|
|
36
39
|
} = require('@blocklet/meta/lib/constants');
|
|
37
40
|
|
|
38
41
|
// eslint-disable-next-line global-require
|
|
@@ -48,15 +51,58 @@ const {
|
|
|
48
51
|
} = require('../util');
|
|
49
52
|
const { getServicesFromBlockletInterface } = require('../util/service');
|
|
50
53
|
const getIpDnsDomainForBlocklet = require('../util/get-ip-dns-domain-for-blocklet');
|
|
54
|
+
const { getFromCache: getAccessibleExternalNodeIp } = require('../util/get-accessible-external-node-ip');
|
|
51
55
|
|
|
52
56
|
const Router = require('./index');
|
|
53
57
|
const states = require('../states');
|
|
54
58
|
|
|
55
|
-
|
|
59
|
+
/**
|
|
60
|
+
* replace 888-888-888-888 with accessible ip for domain
|
|
61
|
+
*/
|
|
62
|
+
const attachRuntimeDomainAliases = async ({ sites = [], context = {}, node }) => {
|
|
63
|
+
let ip;
|
|
64
|
+
const ipRegex = /\d+[-.]\d+[-.]\d+[-.]\d+/;
|
|
65
|
+
const match = ipRegex.exec(context.hostname);
|
|
66
|
+
if (match) {
|
|
67
|
+
ip = match[0].replace(/\./g, '-');
|
|
68
|
+
} else if (node) {
|
|
69
|
+
const nodeInfo = await node.read();
|
|
70
|
+
const nodeIp = await getAccessibleExternalNodeIp(nodeInfo);
|
|
71
|
+
if (nodeIp) {
|
|
72
|
+
ip = nodeIp;
|
|
73
|
+
}
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
const getDomainAliases = (site) =>
|
|
77
|
+
(site.domainAliases || []).map((domain) => {
|
|
78
|
+
if (!domain.value) {
|
|
79
|
+
return domain;
|
|
80
|
+
}
|
|
81
|
+
if (domain.value.includes(SLOT_FOR_IP_DNS_SITE) && ip) {
|
|
82
|
+
domain.value = domain.value.replace(SLOT_FOR_IP_DNS_SITE, ip);
|
|
83
|
+
}
|
|
84
|
+
return domain;
|
|
85
|
+
});
|
|
86
|
+
|
|
87
|
+
if (!Array.isArray(sites)) {
|
|
88
|
+
sites.domainAliases = getDomainAliases(sites);
|
|
89
|
+
return sites;
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
return sites.map((site) => {
|
|
93
|
+
site.domainAliases = getDomainAliases(site);
|
|
94
|
+
|
|
95
|
+
return site;
|
|
96
|
+
});
|
|
97
|
+
};
|
|
98
|
+
|
|
99
|
+
const attachInterfaceUrls = async ({ sites = [], context, node }) => {
|
|
56
100
|
if (!sites) {
|
|
57
101
|
return [];
|
|
58
102
|
}
|
|
59
103
|
|
|
104
|
+
attachRuntimeDomainAliases({ sites, context, node });
|
|
105
|
+
|
|
60
106
|
const getUrl = (rule, domain = '') => {
|
|
61
107
|
const host = getBlockletHost({ domain, context });
|
|
62
108
|
const prefix = trimSlash(rule.from.pathPrefix);
|
|
@@ -340,7 +386,7 @@ const ensureAuthService = async (sites = [], blockletManager) => {
|
|
|
340
386
|
// we should only use rule.to.realInterfaceName, rule.to.interfaceName is for backward compatible
|
|
341
387
|
const interfaceName = rule.to.realInterfaceName || rule.to.interfaceName;
|
|
342
388
|
const { interfaces } = blocklet.meta;
|
|
343
|
-
const _interface = interfaces.find((x) => x.type ===
|
|
389
|
+
const _interface = interfaces.find((x) => x.type === BLOCKLET_INTERFACE_TYPE_WEB && x.name === interfaceName);
|
|
344
390
|
if (_interface) {
|
|
345
391
|
rule.services = rule.services || [];
|
|
346
392
|
rule.services.unshift(...getServicesFromBlockletInterface(_interface, { logError: logger.error }));
|
|
@@ -596,10 +642,13 @@ module.exports = function getRouterHelpers({ dataDirs, routingSnapshot, routerMa
|
|
|
596
642
|
/**
|
|
597
643
|
* Add system sites for blocklet
|
|
598
644
|
*
|
|
599
|
-
* @returns {boolean} if routing changed
|
|
645
|
+
* @returns {boolean} if routing state db changed
|
|
600
646
|
*/
|
|
601
647
|
const _ensureBlockletSites = async (blocklet, sites, nodeInfo, context = {}) => {
|
|
602
|
-
const
|
|
648
|
+
const webInterface = (blocklet.meta.interfaces || []).find((x) => x.type === BLOCKLET_INTERFACE_TYPE_WEB);
|
|
649
|
+
if (!webInterface) {
|
|
650
|
+
return false;
|
|
651
|
+
}
|
|
603
652
|
|
|
604
653
|
const getPrefix = (str) => {
|
|
605
654
|
if (!str || str === '*') {
|
|
@@ -608,68 +657,59 @@ module.exports = function getRouterHelpers({ dataDirs, routingSnapshot, routerMa
|
|
|
608
657
|
return `/${str}`.replace(/^\/+/, '/');
|
|
609
658
|
};
|
|
610
659
|
|
|
611
|
-
const
|
|
612
|
-
|
|
613
|
-
|
|
614
|
-
|
|
615
|
-
|
|
616
|
-
|
|
617
|
-
|
|
618
|
-
|
|
619
|
-
|
|
620
|
-
|
|
621
|
-
|
|
622
|
-
|
|
623
|
-
|
|
624
|
-
};
|
|
660
|
+
const domainGroup = `${blocklet.meta.did}${BLOCKLET_SITE_GROUP_SUFFIX}`;
|
|
661
|
+
const domain = getIpDnsDomainForBlocklet(blocklet, webInterface);
|
|
662
|
+
const pathPrefix = getPrefix(webInterface.prefix);
|
|
663
|
+
const rule = {
|
|
664
|
+
from: { pathPrefix },
|
|
665
|
+
to: {
|
|
666
|
+
port: findInterfacePortByName(blocklet, webInterface.name),
|
|
667
|
+
did: blocklet.meta.did,
|
|
668
|
+
type: ROUTING_RULE_TYPES.BLOCKLET,
|
|
669
|
+
interfaceName: webInterface.name, // root blocklet interface
|
|
670
|
+
},
|
|
671
|
+
isProtected: true,
|
|
672
|
+
};
|
|
625
673
|
|
|
626
|
-
|
|
627
|
-
|
|
628
|
-
|
|
629
|
-
|
|
630
|
-
|
|
631
|
-
|
|
632
|
-
|
|
633
|
-
|
|
634
|
-
|
|
635
|
-
|
|
636
|
-
|
|
637
|
-
|
|
638
|
-
|
|
639
|
-
|
|
640
|
-
|
|
641
|
-
context
|
|
642
|
-
);
|
|
643
|
-
logger.info('add routing site', { site: domain });
|
|
674
|
+
const existSite = await states.site.findOne({ domain: domainGroup });
|
|
675
|
+
if (!existSite) {
|
|
676
|
+
await routerManager.addRoutingSite(
|
|
677
|
+
{
|
|
678
|
+
site: {
|
|
679
|
+
domain: domainGroup,
|
|
680
|
+
domainAliases: [{ value: domain, isProtected: true }],
|
|
681
|
+
isProtected: true,
|
|
682
|
+
rules: [rule],
|
|
683
|
+
},
|
|
684
|
+
skipCheckDynamicBlacklist: true,
|
|
685
|
+
},
|
|
686
|
+
context
|
|
687
|
+
);
|
|
688
|
+
logger.info('add routing site', { site: domain });
|
|
644
689
|
|
|
645
|
-
|
|
646
|
-
|
|
647
|
-
const existRule = (exist.rules || []).find((y) => get(y, 'from.pathPrefix') === pathPrefix);
|
|
648
|
-
if (existRule) {
|
|
649
|
-
await routerManager.updateRoutingRule({
|
|
650
|
-
id: exist.id,
|
|
651
|
-
rule: {
|
|
652
|
-
...rule,
|
|
653
|
-
id: exist.id,
|
|
654
|
-
},
|
|
655
|
-
skipProtectedRuleChecking: true,
|
|
656
|
-
});
|
|
657
|
-
logger.info('update routing rule for site', { site: domain });
|
|
658
|
-
} else {
|
|
659
|
-
await routerManager.addRoutingRule({
|
|
660
|
-
id: exist.id,
|
|
661
|
-
rule,
|
|
662
|
-
});
|
|
663
|
-
logger.info('add routing rule for site', { site: domain });
|
|
664
|
-
}
|
|
665
|
-
changed = true;
|
|
666
|
-
}
|
|
690
|
+
return true;
|
|
691
|
+
}
|
|
667
692
|
|
|
668
|
-
|
|
669
|
-
|
|
670
|
-
|
|
693
|
+
const existRule = (existSite.rules || []).find((y) => get(y, 'from.pathPrefix') === pathPrefix);
|
|
694
|
+
if (existRule) {
|
|
695
|
+
await routerManager.updateRoutingRule({
|
|
696
|
+
id: existSite.id,
|
|
697
|
+
rule: {
|
|
698
|
+
...rule,
|
|
699
|
+
id: existRule.id,
|
|
700
|
+
},
|
|
701
|
+
skipProtectedRuleChecking: true,
|
|
702
|
+
});
|
|
703
|
+
logger.info('update routing rule for site', { site: domain });
|
|
704
|
+
} else {
|
|
705
|
+
await routerManager.addRoutingRule({
|
|
706
|
+
id: existSite.id,
|
|
707
|
+
rule,
|
|
708
|
+
});
|
|
709
|
+
logger.info('add routing rule for site', { site: domain });
|
|
710
|
+
}
|
|
671
711
|
|
|
672
|
-
return
|
|
712
|
+
return true;
|
|
673
713
|
};
|
|
674
714
|
|
|
675
715
|
/**
|
|
@@ -684,7 +724,7 @@ module.exports = function getRouterHelpers({ dataDirs, routingSnapshot, routerMa
|
|
|
684
724
|
}
|
|
685
725
|
|
|
686
726
|
const tasks = (blocklet.meta.interfaces || [])
|
|
687
|
-
.filter((x) => x.
|
|
727
|
+
.filter((x) => x.type === BLOCKLET_INTERFACE_TYPE_WELLKNOWN)
|
|
688
728
|
.map(async (x) => {
|
|
689
729
|
const pathPrefix = normalizePathPrefix(x.prefix);
|
|
690
730
|
if (!pathPrefix.startsWith(WELLKNOWN_PATH_PREFIX)) {
|
|
@@ -811,30 +851,15 @@ module.exports = function getRouterHelpers({ dataDirs, routingSnapshot, routerMa
|
|
|
811
851
|
};
|
|
812
852
|
|
|
813
853
|
const _removeBlockletSites = async (blocklet, nodeInfo, context = {}) => {
|
|
814
|
-
|
|
815
|
-
|
|
816
|
-
const changes = await Promise.all(
|
|
817
|
-
interfaces.map(async (x) => {
|
|
818
|
-
let changed = false;
|
|
819
|
-
|
|
820
|
-
const domain = getIpDnsDomainForBlocklet(blocklet, x);
|
|
821
|
-
|
|
822
|
-
const site = await states.site.findOne({ domain });
|
|
823
|
-
if (
|
|
824
|
-
site &&
|
|
825
|
-
site.isProtected &&
|
|
826
|
-
(!site.domainAliases || !site.domainAliases.length) &&
|
|
827
|
-
(!site.rules || !site.rules.length)
|
|
828
|
-
) {
|
|
829
|
-
await routerManager.deleteRoutingSite({ id: site.id }, context);
|
|
830
|
-
changed = true;
|
|
831
|
-
}
|
|
854
|
+
let changed = false;
|
|
832
855
|
|
|
833
|
-
|
|
834
|
-
|
|
835
|
-
|
|
856
|
+
const site = await states.site.findOne({ domain: `${blocklet.meta.did}${BLOCKLET_SITE_GROUP_SUFFIX}` });
|
|
857
|
+
if (site) {
|
|
858
|
+
await routerManager.deleteRoutingSite({ id: site.id }, context);
|
|
859
|
+
changed = true;
|
|
860
|
+
}
|
|
836
861
|
|
|
837
|
-
return
|
|
862
|
+
return changed;
|
|
838
863
|
};
|
|
839
864
|
|
|
840
865
|
/**
|
|
@@ -854,8 +879,8 @@ module.exports = function getRouterHelpers({ dataDirs, routingSnapshot, routerMa
|
|
|
854
879
|
return false;
|
|
855
880
|
}
|
|
856
881
|
|
|
857
|
-
const
|
|
858
|
-
if (
|
|
882
|
+
const hasWebInterface = (blocklet.meta.interfaces || []).some((x) => x.type === BLOCKLET_INTERFACE_TYPE_WEB);
|
|
883
|
+
if (!hasWebInterface) {
|
|
859
884
|
return false;
|
|
860
885
|
}
|
|
861
886
|
|
|
@@ -886,9 +911,11 @@ module.exports = function getRouterHelpers({ dataDirs, routingSnapshot, routerMa
|
|
|
886
911
|
* @returns {boolean} if routing changed
|
|
887
912
|
*/
|
|
888
913
|
const ensureBlockletCustomRouting = async (blocklet) => {
|
|
914
|
+
// Only one blocklet web interface can be declared since router 2.0
|
|
889
915
|
const interfaces = (blocklet.meta.interfaces || []).filter((x) => x.type === BLOCKLET_INTERFACE_TYPE_WEB);
|
|
890
916
|
const hasInterface = (name) => interfaces.some((x) => x.name === name);
|
|
891
|
-
|
|
917
|
+
|
|
918
|
+
const sites = await siteState.getSitesByBlocklet(blocklet.meta.did);
|
|
892
919
|
let changed = false;
|
|
893
920
|
|
|
894
921
|
for (const site of sites) {
|
|
@@ -1164,7 +1191,7 @@ module.exports = function getRouterHelpers({ dataDirs, routingSnapshot, routerMa
|
|
|
1164
1191
|
if (msg.length < 5) {
|
|
1165
1192
|
throw new Error('Message cannot be less than 5 characters');
|
|
1166
1193
|
}
|
|
1167
|
-
if (msg.length >
|
|
1194
|
+
if (msg.length > 150) {
|
|
1168
1195
|
throw new Error('Message cannot exceed 100 characters');
|
|
1169
1196
|
}
|
|
1170
1197
|
}
|
|
@@ -1216,12 +1243,17 @@ module.exports = function getRouterHelpers({ dataDirs, routingSnapshot, routerMa
|
|
|
1216
1243
|
return attachInterfaceUrls({
|
|
1217
1244
|
sites: await ensureLatestInfo(sites, { withDefaultCors }),
|
|
1218
1245
|
context,
|
|
1246
|
+
node: nodeState,
|
|
1219
1247
|
});
|
|
1220
1248
|
};
|
|
1221
1249
|
|
|
1222
1250
|
const getSnapshotSites = async ({ hash }, context = {}, { withDefaultCors = true } = {}) => {
|
|
1223
1251
|
const sites = await routingSnapshot.readSnapshotSites(hash);
|
|
1224
|
-
return attachInterfaceUrls({
|
|
1252
|
+
return attachInterfaceUrls({
|
|
1253
|
+
sites: await ensureLatestInfo(sites, { withDefaultCors }),
|
|
1254
|
+
context,
|
|
1255
|
+
node: nodeState,
|
|
1256
|
+
});
|
|
1225
1257
|
};
|
|
1226
1258
|
|
|
1227
1259
|
const getCertificates = async () => {
|
|
@@ -1262,7 +1294,7 @@ module.exports = function getRouterHelpers({ dataDirs, routingSnapshot, routerMa
|
|
|
1262
1294
|
logger.info('send certificate expire notification', { domain: cert.domain });
|
|
1263
1295
|
notification.create({
|
|
1264
1296
|
title: 'SSL Certificate Expired',
|
|
1265
|
-
description: `Your SSL certificate for domain ${cert.domain} has expired, please update it in
|
|
1297
|
+
description: `Your SSL certificate for domain ${cert.domain} has expired, please update it in Blocklet Server`,
|
|
1266
1298
|
severity: 'error',
|
|
1267
1299
|
entityType: 'certificate',
|
|
1268
1300
|
entityId: cert._id, // eslint-disable-line no-underscore-dangle
|
|
@@ -1276,7 +1308,7 @@ module.exports = function getRouterHelpers({ dataDirs, routingSnapshot, routerMa
|
|
|
1276
1308
|
cert.domain
|
|
1277
1309
|
} will expire in ${expireInDays} days (on ${new Date(
|
|
1278
1310
|
cert.validTo
|
|
1279
|
-
).toLocaleString()}), please remember to update it in
|
|
1311
|
+
).toLocaleString()}), please remember to update it in Blocklet Server`,
|
|
1280
1312
|
severity: 'warning',
|
|
1281
1313
|
entityType: 'certificate',
|
|
1282
1314
|
entityId: cert._id, // eslint-disable-line no-underscore-dangle
|
package/lib/router/index.js
CHANGED
|
@@ -6,6 +6,7 @@ const {
|
|
|
6
6
|
ROUTING_RULE_TYPES,
|
|
7
7
|
DEFAULT_DASHBOARD_DOMAIN,
|
|
8
8
|
BLOCKLET_PROXY_PATH_PREFIX,
|
|
9
|
+
BLOCKLET_SITE_GROUP_SUFFIX,
|
|
9
10
|
} = require('@abtnode/constant');
|
|
10
11
|
const { BLOCKLET_UI_INTERFACES } = require('@blocklet/meta/lib/constants');
|
|
11
12
|
const { pick } = require('lodash');
|
|
@@ -26,7 +27,11 @@ const expandSites = (sites = []) => {
|
|
|
26
27
|
});
|
|
27
28
|
|
|
28
29
|
delete site.domainAliases;
|
|
29
|
-
|
|
30
|
+
|
|
31
|
+
// skip site if domain is BLOCKLET_SITE_GROUP
|
|
32
|
+
if (!site.domain.endsWith(BLOCKLET_SITE_GROUP_SUFFIX)) {
|
|
33
|
+
result.push(site);
|
|
34
|
+
}
|
|
30
35
|
});
|
|
31
36
|
|
|
32
37
|
const defaultSite = result.find((site) => site.domain === DOMAIN_FOR_DEFAULT_SITE);
|
|
@@ -45,7 +50,10 @@ const mergeAllowedOrigins = (domain, allowedOrigins) => {
|
|
|
45
50
|
origins.push(domain);
|
|
46
51
|
}
|
|
47
52
|
|
|
48
|
-
|
|
53
|
+
// skip site if domain is BLOCKLET_SITE_GROUP
|
|
54
|
+
const res = origins.filter((x) => !x.endsWith(BLOCKLET_SITE_GROUP_SUFFIX));
|
|
55
|
+
|
|
56
|
+
return res;
|
|
49
57
|
};
|
|
50
58
|
|
|
51
59
|
const getRoutingTable = ({ sites, nodeInfo }) => {
|
package/lib/router/manager.js
CHANGED
|
@@ -121,7 +121,7 @@ class RouterManager extends EventEmitter {
|
|
|
121
121
|
await this.validateRouterConfig('addRoutingSite', { site: newSite });
|
|
122
122
|
|
|
123
123
|
const result = await states.site.add(newSite);
|
|
124
|
-
await attachInterfaceUrls({ sites: result, context });
|
|
124
|
+
await attachInterfaceUrls({ sites: result, context, node: states.node });
|
|
125
125
|
|
|
126
126
|
this.emit('router.site.created', result);
|
|
127
127
|
return result;
|
|
@@ -181,7 +181,7 @@ class RouterManager extends EventEmitter {
|
|
|
181
181
|
this.emit('router.site.updated', params.id);
|
|
182
182
|
|
|
183
183
|
const dbSite = await states.site.findOne({ _id: params.id });
|
|
184
|
-
await attachInterfaceUrls({ sites: dbSite, context });
|
|
184
|
+
await attachInterfaceUrls({ sites: dbSite, context, node: states.node });
|
|
185
185
|
return dbSite;
|
|
186
186
|
}
|
|
187
187
|
|
|
@@ -207,7 +207,7 @@ class RouterManager extends EventEmitter {
|
|
|
207
207
|
logger.debug('add domain alias update result', { id, updateResult, domainAlias });
|
|
208
208
|
|
|
209
209
|
const newSite = await states.site.findOne({ _id: id });
|
|
210
|
-
await attachInterfaceUrls({ sites: newSite, context });
|
|
210
|
+
await attachInterfaceUrls({ sites: newSite, context, node: states.node });
|
|
211
211
|
|
|
212
212
|
return newSite;
|
|
213
213
|
}
|
|
@@ -230,7 +230,7 @@ class RouterManager extends EventEmitter {
|
|
|
230
230
|
const updateResult = await states.site.update({ _id: id }, { $set: { domainAliases: dbSite.domainAliases } });
|
|
231
231
|
logger.debug('remove domain alias update result', { id, updateResult, domainAlias });
|
|
232
232
|
|
|
233
|
-
await attachInterfaceUrls({ sites: dbSite, context });
|
|
233
|
+
await attachInterfaceUrls({ sites: dbSite, context, node: states.node });
|
|
234
234
|
|
|
235
235
|
return dbSite;
|
|
236
236
|
}
|
|
@@ -265,7 +265,7 @@ class RouterManager extends EventEmitter {
|
|
|
265
265
|
}
|
|
266
266
|
|
|
267
267
|
const newSite = await states.site.findOne({ _id: id });
|
|
268
|
-
await attachInterfaceUrls({ sites: newSite, context });
|
|
268
|
+
await attachInterfaceUrls({ sites: newSite, context, node: states.node });
|
|
269
269
|
|
|
270
270
|
this.emit('router.rule.created', newSite);
|
|
271
271
|
return newSite;
|
|
@@ -306,7 +306,7 @@ class RouterManager extends EventEmitter {
|
|
|
306
306
|
logger.info('update result', { updateResult });
|
|
307
307
|
const newSite = await states.site.findOne({ _id: id });
|
|
308
308
|
|
|
309
|
-
await attachInterfaceUrls({ sites: newSite, context });
|
|
309
|
+
await attachInterfaceUrls({ sites: newSite, context, node: states.node });
|
|
310
310
|
|
|
311
311
|
this.emit('router.rule.updated', newSite);
|
|
312
312
|
|
|
@@ -335,7 +335,7 @@ class RouterManager extends EventEmitter {
|
|
|
335
335
|
logger.info('router.rule.removed', { id, ruleId });
|
|
336
336
|
const newSite = await states.site.findOne({ _id: id });
|
|
337
337
|
|
|
338
|
-
await attachInterfaceUrls({ sites: newSite, context });
|
|
338
|
+
await attachInterfaceUrls({ sites: newSite, context, node: states.node });
|
|
339
339
|
|
|
340
340
|
this.emit('router.rule.removed', newSite);
|
|
341
341
|
return newSite;
|
package/lib/states/site.js
CHANGED
|
@@ -33,7 +33,7 @@ class SiteState extends BaseState {
|
|
|
33
33
|
return SiteState.renameIdFiledName(result);
|
|
34
34
|
}
|
|
35
35
|
|
|
36
|
-
async
|
|
36
|
+
async getSitesByBlocklet(did) {
|
|
37
37
|
const rules = await this.asyncDB.find({ 'rules.to.did': did });
|
|
38
38
|
return SiteState.renameIdFiledName(rules);
|
|
39
39
|
}
|
package/lib/team/manager.js
CHANGED
|
@@ -190,7 +190,7 @@ class TeamManager extends EventEmitter {
|
|
|
190
190
|
// first getRBAC after blocklet added
|
|
191
191
|
if (!this.cache[did].rbac) {
|
|
192
192
|
if (this.isNodeTeam(did)) {
|
|
193
|
-
throw new Error('
|
|
193
|
+
throw new Error('Blocklet Server rbac instance has not been initialized');
|
|
194
194
|
}
|
|
195
195
|
|
|
196
196
|
// FIXME: cross process lock
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
const {
|
|
2
2
|
NODE_REGISTER_URL,
|
|
3
|
-
|
|
4
|
-
|
|
3
|
+
BLOCKLET_STORE_URL,
|
|
4
|
+
BLOCKLET_STORE_URL_DEV,
|
|
5
5
|
WEB_WALLET_URL,
|
|
6
6
|
NODE_PACKAGE_NAME,
|
|
7
7
|
NODE_COMMAND_NAME,
|
|
@@ -23,18 +23,18 @@ const defaultNodeConfigs = {
|
|
|
23
23
|
blockletRegistryList: {
|
|
24
24
|
getDefaultValue: () => [
|
|
25
25
|
{
|
|
26
|
-
name: 'Official
|
|
26
|
+
name: 'Official Store',
|
|
27
27
|
description: 'ArcBlock official blocklet registry',
|
|
28
|
-
url:
|
|
28
|
+
url: BLOCKLET_STORE_URL,
|
|
29
29
|
logoUrl: '/logo.png',
|
|
30
30
|
maintainer: 'arcblock',
|
|
31
31
|
selected: true,
|
|
32
32
|
protected: true,
|
|
33
33
|
},
|
|
34
34
|
{
|
|
35
|
-
name: 'Dev
|
|
35
|
+
name: 'Dev Store',
|
|
36
36
|
description: 'ArcBlock dev registry that contains demo and example blocklets',
|
|
37
|
-
url:
|
|
37
|
+
url: BLOCKLET_STORE_URL_DEV,
|
|
38
38
|
maintainer: 'arcblock',
|
|
39
39
|
logoUrl: '/logo.png',
|
|
40
40
|
selected: false,
|
package/lib/util/index.js
CHANGED
|
@@ -29,7 +29,9 @@ const {
|
|
|
29
29
|
ROUTING_RULE_TYPES,
|
|
30
30
|
SLOT_FOR_IP_DNS_SITE,
|
|
31
31
|
DEFAULT_IP_DNS_DOMAIN_SUFFIX,
|
|
32
|
+
BLOCKLET_SITE_GROUP_SUFFIX,
|
|
32
33
|
} = require('@abtnode/constant');
|
|
34
|
+
const { BLOCKLET_INTERFACE_TYPE_WEB } = require('@blocklet/meta/lib/constants');
|
|
33
35
|
|
|
34
36
|
const DEFAULT_WELLKNOWN_PORT = 8088;
|
|
35
37
|
|
|
@@ -137,7 +139,7 @@ const getAuthConfig = (rule, blocklet) => {
|
|
|
137
139
|
// find interface in meta
|
|
138
140
|
const interfaceName = rule.to.realInterfaceName;
|
|
139
141
|
const { interfaces } = _blocklet.meta;
|
|
140
|
-
const _interface = interfaces.find((x) => x.type ===
|
|
142
|
+
const _interface = interfaces.find((x) => x.type === BLOCKLET_INTERFACE_TYPE_WEB && x.name === interfaceName);
|
|
141
143
|
|
|
142
144
|
if (!_interface) {
|
|
143
145
|
return null;
|
|
@@ -155,13 +157,14 @@ const getAuthConfig = (rule, blocklet) => {
|
|
|
155
157
|
return auth.config;
|
|
156
158
|
};
|
|
157
159
|
|
|
158
|
-
const getBlockletBaseUrls = ({ routingEnabled = false, port,
|
|
160
|
+
const getBlockletBaseUrls = ({ routingEnabled = false, port, rules = [], context = {}, blocklet, nodeIp }) => {
|
|
159
161
|
let baseUrls = [];
|
|
160
162
|
|
|
161
|
-
if (routingEnabled && Array.isArray(
|
|
162
|
-
baseUrls =
|
|
163
|
-
.
|
|
164
|
-
|
|
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 });
|
|
165
168
|
if (host) {
|
|
166
169
|
let protocol = 'http'; // TODO: 这里固定为 http, 因为判断 url 是不是 https 和证书相关,这里实现的话比较复杂
|
|
167
170
|
if (host.includes(DEFAULT_IP_DNS_DOMAIN_SUFFIX)) {
|
|
@@ -169,10 +172,10 @@ const getBlockletBaseUrls = ({ routingEnabled = false, port, sites = [], context
|
|
|
169
172
|
}
|
|
170
173
|
|
|
171
174
|
return {
|
|
172
|
-
ruleId:
|
|
173
|
-
baseUrl: `${protocol}://${host}/${trimSlash(
|
|
174
|
-
interfaceName: get(
|
|
175
|
-
authConfig: getAuthConfig(
|
|
175
|
+
ruleId: rule.id,
|
|
176
|
+
baseUrl: `${protocol}://${host}/${trimSlash(rule.from.pathPrefix)}`,
|
|
177
|
+
interfaceName: get(rule, 'to.interfaceName', ''),
|
|
178
|
+
authConfig: getAuthConfig(rule, blocklet),
|
|
176
179
|
};
|
|
177
180
|
}
|
|
178
181
|
|
|
@@ -188,7 +191,7 @@ const getBlockletBaseUrls = ({ routingEnabled = false, port, sites = [], context
|
|
|
188
191
|
return baseUrls;
|
|
189
192
|
};
|
|
190
193
|
|
|
191
|
-
const getBlockletInterfaces = ({ blocklet, context, nodeInfo,
|
|
194
|
+
const getBlockletInterfaces = ({ blocklet, context, nodeInfo, routingRules, nodeIp }) => {
|
|
192
195
|
const interfaces = [];
|
|
193
196
|
(blocklet.meta.interfaces || []).forEach((x) => {
|
|
194
197
|
if (x.port && x.port.external) {
|
|
@@ -196,7 +199,7 @@ const getBlockletInterfaces = ({ blocklet, context, nodeInfo, sites, nodeIp }) =
|
|
|
196
199
|
const baseUrls = getBlockletBaseUrls({
|
|
197
200
|
routingEnabled: false,
|
|
198
201
|
port: x.port.external,
|
|
199
|
-
|
|
202
|
+
rules: [],
|
|
200
203
|
context,
|
|
201
204
|
});
|
|
202
205
|
baseUrls.forEach(({ baseUrl }) => interfaces.push({ type: x.type, name: x.name, url: baseUrl }));
|
|
@@ -206,9 +209,11 @@ const getBlockletInterfaces = ({ blocklet, context, nodeInfo, sites, nodeIp }) =
|
|
|
206
209
|
const baseUrls = getBlockletBaseUrls({
|
|
207
210
|
routingEnabled: isRoutingEnabled(nodeInfo.routing),
|
|
208
211
|
port,
|
|
209
|
-
|
|
212
|
+
rules: (routingRules || []).filter((r) => {
|
|
210
213
|
return (
|
|
211
214
|
// don't show wellknown interface
|
|
215
|
+
r.to.type !== ROUTING_RULE_TYPES.GENERAL_PROXY &&
|
|
216
|
+
// LEGACY don't show wellknown interface
|
|
212
217
|
r.to.interfaceName !== BLOCKLET_INTERFACE_WELLKNOWN &&
|
|
213
218
|
// don't show child blocklet interface
|
|
214
219
|
(!r.from.groupPathPrefix || r.from.pathPrefix === r.from.groupPathPrefix)
|
|
@@ -329,7 +334,7 @@ const getDataDirs = (dataDir) => ({
|
|
|
329
334
|
services: path.join(dataDir, 'services'),
|
|
330
335
|
});
|
|
331
336
|
|
|
332
|
-
// Ensure data dir for
|
|
337
|
+
// Ensure data dir for Blocklet Server exists
|
|
333
338
|
const ensureDataDirs = (dataDir) => {
|
|
334
339
|
try {
|
|
335
340
|
logger.info('ensure data dir', { dataDir });
|
package/lib/util/ready.js
CHANGED
|
@@ -29,19 +29,19 @@ const createStateReadyHandler =
|
|
|
29
29
|
// eslint-disable-next-line no-underscore-dangle
|
|
30
30
|
await states.node.remove({ _id: state._id });
|
|
31
31
|
console.error('\n\x1b[31m======================================================');
|
|
32
|
-
console.error(`Data dir: ${options.dataDir} is used by another
|
|
33
|
-
console.error('Sharing data dir between
|
|
32
|
+
console.error(`Data dir: ${options.dataDir} is used by another Blocklet Server instance, abort!`);
|
|
33
|
+
console.error('Sharing data dir between Blocklet Server instances may break things!');
|
|
34
34
|
console.error('======================================================\x1b[0m');
|
|
35
35
|
console.log('\nIf you intend to use this dir:');
|
|
36
|
-
console.log(` 1. Stop
|
|
36
|
+
console.log(` 1. Stop Blocklet Server by ${chalk.cyan('abtnode stop --force')}`);
|
|
37
37
|
console.log(` 2. Clear data dir by ${chalk.cyan(`rm -r ${options.dataDir}`)}`);
|
|
38
|
-
console.log(
|
|
38
|
+
console.log(' 3. Reinitialize and start Blocklet Server');
|
|
39
39
|
process.exit(1);
|
|
40
40
|
}
|
|
41
41
|
}
|
|
42
42
|
})
|
|
43
43
|
.catch((err) => {
|
|
44
|
-
console.error('Can not ready node state on
|
|
44
|
+
console.error('Can not ready node state on Blocklet Server start:', err.message);
|
|
45
45
|
process.exit(1);
|
|
46
46
|
});
|
|
47
47
|
};
|
package/lib/util/upgrade.js
CHANGED
|
@@ -36,15 +36,15 @@ const checkNewVersion = async (params, context) => {
|
|
|
36
36
|
const latestVersion = versions[0].version;
|
|
37
37
|
if (semver.gt(latestVersion, info.version)) {
|
|
38
38
|
// if (semver.gte(latestVersion, info.version)) {
|
|
39
|
-
logger.info('New version found for
|
|
39
|
+
logger.info('New version found for Blocklet Server', {
|
|
40
40
|
latestVersion,
|
|
41
41
|
currentVersion: info.version,
|
|
42
42
|
nextVersion: info.nextVersion,
|
|
43
43
|
});
|
|
44
44
|
await states.node.updateNodeInfo({ nextVersion: latestVersion });
|
|
45
45
|
await states.notification.create({
|
|
46
|
-
title: '
|
|
47
|
-
description: 'A new and improved version of
|
|
46
|
+
title: 'Blocklet Server upgrade available',
|
|
47
|
+
description: 'A new and improved version of blocklet server is now available',
|
|
48
48
|
entityType: 'node',
|
|
49
49
|
severity: 'info',
|
|
50
50
|
sticky: true,
|
|
@@ -57,7 +57,7 @@ const checkNewVersion = async (params, context) => {
|
|
|
57
57
|
|
|
58
58
|
return '';
|
|
59
59
|
} catch (err) {
|
|
60
|
-
logger.error('Failed to check new version for
|
|
60
|
+
logger.error('Failed to check new version for Blocklet Server', { error: err });
|
|
61
61
|
}
|
|
62
62
|
|
|
63
63
|
return '';
|
package/lib/validators/router.js
CHANGED
|
@@ -83,6 +83,13 @@ const corsSchema = Joi.array()
|
|
|
83
83
|
|
|
84
84
|
const ruleJoiSchema = Joi.object(ruleSchema);
|
|
85
85
|
|
|
86
|
+
const addDomainAlias = Joi.alternatives()
|
|
87
|
+
.try(
|
|
88
|
+
Joi.string().domain({ minDomainSegments: 1, tlds: false }),
|
|
89
|
+
Joi.string().regex(WILDCARD_DOMAIN_REGEX) // 这种其实是一种特殊的 tld
|
|
90
|
+
)
|
|
91
|
+
.required();
|
|
92
|
+
|
|
86
93
|
const addSiteSchema = Joi.object({
|
|
87
94
|
domain: Joi.alternatives()
|
|
88
95
|
.try(
|
|
@@ -92,6 +99,12 @@ const addSiteSchema = Joi.object({
|
|
|
92
99
|
)
|
|
93
100
|
.required()
|
|
94
101
|
.messages(domainMessages),
|
|
102
|
+
domainAliases: Joi.array().items(
|
|
103
|
+
Joi.object({
|
|
104
|
+
value: addDomainAlias,
|
|
105
|
+
isProtected: Joi.boolean(),
|
|
106
|
+
})
|
|
107
|
+
),
|
|
95
108
|
isProtected: Joi.boolean(),
|
|
96
109
|
rules: Joi.array().items(ruleJoiSchema),
|
|
97
110
|
corsAllowedOrigins: corsSchema,
|
|
@@ -109,13 +122,6 @@ const updateSite = Joi.object({
|
|
|
109
122
|
.messages(domainMessages),
|
|
110
123
|
});
|
|
111
124
|
|
|
112
|
-
const addDomainAlias = Joi.alternatives()
|
|
113
|
-
.try(
|
|
114
|
-
Joi.string().domain({ minDomainSegments: 1, tlds: false }),
|
|
115
|
-
Joi.string().regex(WILDCARD_DOMAIN_REGEX) // 这种其实是一种特殊的 tld
|
|
116
|
-
)
|
|
117
|
-
.required();
|
|
118
|
-
|
|
119
125
|
const addRuleSchema = Joi.object({
|
|
120
126
|
id: Joi.string().required(),
|
|
121
127
|
rule: ruleJoiSchema,
|
package/lib/webhook/index.js
CHANGED
|
@@ -15,7 +15,7 @@ const getSlackUrlInfo = (actionPath = '/notifications', urls) => {
|
|
|
15
15
|
type: 'section',
|
|
16
16
|
text: {
|
|
17
17
|
type: 'mrkdwn',
|
|
18
|
-
text: 'Use the following links to visit the blocklet detail on your
|
|
18
|
+
text: 'Use the following links to visit the blocklet detail on your Blocklet Server dashboard:',
|
|
19
19
|
},
|
|
20
20
|
});
|
|
21
21
|
} else {
|
|
@@ -23,7 +23,7 @@ const getSlackUrlInfo = (actionPath = '/notifications', urls) => {
|
|
|
23
23
|
type: 'section',
|
|
24
24
|
text: {
|
|
25
25
|
type: 'mrkdwn',
|
|
26
|
-
text: 'Use the following links to visit your
|
|
26
|
+
text: 'Use the following links to visit your Blocklet Server dashboard:',
|
|
27
27
|
},
|
|
28
28
|
});
|
|
29
29
|
}
|
package/package.json
CHANGED
|
@@ -3,7 +3,7 @@
|
|
|
3
3
|
"publishConfig": {
|
|
4
4
|
"access": "public"
|
|
5
5
|
},
|
|
6
|
-
"version": "1.5.
|
|
6
|
+
"version": "1.5.15",
|
|
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.5.
|
|
23
|
-
"@abtnode/cron": "1.5.
|
|
24
|
-
"@abtnode/logger": "1.5.
|
|
25
|
-
"@abtnode/queue": "1.5.
|
|
26
|
-
"@abtnode/rbac": "1.5.
|
|
27
|
-
"@abtnode/router-provider": "1.5.
|
|
28
|
-
"@abtnode/static-server": "1.5.
|
|
29
|
-
"@abtnode/timemachine": "1.5.
|
|
30
|
-
"@abtnode/util": "1.5.
|
|
31
|
-
"@arcblock/did": "^1.13.
|
|
32
|
-
"@arcblock/event-hub": "1.13.
|
|
22
|
+
"@abtnode/constant": "1.5.15",
|
|
23
|
+
"@abtnode/cron": "1.5.15",
|
|
24
|
+
"@abtnode/logger": "1.5.15",
|
|
25
|
+
"@abtnode/queue": "1.5.15",
|
|
26
|
+
"@abtnode/rbac": "1.5.15",
|
|
27
|
+
"@abtnode/router-provider": "1.5.15",
|
|
28
|
+
"@abtnode/static-server": "1.5.15",
|
|
29
|
+
"@abtnode/timemachine": "1.5.15",
|
|
30
|
+
"@abtnode/util": "1.5.15",
|
|
31
|
+
"@arcblock/did": "^1.13.61",
|
|
32
|
+
"@arcblock/event-hub": "1.13.61",
|
|
33
33
|
"@arcblock/pm2-events": "^0.0.5",
|
|
34
|
-
"@arcblock/vc": "^1.13.
|
|
35
|
-
"@blocklet/meta": "1.5.
|
|
34
|
+
"@arcblock/vc": "^1.13.61",
|
|
35
|
+
"@blocklet/meta": "1.5.15",
|
|
36
36
|
"@fidm/x509": "^1.2.1",
|
|
37
37
|
"@nedb/core": "^1.2.2",
|
|
38
38
|
"@nedb/multi": "^1.2.2",
|
|
39
|
-
"@ocap/mcrypto": "^1.13.
|
|
40
|
-
"@ocap/util": "^1.13.
|
|
41
|
-
"@ocap/wallet": "^1.13.
|
|
39
|
+
"@ocap/mcrypto": "^1.13.61",
|
|
40
|
+
"@ocap/util": "^1.13.61",
|
|
41
|
+
"@ocap/wallet": "^1.13.61",
|
|
42
42
|
"@slack/webhook": "^5.0.3",
|
|
43
43
|
"axios": "^0.21.4",
|
|
44
44
|
"axon": "^2.0.3",
|
|
@@ -73,5 +73,5 @@
|
|
|
73
73
|
"express": "^4.17.1",
|
|
74
74
|
"jest": "^27.3.1"
|
|
75
75
|
},
|
|
76
|
-
"gitHead": "
|
|
76
|
+
"gitHead": "dae9d209af2576152ad85f13a2fc4855969608ed"
|
|
77
77
|
}
|