qTox  Version: nightly | Commit: bc751c8e1cac455f9690654fcfe0f560d2d7dfdd
rawdatabase.h
Go to the documentation of this file.
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 #pragma once
21 
22 #include "util/strongtype.h"
23 
24 #include <QByteArray>
25 #include <QMutex>
26 #include <QPair>
27 #include <QQueue>
28 #include <QString>
29 #include <QThread>
30 #include <QVariant>
31 #include <QVector>
32 #include <QRegularExpression>
33 
34 #include <atomic>
35 #include <cassert>
36 #include <functional>
37 #include <memory>
38 
41 #define SQLITE_HAS_CODEC
42 #define SQLITE_TEMP_STORE 2
43 
44 #pragma GCC diagnostic push
45 #pragma GCC diagnostic ignored "-Wzero-as-null-pointer-constant"
46 #include <sqlite3.h>
47 #pragma GCC diagnostic pop
48 
49 using RowId = NamedType<int64_t, struct RowIdTag, Orderable>;
51 
52 class RawDatabase : QObject
53 {
54  Q_OBJECT
55 
56 public:
57  class Query
58  {
59  public:
60  Query(QString query, QVector<QByteArray> blobs = {},
61  const std::function<void(RowId)>& insertCallback = {})
62  : query{query.toUtf8()}
63  , blobs{blobs}
64  , insertCallback{insertCallback}
65  {
66  }
67  Query(QString query, const std::function<void(RowId)>& insertCallback)
68  : query{query.toUtf8()}
69  , insertCallback{insertCallback}
70  {
71  }
72  Query(QString query, const std::function<void(const QVector<QVariant>&)>& rowCallback)
73  : query{query.toUtf8()}
74  , rowCallback{rowCallback}
75  {
76  }
77  Query() = default;
78 
79  private:
80  QByteArray query;
81  QVector<QByteArray> blobs;
82  std::function<void(RowId)> insertCallback;
83  std::function<void(const QVector<QVariant>&)> rowCallback;
84  QVector<sqlite3_stmt*> statements;
85 
86  friend class RawDatabase;
87  };
88 
89 public:
90  enum class SqlCipherParams {
91  // keep these sorted in upgrade order
92  p3_0, // SQLCipher 3.0 default encryption params
93  // SQLCipher 4.0 default params where SQLCipher 3.0 supports them, but 3.0 params where not possible.
94  // We accidentally got to this state when attemption to update all databases to 4.0 defaults even when using
95  // SQLCipher 3.x, but might as well keep using these for people with SQLCipher 3.x.
96  halfUpgradedTo4,
97  p4_0 // SQLCipher 4.0 default encryption params
98  };
99 
100  RawDatabase(const QString& path, const QString& password, const QByteArray& salt);
101  ~RawDatabase();
102  bool isOpen();
103 
104  bool execNow(const QString& statement);
105  bool execNow(const Query& statement);
106  bool execNow(const QVector<Query>& statements);
107 
108  void execLater(const QString& statement);
109  void execLater(const Query& statement);
110  void execLater(const QVector<Query>& statements);
111 
112  void sync();
113 
114  static QString toString(SqlCipherParams params)
115  {
116  switch (params)
117  {
118  case SqlCipherParams::p3_0:
119  return "3.0 default";
120  case SqlCipherParams::halfUpgradedTo4:
121  return "3.x max compatible";
122  case SqlCipherParams::p4_0:
123  return "4.0 default";
124  }
125  assert(false);
126  return {};
127  }
128 
129 public slots:
130  bool setPassword(const QString& password);
131  bool rename(const QString& newPath);
132  bool remove();
133 
134 protected slots:
135  bool open(const QString& path, const QString& hexKey = {});
136  void close();
137  void process();
138 
139 private:
140  QString anonymizeQuery(const QByteArray& query);
141  bool openEncryptedDatabaseAtLatestSupportedVersion(const QString& hexKey);
142  bool updateSavedCipherParameters(const QString& hexKey, SqlCipherParams newParams);
143  bool setCipherParameters(SqlCipherParams params, const QString& database = {});
144  SqlCipherParams highestSupportedParams();
145  SqlCipherParams readSavedCipherParams(const QString& hexKey, SqlCipherParams newParams);
146  bool setKey(const QString& hexKey);
147  int getUserVersion();
148  bool encryptDatabase(const QString& newHexKey);
149  bool decryptDatabase();
150  bool commitDbSwap(const QString& hexKey);
151  bool testUsable();
152 
153 protected:
154  static QString deriveKey(const QString& password, const QByteArray& salt);
155  static QString deriveKey(const QString& password);
156  static QVariant extractData(sqlite3_stmt* stmt, int col);
157  static void regexpInsensitive(sqlite3_context* ctx, int argc, sqlite3_value** argv);
158  static void regexpSensitive(sqlite3_context* ctx, int argc, sqlite3_value** argv);
159 
160 private:
161  static void regexp(sqlite3_context* ctx, int argc, sqlite3_value** argv, const QRegularExpression::PatternOptions cs);
162 
163  struct Transaction
164  {
165  QVector<Query> queries;
166  std::atomic_bool* success = nullptr;
167  std::atomic_bool* done = nullptr;
168  };
169 
170 private:
171  sqlite3* sqlite;
172  std::unique_ptr<QThread> workerThread;
173  QQueue<Transaction> pendingTransactions;
175  QString path;
176  QByteArray currentSalt;
177  QString currentHexKey;
178 };
RawDatabase::Query::Query
Query(QString query, QVector< QByteArray > blobs={}, const std::function< void(RowId)> &insertCallback={})
Definition: rawdatabase.h:60
RawDatabase::path
QString path
Definition: rawdatabase.h:175
RawDatabase::Query
Definition: rawdatabase.h:57
RawDatabase::Query::Query
Query(QString query, const std::function< void(RowId)> &insertCallback)
Definition: rawdatabase.h:67
Q_DECLARE_METATYPE
Q_DECLARE_METATYPE(ExtendedReceiptNum)
RawDatabase::Query::insertCallback
std::function< void(RowId)> insertCallback
Called after execution with the last insert rowid.
Definition: rawdatabase.h:82
RowId
NamedType< int64_t, struct RowIdTag, Orderable > RowId
Definition: rawdatabase.h:49
RawDatabase::Transaction
Definition: rawdatabase.h:163
RawDatabase::Query::query
QByteArray query
UTF-8 query string.
Definition: rawdatabase.h:80
RawDatabase::Query::blobs
QVector< QByteArray > blobs
Bound data blobs.
Definition: rawdatabase.h:81
RawDatabase::Query::Query
Query(QString query, const std::function< void(const QVector< QVariant > &)> &rowCallback)
Definition: rawdatabase.h:72
RawDatabase::toString
static QString toString(SqlCipherParams params)
Definition: rawdatabase.h:114
RawDatabase::SqlCipherParams
SqlCipherParams
Definition: rawdatabase.h:90
RawDatabase
Implements a low level RAII interface to a SQLCipher (SQlite3) database.
Definition: rawdatabase.h:52
RawDatabase::workerThread
std::unique_ptr< QThread > workerThread
Definition: rawdatabase.h:172
RawDatabase::Query::statements
QVector< sqlite3_stmt * > statements
Statements to be compiled from the query.
Definition: rawdatabase.h:84
RawDatabase::sqlite
sqlite3 * sqlite
Definition: rawdatabase.h:171
RawDatabase::pendingTransactions
QQueue< Transaction > pendingTransactions
Definition: rawdatabase.h:173
RawDatabase::currentHexKey
QString currentHexKey
Definition: rawdatabase.h:177
RawDatabase::Transaction::queries
QVector< Query > queries
Definition: rawdatabase.h:165
Query
A query to be executed by the database.
RawDatabase::currentSalt
QByteArray currentSalt
Definition: rawdatabase.h:176
RawDatabase::transactionsMutex
QMutex transactionsMutex
Protects pendingTransactions.
Definition: rawdatabase.h:174
RawDatabase::Query::rowCallback
std::function< void(const QVector< QVariant > &)> rowCallback
Called during execution for each row.
Definition: rawdatabase.h:83