Mercurial > libervia-backend
comparison src/plugins/plugin_misc_account.py @ 1041:9095263011b6
plugin misc_accout: update relative to the introduction of profile password:
- check for the profile password instead of the xmpp password before a modification can be done
- "Change your password" action changes both passwords (a confirmation is asked)
author | souliane <souliane@mailoo.org> |
---|---|
date | Wed, 21 May 2014 12:07:13 +0200 |
parents | 76ad41b708e1 |
children | 85c110c0be86 |
comparison
equal
deleted
inserted
replaced
1040:76ad41b708e1 | 1041:9095263011b6 |
---|---|
19 | 19 |
20 from sat.core.i18n import _, D_ | 20 from sat.core.i18n import _, D_ |
21 from sat.core.log import getLogger | 21 from sat.core.log import getLogger |
22 log = getLogger(__name__) | 22 log = getLogger(__name__) |
23 from sat.core import exceptions | 23 from sat.core import exceptions |
24 from sat.tools import xml_tools | |
25 from sat.memory.memory import Sessions | |
26 from sat.memory.crypto import PasswordHasher | |
27 from sat.core.constants import Const as C | |
28 | |
24 from twisted.internet import reactor, defer, protocol | 29 from twisted.internet import reactor, defer, protocol |
25 from os.path import join, dirname | |
26 from twisted.python.procutils import which | 30 from twisted.python.procutils import which |
27 from twisted.python.failure import Failure | 31 from twisted.python.failure import Failure |
32 from twisted.mail.smtp import sendmail | |
33 from os.path import join, dirname | |
28 from email.mime.text import MIMEText | 34 from email.mime.text import MIMEText |
29 from twisted.mail.smtp import sendmail | |
30 from sat.tools import xml_tools | |
31 | 35 |
32 PLUGIN_INFO = { | 36 PLUGIN_INFO = { |
33 "name": "Account Plugin", | 37 "name": "Account Plugin", |
34 "import_name": "MISC-ACCOUNT", | 38 "import_name": "MISC-ACCOUNT", |
35 "type": "MISC", | 39 "type": "MISC", |
130 log.error(_("Can't find %s") % (self.getConfig('prosodyctl'), )) | 134 log.error(_("Can't find %s") % (self.getConfig('prosodyctl'), )) |
131 else: | 135 else: |
132 self._prosody_path = dirname(paths[0]) | 136 self._prosody_path = dirname(paths[0]) |
133 log.info(_('Prosody path found: %s') % (self._prosody_path, )) | 137 log.info(_('Prosody path found: %s') % (self._prosody_path, )) |
134 | 138 |
139 self._sessions = Sessions() | |
140 | |
135 self.__account_cb_id = host.registerCallback(self._accountDialogCb, with_data=True) | 141 self.__account_cb_id = host.registerCallback(self._accountDialogCb, with_data=True) |
136 self.__delete_account_id = host.registerCallback(self.__deleteAccountCb, with_data=True) | 142 self.__change_password_id = host.registerCallback(self.__changePasswordCb, with_data=True) |
137 | 143 |
138 def deleteBlogCallback(posts, comments): | 144 def deleteBlogCallback(posts, comments): |
139 return lambda data, profile: self.__deleteBlogPostsCb(posts, comments, data, profile) | 145 return lambda data, profile: self.__deleteBlogPostsCb(posts, comments, data, profile) |
140 | 146 |
141 self.__delete_posts_comments_id = host.registerCallback(deleteBlogCallback(True, True), with_data=True) | |
142 self.__delete_posts_id = host.registerCallback(deleteBlogCallback(True, False), with_data=True) | 147 self.__delete_posts_id = host.registerCallback(deleteBlogCallback(True, False), with_data=True) |
143 self.__delete_comments_id = host.registerCallback(deleteBlogCallback(False, True), with_data=True) | 148 self.__delete_comments_id = host.registerCallback(deleteBlogCallback(False, True), with_data=True) |
149 self.__delete_posts_comments_id = host.registerCallback(deleteBlogCallback(True, True), with_data=True) | |
150 | |
151 self.__delete_account_id = host.registerCallback(self.__deleteAccountCb, with_data=True) | |
144 | 152 |
145 def getConfig(self, name): | 153 def getConfig(self, name): |
146 return self.host.memory.getConfig(CONFIG_SECTION, name) or default_conf[name] | 154 return self.host.memory.getConfig(CONFIG_SECTION, name) or default_conf[name] |
147 | 155 |
148 def _registerAccount(self, email, password, profile): | 156 def _registerAccount(self, email, password, profile): |
250 """Get the main dialog to manage your account | 258 """Get the main dialog to manage your account |
251 @param menu_data | 259 @param menu_data |
252 @param profile: %(doc_profile)s | 260 @param profile: %(doc_profile)s |
253 @return: XML of the dialog | 261 @return: XML of the dialog |
254 """ | 262 """ |
255 form_ui = xml_tools.XMLUI("form", "tabs", title=D_("Manage your XMPP account"), submit_id=self.__account_cb_id) | 263 form_ui = xml_tools.XMLUI("form", "tabs", title=D_("Manage your account"), submit_id=self.__account_cb_id) |
256 tab_container = form_ui.current_container | 264 tab_container = form_ui.current_container |
257 | 265 |
258 tab_container.addTab("update", D_("Change your password"), container=xml_tools.PairsContainer) | 266 tab_container.addTab("update", D_("Change your password"), container=xml_tools.PairsContainer) |
259 form_ui.addLabel(D_("Current password")) | 267 form_ui.addLabel(D_("Current profile password")) |
260 form_ui.addPassword("current_passwd", value="") | 268 form_ui.addPassword("current_passwd", value="") |
261 form_ui.addLabel(D_("New password")) | 269 form_ui.addLabel(D_("New password")) |
262 form_ui.addPassword("new_passwd1", value="") | 270 form_ui.addPassword("new_passwd1", value="") |
263 form_ui.addLabel(D_("New password (again)")) | 271 form_ui.addLabel(D_("New password (again)")) |
264 form_ui.addPassword("new_passwd2", value="") | 272 form_ui.addPassword("new_passwd2", value="") |
265 | 273 |
266 if 'GROUPBLOG' in self.host.plugins: | 274 if 'GROUPBLOG' in self.host.plugins: |
267 tab_container.addTab("delete_posts", D_("Delete your posts"), container=xml_tools.PairsContainer) | 275 tab_container.addTab("delete_posts", D_("Delete your posts"), container=xml_tools.PairsContainer) |
268 form_ui.addLabel(D_("Current password")) | 276 form_ui.addLabel(D_("Current profile password")) |
269 form_ui.addPassword("delete_posts_passwd", value="") | 277 form_ui.addPassword("delete_posts_passwd", value="") |
270 form_ui.addLabel(D_("Delete all your posts and their comments")) | 278 form_ui.addLabel(D_("Delete all your posts and their comments")) |
271 form_ui.addBool("delete_posts_checkbox", "false") | 279 form_ui.addBool("delete_posts_checkbox", "false") |
272 form_ui.addLabel(D_("Delete all your comments on other's posts")) | 280 form_ui.addLabel(D_("Delete all your comments on other's posts")) |
273 form_ui.addBool("delete_comments_checkbox", "false") | 281 form_ui.addBool("delete_comments_checkbox", "false") |
274 | 282 |
275 tab_container.addTab("delete", D_("Delete your account"), container=xml_tools.PairsContainer) | 283 tab_container.addTab("delete", D_("Delete your account"), container=xml_tools.PairsContainer) |
276 form_ui.addLabel(D_("Current password")) | 284 form_ui.addLabel(D_("Current profile password")) |
277 form_ui.addPassword("delete_passwd", value="") | 285 form_ui.addPassword("delete_passwd", value="") |
278 form_ui.addLabel(D_("Delete your account")) | 286 form_ui.addLabel(D_("Delete your account")) |
279 form_ui.addBool("delete_checkbox", "false") | 287 form_ui.addBool("delete_checkbox", "false") |
280 return form_ui.toXml() | 288 return form_ui.toXml() |
281 | 289 |
283 def _accountDialogCb(self, data, profile): | 291 def _accountDialogCb(self, data, profile): |
284 """Called when the user submits the main account dialog | 292 """Called when the user submits the main account dialog |
285 @param data | 293 @param data |
286 @param profile | 294 @param profile |
287 """ | 295 """ |
288 password = yield self.host.memory.asyncGetParamA("Password", "Connection", profile_key=profile) | 296 sat_cipher = yield self.host.memory.asyncGetParamA(C.PROFILE_PASS_PATH[1], C.PROFILE_PASS_PATH[0], profile_key=profile) |
289 | 297 |
290 def error_ui(): | 298 @defer.inlineCallbacks |
291 error_ui = xml_tools.XMLUI("popup", title=D_("Error")) | 299 def verify(attempt): |
292 error_ui.addText(D_("Passwords don't match!")) | 300 auth = yield PasswordHasher.verify(attempt, sat_cipher) |
301 defer.returnValue(auth) | |
302 | |
303 def error_ui(message=None): | |
304 if not message: | |
305 D_("The provided profile password doesn't match.") | |
306 error_ui = xml_tools.XMLUI("popup", title=D_("Attempt failure")) | |
307 error_ui.addText(message) | |
293 return {'xmlui': error_ui.toXml()} | 308 return {'xmlui': error_ui.toXml()} |
294 | 309 |
295 # check for account deletion | 310 # check for account deletion |
296 delete_passwd = data[xml_tools.SAT_FORM_PREFIX + 'delete_passwd'] | 311 delete_passwd = data[xml_tools.SAT_FORM_PREFIX + 'delete_passwd'] |
297 delete_checkbox = data[xml_tools.SAT_FORM_PREFIX + 'delete_checkbox'] | 312 delete_checkbox = data[xml_tools.SAT_FORM_PREFIX + 'delete_checkbox'] |
298 if delete_checkbox == 'true': | 313 if delete_checkbox == 'true': |
299 if password == delete_passwd: | 314 if verify(delete_passwd): |
300 defer.returnValue(self.__deleteAccount(profile)) | 315 defer.returnValue(self.__deleteAccount(profile)) |
301 defer.returnValue(error_ui()) | 316 defer.returnValue(error_ui()) |
302 | 317 |
303 # check for blog posts deletion | 318 # check for blog posts deletion |
304 if 'GROUPBLOG' in self.host.plugins: | 319 if 'GROUPBLOG' in self.host.plugins: |
306 delete_posts_checkbox = data[xml_tools.SAT_FORM_PREFIX + 'delete_posts_checkbox'] | 321 delete_posts_checkbox = data[xml_tools.SAT_FORM_PREFIX + 'delete_posts_checkbox'] |
307 delete_comments_checkbox = data[xml_tools.SAT_FORM_PREFIX + 'delete_comments_checkbox'] | 322 delete_comments_checkbox = data[xml_tools.SAT_FORM_PREFIX + 'delete_comments_checkbox'] |
308 posts = delete_posts_checkbox == 'true' | 323 posts = delete_posts_checkbox == 'true' |
309 comments = delete_comments_checkbox == 'true' | 324 comments = delete_comments_checkbox == 'true' |
310 if posts or comments: | 325 if posts or comments: |
311 if password == delete_posts_passwd: | 326 if verify(delete_posts_passwd): |
312 defer.returnValue(self.__deleteBlogPosts(posts, comments, profile)) | 327 defer.returnValue(self.__deleteBlogPosts(posts, comments, profile)) |
313 defer.returnValue(error_ui()) | 328 defer.returnValue(error_ui()) |
314 | 329 |
315 # check for password modification | 330 # check for password modification |
316 current_passwd = data[xml_tools.SAT_FORM_PREFIX + 'current_passwd'] | 331 current_passwd = data[xml_tools.SAT_FORM_PREFIX + 'current_passwd'] |
317 new_passwd1 = data[xml_tools.SAT_FORM_PREFIX + 'new_passwd1'] | 332 new_passwd1 = data[xml_tools.SAT_FORM_PREFIX + 'new_passwd1'] |
318 new_passwd2 = data[xml_tools.SAT_FORM_PREFIX + 'new_passwd2'] | 333 new_passwd2 = data[xml_tools.SAT_FORM_PREFIX + 'new_passwd2'] |
319 if new_passwd1 or new_passwd2: | 334 if new_passwd1 or new_passwd2: |
320 if password == current_passwd and new_passwd1 == new_passwd2: | 335 if verify(current_passwd): |
321 data = yield self.__changePassword(new_passwd1, profile=profile) | 336 if new_passwd1 == new_passwd2: |
322 defer.returnValue(data) | 337 data = yield self.__changePassword(new_passwd1, profile=profile) |
338 defer.returnValue(data) | |
339 else: | |
340 defer.returnValue(error_ui(D_("The values entered for the new password are not equal."))) | |
323 defer.returnValue(error_ui()) | 341 defer.returnValue(error_ui()) |
324 | 342 |
325 defer.returnValue({}) | 343 defer.returnValue({}) |
326 | 344 |
327 def __changePassword(self, password, profile): | 345 def __changePassword(self, password, profile): |
346 """Ask for a confirmation before changing the XMPP account and SàT profile passwords. | |
347 | |
348 @param password (str): the new password | |
349 @param profile (str): %(doc_profile)s | |
350 """ | |
351 session_id, dummy = self._sessions.newSession({'new_password': password}, profile) | |
352 form_ui = xml_tools.XMLUI("form", title=D_("Change your password?"), submit_id=self.__change_password_id, session_id=session_id) | |
353 form_ui.addText(D_("Note for advanced users: this will actually change both your SàT profile password AND your XMPP account password.")) | |
354 form_ui.addText(D_("Continue with changing the password?")) | |
355 return {'xmlui': form_ui.toXml()} | |
356 | |
357 def __changePasswordCb(self, data, profile): | |
328 """Actually change the user XMPP account and SàT profile password | 358 """Actually change the user XMPP account and SàT profile password |
329 @param password: new password | 359 @param data (dict) |
330 @profile | 360 @profile (str): %(doc_profile)s |
331 """ | 361 """ |
362 password = self._sessions.profileGet(data['session_id'], profile)['new_password'] | |
363 | |
332 def passwordChanged(result): | 364 def passwordChanged(result): |
333 self.host.memory.setParam("Password", password, "Connection", profile_key=profile) | 365 d = self.host.memory.setParam(C.PROFILE_PASS_PATH[1], password, C.PROFILE_PASS_PATH[0], profile_key=profile) |
366 d.addCallback(lambda dummy: self.host.memory.setParam("Password", password, "Connection", profile_key=profile)) | |
334 confirm_ui = xml_tools.XMLUI("popup", title=D_("Confirmation")) | 367 confirm_ui = xml_tools.XMLUI("popup", title=D_("Confirmation")) |
335 confirm_ui.addText(D_("Your password has been changed.")) | 368 confirm_ui.addText(D_("Your password has been changed.")) |
336 return defer.succeed({'xmlui': confirm_ui.toXml()}) | 369 return defer.succeed({'xmlui': confirm_ui.toXml()}) |
337 | 370 |
338 def errback(failure): | 371 def errback(failure): |