deltachat-rpc-client 1.160.0__tar.gz → 2.1.0__tar.gz
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.
- {deltachat_rpc_client-1.160.0/src/deltachat_rpc_client.egg-info → deltachat_rpc_client-2.1.0}/PKG-INFO +1 -1
- {deltachat_rpc_client-1.160.0 → deltachat_rpc_client-2.1.0}/pyproject.toml +1 -1
- {deltachat_rpc_client-1.160.0 → deltachat_rpc_client-2.1.0}/src/deltachat_rpc_client/account.py +37 -1
- {deltachat_rpc_client-1.160.0 → deltachat_rpc_client-2.1.0}/src/deltachat_rpc_client/const.py +32 -1
- {deltachat_rpc_client-1.160.0 → deltachat_rpc_client-2.1.0}/src/deltachat_rpc_client/contact.py +0 -4
- {deltachat_rpc_client-1.160.0 → deltachat_rpc_client-2.1.0}/src/deltachat_rpc_client/message.py +6 -1
- {deltachat_rpc_client-1.160.0 → deltachat_rpc_client-2.1.0/src/deltachat_rpc_client.egg-info}/PKG-INFO +1 -1
- {deltachat_rpc_client-1.160.0 → deltachat_rpc_client-2.1.0}/tests/test_securejoin.py +21 -120
- {deltachat_rpc_client-1.160.0 → deltachat_rpc_client-2.1.0}/tests/test_something.py +55 -3
- {deltachat_rpc_client-1.160.0 → deltachat_rpc_client-2.1.0}/LICENSE +0 -0
- {deltachat_rpc_client-1.160.0 → deltachat_rpc_client-2.1.0}/README.md +0 -0
- {deltachat_rpc_client-1.160.0 → deltachat_rpc_client-2.1.0}/setup.cfg +0 -0
- {deltachat_rpc_client-1.160.0 → deltachat_rpc_client-2.1.0}/src/deltachat_rpc_client/__init__.py +0 -0
- {deltachat_rpc_client-1.160.0 → deltachat_rpc_client-2.1.0}/src/deltachat_rpc_client/_utils.py +0 -0
- {deltachat_rpc_client-1.160.0 → deltachat_rpc_client-2.1.0}/src/deltachat_rpc_client/chat.py +0 -0
- {deltachat_rpc_client-1.160.0 → deltachat_rpc_client-2.1.0}/src/deltachat_rpc_client/client.py +0 -0
- {deltachat_rpc_client-1.160.0 → deltachat_rpc_client-2.1.0}/src/deltachat_rpc_client/deltachat.py +0 -0
- {deltachat_rpc_client-1.160.0 → deltachat_rpc_client-2.1.0}/src/deltachat_rpc_client/events.py +0 -0
- {deltachat_rpc_client-1.160.0 → deltachat_rpc_client-2.1.0}/src/deltachat_rpc_client/py.typed +0 -0
- {deltachat_rpc_client-1.160.0 → deltachat_rpc_client-2.1.0}/src/deltachat_rpc_client/pytestplugin.py +0 -0
- {deltachat_rpc_client-1.160.0 → deltachat_rpc_client-2.1.0}/src/deltachat_rpc_client/rpc.py +0 -0
- {deltachat_rpc_client-1.160.0 → deltachat_rpc_client-2.1.0}/src/deltachat_rpc_client.egg-info/SOURCES.txt +0 -0
- {deltachat_rpc_client-1.160.0 → deltachat_rpc_client-2.1.0}/src/deltachat_rpc_client.egg-info/dependency_links.txt +0 -0
- {deltachat_rpc_client-1.160.0 → deltachat_rpc_client-2.1.0}/src/deltachat_rpc_client.egg-info/entry_points.txt +0 -0
- {deltachat_rpc_client-1.160.0 → deltachat_rpc_client-2.1.0}/src/deltachat_rpc_client.egg-info/top_level.txt +0 -0
- {deltachat_rpc_client-1.160.0 → deltachat_rpc_client-2.1.0}/tests/test_account_events.py +0 -0
- {deltachat_rpc_client-1.160.0 → deltachat_rpc_client-2.1.0}/tests/test_chatlist_events.py +0 -0
- {deltachat_rpc_client-1.160.0 → deltachat_rpc_client-2.1.0}/tests/test_iroh_webxdc.py +0 -0
- {deltachat_rpc_client-1.160.0 → deltachat_rpc_client-2.1.0}/tests/test_key_transfer.py +0 -0
- {deltachat_rpc_client-1.160.0 → deltachat_rpc_client-2.1.0}/tests/test_multidevice.py +0 -0
- {deltachat_rpc_client-1.160.0 → deltachat_rpc_client-2.1.0}/tests/test_vcard.py +0 -0
- {deltachat_rpc_client-1.160.0 → deltachat_rpc_client-2.1.0}/tests/test_webxdc.py +0 -0
{deltachat_rpc_client-1.160.0 → deltachat_rpc_client-2.1.0}/src/deltachat_rpc_client/account.py
RENAMED
|
@@ -288,10 +288,46 @@ class Account:
|
|
|
288
288
|
def create_group(self, name: str, protect: bool = False) -> Chat:
|
|
289
289
|
"""Create a new group chat.
|
|
290
290
|
|
|
291
|
-
After creation,
|
|
291
|
+
After creation,
|
|
292
|
+
the group has only self-contact as member one member (see `SpecialContactId.SELF`)
|
|
293
|
+
and is in _unpromoted_ state.
|
|
294
|
+
This means, you can add or remove members, change the name,
|
|
295
|
+
the group image and so on without messages being sent to all group members.
|
|
296
|
+
|
|
297
|
+
This changes as soon as the first message is sent to the group members
|
|
298
|
+
and the group becomes _promoted_.
|
|
299
|
+
After that, all changes are synced with all group members
|
|
300
|
+
by sending status message.
|
|
301
|
+
|
|
302
|
+
To check, if a chat is still unpromoted, you can look at the `is_unpromoted` property of a chat
|
|
303
|
+
(see `get_full_snapshot()` / `get_basic_snapshot()`).
|
|
304
|
+
This may be useful if you want to show some help for just created groups.
|
|
305
|
+
|
|
306
|
+
:param protect: If set to 1 the function creates group with protection initially enabled.
|
|
307
|
+
Only verified members are allowed in these groups
|
|
308
|
+
and end-to-end-encryption is always enabled.
|
|
292
309
|
"""
|
|
293
310
|
return Chat(self, self._rpc.create_group_chat(self.id, name, protect))
|
|
294
311
|
|
|
312
|
+
def create_broadcast(self, name: str) -> Chat:
|
|
313
|
+
"""Create a new **broadcast channel**
|
|
314
|
+
(called "Channel" in the UI).
|
|
315
|
+
|
|
316
|
+
Broadcast channels are similar to groups on the sending device,
|
|
317
|
+
however, recipients get the messages in a read-only chat
|
|
318
|
+
and will not see who the other members are.
|
|
319
|
+
|
|
320
|
+
Called `broadcast` here rather than `channel`,
|
|
321
|
+
because the word "channel" already appears a lot in the code,
|
|
322
|
+
which would make it hard to grep for it.
|
|
323
|
+
|
|
324
|
+
After creation, the chat contains no recipients and is in _unpromoted_ state;
|
|
325
|
+
see `create_group()` for more information on the unpromoted state.
|
|
326
|
+
|
|
327
|
+
Returns the created chat.
|
|
328
|
+
"""
|
|
329
|
+
return Chat(self, self._rpc.create_broadcast(self.id, name))
|
|
330
|
+
|
|
295
331
|
def get_chat_by_id(self, chat_id: int) -> Chat:
|
|
296
332
|
"""Return the Chat instance with the given ID."""
|
|
297
333
|
return Chat(self, chat_id)
|
{deltachat_rpc_client-1.160.0 → deltachat_rpc_client-2.1.0}/src/deltachat_rpc_client/const.py
RENAMED
|
@@ -9,6 +9,7 @@ class ContactFlag(IntEnum):
|
|
|
9
9
|
"""Bit flags for get_contacts() method."""
|
|
10
10
|
|
|
11
11
|
ADD_SELF = 0x02
|
|
12
|
+
ADDRESS = 0x04
|
|
12
13
|
|
|
13
14
|
|
|
14
15
|
class ChatlistFlag(IntEnum):
|
|
@@ -90,10 +91,40 @@ class ChatType(IntEnum):
|
|
|
90
91
|
"""Chat type."""
|
|
91
92
|
|
|
92
93
|
UNDEFINED = 0
|
|
94
|
+
|
|
93
95
|
SINGLE = 100
|
|
96
|
+
"""1:1 chat, i.e. a direct chat with a single contact"""
|
|
97
|
+
|
|
94
98
|
GROUP = 120
|
|
99
|
+
|
|
95
100
|
MAILINGLIST = 140
|
|
96
|
-
|
|
101
|
+
|
|
102
|
+
OUT_BROADCAST = 160
|
|
103
|
+
"""Outgoing broadcast channel, called "Channel" in the UI.
|
|
104
|
+
|
|
105
|
+
The user can send into this channel,
|
|
106
|
+
and all recipients will receive messages
|
|
107
|
+
in an `IN_BROADCAST`.
|
|
108
|
+
|
|
109
|
+
Called `broadcast` here rather than `channel`,
|
|
110
|
+
because the word "channel" already appears a lot in the code,
|
|
111
|
+
which would make it hard to grep for it.
|
|
112
|
+
"""
|
|
113
|
+
|
|
114
|
+
IN_BROADCAST = 165
|
|
115
|
+
"""Incoming broadcast channel, called "Channel" in the UI.
|
|
116
|
+
|
|
117
|
+
This channel is read-only,
|
|
118
|
+
and we do not know who the other recipients are.
|
|
119
|
+
|
|
120
|
+
This is similar to a `MAILINGLIST`,
|
|
121
|
+
with the main difference being that
|
|
122
|
+
`IN_BROADCAST`s are encrypted.
|
|
123
|
+
|
|
124
|
+
Called `broadcast` here rather than `channel`,
|
|
125
|
+
because the word "channel" already appears a lot in the code,
|
|
126
|
+
which would make it hard to grep for it.
|
|
127
|
+
"""
|
|
97
128
|
|
|
98
129
|
|
|
99
130
|
class ChatVisibility(str, Enum):
|
{deltachat_rpc_client-1.160.0 → deltachat_rpc_client-2.1.0}/src/deltachat_rpc_client/contact.py
RENAMED
|
@@ -37,10 +37,6 @@ class Contact:
|
|
|
37
37
|
"""Delete contact."""
|
|
38
38
|
self._rpc.delete_contact(self.account.id, self.id)
|
|
39
39
|
|
|
40
|
-
def reset_encryption(self) -> None:
|
|
41
|
-
"""Reset contact encryption."""
|
|
42
|
-
self._rpc.reset_contact_encryption(self.account.id, self.id)
|
|
43
|
-
|
|
44
40
|
def set_name(self, name: str) -> None:
|
|
45
41
|
"""Change the name of this contact."""
|
|
46
42
|
self._rpc.change_contact_name(self.account.id, self.id, name)
|
{deltachat_rpc_client-1.160.0 → deltachat_rpc_client-2.1.0}/src/deltachat_rpc_client/message.py
RENAMED
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
|
|
3
3
|
import json
|
|
4
4
|
from dataclasses import dataclass
|
|
5
|
-
from typing import TYPE_CHECKING, Optional, Union
|
|
5
|
+
from typing import TYPE_CHECKING, List, Optional, Union
|
|
6
6
|
|
|
7
7
|
from ._utils import AttrDict, futuremethod
|
|
8
8
|
from .const import EventType
|
|
@@ -39,6 +39,11 @@ class Message:
|
|
|
39
39
|
snapshot["message"] = self
|
|
40
40
|
return snapshot
|
|
41
41
|
|
|
42
|
+
def get_read_receipts(self) -> List[AttrDict]:
|
|
43
|
+
"""Get message read receipts."""
|
|
44
|
+
read_receipts = self._rpc.get_message_read_receipts(self.account.id, self.id)
|
|
45
|
+
return [AttrDict(read_receipt) for read_receipt in read_receipts]
|
|
46
|
+
|
|
42
47
|
def get_reactions(self) -> Optional[AttrDict]:
|
|
43
48
|
"""Get message reactions."""
|
|
44
49
|
reactions = self._rpc.get_message_reactions(self.account.id, self.id)
|
|
@@ -1,5 +1,4 @@
|
|
|
1
1
|
import logging
|
|
2
|
-
import time
|
|
3
2
|
|
|
4
3
|
import pytest
|
|
5
4
|
|
|
@@ -16,14 +15,14 @@ def test_qr_setup_contact(acfactory, tmp_path) -> None:
|
|
|
16
15
|
alice.wait_for_securejoin_inviter_success()
|
|
17
16
|
|
|
18
17
|
# Test that Alice verified Bob's profile.
|
|
19
|
-
alice_contact_bob = alice.
|
|
18
|
+
alice_contact_bob = alice.create_contact(bob)
|
|
20
19
|
alice_contact_bob_snapshot = alice_contact_bob.get_snapshot()
|
|
21
20
|
assert alice_contact_bob_snapshot.is_verified
|
|
22
21
|
|
|
23
22
|
bob.wait_for_securejoin_joiner_success()
|
|
24
23
|
|
|
25
24
|
# Test that Bob verified Alice's profile.
|
|
26
|
-
bob_contact_alice = bob.
|
|
25
|
+
bob_contact_alice = bob.create_contact(alice)
|
|
27
26
|
bob_contact_alice_snapshot = bob_contact_alice.get_snapshot()
|
|
28
27
|
assert bob_contact_alice_snapshot.is_verified
|
|
29
28
|
|
|
@@ -84,7 +83,7 @@ def test_qr_securejoin(acfactory, protect):
|
|
|
84
83
|
bob.wait_for_securejoin_joiner_success()
|
|
85
84
|
|
|
86
85
|
# Test that Alice verified Bob's profile.
|
|
87
|
-
alice_contact_bob = alice.
|
|
86
|
+
alice_contact_bob = alice.create_contact(bob)
|
|
88
87
|
alice_contact_bob_snapshot = alice_contact_bob.get_snapshot()
|
|
89
88
|
assert alice_contact_bob_snapshot.is_verified
|
|
90
89
|
|
|
@@ -93,7 +92,7 @@ def test_qr_securejoin(acfactory, protect):
|
|
|
93
92
|
assert snapshot.chat.get_basic_snapshot().is_protected == protect
|
|
94
93
|
|
|
95
94
|
# Test that Bob verified Alice's profile.
|
|
96
|
-
bob_contact_alice = bob.
|
|
95
|
+
bob_contact_alice = bob.create_contact(alice)
|
|
97
96
|
bob_contact_alice_snapshot = bob_contact_alice.get_snapshot()
|
|
98
97
|
assert bob_contact_alice_snapshot.is_verified
|
|
99
98
|
|
|
@@ -101,7 +100,7 @@ def test_qr_securejoin(acfactory, protect):
|
|
|
101
100
|
# Alice observes securejoin protocol and verifies Bob on second device.
|
|
102
101
|
alice2.start_io()
|
|
103
102
|
alice2.wait_for_securejoin_inviter_success()
|
|
104
|
-
alice2_contact_bob = alice2.
|
|
103
|
+
alice2_contact_bob = alice2.create_contact(bob)
|
|
105
104
|
alice2_contact_bob_snapshot = alice2_contact_bob.get_snapshot()
|
|
106
105
|
assert alice2_contact_bob_snapshot.is_verified
|
|
107
106
|
|
|
@@ -213,72 +212,8 @@ def test_setup_contact_resetup(acfactory) -> None:
|
|
|
213
212
|
bob.wait_for_securejoin_joiner_success()
|
|
214
213
|
|
|
215
214
|
|
|
216
|
-
def test_verified_group_recovery(acfactory) -> None:
|
|
217
|
-
"""Tests verified group recovery by reverifying a member and sending a message in a group."""
|
|
218
|
-
ac1, ac2, ac3 = acfactory.get_online_accounts(3)
|
|
219
|
-
|
|
220
|
-
logging.info("ac1 creates verified group")
|
|
221
|
-
chat = ac1.create_group("Verified group", protect=True)
|
|
222
|
-
assert chat.get_basic_snapshot().is_protected
|
|
223
|
-
|
|
224
|
-
logging.info("ac2 joins verified group")
|
|
225
|
-
qr_code = chat.get_qr_code()
|
|
226
|
-
ac2.secure_join(qr_code)
|
|
227
|
-
ac2.wait_for_securejoin_joiner_success()
|
|
228
|
-
|
|
229
|
-
# ac1 has ac2 directly verified.
|
|
230
|
-
ac1_contact_ac2 = ac1.get_contact_by_addr(ac2.get_config("addr"))
|
|
231
|
-
assert ac1_contact_ac2.get_snapshot().verifier_id == SpecialContactId.SELF
|
|
232
|
-
|
|
233
|
-
logging.info("ac3 joins verified group")
|
|
234
|
-
ac3_chat = ac3.secure_join(qr_code)
|
|
235
|
-
ac3.wait_for_securejoin_joiner_success()
|
|
236
|
-
ac3.wait_for_incoming_msg_event() # Member added
|
|
237
|
-
|
|
238
|
-
logging.info("ac2 logs in on a new device")
|
|
239
|
-
ac2 = acfactory.resetup_account(ac2)
|
|
240
|
-
|
|
241
|
-
logging.info("ac2 reverifies with ac3")
|
|
242
|
-
qr_code = ac3.get_qr_code()
|
|
243
|
-
ac2.secure_join(qr_code)
|
|
244
|
-
ac2.wait_for_securejoin_joiner_success()
|
|
245
|
-
|
|
246
|
-
logging.info("ac3 sends a message to the group")
|
|
247
|
-
assert len(ac3_chat.get_contacts()) == 3
|
|
248
|
-
ac3_chat.send_text("Hi!")
|
|
249
|
-
|
|
250
|
-
snapshot = ac1.get_message_by_id(ac1.wait_for_incoming_msg_event().msg_id).get_snapshot()
|
|
251
|
-
assert snapshot.text == "Hi!"
|
|
252
|
-
|
|
253
|
-
msg_id = ac2.wait_for_incoming_msg_event().msg_id
|
|
254
|
-
message = ac2.get_message_by_id(msg_id)
|
|
255
|
-
snapshot = message.get_snapshot()
|
|
256
|
-
assert snapshot.text == "Hi!"
|
|
257
|
-
|
|
258
|
-
# ac1 contact is verified for ac2 because ac3 gossiped ac1 key in the "Hi!" message.
|
|
259
|
-
ac1_contact = ac2.get_contact_by_addr(ac1.get_config("addr"))
|
|
260
|
-
assert ac1_contact.get_snapshot().is_verified
|
|
261
|
-
|
|
262
|
-
# ac2 can write messages to the group.
|
|
263
|
-
snapshot.chat.send_text("Works again!")
|
|
264
|
-
|
|
265
|
-
snapshot = ac3.get_message_by_id(ac3.wait_for_incoming_msg_event().msg_id).get_snapshot()
|
|
266
|
-
assert snapshot.text == "Works again!"
|
|
267
|
-
|
|
268
|
-
snapshot = ac1.get_message_by_id(ac1.wait_for_incoming_msg_event().msg_id).get_snapshot()
|
|
269
|
-
assert snapshot.text == "Works again!"
|
|
270
|
-
|
|
271
|
-
ac1_chat_messages = snapshot.chat.get_messages()
|
|
272
|
-
ac2_addr = ac2.get_config("addr")
|
|
273
|
-
assert ac1_chat_messages[-2].get_snapshot().text == f"Changed setup for {ac2_addr}"
|
|
274
|
-
|
|
275
|
-
# ac2 is now verified by ac3 for ac1
|
|
276
|
-
ac1_contact_ac3 = ac1.get_contact_by_addr(ac3.get_config("addr"))
|
|
277
|
-
assert ac1_contact_ac2.get_snapshot().verifier_id == ac1_contact_ac3.id
|
|
278
|
-
|
|
279
|
-
|
|
280
215
|
def test_verified_group_member_added_recovery(acfactory) -> None:
|
|
281
|
-
"""Tests verified group recovery by
|
|
216
|
+
"""Tests verified group recovery by reverifying then removing and adding a member back."""
|
|
282
217
|
ac1, ac2, ac3 = acfactory.get_online_accounts(3)
|
|
283
218
|
|
|
284
219
|
logging.info("ac1 creates verified group")
|
|
@@ -291,7 +226,7 @@ def test_verified_group_member_added_recovery(acfactory) -> None:
|
|
|
291
226
|
ac2.wait_for_securejoin_joiner_success()
|
|
292
227
|
|
|
293
228
|
# ac1 has ac2 directly verified.
|
|
294
|
-
ac1_contact_ac2 = ac1.
|
|
229
|
+
ac1_contact_ac2 = ac1.create_contact(ac2)
|
|
295
230
|
assert ac1_contact_ac2.get_snapshot().verifier_id == SpecialContactId.SELF
|
|
296
231
|
|
|
297
232
|
logging.info("ac3 joins verified group")
|
|
@@ -299,6 +234,8 @@ def test_verified_group_member_added_recovery(acfactory) -> None:
|
|
|
299
234
|
ac3.wait_for_securejoin_joiner_success()
|
|
300
235
|
ac3.wait_for_incoming_msg_event() # Member added
|
|
301
236
|
|
|
237
|
+
ac3_contact_ac2_old = ac3.create_contact(ac2)
|
|
238
|
+
|
|
302
239
|
logging.info("ac2 logs in on a new device")
|
|
303
240
|
ac2 = acfactory.resetup_account(ac2)
|
|
304
241
|
|
|
@@ -311,21 +248,10 @@ def test_verified_group_member_added_recovery(acfactory) -> None:
|
|
|
311
248
|
assert len(ac3_chat.get_contacts()) == 3
|
|
312
249
|
ac3_chat.send_text("Hi!")
|
|
313
250
|
|
|
314
|
-
msg_id = ac2.wait_for_incoming_msg_event().msg_id
|
|
315
|
-
message = ac2.get_message_by_id(msg_id)
|
|
316
|
-
snapshot = message.get_snapshot()
|
|
317
|
-
logging.info("Received message %s", snapshot.text)
|
|
318
|
-
assert snapshot.text == "Hi!"
|
|
319
|
-
|
|
320
251
|
ac1.wait_for_incoming_msg_event() # Hi!
|
|
321
252
|
|
|
322
|
-
ac3_contact_ac2 = ac3.
|
|
323
|
-
ac3_chat.remove_contact(
|
|
324
|
-
|
|
325
|
-
msg_id = ac2.wait_for_incoming_msg_event().msg_id
|
|
326
|
-
message = ac2.get_message_by_id(msg_id)
|
|
327
|
-
snapshot = message.get_snapshot()
|
|
328
|
-
assert "removed" in snapshot.text
|
|
253
|
+
ac3_contact_ac2 = ac3.create_contact(ac2)
|
|
254
|
+
ac3_chat.remove_contact(ac3_contact_ac2_old)
|
|
329
255
|
|
|
330
256
|
snapshot = ac1.get_message_by_id(ac1.wait_for_incoming_msg_event().msg_id).get_snapshot()
|
|
331
257
|
assert "removed" in snapshot.text
|
|
@@ -354,19 +280,16 @@ def test_verified_group_member_added_recovery(acfactory) -> None:
|
|
|
354
280
|
snapshot = ac1.get_message_by_id(ac1.wait_for_incoming_msg_event().msg_id).get_snapshot()
|
|
355
281
|
assert snapshot.text == "Works again!"
|
|
356
282
|
|
|
357
|
-
ac1_contact_ac2 = ac1.
|
|
283
|
+
ac1_contact_ac2 = ac1.create_contact(ac2)
|
|
284
|
+
ac1_contact_ac3 = ac1.create_contact(ac3)
|
|
358
285
|
ac1_contact_ac2_snapshot = ac1_contact_ac2.get_snapshot()
|
|
359
286
|
assert ac1_contact_ac2_snapshot.is_verified
|
|
360
|
-
assert ac1_contact_ac2_snapshot.verifier_id ==
|
|
361
|
-
|
|
362
|
-
# ac2 is now verified by ac3 for ac1
|
|
363
|
-
ac1_contact_ac3 = ac1.get_contact_by_addr(ac3.get_config("addr"))
|
|
364
|
-
assert ac1_contact_ac2.get_snapshot().verifier_id == ac1_contact_ac3.id
|
|
287
|
+
assert ac1_contact_ac2_snapshot.verifier_id == ac1_contact_ac3.id
|
|
365
288
|
|
|
366
289
|
|
|
367
290
|
def test_qr_join_chat_with_pending_bobstate_issue4894(acfactory):
|
|
368
291
|
"""Regression test for
|
|
369
|
-
issue <https://github.com/
|
|
292
|
+
issue <https://github.com/chatmail/core/issues/4894>.
|
|
370
293
|
"""
|
|
371
294
|
ac1, ac2, ac3, ac4 = acfactory.get_online_accounts(4)
|
|
372
295
|
|
|
@@ -400,12 +323,12 @@ def test_qr_join_chat_with_pending_bobstate_issue4894(acfactory):
|
|
|
400
323
|
logging.info("ac2 now has pending bobstate but ac1 is shutoff")
|
|
401
324
|
|
|
402
325
|
# we meanwhile expect ac3/ac2 verification started in the beginning to have completed
|
|
403
|
-
assert ac3.
|
|
404
|
-
assert ac2.
|
|
326
|
+
assert ac3.create_contact(ac2).get_snapshot().is_verified
|
|
327
|
+
assert ac2.create_contact(ac3).get_snapshot().is_verified
|
|
405
328
|
|
|
406
329
|
logging.info("ac3: create a verified group VG with ac2")
|
|
407
330
|
vg = ac3.create_group("ac3-created", protect=True)
|
|
408
|
-
vg.add_contact(ac3.
|
|
331
|
+
vg.add_contact(ac3.create_contact(ac2))
|
|
409
332
|
|
|
410
333
|
# ensure ac2 receives message in VG
|
|
411
334
|
vg.send_text("hello")
|
|
@@ -443,7 +366,7 @@ def test_qr_new_group_unblocked(acfactory):
|
|
|
443
366
|
ac1.wait_for_securejoin_inviter_success()
|
|
444
367
|
|
|
445
368
|
ac1_new_chat = ac1.create_group("Another group")
|
|
446
|
-
ac1_new_chat.add_contact(ac1.
|
|
369
|
+
ac1_new_chat.add_contact(ac1.create_contact(ac2))
|
|
447
370
|
# Receive "Member added" message.
|
|
448
371
|
ac2.wait_for_incoming_msg_event()
|
|
449
372
|
|
|
@@ -577,30 +500,8 @@ def test_securejoin_after_contact_resetup(acfactory) -> None:
|
|
|
577
500
|
|
|
578
501
|
# ac1 resetups the account.
|
|
579
502
|
ac1 = acfactory.resetup_account(ac1)
|
|
580
|
-
|
|
581
|
-
|
|
582
|
-
# until ac2 accepts new ac1 key.
|
|
583
|
-
#
|
|
584
|
-
# This may not happen immediately because resetup of ac1
|
|
585
|
-
# rewinds "smeared timestamp" so Date: header for messages
|
|
586
|
-
# sent by new ac1 are in the past compared to the last Date:
|
|
587
|
-
# header sent by old ac1.
|
|
588
|
-
while True:
|
|
589
|
-
# ac1 sends a message to ac2.
|
|
590
|
-
ac1_contact_ac2 = ac1.create_contact(ac2, "")
|
|
591
|
-
ac1_chat_ac2 = ac1_contact_ac2.create_chat()
|
|
592
|
-
ac1_chat_ac2.send_text("Hello!")
|
|
593
|
-
|
|
594
|
-
# ac2 receives a message.
|
|
595
|
-
snapshot = ac2.get_message_by_id(ac2.wait_for_incoming_msg_event().msg_id).get_snapshot()
|
|
596
|
-
assert snapshot.text == "Hello!"
|
|
597
|
-
logging.info("ac2 received Hello!")
|
|
598
|
-
|
|
599
|
-
# ac1 is no longer verified for ac2 as new Autocrypt key is not the same as old verified key.
|
|
600
|
-
logging.info("ac2 addr={}, ac1 addr={}".format(ac2.get_config("addr"), ac1.get_config("addr")))
|
|
601
|
-
if not ac2_contact_ac1.get_snapshot().is_verified:
|
|
602
|
-
break
|
|
603
|
-
time.sleep(1)
|
|
503
|
+
ac2_contact_ac1 = ac2.create_contact(ac1, "")
|
|
504
|
+
assert not ac2_contact_ac1.get_snapshot().is_verified
|
|
604
505
|
|
|
605
506
|
# ac1 goes offline.
|
|
606
507
|
ac1.remove()
|
|
@@ -11,7 +11,7 @@ from unittest.mock import MagicMock
|
|
|
11
11
|
import pytest
|
|
12
12
|
|
|
13
13
|
from deltachat_rpc_client import Contact, EventType, Message, events
|
|
14
|
-
from deltachat_rpc_client.const import DownloadState, MessageState
|
|
14
|
+
from deltachat_rpc_client.const import ChatType, DownloadState, MessageState
|
|
15
15
|
from deltachat_rpc_client.rpc import JsonRpcError
|
|
16
16
|
|
|
17
17
|
|
|
@@ -170,7 +170,7 @@ def test_account(acfactory) -> None:
|
|
|
170
170
|
assert alice.get_size()
|
|
171
171
|
assert alice.is_configured()
|
|
172
172
|
assert not alice.get_avatar()
|
|
173
|
-
assert alice.get_contact_by_addr(bob_addr)
|
|
173
|
+
assert alice.get_contact_by_addr(bob_addr) is None # There is no address-contact, only key-contact
|
|
174
174
|
assert alice.get_contacts()
|
|
175
175
|
assert alice.get_contacts(snapshot=True)
|
|
176
176
|
assert alice.self_contact
|
|
@@ -287,7 +287,6 @@ def test_contact(acfactory) -> None:
|
|
|
287
287
|
assert repr(alice_contact_bob)
|
|
288
288
|
alice_contact_bob.block()
|
|
289
289
|
alice_contact_bob.unblock()
|
|
290
|
-
alice_contact_bob.reset_encryption()
|
|
291
290
|
alice_contact_bob.set_name("new name")
|
|
292
291
|
alice_contact_bob.get_encryption_info()
|
|
293
292
|
snapshot = alice_contact_bob.get_snapshot()
|
|
@@ -727,6 +726,26 @@ def test_markseen_contact_request(acfactory):
|
|
|
727
726
|
assert message2.get_snapshot().state == MessageState.IN_SEEN
|
|
728
727
|
|
|
729
728
|
|
|
729
|
+
def test_read_receipt(acfactory):
|
|
730
|
+
"""
|
|
731
|
+
Test sending a read receipt and ensure it is attributed to the correct contact.
|
|
732
|
+
"""
|
|
733
|
+
alice, bob = acfactory.get_online_accounts(2)
|
|
734
|
+
|
|
735
|
+
alice_chat_bob = alice.create_chat(bob)
|
|
736
|
+
alice_contact_bob = alice.create_contact(bob)
|
|
737
|
+
bob.create_chat(alice) # Accept the chat
|
|
738
|
+
|
|
739
|
+
alice_chat_bob.send_text("Hello Bob!")
|
|
740
|
+
msg = bob.wait_for_incoming_msg()
|
|
741
|
+
msg.mark_seen()
|
|
742
|
+
|
|
743
|
+
read_msg = alice.get_message_by_id(alice.wait_for_event(EventType.MSG_READ).msg_id)
|
|
744
|
+
read_receipts = read_msg.get_read_receipts()
|
|
745
|
+
assert len(read_receipts) == 1
|
|
746
|
+
assert read_receipts[0].contact_id == alice_contact_bob.id
|
|
747
|
+
|
|
748
|
+
|
|
730
749
|
def test_get_http_response(acfactory):
|
|
731
750
|
alice = acfactory.new_configured_account()
|
|
732
751
|
http_response = alice._rpc.get_http_response(alice.id, "https://example.org")
|
|
@@ -847,3 +866,36 @@ def test_delete_deltachat_folder(acfactory, direct_imap):
|
|
|
847
866
|
assert msg.text == "hello"
|
|
848
867
|
|
|
849
868
|
assert "DeltaChat" in ac1_direct_imap.list_folders()
|
|
869
|
+
|
|
870
|
+
|
|
871
|
+
def test_broadcast(acfactory):
|
|
872
|
+
alice, bob = acfactory.get_online_accounts(2)
|
|
873
|
+
|
|
874
|
+
alice_chat = alice.create_broadcast("My great channel")
|
|
875
|
+
snapshot = alice_chat.get_basic_snapshot()
|
|
876
|
+
assert snapshot.name == "My great channel"
|
|
877
|
+
assert snapshot.is_unpromoted
|
|
878
|
+
assert snapshot.is_encrypted
|
|
879
|
+
assert snapshot.chat_type == ChatType.OUT_BROADCAST
|
|
880
|
+
|
|
881
|
+
alice_contact_bob = alice.create_contact(bob, "Bob")
|
|
882
|
+
alice_chat.add_contact(alice_contact_bob)
|
|
883
|
+
|
|
884
|
+
alice_msg = alice_chat.send_message(text="hello").get_snapshot()
|
|
885
|
+
assert alice_msg.text == "hello"
|
|
886
|
+
assert alice_msg.show_padlock
|
|
887
|
+
|
|
888
|
+
bob_msg = bob.wait_for_incoming_msg().get_snapshot()
|
|
889
|
+
assert bob_msg.text == "hello"
|
|
890
|
+
assert bob_msg.show_padlock
|
|
891
|
+
assert bob_msg.error is None
|
|
892
|
+
|
|
893
|
+
bob_chat = bob.get_chat_by_id(bob_msg.chat_id)
|
|
894
|
+
bob_chat_snapshot = bob_chat.get_basic_snapshot()
|
|
895
|
+
assert bob_chat_snapshot.name == "My great channel"
|
|
896
|
+
assert not bob_chat_snapshot.is_unpromoted
|
|
897
|
+
assert bob_chat_snapshot.is_encrypted
|
|
898
|
+
assert bob_chat_snapshot.chat_type == ChatType.IN_BROADCAST
|
|
899
|
+
assert bob_chat_snapshot.is_contact_request
|
|
900
|
+
|
|
901
|
+
assert not bob_chat.can_send()
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{deltachat_rpc_client-1.160.0 → deltachat_rpc_client-2.1.0}/src/deltachat_rpc_client/__init__.py
RENAMED
|
File without changes
|
{deltachat_rpc_client-1.160.0 → deltachat_rpc_client-2.1.0}/src/deltachat_rpc_client/_utils.py
RENAMED
|
File without changes
|
{deltachat_rpc_client-1.160.0 → deltachat_rpc_client-2.1.0}/src/deltachat_rpc_client/chat.py
RENAMED
|
File without changes
|
{deltachat_rpc_client-1.160.0 → deltachat_rpc_client-2.1.0}/src/deltachat_rpc_client/client.py
RENAMED
|
File without changes
|
{deltachat_rpc_client-1.160.0 → deltachat_rpc_client-2.1.0}/src/deltachat_rpc_client/deltachat.py
RENAMED
|
File without changes
|
{deltachat_rpc_client-1.160.0 → deltachat_rpc_client-2.1.0}/src/deltachat_rpc_client/events.py
RENAMED
|
File without changes
|
{deltachat_rpc_client-1.160.0 → deltachat_rpc_client-2.1.0}/src/deltachat_rpc_client/py.typed
RENAMED
|
File without changes
|
{deltachat_rpc_client-1.160.0 → deltachat_rpc_client-2.1.0}/src/deltachat_rpc_client/pytestplugin.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|