security hardening
This commit is contained in:
@@ -9,10 +9,12 @@ import {
|
||||
normaliseIban,
|
||||
} from "../services/invoice/validation";
|
||||
import { STORED_LOGO_SENTINEL } from "../services/invoice/logoCache.constants";
|
||||
import { validateMerchantHttpsUrl } from "../services/invoice/safeFetch.server";
|
||||
import {
|
||||
deleteStoredLogo,
|
||||
storeUploadedLogo,
|
||||
} from "../services/invoice/logoCache.server";
|
||||
import { encryptField } from "../services/crypto/fieldCrypto.server";
|
||||
import { RichTextEditor } from "../components/RichTextEditor";
|
||||
import {
|
||||
DEFAULT_EMAIL_BODY_DE,
|
||||
@@ -122,6 +124,13 @@ export const action = async ({ request }: ActionFunctionArgs) => {
|
||||
select: { logoUrl: true },
|
||||
});
|
||||
const submittedLogoUrl = str("logoUrl");
|
||||
// Validate any merchant-supplied external logo URL at the trust boundary:
|
||||
// require a syntactically valid https URL whose host is a domain name, not
|
||||
// an IP literal (SSRF defence-in-depth; safeFetch is the runtime backstop).
|
||||
if (submittedLogoUrl && submittedLogoUrl !== STORED_LOGO_SENTINEL) {
|
||||
const urlError = validateMerchantHttpsUrl(submittedLogoUrl);
|
||||
if (urlError) errors.logo = urlError;
|
||||
}
|
||||
const removeLogo = bool("removeLogo");
|
||||
const logoFile = form.get("logoFile");
|
||||
const hasUpload =
|
||||
@@ -154,13 +163,17 @@ export const action = async ({ request }: ActionFunctionArgs) => {
|
||||
const submittedSmtpPassword = str("smtpPassword");
|
||||
let nextSmtpPassword: string;
|
||||
if (submittedSmtpPassword === SMTP_PASSWORD_SENTINEL) {
|
||||
// Unchanged: keep the stored value as-is (already encrypted at rest).
|
||||
const current = await db.shopSettings.findUnique({
|
||||
where: { shopDomain: session.shop },
|
||||
select: { smtpPassword: true },
|
||||
});
|
||||
nextSmtpPassword = current?.smtpPassword ?? "";
|
||||
} else {
|
||||
nextSmtpPassword = submittedSmtpPassword;
|
||||
// New password (including "" to clear). Encrypt non-empty values at rest.
|
||||
nextSmtpPassword = submittedSmtpPassword
|
||||
? encryptField(submittedSmtpPassword)
|
||||
: "";
|
||||
}
|
||||
|
||||
const data = {
|
||||
|
||||
Reference in New Issue
Block a user