3#include <xrpld/app/main/DBInit.h>
4#include <xrpld/app/misc/Manifest.h>
5#include <xrpld/app/misc/ValidatorList.h>
6#include <xrpld/app/rdb/Wallet.h>
8#include <xrpl/basics/base64.h>
9#include <xrpl/basics/contract.h>
10#include <xrpl/protocol/STExchange.h>
11#include <xrpl/protocol/SecretKey.h>
12#include <xrpl/protocol/Sign.h>
14#include <boost/algorithm/string.hpp>
15#include <boost/filesystem.hpp>
16#include <boost/utility/in_place_factory.hpp>
39 using namespace boost::filesystem;
40 if (!exists(dbPath) || !is_directory(dbPath) || !is_empty(dbPath))
48 using namespace boost::filesystem;
51 create_directory(dbPath);
55 if (!is_directory(dbPath))
58 Throw<std::runtime_error>(
"Cannot create directory: " + dbPath.string());
61 static boost::filesystem::path
64 return boost::filesystem::current_path() /
"manifest_test_databases";
95 st[sfSigningPubKey] = spk;
113 st[sfPublicKey] = pk;
131 st[sfPublicKey] = pk;
142 return std::move(*r);
143 Throw<std::runtime_error>(
"Could not create a revocation manifest");
154 bool invalidSig =
false)
160 st[sfSequence] =
seq;
161 st[sfPublicKey] = pk;
162 st[sfSigningPubKey] = spk;
176 return std::move(*r);
177 Throw<std::runtime_error>(
"Could not create a manifest");
205 cache.for_each_manifest([&result](
Manifest const& man) { result.
push_back(&man); });
210 return lhs->serialized < rhs->serialized;
216 auto& app = env.
app();
223 m.
save(*dbCon,
"ValidatorManifests", [&unl](
PublicKey const& pubKey) {
return unl->listed(pubKey); });
227 loaded.
load(*dbCon,
"ValidatorManifests");
232 for (
auto const& man : loadedManifests)
233 BEAST_EXPECT(man->revoked());
240 for (
auto const& man : inManifests)
242 unl->load({}, s1, keys);
244 m.
save(*dbCon,
"ValidatorManifests", [&unl](
PublicKey const& pubKey) {
return unl->listed(pubKey); });
246 loaded.
load(*dbCon,
"ValidatorManifests");
251 if (inManifests.
size() == loadedManifests.
size())
256 loadedManifests.
begin(),
270 BEAST_EXPECT(!loaded.
load(*dbCon,
"ValidatorManifests", badManifest, emptyRevocation));
278 BEAST_EXPECT(loaded.
load(*dbCon,
"ValidatorManifests", cfgManifest, emptyRevocation));
286 BEAST_EXPECT(!loaded.
load(*dbCon,
"ValidatorManifests", emptyManifest, badRevocation));
294 BEAST_EXPECT(!loaded.
load(*dbCon,
"ValidatorManifests", emptyManifest, nonRevocation));
295 BEAST_EXPECT(!loaded.
revoked(pk));
298 BEAST_EXPECT(!loaded.
load(*dbCon,
"ValidatorManifests", emptyManifest, badSigRevocation));
299 BEAST_EXPECT(!loaded.
revoked(pk));
302 BEAST_EXPECT(loaded.
load(*dbCon,
"ValidatorManifests", emptyManifest, cfgRevocation));
304 BEAST_EXPECT(loaded.
revoked(pk));
307 boost::filesystem::remove(
getDatabasePath() / boost::filesystem::path(dbName));
321 st[sfPublicKey] = pk;
322 st[sfSigningPubKey] = kp.first;
330 BEAST_EXPECT(
strHex(masterSig) ==
strHex(m.getMasterSignature()));
366 BEAST_EXPECT(cache.
getMasterKey(kp0.first) == kp0.first);
375 BEAST_EXPECT(cache.
getMasterKey(kp0.first) == kp0.first);
381 BEAST_EXPECT(cache.
revoked(pk));
383 BEAST_EXPECT(cache.
getMasterKey(kp0.first) == kp0.first);
384 BEAST_EXPECT(cache.
getMasterKey(kp1.first) == kp1.first);
393 auto const valSecret =
399 "eyJ2YWxpZGF0aW9uX3NlY3JldF9rZXkiOiI5ZWQ0NWY4NjYyNDFjYzE4YTI3ND"
401 " \tQzODdjMDYyNTkwNzk3MmY0ZTcxOTAyMzFmYWE5Mzc0NTdmYTlkYWY2Iiwib"
403 "\tc3QiOiJKQUFBQUFGeEllMUZ0d21pbXZHdEgyaUNjTUpxQzlnVkZLaWxHZncx"
406 "hYWExwbGMyR25NaEFrRTFhZ3FYeEJ3RHdEYklENk9NU1l1TTBGREFscEFnTms4"
408 "bjdNTzJmZGtjd1JRSWhBT25ndTlzQUtxWFlvdUorbDJWMFcrc0FPa1ZCK1pSUz"
410 "hsSkFmVXNYZkFpQnNWSkdlc2FhZE9KYy9hQVpva1MxdnltR21WcmxIUEtXWDNZ"
412 "NmluOEhBU1FLUHVnQkQ2N2tNYVJGR3ZtcEFUSGxHS0pkdkRGbFdQWXk1QXFEZW"
414 "VUSmEydzBpMjFlcTNNWXl3TFZKWm5GT3I3QzBrdzJBaVR6U0NqSXpkaXRROD0i"
418 "JAAAAAFxIe1FtwmimvGtH2iCcMJqC9gVFKilGfw1/"
419 "vCxHXXLplc2GnMhAkE1agqXxBwD"
420 "wDbID6OMSYuM0FDAlpAgNk8SKFn7MO2fdkcwRQIhAOngu9sAKqXYouJ+l2V0W+"
422 "+ZRS6PShlJAfUsXfAiBsVJGesaadOJc/"
423 "aAZokS1vymGmVrlHPKWX3Yywu6in8HASQKPu"
424 "gBD67kMaRFGvmpATHlGKJdvDFlWPYy5AqDedFv5TJa2w0i21eq3MYywLVJZnFO"
430 BEAST_EXPECT(token->validationSecret == *valSecret);
431 BEAST_EXPECT(token->manifest ==
manifest);
453 st[sfPublicKey] = pk;
454 st[sfSigningPubKey] = spk;
457 st[sfVersion] = version;
484 std::array<std::uint8_t, 33> const badKey{0x99, 0x30, 0xE7, 0xFC, 0x9D, 0x56, 0xBB, 0x25, 0xD6, 0x89, 0x3B,
485 0xA3, 0xF3, 0x17, 0xAE, 0x5B, 0xCF, 0x33, 0xB3, 0x29, 0x1B, 0xD6,
486 0x3D, 0xB3, 0x26, 0x54, 0xA3, 0x13, 0x22, 0x2F, 0x7F, 0xD0, 0x20};
490 0x03, 0x30, 0xE7, 0xFC, 0x9D, 0x56, 0xBB, 0x25, 0xD6, 0x89, 0x3B, 0xA3, 0xF3, 0x17, 0xAE, 0x5B};
492 auto toString = [](
STObject const& st) {
499 for (
auto const keyType : keyTypes)
504 for (
auto const sKeyType : keyTypes)
511 bool noSigningPublic =
false,
512 bool noSignature =
false) {
514 st[sfSequence] =
seq;
515 st[sfPublicKey] = pk;
520 if (!noSigningPublic)
521 st[sfSigningPubKey] = spk;
532 testcase <<
"deserializeManifest: normal manifest (" <<
to_string(keyType) <<
" + "
536 auto const st = buildManifestObject(++sequence,
std::nullopt);
538 auto const m = toString(st);
542 BEAST_EXPECT(
manifest->masterKey == pk);
543 BEAST_EXPECT(
manifest->signingKey == spk);
544 BEAST_EXPECT(
manifest->sequence == sequence);
545 BEAST_EXPECT(
manifest->serialized == m);
546 BEAST_EXPECT(
manifest->domain.empty());
551 auto const st = buildManifestObject(++sequence,
std::string{});
557 auto const st = buildManifestObject(++sequence,
std::string{
"a.b"});
562 auto const st = buildManifestObject(++sequence, s +
".example.com");
567 auto const st = buildManifestObject(++sequence, s +
".example.com");
571 auto const st = buildManifestObject(++sequence,
std::string{
"example.com"});
575 auto const m = toString(st);
579 BEAST_EXPECT(
manifest->masterKey == pk);
580 BEAST_EXPECT(
manifest->signingKey == spk);
581 BEAST_EXPECT(
manifest->sequence == sequence);
582 BEAST_EXPECT(
manifest->serialized == m);
583 BEAST_EXPECT(
manifest->domain ==
"example.com");
589 badSigSt[sfSequence] = sequence + 1;
591 auto const m = toString(badSigSt);
595 BEAST_EXPECT(
manifest->masterKey == pk);
596 BEAST_EXPECT(
manifest->signingKey == spk);
597 BEAST_EXPECT(
manifest->sequence == sequence + 1);
598 BEAST_EXPECT(
manifest->serialized == m);
599 BEAST_EXPECT(
manifest->domain ==
"example.com");
605 BEAST_EXPECT(badSt.delField(sfSequence));
611 BEAST_EXPECT(badSt.delField(sfPublicKey));
623 badSt[sfPublicKey] =
makeSlice(shortKey);
629 BEAST_EXPECT(badSt.delField(sfSigningPubKey));
635 badSt[sfSigningPubKey] =
makeSlice(badKey);
641 badSt[sfSigningPubKey] =
makeSlice(shortKey);
647 BEAST_EXPECT(badSt.delField(sfMasterSignature));
653 BEAST_EXPECT(badSt.delField(sfSignature));
659 st[sfSequence] = 314159;
660 st[sfPublicKey] = pk;
661 st[sfSigningPubKey] = pk;
672 testcase <<
"deserializeManifest: revocation manifest (" <<
to_string(keyType) <<
" + "
680 auto const m = toString(st);
684 BEAST_EXPECT(
manifest->masterKey == pk);
688 BEAST_EXPECT(!
manifest->signingKey);
690 BEAST_EXPECT(
manifest->domain.empty());
691 BEAST_EXPECT(
manifest->serialized == m);
732 st[sfPublicKey] = pk1;
734 st[sfSigningPubKey] = pk2;
745 BEAST_EXPECT(test(
"example.com"));
746 BEAST_EXPECT(test(
"test.example.com"));
747 BEAST_EXPECT(test(
"example-domain.com"));
748 BEAST_EXPECT(test(
"xn--mxavchb.gr"));
749 BEAST_EXPECT(test(
"test.xn--mxavchb.gr"));
750 BEAST_EXPECT(test(
"123.gr"));
751 BEAST_EXPECT(test(
"x.yz"));
752 BEAST_EXPECT(test(
std::string(63,
'a') +
".example.com"));
756 BEAST_EXPECT(!test(
"example"));
759 BEAST_EXPECT(!test(
".com"));
760 BEAST_EXPECT(!test(
".example.com"));
763 BEAST_EXPECT(!test(
"example.com."));
766 BEAST_EXPECT(!test(
"-example.com"));
767 BEAST_EXPECT(!test(
"example-.com"));
770 BEAST_EXPECT(!test(
"double..periods.example.com"));
773 BEAST_EXPECT(!test(
"example.x"));
774 BEAST_EXPECT(!test(
"example." +
std::string(64,
'a')));
777 BEAST_EXPECT(!test(
"example.com-org"));
778 BEAST_EXPECT(!test(
"bang!.com"));
779 BEAST_EXPECT(!test(
"bang!.example.com"));
782 BEAST_EXPECT(!test(
"a.b"));
785 BEAST_EXPECT(!test(
std::string(64,
'a') +
".com"));
786 BEAST_EXPECT(!test(
std::string(64,
'a') +
".example.com"));
826 auto const fake = s_b2.serialized +
'\0';
832 BEAST_EXPECT(cache.
sequence() > seq0);
836 BEAST_EXPECT(cache.
sequence() == seq1);
846 BEAST_EXPECT(!cache.
revoked(pk_a));
847 BEAST_EXPECT(s_aMax.revoked());
852 BEAST_EXPECT(cache.
revoked(pk_a));
testcase_t testcase
Memberspace for declaring test cases.
void fail(String const &reason, char const *file, int line)
Record a failure.
Remembers manifests with the highest sequence number.
bool load(DatabaseCon &dbCon, std::string const &dbTable, std::string const &configManifest, std::vector< std::string > const &configRevocation)
Populate manifest cache with manifests in database and config.
std::optional< PublicKey > getSigningKey(PublicKey const &pk) const
Returns master key's current signing key.
ManifestDisposition applyManifest(Manifest m)
Add manifest to cache.
PublicKey getMasterKey(PublicKey const &pk) const
Returns ephemeral signing key's master public key.
std::uint32_t sequence() const
A monotonically increasing number used to detect new manifests.
void save(DatabaseCon &dbCon, std::string const &dbTable, std::function< bool(PublicKey const &)> const &isTrusted)
Save cached manifests to database.
bool revoked(PublicKey const &pk) const
Returns true if master key has been revoked in a manifest.
void addWithoutSigningFields(Serializer &s) const
void add(Serializer &s) const override
Slice slice() const noexcept
std::size_t size() const noexcept
void const * data() const noexcept
std::string makeManifestString(PublicKey const &pk, SecretKey const &sk, PublicKey const &spk, SecretKey const &ssk, int seq)
void testManifestDeserialization()
void testLoadStore(ManifestCache &m)
static PublicKey randomMasterKey()
void run() override
Runs the suite.
void testValidatorToken()
void testManifestDomainNames()
std::string makeRevocationString(SecretKey const &sk, KeyType type, bool invalidSig=false)
static void setupDatabaseDir(boost::filesystem::path const &dbPath)
static void cleanupDatabaseDir(boost::filesystem::path const &dbPath)
Manifest makeManifest(SecretKey const &sk, KeyType type, SecretKey const &ssk, KeyType stype, int seq, bool invalidSig=false)
static PublicKey randomNode()
static boost::filesystem::path getDatabasePath()
void testManifestVersioning()
Manifest clone(Manifest const &m)
Manifest makeRevocation(SecretKey const &sk, KeyType type, bool invalidSig=false)
A transaction testing environment.
ManualTimeKeeper & timeKeeper()
beast::Journal const journal
Set the regular signature on a JTx.
void sign(Json::Value &jv, Account const &account, Json::Value &sigObject)
Sign automatically into a specific Json field of the jv object.
Use hash_* containers for keys that do not need a cryptographically secure hashing algorithm.
std::pair< PublicKey, SecretKey > randomKeyPair(KeyType type)
Create a key pair using secure random numbers.
PublicKey derivePublicKey(KeyType type, SecretKey const &sk)
Derive the public key from a secret key.
Seed randomSeed()
Create a seed using secure random numbers.
std::string to_string(base_uint< Bits, Tag > const &a)
std::string strHex(FwdIt begin, FwdIt end)
bool verify(PublicKey const &publicKey, Slice const &m, Slice const &sig) noexcept
Verify a signature on a message.
std::string toBase58(AccountID const &v)
Convert AccountID to base58 checked string.
SecretKey generateSecretKey(KeyType type, Seed const &seed)
Generate a new secret key deterministically.
std::string base64_encode(std::uint8_t const *data, std::size_t len)
std::optional< KeyType > publicKeyType(Slice const &slice)
Returns the type of public key.
std::optional< Manifest > deserializeManifest(Slice s, beast::Journal journal)
Constructs Manifest from serialized string.
std::optional< ValidatorToken > loadValidatorToken(std::vector< std::string > const &blob, beast::Journal journal)
SecretKey randomSecretKey()
Create a secret key using secure random numbers.
std::unique_ptr< DatabaseCon > makeTestWalletDB(DatabaseCon::Setup const &setup, std::string const &dbname, beast::Journal j)
makeTestWalletDB Opens a test wallet database with an arbitrary name.
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)
@ badMasterKey
The master key is not acceptable to us.
@ stale
Sequence is too old.
@ accepted
Manifest is valid.
@ badEphemeralKey
The ephemeral key is not acceptable to us.
@ invalid
Timely, but invalid signature.
boost::filesystem::path dataDir
PublicKey masterKey
The master key associated with this manifest.
std::string serialized
The manifest in serialized form.
std::string domain
The domain, if one was specified in the manifest; empty otherwise.
std::optional< PublicKey > signingKey
The ephemeral key associated with this manifest.
std::uint32_t sequence
The sequence number of this manifest.
Set the sequence number on a JTx.