From 827f0e65dc6d8c9032bc2f5aeace0a8bdecc438c Mon Sep 17 00:00:00 2001 From: dav Date: Sat, 13 Jul 2024 14:04:59 -0700 Subject: [PATCH 01/16] Have burrow gtk use new rpc --- burrow-gtk/Cargo.lock | 1903 +++-------------- burrow-gtk/Cargo.toml | 7 +- burrow-gtk/build-aux/build_appimage.sh | 1 - burrow-gtk/build.rs | 1 + burrow-gtk/src/components/app.rs | 26 +- burrow-gtk/src/components/mod.rs | 7 +- .../src/components/settings/daemon_group.rs | 4 +- .../src/components/settings/diag_group.rs | 6 +- burrow-gtk/src/components/settings_screen.rs | 2 +- burrow-gtk/src/components/switch_screen.rs | 28 +- 10 files changed, 364 insertions(+), 1621 deletions(-) diff --git a/burrow-gtk/Cargo.lock b/burrow-gtk/Cargo.lock index 6721318..fce2a3b 100644 --- a/burrow-gtk/Cargo.lock +++ b/burrow-gtk/Cargo.lock @@ -17,27 +17,6 @@ version = "1.0.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f26201604c87b1e01bd3d98f8d5d9a8fcbb815e8cedb41ffccbeb4bf593a35fe" -[[package]] -name = "aead" -version = "0.5.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d122413f284cf2d62fb1b7db97e02edb8cda96d769b16e443a4f6195e35662b0" -dependencies = [ - "crypto-common", - "generic-array", -] - -[[package]] -name = "aes" -version = "0.8.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ac1f845298e95f983ff1944b728ae08b8cebab80d684f0a832ed0fc74dfa27e2" -dependencies = [ - "cfg-if", - "cipher", - "cpufeatures", -] - [[package]] name = "aho-corasick" version = "1.1.2" @@ -47,54 +26,6 @@ dependencies = [ "memchr", ] -[[package]] -name = "anstream" -version = "0.6.11" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6e2e1ebcb11de5c03c67de28a7df593d32191b44939c482e97702baaaa6ab6a5" -dependencies = [ - "anstyle", - "anstyle-parse", - "anstyle-query", - "anstyle-wincon", - "colorchoice", - "utf8parse", -] - -[[package]] -name = "anstyle" -version = "1.0.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7079075b41f533b8c61d2a4d073c4676e1f8b249ff94a393b0595db304e0dd87" - -[[package]] -name = "anstyle-parse" -version = "0.2.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c75ac65da39e5fe5ab759307499ddad880d724eed2f6ce5b5e8a26f4f387928c" -dependencies = [ - "utf8parse", -] - -[[package]] -name = "anstyle-query" -version = "1.0.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e28923312444cdd728e4738b3f9c9cac739500909bb3d3c94b43551b16517648" -dependencies = [ - "windows-sys 0.52.0", -] - -[[package]] -name = "anstyle-wincon" -version = "3.0.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1cd54b81ec8d6180e24654d0b371ad22fc3dd083b6ff8ba325b72e00c87660a7" -dependencies = [ - "anstyle", - "windows-sys 0.52.0", -] - [[package]] name = "anyhow" version = "1.0.79" @@ -102,18 +33,27 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "080e9890a082662b09c1ad45f567faeeb47f22b5fb23895fbe1e651e718e25ca" [[package]] -name = "async-channel" -version = "2.1.1" +name = "async-stream" +version = "0.3.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1ca33f4bc4ed1babef42cad36cc1f51fa88be00420404e5b1e80ab1b18f7678c" +checksum = "cd56dd203fef61ac097dd65721a419ddccb106b2d2b70ba60a6b529f03961a51" dependencies = [ - "concurrent-queue", - "event-listener", - "event-listener-strategy", + "async-stream-impl", "futures-core", "pin-project-lite", ] +[[package]] +name = "async-stream-impl" +version = "0.3.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "16e62a023e7c117e27523144c5d2459f4397fcc3cab0085af8e2224f643a0193" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.48", +] + [[package]] name = "async-trait" version = "0.1.77" @@ -125,12 +65,65 @@ dependencies = [ "syn 2.0.48", ] +[[package]] +name = "atomic-waker" +version = "1.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1505bd5d3d116872e7271a6d4e16d81d0c8570876c8de68093a09ac269d8aac0" + [[package]] name = "autocfg" version = "1.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d468802bab17cbc0cc575e9b053f41e72aa36bfa6b7f55e3529ffa43161b97fa" +[[package]] +name = "axum" +version = "0.7.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3a6c9af12842a67734c9a2e355436e5d03b22383ed60cf13cd0c18fbfe3dcbcf" +dependencies = [ + "async-trait", + "axum-core", + "bytes", + "futures-util", + "http", + "http-body", + "http-body-util", + "itoa", + "matchit", + "memchr", + "mime", + "percent-encoding", + "pin-project-lite", + "rustversion", + "serde", + "sync_wrapper 1.0.1", + "tower", + "tower-layer", + "tower-service", +] + +[[package]] +name = "axum-core" +version = "0.4.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a15c63fd72d41492dc4f497196f5da1fb04fb7529e631d73630d1b491e47a2e3" +dependencies = [ + "async-trait", + "bytes", + "futures-util", + "http", + "http-body", + "http-body-util", + "mime", + "pin-project-lite", + "rustversion", + "sync_wrapper 0.1.2", + "tower-layer", + "tower-service", +] + [[package]] name = "backtrace" version = "0.3.69" @@ -148,60 +141,9 @@ dependencies = [ [[package]] name = "base64" -version = "0.21.7" +version = "0.22.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9d297deb1925b89f2ccc13d7635fa0714f12c87adce1c75356b39ca9b7178567" - -[[package]] -name = "base64ct" -version = "1.6.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8c3c1a368f70d6cf7302d78f8f7093da241fb8e8807c05cc9e51a125895a6d5b" - -[[package]] -name = "bindgen" -version = "0.64.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c4243e6031260db77ede97ad86c27e501d646a27ab57b59a574f725d98ab1fb4" -dependencies = [ - "bitflags 1.3.2", - "cexpr", - "clang-sys", - "lazy_static", - "lazycell", - "log", - "peeking_take_while", - "proc-macro2", - "quote", - "regex", - "rustc-hash", - "shlex", - "syn 1.0.109", - "which", -] - -[[package]] -name = "bindgen" -version = "0.65.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cfdf7b466f9a4903edc73f95d6d2bcd5baf8ae620638762244d3f60143643cc5" -dependencies = [ - "bitflags 1.3.2", - "cexpr", - "clang-sys", - "lazy_static", - "lazycell", - "log", - "peeking_take_while", - "prettyplease", - "proc-macro2", - "quote", - "regex", - "rustc-hash", - "shlex", - "syn 2.0.48", - "which", -] +checksum = "72b3254f16251a8381aa12e40e3c4d2f0199f8c6508fbecb9d91f575e0fbb8c6" [[package]] name = "bitflags" @@ -215,120 +157,41 @@ version = "2.4.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ed570934406eb16438a4e976b1b4500774099c13b8cb96eec99f620f05090ddf" -[[package]] -name = "blake2" -version = "0.10.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "46502ad458c9a52b69d4d4d32775c788b7a1b85e8bc9d482d92250fc0e3f8efe" -dependencies = [ - "digest", -] - [[package]] name = "block" version = "0.1.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "0d8c1fef690941d3e7788d328517591fecc684c084084702d6ff1641e993699a" -[[package]] -name = "block-buffer" -version = "0.10.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3078c7629b62d3f0439517fa394996acacc5cbc91c5a20d8c658e77abd503a71" -dependencies = [ - "generic-array", -] - [[package]] name = "bumpalo" version = "3.14.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "7f30e7476521f6f8af1a1c4c0b8cc94f0bee37d91763d0ca2665f299b6cd8aec" -[[package]] -name = "burrow" -version = "0.1.0" -dependencies = [ - "aead", - "anyhow", - "async-channel", - "base64", - "blake2", - "caps", - "chacha20poly1305", - "clap", - "console", - "fehler", - "futures", - "hmac", - "ip_network", - "ip_network_table", - "libsystemd", - "log", - "nix 0.27.1", - "once_cell", - "parking_lot", - "rand", - "rand_core", - "ring", - "schemars", - "serde", - "serde_json", - "tokio", - "tracing", - "tracing-journald", - "tracing-log 0.1.4", - "tracing-oslog", - "tracing-subscriber", - "tun", - "x25519-dalek", -] - [[package]] name = "burrow-gtk" version = "0.1.0" dependencies = [ "anyhow", - "burrow", "gettext-rs", "glib-build-tools", + "hyper-util", + "prost", + "prost-types", "relm4", "tokio", + "tonic", + "tonic-build", + "tower", ] -[[package]] -name = "byteorder" -version = "1.5.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1fd0f2584146f6f2ef48085050886acf353beff7305ebd1ae69500e27c67f64b" - [[package]] name = "bytes" version = "1.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "a2bd12c1caf447e69cd4528f47f94d203fd2582878ecb9e9465484c4148a8223" -[[package]] -name = "bzip2" -version = "0.4.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bdb116a6ef3f6c3698828873ad02c3014b3c85cadb88496095628e3ef1e347f8" -dependencies = [ - "bzip2-sys", - "libc", -] - -[[package]] -name = "bzip2-sys" -version = "0.1.11+1.0.8" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "736a955f3fa7875102d57c82b8cac37ec45224a07fd32d58f9f7a186b6cd4cdc" -dependencies = [ - "cc", - "libc", - "pkg-config", -] - [[package]] name = "cairo-rs" version = "0.17.10" @@ -354,35 +217,15 @@ dependencies = [ "system-deps", ] -[[package]] -name = "caps" -version = "0.5.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "190baaad529bcfbde9e1a19022c42781bdb6ff9de25721abdb8fd98c0807730b" -dependencies = [ - "libc", - "thiserror", -] - [[package]] name = "cc" version = "1.0.83" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f1174fb0b6ec23863f8b971027804a42614e347eafb0a95bf0b12cdae21fc4d0" dependencies = [ - "jobserver", "libc", ] -[[package]] -name = "cexpr" -version = "0.6.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6fac387a98bb7c37292057cffc56d62ecb629900026402633ae9160df93a8766" -dependencies = [ - "nom", -] - [[package]] name = "cfg-expr" version = "0.15.6" @@ -399,251 +242,12 @@ version = "1.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd" -[[package]] -name = "chacha20" -version = "0.9.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c3613f74bd2eac03dad61bd53dbe620703d4371614fe0bc3b9f04dd36fe4e818" -dependencies = [ - "cfg-if", - "cipher", - "cpufeatures", -] - -[[package]] -name = "chacha20poly1305" -version = "0.10.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "10cd79432192d1c0f4e1a0fef9527696cc039165d729fb41b3f4f4f354c2dc35" -dependencies = [ - "aead", - "chacha20", - "cipher", - "poly1305", - "zeroize", -] - -[[package]] -name = "cipher" -version = "0.4.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "773f3b9af64447d2ce9850330c473515014aa235e6a783b02db81ff39e4a3dad" -dependencies = [ - "crypto-common", - "inout", - "zeroize", -] - -[[package]] -name = "clang-sys" -version = "1.7.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "67523a3b4be3ce1989d607a828d036249522dd9c1c8de7f4dd2dae43a37369d1" -dependencies = [ - "glob", - "libc", - "libloading 0.8.1", -] - -[[package]] -name = "clap" -version = "4.4.18" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1e578d6ec4194633722ccf9544794b71b1385c3c027efe0c55db226fc880865c" -dependencies = [ - "clap_builder", - "clap_derive", -] - -[[package]] -name = "clap_builder" -version = "4.4.18" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4df4df40ec50c46000231c914968278b1eb05098cf8f1b3a518a95030e71d1c7" -dependencies = [ - "anstream", - "anstyle", - "clap_lex", - "strsim", -] - -[[package]] -name = "clap_derive" -version = "4.4.7" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cf9804afaaf59a91e75b022a30fb7229a7901f60c755489cc61c9b423b836442" -dependencies = [ - "heck", - "proc-macro2", - "quote", - "syn 2.0.48", -] - -[[package]] -name = "clap_lex" -version = "0.6.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "702fc72eb24e5a1e48ce58027a675bc24edd52096d5397d4aea7c6dd9eca0bd1" - -[[package]] -name = "colorchoice" -version = "1.0.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "acbf1af155f9b9ef647e42cdc158db4b64a1b61f743629225fde6f3e0be2a7c7" - -[[package]] -name = "concurrent-queue" -version = "2.4.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d16048cd947b08fa32c24458a22f5dc5e835264f689f4f5653210c69fd107363" -dependencies = [ - "crossbeam-utils", -] - -[[package]] -name = "console" -version = "0.15.8" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0e1f83fc076bd6dd27517eacdf25fef6c4dfe5f1d7448bafaaf3a26f13b5e4eb" -dependencies = [ - "encode_unicode", - "lazy_static", - "libc", - "unicode-width", - "windows-sys 0.52.0", -] - -[[package]] -name = "constant_time_eq" -version = "0.1.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "245097e9a4535ee1e3e3931fcfcd55a796a44c643e8596ff6566d68f09b87bbc" - -[[package]] -name = "core-foundation" -version = "0.9.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "91e195e091a93c46f7102ec7818a2aa394e1e1771c3ab4825963fa03e45afb8f" -dependencies = [ - "core-foundation-sys", - "libc", -] - -[[package]] -name = "core-foundation-sys" -version = "0.8.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "06ea2b9bc92be3c2baa9334a323ebca2d6f074ff852cd1d7b11064035cd3868f" - -[[package]] -name = "cpufeatures" -version = "0.2.12" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "53fe5e26ff1b7aef8bca9c6080520cfb8d9333c7568e1829cef191a9723e5504" -dependencies = [ - "libc", -] - -[[package]] -name = "crc32fast" -version = "1.3.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b540bd8bc810d3885c6ea91e2018302f68baba2129ab3e88f32389ee9370880d" -dependencies = [ - "cfg-if", -] - -[[package]] -name = "crossbeam-utils" -version = "0.8.19" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "248e3bacc7dc6baa3b21e405ee045c3047101a49145e7e9eca583ab4c2ca5345" - -[[package]] -name = "crypto-common" -version = "0.1.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1bfb12502f3fc46cca1bb51ac28df9d618d813cdc3d2f25b9fe775a34af26bb3" -dependencies = [ - "generic-array", - "rand_core", - "typenum", -] - -[[package]] -name = "curve25519-dalek" -version = "4.1.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e89b8c6a2e4b1f45971ad09761aafb85514a84744b67a95e32c3cc1352d1f65c" -dependencies = [ - "cfg-if", - "cpufeatures", - "curve25519-dalek-derive", - "fiat-crypto", - "platforms", - "rustc_version", - "subtle", - "zeroize", -] - -[[package]] -name = "curve25519-dalek-derive" -version = "0.1.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f46882e17999c6cc590af592290432be3bce0428cb0d5f8b6715e4dc7b383eb3" -dependencies = [ - "proc-macro2", - "quote", - "syn 2.0.48", -] - -[[package]] -name = "deranged" -version = "0.3.11" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b42b6fa04a440b495c8b04d0e71b707c585f83cb9cb28cf8cd0d976c315e31b4" -dependencies = [ - "powerfmt", -] - -[[package]] -name = "digest" -version = "0.10.7" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9ed9a281f7bc9b7576e61468ba615a66a5c8cfdff42420a70aa82701a3b1e292" -dependencies = [ - "block-buffer", - "crypto-common", - "subtle", -] - -[[package]] -name = "dyn-clone" -version = "1.0.16" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "545b22097d44f8a9581187cdf93de7a71e4722bf51200cfaba810865b49a495d" - [[package]] name = "either" version = "1.9.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "a26ae43d7bcc3b814de94796a5e736d4029efb0ee900c12e2d54c993ad1a1e07" -[[package]] -name = "encode_unicode" -version = "0.3.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a357d28ed41a50f9c765dbfe56cbc04a64e53e5fc58ba79fbc34c10ef3df831f" - -[[package]] -name = "encoding_rs" -version = "0.8.33" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7268b386296a025e474d5140678f75d6de9493ae55a5d709eeb9dd08149945e1" -dependencies = [ - "cfg-if", -] - [[package]] name = "equivalent" version = "1.0.1" @@ -660,78 +264,27 @@ dependencies = [ "windows-sys 0.52.0", ] -[[package]] -name = "event-listener" -version = "4.0.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "67b215c49b2b248c855fb73579eb1f4f26c38ffdc12973e20e07b91d78d5646e" -dependencies = [ - "concurrent-queue", - "parking", - "pin-project-lite", -] - -[[package]] -name = "event-listener-strategy" -version = "0.4.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "958e4d70b6d5e81971bebec42271ec641e7ff4e170a6fa605f2b8a8b65cb97d3" -dependencies = [ - "event-listener", - "pin-project-lite", -] - [[package]] name = "fastrand" version = "2.0.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "25cbce373ec4653f1a01a31e8a5e5ec0c622dc27ff9c4e6606eefef5cbbed4a5" -[[package]] -name = "fehler" -version = "1.0.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d5729fe49ba028cd550747b6e62cd3d841beccab5390aa398538c31a2d983635" -dependencies = [ - "fehler-macros", -] - -[[package]] -name = "fehler-macros" -version = "1.0.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ccb5acb1045ebbfa222e2c50679e392a71dd77030b78fb0189f2d9c5974400f9" -dependencies = [ - "proc-macro2", - "quote", - "syn 1.0.109", -] - -[[package]] -name = "fiat-crypto" -version = "0.2.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "27573eac26f4dd11e2b1916c3fe1baa56407c83c71a773a8ba17ec0bca03b6b7" - [[package]] name = "field-offset" version = "0.3.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "38e2275cc4e4fc009b0669731a1e5ab7ebf11f469eaede2bab9309a5b4d6057f" dependencies = [ - "memoffset 0.9.0", + "memoffset", "rustc_version", ] [[package]] -name = "flate2" -version = "1.0.28" +name = "fixedbitset" +version = "0.4.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "46303f565772937ffe1d394a4fac6f411c6013172fadde9dcdb1e147a086940e" -dependencies = [ - "crc32fast", - "miniz_oxide", -] +checksum = "0ce7134b9999ecaf8bcd65542e436736ef32ddca1b3e06094cb6ec5755203b80" [[package]] name = "flume" @@ -752,30 +305,6 @@ version = "1.0.7" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "3f9eec918d3f24069decb9af1554cad7c880e2da24a9afd88aca000531ab82c1" -[[package]] -name = "foreign-types" -version = "0.3.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f6f339eb8adc052cd2ca78910fda869aefa38d22d5cb648e6485e4d3fc06f3b1" -dependencies = [ - "foreign-types-shared", -] - -[[package]] -name = "foreign-types-shared" -version = "0.1.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "00b0228411908ca8685dba7fc2cdd70ec9990a6e753e89b6ac91a84c40fbaf4b" - -[[package]] -name = "form_urlencoded" -version = "1.2.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e13624c2627564efccf4934284bdd98cbaa14e79b0b5a141218e507b3a823456" -dependencies = [ - "percent-encoding", -] - [[package]] name = "fragile" version = "2.0.0" @@ -931,16 +460,6 @@ dependencies = [ "system-deps", ] -[[package]] -name = "generic-array" -version = "0.14.7" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "85649ca51fd72272d7821adaf274ad91c288277713d9c18820d8499a7ff69e9a" -dependencies = [ - "typenum", - "version_check", -] - [[package]] name = "getrandom" version = "0.2.12" @@ -1067,12 +586,6 @@ dependencies = [ "system-deps", ] -[[package]] -name = "glob" -version = "0.3.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d2fabcfbdc87f4758337ca535fb41a6d701b65693ce38287d856d1674551ec9b" - [[package]] name = "gobject-sys" version = "0.17.10" @@ -1197,23 +710,29 @@ dependencies = [ [[package]] name = "h2" -version = "0.3.24" +version = "0.4.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bb2c4422095b67ee78da96fbb51a4cc413b3b25883c7717ff7ca1ab31022c9c9" +checksum = "fa82e28a107a8cc405f0839610bdc9b15f1e25ec7d696aa5cf173edbcb1486ab" dependencies = [ + "atomic-waker", "bytes", "fnv", "futures-core", "futures-sink", - "futures-util", "http", - "indexmap", + "indexmap 2.1.0", "slab", "tokio", "tokio-util", "tracing", ] +[[package]] +name = "hashbrown" +version = "0.12.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8a9ee70c43aaf417c914396645a0fa852624801b24ebb7ae78fe8272889ac888" + [[package]] name = "hashbrown" version = "0.14.3" @@ -1232,35 +751,11 @@ version = "0.3.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "5d3d0e0f38255e7fa3cf31335b3a56f05febd18025f4db5ef7a0cfb4f8da651f" -[[package]] -name = "hex" -version = "0.4.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7f24254aa9a54b5c858eaee2f5bccdb46aaf0e486a595ed5fd8f86ba55232a70" - -[[package]] -name = "hmac" -version = "0.12.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6c49c37c09c17a53d937dfbb742eb3a961d65a994e6bcdcf37e7399d0cc8ab5e" -dependencies = [ - "digest", -] - -[[package]] -name = "home" -version = "0.5.9" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e3d1354bf6b7235cb4a0576c2619fd4ed18183f689b12b006a0ee7329eeff9a5" -dependencies = [ - "windows-sys 0.52.0", -] - [[package]] name = "http" -version = "0.2.11" +version = "1.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8947b1a6fad4393052c7ba1f4cd97bed3e953a95c79c92ad9b051a04611d9fbb" +checksum = "21b9ddb458710bc376481b842f5da65cdf31522de232c1ca8146abce2a358258" dependencies = [ "bytes", "fnv", @@ -1269,12 +764,24 @@ dependencies = [ [[package]] name = "http-body" -version = "0.4.6" +version = "1.0.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7ceab25649e9960c0311ea418d17bee82c0dcec1bd053b5f9a66e265a693bed2" +checksum = "1efedce1fb8e6913f23e0c92de8e62cd5b772a67e7b3946df930a62566c93184" dependencies = [ "bytes", "http", +] + +[[package]] +name = "http-body-util" +version = "0.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "793429d76616a256bcb62c2a2ec2bed781c8307e797e2598c50010f2bee2544f" +dependencies = [ + "bytes", + "futures-util", + "http", + "http-body", "pin-project-lite", ] @@ -1292,13 +799,12 @@ checksum = "df3b46402a9d5adb4c86a0cf463f42e19994e3ee891101b1841f30a545cb49a9" [[package]] name = "hyper" -version = "0.14.28" +version = "1.4.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bf96e135eb83a2a8ddf766e426a841d8ddd7449d5f00d34ea02b41d2f19eef80" +checksum = "50dfd22e0e76d0f662d429a5f80fcaf3855009297eab6a0a9f8543834744ba05" dependencies = [ "bytes", "futures-channel", - "futures-core", "futures-util", "h2", "http", @@ -1307,34 +813,52 @@ dependencies = [ "httpdate", "itoa", "pin-project-lite", - "socket2 0.5.5", + "smallvec", "tokio", - "tower-service", - "tracing", "want", ] [[package]] -name = "hyper-tls" -version = "0.5.0" +name = "hyper-timeout" +version = "0.5.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d6183ddfa99b85da61a140bea0efc93fdf56ceaa041b37d553518030827f9905" +checksum = "3203a961e5c83b6f5498933e78b6b263e208c197b63e9c6c53cc82ffd3f63793" dependencies = [ - "bytes", "hyper", - "native-tls", + "hyper-util", + "pin-project-lite", "tokio", - "tokio-native-tls", + "tower-service", ] [[package]] -name = "idna" -version = "0.5.0" +name = "hyper-util" +version = "0.1.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "634d9b1461af396cad843f47fdba5597a4f9e6ddd4bfb6ff5d85028c25cb12f6" +checksum = "3ab92f4f49ee4fb4f997c784b7a2e0fa70050211e0b6a287f898c3c9785ca956" dependencies = [ - "unicode-bidi", - "unicode-normalization", + "bytes", + "futures-channel", + "futures-util", + "http", + "http-body", + "hyper", + "pin-project-lite", + "socket2", + "tokio", + "tower", + "tower-service", + "tracing", +] + +[[package]] +name = "indexmap" +version = "1.9.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bd070e393353796e801d209ad339e89596eb4c8d430d18ede6a1cced8fafbd99" +dependencies = [ + "autocfg", + "hashbrown 0.12.3", ] [[package]] @@ -1344,61 +868,24 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d530e1a18b1cb4c484e6e34556a0d948706958449fca0cab753d649f2bce3d1f" dependencies = [ "equivalent", - "hashbrown", + "hashbrown 0.14.3", ] [[package]] -name = "inout" -version = "0.1.3" +name = "itertools" +version = "0.13.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a0c10553d664a4d0bcff9f4215d0aac67a639cc68ef660840afe309b807bc9f5" +checksum = "413ee7dfc52ee1a4949ceeb7dbc8a33f2d6c088194d9f922fb8318faf1f01186" dependencies = [ - "generic-array", + "either", ] -[[package]] -name = "ip_network" -version = "0.4.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "aa2f047c0a98b2f299aa5d6d7088443570faae494e9ae1305e48be000c9e0eb1" - -[[package]] -name = "ip_network_table" -version = "0.2.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4099b7cfc5c5e2fe8c5edf3f6f7adf7a714c9cc697534f63a5a5da30397cb2c0" -dependencies = [ - "ip_network", - "ip_network_table-deps-treebitmap", -] - -[[package]] -name = "ip_network_table-deps-treebitmap" -version = "0.5.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8e537132deb99c0eb4b752f0346b6a836200eaaa3516dd7e5514b63930a09e5d" - -[[package]] -name = "ipnet" -version = "2.9.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8f518f335dce6725a761382244631d86cf0ccb2863413590b31338feb467f9c3" - [[package]] name = "itoa" version = "1.0.10" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b1a46d1a171d865aa5f83f92695765caa047a9b4cbae2cbf37dbd613a793fd4c" -[[package]] -name = "jobserver" -version = "0.1.27" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8c37f63953c4c63420ed5fd3d6d398c719489b9f872b9fa683262f8edd363c7d" -dependencies = [ - "libc", -] - [[package]] name = "js-sys" version = "0.3.67" @@ -1414,12 +901,6 @@ version = "1.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e2abad23fbc42b3700f2f279844dc832adb2b2eb069b2df918f455c4e18cc646" -[[package]] -name = "lazycell" -version = "1.3.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "830d08ce1d1d941e6b30645f1a0eb5643013d835ce3779a5fc208261dbe10f55" - [[package]] name = "libadwaita" version = "0.4.4" @@ -1459,44 +940,6 @@ version = "0.2.152" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "13e3bf6590cbc649f4d1a3eefc9d5d6eb746f5200ffb04e5e142700b8faa56e7" -[[package]] -name = "libloading" -version = "0.7.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b67380fd3b2fbe7527a606e18729d21c6f3951633d0500574c4dc22d2d638b9f" -dependencies = [ - "cfg-if", - "winapi", -] - -[[package]] -name = "libloading" -version = "0.8.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c571b676ddfc9a8c12f1f3d3085a7b163966a8fd8098a90640953ce5f6170161" -dependencies = [ - "cfg-if", - "windows-sys 0.48.0", -] - -[[package]] -name = "libsystemd" -version = "0.7.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c592dc396b464005f78a5853555b9f240bc5378bf5221acc4e129910b2678869" -dependencies = [ - "hmac", - "libc", - "log", - "nix 0.27.1", - "nom", - "once_cell", - "serde", - "sha2", - "thiserror", - "uuid", -] - [[package]] name = "linux-raw-sys" version = "0.4.13" @@ -1542,13 +985,10 @@ dependencies = [ ] [[package]] -name = "matchers" -version = "0.1.0" +name = "matchit" +version = "0.7.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8263075bb86c5a1b1427b5ae862e8889656f126e9f77c484496e8b47cf5c5558" -dependencies = [ - "regex-automata 0.1.10", -] +checksum = "0e7465ac9959cc2b1404e8e2367b43684a6d13790fe23056cc8c6c5a6b7bcb94" [[package]] name = "memchr" @@ -1556,15 +996,6 @@ version = "2.7.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "523dc4f511e55ab87b694dc30d0f820d60906ef06413f93d4d7a1385599cc149" -[[package]] -name = "memoffset" -version = "0.7.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5de893c32cde5f383baa4c04c5d6dbdd735cfd4a794b0debdb2bb1b421da5ff4" -dependencies = [ - "autocfg", -] - [[package]] name = "memoffset" version = "0.9.0" @@ -1574,41 +1005,12 @@ dependencies = [ "autocfg", ] -[[package]] -name = "miette" -version = "5.10.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "59bb584eaeeab6bd0226ccf3509a69d7936d148cf3d036ad350abe35e8c6856e" -dependencies = [ - "miette-derive", - "once_cell", - "thiserror", - "unicode-width", -] - -[[package]] -name = "miette-derive" -version = "5.10.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "49e7bc1560b95a3c4a25d03de42fe76ca718ab92d1a22a55b9b4cf67b3ae635c" -dependencies = [ - "proc-macro2", - "quote", - "syn 2.0.48", -] - [[package]] name = "mime" version = "0.3.17" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "6877bb514081ee2a7ff5ef9de3281f14a4dd4bceac4c09388074a6b5df8a139a" -[[package]] -name = "minimal-lexical" -version = "0.2.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "68354c5c6bd36d73ff3feceb05efa59b6acb7626617f4962be322a825e61f79a" - [[package]] name = "miniz_oxide" version = "0.7.1" @@ -1629,6 +1031,12 @@ dependencies = [ "windows-sys 0.48.0", ] +[[package]] +name = "multimap" +version = "0.10.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "defc4c55412d89136f966bbb339008b474350e5e6e78d2714439c386b3137a03" + [[package]] name = "nanorand" version = "0.7.0" @@ -1638,69 +1046,6 @@ dependencies = [ "getrandom", ] -[[package]] -name = "native-tls" -version = "0.2.11" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "07226173c32f2926027b63cce4bcd8076c3552846cbe7925f3aaffeac0a3b92e" -dependencies = [ - "lazy_static", - "libc", - "log", - "openssl", - "openssl-probe", - "openssl-sys", - "schannel", - "security-framework", - "security-framework-sys", - "tempfile", -] - -[[package]] -name = "nix" -version = "0.26.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "598beaf3cc6fdd9a5dfb1630c2800c7acd31df7aaf0f565796fba2b53ca1af1b" -dependencies = [ - "bitflags 1.3.2", - "cfg-if", - "libc", - "memoffset 0.7.1", - "pin-utils", -] - -[[package]] -name = "nix" -version = "0.27.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2eb04e9c688eff1c89d72b407f168cf79bb9e867a9d3323ed6c01519eb9cc053" -dependencies = [ - "bitflags 2.4.2", - "cfg-if", - "libc", - "memoffset 0.9.0", -] - -[[package]] -name = "nom" -version = "7.1.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d273983c5a657a70a3e8f2a01329822f3b8c8172b73826411a55751e404a0a4a" -dependencies = [ - "memchr", - "minimal-lexical", -] - -[[package]] -name = "nu-ansi-term" -version = "0.46.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "77a8165726e8236064dbb45459242600304b42a5ea24ee2948e18e023bf7ba84" -dependencies = [ - "overload", - "winapi", -] - [[package]] name = "num_cpus" version = "1.16.0" @@ -1755,62 +1100,6 @@ version = "1.19.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "3fdb12b2476b595f9358c5161aa467c2438859caa136dec86c26fdd2efe17b92" -[[package]] -name = "opaque-debug" -version = "0.3.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "624a8340c38c1b80fd549087862da4ba43e08858af025b236e509b6649fc13d5" - -[[package]] -name = "openssl" -version = "0.10.63" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "15c9d69dd87a29568d4d017cfe8ec518706046a05184e5aea92d0af890b803c8" -dependencies = [ - "bitflags 2.4.2", - "cfg-if", - "foreign-types", - "libc", - "once_cell", - "openssl-macros", - "openssl-sys", -] - -[[package]] -name = "openssl-macros" -version = "0.1.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a948666b637a0f465e8564c73e89d4dde00d72d4d473cc972f390fc3dcee7d9c" -dependencies = [ - "proc-macro2", - "quote", - "syn 2.0.48", -] - -[[package]] -name = "openssl-probe" -version = "0.1.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ff011a302c396a5197692431fc1948019154afc178baf7d8e37367442a4601cf" - -[[package]] -name = "openssl-sys" -version = "0.9.99" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "22e1bf214306098e4832460f797824c05d25aacdf896f64a985fb0fd992454ae" -dependencies = [ - "cc", - "libc", - "pkg-config", - "vcpkg", -] - -[[package]] -name = "overload" -version = "0.1.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b15813163c1d831bf4a13c3610c05c0d03b39feb07f7e09fa234dac9b15aaf39" - [[package]] name = "pango" version = "0.17.10" @@ -1837,70 +1126,22 @@ dependencies = [ "system-deps", ] -[[package]] -name = "parking" -version = "2.2.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bb813b8af86854136c6922af0598d719255ecb2179515e6e7730d468f05c9cae" - -[[package]] -name = "parking_lot" -version = "0.12.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3742b2c103b9f06bc9fff0a37ff4912935851bee6d36f3c02bcc755bcfec228f" -dependencies = [ - "lock_api", - "parking_lot_core", -] - -[[package]] -name = "parking_lot_core" -version = "0.9.9" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4c42a9226546d68acdd9c0a280d17ce19bfe27a46bf68784e4066115788d008e" -dependencies = [ - "cfg-if", - "libc", - "redox_syscall", - "smallvec", - "windows-targets 0.48.5", -] - -[[package]] -name = "password-hash" -version = "0.4.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7676374caaee8a325c9e7a2ae557f216c5563a171d6997b0ef8a65af35147700" -dependencies = [ - "base64ct", - "rand_core", - "subtle", -] - -[[package]] -name = "pbkdf2" -version = "0.11.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "83a0692ec44e4cf1ef28ca317f14f8f07da2d95ec3fa01f86e4467b725e60917" -dependencies = [ - "digest", - "hmac", - "password-hash", - "sha2", -] - -[[package]] -name = "peeking_take_while" -version = "0.1.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "19b17cddbe7ec3f8bc800887bab5e717348c95ea2ca0b1bf0837fb964dc67099" - [[package]] name = "percent-encoding" version = "2.3.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e3148f5046208a5d56bcfc03053e3ca6334e51da8dfb19b6cdc8b306fae3283e" +[[package]] +name = "petgraph" +version = "0.6.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b4c5cc86750666a3ed20bdaf5ca2a0344f9c67674cae0515bec2da16fbaa47db" +dependencies = [ + "fixedbitset", + "indexmap 2.1.0", +] + [[package]] name = "pin-project" version = "1.1.4" @@ -1939,29 +1180,6 @@ version = "0.3.29" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "2900ede94e305130c13ddd391e0ab7cbaeb783945ae07a279c268cb05109c6cb" -[[package]] -name = "platforms" -version = "3.3.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "626dec3cac7cc0e1577a2ec3fc496277ec2baa084bebad95bb6fdbfae235f84c" - -[[package]] -name = "poly1305" -version = "0.8.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8159bd90725d2df49889a078b54f4f79e87f1f8a8444194cdca81d38f5393abf" -dependencies = [ - "cpufeatures", - "opaque-debug", - "universal-hash", -] - -[[package]] -name = "powerfmt" -version = "0.2.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "439ee305def115ba05938db6eb1644ff94165c5ab5e9420d1c1bcedbba909391" - [[package]] name = "ppv-lite86" version = "0.2.17" @@ -2021,6 +1239,59 @@ dependencies = [ "unicode-ident", ] +[[package]] +name = "prost" +version = "0.13.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e13db3d3fde688c61e2446b4d843bc27a7e8af269a69440c0308021dc92333cc" +dependencies = [ + "bytes", + "prost-derive", +] + +[[package]] +name = "prost-build" +version = "0.13.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5bb182580f71dd070f88d01ce3de9f4da5021db7115d2e1c3605a754153b77c1" +dependencies = [ + "bytes", + "heck", + "itertools", + "log", + "multimap", + "once_cell", + "petgraph", + "prettyplease", + "prost", + "prost-types", + "regex", + "syn 2.0.48", + "tempfile", +] + +[[package]] +name = "prost-derive" +version = "0.13.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "18bec9b0adc4eba778b33684b7ba3e7137789434769ee3ce3930463ef904cfca" +dependencies = [ + "anyhow", + "itertools", + "proc-macro2", + "quote", + "syn 2.0.48", +] + +[[package]] +name = "prost-types" +version = "0.13.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cee5168b05f49d4b0ca581206eb14a7b22fafd963efe729ac48eb03266e25cc2" +dependencies = [ + "prost", +] + [[package]] name = "quote" version = "1.0.35" @@ -2077,17 +1348,8 @@ checksum = "b62dbe01f0b06f9d8dc7d49e05a0785f153b00b2c227856282f671e0318c9b15" dependencies = [ "aho-corasick", "memchr", - "regex-automata 0.4.4", - "regex-syntax 0.8.2", -] - -[[package]] -name = "regex-automata" -version = "0.1.10" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6c230d73fb8d8c1b9c0b3135c5142a8acee3a0558fb8db5cf1cb65f8d7862132" -dependencies = [ - "regex-syntax 0.6.29", + "regex-automata", + "regex-syntax", ] [[package]] @@ -2098,15 +1360,9 @@ checksum = "3b7fa1134405e2ec9353fd416b17f8dacd46c473d7d3fd1cf202706a14eb792a" dependencies = [ "aho-corasick", "memchr", - "regex-syntax 0.8.2", + "regex-syntax", ] -[[package]] -name = "regex-syntax" -version = "0.6.29" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f162c6dd7b008981e4d40210aca20b4bd0f9b60ca9271061b07f78537722f2e1" - [[package]] name = "regex-syntax" version = "0.8.2" @@ -2142,70 +1398,12 @@ dependencies = [ "syn 2.0.48", ] -[[package]] -name = "reqwest" -version = "0.11.23" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "37b1ae8d9ac08420c66222fb9096fc5de435c3c48542bc5336c51892cffafb41" -dependencies = [ - "base64", - "bytes", - "encoding_rs", - "futures-core", - "futures-util", - "h2", - "http", - "http-body", - "hyper", - "hyper-tls", - "ipnet", - "js-sys", - "log", - "mime", - "native-tls", - "once_cell", - "percent-encoding", - "pin-project-lite", - "serde", - "serde_json", - "serde_urlencoded", - "system-configuration", - "tokio", - "tokio-native-tls", - "tower-service", - "url", - "wasm-bindgen", - "wasm-bindgen-futures", - "web-sys", - "winreg", -] - -[[package]] -name = "ring" -version = "0.17.7" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "688c63d65483050968b2a8937f7995f443e27041a0f7700aa59b0822aedebb74" -dependencies = [ - "cc", - "getrandom", - "libc", - "spin", - "untrusted", - "windows-sys 0.48.0", -] - [[package]] name = "rustc-demangle" version = "0.1.23" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d626bb9dae77e28219937af045c257c28bfd3f69333c512553507f5f9798cb76" -[[package]] -name = "rustc-hash" -version = "1.1.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "08d43f7aa6b08d49f382cde6a7982047c3426db949b1424bc4b7ec9ae12c6ce2" - [[package]] name = "rustc_version" version = "0.4.0" @@ -2229,43 +1427,10 @@ dependencies = [ ] [[package]] -name = "ryu" -version = "1.0.16" +name = "rustversion" +version = "1.0.17" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f98d2aa92eebf49b69786be48e4477826b256916e84a57ff2a4f21923b48eb4c" - -[[package]] -name = "schannel" -version = "0.1.23" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fbc91545643bcf3a0bbb6569265615222618bdf33ce4ffbbd13c4bbd4c093534" -dependencies = [ - "windows-sys 0.52.0", -] - -[[package]] -name = "schemars" -version = "0.8.16" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "45a28f4c49489add4ce10783f7911893516f15afe45d015608d41faca6bc4d29" -dependencies = [ - "dyn-clone", - "schemars_derive", - "serde", - "serde_json", -] - -[[package]] -name = "schemars_derive" -version = "0.8.16" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c767fd6fa65d9ccf9cf026122c1b555f2ef9a4f0cea69da4d7dbc3e258d30967" -dependencies = [ - "proc-macro2", - "quote", - "serde_derive_internals", - "syn 1.0.109", -] +checksum = "955d28af4278de8121b7ebeb796b6a45735dc01436d898801014aced2773a3d6" [[package]] name = "scopeguard" @@ -2273,29 +1438,6 @@ version = "1.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "94143f37725109f92c262ed2cf5e59bce7498c01bcc1502d7b9afe439a4e9f49" -[[package]] -name = "security-framework" -version = "2.9.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "05b64fb303737d99b81884b2c63433e9ae28abebe5eb5045dcdd175dc2ecf4de" -dependencies = [ - "bitflags 1.3.2", - "core-foundation", - "core-foundation-sys", - "libc", - "security-framework-sys", -] - -[[package]] -name = "security-framework-sys" -version = "2.9.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e932934257d3b408ed8f30db49d85ea163bfe74961f017f405b025af298f0c7a" -dependencies = [ - "core-foundation-sys", - "libc", -] - [[package]] name = "semver" version = "1.0.21" @@ -2322,28 +1464,6 @@ dependencies = [ "syn 2.0.48", ] -[[package]] -name = "serde_derive_internals" -version = "0.26.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "85bf8229e7920a9f636479437026331ce11aa132b4dde37d121944a44d6e5f3c" -dependencies = [ - "proc-macro2", - "quote", - "syn 1.0.109", -] - -[[package]] -name = "serde_json" -version = "1.0.111" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "176e46fa42316f18edd598015a5166857fc835ec732f5215eac6b7bdbf0a84f4" -dependencies = [ - "itoa", - "ryu", - "serde", -] - [[package]] name = "serde_spanned" version = "0.6.5" @@ -2353,66 +1473,6 @@ dependencies = [ "serde", ] -[[package]] -name = "serde_urlencoded" -version = "0.7.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d3491c14715ca2294c4d6a88f15e84739788c1d030eed8c110436aafdaa2f3fd" -dependencies = [ - "form_urlencoded", - "itoa", - "ryu", - "serde", -] - -[[package]] -name = "sha-1" -version = "0.10.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f5058ada175748e33390e40e872bd0fe59a19f265d0158daa551c5a88a76009c" -dependencies = [ - "cfg-if", - "cpufeatures", - "digest", -] - -[[package]] -name = "sha1" -version = "0.10.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e3bf829a2d51ab4a5ddf1352d8470c140cadc8301b2ae1789db023f01cedd6ba" -dependencies = [ - "cfg-if", - "cpufeatures", - "digest", -] - -[[package]] -name = "sha2" -version = "0.10.8" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "793db75ad2bcafc3ffa7c68b215fee268f537982cd901d132f89c6343f3a3dc8" -dependencies = [ - "cfg-if", - "cpufeatures", - "digest", -] - -[[package]] -name = "sharded-slab" -version = "0.1.7" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f40ca3c46823713e0d4209592e8d6e826aa57e928f09752619fc696c499637f6" -dependencies = [ - "lazy_static", -] - -[[package]] -name = "shlex" -version = "1.3.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0fda2ff0d084019ba4d7c6f371c95d8fd75ce3524c3cb8fb653a3023f6323e64" - [[package]] name = "slab" version = "0.4.9" @@ -2428,16 +1488,6 @@ version = "1.13.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e6ecd384b10a64542d77071bd64bd7b231f4ed5940fba55e98c3de13824cf3d7" -[[package]] -name = "socket2" -version = "0.4.10" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9f7916fc008ca5542385b89a3d3ce689953c143e9304a9bf8beec1de48994c0d" -dependencies = [ - "libc", - "winapi", -] - [[package]] name = "socket2" version = "0.5.5" @@ -2457,34 +1507,6 @@ dependencies = [ "lock_api", ] -[[package]] -name = "ssri" -version = "9.2.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "da7a2b3c2bc9693bcb40870c4e9b5bf0d79f9cb46273321bf855ec513e919082" -dependencies = [ - "base64", - "digest", - "hex", - "miette", - "sha-1", - "sha2", - "thiserror", - "xxhash-rust", -] - -[[package]] -name = "strsim" -version = "0.10.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "73473c0e59e6d5812c5dfe2a064a6444949f089e20eec9a2e5506596494e4623" - -[[package]] -name = "subtle" -version = "2.5.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "81cdd64d312baedb58e21336b31bc043b77e01cc99033ce76ef539f78e965ebc" - [[package]] name = "syn" version = "1.0.109" @@ -2508,25 +1530,16 @@ dependencies = [ ] [[package]] -name = "system-configuration" -version = "0.5.1" +name = "sync_wrapper" +version = "0.1.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ba3a3adc5c275d719af8cb4272ea1c4a6d668a777f37e115f6d11ddbc1c8e0e7" -dependencies = [ - "bitflags 1.3.2", - "core-foundation", - "system-configuration-sys", -] +checksum = "2047c6ded9c721764247e62cd3b03c09ffc529b2ba5b10ec482ae507a4a70160" [[package]] -name = "system-configuration-sys" -version = "0.5.0" +name = "sync_wrapper" +version = "1.0.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a75fb188eb626b924683e3b95e3a48e63551fcfb51949de2f06a9d91dbee93c9" -dependencies = [ - "core-foundation-sys", - "libc", -] +checksum = "a7065abeca94b6a8a577f9bd45aa0867a2238b74e8eb67cf10d492bc39351394" [[package]] name = "system-deps" @@ -2586,54 +1599,11 @@ dependencies = [ "syn 2.0.48", ] -[[package]] -name = "thread_local" -version = "1.1.7" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3fdd6f064ccff2d6567adcb3873ca630700f00b5ad3f060c25b5dcfd9a4ce152" -dependencies = [ - "cfg-if", - "once_cell", -] - -[[package]] -name = "time" -version = "0.3.31" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f657ba42c3f86e7680e53c8cd3af8abbe56b5491790b46e22e19c0d57463583e" -dependencies = [ - "deranged", - "powerfmt", - "serde", - "time-core", -] - -[[package]] -name = "time-core" -version = "0.1.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ef927ca75afb808a4d64dd374f00a2adf8d0fcff8e7b184af886c3c87ec4a3f3" - -[[package]] -name = "tinyvec" -version = "1.6.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "87cc5ceb3875bb20c2890005a4e226a4651264a5c75edb2421b52861a0a0cb50" -dependencies = [ - "tinyvec_macros", -] - -[[package]] -name = "tinyvec_macros" -version = "0.1.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1f3ccbac311fea05f86f61904b462b55fb3df8837a366dfc601a0161d0532f20" - [[package]] name = "tokio" -version = "1.35.1" +version = "1.38.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c89b4efa943be685f629b149f53829423f8f5531ea21249408e8e2f8671ec104" +checksum = "ba4f4a02a7a80d6f274636f0aa95c7e383b912d41fe721a31f29e29698585a4a" dependencies = [ "backtrace", "bytes", @@ -2641,17 +1611,16 @@ dependencies = [ "mio", "num_cpus", "pin-project-lite", - "socket2 0.5.5", + "socket2", "tokio-macros", - "tracing", "windows-sys 0.48.0", ] [[package]] name = "tokio-macros" -version = "2.2.0" +version = "2.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5b8a1e28f2deaa14e508979454cb3a223b10b938b45af148bc0986de36f1923b" +checksum = "5f5ae998a069d4b5aba8ee9dad856af7d520c3699e6159b185c2acd48155d39a" dependencies = [ "proc-macro2", "quote", @@ -2659,12 +1628,13 @@ dependencies = [ ] [[package]] -name = "tokio-native-tls" -version = "0.3.1" +name = "tokio-stream" +version = "0.1.15" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bbae76ab933c85776efabc971569dd6119c580d8f5d448769dec1764bf796ef2" +checksum = "267ac89e0bec6e691e5813911606935d77c476ff49024f98abcea3e7b15e37af" dependencies = [ - "native-tls", + "futures-core", + "pin-project-lite", "tokio", ] @@ -2709,7 +1679,7 @@ version = "0.19.15" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "1b5bb770da30e5cbfde35a2d7b9b8a2c4b8ef89548a7a6aeab5c9a576e3e7421" dependencies = [ - "indexmap", + "indexmap 2.1.0", "toml_datetime", "winnow", ] @@ -2720,13 +1690,82 @@ version = "0.20.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "396e4d48bbb2b7554c944bde63101b5ae446cff6ec4a24227428f15eb72ef338" dependencies = [ - "indexmap", + "indexmap 2.1.0", "serde", "serde_spanned", "toml_datetime", "winnow", ] +[[package]] +name = "tonic" +version = "0.12.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f738b6a169a29bca4e39656db89c44a08e09c5b700b896ee9e7459f0652e81dd" +dependencies = [ + "async-stream", + "async-trait", + "axum", + "base64", + "bytes", + "h2", + "http", + "http-body", + "http-body-util", + "hyper", + "hyper-timeout", + "hyper-util", + "percent-encoding", + "pin-project", + "prost", + "socket2", + "tokio", + "tokio-stream", + "tower", + "tower-layer", + "tower-service", + "tracing", +] + +[[package]] +name = "tonic-build" +version = "0.12.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "690943cc223adcdd67bb597a2e573ead1b88e999ba37528fe8e6356bf44b29b6" +dependencies = [ + "prettyplease", + "proc-macro2", + "prost-build", + "quote", + "syn 2.0.48", +] + +[[package]] +name = "tower" +version = "0.4.13" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b8fa9be0de6cf49e536ce1851f987bd21a43b771b09473c3549a6c853db37c1c" +dependencies = [ + "futures-core", + "futures-util", + "indexmap 1.9.3", + "pin-project", + "pin-project-lite", + "rand", + "slab", + "tokio", + "tokio-util", + "tower-layer", + "tower-service", + "tracing", +] + +[[package]] +name = "tower-layer" +version = "0.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c20c8dbed6283a09604c3e69b4b7eeb54e298b8a600d4d5ecb5ad39de609f1d0" + [[package]] name = "tower-service" version = "0.3.2" @@ -2739,6 +1778,7 @@ version = "0.1.40" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "c3523ab5a71916ccf420eebdf5521fcef02141234bbc0b8a49f2fdc4544364ef" dependencies = [ + "log", "pin-project-lite", "tracing-attributes", "tracing-core", @@ -2762,73 +1802,6 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "c06d3da6113f116aaee68e4d601191614c9053067f9ab7f6edbcb161237daa54" dependencies = [ "once_cell", - "valuable", -] - -[[package]] -name = "tracing-journald" -version = "0.3.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ba316a74e8fc3c3896a850dba2375928a9fa171b085ecddfc7c054d39970f3fd" -dependencies = [ - "libc", - "tracing-core", - "tracing-subscriber", -] - -[[package]] -name = "tracing-log" -version = "0.1.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f751112709b4e791d8ce53e32c4ed2d353565a795ce84da2285393f41557bdf2" -dependencies = [ - "log", - "once_cell", - "tracing-core", -] - -[[package]] -name = "tracing-log" -version = "0.2.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ee855f1f400bd0e5c02d150ae5de3840039a3f54b025156404e34c23c03f47c3" -dependencies = [ - "log", - "once_cell", - "tracing-core", -] - -[[package]] -name = "tracing-oslog" -version = "0.1.2" -source = "git+https://github.com/Stormshield-robinc/tracing-oslog#c4d21a95e70cdd62b1cea04fc4f8be1c547cad6c" -dependencies = [ - "bindgen 0.64.0", - "cc", - "cfg-if", - "fnv", - "once_cell", - "parking_lot", - "tracing-core", - "tracing-subscriber", -] - -[[package]] -name = "tracing-subscriber" -version = "0.3.18" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ad0f048c97dbd9faa9b7df56362b8ebcaa52adb06b498c050d2f4e32f90a7a8b" -dependencies = [ - "matchers", - "nu-ansi-term", - "once_cell", - "regex", - "sharded-slab", - "smallvec", - "thread_local", - "tracing", - "tracing-core", - "tracing-log 0.2.0", ] [[package]] @@ -2837,120 +1810,12 @@ version = "0.2.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e421abadd41a4225275504ea4d6566923418b7f05506fbc9c0fe86ba7396114b" -[[package]] -name = "tun" -version = "0.1.0" -dependencies = [ - "anyhow", - "bindgen 0.65.1", - "byteorder", - "fehler", - "futures", - "lazy_static", - "libc", - "libloading 0.7.4", - "log", - "nix 0.26.4", - "reqwest", - "schemars", - "serde", - "socket2 0.4.10", - "ssri", - "tempfile", - "tokio", - "tracing", - "widestring", - "windows", - "zip", -] - -[[package]] -name = "typenum" -version = "1.17.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "42ff0bf0c66b8238c6f3b578df37d0b7848e55df8577b3f74f92a69acceeb825" - -[[package]] -name = "unicode-bidi" -version = "0.3.15" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "08f95100a766bf4f8f28f90d77e0a5461bbdb219042e7679bebe79004fed8d75" - [[package]] name = "unicode-ident" version = "1.0.12" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "3354b9ac3fae1ff6755cb6db53683adb661634f67557942dea4facebec0fee4b" -[[package]] -name = "unicode-normalization" -version = "0.1.22" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5c5713f0fc4b5db668a2ac63cdb7bb4469d8c9fed047b1d0292cc7b0ce2ba921" -dependencies = [ - "tinyvec", -] - -[[package]] -name = "unicode-width" -version = "0.1.11" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e51733f11c9c4f72aa0c160008246859e340b00807569a0da0e7a1079b27ba85" - -[[package]] -name = "universal-hash" -version = "0.5.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fc1de2c688dc15305988b563c3854064043356019f97a4b46276fe734c4f07ea" -dependencies = [ - "crypto-common", - "subtle", -] - -[[package]] -name = "untrusted" -version = "0.9.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8ecb6da28b8a351d773b68d5825ac39017e680750f980f3a1a85cd8dd28a47c1" - -[[package]] -name = "url" -version = "2.5.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "31e6302e3bb753d46e83516cae55ae196fc0c309407cf11ab35cc51a4c2a4633" -dependencies = [ - "form_urlencoded", - "idna", - "percent-encoding", -] - -[[package]] -name = "utf8parse" -version = "0.2.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "711b9620af191e0cdc7468a8d14e709c3dcdb115b36f838e601583af800a370a" - -[[package]] -name = "uuid" -version = "1.7.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f00cc9702ca12d3c81455259621e676d0f7251cec66a21e98fe2e9a37db93b2a" -dependencies = [ - "serde", -] - -[[package]] -name = "valuable" -version = "0.1.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "830b7e5d4d90034032940e4ace0d9a9a057e7a45cd94e6c007832e39edb82f6d" - -[[package]] -name = "vcpkg" -version = "0.2.15" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "accd4ea62f7bb7a82fe23066fb0957d48ef677f6eeb8215f372f52e48bb32426" - [[package]] name = "version-compare" version = "0.1.1" @@ -3003,18 +1868,6 @@ dependencies = [ "wasm-bindgen-shared", ] -[[package]] -name = "wasm-bindgen-futures" -version = "0.4.40" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bde2032aeb86bdfaecc8b261eef3cba735cc426c1f3a3416d1e0791be95fc461" -dependencies = [ - "cfg-if", - "js-sys", - "wasm-bindgen", - "web-sys", -] - [[package]] name = "wasm-bindgen-macro" version = "0.2.90" @@ -3044,34 +1897,6 @@ version = "0.2.90" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "4d91413b1c31d7539ba5ef2451af3f0b833a005eb27a631cec32bc0635a8602b" -[[package]] -name = "web-sys" -version = "0.3.67" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "58cd2333b6e0be7a39605f0e255892fd7418a682d8da8fe042fe25128794d2ed" -dependencies = [ - "js-sys", - "wasm-bindgen", -] - -[[package]] -name = "which" -version = "4.4.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "87ba24419a2078cd2b0f2ede2691b6c66d8e47836da3b6db8265ebad47afbfc7" -dependencies = [ - "either", - "home", - "once_cell", - "rustix", -] - -[[package]] -name = "widestring" -version = "1.0.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "653f141f39ec16bba3c5abe400a0c60da7468261cc2cbf36805022876bc721a8" - [[package]] name = "winapi" version = "0.3.9" @@ -3094,15 +1919,6 @@ version = "0.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f" -[[package]] -name = "windows" -version = "0.48.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e686886bc078bc1b0b600cac0147aadb815089b6e4da64016cbd754b6342700f" -dependencies = [ - "windows-targets 0.48.5", -] - [[package]] name = "windows-sys" version = "0.48.0" @@ -3243,100 +2059,3 @@ checksum = "b7cf47b659b318dccbd69cc4797a39ae128f533dce7902a1096044d1967b9c16" dependencies = [ "memchr", ] - -[[package]] -name = "winreg" -version = "0.50.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "524e57b2c537c0f9b1e69f1965311ec12182b4122e45035b1508cd24d2adadb1" -dependencies = [ - "cfg-if", - "windows-sys 0.48.0", -] - -[[package]] -name = "x25519-dalek" -version = "2.0.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fb66477291e7e8d2b0ff1bcb900bf29489a9692816d79874bea351e7a8b6de96" -dependencies = [ - "curve25519-dalek", - "rand_core", - "serde", - "zeroize", -] - -[[package]] -name = "xxhash-rust" -version = "0.8.8" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "53be06678ed9e83edb1745eb72efc0bbcd7b5c3c35711a860906aed827a13d61" - -[[package]] -name = "zeroize" -version = "1.7.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "525b4ec142c6b68a2d10f01f7bbf6755599ca3f81ea53b8431b7dd348f5fdb2d" -dependencies = [ - "zeroize_derive", -] - -[[package]] -name = "zeroize_derive" -version = "1.4.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ce36e65b0d2999d2aafac989fb249189a141aee1f53c612c1f37d72631959f69" -dependencies = [ - "proc-macro2", - "quote", - "syn 2.0.48", -] - -[[package]] -name = "zip" -version = "0.6.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "760394e246e4c28189f19d488c058bf16f564016aefac5d32bb1f3b51d5e9261" -dependencies = [ - "aes", - "byteorder", - "bzip2", - "constant_time_eq", - "crc32fast", - "crossbeam-utils", - "flate2", - "hmac", - "pbkdf2", - "sha1", - "time", - "zstd", -] - -[[package]] -name = "zstd" -version = "0.11.2+zstd.1.5.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "20cc960326ece64f010d2d2107537f26dc589a6573a316bd5b1dba685fa5fde4" -dependencies = [ - "zstd-safe", -] - -[[package]] -name = "zstd-safe" -version = "5.0.2+zstd.1.5.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1d2a5585e04f9eea4b2a3d1eca508c4dee9592a89ef6f450c11719da0726f4db" -dependencies = [ - "libc", - "zstd-sys", -] - -[[package]] -name = "zstd-sys" -version = "2.0.9+zstd.1.5.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9e16efa8a874a0481a574084d34cc26fdb3b99627480f785888deb6386506656" -dependencies = [ - "cc", - "pkg-config", -] diff --git a/burrow-gtk/Cargo.toml b/burrow-gtk/Cargo.toml index 21cb52e..b73d936 100644 --- a/burrow-gtk/Cargo.toml +++ b/burrow-gtk/Cargo.toml @@ -8,10 +8,15 @@ edition = "2021" [dependencies] anyhow = "1.0" relm4 = { version = "0.6", features = ["libadwaita", "gnome_44"]} -burrow = { version = "*", path = "../burrow/" } tokio = { version = "1.35.0", features = ["time", "sync"] } gettext-rs = { version = "0.7.0", features = ["gettext-system"] } +tonic = "0.12" +prost = "0.13" +prost-types = "0.13" +hyper-util = "0.1.6" +tower = "0.4.13" [build-dependencies] anyhow = "1.0" glib-build-tools = "0.18.0" +tonic-build = "0.12" diff --git a/burrow-gtk/build-aux/build_appimage.sh b/burrow-gtk/build-aux/build_appimage.sh index f054cd9..ef88e57 100755 --- a/burrow-gtk/build-aux/build_appimage.sh +++ b/burrow-gtk/build-aux/build_appimage.sh @@ -27,6 +27,5 @@ CFLAGS="-I/usr/local/include -I/usr/include/$MUSL_TARGET -fPIE" meson setup $BURROW_GTK_BUILD --bindir bin --prefix /usr --buildtype $BURROW_BUILD_TYPE meson compile -C $BURROW_GTK_BUILD DESTDIR=AppDir meson install -C $BURROW_GTK_BUILD -cargo b --$BURROW_BUILD_TYPE --manifest-path=../Cargo.toml /tmp/linuxdeploy --appimage-extract-and-run --appdir $BURROW_GTK_BUILD/AppDir -e $BURROW_GTK_BUILD/../../target/$BURROW_BUILD_TYPE/burrow --output appimage mv *.AppImage $BURROW_GTK_BUILD diff --git a/burrow-gtk/build.rs b/burrow-gtk/build.rs index 4db0175..df2e3d2 100644 --- a/burrow-gtk/build.rs +++ b/burrow-gtk/build.rs @@ -2,6 +2,7 @@ use anyhow::Result; fn main() -> Result<()> { compile_gresources()?; + tonic_build::compile_protos("../proto/burrow.proto")?; Ok(()) } diff --git a/burrow-gtk/src/components/app.rs b/burrow-gtk/src/components/app.rs index 62c98c0..7bc9084 100644 --- a/burrow-gtk/src/components/app.rs +++ b/burrow-gtk/src/components/app.rs @@ -1,11 +1,17 @@ use super::*; use anyhow::Context; +use anyhow::Result; +use hyper_util::rt::TokioIo; use std::time::Duration; +use tokio::net::UnixStream; +use tonic::transport::{Channel, Endpoint, Uri}; +use tower::service_fn; +const BURROW_RPC_SOCKET_PATH: &str = "/run/burrow.sock"; const RECONNECT_POLL_TIME: Duration = Duration::from_secs(5); pub struct App { - daemon_client: Arc>>, + daemon_client: Arc>>, settings_screen: Controller, switch_screen: AsyncController, } @@ -58,7 +64,8 @@ impl AsyncComponent for App { root: Self::Root, sender: AsyncComponentSender, ) -> AsyncComponentParts { - let daemon_client = Arc::new(Mutex::new(DaemonClient::new().await.ok())); + // TODO: RPC REFACTOR (Handle Error) + let daemon_client = Arc::new(Mutex::new(Some(daemon_connect().await.unwrap()))); let switch_screen = switch_screen::SwitchScreen::builder() .launch(switch_screen::SwitchScreenInit { @@ -128,7 +135,8 @@ impl AsyncComponent for App { let mut disconnected_daemon_client = false; if let Some(daemon_client) = daemon_client.as_mut() { - if let Err(_e) = daemon_client.send_command(DaemonCommand::ServerInfo).await { + let mut client = tunnel_client::TunnelClient::new(daemon_client); + if let Err(_e) = client.tunnel_status(burrow_rpc::Empty {}).await { disconnected_daemon_client = true; self.switch_screen .emit(switch_screen::SwitchScreenMsg::DaemonDisconnect); @@ -138,7 +146,7 @@ impl AsyncComponent for App { } if disconnected_daemon_client || daemon_client.is_none() { - match DaemonClient::new().await { + match daemon_connect().await { Ok(new_daemon_client) => { *daemon_client = Some(new_daemon_client); self.switch_screen @@ -155,3 +163,13 @@ impl AsyncComponent for App { } } } + +pub async fn daemon_connect() -> Result { + Ok(Endpoint::try_from("http://[::]:50051")? + .connect_with_connector(service_fn(|_: Uri| async { + Ok::<_, std::io::Error>(TokioIo::new( + UnixStream::connect(BURROW_RPC_SOCKET_PATH).await?, + )) + })) + .await?) +} diff --git a/burrow-gtk/src/components/mod.rs b/burrow-gtk/src/components/mod.rs index b134809..21c51e5 100644 --- a/burrow-gtk/src/components/mod.rs +++ b/burrow-gtk/src/components/mod.rs @@ -1,6 +1,5 @@ use super::*; use adw::prelude::*; -use burrow::{DaemonClient, DaemonCommand, DaemonResponseData}; use gtk::Align; use relm4::{ component::{ @@ -12,6 +11,12 @@ use relm4::{ use std::sync::Arc; use tokio::sync::Mutex; +pub mod burrow_rpc { + tonic::include_proto!("burrow"); +} +use burrow_rpc::tunnel_client; +use tonic::transport::Channel; + mod app; mod settings; mod settings_screen; diff --git a/burrow-gtk/src/components/settings/daemon_group.rs b/burrow-gtk/src/components/settings/daemon_group.rs index 3817ca6..ef22000 100644 --- a/burrow-gtk/src/components/settings/daemon_group.rs +++ b/burrow-gtk/src/components/settings/daemon_group.rs @@ -4,12 +4,12 @@ use std::process::Command; #[derive(Debug)] pub struct DaemonGroup { system_setup: SystemSetup, - daemon_client: Arc>>, + daemon_client: Arc>>, already_running: bool, } pub struct DaemonGroupInit { - pub daemon_client: Arc>>, + pub daemon_client: Arc>>, pub system_setup: SystemSetup, } diff --git a/burrow-gtk/src/components/settings/diag_group.rs b/burrow-gtk/src/components/settings/diag_group.rs index a15e0ea..9e1bcff 100644 --- a/burrow-gtk/src/components/settings/diag_group.rs +++ b/burrow-gtk/src/components/settings/diag_group.rs @@ -2,7 +2,7 @@ use super::*; #[derive(Debug)] pub struct DiagGroup { - daemon_client: Arc>>, + daemon_client: Arc>>, system_setup: SystemSetup, service_installed: StatusTernary, @@ -12,12 +12,12 @@ pub struct DiagGroup { } pub struct DiagGroupInit { - pub daemon_client: Arc>>, + pub daemon_client: Arc>>, pub system_setup: SystemSetup, } impl DiagGroup { - async fn new(daemon_client: Arc>>) -> Result { + async fn new(daemon_client: Arc>>) -> Result { let system_setup = SystemSetup::new(); let daemon_running = daemon_client.lock().await.is_some(); diff --git a/burrow-gtk/src/components/settings_screen.rs b/burrow-gtk/src/components/settings_screen.rs index 971f262..13154fa 100644 --- a/burrow-gtk/src/components/settings_screen.rs +++ b/burrow-gtk/src/components/settings_screen.rs @@ -7,7 +7,7 @@ pub struct SettingsScreen { } pub struct SettingsScreenInit { - pub daemon_client: Arc>>, + pub daemon_client: Arc>>, } #[derive(Debug, PartialEq, Eq)] diff --git a/burrow-gtk/src/components/switch_screen.rs b/burrow-gtk/src/components/switch_screen.rs index f660536..7155d9f 100644 --- a/burrow-gtk/src/components/switch_screen.rs +++ b/burrow-gtk/src/components/switch_screen.rs @@ -1,14 +1,14 @@ use super::*; pub struct SwitchScreen { - daemon_client: Arc>>, + daemon_client: Arc>>, switch: gtk::Switch, switch_screen: gtk::Box, disconnected_banner: adw::Banner, } pub struct SwitchScreenInit { - pub daemon_client: Arc>>, + pub daemon_client: Arc>>, } #[derive(Debug, PartialEq, Eq)] @@ -76,15 +76,13 @@ impl AsyncComponent for SwitchScreen { let mut initial_daemon_server_down = false; if let Some(daemon_client) = init.daemon_client.lock().await.as_mut() { - if let Ok(res) = daemon_client - .send_command(DaemonCommand::ServerInfo) - .await - .as_ref() - { - initial_switch_status = match res.result.as_ref() { - Ok(DaemonResponseData::None) => false, - Ok(DaemonResponseData::ServerInfo(_)) => true, - _ => false, + let mut client = tunnel_client::TunnelClient::new(daemon_client); + if let Ok(res) = client.tunnel_status(burrow_rpc::Empty {}).await.as_mut() { + // TODO: RPC REFACTOR (Handle Error) + let res = res.get_mut().message().await.unwrap().unwrap(); + initial_switch_status = match res.state() { + burrow_rpc::State::Running => true, + burrow_rpc::State::Stopped => false, }; } else { initial_daemon_server_down = true; @@ -123,17 +121,15 @@ impl AsyncComponent for SwitchScreen { let mut disconnected_daemon_client = false; if let Some(daemon_client) = self.daemon_client.lock().await.as_mut() { + let mut client = tunnel_client::TunnelClient::new(daemon_client); match msg { Self::Input::Start => { - if let Err(_e) = daemon_client - .send_command(DaemonCommand::Start(Default::default())) - .await - { + if let Err(_e) = client.tunnel_start(burrow_rpc::Empty {}).await { disconnected_daemon_client = true; } } Self::Input::Stop => { - if let Err(_e) = daemon_client.send_command(DaemonCommand::Stop).await { + if let Err(_e) = client.tunnel_stop(burrow_rpc::Empty {}).await { disconnected_daemon_client = true; } } From 4f2337ef316c841bc16b173081fa3a9f38217625 Mon Sep 17 00:00:00 2001 From: dav Date: Sat, 13 Jul 2024 16:54:57 -0700 Subject: [PATCH 02/16] Integrate tunnel status streaming --- burrow-gtk/src/components/app.rs | 20 +----- burrow-gtk/src/components/mod.rs | 1 + burrow-gtk/src/components/switch_screen.rs | 78 ++++++++++++++++++---- burrow-gtk/src/daemon.rs | 17 +++++ burrow-gtk/src/main.rs | 1 + 5 files changed, 85 insertions(+), 32 deletions(-) create mode 100644 burrow-gtk/src/daemon.rs diff --git a/burrow-gtk/src/components/app.rs b/burrow-gtk/src/components/app.rs index 7bc9084..6d64fa0 100644 --- a/burrow-gtk/src/components/app.rs +++ b/burrow-gtk/src/components/app.rs @@ -1,13 +1,7 @@ use super::*; use anyhow::Context; -use anyhow::Result; -use hyper_util::rt::TokioIo; use std::time::Duration; -use tokio::net::UnixStream; -use tonic::transport::{Channel, Endpoint, Uri}; -use tower::service_fn; -const BURROW_RPC_SOCKET_PATH: &str = "/run/burrow.sock"; const RECONNECT_POLL_TIME: Duration = Duration::from_secs(5); pub struct App { @@ -65,7 +59,7 @@ impl AsyncComponent for App { sender: AsyncComponentSender, ) -> AsyncComponentParts { // TODO: RPC REFACTOR (Handle Error) - let daemon_client = Arc::new(Mutex::new(Some(daemon_connect().await.unwrap()))); + let daemon_client = Arc::new(Mutex::new(Some(daemon::daemon_connect().await.unwrap()))); let switch_screen = switch_screen::SwitchScreen::builder() .launch(switch_screen::SwitchScreenInit { @@ -146,7 +140,7 @@ impl AsyncComponent for App { } if disconnected_daemon_client || daemon_client.is_none() { - match daemon_connect().await { + match daemon::daemon_connect().await { Ok(new_daemon_client) => { *daemon_client = Some(new_daemon_client); self.switch_screen @@ -163,13 +157,3 @@ impl AsyncComponent for App { } } } - -pub async fn daemon_connect() -> Result { - Ok(Endpoint::try_from("http://[::]:50051")? - .connect_with_connector(service_fn(|_: Uri| async { - Ok::<_, std::io::Error>(TokioIo::new( - UnixStream::connect(BURROW_RPC_SOCKET_PATH).await?, - )) - })) - .await?) -} diff --git a/burrow-gtk/src/components/mod.rs b/burrow-gtk/src/components/mod.rs index 21c51e5..7490b82 100644 --- a/burrow-gtk/src/components/mod.rs +++ b/burrow-gtk/src/components/mod.rs @@ -3,6 +3,7 @@ use adw::prelude::*; use gtk::Align; use relm4::{ component::{ + worker::{Worker, WorkerController}, AsyncComponent, AsyncComponentController, AsyncComponentParts, AsyncComponentSender, AsyncController, }, diff --git a/burrow-gtk/src/components/switch_screen.rs b/burrow-gtk/src/components/switch_screen.rs index 7155d9f..7258854 100644 --- a/burrow-gtk/src/components/switch_screen.rs +++ b/burrow-gtk/src/components/switch_screen.rs @@ -1,10 +1,15 @@ use super::*; +use std::time::Duration; + +const RECONNECT_POLL_TIME: Duration = Duration::from_secs(3); pub struct SwitchScreen { daemon_client: Arc>>, switch: gtk::Switch, switch_screen: gtk::Box, disconnected_banner: adw::Banner, + + _tunnel_state_worker: WorkerController, } pub struct SwitchScreenInit { @@ -13,10 +18,13 @@ pub struct SwitchScreenInit { #[derive(Debug, PartialEq, Eq)] pub enum SwitchScreenMsg { + None, DaemonReconnect, DaemonDisconnect, Start, Stop, + SwitchSetStart, + SwitchSetStop, } #[relm4::component(pub, async)] @@ -24,7 +32,7 @@ impl AsyncComponent for SwitchScreen { type Init = SwitchScreenInit; type Input = SwitchScreenMsg; type Output = (); - type CommandOutput = (); + type CommandOutput = SwitchScreenMsg; view! { gtk::Box { @@ -61,7 +69,7 @@ impl AsyncComponent for SwitchScreen { set_hexpand: false, set_vexpand: false, connect_active_notify => move |switch| - sender.input(if switch.is_active() { SwitchScreenMsg::Start } else { SwitchScreenMsg::Stop }) + switch_sender.input(if switch.is_active() { SwitchScreenMsg::Start } else { SwitchScreenMsg::Stop }) }, } } @@ -72,29 +80,25 @@ impl AsyncComponent for SwitchScreen { root: Self::Root, sender: AsyncComponentSender, ) -> AsyncComponentParts { - let mut initial_switch_status = false; let mut initial_daemon_server_down = false; if let Some(daemon_client) = init.daemon_client.lock().await.as_mut() { let mut client = tunnel_client::TunnelClient::new(daemon_client); - if let Ok(res) = client.tunnel_status(burrow_rpc::Empty {}).await.as_mut() { - // TODO: RPC REFACTOR (Handle Error) - let res = res.get_mut().message().await.unwrap().unwrap(); - initial_switch_status = match res.state() { - burrow_rpc::State::Running => true, - burrow_rpc::State::Stopped => false, - }; - } else { + if client + .tunnel_status(burrow_rpc::Empty {}) + .await + .as_mut() + .is_err() + { initial_daemon_server_down = true; } } else { initial_daemon_server_down = true; } + let switch_sender = sender.clone(); let widgets = view_output!(); - widgets.switch.set_active(initial_switch_status); - if initial_daemon_server_down { *init.daemon_client.lock().await = None; widgets.switch.set_active(false); @@ -107,8 +111,13 @@ impl AsyncComponent for SwitchScreen { switch: widgets.switch.clone(), switch_screen: widgets.switch_screen.clone(), disconnected_banner: widgets.setup_banner.clone(), + _tunnel_state_worker: AsyncTunnelStateHandler::builder() + .detach_worker(()) + .forward(sender.input_sender(), |_| SwitchScreenMsg::None), }; + widgets.switch.set_active(false); + AsyncComponentParts { model, widgets } } @@ -133,6 +142,12 @@ impl AsyncComponent for SwitchScreen { disconnected_daemon_client = true; } } + Self::Input::SwitchSetStart => { + self.switch.set_active(true); + } + Self::Input::SwitchSetStop => { + self.switch.set_active(false); + } _ => {} } } else { @@ -146,9 +161,44 @@ impl AsyncComponent for SwitchScreen { if disconnected_daemon_client || msg == Self::Input::DaemonDisconnect { *self.daemon_client.lock().await = None; - self.switch.set_active(false); self.switch_screen.set_sensitive(false); self.disconnected_banner.set_revealed(true); } } } +struct AsyncTunnelStateHandler; + +impl Worker for AsyncTunnelStateHandler { + type Init = (); + type Input = (); + type Output = SwitchScreenMsg; + + fn init(_: Self::Init, _sender: ComponentSender) -> Self { + Self + } + + fn update(&mut self, _: (), sender: ComponentSender) { + let rt = tokio::runtime::Runtime::new().unwrap(); + let task = rt.spawn(async move { + loop { + let conn = daemon::daemon_connect().await; + if let Ok(conn) = conn { + let mut client = tunnel_client::TunnelClient::new(conn); + if let Ok(mut res) = client.tunnel_status(burrow_rpc::Empty {}).await { + let stream = res.get_mut(); + while let Ok(Some(msg)) = stream.message().await { + sender + .output(match msg.state() { + burrow_rpc::State::Running => SwitchScreenMsg::SwitchSetStart, + burrow_rpc::State::Stopped => SwitchScreenMsg::SwitchSetStop, + }) + .unwrap(); + } + } + } + tokio::time::sleep(RECONNECT_POLL_TIME).await; + } + }); + rt.block_on(task).unwrap(); + } +} diff --git a/burrow-gtk/src/daemon.rs b/burrow-gtk/src/daemon.rs new file mode 100644 index 0000000..dc47f24 --- /dev/null +++ b/burrow-gtk/src/daemon.rs @@ -0,0 +1,17 @@ +use anyhow::Result; +use hyper_util::rt::TokioIo; +use tokio::net::UnixStream; +use tonic::transport::{Channel, Endpoint, Uri}; +use tower::service_fn; + +const BURROW_RPC_SOCKET_PATH: &str = "/run/burrow.sock"; + +pub async fn daemon_connect() -> Result { + Ok(Endpoint::try_from("http://[::]:50051")? + .connect_with_connector(service_fn(|_: Uri| async { + Ok::<_, std::io::Error>(TokioIo::new( + UnixStream::connect(BURROW_RPC_SOCKET_PATH).await?, + )) + })) + .await?) +} diff --git a/burrow-gtk/src/main.rs b/burrow-gtk/src/main.rs index 6f91e2a..66e6b36 100644 --- a/burrow-gtk/src/main.rs +++ b/burrow-gtk/src/main.rs @@ -1,6 +1,7 @@ use anyhow::Result; pub mod components; +mod daemon; mod diag; // Generated using meson From 72e490032c280180acc92d4883c2f65c85182c84 Mon Sep 17 00:00:00 2001 From: dav Date: Sat, 13 Jul 2024 16:56:32 -0700 Subject: [PATCH 03/16] Add proto defs into burrow-gtk --- burrow-gtk/proto/burrow.proto | 73 +++++++++++++++++++++++++++++++++++ 1 file changed, 73 insertions(+) create mode 100644 burrow-gtk/proto/burrow.proto diff --git a/burrow-gtk/proto/burrow.proto b/burrow-gtk/proto/burrow.proto new file mode 100644 index 0000000..e0415ad --- /dev/null +++ b/burrow-gtk/proto/burrow.proto @@ -0,0 +1,73 @@ +syntax = "proto3"; +package burrow; + +import "google/protobuf/timestamp.proto"; + +service Tunnel { + rpc TunnelConfiguration (Empty) returns (TunnelConfigurationResponse); + rpc TunnelStart (Empty) returns (Empty); + rpc TunnelStop (Empty) returns (Empty); + rpc TunnelStatus (Empty) returns (stream TunnelStatusResponse); +} + +service Networks { + rpc NetworkAdd (Empty) returns (Empty); + rpc NetworkList (Empty) returns (stream NetworkListResponse); + rpc NetworkReorder (NetworkReorderRequest) returns (Empty); + rpc NetworkDelete (NetworkDeleteRequest) returns (Empty); +} + +message NetworkReorderRequest { + int32 id = 1; + int32 index = 2; +} + +message WireGuardPeer { + string endpoint = 1; + repeated string subnet = 2; +} + +message WireGuardNetwork { + string address = 1; + string dns = 2; + repeated WireGuardPeer peer = 3; +} + +message NetworkDeleteRequest { + int32 id = 1; +} + +message Network { + int32 id = 1; + NetworkType type = 2; + bytes payload = 3; +} + +enum NetworkType { + WireGuard = 0; + HackClub = 1; +} + +message NetworkListResponse { + repeated Network network = 1; +} + +message Empty { + +} + +enum State { + Stopped = 0; + Running = 1; +} + +message TunnelStatusResponse { + State state = 1; + optional google.protobuf.Timestamp start = 2; +} + +message TunnelConfigurationResponse { + repeated string addresses = 1; + int32 mtu = 2; +} + From f7588296b8e1c605a5d4a3d59ede957161e2f00a Mon Sep 17 00:00:00 2001 From: dav Date: Sat, 13 Jul 2024 17:00:46 -0700 Subject: [PATCH 04/16] Have the app actually open --- burrow-gtk/build.rs | 2 +- burrow-gtk/src/components/app.rs | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/burrow-gtk/build.rs b/burrow-gtk/build.rs index df2e3d2..2e4d607 100644 --- a/burrow-gtk/build.rs +++ b/burrow-gtk/build.rs @@ -2,7 +2,7 @@ use anyhow::Result; fn main() -> Result<()> { compile_gresources()?; - tonic_build::compile_protos("../proto/burrow.proto")?; + tonic_build::compile_protos("proto/burrow.proto")?; Ok(()) } diff --git a/burrow-gtk/src/components/app.rs b/burrow-gtk/src/components/app.rs index 6d64fa0..efbaa23 100644 --- a/burrow-gtk/src/components/app.rs +++ b/burrow-gtk/src/components/app.rs @@ -59,7 +59,7 @@ impl AsyncComponent for App { sender: AsyncComponentSender, ) -> AsyncComponentParts { // TODO: RPC REFACTOR (Handle Error) - let daemon_client = Arc::new(Mutex::new(Some(daemon::daemon_connect().await.unwrap()))); + let daemon_client = Arc::new(Mutex::new(daemon::daemon_connect().await.ok())); let switch_screen = switch_screen::SwitchScreen::builder() .launch(switch_screen::SwitchScreenInit { From 951b4ddae2f33e15c7d1976337de64001797d0e9 Mon Sep 17 00:00:00 2001 From: Jett Chen Date: Sat, 13 Jul 2024 18:09:09 -0700 Subject: [PATCH 05/16] add protobuf definition file --- proto/burrow.proto | 72 ++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 72 insertions(+) create mode 100644 proto/burrow.proto diff --git a/proto/burrow.proto b/proto/burrow.proto new file mode 100644 index 0000000..3e15219 --- /dev/null +++ b/proto/burrow.proto @@ -0,0 +1,72 @@ +syntax = "proto3"; +package burrow; + +import "google/protobuf/timestamp.proto"; + +service Tunnel { + rpc TunnelConfiguration (Empty) returns (TunnelConfigurationResponse); + rpc TunnelStart (Empty) returns (Empty); + rpc TunnelStop (Empty) returns (Empty); + rpc TunnelStatus (Empty) returns (stream TunnelStatusResponse); +} + +service Networks { + rpc NetworkAdd (Empty) returns (Empty); + rpc NetworkList (Empty) returns (stream NetworkListResponse); + rpc NetworkReorder (NetworkReorderRequest) returns (Empty); + rpc NetworkDelete (NetworkDeleteRequest) returns (Empty); +} + +message NetworkReorderRequest { + int32 id = 1; + int32 index = 2; +} + +message WireGuardPeer { + string endpoint = 1; + repeated string subnet = 2; +} + +message WireGuardNetwork { + string address = 1; + string dns = 2; + repeated WireGuardPeer peer = 3; +} + +message NetworkDeleteRequest { + int32 id = 1; +} + +message Network { + int32 id = 1; + NetworkType type = 2; + bytes payload = 3; +} + +enum NetworkType { + WireGuard = 0; + HackClub = 1; +} + +message NetworkListResponse { + repeated Network network = 1; +} + +message Empty { + +} + +enum State { + Stopped = 0; + Running = 1; +} + +message TunnelStatusResponse { + State state = 1; + optional google.protobuf.Timestamp start = 2; +} + +message TunnelConfigurationResponse { + repeated string addresses = 1; + int32 mtu = 2; +} From aa634d03e2560dbaf500b19f584d19696abb7161 Mon Sep 17 00:00:00 2001 From: Jett Chen Date: Sat, 13 Jul 2024 18:14:00 -0700 Subject: [PATCH 06/16] update protobuf definition file --- proto/burrow.proto | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/proto/burrow.proto b/proto/burrow.proto index 3e15219..2d29c78 100644 --- a/proto/burrow.proto +++ b/proto/burrow.proto @@ -4,7 +4,7 @@ package burrow; import "google/protobuf/timestamp.proto"; service Tunnel { - rpc TunnelConfiguration (Empty) returns (TunnelConfigurationResponse); + rpc TunnelConfiguration (Empty) returns (stream TunnelConfigurationResponse); rpc TunnelStart (Empty) returns (Empty); rpc TunnelStop (Empty) returns (Empty); rpc TunnelStatus (Empty) returns (stream TunnelStatusResponse); From 45f8f135c4da9f11e9a3acb8788a24e374c09267 Mon Sep 17 00:00:00 2001 From: dav Date: Sat, 13 Jul 2024 18:15:16 -0700 Subject: [PATCH 07/16] Create main screen with placeholder networks --- burrow-gtk/src/components/app.rs | 18 +- burrow-gtk/src/components/main/mod.rs | 9 + .../src/components/main/network_card.rs | 49 +++++ burrow-gtk/src/components/main/networks.rs | 83 +++++++ burrow-gtk/src/components/main/switch.rs | 205 ++++++++++++++++++ burrow-gtk/src/components/main_screen.rs | 109 ++++++++++ burrow-gtk/src/components/mod.rs | 4 +- burrow-gtk/src/components/template.rs | 39 ++++ 8 files changed, 506 insertions(+), 10 deletions(-) create mode 100644 burrow-gtk/src/components/main/mod.rs create mode 100644 burrow-gtk/src/components/main/network_card.rs create mode 100644 burrow-gtk/src/components/main/networks.rs create mode 100644 burrow-gtk/src/components/main/switch.rs create mode 100644 burrow-gtk/src/components/main_screen.rs create mode 100644 burrow-gtk/src/components/template.rs diff --git a/burrow-gtk/src/components/app.rs b/burrow-gtk/src/components/app.rs index efbaa23..c72d01d 100644 --- a/burrow-gtk/src/components/app.rs +++ b/burrow-gtk/src/components/app.rs @@ -7,7 +7,7 @@ const RECONNECT_POLL_TIME: Duration = Duration::from_secs(5); pub struct App { daemon_client: Arc>>, settings_screen: Controller, - switch_screen: AsyncController, + main_screen: AsyncController, } #[derive(Debug)] @@ -61,8 +61,8 @@ impl AsyncComponent for App { // TODO: RPC REFACTOR (Handle Error) let daemon_client = Arc::new(Mutex::new(daemon::daemon_connect().await.ok())); - let switch_screen = switch_screen::SwitchScreen::builder() - .launch(switch_screen::SwitchScreenInit { + let main_screen = main_screen::MainScreen::builder() + .launch(main_screen::MainScreenInit { daemon_client: Arc::clone(&daemon_client), }) .forward(sender.input_sender(), |_| AppMsg::None); @@ -76,7 +76,7 @@ impl AsyncComponent for App { let widgets = view_output!(); let view_stack = adw::ViewStack::new(); - view_stack.add_titled(switch_screen.widget(), None, "Switch"); + view_stack.add_titled(main_screen.widget(), None, "Burrow"); view_stack.add_titled(settings_screen.widget(), None, "Settings"); let view_switcher_bar = adw::ViewSwitcherBar::builder().stack(&view_stack).build(); @@ -109,7 +109,7 @@ impl AsyncComponent for App { let model = App { daemon_client, - switch_screen, + main_screen, settings_screen, }; @@ -132,8 +132,8 @@ impl AsyncComponent for App { let mut client = tunnel_client::TunnelClient::new(daemon_client); if let Err(_e) = client.tunnel_status(burrow_rpc::Empty {}).await { disconnected_daemon_client = true; - self.switch_screen - .emit(switch_screen::SwitchScreenMsg::DaemonDisconnect); + self.main_screen + .emit(main_screen::MainScreenMsg::DaemonDisconnect); self.settings_screen .emit(settings_screen::SettingsScreenMsg::DaemonStateChange) } @@ -143,8 +143,8 @@ impl AsyncComponent for App { match daemon::daemon_connect().await { Ok(new_daemon_client) => { *daemon_client = Some(new_daemon_client); - self.switch_screen - .emit(switch_screen::SwitchScreenMsg::DaemonReconnect); + self.main_screen + .emit(main_screen::MainScreenMsg::DaemonReconnect); self.settings_screen .emit(settings_screen::SettingsScreenMsg::DaemonStateChange) } diff --git a/burrow-gtk/src/components/main/mod.rs b/burrow-gtk/src/components/main/mod.rs new file mode 100644 index 0000000..8e03b41 --- /dev/null +++ b/burrow-gtk/src/components/main/mod.rs @@ -0,0 +1,9 @@ +use super::*; + +mod network_card; +mod networks; +mod switch; + +pub use network_card::{NetworkCard, NetworkCardInit}; +pub use networks::{Networks, NetworksInit}; +pub use switch::{Switch, SwitchInit, SwitchMsg}; diff --git a/burrow-gtk/src/components/main/network_card.rs b/burrow-gtk/src/components/main/network_card.rs new file mode 100644 index 0000000..be75066 --- /dev/null +++ b/burrow-gtk/src/components/main/network_card.rs @@ -0,0 +1,49 @@ +use super::*; + +pub struct NetworkCard {} + +pub struct NetworkCardInit { + pub name: String, + pub enabled: bool, +} + +#[derive(Debug)] +pub enum NetworkCardMsg {} + +#[relm4::component(pub, async)] +impl AsyncComponent for NetworkCard { + type Init = NetworkCardInit; + type Input = NetworkCardMsg; + type Output = (); + type CommandOutput = (); + + view! { + gtk::ListBoxRow { + set_hexpand: true, + set_halign: Align::Center, + gtk::Box { + gtk::Label { + set_label: &init.name + }, + gtk::Switch { + set_halign: Align::Center, + set_hexpand: false, + set_vexpand: false, + set_state: init.enabled, + }, + } + } + } + + async fn init( + init: Self::Init, + root: Self::Root, + sender: AsyncComponentSender, + ) -> AsyncComponentParts { + let widgets = view_output!(); + + let model = NetworkCard {}; + + AsyncComponentParts { model, widgets } + } +} diff --git a/burrow-gtk/src/components/main/networks.rs b/burrow-gtk/src/components/main/networks.rs new file mode 100644 index 0000000..6372e65 --- /dev/null +++ b/burrow-gtk/src/components/main/networks.rs @@ -0,0 +1,83 @@ +use super::*; + +pub struct Networks { + daemon_client: Arc>>, + network_widgets: Vec>, +} + +pub struct NetworksInit { + pub daemon_client: Arc>>, +} + +#[derive(Debug)] +pub enum NetworksMsg { + None, +} + +#[relm4::component(pub, async)] +impl AsyncComponent for Networks { + type Init = NetworksInit; + type Input = NetworksMsg; + type Output = (); + type CommandOutput = (); + + view! { + gtk::Box { + set_orientation: gtk::Orientation::Vertical, + set_spacing: 5, + set_margin_all: 5, + set_valign: Align::Start, + + #[name = "networks"] + gtk::ListBox {} + } + } + + async fn init( + init: Self::Init, + root: Self::Root, + sender: AsyncComponentSender, + ) -> AsyncComponentParts { + let widgets = view_output!(); + + let network_widgets = vec![ + NetworkCard::builder() + .launch(NetworkCardInit { + name: "Hello".to_owned(), + enabled: true, + }) + .forward(sender.input_sender(), |_| NetworksMsg::None), + NetworkCard::builder() + .launch(NetworkCardInit { + name: "World".to_owned(), + enabled: false, + }) + .forward(sender.input_sender(), |_| NetworksMsg::None), + NetworkCard::builder() + .launch(NetworkCardInit { + name: "Yay".to_owned(), + enabled: false, + }) + .forward(sender.input_sender(), |_| NetworksMsg::None), + ]; + + widgets.networks.append(network_widgets[0].widget()); + widgets.networks.append(network_widgets[1].widget()); + widgets.networks.append(network_widgets[2].widget()); + + let model = Networks { + daemon_client: init.daemon_client, + network_widgets, + }; + + AsyncComponentParts { model, widgets } + } + + async fn update( + &mut self, + msg: Self::Input, + _: AsyncComponentSender, + _root: &Self::Root, + ) { + } +} diff --git a/burrow-gtk/src/components/main/switch.rs b/burrow-gtk/src/components/main/switch.rs new file mode 100644 index 0000000..5958e83 --- /dev/null +++ b/burrow-gtk/src/components/main/switch.rs @@ -0,0 +1,205 @@ +use super::*; +use std::time::Duration; + +const RECONNECT_POLL_TIME: Duration = Duration::from_secs(3); + +pub struct Switch { + daemon_client: Arc>>, + switch: gtk::Switch, + switch_screen: gtk::Box, + disconnected_banner: adw::Banner, + + _tunnel_state_worker: WorkerController, +} + +pub struct SwitchInit { + pub daemon_client: Arc>>, +} + +#[derive(Debug, PartialEq, Eq)] +pub enum SwitchMsg { + None, + DaemonReconnect, + DaemonDisconnect, + Start, + Stop, + SwitchSetStart, + SwitchSetStop, +} + +#[relm4::component(pub, async)] +impl AsyncComponent for Switch { + type Init = SwitchInit; + type Input = SwitchMsg; + type Output = (); + type CommandOutput = (); + + view! { + gtk::Box { + set_orientation: gtk::Orientation::Vertical, + set_valign: Align::Fill, + + gtk::Box { + set_orientation: gtk::Orientation::Vertical, + set_spacing: 5, + set_margin_all: 5, + set_valign: Align::Start, + + #[name(setup_banner)] + adw::Banner { + set_title: "Burrow is not running!", + }, + }, + + #[name(switch_screen)] + gtk::Box { + set_orientation: gtk::Orientation::Vertical, + set_spacing: 10, + set_margin_all: 5, + set_valign: Align::Center, + set_vexpand: true, + + gtk::Label { + set_label: "Burrow Switch", + }, + + #[name(switch)] + gtk::Switch { + set_halign: Align::Center, + set_hexpand: false, + set_vexpand: false, + connect_active_notify => move |switch| + switch_sender.input(if switch.is_active() { SwitchMsg::Start } else { SwitchMsg::Stop }) + }, + } + } + } + + async fn init( + init: Self::Init, + root: Self::Root, + sender: AsyncComponentSender, + ) -> AsyncComponentParts { + let mut initial_daemon_server_down = false; + + if let Some(daemon_client) = init.daemon_client.lock().await.as_mut() { + let mut client = tunnel_client::TunnelClient::new(daemon_client); + if client + .tunnel_status(burrow_rpc::Empty {}) + .await + .as_mut() + .is_err() + { + initial_daemon_server_down = true; + } + } else { + initial_daemon_server_down = true; + } + + let switch_sender = sender.clone(); + let widgets = view_output!(); + + if initial_daemon_server_down { + *init.daemon_client.lock().await = None; + widgets.switch.set_active(false); + widgets.switch_screen.set_sensitive(false); + widgets.setup_banner.set_revealed(true); + } + + let model = Switch { + daemon_client: init.daemon_client, + switch: widgets.switch.clone(), + switch_screen: widgets.switch_screen.clone(), + disconnected_banner: widgets.setup_banner.clone(), + _tunnel_state_worker: AsyncTunnelStateHandler::builder() + .detach_worker(()) + .forward(sender.input_sender(), |_| SwitchMsg::None), + }; + + widgets.switch.set_active(false); + + AsyncComponentParts { model, widgets } + } + + async fn update( + &mut self, + msg: Self::Input, + _: AsyncComponentSender, + _root: &Self::Root, + ) { + let mut disconnected_daemon_client = false; + + if let Some(daemon_client) = self.daemon_client.lock().await.as_mut() { + let mut client = tunnel_client::TunnelClient::new(daemon_client); + match msg { + Self::Input::Start => { + if let Err(_e) = client.tunnel_start(burrow_rpc::Empty {}).await { + disconnected_daemon_client = true; + } + } + Self::Input::Stop => { + if let Err(_e) = client.tunnel_stop(burrow_rpc::Empty {}).await { + disconnected_daemon_client = true; + } + } + Self::Input::SwitchSetStart => { + self.switch.set_active(true); + } + Self::Input::SwitchSetStop => { + self.switch.set_active(false); + } + _ => {} + } + } else { + disconnected_daemon_client = true; + } + + if msg == Self::Input::DaemonReconnect { + self.disconnected_banner.set_revealed(false); + self.switch_screen.set_sensitive(true); + } + + if disconnected_daemon_client || msg == Self::Input::DaemonDisconnect { + *self.daemon_client.lock().await = None; + self.switch_screen.set_sensitive(false); + self.disconnected_banner.set_revealed(true); + } + } +} + +struct AsyncTunnelStateHandler; + +impl Worker for AsyncTunnelStateHandler { + type Init = (); + type Input = (); + type Output = SwitchMsg; + + fn init(_: Self::Init, _sender: ComponentSender) -> Self { + Self + } + + fn update(&mut self, _: (), sender: ComponentSender) { + let rt = tokio::runtime::Runtime::new().unwrap(); + let task = rt.spawn(async move { + loop { + let conn = daemon::daemon_connect().await; + if let Ok(conn) = conn { + let mut client = tunnel_client::TunnelClient::new(conn); + if let Ok(mut res) = client.tunnel_status(burrow_rpc::Empty {}).await { + let stream = res.get_mut(); + while let Ok(Some(msg)) = stream.message().await { + sender + .output(match msg.state() { + burrow_rpc::State::Running => SwitchMsg::SwitchSetStart, + burrow_rpc::State::Stopped => SwitchMsg::SwitchSetStop, + }) + .unwrap(); + } + } + } + tokio::time::sleep(RECONNECT_POLL_TIME).await; + } + }); + rt.block_on(task).unwrap(); + } +} diff --git a/burrow-gtk/src/components/main_screen.rs b/burrow-gtk/src/components/main_screen.rs new file mode 100644 index 0000000..52dd98a --- /dev/null +++ b/burrow-gtk/src/components/main_screen.rs @@ -0,0 +1,109 @@ +use super::*; + +pub struct MainScreen { + switch: AsyncController, +} + +pub struct MainScreenInit { + pub daemon_client: Arc>>, +} + +#[derive(Debug)] +pub enum MainScreenMsg { + None, + DaemonDisconnect, + DaemonReconnect, +} + +#[relm4::component(pub, async)] +impl AsyncComponent for MainScreen { + type Init = MainScreenInit; + type Input = MainScreenMsg; + type Output = (); + type CommandOutput = (); + + view! { + gtk::Box { + set_orientation: gtk::Orientation::Vertical, + set_valign: Align::Fill, + set_valign: Align::Center, + + // gtk::Box { + // set_orientation: gtk::Orientation::Vertical, + // set_spacing: 5, + // set_margin_all: 5, + // set_valign: Align::Start, + + // #[name(setup_banner)] + // adw::Banner { + // set_title: "Burrow is not running!", + // }, + // }, + + gtk::Box { + set_orientation: gtk::Orientation::Vertical, + set_spacing: 10, + set_margin_all: 5, + set_valign: Align::Center, + set_vexpand: true, + }, + + #[name(content)] + gtk::Box { + set_orientation: gtk::Orientation::Vertical, + set_spacing: 10, + set_margin_all: 5, + set_valign: Align::Center, + set_vexpand: true, + + gtk::Label { + set_label: "Main Screen", + }, + } + } + } + + async fn init( + init: Self::Init, + root: Self::Root, + sender: AsyncComponentSender, + ) -> AsyncComponentParts { + let switch = main::Switch::builder() + .launch(main::SwitchInit { + daemon_client: Arc::clone(&init.daemon_client), + }) + .forward(sender.input_sender(), |_| MainScreenMsg::None); + + let networks = main::Networks::builder() + .launch(main::NetworksInit { + daemon_client: Arc::clone(&init.daemon_client), + }) + .forward(sender.input_sender(), |_| MainScreenMsg::None); + + let widgets = view_output!(); + + widgets.content.append(networks.widget()); + widgets.content.append(switch.widget()); + + let model = MainScreen { switch }; + + AsyncComponentParts { model, widgets } + } + + async fn update( + &mut self, + msg: Self::Input, + _: AsyncComponentSender, + _root: &Self::Root, + ) { + match msg { + MainScreenMsg::DaemonDisconnect => { + self.switch.emit(main::SwitchMsg::DaemonDisconnect); + } + MainScreenMsg::DaemonReconnect => { + self.switch.emit(main::SwitchMsg::DaemonReconnect); + } + _ => {} + } + } +} diff --git a/burrow-gtk/src/components/mod.rs b/burrow-gtk/src/components/mod.rs index 7490b82..6adb06b 100644 --- a/burrow-gtk/src/components/mod.rs +++ b/burrow-gtk/src/components/mod.rs @@ -19,9 +19,11 @@ use burrow_rpc::tunnel_client; use tonic::transport::Channel; mod app; +mod main; +mod main_screen; mod settings; mod settings_screen; -mod switch_screen; +// mod switch_screen; pub use app::*; pub use settings::{DaemonGroupMsg, DiagGroupMsg}; diff --git a/burrow-gtk/src/components/template.rs b/burrow-gtk/src/components/template.rs new file mode 100644 index 0000000..800a5c9 --- /dev/null +++ b/burrow-gtk/src/components/template.rs @@ -0,0 +1,39 @@ +pub struct Template {} + +pub struct TemplateInit {} + +#[derive(Debug)] +pub enum TemplateMsg {} + +#[relm4::component(pub, async)] +impl AsyncComponent for Template { + type Init = TemplateInit; + type Input = TemplateMsg; + type Output = (); + type CommandOutput = (); + + view! { + gtk::Box { + } + } + + async fn init( + init: Self::Init, + root: Self::Root, + sender: AsyncComponentSender, + ) -> AsyncComponentParts { + let widgets = view_output!(); + + let model = Template {}; + + AsyncComponentParts { model, widgets } + } + + async fn update( + &mut self, + msg: Self::Input, + _: AsyncComponentSender, + _root: &Self::Root, + ) { + } +} From b00bf140cad76af239a4674bd2cf58e419997a10 Mon Sep 17 00:00:00 2001 From: dav Date: Wed, 14 Aug 2024 16:27:54 -0700 Subject: [PATCH 08/16] Connect network list to rpc --- burrow-gtk/src/components/main/networks.rs | 70 +++++++++++++++++++--- burrow-gtk/src/components/mod.rs | 2 +- 2 files changed, 63 insertions(+), 9 deletions(-) diff --git a/burrow-gtk/src/components/main/networks.rs b/burrow-gtk/src/components/main/networks.rs index 6372e65..809c741 100644 --- a/burrow-gtk/src/components/main/networks.rs +++ b/burrow-gtk/src/components/main/networks.rs @@ -1,8 +1,12 @@ use super::*; +use std::time::Duration; + +const RECONNECT_POLL_TIME: Duration = Duration::from_secs(3); pub struct Networks { daemon_client: Arc>>, - network_widgets: Vec>, + network_cards: Vec>, + networks_list_box: gtk::ListBox, } pub struct NetworksInit { @@ -12,6 +16,7 @@ pub struct NetworksInit { #[derive(Debug)] pub enum NetworksMsg { None, + NetworkList(Vec), } #[relm4::component(pub, async)] @@ -40,7 +45,7 @@ impl AsyncComponent for Networks { ) -> AsyncComponentParts { let widgets = view_output!(); - let network_widgets = vec![ + let network_cards = vec![ NetworkCard::builder() .launch(NetworkCardInit { name: "Hello".to_owned(), @@ -61,13 +66,10 @@ impl AsyncComponent for Networks { .forward(sender.input_sender(), |_| NetworksMsg::None), ]; - widgets.networks.append(network_widgets[0].widget()); - widgets.networks.append(network_widgets[1].widget()); - widgets.networks.append(network_widgets[2].widget()); - let model = Networks { daemon_client: init.daemon_client, - network_widgets, + network_cards, + networks_list_box: widgets.networks.clone(), }; AsyncComponentParts { model, widgets } @@ -76,8 +78,60 @@ impl AsyncComponent for Networks { async fn update( &mut self, msg: Self::Input, - _: AsyncComponentSender, + sender: AsyncComponentSender, _root: &Self::Root, ) { + if let NetworksMsg::NetworkList(networks) = msg { + for network_card in self.network_cards.iter() { + self.networks_list_box + .remove(&network_card.widget().clone()); + } + self.network_cards.clear(); + + for network in networks { + let network_card = NetworkCard::builder() + .launch(NetworkCardInit { + name: format!("ID: {}, TYPE: {}", network.id, network.r#type), + enabled: false, + }) + .forward(sender.input_sender(), |_| NetworksMsg::None); + self.networks_list_box.append(network_card.widget()); + self.network_cards.push(network_card); + } + } + } +} + +struct AsyncNetworkStateHandler; + +impl Worker for AsyncNetworkStateHandler { + type Init = (); + type Input = (); + type Output = NetworksMsg; + + fn init(_: Self::Init, _sender: ComponentSender) -> Self { + Self + } + + fn update(&mut self, _: (), sender: ComponentSender) { + let rt = tokio::runtime::Runtime::new().unwrap(); + let task = rt.spawn(async move { + loop { + let conn = daemon::daemon_connect().await; + if let Ok(conn) = conn { + let mut client = networks_client::NetworksClient::new(conn); + if let Ok(mut res) = client.network_list(burrow_rpc::Empty {}).await { + let stream = res.get_mut(); + while let Ok(Some(msg)) = stream.message().await { + sender + .output(NetworksMsg::NetworkList(msg.network)) + .unwrap(); + } + } + } + tokio::time::sleep(RECONNECT_POLL_TIME).await; + } + }); + rt.block_on(task).unwrap(); } } diff --git a/burrow-gtk/src/components/mod.rs b/burrow-gtk/src/components/mod.rs index 6adb06b..0a5eab1 100644 --- a/burrow-gtk/src/components/mod.rs +++ b/burrow-gtk/src/components/mod.rs @@ -15,7 +15,7 @@ use tokio::sync::Mutex; pub mod burrow_rpc { tonic::include_proto!("burrow"); } -use burrow_rpc::tunnel_client; +use burrow_rpc::{networks_client, tunnel_client}; use tonic::transport::Channel; mod app; From 103e5bf3285aefaa480b586bb472985282812dab Mon Sep 17 00:00:00 2001 From: dav Date: Fri, 16 Aug 2024 16:01:28 -0700 Subject: [PATCH 09/16] Implement networks add delete and reoder --- .../src/components/main/network_card.rs | 89 ++++++++++++++++++- burrow-gtk/src/components/main/networks.rs | 70 +++++++++++---- burrow-gtk/src/components/main_screen.rs | 3 +- 3 files changed, 142 insertions(+), 20 deletions(-) diff --git a/burrow-gtk/src/components/main/network_card.rs b/burrow-gtk/src/components/main/network_card.rs index be75066..41a1aa2 100644 --- a/burrow-gtk/src/components/main/network_card.rs +++ b/burrow-gtk/src/components/main/network_card.rs @@ -1,14 +1,27 @@ use super::*; -pub struct NetworkCard {} +pub struct NetworkCard { + id: i32, + index: usize, + index_max: usize, + daemon_client: Arc>>, +} pub struct NetworkCardInit { + pub id: i32, + pub index: usize, + pub index_max: usize, pub name: String, pub enabled: bool, + pub daemon_client: Arc>>, } #[derive(Debug)] -pub enum NetworkCardMsg {} +pub enum NetworkCardMsg { + NetworkDelete, + MoveUp, + MoveDown, +} #[relm4::component(pub, async)] impl AsyncComponent for NetworkCard { @@ -31,6 +44,24 @@ impl AsyncComponent for NetworkCard { set_vexpand: false, set_state: init.enabled, }, + gtk::Button { + set_icon_name: "list-remove", + set_margin_all: 12, + + connect_clicked => NetworkCardMsg::NetworkDelete, + }, + gtk::Button { + set_icon_name: "pan-up-symbolic", + set_margin_all: 12, + + connect_clicked => NetworkCardMsg::MoveUp, + }, + gtk::Button { + set_icon_name: "pan-down-symbolic", + set_margin_all: 12, + + connect_clicked => NetworkCardMsg::MoveDown, + }, } } } @@ -42,8 +73,60 @@ impl AsyncComponent for NetworkCard { ) -> AsyncComponentParts { let widgets = view_output!(); - let model = NetworkCard {}; + let model = NetworkCard { + id: init.id, + index: init.index, + index_max: init.index_max, + daemon_client: init.daemon_client, + }; AsyncComponentParts { model, widgets } } + + async fn update( + &mut self, + msg: Self::Input, + sender: AsyncComponentSender, + _root: &Self::Root, + ) { + match msg { + NetworkCardMsg::NetworkDelete => { + if let Some(daemon_client) = self.daemon_client.lock().await.as_mut() { + let mut client = networks_client::NetworksClient::new(daemon_client); + client + .network_delete(burrow_rpc::NetworkDeleteRequest { id: self.id }) + .await + .unwrap(); + } + } + NetworkCardMsg::MoveUp => { + if self.index.checked_sub(1).is_some() { + if let Some(daemon_client) = self.daemon_client.lock().await.as_mut() { + let mut client = networks_client::NetworksClient::new(daemon_client); + client + .network_reorder(burrow_rpc::NetworkReorderRequest { + id: self.id, + index: self.index as i32 - 1, + }) + .await + .unwrap(); + } + } + } + NetworkCardMsg::MoveDown => { + if self.index + 1 < self.index_max { + if let Some(daemon_client) = self.daemon_client.lock().await.as_mut() { + let mut client = networks_client::NetworksClient::new(daemon_client); + client + .network_reorder(burrow_rpc::NetworkReorderRequest { + id: self.id, + index: self.index as i32 + 1, + }) + .await + .unwrap(); + } + } + } + } + } } diff --git a/burrow-gtk/src/components/main/networks.rs b/burrow-gtk/src/components/main/networks.rs index 809c741..5c63b94 100644 --- a/burrow-gtk/src/components/main/networks.rs +++ b/burrow-gtk/src/components/main/networks.rs @@ -17,6 +17,7 @@ pub struct NetworksInit { pub enum NetworksMsg { None, NetworkList(Vec), + NetworkAdd, } #[relm4::component(pub, async)] @@ -34,7 +35,14 @@ impl AsyncComponent for Networks { set_valign: Align::Start, #[name = "networks"] - gtk::ListBox {} + gtk::ListBox {}, + + gtk::Button { + set_icon_name: "list-add", + set_margin_all: 12, + + connect_clicked => NetworksMsg::NetworkAdd, + }, } } @@ -48,23 +56,39 @@ impl AsyncComponent for Networks { let network_cards = vec![ NetworkCard::builder() .launch(NetworkCardInit { + id: 0, + index: 0, + index_max: 3, + daemon_client: Arc::clone(&init.daemon_client), name: "Hello".to_owned(), enabled: true, }) .forward(sender.input_sender(), |_| NetworksMsg::None), NetworkCard::builder() .launch(NetworkCardInit { + id: 1, + index: 1, + index_max: 3, + daemon_client: Arc::clone(&init.daemon_client), name: "World".to_owned(), enabled: false, }) .forward(sender.input_sender(), |_| NetworksMsg::None), NetworkCard::builder() .launch(NetworkCardInit { + id: 2, + index: 2, + index_max: 3, + daemon_client: Arc::clone(&init.daemon_client), name: "Yay".to_owned(), enabled: false, }) .forward(sender.input_sender(), |_| NetworksMsg::None), ]; + widgets.networks.append(network_cards[0].widget()); + widgets.networks.append(network_cards[1].widget()); + widgets.networks.append(network_cards[2].widget()); + // let network_cards = vec![]; let model = Networks { daemon_client: init.daemon_client, @@ -81,23 +105,37 @@ impl AsyncComponent for Networks { sender: AsyncComponentSender, _root: &Self::Root, ) { - if let NetworksMsg::NetworkList(networks) = msg { - for network_card in self.network_cards.iter() { - self.networks_list_box - .remove(&network_card.widget().clone()); - } - self.network_cards.clear(); + match msg { + NetworksMsg::NetworkList(networks) => { + for network_card in self.network_cards.iter() { + self.networks_list_box + .remove(&network_card.widget().clone()); + } + self.network_cards.clear(); - for network in networks { - let network_card = NetworkCard::builder() - .launch(NetworkCardInit { - name: format!("ID: {}, TYPE: {}", network.id, network.r#type), - enabled: false, - }) - .forward(sender.input_sender(), |_| NetworksMsg::None); - self.networks_list_box.append(network_card.widget()); - self.network_cards.push(network_card); + let index_max = networks.len(); + for (index, network) in networks.iter().enumerate() { + let network_card = NetworkCard::builder() + .launch(NetworkCardInit { + id: network.id, + index, + index_max, + daemon_client: Arc::clone(&self.daemon_client), + name: format!("ID: {}, TYPE: {}", network.id, network.r#type), + enabled: false, + }) + .forward(sender.input_sender(), |_| NetworksMsg::None); + self.networks_list_box.append(network_card.widget()); + self.network_cards.push(network_card); + } } + NetworksMsg::NetworkAdd => { + if let Some(daemon_client) = self.daemon_client.lock().await.as_mut() { + let mut client = networks_client::NetworksClient::new(daemon_client); + client.network_add(burrow_rpc::Empty {}).await.unwrap(); + } + } + _ => {} } } } diff --git a/burrow-gtk/src/components/main_screen.rs b/burrow-gtk/src/components/main_screen.rs index 52dd98a..973fe78 100644 --- a/burrow-gtk/src/components/main_screen.rs +++ b/burrow-gtk/src/components/main_screen.rs @@ -2,6 +2,7 @@ use super::*; pub struct MainScreen { switch: AsyncController, + networks: AsyncController, } pub struct MainScreenInit { @@ -85,7 +86,7 @@ impl AsyncComponent for MainScreen { widgets.content.append(networks.widget()); widgets.content.append(switch.widget()); - let model = MainScreen { switch }; + let model = MainScreen { switch, networks }; AsyncComponentParts { model, widgets } } From 3ecca38c87989eb88899b494f0de66aec2564875 Mon Sep 17 00:00:00 2001 From: dav Date: Fri, 16 Aug 2024 17:32:18 -0700 Subject: [PATCH 10/16] Test against test rpc server --- burrow-gtk/src/components/app.rs | 44 +++- burrow-gtk/src/components/main/mod.rs | 2 +- .../src/components/main/network_card.rs | 17 +- burrow-gtk/src/components/main/networks.rs | 11 +- burrow-gtk/src/components/main/switch.rs | 58 +---- burrow-gtk/src/components/main_screen.rs | 39 ++-- burrow-gtk/src/components/switch_screen.rs | 204 ------------------ 7 files changed, 81 insertions(+), 294 deletions(-) delete mode 100644 burrow-gtk/src/components/switch_screen.rs diff --git a/burrow-gtk/src/components/app.rs b/burrow-gtk/src/components/app.rs index c72d01d..cc12812 100644 --- a/burrow-gtk/src/components/app.rs +++ b/burrow-gtk/src/components/app.rs @@ -2,7 +2,7 @@ use super::*; use anyhow::Context; use std::time::Duration; -const RECONNECT_POLL_TIME: Duration = Duration::from_secs(5); +const RECONNECT_POLL_TIME: Duration = Duration::from_secs(3); pub struct App { daemon_client: Arc>>, @@ -59,7 +59,15 @@ impl AsyncComponent for App { sender: AsyncComponentSender, ) -> AsyncComponentParts { // TODO: RPC REFACTOR (Handle Error) - let daemon_client = Arc::new(Mutex::new(daemon::daemon_connect().await.ok())); + let mut daemon_client_connected = false; + let daemon_client = Arc::new(Mutex::new( + daemon::daemon_connect() + .await + .inspect(|_| { + daemon_client_connected = true; + }) + .ok(), + )); let main_screen = main_screen::MainScreen::builder() .launch(main_screen::MainScreenInit { @@ -73,6 +81,17 @@ impl AsyncComponent for App { }) .forward(sender.input_sender(), |_| AppMsg::None); + if !daemon_client_connected { + main_screen + .sender() + .send(main_screen::MainScreenMsg::DaemonDisconnect) + .unwrap(); + settings_screen + .sender() + .send(settings_screen::SettingsScreenMsg::DaemonStateChange) + .unwrap(); + } + let widgets = view_output!(); let view_stack = adw::ViewStack::new(); @@ -128,15 +147,20 @@ impl AsyncComponent for App { let mut daemon_client = self.daemon_client.lock().await; let mut disconnected_daemon_client = false; - if let Some(daemon_client) = daemon_client.as_mut() { - let mut client = tunnel_client::TunnelClient::new(daemon_client); - if let Err(_e) = client.tunnel_status(burrow_rpc::Empty {}).await { - disconnected_daemon_client = true; - self.main_screen - .emit(main_screen::MainScreenMsg::DaemonDisconnect); - self.settings_screen - .emit(settings_screen::SettingsScreenMsg::DaemonStateChange) + if let Some(client) = daemon_client.as_mut() { + let mut client = tunnel_client::TunnelClient::new(client); + + if let Ok(mut res) = client.tunnel_status(burrow_rpc::Empty {}).await { + let stream = res.get_mut(); + while let Ok(Some(_)) = stream.message().await {} } + + *daemon_client = None; + disconnected_daemon_client = true; + self.main_screen + .emit(main_screen::MainScreenMsg::DaemonDisconnect); + self.settings_screen + .emit(settings_screen::SettingsScreenMsg::DaemonStateChange) } if disconnected_daemon_client || daemon_client.is_none() { diff --git a/burrow-gtk/src/components/main/mod.rs b/burrow-gtk/src/components/main/mod.rs index 8e03b41..903bfba 100644 --- a/burrow-gtk/src/components/main/mod.rs +++ b/burrow-gtk/src/components/main/mod.rs @@ -6,4 +6,4 @@ mod switch; pub use network_card::{NetworkCard, NetworkCardInit}; pub use networks::{Networks, NetworksInit}; -pub use switch::{Switch, SwitchInit, SwitchMsg}; +pub use switch::{Switch, SwitchInit}; diff --git a/burrow-gtk/src/components/main/network_card.rs b/burrow-gtk/src/components/main/network_card.rs index 41a1aa2..b002cd1 100644 --- a/burrow-gtk/src/components/main/network_card.rs +++ b/burrow-gtk/src/components/main/network_card.rs @@ -86,30 +86,28 @@ impl AsyncComponent for NetworkCard { async fn update( &mut self, msg: Self::Input, - sender: AsyncComponentSender, + _: AsyncComponentSender, _root: &Self::Root, ) { match msg { NetworkCardMsg::NetworkDelete => { if let Some(daemon_client) = self.daemon_client.lock().await.as_mut() { let mut client = networks_client::NetworksClient::new(daemon_client); - client + let _ = client .network_delete(burrow_rpc::NetworkDeleteRequest { id: self.id }) - .await - .unwrap(); + .await; } } NetworkCardMsg::MoveUp => { if self.index.checked_sub(1).is_some() { if let Some(daemon_client) = self.daemon_client.lock().await.as_mut() { let mut client = networks_client::NetworksClient::new(daemon_client); - client + let _ = client .network_reorder(burrow_rpc::NetworkReorderRequest { id: self.id, index: self.index as i32 - 1, }) - .await - .unwrap(); + .await; } } } @@ -117,13 +115,12 @@ impl AsyncComponent for NetworkCard { if self.index + 1 < self.index_max { if let Some(daemon_client) = self.daemon_client.lock().await.as_mut() { let mut client = networks_client::NetworksClient::new(daemon_client); - client + let _ = client .network_reorder(burrow_rpc::NetworkReorderRequest { id: self.id, index: self.index as i32 + 1, }) - .await - .unwrap(); + .await; } } } diff --git a/burrow-gtk/src/components/main/networks.rs b/burrow-gtk/src/components/main/networks.rs index 5c63b94..aabd480 100644 --- a/burrow-gtk/src/components/main/networks.rs +++ b/burrow-gtk/src/components/main/networks.rs @@ -7,6 +7,8 @@ pub struct Networks { daemon_client: Arc>>, network_cards: Vec>, networks_list_box: gtk::ListBox, + + _network_state_worker: WorkerController, } pub struct NetworksInit { @@ -94,6 +96,10 @@ impl AsyncComponent for Networks { daemon_client: init.daemon_client, network_cards, networks_list_box: widgets.networks.clone(), + + _network_state_worker: AsyncNetworkStateHandler::builder() + .detach_worker(()) + .forward(sender.input_sender(), |msg| msg), }; AsyncComponentParts { model, widgets } @@ -132,7 +138,7 @@ impl AsyncComponent for Networks { NetworksMsg::NetworkAdd => { if let Some(daemon_client) = self.daemon_client.lock().await.as_mut() { let mut client = networks_client::NetworksClient::new(daemon_client); - client.network_add(burrow_rpc::Empty {}).await.unwrap(); + let _ = client.network_add(burrow_rpc::Empty {}).await; } } _ => {} @@ -147,7 +153,8 @@ impl Worker for AsyncNetworkStateHandler { type Input = (); type Output = NetworksMsg; - fn init(_: Self::Init, _sender: ComponentSender) -> Self { + fn init(_: Self::Init, sender: ComponentSender) -> Self { + sender.input(()); Self } diff --git a/burrow-gtk/src/components/main/switch.rs b/burrow-gtk/src/components/main/switch.rs index 5958e83..0b812ca 100644 --- a/burrow-gtk/src/components/main/switch.rs +++ b/burrow-gtk/src/components/main/switch.rs @@ -6,8 +6,6 @@ const RECONNECT_POLL_TIME: Duration = Duration::from_secs(3); pub struct Switch { daemon_client: Arc>>, switch: gtk::Switch, - switch_screen: gtk::Box, - disconnected_banner: adw::Banner, _tunnel_state_worker: WorkerController, } @@ -19,8 +17,6 @@ pub struct SwitchInit { #[derive(Debug, PartialEq, Eq)] pub enum SwitchMsg { None, - DaemonReconnect, - DaemonDisconnect, Start, Stop, SwitchSetStart, @@ -51,7 +47,6 @@ impl AsyncComponent for Switch { }, }, - #[name(switch_screen)] gtk::Box { set_orientation: gtk::Orientation::Vertical, set_spacing: 10, @@ -80,37 +75,12 @@ impl AsyncComponent for Switch { root: Self::Root, sender: AsyncComponentSender, ) -> AsyncComponentParts { - let mut initial_daemon_server_down = false; - - if let Some(daemon_client) = init.daemon_client.lock().await.as_mut() { - let mut client = tunnel_client::TunnelClient::new(daemon_client); - if client - .tunnel_status(burrow_rpc::Empty {}) - .await - .as_mut() - .is_err() - { - initial_daemon_server_down = true; - } - } else { - initial_daemon_server_down = true; - } - let switch_sender = sender.clone(); let widgets = view_output!(); - if initial_daemon_server_down { - *init.daemon_client.lock().await = None; - widgets.switch.set_active(false); - widgets.switch_screen.set_sensitive(false); - widgets.setup_banner.set_revealed(true); - } - let model = Switch { daemon_client: init.daemon_client, switch: widgets.switch.clone(), - switch_screen: widgets.switch_screen.clone(), - disconnected_banner: widgets.setup_banner.clone(), _tunnel_state_worker: AsyncTunnelStateHandler::builder() .detach_worker(()) .forward(sender.input_sender(), |_| SwitchMsg::None), @@ -127,20 +97,16 @@ impl AsyncComponent for Switch { _: AsyncComponentSender, _root: &Self::Root, ) { - let mut disconnected_daemon_client = false; - if let Some(daemon_client) = self.daemon_client.lock().await.as_mut() { let mut client = tunnel_client::TunnelClient::new(daemon_client); match msg { Self::Input::Start => { - if let Err(_e) = client.tunnel_start(burrow_rpc::Empty {}).await { - disconnected_daemon_client = true; - } + // TODO: Figure out best way for error handling. + let _ = client.tunnel_start(burrow_rpc::Empty {}).await; } Self::Input::Stop => { - if let Err(_e) = client.tunnel_stop(burrow_rpc::Empty {}).await { - disconnected_daemon_client = true; - } + // TODO: Figure out best way for error handling. + let _ = client.tunnel_stop(burrow_rpc::Empty {}).await; } Self::Input::SwitchSetStart => { self.switch.set_active(true); @@ -150,19 +116,6 @@ impl AsyncComponent for Switch { } _ => {} } - } else { - disconnected_daemon_client = true; - } - - if msg == Self::Input::DaemonReconnect { - self.disconnected_banner.set_revealed(false); - self.switch_screen.set_sensitive(true); - } - - if disconnected_daemon_client || msg == Self::Input::DaemonDisconnect { - *self.daemon_client.lock().await = None; - self.switch_screen.set_sensitive(false); - self.disconnected_banner.set_revealed(true); } } } @@ -174,7 +127,8 @@ impl Worker for AsyncTunnelStateHandler { type Input = (); type Output = SwitchMsg; - fn init(_: Self::Init, _sender: ComponentSender) -> Self { + fn init(_: Self::Init, sender: ComponentSender) -> Self { + sender.input(()); Self } diff --git a/burrow-gtk/src/components/main_screen.rs b/burrow-gtk/src/components/main_screen.rs index 973fe78..fc55a12 100644 --- a/burrow-gtk/src/components/main_screen.rs +++ b/burrow-gtk/src/components/main_screen.rs @@ -1,8 +1,10 @@ use super::*; pub struct MainScreen { - switch: AsyncController, - networks: AsyncController, + _switch: AsyncController, + _networks: AsyncController, + content_box: gtk::Box, + daemon_status_banner: adw::Banner, } pub struct MainScreenInit { @@ -29,17 +31,17 @@ impl AsyncComponent for MainScreen { set_valign: Align::Fill, set_valign: Align::Center, - // gtk::Box { - // set_orientation: gtk::Orientation::Vertical, - // set_spacing: 5, - // set_margin_all: 5, - // set_valign: Align::Start, + gtk::Box { + set_orientation: gtk::Orientation::Vertical, + set_spacing: 5, + set_margin_all: 5, + set_valign: Align::Start, - // #[name(setup_banner)] - // adw::Banner { - // set_title: "Burrow is not running!", - // }, - // }, + #[name(daemon_status_banner)] + adw::Banner { + set_title: "Burrow is not running!", + }, + }, gtk::Box { set_orientation: gtk::Orientation::Vertical, @@ -86,7 +88,12 @@ impl AsyncComponent for MainScreen { widgets.content.append(networks.widget()); widgets.content.append(switch.widget()); - let model = MainScreen { switch, networks }; + let model = MainScreen { + _switch: switch, + _networks: networks, + content_box: widgets.content.clone(), + daemon_status_banner: widgets.daemon_status_banner.clone(), + }; AsyncComponentParts { model, widgets } } @@ -99,10 +106,12 @@ impl AsyncComponent for MainScreen { ) { match msg { MainScreenMsg::DaemonDisconnect => { - self.switch.emit(main::SwitchMsg::DaemonDisconnect); + self.daemon_status_banner.set_revealed(true); + self.content_box.set_sensitive(false); } MainScreenMsg::DaemonReconnect => { - self.switch.emit(main::SwitchMsg::DaemonReconnect); + self.daemon_status_banner.set_revealed(false); + self.content_box.set_sensitive(true); } _ => {} } diff --git a/burrow-gtk/src/components/switch_screen.rs b/burrow-gtk/src/components/switch_screen.rs deleted file mode 100644 index 7258854..0000000 --- a/burrow-gtk/src/components/switch_screen.rs +++ /dev/null @@ -1,204 +0,0 @@ -use super::*; -use std::time::Duration; - -const RECONNECT_POLL_TIME: Duration = Duration::from_secs(3); - -pub struct SwitchScreen { - daemon_client: Arc>>, - switch: gtk::Switch, - switch_screen: gtk::Box, - disconnected_banner: adw::Banner, - - _tunnel_state_worker: WorkerController, -} - -pub struct SwitchScreenInit { - pub daemon_client: Arc>>, -} - -#[derive(Debug, PartialEq, Eq)] -pub enum SwitchScreenMsg { - None, - DaemonReconnect, - DaemonDisconnect, - Start, - Stop, - SwitchSetStart, - SwitchSetStop, -} - -#[relm4::component(pub, async)] -impl AsyncComponent for SwitchScreen { - type Init = SwitchScreenInit; - type Input = SwitchScreenMsg; - type Output = (); - type CommandOutput = SwitchScreenMsg; - - view! { - gtk::Box { - set_orientation: gtk::Orientation::Vertical, - set_valign: Align::Fill, - - gtk::Box { - set_orientation: gtk::Orientation::Vertical, - set_spacing: 5, - set_margin_all: 5, - set_valign: Align::Start, - - #[name(setup_banner)] - adw::Banner { - set_title: "Burrow is not running!", - }, - }, - - #[name(switch_screen)] - gtk::Box { - set_orientation: gtk::Orientation::Vertical, - set_spacing: 10, - set_margin_all: 5, - set_valign: Align::Center, - set_vexpand: true, - - gtk::Label { - set_label: "Burrow Switch", - }, - - #[name(switch)] - gtk::Switch { - set_halign: Align::Center, - set_hexpand: false, - set_vexpand: false, - connect_active_notify => move |switch| - switch_sender.input(if switch.is_active() { SwitchScreenMsg::Start } else { SwitchScreenMsg::Stop }) - }, - } - } - } - - async fn init( - init: Self::Init, - root: Self::Root, - sender: AsyncComponentSender, - ) -> AsyncComponentParts { - let mut initial_daemon_server_down = false; - - if let Some(daemon_client) = init.daemon_client.lock().await.as_mut() { - let mut client = tunnel_client::TunnelClient::new(daemon_client); - if client - .tunnel_status(burrow_rpc::Empty {}) - .await - .as_mut() - .is_err() - { - initial_daemon_server_down = true; - } - } else { - initial_daemon_server_down = true; - } - - let switch_sender = sender.clone(); - let widgets = view_output!(); - - if initial_daemon_server_down { - *init.daemon_client.lock().await = None; - widgets.switch.set_active(false); - widgets.switch_screen.set_sensitive(false); - widgets.setup_banner.set_revealed(true); - } - - let model = SwitchScreen { - daemon_client: init.daemon_client, - switch: widgets.switch.clone(), - switch_screen: widgets.switch_screen.clone(), - disconnected_banner: widgets.setup_banner.clone(), - _tunnel_state_worker: AsyncTunnelStateHandler::builder() - .detach_worker(()) - .forward(sender.input_sender(), |_| SwitchScreenMsg::None), - }; - - widgets.switch.set_active(false); - - AsyncComponentParts { model, widgets } - } - - async fn update( - &mut self, - msg: Self::Input, - _: AsyncComponentSender, - _root: &Self::Root, - ) { - let mut disconnected_daemon_client = false; - - if let Some(daemon_client) = self.daemon_client.lock().await.as_mut() { - let mut client = tunnel_client::TunnelClient::new(daemon_client); - match msg { - Self::Input::Start => { - if let Err(_e) = client.tunnel_start(burrow_rpc::Empty {}).await { - disconnected_daemon_client = true; - } - } - Self::Input::Stop => { - if let Err(_e) = client.tunnel_stop(burrow_rpc::Empty {}).await { - disconnected_daemon_client = true; - } - } - Self::Input::SwitchSetStart => { - self.switch.set_active(true); - } - Self::Input::SwitchSetStop => { - self.switch.set_active(false); - } - _ => {} - } - } else { - disconnected_daemon_client = true; - } - - if msg == Self::Input::DaemonReconnect { - self.disconnected_banner.set_revealed(false); - self.switch_screen.set_sensitive(true); - } - - if disconnected_daemon_client || msg == Self::Input::DaemonDisconnect { - *self.daemon_client.lock().await = None; - self.switch_screen.set_sensitive(false); - self.disconnected_banner.set_revealed(true); - } - } -} -struct AsyncTunnelStateHandler; - -impl Worker for AsyncTunnelStateHandler { - type Init = (); - type Input = (); - type Output = SwitchScreenMsg; - - fn init(_: Self::Init, _sender: ComponentSender) -> Self { - Self - } - - fn update(&mut self, _: (), sender: ComponentSender) { - let rt = tokio::runtime::Runtime::new().unwrap(); - let task = rt.spawn(async move { - loop { - let conn = daemon::daemon_connect().await; - if let Ok(conn) = conn { - let mut client = tunnel_client::TunnelClient::new(conn); - if let Ok(mut res) = client.tunnel_status(burrow_rpc::Empty {}).await { - let stream = res.get_mut(); - while let Ok(Some(msg)) = stream.message().await { - sender - .output(match msg.state() { - burrow_rpc::State::Running => SwitchScreenMsg::SwitchSetStart, - burrow_rpc::State::Stopped => SwitchScreenMsg::SwitchSetStop, - }) - .unwrap(); - } - } - } - tokio::time::sleep(RECONNECT_POLL_TIME).await; - } - }); - rt.block_on(task).unwrap(); - } -} From 62a5739d86feb8c2d23ec3d6187d2f1c6dffc9d3 Mon Sep 17 00:00:00 2001 From: Conrad Kramer Date: Sat, 7 Sep 2024 17:01:17 -0700 Subject: [PATCH 11/16] Update pipelines with various fixes --- .github/actions/download-profiles/action.yml | 27 ++++++++++++ .github/workflows/build-appimage.yml | 3 ++ .github/workflows/build-docker.yml | 3 ++ .github/workflows/build-rust.yml | 2 +- .github/workflows/lint-swift.yml | 2 +- .github/workflows/release-appimage.yml | 29 ------------- .github/workflows/release-apple.yml | 5 ++- .github/workflows/release-if-needed.yaml | 2 + .github/workflows/release-linux.yml | 43 +++++++++----------- 9 files changed, 59 insertions(+), 57 deletions(-) create mode 100644 .github/actions/download-profiles/action.yml delete mode 100644 .github/workflows/release-appimage.yml diff --git a/.github/actions/download-profiles/action.yml b/.github/actions/download-profiles/action.yml new file mode 100644 index 0000000..98961aa --- /dev/null +++ b/.github/actions/download-profiles/action.yml @@ -0,0 +1,27 @@ +name: Download Provisioning Profiles +inputs: + app-store-key: + description: App Store key in PEM PKCS#8 format + required: true + app-store-key-id: + description: App Store key ID + required: true + app-store-key-issuer-id: + description: App Store key issuer ID + required: true +runs: + using: composite + steps: + - shell: bash + run: | + cat << EOF > api-key.json + { + "key_id": "${{ inputs.app-store-key-id }}", + "issuer_id": "${{ inputs.app-store-key-issuer-id }}", + "key": "${{ inputs.app-store-key }}" + } + EOF + + fastlane sigh download_all --api_key_path api-key.json --download_xcode_profiles + + rm -rf api-key.json diff --git a/.github/workflows/build-appimage.yml b/.github/workflows/build-appimage.yml index bb510fb..bd29b07 100644 --- a/.github/workflows/build-appimage.yml +++ b/.github/workflows/build-appimage.yml @@ -6,6 +6,9 @@ on: pull_request: branches: - "*" +concurrency: + group: ${{ github.workflow }}-${{ github.event.pull_request.number || github.ref }} + cancel-in-progress: true jobs: appimage: name: Build AppImage diff --git a/.github/workflows/build-docker.yml b/.github/workflows/build-docker.yml index 307a93c..6a3dae1 100644 --- a/.github/workflows/build-docker.yml +++ b/.github/workflows/build-docker.yml @@ -6,6 +6,9 @@ on: pull_request: branches: - "*" +concurrency: + group: ${{ github.workflow }}-${{ github.event.pull_request.number || github.ref }} + cancel-in-progress: true jobs: build: name: Build Docker Image diff --git a/.github/workflows/build-rust.yml b/.github/workflows/build-rust.yml index 76ce9f2..11ff60d 100644 --- a/.github/workflows/build-rust.yml +++ b/.github/workflows/build-rust.yml @@ -58,7 +58,7 @@ jobs: run: | sudo apt-get update sudo apt-get install -y ${{ join(matrix.packages, ' ') }} - - name: Install Windows Deps + - name: Configure LLVM if: matrix.os == 'windows-2022' shell: bash run: echo "C:\Program Files (x86)\Microsoft Visual Studio\2019\Enterprise\VC\Tools\Llvm\x64\bin" >> $GITHUB_PATH diff --git a/.github/workflows/lint-swift.yml b/.github/workflows/lint-swift.yml index a2cc96a..857f575 100644 --- a/.github/workflows/lint-swift.yml +++ b/.github/workflows/lint-swift.yml @@ -13,4 +13,4 @@ jobs: - name: Checkout uses: actions/checkout@v4 - name: Lint - run: swiftlint lint --reporter github-actions-logging + run: swiftlint lint --strict --reporter github-actions-logging diff --git a/.github/workflows/release-appimage.yml b/.github/workflows/release-appimage.yml deleted file mode 100644 index e566186..0000000 --- a/.github/workflows/release-appimage.yml +++ /dev/null @@ -1,29 +0,0 @@ -name: Release (AppImage) -on: - release: - types: - - created -jobs: - appimage: - name: Build AppImage - runs-on: ubuntu-latest - container: docker - steps: - - name: Checkout - uses: actions/checkout@v4 - with: - fetch-depth: 0 - - name: Build - run: | - docker build -t appimage-builder . -f burrow-gtk/build-aux/Dockerfile - docker create --name temp appimage-builder - docker cp temp:/app/burrow-gtk/build-appimage/Burrow-x86_64.AppImage . - docker rm temp - - name: Upload to GitHub - uses: SierraSoftworks/gh-releases@v1.0.7 - with: - token: ${{ secrets.GITHUB_TOKEN }} - release_tag: ${{ github.ref_name }} - overwrite: 'true' - files: | - Burrow-x86_64.AppImage diff --git a/.github/workflows/release-apple.yml b/.github/workflows/release-apple.yml index 1883008..f1ee5dd 100644 --- a/.github/workflows/release-apple.yml +++ b/.github/workflows/release-apple.yml @@ -24,7 +24,7 @@ jobs: - x86_64-apple-darwin - aarch64-apple-darwin env: - DEVELOPER_DIR: /Applications/Xcode_15.4.app/Contents/Developer + DEVELOPER_DIR: /Applications/Xcode_16.0.app/Contents/Developer steps: - name: Checkout uses: actions/checkout@v4 @@ -40,8 +40,9 @@ jobs: with: targets: ${{ join(matrix.rust-targets, ', ') }} - name: Configure Version + id: version shell: bash - run: Tools/version.sh + run: echo "BUILD_NUMBER=$(Tools/version.sh)" >> $GITHUB_OUTPUT - name: Archive uses: ./.github/actions/archive with: diff --git a/.github/workflows/release-if-needed.yaml b/.github/workflows/release-if-needed.yaml index 0d2eb97..79f0d63 100644 --- a/.github/workflows/release-if-needed.yaml +++ b/.github/workflows/release-if-needed.yaml @@ -9,6 +9,8 @@ jobs: create: name: Create Release If Needed runs-on: ubuntu-latest + env: + GH_TOKEN: ${{ github.token }} steps: - name: Checkout uses: actions/checkout@v4 diff --git a/.github/workflows/release-linux.yml b/.github/workflows/release-linux.yml index 6709edb..7db9bcf 100644 --- a/.github/workflows/release-linux.yml +++ b/.github/workflows/release-linux.yml @@ -2,33 +2,28 @@ name: Release (Linux) on: release: types: - - created + - created jobs: appimage: name: Build AppImage runs-on: ubuntu-latest container: docker steps: - - name: Checkout - uses: actions/checkout@v4 - with: - fetch-depth: 0 - - name: Build AppImage - run: | - docker build -t appimage-builder . -f burrow-gtk/build-aux/Dockerfile - docker create --name temp appimage-builder - docker cp temp:/app/burrow-gtk/build-appimage/Burrow-x86_64.AppImage . - docker rm temp - - name: Get Build Number - id: version - shell: bash - run: | - echo "BUILD_NUMBER=$(Tools/version.sh)" >> $GITHUB_OUTPUT - - name: Attach Artifacts - uses: SierraSoftworks/gh-releases@v1.0.7 - with: - token: ${{ secrets.GITHUB_TOKEN }} - release_tag: builds/${{ steps.version.outputs.BUILD_NUMBER }} - overwrite: "true" - files: | - Burrow-x86_64.AppImage + - name: Checkout + uses: actions/checkout@v4 + with: + fetch-depth: 0 + - name: Build AppImage + run: | + docker build -t appimage-builder . -f burrow-gtk/build-aux/Dockerfile + docker create --name temp appimage-builder + docker cp temp:/app/burrow-gtk/build-appimage/Burrow-x86_64.AppImage . + docker rm temp + - name: Attach Artifacts + uses: SierraSoftworks/gh-releases@v1.0.7 + with: + token: ${{ secrets.GITHUB_TOKEN }} + release_tag: ${{ github.ref_name }} + overwrite: "true" + files: | + Burrow-x86_64.AppImage From fa1ef6fcda7acf4f9a0cf66d811baf1e626ac2a4 Mon Sep 17 00:00:00 2001 From: Conrad Kramer Date: Sat, 7 Sep 2024 17:08:02 -0700 Subject: [PATCH 12/16] Download provisioning profiles in release pipeline --- .github/actions/download-profiles/action.yml | 7 +++++-- .github/actions/export/action.yml | 10 +++------- .github/workflows/build-rust.yml | 2 +- .github/workflows/release-apple.yml | 21 ++++++++++++-------- 4 files changed, 22 insertions(+), 18 deletions(-) diff --git a/.github/actions/download-profiles/action.yml b/.github/actions/download-profiles/action.yml index 98961aa..32b615c 100644 --- a/.github/actions/download-profiles/action.yml +++ b/.github/actions/download-profiles/action.yml @@ -13,15 +13,18 @@ runs: using: composite steps: - shell: bash + env: + FASTLANE_OPT_OUT_USAGE: 'YES' run: | + APP_STORE_KEY=$(echo "${{ inputs.app-store-key }}" | jq -sR .) cat << EOF > api-key.json { "key_id": "${{ inputs.app-store-key-id }}", "issuer_id": "${{ inputs.app-store-key-issuer-id }}", - "key": "${{ inputs.app-store-key }}" + "key": $APP_STORE_KEY } EOF - fastlane sigh download_all --api_key_path api-key.json --download_xcode_profiles + fastlane sigh download_all --api_key_path api-key.json rm -rf api-key.json diff --git a/.github/actions/export/action.yml b/.github/actions/export/action.yml index 8f891be..75b748f 100644 --- a/.github/actions/export/action.yml +++ b/.github/actions/export/action.yml @@ -12,11 +12,8 @@ inputs: archive-path: description: Xcode archive path required: true - destination: - description: The Xcode export destination. This can either be "export" or "upload" - required: true - method: - description: The Xcode export method. This can be one of app-store, validation, ad-hoc, package, enterprise, development, developer-id, or mac-application. + export-options: + description: The export options in JSON format required: true export-path: description: The path to export the archive to @@ -29,8 +26,7 @@ runs: run: | echo "${{ inputs.app-store-key }}" > AuthKey_${{ inputs.app-store-key-id }}.p8 - echo '{"destination":"${{ inputs.destination }}","method":"${{ inputs.method }}"}' \ - | plutil -convert xml1 -o ExportOptions.plist - + echo '${{ inputs.export-options }}' | plutil -convert xml1 -o ExportOptions.plist - xcodebuild \ -exportArchive \ diff --git a/.github/workflows/build-rust.yml b/.github/workflows/build-rust.yml index 11ff60d..22bf83a 100644 --- a/.github/workflows/build-rust.yml +++ b/.github/workflows/build-rust.yml @@ -42,7 +42,7 @@ jobs: - aarch64-pc-windows-msvc runs-on: ${{ matrix.os }} env: - DEVELOPER_DIR: /Applications/Xcode_15.4.app/Contents/Developer + DEVELOPER_DIR: /Applications/Xcode_16.0.app/Contents/Developer CARGO_INCREMENTAL: 0 CARGO_TARGET_AARCH64_UNKNOWN_LINUX_GNU_LINKER: aarch64-linux-gnu-gcc RUST_BACKTRACE: short diff --git a/.github/workflows/release-apple.yml b/.github/workflows/release-apple.yml index f1ee5dd..bb9c15a 100644 --- a/.github/workflows/release-apple.yml +++ b/.github/workflows/release-apple.yml @@ -13,13 +13,10 @@ jobs: fail-fast: false matrix: include: - - - destination: generic/platform=iOS - platform: iOS + - platform: iOS rust-targets: - aarch64-apple-ios - - destination: generic/platform=macOS - platform: macOS + - platform: macOS rust-targets: - x86_64-apple-darwin - aarch64-apple-darwin @@ -35,6 +32,12 @@ jobs: with: certificate: ${{ secrets.DEVELOPER_CERT }} password: ${{ secrets.DEVELOPER_CERT_PASSWORD }} + - name: Download Provisioning Profiles + uses: ./.github/actions/download-profiles + with: + app-store-key: ${{ secrets.APPSTORE_KEY }} + app-store-key-id: ${{ secrets.APPSTORE_KEY_ID }} + app-store-key-issuer-id: ${{ secrets.APPSTORE_KEY_ISSUER_ID }} - name: Install Rust uses: dtolnay/rust-toolchain@stable with: @@ -47,7 +50,7 @@ jobs: uses: ./.github/actions/archive with: scheme: App - destination: ${{ matrix.destination }} + destination: generic/platform=${{ matrix.platform }} app-store-key: ${{ secrets.APPSTORE_KEY }} app-store-key-id: ${{ secrets.APPSTORE_KEY_ID }} app-store-key-issuer-id: ${{ secrets.APPSTORE_KEY_ISSUER_ID }} @@ -61,6 +64,8 @@ jobs: app-store-key-id: ${{ secrets.APPSTORE_KEY_ID }} app-store-key-issuer-id: ${{ secrets.APPSTORE_KEY_ISSUER_ID }} archive-path: Burrow.xcarchive + export-options: | + {"teamID":"P6PV2R9443","destination":"export","method":"developer-id","provisioningProfiles":{"com.hackclub.burrow":"Burrow Developer ID","com.hackclub.burrow.network":"Burrow Network Developer ID"},"signingCertificate":"Developer ID Application","signingStyle":"manual"} export-path: Release - name: Notarize if: ${{ matrix.platform == 'macOS' }} @@ -96,10 +101,10 @@ jobs: if: ${{ matrix.platform == 'iOS' }} uses: ./.github/actions/export with: - method: app-store - destination: upload app-store-key: ${{ secrets.APPSTORE_KEY }} app-store-key-id: ${{ secrets.APPSTORE_KEY_ID }} app-store-key-issuer-id: ${{ secrets.APPSTORE_KEY_ISSUER_ID }} archive-path: Burrow.xcarchive + export-options: | + {"method": "app-store", "destination": "upload"} export-path: Release From 3fbb520a106101761ca3cff49ce62029a88408fa Mon Sep 17 00:00:00 2001 From: Conrad Kramer Date: Sat, 7 Sep 2024 17:36:48 -0700 Subject: [PATCH 13/16] Fix SwiftLint errors --- .github/actions/build-for-testing/action.yml | 2 + .github/workflows/build-rust.yml | 6 ++- Apple/App/AppDelegate.swift | 3 +- Apple/App/BurrowView.swift | 1 - Apple/App/OAuth2.swift | 46 +++++++++++--------- 5 files changed, 33 insertions(+), 25 deletions(-) diff --git a/.github/actions/build-for-testing/action.yml b/.github/actions/build-for-testing/action.yml index 084ba81..185c4ab 100644 --- a/.github/actions/build-for-testing/action.yml +++ b/.github/actions/build-for-testing/action.yml @@ -27,7 +27,9 @@ runs: Apple/DerivedData key: ${{ runner.os }}-${{ inputs.scheme }}-${{ hashFiles('**/Package.resolved') }} restore-keys: | + ${{ runner.os }}-${{ inputs.scheme }}-${{ hashFiles('**/Package.resolved') }} ${{ runner.os }}-${{ inputs.scheme }}- + ${{ runner.os }}- - name: Build shell: bash working-directory: Apple diff --git a/.github/workflows/build-rust.yml b/.github/workflows/build-rust.yml index 22bf83a..84ac9d8 100644 --- a/.github/workflows/build-rust.yml +++ b/.github/workflows/build-rust.yml @@ -21,14 +21,16 @@ jobs: - x86_64-unknown-linux-gnu targets: - aarch64-unknown-linux-gnu - - os: macos-12 + - os: macos-13 platform: macOS (Intel) + xcode: /Applications/Xcode_15.2.app test-targets: - x86_64-apple-darwin targets: - x86_64-apple-ios - os: macos-14 platform: macOS + xcode: /Applications/Xcode_16.0.app test-targets: - aarch64-apple-darwin targets: @@ -42,7 +44,7 @@ jobs: - aarch64-pc-windows-msvc runs-on: ${{ matrix.os }} env: - DEVELOPER_DIR: /Applications/Xcode_16.0.app/Contents/Developer + DEVELOPER_DIR: ${{ matrix.xcode }}/Contents/Developer CARGO_INCREMENTAL: 0 CARGO_TARGET_AARCH64_UNKNOWN_LINUX_GNU_LINKER: aarch64-linux-gnu-gcc RUST_BACKTRACE: short diff --git a/Apple/App/AppDelegate.swift b/Apple/App/AppDelegate.swift index bd76a2f..b0c5546 100644 --- a/Apple/App/AppDelegate.swift +++ b/Apple/App/AppDelegate.swift @@ -2,7 +2,8 @@ import AppKit import SwiftUI -@MainActor @main +@main +@MainActor class AppDelegate: NSObject, NSApplicationDelegate { private let quitItem: NSMenuItem = { let quitItem = NSMenuItem( diff --git a/Apple/App/BurrowView.swift b/Apple/App/BurrowView.swift index 8447592..3a53762 100644 --- a/Apple/App/BurrowView.swift +++ b/Apple/App/BurrowView.swift @@ -42,7 +42,6 @@ struct BurrowView: View { } private func addWireGuardNetwork() { - } private func authenticateWithSlack() async throws { diff --git a/Apple/App/OAuth2.swift b/Apple/App/OAuth2.swift index dc8c62b..9a930c9 100644 --- a/Apple/App/OAuth2.swift +++ b/Apple/App/OAuth2.swift @@ -1,6 +1,6 @@ import AuthenticationServices -import SwiftUI import Foundation +import SwiftUI enum OAuth2 { enum Error: Swift.Error { @@ -35,7 +35,7 @@ enum OAuth2 { } } - public init( + init( authorizationEndpoint: URL, tokenEndpoint: URL, redirectURI: URL, @@ -125,7 +125,11 @@ enum OAuth2 { var refreshToken: String? var credential: Credential { - .init(accessToken: accessToken, refreshToken: refreshToken, expirationDate: expiresIn.map { Date.init(timeIntervalSinceNow: $0) }) + .init( + accessToken: accessToken, + refreshToken: refreshToken, + expirationDate: expiresIn.map { Date(timeIntervalSinceNow: $0) } + ) } } @@ -203,7 +207,24 @@ enum OAuth2 { } extension WebAuthenticationSession { - func start(url: URL, redirectURI: URL) async throws -> URL { +#if canImport(BrowserEngineKit) + @available(iOS 17.4, macOS 14.4, tvOS 17.4, watchOS 10.4, *) + fileprivate static func callback(for redirectURI: URL) throws -> ASWebAuthenticationSession.Callback { + switch redirectURI.scheme { + case "https": + guard let host = redirectURI.host else { throw OAuth2.Error.invalidRedirectURI } + return .https(host: host, path: redirectURI.path) + case "http": + throw OAuth2.Error.invalidRedirectURI + case .some(let scheme): + return .customScheme(scheme) + case .none: + throw OAuth2.Error.invalidRedirectURI + } + } +#endif + + fileprivate func start(url: URL, redirectURI: URL) async throws -> URL { #if canImport(BrowserEngineKit) if #available(iOS 17.4, macOS 14.4, tvOS 17.4, watchOS 10.4, *) { return try await authenticate( @@ -231,23 +252,6 @@ extension WebAuthenticationSession { return url } } - - #if canImport(BrowserEngineKit) - @available(iOS 17.4, macOS 14.4, tvOS 17.4, watchOS 10.4, *) - fileprivate static func callback(for redirectURI: URL) throws -> ASWebAuthenticationSession.Callback { - switch redirectURI.scheme { - case "https": - guard let host = redirectURI.host else { throw OAuth2.Error.invalidRedirectURI } - return .https(host: host, path: redirectURI.path) - case "http": - throw OAuth2.Error.invalidRedirectURI - case .some(let scheme): - return .customScheme(scheme) - case .none: - throw OAuth2.Error.invalidRedirectURI - } - } - #endif } extension View { From e4b0f1660bff2112d0e20316c228926bed47f270 Mon Sep 17 00:00:00 2001 From: Jett Chen Date: Sat, 13 Jul 2024 17:32:49 -0700 Subject: [PATCH 14/16] GRPC Server Support - Deprecates old json-rpc system - Add GRPC daemon over uds --- .github/workflows/build-apple.yml | 9 +- .github/workflows/build-rust.yml | 7 +- .gitignore | 5 + .vscode/settings.json | 9 +- .../NetworkExtension/libburrow/build-rust.sh | 2 + Cargo.lock | 341 +++++++++++++++++- Dockerfile | 2 +- Makefile | 6 + burrow/Cargo.toml | 18 +- burrow/build.rs | 4 + burrow/burrow.db | Bin 20480 -> 0 bytes burrow/src/auth/server/db.rs | 2 + burrow/src/daemon/instance.rs | 300 ++++++++++----- burrow/src/daemon/mod.rs | 72 ++-- burrow/src/daemon/net/mod.rs | 9 +- burrow/src/daemon/net/unix.rs | 4 +- burrow/src/daemon/rpc/client.rs | 31 ++ burrow/src/daemon/rpc/grpc_defs.rs | 5 + burrow/src/daemon/rpc/mod.rs | 3 + burrow/src/database.rs | 109 +++++- burrow/src/main.rs | 156 +++++++- burrow/src/wireguard/config.rs | 94 ++++- burrow/src/wireguard/iface.rs | 14 +- burrow/src/wireguard/inifield.rs | 81 +++++ burrow/src/wireguard/mod.rs | 1 + ...guard__config__tests__tst_config_toml.snap | 16 + burrow/tmp/conrd.conf | 8 + proto/burrow.proto | 2 +- 28 files changed, 1110 insertions(+), 200 deletions(-) create mode 100644 burrow/build.rs delete mode 100644 burrow/burrow.db create mode 100644 burrow/src/daemon/rpc/client.rs create mode 100644 burrow/src/daemon/rpc/grpc_defs.rs create mode 100644 burrow/src/wireguard/inifield.rs create mode 100644 burrow/src/wireguard/snapshots/burrow__wireguard__config__tests__tst_config_toml.snap create mode 100644 burrow/tmp/conrd.conf diff --git a/.github/workflows/build-apple.yml b/.github/workflows/build-apple.yml index 84cc03a..b628001 100644 --- a/.github/workflows/build-apple.yml +++ b/.github/workflows/build-apple.yml @@ -1,7 +1,7 @@ name: Build Apple Apps on: push: - branches: + branches: - main pull_request: branches: @@ -39,6 +39,7 @@ jobs: - aarch64-apple-darwin env: DEVELOPER_DIR: /Applications/Xcode_16.0.app/Contents/Developer + PROTOC_VERSION: 3.25.1 steps: - name: Checkout uses: actions/checkout@v3 @@ -54,6 +55,10 @@ jobs: uses: dtolnay/rust-toolchain@stable with: targets: ${{ join(matrix.rust-targets, ', ') }} + - name: Install protoc + uses: taiki-e/install-action@v2 + with: + tool: protoc@${{ env.PROTOC_VERSION }} - name: Build id: build uses: ./.github/actions/build-for-testing @@ -82,4 +87,4 @@ jobs: destination: ${{ matrix.destination }} test-plan: ${{ matrix.xcode-ui-test }} artifact-prefix: ui-tests-${{ matrix.sdk-name }} - check-name: Xcode UI Tests (${{ matrix.platform }}) + check-name: Xcode UI Tests (${{ matrix.platform }}) \ No newline at end of file diff --git a/.github/workflows/build-rust.yml b/.github/workflows/build-rust.yml index 84ac9d8..95fc628 100644 --- a/.github/workflows/build-rust.yml +++ b/.github/workflows/build-rust.yml @@ -48,6 +48,7 @@ jobs: CARGO_INCREMENTAL: 0 CARGO_TARGET_AARCH64_UNKNOWN_LINUX_GNU_LINKER: aarch64-linux-gnu-gcc RUST_BACKTRACE: short + PROTOC_VERSION: 3.25.1 steps: - name: Checkout uses: actions/checkout@v3 @@ -64,6 +65,10 @@ jobs: if: matrix.os == 'windows-2022' shell: bash run: echo "C:\Program Files (x86)\Microsoft Visual Studio\2019\Enterprise\VC\Tools\Llvm\x64\bin" >> $GITHUB_PATH + - name: Install protoc + uses: taiki-e/install-action@v2 + with: + tool: protoc@${{ env.PROTOC_VERSION }} - name: Install Rust uses: dtolnay/rust-toolchain@stable with: @@ -77,4 +82,4 @@ jobs: run: cargo build --verbose --workspace --all-features --target ${{ join(matrix.targets, ' --target ') }} --target ${{ join(matrix.test-targets, ' --target ') }} - name: Test shell: bash - run: cargo test --verbose --workspace --all-features --target ${{ join(matrix.test-targets, ' --target ') }} + run: cargo test --verbose --workspace --all-features --target ${{ join(matrix.test-targets, ' --target ') }} \ No newline at end of file diff --git a/.gitignore b/.gitignore index 96b2507..997d4d5 100644 --- a/.gitignore +++ b/.gitignore @@ -7,3 +7,8 @@ target/ .DS_STORE .idea/ + +tmp/ + +*.db +*.sock \ No newline at end of file diff --git a/.vscode/settings.json b/.vscode/settings.json index a760137..eb85504 100644 --- a/.vscode/settings.json +++ b/.vscode/settings.json @@ -15,5 +15,12 @@ "rust-analyzer.inlayHints.typeHints.enable": false, "rust-analyzer.linkedProjects": [ "./burrow/Cargo.toml" - ] + ], + "[yaml]": { + "editor.insertSpaces": true, + "editor.tabSize": 2, + "editor.autoIndent": "advanced", + "diffEditor.ignoreTrimWhitespace": false, + "editor.formatOnSave": false + } } diff --git a/Apple/NetworkExtension/libburrow/build-rust.sh b/Apple/NetworkExtension/libburrow/build-rust.sh index e7204a5..00c3652 100755 --- a/Apple/NetworkExtension/libburrow/build-rust.sh +++ b/Apple/NetworkExtension/libburrow/build-rust.sh @@ -68,6 +68,8 @@ else CARGO_PATH="$(dirname $(readlink -f $(which cargo))):/usr/bin" fi +CARGO_PATH="$(dirname $(readlink -f $(which protoc))):$CARGO_PATH" + # Run cargo without the various environment variables set by Xcode. # Those variables can confuse cargo and the build scripts it runs. env -i PATH="$CARGO_PATH" CARGO_TARGET_DIR="${CONFIGURATION_TEMP_DIR}/target" IPHONEOS_DEPLOYMENT_TARGET="$IPHONEOS_DEPLOYMENT_TARGET" MACOSX_DEPLOYMENT_TARGET="$MACOSX_DEPLOYMENT_TARGET" cargo build "${CARGO_ARGS[@]}" diff --git a/Cargo.lock b/Cargo.lock index 5ef886c..309fc08 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -132,17 +132,38 @@ dependencies = [ "pin-project-lite", ] +[[package]] +name = "async-stream" +version = "0.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "22068c0c19514942eefcfd4daf8976ef1aad84e61539f95cd200c35202f80af5" +dependencies = [ + "async-stream-impl 0.2.1", + "futures-core", +] + [[package]] name = "async-stream" version = "0.3.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "cd56dd203fef61ac097dd65721a419ddccb106b2d2b70ba60a6b529f03961a51" dependencies = [ - "async-stream-impl", + "async-stream-impl 0.3.5", "futures-core", "pin-project-lite", ] +[[package]] +name = "async-stream-impl" +version = "0.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "25f9db3b38af870bf7e5cc649167533b493928e50744e2c30ae350230b414670" +dependencies = [ + "proc-macro2", + "quote", + "syn 1.0.109", +] + [[package]] name = "async-stream-impl" version = "0.3.5" @@ -165,6 +186,12 @@ dependencies = [ "syn 2.0.48", ] +[[package]] +name = "atomic-waker" +version = "1.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1505bd5d3d116872e7271a6d4e16d81d0c8570876c8de68093a09ac269d8aac0" + [[package]] name = "autocfg" version = "1.1.0" @@ -392,6 +419,8 @@ dependencies = [ "aead", "anyhow", "async-channel", + "async-stream 0.2.1", + "async-stream 0.2.1", "axum 0.7.5", "base64 0.21.7", "blake2", @@ -404,6 +433,7 @@ dependencies = [ "fehler", "futures", "hmac", + "hyper-util", "insta", "ip_network", "ip_network_table", @@ -412,15 +442,24 @@ dependencies = [ "nix 0.27.1", "once_cell", "parking_lot", + "prost 0.13.1", + "prost-types 0.13.1", + "prost 0.13.2", + "prost-types 0.13.2", "rand", "rand_core", "reqwest 0.12.5", "ring", "rusqlite", + "rust-ini", "schemars", "serde", "serde_json", "tokio", + "tokio-stream", + "tonic 0.12.2", + "tonic-build", + "tower", "tracing", "tracing-journald", "tracing-log 0.1.4", @@ -619,9 +658,9 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "fd326812b3fd01da5bb1af7d340d0d555fd3d4b641e7f1dfcf5962a902952787" dependencies = [ "futures-core", - "prost", - "prost-types", - "tonic", + "prost 0.12.3", + "prost-types 0.12.3", + "tonic 0.10.2", "tracing-core", ] @@ -637,18 +676,38 @@ dependencies = [ "futures-task", "hdrhistogram", "humantime", - "prost-types", + "prost-types 0.12.3", "serde", "serde_json", "thread_local", "tokio", "tokio-stream", - "tonic", + "tonic 0.10.2", "tracing", "tracing-core", "tracing-subscriber", ] +[[package]] +name = "const-random" +version = "0.1.18" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "87e00182fe74b066627d63b85fd550ac2998d4b0bd86bfed477a0ae4c7c71359" +dependencies = [ + "const-random-macro", +] + +[[package]] +name = "const-random-macro" +version = "0.1.16" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f9d839f2a20b0aee515dc581a6172f2321f96cab76c1a38a4c584a194955390e" +dependencies = [ + "getrandom", + "once_cell", + "tiny-keccak", +] + [[package]] name = "constant_time_eq" version = "0.1.5" @@ -704,6 +763,12 @@ version = "0.8.19" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "248e3bacc7dc6baa3b21e405ee045c3047101a49145e7e9eca583ab4c2ca5345" +[[package]] +name = "crunchy" +version = "0.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7a81dae078cea95a014a339291cec439d2f232ebe854a9d672b796c6afafa9b7" + [[package]] name = "crypto-common" version = "0.1.6" @@ -762,6 +827,15 @@ dependencies = [ "subtle", ] +[[package]] +name = "dlv-list" +version = "0.5.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "442039f5147480ba31067cb00ada1adae6892028e40e45fc5de7b7df6dcc1b5f" +dependencies = [ + "const-random", +] + [[package]] name = "dotenv" version = "0.15.0" @@ -876,6 +950,12 @@ version = "0.2.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "27573eac26f4dd11e2b1916c3fe1baa56407c83c71a773a8ba17ec0bca03b6b7" +[[package]] +name = "fixedbitset" +version = "0.4.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0ce7134b9999ecaf8bcd65542e436736ef32ddca1b3e06094cb6ec5755203b80" + [[package]] name = "flate2" version = "1.0.28" @@ -1057,6 +1137,25 @@ dependencies = [ "tracing", ] +[[package]] +name = "h2" +version = "0.4.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "524e8ac6999421f49a846c2d4411f337e53497d8ec55d67753beffa43c5d9205" +dependencies = [ + "atomic-waker", + "bytes", + "fnv", + "futures-core", + "futures-sink", + "http 1.1.0", + "indexmap 2.1.0", + "slab", + "tokio", + "tokio-util", + "tracing", +] + [[package]] name = "hashbrown" version = "0.12.3" @@ -1215,7 +1314,7 @@ dependencies = [ "futures-channel", "futures-core", "futures-util", - "h2", + "h2 0.3.24", "http 0.2.11", "http-body 0.4.6", "httparse", @@ -1238,6 +1337,7 @@ dependencies = [ "bytes", "futures-channel", "futures-util", + "h2 0.4.6", "http 1.1.0", "http-body 1.0.0", "httparse", @@ -1279,6 +1379,19 @@ dependencies = [ "tokio-io-timeout", ] +[[package]] +name = "hyper-timeout" +version = "0.5.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3203a961e5c83b6f5498933e78b6b263e208c197b63e9c6c53cc82ffd3f63793" +dependencies = [ + "hyper 1.4.0", + "hyper-util", + "pin-project-lite", + "tokio", + "tower-service", +] + [[package]] name = "hyper-tls" version = "0.5.0" @@ -1615,6 +1728,12 @@ dependencies = [ "windows-sys 0.48.0", ] +[[package]] +name = "multimap" +version = "0.10.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "defc4c55412d89136f966bbb339008b474350e5e6e78d2714439c386b3137a03" + [[package]] name = "native-tls" version = "0.2.11" @@ -1762,6 +1881,16 @@ dependencies = [ "vcpkg", ] +[[package]] +name = "ordered-multimap" +version = "0.7.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "49203cdcae0030493bad186b28da2fa25645fa276a51b6fec8010d281e02ef79" +dependencies = [ + "dlv-list", + "hashbrown 0.14.3", +] + [[package]] name = "overload" version = "0.1.1" @@ -1832,6 +1961,16 @@ version = "2.3.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e3148f5046208a5d56bcfc03053e3ca6334e51da8dfb19b6cdc8b306fae3283e" +[[package]] +name = "petgraph" +version = "0.6.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b4c5cc86750666a3ed20bdaf5ca2a0344f9c67674cae0515bec2da16fbaa47db" +dependencies = [ + "fixedbitset", + "indexmap 2.1.0", +] + [[package]] name = "pin-project" version = "1.1.4" @@ -1925,7 +2064,38 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "146c289cda302b98a28d40c8b3b90498d6e526dd24ac2ecea73e4e491685b94a" dependencies = [ "bytes", - "prost-derive", + "prost-derive 0.12.3", +] + +[[package]] +name = "prost" +version = "0.13.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3b2ecbe40f08db5c006b5764a2645f7f3f141ce756412ac9e1dd6087e6d32995" +dependencies = [ + "bytes", + "prost-derive 0.13.2", +] + +[[package]] +name = "prost-build" +version = "0.13.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f8650aabb6c35b860610e9cff5dc1af886c9e25073b7b1712a68972af4281302" +dependencies = [ + "bytes", + "heck", + "itertools", + "log", + "multimap", + "once_cell", + "petgraph", + "prettyplease", + "prost 0.13.2", + "prost-types 0.13.2", + "regex", + "syn 2.0.48", + "tempfile", ] [[package]] @@ -1941,13 +2111,35 @@ dependencies = [ "syn 2.0.48", ] +[[package]] +name = "prost-derive" +version = "0.13.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "acf0c195eebb4af52c752bec4f52f645da98b6e92077a04110c7f349477ae5ac" +dependencies = [ + "anyhow", + "itertools", + "proc-macro2", + "quote", + "syn 2.0.48", +] + [[package]] name = "prost-types" version = "0.12.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "193898f59edcf43c26227dcd4c8427f00d99d61e95dcde58dabd49fa291d470e" dependencies = [ - "prost", + "prost 0.12.3", +] + +[[package]] +name = "prost-types" +version = "0.13.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "60caa6738c7369b940c3d49246a8d1749323674c65cb13010134f5c9bad5b519" +dependencies = [ + "prost 0.13.2", ] [[package]] @@ -2100,7 +2292,7 @@ dependencies = [ "encoding_rs", "futures-core", "futures-util", - "h2", + "h2 0.3.24", "http 0.2.11", "http-body 0.4.6", "hyper 0.14.28", @@ -2197,6 +2389,17 @@ dependencies = [ "smallvec", ] +[[package]] +name = "rust-ini" +version = "0.21.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0d625ed57d8f49af6cfa514c42e1a71fadcff60eb0b1c517ff82fe41aa025b41" +dependencies = [ + "cfg-if", + "ordered-multimap", + "trim-in-place", +] + [[package]] name = "rustc-demangle" version = "0.1.23" @@ -2404,6 +2607,15 @@ dependencies = [ "serde", ] +[[package]] +name = "serde_spanned" +version = "0.6.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "79e674e01f999af37c49f70a6ede167a8a60b2503e56c5599532a65baa5969a0" +dependencies = [ + "serde", +] + [[package]] name = "serde_urlencoded" version = "0.7.1" @@ -2654,6 +2866,15 @@ version = "0.1.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ef927ca75afb808a4d64dd374f00a2adf8d0fcff8e7b184af886c3c87ec4a3f3" +[[package]] +name = "tiny-keccak" +version = "2.0.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2c9d3793400a45f954c52e73d068316d76b6f4e36977e3fcebb13a2721e80237" +dependencies = [ + "crunchy", +] + [[package]] name = "tinyvec" version = "1.6.0" @@ -2755,25 +2976,59 @@ dependencies = [ "tracing", ] +[[package]] +name = "toml" +version = "0.8.15" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ac2caab0bf757388c6c0ae23b3293fdb463fee59434529014f85e3263b995c28" +dependencies = [ + "serde", + "serde_spanned", + "toml_datetime", + "toml_edit", +] + +[[package]] +name = "toml_datetime" +version = "0.6.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4badfd56924ae69bcc9039335b2e017639ce3f9b001c393c1b2d1ef846ce2cbf" +dependencies = [ + "serde", +] + +[[package]] +name = "toml_edit" +version = "0.22.16" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "278f3d518e152219c994ce877758516bca5e118eaed6996192a774fb9fbf0788" +dependencies = [ + "indexmap 2.1.0", + "serde", + "serde_spanned", + "toml_datetime", + "winnow", +] + [[package]] name = "tonic" version = "0.10.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d560933a0de61cf715926b9cac824d4c883c2c43142f787595e48280c40a1d0e" dependencies = [ - "async-stream", + "async-stream 0.3.5", "async-trait", "axum 0.6.20", "base64 0.21.7", "bytes", - "h2", + "h2 0.3.24", "http 0.2.11", "http-body 0.4.6", "hyper 0.14.28", - "hyper-timeout", + "hyper-timeout 0.4.1", "percent-encoding", "pin-project", - "prost", + "prost 0.12.3", "tokio", "tokio-stream", "tower", @@ -2782,6 +3037,49 @@ dependencies = [ "tracing", ] +[[package]] +name = "tonic" +version = "0.12.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c6f6ba989e4b2c58ae83d862d3a3e27690b6e3ae630d0deb59f3697f32aa88ad" +dependencies = [ + "async-stream 0.3.5", + "async-trait", + "axum 0.7.5", + "base64 0.22.1", + "bytes", + "h2 0.4.6", + "http 1.1.0", + "http-body 1.0.0", + "http-body-util", + "hyper 1.4.0", + "hyper-timeout 0.5.1", + "hyper-util", + "percent-encoding", + "pin-project", + "prost 0.13.2", + "socket2", + "tokio", + "tokio-stream", + "tower", + "tower-layer", + "tower-service", + "tracing", +] + +[[package]] +name = "tonic-build" +version = "0.12.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fe4ee8877250136bd7e3d2331632810a4df4ea5e004656990d8d66d2f5ee8a67" +dependencies = [ + "prettyplease", + "proc-macro2", + "prost-build", + "quote", + "syn 2.0.48", +] + [[package]] name = "tower" version = "0.4.13" @@ -2913,6 +3211,12 @@ dependencies = [ "tracing-log 0.2.0", ] +[[package]] +name = "trim-in-place" +version = "0.1.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "343e926fc669bc8cde4fa3129ab681c63671bae288b1f1081ceee6d9d37904fc" + [[package]] name = "try-lock" version = "0.2.5" @@ -3320,6 +3624,15 @@ version = "0.52.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "dff9641d1cd4be8d1a070daf9e3773c5f67e78b4d9d42263020c057706765c04" +[[package]] +name = "winnow" +version = "0.6.15" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "557404e450152cd6795bb558bca69e43c585055f4606e3bcae5894fc6dac9ba0" +dependencies = [ + "memchr", +] + [[package]] name = "winreg" version = "0.50.0" diff --git a/Dockerfile b/Dockerfile index 8e17812..404179b 100644 --- a/Dockerfile +++ b/Dockerfile @@ -12,7 +12,7 @@ RUN set -eux && \ curl --proto '=https' --tlsv1.2 -sSf https://apt.llvm.org/llvm-snapshot.gpg.key | gpg --dearmor --output $KEYRINGS/llvm.gpg && \ echo "deb [signed-by=$KEYRINGS/llvm.gpg] http://apt.llvm.org/bookworm/ llvm-toolchain-bookworm-$LLVM_VERSION main" > /etc/apt/sources.list.d/llvm.list && \ apt-get update && \ - apt-get install --no-install-recommends -y clang-$LLVM_VERSION llvm-$LLVM_VERSION lld-$LLVM_VERSION build-essential sqlite3 libsqlite3-dev musl musl-tools musl-dev && \ + apt-get install --no-install-recommends -y clang-$LLVM_VERSION llvm-$LLVM_VERSION lld-$LLVM_VERSION build-essential sqlite3 libsqlite3-dev musl musl-tools musl-dev protobuf-compiler libprotobuf-dev && \ ln -s clang-$LLVM_VERSION /usr/bin/clang && \ ln -s clang /usr/bin/clang++ && \ ln -s lld-$LLVM_VERSION /usr/bin/ld.lld && \ diff --git a/Makefile b/Makefile index d0c9bd9..6563ab1 100644 --- a/Makefile +++ b/Makefile @@ -20,6 +20,12 @@ start: stop: @$(cargo_norm) stop +status: + @$(cargo_norm) server-status + +tunnel-config: + @$(cargo_norm) tunnel-config + test-dns: @sudo route delete 8.8.8.8 @sudo route add 8.8.8.8 -interface $(tun) diff --git a/burrow/Cargo.toml b/burrow/Cargo.toml index 0fb63a5..d5e56c1 100644 --- a/burrow/Cargo.toml +++ b/burrow/Cargo.toml @@ -19,6 +19,7 @@ tokio = { version = "1.37", features = [ "signal", "time", "tracing", + "fs", ] } tun = { version = "0.1", path = "../tun", features = ["serde", "tokio"] } clap = { version = "4.4", features = ["derive"] } @@ -56,8 +57,17 @@ reqwest = { version = "0.12", default-features = false, features = [ "json", "rustls-tls", ] } -rusqlite = "0.31.0" +rusqlite = { version = "0.31.0", features = ["blob"] } dotenv = "0.15.0" +tonic = "0.12.0" +prost = "0.13.1" +prost-types = "0.13.1" +tokio-stream = "0.1" +async-stream = "0.2" +tower = "0.4.13" +hyper-util = "0.1.6" +toml = "0.8.15" +rust-ini = "0.21.0" [target.'cfg(target_os = "linux")'.dependencies] caps = "0.5" @@ -66,7 +76,7 @@ tracing-journald = "0.3" [target.'cfg(target_vendor = "apple")'.dependencies] nix = { version = "0.27" } -rusqlite = { version = "0.31.0", features = ["bundled"] } +rusqlite = { version = "0.31.0", features = ["bundled", "blob"] } [dev-dependencies] insta = { version = "1.32", features = ["yaml"] } @@ -83,3 +93,7 @@ pre_uninstall_script = "../package/rpm/pre_uninstall" [features] tokio-console = ["dep:console-subscriber"] bundled = ["rusqlite/bundled"] + + +[build-dependencies] +tonic-build = "0.12.0" diff --git a/burrow/build.rs b/burrow/build.rs new file mode 100644 index 0000000..8eea5dc --- /dev/null +++ b/burrow/build.rs @@ -0,0 +1,4 @@ +fn main() -> Result<(), Box> { + tonic_build::compile_protos("../proto/burrow.proto")?; + Ok(()) +} diff --git a/burrow/burrow.db b/burrow/burrow.db deleted file mode 100644 index c5b6e2c614ecb4db4c264f50691b6f2cea99772a..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 20480 zcmWFz^vNtqRY=P(%1ta$FlG>7U}R))P*7lCU=U|uU|?lH0A>aT1{MUDff0#~iz&{a zSJuG`(#R{q!1sc08t)Wd5nPH##YaP6Gz3ONU^E0qLtr!nMnhmU1V%$(Gz3ONfZicc z$HFcyEzQ^%T#}fSlbV-WQl4Lw4W(F}gIpa$TopnboqSvspn?h-TnbQ-nOBlpl$MyB z8lRb>;OQ5l5ajCS8szHd>>8|4o*oaE*2qlJRPgsx2n}!n8RzU6?Cj{`3N}Wwv7Q<1 zfaXxJ1Ip9m3sO^ypcD&=1E7LbbAS%m1t7nq=A{(mXXceCgt$h8DERq@DENi?_#os9 zN|SOjljE~fD{-kv%*n|wPfdx>EGWjMq@XCZI3uwrH3e=C*nZ6bCN^HWN82kl9QqrXkB9 z2QfHiUEN)S6as=geI0`$6}(*|6&yoD{5}1ggIs-G{X!4{1#$w|{|KR+%;J*Ny!e9r zq7qOV0hxr5%q=O!6f7vpEK4j&g$EOs2uVyyDM~HI8Pq9xXi|`n2KCLkcwHFyck!3- z>+!wdTf`T`C&qh$w~N<>-uZ6SzR?gE4S~@R7!85Z5Eu=C(GVC7fzc2c4S~@R80;b7 z!o|VBz|4@U&dYEr$KN#|EG0iT)hDDP#M7y)%s3>n*efVK)xe{`($6khIH_U^2USdAr-~_TR567W$rN|LLQhA3=b(zL9R1|XAY71JH1mFA{7sYRJyiIoQ0`5rzQLB0iH+K#3bj)4Xl&R*Ju=HcZQ zhK~MaAtqSUX|Z`ug??_jc2R1Wt8borUSVowq<>&`m5YU0o{@HXWL|}#uVrO=rh!Ga zZ6hlS#2qXH?G9#$JD3OB9ZV2+Fb%LfSQyzjLFL%MIs?@IXAq!ac|B_MXb6mkz-S1J ihQMeDjE2By2#kinXb6mkz-S1JhQMeDjE2B~hX4R^(?&G_ diff --git a/burrow/src/auth/server/db.rs b/burrow/src/auth/server/db.rs index b74f7ce..995e64b 100644 --- a/burrow/src/auth/server/db.rs +++ b/burrow/src/auth/server/db.rs @@ -1,5 +1,7 @@ use anyhow::Result; +use crate::daemon::rpc::grpc_defs::{Network, NetworkType}; + pub static PATH: &str = "./server.sqlite3"; pub fn init_db() -> Result<()> { diff --git a/burrow/src/daemon/instance.rs b/burrow/src/daemon/instance.rs index bc506bd..ce96fa5 100644 --- a/burrow/src/daemon/instance.rs +++ b/burrow/src/daemon/instance.rs @@ -1,13 +1,30 @@ use std::{ + ops::Deref, path::{Path, PathBuf}, sync::Arc, + time::Duration, }; use anyhow::Result; -use tokio::{sync::RwLock, task::JoinHandle}; +use rusqlite::Connection; +use tokio::sync::{mpsc, watch, Notify, RwLock}; +use tokio_stream::wrappers::ReceiverStream; +use tonic::{Request, Response, Status as RspStatus}; use tracing::{debug, info, warn}; -use tun::tokio::TunInterface; +use tun::{tokio::TunInterface, TunOptions}; +use super::rpc::grpc_defs::{ + networks_server::Networks, + tunnel_server::Tunnel, + Empty, + Network, + NetworkDeleteRequest, + NetworkListResponse, + NetworkReorderRequest, + State as RPCTunnelState, + TunnelConfigurationResponse, + TunnelStatusResponse, +}; use crate::{ daemon::rpc::{ DaemonCommand, @@ -17,114 +34,223 @@ use crate::{ ServerConfig, ServerInfo, }, - database::{get_connection, load_interface}, + database::{ + add_network, + delete_network, + get_connection, + list_networks, + load_interface, + reorder_network, + }, wireguard::{Config, Interface}, }; +#[derive(Debug, Clone)] enum RunState { - Running(JoinHandle>), + Running, Idle, } -pub struct DaemonInstance { - rx: async_channel::Receiver, - sx: async_channel::Sender, - subx: async_channel::Sender, +impl RunState { + pub fn to_rpc(&self) -> RPCTunnelState { + match self { + RunState::Running => RPCTunnelState::Running, + RunState::Idle => RPCTunnelState::Stopped, + } + } +} + +#[derive(Clone)] +pub struct DaemonRPCServer { tun_interface: Arc>>, wg_interface: Arc>, config: Arc>, db_path: Option, - wg_state: RunState, + wg_state_chan: (watch::Sender, watch::Receiver), + network_update_chan: (watch::Sender<()>, watch::Receiver<()>), } -impl DaemonInstance { +impl DaemonRPCServer { pub fn new( - rx: async_channel::Receiver, - sx: async_channel::Sender, - subx: async_channel::Sender, wg_interface: Arc>, config: Arc>, db_path: Option<&Path>, - ) -> Self { - Self { - rx, - sx, - subx, - wg_interface, + ) -> Result { + Ok(Self { tun_interface: Arc::new(RwLock::new(None)), + wg_interface, config, db_path: db_path.map(|p| p.to_owned()), - wg_state: RunState::Idle, - } + wg_state_chan: watch::channel(RunState::Idle), + network_update_chan: watch::channel(()), + }) } - async fn proc_command(&mut self, command: DaemonCommand) -> Result { - info!("Daemon got command: {:?}", command); - match command { - DaemonCommand::Start(st) => { - match self.wg_state { - RunState::Running(_) => { - warn!("Got start, but tun interface already up."); - } - RunState::Idle => { - let tun_if = st.tun.open()?; - debug!("Setting tun on wg_interface"); - self.wg_interface.read().await.set_tun(tun_if).await; - debug!("tun set on wg_interface"); - - debug!("Setting tun_interface"); - self.tun_interface = self.wg_interface.read().await.get_tun(); - debug!("tun_interface set: {:?}", self.tun_interface); - - debug!("Cloning wg_interface"); - let tmp_wg = self.wg_interface.clone(); - let run_task = tokio::spawn(async move { - let twlock = tmp_wg.read().await; - twlock.run().await - }); - self.wg_state = RunState::Running(run_task); - info!("Daemon started tun interface"); - } - } - Ok(DaemonResponseData::None) - } - DaemonCommand::ServerInfo => match &self.tun_interface.read().await.as_ref() { - None => Ok(DaemonResponseData::None), - Some(ti) => { - info!("{:?}", ti); - Ok(DaemonResponseData::ServerInfo(ServerInfo::try_from( - ti.inner.get_ref(), - )?)) - } - }, - DaemonCommand::Stop => { - self.wg_interface.read().await.remove_tun().await; - self.wg_state = RunState::Idle; - Ok(DaemonResponseData::None) - } - DaemonCommand::ServerConfig => { - Ok(DaemonResponseData::ServerConfig(ServerConfig::default())) - } - DaemonCommand::ReloadConfig(interface_id) => { - let conn = get_connection(self.db_path.as_deref())?; - let cfig = load_interface(&conn, &interface_id)?; - *self.config.write().await = cfig; - self.subx - .send(DaemonNotification::ConfigChange(ServerConfig::try_from( - &self.config.read().await.to_owned(), - )?)) - .await?; - Ok(DaemonResponseData::None) - } - } + pub fn get_connection(&self) -> Result { + get_connection(self.db_path.as_deref()).map_err(proc_err) } - pub async fn run(&mut self) -> Result<()> { - while let Ok(command) = self.rx.recv().await { - let response = self.proc_command(command).await; - info!("Daemon response: {:?}", response); - self.sx.send(DaemonResponse::new(response)).await?; - } - Ok(()) + async fn set_wg_state(&self, state: RunState) -> Result<(), RspStatus> { + self.wg_state_chan.0.send(state).map_err(proc_err) + } + + async fn get_wg_state(&self) -> RunState { + self.wg_state_chan.1.borrow().to_owned() + } + + async fn notify_network_update(&self) -> Result<(), RspStatus> { + self.network_update_chan.0.send(()).map_err(proc_err) + } +} + +#[tonic::async_trait] +impl Tunnel for DaemonRPCServer { + type TunnelConfigurationStream = ReceiverStream>; + type TunnelStatusStream = ReceiverStream>; + + async fn tunnel_configuration( + &self, + _request: Request, + ) -> Result, RspStatus> { + let (tx, rx) = mpsc::channel(10); + tokio::spawn(async move { + let serv_config = ServerConfig::default(); + tx.send(Ok(TunnelConfigurationResponse { + mtu: serv_config.mtu.unwrap_or(1000), + addresses: serv_config.address, + })) + .await + }); + Ok(Response::new(ReceiverStream::new(rx))) + } + + async fn tunnel_start(&self, _request: Request) -> Result, RspStatus> { + let wg_state = self.get_wg_state().await; + match wg_state { + RunState::Idle => { + let tun_if = TunOptions::new().open()?; + debug!("Setting tun on wg_interface"); + self.tun_interface.write().await.replace(tun_if); + self.wg_interface + .write() + .await + .set_tun_ref(self.tun_interface.clone()) + .await; + debug!("tun set on wg_interface"); + + debug!("Setting tun_interface"); + debug!("tun_interface set: {:?}", self.tun_interface); + + debug!("Cloning wg_interface"); + let tmp_wg = self.wg_interface.clone(); + let run_task = tokio::spawn(async move { + let twlock = tmp_wg.read().await; + twlock.run().await + }); + self.set_wg_state(RunState::Running).await?; + } + + RunState::Running => { + warn!("Got start, but tun interface already up."); + } + } + + return Ok(Response::new(Empty {})); + } + + async fn tunnel_stop(&self, _request: Request) -> Result, RspStatus> { + self.wg_interface.write().await.remove_tun().await; + self.set_wg_state(RunState::Idle).await?; + return Ok(Response::new(Empty {})); + } + + async fn tunnel_status( + &self, + _request: Request, + ) -> Result, RspStatus> { + let (tx, rx) = mpsc::channel(10); + let mut state_rx = self.wg_state_chan.1.clone(); + tokio::spawn(async move { + let cur = state_rx.borrow_and_update().to_owned(); + tx.send(Ok(status_rsp(cur))).await; + loop { + state_rx.changed().await.unwrap(); + let cur = state_rx.borrow().to_owned(); + let res = tx.send(Ok(status_rsp(cur))).await; + if res.is_err() { + eprintln!("Tunnel status channel closed"); + break; + } + } + }); + Ok(Response::new(ReceiverStream::new(rx))) + } +} + +#[tonic::async_trait] +impl Networks for DaemonRPCServer { + type NetworkListStream = ReceiverStream>; + + async fn network_add(&self, request: Request) -> Result, RspStatus> { + let conn = self.get_connection()?; + let network = request.into_inner(); + add_network(&conn, &network).map_err(proc_err)?; + self.notify_network_update().await?; + Ok(Response::new(Empty {})) + } + + async fn network_list( + &self, + _request: Request, + ) -> Result, RspStatus> { + debug!("Mock network_list called"); + let (tx, rx) = mpsc::channel(10); + let conn = self.get_connection()?; + let mut sub = self.network_update_chan.1.clone(); + tokio::spawn(async move { + loop { + let networks = list_networks(&conn) + .map(|res| NetworkListResponse { network: res }) + .map_err(proc_err); + let res = tx.send(networks).await; + if res.is_err() { + eprintln!("Network list channel closed"); + break; + } + sub.changed().await.unwrap(); + } + }); + Ok(Response::new(ReceiverStream::new(rx))) + } + + async fn network_reorder( + &self, + request: Request, + ) -> Result, RspStatus> { + let conn = self.get_connection()?; + reorder_network(&conn, request.into_inner()).map_err(proc_err)?; + self.notify_network_update().await?; + Ok(Response::new(Empty {})) + } + + async fn network_delete( + &self, + request: Request, + ) -> Result, RspStatus> { + let conn = self.get_connection()?; + delete_network(&conn, request.into_inner()).map_err(proc_err)?; + self.notify_network_update().await?; + Ok(Response::new(Empty {})) + } +} + +fn proc_err(err: impl ToString) -> RspStatus { + RspStatus::internal(err.to_string()) +} + +fn status_rsp(state: RunState) -> TunnelStatusResponse { + TunnelStatusResponse { + state: state.to_rpc().into(), + start: None, // TODO: Add timestamp } } diff --git a/burrow/src/daemon/mod.rs b/burrow/src/daemon/mod.rs index 4469e90..f6b973f 100644 --- a/burrow/src/daemon/mod.rs +++ b/burrow/src/daemon/mod.rs @@ -5,14 +5,20 @@ mod instance; mod net; pub mod rpc; -use anyhow::Result; -use instance::DaemonInstance; -pub use net::{DaemonClient, Listener}; +use anyhow::{Error as AhError, Result}; +use instance::DaemonRPCServer; +pub use net::{get_socket_path, DaemonClient}; pub use rpc::{DaemonCommand, DaemonResponseData, DaemonStartOptions}; -use tokio::sync::{Notify, RwLock}; +use tokio::{ + net::UnixListener, + sync::{Notify, RwLock}, +}; +use tokio_stream::wrappers::UnixListenerStream; +use tonic::transport::Server; use tracing::{error, info}; use crate::{ + daemon::rpc::grpc_defs::{networks_server::NetworksServer, tunnel_server::TunnelServer}, database::{get_connection, load_interface}, wireguard::Interface, }; @@ -22,52 +28,36 @@ pub async fn daemon_main( db_path: Option<&Path>, notify_ready: Option>, ) -> Result<()> { - let (commands_tx, commands_rx) = async_channel::unbounded(); - let (response_tx, response_rx) = async_channel::unbounded(); - let (subscribe_tx, subscribe_rx) = async_channel::unbounded(); - - let listener = if let Some(path) = socket_path { - info!("Creating listener... {:?}", path); - Listener::new_with_path(commands_tx, response_rx, subscribe_rx, path) - } else { - info!("Creating listener..."); - Listener::new(commands_tx, response_rx, subscribe_rx) - }; if let Some(n) = notify_ready { n.notify_one() } - let listener = listener?; let conn = get_connection(db_path)?; let config = load_interface(&conn, "1")?; - let iface: Interface = config.clone().try_into()?; - let mut instance = DaemonInstance::new( - commands_rx, - response_tx, - subscribe_tx, - Arc::new(RwLock::new(iface)), + let burrow_server = DaemonRPCServer::new( + Arc::new(RwLock::new(config.clone().try_into()?)), Arc::new(RwLock::new(config)), - db_path, - ); + db_path.clone(), + )?; + let spp = socket_path.clone(); + let tmp = get_socket_path(); + let sock_path = spp.unwrap_or(Path::new(tmp.as_str())); + if sock_path.exists() { + std::fs::remove_file(sock_path)?; + } + let uds = UnixListener::bind(sock_path)?; + let serve_job = tokio::spawn(async move { + let uds_stream = UnixListenerStream::new(uds); + let _srv = Server::builder() + .add_service(TunnelServer::new(burrow_server.clone())) + .add_service(NetworksServer::new(burrow_server)) + .serve_with_incoming(uds_stream) + .await?; + Ok::<(), AhError>(()) + }); info!("Starting daemon..."); - let main_job = tokio::spawn(async move { - let result = instance.run().await; - if let Err(e) = result.as_ref() { - error!("Instance exited: {}", e); - } - result - }); - - let listener_job = tokio::spawn(async move { - let result = listener.run().await; - if let Err(e) = result.as_ref() { - error!("Listener exited: {}", e); - } - result - }); - - tokio::try_join!(main_job, listener_job) + tokio::try_join!(serve_job) .map(|_| ()) .map_err(|e| e.into()) } diff --git a/burrow/src/daemon/net/mod.rs b/burrow/src/daemon/net/mod.rs index 242f479..eb45335 100644 --- a/burrow/src/daemon/net/mod.rs +++ b/burrow/src/daemon/net/mod.rs @@ -1,18 +1,11 @@ - - - - - #[cfg(target_family = "unix")] mod unix; #[cfg(target_family = "unix")] -pub use unix::{DaemonClient, Listener}; +pub use unix::{get_socket_path, DaemonClient, Listener}; #[cfg(target_os = "windows")] mod windows; #[cfg(target_os = "windows")] pub use windows::{DaemonClient, Listener}; - - diff --git a/burrow/src/daemon/net/unix.rs b/burrow/src/daemon/net/unix.rs index 70c4207..975c470 100644 --- a/burrow/src/daemon/net/unix.rs +++ b/burrow/src/daemon/net/unix.rs @@ -25,7 +25,7 @@ const UNIX_SOCKET_PATH: &str = "/run/burrow.sock"; #[cfg(target_vendor = "apple")] const UNIX_SOCKET_PATH: &str = "burrow.sock"; -fn get_socket_path() -> String { +pub fn get_socket_path() -> String { if std::env::var("BURROW_SOCKET_PATH").is_ok() { return std::env::var("BURROW_SOCKET_PATH").unwrap(); } @@ -36,7 +36,7 @@ pub struct Listener { cmd_tx: async_channel::Sender, rsp_rx: async_channel::Receiver, sub_chan: async_channel::Receiver, - inner: UnixListener, + pub inner: UnixListener, } impl Listener { diff --git a/burrow/src/daemon/rpc/client.rs b/burrow/src/daemon/rpc/client.rs new file mode 100644 index 0000000..862e34c --- /dev/null +++ b/burrow/src/daemon/rpc/client.rs @@ -0,0 +1,31 @@ +use anyhow::Result; +use hyper_util::rt::TokioIo; +use tokio::net::UnixStream; +use tonic::transport::{Endpoint, Uri}; +use tower::service_fn; + +use super::grpc_defs::{networks_client::NetworksClient, tunnel_client::TunnelClient}; +use crate::daemon::get_socket_path; + +pub struct BurrowClient { + pub networks_client: NetworksClient, + pub tunnel_client: TunnelClient, +} + +impl BurrowClient { + #[cfg(any(target_os = "linux", target_vendor = "apple"))] + pub async fn from_uds() -> Result { + let channel = Endpoint::try_from("http://[::]:50051")? // NOTE: this is a hack(?) + .connect_with_connector(service_fn(|_: Uri| async { + let sock_path = get_socket_path(); + Ok::<_, std::io::Error>(TokioIo::new(UnixStream::connect(sock_path).await?)) + })) + .await?; + let nw_client = NetworksClient::new(channel.clone()); + let tun_client = TunnelClient::new(channel.clone()); + Ok(BurrowClient { + networks_client: nw_client, + tunnel_client: tun_client, + }) + } +} diff --git a/burrow/src/daemon/rpc/grpc_defs.rs b/burrow/src/daemon/rpc/grpc_defs.rs new file mode 100644 index 0000000..f3085ee --- /dev/null +++ b/burrow/src/daemon/rpc/grpc_defs.rs @@ -0,0 +1,5 @@ +pub use burrowgrpc::*; + +mod burrowgrpc { + tonic::include_proto!("burrow"); +} diff --git a/burrow/src/daemon/rpc/mod.rs b/burrow/src/daemon/rpc/mod.rs index 4146e71..512662c 100644 --- a/burrow/src/daemon/rpc/mod.rs +++ b/burrow/src/daemon/rpc/mod.rs @@ -1,7 +1,10 @@ +pub mod client; +pub mod grpc_defs; pub mod notification; pub mod request; pub mod response; +pub use client::BurrowClient; pub use notification::DaemonNotification; pub use request::{DaemonCommand, DaemonRequest, DaemonStartOptions}; pub use response::{DaemonResponse, DaemonResponseData, ServerConfig, ServerInfo}; diff --git a/burrow/src/database.rs b/burrow/src/database.rs index 0047b01..9a9aac3 100644 --- a/burrow/src/database.rs +++ b/burrow/src/database.rs @@ -3,7 +3,15 @@ use std::path::Path; use anyhow::Result; use rusqlite::{params, Connection}; -use crate::wireguard::config::{Config, Interface, Peer}; +use crate::{ + daemon::rpc::grpc_defs::{ + Network as RPCNetwork, + NetworkDeleteRequest, + NetworkReorderRequest, + NetworkType, + }, + wireguard::config::{Config, Interface, Peer}, +}; #[cfg(target_vendor = "apple")] const DB_PATH: &str = "burrow.db"; @@ -30,8 +38,20 @@ const CREATE_WG_PEER_TABLE: &str = "CREATE TABLE IF NOT EXISTS wg_peer ( )"; const CREATE_NETWORK_TABLE: &str = "CREATE TABLE IF NOT EXISTS network ( + id INTEGER PRIMARY KEY AUTOINCREMENT, + type TEXT NOT NULL, + payload BLOB, + idx INTEGER, interface_id INT REFERENCES wg_interface(id) ON UPDATE CASCADE -)"; +); +CREATE TRIGGER IF NOT EXISTS increment_network_idx +AFTER INSERT ON network +BEGIN + UPDATE network + SET idx = (SELECT COALESCE(MAX(idx), 0) + 1 FROM network) + WHERE id = NEW.id; +END; +"; pub fn initialize_tables(conn: &Connection) -> Result<()> { conn.execute(CREATE_WG_INTERFACE_TABLE, [])?; @@ -40,20 +60,6 @@ pub fn initialize_tables(conn: &Connection) -> Result<()> { Ok(()) } -fn parse_lst(s: &str) -> Vec { - if s.is_empty() { - return vec![]; - } - s.split(',').map(|s| s.to_string()).collect() -} - -fn to_lst(v: &Vec) -> String { - v.iter() - .map(|s| s.to_string()) - .collect::>() - .join(",") -} - pub fn load_interface(conn: &Connection, interface_id: &str) -> Result { let iface = conn.query_row( "SELECT private_key, dns, address, listen_port, mtu FROM wg_interface WHERE id = ?", @@ -99,7 +105,7 @@ pub fn dump_interface(conn: &Connection, config: &Config) -> Result<()> { cif.private_key, to_lst(&cif.dns), to_lst(&cif.address), - cif.listen_port, + cif.listen_port.unwrap_or(51820), cif.mtu ])?; let interface_id = conn.last_insert_rowid(); @@ -127,10 +133,75 @@ pub fn get_connection(path: Option<&Path>) -> Result { Ok(Connection::open(p)?) } +pub fn add_network(conn: &Connection, network: &RPCNetwork) -> Result<()> { + let mut stmt = conn.prepare("INSERT INTO network (id, type, payload) VALUES (?, ?, ?)")?; + stmt.execute(params![ + network.id, + network.r#type().as_str_name(), + &network.payload + ])?; + if network.r#type() == NetworkType::WireGuard { + let payload_str = String::from_utf8(network.payload.clone())?; + let wg_config = Config::from_content_fmt(&payload_str, "ini")?; + dump_interface(conn, &wg_config)?; + } + Ok(()) +} + +pub fn list_networks(conn: &Connection) -> Result> { + let mut stmt = conn.prepare("SELECT id, type, payload FROM network ORDER BY idx")?; + let networks: Vec = stmt + .query_map([], |row| { + println!("row: {:?}", row); + let network_id: i32 = row.get(0)?; + let network_type: String = row.get(1)?; + let network_type = NetworkType::from_str_name(network_type.as_str()) + .ok_or(rusqlite::Error::InvalidQuery)?; + let payload: Vec = row.get(2)?; + Ok(RPCNetwork { + id: network_id, + r#type: network_type.into(), + payload: payload.into(), + }) + })? + .collect::, rusqlite::Error>>()?; + Ok(networks) +} + +pub fn reorder_network(conn: &Connection, req: NetworkReorderRequest) -> Result<()> { + let mut stmt = conn.prepare("UPDATE network SET idx = ? WHERE id = ?")?; + let res = stmt.execute(params![req.index, req.id])?; + if res == 0 { + return Err(anyhow::anyhow!("No such network exists")); + } + Ok(()) +} + +pub fn delete_network(conn: &Connection, req: NetworkDeleteRequest) -> Result<()> { + let mut stmt = conn.prepare("DELETE FROM network WHERE id = ?")?; + let res = stmt.execute(params![req.id])?; + if res == 0 { + return Err(anyhow::anyhow!("No such network exists")); + } + Ok(()) +} + +fn parse_lst(s: &str) -> Vec { + if s.is_empty() { + return vec![]; + } + s.split(',').map(|s| s.to_string()).collect() +} + +fn to_lst(v: &Vec) -> String { + v.iter() + .map(|s| s.to_string()) + .collect::>() + .join(",") +} + #[cfg(test)] mod tests { - use std::path::Path; - use super::*; #[test] diff --git a/burrow/src/main.rs b/burrow/src/main.rs index ff07d4c..e87b4c9 100644 --- a/burrow/src/main.rs +++ b/burrow/src/main.rs @@ -11,8 +11,7 @@ mod wireguard; mod auth; #[cfg(any(target_os = "linux", target_vendor = "apple"))] -use daemon::{DaemonClient, DaemonCommand, DaemonStartOptions}; -use tun::TunOptions; +use daemon::{DaemonClient, DaemonCommand}; #[cfg(any(target_os = "linux", target_vendor = "apple"))] use crate::daemon::DaemonResponseData; @@ -20,6 +19,9 @@ use crate::daemon::DaemonResponseData; #[cfg(any(target_os = "linux", target_vendor = "apple"))] pub mod database; +#[cfg(any(target_os = "linux", target_vendor = "apple"))] +use crate::daemon::rpc::{grpc_defs::Empty, BurrowClient}; + #[derive(Parser)] #[command(name = "Burrow")] #[command(author = "Hack Club ")] @@ -52,13 +54,24 @@ enum Commands { ReloadConfig(ReloadConfigArgs), /// Authentication server AuthServer, + /// Server Status + ServerStatus, + /// Tunnel Config + TunnelConfig, + /// Add Network + NetworkAdd(NetworkAddArgs), + /// List Networks + NetworkList, + /// Reorder Network + NetworkReorder(NetworkReorderArgs), + /// Delete Network + NetworkDelete(NetworkDeleteArgs), } #[derive(Args)] struct ReloadConfigArgs { #[clap(long, short)] interface_id: String, - } #[derive(Args)] @@ -67,21 +80,132 @@ struct StartArgs {} #[derive(Args)] struct DaemonArgs {} +#[derive(Args)] +struct NetworkAddArgs { + id: i32, + network_type: i32, + payload_path: String, +} + +#[derive(Args)] +struct NetworkReorderArgs { + id: i32, + index: i32, +} + +#[derive(Args)] +struct NetworkDeleteArgs { + id: i32, +} + #[cfg(any(target_os = "linux", target_vendor = "apple"))] async fn try_start() -> Result<()> { - let mut client = DaemonClient::new().await?; - client - .send_command(DaemonCommand::Start(DaemonStartOptions { - tun: TunOptions::new().address(vec!["10.13.13.2", "::2"]), - })) - .await - .map(|_| ()) + let mut client = BurrowClient::from_uds().await?; + let res = client.tunnel_client.tunnel_start(Empty {}).await?; + println!("Got results! {:?}", res); + Ok(()) } #[cfg(any(target_os = "linux", target_vendor = "apple"))] async fn try_stop() -> Result<()> { - let mut client = DaemonClient::new().await?; - client.send_command(DaemonCommand::Stop).await?; + let mut client = BurrowClient::from_uds().await?; + let res = client.tunnel_client.tunnel_stop(Empty {}).await?; + println!("Got results! {:?}", res); + Ok(()) +} + +#[cfg(any(target_os = "linux", target_vendor = "apple"))] +async fn try_serverstatus() -> Result<()> { + let mut client = BurrowClient::from_uds().await?; + let mut res = client + .tunnel_client + .tunnel_status(Empty {}) + .await? + .into_inner(); + if let Some(st) = res.message().await? { + println!("Server Status: {:?}", st); + } else { + println!("Server Status is None"); + } + Ok(()) +} + +#[cfg(any(target_os = "linux", target_vendor = "apple"))] +async fn try_tun_config() -> Result<()> { + let mut client = BurrowClient::from_uds().await?; + let mut res = client + .tunnel_client + .tunnel_configuration(Empty {}) + .await? + .into_inner(); + if let Some(config) = res.message().await? { + println!("Tunnel Config: {:?}", config); + } else { + println!("Tunnel Config is None"); + } + Ok(()) +} + +#[cfg(any(target_os = "linux", target_vendor = "apple"))] +async fn try_network_add(id: i32, network_type: i32, payload_path: &str) -> Result<()> { + use tokio::{fs::File, io::AsyncReadExt}; + + use crate::daemon::rpc::grpc_defs::Network; + + let mut file = File::open(payload_path).await?; + let mut payload = Vec::new(); + file.read_to_end(&mut payload).await?; + + let mut client = BurrowClient::from_uds().await?; + let network = Network { + id, + r#type: network_type, + payload, + }; + let res = client.networks_client.network_add(network).await?; + println!("Network Add Response: {:?}", res); + Ok(()) +} + +#[cfg(any(target_os = "linux", target_vendor = "apple"))] +async fn try_network_list() -> Result<()> { + let mut client = BurrowClient::from_uds().await?; + let mut res = client + .networks_client + .network_list(Empty {}) + .await? + .into_inner(); + while let Some(network_list) = res.message().await? { + println!("Network List: {:?}", network_list); + } + Ok(()) +} + +#[cfg(any(target_os = "linux", target_vendor = "apple"))] +async fn try_network_reorder(id: i32, index: i32) -> Result<()> { + use crate::daemon::rpc::grpc_defs::NetworkReorderRequest; + + let mut client = BurrowClient::from_uds().await?; + let reorder_request = NetworkReorderRequest { id, index }; + let res = client + .networks_client + .network_reorder(reorder_request) + .await?; + println!("Network Reorder Response: {:?}", res); + Ok(()) +} + +#[cfg(any(target_os = "linux", target_vendor = "apple"))] +async fn try_network_delete(id: i32) -> Result<()> { + use crate::daemon::rpc::grpc_defs::NetworkDeleteRequest; + + let mut client = BurrowClient::from_uds().await?; + let delete_request = NetworkDeleteRequest { id }; + let res = client + .networks_client + .network_delete(delete_request) + .await?; + println!("Network Delete Response: {:?}", res); Ok(()) } @@ -153,6 +277,14 @@ async fn main() -> Result<()> { Commands::ServerConfig => try_serverconfig().await?, Commands::ReloadConfig(args) => try_reloadconfig(args.interface_id.clone()).await?, Commands::AuthServer => crate::auth::server::serve().await?, + Commands::ServerStatus => try_serverstatus().await?, + Commands::TunnelConfig => try_tun_config().await?, + Commands::NetworkAdd(args) => { + try_network_add(args.id, args.network_type, &args.payload_path).await? + } + Commands::NetworkList => try_network_list().await?, + Commands::NetworkReorder(args) => try_network_reorder(args.id, args.index).await?, + Commands::NetworkDelete(args) => try_network_delete(args.id).await?, } Ok(()) diff --git a/burrow/src/wireguard/config.rs b/burrow/src/wireguard/config.rs index bd86a9f..5766675 100644 --- a/burrow/src/wireguard/config.rs +++ b/burrow/src/wireguard/config.rs @@ -3,9 +3,12 @@ use std::{net::ToSocketAddrs, str::FromStr}; use anyhow::{anyhow, Error, Result}; use base64::{engine::general_purpose, Engine}; use fehler::throws; +use ini::{Ini, Properties}; use ip_network::IpNetwork; +use serde::{Deserialize, Serialize}; use x25519_dalek::{PublicKey, StaticSecret}; +use super::inifield::IniField; use crate::wireguard::{Interface as WgInterface, Peer as WgPeer}; #[throws] @@ -31,7 +34,7 @@ fn parse_public_key(string: &str) -> PublicKey { /// A raw version of Peer Config that can be used later to reflect configuration files. /// This should be later converted to a `WgPeer`. /// Refers to https://github.com/pirate/wireguard-docs?tab=readme-ov-file#overview -#[derive(Debug, Clone, Eq, PartialEq)] +#[derive(Debug, Clone, Eq, PartialEq, Serialize, Deserialize)] pub struct Peer { pub public_key: String, pub preshared_key: Option, @@ -41,17 +44,18 @@ pub struct Peer { pub name: Option, } -#[derive(Debug, Clone, Eq, PartialEq)] +#[derive(Debug, Clone, Eq, PartialEq, Serialize, Deserialize)] pub struct Interface { pub private_key: String, pub address: Vec, - pub listen_port: u32, + pub listen_port: Option, pub dns: Vec, pub mtu: Option, } -#[derive(Debug, Clone, Eq, PartialEq)] +#[derive(Debug, Clone, Eq, PartialEq, Serialize, Deserialize)] pub struct Config { + #[serde(rename = "Peer")] pub peers: Vec, pub interface: Interface, // Support for multiple interfaces? } @@ -98,7 +102,7 @@ impl Default for Config { interface: Interface { private_key: "OEPVdomeLTxTIBvv3TYsJRge0Hp9NMiY0sIrhT8OWG8=".into(), address: vec!["10.13.13.2/24".into()], - listen_port: 51820, + listen_port: Some(51820), dns: Default::default(), mtu: Default::default(), }, @@ -113,3 +117,83 @@ impl Default for Config { } } } + +fn props_get(props: &Properties, key: &str) -> Result +where + T: TryFrom, +{ + IniField::try_from(props.get(key))?.try_into() +} + +impl TryFrom<&Properties> for Interface { + type Error = anyhow::Error; + + fn try_from(props: &Properties) -> Result { + Ok(Self { + private_key: props_get(props, "PrivateKey")?, + address: props_get(props, "Address")?, + listen_port: props_get(props, "ListenPort")?, + dns: props_get(props, "DNS")?, + mtu: props_get(props, "MTU")?, + }) + } +} + +impl TryFrom<&Properties> for Peer { + type Error = anyhow::Error; + + fn try_from(props: &Properties) -> Result { + Ok(Self { + public_key: props_get(props, "PublicKey")?, + preshared_key: props_get(props, "PresharedKey")?, + allowed_ips: props_get(props, "AllowedIPs")?, + endpoint: props_get(props, "Endpoint")?, + persistent_keepalive: props_get(props, "PersistentKeepalive")?, + name: props_get(props, "Name")?, + }) + } +} + +impl Config { + pub fn from_toml(toml: &str) -> Result { + toml::from_str(toml).map_err(Into::into) + } + + pub fn from_ini(ini: &str) -> Result { + let ini = Ini::load_from_str(ini)?; + let interface = ini + .section(Some("Interface")) + .ok_or(anyhow!("Interface section not found"))?; + let peers = ini.section_all(Some("Peer")); + Ok(Self { + interface: Interface::try_from(interface)?, + peers: peers + .into_iter() + .map(|v| Peer::try_from(v)) + .collect::>>()?, + }) + } + + pub fn from_content_fmt(content: &str, fmt: &str) -> Result { + match fmt { + "toml" => Self::from_toml(content), + "ini" | "conf" => Self::from_ini(content), + _ => Err(anyhow::anyhow!("Unsupported format: {}", fmt)), + } + } +} + +#[cfg(test)] +mod tests { + use super::*; + + #[test] + fn tst_config_toml() { + let cfig = Config::default(); + let toml = toml::to_string(&cfig).unwrap(); + println!("{}", &toml); + insta::assert_snapshot!(toml); + let cfig2: Config = toml::from_str(&toml).unwrap(); + assert_eq!(cfig, cfig2); + } +} diff --git a/burrow/src/wireguard/iface.rs b/burrow/src/wireguard/iface.rs index 84b5489..321801b 100755 --- a/burrow/src/wireguard/iface.rs +++ b/burrow/src/wireguard/iface.rs @@ -93,6 +93,12 @@ impl Interface { *st = IfaceStatus::Running; } + pub async fn set_tun_ref(&mut self, tun: Arc>>) { + self.tun = tun; + let mut st = self.status.write().await; + *st = IfaceStatus::Running; + } + pub fn get_tun(&self) -> Arc>> { self.tun.clone() } @@ -135,7 +141,7 @@ impl Interface { Some(addr) => addr, None => { debug!("No destination found"); - continue + continue; } }; @@ -154,7 +160,7 @@ impl Interface { } Err(e) => { log::error!("Failed to send packet {}", e); - continue + continue; } }; } @@ -175,7 +181,7 @@ impl Interface { let main_tsk = async move { if let Err(e) = pcb.open_if_closed().await { log::error!("failed to open pcb: {}", e); - return + return; } let r2 = pcb.run(tun).await; if let Err(e) = r2 { @@ -195,7 +201,7 @@ impl Interface { Ok(..) => (), Err(e) => { error!("Failed to update timers: {}", e); - return + return; } } } diff --git a/burrow/src/wireguard/inifield.rs b/burrow/src/wireguard/inifield.rs new file mode 100644 index 0000000..946868d --- /dev/null +++ b/burrow/src/wireguard/inifield.rs @@ -0,0 +1,81 @@ +use std::str::FromStr; + +use anyhow::{Error, Result}; + +pub struct IniField(String); + +impl FromStr for IniField { + type Err = Error; + + fn from_str(s: &str) -> Result { + Ok(Self(s.to_string())) + } +} + +impl TryFrom for Vec { + type Error = Error; + + fn try_from(field: IniField) -> Result { + Ok(field.0.split(',').map(|s| s.trim().to_string()).collect()) + } +} + +impl TryFrom for u32 { + type Error = Error; + + fn try_from(value: IniField) -> Result { + value.0.parse().map_err(Error::from) + } +} + +impl TryFrom for Option { + type Error = Error; + + fn try_from(value: IniField) -> Result { + if value.0.is_empty() { + Ok(None) + } else { + value.0.parse().map(Some).map_err(Error::from) + } + } +} + +impl TryFrom for String { + type Error = Error; + + fn try_from(value: IniField) -> Result { + Ok(value.0) + } +} + +impl TryFrom for Option { + type Error = Error; + + fn try_from(value: IniField) -> Result { + if value.0.is_empty() { + Ok(None) + } else { + Ok(Some(value.0)) + } + } +} + +impl TryFrom> for IniField +where + T: ToString, +{ + type Error = Error; + + fn try_from(value: Option) -> Result { + Ok(match value { + Some(v) => Self(v.to_string()), + None => Self(String::new()), + }) + } +} + +impl IniField { + fn new(value: &str) -> Self { + Self(value.to_string()) + } +} diff --git a/burrow/src/wireguard/mod.rs b/burrow/src/wireguard/mod.rs index 4c70a7f..cfb4585 100755 --- a/burrow/src/wireguard/mod.rs +++ b/burrow/src/wireguard/mod.rs @@ -1,5 +1,6 @@ pub mod config; mod iface; +mod inifield; mod noise; mod pcb; mod peer; diff --git a/burrow/src/wireguard/snapshots/burrow__wireguard__config__tests__tst_config_toml.snap b/burrow/src/wireguard/snapshots/burrow__wireguard__config__tests__tst_config_toml.snap new file mode 100644 index 0000000..3800647 --- /dev/null +++ b/burrow/src/wireguard/snapshots/burrow__wireguard__config__tests__tst_config_toml.snap @@ -0,0 +1,16 @@ +--- +source: burrow/src/wireguard/config.rs +expression: toml +--- +[[Peer]] +public_key = "8GaFjVO6c4luCHG4ONO+1bFG8tO+Zz5/Gy+Geht1USM=" +preshared_key = "ha7j4BjD49sIzyF9SNlbueK0AMHghlj6+u0G3bzC698=" +allowed_ips = ["8.8.8.8/32", "0.0.0.0/0"] +endpoint = "wg.burrow.rs:51820" + +[interface] +private_key = "OEPVdomeLTxTIBvv3TYsJRge0Hp9NMiY0sIrhT8OWG8=" +address = ["10.13.13.2/24"] +listen_port = 51820 +dns = [] + diff --git a/burrow/tmp/conrd.conf b/burrow/tmp/conrd.conf new file mode 100644 index 0000000..52572d1 --- /dev/null +++ b/burrow/tmp/conrd.conf @@ -0,0 +1,8 @@ +[Interface] +PrivateKey = gAaK0KFGOpxY7geGo59XXDufcxeoSNXXNC12mCQmlVs= +Address = 10.1.11.2/32 +DNS = 10.1.11.1 +[Peer] +PublicKey = Ab6V2mgPHiCXaAZfQrNts8ha8RkEzC49VnmMQfe5Yg4= +AllowedIPs = 10.1.11.1/32,10.1.11.2/32,0.0.0.0/0 +Endpoint = 172.251.163.175:51820 \ No newline at end of file diff --git a/proto/burrow.proto b/proto/burrow.proto index 2d29c78..2355b8d 100644 --- a/proto/burrow.proto +++ b/proto/burrow.proto @@ -11,7 +11,7 @@ service Tunnel { } service Networks { - rpc NetworkAdd (Empty) returns (Empty); + rpc NetworkAdd (Network) returns (Empty); rpc NetworkList (Empty) returns (stream NetworkListResponse); rpc NetworkReorder (NetworkReorderRequest) returns (Empty); rpc NetworkDelete (NetworkDeleteRequest) returns (Empty); From 25a0f7c42158831ceb5f6bbe7defe3c067eb586c Mon Sep 17 00:00:00 2001 From: Conrad Kramer Date: Sat, 7 Sep 2024 20:35:28 -0700 Subject: [PATCH 15/16] Add Developer ID Profiles to build --- .github/workflows/release-apple.yml | 5 +++++ .../Burrow_Developer_ID.provisionprofile | Bin 0 -> 13091 bytes ...Burrow_Network_Developer_ID.provisionprofile | Bin 0 -> 13027 bytes 3 files changed, 5 insertions(+) create mode 100644 Apple/Profiles/Burrow_Developer_ID.provisionprofile create mode 100644 Apple/Profiles/Burrow_Network_Developer_ID.provisionprofile diff --git a/.github/workflows/release-apple.yml b/.github/workflows/release-apple.yml index bb9c15a..c0a34a9 100644 --- a/.github/workflows/release-apple.yml +++ b/.github/workflows/release-apple.yml @@ -38,6 +38,11 @@ jobs: app-store-key: ${{ secrets.APPSTORE_KEY }} app-store-key-id: ${{ secrets.APPSTORE_KEY_ID }} app-store-key-issuer-id: ${{ secrets.APPSTORE_KEY_ISSUER_ID }} + - name: Install Provisioning Profiles + shell: bash + run: | + mkdir -p ~/Library/MobileDevice/Provisioning\ Profiles/ + cp -f Apple/Profiles/* ~/Library/MobileDevice/Provisioning\ Profiles/ - name: Install Rust uses: dtolnay/rust-toolchain@stable with: diff --git a/Apple/Profiles/Burrow_Developer_ID.provisionprofile b/Apple/Profiles/Burrow_Developer_ID.provisionprofile new file mode 100644 index 0000000000000000000000000000000000000000..3ecd831fe2614bb8b5aea636ca5c080a48d99a98 GIT binary patch literal 13091 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 Uf<>W=OI4qBvCm4;3e_kF0D*cnOaK4? literal 0 HcmV?d00001 From 85640ffce18eac6ac1b6fa85ff278a457c955198 Mon Sep 17 00:00:00 2001 From: Conrad Kramer Date: Sat, 13 Jul 2024 18:08:43 -0700 Subject: [PATCH 16/16] Switch to gRPC client in Swift app --- .github/workflows/build-apple.yml | 9 +- .github/workflows/release-apple.yml | 4 + .gitignore | 3 + .swiftlint.yml | 1 - Apple/App/AppDelegate.swift | 1 + Apple/App/BurrowApp.swift | 3 +- Apple/App/MainMenu.xib | 4 +- Apple/App/Networks/Network.swift | 10 - Apple/App/Tunnel.swift | 50 - Apple/Burrow.xcodeproj/project.pbxproj | 814 +++++++++---- .../xcshareddata/swiftpm/Package.resolved | 123 ++ .../xcshareddata/xcschemes/App.xcscheme | 5 +- .../xcschemes/NetworkExtension.xcscheme | 6 +- Apple/Configuration/App.xcconfig | 6 +- Apple/Configuration/Compiler.xcconfig | 41 +- .../Configuration.xcconfig} | 5 +- .../Constants/Constants.h | 0 .../Constants}/Constants.swift | 31 +- .../Constants/module.modulemap | 2 +- Apple/Configuration/Debug.xcconfig | 26 + Apple/Configuration/Extension.xcconfig | 6 +- Apple/Configuration/Framework.xcconfig | 14 + Apple/Core/Client.swift | 32 + Apple/Core/Client/burrow.proto | 1 + Apple/Core/Client/grpc-swift-config.json | 11 + Apple/Core/Client/swift-protobuf-config.json | 10 + Apple/{Shared => Core}/Logging.swift | 2 +- .../PacketTunnelProvider.swift | 108 +- .../NetworkExtension/libburrow/build-rust.sh | 5 +- Apple/NetworkExtension/libburrow/libburrow.h | 2 +- Apple/Shared/Client.swift | 106 -- Apple/Shared/DataTypes.swift | 139 --- Apple/Shared/NWConnection+Async.swift | 32 - Apple/Shared/NewlineProtocolFramer.swift | 54 - .../AccentColor.colorset/Contents.json | 0 .../AppIcon.appiconset/100.png | Bin .../AppIcon.appiconset/1024.png | Bin .../AppIcon.appiconset/114.png | Bin .../AppIcon.appiconset/120.png | Bin .../AppIcon.appiconset/128.png | Bin .../AppIcon.appiconset/144.png | Bin .../AppIcon.appiconset/152.png | Bin .../Assets.xcassets/AppIcon.appiconset/16.png | Bin .../AppIcon.appiconset/167.png | Bin .../AppIcon.appiconset/172.png | Bin .../AppIcon.appiconset/180.png | Bin .../AppIcon.appiconset/196.png | Bin .../Assets.xcassets/AppIcon.appiconset/20.png | Bin .../AppIcon.appiconset/216.png | Bin .../AppIcon.appiconset/256.png | Bin .../Assets.xcassets/AppIcon.appiconset/29.png | Bin .../Assets.xcassets/AppIcon.appiconset/32.png | Bin .../Assets.xcassets/AppIcon.appiconset/40.png | Bin .../Assets.xcassets/AppIcon.appiconset/48.png | Bin .../Assets.xcassets/AppIcon.appiconset/50.png | Bin .../AppIcon.appiconset/512.png | Bin .../Assets.xcassets/AppIcon.appiconset/55.png | Bin .../Assets.xcassets/AppIcon.appiconset/57.png | Bin .../Assets.xcassets/AppIcon.appiconset/58.png | Bin .../Assets.xcassets/AppIcon.appiconset/60.png | Bin .../Assets.xcassets/AppIcon.appiconset/64.png | Bin .../Assets.xcassets/AppIcon.appiconset/72.png | Bin .../Assets.xcassets/AppIcon.appiconset/76.png | Bin .../Assets.xcassets/AppIcon.appiconset/80.png | Bin .../Assets.xcassets/AppIcon.appiconset/87.png | Bin .../Assets.xcassets/AppIcon.appiconset/88.png | Bin .../AppIcon.appiconset/Contents.json | 0 .../{App => UI}/Assets.xcassets/Contents.json | 0 .../HackClub.colorset/Contents.json | 0 .../HackClub.imageset/Contents.json | 0 .../flag-standalone-wtransparent.pdf | Bin .../WireGuard.colorset/Contents.json | 0 .../WireGuard.imageset/Contents.json | 0 .../WireGuard.imageset/WireGuard.svg | 0 .../WireGuardTitle.imageset/Contents.json | 0 .../WireGuardTitle.svg | 0 Apple/{App => UI}/BurrowView.swift | 7 +- Apple/{App => UI}/FloatingButtonStyle.swift | 0 Apple/{App => UI}/MenuItemToggleView.swift | 11 +- Apple/{App => UI}/NetworkCarouselView.swift | 8 +- .../{App => UI}/NetworkExtension+Async.swift | 6 +- .../{App => UI}/NetworkExtensionTunnel.swift | 72 +- Apple/{App => UI}/NetworkView.swift | 0 Apple/{App => UI}/Networks/HackClub.swift | 8 +- Apple/UI/Networks/Network.swift | 36 + Apple/{App => UI}/Networks/WireGuard.swift | 8 +- Apple/{App => UI}/OAuth2.swift | 21 +- Apple/UI/Tunnel.swift | 61 + Apple/{App => UI}/TunnelButton.swift | 2 +- Apple/{App => UI}/TunnelStatusView.swift | 2 +- Apple/UI/UI.xcconfig | 3 + Cargo.lock | 1080 +++++++++-------- burrow-gtk/build-aux/Dockerfile | 2 +- 93 files changed, 1666 insertions(+), 1327 deletions(-) delete mode 100644 Apple/App/Networks/Network.swift delete mode 100644 Apple/App/Tunnel.swift create mode 100644 Apple/Burrow.xcodeproj/project.xcworkspace/xcshareddata/swiftpm/Package.resolved rename Apple/{Shared/Shared.xcconfig => Configuration/Configuration.xcconfig} (65%) rename Apple/{Shared => Configuration}/Constants/Constants.h (100%) rename Apple/{Shared => Configuration/Constants}/Constants.swift (61%) rename Apple/{Shared => Configuration}/Constants/module.modulemap (66%) create mode 100644 Apple/Configuration/Debug.xcconfig create mode 100644 Apple/Configuration/Framework.xcconfig create mode 100644 Apple/Core/Client.swift create mode 120000 Apple/Core/Client/burrow.proto create mode 100644 Apple/Core/Client/grpc-swift-config.json create mode 100644 Apple/Core/Client/swift-protobuf-config.json rename Apple/{Shared => Core}/Logging.swift (88%) delete mode 100644 Apple/Shared/Client.swift delete mode 100644 Apple/Shared/DataTypes.swift delete mode 100644 Apple/Shared/NWConnection+Async.swift delete mode 100644 Apple/Shared/NewlineProtocolFramer.swift rename Apple/{App => UI}/Assets.xcassets/AccentColor.colorset/Contents.json (100%) rename Apple/{App => UI}/Assets.xcassets/AppIcon.appiconset/100.png (100%) rename Apple/{App => UI}/Assets.xcassets/AppIcon.appiconset/1024.png (100%) rename Apple/{App => UI}/Assets.xcassets/AppIcon.appiconset/114.png (100%) rename Apple/{App => UI}/Assets.xcassets/AppIcon.appiconset/120.png (100%) rename Apple/{App => UI}/Assets.xcassets/AppIcon.appiconset/128.png (100%) rename Apple/{App => UI}/Assets.xcassets/AppIcon.appiconset/144.png (100%) rename Apple/{App => UI}/Assets.xcassets/AppIcon.appiconset/152.png (100%) rename Apple/{App => UI}/Assets.xcassets/AppIcon.appiconset/16.png (100%) rename Apple/{App => UI}/Assets.xcassets/AppIcon.appiconset/167.png (100%) rename Apple/{App => UI}/Assets.xcassets/AppIcon.appiconset/172.png (100%) rename Apple/{App => UI}/Assets.xcassets/AppIcon.appiconset/180.png (100%) rename Apple/{App => UI}/Assets.xcassets/AppIcon.appiconset/196.png (100%) rename Apple/{App => UI}/Assets.xcassets/AppIcon.appiconset/20.png (100%) rename Apple/{App => UI}/Assets.xcassets/AppIcon.appiconset/216.png (100%) rename Apple/{App => UI}/Assets.xcassets/AppIcon.appiconset/256.png (100%) rename Apple/{App => UI}/Assets.xcassets/AppIcon.appiconset/29.png (100%) rename Apple/{App => UI}/Assets.xcassets/AppIcon.appiconset/32.png (100%) rename Apple/{App => UI}/Assets.xcassets/AppIcon.appiconset/40.png (100%) rename Apple/{App => UI}/Assets.xcassets/AppIcon.appiconset/48.png (100%) rename Apple/{App => UI}/Assets.xcassets/AppIcon.appiconset/50.png (100%) rename Apple/{App => UI}/Assets.xcassets/AppIcon.appiconset/512.png (100%) rename Apple/{App => UI}/Assets.xcassets/AppIcon.appiconset/55.png (100%) rename Apple/{App => UI}/Assets.xcassets/AppIcon.appiconset/57.png (100%) rename Apple/{App => UI}/Assets.xcassets/AppIcon.appiconset/58.png (100%) rename Apple/{App => UI}/Assets.xcassets/AppIcon.appiconset/60.png (100%) rename Apple/{App => UI}/Assets.xcassets/AppIcon.appiconset/64.png (100%) rename Apple/{App => UI}/Assets.xcassets/AppIcon.appiconset/72.png (100%) rename Apple/{App => UI}/Assets.xcassets/AppIcon.appiconset/76.png (100%) rename Apple/{App => UI}/Assets.xcassets/AppIcon.appiconset/80.png (100%) rename Apple/{App => UI}/Assets.xcassets/AppIcon.appiconset/87.png (100%) rename Apple/{App => UI}/Assets.xcassets/AppIcon.appiconset/88.png (100%) rename Apple/{App => UI}/Assets.xcassets/AppIcon.appiconset/Contents.json (100%) rename Apple/{App => UI}/Assets.xcassets/Contents.json (100%) rename Apple/{App => UI}/Assets.xcassets/HackClub.colorset/Contents.json (100%) rename Apple/{App => UI}/Assets.xcassets/HackClub.imageset/Contents.json (100%) rename Apple/{App => UI}/Assets.xcassets/HackClub.imageset/flag-standalone-wtransparent.pdf (100%) rename Apple/{App => UI}/Assets.xcassets/WireGuard.colorset/Contents.json (100%) rename Apple/{App => UI}/Assets.xcassets/WireGuard.imageset/Contents.json (100%) rename Apple/{App => UI}/Assets.xcassets/WireGuard.imageset/WireGuard.svg (100%) rename Apple/{App => UI}/Assets.xcassets/WireGuardTitle.imageset/Contents.json (100%) rename Apple/{App => UI}/Assets.xcassets/WireGuardTitle.imageset/WireGuardTitle.svg (100%) rename Apple/{App => UI}/BurrowView.swift (95%) rename Apple/{App => UI}/FloatingButtonStyle.swift (100%) rename Apple/{App => UI}/MenuItemToggleView.swift (87%) rename Apple/{App => UI}/NetworkCarouselView.swift (90%) rename Apple/{App => UI}/NetworkExtension+Async.swift (82%) rename Apple/{App => UI}/NetworkExtensionTunnel.swift (67%) rename Apple/{App => UI}/NetworkView.swift (100%) rename Apple/{App => UI}/Networks/HackClub.swift (76%) create mode 100644 Apple/UI/Networks/Network.swift rename Apple/{App => UI}/Networks/WireGuard.swift (82%) rename Apple/{App => UI}/OAuth2.swift (94%) create mode 100644 Apple/UI/Tunnel.swift rename Apple/{App => UI}/TunnelButton.swift (95%) rename Apple/{App => UI}/TunnelStatusView.swift (95%) create mode 100644 Apple/UI/UI.xcconfig diff --git a/.github/workflows/build-apple.yml b/.github/workflows/build-apple.yml index b628001..7ae8c4c 100644 --- a/.github/workflows/build-apple.yml +++ b/.github/workflows/build-apple.yml @@ -39,7 +39,7 @@ jobs: - aarch64-apple-darwin env: DEVELOPER_DIR: /Applications/Xcode_16.0.app/Contents/Developer - PROTOC_VERSION: 3.25.1 + PROTOC_PATH: /opt/homebrew/bin/protoc steps: - name: Checkout uses: actions/checkout@v3 @@ -55,10 +55,9 @@ jobs: uses: dtolnay/rust-toolchain@stable with: targets: ${{ join(matrix.rust-targets, ', ') }} - - name: Install protoc - uses: taiki-e/install-action@v2 - with: - tool: protoc@${{ env.PROTOC_VERSION }} + - name: Install Protobuf + shell: bash + run: brew install protobuf - name: Build id: build uses: ./.github/actions/build-for-testing diff --git a/.github/workflows/release-apple.yml b/.github/workflows/release-apple.yml index c0a34a9..c869d6a 100644 --- a/.github/workflows/release-apple.yml +++ b/.github/workflows/release-apple.yml @@ -22,6 +22,7 @@ jobs: - aarch64-apple-darwin env: DEVELOPER_DIR: /Applications/Xcode_16.0.app/Contents/Developer + PROTOC_PATH: /opt/homebrew/bin/protoc steps: - name: Checkout uses: actions/checkout@v4 @@ -47,6 +48,9 @@ jobs: uses: dtolnay/rust-toolchain@stable with: targets: ${{ join(matrix.rust-targets, ', ') }} + - name: Install Protobuf + shell: bash + run: brew install protobuf - name: Configure Version id: version shell: bash diff --git a/.gitignore b/.gitignore index 997d4d5..1b300b4 100644 --- a/.gitignore +++ b/.gitignore @@ -1,6 +1,9 @@ # Xcode xcuserdata +# Swift +Apple/Package/.swiftpm/ + # Rust target/ .env diff --git a/.swiftlint.yml b/.swiftlint.yml index 22ef035..8efc85e 100644 --- a/.swiftlint.yml +++ b/.swiftlint.yml @@ -30,7 +30,6 @@ opt_in_rules: - function_default_parameter_at_end - ibinspectable_in_extension - identical_operands -- implicitly_unwrapped_optional - indentation_width - joined_default_parameter - last_where diff --git a/Apple/App/AppDelegate.swift b/Apple/App/AppDelegate.swift index b0c5546..0ea93f4 100644 --- a/Apple/App/AppDelegate.swift +++ b/Apple/App/AppDelegate.swift @@ -1,5 +1,6 @@ #if os(macOS) import AppKit +import BurrowUI import SwiftUI @main diff --git a/Apple/App/BurrowApp.swift b/Apple/App/BurrowApp.swift index 21ebf84..838ef54 100644 --- a/Apple/App/BurrowApp.swift +++ b/Apple/App/BurrowApp.swift @@ -1,6 +1,7 @@ +#if !os(macOS) +import BurrowUI import SwiftUI -#if !os(macOS) @MainActor @main struct BurrowApp: App { diff --git a/Apple/App/MainMenu.xib b/Apple/App/MainMenu.xib index 587f6c4..50ba431 100644 --- a/Apple/App/MainMenu.xib +++ b/Apple/App/MainMenu.xib @@ -1,7 +1,7 @@ - + - + diff --git a/Apple/App/Networks/Network.swift b/Apple/App/Networks/Network.swift deleted file mode 100644 index d441d24..0000000 --- a/Apple/App/Networks/Network.swift +++ /dev/null @@ -1,10 +0,0 @@ -import SwiftUI - -protocol Network { - associatedtype Label: View - - var id: String { get } - var backgroundColor: Color { get } - - var label: Label { get } -} diff --git a/Apple/App/Tunnel.swift b/Apple/App/Tunnel.swift deleted file mode 100644 index 8db366f..0000000 --- a/Apple/App/Tunnel.swift +++ /dev/null @@ -1,50 +0,0 @@ -import SwiftUI - -protocol Tunnel { - var status: TunnelStatus { get } - - func start() - func stop() - func enable() -} - -enum TunnelStatus: Equatable, Hashable { - case unknown - case permissionRequired - case disabled - case connecting - case connected(Date) - case disconnecting - case disconnected - case reasserting - case invalid - case configurationReadWriteFailed -} - -struct TunnelKey: EnvironmentKey { - static let defaultValue: any Tunnel = NetworkExtensionTunnel() -} - -extension EnvironmentValues { - var tunnel: any Tunnel { - get { self[TunnelKey.self] } - set { self[TunnelKey.self] = newValue } - } -} - -#if DEBUG -@Observable -class PreviewTunnel: Tunnel { - var status: TunnelStatus = .permissionRequired - - func start() { - status = .connected(.now) - } - func stop() { - status = .disconnected - } - func enable() { - status = .disconnected - } -} -#endif diff --git a/Apple/Burrow.xcodeproj/project.pbxproj b/Apple/Burrow.xcodeproj/project.pbxproj index 5c5e80b..617b88f 100644 --- a/Apple/Burrow.xcodeproj/project.pbxproj +++ b/Apple/Burrow.xcodeproj/project.pbxproj @@ -7,52 +7,50 @@ objects = { /* Begin PBXBuildFile section */ - 0BA6D73B2BA638D900BD4B55 /* Client.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0B46E8DF2AC918CA00BA2A3C /* Client.swift */; }; - 0BA6D73C2BA6393200BD4B55 /* NWConnection+Async.swift in Sources */ = {isa = PBXBuildFile; fileRef = D00117302B2FFFC900D87C25 /* NWConnection+Async.swift */; }; - 0BA6D73D2BA6393B00BD4B55 /* NewlineProtocolFramer.swift in Sources */ = {isa = PBXBuildFile; fileRef = D00117322B3001A400D87C25 /* NewlineProtocolFramer.swift */; }; - 0BA6D73E2BA6394B00BD4B55 /* DataTypes.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0B28F1552ABF463A000D44B0 /* DataTypes.swift */; }; - 43AA26D82A10004900F14CE6 /* MenuItemToggleView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 43AA26D72A10004900F14CE6 /* MenuItemToggleView.swift */; }; - D000363D2BB8928E00E582EC /* NetworkCarouselView.swift in Sources */ = {isa = PBXBuildFile; fileRef = D000363C2BB8928E00E582EC /* NetworkCarouselView.swift */; }; - D000363F2BB895FB00E582EC /* OAuth2.swift in Sources */ = {isa = PBXBuildFile; fileRef = D000363E2BB895FB00E582EC /* OAuth2.swift */; }; - D001173B2B30341C00D87C25 /* Logging.swift in Sources */ = {isa = PBXBuildFile; fileRef = D001173A2B30341C00D87C25 /* Logging.swift */; }; - D00117442B30372900D87C25 /* libBurrowShared.a in Frameworks */ = {isa = PBXBuildFile; fileRef = D00117382B30341C00D87C25 /* libBurrowShared.a */; }; - D00117452B30372C00D87C25 /* libBurrowShared.a in Frameworks */ = {isa = PBXBuildFile; fileRef = D00117382B30341C00D87C25 /* libBurrowShared.a */; }; D00AA8972A4669BC005C8102 /* AppDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = D00AA8962A4669BC005C8102 /* AppDelegate.swift */; }; - D01A79312B81630D0024EC91 /* NetworkView.swift in Sources */ = {isa = PBXBuildFile; fileRef = D01A79302B81630D0024EC91 /* NetworkView.swift */; }; D020F65829E4A697002790F6 /* PacketTunnelProvider.swift in Sources */ = {isa = PBXBuildFile; fileRef = D020F65729E4A697002790F6 /* PacketTunnelProvider.swift */; }; D020F65D29E4A697002790F6 /* BurrowNetworkExtension.appex in Embed Foundation Extensions */ = {isa = PBXBuildFile; fileRef = D020F65329E4A697002790F6 /* BurrowNetworkExtension.appex */; settings = {ATTRIBUTES = (RemoveHeadersOnCopy, ); }; }; - D032E6522B8A79C20006B8AD /* HackClub.swift in Sources */ = {isa = PBXBuildFile; fileRef = D032E6512B8A79C20006B8AD /* HackClub.swift */; }; - D032E6542B8A79DA0006B8AD /* WireGuard.swift in Sources */ = {isa = PBXBuildFile; fileRef = D032E6532B8A79DA0006B8AD /* WireGuard.swift */; }; + D03383AD2C8E67E300F7C44E /* SwiftProtobuf in Frameworks */ = {isa = PBXBuildFile; productRef = D078F7E22C8DA375008A8CEC /* SwiftProtobuf */; }; + D03383AE2C8E67E300F7C44E /* NIO in Frameworks */ = {isa = PBXBuildFile; productRef = D044EE902C8DAB2000778185 /* NIO */; }; + D03383AF2C8E67E300F7C44E /* NIOConcurrencyHelpers in Frameworks */ = {isa = PBXBuildFile; productRef = D044EE922C8DAB2000778185 /* NIOConcurrencyHelpers */; }; + D03383B02C8E67E300F7C44E /* NIOTransportServices in Frameworks */ = {isa = PBXBuildFile; productRef = D044EE952C8DAB2800778185 /* NIOTransportServices */; }; D05B9F7629E39EEC008CB1F9 /* BurrowApp.swift in Sources */ = {isa = PBXBuildFile; fileRef = D05B9F7529E39EEC008CB1F9 /* BurrowApp.swift */; }; - D05B9F7829E39EEC008CB1F9 /* BurrowView.swift in Sources */ = {isa = PBXBuildFile; fileRef = D05B9F7729E39EEC008CB1F9 /* BurrowView.swift */; }; - D05B9F7A29E39EED008CB1F9 /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = D05B9F7929E39EED008CB1F9 /* Assets.xcassets */; }; - D05EF8C82B81818D0017AB4F /* FloatingButtonStyle.swift in Sources */ = {isa = PBXBuildFile; fileRef = D05EF8C72B81818D0017AB4F /* FloatingButtonStyle.swift */; }; - D08252762B5C9FC4005DA378 /* Constants.swift in Sources */ = {isa = PBXBuildFile; fileRef = D08252752B5C9FC4005DA378 /* Constants.swift */; }; - D09150422B9D2AF700BE3CB0 /* MainMenu.xib in Resources */ = {isa = PBXBuildFile; fileRef = D09150412B9D2AF700BE3CB0 /* MainMenu.xib */; }; - D0BCC5FD2A086D4700AD070D /* NetworkExtension+Async.swift in Sources */ = {isa = PBXBuildFile; fileRef = D0BCC5FC2A086D4700AD070D /* NetworkExtension+Async.swift */; }; - D0BCC6082A0981FE00AD070D /* Tunnel.swift in Sources */ = {isa = PBXBuildFile; fileRef = D0B98FC629FDC5B5004E7149 /* Tunnel.swift */; }; + D09150422B9D2AF700BE3CB0 /* MainMenu.xib in Resources */ = {isa = PBXBuildFile; fileRef = D09150412B9D2AF700BE3CB0 /* MainMenu.xib */; platformFilters = (macos, ); }; + D0B1D1102C436152004B7823 /* AsyncAlgorithms in Frameworks */ = {isa = PBXBuildFile; productRef = D0B1D10F2C436152004B7823 /* AsyncAlgorithms */; }; D0BCC6092A09A03E00AD070D /* libburrow.a in Frameworks */ = {isa = PBXBuildFile; fileRef = D0BCC6032A09535900AD070D /* libburrow.a */; }; - D0FAB5922B818A5900F6A84B /* NetworkExtensionTunnel.swift in Sources */ = {isa = PBXBuildFile; fileRef = D0FAB5912B818A5900F6A84B /* NetworkExtensionTunnel.swift */; }; - D0FAB5962B818B2900F6A84B /* TunnelButton.swift in Sources */ = {isa = PBXBuildFile; fileRef = D0FAB5952B818B2900F6A84B /* TunnelButton.swift */; }; - D0FAB5982B818B8200F6A84B /* TunnelStatusView.swift in Sources */ = {isa = PBXBuildFile; fileRef = D0FAB5972B818B8200F6A84B /* TunnelStatusView.swift */; }; - D0FAB59A2B818B9600F6A84B /* Network.swift in Sources */ = {isa = PBXBuildFile; fileRef = D0FAB5992B818B9600F6A84B /* Network.swift */; }; + D0BF09522C8E66F6000D8DEC /* BurrowConfiguration.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = D0D4E5622C8D9BF4007F820A /* BurrowConfiguration.framework */; }; + D0BF09552C8E66FD000D8DEC /* BurrowConfiguration.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = D0D4E5622C8D9BF4007F820A /* BurrowConfiguration.framework */; }; + D0D4E53A2C8D996F007F820A /* BurrowCore.framework in Embed Frameworks */ = {isa = PBXBuildFile; fileRef = D0D4E5312C8D996F007F820A /* BurrowCore.framework */; settings = {ATTRIBUTES = (CodeSignOnCopy, RemoveHeadersOnCopy, ); }; }; + D0D4E56B2C8D9C2F007F820A /* Logging.swift in Sources */ = {isa = PBXBuildFile; fileRef = D0D4E49A2C8D921A007F820A /* Logging.swift */; }; + D0D4E5702C8D9C62007F820A /* BurrowCore.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = D0D4E5312C8D996F007F820A /* BurrowCore.framework */; }; + D0D4E5712C8D9C6F007F820A /* HackClub.swift in Sources */ = {isa = PBXBuildFile; fileRef = D0D4E49D2C8D921A007F820A /* HackClub.swift */; }; + D0D4E5722C8D9C6F007F820A /* Network.swift in Sources */ = {isa = PBXBuildFile; fileRef = D0D4E49E2C8D921A007F820A /* Network.swift */; }; + D0D4E5732C8D9C6F007F820A /* WireGuard.swift in Sources */ = {isa = PBXBuildFile; fileRef = D0D4E49F2C8D921A007F820A /* WireGuard.swift */; }; + D0D4E5742C8D9C6F007F820A /* BurrowView.swift in Sources */ = {isa = PBXBuildFile; fileRef = D0D4E4A22C8D921A007F820A /* BurrowView.swift */; }; + D0D4E5752C8D9C6F007F820A /* FloatingButtonStyle.swift in Sources */ = {isa = PBXBuildFile; fileRef = D0D4E4A32C8D921A007F820A /* FloatingButtonStyle.swift */; }; + D0D4E5762C8D9C6F007F820A /* MenuItemToggleView.swift in Sources */ = {isa = PBXBuildFile; fileRef = D0D4E4A42C8D921A007F820A /* MenuItemToggleView.swift */; }; + D0D4E5772C8D9C6F007F820A /* NetworkCarouselView.swift in Sources */ = {isa = PBXBuildFile; fileRef = D0D4E4A52C8D921A007F820A /* NetworkCarouselView.swift */; }; + D0D4E5782C8D9C6F007F820A /* NetworkExtension+Async.swift in Sources */ = {isa = PBXBuildFile; fileRef = D0D4E4A62C8D921A007F820A /* NetworkExtension+Async.swift */; }; + D0D4E5792C8D9C6F007F820A /* NetworkExtensionTunnel.swift in Sources */ = {isa = PBXBuildFile; fileRef = D0D4E4A72C8D921A007F820A /* NetworkExtensionTunnel.swift */; }; + D0D4E57A2C8D9C6F007F820A /* NetworkView.swift in Sources */ = {isa = PBXBuildFile; fileRef = D0D4E4A82C8D921A007F820A /* NetworkView.swift */; }; + D0D4E57B2C8D9C6F007F820A /* OAuth2.swift in Sources */ = {isa = PBXBuildFile; fileRef = D0D4E4A92C8D921A007F820A /* OAuth2.swift */; }; + D0D4E57C2C8D9C6F007F820A /* Tunnel.swift in Sources */ = {isa = PBXBuildFile; fileRef = D0D4E4AA2C8D921A007F820A /* Tunnel.swift */; }; + D0D4E57D2C8D9C6F007F820A /* TunnelButton.swift in Sources */ = {isa = PBXBuildFile; fileRef = D0D4E4AB2C8D921A007F820A /* TunnelButton.swift */; }; + D0D4E57E2C8D9C6F007F820A /* TunnelStatusView.swift in Sources */ = {isa = PBXBuildFile; fileRef = D0D4E4AC2C8D921A007F820A /* TunnelStatusView.swift */; }; + D0D4E5892C8D9C94007F820A /* BurrowUI.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = D0D4E5582C8D9BF2007F820A /* BurrowUI.framework */; }; + D0D4E58A2C8D9C9E007F820A /* BurrowUI.framework in Embed Frameworks */ = {isa = PBXBuildFile; fileRef = D0D4E5582C8D9BF2007F820A /* BurrowUI.framework */; settings = {ATTRIBUTES = (CodeSignOnCopy, RemoveHeadersOnCopy, ); }; }; + D0D4E58B2C8D9CA4007F820A /* BurrowConfiguration.framework in Embed Frameworks */ = {isa = PBXBuildFile; fileRef = D0D4E5622C8D9BF4007F820A /* BurrowConfiguration.framework */; settings = {ATTRIBUTES = (CodeSignOnCopy, RemoveHeadersOnCopy, ); }; }; + D0D4E5922C8D9D15007F820A /* Constants.swift in Sources */ = {isa = PBXBuildFile; fileRef = D0D4E58F2C8D9D0A007F820A /* Constants.swift */; }; + D0D4E5A62C8D9E65007F820A /* BurrowCore.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = D0D4E5312C8D996F007F820A /* BurrowCore.framework */; }; + D0F4FAD32C8DC79C0068730A /* BurrowCore.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = D0D4E5312C8D996F007F820A /* BurrowCore.framework */; }; + D0F7594E2C8DAB6B00126CF3 /* GRPC in Frameworks */ = {isa = PBXBuildFile; productRef = D078F7E02C8DA375008A8CEC /* GRPC */; }; + D0F759612C8DB24B00126CF3 /* grpc-swift-config.json in Sources */ = {isa = PBXBuildFile; fileRef = D0D4E4962C8D921A007F820A /* grpc-swift-config.json */; }; + D0F759622C8DB24B00126CF3 /* swift-protobuf-config.json in Sources */ = {isa = PBXBuildFile; fileRef = D0D4E4972C8D921A007F820A /* swift-protobuf-config.json */; }; + D0F7597E2C8DB30500126CF3 /* CGRPCZlib in Frameworks */ = {isa = PBXBuildFile; productRef = D0F7597D2C8DB30500126CF3 /* CGRPCZlib */; }; + D0F7598D2C8DB3DA00126CF3 /* Client.swift in Sources */ = {isa = PBXBuildFile; fileRef = D0D4E4992C8D921A007F820A /* Client.swift */; }; /* End PBXBuildFile section */ /* Begin PBXContainerItemProxy section */ - D00117462B30373100D87C25 /* PBXContainerItemProxy */ = { - isa = PBXContainerItemProxy; - containerPortal = D05B9F6A29E39EEC008CB1F9 /* Project object */; - proxyType = 1; - remoteGlobalIDString = D00117372B30341C00D87C25; - remoteInfo = Shared; - }; - D00117482B30373500D87C25 /* PBXContainerItemProxy */ = { - isa = PBXContainerItemProxy; - containerPortal = D05B9F6A29E39EEC008CB1F9 /* Project object */; - proxyType = 1; - remoteGlobalIDString = D00117372B30341C00D87C25; - remoteInfo = Shared; - }; D020F65B29E4A697002790F6 /* PBXContainerItemProxy */ = { isa = PBXContainerItemProxy; containerPortal = D05B9F6A29E39EEC008CB1F9 /* Project object */; @@ -60,6 +58,48 @@ remoteGlobalIDString = D020F65229E4A697002790F6; remoteInfo = BurrowNetworkExtension; }; + D0BF09502C8E66F1000D8DEC /* PBXContainerItemProxy */ = { + isa = PBXContainerItemProxy; + containerPortal = D05B9F6A29E39EEC008CB1F9 /* Project object */; + proxyType = 1; + remoteGlobalIDString = D0D4E55A2C8D9BF4007F820A; + remoteInfo = Configuration; + }; + D0BF09532C8E66FA000D8DEC /* PBXContainerItemProxy */ = { + isa = PBXContainerItemProxy; + containerPortal = D05B9F6A29E39EEC008CB1F9 /* Project object */; + proxyType = 1; + remoteGlobalIDString = D0D4E55A2C8D9BF4007F820A; + remoteInfo = Configuration; + }; + D0D4E56E2C8D9C5D007F820A /* PBXContainerItemProxy */ = { + isa = PBXContainerItemProxy; + containerPortal = D05B9F6A29E39EEC008CB1F9 /* Project object */; + proxyType = 1; + remoteGlobalIDString = D0D4E5302C8D996F007F820A; + remoteInfo = Core; + }; + D0D4E57F2C8D9C78007F820A /* PBXContainerItemProxy */ = { + isa = PBXContainerItemProxy; + containerPortal = D05B9F6A29E39EEC008CB1F9 /* Project object */; + proxyType = 1; + remoteGlobalIDString = D0D4E5302C8D996F007F820A; + remoteInfo = Core; + }; + D0D4E5872C8D9C88007F820A /* PBXContainerItemProxy */ = { + isa = PBXContainerItemProxy; + containerPortal = D05B9F6A29E39EEC008CB1F9 /* Project object */; + proxyType = 1; + remoteGlobalIDString = D0D4E5502C8D9BF2007F820A; + remoteInfo = UI; + }; + D0F4FAD12C8DC7960068730A /* PBXContainerItemProxy */ = { + isa = PBXContainerItemProxy; + containerPortal = D05B9F6A29E39EEC008CB1F9 /* Project object */; + proxyType = 1; + remoteGlobalIDString = D0D4E5302C8D996F007F820A; + remoteInfo = Core; + }; /* End PBXContainerItemProxy section */ /* Begin PBXCopyFilesBuildPhase section */ @@ -74,22 +114,24 @@ name = "Embed Foundation Extensions"; runOnlyForDeploymentPostprocessing = 0; }; + D0D4E53F2C8D996F007F820A /* Embed Frameworks */ = { + isa = PBXCopyFilesBuildPhase; + buildActionMask = 2147483647; + dstPath = ""; + dstSubfolderSpec = 10; + files = ( + D0D4E58B2C8D9CA4007F820A /* BurrowConfiguration.framework in Embed Frameworks */, + D0D4E58A2C8D9C9E007F820A /* BurrowUI.framework in Embed Frameworks */, + D0D4E53A2C8D996F007F820A /* BurrowCore.framework in Embed Frameworks */, + ); + name = "Embed Frameworks"; + runOnlyForDeploymentPostprocessing = 0; + }; /* End PBXCopyFilesBuildPhase section */ /* Begin PBXFileReference section */ - 0B28F1552ABF463A000D44B0 /* DataTypes.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = DataTypes.swift; sourceTree = ""; }; - 0B46E8DF2AC918CA00BA2A3C /* Client.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Client.swift; sourceTree = ""; }; - 43AA26D72A10004900F14CE6 /* MenuItemToggleView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MenuItemToggleView.swift; sourceTree = ""; }; - D000363C2BB8928E00E582EC /* NetworkCarouselView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = NetworkCarouselView.swift; sourceTree = ""; }; - D000363E2BB895FB00E582EC /* OAuth2.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = OAuth2.swift; sourceTree = ""; }; - D00117302B2FFFC900D87C25 /* NWConnection+Async.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "NWConnection+Async.swift"; sourceTree = ""; }; - D00117322B3001A400D87C25 /* NewlineProtocolFramer.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = NewlineProtocolFramer.swift; sourceTree = ""; }; - D00117382B30341C00D87C25 /* libBurrowShared.a */ = {isa = PBXFileReference; explicitFileType = archive.ar; includeInIndex = 0; path = libBurrowShared.a; sourceTree = BUILT_PRODUCTS_DIR; }; - D001173A2B30341C00D87C25 /* Logging.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Logging.swift; sourceTree = ""; }; - D00117412B30347800D87C25 /* module.modulemap */ = {isa = PBXFileReference; lastKnownFileType = "sourcecode.module-map"; path = module.modulemap; sourceTree = ""; }; - D00117422B30348D00D87C25 /* Shared.xcconfig */ = {isa = PBXFileReference; lastKnownFileType = text.xcconfig; path = Shared.xcconfig; sourceTree = ""; }; + D00117422B30348D00D87C25 /* Configuration.xcconfig */ = {isa = PBXFileReference; lastKnownFileType = text.xcconfig; path = Configuration.xcconfig; sourceTree = ""; }; D00AA8962A4669BC005C8102 /* AppDelegate.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AppDelegate.swift; sourceTree = ""; }; - D01A79302B81630D0024EC91 /* NetworkView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = NetworkView.swift; sourceTree = ""; }; D020F63D29E4A1FF002790F6 /* Identity.xcconfig */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.xcconfig; path = Identity.xcconfig; sourceTree = ""; }; D020F64029E4A1FF002790F6 /* Compiler.xcconfig */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.xcconfig; path = Compiler.xcconfig; sourceTree = ""; }; D020F64229E4A1FF002790F6 /* Info.plist */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; }; @@ -104,43 +146,54 @@ D020F66729E4A95D002790F6 /* NetworkExtension-iOS.entitlements */ = {isa = PBXFileReference; lastKnownFileType = text.plist.entitlements; path = "NetworkExtension-iOS.entitlements"; sourceTree = ""; }; D020F66829E4AA74002790F6 /* App-iOS.entitlements */ = {isa = PBXFileReference; lastKnownFileType = text.plist.entitlements; path = "App-iOS.entitlements"; sourceTree = ""; }; D020F66929E4AA74002790F6 /* App-macOS.entitlements */ = {isa = PBXFileReference; lastKnownFileType = text.plist.entitlements; path = "App-macOS.entitlements"; sourceTree = ""; }; - D032E6512B8A79C20006B8AD /* HackClub.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = HackClub.swift; sourceTree = ""; }; - D032E6532B8A79DA0006B8AD /* WireGuard.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = WireGuard.swift; sourceTree = ""; }; D04A3E1D2BAF465F0043EC85 /* Version.xcconfig */ = {isa = PBXFileReference; lastKnownFileType = text.xcconfig; path = Version.xcconfig; sourceTree = ""; }; D05B9F7229E39EEC008CB1F9 /* Burrow.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = Burrow.app; sourceTree = BUILT_PRODUCTS_DIR; }; D05B9F7529E39EEC008CB1F9 /* BurrowApp.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = BurrowApp.swift; sourceTree = ""; }; - D05B9F7729E39EEC008CB1F9 /* BurrowView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = BurrowView.swift; sourceTree = ""; }; - D05B9F7929E39EED008CB1F9 /* Assets.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = Assets.xcassets; sourceTree = ""; }; - D05EF8C72B81818D0017AB4F /* FloatingButtonStyle.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = FloatingButtonStyle.swift; sourceTree = ""; }; - D08252742B5C9DEB005DA378 /* Constants.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = Constants.h; sourceTree = ""; }; - D08252752B5C9FC4005DA378 /* Constants.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Constants.swift; sourceTree = ""; }; D09150412B9D2AF700BE3CB0 /* MainMenu.xib */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = file.xib; path = MainMenu.xib; sourceTree = ""; }; D0B98FBF29FD8072004E7149 /* build-rust.sh */ = {isa = PBXFileReference; lastKnownFileType = text.script.sh; path = "build-rust.sh"; sourceTree = ""; }; - D0B98FC629FDC5B5004E7149 /* Tunnel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Tunnel.swift; sourceTree = ""; }; D0B98FD829FDDB6F004E7149 /* libburrow.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = libburrow.h; sourceTree = ""; }; D0B98FDC29FDDDCF004E7149 /* module.modulemap */ = {isa = PBXFileReference; lastKnownFileType = "sourcecode.module-map"; path = module.modulemap; sourceTree = ""; }; - D0BCC5FC2A086D4700AD070D /* NetworkExtension+Async.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "NetworkExtension+Async.swift"; sourceTree = ""; }; D0BCC6032A09535900AD070D /* libburrow.a */ = {isa = PBXFileReference; lastKnownFileType = archive.ar; path = libburrow.a; sourceTree = BUILT_PRODUCTS_DIR; }; - D0FAB5912B818A5900F6A84B /* NetworkExtensionTunnel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = NetworkExtensionTunnel.swift; sourceTree = ""; }; - D0FAB5952B818B2900F6A84B /* TunnelButton.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TunnelButton.swift; sourceTree = ""; }; - D0FAB5972B818B8200F6A84B /* TunnelStatusView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TunnelStatusView.swift; sourceTree = ""; }; - D0FAB5992B818B9600F6A84B /* Network.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Network.swift; sourceTree = ""; }; + D0BF09582C8E6789000D8DEC /* UI.xcconfig */ = {isa = PBXFileReference; lastKnownFileType = text.xcconfig; path = UI.xcconfig; sourceTree = ""; }; + D0D4E4952C8D921A007F820A /* burrow.proto */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.protobuf; path = burrow.proto; sourceTree = ""; }; + D0D4E4962C8D921A007F820A /* grpc-swift-config.json */ = {isa = PBXFileReference; lastKnownFileType = text.json; path = "grpc-swift-config.json"; sourceTree = ""; }; + D0D4E4972C8D921A007F820A /* swift-protobuf-config.json */ = {isa = PBXFileReference; lastKnownFileType = text.json; path = "swift-protobuf-config.json"; sourceTree = ""; }; + D0D4E4992C8D921A007F820A /* Client.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Client.swift; sourceTree = ""; }; + D0D4E49A2C8D921A007F820A /* Logging.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Logging.swift; sourceTree = ""; }; + D0D4E49D2C8D921A007F820A /* HackClub.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = HackClub.swift; sourceTree = ""; }; + D0D4E49E2C8D921A007F820A /* Network.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Network.swift; sourceTree = ""; }; + D0D4E49F2C8D921A007F820A /* WireGuard.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = WireGuard.swift; sourceTree = ""; }; + D0D4E4A12C8D921A007F820A /* Assets.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = Assets.xcassets; sourceTree = ""; }; + D0D4E4A22C8D921A007F820A /* BurrowView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = BurrowView.swift; sourceTree = ""; }; + D0D4E4A32C8D921A007F820A /* FloatingButtonStyle.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = FloatingButtonStyle.swift; sourceTree = ""; }; + D0D4E4A42C8D921A007F820A /* MenuItemToggleView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MenuItemToggleView.swift; sourceTree = ""; }; + D0D4E4A52C8D921A007F820A /* NetworkCarouselView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = NetworkCarouselView.swift; sourceTree = ""; }; + D0D4E4A62C8D921A007F820A /* NetworkExtension+Async.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "NetworkExtension+Async.swift"; sourceTree = ""; }; + D0D4E4A72C8D921A007F820A /* NetworkExtensionTunnel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = NetworkExtensionTunnel.swift; sourceTree = ""; }; + D0D4E4A82C8D921A007F820A /* NetworkView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = NetworkView.swift; sourceTree = ""; }; + D0D4E4A92C8D921A007F820A /* OAuth2.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = OAuth2.swift; sourceTree = ""; }; + D0D4E4AA2C8D921A007F820A /* Tunnel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Tunnel.swift; sourceTree = ""; }; + D0D4E4AB2C8D921A007F820A /* TunnelButton.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TunnelButton.swift; sourceTree = ""; }; + D0D4E4AC2C8D921A007F820A /* TunnelStatusView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TunnelStatusView.swift; sourceTree = ""; }; + D0D4E4F62C8D932D007F820A /* Debug.xcconfig */ = {isa = PBXFileReference; lastKnownFileType = text.xcconfig; path = Debug.xcconfig; sourceTree = ""; }; + D0D4E4F72C8D941D007F820A /* Framework.xcconfig */ = {isa = PBXFileReference; lastKnownFileType = text.xcconfig; path = Framework.xcconfig; sourceTree = ""; }; + D0D4E5312C8D996F007F820A /* BurrowCore.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = BurrowCore.framework; sourceTree = BUILT_PRODUCTS_DIR; }; + D0D4E5582C8D9BF2007F820A /* BurrowUI.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = BurrowUI.framework; sourceTree = BUILT_PRODUCTS_DIR; }; + D0D4E5622C8D9BF4007F820A /* BurrowConfiguration.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = BurrowConfiguration.framework; sourceTree = BUILT_PRODUCTS_DIR; }; + D0D4E58E2C8D9D0A007F820A /* Constants.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = Constants.h; sourceTree = ""; }; + D0D4E58F2C8D9D0A007F820A /* Constants.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Constants.swift; sourceTree = ""; }; + D0D4E5902C8D9D0A007F820A /* module.modulemap */ = {isa = PBXFileReference; lastKnownFileType = "sourcecode.module-map"; path = module.modulemap; sourceTree = ""; }; /* End PBXFileReference section */ /* Begin PBXFrameworksBuildPhase section */ - D00117352B30341C00D87C25 /* Frameworks */ = { - isa = PBXFrameworksBuildPhase; - buildActionMask = 2147483647; - files = ( - ); - runOnlyForDeploymentPostprocessing = 0; - }; D020F65029E4A697002790F6 /* Frameworks */ = { isa = PBXFrameworksBuildPhase; buildActionMask = 2147483647; files = ( - D00117442B30372900D87C25 /* libBurrowShared.a in Frameworks */, + D0BF09522C8E66F6000D8DEC /* BurrowConfiguration.framework in Frameworks */, + D0D4E5A62C8D9E65007F820A /* BurrowCore.framework in Frameworks */, D0BCC6092A09A03E00AD070D /* libburrow.a in Frameworks */, + D0B1D1102C436152004B7823 /* AsyncAlgorithms in Frameworks */, ); runOnlyForDeploymentPostprocessing = 0; }; @@ -148,37 +201,36 @@ isa = PBXFrameworksBuildPhase; buildActionMask = 2147483647; files = ( - D00117452B30372C00D87C25 /* libBurrowShared.a in Frameworks */, + D0BF09552C8E66FD000D8DEC /* BurrowConfiguration.framework in Frameworks */, + D0F4FAD32C8DC79C0068730A /* BurrowCore.framework in Frameworks */, + D0D4E5892C8D9C94007F820A /* BurrowUI.framework in Frameworks */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; + D078F7CF2C8DA213008A8CEC /* Frameworks */ = { + isa = PBXFrameworksBuildPhase; + buildActionMask = 2147483647; + files = ( + D03383B02C8E67E300F7C44E /* NIOTransportServices in Frameworks */, + D03383AF2C8E67E300F7C44E /* NIOConcurrencyHelpers in Frameworks */, + D03383AE2C8E67E300F7C44E /* NIO in Frameworks */, + D03383AD2C8E67E300F7C44E /* SwiftProtobuf in Frameworks */, + D0F7594E2C8DAB6B00126CF3 /* GRPC in Frameworks */, + D0F7597E2C8DB30500126CF3 /* CGRPCZlib in Frameworks */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; + D0D4E5532C8D9BF2007F820A /* Frameworks */ = { + isa = PBXFrameworksBuildPhase; + buildActionMask = 2147483647; + files = ( + D0D4E5702C8D9C62007F820A /* BurrowCore.framework in Frameworks */, ); runOnlyForDeploymentPostprocessing = 0; }; /* End PBXFrameworksBuildPhase section */ /* Begin PBXGroup section */ - D00117392B30341C00D87C25 /* Shared */ = { - isa = PBXGroup; - children = ( - 0B28F1552ABF463A000D44B0 /* DataTypes.swift */, - D00117322B3001A400D87C25 /* NewlineProtocolFramer.swift */, - D00117302B2FFFC900D87C25 /* NWConnection+Async.swift */, - 0B46E8DF2AC918CA00BA2A3C /* Client.swift */, - D001173A2B30341C00D87C25 /* Logging.swift */, - D08252752B5C9FC4005DA378 /* Constants.swift */, - D00117422B30348D00D87C25 /* Shared.xcconfig */, - D001173F2B30347800D87C25 /* Constants */, - ); - path = Shared; - sourceTree = ""; - }; - D001173F2B30347800D87C25 /* Constants */ = { - isa = PBXGroup; - children = ( - D08252742B5C9DEB005DA378 /* Constants.h */, - D00117412B30347800D87C25 /* module.modulemap */, - ); - path = Constants; - sourceTree = ""; - }; D00117432B30372900D87C25 /* Frameworks */ = { isa = PBXGroup; children = ( @@ -192,9 +244,13 @@ D020F63D29E4A1FF002790F6 /* Identity.xcconfig */, D020F64A29E4A452002790F6 /* App.xcconfig */, D020F66329E4A703002790F6 /* Extension.xcconfig */, + D0D4E4F72C8D941D007F820A /* Framework.xcconfig */, D020F64029E4A1FF002790F6 /* Compiler.xcconfig */, + D0D4E4F62C8D932D007F820A /* Debug.xcconfig */, D04A3E1D2BAF465F0043EC85 /* Version.xcconfig */, D020F64229E4A1FF002790F6 /* Info.plist */, + D0D4E5912C8D9D0A007F820A /* Constants */, + D00117422B30348D00D87C25 /* Configuration.xcconfig */, ); path = Configuration; sourceTree = ""; @@ -212,22 +268,13 @@ path = NetworkExtension; sourceTree = ""; }; - D032E64D2B8A69C90006B8AD /* Networks */ = { - isa = PBXGroup; - children = ( - D0FAB5992B818B9600F6A84B /* Network.swift */, - D032E6512B8A79C20006B8AD /* HackClub.swift */, - D032E6532B8A79DA0006B8AD /* WireGuard.swift */, - ); - path = Networks; - sourceTree = ""; - }; D05B9F6929E39EEC008CB1F9 = { isa = PBXGroup; children = ( D05B9F7429E39EEC008CB1F9 /* App */, D020F65629E4A697002790F6 /* NetworkExtension */, - D00117392B30341C00D87C25 /* Shared */, + D0D4E49C2C8D921A007F820A /* Core */, + D0D4E4AD2C8D921A007F820A /* UI */, D020F63C29E4A1FF002790F6 /* Configuration */, D05B9F7329E39EEC008CB1F9 /* Products */, D00117432B30372900D87C25 /* Frameworks */, @@ -239,7 +286,10 @@ children = ( D05B9F7229E39EEC008CB1F9 /* Burrow.app */, D020F65329E4A697002790F6 /* BurrowNetworkExtension.appex */, - D00117382B30341C00D87C25 /* libBurrowShared.a */, + D0BCC6032A09535900AD070D /* libburrow.a */, + D0D4E5312C8D996F007F820A /* BurrowCore.framework */, + D0D4E5582C8D9BF2007F820A /* BurrowUI.framework */, + D0D4E5622C8D9BF4007F820A /* BurrowConfiguration.framework */, ); name = Products; sourceTree = ""; @@ -249,19 +299,6 @@ children = ( D05B9F7529E39EEC008CB1F9 /* BurrowApp.swift */, D00AA8962A4669BC005C8102 /* AppDelegate.swift */, - 43AA26D72A10004900F14CE6 /* MenuItemToggleView.swift */, - D05B9F7729E39EEC008CB1F9 /* BurrowView.swift */, - D000363C2BB8928E00E582EC /* NetworkCarouselView.swift */, - D01A79302B81630D0024EC91 /* NetworkView.swift */, - D000363E2BB895FB00E582EC /* OAuth2.swift */, - D032E64D2B8A69C90006B8AD /* Networks */, - D0FAB5972B818B8200F6A84B /* TunnelStatusView.swift */, - D0FAB5952B818B2900F6A84B /* TunnelButton.swift */, - D0B98FC629FDC5B5004E7149 /* Tunnel.swift */, - D0FAB5912B818A5900F6A84B /* NetworkExtensionTunnel.swift */, - D0BCC5FC2A086D4700AD070D /* NetworkExtension+Async.swift */, - D05EF8C72B81818D0017AB4F /* FloatingButtonStyle.swift */, - D05B9F7929E39EED008CB1F9 /* Assets.xcassets */, D09150412B9D2AF700BE3CB0 /* MainMenu.xib */, D020F66829E4AA74002790F6 /* App-iOS.entitlements */, D020F66929E4AA74002790F6 /* App-macOS.entitlements */, @@ -276,30 +313,74 @@ D0B98FBF29FD8072004E7149 /* build-rust.sh */, D0B98FDC29FDDDCF004E7149 /* module.modulemap */, D0B98FD829FDDB6F004E7149 /* libburrow.h */, - D0BCC6032A09535900AD070D /* libburrow.a */, ); path = libburrow; sourceTree = ""; }; + D0D4E4982C8D921A007F820A /* Client */ = { + isa = PBXGroup; + children = ( + D0D4E4952C8D921A007F820A /* burrow.proto */, + D0D4E4962C8D921A007F820A /* grpc-swift-config.json */, + D0D4E4972C8D921A007F820A /* swift-protobuf-config.json */, + ); + path = Client; + sourceTree = ""; + }; + D0D4E49C2C8D921A007F820A /* Core */ = { + isa = PBXGroup; + children = ( + D0D4E49A2C8D921A007F820A /* Logging.swift */, + D0D4E4992C8D921A007F820A /* Client.swift */, + D0D4E4982C8D921A007F820A /* Client */, + ); + path = Core; + sourceTree = ""; + }; + D0D4E4A02C8D921A007F820A /* Networks */ = { + isa = PBXGroup; + children = ( + D0D4E49D2C8D921A007F820A /* HackClub.swift */, + D0D4E49E2C8D921A007F820A /* Network.swift */, + D0D4E49F2C8D921A007F820A /* WireGuard.swift */, + ); + path = Networks; + sourceTree = ""; + }; + D0D4E4AD2C8D921A007F820A /* UI */ = { + isa = PBXGroup; + children = ( + D0D4E4A22C8D921A007F820A /* BurrowView.swift */, + D0D4E4A02C8D921A007F820A /* Networks */, + D0D4E4A32C8D921A007F820A /* FloatingButtonStyle.swift */, + D0D4E4A42C8D921A007F820A /* MenuItemToggleView.swift */, + D0D4E4A52C8D921A007F820A /* NetworkCarouselView.swift */, + D0D4E4A62C8D921A007F820A /* NetworkExtension+Async.swift */, + D0D4E4A72C8D921A007F820A /* NetworkExtensionTunnel.swift */, + D0D4E4A82C8D921A007F820A /* NetworkView.swift */, + D0D4E4A92C8D921A007F820A /* OAuth2.swift */, + D0D4E4AA2C8D921A007F820A /* Tunnel.swift */, + D0D4E4AB2C8D921A007F820A /* TunnelButton.swift */, + D0D4E4AC2C8D921A007F820A /* TunnelStatusView.swift */, + D0D4E4A12C8D921A007F820A /* Assets.xcassets */, + D0BF09582C8E6789000D8DEC /* UI.xcconfig */, + ); + path = UI; + sourceTree = ""; + }; + D0D4E5912C8D9D0A007F820A /* Constants */ = { + isa = PBXGroup; + children = ( + D0D4E58E2C8D9D0A007F820A /* Constants.h */, + D0D4E58F2C8D9D0A007F820A /* Constants.swift */, + D0D4E5902C8D9D0A007F820A /* module.modulemap */, + ); + path = Constants; + sourceTree = ""; + }; /* End PBXGroup section */ /* Begin PBXNativeTarget section */ - D00117372B30341C00D87C25 /* Shared */ = { - isa = PBXNativeTarget; - buildConfigurationList = D001173C2B30341C00D87C25 /* Build configuration list for PBXNativeTarget "Shared" */; - buildPhases = ( - D00117342B30341C00D87C25 /* Sources */, - D00117352B30341C00D87C25 /* Frameworks */, - ); - buildRules = ( - ); - dependencies = ( - ); - name = Shared; - productName = Shared; - productReference = D00117382B30341C00D87C25 /* libBurrowShared.a */; - productType = "com.apple.product-type.library.static"; - }; D020F65229E4A697002790F6 /* NetworkExtension */ = { isa = PBXNativeTarget; buildConfigurationList = D020F65E29E4A697002790F6 /* Build configuration list for PBXNativeTarget "NetworkExtension" */; @@ -307,12 +388,12 @@ D0BCC60B2A09A0C100AD070D /* Compile Rust */, D020F64F29E4A697002790F6 /* Sources */, D020F65029E4A697002790F6 /* Frameworks */, - D020F65129E4A697002790F6 /* Resources */, ); buildRules = ( ); dependencies = ( - D00117492B30373500D87C25 /* PBXTargetDependency */, + D0BF09512C8E66F1000D8DEC /* PBXTargetDependency */, + D0D4E5802C8D9C78007F820A /* PBXTargetDependency */, ); name = NetworkExtension; productName = BurrowNetworkExtension; @@ -323,16 +404,18 @@ isa = PBXNativeTarget; buildConfigurationList = D05B9F8129E39EED008CB1F9 /* Build configuration list for PBXNativeTarget "App" */; buildPhases = ( - D04A3E232BAF4AE50043EC85 /* Update Build Number */, D05B9F6E29E39EEC008CB1F9 /* Sources */, D05B9F6F29E39EEC008CB1F9 /* Frameworks */, D05B9F7029E39EEC008CB1F9 /* Resources */, + D0D4E53F2C8D996F007F820A /* Embed Frameworks */, D020F66129E4A697002790F6 /* Embed Foundation Extensions */, ); buildRules = ( ); dependencies = ( - D00117472B30373100D87C25 /* PBXTargetDependency */, + D0BF09542C8E66FA000D8DEC /* PBXTargetDependency */, + D0F4FAD22C8DC7960068730A /* PBXTargetDependency */, + D0D4E5882C8D9C88007F820A /* PBXTargetDependency */, D020F65C29E4A697002790F6 /* PBXTargetDependency */, ); name = App; @@ -340,6 +423,71 @@ productReference = D05B9F7229E39EEC008CB1F9 /* Burrow.app */; productType = "com.apple.product-type.application"; }; + D0D4E5302C8D996F007F820A /* Core */ = { + isa = PBXNativeTarget; + buildConfigurationList = D0D4E53C2C8D996F007F820A /* Build configuration list for PBXNativeTarget "Core" */; + buildPhases = ( + D0D4E52D2C8D996F007F820A /* Sources */, + D078F7CF2C8DA213008A8CEC /* Frameworks */, + ); + buildRules = ( + ); + dependencies = ( + D0F7598A2C8DB34200126CF3 /* PBXTargetDependency */, + D0F7595E2C8DB24400126CF3 /* PBXTargetDependency */, + D0F759602C8DB24400126CF3 /* PBXTargetDependency */, + ); + name = Core; + packageProductDependencies = ( + D078F7E02C8DA375008A8CEC /* GRPC */, + D078F7E22C8DA375008A8CEC /* SwiftProtobuf */, + D044EE902C8DAB2000778185 /* NIO */, + D044EE922C8DAB2000778185 /* NIOConcurrencyHelpers */, + D044EE952C8DAB2800778185 /* NIOTransportServices */, + D0F7597D2C8DB30500126CF3 /* CGRPCZlib */, + ); + productName = Core; + productReference = D0D4E5312C8D996F007F820A /* BurrowCore.framework */; + productType = "com.apple.product-type.framework"; + }; + D0D4E5502C8D9BF2007F820A /* UI */ = { + isa = PBXNativeTarget; + buildConfigurationList = D0D4E5552C8D9BF2007F820A /* Build configuration list for PBXNativeTarget "UI" */; + buildPhases = ( + D0D4E5522C8D9BF2007F820A /* Sources */, + D0D4E5532C8D9BF2007F820A /* Frameworks */, + D0D4E5542C8D9BF2007F820A /* Resources */, + ); + buildRules = ( + ); + dependencies = ( + D0D4E56F2C8D9C5D007F820A /* PBXTargetDependency */, + ); + name = UI; + packageProductDependencies = ( + ); + productName = Core; + productReference = D0D4E5582C8D9BF2007F820A /* BurrowUI.framework */; + productType = "com.apple.product-type.framework"; + }; + D0D4E55A2C8D9BF4007F820A /* Configuration */ = { + isa = PBXNativeTarget; + buildConfigurationList = D0D4E55F2C8D9BF4007F820A /* Build configuration list for PBXNativeTarget "Configuration" */; + buildPhases = ( + D0F759912C8DB49E00126CF3 /* Configure Version */, + D0D4E55C2C8D9BF4007F820A /* Sources */, + ); + buildRules = ( + ); + dependencies = ( + ); + name = Configuration; + packageProductDependencies = ( + ); + productName = Core; + productReference = D0D4E5622C8D9BF4007F820A /* BurrowConfiguration.framework */; + productType = "com.apple.product-type.framework"; + }; /* End PBXNativeTarget section */ /* Begin PBXProject section */ @@ -347,18 +495,18 @@ isa = PBXProject; attributes = { BuildIndependentTargetsInParallel = 1; - LastSwiftUpdateCheck = 1510; + LastSwiftUpdateCheck = 1600; LastUpgradeCheck = 1520; TargetAttributes = { - D00117372B30341C00D87C25 = { - CreatedOnToolsVersion = 15.1; - }; D020F65229E4A697002790F6 = { CreatedOnToolsVersion = 14.3; }; D05B9F7129E39EEC008CB1F9 = { CreatedOnToolsVersion = 14.3; }; + D0D4E5302C8D996F007F820A = { + CreatedOnToolsVersion = 16.0; + }; }; }; buildConfigurationList = D05B9F6D29E39EEC008CB1F9 /* Build configuration list for PBXProject "Burrow" */; @@ -371,6 +519,11 @@ ); mainGroup = D05B9F6929E39EEC008CB1F9; packageReferences = ( + D0B1D10E2C436152004B7823 /* XCRemoteSwiftPackageReference "swift-async-algorithms" */, + D0D4E4822C8D8EF6007F820A /* XCRemoteSwiftPackageReference "grpc-swift" */, + D0D4E4852C8D8F29007F820A /* XCRemoteSwiftPackageReference "swift-protobuf" */, + D044EE8F2C8DAB2000778185 /* XCRemoteSwiftPackageReference "swift-nio" */, + D044EE942C8DAB2800778185 /* XCRemoteSwiftPackageReference "swift-nio-transport-services" */, ); productRefGroup = D05B9F7329E39EEC008CB1F9 /* Products */; projectDirPath = ""; @@ -378,52 +531,32 @@ targets = ( D05B9F7129E39EEC008CB1F9 /* App */, D020F65229E4A697002790F6 /* NetworkExtension */, - D00117372B30341C00D87C25 /* Shared */, + D0D4E5502C8D9BF2007F820A /* UI */, + D0D4E5302C8D996F007F820A /* Core */, + D0D4E55A2C8D9BF4007F820A /* Configuration */, ); }; /* End PBXProject section */ /* Begin PBXResourcesBuildPhase section */ - D020F65129E4A697002790F6 /* Resources */ = { - isa = PBXResourcesBuildPhase; - buildActionMask = 2147483647; - files = ( - ); - runOnlyForDeploymentPostprocessing = 0; - }; D05B9F7029E39EEC008CB1F9 /* Resources */ = { isa = PBXResourcesBuildPhase; buildActionMask = 2147483647; files = ( - D05B9F7A29E39EED008CB1F9 /* Assets.xcassets in Resources */, D09150422B9D2AF700BE3CB0 /* MainMenu.xib in Resources */, ); runOnlyForDeploymentPostprocessing = 0; }; + D0D4E5542C8D9BF2007F820A /* Resources */ = { + isa = PBXResourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + runOnlyForDeploymentPostprocessing = 0; + }; /* End PBXResourcesBuildPhase section */ /* Begin PBXShellScriptBuildPhase section */ - D04A3E232BAF4AE50043EC85 /* Update Build Number */ = { - isa = PBXShellScriptBuildPhase; - buildActionMask = 2147483647; - files = ( - ); - inputFileListPaths = ( - ); - inputPaths = ( - "$(PROJECT_DIR)/../Tools/version.sh", - "$(PROJECT_DIR)/../.git", - ); - name = "Update Build Number"; - outputFileListPaths = ( - ); - outputPaths = ( - "$(PROJECT_DIR)/Configuration/Version.xcconfig", - ); - runOnlyForDeploymentPostprocessing = 0; - shellPath = /bin/sh; - shellScript = "\"$PROJECT_DIR/../Tools/version.sh\"\n"; - }; D0BCC60B2A09A0C100AD070D /* Compile Rust */ = { isa = PBXShellScriptBuildPhase; alwaysOutOfDate = 1; @@ -444,22 +577,31 @@ shellScript = "\"${PROJECT_DIR}/NetworkExtension/libburrow/build-rust.sh\"\n"; showEnvVarsInLog = 0; }; + D0F759912C8DB49E00126CF3 /* Configure Version */ = { + isa = PBXShellScriptBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + inputFileListPaths = ( + ); + inputPaths = ( + "$(PROJECT_DIR)/../Tools/version.sh", + "$(PROJECT_DIR)/../.git", + ); + name = "Configure Version"; + outputFileListPaths = ( + ); + outputPaths = ( + "$(PROJECT_DIR)/Configuration/Version.xcconfig", + ); + runOnlyForDeploymentPostprocessing = 0; + shellPath = /bin/sh; + shellScript = "\"$PROJECT_DIR/../Tools/version.sh\"\n"; + showEnvVarsInLog = 0; + }; /* End PBXShellScriptBuildPhase section */ /* Begin PBXSourcesBuildPhase section */ - D00117342B30341C00D87C25 /* Sources */ = { - isa = PBXSourcesBuildPhase; - buildActionMask = 2147483647; - files = ( - D001173B2B30341C00D87C25 /* Logging.swift in Sources */, - 0BA6D73C2BA6393200BD4B55 /* NWConnection+Async.swift in Sources */, - D08252762B5C9FC4005DA378 /* Constants.swift in Sources */, - 0BA6D73E2BA6394B00BD4B55 /* DataTypes.swift in Sources */, - 0BA6D73B2BA638D900BD4B55 /* Client.swift in Sources */, - 0BA6D73D2BA6393B00BD4B55 /* NewlineProtocolFramer.swift in Sources */, - ); - runOnlyForDeploymentPostprocessing = 0; - }; D020F64F29E4A697002790F6 /* Sources */ = { isa = PBXSourcesBuildPhase; buildActionMask = 2147483647; @@ -472,60 +614,104 @@ isa = PBXSourcesBuildPhase; buildActionMask = 2147483647; files = ( - D0FAB59A2B818B9600F6A84B /* Network.swift in Sources */, - D0BCC6082A0981FE00AD070D /* Tunnel.swift in Sources */, - D0FAB5982B818B8200F6A84B /* TunnelStatusView.swift in Sources */, - 43AA26D82A10004900F14CE6 /* MenuItemToggleView.swift in Sources */, - D05B9F7829E39EEC008CB1F9 /* BurrowView.swift in Sources */, - D0FAB5922B818A5900F6A84B /* NetworkExtensionTunnel.swift in Sources */, - D000363F2BB895FB00E582EC /* OAuth2.swift in Sources */, - D0FAB5962B818B2900F6A84B /* TunnelButton.swift in Sources */, D00AA8972A4669BC005C8102 /* AppDelegate.swift in Sources */, - D05EF8C82B81818D0017AB4F /* FloatingButtonStyle.swift in Sources */, - D032E6522B8A79C20006B8AD /* HackClub.swift in Sources */, D05B9F7629E39EEC008CB1F9 /* BurrowApp.swift in Sources */, - D01A79312B81630D0024EC91 /* NetworkView.swift in Sources */, - D032E6542B8A79DA0006B8AD /* WireGuard.swift in Sources */, - D0BCC5FD2A086D4700AD070D /* NetworkExtension+Async.swift in Sources */, - D000363D2BB8928E00E582EC /* NetworkCarouselView.swift in Sources */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; + D0D4E52D2C8D996F007F820A /* Sources */ = { + isa = PBXSourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + D0F759612C8DB24B00126CF3 /* grpc-swift-config.json in Sources */, + D0F759622C8DB24B00126CF3 /* swift-protobuf-config.json in Sources */, + D0F7598D2C8DB3DA00126CF3 /* Client.swift in Sources */, + D0D4E56B2C8D9C2F007F820A /* Logging.swift in Sources */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; + D0D4E5522C8D9BF2007F820A /* Sources */ = { + isa = PBXSourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + D0D4E5712C8D9C6F007F820A /* HackClub.swift in Sources */, + D0D4E5722C8D9C6F007F820A /* Network.swift in Sources */, + D0D4E5732C8D9C6F007F820A /* WireGuard.swift in Sources */, + D0D4E5742C8D9C6F007F820A /* BurrowView.swift in Sources */, + D0D4E5752C8D9C6F007F820A /* FloatingButtonStyle.swift in Sources */, + D0D4E5762C8D9C6F007F820A /* MenuItemToggleView.swift in Sources */, + D0D4E5772C8D9C6F007F820A /* NetworkCarouselView.swift in Sources */, + D0D4E5782C8D9C6F007F820A /* NetworkExtension+Async.swift in Sources */, + D0D4E5792C8D9C6F007F820A /* NetworkExtensionTunnel.swift in Sources */, + D0D4E57A2C8D9C6F007F820A /* NetworkView.swift in Sources */, + D0D4E57B2C8D9C6F007F820A /* OAuth2.swift in Sources */, + D0D4E57C2C8D9C6F007F820A /* Tunnel.swift in Sources */, + D0D4E57D2C8D9C6F007F820A /* TunnelButton.swift in Sources */, + D0D4E57E2C8D9C6F007F820A /* TunnelStatusView.swift in Sources */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; + D0D4E55C2C8D9BF4007F820A /* Sources */ = { + isa = PBXSourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + D0D4E5922C8D9D15007F820A /* Constants.swift in Sources */, ); runOnlyForDeploymentPostprocessing = 0; }; /* End PBXSourcesBuildPhase section */ /* Begin PBXTargetDependency section */ - D00117472B30373100D87C25 /* PBXTargetDependency */ = { - isa = PBXTargetDependency; - target = D00117372B30341C00D87C25 /* Shared */; - targetProxy = D00117462B30373100D87C25 /* PBXContainerItemProxy */; - }; - D00117492B30373500D87C25 /* PBXTargetDependency */ = { - isa = PBXTargetDependency; - target = D00117372B30341C00D87C25 /* Shared */; - targetProxy = D00117482B30373500D87C25 /* PBXContainerItemProxy */; - }; D020F65C29E4A697002790F6 /* PBXTargetDependency */ = { isa = PBXTargetDependency; target = D020F65229E4A697002790F6 /* NetworkExtension */; targetProxy = D020F65B29E4A697002790F6 /* PBXContainerItemProxy */; }; + D0BF09512C8E66F1000D8DEC /* PBXTargetDependency */ = { + isa = PBXTargetDependency; + target = D0D4E55A2C8D9BF4007F820A /* Configuration */; + targetProxy = D0BF09502C8E66F1000D8DEC /* PBXContainerItemProxy */; + }; + D0BF09542C8E66FA000D8DEC /* PBXTargetDependency */ = { + isa = PBXTargetDependency; + target = D0D4E55A2C8D9BF4007F820A /* Configuration */; + targetProxy = D0BF09532C8E66FA000D8DEC /* PBXContainerItemProxy */; + }; + D0D4E56F2C8D9C5D007F820A /* PBXTargetDependency */ = { + isa = PBXTargetDependency; + target = D0D4E5302C8D996F007F820A /* Core */; + targetProxy = D0D4E56E2C8D9C5D007F820A /* PBXContainerItemProxy */; + }; + D0D4E5802C8D9C78007F820A /* PBXTargetDependency */ = { + isa = PBXTargetDependency; + target = D0D4E5302C8D996F007F820A /* Core */; + targetProxy = D0D4E57F2C8D9C78007F820A /* PBXContainerItemProxy */; + }; + D0D4E5882C8D9C88007F820A /* PBXTargetDependency */ = { + isa = PBXTargetDependency; + target = D0D4E5502C8D9BF2007F820A /* UI */; + targetProxy = D0D4E5872C8D9C88007F820A /* PBXContainerItemProxy */; + }; + D0F4FAD22C8DC7960068730A /* PBXTargetDependency */ = { + isa = PBXTargetDependency; + target = D0D4E5302C8D996F007F820A /* Core */; + targetProxy = D0F4FAD12C8DC7960068730A /* PBXContainerItemProxy */; + }; + D0F7595E2C8DB24400126CF3 /* PBXTargetDependency */ = { + isa = PBXTargetDependency; + productRef = D0F7595D2C8DB24400126CF3 /* GRPCSwiftPlugin */; + }; + D0F759602C8DB24400126CF3 /* PBXTargetDependency */ = { + isa = PBXTargetDependency; + productRef = D0F7595F2C8DB24400126CF3 /* SwiftProtobufPlugin */; + }; + D0F7598A2C8DB34200126CF3 /* PBXTargetDependency */ = { + isa = PBXTargetDependency; + productRef = D0F759892C8DB34200126CF3 /* GRPC */; + }; /* End PBXTargetDependency section */ /* Begin XCBuildConfiguration section */ - D001173D2B30341C00D87C25 /* Debug */ = { - isa = XCBuildConfiguration; - baseConfigurationReference = D00117422B30348D00D87C25 /* Shared.xcconfig */; - buildSettings = { - }; - name = Debug; - }; - D001173E2B30341C00D87C25 /* Release */ = { - isa = XCBuildConfiguration; - baseConfigurationReference = D00117422B30348D00D87C25 /* Shared.xcconfig */; - buildSettings = { - }; - name = Release; - }; D020F65F29E4A697002790F6 /* Debug */ = { isa = XCBuildConfiguration; baseConfigurationReference = D020F66229E4A6E5002790F6 /* NetworkExtension.xcconfig */; @@ -568,18 +754,51 @@ }; name = Release; }; + D0D4E53D2C8D996F007F820A /* Debug */ = { + isa = XCBuildConfiguration; + baseConfigurationReference = D0D4E4F72C8D941D007F820A /* Framework.xcconfig */; + buildSettings = { + }; + name = Debug; + }; + D0D4E53E2C8D996F007F820A /* Release */ = { + isa = XCBuildConfiguration; + baseConfigurationReference = D0D4E4F72C8D941D007F820A /* Framework.xcconfig */; + buildSettings = { + }; + name = Release; + }; + D0D4E5562C8D9BF2007F820A /* Debug */ = { + isa = XCBuildConfiguration; + baseConfigurationReference = D0BF09582C8E6789000D8DEC /* UI.xcconfig */; + buildSettings = { + }; + name = Debug; + }; + D0D4E5572C8D9BF2007F820A /* Release */ = { + isa = XCBuildConfiguration; + baseConfigurationReference = D0BF09582C8E6789000D8DEC /* UI.xcconfig */; + buildSettings = { + }; + name = Release; + }; + D0D4E5602C8D9BF4007F820A /* Debug */ = { + isa = XCBuildConfiguration; + baseConfigurationReference = D00117422B30348D00D87C25 /* Configuration.xcconfig */; + buildSettings = { + }; + name = Debug; + }; + D0D4E5612C8D9BF4007F820A /* Release */ = { + isa = XCBuildConfiguration; + baseConfigurationReference = D00117422B30348D00D87C25 /* Configuration.xcconfig */; + buildSettings = { + }; + name = Release; + }; /* End XCBuildConfiguration section */ /* Begin XCConfigurationList section */ - D001173C2B30341C00D87C25 /* Build configuration list for PBXNativeTarget "Shared" */ = { - isa = XCConfigurationList; - buildConfigurations = ( - D001173D2B30341C00D87C25 /* Debug */, - D001173E2B30341C00D87C25 /* Release */, - ); - defaultConfigurationIsVisible = 0; - defaultConfigurationName = Release; - }; D020F65E29E4A697002790F6 /* Build configuration list for PBXNativeTarget "NetworkExtension" */ = { isa = XCConfigurationList; buildConfigurations = ( @@ -607,7 +826,130 @@ defaultConfigurationIsVisible = 0; defaultConfigurationName = Release; }; + D0D4E53C2C8D996F007F820A /* Build configuration list for PBXNativeTarget "Core" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + D0D4E53D2C8D996F007F820A /* Debug */, + D0D4E53E2C8D996F007F820A /* Release */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Release; + }; + D0D4E5552C8D9BF2007F820A /* Build configuration list for PBXNativeTarget "UI" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + D0D4E5562C8D9BF2007F820A /* Debug */, + D0D4E5572C8D9BF2007F820A /* Release */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Release; + }; + D0D4E55F2C8D9BF4007F820A /* Build configuration list for PBXNativeTarget "Configuration" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + D0D4E5602C8D9BF4007F820A /* Debug */, + D0D4E5612C8D9BF4007F820A /* Release */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Release; + }; /* End XCConfigurationList section */ + +/* Begin XCRemoteSwiftPackageReference section */ + D044EE8F2C8DAB2000778185 /* XCRemoteSwiftPackageReference "swift-nio" */ = { + isa = XCRemoteSwiftPackageReference; + repositoryURL = "https://github.com/apple/swift-nio.git"; + requirement = { + kind = upToNextMajorVersion; + minimumVersion = 2.72.0; + }; + }; + D044EE942C8DAB2800778185 /* XCRemoteSwiftPackageReference "swift-nio-transport-services" */ = { + isa = XCRemoteSwiftPackageReference; + repositoryURL = "https://github.com/apple/swift-nio-transport-services.git"; + requirement = { + kind = upToNextMajorVersion; + minimumVersion = 1.21.0; + }; + }; + D0B1D10E2C436152004B7823 /* XCRemoteSwiftPackageReference "swift-async-algorithms" */ = { + isa = XCRemoteSwiftPackageReference; + repositoryURL = "https://github.com/apple/swift-async-algorithms.git"; + requirement = { + kind = upToNextMajorVersion; + minimumVersion = 1.0.1; + }; + }; + D0D4E4822C8D8EF6007F820A /* XCRemoteSwiftPackageReference "grpc-swift" */ = { + isa = XCRemoteSwiftPackageReference; + repositoryURL = "https://github.com/grpc/grpc-swift.git"; + requirement = { + kind = upToNextMajorVersion; + minimumVersion = 1.23.0; + }; + }; + D0D4E4852C8D8F29007F820A /* XCRemoteSwiftPackageReference "swift-protobuf" */ = { + isa = XCRemoteSwiftPackageReference; + repositoryURL = "https://github.com/apple/swift-protobuf.git"; + requirement = { + kind = upToNextMajorVersion; + minimumVersion = 1.28.1; + }; + }; +/* End XCRemoteSwiftPackageReference section */ + +/* Begin XCSwiftPackageProductDependency section */ + D044EE902C8DAB2000778185 /* NIO */ = { + isa = XCSwiftPackageProductDependency; + package = D044EE8F2C8DAB2000778185 /* XCRemoteSwiftPackageReference "swift-nio" */; + productName = NIO; + }; + D044EE922C8DAB2000778185 /* NIOConcurrencyHelpers */ = { + isa = XCSwiftPackageProductDependency; + package = D044EE8F2C8DAB2000778185 /* XCRemoteSwiftPackageReference "swift-nio" */; + productName = NIOConcurrencyHelpers; + }; + D044EE952C8DAB2800778185 /* NIOTransportServices */ = { + isa = XCSwiftPackageProductDependency; + package = D044EE942C8DAB2800778185 /* XCRemoteSwiftPackageReference "swift-nio-transport-services" */; + productName = NIOTransportServices; + }; + D078F7E02C8DA375008A8CEC /* GRPC */ = { + isa = XCSwiftPackageProductDependency; + package = D0D4E4822C8D8EF6007F820A /* XCRemoteSwiftPackageReference "grpc-swift" */; + productName = GRPC; + }; + D078F7E22C8DA375008A8CEC /* SwiftProtobuf */ = { + isa = XCSwiftPackageProductDependency; + package = D0D4E4852C8D8F29007F820A /* XCRemoteSwiftPackageReference "swift-protobuf" */; + productName = SwiftProtobuf; + }; + D0B1D10F2C436152004B7823 /* AsyncAlgorithms */ = { + isa = XCSwiftPackageProductDependency; + package = D0B1D10E2C436152004B7823 /* XCRemoteSwiftPackageReference "swift-async-algorithms" */; + productName = AsyncAlgorithms; + }; + D0F7595D2C8DB24400126CF3 /* GRPCSwiftPlugin */ = { + isa = XCSwiftPackageProductDependency; + package = D0D4E4822C8D8EF6007F820A /* XCRemoteSwiftPackageReference "grpc-swift" */; + productName = "plugin:GRPCSwiftPlugin"; + }; + D0F7595F2C8DB24400126CF3 /* SwiftProtobufPlugin */ = { + isa = XCSwiftPackageProductDependency; + package = D0D4E4852C8D8F29007F820A /* XCRemoteSwiftPackageReference "swift-protobuf" */; + productName = "plugin:SwiftProtobufPlugin"; + }; + D0F7597D2C8DB30500126CF3 /* CGRPCZlib */ = { + isa = XCSwiftPackageProductDependency; + package = D0D4E4822C8D8EF6007F820A /* XCRemoteSwiftPackageReference "grpc-swift" */; + productName = CGRPCZlib; + }; + D0F759892C8DB34200126CF3 /* GRPC */ = { + isa = XCSwiftPackageProductDependency; + package = D0D4E4822C8D8EF6007F820A /* XCRemoteSwiftPackageReference "grpc-swift" */; + productName = GRPC; + }; +/* End XCSwiftPackageProductDependency section */ }; rootObject = D05B9F6A29E39EEC008CB1F9 /* Project object */; } diff --git a/Apple/Burrow.xcodeproj/project.xcworkspace/xcshareddata/swiftpm/Package.resolved b/Apple/Burrow.xcodeproj/project.xcworkspace/xcshareddata/swiftpm/Package.resolved new file mode 100644 index 0000000..739b77c --- /dev/null +++ b/Apple/Burrow.xcodeproj/project.xcworkspace/xcshareddata/swiftpm/Package.resolved @@ -0,0 +1,123 @@ +{ + "originHash" : "fa512b990383b7e309c5854a5279817052294a8191a6d3c55c49cfb38e88c0c3", + "pins" : [ + { + "identity" : "grpc-swift", + "kind" : "remoteSourceControl", + "location" : "https://github.com/grpc/grpc-swift.git", + "state" : { + "revision" : "6a90b7e77e29f9bda6c2b3a4165a40d6c02cfda1", + "version" : "1.23.0" + } + }, + { + "identity" : "swift-async-algorithms", + "kind" : "remoteSourceControl", + "location" : "https://github.com/apple/swift-async-algorithms.git", + "state" : { + "revision" : "6ae9a051f76b81cc668305ceed5b0e0a7fd93d20", + "version" : "1.0.1" + } + }, + { + "identity" : "swift-atomics", + "kind" : "remoteSourceControl", + "location" : "https://github.com/apple/swift-atomics.git", + "state" : { + "revision" : "cd142fd2f64be2100422d658e7411e39489da985", + "version" : "1.2.0" + } + }, + { + "identity" : "swift-collections", + "kind" : "remoteSourceControl", + "location" : "https://github.com/apple/swift-collections.git", + "state" : { + "revision" : "9bf03ff58ce34478e66aaee630e491823326fd06", + "version" : "1.1.3" + } + }, + { + "identity" : "swift-http-types", + "kind" : "remoteSourceControl", + "location" : "https://github.com/apple/swift-http-types", + "state" : { + "revision" : "ae67c8178eb46944fd85e4dc6dd970e1f3ed6ccd", + "version" : "1.3.0" + } + }, + { + "identity" : "swift-log", + "kind" : "remoteSourceControl", + "location" : "https://github.com/apple/swift-log.git", + "state" : { + "revision" : "9cb486020ebf03bfa5b5df985387a14a98744537", + "version" : "1.6.1" + } + }, + { + "identity" : "swift-nio", + "kind" : "remoteSourceControl", + "location" : "https://github.com/apple/swift-nio.git", + "state" : { + "revision" : "9746cf80e29edfef2a39924a66731249223f42a3", + "version" : "2.72.0" + } + }, + { + "identity" : "swift-nio-extras", + "kind" : "remoteSourceControl", + "location" : "https://github.com/apple/swift-nio-extras.git", + "state" : { + "revision" : "d1ead62745cc3269e482f1c51f27608057174379", + "version" : "1.24.0" + } + }, + { + "identity" : "swift-nio-http2", + "kind" : "remoteSourceControl", + "location" : "https://github.com/apple/swift-nio-http2.git", + "state" : { + "revision" : "b5f7062b60e4add1e8c343ba4eb8da2e324b3a94", + "version" : "1.34.0" + } + }, + { + "identity" : "swift-nio-ssl", + "kind" : "remoteSourceControl", + "location" : "https://github.com/apple/swift-nio-ssl.git", + "state" : { + "revision" : "7b84abbdcef69cc3be6573ac12440220789dcd69", + "version" : "2.27.2" + } + }, + { + "identity" : "swift-nio-transport-services", + "kind" : "remoteSourceControl", + "location" : "https://github.com/apple/swift-nio-transport-services.git", + "state" : { + "revision" : "38ac8221dd20674682148d6451367f89c2652980", + "version" : "1.21.0" + } + }, + { + "identity" : "swift-protobuf", + "kind" : "remoteSourceControl", + "location" : "https://github.com/apple/swift-protobuf.git", + "state" : { + "revision" : "edb6ed4919f7756157fe02f2552b7e3850a538e5", + "version" : "1.28.1" + } + }, + { + "identity" : "swift-system", + "kind" : "remoteSourceControl", + "location" : "https://github.com/apple/swift-system.git", + "state" : { + "revision" : "d2ba781702a1d8285419c15ee62fd734a9437ff5", + "version" : "1.3.2" + } + } + ], + "version" : 3 +} diff --git a/Apple/Burrow.xcodeproj/xcshareddata/xcschemes/App.xcscheme b/Apple/Burrow.xcodeproj/xcshareddata/xcschemes/App.xcscheme index 670823d..a524e87 100644 --- a/Apple/Burrow.xcodeproj/xcshareddata/xcschemes/App.xcscheme +++ b/Apple/Burrow.xcodeproj/xcshareddata/xcschemes/App.xcscheme @@ -1,10 +1,11 @@ + buildImplicitDependencies = "YES" + buildArchitectures = "Automatic"> + buildImplicitDependencies = "YES" + buildArchitectures = "Automatic"> = { - guard let groupContainerURL = FileManager.default - .containerURL(forSecurityApplicationGroupIdentifier: appGroupIdentifier) else { - return .failure(.invalidAppGroupIdentifier) - } - return .success(groupContainerURL) - }() public static var socketURL: URL { get throws { try groupContainerURL.appending(component: "burrow.sock", directoryHint: .notDirectory) } } - public static var dbURL: URL { + public static var databaseURL: URL { get throws { try groupContainerURL.appending(component: "burrow.db", directoryHint: .notDirectory) } } + + private static var groupContainerURL: URL { + get throws { try _groupContainerURL.get() } + } + private static let _groupContainerURL: Result = { + switch FileManager.default.containerURL(forSecurityApplicationGroupIdentifier: appGroupIdentifier) { + case .some(let url): .success(url) + case .none: .failure(.invalidAppGroupIdentifier) + } + }() +} + +extension Logger { + @_dynamicReplacement(for: subsystem) + public static var subsystem: String { Constants.bundleIdentifier } } diff --git a/Apple/Shared/Constants/module.modulemap b/Apple/Configuration/Constants/module.modulemap similarity index 66% rename from Apple/Shared/Constants/module.modulemap rename to Apple/Configuration/Constants/module.modulemap index 7ee21fc..0e60f32 100644 --- a/Apple/Shared/Constants/module.modulemap +++ b/Apple/Configuration/Constants/module.modulemap @@ -1,4 +1,4 @@ -module Constants { +module CConstants { header "Constants.h" export * } diff --git a/Apple/Configuration/Debug.xcconfig b/Apple/Configuration/Debug.xcconfig new file mode 100644 index 0000000..9529dbd --- /dev/null +++ b/Apple/Configuration/Debug.xcconfig @@ -0,0 +1,26 @@ +// Release +DEBUG_INFORMATION_FORMAT = dwarf-with-dsym +SWIFT_COMPILATION_MODE = wholemodule +SWIFT_OPTIMIZATION_LEVEL = -Osize +LLVM_LTO = YES +DEAD_CODE_STRIPPING = YES +STRIP_INSTALLED_PRODUCT = YES +STRIP_SWIFT_SYMBOLS = YES +COPY_PHASE_STRIP = NO +VALIDATE_PRODUCT = YES +ENABLE_MODULE_VERIFIER = YES + +// Debug +ONLY_ACTIVE_ARCH[config=Debug] = YES +DEBUG_INFORMATION_FORMAT[config=Debug] = dwarf +ENABLE_TESTABILITY[config=Debug] = YES +GCC_PREPROCESSOR_DEFINITIONS[config=Debug] = DEBUG=1 $(inherited) +SWIFT_OPTIMIZATION_LEVEL[config=Debug] = -Onone +SWIFT_ACTIVE_COMPILATION_CONDITIONS[config=Debug] = DEBUG +SWIFT_COMPILATION_MODE[config=Debug] = singlefile +LLVM_LTO[config=Debug] = NO +DEAD_CODE_STRIPPING[config=Debug] = NO +VALIDATE_PRODUCT[config=Debug] = NO +STRIP_INSTALLED_PRODUCT[config=Debug] = NO +STRIP_SWIFT_SYMBOLS[config=Debug] = NO +ENABLE_MODULE_VERIFIER[config=Debug] = NO diff --git a/Apple/Configuration/Extension.xcconfig b/Apple/Configuration/Extension.xcconfig index f8d90a3..5885c31 100644 --- a/Apple/Configuration/Extension.xcconfig +++ b/Apple/Configuration/Extension.xcconfig @@ -1,4 +1,6 @@ -MERGED_BINARY_TYPE = manual +LD_EXPORT_SYMBOLS = NO + +OTHER_SWIFT_FLAGS = $(inherited) -Xfrontend -disable-autolink-framework -Xfrontend UIKit -Xfrontend -disable-autolink-framework -Xfrontend AppKit -Xfrontend -disable-autolink-framework -Xfrontend SwiftUI LD_RUNPATH_SEARCH_PATHS = $(inherited) @executable_path/Frameworks @executable_path/../../Frameworks -LD_RUNPATH_SEARCH_PATHS[sdk=macos*] = $(inherited) @executable_path/../Frameworks @executable_path/../../../../Frameworks +LD_RUNPATH_SEARCH_PATHS[sdk=macosx*] = $(inherited) @executable_path/../Frameworks @executable_path/../../../../Frameworks diff --git a/Apple/Configuration/Framework.xcconfig b/Apple/Configuration/Framework.xcconfig new file mode 100644 index 0000000..6fa4f19 --- /dev/null +++ b/Apple/Configuration/Framework.xcconfig @@ -0,0 +1,14 @@ +PRODUCT_NAME = Burrow$(TARGET_NAME:c99extidentifier) +PRODUCT_BUNDLE_IDENTIFIER = $(APP_BUNDLE_IDENTIFIER).$(TARGET_NAME:c99extidentifier) +APPLICATION_EXTENSION_API_ONLY = YES +SWIFT_INSTALL_OBJC_HEADER = NO +SWIFT_SKIP_AUTOLINKING_FRAMEWORKS = YES +SWIFT_SKIP_AUTOLINKING_LIBRARIES = YES + +LD_RUNPATH_SEARCH_PATHS = $(inherited) @executable_path/Frameworks @loader_path/Frameworks +LD_RUNPATH_SEARCH_PATHS[sdk=macosx*] = $(inherited) @executable_path/../Frameworks @loader_path/Frameworks + +DYLIB_INSTALL_NAME_BASE = @rpath +DYLIB_COMPATIBILITY_VERSION = 1 +DYLIB_CURRENT_VERSION = 1 +VERSIONING_SYSTEM = diff --git a/Apple/Core/Client.swift b/Apple/Core/Client.swift new file mode 100644 index 0000000..8874e3b --- /dev/null +++ b/Apple/Core/Client.swift @@ -0,0 +1,32 @@ +import GRPC +import NIOTransportServices + +public typealias TunnelClient = Burrow_TunnelAsyncClient +public typealias NetworksClient = Burrow_NetworksAsyncClient + +public protocol Client { + init(channel: GRPCChannel) +} + +extension Client { + public static func unix(socketURL: URL) -> Self { + let group = NIOTSEventLoopGroup() + let configuration = ClientConnection.Configuration.default( + target: .unixDomainSocket(socketURL.path), + eventLoopGroup: group + ) + return Self(channel: ClientConnection(configuration: configuration)) + } +} + +extension TunnelClient: Client { + public init(channel: any GRPCChannel) { + self.init(channel: channel, defaultCallOptions: .init(), interceptors: .none) + } +} + +extension NetworksClient: Client { + public init(channel: any GRPCChannel) { + self.init(channel: channel, defaultCallOptions: .init(), interceptors: .none) + } +} diff --git a/Apple/Core/Client/burrow.proto b/Apple/Core/Client/burrow.proto new file mode 120000 index 0000000..03e86a5 --- /dev/null +++ b/Apple/Core/Client/burrow.proto @@ -0,0 +1 @@ +../../../proto/burrow.proto \ No newline at end of file diff --git a/Apple/Core/Client/grpc-swift-config.json b/Apple/Core/Client/grpc-swift-config.json new file mode 100644 index 0000000..2d89698 --- /dev/null +++ b/Apple/Core/Client/grpc-swift-config.json @@ -0,0 +1,11 @@ +{ + "invocations": [ + { + "protoFiles": [ + "burrow.proto", + ], + "server": false, + "visibility": "public" + } + ] +} diff --git a/Apple/Core/Client/swift-protobuf-config.json b/Apple/Core/Client/swift-protobuf-config.json new file mode 100644 index 0000000..87aaec3 --- /dev/null +++ b/Apple/Core/Client/swift-protobuf-config.json @@ -0,0 +1,10 @@ +{ + "invocations": [ + { + "protoFiles": [ + "burrow.proto", + ], + "visibility": "public" + } + ] +} diff --git a/Apple/Shared/Logging.swift b/Apple/Core/Logging.swift similarity index 88% rename from Apple/Shared/Logging.swift rename to Apple/Core/Logging.swift index 36f024c..ba40888 100644 --- a/Apple/Shared/Logging.swift +++ b/Apple/Core/Logging.swift @@ -4,7 +4,7 @@ import os extension Logger { private static let loggers: OSAllocatedUnfairLock<[String: Logger]> = OSAllocatedUnfairLock(initialState: [:]) - public static let subsystem = Constants.bundleIdentifier + public dynamic static var subsystem: String { "com.hackclub.burrow" } public static func logger(for type: Any.Type) -> Logger { let category = String(describing: type) diff --git a/Apple/NetworkExtension/PacketTunnelProvider.swift b/Apple/NetworkExtension/PacketTunnelProvider.swift index 89e0de6..a8e42e0 100644 --- a/Apple/NetworkExtension/PacketTunnelProvider.swift +++ b/Apple/NetworkExtension/PacketTunnelProvider.swift @@ -1,92 +1,74 @@ -import BurrowShared +import AsyncAlgorithms +import BurrowConfiguration +import BurrowCore import libburrow import NetworkExtension import os class PacketTunnelProvider: NEPacketTunnelProvider { + enum Error: Swift.Error { + case missingTunnelConfiguration + } + private let logger = Logger.logger(for: PacketTunnelProvider.self) - private var client: Client? + + private var client: TunnelClient { + get throws { try _client.get() } + } + private let _client: Result = Result { + try TunnelClient.unix(socketURL: Constants.socketURL) + } override init() { do { libburrow.spawnInProcess( socketPath: try Constants.socketURL.path(percentEncoded: false), - dbPath: try Constants.dbURL.path(percentEncoded: false) + databasePath: try Constants.databaseURL.path(percentEncoded: false) ) } catch { - logger.error("Failed to spawn: \(error)") + logger.error("Failed to spawn networking thread: \(error)") } } override func startTunnel(options: [String: NSObject]? = nil) async throws { do { - let client = try Client() - self.client = client - register_events(client) - - _ = try await self.loadTunSettings() - let startRequest = Start( - tun: Start.TunOptions( - name: nil, no_pi: false, tun_excl: false, tun_retrieve: true, address: [] - ) - ) - let response = try await client.request(startRequest, type: BurrowResult.self) - self.logger.log("Received start server response: \(String(describing: response))") + let configuration = try await Array(client.tunnelConfiguration(.init()).prefix(1)).first + guard let settings = configuration?.settings else { + throw Error.missingTunnelConfiguration + } + try await setTunnelNetworkSettings(settings) + _ = try await client.tunnelStart(.init()) + logger.log("Started tunnel with network settings: \(settings)") } catch { - self.logger.error("Failed to start tunnel: \(error)") + logger.error("Failed to start tunnel: \(error)") throw error } } override func stopTunnel(with reason: NEProviderStopReason) async { do { - let client = try Client() - _ = try await client.single_request("Stop", type: BurrowResult.self) - self.logger.log("Stopped client.") + _ = try await client.tunnelStop(.init()) + logger.log("Stopped client") } catch { - self.logger.error("Failed to stop tunnel: \(error)") - } - } - func loadTunSettings() async throws -> ServerConfig { - guard let client = self.client else { - throw BurrowError.noClient - } - let srvConfig = try await client.single_request("ServerConfig", type: BurrowResult.self) - guard let serverconfig = srvConfig.Ok else { - throw BurrowError.resultIsError - } - guard let tunNs = generateTunSettings(from: serverconfig) else { - throw BurrowError.addrDoesntExist - } - try await self.setTunnelNetworkSettings(tunNs) - self.logger.info("Set remote tunnel address to \(tunNs.tunnelRemoteAddress)") - return serverconfig - } - private func generateTunSettings(from: ServerConfig) -> NETunnelNetworkSettings? { - // Using a makeshift remote tunnel address - let nst = NEPacketTunnelNetworkSettings(tunnelRemoteAddress: "1.1.1.1") - var v4Addresses = [String]() - var v6Addresses = [String]() - for addr in from.address { - if IPv4Address(addr) != nil { - v6Addresses.append(addr) - } - if IPv6Address(addr) != nil { - v4Addresses.append(addr) - } - } - nst.ipv4Settings = NEIPv4Settings(addresses: v4Addresses, subnetMasks: v4Addresses.map { _ in - "255.255.255.0" - }) - nst.ipv6Settings = NEIPv6Settings(addresses: v6Addresses, networkPrefixLengths: v6Addresses.map { _ in 64 }) - logger.log("Initialized ipv4 settings: \(nst.ipv4Settings)") - return nst - } - func register_events(_ client: Client) { - client.on_event(.ConfigChange) { (cfig: ServerConfig) in - self.logger.info("Config Change Notification: \(String(describing: cfig))") - self.setTunnelNetworkSettings(self.generateTunSettings(from: cfig)) - self.logger.info("Updated Tunnel Network Settings.") + logger.error("Failed to stop tunnel: \(error)") } } } + +extension Burrow_TunnelConfigurationResponse { + fileprivate var settings: NEPacketTunnelNetworkSettings { + let ipv6Addresses = addresses.filter { IPv6Address($0) != nil } + + let settings = NEPacketTunnelNetworkSettings(tunnelRemoteAddress: "1.1.1.1") + settings.mtu = NSNumber(value: mtu) + settings.ipv4Settings = NEIPv4Settings( + addresses: addresses.filter { IPv4Address($0) != nil }, + subnetMasks: ["255.255.255.0"] + ) + settings.ipv6Settings = NEIPv6Settings( + addresses: ipv6Addresses, + networkPrefixLengths: ipv6Addresses.map { _ in 64 } + ) + return settings + } +} diff --git a/Apple/NetworkExtension/libburrow/build-rust.sh b/Apple/NetworkExtension/libburrow/build-rust.sh index 00c3652..6f455a9 100755 --- a/Apple/NetworkExtension/libburrow/build-rust.sh +++ b/Apple/NetworkExtension/libburrow/build-rust.sh @@ -68,11 +68,12 @@ else CARGO_PATH="$(dirname $(readlink -f $(which cargo))):/usr/bin" fi -CARGO_PATH="$(dirname $(readlink -f $(which protoc))):$CARGO_PATH" +PROTOC=$(readlink -f $(which protoc)) +CARGO_PATH="$(dirname $PROTOC):$CARGO_PATH" # Run cargo without the various environment variables set by Xcode. # Those variables can confuse cargo and the build scripts it runs. -env -i PATH="$CARGO_PATH" CARGO_TARGET_DIR="${CONFIGURATION_TEMP_DIR}/target" IPHONEOS_DEPLOYMENT_TARGET="$IPHONEOS_DEPLOYMENT_TARGET" MACOSX_DEPLOYMENT_TARGET="$MACOSX_DEPLOYMENT_TARGET" cargo build "${CARGO_ARGS[@]}" +env -i PATH="$CARGO_PATH" PROTOC="$PROTOC" CARGO_TARGET_DIR="${CONFIGURATION_TEMP_DIR}/target" IPHONEOS_DEPLOYMENT_TARGET="$IPHONEOS_DEPLOYMENT_TARGET" MACOSX_DEPLOYMENT_TARGET="$MACOSX_DEPLOYMENT_TARGET" cargo build "${CARGO_ARGS[@]}" mkdir -p "${BUILT_PRODUCTS_DIR}" diff --git a/Apple/NetworkExtension/libburrow/libburrow.h b/Apple/NetworkExtension/libburrow/libburrow.h index 2b578ab..59b4734 100644 --- a/Apple/NetworkExtension/libburrow/libburrow.h +++ b/Apple/NetworkExtension/libburrow/libburrow.h @@ -1,2 +1,2 @@ -__attribute__((__swift_name__("spawnInProcess(socketPath:dbPath:)"))) +__attribute__((__swift_name__("spawnInProcess(socketPath:databasePath:)"))) extern void spawn_in_process(const char * __nullable socket_path, const char * __nullable db_path); diff --git a/Apple/Shared/Client.swift b/Apple/Shared/Client.swift deleted file mode 100644 index f643c6c..0000000 --- a/Apple/Shared/Client.swift +++ /dev/null @@ -1,106 +0,0 @@ -import Foundation -import Network - -public final class Client { - let connection: NWConnection - - private let logger = Logger.logger(for: Client.self) - private var generator = SystemRandomNumberGenerator() - private var continuations: [UInt: UnsafeContinuation] = [:] - private var eventMap: [NotificationType: [(Data) throws -> Void]] = [:] - private var task: Task? - - public convenience init() throws { - self.init(url: try Constants.socketURL) - } - - public init(url: URL) { - let endpoint: NWEndpoint - if url.isFileURL { - endpoint = .unix(path: url.path(percentEncoded: false)) - } else { - endpoint = .url(url) - } - - let parameters = NWParameters.tcp - parameters.defaultProtocolStack - .applicationProtocols - .insert(NWProtocolFramer.Options(definition: NewlineProtocolFramer.definition), at: 0) - let connection = NWConnection(to: endpoint, using: parameters) - connection.start(queue: .global()) - self.connection = connection - self.task = Task { [weak self] in - while true { - let (data, _, _) = try await connection.receiveMessage() - let peek = try JSONDecoder().decode(MessagePeek.self, from: data) - switch peek.type { - case .Response: - let response = try JSONDecoder().decode(ResponsePeek.self, from: data) - self?.logger.info("Received response for \(response.id)") - guard let continuations = self?.continuations else {return} - self?.logger.debug("All keys in continuation table: \(continuations.keys)") - guard let continuation = self?.continuations[response.id] else { return } - self?.logger.debug("Got matching continuation") - continuation.resume(returning: data) - case .Notification: - let peek = try JSONDecoder().decode(NotificationPeek.self, from: data) - guard let handlers = self?.eventMap[peek.method] else { continue } - _ = try handlers.map { try $0(data) } - default: - continue - } - } - } - } - private func send(_ request: T) async throws -> U { - let data: Data = try await withUnsafeThrowingContinuation { continuation in - continuations[request.id] = continuation - do { - let data = try JSONEncoder().encode(request) - let completion: NWConnection.SendCompletion = .contentProcessed { error in - guard let error = error else { - return - } - continuation.resume(throwing: error) - } - connection.send(content: data, completion: completion) - } catch { - continuation.resume(throwing: error) - return - } - } - self.logger.debug("Got response data: \(String(describing: data.base64EncodedString()))") - let res = try JSONDecoder().decode(Response.self, from: data) - self.logger.debug("Got response data decoded: \(String(describing: res))") - return res.result - } - public func request(_ request: T, type: U.Type = U.self) async throws -> U { - let req = BurrowRequest( - id: generator.next(upperBound: UInt.max), - command: request - ) - return try await send(req) - } - public func single_request(_ request: String, type: U.Type = U.self) async throws -> U { - let req = BurrowSimpleRequest( - id: generator.next(upperBound: UInt.max), - command: request - ) - return try await send(req) - } - public func on_event(_ event: NotificationType, callable: @escaping (T) throws -> Void) { - let action = { data in - let decoded = try JSONDecoder().decode(Notification.self, from: data) - try callable(decoded.params) - } - if eventMap[event] != nil { - eventMap[event]?.append(action) - } else { - eventMap[event] = [action] - } - } - - deinit { - connection.cancel() - } -} diff --git a/Apple/Shared/DataTypes.swift b/Apple/Shared/DataTypes.swift deleted file mode 100644 index ac49abc..0000000 --- a/Apple/Shared/DataTypes.swift +++ /dev/null @@ -1,139 +0,0 @@ -import Foundation - -// swiftlint:disable identifier_name raw_value_for_camel_cased_codable_enum -public enum BurrowError: Error { - case addrDoesntExist - case resultIsError - case cantParseResult - case resultIsNone - case noClient -} - -public protocol Request: Codable where Params: Codable { - associatedtype Params - - var id: UInt { get set } - var method: String { get set } - var params: Params? { get set } -} - -public enum MessageType: String, Codable { - case Request - case Response - case Notification -} - -public struct MessagePeek: Codable { - public var type: MessageType - public init(type: MessageType) { - self.type = type - } -} - -public struct BurrowSimpleRequest: Request { - public var id: UInt - public var method: String - public var params: String? - public init(id: UInt, command: String, params: String? = nil) { - self.id = id - self.method = command - self.params = params - } -} - -public struct BurrowRequest: Request where T: Codable { - public var id: UInt - public var method: String - public var params: T? - public init(id: UInt, command: T) { - self.id = id - self.method = "\(T.self)" - self.params = command - } -} - -public struct Response: Decodable where T: Decodable { - public var id: UInt - public var result: T - public init(id: UInt, result: T) { - self.id = id - self.result = result - } -} - -public struct ResponsePeek: Codable { - public var id: UInt - public init(id: UInt) { - self.id = id - } -} - -public enum NotificationType: String, Codable { - case ConfigChange -} - -public struct Notification: Codable where T: Codable { - public var method: NotificationType - public var params: T - public init(method: NotificationType, params: T) { - self.method = method - self.params = params - } -} - -public struct NotificationPeek: Codable { - public var method: NotificationType - public init(method: NotificationType) { - self.method = method - } -} - -public struct AnyResponseData: Codable { - public var type: String - public init(type: String) { - self.type = type - } -} - -public struct BurrowResult: Codable where T: Codable { - public var Ok: T? - public var Err: String? - public init(Ok: T, Err: String? = nil) { - self.Ok = Ok - self.Err = Err - } -} - -public struct ServerConfig: Codable { - public let address: [String] - public let name: String? - public let mtu: Int32? - public init(address: [String], name: String?, mtu: Int32?) { - self.address = address - self.name = name - self.mtu = mtu - } -} - -public struct Start: Codable { - public struct TunOptions: Codable { - public let name: String? - public let no_pi: Bool - public let tun_excl: Bool - public let tun_retrieve: Bool - public let address: [String] - public init(name: String?, no_pi: Bool, tun_excl: Bool, tun_retrieve: Bool, address: [String]) { - self.name = name - self.no_pi = no_pi - self.tun_excl = tun_excl - self.tun_retrieve = tun_retrieve - self.address = address - } - } - public let tun: TunOptions - public init(tun: TunOptions) { - self.tun = tun - } -} - -// swiftlint:enable identifier_name raw_value_for_camel_cased_codable_enum diff --git a/Apple/Shared/NWConnection+Async.swift b/Apple/Shared/NWConnection+Async.swift deleted file mode 100644 index c21fdc0..0000000 --- a/Apple/Shared/NWConnection+Async.swift +++ /dev/null @@ -1,32 +0,0 @@ -import Foundation -import Network - -extension NWConnection { - // swiftlint:disable:next large_tuple - func receiveMessage() async throws -> (Data, NWConnection.ContentContext?, Bool) { - try await withUnsafeThrowingContinuation { continuation in - receiveMessage { completeContent, contentContext, isComplete, error in - if let error { - continuation.resume(throwing: error) - } else { - guard let completeContent = completeContent else { - fatalError("Both error and completeContent were nil") - } - continuation.resume(returning: (completeContent, contentContext, isComplete)) - } - } - } - } - - func send(content: Data) async throws { - try await withCheckedThrowingContinuation { (continuation: CheckedContinuation) in - send(content: content, completion: .contentProcessed { error in - if let error { - continuation.resume(throwing: error) - } else { - continuation.resume(returning: ()) - } - }) - } - } -} diff --git a/Apple/Shared/NewlineProtocolFramer.swift b/Apple/Shared/NewlineProtocolFramer.swift deleted file mode 100644 index d2f71e5..0000000 --- a/Apple/Shared/NewlineProtocolFramer.swift +++ /dev/null @@ -1,54 +0,0 @@ -import Foundation -import Network - -final class NewlineProtocolFramer: NWProtocolFramerImplementation { - private static let delimeter: UInt8 = 10 // `\n` - - static let definition = NWProtocolFramer.Definition(implementation: NewlineProtocolFramer.self) - static let label = "Lines" - - init(framer: NWProtocolFramer.Instance) { } - - func start(framer: NWProtocolFramer.Instance) -> NWProtocolFramer.StartResult { .ready } - func stop(framer: NWProtocolFramer.Instance) -> Bool { true } - - func wakeup(framer: NWProtocolFramer.Instance) { } - func cleanup(framer: NWProtocolFramer.Instance) { } - - func handleInput(framer: NWProtocolFramer.Instance) -> Int { - while true { - var result: [Data] = [] - let parsed = framer.parseInput(minimumIncompleteLength: 1, maximumLength: 16_000) { buffer, _ in - guard let buffer else { return 0 } - var lines = buffer - .split(separator: Self.delimeter, omittingEmptySubsequences: false) - .map { Data($0) } - guard lines.count > 1 else { return 0 } - _ = lines.popLast() - - result = lines - return lines.reduce(lines.count) { $0 + $1.count } - } - - guard parsed && !result.isEmpty else { break } - - for line in result { - framer.deliverInput(data: line, message: .init(instance: framer), isComplete: true) - } - } - return 0 - } - - func handleOutput( - framer: NWProtocolFramer.Instance, - message: NWProtocolFramer.Message, - messageLength: Int, - isComplete: Bool - ) { - do { - try framer.writeOutputNoCopy(length: messageLength) - framer.writeOutput(data: [Self.delimeter]) - } catch { - } - } -} diff --git a/Apple/App/Assets.xcassets/AccentColor.colorset/Contents.json b/Apple/UI/Assets.xcassets/AccentColor.colorset/Contents.json similarity index 100% rename from Apple/App/Assets.xcassets/AccentColor.colorset/Contents.json rename to Apple/UI/Assets.xcassets/AccentColor.colorset/Contents.json diff --git a/Apple/App/Assets.xcassets/AppIcon.appiconset/100.png b/Apple/UI/Assets.xcassets/AppIcon.appiconset/100.png similarity index 100% rename from Apple/App/Assets.xcassets/AppIcon.appiconset/100.png rename to Apple/UI/Assets.xcassets/AppIcon.appiconset/100.png diff --git a/Apple/App/Assets.xcassets/AppIcon.appiconset/1024.png b/Apple/UI/Assets.xcassets/AppIcon.appiconset/1024.png similarity index 100% rename from Apple/App/Assets.xcassets/AppIcon.appiconset/1024.png rename to Apple/UI/Assets.xcassets/AppIcon.appiconset/1024.png diff --git a/Apple/App/Assets.xcassets/AppIcon.appiconset/114.png b/Apple/UI/Assets.xcassets/AppIcon.appiconset/114.png similarity index 100% rename from Apple/App/Assets.xcassets/AppIcon.appiconset/114.png rename to Apple/UI/Assets.xcassets/AppIcon.appiconset/114.png diff --git a/Apple/App/Assets.xcassets/AppIcon.appiconset/120.png b/Apple/UI/Assets.xcassets/AppIcon.appiconset/120.png similarity index 100% rename from Apple/App/Assets.xcassets/AppIcon.appiconset/120.png rename to Apple/UI/Assets.xcassets/AppIcon.appiconset/120.png diff --git a/Apple/App/Assets.xcassets/AppIcon.appiconset/128.png b/Apple/UI/Assets.xcassets/AppIcon.appiconset/128.png similarity index 100% rename from Apple/App/Assets.xcassets/AppIcon.appiconset/128.png rename to Apple/UI/Assets.xcassets/AppIcon.appiconset/128.png diff --git a/Apple/App/Assets.xcassets/AppIcon.appiconset/144.png b/Apple/UI/Assets.xcassets/AppIcon.appiconset/144.png similarity index 100% rename from Apple/App/Assets.xcassets/AppIcon.appiconset/144.png rename to Apple/UI/Assets.xcassets/AppIcon.appiconset/144.png diff --git a/Apple/App/Assets.xcassets/AppIcon.appiconset/152.png b/Apple/UI/Assets.xcassets/AppIcon.appiconset/152.png similarity index 100% rename from Apple/App/Assets.xcassets/AppIcon.appiconset/152.png rename to Apple/UI/Assets.xcassets/AppIcon.appiconset/152.png diff --git a/Apple/App/Assets.xcassets/AppIcon.appiconset/16.png b/Apple/UI/Assets.xcassets/AppIcon.appiconset/16.png similarity index 100% rename from Apple/App/Assets.xcassets/AppIcon.appiconset/16.png rename to Apple/UI/Assets.xcassets/AppIcon.appiconset/16.png diff --git a/Apple/App/Assets.xcassets/AppIcon.appiconset/167.png b/Apple/UI/Assets.xcassets/AppIcon.appiconset/167.png similarity index 100% rename from Apple/App/Assets.xcassets/AppIcon.appiconset/167.png rename to Apple/UI/Assets.xcassets/AppIcon.appiconset/167.png diff --git a/Apple/App/Assets.xcassets/AppIcon.appiconset/172.png b/Apple/UI/Assets.xcassets/AppIcon.appiconset/172.png similarity index 100% rename from Apple/App/Assets.xcassets/AppIcon.appiconset/172.png rename to Apple/UI/Assets.xcassets/AppIcon.appiconset/172.png diff --git a/Apple/App/Assets.xcassets/AppIcon.appiconset/180.png b/Apple/UI/Assets.xcassets/AppIcon.appiconset/180.png similarity index 100% rename from Apple/App/Assets.xcassets/AppIcon.appiconset/180.png rename to Apple/UI/Assets.xcassets/AppIcon.appiconset/180.png diff --git a/Apple/App/Assets.xcassets/AppIcon.appiconset/196.png b/Apple/UI/Assets.xcassets/AppIcon.appiconset/196.png similarity index 100% rename from Apple/App/Assets.xcassets/AppIcon.appiconset/196.png rename to Apple/UI/Assets.xcassets/AppIcon.appiconset/196.png diff --git a/Apple/App/Assets.xcassets/AppIcon.appiconset/20.png b/Apple/UI/Assets.xcassets/AppIcon.appiconset/20.png similarity index 100% rename from Apple/App/Assets.xcassets/AppIcon.appiconset/20.png rename to Apple/UI/Assets.xcassets/AppIcon.appiconset/20.png diff --git a/Apple/App/Assets.xcassets/AppIcon.appiconset/216.png b/Apple/UI/Assets.xcassets/AppIcon.appiconset/216.png similarity index 100% rename from Apple/App/Assets.xcassets/AppIcon.appiconset/216.png rename to Apple/UI/Assets.xcassets/AppIcon.appiconset/216.png diff --git a/Apple/App/Assets.xcassets/AppIcon.appiconset/256.png b/Apple/UI/Assets.xcassets/AppIcon.appiconset/256.png similarity index 100% rename from Apple/App/Assets.xcassets/AppIcon.appiconset/256.png rename to Apple/UI/Assets.xcassets/AppIcon.appiconset/256.png diff --git a/Apple/App/Assets.xcassets/AppIcon.appiconset/29.png b/Apple/UI/Assets.xcassets/AppIcon.appiconset/29.png similarity index 100% rename from Apple/App/Assets.xcassets/AppIcon.appiconset/29.png rename to Apple/UI/Assets.xcassets/AppIcon.appiconset/29.png diff --git a/Apple/App/Assets.xcassets/AppIcon.appiconset/32.png b/Apple/UI/Assets.xcassets/AppIcon.appiconset/32.png similarity index 100% rename from Apple/App/Assets.xcassets/AppIcon.appiconset/32.png rename to Apple/UI/Assets.xcassets/AppIcon.appiconset/32.png diff --git a/Apple/App/Assets.xcassets/AppIcon.appiconset/40.png b/Apple/UI/Assets.xcassets/AppIcon.appiconset/40.png similarity index 100% rename from Apple/App/Assets.xcassets/AppIcon.appiconset/40.png rename to Apple/UI/Assets.xcassets/AppIcon.appiconset/40.png diff --git a/Apple/App/Assets.xcassets/AppIcon.appiconset/48.png b/Apple/UI/Assets.xcassets/AppIcon.appiconset/48.png similarity index 100% rename from Apple/App/Assets.xcassets/AppIcon.appiconset/48.png rename to Apple/UI/Assets.xcassets/AppIcon.appiconset/48.png diff --git a/Apple/App/Assets.xcassets/AppIcon.appiconset/50.png b/Apple/UI/Assets.xcassets/AppIcon.appiconset/50.png similarity index 100% rename from Apple/App/Assets.xcassets/AppIcon.appiconset/50.png rename to Apple/UI/Assets.xcassets/AppIcon.appiconset/50.png diff --git a/Apple/App/Assets.xcassets/AppIcon.appiconset/512.png b/Apple/UI/Assets.xcassets/AppIcon.appiconset/512.png similarity index 100% rename from Apple/App/Assets.xcassets/AppIcon.appiconset/512.png rename to Apple/UI/Assets.xcassets/AppIcon.appiconset/512.png diff --git a/Apple/App/Assets.xcassets/AppIcon.appiconset/55.png b/Apple/UI/Assets.xcassets/AppIcon.appiconset/55.png similarity index 100% rename from Apple/App/Assets.xcassets/AppIcon.appiconset/55.png rename to Apple/UI/Assets.xcassets/AppIcon.appiconset/55.png diff --git a/Apple/App/Assets.xcassets/AppIcon.appiconset/57.png b/Apple/UI/Assets.xcassets/AppIcon.appiconset/57.png similarity index 100% rename from Apple/App/Assets.xcassets/AppIcon.appiconset/57.png rename to Apple/UI/Assets.xcassets/AppIcon.appiconset/57.png diff --git a/Apple/App/Assets.xcassets/AppIcon.appiconset/58.png b/Apple/UI/Assets.xcassets/AppIcon.appiconset/58.png similarity index 100% rename from Apple/App/Assets.xcassets/AppIcon.appiconset/58.png rename to Apple/UI/Assets.xcassets/AppIcon.appiconset/58.png diff --git a/Apple/App/Assets.xcassets/AppIcon.appiconset/60.png b/Apple/UI/Assets.xcassets/AppIcon.appiconset/60.png similarity index 100% rename from Apple/App/Assets.xcassets/AppIcon.appiconset/60.png rename to Apple/UI/Assets.xcassets/AppIcon.appiconset/60.png diff --git a/Apple/App/Assets.xcassets/AppIcon.appiconset/64.png b/Apple/UI/Assets.xcassets/AppIcon.appiconset/64.png similarity index 100% rename from Apple/App/Assets.xcassets/AppIcon.appiconset/64.png rename to Apple/UI/Assets.xcassets/AppIcon.appiconset/64.png diff --git a/Apple/App/Assets.xcassets/AppIcon.appiconset/72.png b/Apple/UI/Assets.xcassets/AppIcon.appiconset/72.png similarity index 100% rename from Apple/App/Assets.xcassets/AppIcon.appiconset/72.png rename to Apple/UI/Assets.xcassets/AppIcon.appiconset/72.png diff --git a/Apple/App/Assets.xcassets/AppIcon.appiconset/76.png b/Apple/UI/Assets.xcassets/AppIcon.appiconset/76.png similarity index 100% rename from Apple/App/Assets.xcassets/AppIcon.appiconset/76.png rename to Apple/UI/Assets.xcassets/AppIcon.appiconset/76.png diff --git a/Apple/App/Assets.xcassets/AppIcon.appiconset/80.png b/Apple/UI/Assets.xcassets/AppIcon.appiconset/80.png similarity index 100% rename from Apple/App/Assets.xcassets/AppIcon.appiconset/80.png rename to Apple/UI/Assets.xcassets/AppIcon.appiconset/80.png diff --git a/Apple/App/Assets.xcassets/AppIcon.appiconset/87.png b/Apple/UI/Assets.xcassets/AppIcon.appiconset/87.png similarity index 100% rename from Apple/App/Assets.xcassets/AppIcon.appiconset/87.png rename to Apple/UI/Assets.xcassets/AppIcon.appiconset/87.png diff --git a/Apple/App/Assets.xcassets/AppIcon.appiconset/88.png b/Apple/UI/Assets.xcassets/AppIcon.appiconset/88.png similarity index 100% rename from Apple/App/Assets.xcassets/AppIcon.appiconset/88.png rename to Apple/UI/Assets.xcassets/AppIcon.appiconset/88.png diff --git a/Apple/App/Assets.xcassets/AppIcon.appiconset/Contents.json b/Apple/UI/Assets.xcassets/AppIcon.appiconset/Contents.json similarity index 100% rename from Apple/App/Assets.xcassets/AppIcon.appiconset/Contents.json rename to Apple/UI/Assets.xcassets/AppIcon.appiconset/Contents.json diff --git a/Apple/App/Assets.xcassets/Contents.json b/Apple/UI/Assets.xcassets/Contents.json similarity index 100% rename from Apple/App/Assets.xcassets/Contents.json rename to Apple/UI/Assets.xcassets/Contents.json diff --git a/Apple/App/Assets.xcassets/HackClub.colorset/Contents.json b/Apple/UI/Assets.xcassets/HackClub.colorset/Contents.json similarity index 100% rename from Apple/App/Assets.xcassets/HackClub.colorset/Contents.json rename to Apple/UI/Assets.xcassets/HackClub.colorset/Contents.json diff --git a/Apple/App/Assets.xcassets/HackClub.imageset/Contents.json b/Apple/UI/Assets.xcassets/HackClub.imageset/Contents.json similarity index 100% rename from Apple/App/Assets.xcassets/HackClub.imageset/Contents.json rename to Apple/UI/Assets.xcassets/HackClub.imageset/Contents.json diff --git a/Apple/App/Assets.xcassets/HackClub.imageset/flag-standalone-wtransparent.pdf b/Apple/UI/Assets.xcassets/HackClub.imageset/flag-standalone-wtransparent.pdf similarity index 100% rename from Apple/App/Assets.xcassets/HackClub.imageset/flag-standalone-wtransparent.pdf rename to Apple/UI/Assets.xcassets/HackClub.imageset/flag-standalone-wtransparent.pdf diff --git a/Apple/App/Assets.xcassets/WireGuard.colorset/Contents.json b/Apple/UI/Assets.xcassets/WireGuard.colorset/Contents.json similarity index 100% rename from Apple/App/Assets.xcassets/WireGuard.colorset/Contents.json rename to Apple/UI/Assets.xcassets/WireGuard.colorset/Contents.json diff --git a/Apple/App/Assets.xcassets/WireGuard.imageset/Contents.json b/Apple/UI/Assets.xcassets/WireGuard.imageset/Contents.json similarity index 100% rename from Apple/App/Assets.xcassets/WireGuard.imageset/Contents.json rename to Apple/UI/Assets.xcassets/WireGuard.imageset/Contents.json diff --git a/Apple/App/Assets.xcassets/WireGuard.imageset/WireGuard.svg b/Apple/UI/Assets.xcassets/WireGuard.imageset/WireGuard.svg similarity index 100% rename from Apple/App/Assets.xcassets/WireGuard.imageset/WireGuard.svg rename to Apple/UI/Assets.xcassets/WireGuard.imageset/WireGuard.svg diff --git a/Apple/App/Assets.xcassets/WireGuardTitle.imageset/Contents.json b/Apple/UI/Assets.xcassets/WireGuardTitle.imageset/Contents.json similarity index 100% rename from Apple/App/Assets.xcassets/WireGuardTitle.imageset/Contents.json rename to Apple/UI/Assets.xcassets/WireGuardTitle.imageset/Contents.json diff --git a/Apple/App/Assets.xcassets/WireGuardTitle.imageset/WireGuardTitle.svg b/Apple/UI/Assets.xcassets/WireGuardTitle.imageset/WireGuardTitle.svg similarity index 100% rename from Apple/App/Assets.xcassets/WireGuardTitle.imageset/WireGuardTitle.svg rename to Apple/UI/Assets.xcassets/WireGuardTitle.imageset/WireGuardTitle.svg diff --git a/Apple/App/BurrowView.swift b/Apple/UI/BurrowView.swift similarity index 95% rename from Apple/App/BurrowView.swift rename to Apple/UI/BurrowView.swift index 3a53762..96467c7 100644 --- a/Apple/App/BurrowView.swift +++ b/Apple/UI/BurrowView.swift @@ -2,11 +2,11 @@ import AuthenticationServices import SwiftUI #if !os(macOS) -struct BurrowView: View { +public struct BurrowView: View { @Environment(\.webAuthenticationSession) private var webAuthenticationSession - var body: some View { + public var body: some View { NavigationStack { VStack { HStack { @@ -35,6 +35,9 @@ struct BurrowView: View { } } + public init() { + } + private func addHackClubNetwork() { Task { try await authenticateWithSlack() diff --git a/Apple/App/FloatingButtonStyle.swift b/Apple/UI/FloatingButtonStyle.swift similarity index 100% rename from Apple/App/FloatingButtonStyle.swift rename to Apple/UI/FloatingButtonStyle.swift diff --git a/Apple/App/MenuItemToggleView.swift b/Apple/UI/MenuItemToggleView.swift similarity index 87% rename from Apple/App/MenuItemToggleView.swift rename to Apple/UI/MenuItemToggleView.swift index 07db51d..ef5e8ee 100644 --- a/Apple/App/MenuItemToggleView.swift +++ b/Apple/UI/MenuItemToggleView.swift @@ -7,11 +7,11 @@ import SwiftUI -struct MenuItemToggleView: View { +public struct MenuItemToggleView: View { @Environment(\.tunnel) var tunnel: Tunnel - var body: some View { + public var body: some View { HStack { VStack(alignment: .leading) { Text("Burrow") @@ -30,10 +30,13 @@ struct MenuItemToggleView: View { .padding(10) .frame(minWidth: 300, minHeight: 32, maxHeight: 32) } + + public init() { + } } extension Tunnel { - fileprivate var toggleDisabled: Bool { + @MainActor fileprivate var toggleDisabled: Bool { switch status { case .disconnected, .permissionRequired, .connected, .disconnecting: false @@ -42,7 +45,7 @@ extension Tunnel { } } - var toggleIsOn: Binding { + @MainActor var toggleIsOn: Binding { Binding { switch status { case .connecting, .reasserting, .connected: diff --git a/Apple/App/NetworkCarouselView.swift b/Apple/UI/NetworkCarouselView.swift similarity index 90% rename from Apple/App/NetworkCarouselView.swift rename to Apple/UI/NetworkCarouselView.swift index b120c60..f969356 100644 --- a/Apple/App/NetworkCarouselView.swift +++ b/Apple/UI/NetworkCarouselView.swift @@ -2,10 +2,10 @@ import SwiftUI struct NetworkCarouselView: View { var networks: [any Network] = [ - HackClub(id: "1"), - HackClub(id: "2"), - WireGuard(id: "4"), - HackClub(id: "5"), + HackClub(id: 1), + HackClub(id: 2), + WireGuard(id: 4), + HackClub(id: 5) ] var body: some View { diff --git a/Apple/App/NetworkExtension+Async.swift b/Apple/UI/NetworkExtension+Async.swift similarity index 82% rename from Apple/App/NetworkExtension+Async.swift rename to Apple/UI/NetworkExtension+Async.swift index 4833efb..5820e7f 100644 --- a/Apple/App/NetworkExtension+Async.swift +++ b/Apple/UI/NetworkExtension+Async.swift @@ -1,6 +1,6 @@ import NetworkExtension -extension NEVPNManager { +extension NEVPNManager: @unchecked @retroactive Sendable { func remove() async throws { _ = try await withUnsafeThrowingContinuation { continuation in removeFromPreferences(completionHandler: completion(continuation)) @@ -14,7 +14,7 @@ extension NEVPNManager { } } -extension NETunnelProviderManager { +extension NETunnelProviderManager: @unchecked @retroactive Sendable { class var managers: [NETunnelProviderManager] { get async throws { try await withUnsafeThrowingContinuation { continuation in @@ -34,7 +34,7 @@ private func completion(_ continuation: UnsafeContinuation) -> (Err } } -private func completion(_ continuation: UnsafeContinuation) -> (T?, Error?) -> Void { +private func completion(_ continuation: UnsafeContinuation) -> (T?, Error?) -> Void { return { value, error in if let error { continuation.resume(throwing: error) diff --git a/Apple/App/NetworkExtensionTunnel.swift b/Apple/UI/NetworkExtensionTunnel.swift similarity index 67% rename from Apple/App/NetworkExtensionTunnel.swift rename to Apple/UI/NetworkExtensionTunnel.swift index 08002de..7aaa3b1 100644 --- a/Apple/App/NetworkExtensionTunnel.swift +++ b/Apple/UI/NetworkExtensionTunnel.swift @@ -1,22 +1,23 @@ -import BurrowShared +import BurrowCore import NetworkExtension @Observable -class NetworkExtensionTunnel: Tunnel { - @MainActor private(set) var status: TunnelStatus = .unknown - private var error: NEVPNError? +public final class NetworkExtensionTunnel: Tunnel { + @MainActor public private(set) var status: TunnelStatus = .unknown + @MainActor private var error: NEVPNError? private let logger = Logger.logger(for: Tunnel.self) private let bundleIdentifier: String - private var tasks: [Task] = [] + private let configurationChanged: Task + private let statusChanged: Task // Each manager corresponds to one entry in the Settings app. // Our goal is to maintain a single manager, so we create one if none exist and delete any extra. - private var managers: [NEVPNManager]? { + @MainActor private var managers: [NEVPNManager]? { didSet { Task { await updateStatus() } } } - private var currentStatus: TunnelStatus { + @MainActor private var currentStatus: TunnelStatus { guard let managers = managers else { guard let error = error else { return .unknown @@ -41,35 +42,40 @@ class NetworkExtensionTunnel: Tunnel { return manager.connection.tunnelStatus } - convenience init() { - self.init(Constants.networkExtensionBundleIdentifier) - } - - init(_ bundleIdentifier: String) { + public init(bundleIdentifier: String) { self.bundleIdentifier = bundleIdentifier let center = NotificationCenter.default - let configurationChanged = Task { [weak self] in - for try await _ in center.notifications(named: .NEVPNConfigurationChange).map({ _ in () }) { - await self?.update() + let tunnel: OSAllocatedUnfairLock = .init(initialState: .none) + configurationChanged = Task { + for try await _ in center.notifications(named: .NEVPNConfigurationChange) { + try Task.checkCancellation() + await tunnel.withLock { $0 }?.update() } } - let statusChanged = Task { [weak self] in - for try await _ in center.notifications(named: .NEVPNStatusDidChange).map({ _ in () }) { - await self?.updateStatus() + statusChanged = Task { + for try await _ in center.notifications(named: .NEVPNStatusDidChange) { + try Task.checkCancellation() + await tunnel.withLock { $0 }?.updateStatus() } } - tasks = [configurationChanged, statusChanged] + tunnel.withLock { $0 = self } Task { await update() } } private func update() async { do { - managers = try await NETunnelProviderManager.managers + let result = try await NETunnelProviderManager.managers + await MainActor.run { + managers = result + status = currentStatus + } await self.updateStatus() } catch let vpnError as NEVPNError { - error = vpnError + await MainActor.run { + error = vpnError + } } catch { logger.error("Failed to update VPN configurations: \(error)") } @@ -82,12 +88,7 @@ class NetworkExtensionTunnel: Tunnel { } func configure() async throws { - if managers == nil { - await update() - } - - guard let managers = managers else { return } - + let managers = try await NETunnelProviderManager.managers if managers.count > 1 { try await withThrowingTaskGroup(of: Void.self, returning: Void.self) { group in for manager in managers.suffix(from: 1) { @@ -110,9 +111,9 @@ class NetworkExtensionTunnel: Tunnel { try await manager.save() } - func start() { - guard let manager = managers?.first else { return } + public func start() { Task { + guard let manager = try await NETunnelProviderManager.managers.first else { return } do { if !manager.isEnabled { manager.isEnabled = true @@ -125,12 +126,14 @@ class NetworkExtensionTunnel: Tunnel { } } - func stop() { - guard let manager = managers?.first else { return } - manager.connection.stopVPNTunnel() + public func stop() { + Task { + guard let manager = try await NETunnelProviderManager.managers.first else { return } + manager.connection.stopVPNTunnel() + } } - func enable() { + public func enable() { Task { do { try await configure() @@ -141,7 +144,8 @@ class NetworkExtensionTunnel: Tunnel { } deinit { - tasks.forEach { $0.cancel() } + configurationChanged.cancel() + statusChanged.cancel() } } diff --git a/Apple/App/NetworkView.swift b/Apple/UI/NetworkView.swift similarity index 100% rename from Apple/App/NetworkView.swift rename to Apple/UI/NetworkView.swift diff --git a/Apple/App/Networks/HackClub.swift b/Apple/UI/Networks/HackClub.swift similarity index 76% rename from Apple/App/Networks/HackClub.swift rename to Apple/UI/Networks/HackClub.swift index f7df674..b1c2023 100644 --- a/Apple/App/Networks/HackClub.swift +++ b/Apple/UI/Networks/HackClub.swift @@ -1,10 +1,14 @@ +import BurrowCore import SwiftUI struct HackClub: Network { - var id: String + typealias NetworkType = Burrow_WireGuardNetwork + static let type: Burrow_NetworkType = .hackClub + + var id: Int32 var backgroundColor: Color { .init("HackClub") } - var label: some View { + @MainActor var label: some View { GeometryReader { reader in VStack(alignment: .leading) { Image("HackClub") diff --git a/Apple/UI/Networks/Network.swift b/Apple/UI/Networks/Network.swift new file mode 100644 index 0000000..c6d5fba --- /dev/null +++ b/Apple/UI/Networks/Network.swift @@ -0,0 +1,36 @@ +import Atomics +import BurrowCore +import SwiftProtobuf +import SwiftUI + +protocol Network { + associatedtype NetworkType: Message + associatedtype Label: View + + static var type: Burrow_NetworkType { get } + + var id: Int32 { get } + var backgroundColor: Color { get } + + @MainActor var label: Label { get } +} + +@Observable +@MainActor +final class NetworkViewModel: Sendable { + private(set) var networks: [Burrow_Network] = [] + + private var task: Task! + + init(socketURL: URL) { + task = Task { [weak self] in + let client = NetworksClient.unix(socketURL: socketURL) + for try await networks in client.networkList(.init()) { + guard let viewModel = self else { continue } + Task { @MainActor in + viewModel.networks = networks.network + } + } + } + } +} diff --git a/Apple/App/Networks/WireGuard.swift b/Apple/UI/Networks/WireGuard.swift similarity index 82% rename from Apple/App/Networks/WireGuard.swift rename to Apple/UI/Networks/WireGuard.swift index 499288a..cba67ef 100644 --- a/Apple/App/Networks/WireGuard.swift +++ b/Apple/UI/Networks/WireGuard.swift @@ -1,10 +1,14 @@ +import BurrowCore import SwiftUI struct WireGuard: Network { - var id: String + typealias NetworkType = Burrow_WireGuardNetwork + static let type: BurrowCore.Burrow_NetworkType = .wireGuard + + var id: Int32 var backgroundColor: Color { .init("WireGuard") } - var label: some View { + @MainActor var label: some View { GeometryReader { reader in VStack(alignment: .leading) { HStack { diff --git a/Apple/App/OAuth2.swift b/Apple/UI/OAuth2.swift similarity index 94% rename from Apple/App/OAuth2.swift rename to Apple/UI/OAuth2.swift index 9a930c9..0fafc8d 100644 --- a/Apple/App/OAuth2.swift +++ b/Apple/UI/OAuth2.swift @@ -1,5 +1,6 @@ import AuthenticationServices import Foundation +import os import SwiftUI enum OAuth2 { @@ -25,11 +26,16 @@ enum OAuth2 { var clientID: String var clientSecret: String - fileprivate static var queue: [Int: CheckedContinuation] = [:] + fileprivate static let queue: OSAllocatedUnfairLock<[Int: CheckedContinuation]> = { + .init(initialState: [:]) + }() fileprivate static func handle(url: URL) { - let continuations = queue - queue.removeAll() + let continuations = queue.withLock { continuations in + let copy = continuations + continuations.removeAll() + return copy + } for (_, continuation) in continuations { continuation.resume(returning: url) } @@ -56,7 +62,7 @@ enum OAuth2 { var queryItems: [URLQueryItem] = [ .init(name: "client_id", value: clientID), .init(name: "response_type", value: responseType.rawValue), - .init(name: "redirect_uri", value: redirectURI.absoluteString), + .init(name: "redirect_uri", value: redirectURI.absoluteString) ] if !scopes.isEmpty { queryItems.append(.init(name: "scope", value: scopes.joined(separator: ","))) @@ -206,6 +212,9 @@ enum OAuth2 { } } +extension WebAuthenticationSession: @unchecked @retroactive Sendable { +} + extension WebAuthenticationSession { #if canImport(BrowserEngineKit) @available(iOS 17.4, macOS 14.4, tvOS 17.4, watchOS 10.4, *) @@ -243,12 +252,12 @@ extension WebAuthenticationSession { let id = Int.random(in: 0..