From c9da3eab046f9c66ec86cef3cc9a1240702c8b8d Mon Sep 17 00:00:00 2001 From: EntireTwix Date: Fri, 2 Jul 2021 17:18:37 -0700 Subject: [PATCH] :sparkles: base64 --- CMakeLists.txt | 8 +++- include/admin_filter.h | 2 + include/substr_view.h | 16 ++++++++ include/user_filter.h | 2 + include/xxhash_str.h | 2 +- src/admin_filter.cpp | 92 ++++++++---------------------------------- src/substr_view.cpp | 31 ++++++++++++++ src/user_filter.cpp | 91 ++++++++--------------------------------- src/xxhash_str.cpp | 2 +- 9 files changed, 92 insertions(+), 154 deletions(-) create mode 100644 include/substr_view.h create mode 100644 src/substr_view.cpp diff --git a/CMakeLists.txt b/CMakeLists.txt index 1dd527f..fc81157 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -20,9 +20,9 @@ target_sources(${PROJECT_NAME} PRIVATE src/admin_filter.cpp src/bank_api.cpp src/bank.cpp - src/base64.c #temp src/change_flag.cpp src/log.cpp + src/substr_view.cpp src/transaction.cpp src/user_filter.cpp src/user.cpp @@ -32,8 +32,12 @@ target_sources(${PROJECT_NAME} PRIVATE target_include_directories(${PROJECT_NAME} PUBLIC include) target_include_directories(${PROJECT_NAME} PUBLIC third_party) target_include_directories(${PROJECT_NAME} PUBLIC third_party/drogon/lib/inc) +target_include_directories(${PROJECT_NAME} PUBLIC third_party/base64/include) add_subdirectory(third_party/drogon) target_link_libraries(${PROJECT_NAME} PRIVATE drogon) target_link_libraries(${PROJECT_NAME} PRIVATE ${CMAKE_THREAD_LIBS_INIT} ) -target_link_libraries(${PROJECT_NAME} PRIVATE xxHash::xxhash) \ No newline at end of file +target_link_libraries(${PROJECT_NAME} PRIVATE xxHash::xxhash) + +# AVX2_CFLAGS=-mavx2 SSSE3_CFLAGS=-mssse3 SSE41_CFLAGS=-msse4.1 SSE42_CFLAGS=-msse4.2 AVX_CFLAGS=-mavx make lib/libbase64.o +target_link_libraries(${PROJECT_NAME} PUBLIC ${CMAKE_CURRENT_SOURCE_DIR}/third_party/base64/lib/libbase64.o) \ No newline at end of file diff --git a/include/admin_filter.h b/include/admin_filter.h index 5474e73..ab51585 100644 --- a/include/admin_filter.h +++ b/include/admin_filter.h @@ -1,5 +1,7 @@ #pragma once #include +#include +#include "substr_view.h" #include "bank.h" using namespace drogon; diff --git a/include/substr_view.h b/include/substr_view.h new file mode 100644 index 0000000..af3e394 --- /dev/null +++ b/include/substr_view.h @@ -0,0 +1,16 @@ +#pragma once +#include +#include + +class substr_view +{ +private: + const char *begin; + size_t end; + +public: + substr_view(std::string_view str, size_t begin_init = 0, size_t end_init = 0) noexcept; + bool operator==(const std::string &str) const noexcept; + const char *data() const noexcept; + std::string_view str_view() const noexcept; +}; \ No newline at end of file diff --git a/include/user_filter.h b/include/user_filter.h index 289ef86..00309f7 100644 --- a/include/user_filter.h +++ b/include/user_filter.h @@ -1,5 +1,7 @@ #pragma once #include +#include +#include "substr_view.h" #include "bank.h" using namespace drogon; diff --git a/include/xxhash_str.h b/include/xxhash_str.h index 61ec6bc..efd900c 100644 --- a/include/xxhash_str.h +++ b/include/xxhash_str.h @@ -4,5 +4,5 @@ struct xxHashStringGen { - XXH64_hash_t operator()(const std::string &str) const noexcept; + XXH64_hash_t operator()(const std::string_view &str) const noexcept; }; diff --git a/src/admin_filter.cpp b/src/admin_filter.cpp index fa6b9e6..18bdab0 100644 --- a/src/admin_filter.cpp +++ b/src/admin_filter.cpp @@ -1,71 +1,5 @@ #include "admin_filter.h" -static char DecodeChar2(const char ch) -{ - if (ch >= 'A' && ch <= 'Z') - { - return ch - 'A'; - } - if (ch >= 'a' && ch <= 'z') - { - return ch - 'a' + 26; - } - if (ch >= '0' && ch <= '9') - { - return ch - '0' + 52; - } - return 63 - (ch == '-'); -} - -char *DecodeBase642(const char *string) -{ - char *output; - size_t length = strlen(string); - if (!(output = (char *)malloc(1 + (length >> 2) * 3 - (string[length - 1] == '=') - (string[length - 2] == '=')))) - { - return (char *)0; - } - - size_t index = 0; - uint32_t storage = 0; - while (string[4]) - { - storage |= DecodeChar2(*string++) << 18; - storage |= DecodeChar2(*string++) << 12; - storage |= DecodeChar2(*string++) << 6; - storage |= DecodeChar2(*string++); - - output[index++] = storage >> 16; - output[index++] = (char)(storage >> 8); - output[index++] = (char)storage; - - storage = 0; - } - - storage |= DecodeChar2(*string++) << 18; - storage |= DecodeChar2(*string++) << 12; - output[index++] = storage >> 16; - - if (*string == '=') - { - output[index] = '\0'; - return output; - } - storage |= DecodeChar2(*string++) << 6; - output[index++] = (char)(storage >> 8); - - if (*string == '=') - { - output[index] = '\0'; - return output; - } - storage |= DecodeChar2(*string); - output[index++] = (char)storage; - - output[index] = '\0'; - return output; -} - AdminFilter::AdminFilter(Bank &b) : bank(b) {} void AdminFilter::doFilter(const HttpRequestPtr &req, @@ -75,18 +9,26 @@ void AdminFilter::doFilter(const HttpRequestPtr &req, const std::string &auth_header = req->getHeader("Authorization"); if (auth_header.size() > 6) { - if (auth_header.substr(0, 6) == "Basic ") + if (substr_view(auth_header, 0, 6) == "Basic ") { - std::stringstream ss(DecodeBase642(auth_header.substr(6).c_str())); - std::string username, password; - std::getline(ss, username, ':'); - std::getline(ss, password); - if (bank.AdminVerifyPass(password)) //is admin + //only one alloc for this entire thing! + char base64_result[((auth_header.size() - 6) * 3) / 4]; + size_t new_sz; + base64_decode(substr_view(auth_header, 6).data(), auth_header.size() - 6, base64_result, &new_sz, 0); + + std::size_t res = std::string_view(base64_result, new_sz).find(':'); + if (res != std::string::npos) { - if (bank.VerifyPassword(username, password)) //is valid pair + std::string_view username = substr_view(base64_result, 0, res).str_view(); + std::string_view password = substr_view(base64_result, res + 1, new_sz).str_view(); + if (bank.AdminVerifyAccount(username)) { - fccb(); - return; + //another alloc + if (bank.VerifyPassword(username, password)) + { + fccb(); + return; + } } } } diff --git a/src/substr_view.cpp b/src/substr_view.cpp new file mode 100644 index 0000000..b39d508 --- /dev/null +++ b/src/substr_view.cpp @@ -0,0 +1,31 @@ +#include "substr_view.h" + +substr_view::substr_view(std::string_view str, size_t begin_init, size_t end_init) noexcept +{ + begin = str.begin() + begin_init; + if (!end_init) + { + end = str.size() - begin_init; + } + else + { + end = end_init - begin_init; + } +} +bool substr_view::operator==(const std::string &str) const noexcept +{ + if (str.size() != end) + { + return false; + } + for (size_t i = 0; i < end; ++i) + { + if (*(begin + end) == str[i]) + { + return false; + } + } + return true; +} +const char *substr_view::data() const noexcept { return begin; } +std::string_view substr_view::str_view() const noexcept { return std::string_view(data(), end); } \ No newline at end of file diff --git a/src/user_filter.cpp b/src/user_filter.cpp index abef932..f87f8a9 100644 --- a/src/user_filter.cpp +++ b/src/user_filter.cpp @@ -1,71 +1,5 @@ #include "user_filter.h" -static char DecodeChar(const char ch) -{ - if (ch >= 'A' && ch <= 'Z') - { - return ch - 'A'; - } - if (ch >= 'a' && ch <= 'z') - { - return ch - 'a' + 26; - } - if (ch >= '0' && ch <= '9') - { - return ch - '0' + 52; - } - return 63 - (ch == '-'); -} - -char *DecodeBase64(const char *string) -{ - char *output; - size_t length = strlen(string); - if (!(output = (char *)malloc(1 + (length >> 2) * 3 - (string[length - 1] == '=') - (string[length - 2] == '=')))) - { - return (char *)0; - } - - size_t index = 0; - uint32_t storage = 0; - while (string[4]) - { - storage |= DecodeChar(*string++) << 18; - storage |= DecodeChar(*string++) << 12; - storage |= DecodeChar(*string++) << 6; - storage |= DecodeChar(*string++); - - output[index++] = storage >> 16; - output[index++] = (char)(storage >> 8); - output[index++] = (char)storage; - - storage = 0; - } - - storage |= DecodeChar(*string++) << 18; - storage |= DecodeChar(*string++) << 12; - output[index++] = storage >> 16; - - if (*string == '=') - { - output[index] = '\0'; - return output; - } - storage |= DecodeChar(*string++) << 6; - output[index++] = (char)(storage >> 8); - - if (*string == '=') - { - output[index] = '\0'; - return output; - } - storage |= DecodeChar(*string); - output[index++] = (char)storage; - - output[index] = '\0'; - return output; -} - UserFilter::UserFilter(Bank &b) : bank(b) {} void UserFilter::doFilter(const HttpRequestPtr &req, @@ -75,17 +9,24 @@ void UserFilter::doFilter(const HttpRequestPtr &req, const std::string &auth_header = req->getHeader("Authorization"); if (auth_header.size() > 6) { - if (auth_header.substr(0, 6) == "Basic ") + if (substr_view(auth_header, 0, 6) == "Basic ") { - std::stringstream ss(DecodeBase64(auth_header.substr(6).c_str())); - std::string username, password; - std::getline(ss, username, ':'); - std::getline(ss, password); - if (bank.VerifyPassword(username, password)) + //only one alloc for this entire thing! + char base64_result[((auth_header.size() - 6) * 3) / 4]; + size_t new_sz; + base64_decode(substr_view(auth_header, 6).data(), auth_header.size() - 6, base64_result, &new_sz, 0); + + std::size_t res = std::string_view(base64_result, new_sz).find(':'); + if (res != std::string::npos) { - req->setBody(username); - fccb(); - return; + std::string_view username = substr_view(base64_result, 0, res).str_view(); + std::string_view password = substr_view(base64_result, res + 1, new_sz).str_view(); + //another alloc + if (bank.VerifyPassword(username, password)) + { + fccb(); + return; + } } } } diff --git a/src/xxhash_str.cpp b/src/xxhash_str.cpp index c3670bb..a665e23 100644 --- a/src/xxhash_str.cpp +++ b/src/xxhash_str.cpp @@ -1,6 +1,6 @@ #include "xxhash_str.h" -XXH64_hash_t xxHashStringGen::operator()(const std::string &str) const noexcept +XXH64_hash_t xxHashStringGen::operator()(const std::string_view &str) const noexcept { return XXH3_64bits(str.data(), str.size()); }