@abtnode/core 1.6.6 → 1.6.10
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/manager/disk.js +56 -15
- package/lib/cert.js +124 -0
- package/lib/event.js +9 -2
- package/lib/index.js +30 -10
- package/lib/migrations/1.6.7-certificate.js +30 -0
- package/lib/migrations/1.6.9-update-node-info-and-certificate.js +38 -0
- package/lib/router/helper.js +132 -115
- package/lib/router/manager.js +9 -8
- package/lib/states/base.js +3 -220
- package/lib/states/index.js +4 -21
- package/lib/states/node.js +10 -1
- package/lib/util/blocklet.js +29 -4
- package/lib/util/{get-ip-dns-domain-for-blocklet.js → get-domain-for-blocklet.js} +5 -1
- package/lib/util/index.js +33 -19
- package/lib/util/ready.js +1 -1
- package/lib/webhook/index.js +3 -3
- package/package.json +22 -20
|
@@ -20,12 +20,13 @@ const hashFiles = require('@abtnode/util/lib/hash-files');
|
|
|
20
20
|
const downloadFile = require('@abtnode/util/lib/download-file');
|
|
21
21
|
const Lock = require('@abtnode/util/lib/lock');
|
|
22
22
|
const { getVcFromPresentation } = require('@abtnode/util/lib/vc');
|
|
23
|
+
const { updateBlocklet: updateDidDocument } = require('@abtnode/util/lib/did-document');
|
|
23
24
|
const { BLOCKLET_PURCHASE_NFT_TYPE } = require('@abtnode/constant');
|
|
24
25
|
|
|
25
26
|
const getBlockletEngine = require('@blocklet/meta/lib/engine');
|
|
26
|
-
const { isFreeBlocklet } = require('@blocklet/meta/lib/util');
|
|
27
|
+
const { isFreeBlocklet, isDeletableBlocklet, getRequiredMissingConfigs } = require('@blocklet/meta/lib/util');
|
|
27
28
|
const validateBlockletEntry = require('@blocklet/meta/lib/entry');
|
|
28
|
-
const {
|
|
29
|
+
const { getBlockletInfo } = require('@blocklet/meta/lib');
|
|
29
30
|
|
|
30
31
|
const {
|
|
31
32
|
BlockletStatus,
|
|
@@ -243,7 +244,7 @@ class BlockletManager extends BaseBlockletManager {
|
|
|
243
244
|
hooks.preStart(b, {
|
|
244
245
|
appDir: b.env.appDir,
|
|
245
246
|
hooks: Object.assign(b.meta.hooks || {}, b.meta.scripts || {}),
|
|
246
|
-
env: getRuntimeEnvironments(b, nodeEnvironments),
|
|
247
|
+
env: getRuntimeEnvironments(b, nodeEnvironments, blocklet),
|
|
247
248
|
did, // root blocklet did,
|
|
248
249
|
progress: blocklet.mode === BLOCKLET_MODES.DEVELOPMENT,
|
|
249
250
|
}),
|
|
@@ -315,7 +316,7 @@ class BlockletManager extends BaseBlockletManager {
|
|
|
315
316
|
hooks.preStop({
|
|
316
317
|
appDir: b.env.appDir,
|
|
317
318
|
hooks: Object.assign(b.meta.hooks || {}, b.meta.scripts || {}),
|
|
318
|
-
env: getRuntimeEnvironments(b, nodeEnvironments),
|
|
319
|
+
env: getRuntimeEnvironments(b, nodeEnvironments, blocklet),
|
|
319
320
|
did, // root blocklet did
|
|
320
321
|
notification: states.notification,
|
|
321
322
|
context,
|
|
@@ -380,6 +381,9 @@ class BlockletManager extends BaseBlockletManager {
|
|
|
380
381
|
|
|
381
382
|
try {
|
|
382
383
|
const blocklet = await this.ensureBlocklet(did);
|
|
384
|
+
if (isDeletableBlocklet(blocklet) === false) {
|
|
385
|
+
throw new Error('Blocklet is protected from accidental deletion');
|
|
386
|
+
}
|
|
383
387
|
|
|
384
388
|
const nodeEnvironments = await states.node.getEnvironments();
|
|
385
389
|
|
|
@@ -388,7 +392,7 @@ class BlockletManager extends BaseBlockletManager {
|
|
|
388
392
|
hooks.preUninstall({
|
|
389
393
|
appDir: b.env.appDir,
|
|
390
394
|
hooks: Object.assign(b.meta.hooks || {}, b.meta.scripts || {}),
|
|
391
|
-
env: getRuntimeEnvironments(b, nodeEnvironments),
|
|
395
|
+
env: getRuntimeEnvironments(b, nodeEnvironments, blocklet),
|
|
392
396
|
did, // root blocklet did
|
|
393
397
|
notification: states.notification,
|
|
394
398
|
context,
|
|
@@ -513,7 +517,7 @@ class BlockletManager extends BaseBlockletManager {
|
|
|
513
517
|
|
|
514
518
|
// run hook
|
|
515
519
|
const nodeEnvironments = await states.node.getEnvironments();
|
|
516
|
-
|
|
520
|
+
for (const x of newConfigs) {
|
|
517
521
|
if (x.key === 'BLOCKLET_APP_SK') {
|
|
518
522
|
try {
|
|
519
523
|
fromSecretKey(x.value);
|
|
@@ -524,6 +528,13 @@ class BlockletManager extends BaseBlockletManager {
|
|
|
524
528
|
throw new Error('Invalid custom blocklet secret key');
|
|
525
529
|
}
|
|
526
530
|
}
|
|
531
|
+
|
|
532
|
+
// Ensure sk is not used by other blocklets, otherwise we may encounter appDid collision
|
|
533
|
+
const blocklets = await states.blocklet.getBlocklets({});
|
|
534
|
+
const others = blocklets.filter((b) => b.meta.did !== did);
|
|
535
|
+
if (others.some((b) => b.environments.find((e) => e.key === 'BLOCKLET_APP_SK').value === x.value)) {
|
|
536
|
+
throw new Error('Invalid custom blocklet secret key: already used by another blocklet');
|
|
537
|
+
}
|
|
527
538
|
}
|
|
528
539
|
|
|
529
540
|
if (x.key === 'BLOCKLET_WALLET_TYPE') {
|
|
@@ -532,8 +543,16 @@ class BlockletManager extends BaseBlockletManager {
|
|
|
532
543
|
}
|
|
533
544
|
}
|
|
534
545
|
|
|
546
|
+
if (x.key === 'BLOCKLET_DELETABLE') {
|
|
547
|
+
if (['yes', 'no'].includes(x.value) === false) {
|
|
548
|
+
throw new Error('BLOCKLET_DELETABLE must be either "yes" or "no"');
|
|
549
|
+
}
|
|
550
|
+
}
|
|
551
|
+
|
|
535
552
|
blocklet.configObj[x.key] = x.value;
|
|
536
|
-
}
|
|
553
|
+
}
|
|
554
|
+
|
|
555
|
+
// FIXME: we should also call preConfig for child blocklets
|
|
537
556
|
await hooks.preConfig({
|
|
538
557
|
appDir: blocklet.env.appDir,
|
|
539
558
|
hooks: Object.assign(blocklet.meta.hooks || {}, blocklet.meta.scripts || {}),
|
|
@@ -897,7 +916,7 @@ class BlockletManager extends BaseBlockletManager {
|
|
|
897
916
|
};
|
|
898
917
|
|
|
899
918
|
const childConfigs = await states.blockletExtras.getChildConfigs(did, childDid);
|
|
900
|
-
fillBlockletConfigs(child, childConfigs);
|
|
919
|
+
fillBlockletConfigs(child, childConfigs, blocklet);
|
|
901
920
|
}
|
|
902
921
|
|
|
903
922
|
return blocklet;
|
|
@@ -1496,6 +1515,15 @@ class BlockletManager extends BaseBlockletManager {
|
|
|
1496
1515
|
return null;
|
|
1497
1516
|
}
|
|
1498
1517
|
|
|
1518
|
+
// When new version found from the store where the blocklet was installed from, we should use that store first
|
|
1519
|
+
if (blocklet.source === BlockletSource.registry && blocklet.deployedFrom) {
|
|
1520
|
+
const latestFromSameRegistry = versions.find((x) => x.registryUrl === blocklet.deployedFrom);
|
|
1521
|
+
if (latestFromSameRegistry) {
|
|
1522
|
+
return latestFromSameRegistry;
|
|
1523
|
+
}
|
|
1524
|
+
}
|
|
1525
|
+
|
|
1526
|
+
// Otherwise try upgrading from other store
|
|
1499
1527
|
let latestBlockletVersion = versions[0];
|
|
1500
1528
|
versions.forEach((item) => {
|
|
1501
1529
|
if (semver.lt(latestBlockletVersion.version, item.version)) {
|
|
@@ -1561,7 +1589,7 @@ class BlockletManager extends BaseBlockletManager {
|
|
|
1561
1589
|
|
|
1562
1590
|
await this._setConfigs(did);
|
|
1563
1591
|
|
|
1564
|
-
logger.info('blocklet added to database', { meta });
|
|
1592
|
+
logger.info('blocklet added to database', { did: meta.did });
|
|
1565
1593
|
|
|
1566
1594
|
const blocklet1 = await states.blocklet.setBlockletStatus(did, BlockletStatus.waiting);
|
|
1567
1595
|
this.emit(BlockletEvents.added, blocklet1);
|
|
@@ -1855,7 +1883,7 @@ class BlockletManager extends BaseBlockletManager {
|
|
|
1855
1883
|
const postInstall = (b) =>
|
|
1856
1884
|
hooks.postInstall({
|
|
1857
1885
|
hooks: Object.assign(b.meta.hooks || {}, b.meta.scripts || {}),
|
|
1858
|
-
env: getRuntimeEnvironments(b, nodeEnvironments),
|
|
1886
|
+
env: getRuntimeEnvironments(b, nodeEnvironments, blocklet),
|
|
1859
1887
|
appDir: blocklet.env.appDir,
|
|
1860
1888
|
did, // root blocklet did
|
|
1861
1889
|
notification: states.notification,
|
|
@@ -1865,7 +1893,19 @@ class BlockletManager extends BaseBlockletManager {
|
|
|
1865
1893
|
|
|
1866
1894
|
await states.blocklet.setBlockletStatus(did, BlockletStatus.installed);
|
|
1867
1895
|
blocklet = await this.ensureBlocklet(did);
|
|
1868
|
-
logger.info('blocklet installed', { source, meta });
|
|
1896
|
+
logger.info('blocklet installed', { source, did: meta.did });
|
|
1897
|
+
if (process.env.NODE_ENV !== 'test') {
|
|
1898
|
+
const nodeInfo = await states.node.read();
|
|
1899
|
+
const blockletInfo = getBlockletInfo(blocklet, nodeInfo.sk);
|
|
1900
|
+
const updateDidDnsResult = await updateDidDocument({
|
|
1901
|
+
wallet: blockletInfo.wallet,
|
|
1902
|
+
domain: nodeInfo.didDomain,
|
|
1903
|
+
nodeDid: nodeInfo.did,
|
|
1904
|
+
didRegistryUrl: nodeInfo.didRegistry,
|
|
1905
|
+
});
|
|
1906
|
+
logger.info('updated did document', { updateDidDnsResult, blockletId: blocklet.meta.did });
|
|
1907
|
+
}
|
|
1908
|
+
|
|
1869
1909
|
this.emit(BlockletEvents.installed, { blocklet, context });
|
|
1870
1910
|
|
|
1871
1911
|
states.notification.create({
|
|
@@ -1943,7 +1983,7 @@ class BlockletManager extends BaseBlockletManager {
|
|
|
1943
1983
|
const postInstall = (b) =>
|
|
1944
1984
|
hooks.postInstall({
|
|
1945
1985
|
hooks: Object.assign(b.meta.hooks || {}, b.meta.scripts || {}),
|
|
1946
|
-
env: getRuntimeEnvironments(b, nodeEnvironments),
|
|
1986
|
+
env: getRuntimeEnvironments(b, nodeEnvironments, blocklet),
|
|
1947
1987
|
appDir: b.env.appDir,
|
|
1948
1988
|
did, // root blocklet did
|
|
1949
1989
|
notification: states.notification,
|
|
@@ -1959,7 +1999,7 @@ class BlockletManager extends BaseBlockletManager {
|
|
|
1959
1999
|
blocklet: b,
|
|
1960
2000
|
oldVersion,
|
|
1961
2001
|
newVersion: version,
|
|
1962
|
-
env: getRuntimeEnvironments(b, nodeEnvironments),
|
|
2002
|
+
env: getRuntimeEnvironments(b, nodeEnvironments, blocklet),
|
|
1963
2003
|
appDir: b.env.appDir,
|
|
1964
2004
|
did: b.meta.did,
|
|
1965
2005
|
notification: states.notification,
|
|
@@ -2251,8 +2291,9 @@ class BlockletManager extends BaseBlockletManager {
|
|
|
2251
2291
|
try {
|
|
2252
2292
|
const state = await states.blocklet.getBlocklet(did);
|
|
2253
2293
|
if (state && util.shouldUpdateBlockletStatus(state.status)) {
|
|
2254
|
-
const
|
|
2255
|
-
|
|
2294
|
+
const newStatus = pm2StatusMap[pm2Status];
|
|
2295
|
+
await states.blocklet.setBlockletStatus(did, newStatus);
|
|
2296
|
+
logger.info('sync pm2 status to blocklet', { did, pm2Status, newStatus });
|
|
2256
2297
|
}
|
|
2257
2298
|
} catch (error) {
|
|
2258
2299
|
logger.error('sync pm2 status to blocklet failed', { did, pm2Status, error });
|
package/lib/cert.js
ADDED
|
@@ -0,0 +1,124 @@
|
|
|
1
|
+
const { EventEmitter } = require('events');
|
|
2
|
+
const CertificateManager = require('@abtnode/certificate-manager/sdk/manager');
|
|
3
|
+
const logger = require('@abtnode/logger')('@abtnode/core:cert');
|
|
4
|
+
const states = require('./states');
|
|
5
|
+
|
|
6
|
+
const onCertExpired = async (cert) => {
|
|
7
|
+
logger.info('send certificate expire notification', { domain: cert.domain });
|
|
8
|
+
states.notification.create({
|
|
9
|
+
title: 'SSL Certificate Expired',
|
|
10
|
+
description: `Your SSL certificate for domain ${cert.domain} has expired, please update it in Blocklet Server`,
|
|
11
|
+
severity: 'error',
|
|
12
|
+
entityType: 'certificate',
|
|
13
|
+
entityId: cert.id,
|
|
14
|
+
});
|
|
15
|
+
};
|
|
16
|
+
|
|
17
|
+
const onCertAboutExpire = (cert) => {
|
|
18
|
+
logger.info('send certificate about-expire notification', { domain: cert.domain });
|
|
19
|
+
states.notification.create({
|
|
20
|
+
title: 'SSL Certificate Expire Warning',
|
|
21
|
+
description: `Your SSL certificate for domain ${cert.domain} will expire in ${
|
|
22
|
+
cert.expireInDays
|
|
23
|
+
} days (on ${new Date(cert.validTo).toLocaleString()}), please remember to update it in Blocklet Server`,
|
|
24
|
+
severity: 'warning',
|
|
25
|
+
entityType: 'certificate',
|
|
26
|
+
entityId: cert.id, // eslint-disable-line no-underscore-dangle
|
|
27
|
+
});
|
|
28
|
+
};
|
|
29
|
+
|
|
30
|
+
const onCertIssued = (cert) => {
|
|
31
|
+
states.notification.create({
|
|
32
|
+
title: 'Certificate Issued',
|
|
33
|
+
description: `The ${cert.domain} certificate is issued successfully`,
|
|
34
|
+
severity: 'success',
|
|
35
|
+
entityType: 'certificate',
|
|
36
|
+
entityId: cert.id,
|
|
37
|
+
});
|
|
38
|
+
};
|
|
39
|
+
|
|
40
|
+
class Cert extends EventEmitter {
|
|
41
|
+
constructor({ maintainerEmail, dataDir }) {
|
|
42
|
+
super();
|
|
43
|
+
|
|
44
|
+
this.manager = new CertificateManager({ maintainerEmail, dataDir });
|
|
45
|
+
|
|
46
|
+
this.manager.on('cert.issued', (cert) => {
|
|
47
|
+
this.emit('cert.issued', cert);
|
|
48
|
+
onCertIssued(cert);
|
|
49
|
+
});
|
|
50
|
+
|
|
51
|
+
this.manager.on('cert.expired', onCertExpired);
|
|
52
|
+
this.manager.on('cert.about_to_expire', onCertAboutExpire);
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
start() {
|
|
56
|
+
return this.manager.start();
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
static fixCertificate(entity) {
|
|
60
|
+
// Hack: this logic exists because gql does not allow line breaks in arg values
|
|
61
|
+
entity.privateKey = entity.privateKey.split('|').join('\n');
|
|
62
|
+
entity.certificate = entity.certificate.split('|').join('\n');
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
getAll() {
|
|
66
|
+
return this.manager.getAll();
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
getAllNormal() {
|
|
70
|
+
return this.manager.getAllNormal();
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
getNormalByDomain(domain) {
|
|
74
|
+
return this.manager.getNormalByDomain(domain);
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
getByDomain(domain) {
|
|
78
|
+
return this.manager.getByDomain(domain);
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
async add(data) {
|
|
82
|
+
if (!data.certificate || !data.privateKey) {
|
|
83
|
+
throw new Error('certificate and privateKey is required');
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
Cert.fixCertificate(data);
|
|
87
|
+
|
|
88
|
+
await this.manager.add(data);
|
|
89
|
+
logger.info('add certificate result', { name: data.name });
|
|
90
|
+
this.emit('cert.added', data);
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
async issue({ domain }) {
|
|
94
|
+
logger.info(`generate certificate for ${domain}`);
|
|
95
|
+
|
|
96
|
+
return this.manager.issue(domain);
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
async upsertByDomain(data) {
|
|
100
|
+
return this.manager.upsertByDomain(data);
|
|
101
|
+
}
|
|
102
|
+
|
|
103
|
+
async update(data) {
|
|
104
|
+
return this.manager.update(data.id, { name: data.name, public: data.public });
|
|
105
|
+
}
|
|
106
|
+
|
|
107
|
+
async remove({ id }) {
|
|
108
|
+
await this.manager.remove(id);
|
|
109
|
+
logger.info('delete certificate', { id });
|
|
110
|
+
this.emit('cert.removed');
|
|
111
|
+
|
|
112
|
+
return {};
|
|
113
|
+
}
|
|
114
|
+
|
|
115
|
+
async addWithoutValidations(data) {
|
|
116
|
+
return this.manager.addWithoutValidations(data);
|
|
117
|
+
}
|
|
118
|
+
|
|
119
|
+
async updateWithoutValidations(id, data) {
|
|
120
|
+
return this.manager.updateWithoutValidations(id, data);
|
|
121
|
+
}
|
|
122
|
+
}
|
|
123
|
+
|
|
124
|
+
module.exports = Cert;
|
package/lib/event.js
CHANGED
|
@@ -1,5 +1,8 @@
|
|
|
1
|
+
const get = require('lodash/get');
|
|
2
|
+
const cloneDeep = require('lodash/cloneDeep');
|
|
1
3
|
const { EventEmitter } = require('events');
|
|
2
4
|
const { BLOCKLET_MODES } = require('@blocklet/meta/lib/constants');
|
|
5
|
+
const { wipeSensitiveData } = require('@blocklet/meta/lib/util');
|
|
3
6
|
const logger = require('@abtnode/logger')('@abtnode/core:event');
|
|
4
7
|
const { BlockletStatus, BlockletSource, BlockletEvents } = require('@blocklet/meta/lib/constants');
|
|
5
8
|
|
|
@@ -43,9 +46,13 @@ module.exports = ({
|
|
|
43
46
|
let eventHandler = null;
|
|
44
47
|
|
|
45
48
|
const onEvent = (name, data) => {
|
|
46
|
-
|
|
49
|
+
let safeData = data;
|
|
50
|
+
if (get(data, 'meta.did', '')) {
|
|
51
|
+
safeData = wipeSensitiveData(cloneDeep(data));
|
|
52
|
+
}
|
|
53
|
+
events.emit(name, safeData);
|
|
47
54
|
if (typeof eventHandler === 'function') {
|
|
48
|
-
eventHandler({ name, data });
|
|
55
|
+
eventHandler({ name, data: safeData });
|
|
49
56
|
}
|
|
50
57
|
};
|
|
51
58
|
|
package/lib/index.js
CHANGED
|
@@ -11,6 +11,7 @@ const {
|
|
|
11
11
|
toBlockletSource,
|
|
12
12
|
} = require('@blocklet/meta/lib/constants');
|
|
13
13
|
const { listProviders } = require('@abtnode/router-provider');
|
|
14
|
+
const { DEFAULT_CERTIFICATE_EMAIL } = require('@abtnode/constant');
|
|
14
15
|
|
|
15
16
|
const RoutingSnapshot = require('./states/routing-snapshot');
|
|
16
17
|
const BlockletRegistry = require('./blocklet/registry');
|
|
@@ -22,6 +23,7 @@ const NodeAPI = require('./api/node');
|
|
|
22
23
|
const TeamAPI = require('./api/team');
|
|
23
24
|
const WebHook = require('./webhook');
|
|
24
25
|
const states = require('./states');
|
|
26
|
+
const Cert = require('./cert');
|
|
25
27
|
|
|
26
28
|
const IP = require('./util/ip');
|
|
27
29
|
const DomainStatus = require('./util/domain-status');
|
|
@@ -108,7 +110,11 @@ function ABTNode(options) {
|
|
|
108
110
|
// Initialize storage
|
|
109
111
|
states.init(dataDirs, options);
|
|
110
112
|
|
|
111
|
-
const
|
|
113
|
+
const certManager = new Cert({
|
|
114
|
+
maintainerEmail: DEFAULT_CERTIFICATE_EMAIL,
|
|
115
|
+
dataDir: dataDirs.certManagerModule,
|
|
116
|
+
});
|
|
117
|
+
const routerManager = new RouterManager({ certManager });
|
|
112
118
|
const routingSnapshot = new RoutingSnapshot({
|
|
113
119
|
baseDir: dataDirs.core,
|
|
114
120
|
getRoutingData: async () => {
|
|
@@ -117,7 +123,6 @@ function ABTNode(options) {
|
|
|
117
123
|
return { sites };
|
|
118
124
|
},
|
|
119
125
|
});
|
|
120
|
-
|
|
121
126
|
const blockletRegistry = new BlockletRegistry();
|
|
122
127
|
const blockletManager = new BlockletManager({
|
|
123
128
|
dataDirs,
|
|
@@ -141,10 +146,10 @@ function ABTNode(options) {
|
|
|
141
146
|
getCertificates,
|
|
142
147
|
getSitesFromSnapshot,
|
|
143
148
|
getRoutingCrons,
|
|
144
|
-
|
|
149
|
+
ensureDashboardCertificate,
|
|
150
|
+
} = getRouterHelpers({ dataDirs, routingSnapshot, routerManager, blockletManager, certManager });
|
|
145
151
|
|
|
146
152
|
const teamManager = new TeamManager({ nodeDid: options.nodeDid, dataDirs, states });
|
|
147
|
-
|
|
148
153
|
const nodeAPI = new NodeAPI(states.node, blockletRegistry);
|
|
149
154
|
const teamAPI = new TeamAPI({ states, teamManager });
|
|
150
155
|
|
|
@@ -162,10 +167,10 @@ function ABTNode(options) {
|
|
|
162
167
|
ensureBlockletRoutingForUpgrade,
|
|
163
168
|
removeBlockletRouting,
|
|
164
169
|
takeRoutingSnapshot,
|
|
165
|
-
routerManager,
|
|
166
170
|
handleRouting,
|
|
167
171
|
domainStatus,
|
|
168
172
|
teamAPI,
|
|
173
|
+
certManager,
|
|
169
174
|
});
|
|
170
175
|
|
|
171
176
|
const isInitialized = async () => {
|
|
@@ -311,6 +316,7 @@ function ABTNode(options) {
|
|
|
311
316
|
takeRoutingSnapshot,
|
|
312
317
|
getSitesFromSnapshot,
|
|
313
318
|
ensureDashboardRouting,
|
|
319
|
+
ensureDashboardCertificate,
|
|
314
320
|
|
|
315
321
|
addDomainAlias: routerManager.addDomainAlias.bind(routerManager),
|
|
316
322
|
deleteDomainAlias: routerManager.deleteDomainAlias.bind(routerManager),
|
|
@@ -319,11 +325,13 @@ function ABTNode(options) {
|
|
|
319
325
|
checkDomains: domainStatus.checkDomainsStatus.bind(domainStatus),
|
|
320
326
|
handleRouting,
|
|
321
327
|
|
|
322
|
-
|
|
328
|
+
certManager,
|
|
329
|
+
updateNginxHttpsCert: certManager.update.bind(certManager), // TODO: 重命名:updateCert
|
|
323
330
|
getCertificates,
|
|
324
|
-
addCertificate:
|
|
325
|
-
deleteCertificate:
|
|
326
|
-
findCertificateByDomain:
|
|
331
|
+
addCertificate: certManager.add.bind(certManager),
|
|
332
|
+
deleteCertificate: certManager.remove.bind(certManager),
|
|
333
|
+
findCertificateByDomain: certManager.getByDomain.bind(certManager),
|
|
334
|
+
issueLetsEncryptCert: certManager.issue.bind(certManager),
|
|
327
335
|
|
|
328
336
|
// Access Key
|
|
329
337
|
getAccessKeys: states.accessKey.list.bind(states.accessKey),
|
|
@@ -385,11 +393,23 @@ function ABTNode(options) {
|
|
|
385
393
|
};
|
|
386
394
|
|
|
387
395
|
if (options.daemon) {
|
|
396
|
+
certManager.start(); // 启动证书服务
|
|
397
|
+
|
|
388
398
|
if (process.env.NODE_ENV === 'development') {
|
|
389
399
|
initCron();
|
|
390
400
|
} else {
|
|
391
401
|
// We should only respond to pm2 events when node is alive
|
|
392
|
-
events.on('node.started', () => {
|
|
402
|
+
events.on('node.started', async () => {
|
|
403
|
+
const info = await states.node.read();
|
|
404
|
+
certManager
|
|
405
|
+
.issue({ domain: `${info.did.toLowerCase()}.${info.didDomain}` })
|
|
406
|
+
.then(() => {
|
|
407
|
+
logger.info('add issue daemon certificate job');
|
|
408
|
+
})
|
|
409
|
+
.catch((error) => {
|
|
410
|
+
logger.error('issue daemon certificate job failed', { error });
|
|
411
|
+
});
|
|
412
|
+
|
|
393
413
|
pm2Events.resume();
|
|
394
414
|
initCron();
|
|
395
415
|
});
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
module.exports = async ({ states, node, printInfo }) => {
|
|
2
|
+
printInfo('Migrate certificates...');
|
|
3
|
+
const certs = await states.certificate.find(
|
|
4
|
+
{},
|
|
5
|
+
{
|
|
6
|
+
domain: 1,
|
|
7
|
+
privateKey: 1,
|
|
8
|
+
certificate: 1,
|
|
9
|
+
createdAt: 1,
|
|
10
|
+
updatedAt: 1,
|
|
11
|
+
}
|
|
12
|
+
);
|
|
13
|
+
|
|
14
|
+
const tasks = certs.map((cert) => {
|
|
15
|
+
const data = {
|
|
16
|
+
_id: cert.id,
|
|
17
|
+
domain: cert.domain,
|
|
18
|
+
privateKey: cert.privateKey,
|
|
19
|
+
certificate: cert.certificate,
|
|
20
|
+
createdAt: cert.createdAt,
|
|
21
|
+
updatedAt: cert.updatedAt,
|
|
22
|
+
source: 'lets_encrypt',
|
|
23
|
+
status: 'generated',
|
|
24
|
+
};
|
|
25
|
+
|
|
26
|
+
return node.certManager.addWithoutValidations(data);
|
|
27
|
+
});
|
|
28
|
+
|
|
29
|
+
await Promise.all(tasks);
|
|
30
|
+
};
|
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
/* eslint-disable no-await-in-loop */
|
|
2
|
+
|
|
3
|
+
const { DEFAULT_DID_REGISTRY, DEFAULT_DID_DOMAIN } = require('@abtnode/constant');
|
|
4
|
+
const { isEmpty, omit } = require('lodash');
|
|
5
|
+
|
|
6
|
+
const updateNodeInfo = async ({ printInfo, states }) => {
|
|
7
|
+
// add didRegistry and didDomain
|
|
8
|
+
const info = await states.node.read();
|
|
9
|
+
const data = {};
|
|
10
|
+
if (!info.didRegistry) {
|
|
11
|
+
data.didRegistry = DEFAULT_DID_REGISTRY;
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
if (!info.didDomain) {
|
|
15
|
+
data.didDomain = DEFAULT_DID_DOMAIN;
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
if (!isEmpty(data)) {
|
|
19
|
+
await states.node.update({ _id: info._id }, { $set: data });
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
printInfo('update did registry and did domain successfully');
|
|
23
|
+
};
|
|
24
|
+
|
|
25
|
+
const updateCertificate = async ({ node, printInfo }) => {
|
|
26
|
+
const certs = await node.certManager.getAllNormal();
|
|
27
|
+
for (const cert of certs || []) {
|
|
28
|
+
await node.certManager.updateWithoutValidations(cert.id, omit(cert, 'id'));
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
printInfo('update certificate successfully');
|
|
32
|
+
};
|
|
33
|
+
|
|
34
|
+
/* eslint-disable no-underscore-dangle */
|
|
35
|
+
module.exports = async ({ node, printInfo, states }) => {
|
|
36
|
+
await updateNodeInfo({ printInfo, states });
|
|
37
|
+
await updateCertificate({ node, printInfo, states });
|
|
38
|
+
};
|