1 /* 2 Copyright © 2014-2019 by The qTox Project Contributors 3 4 This file is part of qTox, a Qt-based graphical interface for Tox. 5 6 qTox is libre software: you can redistribute it and/or modify 7 it under the terms of the GNU General Public License as published by 8 the Free Software Foundation, either version 3 of the License, or 9 (at your option) any later version. 10 11 qTox is distributed in the hope that it will be useful, 12 but WITHOUT ANY WARRANTY; without even the implied warranty of 13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 14 GNU General Public License for more details. 15 16 You should have received a copy of the GNU General Public License 17 along with qTox. If not, see <http://www.gnu.org/licenses/>. 18 */ 19 20 #ifndef RAWDATABASE_H 21 #define RAWDATABASE_H 22 23 #include "src/util/strongtype.h" 24 25 #include <QByteArray> 26 #include <QMutex> 27 #include <QPair> 28 #include <QQueue> 29 #include <QString> 30 #include <QThread> 31 #include <QVariant> 32 #include <QVector> 33 #include <QRegularExpression> 34 35 #include <atomic> 36 #include <cassert> 37 #include <functional> 38 #include <memory> 39 40 /// The two following defines are required to use SQLCipher 41 /// They are used by the sqlite3.h header 42 #define SQLITE_HAS_CODEC 43 #define SQLITE_TEMP_STORE 2 44 45 #include <sqlite3.h> 46 47 using RowId = NamedType<int64_t, struct RowIdTag, Orderable>; 48 Q_DECLARE_METATYPE(RowId); 49 50 class RawDatabase : QObject 51 { 52 Q_OBJECT 53 54 public: 55 class Query 56 { 57 public: 58 Query(QString query, QVector<QByteArray> blobs = {}, 59 const std::function<void(RowId)>& insertCallback = {}) 60 : query{query.toUtf8()} 61 , blobs{blobs} 62 , insertCallback{insertCallback} 63 { 64 } Query(QString query,const std::function<void (RowId)> & insertCallback)65 Query(QString query, const std::function<void(RowId)>& insertCallback) 66 : query{query.toUtf8()} 67 , insertCallback{insertCallback} 68 { 69 } Query(QString query,const std::function<void (const QVector<QVariant> &)> & rowCallback)70 Query(QString query, const std::function<void(const QVector<QVariant>&)>& rowCallback) 71 : query{query.toUtf8()} 72 , rowCallback{rowCallback} 73 { 74 } 75 Query() = default; 76 77 private: 78 QByteArray query; 79 QVector<QByteArray> blobs; 80 std::function<void(RowId)> insertCallback; 81 std::function<void(const QVector<QVariant>&)> rowCallback; 82 QVector<sqlite3_stmt*> statements; 83 84 friend class RawDatabase; 85 }; 86 87 public: 88 enum class SqlCipherParams { 89 // keep these sorted in upgrade order 90 p3_0, // SQLCipher 3.0 default encryption params 91 // SQLCipher 4.0 default params where SQLCipher 3.0 supports them, but 3.0 params where not possible. 92 // We accidentally got to this state when attemption to update all databases to 4.0 defaults even when using 93 // SQLCipher 3.x, but might as well keep using these for people with SQLCipher 3.x. 94 halfUpgradedTo4, 95 p4_0 // SQLCipher 4.0 default encryption params 96 }; 97 98 RawDatabase(const QString& path, const QString& password, const QByteArray& salt); 99 ~RawDatabase(); 100 bool isOpen(); 101 102 bool execNow(const QString& statement); 103 bool execNow(const Query& statement); 104 bool execNow(const QVector<Query>& statements); 105 106 void execLater(const QString& statement); 107 void execLater(const Query& statement); 108 void execLater(const QVector<Query>& statements); 109 110 void sync(); 111 toString(SqlCipherParams params)112 static QString toString(SqlCipherParams params) 113 { 114 switch (params) 115 { 116 case SqlCipherParams::p3_0: 117 return "3.0 default"; 118 case SqlCipherParams::halfUpgradedTo4: 119 return "3.x max compatible"; 120 case SqlCipherParams::p4_0: 121 return "4.0 default"; 122 } 123 assert(false); 124 return {}; 125 } 126 127 public slots: 128 bool setPassword(const QString& password); 129 bool rename(const QString& newPath); 130 bool remove(); 131 132 protected slots: 133 bool open(const QString& path, const QString& hexKey = {}); 134 void close(); 135 void process(); 136 137 private: 138 QString anonymizeQuery(const QByteArray& query); 139 bool openEncryptedDatabaseAtLatestSupportedVersion(const QString& hexKey); 140 bool updateSavedCipherParameters(const QString& hexKey, SqlCipherParams newParams); 141 bool setCipherParameters(SqlCipherParams params, const QString& database = {}); 142 SqlCipherParams highestSupportedParams(); 143 SqlCipherParams readSavedCipherParams(const QString& hexKey, SqlCipherParams newParams); 144 bool setKey(const QString& hexKey); 145 int getUserVersion(); 146 bool encryptDatabase(const QString& newHexKey); 147 bool decryptDatabase(); 148 bool commitDbSwap(const QString& hexKey); 149 bool testUsable(); 150 151 protected: 152 static QString deriveKey(const QString& password, const QByteArray& salt); 153 static QString deriveKey(const QString& password); 154 static QVariant extractData(sqlite3_stmt* stmt, int col); 155 static void regexpInsensitive(sqlite3_context* ctx, int argc, sqlite3_value** argv); 156 static void regexpSensitive(sqlite3_context* ctx, int argc, sqlite3_value** argv); 157 158 private: 159 static void regexp(sqlite3_context* ctx, int argc, sqlite3_value** argv, const QRegularExpression::PatternOptions cs); 160 161 struct Transaction 162 { 163 QVector<Query> queries; 164 std::atomic_bool* success = nullptr; 165 std::atomic_bool* done = nullptr; 166 }; 167 168 private: 169 sqlite3* sqlite; 170 std::unique_ptr<QThread> workerThread; 171 QQueue<Transaction> pendingTransactions; 172 QMutex transactionsMutex; 173 QString path; 174 QByteArray currentSalt; 175 QString currentHexKey; 176 }; 177 178 #endif // RAWDATABASE_H 179