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 #include "StorageActions.h"
23 #include "src/ui/pindialog.h"
24 #include "src/utils/bool_values.h"
25 #include <libnitrokey/NitrokeyManager.h>
26
27 #ifdef Q_OS_LINUX
28 #include "systemutils.h"
29 #include <sys/mount.h> // for unmounting on linux
30 #endif // Q_OS_LINUX
31
32 #if defined(Q_OS_LINUX) || defined(Q_OS_MAC)
33 #include <unistd.h> //for sync syscall
34 #endif // Q_OS_LINUX || Q_OS_MAC
35 #include <OwnSleep.h>
36 #include <src/ui/stick20lockfirmwaredialog.h>
37 #include <src/ui/stick20hiddenvolumedialog.h>
38
39 #define LOCAL_PASSWORD_SIZE 40
40 #include <memory>
41 #include <src/core/ThreadWorker.h>
42 #include <libnitrokey/stick20_commands.h>
43
44
unmountEncryptedVolumes()45 void unmountEncryptedVolumes() {
46 return;
47 #if defined(Q_OS_LINUX)
48 std::string endev = systemutils::getEncryptedDevice();
49 if (endev.size() < 1)
50 return;
51 std::string mntdir = systemutils::getMntPoint(endev);
52 qDebug() << "Unmounting " << mntdir.c_str();
53 // TODO polling with MNT_EXPIRE? test which will suit better
54 // int err = umount2("/dev/nitrospace", MNT_DETACH);
55 int err = umount(mntdir.c_str());
56 if (err != 0) {
57 qDebug() << "Unmount error: " << strerror(errno);
58 }
59 #endif // Q_OS_LINUX
60 }
61
local_sync()62 void local_sync() {
63 // TODO TEST unmount during/after big data transfer
64 fflush(NULL); // for windows, not necessarly needed or working
65 #if defined(Q_OS_LINUX) || defined(Q_OS_MAC)
66 sync();
67 #endif // Q_OS_LINUX || Q_OS_MAC
68 // manual says sync blocks until it's done, but they
69 // are not guaranteeing will this save data integrity anyway,
70 // additional sleep might help
71 OwnSleep::sleep(1);
72 // unmount does sync on its own additionally (if successful)
73 unmountEncryptedVolumes();
74 }
75
76
startStick20EnableCryptedVolume()77 void StorageActions::startStick20EnableCryptedVolume() {
78 bool answer;
79
80 if (TRUE == HiddenVolumeActive) {
81 answer = csApplet()->yesOrNoBox(tr("This activity locks your hidden volume. Do you want to "
82 "proceed?\nTo avoid data loss, please unmount the partitions before "
83 "proceeding."), false);
84 if (!answer)
85 return;
86 }
87
88 PinDialog dialog(PinType::USER_PIN, nullptr);
89
90 const auto user_wants_to_proceed = QDialog::Accepted == dialog.exec();
91 if (user_wants_to_proceed) {
92 startProgressFunc(tr("Enabling encrypted volume")); //FIXME use existing translation
93 const auto s = dialog.getPassword();
94
95 new ThreadWorker(
96 [s]() -> Data { // FIXME make s shared_ptr to delete after use //or secure string
97 Data data;
98 data["error"] = 0;
99
100 auto m = nitrokey::NitrokeyManager::instance();
101 auto l = libada::i();
102 try{
103 local_sync();
104 bool enable_storage_v045_workaround = l->getMinorFirmwareVersion() <= 45;
105 m->unlock_encrypted_volume(s.c_str());
106 if (enable_storage_v045_workaround)
107 OwnSleep::sleep(5); //workaround for https://github.com/Nitrokey/nitrokey-storage-firmware/issues/31
108
109 data["success"] = true;
110 }
111 catch (CommandFailedException &e){
112 data["error"] = e.last_command_status;
113 if (e.reason_wrong_password()){
114 data["wrong_password"] = true;
115 }
116 }
117 catch (DeviceCommunicationException &e){
118 data["error"] = -1;
119 data["comm_error"] = true;
120 }
121
122 return data;
123 },
124 [this](Data data){
125 if(data["success"].toBool()){
126 CryptedVolumeActive = true;
127 emit storageStatusChanged();
128 show_message_function(tr("Encrypted volume enabled"));
129 } else if (data["wrong_password"].toBool()){
130 csApplet()->warningBox(tr("Could not enable encrypted volume.") + " " //FIXME use existing translation
131 + tr("Wrong password."));
132
133 } else {
134 csApplet()->warningBox(tr("Could not enable encrypted volume.") + " "
135 + tr("Status code: %1").arg(data["error"].toInt())); //FIXME use existing translation
136 }
137 end_progress_function();
138 }, this);
139
140 }
141 }
142
startStick20DisableCryptedVolume()143 void StorageActions::startStick20DisableCryptedVolume() {
144 if (TRUE == CryptedVolumeActive) {
145 const bool user_wants_to_proceed = csApplet()->yesOrNoBox(tr("This activity locks your encrypted volume. Do you want to "
146 "proceed?\nTo avoid data loss, please unmount the partitions before "
147 "proceeding."), false);
148 if (!user_wants_to_proceed)
149 return;
150
151 startProgressFunc(tr("Disabling encrypted volume")); //FIXME use existing translation
152
153 new ThreadWorker(
154 []() -> Data {
155 Data data;
156
157 try{
158 local_sync();
159 auto m = nitrokey::NitrokeyManager::instance();
160 m->lock_encrypted_volume();
161 data["success"] = true;
162 }
163 catch (CommandFailedException &e){
164 data["error"] = e.last_command_status;
165 }
166 catch (DeviceCommunicationException &e){
167 data["error"] = -1;
168 data["comm_error"] = true;
169 }
170
171 return data;
172 },
173 [this](Data data){
174 if(data["success"].toBool()) {
175 CryptedVolumeActive = false;
176 emit storageStatusChanged();
177 show_message_function(tr("Encrypted volume disabled"));
178 // for v0.50 and below ask for reinsertion to complete the lock procedure
179 if (libada::i()->getMinorFirmwareVersion() <= 50){
180 csApplet()->messageBox(
181 tr("To complete the lock procedure, please remove and reconnect the Nitrokey."));
182 }
183 } else {
184 csApplet()->warningBox(tr("Could not lock encrypted volume.") + " "
185 + tr("Status code: %1").arg(data["error"].toInt())); //FIXME use existing translation
186 }
187 end_progress_function();
188 }, this);
189 }
190 }
191
startStick20EnableHiddenVolume()192 void StorageActions::startStick20EnableHiddenVolume() {
193 if (!CryptedVolumeActive) {
194 csApplet()->warningBox(tr("Please enable the encrypted volume first."));
195 return;
196 }
197
198 const bool user_wants_to_proceed =
199 csApplet()->yesOrNoBox(tr("This activity locks your encrypted volume. Do you want to "
200 "proceed?\nTo avoid data loss, please unmount the partitions before "
201 "proceeding."), true);
202 if (!user_wants_to_proceed)
203 return;
204
205 PinDialog dialog(PinType::HIDDEN_VOLUME, nullptr);
206 const auto user_gives_password = dialog.exec() == QDialog::Accepted ;
207
208 if (!user_gives_password) {
209 return;
210 }
211
212 startProgressFunc(tr("Enabling hidden volume")); //FIXME use existing translation
213
214 auto s = dialog.getPassword();
215
216 new ThreadWorker(
217 [s]() -> Data { //FIXME transport throuugh shared_ptr or secure string
218 Data data;
219
220 auto m = nitrokey::NitrokeyManager::instance();
221 auto l = libada::i();
222 try {
223 local_sync();
224 bool enable_storage_v045_workaround = l->getMinorFirmwareVersion() <= 45;
225 m->unlock_hidden_volume(s.c_str());
226
227 if (enable_storage_v045_workaround)
228 OwnSleep::sleep(5); //workaround for https://github.com/Nitrokey/nitrokey-storage-firmware/issues/31
229
230 data["success"] = true;
231 }
232 catch (CommandFailedException &e){
233 data["error"] = e.last_command_status;
234 if (e.reason_wrong_password()){
235 data["wrong_password"] = true;
236 }
237 }
238 catch (DeviceCommunicationException &e){
239 data["error"] = -1;
240 data["comm_error"] = true;
241 }
242
243 return data;
244 },
245 [this](Data data){
246
247 if(data["success"].toBool()){
248 HiddenVolumeActive = true;
249 emit storageStatusChanged();
250 show_message_function(tr("Hidden volume enabled"));//FIXME use existing translation
251 } else if (data["wrong_password"].toBool()){
252 csApplet()->warningBox(tr("Could not enable hidden volume.") + " " //FIXME use existing translation
253 + tr("Wrong password."));
254
255 } else {
256 csApplet()->warningBox(tr("Could not enable hidden volume.") + " "
257 + tr("Status code: %1").arg(data["error"].toInt())); //FIXME use existing translation
258 }
259 end_progress_function();
260 }, this);
261
262 }
263
startStick20DisableHiddenVolume()264 void StorageActions::startStick20DisableHiddenVolume() {
265 const bool user_wants_to_proceed =
266 csApplet()->yesOrNoBox(tr("This activity locks your hidden volume. Do you want to proceed?\nTo "
267 "avoid data loss, please unmount the partitions before proceeding."), true);
268 if (!user_wants_to_proceed)
269 return;
270
271 startProgressFunc(tr("Disabling hidden volume")); //FIXME use existing translation
272
273
274 new ThreadWorker(
275 []() -> Data {
276 Data data;
277
278 try{
279 local_sync();
280 auto m = nitrokey::NitrokeyManager::instance();
281 m->lock_hidden_volume();
282 data["success"] = true;
283 }
284 catch (CommandFailedException &e){
285 data["error"] = e.last_command_status;
286 }
287 catch (DeviceCommunicationException &e){
288 data["error"] = -1;
289 data["comm_error"] = true;
290 }
291
292 return data;
293 },
294 [this](Data data){
295 if(data["success"].toBool()) {
296 HiddenVolumeActive = false;
297 emit storageStatusChanged();
298 show_message_function(tr("Hidden volume disabled")); //FIXME use existing translation
299 }
300 else {
301 csApplet()->warningBox(tr("Could not lock hidden volume.") + " "
302 + tr("Status code: %1").arg(data["error"].toInt())); //FIXME use existing translation
303 }
304 end_progress_function();
305 }, this);
306
307 }
308
startLockDeviceAction(bool ask_for_confirmation)309 void StorageActions::startLockDeviceAction(bool ask_for_confirmation) {
310 bool user_wants_to_proceed;
311
312 if ((ask_for_confirmation) && ((TRUE == CryptedVolumeActive) || (TRUE == HiddenVolumeActive))) {
313 user_wants_to_proceed = csApplet()->yesOrNoBox(tr("This activity locks your encrypted volume. Do you want to "
314 "proceed?\nTo avoid data loss, please unmount the partitions before "
315 "proceeding."), true);
316 if (!user_wants_to_proceed) {
317 return;
318 }
319 }
320
321 startProgressFunc(tr("Locking device")); //FIXME use existing translation
322
323
324 new ThreadWorker(
325 []() -> Data {
326 Data data;
327 try {
328 local_sync();
329 auto m = nitrokey::NitrokeyManager::instance();
330 m->lock_device();
331 data["success"] = true;
332 }
333 catch (CommandFailedException &e){
334 data["error"] = e.last_command_status;
335 }
336 catch (DeviceCommunicationException &e){
337 data["error"] = -1;
338 data["comm_error"] = true;
339 }
340 return data;
341 },
342 [this](Data data){
343 if(data["success"].toBool()) {
344 HiddenVolumeActive = false;
345 CryptedVolumeActive = false;
346 emit storageStatusChanged();
347 show_message_function(tr("Device locked")); //FIXME use existing translation
348 // for v0.50 and below ask for reinsertion to complete the lock procedure
349 if (libada::i()->getMinorFirmwareVersion() <= 50){
350 csApplet()->messageBox(
351 tr("To complete the lock procedure, please remove and reconnect the Nitrokey."));
352 }
353 }
354 else {
355 csApplet()->warningBox(tr("Could not lock device.") + " "
356 + tr("Status code: %1").arg(data["error"].toInt())); //FIXME use existing translation
357 }
358
359 end_progress_function();
360 }, this);
361
362 }
363
364 #include "stick20updatedialog.h"
365
startStick20EnableFirmwareUpdate()366 void StorageActions::startStick20EnableFirmwareUpdate() {
367 UpdateDialog dialogUpdate(nullptr);
368
369 bool user_wants_to_proceed = dialogUpdate.exec() == QDialog::Accepted;
370 if (!user_wants_to_proceed) {
371 return;
372 }
373
374 auto successMessage = tr("Device set in update mode");
375 auto failureMessage = tr("Device could not be set in update mode.");
376
377 bool success = false;
378 // try with default password
379 // ask for password when fails
380 runAndHandleErrorsInUI(successMessage, "",
381 [&success](){ //FIXME use secure string
382 local_sync();
383 auto m = nitrokey::NitrokeyManager::instance();
384 m->enable_firmware_update("12345678");
385 success = true;
386 },[](){});
387
388 if(success) return;
389
390 PinDialog dialog(PinType::FIRMWARE_PIN);
391 user_wants_to_proceed = QDialog::Accepted == dialog.exec();
392
393 if (!user_wants_to_proceed) {
394 return;
395 }
396 auto s = dialog.getPassword();
397
398 runAndHandleErrorsInUI(successMessage, failureMessage,
399 [s](){ //FIXME use secure string
400 local_sync();
401 auto m = nitrokey::NitrokeyManager::instance();
402 m->enable_firmware_update(s.c_str());
403 },[](){});
404 }
405
406
startStick20ExportFirmwareToFile()407 void StorageActions::startStick20ExportFirmwareToFile() {
408 PinDialog dialog(PinType::ADMIN_PIN);
409 bool user_provided_PIN = QDialog::Accepted == dialog.exec();
410 if (!user_provided_PIN) {
411 return;
412 }
413 auto s = dialog.getPassword(); //FIXME use secure string
414
415 //FIXME use existing translation
416 runAndHandleErrorsInUI(tr("Firmware exported"), tr("Could not export firmware."), [s](){
417 auto m = nitrokey::NitrokeyManager::instance();
418 m->export_firmware(s.c_str());
419 }, [](){});
420 }
421
startStick20DestroyCryptedVolume(int fillSDWithRandomChars)422 void StorageActions::startStick20DestroyCryptedVolume(int fillSDWithRandomChars) {
423 bool user_entered_PIN;
424 bool answer;
425
426 answer = (fillSDWithRandomChars == 1) || csApplet()->yesOrNoBox(tr("WARNING: Generating new AES keys will destroy the encrypted volumes, "
427 "hidden volumes, and password safe! Continue?"), false);
428 if (answer) {
429 PinDialog dialog(PinType::ADMIN_PIN);
430 user_entered_PIN = QDialog::Accepted == dialog.exec();
431 if (!user_entered_PIN) {
432 return;
433 }
434 auto s = dialog.getPassword();
435
436 startProgressFunc(tr("Generating new AES keys")); //FIXME use existing translation
437
438 new ThreadWorker(
439 [s]() -> Data { //FIXME use secure string
440 Data data;
441 try{
442 auto m = nitrokey::NitrokeyManager::instance();
443 m->lock_device(); //lock device to reset its state
444 m->build_aes_key(s.c_str());
445 data["success"] = true;
446 }
447 catch (CommandFailedException &e){
448 data["error"] = e.last_command_status;
449 if (e.reason_wrong_password()){
450 data["wrong_password"] = true;
451 }
452 }
453 catch (DeviceCommunicationException &e){
454 data["error"] = -1;
455 data["comm_error"] = true;
456 }
457 return data;
458 },
459 [this, fillSDWithRandomChars, s](Data data){ // FIXME use secure string
460 if(data["success"].toBool()) {
461 emit FactoryReset();
462 show_message_function(tr("New AES keys generated")); //FIXME use existing translation
463 if (fillSDWithRandomChars != 0) {
464 _execute_SD_clearing(s);
465 }
466 } else if (data["wrong_password"].toBool()){
467 csApplet()->warningBox(tr("Keys could not be generated.") + " " //FIXME use existing translation
468 + tr("Wrong password."));
469
470 } else {
471 csApplet()->warningBox(tr("Keys could not be generated.") + " "
472 + tr("Status code: %1").arg(data["error"].toInt())); //FIXME use existing translation
473 }
474 end_progress_function();
475 }, this);
476 }
477 }
478
_execute_SD_clearing(const std::string & s)479 void StorageActions::_execute_SD_clearing(const std::string &s) {
480 //does not need long operation indicator
481 new ThreadWorker(
482 [s]() -> Data { //FIXME use secure string
483 Data data;
484 data["success"] = false;
485 try{
486 auto m = nitrokey::NitrokeyManager::instance();
487 m->fill_SD_card_with_random_data(s.c_str());
488 }
489 catch (LongOperationInProgressException &l){
490 //expected
491 data["success"] = true;
492 }
493 catch (CommandFailedException &e){
494 data["error"] = e.last_command_status;
495 if (e.reason_wrong_password()){
496 data["wrong_password"] = true;
497 }
498 }
499 catch (DeviceCommunicationException &e){
500 data["error"] = -1;
501 data["comm_error"] = true;
502 }
503
504 return data;
505 },
506 [this](Data data){
507 if(data["success"].toBool()) {
508 QTimer::singleShot(1000, [this](){
509 emit storageStatusUpdated();
510 emit longOperationStarted();
511 emit storageStatusChanged();
512 });
513 } else if (data["wrong_password"].toBool()){
514 csApplet()->warningBox(tr("Could not clear SD card.") + " " //FIXME use existing translation
515 + tr("Wrong password."));
516
517 } else {
518 csApplet()->warningBox(tr("Could not clear SD card.") + " "
519 + tr("Status code: %1").arg(data["error"].toInt())); //FIXME use existing translation
520 }
521 }, this);
522 }
523
startStick20FillSDCardWithRandomChars()524 void StorageActions::startStick20FillSDCardWithRandomChars() {
525 PinDialog dialog(PinType::ADMIN_PIN);
526 bool user_provided_PIN = QDialog::Accepted == dialog.exec();
527 if (user_provided_PIN) {
528 auto s = dialog.getPassword();
529 _execute_SD_clearing(s);
530 }
531 }
532
runAndHandleErrorsInUI(QString successMessage,QString operationFailureMessage,std::function<void (void)> codeToRunInDeviceThread,std::function<void (void)> onSuccessInGuiThread)533 void StorageActions::runAndHandleErrorsInUI(QString successMessage, QString operationFailureMessage,
534 std::function<void(void)> codeToRunInDeviceThread,
535 std::function<void(void)> onSuccessInGuiThread) {
536 // startProgressFunc(successMessage); //TODO enable after moving blocking code to separate thread
537 try{
538 //TODO run in separate thread
539 codeToRunInDeviceThread();
540 onSuccessInGuiThread();
541 show_message_function(successMessage);
542 }
543 catch (CommandFailedException &e){
544 if (!operationFailureMessage.isEmpty()){
545 if (e.reason_wrong_password()){
546 csApplet()->warningBox(operationFailureMessage + " "
547 + tr("Wrong password."));
548 } else {
549 csApplet()->warningBox(operationFailureMessage + " "
550 + tr("Status code: %1").arg(e.last_command_status));
551 }
552 }
553 }
554 catch (DeviceCommunicationException &e){
555 if (!operationFailureMessage.isEmpty()){
556 csApplet()->warningBox(operationFailureMessage + " " +
557 tr("Communication issue."));
558 }
559 }
560 // end_progress_function();
561 }
562
563
startStick20ClearNewSdCardFound()564 void StorageActions::startStick20ClearNewSdCardFound() {
565 PinDialog dialog(PinType::ADMIN_PIN);
566
567 bool user_provided_pin = QDialog::Accepted == dialog.exec();
568 if (!user_provided_pin) {
569 return;
570 }
571
572 auto s = dialog.getPassword();
573 auto operationFailureMessage = tr("Flag cannot be cleared."); //FIXME use existing translation
574 auto operationSuccessMessage = tr("Flag cleared.");
575
576 runAndHandleErrorsInUI(QString(), operationFailureMessage, [s]() { //FIXME use secure string
577 auto m = nitrokey::NitrokeyManager::instance();
578 m->clear_new_sd_card_warning(s.c_str());
579 }, [this]() {
580 emit storageStatusUpdated();
581 });
582 }
583
584
startStick20SetReadOnlyUncryptedVolume()585 void StorageActions::startStick20SetReadOnlyUncryptedVolume() {
586 using nm = nitrokey::NitrokeyManager;
587 auto type = PinType::ADMIN_PIN;
588 if(nm::instance()->set_unencrypted_volume_rorw_pin_type_user()){
589 type = PinType::USER_PIN;
590 }
591 PinDialog dialog(type);
592
593 bool user_provided_pin = QDialog::Accepted == dialog.exec();
594 if (!user_provided_pin) {
595 return;
596 }
597
598 auto operationFailureMessage = tr("Cannot set unencrypted volume read-only"); //FIXME use existing translation
599 auto operationSuccessMessage = tr("Unencrypted volume set read-only"); //FIXME use existing translation
600 auto s = dialog.getPassword();
601
602 runAndHandleErrorsInUI(operationSuccessMessage, operationFailureMessage, [s, type]() {
603 auto m = nitrokey::NitrokeyManager::instance();
604 //FIXME use secure string
605 switch(type){
606 case USER_PIN:
607 m->set_unencrypted_read_only(s.c_str());
608 break;
609 case ADMIN_PIN:
610 m->set_unencrypted_read_only_admin(s.c_str());
611 break;
612 default:
613 break;
614 }
615 }, [this]() {
616 emit storageStatusChanged();
617 });
618
619 }
620
startStick20SetReadWriteUncryptedVolume()621 void StorageActions::startStick20SetReadWriteUncryptedVolume() {
622 using nm = nitrokey::NitrokeyManager;
623 auto type = PinType::ADMIN_PIN;
624 if(nm::instance()->set_unencrypted_volume_rorw_pin_type_user()){
625 type = PinType::USER_PIN;
626 }
627 PinDialog dialog(type);
628
629 bool user_provided_pin = QDialog::Accepted == dialog.exec();
630 if (!user_provided_pin) {
631 return;
632 }
633
634 auto operationFailureMessage = tr("Cannot set unencrypted volume read-write"); //FIXME use existing translation
635 auto operationSuccessMessage = tr("Unencrypted volume set read-write"); //FIXME use existing translation
636 auto s = dialog.getPassword();
637
638 runAndHandleErrorsInUI(operationSuccessMessage, operationFailureMessage, [s, type]() {
639 auto m = nitrokey::NitrokeyManager::instance();
640 //FIXME use secure string
641 switch(type){
642 case USER_PIN:
643 m->set_unencrypted_read_write(s.c_str());
644 break;
645 case ADMIN_PIN:
646 m->set_unencrypted_read_write_admin(s.c_str());
647 break;
648 default:
649 break;
650 }
651 }, [this]() {
652 emit storageStatusChanged();
653 });
654
655 }
656
startStick20SetReadOnlyEncryptedVolume()657 void StorageActions::startStick20SetReadOnlyEncryptedVolume() {
658 PinDialog dialog(PinType::ADMIN_PIN);
659
660 bool user_provided_pin = QDialog::Accepted == dialog.exec();
661 if (!user_provided_pin) {
662 return;
663 }
664
665 auto operationFailureMessage = tr("Cannot set encrypted volume read-only"); //FIXME use existing translation
666 auto operationSuccessMessage = tr("Encrypted volume set read-only"); //FIXME use existing translation
667 auto s = dialog.getPassword();
668
669 runAndHandleErrorsInUI(operationSuccessMessage, operationFailureMessage, [s]() {
670 auto m = nitrokey::NitrokeyManager::instance();
671 m->set_encrypted_volume_read_only(s.c_str()); //FIXME use secure string
672 }, [this]() {
673 emit storageStatusChanged();
674 });
675
676 }
677
startStick20SetReadWriteEncryptedVolume()678 void StorageActions::startStick20SetReadWriteEncryptedVolume() {
679 PinDialog dialog(PinType::ADMIN_PIN);
680
681 bool user_provided_pin = QDialog::Accepted == dialog.exec();
682 if (!user_provided_pin) {
683 return;
684 }
685
686 auto operationFailureMessage = tr("Cannot set encrypted volume read-write"); //FIXME use existing translation
687 auto operationSuccessMessage = tr("Encrypted volume set read-write"); //FIXME use existing translation
688 auto s = dialog.getPassword();
689
690 runAndHandleErrorsInUI(operationSuccessMessage, operationFailureMessage, [s]() {
691 auto m = nitrokey::NitrokeyManager::instance();
692 m->set_encrypted_volume_read_write(s.c_str()); //FIXME use secure string
693 }, [this]() {
694 emit storageStatusChanged();
695 });
696
697 }
698
startStick20LockStickHardware()699 void StorageActions::startStick20LockStickHardware() {
700 csApplet()->messageBox(tr("Functionality not implemented in current version")); //FIXME use existing translation
701 return;
702
703 stick20LockFirmwareDialog firmwareDialog(nullptr);
704 bool user_wants_to_proceed = QDialog::Accepted == firmwareDialog.exec();
705 if (user_wants_to_proceed) {
706 PinDialog pinDialog(PinType::ADMIN_PIN);
707
708 bool user_provided_PIN = pinDialog.exec() == QDialog::Accepted;
709 if (!user_provided_PIN) {
710 return;
711 }
712 const auto pass = pinDialog.getPassword();
713 // TODO stick20SendCommand(STICK20_CMD_SEND_LOCK_STICK_HARDWARE, password);
714 }
715 }
716
startStick20SetupHiddenVolume()717 void StorageActions::startStick20SetupHiddenVolume() {
718 stick20HiddenVolumeDialog HVDialog(nullptr);
719
720 if (FALSE == CryptedVolumeActive) {
721 csApplet()->warningBox(tr("Please enable the encrypted volume first."));
722 return;
723 }
724
725 auto operationSuccessMessage = tr("Hidden volume created");
726 auto operationFailureMessage = tr("Hidden volume could not be created."); //FIXME use existing translation
727
728 bool user_wants_to_proceed = HVDialog.exec() == QDialog::Accepted;
729 if (!user_wants_to_proceed) {
730 return;
731 }
732 const auto d = HVDialog.HV_Setup_st; //FIXME clear securely struct
733 auto p = std::string( reinterpret_cast< char const* >(d.HiddenVolumePassword_au8));
734
735 runAndHandleErrorsInUI(operationSuccessMessage, operationFailureMessage, [d, p](){ //FIXME use secure string
736 auto m = nitrokey::NitrokeyManager::instance();
737 m->create_hidden_volume(d.SlotNr_u8, d.StartBlockPercent_u8,
738 d.EndBlockPercent_u8, p.c_str());
739 }, [](){});
740
741 }
742
StorageActions(QObject * parent,Authentication * auth_admin,Authentication * auth_user)743 StorageActions::StorageActions(QObject *parent, Authentication *auth_admin, Authentication *auth_user) : QObject(
744 parent), auth_admin(auth_admin), auth_user(auth_user) {
745 connect(this, SIGNAL(storageStatusChanged()), this, SLOT(on_StorageStatusChanged()));
746 }
747
748 #include <QDebug>
749
750
on_StorageStatusChanged()751 void StorageActions::on_StorageStatusChanged() {
752 if (!libada::i()->isStorageDeviceConnected())
753 return;
754
755 new ThreadWorker(
756 []() -> Data {
757 bool interrupt = QThread::currentThread()->isInterruptionRequested();
758 static bool first_run = true;
759 int times = first_run? 5 : 3;
760 first_run = false;
761
762 for (int i = 0; i < times && !interrupt; ++i) {
763 QThread::currentThread()->msleep(500);
764 interrupt = QThread::currentThread()->isInterruptionRequested();
765 }
766 Data data;
767 if(interrupt) {
768 return data;
769 }
770
771 auto m = nitrokey::NitrokeyManager::instance();
772 auto s = m->get_status_storage();
773 data["encrypted_active"] = s.VolumeActiceFlag_st.encrypted;
774 data["hidden_active"] = s.VolumeActiceFlag_st.hidden;
775 return data;
776 },
777 [this](Data data){
778 CryptedVolumeActive = data["encrypted_active"].toBool();
779 HiddenVolumeActive = data["hidden_active"].toBool();
780 emit storageStatusUpdated();
781 }, this, "update storage status");
782 }
783
set_start_progress_window(std::function<void (QString)> _start_progress_function)784 void StorageActions::set_start_progress_window(std::function<void(QString)> _start_progress_function) {
785 startProgressFunc = _start_progress_function;
786 }
787
set_end_progress_window(std::function<void ()> _end_progress_function)788 void StorageActions::set_end_progress_window(std::function<void()> _end_progress_function) {
789 end_progress_function = _end_progress_function;
790 }
791
set_show_message(std::function<void (QString)> _show_message)792 void StorageActions::set_show_message(std::function<void(QString)> _show_message) {
793 show_message_function = _show_message;
794 }
795