We are currently solving the following issue within our repository. Here is the issue text:
--- BEGIN ISSUE ---
[RFE] Remove the sizegrip from the statusbar of the GUI tool
# Feature request

## Description

There should not be any sizegrip available in the statusbar of the GUI tool as suggested in https://github.com/freedomofpress/securedrop/pull/3300#discussion_r184066922

--- END ISSUE ---

Below are some code segments, each from a relevant file. One or more of these files may contain bugs.
--- BEGIN FILES ---
Path: `journalist_gui/journalist_gui/SecureDropUpdater.py`
Content:
```
1 #!/usr/bin/python
2 from PyQt5 import QtGui, QtWidgets
3 from PyQt5.QtCore import QThread, pyqtSignal
4 import subprocess
5 import os
6 import pexpect
7 
8 from journalist_gui import updaterUI, strings, resources_rc  # noqa
9 
10 
11 LOCK_LOCATION = "/home/amnesia/Persistent/securedrop/securedrop_update.lock"  # noqa
12 
13 
14 class SetupThread(QThread):
15     signal = pyqtSignal('PyQt_PyObject')
16 
17     def __init__(self):
18         QThread.__init__(self)
19         self.output = ""
20         self.update_success = False
21         self.failure_reason = ""
22 
23     def run(self):
24         sdadmin_path = '/home/amnesia/Persistent/securedrop/securedrop-admin'
25         update_command = [sdadmin_path, 'setup']
26 
27         # Create lock so we resume failed updates on reboot.
28         # Don't create the lock if it already exists.
29         if not os.path.exists(LOCK_LOCATION):
30             open(LOCK_LOCATION, 'a').close()
31 
32         try:
33             self.output = subprocess.check_output(
34                 update_command,
35                 stderr=subprocess.STDOUT).decode('utf-8')
36             if 'Failed to install' in self.output:
37                 self.update_success = False
38                 self.failure_reason = strings.update_failed_generic_reason
39             else:
40                 self.update_success = True
41         except subprocess.CalledProcessError as e:
42             self.output += e.output.decode('utf-8')
43             self.update_success = False
44             self.failure_reason = strings.update_failed_generic_reason
45         result = {'status': self.update_success,
46                   'output': self.output,
47                   'failure_reason': self.failure_reason}
48         self.signal.emit(result)
49 
50 
51 # This thread will handle the ./securedrop-admin update command
52 class UpdateThread(QThread):
53     signal = pyqtSignal('PyQt_PyObject')
54 
55     def __init__(self):
56         QThread.__init__(self)
57         self.output = ""
58         self.update_success = False
59         self.failure_reason = ""
60 
61     def run(self):
62         sdadmin_path = '/home/amnesia/Persistent/securedrop/securedrop-admin'
63         update_command = [sdadmin_path, 'update']
64         try:
65             self.output = subprocess.check_output(
66                 update_command,
67                 stderr=subprocess.STDOUT).decode('utf-8')
68             if "Signature verification successful" in self.output:
69                 self.update_success = True
70             else:
71                 self.failure_reason = strings.update_failed_generic_reason
72         except subprocess.CalledProcessError as e:
73             self.update_success = False
74             self.output += e.output.decode('utf-8')
75             if 'Signature verification failed' in self.output:
76                 self.failure_reason = strings.update_failed_sig_failure
77             else:
78                 self.failure_reason = strings.update_failed_generic_reason
79         result = {'status': self.update_success,
80                   'output': self.output,
81                   'failure_reason': self.failure_reason}
82         self.signal.emit(result)
83 
84 
85 # This thread will handle the ./securedrop-admin tailsconfig command
86 class TailsconfigThread(QThread):
87     signal = pyqtSignal('PyQt_PyObject')
88 
89     def __init__(self):
90         QThread.__init__(self)
91         self.output = ""
92         self.update_success = False
93         self.failure_reason = ""
94         self.sudo_password = ""
95 
96     def run(self):
97         tailsconfig_command = ("/home/amnesia/Persistent/"
98                                "securedrop/securedrop-admin "
99                                "tailsconfig")
100         try:
101             child = pexpect.spawn(tailsconfig_command)
102             child.expect('SUDO password:')
103             self.output += child.before.decode('utf-8')
104             child.sendline(self.sudo_password)
105             child.expect(pexpect.EOF)
106             self.output += child.before.decode('utf-8')
107 
108             # For Tailsconfig to be considered a success, we expect no
109             # failures in the Ansible output.
110             if 'failed=0' not in self.output:
111                 self.update_success = False
112                 self.failure_reason = strings.tailsconfig_failed_generic_reason  # noqa
113             else:
114                 self.update_success = True
115         except pexpect.exceptions.TIMEOUT:
116             self.update_success = False
117             self.failure_reason = strings.tailsconfig_failed_sudo_password
118 
119         except subprocess.CalledProcessError:
120             self.update_success = False
121             self.failure_reason = strings.tailsconfig_failed_generic_reason
122         result = {'status': self.update_success,
123                   'output': self.output,
124                   'failure_reason': self.failure_reason}
125         self.signal.emit(result)
126 
127 
128 class UpdaterApp(QtWidgets.QMainWindow, updaterUI.Ui_MainWindow):
129 
130     def __init__(self, parent=None):
131         super(UpdaterApp, self).__init__(parent)
132         self.setupUi(self)
133         self.output = strings.initial_text_box
134         self.plainTextEdit.setPlainText(self.output)
135         self.update_success = False
136 
137         pixmap = QtGui.QPixmap(":/images/static/banner.png")
138         self.label_2.setPixmap(pixmap)
139         self.label_2.setScaledContents(True)
140 
141         self.progressBar.setProperty("value", 0)
142         self.setWindowTitle(strings.window_title)
143         self.setWindowIcon(QtGui.QIcon(':/images/static/securedrop_icon.png'))
144         self.label.setText(strings.update_in_progress)
145 
146         self.tabWidget.setTabText(self.tabWidget.indexOf(self.tab),
147                                   strings.main_tab)
148         self.tabWidget.setTabText(self.tabWidget.indexOf(self.tab_2),
149                                   strings.output_tab)
150 
151         # Connect buttons to their functions.
152         self.pushButton.setText(strings.install_later_button)
153         self.pushButton.setStyleSheet("""background-color: lightgrey;
154                                       min-height: 2em;
155                                       border-radius: 10px""")
156         self.pushButton.clicked.connect(self.close)
157         self.pushButton_2.setText(strings.install_update_button)
158         self.pushButton_2.setStyleSheet("""background-color: #E6FFEB;
159                                         min-height: 2em;
160                                         border-radius: 10px;""")
161         self.pushButton_2.clicked.connect(self.update_securedrop)
162         self.update_thread = UpdateThread()
163         self.update_thread.signal.connect(self.update_status)
164         self.tails_thread = TailsconfigThread()
165         self.tails_thread.signal.connect(self.tails_status)
166         self.setup_thread = SetupThread()
167         self.setup_thread.signal.connect(self.setup_status)
168 
169     # At the end of this function, we will try to do tailsconfig.
170     # A new slot will handle tailsconfig output
171     def setup_status(self, result):
172         "This is the slot for setup thread"
173         self.output += result['output']
174         self.update_success = result['status']
175         self.failure_reason = result['failure_reason']
176         self.progressBar.setProperty("value", 60)
177         self.plainTextEdit.setPlainText(self.output)
178         self.plainTextEdit.setReadOnly = True
179         if not self.update_success:  # Failed to do setup update
180             self.pushButton.setEnabled(True)
181             self.pushButton_2.setEnabled(True)
182             self.update_status_bar_and_output(self.failure_reason)
183             self.progressBar.setProperty("value", 0)
184             self.alert_failure(self.failure_reason)
185             return
186         self.progressBar.setProperty("value", 70)
187         self.call_tailsconfig()
188 
189     # This will update the output text after the git commands.
190     def update_status(self, result):
191         "This is the slot for update thread"
192         self.output += result['output']
193         self.update_success = result['status']
194         self.failure_reason = result['failure_reason']
195         self.progressBar.setProperty("value", 40)
196         self.plainTextEdit.setPlainText(self.output)
197         self.plainTextEdit.setReadOnly = True
198         self.progressBar.setProperty("value", 50)
199         self.update_status_bar_and_output(strings.doing_setup)
200         self.setup_thread.start()
201 
202     def update_status_bar_and_output(self, status_message):
203         """This method updates the status bar and the output window with the
204         status_message."""
205         self.statusbar.showMessage(status_message)
206         self.output += status_message + '\n'
207         self.plainTextEdit.setPlainText(self.output)
208 
209     def call_tailsconfig(self):
210         # Now let us work on tailsconfig part
211         if self.update_success:
212             # Get sudo password and add an enter key as tailsconfig command
213             # expects
214             sudo_password = self.get_sudo_password()
215             if not sudo_password:
216                 self.update_success = False
217                 self.failure_reason = strings.missing_sudo_password
218                 self.on_failure()
219                 return
220             self.tails_thread.sudo_password = sudo_password + '\n'
221             self.update_status_bar_and_output(strings.updating_tails_env)
222             self.tails_thread.start()
223         else:
224             self.on_failure()
225 
226     def tails_status(self, result):
227         "This is the slot for Tailsconfig thread"
228         self.output += result['output']
229         self.update_success = result['status']
230         self.failure_reason = result['failure_reason']
231         self.plainTextEdit.setPlainText(self.output)
232         self.progressBar.setProperty("value", 80)
233         if self.update_success:
234             # Remove lock
235             os.remove(LOCK_LOCATION)
236             self.update_status_bar_and_output(strings.finished)
237             self.progressBar.setProperty("value", 100)
238             self.alert_success()
239         else:
240             self.on_failure()
241 
242     def on_failure(self):
243         self.update_status_bar_and_output(self.failure_reason)
244         self.alert_failure(self.failure_reason)
245         # Now everything is done, enable the button.
246         self.pushButton.setEnabled(True)
247         self.pushButton_2.setEnabled(True)
248         self.progressBar.setProperty("value", 0)
249 
250     def update_securedrop(self):
251         self.pushButton_2.setEnabled(False)
252         self.pushButton.setEnabled(False)
253         self.progressBar.setProperty("value", 10)
254         self.update_status_bar_and_output(strings.fetching_update)
255         self.update_thread.start()
256 
257     def alert_success(self):
258         self.success_dialog = QtWidgets.QMessageBox()
259         self.success_dialog.setIcon(QtWidgets.QMessageBox.Information)
260         self.success_dialog.setText(strings.finished_dialog_message)
261         self.success_dialog.setWindowTitle(strings.finished_dialog_title)
262         self.success_dialog.show()
263 
264     def alert_failure(self, failure_reason):
265         self.error_dialog = QtWidgets.QMessageBox()
266         self.error_dialog.setIcon(QtWidgets.QMessageBox.Critical)
267         self.error_dialog.setText(self.failure_reason)
268         self.error_dialog.setWindowTitle(strings.update_failed_dialog_title)
269         self.error_dialog.show()
270 
271     def get_sudo_password(self):
272         sudo_password, ok_is_pressed = QtWidgets.QInputDialog.getText(
273             self, "Tails Administrator password", strings.sudo_password_text,
274             QtWidgets.QLineEdit.Password, "")
275         if ok_is_pressed and sudo_password:
276             return sudo_password
277         else:
278             return None
279
```
--- END FILES ---

Please first localize the bug based on the issue statement, and then generate a patch according to the `git diff` format fenced by three backticks.

Here is an example:

```diff
diff --git a/examples/server_async.py b/examples/server_async.py
--- a/examples/server_async.py
+++ b/examples/server_async.py
@@ -313,4 +313,4 @@
 
 
 if __name__ == "__main__":
-    asyncio.run(run_async_server("."), debug=True)
+    asyncio.run(run_async_server(), debug=True)
diff --git a/examples/server_sync.py b/examples/server_sync.py
--- a/examples/server_sync.py
+++ b/examples/server_sync.py
@@ -313,5 +313,5 @@
 
 
 if __name__ == "__main__":
-    server = run_sync_server(".")
+    server = run_sync_server()
     server.shutdown()

```

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
@@ -130,6 +130,7 @@
     def __init__(self, parent=None):
         super(UpdaterApp, self).__init__(parent)
         self.setupUi(self)
+        self.statusbar.setSizeGripEnabled(False)
         self.output = strings.initial_text_box
         self.plainTextEdit.setPlainText(self.output)
         self.update_success = False

{"golden_diff": "diff --git a/journalist_gui/journalist_gui/SecureDropUpdater.py b/journalist_gui/journalist_gui/SecureDropUpdater.py\n--- a/journalist_gui/journalist_gui/SecureDropUpdater.py\n+++ b/journalist_gui/journalist_gui/SecureDropUpdater.py\n@@ -130,6 +130,7 @@\n     def __init__(self, parent=None):\n         super(UpdaterApp, self).__init__(parent)\n         self.setupUi(self)\n+        self.statusbar.setSizeGripEnabled(False)\n         self.output = strings.initial_text_box\n         self.plainTextEdit.setPlainText(self.output)\n         self.update_success = False\n", "issue": "[RFE] Remove the sizegrip from the statusbar of the GUI tool\n# Feature request\r\n\r\n## Description\r\n\r\nThere should not be any sizegrip available in the statusbar of the GUI tool as suggested in https://github.com/freedomofpress/securedrop/pull/3300#discussion_r184066922\n", "before_files": [{"content": "#!/usr/bin/python\nfrom PyQt5 import QtGui, QtWidgets\nfrom PyQt5.QtCore import QThread, pyqtSignal\nimport subprocess\nimport os\nimport pexpect\n\nfrom journalist_gui import updaterUI, strings, resources_rc  # noqa\n\n\nLOCK_LOCATION = \"/home/amnesia/Persistent/securedrop/securedrop_update.lock\"  # noqa\n\n\nclass SetupThread(QThread):\n    signal = pyqtSignal('PyQt_PyObject')\n\n    def __init__(self):\n        QThread.__init__(self)\n        self.output = \"\"\n        self.update_success = False\n        self.failure_reason = \"\"\n\n    def run(self):\n        sdadmin_path = '/home/amnesia/Persistent/securedrop/securedrop-admin'\n        update_command = [sdadmin_path, 'setup']\n\n        # Create lock so we resume failed updates on reboot.\n        # Don't create the lock if it already exists.\n        if not os.path.exists(LOCK_LOCATION):\n            open(LOCK_LOCATION, 'a').close()\n\n        try:\n            self.output = subprocess.check_output(\n                update_command,\n                stderr=subprocess.STDOUT).decode('utf-8')\n            if 'Failed to install' in self.output:\n                self.update_success = False\n                self.failure_reason = strings.update_failed_generic_reason\n            else:\n                self.update_success = True\n        except subprocess.CalledProcessError as e:\n            self.output += e.output.decode('utf-8')\n            self.update_success = False\n            self.failure_reason = strings.update_failed_generic_reason\n        result = {'status': self.update_success,\n                  'output': self.output,\n                  'failure_reason': self.failure_reason}\n        self.signal.emit(result)\n\n\n# This thread will handle the ./securedrop-admin update command\nclass UpdateThread(QThread):\n    signal = pyqtSignal('PyQt_PyObject')\n\n    def __init__(self):\n        QThread.__init__(self)\n        self.output = \"\"\n        self.update_success = False\n        self.failure_reason = \"\"\n\n    def run(self):\n        sdadmin_path = '/home/amnesia/Persistent/securedrop/securedrop-admin'\n        update_command = [sdadmin_path, 'update']\n        try:\n            self.output = subprocess.check_output(\n                update_command,\n                stderr=subprocess.STDOUT).decode('utf-8')\n            if \"Signature verification successful\" in self.output:\n                self.update_success = True\n            else:\n                self.failure_reason = strings.update_failed_generic_reason\n        except subprocess.CalledProcessError as e:\n            self.update_success = False\n            self.output += e.output.decode('utf-8')\n            if 'Signature verification failed' in self.output:\n                self.failure_reason = strings.update_failed_sig_failure\n            else:\n                self.failure_reason = strings.update_failed_generic_reason\n        result = {'status': self.update_success,\n                  'output': self.output,\n                  'failure_reason': self.failure_reason}\n        self.signal.emit(result)\n\n\n# This thread will handle the ./securedrop-admin tailsconfig command\nclass TailsconfigThread(QThread):\n    signal = pyqtSignal('PyQt_PyObject')\n\n    def __init__(self):\n        QThread.__init__(self)\n        self.output = \"\"\n        self.update_success = False\n        self.failure_reason = \"\"\n        self.sudo_password = \"\"\n\n    def run(self):\n        tailsconfig_command = (\"/home/amnesia/Persistent/\"\n                               \"securedrop/securedrop-admin \"\n                               \"tailsconfig\")\n        try:\n            child = pexpect.spawn(tailsconfig_command)\n            child.expect('SUDO password:')\n            self.output += child.before.decode('utf-8')\n            child.sendline(self.sudo_password)\n            child.expect(pexpect.EOF)\n            self.output += child.before.decode('utf-8')\n\n            # For Tailsconfig to be considered a success, we expect no\n            # failures in the Ansible output.\n            if 'failed=0' not in self.output:\n                self.update_success = False\n                self.failure_reason = strings.tailsconfig_failed_generic_reason  # noqa\n            else:\n                self.update_success = True\n        except pexpect.exceptions.TIMEOUT:\n            self.update_success = False\n            self.failure_reason = strings.tailsconfig_failed_sudo_password\n\n        except subprocess.CalledProcessError:\n            self.update_success = False\n            self.failure_reason = strings.tailsconfig_failed_generic_reason\n        result = {'status': self.update_success,\n                  'output': self.output,\n                  'failure_reason': self.failure_reason}\n        self.signal.emit(result)\n\n\nclass UpdaterApp(QtWidgets.QMainWindow, updaterUI.Ui_MainWindow):\n\n    def __init__(self, parent=None):\n        super(UpdaterApp, self).__init__(parent)\n        self.setupUi(self)\n        self.output = strings.initial_text_box\n        self.plainTextEdit.setPlainText(self.output)\n        self.update_success = False\n\n        pixmap = QtGui.QPixmap(\":/images/static/banner.png\")\n        self.label_2.setPixmap(pixmap)\n        self.label_2.setScaledContents(True)\n\n        self.progressBar.setProperty(\"value\", 0)\n        self.setWindowTitle(strings.window_title)\n        self.setWindowIcon(QtGui.QIcon(':/images/static/securedrop_icon.png'))\n        self.label.setText(strings.update_in_progress)\n\n        self.tabWidget.setTabText(self.tabWidget.indexOf(self.tab),\n                                  strings.main_tab)\n        self.tabWidget.setTabText(self.tabWidget.indexOf(self.tab_2),\n                                  strings.output_tab)\n\n        # Connect buttons to their functions.\n        self.pushButton.setText(strings.install_later_button)\n        self.pushButton.setStyleSheet(\"\"\"background-color: lightgrey;\n                                      min-height: 2em;\n                                      border-radius: 10px\"\"\")\n        self.pushButton.clicked.connect(self.close)\n        self.pushButton_2.setText(strings.install_update_button)\n        self.pushButton_2.setStyleSheet(\"\"\"background-color: #E6FFEB;\n                                        min-height: 2em;\n                                        border-radius: 10px;\"\"\")\n        self.pushButton_2.clicked.connect(self.update_securedrop)\n        self.update_thread = UpdateThread()\n        self.update_thread.signal.connect(self.update_status)\n        self.tails_thread = TailsconfigThread()\n        self.tails_thread.signal.connect(self.tails_status)\n        self.setup_thread = SetupThread()\n        self.setup_thread.signal.connect(self.setup_status)\n\n    # At the end of this function, we will try to do tailsconfig.\n    # A new slot will handle tailsconfig output\n    def setup_status(self, result):\n        \"This is the slot for setup thread\"\n        self.output += result['output']\n        self.update_success = result['status']\n        self.failure_reason = result['failure_reason']\n        self.progressBar.setProperty(\"value\", 60)\n        self.plainTextEdit.setPlainText(self.output)\n        self.plainTextEdit.setReadOnly = True\n        if not self.update_success:  # Failed to do setup update\n            self.pushButton.setEnabled(True)\n            self.pushButton_2.setEnabled(True)\n            self.update_status_bar_and_output(self.failure_reason)\n            self.progressBar.setProperty(\"value\", 0)\n            self.alert_failure(self.failure_reason)\n            return\n        self.progressBar.setProperty(\"value\", 70)\n        self.call_tailsconfig()\n\n    # This will update the output text after the git commands.\n    def update_status(self, result):\n        \"This is the slot for update thread\"\n        self.output += result['output']\n        self.update_success = result['status']\n        self.failure_reason = result['failure_reason']\n        self.progressBar.setProperty(\"value\", 40)\n        self.plainTextEdit.setPlainText(self.output)\n        self.plainTextEdit.setReadOnly = True\n        self.progressBar.setProperty(\"value\", 50)\n        self.update_status_bar_and_output(strings.doing_setup)\n        self.setup_thread.start()\n\n    def update_status_bar_and_output(self, status_message):\n        \"\"\"This method updates the status bar and the output window with the\n        status_message.\"\"\"\n        self.statusbar.showMessage(status_message)\n        self.output += status_message + '\\n'\n        self.plainTextEdit.setPlainText(self.output)\n\n    def call_tailsconfig(self):\n        # Now let us work on tailsconfig part\n        if self.update_success:\n            # Get sudo password and add an enter key as tailsconfig command\n            # expects\n            sudo_password = self.get_sudo_password()\n            if not sudo_password:\n                self.update_success = False\n                self.failure_reason = strings.missing_sudo_password\n                self.on_failure()\n                return\n            self.tails_thread.sudo_password = sudo_password + '\\n'\n            self.update_status_bar_and_output(strings.updating_tails_env)\n            self.tails_thread.start()\n        else:\n            self.on_failure()\n\n    def tails_status(self, result):\n        \"This is the slot for Tailsconfig thread\"\n        self.output += result['output']\n        self.update_success = result['status']\n        self.failure_reason = result['failure_reason']\n        self.plainTextEdit.setPlainText(self.output)\n        self.progressBar.setProperty(\"value\", 80)\n        if self.update_success:\n            # Remove lock\n            os.remove(LOCK_LOCATION)\n            self.update_status_bar_and_output(strings.finished)\n            self.progressBar.setProperty(\"value\", 100)\n            self.alert_success()\n        else:\n            self.on_failure()\n\n    def on_failure(self):\n        self.update_status_bar_and_output(self.failure_reason)\n        self.alert_failure(self.failure_reason)\n        # Now everything is done, enable the button.\n        self.pushButton.setEnabled(True)\n        self.pushButton_2.setEnabled(True)\n        self.progressBar.setProperty(\"value\", 0)\n\n    def update_securedrop(self):\n        self.pushButton_2.setEnabled(False)\n        self.pushButton.setEnabled(False)\n        self.progressBar.setProperty(\"value\", 10)\n        self.update_status_bar_and_output(strings.fetching_update)\n        self.update_thread.start()\n\n    def alert_success(self):\n        self.success_dialog = QtWidgets.QMessageBox()\n        self.success_dialog.setIcon(QtWidgets.QMessageBox.Information)\n        self.success_dialog.setText(strings.finished_dialog_message)\n        self.success_dialog.setWindowTitle(strings.finished_dialog_title)\n        self.success_dialog.show()\n\n    def alert_failure(self, failure_reason):\n        self.error_dialog = QtWidgets.QMessageBox()\n        self.error_dialog.setIcon(QtWidgets.QMessageBox.Critical)\n        self.error_dialog.setText(self.failure_reason)\n        self.error_dialog.setWindowTitle(strings.update_failed_dialog_title)\n        self.error_dialog.show()\n\n    def get_sudo_password(self):\n        sudo_password, ok_is_pressed = QtWidgets.QInputDialog.getText(\n            self, \"Tails Administrator password\", strings.sudo_password_text,\n            QtWidgets.QLineEdit.Password, \"\")\n        if ok_is_pressed and sudo_password:\n            return sudo_password\n        else:\n            return None\n", "path": "journalist_gui/journalist_gui/SecureDropUpdater.py"}], "after_files": [{"content": "#!/usr/bin/python\nfrom PyQt5 import QtGui, QtWidgets\nfrom PyQt5.QtCore import QThread, pyqtSignal\nimport subprocess\nimport os\nimport pexpect\n\nfrom journalist_gui import updaterUI, strings, resources_rc  # noqa\n\n\nLOCK_LOCATION = \"/home/amnesia/Persistent/securedrop/securedrop_update.lock\"  # noqa\n\n\nclass SetupThread(QThread):\n    signal = pyqtSignal('PyQt_PyObject')\n\n    def __init__(self):\n        QThread.__init__(self)\n        self.output = \"\"\n        self.update_success = False\n        self.failure_reason = \"\"\n\n    def run(self):\n        sdadmin_path = '/home/amnesia/Persistent/securedrop/securedrop-admin'\n        update_command = [sdadmin_path, 'setup']\n\n        # Create lock so we resume failed updates on reboot.\n        # Don't create the lock if it already exists.\n        if not os.path.exists(LOCK_LOCATION):\n            open(LOCK_LOCATION, 'a').close()\n\n        try:\n            self.output = subprocess.check_output(\n                update_command,\n                stderr=subprocess.STDOUT).decode('utf-8')\n            if 'Failed to install' in self.output:\n                self.update_success = False\n                self.failure_reason = strings.update_failed_generic_reason\n            else:\n                self.update_success = True\n        except subprocess.CalledProcessError as e:\n            self.output += e.output.decode('utf-8')\n            self.update_success = False\n            self.failure_reason = strings.update_failed_generic_reason\n        result = {'status': self.update_success,\n                  'output': self.output,\n                  'failure_reason': self.failure_reason}\n        self.signal.emit(result)\n\n\n# This thread will handle the ./securedrop-admin update command\nclass UpdateThread(QThread):\n    signal = pyqtSignal('PyQt_PyObject')\n\n    def __init__(self):\n        QThread.__init__(self)\n        self.output = \"\"\n        self.update_success = False\n        self.failure_reason = \"\"\n\n    def run(self):\n        sdadmin_path = '/home/amnesia/Persistent/securedrop/securedrop-admin'\n        update_command = [sdadmin_path, 'update']\n        try:\n            self.output = subprocess.check_output(\n                update_command,\n                stderr=subprocess.STDOUT).decode('utf-8')\n            if \"Signature verification successful\" in self.output:\n                self.update_success = True\n            else:\n                self.failure_reason = strings.update_failed_generic_reason\n        except subprocess.CalledProcessError as e:\n            self.update_success = False\n            self.output += e.output.decode('utf-8')\n            if 'Signature verification failed' in self.output:\n                self.failure_reason = strings.update_failed_sig_failure\n            else:\n                self.failure_reason = strings.update_failed_generic_reason\n        result = {'status': self.update_success,\n                  'output': self.output,\n                  'failure_reason': self.failure_reason}\n        self.signal.emit(result)\n\n\n# This thread will handle the ./securedrop-admin tailsconfig command\nclass TailsconfigThread(QThread):\n    signal = pyqtSignal('PyQt_PyObject')\n\n    def __init__(self):\n        QThread.__init__(self)\n        self.output = \"\"\n        self.update_success = False\n        self.failure_reason = \"\"\n        self.sudo_password = \"\"\n\n    def run(self):\n        tailsconfig_command = (\"/home/amnesia/Persistent/\"\n                               \"securedrop/securedrop-admin \"\n                               \"tailsconfig\")\n        try:\n            child = pexpect.spawn(tailsconfig_command)\n            child.expect('SUDO password:')\n            self.output += child.before.decode('utf-8')\n            child.sendline(self.sudo_password)\n            child.expect(pexpect.EOF)\n            self.output += child.before.decode('utf-8')\n\n            # For Tailsconfig to be considered a success, we expect no\n            # failures in the Ansible output.\n            if 'failed=0' not in self.output:\n                self.update_success = False\n                self.failure_reason = strings.tailsconfig_failed_generic_reason  # noqa\n            else:\n                self.update_success = True\n        except pexpect.exceptions.TIMEOUT:\n            self.update_success = False\n            self.failure_reason = strings.tailsconfig_failed_sudo_password\n\n        except subprocess.CalledProcessError:\n            self.update_success = False\n            self.failure_reason = strings.tailsconfig_failed_generic_reason\n        result = {'status': self.update_success,\n                  'output': self.output,\n                  'failure_reason': self.failure_reason}\n        self.signal.emit(result)\n\n\nclass UpdaterApp(QtWidgets.QMainWindow, updaterUI.Ui_MainWindow):\n\n    def __init__(self, parent=None):\n        super(UpdaterApp, self).__init__(parent)\n        self.setupUi(self)\n        self.statusbar.setSizeGripEnabled(False)\n        self.output = strings.initial_text_box\n        self.plainTextEdit.setPlainText(self.output)\n        self.update_success = False\n\n        pixmap = QtGui.QPixmap(\":/images/static/banner.png\")\n        self.label_2.setPixmap(pixmap)\n        self.label_2.setScaledContents(True)\n\n        self.progressBar.setProperty(\"value\", 0)\n        self.setWindowTitle(strings.window_title)\n        self.setWindowIcon(QtGui.QIcon(':/images/static/securedrop_icon.png'))\n        self.label.setText(strings.update_in_progress)\n\n        self.tabWidget.setTabText(self.tabWidget.indexOf(self.tab),\n                                  strings.main_tab)\n        self.tabWidget.setTabText(self.tabWidget.indexOf(self.tab_2),\n                                  strings.output_tab)\n\n        # Connect buttons to their functions.\n        self.pushButton.setText(strings.install_later_button)\n        self.pushButton.setStyleSheet(\"\"\"background-color: lightgrey;\n                                      min-height: 2em;\n                                      border-radius: 10px\"\"\")\n        self.pushButton.clicked.connect(self.close)\n        self.pushButton_2.setText(strings.install_update_button)\n        self.pushButton_2.setStyleSheet(\"\"\"background-color: #E6FFEB;\n                                        min-height: 2em;\n                                        border-radius: 10px;\"\"\")\n        self.pushButton_2.clicked.connect(self.update_securedrop)\n        self.update_thread = UpdateThread()\n        self.update_thread.signal.connect(self.update_status)\n        self.tails_thread = TailsconfigThread()\n        self.tails_thread.signal.connect(self.tails_status)\n        self.setup_thread = SetupThread()\n        self.setup_thread.signal.connect(self.setup_status)\n\n    # At the end of this function, we will try to do tailsconfig.\n    # A new slot will handle tailsconfig output\n    def setup_status(self, result):\n        \"This is the slot for setup thread\"\n        self.output += result['output']\n        self.update_success = result['status']\n        self.failure_reason = result['failure_reason']\n        self.progressBar.setProperty(\"value\", 60)\n        self.plainTextEdit.setPlainText(self.output)\n        self.plainTextEdit.setReadOnly = True\n        if not self.update_success:  # Failed to do setup update\n            self.pushButton.setEnabled(True)\n            self.pushButton_2.setEnabled(True)\n            self.update_status_bar_and_output(self.failure_reason)\n            self.progressBar.setProperty(\"value\", 0)\n            self.alert_failure(self.failure_reason)\n            return\n        self.progressBar.setProperty(\"value\", 70)\n        self.call_tailsconfig()\n\n    # This will update the output text after the git commands.\n    def update_status(self, result):\n        \"This is the slot for update thread\"\n        self.output += result['output']\n        self.update_success = result['status']\n        self.failure_reason = result['failure_reason']\n        self.progressBar.setProperty(\"value\", 40)\n        self.plainTextEdit.setPlainText(self.output)\n        self.plainTextEdit.setReadOnly = True\n        self.progressBar.setProperty(\"value\", 50)\n        self.update_status_bar_and_output(strings.doing_setup)\n        self.setup_thread.start()\n\n    def update_status_bar_and_output(self, status_message):\n        \"\"\"This method updates the status bar and the output window with the\n        status_message.\"\"\"\n        self.statusbar.showMessage(status_message)\n        self.output += status_message + '\\n'\n        self.plainTextEdit.setPlainText(self.output)\n\n    def call_tailsconfig(self):\n        # Now let us work on tailsconfig part\n        if self.update_success:\n            # Get sudo password and add an enter key as tailsconfig command\n            # expects\n            sudo_password = self.get_sudo_password()\n            if not sudo_password:\n                self.update_success = False\n                self.failure_reason = strings.missing_sudo_password\n                self.on_failure()\n                return\n            self.tails_thread.sudo_password = sudo_password + '\\n'\n            self.update_status_bar_and_output(strings.updating_tails_env)\n            self.tails_thread.start()\n        else:\n            self.on_failure()\n\n    def tails_status(self, result):\n        \"This is the slot for Tailsconfig thread\"\n        self.output += result['output']\n        self.update_success = result['status']\n        self.failure_reason = result['failure_reason']\n        self.plainTextEdit.setPlainText(self.output)\n        self.progressBar.setProperty(\"value\", 80)\n        if self.update_success:\n            # Remove lock\n            os.remove(LOCK_LOCATION)\n            self.update_status_bar_and_output(strings.finished)\n            self.progressBar.setProperty(\"value\", 100)\n            self.alert_success()\n        else:\n            self.on_failure()\n\n    def on_failure(self):\n        self.update_status_bar_and_output(self.failure_reason)\n        self.alert_failure(self.failure_reason)\n        # Now everything is done, enable the button.\n        self.pushButton.setEnabled(True)\n        self.pushButton_2.setEnabled(True)\n        self.progressBar.setProperty(\"value\", 0)\n\n    def update_securedrop(self):\n        self.pushButton_2.setEnabled(False)\n        self.pushButton.setEnabled(False)\n        self.progressBar.setProperty(\"value\", 10)\n        self.update_status_bar_and_output(strings.fetching_update)\n        self.update_thread.start()\n\n    def alert_success(self):\n        self.success_dialog = QtWidgets.QMessageBox()\n        self.success_dialog.setIcon(QtWidgets.QMessageBox.Information)\n        self.success_dialog.setText(strings.finished_dialog_message)\n        self.success_dialog.setWindowTitle(strings.finished_dialog_title)\n        self.success_dialog.show()\n\n    def alert_failure(self, failure_reason):\n        self.error_dialog = QtWidgets.QMessageBox()\n        self.error_dialog.setIcon(QtWidgets.QMessageBox.Critical)\n        self.error_dialog.setText(self.failure_reason)\n        self.error_dialog.setWindowTitle(strings.update_failed_dialog_title)\n        self.error_dialog.show()\n\n    def get_sudo_password(self):\n        sudo_password, ok_is_pressed = QtWidgets.QInputDialog.getText(\n            self, \"Tails Administrator password\", strings.sudo_password_text,\n            QtWidgets.QLineEdit.Password, \"\")\n        if ok_is_pressed and sudo_password:\n            return sudo_password\n        else:\n            return None\n", "path": "journalist_gui/journalist_gui/SecureDropUpdater.py"}]}