From dd0afdfeb0c610770dc97ec295987b4286ae0311 Mon Sep 17 00:00:00 2001 From: holger krekel Date: Wed, 4 Sep 2019 21:17:27 +0200 Subject: [PATCH] add QR based join-group API, with test and SEGFAULT fix to rust --- python/src/deltachat/account.py | 21 ++++++++++++++++--- python/src/deltachat/chatting.py | 10 +++++++++ python/tests/test_account.py | 36 +++++++++++++++++++++++--------- src/chat.rs | 5 +++-- 4 files changed, 57 insertions(+), 15 deletions(-) diff --git a/python/src/deltachat/account.py b/python/src/deltachat/account.py index 1d15b4ca0..39068b716 100644 --- a/python/src/deltachat/account.py +++ b/python/src/deltachat/account.py @@ -334,7 +334,7 @@ class Account(object): this string needs to be transferred to another DC account in a second channel (typically used by mobiles with QRcode-show + scan UX) - where setup_secure_contact(qr) is called. + where qr_setup_contact(qr) is called. """ res = lib.dc_get_securejoin_qr(self._dc_context, 0) return from_dc_charpointer(res) @@ -350,8 +350,8 @@ class Account(object): raise ValueError("invalid or unknown QR code: {}".format(lot.text1())) return ScannedQRCode(lot) - def setup_secure_contact(self, qr): - """ setup secure contact and return a channel after contact is established. + def qr_setup_contact(self, qr): + """ setup contact and return a Chat after contact is established. Note that this function may block for a long time as messages are exchanged with the emitter of the QR code. On success a :class:`deltachat.chatting.Chat` instance @@ -364,6 +364,21 @@ class Account(object): raise ValueError("could not setup secure contact") return Chat(self, chat_id) + def qr_join_chat(self, qr): + """ join a chat group through a QR code. + + Note that this function may block for a long time as messages are exchanged + with the emitter of the QR code. On success a :class:`deltachat.chatting.Chat` instance + is returned which is the chat that we just joined. + + :param qr: valid "join-group" QR code (all other QR codes will result in an exception) + """ + assert self.check_qr(qr).is_ask_verifygroup() + chat_id = lib.dc_join_securejoin(self._dc_context, as_dc_charpointer(qr)) + if chat_id == 0: + raise ValueError("could not join group") + return Chat(self, chat_id) + def start_threads(self): """ start IMAP/SMTP threads (and configure account if it hasn't happened). diff --git a/python/src/deltachat/chatting.py b/python/src/deltachat/chatting.py index 81b64e2f5..384a30524 100644 --- a/python/src/deltachat/chatting.py +++ b/python/src/deltachat/chatting.py @@ -131,6 +131,16 @@ class Chat(object): """ return lib.dc_chat_get_type(self._dc_chat) + def get_join_qr(self): + """ get/create Join-Group QR Code as ascii-string. + + this string needs to be transferred to another DC account + in a second channel (typically used by mobiles with QRcode-show + scan UX) + where account.join_with_qrcode(qr) needs to be called. + """ + res = lib.dc_get_securejoin_qr(self._dc_context, self.id) + return from_dc_charpointer(res) + # ------ chat messaging API ------------------------------ def send_text(self, text): diff --git a/python/tests/test_account.py b/python/tests/test_account.py index 5809cffae..f827bda3e 100644 --- a/python/tests/test_account.py +++ b/python/tests/test_account.py @@ -140,6 +140,13 @@ class TestOfflineChat: chat.set_name("title2") assert chat.get_name() == "title2" + @pytest.mark.parametrize("verified", [True, False]) + def test_group_chat_qr(self, acfactory, ac1, verified): + ac2 = acfactory.get_configured_offline_account() + chat = ac1.create_group_chat(name="title1", verified=verified) + qr = chat.get_join_qr() + assert ac2.check_qr(qr).is_ask_verifygroup + def test_delete_and_send_fails(self, ac1, chat1): chat1.delete() ac1._evlogger.get_matching("DC_EVENT_MSGS_CHANGED") @@ -306,13 +313,10 @@ class TestOfflineChat: chat1.set_draft(None) assert chat1.get_draft() is None - def test_setup_contact(self, acfactory, lp): - # note that the receiving account needs to be configured and running - # before ther setup message is send. DC does not read old messages - # as of Jul2019 + def test_qr_setup_contact(self, acfactory, lp): ac1 = acfactory.get_configured_offline_account() ac2 = acfactory.get_configured_offline_account() - qr = ac1.get_setup_contact_qr() + qr = ac1.qr_setup_contact() assert qr.startswith("OPENPGP4FPR:") res = ac2.check_qr(qr) assert res.is_ask_verifycontact() @@ -560,16 +564,28 @@ class TestOnlineAccount: msg.continue_key_transfer(setup_code) assert ac1.get_info()["fingerprint"] == ac2.get_info()["fingerprint"] - def test_setup_contact(self, acfactory, lp): + def test_qr_setup_contact(self, acfactory, lp): + ac1 = acfactory.get_online_configuring_account() + ac2 = acfactory.get_online_configuring_account() + wait_configuration_progress(ac2, 1000) + wait_configuration_progress(ac1, 1000) + lp.sec("ac1: create QR code and let ac2 scan it, starting the securejoin") + qr = ac1.get_setup_contact_qr() + lp.sec("ac2: start QR-code based setup contact protocol") + ch = ac2.qr_setup_contact(qr) + assert ch.id >= 10 + wait_securejoin_inviter_progress(ac1, 1000) + + def test_qr_join_chat(self, acfactory, lp): ac1 = acfactory.get_online_configuring_account() ac2 = acfactory.get_online_configuring_account() wait_configuration_progress(ac2, 1000) wait_configuration_progress(ac1, 1000) lp.sec("ac1: create QR code and let ac2 scan it, starting the securejoin") - qr = ac1.get_setup_contact_qr() - assert qr.startswith("OPENPGP4FPR:") - lp.sec("ac2: start QR-code based setup contact protocol") - ch = ac2.setup_secure_contact(qr) + chat = ac1.create_group_chat("hello") + qr = chat.get_join_qr() + lp.sec("ac2: start QR-code based join-group protocol") + ch = ac2.qr_join_chat(qr) assert ch.id >= 10 wait_securejoin_inviter_progress(ac1, 1000) diff --git a/src/chat.rs b/src/chat.rs index c88e9f984..47c6e86c9 100644 --- a/src/chat.rs +++ b/src/chat.rs @@ -1941,8 +1941,9 @@ pub unsafe fn get_chat_id_by_grpid( } let v = row.get::<_, Option>(2)?.unwrap_or_default(); - *ret_verified = (v == Chattype::VerifiedGroup) as libc::c_int; - + if !ret_verified.is_null() { + *ret_verified = (v == Chattype::VerifiedGroup) as libc::c_int; + } Ok(chat_id) }, )