summaryrefslogtreecommitdiff
path: root/src/user.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'src/user.cpp')
-rw-r--r--src/user.cpp123
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);
+}