#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" #include "dto/dto.h" size_t payload_source(char* ptr, size_t size, size_t nmemb, void* userp) { auto* ss = (std::stringstream*)userp; return ss->readsome(ptr, (long)(size*nmemb)); } 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::stringstream ss; 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)); ss.imbue(std::locale("en_US.utf8")); ss << "Date: " << std::put_time(std::localtime(&t), "%a, %d %b %Y %T %z") << "\r\n"; ss << "To: " << user.getValueOfName() << "\r\n"; ss << "From: fileserver@mattv.de\r\n"; ss << "Message-ID: " << Botan::UUID(*rng).to_string() << "@mattv.de>\r\n"; ss << "Subject: Fileserver - EMail 2fa code\r\n"; ss << "Your code is: " << totp << "\r\n"; ss << "It is valid for 5 Minutes\r\n"; CURL* curl = curl_easy_init(); curl_easy_setopt(curl, CURLOPT_USERNAME, "no-reply@mattv.de"); curl_easy_setopt(curl, CURLOPT_PASSWORD, "noreplyLONGPASS123"); curl_easy_setopt(curl, CURLOPT_URL, "smtp://mail.mattv.de:587"); curl_easy_setopt(curl, CURLOPT_USE_SSL, (long)CURLUSESSL_ALL); auto recp = curl_slist_append(nullptr, user.getValueOfName().c_str()); curl_easy_setopt(curl, CURLOPT_MAIL_RCPT, recp); curl_easy_setopt(curl, CURLOPT_READFUNCTION, &payload_source); curl_easy_setopt(curl, CURLOPT_READDATA, &ss); curl_easy_setopt(curl, CURLOPT_UPLOAD, 1); curl_easy_perform(curl); curl_slist_free_all(recp); curl_easy_cleanup(curl); } 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{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())); } } #pragma clang diagnostic pop