mirror of
https://github.com/trezor/trezor-firmware.git
synced 2024-12-18 12:28:09 +00:00
feat(core/ui): T3T1 set new PIN flow
[no changelog]
This commit is contained in:
parent
51a78dddee
commit
d8f20616be
@ -214,6 +214,7 @@ static void _librust_qstrs(void) {
|
||||
MP_QSTR_firmware_update__title_fingerprint;
|
||||
MP_QSTR_flow_confirm_reset_create;
|
||||
MP_QSTR_flow_confirm_reset_recover;
|
||||
MP_QSTR_flow_confirm_set_new_pin;
|
||||
MP_QSTR_flow_get_address;
|
||||
MP_QSTR_flow_prompt_backup;
|
||||
MP_QSTR_flow_show_share_words;
|
||||
@ -307,6 +308,9 @@ static void _librust_qstrs(void) {
|
||||
MP_QSTR_passphrase__turn_off;
|
||||
MP_QSTR_passphrase__turn_on;
|
||||
MP_QSTR_path;
|
||||
MP_QSTR_pin__cancel_description;
|
||||
MP_QSTR_pin__cancel_info;
|
||||
MP_QSTR_pin__cancel_setup;
|
||||
MP_QSTR_pin__change;
|
||||
MP_QSTR_pin__changed;
|
||||
MP_QSTR_pin__cursor_will_change;
|
||||
|
@ -1268,6 +1268,10 @@ pub enum TranslatedString {
|
||||
instructions__continue_in_app = 867, // "Continue in the app"
|
||||
words__cancel_and_exit = 868, // "Cancel and exit"
|
||||
address__confirmed = 869, // "Receive address confirmed"
|
||||
reset__title_shamir_backup = 870, // "Multi-share backup"
|
||||
pin__cancel_description = 871, // "Continue without PIN"
|
||||
pin__cancel_info = 872, // "Without a PIN, anyone can access this device."
|
||||
pin__cancel_setup = 873, // "Cancel PIN setup"
|
||||
}
|
||||
|
||||
impl TranslatedString {
|
||||
@ -2531,6 +2535,10 @@ impl TranslatedString {
|
||||
Self::instructions__continue_in_app => "Continue in the app",
|
||||
Self::words__cancel_and_exit => "Cancel and exit",
|
||||
Self::address__confirmed => "Receive address confirmed",
|
||||
Self::reset__title_shamir_backup => "Multi-share backup",
|
||||
Self::pin__cancel_description => "Continue without PIN",
|
||||
Self::pin__cancel_info => "Without a PIN, anyone can access this device.",
|
||||
Self::pin__cancel_setup => "Cancel PIN setup",
|
||||
}
|
||||
}
|
||||
|
||||
@ -3795,6 +3803,10 @@ impl TranslatedString {
|
||||
Qstr::MP_QSTR_instructions__continue_in_app => Some(Self::instructions__continue_in_app),
|
||||
Qstr::MP_QSTR_words__cancel_and_exit => Some(Self::words__cancel_and_exit),
|
||||
Qstr::MP_QSTR_address__confirmed => Some(Self::address__confirmed),
|
||||
Qstr::MP_QSTR_reset__title_shamir_backup => Some(Self::reset__title_shamir_backup),
|
||||
Qstr::MP_QSTR_pin__cancel_description => Some(Self::pin__cancel_description),
|
||||
Qstr::MP_QSTR_pin__cancel_info => Some(Self::pin__cancel_info),
|
||||
Qstr::MP_QSTR_pin__cancel_setup => Some(Self::pin__cancel_setup),
|
||||
_ => None,
|
||||
}
|
||||
}
|
||||
|
@ -32,11 +32,12 @@ const MAX_VISIBLE_DOTS: usize = 18;
|
||||
const MAX_VISIBLE_DIGITS: usize = 18;
|
||||
const DIGIT_COUNT: usize = 10; // 0..10
|
||||
|
||||
const HEADER_PADDING_TOP: i16 = 4;
|
||||
const HEADER_PADDING_SIDE: i16 = 2;
|
||||
const HEADER_PADDING_BOTTOM: i16 = 2;
|
||||
const HEADER_PADDING_BOTTOM: i16 = 4;
|
||||
|
||||
const HEADER_PADDING: Insets = Insets::new(
|
||||
0,
|
||||
HEADER_PADDING_TOP,
|
||||
HEADER_PADDING_SIDE,
|
||||
HEADER_PADDING_BOTTOM,
|
||||
HEADER_PADDING_SIDE,
|
||||
@ -232,23 +233,7 @@ impl Component for PinKeyboard<'_> {
|
||||
}
|
||||
|
||||
fn paint(&mut self) {
|
||||
self.erase_btn.paint();
|
||||
self.textbox_pad.paint();
|
||||
if self.textbox.inner().is_empty() {
|
||||
if let Some(ref mut w) = self.major_warning {
|
||||
w.paint();
|
||||
} else {
|
||||
self.major_prompt.paint();
|
||||
}
|
||||
self.minor_prompt.paint();
|
||||
self.cancel_btn.paint();
|
||||
} else {
|
||||
self.textbox.paint();
|
||||
}
|
||||
self.confirm_btn.paint();
|
||||
for btn in &mut self.digit_btns {
|
||||
btn.paint();
|
||||
}
|
||||
todo!("remove when ui-t3t1 done");
|
||||
}
|
||||
|
||||
fn render<'s>(&'s self, target: &mut impl Renderer<'s>) {
|
||||
|
145
core/embed/rust/src/ui/model_mercury/flow/confirm_set_new_pin.rs
Normal file
145
core/embed/rust/src/ui/model_mercury/flow/confirm_set_new_pin.rs
Normal file
@ -0,0 +1,145 @@
|
||||
use crate::{
|
||||
error,
|
||||
micropython::qstr::Qstr,
|
||||
strutil::TString,
|
||||
translations::TR,
|
||||
ui::{
|
||||
component::{
|
||||
text::paragraphs::{Paragraph, Paragraphs},
|
||||
ComponentExt, SwipeDirection,
|
||||
},
|
||||
flow::{base::Decision, flow_store, FlowMsg, FlowState, FlowStore, SwipeFlow, SwipePage},
|
||||
},
|
||||
};
|
||||
|
||||
use super::super::{
|
||||
component::{
|
||||
CancelInfoConfirmMsg, Frame, FrameMsg, PromptScreen, VerticalMenu, VerticalMenuChoiceMsg,
|
||||
},
|
||||
theme,
|
||||
};
|
||||
|
||||
#[derive(Copy, Clone, PartialEq, Eq, ToPrimitive)]
|
||||
pub enum SetNewPin {
|
||||
Intro,
|
||||
Menu,
|
||||
CancelPinIntro,
|
||||
CancelPinConfirm,
|
||||
}
|
||||
|
||||
impl FlowState for SetNewPin {
|
||||
fn handle_swipe(&self, direction: SwipeDirection) -> Decision<Self> {
|
||||
match (self, direction) {
|
||||
(SetNewPin::Intro, SwipeDirection::Left) => Decision::Goto(SetNewPin::Menu, direction),
|
||||
(SetNewPin::CancelPinIntro, SwipeDirection::Up) => {
|
||||
Decision::Goto(SetNewPin::CancelPinConfirm, direction)
|
||||
}
|
||||
(SetNewPin::CancelPinConfirm, SwipeDirection::Down) => {
|
||||
Decision::Goto(SetNewPin::CancelPinIntro, direction)
|
||||
}
|
||||
(SetNewPin::Intro, SwipeDirection::Up) => Decision::Return(FlowMsg::Confirmed),
|
||||
_ => Decision::Nothing,
|
||||
}
|
||||
}
|
||||
|
||||
fn handle_event(&self, msg: FlowMsg) -> Decision<Self> {
|
||||
match (self, msg) {
|
||||
(SetNewPin::Intro, FlowMsg::Info) => {
|
||||
Decision::Goto(SetNewPin::Menu, SwipeDirection::Left)
|
||||
}
|
||||
(SetNewPin::Menu, FlowMsg::Choice(0)) => {
|
||||
Decision::Goto(SetNewPin::CancelPinIntro, SwipeDirection::Left)
|
||||
}
|
||||
(SetNewPin::Menu, FlowMsg::Cancelled) => {
|
||||
Decision::Goto(SetNewPin::Intro, SwipeDirection::Right)
|
||||
}
|
||||
(SetNewPin::CancelPinIntro, FlowMsg::Cancelled) => {
|
||||
Decision::Goto(SetNewPin::Menu, SwipeDirection::Right)
|
||||
}
|
||||
(SetNewPin::CancelPinConfirm, FlowMsg::Cancelled) => {
|
||||
Decision::Goto(SetNewPin::CancelPinIntro, SwipeDirection::Right)
|
||||
}
|
||||
(SetNewPin::CancelPinConfirm, FlowMsg::Confirmed) => {
|
||||
Decision::Return(FlowMsg::Cancelled)
|
||||
}
|
||||
_ => Decision::Nothing,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
use crate::{
|
||||
micropython::{map::Map, obj::Obj, util},
|
||||
ui::layout::obj::LayoutObj,
|
||||
};
|
||||
|
||||
#[allow(clippy::not_unsafe_ptr_arg_deref)]
|
||||
pub extern "C" fn new_set_new_pin(n_args: usize, args: *const Obj, kwargs: *mut Map) -> Obj {
|
||||
unsafe { util::try_with_args_and_kwargs(n_args, args, kwargs, SetNewPin::new_obj) }
|
||||
}
|
||||
|
||||
impl SetNewPin {
|
||||
fn new_obj(_args: &[Obj], kwargs: &Map) -> Result<Obj, error::Error> {
|
||||
// TODO: supply more arguments for Wipe code setting when figma done
|
||||
let title: TString = kwargs.get(Qstr::MP_QSTR_title)?.try_into()?;
|
||||
let description: TString = kwargs.get(Qstr::MP_QSTR_description)?.try_into()?;
|
||||
|
||||
let par_array: [Paragraph<'static>; 1] =
|
||||
[Paragraph::new(&theme::TEXT_MAIN_GREY_LIGHT, description)];
|
||||
let paragraphs = Paragraphs::new(par_array);
|
||||
let content_intro = Frame::left_aligned(title, SwipePage::vertical(paragraphs))
|
||||
.with_menu_button()
|
||||
.with_footer(TR::instructions__swipe_up.into(), None)
|
||||
.map(|msg| {
|
||||
matches!(msg, FrameMsg::Button(CancelInfoConfirmMsg::Info)).then_some(FlowMsg::Info)
|
||||
});
|
||||
|
||||
let content_menu = Frame::left_aligned(
|
||||
"".into(),
|
||||
VerticalMenu::empty().danger(theme::ICON_CANCEL, TR::pin__cancel_setup.into()),
|
||||
)
|
||||
.with_cancel_button()
|
||||
.map(|msg| match msg {
|
||||
FrameMsg::Content(VerticalMenuChoiceMsg::Selected(i)) => Some(FlowMsg::Choice(i)),
|
||||
FrameMsg::Button(CancelInfoConfirmMsg::Cancelled) => Some(FlowMsg::Cancelled),
|
||||
FrameMsg::Button(_) => None,
|
||||
});
|
||||
|
||||
let par_array_cancel_intro: [Paragraph<'static>; 2] = [
|
||||
Paragraph::new(&theme::TEXT_WARNING, TR::words__not_recommended),
|
||||
Paragraph::new(&theme::TEXT_MAIN_GREY_LIGHT, TR::pin__cancel_info),
|
||||
];
|
||||
let paragraphs_cancel_intro = Paragraphs::new(par_array_cancel_intro);
|
||||
let content_cancel_intro = Frame::left_aligned(
|
||||
TR::pin__cancel_setup.into(),
|
||||
SwipePage::vertical(paragraphs_cancel_intro),
|
||||
)
|
||||
.with_cancel_button()
|
||||
.with_footer(
|
||||
TR::instructions__swipe_up.into(),
|
||||
Some(TR::pin__cancel_description.into()),
|
||||
)
|
||||
.map(|msg| match msg {
|
||||
FrameMsg::Button(CancelInfoConfirmMsg::Cancelled) => Some(FlowMsg::Cancelled),
|
||||
_ => None,
|
||||
});
|
||||
|
||||
let content_cancel_confirm = Frame::left_aligned(
|
||||
TR::pin__cancel_setup.into(),
|
||||
PromptScreen::new_tap_to_cancel(),
|
||||
)
|
||||
.with_footer(TR::instructions__tap_to_confirm.into(), None)
|
||||
.map(|msg| match msg {
|
||||
FrameMsg::Content(()) => Some(FlowMsg::Confirmed),
|
||||
FrameMsg::Button(CancelInfoConfirmMsg::Cancelled) => Some(FlowMsg::Cancelled),
|
||||
_ => None,
|
||||
});
|
||||
|
||||
let store = flow_store()
|
||||
.add(content_intro)?
|
||||
.add(content_menu)?
|
||||
.add(content_cancel_intro)?
|
||||
.add(content_cancel_confirm)?;
|
||||
let res = SwipeFlow::new(SetNewPin::Intro, store)?;
|
||||
Ok(LayoutObj::new(res)?.into())
|
||||
}
|
||||
}
|
@ -1,5 +1,6 @@
|
||||
pub mod confirm_reset_create;
|
||||
pub mod confirm_reset_recover;
|
||||
pub mod confirm_set_new_pin;
|
||||
pub mod get_address;
|
||||
pub mod prompt_backup;
|
||||
pub mod show_share_words;
|
||||
@ -7,6 +8,7 @@ pub mod warning_hi_prio;
|
||||
|
||||
pub use confirm_reset_create::ConfirmResetCreate;
|
||||
pub use confirm_reset_recover::ConfirmResetRecover;
|
||||
pub use confirm_set_new_pin::SetNewPin;
|
||||
pub use get_address::GetAddress;
|
||||
pub use prompt_backup::PromptBackup;
|
||||
pub use show_share_words::ShowShareWords;
|
||||
|
@ -882,14 +882,26 @@ fn new_show_modal(
|
||||
|
||||
extern "C" fn new_show_error(n_args: usize, args: *const Obj, kwargs: *mut Map) -> Obj {
|
||||
let block = move |_args: &[Obj], kwargs: &Map| {
|
||||
let icon = BlendedImage::new(
|
||||
theme::IMAGE_BG_CIRCLE,
|
||||
theme::IMAGE_FG_ERROR,
|
||||
theme::ERROR_COLOR,
|
||||
theme::FG,
|
||||
theme::BG,
|
||||
);
|
||||
new_show_modal(kwargs, icon, theme::button_default())
|
||||
let title: TString = kwargs.get(Qstr::MP_QSTR_title)?.try_into()?;
|
||||
let description: TString = kwargs.get(Qstr::MP_QSTR_description)?.try_into()?;
|
||||
let allow_cancel: bool = kwargs.get(Qstr::MP_QSTR_allow_cancel)?.try_into()?;
|
||||
|
||||
let content = SwipeUpScreen::new(Paragraphs::new([Paragraph::new(
|
||||
&theme::TEXT_MAIN_GREY_LIGHT,
|
||||
description,
|
||||
)]));
|
||||
let frame = if allow_cancel {
|
||||
Frame::left_aligned(title, content)
|
||||
.with_cancel_button()
|
||||
.with_danger()
|
||||
.with_footer(TR::instructions__swipe_up.into(), None)
|
||||
} else {
|
||||
Frame::left_aligned(title, content)
|
||||
.with_danger()
|
||||
.with_footer(TR::instructions__swipe_up.into(), None)
|
||||
};
|
||||
let obj = LayoutObj::new(frame)?;
|
||||
Ok(obj.into())
|
||||
};
|
||||
unsafe { util::try_with_args_and_kwargs(n_args, args, kwargs, block) }
|
||||
}
|
||||
@ -1670,6 +1682,15 @@ pub static mp_module_trezorui2: Module = obj_module! {
|
||||
/// """Confirm TOS before creating a wallet and have a user hold to confirm creation."""
|
||||
Qstr::MP_QSTR_flow_confirm_reset_create => obj_fn_kw!(0, flow::confirm_reset_create::new_confirm_reset_create).as_obj(),
|
||||
|
||||
// TODO: supply more arguments for Wipe code setting when figma done
|
||||
/// def flow_confirm_set_new_pin(
|
||||
/// *,
|
||||
/// title: str,
|
||||
/// description: str,
|
||||
/// ) -> LayoutObj[UiResult]:
|
||||
/// """Confirm new PIN setup with an option to cancel action."""
|
||||
Qstr::MP_QSTR_flow_confirm_set_new_pin => obj_fn_kw!(0, flow::confirm_set_new_pin::new_set_new_pin).as_obj(),
|
||||
|
||||
/// def show_info_with_cancel(
|
||||
/// *,
|
||||
/// title: str,
|
||||
|
@ -155,6 +155,15 @@ def flow_confirm_reset_create() -> LayoutObj[UiResult]:
|
||||
"""Confirm TOS before creating a wallet and have a user hold to confirm creation."""
|
||||
|
||||
|
||||
# rust/src/ui/model_mercury/layout.rs
|
||||
def flow_confirm_set_new_pin(
|
||||
*,
|
||||
title: str,
|
||||
description: str,
|
||||
) -> LayoutObj[UiResult]:
|
||||
"""Confirm new PIN setup with an option to cancel action."""
|
||||
|
||||
|
||||
# rust/src/ui/model_mercury/layout.rs
|
||||
def show_info_with_cancel(
|
||||
*,
|
||||
|
@ -475,6 +475,9 @@ class TR:
|
||||
passphrase__title_source: str = "Passphrase source"
|
||||
passphrase__turn_off: str = "Turn off passphrase protection?"
|
||||
passphrase__turn_on: str = "Turn on passphrase protection?"
|
||||
pin__cancel_description: str = "Continue without PIN"
|
||||
pin__cancel_info: str = "Without a PIN, anyone can access this device."
|
||||
pin__cancel_setup: str = "Cancel PIN setup"
|
||||
pin__change: str = "Change PIN?"
|
||||
pin__changed: str = "PIN changed."
|
||||
pin__cursor_will_change: str = "Position of the cursor will change between entries for enhanced security."
|
||||
|
@ -1404,8 +1404,9 @@ async def pin_mismatch_popup(
|
||||
is_wipe_code: bool = False,
|
||||
) -> None:
|
||||
await button_request("pin_mismatch", code=BR_TYPE_OTHER)
|
||||
title = TR.wipe_code__wipe_code_mismatch if is_wipe_code else TR.pin__pin_mismatch
|
||||
description = TR.wipe_code__mismatch if is_wipe_code else TR.pin__mismatch
|
||||
title = TR.wipe_code__mismatch if is_wipe_code else TR.pin__mismatch
|
||||
description = TR.wipe_code__enter_new if is_wipe_code else TR.pin__reenter_new
|
||||
|
||||
return await show_error_popup(
|
||||
title,
|
||||
description,
|
||||
@ -1432,14 +1433,7 @@ async def confirm_set_new_pin(
|
||||
await raise_if_not_confirmed(
|
||||
interact(
|
||||
RustLayout(
|
||||
trezorui2.confirm_emphasized(
|
||||
title=title,
|
||||
items=(
|
||||
(True, description + "\n\n"),
|
||||
information,
|
||||
),
|
||||
verb=TR.buttons__turn_on,
|
||||
)
|
||||
trezorui2.flow_confirm_set_new_pin(title=title, description=description)
|
||||
),
|
||||
br_type,
|
||||
br_code,
|
||||
|
@ -477,8 +477,11 @@
|
||||
"passphrase__title_source": "Passphrase source",
|
||||
"passphrase__turn_off": "Turn off passphrase protection?",
|
||||
"passphrase__turn_on": "Turn on passphrase protection?",
|
||||
"pin__cancel_info": "Without a PIN, anyone can access this device.",
|
||||
"pin__cancel_setup": "Cancel PIN setup",
|
||||
"pin__change": "Change PIN?",
|
||||
"pin__changed": "PIN changed.",
|
||||
"pin__cancel_description": "Continue without PIN",
|
||||
"pin__cursor_will_change": "Position of the cursor will change between entries for enhanced security.",
|
||||
"pin__diff_from_wipe_code": "The new PIN must be different from your wipe code.",
|
||||
"pin__disabled": "PIN protection\nturned off.",
|
||||
|
@ -868,5 +868,9 @@
|
||||
"866": "address_details__derivation_path",
|
||||
"867": "instructions__continue_in_app",
|
||||
"868": "words__cancel_and_exit",
|
||||
"869": "address__confirmed"
|
||||
"869": "address__confirmed",
|
||||
"870": "reset__title_shamir_backup",
|
||||
"871": "pin__cancel_description",
|
||||
"872": "pin__cancel_info",
|
||||
"873": "pin__cancel_setup"
|
||||
}
|
||||
|
@ -1,8 +1,8 @@
|
||||
{
|
||||
"current": {
|
||||
"merkle_root": "d2a00bb90ebc87448eb0786432129db7c4e67316de7c491bf854d8429d2db9b8",
|
||||
"datetime": "2024-05-17T10:29:37.039056",
|
||||
"commit": "b3379e14e0658ab2327bffdfff5227f6079c8f74"
|
||||
"merkle_root": "9c620dab3212f47d952020e2badc61a9443778fbca180208db622f3d0ebcbe5c",
|
||||
"datetime": "2024-05-17T10:46:08.576451",
|
||||
"commit": "cce30d1364fb62e3ed51509fefe7d48c86b45a5c"
|
||||
},
|
||||
"history": [
|
||||
{
|
||||
|
@ -17,8 +17,8 @@ LEFT = grid(DISPLAY_WIDTH, 3, 0)
|
||||
MID = grid(DISPLAY_WIDTH, 3, 1)
|
||||
RIGHT = grid(DISPLAY_WIDTH, 3, 2)
|
||||
|
||||
TOP = grid(DISPLAY_HEIGHT, 4, 0)
|
||||
BOTTOM = grid(DISPLAY_HEIGHT, 4, 3)
|
||||
TOP = grid(DISPLAY_HEIGHT, 6, 0)
|
||||
BOTTOM = grid(DISPLAY_HEIGHT, 6, 5)
|
||||
|
||||
OK = (RIGHT, BOTTOM)
|
||||
CANCEL = (LEFT, BOTTOM)
|
||||
|
@ -46,10 +46,12 @@ def get_char_category(char: str) -> PassphraseCategory:
|
||||
|
||||
|
||||
def go_next(debug: "DebugLink", wait: bool = False) -> "LayoutContent" | None:
|
||||
if debug.model in (models.T2T1, models.T3T1):
|
||||
if debug.model in (models.T2T1,):
|
||||
return debug.click(buttons.OK, wait=wait) # type: ignore
|
||||
elif debug.model in (models.T2B1,):
|
||||
return debug.press_right(wait=wait) # type: ignore
|
||||
elif debug.model in (models.T3T1,):
|
||||
return debug.swipe_up(wait=wait)
|
||||
else:
|
||||
raise RuntimeError("Unknown model")
|
||||
|
||||
@ -111,6 +113,17 @@ def navigate_to_action_and_press(
|
||||
debug.press_middle(wait=True)
|
||||
|
||||
|
||||
def unlock_gesture(debug: "DebugLink", wait: bool = False) -> "LayoutContent" | None:
|
||||
if debug.model in (models.T2T1,):
|
||||
return debug.click(buttons.OK, wait=wait) # type: ignore
|
||||
elif debug.model in (models.T2B1,):
|
||||
return debug.press_right(wait=wait) # type: ignore
|
||||
elif debug.model in (models.T3T1,):
|
||||
return debug.click(buttons.TAP_TO_CONFIRM, wait=wait) # type: ignore
|
||||
else:
|
||||
raise RuntimeError("Unknown model")
|
||||
|
||||
|
||||
def _get_action_index(wanted_action: str, all_actions: list[str]) -> int:
|
||||
"""Get index of the action in the list of all actions"""
|
||||
if wanted_action in all_actions:
|
||||
|
@ -62,7 +62,7 @@ def select_number_of_words(
|
||||
if wait:
|
||||
debug.wait_layout()
|
||||
TR.assert_equals(debug.read_layout().text_content(), "recovery__num_of_words")
|
||||
if debug.model in (models.T2T1, models.T3T1):
|
||||
if debug.model in (models.T2T1,):
|
||||
# click the number
|
||||
word_option_offset = 6
|
||||
word_options = (12, 18, 20, 24, 33)
|
||||
@ -81,6 +81,20 @@ def select_number_of_words(
|
||||
for _ in range(index):
|
||||
debug.press_right(wait=True)
|
||||
layout = debug.press_middle(wait=True)
|
||||
elif debug.model in (models.T3T1,):
|
||||
if num_of_words == 12:
|
||||
coords = buttons.grid34(0, 1)
|
||||
elif num_of_words == 18:
|
||||
coords = buttons.grid34(2, 1)
|
||||
elif num_of_words == 20:
|
||||
coords = buttons.grid34(0, 2)
|
||||
elif num_of_words == 24:
|
||||
coords = buttons.grid34(2, 2)
|
||||
elif num_of_words == 33:
|
||||
coords = buttons.grid34(1, 3)
|
||||
else:
|
||||
raise ValueError("Invalid num_of_words")
|
||||
layout = debug.click(coords, wait=True)
|
||||
else:
|
||||
raise ValueError("Unknown model")
|
||||
|
||||
|
@ -29,7 +29,7 @@ from .. import translations as TR
|
||||
from ..device_tests.bitcoin.payment_req import make_coinjoin_request
|
||||
from ..tx_cache import TxCache
|
||||
from . import recovery
|
||||
from .common import go_next
|
||||
from .common import go_next, unlock_gesture
|
||||
|
||||
if TYPE_CHECKING:
|
||||
from trezorlib.debuglink import DebugLink, LayoutContent
|
||||
@ -279,7 +279,8 @@ def test_dryrun_locks_at_number_of_words(device_handler: "BackgroundDeviceHandle
|
||||
# unlock
|
||||
# lockscreen triggered automatically
|
||||
debug.wait_layout(wait_for_external_change=True)
|
||||
layout = go_next(debug, wait=True)
|
||||
layout = unlock_gesture(debug, wait=True)
|
||||
|
||||
assert "PinKeyboard" in layout.all_components()
|
||||
layout = debug.input(PIN4, wait=True)
|
||||
assert layout is not None
|
||||
@ -301,7 +302,7 @@ def test_dryrun_locks_at_word_entry(device_handler: "BackgroundDeviceHandler"):
|
||||
recovery.select_number_of_words(debug, 20)
|
||||
|
||||
if debug.model in (models.T2T1, models.T3T1):
|
||||
layout = debug.click(buttons.OK, wait=True)
|
||||
layout = go_next(debug, wait=True)
|
||||
assert layout.main_component() == "MnemonicKeyboard"
|
||||
elif debug.model in (models.T2B1,):
|
||||
layout = debug.press_right(wait=True)
|
||||
|
@ -95,7 +95,9 @@ def prepare(
|
||||
elif situation == Situation.PIN_SETUP:
|
||||
# Set new PIN
|
||||
device_handler.run(device.change_pin) # type: ignore
|
||||
TR.assert_in(debug.wait_layout().text_content(), "pin__turn_on")
|
||||
TR.assert_in_multiple(
|
||||
debug.wait_layout().text_content(), ["pin__turn_on", "pin__info"]
|
||||
)
|
||||
if debug.model in (models.T2T1, models.T3T1):
|
||||
go_next(debug)
|
||||
elif debug.model in (models.T2B1,):
|
||||
@ -306,12 +308,15 @@ def test_pin_setup(device_handler: "BackgroundDeviceHandler"):
|
||||
def test_pin_setup_mismatch(device_handler: "BackgroundDeviceHandler"):
|
||||
with PIN_CANCELLED, prepare(device_handler, Situation.PIN_SETUP) as debug:
|
||||
_enter_two_times(debug, "1", "2")
|
||||
if debug.model in (models.T2T1, models.T3T1):
|
||||
if debug.model in (models.T2T1,):
|
||||
go_next(debug)
|
||||
_cancel_pin(debug)
|
||||
elif debug.model in (models.T2B1,):
|
||||
debug.press_middle()
|
||||
debug.press_no()
|
||||
elif debug.model in (models.T3T1,):
|
||||
go_next(debug, wait=True)
|
||||
_cancel_pin(debug)
|
||||
|
||||
|
||||
@pytest.mark.setup_client(pin="1")
|
||||
|
@ -421,12 +421,11 @@ def pytest_configure(config: "Config") -> None:
|
||||
def pytest_runtest_setup(item: pytest.Item) -> None:
|
||||
"""Called for each test item (class, individual tests).
|
||||
|
||||
Ensures that altcoin tests are skipped, and that no test is skipped on
|
||||
both T1 and TT.
|
||||
Ensures that altcoin tests are skipped, and that no test is skipped for all models.
|
||||
"""
|
||||
if all(
|
||||
item.get_closest_marker(marker)
|
||||
for marker in ("skip_t1b1", "skip_t2t1", "skip_t2b1")
|
||||
for marker in ("skip_t1b1", "skip_t2t1", "skip_t2b1", "skip_t3t1")
|
||||
):
|
||||
raise RuntimeError("Don't skip tests for all trezor models!")
|
||||
|
||||
|
@ -21,6 +21,7 @@ from trezorlib.client import MAX_PIN_LENGTH, PASSPHRASE_TEST_PATH
|
||||
from trezorlib.debuglink import TrezorClientDebugLink as Client
|
||||
from trezorlib.exceptions import Cancelled, TrezorFailure
|
||||
|
||||
from .. import buttons
|
||||
from ..input_flows import (
|
||||
InputFlowCodeChangeFail,
|
||||
InputFlowNewCodeMismatch,
|
||||
@ -180,3 +181,27 @@ def test_change_invalid_current(client: Client):
|
||||
client.init_device()
|
||||
assert client.features.pin_protection is True
|
||||
_check_pin(client, PIN4)
|
||||
|
||||
|
||||
@pytest.mark.skip_t2b1()
|
||||
@pytest.mark.skip_t2t1()
|
||||
@pytest.mark.setup_client(pin=None)
|
||||
def test_pin_menu_cancel_setup(client: Client):
|
||||
def cancel_pin_setup_input_flow():
|
||||
yield
|
||||
# enter context menu
|
||||
client.debug.click(buttons.CORNER_BUTTON)
|
||||
client.debug.synchronize_at("VerticalMenu")
|
||||
# click "Cancel PIN setup"
|
||||
client.debug.click(buttons.VERTICAL_MENU[0])
|
||||
client.debug.synchronize_at("Paragraphs")
|
||||
# swipe through info screen
|
||||
client.debug.swipe_up()
|
||||
client.debug.synchronize_at("PromptScreen")
|
||||
# tap to confirm
|
||||
client.debug.click(buttons.TAP_TO_CONFIRM)
|
||||
|
||||
with client, pytest.raises(Cancelled):
|
||||
client.set_input_flow(cancel_pin_setup_input_flow)
|
||||
client.call(messages.ChangePin())
|
||||
_check_no_pin(client)
|
||||
|
Loading…
Reference in New Issue
Block a user