Skip to content

Commit 47f2407

Browse files
PeterChen13579ckeshava
authored andcommitted
APIv2(account_tx, noripple_check): return error on invalid input (XRPLF#4620)
For the `account_tx` and `noripple_check` methods, perform input validation for optional parameters such as "binary", "forward", "strict", "transactions". Previously, when these parameters had invalid values (e.g. not a bool), no error would be returned. Now, it returns an `invalidParams` error. * This updates the behavior to match Clio (https://github.com/XRPLF/clio). * Since this is potentially a breaking change, it only applies to requests specifying api_version: 2. * Fix XRPLF#4543.
1 parent c8ef65c commit 47f2407

File tree

5 files changed

+201
-135
lines changed

5 files changed

+201
-135
lines changed

src/ripple/rpc/handlers/AccountInfo.cpp

+6-4
Original file line numberDiff line numberDiff line change
@@ -134,10 +134,12 @@ doAccountInfo(RPC::JsonContext& context)
134134

135135
result[jss::account_flags] = std::move(acctFlags);
136136

137-
// The document states that signer_lists is a bool, however
138-
// assigning any string value works. Do not allow this.
139-
// This check is for api Version 2 onwards only
140-
if (!params[jss::signer_lists].isBool() && context.apiVersion > 1)
137+
// The document[https://xrpl.org/account_info.html#account_info] states
138+
// that signer_lists is a bool, however assigning any string value
139+
// works. Do not allow this. This check is for api Version 2 onwards
140+
// only
141+
if (context.apiVersion > 1u && params.isMember(jss::signer_lists) &&
142+
!params[jss::signer_lists].isBool())
141143
{
142144
RPC::inject_error(rpcINVALID_PARAMS, result);
143145
return result;

src/ripple/rpc/handlers/AccountTx.cpp

+17-2
Original file line numberDiff line numberDiff line change
@@ -58,7 +58,7 @@ parseLedgerArgs(RPC::Context& context, Json::Value const& params)
5858
Json::Value response;
5959
// if ledger_index_min or max is specified, then ledger_hash or ledger_index
6060
// should not be specified. Error out if it is
61-
if (context.apiVersion > 1)
61+
if (context.apiVersion > 1u)
6262
{
6363
if ((params.isMember(jss::ledger_index_min) ||
6464
params.isMember(jss::ledger_index_max)) &&
@@ -162,7 +162,7 @@ getLedgerRange(
162162
// if ledger_index_min or ledger_index_max is out of
163163
// valid ledger range, error out. exclude -1 as
164164
// it is a valid input
165-
if (context.apiVersion > 1)
165+
if (context.apiVersion > 1u)
166166
{
167167
if ((ls.max > uValidatedMax && ls.max != -1) ||
168168
(ls.min < uValidatedMin && ls.min != 0))
@@ -389,6 +389,21 @@ doAccountTxJson(RPC::JsonContext& context)
389389
AccountTxArgs args;
390390
Json::Value response;
391391

392+
// The document[https://xrpl.org/account_tx.html#account_tx] states that
393+
// binary and forward params are both boolean values, however, assigning any
394+
// string value works. Do not allow this. This check is for api Version 2
395+
// onwards only
396+
if (context.apiVersion > 1u && params.isMember(jss::binary) &&
397+
!params[jss::binary].isBool())
398+
{
399+
return rpcError(rpcINVALID_PARAMS);
400+
}
401+
if (context.apiVersion > 1u && params.isMember(jss::forward) &&
402+
!params[jss::forward].isBool())
403+
{
404+
return rpcError(rpcINVALID_PARAMS);
405+
}
406+
392407
args.limit = params.isMember(jss::limit) ? params[jss::limit].asUInt() : 0;
393408
args.binary = params.isMember(jss::binary) && params[jss::binary].asBool();
394409
args.forward =

src/ripple/rpc/handlers/NoRippleCheck.cpp

+10
Original file line numberDiff line numberDiff line change
@@ -83,6 +83,16 @@ doNoRippleCheck(RPC::JsonContext& context)
8383
if (params.isMember(jss::transactions))
8484
transactions = params["transactions"].asBool();
8585

86+
// The document[https://xrpl.org/noripple_check.html#noripple_check] states
87+
// that transactions params is a boolean value, however, assigning any
88+
// string value works. Do not allow this. This check is for api Version 2
89+
// onwards only
90+
if (context.apiVersion > 1u && params.isMember(jss::transactions) &&
91+
!params[jss::transactions].isBool())
92+
{
93+
return rpcError(rpcINVALID_PARAMS);
94+
}
95+
8696
std::shared_ptr<ReadView const> ledger;
8797
auto result = RPC::lookupLedger(ledger, context);
8898
if (!ledger)

src/test/rpc/AccountTx_test.cpp

+138-122
Original file line numberDiff line numberDiff line change
@@ -144,176 +144,192 @@ class AccountTx_test : public beast::unit_test::suite
144144
Json::Value jParms;
145145
jParms[jss::api_version] = apiVersion;
146146

147-
if (apiVersion < 2)
148-
{
149-
BEAST_EXPECT(isErr(
150-
env.rpc("json", "account_tx", to_string(jParms)),
151-
rpcINVALID_PARAMS));
147+
BEAST_EXPECT(isErr(
148+
env.rpc("json", "account_tx", to_string(jParms)),
149+
rpcINVALID_PARAMS));
152150

153-
jParms[jss::account] = "0xDEADBEEF";
151+
jParms[jss::account] = "0xDEADBEEF";
154152

155-
BEAST_EXPECT(isErr(
156-
env.rpc("json", "account_tx", to_string(jParms)),
157-
rpcACT_MALFORMED));
153+
BEAST_EXPECT(isErr(
154+
env.rpc("json", "account_tx", to_string(jParms)),
155+
rpcACT_MALFORMED));
158156

159-
jParms[jss::account] = A1.human();
160-
BEAST_EXPECT(
161-
hasTxs(env.rpc("json", "account_tx", to_string(jParms))));
157+
jParms[jss::account] = A1.human();
158+
BEAST_EXPECT(hasTxs(env.rpc("json", "account_tx", to_string(jParms))));
162159

163-
// Ledger min/max index
164-
{
165-
Json::Value p{jParms};
166-
p[jss::ledger_index_min] = -1;
167-
p[jss::ledger_index_max] = -1;
168-
BEAST_EXPECT(
169-
hasTxs(env.rpc("json", "account_tx", to_string(p))));
170-
171-
p[jss::ledger_index_min] = 0;
172-
p[jss::ledger_index_max] = 100;
160+
// Ledger min/max index
161+
{
162+
Json::Value p{jParms};
163+
p[jss::ledger_index_min] = -1;
164+
p[jss::ledger_index_max] = -1;
165+
BEAST_EXPECT(hasTxs(env.rpc("json", "account_tx", to_string(p))));
166+
167+
p[jss::ledger_index_min] = 0;
168+
p[jss::ledger_index_max] = 100;
169+
if (apiVersion < 2u)
173170
BEAST_EXPECT(
174171
hasTxs(env.rpc("json", "account_tx", to_string(p))));
172+
else
173+
BEAST_EXPECT(isErr(
174+
env.rpc("json", "account_tx", to_string(p)),
175+
rpcLGR_IDX_MALFORMED));
175176

176-
p[jss::ledger_index_min] = 1;
177-
p[jss::ledger_index_max] = 2;
177+
p[jss::ledger_index_min] = 1;
178+
p[jss::ledger_index_max] = 2;
179+
if (apiVersion < 2u)
178180
BEAST_EXPECT(
179181
noTxs(env.rpc("json", "account_tx", to_string(p))));
180-
181-
p[jss::ledger_index_min] = 2;
182-
p[jss::ledger_index_max] = 1;
182+
else
183183
BEAST_EXPECT(isErr(
184184
env.rpc("json", "account_tx", to_string(p)),
185-
(RPC::apiMaximumSupportedVersion == 1
186-
? rpcLGR_IDXS_INVALID
187-
: rpcINVALID_LGR_RANGE)));
188-
}
185+
rpcLGR_IDX_MALFORMED));
189186

190-
// Ledger index min only
191-
{
192-
Json::Value p{jParms};
193-
p[jss::ledger_index_min] = -1;
194-
BEAST_EXPECT(
195-
hasTxs(env.rpc("json", "account_tx", to_string(p))));
187+
p[jss::ledger_index_min] = 2;
188+
p[jss::ledger_index_max] = 1;
189+
BEAST_EXPECT(isErr(
190+
env.rpc("json", "account_tx", to_string(p)),
191+
(apiVersion == 1 ? rpcLGR_IDXS_INVALID
192+
: rpcINVALID_LGR_RANGE)));
193+
}
194+
// Ledger index min only
195+
{
196+
Json::Value p{jParms};
197+
p[jss::ledger_index_min] = -1;
198+
BEAST_EXPECT(hasTxs(env.rpc("json", "account_tx", to_string(p))));
196199

197-
p[jss::ledger_index_min] = 1;
200+
p[jss::ledger_index_min] = 1;
201+
if (apiVersion < 2u)
198202
BEAST_EXPECT(
199203
hasTxs(env.rpc("json", "account_tx", to_string(p))));
200-
201-
p[jss::ledger_index_min] = env.current()->info().seq;
204+
else
202205
BEAST_EXPECT(isErr(
203206
env.rpc("json", "account_tx", to_string(p)),
204-
(RPC::apiMaximumSupportedVersion == 1
205-
? rpcLGR_IDXS_INVALID
206-
: rpcINVALID_LGR_RANGE)));
207-
}
207+
rpcLGR_IDX_MALFORMED));
208208

209-
// Ledger index max only
210-
{
211-
Json::Value p{jParms};
212-
p[jss::ledger_index_max] = -1;
213-
BEAST_EXPECT(
214-
hasTxs(env.rpc("json", "account_tx", to_string(p))));
209+
p[jss::ledger_index_min] = env.current()->info().seq;
210+
BEAST_EXPECT(isErr(
211+
env.rpc("json", "account_tx", to_string(p)),
212+
(apiVersion == 1 ? rpcLGR_IDXS_INVALID
213+
: rpcINVALID_LGR_RANGE)));
214+
}
215215

216-
p[jss::ledger_index_max] = env.current()->info().seq;
217-
BEAST_EXPECT(
218-
hasTxs(env.rpc("json", "account_tx", to_string(p))));
216+
// Ledger index max only
217+
{
218+
Json::Value p{jParms};
219+
p[jss::ledger_index_max] = -1;
220+
BEAST_EXPECT(hasTxs(env.rpc("json", "account_tx", to_string(p))));
219221

220-
p[jss::ledger_index_max] = 3;
222+
p[jss::ledger_index_max] = env.current()->info().seq;
223+
if (apiVersion < 2u)
221224
BEAST_EXPECT(
222225
hasTxs(env.rpc("json", "account_tx", to_string(p))));
226+
else
227+
BEAST_EXPECT(isErr(
228+
env.rpc("json", "account_tx", to_string(p)),
229+
rpcLGR_IDX_MALFORMED));
223230

224-
p[jss::ledger_index_max] = env.closed()->info().seq;
225-
BEAST_EXPECT(
226-
hasTxs(env.rpc("json", "account_tx", to_string(p))));
231+
p[jss::ledger_index_max] = 3;
232+
BEAST_EXPECT(hasTxs(env.rpc("json", "account_tx", to_string(p))));
227233

228-
p[jss::ledger_index_max] = env.closed()->info().seq - 1;
229-
BEAST_EXPECT(
230-
noTxs(env.rpc("json", "account_tx", to_string(p))));
231-
}
234+
p[jss::ledger_index_max] = env.closed()->info().seq;
235+
BEAST_EXPECT(hasTxs(env.rpc("json", "account_tx", to_string(p))));
232236

233-
// Ledger Sequence
234-
{
235-
Json::Value p{jParms};
237+
p[jss::ledger_index_max] = env.closed()->info().seq - 1;
238+
BEAST_EXPECT(noTxs(env.rpc("json", "account_tx", to_string(p))));
239+
}
236240

237-
p[jss::ledger_index] = env.closed()->info().seq;
238-
BEAST_EXPECT(
239-
hasTxs(env.rpc("json", "account_tx", to_string(p))));
241+
// Ledger Sequence
242+
{
243+
Json::Value p{jParms};
240244

241-
p[jss::ledger_index] = env.closed()->info().seq - 1;
242-
BEAST_EXPECT(
243-
noTxs(env.rpc("json", "account_tx", to_string(p))));
245+
p[jss::ledger_index] = env.closed()->info().seq;
246+
BEAST_EXPECT(hasTxs(env.rpc("json", "account_tx", to_string(p))));
244247

245-
p[jss::ledger_index] = env.current()->info().seq;
246-
BEAST_EXPECT(isErr(
247-
env.rpc("json", "account_tx", to_string(p)),
248-
rpcLGR_NOT_VALIDATED));
248+
p[jss::ledger_index] = env.closed()->info().seq - 1;
249+
BEAST_EXPECT(noTxs(env.rpc("json", "account_tx", to_string(p))));
249250

250-
p[jss::ledger_index] = env.current()->info().seq + 1;
251-
BEAST_EXPECT(isErr(
252-
env.rpc("json", "account_tx", to_string(p)),
253-
rpcLGR_NOT_FOUND));
254-
}
251+
p[jss::ledger_index] = env.current()->info().seq;
252+
BEAST_EXPECT(isErr(
253+
env.rpc("json", "account_tx", to_string(p)),
254+
rpcLGR_NOT_VALIDATED));
255255

256-
// Ledger Hash
257-
{
258-
Json::Value p{jParms};
256+
p[jss::ledger_index] = env.current()->info().seq + 1;
257+
BEAST_EXPECT(isErr(
258+
env.rpc("json", "account_tx", to_string(p)), rpcLGR_NOT_FOUND));
259+
}
259260

260-
p[jss::ledger_hash] = to_string(env.closed()->info().hash);
261-
BEAST_EXPECT(
262-
hasTxs(env.rpc("json", "account_tx", to_string(p))));
261+
// Ledger Hash
262+
{
263+
Json::Value p{jParms};
263264

264-
p[jss::ledger_hash] =
265-
to_string(env.closed()->info().parentHash);
266-
BEAST_EXPECT(
267-
noTxs(env.rpc("json", "account_tx", to_string(p))));
268-
}
265+
p[jss::ledger_hash] = to_string(env.closed()->info().hash);
266+
BEAST_EXPECT(hasTxs(env.rpc("json", "account_tx", to_string(p))));
267+
268+
p[jss::ledger_hash] = to_string(env.closed()->info().parentHash);
269+
BEAST_EXPECT(noTxs(env.rpc("json", "account_tx", to_string(p))));
269270
}
270-
else
271+
272+
// Ledger index max/min/index all specified
273+
// ERRORS out with invalid Parenthesis
271274
{
272-
// Ledger index max/min/index all specified
273-
// ERRORS out with invalid Parenthesis
274-
{
275-
jParms[jss::account] = "0xDEADBEEF";
276-
jParms[jss::account] = A1.human();
277-
Json::Value p{jParms};
275+
jParms[jss::account] = "0xDEADBEEF";
276+
jParms[jss::account] = A1.human();
277+
Json::Value p{jParms};
278278

279-
p[jss::ledger_index_max] = -1;
280-
p[jss::ledger_index_min] = -1;
281-
p[jss::ledger_index] = -1;
279+
p[jss::ledger_index_max] = -1;
280+
p[jss::ledger_index_min] = -1;
281+
p[jss::ledger_index] = -1;
282282

283+
if (apiVersion < 2u)
284+
BEAST_EXPECT(
285+
hasTxs(env.rpc("json", "account_tx", to_string(p))));
286+
else
283287
BEAST_EXPECT(isErr(
284288
env.rpc("json", "account_tx", to_string(p)),
285289
rpcINVALID_PARAMS));
286-
}
287-
288-
// Ledger index min/max only
289-
{
290-
Json::Value p{jParms};
291-
p[jss::ledger_index_max] = 100;
292-
p[jss::ledger_index_min] = 0;
293-
BEAST_EXPECT(isErr(
294-
env.rpc("json", "account_tx", to_string(p)),
295-
rpcLGR_IDX_MALFORMED));
290+
}
296291

297-
p[jss::ledger_index_max] = -1;
298-
p[jss::ledger_index_min] = -1;
292+
// Ledger index max only
293+
{
294+
Json::Value p{jParms};
295+
p[jss::ledger_index_max] = env.current()->info().seq;
296+
if (apiVersion < 2u)
299297
BEAST_EXPECT(
300298
hasTxs(env.rpc("json", "account_tx", to_string(p))));
301-
302-
p[jss::ledger_index_min] = 2;
303-
p[jss::ledger_index_max] = 1;
299+
else
304300
BEAST_EXPECT(isErr(
305301
env.rpc("json", "account_tx", to_string(p)),
306-
rpcINVALID_LGR_RANGE));
302+
rpcLGR_IDX_MALFORMED));
303+
}
304+
// test binary and forward for bool/non bool values
305+
{
306+
Json::Value p{jParms};
307+
p[jss::binary] = "asdf";
308+
if (apiVersion < 2u)
309+
{
310+
Json::Value result{env.rpc("json", "account_tx", to_string(p))};
311+
BEAST_EXPECT(result[jss::result][jss::status] == "success");
307312
}
313+
else
314+
BEAST_EXPECT(isErr(
315+
env.rpc("json", "account_tx", to_string(p)),
316+
rpcINVALID_PARAMS));
308317

309-
// Ledger index max only
310-
{
311-
Json::Value p{jParms};
312-
p[jss::ledger_index_max] = env.current()->info().seq;
318+
p[jss::binary] = true;
319+
Json::Value result{env.rpc("json", "account_tx", to_string(p))};
320+
BEAST_EXPECT(result[jss::result][jss::status] == "success");
321+
322+
p[jss::forward] = "true";
323+
if (apiVersion < 2u)
324+
BEAST_EXPECT(result[jss::result][jss::status] == "success");
325+
else
313326
BEAST_EXPECT(isErr(
314327
env.rpc("json", "account_tx", to_string(p)),
315-
rpcLGR_IDX_MALFORMED));
316-
}
328+
rpcINVALID_PARAMS));
329+
330+
p[jss::forward] = false;
331+
result = env.rpc("json", "account_tx", to_string(p));
332+
BEAST_EXPECT(result[jss::result][jss::status] == "success");
317333
}
318334
}
319335

0 commit comments

Comments
 (0)