refactor(fsys): 移除遗留死接口与快捷登录入口
删除无调用方的 /api/check_user(Users 无 email 列,生产恒 500)与 /api/hash(前端早改直传密码给 ca,无鉴权 SHA-256 端点徒增哈希预言机 风险),连带清理 _rpc/_call_db/FsysExp/sha256_hex/限速设施等失去唯一 使用方的死代码;login.html 移除 yhdet 快捷登录按钮及"或"分隔线 (fsys 无 /yhdet_callback,入口本就失效)。同步两处 README。
This commit is contained in:
1 parent
9b6aa39b94
commit
175fa5d244
4 files changed
+2
-238
No files matched your search
@@ -122,7 +122,7 @@
|
|||||||
- 支持文件浏览、视频/音频在线播放(HTTP Range 分段请求,返回 206/416)、一键下载。
|
- 支持文件浏览、视频/音频在线播放(HTTP Range 分段请求,返回 206/416)、一键下载。
|
||||||
- 路径遍历防护(realpath 前缀校验),仅允许访问 `--root` 之内。
|
- 路径遍历防护(realpath 前缀校验),仅允许访问 `--root` 之内。
|
||||||
- **dnfs2 代理**:`/get_notes`、`/add_note`、`/delete_note`、`/update_note` 透传 Authorization 转发到 `dnfs2:8006`(解决浏览器跨域)。
|
- **dnfs2 代理**:`/get_notes`、`/add_note`、`/delete_note`、`/update_note` 透传 Authorization 转发到 `dnfs2:8006`(解决浏览器跨域)。
|
||||||
- **账号旁路**:`/api/check_user`、`/api/reset_password` 等接口直接读写 `gateway/sqlite3.db` 的 Users 表;`/yhdet_callback`、`/api/yhdet_*` 对接 yhdet.top OAuth 登录。
|
- **账号旁路已收口**:原 static 时代的 `/api/check_user`、`/api/reset_password`、yhdet OAuth 等旁路接口已移除/迁至 ca(忘记密码走 ca `/reset/send_code` + `/reset_password`),fsys 不再直接读写用户表。
|
||||||
- 统一品牌"树状菜单",支持深色模式(`css/theme.css`)与样式节点注入的自定义主题/样式(见 [docs/dnfs_custom_themes.md](docs/dnfs_custom_themes.md))。
|
- 统一品牌"树状菜单",支持深色模式(`css/theme.css`)与样式节点注入的自定义主题/样式(见 [docs/dnfs_custom_themes.md](docs/dnfs_custom_themes.md))。
|
||||||
- 配置全部经 CLI 传递(CLI > 环境变量 > 默认值,原 `confs/configs/static.ini` 迁入 `core/services.yaml` 的 fsys 条目 args),不依赖 confs。
|
- 配置全部经 CLI 传递(CLI > 环境变量 > 默认值,原 `confs/configs/static.ini` 迁入 `core/services.yaml` 的 fsys 条目 args),不依赖 confs。
|
||||||
|
|
||||||
|
|||||||
+1
-3
@@ -20,7 +20,7 @@ fsys :9200 (libhttp 异步多线程 + CORS)
|
|||||||
│
|
│
|
||||||
├── public/ 静态文件根目录
|
├── public/ 静态文件根目录
|
||||||
├── dnfs2 :8006 笔记代理(反向代理)
|
├── dnfs2 :8006 笔记代理(反向代理)
|
||||||
├── db2 :8005 用户查询 + 日志写入
|
├── db2 :8005 日志写入
|
||||||
└── (配置纯 CLI 传递,不依赖 confs)
|
└── (配置纯 CLI 传递,不依赖 confs)
|
||||||
```
|
```
|
||||||
|
|
||||||
@@ -40,8 +40,6 @@ fsys :9200 (libhttp 异步多线程 + CORS)
|
|||||||
|
|
||||||
| 路径 | 说明 |
|
| 路径 | 说明 |
|
||||||
|------|------|
|
|------|------|
|
||||||
| `POST /api/hash` | SHA-256 密码哈希(限速 20/min/IP) |
|
|
||||||
| `POST /api/check_user` | 检查用户是否已注册(限速 10/min/IP) |
|
|
||||||
| `GET /api/favicon?url=` | favicon SSRF 防护代理(512KB 上限,仅浏览器侧 Cache-Control 缓存 1 天,无服务端缓存) |
|
| `GET /api/favicon?url=` | favicon SSRF 防护代理(512KB 上限,仅浏览器侧 Cache-Control 缓存 1 天,无服务端缓存) |
|
||||||
|
|
||||||
### dnfs2 代理路由
|
### dnfs2 代理路由
|
||||||
|
|||||||
@@ -37,9 +37,6 @@
|
|||||||
</div>
|
</div>
|
||||||
</form>
|
</form>
|
||||||
<a href="forgot.html" style="display:block;text-align:center;color:#999;font-size:13px;margin:8px 0">忘记密码?</a>
|
<a href="forgot.html" style="display:block;text-align:center;color:#999;font-size:13px;margin:8px 0">忘记密码?</a>
|
||||||
<div style="text-align:center;margin:12px 0;position:relative"><div style="position:absolute;top:50%;left:0;right:0;height:1px;background:#e0d6cc"></div><span style="background:#fff;padding:0 12px;position:relative;color:#999;font-size:13px">或</span></div>
|
|
||||||
<a href="https://yhdet.top/yhdet_auth?callback=https://qsont.me/yhdet_callback" class="yhdet-login-btn">开源社区 快捷登录</a>
|
|
||||||
<style>.yhdet-login-btn{display:block;width:100%;padding:12px;border:1.5px solid #1a73e8;border-radius:8px;background:white;color:#1a73e8;font-size:15px;font-weight:600;text-decoration:none;text-align:center;box-sizing:border-box;margin-bottom:12px}.yhdet-login-btn:hover{background:#e8f0fe}</style>
|
|
||||||
|
|
||||||
<!-- 用户使用条例弹窗 -->
|
<!-- 用户使用条例弹窗 -->
|
||||||
<div id="licenseModal" class="license-modal-overlay" style="display:none">
|
<div id="licenseModal" class="license-modal-overlay" style="display:none">
|
||||||
|
|||||||
@@ -5,8 +5,6 @@
|
|||||||
* GET /<path> 静态文件 / 目录浏览
|
* GET /<path> 静态文件 / 目录浏览
|
||||||
* GET /api/filelist?path= 文件列表 JSON
|
* GET /api/filelist?path= 文件列表 JSON
|
||||||
* GET /video/... 视频/音频流媒体(HTTP Range 206)
|
* GET /video/... 视频/音频流媒体(HTTP Range 206)
|
||||||
* POST /api/hash SHA-256 密码哈希(限速 20/min/IP)
|
|
||||||
* POST /api/check_user 用户存在性检查(限速 10/min/IP)
|
|
||||||
* GET /api/favicon?url= favicon SSRF 防护代理
|
* GET /api/favicon?url= favicon SSRF 防护代理
|
||||||
* POST /get_notes 等 4 个 dnfs2 反向代理
|
* POST /get_notes 等 4 个 dnfs2 反向代理
|
||||||
* GET /health 健康检查
|
* GET /health 健康检查
|
||||||
@@ -32,7 +30,6 @@
|
|||||||
#include <boost/json.hpp>
|
#include <boost/json.hpp>
|
||||||
#include <boost/program_options.hpp>
|
#include <boost/program_options.hpp>
|
||||||
#include <curl/curl.h>
|
#include <curl/curl.h>
|
||||||
#include <openssl/evp.h>
|
|
||||||
|
|
||||||
#include <algorithm>
|
#include <algorithm>
|
||||||
#include <atomic>
|
#include <atomic>
|
||||||
@@ -94,12 +91,6 @@ static constexpr size_t kHttpMaxResponse = 10 * 1024 * 1024;
|
|||||||
// 单次文件响应大小上限(string_body 全量读入内存,防大文件 DoS;审计 F-4)
|
// 单次文件响应大小上限(string_body 全量读入内存,防大文件 DoS;审计 F-4)
|
||||||
static constexpr uintmax_t kMaxServeFileSize = 50 * 1024 * 1024;
|
static constexpr uintmax_t kMaxServeFileSize = 50 * 1024 * 1024;
|
||||||
|
|
||||||
// 限速
|
|
||||||
static constexpr int kHashRateLimit = 20;
|
|
||||||
static constexpr int kCheckUserRateLimit = 10;
|
|
||||||
static constexpr int kRateWindowSeconds = 60;
|
|
||||||
static constexpr size_t kRateMaxKeys = 65536; // 限速键数上限,防伪造 XFF 旋转导致内存增长
|
|
||||||
|
|
||||||
// 视图文件名
|
// 视图文件名
|
||||||
static const std::string kViewFile = "__view.html";
|
static const std::string kViewFile = "__view.html";
|
||||||
|
|
||||||
@@ -134,30 +125,6 @@ static int safe_stoi(const std::string& s, const char* field_name) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static std::string sha256_hex(const std::string& input) {
|
|
||||||
EVP_MD* md = EVP_MD_fetch(nullptr, "SHA2-256", nullptr);
|
|
||||||
const bool fetched = (md != nullptr);
|
|
||||||
if (!md) {
|
|
||||||
// OpenSSL < 3.0 回退
|
|
||||||
md = const_cast<EVP_MD*>(EVP_sha256());
|
|
||||||
}
|
|
||||||
unsigned char hash[EVP_MAX_MD_SIZE];
|
|
||||||
unsigned int hash_len = 0;
|
|
||||||
EVP_Digest(input.data(), input.size(), hash, &hash_len, md, nullptr);
|
|
||||||
// EVP_MD_fetch 返回的无论 digest 成败都需释放,EVP_sha256 返回的不需要
|
|
||||||
if (fetched) {
|
|
||||||
EVP_MD_free(md);
|
|
||||||
}
|
|
||||||
static const char hex_chars[] = "0123456789abcdef";
|
|
||||||
std::string result;
|
|
||||||
result.reserve(hash_len * 2);
|
|
||||||
for (unsigned int i = 0; i < hash_len; ++i) {
|
|
||||||
result += hex_chars[hash[i] >> 4];
|
|
||||||
result += hex_chars[hash[i] & 0x0f];
|
|
||||||
}
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
|
|
||||||
static std::string format_file_size(uintmax_t size) {
|
static std::string format_file_size(uintmax_t size) {
|
||||||
double s = static_cast<double>(size);
|
double s = static_cast<double>(size);
|
||||||
const char* units[] = {"B", "KB", "MB", "GB", "TB"};
|
const char* units[] = {"B", "KB", "MB", "GB", "TB"};
|
||||||
@@ -341,19 +308,6 @@ static Config load_config(int argc, char* argv[]) {
|
|||||||
return cfg;
|
return cfg;
|
||||||
}
|
}
|
||||||
|
|
||||||
// ============================================================================
|
|
||||||
// 异常类
|
|
||||||
// ============================================================================
|
|
||||||
|
|
||||||
class FsysExp : public std::runtime_error {
|
|
||||||
public:
|
|
||||||
FsysExp(const std::string& msg, int code)
|
|
||||||
: std::runtime_error(msg), status_(code) {}
|
|
||||||
int status() const noexcept { return status_; }
|
|
||||||
private:
|
|
||||||
int status_;
|
|
||||||
};
|
|
||||||
|
|
||||||
// ============================================================================
|
// ============================================================================
|
||||||
// MIME 类型映射
|
// MIME 类型映射
|
||||||
// ============================================================================
|
// ============================================================================
|
||||||
@@ -582,8 +536,6 @@ class FsysServer {
|
|||||||
public:
|
public:
|
||||||
explicit FsysServer(Config cfg)
|
explicit FsysServer(Config cfg)
|
||||||
: _cfg(std::move(cfg)),
|
: _cfg(std::move(cfg)),
|
||||||
_rpc(_cfg.db_host, _cfg.db_port, "fsys", 5.0,
|
|
||||||
/*retry_on_refused=*/true),
|
|
||||||
_log_rpc(_cfg.db_host, _cfg.db_port, "fsys-log", kLogRpcTimeout,
|
_log_rpc(_cfg.db_host, _cfg.db_port, "fsys-log", kLogRpcTimeout,
|
||||||
/*retry_on_refused=*/false)
|
/*retry_on_refused=*/false)
|
||||||
{
|
{
|
||||||
@@ -618,7 +570,6 @@ public:
|
|||||||
|
|
||||||
private:
|
private:
|
||||||
Config _cfg;
|
Config _cfg;
|
||||||
RpcClient _rpc; // db RPC(retry_on_refused=true)
|
|
||||||
RpcClient _log_rpc; // 日志写入
|
RpcClient _log_rpc; // 日志写入
|
||||||
|
|
||||||
std::unique_ptr<AsyncQueue<LogEntry>> _log_queue;
|
std::unique_ptr<AsyncQueue<LogEntry>> _log_queue;
|
||||||
@@ -627,10 +578,6 @@ private:
|
|||||||
HttpServer* _server = nullptr;
|
HttpServer* _server = nullptr;
|
||||||
static std::atomic<bool> _should_stop;
|
static std::atomic<bool> _should_stop;
|
||||||
|
|
||||||
// 限速存储
|
|
||||||
std::mutex _rate_mutex;
|
|
||||||
std::unordered_map<std::string, std::vector<std::chrono::steady_clock::time_point>> _rate_store;
|
|
||||||
|
|
||||||
static void _signal_handler(int) { _should_stop.store(true); }
|
static void _signal_handler(int) { _should_stop.store(true); }
|
||||||
|
|
||||||
// ---- 日志 --------------------------------------------------------------
|
// ---- 日志 --------------------------------------------------------------
|
||||||
@@ -671,68 +618,6 @@ private:
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// ---- db 调用 -----------------------------------------------------------
|
|
||||||
|
|
||||||
struct DbResult {
|
|
||||||
bool success = false;
|
|
||||||
json::value data;
|
|
||||||
std::string error;
|
|
||||||
};
|
|
||||||
|
|
||||||
DbResult _call_db(const json::object& payload) {
|
|
||||||
try {
|
|
||||||
json::value data = _rpc.call("execute", payload);
|
|
||||||
return {true, data, ""};
|
|
||||||
} catch (const RpcError& e) {
|
|
||||||
return {false, nullptr, e.what()};
|
|
||||||
} catch (const std::exception& e) {
|
|
||||||
_log("ERROR", "fsys", std::string("db 调用失败: ") + e.what());
|
|
||||||
throw FsysExp("数据库服务暂时不可用", 502);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// ---- 客户端 IP ---------------------------------------------------------
|
|
||||||
|
|
||||||
static std::string client_ip(const http::request<http::string_body>& req) {
|
|
||||||
auto xff = req.find("X-Forwarded-For");
|
|
||||||
if (xff != req.end()) {
|
|
||||||
std::string val(xff->value());
|
|
||||||
auto comma = val.find(',');
|
|
||||||
std::string ip = (comma == std::string::npos) ? val : val.substr(0, comma);
|
|
||||||
auto b = ip.find_first_not_of(" ");
|
|
||||||
auto e = ip.find_last_not_of(" ");
|
|
||||||
if (b != std::string::npos) return ip.substr(b, e - b + 1);
|
|
||||||
}
|
|
||||||
return "unknown";
|
|
||||||
}
|
|
||||||
|
|
||||||
// ---- 限速 --------------------------------------------------------------
|
|
||||||
|
|
||||||
bool _check_rate_limit(const std::string& key, int max_requests) {
|
|
||||||
auto now = std::chrono::steady_clock::now();
|
|
||||||
auto cutoff = now - std::chrono::seconds(kRateWindowSeconds);
|
|
||||||
std::lock_guard<std::mutex> lock(_rate_mutex);
|
|
||||||
// 键数超限:全局驱逐过期窗口(防伪造 XFF 旋转导致无限增长)
|
|
||||||
if (_rate_store.size() > kRateMaxKeys) {
|
|
||||||
for (auto it = _rate_store.begin(); it != _rate_store.end();) {
|
|
||||||
auto& ts = it->second;
|
|
||||||
ts.erase(std::remove_if(ts.begin(), ts.end(),
|
|
||||||
[&](const auto& t) { return t < cutoff; }),
|
|
||||||
ts.end());
|
|
||||||
if (ts.empty()) it = _rate_store.erase(it);
|
|
||||||
else ++it;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
auto& timestamps = _rate_store[key];
|
|
||||||
timestamps.erase(
|
|
||||||
std::remove_if(timestamps.begin(), timestamps.end(),
|
|
||||||
[&](const auto& t) { return t < cutoff; }),
|
|
||||||
timestamps.end());
|
|
||||||
if (static_cast<int>(timestamps.size()) >= max_requests) return false;
|
|
||||||
timestamps.push_back(now);
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
// ---- CORS --------------------------------------------------------------
|
// ---- CORS --------------------------------------------------------------
|
||||||
|
|
||||||
bool _is_allowed_origin(const std::string& origin) const {
|
bool _is_allowed_origin(const std::string& origin) const {
|
||||||
@@ -778,10 +663,6 @@ private:
|
|||||||
const http::request<http::string_body>& req);
|
const http::request<http::string_body>& req);
|
||||||
http::response<http::string_body> _handle_video(
|
http::response<http::string_body> _handle_video(
|
||||||
const http::request<http::string_body>& req);
|
const http::request<http::string_body>& req);
|
||||||
http::response<http::string_body> _handle_hash(
|
|
||||||
const http::request<http::string_body>& req);
|
|
||||||
http::response<http::string_body> _handle_check_user(
|
|
||||||
const http::request<http::string_body>& req);
|
|
||||||
http::response<http::string_body> _handle_favicon(
|
http::response<http::string_body> _handle_favicon(
|
||||||
const http::request<http::string_body>& req);
|
const http::request<http::string_body>& req);
|
||||||
http::response<http::string_body> _handle_dnfs_proxy(
|
http::response<http::string_body> _handle_dnfs_proxy(
|
||||||
@@ -822,9 +703,6 @@ void FsysServer::run() {
|
|||||||
server.get("/api/favicon", [this](const auto& req, const auto&) { return _handle_favicon(req); });
|
server.get("/api/favicon", [this](const auto& req, const auto&) { return _handle_favicon(req); });
|
||||||
server.get("/health", [this](const auto& req, const auto&) { return _handle_health(req); });
|
server.get("/health", [this](const auto& req, const auto&) { return _handle_health(req); });
|
||||||
|
|
||||||
server.post("/api/hash", [this](const auto& req, const auto&) { return _handle_hash(req); });
|
|
||||||
server.post("/api/check_user", [this](const auto& req, const auto&) { return _handle_check_user(req); });
|
|
||||||
|
|
||||||
// dnfs2 代理路由
|
// dnfs2 代理路由
|
||||||
auto dnfs_handler = [this](const std::string& route) {
|
auto dnfs_handler = [this](const std::string& route) {
|
||||||
return [this, route](const auto& req, const auto&) {
|
return [this, route](const auto& req, const auto&) {
|
||||||
@@ -1072,8 +950,6 @@ http::response<http::string_body> FsysServer::_handle_filelist(
|
|||||||
result["items"] = items;
|
result["items"] = items;
|
||||||
return make_json_obj(http::status::ok, result, req);
|
return make_json_obj(http::status::ok, result, req);
|
||||||
|
|
||||||
} catch (const FsysExp& e) {
|
|
||||||
return make_error(static_cast<http::status>(e.status()), e.what(), req);
|
|
||||||
} catch (const std::exception& e) {
|
} catch (const std::exception& e) {
|
||||||
_log("ERROR", "fsys", std::string("\u6587\u4ef6\u5217\u8868\u9519\u8bef: ") + e.what());
|
_log("ERROR", "fsys", std::string("\u6587\u4ef6\u5217\u8868\u9519\u8bef: ") + e.what());
|
||||||
return make_error(http::status::internal_server_error, "\u5185\u90e8\u9519\u8bef", req);
|
return make_error(http::status::internal_server_error, "\u5185\u90e8\u9519\u8bef", req);
|
||||||
@@ -1177,113 +1053,6 @@ http::response<http::string_body> FsysServer::_handle_video(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// ============================================================================
|
|
||||||
// POST /api/hash — SHA-256 密码哈希
|
|
||||||
// ============================================================================
|
|
||||||
|
|
||||||
http::response<http::string_body> FsysServer::_handle_hash(
|
|
||||||
const http::request<http::string_body>& req)
|
|
||||||
{
|
|
||||||
try {
|
|
||||||
std::string ip = client_ip(req);
|
|
||||||
if (!_check_rate_limit("hash:" + ip, kHashRateLimit))
|
|
||||||
return make_error(http::status::too_many_requests, "rate limit exceeded", req);
|
|
||||||
|
|
||||||
json::value val;
|
|
||||||
try { val = json::parse(req.body()); }
|
|
||||||
catch (...) { return make_error(http::status::bad_request, "invalid input", req); }
|
|
||||||
|
|
||||||
if (!val.is_object())
|
|
||||||
return make_error(http::status::bad_request, "invalid input", req);
|
|
||||||
|
|
||||||
const auto& obj = val.as_object();
|
|
||||||
auto it = obj.find("password");
|
|
||||||
if (it == obj.end() || !it->value().is_string())
|
|
||||||
return make_error(http::status::bad_request, "invalid input", req);
|
|
||||||
|
|
||||||
std::string password(it->value().as_string());
|
|
||||||
std::string hash = sha256_hex(password);
|
|
||||||
|
|
||||||
json::object result;
|
|
||||||
result["hash"] = hash;
|
|
||||||
return make_json_obj(http::status::ok, result, req);
|
|
||||||
|
|
||||||
} catch (const std::exception& e) {
|
|
||||||
_log("ERROR", "fsys", std::string("hash 错误: ") + e.what());
|
|
||||||
return make_error(http::status::internal_server_error, "内部错误", req);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// ============================================================================
|
|
||||||
// POST /api/check_user — 检查用户是否存在
|
|
||||||
// ============================================================================
|
|
||||||
|
|
||||||
http::response<http::string_body> FsysServer::_handle_check_user(
|
|
||||||
const http::request<http::string_body>& req)
|
|
||||||
{
|
|
||||||
try {
|
|
||||||
std::string ip = client_ip(req);
|
|
||||||
if (!_check_rate_limit("check_user:" + ip, kCheckUserRateLimit))
|
|
||||||
return make_error(http::status::too_many_requests, "rate limit exceeded", req);
|
|
||||||
|
|
||||||
json::value val;
|
|
||||||
try { val = json::parse(req.body()); }
|
|
||||||
catch (...) {
|
|
||||||
json::object r; r["success"] = false; r["error"] = "missing email";
|
|
||||||
return make_json_obj(http::status::bad_request, r, req);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!val.is_object()) {
|
|
||||||
json::object r; r["success"] = false; r["error"] = "missing email";
|
|
||||||
return make_json_obj(http::status::bad_request, r, req);
|
|
||||||
}
|
|
||||||
|
|
||||||
const auto& obj = val.as_object();
|
|
||||||
auto it = obj.find("email");
|
|
||||||
if (it == obj.end() || !it->value().is_string()) {
|
|
||||||
json::object r; r["success"] = false; r["error"] = "missing email";
|
|
||||||
return make_json_obj(http::status::bad_request, r, req);
|
|
||||||
}
|
|
||||||
|
|
||||||
std::string email(it->value().as_string());
|
|
||||||
// trim
|
|
||||||
auto b = email.find_first_not_of(" \t");
|
|
||||||
auto e = email.find_last_not_of(" \t");
|
|
||||||
if (b == std::string::npos) {
|
|
||||||
json::object r; r["success"] = false; r["error"] = "missing email";
|
|
||||||
return make_json_obj(http::status::bad_request, r, req);
|
|
||||||
}
|
|
||||||
email = email.substr(b, e - b + 1);
|
|
||||||
|
|
||||||
json::object payload;
|
|
||||||
payload["action"] = "select";
|
|
||||||
payload["table"] = "Users";
|
|
||||||
payload["where"] = json::object{{"email", email}};
|
|
||||||
payload["columns"] = json::array{"email"};
|
|
||||||
|
|
||||||
DbResult r = _call_db(payload);
|
|
||||||
if (!r.success) {
|
|
||||||
_log("WARNING", "fsys", "check_user 查询失败: " + r.error);
|
|
||||||
json::object result; result["success"] = false; result["error"] = "query failed";
|
|
||||||
return make_json_obj(http::status::internal_server_error, result, req);
|
|
||||||
}
|
|
||||||
|
|
||||||
bool found = r.data.is_array() && !r.data.as_array().empty();
|
|
||||||
json::object result;
|
|
||||||
result["success"] = true;
|
|
||||||
result["found"] = found;
|
|
||||||
return make_json_obj(http::status::ok, result, req);
|
|
||||||
|
|
||||||
} catch (const FsysExp& exp) {
|
|
||||||
json::object r; r["success"] = false; r["error"] = exp.what();
|
|
||||||
return make_json_obj(static_cast<http::status>(exp.status()), r, req);
|
|
||||||
} catch (const std::exception& e) {
|
|
||||||
_log("ERROR", "fsys", std::string("check_user 错误: ") + e.what());
|
|
||||||
json::object r; r["success"] = false; r["error"] = "internal error";
|
|
||||||
return make_json_obj(http::status::internal_server_error, r, req);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// ============================================================================
|
// ============================================================================
|
||||||
// GET /api/favicon?url= — favicon SSRF 防护代理
|
// GET /api/favicon?url= — favicon SSRF 防护代理
|
||||||
// ============================================================================
|
// ============================================================================
|
||||||
|
|||||||
Reference in new issue
Block a user