7#include "createphishingurldatabasejob.h"
8#include "checkphishingurlutil.h"
9#include "updatedatabaseinfo.h"
10#include "webengineviewer_debug.h"
11#include <PimCommon/NetworkManager>
13#include <QJsonDocument>
16using namespace WebEngineViewer;
18WEBENGINEVIEWER_EXPORT
bool webengineview_useCompactJson_CreatePhishingUrlDataBaseJob =
true;
20class WebEngineViewer::CreatePhishingUrlDataBaseJobPrivate
23 [[nodiscard]] UpdateDataBaseInfo::CompressionType parseCompressionType(
const QString &str);
24 [[nodiscard]] RiceDeltaEncoding parseRiceDeltaEncoding(
const QMap<QString, QVariant> &map);
25 [[nodiscard]] QList<Removal> parseRemovals(
const QVariantList &lst);
26 [[nodiscard]] QList<Addition> parseAdditions(
const QVariantList &lst);
27 QString mDataBaseState;
28 CreatePhishingUrlDataBaseJob::ContraintsCompressionType mContraintsCompressionType = CreatePhishingUrlDataBaseJob::RawCompression;
29 CreatePhishingUrlDataBaseJob::DataBaseDownloadType mDataBaseDownloadNeeded = CreatePhishingUrlDataBaseJob::FullDataBase;
30 QNetworkAccessManager *mNetworkAccessManager =
nullptr;
33CreatePhishingUrlDataBaseJob::CreatePhishingUrlDataBaseJob(
QObject *parent)
35 , d(new CreatePhishingUrlDataBaseJobPrivate)
39 d->mNetworkAccessManager->setStrictTransportSecurityEnabled(
true);
40 d->mNetworkAccessManager->enableStrictTransportSecurityStore(
true);
43 connect(d->mNetworkAccessManager, &QNetworkAccessManager::sslErrors,
this, &CreatePhishingUrlDataBaseJob::slotSslErrors);
46CreatePhishingUrlDataBaseJob::~CreatePhishingUrlDataBaseJob() =
default;
50 qCDebug(WEBENGINEVIEWER_LOG) <<
" void CreatePhishingUrlDataBaseJob::slotSslErrors(QNetworkReply *reply, const QList<QSslError> &error)" <<
error.count();
54void CreatePhishingUrlDataBaseJob::start()
56 if (!PimCommon::NetworkManager::self()->isOnline()) {
57 Q_EMIT finished(UpdateDataBaseInfo(), BrokenNetwork);
61 query.addQueryItem(QStringLiteral(
"key"), WebEngineViewer::CheckPhishingUrlUtil::apiKey());
62 QUrl safeUrl = QUrl(QStringLiteral(
"https://safebrowsing.googleapis.com/v4/threatListUpdates:fetch"));
65 QNetworkRequest request(safeUrl);
68 const QByteArray baPostData = jsonRequest();
69 Q_EMIT debugJson(baPostData);
70 qCDebug(WEBENGINEVIEWER_LOG) <<
" postData.toJson()" << baPostData;
74 QNetworkReply *reply = d->mNetworkAccessManager->post(request, baPostData);
79void CreatePhishingUrlDataBaseJob::setDataBaseState(
const QString &value)
81 d->mDataBaseState = value;
87 qWarning() <<
" error " <<
error <<
" error string : " << reply->
errorString();
92QByteArray CreatePhishingUrlDataBaseJob::jsonRequest()
const
97 "clientId" :
"yourcompanyname",
98 "clientVersion" :
"1.5.2"
100 "listUpdateRequests" : [{
101 "threatType" :
"MALWARE",
102 "platformType" :
"WINDOWS",
103 "threatEntryType" :
"URL",
104 "state" :
"Gg4IBBADIgYQgBAiAQEoAQ==",
106 "maxUpdateEntries" : 2048,
107 "maxDatabaseEntries" : 4096,
109 "supportedCompressions" : [
"RAW"]
114 QVariantMap clientMap;
117 clientMap.insert(QStringLiteral(
"clientId"), QStringLiteral(
"KDE"));
118 clientMap.insert(QStringLiteral(
"clientVersion"), CheckPhishingUrlUtil::versionApps());
119 map.insert(QStringLiteral(
"client"), clientMap);
121 QVariantList listUpdateRequests;
123 QVariantMap threatMap;
124 threatMap.insert(QStringLiteral(
"platformType"), QStringLiteral(
"WINDOWS"));
125 threatMap.insert(QStringLiteral(
"threatType"), QStringLiteral(
"MALWARE"));
126 threatMap.insert(QStringLiteral(
"threatEntryType"), QStringLiteral(
"URL"));
129 QVariantMap contraintsMap;
130 QVariantList contraintsCompressionList;
131 QString compressionStr;
132 switch (d->mContraintsCompressionType) {
133 case RiceCompression:
134 compressionStr = QStringLiteral(
"RICE");
137 compressionStr = QStringLiteral(
"RAW");
140 contraintsCompressionList.append(compressionStr);
141 contraintsMap.insert(QStringLiteral(
"supportedCompressions"), contraintsCompressionList);
142 threatMap.insert(QStringLiteral(
"constraints"), contraintsMap);
145 switch (d->mDataBaseDownloadNeeded) {
147 qCDebug(WEBENGINEVIEWER_LOG) <<
" full update";
148 threatMap.insert(QStringLiteral(
"state"), QString());
151 qCDebug(WEBENGINEVIEWER_LOG) <<
" update database";
152 if (d->mDataBaseState.isEmpty()) {
153 qCWarning(WEBENGINEVIEWER_LOG) <<
"Partial Download asked but database set is empty";
155 threatMap.insert(QStringLiteral(
"state"), d->mDataBaseState);
159 listUpdateRequests.append(threatMap);
161 map.insert(QStringLiteral(
"listUpdateRequests"), listUpdateRequests);
168void CreatePhishingUrlDataBaseJob::setDataBaseDownloadNeeded(CreatePhishingUrlDataBaseJob::DataBaseDownloadType type)
170 d->mDataBaseDownloadNeeded = type;
173void CreatePhishingUrlDataBaseJob::slotDownloadDataBaseFinished(QNetworkReply *reply)
175 const QByteArray returnValue(reply->
readAll());
176 Q_EMIT debugJsonResult(returnValue);
177 parseResult(returnValue);
181RiceDeltaEncoding CreatePhishingUrlDataBaseJobPrivate::parseRiceDeltaEncoding(
const QMap<QString, QVariant> &map)
183 RiceDeltaEncoding riceDeltaEncodingTmp;
184 QMap<QString, QVariant>::const_iterator riceHashesIt =
map.cbegin();
185 const QMap<QString, QVariant>::const_iterator riceHashesItEnd =
map.cend();
186 for (; riceHashesIt != riceHashesItEnd; ++riceHashesIt) {
187 const QString key = riceHashesIt.key();
188 if (key == QLatin1StringView(
"firstValue")) {
189 riceDeltaEncodingTmp.firstValue = riceHashesIt.value().toByteArray();
190 }
else if (key == QLatin1StringView(
"riceParameter")) {
191 riceDeltaEncodingTmp.riceParameter = riceHashesIt.value().toInt();
192 }
else if (key == QLatin1StringView(
"numEntries")) {
193 riceDeltaEncodingTmp.numberEntries = riceHashesIt.value().toInt();
194 }
else if (key == QLatin1StringView(
"encodedData")) {
195 riceDeltaEncodingTmp.encodingData = riceHashesIt.value().toByteArray();
197 qCDebug(WEBENGINEVIEWER_LOG) <<
" CreatePhishingUrlDataBaseJob::parseRiceDeltaEncoding unknown riceDeltaEncoding key " << key;
200 return riceDeltaEncodingTmp;
203QList<Addition> CreatePhishingUrlDataBaseJobPrivate::parseAdditions(
const QVariantList &lst)
205 QList<Addition> additionList;
206 for (
const QVariant &v : lst) {
207 if (v.canConvert<QVariantMap>()) {
208 QMapIterator<QString, QVariant> mapIt(v.toMap());
210 while (mapIt.hasNext()) {
212 const QString keyStr = mapIt.key();
213 if (keyStr == QLatin1StringView(
"compressionType")) {
214 tmp.compressionType = parseCompressionType(mapIt.value().toString());
215 }
else if (keyStr == QLatin1StringView(
"riceHashes")) {
216 RiceDeltaEncoding riceDeltaEncodingTmp = parseRiceDeltaEncoding(mapIt.value().toMap());
217 if (riceDeltaEncodingTmp.isValid()) {
218 tmp.riceDeltaEncoding = riceDeltaEncodingTmp;
220 }
else if (keyStr == QLatin1StringView(
"rawHashes")) {
221 QMapIterator<QString, QVariant> rawHashesIt(mapIt.value().toMap());
222 while (rawHashesIt.hasNext()) {
224 const QString key = rawHashesIt.key();
225 if (key == QLatin1StringView(
"rawHashes")) {
227 }
else if (key == QLatin1StringView(
"prefixSize")) {
228 tmp.prefixSize = rawHashesIt.value().toInt();
230 qCDebug(WEBENGINEVIEWER_LOG) <<
" CreatePhishingUrlDataBaseJob::parseAdditions unknown rawHashes key " << key;
234 qCDebug(WEBENGINEVIEWER_LOG) <<
" CreatePhishingUrlDataBaseJob::parseAdditions unknown mapIt.key() " << keyStr;
241 qCDebug(WEBENGINEVIEWER_LOG) <<
" CreatePhishingUrlDataBaseJob::parseAdditions not parsing type " << v.typeName();
247UpdateDataBaseInfo::CompressionType CreatePhishingUrlDataBaseJobPrivate::parseCompressionType(
const QString &str)
249 UpdateDataBaseInfo::CompressionType type(UpdateDataBaseInfo::UnknownCompression);
250 if (str == QLatin1StringView(
"COMPRESSION_TYPE_UNSPECIFIED")) {
251 type = UpdateDataBaseInfo::UnknownCompression;
252 }
else if (str == QLatin1StringView(
"RICE")) {
253 type = UpdateDataBaseInfo::RiceCompression;
254 }
else if (str == QLatin1StringView(
"RAW")) {
255 type = UpdateDataBaseInfo::RawCompression;
257 qCWarning(WEBENGINEVIEWER_LOG) <<
"CreatePhishingUrlDataBaseJob::parseCompressionType unknown compression type " << str;
262QList<Removal> CreatePhishingUrlDataBaseJobPrivate::parseRemovals(
const QVariantList &lst)
264 QList<Removal> removalList;
265 for (
const QVariant &v : lst) {
266 if (v.canConvert<QVariantMap>()) {
268 QMapIterator<QString, QVariant> mapIt(v.toMap());
269 while (mapIt.hasNext()) {
271 const QString keyStr = mapIt.key();
272 if (keyStr == QLatin1StringView(
"compressionType")) {
273 tmp.compressionType = parseCompressionType(mapIt.value().toString());
274 }
else if (keyStr == QLatin1StringView(
"riceIndices")) {
275 RiceDeltaEncoding riceDeltaEncodingTmp = parseRiceDeltaEncoding(mapIt.value().toMap());
276 if (riceDeltaEncodingTmp.isValid()) {
277 tmp.riceDeltaEncoding = riceDeltaEncodingTmp;
279 }
else if (keyStr == QLatin1StringView(
"rawIndices")) {
280 const QVariantMap
map = mapIt.value().toMap();
281 QMapIterator<QString, QVariant> rawIndicesIt(map);
282 while (rawIndicesIt.hasNext()) {
284 if (rawIndicesIt.key() == QLatin1StringView(
"indices")) {
285 const QVariantList rawList = rawIndicesIt.value().toList();
286 QList<quint32> indexList;
287 indexList.
reserve(rawList.count());
288 for (
const QVariant &var : rawList) {
289 indexList.
append(var.toUInt());
291 tmp.indexes = indexList;
293 qCDebug(WEBENGINEVIEWER_LOG) <<
"rawIndicesIt.key() unknown " << rawIndicesIt.key();
297 qCDebug(WEBENGINEVIEWER_LOG) <<
" CreatePhishingUrlDataBaseJob::parseRemovals unknown mapIt.key() " << keyStr;
304 qCDebug(WEBENGINEVIEWER_LOG) <<
" CreatePhishingUrlDataBaseJob::parseRemovals not parsing type " << v.typeName();
310void CreatePhishingUrlDataBaseJob::parseResult(
const QByteArray &value)
312 UpdateDataBaseInfo databaseInfo;
315 Q_EMIT finished(databaseInfo, InvalidData);
318 if (answer.isEmpty()) {
319 Q_EMIT finished(databaseInfo, InvalidData);
321 QMapIterator<QString, QVariant> i(answer);
322 while (i.hasNext()) {
324 if (i.key() == QLatin1StringView(
"listUpdateResponses")) {
325 const QVariantList info = i.value().toList();
326 if (info.count() == 1) {
327 const QVariant infoVar = info.at(0);
329 QMapIterator<QString, QVariant> mapIt(infoVar.
toMap());
330 while (mapIt.hasNext()) {
332 const QString mapKey = mapIt.key();
333 if (mapKey == QLatin1StringView(
"additions")) {
334 const QVariantList lst = mapIt.value().toList();
335 const QList<Addition> addList = d->parseAdditions(lst);
337 databaseInfo.additionList.
append(addList);
339 }
else if (mapKey == QLatin1StringView(
"removals")) {
340 const QVariantList lst = mapIt.value().toList();
341 const QList<Removal> removeList = d->parseRemovals(lst);
343 databaseInfo.removalList.
append(removeList);
345 }
else if (mapKey == QLatin1StringView(
"checksum")) {
346 QMapIterator<QString, QVariant> mapCheckSum(mapIt.value().toMap());
347 while (mapCheckSum.hasNext()) {
349 if (mapCheckSum.key() == QLatin1StringView(
"sha256")) {
350 databaseInfo.sha256 = mapCheckSum.value().toByteArray();
352 qCDebug(WEBENGINEVIEWER_LOG) <<
"Invalid checksum key" << mapCheckSum.key();
355 }
else if (mapKey == QLatin1StringView(
"newClientState")) {
356 databaseInfo.newClientState = mapIt.value().toString();
357 }
else if (mapKey == QLatin1StringView(
"platformType")) {
358 databaseInfo.platformType = mapIt.value().toString();
359 }
else if (mapKey == QLatin1StringView(
"responseType")) {
360 const QString str = mapIt.value().toString();
361 if (str == QLatin1StringView(
"FULL_UPDATE")) {
362 databaseInfo.responseType = UpdateDataBaseInfo::FullUpdate;
363 }
else if (str == QLatin1StringView(
"PARTIAL_UPDATE")) {
364 databaseInfo.responseType = UpdateDataBaseInfo::PartialUpdate;
366 qCDebug(WEBENGINEVIEWER_LOG) <<
" unknown responsetype " << str;
367 databaseInfo.responseType = UpdateDataBaseInfo::Unknown;
369 }
else if (mapKey == QLatin1StringView(
"threatEntryType")) {
370 databaseInfo.threatEntryType = mapIt.value().toString();
371 }
else if (mapKey == QLatin1StringView(
"threatType")) {
372 databaseInfo.threatType = mapIt.value().toString();
374 qCDebug(WEBENGINEVIEWER_LOG) <<
" unknown key " << mapKey;
379 }
else if (i.key() == QLatin1StringView(
"minimumWaitDuration")) {
380 databaseInfo.minimumWaitDuration = i.value().toString();
382 qCDebug(WEBENGINEVIEWER_LOG) <<
" map key unknown " << i.key();
385 Q_EMIT finished(databaseInfo, ValidData);
391void CreatePhishingUrlDataBaseJob::setContraintsCompressionType(CreatePhishingUrlDataBaseJob::ContraintsCompressionType type)
393 d->mContraintsCompressionType = type;
396#include "moc_createphishingurldatabasejob.cpp"
KSERVICE_EXPORT KService::List query(FilterFunc filterFunc)
void error(QWidget *parent, const QString &text, const QString &title, const KGuiItem &buttonOk, Options options=Notify)
QByteArray fromBase64(const QByteArray &base64, Base64Options options)
QString errorString() const const
QJsonDocument fromJson(const QByteArray &json, QJsonParseError *error)
QJsonDocument fromVariant(const QVariant &variant)
bool isNull() const const
QByteArray toJson(JsonFormat format) const const
QVariant toVariant() const const
void append(QList< T > &&value)
bool isEmpty() const const
void reserve(qsizetype size)
void finished(QNetworkReply *reply)
void errorOccurred(QNetworkReply::NetworkError code)
virtual void ignoreSslErrors()
QMetaObject::Connection connect(const QObject *sender, PointerToMemberFunction signal, Functor functor)
T qobject_cast(QObject *object)
QObject * sender() const const
QFuture< void > map(Iterator begin, Iterator end, MapFunctor &&function)
QFuture< ArgsType< Signal > > connect(Sender *sender, Signal signal)
void setQuery(const QString &query, ParsingMode mode)
bool canConvert() const const
QMap< QString, QVariant > toMap() const const