97 lines
3.5 KiB
C++
97 lines
3.5 KiB
C++
#pragma clang diagnostic push
|
|
#pragma ide diagnostic ignored "readability-make-member-function-const"
|
|
#pragma ide diagnostic ignored "readability-convert-member-functions-to-static"
|
|
|
|
#include <chrono>
|
|
#include <iomanip>
|
|
|
|
#include <botan/argon2.h>
|
|
#include <botan/uuid.h>
|
|
#include <botan/totp.h>
|
|
|
|
#if defined(BOTAN_HAS_SYSTEM_RNG)
|
|
#include <botan/system_rng.h>
|
|
#else
|
|
#include <botan/auto_rng.h>
|
|
#endif
|
|
|
|
#include <jwt-cpp/traits/kazuho-picojson/traits.h>
|
|
#include <jwt-cpp/jwt.h>
|
|
#include <SMTPMail.h>
|
|
|
|
#include "controllers/controllers.h"
|
|
#include "db/db.h"
|
|
|
|
|
|
namespace api {
|
|
#if defined(BOTAN_HAS_SYSTEM_RNG)
|
|
std::unique_ptr<Botan::RNG> auth::rng = std::make_unique<Botan::System_RNG>();
|
|
#else
|
|
std::unique_ptr<Botan::RNG> auth::rng = std::make_unique<Botan::AutoSeeded_RNG>();
|
|
#endif
|
|
|
|
bool auth::verify2fa(const db::User& user, uint32_t totp) {
|
|
size_t allowed_skew = db::User_getEnumTfaType(user) == db::tfaTypes::TOTP ? 0 : 10;
|
|
const auto& totp_secret = (const std::vector<uint8_t>&) user.getValueOfTfaSecret();
|
|
return Botan::TOTP(Botan::OctetString(totp_secret)).verify_totp(totp, std::chrono::system_clock::now(), allowed_skew);
|
|
}
|
|
|
|
void auth::send_mail(const db::User& user) {
|
|
std::time_t t = std::time(nullptr);
|
|
const auto& totp_secret = (const std::vector<uint8_t>&) user.getValueOfTfaSecret();
|
|
char totp[16];
|
|
std::snprintf(totp, 16, "%06d", Botan::TOTP(Botan::OctetString(totp_secret)).generate_totp(t));
|
|
|
|
auto config = drogon::app().getCustomConfig();
|
|
|
|
drogon::app().getPlugin<SMTPMail>()->sendEmail(
|
|
config["smtp_server"].asString(),
|
|
(uint16_t)config["smtp_port"].asUInt64(),
|
|
"fileserver@mattv.de",
|
|
user.getValueOfName(),
|
|
"MFileserver - Email 2fa code",
|
|
"Your code is: " + std::string(totp) +"\r\nIt is valid for 5 Minutes",
|
|
config["smtp_user"].asString(),
|
|
config["smtp_password"].asString(),
|
|
false
|
|
);
|
|
}
|
|
|
|
std::string auth::get_token(const db::User& user) {
|
|
auto db = drogon::app().getDbClient();
|
|
|
|
db::MapperToken token_mapper(db);
|
|
const auto iat = std::chrono::duration_cast<std::chrono::seconds>(std::chrono::system_clock::now().time_since_epoch());
|
|
const auto exp = iat + std::chrono::hours{24};
|
|
|
|
db::Token new_token;
|
|
new_token.setOwnerId(user.getValueOfId());
|
|
new_token.setExp(exp.count());
|
|
|
|
token_mapper.insert(new_token);
|
|
|
|
return jwt::create<jwt::traits::kazuho_picojson>()
|
|
.set_type("JWT")
|
|
.set_payload_claim("sub", picojson::value((int64_t)user.getValueOfId()))
|
|
.set_payload_claim("jti", picojson::value((int64_t)new_token.getValueOfId()))
|
|
.set_issued_at(std::chrono::system_clock::from_time_t(iat.count()))
|
|
.set_expires_at(std::chrono::system_clock::from_time_t(exp.count()))
|
|
.sign(jwt::algorithm::hs256{jwt_secret});
|
|
}
|
|
|
|
void auth::generate_root(db::User& user) {
|
|
db::MapperUser user_mapper(drogon::app().getDbClient());
|
|
|
|
auto node = fs::create_node("", user, false, std::nullopt, true);
|
|
user.setRootId(std::get<db::INode>(node).getValueOfId());
|
|
user_mapper.update(user);
|
|
}
|
|
|
|
void auth::revoke_all(const db::User& user) {
|
|
db::MapperToken token_mapper(drogon::app().getDbClient());
|
|
token_mapper.deleteBy(db::Criteria(db::Token::Cols::_owner_id, db::CompareOps::EQ, user.getValueOfId()));
|
|
}
|
|
}
|
|
|
|
#pragma clang diagnostic pop
|