Messagelib

createdatabasefilejob.cpp
1/*
2 SPDX-FileCopyrightText: 2016-2024 Laurent Montel <montel@kde.org>
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
16using namespace WebEngineViewer;
17
18class WebEngineViewer::CreateDatabaseFileJobPrivate
19{
20public:
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
36void 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
113void 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
160void 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
185void 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
199CreateDatabaseFileJob::CreateDatabaseFileJob(QObject *parent)
200 : QObject(parent)
201 , d(new WebEngineViewer::CreateDatabaseFileJobPrivate(this))
202{
203}
204
205CreateDatabaseFileJob::~CreateDatabaseFileJob() = default;
206
207bool CreateDatabaseFileJob::canStart() const
208{
209 return !d->mFileName.isEmpty() && d->mInfoDataBase.isValid();
210}
211
212void CreateDatabaseFileJob::setUpdateDataBaseInfo(const UpdateDataBaseInfo &infoDataBase)
213{
214 d->mInfoDataBase = infoDataBase;
215}
216
217void CreateDatabaseFileJob::start()
218{
219 if (!canStart()) {
220 Q_EMIT finished(false, QString(), QString());
221 deleteLater();
222 } else {
223 d->createBinaryFile();
224 }
225}
226
227void CreateDatabaseFileJob::setFileName(const QString &filename)
228{
229 d->mFileName = filename;
230}
231
232#include "moc_createdatabasefilejob.cpp"
The CreateDatabaseFileJob class.
KIOCORE_EXPORT void add(const QString &fileClass, const QString &directory)
const char * constData() const const
QByteArray mid(qsizetype pos, qsizetype len) const const
qsizetype size() const const
QByteArray toBase64(Base64Options options) const const
QByteArray hash(QByteArrayView data, Algorithm method)
bool exists(const QString &fileName)
bool open(FILE *fh, OpenMode mode, FileHandleFlags handleFlags)
bool remove()
void setFileName(const QString &name)
virtual void close() override
qint64 write(const QByteArray &data)
const_reference at(qsizetype i) const const
iterator begin()
qsizetype count() const const
iterator end()
void remove(qsizetype i, qsizetype n)
Q_EMITQ_EMIT
void deleteLater()
T qobject_cast(QObject *object)
This file is part of the KDE documentation.
Documentation copyright © 1996-2024 The KDE developers.
Generated on Tue Mar 26 2024 11:12:44 by doxygen 1.10.0 written by Dimitri van Heesch, © 1997-2006

KDE's Doxygen guidelines are available online.