@underpostnet/underpost 2.99.1 → 2.99.5
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/.env.development +0 -3
- package/.env.production +1 -3
- package/.env.test +0 -3
- package/LICENSE +1 -1
- package/README.md +30 -30
- package/baremetal/commission-workflows.json +52 -0
- package/bin/deploy.js +101 -47
- package/cli.md +47 -43
- package/examples/static-page/README.md +55 -378
- package/examples/static-page/ssr-components/CustomPage.js +1 -13
- package/jsconfig.json +4 -2
- package/manifests/deployment/dd-default-development/deployment.yaml +2 -2
- package/manifests/deployment/dd-test-development/deployment.yaml +2 -2
- package/manifests/deployment/playwright/deployment.yaml +52 -0
- package/package.json +2 -2
- package/scripts/disk-devices.sh +13 -0
- package/scripts/rocky-pwa.sh +2 -2
- package/scripts/ssl.sh +12 -6
- package/src/api/user/user.model.js +1 -0
- package/src/cli/baremetal.js +576 -176
- package/src/cli/cloud-init.js +97 -79
- package/src/cli/deploy.js +6 -24
- package/src/cli/env.js +4 -1
- package/src/cli/image.js +7 -40
- package/src/cli/index.js +37 -7
- package/src/cli/repository.js +3 -1
- package/src/cli/run.js +109 -92
- package/src/cli/secrets.js +0 -34
- package/src/cli/static.js +0 -26
- package/src/cli/test.js +13 -1
- package/src/client/components/core/Polyhedron.js +896 -7
- package/src/client/components/core/Translate.js +4 -0
- package/src/client/services/default/default.management.js +12 -2
- package/src/index.js +27 -1
- package/src/runtime/express/Express.js +3 -3
- package/src/server/conf.js +6 -4
- package/src/server/logger.js +33 -31
- package/src/server/process.js +27 -2
- package/src/server/proxy.js +4 -6
- package/src/server/tls.js +30 -25
- package/examples/static-page/QUICK-REFERENCE.md +0 -481
- package/examples/static-page/STATIC-GENERATOR-GUIDE.md +0 -757
|
@@ -687,6 +687,10 @@ const TranslateCore = {
|
|
|
687
687
|
en: 'Markdown source copied to clipboard',
|
|
688
688
|
es: 'Fuente de Markdown copiada al portapapeles',
|
|
689
689
|
};
|
|
690
|
+
Translate.Data['success-clear-filter'] = {
|
|
691
|
+
en: 'Filter cleared successfully',
|
|
692
|
+
es: 'Filtro limpiado con éxito',
|
|
693
|
+
};
|
|
690
694
|
},
|
|
691
695
|
};
|
|
692
696
|
|
|
@@ -39,9 +39,19 @@ const DefaultOptions = {
|
|
|
39
39
|
const columnDefFormatter = (obj, columnDefs, customFormat) => {
|
|
40
40
|
for (const colDef of columnDefs)
|
|
41
41
|
switch (colDef.cellDataType) {
|
|
42
|
-
case 'date':
|
|
43
|
-
|
|
42
|
+
case 'date': {
|
|
43
|
+
const value = obj[colDef.field];
|
|
44
|
+
|
|
45
|
+
// Do NOT default missing/blank dates to "now" — render as empty instead.
|
|
46
|
+
if (value === null || value === undefined || value === '') {
|
|
47
|
+
obj[colDef.field] = null;
|
|
48
|
+
break;
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
const date = new Date(value);
|
|
52
|
+
obj[colDef.field] = isNaN(date.getTime()) ? null : date;
|
|
44
53
|
break;
|
|
54
|
+
}
|
|
45
55
|
case 'boolean':
|
|
46
56
|
if (obj[colDef.field] !== true && obj[colDef.field] !== false) obj[colDef.field] = false;
|
|
47
57
|
default:
|
package/src/index.js
CHANGED
|
@@ -25,6 +25,7 @@ import UnderpostDns from './server/dns.js';
|
|
|
25
25
|
import UnderpostBackup from './server/backup.js';
|
|
26
26
|
import UnderpostCron from './server/cron.js';
|
|
27
27
|
import UnderpostStartUp from './server/start.js';
|
|
28
|
+
import UnderpostTLS from './server/tls.js';
|
|
28
29
|
|
|
29
30
|
/**
|
|
30
31
|
* Underpost main module methods
|
|
@@ -38,7 +39,16 @@ class Underpost {
|
|
|
38
39
|
* @type {String}
|
|
39
40
|
* @memberof Underpost
|
|
40
41
|
*/
|
|
41
|
-
static version = 'v2.99.
|
|
42
|
+
static version = 'v2.99.5';
|
|
43
|
+
|
|
44
|
+
/**
|
|
45
|
+
* Required Node.js major version
|
|
46
|
+
* @static
|
|
47
|
+
* @type {String}
|
|
48
|
+
* @memberof Underpost
|
|
49
|
+
*/
|
|
50
|
+
static majorNodejsVersion = 'v24';
|
|
51
|
+
|
|
42
52
|
/**
|
|
43
53
|
* Repository cli API
|
|
44
54
|
* @static
|
|
@@ -228,8 +238,23 @@ class Underpost {
|
|
|
228
238
|
static get start() {
|
|
229
239
|
return UnderpostStartUp.API;
|
|
230
240
|
}
|
|
241
|
+
|
|
242
|
+
/**
|
|
243
|
+
* TLS/SSL server utilities API
|
|
244
|
+
* @static
|
|
245
|
+
* @type {UnderpostTLS.API}
|
|
246
|
+
* @memberof Underpost
|
|
247
|
+
*/
|
|
248
|
+
static get tls() {
|
|
249
|
+
return UnderpostTLS.API;
|
|
250
|
+
}
|
|
231
251
|
}
|
|
232
252
|
|
|
253
|
+
if (!process.version || !process.version.startsWith(`${Underpost.majorNodejsVersion}.`))
|
|
254
|
+
console.warn(
|
|
255
|
+
`${`Underpost Warning: Required Node.js version is `.red}${`${Underpost.majorNodejsVersion}.x`.bgBlue.bold.white}${`, you are using `.red}${process.version.bgRed.bold.white}`,
|
|
256
|
+
);
|
|
257
|
+
|
|
233
258
|
const up = Underpost;
|
|
234
259
|
|
|
235
260
|
const underpost = Underpost;
|
|
@@ -258,6 +283,7 @@ export {
|
|
|
258
283
|
UnderpostBackup,
|
|
259
284
|
UnderpostCron,
|
|
260
285
|
UnderpostStartUp,
|
|
286
|
+
UnderpostTLS,
|
|
261
287
|
};
|
|
262
288
|
|
|
263
289
|
export default Underpost;
|
|
@@ -20,7 +20,7 @@ import { createPeerServer } from '../../server/peer.js';
|
|
|
20
20
|
import { createValkeyConnection } from '../../server/valkey.js';
|
|
21
21
|
import { applySecurity, authMiddlewareFactory } from '../../server/auth.js';
|
|
22
22
|
import { ssrMiddlewareFactory } from '../../server/ssr.js';
|
|
23
|
-
|
|
23
|
+
|
|
24
24
|
import { shellExec } from '../../server/process.js';
|
|
25
25
|
import { devProxyHostFactory, isDevProxyContext, isTlsDevProxy } from '../../server/conf.js';
|
|
26
26
|
|
|
@@ -249,8 +249,8 @@ class ExpressService {
|
|
|
249
249
|
|
|
250
250
|
// Start listening on the main port
|
|
251
251
|
if (useLocalSsl && process.env.NODE_ENV === 'development') {
|
|
252
|
-
if (!
|
|
253
|
-
const { ServerSSL } = await
|
|
252
|
+
if (!Underpost.tls.validateSecureContext()) shellExec(`node bin/deploy tls`);
|
|
253
|
+
const { ServerSSL } = await Underpost.tls.createSslServer(app);
|
|
254
254
|
await Underpost.start.listenPortController(ServerSSL, port, runningData);
|
|
255
255
|
} else await Underpost.start.listenPortController(server, port, runningData);
|
|
256
256
|
|
package/src/server/conf.js
CHANGED
|
@@ -66,7 +66,7 @@ const Config = {
|
|
|
66
66
|
/**
|
|
67
67
|
* @method deployIdFactory
|
|
68
68
|
* @description Creates a new deploy ID.
|
|
69
|
-
* @param {string} [deployId='dd-default
|
|
69
|
+
* @param {string} [deployId='dd-default']
|
|
70
70
|
* @param {object} [options={ subConf: '', cluster: false }] - The options.
|
|
71
71
|
* @memberof ServerConfBuilder
|
|
72
72
|
*/
|
|
@@ -842,8 +842,10 @@ const buildPortProxyRouter = (
|
|
|
842
842
|
|
|
843
843
|
if (options.devProxyContext === true && process.env.NODE_ENV === 'development') {
|
|
844
844
|
const confDevApiServer = JSON.parse(
|
|
845
|
-
fs.readFileSync(
|
|
846
|
-
|
|
845
|
+
fs.readFileSync(
|
|
846
|
+
`./engine-private/conf/${process.argv[3]}/conf.server.dev.${process.argv[4]}-dev-api.json`,
|
|
847
|
+
'utf8',
|
|
848
|
+
),
|
|
847
849
|
);
|
|
848
850
|
let devApiHosts = [];
|
|
849
851
|
let origins = [];
|
|
@@ -899,7 +901,7 @@ const buildReplicaId = ({ deployId, replica }) => `${deployId}-${replica.slice(1
|
|
|
899
901
|
* @description Gets the data deploy.
|
|
900
902
|
* @param {object} options - The options.
|
|
901
903
|
* @param {boolean} [options.buildSingleReplica=false] - The build single replica.
|
|
902
|
-
* @param {string} options.deployId - The deploy ID.
|
|
904
|
+
* @param {string} [options.deployId] - The deploy ID.
|
|
903
905
|
* @param {boolean} [options.disableSyncEnvPort=false] - The disable sync env port.
|
|
904
906
|
* @returns {object} - The data deploy.
|
|
905
907
|
* @memberof ServerConfBuilder
|
package/src/server/logger.js
CHANGED
|
@@ -28,11 +28,13 @@ const levels = {
|
|
|
28
28
|
debug: 4,
|
|
29
29
|
};
|
|
30
30
|
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
31
|
+
/**
|
|
32
|
+
* The `level` function determines the logging level based on the provided `logLevel` parameter or defaults to 'info'.
|
|
33
|
+
* @param {string} logLevel - The logging level to be used. If not provided, it defaults to 'info'.
|
|
34
|
+
* @returns {string} The logging level to be used for the logger.
|
|
35
|
+
* @memberof Logger
|
|
36
|
+
*/
|
|
37
|
+
const level = (logLevel = '') => logLevel || 'info';
|
|
36
38
|
|
|
37
39
|
// Define different colors for each level.
|
|
38
40
|
// Colors make the log message more visible,
|
|
@@ -98,13 +100,14 @@ const setUpInfo = async (logger = new winston.Logger()) => {
|
|
|
98
100
|
* messages.
|
|
99
101
|
* @param meta - The `meta` parameter in the `loggerFactory` function is used to extract the last part
|
|
100
102
|
* of a URL and use it to create log files in a specific directory.
|
|
101
|
-
* @
|
|
103
|
+
* @param logLevel - Specify the logging level for the logger instance. e.g., 'error', 'warn', 'info', 'debug'.
|
|
104
|
+
* @returns {underpostLogger} The `loggerFactory` function returns a logger instance created using Winston logger
|
|
102
105
|
* library. The logger instance is configured with various transports for printing out messages to
|
|
103
106
|
* different destinations such as the terminal, error.log file, and all.log file. The logger instance
|
|
104
107
|
* also has a method `setUpInfo` attached to it for setting up additional information.
|
|
105
108
|
* @memberof Logger
|
|
106
109
|
*/
|
|
107
|
-
const loggerFactory = (meta = { url: '' }) => {
|
|
110
|
+
const loggerFactory = (meta = { url: '' }, logLevel = '') => {
|
|
108
111
|
meta = meta.url.split('/').pop();
|
|
109
112
|
// Define which transports the logger must use to print out messages.
|
|
110
113
|
// In this example, we are using three different transports
|
|
@@ -125,7 +128,7 @@ const loggerFactory = (meta = { url: '' }) => {
|
|
|
125
128
|
// and used to log messages.
|
|
126
129
|
const logger = winston.createLogger({
|
|
127
130
|
defaultMeta: meta,
|
|
128
|
-
level: level(),
|
|
131
|
+
level: level(logLevel),
|
|
129
132
|
levels,
|
|
130
133
|
format: format(meta),
|
|
131
134
|
transports,
|
|
@@ -133,45 +136,44 @@ const loggerFactory = (meta = { url: '' }) => {
|
|
|
133
136
|
// rejectionHandlers: [new winston.transports.File({ filename: 'rejections.log' })],
|
|
134
137
|
// exitOnError: false,
|
|
135
138
|
});
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
+
/**
|
|
140
|
+
* The returned logger is a real Winston logger instance with an extra `setUpInfo` method.
|
|
141
|
+
*
|
|
142
|
+
* @memberof Logger
|
|
143
|
+
* @typedef {winston.Logger & {
|
|
144
|
+
* setUpInfo: (logger?: winston.Logger) => Promise<void>
|
|
145
|
+
* }} underpostLogger
|
|
146
|
+
*/
|
|
147
|
+
logger.setUpInfo = () => setUpInfo(logger);
|
|
148
|
+
|
|
139
149
|
return logger;
|
|
140
150
|
};
|
|
141
151
|
|
|
142
152
|
/**
|
|
143
|
-
* The `loggerMiddleware` function
|
|
144
|
-
*
|
|
145
|
-
* @param
|
|
146
|
-
*
|
|
147
|
-
*
|
|
148
|
-
* @returns {Handler<any, any>} The `loggerMiddleware` function returns a middleware function that uses the Morgan library
|
|
149
|
-
* to log HTTP request information. The middleware function formats the log message using predefined
|
|
150
|
-
* tokens provided by Morgan and custom tokens like `:host` to include specific request details. The
|
|
151
|
-
* log message format includes information such as remote address, HTTP method, host, URL, status code,
|
|
152
|
-
* content length, and response time in milliseconds. The middleware
|
|
153
|
+
* The `loggerMiddleware` function is an Express middleware that uses the Morgan library to log HTTP requests.
|
|
154
|
+
* @param {Object} meta - An object containing metadata, such as the URL, to be used in the logger.
|
|
155
|
+
* @param {string} logLevel - The logging level to be used for the logger (e.g., 'error', 'warn', 'info', 'debug').
|
|
156
|
+
* @param {Function} skip - A function to determine whether to skip logging for a particular request.
|
|
157
|
+
* @returns {Function} A middleware function that can be used in an Express application to log HTTP requests.
|
|
153
158
|
* @memberof Logger
|
|
154
159
|
*/
|
|
155
|
-
const loggerMiddleware = (
|
|
160
|
+
const loggerMiddleware = (
|
|
161
|
+
meta = { url: '' },
|
|
162
|
+
logLevel = 'info',
|
|
163
|
+
skip = (req, res) => process.env.NODE_ENV === 'production',
|
|
164
|
+
) => {
|
|
156
165
|
const stream = {
|
|
157
166
|
// Use the http severity
|
|
158
|
-
write: (message) => loggerFactory(meta).http(message),
|
|
167
|
+
write: (message) => loggerFactory(meta, logLevel).http(message),
|
|
159
168
|
};
|
|
160
169
|
|
|
161
|
-
const skip = (req, res) => process.env.NODE_ENV === 'production';
|
|
162
|
-
|
|
163
170
|
morgan.token('host', function (req, res) {
|
|
164
171
|
return req.headers['host'];
|
|
165
172
|
});
|
|
166
173
|
|
|
167
174
|
return morgan(
|
|
168
|
-
// Define message format string
|
|
169
|
-
// The message format is made from tokens, and each token is
|
|
170
|
-
// defined inside the Morgan library.
|
|
171
|
-
// You can create your custom token to show what do you want from a request.
|
|
175
|
+
// Define message format string
|
|
172
176
|
`:remote-addr :method :host:url :status :res[content-length] - :response-time ms`,
|
|
173
|
-
// Options: in this case, I overwrote the stream and the skip logic.
|
|
174
|
-
// See the methods above.
|
|
175
177
|
{ stream, skip },
|
|
176
178
|
);
|
|
177
179
|
};
|
package/src/server/process.js
CHANGED
|
@@ -12,6 +12,7 @@ import dotenv from 'dotenv';
|
|
|
12
12
|
import { loggerFactory } from './logger.js';
|
|
13
13
|
import clipboard from 'clipboardy';
|
|
14
14
|
import Underpost from '../index.js';
|
|
15
|
+
import { getNpmRootPath } from './conf.js';
|
|
15
16
|
|
|
16
17
|
dotenv.config();
|
|
17
18
|
|
|
@@ -128,16 +129,40 @@ const shellCd = (cd, options = { disableLog: false }) => {
|
|
|
128
129
|
* @param {string} cmd - The command to execute in the new terminal.
|
|
129
130
|
* @param {Object} [options] - Options for the terminal opening.
|
|
130
131
|
* @param {boolean} [options.single=false] - If true, execute as a single session process using `setsid`.
|
|
132
|
+
* @param {string} [options.chown] - Path to change ownership to the target user.
|
|
131
133
|
* @returns {void}
|
|
132
134
|
*/
|
|
133
135
|
const openTerminal = (cmd, options = { single: false }) => {
|
|
136
|
+
// Find the graphical user's UID from /run/user (prefer non-root UID, usually 1000)
|
|
137
|
+
const IDS = shellExec(`ls -1 /run/user`, { stdout: true, silent: true })
|
|
138
|
+
.split('\n')
|
|
139
|
+
.map((v) => v.trim())
|
|
140
|
+
.filter(Boolean);
|
|
141
|
+
|
|
142
|
+
const nonRootIds = IDS.filter((id) => id !== '0');
|
|
143
|
+
const ID = nonRootIds.length > 0 ? nonRootIds[0] : IDS[0];
|
|
144
|
+
|
|
145
|
+
if (!options.chown) options.chown = `/home/dd ${getNpmRootPath()}/underpost`;
|
|
146
|
+
|
|
147
|
+
shellExec(`chown -R ${ID}:${ID} ${options.chown}`);
|
|
148
|
+
|
|
149
|
+
// Run the terminal as the graphical user and use THAT user's runtime dir/bus.
|
|
150
|
+
const confCmd = `USER_GRAPHICAL=$(getent passwd "${ID}" | cut -d: -f1); \
|
|
151
|
+
sudo -u "$USER_GRAPHICAL" env DISPLAY="$DISPLAY" \
|
|
152
|
+
XDG_RUNTIME_DIR="/run/user/${ID}" \
|
|
153
|
+
DBUS_SESSION_BUS_ADDRESS="unix:path=/run/user/${ID}/bus" \
|
|
154
|
+
PATH="$PATH" \
|
|
155
|
+
`;
|
|
156
|
+
|
|
134
157
|
if (options.single === true) {
|
|
135
158
|
// Run as a single session process
|
|
136
|
-
shellExec(
|
|
159
|
+
shellExec(`${confCmd} setsid gnome-terminal -- bash -ic '${cmd}; exec bash' >/dev/null 2>&1 &`, {
|
|
160
|
+
async: true,
|
|
161
|
+
});
|
|
137
162
|
return;
|
|
138
163
|
}
|
|
139
164
|
// Run asynchronously and disown
|
|
140
|
-
shellExec(
|
|
165
|
+
shellExec(`${confCmd} gnome-terminal -- bash -c '${cmd}; exec bash' >/dev/null 2>&1 & disown`, {
|
|
141
166
|
async: true,
|
|
142
167
|
stdout: true,
|
|
143
168
|
});
|
package/src/server/proxy.js
CHANGED
|
@@ -13,10 +13,8 @@ import { createProxyMiddleware } from 'http-proxy-middleware';
|
|
|
13
13
|
import { loggerFactory, loggerMiddleware } from './logger.js';
|
|
14
14
|
import { buildPortProxyRouter, buildProxyRouter, getTlsHosts, isDevProxyContext, isTlsDevProxy } from './conf.js';
|
|
15
15
|
|
|
16
|
-
import { SSL_BASE, TLS } from './tls.js';
|
|
17
16
|
import { shellExec } from './process.js';
|
|
18
17
|
import fs from 'fs-extra';
|
|
19
|
-
|
|
20
18
|
import Underpost from '../index.js';
|
|
21
19
|
|
|
22
20
|
dotenv.config();
|
|
@@ -85,7 +83,7 @@ class ProxyService {
|
|
|
85
83
|
switch (port) {
|
|
86
84
|
case 443:
|
|
87
85
|
// For port 443 (HTTPS), create the SSL server
|
|
88
|
-
const { ServerSSL } = await
|
|
86
|
+
const { ServerSSL } = await Underpost.tls.createSslServer(app, hosts);
|
|
89
87
|
await Underpost.start.listenPortController(ServerSSL, port, runningData);
|
|
90
88
|
break;
|
|
91
89
|
|
|
@@ -103,12 +101,12 @@ class ProxyService {
|
|
|
103
101
|
if (isDevProxyContext() && isTlsDevProxy()) {
|
|
104
102
|
tlsHosts = {};
|
|
105
103
|
for (const tlsHost of getTlsHosts(hosts)) {
|
|
106
|
-
if (fs.existsSync(SSL_BASE(tlsHost))) fs.removeSync(SSL_BASE(tlsHost));
|
|
107
|
-
if (!
|
|
104
|
+
if (fs.existsSync(Underpost.tls.SSL_BASE(tlsHost))) fs.removeSync(Underpost.tls.SSL_BASE(tlsHost));
|
|
105
|
+
if (!Underpost.tls.validateSecureContext(tlsHost)) shellExec(`node bin/deploy tls "${tlsHost}"`);
|
|
108
106
|
tlsHosts[tlsHost] = {};
|
|
109
107
|
}
|
|
110
108
|
}
|
|
111
|
-
const { ServerSSL } = await
|
|
109
|
+
const { ServerSSL } = await Underpost.tls.createSslServer(app, tlsHosts);
|
|
112
110
|
await Underpost.start.listenPortController(ServerSSL, port, runningData);
|
|
113
111
|
break;
|
|
114
112
|
}
|
package/src/server/tls.js
CHANGED
|
@@ -1,8 +1,7 @@
|
|
|
1
1
|
/**
|
|
2
|
-
*
|
|
3
|
-
* primarily using Certbot files and creating HTTPS servers.
|
|
2
|
+
* Transport Layer Security (TLS) / SSL utilities and HTTPS server creation and management.
|
|
4
3
|
* @module src/server/tls.js
|
|
5
|
-
* @namespace
|
|
4
|
+
* @namespace UnderpostTLS
|
|
6
5
|
*/
|
|
7
6
|
|
|
8
7
|
import fs from 'fs-extra';
|
|
@@ -43,7 +42,7 @@ class TLS {
|
|
|
43
42
|
* It attempts to be permissive: accepts cert-only, cert+ca, or fullchain.
|
|
44
43
|
* @param {string} host
|
|
45
44
|
* @returns {{key?:string, cert?:string, fullchain?:string, ca?:string, dir:string}}
|
|
46
|
-
* @memberof
|
|
45
|
+
* @memberof UnderpostTLS
|
|
47
46
|
*/
|
|
48
47
|
static locateSslFiles(host = DEFAULT_HOST) {
|
|
49
48
|
const dir = SSL_BASE(host);
|
|
@@ -103,7 +102,7 @@ class TLS {
|
|
|
103
102
|
* Validate that a secure context can be built for host (key + cert or fullchain present)
|
|
104
103
|
* @param {string} host
|
|
105
104
|
* @returns {boolean}
|
|
106
|
-
* @memberof
|
|
105
|
+
* @memberof UnderpostTLS
|
|
107
106
|
*/
|
|
108
107
|
static validateSecureContext(host = DEFAULT_HOST) {
|
|
109
108
|
const files = TLS.locateSslFiles(host);
|
|
@@ -116,7 +115,7 @@ class TLS {
|
|
|
116
115
|
* If separate cert + ca are found, they will be used accordingly.
|
|
117
116
|
* @param {string} host
|
|
118
117
|
* @returns {{key:string, cert:string, ca?:string}} options
|
|
119
|
-
* @memberof
|
|
118
|
+
* @memberof UnderpostTLS
|
|
120
119
|
*/
|
|
121
120
|
static buildSecureContext(host = DEFAULT_HOST) {
|
|
122
121
|
const files = TLS.locateSslFiles(host);
|
|
@@ -142,7 +141,7 @@ class TLS {
|
|
|
142
141
|
* The function will copy existing discovered files to: key.key, crt.crt, ca_bundle.crt when possible.
|
|
143
142
|
* @param {string} host
|
|
144
143
|
* @returns {boolean} true if at least key+cert exist after operation
|
|
145
|
-
* @memberof
|
|
144
|
+
* @memberof UnderpostTLS
|
|
146
145
|
*/
|
|
147
146
|
static async buildLocalSSL(host = DEFAULT_HOST) {
|
|
148
147
|
const dir = SSL_BASE(host);
|
|
@@ -177,19 +176,16 @@ class TLS {
|
|
|
177
176
|
* @param {import('express').Application} app
|
|
178
177
|
* @param {Object<string, any>} hosts
|
|
179
178
|
* @returns {{ServerSSL?: https.Server}}
|
|
180
|
-
* @memberof
|
|
179
|
+
* @memberof UnderpostTLS
|
|
181
180
|
*/
|
|
182
181
|
static async createSslServer(app, hosts = { [DEFAULT_HOST]: {} }) {
|
|
183
182
|
let server;
|
|
184
183
|
for (const host of Object.keys(hosts)) {
|
|
185
184
|
// ensure canonical files exist (copies where possible)
|
|
186
185
|
await TLS.buildLocalSSL(host);
|
|
187
|
-
if (!TLS.
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
logger.error('Invalid SSL context, skipping host', { host });
|
|
191
|
-
continue;
|
|
192
|
-
}
|
|
186
|
+
if (!TLS.validateSecureContext(host)) {
|
|
187
|
+
logger.error('Invalid SSL context, skipping host', { host });
|
|
188
|
+
continue;
|
|
193
189
|
}
|
|
194
190
|
|
|
195
191
|
// build secure context options
|
|
@@ -218,7 +214,7 @@ class TLS {
|
|
|
218
214
|
* @param {number} port
|
|
219
215
|
* @param {Object<string, any>} proxyRouter
|
|
220
216
|
* @returns {import('express').RequestHandler}
|
|
221
|
-
* @memberof
|
|
217
|
+
* @memberof UnderpostTLS
|
|
222
218
|
*/
|
|
223
219
|
static sslRedirectMiddleware(req, res, port = 80, proxyRouter = {}) {
|
|
224
220
|
const sslRedirectUrl = `https://${req.headers.host}${req.url}`;
|
|
@@ -238,14 +234,23 @@ class TLS {
|
|
|
238
234
|
}
|
|
239
235
|
}
|
|
240
236
|
|
|
241
|
-
|
|
242
|
-
|
|
243
|
-
|
|
244
|
-
|
|
245
|
-
|
|
246
|
-
|
|
247
|
-
|
|
248
|
-
|
|
249
|
-
|
|
237
|
+
/**
|
|
238
|
+
* @class UnderpostTLS
|
|
239
|
+
* @description TLS/SSL utilities for Underpost.
|
|
240
|
+
* @memberof UnderpostTLS
|
|
241
|
+
*/
|
|
242
|
+
class UnderpostTLS {
|
|
243
|
+
static API = {
|
|
244
|
+
TLS,
|
|
245
|
+
SSL_BASE,
|
|
246
|
+
locateSslFiles: TLS.locateSslFiles,
|
|
247
|
+
validateSecureContext: TLS.validateSecureContext,
|
|
248
|
+
buildSecureContext: TLS.buildSecureContext,
|
|
249
|
+
buildLocalSSL: TLS.buildLocalSSL,
|
|
250
|
+
createSslServer: TLS.createSslServer,
|
|
251
|
+
sslRedirectMiddleware: TLS.sslRedirectMiddleware,
|
|
252
|
+
};
|
|
253
|
+
}
|
|
250
254
|
|
|
251
|
-
export { TLS, SSL_BASE,
|
|
255
|
+
export { TLS, SSL_BASE, UnderpostTLS };
|
|
256
|
+
export default UnderpostTLS;
|