Adapt Drogon to take advitange of Trantor TLS refactor (#1505)

Co-authored-by: marty1885 <marty1885@gmail.com>
This commit is contained in:
Martin Chang 2023-03-30 22:14:53 +07:00 committed by GitHub
parent 120aaf249d
commit 122a42cd4f
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
32 changed files with 249 additions and 801 deletions

1
.gitmodules vendored
View File

@ -1,4 +1,3 @@
[submodule "trantor"]
path = trantor
url = https://github.com/an-tao/trantor.git

View File

@ -505,20 +505,6 @@ endif (BUILD_TESTING)
find_package(ZLIB REQUIRED)
target_link_libraries(${PROJECT_NAME} PRIVATE ZLIB::ZLIB)
find_package(OpenSSL)
if (OpenSSL_FOUND)
target_link_libraries(${PROJECT_NAME} PRIVATE OpenSSL::SSL OpenSSL::Crypto)
else (OpenSSL_FOUND)
set(DROGON_SOURCES
${DROGON_SOURCES}
lib/src/ssl_funcs/Md5.cc
lib/src/ssl_funcs/Sha1.cc)
set(private_headers
${private_headers}
lib/src/ssl_funcs/Md5.h
lib/src/ssl_funcs/Sha1.h)
endif (OpenSSL_FOUND)
execute_process(COMMAND "git" rev-parse HEAD
WORKING_DIRECTORY "${CMAKE_SOURCE_DIR}"
OUTPUT_VARIABLE GIT_SHA1

View File

@ -5,8 +5,8 @@
//ssl:The global SSL settings. "key" and "cert" are the path to the SSL key and certificate. While
// "conf" is an array of 1 or 2-element tuples that supplies file style options for `SSL_CONF_cmd`.
"ssl": {
"cert": "../../trantor/trantor/tests/server.pem",
"key": "../../trantor/trantor/tests/server.pem",
"cert": "../../trantor/trantor/tests/server.crt",
"key": "../../trantor/trantor/tests/server.key",
"conf": [
//["Options", "-SessionTicket"],
//["Options", "Compression"]

View File

@ -5,8 +5,8 @@
//ssl:The global SSL settings. "key" and "cert" are the path to the SSL key and certificate. While
// "conf" is an array of 1 or 2-element tuples that supplies file style options for `SSL_CONF_cmd`.
"ssl": {
"cert": "../../trantor/trantor/tests/server.pem",
"key": "../../trantor/trantor/tests/server.pem",
"cert": "../../trantor/trantor/tests/server.crt",
"key": "../../trantor/trantor/tests/server.key",
"conf": [
//["Options", "-SessionTicket"],
//["Options", "Compression"]

View File

@ -15,7 +15,9 @@
#include "version.h"
#include <drogon/config.h>
#include <drogon/version.h>
#include <drogon/utils/Utilities.h>
#include <trantor/net/Resolver.h>
#include <trantor/utils/Utilities.h>
#include <iostream>
using namespace drogon_ctl;
@ -30,6 +32,8 @@ static const char banner[] =
void version::handleCommand(std::vector<std::string> &parameters)
{
const auto tlsBackend = trantor::utils::tlsBackend();
const bool tlsSupported = drogon::utils::supportsTls();
std::cout << banner << std::endl;
std::cout << "A utility for drogon" << std::endl;
std::cout << "Version: " << DROGON_VERSION << std::endl;
@ -43,11 +47,7 @@ void version::handleCommand(std::vector<std::string> &parameters)
<< (LIBPQ_SUPPORTS_BATCH_MODE ? "yes)\n" : "no)\n")
<< " mariadb: " << (USE_MYSQL ? "yes\n" : "no\n")
<< " sqlite3: " << (USE_SQLITE3 ? "yes\n" : "no\n");
#ifdef OpenSSL_FOUND
std::cout << " openssl: yes\n";
#else
std::cout << " openssl: no\n";
#endif
std::cout << " ssl/tls backend: " << tlsBackend << "\n";
#ifdef USE_BROTLI
std::cout << " brotli: yes\n";
#else

View File

@ -4,8 +4,8 @@
/*
//ssl: The global ssl files setting
"ssl": {
"cert": "../../trantor/trantor/tests/server.pem",
"key": "../../trantor/trantor/tests/server.pem"
"cert": "../../trantor/trantor/tests/server.crt",
"key": "../../trantor/trantor/tests/server.key"
},*/
"listeners": [{
//address: Ip address,0.0.0.0 by default

View File

@ -25,6 +25,7 @@
#include <drogon/UploadFile.h>
#include <json/json.h>
#include <trantor/net/InetAddress.h>
#include <trantor/net/Certificate.h>
#include <trantor/utils/Date.h>
#include <memory>
#include <string>
@ -341,6 +342,13 @@ class DROGON_EXPORT HttpRequest
return creationDate();
}
// Return the peer certificate (if any)
virtual const trantor::CertificatePtr &peerCertificate() const = 0;
const trantor::CertificatePtr &getPeerCertificate() const
{
return peerCertificate();
}
/// Get the Json object of the request
/**
* The content type of the request must be 'application/json',

View File

@ -15,6 +15,7 @@
#include <drogon/exports.h>
#include <drogon/utils/string_view.h>
#include <trantor/net/Certificate.h>
#include <drogon/DrClassMap.h>
#include <drogon/Cookie.h>
#include <drogon/HttpTypes.h>
@ -336,6 +337,16 @@ class DROGON_EXPORT HttpResponse
*/
virtual void setPassThrough(bool flag) = 0;
/**
* @brief Get the certificate of the peer, if any.
* @return The certificate of the peer. nullptr is none.
*/
virtual const trantor::CertificatePtr &peerCertificate() const = 0;
const trantor::CertificatePtr &getPeerCertificate() const
{
return peerCertificate();
}
/* The following methods are a series of factory methods that help users
* create response objects. */

View File

@ -160,6 +160,7 @@ enum class ReqResult
Timeout,
HandshakeError,
InvalidCertificate,
EncryptionFailure,
};
enum class WebSocketMessageType
@ -190,6 +191,8 @@ inline string_view to_string_view(drogon::ReqResult result)
return "Handshake error";
case ReqResult::InvalidCertificate:
return "Invalid certificate";
case ReqResult::EncryptionFailure:
return "Unrecoverable encryption failure";
default:
return "Unknown error";
}

View File

@ -134,6 +134,30 @@ inline std::string getMd5(const std::string &originalString)
return getMd5(originalString.data(), originalString.length());
}
DROGON_EXPORT std::string getSha1(const char *data, const size_t dataLen);
inline std::string getSha1(const std::string &originalString)
{
return getSha1(originalString.data(), originalString.length());
}
DROGON_EXPORT std::string getSha256(const char *data, const size_t dataLen);
inline std::string getSha256(const std::string &originalString)
{
return getSha256(originalString.data(), originalString.length());
}
DROGON_EXPORT std::string getSha3(const char *data, const size_t dataLen);
inline std::string getSha3(const std::string &originalString)
{
return getSha3(originalString.data(), originalString.length());
}
DROGON_EXPORT std::string getBlake2b(const char *data, const size_t dataLen);
inline std::string getBlake2b(const std::string &originalString)
{
return getBlake2b(originalString.data(), originalString.length());
}
/// Commpress or decompress data using gzip lib.
/**
* @param data the input data
@ -300,12 +324,18 @@ DROGON_EXPORT void replaceAll(std::string &s,
* @param size number of bytes to generate
*
* @return true if generation is successfull. False otherwise
*
* @note DO NOT abuse this function. Especially if Drogon is built without
* OpenSSL. Entropy running low is a real issue.
*/
DROGON_EXPORT bool secureRandomBytes(void *ptr, size_t size);
/**
* @brief Generates cryptographically secure random string.
*
* @param size number of characters to generate
*
* @return the random string
*/
DROGON_EXPORT std::string secureRandomString(size_t size);
template <typename T>
typename std::enable_if<internal::CanConvertFromStringStream<T>::value, T>::type
fromString(const std::string &p) noexcept(false)
@ -409,6 +439,8 @@ inline bool fromString<bool>(const std::string &p) noexcept(false)
throw std::runtime_error("Can't convert from string '" + p + "' to bool");
}
DROGON_EXPORT bool supportsTls() noexcept;
namespace internal
{
DROGON_EXPORT extern const size_t fixedRandomNumber;

View File

@ -545,10 +545,7 @@ class HttpAppFrameworkImpl final : public HttpAppFramework
bool supportSSL() const override
{
#ifdef OpenSSL_FOUND
return true;
#endif
return false;
return trantor::utils::tlsBackend() != "None";
}
size_t getCurrentThreadIndex() const override

View File

@ -37,19 +37,20 @@ void HttpClientImpl::createTcpClient()
tcpClientPtr_ =
std::make_shared<trantor::TcpClient>(loop_, serverAddr_, "httpClient");
#ifdef OpenSSL_FOUND
if (useSSL_)
if (useSSL_ && utils::supportsTls())
{
LOG_TRACE << "useOldTLS=" << useOldTLS_;
LOG_TRACE << "domain=" << domain_;
tcpClientPtr_->enableSSL(useOldTLS_,
validateCert_,
domain_,
sslConfCmds_,
clientCertPath_,
clientKeyPath_);
auto policy = trantor::TLSPolicy::defaultClientPolicy();
policy->setUseOldTLS(useOldTLS_)
.setValidate(validateCert_)
.setHostname(domain_)
.setConfCmds(sslConfCmds_)
.setCertPath(clientCertPath_)
.setKeyPath(clientKeyPath_);
tcpClientPtr_->enableSSL(std::move(policy));
}
#endif
auto thisPtr = shared_from_this();
std::weak_ptr<HttpClientImpl> weakPtr = thisPtr;
@ -126,6 +127,8 @@ void HttpClientImpl::createTcpClient()
thisPtr->onError(ReqResult::HandshakeError);
else if (err == trantor::SSLError::kSSLInvalidCertificate)
thisPtr->onError(ReqResult::InvalidCertificate);
else if (err == trantor::SSLError::kSSLProtocolError)
thisPtr->onError(ReqResult::EncryptionFailure);
else
{
LOG_FATAL << "Invalid value for SSLError";
@ -159,12 +162,12 @@ HttpClientImpl::HttpClientImpl(trantor::EventLoop *loop,
lowerHost.end(),
lowerHost.begin(),
[](unsigned char c) { return tolower(c); });
if (lowerHost.find("https://") != std::string::npos)
if (lowerHost.find("https://") == 0)
{
useSSL_ = true;
lowerHost = lowerHost.substr(8);
}
else if (lowerHost.find("http://") != std::string::npos)
else if (lowerHost.find("http://") == 0)
{
useSSL_ = false;
lowerHost = lowerHost.substr(7);
@ -621,6 +624,7 @@ void HttpClientImpl::onRecvMessage(const trantor::TcpConnectionPtr &connPtr,
if (responseParser->gotAll())
{
auto resp = responseParser->responseImpl();
resp->setPeerCertificate(connPtr->peerCertificate());
responseParser->reset();
bytesReceived_ += (msgSize - msg->readableBytes());
msgSize = msg->readableBytes();

View File

@ -128,6 +128,16 @@ std::string HttpFileImpl::getMd5() const noexcept
return utils::getMd5(fileContent_.data(), fileContent_.size());
}
std::string HttpFileImpl::getSha256() const noexcept
{
return utils::getSha256(fileContent_.data(), fileContent_.size());
}
std::string HttpFileImpl::getSha3() const noexcept
{
return utils::getSha3(fileContent_.data(), fileContent_.size());
}
const std::string &HttpFile::getFileName() const noexcept
{
return implPtr_->getFileName();

View File

@ -116,8 +116,12 @@ class HttpFileImpl
return parseFileType(getFileExtension());
}
/// Return the md5 string of the file
/// Return md5 hash of the file
std::string getMd5() const noexcept;
// Return sha1 hash of the file
std::string getSha256() const noexcept;
// Return sha512 hash of the file
std::string getSha3() const noexcept;
// int saveTo(const std::string &pathAndFileName) const;
int saveTo(const filesystem::path &pathAndFileName) const noexcept;
void setRequest(const HttpRequestPtr &req) noexcept

View File

@ -21,6 +21,7 @@
#include <drogon/utils/Utilities.h>
#include <trantor/net/EventLoop.h>
#include <trantor/net/InetAddress.h>
#include <trantor/net/Certificate.h>
#include <trantor/utils/Logger.h>
#include <trantor/utils/MsgBuffer.h>
#include <trantor/utils/NonCopyable.h>
@ -74,6 +75,7 @@ class HttpRequestImpl : public HttpRequest
contentTypeString_.clear();
keepAlive_ = true;
jsonParsingErrorPtr_.reset();
peerCertificate_.reset();
}
trantor::EventLoop *getLoop()
{
@ -231,6 +233,11 @@ class HttpRequestImpl : public HttpRequest
return creationDate_;
}
const trantor::CertificatePtr &peerCertificate() const override
{
return peerCertificate_;
}
void setCreationDate(const trantor::Date &date)
{
creationDate_ = date;
@ -246,6 +253,11 @@ class HttpRequestImpl : public HttpRequest
local_ = local;
}
void setPeerCertificate(const trantor::CertificatePtr &cert)
{
peerCertificate_ = cert;
}
void addHeader(const char *start, const char *colon, const char *end);
void removeHeader(std::string key) override
@ -561,6 +573,7 @@ class HttpRequestImpl : public HttpRequest
trantor::InetAddress peer_;
trantor::InetAddress local_;
trantor::Date creationDate_;
trantor::CertificatePtr peerCertificate_;
std::unique_ptr<CacheFile> cacheFilePtr_;
mutable std::unique_ptr<std::string> jsonParsingErrorPtr_;
std::unique_ptr<std::string> expectPtr_;

View File

@ -316,6 +316,14 @@ class DROGON_EXPORT HttpResponseImpl : public HttpResponse
{
return sendfileRange_;
}
const trantor::CertificatePtr &peerCertificate() const override
{
return peerCertificate_;
}
void setPeerCertificate(const trantor::CertificatePtr &cert)
{
peerCertificate_ = cert;
}
void setSendfile(const std::string &filename)
{
sendfileName_ = filename;
@ -472,6 +480,7 @@ class DROGON_EXPORT HttpResponseImpl : public HttpResponse
mutable std::shared_ptr<Json::Value> jsonPtr_;
std::shared_ptr<trantor::MsgBuffer> fullHeaderString_;
trantor::CertificatePtr peerCertificate_;
mutable std::shared_ptr<trantor::MsgBuffer> httpString_;
mutable size_t datePos_{static_cast<size_t>(-1)};
mutable int64_t httpStringDate_{-1};

View File

@ -179,6 +179,7 @@ void HttpServer::onMessage(const TcpConnectionPtr &conn, MsgBuffer *buf)
req->setLocalAddr(conn->localAddr());
req->setCreationDate(trantor::Date::date());
req->setSecure(conn->isSSLConnection());
req->setPeerCertificate(conn->peerCertificate());
if (requestParser->firstReq() && isWebSocket(req))
{
auto wsConn = std::make_shared<WebSocketConnectionImpl>(conn);
@ -505,29 +506,29 @@ static std::size_t chunkingCallback(
// Alternative code if there are client softwares that do not support chunk
// size with leading zeroes
// auto nHeaderLen =
//#ifdef _WIN32
// #ifdef _WIN32
// sprintf_s(pBuffer,
// nHeaderSize, "%llx\r",
// nDataSize);
//#else
// #else
// sprintf(pBuffer, "%lx\r",
// nDataSize);
//#endif
// #endif
// pBuffer[nHeaderLen++] = '\n';
// if (nHeaderLen < nHeaderSize) // smaller that what was reserved ->
// move data
//#ifdef _WIN32
// #ifdef _WIN32
// memmove_s(pBuffer +
// nHeaderLen,
// nSize - nHeaderLen,
// pBuffer +
// nHeaderSize,
// nDataSize + 2);
//#else
// #else
// memmove(pBuffer + nHeaderLen,
// pBuffer + nHeaderSize,
// nDataSize + 2);
//#endif
// #endif
// return nHeaderLen + nDataSize + 2;
}

View File

@ -85,13 +85,21 @@ class HttpServer : trantor::NonCopyable
void start();
void stop();
void enableSSL(
[[deprecated("Use enableSSL(SSLPolicy) instead")]] void enableSSL(
const std::string &certPath,
const std::string &keyPath,
bool useOldTLS,
const std::vector<std::pair<std::string, std::string>> &sslConfCmds)
{
server_.enableSSL(certPath, keyPath, useOldTLS, sslConfCmds);
auto policy =
trantor::TLSPolicy::defaultServerPolicy(certPath, keyPath);
policy->setConfCmds(sslConfCmds).setUseOldTLS(useOldTLS);
server_.enableSSL(std::move(policy));
}
void enableSSL(trantor::TLSPolicyPtr policy)
{
server_.enableSSL(std::move(policy));
}
const trantor::InetAddress &address() const

View File

@ -58,12 +58,8 @@ void ListenerManager::addListener(
bool useOldTLS,
const std::vector<std::pair<std::string, std::string>> &sslConfCmds)
{
#ifndef OpenSSL_FOUND
if (useSSL)
{
if (useSSL && !utils::supportsTls())
LOG_ERROR << "Can't use SSL without OpenSSL found in your system";
}
#endif
listeners_.emplace_back(
ip, port, useSSL, certFile, keyFile, useOldTLS, sslConfCmds);
}
@ -83,15 +79,9 @@ void ListenerManager::createListeners(
const WebSocketNewAsyncCallback &webSocketCallback,
const ConnectionCallback &connectionCallback,
size_t connectionTimeout,
#ifdef OpenSSL_FOUND
const std::string &globalCertFile,
const std::string &globalKeyFile,
const std::vector<std::pair<std::string, std::string>> &sslConfCmds,
#else
const std::string & /*globalCertFile*/,
const std::string & /*globalKeyFile*/,
const std::vector<std::pair<std::string, std::string>> & /*sslConfCmds*/,
#endif
const std::vector<trantor::EventLoop *> &ioLoops,
const std::vector<std::function<HttpResponsePtr(const HttpRequestPtr &)>>
&syncAdvices,
@ -132,9 +122,8 @@ void ListenerManager::createListeners(
syncAdvices,
preSendingAdvices);
if (listener.useSSL_)
if (listener.useSSL_ && utils::supportsTls())
{
#ifdef OpenSSL_FOUND
auto cert = listener.certFile_;
auto key = listener.keyFile_;
if (cert.empty())
@ -152,8 +141,10 @@ void ListenerManager::createListeners(
std::copy(listener.sslConfCmds_.begin(),
listener.sslConfCmds_.end(),
std::back_inserter(cmds));
serverPtr->enableSSL(cert, key, listener.useOldTLS_, cmds);
#endif
auto policy =
trantor::TLSPolicy::defaultServerPolicy(cert, key);
policy->setConfCmds(cmds).setUseOldTLS(listener.useOldTLS_);
serverPtr->enableSSL(std::move(policy));
}
serverPtr->setHttpAsyncCallback(httpCallback);
serverPtr->setNewWebsocketCallback(webSocketCallback);
@ -179,9 +170,8 @@ void ListenerManager::createListeners(
"drogon",
syncAdvices,
preSendingAdvices);
if (listener.useSSL_)
if (listener.useSSL_ && utils::supportsTls())
{
#ifdef OpenSSL_FOUND
auto cert = listener.certFile_;
auto key = listener.keyFile_;
if (cert.empty())
@ -196,11 +186,10 @@ void ListenerManager::createListeners(
exit(1);
}
auto cmds = sslConfCmds;
std::copy(listener.sslConfCmds_.begin(),
listener.sslConfCmds_.end(),
std::back_inserter(cmds));
serverPtr->enableSSL(cert, key, listener.useOldTLS_, cmds);
#endif
auto policy =
trantor::TLSPolicy::defaultServerPolicy(cert, key);
policy->setConfCmds(cmds).setUseOldTLS(listener.useOldTLS_);
serverPtr->enableSSL(std::move(policy));
}
serverPtr->setIoLoops(ioLoops);
serverPtr->setHttpAsyncCallback(httpCallback);

View File

@ -15,13 +15,8 @@
#include <drogon/utils/Utilities.h>
#include "filesystem.h"
#include <trantor/utils/Logger.h>
#include <trantor/utils/Utilities.h>
#include <drogon/config.h>
#ifdef OpenSSL_FOUND
#include <openssl/md5.h>
#include <openssl/rand.h>
#else
#include "ssl_funcs/Md5.h"
#endif
#ifdef USE_BROTLI
#include <brotli/decode.h>
#include <brotli/encode.h>
@ -30,26 +25,23 @@
#include <Rpc.h>
#include <direct.h>
#include <io.h>
#include <ntsecapi.h>
#else
#include <uuid.h>
#include <unistd.h>
#endif
#include <zlib.h>
#include <iomanip>
#include <mutex>
#include <sstream>
#include <stack>
#include <string>
#include <thread>
#include <mutex>
#include <algorithm>
#include <array>
#include <locale>
#include <clocale>
#include <cctype>
#include <cstdlib>
#include <stdio.h>
#include <string.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <stdarg.h>
#ifdef _WIN32
@ -1144,27 +1136,27 @@ std::string brotliDecompress(const char * /*data*/, const size_t /*ndata*/)
std::string getMd5(const char *data, const size_t dataLen)
{
#if defined(OpenSSL_FOUND) && OPENSSL_VERSION_MAJOR < 3
MD5_CTX c;
unsigned char md5[16] = {0};
MD5_Init(&c);
MD5_Update(&c, data, dataLen);
MD5_Final(md5, &c);
return utils::binaryStringToHex(md5, 16);
#elif defined(OpenSSL_FOUND)
unsigned char md5[16] = {0};
const EVP_MD *md = EVP_get_digestbyname("md5");
assert(md != nullptr);
return trantor::utils::toHexString(trantor::utils::md5(data, dataLen));
}
EVP_MD_CTX *mdctx = EVP_MD_CTX_new();
EVP_DigestInit_ex2(mdctx, md, NULL);
EVP_DigestUpdate(mdctx, data, dataLen);
EVP_DigestFinal_ex(mdctx, md5, NULL);
EVP_MD_CTX_free(mdctx);
return utils::binaryStringToHex(md5, 16);
#else
return Md5Encode::encode(data, dataLen);
#endif
std::string getSha1(const char *data, const size_t dataLen)
{
return trantor::utils::toHexString(trantor::utils::sha1(data, dataLen));
}
std::string getSha256(const char *data, const size_t dataLen)
{
return trantor::utils::toHexString(trantor::utils::sha256(data, dataLen));
}
std::string getSha3(const char *data, const size_t dataLen)
{
return trantor::utils::toHexString(trantor::utils::sha3(data, dataLen));
}
std::string getBlake2b(const char *data, const size_t dataLen)
{
return trantor::utils::toHexString(trantor::utils::blake2b(data, dataLen));
}
void replaceAll(std::string &s, const std::string &from, const std::string &to)
@ -1177,48 +1169,50 @@ void replaceAll(std::string &s, const std::string &from, const std::string &to)
}
}
/**
* @brief Generates `size` random bytes from the systems random source and
* stores them into `ptr`.
*/
static bool systemRandomBytes(void *ptr, size_t size)
bool supportsTls() noexcept
{
#if defined(__BSD__) || defined(__APPLE__)
arc4random_buf(ptr, size);
return true;
#elif defined(__linux__) && \
((defined(__GLIBC__) && \
(__GLIBC__ > 2 || (__GLIBC__ == 2 && __GLIBC_MINOR__ >= 25))))
return getentropy(ptr, size) != -1;
#elif defined(_WIN32) // Windows
return RtlGenRandom(ptr, (ULONG)size);
#elif defined(__unix__) || defined(__HAIKU__)
// fallback to /dev/urandom for other/old UNIX
thread_local std::unique_ptr<FILE, std::function<void(FILE *)> > fptr(
fopen("/dev/urandom", "rb"), [](FILE *ptr) {
if (ptr != nullptr)
fclose(ptr);
});
if (fptr == nullptr)
{
LOG_FATAL << "Failed to open /dev/urandom for randomness";
abort();
}
if (fread(ptr, 1, size, fptr.get()) != 0)
return true;
#endif
return false;
return trantor::utils::tlsBackend() != "None";
}
bool secureRandomBytes(void *ptr, size_t size)
{
#ifdef OpenSSL_FOUND
if (RAND_bytes((unsigned char *)ptr, (int)size) == 0)
return true;
#endif
if (systemRandomBytes(ptr, size))
return true;
return false;
return trantor::utils::secureRandomBytes(ptr, size);
}
std::string secureRandomString(size_t size)
{
if (size == 0)
return std::string();
std::string ret(size, 0);
const string_view chars =
"0123456789"
"ABCDEFGHIJKLMNOPQRSTUVWXYZ"
"abcdefghijklmnopqrstuvwxyz"
"+-";
assert(chars.size() == 64);
trantor::utils::Hash256 hash;
// batch up to 32 bytes of random data for efficiency. Calling
// secureRandomBytes can be expensive.
auto randByte = [&hash]() {
static size_t i = 0;
if (i == 0)
{
bool ok = trantor::utils::secureRandomBytes(&hash, sizeof(hash));
if (!ok)
throw std::runtime_error(
"Failed to generate random bytes for secureRandomString");
}
unsigned char *hashBytes = reinterpret_cast<unsigned char *>(&hash);
auto ret = hashBytes[i];
i = (i + 1) % sizeof(hash);
return ret;
};
for (size_t i = 0; i < size; ++i)
ret[i] = chars[randByte() % 64];
return ret;
}
namespace internal

View File

@ -22,11 +22,7 @@
#include <drogon/utils/Utilities.h>
#include <drogon/config.h>
#include <trantor/net/InetAddress.h>
#ifdef OpenSSL_FOUND
#include <openssl/sha.h>
#else
#include "ssl_funcs/Sha1.h"
#endif
#include <trantor/utils/Utilities.h>
using namespace drogon;
using namespace trantor;
@ -55,7 +51,11 @@ void WebSocketClientImpl::createTcpClient()
std::make_shared<trantor::TcpClient>(loop_, serverAddr_, "httpClient");
if (useSSL_)
{
tcpClientPtr_->enableSSL(useOldTLS_, validateCert_, domain_);
auto policy = trantor::TLSPolicy::defaultClientPolicy();
policy->setUseOldTLS(useOldTLS_)
.setValidate(validateCert_)
.setHostname(domain_);
tcpClientPtr_->enableSSL(std::move(policy));
}
auto thisPtr = shared_from_this();
std::weak_ptr<WebSocketClientImpl> weakPtr = thisPtr;
@ -130,11 +130,11 @@ void WebSocketClientImpl::connectToServerInLoop()
auto wsKey = wsKey_;
wsKey.append("258EAFA5-E914-47DA-95CA-C5AB0DC85B11");
unsigned char accKey[SHA_DIGEST_LENGTH];
SHA1(reinterpret_cast<const unsigned char *>(wsKey.c_str()),
wsKey.length(),
accKey);
wsAccept_ = utils::base64Encode(accKey, SHA_DIGEST_LENGTH);
unsigned char accKey[20];
static_assert(sizeof(accKey) == sizeof(trantor::utils::Hash160));
auto sha1 = trantor::utils::sha1(wsKey);
memcpy(accKey, &sha1, sizeof(sha1));
wsAccept_ = utils::base64Encode(accKey, 20);
upgradeRequest_->addHeader("Sec-WebSocket-Key", wsKey_);
// upgradeRequest_->addHeader("Sec-WebSocket-Version","13");

View File

@ -21,11 +21,7 @@
#include <drogon/HttpFilter.h>
#include <drogon/WebSocketController.h>
#include <drogon/config.h>
#ifdef OpenSSL_FOUND
#include <openssl/sha.h>
#else
#include "ssl_funcs/Sha1.h"
#endif
#include <trantor/utils/Utilities.h>
using namespace drogon;
void WebsocketControllersRouter::registerWebSocketController(
@ -338,11 +334,10 @@ void WebsocketControllersRouter::doControllerHandler(
const WebSocketConnectionImplPtr &wsConnPtr)
{
wsKey.append("258EAFA5-E914-47DA-95CA-C5AB0DC85B11");
unsigned char accKey[SHA_DIGEST_LENGTH];
SHA1(reinterpret_cast<const unsigned char *>(wsKey.c_str()),
wsKey.length(),
accKey);
auto base64Key = utils::base64Encode(accKey, SHA_DIGEST_LENGTH);
unsigned char accKey[20];
auto sha1 = trantor::utils::sha1(wsKey.c_str(), wsKey.length());
memcpy(accKey, &sha1, sizeof(sha1));
auto base64Key = utils::base64Encode(accKey, sizeof(accKey));
auto resp = HttpResponse::newHttpResponse();
resp->setStatusCode(k101SwitchingProtocols);
resp->addHeader("Upgrade", "websocket");

View File

@ -1,351 +0,0 @@
/**
*
* Md5.cc
* An Tao
*
* Copyright 2018, An Tao. All rights reserved.
* https://github.com/an-tao/drogon
* Use of this source code is governed by a MIT license
* that can be found in the License file.
*
* Drogon
*
*/
#include "Md5.h"
#include <math.h>
#include <string.h>
const uint32_t Md5Encode::kA = 0x67452301;
const uint32_t Md5Encode::kB = 0xefcdab89;
const uint32_t Md5Encode::kC = 0x98badcfe;
const uint32_t Md5Encode::kD = 0x10325476;
const uint64_t Md5Encode::tiNumInteger = 4294967296;
// function: CycleMoveLeft
// @param srcNum: the number to be moved left
// @param bitNumToMove: the number of bit of moving
// @return result after moving
uint32_t Md5Encode::cycleMoveLeft(uint32_t srcNum, int bitNumToMove)
{
uint32_t srcNum1 = srcNum;
uint32_t srcNum2 = srcNum;
if (0 >= bitNumToMove)
{
return srcNum;
}
return ((srcNum1 << bitNumToMove) | (srcNum2 >> (32 - bitNumToMove)));
}
// function: FillData
// @param inDataPtr: input data
// @param dataByteLen: length of input data
// @param outDataPtr: output data
// return : length of output data
uint32_t Md5Encode::fillData(const char *inDataPtr,
int dataByteLen,
char **outDataPtr)
{
int bitNum = dataByteLen * BIT_OF_BYTE;
// int grop_num = bitNum / BIT_OF_GROUP;
int modBitNum = bitNum % BIT_OF_GROUP;
int bitNeedFill = 0;
if (modBitNum >= (BIT_OF_GROUP - SRC_DATA_LEN))
{
bitNeedFill = (BIT_OF_GROUP - modBitNum);
bitNeedFill += (BIT_OF_GROUP - SRC_DATA_LEN);
}
else
{
bitNeedFill = (BIT_OF_GROUP - SRC_DATA_LEN) - modBitNum;
}
int allBit = bitNum + bitNeedFill;
if (0 < bitNeedFill)
{
*outDataPtr =
new char[allBit / BIT_OF_BYTE + SRC_DATA_LEN / BIT_OF_BYTE];
memset(*outDataPtr,
0,
allBit / BIT_OF_BYTE + SRC_DATA_LEN / BIT_OF_BYTE);
// copy data
memcpy(*outDataPtr, inDataPtr, dataByteLen);
// fill rest data
unsigned char *tmp = reinterpret_cast<unsigned char *>(*outDataPtr);
tmp += dataByteLen;
// fill 1 and 0
*tmp = 0x80;
// fill origin data len
unsigned long long *originNum =
(unsigned long long *)((*outDataPtr) + ((allBit / BIT_OF_BYTE)));
*originNum = dataByteLen * BIT_OF_BYTE;
}
return (allBit / BIT_OF_BYTE + SRC_DATA_LEN / BIT_OF_BYTE);
}
void Md5Encode::roundF(char *data512Ptr, ParamDynamic &param)
{
uint32_t *M = reinterpret_cast<uint32_t *>(data512Ptr);
int s[] = {7, 12, 17, 22};
for (int i = 0; i < 16; ++i)
{
uint64_t ti = tiNumInteger * fabs(sin(i + 1));
if (i % 4 == 0)
{
FF(param.ua_, param.ub_, param.uc_, param.ud_, M[i], s[i % 4], ti);
}
else if (i % 4 == 1)
{
FF(param.ud_, param.ua_, param.ub_, param.uc_, M[i], s[i % 4], ti);
}
else if (i % 4 == 2)
{
FF(param.uc_, param.ud_, param.ua_, param.ub_, M[i], s[i % 4], ti);
}
else if (i % 4 == 3)
{
FF(param.ub_, param.uc_, param.ud_, param.ua_, M[i], s[i % 4], ti);
}
}
}
void Md5Encode::roundG(char *data512Ptr, ParamDynamic &param)
{
uint32_t *M = reinterpret_cast<uint32_t *>(data512Ptr);
int s[] = {5, 9, 14, 20};
for (int i = 0; i < 16; ++i)
{
auto sss = sin(i + 1 + 16);
uint64_t ti = tiNumInteger * fabs(sss);
int index = (i * 5 + 1) % 16;
if (i % 4 == 0)
{
GG(param.ua_,
param.ub_,
param.uc_,
param.ud_,
M[index],
s[i % 4],
ti);
}
else if (i % 4 == 1)
{
GG(param.ud_,
param.ua_,
param.ub_,
param.uc_,
M[index],
s[i % 4],
ti);
}
else if (i % 4 == 2)
{
GG(param.uc_,
param.ud_,
param.ua_,
param.ub_,
M[index],
s[i % 4],
ti);
}
else if (i % 4 == 3)
{
GG(param.ub_,
param.uc_,
param.ud_,
param.ua_,
M[index],
s[i % 4],
ti);
}
}
}
void Md5Encode::roundH(char *data512Ptr, ParamDynamic &param)
{
uint32_t *M = reinterpret_cast<uint32_t *>(data512Ptr);
int s[] = {4, 11, 16, 23};
for (int i = 0; i < 16; ++i)
{
uint64_t ti = tiNumInteger * fabs(sin(i + 1 + 32));
int index = (i * 3 + 5) % 16;
if (i % 4 == 0)
{
HH(param.ua_,
param.ub_,
param.uc_,
param.ud_,
M[index],
s[i % 4],
ti);
}
else if (i % 4 == 1)
{
HH(param.ud_,
param.ua_,
param.ub_,
param.uc_,
M[index],
s[i % 4],
ti);
}
else if (i % 4 == 2)
{
HH(param.uc_,
param.ud_,
param.ua_,
param.ub_,
M[index],
s[i % 4],
ti);
}
else if (i % 4 == 3)
{
HH(param.ub_,
param.uc_,
param.ud_,
param.ua_,
M[index],
s[i % 4],
ti);
}
}
}
void Md5Encode::roundI(char *data512Ptr, ParamDynamic &param)
{
uint32_t *M = reinterpret_cast<uint32_t *>(data512Ptr);
int s[] = {6, 10, 15, 21};
for (int i = 0; i < 16; ++i)
{
uint64_t ti = tiNumInteger * fabs(sin(i + 1 + 48));
int index = (i * 7 + 0) % 16;
if (i % 4 == 0)
{
II(param.ua_,
param.ub_,
param.uc_,
param.ud_,
M[index],
s[i % 4],
ti);
}
else if (i % 4 == 1)
{
II(param.ud_,
param.ua_,
param.ub_,
param.uc_,
M[index],
s[i % 4],
ti);
}
else if (i % 4 == 2)
{
II(param.uc_,
param.ud_,
param.ua_,
param.ub_,
M[index],
s[i % 4],
ti);
}
else if (i % 4 == 3)
{
II(param.ub_,
param.uc_,
param.ud_,
param.ua_,
M[index],
s[i % 4],
ti);
}
}
}
void Md5Encode::rotationCalculate(char *data512Ptr, ParamDynamic &param)
{
if (nullptr == data512Ptr)
{
return;
}
roundF(data512Ptr, param);
roundG(data512Ptr, param);
roundH(data512Ptr, param);
roundI(data512Ptr, param);
param.ua_ = param.va_last_ + param.ua_;
param.ub_ = param.vb_last_ + param.ub_;
param.uc_ = param.vc_last_ + param.uc_;
param.ud_ = param.vd_last_ + param.ud_;
param.va_last_ = param.ua_;
param.vb_last_ = param.ub_;
param.vc_last_ = param.uc_;
param.vd_last_ = param.ud_;
}
// Convert to hex format string
std::string Md5Encode::getHexStr(uint32_t numStr)
{
std::string hexstr = "";
char szch[] = {'0',
'1',
'2',
'3',
'4',
'5',
'6',
'7',
'8',
'9',
'A',
'B',
'C',
'D',
'E',
'F'};
unsigned char *tmptr = (unsigned char *)&numStr;
int len = sizeof(numStr);
for (int i = 0; i < len; ++i)
{
unsigned char ch = tmptr[i] & 0xF0;
ch = ch >> 4;
hexstr.append(1, szch[ch]);
ch = tmptr[i] & 0x0F;
hexstr.append(1, szch[ch]);
}
return hexstr;
}
// function: Encode
// @param srcInfo: the string to be encoded.
// return : the string after encoding
std::string Md5Encode::encode(const char *data, const size_t dataLen)
{
ParamDynamic param;
param.ua_ = kA;
param.ub_ = kB;
param.uc_ = kC;
param.ud_ = kD;
param.va_last_ = kA;
param.vb_last_ = kB;
param.vc_last_ = kC;
param.vd_last_ = kD;
std::string result;
char *outDataPtr = nullptr;
int totalByte = fillData(data, dataLen, &outDataPtr);
for (int i = 0; i < totalByte / (BIT_OF_GROUP / BIT_OF_BYTE); ++i)
{
char *dataBitOfGroup = outDataPtr;
dataBitOfGroup += i * (BIT_OF_GROUP / BIT_OF_BYTE);
rotationCalculate(dataBitOfGroup, param);
}
delete[] outDataPtr, outDataPtr = nullptr;
result.append(getHexStr(param.ua_));
result.append(getHexStr(param.ub_));
result.append(getHexStr(param.uc_));
result.append(getHexStr(param.ud_));
return result;
}

View File

@ -1,81 +0,0 @@
/*
*******************************************************
* brief: md5 encryption
* author: Monkey.Knight
*******************************************************
*/
/**
*
* Md5.h
* An Tao
*
* Copyright 2018, An Tao. All rights reserved.
* https://github.com/an-tao/drogon
* Use of this source code is governed by a MIT license
* that can be found in the License file.
*
* Drogon
*
*/
#pragma once
#include <string>
#include <cstdint>
#define BIT_OF_BYTE 8
#define BIT_OF_GROUP 512
#define SRC_DATA_LEN 64
#define DEF_F(X, Y, Z) ((((X) & (Y)) | ((~X) & (Z))))
#define DEF_G(X, Y, Z) (((X) & (Z)) | ((Y) & (~Z)))
#define DEF_H(X, Y, Z) ((X) ^ (Y) ^ (Z))
#define DEF_I(X, Y, Z) ((Y) ^ ((X) | (~Z)))
#define FF(a, b, c, d, Mj, s, ti) \
(a = b + cycleMoveLeft((a + DEF_F(b, c, d) + Mj + ti), s))
#define GG(a, b, c, d, Mj, s, ti) \
(a = b + cycleMoveLeft((a + DEF_G(b, c, d) + Mj + ti), s))
#define HH(a, b, c, d, Mj, s, ti) \
(a = b + cycleMoveLeft((a + DEF_H(b, c, d) + Mj + ti), s))
#define II(a, b, c, d, Mj, s, ti) \
(a = b + cycleMoveLeft((a + DEF_I(b, c, d) + Mj + ti), s))
class Md5Encode
{
public:
struct ParamDynamic
{
uint32_t ua_;
uint32_t ub_;
uint32_t uc_;
uint32_t ud_;
uint32_t va_last_;
uint32_t vb_last_;
uint32_t vc_last_;
uint32_t vd_last_;
};
public:
static std::string encode(const char *data, const size_t dataLen);
protected:
static uint32_t cycleMoveLeft(uint32_t srcNum, int bitNumToMove);
static void roundF(char *data512Ptr, ParamDynamic &param);
static void roundG(char *data512Ptr, ParamDynamic &param);
static void roundH(char *data512Ptr, ParamDynamic &param);
static void roundI(char *data512Ptr, ParamDynamic &param);
static void rotationCalculate(char *data512Ptr, ParamDynamic &param);
static std::string getHexStr(uint32_t numStr);
static uint32_t fillData(const char *inDataPtr,
int dataByteLen,
char **outDataPtr);
private:
static const uint32_t kA;
static const uint32_t kB;
static const uint32_t kC;
static const uint32_t kD;
static const uint64_t tiNumInteger;
};

View File

@ -1,159 +0,0 @@
/**
*
* Sha1.cc
* An Tao
*
* Copyright 2018, An Tao. All rights reserved.
* https://github.com/an-tao/drogon
* Use of this source code is governed by a MIT license
* that can be found in the License file.
*
* Drogon
*
*/
#include "Sha1.h"
#include <string.h>
static inline unsigned int fromBigEndian(unsigned int v)
{
return ((v & 0xff) << 24) | ((v & 0xff00) << 8) | ((v & 0xff0000) >> 8) |
((v & 0xff000000) >> 24);
}
static void writeBigEndian64(unsigned char *p, unsigned int v)
{
memset(p, 0, 8);
memcpy(p, &v, 4);
int i = 0;
for (i = 0; i < 4; ++i)
{
unsigned char t = p[i];
p[i] = p[7 - i];
p[7 - i] = t;
}
}
static inline unsigned int leftRoll(unsigned int v, int n)
{
return (v << n) | (v >> (32 - n));
}
unsigned char *SHA1(const unsigned char *dataIn,
size_t dataLen,
unsigned char *dataOut)
{
unsigned char *pbytes = (unsigned char *)dataIn;
unsigned int nbyte = (unsigned int)dataLen;
static unsigned int words[80];
unsigned int H[5] = {
0x67452301, 0xEFCDAB89, 0x98BADCFE, 0x10325476, 0xC3D2E1F0};
unsigned int f, k, temp, bitlen[2], word;
unsigned int i, j, index, p1, p2, maxlen;
unsigned char spec[4] = {0};
i = nbyte % 4;
p1 = nbyte - i;
spec[i] = 1 << 7;
while (i--)
{
spec[i] = pbytes[p1 + i];
}
maxlen = (nbyte + 1) % 64;
if (maxlen <= 56)
{
maxlen = (nbyte + 1) - maxlen + 64;
}
else
{
maxlen = (nbyte + 1) - maxlen + 128;
}
p2 = maxlen - 8;
writeBigEndian64((unsigned char *)bitlen, nbyte * 8);
for (j = 0; j < maxlen; j += 64)
{
unsigned int a, b, c, d, e;
a = H[0];
b = H[1];
c = H[2];
d = H[3];
e = H[4];
for (i = 0; i < 80; ++i)
{
if (i < 16)
{
index = j + (i << 2);
if (index < p1)
{
word = *((unsigned int *)(pbytes + index));
}
else if (index == p1)
{
word = *(unsigned int *)spec;
}
else if (index < p2)
{
word = 0;
}
else
{
word = (index < maxlen - 4) ? bitlen[0] : bitlen[1];
}
words[i] = fromBigEndian(word);
}
else
{
words[i] = leftRoll(words[i - 3] ^ words[i - 8] ^
words[i - 14] ^ words[i - 16],
1);
}
if (i < 20)
{
f = (b & c) | ((~b) & d);
k = 0x5A827999;
}
else if (i < 40)
{
f = b ^ c ^ d;
k = 0x6ED9EBA1;
}
else if (i < 60)
{
f = (b & c) | (b & d) | (c & d);
k = 0x8F1BBCDC;
}
else
{
f = b ^ c ^ d;
k = 0xCA62C1D6;
}
temp = leftRoll(a, 5) + f + e + k + words[i];
e = d;
d = c;
c = leftRoll(b, 30);
b = a;
a = temp;
}
H[0] += a;
H[1] += b;
H[2] += c;
H[3] += d;
H[4] += e;
}
int ct = 0;
for (i = 0; i < 5; ++i)
{
unsigned char buf[4] = {0};
memcpy(buf, &(H[i]), 4);
for (int r = 3; r >= 0; r--)
{
dataOut[ct] = buf[r];
++ct;
}
}
return dataOut;
}

View File

@ -1,23 +0,0 @@
/**
*
* Sha1.h
* An Tao
*
* Copyright 2018, An Tao. All rights reserved.
* https://github.com/an-tao/drogon
* Use of this source code is governed by a MIT license
* that can be found in the License file.
*
* Drogon
*
*/
#pragma once
#include <iostream>
#define SHA_DIGEST_LENGTH 20
unsigned char *SHA1(const unsigned char *dataIn,
size_t dataLen,
unsigned char *dataOut);

View File

@ -17,7 +17,6 @@ set(UNITTEST_SOURCES
unittests/OStringStreamTest.cc
unittests/PubSubServiceUnittest.cc
unittests/Sha1Test.cc
../src/ssl_funcs/Sha1.cc
unittests/FileTypeTest.cc
unittests/DrObjectTest.cc
unittests/HttpFullDateTest.cc
@ -99,7 +98,8 @@ if (BUILD_CTL)
${CMAKE_CURRENT_SOURCE_DIR}/integration_test/server/test.md
${CMAKE_CURRENT_SOURCE_DIR}/integration_test/server/index.html.gz
${CMAKE_CURRENT_SOURCE_DIR}/integration_test/server/.txt
${PROJECT_SOURCE_DIR}/trantor/trantor/tests/server.pem
${PROJECT_SOURCE_DIR}/trantor/trantor/tests/server.crt
${PROJECT_SOURCE_DIR}/trantor/trantor/tests/server.key
$<TARGET_FILE_DIR:integration_test_server>)
add_custom_command(
TARGET integration_test_server POST_BUILD

View File

@ -49,9 +49,10 @@ void doTest(const HttpClientPtr &client, std::shared_ptr<test::Case> TEST_CTX)
req->setMethod(drogon::Get);
req->setPath("/");
std::promise<int> waitCookie;
bool haveCert = false;
auto f = waitCookie.get_future();
client->sendRequest(req,
[client, &waitCookie, TEST_CTX](
[client, &waitCookie, &haveCert, TEST_CTX](
ReqResult result, const HttpResponsePtr &resp) {
REQUIRE(result == ReqResult::Ok);
@ -61,8 +62,11 @@ void doTest(const HttpClientPtr &client, std::shared_ptr<test::Case> TEST_CTX)
sessionID = id;
client->addCookie(id);
waitCookie.set_value(1);
haveCert = resp->peerCertificate() != nullptr;
});
f.get();
CHECK(haveCert == client->secure());
}
else
client->addCookie(sessionID);
@ -1067,7 +1071,7 @@ void doTest(const HttpClientPtr &client, std::shared_ptr<test::Case> TEST_CTX)
}
catch (const std::exception &e)
{
FAIL("Unexpected exception, what()" + std::string(e.what()));
FAIL("Unexpected exception, what(): " + std::string(e.what()));
}
// Test Coroutine exception
@ -1080,7 +1084,7 @@ void doTest(const HttpClientPtr &client, std::shared_ptr<test::Case> TEST_CTX)
}
catch (const std::exception &e)
{
FAIL("Unexpected exception, what()" + std::string(e.what()));
FAIL("Unexpected exception, what(): " + std::string(e.what()));
}
// Test Coroutine exception with co_return
@ -1093,7 +1097,7 @@ void doTest(const HttpClientPtr &client, std::shared_ptr<test::Case> TEST_CTX)
}
catch (const std::exception &e)
{
FAIL("Unexpected exception, what()" + std::string(e.what()));
FAIL("Unexpected exception, what(): " + std::string(e.what()));
}
// Test coroutine filter
@ -1110,7 +1114,7 @@ void doTest(const HttpClientPtr &client, std::shared_ptr<test::Case> TEST_CTX)
}
catch (const std::exception &e)
{
FAIL("Unexpected exception, what()" + std::string(e.what()));
FAIL("Unexpected exception, what(): " + std::string(e.what()));
}
// Test coroutine handler with parameters
@ -1124,7 +1128,7 @@ void doTest(const HttpClientPtr &client, std::shared_ptr<test::Case> TEST_CTX)
}
catch (const std::exception &e)
{
FAIL("Unexpected exception, what()" + std::string(e.what()));
FAIL("Unexpected exception, what(): " + std::string(e.what()));
}
try
{
@ -1136,7 +1140,7 @@ void doTest(const HttpClientPtr &client, std::shared_ptr<test::Case> TEST_CTX)
}
catch (const std::exception &e)
{
FAIL("Unexpected exception, what()" + std::string(e.what()));
FAIL("Unexpected exception, what(): " + std::string(e.what()));
}
});
#endif

View File

@ -158,7 +158,7 @@ int main()
if (app().supportSSL())
{
drogon::app()
.setSSLFiles("server.pem", "server.pem")
.setSSLFiles("server.crt", "server.key")
.addListener("0.0.0.0", 8849, true);
}
// Class function example

View File

@ -60,7 +60,7 @@ int main(int argc, char **argv)
std::thread thr([&]() {
app()
.setSSLFiles("server.pem", "server.pem")
.setSSLFiles("server.crt", "server.key")
.addListener("0.0.0.0", 8855, true)
.enableSession();
app().getLoop()->queueInLoop([&p1]() { p1.set_value(); });

View File

@ -1,17 +1,12 @@
#include "../../lib/src/ssl_funcs/Sha1.h"
#include <drogon/utils/Utilities.h>
#include <drogon/drogon_test.h>
#include <string>
DROGON_TEST(SHA1Test)
{
unsigned char in[] =
char in[] =
"1234567890123456789012345678901234567890123456789012345"
"678901234567890123456789012345678901234567890";
unsigned char out[SHA_DIGEST_LENGTH] = {0};
SHA1(in, strlen((const char *)in), out);
std::string outStr;
outStr.resize(SHA_DIGEST_LENGTH * 2);
for (int i = 0; i < SHA_DIGEST_LENGTH; ++i)
sprintf((char *)(outStr.data() + i * 2), "%02x", out[i]);
CHECK(outStr == "fecfd28bbc9345891a66d7c1b8ff46e60192d284");
auto str = drogon::utils::getSha1(in, strlen((const char *)in));
CHECK(str == "FECFD28BBC9345891A66D7C1B8FF46E60192D284");
}

@ -1 +1 @@
Subproject commit b5709ef4d43fa18b6d23090bbc54975fd1974c3d
Subproject commit 8e224d11b2bd6966e435cf5b75fe99973663cb1b