#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