1
0
mirror of https://github.com/trezor/trezor-firmware.git synced 2025-01-27 07:40:59 +00:00

fix(core/rust): more careful management of ShortString capacity

This commit is contained in:
matejcik 2024-06-17 10:44:54 +02:00 committed by matejcik
parent 8cf039740f
commit 4e788aa2f5
13 changed files with 44 additions and 44 deletions

View File

@ -2,7 +2,6 @@ use crate::{
strutil::ShortString, strutil::ShortString,
ui::{component::EventCtx, util::ResultExt}, ui::{component::EventCtx, util::ResultExt},
}; };
use heapless::String;
/// Reified editing operations of `TextBox`. /// Reified editing operations of `TextBox`.
/// ///
@ -22,14 +21,15 @@ pub struct TextBox {
impl TextBox { impl TextBox {
/// Create a new `TextBox` with content `text`. /// Create a new `TextBox` with content `text`.
pub fn new(text: &str) -> Self { pub fn new(text: &str, max_len: usize) -> Self {
let text = unwrap!(String::try_from(text)); let text = unwrap!(ShortString::try_from(text));
debug_assert!(text.capacity() >= max_len);
Self { text } Self { text }
} }
/// Create an empty `TextBox`. /// Create an empty `TextBox`.
pub fn empty() -> Self { pub fn empty(max_len: usize) -> Self {
Self::new("") Self::new("", max_len)
} }
pub fn content(&self) -> &str { pub fn content(&self) -> &str {

View File

@ -176,7 +176,7 @@ impl Bip39Input {
pub fn new() -> Self { pub fn new() -> Self {
Self { Self {
button: Button::empty(), button: Button::empty(),
textbox: TextBox::empty(), textbox: TextBox::empty(MAX_LENGTH),
multi_tap: MultiTapKeyboard::new(), multi_tap: MultiTapKeyboard::new(),
options_num: None, options_num: None,
suggested_word: None, suggested_word: None,
@ -193,7 +193,7 @@ impl Bip39Input {
// Styling the input to reflect already filled word // Styling the input to reflect already filled word
Self { Self {
button: Button::empty().styled(theme::button_recovery_confirm()), button: Button::empty().styled(theme::button_recovery_confirm()),
textbox: TextBox::new(word), textbox: TextBox::new(word, MAX_LENGTH),
multi_tap: MultiTapKeyboard::new(), multi_tap: MultiTapKeyboard::new(),
options_num: bip39::options_num(word), options_num: bip39::options_num(word),
suggested_word: bip39::complete_word(word), suggested_word: bip39::complete_word(word),

View File

@ -414,7 +414,7 @@ impl Input {
fn new() -> Self { fn new() -> Self {
Self { Self {
area: Rect::zero(), area: Rect::zero(),
textbox: TextBox::empty(), textbox: TextBox::empty(MAX_LENGTH),
multi_tap: MultiTapKeyboard::new(), multi_tap: MultiTapKeyboard::new(),
} }
} }

View File

@ -1,5 +1,4 @@
use core::mem; use core::mem;
use heapless::String;
use crate::{ use crate::{
strutil::{ShortString, TString}, strutil::{ShortString, TString},
@ -294,7 +293,7 @@ impl PinDots {
area: Rect::zero(), area: Rect::zero(),
pad: Pad::with_background(style.background_color), pad: Pad::with_background(style.background_color),
style, style,
digits: String::new(), digits: ShortString::new(),
display_digits: false, display_digits: false,
} }
} }

View File

@ -1,7 +1,5 @@
use core::iter; use core::iter;
use heapless::String;
use crate::{ use crate::{
strutil::ShortString, strutil::ShortString,
trezorhal::slip39, trezorhal::slip39,
@ -204,7 +202,7 @@ impl Slip39Input {
Self { Self {
// Button has the same style the whole time // Button has the same style the whole time
button: Button::empty().styled(theme::button_recovery_confirm()), button: Button::empty().styled(theme::button_recovery_confirm()),
textbox: TextBox::empty(), textbox: TextBox::empty(MAX_LENGTH),
multi_tap: MultiTapKeyboard::new(), multi_tap: MultiTapKeyboard::new(),
final_word: None, final_word: None,
input_mask: Slip39Mask::full(), input_mask: Slip39Mask::full(),
@ -222,7 +220,7 @@ impl Slip39Input {
Self { Self {
// Button has the same style the whole time // Button has the same style the whole time
button: Button::empty().styled(theme::button_recovery_confirm()), button: Button::empty().styled(theme::button_recovery_confirm()),
textbox: TextBox::new(&buff), textbox: TextBox::new(&buff, MAX_LENGTH),
multi_tap: MultiTapKeyboard::new(), multi_tap: MultiTapKeyboard::new(),
final_word, final_word,
input_mask, input_mask,

View File

@ -11,8 +11,6 @@ use crate::{
}, },
}; };
use heapless::String;
use super::super::{ use super::super::{
theme, ButtonDetails, ButtonLayout, CancelConfirmMsg, ChangingTextLine, ChoiceFactory, theme, ButtonDetails, ButtonLayout, CancelConfirmMsg, ChangingTextLine, ChoiceFactory,
ChoiceItem, ChoicePage, ChoiceItem, ChoicePage,
@ -286,19 +284,24 @@ impl PassphraseEntry {
passphrase_dots: Child::new(ChangingTextLine::center_mono("", MAX_PASSPHRASE_LENGTH)), passphrase_dots: Child::new(ChangingTextLine::center_mono("", MAX_PASSPHRASE_LENGTH)),
show_plain_passphrase: false, show_plain_passphrase: false,
show_last_digit: false, show_last_digit: false,
textbox: TextBox::empty(), textbox: TextBox::empty(MAX_PASSPHRASE_LENGTH),
current_category: ChoiceCategory::Menu, current_category: ChoiceCategory::Menu,
} }
} }
fn update_passphrase_dots(&mut self, ctx: &mut EventCtx) { fn update_passphrase_dots(&mut self, ctx: &mut EventCtx) {
debug_assert!({
let s = ShortString::new();
s.capacity() >= MAX_PASSPHRASE_LENGTH
});
let text_to_show = if self.show_plain_passphrase { let text_to_show = if self.show_plain_passphrase {
unwrap!(String::try_from(self.passphrase())) unwrap!(ShortString::try_from(self.passphrase()))
} else if self.is_empty() { } else if self.is_empty() {
unwrap!(String::try_from("")) unwrap!(ShortString::try_from(""))
} else { } else {
// Showing asterisks and possibly the last digit. // Showing asterisks and possibly the last digit.
let mut dots: ShortString = String::new(); let mut dots = ShortString::new();
for _ in 0..self.textbox.len() - 1 { for _ in 0..self.textbox.len() - 1 {
unwrap!(dots.push('*')); unwrap!(dots.push('*'));
} }

View File

@ -14,7 +14,6 @@ use super::super::{
theme, ButtonDetails, ButtonLayout, CancelConfirmMsg, ChangingTextLine, ChoiceFactory, theme, ButtonDetails, ButtonLayout, CancelConfirmMsg, ChangingTextLine, ChoiceFactory,
ChoiceItem, ChoicePage, ChoiceItem, ChoicePage,
}; };
use heapless::String;
#[derive(Clone, Copy)] #[derive(Clone, Copy)]
enum PinAction { enum PinAction {
@ -179,7 +178,7 @@ impl<'a> PinEntry<'a> {
showing_real_prompt, showing_real_prompt,
show_real_pin: false, show_real_pin: false,
show_last_digit: false, show_last_digit: false,
textbox: TextBox::empty(), textbox: TextBox::empty(MAX_PIN_LENGTH),
} }
} }
@ -192,15 +191,19 @@ impl<'a> PinEntry<'a> {
/// Show updated content in the changing line. /// Show updated content in the changing line.
/// Many possibilities, according to the PIN state. /// Many possibilities, according to the PIN state.
fn update_pin_line(&mut self, ctx: &mut EventCtx) { fn update_pin_line(&mut self, ctx: &mut EventCtx) {
debug_assert!({
let s = ShortString::new();
s.capacity() >= MAX_PIN_LENGTH
});
let mut used_font = Font::BOLD; let mut used_font = Font::BOLD;
let pin_line_text = if self.is_empty() && !self.subprompt.is_empty() { let pin_line_text = if self.is_empty() && !self.subprompt.is_empty() {
// Showing the subprompt in NORMAL font // Showing the subprompt in NORMAL font
used_font = Font::NORMAL; used_font = Font::NORMAL;
self.subprompt.map(|s| unwrap!(String::try_from(s))) self.subprompt.map(|s| unwrap!(ShortString::try_from(s)))
} else if self.is_empty() { } else if self.is_empty() {
unwrap!(String::try_from(EMPTY_PIN_STR)) unwrap!(ShortString::try_from(EMPTY_PIN_STR))
} else if self.show_real_pin { } else if self.show_real_pin {
unwrap!(String::try_from(self.pin())) unwrap!(ShortString::try_from(self.pin()))
} else { } else {
// Showing asterisks and possibly the last digit. // Showing asterisks and possibly the last digit.
let mut dots = ShortString::new(); let mut dots = ShortString::new();

View File

@ -10,7 +10,7 @@ use crate::{
}; };
use super::super::{theme, ButtonLayout, ChangingTextLine, ChoiceFactory, ChoiceItem, ChoicePage}; use super::super::{theme, ButtonLayout, ChangingTextLine, ChoiceFactory, ChoiceItem, ChoicePage};
use heapless::{String, Vec}; use heapless::Vec;
enum WordlistAction { enum WordlistAction {
Letter(char), Letter(char),
@ -176,7 +176,7 @@ impl WordlistEntry {
.with_carousel(true) .with_carousel(true)
.with_initial_page_counter(get_random_position(choices_count)), .with_initial_page_counter(get_random_position(choices_count)),
chosen_letters: Child::new(ChangingTextLine::center_mono(PROMPT, LINE_CAPACITY)), chosen_letters: Child::new(ChangingTextLine::center_mono(PROMPT, LINE_CAPACITY)),
textbox: TextBox::empty(), textbox: TextBox::empty(MAX_WORD_LENGTH),
offer_words: false, offer_words: false,
wordlist_type, wordlist_type,
can_go_back, can_go_back,
@ -196,7 +196,7 @@ impl WordlistEntry {
.with_incomplete(true) .with_incomplete(true)
.with_initial_page_counter(1), .with_initial_page_counter(1),
chosen_letters: Child::new(ChangingTextLine::center_mono(word, LINE_CAPACITY)), chosen_letters: Child::new(ChangingTextLine::center_mono(word, LINE_CAPACITY)),
textbox: TextBox::new(word), textbox: TextBox::new(word, MAX_WORD_LENGTH),
offer_words: false, offer_words: false,
wordlist_type, wordlist_type,
can_go_back, can_go_back,

View File

@ -210,7 +210,7 @@ impl Bip39Input {
pub fn new() -> Self { pub fn new() -> Self {
Self { Self {
button: Button::empty(), button: Button::empty(),
textbox: TextBox::empty(), textbox: TextBox::empty(MAX_LENGTH),
multi_tap: MultiTapKeyboard::new(), multi_tap: MultiTapKeyboard::new(),
options_num: None, options_num: None,
suggested_word: None, suggested_word: None,
@ -227,7 +227,7 @@ impl Bip39Input {
// Styling the input to reflect already filled word // Styling the input to reflect already filled word
Self { Self {
button: Button::with_icon(theme::ICON_LIST_CHECK).styled(theme::button_pin_confirm()), button: Button::with_icon(theme::ICON_LIST_CHECK).styled(theme::button_pin_confirm()),
textbox: TextBox::new(word), textbox: TextBox::new(word, MAX_LENGTH),
multi_tap: MultiTapKeyboard::new(), multi_tap: MultiTapKeyboard::new(),
options_num: bip39::options_num(word), options_num: bip39::options_num(word),
suggested_word: bip39::complete_word(word), suggested_word: bip39::complete_word(word),

View File

@ -337,7 +337,7 @@ impl Input {
fn new() -> Self { fn new() -> Self {
Self { Self {
area: Rect::zero(), area: Rect::zero(),
textbox: TextBox::empty(), textbox: TextBox::empty(MAX_LENGTH),
multi_tap: MultiTapKeyboard::new(), multi_tap: MultiTapKeyboard::new(),
} }
} }

View File

@ -1,5 +1,4 @@
use core::{char::MAX, mem}; use core::mem;
use heapless::String;
use crate::{ use crate::{
strutil::{ShortString, TString}, strutil::{ShortString, TString},
@ -316,11 +315,13 @@ impl PinDots {
const TWITCH: i16 = 4; const TWITCH: i16 = 4;
fn new(style: TextStyle) -> Self { fn new(style: TextStyle) -> Self {
let digits = ShortString::new();
debug_assert!(digits.capacity() >= MAX_LENGTH);
Self { Self {
area: Rect::zero(), area: Rect::zero(),
pad: Pad::with_background(style.background_color), pad: Pad::with_background(style.background_color),
style, style,
digits: String::new(), digits,
display_digits: false, display_digits: false,
} }
} }

View File

@ -1,7 +1,5 @@
use core::iter; use core::iter;
use heapless::String;
use crate::{ use crate::{
strutil::ShortString, strutil::ShortString,
trezorhal::slip39, trezorhal::slip39,
@ -263,7 +261,7 @@ impl Slip39Input {
Self { Self {
// Button has the same style the whole time // Button has the same style the whole time
button: Button::empty().styled(theme::button_pin_confirm()), button: Button::empty().styled(theme::button_pin_confirm()),
textbox: TextBox::empty(), textbox: TextBox::empty(MAX_LENGTH),
multi_tap: MultiTapKeyboard::new(), multi_tap: MultiTapKeyboard::new(),
final_word: None, final_word: None,
input_mask: Slip39Mask::full(), input_mask: Slip39Mask::full(),
@ -281,7 +279,7 @@ impl Slip39Input {
Self { Self {
// Button has the same style the whole time // Button has the same style the whole time
button: Button::empty().styled(theme::button_pin_confirm()), button: Button::empty().styled(theme::button_pin_confirm()),
textbox: TextBox::new(&buff), textbox: TextBox::new(&buff, MAX_LENGTH),
multi_tap: MultiTapKeyboard::new(), multi_tap: MultiTapKeyboard::new(),
final_word, final_word,
input_mask, input_mask,
@ -290,6 +288,7 @@ impl Slip39Input {
fn setup_from_prefilled_word(word: &str) -> (ShortString, Slip39Mask, Option<&'static str>) { fn setup_from_prefilled_word(word: &str) -> (ShortString, Slip39Mask, Option<&'static str>) {
let mut buff = ShortString::new(); let mut buff = ShortString::new();
debug_assert!(buff.capacity() >= MAX_LENGTH);
// Gradually appending encoded key digits to the buffer and checking if // Gradually appending encoded key digits to the buffer and checking if
// have not already formed a final word. // have not already formed a final word.

View File

@ -9,8 +9,6 @@ use crate::{
}, },
}; };
use heapless::String;
use super::display::Font; use super::display::Font;
pub trait ResultExt { pub trait ResultExt {
@ -129,7 +127,7 @@ pub fn icon_text_center(
/// Convert char to a ShortString. /// Convert char to a ShortString.
pub fn char_to_string(ch: char) -> ShortString { pub fn char_to_string(ch: char) -> ShortString {
let mut s = String::new(); let mut s = ShortString::new();
unwrap!(s.push(ch)); unwrap!(s.push(ch));
s s
} }
@ -137,8 +135,7 @@ pub fn char_to_string(ch: char) -> ShortString {
/// Returns text to be fit on one line of a given length. /// Returns text to be fit on one line of a given length.
/// When the text is too long to fit, it is truncated with ellipsis /// When the text is too long to fit, it is truncated with ellipsis
/// on the left side. /// on the left side.
/// Hardcoding 50 (via ShortString) as the length of the returned String - /// This assumes no lines are longer than 50 chars (ShortString limit)
/// there should not be any lines as long as this.
pub fn long_line_content_with_ellipsis( pub fn long_line_content_with_ellipsis(
text: &str, text: &str,
ellipsis: &str, ellipsis: &str,
@ -146,7 +143,7 @@ pub fn long_line_content_with_ellipsis(
available_width: i16, available_width: i16,
) -> ShortString { ) -> ShortString {
if text_font.text_width(text) <= available_width { if text_font.text_width(text) <= available_width {
unwrap!(String::try_from(text)) // whole text can fit unwrap!(ShortString::try_from(text)) // whole text can fit
} else { } else {
// Text is longer, showing its right end with ellipsis at the beginning. // Text is longer, showing its right end with ellipsis at the beginning.
// Finding out how many additional text characters will fit in, // Finding out how many additional text characters will fit in,