mirror of
https://github.com/juherr/kill-the-news.git
synced 2026-06-20 22:03:48 +00:00
refactor: replace custom escapeHtml with Hono's html template
Hono's `html` tagged template auto-escapes all interpolated values; `raw()` is used for the email body which must render as HTML. This removes the ad-hoc utility and aligns entries.ts with the same pattern already used in admin.ts. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
+13
-17
@@ -1,6 +1,6 @@
|
|||||||
import { Context } from "hono";
|
import { Context } from "hono";
|
||||||
|
import { html, raw } from "hono/html";
|
||||||
import { Env, FeedMetadata, EmailData } from "../types";
|
import { Env, FeedMetadata, EmailData } from "../types";
|
||||||
import { escapeHtml } from "../utils/html";
|
|
||||||
|
|
||||||
export async function handle(c: Context): Promise<Response> {
|
export async function handle(c: Context): Promise<Response> {
|
||||||
const env = c.env as unknown as Env;
|
const env = c.env as unknown as Env;
|
||||||
@@ -34,12 +34,17 @@ export async function handle(c: Context): Promise<Response> {
|
|||||||
return new Response("Entry not found", { status: 404 });
|
return new Response("Entry not found", { status: 404 });
|
||||||
}
|
}
|
||||||
|
|
||||||
const html = `<!DOCTYPE html>
|
c.header(
|
||||||
|
"Content-Security-Policy",
|
||||||
|
"default-src 'none'; style-src 'unsafe-inline'; img-src *; frame-src 'none'",
|
||||||
|
);
|
||||||
|
|
||||||
|
return c.html(html`<!DOCTYPE html>
|
||||||
<html>
|
<html>
|
||||||
<head>
|
<head>
|
||||||
<meta charset="UTF-8">
|
<meta charset="UTF-8">
|
||||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||||
<title>${escapeHtml(emailData.subject)}</title>
|
<title>${emailData.subject}</title>
|
||||||
<style>
|
<style>
|
||||||
body { font-family: sans-serif; max-width: 800px; margin: 0 auto; padding: 1rem; }
|
body { font-family: sans-serif; max-width: 800px; margin: 0 auto; padding: 1rem; }
|
||||||
.meta { color: #666; font-size: 0.875rem; margin-bottom: 1.5rem; border-bottom: 1px solid #eee; padding-bottom: 0.75rem; }
|
.meta { color: #666; font-size: 0.875rem; margin-bottom: 1.5rem; border-bottom: 1px solid #eee; padding-bottom: 0.75rem; }
|
||||||
@@ -48,21 +53,12 @@ export async function handle(c: Context): Promise<Response> {
|
|||||||
</style>
|
</style>
|
||||||
</head>
|
</head>
|
||||||
<body>
|
<body>
|
||||||
<h1>${escapeHtml(emailData.subject)}</h1>
|
<h1>${emailData.subject}</h1>
|
||||||
<dl class="meta">
|
<dl class="meta">
|
||||||
<dt>From:</dt><dd>${escapeHtml(emailData.from)}</dd>
|
<dt>From:</dt><dd>${emailData.from}</dd>
|
||||||
<dt>Date:</dt><dd>${escapeHtml(new Date(emailData.receivedAt).toUTCString())}</dd>
|
<dt>Date:</dt><dd>${new Date(emailData.receivedAt).toUTCString()}</dd>
|
||||||
</dl>
|
</dl>
|
||||||
<div class="content">${emailData.content}</div>
|
<div class="content">${raw(emailData.content)}</div>
|
||||||
</body>
|
</body>
|
||||||
</html>`;
|
</html>`);
|
||||||
|
|
||||||
return new Response(html, {
|
|
||||||
status: 200,
|
|
||||||
headers: {
|
|
||||||
"Content-Type": "text/html; charset=utf-8",
|
|
||||||
"Content-Security-Policy":
|
|
||||||
"default-src 'none'; style-src 'unsafe-inline'; img-src *; frame-src 'none'",
|
|
||||||
},
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,7 +0,0 @@
|
|||||||
export function escapeHtml(str: string): string {
|
|
||||||
return str
|
|
||||||
.replace(/&/g, "&")
|
|
||||||
.replace(/</g, "<")
|
|
||||||
.replace(/>/g, ">")
|
|
||||||
.replace(/"/g, """);
|
|
||||||
}
|
|
||||||
Reference in New Issue
Block a user