blob: 52a72b617fb4ab99ac41b31c5c33029a75a332b1 [file] [log] [blame]
Ed Tanous7045c8d2017-04-03 10:04:37 -07001#pragma once
Ed Tanous1abe55e2018-09-05 08:30:59 -07002
Ed Tanous51dae672018-09-05 16:07:32 -07003#include <openssl/crypto.h>
4
Nan Zhou1d8782e2021-11-29 22:23:18 -08005#include <boost/date_time/posix_time/posix_time.hpp>
Ed Tanouseae855c2021-10-26 11:26:02 -07006#include <boost/url/url.hpp>
Nan Zhou1d8782e2021-11-29 22:23:18 -08007
Ed Tanous9ea15c32022-01-04 14:18:22 -08008#include <array>
Ed Tanous74849be2021-02-05 09:47:47 -08009#include <chrono>
Ed Tanous7045c8d2017-04-03 10:04:37 -070010#include <cstdint>
Ed Tanous9ea15c32022-01-04 14:18:22 -080011#include <ctime>
Ed Tanous7045c8d2017-04-03 10:04:37 -070012#include <functional>
Ed Tanous9ea15c32022-01-04 14:18:22 -080013#include <limits>
Ed Tanous11baefe2022-02-09 12:14:12 -080014#include <regex>
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>
Ed Tanous7045c8d2017-04-03 10:04:37 -070021
Ed Tanous1abe55e2018-09-05 08:30:59 -070022namespace crow
23{
24namespace black_magic
25{
Ed Tanous7045c8d2017-04-03 10:04:37 -070026
Gunnar Mills1214b7e2020-06-04 10:11:30 -050027template <typename T>
Ed Tanous1c30e502022-03-08 18:02:24 -080028constexpr uint64_t getParameterTag()
Ed Tanous1abe55e2018-09-05 08:30:59 -070029{
Ed Tanous69509012019-10-24 16:53:05 -070030 if constexpr (std::is_same_v<int, T>)
31 {
32 return 1;
Ed Tanous1abe55e2018-09-05 08:30:59 -070033 }
Ed Tanous69509012019-10-24 16:53:05 -070034 if constexpr (std::is_same_v<char, T>)
35 {
36 return 1;
37 }
38 if constexpr (std::is_same_v<short, T>)
39 {
40 return 1;
41 }
42 if constexpr (std::is_same_v<long, T>)
43 {
44 return 1;
45 }
46 if constexpr (std::is_same_v<long long, T>)
47 {
48 return 1;
49 }
50 if constexpr (std::is_same_v<unsigned int, T>)
51 {
52 return 2;
53 }
54 if constexpr (std::is_same_v<unsigned char, T>)
55 {
56 return 2;
57 }
58 if constexpr (std::is_same_v<unsigned short, T>)
59 {
60 return 2;
61 }
62 if constexpr (std::is_same_v<unsigned long, T>)
63 {
64 return 2;
65 }
66 if constexpr (std::is_same_v<unsigned long long, T>)
67 {
68 return 2;
69 }
70 if constexpr (std::is_same_v<double, T>)
71 {
72 return 3;
73 }
74 if constexpr (std::is_same_v<std::string, T>)
75 {
76 return 4;
77 }
78 return 0;
79}
80
Gunnar Mills1214b7e2020-06-04 10:11:30 -050081template <typename... Args>
Ed Tanous988403c2020-08-24 11:29:49 -070082struct computeParameterTagFromArgsList;
Ed Tanous7045c8d2017-04-03 10:04:37 -070083
Gunnar Mills1214b7e2020-06-04 10:11:30 -050084template <>
Ed Tanous988403c2020-08-24 11:29:49 -070085struct computeParameterTagFromArgsList<>
Ed Tanous1abe55e2018-09-05 08:30:59 -070086{
Ed Tanous69509012019-10-24 16:53:05 -070087 static constexpr int value = 0;
Ed Tanous7045c8d2017-04-03 10:04:37 -070088};
89
90template <typename Arg, typename... Args>
Ed Tanous988403c2020-08-24 11:29:49 -070091struct computeParameterTagFromArgsList<Arg, Args...>
Ed Tanous1abe55e2018-09-05 08:30:59 -070092{
Ed Tanous69509012019-10-24 16:53:05 -070093 static constexpr int subValue =
Ed Tanous988403c2020-08-24 11:29:49 -070094 computeParameterTagFromArgsList<Args...>::value;
Ed Tanous69509012019-10-24 16:53:05 -070095 static constexpr int value =
Ed Tanous1c30e502022-03-08 18:02:24 -080096 getParameterTag<typename std::decay<Arg>::type>() != 0
Ed Tanous69509012019-10-24 16:53:05 -070097 ? subValue * 6 + getParameterTag<typename std::decay<Arg>::type>()
Ed Tanous1abe55e2018-09-05 08:30:59 -070098 : subValue;
Ed Tanous7045c8d2017-04-03 10:04:37 -070099};
100
Ed Tanous988403c2020-08-24 11:29:49 -0700101inline bool isParameterTagCompatible(uint64_t a, uint64_t b)
Ed Tanous1abe55e2018-09-05 08:30:59 -0700102{
Ed Tanous1c30e502022-03-08 18:02:24 -0800103 while (true)
Ed Tanous1abe55e2018-09-05 08:30:59 -0700104 {
Ed Tanous1c30e502022-03-08 18:02:24 -0800105 if (a == 0)
106 {
107 return b == 0;
108 }
109 if (b == 0)
110 {
111 return a == 0;
112 }
113 uint64_t sa = a % 6;
114 uint64_t sb = a % 6;
115 if (sa == 5)
116 {
117 sa = 4;
118 }
119 if (sb == 5)
120 {
121 sb = 4;
122 }
123 if (sa != sb)
124 {
125 return false;
126 }
127 a /= 6;
128 b /= 6;
Ed Tanous1abe55e2018-09-05 08:30:59 -0700129 }
Ed Tanous1c30e502022-03-08 18:02:24 -0800130 return false;
Ed Tanous7045c8d2017-04-03 10:04:37 -0700131}
132
Ed Tanous1c30e502022-03-08 18:02:24 -0800133constexpr inline uint64_t getParameterTag(std::string_view url)
Ed Tanous1abe55e2018-09-05 08:30:59 -0700134{
Ed Tanous1c30e502022-03-08 18:02:24 -0800135 uint64_t tagValue = 0;
136 size_t urlSegmentIndex = std::string_view::npos;
Ed Tanousb00dcc22021-02-23 12:52:50 -0800137
Ed Tanous1c30e502022-03-08 18:02:24 -0800138 size_t paramIndex = 0;
139
140 for (size_t urlIndex = 0; urlIndex < url.size(); urlIndex++)
141 {
142 char character = url[urlIndex];
143 if (character == '<')
144 {
145 if (urlSegmentIndex != std::string_view::npos)
146 {
147 return 0;
148 }
149 urlSegmentIndex = urlIndex;
150 }
151 if (character == '>')
152 {
153 if (urlSegmentIndex == std::string_view::npos)
154 {
155 return 0;
156 }
157 std::string_view tag =
158 url.substr(urlSegmentIndex, urlIndex + 1 - urlSegmentIndex);
159
160 // Note, this is a really lame way to do std::pow(6, paramIndex)
161 // std::pow doesn't work in constexpr in clang.
162 // Ideally in the future we'd move this to use a power of 2 packing
163 // (probably 8 instead of 6) so that these just become bit shifts
164 uint64_t insertIndex = 1;
165 for (size_t unused = 0; unused < paramIndex; unused++)
166 {
167 insertIndex *= 6;
168 }
169
170 if (tag == "<int>")
171 {
172 tagValue += insertIndex * 1;
173 }
174 if (tag == "<uint>")
175 {
176 tagValue += insertIndex * 2;
177 }
178 if (tag == "<float>" || tag == "<double>")
179 {
180 tagValue += insertIndex * 3;
181 }
182 if (tag == "<str>" || tag == "<string>")
183 {
184 tagValue += insertIndex * 4;
185 }
186 if (tag == "<path>")
187 {
188 tagValue += insertIndex * 5;
189 }
190 paramIndex++;
191 urlSegmentIndex = std::string_view::npos;
192 }
193 }
194 if (urlSegmentIndex != std::string_view::npos)
Ed Tanous988403c2020-08-24 11:29:49 -0700195 {
196 return 0;
197 }
Ed Tanous1c30e502022-03-08 18:02:24 -0800198 return tagValue;
Ed Tanous7045c8d2017-04-03 10:04:37 -0700199}
Ed Tanous7045c8d2017-04-03 10:04:37 -0700200
Gunnar Mills1214b7e2020-06-04 10:11:30 -0500201template <typename... T>
202struct S
Ed Tanous1abe55e2018-09-05 08:30:59 -0700203{
Gunnar Mills1214b7e2020-06-04 10:11:30 -0500204 template <typename U>
205 using push = S<U, T...>;
206 template <typename U>
207 using push_back = S<T..., U>;
208 template <template <typename... Args> class U>
209 using rebind = U<T...>;
Ed Tanous7045c8d2017-04-03 10:04:37 -0700210};
Ed Tanous988403c2020-08-24 11:29:49 -0700211
Gunnar Mills1214b7e2020-06-04 10:11:30 -0500212template <typename F, typename Set>
213struct CallHelper;
Ed Tanous988403c2020-08-24 11:29:49 -0700214
Gunnar Mills1214b7e2020-06-04 10:11:30 -0500215template <typename F, typename... Args>
216struct CallHelper<F, S<Args...>>
Ed Tanous1abe55e2018-09-05 08:30:59 -0700217{
218 template <typename F1, typename... Args1,
219 typename = decltype(std::declval<F1>()(std::declval<Args1>()...))>
Ed Tanous2c70f802020-09-28 14:29:23 -0700220 static char test(int);
Ed Tanous7045c8d2017-04-03 10:04:37 -0700221
Gunnar Mills1214b7e2020-06-04 10:11:30 -0500222 template <typename...>
Ed Tanous2c70f802020-09-28 14:29:23 -0700223 static int test(...);
Ed Tanous7045c8d2017-04-03 10:04:37 -0700224
Ed Tanous2c70f802020-09-28 14:29:23 -0700225 static constexpr bool value = sizeof(test<F, Args...>(0)) == sizeof(char);
Ed Tanous7045c8d2017-04-03 10:04:37 -0700226};
227
Gunnar Mills1214b7e2020-06-04 10:11:30 -0500228template <uint64_t N>
229struct SingleTagToType
230{};
Ed Tanous7045c8d2017-04-03 10:04:37 -0700231
Gunnar Mills1214b7e2020-06-04 10:11:30 -0500232template <>
233struct SingleTagToType<1>
Ed Tanous1abe55e2018-09-05 08:30:59 -0700234{
235 using type = int64_t;
Ed Tanous7045c8d2017-04-03 10:04:37 -0700236};
237
Gunnar Mills1214b7e2020-06-04 10:11:30 -0500238template <>
239struct SingleTagToType<2>
Ed Tanous1abe55e2018-09-05 08:30:59 -0700240{
241 using type = uint64_t;
Ed Tanous7045c8d2017-04-03 10:04:37 -0700242};
243
Gunnar Mills1214b7e2020-06-04 10:11:30 -0500244template <>
245struct SingleTagToType<3>
Ed Tanous1abe55e2018-09-05 08:30:59 -0700246{
247 using type = double;
Ed Tanous7045c8d2017-04-03 10:04:37 -0700248};
249
Gunnar Mills1214b7e2020-06-04 10:11:30 -0500250template <>
251struct SingleTagToType<4>
Ed Tanous1abe55e2018-09-05 08:30:59 -0700252{
253 using type = std::string;
Ed Tanous7045c8d2017-04-03 10:04:37 -0700254};
255
Gunnar Mills1214b7e2020-06-04 10:11:30 -0500256template <>
257struct SingleTagToType<5>
Ed Tanous1abe55e2018-09-05 08:30:59 -0700258{
259 using type = std::string;
Ed Tanous7045c8d2017-04-03 10:04:37 -0700260};
261
Gunnar Mills1214b7e2020-06-04 10:11:30 -0500262template <uint64_t Tag>
263struct Arguments
Ed Tanous1abe55e2018-09-05 08:30:59 -0700264{
265 using subarguments = typename Arguments<Tag / 6>::type;
266 using type = typename subarguments::template push<
267 typename SingleTagToType<Tag % 6>::type>;
Ed Tanous7045c8d2017-04-03 10:04:37 -0700268};
269
Gunnar Mills1214b7e2020-06-04 10:11:30 -0500270template <>
271struct Arguments<0>
Ed Tanous1abe55e2018-09-05 08:30:59 -0700272{
273 using type = S<>;
Ed Tanous7045c8d2017-04-03 10:04:37 -0700274};
275
Gunnar Mills1214b7e2020-06-04 10:11:30 -0500276template <typename T>
Ed Tanous988403c2020-08-24 11:29:49 -0700277struct Promote
Ed Tanous1abe55e2018-09-05 08:30:59 -0700278{
279 using type = T;
280};
281
Gunnar Mills1214b7e2020-06-04 10:11:30 -0500282template <typename T>
Ed Tanous988403c2020-08-24 11:29:49 -0700283using PromoteT = typename Promote<T>::type;
284
285template <>
286struct Promote<char>
287{
288 using type = int64_t;
289};
290template <>
291struct Promote<short>
292{
293 using type = int64_t;
294};
295template <>
296struct Promote<int>
297{
298 using type = int64_t;
299};
300template <>
301struct Promote<long>
302{
303 using type = int64_t;
304};
305template <>
306struct Promote<long long>
307{
308 using type = int64_t;
309};
310template <>
311struct Promote<unsigned char>
312{
313 using type = uint64_t;
314};
315template <>
316struct Promote<unsigned short>
317{
318 using type = uint64_t;
319};
320template <>
321struct Promote<unsigned int>
322{
323 using type = uint64_t;
324};
325template <>
326struct Promote<unsigned long>
327{
328 using type = uint64_t;
329};
330template <>
331struct Promote<unsigned long long>
332{
333 using type = uint64_t;
334};
Ed Tanous7045c8d2017-04-03 10:04:37 -0700335
Ed Tanous1abe55e2018-09-05 08:30:59 -0700336} // namespace black_magic
Ed Tanous7045c8d2017-04-03 10:04:37 -0700337
Ed Tanous1abe55e2018-09-05 08:30:59 -0700338namespace utility
339{
Ed Tanous7045c8d2017-04-03 10:04:37 -0700340
Gunnar Mills1214b7e2020-06-04 10:11:30 -0500341template <typename T>
342struct function_traits;
Ed Tanous7045c8d2017-04-03 10:04:37 -0700343
Ed Tanous7045c8d2017-04-03 10:04:37 -0700344template <typename T>
Ed Tanous1abe55e2018-09-05 08:30:59 -0700345struct function_traits : public function_traits<decltype(&T::operator())>
346{
347 using parent_t = function_traits<decltype(&T::operator())>;
348 static const size_t arity = parent_t::arity;
349 using result_type = typename parent_t::result_type;
Gunnar Mills1214b7e2020-06-04 10:11:30 -0500350 template <size_t i>
351 using arg = typename parent_t::template arg<i>;
Ed Tanous7045c8d2017-04-03 10:04:37 -0700352};
Ed Tanous3dac7492017-08-02 13:46:20 -0700353
Ed Tanous55c7b7a2018-05-22 15:27:24 -0700354template <typename ClassType, typename r, typename... Args>
Ed Tanous1abe55e2018-09-05 08:30:59 -0700355struct function_traits<r (ClassType::*)(Args...) const>
356{
357 static const size_t arity = sizeof...(Args);
Ed Tanous7045c8d2017-04-03 10:04:37 -0700358
Ed Tanous1abe55e2018-09-05 08:30:59 -0700359 using result_type = r;
Ed Tanous7045c8d2017-04-03 10:04:37 -0700360
Ed Tanous1abe55e2018-09-05 08:30:59 -0700361 template <size_t i>
362 using arg = typename std::tuple_element<i, std::tuple<Args...>>::type;
Ed Tanous7045c8d2017-04-03 10:04:37 -0700363};
364
Ed Tanous55c7b7a2018-05-22 15:27:24 -0700365template <typename ClassType, typename r, typename... Args>
Ed Tanous1abe55e2018-09-05 08:30:59 -0700366struct function_traits<r (ClassType::*)(Args...)>
367{
368 static const size_t arity = sizeof...(Args);
Ed Tanous7045c8d2017-04-03 10:04:37 -0700369
Ed Tanous1abe55e2018-09-05 08:30:59 -0700370 using result_type = r;
Ed Tanous7045c8d2017-04-03 10:04:37 -0700371
Ed Tanous1abe55e2018-09-05 08:30:59 -0700372 template <size_t i>
373 using arg = typename std::tuple_element<i, std::tuple<Args...>>::type;
Ed Tanous7045c8d2017-04-03 10:04:37 -0700374};
375
Ed Tanous55c7b7a2018-05-22 15:27:24 -0700376template <typename r, typename... Args>
Ed Tanous1abe55e2018-09-05 08:30:59 -0700377struct function_traits<std::function<r(Args...)>>
378{
379 static const size_t arity = sizeof...(Args);
Ed Tanous7045c8d2017-04-03 10:04:37 -0700380
Ed Tanous1abe55e2018-09-05 08:30:59 -0700381 using result_type = r;
Ed Tanous7045c8d2017-04-03 10:04:37 -0700382
Ed Tanous1abe55e2018-09-05 08:30:59 -0700383 template <size_t i>
384 using arg = typename std::tuple_element<i, std::tuple<Args...>>::type;
Ed Tanous7045c8d2017-04-03 10:04:37 -0700385};
386
Adriana Kobylakd830ff52021-01-27 14:15:27 -0600387inline std::string base64encode(const std::string_view data)
388{
389 const std::array<char, 64> key = {
390 'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K', 'L', 'M',
391 'N', 'O', 'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X', 'Y', 'Z',
392 'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j', 'k', 'l', 'm',
393 'n', 'o', 'p', 'q', 'r', 's', 't', 'u', 'v', 'w', 'x', 'y', 'z',
394 '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', '+', '/'};
395
396 size_t size = data.size();
397 std::string ret;
398 ret.resize((size + 2) / 3 * 4);
399 auto it = ret.begin();
400
401 size_t i = 0;
402 while (i < size)
403 {
Ed Tanous543f4402022-01-06 13:12:53 -0800404 size_t keyIndex = 0;
Adriana Kobylakd830ff52021-01-27 14:15:27 -0600405
406 keyIndex = static_cast<size_t>(data[i] & 0xFC) >> 2;
407 *it++ = key[keyIndex];
408
409 if (i + 1 < size)
410 {
411 keyIndex = static_cast<size_t>(data[i] & 0x03) << 4;
412 keyIndex += static_cast<size_t>(data[i + 1] & 0xF0) >> 4;
413 *it++ = key[keyIndex];
414
415 if (i + 2 < size)
416 {
417 keyIndex = static_cast<size_t>(data[i + 1] & 0x0F) << 2;
418 keyIndex += static_cast<size_t>(data[i + 2] & 0xC0) >> 6;
419 *it++ = key[keyIndex];
420
421 keyIndex = static_cast<size_t>(data[i + 2] & 0x3F);
422 *it++ = key[keyIndex];
423 }
424 else
425 {
426 keyIndex = static_cast<size_t>(data[i + 1] & 0x0F) << 2;
427 *it++ = key[keyIndex];
428 *it++ = '=';
429 }
430 }
431 else
432 {
433 keyIndex = static_cast<size_t>(data[i] & 0x03) << 4;
434 *it++ = key[keyIndex];
435 *it++ = '=';
436 *it++ = '=';
437 }
438
439 i += 3;
440 }
441
442 return ret;
443}
444
Borawski.Lukasz9d8fd302018-01-05 14:56:09 +0100445// TODO this is temporary and should be deleted once base64 is refactored out of
446// crow
Ed Tanous39e77502019-03-04 17:35:53 -0800447inline bool base64Decode(const std::string_view input, std::string& output)
Ed Tanous1abe55e2018-09-05 08:30:59 -0700448{
Ed Tanous271584a2019-07-09 16:24:22 -0700449 static const char nop = static_cast<char>(-1);
Ed Tanous1abe55e2018-09-05 08:30:59 -0700450 // See note on encoding_data[] in above function
Jonathan Doman5beaf842020-08-14 11:23:33 -0700451 static const std::array<char, 256> decodingData = {
Ed Tanous1abe55e2018-09-05 08:30:59 -0700452 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, 62, nop, nop, nop, 63, 52, 53, 54, 55, 56, 57, 58, 59,
456 60, 61, nop, nop, nop, nop, nop, nop, nop, 0, 1, 2, 3, 4,
457 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18,
458 19, 20, 21, 22, 23, 24, 25, nop, nop, nop, nop, nop, nop, 26,
459 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40,
460 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, nop, nop, nop,
461 nop, nop, nop, nop, nop, nop, nop, nop, nop, nop, nop, 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};
Borawski.Lukasz9d8fd302018-01-05 14:56:09 +0100471
Ed Tanous1abe55e2018-09-05 08:30:59 -0700472 size_t inputLength = input.size();
Borawski.Lukasz9d8fd302018-01-05 14:56:09 +0100473
Ed Tanous1abe55e2018-09-05 08:30:59 -0700474 // allocate space for output string
475 output.clear();
476 output.reserve(((inputLength + 2) / 3) * 4);
Borawski.Lukasz9d8fd302018-01-05 14:56:09 +0100477
Jonathan Doman5beaf842020-08-14 11:23:33 -0700478 auto getCodeValue = [](char c) {
479 auto code = static_cast<unsigned char>(c);
480 // Ensure we cannot index outside the bounds of the decoding array
481 static_assert(std::numeric_limits<decltype(code)>::max() <
482 decodingData.size());
483 return decodingData[code];
484 };
485
Ed Tanous1abe55e2018-09-05 08:30:59 -0700486 // for each 4-bytes sequence from the input, extract 4 6-bits sequences by
Gunnar Millscaa3ce32020-07-08 14:46:53 -0500487 // dropping first two bits
Ed Tanous1abe55e2018-09-05 08:30:59 -0700488 // and regenerate into 3 8-bits sequences
James Feist5a806642020-07-31 16:40:33 +0000489
Ed Tanous1abe55e2018-09-05 08:30:59 -0700490 for (size_t i = 0; i < inputLength; i++)
491 {
Ed Tanous543f4402022-01-06 13:12:53 -0800492 char base64code0 = 0;
493 char base64code1 = 0;
Ed Tanous1abe55e2018-09-05 08:30:59 -0700494 char base64code2 = 0; // initialized to 0 to suppress warnings
Ed Tanous543f4402022-01-06 13:12:53 -0800495 char base64code3 = 0;
Borawski.Lukasz9d8fd302018-01-05 14:56:09 +0100496
Jonathan Doman5beaf842020-08-14 11:23:33 -0700497 base64code0 = getCodeValue(input[i]);
Ed Tanous1abe55e2018-09-05 08:30:59 -0700498 if (base64code0 == nop)
499 { // non base64 character
500 return false;
501 }
502 if (!(++i < inputLength))
503 { // we need at least two input bytes for first
504 // byte output
505 return false;
506 }
Jonathan Doman5beaf842020-08-14 11:23:33 -0700507 base64code1 = getCodeValue(input[i]);
Ed Tanous1abe55e2018-09-05 08:30:59 -0700508 if (base64code1 == nop)
509 { // non base64 character
510 return false;
511 }
512 output +=
513 static_cast<char>((base64code0 << 2) | ((base64code1 >> 4) & 0x3));
Borawski.Lukasz9d8fd302018-01-05 14:56:09 +0100514
Ed Tanous1abe55e2018-09-05 08:30:59 -0700515 if (++i < inputLength)
516 {
517 char c = input[i];
518 if (c == '=')
519 { // padding , end of input
520 return (base64code1 & 0x0f) == 0;
521 }
Jonathan Doman5beaf842020-08-14 11:23:33 -0700522 base64code2 = getCodeValue(input[i]);
Ed Tanous1abe55e2018-09-05 08:30:59 -0700523 if (base64code2 == nop)
524 { // non base64 character
525 return false;
526 }
527 output += static_cast<char>(((base64code1 << 4) & 0xf0) |
528 ((base64code2 >> 2) & 0x0f));
529 }
530
531 if (++i < inputLength)
532 {
533 char c = input[i];
534 if (c == '=')
535 { // padding , end of input
536 return (base64code2 & 0x03) == 0;
537 }
Jonathan Doman5beaf842020-08-14 11:23:33 -0700538 base64code3 = getCodeValue(input[i]);
Ed Tanous1abe55e2018-09-05 08:30:59 -0700539 if (base64code3 == nop)
540 { // non base64 character
541 return false;
542 }
543 output +=
544 static_cast<char>((((base64code2 << 6) & 0xc0) | base64code3));
545 }
Borawski.Lukasz9d8fd302018-01-05 14:56:09 +0100546 }
547
Ed Tanous1abe55e2018-09-05 08:30:59 -0700548 return true;
Borawski.Lukasz9d8fd302018-01-05 14:56:09 +0100549}
550
Krzysztof Grobelny45c367e2021-12-29 10:28:53 +0100551namespace details
552{
Ed Tanous22ce5452022-01-11 10:50:23 -0800553constexpr uint64_t maxMilliSeconds = 253402300799999;
554constexpr uint64_t maxSeconds = 253402300799;
Krzysztof Grobelny45c367e2021-12-29 10:28:53 +0100555inline std::string getDateTime(boost::posix_time::milliseconds timeSinceEpoch)
Andrew Geisslercb92c032018-08-17 07:56:14 -0700556{
Nan Zhou1d8782e2021-11-29 22:23:18 -0800557 boost::posix_time::ptime epoch(boost::gregorian::date(1970, 1, 1));
Krzysztof Grobelny45c367e2021-12-29 10:28:53 +0100558 boost::posix_time::ptime time = epoch + timeSinceEpoch;
Nan Zhou1d8782e2021-11-29 22:23:18 -0800559 // append zero offset to the end according to the Redfish spec for Date-Time
Nan Zhou5ae4b692021-12-14 13:30:37 -0800560 return boost::posix_time::to_iso_extended_string(time) + "+00:00";
Nan Zhou1d8782e2021-11-29 22:23:18 -0800561}
Krzysztof Grobelny45c367e2021-12-29 10:28:53 +0100562} // namespace details
Andrew Geisslercb92c032018-08-17 07:56:14 -0700563
Ed Tanous22ce5452022-01-11 10:50:23 -0800564// Returns the formatted date time string.
565// Note that the maximum supported date is 9999-12-31T23:59:59+00:00, if
566// the given |secondsSinceEpoch| is too large, we return the maximum supported
567// date. This behavior is to avoid exceptions throwed by Boost.
Nan Zhou1d8782e2021-11-29 22:23:18 -0800568inline std::string getDateTimeUint(uint64_t secondsSinceEpoch)
569{
Nan Zhou665479d2022-01-26 12:12:59 -0800570 secondsSinceEpoch = std::min(secondsSinceEpoch, details::maxSeconds);
571 boost::posix_time::seconds boostSeconds(secondsSinceEpoch);
Krzysztof Grobelny45c367e2021-12-29 10:28:53 +0100572 return details::getDateTime(
573 boost::posix_time::milliseconds(boostSeconds.total_milliseconds()));
574}
575
Ed Tanous22ce5452022-01-11 10:50:23 -0800576// Returns the formatted date time string.
577// Note that the maximum supported date is 9999-12-31T23:59:59.999+00:00, if
578// the given |millisSecondsSinceEpoch| is too large, we return the maximum
579// supported date.
580inline std::string getDateTimeUintMs(uint64_t milliSecondsSinceEpoch)
Krzysztof Grobelny45c367e2021-12-29 10:28:53 +0100581{
Nan Zhou665479d2022-01-26 12:12:59 -0800582 milliSecondsSinceEpoch =
583 std::min(details::maxMilliSeconds, milliSecondsSinceEpoch);
584 return details::getDateTime(
585 boost::posix_time::milliseconds(milliSecondsSinceEpoch));
Nan Zhou1d8782e2021-11-29 22:23:18 -0800586}
Andrew Geisslercb92c032018-08-17 07:56:14 -0700587
Nan Zhou1d8782e2021-11-29 22:23:18 -0800588inline std::string getDateTimeStdtime(std::time_t secondsSinceEpoch)
589{
Ed Tanous46666f32022-03-03 14:55:16 -0800590 // secondsSinceEpoch >= maxSeconds
591 if constexpr (std::cmp_less_equal(details::maxSeconds,
592 std::numeric_limits<std::time_t>::max()))
Nan Zhou665479d2022-01-26 12:12:59 -0800593 {
Ed Tanous46666f32022-03-03 14:55:16 -0800594 if (std::cmp_greater_equal(secondsSinceEpoch, details::maxSeconds))
595 {
596 secondsSinceEpoch = details::maxSeconds;
597 }
Nan Zhou665479d2022-01-26 12:12:59 -0800598 }
599 boost::posix_time::ptime time =
600 boost::posix_time::from_time_t(secondsSinceEpoch);
Krzysztof Grobelny45c367e2021-12-29 10:28:53 +0100601 return boost::posix_time::to_iso_extended_string(time) + "+00:00";
Andrew Geisslercb92c032018-08-17 07:56:14 -0700602}
603
Tejas Patil7c8c4052021-06-04 17:43:14 +0530604/**
605 * Returns the current Date, Time & the local Time Offset
606 * infromation in a pair
607 *
608 * @param[in] None
609 *
610 * @return std::pair<std::string, std::string>, which consist
611 * of current DateTime & the TimeOffset strings respectively.
612 */
613inline std::pair<std::string, std::string> getDateTimeOffsetNow()
Andrew Geisslercb92c032018-08-17 07:56:14 -0700614{
615 std::time_t time = std::time(nullptr);
Nan Zhou1d8782e2021-11-29 22:23:18 -0800616 std::string dateTime = getDateTimeStdtime(time);
Tejas Patil7c8c4052021-06-04 17:43:14 +0530617
618 /* extract the local Time Offset value from the
619 * recevied dateTime string.
620 */
621 std::string timeOffset("Z00:00");
622 std::size_t lastPos = dateTime.size();
623 std::size_t len = timeOffset.size();
624 if (lastPos > len)
625 {
626 timeOffset = dateTime.substr(lastPos - len);
627 }
628
629 return std::make_pair(dateTime, timeOffset);
Andrew Geisslercb92c032018-08-17 07:56:14 -0700630}
631
Ed Tanous51dae672018-09-05 16:07:32 -0700632inline bool constantTimeStringCompare(const std::string_view a,
633 const std::string_view b)
634{
635 // Important note, this function is ONLY constant time if the two input
636 // sizes are the same
637 if (a.size() != b.size())
638 {
639 return false;
640 }
641 return CRYPTO_memcmp(a.data(), b.data(), a.size()) == 0;
642}
643
644struct ConstantTimeCompare
645{
646 bool operator()(const std::string_view a, const std::string_view b) const
647 {
648 return constantTimeStringCompare(a, b);
649 }
650};
651
Ed Tanouseae855c2021-10-26 11:26:02 -0700652namespace details
653{
654inline boost::urls::url
655 urlFromPiecesDetail(const std::initializer_list<std::string_view> args)
656{
657 boost::urls::url url("/");
658 for (const std::string_view& arg : args)
659 {
660 url.segments().push_back(arg);
661 }
662 return url;
663}
664} // namespace details
665
666template <typename... AV>
667inline boost::urls::url urlFromPieces(const AV... args)
668{
669 return details::urlFromPiecesDetail({args...});
670}
671
Ed Tanous11baefe2022-02-09 12:14:12 -0800672inline bool validateAndSplitUrl(std::string_view destUrl, std::string& urlProto,
673 std::string& host, std::string& port,
674 std::string& path)
675{
676 // Validate URL using regex expression
677 // Format: <protocol>://<host>:<port>/<path>
678 // protocol: http/https
679 const std::regex urlRegex(
680 "(http|https)://([^/\\x20\\x3f\\x23\\x3a]+):?([0-9]*)(/"
681 "([^\\x20\\x23\\x3f]*\\x3f?([^\\x20\\x23\\x3f])*)?)");
682 std::cmatch match;
683 if (!std::regex_match(destUrl.begin(), destUrl.end(), match, urlRegex))
684 {
685 return false;
686 }
687
688 urlProto = std::string(match[1].first, match[1].second);
689 if (urlProto == "http")
690 {
691#ifndef BMCWEB_INSECURE_ENABLE_HTTP_PUSH_STYLE_EVENTING
692 return false;
693#endif
694 }
695
696 host = std::string(match[2].first, match[2].second);
697 port = std::string(match[3].first, match[3].second);
698 path = std::string(match[4].first, match[4].second);
699 if (port.empty())
700 {
701 if (urlProto == "http")
702 {
703 port = "80";
704 }
705 else
706 {
707 port = "443";
708 }
709 }
710 if (path.empty())
711 {
712 path = "/";
713 }
714 return true;
715}
716
Ed Tanous1abe55e2018-09-05 08:30:59 -0700717} // namespace utility
718} // namespace crow