rublon-ssh/PAM/ssh/include/rublon/utils.hpp
2023-07-21 14:41:20 +02:00

162 lines
4.5 KiB
C++

#pragma once
#include <algorithm>
#include <array>
#include <cctype>
#include <cstring>
#include <map>
#include <memory>
#include <memory_resource>
#include <sstream>
#include <string_view>
#include <alloca.h>
#include <cassert>
#include <security/pam_appl.h>
#include <security/pam_modules.h>
#include <syslog.h>
namespace rublon {
enum LogLevel { Debug, Info, Warning, Error };
inline auto dateStr() {
std::array< char, 32 > date;
time_t now;
time(&now);
strftime(date.data(), date.size(), "%FT%TZ", gmtime(&now));
return date;
}
constexpr const char* LogLevelNames[] {"Debug", "Info", "Warning", "Error"};
static LogLevel g_level = Debug;
namespace details{
static void doLog(LogLevel level, const char * line) noexcept {
constexpr auto file_name = "/var/log/rublon-ssh.log";
auto fp = std::unique_ptr< FILE, int (*)(FILE *) >(fopen(file_name, "a"), fclose);
if(fp) {
fprintf(fp.get(), "%s [%s] %s\n", dateStr().data(), LogLevelNames[(int)level], line);
}
}
}
inline void log(LogLevel level, const char * line) noexcept {
if(level > g_level)
return;
details::doLog(level, line);
}
template < typename... Ti >
void log(LogLevel level, const char * fmt, Ti &&... ti) noexcept {
if(level > g_level)
return;
std::array< char, 1000 > line;
sprintf(line.data(), fmt, std::forward< Ti >(ti)...);
details::doLog(level, line.data());
}
template < typename T >
class NonOwningPtr {
T * object;
public:
constexpr NonOwningPtr(T * obj) : object{obj} {}
constexpr T * get() noexcept {
assert(object != nullptr);
return object;
}
constexpr const T * get() const noexcept {
assert(object != nullptr);
return object;
}
constexpr operator const T *() const noexcept {
return get();
}
constexpr operator T *() noexcept {
return get();
}
constexpr T * operator->() {
return get();
}
constexpr const T * operator->() const {
return get();
}
};
namespace details {
inline bool to_bool(std::string_view value) {
auto * buf = ( char * ) alloca(value.size());
buf[value.size()] = '\0';
auto asciitolower = [](char in) { return in - ((in <= 'Z' && in >= 'A') ? ('Z' - 'z') : 0); };
std::transform(value.cbegin(), value.cend(), buf, asciitolower);
return strcmp(buf, "true") == 0;
};
static inline std::string_view ltrim(std::string_view s) {
while(s.length() && std::isspace(*s.begin()))
s.remove_prefix(1);
return s;
}
static inline std::string_view rtrim(std::string_view s) {
while(s.length() && std::isspace(*s.rbegin()))
s.remove_suffix(1);
return s;
}
static inline std::string_view trim(std::string_view s) {
return ltrim(rtrim(s));
}
inline std::map< std::string, std::string > headers(std::string_view data) {
std::map< std::string, std::string > headers{};
std::string tmp{};
std::istringstream resp{};
resp.rdbuf()->pubsetbuf(const_cast< char * >(data.data()), data.size());
while(std::getline(resp, tmp)) {
auto line = std::string_view(tmp);
auto index = tmp.find(':', 0);
if(index != std::string::npos) {
headers.insert({std::string{trim(line.substr(0, index))}, std::string{trim(line.substr(index + 1))}});
}
}
return headers;
}
namespace pmr {
inline std::pmr::map< std::pmr::string, std::pmr::string > headers(std::pmr::memory_resource * mr, std::string_view data) {
char _buf[1024];
std::pmr::monotonic_buffer_resource tmr{_buf, sizeof(_buf)};
std::pmr::map< std::pmr::string, std::pmr::string > headers{mr};
std::pmr::string tmp{&tmr};
std::istringstream resp{};
resp.rdbuf()->pubsetbuf(const_cast< char * >(data.data()), data.size());
while(std::getline(resp, tmp) && !(trim(tmp).empty())) {
auto line = std::string_view(tmp);
auto index = tmp.find(':', 0);
if(index != std::string::npos) {
headers.insert({std::pmr::string{trim(line.substr(0, index)), mr}, std::pmr::string{trim(line.substr(index + 1)), mr}});
}
}
return headers;
}
} // namespace pmr
} // namespace details
} // namespace rublon