mirror of
https://github.com/bulwarkmail/native.git
synced 2026-11-01 16:05:39 +00:00
fix: keep a signed or encrypted reply-to name with a comma as one address
This commit is contained in:
@@ -102,6 +102,18 @@ describe('prepareSecureSend', () => {
|
||||
expect(new TextDecoder().decode(uploaded!)).not.toMatch(/bcc@example.org/i);
|
||||
}, 60_000);
|
||||
|
||||
it('quotes a Reply-To name with a comma so it stays one address', async () => {
|
||||
await importPgpKey(me.privateKey, me.passphrase);
|
||||
let uploaded: Uint8Array | null = null;
|
||||
const msg = { ...outgoing(), replyTo: [{ name: 'Support, ACME', email: 'help@acme.com' }] };
|
||||
await prepareSecureSend(msg, { mode: 'pgp', sign: true, encrypt: false }, {
|
||||
fetchBlob: async () => new Uint8Array([1]),
|
||||
upload: async (bytes) => { uploaded = bytes; return 'x'; },
|
||||
});
|
||||
const text = new TextDecoder().decode(uploaded!);
|
||||
expect(text).toMatch(/^Reply-To: "Support, ACME" <help@acme.com>$/m);
|
||||
}, 60_000);
|
||||
|
||||
it('stops when a recipient has no key, or when the signing key is locked', async () => {
|
||||
await importPgpKey(me.privateKey, me.passphrase);
|
||||
const deps = { fetchBlob: async () => new Uint8Array(), upload: async () => 'x' };
|
||||
|
||||
@@ -8,7 +8,7 @@ import type { OutgoingEmail } from '../../api/email';
|
||||
import type { ContactCard } from '../../api/types';
|
||||
import { useCryptoKeysStore, keysForEmail, isRecordCurrent, type CryptoKeyRecord, type PgpKeyRecord, type SmimeCertRecord } from '../../stores/crypto-keys-store';
|
||||
import { messagePriorityHeaders } from '../message-priority';
|
||||
import { base64Decode, formatHeader, encodeHeaderWords, type MimeAttachment, type MimeMessageInput } from './mime';
|
||||
import { base64Decode, formatHeader, formatAddress, type MimeAttachment, type MimeMessageInput } from './mime';
|
||||
import { buildSecureMessage, type SecureMode } from './secure-send';
|
||||
import { ownKeyFor, unlockedPgpKey, unlockedSmimeKey } from './keyring';
|
||||
|
||||
@@ -100,7 +100,7 @@ export function secureReadiness(choice: SecureChoice, fromEmail: string, recipie
|
||||
function extraHeaders(outgoing: OutgoingEmail): string[] {
|
||||
const lines: string[] = [];
|
||||
if (outgoing.replyTo?.length) {
|
||||
lines.push(formatHeader('Reply-To', outgoing.replyTo.map((a) => (a.name ? `${encodeHeaderWords(a.name)} <${a.email}>` : a.email)).join(', ')));
|
||||
lines.push(formatHeader('Reply-To', outgoing.replyTo.map(formatAddress).join(', ')));
|
||||
}
|
||||
for (const [prop, value] of Object.entries(messagePriorityHeaders(outgoing.priority))) {
|
||||
const name = /^header:([^:]+):/.exec(prop)?.[1];
|
||||
|
||||
@@ -90,7 +90,8 @@ function unfold(value: string | undefined): string {
|
||||
return String(value ?? '').replace(/[\r\n\t]+/g, ' ').replace(/ {2,}/g, ' ').trim();
|
||||
}
|
||||
|
||||
function formatAddress(addr: MimeAddress): string {
|
||||
/** One address for a header: the name quoted (or RFC 2047-encoded) so commas in it stay inside. */
|
||||
export function formatAddress(addr: MimeAddress): string {
|
||||
if (addr.name) {
|
||||
const name = unfold(addr.name);
|
||||
// Raw 8-bit in a header is rejected by some MTAs; encode it.
|
||||
|
||||
Reference in New Issue
Block a user