#pragma clang diagnostic push #pragma ide diagnostic ignored "readability-make-member-function-const" #pragma ide diagnostic ignored "readability-convert-member-functions-to-static" #include #include #include #include #include #if defined(BOTAN_HAS_SYSTEM_RNG) #include #else #include #endif #include #include #include #include "controllers/controllers.h" #include "db/db.h" namespace api { #if defined(BOTAN_HAS_SYSTEM_RNG) std::unique_ptr auth::rng = std::make_unique(); #else std::unique_ptr auth::rng = std::make_unique(); #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&) 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&) 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()->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::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() .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{get_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(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())); } std::string auth::get_jwt_secret() { static std::string token; if (token.empty()) { if (!std::filesystem::exists("jwt.secret")) { auto new_token = rng->random_vec(128); std::ofstream file("jwt.secret", std::ofstream::binary); file.write((const char*)new_token.data(), (std::streamsize)new_token.size()); } std::ifstream file("jwt.secret", std::ifstream::binary); token = {std::istreambuf_iterator(file), std::istreambuf_iterator()}; } return token; } } #pragma clang diagnostic pop