Messagelib

createdatabasefilejob.cpp
1 /*
2  SPDX-FileCopyrightText: 2016-2023 Laurent Montel <[email protected]>
3 
4  SPDX-License-Identifier: LGPL-2.0-or-later
5 */
6 
7 #include "createdatabasefilejob.h"
8 #include "checkphishingurlutil.h"
9 #include "localdatabasefile.h"
10 #include "riceencodingdecoder.h"
11 #include "webengineviewer_debug.h"
12 
13 #include <QCryptographicHash>
14 #include <QFile>
15 
16 using namespace WebEngineViewer;
17 
18 class WebEngineViewer::CreateDatabaseFileJobPrivate
19 {
20 public:
21  explicit CreateDatabaseFileJobPrivate(CreateDatabaseFileJob *qq)
22  : q(qq)
23  {
24  }
25 
26  void createFileFromFullUpdate(const QList<Addition> &additionList);
27  void removeElementFromDataBase(const QList<Removal> &removalList, QList<Addition> &oldDataBaseAddition);
28  void createBinaryFile();
29  void generateFile(bool fullUpdate);
30  WebEngineViewer::UpdateDataBaseInfo mInfoDataBase;
31  QString mFileName;
32  QFile mFile;
33  CreateDatabaseFileJob *const q;
34 };
35 
36 void CreateDatabaseFileJobPrivate::createFileFromFullUpdate(const QList<Addition> &additionList)
37 {
38  // 1 add version number
39  const quint16 major = WebEngineViewer::CheckPhishingUrlUtil::majorVersion();
40  const quint16 minor = WebEngineViewer::CheckPhishingUrlUtil::minorVersion();
41 
42  qint64 hashStartPosition = mFile.write(reinterpret_cast<const char *>(&major), sizeof(major));
43  hashStartPosition += mFile.write(reinterpret_cast<const char *>(&minor), sizeof(minor));
44 
45  // 2 add number of items
46  QList<Addition> itemToStore;
47  for (const Addition &add : additionList) {
48  switch (add.compressionType) {
49  case UpdateDataBaseInfo::RawCompression: {
50  // qCWarning(WEBENGINEVIEWER_LOG) << " add.size" << add.prefixSize;
51  const QByteArray uncompressed = add.hashString;
52  for (int i = 0; i < uncompressed.size();) {
53  const QByteArray m = uncompressed.mid(i, add.prefixSize);
54  i += add.prefixSize;
55 
56  Addition tmp;
57  tmp.hashString = m;
58  tmp.prefixSize = add.prefixSize;
59  itemToStore << tmp;
60 
61  // We store index as 8 octets.
62  hashStartPosition += 8;
63  if (m.size() != add.prefixSize) {
64  qCWarning(WEBENGINEVIEWER_LOG) << "hash string: " << m << " hash string size: " << m.size();
65  }
66  }
67  break;
68  }
69  case UpdateDataBaseInfo::RiceCompression: {
70  // TODO
71  qCWarning(WEBENGINEVIEWER_LOG) << "Rice compression still not implemented";
72  const QList<quint32> listRice = WebEngineViewer::RiceEncodingDecoder::decodeRiceHashesDelta(add.riceDeltaEncoding);
73  qDebug() << " listRice" << listRice;
74  break;
75  }
76  case UpdateDataBaseInfo::UnknownCompression:
77  qCWarning(WEBENGINEVIEWER_LOG) << "Unknown compression type in addition element";
78  break;
79  }
80  }
81  const quint64 numberOfElement = itemToStore.count();
82  hashStartPosition += mFile.write(reinterpret_cast<const char *>(&numberOfElement), sizeof(numberOfElement));
83  // 3 add index of items
84 
85  // Order it first
86  std::sort(itemToStore.begin(), itemToStore.end(), Addition::lessThan);
87 
88  quint64 tmpPos = hashStartPosition;
89 
90  for (const Addition &add : std::as_const(itemToStore)) {
91  mFile.write(reinterpret_cast<const char *>(&tmpPos), sizeof(tmpPos));
92  tmpPos += add.prefixSize + 1; // We add +1 as we store '\0'
93  }
94 
95  // 4 add items
96  QByteArray newSsha256;
97  for (const Addition &add : std::as_const(itemToStore)) {
98  const QByteArray storedBa = add.hashString + '\0';
99  mFile.write(reinterpret_cast<const char *>(storedBa.constData()), storedBa.size());
100  newSsha256 += add.hashString;
101  }
102  mFile.close();
103  // Verify hash with sha256
104  const QByteArray newSsha256Value = QCryptographicHash::hash(newSsha256, QCryptographicHash::Sha256);
105 
106  const bool checkSumCorrect = (mInfoDataBase.sha256 == newSsha256Value.toBase64());
107  if (!checkSumCorrect) {
108  qCWarning(WEBENGINEVIEWER_LOG) << " newSsha256Value different from sha256 : " << newSsha256Value.toBase64() << " from server " << mInfoDataBase.sha256;
109  }
110  Q_EMIT q->finished(checkSumCorrect, mInfoDataBase.newClientState, mInfoDataBase.minimumWaitDuration);
111 }
112 
113 void CreateDatabaseFileJobPrivate::generateFile(bool fullUpdate)
114 {
115  qCDebug(WEBENGINEVIEWER_LOG) << " void CreateDatabaseFileJobPrivate::generateFile(bool fullUpdate)" << fullUpdate;
116  mFile.setFileName(mFileName);
117  if (fullUpdate) {
118  if (mFile.exists() && !mFile.remove()) {
119  qCWarning(WEBENGINEVIEWER_LOG) << "Impossible to remove database file " << mFileName;
120  Q_EMIT q->finished(false, QString(), QString());
121  return;
122  }
123  if (!mFile.open(QIODevice::WriteOnly)) {
124  qCWarning(WEBENGINEVIEWER_LOG) << "Impossible to open database file " << mFileName;
125  Q_EMIT q->finished(false, QString(), QString());
126  return;
127  }
128  createFileFromFullUpdate(mInfoDataBase.additionList);
129  } else {
130  WebEngineViewer::LocalDataBaseFile localeFile(mFileName);
131  if (!localeFile.fileExists()) {
132  qCWarning(WEBENGINEVIEWER_LOG) << "Impossible to create partial update as file doesn't exist";
133  Q_EMIT q->finished(false, QString(), QString());
134  return;
135  }
136  // Read Element from database.
137  QList<Addition> oldDataBaseAddition = localeFile.extractAllInfo();
138 
139  removeElementFromDataBase(mInfoDataBase.removalList, oldDataBaseAddition);
140  QList<Addition> additionList = mInfoDataBase.additionList; // Add value found in database
141  oldDataBaseAddition += additionList;
142 
143  // Close file
144  localeFile.close();
145 
146  if (!mFile.remove()) {
147  qCWarning(WEBENGINEVIEWER_LOG) << "Impossible to remove database file " << mFileName;
148  Q_EMIT q->finished(false, QString(), QString());
149  return;
150  }
151  if (!mFile.open(QIODevice::WriteOnly)) {
152  qCWarning(WEBENGINEVIEWER_LOG) << "Impossible to open database file " << mFileName;
153  Q_EMIT q->finished(false, QString(), QString());
154  return;
155  }
156  createFileFromFullUpdate(oldDataBaseAddition);
157  }
158 }
159 
160 void CreateDatabaseFileJobPrivate::removeElementFromDataBase(const QList<Removal> &removalList, QList<Addition> &oldDataBaseAddition)
161 {
162  QList<quint32> indexToRemove;
163  for (const Removal &removeItem : removalList) {
164  switch (removeItem.compressionType) {
165  case UpdateDataBaseInfo::RawCompression:
166  for (int id : std::as_const(removeItem.indexes)) {
167  indexToRemove << id;
168  }
169  break;
170  case UpdateDataBaseInfo::RiceCompression:
171  indexToRemove = WebEngineViewer::RiceEncodingDecoder::decodeRiceIndiceDelta(removeItem.riceDeltaEncoding);
172  break;
173  case UpdateDataBaseInfo::UnknownCompression:
174  qCWarning(WEBENGINEVIEWER_LOG) << " Unknown compression type defined in removal elements. It's a bug!";
175  break;
176  }
177  }
178 
179  std::sort(indexToRemove.begin(), indexToRemove.end());
180  for (int i = (indexToRemove.count() - 1); i >= 0; --i) {
181  oldDataBaseAddition.remove(indexToRemove.at(i));
182  }
183 }
184 
185 void CreateDatabaseFileJobPrivate::createBinaryFile()
186 {
187  switch (mInfoDataBase.responseType) {
188  case UpdateDataBaseInfo::Unknown:
189  qCWarning(WEBENGINEVIEWER_LOG) << " Response Type of database info is \"unknown\". It's a bug!";
190  break;
191  case UpdateDataBaseInfo::FullUpdate:
192  case UpdateDataBaseInfo::PartialUpdate:
193  generateFile((mInfoDataBase.responseType == UpdateDataBaseInfo::FullUpdate));
194  break;
195  }
196  q->deleteLater();
197 }
198 
199 CreateDatabaseFileJob::CreateDatabaseFileJob(QObject *parent)
200  : QObject(parent)
201  , d(new WebEngineViewer::CreateDatabaseFileJobPrivate(this))
202 {
203 }
204 
205 CreateDatabaseFileJob::~CreateDatabaseFileJob() = default;
206 
207 bool CreateDatabaseFileJob::canStart() const
208 {
209  return !d->mFileName.isEmpty() && d->mInfoDataBase.isValid();
210 }
211 
212 void CreateDatabaseFileJob::setUpdateDataBaseInfo(const UpdateDataBaseInfo &infoDataBase)
213 {
214  d->mInfoDataBase = infoDataBase;
215 }
216 
218 {
219  if (!canStart()) {
220  Q_EMIT finished(false, QString(), QString());
221  deleteLater();
222  } else {
223  d->createBinaryFile();
224  }
225 }
226 
227 void CreateDatabaseFileJob::setFileName(const QString &filename)
228 {
229  d->mFileName = filename;
230 }
231 
232 #include "moc_createdatabasefilejob.cpp"
int count(const T &value) const const
Q_SCRIPTABLE Q_NOREPLY void start()
QByteArray toBase64(QByteArray::Base64Options options) const const
QByteArray mid(int pos, int len) const const
const T & at(int i) const const
QByteArray hash(const QByteArray &data, QCryptographicHash::Algorithm method)
KGuiItem add()
const char * constData() const const
QList::iterator begin()
int size() const const
The CreateDatabaseFileJob class.
QList::iterator end()
This file is part of the KDE documentation.
Documentation copyright © 1996-2023 The KDE developers.
Generated on Thu Nov 30 2023 03:56:25 by doxygen 1.8.17 written by Dimitri van Heesch, © 1997-2006

KDE's Doxygen guidelines are available online.