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:
parent
eacc1a3826
commit
100e36ac20
@ -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();
|
||||||
}
|
}
|
||||||
_ => {}
|
_ => {}
|
||||||
|
Loading…
Reference in New Issue
Block a user