blob: a1561b0c77322a6653da067d298b4590034c184b [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
Nan Zhou1d8782e2021-11-29 22:23:18 -08006#include <boost/date_time/posix_time/posix_time.hpp>
Ed Tanouseae855c2021-10-26 11:26:02 -07007#include <boost/url/url.hpp>
Nan Zhou1d8782e2021-11-29 22:23:18 -08008
Ed Tanous9ea15c32022-01-04 14:18:22 -08009#include <array>
Ed Tanous74849be2021-02-05 09:47:47 -080010#include <chrono>
Ed Tanous7045c8d2017-04-03 10:04:37 -070011#include <cstdint>
Ed Tanous9ea15c32022-01-04 14:18:22 -080012#include <ctime>
Ed Tanous7045c8d2017-04-03 10:04:37 -070013#include <functional>
Ed Tanous9ea15c32022-01-04 14:18:22 -080014#include <limits>
Ed Tanous7045c8d2017-04-03 10:04:37 -070015#include <stdexcept>
16#include <string>
Ed Tanous9ea15c32022-01-04 14:18:22 -080017#include <string_view>
Ed Tanous7045c8d2017-04-03 10:04:37 -070018#include <tuple>
Ed Tanous9ea15c32022-01-04 14:18:22 -080019#include <type_traits>
20#include <utility>
Szymon Dompkeca1600c2022-03-03 14:42:52 +010021#include <variant>
Ed Tanous7045c8d2017-04-03 10:04:37 -070022
Ed Tanous1abe55e2018-09-05 08:30:59 -070023namespace crow
24{
25namespace black_magic
26{
Ed Tanous7045c8d2017-04-03 10:04:37 -070027
Gunnar Mills1214b7e2020-06-04 10:11:30 -050028template <typename T>
Ed Tanous1c30e502022-03-08 18:02:24 -080029constexpr uint64_t getParameterTag()
Ed Tanous1abe55e2018-09-05 08:30:59 -070030{
Ed Tanous69509012019-10-24 16:53:05 -070031 if constexpr (std::is_same_v<int, T>)
32 {
33 return 1;
Ed Tanous1abe55e2018-09-05 08:30:59 -070034 }
Ed Tanous69509012019-10-24 16:53:05 -070035 if constexpr (std::is_same_v<char, T>)
36 {
37 return 1;
38 }
39 if constexpr (std::is_same_v<short, T>)
40 {
41 return 1;
42 }
43 if constexpr (std::is_same_v<long, T>)
44 {
45 return 1;
46 }
47 if constexpr (std::is_same_v<long long, T>)
48 {
49 return 1;
50 }
51 if constexpr (std::is_same_v<unsigned int, T>)
52 {
53 return 2;
54 }
55 if constexpr (std::is_same_v<unsigned char, T>)
56 {
57 return 2;
58 }
59 if constexpr (std::is_same_v<unsigned short, T>)
60 {
61 return 2;
62 }
63 if constexpr (std::is_same_v<unsigned long, T>)
64 {
65 return 2;
66 }
67 if constexpr (std::is_same_v<unsigned long long, T>)
68 {
69 return 2;
70 }
71 if constexpr (std::is_same_v<double, T>)
72 {
73 return 3;
74 }
75 if constexpr (std::is_same_v<std::string, T>)
76 {
77 return 4;
78 }
79 return 0;
80}
81
Gunnar Mills1214b7e2020-06-04 10:11:30 -050082template <typename... Args>
Ed Tanous988403c2020-08-24 11:29:49 -070083struct computeParameterTagFromArgsList;
Ed Tanous7045c8d2017-04-03 10:04:37 -070084
Gunnar Mills1214b7e2020-06-04 10:11:30 -050085template <>
Ed Tanous988403c2020-08-24 11:29:49 -070086struct computeParameterTagFromArgsList<>
Ed Tanous1abe55e2018-09-05 08:30:59 -070087{
Ed Tanous69509012019-10-24 16:53:05 -070088 static constexpr int value = 0;
Ed Tanous7045c8d2017-04-03 10:04:37 -070089};
90
91template <typename Arg, typename... Args>
Ed Tanous988403c2020-08-24 11:29:49 -070092struct computeParameterTagFromArgsList<Arg, Args...>
Ed Tanous1abe55e2018-09-05 08:30:59 -070093{
Ed Tanous69509012019-10-24 16:53:05 -070094 static constexpr int subValue =
Ed Tanous988403c2020-08-24 11:29:49 -070095 computeParameterTagFromArgsList<Args...>::value;
Ed Tanous69509012019-10-24 16:53:05 -070096 static constexpr int value =
Ed Tanous1c30e502022-03-08 18:02:24 -080097 getParameterTag<typename std::decay<Arg>::type>() != 0
Ed Tanous69509012019-10-24 16:53:05 -070098 ? subValue * 6 + getParameterTag<typename std::decay<Arg>::type>()
Ed Tanous1abe55e2018-09-05 08:30:59 -070099 : subValue;
Ed Tanous7045c8d2017-04-03 10:04:37 -0700100};
101
Ed Tanous988403c2020-08-24 11:29:49 -0700102inline bool isParameterTagCompatible(uint64_t a, uint64_t b)
Ed Tanous1abe55e2018-09-05 08:30:59 -0700103{
Ed Tanous1c30e502022-03-08 18:02:24 -0800104 while (true)
Ed Tanous1abe55e2018-09-05 08:30:59 -0700105 {
Ed Tanous1c30e502022-03-08 18:02:24 -0800106 if (a == 0)
107 {
108 return b == 0;
109 }
110 if (b == 0)
111 {
112 return a == 0;
113 }
114 uint64_t sa = a % 6;
115 uint64_t sb = a % 6;
116 if (sa == 5)
117 {
118 sa = 4;
119 }
120 if (sb == 5)
121 {
122 sb = 4;
123 }
124 if (sa != sb)
125 {
126 return false;
127 }
128 a /= 6;
129 b /= 6;
Ed Tanous1abe55e2018-09-05 08:30:59 -0700130 }
Ed Tanous1c30e502022-03-08 18:02:24 -0800131 return false;
Ed Tanous7045c8d2017-04-03 10:04:37 -0700132}
133
Ed Tanous1c30e502022-03-08 18:02:24 -0800134constexpr inline uint64_t getParameterTag(std::string_view url)
Ed Tanous1abe55e2018-09-05 08:30:59 -0700135{
Ed Tanous1c30e502022-03-08 18:02:24 -0800136 uint64_t tagValue = 0;
137 size_t urlSegmentIndex = std::string_view::npos;
Ed Tanousb00dcc22021-02-23 12:52:50 -0800138
Ed Tanous1c30e502022-03-08 18:02:24 -0800139 size_t paramIndex = 0;
140
141 for (size_t urlIndex = 0; urlIndex < url.size(); urlIndex++)
142 {
143 char character = url[urlIndex];
144 if (character == '<')
145 {
146 if (urlSegmentIndex != std::string_view::npos)
147 {
148 return 0;
149 }
150 urlSegmentIndex = urlIndex;
151 }
152 if (character == '>')
153 {
154 if (urlSegmentIndex == std::string_view::npos)
155 {
156 return 0;
157 }
158 std::string_view tag =
159 url.substr(urlSegmentIndex, urlIndex + 1 - urlSegmentIndex);
160
161 // Note, this is a really lame way to do std::pow(6, paramIndex)
162 // std::pow doesn't work in constexpr in clang.
163 // Ideally in the future we'd move this to use a power of 2 packing
164 // (probably 8 instead of 6) so that these just become bit shifts
165 uint64_t insertIndex = 1;
166 for (size_t unused = 0; unused < paramIndex; unused++)
167 {
168 insertIndex *= 6;
169 }
170
171 if (tag == "<int>")
172 {
173 tagValue += insertIndex * 1;
174 }
175 if (tag == "<uint>")
176 {
177 tagValue += insertIndex * 2;
178 }
179 if (tag == "<float>" || tag == "<double>")
180 {
181 tagValue += insertIndex * 3;
182 }
183 if (tag == "<str>" || tag == "<string>")
184 {
185 tagValue += insertIndex * 4;
186 }
187 if (tag == "<path>")
188 {
189 tagValue += insertIndex * 5;
190 }
191 paramIndex++;
192 urlSegmentIndex = std::string_view::npos;
193 }
194 }
195 if (urlSegmentIndex != std::string_view::npos)
Ed Tanous988403c2020-08-24 11:29:49 -0700196 {
197 return 0;
198 }
Ed Tanous1c30e502022-03-08 18:02:24 -0800199 return tagValue;
Ed Tanous7045c8d2017-04-03 10:04:37 -0700200}
Ed Tanous7045c8d2017-04-03 10:04:37 -0700201
Gunnar Mills1214b7e2020-06-04 10:11:30 -0500202template <typename... T>
203struct S
Ed Tanous1abe55e2018-09-05 08:30:59 -0700204{
Gunnar Mills1214b7e2020-06-04 10:11:30 -0500205 template <typename U>
206 using push = S<U, T...>;
207 template <typename U>
208 using push_back = S<T..., U>;
209 template <template <typename... Args> class U>
210 using rebind = U<T...>;
Ed Tanous7045c8d2017-04-03 10:04:37 -0700211};
Ed Tanous988403c2020-08-24 11:29:49 -0700212
Gunnar Mills1214b7e2020-06-04 10:11:30 -0500213template <typename F, typename Set>
214struct CallHelper;
Ed Tanous988403c2020-08-24 11:29:49 -0700215
Gunnar Mills1214b7e2020-06-04 10:11:30 -0500216template <typename F, typename... Args>
217struct CallHelper<F, S<Args...>>
Ed Tanous1abe55e2018-09-05 08:30:59 -0700218{
219 template <typename F1, typename... Args1,
220 typename = decltype(std::declval<F1>()(std::declval<Args1>()...))>
Ed Tanous2c70f802020-09-28 14:29:23 -0700221 static char test(int);
Ed Tanous7045c8d2017-04-03 10:04:37 -0700222
Gunnar Mills1214b7e2020-06-04 10:11:30 -0500223 template <typename...>
Ed Tanous2c70f802020-09-28 14:29:23 -0700224 static int test(...);
Ed Tanous7045c8d2017-04-03 10:04:37 -0700225
Ed Tanous2c70f802020-09-28 14:29:23 -0700226 static constexpr bool value = sizeof(test<F, Args...>(0)) == sizeof(char);
Ed Tanous7045c8d2017-04-03 10:04:37 -0700227};
228
Gunnar Mills1214b7e2020-06-04 10:11:30 -0500229template <uint64_t N>
230struct SingleTagToType
231{};
Ed Tanous7045c8d2017-04-03 10:04:37 -0700232
Gunnar Mills1214b7e2020-06-04 10:11:30 -0500233template <>
234struct SingleTagToType<1>
Ed Tanous1abe55e2018-09-05 08:30:59 -0700235{
236 using type = int64_t;
Ed Tanous7045c8d2017-04-03 10:04:37 -0700237};
238
Gunnar Mills1214b7e2020-06-04 10:11:30 -0500239template <>
240struct SingleTagToType<2>
Ed Tanous1abe55e2018-09-05 08:30:59 -0700241{
242 using type = uint64_t;
Ed Tanous7045c8d2017-04-03 10:04:37 -0700243};
244
Gunnar Mills1214b7e2020-06-04 10:11:30 -0500245template <>
246struct SingleTagToType<3>
Ed Tanous1abe55e2018-09-05 08:30:59 -0700247{
248 using type = double;
Ed Tanous7045c8d2017-04-03 10:04:37 -0700249};
250
Gunnar Mills1214b7e2020-06-04 10:11:30 -0500251template <>
252struct SingleTagToType<4>
Ed Tanous1abe55e2018-09-05 08:30:59 -0700253{
254 using type = std::string;
Ed Tanous7045c8d2017-04-03 10:04:37 -0700255};
256
Gunnar Mills1214b7e2020-06-04 10:11:30 -0500257template <>
258struct SingleTagToType<5>
Ed Tanous1abe55e2018-09-05 08:30:59 -0700259{
260 using type = std::string;
Ed Tanous7045c8d2017-04-03 10:04:37 -0700261};
262
Gunnar Mills1214b7e2020-06-04 10:11:30 -0500263template <uint64_t Tag>
264struct Arguments
Ed Tanous1abe55e2018-09-05 08:30:59 -0700265{
266 using subarguments = typename Arguments<Tag / 6>::type;
267 using type = typename subarguments::template push<
268 typename SingleTagToType<Tag % 6>::type>;
Ed Tanous7045c8d2017-04-03 10:04:37 -0700269};
270
Gunnar Mills1214b7e2020-06-04 10:11:30 -0500271template <>
272struct Arguments<0>
Ed Tanous1abe55e2018-09-05 08:30:59 -0700273{
274 using type = S<>;
Ed Tanous7045c8d2017-04-03 10:04:37 -0700275};
276
Gunnar Mills1214b7e2020-06-04 10:11:30 -0500277template <typename T>
Ed Tanous988403c2020-08-24 11:29:49 -0700278struct Promote
Ed Tanous1abe55e2018-09-05 08:30:59 -0700279{
280 using type = T;
281};
282
Gunnar Mills1214b7e2020-06-04 10:11:30 -0500283template <typename T>
Ed Tanous988403c2020-08-24 11:29:49 -0700284using PromoteT = typename Promote<T>::type;
285
286template <>
287struct Promote<char>
288{
289 using type = int64_t;
290};
291template <>
292struct Promote<short>
293{
294 using type = int64_t;
295};
296template <>
297struct Promote<int>
298{
299 using type = int64_t;
300};
301template <>
302struct Promote<long>
303{
304 using type = int64_t;
305};
306template <>
307struct Promote<long long>
308{
309 using type = int64_t;
310};
311template <>
312struct Promote<unsigned char>
313{
314 using type = uint64_t;
315};
316template <>
317struct Promote<unsigned short>
318{
319 using type = uint64_t;
320};
321template <>
322struct Promote<unsigned int>
323{
324 using type = uint64_t;
325};
326template <>
327struct Promote<unsigned long>
328{
329 using type = uint64_t;
330};
331template <>
332struct Promote<unsigned long long>
333{
334 using type = uint64_t;
335};
Ed Tanous7045c8d2017-04-03 10:04:37 -0700336
Ed Tanous1abe55e2018-09-05 08:30:59 -0700337} // namespace black_magic
Ed Tanous7045c8d2017-04-03 10:04:37 -0700338
Ed Tanous1abe55e2018-09-05 08:30:59 -0700339namespace utility
340{
Ed Tanous7045c8d2017-04-03 10:04:37 -0700341
Gunnar Mills1214b7e2020-06-04 10:11:30 -0500342template <typename T>
343struct function_traits;
Ed Tanous7045c8d2017-04-03 10:04:37 -0700344
Ed Tanous7045c8d2017-04-03 10:04:37 -0700345template <typename T>
Ed Tanous1abe55e2018-09-05 08:30:59 -0700346struct function_traits : public function_traits<decltype(&T::operator())>
347{
348 using parent_t = function_traits<decltype(&T::operator())>;
349 static const size_t arity = parent_t::arity;
350 using result_type = typename parent_t::result_type;
Gunnar Mills1214b7e2020-06-04 10:11:30 -0500351 template <size_t i>
352 using arg = typename parent_t::template arg<i>;
Ed Tanous7045c8d2017-04-03 10:04:37 -0700353};
Ed Tanous3dac7492017-08-02 13:46:20 -0700354
Ed Tanous55c7b7a2018-05-22 15:27:24 -0700355template <typename ClassType, typename r, typename... Args>
Ed Tanous1abe55e2018-09-05 08:30:59 -0700356struct function_traits<r (ClassType::*)(Args...) const>
357{
358 static const size_t arity = sizeof...(Args);
Ed Tanous7045c8d2017-04-03 10:04:37 -0700359
Ed Tanous1abe55e2018-09-05 08:30:59 -0700360 using result_type = r;
Ed Tanous7045c8d2017-04-03 10:04:37 -0700361
Ed Tanous1abe55e2018-09-05 08:30:59 -0700362 template <size_t i>
363 using arg = typename std::tuple_element<i, std::tuple<Args...>>::type;
Ed Tanous7045c8d2017-04-03 10:04:37 -0700364};
365
Ed Tanous55c7b7a2018-05-22 15:27:24 -0700366template <typename ClassType, typename r, typename... Args>
Ed Tanous1abe55e2018-09-05 08:30:59 -0700367struct function_traits<r (ClassType::*)(Args...)>
368{
369 static const size_t arity = sizeof...(Args);
Ed Tanous7045c8d2017-04-03 10:04:37 -0700370
Ed Tanous1abe55e2018-09-05 08:30:59 -0700371 using result_type = r;
Ed Tanous7045c8d2017-04-03 10:04:37 -0700372
Ed Tanous1abe55e2018-09-05 08:30:59 -0700373 template <size_t i>
374 using arg = typename std::tuple_element<i, std::tuple<Args...>>::type;
Ed Tanous7045c8d2017-04-03 10:04:37 -0700375};
376
Ed Tanous55c7b7a2018-05-22 15:27:24 -0700377template <typename r, typename... Args>
Ed Tanous1abe55e2018-09-05 08:30:59 -0700378struct function_traits<std::function<r(Args...)>>
379{
380 static const size_t arity = sizeof...(Args);
Ed Tanous7045c8d2017-04-03 10:04:37 -0700381
Ed Tanous1abe55e2018-09-05 08:30:59 -0700382 using result_type = r;
Ed Tanous7045c8d2017-04-03 10:04:37 -0700383
Ed Tanous1abe55e2018-09-05 08:30:59 -0700384 template <size_t i>
385 using arg = typename std::tuple_element<i, std::tuple<Args...>>::type;
Ed Tanous7045c8d2017-04-03 10:04:37 -0700386};
387
Adriana Kobylakd830ff52021-01-27 14:15:27 -0600388inline std::string base64encode(const std::string_view data)
389{
390 const std::array<char, 64> key = {
391 'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K', 'L', 'M',
392 'N', 'O', 'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X', 'Y', 'Z',
393 'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j', 'k', 'l', 'm',
394 'n', 'o', 'p', 'q', 'r', 's', 't', 'u', 'v', 'w', 'x', 'y', 'z',
395 '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', '+', '/'};
396
397 size_t size = data.size();
398 std::string ret;
399 ret.resize((size + 2) / 3 * 4);
400 auto it = ret.begin();
401
402 size_t i = 0;
403 while (i < size)
404 {
Ed Tanous543f4402022-01-06 13:12:53 -0800405 size_t keyIndex = 0;
Adriana Kobylakd830ff52021-01-27 14:15:27 -0600406
407 keyIndex = static_cast<size_t>(data[i] & 0xFC) >> 2;
408 *it++ = key[keyIndex];
409
410 if (i + 1 < size)
411 {
412 keyIndex = static_cast<size_t>(data[i] & 0x03) << 4;
413 keyIndex += static_cast<size_t>(data[i + 1] & 0xF0) >> 4;
414 *it++ = key[keyIndex];
415
416 if (i + 2 < size)
417 {
418 keyIndex = static_cast<size_t>(data[i + 1] & 0x0F) << 2;
419 keyIndex += static_cast<size_t>(data[i + 2] & 0xC0) >> 6;
420 *it++ = key[keyIndex];
421
422 keyIndex = static_cast<size_t>(data[i + 2] & 0x3F);
423 *it++ = key[keyIndex];
424 }
425 else
426 {
427 keyIndex = static_cast<size_t>(data[i + 1] & 0x0F) << 2;
428 *it++ = key[keyIndex];
429 *it++ = '=';
430 }
431 }
432 else
433 {
434 keyIndex = static_cast<size_t>(data[i] & 0x03) << 4;
435 *it++ = key[keyIndex];
436 *it++ = '=';
437 *it++ = '=';
438 }
439
440 i += 3;
441 }
442
443 return ret;
444}
445
Borawski.Lukasz9d8fd302018-01-05 14:56:09 +0100446// TODO this is temporary and should be deleted once base64 is refactored out of
447// crow
Ed Tanous39e77502019-03-04 17:35:53 -0800448inline bool base64Decode(const std::string_view input, std::string& output)
Ed Tanous1abe55e2018-09-05 08:30:59 -0700449{
Ed Tanous271584a2019-07-09 16:24:22 -0700450 static const char nop = static_cast<char>(-1);
Ed Tanous1abe55e2018-09-05 08:30:59 -0700451 // See note on encoding_data[] in above function
Jonathan Doman5beaf842020-08-14 11:23:33 -0700452 static const std::array<char, 256> decodingData = {
Ed Tanous1abe55e2018-09-05 08:30:59 -0700453 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, 62, nop, nop, nop, 63, 52, 53, 54, 55, 56, 57, 58, 59,
457 60, 61, nop, nop, nop, nop, nop, nop, nop, 0, 1, 2, 3, 4,
458 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18,
459 19, 20, 21, 22, 23, 24, 25, nop, nop, nop, nop, nop, nop, 26,
460 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40,
461 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, nop, nop, nop,
462 nop, nop, nop, nop, nop, nop, nop, nop, nop, nop, nop, nop, nop, nop,
463 nop, nop, nop, nop, nop, nop, nop, nop, nop, nop, nop, nop, nop, nop,
464 nop, nop, nop, nop, nop, nop, nop, nop, nop, nop, nop, nop, nop, nop,
465 nop, nop, nop, nop, nop, nop, nop, nop, nop, nop, nop, nop, nop, nop,
466 nop, nop, nop, nop, nop, nop, nop, nop, nop, nop, nop, nop, nop, nop,
467 nop, nop, nop, nop, nop, nop, nop, nop, nop, nop, nop, nop, nop, nop,
468 nop, nop, nop, nop, nop, nop, nop, nop, nop, nop, nop, nop, nop, nop,
469 nop, nop, nop, nop, nop, nop, nop, nop, nop, nop, nop, nop, nop, nop,
470 nop, nop, nop, nop, nop, nop, nop, nop, nop, nop, nop, nop, nop, nop,
471 nop, nop, nop, nop};
Borawski.Lukasz9d8fd302018-01-05 14:56:09 +0100472
Ed Tanous1abe55e2018-09-05 08:30:59 -0700473 size_t inputLength = input.size();
Borawski.Lukasz9d8fd302018-01-05 14:56:09 +0100474
Ed Tanous1abe55e2018-09-05 08:30:59 -0700475 // allocate space for output string
476 output.clear();
477 output.reserve(((inputLength + 2) / 3) * 4);
Borawski.Lukasz9d8fd302018-01-05 14:56:09 +0100478
Jonathan Doman5beaf842020-08-14 11:23:33 -0700479 auto getCodeValue = [](char c) {
480 auto code = static_cast<unsigned char>(c);
481 // Ensure we cannot index outside the bounds of the decoding array
482 static_assert(std::numeric_limits<decltype(code)>::max() <
483 decodingData.size());
484 return decodingData[code];
485 };
486
Ed Tanous1abe55e2018-09-05 08:30:59 -0700487 // for each 4-bytes sequence from the input, extract 4 6-bits sequences by
Gunnar Millscaa3ce32020-07-08 14:46:53 -0500488 // dropping first two bits
Ed Tanous1abe55e2018-09-05 08:30:59 -0700489 // and regenerate into 3 8-bits sequences
James Feist5a806642020-07-31 16:40:33 +0000490
Ed Tanous1abe55e2018-09-05 08:30:59 -0700491 for (size_t i = 0; i < inputLength; i++)
492 {
Ed Tanous543f4402022-01-06 13:12:53 -0800493 char base64code0 = 0;
494 char base64code1 = 0;
Ed Tanous1abe55e2018-09-05 08:30:59 -0700495 char base64code2 = 0; // initialized to 0 to suppress warnings
Ed Tanous543f4402022-01-06 13:12:53 -0800496 char base64code3 = 0;
Borawski.Lukasz9d8fd302018-01-05 14:56:09 +0100497
Jonathan Doman5beaf842020-08-14 11:23:33 -0700498 base64code0 = getCodeValue(input[i]);
Ed Tanous1abe55e2018-09-05 08:30:59 -0700499 if (base64code0 == nop)
500 { // non base64 character
501 return false;
502 }
503 if (!(++i < inputLength))
504 { // we need at least two input bytes for first
505 // byte output
506 return false;
507 }
Jonathan Doman5beaf842020-08-14 11:23:33 -0700508 base64code1 = getCodeValue(input[i]);
Ed Tanous1abe55e2018-09-05 08:30:59 -0700509 if (base64code1 == nop)
510 { // non base64 character
511 return false;
512 }
513 output +=
514 static_cast<char>((base64code0 << 2) | ((base64code1 >> 4) & 0x3));
Borawski.Lukasz9d8fd302018-01-05 14:56:09 +0100515
Ed Tanous1abe55e2018-09-05 08:30:59 -0700516 if (++i < inputLength)
517 {
518 char c = input[i];
519 if (c == '=')
520 { // padding , end of input
521 return (base64code1 & 0x0f) == 0;
522 }
Jonathan Doman5beaf842020-08-14 11:23:33 -0700523 base64code2 = getCodeValue(input[i]);
Ed Tanous1abe55e2018-09-05 08:30:59 -0700524 if (base64code2 == nop)
525 { // non base64 character
526 return false;
527 }
528 output += static_cast<char>(((base64code1 << 4) & 0xf0) |
529 ((base64code2 >> 2) & 0x0f));
530 }
531
532 if (++i < inputLength)
533 {
534 char c = input[i];
535 if (c == '=')
536 { // padding , end of input
537 return (base64code2 & 0x03) == 0;
538 }
Jonathan Doman5beaf842020-08-14 11:23:33 -0700539 base64code3 = getCodeValue(input[i]);
Ed Tanous1abe55e2018-09-05 08:30:59 -0700540 if (base64code3 == nop)
541 { // non base64 character
542 return false;
543 }
544 output +=
545 static_cast<char>((((base64code2 << 6) & 0xc0) | base64code3));
546 }
Borawski.Lukasz9d8fd302018-01-05 14:56:09 +0100547 }
548
Ed Tanous1abe55e2018-09-05 08:30:59 -0700549 return true;
Borawski.Lukasz9d8fd302018-01-05 14:56:09 +0100550}
551
Krzysztof Grobelny45c367e2021-12-29 10:28:53 +0100552namespace details
553{
Ed Tanous22ce5452022-01-11 10:50:23 -0800554constexpr uint64_t maxMilliSeconds = 253402300799999;
555constexpr uint64_t maxSeconds = 253402300799;
Krzysztof Grobelny45c367e2021-12-29 10:28:53 +0100556inline std::string getDateTime(boost::posix_time::milliseconds timeSinceEpoch)
Andrew Geisslercb92c032018-08-17 07:56:14 -0700557{
Nan Zhou1d8782e2021-11-29 22:23:18 -0800558 boost::posix_time::ptime epoch(boost::gregorian::date(1970, 1, 1));
Krzysztof Grobelny45c367e2021-12-29 10:28:53 +0100559 boost::posix_time::ptime time = epoch + timeSinceEpoch;
Nan Zhou1d8782e2021-11-29 22:23:18 -0800560 // append zero offset to the end according to the Redfish spec for Date-Time
Nan Zhou5ae4b692021-12-14 13:30:37 -0800561 return boost::posix_time::to_iso_extended_string(time) + "+00:00";
Nan Zhou1d8782e2021-11-29 22:23:18 -0800562}
Krzysztof Grobelny45c367e2021-12-29 10:28:53 +0100563} // namespace details
Andrew Geisslercb92c032018-08-17 07:56:14 -0700564
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+00:00, if
567// the given |secondsSinceEpoch| is too large, we return the maximum supported
568// date. This behavior is to avoid exceptions throwed by Boost.
Nan Zhou1d8782e2021-11-29 22:23:18 -0800569inline std::string getDateTimeUint(uint64_t secondsSinceEpoch)
570{
Nan Zhou665479d2022-01-26 12:12:59 -0800571 secondsSinceEpoch = std::min(secondsSinceEpoch, details::maxSeconds);
572 boost::posix_time::seconds boostSeconds(secondsSinceEpoch);
Krzysztof Grobelny45c367e2021-12-29 10:28:53 +0100573 return details::getDateTime(
574 boost::posix_time::milliseconds(boostSeconds.total_milliseconds()));
575}
576
Ed Tanous22ce5452022-01-11 10:50:23 -0800577// Returns the formatted date time string.
578// Note that the maximum supported date is 9999-12-31T23:59:59.999+00:00, if
579// the given |millisSecondsSinceEpoch| is too large, we return the maximum
580// supported date.
581inline std::string getDateTimeUintMs(uint64_t milliSecondsSinceEpoch)
Krzysztof Grobelny45c367e2021-12-29 10:28:53 +0100582{
Nan Zhou665479d2022-01-26 12:12:59 -0800583 milliSecondsSinceEpoch =
584 std::min(details::maxMilliSeconds, milliSecondsSinceEpoch);
585 return details::getDateTime(
586 boost::posix_time::milliseconds(milliSecondsSinceEpoch));
Nan Zhou1d8782e2021-11-29 22:23:18 -0800587}
Andrew Geisslercb92c032018-08-17 07:56:14 -0700588
Nan Zhou1d8782e2021-11-29 22:23:18 -0800589inline std::string getDateTimeStdtime(std::time_t secondsSinceEpoch)
590{
Ed Tanous46666f32022-03-03 14:55:16 -0800591 // secondsSinceEpoch >= maxSeconds
592 if constexpr (std::cmp_less_equal(details::maxSeconds,
593 std::numeric_limits<std::time_t>::max()))
Nan Zhou665479d2022-01-26 12:12:59 -0800594 {
Ed Tanous46666f32022-03-03 14:55:16 -0800595 if (std::cmp_greater_equal(secondsSinceEpoch, details::maxSeconds))
596 {
597 secondsSinceEpoch = details::maxSeconds;
598 }
Nan Zhou665479d2022-01-26 12:12:59 -0800599 }
600 boost::posix_time::ptime time =
601 boost::posix_time::from_time_t(secondsSinceEpoch);
Krzysztof Grobelny45c367e2021-12-29 10:28:53 +0100602 return boost::posix_time::to_iso_extended_string(time) + "+00:00";
Andrew Geisslercb92c032018-08-17 07:56:14 -0700603}
604
Tejas Patil7c8c4052021-06-04 17:43:14 +0530605/**
606 * Returns the current Date, Time & the local Time Offset
607 * infromation in a pair
608 *
609 * @param[in] None
610 *
611 * @return std::pair<std::string, std::string>, which consist
612 * of current DateTime & the TimeOffset strings respectively.
613 */
614inline std::pair<std::string, std::string> getDateTimeOffsetNow()
Andrew Geisslercb92c032018-08-17 07:56:14 -0700615{
616 std::time_t time = std::time(nullptr);
Nan Zhou1d8782e2021-11-29 22:23:18 -0800617 std::string dateTime = getDateTimeStdtime(time);
Tejas Patil7c8c4052021-06-04 17:43:14 +0530618
619 /* extract the local Time Offset value from the
620 * recevied dateTime string.
621 */
622 std::string timeOffset("Z00:00");
623 std::size_t lastPos = dateTime.size();
624 std::size_t len = timeOffset.size();
625 if (lastPos > len)
626 {
627 timeOffset = dateTime.substr(lastPos - len);
628 }
629
630 return std::make_pair(dateTime, timeOffset);
Andrew Geisslercb92c032018-08-17 07:56:14 -0700631}
632
Ed Tanous51dae672018-09-05 16:07:32 -0700633inline bool constantTimeStringCompare(const std::string_view a,
634 const std::string_view b)
635{
636 // Important note, this function is ONLY constant time if the two input
637 // sizes are the same
638 if (a.size() != b.size())
639 {
640 return false;
641 }
642 return CRYPTO_memcmp(a.data(), b.data(), a.size()) == 0;
643}
644
645struct ConstantTimeCompare
646{
647 bool operator()(const std::string_view a, const std::string_view b) const
648 {
649 return constantTimeStringCompare(a, b);
650 }
651};
652
Ed Tanouseae855c2021-10-26 11:26:02 -0700653namespace details
654{
655inline boost::urls::url
656 urlFromPiecesDetail(const std::initializer_list<std::string_view> args)
657{
658 boost::urls::url url("/");
659 for (const std::string_view& arg : args)
660 {
661 url.segments().push_back(arg);
662 }
663 return url;
664}
665} // namespace details
666
667template <typename... AV>
668inline boost::urls::url urlFromPieces(const AV... args)
669{
670 return details::urlFromPiecesDetail({args...});
671}
672
Szymon Dompkeca1600c2022-03-03 14:42:52 +0100673namespace details
674{
675
676// std::reference_wrapper<std::string> - extracts segment to variable
677// std::string_view - checks if segment is equal to variable
678using UrlSegment =
679 std::variant<std::reference_wrapper<std::string>, std::string_view>;
680
681class UrlSegmentMatcherVisitor
682{
683 public:
684 bool operator()(std::string& output)
685 {
686 output = std::string_view(segment.data(), segment.size());
687 return true;
688 }
689
690 bool operator()(std::string_view expected)
691 {
692 return std::string_view(segment.data(), segment.size()) == expected;
693 }
694
695 UrlSegmentMatcherVisitor(const boost::urls::string_value& segmentIn) :
696 segment(segmentIn)
697 {}
698
699 private:
700 const boost::urls::string_value& segment;
701};
702
703inline bool readUrlSegments(const boost::urls::url_view& urlView,
704 std::initializer_list<UrlSegment>&& segments)
705{
706 const boost::urls::segments_view& urlSegments = urlView.segments();
707
708 if (!urlSegments.is_absolute() || segments.size() != urlSegments.size())
709 {
710 return false;
711 }
712
713 boost::urls::segments_view::iterator it = urlSegments.begin();
714 boost::urls::segments_view::iterator end = urlSegments.end();
715
716 for (const auto& segment : segments)
717 {
718 if (!std::visit(UrlSegmentMatcherVisitor(*it), segment))
719 {
720 return false;
721 }
722 it++;
723 }
724 return true;
725}
726
727} // namespace details
728
729template <typename... Args>
730inline bool readUrlSegments(const boost::urls::url_view& urlView,
731 Args&&... args)
732{
733 return details::readUrlSegments(urlView, {std::forward<Args>(args)...});
734}
735
Ed Tanouseb1c47d2022-02-09 11:47:27 -0800736inline std::string setProtocolDefaults(const boost::urls::url_view& url)
737{
738 if (url.scheme() == "https")
739 {
740 return "https";
741 }
742 if (url.scheme() == "http")
743 {
744 if (bmcwebInsecureEnableHttpPushStyleEventing)
745 {
746 return "http";
747 }
748 return "";
749 }
750 return "";
751}
752
753inline uint16_t setPortDefaults(const boost::urls::url_view& url)
754{
755 uint16_t port = url.port_number();
756 if (port != 0)
757 {
758 // user picked a port already.
759 return port;
760 }
761
762 // If the user hasn't explicitly stated a port, pick one explicitly for them
763 // based on the protocol defaults
764 if (url.scheme() == "http")
765 {
766 return 80;
767 }
768 if (url.scheme() == "https")
769 {
770 return 443;
771 }
772 return 0;
773}
774
Ed Tanous11baefe2022-02-09 12:14:12 -0800775inline bool validateAndSplitUrl(std::string_view destUrl, std::string& urlProto,
Ed Tanouseb1c47d2022-02-09 11:47:27 -0800776 std::string& host, uint16_t& port,
Ed Tanous11baefe2022-02-09 12:14:12 -0800777 std::string& path)
778{
Ed Tanouseb1c47d2022-02-09 11:47:27 -0800779 boost::string_view urlBoost(destUrl.data(), destUrl.size());
780 boost::urls::result<boost::urls::url_view> url =
781 boost::urls::parse_uri(urlBoost);
782 if (!url)
783 {
784 return false;
785 }
786 urlProto = setProtocolDefaults(url.value());
787 if (urlProto.empty())
Ed Tanous11baefe2022-02-09 12:14:12 -0800788 {
789 return false;
790 }
791
Ed Tanouseb1c47d2022-02-09 11:47:27 -0800792 port = setPortDefaults(url.value());
Ed Tanous11baefe2022-02-09 12:14:12 -0800793
Ed Tanouseb1c47d2022-02-09 11:47:27 -0800794 host = std::string_view(url->encoded_host().data(),
795 url->encoded_host().size());
796
797 path = std::string_view(url->encoded_path().data(),
798 url->encoded_path().size());
Ed Tanous11baefe2022-02-09 12:14:12 -0800799 if (path.empty())
800 {
801 path = "/";
802 }
Ed Tanouseb1c47d2022-02-09 11:47:27 -0800803 if (url->has_fragment())
804 {
805 path += '#';
806 path += std::string_view(url->encoded_fragment().data(),
807 url->encoded_fragment().size());
808 }
809
810 if (url->has_query())
811 {
812 path += '?';
813 path += std::string_view(url->encoded_query().data(),
814 url->encoded_query().size());
815 }
816
Ed Tanous11baefe2022-02-09 12:14:12 -0800817 return true;
818}
819
Ed Tanous1abe55e2018-09-05 08:30:59 -0700820} // namespace utility
821} // namespace crow