mirror of
https://github.com/trezor/trezor-firmware.git
synced 2025-07-30 18:38:27 +00:00
test(core/sdbackup): reset, recovery
- BIP39 recovery test (MNEMONIC12 backup block written directly to mocked SD card) - BIP39 reset-recovery test - 3-of-5 shamir reset-recovery test - WIP: InputFlows will be updated and polished with UX improvements later
This commit is contained in:
parent
a0ef80baeb
commit
144a4e812d
@ -190,9 +190,14 @@ message DebugLinkEraseSdCard {
|
||||
* @next Success
|
||||
*/
|
||||
message DebugLinkInsertSdCard {
|
||||
optional uint32 serial_number = 1; // mocked serial number of the card (e.g.: 1, 2, 3,...)
|
||||
optional uint32 capacity_bytes = 2; // capacity of the card in bytes
|
||||
optional uint32 serial_number = 1; // mocked serial number of the card (range 1-16)
|
||||
optional uint32 capacity_bytes = 2; // capacity of the mocked card in bytes
|
||||
optional uint32 manuf_ID = 3; // mocked manufacturer ID
|
||||
repeated DebugLinkSdCardDataBlock data_blocks = 4; // data written directly to individual memory blocks
|
||||
message DebugLinkSdCardDataBlock {
|
||||
required uint32 number = 1;
|
||||
required bytes data = 2;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
@ -205,7 +210,6 @@ message DebugLinkWatchLayout {
|
||||
// if false, stop.
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Request: Remove all the previous debug event state
|
||||
* @start
|
||||
|
@ -5,7 +5,7 @@ from typing import *
|
||||
def insert(
|
||||
card_sn: int,
|
||||
capacity_bytes: int | None = 122_945_536,
|
||||
manuf_id: int | None = 27,
|
||||
manuf_id: int | None = 39,
|
||||
) -> None:
|
||||
"""
|
||||
Inserts SD card to the emulator.
|
||||
|
@ -241,15 +241,14 @@ if __debug__:
|
||||
|
||||
try:
|
||||
sdcard.power_on()
|
||||
# trash the whole card
|
||||
assert sdcard.capacity() >= sdcard.BLOCK_SIZE
|
||||
empty_block = bytes([0xFF] * sdcard.BLOCK_SIZE)
|
||||
for i in range(sdcard.capacity() // sdcard.BLOCK_SIZE):
|
||||
sdcard.write(i, empty_block)
|
||||
# make filesystem
|
||||
if msg.format:
|
||||
io.fatfs.mkfs()
|
||||
else:
|
||||
# trash first 1 MB of data to destroy the FAT filesystem
|
||||
assert sdcard.capacity() >= 1024 * 1024
|
||||
empty_block = bytes([0xFF] * sdcard.BLOCK_SIZE)
|
||||
for i in range(1024 * 1024 // sdcard.BLOCK_SIZE):
|
||||
sdcard.write(i, empty_block)
|
||||
|
||||
except OSError:
|
||||
raise wire.ProcessError("SD card operation failed")
|
||||
finally:
|
||||
@ -268,6 +267,12 @@ if __debug__:
|
||||
capacity_bytes=msg.capacity_bytes,
|
||||
manuf_id=msg.manuf_ID,
|
||||
)
|
||||
if msg.data_blocks is not None:
|
||||
sdcard = io.sdcard
|
||||
sdcard.power_on()
|
||||
for block in msg.data_blocks:
|
||||
sdcard.write(block.number, block.data)
|
||||
sdcard.power_off()
|
||||
|
||||
return Success()
|
||||
|
||||
|
@ -2927,10 +2927,12 @@ if TYPE_CHECKING:
|
||||
serial_number: "int | None"
|
||||
capacity_bytes: "int | None"
|
||||
manuf_ID: "int | None"
|
||||
data_blocks: "list[DebugLinkSdCardDataBlock]"
|
||||
|
||||
def __init__(
|
||||
self,
|
||||
*,
|
||||
data_blocks: "list[DebugLinkSdCardDataBlock] | None" = None,
|
||||
serial_number: "int | None" = None,
|
||||
capacity_bytes: "int | None" = None,
|
||||
manuf_ID: "int | None" = None,
|
||||
@ -2961,6 +2963,22 @@ if TYPE_CHECKING:
|
||||
def is_type_of(cls, msg: Any) -> TypeGuard["DebugLinkResetDebugEvents"]:
|
||||
return isinstance(msg, cls)
|
||||
|
||||
class DebugLinkSdCardDataBlock(protobuf.MessageType):
|
||||
number: "int"
|
||||
data: "bytes"
|
||||
|
||||
def __init__(
|
||||
self,
|
||||
*,
|
||||
number: "int",
|
||||
data: "bytes",
|
||||
) -> None:
|
||||
pass
|
||||
|
||||
@classmethod
|
||||
def is_type_of(cls, msg: Any) -> TypeGuard["DebugLinkSdCardDataBlock"]:
|
||||
return isinstance(msg, cls)
|
||||
|
||||
class EosGetPublicKey(protobuf.MessageType):
|
||||
address_n: "list[int]"
|
||||
show_display: "bool | None"
|
||||
|
@ -25,7 +25,7 @@ if TYPE_CHECKING:
|
||||
P = ParamSpec("P")
|
||||
R = TypeVar("R")
|
||||
|
||||
SD_CARD_HOT_SWAPPABLE = False
|
||||
SD_CARD_HOT_SWAPPABLE = True
|
||||
|
||||
|
||||
class FilesystemWrapper:
|
||||
|
@ -746,6 +746,7 @@ class DebugLink:
|
||||
serial_number: int = 1,
|
||||
capacity_bytes: Optional[int] = None,
|
||||
manuf_ID: Optional[int] = None,
|
||||
data_blocks: Optional[List[messages.DebugLinkSdCardDataBlock]] = None,
|
||||
) -> messages.Success:
|
||||
if not self.model == "T":
|
||||
raise RuntimeError("SD card not supported by this device.")
|
||||
@ -756,6 +757,7 @@ class DebugLink:
|
||||
serial_number=serial_number,
|
||||
capacity_bytes=capacity_bytes,
|
||||
manuf_ID=manuf_ID,
|
||||
data_blocks=data_blocks,
|
||||
)
|
||||
)
|
||||
|
||||
|
@ -4091,15 +4091,18 @@ class DebugLinkInsertSdCard(protobuf.MessageType):
|
||||
1: protobuf.Field("serial_number", "uint32", repeated=False, required=False, default=None),
|
||||
2: protobuf.Field("capacity_bytes", "uint32", repeated=False, required=False, default=None),
|
||||
3: protobuf.Field("manuf_ID", "uint32", repeated=False, required=False, default=None),
|
||||
4: protobuf.Field("data_blocks", "DebugLinkSdCardDataBlock", repeated=True, required=False, default=None),
|
||||
}
|
||||
|
||||
def __init__(
|
||||
self,
|
||||
*,
|
||||
data_blocks: Optional[Sequence["DebugLinkSdCardDataBlock"]] = None,
|
||||
serial_number: Optional["int"] = None,
|
||||
capacity_bytes: Optional["int"] = None,
|
||||
manuf_ID: Optional["int"] = None,
|
||||
) -> None:
|
||||
self.data_blocks: Sequence["DebugLinkSdCardDataBlock"] = data_blocks if data_blocks is not None else []
|
||||
self.serial_number = serial_number
|
||||
self.capacity_bytes = capacity_bytes
|
||||
self.manuf_ID = manuf_ID
|
||||
@ -4123,6 +4126,23 @@ class DebugLinkResetDebugEvents(protobuf.MessageType):
|
||||
MESSAGE_WIRE_TYPE = 9008
|
||||
|
||||
|
||||
class DebugLinkSdCardDataBlock(protobuf.MessageType):
|
||||
MESSAGE_WIRE_TYPE = None
|
||||
FIELDS = {
|
||||
1: protobuf.Field("number", "uint32", repeated=False, required=True),
|
||||
2: protobuf.Field("data", "bytes", repeated=False, required=True),
|
||||
}
|
||||
|
||||
def __init__(
|
||||
self,
|
||||
*,
|
||||
number: "int",
|
||||
data: "bytes",
|
||||
) -> None:
|
||||
self.number = number
|
||||
self.data = data
|
||||
|
||||
|
||||
class EosGetPublicKey(protobuf.MessageType):
|
||||
MESSAGE_WIRE_TYPE = 600
|
||||
FIELDS = {
|
||||
|
@ -3220,6 +3220,8 @@ pub struct DebugLinkInsertSdCard {
|
||||
pub capacity_bytes: ::std::option::Option<u32>,
|
||||
// @@protoc_insertion_point(field:hw.trezor.messages.debug.DebugLinkInsertSdCard.manuf_ID)
|
||||
pub manuf_ID: ::std::option::Option<u32>,
|
||||
// @@protoc_insertion_point(field:hw.trezor.messages.debug.DebugLinkInsertSdCard.data_blocks)
|
||||
pub data_blocks: ::std::vec::Vec<debug_link_insert_sd_card::DebugLinkSdCardDataBlock>,
|
||||
// special fields
|
||||
// @@protoc_insertion_point(special_field:hw.trezor.messages.debug.DebugLinkInsertSdCard.special_fields)
|
||||
pub special_fields: ::protobuf::SpecialFields,
|
||||
@ -3294,7 +3296,7 @@ impl DebugLinkInsertSdCard {
|
||||
}
|
||||
|
||||
fn generated_message_descriptor_data() -> ::protobuf::reflect::GeneratedMessageDescriptorData {
|
||||
let mut fields = ::std::vec::Vec::with_capacity(3);
|
||||
let mut fields = ::std::vec::Vec::with_capacity(4);
|
||||
let mut oneofs = ::std::vec::Vec::with_capacity(0);
|
||||
fields.push(::protobuf::reflect::rt::v2::make_option_accessor::<_, _>(
|
||||
"serial_number",
|
||||
@ -3311,6 +3313,11 @@ impl DebugLinkInsertSdCard {
|
||||
|m: &DebugLinkInsertSdCard| { &m.manuf_ID },
|
||||
|m: &mut DebugLinkInsertSdCard| { &mut m.manuf_ID },
|
||||
));
|
||||
fields.push(::protobuf::reflect::rt::v2::make_vec_simpler_accessor::<_, _>(
|
||||
"data_blocks",
|
||||
|m: &DebugLinkInsertSdCard| { &m.data_blocks },
|
||||
|m: &mut DebugLinkInsertSdCard| { &mut m.data_blocks },
|
||||
));
|
||||
::protobuf::reflect::GeneratedMessageDescriptorData::new_2::<DebugLinkInsertSdCard>(
|
||||
"DebugLinkInsertSdCard",
|
||||
fields,
|
||||
@ -3323,6 +3330,11 @@ impl ::protobuf::Message for DebugLinkInsertSdCard {
|
||||
const NAME: &'static str = "DebugLinkInsertSdCard";
|
||||
|
||||
fn is_initialized(&self) -> bool {
|
||||
for v in &self.data_blocks {
|
||||
if !v.is_initialized() {
|
||||
return false;
|
||||
}
|
||||
};
|
||||
true
|
||||
}
|
||||
|
||||
@ -3338,6 +3350,9 @@ impl ::protobuf::Message for DebugLinkInsertSdCard {
|
||||
24 => {
|
||||
self.manuf_ID = ::std::option::Option::Some(is.read_uint32()?);
|
||||
},
|
||||
34 => {
|
||||
self.data_blocks.push(is.read_message()?);
|
||||
},
|
||||
tag => {
|
||||
::protobuf::rt::read_unknown_or_skip_group(tag, is, self.special_fields.mut_unknown_fields())?;
|
||||
},
|
||||
@ -3359,6 +3374,10 @@ impl ::protobuf::Message for DebugLinkInsertSdCard {
|
||||
if let Some(v) = self.manuf_ID {
|
||||
my_size += ::protobuf::rt::uint32_size(3, v);
|
||||
}
|
||||
for value in &self.data_blocks {
|
||||
let len = value.compute_size();
|
||||
my_size += 1 + ::protobuf::rt::compute_raw_varint64_size(len) + len;
|
||||
};
|
||||
my_size += ::protobuf::rt::unknown_fields_size(self.special_fields.unknown_fields());
|
||||
self.special_fields.cached_size().set(my_size as u32);
|
||||
my_size
|
||||
@ -3374,6 +3393,9 @@ impl ::protobuf::Message for DebugLinkInsertSdCard {
|
||||
if let Some(v) = self.manuf_ID {
|
||||
os.write_uint32(3, v)?;
|
||||
}
|
||||
for v in &self.data_blocks {
|
||||
::protobuf::rt::write_message_field_with_cached_size(4, v, os)?;
|
||||
};
|
||||
os.write_unknown_fields(self.special_fields.unknown_fields())?;
|
||||
::std::result::Result::Ok(())
|
||||
}
|
||||
@ -3394,6 +3416,7 @@ impl ::protobuf::Message for DebugLinkInsertSdCard {
|
||||
self.serial_number = ::std::option::Option::None;
|
||||
self.capacity_bytes = ::std::option::Option::None;
|
||||
self.manuf_ID = ::std::option::Option::None;
|
||||
self.data_blocks.clear();
|
||||
self.special_fields.clear();
|
||||
}
|
||||
|
||||
@ -3402,6 +3425,7 @@ impl ::protobuf::Message for DebugLinkInsertSdCard {
|
||||
serial_number: ::std::option::Option::None,
|
||||
capacity_bytes: ::std::option::Option::None,
|
||||
manuf_ID: ::std::option::Option::None,
|
||||
data_blocks: ::std::vec::Vec::new(),
|
||||
special_fields: ::protobuf::SpecialFields::new(),
|
||||
};
|
||||
&instance
|
||||
@ -3425,6 +3449,210 @@ impl ::protobuf::reflect::ProtobufValue for DebugLinkInsertSdCard {
|
||||
type RuntimeType = ::protobuf::reflect::rt::RuntimeTypeMessage<Self>;
|
||||
}
|
||||
|
||||
/// Nested message and enums of message `DebugLinkInsertSdCard`
|
||||
pub mod debug_link_insert_sd_card {
|
||||
// @@protoc_insertion_point(message:hw.trezor.messages.debug.DebugLinkInsertSdCard.DebugLinkSdCardDataBlock)
|
||||
#[derive(PartialEq,Clone,Default,Debug)]
|
||||
pub struct DebugLinkSdCardDataBlock {
|
||||
// message fields
|
||||
// @@protoc_insertion_point(field:hw.trezor.messages.debug.DebugLinkInsertSdCard.DebugLinkSdCardDataBlock.number)
|
||||
pub number: ::std::option::Option<u32>,
|
||||
// @@protoc_insertion_point(field:hw.trezor.messages.debug.DebugLinkInsertSdCard.DebugLinkSdCardDataBlock.data)
|
||||
pub data: ::std::option::Option<::std::vec::Vec<u8>>,
|
||||
// special fields
|
||||
// @@protoc_insertion_point(special_field:hw.trezor.messages.debug.DebugLinkInsertSdCard.DebugLinkSdCardDataBlock.special_fields)
|
||||
pub special_fields: ::protobuf::SpecialFields,
|
||||
}
|
||||
|
||||
impl<'a> ::std::default::Default for &'a DebugLinkSdCardDataBlock {
|
||||
fn default() -> &'a DebugLinkSdCardDataBlock {
|
||||
<DebugLinkSdCardDataBlock as ::protobuf::Message>::default_instance()
|
||||
}
|
||||
}
|
||||
|
||||
impl DebugLinkSdCardDataBlock {
|
||||
pub fn new() -> DebugLinkSdCardDataBlock {
|
||||
::std::default::Default::default()
|
||||
}
|
||||
|
||||
// required uint32 number = 1;
|
||||
|
||||
pub fn number(&self) -> u32 {
|
||||
self.number.unwrap_or(0)
|
||||
}
|
||||
|
||||
pub fn clear_number(&mut self) {
|
||||
self.number = ::std::option::Option::None;
|
||||
}
|
||||
|
||||
pub fn has_number(&self) -> bool {
|
||||
self.number.is_some()
|
||||
}
|
||||
|
||||
// Param is passed by value, moved
|
||||
pub fn set_number(&mut self, v: u32) {
|
||||
self.number = ::std::option::Option::Some(v);
|
||||
}
|
||||
|
||||
// required bytes data = 2;
|
||||
|
||||
pub fn data(&self) -> &[u8] {
|
||||
match self.data.as_ref() {
|
||||
Some(v) => v,
|
||||
None => &[],
|
||||
}
|
||||
}
|
||||
|
||||
pub fn clear_data(&mut self) {
|
||||
self.data = ::std::option::Option::None;
|
||||
}
|
||||
|
||||
pub fn has_data(&self) -> bool {
|
||||
self.data.is_some()
|
||||
}
|
||||
|
||||
// Param is passed by value, moved
|
||||
pub fn set_data(&mut self, v: ::std::vec::Vec<u8>) {
|
||||
self.data = ::std::option::Option::Some(v);
|
||||
}
|
||||
|
||||
// Mutable pointer to the field.
|
||||
// If field is not initialized, it is initialized with default value first.
|
||||
pub fn mut_data(&mut self) -> &mut ::std::vec::Vec<u8> {
|
||||
if self.data.is_none() {
|
||||
self.data = ::std::option::Option::Some(::std::vec::Vec::new());
|
||||
}
|
||||
self.data.as_mut().unwrap()
|
||||
}
|
||||
|
||||
// Take field
|
||||
pub fn take_data(&mut self) -> ::std::vec::Vec<u8> {
|
||||
self.data.take().unwrap_or_else(|| ::std::vec::Vec::new())
|
||||
}
|
||||
|
||||
pub(in super) fn generated_message_descriptor_data() -> ::protobuf::reflect::GeneratedMessageDescriptorData {
|
||||
let mut fields = ::std::vec::Vec::with_capacity(2);
|
||||
let mut oneofs = ::std::vec::Vec::with_capacity(0);
|
||||
fields.push(::protobuf::reflect::rt::v2::make_option_accessor::<_, _>(
|
||||
"number",
|
||||
|m: &DebugLinkSdCardDataBlock| { &m.number },
|
||||
|m: &mut DebugLinkSdCardDataBlock| { &mut m.number },
|
||||
));
|
||||
fields.push(::protobuf::reflect::rt::v2::make_option_accessor::<_, _>(
|
||||
"data",
|
||||
|m: &DebugLinkSdCardDataBlock| { &m.data },
|
||||
|m: &mut DebugLinkSdCardDataBlock| { &mut m.data },
|
||||
));
|
||||
::protobuf::reflect::GeneratedMessageDescriptorData::new_2::<DebugLinkSdCardDataBlock>(
|
||||
"DebugLinkInsertSdCard.DebugLinkSdCardDataBlock",
|
||||
fields,
|
||||
oneofs,
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
impl ::protobuf::Message for DebugLinkSdCardDataBlock {
|
||||
const NAME: &'static str = "DebugLinkSdCardDataBlock";
|
||||
|
||||
fn is_initialized(&self) -> bool {
|
||||
if self.number.is_none() {
|
||||
return false;
|
||||
}
|
||||
if self.data.is_none() {
|
||||
return false;
|
||||
}
|
||||
true
|
||||
}
|
||||
|
||||
fn merge_from(&mut self, is: &mut ::protobuf::CodedInputStream<'_>) -> ::protobuf::Result<()> {
|
||||
while let Some(tag) = is.read_raw_tag_or_eof()? {
|
||||
match tag {
|
||||
8 => {
|
||||
self.number = ::std::option::Option::Some(is.read_uint32()?);
|
||||
},
|
||||
18 => {
|
||||
self.data = ::std::option::Option::Some(is.read_bytes()?);
|
||||
},
|
||||
tag => {
|
||||
::protobuf::rt::read_unknown_or_skip_group(tag, is, self.special_fields.mut_unknown_fields())?;
|
||||
},
|
||||
};
|
||||
}
|
||||
::std::result::Result::Ok(())
|
||||
}
|
||||
|
||||
// Compute sizes of nested messages
|
||||
#[allow(unused_variables)]
|
||||
fn compute_size(&self) -> u64 {
|
||||
let mut my_size = 0;
|
||||
if let Some(v) = self.number {
|
||||
my_size += ::protobuf::rt::uint32_size(1, v);
|
||||
}
|
||||
if let Some(v) = self.data.as_ref() {
|
||||
my_size += ::protobuf::rt::bytes_size(2, &v);
|
||||
}
|
||||
my_size += ::protobuf::rt::unknown_fields_size(self.special_fields.unknown_fields());
|
||||
self.special_fields.cached_size().set(my_size as u32);
|
||||
my_size
|
||||
}
|
||||
|
||||
fn write_to_with_cached_sizes(&self, os: &mut ::protobuf::CodedOutputStream<'_>) -> ::protobuf::Result<()> {
|
||||
if let Some(v) = self.number {
|
||||
os.write_uint32(1, v)?;
|
||||
}
|
||||
if let Some(v) = self.data.as_ref() {
|
||||
os.write_bytes(2, v)?;
|
||||
}
|
||||
os.write_unknown_fields(self.special_fields.unknown_fields())?;
|
||||
::std::result::Result::Ok(())
|
||||
}
|
||||
|
||||
fn special_fields(&self) -> &::protobuf::SpecialFields {
|
||||
&self.special_fields
|
||||
}
|
||||
|
||||
fn mut_special_fields(&mut self) -> &mut ::protobuf::SpecialFields {
|
||||
&mut self.special_fields
|
||||
}
|
||||
|
||||
fn new() -> DebugLinkSdCardDataBlock {
|
||||
DebugLinkSdCardDataBlock::new()
|
||||
}
|
||||
|
||||
fn clear(&mut self) {
|
||||
self.number = ::std::option::Option::None;
|
||||
self.data = ::std::option::Option::None;
|
||||
self.special_fields.clear();
|
||||
}
|
||||
|
||||
fn default_instance() -> &'static DebugLinkSdCardDataBlock {
|
||||
static instance: DebugLinkSdCardDataBlock = DebugLinkSdCardDataBlock {
|
||||
number: ::std::option::Option::None,
|
||||
data: ::std::option::Option::None,
|
||||
special_fields: ::protobuf::SpecialFields::new(),
|
||||
};
|
||||
&instance
|
||||
}
|
||||
}
|
||||
|
||||
impl ::protobuf::MessageFull for DebugLinkSdCardDataBlock {
|
||||
fn descriptor() -> ::protobuf::reflect::MessageDescriptor {
|
||||
static descriptor: ::protobuf::rt::Lazy<::protobuf::reflect::MessageDescriptor> = ::protobuf::rt::Lazy::new();
|
||||
descriptor.get(|| super::file_descriptor().message_by_package_relative_name("DebugLinkInsertSdCard.DebugLinkSdCardDataBlock").unwrap()).clone()
|
||||
}
|
||||
}
|
||||
|
||||
impl ::std::fmt::Display for DebugLinkSdCardDataBlock {
|
||||
fn fmt(&self, f: &mut ::std::fmt::Formatter<'_>) -> ::std::fmt::Result {
|
||||
::protobuf::text_format::fmt(self, f)
|
||||
}
|
||||
}
|
||||
|
||||
impl ::protobuf::reflect::ProtobufValue for DebugLinkSdCardDataBlock {
|
||||
type RuntimeType = ::protobuf::reflect::rt::RuntimeTypeMessage<Self>;
|
||||
}
|
||||
}
|
||||
|
||||
// @@protoc_insertion_point(message:hw.trezor.messages.debug.DebugLinkWatchLayout)
|
||||
#[derive(PartialEq,Clone,Default,Debug)]
|
||||
pub struct DebugLinkWatchLayout {
|
||||
@ -3714,13 +3942,17 @@ static file_descriptor_proto_data: &'static [u8] = b"\
|
||||
\x01(\rR\x07address\x12\x16\n\x06memory\x18\x02\x20\x01(\x0cR\x06memory\
|
||||
\x12\x14\n\x05flash\x18\x03\x20\x01(\x08R\x05flash\"-\n\x13DebugLinkFlas\
|
||||
hErase\x12\x16\n\x06sector\x18\x01\x20\x01(\rR\x06sector\".\n\x14DebugLi\
|
||||
nkEraseSdCard\x12\x16\n\x06format\x18\x01\x20\x01(\x08R\x06format\"~\n\
|
||||
\x15DebugLinkInsertSdCard\x12#\n\rserial_number\x18\x01\x20\x01(\rR\x0cs\
|
||||
erialNumber\x12%\n\x0ecapacity_bytes\x18\x02\x20\x01(\rR\rcapacityBytes\
|
||||
\x12\x19\n\x08manuf_ID\x18\x03\x20\x01(\rR\x07manufID\",\n\x14DebugLinkW\
|
||||
atchLayout\x12\x14\n\x05watch\x18\x01\x20\x01(\x08R\x05watch\"\x1b\n\x19\
|
||||
DebugLinkResetDebugEventsB=\n#com.satoshilabs.trezor.lib.protobufB\x12Tr\
|
||||
ezorMessageDebug\x80\xa6\x1d\x01\
|
||||
nkEraseSdCard\x12\x16\n\x06format\x18\x01\x20\x01(\x08R\x06format\"\xb1\
|
||||
\x02\n\x15DebugLinkInsertSdCard\x12#\n\rserial_number\x18\x01\x20\x01(\r\
|
||||
R\x0cserialNumber\x12%\n\x0ecapacity_bytes\x18\x02\x20\x01(\rR\rcapacity\
|
||||
Bytes\x12\x19\n\x08manuf_ID\x18\x03\x20\x01(\rR\x07manufID\x12i\n\x0bdat\
|
||||
a_blocks\x18\x04\x20\x03(\x0b2H.hw.trezor.messages.debug.DebugLinkInsert\
|
||||
SdCard.DebugLinkSdCardDataBlockR\ndataBlocks\x1aF\n\x18DebugLinkSdCardDa\
|
||||
taBlock\x12\x16\n\x06number\x18\x01\x20\x02(\rR\x06number\x12\x12\n\x04d\
|
||||
ata\x18\x02\x20\x02(\x0cR\x04data\",\n\x14DebugLinkWatchLayout\x12\x14\n\
|
||||
\x05watch\x18\x01\x20\x01(\x08R\x05watch\"\x1b\n\x19DebugLinkResetDebugE\
|
||||
ventsB=\n#com.satoshilabs.trezor.lib.protobufB\x12TrezorMessageDebug\x80\
|
||||
\xa6\x1d\x01\
|
||||
";
|
||||
|
||||
/// `FileDescriptorProto` object which was a source for this generated file
|
||||
@ -3741,7 +3973,7 @@ pub fn file_descriptor() -> &'static ::protobuf::reflect::FileDescriptor {
|
||||
deps.push(super::messages::file_descriptor().clone());
|
||||
deps.push(super::messages_common::file_descriptor().clone());
|
||||
deps.push(super::messages_management::file_descriptor().clone());
|
||||
let mut messages = ::std::vec::Vec::with_capacity(16);
|
||||
let mut messages = ::std::vec::Vec::with_capacity(17);
|
||||
messages.push(DebugLinkDecision::generated_message_descriptor_data());
|
||||
messages.push(DebugLinkLayout::generated_message_descriptor_data());
|
||||
messages.push(DebugLinkReseedRandom::generated_message_descriptor_data());
|
||||
@ -3758,6 +3990,7 @@ pub fn file_descriptor() -> &'static ::protobuf::reflect::FileDescriptor {
|
||||
messages.push(DebugLinkInsertSdCard::generated_message_descriptor_data());
|
||||
messages.push(DebugLinkWatchLayout::generated_message_descriptor_data());
|
||||
messages.push(DebugLinkResetDebugEvents::generated_message_descriptor_data());
|
||||
messages.push(debug_link_insert_sd_card::DebugLinkSdCardDataBlock::generated_message_descriptor_data());
|
||||
let mut enums = ::std::vec::Vec::with_capacity(3);
|
||||
enums.push(debug_link_decision::DebugSwipeDirection::generated_enum_descriptor_data());
|
||||
enums.push(debug_link_decision::DebugButton::generated_enum_descriptor_data());
|
||||
|
@ -215,6 +215,7 @@ def client(
|
||||
# we need to reseed before the wipe
|
||||
_raw_client.debug.reseed(0)
|
||||
|
||||
# Insert SD card if needed
|
||||
sd_marker = request.node.get_closest_marker("sd_card")
|
||||
if sd_marker:
|
||||
_raw_client.debug.insert_sd_card(1)
|
||||
|
@ -1,34 +1,44 @@
|
||||
import pytest
|
||||
|
||||
from trezorlib import device
|
||||
from trezorlib import device, messages
|
||||
from trezorlib.debuglink import TrezorClientDebugLink as Client
|
||||
from trezorlib.messages import BackupType
|
||||
|
||||
from ...common import MNEMONIC12
|
||||
from ...input_flows import InputFlowBip39RecoverySdCard
|
||||
|
||||
pytestmark = [pytest.mark.skip_t1, pytest.mark.skip_tr]
|
||||
|
||||
|
||||
def prepare_data_for_sdcard() -> bytes:
|
||||
# MNEMONIC12 backup block
|
||||
backup_block_str = "54525A4D000000004C616C636F686F6C20776F6D616E206162757365206D75737420647572696E67206D6F6E69746F72206E6F626C652061637475616C206D6978656420747261646520616E676572206169736C654B1118DAD99C3A21E85AC1CBAE3D41F8BA02BE5E6B8422B3225C9DB53C316D8A0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000"
|
||||
return bytes.fromhex(backup_block_str)
|
||||
|
||||
|
||||
@pytest.mark.setup_client(uninitialized=True)
|
||||
@pytest.mark.sd_card(formatted=False)
|
||||
def test_sd_backup_end_to_end(client: Client):
|
||||
def test_sdrecover_tt_nopin_nopassphrase(client: Client):
|
||||
with client:
|
||||
device.reset(client, pin_protection=False, label="SD card")
|
||||
# put seed writing directly to the first backup block
|
||||
mnemonic_data_bytes = prepare_data_for_sdcard()
|
||||
backup_block = messages.DebugLinkSdCardDataBlock(
|
||||
number=65525 + 552 + 63, data=mnemonic_data_bytes
|
||||
)
|
||||
client.debug.insert_sd_card(serial_number=1, data_blocks=[backup_block])
|
||||
|
||||
assert client.features.initialized is True
|
||||
assert client.features.needs_backup is False
|
||||
assert client.features.unfinished_backup is False
|
||||
assert client.features.no_backup is False
|
||||
assert client.features.backup_type is BackupType.Bip39
|
||||
IF = InputFlowBip39RecoverySdCard(client)
|
||||
client.set_input_flow(IF.get())
|
||||
device.recover(
|
||||
client,
|
||||
pin_protection=False,
|
||||
passphrase_protection=False,
|
||||
label="SD recovery",
|
||||
)
|
||||
|
||||
with client:
|
||||
device.wipe(client)
|
||||
assert client.debug.state().mnemonic_secret.decode() == MNEMONIC12
|
||||
|
||||
# assert client.features.initialized is False
|
||||
# assert client.features.no_backup is True
|
||||
|
||||
with client:
|
||||
device.recover(client, pin_protection=False)
|
||||
|
||||
state = client.debug.state()
|
||||
print(f"mnemonic is {state.mnemonic_secret}")
|
||||
# assert state.mnemonic_type is backup_type
|
||||
# assert state.mnemonic_secret == secret
|
||||
assert client.features.pin_protection is False
|
||||
assert client.features.passphrase_protection is False
|
||||
assert client.features.backup_type is messages.BackupType.Bip39
|
||||
assert client.features.label == "SD recovery"
|
||||
|
@ -0,0 +1,63 @@
|
||||
import pytest
|
||||
|
||||
from trezorlib import btc, device, messages
|
||||
from trezorlib.debuglink import TrezorClientDebugLink as Client
|
||||
from trezorlib.messages import BackupType
|
||||
from trezorlib.tools import parse_path
|
||||
|
||||
from ...common import WITH_MOCK_URANDOM
|
||||
from ...input_flows import InputFlowBip39RecoverySdCard, InputFlowBip39ResetBackupSdCard
|
||||
|
||||
pytestmark = [pytest.mark.skip_t1, pytest.mark.skip_tr]
|
||||
|
||||
# NOTE: Test adapted from test_reset_recovery_bip39.py
|
||||
|
||||
|
||||
@pytest.mark.setup_client(uninitialized=True)
|
||||
@pytest.mark.sd_card(formatted=False)
|
||||
def test_reset_recovery_sdcard(client: Client):
|
||||
reset(client)
|
||||
address_before = btc.get_address(client, "Bitcoin", parse_path("m/44h/0h/0h/0/0"))
|
||||
|
||||
device.wipe(client)
|
||||
recover(client)
|
||||
address_after = btc.get_address(client, "Bitcoin", parse_path("m/44h/0h/0h/0/0"))
|
||||
assert address_before == address_after
|
||||
|
||||
|
||||
def reset(client: Client, strength: int = 128, skip_backup: bool = False) -> None:
|
||||
with WITH_MOCK_URANDOM, client:
|
||||
IF = InputFlowBip39ResetBackupSdCard(client)
|
||||
client.set_input_flow(IF.get())
|
||||
|
||||
# No PIN, no passphrase, don't display random
|
||||
device.reset(
|
||||
client,
|
||||
display_random=False,
|
||||
strength=strength,
|
||||
passphrase_protection=False,
|
||||
pin_protection=False,
|
||||
label="test",
|
||||
language="en-US",
|
||||
backup_type=BackupType.Bip39,
|
||||
)
|
||||
|
||||
# Check if device is properly initialized
|
||||
assert client.features.initialized is True
|
||||
assert client.features.needs_backup is False
|
||||
assert client.features.pin_protection is False
|
||||
assert client.features.passphrase_protection is False
|
||||
|
||||
|
||||
|
||||
def recover(client: Client):
|
||||
with client:
|
||||
IF = InputFlowBip39RecoverySdCard(client)
|
||||
client.set_input_flow(IF.get())
|
||||
client.watch_layout()
|
||||
ret = device.recover(client, pin_protection=False, label="label")
|
||||
|
||||
# Workflow successfully ended
|
||||
assert ret == messages.Success(message="Device recovered")
|
||||
assert client.features.pin_protection is False
|
||||
assert client.features.passphrase_protection is False
|
@ -0,0 +1,70 @@
|
||||
import itertools
|
||||
|
||||
import pytest
|
||||
|
||||
from trezorlib import btc, device, messages
|
||||
from trezorlib.debuglink import TrezorClientDebugLink as Client
|
||||
from trezorlib.messages import BackupType
|
||||
from trezorlib.tools import parse_path
|
||||
|
||||
from ...common import WITH_MOCK_URANDOM
|
||||
from ...input_flows import (
|
||||
InputFlowSlip39BasicRecoverySdCard,
|
||||
InputFlowSlip39BasicResetRecoverySdCard,
|
||||
)
|
||||
|
||||
# NOTE: Test adapted from test_reset_recovery_slip39_basic.py
|
||||
|
||||
pytestmark = [pytest.mark.skip_t1, pytest.mark.skip_tr]
|
||||
sdcard_serial_numbers = [1, 2, 3, 4, 5]
|
||||
|
||||
|
||||
@pytest.mark.setup_client(uninitialized=True)
|
||||
@WITH_MOCK_URANDOM
|
||||
def test_reset_recovery(client: Client):
|
||||
reset(client)
|
||||
address_before = btc.get_address(client, "Bitcoin", parse_path("m/44h/0h/0h/0/0"))
|
||||
|
||||
for selected_sdcards in itertools.combinations(sdcard_serial_numbers, 3):
|
||||
device.wipe(client)
|
||||
recover(client, selected_sdcards)
|
||||
address_after = btc.get_address(
|
||||
client, "Bitcoin", parse_path("m/44h/0h/0h/0/0")
|
||||
)
|
||||
assert address_before == address_after
|
||||
|
||||
|
||||
def reset(client: Client, strength: int = 128) -> list[str]:
|
||||
with client:
|
||||
IF = InputFlowSlip39BasicResetRecoverySdCard(client, sdcard_serial_numbers)
|
||||
client.set_input_flow(IF.get())
|
||||
|
||||
# No PIN, no passphrase, don't display random
|
||||
device.reset(
|
||||
client,
|
||||
display_random=False,
|
||||
strength=strength,
|
||||
passphrase_protection=False,
|
||||
pin_protection=False,
|
||||
label="test",
|
||||
language="en-US",
|
||||
backup_type=BackupType.Slip39_Basic,
|
||||
)
|
||||
|
||||
# Check if device is properly initialized
|
||||
assert client.features.initialized is True
|
||||
assert client.features.needs_backup is False
|
||||
assert client.features.pin_protection is False
|
||||
assert client.features.passphrase_protection is False
|
||||
|
||||
|
||||
def recover(client: Client, sdcards: list[int]):
|
||||
with client:
|
||||
IF = InputFlowSlip39BasicRecoverySdCard(client, sdcards)
|
||||
client.set_input_flow(IF.get())
|
||||
ret = device.recover(client, pin_protection=False, label="label")
|
||||
|
||||
# Workflow successfully ended
|
||||
assert ret == messages.Success(message="Device recovered")
|
||||
assert client.features.pin_protection is False
|
||||
assert client.features.passphrase_protection is False
|
@ -7,12 +7,10 @@ pytestmark = [pytest.mark.skip_t1, pytest.mark.skip_tr]
|
||||
|
||||
@pytest.mark.sd_card(formatted=True)
|
||||
def test_sd_eject(client: Client):
|
||||
print(client.features)
|
||||
assert client.features.sd_card_present is True
|
||||
|
||||
client.debug.eject_sd_card()
|
||||
client.refresh_features()
|
||||
print(client.features)
|
||||
assert client.features.sd_card_present is False
|
||||
|
||||
client.debug.insert_sd_card(2)
|
||||
|
@ -913,13 +913,14 @@ class InputFlowBip39Backup(InputFlowBase):
|
||||
self.mnemonic = None
|
||||
|
||||
def input_flow_common(self) -> BRGeneratorType:
|
||||
# choose Words
|
||||
yield
|
||||
self.debug.press_no()
|
||||
|
||||
# 1. Confirm Reset
|
||||
yield from click_through(self.debug, screens=1, code=B.ResetDevice)
|
||||
|
||||
# 2. Choose Words
|
||||
yield
|
||||
self.debug.press_no()
|
||||
|
||||
# mnemonic phrases and rest
|
||||
self.mnemonic = yield from get_mnemonic_and_confirm_success(self.debug)
|
||||
|
||||
@ -935,11 +936,39 @@ class InputFlowBip39ResetBackup(InputFlowBase):
|
||||
# 2. Backup your seed
|
||||
# 3. Confirm warning
|
||||
yield from click_through(self.debug, screens=3, code=B.ResetDevice)
|
||||
# 4. Choose Words
|
||||
yield
|
||||
self.debug.press_no()
|
||||
|
||||
# mnemonic phrases and rest
|
||||
self.mnemonic = yield from get_mnemonic_and_confirm_success(self.debug)
|
||||
|
||||
|
||||
class InputFlowBip39ResetBackupSdCard(InputFlowBase):
|
||||
def __init__(self, client: Client):
|
||||
super().__init__(client)
|
||||
|
||||
def input_flow_common(self) -> BRGeneratorType:
|
||||
|
||||
# 1. Confirm Reset
|
||||
yield from click_through(self.debug, screens=3, code=B.ResetDevice)
|
||||
|
||||
# 2. Choose SD Card
|
||||
yield
|
||||
self.debug.press_yes()
|
||||
|
||||
# 3. Go through format screens
|
||||
yield from click_through(self.debug, screens=2, code=B.Other)
|
||||
|
||||
br = yield # confirm recovery seed check
|
||||
assert br.code == B.Success
|
||||
self.debug.press_yes()
|
||||
|
||||
br = yield # confirm success
|
||||
assert br.code == B.Success
|
||||
self.debug.press_yes()
|
||||
|
||||
|
||||
class InputFlowBip39ResetPIN(InputFlowBase):
|
||||
def __init__(self, client: Client):
|
||||
super().__init__(client)
|
||||
@ -1014,6 +1043,9 @@ def load_5_shares(
|
||||
mnemonics: list[str] = []
|
||||
|
||||
for _ in range(5):
|
||||
# Choose Words
|
||||
yield
|
||||
debug.press_no()
|
||||
# Phrase screen
|
||||
mnemonic = yield from read_and_confirm_mnemonic(debug)
|
||||
assert mnemonic is not None
|
||||
@ -1143,6 +1175,9 @@ def load_5_groups_5_shares(
|
||||
|
||||
for _g in range(5):
|
||||
for _s in range(5):
|
||||
# Choose Words
|
||||
yield
|
||||
debug.press_no()
|
||||
# Phrase screen
|
||||
mnemonic = yield from read_and_confirm_mnemonic(debug)
|
||||
assert mnemonic is not None
|
||||
@ -1154,6 +1189,52 @@ def load_5_groups_5_shares(
|
||||
return mnemonics
|
||||
|
||||
|
||||
class InputFlowSlip39BasicResetRecoverySdCard(InputFlowBase):
|
||||
def __init__(self, client: Client, sdcard_numbers):
|
||||
super().__init__(client)
|
||||
self.sdcard_numbers = sdcard_numbers
|
||||
|
||||
def input_flow_tt(self) -> BRGeneratorType:
|
||||
# 1. Confirm Reset
|
||||
# 2. Backup your seed
|
||||
# 3. Confirm warning
|
||||
# 4. shares info
|
||||
# 5. Set & Confirm number of shares
|
||||
# 6. threshold info
|
||||
# 7. Set & confirm threshold value
|
||||
# 8. Confirm show seeds
|
||||
yield from click_through(self.debug, screens=8, code=B.ResetDevice)
|
||||
|
||||
# Mnemonic phrases
|
||||
yield from load_5_shares_to_sdcards(self.debug, self.sdcard_numbers)
|
||||
|
||||
br = yield # safety warning
|
||||
assert br.code == B.Success
|
||||
self.debug.press_yes()
|
||||
|
||||
|
||||
def load_5_shares_to_sdcards(debug: DebugLink, sdcard_numbers: list[int]) -> None:
|
||||
for n in sdcard_numbers:
|
||||
# Insert the card and erase (i.e. assume empty card)
|
||||
debug.insert_sd_card(n)
|
||||
debug.erase_sd_card(format=False)
|
||||
|
||||
# Choose SD card
|
||||
yield
|
||||
debug.press_yes()
|
||||
|
||||
# Go through format screens
|
||||
yield from click_through(debug, screens=2, code=B.Other)
|
||||
|
||||
# Confirm continue
|
||||
br = yield
|
||||
assert br.code == B.Success
|
||||
debug.press_yes()
|
||||
|
||||
# Eject the card
|
||||
debug.eject_sd_card()
|
||||
|
||||
|
||||
class InputFlowSlip39AdvancedBackup(InputFlowBase):
|
||||
def __init__(self, client: Client, click_info: bool):
|
||||
super().__init__(client)
|
||||
@ -1328,11 +1409,29 @@ class InputFlowBip39Recovery(InputFlowBase):
|
||||
yield from self.REC.confirm_recovery()
|
||||
if self.pin is not None:
|
||||
yield from self.PIN.setup_new_pin(self.pin)
|
||||
# Choose Words
|
||||
yield
|
||||
self.debug.press_no()
|
||||
yield from self.REC.setup_bip39_recovery(len(self.mnemonic))
|
||||
yield from self.REC.input_mnemonic(self.mnemonic)
|
||||
yield from self.REC.success_wallet_recovered()
|
||||
|
||||
|
||||
class InputFlowBip39RecoverySdCard(InputFlowBase):
|
||||
def __init__(self, client: Client, pin: str | None = None):
|
||||
super().__init__(client)
|
||||
self.pin = pin
|
||||
|
||||
def input_flow_common(self) -> BRGeneratorType:
|
||||
yield from self.REC.confirm_recovery()
|
||||
if self.pin is not None:
|
||||
yield from self.PIN.setup_new_pin(self.pin)
|
||||
# Choose "SD card"
|
||||
yield
|
||||
self.debug.press_yes()
|
||||
yield from self.REC.success_wallet_recovered()
|
||||
|
||||
|
||||
class InputFlowSlip39AdvancedRecoveryDryRun(InputFlowBase):
|
||||
def __init__(self, client: Client, shares: list[str], mismatch: bool = False):
|
||||
super().__init__(client)
|
||||
@ -1478,6 +1577,35 @@ class InputFlowSlip39BasicRecovery(InputFlowBase):
|
||||
yield from self.REC.success_wallet_recovered()
|
||||
|
||||
|
||||
class InputFlowSlip39BasicRecoverySdCard(InputFlowBase):
|
||||
def __init__(self, client: Client, sdcard_numbers: list[int], pin: str | None = None):
|
||||
super().__init__(client)
|
||||
self.sdcard_numbers = sdcard_numbers
|
||||
self.pin = pin
|
||||
|
||||
def input_flow_common(self) -> BRGeneratorType:
|
||||
yield from self.REC.confirm_recovery()
|
||||
if self.pin is not None:
|
||||
yield from self.PIN.setup_new_pin(self.pin)
|
||||
|
||||
# "Words" counterpart:
|
||||
# yield from self.REC.setup_slip39_recovery(self.word_count)
|
||||
# yield from self.REC.input_all_slip39_shares(self.shares)
|
||||
|
||||
# choose SD card
|
||||
for n in self.sdcard_numbers:
|
||||
self.debug.eject_sd_card()
|
||||
self.debug.insert_sd_card(n)
|
||||
# choose SD card
|
||||
yield
|
||||
self.debug.press_yes()
|
||||
# enter next share
|
||||
yield
|
||||
self.debug.press_yes()
|
||||
|
||||
yield from self.REC.success_wallet_recovered()
|
||||
|
||||
|
||||
class InputFlowSlip39BasicRecoveryAbort(InputFlowBase):
|
||||
def __init__(self, client: Client):
|
||||
super().__init__(client)
|
||||
|
Loading…
Reference in New Issue
Block a user