Refactor MUC captcha challenge code

This commit is contained in:
Philipp Hörist 2018-12-19 11:01:09 +01:00
parent 1fec6681cd
commit e9f4c5050e
6 changed files with 82 additions and 75 deletions

View File

@ -1684,14 +1684,6 @@ class Connection(CommonConnection, ConnectionHandlers):
show=show, show=show,
caps=ptype != 'unavailable') caps=ptype != 'unavailable')
def send_captcha(self, jid, form_node):
if not app.account_is_connected(self.name):
return
iq = nbxmpp.Iq(typ='set', to=jid)
captcha = iq.addChild(name='captcha', namespace=nbxmpp.NS_CAPTCHA)
captcha.addChild(node=form_node)
self.connection.send(iq)
def check_unique_room_id_support(self, server, instance): def check_unique_room_id_support(self, server, instance):
if not app.account_is_connected(self.name): if not app.account_is_connected(self.name):
return return

View File

@ -416,30 +416,6 @@ class GcMessageReceivedEvent(nec.NetworkIncomingEvent):
from gajim.common.modules.security_labels import parse_securitylabel from gajim.common.modules.security_labels import parse_securitylabel
self.displaymarking = parse_securitylabel(self.stanza) self.displaymarking = parse_securitylabel(self.stanza)
self.captcha_form = None
captcha_tag = self.stanza.getTag('captcha', namespace=nbxmpp.NS_CAPTCHA)
if captcha_tag:
self.captcha_form = captcha_tag.getTag('x',
namespace=nbxmpp.NS_DATA)
for field in self.captcha_form.getTags('field'):
for media in field.getTags('media'):
for uri in media.getTags('uri'):
uri_data = uri.getData()
if uri_data.startswith('cid:'):
uri_data = uri_data[4:]
found = False
for data in self.stanza.getTags('data',
namespace=nbxmpp.NS_BOB):
if data.getAttr('cid') == uri_data:
uri.setData(data.getData())
found = True
if not found:
self.conn.get_module('BitsOfBinary').get_bob_data(
uri_data, self.fjid,
self.conn._dispatch_gc_msg_with_captcha,
[self.stanza, self.msg_obj], 0)
return
from gajim.common.modules.misc import parse_correction from gajim.common.modules.misc import parse_correction
self.correct_id = parse_correction(self.stanza) self.correct_id = parse_correction(self.stanza)

View File

@ -28,7 +28,6 @@ from gajim.common.helpers import AdditionalDataDict
from gajim.common.modules.security_labels import parse_securitylabel from gajim.common.modules.security_labels import parse_securitylabel
from gajim.common.modules.user_nickname import parse_nickname from gajim.common.modules.user_nickname import parse_nickname
from gajim.common.modules.carbons import parse_carbon from gajim.common.modules.carbons import parse_carbon
from gajim.common.modules.bits_of_binary import parse_bob_data
from gajim.common.modules.misc import parse_delay from gajim.common.modules.misc import parse_delay
from gajim.common.modules.misc import parse_eme from gajim.common.modules.misc import parse_eme
from gajim.common.modules.misc import parse_correction from gajim.common.modules.misc import parse_correction
@ -58,7 +57,8 @@ class Message:
nbxmpp.NS_MAM_1, nbxmpp.NS_MAM_1,
nbxmpp.NS_MAM_2, nbxmpp.NS_MAM_2,
nbxmpp.NS_CONFERENCE, nbxmpp.NS_CONFERENCE,
nbxmpp.NS_IBB]) nbxmpp.NS_IBB,
nbxmpp.NS_CAPTCHA,])
def _message_received(self, _con, stanza): def _message_received(self, _con, stanza):
# https://tools.ietf.org/html/rfc6120#section-8.1.1.1 # https://tools.ietf.org/html/rfc6120#section-8.1.1.1
@ -259,8 +259,6 @@ class Message:
event.additional_data.set_value( event.additional_data.set_value(
'gajim', 'user_timestamp', user_timestamp) 'gajim', 'user_timestamp', user_timestamp)
parse_bob_data(event.stanza)
event_attr = { event_attr = {
'popup': False, 'popup': False,
'msg_log_id': None, 'msg_log_id': None,

View File

@ -22,12 +22,13 @@ import weakref
import nbxmpp import nbxmpp
from gajim.common import i18n from gajim.common import i18n
from gajim.common.modules import dataforms
from gajim.common import app from gajim.common import app
from gajim.common import helpers from gajim.common import helpers
from gajim.common.caps_cache import muc_caps_cache from gajim.common.caps_cache import muc_caps_cache
from gajim.common.nec import NetworkEvent from gajim.common.nec import NetworkEvent
from gajim.common.nec import NetworkIncomingEvent from gajim.common.nec import NetworkIncomingEvent
from gajim.common.modules import dataforms
from gajim.common.modules.bits_of_binary import parse_bob_data
log = logging.getLogger('gajim.c.m.muc') log = logging.getLogger('gajim.c.m.muc')
@ -41,6 +42,7 @@ class MUC:
('message', self._on_config_change, '', nbxmpp.NS_MUC_USER), ('message', self._on_config_change, '', nbxmpp.NS_MUC_USER),
('message', self._mediated_invite, '', nbxmpp.NS_MUC_USER), ('message', self._mediated_invite, '', nbxmpp.NS_MUC_USER),
('message', self._direct_invite, '', nbxmpp.NS_CONFERENCE), ('message', self._direct_invite, '', nbxmpp.NS_CONFERENCE),
('message', self._on_captcha_challenge, '', nbxmpp.NS_CAPTCHA),
] ]
def pass_disco(self, from_, identities, features, _data, _node): def pass_disco(self, from_, identities, features, _data, _node):
@ -112,6 +114,35 @@ class MUC:
log.info('Set subject for %s', room_jid) log.info('Set subject for %s', room_jid)
self._con.connection.send(message) self._con.connection.send(message)
def _on_captcha_challenge(self, _con, stanza):
captcha = stanza.getTag('captcha', namespace=nbxmpp.NS_CAPTCHA)
if captcha is None:
return
parse_bob_data(stanza)
room_jid = str(stanza.getFrom())
contact = app.contacts.get_groupchat_contact(self._account, room_jid)
if contact is None:
return
log.info('Captcha challenge received from %s', room_jid)
data_form = captcha.getTag('x', namespace=nbxmpp.NS_DATA)
data_form = dataforms.extend_form(node=data_form)
app.nec.push_incoming_event(
NetworkEvent('captcha-challenge',
account=self._account,
room_jid=room_jid,
form=data_form))
raise nbxmpp.NodeProcessed
def send_captcha(self, room_jid, form_node):
if not app.account_is_connected(self._account):
return
iq = nbxmpp.Iq(typ='set', to=room_jid)
captcha = iq.addChild(name='captcha', namespace=nbxmpp.NS_CAPTCHA)
captcha.addChild(node=form_node)
self._con.connection.send(iq)
def request_config(self, room_jid): def request_config(self, room_jid):
if not app.account_is_connected(self._account): if not app.account_is_connected(self._account):
return return

View File

@ -44,7 +44,6 @@ from gajim import gtkgui_helpers
from gajim import gui_menu_builder from gajim import gui_menu_builder
from gajim import message_control from gajim import message_control
from gajim import vcard from gajim import vcard
from gajim import dataforms_widget
from gajim.common.const import AvatarSize from gajim.common.const import AvatarSize
from gajim.common.caps_cache import muc_caps_cache from gajim.common.caps_cache import muc_caps_cache
@ -53,7 +52,6 @@ from gajim.common import app
from gajim.common import helpers from gajim.common import helpers
from gajim.common.helpers import launch_browser_mailer from gajim.common.helpers import launch_browser_mailer
from gajim.common.helpers import AdditionalDataDict from gajim.common.helpers import AdditionalDataDict
from gajim.common.modules import dataforms
from gajim.common import ged from gajim.common import ged
from gajim.common import i18n from gajim.common import i18n
from gajim.common.i18n import _ from gajim.common.i18n import _
@ -77,6 +75,7 @@ from gajim.gtk.add_contact import AddNewContactWindow
from gajim.gtk.tooltips import GCTooltip from gajim.gtk.tooltips import GCTooltip
from gajim.gtk.groupchat_config import GroupchatConfig from gajim.gtk.groupchat_config import GroupchatConfig
from gajim.gtk.adhoc_commands import CommandWindow from gajim.gtk.adhoc_commands import CommandWindow
from gajim.gtk.dataform import DataFormWidget
from gajim.gtk.util import NickCompletionGenerator from gajim.gtk.util import NickCompletionGenerator
from gajim.gtk.util import get_icon_name from gajim.gtk.util import get_icon_name
from gajim.gtk.util import get_affiliation_surface from gajim.gtk.util import get_affiliation_surface
@ -330,6 +329,8 @@ class GroupchatControl(ChatControlBase):
self._nec_decrypted_message_received) self._nec_decrypted_message_received)
app.ged.register_event_handler('gc-stanza-message-outgoing', ged.OUT_POSTCORE, app.ged.register_event_handler('gc-stanza-message-outgoing', ged.OUT_POSTCORE,
self._message_sent) self._message_sent)
app.ged.register_event_handler('captcha-challenge', ged.GUI1,
self._on_captcha_challenge)
self.is_connected = False self.is_connected = False
# disable win, we are not connected yet # disable win, we are not connected yet
ChatControlBase.got_disconnected(self) ChatControlBase.got_disconnected(self)
@ -1073,6 +1074,48 @@ class GroupchatControl(ChatControlBase):
return return
self._update_banner_state_image() self._update_banner_state_image()
def _on_captcha_challenge(self, event):
if event.account != self.account:
return
if event.room_jid != self.room_jid:
return
if self.form_widget:
self.form_widget.hide()
self.form_widget.destroy()
self.btn_box.destroy()
self.form_widget = DataFormWidget(event.form)
def on_send_dataform_clicked(widget):
if not self.form_widget:
return
form_node = self.form_widget.get_submit_form()
con = app.connections[self.account]
con.get_module('MUC').send_captcha(self.room_jid, form_node)
self.form_widget.hide()
self.form_widget.destroy()
self.btn_box.destroy()
self.form_widget = None
del self.btn_box
# self.form_widget.connect('validated', on_send_dataform_clicked)
self.form_widget.show_all()
vbox = self.xml.get_object('gc_textviews_vbox')
vbox.pack_start(self.form_widget, False, True, 0)
valid_button = Gtk.Button(stock=Gtk.STOCK_OK)
valid_button.connect('clicked', on_send_dataform_clicked)
self.btn_box = Gtk.HButtonBox()
self.btn_box.set_layout(Gtk.ButtonBoxStyle.END)
self.btn_box.pack_start(valid_button, True, True, 0)
self.btn_box.show_all()
vbox.pack_start(self.btn_box, False, False, 0)
if self.parent_win:
self.parent_win.redraw_tab(self, 'attention')
else:
self.attention_flag = True
def _nec_mam_decrypted_message_received(self, obj): def _nec_mam_decrypted_message_received(self, obj):
if obj.conn.name != self.account: if obj.conn.name != self.account:
return return
@ -1090,42 +1133,7 @@ class GroupchatControl(ChatControlBase):
def _nec_gc_message_received(self, obj): def _nec_gc_message_received(self, obj):
if obj.room_jid != self.room_jid or obj.conn.name != self.account: if obj.room_jid != self.room_jid or obj.conn.name != self.account:
return return
if obj.captcha_form:
if self.form_widget:
self.form_widget.hide()
self.form_widget.destroy()
self.btn_box.destroy()
dataform = dataforms.extend_form(node=obj.captcha_form)
self.form_widget = dataforms_widget.DataFormWidget(dataform)
def on_send_dataform_clicked(widget):
if not self.form_widget:
return
form_node = self.form_widget.data_form.get_purged()
form_node.type_ = 'submit'
obj.conn.send_captcha(self.room_jid, form_node)
self.form_widget.hide()
self.form_widget.destroy()
self.btn_box.destroy()
self.form_widget = None
del self.btn_box
self.form_widget.connect('validated', on_send_dataform_clicked)
self.form_widget.show_all()
vbox = self.xml.get_object('gc_textviews_vbox')
vbox.pack_start(self.form_widget, False, True, 0)
valid_button = Gtk.Button(stock=Gtk.STOCK_OK)
valid_button.connect('clicked', on_send_dataform_clicked)
self.btn_box = Gtk.HButtonBox()
self.btn_box.set_layout(Gtk.ButtonBoxStyle.END)
self.btn_box.pack_start(valid_button, True, True, 0)
self.btn_box.show_all()
vbox.pack_start(self.btn_box, False, False, 0)
if self.parent_win:
self.parent_win.redraw_tab(self, 'attention')
else:
self.attention_flag = True
if not obj.nick: if not obj.nick:
# message from server # message from server
self.print_conversation( self.print_conversation(
@ -2169,6 +2177,8 @@ class GroupchatControl(ChatControlBase):
ged.GUI1, self._nec_mam_decrypted_message_received) ged.GUI1, self._nec_mam_decrypted_message_received)
app.ged.remove_event_handler('gc-stanza-message-outgoing', ged.OUT_POSTCORE, app.ged.remove_event_handler('gc-stanza-message-outgoing', ged.OUT_POSTCORE,
self._message_sent) self._message_sent)
app.ged.remove_event_handler('captcha-challenge', ged.GUI1,
self._on_captcha_challenge)
if self.is_connected: if self.is_connected:
app.connections[self.account].send_gc_status(self.nick, app.connections[self.account].send_gc_status(self.nick,

View File

@ -386,7 +386,7 @@ class GajimRemote(Server):
return return
self.raise_signal('GCMessage', (obj.conn.name, [obj.fjid, obj.msgtxt, self.raise_signal('GCMessage', (obj.conn.name, [obj.fjid, obj.msgtxt,
obj.timestamp, obj.delayed, obj.xhtml_msgtxt, obj.timestamp, obj.delayed, obj.xhtml_msgtxt,
obj.displaymarking, obj.captcha_form, obj.needs_highlight])) obj.displaymarking, obj.needs_highlight]))
def on_our_status(self, obj): def on_our_status(self, obj):
self.raise_signal('AccountPresence', (obj.show, obj.conn.name)) self.raise_signal('AccountPresence', (obj.show, obj.conn.name))