blob: 7b0af130a6dbc2ef5f8c76a9809714c555f8e8c6 [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
Ed Tanous4e23a442022-06-06 09:57:26 -0700658 explicit UrlSegmentMatcherVisitor(
659 const boost::urls::string_value& segmentIn) :
Szymon Dompkeca1600c2022-03-03 14:42:52 +0100660 segment(segmentIn)
661 {}
662
663 private:
664 const boost::urls::string_value& segment;
665};
666
667inline bool readUrlSegments(const boost::urls::url_view& urlView,
668 std::initializer_list<UrlSegment>&& segments)
669{
670 const boost::urls::segments_view& urlSegments = urlView.segments();
671
672 if (!urlSegments.is_absolute() || segments.size() != urlSegments.size())
673 {
674 return false;
675 }
676
677 boost::urls::segments_view::iterator it = urlSegments.begin();
678 boost::urls::segments_view::iterator end = urlSegments.end();
679
680 for (const auto& segment : segments)
681 {
682 if (!std::visit(UrlSegmentMatcherVisitor(*it), segment))
683 {
684 return false;
685 }
686 it++;
687 }
688 return true;
689}
690
691} // namespace details
692
693template <typename... Args>
694inline bool readUrlSegments(const boost::urls::url_view& urlView,
695 Args&&... args)
696{
697 return details::readUrlSegments(urlView, {std::forward<Args>(args)...});
698}
699
Ed Tanouseb1c47d2022-02-09 11:47:27 -0800700inline std::string setProtocolDefaults(const boost::urls::url_view& url)
701{
702 if (url.scheme() == "https")
703 {
704 return "https";
705 }
706 if (url.scheme() == "http")
707 {
708 if (bmcwebInsecureEnableHttpPushStyleEventing)
709 {
710 return "http";
711 }
712 return "";
713 }
714 return "";
715}
716
717inline uint16_t setPortDefaults(const boost::urls::url_view& url)
718{
719 uint16_t port = url.port_number();
720 if (port != 0)
721 {
722 // user picked a port already.
723 return port;
724 }
725
726 // If the user hasn't explicitly stated a port, pick one explicitly for them
727 // based on the protocol defaults
728 if (url.scheme() == "http")
729 {
730 return 80;
731 }
732 if (url.scheme() == "https")
733 {
734 return 443;
735 }
736 return 0;
737}
738
Ed Tanous11baefe2022-02-09 12:14:12 -0800739inline bool validateAndSplitUrl(std::string_view destUrl, std::string& urlProto,
Ed Tanouseb1c47d2022-02-09 11:47:27 -0800740 std::string& host, uint16_t& port,
Ed Tanous11baefe2022-02-09 12:14:12 -0800741 std::string& path)
742{
Ed Tanouseb1c47d2022-02-09 11:47:27 -0800743 boost::string_view urlBoost(destUrl.data(), destUrl.size());
744 boost::urls::result<boost::urls::url_view> url =
745 boost::urls::parse_uri(urlBoost);
746 if (!url)
747 {
748 return false;
749 }
750 urlProto = setProtocolDefaults(url.value());
751 if (urlProto.empty())
Ed Tanous11baefe2022-02-09 12:14:12 -0800752 {
753 return false;
754 }
755
Ed Tanouseb1c47d2022-02-09 11:47:27 -0800756 port = setPortDefaults(url.value());
Ed Tanous11baefe2022-02-09 12:14:12 -0800757
Ed Tanouseb1c47d2022-02-09 11:47:27 -0800758 host = std::string_view(url->encoded_host().data(),
759 url->encoded_host().size());
760
761 path = std::string_view(url->encoded_path().data(),
762 url->encoded_path().size());
Ed Tanous11baefe2022-02-09 12:14:12 -0800763 if (path.empty())
764 {
765 path = "/";
766 }
Ed Tanouseb1c47d2022-02-09 11:47:27 -0800767 if (url->has_fragment())
768 {
769 path += '#';
770 path += std::string_view(url->encoded_fragment().data(),
771 url->encoded_fragment().size());
772 }
773
774 if (url->has_query())
775 {
776 path += '?';
777 path += std::string_view(url->encoded_query().data(),
778 url->encoded_query().size());
779 }
780
Ed Tanous11baefe2022-02-09 12:14:12 -0800781 return true;
782}
783
Ed Tanous1abe55e2018-09-05 08:30:59 -0700784} // namespace utility
785} // namespace crow
Ed Tanous71f2db72022-05-25 12:28:09 -0700786
787namespace nlohmann
788{
789template <>
790struct adl_serializer<boost::urls::url>
791{
792 // nlohmann requires a specific casing to look these up in adl
793 // NOLINTNEXTLINE(readability-identifier-naming)
794 static void to_json(json& j, const boost::urls::url& url)
795 {
796 j = url.string();
797 }
798};
799
800template <>
801struct adl_serializer<boost::urls::url_view>
802{
803 // NOLINTNEXTLINE(readability-identifier-naming)
804 static void to_json(json& j, const boost::urls::url_view& url)
805 {
806 j = url.string();
807 }
808};
809} // namespace nlohmann