slidge.core.gateway#

This module extends slixmpp.ComponentXMPP to make writing new LegacyClients easier

Module Contents#

Classes#

BaseGateway

Must be subclassed by a plugin to set up various aspects of the XMPP

Functions#

admin_only(func)

Attributes#

slidge.core.gateway.admin_only(func)[source]#
class slidge.core.gateway.BaseGateway[source]#

Bases: Generic[slidge.core.session.SessionType], slixmpp.ComponentXMPP

Must be subclassed by a plugin to set up various aspects of the XMPP component behaviour, such as its display name or its registration process.

On slidge launch, a singleton is instantiated, and it will be made available to public classes such LegacyContact or BaseSession as the .xmpp attribute. Since it inherits from slixmpp.componentxmpp.ComponentXMPP, this gives you a hand on low-level XMPP interactions via slixmpp plugins, e.g.:

self.send_presence(
    pfrom="somebody@component.example.com",
    pto="someonwelse@anotherexample.com",
)

However, you should not need to do so often since the classes of the plugin API provides higher level abstractions around most commonly needed use-cases, such as sending messages, or displaying a custom status.

REGISTRATION_FIELDS :Iterable[slidge.util.FormField][source]#

Iterable of fields presented to the gateway user when registering using XEP-0077 extended by XEP-0004.

REGISTRATION_INSTRUCTIONS :str = Enter your credentials[source]#

The text presented to a user that wants to register (or modify) their legacy account configuration.

REGISTRATION_MULTISTEP = False[source]#

If the network requires a multistep registration, set this to True to prevent name squatting. Registrations that did not successfully login withing SLIDGE_PARTIAL_REGISTRATION_TIMEOUT seconds will automatically be removed from the user_store.

COMPONENT_NAME :str[source]#

Name of the component, as seen in service discovery by XMPP clients

COMPONENT_TYPE :Optional[str] =[source]#

Type of the gateway, should ideally follow https://xmpp.org/registrar/disco-categories.html

COMPONENT_AVATAR :Optional[slidge.util.types.AvatarType][source]#

Path, bytes or URL used by the component as an avatar.

ROSTER_GROUP :str = slidge[source]#

Roster entries added by the plugin in the user’s roster will be part of the group specified here.

SEARCH_FIELDS :Sequence[slidge.util.FormField][source]#

Fields used for searching items via the component, through XEP-0055 (jabber search). A common use case is to allow users to search for legacy contacts by something else than their usernames, eg their phone number.

Plugins should implement search by overriding BaseSession.search(), effectively restricting search to registered users by default.

SEARCH_TITLE :str = Search for legacy contacts[source]#

Title of the search form.

SEARCH_INSTRUCTIONS :str =[source]#

Instructions of the search form.

_BASE_CHAT_COMMANDS[source]#
CHAT_COMMANDS :dict[str, str][source]#

Keys of this dict can be used to trigger a command by a simple chat message to the gateway component. Extra words after the key are passed as *args to the handler. Values of the dict are strings, and handlers are resolved using getattr() on the BaseGateway instance.

Handlers are coroutines with following signature:

The original slixmpp.stanza.Message is also passed to the handler as the msg kwarg. If the command comes from a registered gateway user, its session attribute is also passed to the handler.

WELCOME_MESSAGE = Thank you for registering. Type 'help' to list the available commands, or just start messaging away![source]#

A welcome message displayed to users on registration. This is useful notably for clients that don’t consider component JIDs as a valid recipient in their UI, yet still open a functional chat window on incoming messages from components.

__exception_handler(loop, context)[source]#

Called when a task created by loop.create_task() raises an Exception

Parameters
Returns

_raise_if_not_allowed_jid(jid)[source]#
Parameters

jid (slixmpp.JID) –

exception(exception)[source]#

Called when a task created by slixmpp’s internal (eg, on slix events) raises an Exception.

Stop the event loop and exit on unhandled exception.

The default :class:slixmpp.basexmpp.BaseXMPP` behaviour is just to log the exception, but we want to avoid undefined behaviour.

Parameters

exception (Exception) – An unhandled Exception object.

__register_slixmpp_api()[source]#
__register_handlers()[source]#
async __on_session_start(event)[source]#
async _login_wrap(session)[source]#
Parameters

session (slidge.core.session.SessionType) –

re_login(session)[source]#
Parameters

session (slidge.core.session.SessionType) –

__add_adhoc_commands()[source]#
_handle_info(iq, session)[source]#

List registered users for admins

Parameters
  • iq (slixmpp.Iq) –

  • session (dict[str, Any]) –

_handle_user_delete(iq, adhoc_session)[source]#
Parameters
  • iq (slixmpp.Iq) –

  • adhoc_session (dict[str, Any]) –

async _handle_user_delete2(form, adhoc_session)[source]#
Parameters

adhoc_session (dict[str, Any]) –

Jabber search, but as an adhoc command (search form)

Parameters
  • iq (slixmpp.Iq) –

  • adhoc_session (dict[str, Any]) –

async _handle_search2(form, adhoc_session)[source]#

Jabber search, but as an adhoc command (results)

Parameters

adhoc_session (dict[str, Any]) –

async _make_registration_form(_jid, _node, _ifrom, iq)[source]#
Parameters

iq (slixmpp.Iq) –

async _user_prevalidate(ifrom, form_dict)[source]#

Pre validate a registration form using the content of self.REGISTRATION_FIELDS before passing it to the plugin custom validation logic.

Parameters
  • ifrom (slixmpp.JID) –

  • form_dict (dict[str, Optional[str]]) –

async _user_validate(_gateway_jid, _node, ifrom, iq)[source]#

SliXMPP internal API stuff

Parameters
  • ifrom (slixmpp.JID) –

  • iq (slixmpp.Iq) –

async _user_modify(_gateway_jid, _node, ifrom, form_dict)[source]#

SliXMPP internal API stuff

Parameters
  • ifrom (slixmpp.JID) –

  • form_dict (dict[str, Optional[str]]) –

async _on_user_register(iq)[source]#
Parameters

iq (slixmpp.Iq) –

async __registration_timeout(session)[source]#
Parameters

session (slidge.core.session.SessionType) –

async _on_user_unregister(iq)[source]#
Parameters

iq (slixmpp.Iq) –

async _search_get_form(_gateway_jid, _node, ifrom, iq)[source]#

Prepare the search form using self.SEARCH_FIELDS

Parameters
  • ifrom (slixmpp.JID) –

  • iq (slixmpp.Iq) –

async _search_query(_gateway_jid, _node, ifrom, iq)[source]#

Handles a search request

Parameters
  • ifrom (slixmpp.JID) –

  • iq (slixmpp.Iq) –

Parameters
  • msg (slixmpp.Message) –

  • session (Optional[slidge.core.session.SessionType]) –

async _chat_command_help(*_args, msg, session)[source]#
Parameters
  • msg (slixmpp.Message) –

  • session (Optional[slidge.core.session.SessionType]) –

async static _chat_command_list_contacts(*_args, msg, session)[source]#
Parameters
  • msg (slixmpp.Message) –

  • session (Optional[slidge.core.session.SessionType]) –

async _chat_command_register(*args, msg, session)[source]#
Parameters
  • msg (slixmpp.Message) –

  • session (Optional[slidge.core.session.SessionType]) –

add_adhoc_commands()[source]#

Override this if you want to provide custom adhoc commands (XEP-0050) for your plugin, using slixmpp.plugins.xep_0050.XEP_0050

Basic example:

config(argv)[source]#

Override this to access CLI args to configure the slidge plugin

Parameters

argv (list[str]) – CLI args that were not parsed by the slidge main entrypoint parser

slidge.__main__.get_parser()

async validate(user_jid, registration_form)[source]#

Validate a registration form from a user.

Since XEP-0077 is pretty limited in terms of validation, it is OK to validate anything that looks good here and continue the legacy auth process via direct messages to the user (using BaseGateway.input() for instance)

Parameters
async unregister(user)[source]#

Optionally override this if you need to clean additional stuff after a user has been removed from the permanent user_store.

Parameters

user (slidge.util.db.GatewayUser) –

Returns

async _on_gateway_message_private(msg)[source]#

Called when an XMPP user (not necessarily registered as a gateway user) sends a direct message to the gateway.

If you override this and still want BaseGateway.input() to work, make sure to include the try/except part.

Parameters

msg (slixmpp.Message) – Message sent by the XMPP user

async static on_gateway_message(msg, session=None)[source]#

Called when the gateway component receives a direct gateway message.

Can be used to implement bot like commands, especially in conjunction with BaseGateway.input()

Parameters
  • msg (slixmpp.Message) –

  • session (Optional[slidge.core.session.SessionType]) – If the message comes from a registered gateway user, their :.BaseSession:

async input(jid, text=None, mtype='chat', **msg_kwargs)[source]#

Request arbitrary user input using a simple chat message, and await the result.

You shouldn’t need to call directly bust instead user BaseSession.input() to directly target a user.

NB: When using this, the next message that the user sent to the component will not be transmitted to BaseGateway.on_gateway_message(), but rather intercepted. Await the coroutine to get its content.

Parameters
  • jid (slixmpp.JID) – The JID we want input from

  • text – A prompt to display for the user

  • mtype (slixmpp.types.MessageTypes) – Message type

Returns

The user’s reply

Return type

str

async send_file(filename, **msg_kwargs)[source]#

Upload a file using XEP-0363 and send the link as out of band (XEP-0066) content in a message.

Parameters
  • filename (str) –

  • msg_kwargs

Returns

async send_qr(text, **msg_kwargs)[source]#

Sends a QR Code to a JID

Parameters
  • text (str) – The text that will be converted to a QR Code

  • msg_kwargs – Optional additional arguments to pass to BaseGateway.send_file(), such as the recipient of the QR code.

shutdown()[source]#

Called by the slidge entrypoint on normal exit.

Sends offline presences from all contacts of all user sessions and from the gateway component itself. No need to call this manually, slidge.__main__.main() should take care of it.

slidge.core.gateway.GatewayType[source]#
slidge.core.gateway.SLIXMPP_PLUGINS = ['xep_0050', 'xep_0055', 'xep_0066', 'xep_0077', 'xep_0084', 'xep_0085', 'xep_0100', 'xep_0106',...[source]#
slidge.core.gateway.log[source]#