From c8e1566343bbae005f9936398819aa8233b669bd Mon Sep 17 00:00:00 2001 From: Forsrobin Date: Sun, 27 Jul 2025 12:20:40 +0200 Subject: [PATCH 1/2] Implement web server with route handling and SSL configuration; refactor main application logic to utilize WebServer class. --- .vscode/tasks.json | 6 +- bankid/includes/api/auth.h | 5 + bankid/includes/api/cancel.h | 5 + bankid/includes/api/collect.h | 5 + bankid/includes/api/other.payment.h | 5 + bankid/includes/api/payment.h | 5 + bankid/includes/api/phone.auth.h | 5 + bankid/includes/api/phone.sign.h | 5 + bankid/includes/api/responses.h | 7 +- bankid/includes/api/sign.h | 5 + bankid/includes/bankid.h | 17 ++- server/CMakeLists.txt | 6 +- server/includes/helper.h | 9 -- server/includes/routes.h | 50 +++++++ server/includes/webserver.h | 32 ++++ server/main.cpp | 218 +++------------------------- server/routes.cpp | 163 +++++++++++++++++++++ server/webserver.cpp | 122 ++++++++++++++++ 18 files changed, 462 insertions(+), 208 deletions(-) delete mode 100644 server/includes/helper.h create mode 100644 server/includes/routes.h create mode 100644 server/includes/webserver.h create mode 100644 server/routes.cpp create mode 100644 server/webserver.cpp diff --git a/.vscode/tasks.json b/.vscode/tasks.json index 4798f9b..677dfe5 100644 --- a/.vscode/tasks.json +++ b/.vscode/tasks.json @@ -5,6 +5,7 @@ "label": "Run Server Debug (Static)", "type": "shell", "command": "./bankid_server.exe", + "args": ["8080"], "options": { "cwd": "${workspaceFolder}/build/vs2022-deb/server/Debug" }, @@ -15,6 +16,7 @@ "label": "Run Server Debug (Shared)", "type": "shell", "command": "./bankid_server.exe", + "args": ["8080"], "group": "test", "options": { "cwd": "${workspaceFolder}/build/vs2022-deb-shared/server/Debug" @@ -25,6 +27,7 @@ "label": "Run Server Release (Static)", "type": "shell", "command": "./bankid_server.exe", + "args": ["8080"], "options": { "cwd": "${workspaceFolder}/build/vs2022-rel/server/Release" }, @@ -35,6 +38,7 @@ "label": "Run Server Release (Shared)", "type": "shell", "command": "./bankid_server.exe", + "args": ["8080"], "group": "test", "options": { "cwd": "${workspaceFolder}/build/vs2022-rel-shared/server/Release" @@ -62,6 +66,6 @@ "group": "test", "dependsOn": "Build Tests (Shared)", "problemMatcher": [] - }, + } ] } diff --git a/bankid/includes/api/auth.h b/bankid/includes/api/auth.h index 0e9a05a..d7abad4 100644 --- a/bankid/includes/api/auth.h +++ b/bankid/includes/api/auth.h @@ -1,3 +1,6 @@ +#ifndef BANKID_API_AUTH_H +#define BANKID_API_AUTH_H + #pragma once #include "../bankid.h" @@ -218,3 +221,5 @@ namespace BankID::API }; } // namespace BankID::API + +#endif // BANKID_API_AUTH_H \ No newline at end of file diff --git a/bankid/includes/api/cancel.h b/bankid/includes/api/cancel.h index 9dfa8e8..7dfe11b 100644 --- a/bankid/includes/api/cancel.h +++ b/bankid/includes/api/cancel.h @@ -1,3 +1,6 @@ +#ifndef BANKID_API_CANCEL_H +#define BANKID_API_CANCEL_H + #pragma once #include "../bankid.h" @@ -47,3 +50,5 @@ namespace BankID::API }; } // namespace BankID::API + +#endif // BANKID_API_CANCEL_H \ No newline at end of file diff --git a/bankid/includes/api/collect.h b/bankid/includes/api/collect.h index 1dc1e2a..41df497 100644 --- a/bankid/includes/api/collect.h +++ b/bankid/includes/api/collect.h @@ -1,3 +1,6 @@ +#ifndef BANKID_API_COLLECT_H +#define BANKID_API_COLLECT_H + #pragma once #include "../bankid.h" @@ -47,3 +50,5 @@ namespace BankID::API }; } // namespace BankID::API + +#endif // BANKID_API_COLLECT_H diff --git a/bankid/includes/api/other.payment.h b/bankid/includes/api/other.payment.h index af30c45..807bb9b 100644 --- a/bankid/includes/api/other.payment.h +++ b/bankid/includes/api/other.payment.h @@ -1,3 +1,6 @@ +#ifndef BANKID_API_OTHER_PAYMENT_H +#define BANKID_API_OTHER_PAYMENT_H + #pragma once #include "../bankid.h" @@ -280,3 +283,5 @@ namespace BankID::API }; } // namespace BankID::API + +#endif // BANKID_API_OTHER_PAYMENT_H diff --git a/bankid/includes/api/payment.h b/bankid/includes/api/payment.h index e065d17..3e96f14 100644 --- a/bankid/includes/api/payment.h +++ b/bankid/includes/api/payment.h @@ -1,3 +1,6 @@ +#ifndef BANKID_API_PAYMENT_H +#define BANKID_API_PAYMENT_H + #pragma once #include "../bankid.h" @@ -328,3 +331,5 @@ namespace BankID::API }; } // namespace BankID::API + +#endif // BANKID_API_PAYMENT_H diff --git a/bankid/includes/api/phone.auth.h b/bankid/includes/api/phone.auth.h index 003ee76..7340d43 100644 --- a/bankid/includes/api/phone.auth.h +++ b/bankid/includes/api/phone.auth.h @@ -1,3 +1,6 @@ +#ifndef BANKID_API_PHONE_AUTH_H +#define BANKID_API_PHONE_AUTH_H + #pragma once #include "../bankid.h" @@ -155,3 +158,5 @@ namespace BankID::API }; } // namespace BankID::API + +#endif // BANKID_API_PHONE_AUTH_H \ No newline at end of file diff --git a/bankid/includes/api/phone.sign.h b/bankid/includes/api/phone.sign.h index c99fff9..072ccfe 100644 --- a/bankid/includes/api/phone.sign.h +++ b/bankid/includes/api/phone.sign.h @@ -1,3 +1,6 @@ +#ifndef BANKID_API_PHONE_SIGN_H +#define BANKID_API_PHONE_SIGN_H + #pragma once #include "../bankid.h" @@ -148,3 +151,5 @@ namespace BankID::API }; } // namespace BankID::API + +#endif // BANKID_API_PHONE_SIGN_H \ No newline at end of file diff --git a/bankid/includes/api/responses.h b/bankid/includes/api/responses.h index 65fc6ea..0e462a2 100644 --- a/bankid/includes/api/responses.h +++ b/bankid/includes/api/responses.h @@ -1,3 +1,6 @@ +#ifndef BANKID_API_RESPONSES_H +#define BANKID_API_RESPONSES_H + #pragma once #include "../bankid.h" @@ -256,4 +259,6 @@ namespace BankID::API if (j.contains("hintCode")) r.hintCode = j.at("hintCode").get(); } -} +} // namespace BankID::API + +#endif // BANKID_API_RESPONSES_H diff --git a/bankid/includes/api/sign.h b/bankid/includes/api/sign.h index 8e67e31..c584b3b 100644 --- a/bankid/includes/api/sign.h +++ b/bankid/includes/api/sign.h @@ -1,3 +1,6 @@ +#ifndef BANKID_API_SIGN_H +#define BANKID_API_SIGN_H + #pragma once #include "../bankid.h" @@ -210,3 +213,5 @@ namespace BankID::API }; } // namespace BankID::API + +#endif // BANKID_API_SIGN_H diff --git a/bankid/includes/bankid.h b/bankid/includes/bankid.h index cdbc6ce..2490bb9 100644 --- a/bankid/includes/bankid.h +++ b/bankid/includes/bankid.h @@ -1,3 +1,16 @@ +// +// bankid.h +// +// Copyright (c) 2025 Forsrobin. All rights reserved. +// MIT License +// +// This file is part of the BankID C++ library, providing a client for the BankID API. +// + + +#ifndef BANKID_H +#define BANKID_H + #pragma once #define CPPHTTPLIB_OPENSSL_SUPPORT @@ -99,7 +112,7 @@ namespace BankID * For example: * openssl pkcs12 -in bankid_cert.p12 -out bankid_key.pem -nocerts -nodes * openssl pkcs12 -in bankid_cert.p12 -out bankid_cert.pem -clcerts -nokeys - * + * * This structure is used to initialize the SSL client with the correct paths for the CA file, certificate, and key. */ struct BANKID_API SSLConfig @@ -356,3 +369,5 @@ namespace BankID #ifdef _WIN32 #pragma warning(pop) #endif + +#endif // BANKID_H diff --git a/server/CMakeLists.txt b/server/CMakeLists.txt index 4cbb941..20ff057 100644 --- a/server/CMakeLists.txt +++ b/server/CMakeLists.txt @@ -16,7 +16,11 @@ find_package(Crow REQUIRED) find_package(nlohmann_json REQUIRED) # Server executable -add_executable(bankid_server main.cpp) +add_executable(bankid_server + main.cpp + webserver.cpp + routes.cpp +) # Enable SSL compilation flag if (CROW_ENABLE_SSL) diff --git a/server/includes/helper.h b/server/includes/helper.h deleted file mode 100644 index 4033eb2..0000000 --- a/server/includes/helper.h +++ /dev/null @@ -1,9 +0,0 @@ -#include - -void logStartingServer() -{ - std::cout << "Starting BankID REST API server on port 8443 (HTTPS)..." << std::endl; - std::cout << "Available endpoints:" << std::endl; - std::cout << " GET https://localhost:8443/init - Start authentication" << std::endl; - std::cout << " GET https://localhost:8443/poll - Check authentication status" << std::endl; -} \ No newline at end of file diff --git a/server/includes/routes.h b/server/includes/routes.h new file mode 100644 index 0000000..a980880 --- /dev/null +++ b/server/includes/routes.h @@ -0,0 +1,50 @@ +#ifndef ROUTES_H +#define ROUTES_H + +#pragma once + +#include "bankid.h" +#include +#include +#include +#include +#include + +using json = nlohmann::json; + +struct EndpointInfo +{ + std::string method; + std::string path; + std::string description; +}; + +class Routes +{ +public: + static void setupRoutes(crow::App &app, + BankID::Session &bankidSession, + BankID::API::AuthConfig &authConfig); + + static const std::vector &getEndpoints(); + +private: + // Static member definition + inline static std::vector endpoints; + + static void registerEndpoint(const std::string &method, + const std::string &path, + const std::string &description); + + static crow::response handleAuthInit(BankID::Session &bankidSession, + BankID::API::AuthConfig &authConfig); + + static crow::response handleAuthPoll(BankID::Session &bankidSession, + BankID::API::AuthConfig &authConfig, + const std::string &orderRef); + + static crow::response handleAuthCancel(BankID::Session &bankidSession, + const std::string &orderRef); +}; + +#endif // ROUTES_H \ No newline at end of file diff --git a/server/includes/webserver.h b/server/includes/webserver.h new file mode 100644 index 0000000..ded8976 --- /dev/null +++ b/server/includes/webserver.h @@ -0,0 +1,32 @@ +#ifndef WEBSERVER_H +#define WEBSERVER_H + +#pragma once + +#include "bankid.h" +#include +#include + +class WebServer { +public: + WebServer(); + ~WebServer(); + + bool initialize(); + void run(uint16_t port = 8080); + void shutdown(); + +private: + crow::App m_app; + std::unique_ptr m_bankidSession; + BankID::API::AuthConfig m_authConfig; + + void setupCORS(); + void setupSSL(); + void setupRoutes(); + void printAvailableEndpoints() const; + + bool m_isInitialized = false; +}; + +#endif // WEBSERVER_H \ No newline at end of file diff --git a/server/main.cpp b/server/main.cpp index 01166eb..d32d9d6 100644 --- a/server/main.cpp +++ b/server/main.cpp @@ -1,224 +1,52 @@ -#include "bankid.h" -#include "helper.h" -#include -#include -#include +#include "webserver.h" +#include #include -#include +#include -#include -using json = nlohmann::json; +std::unique_ptr server; void handleShutdown(int signal) { std::cout << "Received shutdown signal (" << signal << "). Cleaning up..." << std::endl; - BankID::QRGeneratorCache::instance().shutdown(); + if (server) + { + server->shutdown(); + } std::_Exit(0); } -int main() +int main(int argc, char *argv[]) { - // Enable CORS for the application - crow::App app; - auto &cors = app.get_middleware(); - - // clang-format off - cors - .global() - .headers("X-Custom-Header", "Upgrade-Insecure-Requests") - .methods("POST"_method, "GET"_method) - .prefix("/cors") - .origin("localhost:3000") - .prefix("/nocors") - .ignore(); - - // SSL Configuration for BankID - BankID::SSLConfig sslConfig( - BankID::Environment::TEST, - "certs/test.ca", - "certs/bankid_cert.pem", - "certs/bankid_key.pem"); - - - const auto& validationResult = sslConfig.validate(); - if (!validationResult.has_value()) + if (argc < 2) { - std::cerr << "SSL configuration validation failed: " << validationResult.error() << std::endl; + std::cerr << "Usage: bankid_server.exe " << std::endl; return 1; } + const uint16_t port = static_cast(std::stoi(argv[1])); - // Create your BankID session instance with just SSL config - BankID::Session bankidSession(sslConfig); + // Create and initialize the web server + server = std::make_unique(); - if (!bankidSession.isInitialized()) + if (!server->initialize()) { - std::cout << "BankID session initialization failed. Exiting." << std::endl; + std::cerr << "Failed to initialize web server. Exiting." << std::endl; return 1; } - auto authConfig = BankID::API::AuthConfig("127.0.0.1").setUserVisibleData("TG9nZ2luIHDDpSBjKysgdGVzdCBwb3J0YWxlbg=="); - - // GET /api/auth/init endpoint - CROW_ROUTE(app, "/api/auth/init") - ([&bankidSession, &authConfig]() - { - std::cout << "GET /init - Starting authentication" << std::endl; - - // Create auth config on-demand for this specific request - - - auto response = bankidSession.auth(authConfig); - - if (!response) - { - const auto &error = response.error(); - return crow::response(error.httpStatus, error.details); - } - // Simple JSON response using nlohmann::json - json res; - res["orderRef"] = response->orderRef; - res["autoStartToken"] = response->autoStartToken; - res["authCountdown"] = 60; - - crow::response resp(200, res.dump()); - resp.add_header("Content-Type", "application/json"); - return resp; }); - - // GET /api/auth/poll endpoint - CROW_ROUTE(app, "/api/auth/poll/") - ([&bankidSession, &authConfig](std::string orderRef) - { - std::cout << "GET /api/auth/poll - Checking authentication status" << std::endl; - std::cout << "Order Reference: " << orderRef << std::endl; - - // Create collect config on-demand for this specific request - auto collectConfig = BankID::API::CollectConfig::create(orderRef); - auto response = bankidSession.collect(collectConfig); - - json baseResponse; - baseResponse["status"] = response->getStatusString(); - baseResponse["orderRef"] = response->orderRef; - baseResponse["qrCode"] = nullptr; // Include QR code - baseResponse["token"] = nullptr; // No token yet - baseResponse["user"] = nullptr; // No user data yet - - if (!response) - { - const auto &error = response.error(); - return crow::response(error.httpStatus, error.details); - } - - std::cout << "Collect response status: " << response->getStatusString() << std::endl; - - if (response->status == BankID::API::CollectStatus::PENDING) - { - auto qrCode = BankID::QRGeneratorCache::instance().get(response->orderRef)->getNextQRCode(); - - if (!qrCode) - { - const auto &error = qrCode.error(); - return crow::response(error.httpStatus, error.details); - } - - baseResponse["qrCode"] = qrCode.value(); // Include QR code - - crow::response resp(200, baseResponse.dump()); - resp.add_header("Content-Type", "application/json"); - return resp; - } - else if (response->status == BankID::API::CollectStatus::COMPLETE) - { - // Convert the response to JSON - - baseResponse["token"] = nullptr; - baseResponse["user"] = response->completionData->user ? json{ - {"personalNumber", response->completionData->user->personalNumber}, - {"name", response->completionData->user->name}, - {"givenName", response->completionData->user->givenName}, - {"surname", response->completionData->user->surname} - } : nullptr; - - crow::response resp(200, baseResponse.dump()); - resp.add_header("Content-Type", "application/json"); - return resp; - } - else - { - // Try to get a QR code, if the QR code has expired, make a new request - // to the /api/auth/init endpoint - auto newResponse = bankidSession.auth(authConfig); - - - if (!newResponse) - { - const auto &error = response.error(); - return crow::response(error.httpStatus, error.details); - } - - auto qrCode = BankID::QRGeneratorCache::instance().get(newResponse->orderRef); - if (!qrCode) - { - return crow::response(404, "QR code not found in cache"); - } - - auto nextQrCode = qrCode->getNextQRCode(); - - if (!nextQrCode) - { - const auto &error = nextQrCode.error(); - return crow::response(error.httpStatus, error.details); - } - - baseResponse["qrCode"] = nextQrCode.value(); // Include QR code - baseResponse["orderRef"] = newResponse->orderRef; - baseResponse["status"] = "pending"; - - std::cout << "New orderRef: " << newResponse->orderRef << std::endl; - std::cout << "sending back new payload: " << baseResponse.dump() << std::endl; - - crow::response resp(200, baseResponse.dump()); - resp.add_header("Content-Type", "application/json"); - return resp; - } }); - - CROW_ROUTE(app, "/api/auth/cancel/") - ([&bankidSession](std::string orderRef) - { - auto cancelConfig = BankID::API::CancelConfig::create( - orderRef // orderRef - ); - - auto response = bankidSession.cancel(cancelConfig); - - if (!response) - { - const auto &error = response.error(); - return crow::response(error.httpStatus, error.details); - } - - - // Convert the response to JSON - json res; - res["message"] = "Order cancelled successfully"; - - crow::response resp(200, res.dump()); - resp.add_header("Content-Type", "application/json"); - return resp; }); - - logStartingServer(); - - // Register cleanup handler to ensure graceful shutdown + // Register cleanup handlers std::atexit([] { - std::cout << "Application is shutting down. Cleaning up QRGeneratorCache..." << std::endl; - BankID::QRGeneratorCache::instance().shutdown(); }); + std::cout << "Application is shutting down. Cleaning up..." << std::endl; + if (server) { + server->shutdown(); + } }); std::signal(SIGINT, handleShutdown); // Ctrl+C std::signal(SIGTERM, handleShutdown); // kill signal - app.port(8080).multithreaded().run(); + server->run(port); return 0; -} +} \ No newline at end of file diff --git a/server/routes.cpp b/server/routes.cpp new file mode 100644 index 0000000..a9d9503 --- /dev/null +++ b/server/routes.cpp @@ -0,0 +1,163 @@ +#include "routes.h" +#include + +void Routes::setupRoutes(crow::App& app, + BankID::Session& bankidSession, + BankID::API::AuthConfig& authConfig) { + + // Clear any existing endpoints + endpoints.clear(); + + // Register and setup GET /api/auth/init endpoint + registerEndpoint("GET", "/api/auth/init", "Initialize BankID authentication"); + CROW_ROUTE(app, "/api/auth/init") + ([&bankidSession, &authConfig]() { + return handleAuthInit(bankidSession, authConfig); + }); + + // Register and setup GET /api/auth/poll endpoint + registerEndpoint("GET", "/api/auth/poll/", "Poll authentication status"); + CROW_ROUTE(app, "/api/auth/poll/") + ([&bankidSession, &authConfig](std::string orderRef) { + return handleAuthPoll(bankidSession, authConfig, orderRef); + }); + + // Register and setup GET /api/auth/cancel endpoint + registerEndpoint("GET", "/api/auth/cancel/", "Cancel authentication request"); + CROW_ROUTE(app, "/api/auth/cancel/") + ([&bankidSession](std::string orderRef) { + return handleAuthCancel(bankidSession, orderRef); + }); +} + +const std::vector& Routes::getEndpoints() { + return endpoints; +} + +void Routes::registerEndpoint(const std::string& method, + const std::string& path, + const std::string& description) { + endpoints.push_back({method, path, description}); +} + +crow::response Routes::handleAuthInit(BankID::Session& bankidSession, + BankID::API::AuthConfig& authConfig) { + std::cout << "GET /init - Starting authentication" << std::endl; + + auto response = bankidSession.auth(authConfig); + + if (!response) { + const auto& error = response.error(); + return crow::response(error.httpStatus, error.details); + } + + json res; + res["orderRef"] = response->orderRef; + res["autoStartToken"] = response->autoStartToken; + res["authCountdown"] = 60; + + crow::response resp(200, res.dump()); + resp.add_header("Content-Type", "application/json"); + return resp; +} + +crow::response Routes::handleAuthPoll(BankID::Session& bankidSession, + BankID::API::AuthConfig& authConfig, + const std::string& orderRef) { + std::cout << "GET /api/auth/poll - Checking authentication status" << std::endl; + std::cout << "Order Reference: " << orderRef << std::endl; + + auto collectConfig = BankID::API::CollectConfig::create(orderRef); + auto response = bankidSession.collect(collectConfig); + + json baseResponse; + baseResponse["status"] = response->getStatusString(); + baseResponse["orderRef"] = response->orderRef; + baseResponse["qrCode"] = nullptr; + baseResponse["token"] = nullptr; + baseResponse["user"] = nullptr; + + if (!response) { + const auto& error = response.error(); + return crow::response(error.httpStatus, error.details); + } + + std::cout << "Collect response status: " << response->getStatusString() << std::endl; + + if (response->status == BankID::API::CollectStatus::PENDING) { + auto qrCode = BankID::QRGeneratorCache::instance().get(response->orderRef)->getNextQRCode(); + + if (!qrCode) { + const auto& error = qrCode.error(); + return crow::response(error.httpStatus, error.details); + } + + baseResponse["qrCode"] = qrCode.value(); + + crow::response resp(200, baseResponse.dump()); + resp.add_header("Content-Type", "application/json"); + return resp; + } + else if (response->status == BankID::API::CollectStatus::COMPLETE) { + baseResponse["token"] = nullptr; + baseResponse["user"] = response->completionData->user ? json{ + {"personalNumber", response->completionData->user->personalNumber}, + {"name", response->completionData->user->name}, + {"givenName", response->completionData->user->givenName}, + {"surname", response->completionData->user->surname} + } : nullptr; + + crow::response resp(200, baseResponse.dump()); + resp.add_header("Content-Type", "application/json"); + return resp; + } + else { + auto newResponse = bankidSession.auth(authConfig); + + if (!newResponse) { + const auto& error = response.error(); + return crow::response(error.httpStatus, error.details); + } + + auto qrCode = BankID::QRGeneratorCache::instance().get(newResponse->orderRef); + if (!qrCode) { + return crow::response(404, "QR code not found in cache"); + } + + auto nextQrCode = qrCode->getNextQRCode(); + + if (!nextQrCode) { + const auto& error = nextQrCode.error(); + return crow::response(error.httpStatus, error.details); + } + + baseResponse["qrCode"] = nextQrCode.value(); + baseResponse["orderRef"] = newResponse->orderRef; + baseResponse["status"] = "pending"; + + std::cout << "New orderRef: " << newResponse->orderRef << std::endl; + std::cout << "sending back new payload: " << baseResponse.dump() << std::endl; + + crow::response resp(200, baseResponse.dump()); + resp.add_header("Content-Type", "application/json"); + return resp; + } +} + +crow::response Routes::handleAuthCancel(BankID::Session& bankidSession, + const std::string& orderRef) { + auto cancelConfig = BankID::API::CancelConfig::create(orderRef); + auto response = bankidSession.cancel(cancelConfig); + + if (!response) { + const auto& error = response.error(); + return crow::response(error.httpStatus, error.details); + } + + json res; + res["message"] = "Order cancelled successfully"; + + crow::response resp(200, res.dump()); + resp.add_header("Content-Type", "application/json"); + return resp; +} \ No newline at end of file diff --git a/server/webserver.cpp b/server/webserver.cpp new file mode 100644 index 0000000..8d0c88c --- /dev/null +++ b/server/webserver.cpp @@ -0,0 +1,122 @@ +#include "webserver.h" +#include "routes.h" +#include +#include + +WebServer::WebServer() : m_authConfig("127.0.0.1") +{ + m_authConfig.setUserVisibleData("TG9nZ2luIHDDpSBjKysgdGVzdCBwb3J0YWxlbg=="); +} + +WebServer::~WebServer() +{ + shutdown(); +} + +bool WebServer::initialize() +{ + setupCORS(); + setupSSL(); + + if (!m_bankidSession || !m_bankidSession->isInitialized()) + { + std::cout << "BankID session initialization failed." << std::endl; + return false; + } + + setupRoutes(); + m_isInitialized = true; + return true; +} + +void WebServer::setupCORS() +{ + auto &cors = m_app.get_middleware(); + + cors + .global() + .headers("X-Custom-Header", "Upgrade-Insecure-Requests") + .methods("POST"_method, "GET"_method) + .prefix("/cors") + .origin("localhost:3000") + .prefix("/nocors") + .ignore(); +} + +void WebServer::setupSSL() +{ + BankID::SSLConfig sslConfig( + BankID::Environment::TEST, + "certs/test.ca", + "certs/bankid_cert.pem", + "certs/bankid_key.pem"); + + const auto &validationResult = sslConfig.validate(); + if (!validationResult.has_value()) + { + std::cerr << "SSL configuration validation failed: " << validationResult.error() << std::endl; + return; + } + + m_bankidSession = std::make_unique(sslConfig); +} + +void WebServer::setupRoutes() +{ + Routes::setupRoutes(m_app, *m_bankidSession, m_authConfig); +} + +void WebServer::run(uint16_t port) +{ + if (!m_isInitialized) + { + std::cerr << "WebServer not initialized. Call initialize() first." << std::endl; + return; + } + + std::cout << "=== Server starting on port " << port << " ===" << std::endl; + printAvailableEndpoints(); + std::cout << "Server is ready to accept connections!" << std::endl; + std::cout << "=========================================" << std::endl; + + m_app.port(port).multithreaded().run(); +} + +void WebServer::printAvailableEndpoints() const +{ + const auto &endpoints = Routes::getEndpoints(); + + if (endpoints.empty()) + { + std::cout << "No endpoints registered." << std::endl; + return; + } + + std::cout << "\nAvailable endpoints:" << std::endl; + + // Find the maximum method and path lengths for formatting + size_t maxMethodLen = 0; + size_t maxPathLen = 0; + + for (const auto &endpoint : endpoints) + { + maxMethodLen = std::max(maxMethodLen, endpoint.method.length()); + maxPathLen = std::max(maxPathLen, endpoint.path.length()); + } + + // Print endpoints with aligned formatting + for (const auto &endpoint : endpoints) + { + std::cout << " " + << std::left << std::setw(maxMethodLen) << endpoint.method + << " " + << std::left << std::setw(maxPathLen) << endpoint.path + << " - " << endpoint.description << std::endl; + } + std::cout << std::endl; +} + +void WebServer::shutdown() +{ + BankID::QRGeneratorCache::instance().shutdown(); +} \ No newline at end of file From 36339101a8a00ff259f8fa8b6dd32f1589036188 Mon Sep 17 00:00:00 2001 From: forsrobin Date: Mon, 28 Jul 2025 00:41:33 +0200 Subject: [PATCH 2/2] Refactor documentation comments in main.cpp for clarity and consistency --- server/main.cpp | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/server/main.cpp b/server/main.cpp index d32d9d6..a0a13ee 100644 --- a/server/main.cpp +++ b/server/main.cpp @@ -3,6 +3,15 @@ #include #include +/** +* @file main.cpp +* @brief Main entry point for the BankID server application. +* +* This file initializes the web server and handles graceful shutdown. +* It sets up signal handlers for cleanup on termination. +* It also provides a usage message if no port is specified. +*/ + std::unique_ptr server; void handleShutdown(int signal)