From 7a7290363277d7c470ec2b041b7e525e523ecb09 Mon Sep 17 00:00:00 2001 From: Linus Rath <139418639+rathlinus@users.noreply.github.com> Date: Mon, 18 May 2026 00:34:01 +0200 Subject: [PATCH] feat: show size cap on identity signature fields --- components/identity/identity-form.tsx | 58 +++++++++++++++++++++++++-- locales/cs/common.json | 2 + locales/da/common.json | 2 + locales/de/common.json | 2 + locales/en/common.json | 2 + locales/es/common.json | 2 + locales/fr/common.json | 2 + locales/it/common.json | 2 + locales/ja/common.json | 2 + locales/ko/common.json | 2 + locales/lv/common.json | 2 + locales/nl/common.json | 2 + locales/pl/common.json | 2 + locales/pt/common.json | 2 + locales/ru/common.json | 2 + locales/tr/common.json | 2 + locales/uk/common.json | 2 + locales/zh/common.json | 2 + 18 files changed, 88 insertions(+), 4 deletions(-) diff --git a/components/identity/identity-form.tsx b/components/identity/identity-form.tsx index 71cd5313..1dbefb65 100644 --- a/components/identity/identity-form.tsx +++ b/components/identity/identity-form.tsx @@ -8,6 +8,31 @@ import type { Identity, EmailAddress } from '@/lib/jmap/types'; import { sanitizeSignatureHtml } from '@/lib/email-sanitization'; import { getEmailValidationError, validateEmailList } from '@/lib/validation'; +// JMAP Identity/set caps signature fields at 2047 UTF-8 bytes per RFC 8621 §6.1. +const SIGNATURE_MAX_BYTES = 2047; +const utf8Encoder = new TextEncoder(); + +function utf8ByteLength(s: string): number { + return utf8Encoder.encode(s).length; +} + +function truncateToUtf8Bytes(s: string, maxBytes: number): string { + if (utf8ByteLength(s) <= maxBytes) return s; + let lo = 0; + let hi = s.length; + while (lo < hi) { + const mid = (lo + hi + 1) >>> 1; + if (utf8ByteLength(s.slice(0, mid)) <= maxBytes) lo = mid; + else hi = mid - 1; + } + // Don't split a surrogate pair: if we landed right after a high surrogate, back off one code unit. + if (lo > 0) { + const prev = s.charCodeAt(lo - 1); + if (prev >= 0xD800 && prev <= 0xDBFF) lo -= 1; + } + return s.slice(0, lo); +} + interface IdentityFormData { name: string; email: string; @@ -246,14 +271,15 @@ export function IdentityForm({ identity, onSave, onCancel }: IdentityFormProps)