mirror of
https://github.com/trezor/trezor-firmware.git
synced 2025-03-03 16:56:07 +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:
parent
60ad7219fe
commit
50dc265162
1
core/.changelog.d/4054.added
Normal file
1
core/.changelog.d/4054.added
Normal file
@ -0,0 +1 @@
|
|||||||
|
[T3T1] Added reassuring screen when entering empty passphrase
|
@ -248,6 +248,7 @@ static void _librust_qstrs(void) {
|
|||||||
MP_QSTR_flow_get_address;
|
MP_QSTR_flow_get_address;
|
||||||
MP_QSTR_flow_prompt_backup;
|
MP_QSTR_flow_prompt_backup;
|
||||||
MP_QSTR_flow_request_number;
|
MP_QSTR_flow_request_number;
|
||||||
|
MP_QSTR_flow_request_passphrase;
|
||||||
MP_QSTR_flow_show_share_words;
|
MP_QSTR_flow_show_share_words;
|
||||||
MP_QSTR_flow_warning_hi_prio;
|
MP_QSTR_flow_warning_hi_prio;
|
||||||
MP_QSTR_get_language;
|
MP_QSTR_get_language;
|
||||||
@ -346,6 +347,7 @@ static void _librust_qstrs(void) {
|
|||||||
MP_QSTR_paint;
|
MP_QSTR_paint;
|
||||||
MP_QSTR_passphrase__access_wallet;
|
MP_QSTR_passphrase__access_wallet;
|
||||||
MP_QSTR_passphrase__always_on_device;
|
MP_QSTR_passphrase__always_on_device;
|
||||||
|
MP_QSTR_passphrase__continue_with_empty_passphrase;
|
||||||
MP_QSTR_passphrase__from_host_not_shown;
|
MP_QSTR_passphrase__from_host_not_shown;
|
||||||
MP_QSTR_passphrase__hide;
|
MP_QSTR_passphrase__hide;
|
||||||
MP_QSTR_passphrase__next_screen_will_show_passphrase;
|
MP_QSTR_passphrase__next_screen_will_show_passphrase;
|
||||||
|
@ -1357,6 +1357,7 @@ pub enum TranslatedString {
|
|||||||
words__title_done = 956, // "Done"
|
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 = 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."
|
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 {
|
impl TranslatedString {
|
||||||
@ -2708,6 +2709,7 @@ impl TranslatedString {
|
|||||||
Self::words__title_done => "Done",
|
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 => "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::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_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 => 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_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,
|
_ => None,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
use crate::{
|
use crate::{
|
||||||
strutil::TString,
|
strutil::{ShortString, TString},
|
||||||
translations::TR,
|
translations::TR,
|
||||||
ui::{
|
ui::{
|
||||||
component::{
|
component::{
|
||||||
@ -26,7 +26,7 @@ use core::cell::Cell;
|
|||||||
use num_traits::ToPrimitive;
|
use num_traits::ToPrimitive;
|
||||||
|
|
||||||
pub enum PassphraseKeyboardMsg {
|
pub enum PassphraseKeyboardMsg {
|
||||||
Confirmed,
|
Confirmed(ShortString),
|
||||||
Cancelled,
|
Cancelled,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -8,6 +8,7 @@ pub mod continue_recovery;
|
|||||||
pub mod get_address;
|
pub mod get_address;
|
||||||
pub mod prompt_backup;
|
pub mod prompt_backup;
|
||||||
pub mod request_number;
|
pub mod request_number;
|
||||||
|
pub mod request_passphrase;
|
||||||
pub mod set_brightness;
|
pub mod set_brightness;
|
||||||
pub mod show_share_words;
|
pub mod show_share_words;
|
||||||
pub mod show_tutorial;
|
pub mod show_tutorial;
|
||||||
@ -25,6 +26,7 @@ pub use continue_recovery::new_continue_recovery;
|
|||||||
pub use get_address::GetAddress;
|
pub use get_address::GetAddress;
|
||||||
pub use prompt_backup::PromptBackup;
|
pub use prompt_backup::PromptBackup;
|
||||||
pub use request_number::RequestNumber;
|
pub use request_number::RequestNumber;
|
||||||
|
pub use request_passphrase::RequestPassphrase;
|
||||||
pub use set_brightness::SetBrightness;
|
pub use set_brightness::SetBrightness;
|
||||||
pub use show_share_words::ShowShareWords;
|
pub use show_share_words::ShowShareWords;
|
||||||
pub use show_tutorial::ShowTutorial;
|
pub use show_tutorial::ShowTutorial;
|
||||||
|
@ -4,10 +4,9 @@ use super::{
|
|||||||
component::{
|
component::{
|
||||||
AddressDetails, Bip39Input, Button, CancelConfirmMsg, CancelInfoConfirmMsg,
|
AddressDetails, Bip39Input, Button, CancelConfirmMsg, CancelInfoConfirmMsg,
|
||||||
CoinJoinProgress, FidoConfirm, FidoMsg, Frame, FrameMsg, Homescreen, HomescreenMsg,
|
CoinJoinProgress, FidoConfirm, FidoMsg, Frame, FrameMsg, Homescreen, HomescreenMsg,
|
||||||
Lockscreen, MnemonicInput, MnemonicKeyboard, MnemonicKeyboardMsg, PassphraseKeyboard,
|
Lockscreen, MnemonicInput, MnemonicKeyboard, MnemonicKeyboardMsg, PinKeyboard,
|
||||||
PassphraseKeyboardMsg, PinKeyboard, PinKeyboardMsg, Progress, PromptScreen,
|
PinKeyboardMsg, Progress, PromptScreen, SelectWordCount, SelectWordCountMsg, Slip39Input,
|
||||||
SelectWordCount, SelectWordCountMsg, Slip39Input, StatusScreen, SwipeUpScreen,
|
StatusScreen, SwipeUpScreen, SwipeUpScreenMsg, VerticalMenu, VerticalMenuChoiceMsg,
|
||||||
SwipeUpScreenMsg, VerticalMenu, VerticalMenuChoiceMsg,
|
|
||||||
},
|
},
|
||||||
flow, theme,
|
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>
|
impl<T> ComponentMsgObj for MnemonicKeyboard<T>
|
||||||
where
|
where
|
||||||
T: MnemonicInput,
|
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) }
|
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 {
|
extern "C" fn new_request_bip39(n_args: usize, args: *const Obj, kwargs: *mut Map) -> Obj {
|
||||||
let block = move |_args: &[Obj], kwargs: &Map| {
|
let block = move |_args: &[Obj], kwargs: &Map| {
|
||||||
let prompt: TString = kwargs.get(Qstr::MP_QSTR_prompt)?.try_into()?;
|
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."""
|
/// """Request pin on device."""
|
||||||
Qstr::MP_QSTR_request_pin => obj_fn_kw!(0, new_request_pin).as_obj(),
|
Qstr::MP_QSTR_request_pin => obj_fn_kw!(0, new_request_pin).as_obj(),
|
||||||
|
|
||||||
/// def request_passphrase(
|
/// def flow_request_passphrase(
|
||||||
/// *,
|
/// *,
|
||||||
/// prompt: str,
|
/// prompt: str,
|
||||||
/// max_len: int,
|
/// max_len: int,
|
||||||
/// ) -> LayoutObj[str | UiResult]:
|
/// ) -> LayoutObj[str | UiResult]:
|
||||||
/// """Passphrase input keyboard."""
|
/// """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(
|
/// def request_bip39(
|
||||||
/// *,
|
/// *,
|
||||||
|
@ -349,7 +349,7 @@ def request_pin(
|
|||||||
|
|
||||||
|
|
||||||
# rust/src/ui/model_mercury/layout.rs
|
# rust/src/ui/model_mercury/layout.rs
|
||||||
def request_passphrase(
|
def flow_request_passphrase(
|
||||||
*,
|
*,
|
||||||
prompt: str,
|
prompt: str,
|
||||||
max_len: int,
|
max_len: int,
|
||||||
|
@ -487,6 +487,7 @@ class TR:
|
|||||||
nem__unknown_mosaic: str = "Unknown mosaic!"
|
nem__unknown_mosaic: str = "Unknown mosaic!"
|
||||||
passphrase__access_wallet: str = "Access passphrase wallet?"
|
passphrase__access_wallet: str = "Access passphrase wallet?"
|
||||||
passphrase__always_on_device: str = "Always enter your passphrase on Trezor?"
|
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__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__hide: str = "Hide passphrase coming from host?"
|
||||||
passphrase__next_screen_will_show_passphrase: str = "The next screen shows your passphrase."
|
passphrase__next_screen_will_show_passphrase: str = "The next screen shows your passphrase."
|
||||||
|
@ -1374,7 +1374,7 @@ def show_wait_text(message: str) -> None:
|
|||||||
async def request_passphrase_on_device(max_len: int) -> str:
|
async def request_passphrase_on_device(max_len: int) -> str:
|
||||||
result = await interact(
|
result = await interact(
|
||||||
RustLayout(
|
RustLayout(
|
||||||
trezorui2.request_passphrase(
|
trezorui2.flow_request_passphrase(
|
||||||
prompt=TR.passphrase__title_enter, max_len=max_len
|
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:
|
if result is CANCELLED:
|
||||||
raise ActionCancelled("Passphrase entry cancelled")
|
raise ActionCancelled("Passphrase entry cancelled")
|
||||||
|
|
||||||
assert isinstance(result, str)
|
if __debug__:
|
||||||
return result
|
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(
|
async def request_pin_on_device(
|
||||||
|
@ -489,6 +489,7 @@
|
|||||||
"nem__unknown_mosaic": "Unknown mosaic!",
|
"nem__unknown_mosaic": "Unknown mosaic!",
|
||||||
"passphrase__access_wallet": "Access passphrase wallet?",
|
"passphrase__access_wallet": "Access passphrase wallet?",
|
||||||
"passphrase__always_on_device": "Always enter your passphrase on Trezor?",
|
"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__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__wallet": "Passphrase wallet",
|
||||||
"passphrase__hide": "Hide passphrase coming from host?",
|
"passphrase__hide": "Hide passphrase coming from host?",
|
||||||
|
@ -957,5 +957,6 @@
|
|||||||
"955": "brightness__change_title",
|
"955": "brightness__change_title",
|
||||||
"956": "words__title_done",
|
"956": "words__title_done",
|
||||||
"957": "reset__slip39_checklist_more_info_threshold",
|
"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"
|
||||||
}
|
}
|
||||||
|
@ -13,6 +13,20 @@ def grid(dim: int, grid_cells: int, cell: int) -> int:
|
|||||||
return cell * step + ofs
|
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)
|
LEFT = grid(DISPLAY_WIDTH, 3, 0)
|
||||||
MID = grid(DISPLAY_WIDTH, 3, 1)
|
MID = grid(DISPLAY_WIDTH, 3, 1)
|
||||||
RIGHT = grid(DISPLAY_WIDTH, 3, 2)
|
RIGHT = grid(DISPLAY_WIDTH, 3, 2)
|
||||||
@ -31,6 +45,9 @@ CORNER_BUTTON = (215, 25)
|
|||||||
CONFIRM_WORD = (MID, TOP)
|
CONFIRM_WORD = (MID, TOP)
|
||||||
TOP_ROW = (MID, TOP)
|
TOP_ROW = (MID, TOP)
|
||||||
|
|
||||||
|
MERCURY_YES = grid34(2, 2)
|
||||||
|
MERCURY_NO = grid34(0, 2)
|
||||||
|
|
||||||
|
|
||||||
def reset_minus(model_internal_name: str) -> Coords:
|
def reset_minus(model_internal_name: str) -> Coords:
|
||||||
RESET_MINUS_T3T1 = (LEFT, grid(DISPLAY_HEIGHT, 5, 3))
|
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)
|
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]:
|
def type_word(word: str, is_slip39: bool = False) -> Iterator[Coords]:
|
||||||
if is_slip39:
|
if is_slip39:
|
||||||
yield from _type_word_slip39(word)
|
yield from _type_word_slip39(word)
|
||||||
|
@ -168,8 +168,11 @@ def input_passphrase(debug: "DebugLink", passphrase: str, check: bool = True) ->
|
|||||||
|
|
||||||
def enter_passphrase(debug: "DebugLink") -> None:
|
def enter_passphrase(debug: "DebugLink") -> None:
|
||||||
"""Enter a passphrase"""
|
"""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)
|
debug.click(coords, wait=True)
|
||||||
|
if is_empty:
|
||||||
|
debug.click(buttons.MERCURY_YES)
|
||||||
|
|
||||||
|
|
||||||
def delete_char(debug: "DebugLink") -> None:
|
def delete_char(debug: "DebugLink") -> None:
|
||||||
|
@ -1597,7 +1597,7 @@ class InputFlowSlip39BasicResetRecovery(InputFlowBase):
|
|||||||
# Mnemonic phrases
|
# Mnemonic phrases
|
||||||
self.mnemonics = yield from load_N_shares(self.debug, 5)
|
self.mnemonics = yield from load_N_shares(self.debug, 5)
|
||||||
|
|
||||||
br = yield # safety warning
|
br = yield # success screen
|
||||||
assert br.code == B.Success
|
assert br.code == B.Success
|
||||||
self.debug.press_yes()
|
self.debug.press_yes()
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user