Clio  develop
The XRP Ledger API server.
Loading...
Searching...
No Matches
Validators.hpp
1//------------------------------------------------------------------------------
2/*
3 This file is part of clio: https://github.com/XRPLF/clio
4 Copyright (c) 2023, 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 "rpc/Errors.hpp"
23#include "rpc/common/Types.hpp"
24#include "rpc/common/ValidationHelpers.hpp"
25
26#include <boost/json/array.hpp>
27#include <boost/json/object.hpp>
28#include <boost/json/value.hpp>
29#include <fmt/format.h>
30#include <xrpl/basics/base_uint.h>
31#include <xrpl/protocol/ErrorCodes.h>
32
33#include <concepts>
34#include <ctime>
35#include <functional>
36#include <initializer_list>
37#include <string>
38#include <string_view>
39#include <utility>
40#include <vector>
41
42namespace rpc::validation {
43
47struct Required final {
55 [[nodiscard]] static MaybeError
56 verify(boost::json::value const& value, std::string_view key);
57};
58
65template <typename... T>
67
71template <typename T>
72class NotSupported<T> final {
73 T value_;
74
75public:
81 NotSupported(T val) : value_(val)
82 {
83 }
84
92 [[nodiscard]] MaybeError
93 verify(boost::json::value const& value, std::string_view key) const
94 {
95 if (value.is_object() and value.as_object().contains(key)) {
96 using boost::json::value_to;
97 auto const res = value_to<T>(value.as_object().at(key));
98 if (value_ == res) {
99 return Error{Status{
100 RippledError::rpcNOT_SUPPORTED,
101 fmt::format("Not supported field '{}'s value '{}'", std::string{key}, res)
102 }};
103 }
104 }
105 return {};
106 }
107};
108
112template <>
113class NotSupported<> final {
114public:
122 [[nodiscard]] static MaybeError
123 verify(boost::json::value const& value, std::string_view key)
124 {
125 if (value.is_object() and value.as_object().contains(key))
126 return Error{Status{RippledError::rpcNOT_SUPPORTED, "Not supported field '" + std::string{key} + '\''}};
127
128 return {};
129 }
130};
131
135template <typename... T>
136NotSupported(T&&... t) -> NotSupported<T...>;
137
141template <typename... Types>
142struct Type final {
152 [[nodiscard]] MaybeError
153 verify(boost::json::value& value, std::string_view key) const
154 {
155 if (not value.is_object() or not value.as_object().contains(key))
156 return {}; // ignore. If field is supposed to exist, let 'required' fail instead
157
158 auto& res = value.as_object().at(key);
159 auto const convertible = (checkTypeAndClamp<Types>(res) || ...);
160
161 if (not convertible)
162 return Error{Status{RippledError::rpcINVALID_PARAMS}};
163
164 return {};
165 }
166};
167
171template <typename Type>
172class Between final {
173 Type min_;
174 Type max_;
175
176public:
183 explicit Between(Type min, Type max) : min_{min}, max_{max}
184 {
185 }
186
194 [[nodiscard]] MaybeError
195 verify(boost::json::value const& value, std::string_view key) const
196 {
197 using boost::json::value_to;
198
199 if (not value.is_object() or not value.as_object().contains(key))
200 return {}; // ignore. field does not exist, let 'required' fail instead
201
202 auto const res = value_to<Type>(value.as_object().at(key));
203
204 // TODO: may want a way to make this code more generic (e.g. use a free
205 // function that can be overridden for this comparison)
206 if (res < min_ || res > max_)
207 return Error{Status{RippledError::rpcINVALID_PARAMS}};
208
209 return {};
210 }
211};
212
216template <typename Type>
217class Min final {
218 Type min_;
219
220public:
226 explicit Min(Type min) : min_{min}
227 {
228 }
229
237 [[nodiscard]] MaybeError
238 verify(boost::json::value const& value, std::string_view key) const
239 {
240 using boost::json::value_to;
241
242 if (not value.is_object() or not value.as_object().contains(key))
243 return {}; // ignore. field does not exist, let 'required' fail instead
244
245 auto const res = value_to<Type>(value.as_object().at(key));
246
247 if (res < min_)
248 return Error{Status{RippledError::rpcINVALID_PARAMS}};
249
250 return {};
251 }
252};
253
257template <typename Type>
258class Max final {
259 Type max_;
260
261public:
267 explicit Max(Type max) : max_{max}
268 {
269 }
270
278 [[nodiscard]] MaybeError
279 verify(boost::json::value const& value, std::string_view key) const
280 {
281 using boost::json::value_to;
282
283 if (not value.is_object() or not value.as_object().contains(key))
284 return {}; // ignore. field does not exist, let 'required' fail instead
285
286 auto const res = value_to<Type>(value.as_object().at(key));
287
288 if (res > max_)
289 return Error{Status{RippledError::rpcINVALID_PARAMS}};
290
291 return {};
292 }
293};
294
299 std::string format_;
300
301public:
307 explicit TimeFormatValidator(std::string format) : format_{std::move(format)}
308 {
309 }
310
318 [[nodiscard]] MaybeError
319 verify(boost::json::value const& value, std::string_view key) const;
320};
321
325template <typename Type>
326class EqualTo final {
327 Type original_;
328
329public:
335 explicit EqualTo(Type original) : original_{std::move(original)}
336 {
337 }
338
346 [[nodiscard]] MaybeError
347 verify(boost::json::value const& value, std::string_view key) const
348 {
349 using boost::json::value_to;
350
351 if (not value.is_object() or not value.as_object().contains(key))
352 return {}; // ignore. field does not exist, let 'required' fail instead
353
354 auto const res = value_to<Type>(value.as_object().at(key));
355 if (res != original_)
356 return Error{Status{RippledError::rpcINVALID_PARAMS}};
357
358 return {};
359 }
360};
361
365EqualTo(char const*) -> EqualTo<std::string>;
366
370template <typename Type>
371class OneOf final {
372 std::vector<Type> options_;
373
374public:
380 explicit OneOf(std::initializer_list<Type> options) : options_{options}
381 {
382 }
383
389 template <typename InputIt>
390 explicit OneOf(InputIt begin, InputIt end) : options_{begin, end}
391 {
392 }
393
401 [[nodiscard]] MaybeError
402 verify(boost::json::value const& value, std::string_view key) const
403 {
404 using boost::json::value_to;
405
406 if (not value.is_object() or not value.as_object().contains(key))
407 return {}; // ignore. field does not exist, let 'required' fail instead
408
409 auto const res = value_to<Type>(value.as_object().at(key));
410 if (std::find(std::begin(options_), std::end(options_), res) == std::end(options_))
411 return Error{Status{RippledError::rpcINVALID_PARAMS, fmt::format("Invalid field '{}'.", key)}};
412
413 return {};
414 }
415};
416
420OneOf(std::initializer_list<char const*>) -> OneOf<std::string>;
421
425class CustomValidator final {
426 std::function<MaybeError(boost::json::value const&, std::string_view)> validator_;
427
428public:
435 template <typename Fn>
436 requires std::invocable<Fn, boost::json::value const&, std::string_view>
437 explicit CustomValidator(Fn&& fn) : validator_{std::forward<Fn>(fn)}
438 {
439 }
440
448 [[nodiscard]] MaybeError
449 verify(boost::json::value const& value, std::string_view key) const;
450};
451
458[[nodiscard]] bool
459checkIsU32Numeric(std::string_view sv);
460
461template <class HexType>
462 requires(
463 std::is_same_v<HexType, ripple::uint160> || std::is_same_v<HexType, ripple::uint192> ||
464 std::is_same_v<HexType, ripple::uint256>
465 )
467makeHexStringValidator(boost::json::value const& value, std::string_view key)
468{
469 if (!value.is_string())
470 return Error{Status{RippledError::rpcINVALID_PARAMS, std::string(key) + "NotString"}};
471
472 HexType parsedInt;
473 if (!parsedInt.parseHex(value.as_string().c_str()))
474 return Error{Status{RippledError::rpcINVALID_PARAMS, std::string(key) + "Malformed"}};
475
476 return MaybeError{};
477}
478
596
600struct Hex256ItemType final {
609 [[nodiscard]] static MaybeError
610 verify(boost::json::value const& value, std::string_view key)
611 {
612 if (not value.is_object() or not value.as_object().contains(key))
613 return {}; // ignore. If field is supposed to exist, let 'required' fail instead
614
615 auto const& res = value.as_object().at(key);
616
617 // loop through each item in the array and make sure it is uint256 hex string
618 for (auto const& elem : res.as_array()) {
619 ripple::uint256 num;
620 if (!elem.is_string() || !num.parseHex(elem.as_string())) {
621 return Error{Status{RippledError::rpcINVALID_PARAMS, "Item is not a valid uint256 type."}};
622 }
623 }
624 return {};
625 }
626};
627
628} // namespace rpc::validation
MaybeError verify(boost::json::value const &value, std::string_view key) const
Verify that the JSON value is within a certain range.
Definition Validators.hpp:195
Between(Type min, Type max)
Construct the validator storing min and max values.
Definition Validators.hpp:183
A meta-validator that allows to specify a custom validation function.
Definition Validators.hpp:425
MaybeError verify(boost::json::value const &value, std::string_view key) const
Verify that the JSON value is valid according to the custom validation function stored.
Definition Validators.cpp:79
CustomValidator(Fn &&fn)
Constructs a custom validator from any supported callable.
Definition Validators.hpp:437
MaybeError verify(boost::json::value const &value, std::string_view key) const
Verify that the JSON value is equal to the stored original.
Definition Validators.hpp:347
EqualTo(Type original)
Construct the validator with stored original value.
Definition Validators.hpp:335
Max(Type max)
Construct the validator storing max value.
Definition Validators.hpp:267
MaybeError verify(boost::json::value const &value, std::string_view key) const
Verify that the JSON value is not greater than max.
Definition Validators.hpp:279
MaybeError verify(boost::json::value const &value, std::string_view key) const
Verify that the JSON value is not smaller than min.
Definition Validators.hpp:238
Min(Type min)
Construct the validator storing min value.
Definition Validators.hpp:226
MaybeError verify(boost::json::value const &value, std::string_view key) const
Verify whether the field is supported or not.
Definition Validators.hpp:93
NotSupported(T val)
Constructs a new NotSupported validator.
Definition Validators.hpp:81
static MaybeError verify(boost::json::value const &value, std::string_view key)
Verify whether the field is supported or not.
Definition Validators.hpp:123
A validator that forbids a field to be present.
Definition Validators.hpp:66
OneOf(std::initializer_list< Type > options)
Construct the validator with stored options of initializer list.
Definition Validators.hpp:380
OneOf(InputIt begin, InputIt end)
Construct the validator with stored options of other container.
Definition Validators.hpp:390
MaybeError verify(boost::json::value const &value, std::string_view key) const
Verify that the JSON value is one of the stored options.
Definition Validators.hpp:402
MaybeError verify(boost::json::value const &value, std::string_view key) const
Verify that the JSON value is valid formatted time.
Definition Validators.cpp:61
TimeFormatValidator(std::string format)
Construct the validator storing format value.
Definition Validators.hpp:307
std::expected< void, Status > MaybeError
Return type used for Validators that can return error but don't have specific value to return.
Definition Types.hpp:55
std::unexpected< Status > Error
The type that represents just the error part of MaybeError.
Definition Types.hpp:75
A status returned from any RPC handler.
Definition Errors.hpp:83
A group of custom validation functions.
Definition Validators.hpp:482
static CustomValidator uint160HexStringValidator
Provides a commonly used validator for uint160(AccountID) hex string.
Definition Validators.hpp:535
static CustomValidator credentialTypeValidator
Provides a validator for validating credential_type.
Definition Validators.hpp:594
static CustomValidator accountValidator
Provides a commonly used validator for accounts.
Definition Validators.hpp:504
static CustomValidator ledgerTypeValidator
Provides a validator for ledger type.
Definition Validators.hpp:497
static CustomValidator currencyValidator
Provides a commonly used validator for currency, including standard currency code and token code.
Definition Validators.hpp:556
static CustomValidator accountTypeValidator
Provides a validator for account type.
Definition Validators.hpp:527
static CustomValidator accountMarkerValidator
Provides a commonly used validator for markers.
Definition Validators.hpp:519
static CustomValidator issuerValidator
Provides a commonly used validator for issuer type.
Definition Validators.hpp:563
static CustomValidator ledgerIndexValidator
Provides a commonly used validator for ledger index.
Definition Validators.hpp:489
static CustomValidator currencyIssueValidator
Validates an asset (ripple::Issue).
Definition Validators.hpp:580
static CustomValidator subscribeAccountsValidator
Provides a validator for validating accounts used in subscribe/unsubscribe.
Definition Validators.hpp:573
static CustomValidator authorizeCredentialValidator
Provides a validator for validating authorized_credentials json array.
Definition Validators.hpp:587
static CustomValidator uint192HexStringValidator
Provides a commonly used validator for uint192 hex string.
Definition Validators.hpp:543
static CustomValidator uint256HexStringValidator
Provides a commonly used validator for uint256 hex string.
Definition Validators.hpp:551
static CustomValidator subscribeStreamValidator
Provides a validator for validating streams used in subscribe/unsubscribe.
Definition Validators.hpp:568
static CustomValidator accountBase58Validator
Provides a commonly used validator for accounts.
Definition Validators.hpp:511
Validates that the elements of the array is of type Hex256 uint.
Definition Validators.hpp:600
static MaybeError verify(boost::json::value const &value, std::string_view key)
Validates given the prerequisite that the type of the json value is an array, verifies all values wit...
Definition Validators.hpp:610
A validator that simply requires a field to be present.
Definition Validators.hpp:47
static MaybeError verify(boost::json::value const &value, std::string_view key)
Verify that the JSON value is present and not null.
Definition Validators.cpp:52
Validates that the type of the value is one of the given types.
Definition Validators.hpp:142
MaybeError verify(boost::json::value &value, std::string_view key) const
Verify that the JSON value is (one) of specified type(s).
Definition Validators.hpp:153