rippled
TrustedPublisherServer.h
1 //------------------------------------------------------------------------------
2 /*
3  This file is part of rippled: https://github.com/ripple/rippled
4  Copyright 2017 Ripple Labs Inc.
5 
6  Permission to use, copy, modify, and/or distribute this software for any
7  purpose with or without fee is hereby granted, provided that the above
8  copyright notice and this permission notice appear in all copies.
9 
10  THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
11  WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
12  MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
13  ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
14  WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
15  ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
16  OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
17 */
18 //==============================================================================
19 #ifndef RIPPLE_TEST_TRUSTED_PUBLISHER_SERVER_H_INCLUDED
20 #define RIPPLE_TEST_TRUSTED_PUBLISHER_SERVER_H_INCLUDED
21 
22 #include <ripple/basics/base64.h>
23 #include <ripple/basics/random.h>
24 #include <ripple/basics/strHex.h>
25 #include <ripple/protocol/PublicKey.h>
26 #include <ripple/protocol/SecretKey.h>
27 #include <ripple/protocol/Sign.h>
28 #include <boost/algorithm/string/predicate.hpp>
29 #include <boost/asio.hpp>
30 #include <boost/asio/ip/tcp.hpp>
31 #include <boost/asio/ssl/stream.hpp>
32 #include <boost/beast/http.hpp>
33 #include <boost/beast/ssl.hpp>
34 #include <boost/beast/version.hpp>
35 #include <boost/lexical_cast.hpp>
36 #include <test/jtx/envconfig.h>
37 
38 #include <memory>
39 #include <thread>
40 
41 namespace ripple {
42 namespace test {
43 
45  : public std::enable_shared_from_this<TrustedPublisherServer>
46 {
47  using endpoint_type = boost::asio::ip::tcp::endpoint;
48  using address_type = boost::asio::ip::address;
49  using socket_type = boost::asio::ip::tcp::socket;
50 
51  using req_type =
52  boost::beast::http::request<boost::beast::http::string_body>;
53  using resp_type =
54  boost::beast::http::response<boost::beast::http::string_body>;
55  using error_code = boost::system::error_code;
56 
59  boost::asio::ip::tcp::acceptor acceptor_;
60  // Generates a version 1 validator list, using the int parameter as the
61  // actual version.
63  // Generates a version 2 validator list, using the int parameter as the
64  // actual version.
66 
67  // The SSL context is required, and holds certificates
68  bool useSSL_;
69  boost::asio::ssl::context sslCtx_{boost::asio::ssl::context::tlsv12};
70 
73 
74  // Load a signed certificate into the ssl context, and configure
75  // the context for use with a server.
76  inline void
78  {
79  sslCtx_.set_password_callback(
80  [](std::size_t, boost::asio::ssl::context_base::password_purpose) {
81  return "test";
82  });
83 
84  sslCtx_.set_options(
85  boost::asio::ssl::context::default_workarounds |
86  boost::asio::ssl::context::no_sslv2 |
87  boost::asio::ssl::context::single_dh_use);
88 
89  sslCtx_.use_certificate_chain(
90  boost::asio::buffer(cert().data(), cert().size()));
91 
92  sslCtx_.use_private_key(
93  boost::asio::buffer(key().data(), key().size()),
94  boost::asio::ssl::context::file_format::pem);
95 
96  sslCtx_.use_tmp_dh(boost::asio::buffer(dh().data(), dh().size()));
97  }
98 
99  struct BlobInfo
100  {
102  {
103  }
104 
105  // base-64 encoded JSON containing the validator list.
107  // hex-encoded signature of the blob using the publisher's signing key
109  };
110 
111 public:
112  struct Validator
113  {
117  };
118 
119  static std::string
121  PublicKey const& pk,
122  SecretKey const& sk,
123  PublicKey const& spk,
124  SecretKey const& ssk,
125  int seq)
126  {
127  STObject st(sfGeneric);
128  st[sfSequence] = seq;
129  st[sfPublicKey] = pk;
130  st[sfSigningPubKey] = spk;
131 
132  sign(st, HashPrefix::manifest, *publicKeyType(spk), ssk);
133  sign(
134  st,
136  *publicKeyType(pk),
137  sk,
139 
140  Serializer s;
141  st.add(s);
142 
143  return base64_encode(
144  std::string(static_cast<char const*>(s.data()), s.size()));
145  }
146 
147  static Validator
149  {
150  auto const secret = randomSecretKey();
151  auto const masterPublic = derivePublicKey(KeyType::ed25519, secret);
152  auto const signingKeys = randomKeyPair(KeyType::secp256k1);
153  return {
154  masterPublic,
155  signingKeys.first,
157  masterPublic,
158  secret,
159  signingKeys.first,
160  signingKeys.second,
161  1)};
162  }
163 
164  // TrustedPublisherServer must be accessed through a shared_ptr.
165  // This constructor is only public so std::make_shared has access.
166  // The function`make_TrustedPublisherServer` should be used to create
167  // instances.
168  // The `futures` member is expected to be structured as
169  // effective / expiration time point pairs for use in version 2 UNLs
171  boost::asio::io_context& ioc,
172  std::vector<Validator> const& validators,
173  NetClock::time_point validUntil,
174  std::vector<
176  futures,
177  bool useSSL = false,
178  int version = 1,
179  bool immediateStart = true,
180  int sequence = 1)
181  : sock_{ioc}
182  , ep_{beast::IP::Address::from_string(
184  // 0 means let OS pick the port based on what's available
185  0}
186  , acceptor_{ioc}
187  , useSSL_{useSSL}
190  {
191  auto const keys = randomKeyPair(KeyType::secp256k1);
192  auto const manifest = makeManifestString(
193  publisherPublic_, publisherSecret_, keys.first, keys.second, 1);
194 
195  std::vector<BlobInfo> blobInfo;
196  blobInfo.reserve(futures.size() + 1);
197  auto const [data, blob] = [&]() -> std::pair<std::string, std::string> {
198  // Builds the validator list, then encodes it into a blob.
199  std::string data = "{\"sequence\":" + std::to_string(sequence) +
200  ",\"expiration\":" +
201  std::to_string(validUntil.time_since_epoch().count()) +
202  ",\"validators\":[";
203 
204  for (auto const& val : validators)
205  {
206  data += "{\"validation_public_key\":\"" +
207  strHex(val.masterPublic) + "\",\"manifest\":\"" +
208  val.manifest + "\"},";
209  }
210  data.pop_back();
211  data += "]}";
212  std::string blob = base64_encode(data);
213  return std::make_pair(data, blob);
214  }();
215  auto const sig = strHex(sign(keys.first, keys.second, makeSlice(data)));
216  blobInfo.emplace_back(blob, sig);
217  getList_ = [blob = blob, sig, manifest, version](int interval) {
218  // Build the contents of a version 1 format UNL file
220  l << "{\"blob\":\"" << blob << "\""
221  << ",\"signature\":\"" << sig << "\""
222  << ",\"manifest\":\"" << manifest << "\""
223  << ",\"refresh_interval\": " << interval
224  << ",\"version\":" << version << '}';
225  return l.str();
226  };
227  for (auto const& future : futures)
228  {
229  std::string data = "{\"sequence\":" + std::to_string(++sequence) +
230  ",\"effective\":" +
231  std::to_string(future.first.time_since_epoch().count()) +
232  ",\"expiration\":" +
233  std::to_string(future.second.time_since_epoch().count()) +
234  ",\"validators\":[";
235 
236  // Use the same set of validators for simplicity
237  for (auto const& val : validators)
238  {
239  data += "{\"validation_public_key\":\"" +
240  strHex(val.masterPublic) + "\",\"manifest\":\"" +
241  val.manifest + "\"},";
242  }
243  data.pop_back();
244  data += "]}";
245  std::string blob = base64_encode(data);
246  auto const sig =
247  strHex(sign(keys.first, keys.second, makeSlice(data)));
248  blobInfo.emplace_back(blob, sig);
249  }
250  getList2_ = [blobInfo, manifest, version](int interval) {
251  // Build the contents of a version 2 format UNL file
252  // Use `version + 1` to get 2 for most tests, but have
253  // a "bad" version number for tests that provide an override.
255  for (auto const& info : blobInfo)
256  {
257  l << "{\"blob\":\"" << info.blob << "\""
258  << ",\"signature\":\"" << info.signature << "\"},";
259  }
260  std::string blobs = l.str();
261  blobs.pop_back();
262  l.str(std::string());
263  l << "{\"blobs_v2\": [ " << blobs << "],\"manifest\":\"" << manifest
264  << "\""
265  << ",\"refresh_interval\": " << interval
266  << ",\"version\":" << (version + 1) << '}';
267  return l.str();
268  };
269 
270  if (useSSL_)
271  {
272  // This holds the self-signed certificate used by the server
274  }
275  }
276 
277  void
279  {
280  error_code ec;
281  acceptor_.open(ep_.protocol());
282  acceptor_.set_option(
283  boost::asio::ip::tcp::acceptor::reuse_address(true), ec);
284  acceptor_.bind(ep_);
285  acceptor_.listen(boost::asio::socket_base::max_connections);
286  acceptor_.async_accept(
287  sock_,
289  error_code ec) {
290  if (auto p = wp.lock())
291  {
292  p->on_accept(ec);
293  }
294  });
295  }
296 
297  void
299  {
300  error_code ec;
301  acceptor_.close(ec);
302  // TODO consider making this join
303  // any running do_peer threads
304  }
305 
307  {
308  stop();
309  }
310 
313  {
314  return acceptor_.local_endpoint();
315  }
316 
317  PublicKey const&
319  {
320  return publisherPublic_;
321  }
322 
323  /* CA/self-signed certs :
324  *
325  * The following three methods return certs/keys used by
326  * server and/or client to do the SSL handshake. These strings
327  * were generated using the script below. The server key and cert
328  * are used to configure the server (see load_server_certificate
329  * above). The ca.crt should be used to configure the client
330  * when ssl verification is enabled.
331  *
332  * note:
333  * cert() ==> server.crt
334  * key() ==> server.key
335  * ca_cert() ==> ca.crt
336  * dh() ==> dh.pem
337  ```
338  #!/usr/bin/env bash
339 
340  mkdir -p /tmp/__certs__
341  pushd /tmp/__certs__
342  rm *.crt *.key *.pem
343 
344  # generate CA
345  openssl genrsa -out ca.key 2048
346  openssl req -new -x509 -nodes -days 10000 -key ca.key -out ca.crt \
347  -subj "/C=US/ST=CA/L=Los
348  Angeles/O=rippled-unit-tests/CN=example.com" # generate private cert
349  openssl genrsa -out server.key 2048
350  # Generate certificate signing request
351  # since our unit tests can run in either ipv4 or ipv6 mode,
352  # we need to use extensions (subjectAltName) so that we can
353  # associate both ipv4 and ipv6 localhost addresses with this cert
354  cat >"extras.cnf" <<EOF
355  [req]
356  req_extensions = v3_req
357  distinguished_name = req_distinguished_name
358 
359  [req_distinguished_name]
360 
361  [v3_req]
362  subjectAltName = @alt_names
363 
364  [alt_names]
365  DNS.1 = localhost
366  IP.1 = ::1
367  EOF
368  openssl req -new -key server.key -out server.csr \
369  -config extras.cnf \
370  -subj "/C=US/ST=California/L=San
371  Francisco/O=rippled-unit-tests/CN=127.0.0.1" \
372 
373  # Create public certificate by signing with our CA
374  openssl x509 -req -days 10000 -in server.csr -CA ca.crt -CAkey ca.key
375  -out server.crt \ -extfile extras.cnf -set_serial 01 -extensions v3_req
376 
377  # generate DH params for server
378  openssl dhparam -out dh.pem 2048
379  # verify certs
380  openssl verify -CAfile ca.crt server.crt
381  openssl x509 -in server.crt -text -noout
382  popd
383  ```
384  */
385  static std::string const&
387  {
388  static std::string const cert{R"cert(
389 -----BEGIN CERTIFICATE-----
390 MIIDczCCAlugAwIBAgIBATANBgkqhkiG9w0BAQUFADBjMQswCQYDVQQGEwJVUzEL
391 MAkGA1UECAwCQ0ExFDASBgNVBAcMC0xvcyBBbmdlbGVzMRswGQYDVQQKDBJyaXBw
392 bGVkLXVuaXQtdGVzdHMxFDASBgNVBAMMC2V4YW1wbGUuY29tMB4XDTE5MDgwNzE3
393 MzM1OFoXDTQ2MTIyMzE3MzM1OFowazELMAkGA1UEBhMCVVMxEzARBgNVBAgMCkNh
394 bGlmb3JuaWExFjAUBgNVBAcMDVNhbiBGcmFuY2lzY28xGzAZBgNVBAoMEnJpcHBs
395 ZWQtdW5pdC10ZXN0czESMBAGA1UEAwwJMTI3LjAuMC4xMIIBIjANBgkqhkiG9w0B
396 AQEFAAOCAQ8AMIIBCgKCAQEA5Ky0UE9K+gFOznfwBvq2HfnQOOPGtVf4G9m63b5V
397 QNJYCSNiYxkGZW72ESM3XA8BledlkV9pwIm17+7ucB1Ed3efQjQDq2RSk5LDYDaa
398 r0Qzzy0EC3b9+AKA6mAoVY6s1Qws/YvM4esz0H+SVvtVcFqA46kRWhJN7M5ic1lu
399 d58fAq04BHqi5zOEOzfHJYPGUgQOxRTHluYkkkBrL2xioHHnOROshW+PIYFiAc/h
400 WPzuihPHnKaziPRw+O6O8ysnCxycQHgqtvx73T52eJdLxtr3ToRWaY/8VF/Cog5c
401 uvWEtg6EucGOszIH8O7eJWaJpVpAfZIX+c62MQWLpOLi/QIDAQABoyowKDAmBgNV
402 HREEHzAdgglsb2NhbGhvc3SHEAAAAAAAAAAAAAAAAAAAAAEwDQYJKoZIhvcNAQEF
403 BQADggEBAOhLAO/e0lGi9TZ2HiVi4sJ7KVQaBQHGhfsysILoQNHrNqDypPc/ZrSa
404 WQ2OqyUeltMnUdN5S1h3MKRZlbAeBQlwkPdjTzlzWkCMWB5BsfIGy5ovqmNQ7zPa
405 Khg5oxq3mU8ZLiJP4HngyU+hOOCt5tttex2S8ubjFT+3C3cydLKEOXCUPspaVkKn
406 Eq8WSBoYTvyUVmSi6+m6HGiowWsM5Qgj93IRW6JCbkgfPeKXC/5ykAPQcFHwNaKT
407 rpWokcavZyMbVjRsbzCQcc7n2j7tbLOu2svSLy6oXwG6n/bEagl5WpN2/TzQuwe7
408 f5ktutc4DDJSV7fuYYCuGumrHAjcELE=
409 -----END CERTIFICATE-----
410 )cert"};
411  return cert;
412  }
413 
414  static std::string const&
415  key()
416  {
417  static std::string const key{R"pkey(
418 -----BEGIN RSA PRIVATE KEY-----
419 MIIEpQIBAAKCAQEA5Ky0UE9K+gFOznfwBvq2HfnQOOPGtVf4G9m63b5VQNJYCSNi
420 YxkGZW72ESM3XA8BledlkV9pwIm17+7ucB1Ed3efQjQDq2RSk5LDYDaar0Qzzy0E
421 C3b9+AKA6mAoVY6s1Qws/YvM4esz0H+SVvtVcFqA46kRWhJN7M5ic1lud58fAq04
422 BHqi5zOEOzfHJYPGUgQOxRTHluYkkkBrL2xioHHnOROshW+PIYFiAc/hWPzuihPH
423 nKaziPRw+O6O8ysnCxycQHgqtvx73T52eJdLxtr3ToRWaY/8VF/Cog5cuvWEtg6E
424 ucGOszIH8O7eJWaJpVpAfZIX+c62MQWLpOLi/QIDAQABAoIBACf8mzs/4lh9Sg6I
425 ooxV4uqy+Fo6WlDzpQsZs7d6xOWk4ogWi+nQQnISSS0N/2w1o41W/UfCa3ejnRDr
426 sv4f4A0T+eFVvx6FWHs9urRkWAA16OldccufbyGjLm/NiMANRuOqUWO0woru2gyn
427 git7n6EZ8lfdBI+/i6jRHh4VkV+ROt5Zbp9zuJsj0yMqJH7J6Ebtl1jAF6PemLBL
428 yxdiYqR8LKTunTGGP/L+4K5a389oPDcJ1+YX805NEopmfrIhPr+BQYdz8905aVFk
429 FSS4TJy23EhFLzKf3+iSept6Giim+2yy2rv1RPCKgjOXbJ+4LD48xumDol6XWgYr
430 1CBzQIECgYEA/jBEGOjV02a9A3C5RJxZMawlGwGrvvALG2UrKvwQc595uxwrUw9S
431 Mn3ZQBEGnEWwEf44jSpWzp8TtejMxEvrU5243eWgwif1kqr1Mcj54DR7Qm15/hsj
432 M3nA2WscVG2OHBs4AwzMCHE2vfEAkbz71s6xonhg6zvsC26Zy3hYPqkCgYEA5k3k
433 OuCeG5FXW1/GzhvVFuhl6msNKzuUnLmJg6500XPny5Xo7W3RMvjtTM2XLt1USU6D
434 arMCCQ1A8ku1SoFdSw5RC6Fl8ZoUFBz9FPPwT6usQssGyFxiiqdHLvTlk12NNCk3
435 vJYsdQ+v/dKuZ8T4U3GTgQSwPTj6J0kJUf5y2jUCgYEA+hi/R8r/aArz+kiU4T78
436 O3Vm5NWWCD3ij8fQ23A7N6g3e7RRpF20wF02vmSCHowqmumI9swrsQyvthIiNxmD
437 pzfORvXCYIY0h2SR77QQt1qr1EYm+6/zyJgI+WL78s4APwNA7y9OKRhLhkN0DfDl
438 0Qp5mKPcqFbC/tSJmbsFCFECgYEAwlLC2rMgdV5jeWQNGWf+mv+ozu1ZBTuWn88l
439 qwiO5RSJZwysp3nb5MiJYh6vDAoQznIDDQrSEtUuEcOzypPxJh2EYO3kWMGLY5U6
440 Lm3OPUs7ZHhu1qytMRUISSS2eWucc4C72NJV3MhJ1T/pjQF0DuRsc5aDJoVm/bLw
441 vFCYlGkCgYEAgBDIIqdo1th1HE95SQfpP2wV/jA6CPamIciNwS3bpyhDBqs9oLUc
442 qzXidOpXAVYg1wl/BqpaCQcmmhCrnSLJYdOMpudVyLCCfYmBJ0bs2DCAe5ibGbL7
443 VruAOjS4yBepkXJU9xwKHxDmgTo/oQ5smq7SNOUWDSElVI/CyZ0x7qA=
444 -----END RSA PRIVATE KEY-----
445 )pkey"};
446  return key;
447  }
448 
449  static std::string const&
450  ca_cert()
451  {
452  static std::string const cert{R"cert(
453 -----BEGIN CERTIFICATE-----
454 MIIDQjCCAioCCQDxKQafEvp+VTANBgkqhkiG9w0BAQsFADBjMQswCQYDVQQGEwJV
455 UzELMAkGA1UECAwCQ0ExFDASBgNVBAcMC0xvcyBBbmdlbGVzMRswGQYDVQQKDBJy
456 aXBwbGVkLXVuaXQtdGVzdHMxFDASBgNVBAMMC2V4YW1wbGUuY29tMB4XDTE5MDgw
457 NzE3MzM1OFoXDTQ2MTIyMzE3MzM1OFowYzELMAkGA1UEBhMCVVMxCzAJBgNVBAgM
458 AkNBMRQwEgYDVQQHDAtMb3MgQW5nZWxlczEbMBkGA1UECgwScmlwcGxlZC11bml0
459 LXRlc3RzMRQwEgYDVQQDDAtleGFtcGxlLmNvbTCCASIwDQYJKoZIhvcNAQEBBQAD
460 ggEPADCCAQoCggEBAO9oqh72ttM7hjPnbMcJw0EuyULocEn2hlg4HE4YtzaxlRIz
461 dHm8nMkG/9yGmHBCuue/Gzssm/CzlduGezae01p8eaFUuEJsjxdrXe89Wk2QH+dm
462 Fn+SRbGcHaaTV/cyJrvusG7pOu95HL2eebuwiZ+tX5JP01R732iQt8Beeygh/W4P
463 n2f//fAxbdAIWzx2DH6cmSNe6lpoQe/MN15o8V3whutcC3fkis6wcA7BKZcdVdL2
464 daFWA6mt4SPWldOfWQVAIX4vRvheWPy34OLCgx+wZWg691Lwd1F+paarKombatUt
465 vKMTeolFYl3zkZZMYvR0Oyrt5NXUhRfmG7xR3bkCAwEAATANBgkqhkiG9w0BAQsF
466 AAOCAQEAggKO5WdtU67QPcAdo1Uar0SFouvVLwxJvoKlQ5rqF3idd0HnFVy7iojW
467 G2sZq7z8SNDMkUXZLbcbYNRyrZI0PdjfI0kyNpaa3pEcPcR8aOcTEOtW6V67FrPG
468 8aNYpr6a8PPq12aHzPSNjlUGot/qffGIQ0H2OqdWMOUXMMFnmH2KnnWi46Aq3gaF
469 uyHGrEczjJAK7NTzP8A7fbrmT00Sn6ft1FriQyhvDkUgPXBGWKpOFO84V27oo0ZL
470 xXQHDWcpX+8yNKynjafkXLx6qXwcySF2bKcTIRsxlN6WNRqZ+wqpNStkjuoFkYR/
471 IfW9PBfO/gCtNJQ+lqpoTd3kLBCAng==
472 -----END CERTIFICATE-----
473 )cert"};
474  return cert;
475  }
476 
477  static std::string const&
478  dh()
479  {
480  static std::string const dh{R"dh(
481 -----BEGIN DH PARAMETERS-----
482 MIIBCAKCAQEAnJaaKu3U2a7ZVBvIC+NVNHXo9q6hNCazze+4pwXAKBVXH0ozInEw
483 WKozYxVJLW7dvDHdjdFOSuTLQDqaPW9zVMQKM0BKu81+JyfJi7C3HYKUw7ECVHp4
484 DLvhDe6N5eBj/t1FUwcfS2VNIx4QcJiw6FH3CwNNee1fIi5VTRJp2GLUuMCHkT/I
485 FTODJ+Anw12cJqLdgQfV74UV/Y7JCQl3/DOIy+2YkmX8vWVHX1h6EI5Gw4a3jgqF
486 gVyCOWoVCfgu37H5e7ERyoAxigiP8hMqoGpmJUYJghVKWoFgNUqXw+guVJ56eIuH
487 0wVs/LXflOZ42PJAiwv4LTNOtpG2pWGjOwIBAg==
488 -----END DH PARAMETERS-----
489 )dh"};
490  return dh;
491  }
492 
493 private:
494  struct lambda
495  {
496  int id;
499  boost::asio::executor_work_guard<boost::asio::executor> work;
500  bool ssl;
501 
502  lambda(
503  int id_,
504  TrustedPublisherServer& self_,
505  socket_type&& sock_,
506  bool ssl_)
507  : id(id_)
508  , self(self_)
509  , sock(std::move(sock_))
510  , work(sock_.get_executor())
511  , ssl(ssl_)
512  {
513  }
514 
515  void
516  operator()()
517  {
518  self.do_peer(id, std::move(sock), ssl);
519  }
520  };
521 
522  void
524  {
525  if (ec || !acceptor_.is_open())
526  return;
527 
528  static int id_ = 0;
529  std::thread{lambda{++id_, *this, std::move(sock_), useSSL_}}.detach();
530  acceptor_.async_accept(
531  sock_,
533  error_code ec) {
534  if (auto p = wp.lock())
535  {
536  p->on_accept(ec);
537  }
538  });
539  }
540 
541  void
542  do_peer(int id, socket_type&& s, bool ssl)
543  {
544  using namespace boost::beast;
545  using namespace boost::asio;
546  socket_type sock(std::move(s));
547  flat_buffer sb;
548  error_code ec;
550 
551  if (ssl)
552  {
553  // Construct the stream around the socket
554  ssl_stream.emplace(sock, sslCtx_);
555  // Perform the SSL handshake
556  ssl_stream->handshake(ssl::stream_base::server, ec);
557  if (ec)
558  return;
559  }
560 
561  for (;;)
562  {
563  resp_type res;
564  req_type req;
565  try
566  {
567  if (ssl)
568  http::read(*ssl_stream, sb, req, ec);
569  else
570  http::read(sock, sb, req, ec);
571 
572  if (ec)
573  break;
574 
575  auto path = req.target().to_string();
576  res.insert("Server", "TrustedPublisherServer");
577  res.version(req.version());
578  res.keep_alive(req.keep_alive());
579  bool prepare = true;
580 
581  if (boost::starts_with(path, "/validators2"))
582  {
583  res.result(http::status::ok);
584  res.insert("Content-Type", "application/json");
585  if (path == "/validators2/bad")
586  res.body() = "{ 'bad': \"2']";
587  else if (path == "/validators2/missing")
588  res.body() = "{\"version\": 2}";
589  else
590  {
591  int refresh = 5;
592  constexpr char const* refreshPrefix =
593  "/validators2/refresh/";
594  if (boost::starts_with(path, refreshPrefix))
595  refresh = boost::lexical_cast<unsigned int>(
596  path.substr(strlen(refreshPrefix)));
597  res.body() = getList2_(refresh);
598  }
599  }
600  else if (boost::starts_with(path, "/validators"))
601  {
602  res.result(http::status::ok);
603  res.insert("Content-Type", "application/json");
604  if (path == "/validators/bad")
605  res.body() = "{ 'bad': \"1']";
606  else if (path == "/validators/missing")
607  res.body() = "{\"version\": 1}";
608  else
609  {
610  int refresh = 5;
611  constexpr char const* refreshPrefix =
612  "/validators/refresh/";
613  if (boost::starts_with(path, refreshPrefix))
614  refresh = boost::lexical_cast<unsigned int>(
615  path.substr(strlen(refreshPrefix)));
616  res.body() = getList_(refresh);
617  }
618  }
619  else if (boost::starts_with(path, "/textfile"))
620  {
621  prepare = false;
622  res.result(http::status::ok);
623  res.insert("Content-Type", "text/example");
624  // if huge was requested, lie about content length
625  std::uint64_t cl =
626  boost::starts_with(path, "/textfile/huge")
628  : 1024;
629  res.content_length(cl);
630  if (req.method() == http::verb::get)
631  {
632  std::stringstream body;
633  for (auto i = 0; i < 1024; ++i)
634  body << static_cast<char>(rand_int<short>(32, 126)),
635  res.body() = body.str();
636  }
637  }
638  else if (boost::starts_with(path, "/sleep/"))
639  {
640  auto const sleep_sec =
641  boost::lexical_cast<unsigned int>(path.substr(7));
643  std::chrono::seconds{sleep_sec});
644  }
645  else if (boost::starts_with(path, "/redirect"))
646  {
647  if (boost::ends_with(path, "/301"))
648  res.result(http::status::moved_permanently);
649  else if (boost::ends_with(path, "/302"))
650  res.result(http::status::found);
651  else if (boost::ends_with(path, "/307"))
652  res.result(http::status::temporary_redirect);
653  else if (boost::ends_with(path, "/308"))
654  res.result(http::status::permanent_redirect);
655 
656  std::stringstream location;
657  if (boost::starts_with(path, "/redirect_to/"))
658  {
659  location << path.substr(13);
660  }
661  else if (!boost::starts_with(path, "/redirect_nolo"))
662  {
663  location
664  << (ssl ? "https://" : "http://")
665  << local_endpoint()
666  << (boost::starts_with(path, "/redirect_forever/")
667  ? path
668  : "/validators");
669  }
670  if (!location.str().empty())
671  res.insert("Location", location.str());
672  }
673  else
674  {
675  // unknown request
676  res.result(boost::beast::http::status::not_found);
677  res.insert("Content-Type", "text/html");
678  res.body() = "The file '" + path + "' was not found";
679  }
680 
681  if (prepare)
682  res.prepare_payload();
683  }
684  catch (std::exception const& e)
685  {
686  res = {};
687  res.result(boost::beast::http::status::internal_server_error);
688  res.version(req.version());
689  res.insert("Server", "TrustedPublisherServer");
690  res.insert("Content-Type", "text/html");
691  res.body() =
692  std::string{"An internal error occurred"} + e.what();
693  res.prepare_payload();
694  }
695 
696  if (ssl)
697  write(*ssl_stream, res, ec);
698  else
699  write(sock, res, ec);
700 
701  if (ec || req.need_eof())
702  break;
703  }
704 
705  // Perform the SSL shutdown
706  if (ssl)
707  ssl_stream->shutdown(ec);
708  }
709 };
710 
713  boost::asio::io_context& ioc,
715  NetClock::time_point validUntil,
717  futures,
718  bool useSSL = false,
719  int version = 1,
720  bool immediateStart = true,
721  int sequence = 1)
722 {
723  auto const r = std::make_shared<TrustedPublisherServer>(
724  ioc, validators, validUntil, futures, useSSL, version, sequence);
725  if (immediateStart)
726  r->start();
727  return r;
728 }
729 
730 } // namespace test
731 } // namespace ripple
732 #endif
ripple::test::TrustedPublisherServer::publisherPublic
PublicKey const & publisherPublic() const
Definition: TrustedPublisherServer.h:318
ripple::test::Validator
Simulate Validator.
Definition: reduce_relay_test.cpp:310
ripple::test::TrustedPublisherServer::lambda::sock
socket_type sock
Definition: TrustedPublisherServer.h:418
ripple::test::TrustedPublisherServer::lambda::lambda
lambda(int id_, TrustedPublisherServer &self_, socket_type &&sock_, bool ssl_)
Definition: TrustedPublisherServer.h:422
std::this_thread::sleep_for
T sleep_for(T... args)
ripple::makeSlice
std::enable_if_t< std::is_same< T, char >::value||std::is_same< T, unsigned char >::value, Slice > makeSlice(std::array< T, N > const &a)
Definition: Slice.h:240
ripple::test::TrustedPublisherServer::TrustedPublisherServer
TrustedPublisherServer(boost::asio::io_context &ioc, std::vector< Validator > const &validators, NetClock::time_point validUntil, std::vector< std::pair< NetClock::time_point, NetClock::time_point >> const &futures, bool useSSL=false, int version=1, bool immediateStart=true, int sequence=1)
Definition: TrustedPublisherServer.h:170
std::strlen
T strlen(T... args)
std::string
STL class.
std::shared_ptr
STL class.
std::exception
STL class.
ripple::sfGeneric
const SField sfGeneric(access, 0)
Definition: SField.h:332
ripple::test::TrustedPublisherServer::getList_
std::function< std::string(int)> getList_
Definition: TrustedPublisherServer.h:62
ripple::test::TrustedPublisherServer::Validator::manifest
std::string manifest
Definition: TrustedPublisherServer.h:116
std::pair
std::vector::reserve
T reserve(T... args)
ripple::test::TrustedPublisherServer::resp_type
boost::beast::http::response< boost::beast::http::string_body > resp_type
Definition: TrustedPublisherServer.h:54
ripple::test::TrustedPublisherServer::local_endpoint
endpoint_type local_endpoint() const
Definition: TrustedPublisherServer.h:312
ripple::sfSequence
const SF_UINT32 sfSequence
ripple::test::TrustedPublisherServer::publisherSecret_
SecretKey publisherSecret_
Definition: TrustedPublisherServer.h:71
ripple::HashPrefix::manifest
@ manifest
Manifest.
std::vector
STL class.
ripple::base64_encode
std::string base64_encode(std::uint8_t const *data, std::size_t len)
Definition: base64.cpp:236
ripple::sfSigningPubKey
const SF_VL sfSigningPubKey
std::chrono::seconds
ripple::test::TrustedPublisherServer::sslCtx_
boost::asio::ssl::context sslCtx_
Definition: TrustedPublisherServer.h:69
std::optional::emplace
T emplace(T... args)
std::stringstream
STL class.
ripple::test::TrustedPublisherServer::useSSL_
bool useSSL_
Definition: TrustedPublisherServer.h:68
std::function
ripple::test::TrustedPublisherServer::getList2_
std::function< std::string(int)> getList2_
Definition: TrustedPublisherServer.h:65
ripple::test::TrustedPublisherServer::on_accept
void on_accept(error_code ec)
Definition: TrustedPublisherServer.h:443
ripple::test::TrustedPublisherServer::lambda::self
TrustedPublisherServer & self
Definition: TrustedPublisherServer.h:417
ripple::test::TrustedPublisherServer::ca_cert
static std::string const & ca_cert()
Definition: TrustedPublisherServer.h:400
ripple::NodeStore::write
void write(nudb::detail::ostream &os, std::size_t t)
Definition: varint.h:133
ripple::test::TrustedPublisherServer::key
static std::string const & key()
Definition: TrustedPublisherServer.h:393
ripple::test::TrustedPublisherServer::req_type
boost::beast::http::request< boost::beast::http::string_body > req_type
Definition: TrustedPublisherServer.h:52
ripple::test::TrustedPublisherServer::ep_
endpoint_type ep_
Definition: TrustedPublisherServer.h:58
ripple::Serializer::data
void const * data() const noexcept
Definition: Serializer.h:75
ripple::test::TrustedPublisherServer::lambda::ssl
bool ssl
Definition: TrustedPublisherServer.h:420
ripple::test::TrustedPublisherServer::sock_
socket_type sock_
Definition: TrustedPublisherServer.h:57
ripple::KeyType::ed25519
@ ed25519
ripple::publicKeyType
std::optional< KeyType > publicKeyType(Slice const &slice)
Returns the type of public key.
Definition: PublicKey.cpp:203
ripple::test::TrustedPublisherServer::BlobInfo::blob
std::string blob
Definition: TrustedPublisherServer.h:106
ripple::test::TrustedPublisherServer::cert
static std::string const & cert()
Definition: TrustedPublisherServer.h:386
ripple::test::getEnvLocalhostAddr
const char * getEnvLocalhostAddr()
Definition: envconfig.h:31
ripple::test::TrustedPublisherServer::makeManifestString
static std::string makeManifestString(PublicKey const &pk, SecretKey const &sk, PublicKey const &spk, SecretKey const &ssk, int seq)
Definition: TrustedPublisherServer.h:120
std::enable_shared_from_this< TrustedPublisherServer >::shared_from_this
T shared_from_this(T... args)
thread
ripple::PublicKey
A public key.
Definition: PublicKey.h:59
ripple::derivePublicKey
PublicKey derivePublicKey(KeyType type, SecretKey const &sk)
Derive the public key from a secret key.
Definition: SecretKey.cpp:313
ripple::sfMasterSignature
const SF_VL sfMasterSignature
ripple::test::TrustedPublisherServer::Validator
Definition: TrustedPublisherServer.h:112
ripple::test::TrustedPublisherServer::start
void start()
Definition: TrustedPublisherServer.h:278
std::to_string
T to_string(T... args)
boost::asio
Definition: Overlay.h:41
ripple::test::TrustedPublisherServer::stop
void stop()
Definition: TrustedPublisherServer.h:298
ripple::test::TrustedPublisherServer::BlobInfo
Definition: TrustedPublisherServer.h:99
std::enable_shared_from_this
std::chrono::time_point
ripple::test::TrustedPublisherServer
Definition: TrustedPublisherServer.h:44
std::uint64_t
ripple::SecretKey
A secret key.
Definition: SecretKey.h:36
ripple::test::TrustedPublisherServer::socket_type
boost::asio::ip::tcp::socket socket_type
Definition: TrustedPublisherServer.h:49
ripple::test::TrustedPublisherServer::lambda::id
int id
Definition: TrustedPublisherServer.h:416
ripple::test::TrustedPublisherServer::randomValidator
static Validator randomValidator()
Definition: TrustedPublisherServer.h:148
std::string::pop_back
T pop_back(T... args)
ripple::test::TrustedPublisherServer::address_type
boost::asio::ip::address address_type
Definition: TrustedPublisherServer.h:48
memory
ripple::test::TrustedPublisherServer::load_server_certificate
void load_server_certificate()
Definition: TrustedPublisherServer.h:77
ripple::KeyType::secp256k1
@ secp256k1
std::weak_ptr
STL class.
ripple::Serializer
Definition: Serializer.h:39
ripple::randomKeyPair
std::pair< PublicKey, SecretKey > randomKeyPair(KeyType type)
Create a key pair using secure random numbers.
Definition: SecretKey.cpp:368
ripple::test::jtx::seq
Set the sequence number on a JTx.
Definition: seq.h:33
ripple::STObject
Definition: STObject.h:51
ripple::test::TrustedPublisherServer::BlobInfo::signature
std::string signature
Definition: TrustedPublisherServer.h:108
std::vector::emplace_back
T emplace_back(T... args)
ripple
Use hash_* containers for keys that do not need a cryptographically secure hashing algorithm.
Definition: RCLCensorshipDetector.h:29
ripple::test::TrustedPublisherServer::lambda::work
boost::asio::executor_work_guard< boost::asio::executor > work
Definition: TrustedPublisherServer.h:419
ripple::Serializer::size
std::size_t size() const noexcept
Definition: Serializer.h:69
ripple::STObject::add
virtual void add(Serializer &s) const override
Definition: STObject.h:352
ripple::sign
Buffer sign(PublicKey const &pk, SecretKey const &sk, Slice const &m)
Generate a signature for a message.
Definition: SecretKey.cpp:238
ripple::test::TrustedPublisherServer::Validator::masterPublic
PublicKey masterPublic
Definition: TrustedPublisherServer.h:114
std
STL namespace.
ripple::test::TrustedPublisherServer::Validator::signingPublic
PublicKey signingPublic
Definition: TrustedPublisherServer.h:115
ripple::test::TrustedPublisherServer::dh
static std::string const & dh()
Definition: TrustedPublisherServer.h:407
ripple::test::TrustedPublisherServer::endpoint_type
boost::asio::ip::tcp::endpoint endpoint_type
Definition: TrustedPublisherServer.h:47
ripple::test::make_TrustedPublisherServer
std::shared_ptr< TrustedPublisherServer > make_TrustedPublisherServer(boost::asio::io_context &ioc, std::vector< TrustedPublisherServer::Validator > const &validators, NetClock::time_point validUntil, std::vector< std::pair< NetClock::time_point, NetClock::time_point >> const &futures, bool useSSL=false, int version=1, bool immediateStart=true, int sequence=1)
Definition: TrustedPublisherServer.h:712
ripple::test::TrustedPublisherServer::lambda::operator()
void operator()()
Definition: TrustedPublisherServer.h:436
std::optional
std::stringstream::str
T str(T... args)
std::size_t
std::make_pair
T make_pair(T... args)
ripple::strHex
std::string strHex(FwdIt begin, FwdIt end)
Definition: strHex.h:45
std::numeric_limits::max
T max(T... args)
ripple::test::TrustedPublisherServer::error_code
boost::system::error_code error_code
Definition: TrustedPublisherServer.h:55
ripple::test::TrustedPublisherServer::acceptor_
boost::asio::ip::tcp::acceptor acceptor_
Definition: TrustedPublisherServer.h:59
std::data
T data(T... args)
ripple::sfPublicKey
const SF_VL sfPublicKey
std::exception::what
T what(T... args)
ripple::randomSecretKey
SecretKey randomSecretKey()
Create a secret key using secure random numbers.
Definition: SecretKey.cpp:281
ripple::test::TrustedPublisherServer::do_peer
void do_peer(int id, socket_type &&s, bool ssl)
Definition: TrustedPublisherServer.h:462
ripple::test::TrustedPublisherServer::publisherPublic_
PublicKey publisherPublic_
Definition: TrustedPublisherServer.h:72
ripple::test::TrustedPublisherServer::BlobInfo::BlobInfo
BlobInfo(std::string b, std::string s)
Definition: TrustedPublisherServer.h:101
ripple::test::TrustedPublisherServer::~TrustedPublisherServer
~TrustedPublisherServer()
Definition: TrustedPublisherServer.h:306