plugin misc_account: add method asyncConnectWithXMPPCredentials
This commit is contained in:
parent
3fa1ea0376
commit
04bb8beaae
1 changed files with 79 additions and 29 deletions
|
|
@ -33,6 +33,9 @@ from twisted.mail.smtp import sendmail
|
|||
from os.path import join, dirname
|
||||
from email.mime.text import MIMEText
|
||||
|
||||
import random
|
||||
|
||||
|
||||
PLUGIN_INFO = {
|
||||
"name": "Account Plugin",
|
||||
"import_name": "MISC-ACCOUNT",
|
||||
|
|
@ -56,7 +59,6 @@ default_conf = {"email_from": "NOREPLY@example.net",
|
|||
"admin_email": "admin@example.net",
|
||||
"new_account_server": "localhost",
|
||||
"new_account_domain": "example.net",
|
||||
"new_account_resource": "libervia",
|
||||
"prosody_path": None, # prosody path (where prosodyctl will be executed from), or None to automaticaly find it
|
||||
"prosodyctl": "prosodyctl",
|
||||
"reserved_list": ['libervia'] # profiles which can't be used
|
||||
|
|
@ -102,6 +104,7 @@ class ProsodyRegisterProtocol(protocol.ProcessProtocol):
|
|||
@classmethod
|
||||
def prosodyctl(cls, plugin, command, password=None, profile=None):
|
||||
"""Create a new ProsodyRegisterProtocol and execute the given prosodyctl command.
|
||||
|
||||
@param plugin: instance of MiscAccount
|
||||
@param command: the command to execute: "adduser", "passwd" or "deluser"
|
||||
@param password: the user new password (leave to None for "deluser" command)
|
||||
|
|
@ -127,6 +130,7 @@ class MiscAccount(object):
|
|||
host.bridge.addMethod("registerSatAccount", ".plugin", in_sign='sss', out_sign='', method=self._registerAccount, async=True)
|
||||
host.bridge.addMethod("getNewAccountDomain", ".plugin", in_sign='', out_sign='s', method=self.getNewAccountDomain, async=False)
|
||||
host.bridge.addMethod("getAccountDialogUI", ".plugin", in_sign='s', out_sign='s', method=self._getAccountDialogUI, async=False)
|
||||
host.bridge.addMethod("asyncConnectWithXMPPCredentials", ".plugin", in_sign='ss', out_sign='b', method=self.asyncConnectWithXMPPCredentials, async=True)
|
||||
self._prosody_path = self.getConfig('prosody_path')
|
||||
if self._prosody_path is None:
|
||||
paths = which(self.getConfig('prosodyctl'))
|
||||
|
|
@ -153,46 +157,64 @@ class MiscAccount(object):
|
|||
def getConfig(self, name):
|
||||
return self.host.memory.getConfig(CONFIG_SECTION, name, default_conf[name])
|
||||
|
||||
def _registerAccount(self, email, password, profile):
|
||||
|
||||
def generatePassword(self):
|
||||
"""Generate a password with random characters.
|
||||
|
||||
@return unicode
|
||||
"""
|
||||
#Password Generation
|
||||
#_charset = [chr(i) for i in range(0x21,0x7F)] #XXX: this charset seems to have some issues with openfire
|
||||
_charset = [chr(i) for i in range(0x30,0x3A) + range(0x41,0x5B) + range (0x61,0x7B)]
|
||||
import random
|
||||
random.seed()
|
||||
password = ''.join([random.choice(_charset) for i in range(15)])
|
||||
#charset = [chr(i) for i in range(0x21,0x7F)] #XXX: this charset seems to have some issues with openfire
|
||||
charset = [chr(i) for i in range(0x30,0x3A) + range(0x41,0x5B) + range (0x61,0x7B)]
|
||||
return ''.join([random.choice(charset) for i in range(15)])
|
||||
|
||||
def _registerAccount(self, email, password, profile):
|
||||
return self.registerAccount(email, password, None, profile)
|
||||
|
||||
def registerAccount(self, email, password, jid_s, profile):
|
||||
"""Register a new profile and its associated XMPP account.
|
||||
|
||||
@param email (unicode): where to send to confirmation email to
|
||||
@param password (unicode): password chosen by the user
|
||||
@param jid_s (unicode): JID to re-use or to register:
|
||||
- non empty value: bind this JID to the new sat profile
|
||||
- None or "": register a new JID on the local XMPP server
|
||||
@param profile
|
||||
@return Deferred
|
||||
"""
|
||||
if not email or not password or not profile:
|
||||
if not password or not profile:
|
||||
raise exceptions.DataError
|
||||
|
||||
if profile.lower() in self.getConfig('reserved_list'):
|
||||
return defer.fail(Failure(exceptions.ConflictError))
|
||||
|
||||
d = self.host.memory.asyncCreateProfile(profile, password)
|
||||
d.addCallback(self._profileRegistered, email, password, profile)
|
||||
d.addCallback(lambda dummy: self.profileRegistered(email, password, jid_s, profile))
|
||||
return d
|
||||
|
||||
def _profileRegistered(self, result, email, password, profile):
|
||||
"""Create the XMPP account and send the confirmation email.
|
||||
def profileRegistered(self, email, password, jid_s, profile):
|
||||
"""Create the XMPP account, set the profile connection parameters and send the confirmation email.
|
||||
|
||||
@param result: result of asyncCreateProfile
|
||||
@param email: user email
|
||||
@param password: chosen xmpp password
|
||||
@param profile: %(doc_profile)s
|
||||
@return: a deferred None value when all the processing is done
|
||||
@param email (unicode): where to send to confirmation email to
|
||||
@param password (unicode): password chosen by the user
|
||||
@param jid_s (unicode): JID to re-use or to register:
|
||||
- non empty value: bind this JID to the new sat profile
|
||||
- None or empty: register a new JID on the local XMPP server
|
||||
@param profile
|
||||
@return: Deferred
|
||||
"""
|
||||
# XXX: we use "prosodyctl adduser" because "register" doesn't check conflict
|
||||
# and just change the password if the account already exists
|
||||
d = ProsodyRegisterProtocol.prosodyctl(self, 'adduser', password, profile)
|
||||
d.addCallback(self._sendEmails, profile, email, password)
|
||||
d.addCallback(lambda ignore: None)
|
||||
# XXX: we use "prosodyctl adduser" because "register" doesn't check conflict and just change the password if the account already exists
|
||||
if jid_s:
|
||||
d = defer.succeed(None)
|
||||
else:
|
||||
d = ProsodyRegisterProtocol.prosodyctl(self, 'adduser', password, profile)
|
||||
jid_s = "%s@%s" % (profile, self.getConfig('new_account_domain'))
|
||||
if email:
|
||||
d.addCallback(lambda dummy: self.sendEmails(email, jid_s, password, profile))
|
||||
|
||||
def setParams(dummy):
|
||||
jid_s = "%s@%s/%s" % (profile, self.getConfig('new_account_domain'), self.getConfig('new_account_resource'))
|
||||
self.host.memory.setParam("JabberID", jid_s, "Connection", profile_key=profile)
|
||||
d = self.host.memory.setParam("Password", password, "Connection", profile_key=profile)
|
||||
d.addCallback(lambda dummy: self.host.memory.auth_sessions.profileDelUnique(profile))
|
||||
return d.addCallback(lambda dummy: self.host.memory.auth_sessions.profileDelUnique(profile))
|
||||
|
||||
def removeProfile(failure):
|
||||
self.host.memory.asyncDeleteProfile(profile)
|
||||
|
|
@ -202,13 +224,14 @@ class MiscAccount(object):
|
|||
d.addErrback(removeProfile)
|
||||
return d
|
||||
|
||||
def _sendEmails(self, result, login, email, password):
|
||||
def sendEmails(self, email, jid_s, password, profile):
|
||||
# time to send the email
|
||||
|
||||
_email_host = self.getConfig('email_server')
|
||||
_email_from = self.getConfig("email_from")
|
||||
domain = self.getConfig('new_account_domain')
|
||||
|
||||
|
||||
def email_ok(ignore):
|
||||
log.debug(u"Account creation email sent to %s" % email)
|
||||
|
||||
|
|
@ -222,8 +245,8 @@ Your account on %(domain)s has been successfully created. This is a demonstratio
|
|||
|
||||
Here is your connection information:
|
||||
|
||||
Login on libervia.org: %(login)s
|
||||
Jabber ID (JID): %(login)s@%(domain)s
|
||||
Login on libervia.org: %(profile)s
|
||||
Jabber ID (JID): %(jid_s)s
|
||||
|
||||
Your password has been chosen by yourself. If you haven't read our security notice regarding the connection to https://libervia.org, please do it now:
|
||||
|
||||
|
|
@ -237,7 +260,7 @@ Any feedback welcome. Thank you!
|
|||
|
||||
Salut à Toi association
|
||||
http://www.salut-a-toi.org
|
||||
""") % {'login': login, 'domain': domain}).encode('utf-8')
|
||||
""") % {'profile': profile, 'jid_s': jid_s, 'domain': domain}).encode('utf-8')
|
||||
msg = MIMEText(body, 'plain', 'UTF-8')
|
||||
msg['Subject'] = _(u'Libervia account created')
|
||||
msg['From'] = _email_from
|
||||
|
|
@ -247,7 +270,7 @@ http://www.salut-a-toi.org
|
|||
d_user.addCallbacks(email_ok, email_ko)
|
||||
|
||||
# email to the administrator
|
||||
body = (u"""New account created: %(login)s [%(email)s]""" % {'login': login, 'email': email}).encode('utf-8')
|
||||
body = (u"""New account created: %(profile)s [%(email)s]""" % {'profile': profile, 'email': email}).encode('utf-8')
|
||||
msg = MIMEText(body, 'plain', 'UTF-8')
|
||||
msg['Subject'] = _('New Libervia account created')
|
||||
msg['From'] = _email_from
|
||||
|
|
@ -484,3 +507,30 @@ http://www.salut-a-toi.org
|
|||
d.addCallbacks(deleted, errback)
|
||||
return d
|
||||
|
||||
def asyncConnectWithXMPPCredentials(self, jid_s, password):
|
||||
"""Create and connect a new SàT profile using the given XMPP credentials.
|
||||
|
||||
Re-use given JID and XMPP password for the profile name and profile password.
|
||||
@param jid_s (unicode): JID
|
||||
@param password (unicode): XMPP password
|
||||
@return Deferred(bool)
|
||||
@raise exceptions.PasswordError, exceptions.ConflictError
|
||||
"""
|
||||
try: # be sure that the profile doesn't exist yet
|
||||
self.host.memory.getProfileName(jid_s)
|
||||
except exceptions.ProfileUnknownError:
|
||||
pass
|
||||
else:
|
||||
raise exceptions.ConflictError
|
||||
|
||||
d = self.registerAccount(None, password, jid_s, jid_s)
|
||||
d.addCallback(lambda dummy: self.host.memory.getProfileName(jid_s)) # checks if the profile has been successfuly created
|
||||
d.addCallback(self.host.asyncConnect, password)
|
||||
|
||||
def removeProfile(failure): # profile has been successfully created but the XMPP credentials are wrong!
|
||||
log.debug("Removing previously auto-created profile: %s" % failure.getErrorMessage())
|
||||
self.host.memory.asyncDeleteProfile(jid_s)
|
||||
raise failure
|
||||
|
||||
d.addErrback(removeProfile)
|
||||
return d
|
||||
|
|
|
|||
Loading…
Reference in a new issue