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

69 statements  

« prev     ^ index     » next       coverage.py v7.6.1, created at 2024-11-07 05:11 +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): 

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): 

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): 

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): 

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): 

76 if config.NO_ROSTER_PUSH: 

77 return 

78 items = { 

79 self.xmpp.boundjid.bare: { 

80 "name": self.component_name, 

81 "subscription": "both", 

82 "groups": ["Slidge"], 

83 } 

84 } 

85 try: 

86 await self._set_roster(jid, items) 

87 except PermissionError: 

88 warnings.warn( 

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

90 "Users should add the slidge component to their rosters manually." 

91 ) 

92 if config.ROSTER_PUSH_PRESENCE_SUBSCRIPTION_REQUEST_FALLBACK: 

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

94 

95 async def _set_roster(self, jid, items): 

96 try: 

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

98 except PermissionError: 

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

100 

101 def on_presence_unsubscribe(self, p: Presence): 

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

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

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

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

106 

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

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

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

110 

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

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

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

114 return 

115 

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

117 raise XMPPError( 

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

119 ) 

120 

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