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