rippled
Loading...
Searching...
No Matches
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
20#ifndef RIPPLE_TEST_TRUSTED_PUBLISHER_SERVER_H_INCLUDED
21#define RIPPLE_TEST_TRUSTED_PUBLISHER_SERVER_H_INCLUDED
22
23#include <test/jtx/envconfig.h>
24
25#include <xrpl/basics/base64.h>
26#include <xrpl/basics/random.h>
27#include <xrpl/basics/strHex.h>
28#include <xrpl/protocol/PublicKey.h>
29#include <xrpl/protocol/SecretKey.h>
30#include <xrpl/protocol/Sign.h>
31
32#include <boost/algorithm/string/predicate.hpp>
33#include <boost/asio.hpp>
34#include <boost/asio/ip/tcp.hpp>
35#include <boost/asio/ssl/stream.hpp>
36#include <boost/beast/core/flat_buffer.hpp>
37#include <boost/beast/http.hpp>
38#include <boost/beast/ssl.hpp>
39#include <boost/beast/version.hpp>
40#include <boost/lexical_cast.hpp>
41
42#include <memory>
43#include <thread>
44
45namespace ripple {
46namespace test {
47
49 : public std::enable_shared_from_this<TrustedPublisherServer>
50{
51 using endpoint_type = boost::asio::ip::tcp::endpoint;
52 using address_type = boost::asio::ip::address;
53 using socket_type = boost::asio::ip::tcp::socket;
54
55 using req_type =
56 boost::beast::http::request<boost::beast::http::string_body>;
57 using resp_type =
58 boost::beast::http::response<boost::beast::http::string_body>;
59 using error_code = boost::system::error_code;
60
63 boost::asio::ip::tcp::acceptor acceptor_;
64 // Generates a version 1 validator list, using the int parameter as the
65 // actual version.
67 // Generates a version 2 validator list, using the int parameter as the
68 // actual version.
70
71 // The SSL context is required, and holds certificates
72 bool useSSL_;
73 boost::asio::ssl::context sslCtx_{boost::asio::ssl::context::tlsv12};
74
77
78 // Load a signed certificate into the ssl context, and configure
79 // the context for use with a server.
80 inline void
82 {
83 sslCtx_.set_password_callback(
84 [](std::size_t, boost::asio::ssl::context_base::password_purpose) {
85 return "test";
86 });
87
88 sslCtx_.set_options(
89 boost::asio::ssl::context::default_workarounds |
90 boost::asio::ssl::context::no_sslv2 |
91 boost::asio::ssl::context::single_dh_use);
92
93 sslCtx_.use_certificate_chain(
94 boost::asio::buffer(cert().data(), cert().size()));
95
96 sslCtx_.use_private_key(
97 boost::asio::buffer(key().data(), key().size()),
98 boost::asio::ssl::context::file_format::pem);
99
100 sslCtx_.use_tmp_dh(boost::asio::buffer(dh().data(), dh().size()));
101 }
102
103 struct BlobInfo
104 {
106 {
107 }
108
109 // base-64 encoded JSON containing the validator list.
111 // hex-encoded signature of the blob using the publisher's signing key
113 };
114
115public:
122
123 static std::string
125 PublicKey const& pk,
126 SecretKey const& sk,
127 PublicKey const& spk,
128 SecretKey const& ssk,
129 int seq)
130 {
132 st[sfSequence] = seq;
133 st[sfPublicKey] = pk;
134 st[sfSigningPubKey] = spk;
135
136 sign(st, HashPrefix::manifest, *publicKeyType(spk), ssk);
137 sign(
138 st,
140 *publicKeyType(pk),
141 sk,
142 sfMasterSignature);
143
144 Serializer s;
145 st.add(s);
146
147 return base64_encode(
148 std::string(static_cast<char const*>(s.data()), s.size()));
149 }
150
151 static Validator
153 {
154 auto const secret = randomSecretKey();
155 auto const masterPublic = derivePublicKey(KeyType::ed25519, secret);
156 auto const signingKeys = randomKeyPair(KeyType::secp256k1);
157 return {
158 masterPublic,
159 signingKeys.first,
161 masterPublic,
162 secret,
163 signingKeys.first,
164 signingKeys.second,
165 1)};
166 }
167
168 // TrustedPublisherServer must be accessed through a shared_ptr.
169 // This constructor is only public so std::make_shared has access.
170 // The function`make_TrustedPublisherServer` should be used to create
171 // instances.
172 // The `futures` member is expected to be structured as
173 // effective / expiration time point pairs for use in version 2 UNLs
175 boost::asio::io_context& ioc,
176 std::vector<Validator> const& validators,
177 NetClock::time_point validUntil,
180 futures,
181 bool useSSL = false,
182 int version = 1,
183 bool immediateStart = true,
184 int sequence = 1)
185 : sock_{ioc}
186 , ep_{boost::asio::ip::make_address(
187 ripple::test::getEnvLocalhostAddr()),
188 // 0 means let OS pick the port based on what's available
189 0}
190 , acceptor_{ioc}
191 , useSSL_{useSSL}
194 {
195 auto const keys = randomKeyPair(KeyType::secp256k1);
196 auto const manifest = makeManifestString(
197 publisherPublic_, publisherSecret_, keys.first, keys.second, 1);
198
199 std::vector<BlobInfo> blobInfo;
200 blobInfo.reserve(futures.size() + 1);
201 auto const [data, blob] = [&]() -> std::pair<std::string, std::string> {
202 // Builds the validator list, then encodes it into a blob.
203 std::string data = "{\"sequence\":" + std::to_string(sequence) +
204 ",\"expiration\":" +
205 std::to_string(validUntil.time_since_epoch().count()) +
206 ",\"validators\":[";
207
208 for (auto const& val : validators)
209 {
210 data += "{\"validation_public_key\":\"" +
211 strHex(val.masterPublic) + "\",\"manifest\":\"" +
212 val.manifest + "\"},";
213 }
214 data.pop_back();
215 data += "]}";
217 return std::make_pair(data, blob);
218 }();
219 auto const sig = strHex(sign(keys.first, keys.second, makeSlice(data)));
220 blobInfo.emplace_back(blob, sig);
221 getList_ = [blob = blob, sig, manifest, version](int interval) {
222 // Build the contents of a version 1 format UNL file
224 l << "{\"blob\":\"" << blob << "\"" << ",\"signature\":\"" << sig
225 << "\"" << ",\"manifest\":\"" << manifest << "\""
226 << ",\"refresh_interval\": " << interval
227 << ",\"version\":" << version << '}';
228 return l.str();
229 };
230 for (auto const& future : futures)
231 {
232 std::string data = "{\"sequence\":" + std::to_string(++sequence) +
233 ",\"effective\":" +
234 std::to_string(future.first.time_since_epoch().count()) +
235 ",\"expiration\":" +
236 std::to_string(future.second.time_since_epoch().count()) +
237 ",\"validators\":[";
238
239 // Use the same set of validators for simplicity
240 for (auto const& val : validators)
241 {
242 data += "{\"validation_public_key\":\"" +
243 strHex(val.masterPublic) + "\",\"manifest\":\"" +
244 val.manifest + "\"},";
245 }
246 data.pop_back();
247 data += "]}";
249 auto const sig =
250 strHex(sign(keys.first, keys.second, makeSlice(data)));
251 blobInfo.emplace_back(blob, sig);
252 }
253 getList2_ = [blobInfo, manifest, version](int interval) {
254 // Build the contents of a version 2 format UNL file
255 // Use `version + 1` to get 2 for most tests, but have
256 // a "bad" version number for tests that provide an override.
258 for (auto const& info : blobInfo)
259 {
260 l << "{\"blob\":\"" << info.blob << "\"" << ",\"signature\":\""
261 << info.signature << "\"},";
262 }
263 std::string blobs = l.str();
264 blobs.pop_back();
265 l.str(std::string());
266 l << "{\"blobs_v2\": [ " << blobs << "],\"manifest\":\"" << manifest
267 << "\"" << ",\"refresh_interval\": " << interval
268 << ",\"version\":" << (version + 1) << '}';
269 return l.str();
270 };
271
272 if (useSSL_)
273 {
274 // This holds the self-signed certificate used by the server
276 }
277 }
278
279 void
281 {
282 error_code ec;
283 acceptor_.open(ep_.protocol());
284 acceptor_.set_option(
285 boost::asio::ip::tcp::acceptor::reuse_address(true), ec);
286 acceptor_.bind(ep_);
287 acceptor_.listen(boost::asio::socket_base::max_listen_connections);
288 acceptor_.async_accept(
289 sock_,
291 error_code ec) {
292 if (auto p = wp.lock())
293 {
294 p->on_accept(ec);
295 }
296 });
297 }
298
299 void
301 {
302 error_code ec;
303 acceptor_.close(ec);
304 // TODO consider making this join
305 // any running do_peer threads
306 }
307
309 {
310 stop();
311 }
312
315 {
316 return acceptor_.local_endpoint();
317 }
318
319 PublicKey const&
321 {
322 return publisherPublic_;
323 }
324
325 /* CA/self-signed certs :
326 *
327 * The following three methods return certs/keys used by
328 * server and/or client to do the SSL handshake. These strings
329 * were generated using the script below. The server key and cert
330 * are used to configure the server (see load_server_certificate
331 * above). The ca.crt should be used to configure the client
332 * when ssl verification is enabled.
333 *
334 * note:
335 * cert() ==> server.crt
336 * key() ==> server.key
337 * ca_cert() ==> ca.crt
338 * dh() ==> dh.pem
339 ```
340 #!/usr/bin/env bash
341
342 mkdir -p /tmp/__certs__
343 pushd /tmp/__certs__
344 rm *.crt *.key *.pem
345
346 # generate CA
347 openssl genrsa -out ca.key 2048
348 openssl req -new -x509 -nodes -days 10000 -key ca.key -out ca.crt \
349 -subj "/C=US/ST=CA/L=Los
350 Angeles/O=rippled-unit-tests/CN=example.com" # generate private cert
351 openssl genrsa -out server.key 2048
352 # Generate certificate signing request
353 # since our unit tests can run in either ipv4 or ipv6 mode,
354 # we need to use extensions (subjectAltName) so that we can
355 # associate both ipv4 and ipv6 localhost addresses with this cert
356 cat >"extras.cnf" <<EOF
357 [req]
358 req_extensions = v3_req
359 distinguished_name = req_distinguished_name
360
361 [req_distinguished_name]
362
363 [v3_req]
364 subjectAltName = @alt_names
365
366 [alt_names]
367 DNS.1 = localhost
368 IP.1 = ::1
369 EOF
370 openssl req -new -key server.key -out server.csr \
371 -config extras.cnf \
372 -subj "/C=US/ST=California/L=San
373 Francisco/O=rippled-unit-tests/CN=127.0.0.1" \
374
375 # Create public certificate by signing with our CA
376 openssl x509 -req -days 10000 -in server.csr -CA ca.crt -CAkey ca.key
377 -out server.crt \ -extfile extras.cnf -set_serial 01 -extensions v3_req
378
379 # generate DH params for server
380 openssl dhparam -out dh.pem 2048
381 # verify certs
382 openssl verify -CAfile ca.crt server.crt
383 openssl x509 -in server.crt -text -noout
384 popd
385 ```
386 */
387 static std::string const&
389 {
390 static std::string const cert{R"cert(
391-----BEGIN CERTIFICATE-----
392MIIDczCCAlugAwIBAgIBATANBgkqhkiG9w0BAQsFADBjMQswCQYDVQQGEwJVUzEL
393MAkGA1UECAwCQ0ExFDASBgNVBAcMC0xvcyBBbmdlbGVzMRswGQYDVQQKDBJyaXBw
394bGVkLXVuaXQtdGVzdHMxFDASBgNVBAMMC2V4YW1wbGUuY29tMB4XDTIyMDIwNTIz
395NDk0M1oXDTQ5MDYyMzIzNDk0M1owazELMAkGA1UEBhMCVVMxEzARBgNVBAgMCkNh
396bGlmb3JuaWExFjAUBgNVBAcMDVNhbiBGcmFuY2lzY28xGzAZBgNVBAoMEnJpcHBs
397ZWQtdW5pdC10ZXN0czESMBAGA1UEAwwJMTI3LjAuMC4xMIIBIjANBgkqhkiG9w0B
398AQEFAAOCAQ8AMIIBCgKCAQEAueZ1hgRxwPgfeVx2AdngUYx7zYcaxcGYXyqi7izJ
399qTuBUcVcTRC/9Ip67RAEhfcgGudRS/a4Sv1ljwiRknSCcD/ZjzOFDLgbqYGSZNEs
400+T/qkwmc/L+Pbzf85HM7RjeGOd6NDQy9+oOBbUtqpTxcSGa4ln+YBFUSeoS1Aa9f
401n9vrxnWX9LgTu5dSWzH5TqFIti+Zs/v0PFjEivBIAOHPslmnzg/wCr99I6z9CAR3
402zVDe7+sxR//ivpeVE7FWjgkGixnUpZAqn69zNkJjMLNXETgOYskZdMIgbVOMr+0q
403S1Uj77mhwxKfpnB6TqUVvWLBvmBDzPjf0m0NcCf9UAjqPwIDAQABoyowKDAmBgNV
404HREEHzAdgglsb2NhbGhvc3SHEAAAAAAAAAAAAAAAAAAAAAEwDQYJKoZIhvcNAQEL
405BQADggEBAJkUFNS0CeEAKvo0ttzooXnCDH3esj2fwmLJQYLUGsAF8DFrFHTqZEcx
406hFRdr0ftEb/VKpV9dVF6xtSoMU56kHOnhbHEWADyqdKUkCDjrGBet5QdWmEwNV2L
407nYrwGQBAybMt/+1XMUV8HeLFJNHnyxfQYcW0fUsrmNGk8W0kzWuuq88qbhfXZAIx
408KiXrzYpLlM0RlpWXRfYQ6mTdSrRrLnEo5MklizVgNB8HYX78lxa06zP08oReQcfT
409GSGO8NEEq8BTVmp69zD1JyfvQcXzsi7WtkAX+/EOFZ7LesnZ6VsyjZ74wECCaQuD
410X1yu/XxHqchM+DOzzVw6wRKaM7Zsk80=
411-----END CERTIFICATE-----
412)cert"};
413 return cert;
414 }
415
416 static std::string const&
417 key()
419 static std::string const key{R"pkey(
420-----BEGIN RSA PRIVATE KEY-----
421MIIEpAIBAAKCAQEAueZ1hgRxwPgfeVx2AdngUYx7zYcaxcGYXyqi7izJqTuBUcVc
422TRC/9Ip67RAEhfcgGudRS/a4Sv1ljwiRknSCcD/ZjzOFDLgbqYGSZNEs+T/qkwmc
423/L+Pbzf85HM7RjeGOd6NDQy9+oOBbUtqpTxcSGa4ln+YBFUSeoS1Aa9fn9vrxnWX
4249LgTu5dSWzH5TqFIti+Zs/v0PFjEivBIAOHPslmnzg/wCr99I6z9CAR3zVDe7+sx
425R//ivpeVE7FWjgkGixnUpZAqn69zNkJjMLNXETgOYskZdMIgbVOMr+0qS1Uj77mh
426wxKfpnB6TqUVvWLBvmBDzPjf0m0NcCf9UAjqPwIDAQABAoIBAEC9MDpOu+quvg8+
427kt4MKSFdIhQuM7WguNaTe5AkSspDrcJzT7SK275mp259QIYCzMxxuA8TSZTb8A1C
428t6dgKbi7k6FaGMCYMRHzzK6NZfMbPi6cj245q9LYlZpdQswuM/FdPpPH1zUxrNYK
429CIaooZ6ZHzlSD/eaRMgkBQEkONHrZZtEinLIvKedwssPCaXkIISmt7MFQTDOlxkf
430K0Mt1mnRREPYbYSfPEEfIyy/KDIiB5AzgGt+uPOn8Oeb1pSqy69jpYcfhSj+bo4S
431UV6qTuTfBd4qkkNI6d/Z7DcDJFFlfloG/vVgGk/beWNnL2e39vzxiebB3w+MQn4F
432Wyx5mCECgYEA22z1/ihqt9LIAWtP42oSS3S/RxlFzpp5d7QfNqFnEoVgeRhQzleP
433pRJIzVXpMYBxexZYqZA/q8xBSggz+2gmRoYnW20VIzl14DsSH378ye3FRwJB0tLy
434dWU8DC7ZB5XQCTvI9UY3voJNToknODw7RCNO1h3V3T1y6JRLdcLskk8CgYEA2OLy
435aE5bvsUaLBSv7W9NFhSuZ0p9Y0pFmRgHI7g8i/AgRZ0BgiE8u8OZSHmPJPMaNs/h
436YIEIrlsgDci1PzwrUYseRp/aiVE1kyev09/ihqRXTPpLQu6h/d63KRe/06W3t5X3
437Dmfj49hH5zGPBI/0y1ECV/n0fwnRhxSv7fNr3RECgYBEuFpOUAAkNApZj29ErNqv
4388Q9ayAp5yx1RpQLFjEUIoub05e2gwgGF1DUiwc43p59iyjvYVwnp1x13fxwwl4yt
439N6Sp2H7vOja1lCp33MB0yVeohodw7InsxFjLA/0KiBvQWH32exhIPOzTNNcooIx7
440KYeuPUfWc0FCn/cGGZcXtwKBgQC1hp1k99CKBuY05suoanOWe5DNGud/ZvaBgD7Z
441gqYKadxY52QPyknOzZNJuZQ5VM8n+S2lW9osNFDLuKUaW/3Vrh6U9c4vCC1TEPB0
4424PnzvzDiWMsNJjWnCfU7C4meVyFBIt84y3NNjAQCWNRe+S3lzdOsVqRwf4NDD+l/
443uzEYQQKBgQCJczIlwobm1Y6O41hbGZhZL/CGMNS6Z0INi2yasV0WDqYlh7XayHMD
444cK55dMILcbHqeIBq/wR6sIhw6IJcaDBfFfrJiKKDilfij2lHxR2FQrEngtTCCRV+
445ZzARzaWhQPvbDqEtLJDWuXZNXfL8/PTIs5NmuKuQ8F4+gQJpkQgwaw==
446-----END RSA PRIVATE KEY-----
447)pkey"};
448 return key;
449 }
450
451 static std::string const&
452 ca_cert()
453 {
454 static std::string const cert{R"cert(
455-----BEGIN CERTIFICATE-----
456MIIDpzCCAo+gAwIBAgIUWc45WqaaNuaSLoFYTMC/Mjfqw/gwDQYJKoZIhvcNAQEL
457BQAwYzELMAkGA1UEBhMCVVMxCzAJBgNVBAgMAkNBMRQwEgYDVQQHDAtMb3MgQW5n
458ZWxlczEbMBkGA1UECgwScmlwcGxlZC11bml0LXRlc3RzMRQwEgYDVQQDDAtleGFt
459cGxlLmNvbTAeFw0yMjAyMDUyMzQ5MDFaFw00OTA2MjMyMzQ5MDFaMGMxCzAJBgNV
460BAYTAlVTMQswCQYDVQQIDAJDQTEUMBIGA1UEBwwLTG9zIEFuZ2VsZXMxGzAZBgNV
461BAoMEnJpcHBsZWQtdW5pdC10ZXN0czEUMBIGA1UEAwwLZXhhbXBsZS5jb20wggEi
462MA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQC0f2JBW2XNW2wT5/ajX2qxmUY+
463aNJGfpV6gZ5CmwdQpbHrPPvJoskxwsCyr3GifzT/GtCpmb1fiu59uUAPxQEYCxiq
464V+HchX4g4Vl27xKJ0P+usxuEED9v7TCteKum9u9eMZ8UDF0fspXcnWGs9fXlyoTj
465uTRP1SBQllk44DPc/KzlrtH+QNXmr9XQnP8XvwWCgJXMx87voxEGiFFOVhkSSAOv
466v+OUGgEuq0NPgwv2LHBlYHSdkoU9F5Z/TmkCAFMShbyoUjldIz2gcWXjN2tespGo
467D6qYvasvPIpmcholBBkc0z8QDt+RNq+Wzrults7epJXy/u+txGK9cHCNlLCpAgMB
468AAGjUzBRMB0GA1UdDgQWBBS1oydh+YyqDNOFKYOvOtVMWKqV4zAfBgNVHSMEGDAW
469gBS1oydh+YyqDNOFKYOvOtVMWKqV4zAPBgNVHRMBAf8EBTADAQH/MA0GCSqGSIb3
470DQEBCwUAA4IBAQCDPyGKQwQ8Lz0yEgvIl/Uo9BtwAzlvjrLM/39qhStLQqDGSs2Q
471xFIbtjzjuLf5vR3q6OJ62CCvzqXgHkJ+hzVN/tAvyliGTdjJrK+xv1M5a+XipO2f
472c9lb4gRbFL/DyoeoWgb1Rkv3gFf0FlCYH+ZUcYb9ZYCRlGtFgOcxJI2g+T7jSLFp
4738+hSzQ6W5Sp9L6b5iJyCww1vjBvBqzNyZMNeB4gXGtd6z9vMDSvKboTdGD7wcFB+
474mRMyNekaRw+Npy4Hjou5sx272cXHHmPCSF5TjwdaibSaGjx1k0Q50mOf7S9KG5b5
4757X1e3FekJlaD02EBEhtkXURIxogOQALdFncj
476-----END CERTIFICATE-----
477)cert"};
478 return cert;
479 }
480
481 static std::string const&
482 dh()
483 {
484 static std::string const dh{R"dh(
485-----BEGIN DH PARAMETERS-----
486MIIBCAKCAQEAp2I2fWEUZ3sCNfitSRC/MdAhJE/bS+NO0O2tWdIdlvmIFE6B5qhC
487sGW9ojrQT8DTxBvGAcbjr/jagmlE3BV4oSnxyhP37G2mDvMOJ29J3NvFD/ZFAW0d
488BvZJ1RNvMu29NmVCyt6/jgzcqrqnami9uD93aK+zaVrlPsPEYM8xB19HXwqsEYCL
489ux2B7sqXm9Ts74HPg/EV+pcVon9phxNWxxgHlOvFc2QjZ3hXH++kzmJ4vs7N/XDB
490xbEQ+TUZ5jbJGSeBqNFKFeuOUQGJ46Io0jBSYd4rSmKUXkvElQwR+n7KF3jy1uAt
491/8hzd8tHn9TyW7Q2/CPkOA6dCXzltpOSowIBAg==
492-----END DH PARAMETERS-----
493)dh"};
494 return dh;
495 }
496
497private:
498 struct lambda
499 {
500 int id;
501 TrustedPublisherServer& self;
503 boost::asio::executor_work_guard<boost::asio::executor> work;
504 bool ssl;
505
506 lambda(
507 int id_,
508 TrustedPublisherServer& self_,
510 bool ssl_)
511 : id(id_)
512 , self(self_)
513 , sock(std::move(sock_))
514 , work(sock_.get_executor())
515 , ssl(ssl_)
516 {
517 }
518
519 void
520 operator()()
521 {
522 self.do_peer(id, std::move(sock), ssl);
523 }
524 };
525
526 void
528 {
529 if (ec || !acceptor_.is_open())
530 return;
531
532 static int id_ = 0;
533 std::thread{lambda{++id_, *this, std::move(sock_), useSSL_}}.detach();
534 acceptor_.async_accept(
535 sock_,
537 error_code ec) {
538 if (auto p = wp.lock())
539 {
540 p->on_accept(ec);
541 }
542 });
543 }
544
545 void
546 do_peer(int id, socket_type&& s, bool ssl)
547 {
548 using namespace boost::beast;
549 using namespace boost::asio;
550 socket_type sock(std::move(s));
551 flat_buffer sb;
552 error_code ec;
554
555 if (ssl)
556 {
557 // Construct the stream around the socket
558 ssl_stream.emplace(sock, sslCtx_);
559 // Perform the SSL handshake
560 ssl_stream->handshake(ssl::stream_base::server, ec);
561 if (ec)
562 return;
563 }
564
565 for (;;)
566 {
567 resp_type res;
568 req_type req;
569 try
570 {
571 if (ssl)
572 http::read(*ssl_stream, sb, req, ec);
573 else
574 http::read(sock, sb, req, ec);
575
576 if (ec)
577 break;
578
579 std::string_view const path = req.target();
580 res.insert("Server", "TrustedPublisherServer");
581 res.version(req.version());
582 res.keep_alive(req.keep_alive());
583 bool prepare = true;
584
585 if (boost::starts_with(path, "/validators2"))
586 {
587 res.result(http::status::ok);
588 res.insert("Content-Type", "application/json");
589 if (path == "/validators2/bad")
590 res.body() = "{ 'bad': \"2']";
591 else if (path == "/validators2/missing")
592 res.body() = "{\"version\": 2}";
593 else
594 {
595 int refresh = 5;
596 constexpr char const* refreshPrefix =
597 "/validators2/refresh/";
598 if (boost::starts_with(path, refreshPrefix))
599 refresh = boost::lexical_cast<unsigned int>(
600 path.substr(strlen(refreshPrefix)));
601 res.body() = getList2_(refresh);
602 }
603 }
604 else if (boost::starts_with(path, "/validators"))
605 {
606 res.result(http::status::ok);
607 res.insert("Content-Type", "application/json");
608 if (path == "/validators/bad")
609 res.body() = "{ 'bad': \"1']";
610 else if (path == "/validators/missing")
611 res.body() = "{\"version\": 1}";
612 else
613 {
614 int refresh = 5;
615 constexpr char const* refreshPrefix =
616 "/validators/refresh/";
617 if (boost::starts_with(path, refreshPrefix))
618 refresh = boost::lexical_cast<unsigned int>(
619 path.substr(strlen(refreshPrefix)));
620 res.body() = getList_(refresh);
621 }
622 }
623 else if (boost::starts_with(path, "/textfile"))
624 {
625 prepare = false;
626 res.result(http::status::ok);
627 res.insert("Content-Type", "text/example");
628 // if huge was requested, lie about content length
629 std::uint64_t cl =
630 boost::starts_with(path, "/textfile/huge")
632 : 1024;
633 res.content_length(cl);
634 if (req.method() == http::verb::get)
635 {
637 for (auto i = 0; i < 1024; ++i)
638 body << static_cast<char>(rand_int<short>(32, 126)),
639 res.body() = body.str();
640 }
641 }
642 else if (boost::starts_with(path, "/sleep/"))
643 {
644 auto const sleep_sec =
645 boost::lexical_cast<unsigned int>(path.substr(7));
647 std::chrono::seconds(sleep_sec));
648 }
649 else if (boost::starts_with(path, "/redirect"))
650 {
651 if (boost::ends_with(path, "/301"))
652 res.result(http::status::moved_permanently);
653 else if (boost::ends_with(path, "/302"))
654 res.result(http::status::found);
655 else if (boost::ends_with(path, "/307"))
656 res.result(http::status::temporary_redirect);
657 else if (boost::ends_with(path, "/308"))
658 res.result(http::status::permanent_redirect);
659
660 std::stringstream location;
661 if (boost::starts_with(path, "/redirect_to/"))
662 {
663 location << path.substr(13);
664 }
665 else if (!boost::starts_with(path, "/redirect_nolo"))
666 {
667 location
668 << (ssl ? "https://" : "http://")
669 << local_endpoint()
670 << (boost::starts_with(path, "/redirect_forever/")
671 ? path
672 : "/validators");
673 }
674 if (!location.str().empty())
675 res.insert("Location", location.str());
676 }
677 else
678 {
679 // unknown request
680 res.result(boost::beast::http::status::not_found);
681 res.insert("Content-Type", "text/html");
682 res.body() = "The file '" + std::string(path) +
683 "' was not "
684 "found";
685 }
686
687 if (prepare)
688 res.prepare_payload();
689 }
690 catch (std::exception const& e)
691 {
692 res = {};
693 res.result(boost::beast::http::status::internal_server_error);
694 res.version(req.version());
695 res.insert("Server", "TrustedPublisherServer");
696 res.insert("Content-Type", "text/html");
697 res.body() =
698 std::string{"An internal error occurred"} + e.what();
699 res.prepare_payload();
700 }
701
702 if (ssl)
703 write(*ssl_stream, res, ec);
704 else
705 write(sock, res, ec);
706
707 if (ec || req.need_eof())
708 break;
709 }
710
711 // Perform the SSL shutdown
712 if (ssl)
713 ssl_stream->shutdown(ec);
714 }
715};
716
719 boost::asio::io_context& ioc,
721 NetClock::time_point validUntil,
723 futures,
724 bool useSSL = false,
725 int version = 1,
726 bool immediateStart = true,
727 int sequence = 1)
728{
730 ioc, validators, validUntil, futures, useSSL, version, sequence);
731 if (immediateStart)
732 r->start();
733 return r;
734}
735
736} // namespace test
737} // namespace ripple
738#endif
A public key.
Definition PublicKey.h:61
void add(Serializer &s) const override
Definition STObject.cpp:141
A secret key.
Definition SecretKey.h:38
std::size_t size() const noexcept
Definition Serializer.h:72
void const * data() const noexcept
Definition Serializer.h:78
boost::beast::http::request< boost::beast::http::string_body > req_type
void do_peer(int id, socket_type &&s, bool ssl)
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)
boost::asio::ip::tcp::socket socket_type
boost::beast::http::response< boost::beast::http::string_body > resp_type
std::function< std::string(int)> getList2_
boost::asio::ip::tcp::acceptor acceptor_
std::function< std::string(int)> getList_
boost::asio::ip::tcp::endpoint endpoint_type
static std::string makeManifestString(PublicKey const &pk, SecretKey const &sk, PublicKey const &spk, SecretKey const &ssk, int seq)
Set the regular signature on a JTx.
Definition sig.h:35
T emplace_back(T... args)
T emplace(T... args)
T insert(T... args)
T is_same_v
T make_pair(T... args)
T max(T... args)
T move(T... args)
void write(nudb::detail::ostream &os, std::size_t t)
Definition varint.h:134
auto const data
General field definitions, or fields used in multiple transaction namespaces.
void sign(Json::Value &jv, Account const &account)
Sign automatically.
Definition utility.cpp:47
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)
char const * getEnvLocalhostAddr()
Definition envconfig.h:36
Use hash_* containers for keys that do not need a cryptographically secure hashing algorithm.
Definition algorithm.h:25
PublicKey derivePublicKey(KeyType type, SecretKey const &sk)
Derive the public key from a secret key.
std::optional< KeyType > publicKeyType(Slice const &slice)
Returns the type of public key.
std::string strHex(FwdIt begin, FwdIt end)
Definition strHex.h:30
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:244
SecretKey randomSecretKey()
Create a secret key using secure random numbers.
KeyType
Definition KeyType.h:28
std::string base64_encode(std::uint8_t const *data, std::size_t len)
std::pair< PublicKey, SecretKey > randomKeyPair(KeyType type)
Create a key pair using secure random numbers.
SField const sfGeneric
@ manifest
Manifest.
STL namespace.
T pop_back(T... args)
T reserve(T... args)
T sleep_for(T... args)
T str(T... args)
T strlen(T... args)
boost::asio::executor_work_guard< boost::asio::executor > work
lambda(int id_, TrustedPublisherServer &self_, socket_type &&sock_, bool ssl_)
Set the sequence number on a JTx.
Definition seq.h:34
T time_since_epoch(T... args)
T to_string(T... args)
T what(T... args)