From 01c095d269bd25b879dde1a3306488a21afd9488 Mon Sep 17 00:00:00 2001 From: SleeplessOne1917 <28871516+SleeplessOne1917@users.noreply.github.com> Date: Sun, 21 Jul 2024 18:56:57 +0000 Subject: [PATCH] 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 --- src/server/utils/create-ssr-html.tsx | 39 ++++++++----- src/server/utils/generate-manifest-json.ts | 68 +++++++++++----------- 2 files changed, 58 insertions(+), 49 deletions(-) diff --git a/src/server/utils/create-ssr-html.tsx b/src/server/utils/create-ssr-html.tsx index fddb5b26..e69eff76 100644 --- a/src/server/utils/create-ssr-html.tsx +++ b/src/server/utils/create-ssr-html.tsx @@ -33,22 +33,29 @@ export async function createSsrHtml( ); if (!appleTouchIcon) { - appleTouchIcon = site?.site_view.site.icon - ? `data:image/png;base64,${await sharp( - await fetchIconPng(site.site_view.site.icon), - ) - .resize(180, 180) - .extend({ - bottom: 20, - top: 20, - left: 20, - right: 20, - background: "#222222", - }) - .png() - .toBuffer() - .then(buf => buf.toString("base64"))}` - : favIconPngUrl; + try { + appleTouchIcon = site?.site_view.site.icon + ? `data:image/png;base64,${await sharp( + await fetchIconPng(site.site_view.site.icon), + ) + .resize(180, 180) + .extend({ + bottom: 20, + top: 20, + left: 20, + right: 20, + background: "#222222", + }) + .png() + .toBuffer() + .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 = diff --git a/src/server/utils/generate-manifest-json.ts b/src/server/utils/generate-manifest-json.ts index 5571a39a..969f3d4b 100644 --- a/src/server/utils/generate-manifest-json.ts +++ b/src/server/utils/generate-manifest-json.ts @@ -1,19 +1,43 @@ -import { readFile } from "fs/promises"; import { Site } from "lemmy-js-client"; -import path from "path"; 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 defaultLogoPathDirectory = path.join( - process.cwd(), - "dist", - "assets", - "icons", -); +let icons: Icon[] | null = null; 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 { name: site.name, @@ -24,29 +48,7 @@ export default async function (site: Site) { id: "/", background_color: "#222222", theme_color: "#222222", - icons: await Promise.all( - 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", - }; - }), - ), + icons, shortcuts: [ { name: "Search",