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 MIIDczCCAlugAwIBAgIBATANBgkqhkiG9w0BAQsFADBjMQswCQYDVQQGEwJVUzEL
391 MAkGA1UECAwCQ0ExFDASBgNVBAcMC0xvcyBBbmdlbGVzMRswGQYDVQQKDBJyaXBw
392 bGVkLXVuaXQtdGVzdHMxFDASBgNVBAMMC2V4YW1wbGUuY29tMB4XDTIyMDIwNTIz
393 NDk0M1oXDTQ5MDYyMzIzNDk0M1owazELMAkGA1UEBhMCVVMxEzARBgNVBAgMCkNh
394 bGlmb3JuaWExFjAUBgNVBAcMDVNhbiBGcmFuY2lzY28xGzAZBgNVBAoMEnJpcHBs
395 ZWQtdW5pdC10ZXN0czESMBAGA1UEAwwJMTI3LjAuMC4xMIIBIjANBgkqhkiG9w0B
396 AQEFAAOCAQ8AMIIBCgKCAQEAueZ1hgRxwPgfeVx2AdngUYx7zYcaxcGYXyqi7izJ
397 qTuBUcVcTRC/9Ip67RAEhfcgGudRS/a4Sv1ljwiRknSCcD/ZjzOFDLgbqYGSZNEs
398 +T/qkwmc/L+Pbzf85HM7RjeGOd6NDQy9+oOBbUtqpTxcSGa4ln+YBFUSeoS1Aa9f
399 n9vrxnWX9LgTu5dSWzH5TqFIti+Zs/v0PFjEivBIAOHPslmnzg/wCr99I6z9CAR3
400 zVDe7+sxR//ivpeVE7FWjgkGixnUpZAqn69zNkJjMLNXETgOYskZdMIgbVOMr+0q
401 S1Uj77mhwxKfpnB6TqUVvWLBvmBDzPjf0m0NcCf9UAjqPwIDAQABoyowKDAmBgNV
402 HREEHzAdgglsb2NhbGhvc3SHEAAAAAAAAAAAAAAAAAAAAAEwDQYJKoZIhvcNAQEL
403 BQADggEBAJkUFNS0CeEAKvo0ttzooXnCDH3esj2fwmLJQYLUGsAF8DFrFHTqZEcx
404 hFRdr0ftEb/VKpV9dVF6xtSoMU56kHOnhbHEWADyqdKUkCDjrGBet5QdWmEwNV2L
405 nYrwGQBAybMt/+1XMUV8HeLFJNHnyxfQYcW0fUsrmNGk8W0kzWuuq88qbhfXZAIx
406 KiXrzYpLlM0RlpWXRfYQ6mTdSrRrLnEo5MklizVgNB8HYX78lxa06zP08oReQcfT
407 GSGO8NEEq8BTVmp69zD1JyfvQcXzsi7WtkAX+/EOFZ7LesnZ6VsyjZ74wECCaQuD
408 X1yu/XxHqchM+DOzzVw6wRKaM7Zsk80=
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 MIIEpAIBAAKCAQEAueZ1hgRxwPgfeVx2AdngUYx7zYcaxcGYXyqi7izJqTuBUcVc
420 TRC/9Ip67RAEhfcgGudRS/a4Sv1ljwiRknSCcD/ZjzOFDLgbqYGSZNEs+T/qkwmc
421 /L+Pbzf85HM7RjeGOd6NDQy9+oOBbUtqpTxcSGa4ln+YBFUSeoS1Aa9fn9vrxnWX
422 9LgTu5dSWzH5TqFIti+Zs/v0PFjEivBIAOHPslmnzg/wCr99I6z9CAR3zVDe7+sx
423 R//ivpeVE7FWjgkGixnUpZAqn69zNkJjMLNXETgOYskZdMIgbVOMr+0qS1Uj77mh
424 wxKfpnB6TqUVvWLBvmBDzPjf0m0NcCf9UAjqPwIDAQABAoIBAEC9MDpOu+quvg8+
425 kt4MKSFdIhQuM7WguNaTe5AkSspDrcJzT7SK275mp259QIYCzMxxuA8TSZTb8A1C
426 t6dgKbi7k6FaGMCYMRHzzK6NZfMbPi6cj245q9LYlZpdQswuM/FdPpPH1zUxrNYK
427 CIaooZ6ZHzlSD/eaRMgkBQEkONHrZZtEinLIvKedwssPCaXkIISmt7MFQTDOlxkf
428 K0Mt1mnRREPYbYSfPEEfIyy/KDIiB5AzgGt+uPOn8Oeb1pSqy69jpYcfhSj+bo4S
429 UV6qTuTfBd4qkkNI6d/Z7DcDJFFlfloG/vVgGk/beWNnL2e39vzxiebB3w+MQn4F
430 Wyx5mCECgYEA22z1/ihqt9LIAWtP42oSS3S/RxlFzpp5d7QfNqFnEoVgeRhQzleP
431 pRJIzVXpMYBxexZYqZA/q8xBSggz+2gmRoYnW20VIzl14DsSH378ye3FRwJB0tLy
432 dWU8DC7ZB5XQCTvI9UY3voJNToknODw7RCNO1h3V3T1y6JRLdcLskk8CgYEA2OLy
433 aE5bvsUaLBSv7W9NFhSuZ0p9Y0pFmRgHI7g8i/AgRZ0BgiE8u8OZSHmPJPMaNs/h
434 YIEIrlsgDci1PzwrUYseRp/aiVE1kyev09/ihqRXTPpLQu6h/d63KRe/06W3t5X3
435 Dmfj49hH5zGPBI/0y1ECV/n0fwnRhxSv7fNr3RECgYBEuFpOUAAkNApZj29ErNqv
436 8Q9ayAp5yx1RpQLFjEUIoub05e2gwgGF1DUiwc43p59iyjvYVwnp1x13fxwwl4yt
437 N6Sp2H7vOja1lCp33MB0yVeohodw7InsxFjLA/0KiBvQWH32exhIPOzTNNcooIx7
438 KYeuPUfWc0FCn/cGGZcXtwKBgQC1hp1k99CKBuY05suoanOWe5DNGud/ZvaBgD7Z
439 gqYKadxY52QPyknOzZNJuZQ5VM8n+S2lW9osNFDLuKUaW/3Vrh6U9c4vCC1TEPB0
440 4PnzvzDiWMsNJjWnCfU7C4meVyFBIt84y3NNjAQCWNRe+S3lzdOsVqRwf4NDD+l/
441 uzEYQQKBgQCJczIlwobm1Y6O41hbGZhZL/CGMNS6Z0INi2yasV0WDqYlh7XayHMD
442 cK55dMILcbHqeIBq/wR6sIhw6IJcaDBfFfrJiKKDilfij2lHxR2FQrEngtTCCRV+
443 ZzARzaWhQPvbDqEtLJDWuXZNXfL8/PTIs5NmuKuQ8F4+gQJpkQgwaw==
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 MIIDpzCCAo+gAwIBAgIUWc45WqaaNuaSLoFYTMC/Mjfqw/gwDQYJKoZIhvcNAQEL
455 BQAwYzELMAkGA1UEBhMCVVMxCzAJBgNVBAgMAkNBMRQwEgYDVQQHDAtMb3MgQW5n
456 ZWxlczEbMBkGA1UECgwScmlwcGxlZC11bml0LXRlc3RzMRQwEgYDVQQDDAtleGFt
457 cGxlLmNvbTAeFw0yMjAyMDUyMzQ5MDFaFw00OTA2MjMyMzQ5MDFaMGMxCzAJBgNV
458 BAYTAlVTMQswCQYDVQQIDAJDQTEUMBIGA1UEBwwLTG9zIEFuZ2VsZXMxGzAZBgNV
459 BAoMEnJpcHBsZWQtdW5pdC10ZXN0czEUMBIGA1UEAwwLZXhhbXBsZS5jb20wggEi
460 MA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQC0f2JBW2XNW2wT5/ajX2qxmUY+
461 aNJGfpV6gZ5CmwdQpbHrPPvJoskxwsCyr3GifzT/GtCpmb1fiu59uUAPxQEYCxiq
462 V+HchX4g4Vl27xKJ0P+usxuEED9v7TCteKum9u9eMZ8UDF0fspXcnWGs9fXlyoTj
463 uTRP1SBQllk44DPc/KzlrtH+QNXmr9XQnP8XvwWCgJXMx87voxEGiFFOVhkSSAOv
464 v+OUGgEuq0NPgwv2LHBlYHSdkoU9F5Z/TmkCAFMShbyoUjldIz2gcWXjN2tespGo
465 D6qYvasvPIpmcholBBkc0z8QDt+RNq+Wzrults7epJXy/u+txGK9cHCNlLCpAgMB
466 AAGjUzBRMB0GA1UdDgQWBBS1oydh+YyqDNOFKYOvOtVMWKqV4zAfBgNVHSMEGDAW
467 gBS1oydh+YyqDNOFKYOvOtVMWKqV4zAPBgNVHRMBAf8EBTADAQH/MA0GCSqGSIb3
468 DQEBCwUAA4IBAQCDPyGKQwQ8Lz0yEgvIl/Uo9BtwAzlvjrLM/39qhStLQqDGSs2Q
469 xFIbtjzjuLf5vR3q6OJ62CCvzqXgHkJ+hzVN/tAvyliGTdjJrK+xv1M5a+XipO2f
470 c9lb4gRbFL/DyoeoWgb1Rkv3gFf0FlCYH+ZUcYb9ZYCRlGtFgOcxJI2g+T7jSLFp
471 8+hSzQ6W5Sp9L6b5iJyCww1vjBvBqzNyZMNeB4gXGtd6z9vMDSvKboTdGD7wcFB+
472 mRMyNekaRw+Npy4Hjou5sx272cXHHmPCSF5TjwdaibSaGjx1k0Q50mOf7S9KG5b5
473 7X1e3FekJlaD02EBEhtkXURIxogOQALdFncj
474 -----END CERTIFICATE-----
475 )cert"};
476  return cert;
477  }
478 
479  static std::string const&
480  dh()
481  {
482  static std::string const dh{R"dh(
483 -----BEGIN DH PARAMETERS-----
484 MIIBCAKCAQEAp2I2fWEUZ3sCNfitSRC/MdAhJE/bS+NO0O2tWdIdlvmIFE6B5qhC
485 sGW9ojrQT8DTxBvGAcbjr/jagmlE3BV4oSnxyhP37G2mDvMOJ29J3NvFD/ZFAW0d
486 BvZJ1RNvMu29NmVCyt6/jgzcqrqnami9uD93aK+zaVrlPsPEYM8xB19HXwqsEYCL
487 ux2B7sqXm9Ts74HPg/EV+pcVon9phxNWxxgHlOvFc2QjZ3hXH++kzmJ4vs7N/XDB
488 xbEQ+TUZ5jbJGSeBqNFKFeuOUQGJ46Io0jBSYd4rSmKUXkvElQwR+n7KF3jy1uAt
489 /8hzd8tHn9TyW7Q2/CPkOA6dCXzltpOSowIBAg==
490 -----END DH PARAMETERS-----
491 )dh"};
492  return dh;
493  }
494 
495 private:
496  struct lambda
497  {
498  int id;
501  boost::asio::executor_work_guard<boost::asio::executor> work;
502  bool ssl;
503 
504  lambda(
505  int id_,
506  TrustedPublisherServer& self_,
507  socket_type&& sock_,
508  bool ssl_)
509  : id(id_)
510  , self(self_)
511  , sock(std::move(sock_))
512  , work(sock_.get_executor())
513  , ssl(ssl_)
514  {
515  }
516 
517  void
518  operator()()
519  {
520  self.do_peer(id, std::move(sock), ssl);
521  }
522  };
523 
524  void
526  {
527  if (ec || !acceptor_.is_open())
528  return;
529 
530  static int id_ = 0;
531  std::thread{lambda{++id_, *this, std::move(sock_), useSSL_}}.detach();
532  acceptor_.async_accept(
533  sock_,
535  error_code ec) {
536  if (auto p = wp.lock())
537  {
538  p->on_accept(ec);
539  }
540  });
541  }
542 
543  void
544  do_peer(int id, socket_type&& s, bool ssl)
545  {
546  using namespace boost::beast;
547  using namespace boost::asio;
548  socket_type sock(std::move(s));
549  flat_buffer sb;
550  error_code ec;
552 
553  if (ssl)
554  {
555  // Construct the stream around the socket
556  ssl_stream.emplace(sock, sslCtx_);
557  // Perform the SSL handshake
558  ssl_stream->handshake(ssl::stream_base::server, ec);
559  if (ec)
560  return;
561  }
562 
563  for (;;)
564  {
565  resp_type res;
566  req_type req;
567  try
568  {
569  if (ssl)
570  http::read(*ssl_stream, sb, req, ec);
571  else
572  http::read(sock, sb, req, ec);
573 
574  if (ec)
575  break;
576 
577  auto path = req.target().to_string();
578  res.insert("Server", "TrustedPublisherServer");
579  res.version(req.version());
580  res.keep_alive(req.keep_alive());
581  bool prepare = true;
582 
583  if (boost::starts_with(path, "/validators2"))
584  {
585  res.result(http::status::ok);
586  res.insert("Content-Type", "application/json");
587  if (path == "/validators2/bad")
588  res.body() = "{ 'bad': \"2']";
589  else if (path == "/validators2/missing")
590  res.body() = "{\"version\": 2}";
591  else
592  {
593  int refresh = 5;
594  constexpr char const* refreshPrefix =
595  "/validators2/refresh/";
596  if (boost::starts_with(path, refreshPrefix))
597  refresh = boost::lexical_cast<unsigned int>(
598  path.substr(strlen(refreshPrefix)));
599  res.body() = getList2_(refresh);
600  }
601  }
602  else if (boost::starts_with(path, "/validators"))
603  {
604  res.result(http::status::ok);
605  res.insert("Content-Type", "application/json");
606  if (path == "/validators/bad")
607  res.body() = "{ 'bad': \"1']";
608  else if (path == "/validators/missing")
609  res.body() = "{\"version\": 1}";
610  else
611  {
612  int refresh = 5;
613  constexpr char const* refreshPrefix =
614  "/validators/refresh/";
615  if (boost::starts_with(path, refreshPrefix))
616  refresh = boost::lexical_cast<unsigned int>(
617  path.substr(strlen(refreshPrefix)));
618  res.body() = getList_(refresh);
619  }
620  }
621  else if (boost::starts_with(path, "/textfile"))
622  {
623  prepare = false;
624  res.result(http::status::ok);
625  res.insert("Content-Type", "text/example");
626  // if huge was requested, lie about content length
627  std::uint64_t cl =
628  boost::starts_with(path, "/textfile/huge")
630  : 1024;
631  res.content_length(cl);
632  if (req.method() == http::verb::get)
633  {
634  std::stringstream body;
635  for (auto i = 0; i < 1024; ++i)
636  body << static_cast<char>(rand_int<short>(32, 126)),
637  res.body() = body.str();
638  }
639  }
640  else if (boost::starts_with(path, "/sleep/"))
641  {
642  auto const sleep_sec =
643  boost::lexical_cast<unsigned int>(path.substr(7));
645  std::chrono::seconds{sleep_sec});
646  }
647  else if (boost::starts_with(path, "/redirect"))
648  {
649  if (boost::ends_with(path, "/301"))
650  res.result(http::status::moved_permanently);
651  else if (boost::ends_with(path, "/302"))
652  res.result(http::status::found);
653  else if (boost::ends_with(path, "/307"))
654  res.result(http::status::temporary_redirect);
655  else if (boost::ends_with(path, "/308"))
656  res.result(http::status::permanent_redirect);
657 
658  std::stringstream location;
659  if (boost::starts_with(path, "/redirect_to/"))
660  {
661  location << path.substr(13);
662  }
663  else if (!boost::starts_with(path, "/redirect_nolo"))
664  {
665  location
666  << (ssl ? "https://" : "http://")
667  << local_endpoint()
668  << (boost::starts_with(path, "/redirect_forever/")
669  ? path
670  : "/validators");
671  }
672  if (!location.str().empty())
673  res.insert("Location", location.str());
674  }
675  else
676  {
677  // unknown request
678  res.result(boost::beast::http::status::not_found);
679  res.insert("Content-Type", "text/html");
680  res.body() = "The file '" + path + "' was not found";
681  }
682 
683  if (prepare)
684  res.prepare_payload();
685  }
686  catch (std::exception const& e)
687  {
688  res = {};
689  res.result(boost::beast::http::status::internal_server_error);
690  res.version(req.version());
691  res.insert("Server", "TrustedPublisherServer");
692  res.insert("Content-Type", "text/html");
693  res.body() =
694  std::string{"An internal error occurred"} + e.what();
695  res.prepare_payload();
696  }
697 
698  if (ssl)
699  write(*ssl_stream, res, ec);
700  else
701  write(sock, res, ec);
702 
703  if (ec || req.need_eof())
704  break;
705  }
706 
707  // Perform the SSL shutdown
708  if (ssl)
709  ssl_stream->shutdown(ec);
710  }
711 };
712 
715  boost::asio::io_context& ioc,
717  NetClock::time_point validUntil,
719  futures,
720  bool useSSL = false,
721  int version = 1,
722  bool immediateStart = true,
723  int sequence = 1)
724 {
725  auto const r = std::make_shared<TrustedPublisherServer>(
726  ioc, validators, validUntil, futures, useSSL, version, sequence);
727  if (immediateStart)
728  r->start();
729  return r;
730 }
731 
732 } // namespace test
733 } // namespace ripple
734 #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:241
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:327
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:207
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::add
void add(Serializer &s) const override
Definition: STObject.cpp:85
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::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:714
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:30
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