From ea2b187b7ca9064425c5363d00683ab0713d4ae8 Mon Sep 17 00:00:00 2001 From: AoShinHo <126742159+AoShinRO@users.noreply.github.com> Date: Mon, 26 Jan 2026 21:00:15 -0300 Subject: [PATCH] Added CORS support in web-server (#9746) Co-authored-by: Lemongrass3110 --- conf/web_athena.conf | 11 +++++++++++ src/web/web.cpp | 37 ++++++++++++++++++++++++++++++++++++- src/web/web.hpp | 2 ++ 3 files changed, 49 insertions(+), 1 deletion(-) diff --git a/conf/web_athena.conf b/conf/web_athena.conf index 70e7bca1b94..80f5e510320 100644 --- a/conf/web_athena.conf +++ b/conf/web_athena.conf @@ -53,4 +53,15 @@ print_req_res: off // Allow GIF images to be uploaded as guild emblem? allow_gifs: yes +// Allow HTTP requests from specified origin +// This enables Cross-Origin Resource Sharing (CORS) for browser compatibility. +// Only requests from the configured origin will be accepted. +// +// Format: allowed_origin_cors: ://: +// Example: allowed_origin_cors: http://mywebsite.com:8080 +// +// Security Note: Only configure origins you trust, +// as this allows cross-origin requests to your web API. +allowed_origin_cors: + import: conf/import/web_conf.txt diff --git a/src/web/web.cpp b/src/web/web.cpp index f3594a5ee0b..98db47cfb67 100644 --- a/src/web/web.cpp +++ b/src/web/web.cpp @@ -152,12 +152,41 @@ bool web_config_read(const char* cfgName, bool normal) { web_config_read(w2, normal); else if (!strcmpi(w1, "allow_gifs")) web_config.allow_gifs = config_switch(w2) == 1; + else if (!strcmpi(w1, "allowed_origin_cors")) + web_config.allowed_origin_cors = w2; } fclose(fp); ShowInfo("Finished reading %s.\n", cfgName); return true; } +/*========================================== + * CORS for browser requests + *------------------------------------------*/ +void set_cors_headers(Response& res, const std::string& origin) { + res.set_header("Access-Control-Allow-Origin", origin); + res.set_header("Vary", "Origin"); + res.set_header("Access-Control-Allow-Methods", "POST"); + res.set_header("Access-Control-Allow-Headers", "Content-Type, Authorization"); +} + +static httplib::Server::HandlerResponse cors_handler(const httplib::Request& req, httplib::Response& res) { + if (web_config.allowed_origin_cors.empty()) { + // CORS not allowed + return httplib::Server::HandlerResponse::Unhandled; + } + std::string origin = req.get_header_value("Origin"); + + if (origin.empty()) + return httplib::Server::HandlerResponse::Unhandled; + + if (origin != web_config.allowed_origin_cors) + return httplib::Server::HandlerResponse::Unhandled; + + set_cors_headers(res, origin); + return httplib::Server::HandlerResponse::Unhandled; +} + /*========================================== * read config file *------------------------------------------*/ @@ -259,9 +288,11 @@ int32 inter_config_read(const char* cfgName) void web_set_defaults() { web_config.web_ip = "0.0.0.0"; web_config.web_port = 8888; + web_config.print_req_res = false; safestrncpy(web_config.webconf_name, "conf/web_athena.conf", sizeof(web_config.webconf_name)); safestrncpy(web_config.msgconf_name, "conf/msg_conf/web_msg.conf", sizeof(web_config.msgconf_name)); - web_config.print_req_res = false; + web_config.allow_gifs = true; + web_config.allowed_origin_cors = ""; inter_config.emblem_transparency_limit = 100; inter_config.emblem_woe_change = true; @@ -446,6 +477,10 @@ bool WebServer::initialize( int32 argc, char* argv[] ){ ShowStatus("Starting server...\n"); http_server = std::make_shared(); + + // hook func to set up CORS for browsers + http_server->set_pre_routing_handler(cors_handler); + // set up routes http_server->Post("/charconfig/load", charconfig_load); http_server->Post("/charconfig/save", charconfig_save); diff --git a/src/web/web.hpp b/src/web/web.hpp index d7a68d56841..28bd11e38ef 100644 --- a/src/web/web.hpp +++ b/src/web/web.hpp @@ -42,6 +42,8 @@ struct Web_Config { char webconf_name[256]; /// name of main config file char msgconf_name[256]; /// name of msg_conf config file bool allow_gifs; + + std::string allowed_origin_cors; // allowed origin for CORS }; struct Inter_Config {