bwi/v2.3.0 #29

Merged
bartoszek merged 38 commits from bwi/v2.3.0 into main 2025-09-11 08:32:43 +00:00
9 changed files with 274 additions and 203 deletions
Showing only changes of commit e5cc1f619e - Show all commits

View File

@ -1,14 +1,14 @@
#pragma once #pragma once
#include <cctype>
#include <rublon/memory.hpp>
#include <rublon/error.hpp> #include <rublon/error.hpp>
#include <rublon/static_string.hpp> #include <rublon/static_string.hpp>
#include <rublon/utils.hpp> #include <rublon/utils.hpp>
#include <type_traits>
template < typename T > #include <fstream>
constexpr bool is_static_string_v = std::is_base_of_v< rublon::details::StaticStringBase, T >; #include <optional>
#include <string>
static_assert(is_static_string_v< rublon::StaticString< 32 > >);
namespace rublon { namespace rublon {
class ConfigurationFactory; class ConfigurationFactory;
@ -16,11 +16,16 @@ class ConfigurationFactory;
enum class FailMode { bypass, deny }; enum class FailMode { bypass, deny };
class Configuration { class Configuration {
private:
std::pmr::memory_resource * memoryResource;
public: public:
Configuration() : memoryResource{memory::default_resource()} {}
// change to StaticString // change to StaticString
StaticString< 32 > systemToken{}; std::pmr::string systemToken{memoryResource};
StaticString< 32 > secretKey{}; std::pmr::string secretKey{memoryResource};
StaticString< 4096 > apiServer{}; std::pmr::string apiServer{memoryResource};
int prompt{}; int prompt{};
bool enablePasswdEmail{}; bool enablePasswdEmail{};
@ -29,168 +34,36 @@ class Configuration {
FailMode failMode{}; FailMode failMode{};
bool nonInteractiveMode{}; bool nonInteractiveMode{};
StaticString< 8 > proxyType{}; std::optional< std::pmr::string > proxyType{memoryResource};
StaticString< 4096 > proxyServer{}; std::optional< std::pmr::string > proxyServer{memoryResource};
StaticString< 256 > proxyUsername{}; std::optional< std::pmr::string > proxyUsername{memoryResource};
StaticString< 256 > proxyPass{}; std::optional< std::pmr::string > proxyPass{memoryResource};
int proxyPort{}; std::optional< int > proxyPort{};
bool proxyAuthRequired{}; bool proxyAuthRequired{}; // defaulted
bool proxyEnabled{}; bool proxyEnabled{}; // defaulted
}; };
namespace {
template < class C, typename T >
T member_ptr_t(T C::*v);
template < typename T > class ConfigurationReader {
tl::expected< T, ConfigurationError > to(std::string_view);
template < class T >
auto to_string(std::string_view arg) -> tl::expected< T, ConfigurationError > {
T value{};
assert(arg.size() <= (value.size() - 1));
std::memcpy(value.data(), arg.data(), arg.size());
return value;
}
template <>
auto to(std::string_view arg) -> tl::expected< bool, ConfigurationError > {
return conv::to_bool(arg);
}
template <>
auto to(std::string_view arg) -> tl::expected< int, ConfigurationError > {
return conv::to_uint32(arg).value_or(0);
}
template <>
auto to(std::string_view arg) -> tl::expected< FailMode, ConfigurationError > {
if(arg == "bypass")
return FailMode::bypass;
if(arg == "deny")
return FailMode::deny;
return tl::unexpected{ConfigurationError{ConfigurationError::ErrorClass::BadFailMode}};
}
template < typename T >
auto parse(std::string_view arg) -> tl::expected< T, ConfigurationError > {
if(arg.empty()) {
return tl::unexpected{ConfigurationError::ErrorClass::Empty};
} else {
if constexpr(is_static_string_v< T >) {
return to_string< T >(arg);
} else {
return to< T >(arg);
}
}
}
} // namespace
struct Entry {
enum class Source { UserInput, DefaultValue };
template < auto member >
static constexpr auto make_read_function() {
using pType = decltype(member_ptr_t(member));
return
[](const Entry * _this, Configuration * configuration, std::string_view userInput) -> tl::expected< Source, ConfigurationError > {
const auto setDefaultValue = [&](const ConfigurationError & error) -> tl::expected< Source, ConfigurationError > {
log(LogLevel::Warning, "applying user provided value for %s parameter, faild with %s", _this->name, error.what());
if(_this->defaultValue != nullptr) {
configuration->*member = parse< pType >(_this->defaultValue).value();
return Source::DefaultValue;
} else {
log(LogLevel::Error, "parameter %s has not been found and has no default value", _this->name);
if(userInput.empty())
return tl::unexpected{ConfigurationError::ErrorClass::RequiredValueNotFound};
else
return tl::unexpected{ConfigurationError::ErrorClass::BadInput};
}
};
const auto saveValue = [&](const auto & value) -> tl::expected< Source, ConfigurationError > {
configuration->*member = value;
return Source::UserInput;
};
return parse< pType >(userInput).and_then(saveValue).or_else(setDefaultValue);
};
}
const char * name;
const char * defaultValue;
tl::expected< Source, ConfigurationError > (*_read)(const Entry * _this, Configuration * configuration, std::string_view userInput);
bool read(Configuration * configuration, std::optional< std::string_view > userInput) const {
constexpr const auto emptyString = "";
const auto logStored = [&](const auto & source) -> tl::expected< Source, ConfigurationError > {
rublon::log(LogLevel::Debug,
"Configuration parameter '%s' was set to '%s'%s",
this->name,
this->defaultValue,
source == Source::DefaultValue ? " (default)" : "");
return source;
};
const auto logError = [&](const auto & error) -> tl::expected< Source, ConfigurationError > {
rublon::log(LogLevel::Error,
"Configuration parameter '%s' has no default value and is not provided in user configuraion, aborting",
this->name);
return tl::unexpected{error};
};
return _read(this, configuration, userInput.value_or(emptyString)).and_then(logStored).or_else(logError).has_value();
}
};
template < auto member >
constexpr auto make_entry(const char * name, const char * defaultValue) {
return Entry{name, defaultValue, Entry::make_read_function< member >()};
}
constexpr static inline std::array< Entry, 16 > configurationVariables = {
make_entry< &Configuration::logging >("logging", "true"),
make_entry< &Configuration::systemToken >("systemToken", nullptr),
make_entry< &Configuration::secretKey >("secretKey", nullptr),
make_entry< &Configuration::apiServer >("rublonApiServer", nullptr),
make_entry< &Configuration::prompt >("prompt", "1"),
make_entry< &Configuration::enablePasswdEmail >("enablePasswdEmail", "true"),
make_entry< &Configuration::autopushPrompt >("autopushPrompt", "false"),
make_entry< &Configuration::failMode >("failMode", "deny"),
make_entry< &Configuration::nonInteractiveMode >("nonInteractiveMode", "false"),
make_entry< &Configuration::proxyType >("proxyType", nullptr),
make_entry< &Configuration::proxyServer >("proxyServer", nullptr),
make_entry< &Configuration::proxyUsername >("proxyUsername", nullptr),
make_entry< &Configuration::proxyPass >("proxyPass", nullptr),
make_entry< &Configuration::proxyPort >("proxyPort", "8080"),
make_entry< &Configuration::proxyAuthRequired >("proxyAuthRequired", "false"),
make_entry< &Configuration::proxyEnabled >("proxyEnabled", "false") //
};
class ConfigurationFactory {
public: public:
ConfigurationFactory() = default; ConfigurationReader(std::pmr::memory_resource * memResource = memory::default_resource()) : memoryResource(memResource) {}
std::optional< Configuration > systemConfig() { // Load config from file path
memory::MonotonicStackResource< 16 * 1024 > stackResource; bool loadFromFile(const std::string & filepath) {
Configuration configuration{}; using namespace memory::literals;
memory::MonotonicStackResource< 8_kB > stackResource;
std::ifstream file(std::filesystem::path{"/etc/rublon.config"}); std::ifstream file(filepath);
if(not file.good()) if(not file.good())
return std::nullopt; return false;
std::pmr::string line{&stackResource}; std::pmr::string line{&stackResource};
line.reserve(100); line.reserve(8000); // allocate full stack to line
std::pmr::map< std::pmr::string, std::pmr::string > parameters{&stackResource};
const auto readParameterByName = [&](std::string_view name) -> std::optional< std::string_view > {
return parameters.count(name.data()) ? std::optional< std::string_view >{parameters.at(name.data())} : std::nullopt;
};
while(std::getline(file, line)) { while(std::getline(file, line)) {
std::pmr::string key{&stackResource}; std::pmr::string key{memoryResource};
std::pmr::string value{&stackResource}; std::pmr::string value{memoryResource};
details::trimInPlace(line);
if(!line.length()) if(!line.length())
continue; continue;
@ -201,15 +74,147 @@ class ConfigurationFactory {
key = line.substr(0, posEqual); key = line.substr(0, posEqual);
value = line.substr(posEqual + 1); value = line.substr(posEqual + 1);
parameters[std::move(key)] = std::move(value); keyValues[std::move(key)] = std::move(value);
} }
for(const auto & entry : configurationVariables) { return true;
if(not entry.read(&configuration, readParameterByName(entry.name))) }
// Load values into Configuration object, with defaults provided
tl::expected< bool, ConfigurationError > applyTo(Configuration & config) {
// Helper lambdas for conversion
using string = std::pmr::string;
auto getStringOpt = [&](const string & key) -> std::optional< std::pmr::string > {
auto it = keyValues.find(key);
if(it == keyValues.end()) {
return std::nullopt; return std::nullopt;
}
return string{it->second.data(), it->second.size(), memoryResource};
};
auto getStringReq = [&](const string & key) -> tl::expected< std::pmr::string, ConfigurationError > {
auto val = getStringOpt(key);
if(val.has_value())
return std::move(val.value());
return tl::unexpected{ConfigurationError::ErrorClass::RequiredValueNotFound};
};
auto getInt = [&](const string & key) -> std::optional< int > {
auto it = keyValues.find(key);
if(it == keyValues.end())
return std::nullopt;
return conv::to_uint32opt(it->second);
};
auto getBool = [&](const string & key) -> std::optional< bool > {
memory::MonotonicStackResource< 64 > memoryResource;
auto it = keyValues.find(key);
if(it == keyValues.end())
return std::nullopt;
if (it->second.size() > 5 ){
log(LogLevel::Warning, "Configuration value %s is too long, please check", key.c_str());
return std::nullopt;
}
std::pmr::string val{&memoryResource};
val = it->second;
std::transform(val.begin(), val.end(), val.begin(), [](unsigned char c) { return static_cast< char >(std::tolower(c)); });
if(val == "1" || val == "true" || val == "yes" || val == "on")
return true;
if(val == "0" || val == "false" || val == "no" || val == "off")
return false;
return std::nullopt;
};
auto getFailMode = [&](const string & key) -> std::optional< FailMode > {
auto it = keyValues.find(key);
if(it == keyValues.end())
return std::nullopt;
auto val = it->second;
if(val == "bypass")
return FailMode::bypass;
if(val == "deny")
return FailMode::deny;
return std::nullopt;
};
// Reading required fields
if(auto val = getStringReq("systemToken"); not val.has_value())
return tl::unexpected{val.error()};
else
config.systemToken = std::move(val.value());
if(auto val = getStringReq("secretKey"); not val.has_value())
return tl::unexpected{val.error()};
else
config.secretKey = std::move(val.value());
if(auto val = getStringReq("rublonApiServer"); not val.has_value())
return tl::unexpected{val.error()};
else
config.apiServer = std::move(val.value());
// optional
config.prompt = getInt("prompt").value_or(1);
config.enablePasswdEmail = getBool("enablePasswdEmail").value_or(true);
config.logging = getBool("logging").value_or(true);
config.autopushPrompt = getBool("autopushPrompt").value_or(false);
config.nonInteractiveMode = getBool("nonInteractiveMode").value_or(false);
config.failMode = getFailMode("failMode").value_or(FailMode::deny);
// reading proxy configuration
config.proxyEnabled = getBool("proxyEnabled").value_or(false);
config.proxyType = getStringOpt("proxyType");
config.proxyServer = getStringOpt("proxyServer");
if(config.proxyEnabled) {
if(not config.proxyType) {
log(LogLevel::Error, "Proxy is enabled but proxy type is not set");
return tl::unexpected{ConfigurationError::ErrorClass::BadConfiguration};
}
if(not config.proxyServer) {
log(LogLevel::Error, "Proxy is enabled but proxy server is not set");
return tl::unexpected{ConfigurationError::ErrorClass::BadConfiguration};
}
}
config.proxyAuthRequired = getBool("proxyAuthRequired").value_or(false);
config.proxyUsername = getStringOpt("proxyUsername");
config.proxyPass = getStringOpt("proxyPass");
if(config.proxyAuthRequired) {
if(not config.proxyUsername) {
log(LogLevel::Error, "Proxy auth is required but proxy proxy username is not set");
return tl::unexpected{ConfigurationError::ErrorClass::BadConfiguration};
}
if(not config.proxyPass) {
log(LogLevel::Error, "Proxy is enabled but proxy password is not set,");
return tl::unexpected{ConfigurationError::ErrorClass::BadConfiguration};
}
} }
return configuration; config.proxyPort = getInt("proxyPort").value_or(8080);
return true;
}
private:
std::pmr::memory_resource * memoryResource;
std::pmr::map< std::pmr::string, std::pmr::string > keyValues{memoryResource};
};
class ConfigurationFactory {
public:
ConfigurationFactory() = default;
std::optional< Configuration > systemConfig() {
std::optional< Configuration > conf{Configuration{}};
ConfigurationReader reader;
reader.loadFromFile("/etc/rublon.config");
if(auto ok = reader.applyTo(conf.value()); not ok.has_value()){
return std::nullopt;
}
return conf.value();
} }
}; };
} // namespace rublon } // namespace rublon

View File

@ -172,7 +172,8 @@ class CoreHandler : public CoreHandlerInterface< CoreHandler< HttpHandler > > {
signRequest(request); signRequest(request);
std::pmr::string uri{&memoryResource}; std::pmr::string uri{&memoryResource};
uri += _config.apiServer.c_str(); uri.reserve(_config.apiServer.size() + path.size() + 1);
uri += _config.apiServer;
uri += path.data(); uri += path.data();
return http return http

View File

@ -1,6 +1,7 @@
#pragma once #pragma once
#include "rublon/memory.hpp" #include "rublon/memory.hpp"
#include <cstddef>
#include <rublon/error.hpp> #include <rublon/error.hpp>
#include <rublon/utils.hpp> #include <rublon/utils.hpp>
#include <rublon/configuration.hpp> #include <rublon/configuration.hpp>
@ -11,6 +12,7 @@
namespace rublon { namespace rublon {
namespace { namespace {
size_t WriteMemoryCallback(void * contents, size_t size, size_t nmemb, void * userp) { size_t WriteMemoryCallback(void * contents, size_t size, size_t nmemb, void * userp) {
const size_t realsize = size * nmemb; const size_t realsize = size * nmemb;
@ -60,7 +62,7 @@ class CURL {
tl::expected< std::reference_wrapper< Response >, ConnectionError > tl::expected< std::reference_wrapper< Response >, ConnectionError >
request(std::string_view uri, const Request & request, Response & response) const { request(std::string_view uri, const Request & request, Response & response) const {
using namespace memory::literals; using namespace memory::literals;
memory::Monotonic_16k_HeapResource memoryResource; memory::Monotonic_8k_HeapResource memoryResource;
std::pmr::string response_data{&memoryResource}; std::pmr::string response_data{&memoryResource};
response_data.reserve(4_kB); response_data.reserve(4_kB);
@ -73,16 +75,20 @@ class CURL {
// Optional: Build full proxy URL if proxy is enabled // Optional: Build full proxy URL if proxy is enabled
if (_config.proxyEnabled) { if (_config.proxyEnabled) {
std::pmr::string proxyUrl{&memoryResource}; // configuration reader check if proxy has needed fields
proxyUrl.reserve(4_kB); assert(_config.proxyType.has_value());
assert(_config.proxyServer.has_value());
std::pmr::string proxyUrl{&memoryResource};
proxyUrl.reserve(conservative_estimate(_config.proxyType, _config.proxyServer, _config.proxyPort) + 10);
if (_config.proxyType == "http" || _config.proxyType == "https" || _config.proxyType == "socks4" || _config.proxyType == "socks5") { if (_config.proxyType == "http" || _config.proxyType == "https" || _config.proxyType == "socks4" || _config.proxyType == "socks5") {
proxyUrl = _config.proxyType.c_str(); proxyUrl = *_config.proxyType;
proxyUrl += "://"; proxyUrl += "://";
proxyUrl += _config.proxyServer.c_str(); proxyUrl += *_config.proxyServer;
if (_config.proxyPort > 0) { if (_config.proxyPort > 0) {
proxyUrl += ":"; proxyUrl += ":";
proxyUrl += std::to_string(_config.proxyPort); proxyUrl += std::to_string(*_config.proxyPort);
} }
curl_easy_setopt(curl.get(), CURLOPT_PROXY, proxyUrl.c_str()); curl_easy_setopt(curl.get(), CURLOPT_PROXY, proxyUrl.c_str());
@ -96,12 +102,19 @@ class CURL {
} }
if (_config.proxyAuthRequired) { if (_config.proxyAuthRequired) {
assert(_config.proxyUsername.has_value());
assert(_config.proxyPass.has_value());
std::pmr::string proxyAuth{&memoryResource}; std::pmr::string proxyAuth{&memoryResource};
proxyAuth.reserve(1_kB); proxyAuth.reserve(conservative_estimate(_config.proxyUsername->size() + _config.proxyPass->size()));
_config.proxyUsername.c_str();
proxyAuth += ":"; proxyAuth += *_config.proxyUsername;
proxyAuth += _config.proxyPass.c_str(); if(_config.proxyPass->size()) {
// can proxy have name but no pass?
proxyAuth += ":";
proxyAuth += *_config.proxyPass;
}
curl_easy_setopt(curl.get(), CURLOPT_PROXYUSERPWD, proxyAuth.c_str()); curl_easy_setopt(curl.get(), CURLOPT_PROXYUSERPWD, proxyAuth.c_str());
} }
} }

View File

@ -15,12 +15,14 @@ class ConfigurationError {
RequiredValueNotFound, RequiredValueNotFound,
BadFailMode, BadFailMode,
BadInput, BadInput,
BadConfiguration,
Empty Empty
}; };
constexpr static auto errorClassPrettyName = make_array< std::string_view >( // constexpr static auto errorClassPrettyName = make_array< std::string_view >( //
"RequiredValueNotFound", "RequiredValueNotFound",
"BadFailMode", "BadFailMode",
"BadInput", "BadInput",
"BadConfiguration",
"Empty"); "Empty");
constexpr static auto prettyName = "Configurtion Error"; constexpr static auto prettyName = "Configurtion Error";

View File

@ -4,16 +4,17 @@
#include <rublon/configuration.hpp> #include <rublon/configuration.hpp>
#include <rublon/json.hpp> #include <rublon/json.hpp>
#include <rublon/method/method_select.hpp> #include <rublon/method/method_select.hpp>
#include <string_view>
#include <sys/utsname.h> #include <sys/utsname.h>
namespace rublon { namespace rublon {
class Finish : public AuthenticationStep { class Finish : public AuthenticationStep {
const char * apiPath = "/api/transaction/credentials"; const char * apiPath = "/api/transaction/credentials";
const std::string _accessToken; const std::string_view _accessToken; //
void addAccessToken(Document & coreRequest) const { void addAccessToken(Document & coreRequest) const {
auto & alloc = coreRequest.GetAllocator(); auto & alloc = coreRequest.GetAllocator();
coreRequest.AddMember("accessToken", Value{_accessToken.c_str(), alloc}, alloc); coreRequest.AddMember("accessToken", Value{_accessToken.data(), alloc}, alloc);
} }
tl::expected< bool, Error > returnOk(const Document & /*coreResponse*/) const { tl::expected< bool, Error > returnOk(const Document & /*coreResponse*/) const {
@ -23,7 +24,7 @@ class Finish : public AuthenticationStep {
public: public:
const char * name = "Finalization"; const char * name = "Finalization";
Finish(Session & session, std::string accessToken) : AuthenticationStep(session), _accessToken{std::move(accessToken)} {} Finish(Session & session, std::string_view accessToken) : AuthenticationStep(session), _accessToken{accessToken} {}
template < typename Hander_t > template < typename Hander_t >
tl::expected< bool, Error > handle(const CoreHandlerInterface< Hander_t > & coreHandler) const { tl::expected< bool, Error > handle(const CoreHandlerInterface< Hander_t > & coreHandler) const {

View File

@ -43,12 +43,11 @@ class Init : public AuthenticationStep {
} }
void addParams(Document & coreRequest, const Pam_t & pam) const { void addParams(Document & coreRequest, const Pam_t & pam) const {
memory::MonotonicStackResource< 1024 > stackResource; memory::MonotonicStackResource< 1024 > memoryResource;
std::pmr::string releaseInfo{&stackResource};
auto & alloc = coreRequest.GetAllocator(); auto & alloc = coreRequest.GetAllocator();
const auto os = details::osName(&stackResource); const auto os = details::osName(&memoryResource);
const auto host = details::hostname(&stackResource); const auto host = details::hostname(&memoryResource);
if(os == "unknown") { if(os == "unknown") {
log(LogLevel::Warning, "No OS information available"); log(LogLevel::Warning, "No OS information available");

View File

@ -1,5 +1,6 @@
#pragma once #pragma once
#include <optional>
#include <rublon/memory.hpp> #include <rublon/memory.hpp>
#include <rublon/static_string.hpp> #include <rublon/static_string.hpp>
#include <rublon/stdlib.hpp> #include <rublon/stdlib.hpp>
@ -158,6 +159,14 @@ namespace conv {
return tl::make_unexpected(Error::OutOfRange); return tl::make_unexpected(Error::OutOfRange);
} }
} }
inline std::optional< std::uint32_t> to_uint32opt(std::string_view userinput) noexcept {
try {
return std::stoi(userinput.data());
} catch(...) {
return std::nullopt;
}
}
} // namespace conv } // namespace conv
namespace details { namespace details {
@ -176,6 +185,23 @@ namespace details {
static inline std::string_view trim(std::string_view s) { static inline std::string_view trim(std::string_view s) {
return ltrim(rtrim(s)); return ltrim(rtrim(s));
} }
template<typename StrT>
void trimInPlace(StrT & s) {
// Remove leading whitespace
size_t start = 0;
while(start < s.size() && isspace(static_cast< unsigned char >(s[start])))
++start;
// Remove trailing whitespace
size_t end = s.size();
while(end > start && isspace(static_cast< unsigned char >(s[end - 1])))
--end;
if(start > 0 || end < s.size()) {
s = s.substr(start, end - start);
}
}
template < typename Headers > template < typename Headers >
inline void headers(std::string_view data, Headers & headers) { inline void headers(std::string_view data, Headers & headers) {
@ -197,7 +223,7 @@ namespace details {
} }
std::pmr::string hostname(std::pmr::memory_resource * mr) { std::pmr::string hostname(std::pmr::memory_resource * mr) {
std::pmr::string hostname{512, '\0', mr}; std::pmr::string hostname{2048, '\0', mr};
if(gethostname(hostname.data(), hostname.size()) != 0) { if(gethostname(hostname.data(), hostname.size()) != 0) {
log(LogLevel::Warning, "Hostname is not available"); log(LogLevel::Warning, "Hostname is not available");
return ""; return "";
@ -207,18 +233,18 @@ namespace details {
} }
std::pmr::string osName(std::pmr::memory_resource * mr) { std::pmr::string osName(std::pmr::memory_resource * mr) {
memory::MonotonicStackResource< 8 * 1024 > stackResource; memory::Monotonic_8k_HeapResource memoryResource;
std::ifstream file(std::filesystem::path{"/etc/os-release"}); std::ifstream file(std::filesystem::path{"/etc/os-release"});
if(not file.good()) if(not file.good())
return {"unknown", mr}; return {"unknown", mr};
std::pmr::string line{&stackResource}; std::pmr::string line{&memoryResource};
std::pmr::string _key{&memoryResource};
std::pmr::string _value{&memoryResource};
line.reserve(100); line.reserve(100);
while(std::getline(file, line)) { while(std::getline(file, line)) {
std::pmr::string _key{&stackResource};
std::pmr::string _value{&stackResource};
if(!line.length()) if(!line.length())
continue; continue;
@ -266,4 +292,29 @@ constexpr std::array< Out, sizeof...(Types) > make_array(Types... names) {
return {std::forward< Types >(names)...}; return {std::forward< Types >(names)...};
} }
template <typename T> std::size_t size_buffer(const T &item) {
using U = std::decay_t<T>;
if constexpr (std::is_same_v<U, const char *>) {
return strlen(item);
} else if constexpr(std::is_same_v< U, std::pmr::string > || std::is_same_v< U, std::string >) {
return item.size();
} else if constexpr(std::is_integral_v< U > || std::is_floating_point_v< U >) {
return std::numeric_limits<U>::digits;
}
return 0;
}
template <typename T> std::size_t size_buffer(const std::optional<T> &item) {
if(item.has_value())
return size_buffer(*item);
return 0;
}
// min + 10%
template < typename... Args >
std::size_t conservative_estimate(const Args &... args) {
auto min = (size_buffer(args) + ...);
return min + min * 10 / 100;
}
} // namespace rublon } // namespace rublon

View File

@ -44,10 +44,8 @@ class WebSocket {
RublonEventData * currentEvent{nullptr}; RublonEventData * currentEvent{nullptr};
public: public:
WebSocket(const Configuration & config) : _config{config}, urlv{_config.get().apiServer.c_str(), _config.get().apiServer.size()} { WebSocket(const Configuration & config) : _config{config}, urlv{_config.get().apiServer} {
using namespace memory::literals; const auto & cfg = _config.get(); // only a alias to not use _config.get() all the time
memory::Monotonic_8k_HeapResource memoryResource;
const auto & cfg = _config.get();
auto lws_log_emit = [](int level, const char * line) { auto lws_log_emit = [](int level, const char * line) {
LogLevel rlevel{}; LogLevel rlevel{};
@ -77,23 +75,27 @@ class WebSocket {
context = lws_create_context(&info); context = lws_create_context(&info);
if(cfg.proxyEnabled && (cfg.proxyType == "http" || cfg.proxyType == "https")) { if(cfg.proxyEnabled && (cfg.proxyType == "http" || cfg.proxyType == "https")) {
assert(cfg.proxyType.has_value());
assert(cfg.proxyServer.has_value());
memory::Monotonic_8k_HeapResource memoryResource;
std::pmr::string proxyUrl{&memoryResource}; std::pmr::string proxyUrl{&memoryResource};
proxyUrl.reserve(4_kB); proxyUrl.reserve(conservative_estimate(cfg.proxyUsername, cfg.proxyPass, cfg.proxyServer, cfg.proxyPort) + 10);
proxyUrl += cfg.proxyType.data(); proxyUrl += cfg.proxyType->data();
proxyUrl += "://"; proxyUrl += "://";
if(cfg.proxyAuthRequired) { if(cfg.proxyAuthRequired) {
proxyUrl += cfg.proxyUsername.c_str(); proxyUrl += *cfg.proxyUsername;
proxyUrl += ":"; proxyUrl += ":";
proxyUrl += cfg.proxyPass.c_str(); proxyUrl += *cfg.proxyPass;
proxyUrl += "@"; proxyUrl += "@";
} }
proxyUrl += cfg.proxyServer.c_str(); proxyUrl += *cfg.proxyServer;
if(cfg.proxyPort > 0) { if(cfg.proxyPort > 0) {
proxyUrl += ":"; proxyUrl += ":";
proxyUrl += std::to_string(cfg.proxyPort); proxyUrl += std::to_string(*cfg.proxyPort);
} }
// Set environment variable for libwebsockets to pick up // Set environment variable for libwebsockets to pick up
@ -101,7 +103,6 @@ class WebSocket {
} }
const std::string_view prefix = "https://"; const std::string_view prefix = "https://";
if(urlv.substr(0, prefix.size()) == prefix) if(urlv.substr(0, prefix.size()) == prefix)
urlv.remove_prefix(prefix.size()); urlv.remove_prefix(prefix.size());

View File

@ -83,9 +83,7 @@ pam_sm_authenticate(pam_handle_t * pamh, [[maybe_unused]] int flags, [[maybe_unu
auto finalizeTransaction = [&](const AuthenticationStatus & status) mutable -> tl::expected< AuthenticationStatus, Error > { auto finalizeTransaction = [&](const AuthenticationStatus & status) mutable -> tl::expected< AuthenticationStatus, Error > {
if(status.userAuthorized()) { if(status.userAuthorized()) {
auto tok = std::string{status.accessToken().data()}; Finish{session.value(), status.accessToken()}.handle(CH);
Finish finish{session.value(), std::move(tok)};
finish.handle(CH);
} }
return status; return status;
}; };
@ -101,7 +99,7 @@ pam_sm_authenticate(pam_handle_t * pamh, [[maybe_unused]] int flags, [[maybe_unu
{ {
CheckApplication ca; CheckApplication ca;
const auto & config = session.value().config(); const auto & config = session.value().config();
const auto ret = ca.call(CH, {config.systemToken.data(), config.systemToken.size()}).or_else(mapError); const auto ret = ca.call(CH, config.systemToken).or_else(mapError);
if(not ret.has_value()) { if(not ret.has_value()) {
log(LogLevel::Error, "Check Application step failed, check configration"); log(LogLevel::Error, "Check Application step failed, check configration");
return PAM_MAXTRIES; return PAM_MAXTRIES;