mirror of
https://github.com/chatmail/core.git
synced 2026-04-17 21:46:35 +03:00
regen constants and improve high level API for QR setup contact
This commit is contained in:
@@ -330,20 +330,35 @@ class Account(object):
|
|||||||
return from_dc_charpointer(res)
|
return from_dc_charpointer(res)
|
||||||
|
|
||||||
def get_setup_contact_qr(self):
|
def get_setup_contact_qr(self):
|
||||||
""" get/Create Setup-Contact QR Code as ascii-string """
|
""" get/create Setup-Contact 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 setup_secure_contact(qr) is called.
|
||||||
|
"""
|
||||||
res = lib.dc_get_securejoin_qr(self._dc_context, 0)
|
res = lib.dc_get_securejoin_qr(self._dc_context, 0)
|
||||||
return from_dc_charpointer(res)
|
return from_dc_charpointer(res)
|
||||||
|
|
||||||
def check_qr(self, qr):
|
def check_qr(self, qr):
|
||||||
""" check qr code ..."""
|
""" check qr code and return :class:`ScannedQRCode` instance representing the result"""
|
||||||
res = ffi.gc(
|
res = ffi.gc(
|
||||||
lib.dc_check_qr(self._dc_context, as_dc_charpointer(qr)),
|
lib.dc_check_qr(self._dc_context, as_dc_charpointer(qr)),
|
||||||
lib.dc_lot_unref
|
lib.dc_lot_unref
|
||||||
)
|
)
|
||||||
return DCLot(res)
|
lot = DCLot(res)
|
||||||
|
if lot.state() == const.DC_QR_ERROR:
|
||||||
|
raise ValueError("invalid or unknown QR code: {}".format(lot.text1()))
|
||||||
|
return ScannedQRCode(lot)
|
||||||
|
|
||||||
def setup_secure_contact(self, qr):
|
def setup_secure_contact(self, qr):
|
||||||
""" """
|
""" setup secure contact and return a channel 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
|
||||||
|
is returned.
|
||||||
|
:param qr: valid "setup contact" QR code (all other QR codes will result in an exception)
|
||||||
|
"""
|
||||||
|
assert self.check_qr(qr).is_ask_verifycontact()
|
||||||
chat_id = lib.dc_join_securejoin(self._dc_context, as_dc_charpointer(qr))
|
chat_id = lib.dc_join_securejoin(self._dc_context, as_dc_charpointer(qr))
|
||||||
if chat_id == 0:
|
if chat_id == 0:
|
||||||
raise ValueError("could not setup secure contact")
|
raise ValueError("could not setup secure contact")
|
||||||
@@ -512,3 +527,18 @@ def _destroy_dc_context(dc_context, dc_context_unref=lib.dc_context_unref):
|
|||||||
# we are deep into Python Interpreter shutdown,
|
# we are deep into Python Interpreter shutdown,
|
||||||
# so no need to clear the callback context mapping.
|
# so no need to clear the callback context mapping.
|
||||||
pass
|
pass
|
||||||
|
|
||||||
|
|
||||||
|
class ScannedQRCode:
|
||||||
|
def __init__(self, dc_lot):
|
||||||
|
self._dc_lot = dc_lot
|
||||||
|
|
||||||
|
def is_ask_verifycontact(self):
|
||||||
|
return self._dc_lot.state() == const.DC_QR_ASK_VERIFYCONTACT
|
||||||
|
|
||||||
|
def is_ask_verifygroup(self):
|
||||||
|
return self._dc_lot.state() == const.DC_QR_ASK_VERIFYGROUP
|
||||||
|
|
||||||
|
@property
|
||||||
|
def contact_id(self):
|
||||||
|
return self._dc_lot.id()
|
||||||
|
|||||||
@@ -13,6 +13,15 @@ DC_GCL_NO_SPECIALS = 0x02
|
|||||||
DC_GCL_ADD_ALLDONE_HINT = 0x04
|
DC_GCL_ADD_ALLDONE_HINT = 0x04
|
||||||
DC_GCL_VERIFIED_ONLY = 0x01
|
DC_GCL_VERIFIED_ONLY = 0x01
|
||||||
DC_GCL_ADD_SELF = 0x02
|
DC_GCL_ADD_SELF = 0x02
|
||||||
|
DC_QR_ASK_VERIFYCONTACT = 200
|
||||||
|
DC_QR_ASK_VERIFYGROUP = 202
|
||||||
|
DC_QR_FPR_OK = 210
|
||||||
|
DC_QR_FPR_MISMATCH = 220
|
||||||
|
DC_QR_FPR_WITHOUT_ADDR = 230
|
||||||
|
DC_QR_ADDR = 320
|
||||||
|
DC_QR_TEXT = 330
|
||||||
|
DC_QR_URL = 332
|
||||||
|
DC_QR_ERROR = 400
|
||||||
DC_CHAT_ID_DEADDROP = 1
|
DC_CHAT_ID_DEADDROP = 1
|
||||||
DC_CHAT_ID_TRASH = 3
|
DC_CHAT_ID_TRASH = 3
|
||||||
DC_CHAT_ID_MSGS_IN_CREATION = 4
|
DC_CHAT_ID_MSGS_IN_CREATION = 4
|
||||||
@@ -69,15 +78,13 @@ DC_EVENT_IMEX_FILE_WRITTEN = 2052
|
|||||||
DC_EVENT_SECUREJOIN_INVITER_PROGRESS = 2060
|
DC_EVENT_SECUREJOIN_INVITER_PROGRESS = 2060
|
||||||
DC_EVENT_SECUREJOIN_JOINER_PROGRESS = 2061
|
DC_EVENT_SECUREJOIN_JOINER_PROGRESS = 2061
|
||||||
DC_EVENT_GET_STRING = 2091
|
DC_EVENT_GET_STRING = 2091
|
||||||
DC_EVENT_HTTP_GET = 2100
|
|
||||||
DC_EVENT_HTTP_POST = 2110
|
|
||||||
DC_EVENT_FILE_COPIED = 2055
|
DC_EVENT_FILE_COPIED = 2055
|
||||||
DC_EVENT_IS_OFFLINE = 2081
|
DC_EVENT_IS_OFFLINE = 2081
|
||||||
# end const generated
|
# end const generated
|
||||||
|
|
||||||
|
|
||||||
def read_event_defines(f):
|
def read_event_defines(f):
|
||||||
rex = re.compile(r'#define\s+((?:DC_EVENT_|DC_MSG|DC_STATE_|DC_CONTACT_ID_|DC_GCL|DC_CHAT)\S+)\s+([x\d]+).*')
|
rex = re.compile(r'#define\s+((?:DC_EVENT_|DC_QR|DC_MSG|DC_STATE_|DC_CONTACT_ID_|DC_GCL|DC_CHAT)\S+)\s+([x\d]+).*')
|
||||||
for line in f:
|
for line in f:
|
||||||
m = rex.match(line)
|
m = rex.match(line)
|
||||||
if m:
|
if m:
|
||||||
@@ -90,7 +97,7 @@ if __name__ == "__main__":
|
|||||||
if len(sys.argv) >= 2:
|
if len(sys.argv) >= 2:
|
||||||
deltah = sys.argv[1]
|
deltah = sys.argv[1]
|
||||||
else:
|
else:
|
||||||
deltah = joinpath(dirname(dirname(dirname(here_dir))), "src", "deltachat.h")
|
deltah = joinpath(dirname(dirname(dirname(here_dir))), "deltachat-ffi", "deltachat.h")
|
||||||
assert os.path.exists(deltah)
|
assert os.path.exists(deltah)
|
||||||
|
|
||||||
lines = []
|
lines = []
|
||||||
|
|||||||
@@ -306,6 +306,19 @@ class TestOfflineChat:
|
|||||||
chat1.set_draft(None)
|
chat1.set_draft(None)
|
||||||
assert chat1.get_draft() is 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
|
||||||
|
ac1 = acfactory.get_configured_offline_account()
|
||||||
|
ac2 = acfactory.get_configured_offline_account()
|
||||||
|
qr = ac1.get_setup_contact_qr()
|
||||||
|
assert qr.startswith("OPENPGP4FPR:")
|
||||||
|
res = ac2.check_qr(qr)
|
||||||
|
assert res.is_ask_verifycontact()
|
||||||
|
assert not res.is_ask_verifygroup()
|
||||||
|
assert res.contact_id == 10
|
||||||
|
|
||||||
|
|
||||||
class TestOnlineAccount:
|
class TestOnlineAccount:
|
||||||
def test_one_account_init(self, acfactory):
|
def test_one_account_init(self, acfactory):
|
||||||
@@ -548,9 +561,6 @@ class TestOnlineAccount:
|
|||||||
assert ac1.get_info()["fingerprint"] == ac2.get_info()["fingerprint"]
|
assert ac1.get_info()["fingerprint"] == ac2.get_info()["fingerprint"]
|
||||||
|
|
||||||
def test_setup_contact(self, acfactory, lp):
|
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
|
|
||||||
ac1 = acfactory.get_online_configuring_account()
|
ac1 = acfactory.get_online_configuring_account()
|
||||||
ac2 = acfactory.get_online_configuring_account()
|
ac2 = acfactory.get_online_configuring_account()
|
||||||
wait_configuration_progress(ac2, 1000)
|
wait_configuration_progress(ac2, 1000)
|
||||||
@@ -559,11 +569,6 @@ class TestOnlineAccount:
|
|||||||
|
|
||||||
qr = ac1.get_setup_contact_qr()
|
qr = ac1.get_setup_contact_qr()
|
||||||
assert qr.startswith("OPENPGP4FPR:")
|
assert qr.startswith("OPENPGP4FPR:")
|
||||||
|
|
||||||
res = ac2.check_qr(qr)
|
|
||||||
assert res.state() == 200
|
|
||||||
assert res.id() == 10
|
|
||||||
|
|
||||||
lp.sec("ac2: start QR-code based setup contact protocol")
|
lp.sec("ac2: start QR-code based setup contact protocol")
|
||||||
ch = ac2.setup_secure_contact(qr)
|
ch = ac2.setup_secure_contact(qr)
|
||||||
assert ch.id >= 10
|
assert ch.id >= 10
|
||||||
|
|||||||
Reference in New Issue
Block a user