Daniel Brötzmann pushed to branch newcontrol at gajim / gajim
Commits: c671abf2 by wurstsalat at 2022-07-15T18:32:47+02:00 Add captcha and password widgets
- - - - -
5 changed files:
- gajim/common/const.py - gajim/common/modules/muc.py - gajim/common/structs.py - gajim/gtk/chat_function_page.py - gajim/gtk/chat_stack.py
Changes:
===================================== gajim/common/const.py ===================================== @@ -246,6 +246,7 @@ class MUCJoinedState(Enum): CREATING = 'creating' CAPTCHA_REQUEST = 'captcha in progress' CAPTCHA_FAILED = 'captcha failed' + PASSWORD_REQUEST = 'password required'
def __str__(self): return self.name @@ -274,6 +275,10 @@ def is_captcha_request(self): def is_captcha_failed(self): return self == MUCJoinedState.CAPTCHA_FAILED
+ @property + def is_password_request(self): + return self == MUCJoinedState.PASSWORD_REQUEST +
class ClientState(IntEnum): DISCONNECTING = 0
===================================== gajim/common/modules/muc.py ===================================== @@ -815,8 +815,11 @@ def _on_captcha_challenge(self, return
self._log.info('Captcha challenge received from %s', properties.jid) + + assert properties.captcha is not None store_bob_data(properties.captcha.bob_data) muc_data.captcha_id = properties.id + muc_data.captcha_form = properties.captcha.form
self._set_muc_state(properties.jid, MUCJoinedState.CAPTCHA_REQUEST) self._remove_rejoin_timeout(properties.jid)
===================================== gajim/common/structs.py ===================================== @@ -31,8 +31,10 @@ from nbxmpp.const import Chatstate from nbxmpp.const import PresenceShow from nbxmpp.const import Role +from nbxmpp.modules.dataforms import SimpleDataForm from nbxmpp.modules.security_labels import SecurityLabel from nbxmpp.protocol import JID +from nbxmpp.structs import MucSubject from nbxmpp.structs import PresenceProperties
from gajim.common import types @@ -56,7 +58,7 @@ class MUCData: def __init__(self, room_jid: str, nick: str, - password: str, + password: Optional[str], config: Optional[dict[str, Any]] = None ) -> None:
@@ -66,8 +68,9 @@ def __init__(self, self.password = password self.state = MUCJoinedState.NOT_JOINED # Message id of the captcha challenge - self.captcha_id = None - self.subject = None + self.captcha_id: Optional[str] = None + self.captcha_form: Optional[SimpleDataForm] = None + self.subject: Optional[MucSubject] = None
@property def jid(self) -> JID:
===================================== gajim/gtk/chat_function_page.py ===================================== @@ -31,6 +31,7 @@ from gajim.common.modules.contacts import GroupchatContact from gajim.common.types import ChatContactT
+from .dataform import DataFormWidget from .groupchat_inviter import GroupChatInviter
@@ -138,10 +139,32 @@ def set_mode(self, 'destructive-action') self._widget = InputWidget(self._contact, mode, data)
+ elif mode == 'password-request': + self._confirm_button.set_label(_('Join')) + self._confirm_button.get_style_context().add_class( + 'suggested-action') + self._widget = InputWidget(self._contact, mode) + + elif mode == 'captcha-request': + self._confirm_button.set_label(_('Join')) + self._confirm_button.get_style_context().add_class( + 'suggested-action') + muc_data = self._client.get_module('MUC').get_muc_data( + self._contact.jid) + form = muc_data.captcha_form + options = {'no-scrolling': True, + 'entry-activates-default': True} + self._widget = DataFormWidget(form, options=options) + self._widget.set_valign(Gtk.Align.START) + self._widget.show_all() + self._widget.connect('is-valid', self._on_ready) + assert self._widget is not None self._content_box.add(self._widget) if isinstance(self._widget, InputWidget): self._widget.focus() + elif isinstance(self._widget, DataFormWidget): + self._widget.focus_first_entry()
def _on_ready(self, _widget: Gtk.Widget, @@ -181,9 +204,32 @@ def _on_confirm_clicked(self, _button: Gtk.Button) -> None: self._contact.jid, {self._data: {'affiliation': 'outcast', 'reason': reason}})
+ elif self._mode == 'password-request': + assert isinstance(self._widget, InputWidget) + password = self._widget.get_text() + assert self._client is not None + assert self._contact is not None + self._client.get_module('MUC').set_password( + self._contact.jid, password) + self._client.get_module('MUC').join(self._contact.jid) + + elif self._mode == 'captcha-request': + assert isinstance(self._widget, DataFormWidget) + form_node = self._widget.get_submit_form() + assert self._client is not None + assert self._contact is not None + self._client.get_module('MUC').send_captcha( + self._contact.jid, form_node) + self.emit('finish')
def _on_cancel_clicked(self, _button: Gtk.Button) -> None: + if self._mode == 'captcha-request': + assert self._client is not None + assert self._contact is not None + self._client.get_module('MUC').cancel_captcha( + self._contact.jid) + self.emit('finish')
def _invite(self, invited_jid: JID) -> None: @@ -236,12 +282,20 @@ def __init__(self, sub_label.set_text(_('Enter your new nickname')) assert isinstance(self._contact, GroupchatContact) self._entry.set_text(self._contact.nickname or '') + elif mode == 'kick': heading_label.set_text(_('Kick %s') % data) sub_label.set_text(_('Reason (optional)')) + elif mode == 'ban': heading_label.set_text(_('Ban %s') % data) sub_label.set_text(_('Reason (optional)')) + + elif mode == 'password-request': + heading_label.set_text(_('Password Required')) + sub_label.set_text(_('Enter a password to join this chat')) + self._entry.set_input_purpose(Gtk.InputPurpose.PASSWORD) + self.connect('destroy', self._on_destroy) self.show_all()
===================================== gajim/gtk/chat_stack.py ===================================== @@ -27,7 +27,8 @@ from nbxmpp.protocol import JID from nbxmpp.structs import PresenceProperties
-from gajim.common import app, helpers +from gajim.common import app +from gajim.common import helpers from gajim.common.events import MucDiscoUpdate from gajim.common.i18n import _ from gajim.common.const import CallType @@ -112,6 +113,19 @@ def show_chat(self, account: str, jid: JID) -> None: else: self._update_chat_actions(self._current_contact)
+ if isinstance(self._current_contact, GroupchatContact): + muc_data = client.get_module('MUC').get_muc_data( + str(self._current_contact.jid)) + if muc_data is not None: + if muc_data.state.is_captcha_request: + self._chat_function_page.set_mode( + self._current_contact, 'captcha-request') + return + if muc_data.state.is_password_request: + self._chat_function_page.set_mode( + self._current_contact, 'password-request') + return + self.set_transition_type(Gtk.StackTransitionType.NONE) self.set_visible_child_name('controls')
@@ -399,6 +413,7 @@ def _show_chat_function_page(self, self.set_visible_child_name('function')
def _on_function_finished(self, _function_page: ChatFunctionPage) -> None: + # TODO: close control on password/captcha cancel self.set_visible_child_name('controls') self.set_transition_type(Gtk.StackTransitionType.NONE)
View it on GitLab: https://dev.gajim.org/gajim/gajim/-/commit/c671abf28db63c2bbf50ac07a6f54bc99...