plugin account: removed dependency to Prosody/prosodyctl and properly use in-band registration instead
This commit is contained in:
parent
1c64f98989
commit
06be5a58aa
2 changed files with 23 additions and 80 deletions
|
|
@ -439,7 +439,7 @@ class SAT(service.Service):
|
|||
@return: client or None if it doesn't exist
|
||||
@raise exceptions.ProfileKeyUnknown: the profile or profile key doesn't exist
|
||||
@raise exceptions.NotFound: client is not available
|
||||
This happen if profile has not been use yet
|
||||
This happen if profile has not been used yet
|
||||
"""
|
||||
profile = self.memory.getProfileName(profile_key)
|
||||
if not profile:
|
||||
|
|
|
|||
|
|
@ -26,22 +26,24 @@ from sat.memory.memory import Sessions
|
|||
from sat.memory.crypto import PasswordHasher
|
||||
from sat.core.constants import Const as C
|
||||
import ConfigParser
|
||||
from twisted.internet import reactor, defer, protocol
|
||||
from twisted.python.procutils import which
|
||||
from twisted.internet import defer
|
||||
from twisted.python.failure import Failure
|
||||
from twisted.words.protocols.jabber import jid
|
||||
from twisted.mail.smtp import sendmail
|
||||
from os.path import join, dirname
|
||||
from email.mime.text import MIMEText
|
||||
|
||||
import random
|
||||
|
||||
# FIXME: this plugin code is old and need a cleaning
|
||||
# TODO: account deletion/password change need testing
|
||||
|
||||
|
||||
PLUGIN_INFO = {
|
||||
C.PI_NAME: "Account Plugin",
|
||||
C.PI_IMPORT_NAME: "MISC-ACCOUNT",
|
||||
C.PI_TYPE: "MISC",
|
||||
C.PI_PROTOCOLS: [],
|
||||
C.PI_DEPENDENCIES: [],
|
||||
C.PI_DEPENDENCIES: ["XEP-0077"],
|
||||
C.PI_RECOMMENDATIONS: ['GROUPBLOG'],
|
||||
C.PI_MAIN: "MiscAccount",
|
||||
C.PI_HANDLER: "no",
|
||||
|
|
@ -66,70 +68,15 @@ default_conf = {"email_from": "NOREPLY@example.net",
|
|||
"admin_email": "",
|
||||
"new_account_server": "localhost",
|
||||
"new_account_domain": "example.net",
|
||||
"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
|
||||
}
|
||||
|
||||
|
||||
class PasswordsMatchingError(Exception):
|
||||
pass
|
||||
|
||||
|
||||
class ProsodyRegisterProtocol(protocol.ProcessProtocol):
|
||||
""" Try to register an account with prosody """
|
||||
|
||||
def __init__(self, password=None, deferred=None):
|
||||
"""
|
||||
@param password: new user password
|
||||
@param deferred
|
||||
"""
|
||||
self.password = password
|
||||
self.deferred = deferred
|
||||
self.data = ''
|
||||
|
||||
def connectionMade(self):
|
||||
if self.password is None:
|
||||
return
|
||||
self.transport.write("%s\n%s" % ((self.password.encode('utf-8'),) * 2))
|
||||
self.transport.closeStdin()
|
||||
|
||||
def outReceived(self, data):
|
||||
self.data += data
|
||||
|
||||
def errReceived(self, data):
|
||||
self.data += data
|
||||
|
||||
def processEnded(self, reason):
|
||||
if (reason.value.exitCode == 0):
|
||||
log.info(_('Prosody command succeed'))
|
||||
self.deferred.callback(None)
|
||||
else:
|
||||
log.error(_(u"Can't complete Prosody command (error code: %(code)d): %(message)s") % {'code': reason.value.exitCode, 'message': self.data})
|
||||
self.deferred.errback(Failure(exceptions.InternalError))
|
||||
|
||||
@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)
|
||||
@param profile: the user profile
|
||||
@return: a Deferred instance
|
||||
"""
|
||||
d = defer.Deferred()
|
||||
prosody_reg = ProsodyRegisterProtocol(password, d)
|
||||
prosody_exe = join(plugin._prosody_path, plugin.getConfig('prosodyctl'))
|
||||
# TODO delete account which are not on the same host
|
||||
reactor.spawnProcess(prosody_reg, prosody_exe, [prosody_exe, command, "%s@%s" % (profile, plugin.getConfig('new_account_domain'))], path=plugin._prosody_path)
|
||||
return d
|
||||
|
||||
|
||||
class MiscAccount(object):
|
||||
"""Account plugin: create a SàT + Prosody account, used by Libervia"""
|
||||
#XXX: This plugin is a Q&D one used for the demo. Something more generic (and not
|
||||
# only focused on Prosody) is planed
|
||||
"""Account plugin: create a SàT + XMPP account, used by Libervia"""
|
||||
# XXX: This plugin was initialy a Q&D one used for the demo.
|
||||
# TODO: cleaning, separate email handling, more configuration/tests, fixes
|
||||
|
||||
|
||||
def __init__(self, host):
|
||||
log.info(_(u"Plugin Account initialization"))
|
||||
|
|
@ -138,14 +85,6 @@ class MiscAccount(object):
|
|||
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'))
|
||||
if not paths:
|
||||
log.error(_(u"Can't find %s") % (self.getConfig('prosodyctl'),))
|
||||
else:
|
||||
self._prosody_path = dirname(paths[0])
|
||||
log.info(_(u'Prosody path found: %s') % (self._prosody_path,))
|
||||
|
||||
self.fixEmailAdmins()
|
||||
self._sessions = Sessions()
|
||||
|
|
@ -256,12 +195,13 @@ class MiscAccount(object):
|
|||
@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
|
||||
if jid_s:
|
||||
d = defer.succeed(None)
|
||||
jid_ = jid.JID(jid_s)
|
||||
else:
|
||||
d = ProsodyRegisterProtocol.prosodyctl(self, 'adduser', password, profile)
|
||||
jid_s = "%s@%s" % (profile, self.getConfig('new_account_domain'))
|
||||
jid_s = profile + u"@" + self.getConfig('new_account_domain')
|
||||
jid_ = jid.JID(jid_s)
|
||||
d = self.host.plugins['XEP-0077'].registerNewAccount(jid_, password)
|
||||
|
||||
def setParams(dummy):
|
||||
self.host.memory.setParam("JabberID", jid_s, "Connection", profile_key=profile)
|
||||
|
|
@ -481,10 +421,11 @@ http://www.salut-a-toi.org
|
|||
@param data (dict)
|
||||
@profile (str): %(doc_profile)s
|
||||
"""
|
||||
client = self.host.getClient(profile)
|
||||
password = self._sessions.profileGet(data['session_id'], profile)['new_password']
|
||||
del self._sessions[data['session_id']]
|
||||
|
||||
def passwordChanged(result):
|
||||
def passwordChanged(dummy):
|
||||
d = self.host.memory.setParam(C.PROFILE_PASS_PATH[1], password, C.PROFILE_PASS_PATH[0], profile_key=profile)
|
||||
d.addCallback(lambda dummy: self.host.memory.setParam("Password", password, "Connection", profile_key=profile))
|
||||
confirm_ui = xml_tools.XMLUI("popup", title=D_("Confirmation"))
|
||||
|
|
@ -496,7 +437,7 @@ http://www.salut-a-toi.org
|
|||
error_ui.addText(D_("Your password could not be changed: %s") % failure.getErrorMessage())
|
||||
return defer.succeed({'xmlui': error_ui.toXml()})
|
||||
|
||||
d = ProsodyRegisterProtocol.prosodyctl(self, 'passwd', password, profile=profile)
|
||||
d = self.host.plugins['XEP-0077'].changePassword(client, password)
|
||||
d.addCallbacks(passwordChanged, errback)
|
||||
return d
|
||||
|
||||
|
|
@ -513,12 +454,14 @@ http://www.salut-a-toi.org
|
|||
|
||||
def __deleteAccountCb(self, data, profile):
|
||||
"""Actually delete the XMPP account and SàT profile
|
||||
|
||||
@param data
|
||||
@param profile
|
||||
"""
|
||||
def userDeleted(result):
|
||||
client = self.host.profiles[profile]
|
||||
client = self.host.getClient(profile)
|
||||
def userDeleted(dummy):
|
||||
|
||||
# FIXME: client should be disconnected at this point, so 2 next loop should be removed (to be confirmed)
|
||||
for jid_ in client.roster._jids: # empty roster
|
||||
client.presence.unsubscribe(jid_)
|
||||
|
||||
|
|
@ -539,7 +482,7 @@ http://www.salut-a-toi.org
|
|||
error_ui.addText(D_("Your XMPP account could not be deleted: %s") % failure.getErrorMessage())
|
||||
return defer.succeed({'xmlui': error_ui.toXml()})
|
||||
|
||||
d = ProsodyRegisterProtocol.prosodyctl(self, 'deluser', profile=profile)
|
||||
d = self.host.plugins['XEP-0077'].removeRegistration(client, jid.JID(client.jid.host))
|
||||
d.addCallbacks(userDeleted, errback)
|
||||
return d
|
||||
|
||||
|
|
|
|||
Loading…
Reference in a new issue