|
@@ -1,4 +1,5 @@
|
|
|
#include "server.hpp"
|
|
#include "server.hpp"
|
|
|
|
|
+#include "captcha.hpp"
|
|
|
#include "errors.hpp"
|
|
#include "errors.hpp"
|
|
|
#include "json_http.hpp"
|
|
#include "json_http.hpp"
|
|
|
#include "rate_limiter.hpp"
|
|
#include "rate_limiter.hpp"
|
|
@@ -58,8 +59,13 @@ void requireCapability(ServerDeps& d, const ApiKey& k, const httplib::Request& r
|
|
|
throw ApiError(ErrCode::Forbidden, "forbidden", "origin not allowed for this key");
|
|
throw ApiError(ErrCode::Forbidden, "forbidden", "origin not allowed for this key");
|
|
|
if (!rateLimiter().allow(k.id, sc.rateLimitPerMin))
|
|
if (!rateLimiter().allow(k.id, sc.rateLimitPerMin))
|
|
|
throw ApiError(ErrCode::TooManyRequests, "rate_limited", "rate limit exceeded");
|
|
throw ApiError(ErrCode::TooManyRequests, "rate_limited", "rate limit exceeded");
|
|
|
- // Phase 2 (CAPTCHA) inserts the rule->requireHumanToken check here.
|
|
|
|
|
- (void)d;
|
|
|
|
|
|
|
+ if (rule->requireHumanToken) {
|
|
|
|
|
+ std::string token;
|
|
|
|
|
+ if (auto it = req.headers.find("X-Captcha-Token"); it != req.headers.end()) token = it->second;
|
|
|
|
|
+ auto snap = d.settings.snapshot();
|
|
|
|
|
+ if (!verifyCaptcha(*snap, token, req.remote_addr))
|
|
|
|
|
+ throw ApiError(ErrCode::Forbidden, "captcha_required", "human verification required");
|
|
|
|
|
+ }
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
void ApiServer::registerRoutes() {
|
|
void ApiServer::registerRoutes() {
|