fix(tui): preserve credential-like tokens in render sanitization

This commit is contained in:
Vignesh Natarajan
2026-03-05 21:05:52 -08:00
parent 5d4b04040d
commit 8d4a2f2c59
3 changed files with 30 additions and 1 deletions

View File

@@ -249,6 +249,20 @@ describe("sanitizeRenderableText", () => {
expect(sanitized).toBe(input);
});
it("preserves long credential-like mixed alnum tokens for copy safety", () => {
const input = "e3b19c3b87bcf364b23eebb2c276e96ec478956ba1d84c93";
const sanitized = sanitizeRenderableText(input);
expect(sanitized).toBe(input);
});
it("preserves quoted credential-like mixed alnum tokens for copy safety", () => {
const input = "'e3b19c3b87bcf364b23eebb2c276e96ec478956ba1d84c93'";
const sanitized = sanitizeRenderableText(input);
expect(sanitized).toBe(input);
});
it("wraps rtl lines with directional isolation marks", () => {
const input = "مرحبا بالعالم";
const sanitized = sanitizeRenderableText(input);

View File

@@ -11,6 +11,8 @@ const BINARY_LINE_REPLACEMENT_THRESHOLD = 12;
const URL_PREFIX_RE = /^(https?:\/\/|file:\/\/)/i;
const WINDOWS_DRIVE_RE = /^[a-zA-Z]:[\\/]/;
const FILE_LIKE_RE = /^[a-zA-Z0-9._-]+$/;
const EDGE_PUNCTUATION_RE = /^[`"'([{<]+|[`"')\]}>.,:;!?]+$/g;
const TOKENISH_MIN_LENGTH = 24;
const RTL_SCRIPT_RE = /[\u0590-\u08ff\ufb1d-\ufdff\ufe70-\ufefc]/;
const BIDI_CONTROL_RE = /[\u202a-\u202e\u2066-\u2069]/;
const RTL_ISOLATE_START = "\u2067";
@@ -56,6 +58,9 @@ function chunkToken(token: string, maxChars: number): string[] {
}
function isCopySensitiveToken(token: string): boolean {
const coreToken = token.replace(EDGE_PUNCTUATION_RE, "");
const candidate = coreToken || token;
if (URL_PREFIX_RE.test(token)) {
return true;
}
@@ -73,7 +78,16 @@ function isCopySensitiveToken(token: string): boolean {
if (token.includes("/") || token.includes("\\")) {
return true;
}
return token.includes("_") && FILE_LIKE_RE.test(token);
if (token.includes("_") && FILE_LIKE_RE.test(token)) {
return true;
}
// Preserve long credential-like tokens (hex/base62/etc.) to avoid introducing
// visible spaces that users may copy back into secrets.
if (candidate.length >= TOKENISH_MIN_LENGTH && /[a-z]/i.test(candidate) && /\d/.test(candidate)) {
return true;
}
return false;
}
function normalizeLongTokenForDisplay(token: string): string {