feat: Add custom 404 page for config visualisation server

This commit is contained in:
Göran Sander
2025-05-11 22:32:48 +02:00
parent 58e5645783
commit 35230252ff
5 changed files with 120 additions and 16 deletions

View File

@@ -9,6 +9,50 @@ import handlebars from 'handlebars';
import globals from '../globals.js';
import configObfuscate from './config-obfuscate.js';
/**
* Serves the custom 404 error page
*
* @param {object} request - The Fastify request object
* @param {object} reply - The Fastify reply object
* @returns {void}
*/
async function serve404Page(request, reply) {
try {
let template404;
const host = globals.config.get('Butler-SOS.configVisualisation.host');
const port = globals.config.get('Butler-SOS.configVisualisation.port');
if (globals.isSea) {
// In SEA mode, get the 404 template via sea.getAsset
globals.logger.verbose(`CONFIG VIS: Getting 404.html template via sea.getAsset`);
template404 = sea.getAsset('/404.html', 'utf8');
if (!template404) {
globals.logger.error(`CONFIG VIS: Could not find 404.html template in SEA assets`);
reply.code(404).send({ error: 'Page not found' });
return;
}
} else {
// In Node.js mode, read from filesystem
const filePath = path.resolve(globals.appBasePath, 'static', '404.html');
globals.logger.verbose(`CONFIG VIS: Reading 404.html template from ${filePath}`);
template404 = fs.readFileSync(filePath, 'utf8');
}
// Compile handlebars template and replace variables
const compiledTemplate = handlebars.compile(template404);
const renderedHtml = compiledTemplate({
visTaskHost: host,
visTaskPort: port,
});
// Send 404 response with custom page
reply.code(404).header('Content-Type', 'text/html; charset=utf-8').send(renderedHtml);
} catch (err) {
globals.logger.error(`CONFIG VIS: Error serving 404 page: ${err.message}`);
reply.code(404).send({ error: 'Page not found' });
}
}
/**
* Sets up and starts a web server for visualizing Butler SOS configuration.
*
@@ -107,7 +151,8 @@ export async function setupConfigVisServer(logger, config) {
);
if (!content) {
reply.code(404).send({ error: 'File not found' });
// File not found - serve custom 404 page
await serve404Page(request, reply);
return;
}
@@ -116,6 +161,29 @@ export async function setupConfigVisServer(logger, config) {
globals.logger.error(
`CONFIG VIS: Error serving static file in SEA mode: ${err.message}`
);
await serve404Page(request, reply);
}
});
// Add specific handler for the butler-sos.png file at the root path
configVisServer.get('/butler-sos.png', async (request, reply) => {
try {
// Get the asset from SEA
const logoContent = sea.getAsset('/butler-sos.png');
if (!logoContent) {
globals.logger.error(
`CONFIG VIS: Could not find butler-sos.png in SEA assets`
);
reply.code(404).send({ error: 'Logo not found' });
return;
}
reply.code(200).header('Content-Type', 'image/png').send(logoContent);
} catch (err) {
globals.logger.error(
`CONFIG VIS: Error serving logo in SEA mode: ${err.message}`
);
reply.code(500).send({ error: 'Internal server error' });
}
});
@@ -147,6 +215,9 @@ export async function setupConfigVisServer(logger, config) {
});
}
// Set up a global 404 handler for both running modes
configVisServer.setNotFoundHandler(serve404Page);
configVisServer.get('/', async (request, reply) => {
// Obfuscate the config object before sending it to the client
// First get clean copy of the config object

View File

@@ -5,15 +5,8 @@
"assets": {
"package.json": "./package.json",
"/404.html": "./static/404.html",
"/android-chrome-192x192.png": "./static/android-chrome-192x192.png",
"/android-chrome-512x512.png": "./static/android-chrome-512x512.png",
"/apple-touch-icon.png": "./static/apple-touch-icon.png",
"/butler-sos.png": "./static/ctrl-q.png",
"/favicon-16x16.png": "./static/favicon-16x16.png",
"/favicon-32x32.png": "./static/favicon-32x32.png",
"/favicon.ico": "./static/favicon.ico",
"/logo.png": "./static/logo.png",
"/index.html": "./static/index.html",
"/logo.svg": "./static/logo.svg",
"/configvis/butler-sos.png": "./static/configvis/butler-sos.png",
"/configvis/download-solid.svg": "./static/configvis/download-solid.svg",
"/configvis/index.html": "./static/configvis/index.html",

47
static/404.html Normal file
View File

@@ -0,0 +1,47 @@
<!doctype html>
<html>
<head>
<title>404 Not Found</title>
<style>
body {
text-align: center;
padding: 150px;
}
h1 {
font-size: 50px;
}
body {
font:
20px Helvetica,
sans-serif;
color: #333;
}
article {
display: block;
text-align: left;
width: 650px;
margin: 0 auto;
}
a {
color: #dc8100;
text-decoration: none;
}
a:hover {
color: #333;
text-decoration: none;
}
</style>
</head>
<body>
<article>
<img src="/butler-sos.png" alt="Butler SOS logo" style="height: 200px" />
<h1>Err. That's an error.</h1>
<p>The page you were looking for could not be found.</p>
<!-- Open in new tab -->
<p>
This really shouldn't happen, so please open a ticket in the Butler SOS bug tracker
<a target="_blank" href="https://github.com/ptarmiganlabs/butler-sos/issues/new/choose">on GitHub</a>.
</p>
</article>
</body>
</html>

BIN
static/logo.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 29 KiB

File diff suppressed because one or more lines are too long

Before

Width:  |  Height:  |  Size: 31 KiB