bwi/v2.3.0 #29
@ -1,14 +1,14 @@
|
||||
#pragma once
|
||||
|
||||
#include <cctype>
|
||||
#include <rublon/memory.hpp>
|
||||
#include <rublon/error.hpp>
|
||||
#include <rublon/static_string.hpp>
|
||||
#include <rublon/utils.hpp>
|
||||
#include <type_traits>
|
||||
|
||||
template < typename T >
|
||||
constexpr bool is_static_string_v = std::is_base_of_v< rublon::details::StaticStringBase, T >;
|
||||
|
||||
static_assert(is_static_string_v< rublon::StaticString< 32 > >);
|
||||
#include <fstream>
|
||||
#include <optional>
|
||||
#include <string>
|
||||
|
||||
namespace rublon {
|
||||
class ConfigurationFactory;
|
||||
@ -16,11 +16,16 @@ class ConfigurationFactory;
|
||||
enum class FailMode { bypass, deny };
|
||||
|
||||
class Configuration {
|
||||
private:
|
||||
std::pmr::memory_resource * memoryResource;
|
||||
|
||||
public:
|
||||
Configuration() : memoryResource{memory::default_resource()} {}
|
||||
|
||||
// change to StaticString
|
||||
StaticString< 32 > systemToken{};
|
||||
StaticString< 32 > secretKey{};
|
||||
StaticString< 4096 > apiServer{};
|
||||
std::pmr::string systemToken{memoryResource};
|
||||
std::pmr::string secretKey{memoryResource};
|
||||
std::pmr::string apiServer{memoryResource};
|
||||
|
||||
int prompt{};
|
||||
bool enablePasswdEmail{};
|
||||
@ -29,168 +34,36 @@ class Configuration {
|
||||
FailMode failMode{};
|
||||
bool nonInteractiveMode{};
|
||||
|
||||
StaticString< 8 > proxyType{};
|
||||
StaticString< 4096 > proxyServer{};
|
||||
StaticString< 256 > proxyUsername{};
|
||||
StaticString< 256 > proxyPass{};
|
||||
int proxyPort{};
|
||||
bool proxyAuthRequired{};
|
||||
bool proxyEnabled{};
|
||||
std::optional< std::pmr::string > proxyType{memoryResource};
|
||||
std::optional< std::pmr::string > proxyServer{memoryResource};
|
||||
std::optional< std::pmr::string > proxyUsername{memoryResource};
|
||||
std::optional< std::pmr::string > proxyPass{memoryResource};
|
||||
std::optional< int > proxyPort{};
|
||||
bool proxyAuthRequired{}; // defaulted
|
||||
bool proxyEnabled{}; // defaulted
|
||||
};
|
||||
|
||||
namespace {
|
||||
template < class C, typename T >
|
||||
T member_ptr_t(T C::*v);
|
||||
|
||||
template < typename T >
|
||||
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 {
|
||||
class ConfigurationReader {
|
||||
public:
|
||||
ConfigurationFactory() = default;
|
||||
ConfigurationReader(std::pmr::memory_resource * memResource = memory::default_resource()) : memoryResource(memResource) {}
|
||||
|
||||
std::optional< Configuration > systemConfig() {
|
||||
memory::MonotonicStackResource< 16 * 1024 > stackResource;
|
||||
Configuration configuration{};
|
||||
|
||||
std::ifstream file(std::filesystem::path{"/etc/rublon.config"});
|
||||
// Load config from file path
|
||||
bool loadFromFile(const std::string & filepath) {
|
||||
using namespace memory::literals;
|
||||
memory::MonotonicStackResource< 8_kB > stackResource;
|
||||
std::ifstream file(filepath);
|
||||
if(not file.good())
|
||||
return std::nullopt;
|
||||
return false;
|
||||
|
||||
std::pmr::string line{&stackResource};
|
||||
line.reserve(100);
|
||||
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;
|
||||
};
|
||||
line.reserve(8000); // allocate full stack to line
|
||||
|
||||
while(std::getline(file, line)) {
|
||||
std::pmr::string key{&stackResource};
|
||||
std::pmr::string value{&stackResource};
|
||||
std::pmr::string key{memoryResource};
|
||||
std::pmr::string value{memoryResource};
|
||||
|
||||
details::trimInPlace(line);
|
||||
if(!line.length())
|
||||
continue;
|
||||
|
||||
@ -201,15 +74,147 @@ class ConfigurationFactory {
|
||||
key = line.substr(0, posEqual);
|
||||
value = line.substr(posEqual + 1);
|
||||
|
||||
parameters[std::move(key)] = std::move(value);
|
||||
keyValues[std::move(key)] = std::move(value);
|
||||
}
|
||||
|
||||
for(const auto & entry : configurationVariables) {
|
||||
if(not entry.read(&configuration, readParameterByName(entry.name)))
|
||||
return true;
|
||||
}
|
||||
|
||||
// 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 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
|
||||
|
||||
@ -172,7 +172,8 @@ class CoreHandler : public CoreHandlerInterface< CoreHandler< HttpHandler > > {
|
||||
|
||||
signRequest(request);
|
||||
std::pmr::string uri{&memoryResource};
|
||||
uri += _config.apiServer.c_str();
|
||||
uri.reserve(_config.apiServer.size() + path.size() + 1);
|
||||
uri += _config.apiServer;
|
||||
uri += path.data();
|
||||
|
||||
return http
|
||||
|
||||
@ -1,6 +1,7 @@
|
||||
#pragma once
|
||||
|
||||
#include "rublon/memory.hpp"
|
||||
#include <cstddef>
|
||||
#include <rublon/error.hpp>
|
||||
#include <rublon/utils.hpp>
|
||||
#include <rublon/configuration.hpp>
|
||||
@ -11,6 +12,7 @@
|
||||
|
||||
namespace rublon {
|
||||
|
||||
|
||||
namespace {
|
||||
size_t WriteMemoryCallback(void * contents, size_t size, size_t nmemb, void * userp) {
|
||||
const size_t realsize = size * nmemb;
|
||||
@ -60,7 +62,7 @@ class CURL {
|
||||
tl::expected< std::reference_wrapper< Response >, ConnectionError >
|
||||
request(std::string_view uri, const Request & request, Response & response) const {
|
||||
using namespace memory::literals;
|
||||
memory::Monotonic_16k_HeapResource memoryResource;
|
||||
memory::Monotonic_8k_HeapResource memoryResource;
|
||||
|
||||
std::pmr::string response_data{&memoryResource};
|
||||
response_data.reserve(4_kB);
|
||||
@ -73,16 +75,20 @@ class CURL {
|
||||
|
||||
// Optional: Build full proxy URL if proxy is enabled
|
||||
if (_config.proxyEnabled) {
|
||||
std::pmr::string proxyUrl{&memoryResource};
|
||||
proxyUrl.reserve(4_kB);
|
||||
// configuration reader check if proxy has needed fields
|
||||
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") {
|
||||
proxyUrl = _config.proxyType.c_str();
|
||||
proxyUrl = *_config.proxyType;
|
||||
proxyUrl += "://";
|
||||
proxyUrl += _config.proxyServer.c_str();
|
||||
proxyUrl += *_config.proxyServer;
|
||||
if (_config.proxyPort > 0) {
|
||||
proxyUrl += ":";
|
||||
proxyUrl += std::to_string(_config.proxyPort);
|
||||
proxyUrl += std::to_string(*_config.proxyPort);
|
||||
}
|
||||
|
||||
curl_easy_setopt(curl.get(), CURLOPT_PROXY, proxyUrl.c_str());
|
||||
@ -96,12 +102,19 @@ class CURL {
|
||||
}
|
||||
|
||||
if (_config.proxyAuthRequired) {
|
||||
assert(_config.proxyUsername.has_value());
|
||||
assert(_config.proxyPass.has_value());
|
||||
|
||||
std::pmr::string proxyAuth{&memoryResource};
|
||||
proxyAuth.reserve(1_kB);
|
||||
_config.proxyUsername.c_str();
|
||||
proxyAuth += ":";
|
||||
proxyAuth += _config.proxyPass.c_str();
|
||||
|
||||
proxyAuth.reserve(conservative_estimate(_config.proxyUsername->size() + _config.proxyPass->size()));
|
||||
|
||||
proxyAuth += *_config.proxyUsername;
|
||||
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());
|
||||
}
|
||||
}
|
||||
|
||||
@ -15,12 +15,14 @@ class ConfigurationError {
|
||||
RequiredValueNotFound,
|
||||
BadFailMode,
|
||||
BadInput,
|
||||
BadConfiguration,
|
||||
Empty
|
||||
};
|
||||
constexpr static auto errorClassPrettyName = make_array< std::string_view >( //
|
||||
"RequiredValueNotFound",
|
||||
"BadFailMode",
|
||||
"BadInput",
|
||||
"BadConfiguration",
|
||||
"Empty");
|
||||
constexpr static auto prettyName = "Configurtion Error";
|
||||
|
||||
|
||||
@ -4,16 +4,17 @@
|
||||
#include <rublon/configuration.hpp>
|
||||
#include <rublon/json.hpp>
|
||||
#include <rublon/method/method_select.hpp>
|
||||
#include <string_view>
|
||||
#include <sys/utsname.h>
|
||||
|
||||
namespace rublon {
|
||||
class Finish : public AuthenticationStep {
|
||||
const char * apiPath = "/api/transaction/credentials";
|
||||
const std::string _accessToken;
|
||||
const std::string_view _accessToken; //
|
||||
|
||||
void addAccessToken(Document & coreRequest) const {
|
||||
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 {
|
||||
@ -23,7 +24,7 @@ class Finish : public AuthenticationStep {
|
||||
public:
|
||||
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 >
|
||||
tl::expected< bool, Error > handle(const CoreHandlerInterface< Hander_t > & coreHandler) const {
|
||||
|
||||
@ -43,12 +43,11 @@ class Init : public AuthenticationStep {
|
||||
}
|
||||
|
||||
void addParams(Document & coreRequest, const Pam_t & pam) const {
|
||||
memory::MonotonicStackResource< 1024 > stackResource;
|
||||
std::pmr::string releaseInfo{&stackResource};
|
||||
memory::MonotonicStackResource< 1024 > memoryResource;
|
||||
auto & alloc = coreRequest.GetAllocator();
|
||||
|
||||
const auto os = details::osName(&stackResource);
|
||||
const auto host = details::hostname(&stackResource);
|
||||
const auto os = details::osName(&memoryResource);
|
||||
const auto host = details::hostname(&memoryResource);
|
||||
|
||||
if(os == "unknown") {
|
||||
log(LogLevel::Warning, "No OS information available");
|
||||
|
||||
@ -1,5 +1,6 @@
|
||||
#pragma once
|
||||
|
||||
#include <optional>
|
||||
#include <rublon/memory.hpp>
|
||||
#include <rublon/static_string.hpp>
|
||||
#include <rublon/stdlib.hpp>
|
||||
@ -158,6 +159,14 @@ namespace conv {
|
||||
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 details {
|
||||
@ -176,6 +185,23 @@ namespace details {
|
||||
static inline std::string_view trim(std::string_view 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 >
|
||||
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{512, '\0', mr};
|
||||
std::pmr::string hostname{2048, '\0', mr};
|
||||
if(gethostname(hostname.data(), hostname.size()) != 0) {
|
||||
log(LogLevel::Warning, "Hostname is not available");
|
||||
return "";
|
||||
@ -207,18 +233,18 @@ namespace details {
|
||||
}
|
||||
|
||||
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"});
|
||||
if(not file.good())
|
||||
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);
|
||||
|
||||
|
||||
while(std::getline(file, line)) {
|
||||
std::pmr::string _key{&stackResource};
|
||||
std::pmr::string _value{&stackResource};
|
||||
|
||||
if(!line.length())
|
||||
continue;
|
||||
@ -266,4 +292,29 @@ constexpr std::array< Out, sizeof...(Types) > make_array(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
|
||||
|
||||
@ -44,10 +44,8 @@ class WebSocket {
|
||||
RublonEventData * currentEvent{nullptr};
|
||||
|
||||
public:
|
||||
WebSocket(const Configuration & config) : _config{config}, urlv{_config.get().apiServer.c_str(), _config.get().apiServer.size()} {
|
||||
using namespace memory::literals;
|
||||
memory::Monotonic_8k_HeapResource memoryResource;
|
||||
const auto & cfg = _config.get();
|
||||
WebSocket(const Configuration & config) : _config{config}, urlv{_config.get().apiServer} {
|
||||
const auto & cfg = _config.get(); // only a alias to not use _config.get() all the time
|
||||
|
||||
auto lws_log_emit = [](int level, const char * line) {
|
||||
LogLevel rlevel{};
|
||||
@ -77,23 +75,27 @@ class WebSocket {
|
||||
context = lws_create_context(&info);
|
||||
|
||||
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};
|
||||
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 += "://";
|
||||
|
||||
if(cfg.proxyAuthRequired) {
|
||||
proxyUrl += cfg.proxyUsername.c_str();
|
||||
proxyUrl += *cfg.proxyUsername;
|
||||
proxyUrl += ":";
|
||||
proxyUrl += cfg.proxyPass.c_str();
|
||||
proxyUrl += *cfg.proxyPass;
|
||||
proxyUrl += "@";
|
||||
}
|
||||
|
||||
proxyUrl += cfg.proxyServer.c_str();
|
||||
proxyUrl += *cfg.proxyServer;
|
||||
if(cfg.proxyPort > 0) {
|
||||
proxyUrl += ":";
|
||||
proxyUrl += std::to_string(cfg.proxyPort);
|
||||
proxyUrl += std::to_string(*cfg.proxyPort);
|
||||
}
|
||||
|
||||
// Set environment variable for libwebsockets to pick up
|
||||
@ -101,7 +103,6 @@ class WebSocket {
|
||||
}
|
||||
|
||||
const std::string_view prefix = "https://";
|
||||
|
||||
if(urlv.substr(0, prefix.size()) == prefix)
|
||||
urlv.remove_prefix(prefix.size());
|
||||
|
||||
|
||||
@ -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 > {
|
||||
if(status.userAuthorized()) {
|
||||
auto tok = std::string{status.accessToken().data()};
|
||||
Finish finish{session.value(), std::move(tok)};
|
||||
finish.handle(CH);
|
||||
Finish{session.value(), status.accessToken()}.handle(CH);
|
||||
}
|
||||
return status;
|
||||
};
|
||||
@ -101,7 +99,7 @@ pam_sm_authenticate(pam_handle_t * pamh, [[maybe_unused]] int flags, [[maybe_unu
|
||||
{
|
||||
CheckApplication ca;
|
||||
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()) {
|
||||
log(LogLevel::Error, "Check Application step failed, check configration");
|
||||
return PAM_MAXTRIES;
|
||||
|
||||
Loading…
Reference in New Issue
Block a user