mirror of
https://github.com/XRPLF/clio.git
synced 2025-11-04 11:55:51 +00:00
fix: Add more account check (#1543)
Make sure all char is alphanumeric for account
This commit is contained in:
@@ -24,6 +24,7 @@
|
|||||||
#include "rpc/Errors.hpp"
|
#include "rpc/Errors.hpp"
|
||||||
#include "rpc/JS.hpp"
|
#include "rpc/JS.hpp"
|
||||||
#include "rpc/common/Types.hpp"
|
#include "rpc/common/Types.hpp"
|
||||||
|
#include "util/AccountUtils.hpp"
|
||||||
#include "util/Profiler.hpp"
|
#include "util/Profiler.hpp"
|
||||||
#include "util/log/Logger.hpp"
|
#include "util/log/Logger.hpp"
|
||||||
#include "web/Context.hpp"
|
#include "web/Context.hpp"
|
||||||
@@ -186,14 +187,14 @@ accountFromStringStrict(std::string const& account)
|
|||||||
if (blob && ripple::publicKeyType(ripple::makeSlice(*blob))) {
|
if (blob && ripple::publicKeyType(ripple::makeSlice(*blob))) {
|
||||||
publicKey = ripple::PublicKey(ripple::Slice{blob->data(), blob->size()});
|
publicKey = ripple::PublicKey(ripple::Slice{blob->data(), blob->size()});
|
||||||
} else {
|
} else {
|
||||||
publicKey = ripple::parseBase58<ripple::PublicKey>(ripple::TokenType::AccountPublic, account);
|
publicKey = util::parseBase58Wrapper<ripple::PublicKey>(ripple::TokenType::AccountPublic, account);
|
||||||
}
|
}
|
||||||
|
|
||||||
std::optional<ripple::AccountID> result;
|
std::optional<ripple::AccountID> result;
|
||||||
if (publicKey) {
|
if (publicKey) {
|
||||||
result = ripple::calcAccountID(*publicKey);
|
result = ripple::calcAccountID(*publicKey);
|
||||||
} else {
|
} else {
|
||||||
result = ripple::parseBase58<ripple::AccountID>(account);
|
result = util::parseBase58Wrapper<ripple::AccountID>(account);
|
||||||
}
|
}
|
||||||
|
|
||||||
return result;
|
return result;
|
||||||
@@ -799,7 +800,7 @@ getAccountsFromTransaction(boost::json::object const& transaction)
|
|||||||
auto inObject = getAccountsFromTransaction(value.as_object());
|
auto inObject = getAccountsFromTransaction(value.as_object());
|
||||||
accounts.insert(accounts.end(), inObject.begin(), inObject.end());
|
accounts.insert(accounts.end(), inObject.begin(), inObject.end());
|
||||||
} else if (value.is_string()) {
|
} else if (value.is_string()) {
|
||||||
auto const account = ripple::parseBase58<ripple::AccountID>(boost::json::value_to<std::string>(value));
|
auto const account = util::parseBase58Wrapper<ripple::AccountID>(boost::json::value_to<std::string>(value));
|
||||||
if (account) {
|
if (account) {
|
||||||
accounts.push_back(*account);
|
accounts.push_back(*account);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -22,6 +22,7 @@
|
|||||||
#include "rpc/Errors.hpp"
|
#include "rpc/Errors.hpp"
|
||||||
#include "rpc/RPCHelpers.hpp"
|
#include "rpc/RPCHelpers.hpp"
|
||||||
#include "rpc/common/Types.hpp"
|
#include "rpc/common/Types.hpp"
|
||||||
|
#include "util/AccountUtils.hpp"
|
||||||
|
|
||||||
#include <boost/json/object.hpp>
|
#include <boost/json/object.hpp>
|
||||||
#include <boost/json/value.hpp>
|
#include <boost/json/value.hpp>
|
||||||
@@ -114,7 +115,7 @@ CustomValidator AccountBase58Validator =
|
|||||||
if (!value.is_string())
|
if (!value.is_string())
|
||||||
return Error{Status{RippledError::rpcINVALID_PARAMS, std::string(key) + "NotString"}};
|
return Error{Status{RippledError::rpcINVALID_PARAMS, std::string(key) + "NotString"}};
|
||||||
|
|
||||||
auto const account = ripple::parseBase58<ripple::AccountID>(boost::json::value_to<std::string>(value));
|
auto const account = util::parseBase58Wrapper<ripple::AccountID>(boost::json::value_to<std::string>(value));
|
||||||
if (!account || account->isZero())
|
if (!account || account->isZero())
|
||||||
return Error{Status{ClioError::rpcMALFORMED_ADDRESS}};
|
return Error{Status{ClioError::rpcMALFORMED_ADDRESS}};
|
||||||
|
|
||||||
|
|||||||
@@ -25,6 +25,7 @@
|
|||||||
#include "rpc/common/Specs.hpp"
|
#include "rpc/common/Specs.hpp"
|
||||||
#include "rpc/common/Types.hpp"
|
#include "rpc/common/Types.hpp"
|
||||||
#include "rpc/common/Validators.hpp"
|
#include "rpc/common/Validators.hpp"
|
||||||
|
#include "util/AccountUtils.hpp"
|
||||||
|
|
||||||
#include <boost/json/array.hpp>
|
#include <boost/json/array.hpp>
|
||||||
#include <boost/json/conversion.hpp>
|
#include <boost/json/conversion.hpp>
|
||||||
@@ -116,14 +117,14 @@ public:
|
|||||||
auto const wallets = value.is_array() ? value.as_array() : boost::json::array{value};
|
auto const wallets = value.is_array() ? value.as_array() : boost::json::array{value};
|
||||||
auto const getAccountID = [](auto const& j) -> std::optional<ripple::AccountID> {
|
auto const getAccountID = [](auto const& j) -> std::optional<ripple::AccountID> {
|
||||||
if (j.is_string()) {
|
if (j.is_string()) {
|
||||||
auto const pk = ripple::parseBase58<ripple::PublicKey>(
|
auto const pk = util::parseBase58Wrapper<ripple::PublicKey>(
|
||||||
ripple::TokenType::AccountPublic, boost::json::value_to<std::string>(j)
|
ripple::TokenType::AccountPublic, boost::json::value_to<std::string>(j)
|
||||||
);
|
);
|
||||||
|
|
||||||
if (pk)
|
if (pk)
|
||||||
return ripple::calcAccountID(*pk);
|
return ripple::calcAccountID(*pk);
|
||||||
|
|
||||||
return ripple::parseBase58<ripple::AccountID>(boost::json::value_to<std::string>(j));
|
return util::parseBase58Wrapper<ripple::AccountID>(boost::json::value_to<std::string>(j));
|
||||||
}
|
}
|
||||||
|
|
||||||
return {};
|
return {};
|
||||||
|
|||||||
@@ -23,6 +23,7 @@
|
|||||||
#include "rpc/JS.hpp"
|
#include "rpc/JS.hpp"
|
||||||
#include "rpc/RPCHelpers.hpp"
|
#include "rpc/RPCHelpers.hpp"
|
||||||
#include "rpc/common/Types.hpp"
|
#include "rpc/common/Types.hpp"
|
||||||
|
#include "util/AccountUtils.hpp"
|
||||||
|
|
||||||
#include <boost/asio/spawn.hpp>
|
#include <boost/asio/spawn.hpp>
|
||||||
#include <boost/bimap/bimap.hpp>
|
#include <boost/bimap/bimap.hpp>
|
||||||
@@ -263,7 +264,7 @@ tag_invoke(boost::json::value_to_tag<GetAggregatePriceHandler::Input>, boost::js
|
|||||||
for (auto const& oracle : jsonObject.at(JS(oracles)).as_array()) {
|
for (auto const& oracle : jsonObject.at(JS(oracles)).as_array()) {
|
||||||
input.oracles.push_back(GetAggregatePriceHandler::Oracle{
|
input.oracles.push_back(GetAggregatePriceHandler::Oracle{
|
||||||
.documentId = boost::json::value_to<std::uint64_t>(oracle.as_object().at(JS(oracle_document_id))),
|
.documentId = boost::json::value_to<std::uint64_t>(oracle.as_object().at(JS(oracle_document_id))),
|
||||||
.account = *ripple::parseBase58<ripple::AccountID>(
|
.account = *util::parseBase58Wrapper<ripple::AccountID>(
|
||||||
boost::json::value_to<std::string>(oracle.as_object().at(JS(account)))
|
boost::json::value_to<std::string>(oracle.as_object().at(JS(account)))
|
||||||
)
|
)
|
||||||
});
|
});
|
||||||
|
|||||||
@@ -23,6 +23,7 @@
|
|||||||
#include "rpc/JS.hpp"
|
#include "rpc/JS.hpp"
|
||||||
#include "rpc/RPCHelpers.hpp"
|
#include "rpc/RPCHelpers.hpp"
|
||||||
#include "rpc/common/Types.hpp"
|
#include "rpc/common/Types.hpp"
|
||||||
|
#include "util/AccountUtils.hpp"
|
||||||
|
|
||||||
#include <boost/json/conversion.hpp>
|
#include <boost/json/conversion.hpp>
|
||||||
#include <boost/json/object.hpp>
|
#include <boost/json/object.hpp>
|
||||||
@@ -62,9 +63,9 @@ LedgerEntryHandler::process(LedgerEntryHandler::Input input, Context const& ctx)
|
|||||||
if (input.index) {
|
if (input.index) {
|
||||||
key = ripple::uint256{std::string_view(*(input.index))};
|
key = ripple::uint256{std::string_view(*(input.index))};
|
||||||
} else if (input.accountRoot) {
|
} else if (input.accountRoot) {
|
||||||
key = ripple::keylet::account(*ripple::parseBase58<ripple::AccountID>(*(input.accountRoot))).key;
|
key = ripple::keylet::account(*util::parseBase58Wrapper<ripple::AccountID>(*(input.accountRoot))).key;
|
||||||
} else if (input.did) {
|
} else if (input.did) {
|
||||||
key = ripple::keylet::did(*ripple::parseBase58<ripple::AccountID>(*(input.did))).key;
|
key = ripple::keylet::did(*util::parseBase58Wrapper<ripple::AccountID>(*(input.did))).key;
|
||||||
} else if (input.directory) {
|
} else if (input.directory) {
|
||||||
auto const keyOrStatus = composeKeyFromDirectory(*input.directory);
|
auto const keyOrStatus = composeKeyFromDirectory(*input.directory);
|
||||||
if (auto const status = std::get_if<Status>(&keyOrStatus))
|
if (auto const status = std::get_if<Status>(&keyOrStatus))
|
||||||
@@ -73,13 +74,14 @@ LedgerEntryHandler::process(LedgerEntryHandler::Input input, Context const& ctx)
|
|||||||
key = std::get<ripple::uint256>(keyOrStatus);
|
key = std::get<ripple::uint256>(keyOrStatus);
|
||||||
} else if (input.offer) {
|
} else if (input.offer) {
|
||||||
auto const id =
|
auto const id =
|
||||||
ripple::parseBase58<ripple::AccountID>(boost::json::value_to<std::string>(input.offer->at(JS(account))));
|
util::parseBase58Wrapper<ripple::AccountID>(boost::json::value_to<std::string>(input.offer->at(JS(account)))
|
||||||
|
);
|
||||||
key = ripple::keylet::offer(*id, boost::json::value_to<std::uint32_t>(input.offer->at(JS(seq)))).key;
|
key = ripple::keylet::offer(*id, boost::json::value_to<std::uint32_t>(input.offer->at(JS(seq)))).key;
|
||||||
} else if (input.rippleStateAccount) {
|
} else if (input.rippleStateAccount) {
|
||||||
auto const id1 = ripple::parseBase58<ripple::AccountID>(
|
auto const id1 = util::parseBase58Wrapper<ripple::AccountID>(
|
||||||
boost::json::value_to<std::string>(input.rippleStateAccount->at(JS(accounts)).as_array().at(0))
|
boost::json::value_to<std::string>(input.rippleStateAccount->at(JS(accounts)).as_array().at(0))
|
||||||
);
|
);
|
||||||
auto const id2 = ripple::parseBase58<ripple::AccountID>(
|
auto const id2 = util::parseBase58Wrapper<ripple::AccountID>(
|
||||||
boost::json::value_to<std::string>(input.rippleStateAccount->at(JS(accounts)).as_array().at(1))
|
boost::json::value_to<std::string>(input.rippleStateAccount->at(JS(accounts)).as_array().at(1))
|
||||||
);
|
);
|
||||||
auto const currency =
|
auto const currency =
|
||||||
@@ -88,20 +90,22 @@ LedgerEntryHandler::process(LedgerEntryHandler::Input input, Context const& ctx)
|
|||||||
key = ripple::keylet::line(*id1, *id2, currency).key;
|
key = ripple::keylet::line(*id1, *id2, currency).key;
|
||||||
} else if (input.escrow) {
|
} else if (input.escrow) {
|
||||||
auto const id =
|
auto const id =
|
||||||
ripple::parseBase58<ripple::AccountID>(boost::json::value_to<std::string>(input.escrow->at(JS(owner))));
|
util::parseBase58Wrapper<ripple::AccountID>(boost::json::value_to<std::string>(input.escrow->at(JS(owner)))
|
||||||
|
);
|
||||||
key = ripple::keylet::escrow(*id, input.escrow->at(JS(seq)).as_int64()).key;
|
key = ripple::keylet::escrow(*id, input.escrow->at(JS(seq)).as_int64()).key;
|
||||||
} else if (input.depositPreauth) {
|
} else if (input.depositPreauth) {
|
||||||
auto const owner = ripple::parseBase58<ripple::AccountID>(
|
auto const owner = util::parseBase58Wrapper<ripple::AccountID>(
|
||||||
boost::json::value_to<std::string>(input.depositPreauth->at(JS(owner)))
|
boost::json::value_to<std::string>(input.depositPreauth->at(JS(owner)))
|
||||||
);
|
);
|
||||||
auto const authorized = ripple::parseBase58<ripple::AccountID>(
|
auto const authorized = util::parseBase58Wrapper<ripple::AccountID>(
|
||||||
boost::json::value_to<std::string>(input.depositPreauth->at(JS(authorized)))
|
boost::json::value_to<std::string>(input.depositPreauth->at(JS(authorized)))
|
||||||
);
|
);
|
||||||
|
|
||||||
key = ripple::keylet::depositPreauth(*owner, *authorized).key;
|
key = ripple::keylet::depositPreauth(*owner, *authorized).key;
|
||||||
} else if (input.ticket) {
|
} else if (input.ticket) {
|
||||||
auto const id =
|
auto const id =
|
||||||
ripple::parseBase58<ripple::AccountID>(boost::json::value_to<std::string>(input.ticket->at(JS(account))));
|
util::parseBase58Wrapper<ripple::AccountID>(boost::json::value_to<std::string>(input.ticket->at(JS(account))
|
||||||
|
));
|
||||||
|
|
||||||
key = ripple::getTicketIndex(*id, input.ticket->at(JS(ticket_seq)).as_int64());
|
key = ripple::getTicketIndex(*id, input.ticket->at(JS(ticket_seq)).as_int64());
|
||||||
} else if (input.amm) {
|
} else if (input.amm) {
|
||||||
@@ -112,7 +116,8 @@ LedgerEntryHandler::process(LedgerEntryHandler::Input input, Context const& ctx)
|
|||||||
return ripple::xrpIssue();
|
return ripple::xrpIssue();
|
||||||
}
|
}
|
||||||
auto const issuer =
|
auto const issuer =
|
||||||
ripple::parseBase58<ripple::AccountID>(boost::json::value_to<std::string>(assetJson.at(JS(issuer))));
|
util::parseBase58Wrapper<ripple::AccountID>(boost::json::value_to<std::string>(assetJson.at(JS(issuer)))
|
||||||
|
);
|
||||||
return ripple::Issue{currency, *issuer};
|
return ripple::Issue{currency, *issuer};
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -125,7 +130,7 @@ LedgerEntryHandler::process(LedgerEntryHandler::Input input, Context const& ctx)
|
|||||||
return Error{Status{ClioError::rpcMALFORMED_REQUEST}};
|
return Error{Status{ClioError::rpcMALFORMED_REQUEST}};
|
||||||
|
|
||||||
if (input.bridgeAccount) {
|
if (input.bridgeAccount) {
|
||||||
auto const bridgeAccount = ripple::parseBase58<ripple::AccountID>(*(input.bridgeAccount));
|
auto const bridgeAccount = util::parseBase58Wrapper<ripple::AccountID>(*(input.bridgeAccount));
|
||||||
auto const chainType = ripple::STXChainBridge::srcChain(bridgeAccount == input.bridge->lockingChainDoor());
|
auto const chainType = ripple::STXChainBridge::srcChain(bridgeAccount == input.bridge->lockingChainDoor());
|
||||||
|
|
||||||
if (bridgeAccount != input.bridge->door(chainType))
|
if (bridgeAccount != input.bridge->door(chainType))
|
||||||
@@ -201,7 +206,7 @@ LedgerEntryHandler::composeKeyFromDirectory(boost::json::object const& directory
|
|||||||
}
|
}
|
||||||
|
|
||||||
auto const ownerID =
|
auto const ownerID =
|
||||||
ripple::parseBase58<ripple::AccountID>(boost::json::value_to<std::string>(directory.at(JS(owner))));
|
util::parseBase58Wrapper<ripple::AccountID>(boost::json::value_to<std::string>(directory.at(JS(owner))));
|
||||||
return ripple::keylet::page(ripple::keylet::ownerDir(*ownerID), subIndex).key;
|
return ripple::keylet::page(ripple::keylet::ownerDir(*ownerID), subIndex).key;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -262,10 +267,10 @@ tag_invoke(boost::json::value_to_tag<LedgerEntryHandler::Input>, boost::json::va
|
|||||||
};
|
};
|
||||||
|
|
||||||
auto const parseBridgeFromJson = [](boost::json::value const& bridgeJson) {
|
auto const parseBridgeFromJson = [](boost::json::value const& bridgeJson) {
|
||||||
auto const lockingDoor = *ripple::parseBase58<ripple::AccountID>(
|
auto const lockingDoor = *util::parseBase58Wrapper<ripple::AccountID>(
|
||||||
boost::json::value_to<std::string>(bridgeJson.at(ripple::sfLockingChainDoor.getJsonName().c_str()))
|
boost::json::value_to<std::string>(bridgeJson.at(ripple::sfLockingChainDoor.getJsonName().c_str()))
|
||||||
);
|
);
|
||||||
auto const issuingDoor = *ripple::parseBase58<ripple::AccountID>(
|
auto const issuingDoor = *util::parseBase58Wrapper<ripple::AccountID>(
|
||||||
boost::json::value_to<std::string>(bridgeJson.at(ripple::sfIssuingChainDoor.getJsonName().c_str()))
|
boost::json::value_to<std::string>(bridgeJson.at(ripple::sfIssuingChainDoor.getJsonName().c_str()))
|
||||||
);
|
);
|
||||||
auto const lockingIssue =
|
auto const lockingIssue =
|
||||||
@@ -278,7 +283,7 @@ tag_invoke(boost::json::value_to_tag<LedgerEntryHandler::Input>, boost::json::va
|
|||||||
|
|
||||||
auto const parseOracleFromJson = [](boost::json::value const& json) {
|
auto const parseOracleFromJson = [](boost::json::value const& json) {
|
||||||
auto const account =
|
auto const account =
|
||||||
ripple::parseBase58<ripple::AccountID>(boost::json::value_to<std::string>(json.at(JS(account))));
|
util::parseBase58Wrapper<ripple::AccountID>(boost::json::value_to<std::string>(json.at(JS(account))));
|
||||||
auto const documentId = boost::json::value_to<uint32_t>(json.at(JS(oracle_document_id)));
|
auto const documentId = boost::json::value_to<uint32_t>(json.at(JS(oracle_document_id)));
|
||||||
|
|
||||||
return ripple::keylet::oracle(*account, documentId).key;
|
return ripple::keylet::oracle(*account, documentId).key;
|
||||||
|
|||||||
@@ -28,6 +28,7 @@
|
|||||||
#include "rpc/common/Specs.hpp"
|
#include "rpc/common/Specs.hpp"
|
||||||
#include "rpc/common/Types.hpp"
|
#include "rpc/common/Types.hpp"
|
||||||
#include "rpc/common/Validators.hpp"
|
#include "rpc/common/Validators.hpp"
|
||||||
|
#include "util/AccountUtils.hpp"
|
||||||
|
|
||||||
#include <boost/json/conversion.hpp>
|
#include <boost/json/conversion.hpp>
|
||||||
#include <boost/json/object.hpp>
|
#include <boost/json/object.hpp>
|
||||||
@@ -136,9 +137,11 @@ public:
|
|||||||
}
|
}
|
||||||
|
|
||||||
auto const id1 =
|
auto const id1 =
|
||||||
ripple::parseBase58<ripple::AccountID>(boost::json::value_to<std::string>(value.as_array()[0]));
|
util::parseBase58Wrapper<ripple::AccountID>(boost::json::value_to<std::string>(value.as_array()[0])
|
||||||
|
);
|
||||||
auto const id2 =
|
auto const id2 =
|
||||||
ripple::parseBase58<ripple::AccountID>(boost::json::value_to<std::string>(value.as_array()[1]));
|
util::parseBase58Wrapper<ripple::AccountID>(boost::json::value_to<std::string>(value.as_array()[1])
|
||||||
|
);
|
||||||
|
|
||||||
if (!id1 || !id2)
|
if (!id1 || !id2)
|
||||||
return Error{Status{ClioError::rpcMALFORMED_ADDRESS, "malformedAddresses"}};
|
return Error{Status{ClioError::rpcMALFORMED_ADDRESS, "malformedAddresses"}};
|
||||||
|
|||||||
67
src/util/AccountUtils.hpp
Normal file
67
src/util/AccountUtils.hpp
Normal file
@@ -0,0 +1,67 @@
|
|||||||
|
//------------------------------------------------------------------------------
|
||||||
|
/*
|
||||||
|
This file is part of clio: https://github.com/XRPLF/clio
|
||||||
|
Copyright (c) 2024, the clio developers.
|
||||||
|
|
||||||
|
Permission to use, copy, modify, and distribute this software for any
|
||||||
|
purpose with or without fee is hereby granted, provided that the above
|
||||||
|
copyright notice and this permission notice appear in all copies.
|
||||||
|
|
||||||
|
THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
|
||||||
|
WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
|
||||||
|
MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
|
||||||
|
ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
|
||||||
|
WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
|
||||||
|
ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
|
||||||
|
OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
||||||
|
*/
|
||||||
|
//==============================================================================
|
||||||
|
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <ripple/protocol/tokens.h>
|
||||||
|
|
||||||
|
#include <cctype>
|
||||||
|
#include <optional>
|
||||||
|
#include <string>
|
||||||
|
|
||||||
|
namespace util {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief A wrapper of parseBase58 function. It adds the check if all characters in the input string are alphanumeric.
|
||||||
|
* If not, it returns an empty optional, instead of calling the parseBase58 function.
|
||||||
|
*
|
||||||
|
* @tparam T The type of the value to parse to.
|
||||||
|
* @param str The string to parse.
|
||||||
|
* @return An optional with the parsed value, or an empty optional if the parse fails.
|
||||||
|
*/
|
||||||
|
template <class T>
|
||||||
|
[[nodiscard]] std::optional<T>
|
||||||
|
parseBase58Wrapper(std::string const& str)
|
||||||
|
{
|
||||||
|
if (!std::all_of(std::begin(str), std::end(str), [](unsigned char c) { return std::isalnum(c); }))
|
||||||
|
return std::nullopt;
|
||||||
|
|
||||||
|
return ripple::parseBase58<T>(str);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief A wrapper of parseBase58 function. It add the check if all characters in the input string are alphanumeric. If
|
||||||
|
* not, it returns an empty optional, instead of calling the parseBase58 function.
|
||||||
|
*
|
||||||
|
* @tparam T The type of the value to parse to.
|
||||||
|
* @param type The type of the token to parse.
|
||||||
|
* @param str The string to parse.
|
||||||
|
* @return An optional with the parsed value, or an empty optional if the parse fails.
|
||||||
|
*/
|
||||||
|
template <class T>
|
||||||
|
[[nodiscard]] std::optional<T>
|
||||||
|
parseBase58Wrapper(ripple::TokenType type, std::string const& str)
|
||||||
|
{
|
||||||
|
if (!std::all_of(std::begin(str), std::end(str), [](unsigned char c) { return std::isalnum(c); }))
|
||||||
|
return std::nullopt;
|
||||||
|
|
||||||
|
return ripple::parseBase58<T>(type, str);
|
||||||
|
}
|
||||||
|
|
||||||
|
} // namespace util
|
||||||
@@ -21,6 +21,7 @@
|
|||||||
|
|
||||||
#include "data/DBHelpers.hpp"
|
#include "data/DBHelpers.hpp"
|
||||||
#include "data/Types.hpp"
|
#include "data/Types.hpp"
|
||||||
|
#include "util/AccountUtils.hpp"
|
||||||
#include "util/Assert.hpp"
|
#include "util/Assert.hpp"
|
||||||
|
|
||||||
#include <ripple/basics/Blob.h>
|
#include <ripple/basics/Blob.h>
|
||||||
@@ -60,7 +61,7 @@ constexpr static auto INDEX1 = "1B8590C01B0006EDFA9ED60296DD052DC5E90F99659B2501
|
|||||||
ripple::AccountID
|
ripple::AccountID
|
||||||
GetAccountIDWithString(std::string_view id)
|
GetAccountIDWithString(std::string_view id)
|
||||||
{
|
{
|
||||||
return ripple::parseBase58<ripple::AccountID>(std::string(id)).value();
|
return util::parseBase58Wrapper<ripple::AccountID>(std::string(id)).value();
|
||||||
}
|
}
|
||||||
|
|
||||||
ripple::uint256
|
ripple::uint256
|
||||||
@@ -154,11 +155,11 @@ CreatePaymentTransactionObject(
|
|||||||
{
|
{
|
||||||
ripple::STObject obj(ripple::sfTransaction);
|
ripple::STObject obj(ripple::sfTransaction);
|
||||||
obj.setFieldU16(ripple::sfTransactionType, ripple::ttPAYMENT);
|
obj.setFieldU16(ripple::sfTransactionType, ripple::ttPAYMENT);
|
||||||
auto account = ripple::parseBase58<ripple::AccountID>(std::string(accountId1));
|
auto account = util::parseBase58Wrapper<ripple::AccountID>(std::string(accountId1));
|
||||||
obj.setAccountID(ripple::sfAccount, account.value());
|
obj.setAccountID(ripple::sfAccount, account.value());
|
||||||
obj.setFieldAmount(ripple::sfAmount, ripple::STAmount(amount, false));
|
obj.setFieldAmount(ripple::sfAmount, ripple::STAmount(amount, false));
|
||||||
obj.setFieldAmount(ripple::sfFee, ripple::STAmount(fee, false));
|
obj.setFieldAmount(ripple::sfFee, ripple::STAmount(fee, false));
|
||||||
auto account2 = ripple::parseBase58<ripple::AccountID>(std::string(accountId2));
|
auto account2 = util::parseBase58Wrapper<ripple::AccountID>(std::string(accountId2));
|
||||||
obj.setAccountID(ripple::sfDestination, account2.value());
|
obj.setAccountID(ripple::sfDestination, account2.value());
|
||||||
obj.setFieldU32(ripple::sfSequence, seq);
|
obj.setFieldU32(ripple::sfSequence, seq);
|
||||||
char const* key = "test";
|
char const* key = "test";
|
||||||
@@ -258,14 +259,14 @@ CreateCreateOfferTransactionObject(
|
|||||||
{
|
{
|
||||||
ripple::STObject obj(ripple::sfTransaction);
|
ripple::STObject obj(ripple::sfTransaction);
|
||||||
obj.setFieldU16(ripple::sfTransactionType, ripple::ttOFFER_CREATE);
|
obj.setFieldU16(ripple::sfTransactionType, ripple::ttOFFER_CREATE);
|
||||||
auto account = ripple::parseBase58<ripple::AccountID>(std::string(accountId));
|
auto account = util::parseBase58Wrapper<ripple::AccountID>(std::string(accountId));
|
||||||
obj.setAccountID(ripple::sfAccount, account.value());
|
obj.setAccountID(ripple::sfAccount, account.value());
|
||||||
auto amount = ripple::STAmount(fee, false);
|
auto amount = ripple::STAmount(fee, false);
|
||||||
obj.setFieldAmount(ripple::sfFee, amount);
|
obj.setFieldAmount(ripple::sfFee, amount);
|
||||||
obj.setFieldU32(ripple::sfSequence, seq);
|
obj.setFieldU32(ripple::sfSequence, seq);
|
||||||
// add amount
|
// add amount
|
||||||
ripple::Issue const issue1(
|
ripple::Issue const issue1(
|
||||||
ripple::Currency{currency}, ripple::parseBase58<ripple::AccountID>(std::string(issuer)).value()
|
ripple::Currency{currency}, util::parseBase58Wrapper<ripple::AccountID>(std::string(issuer)).value()
|
||||||
);
|
);
|
||||||
if (reverse) {
|
if (reverse) {
|
||||||
obj.setFieldAmount(ripple::sfTakerPays, ripple::STAmount(issue1, takerGets));
|
obj.setFieldAmount(ripple::sfTakerPays, ripple::STAmount(issue1, takerGets));
|
||||||
@@ -288,11 +289,11 @@ GetIssue(std::string_view currency, std::string_view issuerId)
|
|||||||
if (currency.size() == 3) {
|
if (currency.size() == 3) {
|
||||||
return ripple::Issue(
|
return ripple::Issue(
|
||||||
ripple::to_currency(std::string(currency)),
|
ripple::to_currency(std::string(currency)),
|
||||||
ripple::parseBase58<ripple::AccountID>(std::string(issuerId)).value()
|
util::parseBase58Wrapper<ripple::AccountID>(std::string(issuerId)).value()
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
return ripple::Issue(
|
return ripple::Issue(
|
||||||
ripple::Currency{currency}, ripple::parseBase58<ripple::AccountID>(std::string(issuerId)).value()
|
ripple::Currency{currency}, util::parseBase58Wrapper<ripple::AccountID>(std::string(issuerId)).value()
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -636,7 +637,7 @@ CreateMintNFTTxWithMetadata(
|
|||||||
// tx
|
// tx
|
||||||
ripple::STObject tx(ripple::sfTransaction);
|
ripple::STObject tx(ripple::sfTransaction);
|
||||||
tx.setFieldU16(ripple::sfTransactionType, ripple::ttNFTOKEN_MINT);
|
tx.setFieldU16(ripple::sfTransactionType, ripple::ttNFTOKEN_MINT);
|
||||||
auto account = ripple::parseBase58<ripple::AccountID>(std::string(accountId));
|
auto account = util::parseBase58Wrapper<ripple::AccountID>(std::string(accountId));
|
||||||
tx.setAccountID(ripple::sfAccount, account.value());
|
tx.setAccountID(ripple::sfAccount, account.value());
|
||||||
auto amount = ripple::STAmount(fee, false);
|
auto amount = ripple::STAmount(fee, false);
|
||||||
tx.setFieldAmount(ripple::sfFee, amount);
|
tx.setFieldAmount(ripple::sfFee, amount);
|
||||||
@@ -693,7 +694,7 @@ CreateAcceptNFTOfferTxWithMetadata(std::string_view accountId, uint32_t seq, uin
|
|||||||
// tx
|
// tx
|
||||||
ripple::STObject tx(ripple::sfTransaction);
|
ripple::STObject tx(ripple::sfTransaction);
|
||||||
tx.setFieldU16(ripple::sfTransactionType, ripple::ttNFTOKEN_ACCEPT_OFFER);
|
tx.setFieldU16(ripple::sfTransactionType, ripple::ttNFTOKEN_ACCEPT_OFFER);
|
||||||
auto account = ripple::parseBase58<ripple::AccountID>(std::string(accountId));
|
auto account = util::parseBase58Wrapper<ripple::AccountID>(std::string(accountId));
|
||||||
tx.setAccountID(ripple::sfAccount, account.value());
|
tx.setAccountID(ripple::sfAccount, account.value());
|
||||||
auto amount = ripple::STAmount(fee, false);
|
auto amount = ripple::STAmount(fee, false);
|
||||||
tx.setFieldAmount(ripple::sfFee, amount);
|
tx.setFieldAmount(ripple::sfFee, amount);
|
||||||
@@ -737,7 +738,7 @@ CreateCancelNFTOffersTxWithMetadata(
|
|||||||
// tx
|
// tx
|
||||||
ripple::STObject tx(ripple::sfTransaction);
|
ripple::STObject tx(ripple::sfTransaction);
|
||||||
tx.setFieldU16(ripple::sfTransactionType, ripple::ttNFTOKEN_CANCEL_OFFER);
|
tx.setFieldU16(ripple::sfTransactionType, ripple::ttNFTOKEN_CANCEL_OFFER);
|
||||||
auto account = ripple::parseBase58<ripple::AccountID>(std::string(accountId));
|
auto account = util::parseBase58Wrapper<ripple::AccountID>(std::string(accountId));
|
||||||
tx.setAccountID(ripple::sfAccount, account.value());
|
tx.setAccountID(ripple::sfAccount, account.value());
|
||||||
auto amount = ripple::STAmount(fee, false);
|
auto amount = ripple::STAmount(fee, false);
|
||||||
tx.setFieldAmount(ripple::sfFee, amount);
|
tx.setFieldAmount(ripple::sfFee, amount);
|
||||||
@@ -791,7 +792,7 @@ CreateCreateNFTOfferTxWithMetadata(
|
|||||||
// tx
|
// tx
|
||||||
ripple::STObject tx(ripple::sfTransaction);
|
ripple::STObject tx(ripple::sfTransaction);
|
||||||
tx.setFieldU16(ripple::sfTransactionType, ripple::ttNFTOKEN_CREATE_OFFER);
|
tx.setFieldU16(ripple::sfTransactionType, ripple::ttNFTOKEN_CREATE_OFFER);
|
||||||
auto account = ripple::parseBase58<ripple::AccountID>(std::string(accountId));
|
auto account = util::parseBase58Wrapper<ripple::AccountID>(std::string(accountId));
|
||||||
tx.setAccountID(ripple::sfAccount, account.value());
|
tx.setAccountID(ripple::sfAccount, account.value());
|
||||||
auto amount = ripple::STAmount(fee, false);
|
auto amount = ripple::STAmount(fee, false);
|
||||||
tx.setFieldAmount(ripple::sfFee, amount);
|
tx.setFieldAmount(ripple::sfFee, amount);
|
||||||
@@ -839,7 +840,7 @@ CreateOracleSetTxWithMetadata(
|
|||||||
// tx
|
// tx
|
||||||
ripple::STObject tx(ripple::sfTransaction);
|
ripple::STObject tx(ripple::sfTransaction);
|
||||||
tx.setFieldU16(ripple::sfTransactionType, ripple::ttORACLE_SET);
|
tx.setFieldU16(ripple::sfTransactionType, ripple::ttORACLE_SET);
|
||||||
auto account = ripple::parseBase58<ripple::AccountID>(std::string(accountId));
|
auto account = util::parseBase58Wrapper<ripple::AccountID>(std::string(accountId));
|
||||||
tx.setAccountID(ripple::sfAccount, account.value());
|
tx.setAccountID(ripple::sfAccount, account.value());
|
||||||
auto amount = ripple::STAmount(fee, false);
|
auto amount = ripple::STAmount(fee, false);
|
||||||
tx.setFieldAmount(ripple::sfFee, amount);
|
tx.setFieldAmount(ripple::sfFee, amount);
|
||||||
@@ -909,7 +910,7 @@ CreateAMMObject(
|
|||||||
amm.setFieldIssue(ripple::sfAsset2, ripple::STIssue{ripple::sfAsset2, GetIssue(asset2Currency, asset2Issuer)});
|
amm.setFieldIssue(ripple::sfAsset2, ripple::STIssue{ripple::sfAsset2, GetIssue(asset2Currency, asset2Issuer)});
|
||||||
ripple::Issue const issue1(
|
ripple::Issue const issue1(
|
||||||
ripple::Currency{lpTokenBalanceIssueCurrency},
|
ripple::Currency{lpTokenBalanceIssueCurrency},
|
||||||
ripple::parseBase58<ripple::AccountID>(std::string(accountId)).value()
|
util::parseBase58Wrapper<ripple::AccountID>(std::string(accountId)).value()
|
||||||
);
|
);
|
||||||
amm.setFieldAmount(ripple::sfLPTokenBalance, ripple::STAmount(issue1, lpTokenBalanceIssueAmount));
|
amm.setFieldAmount(ripple::sfLPTokenBalance, ripple::STAmount(issue1, lpTokenBalanceIssueAmount));
|
||||||
amm.setFieldU32(ripple::sfFlags, 0);
|
amm.setFieldU32(ripple::sfFlags, 0);
|
||||||
|
|||||||
@@ -92,6 +92,7 @@ target_sources(
|
|||||||
rpc/JsonBoolTests.cpp
|
rpc/JsonBoolTests.cpp
|
||||||
rpc/RPCHelpersTests.cpp
|
rpc/RPCHelpersTests.cpp
|
||||||
rpc/WorkQueueTests.cpp
|
rpc/WorkQueueTests.cpp
|
||||||
|
util/AccountUtilsTests.cpp
|
||||||
util/AssertTests.cpp
|
util/AssertTests.cpp
|
||||||
# Async framework
|
# Async framework
|
||||||
util/async/AnyExecutionContextTests.cpp
|
util/async/AnyExecutionContextTests.cpp
|
||||||
|
|||||||
@@ -426,6 +426,9 @@ TEST_F(RPCBaseTest, AccountValidator)
|
|||||||
failingInput = json::parse(R"({ "account": "02000000000000000000000000000000000000000000000000000000000000000" })");
|
failingInput = json::parse(R"({ "account": "02000000000000000000000000000000000000000000000000000000000000000" })");
|
||||||
ASSERT_FALSE(spec.process(failingInput));
|
ASSERT_FALSE(spec.process(failingInput));
|
||||||
|
|
||||||
|
failingInput = json::parse(R"({ "account": "rf1BiGeXwwQoi8Z2ueFYTEXSwuJYfV2Jp?" })");
|
||||||
|
ASSERT_FALSE(spec.process(failingInput));
|
||||||
|
|
||||||
auto passingInput = json::parse(R"({ "account": "rf1BiGeXwwQoi8Z2ueFYTEXSwuJYfV2Jpn" })");
|
auto passingInput = json::parse(R"({ "account": "rf1BiGeXwwQoi8Z2ueFYTEXSwuJYfV2Jpn" })");
|
||||||
ASSERT_TRUE(spec.process(passingInput));
|
ASSERT_TRUE(spec.process(passingInput));
|
||||||
|
|
||||||
@@ -434,6 +437,28 @@ TEST_F(RPCBaseTest, AccountValidator)
|
|||||||
ASSERT_TRUE(spec.process(passingInput));
|
ASSERT_TRUE(spec.process(passingInput));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
TEST_F(RPCBaseTest, AccountBase58Validator)
|
||||||
|
{
|
||||||
|
auto spec = RpcSpec{
|
||||||
|
{"account", validation::AccountBase58Validator},
|
||||||
|
};
|
||||||
|
auto failingInput = json::parse(R"({ "account": 256 })");
|
||||||
|
ASSERT_FALSE(spec.process(failingInput));
|
||||||
|
|
||||||
|
failingInput = json::parse(R"({ "account": "rf1BiGeXwwQoi8Z2ueFYTEXSwuJYfV2Jp" })");
|
||||||
|
ASSERT_FALSE(spec.process(failingInput));
|
||||||
|
|
||||||
|
failingInput =
|
||||||
|
json::parse(R"({ "account": "020000000000000000000000000000000000000000000000000000000000000000" })");
|
||||||
|
ASSERT_FALSE(spec.process(failingInput));
|
||||||
|
|
||||||
|
failingInput = json::parse(R"({ "account": "rf1BiGeXwwQoi8Z2ueFYTEXSwuJYfV2Jp?" })");
|
||||||
|
ASSERT_FALSE(spec.process(failingInput));
|
||||||
|
|
||||||
|
auto passingInput = json::parse(R"({ "account": "rf1BiGeXwwQoi8Z2ueFYTEXSwuJYfV2Jpn" })");
|
||||||
|
ASSERT_TRUE(spec.process(passingInput));
|
||||||
|
}
|
||||||
|
|
||||||
TEST_F(RPCBaseTest, AccountMarkerValidator)
|
TEST_F(RPCBaseTest, AccountMarkerValidator)
|
||||||
{
|
{
|
||||||
auto spec = RpcSpec{
|
auto spec = RpcSpec{
|
||||||
|
|||||||
40
tests/unit/util/AccountUtilsTests.cpp
Normal file
40
tests/unit/util/AccountUtilsTests.cpp
Normal file
@@ -0,0 +1,40 @@
|
|||||||
|
//------------------------------------------------------------------------------
|
||||||
|
/*
|
||||||
|
This file is part of clio: https://github.com/XRPLF/clio
|
||||||
|
Copyright (c) 2024, the clio developers.
|
||||||
|
|
||||||
|
Permission to use, copy, modify, and distribute this software for any
|
||||||
|
purpose with or without fee is hereby granted, provided that the above
|
||||||
|
copyright notice and this permission notice appear in all copies.
|
||||||
|
|
||||||
|
THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
|
||||||
|
WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
|
||||||
|
MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
|
||||||
|
ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
|
||||||
|
WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
|
||||||
|
ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
|
||||||
|
OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
||||||
|
*/
|
||||||
|
//==============================================================================
|
||||||
|
|
||||||
|
#include "util/AccountUtils.hpp"
|
||||||
|
|
||||||
|
#include <gtest/gtest.h>
|
||||||
|
#include <ripple/protocol/AccountID.h>
|
||||||
|
#include <ripple/protocol/SecretKey.h>
|
||||||
|
#include <ripple/protocol/tokens.h>
|
||||||
|
|
||||||
|
constexpr static auto ACCOUNT = "rf1BiGeXwwQoi8Z2ueFYTEXSwuJYfV2Jpn";
|
||||||
|
|
||||||
|
TEST(AccountUtils, parseBase58Wrapper)
|
||||||
|
{
|
||||||
|
EXPECT_FALSE(util::parseBase58Wrapper<ripple::AccountID>("rf1BiGeXwwQoi8Z2ueFYTEXSwuJYfV2Jp!"));
|
||||||
|
EXPECT_TRUE(util::parseBase58Wrapper<ripple::AccountID>(ACCOUNT));
|
||||||
|
|
||||||
|
EXPECT_TRUE(util::parseBase58Wrapper<ripple::SecretKey>(
|
||||||
|
ripple::TokenType::NodePrivate, "paQmjZ37pKKPMrgadBLsuf9ab7Y7EUNzh27LQrZqoexpAs31nJi"
|
||||||
|
));
|
||||||
|
EXPECT_FALSE(util::parseBase58Wrapper<ripple::SecretKey>(
|
||||||
|
ripple::TokenType::NodePrivate, "??paQmjZ37pKKPMrgadBLsuf9ab7Y7EUNzh27LQrZqoexpAs31n"
|
||||||
|
));
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user