1
0
mirror of https://github.com/trezor/trezor-firmware.git synced 2025-03-03 08:46:05 +00:00

feat(core/mercury): impl flow_request_passphrase

This commit replaces request_passphrase with flow_request_passphrase.
The added benefit is that the user is prompted for confirmation if they
want to proceed with an empty passphrase.
This commit is contained in:
obrusvit 2024-08-02 11:52:45 +02:00 committed by Vít Obrusník
parent 60ad7219fe
commit 50dc265162
14 changed files with 55 additions and 48 deletions

View File

@ -0,0 +1 @@
[T3T1] Added reassuring screen when entering empty passphrase

View File

@ -248,6 +248,7 @@ static void _librust_qstrs(void) {
MP_QSTR_flow_get_address;
MP_QSTR_flow_prompt_backup;
MP_QSTR_flow_request_number;
MP_QSTR_flow_request_passphrase;
MP_QSTR_flow_show_share_words;
MP_QSTR_flow_warning_hi_prio;
MP_QSTR_get_language;
@ -346,6 +347,7 @@ static void _librust_qstrs(void) {
MP_QSTR_paint;
MP_QSTR_passphrase__access_wallet;
MP_QSTR_passphrase__always_on_device;
MP_QSTR_passphrase__continue_with_empty_passphrase;
MP_QSTR_passphrase__from_host_not_shown;
MP_QSTR_passphrase__hide;
MP_QSTR_passphrase__next_screen_will_show_passphrase;

View File

@ -1357,6 +1357,7 @@ pub enum TranslatedString {
words__title_done = 956, // "Done"
reset__slip39_checklist_more_info_threshold = 957, // "The threshold sets the minumum number of shares needed to recover your wallet."
reset__slip39_checklist_more_info_threshold_example_template = 958, // "If you set {0} out of {1} shares, you'll need {2} backup shares to recover your wallet."
passphrase__continue_with_empty_passphrase = 959, // "Continue with empty passphrase?"
}
impl TranslatedString {
@ -2708,6 +2709,7 @@ impl TranslatedString {
Self::words__title_done => "Done",
Self::reset__slip39_checklist_more_info_threshold => "The threshold sets the minumum number of shares needed to recover your wallet.",
Self::reset__slip39_checklist_more_info_threshold_example_template => "If you set {0} out of {1} shares, you'll need {2} backup shares to recover your wallet.",
Self::passphrase__continue_with_empty_passphrase => "Continue with empty passphrase?",
}
}
@ -4060,6 +4062,7 @@ impl TranslatedString {
Qstr::MP_QSTR_words__title_done => Some(Self::words__title_done),
Qstr::MP_QSTR_reset__slip39_checklist_more_info_threshold => Some(Self::reset__slip39_checklist_more_info_threshold),
Qstr::MP_QSTR_reset__slip39_checklist_more_info_threshold_example_template => Some(Self::reset__slip39_checklist_more_info_threshold_example_template),
Qstr::MP_QSTR_passphrase__continue_with_empty_passphrase => Some(Self::passphrase__continue_with_empty_passphrase),
_ => None,
}
}

View File

@ -1,5 +1,5 @@
use crate::{
strutil::TString,
strutil::{ShortString, TString},
translations::TR,
ui::{
component::{
@ -26,7 +26,7 @@ use core::cell::Cell;
use num_traits::ToPrimitive;
pub enum PassphraseKeyboardMsg {
Confirmed,
Confirmed(ShortString),
Cancelled,
}

View File

@ -8,6 +8,7 @@ pub mod continue_recovery;
pub mod get_address;
pub mod prompt_backup;
pub mod request_number;
pub mod request_passphrase;
pub mod set_brightness;
pub mod show_share_words;
pub mod show_tutorial;
@ -25,6 +26,7 @@ pub use continue_recovery::new_continue_recovery;
pub use get_address::GetAddress;
pub use prompt_backup::PromptBackup;
pub use request_number::RequestNumber;
pub use request_passphrase::RequestPassphrase;
pub use set_brightness::SetBrightness;
pub use show_share_words::ShowShareWords;
pub use show_tutorial::ShowTutorial;

View File

@ -4,10 +4,9 @@ use super::{
component::{
AddressDetails, Bip39Input, Button, CancelConfirmMsg, CancelInfoConfirmMsg,
CoinJoinProgress, FidoConfirm, FidoMsg, Frame, FrameMsg, Homescreen, HomescreenMsg,
Lockscreen, MnemonicInput, MnemonicKeyboard, MnemonicKeyboardMsg, PassphraseKeyboard,
PassphraseKeyboardMsg, PinKeyboard, PinKeyboardMsg, Progress, PromptScreen,
SelectWordCount, SelectWordCountMsg, Slip39Input, StatusScreen, SwipeUpScreen,
SwipeUpScreenMsg, VerticalMenu, VerticalMenuChoiceMsg,
Lockscreen, MnemonicInput, MnemonicKeyboard, MnemonicKeyboardMsg, PinKeyboard,
PinKeyboardMsg, Progress, PromptScreen, SelectWordCount, SelectWordCountMsg, Slip39Input,
StatusScreen, SwipeUpScreen, SwipeUpScreenMsg, VerticalMenu, VerticalMenuChoiceMsg,
},
flow, theme,
};
@ -124,15 +123,6 @@ impl ComponentMsgObj for PinKeyboard<'_> {
}
}
impl ComponentMsgObj for PassphraseKeyboard {
fn msg_try_into_obj(&self, msg: Self::Msg) -> Result<Obj, Error> {
match msg {
PassphraseKeyboardMsg::Confirmed => self.passphrase().try_into(),
PassphraseKeyboardMsg::Cancelled => Ok(CANCELLED.as_obj()),
}
}
}
impl<T> ComponentMsgObj for MnemonicKeyboard<T>
where
T: MnemonicInput,
@ -954,16 +944,6 @@ extern "C" fn new_request_pin(n_args: usize, args: *const Obj, kwargs: *mut Map)
unsafe { util::try_with_args_and_kwargs(n_args, args, kwargs, block) }
}
extern "C" fn new_request_passphrase(n_args: usize, args: *const Obj, kwargs: *mut Map) -> Obj {
let block = move |_args: &[Obj], kwargs: &Map| {
let _prompt: TString = kwargs.get(Qstr::MP_QSTR_prompt)?.try_into()?;
let _max_len: u32 = kwargs.get(Qstr::MP_QSTR_max_len)?.try_into()?;
let obj = LayoutObj::new(PassphraseKeyboard::new())?;
Ok(obj.into())
};
unsafe { util::try_with_args_and_kwargs(n_args, args, kwargs, block) }
}
extern "C" fn new_request_bip39(n_args: usize, args: *const Obj, kwargs: *mut Map) -> Obj {
let block = move |_args: &[Obj], kwargs: &Map| {
let prompt: TString = kwargs.get(Qstr::MP_QSTR_prompt)?.try_into()?;
@ -1570,13 +1550,13 @@ pub static mp_module_trezorui2: Module = obj_module! {
/// """Request pin on device."""
Qstr::MP_QSTR_request_pin => obj_fn_kw!(0, new_request_pin).as_obj(),
/// def request_passphrase(
/// def flow_request_passphrase(
/// *,
/// prompt: str,
/// max_len: int,
/// ) -> LayoutObj[str | UiResult]:
/// """Passphrase input keyboard."""
Qstr::MP_QSTR_request_passphrase => obj_fn_kw!(0, new_request_passphrase).as_obj(),
Qstr::MP_QSTR_flow_request_passphrase => obj_fn_kw!(0, flow::request_passphrase::new_request_passphrase).as_obj(),
/// def request_bip39(
/// *,

View File

@ -349,7 +349,7 @@ def request_pin(
# rust/src/ui/model_mercury/layout.rs
def request_passphrase(
def flow_request_passphrase(
*,
prompt: str,
max_len: int,

View File

@ -487,6 +487,7 @@ class TR:
nem__unknown_mosaic: str = "Unknown mosaic!"
passphrase__access_wallet: str = "Access passphrase wallet?"
passphrase__always_on_device: str = "Always enter your passphrase on Trezor?"
passphrase__continue_with_empty_passphrase: str = "Continue with empty passphrase?"
passphrase__from_host_not_shown: str = "Passphrase provided by host will be used but will not be displayed due to the device settings."
passphrase__hide: str = "Hide passphrase coming from host?"
passphrase__next_screen_will_show_passphrase: str = "The next screen shows your passphrase."

View File

@ -1374,7 +1374,7 @@ def show_wait_text(message: str) -> None:
async def request_passphrase_on_device(max_len: int) -> str:
result = await interact(
RustLayout(
trezorui2.request_passphrase(
trezorui2.flow_request_passphrase(
prompt=TR.passphrase__title_enter, max_len=max_len
)
),
@ -1384,8 +1384,18 @@ async def request_passphrase_on_device(max_len: int) -> str:
if result is CANCELLED:
raise ActionCancelled("Passphrase entry cancelled")
assert isinstance(result, str)
return result
if __debug__:
if not isinstance(result, tuple):
# TODO: DebugLink problem, better comment or solution?
result = (CONFIRMED, str(result))
status, value = result
if status == CONFIRMED:
assert isinstance(value, str)
return value
else:
# flow_request_pin returns either CANCELLED or (CONFIRMED, str) so this branch shouldn't be taken
raise ActionCancelled("Passphrase entry cancelled")
async def request_pin_on_device(

View File

@ -489,6 +489,7 @@
"nem__unknown_mosaic": "Unknown mosaic!",
"passphrase__access_wallet": "Access passphrase wallet?",
"passphrase__always_on_device": "Always enter your passphrase on Trezor?",
"passphrase__continue_with_empty_passphrase": "Continue with empty passphrase?",
"passphrase__from_host_not_shown": "Passphrase provided by host will be used but will not be displayed due to the device settings.",
"passphrase__wallet": "Passphrase wallet",
"passphrase__hide": "Hide passphrase coming from host?",

View File

@ -957,5 +957,6 @@
"955": "brightness__change_title",
"956": "words__title_done",
"957": "reset__slip39_checklist_more_info_threshold",
"958": "reset__slip39_checklist_more_info_threshold_example_template"
"958": "reset__slip39_checklist_more_info_threshold_example_template",
"959": "passphrase__continue_with_empty_passphrase"
}

View File

@ -13,6 +13,20 @@ def grid(dim: int, grid_cells: int, cell: int) -> int:
return cell * step + ofs
def grid35(x: int, y: int) -> Coords:
return grid(DISPLAY_WIDTH, 3, x), grid(DISPLAY_HEIGHT, 5, y)
def grid34(x: int, y: int) -> Coords:
return grid(DISPLAY_WIDTH, 3, x), grid(DISPLAY_HEIGHT, 4, y)
def _grid34_from_index(idx: int) -> Coords:
grid_x = idx % 3
grid_y = idx // 3 + 1 # first line is empty
return grid34(grid_x, grid_y)
LEFT = grid(DISPLAY_WIDTH, 3, 0)
MID = grid(DISPLAY_WIDTH, 3, 1)
RIGHT = grid(DISPLAY_WIDTH, 3, 2)
@ -31,6 +45,9 @@ CORNER_BUTTON = (215, 25)
CONFIRM_WORD = (MID, TOP)
TOP_ROW = (MID, TOP)
MERCURY_YES = grid34(2, 2)
MERCURY_NO = grid34(0, 2)
def reset_minus(model_internal_name: str) -> Coords:
RESET_MINUS_T3T1 = (LEFT, grid(DISPLAY_HEIGHT, 5, 3))
@ -109,20 +126,6 @@ def pin_passphrase_grid(idx: int) -> Coords:
return grid35(grid_x, grid_y)
def grid35(x: int, y: int) -> Coords:
return grid(DISPLAY_WIDTH, 3, x), grid(DISPLAY_HEIGHT, 5, y)
def grid34(x: int, y: int) -> Coords:
return grid(DISPLAY_WIDTH, 3, x), grid(DISPLAY_HEIGHT, 4, y)
def _grid34_from_index(idx: int) -> Coords:
grid_x = idx % 3
grid_y = idx // 3 + 1 # first line is empty
return grid34(grid_x, grid_y)
def type_word(word: str, is_slip39: bool = False) -> Iterator[Coords]:
if is_slip39:
yield from _type_word_slip39(word)

View File

@ -168,8 +168,11 @@ def input_passphrase(debug: "DebugLink", passphrase: str, check: bool = True) ->
def enter_passphrase(debug: "DebugLink") -> None:
"""Enter a passphrase"""
coords = buttons.grid35(2, 0) # top-right corner
is_empty: bool = len(debug.read_layout().passphrase()) == 0
coords = buttons.CORNER_BUTTON # top-right corner
debug.click(coords, wait=True)
if is_empty:
debug.click(buttons.MERCURY_YES)
def delete_char(debug: "DebugLink") -> None:

View File

@ -1597,7 +1597,7 @@ class InputFlowSlip39BasicResetRecovery(InputFlowBase):
# Mnemonic phrases
self.mnemonics = yield from load_N_shares(self.debug, 5)
br = yield # safety warning
br = yield # success screen
assert br.code == B.Success
self.debug.press_yes()