AuthTable.h 8.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320
  1. #pragma once
  2. // hyperion
  3. #include <db/DBManager.h>
  4. #include <QCryptographicHash>
  5. // qt
  6. #include <QDateTime>
  7. #include <QUuid>
  8. ///
  9. /// @brief Authentication table interface
  10. ///
  11. class AuthTable : public DBManager
  12. {
  13. public:
  14. /// construct wrapper with auth table
  15. AuthTable(const QString& rootPath = "", QObject* parent = nullptr, bool readonlyMode = false)
  16. : DBManager(parent)
  17. {
  18. setReadonlyMode(readonlyMode);
  19. if(!rootPath.isEmpty()){
  20. // Init Hyperion database usage
  21. setRootPath(rootPath);
  22. setDatabaseName("hyperion");
  23. }
  24. // init Auth table
  25. setTable("auth");
  26. // create table columns
  27. createTable(QStringList()<<"user TEXT"<<"password BLOB"<<"token BLOB"<<"salt BLOB"<<"comment TEXT"<<"id TEXT"<<"created_at TEXT"<<"last_use TEXT");
  28. };
  29. ///
  30. /// @brief Create a user record, if called on a existing user the auth is recreated
  31. /// @param[in] user The username
  32. /// @param[in] pw The password
  33. /// @return true on success else false
  34. ///
  35. inline bool createUser(const QString& user, const QString& pw)
  36. {
  37. // new salt
  38. QByteArray salt = QCryptographicHash::hash(QUuid::createUuid().toByteArray(), QCryptographicHash::Sha512).toHex();
  39. QVariantMap map;
  40. map["user"] = user;
  41. map["salt"] = salt;
  42. map["password"] = hashPasswordWithSalt(pw,salt);
  43. map["created_at"] = QDateTime::currentDateTimeUtc().toString(Qt::ISODate);
  44. VectorPair cond;
  45. cond.append(CPair("user",user));
  46. return createRecord(cond, map);
  47. }
  48. ///
  49. /// @brief Test if user record exists
  50. /// @param[in] user The user id
  51. /// @return true on success else false
  52. ///
  53. inline bool userExist(const QString& user)
  54. {
  55. VectorPair cond;
  56. cond.append(CPair("user",user));
  57. return recordExists(cond);
  58. }
  59. ///
  60. /// @brief Test if a user is authorized for access with given pw.
  61. /// @param user The user name
  62. /// @param pw The password
  63. /// @return True on success else false
  64. ///
  65. inline bool isUserAuthorized(const QString& user, const QString& pw)
  66. {
  67. if(userExist(user) && (calcPasswordHashOfUser(user, pw) == getPasswordHashOfUser(user)))
  68. {
  69. updateUserUsed(user);
  70. return true;
  71. }
  72. return false;
  73. }
  74. ///
  75. /// @brief Test if a user token is authorized for access.
  76. /// @param usr The user name
  77. /// @param token The token
  78. /// @return True on success else false
  79. ///
  80. inline bool isUserTokenAuthorized(const QString& usr, const QString& token)
  81. {
  82. if(getUserToken(usr) == token.toUtf8())
  83. {
  84. updateUserUsed(usr);
  85. return true;
  86. }
  87. return false;
  88. }
  89. ///
  90. /// @brief Update token of a user. It's an alternate login path which is replaced on startup. This token is NOT hashed(!)
  91. /// @param user The user name
  92. /// @return True on success else false
  93. ///
  94. inline bool setUserToken(const QString& user)
  95. {
  96. QVariantMap map;
  97. map["token"] = QCryptographicHash::hash(QUuid::createUuid().toByteArray(), QCryptographicHash::Sha512).toHex();
  98. VectorPair cond;
  99. cond.append(CPair("user", user));
  100. return updateRecord(cond, map);
  101. }
  102. ///
  103. /// @brief Get token of a user. This token is NOT hashed(!)
  104. /// @param user The user name
  105. /// @return The token
  106. ///
  107. inline const QByteArray getUserToken(const QString& user)
  108. {
  109. QVariantMap results;
  110. VectorPair cond;
  111. cond.append(CPair("user", user));
  112. getRecord(cond, results, QStringList()<<"token");
  113. return results["token"].toByteArray();
  114. }
  115. ///
  116. /// @brief update password of given user. The user should be tested (isUserAuthorized) to verify this change
  117. /// @param user The user name
  118. /// @param newPw The new password to set
  119. /// @return True on success else false
  120. ///
  121. inline bool updateUserPassword(const QString& user, const QString& newPw)
  122. {
  123. QVariantMap map;
  124. map["password"] = calcPasswordHashOfUser(user, newPw);
  125. VectorPair cond;
  126. cond.append(CPair("user", user));
  127. return updateRecord(cond, map);
  128. }
  129. ///
  130. /// @brief Reset password of Hyperion user !DANGER! Used in Hyperion main.cpp
  131. /// @return True on success else false
  132. ///
  133. inline bool resetHyperionUser()
  134. {
  135. QVariantMap map;
  136. map["password"] = calcPasswordHashOfUser("Hyperion", "hyperion");
  137. VectorPair cond;
  138. cond.append(CPair("user", "Hyperion"));
  139. return updateRecord(cond, map);
  140. }
  141. ///
  142. /// @brief Update 'last_use' column entry for the corresponding user
  143. /// @param[in] user The user to search for
  144. ///
  145. inline void updateUserUsed(const QString& user)
  146. {
  147. QVariantMap map;
  148. map["last_use"] = QDateTime::currentDateTimeUtc().toString(Qt::ISODate);
  149. VectorPair cond;
  150. cond.append(CPair("user", user));
  151. updateRecord(cond, map);
  152. }
  153. ///
  154. /// @brief Test if token record exists, updates last_use on success
  155. /// @param[in] token The token id
  156. /// @return true on success else false
  157. ///
  158. inline bool tokenExist(const QString& token)
  159. {
  160. QVariantMap map;
  161. map["last_use"] = QDateTime::currentDateTimeUtc().toString(Qt::ISODate);
  162. VectorPair cond;
  163. cond.append(CPair("token", hashToken(token)));
  164. if(recordExists(cond))
  165. {
  166. // update it
  167. createRecord(cond,map);
  168. return true;
  169. }
  170. return false;
  171. }
  172. ///
  173. /// @brief Create a new token record with comment
  174. /// @param[in] token The token id as plaintext
  175. /// @param[in] comment The comment for the token (eg a human readable identifier)
  176. /// @param[in] id The id for the token
  177. /// @return true on success else false
  178. ///
  179. inline bool createToken(const QString& token, const QString& comment, const QString& id)
  180. {
  181. QVariantMap map;
  182. map["comment"] = comment;
  183. map["id"] = idExist(id) ? QUuid::createUuid().toString().remove("{").remove("}").left(5) : id;
  184. map["created_at"] = QDateTime::currentDateTimeUtc().toString(Qt::ISODate);
  185. VectorPair cond;
  186. cond.append(CPair("token", hashToken(token)));
  187. return createRecord(cond, map);
  188. }
  189. ///
  190. /// @brief Delete token record by id
  191. /// @param[in] id The token id
  192. /// @return true on success else false
  193. ///
  194. inline bool deleteToken(const QString& id)
  195. {
  196. VectorPair cond;
  197. cond.append(CPair("id", id));
  198. return deleteRecord(cond);
  199. }
  200. ///
  201. /// @brief Rename token record by id
  202. /// @param[in] id The token id
  203. /// @param[in] comment The new comment
  204. /// @return true on success else false
  205. ///
  206. inline bool renameToken(const QString &id, const QString &comment)
  207. {
  208. QVariantMap map;
  209. map["comment"] = comment;
  210. VectorPair cond;
  211. cond.append(CPair("id", id));
  212. return updateRecord(cond, map);
  213. }
  214. ///
  215. /// @brief Get all 'comment', 'last_use' and 'id' column entries
  216. /// @return A vector of all lists
  217. ///
  218. inline const QVector<QVariantMap> getTokenList()
  219. {
  220. QVector<QVariantMap> results;
  221. getRecords(results, QStringList() << "comment" << "id" << "last_use");
  222. return results;
  223. }
  224. ///
  225. /// @brief Test if id exists
  226. /// @param[in] id The id
  227. /// @return true on success else false
  228. ///
  229. inline bool idExist(const QString& id)
  230. {
  231. VectorPair cond;
  232. cond.append(CPair("id", id));
  233. return recordExists(cond);
  234. }
  235. ///
  236. /// @brief Get the passwort hash of a user from db
  237. /// @param user The user name
  238. /// @return password as hash
  239. ///
  240. inline const QByteArray getPasswordHashOfUser(const QString& user)
  241. {
  242. QVariantMap results;
  243. VectorPair cond;
  244. cond.append(CPair("user", user));
  245. getRecord(cond, results, QStringList()<<"password");
  246. return results["password"].toByteArray();
  247. }
  248. ///
  249. /// @brief Calc the password hash of a user based on user name and password
  250. /// @param user The user name
  251. /// @param pw The password
  252. /// @return The calced password hash
  253. ///
  254. inline const QByteArray calcPasswordHashOfUser(const QString& user, const QString& pw)
  255. {
  256. // get salt
  257. QVariantMap results;
  258. VectorPair cond;
  259. cond.append(CPair("user", user));
  260. getRecord(cond, results, QStringList()<<"salt");
  261. // calc
  262. return hashPasswordWithSalt(pw,results["salt"].toByteArray());
  263. }
  264. ///
  265. /// @brief Create a password hash of plaintex password + salt
  266. /// @param pw The plaintext password
  267. /// @param salt The salt
  268. /// @return The password hash with salt
  269. ///
  270. inline const QByteArray hashPasswordWithSalt(const QString& pw, const QByteArray& salt)
  271. {
  272. return QCryptographicHash::hash(pw.toUtf8().append(salt), QCryptographicHash::Sha512).toHex();
  273. }
  274. ///
  275. /// @brief Create a token hash
  276. /// @param token The plaintext token
  277. /// @return The token hash
  278. ///
  279. inline const QByteArray hashToken(const QString& token)
  280. {
  281. return QCryptographicHash::hash(token.toUtf8(), QCryptographicHash::Sha512).toHex();
  282. }
  283. };