mirror of
https://github.com/twonlyapp/twonly-app.git
synced 2026-04-18 14:22:53 +00:00
started with ud
This commit is contained in:
parent
8aacdc5235
commit
87ba1c23e5
16 changed files with 1394 additions and 21 deletions
2
rust/.gitignore
vendored
2
rust/.gitignore
vendored
|
|
@ -1 +1,3 @@
|
|||
/target
|
||||
|
||||
tests/tmp_testing.db*
|
||||
560
rust/Cargo.lock
generated
560
rust/Cargo.lock
generated
|
|
@ -71,9 +71,9 @@ dependencies = [
|
|||
|
||||
[[package]]
|
||||
name = "anyhow"
|
||||
version = "1.0.75"
|
||||
version = "1.0.102"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "a4668cab20f66d8d020e1fbc0ebe47217433c1b6c8f2040faf858554e394ace6"
|
||||
checksum = "7f202df86484c868dbad7eaa557ef785d5c66295e41b460ef922eca0723b842c"
|
||||
|
||||
[[package]]
|
||||
name = "atoi"
|
||||
|
|
@ -90,6 +90,15 @@ version = "0.5.3"
|
|||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "c59bdb34bc650a32731b31bd8f0829cc15d24a708ee31559e0bb34f2bc320cba"
|
||||
|
||||
[[package]]
|
||||
name = "atomic-polyfill"
|
||||
version = "1.0.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "8cf2bce30dfe09ef0bfaef228b9d414faaf7e563035494d7fe092dba54b300f4"
|
||||
dependencies = [
|
||||
"critical-section",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "autocfg"
|
||||
version = "1.1.0"
|
||||
|
|
@ -132,6 +141,17 @@ dependencies = [
|
|||
"serde_core",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "blahaj"
|
||||
version = "0.6.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "5106bf2680d585dc5f29711b8aa5dde353180b8e14af89b7f0424f760c84e7ce"
|
||||
dependencies = [
|
||||
"hashbrown 0.15.5",
|
||||
"rand 0.8.5",
|
||||
"zeroize",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "block-buffer"
|
||||
version = "0.10.4"
|
||||
|
|
@ -187,6 +207,17 @@ version = "1.0.0"
|
|||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd"
|
||||
|
||||
[[package]]
|
||||
name = "chacha20"
|
||||
version = "0.10.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "6f8d983286843e49675a4b7a2d174efe136dc93a18d69130dd18198a6c167601"
|
||||
dependencies = [
|
||||
"cfg-if",
|
||||
"cpufeatures 0.3.0",
|
||||
"rand_core 0.10.0",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "chrono"
|
||||
version = "0.4.44"
|
||||
|
|
@ -198,6 +229,15 @@ dependencies = [
|
|||
"windows-link",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "cobs"
|
||||
version = "0.3.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "0fa961b519f0b462e3a3b4a34b64d119eeaca1d59af726fe450bbba07a9fc0a1"
|
||||
dependencies = [
|
||||
"thiserror",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "concurrent-queue"
|
||||
version = "2.5.0"
|
||||
|
|
@ -238,6 +278,15 @@ dependencies = [
|
|||
"libc",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "cpufeatures"
|
||||
version = "0.3.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "8b2a41393f66f16b0823bb79094d54ac5fbd34ab292ddafb9a0456ac9f87d201"
|
||||
dependencies = [
|
||||
"libc",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "crc"
|
||||
version = "3.4.0"
|
||||
|
|
@ -253,6 +302,12 @@ version = "2.4.0"
|
|||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "19d374276b40fb8bbdee95aef7c7fa6b5316ec764510eb64b8dd0e2ed0d7e7f5"
|
||||
|
||||
[[package]]
|
||||
name = "critical-section"
|
||||
version = "1.2.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "790eea4361631c5e7d22598ecd5723ff611904e3344ce8720784c93e3d83d40b"
|
||||
|
||||
[[package]]
|
||||
name = "crossbeam-queue"
|
||||
version = "0.3.12"
|
||||
|
|
@ -360,6 +415,18 @@ dependencies = [
|
|||
"serde",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "embedded-io"
|
||||
version = "0.4.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "ef1a6892d9eef45c8fa6b9e0086428a2cca8491aca8f787c534a3d6d0bcb3ced"
|
||||
|
||||
[[package]]
|
||||
name = "embedded-io"
|
||||
version = "0.6.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "edd0f118536f44f5ccd48bcb8b111bdc3de888b58c74639dfb034a357d0f206d"
|
||||
|
||||
[[package]]
|
||||
name = "env_filter"
|
||||
version = "0.1.4"
|
||||
|
|
@ -408,12 +475,24 @@ dependencies = [
|
|||
"pin-project-lite",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "fastrand"
|
||||
version = "2.4.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "9f1f227452a390804cdb637b74a86990f2a7d7ba4b7d5693aac9b4dd6defd8d6"
|
||||
|
||||
[[package]]
|
||||
name = "find-msvc-tools"
|
||||
version = "0.1.9"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "5baebc0774151f905a1a2cc41989300b1e6fbb29aff0ceffa1064fdd3088d582"
|
||||
|
||||
[[package]]
|
||||
name = "fixedbitset"
|
||||
version = "0.5.7"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "1d674e81391d1e1ab681a28d99df07927c6d4aa5b027d7da16ba32d1d21ecd99"
|
||||
|
||||
[[package]]
|
||||
name = "flume"
|
||||
version = "0.11.1"
|
||||
|
|
@ -609,12 +688,35 @@ dependencies = [
|
|||
"wasi",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "getrandom"
|
||||
version = "0.4.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "0de51e6874e94e7bf76d726fc5d13ba782deca734ff60d5bb2fb2607c7406555"
|
||||
dependencies = [
|
||||
"cfg-if",
|
||||
"libc",
|
||||
"r-efi",
|
||||
"rand_core 0.10.0",
|
||||
"wasip2",
|
||||
"wasip3",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "gimli"
|
||||
version = "0.28.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "4271d37baee1b8c7e4b708028c57d816cf9d2434acb33a549475f78c181f6253"
|
||||
|
||||
[[package]]
|
||||
name = "hash32"
|
||||
version = "0.2.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "b0c35f58762feb77d74ebe43bdbc3210f09be9fe6742234d573bacc26ed92b67"
|
||||
dependencies = [
|
||||
"byteorder",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "hashbrown"
|
||||
version = "0.14.5"
|
||||
|
|
@ -627,6 +729,8 @@ version = "0.15.5"
|
|||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "9229cfe53dfd69f0609a49f65461bd93001ea1ef889cd5529dd176593f5338a1"
|
||||
dependencies = [
|
||||
"allocator-api2",
|
||||
"equivalent",
|
||||
"foldhash 0.1.5",
|
||||
]
|
||||
|
||||
|
|
@ -656,6 +760,20 @@ dependencies = [
|
|||
"hashbrown 0.15.5",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "heapless"
|
||||
version = "0.7.17"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "cdc6457c0eb62c71aac4bc17216026d8410337c4126773b9c5daba343f17964f"
|
||||
dependencies = [
|
||||
"atomic-polyfill",
|
||||
"hash32",
|
||||
"rustc_version",
|
||||
"serde",
|
||||
"spin 0.9.8",
|
||||
"stable_deref_trait",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "heck"
|
||||
version = "0.5.0"
|
||||
|
|
@ -807,6 +925,12 @@ dependencies = [
|
|||
"zerovec",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "id-arena"
|
||||
version = "2.3.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "3d3067d79b975e8844ca9eb072e16b31c3c1c36928edf9c6789548c524d0d954"
|
||||
|
||||
[[package]]
|
||||
name = "idna"
|
||||
version = "1.1.0"
|
||||
|
|
@ -836,6 +960,17 @@ checksum = "d466e9454f08e4a911e14806c24e16fba1b4c121d1ea474396f396069cf949d9"
|
|||
dependencies = [
|
||||
"equivalent",
|
||||
"hashbrown 0.17.0",
|
||||
"serde",
|
||||
"serde_core",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "itertools"
|
||||
version = "0.14.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "2b192c782037fadd9cfa75548310488aabdbf3d2da73885b31bd0abd03351285"
|
||||
dependencies = [
|
||||
"either",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
|
|
@ -862,6 +997,12 @@ dependencies = [
|
|||
"spin 0.5.2",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "leb128fmt"
|
||||
version = "0.1.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "09edd9e8b54e49e587e4f6295a7d29c3ea94d469cb40ab8ca70b288248a81db2"
|
||||
|
||||
[[package]]
|
||||
name = "libc"
|
||||
version = "0.2.184"
|
||||
|
|
@ -897,6 +1038,12 @@ dependencies = [
|
|||
"vcpkg",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "linux-raw-sys"
|
||||
version = "0.4.15"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "d26c52dbd32dccf2d10cac7725f8eae5296885fb5703b261f7d0a0739ec807ab"
|
||||
|
||||
[[package]]
|
||||
name = "litemap"
|
||||
version = "0.8.2"
|
||||
|
|
@ -954,6 +1101,21 @@ dependencies = [
|
|||
"windows-sys 0.61.2",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "multimap"
|
||||
version = "0.10.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "1d87ecb2933e8aeadb3e3a02b828fed80a7528047e68b4f424523a0981a3a084"
|
||||
|
||||
[[package]]
|
||||
name = "nu-ansi-term"
|
||||
version = "0.50.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "7957b9740744892f114936ab4a57b3f487491bbeafaf8083688b16841a4240e5"
|
||||
dependencies = [
|
||||
"windows-sys 0.61.2",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "num-bigint-dig"
|
||||
version = "0.8.6"
|
||||
|
|
@ -965,7 +1127,7 @@ dependencies = [
|
|||
"num-integer",
|
||||
"num-iter",
|
||||
"num-traits",
|
||||
"rand",
|
||||
"rand 0.8.5",
|
||||
"smallvec",
|
||||
"zeroize",
|
||||
]
|
||||
|
|
@ -1080,6 +1242,17 @@ version = "2.3.2"
|
|||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "9b4f627cb1b25917193a259e49bdad08f671f8d9708acfd5fe0a8c1455d87220"
|
||||
|
||||
[[package]]
|
||||
name = "petgraph"
|
||||
version = "0.8.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "8701b58ea97060d5e5b155d383a69952a60943f0e6dfe30b04c287beb0b27455"
|
||||
dependencies = [
|
||||
"fixedbitset",
|
||||
"hashbrown 0.15.5",
|
||||
"indexmap",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "pin-project-lite"
|
||||
version = "0.2.13"
|
||||
|
|
@ -1131,6 +1304,19 @@ version = "1.13.1"
|
|||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "c33a9471896f1c69cecef8d20cbe2f7accd12527ce60845ff44c153bb2a21b49"
|
||||
|
||||
[[package]]
|
||||
name = "postcard"
|
||||
version = "1.1.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "6764c3b5dd454e283a30e6dfe78e9b31096d9e32036b5d1eaac7a6119ccb9a24"
|
||||
dependencies = [
|
||||
"cobs",
|
||||
"embedded-io 0.4.0",
|
||||
"embedded-io 0.6.1",
|
||||
"heapless",
|
||||
"serde",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "potential_utf"
|
||||
version = "0.1.5"
|
||||
|
|
@ -1149,6 +1335,16 @@ dependencies = [
|
|||
"zerocopy",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "prettyplease"
|
||||
version = "0.2.37"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "479ca8adacdd7ce8f1fb39ce9ecccbfe93a3f1344b3d0d97f20bc0196208f62b"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"syn",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "proc-macro2"
|
||||
version = "1.0.106"
|
||||
|
|
@ -1158,6 +1354,57 @@ dependencies = [
|
|||
"unicode-ident",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "prost"
|
||||
version = "0.14.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "d2ea70524a2f82d518bce41317d0fae74151505651af45faf1ffbd6fd33f0568"
|
||||
dependencies = [
|
||||
"bytes",
|
||||
"prost-derive",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "prost-build"
|
||||
version = "0.14.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "343d3bd7056eda839b03204e68deff7d1b13aba7af2b2fd16890697274262ee7"
|
||||
dependencies = [
|
||||
"heck",
|
||||
"itertools",
|
||||
"log",
|
||||
"multimap",
|
||||
"petgraph",
|
||||
"prettyplease",
|
||||
"prost",
|
||||
"prost-types",
|
||||
"regex",
|
||||
"syn",
|
||||
"tempfile",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "prost-derive"
|
||||
version = "0.14.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "27c6023962132f4b30eb4c172c91ce92d933da334c59c23cddee82358ddafb0b"
|
||||
dependencies = [
|
||||
"anyhow",
|
||||
"itertools",
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"syn",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "prost-types"
|
||||
version = "0.14.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "8991c4cbdb8bc5b11f0b074ffe286c30e523de90fee5ba8132f1399f23cb3dd7"
|
||||
dependencies = [
|
||||
"prost",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "quote"
|
||||
version = "1.0.45"
|
||||
|
|
@ -1167,6 +1414,12 @@ dependencies = [
|
|||
"proc-macro2",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "r-efi"
|
||||
version = "6.0.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "f8dcc9c7d52a811697d2151c701e0d08956f92b0e24136cf4cf27b57a6a0d9bf"
|
||||
|
||||
[[package]]
|
||||
name = "rand"
|
||||
version = "0.8.5"
|
||||
|
|
@ -1175,7 +1428,18 @@ checksum = "34af8d1a0e25924bc5b7c43c079c942339d8f0a8b57c39049bef581b46327404"
|
|||
dependencies = [
|
||||
"libc",
|
||||
"rand_chacha",
|
||||
"rand_core",
|
||||
"rand_core 0.6.4",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "rand"
|
||||
version = "0.10.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "d2e8e8bcc7961af1fdac401278c6a831614941f6164ee3bf4ce61b7edb162207"
|
||||
dependencies = [
|
||||
"chacha20",
|
||||
"getrandom 0.4.2",
|
||||
"rand_core 0.10.0",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
|
|
@ -1185,7 +1449,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
|
|||
checksum = "e6c10a63a0fa32252be49d21e7709d4d4baf8d231c2dbce1eaa8141b9b127d88"
|
||||
dependencies = [
|
||||
"ppv-lite86",
|
||||
"rand_core",
|
||||
"rand_core 0.6.4",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
|
|
@ -1194,9 +1458,15 @@ version = "0.6.4"
|
|||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "ec0be4795e2f6a28069bec0b5ff3e2ac9bafc99e6a9a7dc3547996c5c816922c"
|
||||
dependencies = [
|
||||
"getrandom",
|
||||
"getrandom 0.2.17",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "rand_core"
|
||||
version = "0.10.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "0c8d0fd677905edcbeedbf2edb6494d676f0e98d54d5cf9bda0b061cb8fb8aba"
|
||||
|
||||
[[package]]
|
||||
name = "redox_syscall"
|
||||
version = "0.5.18"
|
||||
|
|
@ -1257,7 +1527,7 @@ dependencies = [
|
|||
"num-traits",
|
||||
"pkcs1",
|
||||
"pkcs8",
|
||||
"rand_core",
|
||||
"rand_core 0.6.4",
|
||||
"signature",
|
||||
"spki",
|
||||
"subtle",
|
||||
|
|
@ -1268,11 +1538,18 @@ dependencies = [
|
|||
name = "rust_lib_twonly"
|
||||
version = "0.1.0"
|
||||
dependencies = [
|
||||
"blahaj",
|
||||
"flutter_rust_bridge",
|
||||
"postcard",
|
||||
"prost",
|
||||
"prost-build",
|
||||
"rand 0.10.1",
|
||||
"serde",
|
||||
"sqlx",
|
||||
"thiserror",
|
||||
"tokio",
|
||||
"tracing",
|
||||
"tracing-subscriber",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
|
|
@ -1281,6 +1558,28 @@ version = "0.1.23"
|
|||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "d626bb9dae77e28219937af045c257c28bfd3f69333c512553507f5f9798cb76"
|
||||
|
||||
[[package]]
|
||||
name = "rustc_version"
|
||||
version = "0.4.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "cfcb3a22ef46e85b45de6ee7e79d063319ebb6594faafcf1c225ea92ab6e9b92"
|
||||
dependencies = [
|
||||
"semver",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "rustix"
|
||||
version = "0.38.44"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "fdb5bc1ae2baa591800df16c9ca78619bf65c0488b41b96ccec5d11220d8c154"
|
||||
dependencies = [
|
||||
"bitflags",
|
||||
"errno",
|
||||
"libc",
|
||||
"linux-raw-sys",
|
||||
"windows-sys 0.59.0",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "ryu"
|
||||
version = "1.0.23"
|
||||
|
|
@ -1293,6 +1592,12 @@ version = "1.2.0"
|
|||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "94143f37725109f92c262ed2cf5e59bce7498c01bcc1502d7b9afe439a4e9f49"
|
||||
|
||||
[[package]]
|
||||
name = "semver"
|
||||
version = "1.0.28"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "8a7852d02fc848982e0c167ef163aaff9cd91dc640ba85e263cb1ce46fae51cd"
|
||||
|
||||
[[package]]
|
||||
name = "serde"
|
||||
version = "1.0.228"
|
||||
|
|
@ -1355,7 +1660,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
|
|||
checksum = "e3bf829a2d51ab4a5ddf1352d8470c140cadc8301b2ae1789db023f01cedd6ba"
|
||||
dependencies = [
|
||||
"cfg-if",
|
||||
"cpufeatures",
|
||||
"cpufeatures 0.2.17",
|
||||
"digest",
|
||||
]
|
||||
|
||||
|
|
@ -1366,10 +1671,19 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
|
|||
checksum = "a7507d819769d01a365ab707794a4084392c824f54a7a6a7862f8c3d0892b283"
|
||||
dependencies = [
|
||||
"cfg-if",
|
||||
"cpufeatures",
|
||||
"cpufeatures 0.2.17",
|
||||
"digest",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "sharded-slab"
|
||||
version = "0.1.7"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "f40ca3c46823713e0d4209592e8d6e826aa57e928f09752619fc696c499637f6"
|
||||
dependencies = [
|
||||
"lazy_static",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "shlex"
|
||||
version = "1.3.0"
|
||||
|
|
@ -1393,7 +1707,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
|
|||
checksum = "77549399552de45a898a580c1b41d445bf730df867cc44e6c0233bbc4b8329de"
|
||||
dependencies = [
|
||||
"digest",
|
||||
"rand_core",
|
||||
"rand_core 0.6.4",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
|
|
@ -1565,7 +1879,7 @@ dependencies = [
|
|||
"md-5",
|
||||
"memchr",
|
||||
"percent-encoding",
|
||||
"rand",
|
||||
"rand 0.8.5",
|
||||
"rsa",
|
||||
"serde",
|
||||
"sha1",
|
||||
|
|
@ -1603,7 +1917,7 @@ dependencies = [
|
|||
"log",
|
||||
"md-5",
|
||||
"memchr",
|
||||
"rand",
|
||||
"rand 0.8.5",
|
||||
"serde",
|
||||
"serde_json",
|
||||
"sha2",
|
||||
|
|
@ -1685,6 +1999,18 @@ dependencies = [
|
|||
"syn",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "tempfile"
|
||||
version = "3.10.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "85b77fafb263dd9d05cbeac119526425676db3784113aa9295c88498cbf8bff1"
|
||||
dependencies = [
|
||||
"cfg-if",
|
||||
"fastrand",
|
||||
"rustix",
|
||||
"windows-sys 0.52.0",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "thiserror"
|
||||
version = "2.0.18"
|
||||
|
|
@ -1705,6 +2031,15 @@ dependencies = [
|
|||
"syn",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "thread_local"
|
||||
version = "1.1.9"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "f60246a4944f24f6e018aa17cdeffb7818b76356965d03b07d6a9886e8962185"
|
||||
dependencies = [
|
||||
"cfg-if",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "threadpool"
|
||||
version = "1.8.1"
|
||||
|
|
@ -1808,6 +2143,32 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
|
|||
checksum = "db97caf9d906fbde555dd62fa95ddba9eecfd14cb388e4f491a66d74cd5fb79a"
|
||||
dependencies = [
|
||||
"once_cell",
|
||||
"valuable",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "tracing-log"
|
||||
version = "0.2.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "ee855f1f400bd0e5c02d150ae5de3840039a3f54b025156404e34c23c03f47c3"
|
||||
dependencies = [
|
||||
"log",
|
||||
"once_cell",
|
||||
"tracing-core",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "tracing-subscriber"
|
||||
version = "0.3.23"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "cb7f578e5945fb242538965c2d0b04418d38ec25c79d160cd279bf0731c8d319"
|
||||
dependencies = [
|
||||
"nu-ansi-term",
|
||||
"sharded-slab",
|
||||
"smallvec",
|
||||
"thread_local",
|
||||
"tracing-core",
|
||||
"tracing-log",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
|
|
@ -1843,6 +2204,12 @@ version = "0.1.4"
|
|||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "7df058c713841ad818f1dc5d3fd88063241cc61f49f5fbea4b951e8cf5a8d71d"
|
||||
|
||||
[[package]]
|
||||
name = "unicode-xid"
|
||||
version = "0.2.6"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "ebc1c04c71510c7f702b52b7c350734c9ff1295c464a03335b00bb84fc54f853"
|
||||
|
||||
[[package]]
|
||||
name = "url"
|
||||
version = "2.5.8"
|
||||
|
|
@ -1861,6 +2228,12 @@ version = "1.0.4"
|
|||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "b6c140620e7ffbb22c2dee59cafe6084a59b5ffc27a8859a5f0d494b5d52b6be"
|
||||
|
||||
[[package]]
|
||||
name = "valuable"
|
||||
version = "0.1.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "ba73ea9cf16a25df0c8caa16c51acb937d5712a8429db78a3ee29d5dcacd3a65"
|
||||
|
||||
[[package]]
|
||||
name = "vcpkg"
|
||||
version = "0.2.15"
|
||||
|
|
@ -1879,6 +2252,24 @@ version = "0.11.1+wasi-snapshot-preview1"
|
|||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "ccf3ec651a847eb01de73ccad15eb7d99f80485de043efb2f370cd654f4ea44b"
|
||||
|
||||
[[package]]
|
||||
name = "wasip2"
|
||||
version = "1.0.2+wasi-0.2.9"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "9517f9239f02c069db75e65f174b3da828fe5f5b945c4dd26bd25d89c03ebcf5"
|
||||
dependencies = [
|
||||
"wit-bindgen",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "wasip3"
|
||||
version = "0.4.0+wasi-0.3.0-rc-2026-01-06"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "5428f8bf88ea5ddc08faddef2ac4a67e390b88186c703ce6dbd955e1c145aca5"
|
||||
dependencies = [
|
||||
"wit-bindgen",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "wasite"
|
||||
version = "0.1.0"
|
||||
|
|
@ -1951,6 +2342,40 @@ version = "0.2.92"
|
|||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "af190c94f2773fdb3729c55b007a722abb5384da03bc0986df4c289bf5567e96"
|
||||
|
||||
[[package]]
|
||||
name = "wasm-encoder"
|
||||
version = "0.244.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "990065f2fe63003fe337b932cfb5e3b80e0b4d0f5ff650e6985b1048f62c8319"
|
||||
dependencies = [
|
||||
"leb128fmt",
|
||||
"wasmparser",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "wasm-metadata"
|
||||
version = "0.244.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "bb0e353e6a2fbdc176932bbaab493762eb1255a7900fe0fea1a2f96c296cc909"
|
||||
dependencies = [
|
||||
"anyhow",
|
||||
"indexmap",
|
||||
"wasm-encoder",
|
||||
"wasmparser",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "wasmparser"
|
||||
version = "0.244.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "47b807c72e1bac69382b3a6fb3dbe8ea4c0ed87ff5629b8685ae6b9a611028fe"
|
||||
dependencies = [
|
||||
"bitflags",
|
||||
"hashbrown 0.15.5",
|
||||
"indexmap",
|
||||
"semver",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "web-sys"
|
||||
version = "0.3.66"
|
||||
|
|
@ -2030,6 +2455,15 @@ dependencies = [
|
|||
"windows-link",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "windows-sys"
|
||||
version = "0.52.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "282be5f36a8ce781fad8c8ae18fa3f9beff57ec1b52cb3de0789201425d9a33d"
|
||||
dependencies = [
|
||||
"windows-targets",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "windows-sys"
|
||||
version = "0.59.0"
|
||||
|
|
@ -2112,6 +2546,94 @@ version = "0.52.6"
|
|||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "589f6da84c646204747d1270a2a5661ea66ed1cced2631d546fdfb155959f9ec"
|
||||
|
||||
[[package]]
|
||||
name = "wit-bindgen"
|
||||
version = "0.51.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "d7249219f66ced02969388cf2bb044a09756a083d0fab1e566056b04d9fbcaa5"
|
||||
dependencies = [
|
||||
"wit-bindgen-rust-macro",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "wit-bindgen-core"
|
||||
version = "0.51.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "ea61de684c3ea68cb082b7a88508a8b27fcc8b797d738bfc99a82facf1d752dc"
|
||||
dependencies = [
|
||||
"anyhow",
|
||||
"heck",
|
||||
"wit-parser",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "wit-bindgen-rust"
|
||||
version = "0.51.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "b7c566e0f4b284dd6561c786d9cb0142da491f46a9fbed79ea69cdad5db17f21"
|
||||
dependencies = [
|
||||
"anyhow",
|
||||
"heck",
|
||||
"indexmap",
|
||||
"prettyplease",
|
||||
"syn",
|
||||
"wasm-metadata",
|
||||
"wit-bindgen-core",
|
||||
"wit-component",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "wit-bindgen-rust-macro"
|
||||
version = "0.51.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "0c0f9bfd77e6a48eccf51359e3ae77140a7f50b1e2ebfe62422d8afdaffab17a"
|
||||
dependencies = [
|
||||
"anyhow",
|
||||
"prettyplease",
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"syn",
|
||||
"wit-bindgen-core",
|
||||
"wit-bindgen-rust",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "wit-component"
|
||||
version = "0.244.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "9d66ea20e9553b30172b5e831994e35fbde2d165325bec84fc43dbf6f4eb9cb2"
|
||||
dependencies = [
|
||||
"anyhow",
|
||||
"bitflags",
|
||||
"indexmap",
|
||||
"log",
|
||||
"serde",
|
||||
"serde_derive",
|
||||
"serde_json",
|
||||
"wasm-encoder",
|
||||
"wasm-metadata",
|
||||
"wasmparser",
|
||||
"wit-parser",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "wit-parser"
|
||||
version = "0.244.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "ecc8ac4bc1dc3381b7f59c34f00b67e18f910c2c0f50015669dde7def656a736"
|
||||
dependencies = [
|
||||
"anyhow",
|
||||
"id-arena",
|
||||
"indexmap",
|
||||
"log",
|
||||
"semver",
|
||||
"serde",
|
||||
"serde_derive",
|
||||
"serde_json",
|
||||
"unicode-xid",
|
||||
"wasmparser",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "writeable"
|
||||
version = "0.6.3"
|
||||
|
|
@ -2187,6 +2709,20 @@ name = "zeroize"
|
|||
version = "1.8.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "b97154e67e32c85465826e8bcc1c59429aaaf107c1e4a9e53c8d8ccd5eff88d0"
|
||||
dependencies = [
|
||||
"zeroize_derive",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "zeroize_derive"
|
||||
version = "1.4.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "85a5b4158499876c763cb03bc4e49185d3cccbabb15b33c627f7884f43db852e"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"syn",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "zerotrie"
|
||||
|
|
|
|||
|
|
@ -20,6 +20,13 @@ sqlx = { version = "0.9.0-alpha.1", default-features = false, features = [
|
|||
] }
|
||||
tokio = { version = "1.44", features = ["full"] }
|
||||
tracing = "0.1.44"
|
||||
serde = "1.0.228"
|
||||
prost = "0.14.1"
|
||||
rand = "0.10.1"
|
||||
tracing-subscriber = "0.3.23"
|
||||
blahaj = "0.6.0"
|
||||
postcard = { version = "1.1.3", features = ["alloc"] }
|
||||
|
||||
[lints.rust]
|
||||
unexpected_cfgs = { level = "warn", check-cfg = ['cfg(frb_expand)'] }
|
||||
|
||||
[build-dependencies]
|
||||
prost-build = "0.14.1"
|
||||
|
|
|
|||
5
rust/build.rs
Normal file
5
rust/build.rs
Normal file
|
|
@ -0,0 +1,5 @@
|
|||
use std::io::Result;
|
||||
fn main() -> Result<()> {
|
||||
prost_build::compile_protos(&["src/user_discovery/types.proto"], &["src/"])?;
|
||||
Ok(())
|
||||
}
|
||||
|
|
@ -1,9 +1,5 @@
|
|||
// Table is defined in contacts.table.dart
|
||||
|
||||
use sqlx::{
|
||||
types::chrono::{DateTime, Utc},
|
||||
FromRow,
|
||||
};
|
||||
// use sqlx::types::chrono::{DateTime, Utc};
|
||||
use sqlx::FromRow;
|
||||
|
||||
use crate::twonly::{database::Database, error::Result};
|
||||
|
||||
|
|
@ -11,7 +7,7 @@ use crate::twonly::{database::Database, error::Result};
|
|||
struct ContactRow {
|
||||
pub(crate) user_id: i64,
|
||||
pub(crate) username: String,
|
||||
pub(crate) created_at: DateTime<Utc>,
|
||||
// pub(crate) created_at: DateTime<Utc>,
|
||||
}
|
||||
|
||||
pub struct Contact {
|
||||
|
|
@ -38,3 +34,23 @@ impl Contact {
|
|||
Ok(rows.into_iter().map(Into::into).collect())
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use crate::twonly::{database::contact::Contact, tests::initialize_twonly_for_testing};
|
||||
|
||||
#[tokio::test]
|
||||
async fn test_get_all_contacts() {
|
||||
let twonly = initialize_twonly_for_testing().await.unwrap();
|
||||
|
||||
let contacts = Contact::get_all_contacts(&twonly.database).await.unwrap();
|
||||
|
||||
let users = vec!["alice", "bob", "charlie", "diana", "eve", "frank", "grace"];
|
||||
|
||||
assert_eq!(contacts.len(), users.len());
|
||||
|
||||
for contact in contacts {
|
||||
assert_eq!(users[contact.user_id as usize], &contact.username);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -11,6 +11,7 @@ pub struct TwonlyConfig {
|
|||
}
|
||||
|
||||
struct Twonly {
|
||||
#[allow(dead_code)]
|
||||
pub(crate) config: TwonlyConfig,
|
||||
database: Arc<Database>,
|
||||
}
|
||||
|
|
@ -39,3 +40,38 @@ pub async fn get_all_contacts() -> Result<Vec<Contact>> {
|
|||
let twonly = get_instance()?;
|
||||
Contact::get_all_contacts(twonly.database.as_ref()).await
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
pub(crate) mod tests {
|
||||
use super::error::Result;
|
||||
use super::Twonly;
|
||||
use std::path::PathBuf;
|
||||
|
||||
use crate::twonly::{get_instance, initialize_twonly, TwonlyConfig};
|
||||
|
||||
pub(super) async fn initialize_twonly_for_testing() -> Result<&'static Twonly> {
|
||||
let default_twonly_database = PathBuf::from("tests/testing.db");
|
||||
|
||||
if !default_twonly_database.is_file() {
|
||||
panic!("{} not found!", default_twonly_database.display())
|
||||
}
|
||||
|
||||
let copied_twonly_database = default_twonly_database
|
||||
.parent()
|
||||
.unwrap()
|
||||
.join("tmp_testing.db");
|
||||
if copied_twonly_database.exists() {
|
||||
std::fs::remove_file(&copied_twonly_database).unwrap();
|
||||
}
|
||||
|
||||
std::fs::copy(default_twonly_database, &copied_twonly_database).unwrap();
|
||||
|
||||
initialize_twonly(TwonlyConfig {
|
||||
database_path: copied_twonly_database.display().to_string(),
|
||||
})
|
||||
.await
|
||||
.unwrap();
|
||||
|
||||
get_instance()
|
||||
}
|
||||
}
|
||||
|
|
|
|||
10
rust/src/user_discovery/README.md
Normal file
10
rust/src/user_discovery/README.md
Normal file
|
|
@ -0,0 +1,10 @@
|
|||
|
||||
|
||||
|
||||
// **Store** promotions:
|
||||
// version_id, contact_id, Option<UserDiscoveryMessage>
|
||||
// -> In case a contact_id deleted his account deleted or was removed
|
||||
// - Remove the previous row (version_id must be increased...)
|
||||
// - Create a new entry with User Discovery Recall
|
||||
// -> Otherwise this promotion contains the Promotion
|
||||
//
|
||||
28
rust/src/user_discovery/error.rs
Normal file
28
rust/src/user_discovery/error.rs
Normal file
|
|
@ -0,0 +1,28 @@
|
|||
use prost::DecodeError;
|
||||
use thiserror::Error;
|
||||
|
||||
pub type Result<T> = core::result::Result<T, UserDiscoveryError>;
|
||||
|
||||
#[derive(Error, Debug)]
|
||||
pub enum UserDiscoveryError {
|
||||
#[error("The encrypted announcement data contains malicious data: `{0}`")]
|
||||
MaliciousAnnouncementData(String),
|
||||
|
||||
#[error("no shares left.")]
|
||||
NoSharesLeft,
|
||||
|
||||
#[error("User discovery contains no configuration.")]
|
||||
NotInitialized,
|
||||
|
||||
#[error("`{0}`")]
|
||||
PostcardError(#[from] postcard::Error),
|
||||
|
||||
#[error("error while calculating shamirs secret shares: `{0}`")]
|
||||
ShamirsSecret(String),
|
||||
|
||||
#[error("tried to push a invalid version")]
|
||||
PushedInvalidVersion,
|
||||
|
||||
#[error("`{0}`")]
|
||||
Prost(#[from] DecodeError),
|
||||
}
|
||||
|
|
@ -0,0 +1,471 @@
|
|||
mod error;
|
||||
pub mod stores;
|
||||
mod traits;
|
||||
|
||||
use blahaj::{Share, Sharks};
|
||||
use postcard::{from_bytes, to_allocvec};
|
||||
use prost::Message;
|
||||
use serde::{Deserialize, Serialize};
|
||||
use crate::user_discovery::error::{Result, UserDiscoveryError};
|
||||
use crate::user_discovery::traits::UserDiscoveryUtils;
|
||||
use crate::user_discovery::user_discovery_message::{UserDiscoveryAnnouncement, UserDiscoveryPromotion};
|
||||
use crate::user_discovery::user_discovery_message::user_discovery_promotion::AnnouncementShareDecrypted;
|
||||
use crate::user_discovery::user_discovery_message::user_discovery_promotion::announcement_share_decrypted::SignedData;
|
||||
pub use traits::UserDiscoveryStore;
|
||||
|
||||
pub type UserID = i64;
|
||||
|
||||
include!(concat!(env!("OUT_DIR"), "/_.rs"));
|
||||
|
||||
#[derive(Serialize, Deserialize, Clone, Debug)]
|
||||
struct UserDiscoveryConfig {
|
||||
/// The number of required shares to get the secret
|
||||
threshold: u8,
|
||||
/// Currently limited to <= 255 as GF 256 is used
|
||||
total_number_of_shares: usize,
|
||||
/// Version of announcements
|
||||
announcement_version: u32,
|
||||
/// Version of promotions
|
||||
promotion_version: u32,
|
||||
/// This is a random public_id associated with a single announcement.
|
||||
public_id: u64,
|
||||
/// Verification shares
|
||||
verification_shares: Vec<Vec<u8>>,
|
||||
}
|
||||
|
||||
impl Default for UserDiscoveryConfig {
|
||||
fn default() -> Self {
|
||||
Self {
|
||||
threshold: 2,
|
||||
total_number_of_shares: 255,
|
||||
announcement_version: 0,
|
||||
promotion_version: 0,
|
||||
verification_shares: vec![],
|
||||
public_id: 0,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub struct UserDiscovery<Store, Utils>
|
||||
where
|
||||
Store: UserDiscoveryStore,
|
||||
Utils: UserDiscoveryUtils,
|
||||
{
|
||||
store: Store,
|
||||
utils: Utils,
|
||||
}
|
||||
|
||||
impl<Store: UserDiscoveryStore, Utils: UserDiscoveryUtils> UserDiscovery<Store, Utils> {
|
||||
pub fn new(store: Store, utils: Utils) -> Result<Self> {
|
||||
Ok(Self { store, utils })
|
||||
}
|
||||
|
||||
pub fn initialize_or_update(
|
||||
&self,
|
||||
threshold: u8,
|
||||
user_id: UserID,
|
||||
public_key: Vec<u8>,
|
||||
) -> Result<()> {
|
||||
let mut config = match self.store.get_config() {
|
||||
Ok(config) => {
|
||||
let mut config: UserDiscoveryConfig = from_bytes(&config)?;
|
||||
config.threshold = threshold;
|
||||
config
|
||||
}
|
||||
Err(_) => UserDiscoveryConfig {
|
||||
threshold,
|
||||
..Default::default()
|
||||
},
|
||||
};
|
||||
|
||||
let public_id = rand::random();
|
||||
|
||||
let signed_data = SignedData {
|
||||
public_id,
|
||||
user_id,
|
||||
public_key,
|
||||
};
|
||||
|
||||
let signature = self.utils.sign_data(signed_data.encode_to_vec())?;
|
||||
|
||||
let verification_shares = self.setup_announcements(&config, signed_data, signature)?;
|
||||
|
||||
config.public_id = public_id;
|
||||
config.announcement_version += 1;
|
||||
config.verification_shares = verification_shares;
|
||||
|
||||
self.store.update_config(to_allocvec(&config)?)?;
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn setup_announcements(
|
||||
&self,
|
||||
config: &UserDiscoveryConfig,
|
||||
signed_data: SignedData,
|
||||
signature: Vec<u8>,
|
||||
) -> Result<Vec<Vec<u8>>> {
|
||||
tracing::debug!(
|
||||
"Initializing user discovery with {} total shares and with a threshold of {}",
|
||||
config.total_number_of_shares,
|
||||
config.threshold
|
||||
);
|
||||
|
||||
let encrypted_announcement = AnnouncementShareDecrypted {
|
||||
signed_data: Some(signed_data),
|
||||
signature,
|
||||
}
|
||||
.encode_to_vec();
|
||||
|
||||
let sharks = Sharks(config.threshold as u8);
|
||||
let dealer = sharks.dealer(&encrypted_announcement);
|
||||
|
||||
let mut shares: Vec<Vec<u8>> = dealer
|
||||
.take(config.total_number_of_shares)
|
||||
.map(|x| Vec::from(&x))
|
||||
.collect();
|
||||
|
||||
if shares.len() != config.total_number_of_shares as usize
|
||||
|| shares.is_empty()
|
||||
|| shares.len() <= (config.threshold as usize * 2)
|
||||
{
|
||||
return Err(UserDiscoveryError::ShamirsSecret(
|
||||
"Invalid length of shares where generated".to_string(),
|
||||
));
|
||||
}
|
||||
|
||||
tracing::debug!(
|
||||
"Generated {} shares each with a size of: {}",
|
||||
shares.len(),
|
||||
shares[0].len()
|
||||
);
|
||||
|
||||
let mut verification_shares = vec![];
|
||||
|
||||
let split_index = shares.len() - (config.threshold - 1) as usize;
|
||||
verification_shares.extend(shares.drain(split_index..));
|
||||
|
||||
self.store.set_shares(shares)?;
|
||||
|
||||
Ok(verification_shares)
|
||||
}
|
||||
|
||||
fn get_config(&self) -> Result<UserDiscoveryConfig> {
|
||||
Ok(from_bytes(&self.store.get_config()?)?)
|
||||
}
|
||||
|
||||
/// Returns the current version of the user discovery.
|
||||
pub fn get_current_version(&self) -> Result<Vec<u8>> {
|
||||
let config = self.get_config()?;
|
||||
Ok(UserDiscoveryVersion {
|
||||
announcement: config.announcement_version,
|
||||
promotion: config.promotion_version,
|
||||
}
|
||||
.encode_to_vec())
|
||||
}
|
||||
|
||||
/// Returns all new user discovery messages for the provided contact
|
||||
pub fn get_new_messages(
|
||||
&self,
|
||||
contact_id: UserID,
|
||||
received_version: &[u8],
|
||||
) -> Result<Vec<Vec<u8>>> {
|
||||
let mut messages = vec![];
|
||||
let received_version = UserDiscoveryVersion::decode(received_version)?;
|
||||
|
||||
let config = self.get_config()?;
|
||||
let version = Some(UserDiscoveryVersion {
|
||||
announcement: config.announcement_version,
|
||||
promotion: config.promotion_version,
|
||||
});
|
||||
|
||||
if received_version.announcement < config.announcement_version {
|
||||
tracing::info!("New announcement message available for {}", contact_id);
|
||||
|
||||
let announcement_share = self.store.get_share_for_contact(contact_id)?;
|
||||
|
||||
let user_discovery_announcement = Some(UserDiscoveryAnnouncement {
|
||||
public_id: config.public_id,
|
||||
threshold: config.threshold as u32,
|
||||
announcement_share,
|
||||
verification_shares: config.verification_shares,
|
||||
});
|
||||
|
||||
messages.push(
|
||||
UserDiscoveryMessage {
|
||||
user_discovery_announcement,
|
||||
version,
|
||||
..Default::default()
|
||||
}
|
||||
.encode_to_vec(),
|
||||
);
|
||||
|
||||
// messages.push(value);
|
||||
}
|
||||
if received_version.promotion < config.promotion_version {
|
||||
tracing::info!("New promotion message available for user {}", contact_id);
|
||||
let promoting_messages = self
|
||||
.store
|
||||
.get_promotions_after_version(received_version.promotion)?;
|
||||
messages.extend_from_slice(&promoting_messages);
|
||||
}
|
||||
Ok(messages)
|
||||
}
|
||||
|
||||
/// Checks if the provided user has new announcements.
|
||||
/// In this case the user should be requested to send there updates.
|
||||
pub fn should_request_new_messages(&self, contact_id: UserID, version: &[u8]) -> Result<bool> {
|
||||
let received_version = UserDiscoveryVersion::decode(version)?;
|
||||
let stored_version = match self.store.get_contact_version(contact_id)? {
|
||||
Some(buf) => UserDiscoveryVersion::decode(buf.as_slice())?,
|
||||
None => UserDiscoveryVersion {
|
||||
announcement: 0,
|
||||
promotion: 0,
|
||||
},
|
||||
};
|
||||
Ok(received_version.announcement > stored_version.announcement
|
||||
|| received_version.promotion < received_version.promotion)
|
||||
}
|
||||
|
||||
pub(crate) fn get_contact_version(&self, contact_id: UserID) -> Result<Option<Vec<u8>>> {
|
||||
self.store.get_contact_version(contact_id)
|
||||
}
|
||||
|
||||
/// Returns the latest version for this discovery.
|
||||
/// Before calling this function the application must sure that contact_id is qualified to be announced.
|
||||
pub fn handle_user_discovery_messages(
|
||||
&self,
|
||||
contact_id: UserID,
|
||||
messages: Vec<Vec<u8>>,
|
||||
) -> Result<()> {
|
||||
for message in messages {
|
||||
let message = UserDiscoveryMessage::decode(message.as_slice())?;
|
||||
let Some(version) = message.version else {
|
||||
continue;
|
||||
};
|
||||
|
||||
if let Some(uda) = message.user_discovery_announcement {
|
||||
self.handle_user_discovery_announcement(contact_id, uda)?;
|
||||
}
|
||||
if let Some(udp) = message.user_discovery_promotion {
|
||||
self.handle
|
||||
tracing::info!("Got UDP from {contact_id}");
|
||||
}
|
||||
|
||||
self.store
|
||||
.set_contact_version(contact_id, version.encode_to_vec())?;
|
||||
}
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn handle_user_discovery_announcement(
|
||||
&self,
|
||||
contact_id: UserID,
|
||||
uda: UserDiscoveryAnnouncement,
|
||||
) -> Result<()> {
|
||||
tracing::info!("Got a user discovery announcement from {contact_id}.");
|
||||
|
||||
if uda.threshold as usize != uda.verification_shares.len() + 1 {
|
||||
tracing::error!(
|
||||
"UDA contains to few shares to verify: {} != {} + 1.",
|
||||
uda.threshold,
|
||||
uda.verification_shares.len(),
|
||||
);
|
||||
return Ok(());
|
||||
}
|
||||
|
||||
let sharks = Sharks(uda.threshold as u8);
|
||||
|
||||
let mut all_shares = uda.verification_shares.clone();
|
||||
all_shares.push(uda.announcement_share.clone());
|
||||
let shares: Vec<_> = all_shares
|
||||
.iter()
|
||||
.filter_map(|x| Share::try_from(x.as_slice()).ok())
|
||||
.collect();
|
||||
|
||||
match sharks.recover(&shares) {
|
||||
Ok(secret) => {
|
||||
let asd = AnnouncementShareDecrypted::decode(secret.as_slice())?;
|
||||
|
||||
let Some(signed_data) = asd.signed_data else {
|
||||
return Err(UserDiscoveryError::MaliciousAnnouncementData(
|
||||
"missing signed data".into(),
|
||||
));
|
||||
};
|
||||
|
||||
if contact_id != signed_data.user_id {
|
||||
return Err(UserDiscoveryError::MaliciousAnnouncementData(format!(
|
||||
"contact_id ({contact_id}) != signed_data.user_id ({})",
|
||||
signed_data.user_id
|
||||
)));
|
||||
}
|
||||
|
||||
if !self.utils.verify_pubkey_and_signature_from(
|
||||
contact_id,
|
||||
signed_data.encode_to_vec(),
|
||||
signed_data.public_key,
|
||||
asd.signature,
|
||||
)? {
|
||||
return Err(UserDiscoveryError::MaliciousAnnouncementData(format!(
|
||||
"signature invalid or public key does not match with stored one",
|
||||
)));
|
||||
}
|
||||
|
||||
let mut config = self.get_config()?;
|
||||
config.promotion_version += 1;
|
||||
self.store.update_config(to_allocvec(&config)?)?;
|
||||
|
||||
let message = UserDiscoveryMessage {
|
||||
version: Some(UserDiscoveryVersion {
|
||||
announcement: config.announcement_version,
|
||||
promotion: config.promotion_version,
|
||||
}),
|
||||
user_discovery_promotion: Some(UserDiscoveryPromotion {
|
||||
promotion_id: rand::random(),
|
||||
public_id: signed_data.public_id,
|
||||
threshold: uda.threshold,
|
||||
announcement_share: uda.announcement_share,
|
||||
verification_state: None,
|
||||
}),
|
||||
..Default::default()
|
||||
};
|
||||
|
||||
self.store
|
||||
.push_promotion(config.promotion_version, message.encode_to_vec())?;
|
||||
|
||||
Ok(())
|
||||
}
|
||||
Err(err) => {
|
||||
return Err(UserDiscoveryError::ShamirsSecret(err.to_string()));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn handle_user_discovery_promotion(
|
||||
&self,
|
||||
contact_id: UserID,
|
||||
uda: UserDiscoveryPromotion,
|
||||
) {
|
||||
|
||||
// contact_id
|
||||
// uda.promotion_id
|
||||
// uda.public_id
|
||||
// uda.threshold
|
||||
// uda.announcement_share
|
||||
// uda.verification_state
|
||||
|
||||
// store this into the received_promotion_table
|
||||
// check if the threshold is reached
|
||||
// in case thr threshold is reached -> CALL STORE -> NEW USER
|
||||
// otherwise do nothing
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
|
||||
use crate::user_discovery::stores::InMemoryStore;
|
||||
use crate::user_discovery::traits::tests::TestingUtils;
|
||||
use crate::user_discovery::{UserDiscovery, UserDiscoveryVersion, UserID};
|
||||
use prost::Message;
|
||||
|
||||
fn get_version_bytes(announcement: u32, promotion: u32) -> Vec<u8> {
|
||||
UserDiscoveryVersion {
|
||||
announcement,
|
||||
promotion,
|
||||
}
|
||||
.encode_to_vec()
|
||||
}
|
||||
|
||||
fn zero() -> Vec<u8> {
|
||||
get_version_bytes(0, 0)
|
||||
}
|
||||
|
||||
fn get_ud(user_id: UserID, friends: &[UserID]) -> UserDiscovery<InMemoryStore, TestingUtils> {
|
||||
let store = InMemoryStore::default();
|
||||
store.set_friends(friends.iter().copied().collect());
|
||||
let ud = UserDiscovery::new(store.to_owned(), TestingUtils::default()).unwrap();
|
||||
|
||||
ud.initialize_or_update(3, user_id, vec![user_id as u8; 32])
|
||||
.unwrap();
|
||||
|
||||
let version = ud.get_current_version().unwrap();
|
||||
|
||||
assert_eq!(version, get_version_bytes(1, 0));
|
||||
ud
|
||||
}
|
||||
|
||||
fn init() {
|
||||
tracing_subscriber::fmt()
|
||||
.with_max_level(tracing::Level::DEBUG)
|
||||
.init();
|
||||
}
|
||||
|
||||
fn request_and_handle_messages(
|
||||
from: (UserID, &UserDiscovery<InMemoryStore, TestingUtils>),
|
||||
to: (UserID, &UserDiscovery<InMemoryStore, TestingUtils>),
|
||||
messages_count: usize,
|
||||
) {
|
||||
// From sends a message with his current version to To
|
||||
let to_received_version = &from.1.get_current_version().unwrap();
|
||||
assert_eq!(
|
||||
to.1.should_request_new_messages(from.0, to_received_version)
|
||||
.unwrap(),
|
||||
true
|
||||
);
|
||||
|
||||
// As To has a older version stored he sends a request to From: Give me all messages since version.
|
||||
let from_request_version_from_to =
|
||||
to.1.get_contact_version(from.0).unwrap().unwrap_or(zero());
|
||||
|
||||
let new_messages = from
|
||||
.1
|
||||
.get_new_messages(to.0, &from_request_version_from_to)
|
||||
.unwrap();
|
||||
|
||||
assert_eq!(new_messages.len(), messages_count);
|
||||
|
||||
to.1.handle_user_discovery_messages(from.0, new_messages)
|
||||
.unwrap();
|
||||
|
||||
assert_eq!(
|
||||
to.1.should_request_new_messages(from.0, &from.1.get_current_version().unwrap())
|
||||
.unwrap(),
|
||||
false
|
||||
);
|
||||
}
|
||||
|
||||
#[tokio::test]
|
||||
async fn test_initialize_user_discovery() {
|
||||
init();
|
||||
|
||||
const ALICE: UserID = 0;
|
||||
const BOB: UserID = 1;
|
||||
const CHARLIE: UserID = 2;
|
||||
const DAVID: UserID = 3;
|
||||
const FRANK: UserID = 4;
|
||||
|
||||
let alice_ud = get_ud(ALICE, &[BOB, CHARLIE]);
|
||||
let bob_ud = get_ud(BOB, &[ALICE, CHARLIE, DAVID]);
|
||||
let charlie_ud = get_ud(CHARLIE, &[ALICE, BOB, DAVID, FRANK]);
|
||||
let david_ud = get_ud(DAVID, &[BOB, CHARLIE]);
|
||||
let frank_ud = get_ud(FRANK, &[CHARLIE]);
|
||||
|
||||
{
|
||||
// Alice send UDA to Bob and Charlie
|
||||
request_and_handle_messages((ALICE, &alice_ud), (BOB, &bob_ud), 1);
|
||||
request_and_handle_messages((ALICE, &alice_ud), (CHARLIE, &charlie_ud), 1);
|
||||
}
|
||||
|
||||
{
|
||||
// This now contains Bob's own announcement in addition this now also contains the promotion from Alice
|
||||
request_and_handle_messages((BOB, &bob_ud), (DAVID, &david_ud), 2);
|
||||
request_and_handle_messages((BOB, &bob_ud), (CHARLIE, &charlie_ud), 2);
|
||||
}
|
||||
|
||||
todo!();
|
||||
}
|
||||
}
|
||||
102
rust/src/user_discovery/stores/in_memory_store.rs
Normal file
102
rust/src/user_discovery/stores/in_memory_store.rs
Normal file
|
|
@ -0,0 +1,102 @@
|
|||
use crate::user_discovery::error::UserDiscoveryError;
|
||||
use crate::user_discovery::traits::UserDiscoveryStore;
|
||||
use crate::user_discovery::UserID;
|
||||
use std::collections::{HashMap, HashSet};
|
||||
use std::sync::{Arc, Mutex};
|
||||
|
||||
#[derive(Default)]
|
||||
pub(crate) struct Storage {
|
||||
config: Option<Vec<u8>>,
|
||||
unused_shares: Vec<Vec<u8>>,
|
||||
used_shares: HashMap<UserID, Vec<u8>>,
|
||||
contact_versions: HashMap<UserID, Vec<u8>>,
|
||||
friends: HashSet<UserID>,
|
||||
promotions: Vec<Vec<u8>>,
|
||||
}
|
||||
|
||||
#[derive(Default, Clone)]
|
||||
pub struct InMemoryStore {
|
||||
pub(crate) storage: Arc<Mutex<Storage>>,
|
||||
}
|
||||
|
||||
impl InMemoryStore {
|
||||
fn storage(&self) -> std::sync::MutexGuard<'_, Storage> {
|
||||
self.storage.lock().unwrap()
|
||||
}
|
||||
pub fn set_friends(&self, friends: HashSet<UserID>) {
|
||||
self.storage().friends = friends;
|
||||
}
|
||||
}
|
||||
|
||||
impl UserDiscoveryStore for InMemoryStore {
|
||||
fn get_config(&self) -> crate::user_discovery::error::Result<Vec<u8>> {
|
||||
if let Some(storage) = self.storage().config.clone() {
|
||||
return Ok(storage);
|
||||
}
|
||||
Err(UserDiscoveryError::NotInitialized)
|
||||
}
|
||||
|
||||
fn update_config(&self, update: Vec<u8>) -> crate::user_discovery::error::Result<()> {
|
||||
self.storage().config = Some(update);
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn set_shares(&self, shares: Vec<Vec<u8>>) -> crate::user_discovery::error::Result<()> {
|
||||
self.storage().unused_shares = shares;
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn get_share_for_contact(
|
||||
&self,
|
||||
contact_id: UserID,
|
||||
) -> crate::user_discovery::error::Result<Vec<u8>> {
|
||||
let mut storage = self.storage();
|
||||
if let Some(share) = storage.used_shares.get(&contact_id) {
|
||||
return Ok(share.to_vec());
|
||||
}
|
||||
if let Some(new_share) = storage.unused_shares.pop() {
|
||||
storage.used_shares.insert(contact_id, new_share.clone());
|
||||
return Ok(new_share);
|
||||
}
|
||||
Err(UserDiscoveryError::NoSharesLeft)
|
||||
}
|
||||
|
||||
fn get_contact_version(
|
||||
&self,
|
||||
contact_id: UserID,
|
||||
) -> crate::user_discovery::error::Result<Option<Vec<u8>>> {
|
||||
Ok(self.storage().contact_versions.get(&contact_id).cloned())
|
||||
}
|
||||
|
||||
fn set_contact_version(
|
||||
&self,
|
||||
contact_id: UserID,
|
||||
update: Vec<u8>,
|
||||
) -> crate::user_discovery::error::Result<()> {
|
||||
self.storage().contact_versions.insert(contact_id, update);
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn push_promotion(
|
||||
&self,
|
||||
version: u32,
|
||||
promotion: Vec<u8>,
|
||||
) -> crate::user_discovery::error::Result<()> {
|
||||
let mut storage = self.storage();
|
||||
// println!("{} != {}", version, storage.promotions.len());
|
||||
if version as usize != storage.promotions.len() + 1 {
|
||||
return Err(UserDiscoveryError::PushedInvalidVersion);
|
||||
}
|
||||
storage.promotions.push(promotion);
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn get_promotions_after_version(
|
||||
&self,
|
||||
version: u32,
|
||||
) -> crate::user_discovery::error::Result<Vec<Vec<u8>>> {
|
||||
let storage = self.storage();
|
||||
let elements = storage.promotions[(version as usize)..].to_vec();
|
||||
Ok(elements)
|
||||
}
|
||||
}
|
||||
2
rust/src/user_discovery/stores/mod.rs
Normal file
2
rust/src/user_discovery/stores/mod.rs
Normal file
|
|
@ -0,0 +1,2 @@
|
|||
mod in_memory_store;
|
||||
pub use in_memory_store::InMemoryStore;
|
||||
50
rust/src/user_discovery/traits.rs
Normal file
50
rust/src/user_discovery/traits.rs
Normal file
|
|
@ -0,0 +1,50 @@
|
|||
use crate::user_discovery::error::Result;
|
||||
use crate::user_discovery::UserID;
|
||||
|
||||
pub trait UserDiscoveryStore {
|
||||
fn get_config(&self) -> Result<Vec<u8>>;
|
||||
fn update_config(&self, update: Vec<u8>) -> Result<()>;
|
||||
fn set_shares(&self, shares: Vec<Vec<u8>>) -> Result<()>;
|
||||
|
||||
fn get_share_for_contact(&self, contact_id: UserID) -> Result<Vec<u8>>;
|
||||
|
||||
fn push_promotion(&self, version: u32, promotion: Vec<u8>) -> Result<()>;
|
||||
fn get_promotions_after_version(&self, version: u32) -> Result<Vec<Vec<u8>>>;
|
||||
|
||||
fn get_contact_version(&self, contact_id: UserID) -> Result<Option<Vec<u8>>>;
|
||||
fn set_contact_version(&self, contact_id: UserID, update: Vec<u8>) -> Result<()>;
|
||||
}
|
||||
|
||||
pub trait UserDiscoveryUtils {
|
||||
fn sign_data(&self, input_data: Vec<u8>) -> Result<Vec<u8>>;
|
||||
fn verify_pubkey_and_signature_from(
|
||||
&self,
|
||||
from_contact_id: UserID,
|
||||
data: Vec<u8>,
|
||||
pubkey: Vec<u8>,
|
||||
signature: Vec<u8>,
|
||||
) -> Result<bool>;
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
pub(crate) mod tests {
|
||||
use crate::user_discovery::traits::UserDiscoveryUtils;
|
||||
|
||||
#[derive(Default)]
|
||||
pub(crate) struct TestingUtils {}
|
||||
impl UserDiscoveryUtils for TestingUtils {
|
||||
fn sign_data(&self, _input_data: Vec<u8>) -> crate::user_discovery::error::Result<Vec<u8>> {
|
||||
Ok(vec![0; 64])
|
||||
}
|
||||
|
||||
fn verify_pubkey_and_signature_from(
|
||||
&self,
|
||||
from_contact_id: crate::user_discovery::UserID,
|
||||
data: Vec<u8>,
|
||||
pubkey: Vec<u8>,
|
||||
signature: Vec<u8>,
|
||||
) -> crate::user_discovery::error::Result<bool> {
|
||||
Ok(true)
|
||||
}
|
||||
}
|
||||
}
|
||||
52
rust/src/user_discovery/types.proto
Normal file
52
rust/src/user_discovery/types.proto
Normal file
|
|
@ -0,0 +1,52 @@
|
|||
syntax = "proto3";
|
||||
|
||||
message UserDiscoveryVersion {
|
||||
uint32 announcement = 1;
|
||||
uint32 promotion = 2;
|
||||
}
|
||||
|
||||
message UserDiscoveryMessage {
|
||||
|
||||
UserDiscoveryVersion version = 1;
|
||||
|
||||
optional UserDiscoveryAnnouncement user_discovery_announcement = 2;
|
||||
optional UserDiscoveryPromotion user_discovery_promotion = 3;
|
||||
optional UserDiscoveryRecall user_discovery_recall = 4;
|
||||
|
||||
message UserDiscoveryAnnouncement {
|
||||
uint64 public_id = 1;
|
||||
uint32 threshold = 2;
|
||||
bytes announcement_share = 4;
|
||||
repeated bytes verification_shares = 5;
|
||||
}
|
||||
|
||||
message UserDiscoveryPromotion {
|
||||
uint32 promotion_id = 1;
|
||||
uint64 public_id = 2;
|
||||
uint32 threshold = 3;
|
||||
bytes announcement_share = 5;
|
||||
|
||||
optional VerificationState verification_state = 6;
|
||||
|
||||
message AnnouncementShareDecrypted {
|
||||
message SignedData {
|
||||
uint64 public_id = 1;
|
||||
int64 user_id = 2;
|
||||
bytes public_key = 3;
|
||||
}
|
||||
SignedData signed_data = 1;
|
||||
bytes signature = 2;
|
||||
}
|
||||
|
||||
message VerificationState {
|
||||
int64 timestamp = 1;
|
||||
bytes signature = 2;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
message UserDiscoveryRecall {
|
||||
int64 promotion_id = 1;
|
||||
}
|
||||
|
||||
}
|
||||
BIN
rust/tests/testing.db
Normal file
BIN
rust/tests/testing.db
Normal file
Binary file not shown.
56
test/rust/create_db_for_rust_testing.dart
Normal file
56
test/rust/create_db_for_rust_testing.dart
Normal file
|
|
@ -0,0 +1,56 @@
|
|||
import 'dart:io';
|
||||
import 'package:drift/drift.dart' show Value;
|
||||
import 'package:drift/native.dart';
|
||||
import 'package:flutter/foundation.dart';
|
||||
import 'package:flutter_test/flutter_test.dart';
|
||||
import 'package:twonly/src/database/twonly.db.dart';
|
||||
|
||||
void main() {
|
||||
if (!Platform.isMacOS) return;
|
||||
late TwonlyDB database;
|
||||
late File dbFile;
|
||||
|
||||
setUp(() {
|
||||
dbFile = File('rust/tests/testing.db');
|
||||
if (dbFile.existsSync()) {
|
||||
dbFile.deleteSync();
|
||||
}
|
||||
database = TwonlyDB(NativeDatabase(dbFile));
|
||||
});
|
||||
|
||||
tearDown(() async {
|
||||
await database.close();
|
||||
});
|
||||
|
||||
test('Database successfully writes to the physical file system', () async {
|
||||
final users = [
|
||||
'alice',
|
||||
'bob',
|
||||
'charlie',
|
||||
'david',
|
||||
'frank',
|
||||
];
|
||||
|
||||
for (var i = 0; i < users.length; i++) {
|
||||
await database.contactsDao.insertContact(
|
||||
ContactsCompanion(userId: Value(i), username: Value(users[i])),
|
||||
);
|
||||
}
|
||||
|
||||
expect(
|
||||
dbFile.existsSync(),
|
||||
isTrue,
|
||||
reason: 'The SQLite file was not created on disk.',
|
||||
);
|
||||
|
||||
expect(
|
||||
dbFile.lengthSync(),
|
||||
greaterThan(0),
|
||||
reason: 'The SQLite file is completely empty.',
|
||||
);
|
||||
|
||||
if (kDebugMode) {
|
||||
print('Test passed! Database written to: ${dbFile.absolute.path}');
|
||||
}
|
||||
});
|
||||
}
|
||||
Loading…
Reference in a new issue