1 /*!
2  * \copyright Copyright (c) 2019-2021 Governikus GmbH & Co. KG, Germany
3  */
4 
5 #include "SurveyModel.h"
6 
7 #include "DeviceInfo.h"
8 #include "Env.h"
9 #include "LogHandler.h"
10 #include "NetworkManager.h"
11 #include "SecureStorage.h"
12 #include "TlsChecker.h"
13 
14 #include <QCoreApplication>
15 #include <QDebug>
16 #include <QJsonDocument>
17 #include <QJsonObject>
18 #include <QLoggingCategory>
19 #include <QNetworkReply>
20 #include <QNetworkRequest>
21 
22 Q_DECLARE_LOGGING_CATEGORY(network)
23 
24 using namespace governikus;
25 
26 #define VALUE_NAME(_name, _key)\
27 	inline QLatin1String _name(){\
28 		return QLatin1String(_key);\
29 	}
30 
31 
32 namespace
33 {
34 VALUE_NAME(ROM, "Rom")
35 VALUE_NAME(BUILD_NUMBER, "BuildNumber")
36 VALUE_NAME(ANDROID_VERSION, "AndroidVersion")
37 VALUE_NAME(KERNEL_VERSION, "KernelVersion")
38 VALUE_NAME(MAXIMUM_NFC_PACKET_LENGTH, "MaximumNfcPacketLength")
39 VALUE_NAME(VENDOR, "Vendor")
40 VALUE_NAME(MODEL_NUMBER, "ModelNumber")
41 VALUE_NAME(MODEL_NAME, "ModelName")
42 VALUE_NAME(AUSWEISAPP_VERSION_NUMBER, "AusweisAppVersionNumber")
43 } // namespace
44 
45 
SurveyModel()46 SurveyModel::SurveyModel()
47 	: QAbstractListModel()
48 	, mBuildNumber(DeviceInfo::getOSBuildNumber())
49 	, mAndroidVersion(DeviceInfo::getOSVersion())
50 	, mKernelVersion(DeviceInfo::getKernelVersion())
51 	, mMaximumNfcPacketLength(0)
52 	, mVendor(DeviceInfo::getVendor())
53 	, mModelNumber(DeviceInfo::getModelNumber())
54 	, mModelName(DeviceInfo::getModelName())
55 	, mAusweisAppVersionNumber(QCoreApplication::applicationVersion())
56 {
57 	buildDataObject();
58 }
59 
60 
rowCount(const QModelIndex &) const61 int SurveyModel::rowCount(const QModelIndex&) const
62 {
63 	return mData.size();
64 }
65 
66 
data(const QModelIndex & pIndex,int pRole) const67 QVariant SurveyModel::data(const QModelIndex& pIndex, int pRole) const
68 {
69 	if (pIndex.isValid() && pIndex.row() < rowCount())
70 	{
71 		auto entry = mData[pIndex.row()];
72 		if (pRole == TITLE)
73 		{
74 			return entry.first;
75 		}
76 		if (pRole == VALUE)
77 		{
78 			return entry.second;
79 		}
80 	}
81 	return QVariant();
82 }
83 
84 
roleNames() const85 QHash<int, QByteArray> SurveyModel::roleNames() const
86 {
87 	QHash<int, QByteArray> roles = QAbstractListModel::roleNames();
88 	roles.insert(TITLE, "title");
89 	roles.insert(VALUE, "value");
90 	return roles;
91 }
92 
93 
buildDataObject()94 void SurveyModel::buildDataObject()
95 {
96 	beginResetModel();
97 	mData.clear();
98 	mData += qMakePair(tr("Vendor"), mVendor);
99 	mData += qMakePair(tr("Model Name"), mModelName);
100 	mData += qMakePair(tr("Model Number"), mModelNumber);
101 	mData += qMakePair(tr("Build Number"), mBuildNumber);
102 	mData += qMakePair(tr("Android version"), mAndroidVersion);
103 	mData += qMakePair(tr("Kernel version"), mKernelVersion);
104 	mData += qMakePair(tr("Max. NFC Packet Length"), QString::number(mMaximumNfcPacketLength));
105 	mData += qMakePair(tr("AusweisApp2 Version"), mAusweisAppVersionNumber);
106 	endResetModel();
107 }
108 
109 
toJsonByteArray() const110 QByteArray SurveyModel::toJsonByteArray() const
111 {
112 	QJsonObject rom;
113 	rom[BUILD_NUMBER()] = mBuildNumber;
114 	rom[ANDROID_VERSION()] = mAndroidVersion;
115 	rom[KERNEL_VERSION()] = mKernelVersion;
116 	rom[MAXIMUM_NFC_PACKET_LENGTH()] = QJsonValue(mMaximumNfcPacketLength);
117 
118 	QJsonObject mainObject;
119 	mainObject[ROM()] = rom;
120 	mainObject[VENDOR()] = mVendor;
121 	mainObject[MODEL_NUMBER()] = mModelNumber;
122 	mainObject[MODEL_NAME()] = mModelName;
123 	mainObject[AUSWEISAPP_VERSION_NUMBER()] = mAusweisAppVersionNumber;
124 
125 #ifndef QT_NO_DEBUG
126 	if (QCoreApplication::applicationName().startsWith(QLatin1String("Test")))
127 	{
128 		return QJsonDocument(mainObject).toJson(QJsonDocument::Indented);
129 	}
130 #endif
131 
132 	return QJsonDocument(mainObject).toJson(QJsonDocument::Compact);
133 }
134 
135 
setMaximumNfcPacketLength(int pMaximumNfcPacketLength)136 void SurveyModel::setMaximumNfcPacketLength(int pMaximumNfcPacketLength)
137 {
138 	mMaximumNfcPacketLength = pMaximumNfcPacketLength;
139 	buildDataObject();
140 }
141 
142 
transmitSurvey()143 void SurveyModel::transmitSurvey()
144 {
145 	const QUrl whitelistServerBaseUrl = Env::getSingleton<SecureStorage>()->getWhitelistServerBaseUrl();
146 	const QUrl postSurveyUrl(whitelistServerBaseUrl.toString() + QStringLiteral("/new"));
147 	QNetworkRequest request(postSurveyUrl);
148 	request.setHeader(QNetworkRequest::ContentTypeHeader, QLatin1String("application/json; charset=UTF-8"));
149 
150 	const QByteArray jsonData = toJsonByteArray();
151 	mReply.reset(Env::getSingleton<NetworkManager>()->post(request, jsonData), &QNetworkReply::deleteLater);
152 
153 	connect(mReply.data(), &QNetworkReply::sslErrors, this, &SurveyModel::onSslErrors);
154 	connect(mReply.data(), &QNetworkReply::encrypted, this, &SurveyModel::onSslHandshakeDone);
155 	connect(mReply.data(), &QNetworkReply::finished, this, &SurveyModel::onNetworkReplyFinished);
156 
157 	qDebug().noquote() << "Sent survey to whitelist server:" << jsonData;
158 }
159 
160 
onSslErrors(const QList<QSslError> & pErrors)161 void SurveyModel::onSslErrors(const QList<QSslError>& pErrors)
162 {
163 	TlsChecker::containsFatalError(mReply, pErrors);
164 }
165 
166 
onSslHandshakeDone()167 void SurveyModel::onSslHandshakeDone()
168 {
169 	const auto& cfg = mReply->sslConfiguration();
170 	TlsChecker::logSslConfig(cfg, spawnMessageLogger(network));
171 
172 	if (!Env::getSingleton<NetworkManager>()->checkUpdateServerCertificate(mReply))
173 	{
174 		qCCritical(network) << "Untrusted certificate of Whitelist server found:" << cfg.peerCertificate();
175 		mReply->abort();
176 	}
177 }
178 
179 
onNetworkReplyFinished()180 void SurveyModel::onNetworkReplyFinished()
181 {
182 	if (mReply)
183 	{
184 		mReply->disconnect(this);
185 		mReply.reset();
186 	}
187 }
188