// SPDX-FileCopyrightText: 2023 Yury Gubich // SPDX-License-Identifier: GPL-3.0-or-later #include "server.h" #include #include "handler/info.h" #include "handler/env.h" #include "handler/register.h" constexpr const char* pepper = "well, not much of a secret, huh?"; constexpr uint8_t currentDbVesion = 1; constexpr const char* randomChars = "0123456789abcdef"; constexpr uint8_t saltSize = 16; constexpr uint8_t hashSize = 32; constexpr uint8_t hashParallel = 1; constexpr uint8_t hashIterations = 2; constexpr uint32_t hashMemoryCost = 65536; Server::Server(): terminating(false), requestCount(0), serverName(std::nullopt), router(), db() { std::cout << "Startig pica..." << std::endl; db = DBInterface::create(DBInterface::Type::mysql); std::cout << "Database type: MySQL" << std::endl; db->setCredentials("pica", "pica"); db->setDatabase("pica"); db->connect("/run/mysqld/mysqld.sock"); db->migrate(currentDbVesion); router.addRoute(std::make_unique()); router.addRoute(std::make_unique()); router.addRoute(std::make_unique(this)); } Server::~Server() {} void Server::run(int socketDescriptor) { while (!terminating) { std::unique_ptr request = std::make_unique(); bool result = request->wait(socketDescriptor); if (!result) { std::cerr << "Error accepting a request" << std::endl; return; } handleRequest(std::move(request)); } } void Server::handleRequest(std::unique_ptr request) { ++requestCount; if (!serverName) { try { serverName = request->getServerName(); std::cout << "received server name " << serverName.value() << std::endl; } catch (...) { std::cerr << "failed to read server name" << std::endl; Response error(*request.get(), Response::Status::internalError); error.send(); return; } } std::string path = request->getPath(serverName.value()); router.route(path.data(), std::move(request)); } std::string Server::generateRandomString(std::size_t length) { std::random_device rd; std::mt19937 gen(rd()); std::uniform_int_distribution distribution(0, std::strlen(randomChars)); std::string result(length, 0); for (size_t i = 0; i < length; ++i) result[i] = randomChars[distribution(gen)]; return result; } unsigned int Server::registerAccount(const std::string& login, const std::string& password) { std::size_t encSize = argon2_encodedlen( hashIterations, hashMemoryCost, hashParallel, saltSize, hashSize, Argon2_id ); std::string hash(encSize, 0); std::string salt = generateRandomString(saltSize); std::string spiced = password + pepper; int result = argon2id_hash_encoded( hashIterations, hashMemoryCost, hashParallel, spiced.data(), spiced.size(), salt.data(), saltSize, hashSize, hash.data(), encSize ); if (result != ARGON2_OK) throw std::runtime_error(std::string("Hashing failed: ") + argon2_error_message(result)); return db->registerAccount(login, hash); }