implements Oauth2 mechanism to connect to MSN xmpp server. Fixes #6978
This commit is contained in:
parent
a1e369dde4
commit
6e4bac262c
|
@ -384,6 +384,9 @@ class Config:
|
|||
'last_archiving_time': [opt_str, '1970-01-01T00:00:00Z', _('Last time we syncronized with logs from server.')],
|
||||
'enable_message_carbons': [ opt_bool, False, _('If enabled and if server supports this feature, Gajim will receive messages sent and received by other resources.')],
|
||||
'ft_send_local_ips': [ opt_bool, True, _('If enabled, Gajim will send your local IPs so your contact can connect to your machine to transfer files.')],
|
||||
'oauth2_refresh_token': [ opt_str, '', _('Latest token for Oauth2 authentication.')],
|
||||
'oauth2_client_id': [ opt_str, '0000000044077801', _('client_id for Oauth2 authentication.')],
|
||||
'oauth2_redirect_url': [ opt_str, 'http%3A%2F%2Fgajim.org%2Fmsnauth%2Findex.cgi', _('redirect_url for Oauth2 authentication.')],
|
||||
}, {}),
|
||||
'statusmsg': ({
|
||||
'message': [ opt_str, '' ],
|
||||
|
|
|
@ -40,6 +40,7 @@ import operator
|
|||
import time
|
||||
import locale
|
||||
import hmac
|
||||
import json
|
||||
|
||||
try:
|
||||
randomsource = random.SystemRandom()
|
||||
|
@ -2492,6 +2493,32 @@ class Connection(CommonConnection, ConnectionHandlers):
|
|||
|
||||
def get_password(self, callback, type_):
|
||||
self.pasword_callback = (callback, type_)
|
||||
if type_ == 'X-MESSENGER-OAUTH2':
|
||||
client_id = gajim.config.get_per('accounts', self.name,
|
||||
'oauth2_client_id')
|
||||
refresh_token = gajim.config.get_per('accounts', self.name,
|
||||
'oauth2_refresh_token')
|
||||
if refresh_token:
|
||||
renew_URL = 'https://oauth.live.com/token?client_id=' \
|
||||
'%(client_id)s&redirect_uri=https%%3A%%2F%%2Foauth.live.' \
|
||||
'com%%2Fdesktop&grant_type=refresh_token&refresh_token=' \
|
||||
'%(refresh_token)s' % locals()
|
||||
result = helpers.download_image(self.name, {'src': renew_URL})[0]
|
||||
if result:
|
||||
dict_ = json.loads(result)
|
||||
if 'access_token' in dict_:
|
||||
self.set_password(dict_['access_token'])
|
||||
return
|
||||
script_url = gajim.config.get_per('accounts', self.name,
|
||||
'oauth2_redirect_url')
|
||||
token_URL = 'https://oauth.live.com/authorize?client_id=' \
|
||||
'%(client_id)s&scope=wl.messenger%%20wl.offline_access&' \
|
||||
'response_type=code&redirect_uri=%(script_url)s' % locals()
|
||||
helpers.launch_browser_mailer('url', token_URL)
|
||||
self.disconnect(on_purpose=True)
|
||||
gajim.nec.push_incoming_event(Oauth2CredentialsRequiredEvent(None,
|
||||
conn=self))
|
||||
return
|
||||
if self.password:
|
||||
self.set_password(self.password)
|
||||
return
|
||||
|
|
|
@ -1783,6 +1783,10 @@ class PasswordRequiredEvent(nec.NetworkIncomingEvent):
|
|||
name = 'password-required'
|
||||
base_network_events = []
|
||||
|
||||
class Oauth2CredentialsRequiredEvent(nec.NetworkIncomingEvent):
|
||||
name = 'oauth2-credentials-required'
|
||||
base_network_events = []
|
||||
|
||||
class FailedDecryptEvent(nec.NetworkIncomingEvent):
|
||||
name = 'failed-decrypt'
|
||||
base_network_events = []
|
||||
|
|
|
@ -264,6 +264,12 @@ class SASL(PlugIn):
|
|||
self._owner._caller.get_password(self.set_password, self.mechanism)
|
||||
self.startsasl = SASL_IN_PROCESS
|
||||
raise NodeProcessed
|
||||
if 'X-MESSENGER-OAUTH2' in self.mecs:
|
||||
self.mecs.remove('X-MESSENGER-OAUTH2')
|
||||
self.mechanism = 'X-MESSENGER-OAUTH2'
|
||||
self._owner._caller.get_password(self.set_password, self.mechanism)
|
||||
self.startsasl = SASL_IN_PROCESS
|
||||
raise NodeProcessed
|
||||
self.startsasl = SASL_FAILURE
|
||||
log.info('I can only use EXTERNAL, SCRAM-SHA-1, DIGEST-MD5, GSSAPI and '
|
||||
'PLAIN mecanisms.')
|
||||
|
@ -497,6 +503,10 @@ class SASL(PlugIn):
|
|||
'\n', '')
|
||||
node = Node('auth', attrs={'xmlns': NS_SASL, 'mechanism': 'PLAIN'},
|
||||
payload=[sasl_data])
|
||||
elif self.mechanism == 'X-MESSENGER-OAUTH2':
|
||||
node = Node('auth', attrs={'xmlns': NS_SASL,
|
||||
'mechanism': 'X-MESSENGER-OAUTH2'})
|
||||
node.addData(password)
|
||||
self._owner.send(str(node))
|
||||
|
||||
|
||||
|
|
|
@ -2165,6 +2165,7 @@ class DoubleInputDialog:
|
|||
def on_okbutton_clicked(self, widget):
|
||||
user_input1 = self.input_entry1.get_text().decode('utf-8')
|
||||
user_input2 = self.input_entry2.get_text().decode('utf-8')
|
||||
self.cancel_handler = None
|
||||
self.dialog.destroy()
|
||||
if not self.ok_handler:
|
||||
return
|
||||
|
|
|
@ -63,7 +63,7 @@ if os.name == 'nt':
|
|||
os.environ['PATH'] = ';'.join(new_list)
|
||||
|
||||
from common import demandimport
|
||||
#demandimport.enable()
|
||||
demandimport.enable()
|
||||
demandimport.ignore += ['gobject._gobject', 'libasyncns', 'i18n',
|
||||
'logging.NullHandler', 'dbus.glib', 'dbus.service',
|
||||
'command_system.implementation.standard',
|
||||
|
|
|
@ -701,6 +701,30 @@ class Interface:
|
|||
_('Password Required'), text, _('Save password'), ok_handler=on_ok,
|
||||
cancel_handler=on_cancel)
|
||||
|
||||
def handle_oauth2_credentials(self, obj):
|
||||
account = obj.conn.name
|
||||
def on_ok(refresh):
|
||||
gajim.config.set_per('accounts', account, 'oauth2_refresh_token',
|
||||
refresh)
|
||||
st = gajim.config.get_per('accounts', account, 'last_status')
|
||||
msg = helpers.from_one_line(gajim.config.get_per('accounts',
|
||||
account, 'last_status_msg'))
|
||||
gajim.interface.roster.send_status(account, st, msg)
|
||||
del self.pass_dialog[account]
|
||||
|
||||
def on_cancel():
|
||||
gajim.config.set_per('accounts', account, 'oauth2_refresh_token',
|
||||
'')
|
||||
self.roster.set_state(account, 'offline')
|
||||
self.roster.update_status_combobox()
|
||||
del self.pass_dialog[account]
|
||||
|
||||
instruction = _('Please copy / paste the refresh token from the website'
|
||||
' that has just been opened.')
|
||||
self.pass_dialog[account] = dialogs.InputTextDialog(
|
||||
_('Oauth2 Credentials'), instruction, is_modal=False,
|
||||
ok_handler=on_ok, cancel_handler=on_cancel)
|
||||
|
||||
def handle_event_roster_info(self, obj):
|
||||
#('ROSTER_INFO', account, (jid, name, sub, ask, groups))
|
||||
account = obj.conn.name
|
||||
|
@ -1412,6 +1436,7 @@ class Interface:
|
|||
'metacontacts-received': [self.handle_event_metacontacts],
|
||||
'muc-admin-received': [self.handle_event_gc_affiliation],
|
||||
'muc-owner-received': [self.handle_event_gc_config],
|
||||
'oauth2-credentials-required': [self.handle_oauth2_credentials],
|
||||
'our-show': [self.handle_event_status],
|
||||
'password-required': [self.handle_event_password_required],
|
||||
'plain-connection': [self.handle_event_plain_connection],
|
||||
|
|
Loading…
Reference in New Issue