Coverage for slidge/slixfix/xep_0100/gateway.py: 64%

64 statements  

« prev     ^ index     » next       coverage.py v7.8.0, created at 2025-05-04 08:17 +0000

1import logging 

2import warnings 

3 

4from slixmpp import JID, Iq, Message, Presence, register_stanza_plugin 

5from slixmpp.exceptions import XMPPError 

6from slixmpp.plugins.base import BasePlugin 

7 

8from slidge.core import config 

9 

10from . import stanza 

11 

12log = logging.getLogger(__name__) 

13 

14 

15class XEP_0100(BasePlugin): 

16 name = "xep_0100" 

17 description = "XEP-0100: Gateway interaction (slidge)" 

18 dependencies = { 

19 "xep_0030", # Service discovery 

20 "xep_0077", # In band registration 

21 "xep_0356", # Privileged entities 

22 } 

23 

24 default_config = { 

25 "component_name": "SliXMPP gateway", 

26 "type": "xmpp", 

27 "needs_registration": True, 

28 } 

29 

30 def plugin_init(self) -> None: 

31 if not self.xmpp.is_component: 

32 log.error("Only components can be gateways, aborting plugin load") 

33 return 

34 

35 self.xmpp["xep_0030"].add_identity( 

36 name=self.component_name, category="gateway", itype=self.type 

37 ) 

38 

39 # Without that BaseXMPP sends unsub/unavailable on sub requests, and we don't want that 

40 self.xmpp.client_roster.auto_authorize = False 

41 self.xmpp.client_roster.auto_subscribe = False 

42 

43 self.xmpp.add_event_handler("user_register", self.on_user_register) 

44 self.xmpp.add_event_handler("user_unregister", self.on_user_unregister) 

45 self.xmpp.add_event_handler( 

46 "presence_unsubscribe", self.on_presence_unsubscribe 

47 ) 

48 

49 self.xmpp.add_event_handler("message", self.on_message) 

50 

51 register_stanza_plugin(Iq, stanza.Gateway) 

52 

53 def plugin_end(self) -> None: 

54 if not self.xmpp.is_component: 

55 self.xmpp.remove_event_handler("user_register", self.on_user_register) 

56 self.xmpp.remove_event_handler("user_unregister", self.on_user_unregister) 

57 self.xmpp.remove_event_handler( 

58 "presence_unsubscribe", self.on_presence_unsubscribe 

59 ) 

60 

61 self.xmpp.remove_event_handler("message", self.on_message) 

62 

63 async def get_user(self, stanza): 

64 return await self.xmpp["xep_0077"].api["user_get"](None, None, None, stanza) 

65 

66 async def on_user_unregister(self, iq: Iq) -> None: 

67 self.xmpp.send_presence(pto=iq.get_from().bare, ptype="unavailable") 

68 self.xmpp.send_presence(pto=iq.get_from().bare, ptype="unsubscribe") 

69 self.xmpp.send_presence(pto=iq.get_from().bare, ptype="unsubscribed") 

70 

71 async def on_user_register(self, iq: Iq) -> None: 

72 self.xmpp.client_roster[iq.get_from()].load() 

73 await self.add_component_to_roster(jid=iq.get_from()) 

74 

75 async def add_component_to_roster(self, jid: JID) -> None: 

76 items = { 

77 self.xmpp.boundjid.bare: { 

78 "name": self.component_name, 

79 "subscription": "both", 

80 "groups": ["Slidge"], 

81 } 

82 } 

83 try: 

84 await self._set_roster(jid, items) 

85 except PermissionError: 

86 from slidge import __version__ 

87 

88 warnings.warn( 

89 "Slidge does not have the privilege to manage rosters. See " 

90 f"https://slidge.im/docs/slidge/{__version__}/admin/privilege.html" 

91 ) 

92 self.xmpp.send_presence(ptype="subscribe", pto=jid.bare) 

93 

94 async def _set_roster(self, jid, items) -> None: 

95 await self.xmpp["xep_0356"].set_roster(jid=jid.bare, roster_items=items) 

96 

97 def on_presence_unsubscribe(self, p: Presence) -> None: 

98 if p.get_to() == self.xmpp.boundjid.bare: 

99 log.debug("REMOVE: Our roster: %s", self.xmpp.client_roster) 

100 self.xmpp["xep_0077"].api["user_remove"](None, None, p["from"], p) 

101 self.xmpp.event("user_unregister", p) 

102 

103 async def on_message(self, msg: Message): 

104 if msg["type"] == "groupchat": 

105 return # groupchat messages are out of scope of XEP-0100 

106 

107 if msg["to"] == self.xmpp.boundjid.bare: 

108 # It may be useful to exchange direct messages with the component 

109 self.xmpp.event("gateway_message", msg) 

110 return 

111 

112 if self.needs_registration and await self.get_user(msg) is None: 

113 raise XMPPError( 

114 "registration-required", text="You are not registered to this gateway" 

115 ) 

116 

117 self.xmpp.event("legacy_message", msg)