123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320 |
- #pragma once
- // hyperion
- #include <db/DBManager.h>
- #include <QCryptographicHash>
- // qt
- #include <QDateTime>
- #include <QUuid>
- ///
- /// @brief Authentication table interface
- ///
- class AuthTable : public DBManager
- {
- public:
- /// construct wrapper with auth table
- AuthTable(const QString& rootPath = "", QObject* parent = nullptr, bool readonlyMode = false)
- : DBManager(parent)
- {
- setReadonlyMode(readonlyMode);
- if(!rootPath.isEmpty()){
- // Init Hyperion database usage
- setRootPath(rootPath);
- setDatabaseName("hyperion");
- }
- // init Auth table
- setTable("auth");
- // create table columns
- createTable(QStringList()<<"user TEXT"<<"password BLOB"<<"token BLOB"<<"salt BLOB"<<"comment TEXT"<<"id TEXT"<<"created_at TEXT"<<"last_use TEXT");
- };
- ///
- /// @brief Create a user record, if called on a existing user the auth is recreated
- /// @param[in] user The username
- /// @param[in] pw The password
- /// @return true on success else false
- ///
- inline bool createUser(const QString& user, const QString& pw)
- {
- // new salt
- QByteArray salt = QCryptographicHash::hash(QUuid::createUuid().toByteArray(), QCryptographicHash::Sha512).toHex();
- QVariantMap map;
- map["user"] = user;
- map["salt"] = salt;
- map["password"] = hashPasswordWithSalt(pw,salt);
- map["created_at"] = QDateTime::currentDateTimeUtc().toString(Qt::ISODate);
- VectorPair cond;
- cond.append(CPair("user",user));
- return createRecord(cond, map);
- }
- ///
- /// @brief Test if user record exists
- /// @param[in] user The user id
- /// @return true on success else false
- ///
- inline bool userExist(const QString& user)
- {
- VectorPair cond;
- cond.append(CPair("user",user));
- return recordExists(cond);
- }
- ///
- /// @brief Test if a user is authorized for access with given pw.
- /// @param user The user name
- /// @param pw The password
- /// @return True on success else false
- ///
- inline bool isUserAuthorized(const QString& user, const QString& pw)
- {
- if(userExist(user) && (calcPasswordHashOfUser(user, pw) == getPasswordHashOfUser(user)))
- {
- updateUserUsed(user);
- return true;
- }
- return false;
- }
- ///
- /// @brief Test if a user token is authorized for access.
- /// @param usr The user name
- /// @param token The token
- /// @return True on success else false
- ///
- inline bool isUserTokenAuthorized(const QString& usr, const QString& token)
- {
- if(getUserToken(usr) == token.toUtf8())
- {
- updateUserUsed(usr);
- return true;
- }
- return false;
- }
- ///
- /// @brief Update token of a user. It's an alternate login path which is replaced on startup. This token is NOT hashed(!)
- /// @param user The user name
- /// @return True on success else false
- ///
- inline bool setUserToken(const QString& user)
- {
- QVariantMap map;
- map["token"] = QCryptographicHash::hash(QUuid::createUuid().toByteArray(), QCryptographicHash::Sha512).toHex();
- VectorPair cond;
- cond.append(CPair("user", user));
- return updateRecord(cond, map);
- }
- ///
- /// @brief Get token of a user. This token is NOT hashed(!)
- /// @param user The user name
- /// @return The token
- ///
- inline const QByteArray getUserToken(const QString& user)
- {
- QVariantMap results;
- VectorPair cond;
- cond.append(CPair("user", user));
- getRecord(cond, results, QStringList()<<"token");
- return results["token"].toByteArray();
- }
- ///
- /// @brief update password of given user. The user should be tested (isUserAuthorized) to verify this change
- /// @param user The user name
- /// @param newPw The new password to set
- /// @return True on success else false
- ///
- inline bool updateUserPassword(const QString& user, const QString& newPw)
- {
- QVariantMap map;
- map["password"] = calcPasswordHashOfUser(user, newPw);
- VectorPair cond;
- cond.append(CPair("user", user));
- return updateRecord(cond, map);
- }
- ///
- /// @brief Reset password of Hyperion user !DANGER! Used in Hyperion main.cpp
- /// @return True on success else false
- ///
- inline bool resetHyperionUser()
- {
- QVariantMap map;
- map["password"] = calcPasswordHashOfUser("Hyperion", "hyperion");
- VectorPair cond;
- cond.append(CPair("user", "Hyperion"));
- return updateRecord(cond, map);
- }
- ///
- /// @brief Update 'last_use' column entry for the corresponding user
- /// @param[in] user The user to search for
- ///
- inline void updateUserUsed(const QString& user)
- {
- QVariantMap map;
- map["last_use"] = QDateTime::currentDateTimeUtc().toString(Qt::ISODate);
- VectorPair cond;
- cond.append(CPair("user", user));
- updateRecord(cond, map);
- }
- ///
- /// @brief Test if token record exists, updates last_use on success
- /// @param[in] token The token id
- /// @return true on success else false
- ///
- inline bool tokenExist(const QString& token)
- {
- QVariantMap map;
- map["last_use"] = QDateTime::currentDateTimeUtc().toString(Qt::ISODate);
- VectorPair cond;
- cond.append(CPair("token", hashToken(token)));
- if(recordExists(cond))
- {
- // update it
- createRecord(cond,map);
- return true;
- }
- return false;
- }
- ///
- /// @brief Create a new token record with comment
- /// @param[in] token The token id as plaintext
- /// @param[in] comment The comment for the token (eg a human readable identifier)
- /// @param[in] id The id for the token
- /// @return true on success else false
- ///
- inline bool createToken(const QString& token, const QString& comment, const QString& id)
- {
- QVariantMap map;
- map["comment"] = comment;
- map["id"] = idExist(id) ? QUuid::createUuid().toString().remove("{").remove("}").left(5) : id;
- map["created_at"] = QDateTime::currentDateTimeUtc().toString(Qt::ISODate);
- VectorPair cond;
- cond.append(CPair("token", hashToken(token)));
- return createRecord(cond, map);
- }
- ///
- /// @brief Delete token record by id
- /// @param[in] id The token id
- /// @return true on success else false
- ///
- inline bool deleteToken(const QString& id)
- {
- VectorPair cond;
- cond.append(CPair("id", id));
- return deleteRecord(cond);
- }
- ///
- /// @brief Rename token record by id
- /// @param[in] id The token id
- /// @param[in] comment The new comment
- /// @return true on success else false
- ///
- inline bool renameToken(const QString &id, const QString &comment)
- {
- QVariantMap map;
- map["comment"] = comment;
- VectorPair cond;
- cond.append(CPair("id", id));
- return updateRecord(cond, map);
- }
- ///
- /// @brief Get all 'comment', 'last_use' and 'id' column entries
- /// @return A vector of all lists
- ///
- inline const QVector<QVariantMap> getTokenList()
- {
- QVector<QVariantMap> results;
- getRecords(results, QStringList() << "comment" << "id" << "last_use");
- return results;
- }
- ///
- /// @brief Test if id exists
- /// @param[in] id The id
- /// @return true on success else false
- ///
- inline bool idExist(const QString& id)
- {
- VectorPair cond;
- cond.append(CPair("id", id));
- return recordExists(cond);
- }
- ///
- /// @brief Get the passwort hash of a user from db
- /// @param user The user name
- /// @return password as hash
- ///
- inline const QByteArray getPasswordHashOfUser(const QString& user)
- {
- QVariantMap results;
- VectorPair cond;
- cond.append(CPair("user", user));
- getRecord(cond, results, QStringList()<<"password");
- return results["password"].toByteArray();
- }
- ///
- /// @brief Calc the password hash of a user based on user name and password
- /// @param user The user name
- /// @param pw The password
- /// @return The calced password hash
- ///
- inline const QByteArray calcPasswordHashOfUser(const QString& user, const QString& pw)
- {
- // get salt
- QVariantMap results;
- VectorPair cond;
- cond.append(CPair("user", user));
- getRecord(cond, results, QStringList()<<"salt");
- // calc
- return hashPasswordWithSalt(pw,results["salt"].toByteArray());
- }
- ///
- /// @brief Create a password hash of plaintex password + salt
- /// @param pw The plaintext password
- /// @param salt The salt
- /// @return The password hash with salt
- ///
- inline const QByteArray hashPasswordWithSalt(const QString& pw, const QByteArray& salt)
- {
- return QCryptographicHash::hash(pw.toUtf8().append(salt), QCryptographicHash::Sha512).toHex();
- }
- ///
- /// @brief Create a token hash
- /// @param token The plaintext token
- /// @return The token hash
- ///
- inline const QByteArray hashToken(const QString& token)
- {
- return QCryptographicHash::hash(token.toUtf8(), QCryptographicHash::Sha512).toHex();
- }
- };
|