comparison src/plugins/plugin_misc_account.py @ 2181:968b0d13bcc7

plugin account, tools: some cleaning account + email and password tools: - plugin misc account has been reordered and cleaned a bit. - new xmpp_domain setting is used to get the domain name of main XMPP server - password generation method has been moved to tools.utils - email sending method has been moved to tools.email
author Goffi <goffi@goffi.org>
date Sun, 12 Mar 2017 19:32:59 +0100
parents 09cfec4d8d19
children 8be4f5769bf7
comparison
equal deleted inserted replaced
2180:be54e1c3394c 2181:968b0d13bcc7
27 from sat.core.constants import Const as C 27 from sat.core.constants import Const as C
28 import ConfigParser 28 import ConfigParser
29 from twisted.internet import defer 29 from twisted.internet import defer
30 from twisted.python.failure import Failure 30 from twisted.python.failure import Failure
31 from twisted.words.protocols.jabber import jid 31 from twisted.words.protocols.jabber import jid
32 from twisted.mail.smtp import sendmail 32 from sat.tools import email as sat_email
33 from email.mime.text import MIMEText
34
35 import random
36 33
37 # FIXME: this plugin code is old and need a cleaning 34 # FIXME: this plugin code is old and need a cleaning
38 # TODO: account deletion/password change need testing 35 # TODO: account deletion/password change need testing
39 36
40 37
65 "email_starttls": "false", 62 "email_starttls": "false",
66 "email_auth": "false", 63 "email_auth": "false",
67 "email_admins_list": [], 64 "email_admins_list": [],
68 "admin_email": "", 65 "admin_email": "",
69 "new_account_server": "localhost", 66 "new_account_server": "localhost",
70 "new_account_domain": "example.net", 67 "new_account_domain": "", # use xmpp_domain if not found
71 "reserved_list": ['libervia'] # profiles which can't be used 68 "reserved_list": ['libervia'] # profiles which can't be used
72 } 69 }
70
71 WELCOME_MSG = D_(u"""Welcome to Libervia, the web interface of Salut à Toi.
72
73 Your account on {domain} has been successfully created.
74 This is a demonstration version to show you the current status of the project.
75 It is still under development, please keep it in mind!
76
77 Here is your connection information:
78
79 Login on {domain}: {profile}
80 Jabber ID (JID): {jid}
81 Your password has been chosen by yourself during registration.
82
83 In the beginning, you have nobody to talk to. To find some contacts, you may use the users' directory:
84 - make yourself visible in "Service / Directory subscription".
85 - search for people with "Contacts" / Search directory".
86
87 Any feedback welcome. Thank you!
88
89 Salut à Toi association
90 https://www.salut-a-toi.org
91 """)
73 92
74 93
75 class MiscAccount(object): 94 class MiscAccount(object):
76 """Account plugin: create a SàT + XMPP account, used by Libervia""" 95 """Account plugin: create a SàT + XMPP account, used by Libervia"""
77 # XXX: This plugin was initialy a Q&D one used for the demo. 96 # XXX: This plugin was initialy a Q&D one used for the demo.
119 138
120 value = set(value) 139 value = set(value)
121 value.add(admin_email) 140 value.add(admin_email)
122 self.host.memory.config.set(section, param_name, ",".join(value)) 141 self.host.memory.config.set(section, param_name, ",".join(value))
123 142
124 def getConfig(self, name): 143 def getConfig(self, name, section=CONFIG_SECTION):
125 if name.startswith("email_"): 144 if name.startswith("email_"):
126 # XXX: email_ parameters were first in [plugin account] section 145 # XXX: email_ parameters were first in [plugin account] section
127 # but as it make more sense to have them in common with other plugins, 146 # but as it make more sense to have them in common with other plugins,
128 # they can now be in [DEFAULT] section 147 # they can now be in [DEFAULT] section
129 try: 148 try:
131 except (ConfigParser.NoOptionError, ConfigParser.NoSectionError): 150 except (ConfigParser.NoOptionError, ConfigParser.NoSectionError):
132 pass 151 pass
133 else: 152 else:
134 return value 153 return value
135 154
136 return self.host.memory.getConfig(CONFIG_SECTION, name, default_conf[name]) 155 if section == CONFIG_SECTION:
137 156 default = default_conf[name]
138 def generatePassword(self): 157 else:
139 """Generate a password with random characters. 158 default = None
140 159 return self.host.memory.getConfig(section, name, default)
141 @return unicode
142 """
143 random.seed()
144 #charset = [chr(i) for i in range(0x21,0x7F)] #XXX: this charset seems to have some issues with openfire
145 charset = [chr(i) for i in range(0x30,0x3A) + range(0x41,0x5B) + range (0x61,0x7B)]
146 return ''.join([random.choice(charset) for i in range(15)])
147 160
148 def _registerAccount(self, email, password, profile): 161 def _registerAccount(self, email, password, profile):
149 return self.registerAccount(email, password, None, profile) 162 return self.registerAccount(email, password, None, profile)
150 163
151 def registerAccount(self, email, password, jid_s, profile): 164 def registerAccount(self, email, password, jid_s, profile):
197 """ 210 """
198 if jid_s: 211 if jid_s:
199 d = defer.succeed(None) 212 d = defer.succeed(None)
200 jid_ = jid.JID(jid_s) 213 jid_ = jid.JID(jid_s)
201 else: 214 else:
202 jid_s = profile + u"@" + self.getConfig('new_account_domain') 215 jid_s = profile + u"@" + self.getNewAccountDomain()
203 jid_ = jid.JID(jid_s) 216 jid_ = jid.JID(jid_s)
204 d = self.host.plugins['XEP-0077'].registerNewAccount(jid_, password) 217 d = self.host.plugins['XEP-0077'].registerNewAccount(jid_, password)
205 218
206 def setParams(dummy): 219 def setParams(dummy):
207 self.host.memory.setParam("JabberID", jid_s, "Connection", profile_key=profile) 220 self.host.memory.setParam("JabberID", jid_s, "Connection", profile_key=profile)
216 d.addCallback(setParams) 229 d.addCallback(setParams)
217 d.addCallback(lambda dummy: self.host.memory.stopSession(profile)) 230 d.addCallback(lambda dummy: self.host.memory.stopSession(profile))
218 d.addErrback(removeProfile) 231 d.addErrback(removeProfile)
219 return d 232 return d
220 233
234 def _sendEmailEb(self, failure_, email):
235 # TODO: return error code to user
236 log.error(_(u"Failed to send account creation confirmation to {email}: {msg}").format(
237 email = email,
238 msg = failure_))
239
221 def sendEmails(self, email, profile): 240 def sendEmails(self, email, profile):
222 # time to send the email 241 # time to send the email
223 242
224 email_host = self.getConfig('email_server') 243 domain = self.getNewAccountDomain()
225 email_from = self.getConfig("email_from")
226 email_sender_domain = self.getConfig("email_sender_domain") or None
227 email_port = int(self.getConfig("email_port"))
228 email_username = self.getConfig("email_username") or None
229 email_password = self.getConfig("email_password") or None
230 email_starttls = C.bool(self.getConfig("email_starttls"))
231 email_auth = C.bool(self.getConfig("email_auth"))
232 domain = self.getConfig('new_account_domain')
233
234 def sendEmail(recipients, msg):
235 return sendmail(email_host.encode("utf-8"),
236 email_from.encode("utf-8"),
237 [email.encode("utf-8") for email in recipients],
238 msg.as_string(),
239 senderDomainName=email_sender_domain.encode("utf-8") if email_sender_domain else None,
240 port=email_port,
241 username=email_username.encode("utf-8") if email_username else None,
242 password=email_password.encode("utf-8") if email_password else None,
243 requireAuthentication=email_starttls,
244 requireTransportSecurity=email_auth)
245 244
246 # email to the administrators 245 # email to the administrators
247 admins_emails = self.getConfig('email_admins_list') 246 admins_emails = self.getConfig('email_admins_list')
248 if not admins_emails: 247 if not admins_emails:
249 log.warning(u"No known admin email, we can't send email to administrator(s).\nPlease fill email_admins_list parameter") 248 log.warning(u"No known admin email, we can't send email to administrator(s).\nPlease fill email_admins_list parameter")
250 d_admin = defer.fail(exceptions.DataError("no admin email")) 249 d_admin = defer.fail(exceptions.DataError("no admin email"))
251 else: 250 else:
252 body = (u"""New account created: %(profile)s [%(email)s]""" % {'profile': profile, 'email': email}).encode('utf-8') 251 subject = _(u'New Libervia account created')
253 msg = MIMEText(body, 'plain', 'UTF-8') 252 body = (u"""New account created: {profile} [{email}]""".format(
254 msg['Subject'] = _('New Libervia account created') 253 profile = profile,
255 msg['From'] = email_from 254 # there is no email when an existing XMPP account is used
256 msg['To'] = ", ".join(admins_emails) 255 email = email or u"<no email>"))
257 256 d_admin = sat_email.sendEmail(self.host, admins_emails, subject, body)
258 d_admin = sendEmail(admins_emails, msg) 257
259 admins_emails_txt = u', '.join([u"<{}>".format(addr) for addr in admins_emails]) 258 admins_emails_txt = u', '.join([u'<' + addr + u'>' for addr in admins_emails])
260 d_admin.addCallbacks(lambda dummy: log.debug(u"Account creation notification sent to admin(s) {}".format(admins_emails_txt)), 259 d_admin.addCallbacks(lambda dummy: log.debug(u"Account creation notification sent to admin(s) {}".format(admins_emails_txt)),
261 lambda dummy: log.error(u"Failed to send account creation notification to admin {}".format(admins_emails_txt))) 260 lambda dummy: log.error(u"Failed to send account creation notification to admin {}".format(admins_emails_txt)))
262 if not email: 261 if not email:
262 # TODO: if use register with an existing account, an XMPP message should be sent
263 return d_admin 263 return d_admin
264 264
265 jid_s = self.host.memory.getParamA("JabberID", "Connection", profile_key=profile) 265 jid_s = self.host.memory.getParamA(u"JabberID", u"Connection", profile_key=profile)
266 body = (_(u"""Welcome to Libervia, the web interface of Salut à Toi. 266 subject = _(u'Your Libervia account has been created')
267 267 body = (_(WELCOME_MSG).format(profile=profile, jid=jid_s, domain=domain))
268 Your account on {domain} has been successfully created. This is a demonstration version to show you the current status of the project. It is still under development, please keep it in mind!
269
270 Here is your connection information:
271
272 Login on {domain}: {profile}
273 Jabber ID (JID): {jid}
274 Your password has been chosen by yourself during registration.
275
276 In the beginning, you have nobody to talk to. To find some contacts, you may use the users' directory:
277 - make yourself visible in "Service / Directory subscription".
278 - search for people with "Contacts" / Search directory".
279
280 Any feedback welcome. Thank you!
281
282 Salut à Toi association
283 http://www.salut-a-toi.org
284 """).format(profile=profile, jid=jid_s, domain=domain)).encode('utf-8')
285 msg = MIMEText(body, 'plain', 'UTF-8')
286 msg['Subject'] = _(u'Libervia account created')
287 msg['From'] = email_from
288 msg['To'] = email
289
290 def email_ko(dummy):
291 # TODO: return error code to user
292 log.error(u"Failed to send account creation confirmation to <%s>" % email)
293 268
294 # XXX: this will not fail when the email address doesn't exist 269 # XXX: this will not fail when the email address doesn't exist
295 # FIXME: check email reception to validate email given by the user 270 # FIXME: check email reception to validate email given by the user
296 # FIXME: delete the profile if the email could not been sent? 271 # FIXME: delete the profile if the email could not been sent?
297 d_user = sendEmail([email], msg) 272 d_user = sat_email.sendEmail(self.host, [email], subject, body)
298 d_user.addCallbacks(lambda dummy: log.debug(u"Account creation confirmation sent to <%s>" % email), 273 d_user.addCallbacks(lambda dummy: log.debug(u"Account creation confirmation sent to <{}>".format(email)),
299 email_ko) 274 self._sendEmailEb)
300 return defer.DeferredList([d_user, d_admin]) 275 return defer.DeferredList([d_user, d_admin])
301 276
302 def getNewAccountDomain(self): 277 def getNewAccountDomain(self):
303 """@return: the domain that will be set to new account""" 278 """get the domain that will be set to new account"""
304 return self.getConfig('new_account_domain') 279
280 domain = self.getConfig('new_account_domain') or self.getConfig('xmpp_domain', None)
281 if not domain:
282 raise ValueError(_(u"xmpp_domain need to be set in sat.conf"))
283 return domain
305 284
306 def _getAccountDialogUI(self, profile): 285 def _getAccountDialogUI(self, profile):
307 """Get the main dialog to manage your account 286 """Get the main dialog to manage your account
308 @param menu_data 287 @param menu_data
309 @param profile: %(doc_profile)s 288 @param profile: %(doc_profile)s