diff --git a/src/libxrpl/protocol/SField.cpp b/src/libxrpl/protocol/SField.cpp index 18226008504..537fa557fcc 100644 --- a/src/libxrpl/protocol/SField.cpp +++ b/src/libxrpl/protocol/SField.cpp @@ -72,7 +72,10 @@ TypedField::TypedField(private_access_tag_t pat, Args&&... args) // SFields which, for historical reasons, do not follow naming conventions. SField const sfInvalid(access, -1); SField const sfGeneric(access, 0); +// The following two fields aren't used anywhere, but they break tests/have +// downstream effects. SField const sfHash(access, STI_UINT256, 257, "hash"); +SField const sfIndex(access, STI_UINT256, 258, "index"); #include diff --git a/src/test/rpc/LedgerRPC_test.cpp b/src/test/rpc/LedgerRPC_test.cpp index c5e10198c49..41657468666 100644 --- a/src/test/rpc/LedgerRPC_test.cpp +++ b/src/test/rpc/LedgerRPC_test.cpp @@ -26,6 +26,7 @@ #include #include #include +#include #include #include #include @@ -1207,6 +1208,42 @@ class LedgerRPC_test : public beast::unit_test::suite checkErrorValue(jrr[jss::result], "malformedRequest", ""); } + { + // Failed, authorized_credentials contains string data + Json::Value jvParams; + jvParams[jss::ledger_index] = jss::validated; + jvParams[jss::deposit_preauth][jss::owner] = bob.human(); + jvParams[jss::deposit_preauth][jss::authorized_credentials] = + Json::arrayValue; + auto& arr( + jvParams[jss::deposit_preauth][jss::authorized_credentials]); + arr.append("foobar"); + + auto const jrr = + env.rpc("json", "ledger_entry", to_string(jvParams)); + checkErrorValue( + jrr[jss::result], "malformedAuthorizedCredentials", ""); + } + + { + // Failed, authorized_credentials contains arrays + Json::Value jvParams; + jvParams[jss::ledger_index] = jss::validated; + jvParams[jss::deposit_preauth][jss::owner] = bob.human(); + jvParams[jss::deposit_preauth][jss::authorized_credentials] = + Json::arrayValue; + auto& arr( + jvParams[jss::deposit_preauth][jss::authorized_credentials]); + Json::Value payload = Json::arrayValue; + payload.append(42); + arr.append(std::move(payload)); + + auto const jrr = + env.rpc("json", "ledger_entry", to_string(jvParams)); + checkErrorValue( + jrr[jss::result], "malformedAuthorizedCredentials", ""); + } + { // Failed, authorized_credentials is empty array Json::Value jvParams; @@ -1263,6 +1300,27 @@ class LedgerRPC_test : public beast::unit_test::suite jrr[jss::result], "malformedAuthorizedCredentials", ""); } + { + // Failed, issuer is not set + Json::Value jvParams; + jvParams[jss::ledger_index] = jss::validated; + jvParams[jss::deposit_preauth][jss::owner] = bob.human(); + + jvParams[jss::deposit_preauth][jss::authorized_credentials] = + Json::arrayValue; + auto& arr( + jvParams[jss::deposit_preauth][jss::authorized_credentials]); + + Json::Value jo; + jo[jss::credential_type] = strHex(std::string_view(credType)); + arr.append(std::move(jo)); + + auto const jrr = + env.rpc("json", "ledger_entry", to_string(jvParams)); + checkErrorValue( + jrr[jss::result], "malformedAuthorizedCredentials", ""); + } + { // Failed, issuer isn't string Json::Value jvParams; @@ -1285,6 +1343,30 @@ class LedgerRPC_test : public beast::unit_test::suite jrr[jss::result], "malformedAuthorizedCredentials", ""); } + { + // Failed, issuer is an array + Json::Value jvParams; + jvParams[jss::ledger_index] = jss::validated; + jvParams[jss::deposit_preauth][jss::owner] = bob.human(); + + jvParams[jss::deposit_preauth][jss::authorized_credentials] = + Json::arrayValue; + auto& arr( + jvParams[jss::deposit_preauth][jss::authorized_credentials]); + + Json::Value jo; + Json::Value payload = Json::arrayValue; + payload.append(42); + jo[jss::issuer] = std::move(payload); + jo[jss::credential_type] = strHex(std::string_view(credType)); + arr.append(std::move(jo)); + + auto const jrr = + env.rpc("json", "ledger_entry", to_string(jvParams)); + checkErrorValue( + jrr[jss::result], "malformedAuthorizedCredentials", ""); + } + { // Failed, issuer isn't valid encoded account Json::Value jvParams; @@ -1307,12 +1389,32 @@ class LedgerRPC_test : public beast::unit_test::suite jrr[jss::result], "malformedAuthorizedCredentials", ""); } + { + // Failed, credential_type is not set + Json::Value jvParams; + jvParams[jss::ledger_index] = jss::validated; + jvParams[jss::deposit_preauth][jss::owner] = bob.human(); + + jvParams[jss::deposit_preauth][jss::authorized_credentials] = + Json::arrayValue; + auto& arr( + jvParams[jss::deposit_preauth][jss::authorized_credentials]); + + Json::Value jo; + jo[jss::issuer] = issuer.human(); + arr.append(std::move(jo)); + + auto const jrr = + env.rpc("json", "ledger_entry", to_string(jvParams)); + checkErrorValue( + jrr[jss::result], "malformedAuthorizedCredentials", ""); + } + { // Failed, credential_type isn't string Json::Value jvParams; jvParams[jss::ledger_index] = jss::validated; jvParams[jss::deposit_preauth][jss::owner] = bob.human(); - jvParams[jss::deposit_preauth][jss::authorized] = alice.human(); jvParams[jss::deposit_preauth][jss::authorized_credentials] = Json::arrayValue; @@ -1326,7 +1428,32 @@ class LedgerRPC_test : public beast::unit_test::suite auto const jrr = env.rpc("json", "ledger_entry", to_string(jvParams)); - checkErrorValue(jrr[jss::result], "malformedRequest", ""); + checkErrorValue( + jrr[jss::result], "malformedAuthorizedCredentials", ""); + } + + { + // Failed, credential_type is an array + Json::Value jvParams; + jvParams[jss::ledger_index] = jss::validated; + jvParams[jss::deposit_preauth][jss::owner] = bob.human(); + + jvParams[jss::deposit_preauth][jss::authorized_credentials] = + Json::arrayValue; + auto& arr( + jvParams[jss::deposit_preauth][jss::authorized_credentials]); + + Json::Value jo; + jo[jss::issuer] = issuer.human(); + Json::Value payload = Json::arrayValue; + payload.append(42); + jo[jss::credential_type] = std::move(payload); + arr.append(std::move(jo)); + + auto const jrr = + env.rpc("json", "ledger_entry", to_string(jvParams)); + checkErrorValue( + jrr[jss::result], "malformedAuthorizedCredentials", ""); } { @@ -1334,7 +1461,6 @@ class LedgerRPC_test : public beast::unit_test::suite Json::Value jvParams; jvParams[jss::ledger_index] = jss::validated; jvParams[jss::deposit_preauth][jss::owner] = bob.human(); - jvParams[jss::deposit_preauth][jss::authorized] = alice.human(); jvParams[jss::deposit_preauth][jss::authorized_credentials] = Json::arrayValue; @@ -1348,7 +1474,8 @@ class LedgerRPC_test : public beast::unit_test::suite auto const jrr = env.rpc("json", "ledger_entry", to_string(jvParams)); - checkErrorValue(jrr[jss::result], "malformedRequest", ""); + checkErrorValue( + jrr[jss::result], "malformedAuthorizedCredentials", ""); } } diff --git a/src/test/rpc/ServerInfo_test.cpp b/src/test/rpc/ServerInfo_test.cpp index fbeb4220d16..e6f889c5bdf 100644 --- a/src/test/rpc/ServerInfo_test.cpp +++ b/src/test/rpc/ServerInfo_test.cpp @@ -198,6 +198,28 @@ admin = 127.0.0.1 BEAST_EXPECT( result[jss::result][jss::TYPES]["AccountID"].asUInt() == 8); + // check exception SFields + { + auto const fieldExists = [&](std::string name) { + for (auto& field : result[jss::result][jss::FIELDS]) + { + if (field[0u].asString() == name) + { + return true; + } + } + return false; + }; + BEAST_EXPECT(fieldExists("Generic")); + BEAST_EXPECT(fieldExists("Invalid")); + BEAST_EXPECT(fieldExists("ObjectEndMarker")); + BEAST_EXPECT(fieldExists("ArrayEndMarker")); + BEAST_EXPECT(fieldExists("taker_gets_funded")); + BEAST_EXPECT(fieldExists("taker_pays_funded")); + BEAST_EXPECT(fieldExists("hash")); + BEAST_EXPECT(fieldExists("index")); + } + // test that base_uint types are replaced with "Hash" prefix { auto const types = result[jss::result][jss::TYPES]; diff --git a/src/xrpld/rpc/handlers/LedgerEntry.cpp b/src/xrpld/rpc/handlers/LedgerEntry.cpp index 6a3b7a48686..5d03bbb189d 100644 --- a/src/xrpld/rpc/handlers/LedgerEntry.cpp +++ b/src/xrpld/rpc/handlers/LedgerEntry.cpp @@ -41,6 +41,12 @@ parseAuthorizeCredentials(Json::Value const& jv) STArray arr(sfAuthorizeCredentials, jv.size()); for (auto const& jo : jv) { + if (!jo.isObject() || // + !jo.isMember(jss::issuer) || !jo[jss::issuer].isString() || + !jo.isMember(jss::credential_type) || + !jo[jss::credential_type].isString()) + return {}; + auto const issuer = parseBase58(jo[jss::issuer].asString()); if (!issuer || !*issuer) return {};