blob: 431a2fe40b49e669b384b8e7762197a9a27ee12f [file] [log] [blame]
Ed Tanous7045c8d2017-04-03 10:04:37 -07001#pragma once
Ed Tanous1abe55e2018-09-05 08:30:59 -07002
Ed Tanouseb1c47d2022-02-09 11:47:27 -08003#include <bmcweb_config.h>
Ed Tanous51dae672018-09-05 16:07:32 -07004#include <openssl/crypto.h>
5
Ed Tanousc867a832022-03-10 14:17:00 -08006#include <boost/callable_traits.hpp>
Nan Zhou1d8782e2021-11-29 22:23:18 -08007#include <boost/date_time/posix_time/posix_time.hpp>
Ed Tanouseae855c2021-10-26 11:26:02 -07008#include <boost/url/url.hpp>
Ed Tanous71f2db72022-05-25 12:28:09 -07009#include <nlohmann/json.hpp>
Nan Zhou1d8782e2021-11-29 22:23:18 -080010
Ed Tanous9ea15c32022-01-04 14:18:22 -080011#include <array>
Ed Tanous74849be2021-02-05 09:47:47 -080012#include <chrono>
Ed Tanousc715ec22022-03-10 15:38:01 -080013#include <cstddef>
Ed Tanous7045c8d2017-04-03 10:04:37 -070014#include <cstdint>
Ed Tanous9ea15c32022-01-04 14:18:22 -080015#include <ctime>
Ed Tanous7045c8d2017-04-03 10:04:37 -070016#include <functional>
Ed Tanous9ea15c32022-01-04 14:18:22 -080017#include <limits>
Ed Tanous7045c8d2017-04-03 10:04:37 -070018#include <stdexcept>
19#include <string>
Ed Tanous9ea15c32022-01-04 14:18:22 -080020#include <string_view>
Ed Tanous7045c8d2017-04-03 10:04:37 -070021#include <tuple>
Ed Tanous9ea15c32022-01-04 14:18:22 -080022#include <type_traits>
23#include <utility>
Szymon Dompkeca1600c2022-03-03 14:42:52 +010024#include <variant>
Ed Tanous7045c8d2017-04-03 10:04:37 -070025
Ed Tanous1abe55e2018-09-05 08:30:59 -070026namespace crow
27{
28namespace black_magic
29{
Ed Tanous7045c8d2017-04-03 10:04:37 -070030
Ed Tanousc715ec22022-03-10 15:38:01 -080031enum class TypeCode : uint8_t
32{
33 Unspecified = 0,
34 Integer = 1,
35 UnsignedInteger = 2,
36 Float = 3,
37 String = 4,
38 Path = 5,
39 Max = 6,
40};
41
42// Remove when we have c++23
43template <typename E>
44constexpr typename std::underlying_type<E>::type toUnderlying(E e) noexcept
45{
46 return static_cast<typename std::underlying_type<E>::type>(e);
47}
48
Gunnar Mills1214b7e2020-06-04 10:11:30 -050049template <typename T>
Ed Tanousc715ec22022-03-10 15:38:01 -080050constexpr TypeCode getParameterTag()
Ed Tanous1abe55e2018-09-05 08:30:59 -070051{
Ed Tanous69509012019-10-24 16:53:05 -070052 if constexpr (std::is_same_v<int, T>)
53 {
Ed Tanousc715ec22022-03-10 15:38:01 -080054 return TypeCode::Integer;
Ed Tanous1abe55e2018-09-05 08:30:59 -070055 }
Ed Tanous69509012019-10-24 16:53:05 -070056 if constexpr (std::is_same_v<char, T>)
57 {
Ed Tanousc715ec22022-03-10 15:38:01 -080058 return TypeCode::Integer;
Ed Tanous69509012019-10-24 16:53:05 -070059 }
60 if constexpr (std::is_same_v<short, T>)
61 {
Ed Tanousc715ec22022-03-10 15:38:01 -080062 return TypeCode::Integer;
Ed Tanous69509012019-10-24 16:53:05 -070063 }
64 if constexpr (std::is_same_v<long, T>)
65 {
Ed Tanousc715ec22022-03-10 15:38:01 -080066 return TypeCode::Integer;
Ed Tanous69509012019-10-24 16:53:05 -070067 }
68 if constexpr (std::is_same_v<long long, T>)
69 {
Ed Tanousc715ec22022-03-10 15:38:01 -080070 return TypeCode::Integer;
Ed Tanous69509012019-10-24 16:53:05 -070071 }
72 if constexpr (std::is_same_v<unsigned int, T>)
73 {
Ed Tanousc715ec22022-03-10 15:38:01 -080074 return TypeCode::UnsignedInteger;
Ed Tanous69509012019-10-24 16:53:05 -070075 }
76 if constexpr (std::is_same_v<unsigned char, T>)
77 {
Ed Tanousc715ec22022-03-10 15:38:01 -080078 return TypeCode::UnsignedInteger;
Ed Tanous69509012019-10-24 16:53:05 -070079 }
80 if constexpr (std::is_same_v<unsigned short, T>)
81 {
Ed Tanousc715ec22022-03-10 15:38:01 -080082 return TypeCode::UnsignedInteger;
Ed Tanous69509012019-10-24 16:53:05 -070083 }
84 if constexpr (std::is_same_v<unsigned long, T>)
85 {
Ed Tanousc715ec22022-03-10 15:38:01 -080086 return TypeCode::UnsignedInteger;
Ed Tanous69509012019-10-24 16:53:05 -070087 }
88 if constexpr (std::is_same_v<unsigned long long, T>)
89 {
Ed Tanousc715ec22022-03-10 15:38:01 -080090 return TypeCode::UnsignedInteger;
Ed Tanous69509012019-10-24 16:53:05 -070091 }
92 if constexpr (std::is_same_v<double, T>)
93 {
Ed Tanousc715ec22022-03-10 15:38:01 -080094 return TypeCode::Float;
Ed Tanous69509012019-10-24 16:53:05 -070095 }
96 if constexpr (std::is_same_v<std::string, T>)
97 {
Ed Tanousc715ec22022-03-10 15:38:01 -080098 return TypeCode::String;
Ed Tanous69509012019-10-24 16:53:05 -070099 }
Ed Tanousc715ec22022-03-10 15:38:01 -0800100 return TypeCode::Unspecified;
Ed Tanous69509012019-10-24 16:53:05 -0700101}
102
Gunnar Mills1214b7e2020-06-04 10:11:30 -0500103template <typename... Args>
Ed Tanous988403c2020-08-24 11:29:49 -0700104struct computeParameterTagFromArgsList;
Ed Tanous7045c8d2017-04-03 10:04:37 -0700105
Gunnar Mills1214b7e2020-06-04 10:11:30 -0500106template <>
Ed Tanous988403c2020-08-24 11:29:49 -0700107struct computeParameterTagFromArgsList<>
Ed Tanous1abe55e2018-09-05 08:30:59 -0700108{
Ed Tanous69509012019-10-24 16:53:05 -0700109 static constexpr int value = 0;
Ed Tanous7045c8d2017-04-03 10:04:37 -0700110};
111
112template <typename Arg, typename... Args>
Ed Tanous988403c2020-08-24 11:29:49 -0700113struct computeParameterTagFromArgsList<Arg, Args...>
Ed Tanous1abe55e2018-09-05 08:30:59 -0700114{
Ed Tanous69509012019-10-24 16:53:05 -0700115 static constexpr int subValue =
Ed Tanous988403c2020-08-24 11:29:49 -0700116 computeParameterTagFromArgsList<Args...>::value;
Ed Tanous69509012019-10-24 16:53:05 -0700117 static constexpr int value =
Ed Tanousc715ec22022-03-10 15:38:01 -0800118 getParameterTag<typename std::decay<Arg>::type>() !=
119 TypeCode::Unspecified
120 ? static_cast<unsigned long>(subValue *
121 toUnderlying(TypeCode::Max)) +
122 static_cast<uint64_t>(
123 getParameterTag<typename std::decay<Arg>::type>())
Ed Tanous1abe55e2018-09-05 08:30:59 -0700124 : subValue;
Ed Tanous7045c8d2017-04-03 10:04:37 -0700125};
126
Ed Tanous988403c2020-08-24 11:29:49 -0700127inline bool isParameterTagCompatible(uint64_t a, uint64_t b)
Ed Tanous1abe55e2018-09-05 08:30:59 -0700128{
Ed Tanous1c30e502022-03-08 18:02:24 -0800129 while (true)
Ed Tanous1abe55e2018-09-05 08:30:59 -0700130 {
Ed Tanous1c30e502022-03-08 18:02:24 -0800131 if (a == 0)
132 {
133 return b == 0;
134 }
135 if (b == 0)
136 {
137 return a == 0;
138 }
Ed Tanousc715ec22022-03-10 15:38:01 -0800139 TypeCode sa = static_cast<TypeCode>(a % toUnderlying(TypeCode::Max));
140 TypeCode sb = static_cast<TypeCode>(b % toUnderlying(TypeCode::Max));
141
142 if (sa == TypeCode::Path)
Ed Tanous1c30e502022-03-08 18:02:24 -0800143 {
Ed Tanousc715ec22022-03-10 15:38:01 -0800144 sa = TypeCode::String;
Ed Tanous1c30e502022-03-08 18:02:24 -0800145 }
Ed Tanousc715ec22022-03-10 15:38:01 -0800146 if (sb == TypeCode::Path)
Ed Tanous1c30e502022-03-08 18:02:24 -0800147 {
Ed Tanousc715ec22022-03-10 15:38:01 -0800148 sb = TypeCode::String;
Ed Tanous1c30e502022-03-08 18:02:24 -0800149 }
150 if (sa != sb)
151 {
152 return false;
153 }
Ed Tanousc715ec22022-03-10 15:38:01 -0800154 a /= toUnderlying(TypeCode::Max);
155 b /= toUnderlying(TypeCode::Max);
Ed Tanous1abe55e2018-09-05 08:30:59 -0700156 }
Ed Tanous1c30e502022-03-08 18:02:24 -0800157 return false;
Ed Tanous7045c8d2017-04-03 10:04:37 -0700158}
159
Ed Tanous1c30e502022-03-08 18:02:24 -0800160constexpr inline uint64_t getParameterTag(std::string_view url)
Ed Tanous1abe55e2018-09-05 08:30:59 -0700161{
Ed Tanous1c30e502022-03-08 18:02:24 -0800162 uint64_t tagValue = 0;
163 size_t urlSegmentIndex = std::string_view::npos;
Ed Tanousb00dcc22021-02-23 12:52:50 -0800164
Ed Tanous1c30e502022-03-08 18:02:24 -0800165 size_t paramIndex = 0;
166
167 for (size_t urlIndex = 0; urlIndex < url.size(); urlIndex++)
168 {
169 char character = url[urlIndex];
170 if (character == '<')
171 {
172 if (urlSegmentIndex != std::string_view::npos)
173 {
174 return 0;
175 }
176 urlSegmentIndex = urlIndex;
177 }
178 if (character == '>')
179 {
180 if (urlSegmentIndex == std::string_view::npos)
181 {
182 return 0;
183 }
184 std::string_view tag =
185 url.substr(urlSegmentIndex, urlIndex + 1 - urlSegmentIndex);
186
187 // Note, this is a really lame way to do std::pow(6, paramIndex)
188 // std::pow doesn't work in constexpr in clang.
189 // Ideally in the future we'd move this to use a power of 2 packing
190 // (probably 8 instead of 6) so that these just become bit shifts
191 uint64_t insertIndex = 1;
192 for (size_t unused = 0; unused < paramIndex; unused++)
193 {
194 insertIndex *= 6;
195 }
196
197 if (tag == "<int>")
198 {
Ed Tanousc715ec22022-03-10 15:38:01 -0800199 tagValue += insertIndex * toUnderlying(TypeCode::Integer);
Ed Tanous1c30e502022-03-08 18:02:24 -0800200 }
201 if (tag == "<uint>")
202 {
Ed Tanousc715ec22022-03-10 15:38:01 -0800203 tagValue +=
204 insertIndex * toUnderlying(TypeCode::UnsignedInteger);
Ed Tanous1c30e502022-03-08 18:02:24 -0800205 }
206 if (tag == "<float>" || tag == "<double>")
207 {
Ed Tanousc715ec22022-03-10 15:38:01 -0800208 tagValue += insertIndex * toUnderlying(TypeCode::Float);
Ed Tanous1c30e502022-03-08 18:02:24 -0800209 }
210 if (tag == "<str>" || tag == "<string>")
211 {
Ed Tanousc715ec22022-03-10 15:38:01 -0800212 tagValue += insertIndex * toUnderlying(TypeCode::String);
Ed Tanous1c30e502022-03-08 18:02:24 -0800213 }
214 if (tag == "<path>")
215 {
Ed Tanousc715ec22022-03-10 15:38:01 -0800216 tagValue += insertIndex * toUnderlying(TypeCode::Path);
Ed Tanous1c30e502022-03-08 18:02:24 -0800217 }
218 paramIndex++;
219 urlSegmentIndex = std::string_view::npos;
220 }
221 }
222 if (urlSegmentIndex != std::string_view::npos)
Ed Tanous988403c2020-08-24 11:29:49 -0700223 {
224 return 0;
225 }
Ed Tanous1c30e502022-03-08 18:02:24 -0800226 return tagValue;
Ed Tanous7045c8d2017-04-03 10:04:37 -0700227}
Ed Tanous7045c8d2017-04-03 10:04:37 -0700228
Gunnar Mills1214b7e2020-06-04 10:11:30 -0500229template <typename... T>
230struct S
Ed Tanous1abe55e2018-09-05 08:30:59 -0700231{
Gunnar Mills1214b7e2020-06-04 10:11:30 -0500232 template <typename U>
233 using push = S<U, T...>;
234 template <typename U>
235 using push_back = S<T..., U>;
236 template <template <typename... Args> class U>
237 using rebind = U<T...>;
Ed Tanous7045c8d2017-04-03 10:04:37 -0700238};
Ed Tanous988403c2020-08-24 11:29:49 -0700239
Gunnar Mills1214b7e2020-06-04 10:11:30 -0500240template <typename F, typename Set>
241struct CallHelper;
Ed Tanous988403c2020-08-24 11:29:49 -0700242
Gunnar Mills1214b7e2020-06-04 10:11:30 -0500243template <typename F, typename... Args>
244struct CallHelper<F, S<Args...>>
Ed Tanous1abe55e2018-09-05 08:30:59 -0700245{
246 template <typename F1, typename... Args1,
247 typename = decltype(std::declval<F1>()(std::declval<Args1>()...))>
Ed Tanous2c70f802020-09-28 14:29:23 -0700248 static char test(int);
Ed Tanous7045c8d2017-04-03 10:04:37 -0700249
Gunnar Mills1214b7e2020-06-04 10:11:30 -0500250 template <typename...>
Ed Tanous2c70f802020-09-28 14:29:23 -0700251 static int test(...);
Ed Tanous7045c8d2017-04-03 10:04:37 -0700252
Ed Tanous2c70f802020-09-28 14:29:23 -0700253 static constexpr bool value = sizeof(test<F, Args...>(0)) == sizeof(char);
Ed Tanous7045c8d2017-04-03 10:04:37 -0700254};
255
Gunnar Mills1214b7e2020-06-04 10:11:30 -0500256template <uint64_t N>
257struct SingleTagToType
258{};
Ed Tanous7045c8d2017-04-03 10:04:37 -0700259
Gunnar Mills1214b7e2020-06-04 10:11:30 -0500260template <>
261struct SingleTagToType<1>
Ed Tanous1abe55e2018-09-05 08:30:59 -0700262{
263 using type = int64_t;
Ed Tanous7045c8d2017-04-03 10:04:37 -0700264};
265
Gunnar Mills1214b7e2020-06-04 10:11:30 -0500266template <>
267struct SingleTagToType<2>
Ed Tanous1abe55e2018-09-05 08:30:59 -0700268{
269 using type = uint64_t;
Ed Tanous7045c8d2017-04-03 10:04:37 -0700270};
271
Gunnar Mills1214b7e2020-06-04 10:11:30 -0500272template <>
273struct SingleTagToType<3>
Ed Tanous1abe55e2018-09-05 08:30:59 -0700274{
275 using type = double;
Ed Tanous7045c8d2017-04-03 10:04:37 -0700276};
277
Gunnar Mills1214b7e2020-06-04 10:11:30 -0500278template <>
279struct SingleTagToType<4>
Ed Tanous1abe55e2018-09-05 08:30:59 -0700280{
281 using type = std::string;
Ed Tanous7045c8d2017-04-03 10:04:37 -0700282};
283
Gunnar Mills1214b7e2020-06-04 10:11:30 -0500284template <>
285struct SingleTagToType<5>
Ed Tanous1abe55e2018-09-05 08:30:59 -0700286{
287 using type = std::string;
Ed Tanous7045c8d2017-04-03 10:04:37 -0700288};
289
Gunnar Mills1214b7e2020-06-04 10:11:30 -0500290template <uint64_t Tag>
291struct Arguments
Ed Tanous1abe55e2018-09-05 08:30:59 -0700292{
293 using subarguments = typename Arguments<Tag / 6>::type;
294 using type = typename subarguments::template push<
295 typename SingleTagToType<Tag % 6>::type>;
Ed Tanous7045c8d2017-04-03 10:04:37 -0700296};
297
Gunnar Mills1214b7e2020-06-04 10:11:30 -0500298template <>
299struct Arguments<0>
Ed Tanous1abe55e2018-09-05 08:30:59 -0700300{
301 using type = S<>;
Ed Tanous7045c8d2017-04-03 10:04:37 -0700302};
303
Gunnar Mills1214b7e2020-06-04 10:11:30 -0500304template <typename T>
Ed Tanous988403c2020-08-24 11:29:49 -0700305struct Promote
Ed Tanous1abe55e2018-09-05 08:30:59 -0700306{
307 using type = T;
308};
309
Gunnar Mills1214b7e2020-06-04 10:11:30 -0500310template <typename T>
Ed Tanous988403c2020-08-24 11:29:49 -0700311using PromoteT = typename Promote<T>::type;
312
313template <>
314struct Promote<char>
315{
316 using type = int64_t;
317};
318template <>
319struct Promote<short>
320{
321 using type = int64_t;
322};
323template <>
324struct Promote<int>
325{
326 using type = int64_t;
327};
328template <>
329struct Promote<long>
330{
331 using type = int64_t;
332};
333template <>
334struct Promote<long long>
335{
336 using type = int64_t;
337};
338template <>
339struct Promote<unsigned char>
340{
341 using type = uint64_t;
342};
343template <>
344struct Promote<unsigned short>
345{
346 using type = uint64_t;
347};
348template <>
349struct Promote<unsigned int>
350{
351 using type = uint64_t;
352};
353template <>
354struct Promote<unsigned long>
355{
356 using type = uint64_t;
357};
358template <>
359struct Promote<unsigned long long>
360{
361 using type = uint64_t;
362};
Ed Tanous7045c8d2017-04-03 10:04:37 -0700363
Ed Tanous1abe55e2018-09-05 08:30:59 -0700364} // namespace black_magic
Ed Tanous7045c8d2017-04-03 10:04:37 -0700365
Ed Tanous1abe55e2018-09-05 08:30:59 -0700366namespace utility
367{
Ed Tanous7045c8d2017-04-03 10:04:37 -0700368
Gunnar Mills1214b7e2020-06-04 10:11:30 -0500369template <typename T>
Ed Tanousc867a832022-03-10 14:17:00 -0800370struct FunctionTraits
Ed Tanous1abe55e2018-09-05 08:30:59 -0700371{
Gunnar Mills1214b7e2020-06-04 10:11:30 -0500372 template <size_t i>
Ed Tanousc867a832022-03-10 14:17:00 -0800373 using arg = std::tuple_element_t<i, boost::callable_traits::args_t<T>>;
Ed Tanous7045c8d2017-04-03 10:04:37 -0700374};
375
Adriana Kobylakd830ff52021-01-27 14:15:27 -0600376inline std::string base64encode(const std::string_view data)
377{
378 const std::array<char, 64> key = {
379 'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K', 'L', 'M',
380 'N', 'O', 'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X', 'Y', 'Z',
381 'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j', 'k', 'l', 'm',
382 'n', 'o', 'p', 'q', 'r', 's', 't', 'u', 'v', 'w', 'x', 'y', 'z',
383 '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', '+', '/'};
384
385 size_t size = data.size();
386 std::string ret;
387 ret.resize((size + 2) / 3 * 4);
388 auto it = ret.begin();
389
390 size_t i = 0;
391 while (i < size)
392 {
Ed Tanous543f4402022-01-06 13:12:53 -0800393 size_t keyIndex = 0;
Adriana Kobylakd830ff52021-01-27 14:15:27 -0600394
395 keyIndex = static_cast<size_t>(data[i] & 0xFC) >> 2;
396 *it++ = key[keyIndex];
397
398 if (i + 1 < size)
399 {
400 keyIndex = static_cast<size_t>(data[i] & 0x03) << 4;
401 keyIndex += static_cast<size_t>(data[i + 1] & 0xF0) >> 4;
402 *it++ = key[keyIndex];
403
404 if (i + 2 < size)
405 {
406 keyIndex = static_cast<size_t>(data[i + 1] & 0x0F) << 2;
407 keyIndex += static_cast<size_t>(data[i + 2] & 0xC0) >> 6;
408 *it++ = key[keyIndex];
409
410 keyIndex = static_cast<size_t>(data[i + 2] & 0x3F);
411 *it++ = key[keyIndex];
412 }
413 else
414 {
415 keyIndex = static_cast<size_t>(data[i + 1] & 0x0F) << 2;
416 *it++ = key[keyIndex];
417 *it++ = '=';
418 }
419 }
420 else
421 {
422 keyIndex = static_cast<size_t>(data[i] & 0x03) << 4;
423 *it++ = key[keyIndex];
424 *it++ = '=';
425 *it++ = '=';
426 }
427
428 i += 3;
429 }
430
431 return ret;
432}
433
Borawski.Lukasz9d8fd302018-01-05 14:56:09 +0100434// TODO this is temporary and should be deleted once base64 is refactored out of
435// crow
Ed Tanous39e77502019-03-04 17:35:53 -0800436inline bool base64Decode(const std::string_view input, std::string& output)
Ed Tanous1abe55e2018-09-05 08:30:59 -0700437{
Ed Tanous271584a2019-07-09 16:24:22 -0700438 static const char nop = static_cast<char>(-1);
Ed Tanous1abe55e2018-09-05 08:30:59 -0700439 // See note on encoding_data[] in above function
Jonathan Doman5beaf842020-08-14 11:23:33 -0700440 static const std::array<char, 256> decodingData = {
Ed Tanous1abe55e2018-09-05 08:30:59 -0700441 nop, nop, nop, nop, nop, nop, nop, nop, nop, nop, nop, nop, nop, nop,
442 nop, nop, nop, nop, nop, nop, nop, nop, nop, nop, nop, nop, nop, nop,
443 nop, nop, nop, nop, nop, nop, nop, nop, nop, nop, nop, nop, nop, nop,
444 nop, 62, nop, nop, nop, 63, 52, 53, 54, 55, 56, 57, 58, 59,
445 60, 61, nop, nop, nop, nop, nop, nop, nop, 0, 1, 2, 3, 4,
446 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18,
447 19, 20, 21, 22, 23, 24, 25, nop, nop, nop, nop, nop, nop, 26,
448 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40,
449 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, nop, nop, nop,
450 nop, nop, nop, nop, nop, nop, nop, nop, nop, nop, nop, nop, nop, nop,
451 nop, nop, nop, nop, nop, nop, nop, nop, nop, nop, nop, nop, nop, nop,
452 nop, nop, nop, nop, nop, nop, nop, nop, nop, nop, nop, nop, nop, nop,
453 nop, nop, nop, nop, nop, nop, nop, nop, nop, nop, nop, nop, nop, nop,
454 nop, nop, nop, nop, nop, nop, nop, nop, nop, nop, nop, nop, nop, nop,
455 nop, nop, nop, nop, nop, nop, nop, nop, nop, nop, nop, nop, nop, nop,
456 nop, nop, nop, nop, nop, nop, nop, nop, nop, nop, nop, nop, nop, nop,
457 nop, nop, nop, nop, nop, nop, nop, nop, nop, nop, nop, nop, nop, nop,
458 nop, nop, nop, nop, nop, nop, nop, nop, nop, nop, nop, nop, nop, nop,
459 nop, nop, nop, nop};
Borawski.Lukasz9d8fd302018-01-05 14:56:09 +0100460
Ed Tanous1abe55e2018-09-05 08:30:59 -0700461 size_t inputLength = input.size();
Borawski.Lukasz9d8fd302018-01-05 14:56:09 +0100462
Ed Tanous1abe55e2018-09-05 08:30:59 -0700463 // allocate space for output string
464 output.clear();
465 output.reserve(((inputLength + 2) / 3) * 4);
Borawski.Lukasz9d8fd302018-01-05 14:56:09 +0100466
Jonathan Doman5beaf842020-08-14 11:23:33 -0700467 auto getCodeValue = [](char c) {
468 auto code = static_cast<unsigned char>(c);
469 // Ensure we cannot index outside the bounds of the decoding array
470 static_assert(std::numeric_limits<decltype(code)>::max() <
471 decodingData.size());
472 return decodingData[code];
473 };
474
Ed Tanous1abe55e2018-09-05 08:30:59 -0700475 // for each 4-bytes sequence from the input, extract 4 6-bits sequences by
Gunnar Millscaa3ce32020-07-08 14:46:53 -0500476 // dropping first two bits
Ed Tanous1abe55e2018-09-05 08:30:59 -0700477 // and regenerate into 3 8-bits sequences
James Feist5a806642020-07-31 16:40:33 +0000478
Ed Tanous1abe55e2018-09-05 08:30:59 -0700479 for (size_t i = 0; i < inputLength; i++)
480 {
Ed Tanous543f4402022-01-06 13:12:53 -0800481 char base64code0 = 0;
482 char base64code1 = 0;
Ed Tanous1abe55e2018-09-05 08:30:59 -0700483 char base64code2 = 0; // initialized to 0 to suppress warnings
Ed Tanous543f4402022-01-06 13:12:53 -0800484 char base64code3 = 0;
Borawski.Lukasz9d8fd302018-01-05 14:56:09 +0100485
Jonathan Doman5beaf842020-08-14 11:23:33 -0700486 base64code0 = getCodeValue(input[i]);
Ed Tanous1abe55e2018-09-05 08:30:59 -0700487 if (base64code0 == nop)
488 { // non base64 character
489 return false;
490 }
491 if (!(++i < inputLength))
492 { // we need at least two input bytes for first
493 // byte output
494 return false;
495 }
Jonathan Doman5beaf842020-08-14 11:23:33 -0700496 base64code1 = getCodeValue(input[i]);
Ed Tanous1abe55e2018-09-05 08:30:59 -0700497 if (base64code1 == nop)
498 { // non base64 character
499 return false;
500 }
501 output +=
502 static_cast<char>((base64code0 << 2) | ((base64code1 >> 4) & 0x3));
Borawski.Lukasz9d8fd302018-01-05 14:56:09 +0100503
Ed Tanous1abe55e2018-09-05 08:30:59 -0700504 if (++i < inputLength)
505 {
506 char c = input[i];
507 if (c == '=')
508 { // padding , end of input
509 return (base64code1 & 0x0f) == 0;
510 }
Jonathan Doman5beaf842020-08-14 11:23:33 -0700511 base64code2 = getCodeValue(input[i]);
Ed Tanous1abe55e2018-09-05 08:30:59 -0700512 if (base64code2 == nop)
513 { // non base64 character
514 return false;
515 }
516 output += static_cast<char>(((base64code1 << 4) & 0xf0) |
517 ((base64code2 >> 2) & 0x0f));
518 }
519
520 if (++i < inputLength)
521 {
522 char c = input[i];
523 if (c == '=')
524 { // padding , end of input
525 return (base64code2 & 0x03) == 0;
526 }
Jonathan Doman5beaf842020-08-14 11:23:33 -0700527 base64code3 = getCodeValue(input[i]);
Ed Tanous1abe55e2018-09-05 08:30:59 -0700528 if (base64code3 == nop)
529 { // non base64 character
530 return false;
531 }
532 output +=
533 static_cast<char>((((base64code2 << 6) & 0xc0) | base64code3));
534 }
Borawski.Lukasz9d8fd302018-01-05 14:56:09 +0100535 }
536
Ed Tanous1abe55e2018-09-05 08:30:59 -0700537 return true;
Borawski.Lukasz9d8fd302018-01-05 14:56:09 +0100538}
539
Krzysztof Grobelny45c367e2021-12-29 10:28:53 +0100540namespace details
541{
Ed Tanous22ce5452022-01-11 10:50:23 -0800542constexpr uint64_t maxMilliSeconds = 253402300799999;
543constexpr uint64_t maxSeconds = 253402300799;
Krzysztof Grobelny45c367e2021-12-29 10:28:53 +0100544inline std::string getDateTime(boost::posix_time::milliseconds timeSinceEpoch)
Andrew Geisslercb92c032018-08-17 07:56:14 -0700545{
Nan Zhou1d8782e2021-11-29 22:23:18 -0800546 boost::posix_time::ptime epoch(boost::gregorian::date(1970, 1, 1));
Krzysztof Grobelny45c367e2021-12-29 10:28:53 +0100547 boost::posix_time::ptime time = epoch + timeSinceEpoch;
Nan Zhou1d8782e2021-11-29 22:23:18 -0800548 // append zero offset to the end according to the Redfish spec for Date-Time
Nan Zhou5ae4b692021-12-14 13:30:37 -0800549 return boost::posix_time::to_iso_extended_string(time) + "+00:00";
Nan Zhou1d8782e2021-11-29 22:23:18 -0800550}
Krzysztof Grobelny45c367e2021-12-29 10:28:53 +0100551} // namespace details
Andrew Geisslercb92c032018-08-17 07:56:14 -0700552
Ed Tanous22ce5452022-01-11 10:50:23 -0800553// Returns the formatted date time string.
554// Note that the maximum supported date is 9999-12-31T23:59:59+00:00, if
555// the given |secondsSinceEpoch| is too large, we return the maximum supported
556// date. This behavior is to avoid exceptions throwed by Boost.
Nan Zhou1d8782e2021-11-29 22:23:18 -0800557inline std::string getDateTimeUint(uint64_t secondsSinceEpoch)
558{
Nan Zhou665479d2022-01-26 12:12:59 -0800559 secondsSinceEpoch = std::min(secondsSinceEpoch, details::maxSeconds);
560 boost::posix_time::seconds boostSeconds(secondsSinceEpoch);
Krzysztof Grobelny45c367e2021-12-29 10:28:53 +0100561 return details::getDateTime(
562 boost::posix_time::milliseconds(boostSeconds.total_milliseconds()));
563}
564
Ed Tanous22ce5452022-01-11 10:50:23 -0800565// Returns the formatted date time string.
566// Note that the maximum supported date is 9999-12-31T23:59:59.999+00:00, if
567// the given |millisSecondsSinceEpoch| is too large, we return the maximum
568// supported date.
569inline std::string getDateTimeUintMs(uint64_t milliSecondsSinceEpoch)
Krzysztof Grobelny45c367e2021-12-29 10:28:53 +0100570{
Nan Zhou665479d2022-01-26 12:12:59 -0800571 milliSecondsSinceEpoch =
572 std::min(details::maxMilliSeconds, milliSecondsSinceEpoch);
573 return details::getDateTime(
574 boost::posix_time::milliseconds(milliSecondsSinceEpoch));
Nan Zhou1d8782e2021-11-29 22:23:18 -0800575}
Andrew Geisslercb92c032018-08-17 07:56:14 -0700576
Nan Zhou1d8782e2021-11-29 22:23:18 -0800577inline std::string getDateTimeStdtime(std::time_t secondsSinceEpoch)
578{
Ed Tanous46666f32022-03-03 14:55:16 -0800579 // secondsSinceEpoch >= maxSeconds
580 if constexpr (std::cmp_less_equal(details::maxSeconds,
581 std::numeric_limits<std::time_t>::max()))
Nan Zhou665479d2022-01-26 12:12:59 -0800582 {
Ed Tanous46666f32022-03-03 14:55:16 -0800583 if (std::cmp_greater_equal(secondsSinceEpoch, details::maxSeconds))
584 {
585 secondsSinceEpoch = details::maxSeconds;
586 }
Nan Zhou665479d2022-01-26 12:12:59 -0800587 }
588 boost::posix_time::ptime time =
589 boost::posix_time::from_time_t(secondsSinceEpoch);
Krzysztof Grobelny45c367e2021-12-29 10:28:53 +0100590 return boost::posix_time::to_iso_extended_string(time) + "+00:00";
Andrew Geisslercb92c032018-08-17 07:56:14 -0700591}
592
Tejas Patil7c8c4052021-06-04 17:43:14 +0530593/**
594 * Returns the current Date, Time & the local Time Offset
595 * infromation in a pair
596 *
597 * @param[in] None
598 *
599 * @return std::pair<std::string, std::string>, which consist
600 * of current DateTime & the TimeOffset strings respectively.
601 */
602inline std::pair<std::string, std::string> getDateTimeOffsetNow()
Andrew Geisslercb92c032018-08-17 07:56:14 -0700603{
604 std::time_t time = std::time(nullptr);
Nan Zhou1d8782e2021-11-29 22:23:18 -0800605 std::string dateTime = getDateTimeStdtime(time);
Tejas Patil7c8c4052021-06-04 17:43:14 +0530606
607 /* extract the local Time Offset value from the
608 * recevied dateTime string.
609 */
610 std::string timeOffset("Z00:00");
611 std::size_t lastPos = dateTime.size();
612 std::size_t len = timeOffset.size();
613 if (lastPos > len)
614 {
615 timeOffset = dateTime.substr(lastPos - len);
616 }
617
618 return std::make_pair(dateTime, timeOffset);
Andrew Geisslercb92c032018-08-17 07:56:14 -0700619}
620
Ed Tanous51dae672018-09-05 16:07:32 -0700621inline bool constantTimeStringCompare(const std::string_view a,
622 const std::string_view b)
623{
624 // Important note, this function is ONLY constant time if the two input
625 // sizes are the same
626 if (a.size() != b.size())
627 {
628 return false;
629 }
630 return CRYPTO_memcmp(a.data(), b.data(), a.size()) == 0;
631}
632
633struct ConstantTimeCompare
634{
635 bool operator()(const std::string_view a, const std::string_view b) const
636 {
637 return constantTimeStringCompare(a, b);
638 }
639};
640
Ed Tanouseae855c2021-10-26 11:26:02 -0700641namespace details
642{
643inline boost::urls::url
644 urlFromPiecesDetail(const std::initializer_list<std::string_view> args)
645{
646 boost::urls::url url("/");
647 for (const std::string_view& arg : args)
648 {
649 url.segments().push_back(arg);
650 }
651 return url;
652}
653} // namespace details
654
655template <typename... AV>
656inline boost::urls::url urlFromPieces(const AV... args)
657{
658 return details::urlFromPiecesDetail({args...});
659}
660
Szymon Dompkeca1600c2022-03-03 14:42:52 +0100661namespace details
662{
663
664// std::reference_wrapper<std::string> - extracts segment to variable
665// std::string_view - checks if segment is equal to variable
666using UrlSegment =
667 std::variant<std::reference_wrapper<std::string>, std::string_view>;
668
669class UrlSegmentMatcherVisitor
670{
671 public:
672 bool operator()(std::string& output)
673 {
674 output = std::string_view(segment.data(), segment.size());
675 return true;
676 }
677
678 bool operator()(std::string_view expected)
679 {
680 return std::string_view(segment.data(), segment.size()) == expected;
681 }
682
Ed Tanous4e23a442022-06-06 09:57:26 -0700683 explicit UrlSegmentMatcherVisitor(
684 const boost::urls::string_value& segmentIn) :
Szymon Dompkeca1600c2022-03-03 14:42:52 +0100685 segment(segmentIn)
686 {}
687
688 private:
689 const boost::urls::string_value& segment;
690};
691
692inline bool readUrlSegments(const boost::urls::url_view& urlView,
693 std::initializer_list<UrlSegment>&& segments)
694{
695 const boost::urls::segments_view& urlSegments = urlView.segments();
696
697 if (!urlSegments.is_absolute() || segments.size() != urlSegments.size())
698 {
699 return false;
700 }
701
702 boost::urls::segments_view::iterator it = urlSegments.begin();
703 boost::urls::segments_view::iterator end = urlSegments.end();
704
705 for (const auto& segment : segments)
706 {
707 if (!std::visit(UrlSegmentMatcherVisitor(*it), segment))
708 {
709 return false;
710 }
711 it++;
712 }
713 return true;
714}
715
716} // namespace details
717
718template <typename... Args>
719inline bool readUrlSegments(const boost::urls::url_view& urlView,
720 Args&&... args)
721{
722 return details::readUrlSegments(urlView, {std::forward<Args>(args)...});
723}
724
Ed Tanouseb1c47d2022-02-09 11:47:27 -0800725inline std::string setProtocolDefaults(const boost::urls::url_view& url)
726{
727 if (url.scheme() == "https")
728 {
729 return "https";
730 }
731 if (url.scheme() == "http")
732 {
733 if (bmcwebInsecureEnableHttpPushStyleEventing)
734 {
735 return "http";
736 }
737 return "";
738 }
739 return "";
740}
741
742inline uint16_t setPortDefaults(const boost::urls::url_view& url)
743{
744 uint16_t port = url.port_number();
745 if (port != 0)
746 {
747 // user picked a port already.
748 return port;
749 }
750
751 // If the user hasn't explicitly stated a port, pick one explicitly for them
752 // based on the protocol defaults
753 if (url.scheme() == "http")
754 {
755 return 80;
756 }
757 if (url.scheme() == "https")
758 {
759 return 443;
760 }
761 return 0;
762}
763
Ed Tanous11baefe2022-02-09 12:14:12 -0800764inline bool validateAndSplitUrl(std::string_view destUrl, std::string& urlProto,
Ed Tanouseb1c47d2022-02-09 11:47:27 -0800765 std::string& host, uint16_t& port,
Ed Tanous11baefe2022-02-09 12:14:12 -0800766 std::string& path)
767{
Ed Tanouseb1c47d2022-02-09 11:47:27 -0800768 boost::string_view urlBoost(destUrl.data(), destUrl.size());
769 boost::urls::result<boost::urls::url_view> url =
770 boost::urls::parse_uri(urlBoost);
771 if (!url)
772 {
773 return false;
774 }
775 urlProto = setProtocolDefaults(url.value());
776 if (urlProto.empty())
Ed Tanous11baefe2022-02-09 12:14:12 -0800777 {
778 return false;
779 }
780
Ed Tanouseb1c47d2022-02-09 11:47:27 -0800781 port = setPortDefaults(url.value());
Ed Tanous11baefe2022-02-09 12:14:12 -0800782
Ed Tanouseb1c47d2022-02-09 11:47:27 -0800783 host = std::string_view(url->encoded_host().data(),
784 url->encoded_host().size());
785
786 path = std::string_view(url->encoded_path().data(),
787 url->encoded_path().size());
Ed Tanous11baefe2022-02-09 12:14:12 -0800788 if (path.empty())
789 {
790 path = "/";
791 }
Ed Tanouseb1c47d2022-02-09 11:47:27 -0800792 if (url->has_fragment())
793 {
794 path += '#';
795 path += std::string_view(url->encoded_fragment().data(),
796 url->encoded_fragment().size());
797 }
798
799 if (url->has_query())
800 {
801 path += '?';
802 path += std::string_view(url->encoded_query().data(),
803 url->encoded_query().size());
804 }
805
Ed Tanous11baefe2022-02-09 12:14:12 -0800806 return true;
807}
808
Ed Tanous1abe55e2018-09-05 08:30:59 -0700809} // namespace utility
810} // namespace crow
Ed Tanous71f2db72022-05-25 12:28:09 -0700811
812namespace nlohmann
813{
814template <>
815struct adl_serializer<boost::urls::url>
816{
817 // nlohmann requires a specific casing to look these up in adl
818 // NOLINTNEXTLINE(readability-identifier-naming)
819 static void to_json(json& j, const boost::urls::url& url)
820 {
821 j = url.string();
822 }
823};
824
825template <>
826struct adl_serializer<boost::urls::url_view>
827{
828 // NOLINTNEXTLINE(readability-identifier-naming)
829 static void to_json(json& j, const boost::urls::url_view& url)
830 {
831 j = url.string();
832 }
833};
834} // namespace nlohmann