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:
parent
8cf039740f
commit
4e788aa2f5
@ -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 {
|
||||||
|
@ -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),
|
||||||
|
@ -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(),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -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,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -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,
|
||||||
|
@ -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('*'));
|
||||||
}
|
}
|
||||||
|
@ -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();
|
||||||
|
@ -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,
|
||||||
|
@ -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),
|
||||||
|
@ -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(),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -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,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -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.
|
||||||
|
@ -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,
|
||||||
|
Loading…
Reference in New Issue
Block a user