Fix lowercase ctid (#977)

Fix #963
This commit is contained in:
cyan317
2023-11-07 16:10:12 +00:00
committed by GitHub
parent 0597a9d685
commit b016c1d7ba
5 changed files with 55 additions and 7 deletions

View File

@@ -66,7 +66,7 @@
// Max number of requests to queue up before rejecting further requests.
// Defaults to 0, which disables the limit.
"max_queue_size": 500,
// If request contains header with authorization, Clio will check if it matches this value's sha256 hash
// If request contains header with authorization, Clio will check if it matches the prefix 'Password ' + this value's sha256 hash
// If matches, the request will be considered as admin request
"admin_password": "xrp",
// If local_admin is true, Clio will consider requests come from 127.0.0.1 as admin requests

View File

@@ -24,6 +24,7 @@
#include <rpc/RPCHelpers.h>
#include <rpc/common/Types.h>
#include <rpc/common/Validators.h>
#include <util/JsonUtils.h>
namespace rpc {
@@ -224,8 +225,10 @@ private:
if (jsonObject.contains(JS(transaction)))
input.transaction = jv.at(JS(transaction)).as_string().c_str();
if (jsonObject.contains(JS(ctid)))
if (jsonObject.contains(JS(ctid))) {
input.ctid = jv.at(JS(ctid)).as_string().c_str();
input.ctid = util::toUpper(*input.ctid);
}
if (jsonObject.contains(JS(binary)))
input.binary = jv.at(JS(binary)).as_bool();

View File

@@ -37,6 +37,13 @@ toLower(std::string str)
return str;
}
inline std::string
toUpper(std::string str)
{
std::transform(std::begin(str), std::end(str), std::begin(str), [](unsigned char c) { return std::toupper(c); });
return str;
}
/**
* @brief Removes any detected secret information from a response JSON object.
*

View File

@@ -18,6 +18,7 @@
//==============================================================================
#include <fmt/format.h>
#include <util/JsonUtils.h>
#include <web/impl/AdminVerificationStrategy.h>
#include <ripple/protocol/digest.h>
@@ -39,7 +40,7 @@ PasswordAdminVerificationStrategy::PasswordAdminVerificationStrategy(std::string
std::memcpy(sha256.data(), d.data(), d.size());
passwordSha256_ = ripple::to_string(sha256);
// make sure it's uppercase
std::transform(passwordSha256_.begin(), passwordSha256_.end(), passwordSha256_.begin(), ::toupper);
passwordSha256_ = util::toUpper(std::move(passwordSha256_));
}
bool
@@ -55,11 +56,9 @@ PasswordAdminVerificationStrategy::isAdmin(RequestType const& request, std::stri
// Invalid Authorization header
return false;
}
userAuth.remove_prefix(passwordPrefix.size());
std::string userPasswordHash;
userPasswordHash.reserve(userAuth.size());
std::transform(userAuth.begin(), userAuth.end(), std::back_inserter(userPasswordHash), ::toupper);
return passwordSha256_ == userPasswordHash;
return passwordSha256_ == util::toUpper(userAuth);
}
std::shared_ptr<AdminVerificationStrategy>

View File

@@ -913,3 +913,42 @@ TEST_F(RPCTxTest, ViaCTID)
EXPECT_EQ(*output, json::parse(OUT));
});
}
TEST_F(RPCTxTest, ViaLowercaseCTID)
{
auto const rawBackendPtr = dynamic_cast<MockBackend*>(mockBackendPtr.get());
TransactionAndMetadata tx1;
tx1.metadata = CreateMetaDataForCreateOffer(CURRENCY, ACCOUNT, 1, 200, 300).getSerializer().peekData();
tx1.transaction =
CreateCreateOfferTransactionObject(ACCOUNT, 2, 100, CURRENCY, ACCOUNT2, 200, 300).getSerializer().peekData();
tx1.date = 123456;
tx1.ledgerSequence = SEQ_FROM_CTID;
TransactionAndMetadata tx2;
tx2.transaction = CreatePaymentTransactionObject(ACCOUNT, ACCOUNT2, 2, 3, 300).getSerializer().peekData();
tx2.metadata = CreatePaymentTransactionMetaObject(ACCOUNT, ACCOUNT2, 110, 30).getSerializer().peekData();
tx2.ledgerSequence = SEQ_FROM_CTID;
EXPECT_CALL(*rawBackendPtr, fetchAllTransactionsInLedger(SEQ_FROM_CTID, _)).WillOnce(Return(std::vector{tx1, tx2}));
auto const rawETLPtr = dynamic_cast<MockETLService*>(mockETLServicePtr.get());
ASSERT_NE(rawETLPtr, nullptr);
EXPECT_CALL(*rawETLPtr, getETLState).WillOnce(Return(etl::ETLState{.networkID = 2}));
std::string ctid(CTID);
std::transform(ctid.begin(), ctid.end(), ctid.begin(), ::tolower);
runSpawn([&, this](auto yield) {
auto const handler = AnyHandler{TestTxHandler{mockBackendPtr, mockETLServicePtr}};
auto const req = json::parse(fmt::format(
R"({{
"command": "tx",
"ctid": "{}"
}})",
ctid
));
auto const output = handler.process(req, Context{yield});
ASSERT_TRUE(output);
EXPECT_EQ(output->at("ctid").as_string(), CTID);
});
}