comparison src/plugins/plugin_misc_account.py @ 1855:1c9b2c184663

plugin account: email sending improvments: the following new options are handled: - email_sender_domain (default None) - email_port (default 25) - email_username (defaut None) - email_password (default None) - email_starttls true to force starttls (default false) - email_auth true to require authentication (default false) in addition, admin_email has been deprecated in favor of email_admins_list which can handle several addresses
author Goffi <goffi@goffi.org>
date Sat, 27 Feb 2016 14:49:20 +0100
parents 33e73c70d78a
children d7e29a12ec2c
comparison
equal deleted inserted replaced
1854:3c0bb714a80b 1855:1c9b2c184663
23 from sat.core import exceptions 23 from sat.core import exceptions
24 from sat.tools import xml_tools 24 from sat.tools import xml_tools
25 from sat.memory.memory import Sessions 25 from sat.memory.memory import Sessions
26 from sat.memory.crypto import PasswordHasher 26 from sat.memory.crypto import PasswordHasher
27 from sat.core.constants import Const as C 27 from sat.core.constants import Const as C
28 28 import ConfigParser
29 from twisted.internet import reactor, defer, protocol 29 from twisted.internet import reactor, defer, protocol
30 from twisted.python.procutils import which 30 from twisted.python.procutils import which
31 from twisted.python.failure import Failure 31 from twisted.python.failure import Failure
32 from twisted.mail.smtp import sendmail 32 from twisted.mail.smtp import sendmail
33 from os.path import join, dirname 33 from os.path import join, dirname
54 # all theses values (key=option name, value=default) can (and should) be overriden in sat.conf 54 # all theses values (key=option name, value=default) can (and should) be overriden in sat.conf
55 # in section CONFIG_SECTION 55 # in section CONFIG_SECTION
56 56
57 default_conf = {"email_from": "NOREPLY@example.net", 57 default_conf = {"email_from": "NOREPLY@example.net",
58 "email_server": "localhost", 58 "email_server": "localhost",
59 "admin_email": "admin@example.net", 59 "email_sender_domain": "",
60 "email_port": 25,
61 "email_username": "",
62 "email_password": "",
63 "email_starttls": "false",
64 "email_auth": "false",
65 "email_admins_list": [],
66 "admin_email": "",
60 "new_account_server": "localhost", 67 "new_account_server": "localhost",
61 "new_account_domain": "example.net", 68 "new_account_domain": "example.net",
62 "prosody_path": None, # prosody path (where prosodyctl will be executed from), or None to automaticaly find it 69 "prosody_path": None, # prosody path (where prosodyctl will be executed from), or None to automaticaly find it
63 "prosodyctl": "prosodyctl", 70 "prosodyctl": "prosodyctl",
64 "reserved_list": ['libervia'] # profiles which can't be used 71 "reserved_list": ['libervia'] # profiles which can't be used
153 self.__delete_posts_comments_id = host.registerCallback(deleteBlogCallback(True, True), with_data=True) 160 self.__delete_posts_comments_id = host.registerCallback(deleteBlogCallback(True, True), with_data=True)
154 161
155 self.__delete_account_id = host.registerCallback(self.__deleteAccountCb, with_data=True) 162 self.__delete_account_id = host.registerCallback(self.__deleteAccountCb, with_data=True)
156 163
157 def getConfig(self, name): 164 def getConfig(self, name):
165 if name.startswith("email_"):
166 # XXX: email_ parameters were first in [plugin account] section
167 # but as it make more sense to have them in common with other plugins,
168 # they can now be in [DEFAULT] section
169 try:
170 value = self.host.memory.getConfig(None, name, Exception)
171 except (ConfigParser.NoOptionError, ConfigParser.NoSectionError):
172 pass
173 else:
174 return value
175
158 return self.host.memory.getConfig(CONFIG_SECTION, name, default_conf[name]) 176 return self.host.memory.getConfig(CONFIG_SECTION, name, default_conf[name])
159 177
160 def generatePassword(self): 178 def generatePassword(self):
161 """Generate a password with random characters. 179 """Generate a password with random characters.
162 180
230 def sendEmails(self, email, jid_s, password, profile): 248 def sendEmails(self, email, jid_s, password, profile):
231 # time to send the email 249 # time to send the email
232 250
233 email_host = self.getConfig('email_server') 251 email_host = self.getConfig('email_server')
234 email_from = self.getConfig("email_from") 252 email_from = self.getConfig("email_from")
253 email_sender_domain = self.getConfig("email_sender_domain") or None
254 email_port = int(self.getConfig("email_port"))
255 email_username = self.getConfig("email_username") or None
256 email_password = self.getConfig("email_password") or None
257 email_starttls = C.bool(self.getConfig("email_starttls"))
258 email_auth = C.bool(self.getConfig("email_auth"))
235 domain = self.getConfig('new_account_domain') 259 domain = self.getConfig('new_account_domain')
236 260
261 # admin
262 admins_emails = self.getConfig('email_admins_list')
263 admin_email = self.getConfig('admin_email')
264 if admin_email:
265 log.warning(u"admin_email parameter is deprecated, please use email_admins_list instead")
266 admins_emails.append(admin_email)
267
237 # email to the administrator 268 # email to the administrator
238 body = (u"""New account created: %(profile)s [%(email)s]""" % {'profile': profile, 'email': email}).encode('utf-8') 269 if not admins_emails:
239 msg = MIMEText(body, 'plain', 'UTF-8') 270 log.warning(u"No known admin email, we can't send email to administrator(s).\nPlease fill email_admins_list parameter")
240 msg['Subject'] = _('New Libervia account created') 271 d_admin = defer.fail(exceptions.DataError("no admin email"))
241 msg['From'] = email_from 272 else:
242 msg['To'] = self.getConfig('admin_email') 273 body = (u"""New account created: %(profile)s [%(email)s]""" % {'profile': profile, 'email': email}).encode('utf-8')
243 274 msg = MIMEText(body, 'plain', 'UTF-8')
244 admin_email = self.getConfig('admin_email') 275 msg['Subject'] = _('New Libervia account created')
245 d_admin = sendmail(email_host, email_from, admin_email, msg.as_string()) 276 msg['From'] = email_from
246 d_admin.addCallbacks(lambda dummy: log.debug(u"Account creation notification sent to admin <%s>" % admin_email), 277 msg['To'] = ", ".join(admins_emails)
247 lambda dummy: log.error(u"Failed to send account creation notification to admin <%s>" % admin_email)) 278
279 d_admin = sendmail(email_host, email_from, admins_emails, msg.as_string(),
280 senderDomainName=email_sender_domain,
281 port=email_port,
282 username=email_username,
283 password=email_password,
284 requireAuthentication=email_starttls,
285 requireTransportSecurity=email_auth)
286 admins_emails_txt = u', '.join([u"<{}>".format(addr) for addr in admins_emails])
287 d_admin.addCallbacks(lambda dummy: log.debug(u"Account creation notification sent to admin(s) {}".format(admins_emails_txt)),
288 lambda dummy: log.error(u"Failed to send account creation notification to admin {}".format(admins_emails_txt)))
248 if not email: 289 if not email:
249 return d_admin 290 return d_admin
250 291
251 body = (_(u"""Welcome to Libervia, the web interface of Salut à Toi. 292 body = (_(u"""Welcome to Libervia, the web interface of Salut à Toi.
252 293
280 log.error(u"Failed to send account creation confirmation to <%s>" % email) 321 log.error(u"Failed to send account creation confirmation to <%s>" % email)
281 322
282 # XXX: this will not fail when the email address doesn't exist 323 # XXX: this will not fail when the email address doesn't exist
283 # FIXME: check email reception to validate email given by the user 324 # FIXME: check email reception to validate email given by the user
284 # FIXME: delete the profile if the email could not been sent? 325 # FIXME: delete the profile if the email could not been sent?
285 d_user = sendmail(email_host, email_from, email, msg.as_string()) 326 d_user = sendmail(email_host, email_from, email, msg.as_string(),
327 senderDomainName=email_sender_domain,
328 port=email_port,
329 username=email_username,
330 password=email_password,
331 requireAuthentication=email_starttls,
332 requireTransportSecurity=email_auth)
286 d_user.addCallbacks(lambda dummy: log.debug(u"Account creation confirmation sent to <%s>" % email), 333 d_user.addCallbacks(lambda dummy: log.debug(u"Account creation confirmation sent to <%s>" % email),
287 email_ko) 334 email_ko)
288 return defer.DeferredList([d_user, d_admin]) 335 return defer.DeferredList([d_user, d_admin])
289 336
290 def getNewAccountDomain(self): 337 def getNewAccountDomain(self):
306 form_ui.addLabel(D_("New password")) 353 form_ui.addLabel(D_("New password"))
307 form_ui.addPassword("new_passwd1", value="") 354 form_ui.addPassword("new_passwd1", value="")
308 form_ui.addLabel(D_("New password (again)")) 355 form_ui.addLabel(D_("New password (again)"))
309 form_ui.addPassword("new_passwd2", value="") 356 form_ui.addPassword("new_passwd2", value="")
310 357
311 # FIXME: uncomment and fix these features 358 # FIXME: uncomment and fix these features
312 """ 359 """
313 if 'GROUPBLOG' in self.host.plugins: 360 if 'GROUPBLOG' in self.host.plugins:
314 tab_container.addTab("delete_posts", D_("Delete your posts"), container=xml_tools.PairsContainer) 361 tab_container.addTab("delete_posts", D_("Delete your posts"), container=xml_tools.PairsContainer)
315 form_ui.addLabel(D_("Current profile password")) 362 form_ui.addLabel(D_("Current profile password"))
316 form_ui.addPassword("delete_posts_passwd", value="") 363 form_ui.addPassword("delete_posts_passwd", value="")
347 error_ui = xml_tools.XMLUI("popup", title=D_("Attempt failure")) 394 error_ui = xml_tools.XMLUI("popup", title=D_("Attempt failure"))
348 error_ui.addText(message) 395 error_ui.addText(message)
349 return {'xmlui': error_ui.toXml()} 396 return {'xmlui': error_ui.toXml()}
350 397
351 # check for account deletion 398 # check for account deletion
352 # FIXME: uncomment and fix these features 399 # FIXME: uncomment and fix these features
353 """ 400 """
354 delete_passwd = data[xml_tools.SAT_FORM_PREFIX + 'delete_passwd'] 401 delete_passwd = data[xml_tools.SAT_FORM_PREFIX + 'delete_passwd']
355 delete_checkbox = data[xml_tools.SAT_FORM_PREFIX + 'delete_checkbox'] 402 delete_checkbox = data[xml_tools.SAT_FORM_PREFIX + 'delete_checkbox']
356 if delete_checkbox == 'true': 403 if delete_checkbox == 'true':
357 verified = yield verify(delete_passwd) 404 verified = yield verify(delete_passwd)