1 /*!
2 * \copyright Copyright (c) 2017-2021 Governikus GmbH & Co. KG, Germany
3 */
4
5 #include "RemoteServiceModel.h"
6
7 #include "ApplicationModel.h"
8 #include "AppSettings.h"
9 #include "EstablishPaceChannel.h"
10 #include "NumberModel.h"
11 #include "RemoteClientImpl.h"
12 #include "RemoteServiceSettings.h"
13
14 #ifdef Q_OS_IOS
15 #include <QOperatingSystemVersion>
16 #endif
17
18 using namespace governikus;
19
RemoteServiceModel()20 RemoteServiceModel::RemoteServiceModel()
21 : WorkflowModel()
22 , mContext()
23 , mRunnable(false)
24 , mIsStarting(false)
25 , mCanEnableNfc(false)
26 , mPairingRequested(false)
27 , mRequestTransportPin(false)
28 , mErrorMessage()
29 , mPsk()
30 , mAvailableRemoteDevices(this, false, true)
31 , mKnownDevices(this, true, false)
32 , mCombinedDevices(this, true, true)
33 , mConnectionInfo()
34 , mConnectedServerDeviceNames()
35 , mRememberedServerEntry()
36 #ifdef Q_OS_IOS
37 // iOS 14 introduced a local network permission, so we need to handle it.
38 , mRequiresLocalNetworkPermission(QOperatingSystemVersion::current() >= QOperatingSystemVersion(QOperatingSystemVersion::IOS, 14))
39 #else
40 , mRequiresLocalNetworkPermission(false)
41 #endif
42 {
43 const auto readerManager = Env::getSingleton<ReaderManager>();
44 connect(readerManager, &ReaderManager::firePluginAdded, this, &RemoteServiceModel::onEnvironmentChanged);
45 connect(readerManager, &ReaderManager::fireStatusChanged, this, &RemoteServiceModel::onEnvironmentChanged);
46 connect(readerManager, &ReaderManager::fireReaderAdded, this, &RemoteServiceModel::onEnvironmentChanged);
47 connect(readerManager, &ReaderManager::fireReaderRemoved, this, &RemoteServiceModel::onEnvironmentChanged);
48 const auto applicationModel = Env::getSingleton<ApplicationModel>();
49 connect(applicationModel, &ApplicationModel::fireWifiEnabledChanged, this, &RemoteServiceModel::onEnvironmentChanged);
50
51 const auto* const remoteClient = Env::getSingleton<RemoteClient>();
52 connect(remoteClient, &RemoteClient::fireDetectionChanged, this, &RemoteServiceModel::fireDetectionChanged);
53 connect(remoteClient, &RemoteClient::fireNewRemoteDispatcher, this, &RemoteServiceModel::onConnectedDevicesChanged);
54 connect(remoteClient, &RemoteClient::fireDispatcherDestroyed, this, &RemoteServiceModel::onConnectedDevicesChanged);
55 connect(remoteClient, &RemoteClient::fireDeviceAppeared, this, &RemoteServiceModel::fireRemoteReaderVisibleChanged);
56 connect(remoteClient, &RemoteClient::fireDeviceVanished, this, &RemoteServiceModel::fireRemoteReaderVisibleChanged);
57
58 const auto& settings = Env::getSingleton<AppSettings>()->getGeneralSettings();
59 connect(&settings, &GeneralSettings::fireLanguageChanged, this, &RemoteServiceModel::onEnvironmentChanged);
60
61 QMetaObject::invokeMethod(this, &RemoteServiceModel::onEnvironmentChanged, Qt::QueuedConnection);
62 }
63
64
onEnvironmentChanged()65 void RemoteServiceModel::onEnvironmentChanged()
66 {
67 bool nfcPluginAvailable = false;
68 bool nfcPluginEnabled = false;
69 const auto& allPlugins = Env::getSingleton<ReaderManager>()->getPlugInInfos();
70 for (const auto& pluginInfo : allPlugins)
71 {
72 if (pluginInfo.getPlugInType() != ReaderManagerPlugInType::NFC)
73 {
74 // At this time no basic reader available so we can skip
75 continue;
76 }
77
78 nfcPluginAvailable |= pluginInfo.isAvailable();
79 nfcPluginEnabled |= pluginInfo.isEnabled();
80 }
81
82 bool readerAvailable = !(Env::getSingleton<ReaderManager>()->getReaderInfos(ReaderFilter({ReaderManagerPlugInType::NFC})).isEmpty());
83 const bool wifiEnabled = Env::getSingleton<ApplicationModel>()->isWifiEnabled();
84
85 const bool runnable = readerAvailable && wifiEnabled;
86 const bool canEnableNfc = nfcPluginAvailable && !nfcPluginEnabled;
87 const QString errorMessage = getErrorMessage(nfcPluginAvailable, nfcPluginEnabled, wifiEnabled);
88 if (mRunnable != runnable || mCanEnableNfc != canEnableNfc || mErrorMessage != errorMessage)
89 {
90 mRunnable = runnable;
91 mCanEnableNfc = canEnableNfc;
92 mErrorMessage = errorMessage;
93
94 Q_EMIT fireEnvironmentChanged();
95 }
96
97 if (!runnable && isRunning())
98 {
99 setRunning(false);
100 }
101 }
102
103
isRunning() const104 bool RemoteServiceModel::isRunning() const
105 {
106 return mContext ? mContext->isRunning() : false;
107 }
108
109
setRunning(bool pState,bool pEnablePairing)110 void RemoteServiceModel::setRunning(bool pState, bool pEnablePairing)
111 {
112 bool enablePairing = pEnablePairing && pState;
113 if (mContext)
114 {
115 setPairing(enablePairing);
116 }
117 else
118 {
119 mPairingRequested = enablePairing;
120 }
121
122 if (isRunning() == pState)
123 {
124 return;
125 }
126
127 if (isRunning() && mContext)
128 {
129 Q_EMIT mContext->fireCancelWorkflow();
130 }
131 else
132 {
133 setStarting(true);
134 Q_EMIT fireStartWorkflow();
135 }
136 }
137
138
setStarting(bool pStarting)139 void RemoteServiceModel::setStarting(bool pStarting)
140 {
141 mIsStarting = pStarting;
142 Q_EMIT fireIsStartingChanged();
143 }
144
145
isStarting() const146 bool RemoteServiceModel::isStarting() const
147 {
148 return mIsStarting;
149 }
150
151
getAvailableRemoteDevices()152 RemoteDeviceModel* RemoteServiceModel::getAvailableRemoteDevices()
153 {
154 return &mAvailableRemoteDevices;
155 }
156
157
getKnownDevices()158 RemoteDeviceModel* RemoteServiceModel::getKnownDevices()
159 {
160 return &mKnownDevices;
161 }
162
163
getCombinedDevices()164 RemoteDeviceModel* RemoteServiceModel::getCombinedDevices()
165 {
166 return &mCombinedDevices;
167 }
168
169
setDetectRemoteDevices(bool pNewStatus)170 void RemoteServiceModel::setDetectRemoteDevices(bool pNewStatus)
171 {
172 if (pNewStatus == Env::getSingleton<RemoteClient>()->isDetecting())
173 {
174 return;
175 }
176
177 if (pNewStatus)
178 {
179 mAvailableRemoteDevices.onUiShown();
180 mKnownDevices.onUiShown();
181 }
182 else
183 {
184 mAvailableRemoteDevices.onUiHidden();
185 mKnownDevices.onUiHidden();
186 }
187 }
188
189
detectRemoteDevices() const190 bool RemoteServiceModel::detectRemoteDevices() const
191 {
192 return Env::getSingleton<RemoteClient>()->isDetecting();
193 }
194
195
connectToRememberedServer(const QString & pServerPsk)196 void RemoteServiceModel::connectToRememberedServer(const QString& pServerPsk)
197 {
198 if (!pServerPsk.isEmpty() && !mRememberedServerEntry.isNull())
199 {
200 auto* const remoteClient = Env::getSingleton<RemoteClient>();
201 connect(remoteClient, &RemoteClient::fireEstablishConnectionDone, this, &RemoteServiceModel::onEstablishConnectionDone);
202
203 qDebug() << "Starting to pair.";
204 remoteClient->establishConnection(mRememberedServerEntry, pServerPsk);
205 }
206 }
207
208
rememberServer(const QString & pDeviceId)209 bool RemoteServiceModel::rememberServer(const QString& pDeviceId)
210 {
211 mRememberedServerEntry = mAvailableRemoteDevices.getRemoteDeviceListEntry(pDeviceId);
212 return !mRememberedServerEntry.isNull();
213 }
214
215
onEstablishConnectionDone(const QSharedPointer<RemoteDeviceListEntry> & pEntry,const GlobalStatus & pStatus)216 void RemoteServiceModel::onEstablishConnectionDone(const QSharedPointer<RemoteDeviceListEntry>& pEntry, const GlobalStatus& pStatus)
217 {
218 const auto* const remoteClient = Env::getSingleton<RemoteClient>();
219 disconnect(remoteClient, &RemoteClient::fireEstablishConnectionDone, this, &RemoteServiceModel::onEstablishConnectionDone);
220 qDebug() << "Pairing finished:" << pStatus;
221 const auto deviceName = RemoteServiceSettings::escapeDeviceName(pEntry->getRemoteDeviceDescriptor().getIfdName());
222 if (pStatus.isError())
223 {
224 Q_EMIT firePairingFailed(deviceName, pStatus.toErrorDescription());
225 }
226 else
227 {
228 Q_EMIT firePairingSuccess(deviceName);
229 }
230 }
231
232
onConnectionInfoChanged(bool pConnected)233 void RemoteServiceModel::onConnectionInfoChanged(bool pConnected)
234 {
235 if (mContext && pConnected)
236 {
237 const RemoteServiceSettings& settings = Env::getSingleton<AppSettings>()->getRemoteServiceSettings();
238 const QString peerName = settings.getRemoteInfo(mContext->getRemoteServer()->getCurrentCertificate()).getNameEscaped();
239 //: INFO ANDROID IOS The smartphone is connected as card reader (SaK) and currently processing an authentication request. The user is asked to pay attention the its screen.
240 mConnectionInfo = tr("Please pay attention to the display on your other device \"%1\".").arg(peerName);
241 Q_EMIT fireConnectionInfoChanged();
242 }
243 Q_EMIT fireConnectedChanged();
244 }
245
246
onCardConnectionEstablished(const QSharedPointer<CardConnection> & pConnection)247 void RemoteServiceModel::onCardConnectionEstablished(const QSharedPointer<CardConnection>& pConnection)
248 {
249 pConnection->setProgressMessage(mConnectionInfo);
250 }
251
252
resetRemoteServiceContext(const QSharedPointer<RemoteServiceContext> & pContext)253 void RemoteServiceModel::resetRemoteServiceContext(const QSharedPointer<RemoteServiceContext>& pContext)
254 {
255 mContext = pContext;
256 WorkflowModel::resetWorkflowContext(pContext);
257
258 mPsk.clear();
259 onEstablishPaceChannelUpdated();
260
261 if (mContext)
262 {
263 connect(mContext.data(), &RemoteServiceContext::fireIsRunningChanged, this, [this](){
264 setStarting(false);
265 });
266 connect(mContext.data(), &RemoteServiceContext::fireIsRunningChanged, this, &RemoteServiceModel::fireIsRunningChanged);
267 connect(mContext->getRemoteServer().data(), &RemoteServer::firePskChanged, this, [this](const QByteArray& pPsk){
268 mPsk = pPsk;
269 });
270 connect(mContext->getRemoteServer().data(), &RemoteServer::firePskChanged, this, &RemoteServiceModel::firePskChanged);
271 connect(mContext->getRemoteServer().data(), &RemoteServer::fireConnectedChanged, this, &RemoteServiceModel::onConnectionInfoChanged);
272 connect(mContext->getRemoteServer().data(), &RemoteServer::firePairingCompleted, this, &RemoteServiceModel::firePairingCompleted);
273 connect(mContext.data(), &RemoteServiceContext::fireCardConnectionEstablished, this, &RemoteServiceModel::onCardConnectionEstablished);
274 connect(mContext.data(), &RemoteServiceContext::fireEstablishPaceChannelUpdated, this, &RemoteServiceModel::onEstablishPaceChannelUpdated);
275
276 setPairing(mPairingRequested);
277 }
278 else
279 {
280 setStarting(false);
281 }
282
283 mPairingRequested = false;
284
285 Q_EMIT fireIsRunningChanged();
286 Q_EMIT fireConnectedChanged();
287 }
288
289
setPairing(bool pEnabled)290 void RemoteServiceModel::setPairing(bool pEnabled)
291 {
292 if (mContext)
293 {
294 mContext->getRemoteServer()->setPairing(pEnabled);
295 }
296 }
297
298
isPairing()299 bool RemoteServiceModel::isPairing()
300 {
301 if (!mContext)
302 {
303 return false;
304 }
305
306 return !getPsk().isEmpty();
307 }
308
309
isConnectedToPairedDevice() const310 bool RemoteServiceModel::isConnectedToPairedDevice() const
311 {
312 if (mContext)
313 {
314 return mContext->getRemoteServer()->isConnected() && !mContext->getRemoteServer()->isPairingConnection();
315 }
316
317 return false;
318 }
319
320
enableTransportPinLink() const321 bool RemoteServiceModel::enableTransportPinLink() const
322 {
323 return mContext && mContext->isPinChangeWorkflow() && mContext->getPreferredPinLength() == 0;
324 }
325
326
isRequestTransportPin() const327 bool RemoteServiceModel::isRequestTransportPin() const
328 {
329 return mRequestTransportPin;
330 }
331
332
isRunnable() const333 bool RemoteServiceModel::isRunnable() const
334 {
335 return mRunnable;
336 }
337
338
isCanEnableNfc() const339 bool RemoteServiceModel::isCanEnableNfc() const
340 {
341 return mCanEnableNfc;
342 }
343
344
getErrorMessage() const345 QString RemoteServiceModel::getErrorMessage() const
346 {
347 return mErrorMessage;
348 }
349
350
getPsk() const351 QByteArray RemoteServiceModel::getPsk() const
352 {
353 return mPsk;
354 }
355
356
getConnectionInfo() const357 QString RemoteServiceModel::getConnectionInfo() const
358 {
359 return mConnectionInfo;
360 }
361
362
getConnectedServerDeviceNames() const363 QString RemoteServiceModel::getConnectedServerDeviceNames() const
364 {
365 return mConnectedServerDeviceNames;
366 }
367
368
getRemoteReaderVisible() const369 bool RemoteServiceModel::getRemoteReaderVisible() const
370 {
371 return Env::getSingleton<RemoteClient>()->hasAnnouncingRemoteDevices();
372 }
373
374
pinPadModeOn() const375 bool RemoteServiceModel::pinPadModeOn() const
376 {
377 return Env::getSingleton<AppSettings>()->getRemoteServiceSettings().getPinPadMode();
378 }
379
380
getPasswordType() const381 QString RemoteServiceModel::getPasswordType() const
382 {
383 if (!mContext)
384 {
385 return QString();
386 }
387
388 switch (mContext->getEstablishPaceChannel().getPasswordId())
389 {
390 case PacePasswordId::PACE_CAN:
391 return QStringLiteral("CAN");
392
393 case PacePasswordId::PACE_PIN:
394 return QStringLiteral("PIN");
395
396 case PacePasswordId::PACE_PUK:
397 return QStringLiteral("PUK");
398
399 default:
400 return QString();
401 }
402 }
403
404
getErrorMessage(bool pNfcPluginAvailable,bool pNfcPluginEnabled,bool pWifiEnabled) const405 QString RemoteServiceModel::getErrorMessage(bool pNfcPluginAvailable, bool pNfcPluginEnabled, bool pWifiEnabled) const
406 {
407 if (!pNfcPluginAvailable)
408 {
409 //: INFO ALL_PLATFORMS The device does not offer NFC.
410 return tr("NFC is not available on your device.");
411 }
412 if (!pNfcPluginEnabled)
413 {
414 //: INFO ALL_PLATFORMS NFC is available but not active.
415 return tr("Please enable NFC to use the remote service.");
416 }
417 if (!pWifiEnabled)
418 {
419 //: INFO ALL_PLATFORMS The WiFi feature is not enabled but required to use the smartphone as a card reader (SaK).
420 return tr("Please connect your WiFi to use the remote service.");
421 }
422
423 return QString();
424 }
425
426
forgetDevice(const QString & pId)427 void RemoteServiceModel::forgetDevice(const QString& pId)
428 {
429 mKnownDevices.forgetDevice(pId);
430 }
431
432
cancelPasswordRequest()433 void RemoteServiceModel::cancelPasswordRequest()
434 {
435 if (mContext)
436 {
437 Q_EMIT mContext->fireCancelPasswordRequest();
438 }
439 }
440
441
changePinLength()442 void RemoteServiceModel::changePinLength()
443 {
444 mRequestTransportPin = !mRequestTransportPin;
445 Q_EMIT fireEstablishPaceChannelUpdated();
446 }
447
448
onConnectedDevicesChanged()449 void RemoteServiceModel::onConnectedDevicesChanged()
450 {
451 auto* const remoteClient = Env::getSingleton<RemoteClient>();
452 const auto deviceInfos = remoteClient->getConnectedDeviceInfos();
453 QStringList deviceNames;
454 for (const auto& info : deviceInfos)
455 {
456 deviceNames.append(QLatin1Char('"') + info.getNameEscaped() + QLatin1Char('"'));
457 }
458 mConnectedServerDeviceNames = deviceNames.join(QLatin1String(", "));
459 Q_EMIT fireConnectedServerDeviceNamesChanged();
460 }
461
462
onEstablishPaceChannelUpdated()463 void RemoteServiceModel::onEstablishPaceChannelUpdated()
464 {
465 mRequestTransportPin = (mContext && mContext->isPinChangeWorkflow() && mContext->getPreferredPinLength() == 5);
466 Q_EMIT fireEstablishPaceChannelUpdated();
467 }
468