212 lines
6.5 KiB
C++
212 lines
6.5 KiB
C++
#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(<ime_cur);
|
||
// gmtime_r(<ime_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;
|
||
}
|
||
|
||
bool uns::secure::IsSafePath(const std::string & safe_path, const std::string & requested_path)
|
||
{
|
||
return PathTraversal::IsSafePath(safe_path, requested_path);
|
||
}
|