@underpostnet/underpost 2.99.1 → 2.99.4
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/LICENSE +1 -1
- package/README.md +30 -30
- package/bin/deploy.js +49 -3
- package/cli.md +42 -31
- 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 +1 -1
- 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 +14 -12
- package/src/cli/deploy.js +6 -24
- package/src/cli/image.js +4 -4
- package/src/cli/index.js +21 -1
- package/src/cli/run.js +96 -92
- 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 +13 -1
- package/src/runtime/express/Express.js +3 -3
- package/src/server/conf.js +6 -4
- package/src/server/logger.js +11 -4
- package/src/server/process.js +27 -2
- package/src/server/proxy.js +4 -6
- package/src/server/tls.js +31 -26
|
@@ -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,7 @@ class Underpost {
|
|
|
38
39
|
* @type {String}
|
|
39
40
|
* @memberof Underpost
|
|
40
41
|
*/
|
|
41
|
-
static version = 'v2.99.
|
|
42
|
+
static version = 'v2.99.4';
|
|
42
43
|
/**
|
|
43
44
|
* Repository cli API
|
|
44
45
|
* @static
|
|
@@ -228,6 +229,16 @@ class Underpost {
|
|
|
228
229
|
static get start() {
|
|
229
230
|
return UnderpostStartUp.API;
|
|
230
231
|
}
|
|
232
|
+
|
|
233
|
+
/**
|
|
234
|
+
* TLS/SSL server utilities API
|
|
235
|
+
* @static
|
|
236
|
+
* @type {UnderpostTls.API}
|
|
237
|
+
* @memberof Underpost
|
|
238
|
+
*/
|
|
239
|
+
static get tls() {
|
|
240
|
+
return UnderpostTls.API;
|
|
241
|
+
}
|
|
231
242
|
}
|
|
232
243
|
|
|
233
244
|
const up = Underpost;
|
|
@@ -258,6 +269,7 @@ export {
|
|
|
258
269
|
UnderpostBackup,
|
|
259
270
|
UnderpostCron,
|
|
260
271
|
UnderpostStartUp,
|
|
272
|
+
UnderpostTls,
|
|
261
273
|
};
|
|
262
274
|
|
|
263
275
|
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
|
@@ -98,7 +98,7 @@ const setUpInfo = async (logger = new winston.Logger()) => {
|
|
|
98
98
|
* messages.
|
|
99
99
|
* @param meta - The `meta` parameter in the `loggerFactory` function is used to extract the last part
|
|
100
100
|
* of a URL and use it to create log files in a specific directory.
|
|
101
|
-
* @returns {
|
|
101
|
+
* @returns {underpostLogger} The `loggerFactory` function returns a logger instance created using Winston logger
|
|
102
102
|
* library. The logger instance is configured with various transports for printing out messages to
|
|
103
103
|
* different destinations such as the terminal, error.log file, and all.log file. The logger instance
|
|
104
104
|
* also has a method `setUpInfo` attached to it for setting up additional information.
|
|
@@ -133,9 +133,16 @@ const loggerFactory = (meta = { url: '' }) => {
|
|
|
133
133
|
// rejectionHandlers: [new winston.transports.File({ filename: 'rejections.log' })],
|
|
134
134
|
// exitOnError: false,
|
|
135
135
|
});
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
136
|
+
/**
|
|
137
|
+
* The returned logger is a real Winston logger instance with an extra `setUpInfo` method.
|
|
138
|
+
*
|
|
139
|
+
* @memberof Logger
|
|
140
|
+
* @typedef {winston.Logger & {
|
|
141
|
+
* setUpInfo: (logger?: winston.Logger) => Promise<void>
|
|
142
|
+
* }} underpostLogger
|
|
143
|
+
*/
|
|
144
|
+
logger.setUpInfo = () => setUpInfo(logger);
|
|
145
|
+
|
|
139
146
|
return logger;
|
|
140
147
|
};
|
|
141
148
|
|
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
|
-
*
|
|
4
|
-
* @
|
|
5
|
-
* @namespace TransportLayerSecurity
|
|
2
|
+
* @class UnderpostTls
|
|
3
|
+
* @description TLS/SSL utilities for Underpost.
|
|
4
|
+
* @memberof 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;
|