slidge 0.2.8__py3-none-any.whl → 0.2.10__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
slidge/__init__.py CHANGED
@@ -6,6 +6,7 @@ Contains importable classes for a minimal function :term:`Legacy Module`.
6
6
 
7
7
  import sys
8
8
  import warnings
9
+ from importlib.metadata import PackageNotFoundError, version
9
10
 
10
11
  from . import slixfix # noqa: F401
11
12
  from .command import FormField, SearchResult # noqa: F401
@@ -28,7 +29,7 @@ def entrypoint(module_name: str) -> None:
28
29
  :param module_name: An importable :term:`Legacy Module`.
29
30
  """
30
31
  sys.argv.extend(["--legacy", module_name])
31
- main_func()
32
+ main_func(module_name)
32
33
 
33
34
 
34
35
  def formatwarning(message, category, filename, lineno, line=""):
@@ -37,8 +38,15 @@ def formatwarning(message, category, filename, lineno, line=""):
37
38
 
38
39
  warnings.formatwarning = formatwarning
39
40
 
41
+ try:
42
+ __version__ = version("slidge")
43
+ except PackageNotFoundError:
44
+ # package is not installed
45
+ __version__ = "dev"
46
+
40
47
 
41
48
  __all__ = [
49
+ "__version__",
42
50
  "BaseGateway",
43
51
  "BaseSession",
44
52
  # For backwards compatibility, these names are still importable from the
slidge/command/admin.py CHANGED
@@ -60,8 +60,6 @@ class SlidgeInfo(AdminCommand):
60
60
  ACCESS = CommandAccess.ANY
61
61
 
62
62
  async def run(self, _session, _ifrom, *_):
63
- from slidge.__version__ import __version__
64
-
65
63
  start = self.xmpp.datetime_started # type:ignore
66
64
  uptime = datetime.now() - start
67
65
 
@@ -100,8 +98,10 @@ class SlidgeInfo(AdminCommand):
100
98
  legacy_module = importlib.import_module(config.LEGACY_MODULE)
101
99
  version = getattr(legacy_module, "__version__", "No version")
102
100
 
101
+ import slidge
102
+
103
103
  return (
104
- f"{self.xmpp.COMPONENT_NAME} (slidge core {__version__},"
104
+ f"{self.xmpp.COMPONENT_NAME} (slidge core {slidge.__version__},"
105
105
  f" {config.LEGACY_MODULE} {version})\n"
106
106
  f"Up since {start:%Y-%m-%d %H:%M} ({ago} ago)"
107
107
  )
slidge/core/gateway.py CHANGED
@@ -31,6 +31,7 @@ from slidge.core.pubsub import PubSubComponent
31
31
  from slidge.core.session import BaseSession
32
32
  from slidge.db import GatewayUser, SlidgeStore
33
33
  from slidge.db.avatar import avatar_cache
34
+ from slidge.slixfix import PrivilegedIqError
34
35
  from slidge.slixfix.delivery_receipt import DeliveryReceipt
35
36
  from slidge.slixfix.roster import RosterBackend
36
37
  from slidge.util import ABCSubclassableOnceAtMost
@@ -474,11 +475,12 @@ class BaseGateway(
474
475
  "create the MDS node of %s",
475
476
  user_jid,
476
477
  )
477
- except (IqError, IqTimeout) as e:
478
+ except PrivilegedIqError as exc:
479
+ nested = exc.nested_error()
478
480
  # conflict this means the node already exists, we can ignore that
479
- if e.condition != "conflict":
481
+ if nested is not None and nested.condition != "conflict":
480
482
  log.exception(
481
- "Could not create the MDS node of %s", user_jid, exc_info=e
483
+ "Could not create the MDS node of %s", user_jid, exc_info=exc
482
484
  )
483
485
  except Exception as e:
484
486
  log.exception(
@@ -526,6 +528,7 @@ class BaseGateway(
526
528
  "You are not connected to this gateway! "
527
529
  f"Maybe this message will tell you why: {e}"
528
530
  )
531
+ session.logged = False
529
532
  return
530
533
 
531
534
  log.info("Login success for %s", session.user_jid)
@@ -46,7 +46,7 @@ class AttachmentMixin(TextMessageMixin):
46
46
  file_path: Path,
47
47
  file_name: Optional[str] = None,
48
48
  content_type: Optional[str] = None,
49
- ):
49
+ ) -> str | None:
50
50
  if file_name and file_path.name != file_name:
51
51
  d = Path(tempfile.mkdtemp())
52
52
  temp = d / file_name
@@ -215,7 +215,7 @@ class AttachmentMixin(TextMessageMixin):
215
215
  else:
216
216
  local_path = file_path
217
217
  new_url = await self.__upload(file_path, file_name, content_type)
218
- if legacy_file_id:
218
+ if legacy_file_id and new_url is not None:
219
219
  self.__store.set_url(self.session.user_pk, str(legacy_file_id), new_url)
220
220
 
221
221
  return is_temp, local_path, new_url
slidge/core/pubsub.py CHANGED
@@ -11,7 +11,7 @@ from slixmpp import (
11
11
  StanzaPath,
12
12
  register_stanza_plugin,
13
13
  )
14
- from slixmpp.exceptions import XMPPError
14
+ from slixmpp.exceptions import IqError, IqTimeout, XMPPError
15
15
  from slixmpp.plugins.base import BasePlugin, register_plugin
16
16
  from slixmpp.plugins.xep_0060.stanza import Event, EventItem, EventItems, Item
17
17
  from slixmpp.plugins.xep_0084 import Data as AvatarData
@@ -134,7 +134,11 @@ class PubSubComponent(NamedLockMixin, BasePlugin):
134
134
  info = None
135
135
  if info is None:
136
136
  async with self.lock(from_):
137
- iq = await self.xmpp.plugin["xep_0030"].get_info(from_)
137
+ try:
138
+ iq = await self.xmpp.plugin["xep_0030"].get_info(from_)
139
+ except (IqError, IqTimeout):
140
+ log.debug("Could get disco#info of %s, ignoring", from_)
141
+ return []
138
142
  info = iq["disco_info"]
139
143
  return info["features"]
140
144
 
slidge/core/session.py CHANGED
@@ -543,10 +543,10 @@ class BaseSession(
543
543
  return f"<Session of {self.user_jid}>"
544
544
 
545
545
  def shutdown(self, logout=True) -> asyncio.Task:
546
- for c in self.contacts:
547
- c.offline()
548
546
  for m in self.bookmarks:
549
547
  m.shutdown()
548
+ for c in self.contacts:
549
+ c.offline()
550
550
  if logout:
551
551
  return self.xmpp.loop.create_task(self.logout())
552
552
  else:
slidge/db/store.py CHANGED
@@ -1076,6 +1076,7 @@ class ParticipantStore(EngineMixin):
1076
1076
  update(Participant)
1077
1077
  .where(Participant.id == participant.pk)
1078
1078
  .values(
1079
+ nickname=participant.nickname,
1079
1080
  resource=participant.jid.resource,
1080
1081
  nickname_no_illegal=participant._nickname_no_illegal,
1081
1082
  affiliation=participant.affiliation,
@@ -229,6 +229,8 @@ class LegacyParticipant(
229
229
  p = self._make_presence(ptype="available", last_seen=last_seen, **kwargs)
230
230
  self._send(p)
231
231
 
232
+ self.__part_store.update(self)
233
+
232
234
  def _make_presence(
233
235
  self,
234
236
  *,
slidge/group/room.py CHANGED
@@ -648,7 +648,7 @@ class LegacyMUC(
648
648
  since = self.xmpp.plugin["xep_0082"].parse(history_params["since"])
649
649
  except ValueError:
650
650
  since = None
651
- if seconds:
651
+ if seconds is not None:
652
652
  since = datetime.now() - timedelta(seconds=seconds)
653
653
  if equals_zero(maxchars) or equals_zero(maxstanzas):
654
654
  log.debug("Joining client does not want any old-school MUC history-on-join")
@@ -1016,8 +1016,11 @@ class LegacyMUC(
1016
1016
  item = ans["pubsub"]["items"]["item"]
1017
1017
  item["id"] = self.jid
1018
1018
  return item
1019
- except (IqError, IqTimeout) as exc:
1020
- warnings.warn(f"Cannot fetch bookmark: {exc}")
1019
+ except IqTimeout as exc:
1020
+ warnings.warn(f"Cannot fetch bookmark for {self.user_jid}: timeout")
1021
+ return None
1022
+ except IqError as exc:
1023
+ warnings.warn(f"Cannot fetch bookmark for {self.user_jid}: {exc}")
1021
1024
  return None
1022
1025
  except PermissionError:
1023
1026
  warnings.warn(
slidge/main.py CHANGED
@@ -24,8 +24,8 @@ from pathlib import Path
24
24
 
25
25
  import configargparse
26
26
 
27
+ import slidge
27
28
  from slidge import BaseGateway
28
- from slidge.__version__ import __version__
29
29
  from slidge.core import config
30
30
  from slidge.core.pubsub import PepAvatar, PepNick
31
31
  from slidge.db import SlidgeStore
@@ -60,7 +60,7 @@ class SigTermInterrupt(Exception):
60
60
  pass
61
61
 
62
62
 
63
- def get_configurator():
63
+ def get_configurator(from_entrypoint: bool = False):
64
64
  p = configargparse.ArgumentParser(
65
65
  default_config_files=os.getenv(
66
66
  "SLIDGE_CONF_DIR", "/etc/slidge/conf.d/*.conf"
@@ -96,9 +96,11 @@ def get_configurator():
96
96
  p.add_argument(
97
97
  "--version",
98
98
  action="version",
99
- version=f"%(prog)s {__version__}",
99
+ version=f"%(prog)s {slidge.__version__}",
100
+ )
101
+ configurator = MainConfig(
102
+ config, p, skip_options=("legacy_module",) if from_entrypoint else ()
100
103
  )
101
- configurator = MainConfig(config, p)
102
104
  return configurator
103
105
 
104
106
 
@@ -106,8 +108,8 @@ def get_parser():
106
108
  return get_configurator().parser
107
109
 
108
110
 
109
- def configure():
110
- configurator = get_configurator()
111
+ def configure(from_entrypoint: bool):
112
+ configurator = get_configurator(from_entrypoint)
111
113
  args, unknown_argv = configurator.set_conf()
112
114
 
113
115
  if not (h := config.HOME_DIR).exists():
@@ -124,11 +126,15 @@ def handle_sigterm(_signum, _frame):
124
126
  raise SigTermInterrupt
125
127
 
126
128
 
127
- def main():
129
+ def main(module_name: str | None = None) -> None:
130
+ from_entrypoint = module_name is None
128
131
  signal.signal(signal.SIGTERM, handle_sigterm)
129
132
 
130
- unknown_argv = configure()
131
- logging.info("Starting slidge version %s", __version__)
133
+ unknown_argv = configure(from_entrypoint)
134
+ logging.info("Starting slidge version %s", slidge.__version__)
135
+
136
+ if module_name is not None:
137
+ config.LEGACY_MODULE = module_name
132
138
 
133
139
  legacy_module = importlib.import_module(config.LEGACY_MODULE)
134
140
  logging.debug("Legacy module: %s", dir(legacy_module))
@@ -3,12 +3,15 @@
3
3
 
4
4
  # ruff: noqa: F401
5
5
 
6
- import logging
6
+ import uuid
7
7
 
8
8
  import slixmpp.plugins
9
9
  import slixmpp.stanza.roster
10
- from slixmpp import InvalidJID, Message
10
+ from slixmpp import Message
11
+ from slixmpp.exceptions import IqError
11
12
  from slixmpp.plugins.xep_0050 import XEP_0050, Command
13
+ from slixmpp.plugins.xep_0356.permissions import IqPermission
14
+ from slixmpp.plugins.xep_0356.privilege import XEP_0356
12
15
  from slixmpp.plugins.xep_0469.stanza import NS as PINNED_NS
13
16
  from slixmpp.plugins.xep_0469.stanza import Pinned
14
17
  from slixmpp.xmlstream import StanzaBase
@@ -22,24 +25,6 @@ from . import (
22
25
  )
23
26
 
24
27
 
25
- # TODO: remove this when we pin slixmpp > 1.9.0
26
- def get_items(self):
27
- items = {}
28
- for item in self["substanzas"]:
29
- if isinstance(item, slixmpp.stanza.roster.RosterItem):
30
- try:
31
- items[item["jid"]] = item.values
32
- except InvalidJID:
33
- logging.warning("Invalid JID in roster: %s", item)
34
- continue
35
- del items[item["jid"]]["jid"]
36
- del items[item["jid"]]["lang"]
37
- return items
38
-
39
-
40
- slixmpp.stanza.roster.Roster.get_items = get_items # type:ignore
41
-
42
-
43
28
  def set_pinned(self, val: bool):
44
29
  extensions = self.parent()
45
30
  if val:
@@ -83,6 +68,70 @@ def reply(self, body=None, clear=True):
83
68
 
84
69
  Message.reply = reply # type: ignore
85
70
 
71
+ # TODO: remove me when https://codeberg.org/poezio/slixmpp/pulls/3622 is merged
72
+
73
+
74
+ class PrivilegedIqError(IqError):
75
+ """
76
+ Exception raised when sending a privileged IQ stanza fails.
77
+ """
78
+
79
+ def nested_error(self) -> IqError | None:
80
+ """
81
+ Return the IQError generated from the inner IQ stanza, if present.
82
+ """
83
+ if "privilege" in self.iq:
84
+ if "forwarded" in self.iq["privilege"]:
85
+ if "iq" in self.iq["privilege"]["forwarded"]:
86
+ return IqError(self.iq["privilege"]["forwarded"]["iq"])
87
+ return None
88
+
89
+
90
+ async def send_privileged_iq(self, encapsulated_iq, iq_id=None):
91
+ """
92
+ Send an IQ on behalf of a user
93
+
94
+ Caution: the IQ *must* have the jabber:client namespace
95
+
96
+ Raises :class:`PrivilegedIqError` on failure.
97
+ """
98
+ iq_id = iq_id or str(uuid.uuid4())
99
+ encapsulated_iq["id"] = iq_id
100
+ server = encapsulated_iq.get_to().domain
101
+ perms = self.granted_privileges.get(server)
102
+ if not perms:
103
+ raise PermissionError(f"{server} has not granted us any privilege")
104
+ itype = encapsulated_iq["type"]
105
+ for ns in encapsulated_iq.plugins.values():
106
+ type_ = perms.iq[ns.namespace]
107
+ if type_ == IqPermission.NONE:
108
+ raise PermissionError(
109
+ f"{server} has not granted any IQ privilege for namespace {ns.namespace}"
110
+ )
111
+ elif type_ == IqPermission.BOTH:
112
+ pass
113
+ elif type_ != itype:
114
+ raise PermissionError(
115
+ f"{server} has not granted IQ {itype} privilege for namespace {ns.namespace}"
116
+ )
117
+ iq = self.xmpp.make_iq(
118
+ itype=itype,
119
+ ifrom=self.xmpp.boundjid.bare,
120
+ ito=encapsulated_iq.get_from(),
121
+ id=iq_id,
122
+ )
123
+ iq["privileged_iq"].append(encapsulated_iq)
124
+
125
+ try:
126
+ resp = await iq.send()
127
+ except IqError as exc:
128
+ raise PrivilegedIqError(exc.iq)
129
+
130
+ return resp["privilege"]["forwarded"]["iq"]
131
+
132
+
133
+ XEP_0356.send_privileged_iq = send_privileged_iq
134
+
86
135
 
87
136
  slixmpp.plugins.PLUGINS.extend(
88
137
  [
slidge/util/conf.py CHANGED
@@ -95,20 +95,27 @@ class ConfigModule:
95
95
  ENV_VAR_PREFIX = "SLIDGE_"
96
96
 
97
97
  def __init__(
98
- self, config_obj, parser: Optional[configargparse.ArgumentParser] = None
98
+ self,
99
+ config_obj,
100
+ parser: Optional[configargparse.ArgumentParser] = None,
101
+ skip_options: tuple[str, ...] = (),
99
102
  ):
100
103
  self.config_obj = config_obj
101
104
  if parser is None:
102
105
  parser = configargparse.ArgumentParser()
103
106
  self.parser = parser
104
107
 
105
- self.add_options_to_parser()
108
+ self.skip_options = skip_options
109
+ self.add_options_to_parser(skip_options)
106
110
 
107
111
  def _list_options(self):
108
112
  return {
109
113
  o
110
114
  for o in (set(dir(self.config_obj)) | set(get_type_hints(self.config_obj)))
111
- if o.upper() == o and not o.startswith("_") and "__" not in o
115
+ if o.upper() == o
116
+ and not o.startswith("_")
117
+ and "__" not in o
118
+ and o.lower() not in self.skip_options
112
119
  }
113
120
 
114
121
  def set_conf(self, argv: Optional[list[str]] = None):
@@ -179,9 +186,12 @@ class ConfigModule:
179
186
  res.append(Option(self, opt))
180
187
  return res
181
188
 
182
- def add_options_to_parser(self):
189
+ def add_options_to_parser(self, skip_options: tuple[str, ...]):
190
+ skip_options = tuple(o.lower() for o in skip_options)
183
191
  p = self.parser
184
192
  for o in sorted(self.options, key=lambda x: (not x.required, x.name)):
193
+ if o.name.lower() in skip_options:
194
+ continue
185
195
  p.add_argument(*o.names, **o.kwargs)
186
196
 
187
197
  def update_dynamic_defaults(self, args):
slidge/util/types.py CHANGED
@@ -21,7 +21,7 @@ from typing import (
21
21
  )
22
22
 
23
23
  from slixmpp import Message, Presence
24
- from slixmpp.types import PresenceShows, PresenceTypes
24
+ from slixmpp.types import PresenceShows, PresenceTypes, ResourceDict
25
25
 
26
26
  if TYPE_CHECKING:
27
27
  from ..contact import LegacyContact
@@ -155,12 +155,6 @@ class MucType(IntEnum):
155
155
  PseudoPresenceShow = Union[PresenceShows, Literal[""]]
156
156
 
157
157
 
158
- class ResourceDict(TypedDict):
159
- show: PseudoPresenceShow
160
- status: str
161
- priority: int
162
-
163
-
164
158
  MessageOrPresenceTypeVar = TypeVar(
165
159
  "MessageOrPresenceTypeVar", bound=Union[Message, Presence]
166
160
  )
slidge/util/util.py CHANGED
@@ -218,19 +218,6 @@ class SlidgeLogger(logging.Logger):
218
218
  log = logging.getLogger(__name__)
219
219
 
220
220
 
221
- def get_version() -> str:
222
- try:
223
- git = subprocess.check_output(
224
- ["git", "rev-parse", "HEAD"],
225
- stderr=subprocess.DEVNULL,
226
- cwd=Path(__file__).parent,
227
- ).decode()
228
- except (FileNotFoundError, subprocess.CalledProcessError):
229
- return "NO_VERSION"
230
- else:
231
- return "git-" + git[:10]
232
-
233
-
234
221
  def merge_resources(resources: dict[str, ResourceDict]) -> Optional[ResourceDict]:
235
222
  if len(resources) == 0:
236
223
  return None
@@ -0,0 +1,133 @@
1
+ Metadata-Version: 2.4
2
+ Name: slidge
3
+ Version: 0.2.10
4
+ Summary: XMPP bridging framework
5
+ Author-email: Nicolas Cedilnik <nicoco@nicoco.fr>
6
+ License-Expression: AGPL-3.0-or-later
7
+ Project-URL: Homepage, https://codeberg.org/slidge/
8
+ Project-URL: Issues, https://codeberg.org/slidge/slidge/issues
9
+ Project-URL: Repository, https://codeberg.org/slidge/slidge/
10
+ Project-URL: Chat room, https://conference.nicoco.fr:5281/muc_log/slidge/
11
+ Project-URL: Documentation, https://slidge.im/docs/slidge/main
12
+ Project-URL: changelog, https://codeberg.org/slidge/slidge/releases
13
+ Keywords: xmpp,gateway,bridge,instant messaging
14
+ Classifier: Topic :: Internet :: XMPP
15
+ Classifier: Topic :: Software Development :: Libraries :: Python Modules
16
+ Requires-Python: >=3.11
17
+ Description-Content-Type: text/markdown
18
+ License-File: LICENSE
19
+ Requires-Dist: aiohttp[speedups]<4,>=3.11.11
20
+ Requires-Dist: alembic<2,>=1.14.0
21
+ Requires-Dist: configargparse<2,>=1.7
22
+ Requires-Dist: defusedxml>=0.7.1
23
+ Requires-Dist: pillow<12,>=11.0.0
24
+ Requires-Dist: python-magic<0.5,>=0.4.27
25
+ Requires-Dist: qrcode<9,>=8.0
26
+ Requires-Dist: slixmpp<2,>=1.10.0
27
+ Requires-Dist: sqlalchemy<3,>=2
28
+ Requires-Dist: thumbhash>=0.1.2
29
+ Dynamic: license-file
30
+
31
+ ![Slidge logo](https://codeberg.org/slidge/slidge/raw/branch/main/dev/assets/slidge-color-small.png)
32
+
33
+ [![woodpecker CI status](https://ci.codeberg.org/api/badges/14027/status.svg)](https://ci.codeberg.org/repos/14027)
34
+ [![coverage](https://slidge.im/coverage/slidge/main/coverage.svg)](https://slidge.im/coverage/slidge/main)
35
+ [![Chat](https://conference.nicoco.fr:5281/muc_badge/slidge@conference.nicoco.fr)](https://conference.nicoco.fr:5281/muc_log/slidge/)
36
+
37
+ Slidge is an XMPP (puppeteer) gateway library in python.
38
+ It makes
39
+ [writing gateways to other chat networks](https://slidge.im/docs/slidge/main/dev/tutorial.html)
40
+ (*legacy modules*) as frictionless as possible.
41
+ It supports fancy IM features, such as
42
+ [(emoji) reactions](https://xmpp.org/extensions/xep-0444.html),
43
+ [replies](https://xmpp.org/extensions/xep-0461.html), and
44
+ [retractions](https://xmpp.org/extensions/xep-0424.html).
45
+ The full list of supported XEPs in on [xmpp.org](https://xmpp.org/software/slidge/).
46
+
47
+ Status
48
+ ------
49
+
50
+ Slidge is **beta**-grade software. It support groups and 1:1 chats.
51
+ Try slidge and give us some
52
+ feedback, through the [MUC](xmpp:slidge@conference.nicoco.fr?join) or the
53
+ [issue tracker](https://codeberg.org/slidge/slidge/issues).
54
+ Don't be shy!
55
+
56
+ Usage
57
+ -----
58
+
59
+ A minimal (and fictional!) slidge-powered "legacy module" looks like this:
60
+
61
+ ```python
62
+ from cool_chat_lib import CoolClient
63
+ from slidge import BaseGateway, BaseSession
64
+ from slidge.contact import LegacyContact
65
+ from slidge.group import LegacyMUC
66
+ from slidge.db import GatewayUser
67
+
68
+
69
+ class Gateway(BaseGateway):
70
+ # Various aspects of the gateway component are configured as class
71
+ # attributes of the concrete Gateway class
72
+ COMPONENT_NAME = "Gateway to the super duper chat network"
73
+
74
+
75
+ class Session(BaseSession):
76
+ def __init__(self, user: GatewayUser):
77
+ super().__init__(user)
78
+ self.legacy_client = CoolClient(
79
+ login=user.legacy_module_data["username"],
80
+ password=user.legacy_module_data["password"],
81
+ )
82
+
83
+ async def on_text(self, chat: LegacyContact | LegacyMUC, text: str, **kwargs):
84
+ """
85
+ Triggered when the slidge user sends an XMPP message through the gateway
86
+ """
87
+ self.legacy_client.send_message(text=text, destination=chat.legacy_id)
88
+ ```
89
+
90
+ There's more in [the tutorial](https://slidge.im/docs/slidge/main/dev/tutorial.html)!
91
+
92
+ Installation
93
+ ------------
94
+
95
+ ⚠️ Slidge is a lib for gateway developers, if you are an XMPP server admin and
96
+ want to install gateways on your server, you are looking for a
97
+ [slidge-based gateway](https://codeberg.org/explore/repos?q=slidge&topic=1).
98
+ or the
99
+ [slidge-debian](https://git.sr.ht/~nicoco/slidge-debian)
100
+ bundle.
101
+
102
+ [![pypi version](https://badge.fury.io/py/slidge.svg)](https://pypi.org/project/slidge/)
103
+
104
+ [![Packaging status](https://repology.org/badge/vertical-allrepos/slidge.svg)](https://repology.org/project/slidge/versions)
105
+
106
+ Slidge is available on
107
+ [codeberg](https://codeberg.org/slidge/slidge/releases)
108
+ and [pypi](https://pypi.org/project/slidge/).
109
+ Refer to [the docs](https://slidge.im/docs/slidge/main/admin/install.html) for details.
110
+
111
+ About privacy
112
+ -------------
113
+
114
+ Slidge (and most if not all XMPP gateway that I know of) will break
115
+ end-to-end encryption, or more precisely one of the 'ends' become the
116
+ gateway itself. If privacy is a major concern for you, my advice would
117
+ be to:
118
+
119
+ - use XMPP + OMEMO
120
+ - self-host your gateways
121
+ - have your gateways hosted by someone you know AFK and trust
122
+
123
+ Related projects
124
+ ----------------
125
+
126
+ - [Spectrum](https://www.spectrum.im/)
127
+ - [telegabber](https://dev.narayana.im/narayana/telegabber)
128
+ - [biboumi](https://biboumi.louiz.org/)
129
+ - [Bifröst](https://github.com/matrix-org/matrix-bifrost)
130
+ - [Mautrix](https://github.com/mautrix)
131
+ - [matterbridge](https://github.com/42wim/matterbridge)
132
+
133
+ Thank you, [Trung](https://trung.fun/), for the slidge logo!
@@ -1,12 +1,11 @@
1
- slidge/__init__.py,sha256=S0tUjqpZlzsr8G4Y_1Xt-KCYB07qaknTB0OwHU8k29U,1587
1
+ slidge/__init__.py,sha256=OKdIR1pz7HNSokVRB4cEyistagdPM9TDmaARJdnk0kc,1804
2
2
  slidge/__main__.py,sha256=ydjUklOoavS4YlGfjRX_8BQN2DaSbaXPMi47RkOgcFI,37
3
- slidge/__version__.py,sha256=Zirtlo5Bp-7eCiwh-NWenCh2s-v0fenKkV8OFlv_O1Y,165
4
- slidge/main.py,sha256=vMJzhvUxbeuIXuHxXXs6lm_ShBjXiS9B5Li5Ge4vWPo,6238
3
+ slidge/main.py,sha256=NpDKks_6Ib7thhTQu8gI_g3XifX1RNV19p6-Rtz2phY,6533
5
4
  slidge/migration.py,sha256=4BJmPIRB56_WIhRTqBFIIBXuvnhhBjjOMl4CE7jY6oc,1541
6
5
  slidge/py.typed,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
7
6
  slidge/command/__init__.py,sha256=UYf1mjCYbZ5G7PIgaFTWSQRAzEJkQ6dTH8Fu_e_XnO0,613
8
7
  slidge/command/adhoc.py,sha256=bYLXcYJjbqPE9nBhrEQevqYFh9AS7Ei3m1vTZBIggrc,10557
9
- slidge/command/admin.py,sha256=TYrzgCIhjcTIwl1IUaFlUd3D98SPyao10gB20zo8b3Q,6187
8
+ slidge/command/admin.py,sha256=DYN9yADZo2hKV0t20K2qnFPJHU98eKsaZTOqi1zdMys,6165
10
9
  slidge/command/base.py,sha256=EDcEl5dJcooSmLarXI2fmBq6QtU7h-7MOM3DDsxXmTU,13447
11
10
  slidge/command/categories.py,sha256=vF0KGDV9sEn8TNkcMoDRw-u3gEyNHSXghOU2JRHQtKs,351
12
11
  slidge/command/chat_command.py,sha256=z-4qp03rK7kCh3_kEozDViwkDg_hVjHvRCiYYJxedBQ,11153
@@ -17,9 +16,9 @@ slidge/contact/contact.py,sha256=CLWuNLvWuODi1mlT6MFGx9s3y8yGPM8ZEsH-Ih6QEn8,229
17
16
  slidge/contact/roster.py,sha256=19EYyX-usuevMob9AgnQmSt6APdE5MxMroHOYmVYt-w,10205
18
17
  slidge/core/__init__.py,sha256=RG7Jj5JCJERjhqJ31lOLYV-7bH_oblClQD1KF9LsTXo,68
19
18
  slidge/core/config.py,sha256=OjJfpXJaDhMxRB-vYA0cqkSf0fwMt-HMThM8GS1htCg,7964
20
- slidge/core/gateway.py,sha256=6qu3Ca5e3Kxtfm343zz43Iqjpw7cxZ1A7LC3bUdkDLo,37457
21
- slidge/core/pubsub.py,sha256=BoeYE__ptmRAn4x55Hn_6JWRA4nM-XJgDemG5Cy5kN4,11959
22
- slidge/core/session.py,sha256=Y6psOKm_lv4q7yXARiLuijvSebuS64NjqSNF1WARtHM,28439
19
+ slidge/core/gateway.py,sha256=Ghe2-bZ2XSeWC34uXO0D31yn04WbcwKH5pnDpPL4cVA,37606
20
+ slidge/core/pubsub.py,sha256=IAu-MV_ncrUk3SiVVWyzmKtv9I9yXBNAOE78GaowyYE,12156
21
+ slidge/core/session.py,sha256=Ie1a6bpUCC_HFvm98S-t03WG5JlOFG0SwbmGB2l9ZTc,28439
23
22
  slidge/core/dispatcher/__init__.py,sha256=1EXcjXietUKlxEqdrCWCV3xZ3q_DSsjHoqWrPMbtYao,84
24
23
  slidge/core/dispatcher/caps.py,sha256=vzCAXo_bhALuLEpJWtyJTzVfWx96g1AsWD8_wkoDl0Y,2028
25
24
  slidge/core/dispatcher/disco.py,sha256=j56VY9NIFzwPEWFKQQZ7YIqS9GdD-ZaF_K8a2L-JvRk,2006
@@ -40,7 +39,7 @@ slidge/core/dispatcher/muc/misc.py,sha256=bHBjMC-Pu3jR5hAPGMzXf-C05UbACIwg38YbJU
40
39
  slidge/core/dispatcher/muc/owner.py,sha256=1a6YV7b_mmi1jC6q1ko8weeL8imQA-s-hYGPLIHd10I,3308
41
40
  slidge/core/dispatcher/muc/ping.py,sha256=lb1VQPhiUPZ19KhbofRXMVCcY6wwQ2w-asnqtANaAwA,1660
42
41
  slidge/core/mixins/__init__.py,sha256=muReAzgvENgMvlfm0Fpe6BQFfm2EMjoDe9ZhGgo6Vig,627
43
- slidge/core/mixins/attachment.py,sha256=rZcipXiGgo-8klumBvfgrSsU_rmS6cl1zx-zev_FZRg,20174
42
+ slidge/core/mixins/attachment.py,sha256=diEmZAkc_fv9UEHzDXVHtRbE9-vhK8yN9ZtI9gL0JAY,20212
44
43
  slidge/core/mixins/avatar.py,sha256=BVOeH5j5tsPJ0IHUcB5ozpyh02TBPKiZMd9MYizDokA,8136
45
44
  slidge/core/mixins/base.py,sha256=MOd-pas38_52VawQVlxWtBtmTKC6My9G0ZaCeQxOJbs,748
46
45
  slidge/core/mixins/db.py,sha256=5Qpegd7D8e5TLXLLINYcf_DuVdN-7wNmsfztUuFYPcU,442
@@ -55,7 +54,7 @@ slidge/db/__init__.py,sha256=EBDH1JSEhgqYcli2Bw11CRC749wJk8AOucgBzmhDSvU,105
55
54
  slidge/db/avatar.py,sha256=z5e72STv8PdN6zkNyKlLqF7NFxHwCa6IjwgFpzu5ghE,8033
56
55
  slidge/db/meta.py,sha256=v1Jf-npZ28QwdGpsLQWLBHEbEP3-jnPrygRg05tJ_Iw,1831
57
56
  slidge/db/models.py,sha256=MSVNW04x05qfxahvjCYRDFjfFP-XXp-lOHnK5IqFCXw,14046
58
- slidge/db/store.py,sha256=AjbeYAbhd_7KHS094vTEPiuecu_ntIAlpyzsrCIjHHE,47155
57
+ slidge/db/store.py,sha256=P9gprCsRsbJjdzvyG2UKV5IHL6R0tWu-Q7t6mivqJVI,47206
59
58
  slidge/db/alembic/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
60
59
  slidge/db/alembic/env.py,sha256=hsBlRNs0zF5diSHGRSa8Fi3qRVQDA2rJdR41AEIdvxc,1642
61
60
  slidge/db/alembic/script.py.mako,sha256=MEqL-2qATlST9TAOeYgscMn1uy6HUS9NFvDgl93dMj8,635
@@ -80,9 +79,9 @@ slidge/db/alembic/versions/e91195719c2c_store_users_avatars_persistently.py,sha2
80
79
  slidge/group/__init__.py,sha256=yFt7cHqeaKIMN6f9ZyhhspOcJJvBtLedGv-iICG7lto,258
81
80
  slidge/group/archive.py,sha256=AUzVtXlHiCreyY3jp1XMt0G7LDNm-qOU-4CEPQ89ics,5445
82
81
  slidge/group/bookmarks.py,sha256=uGw_XtF0nloZ7rhNLdKM0nNZZb5C6SBfTsLyZryxjxY,6592
83
- slidge/group/participant.py,sha256=h9Cz4liCWzCaysvDk4wr8-zHvLOyIoM3vvQWzHCdpFE,17690
84
- slidge/group/room.py,sha256=UlmgIwZDjCyxXtAjQGVHo1xZoU9lq2WR7blwC9BAriY,49019
85
- slidge/slixfix/__init__.py,sha256=opamnCRI89KtCY2jfUrzij423hROgMF_Jw8Rrv1i0pw,2515
82
+ slidge/group/participant.py,sha256=YExXhm7FWK_G-_H6VJKFhJhA07l1KB7pZvD1xAYibj8,17730
83
+ slidge/group/room.py,sha256=c1SVpdrI7-xTr0UsF2n539R3iV8C4P5KZw6HhK5cPuU,49176
84
+ slidge/slixfix/__init__.py,sha256=su7mDAHgP3uU7bSxjK8dwW79k7KBLevJHdMQV8_33WA,4130
86
85
  slidge/slixfix/delivery_receipt.py,sha256=3bWdZH3-X3CZJXmnI_TpjkTUUK-EY4Ktm78lW0-40fc,1366
87
86
  slidge/slixfix/roster.py,sha256=KvDjh9q7pqaZf69H93okfib13cc95uVZUJ6rzpqmDaU,1704
88
87
  slidge/slixfix/link_preview/__init__.py,sha256=TDPTSEH5FQxgGpQpQIde-D72AHg-6YVWG-tOj4KpKmU,290
@@ -100,13 +99,14 @@ slidge/slixfix/xep_0292/__init__.py,sha256=_MvS9wGra6ig3P_dPAVlCPDJkiOFvUWGjaRsH
100
99
  slidge/slixfix/xep_0292/vcard4.py,sha256=jL-TOW3eG2QXLduSLNq03L8HoUNmvy8kTZI5ojvo6GE,358
101
100
  slidge/util/__init__.py,sha256=BELovoTMPcPPGz3D48esBr8A4BRRHXTvavfgnArBgEc,301
102
101
  slidge/util/archive_msg.py,sha256=xXAR0BI5r3d6KKWjae9594izCOv6iI03z2WLuTecNw8,1724
103
- slidge/util/conf.py,sha256=1j2OnOsCBar1tOObErhXR5RC3Vl3faliOZ1U8J3My58,6613
102
+ slidge/util/conf.py,sha256=yT_9Wino0xfhTvOjmmokt2PIQBTwBKVuVPWp7_7aoKU,6967
104
103
  slidge/util/jid_escaping.py,sha256=pWJTrB6-M923a_rEE-nxPmiDTOx9UCMa8UgE7JbLC0c,1066
105
104
  slidge/util/test.py,sha256=l1VHBsw5Uzk2t7wtkfb9kWvtehcYhw1t_d567JAJFKA,14135
106
- slidge/util/types.py,sha256=R_xfS5mRL0XUJIoDpnaAkZlTOoLPerduXBFftaVwIAI,5489
107
- slidge/util/util.py,sha256=IfyYLkujW6Pk0kvHpfkpQwejFDHSe5oR4_bczEUnhjs,9678
108
- slidge-0.2.8.dist-info/METADATA,sha256=_Ugh-_g55rL-uqTZ16WU-Nfo--8JO74xfLfIh75twEg,44841
109
- slidge-0.2.8.dist-info/WHEEL,sha256=jB7zZ3N9hIM9adW7qlTAyycLYW9npaWKLRzaoVcLKcM,91
110
- slidge-0.2.8.dist-info/entry_points.txt,sha256=py3_x834fFJ2TEzPd18Wt2DnysdAfuVqJ5zzBrXbAZs,44
111
- slidge-0.2.8.dist-info/top_level.txt,sha256=2LRjDYHaGZ5ieCMF8xy58JIiabRMzX-MGMbCZwfE17c,7
112
- slidge-0.2.8.dist-info/RECORD,,
105
+ slidge/util/types.py,sha256=5j0G22hhsh3PNhtpJaz2DVt5XINJznZjz0hqewPZoFo,5407
106
+ slidge/util/util.py,sha256=ZkQltO6JmfqZc9T-86XI6gAsZx9BLdF0CCurnxPRNRc,9329
107
+ slidge-0.2.10.dist-info/licenses/LICENSE,sha256=DZak_2itbUtvHzD3E7GNUYSRK6jdOJ-GqncQ2weavLA,34523
108
+ slidge-0.2.10.dist-info/METADATA,sha256=OFlStm_YVTPwHPhpu8z60NtKdi00uMU2Tp8crY5-6F8,5055
109
+ slidge-0.2.10.dist-info/WHEEL,sha256=CmyFI0kx5cdEMTLiONQRbGQwjIoR1aIYB7eCAQ4KPJ0,91
110
+ slidge-0.2.10.dist-info/entry_points.txt,sha256=py3_x834fFJ2TEzPd18Wt2DnysdAfuVqJ5zzBrXbAZs,44
111
+ slidge-0.2.10.dist-info/top_level.txt,sha256=2LRjDYHaGZ5ieCMF8xy58JIiabRMzX-MGMbCZwfE17c,7
112
+ slidge-0.2.10.dist-info/RECORD,,