diff options
| author | Nikita Kostovsky <nikita@kostovsky.me> | 2025-06-22 21:39:13 +0200 |
|---|---|---|
| committer | Nikita Kostovsky <nikita@kostovsky.me> | 2025-06-22 21:39:13 +0200 |
| commit | c9fcceb74d861525b2defec8219374edb9c1455a (patch) | |
| tree | fc10d7c2abcb08db76946e0bfd73f6b93a652422 /src/user.cpp | |
| parent | f674e179d602d3ccb9818d28fe06f371059449dc (diff) | |
add User class
Diffstat (limited to 'src/user.cpp')
| -rw-r--r-- | src/user.cpp | 123 |
1 files changed, 123 insertions, 0 deletions
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 <QCryptographicHash> +#include <QDebug> +#include <QRandomGenerator> +#include <QSqlError> +#include <QSqlQuery> + +#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<int>()) + 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); +} |
