Compare commits

..

5 Commits

Author SHA1 Message Date
holger krekel
e8158b5fbf fix the merge 2019-09-04 14:52:06 +02:00
holger krekel
580fda26b7 Merge branch 'master' into fix_securejoin_closure 2019-09-03 19:06:40 +02:00
jikstra
7b9da77d51 cargo fmt 2019-09-02 18:31:51 +02:00
jikstra
91510e7717 Cleanup closure should be defined as first thing and all variables should get passed as arguments 2019-09-02 17:37:41 +02:00
jikstra
ff1e62a42d Closure shouldn't copy qr variable into it's own scope and we should
never return null pointer
2019-09-02 17:05:31 +02:00
26 changed files with 1710 additions and 1637 deletions

98
Cargo.lock generated
View File

@@ -221,7 +221,7 @@ name = "c2-chacha"
version = "0.2.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"lazy_static 1.4.0 (registry+https://github.com/rust-lang/crates.io-index)",
"lazy_static 1.3.0 (registry+https://github.com/rust-lang/crates.io-index)",
"ppv-lite86 0.2.5 (registry+https://github.com/rust-lang/crates.io-index)",
]
@@ -382,7 +382,7 @@ dependencies = [
"arrayvec 0.4.11 (registry+https://github.com/rust-lang/crates.io-index)",
"cfg-if 0.1.9 (registry+https://github.com/rust-lang/crates.io-index)",
"crossbeam-utils 0.6.6 (registry+https://github.com/rust-lang/crates.io-index)",
"lazy_static 1.4.0 (registry+https://github.com/rust-lang/crates.io-index)",
"lazy_static 1.3.0 (registry+https://github.com/rust-lang/crates.io-index)",
"memoffset 0.5.1 (registry+https://github.com/rust-lang/crates.io-index)",
"scopeguard 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)",
]
@@ -401,7 +401,7 @@ version = "0.6.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"cfg-if 0.1.9 (registry+https://github.com/rust-lang/crates.io-index)",
"lazy_static 1.4.0 (registry+https://github.com/rust-lang/crates.io-index)",
"lazy_static 1.3.0 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
@@ -474,9 +474,9 @@ dependencies = [
"failure_derive 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)",
"hex 0.3.2 (registry+https://github.com/rust-lang/crates.io-index)",
"image-meta 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)",
"imap 1.0.2 (git+https://github.com/jonhoo/rust-imap?rev=281d2eb8ab50dc656ceff2ae749ca5045f334e15)",
"imap 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)",
"itertools 0.8.0 (registry+https://github.com/rust-lang/crates.io-index)",
"lazy_static 1.4.0 (registry+https://github.com/rust-lang/crates.io-index)",
"lazy_static 1.3.0 (registry+https://github.com/rust-lang/crates.io-index)",
"lettre 0.9.2 (registry+https://github.com/rust-lang/crates.io-index)",
"libc 0.2.62 (registry+https://github.com/rust-lang/crates.io-index)",
"mmime 0.1.2-alpha.0 (git+https://github.com/dignifiedquire/mmime?rev=bccd2c2)",
@@ -949,24 +949,23 @@ dependencies = [
[[package]]
name = "imap"
version = "1.0.2"
source = "git+https://github.com/jonhoo/rust-imap?rev=281d2eb8ab50dc656ceff2ae749ca5045f334e15#281d2eb8ab50dc656ceff2ae749ca5045f334e15"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"base64 0.10.1 (registry+https://github.com/rust-lang/crates.io-index)",
"bufstream 0.1.4 (registry+https://github.com/rust-lang/crates.io-index)",
"chrono 0.4.7 (registry+https://github.com/rust-lang/crates.io-index)",
"imap-proto 0.9.0 (registry+https://github.com/rust-lang/crates.io-index)",
"lazy_static 1.4.0 (registry+https://github.com/rust-lang/crates.io-index)",
"imap-proto 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)",
"native-tls 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)",
"nom 5.0.1 (registry+https://github.com/rust-lang/crates.io-index)",
"nom 4.2.3 (registry+https://github.com/rust-lang/crates.io-index)",
"regex 1.2.1 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "imap-proto"
version = "0.9.0"
version = "0.7.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"nom 5.0.1 (registry+https://github.com/rust-lang/crates.io-index)",
"nom 4.2.3 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
@@ -1012,7 +1011,7 @@ dependencies = [
[[package]]
name = "lazy_static"
version = "1.4.0"
version = "1.3.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
[[package]]
@@ -1032,18 +1031,6 @@ dependencies = [
"serde_json 1.0.40 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "lexical-core"
version = "0.4.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"cfg-if 0.1.9 (registry+https://github.com/rust-lang/crates.io-index)",
"rustc_version 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)",
"ryu 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)",
"stackvector 1.0.7 (registry+https://github.com/rust-lang/crates.io-index)",
"static_assertions 0.3.4 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "libc"
version = "0.2.62"
@@ -1211,7 +1198,7 @@ dependencies = [
"charset 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)",
"chrono 0.4.7 (registry+https://github.com/rust-lang/crates.io-index)",
"hex 0.3.2 (registry+https://github.com/rust-lang/crates.io-index)",
"lazy_static 1.4.0 (registry+https://github.com/rust-lang/crates.io-index)",
"lazy_static 1.3.0 (registry+https://github.com/rust-lang/crates.io-index)",
"libc 0.2.62 (registry+https://github.com/rust-lang/crates.io-index)",
"memmap 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)",
"rand 0.6.5 (registry+https://github.com/rust-lang/crates.io-index)",
@@ -1222,7 +1209,7 @@ name = "native-tls"
version = "0.2.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"lazy_static 1.4.0 (registry+https://github.com/rust-lang/crates.io-index)",
"lazy_static 1.3.0 (registry+https://github.com/rust-lang/crates.io-index)",
"libc 0.2.62 (registry+https://github.com/rust-lang/crates.io-index)",
"log 0.4.8 (registry+https://github.com/rust-lang/crates.io-index)",
"openssl 0.10.24 (registry+https://github.com/rust-lang/crates.io-index)",
@@ -1270,23 +1257,13 @@ dependencies = [
"version_check 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "nom"
version = "5.0.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"lexical-core 0.4.3 (registry+https://github.com/rust-lang/crates.io-index)",
"memchr 2.2.1 (registry+https://github.com/rust-lang/crates.io-index)",
"version_check 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "num-bigint-dig"
version = "0.4.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"byteorder 1.3.2 (registry+https://github.com/rust-lang/crates.io-index)",
"lazy_static 1.4.0 (registry+https://github.com/rust-lang/crates.io-index)",
"lazy_static 1.3.0 (registry+https://github.com/rust-lang/crates.io-index)",
"num-integer 0.1.41 (registry+https://github.com/rust-lang/crates.io-index)",
"num-iter 0.1.39 (registry+https://github.com/rust-lang/crates.io-index)",
"num-traits 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)",
@@ -1361,7 +1338,7 @@ dependencies = [
"bitflags 1.1.0 (registry+https://github.com/rust-lang/crates.io-index)",
"cfg-if 0.1.9 (registry+https://github.com/rust-lang/crates.io-index)",
"foreign-types 0.3.2 (registry+https://github.com/rust-lang/crates.io-index)",
"lazy_static 1.4.0 (registry+https://github.com/rust-lang/crates.io-index)",
"lazy_static 1.3.0 (registry+https://github.com/rust-lang/crates.io-index)",
"libc 0.2.62 (registry+https://github.com/rust-lang/crates.io-index)",
"openssl-sys 0.9.49 (registry+https://github.com/rust-lang/crates.io-index)",
]
@@ -1531,7 +1508,7 @@ dependencies = [
"flate2 1.0.11 (registry+https://github.com/rust-lang/crates.io-index)",
"generic-array 0.12.3 (registry+https://github.com/rust-lang/crates.io-index)",
"hex 0.3.2 (registry+https://github.com/rust-lang/crates.io-index)",
"lazy_static 1.4.0 (registry+https://github.com/rust-lang/crates.io-index)",
"lazy_static 1.3.0 (registry+https://github.com/rust-lang/crates.io-index)",
"log 0.4.8 (registry+https://github.com/rust-lang/crates.io-index)",
"md-5 0.8.0 (registry+https://github.com/rust-lang/crates.io-index)",
"nom 4.2.3 (registry+https://github.com/rust-lang/crates.io-index)",
@@ -1654,7 +1631,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"error-chain 0.12.1 (registry+https://github.com/rust-lang/crates.io-index)",
"idna 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)",
"lazy_static 1.4.0 (registry+https://github.com/rust-lang/crates.io-index)",
"lazy_static 1.3.0 (registry+https://github.com/rust-lang/crates.io-index)",
"regex 1.2.1 (registry+https://github.com/rust-lang/crates.io-index)",
"url 1.7.2 (registry+https://github.com/rust-lang/crates.io-index)",
]
@@ -1973,7 +1950,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"byteorder 1.3.2 (registry+https://github.com/rust-lang/crates.io-index)",
"failure 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)",
"lazy_static 1.4.0 (registry+https://github.com/rust-lang/crates.io-index)",
"lazy_static 1.3.0 (registry+https://github.com/rust-lang/crates.io-index)",
"num-bigint-dig 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)",
"num-integer 0.1.41 (registry+https://github.com/rust-lang/crates.io-index)",
"num-iter 0.1.39 (registry+https://github.com/rust-lang/crates.io-index)",
@@ -2059,7 +2036,7 @@ name = "schannel"
version = "0.1.15"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"lazy_static 1.4.0 (registry+https://github.com/rust-lang/crates.io-index)",
"lazy_static 1.3.0 (registry+https://github.com/rust-lang/crates.io-index)",
"winapi 0.3.7 (registry+https://github.com/rust-lang/crates.io-index)",
]
@@ -2232,20 +2209,6 @@ name = "stable_deref_trait"
version = "1.1.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
[[package]]
name = "stackvector"
version = "1.0.7"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"rustc_version 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)",
"unreachable 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "static_assertions"
version = "0.3.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
[[package]]
name = "stream-cipher"
version = "0.3.0"
@@ -2380,7 +2343,7 @@ name = "thread_local"
version = "0.3.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"lazy_static 1.4.0 (registry+https://github.com/rust-lang/crates.io-index)",
"lazy_static 1.3.0 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
@@ -2456,7 +2419,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"crossbeam-utils 0.6.6 (registry+https://github.com/rust-lang/crates.io-index)",
"futures 0.1.28 (registry+https://github.com/rust-lang/crates.io-index)",
"lazy_static 1.4.0 (registry+https://github.com/rust-lang/crates.io-index)",
"lazy_static 1.3.0 (registry+https://github.com/rust-lang/crates.io-index)",
"log 0.4.8 (registry+https://github.com/rust-lang/crates.io-index)",
"mio 0.6.19 (registry+https://github.com/rust-lang/crates.io-index)",
"num_cpus 1.10.1 (registry+https://github.com/rust-lang/crates.io-index)",
@@ -2601,14 +2564,6 @@ name = "unicode-xid"
version = "0.2.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
[[package]]
name = "unreachable"
version = "1.0.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"void 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "unsafe-any"
version = "0.4.2"
@@ -2900,17 +2855,16 @@ dependencies = [
"checksum ident_case 1.0.1 (registry+https://github.com/rust-lang/crates.io-index)" = "b9e0384b61958566e926dc50660321d12159025e767c18e043daf26b70104c39"
"checksum idna 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)" = "38f09e0f0b1fb55fdee1f17470ad800da77af5186a1a76c026b679358b7e844e"
"checksum image-meta 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "b00861cbbb254a627d8acc0cec786b484297d896ab8f20fdc8e28536a3e918ef"
"checksum imap 1.0.2 (git+https://github.com/jonhoo/rust-imap?rev=281d2eb8ab50dc656ceff2ae749ca5045f334e15)" = "<none>"
"checksum imap-proto 0.9.0 (registry+https://github.com/rust-lang/crates.io-index)" = "1b92ca529b24c5f80a950abe993d3883df6fe6791d4a46b1fda1eb339796c589"
"checksum imap 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)" = "178392198cb2716f4fe34b86a1bf1de1240a3e31136a199b16490fa87538fa25"
"checksum imap-proto 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)" = "c4e77b1d61faf028893531b071cc5584cdd02b6186cebe7f7168ffd8d591339a"
"checksum indexmap 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)" = "7e81a7c05f79578dbc15793d8b619db9ba32b4577003ef3af1a91c416798c58d"
"checksum iovec 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)" = "dbe6e417e7d0975db6512b90796e8ce223145ac4e33c377e4a42882a0e88bb08"
"checksum itertools 0.8.0 (registry+https://github.com/rust-lang/crates.io-index)" = "5b8467d9c1cebe26feb08c640139247fac215782d35371ade9a2136ed6085358"
"checksum itoa 0.4.4 (registry+https://github.com/rust-lang/crates.io-index)" = "501266b7edd0174f8530248f87f99c88fbe60ca4ef3dd486835b8d8d53136f7f"
"checksum keccak 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "67c21572b4949434e4fc1e1978b99c5f77064153c59d998bf13ecd96fb5ecba7"
"checksum kernel32-sys 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)" = "7507624b29483431c0ba2d82aece8ca6cdba9382bff4ddd0f7490560c056098d"
"checksum lazy_static 1.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "e2abad23fbc42b3700f2f279844dc832adb2b2eb069b2df918f455c4e18cc646"
"checksum lazy_static 1.3.0 (registry+https://github.com/rust-lang/crates.io-index)" = "bc5729f27f159ddd61f4df6228e827e86643d4d3e7c32183cb30a1c08f604a14"
"checksum lettre 0.9.2 (registry+https://github.com/rust-lang/crates.io-index)" = "c66afaa5dfadbb81d4e00fd1d1ab057c7cd4c799c5a44e0009386d553587e728"
"checksum lexical-core 0.4.3 (registry+https://github.com/rust-lang/crates.io-index)" = "b8b0f90c979adde96d19eb10eb6431ba0c441e2f9e9bdff868b2f6f5114ff519"
"checksum libc 0.2.62 (registry+https://github.com/rust-lang/crates.io-index)" = "34fcd2c08d2f832f376f4173a231990fa5aef4e99fb569867318a227ef4c06ba"
"checksum libsqlite3-sys 0.16.0 (registry+https://github.com/rust-lang/crates.io-index)" = "5e5b95e89c330291768dc840238db7f9e204fd208511ab6319b56193a7f2ae25"
"checksum linked-hash-map 0.5.2 (registry+https://github.com/rust-lang/crates.io-index)" = "ae91b68aebc4ddb91978b11a1b02ddd8602a05ec19002801c5666000e05e0f83"
@@ -2936,7 +2890,6 @@ dependencies = [
"checksum nix 0.13.1 (registry+https://github.com/rust-lang/crates.io-index)" = "4dbdc256eaac2e3bd236d93ad999d3479ef775c863dbda3068c4006a92eec51b"
"checksum nodrop 0.1.13 (registry+https://github.com/rust-lang/crates.io-index)" = "2f9667ddcc6cc8a43afc9b7917599d7216aa09c463919ea32c59ed6cac8bc945"
"checksum nom 4.2.3 (registry+https://github.com/rust-lang/crates.io-index)" = "2ad2a91a8e869eeb30b9cb3119ae87773a8f4ae617f41b1eb9c154b2905f7bd6"
"checksum nom 5.0.1 (registry+https://github.com/rust-lang/crates.io-index)" = "c618b63422da4401283884e6668d39f819a106ef51f5f59b81add00075da35ca"
"checksum num-bigint-dig 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "3cd60678022301da54082fcc383647fc895cba2795f868c871d58d29c8922595"
"checksum num-derive 0.2.5 (registry+https://github.com/rust-lang/crates.io-index)" = "eafd0b45c5537c3ba526f79d3e75120036502bebacbb3f3220914067ce39dbf2"
"checksum num-integer 0.1.41 (registry+https://github.com/rust-lang/crates.io-index)" = "b85e541ef8255f6cf42bbfe4ef361305c6c135d10919ecc26126c4e5ae94bc09"
@@ -3035,8 +2988,6 @@ dependencies = [
"checksum slice-deque 0.2.4 (registry+https://github.com/rust-lang/crates.io-index)" = "ffddf594f5f597f63533d897427a570dbaa9feabaaa06595b74b71b7014507d7"
"checksum smallvec 0.6.10 (registry+https://github.com/rust-lang/crates.io-index)" = "ab606a9c5e214920bb66c458cd7be8ef094f813f20fe77a54cc7dbfff220d4b7"
"checksum stable_deref_trait 1.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "dba1a27d3efae4351c8051072d619e3ade2820635c3958d826bfea39d59b54c8"
"checksum stackvector 1.0.7 (registry+https://github.com/rust-lang/crates.io-index)" = "4dade1e9ad1ce13baaba168a04cdefb5c0cbc100242a4035d6dfa9c64348f9c5"
"checksum static_assertions 0.3.4 (registry+https://github.com/rust-lang/crates.io-index)" = "7f3eb36b47e512f8f1c9e3d10c2c1965bc992bd9cdb024fa581e2194501c83d3"
"checksum stream-cipher 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)" = "8861bc80f649f5b4c9bd38b696ae9af74499d479dbfb327f0607de6b326a36bc"
"checksum string 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)" = "d24114bfcceb867ca7f71a0d3fe45d45619ec47a6fbfa98cb14e14250bfa5d6d"
"checksum strsim 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)" = "bb4f380125926a99e52bc279241539c018323fab05ad6368b56f93d9369ff550"
@@ -3077,7 +3028,6 @@ dependencies = [
"checksum unicode-width 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)" = "882386231c45df4700b275c7ff55b6f3698780a650026380e72dabe76fa46526"
"checksum unicode-xid 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "fc72304796d0818e357ead4e000d19c9c174ab23dc11093ac919054d20a6a7fc"
"checksum unicode-xid 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "826e7639553986605ec5979c7dd957c7895e93eabed50ab2ffa7f6128a75097c"
"checksum unreachable 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)" = "382810877fe448991dfc7f0dd6e3ae5d58088fd0ea5e35189655f84e6814fa56"
"checksum unsafe-any 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)" = "f30360d7979f5e9c6e6cea48af192ea8fab4afb3cf72597154b8f08935bc9c7f"
"checksum url 1.7.2 (registry+https://github.com/rust-lang/crates.io-index)" = "dd4e7c0d531266369519a4aa4f399d748bd37043b00bde1e4ff1f60a120b355a"
"checksum utf8parse 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "8772a4ccbb4e89959023bc5b7cb8623a795caa7092d99f3aa9501b9484d4557d"

View File

@@ -23,7 +23,7 @@ num-derive = "0.2.5"
num-traits = "0.2.6"
native-tls = "0.2.3"
lettre = "0.9.0"
imap = { git = "https://github.com/jonhoo/rust-imap", rev = "281d2eb8ab50dc656ceff2ae749ca5045f334e15" }
imap = "1.0.1"
mmime = { git = "https://github.com/dignifiedquire/mmime", rev = "bccd2c2" }
base64 = "0.10"
charset = "0.1"
@@ -35,7 +35,7 @@ failure = "0.1.5"
failure_derive = "0.1.5"
# TODO: make optional
rustyline = "4.1.0"
lazy_static = "1.4.0"
lazy_static = "1.3.0"
regex = "1.1.6"
rusqlite = { version = "0.20", features = ["bundled"] }
r2d2_sqlite = "0.12.0"

View File

@@ -1320,13 +1320,12 @@ pub unsafe extern "C" fn dc_get_securejoin_qr(
) -> *mut libc::c_char {
if context.is_null() {
eprintln!("ignoring careless call to dc_get_securejoin_qr()");
return "".strdup();
return dc_strdup(ptr::null());
}
let context = &*context;
securejoin::dc_get_securejoin_qr(context, chat_id)
.unwrap_or("".to_string())
.strdup()
dc_securejoin::dc_get_securejoin_qr(context, chat_id)
}
#[no_mangle]
@@ -1341,7 +1340,7 @@ pub unsafe extern "C" fn dc_join_securejoin(
let context = &*context;
securejoin::dc_join_securejoin(context, as_str(qr))
dc_securejoin::dc_join_securejoin(context, qr)
}
#[no_mangle]

View File

@@ -14,8 +14,6 @@ extern crate lazy_static;
extern crate rusqlite;
use std::borrow::Cow::{self, Borrowed, Owned};
use std::io::{self, Write};
use std::process::Command;
use std::ptr;
use std::sync::atomic::{AtomicBool, Ordering};
use std::sync::{Arc, Mutex, RwLock};
@@ -24,10 +22,10 @@ use deltachat::config;
use deltachat::configure::*;
use deltachat::constants::*;
use deltachat::context::*;
use deltachat::dc_securejoin::*;
use deltachat::dc_tools::*;
use deltachat::job::*;
use deltachat::oauth2::*;
use deltachat::securejoin::*;
use deltachat::types::*;
use deltachat::x::*;
use rustyline::completion::{Completer, FilenameCompleter, Pair};
@@ -518,27 +516,30 @@ unsafe fn handle_cmd(line: &str, ctx: Arc<RwLock<Context>>) -> Result<ExitResult
}
"getqr" | "getbadqr" => {
start_threads(ctx.clone());
if let Some(mut qr) =
dc_get_securejoin_qr(&ctx.read().unwrap(), arg1.parse().unwrap_or_default())
{
if !qr.is_empty() {
if arg0 == "getbadqr" && qr.len() > 40 {
qr.replace_range(12..22, "0000000000")
let qrstr =
dc_get_securejoin_qr(&ctx.read().unwrap(), arg1.parse().unwrap_or_default());
if !qrstr.is_null() && 0 != *qrstr.offset(0isize) as libc::c_int {
if arg0 == "getbadqr" && strlen(qrstr) > 40 {
let mut i: libc::c_int = 12i32;
while i < 22i32 {
*qrstr.offset(i as isize) = '0' as i32 as libc::c_char;
i += 1
}
println!("{}", qr);
let output = Command::new("qrencode")
.args(&["-t", "ansiutf8", qr.as_str(), "-o", "-"])
.output()
.expect("failed to execute process");
io::stdout().write_all(&output.stdout).unwrap();
io::stderr().write_all(&output.stderr).unwrap();
}
println!("{}", to_string(qrstr as *const _));
let syscmd = dc_mprintf(
b"qrencode -t ansiutf8 \"%s\" -o -\x00" as *const u8 as *const libc::c_char,
qrstr,
);
system(syscmd);
free(syscmd as *mut libc::c_void);
}
free(qrstr as *mut libc::c_void);
}
"joinqr" => {
start_threads(ctx.clone());
if !arg0.is_empty() {
dc_join_securejoin(&ctx.read().unwrap(), arg1);
dc_join_securejoin(&ctx.read().unwrap(), arg1_c);
}
}
"exit" | "quit" => return Ok(ExitResult::Exit),

View File

@@ -72,10 +72,10 @@ then cargo-build and install the deltachat bindings::
python install_python_bindings.py
The bindings will be installed in release mode but with debug symbols.
The release mode is necessary because some tests generate RSA keys
The release mode is neccessary because some tests generate RSA keys
which is prohibitively slow in debug mode.
After successful binding installation you can finally run the tests::
After succcessul binding installation you can finally run the tests::
pytest -v tests

View File

@@ -14,7 +14,7 @@ except ImportError:
import deltachat
from . import const
from .capi import ffi, lib
from .cutil import as_dc_charpointer, from_dc_charpointer, iter_array, DCLot
from .cutil import as_dc_charpointer, from_dc_charpointer, iter_array
from .chatting import Contact, Chat, Message
@@ -329,56 +329,6 @@ class Account(object):
raise RuntimeError("could not send out autocrypt setup message")
return from_dc_charpointer(res)
def get_setup_contact_qr(self):
""" 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 qr_setup_contact(qr) is called.
"""
res = lib.dc_get_securejoin_qr(self._dc_context, 0)
return from_dc_charpointer(res)
def check_qr(self, qr):
""" check qr code and return :class:`ScannedQRCode` instance representing the result"""
res = ffi.gc(
lib.dc_check_qr(self._dc_context, as_dc_charpointer(qr)),
lib.dc_lot_unref
)
lot = DCLot(res)
if lot.state() == const.DC_QR_ERROR:
raise ValueError("invalid or unknown QR code: {}".format(lot.text1()))
return ScannedQRCode(lot)
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
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))
if chat_id == 0:
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).
@@ -542,18 +492,3 @@ def _destroy_dc_context(dc_context, dc_context_unref=lib.dc_context_unref):
# we are deep into Python Interpreter shutdown,
# so no need to clear the callback context mapping.
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()

View File

@@ -131,16 +131,6 @@ 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):

View File

@@ -13,15 +13,6 @@ DC_GCL_NO_SPECIALS = 0x02
DC_GCL_ADD_ALLDONE_HINT = 0x04
DC_GCL_VERIFIED_ONLY = 0x01
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_TRASH = 3
DC_CHAT_ID_MSGS_IN_CREATION = 4
@@ -78,13 +69,15 @@ DC_EVENT_IMEX_FILE_WRITTEN = 2052
DC_EVENT_SECUREJOIN_INVITER_PROGRESS = 2060
DC_EVENT_SECUREJOIN_JOINER_PROGRESS = 2061
DC_EVENT_GET_STRING = 2091
DC_EVENT_HTTP_GET = 2100
DC_EVENT_HTTP_POST = 2110
DC_EVENT_FILE_COPIED = 2055
DC_EVENT_IS_OFFLINE = 2081
# end const generated
def read_event_defines(f):
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]+).*')
rex = re.compile(r'#define\s+((?:DC_EVENT_|DC_MSG|DC_STATE_|DC_CONTACT_ID_|DC_GCL|DC_CHAT)\S+)\s+([x\d]+).*')
for line in f:
m = rex.match(line)
if m:
@@ -97,7 +90,7 @@ if __name__ == "__main__":
if len(sys.argv) >= 2:
deltah = sys.argv[1]
else:
deltah = joinpath(dirname(dirname(dirname(here_dir))), "deltachat-ffi", "deltachat.h")
deltah = joinpath(dirname(dirname(dirname(here_dir))), "src", "deltachat.h")
assert os.path.exists(deltah)
lines = []

View File

@@ -1,6 +1,5 @@
from .capi import lib
from .capi import ffi
from datetime import datetime
def as_dc_charpointer(obj):
@@ -18,29 +17,3 @@ def iter_array(dc_array_t, constructor):
def from_dc_charpointer(obj):
return ffi.string(ffi.gc(obj, lib.dc_str_unref)).decode("utf8")
class DCLot:
def __init__(self, dc_lot):
self._dc_lot = dc_lot
def id(self):
return lib.dc_lot_get_id(self._dc_lot)
def state(self):
return lib.dc_lot_get_state(self._dc_lot)
def text1(self):
return from_dc_charpointer(lib.dc_lot_get_text1(self._dc_lot))
def text1_meaning(self):
return lib.dc_lot_get_text1_meaning(self._dc_lot)
def text2(self):
return from_dc_charpointer(lib.dc_lot_get_text2(self._dc_lot))
def timestamp(self):
ts = lib.dc_lot_get_timestamp(self._dc_lot)
if ts == 0:
return None
return datetime.utcfromtimestamp(ts)

View File

@@ -213,15 +213,6 @@ def wait_configuration_progress(account, target):
break
def wait_securejoin_inviter_progress(account, target):
while 1:
evt_name, data1, data2 = \
account._evlogger.get_matching("DC_EVENT_SECUREJOIN_INVITER_PROGRESS")
if data2 >= target:
print("** SECUREJOINT-INVITER PROGRESS {}".format(target), account)
break
def wait_successful_IMAP_SMTP_connection(account):
imap_ok = smtp_ok = False
while not imap_ok or not smtp_ok:

View File

@@ -4,7 +4,7 @@ import os
from deltachat import const, Account
from deltachat.message import Message
from datetime import datetime, timedelta
from conftest import wait_configuration_progress, wait_successful_IMAP_SMTP_connection, wait_securejoin_inviter_progress
from conftest import wait_configuration_progress, wait_successful_IMAP_SMTP_connection
class TestOfflineAccountBasic:
@@ -140,13 +140,6 @@ 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")
@@ -313,16 +306,6 @@ class TestOfflineChat:
chat1.set_draft(None)
assert chat1.get_draft() is None
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()
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:
def test_one_account_init(self, acfactory):
@@ -563,29 +546,3 @@ class TestOnlineAccount:
print("*************** Setup Code: ", setup_code)
msg.continue_key_transfer(setup_code)
assert ac1.get_info()["fingerprint"] == ac2.get_info()["fingerprint"]
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")
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)

View File

@@ -854,7 +854,7 @@ pub fn unarchive(context: &Context, chat_id: u32) -> Result<(), Error> {
/// However, this does not imply, the message really reached the recipient -
/// sending may be delayed eg. due to network problems. However, from your
/// view, you're done with the message. Sooner or later it will find its way.
pub fn send_msg<'a>(
pub unsafe fn send_msg<'a>(
context: &'a Context,
chat_id: u32,
msg: &mut Message<'a>,
@@ -872,7 +872,7 @@ pub fn send_msg<'a>(
}
ensure!(
unsafe { job_send_msg(context, msg.id) } != 0,
job_send_msg(context, msg.id) != 0,
"Failed to initiate send job"
);
@@ -1394,7 +1394,7 @@ pub unsafe fn add_contact_to_chat(context: &Context, chat_id: u32, contact_id: u
// TODO should return bool /rtn
#[allow(non_snake_case)]
pub fn add_contact_to_chat_ex(
pub unsafe fn add_contact_to_chat_ex(
context: &Context,
chat_id: u32,
contact_id: u32,
@@ -1407,7 +1407,7 @@ pub fn add_contact_to_chat_ex(
if contact.is_err() || chat_id <= DC_CHAT_ID_LAST_SPECIAL {
return 0;
}
let mut msg = unsafe { dc_msg_new_untyped(context) };
let mut msg = dc_msg_new_untyped(context);
reset_gossiped_timestamp(context, chat_id);
let contact = contact.unwrap();
@@ -1918,7 +1918,16 @@ pub fn get_chat_cnt(context: &Context) -> usize {
}
}
pub fn get_chat_id_by_grpid(context: &Context, grpid: impl AsRef<str>) -> (u32, bool, Blocked) {
pub unsafe fn get_chat_id_by_grpid(
context: &Context,
grpid: impl AsRef<str>,
ret_blocked: Option<&mut Blocked>,
ret_verified: *mut libc::c_int,
) -> u32 {
if !ret_verified.is_null() {
*ret_verified = 0;
}
context
.sql
.query_row(
@@ -1927,12 +1936,17 @@ pub fn get_chat_id_by_grpid(context: &Context, grpid: impl AsRef<str>) -> (u32,
|row| {
let chat_id = row.get(0)?;
let b = row.get::<_, Option<Blocked>>(1)?.unwrap_or_default();
if let Some(b) = ret_blocked {
*b = row.get::<_, Option<Blocked>>(1)?.unwrap_or_default();
}
let v = row.get::<_, Option<Chattype>>(2)?.unwrap_or_default();
Ok((chat_id, v == Chattype::VerifiedGroup, b))
*ret_verified = (v == Chattype::VerifiedGroup) as libc::c_int;
Ok(chat_id)
},
)
.unwrap_or((0, false, Blocked::Not))
.unwrap_or_default()
}
pub fn add_device_msg(context: &Context, chat_id: u32, text: impl AsRef<str>) {

File diff suppressed because it is too large Load Diff

View File

@@ -42,7 +42,7 @@ impl Default for Blocked {
pub const DC_IMAP_SEEN: u32 = 0x1;
pub const DC_HANDSHAKE_CONTINUE_NORMAL_PROCESSING: i32 = 0x01;
const DC_HANDSHAKE_CONTINUE_NORMAL_PROCESSING: i32 = 0x01;
pub const DC_HANDSHAKE_STOP_NORMAL_PROCESSING: i32 = 0x02;
pub const DC_HANDSHAKE_ADD_DELETE_JOB: i32 = 0x04;
@@ -169,12 +169,6 @@ const DC_LP_IMAP_SOCKET_FLAGS: usize =
const DC_LP_SMTP_SOCKET_FLAGS: usize =
(DC_LP_SMTP_SOCKET_STARTTLS | DC_LP_SMTP_SOCKET_SSL | DC_LP_SMTP_SOCKET_PLAIN);
// QR code scanning (view from Bob, the joiner)
pub const DC_VC_AUTH_REQUIRED: i32 = 2;
pub const DC_VC_CONTACT_CONFIRM: i32 = 6;
pub const DC_BOB_ERROR: i32 = 0;
pub const DC_BOB_SUCCESS: i32 = 1;
#[derive(Debug, Display, Clone, Copy, PartialEq, Eq, FromPrimitive, ToPrimitive, FromSql, ToSql)]
#[repr(i32)]
pub enum Viewtype {

View File

@@ -103,7 +103,7 @@ pub unsafe fn dc_imex_has_backup(
pub unsafe fn dc_initiate_key_transfer(context: &Context) -> *mut libc::c_char {
let mut setup_file_name: *mut libc::c_char = ptr::null_mut();
let mut msg: Message;
if !dc_alloc_ongoing(context) {
if dc_alloc_ongoing(context) == 0 {
return std::ptr::null_mut();
}
let setup_code = dc_create_setup_code(context);
@@ -502,9 +502,11 @@ pub unsafe fn dc_normalize_setup_code(
pub unsafe fn dc_job_do_DC_JOB_IMEX_IMAP(context: &Context, job: &Job) {
let mut ok_to_continue = true;
let mut success: libc::c_int = 0;
let mut ongoing_allocated_here: libc::c_int = 0;
let what: libc::c_int;
if dc_alloc_ongoing(context) {
if !(0 == dc_alloc_ongoing(context)) {
ongoing_allocated_here = 1;
what = job.param.get_int(Param::Cmd).unwrap_or_default();
let param1_s = job.param.get(Param::Arg).unwrap_or_default();
let param1 = CString::yolo(param1_s);
@@ -562,6 +564,9 @@ pub unsafe fn dc_job_do_DC_JOB_IMEX_IMAP(context: &Context, job: &Job) {
}
}
}
}
if 0 != ongoing_allocated_here {
dc_free_ongoing(context);
}
context.call_cb(

View File

@@ -15,6 +15,7 @@ use crate::constants::*;
use crate::contact::*;
use crate::context::{do_heuristics_moves, Context};
use crate::dc_mimeparser::*;
use crate::dc_securejoin::*;
use crate::dc_strencode::*;
use crate::dc_tools::*;
use crate::error::Result;
@@ -23,7 +24,6 @@ use crate::location;
use crate::message::*;
use crate::param::*;
use crate::peerstate::*;
use crate::securejoin::handle_securejoin_handshake;
use crate::sql;
use crate::stock::StockMessage;
use crate::types::*;
@@ -400,7 +400,7 @@ unsafe fn add_parts(
msgrmsg = 1;
*chat_id = 0;
allow_creation = 1;
let handshake = handle_securejoin_handshake(context, mime_parser, *from_id);
let handshake = dc_handle_securejoin_handshake(context, mime_parser, *from_id);
if 0 != handshake & DC_HANDSHAKE_STOP_NORMAL_PROCESSING {
*hidden = 1;
*add_delete_job = handshake & DC_HANDSHAKE_ADD_DELETE_JOB;
@@ -1034,6 +1034,7 @@ unsafe fn create_or_lookup_group(
let group_explicitly_left: bool;
let mut chat_id = 0;
let mut chat_id_blocked = Blocked::Not;
let mut chat_id_verified = 0;
let mut grpid = "".to_string();
let mut grpname = std::ptr::null_mut();
let to_ids_cnt = to_ids.len();
@@ -1215,9 +1216,14 @@ unsafe fn create_or_lookup_group(
set_better_msg(mime_parser, &better_msg);
// check, if we have a chat with this group ID
let (mut chat_id, chat_id_verified, _blocked) = chat::get_chat_id_by_grpid(context, &grpid);
chat_id = chat::get_chat_id_by_grpid(
context,
&grpid,
Some(&mut chat_id_blocked),
&mut chat_id_verified,
);
if chat_id != 0 {
if chat_id_verified
if 0 != chat_id_verified
&& 0 == check_verified_properties(
context,
mime_parser,

1009
src/dc_securejoin.rs Normal file

File diff suppressed because it is too large Load Diff

View File

@@ -10,17 +10,20 @@ pub const DC_TOKEN_INVITENUMBER: dc_tokennamespc_t = 100;
// Functions to read/write token from/to the database. A token is any string associated with a key.
pub fn dc_token_save(context: &Context, namespc: dc_tokennamespc_t, foreign_id: u32) -> String {
pub fn dc_token_save(
context: &Context,
namespc: dc_tokennamespc_t,
foreign_id: u32,
token: &str,
) -> bool {
// foreign_id may be 0
let token = dc_create_id();
sql::execute(
context,
&context.sql,
"INSERT INTO tokens (namespc, foreign_id, token, timestamp) VALUES (?, ?, ?, ?);",
params![namespc as i32, foreign_id as i32, &token, time()],
params![namespc as i32, foreign_id as i32, token, time()],
)
.ok();
token
.is_ok()
}
pub fn dc_token_lookup(
@@ -36,15 +39,6 @@ pub fn dc_token_lookup(
)
}
pub fn dc_token_lookup_or_new(
context: &Context,
namespc: dc_tokennamespc_t,
foreign_id: u32,
) -> String {
dc_token_lookup(context, namespc, foreign_id)
.unwrap_or_else(|| dc_token_save(context, namespc, foreign_id))
}
pub fn dc_token_exists(context: &Context, namespc: dc_tokennamespc_t, token: &str) -> bool {
context
.sql

View File

@@ -23,13 +23,13 @@ use crate::aheader::*;
use crate::config::Config;
use crate::context::Context;
use crate::dc_mimeparser::*;
use crate::dc_securejoin::*;
use crate::dc_tools::*;
use crate::error::*;
use crate::key::*;
use crate::keyring::*;
use crate::peerstate::*;
use crate::pgp::*;
use crate::securejoin::handle_degrade_event;
use crate::types::*;
use crate::x::*;
@@ -440,7 +440,7 @@ impl E2eeHelper {
}
if let Some(ref peerstate) = peerstate {
if peerstate.degrade_event.is_some() {
handle_degrade_event(context, &peerstate);
dc_handle_degrade_event(context, &peerstate);
}
if let Some(ref key) = peerstate.gossip_key {
public_keyring_for_validate.add_ref(key);
@@ -681,7 +681,7 @@ unsafe fn update_gossip_peerstates(
}
if let Some(peerstate) = peerstate {
if peerstate.degrade_event.is_some() {
handle_degrade_event(context, &peerstate);
dc_handle_degrade_event(context, &peerstate);
}
}

View File

@@ -548,17 +548,19 @@ impl Imap {
}
let (teardown, can_idle, has_xlist) = match &mut *self.session.lock().unwrap() {
Some(ref mut session) => match session.capabilities() {
Ok(caps) => {
Some(ref mut session) => {
if let Ok(caps) = session.capabilities() {
if !context.sql.is_open() {
warn!(context, 0, "IMAP-LOGIN as {} ok but ABORTING", lp.mail_user,);
(true, false, false)
} else {
let can_idle = caps.has_str("IDLE");
let has_xlist = caps.has_str("XLIST");
let caps_list = caps
.iter()
.fold(String::new(), |s, c| s + &format!(" {:?}", c));
let can_idle = caps.has("IDLE");
let has_xlist = caps.has("XLIST");
let caps_list = caps.iter().fold(String::new(), |mut s, c| {
s += " ";
s += c;
s
});
log_event!(
context,
Event::IMAP_CONNECTED,
@@ -569,12 +571,10 @@ impl Imap {
);
(false, can_idle, has_xlist)
}
}
Err(err) => {
info!(context, 0, "CAPABILITY command error: {}", err);
} else {
(true, false, false)
}
},
}
None => (true, false, false),
};

View File

@@ -111,6 +111,11 @@ impl Job {
#[allow(non_snake_case)]
fn do_DC_JOB_SEND(&mut self, context: &Context) {
let ok_to_continue;
let mut filename = ptr::null_mut();
let mut buf = ptr::null_mut();
let mut buf_bytes = 0;
/* connect to SMTP server, if not yet done */
if !context.smtp.lock().unwrap().is_connected() {
let loginparam = dc_loginparam_read(context, &context.sql, "configured_");
@@ -118,12 +123,19 @@ impl Job {
if !connected {
self.try_again_later(3i32, None);
return;
ok_to_continue = false;
} else {
ok_to_continue = true;
}
} else {
ok_to_continue = true;
}
if let Some(filename) = self.param.get(Param::File) {
if let Some(body) = dc_read_file_safe(context, filename) {
if ok_to_continue {
let filename_s = self.param.get(Param::File).unwrap_or_default();
filename = unsafe { filename_s.strdup() };
if unsafe { strlen(filename) } == 0 {
warn!(context, 0, "Missing file name for job {}", self.job_id,);
} else if 0 != unsafe { dc_read_file(context, filename, &mut buf, &mut buf_bytes) } {
if let Some(recipients) = self.param.get(Param::Recipients) {
let recipients_list = recipients
.split("\x1e")
@@ -135,50 +147,63 @@ impl Job {
}
})
.collect::<Vec<_>>();
/* if there is a msg-id and it does not exist in the db, cancel sending.
this happends if dc_delete_msgs() was called
before the generated mime was sent out */
if 0 != self.foreign_id
&& 0 == unsafe { dc_msg_exists(context, self.foreign_id) }
{
warn!(
context,
0, "Message {} for job {} does not exist", self.foreign_id, self.job_id,
);
return;
};
// hold the smtp lock during sending of a job and
// its ok/error response processing. Note that if a message
// was sent we need to mark it in the database as we
// otherwise might send it twice.
let mut sock = context.smtp.lock().unwrap();
if 0 == sock.send(context, recipients_list, body) {
sock.disconnect();
self.try_again_later(-1i32, Some(as_str(sock.error)));
} else {
dc_delete_file(context, filename);
if 0 != self.foreign_id {
dc_update_msg_state(
let ok_to_continue1;
if 0 != self.foreign_id {
if 0 == unsafe { dc_msg_exists(context, self.foreign_id) } {
warn!(
context,
0,
"Message {} for job {} does not exist",
self.foreign_id,
MessageState::OutDelivered,
self.job_id,
);
let chat_id: i32 = context
.sql
.query_row_col(
ok_to_continue1 = false;
} else {
ok_to_continue1 = true;
}
} else {
ok_to_continue1 = true;
}
if ok_to_continue1 {
/* send message */
let body = unsafe {
std::slice::from_raw_parts(buf as *const u8, buf_bytes).to_vec()
};
// hold the smtp lock during sending of a job and
// its ok/error response processing. Note that if a message
// was sent we need to mark it in the database as we
// otherwise might send it twice.
let mut sock = context.smtp.lock().unwrap();
if 0 == sock.send(context, recipients_list, body) {
sock.disconnect();
self.try_again_later(-1i32, Some(as_str(sock.error)));
} else {
dc_delete_file(context, filename_s);
if 0 != self.foreign_id {
dc_update_msg_state(
context,
"SELECT chat_id FROM msgs WHERE id=?",
params![self.foreign_id as i32],
0,
)
.unwrap_or_default();
context.call_cb(
Event::MSG_DELIVERED,
chat_id as uintptr_t,
self.foreign_id as uintptr_t,
);
self.foreign_id,
MessageState::OutDelivered,
);
let chat_id: i32 = context
.sql
.query_row_col(
context,
"SELECT chat_id FROM msgs WHERE id=?",
params![self.foreign_id as i32],
0,
)
.unwrap_or_default();
context.call_cb(
Event::MSG_DELIVERED,
chat_id as uintptr_t,
self.foreign_id as uintptr_t,
);
}
}
}
} else {
@@ -186,6 +211,8 @@ impl Job {
}
}
}
unsafe { free(buf) };
unsafe { free(filename.cast()) };
}
// this value does not increase the number of tries

View File

@@ -57,11 +57,11 @@ mod dc_loginparam;
mod dc_mimefactory;
pub mod dc_mimeparser;
pub mod dc_receive_imf;
pub mod dc_securejoin;
mod dc_simplify;
mod dc_strencode;
mod dc_token;
pub mod dc_tools;
pub mod securejoin;
#[cfg(test)]
mod test_utils;

View File

@@ -220,7 +220,7 @@ pub fn send_locations_to_chat(context: &Context, chat_id: u32, seconds: i64) {
msg.text =
Some(context.stock_system_msg(StockMessage::MsgLocationEnabled, "", "", 0));
msg.param.set_int(Param::Cmd, 8);
chat::send_msg(context, chat_id, &mut msg).unwrap();
unsafe { chat::send_msg(context, chat_id, &mut msg).unwrap() };
} else if 0 == seconds && is_sending_locations_before {
let stock_str =
context.stock_system_msg(StockMessage::MsgLocationDisabled, "", "", 0);
@@ -607,7 +607,7 @@ pub fn job_do_DC_JOB_MAYBE_SEND_LOCATIONS(context: &Context, _job: &Job) {
msg.hidden = true;
msg.param.set_int(Param::Cmd, 9);
// TODO: handle cleanup on error
chat::send_msg(context, chat_id as u32, &mut msg).unwrap();
unsafe { chat::send_msg(context, chat_id as u32, &mut msg).unwrap() };
}
Ok(())
},

View File

@@ -57,10 +57,3 @@ macro_rules! log_event {
formatted_c.as_ptr() as libc::uintptr_t);
}};
}
#[macro_export]
macro_rules! emit_event {
($ctx:expr, $event:expr, $data1:expr, $data2:expr) => {
$ctx.call_cb($event, $data1 as libc::uintptr_t, $data2 as libc::uintptr_t);
};
}

View File

@@ -178,11 +178,8 @@ impl<'a> Peerstate<'a> {
OR gossip_key_fingerprint=? COLLATE NOCASE \
ORDER BY public_key_fingerprint=? DESC;";
Self::from_stmt(
context,
query,
params![fingerprint, fingerprint, fingerprint],
)
let fp = fingerprint.as_bytes();
Self::from_stmt(context, query, params![fp, fp, fp])
}
fn from_stmt<P>(context: &'a Context, query: &str, params: P) -> Option<Self>
@@ -526,10 +523,6 @@ mod tests {
// clear to_save, as that is not persissted
peerstate.to_save = None;
assert_eq!(peerstate, peerstate_new);
let peerstate_new2 =
Peerstate::from_fingerprint(&ctx.ctx, &ctx.ctx.sql, &pub_key.fingerprint())
.expect("failed to load peerstate from db");
assert_eq!(peerstate, peerstate_new2);
}
#[test]

View File

@@ -1,782 +0,0 @@
use mmime::mailimf_types::*;
use percent_encoding::{utf8_percent_encode, AsciiSet, NON_ALPHANUMERIC};
use std::ptr;
use crate::aheader::EncryptPreference;
use crate::chat::{self, Chat};
use crate::configure::*;
use crate::constants::*;
use crate::contact::*;
use crate::context::Context;
use crate::dc_mimeparser::*;
use crate::dc_token::*;
use crate::dc_tools::*;
use crate::e2ee::*;
use crate::error::Error;
use crate::key::*;
use crate::lot::LotState;
use crate::message::*;
use crate::param::*;
use crate::peerstate::*;
use crate::qr::check_qr;
use crate::stock::StockMessage;
use crate::types::*;
pub const NON_ALPHANUMERIC_WITHOUT_DOT: &AsciiSet = &NON_ALPHANUMERIC.remove(b'.');
macro_rules! progress {
($context:tt, $event:expr, $contact_id:expr, $progress:expr) => {
assert!(
$progress >= 0 && $progress <= 1000,
"value in range 0..1000 expected with: 0=error, 1..999=progress, 1000=success"
);
$context.call_cb($event, $contact_id as uintptr_t, $progress as uintptr_t);
};
}
macro_rules! joiner_progress {
($context:tt, $contact_id:expr, $progress:expr) => {
progress!(
$context,
Event::SECUREJOIN_JOINER_PROGRESS,
$contact_id,
$progress
);
};
}
macro_rules! inviter_progress {
($context:tt, $contact_id:expr, $progress:expr) => {
progress!(
$context,
Event::SECUREJOIN_INVITER_PROGRESS,
$contact_id,
$progress
);
};
}
macro_rules! get_qr_attr {
($context:tt, $attr:ident) => {
$context
.bob
.read()
.unwrap()
.qr_scan
.as_ref()
.unwrap()
.$attr
.as_ref()
.unwrap()
};
}
pub fn dc_get_securejoin_qr(context: &Context, group_chat_id: uint32_t) -> Option<String> {
/* =========================================================
==== Alice - the inviter side ====
==== Step 1 in "Setup verified contact" protocol ====
========================================================= */
let fingerprint: String;
ensure_secret_key_exists(context).ok();
let invitenumber = dc_token_lookup_or_new(context, DC_TOKEN_INVITENUMBER, group_chat_id);
let auth = dc_token_lookup_or_new(context, DC_TOKEN_AUTH, group_chat_id);
let self_addr = match context.sql.get_config(context, "configured_addr") {
Some(addr) => addr,
None => {
error!(context, 0, "Not configured, cannot generate QR code.",);
return None;
}
};
let self_name = context
.sql
.get_config(context, "displayname")
.unwrap_or_default();
fingerprint = match get_self_fingerprint(context) {
Some(fp) => fp,
None => {
return None;
}
};
let self_addr_urlencoded =
utf8_percent_encode(&self_addr, NON_ALPHANUMERIC_WITHOUT_DOT).to_string();
let self_name_urlencoded =
utf8_percent_encode(&self_name, NON_ALPHANUMERIC_WITHOUT_DOT).to_string();
let qr = if 0 != group_chat_id {
if let Ok(chat) = Chat::load_from_db(context, group_chat_id) {
let group_name = chat.get_name();
let group_name_urlencoded =
utf8_percent_encode(&group_name, NON_ALPHANUMERIC).to_string();
Some(format!(
"OPENPGP4FPR:{}#a={}&g={}&x={}&i={}&s={}",
fingerprint,
self_addr_urlencoded,
&group_name_urlencoded,
&chat.grpid,
&invitenumber,
&auth,
))
} else {
error!(
context,
0, "Cannot get QR-code for chat-id {}", group_chat_id,
);
return None;
}
} else {
Some(format!(
"OPENPGP4FPR:{}#a={}&n={}&i={}&s={}",
fingerprint, self_addr_urlencoded, self_name_urlencoded, &invitenumber, &auth,
))
};
info!(context, 0, "Generated QR code: {}", qr.as_ref().unwrap());
qr
}
fn get_self_fingerprint(context: &Context) -> Option<String> {
if let Some(self_addr) = context.sql.get_config(context, "configured_addr") {
if let Some(key) = Key::from_self_public(context, self_addr, &context.sql) {
return Some(key.fingerprint());
}
}
None
}
pub fn dc_join_securejoin(context: &Context, qr: &str) -> uint32_t {
let cleanup =
|context: &Context, contact_chat_id: u32, ongoing_allocated: bool, join_vg: bool| {
let mut bob = context.bob.write().unwrap();
bob.expects = 0;
let ret_chat_id = if bob.status == DC_BOB_SUCCESS {
if join_vg {
chat::get_chat_id_by_grpid(
context,
bob.qr_scan.as_ref().unwrap().text2.as_ref().unwrap(),
)
.0
} else {
contact_chat_id
}
} else {
0
};
bob.qr_scan = None;
if ongoing_allocated {
dc_free_ongoing(context);
}
ret_chat_id as uint32_t
};
/* ==========================================================
==== Bob - the joiner's side =====
==== Step 2 in "Setup verified contact" protocol =====
========================================================== */
let mut contact_chat_id: uint32_t = 0;
let mut join_vg: bool = false;
info!(context, 0, "Requesting secure-join ...",);
ensure_secret_key_exists(context).ok();
if !dc_alloc_ongoing(context) {
return cleanup(&context, contact_chat_id, false, join_vg);
}
let qr_scan = check_qr(context, &qr);
if qr_scan.state != LotState::QrAskVerifyContact && qr_scan.state != LotState::QrAskVerifyGroup
{
error!(context, 0, "Unknown QR code.",);
return cleanup(&context, contact_chat_id, true, join_vg);
}
contact_chat_id = chat::create_by_contact_id(context, qr_scan.id).unwrap_or_default();
if contact_chat_id == 0 {
error!(context, 0, "Unknown contact.",);
return cleanup(&context, contact_chat_id, true, join_vg);
}
if check_exit(context) {
return cleanup(&context, contact_chat_id, true, join_vg);
}
join_vg = qr_scan.get_state() == LotState::QrAskVerifyGroup;
{
let mut bob = context.bob.write().unwrap();
bob.status = 0;
bob.qr_scan = Some(qr_scan);
}
if fingerprint_equals_sender(
context,
context
.bob
.read()
.unwrap()
.qr_scan
.as_ref()
.unwrap()
.fingerprint
.as_ref()
.unwrap(),
contact_chat_id,
) {
info!(context, 0, "Taking protocol shortcut.");
context.bob.write().unwrap().expects = DC_VC_CONTACT_CONFIRM;
joiner_progress!(context, chat_id_2_contact_id(context, contact_chat_id), 400);
let own_fingerprint = get_self_fingerprint(context).unwrap();
send_handshake_msg(
context,
contact_chat_id,
if join_vg {
"vg-request-with-auth"
} else {
"vc-request-with-auth"
},
get_qr_attr!(context, auth).to_string(),
Some(own_fingerprint),
if join_vg {
get_qr_attr!(context, text2).to_string()
} else {
"".to_string()
},
);
} else {
context.bob.write().unwrap().expects = DC_VC_AUTH_REQUIRED;
send_handshake_msg(
context,
contact_chat_id,
if join_vg { "vg-request" } else { "vc-request" },
get_qr_attr!(context, invitenumber),
None,
"",
);
}
// Bob -> Alice
while !check_exit(&context) {
std::thread::sleep(std::time::Duration::new(0, 3_000_000));
}
cleanup(&context, contact_chat_id, true, join_vg)
}
fn check_exit(context: &Context) -> bool {
context
.running_state
.clone()
.read()
.unwrap()
.shall_stop_ongoing
}
fn send_handshake_msg(
context: &Context,
contact_chat_id: uint32_t,
step: &str,
param2: impl AsRef<str>,
fingerprint: Option<String>,
grpid: impl AsRef<str>,
) {
let mut msg = unsafe { dc_msg_new_untyped(context) };
msg.type_0 = Viewtype::Text;
msg.text = Some(format!("Secure-Join: {}", step));
msg.hidden = true;
msg.param.set_int(Param::Cmd, 7);
if step.is_empty() {
msg.param.remove(Param::Arg);
} else {
msg.param.set(Param::Arg, step);
}
if !param2.as_ref().is_empty() {
msg.param.set(Param::Arg2, param2);
}
if let Some(fp) = fingerprint {
msg.param.set(Param::Arg3, fp);
}
if !grpid.as_ref().is_empty() {
msg.param.set(Param::Arg4, grpid.as_ref());
}
if step == "vg-request" || step == "vc-request" {
msg.param.set_int(
Param::ForcePlaintext,
ForcePlaintext::AddAutocryptHeader as i32,
);
} else {
msg.param.set_int(Param::GuranteeE2ee, 1);
}
// TODO. handle cleanup on error
chat::send_msg(context, contact_chat_id, &mut msg).unwrap();
}
fn chat_id_2_contact_id(context: &Context, contact_chat_id: uint32_t) -> uint32_t {
let contacts = chat::get_chat_contacts(context, contact_chat_id);
if contacts.len() == 1 {
contacts[0]
} else {
0
}
}
fn fingerprint_equals_sender(
context: &Context,
fingerprint: impl AsRef<str>,
contact_chat_id: u32,
) -> bool {
let contacts = chat::get_chat_contacts(context, contact_chat_id);
if contacts.len() == 1 {
if let Ok(contact) = Contact::load_from_db(context, contacts[0]) {
if let Some(peerstate) = Peerstate::from_addr(context, &context.sql, contact.get_addr())
{
let fingerprint_normalized = dc_normalize_fingerprint(fingerprint.as_ref());
if peerstate.public_key_fingerprint.is_some()
&& &fingerprint_normalized == peerstate.public_key_fingerprint.as_ref().unwrap()
{
return true;
}
}
}
}
false
}
/* library private: secure-join */
pub fn handle_securejoin_handshake(
context: &Context,
mimeparser: &dc_mimeparser_t,
contact_id: uint32_t,
) -> libc::c_int {
let own_fingerprint: String;
if contact_id <= DC_CONTACT_ID_LAST_SPECIAL {
return 0;
}
let step = match lookup_field(mimeparser, "Secure-Join") {
Some(s) => s,
None => {
return 0;
}
};
info!(
context,
0, ">>>>>>>>>>>>>>>>>>>>>>>>> secure-join message \'{}\' received", step,
);
let (contact_chat_id, contact_chat_id_blocked) =
chat::create_or_lookup_by_contact_id(context, contact_id, Blocked::Not).unwrap_or_default();
if contact_chat_id_blocked != Blocked::Not {
chat::unblock(context, contact_chat_id);
}
let mut ret: libc::c_int = DC_HANDSHAKE_STOP_NORMAL_PROCESSING;
let join_vg = step.starts_with("vg-");
match step.as_str() {
"vg-request" | "vc-request" => {
/* =========================================================
==== Alice - the inviter side ====
==== Step 3 in "Setup verified contact" protocol ====
========================================================= */
// this message may be unencrypted (Bob, the joinder and the sender, might not have Alice's key yet)
// it just ensures, we have Bobs key now. If we do _not_ have the key because eg. MitM has removed it,
// send_message() will fail with the error "End-to-end-encryption unavailable unexpectedly.", so, there is no additional check needed here.
// verify that the `Secure-Join-Invitenumber:`-header matches invitenumber written to the QR code
let invitenumber = match lookup_field(mimeparser, "Secure-Join-Invitenumber") {
Some(n) => n,
None => {
warn!(context, 0, "Secure-join denied (invitenumber missing).",);
return ret;
}
};
if !dc_token_exists(context, DC_TOKEN_INVITENUMBER, &invitenumber) {
warn!(context, 0, "Secure-join denied (bad invitenumber).",);
return ret;
}
info!(context, 0, "Secure-join requested.",);
inviter_progress!(context, contact_id, 300);
send_handshake_msg(
context,
contact_chat_id,
&format!("{}-auth-required", &step[..2]),
"",
None,
"",
);
}
"vg-auth-required" | "vc-auth-required" => {
let cond = {
let bob = context.bob.read().unwrap();
let scan = bob.qr_scan.as_ref();
scan.is_none()
|| bob.expects != DC_VC_AUTH_REQUIRED
|| join_vg && scan.unwrap().state != LotState::QrAskVerifyGroup
};
if cond {
warn!(context, 0, "auth-required message out of sync.",);
// no error, just aborted somehow or a mail from another handshake
return ret;
}
let scanned_fingerprint_of_alice = get_qr_attr!(context, fingerprint).to_string();
let auth = get_qr_attr!(context, auth).to_string();
if !encrypted_and_signed(mimeparser, &scanned_fingerprint_of_alice) {
could_not_establish_secure_connection(
context,
contact_chat_id,
if mimeparser.e2ee_helper.encrypted {
"No valid signature."
} else {
"Not encrypted."
},
);
end_bobs_joining(context, DC_BOB_ERROR);
return ret;
}
if !fingerprint_equals_sender(context, &scanned_fingerprint_of_alice, contact_chat_id) {
could_not_establish_secure_connection(
context,
contact_chat_id,
"Fingerprint mismatch on joiner-side.",
);
end_bobs_joining(context, DC_BOB_ERROR);
return ret;
}
info!(context, 0, "Fingerprint verified.",);
own_fingerprint = get_self_fingerprint(context).unwrap();
joiner_progress!(context, contact_id, 400);
context.bob.write().unwrap().expects = DC_VC_CONTACT_CONFIRM;
send_handshake_msg(
context,
contact_chat_id,
&format!("{}-request-with-auth", &step[..2]),
auth,
Some(own_fingerprint),
if join_vg {
get_qr_attr!(context, text2).to_string()
} else {
"".to_string()
},
);
}
"vg-request-with-auth" | "vc-request-with-auth" => {
/* ============================================================
==== Alice - the inviter side ====
==== Steps 5+6 in "Setup verified contact" protocol ====
==== Step 6 in "Out-of-band verified groups" protocol ====
============================================================ */
// verify that Secure-Join-Fingerprint:-header matches the fingerprint of Bob
let fingerprint = match lookup_field(mimeparser, "Secure-Join-Fingerprint") {
Some(fp) => fp,
None => {
could_not_establish_secure_connection(
context,
contact_chat_id,
"Fingerprint not provided.",
);
return ret;
}
};
if !encrypted_and_signed(mimeparser, &fingerprint) {
could_not_establish_secure_connection(
context,
contact_chat_id,
"Auth not encrypted.",
);
return ret;
}
if !fingerprint_equals_sender(context, &fingerprint, contact_chat_id) {
could_not_establish_secure_connection(
context,
contact_chat_id,
"Fingerprint mismatch on inviter-side.",
);
return ret;
}
info!(context, 0, "Fingerprint verified.",);
// verify that the `Secure-Join-Auth:`-header matches the secret written to the QR code
let auth_0 = match lookup_field(mimeparser, "Secure-Join-Auth") {
Some(auth) => auth,
None => {
could_not_establish_secure_connection(
context,
contact_chat_id,
"Auth not provided.",
);
return ret;
}
};
if !dc_token_exists(context, DC_TOKEN_AUTH, &auth_0) {
could_not_establish_secure_connection(context, contact_chat_id, "Auth invalid.");
return ret;
}
if mark_peer_as_verified(context, fingerprint).is_err() {
could_not_establish_secure_connection(
context,
contact_chat_id,
"Fingerprint mismatch on inviter-side.",
);
return ret;
}
Contact::scaleup_origin_by_id(context, contact_id, Origin::SecurejoinInvited);
info!(context, 0, "Auth verified.",);
secure_connection_established(context, contact_chat_id);
emit_event!(context, Event::CONTACTS_CHANGED, contact_id, 0);
inviter_progress!(context, contact_id, 600);
if join_vg {
let field_grpid = lookup_field(mimeparser, "Secure-Join-Group").unwrap_or_default();
let (group_chat_id, _, _) = chat::get_chat_id_by_grpid(context, &field_grpid);
if group_chat_id == 0 {
error!(context, 0, "Chat {} not found.", &field_grpid);
return ret;
} else {
chat::add_contact_to_chat_ex(context, group_chat_id, contact_id, 0x1i32);
}
} else {
send_handshake_msg(context, contact_chat_id, "vc-contact-confirm", "", None, "");
inviter_progress!(context, contact_id, 1000);
}
}
"vg-member-added" | "vc-contact-confirm" => {
if join_vg {
ret = DC_HANDSHAKE_CONTINUE_NORMAL_PROCESSING;
}
if context.bob.read().unwrap().expects != DC_VC_CONTACT_CONFIRM {
info!(context, 0, "Message belongs to a different handshake.",);
return ret;
}
let cond = {
let bob = context.bob.read().unwrap();
let scan = bob.qr_scan.as_ref();
scan.is_none() || join_vg && scan.unwrap().state != LotState::QrAskVerifyGroup
};
if cond {
warn!(
context,
0, "Message out of sync or belongs to a different handshake.",
);
return ret;
}
let scanned_fingerprint_of_alice = get_qr_attr!(context, fingerprint).to_string();
let vg_expect_encrypted = if join_vg {
let group_id = get_qr_attr!(context, text2).to_string();
let (_, is_verified_group, _) = chat::get_chat_id_by_grpid(context, group_id);
// when joining a non-verified group
// the vg-member-added message may be unencrypted
// when not all group members have keys or prefer encryption.
// So only expect encryption if this is a verified group
is_verified_group
} else {
// setup contact is always encrypted
true
};
if vg_expect_encrypted
&& !encrypted_and_signed(mimeparser, &scanned_fingerprint_of_alice)
{
could_not_establish_secure_connection(
context,
contact_chat_id,
"Contact confirm message not encrypted.",
);
end_bobs_joining(context, DC_BOB_ERROR);
return ret;
}
if mark_peer_as_verified(context, &scanned_fingerprint_of_alice).is_err() {
could_not_establish_secure_connection(
context,
contact_chat_id,
"Fingerprint mismatch on joiner-side.",
);
return ret;
}
Contact::scaleup_origin_by_id(context, contact_id, Origin::SecurejoinJoined);
emit_event!(context, Event::CONTACTS_CHANGED, 0, 0);
let cg_member_added =
lookup_field(mimeparser, "Chat-Group-Member-Added").unwrap_or_default();
if join_vg && !addr_equals_self(context, cg_member_added) {
info!(context, 0, "Message belongs to a different handshake (scaled up contact anyway to allow creation of group).");
return ret;
}
secure_connection_established(context, contact_chat_id);
context.bob.write().unwrap().expects = 0;
if join_vg {
send_handshake_msg(
context,
contact_chat_id,
"vg-member-added-received",
"",
None,
"",
);
}
end_bobs_joining(context, DC_BOB_SUCCESS);
}
"vg-member-added-received" => {
/* ============================================================
==== Alice - the inviter side ====
==== Step 8 in "Out-of-band verified groups" protocol ====
============================================================ */
if let Ok(contact) = Contact::get_by_id(context, contact_id) {
if contact.is_verified() == VerifiedStatus::Unverified {
warn!(context, 0, "vg-member-added-received invalid.",);
return ret;
}
inviter_progress!(context, contact_id, 800);
inviter_progress!(context, contact_id, 1000);
} else {
warn!(context, 0, "vg-member-added-received invalid.",);
return ret;
}
}
_ => {
warn!(context, 0, "invalid step: {}", step);
}
}
if ret == DC_HANDSHAKE_STOP_NORMAL_PROCESSING {
ret |= DC_HANDSHAKE_ADD_DELETE_JOB;
}
ret
}
fn end_bobs_joining(context: &Context, status: libc::c_int) {
context.bob.write().unwrap().status = status;
dc_stop_ongoing_process(context);
}
fn secure_connection_established(context: &Context, contact_chat_id: uint32_t) {
let contact_id: uint32_t = chat_id_2_contact_id(context, contact_chat_id);
let contact = Contact::get_by_id(context, contact_id);
let addr = if let Ok(ref contact) = contact {
contact.get_addr()
} else {
"?"
};
let msg = context.stock_string_repl_str(StockMessage::ContactVerified, addr);
chat::add_device_msg(context, contact_chat_id, msg);
emit_event!(context, Event::CHAT_MODIFIED, contact_chat_id, 0);
}
fn lookup_field(mimeparser: &dc_mimeparser_t, key: &str) -> Option<String> {
let field: *mut mailimf_field = dc_mimeparser_lookup_field(mimeparser, key);
unsafe {
let mut value: *const libc::c_char = ptr::null();
if field.is_null()
|| (*field).fld_type != MAILIMF_FIELD_OPTIONAL_FIELD as libc::c_int
|| (*field).fld_data.fld_optional_field.is_null()
|| {
value = (*(*field).fld_data.fld_optional_field).fld_value;
value.is_null()
}
{
return None;
}
Some(as_str(value).to_string())
}
}
fn could_not_establish_secure_connection(
context: &Context,
contact_chat_id: uint32_t,
details: &str,
) {
let contact_id = chat_id_2_contact_id(context, contact_chat_id);
let contact = Contact::get_by_id(context, contact_id);
let msg = context.stock_string_repl_str(
StockMessage::ContactNotVerified,
if let Ok(ref contact) = contact {
contact.get_addr()
} else {
"?"
},
);
chat::add_device_msg(context, contact_chat_id, &msg);
error!(context, 0, "{} ({})", &msg, details);
}
fn mark_peer_as_verified(context: &Context, fingerprint: impl AsRef<str>) -> Result<(), Error> {
if let Some(ref mut peerstate) =
Peerstate::from_fingerprint(context, &context.sql, fingerprint.as_ref())
{
if peerstate.set_verified(1, fingerprint.as_ref(), 2) {
peerstate.prefer_encrypt = EncryptPreference::Mutual;
peerstate.to_save = Some(ToSave::All);
peerstate.save_to_db(&context.sql, false);
return Ok(());
}
}
bail!(
"could not mark peer as verified for fingerprint {}",
fingerprint.as_ref()
);
}
/* ******************************************************************************
* Tools: Misc.
******************************************************************************/
fn encrypted_and_signed(
mimeparser: &dc_mimeparser_t,
expected_fingerprint: impl AsRef<str>,
) -> bool {
if !mimeparser.e2ee_helper.encrypted {
warn!(mimeparser.context, 0, "Message not encrypted.",);
false
} else if mimeparser.e2ee_helper.signatures.len() <= 0 {
warn!(mimeparser.context, 0, "Message not signed.",);
false
} else if expected_fingerprint.as_ref().is_empty() {
warn!(mimeparser.context, 0, "Fingerprint for comparison missing.",);
false
} else if !mimeparser
.e2ee_helper
.signatures
.contains(expected_fingerprint.as_ref())
{
warn!(
mimeparser.context,
0,
"Message does not match expected fingerprint {}.",
expected_fingerprint.as_ref(),
);
false
} else {
true
}
}
pub fn handle_degrade_event(context: &Context, peerstate: &Peerstate) {
// - we do not issue an warning for DC_DE_ENCRYPTION_PAUSED as this is quite normal
// - currently, we do not issue an extra warning for DC_DE_VERIFICATION_LOST - this always comes
// together with DC_DE_FINGERPRINT_CHANGED which is logged, the idea is not to bother
// with things they cannot fix, so the user is just kicked from the verified group
// (and he will know this and can fix this)
if Some(DegradeEvent::FingerprintChanged) == peerstate.degrade_event {
let contact_id: i32 = context
.sql
.query_row_col(
context,
"SELECT id FROM contacts WHERE addr=?;",
params![&peerstate.addr],
0,
)
.unwrap_or_default();
if contact_id > 0 {
let (contact_chat_id, _) =
chat::create_or_lookup_by_contact_id(context, contact_id as u32, Blocked::Deaddrop)
.unwrap_or_default();
let peeraddr: &str = match peerstate.addr {
Some(ref addr) => &addr,
None => "",
};
let msg = context.stock_string_repl_str(StockMessage::ContactSetupChanged, peeraddr);
chat::add_device_msg(context, contact_chat_id, msg);
emit_event!(context, Event::CHAT_MODIFIED, contact_chat_id, 0);
}
}
}