underpost 2.7.83 → 2.7.91
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/.github/workflows/ghpkg.yml +41 -1
- package/.github/workflows/pwa-microservices-template.page.yml +54 -0
- package/.vscode/settings.json +7 -0
- package/CHANGELOG.md +64 -16
- package/bin/cron.js +47 -0
- package/bin/db.js +60 -7
- package/bin/deploy.js +345 -15
- package/bin/file.js +17 -1
- package/bin/index.js +1 -1
- package/bin/util.js +31 -1
- package/conf.js +18 -4
- package/docker-compose.yml +1 -1
- package/package.json +3 -3
- package/src/api/core/core.router.js +9 -9
- package/src/api/core/core.service.js +12 -4
- package/src/api/default/default.service.js +4 -4
- package/src/api/file/file.service.js +3 -3
- package/src/api/user/user.service.js +10 -8
- package/src/client/components/core/CommonJs.js +3 -0
- package/src/client/components/core/CssCore.js +30 -3
- package/src/client/components/core/Docs.js +110 -10
- package/src/client/components/core/LoadingAnimation.js +4 -2
- package/src/client/components/core/Modal.js +224 -22
- package/src/client/components/core/Panel.js +1 -1
- package/src/client/components/core/PanelForm.js +2 -1
- package/src/client/components/core/Responsive.js +34 -5
- package/src/client/components/core/RichText.js +4 -2
- package/src/client/components/core/WebComponent.js +44 -0
- package/src/client/components/core/Worker.js +13 -15
- package/src/client/public/default/plantuml/client-conf.svg +1 -1
- package/src/client/public/default/plantuml/client-schema.svg +1 -1
- package/src/client/public/default/plantuml/cron-conf.svg +1 -1
- package/src/client/public/default/plantuml/cron-schema.svg +1 -1
- package/src/client/public/default/plantuml/server-conf.svg +1 -1
- package/src/client/public/default/plantuml/server-schema.svg +1 -1
- package/src/client/public/default/plantuml/ssr-conf.svg +1 -1
- package/src/client/public/default/plantuml/ssr-schema.svg +1 -1
- package/src/client/public/default/site.webmanifest +69 -0
- package/src/client/ssr/components/body/CacheControl.js +1 -1
- package/src/client/ssr/components/head/Production.js +1 -0
- package/src/client/ssr/components/head/Pwa.js +146 -0
- package/src/client/ssr/components/head/Seo.js +14 -0
- package/src/client/ssr/pages/maintenance.js +14 -0
- package/src/client/ssr/pages/offline.js +21 -0
- package/src/client/sw/default.sw.js +4 -2
- package/src/db/DataBaseProvider.js +12 -1
- package/src/db/mongo/MongooseDB.js +0 -1
- package/src/runtime/lampp/Lampp.js +9 -9
- package/src/server/backup.js +82 -70
- package/src/server/client-build.js +46 -94
- package/src/server/conf.js +82 -18
- package/src/server/crypto.js +91 -0
- package/src/server/dns.js +48 -16
- package/src/server/network.js +94 -7
- package/src/server/proxy.js +27 -27
- package/src/server/runtime.js +4 -2
- package/src/server/ssl.js +2 -2
- package/src/client/ssr/offline/default.index.js +0 -31
- package/src/cron.js +0 -30
- package/src/server/cron.js +0 -35
|
@@ -0,0 +1,91 @@
|
|
|
1
|
+
import crypto from 'crypto';
|
|
2
|
+
import fs from 'fs-extra';
|
|
3
|
+
|
|
4
|
+
const CryptoBuilder = {
|
|
5
|
+
symmetric: {
|
|
6
|
+
instance: function (options = { iv: '', encryptionKey: '' }) {
|
|
7
|
+
// Generate a random 32-byte encryption key
|
|
8
|
+
const encryptionKey = option?.encryptionKey ? options.encryptionKey : crypto.randomBytes(32);
|
|
9
|
+
const iv = option?.iv ? options.iv : crypto.randomBytes(16); // Generate a new Initialization Vector (IV) for each encryption
|
|
10
|
+
|
|
11
|
+
// Function to encrypt data
|
|
12
|
+
function encryptData(plaintext = '') {
|
|
13
|
+
const cipher = crypto.createCipheriv('aes-256-cbc', encryptionKey, iv);
|
|
14
|
+
let encrypted = cipher.update(plaintext, 'utf8', 'hex');
|
|
15
|
+
encrypted += cipher.final('hex');
|
|
16
|
+
return `${iv.toString('hex')}:${encrypted}`;
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
// Function to decrypt data
|
|
20
|
+
function decryptData(ciphertext = '') {
|
|
21
|
+
const [ivHex, encrypted] = ciphertext.split(':');
|
|
22
|
+
const _iv = Buffer.from(ivHex, 'hex');
|
|
23
|
+
const decipher = crypto.createDecipheriv('aes-256-cbc', encryptionKey, _iv);
|
|
24
|
+
let decrypted = decipher.update(encrypted, 'hex', 'utf8');
|
|
25
|
+
decrypted += decipher.final('utf8');
|
|
26
|
+
return decrypted;
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
return {
|
|
30
|
+
encryptionKey,
|
|
31
|
+
iv,
|
|
32
|
+
encryptData,
|
|
33
|
+
decryptData,
|
|
34
|
+
};
|
|
35
|
+
},
|
|
36
|
+
},
|
|
37
|
+
asymmetric: {
|
|
38
|
+
instance: function (
|
|
39
|
+
options = {
|
|
40
|
+
publicKey: '', // fs.readFileSync('./key.pem', 'utf8')
|
|
41
|
+
privateKey: '', // fs.readFileSync('./key.pem', 'utf8')
|
|
42
|
+
},
|
|
43
|
+
) {
|
|
44
|
+
// Generate a new key pair
|
|
45
|
+
const { privateKey, publicKey } = options
|
|
46
|
+
? options
|
|
47
|
+
: crypto.generateKeyPairSync('rsa', {
|
|
48
|
+
modulusLength: 2048, // Key size in bits
|
|
49
|
+
publicKeyEncoding: {
|
|
50
|
+
type: 'spki',
|
|
51
|
+
format: 'pem',
|
|
52
|
+
},
|
|
53
|
+
privateKeyEncoding: {
|
|
54
|
+
type: 'pkcs8',
|
|
55
|
+
format: 'pem',
|
|
56
|
+
},
|
|
57
|
+
});
|
|
58
|
+
|
|
59
|
+
// Function to encrypt data
|
|
60
|
+
function encryptData(plaintext) {
|
|
61
|
+
const buffer = Buffer.from(plaintext, 'utf8');
|
|
62
|
+
const encrypted = crypto.publicEncrypt(publicKey, buffer);
|
|
63
|
+
return encrypted.toString('hex');
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
// Function to decrypt data
|
|
67
|
+
function decryptData(ciphertext) {
|
|
68
|
+
const buffer = Buffer.from(ciphertext, 'hex');
|
|
69
|
+
const decrypted = crypto.privateDecrypt(privateKey, buffer);
|
|
70
|
+
return decrypted.toString('utf8');
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
fs.writeFileSync('./public.pem', publicKey);
|
|
74
|
+
fs.writeFileSync('./private.pem', privateKey);
|
|
75
|
+
|
|
76
|
+
const result = {
|
|
77
|
+
privateKey: fs.readFileSync('./public.pem', 'utf8'),
|
|
78
|
+
publicKey: fs.readFileSync('./private.pem', 'utf8'),
|
|
79
|
+
encryptData,
|
|
80
|
+
decryptData,
|
|
81
|
+
};
|
|
82
|
+
|
|
83
|
+
fs.removeSync('./public.pem');
|
|
84
|
+
fs.removeSync('./private.pem');
|
|
85
|
+
|
|
86
|
+
return result;
|
|
87
|
+
},
|
|
88
|
+
},
|
|
89
|
+
};
|
|
90
|
+
|
|
91
|
+
export { CryptoBuilder };
|
package/src/server/dns.js
CHANGED
|
@@ -1,38 +1,47 @@
|
|
|
1
1
|
import axios from 'axios';
|
|
2
2
|
import dotenv from 'dotenv';
|
|
3
3
|
import fs from 'fs';
|
|
4
|
-
import
|
|
4
|
+
import https from 'https';
|
|
5
5
|
|
|
6
6
|
import { ip } from './network.js';
|
|
7
7
|
import { loggerFactory } from './logger.js';
|
|
8
8
|
import { isIPv4 } from 'is-ip';
|
|
9
|
+
import { shellExec } from './process.js';
|
|
10
|
+
|
|
11
|
+
const httpsAgent = new https.Agent({
|
|
12
|
+
rejectUnauthorized: false,
|
|
13
|
+
});
|
|
14
|
+
|
|
15
|
+
axios.defaults.httpsAgent = httpsAgent;
|
|
9
16
|
|
|
10
17
|
dotenv.config();
|
|
11
18
|
|
|
12
19
|
const logger = loggerFactory(import.meta);
|
|
13
20
|
|
|
14
21
|
const Dns = {
|
|
15
|
-
|
|
16
|
-
ipDaemon: null,
|
|
22
|
+
repoUrl: `https://${process.env.GITHUB_TOKEN}@github.com/${process.env.GITHUB_USERNAME}/${process.env.GITHUB_DNS_REPO}.git`,
|
|
17
23
|
callback: () => null,
|
|
18
|
-
InitIpDaemon: async function () {
|
|
19
|
-
//
|
|
24
|
+
InitIpDaemon: async function ({ deployId }) {
|
|
25
|
+
// NAT-VPS modem/router device configuration:
|
|
26
|
+
// LAN --> [NAT-VPS] --> WAN
|
|
20
27
|
// enabled DMZ Host to proxy IP 80-443 (79-444) sometimes router block first port
|
|
21
|
-
//
|
|
22
|
-
//
|
|
28
|
+
// disabled local red DHCP
|
|
29
|
+
// verify inet ip proxy server address
|
|
23
30
|
// DHCP (Dynamic Host Configuration Protocol) LAN reserver IP -> MAC ID
|
|
31
|
+
// LAN server or device's local servers port -> 3000-3100 (2999-3101)
|
|
32
|
+
// DNS Records: [ANAME](Address Dynamic) -> [A](ipv4) host | [AAAA](ipv6) host -> [public-ip]
|
|
24
33
|
// Forward the router's TCP/UDP ports to the LAN device's IP address
|
|
25
34
|
|
|
26
|
-
const privateCronConfPath = `./engine-private/conf/${
|
|
35
|
+
const privateCronConfPath = `./engine-private/conf/${deployId}/conf.cron.json`;
|
|
27
36
|
|
|
28
37
|
const confCronPath = fs.existsSync(privateCronConfPath) ? privateCronConfPath : './conf/conf.cron.json';
|
|
29
|
-
|
|
30
38
|
let confCronData = JSON.parse(fs.readFileSync(confCronPath, 'utf8'));
|
|
31
39
|
if (confCronData.ipDaemon.disabled) return;
|
|
32
40
|
Dns.ip = confCronData.ipDaemon.ip;
|
|
33
41
|
logger.info(`Current ip`, Dns.ip);
|
|
34
|
-
if (Dns.ipDaemon) clearInterval(Dns.ipDaemon);
|
|
35
42
|
const callback = async () => {
|
|
43
|
+
logger.info('init dns ip callback');
|
|
44
|
+
await logger.setUpInfo();
|
|
36
45
|
let testIp;
|
|
37
46
|
try {
|
|
38
47
|
testIp = await ip.public.ipv4();
|
|
@@ -41,15 +50,12 @@ const Dns = {
|
|
|
41
50
|
}
|
|
42
51
|
if (testIp && typeof testIp === 'string' && isIPv4(testIp) && Dns.ip !== testIp) {
|
|
43
52
|
logger.info(`New ip`, testIp);
|
|
44
|
-
Dns.ip = testIp;
|
|
45
|
-
confCronData.ipDaemon.ip = Dns.ip;
|
|
46
|
-
fs.writeFileSync(confCronPath, JSON.stringify(confCronData, null, 4), 'utf8');
|
|
47
53
|
for (const recordType of Object.keys(confCronData.records)) {
|
|
48
54
|
switch (recordType) {
|
|
49
55
|
case 'A':
|
|
50
56
|
for (const dnsProvider of confCronData.records[recordType]) {
|
|
51
57
|
if (typeof Dns.services.updateIp[dnsProvider.dns] === 'function')
|
|
52
|
-
await Dns.services.updateIp[dnsProvider.dns](dnsProvider);
|
|
58
|
+
await Dns.services.updateIp[dnsProvider.dns]({ ...dnsProvider, ip: testIp });
|
|
53
59
|
}
|
|
54
60
|
break;
|
|
55
61
|
|
|
@@ -57,16 +63,28 @@ const Dns = {
|
|
|
57
63
|
break;
|
|
58
64
|
}
|
|
59
65
|
}
|
|
66
|
+
try {
|
|
67
|
+
const ipUrlTest = `https://${process.env.DEFAULT_DEPLOY_HOST}`;
|
|
68
|
+
const response = await axios.get(ipUrlTest);
|
|
69
|
+
const verifyIp = response.request.socket.remoteAddress;
|
|
70
|
+
logger.info(ipUrlTest + ' IP', verifyIp);
|
|
71
|
+
if (verifyIp === testIp) {
|
|
72
|
+
await this.saveIp(confCronPath, confCronData, testIp);
|
|
73
|
+
} else logger.error('ip not updated');
|
|
74
|
+
} catch (error) {
|
|
75
|
+
logger.error(error), 'ip not updated';
|
|
76
|
+
}
|
|
60
77
|
}
|
|
61
78
|
};
|
|
79
|
+
await callback();
|
|
62
80
|
this.callback = callback;
|
|
63
81
|
return callback;
|
|
64
82
|
},
|
|
65
83
|
services: {
|
|
66
84
|
updateIp: {
|
|
67
85
|
dondominio: (options) => {
|
|
68
|
-
const { user, api_key, host, dns } = options;
|
|
69
|
-
const url = `https://dondns.dondominio.com/json/?user=${user}&password=${api_key}&host=${host}&ip=${
|
|
86
|
+
const { user, api_key, host, dns, ip } = options;
|
|
87
|
+
const url = `https://dondns.dondominio.com/json/?user=${user}&password=${api_key}&host=${host}&ip=${ip}`;
|
|
70
88
|
logger.info(`${dns} update ip url`, url);
|
|
71
89
|
if (process.env.NODE_ENV !== 'production') return false;
|
|
72
90
|
return new Promise((resolve) => {
|
|
@@ -84,6 +102,20 @@ const Dns = {
|
|
|
84
102
|
},
|
|
85
103
|
},
|
|
86
104
|
},
|
|
105
|
+
saveIp: async (confCronPath, confCronData, ip) => {
|
|
106
|
+
Dns.ip = ip;
|
|
107
|
+
confCronData.ipDaemon.ip = ip;
|
|
108
|
+
fs.writeFileSync(confCronPath, JSON.stringify(confCronData, null, 4), 'utf8');
|
|
109
|
+
shellExec(
|
|
110
|
+
`cd ./engine-private` +
|
|
111
|
+
` && git pull ${Dns.repoUrl}` +
|
|
112
|
+
` && git add . && git commit -m "update ip ${new Date().toLocaleDateString()}"` +
|
|
113
|
+
` && git push ${Dns.repoUrl}`,
|
|
114
|
+
{
|
|
115
|
+
disableLog: true,
|
|
116
|
+
},
|
|
117
|
+
);
|
|
118
|
+
},
|
|
87
119
|
};
|
|
88
120
|
|
|
89
121
|
export { Dns };
|
package/src/server/network.js
CHANGED
|
@@ -5,6 +5,8 @@ import { publicIp, publicIpv4, publicIpv6 } from 'public-ip';
|
|
|
5
5
|
import { killPortProcess } from 'kill-port-process';
|
|
6
6
|
import { loggerFactory } from './logger.js';
|
|
7
7
|
import { orderArrayFromAttrInt } from '../client/components/core/CommonJs.js';
|
|
8
|
+
import { DataBaseProvider } from '../db/DataBaseProvider.js';
|
|
9
|
+
import { getDeployId } from './conf.js';
|
|
8
10
|
|
|
9
11
|
// Network Address Translation Management
|
|
10
12
|
|
|
@@ -66,12 +68,86 @@ const logRuntimeRouter = () => {
|
|
|
66
68
|
logger.info('Runtime network', displayLog);
|
|
67
69
|
};
|
|
68
70
|
|
|
69
|
-
const saveRuntimeRouter = () =>
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
71
|
+
const saveRuntimeRouter = async () => {
|
|
72
|
+
try {
|
|
73
|
+
const deployId = process.env.DEFAULT_DEPLOY_ID;
|
|
74
|
+
const host = process.env.DEFAULT_DEPLOY_HOST;
|
|
75
|
+
const path = process.env.DEFAULT_DEPLOY_PATH;
|
|
76
|
+
const confServerPath = `./engine-private/conf/${deployId}/conf.server.json`;
|
|
77
|
+
const confServer = JSON.parse(fs.readFileSync(confServerPath, 'utf8'));
|
|
78
|
+
const { db } = confServer[host][path];
|
|
79
|
+
|
|
80
|
+
let closeConn;
|
|
81
|
+
if (!DataBaseProvider.instance[`${host}${path}`]) {
|
|
82
|
+
await DataBaseProvider.load({ apis: ['instance'], host, path, db });
|
|
83
|
+
closeConn = true;
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
/** @type {import('../api/instance/instance.model.js').InstanceModel} */
|
|
87
|
+
const Instance = DataBaseProvider.instance[`${host}${path}`].mongoose.models.Instance;
|
|
88
|
+
|
|
89
|
+
for (const _host of Object.keys(networkRouter)) {
|
|
90
|
+
for (const _path of Object.keys(networkRouter[_host])) {
|
|
91
|
+
const body = {
|
|
92
|
+
host: _host,
|
|
93
|
+
path: _path,
|
|
94
|
+
deployId: getDeployId(),
|
|
95
|
+
client: networkRouter[_host][_path].client,
|
|
96
|
+
runtime: networkRouter[_host][_path].runtime,
|
|
97
|
+
port: networkRouter[_host][_path].port,
|
|
98
|
+
apis: networkRouter[_host][_path].apis,
|
|
99
|
+
};
|
|
100
|
+
const instance = await Instance.findOne({ deployId: body.deployId, port: body.port });
|
|
101
|
+
if (instance) {
|
|
102
|
+
await Instance.findByIdAndUpdate(instance._id, body);
|
|
103
|
+
} else {
|
|
104
|
+
await new Instance(body).save();
|
|
105
|
+
}
|
|
106
|
+
}
|
|
107
|
+
}
|
|
108
|
+
|
|
109
|
+
if (closeConn) await DataBaseProvider.instance[`${host}${path}`].mongoose.close();
|
|
110
|
+
} catch (error) {
|
|
111
|
+
logger.error(error);
|
|
112
|
+
}
|
|
113
|
+
};
|
|
114
|
+
|
|
115
|
+
const netWorkCron = [];
|
|
116
|
+
|
|
117
|
+
const saveRuntimeCron = async () => {
|
|
118
|
+
try {
|
|
119
|
+
const deployId = process.env.DEFAULT_DEPLOY_ID;
|
|
120
|
+
const host = process.env.DEFAULT_DEPLOY_HOST;
|
|
121
|
+
const path = process.env.DEFAULT_DEPLOY_PATH;
|
|
122
|
+
const confServerPath = `./engine-private/conf/${deployId}/conf.server.json`;
|
|
123
|
+
const confServer = JSON.parse(fs.readFileSync(confServerPath, 'utf8'));
|
|
124
|
+
const { db } = confServer[host][path];
|
|
125
|
+
|
|
126
|
+
let closeConn;
|
|
127
|
+
if (!DataBaseProvider.instance[`${host}${path}`]) {
|
|
128
|
+
await DataBaseProvider.load({ apis: ['cron'], host, path, db });
|
|
129
|
+
closeConn = true;
|
|
130
|
+
}
|
|
131
|
+
|
|
132
|
+
/** @type {import('../api/cron/cron.model.js').CronModel} */
|
|
133
|
+
const Cron = DataBaseProvider.instance[`${host}${path}`].mongoose.models.Cron;
|
|
134
|
+
|
|
135
|
+
// await Cron.insertMany(netWorkCron);
|
|
136
|
+
|
|
137
|
+
for (const cronInstance of netWorkCron) {
|
|
138
|
+
const cron = await Cron.findOne({ deployId: cronInstance.deployId, jobId: cronInstance.jobId });
|
|
139
|
+
if (cron) {
|
|
140
|
+
await Cron.findByIdAndUpdate(cron._id, cronInstance);
|
|
141
|
+
} else {
|
|
142
|
+
await new Cron(cronInstance).save();
|
|
143
|
+
}
|
|
144
|
+
}
|
|
145
|
+
|
|
146
|
+
if (closeConn) await DataBaseProvider.instance[`${host}${path}`].mongoose.close();
|
|
147
|
+
} catch (error) {
|
|
148
|
+
logger.error(error);
|
|
149
|
+
}
|
|
150
|
+
};
|
|
75
151
|
|
|
76
152
|
const listenServerFactory = (logic = async () => {}) => {
|
|
77
153
|
return {
|
|
@@ -109,6 +185,7 @@ const listenPortController = async (server, port, metadata) =>
|
|
|
109
185
|
? `https://${host}${path}`
|
|
110
186
|
: `http://${host}:${port}${path}`,
|
|
111
187
|
local: `http://localhost:${port}${path}`,
|
|
188
|
+
apis: metadata.apis,
|
|
112
189
|
};
|
|
113
190
|
|
|
114
191
|
return resolve(true);
|
|
@@ -119,4 +196,14 @@ const listenPortController = async (server, port, metadata) =>
|
|
|
119
196
|
}
|
|
120
197
|
});
|
|
121
198
|
|
|
122
|
-
export {
|
|
199
|
+
export {
|
|
200
|
+
ip,
|
|
201
|
+
network,
|
|
202
|
+
listenPortController,
|
|
203
|
+
networkRouter,
|
|
204
|
+
netWorkCron,
|
|
205
|
+
saveRuntimeRouter,
|
|
206
|
+
logRuntimeRouter,
|
|
207
|
+
listenServerFactory,
|
|
208
|
+
saveRuntimeCron,
|
|
209
|
+
};
|
package/src/server/proxy.js
CHANGED
|
@@ -9,7 +9,8 @@ import { loggerFactory, loggerMiddleware } from './logger.js';
|
|
|
9
9
|
import { listenPortController, network } from './network.js';
|
|
10
10
|
import { orderArrayFromAttrInt } from '../client/components/core/CommonJs.js';
|
|
11
11
|
import { createSslServer, sslRedirectMiddleware } from './ssl.js';
|
|
12
|
-
import { buildProxyRouter } from './conf.js';
|
|
12
|
+
import { buildProxyRouter, maintenanceMiddleware } from './conf.js';
|
|
13
|
+
import { getRootDirectory } from './process.js';
|
|
13
14
|
|
|
14
15
|
dotenv.config();
|
|
15
16
|
|
|
@@ -25,6 +26,9 @@ const buildProxy = async () => {
|
|
|
25
26
|
for (let port of Object.keys(proxyRouter)) {
|
|
26
27
|
port = parseInt(port);
|
|
27
28
|
const hosts = proxyRouter[port];
|
|
29
|
+
const proxyPath = '/';
|
|
30
|
+
const proxyHost = 'localhost';
|
|
31
|
+
const runningData = { host: proxyHost, path: proxyPath, client: null, runtime: 'nodejs', meta: import.meta };
|
|
28
32
|
const app = express();
|
|
29
33
|
|
|
30
34
|
// set logger
|
|
@@ -47,6 +51,7 @@ const buildProxy = async () => {
|
|
|
47
51
|
onProxyReq: (proxyReq, req, res, options) => {
|
|
48
52
|
// https://wtools.io/check-http-status-code
|
|
49
53
|
// http://nexodev.org
|
|
54
|
+
maintenanceMiddleware(req, res, port, proxyRouter);
|
|
50
55
|
sslRedirectMiddleware(req, res, port, proxyRouter);
|
|
51
56
|
},
|
|
52
57
|
pathRewrite: {
|
|
@@ -54,30 +59,27 @@ const buildProxy = async () => {
|
|
|
54
59
|
// '^/target-path': '/',
|
|
55
60
|
},
|
|
56
61
|
};
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
// instance proxy server
|
|
79
|
-
const proxyPath = '/';
|
|
80
|
-
const proxyHost = 'localhost';
|
|
62
|
+
if (!process.argv.includes('maintenance')) {
|
|
63
|
+
// build router
|
|
64
|
+
Object.keys(hosts).map((hostKey) => {
|
|
65
|
+
let { host, path, target, proxy, peer } = hosts[hostKey];
|
|
66
|
+
if (process.env.NODE_ENV === 'development') host = `localhost`;
|
|
67
|
+
|
|
68
|
+
if (!proxy.includes(port)) return;
|
|
69
|
+
const absoluteHost = [80, 443].includes(port)
|
|
70
|
+
? `${host}${path === '/' ? '' : path}`
|
|
71
|
+
: `${host}:${port}${path === '/' ? '' : path}`;
|
|
72
|
+
|
|
73
|
+
if (!(absoluteHost in options.router)) options.router[absoluteHost] = target;
|
|
74
|
+
});
|
|
75
|
+
if (Object.keys(options.router).length === 0) continue;
|
|
76
|
+
|
|
77
|
+
// order router
|
|
78
|
+
const router = {};
|
|
79
|
+
for (const absoluteHostKey of orderArrayFromAttrInt(Object.keys(options.router), 'length'))
|
|
80
|
+
router[absoluteHostKey] = options.router[absoluteHostKey];
|
|
81
|
+
options.router = router;
|
|
82
|
+
}
|
|
81
83
|
|
|
82
84
|
const filter = false
|
|
83
85
|
? (pathname, req) => {
|
|
@@ -88,8 +90,6 @@ const buildProxy = async () => {
|
|
|
88
90
|
app.use(proxyPath, createProxyMiddleware(filter, options));
|
|
89
91
|
await network.port.portClean(port);
|
|
90
92
|
|
|
91
|
-
const runningData = { host: proxyHost, path: proxyPath, client: null, runtime: 'nodejs', meta: import.meta };
|
|
92
|
-
|
|
93
93
|
switch (process.env.NODE_ENV) {
|
|
94
94
|
case 'production':
|
|
95
95
|
switch (port) {
|
package/src/server/runtime.js
CHANGED
|
@@ -18,13 +18,14 @@ import { DataBaseProvider } from '../db/DataBaseProvider.js';
|
|
|
18
18
|
import { createProxyMiddleware } from 'http-proxy-middleware';
|
|
19
19
|
import { createPeerServer } from './peer.js';
|
|
20
20
|
import { Lampp } from '../runtime/lampp/Lampp.js';
|
|
21
|
+
import { getDeployId } from './conf.js';
|
|
21
22
|
|
|
22
23
|
dotenv.config();
|
|
23
24
|
|
|
24
25
|
const logger = loggerFactory(import.meta);
|
|
25
26
|
|
|
26
27
|
const buildRuntime = async () => {
|
|
27
|
-
const deployId =
|
|
28
|
+
const deployId = getDeployId();
|
|
28
29
|
|
|
29
30
|
const collectDefaultMetrics = promClient.collectDefaultMetrics;
|
|
30
31
|
collectDefaultMetrics();
|
|
@@ -95,6 +96,7 @@ export PATH=$PATH:/opt/lampp/bin`,
|
|
|
95
96
|
runtime,
|
|
96
97
|
client,
|
|
97
98
|
meta: import.meta,
|
|
99
|
+
apis,
|
|
98
100
|
};
|
|
99
101
|
|
|
100
102
|
let redirectUrl;
|
|
@@ -325,7 +327,7 @@ export PATH=$PATH:/opt/lampp/bin`,
|
|
|
325
327
|
apis && process.env.NODE_ENV === 'development' ? [`http://localhost:${currentPort + 2}`] : [],
|
|
326
328
|
),
|
|
327
329
|
};
|
|
328
|
-
logger.info('originPayload', originPayload);
|
|
330
|
+
// logger.info('originPayload', originPayload);
|
|
329
331
|
app.use(cors(originPayload));
|
|
330
332
|
|
|
331
333
|
if (redirect) {
|
package/src/server/ssl.js
CHANGED
|
@@ -16,7 +16,7 @@ const buildSSL = async (host) => {
|
|
|
16
16
|
const files = await fs.readdir(sslPath);
|
|
17
17
|
|
|
18
18
|
for (const folderHost of files)
|
|
19
|
-
if (folderHost.match(host.split('/')[0])) {
|
|
19
|
+
if (folderHost.match(host.split('/')[0]) && host.split('.')[0] === folderHost.split('.')[0]) {
|
|
20
20
|
for (const i of [''].concat(range(1, 10))) {
|
|
21
21
|
const privateKeyPath = `${sslPath}/${folderHost}/privkey${i}.pem`;
|
|
22
22
|
const certificatePath = `${sslPath}/${folderHost}/cert${i}.pem`;
|
|
@@ -51,7 +51,7 @@ const buildSSL = async (host) => {
|
|
|
51
51
|
fs.writeFileSync(`./engine-private/ssl/${host}/_ca_bundle.crt`, ca, 'utf8');
|
|
52
52
|
fs.writeFileSync(`./engine-private/ssl/${host}/_ca_full_bundle.crt`, caFull, 'utf8');
|
|
53
53
|
|
|
54
|
-
|
|
54
|
+
fs.removeSync(`${sslPath}/${folderHost}`);
|
|
55
55
|
return true;
|
|
56
56
|
}
|
|
57
57
|
}
|
|
@@ -1,31 +0,0 @@
|
|
|
1
|
-
import { htmls, loggerFactory } from '../common/SsrCore.js';
|
|
2
|
-
import { Alert } from '../common/Alert.js';
|
|
3
|
-
import { Translate } from '../common/Translate.js';
|
|
4
|
-
import { Worker } from '../common/Worker.js';
|
|
5
|
-
/*imports*/
|
|
6
|
-
|
|
7
|
-
const logger = loggerFactory({ url: '/offline.js' });
|
|
8
|
-
|
|
9
|
-
window.onload = () =>
|
|
10
|
-
Worker.instance({
|
|
11
|
-
render: async () => {
|
|
12
|
-
window.ononline = async () => {
|
|
13
|
-
location.href = '/';
|
|
14
|
-
};
|
|
15
|
-
window.onoffline = async () => {
|
|
16
|
-
htmls(`.page-render`, html`${await Alert.noInternet({ Translate })}`);
|
|
17
|
-
};
|
|
18
|
-
try {
|
|
19
|
-
if (navigator.onLine) {
|
|
20
|
-
const maintenance = await fetch(location.origin + '/favicon.ico');
|
|
21
|
-
if (maintenance.status !== 200) {
|
|
22
|
-
htmls(`.page-render`, html`${await Alert.maintenance({ Translate })}`);
|
|
23
|
-
} else window.ononline();
|
|
24
|
-
}
|
|
25
|
-
throw new Error(`no internet connection`);
|
|
26
|
-
} catch (error) {
|
|
27
|
-
logger.error(error);
|
|
28
|
-
window.onoffline();
|
|
29
|
-
}
|
|
30
|
-
},
|
|
31
|
-
});
|
package/src/cron.js
DELETED
|
@@ -1,30 +0,0 @@
|
|
|
1
|
-
'use strict';
|
|
2
|
-
|
|
3
|
-
// https://nodejs.org/api
|
|
4
|
-
// https://expressjs.com/en/4x/api.html
|
|
5
|
-
|
|
6
|
-
import dotenv from 'dotenv';
|
|
7
|
-
import { loggerFactory } from './server/logger.js';
|
|
8
|
-
import { Dns } from './server/dns.js';
|
|
9
|
-
import { ProcessController } from './server/process.js';
|
|
10
|
-
import { Config } from './server/conf.js';
|
|
11
|
-
import { BackUpManagement } from './server/backup.js';
|
|
12
|
-
import { CronManagement } from './server/cron.js';
|
|
13
|
-
|
|
14
|
-
dotenv.config();
|
|
15
|
-
|
|
16
|
-
await Config.build();
|
|
17
|
-
|
|
18
|
-
const logger = loggerFactory(import.meta);
|
|
19
|
-
|
|
20
|
-
await logger.setUpInfo();
|
|
21
|
-
|
|
22
|
-
// every minutes
|
|
23
|
-
CronManagement.add('ip', '* * * * *', await Dns.InitIpDaemon());
|
|
24
|
-
|
|
25
|
-
// every day at 1 am
|
|
26
|
-
CronManagement.add('backup', '0 1 * * *', await BackUpManagement.Init());
|
|
27
|
-
|
|
28
|
-
await CronManagement.init();
|
|
29
|
-
|
|
30
|
-
ProcessController.init(logger);
|
package/src/server/cron.js
DELETED
|
@@ -1,35 +0,0 @@
|
|
|
1
|
-
import cron from 'node-cron';
|
|
2
|
-
import { loggerFactory } from './logger.js';
|
|
3
|
-
|
|
4
|
-
const logger = loggerFactory(import.meta);
|
|
5
|
-
|
|
6
|
-
const CronManagement = {
|
|
7
|
-
data: {},
|
|
8
|
-
init: function () {
|
|
9
|
-
// verify tokens
|
|
10
|
-
// https://github.com/settings/tokens
|
|
11
|
-
for (const cronKey of Object.keys(this.data)) {
|
|
12
|
-
if (this.data[cronKey].valid) {
|
|
13
|
-
this.data[cronKey].task.start();
|
|
14
|
-
logger.info(`Cron task "${this.data[cronKey].name}" started`);
|
|
15
|
-
} else {
|
|
16
|
-
logger.error(
|
|
17
|
-
`Invalid cron expression "${this.data[cronKey].expression}" for task "${this.data[cronKey].name}"`,
|
|
18
|
-
);
|
|
19
|
-
}
|
|
20
|
-
}
|
|
21
|
-
},
|
|
22
|
-
add: function (name = 'task', expression = '* * * * *', callback = async () => null) {
|
|
23
|
-
const args = { name, expression, valid: cron.validate(expression) };
|
|
24
|
-
this.data[name] = {
|
|
25
|
-
...args,
|
|
26
|
-
task: cron.schedule(expression, callback, {
|
|
27
|
-
scheduled: false,
|
|
28
|
-
timezone: process.env.TIME_ZONE || 'America/New_York',
|
|
29
|
-
name,
|
|
30
|
-
}),
|
|
31
|
-
};
|
|
32
|
-
},
|
|
33
|
-
};
|
|
34
|
-
|
|
35
|
-
export { CronManagement };
|