diff --git a/Cargo.lock b/Cargo.lock index d612092..dfa84c5 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -9,7 +9,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "de7fa236829ba0841304542f7614c42b80fca007455315c45c785ccfa873a85b" dependencies = [ "actix-rt", - "bitflags 2.11.1", + "bitflags 2.12.1", "bytes", "crossbeam-channel", "futures-core", @@ -31,7 +31,7 @@ version = "0.5.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "5f7b0a21988c1bf877cf4759ef5ddaac04c1c9fe808c9142ecb78ba97d97a28a" dependencies = [ - "bitflags 2.11.1", + "bitflags 2.12.1", "bytes", "futures-core", "futures-sink", @@ -54,7 +54,7 @@ dependencies = [ "actix-tls", "actix-utils", "base64", - "bitflags 2.11.1", + "bitflags 2.12.1", "brotli", "bytes", "bytestring", @@ -211,7 +211,7 @@ dependencies = [ "serde_json", "serde_urlencoded", "smallvec", - "socket2 0.6.3", + "socket2 0.6.4", "time", "tracing", "url", @@ -474,9 +474,9 @@ checksum = "bef38d45163c2f1dde094a7dfd33ccf595c92905c8f8f4fdc18d06fb1037718a" [[package]] name = "bitflags" -version = "2.11.1" +version = "2.12.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c4512299f36f043ab09a583e57bceb5a5aab7a73db1805848e8fef3c9e8c78b3" +checksum = "84d7ced0ae9557296835c32bf1b1e02b44c746701f898460fb000d7eaa84f00a" [[package]] name = "block-buffer" @@ -498,9 +498,9 @@ dependencies = [ [[package]] name = "brotli" -version = "8.0.2" +version = "8.0.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4bd8b9603c7aa97359dbd97ecf258968c95f3adddd6db2f7e7a5bef101c84560" +checksum = "8119e4516436f5708bbc474a9d395bf12f1b5395e93a92a56e647ac3388c8610" dependencies = [ "alloc-no-stdlib", "alloc-stdlib", @@ -509,9 +509,9 @@ dependencies = [ [[package]] name = "brotli-decompressor" -version = "5.0.0" +version = "5.0.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "874bb8112abecc98cbd6d81ea4fa7e94fb9449648c93cc89aa40c81c24d7de03" +checksum = "5962523e1b92ce1b5e793d9169b9943eece10d39f62550bc04bb605d75b94924" dependencies = [ "alloc-no-stdlib", "alloc-stdlib", @@ -570,9 +570,9 @@ dependencies = [ [[package]] name = "cc" -version = "1.2.62" +version = "1.2.63" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a1dce859f0832a7d088c4f1119888ab94ef4b5d6795d1ce05afb7fe159d79f98" +checksum = "556e016178bb5662a08681bbe0f00f8e17631781a4dfc8c45e466e4b185ec27f" dependencies = [ "find-msvc-tools", "jobserver", @@ -699,9 +699,9 @@ dependencies = [ [[package]] name = "compact_str" -version = "0.9.0" +version = "0.9.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3fdb1325a1cece981e8a296ab8f0f9b63ae357bd0784a9faaf548cc7b480707a" +checksum = "9dfdd1c2274d9aa354115b09dc9a901d6c5576818cdf70d14cae2bdb47df00ab" dependencies = [ "castaway", "cfg-if", @@ -832,7 +832,7 @@ version = "0.29.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d8b9f2e4c67f833b660cdb0a3523065869fb35570177239812ed4c905aeff87b" dependencies = [ - "bitflags 2.11.1", + "bitflags 2.12.1", "crossterm_winapi", "derive_more", "document-features", @@ -1039,9 +1039,9 @@ dependencies = [ [[package]] name = "displaydoc" -version = "0.2.5" +version = "0.2.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "97369cbbc041bc366949bc74d34658d6cda5621039731c6310521892a3a20ae0" +checksum = "1ac70aa55017e108007fbaf5aa0f54b021c98f92ff8af59d42eda9da96e3dd4f" dependencies = [ "proc-macro2", "quote", @@ -1421,7 +1421,7 @@ dependencies = [ "fnv", "futures-core", "futures-sink", - "http 1.4.0", + "http 1.4.1", "indexmap", "slab", "tokio", @@ -1479,7 +1479,7 @@ dependencies = [ "base64", "bytes", "headers-core", - "http 1.4.0", + "http 1.4.1", "httpdate", "mime", "sha1 0.10.6", @@ -1491,7 +1491,7 @@ version = "0.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "54b4a22553d4242c49fddb9ba998a99962b5cc6f22cb5a3482bec22522403ce4" dependencies = [ - "http 1.4.0", + "http 1.4.1", ] [[package]] @@ -1543,9 +1543,9 @@ dependencies = [ [[package]] name = "http" -version = "1.4.0" +version = "1.4.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e3ba2a386d7f85a81f119ad7498ebe444d2e22c2af0b86b069416ace48b3311a" +checksum = "8be7462df143984c4598a256ef469b251d7d7f9e271135073e78fc535414f3d0" dependencies = [ "bytes", "itoa", @@ -1558,7 +1558,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "1efedce1fb8e6913f23e0c92de8e62cd5b772a67e7b3946df930a62566c93184" dependencies = [ "bytes", - "http 1.4.0", + "http 1.4.1", ] [[package]] @@ -1569,7 +1569,7 @@ checksum = "b021d93e26becf5dc7e1b75b1bed1fd93124b374ceb73f43d4d4eafec896a64a" dependencies = [ "bytes", "futures-core", - "http 1.4.0", + "http 1.4.1", "http-body", "pin-project-lite", ] @@ -1597,16 +1597,16 @@ dependencies = [ [[package]] name = "hyper" -version = "1.9.0" +version = "1.10.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6299f016b246a94207e63da54dbe807655bf9e00044f73ded42c3ac5305fbcca" +checksum = "55281c53a1894c864990125767da440a4e630446785086f52523b20033b74498" dependencies = [ "atomic-waker", "bytes", "futures-channel", "futures-core", "h2 0.4.14", - "http 1.4.0", + "http 1.4.1", "http-body", "httparse", "httpdate", @@ -1623,7 +1623,7 @@ version = "0.27.9" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "33ca68d021ef39cf6463ab54c1d0f5daf03377b70561305bb89a8f83aab66e0f" dependencies = [ - "http 1.4.0", + "http 1.4.1", "hyper", "hyper-util", "rustls", @@ -1642,14 +1642,14 @@ dependencies = [ "bytes", "futures-channel", "futures-util", - "http 1.4.0", + "http 1.4.1", "http-body", "hyper", "ipnet", "libc", "percent-encoding", "pin-project-lite", - "socket2 0.6.3", + "socket2 0.6.4", "system-configuration", "tokio", "tower-service", @@ -2276,7 +2276,7 @@ version = "0.3.7" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "3f50e8f47623268b5407192d26876c4d7f89d686ca130fdc53bced4814cd29f8" dependencies = [ - "bitflags 2.11.1", + "bitflags 2.12.1", ] [[package]] @@ -2325,9 +2325,9 @@ dependencies = [ [[package]] name = "log" -version = "0.4.29" +version = "0.4.31" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5e5032e24019045c762d3c0f28f5b6b8bbf38563a65908389bf7978758920897" +checksum = "113b30b4cd05f7c06868fdb2854f66a7b9fece9a48425351cd532e810d74024f" [[package]] name = "lru" @@ -2366,9 +2366,9 @@ dependencies = [ [[package]] name = "memchr" -version = "2.8.0" +version = "2.8.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f8ca58f447f06ed17d5fc4043ce1b10dd205e060fb3ce5b979b8ed8e59ff3f79" +checksum = "6b947ae49db0d222b1dbc6b113ce7248a3fc3a6ca21b696717bfc000ba4484d8" [[package]] name = "memmem" @@ -2419,9 +2419,9 @@ dependencies = [ [[package]] name = "mio" -version = "1.2.0" +version = "1.2.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "50b7e5b27aa02a74bac8c3f23f448f8d87ff11f92d3aac1a6ed369ee08cc56c1" +checksum = "02bd0af71c67b473010cbbc60715ee815645a4dc942899111f494b4b737d6fda" dependencies = [ "libc", "log", @@ -2452,7 +2452,7 @@ version = "0.29.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "71e2746dc3a24dd78b3cfcb7be93368c6de9963d30f43a6a73998a9cf4b17b46" dependencies = [ - "bitflags 2.11.1", + "bitflags 2.12.1", "cfg-if", "cfg_aliases", "libc", @@ -2544,7 +2544,7 @@ version = "0.3.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "2a180dd8642fa45cdb7dd721cd4c11b1cadd4929ce112ebd8b9f5803cc79d536" dependencies = [ - "bitflags 2.11.1", + "bitflags 2.12.1", ] [[package]] @@ -2622,7 +2622,7 @@ version = "0.10.80" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "a45fa2aa886c42762255da344f0a0d313e254066c46aad76f300c3d3da62d967" dependencies = [ - "bitflags 2.11.1", + "bitflags 2.12.1", "cfg-if", "foreign-types", "libc", @@ -3073,7 +3073,7 @@ dependencies = [ "quinn-udp", "rustc-hash", "rustls", - "socket2 0.6.3", + "socket2 0.6.4", "thiserror 2.0.18", "tokio", "tracing", @@ -3111,7 +3111,7 @@ dependencies = [ "cfg_aliases", "libc", "once_cell", - "socket2 0.6.3", + "socket2 0.6.4", "tracing", "windows-sys 0.60.2", ] @@ -3239,7 +3239,7 @@ version = "0.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "5ef8dea09a92caaf73bff7adb70b76162e5937524058a7e5bff37869cbbec293" dependencies = [ - "bitflags 2.11.1", + "bitflags 2.12.1", "compact_str", "hashbrown 0.16.1", "indoc", @@ -3291,7 +3291,7 @@ version = "0.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d7dbfa023cd4e604c2553483820c5fe8aa9d71a42eea5aa77c6e7f35756612db" dependencies = [ - "bitflags 2.11.1", + "bitflags 2.12.1", "hashbrown 0.16.1", "indoc", "instability", @@ -3323,7 +3323,7 @@ version = "0.5.18" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ed2bf2547551a7053d6fdfafda3f938979645c44812fbfcda098faae3f1a362d" dependencies = [ - "bitflags 2.11.1", + "bitflags 2.12.1", ] [[package]] @@ -3363,16 +3363,16 @@ checksum = "dc897dd8d9e8bd1ed8cdad82b5966c3e0ecae09fb1907d58efaa013543185d0a" [[package]] name = "reqwest" -version = "0.13.3" +version = "0.13.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "62e0021ea2c22aed41653bc7e1419abb2c97e038ff2c33d0e1309e49a97deec0" +checksum = "219c5811de6525e5416c7d5d53bb656d3afdbc6c5af816e0802bcfa42dbdc1c3" dependencies = [ "base64", "bytes", "encoding_rs", "futures-core", "h2 0.4.14", - "http 1.4.0", + "http 1.4.1", "http-body", "http-body-util", "hyper", @@ -3429,7 +3429,7 @@ version = "0.39.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "a0d2b0146dd9661bf67bb107c0bb2a55064d556eeb3fc314151b957f313bcd4e" dependencies = [ - "bitflags 2.11.1", + "bitflags 2.12.1", "fallible-iterator", "fallible-streaming-iterator", "hashlink", @@ -3468,7 +3468,7 @@ version = "1.1.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b6fe4565b9518b83ef4f91bb47ce29620ca828bd32cb7e408f0062e9930ba190" dependencies = [ - "bitflags 2.11.1", + "bitflags 2.12.1", "errno", "libc", "linux-raw-sys", @@ -3493,9 +3493,9 @@ dependencies = [ [[package]] name = "rustls-native-certs" -version = "0.8.3" +version = "0.8.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "612460d5f7bea540c490b2b6395d8e34a953e52b491accd6c86c8164c5932a63" +checksum = "dab5152771c58876a2146916e53e35057e1a4dfa2b9df0f0305b07f611fdea4d" dependencies = [ "openssl-probe", "rustls-pki-types", @@ -3609,7 +3609,7 @@ version = "3.7.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b7f4bc775c73d9a02cde8bf7b2ec4c9d12743edf609006c7facc23998404cd1d" dependencies = [ - "bitflags 2.11.1", + "bitflags 2.12.1", "core-foundation 0.10.1", "core-foundation-sys", "libc", @@ -3744,9 +3744,9 @@ dependencies = [ [[package]] name = "shlex" -version = "1.3.0" +version = "2.0.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0fda2ff0d084019ba4d7c6f371c95d8fd75ce3524c3cb8fb653a3023f6323e64" +checksum = "f8fadd59c855ef2080decdef8ff161eb6661b86933c9d82e5ba29dc602a55aba" [[package]] name = "signal-hook" @@ -3831,9 +3831,9 @@ dependencies = [ [[package]] name = "socket2" -version = "0.6.3" +version = "0.6.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3a766e1110788c36f4fa1c2b71b387a7815aa65f88ce0229841826633d93723e" +checksum = "52d1cfed4120b4d927bf7c0f86d2087a4a7d6027c906d9f9d525a80573b9be51" dependencies = [ "libc", "windows-sys 0.61.2", @@ -3841,9 +3841,9 @@ dependencies = [ [[package]] name = "sqlite-wasm-rs" -version = "0.5.4" +version = "0.5.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cdd578e94101503d97e2b286bbf8db2135035ca24b2ce4cbf3f9e2fb2bbf1eee" +checksum = "dc3efc0da82635d7e1ced0053bbbfa8c7ab9645d0bf36ceb4f7127bb85315d75" dependencies = [ "cc", "js-sys", @@ -3976,7 +3976,7 @@ version = "0.7.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "a13f3d0daba03132c0aa9767f98351b3488edc2c100cda2d2ec2b04f3d8d3c8b" dependencies = [ - "bitflags 2.11.1", + "bitflags 2.12.1", "core-foundation 0.9.4", "system-configuration-sys", ] @@ -4033,7 +4033,7 @@ checksum = "4676b37242ccbd1aabf56edb093a4827dc49086c0ffd764a5705899e0f35f8f7" dependencies = [ "anyhow", "base64", - "bitflags 2.11.1", + "bitflags 2.12.1", "fancy-regex", "filedescriptor", "finl_unicode", @@ -4177,7 +4177,7 @@ dependencies = [ "parking_lot", "pin-project-lite", "signal-hook-registry", - "socket2 0.6.3", + "socket2 0.6.4", "tokio-macros", "windows-sys 0.61.2", ] @@ -4261,10 +4261,10 @@ version = "0.6.11" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "4cfcf7e2740e6fc6d4d688b4ef00650406bb94adf4731e43c096c3a19fe40840" dependencies = [ - "bitflags 2.11.1", + "bitflags 2.12.1", "bytes", "futures-util", - "http 1.4.0", + "http 1.4.1", "http-body", "pin-project-lite", "tower", @@ -4326,7 +4326,7 @@ checksum = "e421abadd41a4225275504ea4d6566923418b7f05506fbc9c0fe86ba7396114b" [[package]] name = "ttp-core" version = "0.1.0" -source = "git+https://git.methanium.net/Tensamin/TTP.git#886edbf51d26636e46745c3637b80610df82f5dc" +source = "git+https://git.methanium.net/Tensamin/TTP.git#23438fa8f884e6ad0d32ca1004c0dedcce0cc8d2" dependencies = [ "base64", "byteorder", @@ -4339,7 +4339,7 @@ dependencies = [ [[package]] name = "ttp-native" version = "0.1.0" -source = "git+https://git.methanium.net/Tensamin/TTP.git#886edbf51d26636e46745c3637b80610df82f5dc" +source = "git+https://git.methanium.net/Tensamin/TTP.git#23438fa8f884e6ad0d32ca1004c0dedcce0cc8d2" dependencies = [ "quinn", "rustls", @@ -4358,7 +4358,7 @@ checksum = "6c01152af293afb9c7c2a57e4b559c5620b421f6d133261c60dd2d0cdb38e6b8" dependencies = [ "bytes", "data-encoding", - "http 1.4.0", + "http 1.4.1", "httparse", "log", "native-tls", @@ -4369,9 +4369,9 @@ dependencies = [ [[package]] name = "typenum" -version = "1.20.0" +version = "1.20.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "40ce102ab67701b8526c123c1bab5cbe42d7040ccfd0f64af1a385808d2f43de" +checksum = "b6f5e870be6c3b371b77fe0ee0bafb859fa4964b4404c27de1d380043c4dda20" [[package]] name = "ucd-trie" @@ -4393,9 +4393,9 @@ checksum = "e6e4313cd5fcd3dad5cafa179702e2b244f760991f45397d14d4ebf38247da75" [[package]] name = "unicode-segmentation" -version = "1.13.2" +version = "1.13.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9629274872b2bfaf8d66f5f15725007f635594914870f65218920345aa11aa8c" +checksum = "c6f5d3c3b1bf09027a88a6bc961fc00497d651009560b5463668dc81b0fa87a8" [[package]] name = "unicode-truncate" @@ -4468,9 +4468,9 @@ checksum = "06abde3611657adf66d383f00b093d7faecc7fa57071cce2578660c9f1010821" [[package]] name = "uuid" -version = "1.23.1" +version = "1.23.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ddd74a9687298c6858e9b88ec8935ec45d22e8fd5e6394fa1bd4e99a87789c76" +checksum = "d258b83ceec21034727ecee8c382cfa6c3e133699b0742c64571814fb420c9f7" dependencies = [ "atomic", "getrandom 0.4.2", @@ -4527,7 +4527,7 @@ dependencies = [ "bytes", "futures-util", "headers", - "http 1.4.0", + "http 1.4.1", "http-body", "http-body-util", "log", @@ -4652,7 +4652,7 @@ version = "0.244.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "47b807c72e1bac69382b3a6fb3dbe8ea4c0ed87ff5629b8685ae6b9a611028fe" dependencies = [ - "bitflags 2.11.1", + "bitflags 2.12.1", "hashbrown 0.15.5", "indexmap", "semver", @@ -5191,7 +5191,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9d66ea20e9553b30172b5e831994e35fbde2d165325bec84fc43dbf6f4eb9cb2" dependencies = [ "anyhow", - "bitflags 2.11.1", + "bitflags 2.12.1", "indexmap", "log", "serde", @@ -5241,7 +5241,7 @@ dependencies = [ "rustls-native-certs", "rustls-pki-types", "sha2 0.11.0", - "socket2 0.6.3", + "socket2 0.6.4", "thiserror 2.0.18", "time", "tokio", @@ -5327,18 +5327,18 @@ dependencies = [ [[package]] name = "zerocopy" -version = "0.8.48" +version = "0.8.50" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "eed437bf9d6692032087e337407a86f04cd8d6a16a37199ed57949d415bd68e9" +checksum = "3b065d4f0e55f82fae73202e189638116a87c55ab6b8e6c2721e13dd9d854ad1" dependencies = [ "zerocopy-derive", ] [[package]] name = "zerocopy-derive" -version = "0.8.48" +version = "0.8.50" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "70e3cd084b1788766f53af483dd21f93881ff30d7320490ec3ef7526d203bad4" +checksum = "0b631b19d36a892ab55420c92dbc83ccd79274f25be714855d3074aa71cab639" dependencies = [ "proc-macro2", "quote", diff --git a/omikron-connector/src/omikron_connection.rs b/omikron-connector/src/omikron_connection.rs index e0c6b9c..6e18561 100755 --- a/omikron-connector/src/omikron_connection.rs +++ b/omikron-connector/src/omikron_connection.rs @@ -2,14 +2,13 @@ use dashmap::DashMap; use iota_logger::{log, log_cv_in, log_cv_out, log_t}; use iota_state::{ACTIVE_TASKS, SHUTDOWN}; use iota_storage::users::contact::Contact; -use iota_storage::util::chat_files::{MessageState, change_message_state}; -use iota_storage::util::chats_util::{get_user, mod_user}; +use iota_storage::util::chat_files::{self, MessageState, change_message_state}; +use iota_storage::util::chats_util::{self, get_user, mod_user}; use iota_storage::util::communities_util::CommunitiesUtil; use iota_storage::util::config_util::CONFIG; -use iota_storage::util::{chat_files, chats_util}; use iota_util::crypto_helper; use iota_util::crypto_util::{DataFormat, SecurePayload}; -use iota_util::file_util::{get_children, load_file, save_file}; +use iota_util::file_util::{get_children, has_file, load_file, save_file}; use json::JsonValue; use std::collections::HashMap; use std::sync::{Arc, LazyLock}; @@ -21,6 +20,18 @@ use ttp_core::{CommunicationType, CommunicationValue, DataTypes, DataValue}; use ttp_native::{Policy, Receiver, SendMode, Sender}; use uuid::Uuid; +// Helper function to check if read receipts are enabled globally +async fn is_read_receipts_enabled() -> bool { + // Check global config for read receipts setting + // Default to true if not set + let conf = CONFIG.read().await; + let value = conf.get("read_receipts_enabled"); + match value { + JsonValue::Boolean(b) => *b, + _ => true, + } +} + // ============================================================================ // Configuration // ============================================================================ @@ -933,7 +944,7 @@ impl OmikronConnection { // Attempt delivery and await a response from the local client let user_resp = self .clone() - .await_response(&user_forward, Some(Duration::from_secs(10))) + .await_response(&user_forward, Some(Duration::from_secs(3))) .await; if let Ok(user_resp) = user_resp { @@ -959,23 +970,25 @@ impl OmikronConnection { ms.clone(), ); - // notify original sender about the delivered/read state - self.send_message( - &CommunicationValue::new(CommunicationType::message_state) - .with_id(cv.get_id()) - .with_receiver(sender_id as u64) - .with_sender(receiver_id as u64) - .add_data( - DataTypes::chat_partner_id, - DataValue::Number(receiver_id as i64), - ) - .add_data(DataTypes::send_time, DataValue::Number(timestamp_i64)) - .add_data( - DataTypes::message_state, - DataValue::Str(ms.as_str().to_string()), - ), - ) - .await; + // notify original sender about the delivered/read state (if read receipts are enabled) + if is_read_receipts_enabled().await { + self.send_message( + &CommunicationValue::new(CommunicationType::message_state) + .with_id(cv.get_id()) + .with_receiver(sender_id as u64) + .with_sender(receiver_id as u64) + .add_data( + DataTypes::chat_partner_id, + DataValue::Number(receiver_id as i64), + ) + .add_data(DataTypes::send_time, DataValue::Number(timestamp_i64)) + .add_data( + DataTypes::message_state, + DataValue::Str(ms.as_str().to_string()), + ), + ) + .await; + } } else { // Delivery failed or timed out; mark as Sent let _ = chat_files::change_message_state( @@ -1072,7 +1085,7 @@ impl OmikronConnection { let user_resp = self .clone() - .await_response(&user_forward, Some(Duration::from_secs(10))) + .await_response(&user_forward, Some(Duration::from_secs(3))) .await; if let Ok(user_resp) = user_resp { @@ -1089,22 +1102,25 @@ impl OmikronConnection { ms.clone(), ); - self.send_message( - &CommunicationValue::new(CommunicationType::message_state) - .with_id(cv.get_id()) - .with_receiver(*sender_id) - .with_sender(*receiver_id) - .add_data(DataTypes::send_time, DataValue::Number(timestamp)) - .add_data( - DataTypes::chat_partner_id, - DataValue::Number(*sender_id as i64), - ) - .add_data( - DataTypes::message_state, - DataValue::Str(ms.as_str().to_string()), - ), - ) - .await; + // notify original sender about the delivered/read state (if read receipts are enabled) + if is_read_receipts_enabled().await { + self.send_message( + &CommunicationValue::new(CommunicationType::message_state) + .with_id(cv.get_id()) + .with_receiver(*sender_id) + .with_sender(*receiver_id) + .add_data(DataTypes::send_time, DataValue::Number(timestamp)) + .add_data( + DataTypes::chat_partner_id, + DataValue::Number(*sender_id as i64), + ) + .add_data( + DataTypes::message_state, + DataValue::Str(ms.as_str().to_string()), + ), + ) + .await; + } } else { // Delivery timed out/failed — update stored state and notify sender with numeric timestamp let _ = chat_files::change_message_state( @@ -1306,20 +1322,145 @@ impl OmikronConnection { return; } - if cv.is_type(CommunicationType::settings_save) { + if cv.is_type(CommunicationType::global_settings_save) { let my_id = cv.get_sender(); - let settings_name = cv.get_data(DataTypes::settings_name).as_str().unwrap(); - let settings_value = cv.get_data(DataTypes::payload).as_str().unwrap(); + let Some(settings_value) = cv.get_data(DataTypes::payload).as_str() else { + let response = CommunicationValue::new(CommunicationType::error_invalid_data) + .with_id(cv.get_id()) + .with_receiver(my_id) + .add_data( + DataTypes::message, + DataValue::Str("Missing settings payload".to_string()), + ); + self.send_message(&response).await; + return; + }; save_file( - &format!("users/{}/settings/", my_id), + &format!("users/{}", my_id), + "global.settings", + settings_value, + ); + + let mut response = CommunicationValue::new(CommunicationType::global_settings_save) + .with_receiver(my_id) + .with_id(cv.get_id()); + + if let Some(session_id) = cv.get_data(DataTypes::session_id).as_number() { + response = response.add_data(DataTypes::session_id, DataValue::Number(session_id)); + } + + self.send_message(&response).await; + return; + } + + if cv.is_type(CommunicationType::global_settings_load) { + let my_id = cv.get_sender(); + let path = format!("users/{}", my_id); + let name = "global.settings"; + + if !has_file(&path, name) { + let mut response = CommunicationValue::new(CommunicationType::error_not_found) + .with_id(cv.get_id()) + .with_receiver(my_id) + .add_data(DataTypes::path, DataValue::Str(name.to_string())); + + if let Some(session_id) = cv.get_data(DataTypes::session_id).as_number() { + response = + response.add_data(DataTypes::session_id, DataValue::Number(session_id)); + } + + self.send_message(&response).await; + return; + } + + let settings_value_str = load_file(&path, name); + let mut response = CommunicationValue::new(CommunicationType::global_settings_load) + .with_id(cv.get_id()) + .with_receiver(my_id) + .add_data(DataTypes::payload, DataValue::Str(settings_value_str)); + + if let Some(session_id) = cv.get_data(DataTypes::session_id).as_number() { + response = response.add_data(DataTypes::session_id, DataValue::Number(session_id)); + } + + self.send_message(&response).await; + return; + } + + if cv.is_type(CommunicationType::settings_save) { + let my_id = cv.get_sender(); + let Some(session_id) = cv.get_data(DataTypes::session_id).as_number() else { + let response = CommunicationValue::new(CommunicationType::error_invalid_data) + .with_id(cv.get_id()) + .with_receiver(my_id) + .add_data( + DataTypes::message, + DataValue::Str("Missing session_id".to_string()), + ); + self.send_message(&response).await; + return; + }; + let Some(settings_name) = cv.get_data(DataTypes::settings_name).as_str() else { + let response = CommunicationValue::new(CommunicationType::error_invalid_data) + .with_id(cv.get_id()) + .with_receiver(my_id) + .add_data( + DataTypes::message, + DataValue::Str("Missing settings_name".to_string()), + ) + .add_data(DataTypes::session_id, DataValue::Number(session_id)); + self.send_message(&response).await; + return; + }; + let Some(settings_value) = cv.get_data(DataTypes::payload).as_str() else { + let response = CommunicationValue::new(CommunicationType::error_invalid_data) + .with_id(cv.get_id()) + .with_receiver(my_id) + .add_data( + DataTypes::message, + DataValue::Str("Missing settings payload".to_string()), + ) + .add_data(DataTypes::session_id, DataValue::Number(session_id)); + self.send_message(&response).await; + return; + }; + + if !settings_name + .chars() + .all(|c| c.is_alphanumeric() || c == '_' || c == '-' || c == '.') + || settings_name.contains("..") + { + let response = CommunicationValue::new(CommunicationType::error_invalid_data) + .with_id(cv.get_id()) + .with_receiver(my_id) + .add_data( + DataTypes::message, + DataValue::Str("Invalid settings_name".to_string()), + ) + .add_data( + DataTypes::settings_name, + DataValue::Str(settings_name.to_string()), + ) + .add_data(DataTypes::session_id, DataValue::Number(session_id)); + self.send_message(&response).await; + return; + } + + save_file( + &format!("users/{}/settings/{}/", my_id, session_id), &format!("{}.settings", settings_name), - &settings_value, + settings_value, ); let response = CommunicationValue::new(CommunicationType::settings_save) .with_receiver(my_id) - .with_id(cv.get_id()); + .with_id(cv.get_id()) + .add_data( + DataTypes::settings_name, + DataValue::Str(settings_name.to_string()), + ) + .add_data(DataTypes::session_id, DataValue::Number(session_id)); self.send_message(&response).await; return; @@ -1327,16 +1468,76 @@ impl OmikronConnection { if cv.is_type(CommunicationType::settings_load) { let my_id = cv.get_sender(); - let settings_name = cv.get_data(DataTypes::settings_name).as_string().unwrap(); - let settings_value_str = load_file( - &format!("users/{}/settings/", my_id), - &format!("{}.settings", settings_name), - ); + let Some(session_id) = cv.get_data(DataTypes::session_id).as_number() else { + let response = CommunicationValue::new(CommunicationType::error_invalid_data) + .with_id(cv.get_id()) + .with_receiver(my_id) + .add_data( + DataTypes::message, + DataValue::Str("Missing session_id".to_string()), + ); + self.send_message(&response).await; + return; + }; + let Some(settings_name) = cv.get_data(DataTypes::settings_name).as_str() else { + let response = CommunicationValue::new(CommunicationType::error_invalid_data) + .with_id(cv.get_id()) + .with_receiver(my_id) + .add_data( + DataTypes::message, + DataValue::Str("Missing settings_name".to_string()), + ) + .add_data(DataTypes::session_id, DataValue::Number(session_id)); + self.send_message(&response).await; + return; + }; + + if !settings_name + .chars() + .all(|c| c.is_alphanumeric() || c == '_' || c == '-' || c == '.') + || settings_name.contains("..") + { + let response = CommunicationValue::new(CommunicationType::error_invalid_data) + .with_id(cv.get_id()) + .with_receiver(my_id) + .add_data( + DataTypes::message, + DataValue::Str("Invalid settings_name".to_string()), + ) + .add_data( + DataTypes::settings_name, + DataValue::Str(settings_name.to_string()), + ) + .add_data(DataTypes::session_id, DataValue::Number(session_id)); + self.send_message(&response).await; + return; + } + + let settings_file = format!("{}.settings", settings_name); + let settings_path = format!("users/{}/settings/{}/", my_id, session_id); + if !has_file(&settings_path, &settings_file) { + let response = CommunicationValue::new(CommunicationType::error_not_found) + .with_id(cv.get_id()) + .with_receiver(my_id) + .add_data( + DataTypes::settings_name, + DataValue::Str(settings_name.to_string()), + ) + .add_data(DataTypes::session_id, DataValue::Number(session_id)); + self.send_message(&response).await; + return; + } + + let settings_value_str = load_file(&settings_path, &settings_file); let response = CommunicationValue::new(CommunicationType::settings_load) .with_id(cv.get_id()) .with_receiver(my_id) .add_data(DataTypes::payload, DataValue::Str(settings_value_str)) - .add_data(DataTypes::settings_name, DataValue::Str(settings_name)); + .add_data( + DataTypes::settings_name, + DataValue::Str(settings_name.to_string()), + ) + .add_data(DataTypes::session_id, DataValue::Number(session_id)); self.send_message(&response).await; return; @@ -1344,7 +1545,19 @@ impl OmikronConnection { if cv.is_type(CommunicationType::settings_list) { let my_id = cv.get_sender(); - let settings = get_children(&format!("users/{}/settings/", my_id)); + let Some(session_id) = cv.get_data(DataTypes::session_id).as_number() else { + let response = CommunicationValue::new(CommunicationType::error_invalid_data) + .with_id(cv.get_id()) + .with_receiver(my_id) + .add_data( + DataTypes::message, + DataValue::Str("Missing session_id".to_string()), + ); + self.send_message(&response).await; + return; + }; + + let settings = get_children(&format!("users/{}/settings/{}/", my_id, session_id)); let mut settings_json = Vec::new(); for s in settings { let s = s.replace(".settings", ""); @@ -1356,7 +1569,8 @@ impl OmikronConnection { let response = CommunicationValue::new(CommunicationType::settings_list) .with_id(cv.get_id()) .with_receiver(my_id) - .add_data(DataTypes::settings, DataValue::Array(settings_json)); + .add_data(DataTypes::settings, DataValue::Array(settings_json)) + .add_data(DataTypes::session_id, DataValue::Number(session_id)); self.send_message(&response).await; return; @@ -1365,29 +1579,38 @@ impl OmikronConnection { async fn handle_challenge(&self, cv: &CommunicationValue) { let conf = CONFIG.read().await; - let private_key = conf.get_private_key().unwrap(); + let Some(private_key) = conf.get_private_key() else { + drop(conf); + log_t!("omikron_challenge_decryption_failed"); + *self.auth_failure.write().await = Some( + "Challenge decryption failed: no private key configured on this Iota.".to_string(), + ); + return; + }; drop(conf); - let omikron_public_key = cv.get_data(DataTypes::public_key).as_str().unwrap(); - let encrypted_challenge = cv.get_data(DataTypes::challenge).as_str().unwrap(); - - let solved_challenge = { - if let Ok(decrypted) = SecurePayload::new( - encrypted_challenge, - DataFormat::Base64, - crypto_helper::load_secret_key(&private_key).unwrap(), - ) { - if let Ok(decrypted) = decrypted - .decrypt_x448(crypto_helper::load_public_key(omikron_public_key).unwrap()) - { - Some(decrypted) - } else { - None - } - } else { - None - } + let Some(omikron_public_key) = cv.get_data(DataTypes::public_key).as_str() else { + log_t!("omikron_challenge_decryption_failed"); + return; }; + let Some(encrypted_challenge) = cv.get_data(DataTypes::challenge).as_str() else { + log_t!("omikron_challenge_decryption_failed"); + return; + }; + + let Some(secret_key) = crypto_helper::load_secret_key(&private_key) else { + log_t!("omikron_challenge_decryption_failed"); + return; + }; + let Some(pub_key) = crypto_helper::load_public_key(omikron_public_key) else { + log_t!("omikron_challenge_decryption_failed"); + return; + }; + + let solved_challenge = + SecurePayload::new(encrypted_challenge, DataFormat::Base64, secret_key) + .ok() + .and_then(|decrypted| decrypted.decrypt_x448(pub_key).ok()); if let Some(decrypted) = solved_challenge { let solved = decrypted.export(DataFormat::Raw);