1 #pragma once 2 3 #include "nlohmann/json.hpp" 4 5 #include <openssl/crypto.h> 6 7 #include <cstdint> 8 #include <cstring> 9 #include <functional> 10 #include <regex> 11 #include <stdexcept> 12 #include <string> 13 #include <tuple> 14 15 namespace crow 16 { 17 namespace black_magic 18 { 19 20 constexpr unsigned findClosingTag(std::string_view s, unsigned p) 21 { 22 return s[p] == '>' ? p : findClosingTag(s, p + 1); 23 } 24 25 constexpr bool isInt(std::string_view s, unsigned i) 26 { 27 return s.substr(i, 5) == "<int>"; 28 } 29 30 constexpr bool isUint(std::string_view s, unsigned i) 31 { 32 return s.substr(i, 6) == "<uint>"; 33 } 34 35 constexpr bool isFloat(std::string_view s, unsigned i) 36 { 37 return s.substr(i, 7) == "<float>" || s.substr(i, 8) == "<double>"; 38 } 39 40 constexpr bool isStr(std::string_view s, unsigned i) 41 { 42 return s.substr(i, 5) == "<str>" || s.substr(i, 8) == "<string>"; 43 } 44 45 constexpr bool isPath(std::string_view s, unsigned i) 46 { 47 return s.substr(i, 6) == "<path>"; 48 } 49 50 template <typename T> 51 constexpr int getParameterTag() 52 { 53 if constexpr (std::is_same_v<int, T>) 54 { 55 return 1; 56 } 57 if constexpr (std::is_same_v<char, T>) 58 { 59 return 1; 60 } 61 if constexpr (std::is_same_v<short, T>) 62 { 63 return 1; 64 } 65 if constexpr (std::is_same_v<long, T>) 66 { 67 return 1; 68 } 69 if constexpr (std::is_same_v<long long, T>) 70 { 71 return 1; 72 } 73 if constexpr (std::is_same_v<unsigned int, T>) 74 { 75 return 2; 76 } 77 if constexpr (std::is_same_v<unsigned char, T>) 78 { 79 return 2; 80 } 81 if constexpr (std::is_same_v<unsigned short, T>) 82 { 83 return 2; 84 } 85 if constexpr (std::is_same_v<unsigned long, T>) 86 { 87 return 2; 88 } 89 if constexpr (std::is_same_v<unsigned long long, T>) 90 { 91 return 2; 92 } 93 if constexpr (std::is_same_v<double, T>) 94 { 95 return 3; 96 } 97 if constexpr (std::is_same_v<std::string, T>) 98 { 99 return 4; 100 } 101 return 0; 102 } 103 104 template <typename... Args> 105 struct computeParameterTagFromArgsList; 106 107 template <> 108 struct computeParameterTagFromArgsList<> 109 { 110 static constexpr int value = 0; 111 }; 112 113 template <typename Arg, typename... Args> 114 struct computeParameterTagFromArgsList<Arg, Args...> 115 { 116 static constexpr int subValue = 117 computeParameterTagFromArgsList<Args...>::value; 118 static constexpr int value = 119 getParameterTag<typename std::decay<Arg>::type>() 120 ? subValue * 6 + getParameterTag<typename std::decay<Arg>::type>() 121 : subValue; 122 }; 123 124 inline bool isParameterTagCompatible(uint64_t a, uint64_t b) 125 { 126 if (a == 0) 127 { 128 return b == 0; 129 } 130 if (b == 0) 131 { 132 return a == 0; 133 } 134 uint64_t sa = a % 6; 135 uint64_t sb = a % 6; 136 if (sa == 5) 137 { 138 sa = 4; 139 } 140 if (sb == 5) 141 { 142 sb = 4; 143 } 144 if (sa != sb) 145 { 146 return false; 147 } 148 return isParameterTagCompatible(a / 6, b / 6); 149 } 150 151 constexpr uint64_t getParameterTag(std::string_view s, unsigned p = 0) 152 { 153 if (p == s.size()) 154 { 155 return 0; 156 } 157 158 if (s[p] != '<') 159 { 160 return getParameterTag(s, p + 1); 161 } 162 163 if (isInt(s, p)) 164 { 165 return getParameterTag(s, findClosingTag(s, p)) * 6 + 1; 166 } 167 168 if (isUint(s, p)) 169 { 170 return getParameterTag(s, findClosingTag(s, p)) * 6 + 2; 171 } 172 173 if (isFloat(s, p)) 174 { 175 return getParameterTag(s, findClosingTag(s, p)) * 6 + 3; 176 } 177 178 if (isStr(s, p)) 179 { 180 return getParameterTag(s, findClosingTag(s, p)) * 6 + 4; 181 } 182 183 if (isPath(s, p)) 184 { 185 return getParameterTag(s, findClosingTag(s, p)) * 6 + 5; 186 } 187 188 throw std::runtime_error("invalid parameter type"); 189 } 190 191 template <typename... T> 192 struct S 193 { 194 template <typename U> 195 using push = S<U, T...>; 196 template <typename U> 197 using push_back = S<T..., U>; 198 template <template <typename... Args> class U> 199 using rebind = U<T...>; 200 }; 201 202 template <typename F, typename Set> 203 struct CallHelper; 204 205 template <typename F, typename... Args> 206 struct CallHelper<F, S<Args...>> 207 { 208 template <typename F1, typename... Args1, 209 typename = decltype(std::declval<F1>()(std::declval<Args1>()...))> 210 static char test(int); 211 212 template <typename...> 213 static int test(...); 214 215 static constexpr bool value = sizeof(test<F, Args...>(0)) == sizeof(char); 216 }; 217 218 template <uint64_t N> 219 struct SingleTagToType 220 {}; 221 222 template <> 223 struct SingleTagToType<1> 224 { 225 using type = int64_t; 226 }; 227 228 template <> 229 struct SingleTagToType<2> 230 { 231 using type = uint64_t; 232 }; 233 234 template <> 235 struct SingleTagToType<3> 236 { 237 using type = double; 238 }; 239 240 template <> 241 struct SingleTagToType<4> 242 { 243 using type = std::string; 244 }; 245 246 template <> 247 struct SingleTagToType<5> 248 { 249 using type = std::string; 250 }; 251 252 template <uint64_t Tag> 253 struct Arguments 254 { 255 using subarguments = typename Arguments<Tag / 6>::type; 256 using type = typename subarguments::template push< 257 typename SingleTagToType<Tag % 6>::type>; 258 }; 259 260 template <> 261 struct Arguments<0> 262 { 263 using type = S<>; 264 }; 265 266 template <typename T> 267 struct Promote 268 { 269 using type = T; 270 }; 271 272 template <typename T> 273 using PromoteT = typename Promote<T>::type; 274 275 template <> 276 struct Promote<char> 277 { 278 using type = int64_t; 279 }; 280 template <> 281 struct Promote<short> 282 { 283 using type = int64_t; 284 }; 285 template <> 286 struct Promote<int> 287 { 288 using type = int64_t; 289 }; 290 template <> 291 struct Promote<long> 292 { 293 using type = int64_t; 294 }; 295 template <> 296 struct Promote<long long> 297 { 298 using type = int64_t; 299 }; 300 template <> 301 struct Promote<unsigned char> 302 { 303 using type = uint64_t; 304 }; 305 template <> 306 struct Promote<unsigned short> 307 { 308 using type = uint64_t; 309 }; 310 template <> 311 struct Promote<unsigned int> 312 { 313 using type = uint64_t; 314 }; 315 template <> 316 struct Promote<unsigned long> 317 { 318 using type = uint64_t; 319 }; 320 template <> 321 struct Promote<unsigned long long> 322 { 323 using type = uint64_t; 324 }; 325 326 } // namespace black_magic 327 328 namespace detail 329 { 330 331 template <class T, std::size_t N, class... Args> 332 struct GetIndexOfElementFromTupleByTypeImpl 333 { 334 static constexpr std::size_t value = N; 335 }; 336 337 template <class T, std::size_t N, class... Args> 338 struct GetIndexOfElementFromTupleByTypeImpl<T, N, T, Args...> 339 { 340 static constexpr std::size_t value = N; 341 }; 342 343 template <class T, std::size_t N, class U, class... Args> 344 struct GetIndexOfElementFromTupleByTypeImpl<T, N, U, Args...> 345 { 346 static constexpr std::size_t value = 347 GetIndexOfElementFromTupleByTypeImpl<T, N + 1, Args...>::value; 348 }; 349 350 } // namespace detail 351 352 namespace utility 353 { 354 template <class T, class... Args> 355 T& getElementByType(std::tuple<Args...>& t) 356 { 357 return std::get< 358 detail::GetIndexOfElementFromTupleByTypeImpl<T, 0, Args...>::value>(t); 359 } 360 361 template <typename T> 362 struct function_traits; 363 364 template <typename T> 365 struct function_traits : public function_traits<decltype(&T::operator())> 366 { 367 using parent_t = function_traits<decltype(&T::operator())>; 368 static const size_t arity = parent_t::arity; 369 using result_type = typename parent_t::result_type; 370 template <size_t i> 371 using arg = typename parent_t::template arg<i>; 372 }; 373 374 template <typename ClassType, typename r, typename... Args> 375 struct function_traits<r (ClassType::*)(Args...) const> 376 { 377 static const size_t arity = sizeof...(Args); 378 379 using result_type = r; 380 381 template <size_t i> 382 using arg = typename std::tuple_element<i, std::tuple<Args...>>::type; 383 }; 384 385 template <typename ClassType, typename r, typename... Args> 386 struct function_traits<r (ClassType::*)(Args...)> 387 { 388 static const size_t arity = sizeof...(Args); 389 390 using result_type = r; 391 392 template <size_t i> 393 using arg = typename std::tuple_element<i, std::tuple<Args...>>::type; 394 }; 395 396 template <typename r, typename... Args> 397 struct function_traits<std::function<r(Args...)>> 398 { 399 static const size_t arity = sizeof...(Args); 400 401 using result_type = r; 402 403 template <size_t i> 404 using arg = typename std::tuple_element<i, std::tuple<Args...>>::type; 405 }; 406 407 // TODO this is temporary and should be deleted once base64 is refactored out of 408 // crow 409 inline bool base64Decode(const std::string_view input, std::string& output) 410 { 411 static const char nop = static_cast<char>(-1); 412 // See note on encoding_data[] in above function 413 static const std::array<char, 256> decodingData = { 414 nop, nop, nop, nop, nop, nop, nop, nop, nop, nop, nop, nop, nop, nop, 415 nop, nop, nop, nop, nop, nop, nop, nop, nop, nop, nop, nop, nop, nop, 416 nop, nop, nop, nop, nop, nop, nop, nop, nop, nop, nop, nop, nop, nop, 417 nop, 62, nop, nop, nop, 63, 52, 53, 54, 55, 56, 57, 58, 59, 418 60, 61, nop, nop, nop, nop, nop, nop, nop, 0, 1, 2, 3, 4, 419 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 420 19, 20, 21, 22, 23, 24, 25, nop, nop, nop, nop, nop, nop, 26, 421 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 422 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, nop, nop, nop, 423 nop, nop, nop, nop, nop, nop, nop, nop, nop, nop, nop, nop, nop, nop, 424 nop, nop, nop, nop, nop, nop, nop, nop, nop, nop, nop, 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}; 433 434 size_t inputLength = input.size(); 435 436 // allocate space for output string 437 output.clear(); 438 output.reserve(((inputLength + 2) / 3) * 4); 439 440 auto getCodeValue = [](char c) { 441 auto code = static_cast<unsigned char>(c); 442 // Ensure we cannot index outside the bounds of the decoding array 443 static_assert(std::numeric_limits<decltype(code)>::max() < 444 decodingData.size()); 445 return decodingData[code]; 446 }; 447 448 // for each 4-bytes sequence from the input, extract 4 6-bits sequences by 449 // dropping first two bits 450 // and regenerate into 3 8-bits sequences 451 452 for (size_t i = 0; i < inputLength; i++) 453 { 454 char base64code0; 455 char base64code1; 456 char base64code2 = 0; // initialized to 0 to suppress warnings 457 char base64code3; 458 459 base64code0 = getCodeValue(input[i]); 460 if (base64code0 == nop) 461 { // non base64 character 462 return false; 463 } 464 if (!(++i < inputLength)) 465 { // we need at least two input bytes for first 466 // byte output 467 return false; 468 } 469 base64code1 = getCodeValue(input[i]); 470 if (base64code1 == nop) 471 { // non base64 character 472 return false; 473 } 474 output += 475 static_cast<char>((base64code0 << 2) | ((base64code1 >> 4) & 0x3)); 476 477 if (++i < inputLength) 478 { 479 char c = input[i]; 480 if (c == '=') 481 { // padding , end of input 482 return (base64code1 & 0x0f) == 0; 483 } 484 base64code2 = getCodeValue(input[i]); 485 if (base64code2 == nop) 486 { // non base64 character 487 return false; 488 } 489 output += static_cast<char>(((base64code1 << 4) & 0xf0) | 490 ((base64code2 >> 2) & 0x0f)); 491 } 492 493 if (++i < inputLength) 494 { 495 char c = input[i]; 496 if (c == '=') 497 { // padding , end of input 498 return (base64code2 & 0x03) == 0; 499 } 500 base64code3 = getCodeValue(input[i]); 501 if (base64code3 == nop) 502 { // non base64 character 503 return false; 504 } 505 output += 506 static_cast<char>((((base64code2 << 6) & 0xc0) | base64code3)); 507 } 508 } 509 510 return true; 511 } 512 513 /** 514 * Method returns Date Time information according to requested format 515 * 516 * @param[in] time time in second since the Epoch 517 * 518 * @return Date Time according to requested format 519 */ 520 inline std::string getDateTime(const std::time_t& time) 521 { 522 std::array<char, 128> dateTime; 523 std::string redfishDateTime("0000-00-00T00:00:00Z00:00"); 524 525 if (std::strftime(dateTime.begin(), dateTime.size(), "%FT%T%z", 526 std::localtime(&time))) 527 { 528 // insert the colon required by the ISO 8601 standard 529 redfishDateTime = std::string(dateTime.data()); 530 redfishDateTime.insert(redfishDateTime.end() - 2, ':'); 531 } 532 533 return redfishDateTime; 534 } 535 536 inline std::string dateTimeNow() 537 { 538 std::time_t time = std::time(nullptr); 539 return getDateTime(time); 540 } 541 542 inline bool constantTimeStringCompare(const std::string_view a, 543 const std::string_view b) 544 { 545 // Important note, this function is ONLY constant time if the two input 546 // sizes are the same 547 if (a.size() != b.size()) 548 { 549 return false; 550 } 551 return CRYPTO_memcmp(a.data(), b.data(), a.size()) == 0; 552 } 553 554 struct ConstantTimeCompare 555 { 556 bool operator()(const std::string_view a, const std::string_view b) const 557 { 558 return constantTimeStringCompare(a, b); 559 } 560 }; 561 562 inline std::time_t getTimestamp(uint64_t millisTimeStamp) 563 { 564 // Retrieve Created property with format: 565 // yyyy-mm-ddThh:mm:ss 566 std::chrono::milliseconds chronoTimeStamp(millisTimeStamp); 567 return std::chrono::duration_cast<std::chrono::duration<int>>( 568 chronoTimeStamp) 569 .count(); 570 } 571 572 } // namespace utility 573 } // namespace crow 574