blob: 0b1743f228f385bc9921e393324db9be530466ed [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 Tanous7045c8d2017-04-03 10:04:37 -070013#include <cstdint>
Ed Tanous9ea15c32022-01-04 14:18:22 -080014#include <ctime>
Ed Tanous7045c8d2017-04-03 10:04:37 -070015#include <functional>
Ed Tanous9ea15c32022-01-04 14:18:22 -080016#include <limits>
Ed Tanous7045c8d2017-04-03 10:04:37 -070017#include <stdexcept>
18#include <string>
Ed Tanous9ea15c32022-01-04 14:18:22 -080019#include <string_view>
Ed Tanous7045c8d2017-04-03 10:04:37 -070020#include <tuple>
Ed Tanous9ea15c32022-01-04 14:18:22 -080021#include <type_traits>
22#include <utility>
Szymon Dompkeca1600c2022-03-03 14:42:52 +010023#include <variant>
Ed Tanous7045c8d2017-04-03 10:04:37 -070024
Ed Tanous1abe55e2018-09-05 08:30:59 -070025namespace crow
26{
27namespace black_magic
28{
Ed Tanous7045c8d2017-04-03 10:04:37 -070029
Gunnar Mills1214b7e2020-06-04 10:11:30 -050030template <typename T>
Ed Tanous1c30e502022-03-08 18:02:24 -080031constexpr uint64_t getParameterTag()
Ed Tanous1abe55e2018-09-05 08:30:59 -070032{
Ed Tanous69509012019-10-24 16:53:05 -070033 if constexpr (std::is_same_v<int, T>)
34 {
35 return 1;
Ed Tanous1abe55e2018-09-05 08:30:59 -070036 }
Ed Tanous69509012019-10-24 16:53:05 -070037 if constexpr (std::is_same_v<char, T>)
38 {
39 return 1;
40 }
41 if constexpr (std::is_same_v<short, T>)
42 {
43 return 1;
44 }
45 if constexpr (std::is_same_v<long, T>)
46 {
47 return 1;
48 }
49 if constexpr (std::is_same_v<long long, T>)
50 {
51 return 1;
52 }
53 if constexpr (std::is_same_v<unsigned int, T>)
54 {
55 return 2;
56 }
57 if constexpr (std::is_same_v<unsigned char, T>)
58 {
59 return 2;
60 }
61 if constexpr (std::is_same_v<unsigned short, T>)
62 {
63 return 2;
64 }
65 if constexpr (std::is_same_v<unsigned long, T>)
66 {
67 return 2;
68 }
69 if constexpr (std::is_same_v<unsigned long long, T>)
70 {
71 return 2;
72 }
73 if constexpr (std::is_same_v<double, T>)
74 {
75 return 3;
76 }
77 if constexpr (std::is_same_v<std::string, T>)
78 {
79 return 4;
80 }
81 return 0;
82}
83
Gunnar Mills1214b7e2020-06-04 10:11:30 -050084template <typename... Args>
Ed Tanous988403c2020-08-24 11:29:49 -070085struct computeParameterTagFromArgsList;
Ed Tanous7045c8d2017-04-03 10:04:37 -070086
Gunnar Mills1214b7e2020-06-04 10:11:30 -050087template <>
Ed Tanous988403c2020-08-24 11:29:49 -070088struct computeParameterTagFromArgsList<>
Ed Tanous1abe55e2018-09-05 08:30:59 -070089{
Ed Tanous69509012019-10-24 16:53:05 -070090 static constexpr int value = 0;
Ed Tanous7045c8d2017-04-03 10:04:37 -070091};
92
93template <typename Arg, typename... Args>
Ed Tanous988403c2020-08-24 11:29:49 -070094struct computeParameterTagFromArgsList<Arg, Args...>
Ed Tanous1abe55e2018-09-05 08:30:59 -070095{
Ed Tanous69509012019-10-24 16:53:05 -070096 static constexpr int subValue =
Ed Tanous988403c2020-08-24 11:29:49 -070097 computeParameterTagFromArgsList<Args...>::value;
Ed Tanous69509012019-10-24 16:53:05 -070098 static constexpr int value =
Ed Tanous1c30e502022-03-08 18:02:24 -080099 getParameterTag<typename std::decay<Arg>::type>() != 0
Ed Tanous69509012019-10-24 16:53:05 -0700100 ? subValue * 6 + getParameterTag<typename std::decay<Arg>::type>()
Ed Tanous1abe55e2018-09-05 08:30:59 -0700101 : subValue;
Ed Tanous7045c8d2017-04-03 10:04:37 -0700102};
103
Ed Tanous988403c2020-08-24 11:29:49 -0700104inline bool isParameterTagCompatible(uint64_t a, uint64_t b)
Ed Tanous1abe55e2018-09-05 08:30:59 -0700105{
Ed Tanous1c30e502022-03-08 18:02:24 -0800106 while (true)
Ed Tanous1abe55e2018-09-05 08:30:59 -0700107 {
Ed Tanous1c30e502022-03-08 18:02:24 -0800108 if (a == 0)
109 {
110 return b == 0;
111 }
112 if (b == 0)
113 {
114 return a == 0;
115 }
116 uint64_t sa = a % 6;
117 uint64_t sb = a % 6;
118 if (sa == 5)
119 {
120 sa = 4;
121 }
122 if (sb == 5)
123 {
124 sb = 4;
125 }
126 if (sa != sb)
127 {
128 return false;
129 }
130 a /= 6;
131 b /= 6;
Ed Tanous1abe55e2018-09-05 08:30:59 -0700132 }
Ed Tanous1c30e502022-03-08 18:02:24 -0800133 return false;
Ed Tanous7045c8d2017-04-03 10:04:37 -0700134}
135
Ed Tanous1c30e502022-03-08 18:02:24 -0800136constexpr inline uint64_t getParameterTag(std::string_view url)
Ed Tanous1abe55e2018-09-05 08:30:59 -0700137{
Ed Tanous1c30e502022-03-08 18:02:24 -0800138 uint64_t tagValue = 0;
139 size_t urlSegmentIndex = std::string_view::npos;
Ed Tanousb00dcc22021-02-23 12:52:50 -0800140
Ed Tanous1c30e502022-03-08 18:02:24 -0800141 size_t paramIndex = 0;
142
143 for (size_t urlIndex = 0; urlIndex < url.size(); urlIndex++)
144 {
145 char character = url[urlIndex];
146 if (character == '<')
147 {
148 if (urlSegmentIndex != std::string_view::npos)
149 {
150 return 0;
151 }
152 urlSegmentIndex = urlIndex;
153 }
154 if (character == '>')
155 {
156 if (urlSegmentIndex == std::string_view::npos)
157 {
158 return 0;
159 }
160 std::string_view tag =
161 url.substr(urlSegmentIndex, urlIndex + 1 - urlSegmentIndex);
162
163 // Note, this is a really lame way to do std::pow(6, paramIndex)
164 // std::pow doesn't work in constexpr in clang.
165 // Ideally in the future we'd move this to use a power of 2 packing
166 // (probably 8 instead of 6) so that these just become bit shifts
167 uint64_t insertIndex = 1;
168 for (size_t unused = 0; unused < paramIndex; unused++)
169 {
170 insertIndex *= 6;
171 }
172
173 if (tag == "<int>")
174 {
175 tagValue += insertIndex * 1;
176 }
177 if (tag == "<uint>")
178 {
179 tagValue += insertIndex * 2;
180 }
181 if (tag == "<float>" || tag == "<double>")
182 {
183 tagValue += insertIndex * 3;
184 }
185 if (tag == "<str>" || tag == "<string>")
186 {
187 tagValue += insertIndex * 4;
188 }
189 if (tag == "<path>")
190 {
191 tagValue += insertIndex * 5;
192 }
193 paramIndex++;
194 urlSegmentIndex = std::string_view::npos;
195 }
196 }
197 if (urlSegmentIndex != std::string_view::npos)
Ed Tanous988403c2020-08-24 11:29:49 -0700198 {
199 return 0;
200 }
Ed Tanous1c30e502022-03-08 18:02:24 -0800201 return tagValue;
Ed Tanous7045c8d2017-04-03 10:04:37 -0700202}
Ed Tanous7045c8d2017-04-03 10:04:37 -0700203
Gunnar Mills1214b7e2020-06-04 10:11:30 -0500204template <typename... T>
205struct S
Ed Tanous1abe55e2018-09-05 08:30:59 -0700206{
Gunnar Mills1214b7e2020-06-04 10:11:30 -0500207 template <typename U>
208 using push = S<U, T...>;
209 template <typename U>
210 using push_back = S<T..., U>;
211 template <template <typename... Args> class U>
212 using rebind = U<T...>;
Ed Tanous7045c8d2017-04-03 10:04:37 -0700213};
Ed Tanous988403c2020-08-24 11:29:49 -0700214
Gunnar Mills1214b7e2020-06-04 10:11:30 -0500215template <typename F, typename Set>
216struct CallHelper;
Ed Tanous988403c2020-08-24 11:29:49 -0700217
Gunnar Mills1214b7e2020-06-04 10:11:30 -0500218template <typename F, typename... Args>
219struct CallHelper<F, S<Args...>>
Ed Tanous1abe55e2018-09-05 08:30:59 -0700220{
221 template <typename F1, typename... Args1,
222 typename = decltype(std::declval<F1>()(std::declval<Args1>()...))>
Ed Tanous2c70f802020-09-28 14:29:23 -0700223 static char test(int);
Ed Tanous7045c8d2017-04-03 10:04:37 -0700224
Gunnar Mills1214b7e2020-06-04 10:11:30 -0500225 template <typename...>
Ed Tanous2c70f802020-09-28 14:29:23 -0700226 static int test(...);
Ed Tanous7045c8d2017-04-03 10:04:37 -0700227
Ed Tanous2c70f802020-09-28 14:29:23 -0700228 static constexpr bool value = sizeof(test<F, Args...>(0)) == sizeof(char);
Ed Tanous7045c8d2017-04-03 10:04:37 -0700229};
230
Gunnar Mills1214b7e2020-06-04 10:11:30 -0500231template <uint64_t N>
232struct SingleTagToType
233{};
Ed Tanous7045c8d2017-04-03 10:04:37 -0700234
Gunnar Mills1214b7e2020-06-04 10:11:30 -0500235template <>
236struct SingleTagToType<1>
Ed Tanous1abe55e2018-09-05 08:30:59 -0700237{
238 using type = int64_t;
Ed Tanous7045c8d2017-04-03 10:04:37 -0700239};
240
Gunnar Mills1214b7e2020-06-04 10:11:30 -0500241template <>
242struct SingleTagToType<2>
Ed Tanous1abe55e2018-09-05 08:30:59 -0700243{
244 using type = uint64_t;
Ed Tanous7045c8d2017-04-03 10:04:37 -0700245};
246
Gunnar Mills1214b7e2020-06-04 10:11:30 -0500247template <>
248struct SingleTagToType<3>
Ed Tanous1abe55e2018-09-05 08:30:59 -0700249{
250 using type = double;
Ed Tanous7045c8d2017-04-03 10:04:37 -0700251};
252
Gunnar Mills1214b7e2020-06-04 10:11:30 -0500253template <>
254struct SingleTagToType<4>
Ed Tanous1abe55e2018-09-05 08:30:59 -0700255{
256 using type = std::string;
Ed Tanous7045c8d2017-04-03 10:04:37 -0700257};
258
Gunnar Mills1214b7e2020-06-04 10:11:30 -0500259template <>
260struct SingleTagToType<5>
Ed Tanous1abe55e2018-09-05 08:30:59 -0700261{
262 using type = std::string;
Ed Tanous7045c8d2017-04-03 10:04:37 -0700263};
264
Gunnar Mills1214b7e2020-06-04 10:11:30 -0500265template <uint64_t Tag>
266struct Arguments
Ed Tanous1abe55e2018-09-05 08:30:59 -0700267{
268 using subarguments = typename Arguments<Tag / 6>::type;
269 using type = typename subarguments::template push<
270 typename SingleTagToType<Tag % 6>::type>;
Ed Tanous7045c8d2017-04-03 10:04:37 -0700271};
272
Gunnar Mills1214b7e2020-06-04 10:11:30 -0500273template <>
274struct Arguments<0>
Ed Tanous1abe55e2018-09-05 08:30:59 -0700275{
276 using type = S<>;
Ed Tanous7045c8d2017-04-03 10:04:37 -0700277};
278
Gunnar Mills1214b7e2020-06-04 10:11:30 -0500279template <typename T>
Ed Tanous988403c2020-08-24 11:29:49 -0700280struct Promote
Ed Tanous1abe55e2018-09-05 08:30:59 -0700281{
282 using type = T;
283};
284
Gunnar Mills1214b7e2020-06-04 10:11:30 -0500285template <typename T>
Ed Tanous988403c2020-08-24 11:29:49 -0700286using PromoteT = typename Promote<T>::type;
287
288template <>
289struct Promote<char>
290{
291 using type = int64_t;
292};
293template <>
294struct Promote<short>
295{
296 using type = int64_t;
297};
298template <>
299struct Promote<int>
300{
301 using type = int64_t;
302};
303template <>
304struct Promote<long>
305{
306 using type = int64_t;
307};
308template <>
309struct Promote<long long>
310{
311 using type = int64_t;
312};
313template <>
314struct Promote<unsigned char>
315{
316 using type = uint64_t;
317};
318template <>
319struct Promote<unsigned short>
320{
321 using type = uint64_t;
322};
323template <>
324struct Promote<unsigned int>
325{
326 using type = uint64_t;
327};
328template <>
329struct Promote<unsigned long>
330{
331 using type = uint64_t;
332};
333template <>
334struct Promote<unsigned long long>
335{
336 using type = uint64_t;
337};
Ed Tanous7045c8d2017-04-03 10:04:37 -0700338
Ed Tanous1abe55e2018-09-05 08:30:59 -0700339} // namespace black_magic
Ed Tanous7045c8d2017-04-03 10:04:37 -0700340
Ed Tanous1abe55e2018-09-05 08:30:59 -0700341namespace utility
342{
Ed Tanous7045c8d2017-04-03 10:04:37 -0700343
Gunnar Mills1214b7e2020-06-04 10:11:30 -0500344template <typename T>
Ed Tanousc867a832022-03-10 14:17:00 -0800345struct FunctionTraits
Ed Tanous1abe55e2018-09-05 08:30:59 -0700346{
Gunnar Mills1214b7e2020-06-04 10:11:30 -0500347 template <size_t i>
Ed Tanousc867a832022-03-10 14:17:00 -0800348 using arg = std::tuple_element_t<i, boost::callable_traits::args_t<T>>;
Ed Tanous7045c8d2017-04-03 10:04:37 -0700349};
350
Adriana Kobylakd830ff52021-01-27 14:15:27 -0600351inline std::string base64encode(const std::string_view data)
352{
353 const std::array<char, 64> key = {
354 'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K', 'L', 'M',
355 'N', 'O', 'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X', 'Y', 'Z',
356 'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j', 'k', 'l', 'm',
357 'n', 'o', 'p', 'q', 'r', 's', 't', 'u', 'v', 'w', 'x', 'y', 'z',
358 '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', '+', '/'};
359
360 size_t size = data.size();
361 std::string ret;
362 ret.resize((size + 2) / 3 * 4);
363 auto it = ret.begin();
364
365 size_t i = 0;
366 while (i < size)
367 {
Ed Tanous543f4402022-01-06 13:12:53 -0800368 size_t keyIndex = 0;
Adriana Kobylakd830ff52021-01-27 14:15:27 -0600369
370 keyIndex = static_cast<size_t>(data[i] & 0xFC) >> 2;
371 *it++ = key[keyIndex];
372
373 if (i + 1 < size)
374 {
375 keyIndex = static_cast<size_t>(data[i] & 0x03) << 4;
376 keyIndex += static_cast<size_t>(data[i + 1] & 0xF0) >> 4;
377 *it++ = key[keyIndex];
378
379 if (i + 2 < size)
380 {
381 keyIndex = static_cast<size_t>(data[i + 1] & 0x0F) << 2;
382 keyIndex += static_cast<size_t>(data[i + 2] & 0xC0) >> 6;
383 *it++ = key[keyIndex];
384
385 keyIndex = static_cast<size_t>(data[i + 2] & 0x3F);
386 *it++ = key[keyIndex];
387 }
388 else
389 {
390 keyIndex = static_cast<size_t>(data[i + 1] & 0x0F) << 2;
391 *it++ = key[keyIndex];
392 *it++ = '=';
393 }
394 }
395 else
396 {
397 keyIndex = static_cast<size_t>(data[i] & 0x03) << 4;
398 *it++ = key[keyIndex];
399 *it++ = '=';
400 *it++ = '=';
401 }
402
403 i += 3;
404 }
405
406 return ret;
407}
408
Borawski.Lukasz9d8fd302018-01-05 14:56:09 +0100409// TODO this is temporary and should be deleted once base64 is refactored out of
410// crow
Ed Tanous39e77502019-03-04 17:35:53 -0800411inline bool base64Decode(const std::string_view input, std::string& output)
Ed Tanous1abe55e2018-09-05 08:30:59 -0700412{
Ed Tanous271584a2019-07-09 16:24:22 -0700413 static const char nop = static_cast<char>(-1);
Ed Tanous1abe55e2018-09-05 08:30:59 -0700414 // See note on encoding_data[] in above function
Jonathan Doman5beaf842020-08-14 11:23:33 -0700415 static const std::array<char, 256> decodingData = {
Ed Tanous1abe55e2018-09-05 08:30:59 -0700416 nop, nop, nop, nop, nop, nop, nop, nop, nop, nop, nop, nop, nop, nop,
417 nop, nop, nop, nop, nop, nop, nop, nop, nop, nop, nop, nop, nop, nop,
418 nop, nop, nop, nop, nop, nop, nop, nop, nop, nop, nop, nop, nop, nop,
419 nop, 62, nop, nop, nop, 63, 52, 53, 54, 55, 56, 57, 58, 59,
420 60, 61, nop, nop, nop, nop, nop, nop, nop, 0, 1, 2, 3, 4,
421 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18,
422 19, 20, 21, 22, 23, 24, 25, nop, nop, nop, nop, nop, nop, 26,
423 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40,
424 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, nop, nop, nop,
425 nop, nop, nop, nop, nop, nop, nop, nop, nop, nop, nop, nop, nop, nop,
426 nop, nop, nop, nop, nop, nop, nop, nop, nop, nop, nop, nop, nop, nop,
427 nop, nop, nop, nop, nop, nop, nop, nop, nop, nop, nop, nop, nop, nop,
428 nop, nop, nop, nop, nop, nop, nop, nop, nop, nop, nop, nop, nop, nop,
429 nop, nop, nop, nop, nop, nop, nop, nop, nop, nop, nop, nop, nop, nop,
430 nop, nop, nop, nop, nop, nop, nop, nop, nop, nop, nop, nop, nop, nop,
431 nop, nop, nop, nop, nop, nop, nop, nop, nop, nop, nop, nop, nop, nop,
432 nop, nop, nop, nop, nop, nop, nop, nop, nop, nop, nop, nop, nop, nop,
433 nop, nop, nop, nop, nop, nop, nop, nop, nop, nop, nop, nop, nop, nop,
434 nop, nop, nop, nop};
Borawski.Lukasz9d8fd302018-01-05 14:56:09 +0100435
Ed Tanous1abe55e2018-09-05 08:30:59 -0700436 size_t inputLength = input.size();
Borawski.Lukasz9d8fd302018-01-05 14:56:09 +0100437
Ed Tanous1abe55e2018-09-05 08:30:59 -0700438 // allocate space for output string
439 output.clear();
440 output.reserve(((inputLength + 2) / 3) * 4);
Borawski.Lukasz9d8fd302018-01-05 14:56:09 +0100441
Jonathan Doman5beaf842020-08-14 11:23:33 -0700442 auto getCodeValue = [](char c) {
443 auto code = static_cast<unsigned char>(c);
444 // Ensure we cannot index outside the bounds of the decoding array
445 static_assert(std::numeric_limits<decltype(code)>::max() <
446 decodingData.size());
447 return decodingData[code];
448 };
449
Ed Tanous1abe55e2018-09-05 08:30:59 -0700450 // for each 4-bytes sequence from the input, extract 4 6-bits sequences by
Gunnar Millscaa3ce32020-07-08 14:46:53 -0500451 // dropping first two bits
Ed Tanous1abe55e2018-09-05 08:30:59 -0700452 // and regenerate into 3 8-bits sequences
James Feist5a806642020-07-31 16:40:33 +0000453
Ed Tanous1abe55e2018-09-05 08:30:59 -0700454 for (size_t i = 0; i < inputLength; i++)
455 {
Ed Tanous543f4402022-01-06 13:12:53 -0800456 char base64code0 = 0;
457 char base64code1 = 0;
Ed Tanous1abe55e2018-09-05 08:30:59 -0700458 char base64code2 = 0; // initialized to 0 to suppress warnings
Ed Tanous543f4402022-01-06 13:12:53 -0800459 char base64code3 = 0;
Borawski.Lukasz9d8fd302018-01-05 14:56:09 +0100460
Jonathan Doman5beaf842020-08-14 11:23:33 -0700461 base64code0 = getCodeValue(input[i]);
Ed Tanous1abe55e2018-09-05 08:30:59 -0700462 if (base64code0 == nop)
463 { // non base64 character
464 return false;
465 }
466 if (!(++i < inputLength))
467 { // we need at least two input bytes for first
468 // byte output
469 return false;
470 }
Jonathan Doman5beaf842020-08-14 11:23:33 -0700471 base64code1 = getCodeValue(input[i]);
Ed Tanous1abe55e2018-09-05 08:30:59 -0700472 if (base64code1 == nop)
473 { // non base64 character
474 return false;
475 }
476 output +=
477 static_cast<char>((base64code0 << 2) | ((base64code1 >> 4) & 0x3));
Borawski.Lukasz9d8fd302018-01-05 14:56:09 +0100478
Ed Tanous1abe55e2018-09-05 08:30:59 -0700479 if (++i < inputLength)
480 {
481 char c = input[i];
482 if (c == '=')
483 { // padding , end of input
484 return (base64code1 & 0x0f) == 0;
485 }
Jonathan Doman5beaf842020-08-14 11:23:33 -0700486 base64code2 = getCodeValue(input[i]);
Ed Tanous1abe55e2018-09-05 08:30:59 -0700487 if (base64code2 == nop)
488 { // non base64 character
489 return false;
490 }
491 output += static_cast<char>(((base64code1 << 4) & 0xf0) |
492 ((base64code2 >> 2) & 0x0f));
493 }
494
495 if (++i < inputLength)
496 {
497 char c = input[i];
498 if (c == '=')
499 { // padding , end of input
500 return (base64code2 & 0x03) == 0;
501 }
Jonathan Doman5beaf842020-08-14 11:23:33 -0700502 base64code3 = getCodeValue(input[i]);
Ed Tanous1abe55e2018-09-05 08:30:59 -0700503 if (base64code3 == nop)
504 { // non base64 character
505 return false;
506 }
507 output +=
508 static_cast<char>((((base64code2 << 6) & 0xc0) | base64code3));
509 }
Borawski.Lukasz9d8fd302018-01-05 14:56:09 +0100510 }
511
Ed Tanous1abe55e2018-09-05 08:30:59 -0700512 return true;
Borawski.Lukasz9d8fd302018-01-05 14:56:09 +0100513}
514
Krzysztof Grobelny45c367e2021-12-29 10:28:53 +0100515namespace details
516{
Ed Tanous22ce5452022-01-11 10:50:23 -0800517constexpr uint64_t maxMilliSeconds = 253402300799999;
518constexpr uint64_t maxSeconds = 253402300799;
Krzysztof Grobelny45c367e2021-12-29 10:28:53 +0100519inline std::string getDateTime(boost::posix_time::milliseconds timeSinceEpoch)
Andrew Geisslercb92c032018-08-17 07:56:14 -0700520{
Nan Zhou1d8782e2021-11-29 22:23:18 -0800521 boost::posix_time::ptime epoch(boost::gregorian::date(1970, 1, 1));
Krzysztof Grobelny45c367e2021-12-29 10:28:53 +0100522 boost::posix_time::ptime time = epoch + timeSinceEpoch;
Nan Zhou1d8782e2021-11-29 22:23:18 -0800523 // append zero offset to the end according to the Redfish spec for Date-Time
Nan Zhou5ae4b692021-12-14 13:30:37 -0800524 return boost::posix_time::to_iso_extended_string(time) + "+00:00";
Nan Zhou1d8782e2021-11-29 22:23:18 -0800525}
Krzysztof Grobelny45c367e2021-12-29 10:28:53 +0100526} // namespace details
Andrew Geisslercb92c032018-08-17 07:56:14 -0700527
Ed Tanous22ce5452022-01-11 10:50:23 -0800528// Returns the formatted date time string.
529// Note that the maximum supported date is 9999-12-31T23:59:59+00:00, if
530// the given |secondsSinceEpoch| is too large, we return the maximum supported
531// date. This behavior is to avoid exceptions throwed by Boost.
Nan Zhou1d8782e2021-11-29 22:23:18 -0800532inline std::string getDateTimeUint(uint64_t secondsSinceEpoch)
533{
Nan Zhou665479d2022-01-26 12:12:59 -0800534 secondsSinceEpoch = std::min(secondsSinceEpoch, details::maxSeconds);
535 boost::posix_time::seconds boostSeconds(secondsSinceEpoch);
Krzysztof Grobelny45c367e2021-12-29 10:28:53 +0100536 return details::getDateTime(
537 boost::posix_time::milliseconds(boostSeconds.total_milliseconds()));
538}
539
Ed Tanous22ce5452022-01-11 10:50:23 -0800540// Returns the formatted date time string.
541// Note that the maximum supported date is 9999-12-31T23:59:59.999+00:00, if
542// the given |millisSecondsSinceEpoch| is too large, we return the maximum
543// supported date.
544inline std::string getDateTimeUintMs(uint64_t milliSecondsSinceEpoch)
Krzysztof Grobelny45c367e2021-12-29 10:28:53 +0100545{
Nan Zhou665479d2022-01-26 12:12:59 -0800546 milliSecondsSinceEpoch =
547 std::min(details::maxMilliSeconds, milliSecondsSinceEpoch);
548 return details::getDateTime(
549 boost::posix_time::milliseconds(milliSecondsSinceEpoch));
Nan Zhou1d8782e2021-11-29 22:23:18 -0800550}
Andrew Geisslercb92c032018-08-17 07:56:14 -0700551
Nan Zhou1d8782e2021-11-29 22:23:18 -0800552inline std::string getDateTimeStdtime(std::time_t secondsSinceEpoch)
553{
Ed Tanous46666f32022-03-03 14:55:16 -0800554 // secondsSinceEpoch >= maxSeconds
555 if constexpr (std::cmp_less_equal(details::maxSeconds,
556 std::numeric_limits<std::time_t>::max()))
Nan Zhou665479d2022-01-26 12:12:59 -0800557 {
Ed Tanous46666f32022-03-03 14:55:16 -0800558 if (std::cmp_greater_equal(secondsSinceEpoch, details::maxSeconds))
559 {
560 secondsSinceEpoch = details::maxSeconds;
561 }
Nan Zhou665479d2022-01-26 12:12:59 -0800562 }
563 boost::posix_time::ptime time =
564 boost::posix_time::from_time_t(secondsSinceEpoch);
Krzysztof Grobelny45c367e2021-12-29 10:28:53 +0100565 return boost::posix_time::to_iso_extended_string(time) + "+00:00";
Andrew Geisslercb92c032018-08-17 07:56:14 -0700566}
567
Tejas Patil7c8c4052021-06-04 17:43:14 +0530568/**
569 * Returns the current Date, Time & the local Time Offset
570 * infromation in a pair
571 *
572 * @param[in] None
573 *
574 * @return std::pair<std::string, std::string>, which consist
575 * of current DateTime & the TimeOffset strings respectively.
576 */
577inline std::pair<std::string, std::string> getDateTimeOffsetNow()
Andrew Geisslercb92c032018-08-17 07:56:14 -0700578{
579 std::time_t time = std::time(nullptr);
Nan Zhou1d8782e2021-11-29 22:23:18 -0800580 std::string dateTime = getDateTimeStdtime(time);
Tejas Patil7c8c4052021-06-04 17:43:14 +0530581
582 /* extract the local Time Offset value from the
583 * recevied dateTime string.
584 */
585 std::string timeOffset("Z00:00");
586 std::size_t lastPos = dateTime.size();
587 std::size_t len = timeOffset.size();
588 if (lastPos > len)
589 {
590 timeOffset = dateTime.substr(lastPos - len);
591 }
592
593 return std::make_pair(dateTime, timeOffset);
Andrew Geisslercb92c032018-08-17 07:56:14 -0700594}
595
Ed Tanous51dae672018-09-05 16:07:32 -0700596inline bool constantTimeStringCompare(const std::string_view a,
597 const std::string_view b)
598{
599 // Important note, this function is ONLY constant time if the two input
600 // sizes are the same
601 if (a.size() != b.size())
602 {
603 return false;
604 }
605 return CRYPTO_memcmp(a.data(), b.data(), a.size()) == 0;
606}
607
608struct ConstantTimeCompare
609{
610 bool operator()(const std::string_view a, const std::string_view b) const
611 {
612 return constantTimeStringCompare(a, b);
613 }
614};
615
Ed Tanouseae855c2021-10-26 11:26:02 -0700616namespace details
617{
618inline boost::urls::url
619 urlFromPiecesDetail(const std::initializer_list<std::string_view> args)
620{
621 boost::urls::url url("/");
622 for (const std::string_view& arg : args)
623 {
624 url.segments().push_back(arg);
625 }
626 return url;
627}
628} // namespace details
629
630template <typename... AV>
631inline boost::urls::url urlFromPieces(const AV... args)
632{
633 return details::urlFromPiecesDetail({args...});
634}
635
Szymon Dompkeca1600c2022-03-03 14:42:52 +0100636namespace details
637{
638
639// std::reference_wrapper<std::string> - extracts segment to variable
640// std::string_view - checks if segment is equal to variable
641using UrlSegment =
642 std::variant<std::reference_wrapper<std::string>, std::string_view>;
643
644class UrlSegmentMatcherVisitor
645{
646 public:
647 bool operator()(std::string& output)
648 {
649 output = std::string_view(segment.data(), segment.size());
650 return true;
651 }
652
653 bool operator()(std::string_view expected)
654 {
655 return std::string_view(segment.data(), segment.size()) == expected;
656 }
657
658 UrlSegmentMatcherVisitor(const boost::urls::string_value& segmentIn) :
659 segment(segmentIn)
660 {}
661
662 private:
663 const boost::urls::string_value& segment;
664};
665
666inline bool readUrlSegments(const boost::urls::url_view& urlView,
667 std::initializer_list<UrlSegment>&& segments)
668{
669 const boost::urls::segments_view& urlSegments = urlView.segments();
670
671 if (!urlSegments.is_absolute() || segments.size() != urlSegments.size())
672 {
673 return false;
674 }
675
676 boost::urls::segments_view::iterator it = urlSegments.begin();
677 boost::urls::segments_view::iterator end = urlSegments.end();
678
679 for (const auto& segment : segments)
680 {
681 if (!std::visit(UrlSegmentMatcherVisitor(*it), segment))
682 {
683 return false;
684 }
685 it++;
686 }
687 return true;
688}
689
690} // namespace details
691
692template <typename... Args>
693inline bool readUrlSegments(const boost::urls::url_view& urlView,
694 Args&&... args)
695{
696 return details::readUrlSegments(urlView, {std::forward<Args>(args)...});
697}
698
Ed Tanouseb1c47d2022-02-09 11:47:27 -0800699inline std::string setProtocolDefaults(const boost::urls::url_view& url)
700{
701 if (url.scheme() == "https")
702 {
703 return "https";
704 }
705 if (url.scheme() == "http")
706 {
707 if (bmcwebInsecureEnableHttpPushStyleEventing)
708 {
709 return "http";
710 }
711 return "";
712 }
713 return "";
714}
715
716inline uint16_t setPortDefaults(const boost::urls::url_view& url)
717{
718 uint16_t port = url.port_number();
719 if (port != 0)
720 {
721 // user picked a port already.
722 return port;
723 }
724
725 // If the user hasn't explicitly stated a port, pick one explicitly for them
726 // based on the protocol defaults
727 if (url.scheme() == "http")
728 {
729 return 80;
730 }
731 if (url.scheme() == "https")
732 {
733 return 443;
734 }
735 return 0;
736}
737
Ed Tanous11baefe2022-02-09 12:14:12 -0800738inline bool validateAndSplitUrl(std::string_view destUrl, std::string& urlProto,
Ed Tanouseb1c47d2022-02-09 11:47:27 -0800739 std::string& host, uint16_t& port,
Ed Tanous11baefe2022-02-09 12:14:12 -0800740 std::string& path)
741{
Ed Tanouseb1c47d2022-02-09 11:47:27 -0800742 boost::string_view urlBoost(destUrl.data(), destUrl.size());
743 boost::urls::result<boost::urls::url_view> url =
744 boost::urls::parse_uri(urlBoost);
745 if (!url)
746 {
747 return false;
748 }
749 urlProto = setProtocolDefaults(url.value());
750 if (urlProto.empty())
Ed Tanous11baefe2022-02-09 12:14:12 -0800751 {
752 return false;
753 }
754
Ed Tanouseb1c47d2022-02-09 11:47:27 -0800755 port = setPortDefaults(url.value());
Ed Tanous11baefe2022-02-09 12:14:12 -0800756
Ed Tanouseb1c47d2022-02-09 11:47:27 -0800757 host = std::string_view(url->encoded_host().data(),
758 url->encoded_host().size());
759
760 path = std::string_view(url->encoded_path().data(),
761 url->encoded_path().size());
Ed Tanous11baefe2022-02-09 12:14:12 -0800762 if (path.empty())
763 {
764 path = "/";
765 }
Ed Tanouseb1c47d2022-02-09 11:47:27 -0800766 if (url->has_fragment())
767 {
768 path += '#';
769 path += std::string_view(url->encoded_fragment().data(),
770 url->encoded_fragment().size());
771 }
772
773 if (url->has_query())
774 {
775 path += '?';
776 path += std::string_view(url->encoded_query().data(),
777 url->encoded_query().size());
778 }
779
Ed Tanous11baefe2022-02-09 12:14:12 -0800780 return true;
781}
782
Ed Tanous1abe55e2018-09-05 08:30:59 -0700783} // namespace utility
784} // namespace crow
Ed Tanous71f2db72022-05-25 12:28:09 -0700785
786namespace nlohmann
787{
788template <>
789struct adl_serializer<boost::urls::url>
790{
791 // nlohmann requires a specific casing to look these up in adl
792 // NOLINTNEXTLINE(readability-identifier-naming)
793 static void to_json(json& j, const boost::urls::url& url)
794 {
795 j = url.string();
796 }
797};
798
799template <>
800struct adl_serializer<boost::urls::url_view>
801{
802 // NOLINTNEXTLINE(readability-identifier-naming)
803 static void to_json(json& j, const boost::urls::url_view& url)
804 {
805 j = url.string();
806 }
807};
808} // namespace nlohmann