From c9fcceb74d861525b2defec8219374edb9c1455a Mon Sep 17 00:00:00 2001 From: Nikita Kostovsky Date: Sun, 22 Jun 2025 21:39:13 +0200 Subject: add User class --- src/user.cpp | 123 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 123 insertions(+) create mode 100644 src/user.cpp (limited to 'src/user.cpp') diff --git a/src/user.cpp b/src/user.cpp new file mode 100644 index 0000000..4667ebf --- /dev/null +++ b/src/user.cpp @@ -0,0 +1,123 @@ +#include "user.h" + +#include +#include +#include +#include +#include + +#include "constants.h" +#include "rsshit_db.h" + +namespace rsshit { +QByteArray generateSalt() +{ + constexpr qsizetype hashSizeBytes{32}; + + QByteArray saltArray{hashSizeBytes, char{0}}; + + auto generator = QRandomGenerator::global(); + generator->fillRange((uint32_t *) saltArray.data(), hashSizeBytes); + + return saltArray; +} +} // namespace rsshit + +// FIXME: use better password hashing algo +User::User(const QString &login, const QString &password) + : login{login} + , salt{rsshit::generateSalt()} + , passwordHash{hashPassword(password)} +{ + qDebug() << __func__ << "login:" << login; + qDebug() << __func__ << "salt size:" << salt.size(); + qDebug() << __func__ << "passwordHash size:" << passwordHash.size(); +} + +int User::getDbId() +{ + if (id != rsshit::db::IdNotFound) + return id; + + const auto db = rsshit::db::open(); + + if (!db) + return rsshit::db::IdNotFound; + + QSqlQuery selectQ{"select id from users where login=?"}; + selectQ.addBindValue(login); + + if (!selectQ.exec()) { + qWarning() << "cannot exec query" << selectQ.lastQuery() << ":" + << selectQ.lastError().text(); + + return rsshit::db::IdNotFound; + } + + if (!selectQ.next()) + return rsshit::db::IdNotFound; + + const auto idVariant = selectQ.value(rsshit::db::idTag); + + if (!idVariant.isValid() || !idVariant.canConvert()) + return rsshit::db::IdNotFound; + + bool ok{false}; + const auto result = idVariant.toInt(&ok); + + if (!ok) { + qWarning() << "got invalid id from db:" << idVariant; + + return rsshit::db::IdNotFound; + } + + return result; +} + +int User::createInDb() +{ + if (id != rsshit::db::IdNotFound) + return id; + + const auto db = rsshit::db::open(); + + if (!db) + return rsshit::db::IdNotFound; + + if (login.isEmpty() || salt.isEmpty() || passwordHash.isEmpty()) + return rsshit::db::IdNotFound; + + QSqlQuery insertQ{"insert into users(login, salt, password_hash) values(?, ?, ?)"}; + insertQ.addBindValue(login); + insertQ.addBindValue(salt); + insertQ.addBindValue(passwordHash); + + if (!insertQ.exec()) { + qWarning() << "cannot exec query" << insertQ.lastQuery() << ":" + << insertQ.lastError().text(); + + return rsshit::db::IdNotFound; + } + + return insertQ.lastInsertId().toInt(); +} + +int User::getOrInsertDbId() +{ + const auto id = getDbId(); + + if (id != rsshit::db::IdNotFound) + return id; + + return createInDb(); +} + +bool User::verifyPassword(const QString &password) +{ + return hashPassword(password) == passwordHash; +} + +QByteArray User::hashPassword(const QString &password) +{ + return QCryptographicHash::hash(salt + password.toUtf8(), QCryptographicHash::Sha256); +} -- cgit v1.2.3-70-g09d2