Files
UNSWebServerCore_LinuxSO/Global.cpp
T

305 lines
9.4 KiB
C++
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
#include "Global.h"
#include <memory>
#include <format>
#include <chrono>
#include <cstring>
#include <fstream>
#ifndef _WIN32
#include "UOHash.h"
#else
#include "../UOHash/UOHash.h"
#endif
#include <sodium.h>
#include "SafeRNG.h"
#include <algorithm>
#include <openssl/evp.h>
#include "PathTraversal.h"
std::string uns::EncodeErrorPage(int code)
{
// size_t str_size = strlen(G_SERVER_NAME) + strlen(G_ERROR_PAGE);
// char* buffer = new char[str_size];
// memset(buffer, 0, str_size);
// snprintf(buffer, str_size, G_ERROR_PAGE, code, code, G_SERVER_NAME);
// std::string ret = buffer;
// delete[] buffer;
// return ret;
return std::vformat(G_ERROR_PAGE, std::make_format_args(code, code, G_SERVER_NAME));
}
std::string uns::EncodeHTTPTime(time_t* time)
{
// struct tm t;
// if (time != NULL)
// gmtime_r(time, &t);
// else
// {
// int64_t ltime_cur;
// ::time(&ltime_cur);
// gmtime_r(&ltime_cur, &t);
// }
// char szTime[100] = { 0 };
// // - Sun, 24 Aug 2008 22:43:45 GMT
// sprintf(szTime, "%s, %d %s %d %d:%d:%d GMT", G_HTTP_STD_WEEK[t.tm_wday].c_str(), t.tm_mday, G_HTTP_STD_MONTH[t.tm_mon].c_str(), t.tm_year + 1900, t.tm_hour, t.tm_min, t.tm_sec);
// return szTime;
// 1. 一行搞定时间点获取:如果指针有效就转换,否则直接取当前系统时间
auto tp = time ? std::chrono::system_clock::from_time_t(*time) : std::chrono::system_clock::now();
// 2. 强制截断到“秒”级(floor),避免有些平台输出微秒等尾巴
auto tp_secs = std::chrono::floor<std::chrono::seconds>(tp);
// 3. 直接利用 chrono 占位符格式化输出
// %a: 星期缩写(Sun), %d: 两位日子(02), %b: 月份缩写(Jun), %Y: 四位年份(2026), %T: 24小时制时间(00:00:00)
return std::format("{:%a, %d %b %Y %T} GMT", tp_secs);
}
std::string uns::btos(bool val)
{
return (val ? "true" : "false");
}
bool uns::stob(const std::string& obj)
{
return (obj == "true");
}
DateTime uns::stot(const std::string& obj)
{
int nYear, nMonth, nDate, nHour, nMin, nSec;
int cnt = sscanf(obj.c_str(), "%d-%d-%d %d:%d:%d", &nYear, &nMonth, &nDate, &nHour, &nMin, &nSec);
if (cnt != 6)
return DateTime();
else
return DateTime(nYear, nMonth, nDate, nHour, nMin, nSec);
}
std::string uns::RestoreURL(const std::string& url)
{
std::string res = url;
std::replace(res.begin(), res.end(), '{', '&');
std::replace(res.begin(), res.end(), '}', '=');
return res;
}
void uns::Stringsplit(const std::string& str, const std::string& splits, std::vector<std::string>& res)
{
if (str == "")
return;
std::string strs = str + splits;
size_t pos = strs.find(splits);
size_t step = splits.size();
while (pos != strs.npos)
{
std::string temp = strs.substr(0, pos);
res.push_back(temp);
strs = strs.substr(pos + step, strs.size());
pos = strs.find(splits);
}
}
void uns::ProcessPOSTArgs(const std::string& args, POSTArgs& args_output)
{
args_output.clear();
std::vector<std::string> c1_split, c2_split;
Stringsplit(args, "&", c1_split);
for (const auto& kv : c1_split)
{
c2_split.clear();
c2_split.shrink_to_fit();
Stringsplit(kv, "=", c2_split);
if (c2_split.size() != 2)
continue;
if (c2_split[0] == "origin_url")
args_output.insert({ c2_split[0], RestoreURL(c2_split[1]) });
else
args_output.insert({ c2_split[0], c2_split[1] });
}
}
std::string uns::tools::EncryptPassword(const std::string reg_date, const std::string& password)
{
std::string res_reg_date = reg_date;
std::reverse(res_reg_date.begin(), res_reg_date.end());
std::string war_pwd = reg_date + password + res_reg_date;
auto res = uns::UOHash::HashString(uns::HashID::SHA3_512, war_pwd);
if (!res)
return "";
return res.GetResult();
}
std::string uns::tools::EncryptPasswordSodium(const std::string& pwd)
{
// ======== 参数(128MB 内存) ========
static const size_t MEMLIMIT = 128UL * 1024 * 1024; // 128 MB
static const uint64_t OPSLIMIT = crypto_pwhash_OPSLIMIT_MODERATE;
// =====================================
// 输出缓冲:libsodium 定义的固定大小
char out_str[crypto_pwhash_STRBYTES] = { 0 };
// 生成编码字符串(包含算法、参数、盐、hash),直接存 DB(TEXT)
if (crypto_pwhash_str(out_str, pwd.c_str(), pwd.size(), OPSLIMIT, MEMLIMIT) != 0)
return "";
else
return std::string(out_str);
}
bool uns::tools::CheckPasswordSodium(const std::string& pwd, const std::string& encrypted)
{
return (crypto_pwhash_str_verify(encrypted.c_str(), pwd.c_str(), pwd.length()) == 0);
}
std::string uns::tools::SecureRandomHex(size_t bytes)
{
return RandomNumberGenerator::SecureRandomHex(bytes);
}
std::string uns::tools::ToUpper(const std::string& s)
{
std::string r; r.reserve(s.size());
for (unsigned char c : s)
r.push_back(static_cast<char>(std::toupper(c)));
return r;
}
std::string uns::tools::ToLower(const std::string& s)
{
std::string r; r.reserve(s.size());
for (unsigned char c : s)
r.push_back(static_cast<char>(std::tolower(c)));
return r;
}
std::string uns::tools::CalculateFileHashSHA256(const std::string& file)
{
// 1. 以二进制模式打开文件
std::ifstream ifs(file, std::ios::binary);
if (!ifs.is_open()) // 文件打开失败,返回空字符串(也可以根据你的项目规范记录日志或抛出异常)
return std::string();
// 2. 初始化 OpenSSL EVP 上下文,使用智能指针自动管理内存释放
std::unique_ptr<EVP_MD_CTX, void(*)(EVP_MD_CTX*)> ctx(EVP_MD_CTX_new(), EVP_MD_CTX_free);
if (!ctx)
return std::string();
// 3. 指定使用 SHA256 算法
if (EVP_DigestInit_ex(ctx.get(), EVP_sha256(), nullptr) != 1)
return std::string();
// 4. 分块读取文件并更新哈希计算(每次读取 4096 字节,避免大文件占用过多内存)
constexpr size_t kBufferSize = 4096;
char buffer[kBufferSize];
while (ifs.read(buffer, kBufferSize) || ifs.gcount() > 0)
{
if (EVP_DigestUpdate(ctx.get(), buffer, ifs.gcount()) != 1)
return std::string();
}
// 5. 结束哈希计算并获取二进制结果
unsigned char hash[EVP_MAX_MD_SIZE];
unsigned int length = 0;
if (EVP_DigestFinal_ex(ctx.get(), hash, &length) != 1)
return std::string();
// 6. 将二进制哈希值转换为 16 进制字符串 (Hex String)
std::string hex_result;
hex_result.reserve(length * 2);
for (unsigned int i = 0; i < length; ++i)
{
char buf[3];
snprintf(buf, sizeof(buf), "%02x", hash[i]);
hex_result.append(buf);
}
return hex_result;
}
Json::Value uns::tools::SafeJsonDecode(const std::string& str)
{
try
{
Json::Value root;
Json::Reader reader;
if (!reader.parse(str, root, false))
return Json::nullValue;
else
return root;
}
catch (...)
{
return Json::nullValue;
}
}
namespace
{
template <typename> inline constexpr bool always_false_v = false;
template <typename T, typename CharT>
T do_sto(const std::basic_string<CharT>& str, std::size_t* pos, int base)
{
if constexpr (std::is_same_v<T, int>)
return std::stoi(str, pos, base);
else if constexpr (std::is_same_v<T, long>)
return std::stol(str, pos, base);
else if constexpr (std::is_same_v<T, long long>)
return std::stoll(str, pos, base);
else if constexpr (std::is_same_v<T, unsigned long>)
return std::stoul(str, pos, base);
else if constexpr (std::is_same_v<T, unsigned long long>)
return std::stoull(str, pos, base);
else if constexpr (std::is_same_v<T, float>)
return std::stof(str, pos);
else if constexpr (std::is_same_v<T, double>)
return std::stod(str, pos);
else if constexpr (std::is_same_v<T, long double>)
return std::stold(str, pos);
else
static_assert(always_false_v<T>, "不支持的转换类型!");
}
}
template <typename T, typename CharT>
std::optional<T> uns::tools::SafeStoX(const std::basic_string<CharT>& str, std::size_t* pos, int base)
{
try
{
return do_sto<T>(str, pos, base);
}
catch (...)
{
return std::nullopt;
}
}
template <typename T, typename CharT>
std::optional<T> uns::tools::SafeStoX(std::basic_string_view<CharT> str, std::size_t* pos, int base)
{
return SafeStoX<T>(std::basic_string<CharT>(str), pos, base);
}
bool uns::secure::IsSafePath(const std::string& safe_path, const std::string& requested_path)
{
return PathTraversal::IsSafePath(safe_path, requested_path);
}
namespace uns
{
namespace tools
{
// -------------------------------------------------------------
// 显式模板实例化(注意:必须放在命名空间内部!)
// -------------------------------------------------------------
#define INSTANTIATE_SAFE_STO(T, CharT) \
template std::optional<T> UNSWSC_DLL_EXPORT SafeStoX<T, CharT>(const std::basic_string<CharT>&, std::size_t*, int); \
template std::optional<T> UNSWSC_DLL_EXPORT SafeStoX<T, CharT>(std::basic_string_view<CharT>, std::size_t*, int);
#define INSTANTIATE_ALL_NUMERIC_TYPES(CharT) \
INSTANTIATE_SAFE_STO(int, CharT) \
INSTANTIATE_SAFE_STO(long, CharT) \
INSTANTIATE_SAFE_STO(long long, CharT) \
INSTANTIATE_SAFE_STO(unsigned long, CharT) \
INSTANTIATE_SAFE_STO(unsigned long long, CharT) \
INSTANTIATE_SAFE_STO(float, CharT) \
INSTANTIATE_SAFE_STO(double, CharT) \
INSTANTIATE_SAFE_STO(long double, CharT)
INSTANTIATE_ALL_NUMERIC_TYPES(char)
INSTANTIATE_ALL_NUMERIC_TYPES(wchar_t)
#undef INSTANTIATE_ALL_NUMERIC_TYPES
#undef INSTANTIATE_SAFE_STO
}
}