mirror of
https://github.com/openai/codex.git
synced 2026-09-04 15:08:45 +00:00
refactor(tui): share osc text sanitization
This commit is contained in:
@@ -164,6 +164,7 @@ mod notifications;
|
||||
#[cfg(any(not(debug_assertions), test))]
|
||||
mod npm_registry;
|
||||
pub(crate) mod onboarding;
|
||||
mod osc_text;
|
||||
mod oss_selection;
|
||||
mod pager_overlay;
|
||||
mod permission_compat;
|
||||
|
||||
28
codex-rs/tui/src/osc_text.rs
Normal file
28
codex-rs/tui/src/osc_text.rs
Normal file
@@ -0,0 +1,28 @@
|
||||
//! Sanitization for untrusted terminal-title and tab-status OSC text.
|
||||
|
||||
/// Whether a control or invisible formatting character is unsafe in OSC text.
|
||||
pub(crate) fn is_disallowed_osc_text_char(ch: char) -> bool {
|
||||
if ch.is_control() {
|
||||
return true;
|
||||
}
|
||||
|
||||
matches!(
|
||||
ch,
|
||||
'\u{00AD}'
|
||||
| '\u{034F}'
|
||||
| '\u{061C}'
|
||||
| '\u{180E}'
|
||||
| '\u{200B}'..='\u{200F}'
|
||||
| '\u{202A}'..='\u{202E}'
|
||||
| '\u{2060}'..='\u{206F}'
|
||||
| '\u{FE00}'..='\u{FE0F}'
|
||||
| '\u{FEFF}'
|
||||
| '\u{FFF9}'..='\u{FFFB}'
|
||||
| '\u{1BCA0}'..='\u{1BCA3}'
|
||||
| '\u{E0100}'..='\u{E01EF}'
|
||||
)
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
#[path = "osc_text_tests.rs"]
|
||||
mod tests;
|
||||
24
codex-rs/tui/src/osc_text_tests.rs
Normal file
24
codex-rs/tui/src/osc_text_tests.rs
Normal file
@@ -0,0 +1,24 @@
|
||||
use super::is_disallowed_osc_text_char;
|
||||
|
||||
#[test]
|
||||
fn rejects_controls_bidi_and_invisible_format_chars() {
|
||||
for ch in [
|
||||
'\x07', '\x1b', '\u{009b}', '\n', '\u{202E}', '\u{2066}', '\u{200F}', '\u{061C}',
|
||||
'\u{200B}', '\u{FEFF}',
|
||||
] {
|
||||
assert!(
|
||||
is_disallowed_osc_text_char(ch),
|
||||
"expected {ch:?} to be disallowed"
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn allows_ordinary_text() {
|
||||
for ch in ['a', 'Z', '0', ' ', '/', '.', '\u{2026}', '\u{00E9}'] {
|
||||
assert!(
|
||||
!is_disallowed_osc_text_char(ch),
|
||||
"expected {ch:?} to be allowed"
|
||||
);
|
||||
}
|
||||
}
|
||||
@@ -121,7 +121,7 @@ fn sanitize_terminal_title(title: &str) -> String {
|
||||
continue;
|
||||
}
|
||||
|
||||
if is_disallowed_terminal_title_char(ch) {
|
||||
if crate::osc_text::is_disallowed_osc_text_char(ch) {
|
||||
continue;
|
||||
}
|
||||
|
||||
@@ -145,37 +145,6 @@ fn sanitize_terminal_title(title: &str) -> String {
|
||||
sanitized
|
||||
}
|
||||
|
||||
/// Returns whether `ch` should be dropped from terminal-title output.
|
||||
///
|
||||
/// This includes both plain control characters and a curated set of invisible
|
||||
/// formatting codepoints. The bidi entries here cover the Trojan-Source-style
|
||||
/// text-reordering controls that can make a title render misleadingly relative
|
||||
/// to its underlying byte sequence.
|
||||
fn is_disallowed_terminal_title_char(ch: char) -> bool {
|
||||
if ch.is_control() {
|
||||
return true;
|
||||
}
|
||||
|
||||
// Strip Trojan-Source-related bidi controls plus common non-rendering
|
||||
// formatting characters so title text cannot smuggle terminal control
|
||||
// semantics or visually misleading content.
|
||||
matches!(
|
||||
ch,
|
||||
'\u{00AD}'
|
||||
| '\u{034F}'
|
||||
| '\u{061C}'
|
||||
| '\u{180E}'
|
||||
| '\u{200B}'..='\u{200F}'
|
||||
| '\u{202A}'..='\u{202E}'
|
||||
| '\u{2060}'..='\u{206F}'
|
||||
| '\u{FE00}'..='\u{FE0F}'
|
||||
| '\u{FEFF}'
|
||||
| '\u{FFF9}'..='\u{FFFB}'
|
||||
| '\u{1BCA0}'..='\u{1BCA3}'
|
||||
| '\u{E0100}'..='\u{E01EF}'
|
||||
)
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::MAX_TERMINAL_TITLE_CHARS;
|
||||
|
||||
Reference in New Issue
Block a user