1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
|
# -*- coding: utf-8 -*-
# passwordwindow.py
# Copyright (C) 2014 LEAP
#
# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program. If not, see <http://www.gnu.org/licenses/>.
"""
Change password dialog window
"""
from PySide import QtCore, QtGui
from leap.bitmask.util.credentials import password_checks
from leap.bitmask.gui.ui_password_change import Ui_PasswordChange
from leap.bitmask.gui.flashable import Flashable
import logging
logger = logging.getLogger(__name__)
class PasswordWindow(QtGui.QDialog, Flashable):
def __init__(self, parent, account, app):
"""
:param parent: parent object of the PreferencesWindow.
:parent type: QWidget
:param account: the user set in the login widget
:type account: Account
:param app: App instance
:type app: App
"""
QtGui.QDialog.__init__(self, parent)
self.account = account
self.app = app
self._backend_connect()
self.ui = Ui_PasswordChange()
self.ui.setupUi(self)
self.hide_flash()
self.ui.ok_button.clicked.connect(self._change_password)
self.ui.cancel_button.clicked.connect(self._close)
self.ui.username_lineedit.setText(account.address)
self._disabled = False # if set to True, never again enable widgets.
if account.username is None:
# should not ever happen, but just in case
self._disabled = True
self._enable_password_widgets(False)
self.ui.cancel_button.setEnabled(True)
self.flash_error(self.tr("Please log in to change your password."))
if self.is_soledad_needed() and not self._soledad_ready:
self._enable_password_widgets(False)
self.ui.cancel_button.setEnabled(True)
self.flash_message(
self.tr("Please wait for data storage to be ready."))
def is_soledad_needed(self):
"""
Returns true if the current account needs to change the soledad
password as well as the SRP password.
"""
return self.account.is_email_enabled()
#
# MANAGE WIDGETS
#
def _enable_password_widgets(self, enabled):
"""
Enables or disables the widgets in the password change group box.
:param enabled: True if the widgets should be enabled.
False if widgets should be disabled and
display the status label that shows that is
changing the password.
:type enabled: bool
"""
if self._disabled:
return
if enabled:
self.hide_flash()
else:
self.flash_message(self.tr("Changing password..."))
self.ui.current_password_lineedit.setEnabled(enabled)
self.ui.new_password_lineedit.setEnabled(enabled)
self.ui.new_password_confirmation_lineedit.setEnabled(enabled)
self.ui.ok_button.setEnabled(enabled)
self.ui.cancel_button.setEnabled(enabled)
def _change_password_success(self):
"""
Callback used to display a successfully changed password.
"""
logger.debug("Password changed successfully.")
self._clear_password_inputs()
self._enable_password_widgets(True)
self.flash_success(self.tr("Password changed successfully."))
def _clear_password_inputs(self):
"""
Clear the contents of the inputs.
"""
self.ui.current_password_lineedit.setText("")
self.ui.new_password_lineedit.setText("")
self.ui.new_password_confirmation_lineedit.setText("")
#
# SLOTS
#
def _backend_connect(self):
"""
Helper to connect to backend signals
"""
sig = self.app.signaler
sig.srp_password_change_ok.connect(self._srp_change_password_ok)
pwd_change_error = lambda: self._srp_change_password_problem(
self.tr("There was a problem changing the password."),
None)
sig.srp_password_change_error.connect(pwd_change_error)
pwd_change_badpw = lambda: self._srp_change_password_problem(
self.tr("You did not enter a correct current password."),
'current_password')
sig.srp_password_change_badpw.connect(pwd_change_badpw)
sig.soledad_password_change_ok.connect(
self._soledad_change_password_ok)
sig.soledad_password_change_error.connect(
self._soledad_change_password_problem)
self._soledad_ready = False
sig.soledad_bootstrap_finished.connect(self._on_soledad_ready)
@QtCore.Slot()
def _change_password(self):
"""
TRIGGERS:
self.ui.buttonBox.accepted
Changes the user's password if the inputboxes are correctly filled.
"""
current_password = self.ui.current_password_lineedit.text()
new_password = self.ui.new_password_lineedit.text()
new_password2 = self.ui.new_password_confirmation_lineedit.text()
self._enable_password_widgets(True)
if len(current_password) == 0:
self.flash_error(self.tr("Password is empty."))
self.ui.current_password_lineedit.setFocus()
return
ok, msg, field = password_checks(self.account.username, new_password,
new_password2)
if not ok:
self.flash_error(msg)
if field == 'new_password':
self.ui.new_password_lineedit.setFocus()
elif field == 'new_password_confirmation':
self.ui.new_password_confirmation_lineedit.setFocus()
return
self._enable_password_widgets(False)
self.app.backend.user_change_password(
current_password=current_password,
new_password=new_password)
@QtCore.Slot()
def _close(self):
"""
TRIGGERS:
self.ui.buttonBox.rejected
Close this dialog
"""
self.hide()
@QtCore.Slot()
def _srp_change_password_ok(self):
"""
TRIGGERS:
self._backend.signaler.srp_password_change_ok
Callback used to display a successfully changed password.
"""
new_password = self.ui.new_password_lineedit.text()
logger.debug("SRP password changed successfully.")
if self.is_soledad_needed():
self._backend.soledad_change_password(new_password=new_password)
else:
self._change_password_success()
@QtCore.Slot(unicode)
def _srp_change_password_problem(self, msg, field):
"""
TRIGGERS:
self._backend.signaler.srp_password_change_error
self._backend.signaler.srp_password_change_badpw
Callback used to display an error on changing password.
:param msg: the message to show to the user.
:type msg: unicode
"""
logger.error("Error changing password: %s" % (msg,))
self._enable_password_widgets(True)
self.flash_error(msg)
if field == 'current_password':
self.ui.current_password_lineedit.setFocus()
@QtCore.Slot()
def _soledad_change_password_ok(self):
"""
TRIGGERS:
Signaler.soledad_password_change_ok
Soledad password change went OK.
"""
logger.debug("Soledad password changed successfully.")
self._change_password_success()
@QtCore.Slot(unicode)
def _soledad_change_password_problem(self, msg):
"""
TRIGGERS:
Signaler.soledad_password_change_error
Callback used to display an error on changing password.
:param msg: the message to show to the user.
:type msg: unicode
"""
logger.error("Error changing soledad password: %s" % (msg,))
self._enable_password_widgets(True)
self.flash_error(msg)
@QtCore.Slot()
def _on_soledad_ready(self):
"""
TRIGGERS:
Signaler.soledad_bootstrap_finished
"""
self._enable_password_widgets(True)
self._soledad_ready = True
|