diff --git a/common/protob/messages-hello.proto b/common/protob/messages-hello.proto new file mode 100644 index 000000000..a2c0c1b2a --- /dev/null +++ b/common/protob/messages-hello.proto @@ -0,0 +1,28 @@ +syntax = "proto2"; +package hw.trezor.messages.helloworld; + +// Sugar for easier handling in Java +option java_package = "com.satoshilabs.trezor.lib.protobuf"; +option java_outer_classname = "TrezorMessageHelloWorld"; + +import "messages.proto"; + + +/** + * Request: Hello world request for text + * @next HelloWorldResponse + * @next Failure + */ +message HelloWorldRequest { + required string name = 1; + optional uint32 amount = 2 [default=1]; + optional bool show_display = 3; +} + +/** + * Response: Hello world text + * @end + */ + message HelloWorldResponse { + required string text = 1; +} diff --git a/common/protob/messages.proto b/common/protob/messages.proto index e54e7ed6a..ae0e9383a 100644 --- a/common/protob/messages.proto +++ b/common/protob/messages.proto @@ -372,4 +372,8 @@ enum MessageType { MessageType_SolanaAddress = 903 [(wire_out) = true]; MessageType_SolanaSignTx = 904 [(wire_in) = true]; MessageType_SolanaTxSignature = 905 [(wire_out) = true]; + + // Hello world + MessageType_HelloWorldRequest = 1000 [(wire_in) = true]; + MessageType_HelloWorldResponse = 1001 [(wire_out) = true]; } diff --git a/core/src/all_modules.py b/core/src/all_modules.py index aba9d6a11..af5f7d4dd 100644 --- a/core/src/all_modules.py +++ b/core/src/all_modules.py @@ -365,6 +365,8 @@ apps.misc.get_entropy import apps.misc.get_entropy apps.misc.get_firmware_hash import apps.misc.get_firmware_hash +apps.misc.hello_world +import apps.misc.hello_world apps.misc.sign_identity import apps.misc.sign_identity apps.workflow_handlers diff --git a/core/src/apps/misc/hello_world.py b/core/src/apps/misc/hello_world.py new file mode 100644 index 000000000..867d1e3e2 --- /dev/null +++ b/core/src/apps/misc/hello_world.py @@ -0,0 +1,23 @@ +from typing import TYPE_CHECKING + +from trezor.messages import HelloWorldResponse +from trezor.ui.layouts import confirm_text + +if TYPE_CHECKING: + from trezor.messages import HelloWorldRequest + + +async def hello_world(msg: HelloWorldRequest) -> HelloWorldResponse: + text = _get_text_from_msg(msg) + if msg.show_display: + await confirm_text( + "confirm_hello_world", + "Hello world", + text, + description="Hello world example", + ) + return HelloWorldResponse(text=text) + + +def _get_text_from_msg(msg: HelloWorldRequest) -> str: + return msg.amount * f"Hello {msg.name}!\n" diff --git a/core/src/apps/workflow_handlers.py b/core/src/apps/workflow_handlers.py index 8b373c4c4..1a34b4849 100644 --- a/core/src/apps/workflow_handlers.py +++ b/core/src/apps/workflow_handlers.py @@ -93,6 +93,8 @@ def _find_message_handler_module(msg_type: int) -> str: return "apps.misc.get_firmware_hash" if msg_type == MessageType.CosiCommit: return "apps.misc.cosi_commit" + if msg_type == MessageType.HelloWorldRequest: + return "apps.misc.hello_world" if not utils.BITCOIN_ONLY: if msg_type == MessageType.SetU2FCounter: diff --git a/core/src/trezor/enums/MessageType.py b/core/src/trezor/enums/MessageType.py index 5c210d0a1..acad3368d 100644 --- a/core/src/trezor/enums/MessageType.py +++ b/core/src/trezor/enums/MessageType.py @@ -243,3 +243,5 @@ if not utils.BITCOIN_ONLY: SolanaAddress = 903 SolanaSignTx = 904 SolanaTxSignature = 905 + HelloWorldRequest = 1000 + HelloWorldResponse = 1001 diff --git a/core/src/trezor/enums/__init__.py b/core/src/trezor/enums/__init__.py index 93daa4533..3d6bbc6bb 100644 --- a/core/src/trezor/enums/__init__.py +++ b/core/src/trezor/enums/__init__.py @@ -261,6 +261,8 @@ if TYPE_CHECKING: SolanaAddress = 903 SolanaSignTx = 904 SolanaTxSignature = 905 + HelloWorldRequest = 1000 + HelloWorldResponse = 1001 class FailureType(IntEnum): UnexpectedMessage = 1 diff --git a/core/src/trezor/messages.py b/core/src/trezor/messages.py index e8aabef61..e40298c9a 100644 --- a/core/src/trezor/messages.py +++ b/core/src/trezor/messages.py @@ -3923,6 +3923,38 @@ if TYPE_CHECKING: def is_type_of(cls, msg: Any) -> TypeGuard["EthereumAccessList"]: return isinstance(msg, cls) + class HelloWorldRequest(protobuf.MessageType): + name: "str" + amount: "int" + show_display: "bool | None" + + def __init__( + self, + *, + name: "str", + amount: "int | None" = None, + show_display: "bool | None" = None, + ) -> None: + pass + + @classmethod + def is_type_of(cls, msg: Any) -> TypeGuard["HelloWorldRequest"]: + return isinstance(msg, cls) + + class HelloWorldResponse(protobuf.MessageType): + text: "str" + + def __init__( + self, + *, + text: "str", + ) -> None: + pass + + @classmethod + def is_type_of(cls, msg: Any) -> TypeGuard["HelloWorldResponse"]: + return isinstance(msg, cls) + class MoneroTransactionSourceEntry(protobuf.MessageType): outputs: "list[MoneroOutputEntry]" real_output: "int | None" diff --git a/core/tests/test_apps.misc.hello_world.py b/core/tests/test_apps.misc.hello_world.py new file mode 100644 index 000000000..bec634af8 --- /dev/null +++ b/core/tests/test_apps.misc.hello_world.py @@ -0,0 +1,14 @@ +from common import * + +from trezor.messages import HelloWorldRequest +from apps.misc.hello_world import _get_text_from_msg + + +class TestHelloWorld(unittest.TestCase): + def test_get_text_from_msg(self): + msg = HelloWorldRequest(name="Satoshi", amount=2, show_display=False) + self.assertEqual(_get_text_from_msg(msg), "Hello Satoshi!\nHello Satoshi!\n") + + +if __name__ == "__main__": + unittest.main() diff --git a/legacy/firmware/protob/Makefile b/legacy/firmware/protob/Makefile index 06129b1d1..0df50ccdb 100644 --- a/legacy/firmware/protob/Makefile +++ b/legacy/firmware/protob/Makefile @@ -9,7 +9,8 @@ SKIPPED_MESSAGES := Binance Cardano DebugMonero Eos Monero Ontology Ripple SdPro EthereumSignTypedData EthereumTypedDataStructRequest EthereumTypedDataStructAck \ EthereumTypedDataValueRequest EthereumTypedDataValueAck ShowDeviceTutorial \ UnlockBootloader AuthenticateDevice AuthenticityProof \ - Solana StellarClaimClaimableBalanceOp + Solana StellarClaimClaimableBalanceOp \ + HelloWorldRequest HelloWorldResponse ifeq ($(BITCOIN_ONLY), 1) SKIPPED_MESSAGES += Ethereum NEM Stellar diff --git a/python/src/trezorlib/cli/hello_world.py b/python/src/trezorlib/cli/hello_world.py new file mode 100644 index 000000000..d27a18d7a --- /dev/null +++ b/python/src/trezorlib/cli/hello_world.py @@ -0,0 +1,28 @@ +from typing import TYPE_CHECKING, Optional + +import click + +from .. import hello_world +from . import with_client + +if TYPE_CHECKING: + from ..client import TrezorClient + + +@click.group(name="helloworld") +def cli() -> None: + """Hello world commands.""" + + +@cli.command() +@click.argument("name") +@click.option("-a", "--amount", type=int, help="How many times to greet.") +@click.option( + "-d", "--show-display", is_flag=True, help="Whether to show confirmation screen." +) +@with_client +def say_hello( + client: "TrezorClient", name: str, amount: Optional[int], show_display: bool +) -> str: + """Simply say hello to the supplied name.""" + return hello_world.say_hello(client, name, amount, show_display=show_display) diff --git a/python/src/trezorlib/cli/trezorctl.py b/python/src/trezorlib/cli/trezorctl.py index e00c965ae..2bab2dbe0 100755 --- a/python/src/trezorlib/cli/trezorctl.py +++ b/python/src/trezorlib/cli/trezorctl.py @@ -42,6 +42,7 @@ from . import ( ethereum, fido, firmware, + hello_world, monero, nem, ripple, @@ -407,6 +408,7 @@ cli.add_command(crypto.cli) cli.add_command(device.cli) cli.add_command(eos.cli) cli.add_command(ethereum.cli) +cli.add_command(hello_world.cli) cli.add_command(fido.cli) cli.add_command(monero.cli) cli.add_command(nem.cli) diff --git a/python/src/trezorlib/hello_world.py b/python/src/trezorlib/hello_world.py new file mode 100644 index 000000000..856a195cd --- /dev/null +++ b/python/src/trezorlib/hello_world.py @@ -0,0 +1,24 @@ +from typing import TYPE_CHECKING, Optional + +from . import messages +from .tools import expect + +if TYPE_CHECKING: + from .client import TrezorClient + from .protobuf import MessageType + + +@expect(messages.HelloWorldResponse, field="text", ret_type=str) +def say_hello( + client: "TrezorClient", + name: str, + amount: Optional[int], + show_display: bool, +) -> "MessageType": + return client.call( + messages.HelloWorldRequest( + name=name, + amount=amount, + show_display=show_display, + ) + ) diff --git a/python/src/trezorlib/messages.py b/python/src/trezorlib/messages.py index 23940e5ff..9971cc605 100644 --- a/python/src/trezorlib/messages.py +++ b/python/src/trezorlib/messages.py @@ -269,6 +269,8 @@ class MessageType(IntEnum): SolanaAddress = 903 SolanaSignTx = 904 SolanaTxSignature = 905 + HelloWorldRequest = 1000 + HelloWorldResponse = 1001 class FailureType(IntEnum): @@ -5211,6 +5213,40 @@ class EthereumAccessList(protobuf.MessageType): self.address = address +class HelloWorldRequest(protobuf.MessageType): + MESSAGE_WIRE_TYPE = 1000 + FIELDS = { + 1: protobuf.Field("name", "string", repeated=False, required=True), + 2: protobuf.Field("amount", "uint32", repeated=False, required=False, default=1), + 3: protobuf.Field("show_display", "bool", repeated=False, required=False, default=None), + } + + def __init__( + self, + *, + name: "str", + amount: Optional["int"] = 1, + show_display: Optional["bool"] = None, + ) -> None: + self.name = name + self.amount = amount + self.show_display = show_display + + +class HelloWorldResponse(protobuf.MessageType): + MESSAGE_WIRE_TYPE = 1001 + FIELDS = { + 1: protobuf.Field("text", "string", repeated=False, required=True), + } + + def __init__( + self, + *, + text: "str", + ) -> None: + self.text = text + + class MoneroTransactionSourceEntry(protobuf.MessageType): MESSAGE_WIRE_TYPE = None FIELDS = { diff --git a/rust/trezor-client/src/messages/generated.rs b/rust/trezor-client/src/messages/generated.rs index 6fd14de9f..68c3045ff 100644 --- a/rust/trezor-client/src/messages/generated.rs +++ b/rust/trezor-client/src/messages/generated.rs @@ -246,6 +246,8 @@ trezor_message_impl! { SolanaAddress => MessageType_SolanaAddress, SolanaSignTx => MessageType_SolanaSignTx, SolanaTxSignature => MessageType_SolanaTxSignature, + HelloWorldRequest => MessageType_HelloWorldRequest, + HelloWorldResponse => MessageType_HelloWorldResponse, } #[cfg(feature = "stellar")] diff --git a/rust/trezor-client/src/protos/generated/messages.rs b/rust/trezor-client/src/protos/generated/messages.rs index 962a88de5..0a0203b79 100644 --- a/rust/trezor-client/src/protos/generated/messages.rs +++ b/rust/trezor-client/src/protos/generated/messages.rs @@ -508,6 +508,10 @@ pub enum MessageType { MessageType_SolanaSignTx = 904, // @@protoc_insertion_point(enum_value:hw.trezor.messages.MessageType.MessageType_SolanaTxSignature) MessageType_SolanaTxSignature = 905, + // @@protoc_insertion_point(enum_value:hw.trezor.messages.MessageType.MessageType_HelloWorldRequest) + MessageType_HelloWorldRequest = 1000, + // @@protoc_insertion_point(enum_value:hw.trezor.messages.MessageType.MessageType_HelloWorldResponse) + MessageType_HelloWorldResponse = 1001, } impl ::protobuf::Enum for MessageType { @@ -759,6 +763,8 @@ impl ::protobuf::Enum for MessageType { 903 => ::std::option::Option::Some(MessageType::MessageType_SolanaAddress), 904 => ::std::option::Option::Some(MessageType::MessageType_SolanaSignTx), 905 => ::std::option::Option::Some(MessageType::MessageType_SolanaTxSignature), + 1000 => ::std::option::Option::Some(MessageType::MessageType_HelloWorldRequest), + 1001 => ::std::option::Option::Some(MessageType::MessageType_HelloWorldResponse), _ => ::std::option::Option::None } } @@ -1005,6 +1011,8 @@ impl ::protobuf::Enum for MessageType { "MessageType_SolanaAddress" => ::std::option::Option::Some(MessageType::MessageType_SolanaAddress), "MessageType_SolanaSignTx" => ::std::option::Option::Some(MessageType::MessageType_SolanaSignTx), "MessageType_SolanaTxSignature" => ::std::option::Option::Some(MessageType::MessageType_SolanaTxSignature), + "MessageType_HelloWorldRequest" => ::std::option::Option::Some(MessageType::MessageType_HelloWorldRequest), + "MessageType_HelloWorldResponse" => ::std::option::Option::Some(MessageType::MessageType_HelloWorldResponse), _ => ::std::option::Option::None } } @@ -1250,6 +1258,8 @@ impl ::protobuf::Enum for MessageType { MessageType::MessageType_SolanaAddress, MessageType::MessageType_SolanaSignTx, MessageType::MessageType_SolanaTxSignature, + MessageType::MessageType_HelloWorldRequest, + MessageType::MessageType_HelloWorldResponse, ]; } @@ -1501,6 +1511,8 @@ impl ::protobuf::EnumFull for MessageType { MessageType::MessageType_SolanaAddress => 237, MessageType::MessageType_SolanaSignTx => 238, MessageType::MessageType_SolanaTxSignature => 239, + MessageType::MessageType_HelloWorldRequest => 240, + MessageType::MessageType_HelloWorldResponse => 241, }; Self::enum_descriptor().value_by_index(index) } @@ -1550,7 +1562,7 @@ pub mod exts { static file_descriptor_proto_data: &'static [u8] = b"\ \n\x0emessages.proto\x12\x12hw.trezor.messages\x1a\x20google/protobuf/de\ - scriptor.proto*\x8bS\n\x0bMessageType\x12(\n\x16MessageType_Initialize\ + scriptor.proto*\xe0S\n\x0bMessageType\x12(\n\x16MessageType_Initialize\ \x10\0\x1a\x0c\x80\xa6\x1d\x01\xb0\xb5\x18\x01\x90\xb5\x18\x01\x12\x1e\n\ \x10MessageType_Ping\x10\x01\x1a\x08\x80\xa6\x1d\x01\x90\xb5\x18\x01\x12\ %\n\x13MessageType_Success\x10\x02\x1a\x0c\x80\xa6\x1d\x01\xa8\xb5\x18\ @@ -1821,30 +1833,32 @@ static file_descriptor_proto_data: &'static [u8] = b"\ \x07\x1a\x04\x90\xb5\x18\x01\x12$\n\x19MessageType_SolanaAddress\x10\x87\ \x07\x1a\x04\x98\xb5\x18\x01\x12#\n\x18MessageType_SolanaSignTx\x10\x88\ \x07\x1a\x04\x90\xb5\x18\x01\x12(\n\x1dMessageType_SolanaTxSignature\x10\ - \x89\x07\x1a\x04\x98\xb5\x18\x01\x1a\x04\xc8\xf3\x18\x01\"\x04\x08Z\x10\ - \\\"\x04\x08r\x10z\"\x06\x08\xdb\x01\x10\xdb\x01\"\x06\x08\xe0\x01\x10\ - \xe0\x01\"\x06\x08\xac\x02\x10\xb0\x02\"\x06\x08\xb5\x02\x10\xb8\x02:<\n\ - \x07wire_in\x18\xd2\x86\x03\x20\x01(\x08\x12!.google.protobuf.EnumValueO\ - ptionsR\x06wireIn:>\n\x08wire_out\x18\xd3\x86\x03\x20\x01(\x08\x12!.goog\ - le.protobuf.EnumValueOptionsR\x07wireOut:G\n\rwire_debug_in\x18\xd4\x86\ - \x03\x20\x01(\x08\x12!.google.protobuf.EnumValueOptionsR\x0bwireDebugIn:\ - I\n\x0ewire_debug_out\x18\xd5\x86\x03\x20\x01(\x08\x12!.google.protobuf.\ - EnumValueOptionsR\x0cwireDebugOut:@\n\twire_tiny\x18\xd6\x86\x03\x20\x01\ - (\x08\x12!.google.protobuf.EnumValueOptionsR\x08wireTiny:L\n\x0fwire_boo\ - tloader\x18\xd7\x86\x03\x20\x01(\x08\x12!.google.protobuf.EnumValueOptio\ - nsR\x0ewireBootloader:C\n\x0bwire_no_fsm\x18\xd8\x86\x03\x20\x01(\x08\ - \x12!.google.protobuf.EnumValueOptionsR\twireNoFsm:F\n\x0cbitcoin_only\ - \x18\xe0\xd4\x03\x20\x01(\x08\x12!.google.protobuf.EnumValueOptionsR\x0b\ - bitcoinOnly:U\n\x17has_bitcoin_only_values\x18\xb9\x8e\x03\x20\x01(\x08\ - \x12\x1c.google.protobuf.EnumOptionsR\x14hasBitcoinOnlyValues:T\n\x14exp\ - erimental_message\x18\xa1\x96\x03\x20\x01(\x08\x12\x1f.google.protobuf.M\ - essageOptionsR\x13experimentalMessage:>\n\twire_type\x18\xa2\x96\x03\x20\ - \x01(\r\x12\x1f.google.protobuf.MessageOptionsR\x08wireType:N\n\x12exper\ - imental_field\x18\x89\x9e\x03\x20\x01(\x08\x12\x1d.google.protobuf.Field\ - OptionsR\x11experimentalField:U\n\x17include_in_bitcoin_only\x18\xe0\xd4\ - \x03\x20\x01(\x08\x12\x1c.google.protobuf.FileOptionsR\x14includeInBitco\ - inOnlyB8\n#com.satoshilabs.trezor.lib.protobufB\rTrezorMessage\x80\xa6\ - \x1d\x01\ + \x89\x07\x1a\x04\x98\xb5\x18\x01\x12(\n\x1dMessageType_HelloWorldRequest\ + \x10\xe8\x07\x1a\x04\x90\xb5\x18\x01\x12)\n\x1eMessageType_HelloWorldRes\ + ponse\x10\xe9\x07\x1a\x04\x98\xb5\x18\x01\x1a\x04\xc8\xf3\x18\x01\"\x04\ + \x08Z\x10\\\"\x04\x08r\x10z\"\x06\x08\xdb\x01\x10\xdb\x01\"\x06\x08\xe0\ + \x01\x10\xe0\x01\"\x06\x08\xac\x02\x10\xb0\x02\"\x06\x08\xb5\x02\x10\xb8\ + \x02:<\n\x07wire_in\x18\xd2\x86\x03\x20\x01(\x08\x12!.google.protobuf.En\ + umValueOptionsR\x06wireIn:>\n\x08wire_out\x18\xd3\x86\x03\x20\x01(\x08\ + \x12!.google.protobuf.EnumValueOptionsR\x07wireOut:G\n\rwire_debug_in\ + \x18\xd4\x86\x03\x20\x01(\x08\x12!.google.protobuf.EnumValueOptionsR\x0b\ + wireDebugIn:I\n\x0ewire_debug_out\x18\xd5\x86\x03\x20\x01(\x08\x12!.goog\ + le.protobuf.EnumValueOptionsR\x0cwireDebugOut:@\n\twire_tiny\x18\xd6\x86\ + \x03\x20\x01(\x08\x12!.google.protobuf.EnumValueOptionsR\x08wireTiny:L\n\ + \x0fwire_bootloader\x18\xd7\x86\x03\x20\x01(\x08\x12!.google.protobuf.En\ + umValueOptionsR\x0ewireBootloader:C\n\x0bwire_no_fsm\x18\xd8\x86\x03\x20\ + \x01(\x08\x12!.google.protobuf.EnumValueOptionsR\twireNoFsm:F\n\x0cbitco\ + in_only\x18\xe0\xd4\x03\x20\x01(\x08\x12!.google.protobuf.EnumValueOptio\ + nsR\x0bbitcoinOnly:U\n\x17has_bitcoin_only_values\x18\xb9\x8e\x03\x20\ + \x01(\x08\x12\x1c.google.protobuf.EnumOptionsR\x14hasBitcoinOnlyValues:T\ + \n\x14experimental_message\x18\xa1\x96\x03\x20\x01(\x08\x12\x1f.google.p\ + rotobuf.MessageOptionsR\x13experimentalMessage:>\n\twire_type\x18\xa2\ + \x96\x03\x20\x01(\r\x12\x1f.google.protobuf.MessageOptionsR\x08wireType:\ + N\n\x12experimental_field\x18\x89\x9e\x03\x20\x01(\x08\x12\x1d.google.pr\ + otobuf.FieldOptionsR\x11experimentalField:U\n\x17include_in_bitcoin_only\ + \x18\xe0\xd4\x03\x20\x01(\x08\x12\x1c.google.protobuf.FileOptionsR\x14in\ + cludeInBitcoinOnlyB8\n#com.satoshilabs.trezor.lib.protobufB\rTrezorMessa\ + ge\x80\xa6\x1d\x01\ "; /// `FileDescriptorProto` object which was a source for this generated file diff --git a/rust/trezor-client/src/protos/generated/messages_hello.rs b/rust/trezor-client/src/protos/generated/messages_hello.rs new file mode 100644 index 000000000..d2810357f --- /dev/null +++ b/rust/trezor-client/src/protos/generated/messages_hello.rs @@ -0,0 +1,462 @@ +// This file is generated by rust-protobuf 3.3.0. Do not edit +// .proto file is parsed by protoc 3.19.6 +// @generated + +// https://github.com/rust-lang/rust-clippy/issues/702 +#![allow(unknown_lints)] +#![allow(clippy::all)] + +#![allow(unused_attributes)] +#![cfg_attr(rustfmt, rustfmt::skip)] + +#![allow(box_pointers)] +#![allow(dead_code)] +#![allow(missing_docs)] +#![allow(non_camel_case_types)] +#![allow(non_snake_case)] +#![allow(non_upper_case_globals)] +#![allow(trivial_casts)] +#![allow(unused_results)] +#![allow(unused_mut)] + +//! Generated file from `messages-hello.proto` + +/// Generated files are compatible only with the same version +/// of protobuf runtime. +const _PROTOBUF_VERSION_CHECK: () = ::protobuf::VERSION_3_3_0; + +// @@protoc_insertion_point(message:hw.trezor.messages.helloworld.HelloWorldRequest) +#[derive(PartialEq,Clone,Default,Debug)] +pub struct HelloWorldRequest { + // message fields + // @@protoc_insertion_point(field:hw.trezor.messages.helloworld.HelloWorldRequest.name) + pub name: ::std::option::Option<::std::string::String>, + // @@protoc_insertion_point(field:hw.trezor.messages.helloworld.HelloWorldRequest.amount) + pub amount: ::std::option::Option, + // @@protoc_insertion_point(field:hw.trezor.messages.helloworld.HelloWorldRequest.show_display) + pub show_display: ::std::option::Option, + // special fields + // @@protoc_insertion_point(special_field:hw.trezor.messages.helloworld.HelloWorldRequest.special_fields) + pub special_fields: ::protobuf::SpecialFields, +} + +impl<'a> ::std::default::Default for &'a HelloWorldRequest { + fn default() -> &'a HelloWorldRequest { + ::default_instance() + } +} + +impl HelloWorldRequest { + pub fn new() -> HelloWorldRequest { + ::std::default::Default::default() + } + + // required string name = 1; + + pub fn name(&self) -> &str { + match self.name.as_ref() { + Some(v) => v, + None => "", + } + } + + pub fn clear_name(&mut self) { + self.name = ::std::option::Option::None; + } + + pub fn has_name(&self) -> bool { + self.name.is_some() + } + + // Param is passed by value, moved + pub fn set_name(&mut self, v: ::std::string::String) { + self.name = ::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_name(&mut self) -> &mut ::std::string::String { + if self.name.is_none() { + self.name = ::std::option::Option::Some(::std::string::String::new()); + } + self.name.as_mut().unwrap() + } + + // Take field + pub fn take_name(&mut self) -> ::std::string::String { + self.name.take().unwrap_or_else(|| ::std::string::String::new()) + } + + // optional uint32 amount = 2; + + pub fn amount(&self) -> u32 { + self.amount.unwrap_or(1u32) + } + + pub fn clear_amount(&mut self) { + self.amount = ::std::option::Option::None; + } + + pub fn has_amount(&self) -> bool { + self.amount.is_some() + } + + // Param is passed by value, moved + pub fn set_amount(&mut self, v: u32) { + self.amount = ::std::option::Option::Some(v); + } + + // optional bool show_display = 3; + + pub fn show_display(&self) -> bool { + self.show_display.unwrap_or(false) + } + + pub fn clear_show_display(&mut self) { + self.show_display = ::std::option::Option::None; + } + + pub fn has_show_display(&self) -> bool { + self.show_display.is_some() + } + + // Param is passed by value, moved + pub fn set_show_display(&mut self, v: bool) { + self.show_display = ::std::option::Option::Some(v); + } + + fn generated_message_descriptor_data() -> ::protobuf::reflect::GeneratedMessageDescriptorData { + let mut fields = ::std::vec::Vec::with_capacity(3); + let mut oneofs = ::std::vec::Vec::with_capacity(0); + fields.push(::protobuf::reflect::rt::v2::make_option_accessor::<_, _>( + "name", + |m: &HelloWorldRequest| { &m.name }, + |m: &mut HelloWorldRequest| { &mut m.name }, + )); + fields.push(::protobuf::reflect::rt::v2::make_option_accessor::<_, _>( + "amount", + |m: &HelloWorldRequest| { &m.amount }, + |m: &mut HelloWorldRequest| { &mut m.amount }, + )); + fields.push(::protobuf::reflect::rt::v2::make_option_accessor::<_, _>( + "show_display", + |m: &HelloWorldRequest| { &m.show_display }, + |m: &mut HelloWorldRequest| { &mut m.show_display }, + )); + ::protobuf::reflect::GeneratedMessageDescriptorData::new_2::( + "HelloWorldRequest", + fields, + oneofs, + ) + } +} + +impl ::protobuf::Message for HelloWorldRequest { + const NAME: &'static str = "HelloWorldRequest"; + + fn is_initialized(&self) -> bool { + if self.name.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 { + 10 => { + self.name = ::std::option::Option::Some(is.read_string()?); + }, + 16 => { + self.amount = ::std::option::Option::Some(is.read_uint32()?); + }, + 24 => { + self.show_display = ::std::option::Option::Some(is.read_bool()?); + }, + 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.name.as_ref() { + my_size += ::protobuf::rt::string_size(1, &v); + } + if let Some(v) = self.amount { + my_size += ::protobuf::rt::uint32_size(2, v); + } + if let Some(v) = self.show_display { + my_size += 1 + 1; + } + 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.name.as_ref() { + os.write_string(1, v)?; + } + if let Some(v) = self.amount { + os.write_uint32(2, v)?; + } + if let Some(v) = self.show_display { + os.write_bool(3, 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() -> HelloWorldRequest { + HelloWorldRequest::new() + } + + fn clear(&mut self) { + self.name = ::std::option::Option::None; + self.amount = ::std::option::Option::None; + self.show_display = ::std::option::Option::None; + self.special_fields.clear(); + } + + fn default_instance() -> &'static HelloWorldRequest { + static instance: HelloWorldRequest = HelloWorldRequest { + name: ::std::option::Option::None, + amount: ::std::option::Option::None, + show_display: ::std::option::Option::None, + special_fields: ::protobuf::SpecialFields::new(), + }; + &instance + } +} + +impl ::protobuf::MessageFull for HelloWorldRequest { + fn descriptor() -> ::protobuf::reflect::MessageDescriptor { + static descriptor: ::protobuf::rt::Lazy<::protobuf::reflect::MessageDescriptor> = ::protobuf::rt::Lazy::new(); + descriptor.get(|| file_descriptor().message_by_package_relative_name("HelloWorldRequest").unwrap()).clone() + } +} + +impl ::std::fmt::Display for HelloWorldRequest { + fn fmt(&self, f: &mut ::std::fmt::Formatter<'_>) -> ::std::fmt::Result { + ::protobuf::text_format::fmt(self, f) + } +} + +impl ::protobuf::reflect::ProtobufValue for HelloWorldRequest { + type RuntimeType = ::protobuf::reflect::rt::RuntimeTypeMessage; +} + +// @@protoc_insertion_point(message:hw.trezor.messages.helloworld.HelloWorldResponse) +#[derive(PartialEq,Clone,Default,Debug)] +pub struct HelloWorldResponse { + // message fields + // @@protoc_insertion_point(field:hw.trezor.messages.helloworld.HelloWorldResponse.text) + pub text: ::std::option::Option<::std::string::String>, + // special fields + // @@protoc_insertion_point(special_field:hw.trezor.messages.helloworld.HelloWorldResponse.special_fields) + pub special_fields: ::protobuf::SpecialFields, +} + +impl<'a> ::std::default::Default for &'a HelloWorldResponse { + fn default() -> &'a HelloWorldResponse { + ::default_instance() + } +} + +impl HelloWorldResponse { + pub fn new() -> HelloWorldResponse { + ::std::default::Default::default() + } + + // required string text = 1; + + pub fn text(&self) -> &str { + match self.text.as_ref() { + Some(v) => v, + None => "", + } + } + + pub fn clear_text(&mut self) { + self.text = ::std::option::Option::None; + } + + pub fn has_text(&self) -> bool { + self.text.is_some() + } + + // Param is passed by value, moved + pub fn set_text(&mut self, v: ::std::string::String) { + self.text = ::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_text(&mut self) -> &mut ::std::string::String { + if self.text.is_none() { + self.text = ::std::option::Option::Some(::std::string::String::new()); + } + self.text.as_mut().unwrap() + } + + // Take field + pub fn take_text(&mut self) -> ::std::string::String { + self.text.take().unwrap_or_else(|| ::std::string::String::new()) + } + + fn generated_message_descriptor_data() -> ::protobuf::reflect::GeneratedMessageDescriptorData { + let mut fields = ::std::vec::Vec::with_capacity(1); + let mut oneofs = ::std::vec::Vec::with_capacity(0); + fields.push(::protobuf::reflect::rt::v2::make_option_accessor::<_, _>( + "text", + |m: &HelloWorldResponse| { &m.text }, + |m: &mut HelloWorldResponse| { &mut m.text }, + )); + ::protobuf::reflect::GeneratedMessageDescriptorData::new_2::( + "HelloWorldResponse", + fields, + oneofs, + ) + } +} + +impl ::protobuf::Message for HelloWorldResponse { + const NAME: &'static str = "HelloWorldResponse"; + + fn is_initialized(&self) -> bool { + if self.text.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 { + 10 => { + self.text = ::std::option::Option::Some(is.read_string()?); + }, + 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.text.as_ref() { + my_size += ::protobuf::rt::string_size(1, &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.text.as_ref() { + os.write_string(1, 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() -> HelloWorldResponse { + HelloWorldResponse::new() + } + + fn clear(&mut self) { + self.text = ::std::option::Option::None; + self.special_fields.clear(); + } + + fn default_instance() -> &'static HelloWorldResponse { + static instance: HelloWorldResponse = HelloWorldResponse { + text: ::std::option::Option::None, + special_fields: ::protobuf::SpecialFields::new(), + }; + &instance + } +} + +impl ::protobuf::MessageFull for HelloWorldResponse { + fn descriptor() -> ::protobuf::reflect::MessageDescriptor { + static descriptor: ::protobuf::rt::Lazy<::protobuf::reflect::MessageDescriptor> = ::protobuf::rt::Lazy::new(); + descriptor.get(|| file_descriptor().message_by_package_relative_name("HelloWorldResponse").unwrap()).clone() + } +} + +impl ::std::fmt::Display for HelloWorldResponse { + fn fmt(&self, f: &mut ::std::fmt::Formatter<'_>) -> ::std::fmt::Result { + ::protobuf::text_format::fmt(self, f) + } +} + +impl ::protobuf::reflect::ProtobufValue for HelloWorldResponse { + type RuntimeType = ::protobuf::reflect::rt::RuntimeTypeMessage; +} + +static file_descriptor_proto_data: &'static [u8] = b"\ + \n\x14messages-hello.proto\x12\x1dhw.trezor.messages.helloworld\x1a\x0em\ + essages.proto\"e\n\x11HelloWorldRequest\x12\x12\n\x04name\x18\x01\x20\ + \x02(\tR\x04name\x12\x19\n\x06amount\x18\x02\x20\x01(\r:\x011R\x06amount\ + \x12!\n\x0cshow_display\x18\x03\x20\x01(\x08R\x0bshowDisplay\"(\n\x12Hel\ + loWorldResponse\x12\x12\n\x04text\x18\x01\x20\x02(\tR\x04textB>\n#com.sa\ + toshilabs.trezor.lib.protobufB\x17TrezorMessageHelloWorld\ +"; + +/// `FileDescriptorProto` object which was a source for this generated file +fn file_descriptor_proto() -> &'static ::protobuf::descriptor::FileDescriptorProto { + static file_descriptor_proto_lazy: ::protobuf::rt::Lazy<::protobuf::descriptor::FileDescriptorProto> = ::protobuf::rt::Lazy::new(); + file_descriptor_proto_lazy.get(|| { + ::protobuf::Message::parse_from_bytes(file_descriptor_proto_data).unwrap() + }) +} + +/// `FileDescriptor` object which allows dynamic access to files +pub fn file_descriptor() -> &'static ::protobuf::reflect::FileDescriptor { + static generated_file_descriptor_lazy: ::protobuf::rt::Lazy<::protobuf::reflect::GeneratedFileDescriptor> = ::protobuf::rt::Lazy::new(); + static file_descriptor: ::protobuf::rt::Lazy<::protobuf::reflect::FileDescriptor> = ::protobuf::rt::Lazy::new(); + file_descriptor.get(|| { + let generated_file_descriptor = generated_file_descriptor_lazy.get(|| { + let mut deps = ::std::vec::Vec::with_capacity(1); + deps.push(super::messages::file_descriptor().clone()); + let mut messages = ::std::vec::Vec::with_capacity(2); + messages.push(HelloWorldRequest::generated_message_descriptor_data()); + messages.push(HelloWorldResponse::generated_message_descriptor_data()); + let mut enums = ::std::vec::Vec::with_capacity(0); + ::protobuf::reflect::GeneratedFileDescriptor::new_generated( + file_descriptor_proto(), + deps, + messages, + enums, + ) + }); + ::protobuf::reflect::FileDescriptor::new_generated_2(generated_file_descriptor) + }) +} diff --git a/tests/device_tests/misc/test_hello_world.py b/tests/device_tests/misc/test_hello_world.py new file mode 100644 index 000000000..ede1ee594 --- /dev/null +++ b/tests/device_tests/misc/test_hello_world.py @@ -0,0 +1,43 @@ +# This file is part of the Trezor project. +# +# Copyright (C) 2012-2019 SatoshiLabs and contributors +# +# This library is free software: you can redistribute it and/or modify +# it under the terms of the GNU Lesser General Public License version 3 +# as published by the Free Software Foundation. +# +# This library is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU Lesser General Public License for more details. +# +# You should have received a copy of the License along with this library. +# If not, see . + +from typing import Optional + +import pytest + +from trezorlib import hello_world +from trezorlib.debuglink import TrezorClientDebugLink as Client + +VECTORS = ( # name, amount, show_display + ("George", 2, True), + ("John", 3, False), + ("Hannah", None, False), +) + + +@pytest.mark.skip_t1 +@pytest.mark.parametrize("name, amount, show_display", VECTORS) +def test_hello_world( + client: Client, name: str, amount: Optional[int], show_display: bool +): + with client: + greeting_text = hello_world.say_hello( + client, name=name, amount=amount, show_display=show_display + ) + greeting_lines = greeting_text.strip().splitlines() + + assert len(greeting_lines) == amount or 1 + assert all(name in line for line in greeting_lines) diff --git a/tests/ui_tests/fixtures.json b/tests/ui_tests/fixtures.json index 217c1ce5c..24bcfe25c 100644 --- a/tests/ui_tests/fixtures.json +++ b/tests/ui_tests/fixtures.json @@ -3139,6 +3139,9 @@ "TT_misc-test_cosi.py::test_slip26_paths[\\x00-3]": "2cbaa2088776f1c7c735aa1ef767d33f8ad8ebdb592b6d9814dd1bbabd6da9b5", "TT_misc-test_cosi.py::test_slip26_paths[\\xfe\\xfe\\xfe\\xfe-0]": "58a16c31957f7d540da34a30f54631e607eca1af6efb27a0b3877e49f77a9d56", "TT_misc-test_cosi.py::test_slip26_paths[dog-0]": "7cee26436a0025a56eb1f67e432e4e707857714c1bbf5f61df60cc20f54c84ab", +"TT_misc-test_hello_world.py::test_hello_world[George-2-True]": "061e096ed3b47be216f4c7eb01999b4ec8bace1e3608a0de1fc128747b28a060", +"TT_misc-test_hello_world.py::test_hello_world[Hannah-None-False]": "80a6e289138a604cf351a29511cf6f85e2243591317894703152787e1351a1a3", +"TT_misc-test_hello_world.py::test_hello_world[John-3-False]": "80a6e289138a604cf351a29511cf6f85e2243591317894703152787e1351a1a3", "TT_misc-test_msg_cipherkeyvalue.py::test_decrypt": "b34ae9ac7b3ea7467afe774bf615ca1e1eab26c64fe5d25178071bf15e8d6518", "TT_misc-test_msg_cipherkeyvalue.py::test_decrypt_badlen": "80a6e289138a604cf351a29511cf6f85e2243591317894703152787e1351a1a3", "TT_misc-test_msg_cipherkeyvalue.py::test_encrypt": "648e45403ce412314e9d91625ace8ffdee52ff37ac99b13f4e86d018a024515d",