Files
DpsManagerServer/tests/crypto_smoke_test.cpp
2026-04-15 15:19:28 +08:00

163 lines
5.2 KiB
C++

#include "dps/app.hpp"
#include "dps/config.hpp"
#include <cassert>
#include <cstdio>
#include <cstdlib>
#include <filesystem>
#include <fstream>
#include <string>
#include <vector>
#include <openssl/evp.h>
#include <zlib.h>
namespace fs = std::filesystem;
namespace {
void set_env(const char *name, const char *value) {
#ifdef _WIN32
_putenv_s(name, value);
#else
setenv(name, value, 1);
#endif
}
void clear_env(const char *name) {
#ifdef _WIN32
_putenv_s(name, "");
#else
unsetenv(name);
#endif
}
std::vector<unsigned char> decode_base64(const std::string &text) {
std::string normalized = text;
while (normalized.size() % 4 != 0) normalized.push_back('=');
std::vector<unsigned char> decoded((normalized.size() / 4) * 3);
const int size = EVP_DecodeBlock(decoded.data(),
reinterpret_cast<const unsigned char *>(normalized.data()),
static_cast<int>(normalized.size()));
assert(size >= 0);
std::size_t padding = 0;
if (!normalized.empty() && normalized.back() == '=') ++padding;
if (normalized.size() > 1 && normalized[normalized.size() - 2] == '=') ++padding;
decoded.resize(static_cast<std::size_t>(size) - padding);
return decoded;
}
std::string gunzip_bytes(const std::vector<unsigned char> &compressed) {
z_stream stream{};
stream.next_in = const_cast<Bytef *>(reinterpret_cast<const Bytef *>(compressed.data()));
stream.avail_in = static_cast<uInt>(compressed.size());
const int init = inflateInit2(&stream, 15 + 16);
assert(init == Z_OK);
std::string output;
std::vector<char> buffer(4096);
int ret = Z_OK;
while (ret == Z_OK) {
stream.next_out = reinterpret_cast<Bytef *>(buffer.data());
stream.avail_out = static_cast<uInt>(buffer.size());
ret = inflate(&stream, Z_NO_FLUSH);
output.append(buffer.data(), buffer.size() - stream.avail_out);
}
inflateEnd(&stream);
assert(ret == Z_STREAM_END);
return output;
}
void test_crypto() {
dps::LegacyCrypto crypto("unit-test-secret");
const std::string password = "P@ssw0rd!";
const std::string hashed = crypto.hash_password(password);
assert(!hashed.empty());
assert(hashed.rfind("$2", 0) == 0);
assert(crypto.verify_password(password, hashed));
assert(!crypto.verify_password(password, password));
const std::string token = crypto.issue_jwt("tester", 60);
assert(!token.empty());
const auto subject = crypto.validate_jwt(token);
assert(subject.has_value());
assert(subject.value() == "tester");
assert(!crypto.validate_jwt(token + "broken").has_value());
const std::string gzip_payload = crypto.gzip_base64("{\"hello\":\"world\"}");
assert(!gzip_payload.empty());
const std::string inflated = gunzip_bytes(decode_base64(gzip_payload));
assert(inflated == "{\"hello\":\"world\"}");
const std::string rsa_tool = crypto.rsa_private_encrypt_tool("abc123");
const std::string rsa_script = crypto.rsa_private_encrypt_script("xyz789");
assert(!rsa_tool.empty());
assert(!rsa_script.empty());
assert(rsa_tool != "abc123");
assert(rsa_script != "xyz789");
}
void test_config() {
const fs::path path = fs::temp_directory_path() / "dps-config-smoke.conf";
{
std::ofstream out(path);
out << "server.host=0.0.0.0\n";
out << "server.port=8651\n";
out << "server.trust_proxy=true\n";
out << "server.proxy_header=x-real-ip\n";
out << "database.host=127.0.0.1\n";
out << "database.name=rindro\n";
out << "database.user=root\n";
out << "database.password=test\n";
out << "database.ssl_mode=verify_ca\n";
out << "database.ssl_ca=C:/certs/demo-ca.pem\n";
out << "database.plugin_dir=C:/mariadb/plugin\n";
}
set_env("DPS_SERVER_HOST", "10.0.0.8");
set_env("DPS_SERVER_PROXY_HEADER", "x-forwarded-for");
set_env("DPS_DB_HOST", "192.168.0.10");
set_env("DPS_DB_USER", "tester");
set_env("DPS_DB_PASSWORD", "secret");
set_env("DPS_DB_NAME", "demo");
set_env("DPS_DB_SSL_MODE", "disable");
set_env("DPS_DB_SSL_CA", "D:/certs/dev-ca.pem");
set_env("DPS_DB_PLUGIN_DIR", "D:/mariadb/plugin");
const dps::AppConfig config = dps::load_config(path.string());
assert(config.server.host == "10.0.0.8");
assert(config.server.port == 8651);
assert(config.server.trust_proxy);
assert(config.server.proxy_header == "x-forwarded-for");
assert(config.database.host == "192.168.0.10");
assert(config.database.user == "tester");
assert(config.database.password == "secret");
assert(config.database.name == "demo");
assert(config.database.ssl_mode == "disable");
assert(config.database.ssl_ca == "D:/certs/dev-ca.pem");
assert(config.database.plugin_dir == "D:/mariadb/plugin");
clear_env("DPS_SERVER_HOST");
clear_env("DPS_SERVER_PROXY_HEADER");
clear_env("DPS_DB_HOST");
clear_env("DPS_DB_USER");
clear_env("DPS_DB_PASSWORD");
clear_env("DPS_DB_NAME");
clear_env("DPS_DB_SSL_MODE");
clear_env("DPS_DB_SSL_CA");
clear_env("DPS_DB_PLUGIN_DIR");
std::remove(path.string().c_str());
}
} // namespace
int main() {
test_crypto();
test_config();
return 0;
}