Prevent broken logo from crashing site (#2619)

* Prevent broken logo from crashing site

* Cache icons in memory to make site less vulnerable to DOS attacks

* Swap try and if blocks for apple touch icon
This commit is contained in:
SleeplessOne1917 2024-07-21 18:56:57 +00:00 committed by GitHub
parent ab51245ca5
commit 01c095d269
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
2 changed files with 58 additions and 49 deletions

View file

@ -33,22 +33,29 @@ export async function createSsrHtml(
); );
if (!appleTouchIcon) { if (!appleTouchIcon) {
appleTouchIcon = site?.site_view.site.icon try {
? `data:image/png;base64,${await sharp( appleTouchIcon = site?.site_view.site.icon
await fetchIconPng(site.site_view.site.icon), ? `data:image/png;base64,${await sharp(
) await fetchIconPng(site.site_view.site.icon),
.resize(180, 180) )
.extend({ .resize(180, 180)
bottom: 20, .extend({
top: 20, bottom: 20,
left: 20, top: 20,
right: 20, left: 20,
background: "#222222", right: 20,
}) background: "#222222",
.png() })
.toBuffer() .png()
.then(buf => buf.toString("base64"))}` .toBuffer()
: favIconPngUrl; .then(buf => buf.toString("base64"))}`
: favIconPngUrl;
} catch (e) {
console.log(
"Could not fetch site logo for apple touch icon. Using default icon.",
);
appleTouchIcon = favIconPngUrl;
}
} }
const erudaStr = const erudaStr =

View file

@ -1,19 +1,43 @@
import { readFile } from "fs/promises";
import { Site } from "lemmy-js-client"; import { Site } from "lemmy-js-client";
import path from "path";
import { fetchIconPng } from "./fetch-icon-png"; import { fetchIconPng } from "./fetch-icon-png";
import { getStaticDir } from "@utils/env";
type Icon = { sizes: string; src: string; type: string; purpose: string };
const iconSizes = [72, 96, 128, 144, 152, 192, 384, 512]; const iconSizes = [72, 96, 128, 144, 152, 192, 384, 512];
let icons: Icon[] | null = null;
const defaultLogoPathDirectory = path.join(
process.cwd(),
"dist",
"assets",
"icons",
);
export default async function (site: Site) { export default async function (site: Site) {
const icon = site.icon ? await fetchIconPng(site.icon) : null; if (!icons) {
try {
const icon = site.icon ? await fetchIconPng(site.icon) : null;
icons = await Promise.all(
iconSizes.map(async size => {
let src = `${getStaticDir()}/assets/icons/icon-${size}x${size}.png`;
if (icon) {
const sharp = (await import("sharp")).default;
src = `data:image/png:base64,${await sharp(icon)
.resize(size, size)
.png()
.toBuffer()
.then(buf => buf.toString("base64"))}`;
}
return {
sizes: `${size}x${size}`,
type: "image/png",
src,
purpose: "any maskable",
};
}),
);
} catch (e) {
console.log(
`Failed to fetch site logo for manifest icon. Using default icon`,
);
}
}
return { return {
name: site.name, name: site.name,
@ -24,29 +48,7 @@ export default async function (site: Site) {
id: "/", id: "/",
background_color: "#222222", background_color: "#222222",
theme_color: "#222222", theme_color: "#222222",
icons: await Promise.all( icons,
iconSizes.map(async size => {
let src = await readFile(
path.join(defaultLogoPathDirectory, `icon-${size}x${size}.png`),
).then(buf => buf.toString("base64"));
if (icon) {
const sharp = (await import("sharp")).default;
src = await sharp(icon)
.resize(size, size)
.png()
.toBuffer()
.then(buf => buf.toString("base64"));
}
return {
sizes: `${size}x${size}`,
type: "image/png",
src: `data:image/png;base64,${src}`,
purpose: "any maskable",
};
}),
),
shortcuts: [ shortcuts: [
{ {
name: "Search", name: "Search",