fix security issues
This commit is contained in:
@@ -11,6 +11,7 @@ import {
|
||||
DEFAULT_EMAIL_SUBJECT_EN,
|
||||
} from "./emailTemplates";
|
||||
import { STORED_LOGO_SENTINEL } from "./logoCache.constants";
|
||||
import { safeFetch, SafeFetchError, SHOPIFY_CDN_HOSTS } from "./safeFetch.server";
|
||||
|
||||
export interface SendInvoiceEmailArgs {
|
||||
shopDomain: string;
|
||||
@@ -100,9 +101,15 @@ export async function sendInvoiceEmail(
|
||||
// Download the PDF (Shopify Files URLs are public CDN URLs).
|
||||
let pdfBytes: Uint8Array;
|
||||
try {
|
||||
const res = await fetch(invoice.pdfUrl);
|
||||
if (!res.ok) throw new Error(`HTTP ${res.status}`);
|
||||
pdfBytes = new Uint8Array(await res.arrayBuffer());
|
||||
const res = await safeFetch(invoice.pdfUrl, {
|
||||
maxBytes: 25 * 1024 * 1024, // 25 MB — generous; emails impose their own limit later
|
||||
accept: "application/pdf",
|
||||
// Invoice PDFs always live on Shopify's Files CDN — anything else is
|
||||
// suspicious and should be rejected.
|
||||
allowedHosts: SHOPIFY_CDN_HOSTS,
|
||||
});
|
||||
if (res.status < 200 || res.status >= 300) throw new Error(`HTTP ${res.status}`);
|
||||
pdfBytes = res.bytes;
|
||||
} catch (err) {
|
||||
const m = err instanceof Error ? err.message : String(err);
|
||||
return failLog(args, `Failed to download invoice PDF: ${m}`, invoice.id);
|
||||
@@ -348,11 +355,17 @@ async function loadInlineLogo(
|
||||
if (!cached) return null;
|
||||
return { bytes: new Uint8Array(cached.bytes), contentType: cached.contentType };
|
||||
}
|
||||
const res = await fetch(settings.logoUrl);
|
||||
if (!res.ok) return null;
|
||||
const ct = res.headers.get("content-type") ?? "image/png";
|
||||
return { bytes: new Uint8Array(await res.arrayBuffer()), contentType: ct };
|
||||
} catch {
|
||||
const res = await safeFetch(settings.logoUrl, {
|
||||
maxBytes: 5 * 1024 * 1024,
|
||||
accept: "image/*",
|
||||
});
|
||||
if (res.status < 200 || res.status >= 300) return null;
|
||||
const ct = res.contentType ?? "image/png";
|
||||
return { bytes: res.bytes, contentType: ct };
|
||||
} catch (err) {
|
||||
if (err instanceof SafeFetchError) {
|
||||
console.warn(`Inline logo fetch refused (${err.code}): ${err.message}`);
|
||||
}
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user