1
0
mirror of https://github.com/trezor/trezor-firmware.git synced 2024-11-15 20:19:23 +00:00

feat(core/rust): randomize positions in passphrase input

[no changelog]
This commit is contained in:
grdddj 2023-06-13 11:48:35 +02:00 committed by Jiří Musil
parent eacc1a3826
commit 100e36ac20

View File

@ -1,5 +1,6 @@
use crate::{ use crate::{
strutil::StringType, strutil::StringType,
trezorhal::random,
ui::{ ui::{
component::{text::common::TextBox, Child, Component, ComponentExt, Event, EventCtx}, component::{text::common::TextBox, Child, Component, ComponentExt, Event, EventCtx},
display::Icon, display::Icon,
@ -111,17 +112,6 @@ fn get_char(current_category: &ChoiceCategory, index: usize) -> char {
unwrap!(group.chars().nth(index)) unwrap!(group.chars().nth(index))
} }
/// Return category from menu based on page index.
fn get_category_from_menu(page_index: usize) -> ChoiceCategory {
match page_index {
LOWERCASE_INDEX => ChoiceCategory::LowercaseLetter,
UPPERCASE_INDEX => ChoiceCategory::UppercaseLetter,
DIGITS_INDEX => ChoiceCategory::Digit,
SPECIAL_INDEX => ChoiceCategory::SpecialSymbol,
_ => unreachable!(),
}
}
/// How many choices are available for a specified category. /// How many choices are available for a specified category.
/// (does not count the extra MENU choice for characters) /// (does not count the extra MENU choice for characters)
fn get_category_length(current_category: &ChoiceCategory) -> usize { fn get_category_length(current_category: &ChoiceCategory) -> usize {
@ -134,6 +124,12 @@ fn get_category_length(current_category: &ChoiceCategory) -> usize {
} }
} }
/// Random position/index in the given category
fn random_category_position(category: &ChoiceCategory) -> usize {
let category_length = get_category_length(category) as u32;
random::uniform_between(0, category_length - 1) as usize
}
/// Whether this index is the MENU index - the last one in the list. /// Whether this index is the MENU index - the last one in the list.
fn is_menu_choice(current_category: &ChoiceCategory, page_index: usize) -> bool { fn is_menu_choice(current_category: &ChoiceCategory, page_index: usize) -> bool {
if let ChoiceCategory::Menu = current_category { if let ChoiceCategory::Menu = current_category {
@ -143,6 +139,11 @@ fn is_menu_choice(current_category: &ChoiceCategory, page_index: usize) -> bool
page_index == category_length page_index == category_length
} }
/// Choose random character category to be pre-selected
fn random_menu_position() -> usize {
random::uniform_between(LOWERCASE_INDEX as u32, SPECIAL_INDEX as u32) as usize
}
struct ChoiceFactoryPassphrase { struct ChoiceFactoryPassphrase {
current_category: ChoiceCategory, current_category: ChoiceCategory,
/// Used to either show DELETE or CANCEL /// Used to either show DELETE or CANCEL
@ -237,7 +238,6 @@ pub struct PassphraseEntry<T: StringType + Clone> {
show_plain_passphrase: bool, show_plain_passphrase: bool,
textbox: TextBox<MAX_PASSPHRASE_LENGTH>, textbox: TextBox<MAX_PASSPHRASE_LENGTH>,
current_category: ChoiceCategory, current_category: ChoiceCategory,
menu_position: usize, // position in the menu so we can return back
} }
impl<T> PassphraseEntry<T> impl<T> PassphraseEntry<T>
@ -248,12 +248,11 @@ where
Self { Self {
choice_page: ChoicePage::new(ChoiceFactoryPassphrase::new(ChoiceCategory::Menu, true)) choice_page: ChoicePage::new(ChoiceFactoryPassphrase::new(ChoiceCategory::Menu, true))
.with_carousel(true) .with_carousel(true)
.with_initial_page_counter(LOWERCASE_INDEX), .with_initial_page_counter(random_menu_position()),
passphrase_dots: Child::new(ChangingTextLine::center_mono(String::new())), passphrase_dots: Child::new(ChangingTextLine::center_mono(String::new())),
show_plain_passphrase: false, show_plain_passphrase: false,
textbox: TextBox::empty(), textbox: TextBox::empty(),
current_category: ChoiceCategory::Menu, current_category: ChoiceCategory::Menu,
menu_position: 0,
} }
} }
@ -284,15 +283,19 @@ where
/// Displaying the MENU /// Displaying the MENU
fn show_menu_page(&mut self, ctx: &mut EventCtx) { fn show_menu_page(&mut self, ctx: &mut EventCtx) {
let menu_choices = ChoiceFactoryPassphrase::new(ChoiceCategory::Menu, self.is_empty()); let menu_choices = ChoiceFactoryPassphrase::new(ChoiceCategory::Menu, self.is_empty());
// Going back to the last MENU position before showing the MENU
self.choice_page self.choice_page
.reset(ctx, menu_choices, Some(self.menu_position), true); .reset(ctx, menu_choices, Some(random_menu_position()), true);
} }
/// Displaying the character category /// Displaying the character category
fn show_category_page(&mut self, ctx: &mut EventCtx) { fn show_category_page(&mut self, ctx: &mut EventCtx) {
let category_choices = ChoiceFactoryPassphrase::new(self.current_category, self.is_empty()); let category_choices = ChoiceFactoryPassphrase::new(self.current_category, self.is_empty());
self.choice_page.reset(ctx, category_choices, Some(0), true); self.choice_page.reset(
ctx,
category_choices,
Some(random_category_position(&self.current_category)),
true,
);
} }
pub fn passphrase(&self) -> &str { pub fn passphrase(&self) -> &str {
@ -306,6 +309,12 @@ where
fn is_full(&self) -> bool { fn is_full(&self) -> bool {
self.textbox.is_full() self.textbox.is_full()
} }
/// Randomly choose an index in the current category
fn randomize_category_position(&mut self, ctx: &mut EventCtx) {
self.choice_page
.set_page_counter(ctx, random_category_position(&self.current_category));
}
} }
impl<T> Component for PassphraseEntry<T> impl<T> Component for PassphraseEntry<T>
@ -339,7 +348,6 @@ where
self.update_passphrase_dots(ctx); self.update_passphrase_dots(ctx);
if self.is_empty() { if self.is_empty() {
// Allowing for DELETE/CANCEL change // Allowing for DELETE/CANCEL change
self.menu_position = CANCEL_DELETE_INDEX;
self.show_menu_page(ctx); self.show_menu_page(ctx);
} }
ctx.request_paint(); ctx.request_paint();
@ -354,7 +362,6 @@ where
ctx.request_paint(); ctx.request_paint();
} }
PassphraseAction::Category(category) => { PassphraseAction::Category(category) => {
self.menu_position = self.choice_page.page_index();
self.current_category = category; self.current_category = category;
self.show_category_page(ctx); self.show_category_page(ctx);
ctx.request_paint(); ctx.request_paint();
@ -367,6 +374,7 @@ where
PassphraseAction::Character(ch) if !self.is_full() => { PassphraseAction::Character(ch) if !self.is_full() => {
self.append_char(ctx, ch); self.append_char(ctx, ch);
self.update_passphrase_dots(ctx); self.update_passphrase_dots(ctx);
self.randomize_category_position(ctx);
ctx.request_paint(); ctx.request_paint();
} }
_ => {} _ => {}