Repository: freedomofpress/securedrop

Issue:
[qt-journalist-updater] Update UI properly if Tails Administrator password is not provided
# Feature request

## Description

If the user does not provide the `Tails Administrator` password, the tool should show that in the UI and does not close the application.



Discussion:

Resolving patch:
diff --git a/journalist_gui/journalist_gui/SecureDropUpdater.py b/journalist_gui/journalist_gui/SecureDropUpdater.py
--- a/journalist_gui/journalist_gui/SecureDropUpdater.py
+++ b/journalist_gui/journalist_gui/SecureDropUpdater.py
@@ -1,7 +1,6 @@
 #!/usr/bin/python
 from PyQt5 import QtGui, QtWidgets
 from PyQt5.QtCore import QThread, pyqtSignal
-import sys
 import subprocess
 import os
 import pexpect
@@ -212,16 +211,17 @@ def call_tailsconfig(self):
         if self.update_success:
             # Get sudo password and add an enter key as tailsconfig command
             # expects
-            sudo_password = self.get_sudo_password() + '\n'
-            self.tails_thread.sudo_password = sudo_password
+            sudo_password = self.get_sudo_password()
+            if not sudo_password:
+                self.update_success = False
+                self.failure_reason = strings.missing_sudo_password
+                self.on_failure()
+                return
+            self.tails_thread.sudo_password = sudo_password + '\n'
             self.update_status_bar_and_output(strings.updating_tails_env)
             self.tails_thread.start()
         else:
-            self.pushButton.setEnabled(True)
-            self.pushButton_2.setEnabled(True)
-            self.update_status_bar_and_output(self.failure_reason)
-            self.progressBar.setProperty("value", 0)
-            self.alert_failure(self.failure_reason)
+            self.on_failure()
 
     def tails_status(self, result):
         "This is the slot for Tailsconfig thread"
@@ -237,12 +237,15 @@ def tails_status(self, result):
             self.progressBar.setProperty("value", 100)
             self.alert_success()
         else:
-            self.update_status_bar_and_output(self.failure_reason)
-            self.alert_failure(self.failure_reason)
-            # Now everything is done, enable the button.
-            self.pushButton.setEnabled(True)
-            self.pushButton_2.setEnabled(True)
-            self.progressBar.setProperty("value", 0)
+            self.on_failure()
+
+    def on_failure(self):
+        self.update_status_bar_and_output(self.failure_reason)
+        self.alert_failure(self.failure_reason)
+        # Now everything is done, enable the button.
+        self.pushButton.setEnabled(True)
+        self.pushButton_2.setEnabled(True)
+        self.progressBar.setProperty("value", 0)
 
     def update_securedrop(self):
         self.pushButton_2.setEnabled(False)
@@ -272,4 +275,4 @@ def get_sudo_password(self):
         if ok_is_pressed and sudo_password:
             return sudo_password
         else:
-            sys.exit(0)
+            return None
diff --git a/journalist_gui/journalist_gui/strings.py b/journalist_gui/journalist_gui/strings.py
--- a/journalist_gui/journalist_gui/strings.py
+++ b/journalist_gui/journalist_gui/strings.py
@@ -16,6 +16,7 @@
 finished = 'Update successfully completed!'
 finished_dialog_message = 'Updates completed successfully. '
 finished_dialog_title = 'SecureDrop Workstation is up to date!'
+missing_sudo_password = 'Missing Tails Administrator password'
 update_failed_dialog_title = 'Error Updating SecureDrop Workstation'
 update_failed_generic_reason = ("Update failed. "
                                 "Please contact your SecureDrop "


Test patch:
diff --git a/journalist_gui/test_gui.py b/journalist_gui/test_gui.py
--- a/journalist_gui/test_gui.py
+++ b/journalist_gui/test_gui.py
@@ -123,10 +123,7 @@ def test_get_sudo_password_when_password_not_provided(self):
 
         with mock.patch.object(QInputDialog, 'getText',
                                return_value=[test_password, False]):
-            # If the user does not provide a sudo password, we exit
-            # as we cannot update.
-            with self.assertRaises(SystemExit):
-                self.window.get_sudo_password()
+            self.assertIsNone(self.window.get_sudo_password())
 
     @mock.patch('pexpect.spawn')
     def test_tailsconfigThread_no_failures(self, pt):