From 81700d30b6742ea34892a1a3fb3578d743f1b264 Mon Sep 17 00:00:00 2001 From: Kat Inskip Date: Mon, 27 Oct 2025 02:20:07 -0700 Subject: [PATCH] feat: various attempts --- Cargo.lock | 552 ++++++++++++++++++++++++++++++++++++++++++++++++++- Cargo.toml | 7 +- secrets.yaml | 8 +- src/http.rs | 185 +++++++++++++++++ src/main.rs | 71 +++++-- src/rng.rs | 56 ++++++ 6 files changed, 854 insertions(+), 25 deletions(-) create mode 100644 src/http.rs create mode 100644 src/rng.rs diff --git a/Cargo.lock b/Cargo.lock index 800a875..f363339 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -2,6 +2,41 @@ # It is not intended for manual editing. version = 4 +[[package]] +name = "aead" +version = "0.5.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d122413f284cf2d62fb1b7db97e02edb8cda96d769b16e443a4f6195e35662b0" +dependencies = [ + "crypto-common", + "generic-array 0.14.9", +] + +[[package]] +name = "aes" +version = "0.8.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b169f7a6d4742236a0a00c541b845991d0ac43e546831af1249753ab4c3aa3a0" +dependencies = [ + "cfg-if", + "cipher", + "cpufeatures", +] + +[[package]] +name = "aes-gcm" +version = "0.10.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "831010a0f742e1209b3bcea8fab6a8e149051ba6099432c8cb2cc117dec3ead1" +dependencies = [ + "aead", + "aes", + "cipher", + "ctr", + "ghash", + "subtle", +] + [[package]] name = "allocator-api2" version = "0.3.1" @@ -14,6 +49,27 @@ version = "1.0.100" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "a23eb6b1614318a8071c9b2521f36b424b2c83db5eb3a0fead4a6c0809af6e61" +[[package]] +name = "as-slice" +version = "0.1.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "45403b49e3954a4b8428a0ac21a4b7afadccf92bfd96273f1a58cd4812496ae0" +dependencies = [ + "generic-array 0.12.4", + "generic-array 0.13.3", + "generic-array 0.14.9", + "stable_deref_trait", +] + +[[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.4.0" @@ -26,12 +82,24 @@ version = "1.2.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "7b7e4c2464d97fe331d41de9d5db0def0a96f4d823b8b32a2efd503578988973" +[[package]] +name = "base16ct" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4c7f02d4ea65f2c1853089ffd8d2787bdbc63de2f0d29dedbcf8ccdfa0ccd4cf" + [[package]] name = "base64" version = "0.13.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9e1b586273c5702936fe7b7d6896644d8be71e6314cfe09d3167c95f712589e8" +[[package]] +name = "base64" +version = "0.21.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9d297deb1925b89f2ccc13d7635fa0714f12c87adce1c75356b39ca9b7178567" + [[package]] name = "bitfield" version = "0.19.1" @@ -64,6 +132,25 @@ version = "2.9.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "5c8214115b7bf84099f1309324e63141d4c5d7cc26862f97a0a857dbefe165bd" +[[package]] +name = "block-buffer" +version = "0.10.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3078c7629b62d3f0439517fa394996acacc5cbc91c5a20d8c658e77abd503a71" +dependencies = [ + "generic-array 0.14.9", +] + +[[package]] +name = "buffered-io" +version = "0.5.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d5698b2eda4613b62f3aa3119805df1ca6739e00167a2600b3a234ac49b14803" +dependencies = [ + "embedded-io 0.6.1", + "embedded-io-async 0.6.1", +] + [[package]] name = "byte-slice-cast" version = "1.2.3" @@ -88,28 +175,74 @@ version = "1.0.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "2fd1289c04a9ea8cb22300a459a72a385d7c73d3259e2ed7dcb2af674838cfa9" +[[package]] +name = "cipher" +version = "0.4.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "773f3b9af64447d2ce9850330c473515014aa235e6a783b02db81ff39e4a3dad" +dependencies = [ + "crypto-common", + "inout", +] + [[package]] name = "const-default" version = "1.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "0b396d1f76d455557e1218ec8066ae14bba60b4b36ecd55577ba979f5db7ecaa" +[[package]] +name = "const-oid" +version = "0.9.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c2459377285ad874054d797f3ccebf984978aa39129f6eafde5cdc8315b612f8" + +[[package]] +name = "cpufeatures" +version = "0.2.17" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "59ed5838eebb26a2bb2e58f6d5b5316989ae9d08bab10e0e6d103e656d1b0280" +dependencies = [ + "libc", +] + [[package]] name = "critical-section" version = "1.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "790eea4361631c5e7d22598ecd5723ff611904e3344ce8720784c93e3d83d40b" +[[package]] +name = "crypto-bigint" +version = "0.5.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0dc92fb57ca44df6db8059111ab3af99a63d5d0f8375d9972e319a379c6bab76" +dependencies = [ + "generic-array 0.14.9", + "rand_core 0.6.4", + "subtle", + "zeroize", +] + [[package]] name = "crypto-common" version = "0.1.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "1bfb12502f3fc46cca1bb51ac28df9d618d813cdc3d2f25b9fe775a34af26bb3" dependencies = [ - "generic-array", + "generic-array 0.14.9", "typenum", ] +[[package]] +name = "ctr" +version = "0.9.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0369ee1ad671834580515889b80f2ea915f23b8be8d0daa4bbaf2ac5c7590835" +dependencies = [ + "cipher", +] + [[package]] name = "darling" version = "0.20.11" @@ -145,6 +278,47 @@ dependencies = [ "syn 2.0.102", ] +[[package]] +name = "defmt" +version = "0.3.100" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f0963443817029b2024136fc4dd07a5107eb8f977eaf18fcd1fdeb11306b64ad" +dependencies = [ + "defmt 1.0.1", +] + +[[package]] +name = "defmt" +version = "1.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "548d977b6da32fa1d1fda2876453da1e7df63ad0304c8b3dae4dbe7b96f39b78" +dependencies = [ + "bitflags 1.3.2", + "defmt-macros", +] + +[[package]] +name = "defmt-macros" +version = "1.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3d4fc12a85bcf441cfe44344c4b72d58493178ce635338a3f3b78943aceb258e" +dependencies = [ + "defmt-parser", + "proc-macro-error2", + "proc-macro2", + "quote", + "syn 2.0.102", +] + +[[package]] +name = "defmt-parser" +version = "1.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "10d60334b3b2e7c9d91ef8150abfb6fa4c1c39ebbcf4a81c2e346aad939fee3e" +dependencies = [ + "thiserror", +] + [[package]] name = "delegate" version = "0.13.3" @@ -156,13 +330,25 @@ dependencies = [ "syn 2.0.102", ] +[[package]] +name = "der" +version = "0.7.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e7c1832837b905bbfb5101e07cc24c8deddf52f93225eee6ead5f4d63d53ddcb" +dependencies = [ + "const-oid", + "zeroize", +] + [[package]] name = "digest" version = "0.10.7" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9ed9a281f7bc9b7576e61468ba615a66a5c8cfdff42420a70aa82701a3b1e292" dependencies = [ + "block-buffer", "crypto-common", + "subtle", ] [[package]] @@ -192,6 +378,25 @@ dependencies = [ "litrs", ] +[[package]] +name = "elliptic-curve" +version = "0.13.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b5e6043086bf7973472e0c7dff2142ea0b680d30e18d9cc40f267efbf222bd47" +dependencies = [ + "base16ct", + "crypto-bigint", + "digest", + "ff", + "generic-array 0.14.9", + "group", + "hkdf", + "rand_core 0.6.4", + "sec1", + "subtle", + "zeroize", +] + [[package]] name = "embassy-embedded-hal" version = "0.5.0" @@ -265,7 +470,7 @@ dependencies = [ "embassy-sync 0.7.2", "embassy-time", "embedded-io-async 0.6.1", - "embedded-nal-async", + "embedded-nal-async 0.8.0", "heapless 0.8.0", "managed", "smoltcp", @@ -477,6 +682,16 @@ dependencies = [ "embedded-nal", ] +[[package]] +name = "embedded-nal-async" +version = "0.9.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "eb5a1bd585135d302f8f6d7de329310938093da6271b37a6c94b8798795c0c6d" +dependencies = [ + "embedded-io-async 0.7.0", + "embedded-nal", +] + [[package]] name = "embedded-storage" version = "0.3.1" @@ -503,6 +718,28 @@ dependencies = [ "object-chain", ] +[[package]] +name = "embedded-tls" +version = "0.17.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a6efb76fdd004a4ef787640177237b83449e6c5847765ea50bf15900061fd601" +dependencies = [ + "aes-gcm", + "atomic-polyfill", + "digest", + "embedded-io 0.6.1", + "embedded-io-async 0.6.1", + "generic-array 0.14.9", + "heapless 0.6.1", + "heapless 0.8.0", + "hkdf", + "hmac", + "p256", + "rand_core 0.6.4", + "sha2", + "typenum", +] + [[package]] name = "enumset" version = "1.1.6" @@ -867,6 +1104,16 @@ dependencies = [ "vcell", ] +[[package]] +name = "ff" +version = "0.13.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c0b50bfb653653f9ca9095b427bed08ab8d75a137839d9ad64eb11810d5b6393" +dependencies = [ + "rand_core 0.6.4", + "subtle", +] + [[package]] name = "float-cmp" version = "0.9.0" @@ -927,6 +1174,24 @@ version = "2.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "1d758ba1b47b00caf47f24925c0074ecb20d6dfcffe7f6d53395c0465674841a" +[[package]] +name = "generic-array" +version = "0.12.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ffdf9f34f1447443d37393cc6c2b8313aebddcd96906caf34e54c68d8e57d7bd" +dependencies = [ + "typenum", +] + +[[package]] +name = "generic-array" +version = "0.13.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f797e67af32588215eaaab8327027ee8e71b9dd0b2b26996aedf20c030fce309" +dependencies = [ + "typenum", +] + [[package]] name = "generic-array" version = "0.14.9" @@ -935,6 +1200,37 @@ checksum = "4bb6743198531e02858aeaea5398fcc883e71851fcbcb5a2f773e2fb6cb1edf2" dependencies = [ "typenum", "version_check", + "zeroize", +] + +[[package]] +name = "ghash" +version = "0.5.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f0d8a4362ccb29cb0b265253fb0a2728f592895ee6854fd9bc13f2ffda266ff1" +dependencies = [ + "opaque-debug", + "polyval", +] + +[[package]] +name = "group" +version = "0.13.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f0f9ef7462f7c099f518d754361858f86d8a07af53ba9af0fe635bbccb151a63" +dependencies = [ + "ff", + "rand_core 0.6.4", + "subtle", +] + +[[package]] +name = "hash32" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d4041af86e63ac4298ce40e5cca669066e75b6f1aa3390fe2561ffa5e1d9f4cc" +dependencies = [ + "byteorder", ] [[package]] @@ -952,13 +1248,25 @@ version = "0.15.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "bf151400ff0baff5465007dd2f3e717f3fe502074ca563069ce3a6629d07b289" +[[package]] +name = "heapless" +version = "0.6.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "634bd4d29cbf24424d0a4bfcbf80c6960129dc24424752a7d1d1390607023422" +dependencies = [ + "as-slice", + "generic-array 0.14.9", + "hash32 0.1.1", + "stable_deref_trait", +] + [[package]] name = "heapless" version = "0.8.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "0bfb9eb618601c89945a70e254898da93b13be0388091d42117462b265bb3fad" dependencies = [ - "hash32", + "hash32 0.3.1", "stable_deref_trait", ] @@ -968,7 +1276,7 @@ version = "0.9.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b1edcd5a338e64688fbdcb7531a846cfd3476a54784dcb918a0844682bc7ada5" dependencies = [ - "hash32", + "hash32 0.3.1", "stable_deref_trait", ] @@ -978,6 +1286,36 @@ version = "0.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "2304e00983f87ffb38b55b444b5e3b60a884b5d30c0fca7d82fe33449bbe55ea" +[[package]] +name = "hex" +version = "0.4.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7f24254aa9a54b5c858eaee2f5bccdb46aaf0e486a595ed5fd8f86ba55232a70" + +[[package]] +name = "hkdf" +version = "0.12.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7b5f8eb2ad728638ea2c7d47a21db23b7b58a72ed6a38256b8a1849f15fbbdf7" +dependencies = [ + "hmac", +] + +[[package]] +name = "hmac" +version = "0.12.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6c49c37c09c17a53d937dfbb742eb3a961d65a994e6bcdcf37e7399d0cc8ab5e" +dependencies = [ + "digest", +] + +[[package]] +name = "httparse" +version = "1.10.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6dbf3de79e51f3d586ab4cb9d5c3e2c14aa28ed23d180cf89b4df0454a69cc87" + [[package]] name = "ident_case" version = "1.0.1" @@ -1011,6 +1349,15 @@ version = "2.0.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f4c7245a08504955605670dbf141fceab975f15ca21570696aebe9d2e71576bd" +[[package]] +name = "inout" +version = "0.1.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "879f10e63c20629ecabbb64a8010319738c66a5cd0c29b02d63d272b03751d01" +dependencies = [ + "generic-array 0.14.9", +] + [[package]] name = "instability" version = "0.3.9" @@ -1096,7 +1443,9 @@ dependencies = [ "embedded-graphics", "embedded-hal-bus", "embedded-layout", + "embedded-nal-async 0.9.0", "embedded-text", + "embedded-tls", "esp-alloc", "esp-backtrace", "esp-bootloader-esp-idf", @@ -1106,6 +1455,8 @@ dependencies = [ "esp-rtos", "ili9341", "log", + "rand_core 0.9.3", + "reqwless", "static_cell", ] @@ -1136,6 +1487,12 @@ version = "1.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "8d5439c4ad607c3c23abf66de8c8bf57ba8adcd1f129e699851a6e43935d339d" +[[package]] +name = "nourl" +version = "0.1.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "aa07b0722c63805057dec824444fdc814bdfd30d1c782a3a8f63bbcf67c4ed1c" + [[package]] name = "num-derive" version = "0.4.2" @@ -1162,6 +1519,22 @@ version = "0.1.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "41af26158b0f5530f7b79955006c2727cd23d0d8e7c3109dc316db0a919784dd" +[[package]] +name = "opaque-debug" +version = "0.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c08d65885ee38876c4f86fa503fb49d7b507c2b62552df7c70b2fce627e06381" + +[[package]] +name = "p256" +version = "0.13.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c9863ad85fa8f4460f9c48cb909d38a0d689dba1f6f6988a5e3e0d31071bcd4b" +dependencies = [ + "elliptic-curve", + "primeorder", +] + [[package]] name = "paste" version = "1.0.15" @@ -1180,6 +1553,18 @@ version = "0.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "8b870d8c151b6f2fb93e84a13146138f05d02ed11c7e7c54f8826aaaf7c9f184" +[[package]] +name = "polyval" +version = "0.6.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9d1fe60d06143b2430aa532c94cfe9e29783047f06c0d7fd359a9a51b729fa25" +dependencies = [ + "cfg-if", + "cpufeatures", + "opaque-debug", + "universal-hash", +] + [[package]] name = "portable-atomic" version = "1.11.0" @@ -1216,6 +1601,24 @@ dependencies = [ "syn 2.0.102", ] +[[package]] +name = "ppv-lite86" +version = "0.2.21" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "85eae3c4ed2f50dcfe72643da4befc30deadb458a9b590d720cde2f2b1e97da9" +dependencies = [ + "zerocopy", +] + +[[package]] +name = "primeorder" +version = "0.13.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "353e1ca18966c16d9deb1c69278edbc5f194139612772bd9537af60ac231e1e6" +dependencies = [ + "elliptic-curve", +] + [[package]] name = "proc-macro-crate" version = "3.4.0" @@ -1225,6 +1628,28 @@ dependencies = [ "toml_edit", ] +[[package]] +name = "proc-macro-error-attr2" +version = "2.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "96de42df36bb9bba5542fe9f1a054b8cc87e172759a1868aa05c1f3acc89dfc5" +dependencies = [ + "proc-macro2", + "quote", +] + +[[package]] +name = "proc-macro-error2" +version = "2.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "11ec05c52be0a07b08061f7dd003e7d7092e0472bc731b4af7bb1ef876109802" +dependencies = [ + "proc-macro-error-attr2", + "proc-macro2", + "quote", + "syn 2.0.102", +] + [[package]] name = "proc-macro2" version = "1.0.95" @@ -1243,6 +1668,16 @@ dependencies = [ "proc-macro2", ] +[[package]] +name = "rand_chacha" +version = "0.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e6c10a63a0fa32252be49d21e7709d4d4baf8d231c2dbce1eaa8141b9b127d88" +dependencies = [ + "ppv-lite86", + "rand_core 0.6.4", +] + [[package]] name = "rand_core" version = "0.6.4" @@ -1255,6 +1690,26 @@ version = "0.9.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "99d9a13982dcf210057a8a78572b2217b667c3beacbf3a0d8b454f6f82837d38" +[[package]] +name = "reqwless" +version = "0.13.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fb1be74cb817fa6dbda417110f575d9b9ad5488817f1eb65f2f6468fe6d5d663" +dependencies = [ + "base64 0.21.7", + "buffered-io", + "embedded-io 0.6.1", + "embedded-io-async 0.6.1", + "embedded-nal-async 0.8.0", + "embedded-tls", + "heapless 0.8.0", + "hex", + "httparse", + "nourl", + "rand_chacha", + "rand_core 0.6.4", +] + [[package]] name = "riscv" version = "0.15.0" @@ -1338,6 +1793,19 @@ version = "1.0.20" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "28d3b2b1366ec20994f1fd18c3c594f05c5dd4bc44d8bb0c1c632c8d6829481f" +[[package]] +name = "sec1" +version = "0.7.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d3e97a565f76233a6003f9f5c54be1d9c5bdfa3eccfb189469f11ec4901c47dc" +dependencies = [ + "base16ct", + "der", + "generic-array 0.14.9", + "subtle", + "zeroize", +] + [[package]] name = "serde" version = "1.0.228" @@ -1381,6 +1849,17 @@ dependencies = [ "unsafe-libyaml", ] +[[package]] +name = "sha2" +version = "0.10.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a7507d819769d01a365ab707794a4084392c824f54a7a6a7862f8c3d0892b283" +dependencies = [ + "cfg-if", + "cpufeatures", + "digest", +] + [[package]] name = "smoltcp" version = "0.12.0" @@ -1390,6 +1869,7 @@ dependencies = [ "bitflags 1.3.2", "byteorder", "cfg-if", + "defmt 0.3.100", "heapless 0.8.0", "managed", ] @@ -1452,13 +1932,19 @@ dependencies = [ "syn 2.0.102", ] +[[package]] +name = "subtle" +version = "2.6.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "13c2bddecc57b384dee18652358fb23172facb8a2c51ccc10d74c157bdea3292" + [[package]] name = "svgbobdoc" version = "0.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f2c04b93fc15d79b39c63218f15e3fdffaa4c227830686e3b7c5f41244eb3e50" dependencies = [ - "base64", + "base64 0.13.1", "proc-macro2", "quote", "syn 1.0.109", @@ -1496,6 +1982,26 @@ dependencies = [ "winapi-util", ] +[[package]] +name = "thiserror" +version = "2.0.17" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f63587ca0f12b72a0600bcba1d40081f830876000bb46dd2337a3051618f4fc8" +dependencies = [ + "thiserror-impl", +] + +[[package]] +name = "thiserror-impl" +version = "2.0.17" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3ff15c8ecd7de3849db632e14d18d2571fa09dfc5ed93479bc4485c7a517c913" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.102", +] + [[package]] name = "toml_datetime" version = "0.7.3" @@ -1550,6 +2056,16 @@ version = "0.1.14" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "7dd6e30e90baa6f72411720665d41d89b9a3d039dc45b8faea1ddd07f617f6af" +[[package]] +name = "universal-hash" +version = "0.5.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fc1de2c688dc15305988b563c3854064043356019f97a4b46276fe734c4f07ea" +dependencies = [ + "crypto-common", + "subtle", +] + [[package]] name = "unsafe-libyaml" version = "0.2.11" @@ -1695,3 +2211,29 @@ dependencies = [ "quote", "syn 2.0.102", ] + +[[package]] +name = "zerocopy" +version = "0.8.27" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0894878a5fa3edfd6da3f88c4805f4c8558e2b996227a3d864f47fe11e38282c" +dependencies = [ + "zerocopy-derive", +] + +[[package]] +name = "zerocopy-derive" +version = "0.8.27" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "88d2b8d9c68ad2b9e4340d7832716a4d21a22a1154777ad56ea55c51a9cf3831" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.102", +] + +[[package]] +name = "zeroize" +version = "1.8.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b97154e67e32c85465826e8bcc1c59429aaaf107c1e4a9e53c8d8ccd5eff88d0" diff --git a/Cargo.toml b/Cargo.toml index 82aaf63..de8a44b 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -24,7 +24,7 @@ esp32c3 = [ [dependencies] display-interface-spi = "0.5.0" embassy-executor = "0.9.1" -embassy-net = { version = "0.7.1", features = ["tcp", "udp", "dhcpv4", "medium-ethernet"] } +embassy-net = { version = "0.7.1", features = ["tcp", "udp", "dhcpv4", "dns", "alloc", "medium-ethernet"] } embassy-time = "0.5.0" embedded-graphics = "0.8.1" embedded-hal-bus = "0.3.0" @@ -43,9 +43,12 @@ esp-radio = { version = "0.16.0", features = ["smoltcp", "wifi", "esp32c3", "uns esp-rtos = { version = "0.1.1", features = ["esp32c3", "embassy", "esp-radio"] } ili9341 = "0.6.0" static_cell = "2.1.1" - log = { version = "0.4.28", optional = true } embassy-sync = "0.7.2" +reqwless = { version = "0.13.0", features = ["alloc", "embedded-tls"] } +embedded-tls = { version = "0.17.0", features = ["alloc"], default-features = false } +embedded-nal-async = "0.9.0" +rand_core = "0.9.3" # https://docs.espressif.com/projects/rust/esp-wifi/0.15.0/esp32c3/esp_wifi/index.html#optimization-level [profile.dev.package.esp-wifi] diff --git a/secrets.yaml b/secrets.yaml index ad8f5e4..e4ad4fc 100644 --- a/secrets.yaml +++ b/secrets.yaml @@ -1,9 +1,13 @@ WIFI_SSID: ENC[AES256_GCM,data:4mQfGSI=,iv:q8ljooV+fN/g2oBL7J6M5CkQ/h/pYnagdsVJ+PLF+hA=,tag:3eGz3yh0UX0mWL1H+aFGpA==,type:str] +NTFY_TOKEN: ENC[AES256_GCM,data:eDt3IRJFgEcQUZllsw/RzZtkBEXAbsPZahyr5dy838A=,iv:BZ2NLSfh9/3oRFVrQqFapcXxl2fPWhfV8b5VXZv1bDc=,tag:jEM64KW/gEp5sHRztaKcJw==,type:str] WIFI_PASSWORD: ENC[AES256_GCM,data:MUZ0olPXKE4=,iv:AOIfYGGhLvcTVb+7HOY/2hQT8AzAQq358xDd5pIRSO8=,tag:ZyCEhEitqwGweZ0hEAeG0Q==,type:str] +NTFY_SCHEME: ENC[AES256_GCM,data:M4ru0dY=,iv:3btErbaLfmIWrH7rpaGWsbwnSk2hQpEqRBqdMRnVYSE=,tag:gPkIRZbBEI0qB7dXh8p8SA==,type:str] +NTFY_UPSTREAM: ENC[AES256_GCM,data:wVDk4vRy2lQGpq5fA8zN1A==,iv:G0BJesBc9s/JYf12qp1M176Xf3Or6fcPZwp0o80IgH0=,tag:J26ca+vdfzaKsUtC63a04w==,type:str] +NTFY_SUBPATH: ENC[AES256_GCM,data:xtesTGFm,iv:HG/+3J1adQLTIHHvfZmaqwvXwXEpEQ6Yr1CnezG9k3U=,tag:VM6/pGe681z3BGHG1tDvFQ==,type:str] sops: shamir_threshold: 1 - lastmodified: "2025-10-18T08:32:27Z" - mac: ENC[AES256_GCM,data:rm46Or9iyN2mNy6id0oNDLf+y0zXiLUCZB8wRxh0zItQyTAnAWiE/ccVmKu/AKQASDdimEwlxn2JWXZQZuulFVGBrSRzPkr2mxkIpCLT2ybMbghropTnSWANw55YcXblNl4QptW3r2ZioM5jD93ADqGsZxm++0zanqCIlZU8HWA=,iv:UnrDnYBKD2ZA9FWcASn0TaJNDqTN/WNAgbi8KVxwgvw=,tag:UuSALcsVmYWKCFzZdkukOQ==,type:str] + lastmodified: "2025-10-19T10:51:12Z" + mac: ENC[AES256_GCM,data:7ngRwKB6qKQiFm5iEf/SDPtZ1yngXGvn2ZL6wK8I2bAKled44cZ6rkTT8Y5a2aAaUZ6LYkjWVcHqiyGJCEaVclCSKb+70HHLX+znYbWlMMSiScp80dnQLlzFcwEAKghCA2UFz2MwUU/51UMs2N10IjfDn1aRvQ7WNboVsCVRWEw=,iv:P+eA6x0uBBdSbJ8e5CVlGI2pfEnilzqBiQ46yqxj6T0=,tag:+sLKoA/U6PJRkfVLplNF8A==,type:str] pgp: - created_at: "2025-10-18T08:31:23Z" enc: |- diff --git a/src/http.rs b/src/http.rs new file mode 100644 index 0000000..b3c2f29 --- /dev/null +++ b/src/http.rs @@ -0,0 +1,185 @@ +// Copyright Claudio Mattera 2024-2025. +// +// Distributed under the MIT License or the Apache 2.0 License at your option. +// See the accompanying files LICENSE-MIT.txt and LICENSE-APACHE-2.0.txt, or +// online at +// https://opensource.org/licenses/MIT +// https://opensource.org/licenses/Apache-2.0 + +//! HTTP client + +use alloc::format; +use alloc::string::FromUtf8Error; +use alloc::string::String; +use embassy_net::dns::DnsSocket; +use alloc::vec::Vec; +use embassy_net::dns::Error as DnsError; +use embassy_net::tcp::client::TcpClient; +use embassy_net::tcp::client::TcpClientState; +use embassy_net::tcp::ConnectError as TcpConnectError; +use embassy_net::tcp::Error as TcpError; +use embassy_net::Stack; +use log::debug; + +use reqwless::client::HttpClient; +use reqwless::client::TlsConfig; +use reqwless::client::TlsVerify; +use reqwless::headers::ContentType; +use reqwless::request::Method; +use reqwless::request::RequestBuilder; +use reqwless::Error as ReqlessError; + +use rand_core::RngCore as _; + +use crate::RngWrapper; +use crate::NTFY_TOKEN; + +/// Response size +const RESPONSE_SIZE: usize = 4096; + +/// HTTP client +/// +/// This trait exists to be extended with requests to specific sites, like in +/// [`WorldTimeApiClient`][crate::worldtimeapi::WorldTimeApiClient]. +pub trait ClientTrait { + /// Send an HTTP request + async fn send_request(&mut self, url: &str) -> Result; +} + +/// HTTP client +pub struct Client { + /// Wifi stack + stack: Stack<'static>, + + /// Random numbers generator + rng: RngWrapper, + + /// TCP client state + tcp_client_state: TcpClientState<1, 4096, 4096>, + + /// Buffer for received TLS data + read_record_buffer: [u8; 16640], + + /// Buffer for transmitted TLS data + write_record_buffer: [u8; 16640], +} + +impl Client { + /// Create a new client + pub fn new(stack: Stack<'static>, rng: RngWrapper) -> Self { + debug!("Create TCP client state"); + let tcp_client_state = TcpClientState::<1, 4096, 4096>::new(); + + Self { + stack, + rng, + + tcp_client_state, + + read_record_buffer: [0_u8; 16640], + write_record_buffer: [0_u8; 16640], + } + } +} + +impl ClientTrait for Client { + async fn send_request(&mut self, url: &str) -> Result { + debug!("Send HTTPs request to {url}"); + + debug!("Create DNS socket"); + let dns_socket = DnsSocket::new(self.stack); + + let seed = self.rng.next_u64(); + let tls_config = TlsConfig::new( + seed, + &mut self.read_record_buffer, + &mut self.write_record_buffer, + TlsVerify::None, + ); + + debug!("Create TCP client"); + let tcp_client = TcpClient::new(self.stack, &self.tcp_client_state); + + debug!("Create HTTP client"); + let mut client = HttpClient::new_with_tls(&tcp_client, &dns_socket, tls_config); + + debug!("Create HTTP request"); + let mut buffer = [0_u8; 4096]; + let mut request = client.request(Method::GET, url).await?; + + debug!("Send HTTP request"); + let auth = format!("Bearer {}", NTFY_TOKEN); + let auth_str = auth.as_str(); + let headers = [("Authorization", auth_str)]; + // -H "Authorization: Bearer ''${SSH_NOTIFY_TOKEN}" \= + let mut response = request + //.host("ntfy.kittywit.ch") + .content_type(ContentType::TextPlain) + .headers(&headers); + let mut response = response + .send(&mut buffer).await?; + + debug!("Response status: {:?}", response.status); + + let buffer = response.body().read_to_end().await?; + + debug!("Read {} bytes", buffer.len()); + + let mut vecy = Vec::new(); + vecy.extend_from_slice(buffer); + let output = String::from_utf8(vecy)?; + Ok(output) + } +} + +/// An error within an HTTP request +#[derive(Debug)] +pub enum Error { + // Error turning it into a utf-8 string + FromUtf8Error(FromUtf8Error), + + /// Response was too large + ResponseTooLarge, + + /// Error within TCP streams + Tcp(TcpError), + + /// Error within TCP connection + TcpConnect(#[expect(unused, reason = "Never read directly")] TcpConnectError), + + /// Error within DNS system + Dns(#[expect(unused, reason = "Never read directly")] DnsError), + + /// Error in HTTP client + Reqless(#[expect(unused, reason = "Never read directly")] ReqlessError), +} + +impl From for Error { + fn from(error: FromUtf8Error) -> Self { + Self::FromUtf8Error(error) + } +} + +impl From for Error { + fn from(error: TcpError) -> Self { + Self::Tcp(error) + } +} + +impl From for Error { + fn from(error: TcpConnectError) -> Self { + Self::TcpConnect(error) + } +} + +impl From for Error { + fn from(error: DnsError) -> Self { + Self::Dns(error) + } +} + +impl From for Error { + fn from(error: ReqlessError) -> Self { + Self::Reqless(error) + } +} diff --git a/src/main.rs b/src/main.rs index 043dd77..dcb6761 100644 --- a/src/main.rs +++ b/src/main.rs @@ -5,13 +5,20 @@ extern crate alloc; -use alloc::format; +use alloc::{format, string::{String, ToString}, vec::Vec}; use embassy_sync::{blocking_mutex::raw::CriticalSectionRawMutex, once_lock::OnceLock, rwlock::RwLock}; use esp_alloc as _; use esp_backtrace as _; +use esp_hal::{peripherals::RSA, rsa::Rsa}; + +use crate::http::ClientTrait; use { - embassy_net::Runner, + core::error::Error, + embassy_net::{ + Runner, + + }, embassy_time::{Duration, Timer}, display_interface_spi::SPIInterface, embassy_executor::Spawner, embedded_graphics::{ mono_font::{ascii::FONT_6X10, MonoTextStyle}, @@ -36,7 +43,14 @@ use { esp_println::println }; -use embassy_net::{Stack, StackResources}; +mod rng; +mod http; + +use { + rng::RngWrapper, +}; + +use embassy_net::{dns::DnsSocket, tcp::client::{TcpClient, TcpClientState}, IpAddress, Stack, StackResources}; #[cfg(target_arch = "riscv32")] use esp_hal::interrupt::software::SoftwareInterruptControl; use esp_radio::{ @@ -47,6 +61,10 @@ use esp_radio::{ const SSID: &str = env!("WIFI_SSID"); const PASSWORD: &str = env!("WIFI_PASSWORD"); +const NTFY_TOKEN: &str = env!("NTFY_TOKEN"); +const NTFY_SCHEME: &str = env!("NTFY_SCHEME"); +const NTFY_UPSTREAM: &str = env!("NTFY_UPSTREAM"); +const NTFY_SUBPATH: &str = env!("NTFY_SUBPATH"); esp_bootloader_esp_idf::esp_app_desc!(); @@ -320,30 +338,44 @@ struct Controller<'tft> { } impl <'tft>Controller<'tft> { - async fn init(spawner: Spawner, mut display: TFT<'tft>, stack: Stack<'static>) -> Self { - let wifi = ControllerWifi::init_wifi(spawner, &mut display, stack).await; + async fn init(mut display: TFT<'tft>, stack: Stack<'static>) -> Self { + let mut wifi = ControllerWifi::init_wifi(&mut display, stack).await; let mut controller = Self { display, wifi, }; if let Some(config) = controller.wifi.stack.config_v4() { - controller.display.fullscreen_alert(&format!("Controller initialized!\nCurrent IP address: {}", config.address), true); + let dns_servers = config.dns_servers + .iter() + .map(|x| x.to_string()) + .collect::>() + .join("\n"); + controller.display.fullscreen_alert(&format!("Controller initialized!\nCurrent IP address: {}\nDNS: {}", config.address, dns_servers), true); } controller } + async fn req(&mut self) { + //let url = format!("{}://{}/{}/raw", NTFY_SCHEME, NTFY_UPSTREAM, NTFY_SUBPATH); + let url = "https://ntfy.kittywit.ch/alerts/raw"; + match self.wifi.client.send_request(&url).await { + Ok(dat) => self.display.fullscreen_alert(&dat, true), + Err(err) => { + let out = format!("Error in request: {:?}", err); + log::error!("{}", out); + self.display.fullscreen_alert(&out, true) + } + } + } } struct ControllerWifi { stack: Stack<'static>, + client: http::Client, + } impl ControllerWifi { - async fn init_wifi(spawner: Spawner, display: &mut TFT<'_>, stack: Stack<'static>) -> Self { - - - let mut rx_buffer = [0; 4096]; - let mut tx_buffer = [0; 4096]; - + async fn init_wifi(display: &mut TFT<'_>, stack: Stack<'static>) -> Self { println!("Waiting to get IP address..."); display.fullscreen_alert("Waiting to obtain an IP address", true); loop { @@ -354,11 +386,14 @@ impl ControllerWifi { } Timer::after(Duration::from_millis(500)).await; } - + let rng = Rng::new(); + let client = http::Client::new(stack, RngWrapper::from(rng)); Self { - stack + stack, + client, } } + } #[embassy_executor::task] @@ -420,7 +455,7 @@ async fn main(spawner: Spawner) { #[cfg(feature = "log")] // The default log level can be specified here. // You can see the esp-println documentation: https://docs.rs/esp-println - esp_println::logger::init_logger(log::LevelFilter::Info); + esp_println::logger::init_logger(log::LevelFilter::Debug); let config = esp_hal::Config::default().with_cpu_clock(CpuClock::max()); let peripherals: Peripherals = init(config); @@ -467,7 +502,11 @@ async fn main(spawner: Spawner) { spawner.spawn(connection(wifi_controller)).ok(); spawner.spawn(net_task(runner)).ok(); - let controller = Controller::init(spawner, display, stack).await; + + let mut controller = Controller::init(display, stack).await; + + Timer::after(Duration::from_millis(5000)).await; + controller.req().await; loop { // your business logic diff --git a/src/rng.rs b/src/rng.rs new file mode 100644 index 0000000..dd4abb1 --- /dev/null +++ b/src/rng.rs @@ -0,0 +1,56 @@ +// Copyright Claudio Mattera 2024-2025. +// +// Distributed under the MIT License or the Apache 2.0 License at your option. +// See the accompanying files LICENSE-MIT.txt and LICENSE-APACHE-2.0.txt, or +// online at +// https://opensource.org/licenses/MIT +// https://opensource.org/licenses/Apache-2.0 + +//! Random numbers generator + +use rand_core::CryptoRng; +use rand_core::RngCore; + +use esp_hal::rng::Rng; + +/// A wrapper for ESP random number generator that implement traits form +/// `rand_core` +#[derive(Clone)] +pub struct RngWrapper(Rng); + +impl From for RngWrapper { + fn from(rng: Rng) -> Self { + Self(rng) + } +} + +impl RngCore for RngWrapper { + fn next_u32(&mut self) -> u32 { + self.0.random() + } + + fn next_u64(&mut self) -> u64 { + u32_pair_to_u64(self.next_u32(), self.next_u32()) + } + + fn fill_bytes(&mut self, dest: &mut [u8]) { + for value in dest.iter_mut() { + let [random_value, _, _, _] = self.next_u32().to_ne_bytes(); + *value = random_value; + } + } +} + +impl CryptoRng for RngWrapper {} + +/// Join a pair of `u32` into a `u64` +#[allow( + clippy::many_single_char_names, + clippy::min_ident_chars, + reason = "This is still readable" +)] +fn u32_pair_to_u64(first: u32, second: u32) -> u64 { + let [a, b, c, d] = first.to_ne_bytes(); + let [e, f, g, h] = second.to_ne_bytes(); + u64::from_ne_bytes([a, b, c, d, e, f, g, h]) +}