fix(places): e-mail check without a backtracking regex; explicit grouping in the no-proxy match

This commit is contained in:
Maurice
2026-10-01 16:10:33 +02:00
parent 8f4accc8a5
commit 5669f8b860
3 changed files with 14 additions and 3 deletions
+1 -1
View File
@@ -541,7 +541,7 @@ export function proxyFor(rawUrl: string, proxy = PROXY): string | null {
const port = url.port || (url.protocol === 'https:' ? '443' : '80');
const bypass = proxy.noProxy.some((entry) => {
if (entry === '*') return true;
const [name, entryPort] = entry.replace(/^\[|\](?=:|$)/g, '').split(/:(?=\d+$)/);
const [name, entryPort] = entry.replace(/(?:^\[)|(?:\](?=:|$))/g, '').split(/:(?=\d+$)/);
if (entryPort && entryPort !== port) return false;
const bare = name.replace(/^\*?\./, '');
return host === bare || host.endsWith(`.${bare}`);
+4
View File
@@ -29,6 +29,10 @@ describe('place hours and e-mail (#2472)', () => {
expect(placeEmailField.safeParse('a@b.co').success).toBe(true);
expect(placeEmailField.safeParse('').success).toBe(true);
expect(placeEmailField.safeParse('nope').success).toBe(false);
for (const bad of ['@b.co', 'a@@b.co', 'a@b@c.co', 'a@bco', 'a@.co', 'a@b.', 'a b@c.co']) {
expect(placeEmailField.safeParse(bad).success).toBe(false);
}
expect(placeEmailField.safeParse(' a.b@mail.example.org ').success).toBe(true);
expect(placeCreateRequestSchema.safeParse({ name: 'X', email: 'nope' }).success).toBe(false);
expect(placeUpdateRequestSchema.safeParse({ opening_hours: WEEK, email: null }).success).toBe(true);
});
+9 -2
View File
@@ -47,12 +47,19 @@ export const placeOpeningHoursField = z
.nullable()
.optional();
const EMAIL = /^[^\s@]+@[^\s@]+\.[^\s@]+$/;
/** One @ with something on both sides, a dot inside the domain, no whitespace anywhere. */
function isEmail(value: string): boolean {
if (/\s/.test(value)) return false;
const at = value.indexOf('@');
if (at < 1 || at !== value.lastIndexOf('@')) return false;
// A dot with something on both sides, like the former /[^\s@]+\.[^\s@]+$/ domain part.
return value.slice(at + 2, -1).includes('.');
}
/** An e-mail address, or empty to clear it. */
export const placeEmailField = z
.string()
.max(254)
.refine((v) => v === '' || EMAIL.test(v.trim()), { message: 'email must be an e-mail address' })
.refine((v) => v === '' || isEmail(v.trim()), { message: 'email must be an e-mail address' })
.nullable()
.optional();