Skip to content

Commit 665fab1

Browse files
cindyyan317godexsoft
authored andcommitted
fix: Add more account check (#1543)
Make sure all char is alphanumeric for account
1 parent b65ac67 commit 665fab1

File tree

11 files changed

+183
-37
lines changed

11 files changed

+183
-37
lines changed

src/rpc/RPCHelpers.cpp

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,7 @@
2424
#include "rpc/Errors.hpp"
2525
#include "rpc/JS.hpp"
2626
#include "rpc/common/Types.hpp"
27+
#include "util/AccountUtils.hpp"
2728
#include "util/Profiler.hpp"
2829
#include "util/log/Logger.hpp"
2930
#include "web/Context.hpp"
@@ -186,14 +187,14 @@ accountFromStringStrict(std::string const& account)
186187
if (blob && ripple::publicKeyType(ripple::makeSlice(*blob))) {
187188
publicKey = ripple::PublicKey(ripple::Slice{blob->data(), blob->size()});
188189
} else {
189-
publicKey = ripple::parseBase58<ripple::PublicKey>(ripple::TokenType::AccountPublic, account);
190+
publicKey = util::parseBase58Wrapper<ripple::PublicKey>(ripple::TokenType::AccountPublic, account);
190191
}
191192

192193
std::optional<ripple::AccountID> result;
193194
if (publicKey) {
194195
result = ripple::calcAccountID(*publicKey);
195196
} else {
196-
result = ripple::parseBase58<ripple::AccountID>(account);
197+
result = util::parseBase58Wrapper<ripple::AccountID>(account);
197198
}
198199

199200
return result;
@@ -799,7 +800,7 @@ getAccountsFromTransaction(boost::json::object const& transaction)
799800
auto inObject = getAccountsFromTransaction(value.as_object());
800801
accounts.insert(accounts.end(), inObject.begin(), inObject.end());
801802
} else if (value.is_string()) {
802-
auto const account = ripple::parseBase58<ripple::AccountID>(boost::json::value_to<std::string>(value));
803+
auto const account = util::parseBase58Wrapper<ripple::AccountID>(boost::json::value_to<std::string>(value));
803804
if (account) {
804805
accounts.push_back(*account);
805806
}

src/rpc/common/Validators.cpp

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,7 @@
2222
#include "rpc/Errors.hpp"
2323
#include "rpc/RPCHelpers.hpp"
2424
#include "rpc/common/Types.hpp"
25+
#include "util/AccountUtils.hpp"
2526

2627
#include <boost/json/object.hpp>
2728
#include <boost/json/value.hpp>
@@ -114,7 +115,7 @@ CustomValidator AccountBase58Validator =
114115
if (!value.is_string())
115116
return Error{Status{RippledError::rpcINVALID_PARAMS, std::string(key) + "NotString"}};
116117

117-
auto const account = ripple::parseBase58<ripple::AccountID>(boost::json::value_to<std::string>(value));
118+
auto const account = util::parseBase58Wrapper<ripple::AccountID>(boost::json::value_to<std::string>(value));
118119
if (!account || account->isZero())
119120
return Error{Status{ClioError::rpcMALFORMED_ADDRESS}};
120121

src/rpc/handlers/GatewayBalances.hpp

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,7 @@
2525
#include "rpc/common/Specs.hpp"
2626
#include "rpc/common/Types.hpp"
2727
#include "rpc/common/Validators.hpp"
28+
#include "util/AccountUtils.hpp"
2829

2930
#include <boost/json/array.hpp>
3031
#include <boost/json/conversion.hpp>
@@ -116,14 +117,14 @@ class GatewayBalancesHandler {
116117
auto const wallets = value.is_array() ? value.as_array() : boost::json::array{value};
117118
auto const getAccountID = [](auto const& j) -> std::optional<ripple::AccountID> {
118119
if (j.is_string()) {
119-
auto const pk = ripple::parseBase58<ripple::PublicKey>(
120+
auto const pk = util::parseBase58Wrapper<ripple::PublicKey>(
120121
ripple::TokenType::AccountPublic, boost::json::value_to<std::string>(j)
121122
);
122123

123124
if (pk)
124125
return ripple::calcAccountID(*pk);
125126

126-
return ripple::parseBase58<ripple::AccountID>(boost::json::value_to<std::string>(j));
127+
return util::parseBase58Wrapper<ripple::AccountID>(boost::json::value_to<std::string>(j));
127128
}
128129

129130
return {};

src/rpc/handlers/GetAggregatePrice.cpp

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,7 @@
2323
#include "rpc/JS.hpp"
2424
#include "rpc/RPCHelpers.hpp"
2525
#include "rpc/common/Types.hpp"
26+
#include "util/AccountUtils.hpp"
2627

2728
#include <boost/asio/spawn.hpp>
2829
#include <boost/bimap/bimap.hpp>
@@ -263,7 +264,7 @@ tag_invoke(boost::json::value_to_tag<GetAggregatePriceHandler::Input>, boost::js
263264
for (auto const& oracle : jsonObject.at(JS(oracles)).as_array()) {
264265
input.oracles.push_back(GetAggregatePriceHandler::Oracle{
265266
.documentId = boost::json::value_to<std::uint64_t>(oracle.as_object().at(JS(oracle_document_id))),
266-
.account = *ripple::parseBase58<ripple::AccountID>(
267+
.account = *util::parseBase58Wrapper<ripple::AccountID>(
267268
boost::json::value_to<std::string>(oracle.as_object().at(JS(account)))
268269
)
269270
});

src/rpc/handlers/LedgerEntry.cpp

Lines changed: 20 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,7 @@
2323
#include "rpc/JS.hpp"
2424
#include "rpc/RPCHelpers.hpp"
2525
#include "rpc/common/Types.hpp"
26+
#include "util/AccountUtils.hpp"
2627

2728
#include <boost/json/conversion.hpp>
2829
#include <boost/json/object.hpp>
@@ -62,9 +63,9 @@ LedgerEntryHandler::process(LedgerEntryHandler::Input input, Context const& ctx)
6263
if (input.index) {
6364
key = ripple::uint256{std::string_view(*(input.index))};
6465
} else if (input.accountRoot) {
65-
key = ripple::keylet::account(*ripple::parseBase58<ripple::AccountID>(*(input.accountRoot))).key;
66+
key = ripple::keylet::account(*util::parseBase58Wrapper<ripple::AccountID>(*(input.accountRoot))).key;
6667
} else if (input.did) {
67-
key = ripple::keylet::did(*ripple::parseBase58<ripple::AccountID>(*(input.did))).key;
68+
key = ripple::keylet::did(*util::parseBase58Wrapper<ripple::AccountID>(*(input.did))).key;
6869
} else if (input.directory) {
6970
auto const keyOrStatus = composeKeyFromDirectory(*input.directory);
7071
if (auto const status = std::get_if<Status>(&keyOrStatus))
@@ -73,13 +74,14 @@ LedgerEntryHandler::process(LedgerEntryHandler::Input input, Context const& ctx)
7374
key = std::get<ripple::uint256>(keyOrStatus);
7475
} else if (input.offer) {
7576
auto const id =
76-
ripple::parseBase58<ripple::AccountID>(boost::json::value_to<std::string>(input.offer->at(JS(account))));
77+
util::parseBase58Wrapper<ripple::AccountID>(boost::json::value_to<std::string>(input.offer->at(JS(account)))
78+
);
7779
key = ripple::keylet::offer(*id, boost::json::value_to<std::uint32_t>(input.offer->at(JS(seq)))).key;
7880
} else if (input.rippleStateAccount) {
79-
auto const id1 = ripple::parseBase58<ripple::AccountID>(
81+
auto const id1 = util::parseBase58Wrapper<ripple::AccountID>(
8082
boost::json::value_to<std::string>(input.rippleStateAccount->at(JS(accounts)).as_array().at(0))
8183
);
82-
auto const id2 = ripple::parseBase58<ripple::AccountID>(
84+
auto const id2 = util::parseBase58Wrapper<ripple::AccountID>(
8385
boost::json::value_to<std::string>(input.rippleStateAccount->at(JS(accounts)).as_array().at(1))
8486
);
8587
auto const currency =
@@ -88,20 +90,22 @@ LedgerEntryHandler::process(LedgerEntryHandler::Input input, Context const& ctx)
8890
key = ripple::keylet::line(*id1, *id2, currency).key;
8991
} else if (input.escrow) {
9092
auto const id =
91-
ripple::parseBase58<ripple::AccountID>(boost::json::value_to<std::string>(input.escrow->at(JS(owner))));
93+
util::parseBase58Wrapper<ripple::AccountID>(boost::json::value_to<std::string>(input.escrow->at(JS(owner)))
94+
);
9295
key = ripple::keylet::escrow(*id, input.escrow->at(JS(seq)).as_int64()).key;
9396
} else if (input.depositPreauth) {
94-
auto const owner = ripple::parseBase58<ripple::AccountID>(
97+
auto const owner = util::parseBase58Wrapper<ripple::AccountID>(
9598
boost::json::value_to<std::string>(input.depositPreauth->at(JS(owner)))
9699
);
97-
auto const authorized = ripple::parseBase58<ripple::AccountID>(
100+
auto const authorized = util::parseBase58Wrapper<ripple::AccountID>(
98101
boost::json::value_to<std::string>(input.depositPreauth->at(JS(authorized)))
99102
);
100103

101104
key = ripple::keylet::depositPreauth(*owner, *authorized).key;
102105
} else if (input.ticket) {
103106
auto const id =
104-
ripple::parseBase58<ripple::AccountID>(boost::json::value_to<std::string>(input.ticket->at(JS(account))));
107+
util::parseBase58Wrapper<ripple::AccountID>(boost::json::value_to<std::string>(input.ticket->at(JS(account))
108+
));
105109

106110
key = ripple::getTicketIndex(*id, input.ticket->at(JS(ticket_seq)).as_int64());
107111
} else if (input.amm) {
@@ -112,7 +116,8 @@ LedgerEntryHandler::process(LedgerEntryHandler::Input input, Context const& ctx)
112116
return ripple::xrpIssue();
113117
}
114118
auto const issuer =
115-
ripple::parseBase58<ripple::AccountID>(boost::json::value_to<std::string>(assetJson.at(JS(issuer))));
119+
util::parseBase58Wrapper<ripple::AccountID>(boost::json::value_to<std::string>(assetJson.at(JS(issuer)))
120+
);
116121
return ripple::Issue{currency, *issuer};
117122
};
118123

@@ -125,7 +130,7 @@ LedgerEntryHandler::process(LedgerEntryHandler::Input input, Context const& ctx)
125130
return Error{Status{ClioError::rpcMALFORMED_REQUEST}};
126131

127132
if (input.bridgeAccount) {
128-
auto const bridgeAccount = ripple::parseBase58<ripple::AccountID>(*(input.bridgeAccount));
133+
auto const bridgeAccount = util::parseBase58Wrapper<ripple::AccountID>(*(input.bridgeAccount));
129134
auto const chainType = ripple::STXChainBridge::srcChain(bridgeAccount == input.bridge->lockingChainDoor());
130135

131136
if (bridgeAccount != input.bridge->door(chainType))
@@ -201,7 +206,7 @@ LedgerEntryHandler::composeKeyFromDirectory(boost::json::object const& directory
201206
}
202207

203208
auto const ownerID =
204-
ripple::parseBase58<ripple::AccountID>(boost::json::value_to<std::string>(directory.at(JS(owner))));
209+
util::parseBase58Wrapper<ripple::AccountID>(boost::json::value_to<std::string>(directory.at(JS(owner))));
205210
return ripple::keylet::page(ripple::keylet::ownerDir(*ownerID), subIndex).key;
206211
}
207212

@@ -262,10 +267,10 @@ tag_invoke(boost::json::value_to_tag<LedgerEntryHandler::Input>, boost::json::va
262267
};
263268

264269
auto const parseBridgeFromJson = [](boost::json::value const& bridgeJson) {
265-
auto const lockingDoor = *ripple::parseBase58<ripple::AccountID>(
270+
auto const lockingDoor = *util::parseBase58Wrapper<ripple::AccountID>(
266271
boost::json::value_to<std::string>(bridgeJson.at(ripple::sfLockingChainDoor.getJsonName().c_str()))
267272
);
268-
auto const issuingDoor = *ripple::parseBase58<ripple::AccountID>(
273+
auto const issuingDoor = *util::parseBase58Wrapper<ripple::AccountID>(
269274
boost::json::value_to<std::string>(bridgeJson.at(ripple::sfIssuingChainDoor.getJsonName().c_str()))
270275
);
271276
auto const lockingIssue =
@@ -278,7 +283,7 @@ tag_invoke(boost::json::value_to_tag<LedgerEntryHandler::Input>, boost::json::va
278283

279284
auto const parseOracleFromJson = [](boost::json::value const& json) {
280285
auto const account =
281-
ripple::parseBase58<ripple::AccountID>(boost::json::value_to<std::string>(json.at(JS(account))));
286+
util::parseBase58Wrapper<ripple::AccountID>(boost::json::value_to<std::string>(json.at(JS(account))));
282287
auto const documentId = boost::json::value_to<uint32_t>(json.at(JS(oracle_document_id)));
283288

284289
return ripple::keylet::oracle(*account, documentId).key;

src/rpc/handlers/LedgerEntry.hpp

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,7 @@
2828
#include "rpc/common/Specs.hpp"
2929
#include "rpc/common/Types.hpp"
3030
#include "rpc/common/Validators.hpp"
31+
#include "util/AccountUtils.hpp"
3132

3233
#include <boost/json/conversion.hpp>
3334
#include <boost/json/object.hpp>
@@ -136,9 +137,11 @@ class LedgerEntryHandler {
136137
}
137138

138139
auto const id1 =
139-
ripple::parseBase58<ripple::AccountID>(boost::json::value_to<std::string>(value.as_array()[0]));
140+
util::parseBase58Wrapper<ripple::AccountID>(boost::json::value_to<std::string>(value.as_array()[0])
141+
);
140142
auto const id2 =
141-
ripple::parseBase58<ripple::AccountID>(boost::json::value_to<std::string>(value.as_array()[1]));
143+
util::parseBase58Wrapper<ripple::AccountID>(boost::json::value_to<std::string>(value.as_array()[1])
144+
);
142145

143146
if (!id1 || !id2)
144147
return Error{Status{ClioError::rpcMALFORMED_ADDRESS, "malformedAddresses"}};

src/util/AccountUtils.hpp

Lines changed: 67 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,67 @@
1+
//------------------------------------------------------------------------------
2+
/*
3+
This file is part of clio: https://github.com/XRPLF/clio
4+
Copyright (c) 2024, the clio developers.
5+
6+
Permission to use, copy, modify, and distribute this software for any
7+
purpose with or without fee is hereby granted, provided that the above
8+
copyright notice and this permission notice appear in all copies.
9+
10+
THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
11+
WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
12+
MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
13+
ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
14+
WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
15+
ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
16+
OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
17+
*/
18+
//==============================================================================
19+
20+
#pragma once
21+
22+
#include <ripple/protocol/tokens.h>
23+
24+
#include <cctype>
25+
#include <optional>
26+
#include <string>
27+
28+
namespace util {
29+
30+
/**
31+
* @brief A wrapper of parseBase58 function. It adds the check if all characters in the input string are alphanumeric.
32+
* If not, it returns an empty optional, instead of calling the parseBase58 function.
33+
*
34+
* @tparam T The type of the value to parse to.
35+
* @param str The string to parse.
36+
* @return An optional with the parsed value, or an empty optional if the parse fails.
37+
*/
38+
template <class T>
39+
[[nodiscard]] std::optional<T>
40+
parseBase58Wrapper(std::string const& str)
41+
{
42+
if (!std::all_of(std::begin(str), std::end(str), [](unsigned char c) { return std::isalnum(c); }))
43+
return std::nullopt;
44+
45+
return ripple::parseBase58<T>(str);
46+
}
47+
48+
/**
49+
* @brief A wrapper of parseBase58 function. It add the check if all characters in the input string are alphanumeric. If
50+
* not, it returns an empty optional, instead of calling the parseBase58 function.
51+
*
52+
* @tparam T The type of the value to parse to.
53+
* @param type The type of the token to parse.
54+
* @param str The string to parse.
55+
* @return An optional with the parsed value, or an empty optional if the parse fails.
56+
*/
57+
template <class T>
58+
[[nodiscard]] std::optional<T>
59+
parseBase58Wrapper(ripple::TokenType type, std::string const& str)
60+
{
61+
if (!std::all_of(std::begin(str), std::end(str), [](unsigned char c) { return std::isalnum(c); }))
62+
return std::nullopt;
63+
64+
return ripple::parseBase58<T>(type, str);
65+
}
66+
67+
} // namespace util

0 commit comments

Comments
 (0)