Monero
transport.hpp
Go to the documentation of this file.
1 // Copyright (c) 2017-2022, The Monero Project
2 //
3 // All rights reserved.
4 //
5 // Redistribution and use in source and binary forms, with or without modification, are
6 // permitted provided that the following conditions are met:
7 //
8 // 1. Redistributions of source code must retain the above copyright notice, this list of
9 // conditions and the following disclaimer.
10 //
11 // 2. Redistributions in binary form must reproduce the above copyright notice, this list
12 // of conditions and the following disclaimer in the documentation and/or other
13 // materials provided with the distribution.
14 //
15 // 3. Neither the name of the copyright holder nor the names of its contributors may be
16 // used to endorse or promote products derived from this software without specific
17 // prior written permission.
18 //
19 // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY
20 // EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
21 // MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL
22 // THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
23 // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
24 // PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
25 // INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
26 // STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF
27 // THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
28 //
29 
30 #ifndef MONERO_TRANSPORT_H
31 #define MONERO_TRANSPORT_H
32 
33 
34 #include <boost/asio.hpp>
35 #include <boost/asio/deadline_timer.hpp>
36 #include <boost/array.hpp>
37 #include <boost/utility/string_ref.hpp>
38 
39 #include <typeinfo>
40 #include <type_traits>
41 #include "net/http_client.h"
42 
43 #include "rapidjson/document.h"
44 #include "rapidjson/writer.h"
45 #include "rapidjson/stringbuffer.h"
46 
47 #include "exceptions.hpp"
48 #include "trezor_defs.hpp"
49 #include "messages_map.hpp"
50 
51 #include "messages/messages.pb.h"
52 #include "messages/messages-common.pb.h"
53 #include "messages/messages-management.pb.h"
54 #include "messages/messages-monero.pb.h"
55 
56 namespace hw {
57 namespace trezor {
58 
61  namespace http = epee::net_utils::http;
62 
63  const std::string DEFAULT_BRIDGE = "127.0.0.1:21325";
64 
65  uint64_t pack_version(uint32_t major, uint32_t minor=0, uint32_t patch=0);
66 
67  // Base HTTP comm serialization.
68  bool t_serialize(const std::string & in, std::string & out);
69  bool t_serialize(const epee::wipeable_string & in, std::string & out);
70  bool t_serialize(const json_val & in, std::string & out);
71  std::string t_serialize(const json_val & in);
72 
73  bool t_deserialize(const std::string & in, std::string & out);
75  bool t_deserialize(const std::string & in, json & out);
76 
77  // Flexible json serialization. HTTP client tailored for bridge API
78  template<class t_req, class t_res, class t_transport>
79  bool invoke_bridge_http(const boost::string_ref uri, const t_req & out_struct, t_res & result_struct, t_transport& transport, const boost::string_ref method = "POST", std::chrono::milliseconds timeout = std::chrono::seconds(180))
80  {
81  std::string req_param;
82  t_serialize(out_struct, req_param);
83 
84  http::fields_list additional_params;
85  additional_params.push_back(std::make_pair("Origin","https://monero.trezor.io"));
86  additional_params.push_back(std::make_pair("Content-Type","application/json; charset=utf-8"));
87 
88  const http::http_response_info* pri = nullptr;
89  const auto data_cleaner = epee::misc_utils::create_scope_leave_handler([&]() {
90  if (!req_param.empty()) {
91  memwipe(&req_param[0], req_param.size());
92  }
93  transport.wipe_response();
94  });
95 
96  if(!transport.invoke(uri, method, req_param, timeout, &pri, std::move(additional_params)))
97  {
98  MERROR("Failed to invoke http request to " << uri);
99  return false;
100  }
101 
102  if(!pri)
103  {
104  MERROR("Failed to invoke http request to " << uri << ", internal error (null response ptr)");
105  return false;
106  }
107 
108  if(pri->m_response_code != 200)
109  {
110  MERROR("Failed to invoke http request to " << uri << ", wrong response code: " << pri->m_response_code
111  << " Response Body: " << pri->m_body);
112  return false;
113  }
114 
115  return t_deserialize(const_cast<http::http_response_info*>(pri)->m_body, result_struct);
116  }
117 
118  // Forward decl
119  class Transport;
120  class Protocol;
121 
122  // Communication protocol
123  class Protocol {
124  public:
125  Protocol() = default;
126  virtual ~Protocol() = default;
127  virtual void session_begin(Transport & transport){ };
128  virtual void session_end(Transport & transport){ };
129  virtual void write(Transport & transport, const google::protobuf::Message & req)= 0;
130  virtual void read(Transport & transport, std::shared_ptr<google::protobuf::Message> & msg, messages::MessageType * msg_type=nullptr)= 0;
131  };
132 
133  class ProtocolV1 : public Protocol {
134  public:
135  ProtocolV1() = default;
136  virtual ~ProtocolV1() = default;
137 
138  void write(Transport & transport, const google::protobuf::Message & req) override;
139  void read(Transport & transport, std::shared_ptr<google::protobuf::Message> & msg, messages::MessageType * msg_type=nullptr) override;
140  };
141 
142 
143  // Base transport
144  typedef std::vector<std::shared_ptr<Transport>> t_transport_vect;
145 
146  class Transport {
147  public:
148  Transport();
149  virtual ~Transport() = default;
150 
151  virtual bool ping() { return false; };
152  virtual std::string get_path() const { return ""; };
153  virtual void enumerate(t_transport_vect & res){};
154  virtual void open(){};
155  virtual void close(){};
156  virtual void write(const google::protobuf::Message & req) =0;
157  virtual void read(std::shared_ptr<google::protobuf::Message> & msg, messages::MessageType * msg_type=nullptr) =0;
158  virtual std::shared_ptr<Transport> find_debug() { return nullptr; };
159 
160  virtual void write_chunk(const void * buff, size_t size) { };
161  virtual size_t read_chunk(void * buff, size_t size) { return 0; };
162  virtual std::ostream& dump(std::ostream& o) const { return o << "Transport<>"; }
163  protected:
165 
166  virtual bool pre_open();
167  virtual bool pre_close();
168  };
169 
170  // Bridge transport
171  class BridgeTransport : public Transport {
172  public:
174  boost::optional<std::string> device_path = boost::none,
175  boost::optional<std::string> bridge_host = boost::none);
176 
177  virtual ~BridgeTransport() = default;
178 
179  static const char * PATH_PREFIX;
180 
181  std::string get_path() const override;
182  void enumerate(t_transport_vect & res) override;
183 
184  void open() override;
185  void close() override;
186 
187  void write(const google::protobuf::Message &req) override;
188  void read(std::shared_ptr<google::protobuf::Message> & msg, messages::MessageType * msg_type=nullptr) override;
189 
190  const boost::optional<json> & device_info() const;
191  std::ostream& dump(std::ostream& o) const override;
192 
193  private:
196  boost::optional<std::string> m_device_path;
197  boost::optional<std::string> m_session;
198  boost::optional<epee::wipeable_string> m_response;
199  boost::optional<json> m_device_info;
200  };
201 
202  // UdpTransport transport
203  using boost::asio::ip::udp;
204 
205  class UdpTransport : public Transport {
206  public:
207 
208  explicit UdpTransport(
209  boost::optional<std::string> device_path=boost::none,
210  boost::optional<std::shared_ptr<Protocol>> proto=boost::none);
211 
212  virtual ~UdpTransport() = default;
213 
214  static const char * PATH_PREFIX;
215  static const char * DEFAULT_HOST;
216  static const int DEFAULT_PORT;
217 
218  bool ping() override;
219  std::string get_path() const override;
220  void enumerate(t_transport_vect & res) override;
221 
222  void open() override;
223  void close() override;
224  std::shared_ptr<Transport> find_debug() override;
225 
226  void write(const google::protobuf::Message &req) override;
227  void read(std::shared_ptr<google::protobuf::Message> & msg, messages::MessageType * msg_type=nullptr) override;
228 
229  void write_chunk(const void * buff, size_t size) override;
230  size_t read_chunk(void * buff, size_t size) override;
231 
232  std::ostream& dump(std::ostream& o) const override;
233 
234  private:
235  void require_socket();
236  ssize_t receive(void * buff, size_t size, boost::system::error_code * error_code=nullptr, bool no_throw=false, boost::posix_time::time_duration timeout=boost::posix_time::seconds(10));
237  void check_deadline();
238  static void handle_receive(const boost::system::error_code& ec, std::size_t length,
239  boost::system::error_code* out_ec, std::size_t* out_length);
240  bool ping_int(boost::posix_time::time_duration timeout=boost::posix_time::milliseconds(1500));
241 
242  std::shared_ptr<Protocol> m_proto;
245 
246  std::unique_ptr<udp::socket> m_socket;
247  boost::asio::io_context m_io_service;
248  boost::asio::deadline_timer m_deadline;
249  udp::endpoint m_endpoint;
250  };
251 
252 #ifdef WITH_DEVICE_TREZOR_WEBUSB
253 #include <libusb.h>
254 
255  class WebUsbTransport : public Transport {
256  public:
257 
258  explicit WebUsbTransport(
259  boost::optional<libusb_device_descriptor*> descriptor = boost::none,
260  boost::optional<std::shared_ptr<Protocol>> proto = boost::none
261  );
262 
263  virtual ~WebUsbTransport();
264 
265  static const char * PATH_PREFIX;
266 
267  std::string get_path() const override;
268  void enumerate(t_transport_vect & res) override;
269 
270  void open() override;
271  void close() override;
272  std::shared_ptr<Transport> find_debug() override;
273 
274  void write(const google::protobuf::Message &req) override;
275  void read(std::shared_ptr<google::protobuf::Message> & msg, messages::MessageType * msg_type=nullptr) override;
276 
277  void write_chunk(const void * buff, size_t size) override;
278  size_t read_chunk(void * buff, size_t size) override;
279 
280  std::ostream& dump(std::ostream& o) const override;
281 
282  private:
283  void require_device() const;
284  void require_connected() const;
285  int get_interface() const;
286  unsigned char get_endpoint() const;
287 
288  std::shared_ptr<Protocol> m_proto;
289 
290  libusb_context *m_usb_session;
291  libusb_device *m_usb_device;
292  libusb_device_handle *m_usb_device_handle;
293  std::unique_ptr<libusb_device_descriptor> m_usb_device_desc;
294  std::vector<uint8_t> m_port_numbers;
295  int m_bus_id;
296  int m_device_addr;
297 
298 #ifdef WITH_TREZOR_DEBUGGING
299  bool m_debug_mode;
300 #endif
301  };
302 
303 #endif
304 
305  //
306  // General helpers
307  //
308 
313 
318 
322  std::shared_ptr<Transport> transport(const std::string & path);
323 
327  template<class t_transport=Transport>
328  std::shared_ptr<t_transport> transport_typed(const std::string & path){
329  auto t = transport(path);
330  if (!t){
331  return nullptr;
332  }
333 
334  return std::dynamic_pointer_cast<t_transport>(t);
335  }
336 
337  // Exception carries unexpected message being received
338  namespace exc {
340  protected:
341  hw::trezor::messages::MessageType recvType;
342  std::shared_ptr<google::protobuf::Message> recvMsg;
343 
344  public:
346  UnexpectedMessageException(): ProtocolException("Trezor returned unexpected message") {};
347  UnexpectedMessageException(hw::trezor::messages::MessageType recvType,
348  const std::shared_ptr<google::protobuf::Message> & recvMsg)
350  reason = std::string("Trezor returned unexpected message: ") + std::to_string(recvType);
351  }
352  };
353  }
354 
358  [[ noreturn ]] void throw_failure_exception(const messages::common::Failure * failure);
359 
364  public:
366  GenericMessage(messages::MessageType m_type, const std::shared_ptr<google::protobuf::Message> &m_msg);
367  bool empty() const { return m_empty; }
368 
369  hw::trezor::messages::MessageType m_type;
370  std::shared_ptr<google::protobuf::Message> m_msg;
371  bool m_empty;
372  };
373 
380  template<class t_message=google::protobuf::Message>
381  std::shared_ptr<t_message>
382  exchange_message(Transport & transport, const google::protobuf::Message & req,
383  boost::optional<messages::MessageType> resp_type = boost::none)
384  {
385  // Require strictly protocol buffers response in the template.
387 
388  // Write the request
389  transport.write(req);
390 
391  // Read the response
392  std::shared_ptr<google::protobuf::Message> msg_resp;
393  hw::trezor::messages::MessageType msg_resp_type;
394  transport.read(msg_resp, &msg_resp_type);
395 
396  // Determine type of expected message response
397  messages::MessageType required_type = resp_type ? resp_type.get() : MessageMapper::get_message_wire_number<t_message>();
398 
399  if (msg_resp_type == required_type) {
400  return message_ptr_retype<t_message>(msg_resp);
401  } else if (msg_resp_type == messages::MessageType_Failure){
402  throw_failure_exception(dynamic_cast<messages::common::Failure*>(msg_resp.get()));
403  } else {
404  throw exc::UnexpectedMessageException(msg_resp_type, msg_resp);
405  }
406  }
407 
408  std::ostream& operator<<(std::ostream& o, hw::trezor::Transport const& t);
409  std::ostream& operator<<(std::ostream& o, std::shared_ptr<hw::trezor::Transport> const& t);
410 }}
411 
412 
413 #endif //MONERO_TRANSPORT_H
const char * res
Definition: hmac_keccak.cpp:42
bool ping() override
Definition: transport.cpp:569
std::shared_ptr< google::protobuf::Message > recvMsg
Definition: transport.hpp:342
const std::string DEFAULT_BRIDGE
Definition: transport.hpp:63
static const char * PATH_PREFIX
Definition: transport.hpp:179
boost::optional< epee::wipeable_string > m_response
Definition: transport.hpp:198
void require_socket()
Definition: transport.cpp:563
void enumerate(t_transport_vect &res)
Definition: transport.cpp:1171
std::string m_bridge_host
Definition: transport.hpp:195
std::list< std::pair< std::string, std::string > > fields_list
Definition: http_base.h:66
UdpTransport(boost::optional< std::string > device_path=boost::none, boost::optional< std::shared_ptr< Protocol >> proto=boost::none)
Definition: transport.cpp:533
void enumerate(t_transport_vect &res) override
Definition: transport.cpp:594
std::ostream & dump(std::ostream &o) const override
Definition: transport.cpp:793
rapidjson::Value json_val
Definition: transport.hpp:60
virtual void write(const google::protobuf::Message &req)=0
void dump(const char *buffer, uint64_t count, const char *name)
Definition: utility.hpp:75
ssize_t receive(void *buff, size_t size, boost::system::error_code *error_code=nullptr, bool no_throw=false, boost::posix_time::time_duration timeout=boost::posix_time::seconds(10))
Definition: transport.cpp:703
std::shared_ptr< t_message > exchange_message(Transport &transport, const google::protobuf::Message &req, boost::optional< messages::MessageType > resp_type=boost::none)
Definition: transport.hpp:382
std::ostream & dump(std::ostream &o) const override
Definition: transport.cpp:503
rapidjson::Document json
Definition: transport.hpp:59
bool t_serialize(const std::string &in, std::string &out)
Definition: transport.cpp:55
Definition: transport.hpp:171
long m_open_counter
Definition: transport.hpp:164
::std::string string
Definition: gtest-port.h:1097
static const int DEFAULT_PORT
Definition: transport.hpp:216
auto_scope_leave_caller create_scope_leave_handler(t_scope_leave_handler f)
Definition: misc_language.h:97
void read(std::shared_ptr< google::protobuf::Message > &msg, messages::MessageType *msg_type=nullptr) override
Definition: transport.cpp:756
void close() override
Definition: transport.cpp:628
static const char * PATH_PREFIX
Definition: transport.hpp:214
t
Definition: console.py:33
string proto
Definition: pymoduletest.py:71
virtual void enumerate(t_transport_vect &res)
Definition: transport.hpp:153
boost::optional< json > m_device_info
Definition: transport.hpp:199
virtual bool pre_open()
Definition: transport.cpp:301
std::unique_ptr< udp::socket > m_socket
Definition: transport.hpp:246
virtual void close()
Definition: transport.hpp:155
void read(Transport &transport, std::shared_ptr< google::protobuf::Message > &msg, messages::MessageType *msg_type=nullptr) override
Definition: transport.cpp:243
virtual void write(Transport &transport, const google::protobuf::Message &req)=0
void enumerate(t_transport_vect &res) override
Definition: transport.cpp:369
virtual std::ostream & dump(std::ostream &o) const
Definition: transport.hpp:162
int m_device_port
Definition: transport.hpp:244
Definition: abstract_http_client.h:59
Definition: transport.hpp:146
virtual ~ProtocolV1()=default
Definition: transport.hpp:205
virtual ~BridgeTransport()=default
virtual void read(std::shared_ptr< google::protobuf::Message > &msg, messages::MessageType *msg_type=nullptr)=0
bool m_empty
Definition: transport.hpp:371
std::shared_ptr< Protocol > m_proto
Definition: transport.hpp:242
void open() override
Definition: transport.cpp:610
const boost::optional< json > & device_info() const
Definition: transport.cpp:499
void write(Transport &transport, const google::protobuf::Message &req) override
Definition: transport.cpp:206
BridgeTransport(boost::optional< std::string > device_path=boost::none, boost::optional< std::string > bridge_host=boost::none)
Definition: transport.cpp:337
std::shared_ptr< t_transport > transport_typed(const std::string &path)
Definition: transport.hpp:328
std::string get_path() const override
Definition: transport.cpp:360
static void close()
Definition: blockchain_blackball.cpp:279
boost::optional< std::string > m_device_path
Definition: transport.hpp:196
GenericValue< UTF8<> > Value
GenericValue with UTF8 encoding.
Definition: document.h:2116
unsigned int uint32_t
Definition: stdint.h:126
std::shared_ptr< Transport > find_debug() override
Definition: transport.cpp:643
bool empty() const
Definition: transport.hpp:367
bool invoke_bridge_http(const boost::string_ref uri, const t_req &out_struct, t_res &result_struct, t_transport &transport, const boost::string_ref method="POST", std::chrono::milliseconds timeout=std::chrono::seconds(180))
Definition: transport.hpp:79
void write(const google::protobuf::Message &req) override
Definition: transport.cpp:752
unsigned __int64 uint64_t
Definition: stdint.h:136
UnexpectedMessageException(hw::trezor::messages::MessageType recvType, const std::shared_ptr< google::protobuf::Message > &recvMsg)
Definition: transport.hpp:347
GenericDocument< UTF8<> > Document
GenericDocument with UTF8 encoding.
Definition: document.h:2512
virtual std::shared_ptr< Transport > find_debug()
Definition: transport.hpp:158
Definition: device.cpp:38
GenericMessage()
Definition: transport.hpp:365
virtual void session_end(Transport &transport)
Definition: transport.hpp:128
int m_response_code
Definition: http_base.h:164
hw::trezor::messages::MessageType recvType
Definition: transport.hpp:341
virtual ~Protocol()=default
virtual void session_begin(Transport &transport)
Definition: transport.hpp:127
virtual void write_chunk(const void *buff, size_t size)
Definition: transport.hpp:160
virtual bool pre_close()
Definition: transport.cpp:317
void throw_failure_exception(const messages::common::Failure *failure)
Definition: transport.cpp:1244
void sort_transports_by_env(t_transport_vect &res)
Definition: transport.cpp:1198
virtual void read(Transport &transport, std::shared_ptr< google::protobuf::Message > &msg, messages::MessageType *msg_type=nullptr)=0
uint64_t pack_version(uint32_t major, uint32_t minor, uint32_t patch)
Definition: transport.cpp:100
bool t_deserialize(const std::string &in, std::string &out)
Definition: transport.cpp:79
Definition: exceptions.hpp:115
boost::asio::deadline_timer m_deadline
Definition: transport.hpp:248
void write_chunk(const void *buff, size_t size) override
Definition: transport.cpp:656
boost::optional< std::string > m_session
Definition: transport.hpp:197
virtual ~UdpTransport()=default
boost::asio::io_context m_io_service
Definition: transport.hpp:247
void close() override
Definition: transport.cpp:426
void check_deadline()
Definition: transport.cpp:760
Transport()
Definition: transport.cpp:297
const T & move(const T &t)
Definition: gtest-port.h:1317
boost::optional< std::string > reason
Definition: exceptions.hpp:62
udp::endpoint m_endpoint
Definition: transport.hpp:249
std::string m_device_host
Definition: transport.hpp:243
const GenericPointer< typename T::ValueType > T2 value
Definition: pointer.h:1225
Definition: transport.hpp:133
hw::trezor::messages::MessageType m_type
Definition: transport.hpp:369
std::string get_path() const override
Definition: transport.cpp:558
ProtocolException()
Definition: exceptions.hpp:118
epee::net_utils::http::http_simple_client m_http_client
Definition: transport.hpp:194
Definition: wipeable_string.h:40
void open() override
Definition: transport.cpp:405
std::shared_ptr< google::protobuf::Message > m_msg
Definition: transport.hpp:370
UnexpectedMessageException()
Definition: transport.hpp:346
void write(const google::protobuf::Message &req) override
Definition: transport.cpp:447
Definition: uri.py:1
virtual void open()
Definition: transport.hpp:154
std::string m_body
Definition: http_base.h:167
virtual std::string get_path() const
Definition: transport.hpp:152
std::string to_string(t_connection_type type)
Definition: connection_basic.cpp:70
bool ping_int(boost::posix_time::time_duration timeout=boost::posix_time::milliseconds(1500))
Definition: transport.cpp:573
virtual size_t read_chunk(void *buff, size_t size)
Definition: transport.hpp:161
void * memwipe(void *src, size_t n)
Definition: memwipe.c:107
static void open(MDB_env *&env, const boost::filesystem::path &path, uint64_t db_flags, bool readonly)
Definition: blockchain_prune.cpp:66
std::vector< std::shared_ptr< Transport > > t_transport_vect
Definition: transport.hpp:144
Definition: transport.hpp:363
std::ostream & operator<<(std::ostream &o, hw::trezor::Transport const &t)
Definition: transport.cpp:1278
void read(std::shared_ptr< google::protobuf::Message > &msg, messages::MessageType *msg_type=nullptr) override
Definition: transport.cpp:471
static const char * DEFAULT_HOST
Definition: transport.hpp:215
virtual ~Transport()=default
Definition: transport.hpp:339
#define true
Definition: stdbool.h:36
static void handle_receive(const boost::system::error_code &ec, std::size_t length, boost::system::error_code *out_ec, std::size_t *out_length)
Definition: transport.cpp:787
size_t read_chunk(void *buff, size_t size) override
Definition: transport.cpp:669
std::shared_ptr< Transport > transport(const std::string &path)
Definition: transport.cpp:1231
Definition: transport.hpp:123
virtual bool ping()
Definition: transport.hpp:151