diff --git a/apps/web/pages/api/logo.ts b/apps/web/pages/api/logo.ts index 0e7f0e66c2..5afdedeb16 100644 --- a/apps/web/pages/api/logo.ts +++ b/apps/web/pages/api/logo.ts @@ -1,106 +1,80 @@ -import fs from "fs"; -import mime from "mime-types"; import type { NextApiRequest, NextApiResponse } from "next"; -import path from "path"; import { z } from "zod"; -import { LOGO, LOGO_ICON } from "@calcom/lib/constants"; -import logger from "@calcom/lib/logger"; - -const log = logger.getChildLogger({ prefix: [`[api/logo]`] }); +import { IS_SELF_HOSTED, LOGO, LOGO_ICON, WEBAPP_URL } from "@calcom/lib/constants"; function removePort(url: string) { return url.replace(/:\d+$/, ""); } -function extractSubdomainAndDomain(url: string): [string, string] | null { - try { - const parsedUrl = new URL(url); - const hostParts = parsedUrl.href.split("."); - if (hostParts.length > 2) { - const subdomain = hostParts.slice(0, hostParts.length - 2).join("."); - const domain = hostParts.slice(hostParts.length - 2).join("."); - return [subdomain, removePort(domain)]; - } else if (hostParts.length === 2) { - const subdomain = ""; - const domain = hostParts.join("."); - return [subdomain, removePort(domain)]; - } else { - return null; - } - } catch (error) { - return null; - } +function extractSubdomainAndDomain(hostname: string) { + const hostParts = removePort(hostname).split("."); + + const subdomainParts = hostParts.slice(0, hostParts.length - 2); + const domain = hostParts.slice(hostParts.length - 2).join("."); + + return [subdomainParts[0], domain]; } const logoApiSchema = z.object({ icon: z.coerce.boolean().optional(), }); -function handleDefaultLogo( - req: NextApiRequest, - res: NextApiResponse, - parsedQuery?: z.infer -) { - let fileNameParts = LOGO.split("."); +const SYSTEM_SUBDOMAINS = ["console", "app", "www"]; - if (parsedQuery?.icon) { - fileNameParts = LOGO_ICON.split("."); +async function getTeamLogos(subdomain: string) { + if ( + // if not cal.com + IS_SELF_HOSTED || + // missing subdomain (empty string) + !subdomain || + // in SYSTEM_SUBDOMAINS list + SYSTEM_SUBDOMAINS.includes(subdomain) + ) { + return { + appLogo: `${WEBAPP_URL}${LOGO}`, + appIconLogo: `${WEBAPP_URL}${LOGO_ICON}`, + }; } - - const { [fileNameParts.length - 1]: fileExtension } = fileNameParts; - const STATIC_PATH = path.join(process.cwd(), "public" + LOGO); - const imageBuffer = fs.readFileSync(STATIC_PATH); - const mimeType = mime.lookup(fileExtension); - if (mimeType) res.setHeader("Content-Type", mimeType); - res.setHeader("Cache-Control", "s-maxage=86400"); - res.send(imageBuffer); + // load from DB + const { default: prisma } = await import("@calcom/prisma"); + const team = await prisma.team.findUniqueOrThrow({ + where: { + slug: subdomain, + }, + select: { + appLogo: true, + appIconLogo: true, + }, + }); + // try to use team logos, otherwise default to LOGO/LOGO_ICON regardless + return { + appLogo: team.appLogo || `${WEBAPP_URL}${LOGO}`, + appIconLogo: team.appIconLogo || `${WEBAPP_URL}${LOGO_ICON}`, + }; } /** * This API endpoint is used to serve the logo associated with a team if no logo is found we serve our default logo */ export default async function handler(req: NextApiRequest, res: NextApiResponse) { - try { - const { query } = req; - const parsedQuery = logoApiSchema.parse(query); + const { query } = req; + const parsedQuery = logoApiSchema.parse(query); - const hostname = req?.headers["host"]; - if (!hostname) throw new Error("No hostname"); - const domains = extractSubdomainAndDomain(hostname); - if (!domains) throw new Error("No domains"); - const [subdomain, domain] = domains; - // Only supported on cal.com and cal.dev - if (["cal.com", "cal.dev"].includes(domain)) return handleDefaultLogo(req, res, parsedQuery); - // Skip if no subdomain - if (!subdomain) throw new Error("No subdomain"); - // Omit system subdomains - if (["console", "app", "www"].includes(subdomain)) return handleDefaultLogo(req, res, parsedQuery); + const hostname = req?.headers["host"]; + if (!hostname) throw new Error("No hostname"); + const domains = extractSubdomainAndDomain(hostname); + if (!domains) throw new Error("No domains"); - const { default: prisma } = await import("@calcom/prisma"); + const [subdomain] = domains; + const { appLogo, appIconLogo } = await getTeamLogos(subdomain); - const team = await prisma.team.findUnique({ - where: { - slug: subdomain, - }, - select: { - appLogo: true, - appIconLogo: true, - }, - }); + const filteredLogo = parsedQuery?.icon ? appIconLogo : appLogo; - const filteredLogo = parsedQuery?.icon ? team?.appIconLogo : team?.appLogo; - - if (!filteredLogo) throw new Error("No team appLogo"); - - const response = await fetch(filteredLogo); - const arrayBuffer = await response.arrayBuffer(); - const buffer = Buffer.from(arrayBuffer); - res.setHeader("Content-Type", response.headers.get("content-type") as string); - res.setHeader("Cache-Control", "s-maxage=86400"); - res.send(buffer); - } catch (e) { - if (e instanceof Error) log.debug(e.message); - handleDefaultLogo(req, res); - } + const response = await fetch(filteredLogo); + const arrayBuffer = await response.arrayBuffer(); + const buffer = Buffer.from(arrayBuffer); + res.setHeader("Content-Type", response.headers.get("content-type") as string); + res.setHeader("Cache-Control", "s-maxage=86400"); + res.send(buffer); }