mirror of
https://github.com/bulwarkmail/webmail.git
synced 2026-10-31 08:13:50 +00:00
fix: stop a quoted sender name from adding a recipient to a draft
`formatRecipient` writes a quote inside a display name as `\"`, but the parsers that read recipient strings back took every `"` as the end of the quoted name. A sender named `Support", ceo@corp.example, "x` came back from the draft stash (or the dirty check) as three recipients, one of them an address the user never chose. The splitter and its helpers now skip escaped characters inside quotes.
This commit is contained in:
@@ -375,6 +375,19 @@ describe("parseRecipientList / formatRecipientList", () => {
|
||||
it("parses an empty string to an empty array", () => {
|
||||
expect(parseRecipientList("")).toEqual([]);
|
||||
});
|
||||
|
||||
it("keeps a display name with quotes as one recipient (no injected To)", () => {
|
||||
// A sender named `Support", ceo@corp.example, "x` used to come back from
|
||||
// the draft stash as three recipients, one of them the injected ceo.
|
||||
const list = [{ name: 'Support", ceo@corp.example, "x', email: "help@vendor.example" }];
|
||||
const serialized = formatRecipientList(list);
|
||||
expect(parseRecipientList(serialized)).toEqual(list);
|
||||
});
|
||||
|
||||
it("round-trips backslashes in a quoted name", () => {
|
||||
const list = [{ name: 'a\\b, "c"', email: "x@example.com" }, { email: "y@example.com" }];
|
||||
expect(parseRecipientList(formatRecipientList(list))).toEqual(list);
|
||||
});
|
||||
});
|
||||
|
||||
describe("splitPastedRecipients", () => {
|
||||
|
||||
@@ -254,7 +254,8 @@ function angleRunCloses(value: string, from: number): boolean {
|
||||
let inQuotes = false;
|
||||
for (let i = from + 1; i < value.length; i++) {
|
||||
const ch = value[i];
|
||||
if (ch === '"') inQuotes = !inQuotes;
|
||||
if (inQuotes && ch === '\\') i++;
|
||||
else if (ch === '"') inQuotes = !inQuotes;
|
||||
else if (inQuotes) continue;
|
||||
else if (ch === '>') return true;
|
||||
else if (ch === '<') return false;
|
||||
@@ -280,7 +281,13 @@ export function splitRecipients(value: string, separators = ','): string[] {
|
||||
let inGroup = false;
|
||||
for (let i = 0; i < value.length; i++) {
|
||||
const ch = value[i];
|
||||
if (ch === '"') {
|
||||
if (inQuotes && ch === '\\' && i + 1 < value.length) {
|
||||
// A quoted-pair: formatRecipient writes a `"` in a display name as
|
||||
// `\"`. Taking it as the closing quote let a sender's name like
|
||||
// `Support", ceo@corp.example, "x` split into an extra recipient.
|
||||
current += ch + value[i + 1];
|
||||
i++;
|
||||
} else if (ch === '"') {
|
||||
inQuotes = !inQuotes;
|
||||
current += ch;
|
||||
} else if (ch === '<' && !inQuotes) {
|
||||
@@ -353,7 +360,8 @@ function findTopLevelColon(value: string): number {
|
||||
let inAngle = false;
|
||||
for (let i = 0; i < value.length; i++) {
|
||||
const ch = value[i];
|
||||
if (ch === '"') inQuotes = !inQuotes;
|
||||
if (inQuotes && ch === '\\') i++;
|
||||
else if (ch === '"') inQuotes = !inQuotes;
|
||||
else if (ch === '<' && !inQuotes) inAngle = true;
|
||||
else if (ch === '>' && !inQuotes) inAngle = false;
|
||||
else if (ch === ':' && !inQuotes && !inAngle) return i;
|
||||
|
||||
Reference in New Issue
Block a user