From a1b4311ab4c4175d32266c02ec2851e77a3a7fc7 Mon Sep 17 00:00:00 2001 From: Aiden McClelland Date: Fri, 13 Dec 2024 15:37:28 -0700 Subject: [PATCH] individualized acme and privacy settings for domains and bindings --- core/Cargo.lock | 548 +++++++++--------- core/startos/Cargo.toml | 2 +- core/startos/src/db/model/public.rs | 23 +- core/startos/src/net/acme.rs | 174 ++---- core/startos/src/net/host/address.rs | 321 ++++++++-- core/startos/src/net/host/binding.rs | 126 +++- core/startos/src/net/host/mod.rs | 162 ++---- core/startos/src/net/net_controller.rs | 125 ++-- core/startos/src/net/network_interface.rs | 302 ++++++++-- core/startos/src/net/ssl.rs | 1 - core/startos/src/net/static_server.rs | 3 +- core/startos/src/net/vhost.rs | 331 ++++++----- core/startos/src/net/wifi.rs | 6 +- core/startos/src/prelude.rs | 10 +- core/startos/src/registry/context.rs | 1 - core/startos/src/registry/mod.rs | 3 +- .../signer/commitment/merkle_archive.rs | 4 +- core/startos/src/service/effects/callbacks.rs | 2 +- core/startos/src/service/effects/net/ssl.rs | 20 +- core/startos/src/service/effects/store.rs | 2 +- core/startos/src/service/mod.rs | 2 - .../src/service/persistent_container.rs | 2 +- core/startos/src/service/rpc.rs | 2 +- .../startos/src/service/transition/restore.rs | 2 +- core/startos/src/util/rpc_client.rs | 6 +- core/startos/src/version/v0_3_6_alpha_0.rs | 2 - .../{HostAddress.ts => AcmeProvider.ts} | 4 +- sdk/base/lib/osBindings/AcmeSettings.ts | 12 +- sdk/base/lib/osBindings/DomainConfig.ts | 4 + .../lib/osBindings/ForgetInterfaceParams.ts | 3 + sdk/base/lib/osBindings/Host.ts | 5 +- sdk/base/lib/osBindings/IpInfo.ts | 1 + sdk/base/lib/osBindings/ServerInfo.ts | 3 +- sdk/base/lib/osBindings/index.ts | 4 +- .../ui/src/app/services/api/mock-patch.ts | 2 + 35 files changed, 1322 insertions(+), 898 deletions(-) rename sdk/base/lib/osBindings/{HostAddress.ts => AcmeProvider.ts} (51%) create mode 100644 sdk/base/lib/osBindings/DomainConfig.ts create mode 100644 sdk/base/lib/osBindings/ForgetInterfaceParams.ts diff --git a/core/Cargo.lock b/core/Cargo.lock index 16a0a0e7b1..4a79149993 100644 --- a/core/Cargo.lock +++ b/core/Cargo.lock @@ -92,9 +92,9 @@ dependencies = [ [[package]] name = "allocator-api2" -version = "0.2.20" +version = "0.2.21" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "45862d1c77f2228b9e10bc609d5bc203d86ebc9b87ad8d5d5167a6c9abf739d9" +checksum = "683d7910e743518b0e34f1186f92494becacb047c7b6bf616c96772180fef923" [[package]] name = "android-tzdata" @@ -162,9 +162,9 @@ dependencies = [ [[package]] name = "anyhow" -version = "1.0.93" +version = "1.0.94" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4c95c10ba0b00a02636238b814946408b1322d5ac4760326e6fb8ec956d85775" +checksum = "c1fd03a028ef38ba2276dce7e33fcd6369c158a1bca17946c4b1b701891c1ff7" [[package]] name = "arrayref" @@ -205,7 +205,7 @@ dependencies = [ "nom 7.1.3", "num-traits", "rusticata-macros", - "thiserror", + "thiserror 1.0.69", "time", ] @@ -217,7 +217,7 @@ checksum = "965c2d33e53cb6b267e148a4cb0760bc01f4904c1cd4bb4002a085bb016d1490" dependencies = [ "proc-macro2", "quote", - "syn 2.0.87", + "syn 2.0.90", "synstructure", ] @@ -229,13 +229,13 @@ checksum = "7b18050c2cd6fe86c3a76584ef5e0baf286d038cda203eb6223df2cc413565f7" dependencies = [ "proc-macro2", "quote", - "syn 2.0.87", + "syn 2.0.90", ] [[package]] name = "async-acme" -version = "0.5.0" -source = "git+https://github.com/dr-bonez/async-acme.git#b9ff31ad900adc9086c0d1437ce51661d30856d2" +version = "0.6.0" +source = "git+https://github.com/dr-bonez/async-acme.git#0ddf25152237b5fc1726d977a7931e44513ce309" dependencies = [ "async-trait", "base64 0.22.1", @@ -245,11 +245,11 @@ dependencies = [ "pem", "rcgen", "ring", - "rustls 0.23.17", + "rustls 0.23.20", "rustls-pemfile 2.2.0", "serde", "serde_json", - "thiserror", + "thiserror 1.0.69", "tokio", "x509-parser", ] @@ -291,9 +291,9 @@ dependencies = [ [[package]] name = "async-compression" -version = "0.4.17" +version = "0.4.18" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0cb8f1d480b0ea3783ab015936d2a55c87e219676f0c0b7dec61494043f21857" +checksum = "df895a515f70646414f4b45c0b79082783b80552b373a68283012928df56f522" dependencies = [ "brotli", "flate2", @@ -384,7 +384,7 @@ checksum = "3b43422f69d8ff38f95f1b2bb76517c91589a924d1559a0e935d7c8ce0274c11" dependencies = [ "proc-macro2", "quote", - "syn 2.0.87", + "syn 2.0.90", ] [[package]] @@ -424,7 +424,7 @@ checksum = "c7c24de15d275a1ecfd47a380fb4d5ec9bfe0933f309ed5e705b775596a3574d" dependencies = [ "proc-macro2", "quote", - "syn 2.0.87", + "syn 2.0.90", ] [[package]] @@ -441,7 +441,7 @@ checksum = "721cae7de5c34fbb2acd27e21e6d2cf7b886dce0c27388d46c4e6c47ea4318dd" dependencies = [ "proc-macro2", "quote", - "syn 2.0.87", + "syn 2.0.90", ] [[package]] @@ -467,21 +467,20 @@ checksum = "ace50bade8e6234aa140d9a2f552bbee1db4d353f69b8217bc503490fc1a9f26" [[package]] name = "aws-lc-rs" -version = "1.11.0" +version = "1.11.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fe7c2840b66236045acd2607d5866e274380afd87ef99d6226e961e2cb47df45" +checksum = "f47bb8cc16b669d267eeccf585aea077d0882f4777b1c1f740217885d6e6e5a3" dependencies = [ "aws-lc-sys", - "mirai-annotations", "paste", "zeroize", ] [[package]] name = "aws-lc-sys" -version = "0.23.0" +version = "0.23.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ad3a619a9de81e1d7de1f1186dcba4506ed661a0e483d84410fdef0ee87b2f96" +checksum = "a2101df3813227bbaaaa0b04cd61c534c7954b22bd68d399b440be937dc63ff7" dependencies = [ "bindgen", "cc", @@ -531,7 +530,7 @@ dependencies = [ "base64 0.22.1", "bytes", "futures-util", - "http 1.1.0", + "http 1.2.0", "http-body 1.0.1", "http-body-util", "hyper 1.5.1", @@ -548,10 +547,10 @@ dependencies = [ "serde_path_to_error", "serde_urlencoded", "sha1", - "sync_wrapper 1.0.1", + "sync_wrapper 1.0.2", "tokio", "tokio-tungstenite 0.24.0", - "tower 0.5.1", + "tower 0.5.2", "tower-layer", "tower-service", "tracing", @@ -583,13 +582,13 @@ dependencies = [ "async-trait", "bytes", "futures-util", - "http 1.1.0", + "http 1.2.0", "http-body 1.0.1", "http-body-util", "mime", "pin-project-lite", "rustversion", - "sync_wrapper 1.0.1", + "sync_wrapper 1.0.2", "tower-layer", "tower-service", "tracing", @@ -603,7 +602,7 @@ checksum = "c1ad46c3ec4e12f4a4b6835e173ba21c25e484c9d02b49770bf006ce5367c036" dependencies = [ "bytes", "futures-util", - "http 1.1.0", + "http 1.2.0", "http-body 1.0.1", "http-body-util", "hyper 1.5.1", @@ -623,7 +622,7 @@ dependencies = [ "deku", "flate2", "rustc-hash", - "thiserror", + "thiserror 1.0.69", "tracing", "xz2", "zstd", @@ -731,7 +730,7 @@ dependencies = [ "regex", "rustc-hash", "shlex", - "syn 2.0.87", + "syn 2.0.90", "which", ] @@ -808,9 +807,9 @@ dependencies = [ [[package]] name = "blake3" -version = "1.5.4" +version = "1.5.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d82033247fd8e890df8f740e407ad4d038debb9eb1f40533fffb32e7d17dc6f7" +checksum = "b8ee0c1824c4dea5b5f81736aff91bae041d2c07ee1192bec91054e10e3e601e" dependencies = [ "arrayref", "arrayvec 0.7.6", @@ -899,9 +898,9 @@ checksum = "8f1fe948ff07f4bd06c30984e69f5b4899c516a3ef74f34df92a2df2ab535495" [[package]] name = "bytes" -version = "1.8.0" +version = "1.9.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9ac0150caa2ae65ca5bd83f25c7de183dea78d4d366469f148435e2acfbad0da" +checksum = "325918d6fe32f23b19878fe4b34794ae41fc19ddbe53b10571a4874d44ffd39b" [[package]] name = "cache-padded" @@ -911,9 +910,9 @@ checksum = "981520c98f422fcc584dc1a95c334e6953900b9106bc47a9839b81790009eb21" [[package]] name = "cc" -version = "1.2.1" +version = "1.2.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fd9de9f2205d5ef3fd67e685b0df337994ddd4495e2a28d185500d0e1edfea47" +checksum = "27f657647bcff5394bf56c7317665bbf790a137a50eaaa5c6bfbb9e27a518f2d" dependencies = [ "jobserver", "libc", @@ -943,9 +942,9 @@ checksum = "613afe47fcd5fac7ccf1db93babcb082c5994d996f20b8b159f2ad1658eb5724" [[package]] name = "chrono" -version = "0.4.38" +version = "0.4.39" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a21f936df1771bf62b77f047b726c4625ff2e8aa607c01ec06e5a05bd8463401" +checksum = "7e36cc9d416881d2e24f9a963be5fb1cd90966419ac844274161d10488b3e825" dependencies = [ "android-tzdata", "iana-time-zone", @@ -1024,9 +1023,9 @@ dependencies = [ [[package]] name = "clap" -version = "4.5.21" +version = "4.5.23" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fb3b4b9e5a7c7514dfa52869339ee98b3156b0bfb4e8a77c4ff4babb64b1604f" +checksum = "3135e7ec2ef7b10c6ed8950f0f792ed96ee093fa088608f1c76e569722700c84" dependencies = [ "clap_builder", "clap_derive", @@ -1034,9 +1033,9 @@ dependencies = [ [[package]] name = "clap_builder" -version = "4.5.21" +version = "4.5.23" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b17a95aa67cc7b5ebd32aa5370189aa0d79069ef1c64ce893bd30fb24bff20ec" +checksum = "30582fc632330df2bd26877bde0c1f4470d57c582bbc070376afcd04d8cb4838" dependencies = [ "anstream", "anstyle", @@ -1053,20 +1052,20 @@ dependencies = [ "heck 0.5.0", "proc-macro2", "quote", - "syn 2.0.87", + "syn 2.0.90", ] [[package]] name = "clap_lex" -version = "0.7.3" +version = "0.7.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "afb84c814227b90d6895e01398aee0d8033c00e7466aca416fb6a8e0eb19d8a7" +checksum = "f46ad14479a25103f283c0f10005961cf086d8dc42205bb44c46ac563475dca6" [[package]] name = "cmake" -version = "0.1.51" +version = "0.1.52" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fb1e43aa7fd152b1f968787f7dbcdeb306d1867ff373c69955211876c053f91a" +checksum = "c682c223677e0e5b6b7f63a64b9351844c3f1b1678a68b7ee617e30fb082620e" dependencies = [ "cc", ] @@ -1267,9 +1266,9 @@ checksum = "773648b94d0e5d620f64f280777445740e61fe701025087ec8b57f45c791888b" [[package]] name = "cpufeatures" -version = "0.2.15" +version = "0.2.16" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0ca741a962e1b0bff6d724a1a0958b686406e853bb14061f218562e1896f95e6" +checksum = "16b80225097f2e5ae4e7179dd2266824648f3e2f49d9134d584b76389d31c4c3" dependencies = [ "libc", ] @@ -1462,7 +1461,7 @@ checksum = "f46882e17999c6cc590af592290432be3bce0428cb0d5f8b6715e4dc7b383eb3" dependencies = [ "proc-macro2", "quote", - "syn 2.0.87", + "syn 2.0.90", ] [[package]] @@ -1486,7 +1485,7 @@ dependencies = [ "proc-macro2", "quote", "strsim 0.11.1", - "syn 2.0.87", + "syn 2.0.90", ] [[package]] @@ -1497,7 +1496,7 @@ checksum = "d336a2a514f6ccccaa3e09b02d41d35330c07ddf03a62165fcec10bb561c7806" dependencies = [ "darling_core", "quote", - "syn 2.0.87", + "syn 2.0.90", ] [[package]] @@ -1528,7 +1527,7 @@ dependencies = [ "proc-macro-crate", "proc-macro2", "quote", - "syn 2.0.87", + "syn 2.0.90", ] [[package]] @@ -1565,7 +1564,7 @@ checksum = "8034092389675178f570469e6c3b0465d3d30b4505c294a6550db47f3c17ad18" dependencies = [ "proc-macro2", "quote", - "syn 2.0.87", + "syn 2.0.90", ] [[package]] @@ -1588,7 +1587,7 @@ dependencies = [ "proc-macro2", "quote", "rustc_version", - "syn 2.0.87", + "syn 2.0.90", ] [[package]] @@ -1641,7 +1640,7 @@ checksum = "97369cbbc041bc366949bc74d34658d6cda5621039731c6310521892a3a20ae0" dependencies = [ "proc-macro2", "quote", - "syn 2.0.87", + "syn 2.0.90", ] [[package]] @@ -1836,7 +1835,7 @@ dependencies = [ "heck 0.5.0", "proc-macro2", "quote", - "syn 2.0.87", + "syn 2.0.90", ] [[package]] @@ -1857,7 +1856,7 @@ checksum = "de0d48a183585823424a4ce1aa132d174a6a81bd540895822eb4c8373a8e49e8" dependencies = [ "proc-macro2", "quote", - "syn 2.0.87", + "syn 2.0.90", ] [[package]] @@ -1879,12 +1878,12 @@ dependencies = [ [[package]] name = "errno" -version = "0.3.9" +version = "0.3.10" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "534c5cf6194dfab3db3242765c03bbe257cf92f22b38f6bc0c58d59108a820ba" +checksum = "33d852cb9b869c2a9b3df2f71a3074817f01e1844f839a144f5fcef059a4eb5d" dependencies = [ "libc", - "windows-sys 0.52.0", + "windows-sys 0.59.0", ] [[package]] @@ -1927,9 +1926,9 @@ dependencies = [ [[package]] name = "event-listener-strategy" -version = "0.5.2" +version = "0.5.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0f214dc438f977e6d4e3500aaa277f5ad94ca83fbbd9b1a15713ce2344ccc5a1" +checksum = "3c3e4e0dd3673c1139bf041f3008816d9cf2946bbfac2945c09e523b8d7b05b2" dependencies = [ "event-listener 5.3.1", "pin-project-lite", @@ -1965,9 +1964,9 @@ dependencies = [ [[package]] name = "fastrand" -version = "2.2.0" +version = "2.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "486f806e73c5707928240ddc295403b1b93c96a02038563881c4a2fd84b81ac4" +checksum = "37909eebbb50d72f9059c3b6d82c0463f2ff062c9e95845c43a6c9c0355411be" [[package]] name = "fd-lock-rs" @@ -2170,7 +2169,7 @@ checksum = "162ee34ebcb7c64a8abebc059ce0fee27c2262618d7b60ed8faf72fef13c3650" dependencies = [ "proc-macro2", "quote", - "syn 2.0.87", + "syn 2.0.90", ] [[package]] @@ -2241,7 +2240,7 @@ dependencies = [ "serde_urlencoded", "tokio", "tokio-rustls 0.25.0", - "webpki-roots 0.26.6", + "webpki-roots 0.26.7", ] [[package]] @@ -2324,7 +2323,7 @@ dependencies = [ "futures-sink", "futures-util", "http 0.2.12", - "indexmap 2.6.0", + "indexmap 2.7.0", "slab", "tokio", "tokio-util", @@ -2342,8 +2341,8 @@ dependencies = [ "fnv", "futures-core", "futures-sink", - "http 1.1.0", - "indexmap 2.6.0", + "http 1.2.0", + "indexmap 2.7.0", "slab", "tokio", "tokio-util", @@ -2393,9 +2392,9 @@ dependencies = [ [[package]] name = "hashbrown" -version = "0.15.1" +version = "0.15.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3a9bfc1af68b1726ea47d3d5109de126281def866b33970e10fbab11b5dafab3" +checksum = "bf151400ff0baff5465007dd2f3e717f3fe502074ca563069ce3a6629d07b289" [[package]] name = "hashlink" @@ -2515,9 +2514,9 @@ dependencies = [ [[package]] name = "http" -version = "1.1.0" +version = "1.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "21b9ddb458710bc376481b842f5da65cdf31522de232c1ca8146abce2a358258" +checksum = "f16ca2af56261c99fba8bac40a10251ce8188205a4c448fbb745a2e4daa76fea" dependencies = [ "bytes", "fnv", @@ -2542,7 +2541,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "1efedce1fb8e6913f23e0c92de8e62cd5b772a67e7b3946df930a62566c93184" dependencies = [ "bytes", - "http 1.1.0", + "http 1.2.0", ] [[package]] @@ -2553,7 +2552,7 @@ checksum = "793429d76616a256bcb62c2a2ec2bed781c8307e797e2598c50010f2bee2544f" dependencies = [ "bytes", "futures-util", - "http 1.1.0", + "http 1.2.0", "http-body 1.0.1", "pin-project-lite", ] @@ -2610,7 +2609,7 @@ dependencies = [ "futures-channel", "futures-util", "h2 0.4.7", - "http 1.1.0", + "http 1.2.0", "http-body 1.0.1", "httparse", "httpdate", @@ -2628,13 +2627,13 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "08afdbb5c31130e3034af566421053ab03787c640246a446327f550d11bcb333" dependencies = [ "futures-util", - "http 1.1.0", + "http 1.2.0", "hyper 1.5.1", "hyper-util", - "rustls 0.23.17", + "rustls 0.23.20", "rustls-pki-types", "tokio", - "tokio-rustls 0.26.0", + "tokio-rustls 0.26.1", "tower-service", ] @@ -2675,7 +2674,7 @@ dependencies = [ "bytes", "futures-channel", "futures-util", - "http 1.1.0", + "http 1.2.0", "http-body 1.0.1", "hyper 1.5.1", "pin-project-lite", @@ -2823,7 +2822,7 @@ checksum = "1ec89e9337638ecdc08744df490b221a7399bf8d164eb52a665454e60e075ad6" dependencies = [ "proc-macro2", "quote", - "syn 2.0.87", + "syn 2.0.90", ] [[package]] @@ -2908,8 +2907,8 @@ dependencies = [ [[package]] name = "imbl-value" -version = "0.1.0" -source = "git+https://github.com/Start9Labs/imbl-value.git#3ce01b17ae5e756fc829ee5e3513a1b19b2a03fc" +version = "0.1.1" +source = "git+https://github.com/Start9Labs/imbl-value.git#1900943e17116def03bf00bff05cf12e54d810bc" dependencies = [ "imbl", "serde", @@ -2956,12 +2955,12 @@ dependencies = [ [[package]] name = "indexmap" -version = "2.6.0" +version = "2.7.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "707907fe3c25f5424cce2cb7e1cbcafee6bdbe735ca90ef77c29e84591e5b9da" +checksum = "62f822373a4fe84d4bb149bf54e584a7f4abec90e072ed49cda0edea5b95471f" dependencies = [ "equivalent", - "hashbrown 0.15.1", + "hashbrown 0.15.2", "serde", ] @@ -3041,7 +3040,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "1ea1dc4bf0fb4904ba83ffdb98af3d9c325274e92e6e295e4151e86c96363e04" dependencies = [ "serde", - "thiserror", + "thiserror 1.0.69", ] [[package]] @@ -3091,9 +3090,9 @@ dependencies = [ [[package]] name = "itoa" -version = "1.0.11" +version = "1.0.14" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "49f1f14873335454500d59611f1cf4a4b0f786f9ac11f4312a78e4cf2566695b" +checksum = "d75a2a4b1b190afb6f5425f10f6a8f959d2ea0b9c2b1d79553551850539e4674" [[package]] name = "jaq-core" @@ -3156,16 +3155,17 @@ dependencies = [ "regex", "serde", "serde_json", - "thiserror", + "thiserror 1.0.69", "time", ] [[package]] name = "js-sys" -version = "0.3.72" +version = "0.3.76" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6a88f1bda2bd75b0452a14784937d796722fdebfe50df998aeb3f0b7603019a9" +checksum = "6717b6b5b077764fb5966237269cb3c64edddde4b14ce42647430a78ced9e7b7" dependencies = [ + "once_cell", "wasm-bindgen", ] @@ -3186,7 +3186,7 @@ dependencies = [ "imbl", "imbl-value", "serde", - "thiserror", + "thiserror 1.0.69", ] [[package]] @@ -3286,15 +3286,15 @@ dependencies = [ [[package]] name = "libc" -version = "0.2.164" +version = "0.2.168" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "433bfe06b8c75da9b2e3fbea6e5329ff87748f0b144ef75306e674c3f6f7c13f" +checksum = "5aaeb2981e0606ca11d79718f8bb01164f1d6ed75080182d3abf017e6d244b6d" [[package]] name = "libloading" -version = "0.8.5" +version = "0.8.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4979f22fdb869068da03c9f7528f8297c6fd2606bc3a4affe42e6a823fdb8da4" +checksum = "fc2f4eb4bc735547cfed7c0a4922cbd04a4655978c09b54f1f7b228750664c34" dependencies = [ "cfg-if", "windows-targets 0.52.6", @@ -3314,7 +3314,7 @@ checksum = "c0ff37bd590ca25063e35af745c343cb7a0271906fb7b37e4813e8f79f00268d" dependencies = [ "bitflags 2.6.0", "libc", - "redox_syscall 0.5.7", + "redox_syscall 0.5.8", ] [[package]] @@ -3342,9 +3342,9 @@ checksum = "78b3ae25bc7c8c38cec158d1f2757ee79e9b3740fbc7ccf0e59e4b08d793fa89" [[package]] name = "litemap" -version = "0.7.3" +version = "0.7.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "643cb0b8d4fcc284004d5fd0d67ccf61dfffadb7f75e1e71bc420f4688a3a704" +checksum = "4ee93343901ab17bd981295f2cf0026d4ad018c7c31ba84549a4ddbb47a45104" [[package]] name = "litrs" @@ -3404,7 +3404,7 @@ dependencies = [ "bitvec 1.0.1", "serde", "serde-big-array", - "thiserror", + "thiserror 1.0.69", ] [[package]] @@ -3491,23 +3491,16 @@ dependencies = [ [[package]] name = "mio" -version = "1.0.2" +version = "1.0.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "80e04d1dcff3aae0704555fe5fee3bcfaf3d1fdf8a7e521d5b9d2b42acb52cec" +checksum = "2886843bf800fba2e3377cff24abf6379b4c4d5c6681eaf9ea5b0d15090450bd" dependencies = [ - "hermit-abi 0.3.9", "libc", "log", "wasi 0.11.0+wasi-snapshot-preview1", "windows-sys 0.52.0", ] -[[package]] -name = "mirai-annotations" -version = "1.12.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c9be0862c1b3f26a88803c4a49de6889c10e608b3ee9344e6ef5b45fb37ad3d1" - [[package]] name = "models" version = "0.1.0" @@ -3531,7 +3524,7 @@ dependencies = [ "serde_json", "sqlx", "ssh-key", - "thiserror", + "thiserror 1.0.69", "tokio", "torut", "tracing", @@ -3778,7 +3771,7 @@ dependencies = [ "proc-macro-crate", "proc-macro2", "quote", - "syn 2.0.87", + "syn 2.0.90", ] [[package]] @@ -3827,7 +3820,7 @@ dependencies = [ "byteorder", "md-5", "sha2 0.10.8", - "thiserror", + "thiserror 1.0.69", ] [[package]] @@ -3853,7 +3846,7 @@ checksum = "a948666b637a0f465e8564c73e89d4dde00d72d4d473cc972f390fc3dcee7d9c" dependencies = [ "proc-macro2", "quote", - "syn 2.0.87", + "syn 2.0.90", ] [[package]] @@ -3968,7 +3961,7 @@ checksum = "1e401f977ab385c9e4e3ab30627d6f26d00e2c73eef317493c4ec6d468726cf8" dependencies = [ "cfg-if", "libc", - "redox_syscall 0.5.7", + "redox_syscall 0.5.8", "smallvec", "windows-targets 0.52.6", ] @@ -3995,7 +3988,7 @@ dependencies = [ "patch-db-macro", "serde", "serde_cbor", - "thiserror", + "thiserror 1.0.69", "tokio", "tracing", "tracing-error", @@ -4057,20 +4050,20 @@ checksum = "e3148f5046208a5d56bcfc03053e3ca6334e51da8dfb19b6cdc8b306fae3283e" [[package]] name = "pest" -version = "2.7.14" +version = "2.7.15" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "879952a81a83930934cbf1786752d6dedc3b1f29e8f8fb2ad1d0a36f377cf442" +checksum = "8b7cafe60d6cf8e62e1b9b2ea516a089c008945bb5a275416789e7db0bc199dc" dependencies = [ "memchr", - "thiserror", + "thiserror 2.0.6", "ucd-trie", ] [[package]] name = "pest_derive" -version = "2.7.14" +version = "2.7.15" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d214365f632b123a47fd913301e14c946c61d1c183ee245fa76eb752e59a02dd" +checksum = "816518421cfc6887a0d62bf441b6ffb4536fcc926395a69e1a85852d4363f57e" dependencies = [ "pest", "pest_generator", @@ -4078,22 +4071,22 @@ dependencies = [ [[package]] name = "pest_generator" -version = "2.7.14" +version = "2.7.15" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "eb55586734301717aea2ac313f50b2eb8f60d2fc3dc01d190eefa2e625f60c4e" +checksum = "7d1396fd3a870fc7838768d171b4616d5c91f6cc25e377b673d714567d99377b" dependencies = [ "pest", "pest_meta", "proc-macro2", "quote", - "syn 2.0.87", + "syn 2.0.90", ] [[package]] name = "pest_meta" -version = "2.7.14" +version = "2.7.15" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b75da2a70cf4d9cb76833c990ac9cd3923c9a8905a8929789ce347c84564d03d" +checksum = "e1e58089ea25d717bfd31fb534e4f3afcc2cc569c70de3e239778991ea3b7dea" dependencies = [ "once_cell", "pest", @@ -4107,7 +4100,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b4c5cc86750666a3ed20bdaf5ca2a0344f9c67674cae0515bec2da16fbaa47db" dependencies = [ "fixedbitset", - "indexmap 2.6.0", + "indexmap 2.7.0", ] [[package]] @@ -4142,7 +4135,7 @@ checksum = "3c0f5fad0874fc7abcd4d750e76917eaebbecaa2c20bde22e1dbeeba8beb758c" dependencies = [ "proc-macro2", "quote", - "syn 2.0.87", + "syn 2.0.90", ] [[package]] @@ -4212,9 +4205,9 @@ dependencies = [ [[package]] name = "portable-atomic" -version = "1.9.0" +version = "1.10.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cc9c68a3f6da06753e9335d63e27f6b9754dd1920d941135b7ea8224f141adb2" +checksum = "280dc24453071f1b63954171985a0b0d30058d287960968b9b2aca264c8d4ee6" [[package]] name = "powerfmt" @@ -4244,7 +4237,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "64d1ec885c64d0457d564db4ec299b2dae3f9c02808b8ad9c3a089c591b18033" dependencies = [ "proc-macro2", - "syn 2.0.87", + "syn 2.0.90", ] [[package]] @@ -4281,9 +4274,9 @@ dependencies = [ [[package]] name = "proc-macro2" -version = "1.0.89" +version = "1.0.92" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f139b0662de085916d1fb67d2b4169d1addddda1919e696f3252b740b629986e" +checksum = "37d3544b3f2748c54e147655edb5025752e2303145b5aefb3c3ea2c78b973bb0" dependencies = [ "unicode-ident", ] @@ -4342,7 +4335,7 @@ checksum = "6ff7ff745a347b87471d859a377a9a404361e7efc2a971d73424a6d183c0fc77" dependencies = [ "proc-macro2", "quote", - "syn 2.0.87", + "syn 2.0.90", ] [[package]] @@ -4365,7 +4358,7 @@ dependencies = [ "itertools 0.12.1", "proc-macro2", "quote", - "syn 2.0.87", + "syn 2.0.90", ] [[package]] @@ -4557,9 +4550,9 @@ dependencies = [ [[package]] name = "redox_syscall" -version = "0.5.7" +version = "0.5.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9b6dfecf2c74bce2466cabf93f6664d6998a69eb21e39f4207930065b27b771f" +checksum = "03a862b389f93e68874fbf580b9de08dd02facb9a788ebadaf4a3fd33cf58834" dependencies = [ "bitflags 2.6.0", ] @@ -4572,7 +4565,7 @@ checksum = "ba009ff324d1fc1b900bd1fdb31564febe58a8ccc8a6fdbb93b543d33b13ca43" dependencies = [ "getrandom 0.2.15", "libredox", - "thiserror", + "thiserror 1.0.69", ] [[package]] @@ -4633,7 +4626,7 @@ dependencies = [ "futures-core", "futures-util", "h2 0.4.7", - "http 1.1.0", + "http 1.2.0", "http-body 1.0.1", "http-body-util", "hyper 1.5.1", @@ -4652,7 +4645,7 @@ dependencies = [ "serde", "serde_json", "serde_urlencoded", - "sync_wrapper 1.0.1", + "sync_wrapper 1.0.2", "system-configuration", "tokio", "tokio-native-tls", @@ -4725,7 +4718,7 @@ dependencies = [ "axum 0.7.9", "clap", "futures", - "http 1.1.0", + "http 1.2.0", "http-body-util", "imbl-value", "itertools 0.12.1", @@ -4736,7 +4729,7 @@ dependencies = [ "reqwest", "serde", "serde_json", - "thiserror", + "thiserror 1.0.69", "tokio", "tokio-stream", "url", @@ -4745,9 +4738,9 @@ dependencies = [ [[package]] name = "rsa" -version = "0.9.6" +version = "0.9.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5d0e5124fcb30e76a7e79bfee683a2746db83784b86289f6251b54b7950a0dfc" +checksum = "47c75d7c5c6b673e58bf54d8544a9f432e3a925b0e80f7cd3602ab5c50c55519" dependencies = [ "const-oid", "digest 0.10.7", @@ -4817,15 +4810,15 @@ dependencies = [ [[package]] name = "rustix" -version = "0.38.41" +version = "0.38.42" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d7f649912bc1495e167a6edee79151c84b1bad49748cb4f1f1167f459f6224f6" +checksum = "f93dc38ecbab2eb790ff964bb77fa94faf256fd3e73285fd7ba0903b76bedb85" dependencies = [ "bitflags 2.6.0", - "errno 0.3.9", + "errno 0.3.10", "libc", "linux-raw-sys", - "windows-sys 0.52.0", + "windows-sys 0.59.0", ] [[package]] @@ -4855,9 +4848,9 @@ dependencies = [ [[package]] name = "rustls" -version = "0.23.17" +version = "0.23.20" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7f1a745511c54ba6d4465e8d5dfbd81b45791756de28d4981af70d6dca128f1e" +checksum = "5065c3f250cbd332cd894be57c40fa52387247659b14a2d6041d121547903b1b" dependencies = [ "aws-lc-rs", "log", @@ -4935,18 +4928,18 @@ dependencies = [ [[package]] name = "rustyline-async" -version = "0.4.3" +version = "0.4.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bc9396d834c31f9fddd716e7c279e7cb70207092a1e59767918610f5c560c6eb" +checksum = "1b8a29112291cda41f18306ed8919c49360e5273328162445ca250aae37c8f89" dependencies = [ "crossterm", "futures-channel", "futures-util", "pin-project", "thingbuf", - "thiserror", + "thiserror 2.0.6", "unicode-segmentation", - "unicode-width 0.1.12", + "unicode-width 0.2.0", ] [[package]] @@ -5037,9 +5030,9 @@ dependencies = [ [[package]] name = "serde" -version = "1.0.215" +version = "1.0.216" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6513c1ad0b11a9376da888e3e0baa0077f1aed55c17f50e7b2397136129fb88f" +checksum = "0b9781016e935a97e8beecf0c933758c97a5520d32930e460142b4cd80c6338e" dependencies = [ "serde_derive", ] @@ -5063,13 +5056,13 @@ dependencies = [ [[package]] name = "serde_derive" -version = "1.0.215" +version = "1.0.216" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ad1e866f866923f252f05c889987993144fb74e722403468a4ebd70c3cd756c0" +checksum = "46f859dbbf73865c6627ed570e78961cd3ac92407a2d117204c49232485da55e" dependencies = [ "proc-macro2", "quote", - "syn 2.0.87", + "syn 2.0.90", ] [[package]] @@ -5078,7 +5071,7 @@ version = "1.0.133" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "c7fceb2473b9166b2294ef05efcb65a3db80803f0b03ef86a5fc88a2b85ee377" dependencies = [ - "indexmap 2.6.0", + "indexmap 2.7.0", "itoa", "memchr", "ryu", @@ -5103,7 +5096,7 @@ checksum = "0431a35568651e363364210c91983c1da5eb29404d9f0928b67d4ebcfa7d330c" dependencies = [ "percent-encoding", "serde", - "thiserror", + "thiserror 1.0.69", ] [[package]] @@ -5114,7 +5107,7 @@ checksum = "6c64451ba24fc7a6a2d60fc75dd9c83c90903b19028d4eff35e88fc1e86564e9" dependencies = [ "proc-macro2", "quote", - "syn 2.0.87", + "syn 2.0.90", ] [[package]] @@ -5148,7 +5141,7 @@ dependencies = [ "chrono", "hex", "indexmap 1.9.3", - "indexmap 2.6.0", + "indexmap 2.7.0", "serde", "serde_derive", "serde_json", @@ -5165,7 +5158,7 @@ dependencies = [ "darling", "proc-macro2", "quote", - "syn 2.0.87", + "syn 2.0.90", ] [[package]] @@ -5174,7 +5167,7 @@ version = "0.0.10" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "78ce6afeda22f0b55dde2c34897bce76a629587348480384231205c14b59a01f" dependencies = [ - "indexmap 2.6.0", + "indexmap 2.7.0", "itoa", "libyml", "log", @@ -5337,9 +5330,9 @@ checksum = "b7c388c1b5e93756d0c740965c41e8822f866621d41acbdf6336a6a168f8840c" [[package]] name = "socket2" -version = "0.5.7" +version = "0.5.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ce305eb0b4296696835b71df73eb912e0f1ffd2556a501fcede6e0c50349191c" +checksum = "c970269d99b64e60ec3bd6ad27270092a5394c4e309314b18ae3fe575695fbe8" dependencies = [ "libc", "windows-sys 0.52.0", @@ -5409,7 +5402,7 @@ dependencies = [ "futures-util", "hashlink", "hex", - "indexmap 2.6.0", + "indexmap 2.7.0", "log", "memchr", "once_cell", @@ -5422,7 +5415,7 @@ dependencies = [ "sha2 0.10.8", "smallvec", "sqlformat", - "thiserror", + "thiserror 1.0.69", "tokio", "tokio-stream", "tracing", @@ -5507,7 +5500,7 @@ dependencies = [ "smallvec", "sqlx-core", "stringprep", - "thiserror", + "thiserror 1.0.69", "tracing", "whoami", ] @@ -5546,7 +5539,7 @@ dependencies = [ "smallvec", "sqlx-core", "stringprep", - "thiserror", + "thiserror 1.0.69", "tracing", "whoami", ] @@ -5598,7 +5591,7 @@ dependencies = [ "quote", "regex-syntax 0.6.29", "strsim 0.10.0", - "syn 2.0.87", + "syn 2.0.90", "unicode-width 0.1.12", ] @@ -5692,14 +5685,14 @@ dependencies = [ "helpers", "hex", "hmac", - "http 1.1.0", + "http 1.2.0", "http-body-util", "hyper-util", "id-pool", "imbl", "imbl-value", "include_dir", - "indexmap 2.6.0", + "indexmap 2.7.0", "indicatif", "integer-encoding", "ipnet", @@ -5760,9 +5753,9 @@ dependencies = [ "ssh-key", "tar", "textwrap", - "thiserror", + "thiserror 1.0.69", "tokio", - "tokio-rustls 0.26.0", + "tokio-rustls 0.26.1", "tokio-socks", "tokio-stream", "tokio-tar", @@ -5849,9 +5842,9 @@ dependencies = [ [[package]] name = "syn" -version = "2.0.87" +version = "2.0.90" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "25aa4ce346d03a6dcd68dd8b4010bcb74e54e62c90c573f394c46eae99aba32d" +checksum = "919d3b74a5dd0ccd15aeb8f93e7006bd9e14c295087c9896a110f490752bcf31" dependencies = [ "proc-macro2", "quote", @@ -5866,9 +5859,9 @@ checksum = "2047c6ded9c721764247e62cd3b03c09ffc529b2ba5b10ec482ae507a4a70160" [[package]] name = "sync_wrapper" -version = "1.0.1" +version = "1.0.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a7065abeca94b6a8a577f9bd45aa0867a2238b74e8eb67cf10d492bc39351394" +checksum = "0bf256ce5efdfa370213c1dabab5935a12e49f2c58d15e9eac2870d3b4f27263" dependencies = [ "futures-core", ] @@ -5881,7 +5874,7 @@ checksum = "c8af7666ab7b6390ab78131fb5b0fce11d6b7a6951602017c35fa82800708971" dependencies = [ "proc-macro2", "quote", - "syn 2.0.87", + "syn 2.0.90", ] [[package]] @@ -5982,7 +5975,16 @@ version = "1.0.69" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b6aaf5339b578ea85b50e080feb250a3e8ae8cfcdff9a461c9ec2904bc923f52" dependencies = [ - "thiserror-impl", + "thiserror-impl 1.0.69", +] + +[[package]] +name = "thiserror" +version = "2.0.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8fec2a1820ebd077e2b90c4df007bebf344cd394098a13c563957d0afc83ea47" +dependencies = [ + "thiserror-impl 2.0.6", ] [[package]] @@ -5993,7 +5995,18 @@ checksum = "4fee6c4efc90059e10f81e6d42c60a18f76588c3d74cb83a0b242a2b6c7504c1" dependencies = [ "proc-macro2", "quote", - "syn 2.0.87", + "syn 2.0.90", +] + +[[package]] +name = "thiserror-impl" +version = "2.0.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d65750cab40f4ff1929fb1ba509e9914eb756131cef4210da8d5d700d26f6312" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.90", ] [[package]] @@ -6019,9 +6032,9 @@ dependencies = [ [[package]] name = "time" -version = "0.3.36" +version = "0.3.37" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5dfd88e563464686c916c7e46e623e520ddc6d79fa6641390f2e3fa86e83e885" +checksum = "35e7868883861bd0e56d9ac6efcaaca0d6d5d82a2a7ec8209ff492c07cf37b21" dependencies = [ "deranged", "itoa", @@ -6040,9 +6053,9 @@ checksum = "ef927ca75afb808a4d64dd374f00a2adf8d0fcff8e7b184af886c3c87ec4a3f3" [[package]] name = "time-macros" -version = "0.2.18" +version = "0.2.19" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3f252a68540fde3a3877aeea552b832b40ab9a69e318efd078774a01ddee1ccf" +checksum = "2834e6017e3e5e4b9834939793b282bc03b37a3336245fa820e35e233e2a85de" dependencies = [ "num-conv", "time-core", @@ -6084,9 +6097,9 @@ checksum = "1f3ccbac311fea05f86f61904b462b55fb3df8837a366dfc601a0161d0532f20" [[package]] name = "tokio" -version = "1.41.1" +version = "1.42.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "22cfb5bee7a6a52939ca9224d6ac897bb669134078daa8735560897f69de4d33" +checksum = "5cec9b21b0450273377fc97bd4c33a8acffc8c996c987a7c5b319a0083707551" dependencies = [ "backtrace", "bytes", @@ -6119,7 +6132,7 @@ checksum = "693d596312e88961bc67d7f1f97af8a70227d9f90c31bba5806eec004978d752" dependencies = [ "proc-macro2", "quote", - "syn 2.0.87", + "syn 2.0.90", ] [[package]] @@ -6145,12 +6158,11 @@ dependencies = [ [[package]] name = "tokio-rustls" -version = "0.26.0" +version = "0.26.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0c7bc40d0e5a97695bb96e27995cd3a08538541b0a846f65bba7a359f36700d4" +checksum = "5f6d0975eaace0cf0fcadee4e4aaa5da15b5c079146f2cffb67c113be122bf37" dependencies = [ - "rustls 0.23.17", - "rustls-pki-types", + "rustls 0.23.20", "tokio", ] @@ -6162,15 +6174,15 @@ checksum = "0d4770b8024672c1101b3f6733eab95b18007dbe0847a8afe341fcf79e06043f" dependencies = [ "either", "futures-util", - "thiserror", + "thiserror 1.0.69", "tokio", ] [[package]] name = "tokio-stream" -version = "0.1.16" +version = "0.1.17" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4f4e6ce100d0eb49a2734f8c0812bcd324cf357d21810932c5df6b96ef2b86f1" +checksum = "eca58d7bba4a75707817a2c44174253f9236b2d5fbd055602e9d5c07c139a047" dependencies = [ "futures-core", "pin-project-lite", @@ -6220,9 +6232,9 @@ dependencies = [ [[package]] name = "tokio-util" -version = "0.7.12" +version = "0.7.13" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "61e7c3654c13bcd040d4a03abee2c75b1d14a37b423cf5a813ceae1cc903ec6a" +checksum = "d7fcaa8d55a2bdd6b83ace262b016eca0d79ee02818c5c1bcdf0305114081078" dependencies = [ "bytes", "futures-core", @@ -6270,7 +6282,7 @@ version = "0.19.15" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "1b5bb770da30e5cbfde35a2d7b9b8a2c4b8ef89548a7a6aeab5c9a576e3e7421" dependencies = [ - "indexmap 2.6.0", + "indexmap 2.7.0", "serde", "serde_spanned", "toml_datetime", @@ -6283,7 +6295,7 @@ version = "0.22.22" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "4ae48d6208a266e853d946088ed816055e556cc6028c5e8e2b84d9fa5dd7c7f5" dependencies = [ - "indexmap 2.6.0", + "indexmap 2.7.0", "serde", "serde_spanned", "toml_datetime", @@ -6358,14 +6370,14 @@ dependencies = [ [[package]] name = "tower" -version = "0.5.1" +version = "0.5.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2873938d487c3cfb9aed7546dc9f2711d867c9f90c46b889989a2cb84eba6b4f" +checksum = "d039ad9159c98b70ecfd540b2573b97f7f52c3e8d9f8ad57a24b916a536975f9" dependencies = [ "futures-core", "futures-util", "pin-project-lite", - "sync_wrapper 0.1.2", + "sync_wrapper 1.0.2", "tokio", "tower-layer", "tower-service", @@ -6386,9 +6398,9 @@ checksum = "8df9b6e13f2d32c91b9bd719c00d1958837bc7dec474d94952798cc8e69eeec3" [[package]] name = "tracing" -version = "0.1.40" +version = "0.1.41" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c3523ab5a71916ccf420eebdf5521fcef02141234bbc0b8a49f2fdc4544364ef" +checksum = "784e0ac535deb450455cbfa28a6f0df145ea1bb7ae51b821cf5e7927fdcfbdd0" dependencies = [ "log", "pin-project-lite", @@ -6398,20 +6410,20 @@ dependencies = [ [[package]] name = "tracing-attributes" -version = "0.1.27" +version = "0.1.28" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "34704c8d6ebcbc939824180af020566b01a7c01f80641264eba0999f6c2b6be7" +checksum = "395ae124c09f9e6918a2310af6038fba074bcf474ac352496d5910dd59a2226d" dependencies = [ "proc-macro2", "quote", - "syn 2.0.87", + "syn 2.0.90", ] [[package]] name = "tracing-core" -version = "0.1.32" +version = "0.1.33" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c06d3da6113f116aaee68e4d601191614c9053067f9ab7f6edbcb161237daa54" +checksum = "e672c95779cf947c5311f83787af4fa8fffd12fb27e4993211a84bdfd9610f9c" dependencies = [ "once_cell", "valuable", @@ -6419,9 +6431,9 @@ dependencies = [ [[package]] name = "tracing-error" -version = "0.2.0" +version = "0.2.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d686ec1c0f384b1277f097b2f279a2ecc11afe8c133c1aabf036a27cb4cd206e" +checksum = "8b1581020d7a273442f5b45074a6a57d5757ad0a47dac0e9f0bd57b81936f3db" dependencies = [ "tracing", "tracing-subscriber", @@ -6439,9 +6451,9 @@ dependencies = [ [[package]] name = "tracing-journald" -version = "0.3.0" +version = "0.3.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ba316a74e8fc3c3896a850dba2375928a9fa171b085ecddfc7c054d39970f3fd" +checksum = "fc0b4143302cf1022dac868d521e36e8b27691f72c84b3311750d5188ebba657" dependencies = [ "libc", "tracing-core", @@ -6461,9 +6473,9 @@ dependencies = [ [[package]] name = "tracing-subscriber" -version = "0.3.18" +version = "0.3.19" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ad0f048c97dbd9faa9b7df56362b8ebcaa52adb06b498c050d2f4e32f90a7a8b" +checksum = "e8189decb5ac0fa7bc8b96b7cb9b2701d60d48805aca84a238004d665fcc4008" dependencies = [ "matchers", "nu-ansi-term", @@ -6504,7 +6516,7 @@ dependencies = [ "once_cell", "rand 0.8.5", "smallvec", - "thiserror", + "thiserror 1.0.69", "tinyvec", "tokio", "tracing", @@ -6525,7 +6537,7 @@ dependencies = [ "futures-executor", "futures-util", "serde", - "thiserror", + "thiserror 1.0.69", "time", "tokio", "toml 0.7.8", @@ -6544,7 +6556,7 @@ name = "ts-rs" version = "8.1.0" source = "git+https://github.com/dr-bonez/ts-rs.git?branch=feature%2Ftop-level-as#7ae88ade90b5e724159048a663a0bdb04bed27f7" dependencies = [ - "thiserror", + "thiserror 1.0.69", "ts-rs-macros", ] @@ -6556,7 +6568,7 @@ dependencies = [ "Inflector", "proc-macro2", "quote", - "syn 2.0.87", + "syn 2.0.90", "termcolor", ] @@ -6580,13 +6592,13 @@ dependencies = [ "byteorder", "bytes", "data-encoding", - "http 1.1.0", + "http 1.2.0", "httparse", "log", "native-tls", "rand 0.8.5", "sha1", - "thiserror", + "thiserror 1.0.69", "url", "utf-8", ] @@ -6600,12 +6612,12 @@ dependencies = [ "byteorder", "bytes", "data-encoding", - "http 1.1.0", + "http 1.2.0", "httparse", "log", "rand 0.8.5", "sha1", - "thiserror", + "thiserror 1.0.69", "utf-8", ] @@ -6626,7 +6638,7 @@ checksum = "1f718dfaf347dcb5b983bfc87608144b0bad87970aebcbea5ce44d2a30c08e63" dependencies = [ "proc-macro2", "quote", - "syn 2.0.87", + "syn 2.0.90", ] [[package]] @@ -6672,9 +6684,9 @@ checksum = "5ab17db44d7388991a428b2ee655ce0c212e862eff1768a455c58f9aad6e7893" [[package]] name = "unicode-ident" -version = "1.0.13" +version = "1.0.14" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e91b56cd4cadaeb79bbf1a5645f6b4f8dc5bde8834ad5894a8db35fda9efa1fe" +checksum = "adb9e6ca4f869e1180728b7950e35922a7fc6397f7b641499e8f3ef06e50dc83" [[package]] name = "unicode-linebreak" @@ -6745,9 +6757,9 @@ checksum = "8ecb6da28b8a351d773b68d5825ac39017e680750f980f3a1a85cd8dd28a47c1" [[package]] name = "url" -version = "2.5.3" +version = "2.5.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8d157f1b96d14500ffdc1f10ba712e780825526c03d9a49b4d0324b0d9113ada" +checksum = "32f8b686cadd1473f4bd0117a5d28d36b1ade384ea9b5069a1c40aefed7fda60" dependencies = [ "form_urlencoded", "idna 1.0.3", @@ -6860,9 +6872,9 @@ checksum = "b8dad83b4f25e74f184f64c43b150b91efe7647395b42289f38e50566d82855b" [[package]] name = "wasm-bindgen" -version = "0.2.95" +version = "0.2.99" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "128d1e363af62632b8eb57219c8fd7877144af57558fb2ef0368d0087bddeb2e" +checksum = "a474f6281d1d70c17ae7aa6a613c87fce69a127e2624002df63dcb39d6cf6396" dependencies = [ "cfg-if", "once_cell", @@ -6871,36 +6883,36 @@ dependencies = [ [[package]] name = "wasm-bindgen-backend" -version = "0.2.95" +version = "0.2.99" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cb6dd4d3ca0ddffd1dd1c9c04f94b868c37ff5fac97c30b97cff2d74fce3a358" +checksum = "5f89bb38646b4f81674e8f5c3fb81b562be1fd936d84320f3264486418519c79" dependencies = [ "bumpalo", "log", - "once_cell", "proc-macro2", "quote", - "syn 2.0.87", + "syn 2.0.90", "wasm-bindgen-shared", ] [[package]] name = "wasm-bindgen-futures" -version = "0.4.45" +version = "0.4.49" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cc7ec4f8827a71586374db3e87abdb5a2bb3a15afed140221307c3ec06b1f63b" +checksum = "38176d9b44ea84e9184eff0bc34cc167ed044f816accfe5922e54d84cf48eca2" dependencies = [ "cfg-if", "js-sys", + "once_cell", "wasm-bindgen", "web-sys", ] [[package]] name = "wasm-bindgen-macro" -version = "0.2.95" +version = "0.2.99" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e79384be7f8f5a9dd5d7167216f022090cf1f9ec128e6e6a482a2cb5c5422c56" +checksum = "2cc6181fd9a7492eef6fef1f33961e3695e4579b9872a6f7c83aee556666d4fe" dependencies = [ "quote", "wasm-bindgen-macro-support", @@ -6908,22 +6920,22 @@ dependencies = [ [[package]] name = "wasm-bindgen-macro-support" -version = "0.2.95" +version = "0.2.99" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "26c6ab57572f7a24a4985830b120de1594465e5d500f24afe89e16b4e833ef68" +checksum = "30d7a95b763d3c45903ed6c81f156801839e5ee968bb07e534c44df0fcd330c2" dependencies = [ "proc-macro2", "quote", - "syn 2.0.87", + "syn 2.0.90", "wasm-bindgen-backend", "wasm-bindgen-shared", ] [[package]] name = "wasm-bindgen-shared" -version = "0.2.95" +version = "0.2.99" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "65fc09f10666a9f147042251e0dda9c18f166ff7de300607007e96bdebc1068d" +checksum = "943aab3fdaaa029a6e0271b35ea10b72b943135afe9bffca82384098ad0e06a6" [[package]] name = "wasm-streams" @@ -6940,9 +6952,9 @@ dependencies = [ [[package]] name = "web-sys" -version = "0.3.72" +version = "0.3.76" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f6488b90108c040df0fe62fa815cbdee25124641df01814dd7282749234c6112" +checksum = "04dd7223427d52553d3702c004d3b2fe07c148165faa56313cb00211e31c12bc" dependencies = [ "js-sys", "wasm-bindgen", @@ -6966,9 +6978,9 @@ checksum = "5f20c57d8d7db6d3b86154206ae5d8fba62dd39573114de97c2cb0578251f8e1" [[package]] name = "webpki-roots" -version = "0.26.6" +version = "0.26.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "841c67bff177718f1d4dfefde8d8f0e78f9b6589319ba88312f567fc5841a958" +checksum = "5d642ff16b7e79272ae451b7322067cdc17cadf68c23264be9d94a32319efe7e" dependencies = [ "rustls-pki-types", ] @@ -6991,7 +7003,7 @@ version = "1.5.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "372d5b87f58ec45c384ba03563b03544dc5fadc3983e434b286913f5b4a9bb6d" dependencies = [ - "redox_syscall 0.5.7", + "redox_syscall 0.5.8", "wasite", ] @@ -7271,7 +7283,7 @@ dependencies = [ "nom 7.1.3", "oid-registry", "rusticata-macros", - "thiserror", + "thiserror 1.0.69", "time", ] @@ -7323,7 +7335,7 @@ dependencies = [ "anyhow", "serde", "serde_json", - "thiserror", + "thiserror 1.0.69", ] [[package]] @@ -7349,9 +7361,9 @@ dependencies = [ [[package]] name = "yoke" -version = "0.7.4" +version = "0.7.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6c5b1314b079b0930c31e3af543d8ee1757b1951ae1e1565ec704403a7240ca5" +checksum = "120e6aef9aa629e3d4f52dc8cc43a015c7724194c97dfaf45180d2daf2b77f40" dependencies = [ "serde", "stable_deref_trait", @@ -7361,13 +7373,13 @@ dependencies = [ [[package]] name = "yoke-derive" -version = "0.7.4" +version = "0.7.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "28cc31741b18cb6f1d5ff12f5b7523e3d6eb0852bbbad19d73905511d9849b95" +checksum = "2380878cad4ac9aac1e2435f3eb4020e8374b5f13c296cb75b4620ff8e229154" dependencies = [ "proc-macro2", "quote", - "syn 2.0.87", + "syn 2.0.90", "synstructure", ] @@ -7416,7 +7428,7 @@ dependencies = [ "proc-macro-crate", "proc-macro2", "quote", - "syn 2.0.87", + "syn 2.0.90", "zbus_names", "zvariant", "zvariant_utils", @@ -7452,27 +7464,27 @@ checksum = "fa4f8080344d4671fb4e831a13ad1e68092748387dfc4f55e356242fae12ce3e" dependencies = [ "proc-macro2", "quote", - "syn 2.0.87", + "syn 2.0.90", ] [[package]] name = "zerofrom" -version = "0.1.4" +version = "0.1.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "91ec111ce797d0e0784a1116d0ddcdbea84322cd79e5d5ad173daeba4f93ab55" +checksum = "cff3ee08c995dee1859d998dea82f7374f2826091dd9cd47def953cae446cd2e" dependencies = [ "zerofrom-derive", ] [[package]] name = "zerofrom-derive" -version = "0.1.4" +version = "0.1.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0ea7b4a3637ea8669cedf0f1fd5c286a17f3de97b8dd5a70a6c167a1730e63a5" +checksum = "595eed982f7d355beb85837f651fa22e90b3c044842dc7f2c2842c086f295808" dependencies = [ "proc-macro2", "quote", - "syn 2.0.87", + "syn 2.0.90", "synstructure", ] @@ -7493,7 +7505,7 @@ checksum = "ce36e65b0d2999d2aafac989fb249189a141aee1f53c612c1f37d72631959f69" dependencies = [ "proc-macro2", "quote", - "syn 2.0.87", + "syn 2.0.90", ] [[package]] @@ -7515,7 +7527,7 @@ checksum = "6eafa6dfb17584ea3e2bd6e76e0cc15ad7af12b09abdd1ca55961bed9b1063c6" dependencies = [ "proc-macro2", "quote", - "syn 2.0.87", + "syn 2.0.90", ] [[package]] @@ -7570,7 +7582,7 @@ dependencies = [ "proc-macro-crate", "proc-macro2", "quote", - "syn 2.0.87", + "syn 2.0.90", "zvariant_utils", ] @@ -7584,6 +7596,6 @@ dependencies = [ "quote", "serde", "static_assertions", - "syn 2.0.87", + "syn 2.0.90", "winnow 0.6.20", ] diff --git a/core/startos/Cargo.toml b/core/startos/Cargo.toml index a9d7bb1fca..7ee26dbcad 100644 --- a/core/startos/Cargo.toml +++ b/core/startos/Cargo.toml @@ -50,7 +50,7 @@ test = [] [dependencies] aes = { version = "0.7.5", features = ["ctr"] } -async-acme = { version = "0.5.0", git = "https://github.com/dr-bonez/async-acme.git", features = [ +async-acme = { version = "0.6.0", git = "https://github.com/dr-bonez/async-acme.git", features = [ "use_rustls", "use_tokio", ] } diff --git a/core/startos/src/db/model/public.rs b/core/startos/src/db/model/public.rs index 972d0e8e81..3463d4db68 100644 --- a/core/startos/src/db/model/public.rs +++ b/core/startos/src/db/model/public.rs @@ -1,10 +1,10 @@ use std::collections::{BTreeMap, BTreeSet}; -use std::net::{IpAddr, Ipv4Addr, Ipv6Addr}; +use std::net::{IpAddr, Ipv4Addr}; use chrono::{DateTime, Utc}; use exver::{Version, VersionRange}; use imbl_value::InternedString; -use ipnet::{IpNet, Ipv4Net, Ipv6Net}; +use ipnet::IpNet; use isocountry::CountryCode; use itertools::Itertools; use models::PackageId; @@ -17,7 +17,7 @@ use ts_rs::TS; use crate::account::AccountInfo; use crate::db::model::package::AllPackageData; -use crate::net::utils::{get_iface_ipv4_addr, get_iface_ipv6_addr}; +use crate::net::acme::AcmeProvider; use crate::prelude::*; use crate::progress::FullProgress; use crate::system::SmtpValue; @@ -55,7 +55,7 @@ impl Public { .parse() .unwrap(), network_interfaces: BTreeMap::new(), - acme: None, + acme: BTreeMap::new(), status_info: ServerStatus { backup_progress: None, updated: false, @@ -133,7 +133,8 @@ pub struct ServerInfo { #[ts(as = "BTreeMap::")] #[serde(default)] pub network_interfaces: BTreeMap, - pub acme: Option, + #[serde(default)] + pub acme: BTreeMap, #[serde(default)] pub status_info: ServerStatus, pub wifi: WifiInfo, @@ -167,7 +168,9 @@ impl NetworkInterfaceInfo { !self.ip_info.as_ref().map_or(true, |ip_info| { ip_info.subnets.iter().all(|ipnet| { if let IpAddr::V4(ip4) = ipnet.addr() { - ip4.is_loopback() || ip4.is_private() || ip4.is_link_local() + ip4.is_loopback() + || (ip4.is_private() && !ip4.octets().starts_with(&[10, 59])) // reserving 10.59 for public wireguard configurations + || ip4.is_link_local() } else { true } @@ -185,6 +188,8 @@ pub struct IpInfo { #[ts(type = "string[]")] pub subnets: BTreeSet, pub wan_ip: Option, + #[ts(type = "string[]")] + pub ntp_servers: BTreeSet, } #[derive(Debug, Deserialize, Serialize, HasModel, TS)] @@ -192,13 +197,7 @@ pub struct IpInfo { #[model = "Model"] #[ts(export)] pub struct AcmeSettings { - #[ts(type = "string")] - pub provider: Url, - /// email addresses for letsencrypt pub contact: Vec, - #[ts(type = "string[]")] - /// domains to get letsencrypt certs for - pub domains: BTreeSet, } #[derive(Debug, Default, Deserialize, Serialize, HasModel, TS)] diff --git a/core/startos/src/net/acme.rs b/core/startos/src/net/acme.rs index 95f9d4adb8..5d8da41f16 100644 --- a/core/startos/src/net/acme.rs +++ b/core/startos/src/net/acme.rs @@ -1,6 +1,7 @@ use std::collections::{BTreeMap, BTreeSet}; use std::str::FromStr; +use async_acme::acme::Identifier; use clap::builder::ValueParserFactory; use clap::Parser; use imbl_value::InternedString; @@ -10,6 +11,7 @@ use openssl::pkey::{PKey, Private}; use openssl::x509::X509; use rpc_toolkit::{from_fn_async, Context, HandlerExt, ParentHandler}; use serde::{Deserialize, Serialize}; +use ts_rs::TS; use url::Url; use crate::context::{CliContext, RpcContext}; @@ -78,10 +80,18 @@ impl<'a> async_acme::cache::AcmeCache for AcmeCertCache<'a> { async fn read_certificate( &self, - domains: &[String], + identifiers: &[Identifier], directory_url: &str, ) -> Result, Self::Error> { - let domains = JsonKey::new(domains.into_iter().map(InternedString::intern).collect()); + let identifiers = JsonKey::new( + identifiers + .into_iter() + .map(|d| match d { + Identifier::Dns(d) => d.into(), + Identifier::Ip(ip) => InternedString::from_display(ip), + }) + .collect(), + ); let directory_url = directory_url .parse::() .with_kind(ErrorKind::ParseUrl)?; @@ -94,7 +104,7 @@ impl<'a> async_acme::cache::AcmeCache for AcmeCertCache<'a> { .into_acme() .into_certs() .into_idx(&directory_url) - .and_then(|a| a.into_idx(&domains)) + .and_then(|a| a.into_idx(&identifiers)) else { return Ok(None); }; @@ -120,13 +130,21 @@ impl<'a> async_acme::cache::AcmeCache for AcmeCertCache<'a> { async fn write_certificate( &self, - domains: &[String], + identifiers: &[Identifier], directory_url: &str, key_pem: &str, certificate_pem: &str, ) -> Result<(), Self::Error> { - tracing::info!("Saving new certificate for {domains:?}"); - let domains = JsonKey::new(domains.into_iter().map(InternedString::intern).collect()); + tracing::info!("Saving new certificate for {identifiers:?}"); + let identifiers = JsonKey::new( + identifiers + .into_iter() + .map(|d| match d { + Identifier::Dns(d) => d.into(), + Identifier::Ip(ip) => InternedString::from_display(ip), + }) + .collect(), + ); let directory_url = directory_url .parse::() .with_kind(ErrorKind::ParseUrl)?; @@ -146,7 +164,7 @@ impl<'a> async_acme::cache::AcmeCache for AcmeCertCache<'a> { .as_acme_mut() .as_certs_mut() .upsert(&directory_url, || Ok(BTreeMap::new()))? - .insert(&domains, &cert) + .insert(&identifiers, &cert) }) .await?; @@ -155,22 +173,17 @@ impl<'a> async_acme::cache::AcmeCache for AcmeCertCache<'a> { } pub fn acme() -> ParentHandler { - ParentHandler::new() - .subcommand( - "init", - from_fn_async(init) - .no_display() - .with_about("Setup ACME certificate acquisition") - .with_call_remote::(), - ) - .subcommand( - "domain", - domain::() - .with_about("Add, remove, or view domains for which to acquire ACME certificates"), - ) + ParentHandler::new().subcommand( + "init", + from_fn_async(init) + .no_display() + .with_about("Setup ACME certificate acquisition") + .with_call_remote::(), + ) } -#[derive(Clone, Deserialize, Serialize)] +#[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord, Deserialize, Serialize, TS)] +#[ts(type = "string")] pub struct AcmeProvider(pub Url); impl FromStr for AcmeProvider { type Err = ::Err; @@ -183,6 +196,11 @@ impl FromStr for AcmeProvider { .map(Self) } } +impl AsRef for AcmeProvider { + fn as_ref(&self) -> &str { + self.0.as_str() + } +} impl ValueParserFactory for AcmeProvider { type Parser = FromStrParser; fn value_parser() -> Self::Parser { @@ -200,125 +218,15 @@ pub struct InitAcmeParams { pub async fn init( ctx: RpcContext, - InitAcmeParams { - provider: AcmeProvider(provider), - contact, - }: InitAcmeParams, + InitAcmeParams { provider, contact }: InitAcmeParams, ) -> Result<(), Error> { ctx.db .mutate(|db| { db.as_public_mut() .as_server_info_mut() .as_acme_mut() - .map_mutate(|acme| { - Ok(Some(AcmeSettings { - provider, - contact, - domains: acme.map(|acme| acme.domains).unwrap_or_default(), - })) - }) + .insert(&provider, &AcmeSettings { contact }) }) .await?; Ok(()) } - -pub fn domain() -> ParentHandler { - ParentHandler::new() - .subcommand( - "add", - from_fn_async(add_domain) - .no_display() - .with_about("Add a domain for which to acquire ACME certificates") - .with_call_remote::(), - ) - .subcommand( - "remove", - from_fn_async(remove_domain) - .no_display() - .with_about("Remove a domain for which to acquire ACME certificates") - .with_call_remote::(), - ) - .subcommand( - "list", - from_fn_async(list_domains) - .with_custom_display_fn(|_, res| { - for domain in res { - println!("{domain}") - } - Ok(()) - }) - .with_about("List domains for which to acquire ACME certificates") - .with_call_remote::(), - ) -} - -#[derive(Deserialize, Serialize, Parser)] -pub struct DomainParams { - pub domain: InternedString, -} - -pub async fn add_domain( - ctx: RpcContext, - DomainParams { domain }: DomainParams, -) -> Result<(), Error> { - ctx.db - .mutate(|db| { - db.as_public_mut() - .as_server_info_mut() - .as_acme_mut() - .transpose_mut() - .ok_or_else(|| { - Error::new( - eyre!("Please call `start-cli net acme init` before adding a domain"), - ErrorKind::InvalidRequest, - ) - })? - .as_domains_mut() - .mutate(|domains| { - domains.insert(domain); - Ok(()) - }) - }) - .await?; - Ok(()) -} - -pub async fn remove_domain( - ctx: RpcContext, - DomainParams { domain }: DomainParams, -) -> Result<(), Error> { - ctx.db - .mutate(|db| { - if let Some(acme) = db - .as_public_mut() - .as_server_info_mut() - .as_acme_mut() - .transpose_mut() - { - acme.as_domains_mut().mutate(|domains| { - domains.remove(&domain); - Ok(()) - }) - } else { - Ok(()) - } - }) - .await?; - Ok(()) -} - -pub async fn list_domains(ctx: RpcContext) -> Result, Error> { - if let Some(acme) = ctx - .db - .peek() - .await - .into_public() - .into_server_info() - .into_acme() - .transpose() - { - acme.into_domains().de() - } else { - Ok(BTreeSet::new()) - } -} diff --git a/core/startos/src/net/host/address.rs b/core/startos/src/net/host/address.rs index 05942ffa93..3d639b31e6 100644 --- a/core/startos/src/net/host/address.rs +++ b/core/startos/src/net/host/address.rs @@ -1,57 +1,298 @@ -use std::fmt; -use std::str::FromStr; - -use clap::builder::ValueParserFactory; +use clap::Parser; use imbl_value::InternedString; -use models::FromStrParser; +use models::{HostId, PackageId}; +use rpc_toolkit::{from_fn_async, Context, Empty, HandlerArgs, HandlerExt, ParentHandler}; use serde::{Deserialize, Serialize}; use torut::onion::OnionAddressV3; use ts_rs::TS; +use crate::context::{CliContext, RpcContext}; +use crate::net::acme::AcmeProvider; use crate::prelude::*; +use crate::util::serde::{display_serializable, HandlerExtSerde}; -#[derive(Clone, Debug, Deserialize, Serialize, PartialEq, Eq, PartialOrd, Ord, TS)] -#[serde(rename_all = "camelCase")] -#[serde(tag = "kind")] -#[ts(export)] +#[derive(Clone, Debug, Deserialize, Serialize)] pub enum HostAddress { Onion { - #[ts(type = "string")] address: OnionAddressV3, }, Domain { - #[ts(type = "string")] address: InternedString, + public: bool, + acme: Option, }, } -impl FromStr for HostAddress { - type Err = Error; - fn from_str(s: &str) -> Result { - if let Some(addr) = s.strip_suffix(".onion") { - Ok(HostAddress::Onion { - address: addr - .parse::() - .with_kind(ErrorKind::ParseUrl)?, - }) - } else { - Ok(HostAddress::Domain { address: s.into() }) - } - } -} - -impl fmt::Display for HostAddress { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - match self { - Self::Onion { address } => write!(f, "{address}"), - Self::Domain { address } => write!(f, "{address}"), - } - } -} - -impl ValueParserFactory for HostAddress { - type Parser = FromStrParser; - fn value_parser() -> Self::Parser { - Self::Parser::new() - } +#[derive(Debug, Deserialize, Serialize, TS)] +pub struct DomainConfig { + pub public: bool, + pub acme: Option, +} + +#[derive(Deserialize, Serialize, Parser)] +pub struct AddressApiParams { + host: HostId, +} + +pub fn address() -> ParentHandler { + ParentHandler::::new() + .subcommand( + "domain", + ParentHandler::::new() + .subcommand( + "add", + from_fn_async(add_domain) + .with_inherited(|_, a| a) + .no_display() + .with_about("Add an address to this host") + .with_call_remote::(), + ) + .subcommand( + "remove", + from_fn_async(remove_domain) + .with_inherited(|_, a| a) + .no_display() + .with_about("Remove an address from this host") + .with_call_remote::(), + ) + .with_inherited(|AddressApiParams { host }, package| (package, host)), + ) + .subcommand( + "onion", + ParentHandler::::new() + .subcommand( + "add", + from_fn_async(add_onion) + .with_inherited(|_, a| a) + .no_display() + .with_about("Add an address to this host") + .with_call_remote::(), + ) + .subcommand( + "remove", + from_fn_async(remove_onion) + .with_inherited(|_, a| a) + .no_display() + .with_about("Remove an address from this host") + .with_call_remote::(), + ) + .with_inherited(|AddressApiParams { host }, package| (package, host)), + ) + .subcommand( + "list", + from_fn_async(list_addresses) + .with_inherited(|AddressApiParams { host }, package| (package, host)) + .with_display_serializable() + .with_custom_display_fn(|HandlerArgs { params, .. }, res| { + use prettytable::*; + + if let Some(format) = params.format { + display_serializable(format, res); + return Ok(()); + } + + let mut table = Table::new(); + table.add_row(row![bc => "ADDRESS", "PUBLIC", "ACME PROVIDER"]); + for address in &res { + match address { + HostAddress::Onion { address } => { + table.add_row(row![address, true, "N/A"]); + } + HostAddress::Domain { + address, + public, + acme, + } => { + table.add_row(row![ + address, + *public, + acme.as_ref().map(|a| a.0.as_str()).unwrap_or("NONE") + ]); + } + } + } + + table.print_tty(false)?; + + Ok(()) + }) + .with_about("List addresses for this host") + .with_call_remote::(), + ) +} + +#[derive(Deserialize, Serialize, Parser)] +pub struct AddDomainParams { + pub domain: InternedString, + #[arg(long)] + pub private: bool, + #[arg(long)] + pub acme: Option, +} + +pub async fn add_domain( + ctx: RpcContext, + AddDomainParams { + domain, + private, + acme, + }: AddDomainParams, + (package, host): (PackageId, HostId), +) -> Result<(), Error> { + ctx.db + .mutate(|db| { + if let Some(acme) = &acme { + if !db.as_public().as_server_info().as_acme().contains_key(&acme)? { + return Err(Error::new(eyre!("unknown acme provider {}, please run acme.init for this provider first", acme.0), ErrorKind::InvalidRequest)); + } + } + + db.as_public_mut() + .as_package_data_mut() + .as_idx_mut(&package) + .or_not_found(&package)? + .as_hosts_mut() + .as_idx_mut(&host) + .or_not_found(&host)? + .as_domains_mut() + .insert( + &domain, + &DomainConfig { + public: !private, + acme, + }, + ) + }) + .await?; + let service = ctx.services.get(&package).await; + let service_ref = service.as_ref().or_not_found(&package)?; + service_ref.update_host(host).await?; + + Ok(()) +} + +#[derive(Deserialize, Serialize, Parser)] +pub struct RemoveDomainParams { + pub domain: InternedString, +} + +pub async fn remove_domain( + ctx: RpcContext, + RemoveDomainParams { domain }: RemoveDomainParams, + (package, host): (PackageId, HostId), +) -> Result<(), Error> { + ctx.db + .mutate(|db| { + db.as_public_mut() + .as_package_data_mut() + .as_idx_mut(&package) + .or_not_found(&package)? + .as_hosts_mut() + .as_idx_mut(&host) + .or_not_found(&host)? + .as_domains_mut() + .remove(&domain) + }) + .await?; + let service = ctx.services.get(&package).await; + let service_ref = service.as_ref().or_not_found(&package)?; + service_ref.update_host(host).await?; + + Ok(()) +} + +#[derive(Deserialize, Serialize, Parser)] +pub struct OnionParams { + pub onion: String, +} + +pub async fn add_onion( + ctx: RpcContext, + OnionParams { onion }: OnionParams, + (package, host): (PackageId, HostId), +) -> Result<(), Error> { + let onion = onion + .strip_suffix(".onion") + .ok_or_else(|| { + Error::new( + eyre!("onion hostname must end in .onion"), + ErrorKind::InvalidOnionAddress, + ) + })? + .parse::()?; + ctx.db + .mutate(|db| { + db.as_private().as_key_store().as_onion().get_key(&onion)?; + + db.as_public_mut() + .as_package_data_mut() + .as_idx_mut(&package) + .or_not_found(&package)? + .as_hosts_mut() + .as_idx_mut(&host) + .or_not_found(&host)? + .as_onions_mut() + .mutate(|a| Ok(a.insert(onion))) + }) + .await?; + let service = ctx.services.get(&package).await; + let service_ref = service.as_ref().or_not_found(&package)?; + service_ref.update_host(host).await?; + + Ok(()) +} + +pub async fn remove_onion( + ctx: RpcContext, + OnionParams { onion }: OnionParams, + (package, host): (PackageId, HostId), +) -> Result<(), Error> { + let onion = onion + .strip_suffix(".onion") + .ok_or_else(|| { + Error::new( + eyre!("onion hostname must end in .onion"), + ErrorKind::InvalidOnionAddress, + ) + })? + .parse::()?; + ctx.db + .mutate(|db| { + db.as_public_mut() + .as_package_data_mut() + .as_idx_mut(&package) + .or_not_found(&package)? + .as_hosts_mut() + .as_idx_mut(&host) + .or_not_found(&host)? + .as_onions_mut() + .mutate(|a| Ok(a.remove(&onion))) + }) + .await?; + let service = ctx.services.get(&package).await; + let service_ref = service.as_ref().or_not_found(&package)?; + service_ref.update_host(host).await?; + + Ok(()) +} + +pub async fn list_addresses( + ctx: RpcContext, + _: Empty, + (package, host): (PackageId, HostId), +) -> Result, Error> { + Ok(ctx + .db + .peek() + .await + .into_public() + .into_package_data() + .into_idx(&package) + .or_not_found(&package)? + .into_hosts() + .into_idx(&host) + .or_not_found(&host)? + .de()? + .addresses() + .collect()) } diff --git a/core/startos/src/net/host/binding.rs b/core/startos/src/net/host/binding.rs index 41261b7c61..d56f607a9e 100644 --- a/core/startos/src/net/host/binding.rs +++ b/core/startos/src/net/host/binding.rs @@ -1,13 +1,18 @@ +use std::collections::BTreeMap; use std::str::FromStr; use clap::builder::ValueParserFactory; -use models::{FromStrParser, HostId}; +use clap::Parser; +use models::{FromStrParser, HostId, PackageId}; +use rpc_toolkit::{from_fn_async, Context, Empty, HandlerArgs, HandlerExt, ParentHandler}; use serde::{Deserialize, Serialize}; use ts_rs::TS; +use crate::context::{CliContext, RpcContext}; use crate::net::forward::AvailablePorts; use crate::net::vhost::AlpnInfo; use crate::prelude::*; +use crate::util::serde::{display_serializable, HandlerExtSerde}; #[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord, Serialize, Deserialize, TS)] #[ts(export)] @@ -140,3 +145,122 @@ pub struct AddSslOptions { // pub add_x_forwarded_headers: bool, // TODO pub alpn: Option, } + +#[derive(Deserialize, Serialize, Parser)] +pub struct BindingApiParams { + host: HostId, +} + +pub fn binding() -> ParentHandler { + ParentHandler::::new() + .subcommand( + "list", + from_fn_async(list_bindings) + .with_inherited(|BindingApiParams { host }, package| (package, host)) + .with_display_serializable() + .with_custom_display_fn(|HandlerArgs { params, .. }, res| { + use prettytable::*; + + if let Some(format) = params.format { + return Ok(display_serializable(format, res)); + } + + let mut table = Table::new(); + table.add_row(row![bc => "INTERNAL PORT", "ENABLED", "PUBLIC", "EXTERNAL PORT", "EXTERNAL SSL PORT"]); + for (internal, info) in res { + table.add_row(row![ + internal, + info.enabled, + info.net.public, + if let Some(port) = info.net.assigned_port { + port.to_string() + } else { + "N/A".to_owned() + }, + if let Some(port) = info.net.assigned_ssl_port { + port.to_string() + } else { + "N/A".to_owned() + }, + ]); + } + + table.print_tty(false).unwrap(); + + Ok(()) + }) + .with_about("List bindinges for this host") + .with_call_remote::(), + ) + .subcommand( + "set-public", + from_fn_async(set_public) + .with_inherited(|BindingApiParams { host }, package| (package, host)) + .no_display() + .with_about("Add an binding to this host") + .with_call_remote::(), + ) +} + +pub async fn list_bindings( + ctx: RpcContext, + _: Empty, + (package, host): (PackageId, HostId), +) -> Result, Error> { + ctx.db + .peek() + .await + .into_public() + .into_package_data() + .into_idx(&package) + .or_not_found(&package)? + .into_hosts() + .into_idx(&host) + .or_not_found(&host)? + .into_bindings() + .de() +} + +#[derive(Deserialize, Serialize, Parser)] +#[serde(rename_all = "camelCase")] +pub struct SetPublicParams { + internal_port: u16, + #[arg(long)] + public: Option, +} + +pub async fn set_public( + ctx: RpcContext, + SetPublicParams { + internal_port, + public, + }: SetPublicParams, + (package, host): (PackageId, HostId), +) -> Result<(), Error> { + ctx.db + .mutate(|db| { + db.as_public_mut() + .as_package_data_mut() + .as_idx_mut(&package) + .or_not_found(&package)? + .as_hosts_mut() + .as_idx_mut(&host) + .or_not_found(&host)? + .as_bindings_mut() + .mutate(|b| { + b.get_mut(&internal_port) + .or_not_found(internal_port)? + .net + .public = public.unwrap_or(true); + Ok(()) + }) + }) + .await?; + ctx.services + .get(&package) + .await + .as_ref() + .or_not_found(&package)? + .update_host(host) + .await +} diff --git a/core/startos/src/net/host/mod.rs b/core/startos/src/net/host/mod.rs index be5db0f2d5..a9ae31c8f3 100644 --- a/core/startos/src/net/host/mod.rs +++ b/core/startos/src/net/host/mod.rs @@ -5,13 +5,14 @@ use imbl_value::InternedString; use models::{HostId, PackageId}; use rpc_toolkit::{from_fn_async, Context, Empty, HandlerExt, ParentHandler}; use serde::{Deserialize, Serialize}; +use torut::onion::OnionAddressV3; use ts_rs::TS; -use crate::context::{CliContext, RpcContext}; +use crate::context::RpcContext; use crate::db::model::DatabaseModel; use crate::net::forward::AvailablePorts; -use crate::net::host::address::HostAddress; -use crate::net::host::binding::{BindInfo, BindOptions}; +use crate::net::host::address::{address, DomainConfig, HostAddress}; +use crate::net::host::binding::{binding, BindInfo, BindOptions}; use crate::net::service_interface::HostnameInfo; use crate::prelude::*; @@ -25,7 +26,10 @@ pub mod binding; pub struct Host { pub kind: HostKind, pub bindings: BTreeMap, - pub addresses: BTreeSet, + #[ts(type = "string[]")] + pub onions: BTreeSet, + #[ts(as = "BTreeMap::")] + pub domains: BTreeMap, /// COMPUTED: NetService::update pub hostname_info: BTreeMap>, // internal port -> Hostnames } @@ -39,13 +43,28 @@ impl Host { Self { kind, bindings: BTreeMap::new(), - addresses: BTreeSet::new(), + onions: BTreeSet::new(), + domains: BTreeMap::new(), hostname_info: BTreeMap::new(), } } - pub fn addresses(&self) -> impl Iterator { + pub fn addresses<'a>(&'a self) -> impl Iterator + 'a { // TODO: handle primary - self.addresses.iter() + self.onions + .iter() + .cloned() + .map(|address| HostAddress::Onion { address }) + .chain( + self.domains + .iter() + .map( + |(address, DomainConfig { public, acme })| HostAddress::Domain { + address: address.clone(), + public: *public, + acme: acme.clone(), + }, + ), + ) } } @@ -104,12 +123,12 @@ pub fn host_for<'a>( }; host_info(db, package_id)?.upsert(host_id, || { let mut h = Host::new(host_kind); - h.addresses.insert(HostAddress::Onion { - address: tor_key + h.onions.insert( + tor_key .or_not_found("generated tor key")? .public() .get_onion_address(), - }); + ); Ok(h) }) } @@ -161,6 +180,10 @@ pub fn host() -> ParentHandler { "address", address::().with_inherited(|HostParams { package }, _| package), ) + .subcommand( + "binding", + binding::().with_inherited(|HostParams { package }, _| package), + ) } pub async fn list_hosts( @@ -178,122 +201,3 @@ pub async fn list_hosts( .into_hosts() .keys() } - -#[derive(Deserialize, Serialize, Parser)] -pub struct AddressApiParams { - host: HostId, -} - -pub fn address() -> ParentHandler { - ParentHandler::::new() - .subcommand( - "add", - from_fn_async(add_address) - .with_inherited(|AddressApiParams { host }, package| (package, host)) - .no_display() - .with_about("Add an address to this host") - .with_call_remote::(), - ) - .subcommand( - "remove", - from_fn_async(remove_address) - .with_inherited(|AddressApiParams { host }, package| (package, host)) - .no_display() - .with_about("Remove an address from this host") - .with_call_remote::(), - ) - .subcommand( - "list", - from_fn_async(list_addresses) - .with_inherited(|AddressApiParams { host }, package| (package, host)) - .with_custom_display_fn(|_, res| { - for address in res { - println!("{address}") - } - Ok(()) - }) - .with_about("List addresses for this host") - .with_call_remote::(), - ) -} - -#[derive(Deserialize, Serialize, Parser)] -pub struct AddressParams { - pub address: HostAddress, -} - -pub async fn add_address( - ctx: RpcContext, - AddressParams { address }: AddressParams, - (package, host): (PackageId, HostId), -) -> Result<(), Error> { - ctx.db - .mutate(|db| { - if let HostAddress::Onion { address } = address { - db.as_private() - .as_key_store() - .as_onion() - .get_key(&address)?; - } - - db.as_public_mut() - .as_package_data_mut() - .as_idx_mut(&package) - .or_not_found(&package)? - .as_hosts_mut() - .as_idx_mut(&host) - .or_not_found(&host)? - .as_addresses_mut() - .mutate(|a| Ok(a.insert(address))) - }) - .await?; - let service = ctx.services.get(&package).await; - let service_ref = service.as_ref().or_not_found(&package)?; - service_ref.update_host(host).await?; - - Ok(()) -} - -pub async fn remove_address( - ctx: RpcContext, - AddressParams { address }: AddressParams, - (package, host): (PackageId, HostId), -) -> Result<(), Error> { - ctx.db - .mutate(|db| { - db.as_public_mut() - .as_package_data_mut() - .as_idx_mut(&package) - .or_not_found(&package)? - .as_hosts_mut() - .as_idx_mut(&host) - .or_not_found(&host)? - .as_addresses_mut() - .mutate(|a| Ok(a.remove(&address))) - }) - .await?; - let service = ctx.services.get(&package).await; - let service_ref = service.as_ref().or_not_found(&package)?; - service_ref.update_host(host).await?; - - Ok(()) -} - -pub async fn list_addresses( - ctx: RpcContext, - _: Empty, - (package, host): (PackageId, HostId), -) -> Result, Error> { - ctx.db - .peek() - .await - .into_public() - .into_package_data() - .into_idx(&package) - .or_not_found(&package)? - .into_hosts() - .into_idx(&host) - .or_not_found(&host)? - .into_addresses() - .de() -} diff --git a/core/startos/src/net/net_controller.rs b/core/startos/src/net/net_controller.rs index 91e3e8e677..891f6a9a56 100644 --- a/core/startos/src/net/net_controller.rs +++ b/core/startos/src/net/net_controller.rs @@ -85,6 +85,7 @@ impl PreInitNetController { hostname, 443, false, + None, ([127, 0, 0, 1], 80).into(), alpn.clone(), )?); @@ -97,6 +98,7 @@ impl PreInitNetController { )), 443, false, + None, ([127, 0, 0, 1], 80).into(), alpn.clone(), )?); @@ -214,7 +216,7 @@ impl NetService { internal_port: u16, options: BindOptions, ) -> Result<(), Error> { - dbg!("bind", &kind, &id, internal_port, &options); + crate::dbg!("bind", &kind, &id, internal_port, &options); let pkg_id = &self.id; let host = self .net_controller()? @@ -281,10 +283,10 @@ impl NetService { let net_ifaces = server_info.as_network_interfaces().de()?; let hostname = server_info.as_hostname().de()?; for (port, bind) in &host.bindings { + let old_lan_bind = binds.lan.remove(port); if !bind.enabled { continue; } - let old_lan_bind = binds.lan.remove(port); let lan_bind = old_lan_bind .as_ref() .filter(|(external, ssl, _, _)| { @@ -295,7 +297,9 @@ impl NetService { let new_lan_bind = if let Some(b) = lan_bind { b } else { - let mut rcs = Vec::with_capacity(2 + host.addresses.len()); + let mut rcs = Vec::with_capacity( + 2 + ctrl.server_hostnames.len() + host.domains.len() + host.onions.len(), + ); let mut hostnames = BTreeSet::new(); if let Some(ssl) = &bind.options.add_ssl { let external = bind @@ -317,6 +321,7 @@ impl NetService { hostname, external, bind.net.public, + None, target, connect_ssl.clone(), )?); @@ -324,39 +329,50 @@ impl NetService { for address in host.addresses() { match address { HostAddress::Onion { address } => { - let hostname = InternedString::from_display(address); + let hostname = InternedString::from_display(&address); if hostnames.insert(hostname.clone()) { rcs.push(ctrl.vhost.add( Some(hostname), external, false, + None, target, connect_ssl.clone(), )?); } } - HostAddress::Domain { address } => { + HostAddress::Domain { + address, + public, + acme, + } => { if hostnames.insert(address.clone()) { let address = Some(address.clone()); - rcs.push(ctrl.vhost.add( - address.clone(), - external, - bind.net.public, - target, - connect_ssl.clone(), - )?); if ssl.preferred_external_port == 443 { + if public && bind.net.public { + rcs.push(ctrl.vhost.add( + address.clone(), + 5443, + false, + acme.clone(), + target, + connect_ssl.clone(), + )?); + } rcs.push(ctrl.vhost.add( address.clone(), - 5443, - false, + 443, + public && bind.net.public, + acme, target, connect_ssl.clone(), )?); + } else { rcs.push(ctrl.vhost.add( address.clone(), - 443, - true, + external, + public && bind.net.public, + acme, target, connect_ssl.clone(), )?); @@ -403,33 +419,40 @@ impl NetService { }); } for address in host.addresses() { - if let HostAddress::Domain { address } = address { - if new_lan_bind - .1 - .as_ref() - .map_or(false, |ssl| ssl.preferred_external_port == 443) - { - bind_hostname_info.push(HostnameInfo::Ip { - network_interface_id: interface.clone(), - public: true, // TODO: check if port forward is active - hostname: IpHostname::Domain { - domain: address.clone(), - subdomain: None, - port: None, - ssl_port: Some(443), - }, - }); - } else if public && new_lan_bind.0.public { - bind_hostname_info.push(HostnameInfo::Ip { - network_interface_id: interface.clone(), - public, - hostname: IpHostname::Domain { - domain: address.clone(), - subdomain: None, - port: new_lan_bind.0.assigned_port, - ssl_port: new_lan_bind.0.assigned_ssl_port, - }, - }); + if let HostAddress::Domain { + address, + public: domain_public, + .. + } = address + { + if !public || (domain_public && new_lan_bind.0.public) { + if new_lan_bind + .1 + .as_ref() + .map_or(false, |ssl| ssl.preferred_external_port == 443) + { + bind_hostname_info.push(HostnameInfo::Ip { + network_interface_id: interface.clone(), + public: public && domain_public && bind.net.public, // TODO: check if port forward is active + hostname: IpHostname::Domain { + domain: address.clone(), + subdomain: None, + port: None, + ssl_port: Some(443), + }, + }); + } else { + bind_hostname_info.push(HostnameInfo::Ip { + network_interface_id: interface.clone(), + public, + hostname: IpHostname::Domain { + domain: address.clone(), + subdomain: None, + port: new_lan_bind.0.assigned_port, + ssl_port: new_lan_bind.0.assigned_ssl_port, + }, + }); + } } } } @@ -481,10 +504,10 @@ impl NetService { if let Some((lan, _, hostnames, _)) = old_lan_bind { if let Some(external) = lan.assigned_ssl_port { for hostname in ctrl.server_hostnames.iter().cloned() { - ctrl.vhost.gc(hostname, external)?; + ctrl.vhost.gc(hostname, external); } for hostname in hostnames { - ctrl.vhost.gc(Some(hostname), external)?; + ctrl.vhost.gc(Some(hostname), external); } } if let Some(external) = lan.assigned_port { @@ -505,10 +528,10 @@ impl NetService { for (lan, hostnames) in removed { if let Some(external) = lan.assigned_ssl_port { for hostname in ctrl.server_hostnames.iter().cloned() { - ctrl.vhost.gc(hostname, external)?; + ctrl.vhost.gc(hostname, external); } for hostname in hostnames { - ctrl.vhost.gc(Some(hostname), external)?; + ctrl.vhost.gc(Some(hostname), external); } } if let Some(external) = lan.assigned_port { @@ -557,13 +580,7 @@ impl NetService { } let mut keep_tor_addrs = BTreeSet::new(); - for tor_addr in host.addresses().filter_map(|a| { - if let HostAddress::Onion { address } = a { - Some(address) - } else { - None - } - }) { + for tor_addr in host.onions.iter() { keep_tor_addrs.insert(tor_addr); let old_tor_bind = binds.tor.remove(tor_addr); let tor_bind = old_tor_bind.filter(|(ports, _)| ports == &tor_binds); diff --git a/core/startos/src/net/network_interface.rs b/core/startos/src/net/network_interface.rs index dfb1f34b27..9f7439bfd5 100644 --- a/core/startos/src/net/network_interface.rs +++ b/core/startos/src/net/network_interface.rs @@ -1,13 +1,13 @@ use std::collections::{BTreeMap, BTreeSet}; use std::future::Future; -use std::net::{IpAddr, Ipv4Addr, SocketAddr, SocketAddrV6}; +use std::net::{IpAddr, Ipv4Addr, Ipv6Addr, SocketAddr, SocketAddrV6}; use std::pin::Pin; use std::sync::{Arc, Weak}; use std::task::Poll; use std::time::Duration; use clap::Parser; -use futures::{Stream, StreamExt, TryStreamExt}; +use futures::{FutureExt, Stream, StreamExt, TryStreamExt}; use getifaddrs::if_nametoindex; use helpers::NonDetachingJoinHandle; use imbl_value::InternedString; @@ -16,12 +16,14 @@ use itertools::Itertools; use patch_db::json_ptr::JsonPointer; use rpc_toolkit::{from_fn_async, Context, HandlerArgs, HandlerExt, ParentHandler}; use serde::{Deserialize, Serialize}; +use tokio::io::{AsyncBufReadExt, BufReader}; use tokio::net::{TcpListener, TcpStream}; +use tokio::process::Command; use tokio::sync::watch; use ts_rs::TS; use zbus::proxy::{PropertyChanged, PropertyStream, SignalStream}; use zbus::zvariant::{ - DeserializeDict, OwnedObjectPath, OwnedValue, Type as ZType, Value as ZValue, + DeserializeDict, Dict, OwnedObjectPath, OwnedValue, Type as ZType, Value as ZValue, }; use zbus::{proxy, Connection}; @@ -31,8 +33,10 @@ use crate::db::model::Database; use crate::net::network_interface::active_connection::ActiveConnectionProxy; use crate::prelude::*; use crate::util::future::Until; +use crate::util::io::open_file; use crate::util::serde::{display_serializable, HandlerExtSerde}; use crate::util::sync::SyncMutex; +use crate::util::Invoke; pub fn network_interface_api() -> ParentHandler { ParentHandler::new() @@ -48,15 +52,15 @@ pub fn network_interface_api() -> ParentHandler { } let mut table = Table::new(); - table.add_row(row![bc => "INTERFACE", "PUBLIC", "ADDRESSES"]); + table.add_row(row![bc => "INTERFACE", "PUBLIC", "ADDRESSES", "WAN IP"]); for (iface, info) in res { table.add_row(row![ iface, info.public(), - info.ip_info.map_or_else( + info.ip_info.as_ref().map_or_else( || "".to_owned(), |ip_info| ip_info.subnets - .into_iter() + .iter() .map(|ipnet| match ipnet.addr() { IpAddr::V4(ip) => format!("{ip}/{}", ipnet.prefix_len()), IpAddr::V6(ip) => format!( @@ -65,7 +69,10 @@ pub fn network_interface_api() -> ParentHandler { ipnet.prefix_len() ), }) - .join(", ")) + .join(", ")), + info.ip_info.as_ref() + .and_then(|ip_info| ip_info.wan_ip) + .map_or_else(|| "N/A".to_owned(), |ip| ip.to_string()) ]); } @@ -90,6 +97,12 @@ pub fn network_interface_api() -> ParentHandler { .no_display() .with_about("Allow this interface to infer whether it is publicly addressable based on its IPv4 address") .with_call_remote::(), + ).subcommand("forget", + from_fn_async(forget_iface) + .with_metadata("sync_db", Value::Bool(true)) + .no_display() + .with_about("Forget a disconnected interface") + .with_call_remote::() ) } @@ -134,6 +147,20 @@ async fn unset_public( .await } +#[derive(Debug, Clone, Deserialize, Serialize, Parser, TS)] +#[ts(export)] +struct ForgetInterfaceParams { + #[ts(type = "string")] + interface: InternedString, +} + +async fn forget_iface( + ctx: RpcContext, + ForgetInterfaceParams { interface }: ForgetInterfaceParams, +) -> Result<(), Error> { + ctx.net_controller.net_iface.forget(&interface).await +} + #[proxy( interface = "org.freedesktop.NetworkManager", default_service = "org.freedesktop.NetworkManager", @@ -152,6 +179,7 @@ trait NetworkManager { mod active_connection { use zbus::proxy; + use zbus::zvariant::OwnedObjectPath; use crate::prelude::*; @@ -168,6 +196,9 @@ mod active_connection { #[zbus(signal)] fn state_changed(&self) -> Result<(), Error>; + + #[zbus(property)] + fn dhcp4_config(&self) -> Result; } } @@ -202,6 +233,30 @@ impl TryFrom for IpNet { } } +#[proxy( + interface = "org.freedesktop.NetworkManager.DHCP4Config", + default_service = "org.freedesktop.NetworkManager" +)] +trait Dhcp4Config { + #[zbus(property)] + fn options(&self) -> Result; +} + +#[derive(Clone, Debug, DeserializeDict, ZType)] +#[zvariant(signature = "dict")] +struct Dhcp4Options { + ntp_servers: Option, +} +impl TryFrom for Dhcp4Options { + type Error = zbus::Error; + fn try_from(value: OwnedValue) -> Result { + let dict = value.downcast_ref::()?; + Ok(Self { + ntp_servers: dict.get::<_, String>(&zbus::zvariant::Str::from_static("ntp_servers"))?, + }) + } +} + #[proxy( interface = "org.freedesktop.NetworkManager.Device", default_service = "org.freedesktop.NetworkManager" @@ -276,9 +331,9 @@ async fn watcher(write_to: watch::Sender Result, Error> { +async fn get_wan_ipv4(iface: &str) -> Result, Error> { Ok(reqwest::Client::builder() - .local_address(Some(IpAddr::V4(local_addr))) + .interface(iface) .build()? .get("http://ip4only.me/api/") .timeout(Duration::from_secs(10)) @@ -352,7 +407,7 @@ async fn get_wan_ipv4(local_addr: Ipv4Addr) -> Result, Error> { .split(",") .skip(1) .next() - .filter(|s| s.is_empty()) + .filter(|s| !s.is_empty()) .map(|s| s.parse()) .transpose()?) } @@ -387,11 +442,18 @@ async fn watch_ip( .stub(), ) .with_stream(device_proxy.receive_ip4_config_changed().await.stub()) - .with_stream(device_proxy.receive_ip6_config_changed().await.stub()); + .with_stream(device_proxy.receive_ip6_config_changed().await.stub()) + .with_stream( + active_connection_proxy + .receive_dhcp4_config_changed() + .await + .stub(), + ); loop { let ip4_config = device_proxy.ip4_config().await?; let ip6_config = device_proxy.ip6_config().await?; + let dhcp4_config = active_connection_proxy.dhcp4_config().await?; until .run(async { let ip4_proxy = Ip4ConfigProxy::new(&connection, ip4_config).await?; @@ -400,49 +462,50 @@ async fn watch_ip( .with_stream(ip4_proxy.receive_address_data_changed().await.stub()) .with_stream(ip6_proxy.receive_address_data_changed().await.stub()); + let dhcp4_proxy = if &*dhcp4_config != "/" { + let dhcp4_proxy = Dhcp4ConfigProxy::new(&connection, dhcp4_config).await?; + until = until.with_stream(dhcp4_proxy.receive_options_changed().await.stub()); + Some(dhcp4_proxy) + } else { + None + }; + loop { - let addresses = ip4_proxy - .address_data() - .await? - .into_iter() - .chain(ip6_proxy.address_data().await?) - .collect_vec(); - if iface == "enp1s0" { - dbg!(&addresses); - } until .run(async { + let addresses = ip4_proxy + .address_data() + .await? + .into_iter() + .chain(ip6_proxy.address_data().await?) + .collect_vec(); + let mut ntp_servers = BTreeSet::new(); + if let Some(dhcp4_proxy) = &dhcp4_proxy { + let dhcp = crate::dbg!(dhcp4_proxy.options().await?); + if let Some(ntp) = dhcp.ntp_servers { + ntp_servers + .extend(ntp.split_whitespace().map(InternedString::intern)); + } + } let scope_id = if_nametoindex(&*iface).with_kind(ErrorKind::Network)?; let subnets: BTreeSet = addresses.into_iter().map(TryInto::try_into).try_collect()?; let ip_info = if !subnets.is_empty() { - let wan_ip = if let Some(local_addr) = - subnets.iter().find_map(|s| match s { - IpNet::V4(net) - if !net.addr().is_loopback() - && !net.addr().is_link_local() => - { - Some(net) - } - _ => None, - }) { - match get_wan_ipv4(local_addr.addr()).await { - Ok(a) => a, - Err(e) => { - tracing::error!( - "Failed to determine WAN IP for {iface}: {e}" - ); - tracing::debug!("{e:?}"); - None - } + let wan_ip = match get_wan_ipv4(&*iface).await { + Ok(a) => a, + Err(e) => { + tracing::error!( + "Failed to determine WAN IP for {iface}: {e}" + ); + tracing::debug!("{e:?}"); + None } - } else { - None }; Some(IpInfo { scope_id, subnets, wan_ip, + ntp_servers, }) } else { None @@ -452,12 +515,12 @@ async fn watch_ip( let public = m.get(&iface).map_or(None, |i| i.public); m.insert( iface.clone(), - dbg!(NetworkInterfaceInfo { + NetworkInterfaceInfo { public, ip_info: ip_info.clone(), - }), + }, ) - .filter(|old| &dbg!(old).ip_info == &ip_info) + .filter(|old| &old.ip_info == &ip_info) .is_none() }); @@ -481,6 +544,8 @@ impl NetworkInterfaceController { db: &TypedPatchDb, info: &BTreeMap, ) -> Result<(), Error> { + tracing::debug!("syncronizing {info:?} to db"); + db.mutate(|db| { db.as_public_mut() .as_server_info_mut() @@ -488,6 +553,55 @@ impl NetworkInterfaceController { .ser(info) }) .await?; + + let ntp: BTreeSet<_> = info + .values() + .filter_map(|i| i.ip_info.as_ref()) + .flat_map(|i| &i.ntp_servers) + .cloned() + .collect(); + let prev_ntp = tokio_stream::wrappers::LinesStream::new( + BufReader::new(open_file("/etc/systemd/timesyncd.conf").await?).lines(), + ) + .try_filter_map(|l| async move { + Ok(l.strip_prefix("NTP=").map(|s| { + s.split_whitespace() + .map(InternedString::intern) + .collect::>() + })) + }) + .boxed() + .try_next() + .await? + .unwrap_or_default(); + if ntp != prev_ntp { + // sed -i '/\(^\|#\)NTP=/c\NTP='"${servers}" /etc/systemd/timesyncd.conf + Command::new("sed") + .arg("-i") + .arg( + [r#"/\(^\|#\)NTP=/c\NTP="#] + .into_iter() + .chain(Itertools::intersperse( + { + fn to_str(ntp: &InternedString) -> &str { + &*ntp + } + ntp.iter().map(to_str) + }, + " ", + )) + .join(""), + ) + .arg("/etc/systemd/timesyncd.conf") + .invoke(ErrorKind::Filesystem) + .await?; + Command::new("systemctl") + .arg("restart") + .arg("systemd-timesyncd") + .invoke(ErrorKind::Systemd) + .await?; + } + Ok(()) } pub fn new(db: TypedPatchDb) -> Self { @@ -516,10 +630,19 @@ impl NetworkInterfaceController { } }; tokio::join!(watcher(write_to), async { - loop { - if let Err(e) = async { - let ip_info = read_from.borrow().clone(); - Self::sync(&db, &ip_info).await?; + let res: Result<(), Error> = async { + loop { + if let Err(e) = async { + let ip_info = { read_from.borrow().clone() }; + Self::sync(&db, &ip_info).boxed().await?; + + Ok::<_, Error>(()) + } + .await + { + tracing::error!("Error syncing ip info to db: {e}"); + tracing::debug!("{e:?}"); + } read_from.changed().await.map_err(|_| { Error::new( @@ -527,15 +650,13 @@ impl NetworkInterfaceController { ErrorKind::Network, ) })?; - - Ok::<_, Error>(()) - } - .await - { - tracing::error!("Error syncing ip info to db: {e}"); - tracing::debug!("{e:?}"); } } + .await; + if let Err(e) = res { + tracing::error!("Error syncing ip info to db: {e}"); + tracing::debug!("{e:?}"); + } }); }) .into(), @@ -599,11 +720,43 @@ impl NetworkInterfaceController { } Ok(()) } + + pub async fn forget(&self, interface: &InternedString) -> Result<(), Error> { + let mut sub = self + .db + .subscribe( + "/public/serverInfo/networkInterfaces" + .parse::>() + .with_kind(ErrorKind::Database)?, + ) + .await; + let mut err = None; + let changed = self.ip_info.send_if_modified(|ip_info| { + if ip_info + .get(interface) + .map_or(false, |i| i.ip_info.is_some()) + { + err = Some(Error::new( + eyre!("Cannot forget currently connected interface"), + ErrorKind::InvalidRequest, + )); + return false; + } + ip_info.remove(interface).is_some() + }); + if let Some(e) = err { + return Err(e); + } + if changed { + sub.recv().await; + } + Ok(()) + } } struct ListenerMap { port: u16, - listeners: BTreeMap<(IpAddr, u32), (TcpListener, bool)>, + listeners: BTreeMap<(IpAddr, u32), (TcpListener, bool, Option)>, } impl ListenerMap { fn new(port: u16) -> Self { @@ -618,14 +771,28 @@ impl ListenerMap { public: bool, ) -> Result<(), Error> { let mut keep = BTreeSet::<(IpAddr, u32)>::new(); - for info in ip_info.values() { + for info in ip_info.values().chain([&NetworkInterfaceInfo { + public: Some(false), + ip_info: Some(IpInfo { + scope_id: 1, + subnets: [ + IpNet::new(Ipv4Addr::LOCALHOST.into(), 8).unwrap(), + IpNet::new(Ipv6Addr::LOCALHOST.into(), 128).unwrap(), + ] + .into_iter() + .collect(), + wan_ip: None, + ntp_servers: Default::default(), + }), + }]) { if public || !info.public() { if let Some(ip_info) = &info.ip_info { for ipnet in &ip_info.subnets { let key = (ipnet.addr(), ip_info.scope_id); keep.insert(key); - if let Some((_, is_public)) = self.listeners.get_mut(&key) { + if let Some((_, is_public, wan_ip)) = self.listeners.get_mut(&key) { *is_public = info.public(); + *wan_ip = info.ip_info.as_ref().and_then(|i| i.wan_ip); continue; } self.listeners.insert( @@ -640,6 +807,7 @@ impl ListenerMap { }) .await?, info.public(), + info.ip_info.as_ref().and_then(|i| i.wan_ip), ), ); } @@ -654,14 +822,14 @@ impl ListenerMap { } } #[pin_project::pin_project] -struct ListenerMapFut<'a>(&'a mut BTreeMap<(IpAddr, u32), (TcpListener, bool)>); +struct ListenerMapFut<'a>(&'a mut BTreeMap<(IpAddr, u32), (TcpListener, bool, Option)>); impl<'a> Future for ListenerMapFut<'a> { - type Output = Result<(IpAddr, bool, TcpStream, SocketAddr), Error>; + type Output = Result<(IpAddr, bool, Option, TcpStream, SocketAddr), Error>; fn poll(self: Pin<&mut Self>, cx: &mut std::task::Context<'_>) -> Poll { let this = self.project(); for ((ip, _), listener) in this.0.iter() { if let Poll::Ready((stream, addr)) = listener.0.poll_accept(cx)? { - return Poll::Ready(Ok((*ip, listener.1, stream, addr))); + return Poll::Ready(Ok((*ip, listener.1, listener.2, stream, addr))); } } Poll::Pending @@ -675,6 +843,10 @@ pub struct NetworkInterfaceListener { _arc: Arc<()>, } impl NetworkInterfaceListener { + pub fn port(&self) -> u16 { + self.listeners.port + } + pub async fn accept(&mut self, public: bool) -> Result { loop { if self.needs_update { @@ -684,11 +856,12 @@ impl NetworkInterfaceListener { } tokio::select! { accepted = self.listeners.accept() => { - let (ip, is_public, stream, peer) = accepted?; + let (ip, is_public, wan_ip, stream, peer) = accepted?; return Ok(Accepted { stream, peer, is_public, + wan_ip, bind: (ip, self.listeners.port).into(), }) }, @@ -708,6 +881,7 @@ pub struct Accepted { pub stream: TcpStream, pub peer: SocketAddr, pub is_public: bool, + pub wan_ip: Option, pub bind: SocketAddr, } diff --git a/core/startos/src/net/ssl.rs b/core/startos/src/net/ssl.rs index 29bcd96528..a89853591d 100644 --- a/core/startos/src/net/ssl.rs +++ b/core/startos/src/net/ssl.rs @@ -17,7 +17,6 @@ use openssl::x509::{X509Builder, X509Extension, X509NameBuilder, X509}; use openssl::*; use patch_db::HasModel; use serde::{Deserialize, Serialize}; -use tokio::time::Instant; use tracing::instrument; use crate::account::AccountInfo; diff --git a/core/startos/src/net/static_server.rs b/core/startos/src/net/static_server.rs index c070d7920d..b6961df937 100644 --- a/core/startos/src/net/static_server.rs +++ b/core/startos/src/net/static_server.rs @@ -9,7 +9,7 @@ use async_compression::tokio::bufread::GzipEncoder; use axum::body::Body; use axum::extract::{self as x, Request}; use axum::response::Response; -use axum::routing::{any, get, post}; +use axum::routing::{any, get}; use axum::Router; use base64::display::Base64Display; use digest::Digest; @@ -26,7 +26,6 @@ use new_mime_guess::MimeGuess; use openssl::hash::MessageDigest; use openssl::x509::X509; use rpc_toolkit::{Context, HttpServer, Server}; -use sqlx::query; use tokio::io::{AsyncRead, AsyncReadExt, AsyncSeekExt, BufReader}; use tokio_util::io::ReaderStream; use url::Url; diff --git a/core/startos/src/net/vhost.rs b/core/startos/src/net/vhost.rs index 7984712199..809effc7d8 100644 --- a/core/startos/src/net/vhost.rs +++ b/core/startos/src/net/vhost.rs @@ -1,22 +1,23 @@ use std::collections::BTreeMap; -use std::net::{IpAddr, Ipv6Addr, SocketAddr}; +use std::net::{IpAddr, SocketAddr}; use std::str::FromStr; use std::sync::{Arc, Weak}; use std::time::Duration; -use async_acme::acme::ACME_TLS_ALPN_NAME; +use async_acme::acme::{Identifier, ACME_TLS_ALPN_NAME}; use axum::body::Body; use axum::extract::Request; use axum::response::Response; use color_eyre::eyre::eyre; +use futures::FutureExt; use helpers::NonDetachingJoinHandle; use http::Uri; use imbl_value::InternedString; use models::ResultExt; use serde::{Deserialize, Serialize}; use tokio::io::AsyncWriteExt; -use tokio::net::{TcpListener, TcpStream}; -use tokio::sync::{watch, Mutex, RwLock}; +use tokio::net::TcpStream; +use tokio::sync::watch; use tokio_rustls::rustls::crypto::CryptoProvider; use tokio_rustls::rustls::pki_types::{ CertificateDer, PrivateKeyDer, PrivatePkcs8KeyDer, ServerName, @@ -31,7 +32,7 @@ use tracing::instrument; use ts_rs::TS; use crate::db::model::Database; -use crate::net::acme::AcmeCertCache; +use crate::net::acme::{AcmeCertCache, AcmeProvider}; use crate::net::network_interface::{ Accepted, NetworkInterfaceController, NetworkInterfaceListener, }; @@ -55,6 +56,7 @@ pub struct VHostController { db: TypedPatchDb, interfaces: Arc, crypto_provider: Arc, + acme_tls_alpn_cache: AcmeTlsAlpnCache, servers: SyncMutex>, } impl VHostController { @@ -63,6 +65,7 @@ impl VHostController { db, interfaces, crypto_provider: Arc::new(tokio_rustls::rustls::crypto::ring::default_provider()), + acme_tls_alpn_cache: Arc::new(SyncMutex::new(BTreeMap::new())), servers: SyncMutex::new(BTreeMap::new()), } } @@ -72,6 +75,7 @@ impl VHostController { hostname: Option, external: u16, public: bool, + acme: Option, target: SocketAddr, connect_ssl: Result<(), AlpnInfo>, // Ok: yes, connect using ssl, pass through alpn; Err: connect tcp, use provided strategy for alpn ) -> Result, Error> { @@ -84,12 +88,14 @@ impl VHostController { self.db.clone(), self.interfaces.clone(), self.crypto_provider.clone(), + self.acme_tls_alpn_cache.clone(), )? }; let rc = server.add( hostname, TargetInfo { public, + acme, addr: target, connect_ssl, }, @@ -99,15 +105,14 @@ impl VHostController { }) } #[instrument(skip_all)] - pub fn gc(&self, hostname: Option, external: u16) -> Result<(), Error> { + pub fn gc(&self, hostname: Option, external: u16) { self.servers.mutate(|writable| { if let Some(server) = writable.remove(&external) { - server.gc(hostname)?; - if !server.is_empty()? { + server.gc(hostname); + if !server.is_empty() { writable.insert(external, server); } } - Ok(()) }) } } @@ -115,6 +120,7 @@ impl VHostController { #[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord)] struct TargetInfo { public: bool, + acme: Option, addr: SocketAddr, connect_ssl: Result<(), AlpnInfo>, } @@ -134,26 +140,48 @@ impl Default for AlpnInfo { type AcmeTlsAlpnCache = Arc>>>>>; -type Mapping = SyncMutex, BTreeMap>>>; +type Mapping = BTreeMap, BTreeMap>>; struct VHostServer { - mapping: Weak, + mapping: watch::Sender, _thread: NonDetachingJoinHandle<()>, } impl VHostServer { async fn accept( listener: &mut NetworkInterfaceListener, - mapping: Arc, + mut mapping: watch::Receiver, db: TypedPatchDb, acme_tls_alpn_cache: AcmeTlsAlpnCache, crypto_provider: Arc, ) -> Result<(), Error> { - let any_public = mapping.peek(|m| { - m.iter() - .any(|(_, targets)| targets.keys().any(|target| target.public)) - }); - let accepted = listener.accept(any_public).await?; + let accepted; + + loop { + let any_public = mapping + .borrow() + .iter() + .any(|(_, targets)| targets.iter().any(|(target, _)| target.public)); + + let changed_public = mapping + .wait_for(|m| { + m.iter() + .any(|(_, targets)| targets.iter().any(|(target, _)| target.public)) + != any_public + }) + .boxed(); + + tokio::select! { + a = listener.accept(any_public) => { + accepted = a?; + break; + } + _ = changed_public => { + tracing::debug!("port {} {} public bindings", listener.port(), if any_public { "no longer has" } else { "now has" }); + } + } + } + if let Err(e) = socket2::SockRef::from(&accepted.stream).set_tcp_keepalive( &socket2::TcpKeepalive::new() .with_time(Duration::from_secs(900)) @@ -181,10 +209,11 @@ impl VHostServer { Accepted { stream, is_public, + wan_ip, bind, .. }: Accepted, - mapping: Arc, + mapping: watch::Receiver, db: TypedPatchDb, acme_tls_alpn_cache: AcmeTlsAlpnCache, crypto_provider: Arc, @@ -258,8 +287,58 @@ impl VHostServer { } } }; - let target_name = mid.client_hello().server_name().map(|s| s.into()); - let target = mapping.peek(|m| { + let target_name: Option = + mid.client_hello().server_name().map(|s| s.into()); + if let Some(domain) = target_name.as_ref() { + if mid + .client_hello() + .alpn() + .into_iter() + .flatten() + .any(|alpn| alpn == ACME_TLS_ALPN_NAME) + { + let cert = WatchStream::new( + acme_tls_alpn_cache + .peek(|c| c.get(&**domain).cloned()) + .ok_or_else(|| { + Error::new( + eyre!("No challenge recv available for {domain}"), + ErrorKind::OpenSsl, + ) + })?, + ); + tracing::info!("Waiting for verification cert for {domain}"); + let cert = cert + .filter(|c| c.is_some()) + .next() + .await + .flatten() + .ok_or_else(|| { + Error::new( + eyre!("No challenge available for {domain}"), + ErrorKind::OpenSsl, + ) + })?; + tracing::info!("Verification cert received for {domain}"); + let mut cfg = ServerConfig::builder_with_provider(crypto_provider.clone()) + .with_safe_default_protocol_versions() + .with_kind(crate::ErrorKind::OpenSsl)? + .with_no_client_auth() + .with_cert_resolver(Arc::new(SingleCertResolver(cert))); + + cfg.alpn_protocols = vec![ACME_TLS_ALPN_NAME.to_vec()]; + tracing::info!("performing ACME auth challenge"); + let mut accept = mid.into_stream(Arc::new(cfg)); + let io = accept.get_mut().unwrap(); + let buffered = io.stop_buffering(); + io.write_all(&buffered).await?; + accept.await?; + tracing::info!("ACME auth challenge completed"); + return Ok(()); + } + } + let target = { + let m = mapping.borrow(); m.get(&target_name) .into_iter() .flatten() @@ -279,10 +358,12 @@ impl VHostServer { } }) .map(|(target, _)| target.clone()) - }); - if let Some(target) = dbg!(target) { + }; + if let Some(target) = target { if is_public && !target.public { - log::warn!("Rejecting connection from public interface to private bind"); + log::warn!( + "Rejecting connection from public interface to private bind: {bind} -> {target:?}" + ); return Ok(()); } let peek = db.peek().await; @@ -292,80 +373,52 @@ impl VHostServer { .as_local_certs() .as_root_cert() .de()?; - let mut cfg = match async { - if let Some(acme_settings) = peek.as_public().as_server_info().as_acme().de()? { - if let Some(domain) = target_name - .as_ref() - .filter(|target_name| acme_settings.domains.contains(*target_name)) + let mut cfg = async { + if let Some((domain, provider, settings)) = + target_name.as_ref().and_then(|domain| { + target.acme.as_ref().and_then(|a| { + peek.as_public() + .as_server_info() + .as_acme() + .as_idx(a) + .map(|s| (domain, a, s)) + }) + }) + { + let acme_settings = settings.de()?; + let mut identifiers = vec![Identifier::Dns(domain.to_string())]; + if false + // Requires RFC 8738 { - if mid - .client_hello() - .alpn() - .into_iter() - .flatten() - .any(|alpn| alpn == ACME_TLS_ALPN_NAME) - { - let cert = WatchStream::new( - acme_tls_alpn_cache - .peek(|c| c.get(&**domain).cloned()) - .ok_or_else(|| { - Error::new( - eyre!("No challenge recv available for {domain}"), - ErrorKind::OpenSsl, - ) - })?, - ); - tracing::info!("Waiting for verification cert for {domain}"); - let cert = cert - .filter(|c| c.is_some()) - .next() - .await - .flatten() - .ok_or_else(|| { - Error::new( - eyre!("No challenge available for {domain}"), - ErrorKind::OpenSsl, - ) - })?; - tracing::info!("Verification cert received for {domain}"); - let mut cfg = - ServerConfig::builder_with_provider(crypto_provider.clone()) - .with_safe_default_protocol_versions() - .with_kind(crate::ErrorKind::OpenSsl)? - .with_no_client_auth() - .with_cert_resolver(Arc::new(SingleCertResolver(cert))); - - cfg.alpn_protocols = vec![ACME_TLS_ALPN_NAME.to_vec()]; - return Ok(Err(cfg)); - } else { - let domains = [domain.to_string()]; - let (send, recv) = watch::channel(None); - acme_tls_alpn_cache.mutate(|c| c.insert(domain.clone(), recv)); - let cert = async_acme::rustls_helper::order( - |_, cert| { - send.send_replace(Some(Arc::new(cert))); - Ok(()) - }, - acme_settings.provider.as_str(), - &domains, - Some(&AcmeCertCache(&db)), - &acme_settings.contact, - ) - .await - .with_kind(ErrorKind::OpenSsl)?; - return Ok(Ok(ServerConfig::builder_with_provider( - crypto_provider.clone(), - ) - .with_safe_default_protocol_versions() - .with_kind(crate::ErrorKind::OpenSsl)? - .with_no_client_auth() - .with_cert_resolver(Arc::new(SingleCertResolver(Arc::new(cert)))))); + if let Some(wan_ip) = wan_ip { + identifiers.push(Identifier::Ip(wan_ip.into())); } } + let (send, recv) = watch::channel(None); + acme_tls_alpn_cache.mutate(|c| c.insert(domain.clone(), recv)); + let cert = async_acme::rustls_helper::order( + |_, cert| { + send.send_replace(Some(Arc::new(cert))); + Ok(()) + }, + provider.0.as_str(), + &identifiers, + Some(&AcmeCertCache(&db)), + &acme_settings.contact, + ) + .await + .with_kind(ErrorKind::OpenSsl)?; + return Ok(ServerConfig::builder_with_provider(crypto_provider.clone()) + .with_safe_default_protocol_versions() + .with_kind(crate::ErrorKind::OpenSsl)? + .with_no_client_auth() + .with_cert_resolver(Arc::new(SingleCertResolver(Arc::new(cert))))); } + let hostnames = target_name .into_iter() .chain([InternedString::from_display(&bind.ip())]) + .chain(wan_ip.as_ref().map(InternedString::from_display)) .collect(); let key = db .mutate(|v| { @@ -413,22 +466,8 @@ impl VHostServer { ) } .with_kind(crate::ErrorKind::OpenSsl) - .map(Ok) } - .await? - { - Ok(a) => a, - Err(cfg) => { - tracing::info!("performing ACME auth challenge"); - let mut accept = mid.into_stream(Arc::new(cfg)); - let io = accept.get_mut().unwrap(); - let buffered = io.stop_buffering(); - io.write_all(&buffered).await?; - accept.await?; - tracing::info!("ACME auth challenge completed"); - return Ok(()); - } - }; + .await?; let mut tcp_stream = TcpStream::connect(target.addr).await?; match target.connect_ssl { Ok(()) => { @@ -546,17 +585,17 @@ impl VHostServer { db: TypedPatchDb, iface_ctrl: Arc, crypto_provider: Arc, + acme_tls_alpn_cache: AcmeTlsAlpnCache, ) -> Result { - let acme_tls_alpn_cache = Arc::new(SyncMutex::new(BTreeMap::new())); let mut listener = iface_ctrl.bind(port).with_kind(crate::ErrorKind::Network)?; - let mapping = Arc::new(SyncMutex::new(BTreeMap::new())); + let (map_send, map_recv) = watch::channel(BTreeMap::new()); Ok(Self { - mapping: Arc::downgrade(&mapping), + mapping: map_send, _thread: tokio::spawn(async move { loop { if let Err(e) = Self::accept( &mut listener, - mapping.clone(), + map_recv.clone(), db.clone(), acme_tls_alpn_cache.clone(), crypto_provider.clone(), @@ -574,19 +613,23 @@ impl VHostServer { }) } fn add(&self, hostname: Option, target: TargetInfo) -> Result, Error> { - if let Some(mapping) = Weak::upgrade(&self.mapping) { - mapping.mutate(|writable| { - let mut targets = writable.remove(&hostname).unwrap_or_default(); - let rc = - if let Some(rc) = Weak::upgrade(&targets.remove(&target).unwrap_or_default()) { - rc - } else { - Arc::new(()) - }; - targets.insert(target, Arc::downgrade(&rc)); - writable.insert(hostname, targets); - Ok(rc) - }) + let mut res = Ok(Arc::new(())); + self.mapping.send_if_modified(|writable| { + let mut changed = false; + let mut targets = writable.remove(&hostname).unwrap_or_default(); + let rc = if let Some(rc) = Weak::upgrade(&targets.remove(&target).unwrap_or_default()) { + rc + } else { + changed = true; + Arc::new(()) + }; + targets.insert(target, Arc::downgrade(&rc)); + writable.insert(hostname, targets); + res = Ok(rc); + changed + }); + if !self.mapping.is_closed() { + res } else { Err(Error::new( eyre!("VHost Service Thread has exited"), @@ -594,34 +637,22 @@ impl VHostServer { )) } } - fn gc(&self, hostname: Option) -> Result<(), Error> { - if let Some(mapping) = Weak::upgrade(&self.mapping) { - mapping.mutate(|writable| { - let mut targets = writable.remove(&hostname).unwrap_or_default(); - targets = targets - .into_iter() - .filter(|(_, rc)| rc.strong_count() > 0) - .collect(); - if !targets.is_empty() { - writable.insert(hostname, targets); - } - Ok(()) - }) - } else { - Err(Error::new( - eyre!("VHost Service Thread has exited"), - crate::ErrorKind::Network, - )) - } + fn gc(&self, hostname: Option) { + self.mapping.send_if_modified(|writable| { + let mut targets = writable.remove(&hostname).unwrap_or_default(); + let pre = targets.len(); + targets = targets + .into_iter() + .filter(|(_, rc)| rc.strong_count() > 0) + .collect(); + let post = targets.len(); + if !targets.is_empty() { + writable.insert(hostname, targets); + } + pre == post + }); } - fn is_empty(&self) -> Result { - if let Some(mapping) = Weak::upgrade(&self.mapping) { - Ok(mapping.peek(|m| m.is_empty())) - } else { - Err(Error::new( - eyre!("VHost Service Thread has exited"), - crate::ErrorKind::Network, - )) - } + fn is_empty(&self) -> bool { + self.mapping.borrow().is_empty() } } diff --git a/core/startos/src/net/wifi.rs b/core/startos/src/net/wifi.rs index 5c879399c4..b2e59c20fc 100644 --- a/core/startos/src/net/wifi.rs +++ b/core/startos/src/net/wifi.rs @@ -298,7 +298,7 @@ fn display_wifi_info(params: WithIoFormat, info: WifiListInfo) { let mut table_global = Table::new(); table_global.add_row(row![bc => "CONNECTED", - "SIGNAL_STRENGTH", + "SIGNAL STRENGTH", "COUNTRY", "ETHERNET", ]); @@ -306,12 +306,12 @@ fn display_wifi_info(params: WithIoFormat, info: WifiListInfo) { &info .connected .as_ref() - .map_or("[N/A]".to_owned(), |c| c.0.clone()), + .map_or("N/A".to_owned(), |c| c.0.clone()), &info .connected .as_ref() .and_then(|x| info.ssids.get(x)) - .map_or("[N/A]".to_owned(), |ss| format!("{}", ss.0)), + .map_or("N/A".to_owned(), |ss| format!("{}", ss.0)), info.country.as_ref().map(|c| c.alpha2()).unwrap_or("00"), &format!("{}", info.ethernet) ]); diff --git a/core/startos/src/prelude.rs b/core/startos/src/prelude.rs index a6a78a58db..702d77c2d3 100644 --- a/core/startos/src/prelude.rs +++ b/core/startos/src/prelude.rs @@ -9,9 +9,17 @@ pub use crate::error::{Error, ErrorCollection, ErrorKind, ResultExt}; #[macro_export] macro_rules! dbg { + () => {{ + tracing::debug!("[{}:{}:{}]", file!(), line!(), column!()); + }}; ($e:expr) => {{ let e = $e; - tracing::debug!("[{}:{}:{}] $e = {e:?}", file!(), line!(), column!()); + tracing::debug!("[{}:{}:{}] {} = {e:?}", file!(), line!(), column!(), stringify!($e)); e }}; + ($($e:expr),+) => { + ($( + crate::dbg!($e) + ),+) + } } diff --git a/core/startos/src/registry/context.rs b/core/startos/src/registry/context.rs index 16c6465ed3..d78fde50e5 100644 --- a/core/startos/src/registry/context.rs +++ b/core/startos/src/registry/context.rs @@ -19,7 +19,6 @@ use crate::context::config::{ContextConfig, CONFIG_PATH}; use crate::context::{CliContext, RpcContext}; use crate::prelude::*; use crate::registry::auth::{SignatureHeader, AUTH_SIG_HEADER}; -use crate::registry::device_info::{DeviceInfo, DEVICE_INFO_HEADER}; use crate::registry::signer::sign::AnySigningKey; use crate::registry::RegistryDatabase; use crate::rpc_continuations::RpcContinuations; diff --git a/core/startos/src/registry/mod.rs b/core/startos/src/registry/mod.rs index 0cbbce4e0c..9bb605d926 100644 --- a/core/startos/src/registry/mod.rs +++ b/core/startos/src/registry/mod.rs @@ -2,7 +2,6 @@ use std::collections::{BTreeMap, BTreeSet}; use axum::Router; use futures::future::ready; -use imbl_value::InternedString; use models::DataUrl; use rpc_toolkit::{from_fn_async, Context, HandlerExt, ParentHandler, Server}; use serde::{Deserialize, Serialize}; @@ -17,7 +16,7 @@ use crate::registry::auth::Auth; use crate::registry::context::RegistryContext; use crate::registry::device_info::DeviceInfoMiddleware; use crate::registry::os::index::OsIndex; -use crate::registry::package::index::{Category, PackageIndex}; +use crate::registry::package::index::PackageIndex; use crate::registry::signer::SignerInfo; use crate::rpc_continuations::Guid; use crate::util::serde::HandlerExtSerde; diff --git a/core/startos/src/registry/signer/commitment/merkle_archive.rs b/core/startos/src/registry/signer/commitment/merkle_archive.rs index 1b9d7d1e0a..b27fb7ef4b 100644 --- a/core/startos/src/registry/signer/commitment/merkle_archive.rs +++ b/core/startos/src/registry/signer/commitment/merkle_archive.rs @@ -24,10 +24,10 @@ impl MerkleArchiveCommitment { pub fn from_query(query: &str) -> Result, Error> { let mut root_sighash = None; let mut root_maxsize = None; - for (k, v) in form_urlencoded::parse(dbg!(query).as_bytes()) { + for (k, v) in form_urlencoded::parse(query.as_bytes()) { match &*k { "rootSighash" => { - root_sighash = Some(dbg!(v).parse()?); + root_sighash = Some(v.parse()?); } "rootMaxsize" => { root_maxsize = Some(v.parse()?); diff --git a/core/startos/src/service/effects/callbacks.rs b/core/startos/src/service/effects/callbacks.rs index 65eb707d8a..19946672ce 100644 --- a/core/startos/src/service/effects/callbacks.rs +++ b/core/startos/src/service/effects/callbacks.rs @@ -294,7 +294,7 @@ impl CallbackHandler { } } pub async fn call(mut self, args: Vector) -> Result<(), Error> { - dbg!(eyre!("callback fired: {}", self.handle.is_active())); + crate::dbg!(eyre!("callback fired: {}", self.handle.is_active())); if let Some(seed) = self.seed.upgrade() { seed.persistent_container .callback(self.handle.take(), args) diff --git a/core/startos/src/service/effects/net/ssl.rs b/core/startos/src/service/effects/net/ssl.rs index d37a2d241b..66b4fa1e69 100644 --- a/core/startos/src/service/effects/net/ssl.rs +++ b/core/startos/src/service/effects/net/ssl.rs @@ -51,10 +51,16 @@ pub async fn get_ssl_certificate( .iter() .map(|(_, m)| m.as_hosts().as_entries()) .flatten_ok() - .map_ok(|(_, m)| m.as_addresses().de()) + .map_ok(|(_, m)| { + Ok(m.as_onions() + .de()? + .iter() + .map(InternedString::from_display) + .chain(m.as_domains().keys()?) + .collect::>()) + }) .map(|a| a.and_then(|a| a)) .flatten_ok() - .map_ok(|a| InternedString::from_display(&a)) .try_collect::<_, BTreeSet<_>, _>()?; for hostname in &hostnames { if let Some(internal) = hostname @@ -135,10 +141,16 @@ pub async fn get_ssl_key( .into_iter() .map(|m| m.as_hosts().as_entries()) .flatten_ok() - .map_ok(|(_, m)| m.as_addresses().de()) + .map_ok(|(_, m)| { + Ok(m.as_onions() + .de()? + .iter() + .map(InternedString::from_display) + .chain(m.as_domains().keys()?) + .collect::>()) + }) .map(|a| a.and_then(|a| a)) .flatten_ok() - .map_ok(|a| InternedString::from_display(&a)) .try_collect::<_, BTreeSet<_>, _>()?; for hostname in &hostnames { if let Some(internal) = hostname diff --git a/core/startos/src/service/effects/store.rs b/core/startos/src/service/effects/store.rs index 1d4a070864..39166c3333 100644 --- a/core/startos/src/service/effects/store.rs +++ b/core/startos/src/service/effects/store.rs @@ -26,7 +26,7 @@ pub async fn get_store( callback, }: GetStoreParams, ) -> Result { - dbg!(&callback); + crate::dbg!(&callback); let context = context.deref()?; let peeked = context.seed.ctx.db.peek().await; let package_id = package_id.unwrap_or(context.seed.id.clone()); diff --git a/core/startos/src/service/mod.rs b/core/startos/src/service/mod.rs index d2e2939090..6242e3b12b 100644 --- a/core/startos/src/service/mod.rs +++ b/core/startos/src/service/mod.rs @@ -934,7 +934,6 @@ pub async fn attach( .with_kind(ErrorKind::Network)?; current_out = "stdout"; } - dbg!(¤t_out); ws.send(Message::Binary(out)) .await .with_kind(ErrorKind::Network)?; @@ -948,7 +947,6 @@ pub async fn attach( .with_kind(ErrorKind::Network)?; current_out = "stderr"; } - dbg!(¤t_out); ws.send(Message::Binary(err)) .await .with_kind(ErrorKind::Network)?; diff --git a/core/startos/src/service/persistent_container.rs b/core/startos/src/service/persistent_container.rs index 13cb7688ce..c99e1cac6d 100644 --- a/core/startos/src/service/persistent_container.rs +++ b/core/startos/src/service/persistent_container.rs @@ -452,7 +452,7 @@ impl PersistentContainer { #[instrument(skip_all)] pub async fn exit(mut self) -> Result<(), Error> { if let Some(destroy) = self.destroy(false) { - dbg!(destroy.await)?; + destroy.await?; } tracing::info!("Service for {} exited", self.s9pk.as_manifest().id); diff --git a/core/startos/src/service/rpc.rs b/core/startos/src/service/rpc.rs index f008de5c77..61eb5d5925 100644 --- a/core/startos/src/service/rpc.rs +++ b/core/startos/src/service/rpc.rs @@ -155,7 +155,7 @@ impl serde::Serialize for Sandbox { pub struct CallbackId(u64); impl CallbackId { pub fn register(self, container: &PersistentContainer) -> CallbackHandle { - dbg!(eyre!( + crate::dbg!(eyre!( "callback {} registered for {}", self.0, container.s9pk.as_manifest().id diff --git a/core/startos/src/service/transition/restore.rs b/core/startos/src/service/transition/restore.rs index 1c4020ea4c..08f3be9429 100644 --- a/core/startos/src/service/transition/restore.rs +++ b/core/startos/src/service/transition/restore.rs @@ -48,7 +48,7 @@ impl Handler for ServiceActor { Ok::<_, Error>(()) } .map(|x| { - if let Err(err) = dbg!(x) { + if let Err(err) = x { tracing::debug!("{:?}", err); tracing::warn!("{}", err); } diff --git a/core/startos/src/util/rpc_client.rs b/core/startos/src/util/rpc_client.rs index fc93e4c649..82ce11e202 100644 --- a/core/startos/src/util/rpc_client.rs +++ b/core/startos/src/util/rpc_client.rs @@ -47,7 +47,7 @@ impl RpcClient { let mut lines = BufReader::new(reader).lines(); while let Some(line) = lines.next_line().await.transpose() { match line.map_err(Error::from).and_then(|l| { - serde_json::from_str::(dbg!(&l)) + serde_json::from_str::(crate::dbg!(&l)) .with_kind(ErrorKind::Deserialization) }) { Ok(l) => { @@ -114,7 +114,7 @@ impl RpcClient { let (send, recv) = oneshot::channel(); w.lock().await.insert(id.clone(), send); self.writer - .write_all((dbg!(serde_json::to_string(&request))? + "\n").as_bytes()) + .write_all((crate::dbg!(serde_json::to_string(&request))? + "\n").as_bytes()) .await .map_err(|e| { let mut err = rpc_toolkit::yajrc::INTERNAL_ERROR.clone(); @@ -154,7 +154,7 @@ impl RpcClient { params, }; self.writer - .write_all((dbg!(serde_json::to_string(&request))? + "\n").as_bytes()) + .write_all((crate::dbg!(serde_json::to_string(&request))? + "\n").as_bytes()) .await .map_err(|e| { let mut err = rpc_toolkit::yajrc::INTERNAL_ERROR.clone(); diff --git a/core/startos/src/version/v0_3_6_alpha_0.rs b/core/startos/src/version/v0_3_6_alpha_0.rs index 7a6045a3af..64c7d2e12a 100644 --- a/core/startos/src/version/v0_3_6_alpha_0.rs +++ b/core/startos/src/version/v0_3_6_alpha_0.rs @@ -191,7 +191,6 @@ async fn init_postgres(datadir: impl AsRef) -> Result { .run(&secret_store) .await .with_kind(crate::ErrorKind::Database)?; - dbg!("Init Postgres Done"); Ok(secret_store) } @@ -315,7 +314,6 @@ impl VersionT for Version { "private": private, }); - dbg!("Should be done with the up"); *db = next; Ok(()) } diff --git a/sdk/base/lib/osBindings/HostAddress.ts b/sdk/base/lib/osBindings/AcmeProvider.ts similarity index 51% rename from sdk/base/lib/osBindings/HostAddress.ts rename to sdk/base/lib/osBindings/AcmeProvider.ts index 73b46d8e5a..0ad3f00525 100644 --- a/sdk/base/lib/osBindings/HostAddress.ts +++ b/sdk/base/lib/osBindings/AcmeProvider.ts @@ -1,5 +1,3 @@ // This file was generated by [ts-rs](https://github.com/Aleph-Alpha/ts-rs). Do not edit this file manually. -export type HostAddress = - | { kind: "onion"; address: string } - | { kind: "domain"; address: string } +export type AcmeProvider = string diff --git a/sdk/base/lib/osBindings/AcmeSettings.ts b/sdk/base/lib/osBindings/AcmeSettings.ts index bdf151ec75..44e70d9dfb 100644 --- a/sdk/base/lib/osBindings/AcmeSettings.ts +++ b/sdk/base/lib/osBindings/AcmeSettings.ts @@ -1,13 +1,3 @@ // This file was generated by [ts-rs](https://github.com/Aleph-Alpha/ts-rs). Do not edit this file manually. -export type AcmeSettings = { - provider: string - /** - * email addresses for letsencrypt - */ - contact: Array - /** - * domains to get letsencrypt certs for - */ - domains: string[] -} +export type AcmeSettings = { contact: Array } diff --git a/sdk/base/lib/osBindings/DomainConfig.ts b/sdk/base/lib/osBindings/DomainConfig.ts new file mode 100644 index 0000000000..433bc65f55 --- /dev/null +++ b/sdk/base/lib/osBindings/DomainConfig.ts @@ -0,0 +1,4 @@ +// This file was generated by [ts-rs](https://github.com/Aleph-Alpha/ts-rs). Do not edit this file manually. +import type { AcmeProvider } from "./AcmeProvider" + +export type DomainConfig = { public: boolean; acme: AcmeProvider | null } diff --git a/sdk/base/lib/osBindings/ForgetInterfaceParams.ts b/sdk/base/lib/osBindings/ForgetInterfaceParams.ts new file mode 100644 index 0000000000..b3532602c5 --- /dev/null +++ b/sdk/base/lib/osBindings/ForgetInterfaceParams.ts @@ -0,0 +1,3 @@ +// This file was generated by [ts-rs](https://github.com/Aleph-Alpha/ts-rs). Do not edit this file manually. + +export type ForgetInterfaceParams = { interface: string } diff --git a/sdk/base/lib/osBindings/Host.ts b/sdk/base/lib/osBindings/Host.ts index 7d8cf3a907..5436e99552 100644 --- a/sdk/base/lib/osBindings/Host.ts +++ b/sdk/base/lib/osBindings/Host.ts @@ -1,13 +1,14 @@ // This file was generated by [ts-rs](https://github.com/Aleph-Alpha/ts-rs). Do not edit this file manually. import type { BindInfo } from "./BindInfo" -import type { HostAddress } from "./HostAddress" +import type { DomainConfig } from "./DomainConfig" import type { HostKind } from "./HostKind" import type { HostnameInfo } from "./HostnameInfo" export type Host = { kind: HostKind bindings: { [key: number]: BindInfo } - addresses: Array + onions: string[] + domains: { [key: string]: DomainConfig } /** * COMPUTED: NetService::update */ diff --git a/sdk/base/lib/osBindings/IpInfo.ts b/sdk/base/lib/osBindings/IpInfo.ts index 0933b80e68..e9b0c9fb3d 100644 --- a/sdk/base/lib/osBindings/IpInfo.ts +++ b/sdk/base/lib/osBindings/IpInfo.ts @@ -4,4 +4,5 @@ export type IpInfo = { scopeId: number subnets: string[] wanIp: string | null + ntpServers: string[] } diff --git a/sdk/base/lib/osBindings/ServerInfo.ts b/sdk/base/lib/osBindings/ServerInfo.ts index b5d5be2933..6eec147456 100644 --- a/sdk/base/lib/osBindings/ServerInfo.ts +++ b/sdk/base/lib/osBindings/ServerInfo.ts @@ -1,4 +1,5 @@ // This file was generated by [ts-rs](https://github.com/Aleph-Alpha/ts-rs). Do not edit this file manually. +import type { AcmeProvider } from "./AcmeProvider" import type { AcmeSettings } from "./AcmeSettings" import type { Governor } from "./Governor" import type { LshwDevice } from "./LshwDevice" @@ -23,7 +24,7 @@ export type ServerInfo = { */ torAddress: string networkInterfaces: { [key: string]: NetworkInterfaceInfo } - acme: AcmeSettings | null + acme: { [key: AcmeProvider]: AcmeSettings } statusInfo: ServerStatus wifi: WifiInfo unreadNotificationCount: number diff --git a/sdk/base/lib/osBindings/index.ts b/sdk/base/lib/osBindings/index.ts index 623ebc23a1..b230aea31b 100644 --- a/sdk/base/lib/osBindings/index.ts +++ b/sdk/base/lib/osBindings/index.ts @@ -1,4 +1,5 @@ export { AcceptSigners } from "./AcceptSigners" +export { AcmeProvider } from "./AcmeProvider" export { AcmeSettings } from "./AcmeSettings" export { ActionId } from "./ActionId" export { ActionInput } from "./ActionInput" @@ -66,6 +67,7 @@ export { DepInfo } from "./DepInfo" export { Description } from "./Description" export { DestroySubcontainerFsParams } from "./DestroySubcontainerFsParams" export { DeviceFilter } from "./DeviceFilter" +export { DomainConfig } from "./DomainConfig" export { Duration } from "./Duration" export { EchoParams } from "./EchoParams" export { EditSignerParams } from "./EditSignerParams" @@ -73,6 +75,7 @@ export { EncryptedWire } from "./EncryptedWire" export { ExportActionParams } from "./ExportActionParams" export { ExportServiceInterfaceParams } from "./ExportServiceInterfaceParams" export { ExposeForDependentsParams } from "./ExposeForDependentsParams" +export { ForgetInterfaceParams } from "./ForgetInterfaceParams" export { FullIndex } from "./FullIndex" export { FullProgress } from "./FullProgress" export { GetActionInputParams } from "./GetActionInputParams" @@ -95,7 +98,6 @@ export { Governor } from "./Governor" export { Guid } from "./Guid" export { HardwareRequirements } from "./HardwareRequirements" export { HealthCheckId } from "./HealthCheckId" -export { HostAddress } from "./HostAddress" export { HostId } from "./HostId" export { HostKind } from "./HostKind" export { HostnameInfo } from "./HostnameInfo" diff --git a/web/projects/ui/src/app/services/api/mock-patch.ts b/web/projects/ui/src/app/services/api/mock-patch.ts index 9fd777da87..0e6477266f 100644 --- a/web/projects/ui/src/app/services/api/mock-patch.ts +++ b/web/projects/ui/src/app/services/api/mock-patch.ts @@ -48,6 +48,7 @@ export const mockPatchData: DataModel = { scopeId: 1, subnets: ['10.0.0.1/24'], wanIp: null, + ntpServers: [], }, }, wlan0: { @@ -59,6 +60,7 @@ export const mockPatchData: DataModel = { 'FE80:CD00:0000:0CDE:1257:0000:211E:729CD/64', ], wanIp: null, + ntpServers: [], }, }, },