feat: add branded 404 page
This commit is contained in:
@@ -11,7 +11,7 @@ import { seedDemoMemes } from './src/seed.js';
|
||||
import { moderateImage } from './src/moderation.js';
|
||||
import { createUploadLimiter } from './src/uploadLimits.js';
|
||||
import { createIpRateLimiter } from './src/rateLimits.js';
|
||||
import { feedJson, llmsTxt, manifest, noIndex, publicBaseUrl, renderIndex, robotsTxt, sitemapXml } from './src/seo.js';
|
||||
import { feedJson, llmsTxt, manifest, noIndex, publicBaseUrl, renderIndex, renderNotFound, robotsTxt, sitemapXml } from './src/seo.js';
|
||||
|
||||
await loadDotEnv();
|
||||
|
||||
@@ -36,6 +36,7 @@ const DISCOVERY_ROUTES = new Set([
|
||||
]);
|
||||
const ADMIN_TOKEN = process.env.ADMIN_TOKEN || crypto.randomBytes(24).toString('hex');
|
||||
const indexTemplate = await fs.readFile('./public/index.html', 'utf8');
|
||||
const notFoundTemplate = await fs.readFile('./public/404.html', 'utf8');
|
||||
const openApiSpec = JSON.parse(await fs.readFile('./openapi.json', 'utf8'));
|
||||
const memeApiSkillTemplate = await fs.readFile('./meme-api.skill.md', 'utf8');
|
||||
|
||||
@@ -90,7 +91,9 @@ const server = http.createServer(async (req, res) => {
|
||||
const memePageMatch = url.pathname.match(/^\/meme\/([a-f0-9]{64})\/?$/);
|
||||
if (req.method === 'GET' && memePageMatch) {
|
||||
const meme = store.get(memePageMatch[1]);
|
||||
if (!meme || meme.status !== 'approved') return sendText(res, 404, 'Not found');
|
||||
if (!meme || meme.status !== 'approved') {
|
||||
return sendNotFoundPage(res, { baseUrl, pathname: url.pathname });
|
||||
}
|
||||
const nonce = crypto.randomBytes(16).toString('base64');
|
||||
withSecurityHeaders(res, { scriptNonce: nonce });
|
||||
return sendHtml(res, 200, renderIndex({
|
||||
@@ -292,6 +295,9 @@ const server = http.createServer(async (req, res) => {
|
||||
return sendJson(res, 200, { ok: true });
|
||||
}
|
||||
|
||||
if (isBrowserPageRequest(req, url)) {
|
||||
return sendNotFoundPage(res, { baseUrl, pathname: url.pathname });
|
||||
}
|
||||
return sendText(res, 404, 'Not found');
|
||||
} catch (error) {
|
||||
const status = error.statusCode || 500;
|
||||
@@ -323,6 +329,27 @@ function isDiscoveryRoute(req, url) {
|
||||
return DISCOVERY_ROUTES.has(url.pathname);
|
||||
}
|
||||
|
||||
function isBrowserPageRequest(req, url) {
|
||||
if (req.method !== 'GET') return false;
|
||||
return ![
|
||||
'/api',
|
||||
'/assets',
|
||||
'/media',
|
||||
'/download',
|
||||
'/admin',
|
||||
'/admin-media'
|
||||
].some((prefix) => url.pathname === prefix || url.pathname.startsWith(`${prefix}/`));
|
||||
}
|
||||
|
||||
function sendNotFoundPage(res, { baseUrl, pathname }) {
|
||||
noIndex(res);
|
||||
return sendHtml(res, 404, renderNotFound({
|
||||
template: notFoundTemplate,
|
||||
baseUrl,
|
||||
pathname
|
||||
}));
|
||||
}
|
||||
|
||||
async function loadDotEnv() {
|
||||
let content = '';
|
||||
try {
|
||||
|
||||
Reference in New Issue
Block a user