#include "server_internal.hxx" std::shared_ptr<Token> Server::get_token(const std::string &token) { std::shared_lock lock{token_lock}; const auto &entry = tokens.find(token); if (entry == tokens.end()) return nullptr; return entry->second; } std::shared_ptr<User> Server::get_user(std::uint64_t id) { std::shared_lock lock{user_lock}; const auto &entry = users.find(id); if (entry == users.end()) return nullptr; return entry->second; } std::shared_ptr<User> Server::is_token_valid(const std::string &token) { auto t = get_token(token); if (!t) return nullptr; if (Token::clock::now() <= t->expire) { t->refresh(); return t->user; } { std::unique_lock lock{token_lock}; tokens.erase(token); } return nullptr; } void Server::logout_user(std::uint64_t id) { std::unique_lock lock{token_lock}; for (auto it = tokens.begin(); it != tokens.end();) { if (it->second->user->id == id) tokens.erase(it++); else ++it; } } void Server::delete_user(const std::shared_ptr<User> &user) { std::unique_lock lock{user_lock}; logout_user(user->id); delete_node(user, 0, [](const std::string&){}); users.erase(user->id); } void Server::send_tfa_mail(const std::shared_ptr<User> &user) { std::lock_guard lock{mail_otp_lock}; std::string code; code.reserve(10); for (int i = 0; i < 10; ++i) { auto j = auth_rng->next_byte(); while (j > 249) j = auth_rng->next_byte(); code.push_back('0' + (j%10)); } mail_otp.emplace(code, std::make_pair(user->id, Token::clock::now() + std::chrono::minutes{10})); send_mail(user->name, "MFileserver - TFA code", "Your code is: " + code + "\r\nIt is valid for 10 minutes"); } bool Server::check_mail_code(const std::shared_ptr<User> &user, const std::string &code) { std::lock_guard lock{mail_otp_lock}; auto now = Token::clock::now(); for (auto it = mail_otp.begin(); it != mail_otp.end();) { if (now >= it->second.second) mail_otp.erase(it++); else ++it; } const auto &entry = mail_otp.find(code); bool ok = entry != mail_otp.end() && entry->second.first == user->id; if (ok) mail_otp.erase(code); return ok; } bool Server::check_tfa_code(const std::shared_ptr<User> &user, const std::string &code_str) { Botan::OctetString secret{user->tfa_secret}; Botan::TOTP totp{secret}; try { std::uint32_t code = std::stoul(code_str); return totp.verify_totp(code, std::chrono::system_clock::now(), 1); } catch (std::exception &_) {} return false; }