From 14fcb606707def51146a5f102511504ace1eac92 Mon Sep 17 00:00:00 2001 From: Aiden McClelland Date: Mon, 10 Nov 2025 09:45:30 -0700 Subject: [PATCH] wip: types --- core/Cargo.lock | 249 +++++++++----------- core/startos/Cargo.toml | 2 +- core/startos/src/auth.rs | 10 +- core/startos/src/backup/target/cifs.rs | 2 +- core/startos/src/backup/target/mod.rs | 10 +- core/startos/src/db/mod.rs | 13 +- core/startos/src/db/prelude.rs | 19 ++ core/startos/src/diagnostic.rs | 2 + core/startos/src/disk/fsck/mod.rs | 3 +- core/startos/src/disk/util.rs | 12 +- core/startos/src/hostname.rs | 4 +- core/startos/src/init.rs | 2 + core/startos/src/lib.rs | 20 +- core/startos/src/logs.rs | 26 +- core/startos/src/middleware/auth.rs | 5 +- core/startos/src/net/acme.rs | 4 +- core/startos/src/net/dns.rs | 5 +- core/startos/src/net/forward.rs | 5 +- core/startos/src/net/gateway.rs | 1 + core/startos/src/net/host/address.rs | 10 +- core/startos/src/net/host/mod.rs | 4 +- core/startos/src/net/ssl.rs | 10 +- core/startos/src/net/tor/arti.rs | 4 +- core/startos/src/net/tor/ctor.rs | 6 +- core/startos/src/net/vhost.rs | 1 - core/startos/src/net/wifi.rs | 10 +- core/startos/src/notifications.rs | 4 +- core/startos/src/registry/admin.rs | 3 +- core/startos/src/registry/db.rs | 8 +- core/startos/src/registry/mod.rs | 1 - core/startos/src/registry/os/asset/get.rs | 3 + core/startos/src/registry/os/asset/mod.rs | 2 + core/startos/src/registry/os/version/mod.rs | 4 + core/startos/src/registry/package/mod.rs | 1 + core/startos/src/s9pk/rpc.rs | 7 +- core/startos/src/service/effects/mod.rs | 15 +- core/startos/src/setup.rs | 9 +- core/startos/src/ssh.rs | 2 +- core/startos/src/system.rs | 6 +- core/startos/src/tunnel/api.rs | 4 +- core/startos/src/tunnel/auth.rs | 2 +- core/startos/src/tunnel/db.rs | 8 +- core/startos/src/tunnel/web.rs | 39 ++- core/startos/src/tunnel/wg.rs | 2 +- core/startos/src/update/mod.rs | 2 +- core/startos/src/util/collections/eq_set.rs | 3 +- core/startos/src/util/rpc.rs | 3 +- core/startos/src/util/serde.rs | 121 +++++++++- core/startos/src/util/squashfs.rs | 138 ++++++----- core/startos/src/version/mod.rs | 1 + 50 files changed, 529 insertions(+), 298 deletions(-) diff --git a/core/Cargo.lock b/core/Cargo.lock index 6475294c7..2ffbca243 100644 --- a/core/Cargo.lock +++ b/core/Cargo.lock @@ -270,7 +270,7 @@ source = "git+https://github.com/Start9Labs/arti.git?branch=patch%2Fdisable-exit dependencies = [ "async-trait", "cfg-if", - "derive-deftly 1.2.0", + "derive-deftly", "derive_builder_fork_arti", "derive_more 2.0.1", "educe", @@ -367,7 +367,7 @@ checksum = "965c2d33e53cb6b267e148a4cb0760bc01f4904c1cd4bb4002a085bb016d1490" dependencies = [ "proc-macro2", "quote", - "syn 2.0.108", + "syn 2.0.109", "synstructure", ] @@ -379,7 +379,7 @@ checksum = "3109e49b1e4909e9db6515a30c633684d68cdeaa252f215214cb4fa1a5bfee2c" dependencies = [ "proc-macro2", "quote", - "syn 2.0.108", + "syn 2.0.109", "synstructure", ] @@ -391,7 +391,7 @@ checksum = "7b18050c2cd6fe86c3a76584ef5e0baf286d038cda203eb6223df2cc413565f7" dependencies = [ "proc-macro2", "quote", - "syn 2.0.108", + "syn 2.0.109", ] [[package]] @@ -567,7 +567,7 @@ checksum = "3b43422f69d8ff38f95f1b2bb76517c91589a924d1559a0e935d7c8ce0274c11" dependencies = [ "proc-macro2", "quote", - "syn 2.0.108", + "syn 2.0.109", ] [[package]] @@ -634,7 +634,7 @@ checksum = "c7c24de15d275a1ecfd47a380fb4d5ec9bfe0933f309ed5e705b775596a3574d" dependencies = [ "proc-macro2", "quote", - "syn 2.0.108", + "syn 2.0.109", ] [[package]] @@ -651,7 +651,7 @@ checksum = "9035ad2d096bed7955a320ee7e2230574d28fd3c3a0f186cbea1ff3c7eed5dbb" dependencies = [ "proc-macro2", "quote", - "syn 2.0.108", + "syn 2.0.109", ] [[package]] @@ -989,7 +989,7 @@ dependencies = [ "regex", "rustc-hash", "shlex", - "syn 2.0.108", + "syn 2.0.109", ] [[package]] @@ -1107,7 +1107,7 @@ checksum = "e0b121a9fe0df916e362fb3271088d071159cdf11db0e4182d02152850756eff" dependencies = [ "proc-macro2", "quote", - "syn 2.0.108", + "syn 2.0.109", ] [[package]] @@ -1247,9 +1247,9 @@ checksum = "37b2a672a2cb129a2e41c10b1224bb368f9f37a2b16b612598138befd7b37eb5" [[package]] name = "cc" -version = "1.2.44" +version = "1.2.45" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "37521ac7aabe3d13122dc382493e20c9416f299d2ccd5b3a5340a2570cdeb0f3" +checksum = "35900b6c8d709fb1d854671ae27aeaa9eec2f8b01b364e1619a40da3e6fe2afe" dependencies = [ "find-msvc-tools", "jobserver", @@ -1404,7 +1404,7 @@ dependencies = [ "heck 0.5.0", "proc-macro2", "quote", - "syn 2.0.108", + "syn 2.0.109", ] [[package]] @@ -2011,7 +2011,7 @@ checksum = "f46882e17999c6cc590af592290432be3bce0428cb0d5f8b6715e4dc7b383eb3" dependencies = [ "proc-macro2", "quote", - "syn 2.0.108", + "syn 2.0.109", ] [[package]] @@ -2059,7 +2059,7 @@ dependencies = [ "proc-macro2", "quote", "strsim 0.11.1", - "syn 2.0.108", + "syn 2.0.109", ] [[package]] @@ -2081,7 +2081,7 @@ checksum = "d38308df82d1080de0afee5d069fa14b0326a88c14f15c5ccda35b4a6c414c81" dependencies = [ "darling_core 0.21.3", "quote", - "syn 2.0.108", + "syn 2.0.109", ] [[package]] @@ -2138,7 +2138,7 @@ checksum = "8034092389675178f570469e6c3b0465d3d30b4505c294a6550db47f3c17ad18" dependencies = [ "proc-macro2", "quote", - "syn 2.0.108", + "syn 2.0.109", ] [[package]] @@ -2151,44 +2151,16 @@ dependencies = [ "serde_core", ] -[[package]] -name = "derive-deftly" -version = "0.14.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e8ea84d0109517cc2253d4a679bdda1e8989e9bd86987e9e4f75ffdda0095fd1" -dependencies = [ - "derive-deftly-macros 0.14.6", - "heck 0.5.0", -] - [[package]] name = "derive-deftly" version = "1.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "957bb73a3a9c0bbcac67e129b81954661b3cfcb9e28873d8441f91b54852e77a" dependencies = [ - "derive-deftly-macros 1.2.0", + "derive-deftly-macros", "heck 0.5.0", ] -[[package]] -name = "derive-deftly-macros" -version = "0.14.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "357422a457ccb850dc8f1c1680e0670079560feaad6c2e247e3f345c4fab8a3f" -dependencies = [ - "heck 0.5.0", - "indexmap 2.12.0", - "itertools 0.14.0", - "proc-macro-crate", - "proc-macro2", - "quote", - "sha3 0.10.8", - "strum", - "syn 2.0.108", - "void", -] - [[package]] name = "derive-deftly-macros" version = "1.2.0" @@ -2203,7 +2175,7 @@ dependencies = [ "quote", "sha3 0.10.8", "strum", - "syn 2.0.108", + "syn 2.0.109", "void", ] @@ -2215,7 +2187,7 @@ checksum = "1e567bd82dcff979e4b03460c307b3cdc9e96fde3d73bed1496d2bc75d9dd62a" dependencies = [ "proc-macro2", "quote", - "syn 2.0.108", + "syn 2.0.109", ] [[package]] @@ -2259,7 +2231,7 @@ dependencies = [ "proc-macro2", "quote", "rustc_version", - "syn 2.0.108", + "syn 2.0.109", ] [[package]] @@ -2280,7 +2252,7 @@ dependencies = [ "convert_case 0.7.1", "proc-macro2", "quote", - "syn 2.0.108", + "syn 2.0.109", "unicode-xid", ] @@ -2370,7 +2342,7 @@ checksum = "97369cbbc041bc366949bc74d34658d6cda5621039731c6310521892a3a20ae0" dependencies = [ "proc-macro2", "quote", - "syn 2.0.108", + "syn 2.0.109", ] [[package]] @@ -2451,7 +2423,7 @@ dependencies = [ "proc-macro-error2", "proc-macro2", "quote", - "syn 2.0.108", + "syn 2.0.109", ] [[package]] @@ -2645,7 +2617,7 @@ dependencies = [ "heck 0.5.0", "proc-macro2", "quote", - "syn 2.0.108", + "syn 2.0.109", ] [[package]] @@ -2658,7 +2630,7 @@ dependencies = [ "num-traits", "proc-macro2", "quote", - "syn 2.0.108", + "syn 2.0.109", ] [[package]] @@ -2679,7 +2651,7 @@ checksum = "67c78a4d8fdf9953a5c9d458f9efe940fd97a0cab0941c075a813ac594733827" dependencies = [ "proc-macro2", "quote", - "syn 2.0.108", + "syn 2.0.109", ] [[package]] @@ -3113,7 +3085,7 @@ checksum = "162ee34ebcb7c64a8abebc059ce0fee27c2262618d7b60ed8faf72fef13c3650" dependencies = [ "proc-macro2", "quote", - "syn 2.0.108", + "syn 2.0.109", ] [[package]] @@ -4767,7 +4739,7 @@ checksum = "db5b29714e950dbb20d5e6f74f9dcec4edbcc1067bb7f8ed198c097b8c1a818b" dependencies = [ "proc-macro2", "quote", - "syn 2.0.108", + "syn 2.0.109", ] [[package]] @@ -5150,7 +5122,7 @@ dependencies = [ "proc-macro-crate", "proc-macro2", "quote", - "syn 2.0.108", + "syn 2.0.109", ] [[package]] @@ -5313,9 +5285,9 @@ dependencies = [ [[package]] name = "openssl" -version = "0.10.74" +version = "0.10.75" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "24ad14dd45412269e1a30f52ad8f0664f0f4f4a89ee8fe28c3b3527021ebb654" +checksum = "08838db121398ad17ab8531ce9de97b244589089e290a384c900cb9ff7434328" dependencies = [ "bitflags 2.10.0", "cfg-if", @@ -5334,7 +5306,7 @@ checksum = "a948666b637a0f465e8564c73e89d4dde00d72d4d473cc972f390fc3dcee7d9c" dependencies = [ "proc-macro2", "quote", - "syn 2.0.108", + "syn 2.0.109", ] [[package]] @@ -5354,9 +5326,9 @@ dependencies = [ [[package]] name = "openssl-sys" -version = "0.9.110" +version = "0.9.111" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0a9f0075ba3c21b09f8e8b2026584b1d18d49388648f2fbbf3c97ea8deced8e2" +checksum = "82cab2d520aa75e3c58898289429321eb788c3106963d0dc886ec7a5f4adc321" dependencies = [ "cc", "libc", @@ -5518,7 +5490,7 @@ dependencies = [ "nix 0.30.1", "patch-db-macro", "serde", - "serde_cbor", + "serde_cbor 0.11.1", "thiserror 2.0.17", "tokio", "tracing", @@ -5609,7 +5581,7 @@ dependencies = [ "pest_meta", "proc-macro2", "quote", - "syn 2.0.108", + "syn 2.0.109", ] [[package]] @@ -5683,7 +5655,7 @@ dependencies = [ "phf_shared 0.11.3", "proc-macro2", "quote", - "syn 2.0.108", + "syn 2.0.109", ] [[package]] @@ -5696,7 +5668,7 @@ dependencies = [ "phf_shared 0.13.1", "proc-macro2", "quote", - "syn 2.0.108", + "syn 2.0.109", ] [[package]] @@ -5740,7 +5712,7 @@ checksum = "6e918e4ff8c4549eb882f14b3a4bc8c8bc93de829416eacf579f1207a8fbf861" dependencies = [ "proc-macro2", "quote", - "syn 2.0.108", + "syn 2.0.109", ] [[package]] @@ -5947,7 +5919,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "479ca8adacdd7ce8f1fb39ce9ecccbfe93a3f1344b3d0d97f20bc0196208f62b" dependencies = [ "proc-macro2", - "syn 2.0.108", + "syn 2.0.109", ] [[package]] @@ -6012,7 +5984,7 @@ dependencies = [ "proc-macro-error-attr2", "proc-macro2", "quote", - "syn 2.0.108", + "syn 2.0.109", ] [[package]] @@ -6076,7 +6048,7 @@ checksum = "4ee1c9ac207483d5e7db4940700de86a9aae46ef90c48b57f99fe7edb8345e49" dependencies = [ "proc-macro2", "quote", - "syn 2.0.108", + "syn 2.0.109", ] [[package]] @@ -6099,7 +6071,7 @@ dependencies = [ "itertools 0.14.0", "proc-macro2", "quote", - "syn 2.0.108", + "syn 2.0.109", ] [[package]] @@ -6148,14 +6120,14 @@ dependencies = [ [[package]] name = "pwd-grp" -version = "1.0.0" +version = "1.0.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b94fdf3867b7f2889a736f0022ea9386766280d2cca4bdbe41629ada9e4f3b8f" +checksum = "0e2023f41b5fcb7c30eb5300a5733edfaa9e0e0d502d51b586f65633fd39e40c" dependencies = [ - "derive-deftly 0.14.6", + "derive-deftly", "libc", "paste", - "thiserror 1.0.69", + "thiserror 2.0.17", ] [[package]] @@ -6248,9 +6220,9 @@ dependencies = [ [[package]] name = "quote" -version = "1.0.41" +version = "1.0.42" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ce25767e7b499d1b604768e7cde645d14cc8584231ea6b295e9c9eb22c02e1d1" +checksum = "a338cc41d27e6cc6dce6cefc13a0729dfbb81c262b1f519331575dd80ef3067f" dependencies = [ "proc-macro2", ] @@ -6577,7 +6549,7 @@ checksum = "b7186006dcb21920990093f30e3dea63b7d6e977bf1256be20c3563a5db070da" dependencies = [ "proc-macro2", "quote", - "syn 2.0.108", + "syn 2.0.109", ] [[package]] @@ -6719,7 +6691,7 @@ dependencies = [ [[package]] name = "rpc-toolkit" version = "0.3.2" -source = "git+https://github.com/Start9Labs/rpc-toolkit.git?branch=master#068db905ee38a7da97cc4a43b806409204e73723" +source = "git+https://github.com/Start9Labs/rpc-toolkit.git?branch=master#eb64c1f422d21b4fbba87994d2aadd269e641c97" dependencies = [ "async-stream", "async-trait", @@ -6736,10 +6708,12 @@ dependencies = [ "pin-project", "reqwest", "serde", + "serde_cbor 0.11.2", "serde_json", "thiserror 2.0.17", "tokio", "tokio-stream", + "ts-rs", "url", "yajrc", ] @@ -7045,9 +7019,9 @@ dependencies = [ [[package]] name = "schemars" -version = "1.0.5" +version = "1.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1317c3bf3e7df961da95b0a56a172a02abead31276215a0497241a7624b487ce" +checksum = "9558e172d4e8533736ba97870c4b2cd63f84b382a3d6eb063da41b91cce17289" dependencies = [ "dyn-clone", "ref-cast", @@ -7174,6 +7148,16 @@ dependencies = [ "serde", ] +[[package]] +name = "serde_cbor" +version = "0.11.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2bef2ebfde456fb76bbcf9f59315333decc4fda0b2b44b420243c11e0f5ec1f5" +dependencies = [ + "half 1.8.3", + "serde", +] + [[package]] name = "serde_core" version = "1.0.228" @@ -7191,7 +7175,7 @@ checksum = "d540f220d3187173da220f885ab66608367b6574e925011a9353e4badda91d79" dependencies = [ "proc-macro2", "quote", - "syn 2.0.108", + "syn 2.0.109", ] [[package]] @@ -7248,7 +7232,7 @@ checksum = "175ee3e80ae9982737ca543e96133087cbd9a485eecc3bc4de9c1a37b47ea59c" dependencies = [ "proc-macro2", "quote", - "syn 2.0.108", + "syn 2.0.109", ] [[package]] @@ -7293,7 +7277,7 @@ dependencies = [ "indexmap 1.9.3", "indexmap 2.12.0", "schemars 0.9.0", - "schemars 1.0.5", + "schemars 1.1.0", "serde_core", "serde_json", "serde_with_macros", @@ -7309,7 +7293,7 @@ dependencies = [ "darling 0.21.3", "proc-macro2", "quote", - "syn 2.0.108", + "syn 2.0.109", ] [[package]] @@ -7727,7 +7711,7 @@ dependencies = [ "quote", "sqlx-core", "sqlx-macros-core", - "syn 2.0.108", + "syn 2.0.109", ] [[package]] @@ -7748,7 +7732,7 @@ dependencies = [ "sha2 0.10.9", "sqlx-core", "sqlx-postgres", - "syn 2.0.108", + "syn 2.0.109", "tokio", "url", ] @@ -7813,7 +7797,7 @@ dependencies = [ "quote", "regex-syntax 0.6.29", "strsim 0.11.1", - "syn 2.0.108", + "syn 2.0.109", "unicode-width 0.1.14", ] @@ -8114,7 +8098,7 @@ dependencies = [ "heck 0.5.0", "proc-macro2", "quote", - "syn 2.0.108", + "syn 2.0.109", ] [[package]] @@ -8157,9 +8141,9 @@ dependencies = [ [[package]] name = "syn" -version = "2.0.108" +version = "2.0.109" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "da58917d35242480a05c2897064da0a80589a2a0476c9a3f2fdc83b53502e917" +checksum = "2f17c7e013e88258aa9543dcbe81aca68a667a9ac37cd69c9fbc07858bfe0e2f" dependencies = [ "proc-macro2", "quote", @@ -8183,7 +8167,7 @@ checksum = "728a70f3dbaf5bab7f0c4b1ac8d7ae5ea60a4b5549c8a5914361c99147a709d2" dependencies = [ "proc-macro2", "quote", - "syn 2.0.108", + "syn 2.0.109", ] [[package]] @@ -8351,7 +8335,7 @@ checksum = "4fee6c4efc90059e10f81e6d42c60a18f76588c3d74cb83a0b242a2b6c7504c1" dependencies = [ "proc-macro2", "quote", - "syn 2.0.108", + "syn 2.0.109", ] [[package]] @@ -8362,7 +8346,7 @@ checksum = "3ff15c8ecd7de3849db632e14d18d2571fa09dfc5ed93479bc4485c7a517c913" dependencies = [ "proc-macro2", "quote", - "syn 2.0.108", + "syn 2.0.109", ] [[package]] @@ -8487,7 +8471,7 @@ checksum = "af407857209536a95c8e56f8231ef2c2e2aff839b22e07a1ffcbc617e9db9fa5" dependencies = [ "proc-macro2", "quote", - "syn 2.0.108", + "syn 2.0.109", ] [[package]] @@ -8723,7 +8707,7 @@ name = "tor-async-utils" version = "0.33.0" source = "git+https://github.com/Start9Labs/arti.git?branch=patch%2Fdisable-exit#24730694701a83432d791d80802db8bda0699700" dependencies = [ - "derive-deftly 1.2.0", + "derive-deftly", "educe", "futures", "oneshot-fused-workaround", @@ -8757,7 +8741,7 @@ version = "0.33.0" source = "git+https://github.com/Start9Labs/arti.git?branch=patch%2Fdisable-exit#24730694701a83432d791d80802db8bda0699700" dependencies = [ "bytes", - "derive-deftly 1.2.0", + "derive-deftly", "digest 0.10.7", "educe", "getrandom 0.3.4", @@ -8777,7 +8761,7 @@ dependencies = [ "bitflags 2.10.0", "bytes", "caret", - "derive-deftly 1.2.0", + "derive-deftly", "derive_more 2.0.1", "educe", "itertools 0.14.0", @@ -8868,7 +8852,7 @@ dependencies = [ "async-trait", "bounded-vec-deque", "cfg-if", - "derive-deftly 1.2.0", + "derive-deftly", "derive_builder_fork_arti", "derive_more 2.0.1", "downcast-rs 2.0.2", @@ -8915,7 +8899,7 @@ source = "git+https://github.com/Start9Labs/arti.git?branch=patch%2Fdisable-exit dependencies = [ "amplify", "cfg-if", - "derive-deftly 1.2.0", + "derive-deftly", "derive_builder_fork_arti", "educe", "either", @@ -9078,7 +9062,7 @@ source = "git+https://github.com/Start9Labs/arti.git?branch=patch%2Fdisable-exit dependencies = [ "amplify", "base64ct", - "derive-deftly 1.2.0", + "derive-deftly", "derive_builder_fork_arti", "derive_more 2.0.1", "dyn-clone", @@ -9118,7 +9102,7 @@ version = "0.33.0" source = "git+https://github.com/Start9Labs/arti.git?branch=patch%2Fdisable-exit#24730694701a83432d791d80802db8bda0699700" dependencies = [ "async-trait", - "derive-deftly 1.2.0", + "derive-deftly", "derive_more 2.0.1", "educe", "either", @@ -9162,7 +9146,7 @@ source = "git+https://github.com/Start9Labs/arti.git?branch=patch%2Fdisable-exit dependencies = [ "cipher 0.4.4", "data-encoding", - "derive-deftly 1.2.0", + "derive-deftly", "derive_more 2.0.1", "digest 0.10.7", "equix", @@ -9196,7 +9180,7 @@ dependencies = [ "async-trait", "base64ct", "cfg-if", - "derive-deftly 1.2.0", + "derive-deftly", "derive_builder_fork_arti", "derive_more 2.0.1", "digest 0.10.7", @@ -9249,7 +9233,7 @@ name = "tor-key-forge" version = "0.33.0" source = "git+https://github.com/Start9Labs/arti.git?branch=patch%2Fdisable-exit#24730694701a83432d791d80802db8bda0699700" dependencies = [ - "derive-deftly 1.2.0", + "derive-deftly", "derive_more 2.0.1", "downcast-rs 2.0.2", "paste", @@ -9272,7 +9256,7 @@ dependencies = [ "amplify", "arrayvec 0.7.6", "cfg-if", - "derive-deftly 1.2.0", + "derive-deftly", "derive_builder_fork_arti", "derive_more 2.0.1", "downcast-rs 2.0.2", @@ -9311,7 +9295,7 @@ dependencies = [ "base64ct", "by_address", "caret", - "derive-deftly 1.2.0", + "derive-deftly", "derive_builder_fork_arti", "derive_more 2.0.1", "hex", @@ -9339,7 +9323,7 @@ dependencies = [ "ctr 0.9.2", "curve25519-dalek 4.1.3", "der-parser 10.0.0", - "derive-deftly 1.2.0", + "derive-deftly", "derive_more 2.0.1", "digest 0.10.7", "ed25519-dalek 2.2.0", @@ -9387,7 +9371,7 @@ version = "0.33.0" source = "git+https://github.com/Start9Labs/arti.git?branch=patch%2Fdisable-exit#24730694701a83432d791d80802db8bda0699700" dependencies = [ "cfg-if", - "derive-deftly 1.2.0", + "derive-deftly", "derive_more 2.0.1", "dyn-clone", "educe", @@ -9451,7 +9435,7 @@ dependencies = [ "base64ct", "bitflags 2.10.0", "cipher 0.4.4", - "derive-deftly 1.2.0", + "derive-deftly", "derive_builder_fork_arti", "derive_more 2.0.1", "digest 0.10.7", @@ -9494,7 +9478,7 @@ version = "0.33.0" source = "git+https://github.com/Start9Labs/arti.git?branch=patch%2Fdisable-exit#24730694701a83432d791d80802db8bda0699700" dependencies = [ "amplify", - "derive-deftly 1.2.0", + "derive-deftly", "derive_more 2.0.1", "filetime", "fs-mistrust", @@ -9530,7 +9514,7 @@ dependencies = [ "cipher 0.4.4", "coarsetime", "criterion-cycles-per-byte", - "derive-deftly 1.2.0", + "derive-deftly", "derive_builder_fork_arti", "derive_more 2.0.1", "digest 0.10.7", @@ -9645,7 +9629,7 @@ dependencies = [ "amplify", "assert_matches", "async-trait", - "derive-deftly 1.2.0", + "derive-deftly", "derive_more 2.0.1", "educe", "futures", @@ -9672,7 +9656,7 @@ source = "git+https://github.com/Start9Labs/arti.git?branch=patch%2Fdisable-exit dependencies = [ "amplify", "caret", - "derive-deftly 1.2.0", + "derive-deftly", "educe", "safelog", "subtle", @@ -9686,7 +9670,7 @@ name = "tor-units" version = "0.33.0" source = "git+https://github.com/Start9Labs/arti.git?branch=patch%2Fdisable-exit#24730694701a83432d791d80802db8bda0699700" dependencies = [ - "derive-deftly 1.2.0", + "derive-deftly", "derive_more 2.0.1", "serde", "thiserror 2.0.17", @@ -9811,7 +9795,7 @@ checksum = "81383ab64e72a7a8b8e13130c49e3dab29def6d0c7d76a03087b3cf71c5c6903" dependencies = [ "proc-macro2", "quote", - "syn 2.0.108", + "syn 2.0.109", ] [[package]] @@ -9902,7 +9886,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "04659ddb06c87d233c566112c1c9c5b9e98256d9af50ec3bc9c8327f873a7568" dependencies = [ "quote", - "syn 2.0.108", + "syn 2.0.109", ] [[package]] @@ -9917,6 +9901,7 @@ version = "9.0.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b44017f9f875786e543595076374b9ef7d13465a518dd93d6ccdbf5b432dde8c" dependencies = [ + "chrono", "thiserror 1.0.69", "ts-rs-macros", ] @@ -9929,7 +9914,7 @@ checksum = "c88cc88fd23b5a04528f3a8436024f20010a16ec18eb23c164b1242f65860130" dependencies = [ "proc-macro2", "quote", - "syn 2.0.108", + "syn 2.0.109", "termcolor", ] @@ -9986,7 +9971,7 @@ checksum = "1ecb9ecf7799210407c14a8cfdfe0173365780968dc57973ed082211958e0b18" dependencies = [ "proc-macro2", "quote", - "syn 2.0.108", + "syn 2.0.109", ] [[package]] @@ -10214,7 +10199,7 @@ checksum = "d674d135b4a8c1d7e813e2f8d1c9a58308aee4a680323066025e53132218bd91" dependencies = [ "proc-macro2", "quote", - "syn 2.0.108", + "syn 2.0.109", ] [[package]] @@ -10237,7 +10222,7 @@ checksum = "de41688745bbd6ed24e2f4923026911b523f0c057e10f86f44652a20e65555ce" dependencies = [ "proc-macro2", "quote", - "syn 2.0.108", + "syn 2.0.109", ] [[package]] @@ -10364,7 +10349,7 @@ dependencies = [ "bumpalo", "proc-macro2", "quote", - "syn 2.0.108", + "syn 2.0.109", "wasm-bindgen-shared", ] @@ -10645,7 +10630,7 @@ checksum = "053e2e040ab57b9dc951b72c264860db7eb3b0200ba345b4e4c3b14f67855ddf" dependencies = [ "proc-macro2", "quote", - "syn 2.0.108", + "syn 2.0.109", ] [[package]] @@ -10656,7 +10641,7 @@ checksum = "3f316c4a2570ba26bbec722032c4099d8c8bc095efccdc15688708623367e358" dependencies = [ "proc-macro2", "quote", - "syn 2.0.108", + "syn 2.0.109", ] [[package]] @@ -11245,7 +11230,7 @@ checksum = "b659052874eb698efe5b9e8cf382204678a0086ebf46982b79d6ca3182927e5d" dependencies = [ "proc-macro2", "quote", - "syn 2.0.108", + "syn 2.0.109", "synstructure", ] @@ -11292,7 +11277,7 @@ dependencies = [ "proc-macro-crate", "proc-macro2", "quote", - "syn 2.0.108", + "syn 2.0.109", "zbus_names", "zvariant", "zvariant_utils", @@ -11327,7 +11312,7 @@ checksum = "88d2b8d9c68ad2b9e4340d7832716a4d21a22a1154777ad56ea55c51a9cf3831" dependencies = [ "proc-macro2", "quote", - "syn 2.0.108", + "syn 2.0.109", ] [[package]] @@ -11347,7 +11332,7 @@ checksum = "d71e5d6e06ab090c67b5e44993ec16b72dcbaabc526db883a360057678b48502" dependencies = [ "proc-macro2", "quote", - "syn 2.0.108", + "syn 2.0.109", "synstructure", ] @@ -11368,7 +11353,7 @@ checksum = "ce36e65b0d2999d2aafac989fb249189a141aee1f53c612c1f37d72631959f69" dependencies = [ "proc-macro2", "quote", - "syn 2.0.108", + "syn 2.0.109", ] [[package]] @@ -11402,7 +11387,7 @@ checksum = "eadce39539ca5cb3985590102671f2567e659fca9666581ad3411d59207951f3" dependencies = [ "proc-macro2", "quote", - "syn 2.0.108", + "syn 2.0.109", ] [[package]] @@ -11456,7 +11441,7 @@ dependencies = [ "proc-macro-crate", "proc-macro2", "quote", - "syn 2.0.108", + "syn 2.0.109", "zvariant_utils", ] @@ -11469,6 +11454,6 @@ dependencies = [ "proc-macro2", "quote", "serde", - "syn 2.0.108", + "syn 2.0.109", "winnow", ] diff --git a/core/startos/Cargo.toml b/core/startos/Cargo.toml index c3ccdbb9d..2296e7ac5 100644 --- a/core/startos/Cargo.toml +++ b/core/startos/Cargo.toml @@ -280,7 +280,7 @@ tracing-error = "0.2.0" tracing-futures = "0.2.5" tracing-journald = "0.3.0" tracing-subscriber = { version = "0.3.17", features = ["env-filter"] } -ts-rs = "9.0.1" +ts-rs = { version = "9.0.1", features = ["chrono-impl"] } typed-builder = "0.21.0" unix-named-pipe = "0.2.0" url = { version = "2.4.1", features = ["serde"] } diff --git a/core/startos/src/auth.rs b/core/startos/src/auth.rs index c4ef42475..ad05b3d37 100644 --- a/core/startos/src/auth.rs +++ b/core/startos/src/auth.rs @@ -149,14 +149,6 @@ where .no_display() .with_about("Reset password"), ) - .subcommand( - "get-pubkey", - from_fn_async(get_pubkey) - .with_metadata("authenticated", Value::Bool(false)) - .no_display() - .with_about("Get public key derived from server private key") - .with_call_remote::(), - ) } #[test] @@ -395,7 +387,7 @@ pub async fn list( }) } -#[derive(Debug, Clone, Serialize, Deserialize)] +#[derive(Debug, Clone, Serialize, Deserialize, TS)] struct KillSessionId(InternedString); impl KillSessionId { diff --git a/core/startos/src/backup/target/cifs.rs b/core/startos/src/backup/target/cifs.rs index 350e53220..edab29549 100644 --- a/core/startos/src/backup/target/cifs.rs +++ b/core/startos/src/backup/target/cifs.rs @@ -36,7 +36,7 @@ impl Map for CifsTargets { } } -#[derive(Debug, Deserialize, Serialize)] +#[derive(Debug, Deserialize, Serialize, TS)] #[serde(rename_all = "camelCase")] pub struct CifsBackupTarget { hostname: String, diff --git a/core/startos/src/backup/target/mod.rs b/core/startos/src/backup/target/mod.rs index 3eb37e12e..2446cba6c 100644 --- a/core/startos/src/backup/target/mod.rs +++ b/core/startos/src/backup/target/mod.rs @@ -34,11 +34,11 @@ use crate::util::serde::{ pub mod cifs; -#[derive(Debug, Deserialize, Serialize)] +#[derive(Debug, Deserialize, Serialize, TS)] #[serde(tag = "type")] #[serde(rename_all = "camelCase")] +#[serde(rename_all_fields = "camelCase")] pub enum BackupTarget { - #[serde(rename_all = "camelCase")] Disk { vendor: Option, model: Option, @@ -210,19 +210,21 @@ pub async fn list(ctx: RpcContext) -> Result>, pub package_backups: BTreeMap, } -#[derive(Clone, Debug, Deserialize, Serialize)] +#[derive(Clone, Debug, Deserialize, Serialize, TS)] #[serde(rename_all = "camelCase")] pub struct PackageBackupInfo { pub title: InternedString, pub version: VersionString, + #[ts(type = "string")] pub os_version: Version, pub timestamp: DateTime, } diff --git a/core/startos/src/db/mod.rs b/core/startos/src/db/mod.rs index aad28d1eb..1c78d30fb 100644 --- a/core/startos/src/db/mod.rs +++ b/core/startos/src/db/mod.rs @@ -1,7 +1,6 @@ pub mod model; pub mod prelude; -use std::panic::UnwindSafe; use std::path::PathBuf; use std::sync::Arc; use std::time::Duration; @@ -56,9 +55,18 @@ pub fn db() -> ParentHandler { "dump", from_fn_async(cli_dump) .with_display_serializable() + .no_ts() .with_about("Filter/query db to display tables and records"), ) - .subcommand("dump", from_fn_async(dump).no_cli()) + .subcommand( + "dump", + from_fn_async(dump) + .custom_ts( + DumpParams::inline(), + format!("{{ id: number; value: unknown }}"), + ) + .no_cli(), + ) .subcommand( "subscribe", from_fn_async(subscribe) @@ -73,6 +81,7 @@ pub fn db() -> ParentHandler { "apply", from_fn_async(cli_apply) .no_display() + .no_ts() .with_about("Update a db record"), ) .subcommand("apply", from_fn_async(apply).no_cli()) diff --git a/core/startos/src/db/prelude.rs b/core/startos/src/db/prelude.rs index f45d051cc..9ca704ebd 100644 --- a/core/startos/src/db/prelude.rs +++ b/core/startos/src/db/prelude.rs @@ -10,6 +10,7 @@ use patch_db::value::InternedString; pub use patch_db::{HasModel, MutateResult, PatchDb}; use serde::de::DeserializeOwned; use serde::{Deserialize, Serialize}; +use ts_rs::TS; use crate::prelude::*; @@ -479,6 +480,24 @@ impl<'de, T: DeserializeOwned> Deserialize<'de> for JsonKey { )) } } +impl TS for JsonKey { + type WithoutGenerics = JsonKey; + fn decl() -> String { + format!("type {} = string", Self::name()) + } + fn decl_concrete() -> String { + Self::decl() + } + fn name() -> String { + "JsonKey".into() + } + fn inline() -> String { + "string".into() + } + fn inline_flattened() -> String { + Self::inline() + } +} #[derive(Debug, Clone, Deserialize, Serialize)] pub struct WithTimeData { diff --git a/core/startos/src/diagnostic.rs b/core/startos/src/diagnostic.rs index 820d05512..5071043e7 100644 --- a/core/startos/src/diagnostic.rs +++ b/core/startos/src/diagnostic.rs @@ -28,6 +28,7 @@ pub fn diagnostic() -> ParentHandler { "logs", from_fn_async(crate::logs::cli_logs::) .no_display() + .no_ts() .with_about("Display OS logs"), ) .subcommand( @@ -38,6 +39,7 @@ pub fn diagnostic() -> ParentHandler { "kernel-logs", from_fn_async(crate::logs::cli_logs::) .no_display() + .no_ts() .with_about("Display kernal logs"), ) .subcommand( diff --git a/core/startos/src/disk/fsck/mod.rs b/core/startos/src/disk/fsck/mod.rs index 1c6949138..58d9a7942 100644 --- a/core/startos/src/disk/fsck/mod.rs +++ b/core/startos/src/disk/fsck/mod.rs @@ -2,6 +2,7 @@ use std::path::Path; use color_eyre::eyre::eyre; use tokio::process::Command; +use ts_rs::TS; use crate::Error; use crate::disk::fsck::btrfs::{btrfs_check_readonly, btrfs_check_repair}; @@ -11,7 +12,7 @@ use crate::util::Invoke; pub mod btrfs; pub mod ext4; -#[derive(Debug, Clone, Copy, serde::Serialize, serde::Deserialize)] +#[derive(Debug, Clone, Copy, serde::Serialize, serde::Deserialize, TS)] #[must_use] pub struct RequiresReboot(pub bool); impl std::ops::BitOrAssign for RequiresReboot { diff --git a/core/startos/src/disk/util.rs b/core/startos/src/disk/util.rs index a6b5bea39..e2f2adca0 100644 --- a/core/startos/src/disk/util.rs +++ b/core/startos/src/disk/util.rs @@ -13,6 +13,7 @@ use regex::Regex; use serde::{Deserialize, Serialize}; use tokio::process::Command; use tracing::instrument; +use ts_rs::TS; use super::mount::filesystem::ReadOnly; use super::mount::filesystem::block_dev::BlockDev; @@ -24,14 +25,14 @@ use crate::util::Invoke; use crate::util::serde::IoFormat; use crate::{Error, ResultExt as _}; -#[derive(Clone, Copy, Debug, Deserialize, Serialize)] -#[serde(rename_all = "camelCase")] +#[derive(Clone, Copy, Debug, Deserialize, Serialize, TS)] +#[serde(rename_all = "kebab-case")] pub enum PartitionTable { Mbr, Gpt, } -#[derive(Clone, Debug, Deserialize, Serialize)] +#[derive(Clone, Debug, Deserialize, Serialize, TS)] #[serde(rename_all = "camelCase")] pub struct DiskInfo { pub logicalname: PathBuf, @@ -43,7 +44,7 @@ pub struct DiskInfo { pub guid: Option, } -#[derive(Clone, Debug, Deserialize, Serialize)] +#[derive(Clone, Debug, Deserialize, Serialize, TS)] #[serde(rename_all = "camelCase")] pub struct PartitionInfo { pub logicalname: PathBuf, @@ -54,10 +55,11 @@ pub struct PartitionInfo { pub guid: Option, } -#[derive(Clone, Debug, Default, Deserialize, Serialize)] +#[derive(Clone, Debug, Default, Deserialize, Serialize, TS)] #[serde(rename_all = "camelCase")] pub struct StartOsRecoveryInfo { pub hostname: Hostname, + #[ts(type = "string")] pub version: exver::Version, pub timestamp: DateTime, pub password_hash: Option, diff --git a/core/startos/src/hostname.rs b/core/startos/src/hostname.rs index 5c88bdcec..c39e73358 100644 --- a/core/startos/src/hostname.rs +++ b/core/startos/src/hostname.rs @@ -1,12 +1,14 @@ use imbl_value::InternedString; use lazy_format::lazy_format; use rand::{Rng, rng}; +use serde::{Deserialize, Serialize}; use tokio::process::Command; use tracing::instrument; +use ts_rs::TS; use crate::util::Invoke; use crate::{Error, ErrorKind}; -#[derive(Clone, Debug, Default, serde::Deserialize, serde::Serialize)] +#[derive(Clone, Debug, Default, Deserialize, Serialize, TS)] pub struct Hostname(pub InternedString); lazy_static::lazy_static! { diff --git a/core/startos/src/init.rs b/core/startos/src/init.rs index 001dca911..5736c3b17 100644 --- a/core/startos/src/init.rs +++ b/core/startos/src/init.rs @@ -425,6 +425,7 @@ pub fn init_api() -> ParentHandler { "logs", from_fn_async(crate::logs::cli_logs::) .no_display() + .no_ts() .with_about("Display OS logs"), ) .subcommand( @@ -435,6 +436,7 @@ pub fn init_api() -> ParentHandler { "kernel-logs", from_fn_async(crate::logs::cli_logs::) .no_display() + .no_ts() .with_about("Display kernel logs"), ) .subcommand("subscribe", from_fn_async(init_progress).no_cli()) diff --git a/core/startos/src/lib.rs b/core/startos/src/lib.rs index 7b0d83e1f..ec7fb46f0 100644 --- a/core/startos/src/lib.rs +++ b/core/startos/src/lib.rs @@ -277,7 +277,7 @@ pub fn server() -> ParentHandler { ) .subcommand( "logs", - from_fn_async(logs::cli_logs::).no_display().with_about("Display OS logs"), + from_fn_async(logs::cli_logs::).no_display().no_ts().with_about("Display OS logs"), ) .subcommand( "kernel-logs", @@ -285,7 +285,7 @@ pub fn server() -> ParentHandler { ) .subcommand( "kernel-logs", - from_fn_async(logs::cli_logs::).no_display().with_about("Display Kernel logs"), + from_fn_async(logs::cli_logs::).no_display().no_ts().with_about("Display Kernel logs"), ) .subcommand( "metrics", @@ -297,7 +297,7 @@ pub fn server() -> ParentHandler { .with_call_remote::() ) .subcommand( - "follow", + "follow", from_fn_async(system::metrics_follow) .no_cli() ) @@ -394,6 +394,7 @@ pub fn package() -> ParentHandler { "install", from_fn_async_local(install::cli_install) .no_display() + .no_ts() .with_about("Install a package from a marketplace or via sideloading"), ) .subcommand( @@ -497,7 +498,6 @@ pub fn package() -> ParentHandler { .with_about("List information related to the lxc containers i.e. CPU, Memory, Disk") .with_call_remote::(), ) - .subcommand("logs", logs::package_logs()) .subcommand( "logs", logs::package_logs().with_about("Display package logs"), @@ -506,6 +506,7 @@ pub fn package() -> ParentHandler { "logs", from_fn_async(logs::cli_logs::) .no_display() + .no_ts() .with_about("Display package logs"), ) .subcommand( @@ -520,7 +521,16 @@ pub fn package() -> ParentHandler { .with_about("Execute commands within a service container") .no_cli(), ) - .subcommand("attach", from_fn_async(service::cli_attach).no_display()) + .subcommand( + "attach", + from_fn_async(service::cli_attach).no_display().no_ts(), + ) + .subcommand( + "list-subcontainers", + from_fn_async(service::list_subcontainers) + .with_about("List all subcontainers for a package") + .no_cli(), + ) .subcommand( "host", net::host::host_api::().with_about("Manage network hosts for a package"), diff --git a/core/startos/src/logs.rs b/core/startos/src/logs.rs index 15bf31ebe..73a3e2936 100644 --- a/core/startos/src/logs.rs +++ b/core/startos/src/logs.rs @@ -24,6 +24,7 @@ use tokio::process::{Child, Command}; use tokio_stream::wrappers::LinesStream; use tokio_tungstenite::tungstenite::Message; use tracing::instrument; +use ts_rs::TS; use crate::context::{CliContext, RpcContext}; use crate::error::ResultExt; @@ -109,21 +110,21 @@ async fn ws_handler( } } -#[derive(serde::Serialize, serde::Deserialize, Debug, Clone)] +#[derive(serde::Serialize, serde::Deserialize, Debug, Clone, TS)] #[serde(rename_all = "camelCase")] pub struct LogResponse { pub entries: Reversible, start_cursor: Option, end_cursor: Option, } -#[derive(serde::Serialize, serde::Deserialize, Debug, Clone)] +#[derive(serde::Serialize, serde::Deserialize, Debug, Clone, TS)] #[serde(rename_all = "camelCase")] pub struct LogFollowResponse { start_cursor: Option, guid: Guid, } -#[derive(serde::Serialize, serde::Deserialize, Debug, Clone)] +#[derive(serde::Serialize, serde::Deserialize, Debug, Clone, TS)] #[serde(rename_all = "camelCase")] pub struct LogEntry { timestamp: DateTime, @@ -142,7 +143,7 @@ impl std::fmt::Display for LogEntry { } } -#[derive(Serialize, Deserialize, Debug)] +#[derive(Serialize, Deserialize, Debug, TS)] pub struct JournalctlEntry { #[serde(rename = "__REALTIME_TIMESTAMP")] pub timestamp: String, @@ -228,14 +229,15 @@ pub enum LogSource { pub const SYSTEM_UNIT: &str = "startd"; -#[derive(Deserialize, Serialize, Parser)] +#[derive(Deserialize, Serialize, Parser, TS)] #[serde(rename_all = "camelCase")] #[command(rename_all = "kebab-case")] pub struct PackageIdParams { id: PackageId, } -#[derive(Debug, Clone)] +#[derive(Debug, Clone, TS)] +#[ts(type = "number | string")] pub enum BootIdentifier { Index(i32), Id(String), @@ -320,10 +322,10 @@ impl From for String { } } -#[derive(Deserialize, Serialize, Parser)] +#[derive(Deserialize, Serialize, Parser, TS)] #[serde(rename_all = "camelCase")] #[command(rename_all = "kebab-case")] -pub struct LogsParams { +pub struct LogsParams { #[command(flatten)] #[serde(flatten)] extra: Extra, @@ -354,7 +356,7 @@ pub struct CliLogsParams { #[allow(private_bounds)] pub fn logs< C: Context + AsRef, - Extra: FromArgMatches + Serialize + DeserializeOwned + Args + Send + Sync + 'static, + Extra: FromArgMatches + Serialize + DeserializeOwned + Args + TS + Send + Sync + 'static, >( source: impl for<'a> LogSourceFn<'a, C, Extra>, ) -> ParentHandler> { @@ -379,7 +381,7 @@ pub async fn cli_logs( ) -> Result<(), RpcError> where CliContext: CallRemote, - Extra: FromArgMatches + Args + Serialize + Send + Sync, + Extra: FromArgMatches + Args + TS + Serialize + Send + Sync, { let method = parent_method .into_iter() @@ -434,7 +436,7 @@ fn logs_nofollow( ) -> impl HandlerFor, InheritedParams = Empty, Ok = LogResponse, Err = Error> where C: Context, - Extra: FromArgMatches + Args + Send + Sync + 'static, + Extra: FromArgMatches + Args + TS + Send + Sync + 'static, { from_fn_async( move |HandlerArgs { @@ -466,7 +468,7 @@ where fn logs_follow< C: Context + AsRef, - Extra: FromArgMatches + Args + Send + Sync + 'static, + Extra: FromArgMatches + Args + TS + Send + Sync + 'static, >( f: impl for<'a> LogSourceFn<'a, C, Extra>, ) -> impl HandlerFor< diff --git a/core/startos/src/middleware/auth.rs b/core/startos/src/middleware/auth.rs index 3d2d7679e..2f2f5d9e8 100644 --- a/core/startos/src/middleware/auth.rs +++ b/core/startos/src/middleware/auth.rs @@ -24,6 +24,7 @@ use sha2::Sha256; use tokio::io::AsyncWriteExt; use tokio::process::Command; use tokio::sync::Mutex; +use ts_rs::TS; use crate::auth::{Sessions, check_password, write_shadow}; use crate::context::RpcContext; @@ -89,7 +90,7 @@ impl AuthContext for RpcContext { } } -#[derive(Deserialize, Serialize)] +#[derive(Deserialize, Serialize, TS)] #[serde(rename_all = "camelCase")] pub struct LoginRes { pub session: InternedString, @@ -100,7 +101,7 @@ pub trait AsLogoutSessionId { } /// Will need to know when we have logged out from a route -#[derive(Serialize, Deserialize)] +#[derive(Serialize, Deserialize, TS)] pub struct HasLoggedOutSessions(()); impl HasLoggedOutSessions { diff --git a/core/startos/src/net/acme.rs b/core/startos/src/net/acme.rs index 857ec3e65..02c451213 100644 --- a/core/startos/src/net/acme.rs +++ b/core/startos/src/net/acme.rs @@ -460,7 +460,7 @@ impl ValueParserFactory for AcmeProvider { } } -#[derive(Deserialize, Serialize, Parser)] +#[derive(Deserialize, Serialize, Parser, TS)] pub struct InitAcmeParams { #[arg(long)] pub provider: AcmeProvider, @@ -485,7 +485,7 @@ pub async fn init( Ok(()) } -#[derive(Deserialize, Serialize, Parser)] +#[derive(Deserialize, Serialize, Parser, TS)] pub struct RemoveAcmeParams { #[arg(long)] pub provider: AcmeProvider, diff --git a/core/startos/src/net/dns.rs b/core/startos/src/net/dns.rs index fac1249cd..5c4909f07 100644 --- a/core/startos/src/net/dns.rs +++ b/core/startos/src/net/dns.rs @@ -32,6 +32,7 @@ use rpc_toolkit::{ use serde::{Deserialize, Serialize}; use tokio::net::{TcpListener, UdpSocket}; use tracing::instrument; +use ts_rs::TS; use crate::context::{CliContext, RpcContext}; use crate::db::model::Database; @@ -99,7 +100,7 @@ pub fn dns_api() -> ParentHandler { ) } -#[derive(Deserialize, Serialize, Parser)] +#[derive(Deserialize, Serialize, Parser, TS)] pub struct QueryDnsParams { pub fqdn: InternedString, } @@ -138,7 +139,7 @@ pub fn query_dns( .map_err(Error::from) } -#[derive(Deserialize, Serialize, Parser)] +#[derive(Deserialize, Serialize, Parser, TS)] pub struct SetStaticDnsParams { pub servers: Option>, } diff --git a/core/startos/src/net/forward.rs b/core/startos/src/net/forward.rs index d02c8d1af..d97928cef 100644 --- a/core/startos/src/net/forward.rs +++ b/core/startos/src/net/forward.rs @@ -13,6 +13,7 @@ use rpc_toolkit::{Context, HandlerArgs, HandlerExt, ParentHandler, from_fn_async use serde::{Deserialize, Serialize}; use tokio::process::Command; use tokio::sync::mpsc; +use ts_rs::TS; use crate::context::{CliContext, RpcContext}; use crate::db::model::public::NetworkInterfaceInfo; @@ -448,10 +449,10 @@ fn err_has_exited(_: T) -> Error { ) } -#[derive(Debug, Clone, Deserialize, Serialize)] +#[derive(Debug, Clone, Deserialize, Serialize, TS)] pub struct ForwardTable(pub BTreeMap); -#[derive(Debug, Clone, Deserialize, Serialize)] +#[derive(Debug, Clone, Deserialize, Serialize, TS)] pub struct ForwardTarget { pub target: SocketAddrV4, pub filter: String, diff --git a/core/startos/src/net/gateway.rs b/core/startos/src/net/gateway.rs index 2db91cd70..012ff3aee 100644 --- a/core/startos/src/net/gateway.rs +++ b/core/startos/src/net/gateway.rs @@ -51,6 +51,7 @@ pub fn gateway_api() -> ParentHandler { .subcommand( "list", from_fn_async(list_interfaces) + .custom_ts("{}".into(), BTreeMap::::inline()) .with_display_serializable() .with_custom_display_fn(|HandlerArgs { params, .. }, res| { use prettytable::*; diff --git a/core/startos/src/net/host/address.rs b/core/startos/src/net/host/address.rs index 6d7723a23..6b375df8d 100644 --- a/core/startos/src/net/host/address.rs +++ b/core/startos/src/net/host/address.rs @@ -16,7 +16,7 @@ use crate::net::tor::OnionAddress; use crate::prelude::*; use crate::util::serde::{HandlerExtSerde, display_serializable}; -#[derive(Clone, Debug, Deserialize, Serialize)] +#[derive(Clone, Debug, Deserialize, Serialize, TS)] #[serde(rename_all = "kebab-case")] #[serde(rename_all_fields = "camelCase")] #[serde(tag = "kind")] @@ -235,7 +235,7 @@ pub fn address_api() ) } -#[derive(Deserialize, Serialize, Parser)] +#[derive(Deserialize, Serialize, Parser, TS)] pub struct AddPublicDomainParams { pub fqdn: InternedString, #[arg(long)] @@ -282,7 +282,7 @@ pub async fn add_public_domain( .with_kind(ErrorKind::Unknown)? } -#[derive(Deserialize, Serialize, Parser)] +#[derive(Deserialize, Serialize, Parser, TS)] pub struct RemoveDomainParams { pub fqdn: InternedString, } @@ -305,7 +305,7 @@ pub async fn remove_public_domain( Ok(()) } -#[derive(Deserialize, Serialize, Parser)] +#[derive(Deserialize, Serialize, Parser, TS)] pub struct AddPrivateDomainParams { pub fqdn: InternedString, } @@ -347,7 +347,7 @@ pub async fn remove_private_domain( Ok(()) } -#[derive(Deserialize, Serialize, Parser)] +#[derive(Deserialize, Serialize, Parser, TS)] pub struct OnionParams { pub onion: String, } diff --git a/core/startos/src/net/host/mod.rs b/core/startos/src/net/host/mod.rs index c5e6388eb..d2c21d0bd 100644 --- a/core/startos/src/net/host/mod.rs +++ b/core/startos/src/net/host/mod.rs @@ -164,12 +164,12 @@ impl Model { } } -#[derive(Deserialize, Serialize, Parser)] +#[derive(Deserialize, Serialize, Parser, TS)] pub struct RequiresPackageId { package: PackageId, } -#[derive(Deserialize, Serialize, Parser)] +#[derive(Deserialize, Serialize, Parser, TS)] pub struct RequiresHostId { host: HostId, } diff --git a/core/startos/src/net/ssl.rs b/core/startos/src/net/ssl.rs index baa18c2e3..d3a5f8d1c 100644 --- a/core/startos/src/net/ssl.rs +++ b/core/startos/src/net/ssl.rs @@ -240,12 +240,16 @@ impl CertPair { } } -pub async fn root_ca_start_time() -> Result { - Ok(if check_time_is_synchronized().await? { +pub async fn root_ca_start_time() -> SystemTime { + if check_time_is_synchronized() + .await + .log_err() + .unwrap_or(false) + { SystemTime::now() } else { *SOURCE_DATE - }) + } } const EC_CURVE_NAME: nid::Nid = nid::Nid::X9_62_PRIME256V1; diff --git a/core/startos/src/net/tor/arti.rs b/core/startos/src/net/tor/arti.rs index 1cfe7cfb1..6d09e40d1 100644 --- a/core/startos/src/net/tor/arti.rs +++ b/core/startos/src/net/tor/arti.rs @@ -357,7 +357,7 @@ pub fn display_services( Ok(()) } -#[derive(Debug, Serialize, Deserialize)] +#[derive(Debug, Serialize, Deserialize, TS)] #[serde(rename_all = "kebab-case")] pub enum OnionServiceState { Shutdown, @@ -383,7 +383,7 @@ impl From for OnionServiceState { } } -#[derive(Debug, Serialize, Deserialize)] +#[derive(Debug, Serialize, Deserialize, TS)] #[serde(rename_all = "camelCase")] pub struct OnionServiceInfo { pub state: OnionServiceState, diff --git a/core/startos/src/net/tor/ctor.rs b/core/startos/src/net/tor/ctor.rs index 83011bd36..6456f8422 100644 --- a/core/startos/src/net/tor/ctor.rs +++ b/core/startos/src/net/tor/ctor.rs @@ -45,7 +45,8 @@ const TOR_CONTROL: SocketAddr = SocketAddr::V4(SocketAddrV4::new(Ipv4Addr::new(127, 0, 1, 1), 9051)); const TOR_SOCKS: SocketAddr = SocketAddr::V4(SocketAddrV4::new(Ipv4Addr::new(127, 0, 1, 1), 9050)); -#[derive(Debug, Clone, Copy, PartialEq, Eq)] +#[derive(Debug, Clone, Copy, PartialEq, Eq, TS)] +#[ts(type = "string")] pub struct OnionAddress(OnionAddressV3); impl std::fmt::Display for OnionAddress { fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { @@ -255,6 +256,7 @@ pub fn tor_api() -> ParentHandler { "logs", from_fn_async(crate::logs::cli_logs::) .no_display() + .no_ts() .with_about("Display Tor logs"), ) .subcommand( @@ -312,7 +314,7 @@ pub async fn generate_key(ctx: RpcContext) -> Result { .result } -#[derive(Deserialize, Serialize, Parser)] +#[derive(Deserialize, Serialize, Parser, TS)] pub struct AddKeyParams { pub key: Base64<[u8; 64]>, } diff --git a/core/startos/src/net/vhost.rs b/core/startos/src/net/vhost.rs index 80c3325fd..58308296b 100644 --- a/core/startos/src/net/vhost.rs +++ b/core/startos/src/net/vhost.rs @@ -134,7 +134,6 @@ impl VHostController { pub fn dump_table( &self, ) -> BTreeMap, BTreeMap>, EqSet>> { - let ip_info = self.interfaces.watcher.ip_info(); self.servers.peek(|s| { s.iter() .map(|(k, v)| { diff --git a/core/startos/src/net/wifi.rs b/core/startos/src/net/wifi.rs index 6d6774998..ef6c8071f 100644 --- a/core/startos/src/net/wifi.rs +++ b/core/startos/src/net/wifi.rs @@ -343,22 +343,23 @@ pub async fn remove(ctx: RpcContext, SsidParams { ssid }: SsidParams) -> Result< .result?; Ok(()) } -#[derive(serde::Serialize, serde::Deserialize)] +#[derive(serde::Serialize, serde::Deserialize, TS)] #[serde(rename_all = "camelCase")] pub struct WifiListInfo { ssids: HashMap, connected: Option, + #[ts(type = "sttring | null")] country: Option, ethernet: bool, available_wifi: Vec, } -#[derive(serde::Serialize, serde::Deserialize, Clone)] +#[derive(serde::Serialize, serde::Deserialize, Clone, TS)] #[serde(rename_all = "camelCase")] pub struct WifiListInfoLow { strength: SignalStrength, security: Vec, } -#[derive(serde::Serialize, serde::Deserialize)] +#[derive(serde::Serialize, serde::Deserialize, TS)] #[serde(rename_all = "camelCase")] pub struct WifiListOut { ssid: Ssid, @@ -589,7 +590,7 @@ pub struct NetworkId(String); /// Ssid are the names of the wifis, usually human readable. #[derive( - Clone, Debug, PartialEq, Eq, PartialOrd, Ord, Hash, serde::Serialize, serde::Deserialize, + Clone, Debug, PartialEq, Eq, PartialOrd, Ord, Hash, serde::Serialize, serde::Deserialize, TS, )] pub struct Ssid(String); @@ -606,6 +607,7 @@ pub struct Ssid(String); Hash, serde::Serialize, serde::Deserialize, + TS, )] pub struct SignalStrength(u8); diff --git a/core/startos/src/notifications.rs b/core/startos/src/notifications.rs index cbbea5da6..27ca60b90 100644 --- a/core/startos/src/notifications.rs +++ b/core/startos/src/notifications.rs @@ -388,7 +388,7 @@ impl Map for Notifications { } } -#[derive(Debug, Serialize, Deserialize, HasModel)] +#[derive(Debug, Serialize, Deserialize, HasModel, TS)] #[serde(rename_all = "camelCase")] #[model = "Model"] pub struct Notification { @@ -403,7 +403,7 @@ pub struct Notification { pub seen: bool, } -#[derive(Debug, Serialize, Deserialize)] +#[derive(Debug, Serialize, Deserialize, TS)] #[serde(rename_all = "camelCase")] pub struct NotificationWithId { id: u32, diff --git a/core/startos/src/registry/admin.rs b/core/startos/src/registry/admin.rs index e28397b5a..38a141e09 100644 --- a/core/startos/src/registry/admin.rs +++ b/core/startos/src/registry/admin.rs @@ -32,6 +32,7 @@ pub fn admin_api() -> ParentHandler { "add", from_fn_async(cli_add_admin) .no_display() + .no_ts() .with_about("Add admin signer"), ) .subcommand( @@ -72,7 +73,7 @@ fn signers_api() -> ParentHandler { ) .subcommand( "add", - from_fn_async(cli_add_signer).with_about("Add signer"), + from_fn_async(cli_add_signer).no_ts().with_about("Add signer"), ) .subcommand( "edit", diff --git a/core/startos/src/registry/db.rs b/core/startos/src/registry/db.rs index 3c3da4c12..316adfaef 100644 --- a/core/startos/src/registry/db.rs +++ b/core/startos/src/registry/db.rs @@ -22,18 +22,24 @@ pub fn db_api() -> ParentHandler { "dump", from_fn_async(cli_dump) .with_display_serializable() + .no_ts() .with_about("Filter/query db to display tables and records"), ) .subcommand( "dump", from_fn_async(dump) .with_metadata("admin", Value::Bool(true)) - .no_cli(), + .no_cli() + .custom_ts( + DumpParams::inline(), + format!("{{ id: number; value: unknown }}"), + ), ) .subcommand( "apply", from_fn_async(cli_apply) .no_display() + .no_ts() .with_about("Update a db record"), ) .subcommand( diff --git a/core/startos/src/registry/mod.rs b/core/startos/src/registry/mod.rs index 11fe2b807..4bae32d14 100644 --- a/core/startos/src/registry/mod.rs +++ b/core/startos/src/registry/mod.rs @@ -11,7 +11,6 @@ use crate::context::CliContext; use crate::middleware::cors::Cors; use crate::middleware::signature::SignatureAuth; use crate::net::static_server::{bad_request, not_found, server_error}; -use crate::net::web_server::{Accept, WebServer}; use crate::prelude::*; use crate::registry::context::RegistryContext; use crate::registry::device_info::DeviceInfoMiddleware; diff --git a/core/startos/src/registry/os/asset/get.rs b/core/startos/src/registry/os/asset/get.rs index d3723c894..dfa656511 100644 --- a/core/startos/src/registry/os/asset/get.rs +++ b/core/startos/src/registry/os/asset/get.rs @@ -30,6 +30,7 @@ pub fn get_api() -> ParentHandler { "iso", from_fn_async(cli_get_os_asset) .no_display() + .no_ts() .with_about("Download iso"), ) .subcommand("img", from_fn_async(get_img).no_cli()) @@ -37,6 +38,7 @@ pub fn get_api() -> ParentHandler { "img", from_fn_async(cli_get_os_asset) .no_display() + .no_ts() .with_about("Download img"), ) .subcommand("squashfs", from_fn_async(get_squashfs).no_cli()) @@ -44,6 +46,7 @@ pub fn get_api() -> ParentHandler { "squashfs", from_fn_async(cli_get_os_asset) .no_display() + .no_ts() .with_about("Download squashfs"), ) } diff --git a/core/startos/src/registry/os/asset/mod.rs b/core/startos/src/registry/os/asset/mod.rs index 39b881128..febbe17bf 100644 --- a/core/startos/src/registry/os/asset/mod.rs +++ b/core/startos/src/registry/os/asset/mod.rs @@ -11,6 +11,7 @@ pub fn asset_api() -> ParentHandler { "add", from_fn_async(add::cli_add_asset) .no_display() + .no_ts() .with_about("Add asset to registry"), ) .subcommand("remove", add::remove_api::()) @@ -19,6 +20,7 @@ pub fn asset_api() -> ParentHandler { "sign", from_fn_async(sign::cli_sign_asset) .no_display() + .no_ts() .with_about("Sign file and add to registry index"), ) // TODO: remove signature api diff --git a/core/startos/src/registry/os/version/mod.rs b/core/startos/src/registry/os/version/mod.rs index 29105d577..99a552af5 100644 --- a/core/startos/src/registry/os/version/mod.rs +++ b/core/startos/src/registry/os/version/mod.rs @@ -46,6 +46,10 @@ pub fn version_api() -> ParentHandler { "get", from_fn_async(get_version) .with_metadata("get_device_info", Value::Bool(true)) + .custom_ts( + GetOsVersionParams::inline(), + BTreeMap::::inline(), + ) .with_display_serializable() .with_custom_display_fn(|handle, result| { display_version_info(handle.params, result) diff --git a/core/startos/src/registry/package/mod.rs b/core/startos/src/registry/package/mod.rs index db9059a7f..77db591c6 100644 --- a/core/startos/src/registry/package/mod.rs +++ b/core/startos/src/registry/package/mod.rs @@ -29,6 +29,7 @@ pub fn package_api() -> ParentHandler { "add", from_fn_async(add::cli_add_package) .no_display() + .no_ts() .with_about("Add package to registry index"), ) .subcommand( diff --git a/core/startos/src/s9pk/rpc.rs b/core/startos/src/s9pk/rpc.rs index eced48e97..c979d3c5d 100644 --- a/core/startos/src/s9pk/rpc.rs +++ b/core/startos/src/s9pk/rpc.rs @@ -25,11 +25,13 @@ pub fn s9pk() -> ParentHandler { "pack", from_fn_async(super::v2::pack::pack) .no_display() + .no_ts() .with_about("Package s9pk input files into valid s9pk"), ) .subcommand( "list-ingredients", from_fn_async(super::v2::pack::list_ingredients) + .no_ts() .with_custom_display_fn(|_, ingredients| { ingredients .into_iter() @@ -49,16 +51,17 @@ pub fn s9pk() -> ParentHandler { ) .subcommand( "edit", - edit().with_about("Commands to add an image to an s9pk or edit the manifest"), + edit().no_ts().with_about("Commands to add an image to an s9pk or edit the manifest"), ) .subcommand( "inspect", - inspect().with_about("Commands to display file paths, file contents, or manifest"), + inspect().no_ts().with_about("Commands to display file paths, file contents, or manifest"), ) .subcommand( "convert", from_fn_async(convert) .no_display() + .no_ts() .with_about("Convert s9pk from v1 to v2"), ) } diff --git a/core/startos/src/service/effects/mod.rs b/core/startos/src/service/effects/mod.rs index eb2a52bc9..f4caaf167 100644 --- a/core/startos/src/service/effects/mod.rs +++ b/core/startos/src/service/effects/mod.rs @@ -96,16 +96,23 @@ pub fn handler() -> ParentHandler { ParentHandler::::new() .subcommand( "launch", - from_fn_blocking(subcontainer::launch).no_display(), + from_fn_blocking(subcontainer::launch).no_display().no_ts(), ) .subcommand( "launch-init", - from_fn_blocking(subcontainer::launch_init).no_display(), + from_fn_blocking(subcontainer::launch_init) + .no_display() + .no_ts(), + ) + .subcommand( + "exec", + from_fn_blocking(subcontainer::exec).no_display().no_ts(), ) - .subcommand("exec", from_fn_blocking(subcontainer::exec).no_display()) .subcommand( "exec-command", - from_fn_blocking(subcontainer::exec_command).no_display(), + from_fn_blocking(subcontainer::exec_command) + .no_display() + .no_ts(), ) .subcommand( "create-fs", diff --git a/core/startos/src/setup.rs b/core/startos/src/setup.rs index b206119b9..1c67a8958 100644 --- a/core/startos/src/setup.rs +++ b/core/startos/src/setup.rs @@ -60,13 +60,14 @@ pub fn setup() -> ParentHandler { "get-pubkey", from_fn_async(get_pubkey) .with_metadata("authenticated", Value::Bool(false)) - .no_cli(), + .no_cli() + .custom_ts("{}".to_string(), "unknown".to_string()), ) .subcommand("exit", from_fn_async(exit).no_cli()) - .subcommand("logs", crate::system::logs::()) + .subcommand("logs", crate::system::logs::().no_ts()) .subcommand( "logs", - from_fn_async(crate::logs::cli_logs::).no_display(), + from_fn_async(crate::logs::cli_logs::).no_display().no_ts(), ) .subcommand("restart", from_fn_async(restart).no_cli()) } @@ -499,7 +500,7 @@ async fn fresh_setup( .. }: SetupExecuteProgress, ) -> Result<(SetupResult, RpcContext), Error> { - let account = AccountInfo::new(start_os_password, root_ca_start_time().await?)?; + let account = AccountInfo::new(start_os_password, root_ca_start_time().await)?; let db = ctx.db().await?; let kiosk = Some(kiosk.unwrap_or(true)).filter(|_| &*PLATFORM != "raspberrypi"); sync_kiosk(kiosk).await?; diff --git a/core/startos/src/ssh.rs b/core/startos/src/ssh.rs index c54989f37..a1ae55de9 100644 --- a/core/startos/src/ssh.rs +++ b/core/startos/src/ssh.rs @@ -59,7 +59,7 @@ impl ValueParserFactory for SshPubKey { } } -#[derive(serde::Serialize, serde::Deserialize)] +#[derive(serde::Serialize, serde::Deserialize, TS)] #[serde(rename_all = "camelCase")] pub struct SshKeyResponse { pub alg: String, diff --git a/core/startos/src/system.rs b/core/startos/src/system.rs index a76ca8641..45339b537 100644 --- a/core/startos/src/system.rs +++ b/core/startos/src/system.rs @@ -186,7 +186,7 @@ pub async fn governor( Ok(GovernorInfo { current, available }) } -#[derive(Serialize, Deserialize)] +#[derive(Serialize, Deserialize, TS)] pub struct TimeInfo { now: String, uptime: u64, @@ -319,8 +319,8 @@ pub fn kiosk() -> ParentHandler { ) } -#[derive(Serialize, Deserialize)] -pub struct MetricLeaf { +#[derive(Serialize, Deserialize, TS)] +pub struct MetricLeaf { value: T, unit: Option, } diff --git a/core/startos/src/tunnel/api.rs b/core/startos/src/tunnel/api.rs index e2e60ffe7..1e1fa507c 100644 --- a/core/startos/src/tunnel/api.rs +++ b/core/startos/src/tunnel/api.rs @@ -5,6 +5,7 @@ use imbl_value::InternedString; use ipnet::Ipv4Net; use rpc_toolkit::{Context, Empty, HandlerArgs, HandlerExt, ParentHandler, from_fn_async}; use serde::{Deserialize, Serialize}; +use ts_rs::TS; use crate::context::CliContext; use crate::prelude::*; @@ -54,9 +55,10 @@ pub fn tunnel_api() -> ParentHandler { ) } -#[derive(Deserialize, Serialize, Parser)] +#[derive(Deserialize, Serialize, Parser, TS)] #[serde(rename_all = "camelCase")] pub struct SubnetParams { + #[ts(type = "string")] subnet: Ipv4Net, } diff --git a/core/startos/src/tunnel/auth.rs b/core/startos/src/tunnel/auth.rs index 21482980f..16979c03a 100644 --- a/core/startos/src/tunnel/auth.rs +++ b/core/startos/src/tunnel/auth.rs @@ -240,7 +240,7 @@ pub async fn list_keys(ctx: TunnelContext) -> Result() -> ParentHandler { "dump", from_fn_async(cli_dump) .with_display_serializable() + .no_ts() .with_about("Filter/query db to display tables and records"), ) .subcommand( "dump", from_fn_async(dump) .with_metadata("admin", Value::Bool(true)) - .no_cli(), + .no_cli() + .custom_ts( + DumpParams::inline(), + format!("{{ id: number; value: unknown }}"), + ), ) .subcommand( "subscribe", @@ -87,6 +92,7 @@ pub fn db_api() -> ParentHandler { "apply", from_fn_async(cli_apply) .no_display() + .no_ts() .with_about("Update a db record"), ) .subcommand( diff --git a/core/startos/src/tunnel/web.rs b/core/startos/src/tunnel/web.rs index 6d77f4309..121b36a3e 100644 --- a/core/startos/src/tunnel/web.rs +++ b/core/startos/src/tunnel/web.rs @@ -1,9 +1,8 @@ use std::collections::VecDeque; -use std::net::{IpAddr, Ipv6Addr, SocketAddr}; +use std::net::{IpAddr, SocketAddr}; use std::sync::Arc; use clap::Parser; -use hickory_client::proto::rr::rdata::cert; use imbl_value::{InternedString, json}; use itertools::Itertools; use openssl::pkey::{PKey, Private}; @@ -12,7 +11,6 @@ use rpc_toolkit::{ Context, Empty, HandlerArgs, HandlerExt, ParentHandler, from_fn_async, from_fn_async_local, }; use serde::{Deserialize, Serialize}; -use tokio::io::{AsyncBufReadExt, BufReader}; use tokio_rustls::rustls::ServerConfig; use tokio_rustls::rustls::crypto::CryptoProvider; use tokio_rustls::rustls::pki_types::{CertificateDer, PrivateKeyDer, PrivatePkcs8KeyDer}; @@ -20,7 +18,8 @@ use tokio_rustls::rustls::server::ClientHello; use ts_rs::TS; use crate::context::CliContext; -use crate::net::ssl::SANInfo; +use crate::hostname::Hostname; +use crate::net::ssl::{SANInfo, root_ca_start_time}; use crate::net::tls::TlsHandler; use crate::net::web_server::Accept; use crate::prelude::*; @@ -134,7 +133,7 @@ pub fn web_api() -> ParentHandler { .subcommand( "generate-certificate", from_fn_async(generate_certificate) - .with_about("Generate a self signed certificaet to use for the webserver") + .with_about("Generate a certificate to use for the webserver") .with_call_remote::(), ) .subcommand( @@ -286,11 +285,21 @@ pub struct GenerateCertParams { pub async fn generate_certificate( ctx: TunnelContext, GenerateCertParams { subject }: GenerateCertParams, -) -> Result, Error> { +) -> Result>, Error> { let saninfo = SANInfo::new(&subject.into_iter().collect()); + let root_key = crate::net::ssl::generate_key()?; + let root_cert = crate::net::ssl::make_root_cert( + &root_key, + &Hostname("start-tunnel".into()), + root_ca_start_time().await, + )?; + let int_key = crate::net::ssl::generate_key()?; + let int_cert = crate::net::ssl::make_int_cert((&root_key, &root_cert), &int_key)?; + let key = crate::net::ssl::generate_key()?; - let cert = crate::net::ssl::make_self_signed((&key, &saninfo))?; + let cert = crate::net::ssl::make_leaf_cert((&int_key, &int_cert), (&key, &saninfo))?; + let chain = Pem(vec![cert, int_cert, root_cert]); ctx.db .mutate(|db| { @@ -298,13 +307,13 @@ pub async fn generate_certificate( .as_certificate_mut() .ser(&Some(TunnelCertData { key: Pem(key), - cert: Pem(vec![cert.clone()]), + cert: chain.clone(), })) }) .await .result?; - Ok(Pem(cert)) + Ok(chain) } pub async fn get_certificate(ctx: TunnelContext) -> Result>>, Error> { @@ -501,8 +510,12 @@ pub async fn init_web(ctx: CliContext) -> Result<(), Error> { let cert = from_value::>>( ctx.call_remote::("web.get-certificate", json!({})) .await?, - )?; - println!("📝 SSL Certificate:"); + )? + .0 + .pop() + .map(Pem) + .or_not_found("certificate in chain")?; + println!("📝 Root SSL Certificate:"); print!("{cert}"); println!(concat!( @@ -594,7 +607,7 @@ pub async fn init_web(ctx: CliContext) -> Result<(), Error> { impl std::fmt::Display for Choice { fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { match self { - Self::Generate => write!(f, "Generate a Self Signed Certificate"), + Self::Generate => write!(f, "Generate an SSL certificate"), Self::Provide => write!(f, "Provide your own certificate and key"), } } @@ -602,7 +615,7 @@ pub async fn init_web(ctx: CliContext) -> Result<(), Error> { let options = vec![Choice::Generate, Choice::Provide]; let choice = choose( concat!( - "Select whether to autogenerate a self-signed SSL certificate ", + "Select whether to generate an SSL certificate ", "or provide your own certificate and key:" ), &options, diff --git a/core/startos/src/tunnel/wg.rs b/core/startos/src/tunnel/wg.rs index 539a7438e..6ffa1340b 100644 --- a/core/startos/src/tunnel/wg.rs +++ b/core/startos/src/tunnel/wg.rs @@ -209,7 +209,7 @@ where }) } -#[derive(Clone, Serialize, Deserialize)] +#[derive(Clone, Serialize, Deserialize, TS)] pub struct ClientConfig { client_config: WgConfig, client_addr: Ipv4Addr, diff --git a/core/startos/src/update/mod.rs b/core/startos/src/update/mod.rs index 635ab59c1..633d8d04e 100644 --- a/core/startos/src/update/mod.rs +++ b/core/startos/src/update/mod.rs @@ -217,7 +217,7 @@ pub async fn cli_update_system( } /// What is the status of the updates? -#[derive(serde::Serialize, serde::Deserialize, Clone, Debug)] +#[derive(serde::Serialize, serde::Deserialize, Clone, Debug, TS)] #[serde(rename_all = "camelCase")] pub enum UpdateResult { NoUpdates, diff --git a/core/startos/src/util/collections/eq_set.rs b/core/startos/src/util/collections/eq_set.rs index 5ff4d3ba9..986b11efa 100644 --- a/core/startos/src/util/collections/eq_set.rs +++ b/core/startos/src/util/collections/eq_set.rs @@ -3,8 +3,9 @@ use std::fmt; use std::marker::PhantomData; use serde::{Deserialize, Serialize}; +use ts_rs::TS; -#[derive(Clone, Serialize)] +#[derive(Clone, Serialize, TS)] pub struct EqSet(Vec); impl Default for EqSet { fn default() -> Self { diff --git a/core/startos/src/util/rpc.rs b/core/startos/src/util/rpc.rs index 165632c5d..f2eac8039 100644 --- a/core/startos/src/util/rpc.rs +++ b/core/startos/src/util/rpc.rs @@ -3,6 +3,7 @@ use std::path::Path; use clap::Parser; use rpc_toolkit::{Context, HandlerExt, ParentHandler, from_fn_async}; use serde::{Deserialize, Serialize}; +use ts_rs::TS; use crate::CAP_10_MiB; use crate::context::CliContext; @@ -21,7 +22,7 @@ pub fn util() -> ParentHandler { ) } -#[derive(Debug, Deserialize, Serialize, Parser)] +#[derive(Debug, Deserialize, Serialize, Parser, TS)] pub struct B3sumParams { #[arg(long = "no-mmap", action = clap::ArgAction::SetFalse)] allow_mmap: bool, diff --git a/core/startos/src/util/serde.rs b/core/startos/src/util/serde.rs index 2b462e5fd..4f7636d96 100644 --- a/core/startos/src/util/serde.rs +++ b/core/startos/src/util/serde.rs @@ -12,7 +12,8 @@ use models::FromStrParser; use openssl::pkey::{PKey, Private}; use openssl::x509::X509; use rpc_toolkit::{ - CliBindings, Context, HandlerArgs, HandlerArgsFor, HandlerFor, HandlerTypes, PrintCliResult, + CliBindings, Context, HandlerArgs, HandlerArgsFor, HandlerFor, HandlerTS, HandlerTypes, + PrintCliResult, }; use serde::de::DeserializeOwned; use serde::ser::{SerializeMap, SerializeSeq}; @@ -451,6 +452,36 @@ impl CommandFactory for WithIoFormat { } } } +impl TS for WithIoFormat { + type WithoutGenerics = T::WithoutGenerics; + fn decl() -> String { + T::decl() + } + fn decl_concrete() -> String { + T::decl_concrete() + } + fn name() -> String { + T::name() + } + fn inline() -> String { + T::inline() + } + fn inline_flattened() -> String { + T::inline_flattened() + } + fn visit_dependencies(v: &mut impl ts_rs::TypeVisitor) + where + Self: 'static, + { + T::visit_dependencies(v); + } + fn visit_generics(v: &mut impl ts_rs::TypeVisitor) + where + Self: 'static, + { + T::visit_generics(v); + } +} pub trait HandlerExtSerde: HandlerFor { fn with_display_serializable(self) -> DisplaySerializable; @@ -469,6 +500,11 @@ impl HandlerTypes for DisplaySerializable { type Ok = T::Ok; type Err = T::Err; } +impl HandlerTS for DisplaySerializable { + fn type_info(&self) -> Option { + self.0.type_info() + } +} impl, C: Context> HandlerFor for DisplaySerializable { fn handle_sync( &self, @@ -891,6 +927,48 @@ where } } +impl TS for Reversible +where + for<'a> &'a Container: IntoDoubleEndedIterator<&'a T>, + Container: TS, +{ + type WithoutGenerics = Reversible; + + fn decl() -> String { + Container::decl() + } + + fn decl_concrete() -> String { + Container::decl_concrete() + } + + fn name() -> String { + Container::name() + } + + fn inline() -> String { + Container::inline() + } + + fn inline_flattened() -> String { + Container::inline_flattened() + } + + fn visit_dependencies(v: &mut impl ts_rs::TypeVisitor) + where + Self: 'static, + { + Container::visit_dependencies(v); + } + + fn visit_generics(v: &mut impl ts_rs::TypeVisitor) + where + Self: 'static, + { + Container::visit_generics(v); + } +} + pub struct KeyVal { pub key: K, pub value: V, @@ -929,6 +1007,47 @@ impl<'de, K: Deserialize<'de>, V: Deserialize<'de>> Deserialize<'de> for KeyVal< deserializer.deserialize_map(Visitor(PhantomData)) } } +impl TS for KeyVal { + type WithoutGenerics = KeyVal; + fn decl() -> String { + format!("type {} = {{ [T in K]: V }}", Self::name()) + } + fn decl_concrete() -> String { + format!( + "type {} = {{ [T in {}]: {} }}", + Self::name(), + K::name(), + V::name() + ) + } + fn name() -> String { + "KeyVal".into() + } + fn inline() -> String { + format!("{{ [T in {}]: {} }}", K::inline(), V::inline()) + } + fn inline_flattened() -> String { + Self::inline() + } + fn visit_dependencies(v: &mut impl ts_rs::TypeVisitor) + where + Self: 'static, + { + v.visit::(); + K::visit_dependencies(v); + v.visit::(); + V::visit_dependencies(v); + } + fn visit_generics(v: &mut impl ts_rs::TypeVisitor) + where + Self: 'static, + { + v.visit::(); + K::visit_generics(v); + v.visit::(); + V::visit_generics(v); + } +} #[derive(TS)] #[ts(type = "string", concrete(T = Vec))] diff --git a/core/startos/src/util/squashfs.rs b/core/startos/src/util/squashfs.rs index d2ab135c2..7057da71d 100644 --- a/core/startos/src/util/squashfs.rs +++ b/core/startos/src/util/squashfs.rs @@ -349,22 +349,23 @@ impl AsyncWrite for MetadataBlocksWriter { *this.size_addr = Some(pos); None }; - this.output.unwritten_mut()[..2] - .copy_from_slice(&u16::to_le_bytes(size)[..]); + this.output.unwritten_mut()[..2].copy_from_slice(&u16::to_le_bytes(size)[..]); this.output.advance(2); - *this.write_state = WriteState::WritingOutput(Box::new(if let Some(end) = done { - WriteState::SeekingToEnd(end) - } else { - WriteState::EncodingInput - })); + *this.write_state = + WriteState::WritingOutput(Box::new(if let Some(end) = done { + WriteState::SeekingToEnd(end) + } else { + WriteState::EncodingInput + })); } WriteState::WritingOutput(next) => { if this.output.written().len() > *this.output_flushed { - let n = ready!(this - .writer - .as_mut() - .poll_write(cx, &this.output.written()[*this.output_flushed..]))?; + let n = ready!( + this.writer + .as_mut() + .poll_write(cx, &this.output.written()[*this.output_flushed..]) + )?; *this.output_flushed += n; } else { this.output.reset(); @@ -375,10 +376,7 @@ impl AsyncWrite for MetadataBlocksWriter { WriteState::EncodingInput => { let encoder = this.zstd.get_or_insert_with(|| ZstdEncoder::new(22)); - encoder.encode( - &mut PartialBuffer::new(this.input.written()), - this.output, - )?; + encoder.encode(&mut PartialBuffer::new(this.input.written()), this.output)?; let compressed = if !encoder.finish(this.output)? { std::mem::swap(this.output, this.input); false @@ -387,12 +385,11 @@ impl AsyncWrite for MetadataBlocksWriter { }; *this.zstd = None; this.input.reset(); - *this.write_state = WriteState::WritingOutput(Box::new( - WriteState::WritingSizeHeader( + *this.write_state = + WriteState::WritingOutput(Box::new(WriteState::WritingSizeHeader( this.output.written().len() as u16 | if compressed { 0 } else { 0x8000 }, - ), - )); + ))); } WriteState::SeekingToEnd(end_addr) => { @@ -441,10 +438,12 @@ pub struct MetadataBlocksReader { #[pin] reader: R, size_buf: PartialBuffer<[u8; 2]>, - compressed: PartialBuffer<[u8; 8192]>, + compressed: [u8; 8192], compressed_size: usize, + compressed_pos: usize, is_compressed: bool, - output: PartialBuffer<[u8; 8192]>, + output: [u8; 8192], + output_size: usize, output_pos: usize, zstd: Option, state: ReadState, @@ -464,10 +463,12 @@ impl MetadataBlocksReader { Self { reader, size_buf: PartialBuffer::new([0; 2]), - compressed: PartialBuffer::new([0; 8192]), + compressed: [0; 8192], compressed_size: 0, + compressed_pos: 0, is_compressed: false, - output: PartialBuffer::new([0; 8192]), + output: [0; 8192], + output_size: 0, output_pos: 0, zstd: None, state: ReadState::ReadingSize, @@ -515,14 +516,16 @@ impl Read for MetadataBlocksReader { )); } - self.compressed.reset(); + self.compressed_pos = 0; self.size_buf.reset(); self.state = ReadState::ReadingData; continue; } ReadState::ReadingData => { - let n = self.reader.read(self.compressed.unwritten_mut())?; + let n = self + .reader + .read(&mut self.compressed[self.compressed_pos..self.compressed_size])?; if n == 0 { return Err(std::io::Error::new( std::io::ErrorKind::UnexpectedEof, @@ -530,59 +533,67 @@ impl Read for MetadataBlocksReader { )); } - self.compressed.advance(n); + self.compressed_pos += n; - if !self.compressed.unwritten().is_empty() { + if self.compressed_pos < self.compressed_size { continue; } self.output_pos = 0; - self.output.reset(); + self.output_size = 0; if self.is_compressed { self.zstd = Some(ZstdDecoder::new()); self.state = ReadState::Decompressing; } else { - self.output - .copy_unwritten_from(&mut PartialBuffer::new(self.compressed.written())); + // For uncompressed blocks, copy directly to output + self.output[..self.compressed_size] + .copy_from_slice(&self.compressed[..self.compressed_size]); + self.output_size = self.compressed_size; self.state = ReadState::Outputting; } continue; } ReadState::Decompressing => { - if self.output.unwritten().is_empty() { + let mut output = PartialBuffer::new(&mut self.output); + output.advance(self.output_size); + + if output.unwritten().is_empty() { self.state = ReadState::Outputting; continue; } - let mut input = PartialBuffer::new(self.compressed.written()); + let mut input = PartialBuffer::new(&self.compressed[..self.compressed_size]); let decoder = self.zstd.as_mut().unwrap(); - if decoder.decode(&mut input, &mut self.output)? { + if decoder.decode(&mut input, &mut output)? { self.zstd = None; + } + self.output_size = output.written().len(); + + if self.output_size > self.output_pos { self.state = ReadState::Outputting; } continue; } ReadState::Outputting => { - let available = self.output.written().len() - self.output_pos; + let available = self.output_size - self.output_pos; if available == 0 { if self.zstd.is_none() { self.state = ReadState::ReadingSize; continue; } else { - self.output.reset(); self.output_pos = 0; + self.output_size = 0; self.state = ReadState::Decompressing; continue; } } let to_copy = available.min(buf.len()); - buf[..to_copy].copy_from_slice( - &self.output.written()[self.output_pos..self.output_pos + to_copy], - ); + buf[..to_copy] + .copy_from_slice(&self.output[self.output_pos..self.output_pos + to_copy]); self.output_pos += to_copy; return Ok(to_copy); } @@ -629,26 +640,30 @@ impl AsyncRead for MetadataBlocksReader { continue; } - let size_header = u16::from_le_bytes(*this.size_buf.written()); + let size_header = u16::from_le_bytes([ + this.size_buf.written()[0], + this.size_buf.written()[1], + ]); *this.is_compressed = (size_header & 0x8000) == 0; - let size = (size_header & 0x7FFF) as usize; + *this.compressed_size = (size_header & 0x7FFF) as usize; - if size == 0 || size > 8192 { + if *this.compressed_size == 0 || *this.compressed_size > 8192 { return Poll::Ready(Err(std::io::Error::new( std::io::ErrorKind::InvalidData, - format!("Invalid metadata block size: {}", size), + format!("Invalid metadata block size: {}", *this.compressed_size), ))); } - this.compressed.reset(); - this.compressed.reserve(size); + *this.compressed_pos = 0; this.size_buf.reset(); *this.state = ReadState::ReadingData; continue; } ReadState::ReadingData => { - let mut read_buf = tokio::io::ReadBuf::new(this.compressed.unwritten_mut()); + let mut read_buf = tokio::io::ReadBuf::new( + &mut this.compressed[*this.compressed_pos..*this.compressed_size], + ); let before = read_buf.filled().len(); ready!(this.reader.as_mut().poll_read(cx, &mut read_buf))?; let n = read_buf.filled().len() - before; @@ -660,59 +675,66 @@ impl AsyncRead for MetadataBlocksReader { ))); } - this.compressed.advance(n); + *this.compressed_pos += n; - if !this.compressed.unwritten().is_empty() { + if *this.compressed_pos < *this.compressed_size { continue; } *this.output_pos = 0; - this.output.reset(); + *this.output_size = 0; if *this.is_compressed { *this.zstd = Some(ZstdDecoder::new()); *this.state = ReadState::Decompressing; } else { - this.output - .copy_unwritten_from(&mut PartialBuffer::new(this.compressed.written())); + // For uncompressed blocks, copy directly to output + this.output[..*this.compressed_size] + .copy_from_slice(&this.compressed[..*this.compressed_size]); + *this.output_size = *this.compressed_size; *this.state = ReadState::Outputting; } continue; } ReadState::Decompressing => { - if this.output.unwritten().is_empty() { + let mut output = PartialBuffer::new(this.output); + output.advance(*this.output_size); + + if output.unwritten().is_empty() { *this.state = ReadState::Outputting; continue; } - let mut input = PartialBuffer::new(this.compressed.written()); + let mut input = PartialBuffer::new(&this.compressed[..*this.compressed_size]); let decoder = this.zstd.as_mut().unwrap(); - if decoder.decode(&mut input, this.output)? { + if decoder.decode(&mut input, &mut output)? { *this.zstd = None; + } + *this.output_size = output.written().len(); + + if *this.output_size > *this.output_pos { *this.state = ReadState::Outputting; } continue; } ReadState::Outputting => { - let available = this.output.written().len() - *this.output_pos; + let available = *this.output_size - *this.output_pos; if available == 0 { if this.zstd.is_none() { *this.state = ReadState::ReadingSize; continue; } else { - this.output.reset(); *this.output_pos = 0; + *this.output_size = 0; *this.state = ReadState::Decompressing; continue; } } let to_copy = available.min(buf.remaining()); - buf.put_slice( - &this.output.written()[*this.output_pos..*this.output_pos + to_copy], - ); + buf.put_slice(&this.output[*this.output_pos..*this.output_pos + to_copy]); *this.output_pos += to_copy; return Poll::Ready(Ok(())); } diff --git a/core/startos/src/version/mod.rs b/core/startos/src/version/mod.rs index 6f8bae32a..fd8bc4a17 100644 --- a/core/startos/src/version/mod.rs +++ b/core/startos/src/version/mod.rs @@ -7,6 +7,7 @@ use futures::future::BoxFuture; use futures::{Future, FutureExt}; use imbl_value::{InternedString, to_value}; use patch_db::json_ptr::ROOT; +use ts_rs::TS; use crate::Error; use crate::context::RpcContext;