1 /*
2 * Copyright (c) 2017-2018 Nitrokey UG
3 *
4 * This file is part of Nitrokey App.
5 *
6 * Nitrokey App is free software: you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License as published by
8 * the Free Software Foundation, either version 3 of the License, or
9 * any later version.
10 *
11 * Nitrokey App is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU General Public License for more details.
15 *
16 * You should have received a copy of the GNU General Public License
17 * along with Nitrokey App. If not, see <http://www.gnu.org/licenses/>.
18 *
19 * SPDX-License-Identifier: GPL-3.0
20 */
21
22 /*
23 TODO
24 1. remove doubled debug
25 2. remove stick10 changing pin
26 */
27
28 #include "Tray.h"
29 #include <QThread>
30 #include "libada.h"
31 #include "bool_values.h"
32 #include "nitrokey-applet.h"
33 #include <libnitrokey/NitrokeyManager.h>
34 #include <QMenu>
35 #include <QMenuBar>
36 #include "graphicstools.h"
37
Tray(QObject * _parent,bool _debug_mode,bool _extended_config,StorageActions * actions)38 Tray::Tray(QObject *_parent, bool _debug_mode, bool _extended_config,
39 StorageActions *actions) :
40 QObject(_parent),
41 trayMenu(nullptr),
42 trayMenuPasswdSubMenu(nullptr),
43 file_menu(nullptr),
44 worker(nullptr)
45 {
46 main_window = _parent;
47 storageActions = actions;
48 debug_mode = _debug_mode;
49 ExtendedConfigActive = _extended_config;
50
51 createIndicator();
52 initActionsForStick10();
53 initActionsForStick20();
54 initCommonActions();
55
56 mapper_TOTP = new QSignalMapper(this);
57 mapper_HOTP = new QSignalMapper(this);
58 mapper_PWS = new QSignalMapper(this);
59 connect(mapper_TOTP, SIGNAL(mapped(int)), main_window, SLOT(getTOTPDialog(int)));
60 connect(mapper_HOTP, SIGNAL(mapped(int)), main_window, SLOT(getHOTPDialog(int)));
61 connect(mapper_PWS, SIGNAL(mapped(int)), main_window, SLOT(PWS_ExceClickedSlot(int)));
62 }
63
setDebug_mode(bool _debug_mode)64 void Tray::setDebug_mode(bool _debug_mode) {
65 debug_mode = _debug_mode;
66 }
67
~Tray()68 Tray::~Tray() {
69 destroyThread();
70 }
71
delayedShowIndicator()72 void Tray::delayedShowIndicator(){
73 if(!trayIcon->isSystemTrayAvailable()) return;
74 trayIcon->show();
75 delayedShowTimer->stop();
76 }
77
78 /*
79 * Create the tray menu.
80 */
createIndicator()81 void Tray::createIndicator() {
82 trayIcon = new QSystemTrayIcon(this);
83 trayIcon->setIcon(GraphicsTools::loadColorize(":/images/new/icon_NK.svg", true));
84 connect(trayIcon, SIGNAL(activated(QSystemTrayIcon::ActivationReason)), this,
85 SLOT(iconActivated(QSystemTrayIcon::ActivationReason)));
86
87 delayedShowTimer = new QTimer(this);
88 connect(delayedShowTimer, SIGNAL(timeout()), this, SLOT(delayedShowIndicator()));
89 delayedShowTimer->setSingleShot(false);
90 delayedShowTimer->start(2000);
91
92 // Initial message
93 if (debug_mode)
94 showTrayMessage("Nitrokey App", tr("Active (debug mode)"), INFORMATION, TRAY_MSG_TIMEOUT);
95 else
96 showTrayMessage("Nitrokey App", tr("Active"), INFORMATION, TRAY_MSG_TIMEOUT);
97 }
98
showTrayMessage(QString message)99 void Tray::showTrayMessage(QString message) {
100 showTrayMessage("Nitrokey App", message, INFORMATION, 2000);
101 }
102
showTrayMessage(const QString & title,const QString & msg,enum trayMessageType type,int timeout)103 void Tray::showTrayMessage(const QString &title, const QString &msg,
104 enum trayMessageType type, int timeout) {
105 if(debug_mode)
106 qDebug() << msg;
107 if (trayIcon->supportsMessages()) {
108 switch (type) {
109 case INFORMATION:
110 trayIcon->showMessage(title, msg, QSystemTrayIcon::Information, timeout);
111 break;
112 case WARNING:
113 trayIcon->showMessage(title, msg, QSystemTrayIcon::Warning, timeout);
114 break;
115 case CRITICAL:
116 trayIcon->showMessage(title, msg, QSystemTrayIcon::Critical, timeout);
117 break;
118 }
119 } else
120 csApplet()->messageBox(msg);
121 }
122
iconActivated(QSystemTrayIcon::ActivationReason reason)123 void Tray::iconActivated(QSystemTrayIcon::ActivationReason reason) {
124
125 switch (reason) {
126 case QSystemTrayIcon::Context:
127 // trayMenu->close();
128 #ifdef Q_OS_MAC
129 trayMenu->popup(QCursor::pos());
130 #endif
131 break;
132 case QSystemTrayIcon::Trigger:
133 #ifndef Q_OS_MAC
134 trayMenu->popup(QCursor::pos());
135 #endif
136 break;
137 case QSystemTrayIcon::DoubleClick:
138 break;
139 case QSystemTrayIcon::MiddleClick:
140 break;
141 default:;
142 }
143 }
144
eventFilter(QObject * obj,QEvent * event)145 bool Tray::eventFilter(QObject *obj, QEvent *event) {
146 if (event->type() == QEvent::MouseButtonPress) {
147 QMouseEvent *mEvent = static_cast<QMouseEvent *>(event);
148
149 if (mEvent->button() == Qt::LeftButton) {
150 /*
151 QMouseEvent my_event = new QMouseEvent ( mEvent->type(), mEvent->pos(),
152 Qt::Rightbutton , mEvent->buttons(), mEvent->modifiers() );
153 QCoreApplication::postEvent ( trayIcon, my_event ); */
154 return true;
155 }
156 }
157 return QObject::eventFilter(obj, event);
158 }
159
generateMenu(bool init,std::function<void (QMenu *)> run_before)160 void Tray::generateMenu(bool init, std::function<void(QMenu *)> run_before) {
161 static QMutex mtx;
162 QMutexLocker locker(&mtx);
163
164 if (nullptr == trayMenu)
165 trayMenu = std::make_shared<QMenu>();
166 else
167 trayMenu->clear(); // Clear old menu
168
169 if (nullptr == windowMenu)
170 windowMenu = std::make_shared<QMenu>("Menu");
171 else
172 windowMenu->clear(); // Clear old menu
173
174
175 run_before(trayMenu.get());
176
177 if (!init){
178 // Setup the new menu
179 if (!libada::i()->isDeviceConnected()) {
180 trayMenu->addAction(tr("Nitrokey is not connected!"));
181 } else {
182 if (!libada::i()->isStorageDeviceConnected()) // Nitrokey Pro connected
183 generateMenuForProDevice();
184 else {
185 // Nitrokey Storage is connected
186 generateMenuForStorageDevice();
187 }
188 }
189 }
190
191 // Add debug window ?
192 if (debug_mode){
193 trayMenu->addAction(DebugAction);
194 windowMenu->addAction(DebugAction);
195 }
196
197 trayMenu->addSeparator();
198
199 if (!long_operation_in_progress)
200 trayMenu->addAction(ShowWindowAction);
201
202 trayMenu->addAction(ActionHelp_tray);
203 trayMenu->addAction(ActionAboutDialog_tray);
204 trayMenu->addAction(quitAction_tray);
205
206 windowMenu->addSeparator();
207 windowMenu->addAction(ActionHelp);
208 windowMenu->addAction(ActionAboutDialog);
209 windowMenu->addAction(quitAction);
210
211 trayIcon->setContextMenu(trayMenu.get());
212
213 if (file_menu != nullptr && windowMenu != nullptr){
214 // file_menu->addMenu(windowMenu.get()); // does not work for macOS
215 file_menu->addAction(windowMenu->menuAction());
216 }
217 }
218
initActionsForStick10()219 void Tray::initActionsForStick10() {
220 UnlockPasswordSafeAction = new QAction(tr("Unlock password safe"), main_window);
221 UnlockPasswordSafeAction->setIcon(GraphicsTools::loadColorize(":/images/new/icon_safe.svg"));
222 connect(UnlockPasswordSafeAction, SIGNAL(triggered()), main_window, SLOT(PWS_Clicked_EnablePWSAccess()));
223
224 UnlockPasswordSafeAction_tray = new QAction(tr("Unlock password safe"), main_window);
225 UnlockPasswordSafeAction_tray->setIcon(GraphicsTools::loadColorize(":/images/new/icon_safe.svg", true));
226 connect(UnlockPasswordSafeAction_tray, SIGNAL(triggered()), main_window, SLOT(PWS_Clicked_EnablePWSAccess()));
227
228 configureAction = new QAction(tr("&OTP"), main_window);
229 connect(configureAction, SIGNAL(triggered()), main_window, SLOT(startConfiguration()));
230
231 resetAction = new QAction(tr("&Factory reset"), main_window);
232 connect(resetAction, SIGNAL(triggered()), main_window, SLOT(factoryResetAction()));
233
234 Stick10ActionChangeUserPIN = new QAction(tr("&Change User PIN"), main_window);
235 connect(Stick10ActionChangeUserPIN, SIGNAL(triggered()), main_window,
236 SLOT(startStick20ActionChangeUserPIN()));
237
238 Stick10ActionChangeAdminPIN = new QAction(tr("&Change Admin PIN"), main_window);
239 connect(Stick10ActionChangeAdminPIN, SIGNAL(triggered()), main_window,
240 SLOT(startStick20ActionChangeAdminPIN()));
241 }
242
initCommonActions()243 void Tray::initCommonActions() {
244 DebugAction = new QAction(tr("&Debug"), main_window);
245 connect(DebugAction, SIGNAL(triggered()), main_window, SLOT(startStickDebug()));
246
247 ShowWindowAction = new QAction(tr("&Overview"), main_window);
248 connect(ShowWindowAction, SIGNAL(triggered()), main_window, SLOT(startConfigurationMain()));
249
250 quitAction_tray = new QAction(tr("&Quit"), main_window);
251 quitAction_tray->setIcon(GraphicsTools::loadColorize(":/images/new/icon_quit.svg", true));
252 connect(quitAction_tray, SIGNAL(triggered()), qApp, SLOT(quit()));
253
254 quitAction = new QAction(tr("&Quit"), main_window);
255 quitAction->setIcon(GraphicsTools::loadColorize(":/images/new/icon_quit.svg"));
256 connect(quitAction, SIGNAL(triggered()), qApp, SLOT(quit()));
257
258 ActionHelp = new QAction(tr("&Help"), main_window);
259 ActionHelp->setIcon(GraphicsTools::loadColorize(":/images/new/icon_fragezeichen.svg"));
260 connect(ActionHelp, SIGNAL(triggered()), main_window, SLOT(startHelpAction()));
261
262 ActionHelp_tray = new QAction(tr("&Help"), main_window);
263 ActionHelp_tray->setIcon(GraphicsTools::loadColorize(":/images/new/icon_fragezeichen.svg", true));
264 connect(ActionHelp_tray, SIGNAL(triggered()), main_window, SLOT(startHelpAction()));
265
266 ActionAboutDialog = new QAction(tr("&About Nitrokey"), main_window);
267 ActionAboutDialog->setIcon(GraphicsTools::loadColorize(":/images/new/icon_about_nitrokey.svg"));
268 connect(ActionAboutDialog, SIGNAL(triggered()), main_window, SLOT(startAboutDialog()));
269
270 ActionAboutDialog_tray = new QAction(tr("&About Nitrokey"), main_window);
271 ActionAboutDialog_tray->setIcon(GraphicsTools::loadColorize(":/images/new/icon_about_nitrokey.svg", true));
272 connect(ActionAboutDialog_tray, SIGNAL(triggered()), main_window, SLOT(startAboutDialog()));
273 }
274
initActionsForStick20()275 void Tray::initActionsForStick20() {
276 configureActionStick20 = new QAction(tr("&OTP and Password safe"), main_window);
277 connect(configureActionStick20, SIGNAL(triggered()), main_window, SLOT(startConfiguration()));
278
279 Stick20ActionEnableCryptedVolume = new QAction(tr("&Unlock encrypted volume"), main_window);
280 Stick20ActionEnableCryptedVolume->setIcon(GraphicsTools::loadColorize(":/images/new/icon_harddrive.svg"));
281 connect(Stick20ActionEnableCryptedVolume, SIGNAL(triggered()), storageActions,
282 SLOT(startStick20EnableCryptedVolume()));
283
284 Stick20ActionDisableCryptedVolume = new QAction(tr("&Lock encrypted volume"), main_window);
285 Stick20ActionDisableCryptedVolume->setIcon(GraphicsTools::loadColorize(":/images/new/icon_harddrive.svg"));
286 connect(Stick20ActionDisableCryptedVolume, SIGNAL(triggered()), storageActions,
287 SLOT(startStick20DisableCryptedVolume()));
288
289 Stick20ActionEnableHiddenVolume = new QAction(tr("&Unlock hidden volume"), main_window);
290 Stick20ActionEnableHiddenVolume->setIcon(GraphicsTools::loadColorize(":/images/new/icon_harddrive.svg"));
291 connect(Stick20ActionEnableHiddenVolume, SIGNAL(triggered()), storageActions,
292 SLOT(startStick20EnableHiddenVolume()));
293
294 Stick20ActionDisableHiddenVolume = new QAction(tr("&Lock hidden volume"), main_window);
295 Stick20ActionDisableHiddenVolume->setIcon(GraphicsTools::loadColorize(":/images/new/icon_harddrive.svg"));
296 connect(Stick20ActionDisableHiddenVolume, SIGNAL(triggered()), storageActions,
297 SLOT(startStick20DisableHiddenVolume()));
298
299
300 Stick20ActionEnableCryptedVolume_tray = new QAction(tr("&Unlock encrypted volume"), main_window);
301 Stick20ActionEnableCryptedVolume_tray->setIcon(GraphicsTools::loadColorize(":/images/new/icon_harddrive.svg", true));
302 connect(Stick20ActionEnableCryptedVolume_tray, SIGNAL(triggered()), storageActions,
303 SLOT(startStick20EnableCryptedVolume()));
304
305 Stick20ActionDisableCryptedVolume_tray = new QAction(tr("&Lock encrypted volume"), main_window);
306 Stick20ActionDisableCryptedVolume_tray->setIcon(GraphicsTools::loadColorize(":/images/new/icon_harddrive.svg", true));
307 connect(Stick20ActionDisableCryptedVolume_tray, SIGNAL(triggered()), storageActions,
308 SLOT(startStick20DisableCryptedVolume()));
309
310 Stick20ActionEnableHiddenVolume_tray = new QAction(tr("&Unlock hidden volume"), main_window);
311 Stick20ActionEnableHiddenVolume_tray->setIcon(GraphicsTools::loadColorize(":/images/new/icon_harddrive.svg", true));
312 connect(Stick20ActionEnableHiddenVolume_tray, SIGNAL(triggered()), storageActions,
313 SLOT(startStick20EnableHiddenVolume()));
314
315 Stick20ActionDisableHiddenVolume_tray = new QAction(tr("&Lock hidden volume"), main_window);
316 Stick20ActionDisableHiddenVolume_tray->setIcon(GraphicsTools::loadColorize(":/images/new/icon_harddrive.svg", true));
317 connect(Stick20ActionDisableHiddenVolume_tray, SIGNAL(triggered()), storageActions,
318 SLOT(startStick20DisableHiddenVolume()));
319
320 Stick20ActionChangeUserPIN = new QAction(tr("&Change User PIN"), main_window);
321 connect(Stick20ActionChangeUserPIN, SIGNAL(triggered()), main_window,
322 SLOT(startStick20ActionChangeUserPIN()));
323
324 Stick20ActionChangeAdminPIN = new QAction(tr("&Change Admin PIN"), main_window);
325 connect(Stick20ActionChangeAdminPIN, SIGNAL(triggered()), main_window,
326 SLOT(startStick20ActionChangeAdminPIN()));
327
328 Stick20ActionChangeUpdatePIN = new QAction(tr("&Change Firmware Password"), main_window);
329 connect(Stick20ActionChangeUpdatePIN, SIGNAL(triggered()), main_window,
330 SLOT(startStick20ActionChangeUpdatePIN()));
331
332 Stick20ActionEnableFirmwareUpdate = new QAction(tr("&Enable firmware update"), main_window);
333 connect(Stick20ActionEnableFirmwareUpdate, SIGNAL(triggered()), storageActions,
334 SLOT(startStick20EnableFirmwareUpdate()));
335
336 Stick20ActionExportFirmwareToFile = new QAction(tr("&Export firmware to file"), main_window);
337 connect(Stick20ActionExportFirmwareToFile, SIGNAL(triggered()), storageActions,
338 SLOT(startStick20ExportFirmwareToFile()));
339
340 QSignalMapper *signalMapper_startStick20DestroyCryptedVolume =
341 new QSignalMapper(main_window);
342
343 Stick20ActionDestroyCryptedVolume = new QAction(tr("&Destroy encrypted data"), main_window);
344 signalMapper_startStick20DestroyCryptedVolume->setMapping(Stick20ActionDestroyCryptedVolume, 0);
345 connect(Stick20ActionDestroyCryptedVolume, SIGNAL(triggered()),
346 signalMapper_startStick20DestroyCryptedVolume, SLOT(map()));
347
348 Stick20ActionInitCryptedVolume = new QAction(tr("&Initialize device"), main_window);
349 signalMapper_startStick20DestroyCryptedVolume->setMapping(Stick20ActionInitCryptedVolume, 1);
350 connect(Stick20ActionInitCryptedVolume, SIGNAL(triggered()),
351 signalMapper_startStick20DestroyCryptedVolume, SLOT(map()));
352
353 connect(signalMapper_startStick20DestroyCryptedVolume, SIGNAL(mapped(int)), storageActions,
354 SLOT(startStick20DestroyCryptedVolume(int)));
355
356 Stick20ActionFillSDCardWithRandomChars =
357 new QAction(tr("&Initialize storage with random data"), main_window);
358 connect(Stick20ActionFillSDCardWithRandomChars, SIGNAL(triggered()), storageActions,
359 SLOT(startStick20FillSDCardWithRandomChars()));
360
361 Stick20ActionSetReadonlyUncryptedVolume =
362 new QAction(tr("&Set unencrypted volume read-only"), main_window);
363 connect(Stick20ActionSetReadonlyUncryptedVolume, SIGNAL(triggered()), storageActions,
364 SLOT(startStick20SetReadOnlyUncryptedVolume()));
365
366 Stick20ActionSetReadWriteUncryptedVolume =
367 new QAction(tr("&Set unencrypted volume read-write"), main_window);
368 connect(Stick20ActionSetReadWriteUncryptedVolume, SIGNAL(triggered()), storageActions,
369 SLOT(startStick20SetReadWriteUncryptedVolume()));
370
371 //do not show until supported
372 #if 0
373 Stick20ActionSetReadonlyEncryptedVolume =
374 new QAction(tr("&Set encrypted volume read-only"), main_window);
375 connect(Stick20ActionSetReadonlyEncryptedVolume, SIGNAL(triggered()), storageActions,
376 SLOT(startStick20SetReadOnlyEncryptedVolume()));
377
378 Stick20ActionSetReadWriteEncryptedVolume =
379 new QAction(tr("&Set encrypted volume read-write"), main_window);
380 connect(Stick20ActionSetReadWriteEncryptedVolume, SIGNAL(triggered()), storageActions,
381 SLOT(startStick20SetReadWriteEncryptedVolume()));
382 #endif
383
384 // Stick20ActionDebugAction = new QAction(tr("&Debug"), main_window);
385 // connect(Stick20ActionDebugAction, SIGNAL(triggered()), storageActions, SLOT(startStick20DebugAction()));
386
387 Stick20ActionSetupHiddenVolume = new QAction(tr("&Setup hidden volume"), main_window);
388 connect(Stick20ActionSetupHiddenVolume, SIGNAL(triggered()), storageActions,
389 SLOT(startStick20SetupHiddenVolume()));
390
391 Stick20ActionClearNewSDCardFound =
392 new QAction(tr("&Disable 'initialize storage with random data' warning"), main_window);
393 connect(Stick20ActionClearNewSDCardFound, SIGNAL(triggered()), storageActions,
394 SLOT(startStick20ClearNewSdCardFound()));
395
396 Stick20ActionLockStickHardware = new QAction(tr("&Lock stick hardware"), main_window);
397 connect(Stick20ActionLockStickHardware, SIGNAL(triggered()), storageActions,
398 SLOT(startStick20LockStickHardware()));
399
400 Stick20ActionResetUserPassword = new QAction(tr("&Reset User PIN"), main_window);
401 connect(Stick20ActionResetUserPassword, SIGNAL(triggered()), main_window,
402 SLOT(startResetUserPassword()));
403
404 LockDeviceAction = new QAction(tr("&Lock Device"), main_window);
405 LockDeviceAction->setIcon(GraphicsTools::loadColorize(":/images/new/icon_unsafe.svg"));
406 connect(LockDeviceAction, SIGNAL(triggered()), main_window, SLOT(startLockDeviceAction()));
407
408 Stick20ActionUpdateStickStatus = new QAction(tr("Smartcard or SD card are not ready"), main_window);
409 connect(Stick20ActionUpdateStickStatus, SIGNAL(triggered()), main_window, SLOT(startAboutDialog()));
410 }
411
412
413 std::shared_ptr<QThread> thread_tray_populateOTP;
414
doWork()415 void tray_Worker::doWork() {
416 QMutexLocker mutexLocker(&mtx);
417 auto passwordSafeUnlocked = libada::i()->isPasswordSafeUnlocked();
418 const auto total = TOTP_SLOT_COUNT+HOTP_SLOT_COUNT+
419 (passwordSafeUnlocked?PWS_SLOT_COUNT:0)+1;
420 int p = 0;
421 emit progress(0);
422
423 //populate OTP name cache
424 for (int i=0; i < TOTP_SLOT_COUNT; i++){
425 auto slotName = libada::i()->getTOTPSlotName(i);
426 emit progress(++p * 100 / total);
427 }
428
429 for (int i=0; i<HOTP_SLOT_COUNT; i++){
430 auto slotName = libada::i()->getHOTPSlotName(i);
431 emit progress(++p * 100 / total);
432 }
433
434 if(passwordSafeUnlocked){
435 for (int i=0; i<PWS_SLOT_COUNT; i++){
436 if(libada::i()->getPWSSlotStatus(i))
437 auto slotName = libada::i()->getPWSSlotName(i);
438 emit progress(++p * 100 / total);
439 }
440 }
441
442 emit progress(100);
443 emit resultReady();
444 }
445
generatePasswordMenu()446 void Tray::generatePasswordMenu() {
447 trayMenuPasswdSubMenu = std::make_shared<QMenu>(tr("Passwords"));
448 trayMenuPasswdSubMenu->setIcon(GraphicsTools::loadColorize(":/images/new/icon_passwords.svg"));
449
450 trayMenuPasswdSubMenu_tray = std::make_shared<QMenu>(tr("Passwords"));
451 trayMenuPasswdSubMenu_tray->setIcon(GraphicsTools::loadColorize(":/images/new/icon_passwords.svg", true));
452
453
454 trayMenu->addMenu(trayMenuPasswdSubMenu_tray.get());
455 trayMenu->addSeparator();
456
457 windowMenu->addMenu(trayMenuPasswdSubMenu.get());
458 windowMenu->addSeparator();
459
460 if (thread_tray_populateOTP!= nullptr){
461 destroyThread();
462 }
463 thread_tray_populateOTP = std::make_shared<QThread>();
464 worker = new tray_Worker;
465 worker->moveToThread(thread_tray_populateOTP.get());
466 connect(thread_tray_populateOTP.get(), &QThread::finished, worker, &QObject::deleteLater);
467 connect(thread_tray_populateOTP.get(), SIGNAL(started()), worker, SLOT(doWork()));
468 connect(worker, SIGNAL(resultReady()), this, SLOT(populateOTPPasswordMenu()));
469
470 connect(worker, SIGNAL(resultReady()), main_window, SLOT(generateComboBoxEntrys()));
471 connect(worker, SIGNAL(progress(int)), this, SLOT(passOTPProgressFurther(int)));
472 connect(worker, SIGNAL(progress(int)), this, SLOT(showOTPProgressInTray(int)));
473
474 thread_tray_populateOTP->start();
475 }
476
destroyThread()477 void Tray::destroyThread() {
478 if (thread_tray_populateOTP == nullptr) return;
479 thread_tray_populateOTP->quit();
480 thread_tray_populateOTP->wait();
481 }
482
483 #include "mainwindow.h"
populateOTPPasswordMenu()484 void Tray::populateOTPPasswordMenu() {
485 //should not run before worker is done
486 QMutexLocker mutexLocker(&worker->mtx);
487
488 if (!trayMenuPasswdSubMenu->actions().empty()) {
489 return;
490 }
491
492
493 for (int i=0; i < TOTP_SLOT_COUNT; i++){
494 auto slotName = libada::i()->getTOTPSlotName(i);
495 bool slotProgrammed = libada::i()->isTOTPSlotProgrammed(i);
496 if (slotProgrammed){
497 auto action = trayMenuPasswdSubMenu->addAction(QString::fromStdString(slotName));
498 connect(action, SIGNAL(triggered()), mapper_TOTP, SLOT(map()));
499 mapper_TOTP->setMapping(action, i) ;
500 }
501 }
502
503 for (int i=0; i<HOTP_SLOT_COUNT; i++){
504 auto slotName = libada::i()->getHOTPSlotName(i);
505 bool slotProgrammed = libada::i()->isHOTPSlotProgrammed(i);
506 if (slotProgrammed){
507 auto action = trayMenuPasswdSubMenu->addAction(QString::fromStdString(slotName));
508 connect(action, SIGNAL(triggered()), mapper_HOTP, SLOT(map()));
509 mapper_HOTP->setMapping(action, i) ;
510 }
511 }
512
513 if (TRUE == libada::i()->isPasswordSafeUnlocked()) {
514 for (int i = 0; i < PWS_SLOT_COUNT; i++) {
515 if (libada::i()->getPWSSlotStatus(i)) {
516 auto slotName = libada::i()->getPWSSlotName(i);
517 auto action = trayMenuPasswdSubMenu->addAction(QString::fromStdString(slotName));
518 connect(action, SIGNAL(triggered()), mapper_PWS, SLOT(map()));
519 mapper_PWS->setMapping(action, i) ;
520 }
521 }
522 }
523
524 if (trayMenuPasswdSubMenu->actions().empty()) {
525 trayMenuPasswdSubMenu->setEnabled(false);
526 trayMenuPasswdSubMenu->setTitle( trayMenuPasswdSubMenu->title() + " " + tr("(empty)") );
527 }
528
529 trayMenuPasswdSubMenu_tray->addActions(trayMenuPasswdSubMenu->actions());
530
531 if (trayMenuPasswdSubMenu_tray->actions().empty()) {
532 trayMenuPasswdSubMenu_tray->setEnabled(false);
533 trayMenuPasswdSubMenu_tray->setTitle( trayMenuPasswdSubMenu_tray->title() + " " + tr("(empty)") );
534 }
535 }
536
537
generateMenuForProDevice()538 void Tray::generateMenuForProDevice() {
539 generatePasswordMenu();
540 trayMenu->addSeparator();
541 generateMenuPasswordSafe();
542
543 trayMenuSubConfigure = trayMenu->addMenu(tr("Configure"));
544 trayMenuSubConfigure->setIcon(GraphicsTools::loadColorize(":/images/new/icon_settings.svg"));
545
546 if (TRUE == libada::i()->isPasswordSafeAvailable())
547 trayMenuSubConfigure->addAction(configureActionStick20);
548 else
549 trayMenuSubConfigure->addAction(configureAction);
550
551 trayMenuSubConfigure->addSeparator();
552
553 trayMenuSubConfigure->addAction(Stick10ActionChangeUserPIN);
554 trayMenuSubConfigure->addAction(Stick10ActionChangeAdminPIN);
555
556 // Enable "reset user PIN" ?
557 if (0 == libada::i()->getUserPasswordRetryCount())
558 {
559 trayMenuSubConfigure->addAction(Stick20ActionResetUserPassword);
560 }
561
562 if (ExtendedConfigActive) {
563 trayMenuSubConfigure->addSeparator();
564 trayMenuSubConfigure->addAction(resetAction);
565 }
566 windowMenu->addMenu(trayMenuSubConfigure);
567 }
568 using nm = nitrokey::NitrokeyManager;
569
generateMenuForStorageDevice()570 void Tray::generateMenuForStorageDevice() {
571 int AddSeperator = FALSE;
572 {
573 nitrokey::proto::stick20::DeviceConfigurationResponsePacket::ResponsePayload status;
574
575 for (int i=0; i < 20; i++){
576 try {
577 status = nm::instance()->get_status_storage();
578 if(status.ActiveSD_CardID_u32 != 0) break;
579 auto message = "No active SD card or empty Storage status received, retrying " + std::to_string(i);
580 LOG(message, nitrokey::log::Loglevel::DEBUG);
581 }
582 catch (LongOperationInProgressException &e){
583 long_operation_in_progress = true;
584 return;
585 }
586 catch (DeviceCommunicationException &e){
587 //TODO add info to tray about the error?
588 return;
589 }
590 }
591 long_operation_in_progress = false;
592
593 if (status.ActiveSD_CardID_u32 == 0) // Is Stick 2.0 online (SD + SC
594 // accessable?)
595 {
596 trayMenu->addAction(Stick20ActionUpdateStickStatus);
597 LOG("SD card status not active, aborting", nitrokey::log::Loglevel::DEBUG);
598 return;
599 }
600
601 // Add special entrys
602 // if (TRUE == StickNotInitated) {
603 if (TRUE == status.StickKeysNotInitiated) {
604 trayMenu->addAction(Stick20ActionInitCryptedVolume);
605 windowMenu->addAction(Stick20ActionInitCryptedVolume);
606 AddSeperator = TRUE;
607 }
608
609 // if (FALSE == StickNotInitated && TRUE == SdCardNotErased) {
610 if (!status.StickKeysNotInitiated && !status.SDFillWithRandomChars_u8) {
611 trayMenu->addAction(Stick20ActionFillSDCardWithRandomChars);
612 windowMenu->addAction(Stick20ActionFillSDCardWithRandomChars);
613 AddSeperator = TRUE;
614 }
615
616 if (TRUE == AddSeperator){
617 trayMenu->addSeparator();
618 windowMenu->addSeparator();
619 }
620
621 generatePasswordMenu();
622 trayMenu->addSeparator();
623
624 if (!status.StickKeysNotInitiated) {
625 // Setup entrys for password safe
626 generateMenuPasswordSafe();
627 }
628
629 if (status.SDFillWithRandomChars_u8) { //filled randomly
630 if (!status.VolumeActiceFlag_st.encrypted){
631 trayMenu->addAction(Stick20ActionEnableCryptedVolume_tray);
632 windowMenu->addAction(Stick20ActionEnableCryptedVolume);
633 }
634 else{
635 trayMenu->addAction(Stick20ActionDisableCryptedVolume_tray);
636 windowMenu->addAction(Stick20ActionDisableCryptedVolume);
637 }
638
639 if (!status.VolumeActiceFlag_st.hidden){
640 trayMenu->addAction(Stick20ActionEnableHiddenVolume_tray);
641 windowMenu->addAction(Stick20ActionEnableHiddenVolume);
642 }
643 else{
644 trayMenu->addAction(Stick20ActionDisableHiddenVolume_tray);
645 windowMenu->addAction(Stick20ActionDisableHiddenVolume);
646 }
647 }
648
649 //FIXME run in separate thread
650 const auto PasswordSafeEnabled = libada::i()->isPasswordSafeUnlocked();
651 if (false != (status.VolumeActiceFlag_st.hidden || status.VolumeActiceFlag_st.encrypted || PasswordSafeEnabled)){
652 trayMenu->addAction(LockDeviceAction);
653 windowMenu->addAction(LockDeviceAction);
654 }
655
656 trayMenuSubConfigure = trayMenu->addMenu(tr("Configure"));
657 trayMenuSubConfigure->setIcon(GraphicsTools::loadColorize(":/images/new/icon_settings.svg"));
658 trayMenuSubConfigure->addAction(configureActionStick20);
659 trayMenuSubConfigure->addSeparator();
660
661 // Pin actions
662 trayMenuSubConfigure->addAction(Stick20ActionChangeUserPIN);
663 trayMenuSubConfigure->addAction(Stick20ActionChangeAdminPIN);
664 trayMenuSubConfigure->addAction(Stick20ActionChangeUpdatePIN);
665 trayMenuSubConfigure->addSeparator();
666
667 // Storage actions
668 auto read_write_active = status.ReadWriteFlagUncryptedVolume_u8 == 0;
669 if (read_write_active)
670 // Set readonly active
671 trayMenuSubConfigure->addAction(Stick20ActionSetReadonlyUncryptedVolume);
672 else
673 // Set RW active
674 trayMenuSubConfigure->addAction(Stick20ActionSetReadWriteUncryptedVolume);
675
676 #if 0
677 auto read_write_active_encrypted = status.ReadWriteFlagCryptedVolume_u8 == 0;
678 trayMenuSubConfigure->addAction(
679 read_write_active_encrypted ?
680 Stick20ActionSetReadonlyEncryptedVolume : Stick20ActionSetReadWriteEncryptedVolume
681 );
682 #endif
683
684 // if (FALSE == SdCardNotErased)
685 if (status.SDFillWithRandomChars_u8)
686 trayMenuSubConfigure->addAction(Stick20ActionSetupHiddenVolume);
687
688 trayMenuSubConfigure->addAction(Stick20ActionDestroyCryptedVolume);
689 trayMenuSubConfigure->addSeparator();
690
691 // Other actions
692 // if (TRUE == LockHardware) //FIXME
693 // trayMenuSubConfigure->addAction(Stick20ActionLockStickHardware);
694
695
696 trayMenuSubConfigure->addAction(Stick20ActionEnableFirmwareUpdate);
697 trayMenuSubConfigure->addAction(Stick20ActionExportFirmwareToFile);
698
699
700 if (TRUE == ExtendedConfigActive) {
701 trayMenuSubConfigure->addSeparator();
702 trayMenuSubSpecialConfigure = trayMenuSubConfigure->addMenu(tr("Special Configure"));
703 trayMenuSubSpecialConfigure->addAction(Stick20ActionFillSDCardWithRandomChars);
704
705 if (status.NewSDCardFound_u8 && !status.SDFillWithRandomChars_u8)
706 trayMenuSubSpecialConfigure->addAction(Stick20ActionClearNewSDCardFound);
707
708 trayMenuSubSpecialConfigure->addAction(resetAction);
709 }
710 windowMenu->addMenu(trayMenuSubConfigure);
711
712 // Enable "reset user PIN" ?
713 if (0 == libada::i()->getUserPasswordRetryCount()) {
714 trayMenu->addSeparator();
715 trayMenu->addAction(Stick20ActionResetUserPassword);
716 windowMenu->addAction(Stick20ActionResetUserPassword);
717 }
718
719 // // Add debug window ?
720 // if (TRUE == DebugWindowActive) {
721 // trayMenu->addSeparator();
722 // trayMenu->addAction(Stick20ActionDebugAction);
723 // }
724
725 }
726 }
727
UpdateDynamicMenuEntrys(void)728 int Tray::UpdateDynamicMenuEntrys(void) {
729 generateMenu(false);
730 return (TRUE);
731 }
732
generateMenuPasswordSafe()733 void Tray::generateMenuPasswordSafe() {
734 auto passwordSafeUnlocked = libada::i()->isPasswordSafeUnlocked();
735 if (!passwordSafeUnlocked) {
736 trayMenu->addAction(UnlockPasswordSafeAction_tray);
737 windowMenu->addAction(UnlockPasswordSafeAction);
738
739 auto passwordSafeAvailable = libada::i()->isPasswordSafeAvailable();
740 UnlockPasswordSafeAction->setEnabled(passwordSafeAvailable);
741 UnlockPasswordSafeAction_tray->setEnabled(passwordSafeAvailable);
742 } else {
743 trayMenu->addAction(LockDeviceAction);
744 windowMenu->addAction(LockDeviceAction);
745 }
746 }
747
regenerateMenu()748 void Tray::regenerateMenu() {
749 generateMenu(false);
750 }
751
passOTPProgressFurther(int i)752 void Tray::passOTPProgressFurther(int i) {
753 emit progress(i);
754 }
755
showOTPProgressInTray(int i)756 void Tray::showOTPProgressInTray(int i) {
757 static const QString &s = trayMenuPasswdSubMenu->title();
758 if (i!=100)
759 trayMenuPasswdSubMenu->setTitle(s +" ("+ QString::number(i) + "%)");
760 else
761 trayMenuPasswdSubMenu->setTitle(s);
762 }
763
updateOperationInProgressBar(int p)764 void Tray::updateOperationInProgressBar(int p) {
765 auto te = QString(tr("Long operation in progress: %1%")).arg(p);
766 static auto a = std::make_shared<QAction>("", nullptr);
767 connect(a.get(), SIGNAL(triggered()), main_window, SLOT(show_progress_window()));
768 if (trayMenu == nullptr) {
769 generateMenu(true);
770 }
771 static bool initialized = false;
772 if (!initialized){
773 this->showTrayMessage(te);
774 trayMenu->addAction(a.get());
775 initialized = true;
776 }
777 a->setText(te);
778 trayIcon->setContextMenu(trayMenu.get());
779 }
780
setAdmin_mode(bool _admin_mode)781 void Tray::setAdmin_mode(bool _admin_mode) {
782 ExtendedConfigActive = _admin_mode;
783 }
784
setFile_menu(QMenuBar * file_menu)785 void Tray::setFile_menu(QMenuBar *file_menu) {
786 Tray::file_menu = file_menu;
787 generateMenu(true);
788 if (windowMenu!= nullptr)
789 file_menu->addMenu(windowMenu.get());
790 }
791
792