1
0
mirror of https://github.com/trezor/trezor-firmware.git synced 2024-12-18 04:18:10 +00:00

feat(core/ui): info screens before ShareWords

Inform the user about possible repeated words in 1-of-1 SLIP39.

Instruct the user to "repeat for all shares".

[no changelog]
This commit is contained in:
obrusvit 2024-06-03 14:36:45 +02:00 committed by matejcik
parent d4b854a95e
commit 25a9ef3cf5
11 changed files with 45 additions and 17 deletions

View File

@ -502,6 +502,7 @@ static void _librust_qstrs(void) {
MP_QSTR_reset__only_one_share_will_be_created; MP_QSTR_reset__only_one_share_will_be_created;
MP_QSTR_reset__recovery_share_title_template; MP_QSTR_reset__recovery_share_title_template;
MP_QSTR_reset__recovery_wallet_backup_title; MP_QSTR_reset__recovery_wallet_backup_title;
MP_QSTR_reset__repeat_for_all_shares;
MP_QSTR_reset__required_number_of_groups; MP_QSTR_reset__required_number_of_groups;
MP_QSTR_reset__select_correct_word; MP_QSTR_reset__select_correct_word;
MP_QSTR_reset__select_threshold; MP_QSTR_reset__select_threshold;
@ -541,6 +542,7 @@ static void _librust_qstrs(void) {
MP_QSTR_reset__tos_link; MP_QSTR_reset__tos_link;
MP_QSTR_reset__total_number_of_shares_in_group_template; MP_QSTR_reset__total_number_of_shares_in_group_template;
MP_QSTR_reset__use_your_backup; MP_QSTR_reset__use_your_backup;
MP_QSTR_reset__words_may_repeat;
MP_QSTR_reset__words_written_down_template; MP_QSTR_reset__words_written_down_template;
MP_QSTR_reset__write_down_words_template; MP_QSTR_reset__write_down_words_template;
MP_QSTR_reset__wrong_word_selected; MP_QSTR_reset__wrong_word_selected;

View File

@ -1334,6 +1334,8 @@ pub enum TranslatedString {
recovery__unlock_repeated_backup = 934, // "Create additional backup?" recovery__unlock_repeated_backup = 934, // "Create additional backup?"
recovery__unlock_repeated_backup_verb = 935, // "Unlock backup" recovery__unlock_repeated_backup_verb = 935, // "Unlock backup"
homescreen__set_default = 936, // "Do you really want to set default homescreen image?" homescreen__set_default = 936, // "Do you really want to set default homescreen image?"
reset__words_may_repeat = 937, // "Words may repeat."
reset__repeat_for_all_shares = 938, // "Repeat for all shares."
} }
impl TranslatedString { impl TranslatedString {
@ -2663,6 +2665,8 @@ impl TranslatedString {
Self::recovery__unlock_repeated_backup => "Create additional backup?", Self::recovery__unlock_repeated_backup => "Create additional backup?",
Self::recovery__unlock_repeated_backup_verb => "Unlock backup", Self::recovery__unlock_repeated_backup_verb => "Unlock backup",
Self::homescreen__set_default => "Do you really want to set default homescreen image?", Self::homescreen__set_default => "Do you really want to set default homescreen image?",
Self::reset__words_may_repeat => "Words may repeat.",
Self::reset__repeat_for_all_shares => "Repeat for all shares.",
} }
} }
@ -3993,6 +3997,8 @@ impl TranslatedString {
Qstr::MP_QSTR_recovery__unlock_repeated_backup => Some(Self::recovery__unlock_repeated_backup), Qstr::MP_QSTR_recovery__unlock_repeated_backup => Some(Self::recovery__unlock_repeated_backup),
Qstr::MP_QSTR_recovery__unlock_repeated_backup_verb => Some(Self::recovery__unlock_repeated_backup_verb), Qstr::MP_QSTR_recovery__unlock_repeated_backup_verb => Some(Self::recovery__unlock_repeated_backup_verb),
Qstr::MP_QSTR_homescreen__set_default => Some(Self::homescreen__set_default), Qstr::MP_QSTR_homescreen__set_default => Some(Self::homescreen__set_default),
Qstr::MP_QSTR_reset__words_may_repeat => Some(Self::reset__words_may_repeat),
Qstr::MP_QSTR_reset__repeat_for_all_shares => Some(Self::reset__repeat_for_all_shares),
_ => None, _ => None,
} }
} }

View File

@ -1,13 +1,13 @@
use crate::{ use crate::{
error, error,
micropython::{map::Map, obj::Obj, qstr::Qstr, util}, micropython::{iter::IterBuf, map::Map, obj::Obj, qstr::Qstr, util},
strutil::TString, strutil::TString,
translations::TR, translations::TR,
ui::{ ui::{
button_request::ButtonRequestCode, button_request::ButtonRequestCode,
component::{ component::{
swipe_detect::SwipeSettings, swipe_detect::SwipeSettings,
text::paragraphs::{Paragraph, Paragraphs}, text::paragraphs::{Paragraph, ParagraphSource, ParagraphVecShort, Paragraphs, VecExt},
ButtonRequestExt, ComponentExt, SwipeDirection, ButtonRequestExt, ComponentExt, SwipeDirection,
}, },
flow::{base::Decision, flow_store, FlowMsg, FlowState, FlowStore, SwipeFlow}, flow::{base::Decision, flow_store, FlowMsg, FlowState, FlowStore, SwipeFlow},
@ -24,7 +24,6 @@ use super::super::{
#[derive(Copy, Clone, PartialEq, Eq, ToPrimitive)] #[derive(Copy, Clone, PartialEq, Eq, ToPrimitive)]
pub enum ShowShareWords { pub enum ShowShareWords {
// TODO: potentially also add there the 'never put anywhere digital' warning?
Instruction, Instruction,
Words, Words,
Confirm, Confirm,
@ -80,16 +79,23 @@ impl ShowShareWords {
let subtitle: TString = kwargs.get(Qstr::MP_QSTR_subtitle)?.try_into()?; let subtitle: TString = kwargs.get(Qstr::MP_QSTR_subtitle)?.try_into()?;
let share_words_obj: Obj = kwargs.get(Qstr::MP_QSTR_words)?; let share_words_obj: Obj = kwargs.get(Qstr::MP_QSTR_words)?;
let share_words_vec: Vec<TString, 33> = util::iter_into_vec(share_words_obj)?; let share_words_vec: Vec<TString, 33> = util::iter_into_vec(share_words_obj)?;
let text_info: TString = kwargs.get(Qstr::MP_QSTR_text_info)?.try_into()?; let text_info: Obj = kwargs.get(Qstr::MP_QSTR_text_info)?;
let text_confirm: TString = kwargs.get(Qstr::MP_QSTR_text_confirm)?.try_into()?; let text_confirm: TString = kwargs.get(Qstr::MP_QSTR_text_confirm)?.try_into()?;
let nwords = share_words_vec.len(); let nwords = share_words_vec.len();
let mut instructions_paragraphs = ParagraphVecShort::new();
for item in IterBuf::new().try_iterate(text_info)? {
let text: TString = item.try_into()?;
instructions_paragraphs.add(Paragraph::new(&theme::TEXT_MAIN_GREY_LIGHT, text));
}
let paragraphs_spacing = 8;
let content_instruction = Frame::left_aligned( let content_instruction = Frame::left_aligned(
title, title,
SwipeContent::new(Paragraphs::new(Paragraph::new( SwipeContent::new(
&theme::TEXT_MAIN_GREY_LIGHT, instructions_paragraphs
text_info, .into_paragraphs()
))), .with_spacing(paragraphs_spacing),
),
) )
.with_subtitle(TR::words__instructions.into()) .with_subtitle(TR::words__instructions.into())
.with_footer(TR::instructions__swipe_up.into(), None) .with_footer(TR::instructions__swipe_up.into(), None)

View File

@ -1688,7 +1688,7 @@ pub static mp_module_trezorui2: Module = obj_module! {
/// title: str, /// title: str,
/// subtitle: str, /// subtitle: str,
/// words: Iterable[str], /// words: Iterable[str],
/// text_info: str, /// text_info: Iterable[str],
/// text_confirm: str, /// text_confirm: str,
/// ) -> LayoutObj[UiResult]: /// ) -> LayoutObj[UiResult]:
/// """Show wallet backup words preceded by an instruction screen and followed by /// """Show wallet backup words preceded by an instruction screen and followed by

View File

@ -402,7 +402,7 @@ def flow_show_share_words(
title: str, title: str,
subtitle: str, subtitle: str,
words: Iterable[str], words: Iterable[str],
text_info: str, text_info: Iterable[str],
text_confirm: str, text_confirm: str,
) -> LayoutObj[UiResult]: ) -> LayoutObj[UiResult]:
"""Show wallet backup words preceded by an instruction screen and followed by """Show wallet backup words preceded by an instruction screen and followed by

View File

@ -638,6 +638,7 @@ class TR:
reset__only_one_share_will_be_created: str = "Only one share will be created." reset__only_one_share_will_be_created: str = "Only one share will be created."
reset__recovery_share_title_template: str = "Recovery share #{0}" reset__recovery_share_title_template: str = "Recovery share #{0}"
reset__recovery_wallet_backup_title: str = "Wallet backup" reset__recovery_wallet_backup_title: str = "Wallet backup"
reset__repeat_for_all_shares: str = "Repeat for all shares."
reset__required_number_of_groups: str = "The required number of groups for recovery." reset__required_number_of_groups: str = "The required number of groups for recovery."
reset__select_correct_word: str = "Select the correct word for each position." reset__select_correct_word: str = "Select the correct word for each position."
reset__select_threshold: str = "Select the minimum shares required to recover your wallet." reset__select_threshold: str = "Select the minimum shares required to recover your wallet."
@ -676,6 +677,7 @@ class TR:
reset__tos_link: str = "trezor.io/tos" reset__tos_link: str = "trezor.io/tos"
reset__total_number_of_shares_in_group_template: str = "Set the total number of shares in Group {0}." reset__total_number_of_shares_in_group_template: str = "Set the total number of shares in Group {0}."
reset__use_your_backup: str = "Use your backup when you need to recover your wallet." reset__use_your_backup: str = "Use your backup when you need to recover your wallet."
reset__words_may_repeat: str = "Words may repeat."
reset__words_written_down_template: str = "I wrote down all {0} words in order." reset__words_written_down_template: str = "I wrote down all {0} words in order."
reset__write_down_words_template: str = "Write the following {0} words in order on your wallet backup card." reset__write_down_words_template: str = "Write the following {0} words in order on your wallet backup card."
reset__wrong_word_selected: str = "Wrong word selected!" reset__wrong_word_selected: str = "Wrong word selected!"

View File

@ -32,7 +32,13 @@ async def show_share_words(
group_index + 1, share_index + 1 group_index + 1, share_index + 1
) )
words_count = len(share_words) words_count = len(share_words)
text_info = TR.reset__write_down_words_template.format(words_count) text_info = [TR.reset__write_down_words_template.format(words_count)]
if words_count == 20 and share_index is None:
# 1-of-1 SLIP39: inform the user about repeated words
text_info.append(TR.reset__words_may_repeat)
if share_index == 0:
# regular SLIP39, 1st share
text_info.append(TR.reset__repeat_for_all_shares)
text_confirm = TR.reset__words_written_down_template.format(words_count) text_confirm = TR.reset__words_written_down_template.format(words_count)
result = await RustLayout( result = await RustLayout(

View File

@ -642,6 +642,7 @@
"reset__only_one_share_will_be_created": "Only one share will be created.", "reset__only_one_share_will_be_created": "Only one share will be created.",
"reset__recovery_share_title_template": "Recovery share #{0}", "reset__recovery_share_title_template": "Recovery share #{0}",
"reset__recovery_wallet_backup_title": "Wallet backup", "reset__recovery_wallet_backup_title": "Wallet backup",
"reset__repeat_for_all_shares": "Repeat for all shares.",
"reset__required_number_of_groups": "The required number of groups for recovery.", "reset__required_number_of_groups": "The required number of groups for recovery.",
"reset__select_correct_word": "Select the correct word for each position.", "reset__select_correct_word": "Select the correct word for each position.",
"reset__select_threshold": "Select the minimum shares required to recover your wallet.", "reset__select_threshold": "Select the minimum shares required to recover your wallet.",
@ -680,6 +681,7 @@
"reset__tos_link": "trezor.io/tos", "reset__tos_link": "trezor.io/tos",
"reset__total_number_of_shares_in_group_template": "Set the total number of shares in Group {0}.", "reset__total_number_of_shares_in_group_template": "Set the total number of shares in Group {0}.",
"reset__use_your_backup": "Use your backup when you need to recover your wallet.", "reset__use_your_backup": "Use your backup when you need to recover your wallet.",
"reset__words_may_repeat": "Words may repeat.",
"reset__words_written_down_template": "I wrote down all {0} words in order.", "reset__words_written_down_template": "I wrote down all {0} words in order.",
"reset__write_down_words_template": "Write the following {0} words in order on your wallet backup card.", "reset__write_down_words_template": "Write the following {0} words in order on your wallet backup card.",
"reset__wrong_word_selected": "Wrong word selected!", "reset__wrong_word_selected": "Wrong word selected!",

View File

@ -935,5 +935,7 @@
"933": "recovery__title_unlock_repeated_backup", "933": "recovery__title_unlock_repeated_backup",
"934": "recovery__unlock_repeated_backup", "934": "recovery__unlock_repeated_backup",
"935": "recovery__unlock_repeated_backup_verb", "935": "recovery__unlock_repeated_backup_verb",
"936": "homescreen__set_default" "936": "homescreen__set_default",
"937": "reset__words_may_repeat",
"938": "reset__repeat_for_all_shares"
} }

View File

@ -1,8 +1,8 @@
{ {
"current": { "current": {
"merkle_root": "7a115e582a5f5f09b1850946030762360f55e516a60cf960dffc9ba174c2e4d2", "merkle_root": "405ce2be8dcb492a1d4b25ec8aaeaa9914ff88594151beaceea52315172b11d0",
"datetime": "2024-06-02T11:07:12.183601", "datetime": "2024-06-03T12:40:07.498873",
"commit": "66496206ccbe9583203fbfebf8c9222e8c6379b8" "commit": "2ac4967ef190dac1fe238cc00878ff2d08e17bb5"
}, },
"history": [ "history": [
{ {

View File

@ -1554,7 +1554,9 @@ class InputFlowSlip39BasicResetRecovery(InputFlowBase):
# 6. threshold info # 6. threshold info
# 7. Set & confirm threshold value # 7. Set & confirm threshold value
# 8. Confirm show seeds # 8. Confirm show seeds
yield from click_through(self.debug, screens=9, code=B.ResetDevice) # 9. Warning
# 10. Instructions
yield from click_through(self.debug, screens=10, code=B.ResetDevice)
# Mnemonic phrases # Mnemonic phrases
self.mnemonics = yield from load_N_shares(self.debug, 5) self.mnemonics = yield from load_N_shares(self.debug, 5)