Implementation of the WebServer entity in the Secure Login example

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