* Fix log file access, refactor configuration reading class * Remove bypass option in favor of failmode * fix loging, print enrolment info * Add EMAIL method * Add yubi authentication method * Add support for verification message * Add verification * Made changes in Vagrant's files to run different OSs * Switch off tests and packages demands to run PAM on Debian 11 * Add authentication totp * Changes in utils * Remove unnessesary interface * Changed vagrant files and postinstal script for Ubuntu 20 and 22 * Moved adding PasswordAuth to vagrant file from posinst * Added ubuntu 24.04 * Set version * Poprawki UI * WebSocket implementation * Add totp authentication method * fixup changes in utils * Remove unnessesary interface and simplify code * Remove "default" message handler from WebSocket class * Change display names of known authentication methods * Cleanup code in 'main' file * Add CheckApplication * Remove unused function * Changed vagrant files and postinstal script for Ubuntu 20 and 22 * Moved adding PasswordAuth to vagrant file from posinst * Added ubuntu 24.04 * Set version to 2.0.2 * Proper handle for missing configuration * Fixup use value of optional object * Add more vCPU/RAM to vagrant VM's + fix translations * Minor WS fixes, translations * Proper handler for Werification error * Make use of prompt parameter * Add max number of prompts * remove unused code, fir includes * Add Waiting status * Add check application status check --------- Co-authored-by: Madzik <m.w@linux.pl>
140 lines
4.9 KiB
C++
Executable File
140 lines
4.9 KiB
C++
Executable File
#pragma once
|
|
|
|
#include <algorithm>
|
|
#include <cstdlib>
|
|
#include <cstring>
|
|
#include <curl/curl.h>
|
|
#include <functional>
|
|
#include <memory>
|
|
#include <string>
|
|
#include <string_view>
|
|
#include <map>
|
|
|
|
#include <memory_resource>
|
|
|
|
#include <rublon/error.hpp>
|
|
#include <rublon/utils.hpp>
|
|
|
|
#include <tl/expected.hpp>
|
|
|
|
#include <curl/curl.h>
|
|
|
|
namespace rublon {
|
|
|
|
inline bool replace(std::string& str, const std::string& from, const std::string& to) {
|
|
size_t start_pos = str.find(from);
|
|
if(start_pos == std::string::npos)
|
|
return false;
|
|
str.replace(start_pos, from.length(), to);
|
|
return true;
|
|
}
|
|
|
|
namespace {
|
|
size_t WriteMemoryCallback(void * contents, size_t size, size_t nmemb, void * userp) {
|
|
const size_t realsize = size * nmemb;
|
|
reinterpret_cast< std::pmr::string * >(userp)->append(static_cast< const char * >(contents), realsize);
|
|
return realsize;
|
|
}
|
|
} // namespace
|
|
|
|
struct Request {
|
|
std::pmr::memory_resource * _mr;
|
|
|
|
std::pmr::map< std::pmr::string, std::pmr::string > headers;
|
|
std::pmr::string body;
|
|
|
|
public:
|
|
Request(std::pmr::memory_resource * mr) : _mr{mr}, headers{_mr}, body{_mr} {};
|
|
|
|
Request(const Request & res) = delete;
|
|
Request & operator=(const Request & res) = delete;
|
|
|
|
Request(Request && res) = delete;
|
|
Request & operator=(Request &&) = delete;
|
|
};
|
|
|
|
struct Response {
|
|
std::pmr::memory_resource * _mr;
|
|
|
|
std::pmr::map< std::pmr::string, std::pmr::string > headers;
|
|
std::pmr::string body;
|
|
|
|
public:
|
|
Response(std::pmr::memory_resource * mr) : _mr{mr}, headers{_mr}, body{_mr} {};
|
|
|
|
Response(const Response & res) = delete;
|
|
Response & operator=(const Response & res) = delete;
|
|
|
|
Response(Response && res) noexcept = default;
|
|
Response & operator=(Response && res) noexcept = default;
|
|
};
|
|
|
|
class CURL {
|
|
std::unique_ptr< ::CURL, void (*)(::CURL *) > curl;
|
|
|
|
public:
|
|
CURL() : curl{std::unique_ptr< ::CURL, void (*)(::CURL *) >(curl_easy_init(), curl_easy_cleanup)} {}
|
|
|
|
tl::expected< std::reference_wrapper< Response >, ConnectionError >
|
|
request(std::string_view uri, const Request & request, Response & response) const {
|
|
memory::MonotonicStackResource< 4 * 1024 > stackResource;
|
|
|
|
std::pmr::string response_data{&stackResource};
|
|
response_data.reserve(3000);
|
|
|
|
/// TODO this can be done on stack using pmr
|
|
auto curl_headers = std::unique_ptr< curl_slist, void (*)(curl_slist *) >(nullptr, curl_slist_free_all);
|
|
std::for_each(request.headers.begin(), request.headers.end(), [&](auto header) {
|
|
log(LogLevel::Debug, "%s header: %s: %s", "CURL", header.first.c_str(), header.second.c_str());
|
|
curl_headers.reset(curl_slist_append(curl_headers.release(), (header.first + ": " + header.second).c_str()));
|
|
});
|
|
|
|
curl_easy_setopt(curl.get(), CURLOPT_VERBOSE, 1);
|
|
curl_easy_setopt(curl.get(), CURLOPT_URL, uri.data());
|
|
curl_easy_setopt(curl.get(), CURLOPT_HTTPHEADER, curl_headers.get());
|
|
curl_easy_setopt(curl.get(), CURLOPT_POST, 1);
|
|
curl_easy_setopt(curl.get(), CURLOPT_POSTFIELDS, request.body.data());
|
|
curl_easy_setopt(curl.get(), CURLOPT_POSTFIELDSIZE, static_cast< u_int32_t >(request.body.size()));
|
|
curl_easy_setopt(curl.get(), CURLOPT_HEADER, 1);
|
|
curl_easy_setopt(curl.get(), CURLOPT_WRITEFUNCTION, WriteMemoryCallback);
|
|
curl_easy_setopt(curl.get(), CURLOPT_WRITEDATA, &response_data);
|
|
|
|
log(LogLevel::Debug, "Sending request to %s", uri.data());
|
|
for(const auto &[name, value] : request.headers){
|
|
log(LogLevel::Debug, "Header %s:%s", name.c_str(), value.c_str());
|
|
}
|
|
log(LogLevel::Debug, "Body %s", request.body.c_str());
|
|
|
|
const auto res = curl_easy_perform(curl.get());
|
|
|
|
if(res != CURLE_OK) {
|
|
log(LogLevel::Error, "%s no response from Rublon server err:{%s}", "CURL", curl_easy_strerror(res));
|
|
return tl::unexpected{ConnectionError{ConnectionError::Timeout, 0}};
|
|
}
|
|
|
|
long http_code = 0;
|
|
curl_easy_getinfo(curl.get(), CURLINFO_RESPONSE_CODE, &http_code);
|
|
|
|
if(http_code >= 500) {
|
|
log(LogLevel::Error, "%s response with code %d ", "CURL", http_code);
|
|
return tl::unexpected{ConnectionError{ConnectionError::HttpError, http_code}};
|
|
}
|
|
|
|
long size{};
|
|
curl_easy_getinfo(curl.get(), CURLINFO_HEADER_SIZE, &size);
|
|
|
|
details::headers(response_data, response.headers);
|
|
response.body = response_data.substr(size);
|
|
|
|
log(LogLevel::Debug, "Received %d bytes", response_data.size());
|
|
for(const auto &[name, value] : response.headers){
|
|
log(LogLevel::Debug, "Header %s:%s", name.c_str(), value.c_str());
|
|
}
|
|
log(LogLevel::Debug, "Body %s", response.body.c_str());
|
|
|
|
return response;
|
|
}
|
|
};
|
|
|
|
} // namespace rublon
|