diff options
| -rw-r--r-- | src/atomchannel.cpp | 20 | ||||
| -rw-r--r-- | src/atomchannel.h | 4 | ||||
| -rw-r--r-- | src/constants.h | 3 | ||||
| -rw-r--r-- | src/main.cpp | 1 | ||||
| -rw-r--r-- | src/rsshit_db.cpp | 1 | ||||
| -rw-r--r-- | src/user.cpp | 95 | ||||
| -rw-r--r-- | src/user.h | 47 |
7 files changed, 134 insertions, 37 deletions
diff --git a/src/atomchannel.cpp b/src/atomchannel.cpp index 6a7c87c..95f4f0d 100644 --- a/src/atomchannel.cpp +++ b/src/atomchannel.cpp @@ -81,8 +81,8 @@ AtomChannel::AtomChannel(QXmlStreamReader *xmlReader) // TODO: move to a separate function, code is almost identical in all methods called `getDbId` int AtomChannel::getDbId() { - if (id != rsshit::db::IdNotFound) - return id; + if (m_id != rsshit::db::IdNotFound) + return m_id; const auto db = rsshit::db::open(); @@ -122,8 +122,8 @@ int AtomChannel::getDbId() // TODO: move to a separate function, code is almost identical in all methods called `createInDb` int AtomChannel::createInDb() { - if (id != rsshit::db::IdNotFound) - return id; + if (m_id != rsshit::db::IdNotFound) + return m_id; const auto db = rsshit::db::open(); @@ -142,7 +142,9 @@ int AtomChannel::createInDb() return rsshit::db::IdNotFound; } - return insertQ.lastInsertId().toInt(); + m_id = insertQ.lastInsertId().toInt(); + + return m_id; } // TODO: can be moved to IDbObject @@ -158,16 +160,16 @@ int AtomChannel::getOrInsertDbId() QList<int> AtomChannel::syncDbItems() { - if (id == rsshit::db::IdNotFound) - id = getOrInsertDbId(); + if (m_id == rsshit::db::IdNotFound) + m_id = getOrInsertDbId(); - if (id == rsshit::db::IdNotFound) + if (m_id == rsshit::db::IdNotFound) return {}; QList<int> result; for (auto &item : items) { - auto id = item.getOrInsertDbId(this->id); + auto id = item.getOrInsertDbId(this->m_id); if (id != rsshit::db::IdNotFound) result << id; diff --git a/src/atomchannel.h b/src/atomchannel.h index cde066b..7f7294a 100644 --- a/src/atomchannel.h +++ b/src/atomchannel.h @@ -49,9 +49,9 @@ public: public: /*! - * \brief id - cache db id + * \brief m_id - cache db m_id */ - int id{0}; + int m_id{0}; QString title; /*! diff --git a/src/constants.h b/src/constants.h index c27b777..bd67eda 100644 --- a/src/constants.h +++ b/src/constants.h @@ -10,6 +10,9 @@ const QString feedsTableName{"feeds"}; const QString idTag{"id"}; const QString linkTag{"link"}; +const QString loginTag{"loging"}; +const QString passwordHashTag{"password_hash"}; +const QString saltTag{"salt"}; constexpr int IdNotFound{0}; diff --git a/src/main.cpp b/src/main.cpp index 22029a9..2dab907 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -66,6 +66,7 @@ int main(int argc, char *argv[]) qDebug() << "verify password 321:" << user.verifyPassword("321"); qDebug() << "user.getDbId()" << user.getDbId(); qDebug() << "user.createInDb()" << user.createInDb(); + qDebug() << "user.createInDb()" << user.createInDb(); qDebug() << "user.createInDb()" << user.getOrInsertDbId(); qDebug() << "user.createInDb()" << user.createInDb(); diff --git a/src/rsshit_db.cpp b/src/rsshit_db.cpp index d5d2a2a..b690eaa 100644 --- a/src/rsshit_db.cpp +++ b/src/rsshit_db.cpp @@ -48,7 +48,6 @@ std::optional<QSqlDatabase> rsshit::db::open() + QFileInfo{rsshit::db::dbSqliteResourceFilename}.fileName()}; db.setDatabaseName(dbFilepath); - qDebug() << "open" << dbFilepath; if (!db.open()) { qWarning() << "cannot open db:" << db.lastError().text(); diff --git a/src/user.cpp b/src/user.cpp index 4667ebf..1c83921 100644 --- a/src/user.cpp +++ b/src/user.cpp @@ -25,19 +25,26 @@ QByteArray generateSalt() // FIXME: use better password hashing algo User::User(const QString &login, const QString &password) - : login{login} - , salt{rsshit::generateSalt()} - , passwordHash{hashPassword(password)} + : m_login{login} + , m_salt{rsshit::generateSalt()} + , m_passwordHash{hashPassword(password)} { qDebug() << __func__ << "login:" << login; - qDebug() << __func__ << "salt size:" << salt.size(); - qDebug() << __func__ << "passwordHash size:" << passwordHash.size(); + qDebug() << __func__ << "salt size:" << m_salt.size(); + qDebug() << __func__ << "passwordHash size:" << m_passwordHash.size(); } +User::User(const QString &login) + : m_login{login} +{ + fetchFromDb(); +} + +// TODO: rename to `fetchFromDb` and fill all data? int User::getDbId() { - if (id != rsshit::db::IdNotFound) - return id; + if (m_id != rsshit::db::IdNotFound) + return m_id; const auto db = rsshit::db::open(); @@ -45,7 +52,7 @@ int User::getDbId() return rsshit::db::IdNotFound; QSqlQuery selectQ{"select id from users where login=?"}; - selectQ.addBindValue(login); + selectQ.addBindValue(m_login); if (!selectQ.exec()) { qWarning() << "cannot exec query" << selectQ.lastQuery() << ":" @@ -71,26 +78,78 @@ int User::getDbId() return rsshit::db::IdNotFound; } + if (m_id != result) + m_id = result; + return result; } +int User::fetchFromDb() +{ + const auto db = rsshit::db::open(); + + if (!db) + return rsshit::db::IdNotFound; + + // ignore local `id` if exists, fetch all fields + QSqlQuery selectQ{"select id, login, salt, password_hash from users where login=?"}; + selectQ.addBindValue(m_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}; + m_id = idVariant.toInt(&ok); + + if (!ok) { + qWarning() << "got invalid id from db:" << idVariant; + + return rsshit::db::IdNotFound; + } + + if (m_id == rsshit::db::IdNotFound) + return m_id; + + m_salt = selectQ.value(rsshit::db::saltTag).toByteArray(); + m_passwordHash = selectQ.value(rsshit::db::passwordHashTag).toByteArray(); + + return m_id; +} + +bool User::existsInDb() +{ + return getDbId() != rsshit::db::IdNotFound; +} + int User::createInDb() { - if (id != rsshit::db::IdNotFound) - return id; + if (m_id != rsshit::db::IdNotFound) + return m_id; const auto db = rsshit::db::open(); if (!db) return rsshit::db::IdNotFound; - if (login.isEmpty() || salt.isEmpty() || passwordHash.isEmpty()) + if (m_login.isEmpty() || m_salt.isEmpty() || m_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); + insertQ.addBindValue(m_login); + insertQ.addBindValue(m_salt); + insertQ.addBindValue(m_passwordHash); if (!insertQ.exec()) { qWarning() << "cannot exec query" << insertQ.lastQuery() << ":" @@ -99,7 +158,9 @@ int User::createInDb() return rsshit::db::IdNotFound; } - return insertQ.lastInsertId().toInt(); + m_id = insertQ.lastInsertId().toInt(); + + return m_id; } int User::getOrInsertDbId() @@ -114,10 +175,10 @@ int User::getOrInsertDbId() bool User::verifyPassword(const QString &password) { - return hashPassword(password) == passwordHash; + return (!m_passwordHash.isEmpty()) && (hashPassword(password) == m_passwordHash); } QByteArray User::hashPassword(const QString &password) { - return QCryptographicHash::hash(salt + password.toUtf8(), QCryptographicHash::Sha256); + return QCryptographicHash::hash(m_salt + password.toUtf8(), QCryptographicHash::Sha256); } @@ -14,22 +14,53 @@ public: /*! * \brief User - create user with given `login` and `password`. `salt` and * `passwordHash` will be generated and stored instead of real `password`. - * Will *not* be committed to db automatically. + * Will *not* be committed to db automatically. Should be used to create a + * new user + * \code + * User user{"admin", "123"}; + * auto id = user.createInDb(); + * if (id == rsshit::db::IdNotFound) // error + * ... * \param login - max len is 32 * \param password - max len is 32 */ explicit User(const QString &login, const QString &password); + /*! + * \brief User - create user with given `login` and try to fetch data from db + * automatically. Should be used for existing users + * \code + * User user{"admin"}; + * if (user.getDbId() == rsshit::db::IdNotFound) // user not found + * ... + * if (!user.verifyPassword("123)) // wrong password + * ... + */ + explicit User(const QString &login); + public: /*! * \brief getDbId - check if user with corresponding `link` exists in db - * and return db id if any + * and return db id if any (fills `id` var as well) * \return id on success, 0 otherwise */ int getDbId(); /*! - * \brief createInDb - create user in db + * \brief fetchFromDb - fetch db user record with corresponding `login` + * \return existing `id` on success, 0 otherwise + */ + int fetchFromDb(); + + /*! + * \brief existsInDb - helper function, checks if `this` has valid `id`, or + * db record with corresponding `login` exists (calls `getDbId` under the hood) + * \return true if exists, false otherwise + */ + bool existsInDb(); + + /*! + * \brief createInDb - create user in db, fill `id` * \return new user id on success, 0 otherwise */ int createInDb(); @@ -43,11 +74,11 @@ public: bool verifyPassword(const QString &password); -public: - int id{0}; - QString login; - QByteArray salt; - QByteArray passwordHash; +private: + int m_id{0}; + QString m_login; + QByteArray m_salt; + QByteArray m_passwordHash; private: QByteArray hashPassword(const QString &password); |
