#include "Global.h" #include #include #include #include #include #ifndef _WIN32 #include "UOHash.h" #else #include "../UOHash/UOHash.h" #endif #include #include "SafeRNG.h" #include #include #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(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& 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 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(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(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 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 inline constexpr bool always_false_v = false; template T do_sto(const std::basic_string& str, std::size_t* pos, int base) { if constexpr (std::is_same_v) return std::stoi(str, pos, base); else if constexpr (std::is_same_v) return std::stol(str, pos, base); else if constexpr (std::is_same_v) return std::stoll(str, pos, base); else if constexpr (std::is_same_v) return std::stoul(str, pos, base); else if constexpr (std::is_same_v) return std::stoull(str, pos, base); else if constexpr (std::is_same_v) return std::stof(str, pos); else if constexpr (std::is_same_v) return std::stod(str, pos); else if constexpr (std::is_same_v) return std::stold(str, pos); else static_assert(always_false_v, "不支持的转换类型!"); } } template std::optional uns::tools::SafeStoX(const std::basic_string& str, std::size_t* pos, int base) { try { return do_sto(str, pos, base); } catch (...) { return std::nullopt; } } template std::optional uns::tools::SafeStoX(std::basic_string_view str, std::size_t* pos, int base) { return SafeStoX(std::basic_string(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 UNSWSC_DLL_EXPORT SafeStoX(const std::basic_string&, std::size_t*, int); \ template std::optional UNSWSC_DLL_EXPORT SafeStoX(std::basic_string_view, 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 } }