88 lines
2.6 KiB
C++
88 lines
2.6 KiB
C++
|
#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;
|
||
|
}
|