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/core.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 {
150 [[nodiscard]] MaybeError
151 verify(boost::json::value const& value, std::string_view key) const
152 {
153 if (not value.is_object() or not value.as_object().contains(key))
154 return {}; // ignore. If field is supposed to exist, let 'required' fail instead
155
156 auto const& res = value.as_object().at(key);
157 auto const convertible = (checkType<Types>(res) || ...);
158
159 if (not convertible)
160 return Error{Status{RippledError::rpcINVALID_PARAMS}};
161
162 return {};
163 }
164};
165
169template <typename Type>
170class Between final {
171 Type min_;
172 Type max_;
173
174public:
181 explicit Between(Type min, Type max) : min_{min}, max_{max}
182 {
183 }
184
192 [[nodiscard]] MaybeError
193 verify(boost::json::value const& value, std::string_view key) const
194 {
195 using boost::json::value_to;
196
197 if (not value.is_object() or not value.as_object().contains(key))
198 return {}; // ignore. field does not exist, let 'required' fail instead
199
200 auto const res = value_to<Type>(value.as_object().at(key));
201
202 // TODO: may want a way to make this code more generic (e.g. use a free
203 // function that can be overridden for this comparison)
204 if (res < min_ || res > max_)
205 return Error{Status{RippledError::rpcINVALID_PARAMS}};
206
207 return {};
208 }
209};
210
214template <typename Type>
215class Min final {
216 Type min_;
217
218public:
224 explicit Min(Type min) : min_{min}
225 {
226 }
227
235 [[nodiscard]] MaybeError
236 verify(boost::json::value const& value, std::string_view key) const
237 {
238 using boost::json::value_to;
239
240 if (not value.is_object() or not value.as_object().contains(key))
241 return {}; // ignore. field does not exist, let 'required' fail instead
242
243 auto const res = value_to<Type>(value.as_object().at(key));
244
245 if (res < min_)
246 return Error{Status{RippledError::rpcINVALID_PARAMS}};
247
248 return {};
249 }
250};
251
255template <typename Type>
256class Max final {
257 Type max_;
258
259public:
265 explicit Max(Type max) : max_{max}
266 {
267 }
268
276 [[nodiscard]] MaybeError
277 verify(boost::json::value const& value, std::string_view key) const
278 {
279 using boost::json::value_to;
280
281 if (not value.is_object() or not value.as_object().contains(key))
282 return {}; // ignore. field does not exist, let 'required' fail instead
283
284 auto const res = value_to<Type>(value.as_object().at(key));
285
286 if (res > max_)
287 return Error{Status{RippledError::rpcINVALID_PARAMS}};
288
289 return {};
290 }
291};
292
297 std::string format_;
298
299public:
305 explicit TimeFormatValidator(std::string format) : format_{std::move(format)}
306 {
307 }
308
316 [[nodiscard]] MaybeError
317 verify(boost::json::value const& value, std::string_view key) const;
318};
319
323template <typename Type>
324class EqualTo final {
325 Type original_;
326
327public:
333 explicit EqualTo(Type original) : original_{std::move(original)}
334 {
335 }
336
344 [[nodiscard]] MaybeError
345 verify(boost::json::value const& value, std::string_view key) const
346 {
347 using boost::json::value_to;
348
349 if (not value.is_object() or not value.as_object().contains(key))
350 return {}; // ignore. field does not exist, let 'required' fail instead
351
352 auto const res = value_to<Type>(value.as_object().at(key));
353 if (res != original_)
354 return Error{Status{RippledError::rpcINVALID_PARAMS}};
355
356 return {};
357 }
358};
359
363EqualTo(char const*) -> EqualTo<std::string>;
364
368template <typename Type>
369class OneOf final {
370 std::vector<Type> options_;
371
372public:
378 explicit OneOf(std::initializer_list<Type> options) : options_{options}
379 {
380 }
381
387 template <typename InputIt>
388 explicit OneOf(InputIt begin, InputIt end) : options_{begin, end}
389 {
390 }
391
399 [[nodiscard]] MaybeError
400 verify(boost::json::value const& value, std::string_view key) const
401 {
402 using boost::json::value_to;
403
404 if (not value.is_object() or not value.as_object().contains(key))
405 return {}; // ignore. field does not exist, let 'required' fail instead
406
407 auto const res = value_to<Type>(value.as_object().at(key));
408 if (std::find(std::begin(options_), std::end(options_), res) == std::end(options_))
409 return Error{Status{RippledError::rpcINVALID_PARAMS, fmt::format("Invalid field '{}'.", key)}};
410
411 return {};
412 }
413};
414
418OneOf(std::initializer_list<char const*>) -> OneOf<std::string>;
419
423class CustomValidator final {
424 std::function<MaybeError(boost::json::value const&, std::string_view)> validator_;
425
426public:
433 template <typename Fn>
434 requires std::invocable<Fn, boost::json::value const&, std::string_view>
435 explicit CustomValidator(Fn&& fn) : validator_{std::forward<Fn>(fn)}
436 {
437 }
438
446 [[nodiscard]] MaybeError
447 verify(boost::json::value const& value, std::string_view key) const;
448};
449
456[[nodiscard]] bool
457checkIsU32Numeric(std::string_view sv);
458
459template <class HexType>
460 requires(std::is_same_v<HexType, ripple::uint160> || std::is_same_v<HexType, ripple::uint192> || std::is_same_v<HexType, ripple::uint256>)
462makeHexStringValidator(boost::json::value const& value, std::string_view key)
463{
464 if (!value.is_string())
465 return Error{Status{RippledError::rpcINVALID_PARAMS, std::string(key) + "NotString"}};
466
467 HexType parsedInt;
468 if (!parsedInt.parseHex(value.as_string().c_str()))
469 return Error{Status{RippledError::rpcINVALID_PARAMS, std::string(key) + "Malformed"}};
470
471 return MaybeError{};
472}
473
575
579struct Hex256ItemType final {
588 [[nodiscard]] static MaybeError
589 verify(boost::json::value const& value, std::string_view key)
590 {
591 if (not value.is_object() or not value.as_object().contains(key))
592 return {}; // ignore. If field is supposed to exist, let 'required' fail instead
593
594 auto const& res = value.as_object().at(key);
595
596 // loop through each item in the array and make sure it is uint256 hex string
597 for (auto const& elem : res.as_array()) {
598 ripple::uint256 num;
599 if (!elem.is_string() || !num.parseHex(elem.as_string())) {
600 return Error{Status{RippledError::rpcINVALID_PARAMS, "Item is not a valid uint256 type."}};
601 }
602 }
603 return {};
604 }
605};
606
607} // namespace rpc::validation
Validate that value is between specified min and max.
Definition Validators.hpp:170
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:193
Between(Type min, Type max)
Construct the validator storing min and max values.
Definition Validators.hpp:181
A meta-validator that allows to specify a custom validation function.
Definition Validators.hpp:423
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:77
CustomValidator(Fn &&fn)
Constructs a custom validator from any supported callable.
Definition Validators.hpp:435
Validates that the value is equal to the one passed in.
Definition Validators.hpp:324
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:345
EqualTo(Type original)
Construct the validator with stored original value.
Definition Validators.hpp:333
Validate that value is not greater than max.
Definition Validators.hpp:256
Max(Type max)
Construct the validator storing max value.
Definition Validators.hpp:265
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:277
Validate that value is equal or greater than the specified min.
Definition Validators.hpp:215
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:236
Min(Type min)
Construct the validator storing min value.
Definition Validators.hpp:224
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
Validates that the value is one of the values passed in.
Definition Validators.hpp:369
OneOf(std::initializer_list< Type > options)
Construct the validator with stored options of initializer list.
Definition Validators.hpp:378
OneOf(InputIt begin, InputIt end)
Construct the validator with stored options of other container.
Definition Validators.hpp:388
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:400
Validate that value can be converted to time according to the given format.
Definition Validators.hpp:296
MaybeError verify(boost::json::value const &value, std::string_view key) const
Verify that the JSON value is valid formatted time.
Definition Validators.cpp:59
TimeFormatValidator(std::string format)
Construct the validator storing format value.
Definition Validators.hpp:305
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:82
A group of custom validation functions.
Definition Validators.hpp:477
static CustomValidator uint160HexStringValidator
Provides a commonly used validator for uint160(AccountID) hex string.
Definition Validators.hpp:514
static CustomValidator credentialTypeValidator
Provides a validator for validating credential_type.
Definition Validators.hpp:573
static CustomValidator accountValidator
Provides a commonly used validator for accounts.
Definition Validators.hpp:491
static CustomValidator currencyValidator
Provides a commonly used validator for currency, including standard currency code and token code.
Definition Validators.hpp:535
static CustomValidator accountMarkerValidator
Provides a commonly used validator for markers.
Definition Validators.hpp:506
static CustomValidator issuerValidator
Provides a commonly used validator for issuer type.
Definition Validators.hpp:542
static CustomValidator ledgerIndexValidator
Provides a commonly used validator for ledger index.
Definition Validators.hpp:484
static CustomValidator currencyIssueValidator
Validates an asset (ripple::Issue).
Definition Validators.hpp:559
static CustomValidator subscribeAccountsValidator
Provides a validator for validating accounts used in subscribe/unsubscribe.
Definition Validators.hpp:552
static CustomValidator authorizeCredentialValidator
Provides a validator for validating authorized_credentials json array.
Definition Validators.hpp:566
static CustomValidator uint192HexStringValidator
Provides a commonly used validator for uint192 hex string.
Definition Validators.hpp:522
static CustomValidator uint256HexStringValidator
Provides a commonly used validator for uint256 hex string.
Definition Validators.hpp:530
static CustomValidator subscribeStreamValidator
Provides a validator for validating streams used in subscribe/unsubscribe.
Definition Validators.hpp:547
static CustomValidator accountBase58Validator
Provides a commonly used validator for accounts.
Definition Validators.hpp:498
Validates that the elements of the array is of type Hex256 uint.
Definition Validators.hpp:579
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:589
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:50
Validates that the type of the value is one of the given types.
Definition Validators.hpp:142
MaybeError verify(boost::json::value const &value, std::string_view key) const
Verify that the JSON value is (one) of specified type(s).
Definition Validators.hpp:151