main.cpp
#include "authhandler.h"
#include "authresulthandler.h"
#include "general.h"
#include "kos_connector.h"
#include <CivetServer.h>
#include <connections.h>
#include <kos_net.h>
#include <cstring>
#include <iostream>
#include <memory>
#include <sys/mount.h>
#include <sys/stat.h>
#include <sys/types.h>
#include <openssl/rand.h>
#include <unistd.h>
namespace consts {
constexpr const char *AuthUri = "/auth";
constexpr const char *AuthResultUri = "/authresult";
constexpr const char *DocumentRoot = "/mnt";
constexpr const char *Port = "1106";
} // namespace consts
// Exit flag for main loop
volatile bool exitNow = false;
std::vector<std::string> SetOptions()
{
constexpr const char *Options[] = {
"document_root",
consts::DocumentRoot,
"listening_ports",
consts::Port,
0};
std::vector<std::string> cppOptions;
for (size_t i = 0; i < (sizeof(Options) / sizeof(Options[0]) - 1); ++i)
{
cppOptions.push_back(Options[i]);
}
return cppOptions;
}
static int mountFolders()
{
if (mkdir("/dev", S_IRWXU | S_IRWXG | S_IRWXO) != 0)
{
std::cerr << app::AppTag << "Error: Failed to create \"/dev\" dir\n"
<< std::endl;
return false;
}
// mount /dev/urandom
if (mount("devfs", "/dev", "devfs", 0, "") != 0)
{
std::cerr << "Failed to mount devfs /dev, devfs (error " << errno
<< ": " << strerror(errno) << ")" << std::endl;
return false;
}
// mount filesystem
if (mkdir(consts::DocumentRoot, S_IRWXU | S_IRWXG | S_IRWXO) != 0)
{
std::cerr << app::AppTag << "Failed to create " << consts::DocumentRoot
<< " dir" << std::endl;
return false;
}
else if (mount("romfs", consts::DocumentRoot, "romfs", 0, "") != 0)
{
std::cerr << app::AppTag << "Failed mount romfs to "
<< consts::DocumentRoot << " dir" << std::endl;
return false;
}
return true;
}
void Run(const std::vector<std::string> &cppOptions, KosConnectorPtr connector)
{
CivetServer server(cppOptions);
AuthHandler hAuth(connector);
server.addHandler(consts::AuthUri, hAuth);
AuthResultHandler hAuthResult(connector);
server.addHandler(consts::AuthResultUri, hAuthResult);
std::cout << app::AppTag << "WebServer started (port: " << consts::Port
<< ")" << std::endl;
while (!exitNow)
{
sleep(1);
}
std::cout << app::AppTag << "WebServer stoped" << std::endl;
}
int main(int argc, char *argv[])
{
if (!wait_for_network())
{
std::cerr << app::AppTag << "Error: Wait for network failed!"
<< std::endl;
return EXIT_FAILURE;
}
if (!mountFolders())
{
std::cerr << app::AppTag << "Error: Unable to mount folders!"
<< std::endl;
return EXIT_FAILURE;
}
auto kosCon = std::make_shared<KosConnector>();
if (!kosCon->Connect())
{
std::cerr << app::AppTag
<< "Error: Unable to establish IPS connection to "
"authentication server."
<< std::endl;
return EXIT_FAILURE;
}
mg_init_library(0);
auto options = SetOptions();
Run(options, kosCon);
mg_exit_library();
return EXIT_SUCCESS;
}
authhandler.cpp
#include "authhandler.h"
#include "general.h"
#include "log.h"
#include <fstream>
#include <iostream>
#include <map>
#include <string.h>
#include <strstream>
#include <variant>
AuthHandler::AuthHandler(ipc::ILoginFormReaderPtr loginReader)
: m_comExecutor(loginReader)
{}
bool AuthHandler::handleGet(CivetServer *server, struct mg_connection *conn)
{
log::Log(conn);
mg_printf(
conn,
"HTTP/1.1 200 OK\r\nContent-Type: "
"text/html\r\nConnection: close\r\n\r\n");
if (!m_comExecutor->OpenLoginStream())
{
std::cerr
<< app::AppTag
<< "Error: Unable to open HTML stream from authentication server!"
<< std::endl;
return false;
}
for (bool isEof = false;;)
{
std::string htmlLine;
if (!m_comExecutor->ReadLoginLine(htmlLine, isEof))
{
std::cerr
<< app::AppTag
<< "Error: Unable to get HTML line from authentication server!"
<< std::endl;
break;
}
mg_printf(conn, "%s\r\n", htmlLine.c_str());
if (isEof)
{
break;
}
}
if (!m_comExecutor->DisposeLogin())
{
std::cerr << app::AppTag
<< "Error: Unable to close HTML stream of the authentication "
"server!"
<< std::endl;
return false;
}
return true;
}
authresulthandler.cpp
#include "authresulthandler.h"
#include "general.h"
#include "log.h"
#include <fstream>
#include <iostream>
AuthResultHandler::AuthResultHandler(ipc::IResultFormReaderPtr reader)
: m_reader(reader)
{}
std::string AuthResultHandler::GetParam(
struct mg_connection *conn, const std::string &key) const
{
std::string value;
if (!CivetServer::getParam(conn, key.c_str(), value))
{
return "";
}
return value;
}
bool AuthResultHandler::handleGet(
CivetServer *server, struct mg_connection *conn)
{
log::Log(conn);
std::string userName = GetParam(conn, "username");
std::string cryptoPassword = GetParam(conn, "password");
std::string cryptoB = GetParam(conn, "cryptoB");
mg_printf(
conn,
"HTTP/1.1 200 OK\r\nContent-Type: "
"text/html\r\nConnection: close\r\n\r\n");
if (!m_reader->OpenResultStream(userName, cryptoPassword, cryptoB))
{
std::cerr
<< app::AppTag << __func__
<< " Error: Unable to open HTML stream from authentication server!"
<< std::endl;
return false;
}
for (bool isEof = false;;)
{
std::string htmlLine;
if (!m_reader->ReadResultLine(htmlLine, isEof))
{
std::cerr
<< app::AppTag << __func__
<< " Error: Unable to get HTML line from authentication server!"
<< std::endl;
break;
}
mg_printf(conn, "%s\r\n", htmlLine.c_str());
if (isEof)
{
break;
}
}
if (!m_reader->DisposeResult())
{
std::cerr << app::AppTag << __func__
<< " Error: Unable to close HTML stream of the "
"authentication server!"
<< std::endl;
return false;
}
return true;
}
kos_connector.cpp
#include "kos_connector.h"
#include "connections.h"
#include "general.h"
#include <rtl/string.h>
#include <iostream>
constexpr const char *Tag = "[KosConnector] ";
namespace utils {
nk_err_t StringToArena(const std::string &str, nk_arena *arena, nk_ptr_t *dst)
{
nk_char_t *nk_str = nk_arena_alloc(nk_char_t, arena, dst, str.length() + 1);
if (nk_str == nullptr)
{
return NK_ENOMEM;
}
rtl_strncpy(nk_str, str.c_str(), str.length() + 1);
return NK_EOK;
}
} // namespace utils
bool KosConnector::Connect()
{
auto handle = ServiceLocatorConnect(connections::ConnectionName);
if (handle == INVALID_HANDLE)
{
std::cerr
<< app::AppTag << Tag
<< "Error: can`t establish static IPC connection! Connection Name: "
<< connections::ConnectionName << std::endl;
return false;
}
NkKosTransport_Init(&m_transport, handle, NK_NULL, 0);
// Init runtime implementations of ILoginForm
{
nk_iid_t riid =
ServiceLocatorGetRiid(handle, connections::LoginConnectionPoint);
if (riid == INVALID_RIID)
{
std::cerr << app::AppTag
<< "Error: can`t get runtime implementation ID (RIID) of "
"interface '"
<< connections::LoginConnectionPoint << "'" << std::endl;
return false;
}
auth_service_ILoginForm_proxy_init(
&m_loginFormProxy, &m_transport.base, riid);
}
// Init runtime implementations of ILoginResultForm
{
nk_iid_t riid =
ServiceLocatorGetRiid(handle, connections::ResultConnectionPoint);
if (riid == INVALID_RIID)
{
std::cerr << app::AppTag
<< "Error: can`t get runtime implementation ID (RIID) of "
"interface '"
<< connections::ResultConnectionPoint << "'" << std::endl;
return false;
}
auth_service_ILoginResultForm_proxy_init(
&m_loginResultFormProxy, &m_transport.base, riid);
}
return true;
}
bool KosConnector::OpenLoginStream()
{
auth_service_ILoginForm_Open_req req;
auth_service_ILoginForm_Open_res response;
char resBuffer[auth_service_ILoginForm_Open_res_arena_size + 1];
nk_arena resArena =
NK_ARENA_INITIALIZER(resBuffer, resBuffer + sizeof(resBuffer));
auto code = auth_service_ILoginForm_Open(
&m_loginFormProxy.base, &req, nullptr, &response, &resArena);
bool result = false;
if (code == NK_EOK)
{
result = response.result;
}
return code == NK_EOK && result;
}
bool KosConnector::ReadLoginLine(std::string &htmlLine, bool &isEof)
{
auth_service_ILoginForm_Read_req req;
auth_service_ILoginForm_Read_res response;
char resBuffer[auth_service_ILoginForm_Read_res_arena_size];
nk_arena resArena =
NK_ARENA_INITIALIZER(resBuffer, resBuffer + sizeof(resBuffer));
auto code = auth_service_ILoginForm_Read(
&m_loginFormProxy.base, &req, nullptr, &response, &resArena);
if (code == NK_EOK)
{
uint64_t msgLen = 0;
nk_char_t *msgPtr =
nk_arena_get(nk_char_t, &resArena, &response.line, &msgLen);
htmlLine = msgPtr != nullptr ? msgPtr : "";
isEof = htmlLine.empty();
}
return code == NK_EOK;
}
bool KosConnector::DisposeLogin()
{
auth_service_ILoginForm_Dispose_req req;
auth_service_ILoginForm_Dispose_res response;
auto code = auth_service_ILoginForm_Dispose(
&m_loginFormProxy.base, &req, nullptr, &response, nullptr);
return code == NK_EOK;
}
bool KosConnector::OpenResultStream(
const std::string &userName,
const std::string &password,
const std::string &cryptoB)
{
auth_service_ILoginResultForm_Open_req req;
char reqBuffer[auth_service_ILoginResultForm_Open_req_arena_size];
nk_arena reqArena =
NK_ARENA_INITIALIZER(reqBuffer, reqBuffer + sizeof(reqBuffer));
auth_service_ILoginResultForm_Open_res response;
char resBuffer[auth_service_ILoginForm_Open_res_arena_size];
nk_arena resArena =
NK_ARENA_INITIALIZER(resBuffer, resBuffer + sizeof(resBuffer));
if (auto code =
utils::StringToArena(userName, &reqArena, &req.login.userName);
code != NK_EOK)
{
std::cerr << app::AppTag << __func__
<< " Error: unable to allocate space of \
arena request for user name. User name: '"
<< userName << "'!" << std::endl;
return code;
}
if (auto code =
utils::StringToArena(password, &reqArena, &req.login.password);
code != NK_EOK)
{
std::cerr << app::AppTag << __func__
<< " Error: unable to allocate space of \
arena request for user password. Password: '"
<< password << "'!" << std::endl;
return code;
}
if (auto code =
utils::StringToArena(cryptoB, &reqArena, &req.login.cryptoB);
code != NK_EOK)
{
std::cerr << app::AppTag << __func__
<< " Error: unable to allocate space of \
arena request for B-value. B-value = '"
<< cryptoB << "'!" << std::endl;
return code;
}
auto code = auth_service_ILoginResultForm_Open(
&m_loginResultFormProxy.base, &req, &reqArena, &response, &resArena);
return code == NK_EOK;
}
bool KosConnector::ReadResultLine(std::string &htmlLine, bool &isEof)
{
auth_service_ILoginResultForm_Read_req req;
auth_service_ILoginResultForm_Read_res response;
char resBuffer[auth_service_ILoginResultForm_Read_res_arena_size];
nk_arena resArena =
NK_ARENA_INITIALIZER(resBuffer, resBuffer + sizeof(resBuffer));
auto code = auth_service_ILoginResultForm_Read(
&m_loginResultFormProxy.base, &req, nullptr, &response, &resArena);
if (code == NK_EOK)
{
uint64_t msgLen = 0;
nk_char_t *msgPtr =
nk_arena_get(nk_char_t, &resArena, &response.line, &msgLen);
htmlLine = msgPtr != nullptr ? msgPtr : "";
isEof = htmlLine.empty();
}
return code == NK_EOK;
}
bool KosConnector::DisposeResult()
{
auth_service_ILoginResultForm_Dispose_req req;
auth_service_ILoginResultForm_Dispose_res response;
auto code = auth_service_ILoginResultForm_Dispose(
&m_loginResultFormProxy.base, &req, nullptr, &response, nullptr);
return code == NK_EOK;
}
log.cpp
#include "log.h"
#include "general.h"
#include <iostream>
void log::Log(const mg_connection *conn)
{
if(conn == nullptr)
return;
const mg_request_info *ri = mg_get_request_info(conn);
if (ri == nullptr)
return;
std::cout << app::AppTag << " ==> "
<< " Local URL: " << ri->local_uri
<< " Query: " << ri->query_string
<< std::endl;
}
Page top