slidge 0.1.3__py3-none-any.whl → 0.2.0a0__py3-none-any.whl
Sign up to get free protection for your applications and to get access to all the features.
- slidge/__init__.py +3 -5
- slidge/__main__.py +2 -196
- slidge/__version__.py +5 -0
- slidge/command/adhoc.py +8 -1
- slidge/command/admin.py +5 -6
- slidge/command/base.py +1 -2
- slidge/command/register.py +32 -16
- slidge/command/user.py +85 -5
- slidge/contact/contact.py +93 -31
- slidge/contact/roster.py +54 -39
- slidge/core/config.py +13 -7
- slidge/core/gateway/base.py +139 -34
- slidge/core/gateway/disco.py +2 -4
- slidge/core/gateway/mam.py +1 -4
- slidge/core/gateway/ping.py +2 -3
- slidge/core/gateway/presence.py +1 -1
- slidge/core/gateway/registration.py +32 -21
- slidge/core/gateway/search.py +3 -5
- slidge/core/gateway/session_dispatcher.py +100 -51
- slidge/core/gateway/vcard_temp.py +6 -4
- slidge/core/mixins/__init__.py +11 -1
- slidge/core/mixins/attachment.py +15 -10
- slidge/core/mixins/avatar.py +66 -18
- slidge/core/mixins/base.py +8 -2
- slidge/core/mixins/message.py +11 -7
- slidge/core/mixins/message_maker.py +17 -9
- slidge/core/mixins/presence.py +14 -4
- slidge/core/pubsub.py +54 -212
- slidge/core/session.py +65 -33
- slidge/db/__init__.py +4 -0
- slidge/db/alembic/env.py +64 -0
- slidge/db/alembic/script.py.mako +26 -0
- slidge/db/alembic/versions/09f27f098baa_add_missing_attributes_in_room.py +36 -0
- slidge/db/alembic/versions/29f5280c61aa_store_subject_setter_in_room.py +37 -0
- slidge/db/alembic/versions/8d2ced764698_rely_on_db_to_store_contacts_rooms_and_.py +133 -0
- slidge/db/alembic/versions/aa9d82a7f6ef_db_creation.py +76 -0
- slidge/db/alembic/versions/b33993e87db3_move_everything_to_persistent_db.py +214 -0
- slidge/db/alembic/versions/e91195719c2c_store_users_avatars_persistently.py +26 -0
- slidge/db/avatar.py +224 -0
- slidge/db/meta.py +65 -0
- slidge/db/models.py +365 -0
- slidge/db/store.py +976 -0
- slidge/group/archive.py +13 -14
- slidge/group/bookmarks.py +59 -56
- slidge/group/participant.py +77 -25
- slidge/group/room.py +242 -142
- slidge/main.py +201 -0
- slidge/migration.py +30 -0
- slidge/slixfix/__init__.py +35 -2
- slidge/slixfix/roster.py +11 -4
- slidge/slixfix/xep_0292/vcard4.py +1 -0
- slidge/util/db.py +1 -47
- slidge/util/test.py +21 -4
- slidge/util/types.py +24 -4
- {slidge-0.1.3.dist-info → slidge-0.2.0a0.dist-info}/METADATA +3 -1
- slidge-0.2.0a0.dist-info/RECORD +108 -0
- slidge/core/cache.py +0 -183
- slidge/util/schema.sql +0 -126
- slidge/util/sql.py +0 -508
- slidge-0.1.3.dist-info/RECORD +0 -96
- {slidge-0.1.3.dist-info → slidge-0.2.0a0.dist-info}/LICENSE +0 -0
- {slidge-0.1.3.dist-info → slidge-0.2.0a0.dist-info}/WHEEL +0 -0
- {slidge-0.1.3.dist-info → slidge-0.2.0a0.dist-info}/entry_points.txt +0 -0
slidge/core/gateway/base.py
CHANGED
@@ -8,7 +8,16 @@ import re
|
|
8
8
|
import tempfile
|
9
9
|
from copy import copy
|
10
10
|
from datetime import datetime
|
11
|
-
from typing import
|
11
|
+
from typing import (
|
12
|
+
TYPE_CHECKING,
|
13
|
+
Any,
|
14
|
+
Callable,
|
15
|
+
Collection,
|
16
|
+
Mapping,
|
17
|
+
Optional,
|
18
|
+
Sequence,
|
19
|
+
Union,
|
20
|
+
)
|
12
21
|
|
13
22
|
import aiohttp
|
14
23
|
import qrcode
|
@@ -24,11 +33,11 @@ from ...command.admin import Exec
|
|
24
33
|
from ...command.base import Command, FormField
|
25
34
|
from ...command.chat_command import ChatCommandProvider
|
26
35
|
from ...command.register import RegistrationType
|
36
|
+
from ...db import GatewayUser, SlidgeStore
|
37
|
+
from ...db.avatar import avatar_cache
|
27
38
|
from ...slixfix.roster import RosterBackend
|
28
39
|
from ...slixfix.xep_0292.vcard4 import VCard4Provider
|
29
40
|
from ...util import ABCSubclassableOnceAtMost
|
30
|
-
from ...util.db import GatewayUser, user_store
|
31
|
-
from ...util.sql import db
|
32
41
|
from ...util.types import AvatarType, MessageOrPresenceTypeVar
|
33
42
|
from .. import config
|
34
43
|
from ..mixins import MessageMixin
|
@@ -141,6 +150,23 @@ class BaseGateway(
|
|
141
150
|
)
|
142
151
|
REGISTRATION_QR_INSTRUCTIONS = "Flash this code or follow this link"
|
143
152
|
|
153
|
+
PREFERENCES = [
|
154
|
+
FormField(
|
155
|
+
var="sync_presence",
|
156
|
+
label="Propagate your XMPP presence to the legacy network.",
|
157
|
+
value="true",
|
158
|
+
required=True,
|
159
|
+
type="boolean",
|
160
|
+
),
|
161
|
+
FormField(
|
162
|
+
var="sync_avatar",
|
163
|
+
label="Propagate your XMPP avatar to the legacy network.",
|
164
|
+
value="true",
|
165
|
+
required=True,
|
166
|
+
type="boolean",
|
167
|
+
),
|
168
|
+
]
|
169
|
+
|
144
170
|
ROSTER_GROUP: str = "slidge"
|
145
171
|
"""
|
146
172
|
Name of the group assigned to a :class:`.LegacyContact` automagically
|
@@ -202,6 +228,47 @@ class BaseGateway(
|
|
202
228
|
mtype: MessageTypes = "chat"
|
203
229
|
is_group = False
|
204
230
|
_can_send_carbon = False
|
231
|
+
store: SlidgeStore
|
232
|
+
avatar_pk: int
|
233
|
+
|
234
|
+
AVATAR_ID_TYPE: Callable[[str], Any] = str
|
235
|
+
"""
|
236
|
+
Modify this if the legacy network uses unique avatar IDs that are not strings.
|
237
|
+
|
238
|
+
This is required because we store those IDs as TEXT in the persistent SQL DB.
|
239
|
+
The callable specified here will receive is responsible for converting the
|
240
|
+
serialised-as-text version of the avatar unique ID back to the proper type.
|
241
|
+
Common example: ``int``.
|
242
|
+
"""
|
243
|
+
# FIXME: do we really need this since we have session.xmpp_to_legacy_msg_id?
|
244
|
+
# (maybe we do)
|
245
|
+
LEGACY_MSG_ID_TYPE: Callable[[str], Any] = str
|
246
|
+
"""
|
247
|
+
Modify this if the legacy network uses unique message IDs that are not strings.
|
248
|
+
|
249
|
+
This is required because we store those IDs as TEXT in the persistent SQL DB.
|
250
|
+
The callable specified here will receive is responsible for converting the
|
251
|
+
serialised-as-text version of the message unique ID back to the proper type.
|
252
|
+
Common example: ``int``.
|
253
|
+
"""
|
254
|
+
LEGACY_CONTACT_ID_TYPE: Callable[[str], Any] = str
|
255
|
+
"""
|
256
|
+
Modify this if the legacy network uses unique contact IDs that are not strings.
|
257
|
+
|
258
|
+
This is required because we store those IDs as TEXT in the persistent SQL DB.
|
259
|
+
The callable specified here is responsible for converting the
|
260
|
+
serialised-as-text version of the contact unique ID back to the proper type.
|
261
|
+
Common example: ``int``.
|
262
|
+
"""
|
263
|
+
LEGACY_ROOM_ID_TYPE: Callable[[str], Any] = str
|
264
|
+
"""
|
265
|
+
Modify this if the legacy network uses unique room IDs that are not strings.
|
266
|
+
|
267
|
+
This is required because we store those IDs as TEXT in the persistent SQL DB.
|
268
|
+
The callable specified here is responsible for converting the
|
269
|
+
serialised-as-text version of the room unique ID back to the proper type.
|
270
|
+
Common example: ``int``.
|
271
|
+
"""
|
205
272
|
|
206
273
|
def __init__(self):
|
207
274
|
self.datetime_started = datetime.now()
|
@@ -222,7 +289,6 @@ class BaseGateway(
|
|
222
289
|
},
|
223
290
|
"xep_0100": {
|
224
291
|
"component_name": self.COMPONENT_NAME,
|
225
|
-
"user_store": user_store,
|
226
292
|
"type": self.COMPONENT_TYPE,
|
227
293
|
},
|
228
294
|
"xep_0184": {
|
@@ -241,11 +307,15 @@ class BaseGateway(
|
|
241
307
|
self.use_origin_id = False
|
242
308
|
|
243
309
|
self.jid_validator: re.Pattern = re.compile(config.USER_JID_VALIDATOR)
|
244
|
-
self.qr_pending_registrations = dict[str, asyncio.Future[
|
310
|
+
self.qr_pending_registrations = dict[str, asyncio.Future[Optional[dict]]]()
|
245
311
|
|
246
312
|
self.session_cls: BaseSession = BaseSession.get_unique_subclass()
|
247
313
|
self.session_cls.xmpp = self
|
248
314
|
|
315
|
+
from ...group.room import LegacyMUC
|
316
|
+
|
317
|
+
LegacyMUC.get_unique_subclass().xmpp = self
|
318
|
+
|
249
319
|
self.get_session_from_stanza: Callable[
|
250
320
|
[Union[Message, Presence, Iq]], BaseSession
|
251
321
|
] = self.session_cls.from_stanza # type: ignore
|
@@ -255,7 +325,7 @@ class BaseGateway(
|
|
255
325
|
|
256
326
|
self.register_plugins()
|
257
327
|
self.__register_slixmpp_events()
|
258
|
-
self.roster.set_backend(RosterBackend)
|
328
|
+
self.roster.set_backend(RosterBackend(self))
|
259
329
|
|
260
330
|
self.register_plugin("pubsub", {"component_name": self.COMPONENT_NAME})
|
261
331
|
self.pubsub: PubSubComponent = self["pubsub"]
|
@@ -294,7 +364,14 @@ class BaseGateway(
|
|
294
364
|
|
295
365
|
self.__register_commands()
|
296
366
|
|
297
|
-
|
367
|
+
self.__mam_cleanup_task = self.loop.create_task(self.__mam_cleanup())
|
368
|
+
|
369
|
+
async def __mam_cleanup(self):
|
370
|
+
if not config.MAM_MAX_DAYS:
|
371
|
+
return
|
372
|
+
while True:
|
373
|
+
await asyncio.sleep(3600 * 6)
|
374
|
+
self.store.mam.nuke_older_than(config.MAM_MAX_DAYS)
|
298
375
|
|
299
376
|
def __register_commands(self):
|
300
377
|
for cls in Command.subclasses:
|
@@ -303,7 +380,7 @@ class BaseGateway(
|
|
303
380
|
continue
|
304
381
|
if cls is Exec:
|
305
382
|
if config.DEV_MODE:
|
306
|
-
log.warning("/!\ DEV MODE ENABLED /!\\")
|
383
|
+
log.warning(r"/!\ DEV MODE ENABLED /!\\")
|
307
384
|
else:
|
308
385
|
continue
|
309
386
|
c = cls(self)
|
@@ -356,7 +433,7 @@ class BaseGateway(
|
|
356
433
|
mfrom = msg.get_from()
|
357
434
|
resource = mfrom.resource
|
358
435
|
try:
|
359
|
-
muc.
|
436
|
+
muc.remove_user_resource(resource)
|
360
437
|
except KeyError:
|
361
438
|
# this actually happens quite frequently on for both beagle and monal
|
362
439
|
# (not sure why?), but is of no consequence
|
@@ -374,11 +451,15 @@ class BaseGateway(
|
|
374
451
|
await disco.del_feature(feature="urn:xmpp:http:upload:0", jid=self.boundjid)
|
375
452
|
await self.plugin["xep_0115"].update_caps(jid=self.boundjid)
|
376
453
|
|
377
|
-
|
378
|
-
|
379
|
-
|
454
|
+
if self.COMPONENT_AVATAR:
|
455
|
+
cached_avatar = await avatar_cache.convert_or_get(
|
456
|
+
self.COMPONENT_AVATAR, None
|
457
|
+
)
|
458
|
+
self.avatar_pk = cached_avatar.pk
|
459
|
+
else:
|
460
|
+
cached_avatar = None
|
380
461
|
|
381
|
-
for user in
|
462
|
+
for user in self.store.users.get_all():
|
382
463
|
# TODO: before this, we should check if the user has removed us from their roster
|
383
464
|
# while we were offline and trigger unregister from there. Presence probe does not seem
|
384
465
|
# to work in this case, there must be another way. privileged entity could be used
|
@@ -396,10 +477,14 @@ class BaseGateway(
|
|
396
477
|
)
|
397
478
|
continue
|
398
479
|
self.send_presence(
|
399
|
-
pto=user.
|
480
|
+
pto=user.jid.bare, ptype="probe"
|
400
481
|
) # ensure we get all resources for user
|
401
482
|
session = self.session_cls.from_user(user)
|
402
483
|
session.create_task(self.__login_wrap(session))
|
484
|
+
if cached_avatar is not None:
|
485
|
+
await self.pubsub.broadcast_avatar(
|
486
|
+
self.boundjid.bare, session.user_jid, cached_avatar
|
487
|
+
)
|
403
488
|
|
404
489
|
log.info("Slidge has successfully started")
|
405
490
|
|
@@ -460,7 +545,7 @@ class BaseGateway(
|
|
460
545
|
try:
|
461
546
|
status = await session.login()
|
462
547
|
except Exception as e:
|
463
|
-
log.warning("Login problem for %s", session.
|
548
|
+
log.warning("Login problem for %s", session.user_jid, exc_info=e)
|
464
549
|
log.exception(e)
|
465
550
|
session.send_gateway_status(f"Could not login: {e}", show="busy")
|
466
551
|
session.send_gateway_message(
|
@@ -469,7 +554,7 @@ class BaseGateway(
|
|
469
554
|
)
|
470
555
|
return
|
471
556
|
|
472
|
-
log.info("Login success for %s", session.
|
557
|
+
log.info("Login success for %s", session.user_jid)
|
473
558
|
session.logged = True
|
474
559
|
session.send_gateway_status("Syncing contacts…", show="dnd")
|
475
560
|
await session.contacts.fill()
|
@@ -483,19 +568,18 @@ class BaseGateway(
|
|
483
568
|
for c in session.contacts:
|
484
569
|
# we need to receive presences directed at the contacts, in
|
485
570
|
# order to send pubsub events for their +notify features
|
486
|
-
self.send_presence(pfrom=c.jid, pto=session.
|
571
|
+
self.send_presence(pfrom=c.jid, pto=session.user_jid.bare, ptype="probe")
|
487
572
|
if status is None:
|
488
573
|
session.send_gateway_status("Logged in", show="chat")
|
489
574
|
else:
|
490
575
|
session.send_gateway_status(status, show="chat")
|
491
|
-
|
492
|
-
|
493
|
-
session.create_task(self.__fetch_user_avatar(session))
|
576
|
+
if session.user.preferences.get("sync_avatar", False):
|
577
|
+
session.create_task(self.fetch_user_avatar(session))
|
494
578
|
|
495
|
-
async def
|
579
|
+
async def fetch_user_avatar(self, session: BaseSession):
|
496
580
|
try:
|
497
581
|
iq = await self.xmpp.plugin["xep_0060"].get_items(
|
498
|
-
session.
|
582
|
+
session.user_jid.bare,
|
499
583
|
self.xmpp.plugin["xep_0084"].stanza.MetaData.namespace,
|
500
584
|
ifrom=self.boundjid.bare,
|
501
585
|
)
|
@@ -577,7 +661,7 @@ class BaseGateway(
|
|
577
661
|
)
|
578
662
|
|
579
663
|
ifrom = iq.get_from()
|
580
|
-
user =
|
664
|
+
user = self.store.users.get(ifrom)
|
581
665
|
if user is None:
|
582
666
|
raise XMPPError("registration-required")
|
583
667
|
|
@@ -629,7 +713,7 @@ class BaseGateway(
|
|
629
713
|
async def make_registration_form(self, _jid, _node, _ifrom, iq: Iq):
|
630
714
|
self.raise_if_not_allowed_jid(iq.get_from())
|
631
715
|
reg = iq["register"]
|
632
|
-
user =
|
716
|
+
user = self.store.users.get_by_stanza(iq)
|
633
717
|
log.debug("User found: %s", user)
|
634
718
|
|
635
719
|
form = reg["form"]
|
@@ -675,18 +759,20 @@ class BaseGateway(
|
|
675
759
|
reply.set_payload(reg)
|
676
760
|
return reply
|
677
761
|
|
678
|
-
async def user_prevalidate(
|
762
|
+
async def user_prevalidate(
|
763
|
+
self, ifrom: JID, form_dict: dict[str, Optional[str]]
|
764
|
+
) -> Optional[Mapping]:
|
679
765
|
# Pre validate a registration form using the content of self.REGISTRATION_FIELDS
|
680
766
|
# before passing it to the plugin custom validation logic.
|
681
767
|
for field in self.REGISTRATION_FIELDS:
|
682
768
|
if field.required and not form_dict.get(field.var):
|
683
769
|
raise ValueError(f"Missing field: '{field.label}'")
|
684
770
|
|
685
|
-
await self.validate(ifrom, form_dict)
|
771
|
+
return await self.validate(ifrom, form_dict)
|
686
772
|
|
687
773
|
async def validate(
|
688
774
|
self, user_jid: JID, registration_form: dict[str, Optional[str]]
|
689
|
-
):
|
775
|
+
) -> Optional[Mapping]:
|
690
776
|
"""
|
691
777
|
Validate a user's initial registration form.
|
692
778
|
|
@@ -706,11 +792,19 @@ class BaseGateway(
|
|
706
792
|
|
707
793
|
:param user_jid: JID of the user that has just registered
|
708
794
|
:param registration_form: A dict where keys are the :attr:`.FormField.var` attributes
|
709
|
-
|
795
|
+
of the :attr:`.BaseGateway.REGISTRATION_FIELDS` iterable.
|
796
|
+
This dict can be modified and will be accessible as the ``legacy_module_data``
|
797
|
+
of the
|
798
|
+
|
799
|
+
:return : A dict that will be stored as the persistent "legacy_module_data"
|
800
|
+
for this user. If you don't return anything here, the whole registration_form
|
801
|
+
content will be stored.
|
710
802
|
"""
|
711
803
|
raise NotImplementedError
|
712
804
|
|
713
|
-
async def validate_two_factor_code(
|
805
|
+
async def validate_two_factor_code(
|
806
|
+
self, user: GatewayUser, code: str
|
807
|
+
) -> Optional[dict]:
|
714
808
|
"""
|
715
809
|
Called when the user enters their 2FA code.
|
716
810
|
|
@@ -725,6 +819,9 @@ class BaseGateway(
|
|
725
819
|
:attr:`.registration_form` attributes to get what you need.
|
726
820
|
:param code: The code they entered, either via "chatbot" message or
|
727
821
|
adhoc command
|
822
|
+
|
823
|
+
:return : A dict which keys and values will be added to the persistent "legacy_module_data"
|
824
|
+
for this user.
|
728
825
|
"""
|
729
826
|
raise NotImplementedError
|
730
827
|
|
@@ -744,7 +841,10 @@ class BaseGateway(
|
|
744
841
|
raise NotImplementedError
|
745
842
|
|
746
843
|
async def confirm_qr(
|
747
|
-
self,
|
844
|
+
self,
|
845
|
+
user_bare_jid: str,
|
846
|
+
exception: Optional[Exception] = None,
|
847
|
+
legacy_data: Optional[dict] = None,
|
748
848
|
):
|
749
849
|
"""
|
750
850
|
This method is meant to be called to finalize QR code-based registration
|
@@ -757,10 +857,12 @@ class BaseGateway(
|
|
757
857
|
:class:`GatewayUser` instance
|
758
858
|
:param exception: Optionally, an XMPPError to be raised to **not** confirm
|
759
859
|
QR code flashing.
|
860
|
+
:param legacy_data: dict which keys and values will be added to the persistent
|
861
|
+
"legacy_module_data" for this user.
|
760
862
|
"""
|
761
863
|
fut = self.qr_pending_registrations[user_bare_jid]
|
762
864
|
if exception is None:
|
763
|
-
fut.set_result(
|
865
|
+
fut.set_result(legacy_data)
|
764
866
|
else:
|
765
867
|
fut.set_exception(exception)
|
766
868
|
|
@@ -771,14 +873,17 @@ class BaseGateway(
|
|
771
873
|
async def unregister(self, user: GatewayUser):
|
772
874
|
"""
|
773
875
|
Optionally override this if you need to clean additional
|
774
|
-
stuff after a user has been removed from the
|
876
|
+
stuff after a user has been removed from the persistent user store.
|
775
877
|
|
776
878
|
By default, this just calls :meth:`BaseSession.logout`.
|
777
879
|
|
778
880
|
:param user:
|
779
881
|
"""
|
780
882
|
session = self.get_session_from_user(user)
|
781
|
-
|
883
|
+
try:
|
884
|
+
await session.logout()
|
885
|
+
except NotImplementedError:
|
886
|
+
pass
|
782
887
|
|
783
888
|
async def input(
|
784
889
|
self, jid: JID, text=None, mtype: MessageTypes = "chat", **msg_kwargs
|
@@ -825,7 +930,7 @@ class BaseGateway(
|
|
825
930
|
# """
|
826
931
|
log.debug("Shutting down")
|
827
932
|
tasks = []
|
828
|
-
for user in
|
933
|
+
for user in self.store.users.get_all():
|
829
934
|
tasks.append(self.session_cls.from_jid(user.jid).shutdown())
|
830
935
|
self.send_presence(ptype="unavailable", pto=user.jid)
|
831
936
|
return tasks
|
slidge/core/gateway/disco.py
CHANGED
@@ -5,8 +5,6 @@ from slixmpp.exceptions import XMPPError
|
|
5
5
|
from slixmpp.plugins.xep_0030.stanza.items import DiscoItems
|
6
6
|
from slixmpp.types import OptJid
|
7
7
|
|
8
|
-
from ...util.db import user_store
|
9
|
-
|
10
8
|
if TYPE_CHECKING:
|
11
9
|
from .base import BaseGateway
|
12
10
|
|
@@ -38,7 +36,7 @@ class Disco:
|
|
38
36
|
if ifrom is None:
|
39
37
|
raise XMPPError("subscription-required")
|
40
38
|
|
41
|
-
user =
|
39
|
+
user = self.xmpp.store.users.get(ifrom)
|
42
40
|
if user is None:
|
43
41
|
raise XMPPError("registration-required")
|
44
42
|
session = self.xmpp.get_session_from_user(user)
|
@@ -63,7 +61,7 @@ class Disco:
|
|
63
61
|
if jid != self.xmpp.boundjid.bare:
|
64
62
|
return DiscoItems()
|
65
63
|
|
66
|
-
user =
|
64
|
+
user = self.xmpp.store.users.get(ifrom)
|
67
65
|
if user is None:
|
68
66
|
raise XMPPError("registration-required")
|
69
67
|
|
slidge/core/gateway/mam.py
CHANGED
@@ -3,8 +3,6 @@ from typing import TYPE_CHECKING
|
|
3
3
|
from slixmpp import CoroutineCallback, Iq, StanzaPath
|
4
4
|
from slixmpp.exceptions import XMPPError
|
5
5
|
|
6
|
-
from ...util.db import user_store
|
7
|
-
|
8
6
|
if TYPE_CHECKING:
|
9
7
|
from .base import BaseGateway
|
10
8
|
|
@@ -46,8 +44,7 @@ class Mam:
|
|
46
44
|
text="No MAM on the component itself, use a JID with a resource"
|
47
45
|
)
|
48
46
|
|
49
|
-
|
50
|
-
user = user_store.get_by_jid(ifrom)
|
47
|
+
user = self.xmpp.store.users.get(iq.get_from())
|
51
48
|
if user is None:
|
52
49
|
raise XMPPError("registration-required")
|
53
50
|
|
slidge/core/gateway/ping.py
CHANGED
@@ -4,7 +4,6 @@ from slixmpp import CoroutineCallback, Iq, StanzaPath
|
|
4
4
|
from slixmpp.exceptions import XMPPError
|
5
5
|
|
6
6
|
from ...group import LegacyMUC
|
7
|
-
from ...util.db import user_store
|
8
7
|
|
9
8
|
if TYPE_CHECKING:
|
10
9
|
from .base import BaseGateway
|
@@ -31,7 +30,7 @@ class Ping:
|
|
31
30
|
iq.reply().send()
|
32
31
|
|
33
32
|
ifrom = iq.get_from()
|
34
|
-
user =
|
33
|
+
user = self.xmpp.store.users.get(ifrom)
|
35
34
|
if user is None:
|
36
35
|
raise XMPPError("registration-required")
|
37
36
|
|
@@ -60,7 +59,7 @@ class Ping:
|
|
60
59
|
|
61
60
|
@staticmethod
|
62
61
|
def __handle_muc_ping(muc: LegacyMUC, iq: Iq):
|
63
|
-
if iq.get_from().resource in muc.
|
62
|
+
if iq.get_from().resource in muc.get_user_resources():
|
64
63
|
iq.reply().send()
|
65
64
|
else:
|
66
65
|
raise XMPPError("not-acceptable", etype="cancel", by=muc.jid)
|
slidge/core/gateway/presence.py
CHANGED
@@ -47,7 +47,7 @@ class PresenceHandlerMixin:
|
|
47
47
|
contact = await self.__get_contact(pres)
|
48
48
|
except _IsDirectedAtComponent as e:
|
49
49
|
e.session.send_gateway_message("Bye bye!")
|
50
|
-
await e.session.kill_by_jid(e.session.
|
50
|
+
await e.session.kill_by_jid(e.session.user_jid)
|
51
51
|
return
|
52
52
|
|
53
53
|
contact.is_friend = False
|
@@ -1,9 +1,12 @@
|
|
1
|
+
from __future__ import annotations
|
2
|
+
|
1
3
|
import logging
|
2
4
|
from typing import TYPE_CHECKING, Optional
|
3
5
|
|
4
6
|
from slixmpp import JID, Iq
|
7
|
+
from slixmpp.exceptions import XMPPError
|
5
8
|
|
6
|
-
from ...
|
9
|
+
from ...db import GatewayUser
|
7
10
|
|
8
11
|
if TYPE_CHECKING:
|
9
12
|
from .base import BaseGateway
|
@@ -12,42 +15,50 @@ if TYPE_CHECKING:
|
|
12
15
|
class Registration:
|
13
16
|
def __init__(self, xmpp: "BaseGateway"):
|
14
17
|
self.xmpp = xmpp
|
15
|
-
xmpp["xep_0077"].api.register(
|
16
|
-
user_store.get,
|
17
|
-
"user_get",
|
18
|
-
)
|
19
|
-
xmpp["xep_0077"].api.register(
|
20
|
-
user_store.remove,
|
21
|
-
"user_remove",
|
22
|
-
)
|
23
18
|
xmpp["xep_0077"].api.register(
|
24
19
|
self.xmpp.make_registration_form, "make_registration_form"
|
25
20
|
)
|
21
|
+
xmpp["xep_0077"].api.register(self._user_get, "user_get")
|
26
22
|
xmpp["xep_0077"].api.register(self._user_validate, "user_validate")
|
27
23
|
xmpp["xep_0077"].api.register(self._user_modify, "user_modify")
|
24
|
+
# kept for slixmpp internal API compat
|
25
|
+
# TODO: either fully use slixmpp internal API or rewrite registration without it at all
|
26
|
+
xmpp["xep_0077"].api.register(lambda *a: None, "user_remove")
|
27
|
+
|
28
|
+
def get_user(self, jid: JID) -> GatewayUser | None:
|
29
|
+
return self.xmpp.store.users.get(jid)
|
30
|
+
|
31
|
+
async def _user_get(
|
32
|
+
self, _gateway_jid, _node, ifrom: JID, iq: Iq
|
33
|
+
) -> GatewayUser | None:
|
34
|
+
if ifrom is None:
|
35
|
+
ifrom = iq.get_from()
|
36
|
+
return self.get_user(ifrom)
|
28
37
|
|
29
38
|
async def _user_validate(self, _gateway_jid, _node, ifrom: JID, iq: Iq):
|
30
|
-
"""
|
31
|
-
SliXMPP internal API stuff
|
32
|
-
"""
|
33
39
|
xmpp = self.xmpp
|
34
40
|
log.debug("User validate: %s", ifrom.bare)
|
35
41
|
form_dict = {f.var: iq.get(f.var) for f in xmpp.REGISTRATION_FIELDS}
|
36
42
|
xmpp.raise_if_not_allowed_jid(ifrom)
|
37
|
-
await xmpp.user_prevalidate(ifrom, form_dict)
|
38
|
-
|
39
|
-
|
43
|
+
legacy_module_data = await xmpp.user_prevalidate(ifrom, form_dict)
|
44
|
+
if legacy_module_data is None:
|
45
|
+
legacy_module_data = form_dict
|
46
|
+
user = self.xmpp.store.users.new(
|
47
|
+
jid=ifrom,
|
48
|
+
legacy_module_data=legacy_module_data, # type:ignore
|
49
|
+
)
|
50
|
+
log.info("New user: %s", user)
|
40
51
|
|
41
52
|
async def _user_modify(
|
42
53
|
self, _gateway_jid, _node, ifrom: JID, form_dict: dict[str, Optional[str]]
|
43
54
|
):
|
44
|
-
"""
|
45
|
-
SliXMPP internal API stuff
|
46
|
-
"""
|
47
|
-
user = user_store.get_by_jid(ifrom)
|
48
|
-
log.debug("Modify user: %s", user)
|
49
55
|
await self.xmpp.user_prevalidate(ifrom, form_dict)
|
50
|
-
|
56
|
+
log.debug("Modify user: %s", ifrom)
|
57
|
+
user = self.xmpp.store.users.get(ifrom)
|
58
|
+
if user is None:
|
59
|
+
raise XMPPError("internal-server-error", "User not found")
|
60
|
+
user.legacy_module_data.update(form_dict)
|
61
|
+
self.xmpp.store.users.update(user)
|
51
62
|
|
52
63
|
|
53
64
|
log = logging.getLogger(__name__)
|
slidge/core/gateway/search.py
CHANGED
@@ -3,8 +3,6 @@ from typing import TYPE_CHECKING
|
|
3
3
|
from slixmpp import JID, CoroutineCallback, Iq, StanzaPath
|
4
4
|
from slixmpp.exceptions import XMPPError
|
5
5
|
|
6
|
-
from ...util.db import user_store
|
7
|
-
|
8
6
|
if TYPE_CHECKING:
|
9
7
|
from .base import BaseGateway
|
10
8
|
|
@@ -29,7 +27,7 @@ class Search:
|
|
29
27
|
"""
|
30
28
|
Prepare the search form using :attr:`.BaseSession.SEARCH_FIELDS`
|
31
29
|
"""
|
32
|
-
user =
|
30
|
+
user = self.xmpp.store.users.get(ifrom)
|
33
31
|
if user is None:
|
34
32
|
raise XMPPError(text="Search is only allowed for registered users")
|
35
33
|
|
@@ -47,7 +45,7 @@ class Search:
|
|
47
45
|
"""
|
48
46
|
Handles a search request
|
49
47
|
"""
|
50
|
-
user =
|
48
|
+
user = self.xmpp.store.users.get(ifrom)
|
51
49
|
if user is None:
|
52
50
|
raise XMPPError(text="Search is only allowed for registered users")
|
53
51
|
|
@@ -70,7 +68,7 @@ class Search:
|
|
70
68
|
if iq.get_to() != self.xmpp.boundjid.bare:
|
71
69
|
raise XMPPError("bad-request", "This can only be used on the component JID")
|
72
70
|
|
73
|
-
user =
|
71
|
+
user = self.xmpp.store.users.get(iq.get_from())
|
74
72
|
if user is None:
|
75
73
|
raise XMPPError("not-authorized", "Register to the gateway first")
|
76
74
|
|