diff --git a/.envrc b/.envrc new file mode 100644 index 0000000..bfa560a --- /dev/null +++ b/.envrc @@ -0,0 +1,6 @@ +#! /bin/sh + +# shellcheck disable=SC1090 +. "$(fetchurl https://raw.githubusercontent.com/paisano-nix/direnv/main/lib sha256-IgQhKK7UHL1AfCUntJO2KCaIDJQotRnK2qC4Daxk+wI=)" + +use env //repo/shells/default diff --git a/.gitignore b/.gitignore index 9582cca..650c753 100644 --- a/.gitignore +++ b/.gitignore @@ -1,3 +1,18 @@ target target-install systemd/cloudflare-dyndns.config + +.std + +result + +# prj-spec dirs +# +.bin +.cache +.config +.data +.run + +# nixago-auto-created: mdbook-build-folder +docs/build diff --git a/Cargo.lock b/Cargo.lock index 6d48c3e..2afc83b 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -2,6 +2,16 @@ # It is not intended for manual editing. version = 3 +[[package]] +name = "addr" +version = "0.15.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a93b8a41dbe230ad5087cc721f8d41611de654542180586b315d9f4cf6b72bef" +dependencies = [ + "psl", + "psl-types", +] + [[package]] name = "addr2line" version = "0.21.0" @@ -41,6 +51,60 @@ dependencies = [ "libc", ] +[[package]] +name = "anstream" +version = "0.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b1f58811cfac344940f1a400b6e6231ce35171f614f26439e80f8c1465c5cc0c" +dependencies = [ + "anstyle", + "anstyle-parse", + "anstyle-query", + "anstyle-wincon", + "colorchoice", + "utf8parse", +] + +[[package]] +name = "anstyle" +version = "1.0.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "15c4c2c83f81532e5845a733998b6971faca23490340a418e9b72a3ec9de12ea" + +[[package]] +name = "anstyle-parse" +version = "0.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "938874ff5980b03a87c5524b3ae5b59cf99b1d6bc836848df7bc5ada9643c333" +dependencies = [ + "utf8parse", +] + +[[package]] +name = "anstyle-query" +version = "1.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5ca11d4be1bab0c8bc8734a9aa7bf4ee8316d462a08c6ac5052f888fef5b494b" +dependencies = [ + "windows-sys", +] + +[[package]] +name = "anstyle-wincon" +version = "2.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "58f54d10c6dfa51283a066ceab3ec1ab78d13fae00aa49243a45e4571fb79dfd" +dependencies = [ + "anstyle", + "windows-sys", +] + +[[package]] +name = "anyhow" +version = "1.0.75" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a4668cab20f66d8d020e1fbc0ebe47217433c1b6c8f2040faf858554e394ace6" + [[package]] name = "async-trait" version = "0.1.73" @@ -49,7 +113,7 @@ checksum = "bc00ceb34980c03614e35a3a4e218276a0a824e911d07651cd0d858a51e8c0f0" dependencies = [ "proc-macro2", "quote", - "syn 2.0.29", + "syn 2.0.31", ] [[package]] @@ -60,7 +124,7 @@ checksum = "d9b39be18770d11421cdb1b9947a45dd3f37e93092cbf377614828a319d5fee8" dependencies = [ "hermit-abi 0.1.19", "libc", - "winapi 0.3.9", + "winapi", ] [[package]] @@ -77,7 +141,7 @@ checksum = "2089b7e3f35b9dd2d0ed921ead4f6d318c27680d4a5bd167b3ee120edb105837" dependencies = [ "addr2line", "cc", - "cfg-if 1.0.0", + "cfg-if", "libc", "miniz_oxide", "object", @@ -90,6 +154,12 @@ version = "0.13.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9e1b586273c5702936fe7b7d6896644d8be71e6314cfe09d3167c95f712589e8" +[[package]] +name = "base64" +version = "0.21.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "414dcefbc63d77c526a76b3afcf6fbb9b5e2791c19c3aa2297733208750c6e53" + [[package]] name = "bitflags" version = "1.3.2" @@ -108,12 +178,6 @@ version = "3.13.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "a3e2c3daef883ecc1b5d58c15adae93470a91d425f3532ba1695849656af3fc1" -[[package]] -name = "bytes" -version = "0.5.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0e4cec68f03f32e44924783795810fa50a7035d8c8ebe78580ad7e6c703fba38" - [[package]] name = "bytes" version = "1.4.0" @@ -131,22 +195,20 @@ dependencies = [ [[package]] name = "cfdyndns" -version = "0.0.3" +version = "0.1.1" dependencies = [ + "addr", + "anyhow", + "clap", + "clap-verbosity-flag", + "cloudflare", "log", "pretty_env_logger", - "reqwest", - "serde", + "public-ip", "serde_json", - "trust-dns-client", + "tokio", ] -[[package]] -name = "cfg-if" -version = "0.1.10" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4785bdd1c96b2a846b2bd7cc02e86b6b3dbf14e7e53446c4f54c92a361040822" - [[package]] name = "cfg-if" version = "1.0.0" @@ -155,19 +217,98 @@ checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd" [[package]] name = "chrono" -version = "0.4.28" +version = "0.4.29" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "95ed24df0632f708f5f6d8082675bef2596f7084dee3dd55f632290bf35bfe0f" +checksum = "d87d9d13be47a5b7c3907137f1290b0459a7f80efb26be8c52afb11963bccb02" dependencies = [ "android-tzdata", "iana-time-zone", "js-sys", "num-traits", - "time", + "serde", + "time 0.1.45", "wasm-bindgen", "windows-targets", ] +[[package]] +name = "clap" +version = "4.4.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6a13b88d2c62ff462f88e4a121f17a82c1af05693a2f192b5c38d14de73c19f6" +dependencies = [ + "clap_builder", + "clap_derive", +] + +[[package]] +name = "clap-verbosity-flag" +version = "2.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1eef05769009513df2eb1c3b4613e7fad873a14c600ff025b08f250f59fee7de" +dependencies = [ + "clap", + "log", +] + +[[package]] +name = "clap_builder" +version = "4.4.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2bb9faaa7c2ef94b2743a21f5a29e6f0010dff4caa69ac8e9d6cf8b6fa74da08" +dependencies = [ + "anstream", + "anstyle", + "clap_lex", + "strsim 0.10.0", + "terminal_size", +] + +[[package]] +name = "clap_derive" +version = "4.4.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0862016ff20d69b84ef8247369fabf5c008a7417002411897d40ee1f4532b873" +dependencies = [ + "heck", + "proc-macro2", + "quote", + "syn 2.0.31", +] + +[[package]] +name = "clap_lex" +version = "0.5.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cd7cc57abe963c6d3b9d8be5b06ba7c8957a930305ca90304f24ef040aa6f961" + +[[package]] +name = "cloudflare" +version = "0.10.1" +source = "git+https://github.com/jcgruenhage/cloudflare-rs.git?branch=make-owner-fields-optional#02397fc4211886548a31a0731b240f2e17309de4" +dependencies = [ + "anyhow", + "async-trait", + "base64 0.13.1", + "cfg-if", + "chrono", + "http", + "percent-encoding", + "reqwest", + "serde", + "serde_json", + "serde_qs", + "serde_with", + "url", + "uuid", +] + +[[package]] +name = "colorchoice" +version = "1.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "acbf1af155f9b9ef647e42cdc158db4b64a1b61f743629225fde6f3e0be2a7c7" + [[package]] name = "core-foundation" version = "0.9.3" @@ -184,19 +325,135 @@ version = "0.8.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e496a50fda8aacccc86d7529e2c1e0892dbd0f898a6b5645b5561b89c3210efa" +[[package]] +name = "darling" +version = "0.10.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0d706e75d87e35569db781a9b5e2416cff1236a47ed380831f959382ccd5f858" +dependencies = [ + "darling_core 0.10.2", + "darling_macro 0.10.2", +] + +[[package]] +name = "darling" +version = "0.20.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0209d94da627ab5605dcccf08bb18afa5009cfbef48d8a8b7d7bdbc79be25c5e" +dependencies = [ + "darling_core 0.20.3", + "darling_macro 0.20.3", +] + +[[package]] +name = "darling_core" +version = "0.10.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f0c960ae2da4de88a91b2d920c2a7233b400bc33cb28453a2987822d8392519b" +dependencies = [ + "fnv", + "ident_case", + "proc-macro2", + "quote", + "strsim 0.9.3", + "syn 1.0.109", +] + +[[package]] +name = "darling_core" +version = "0.20.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "177e3443818124b357d8e76f53be906d60937f0d3a90773a664fa63fa253e621" +dependencies = [ + "fnv", + "ident_case", + "proc-macro2", + "quote", + "strsim 0.10.0", + "syn 2.0.31", +] + +[[package]] +name = "darling_macro" +version = "0.10.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d9b5a2f4ac4969822c62224815d069952656cadc7084fdca9751e6d959189b72" +dependencies = [ + "darling_core 0.10.2", + "quote", + "syn 1.0.109", +] + +[[package]] +name = "darling_macro" +version = "0.20.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "836a9bbc7ad63342d6d6e7b815ccab164bc77a2d95d84bc3117a8c0d5c98e2d5" +dependencies = [ + "darling_core 0.20.3", + "quote", + "syn 2.0.31", +] + [[package]] name = "data-encoding" version = "2.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "c2e66c9d817f1720209181c316d28635c050fa304f9c79e47a520882661b7308" +[[package]] +name = "deranged" +version = "0.3.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f2696e8a945f658fd14dc3b87242e6b80cd0f36ff04ea560fa39082368847946" +dependencies = [ + "serde", +] + +[[package]] +name = "derive_builder" +version = "0.9.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a2658621297f2cf68762a6f7dc0bb7e1ff2cfd6583daef8ee0fed6f7ec468ec0" +dependencies = [ + "darling 0.10.2", + "derive_builder_core", + "proc-macro2", + "quote", + "syn 1.0.109", +] + +[[package]] +name = "derive_builder_core" +version = "0.9.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2791ea3e372c8495c0bc2033991d76b512cd799d07491fbd6890124db9458bef" +dependencies = [ + "darling 0.10.2", + "proc-macro2", + "quote", + "syn 1.0.109", +] + +[[package]] +name = "dns-lookup" +version = "1.0.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "53ecafc952c4528d9b51a458d1a8904b81783feff9fde08ab6ed2545ff396872" +dependencies = [ + "cfg-if", + "libc", + "socket2 0.4.9", + "winapi", +] + [[package]] name = "encoding_rs" version = "0.8.33" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "7268b386296a025e474d5140678f75d6de9493ae55a5d709eeb9dd08149945e1" dependencies = [ - "cfg-if 1.0.0", + "cfg-if", ] [[package]] @@ -207,9 +464,9 @@ checksum = "c34f04666d835ff5d62e058c3995147c06f42fe86ff053337632bca83e42702d" [[package]] name = "enum-as-inner" -version = "0.3.4" +version = "0.5.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "570d109b813e904becc80d8d5da38376818a143348413f7149f1340fe04754d4" +checksum = "c9720bba047d567ffc8a3cba48bf19126600e249ab7f128e9233e6376976a116" dependencies = [ "heck", "proc-macro2", @@ -287,22 +544,6 @@ dependencies = [ "percent-encoding", ] -[[package]] -name = "fuchsia-zircon" -version = "0.3.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2e9763c69ebaae630ba35f74888db465e49e259ba1bc0eda7d06f4a067615d82" -dependencies = [ - "bitflags 1.3.2", - "fuchsia-zircon-sys", -] - -[[package]] -name = "fuchsia-zircon-sys" -version = "0.3.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3dcaa9ae7725d12cdb85b3ad99a434db70b468c09ded17e012d86b5c1010f7a7" - [[package]] name = "futures" version = "0.3.28" @@ -311,6 +552,7 @@ checksum = "23342abe12aba583913b2e62f22225ff9c950774065e4bfb61a19cd9770fec40" dependencies = [ "futures-channel", "futures-core", + "futures-executor", "futures-io", "futures-sink", "futures-task", @@ -333,12 +575,34 @@ version = "0.3.28" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "4bca583b7e26f571124fe5b7561d49cb2868d79116cfa0eefce955557c6fee8c" +[[package]] +name = "futures-executor" +version = "0.3.28" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ccecee823288125bd88b4d7f565c9e58e41858e47ab72e8ea2d64e93624386e0" +dependencies = [ + "futures-core", + "futures-task", + "futures-util", +] + [[package]] name = "futures-io" version = "0.3.28" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "4fff74096e71ed47f8e023204cfd0aa1289cd54ae5430a9523be060cdb849964" +[[package]] +name = "futures-macro" +version = "0.3.28" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "89ca545a94061b6365f2c7355b4b32bd20df3ff95f02da9329b34ccc3bd6ee72" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.31", +] + [[package]] name = "futures-sink" version = "0.3.28" @@ -360,23 +624,24 @@ dependencies = [ "futures-channel", "futures-core", "futures-io", + "futures-macro", "futures-sink", "futures-task", "memchr", - "pin-project-lite 0.2.13", + "pin-project-lite", "pin-utils", "slab", ] [[package]] name = "getrandom" -version = "0.1.16" +version = "0.2.10" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8fc3cb4d91f53b50155bdcfd23f6a4c39ae1969c2ae85982b135750cccaf5fce" +checksum = "be4136b2a15dd319360be1c07d9933517ccf0be8f16bf62a3bee4f0d618df427" dependencies = [ - "cfg-if 1.0.0", + "cfg-if", "libc", - "wasi 0.9.0+wasi-snapshot-preview1", + "wasi 0.11.0+wasi-snapshot-preview1", ] [[package]] @@ -387,11 +652,11 @@ checksum = "6fb8d784f27acf97159b40fc4db5ecd8aa23b9ad5ef69cdd136d3bc80665f0c0" [[package]] name = "h2" -version = "0.2.7" +version = "0.3.21" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5e4728fd124914ad25e99e3d15a9361a879f6620f63cb56bbb08f95abb97a535" +checksum = "91fc23aa11be92976ef4729127f1a74adf36d8436f7816b185d18df956790833" dependencies = [ - "bytes 0.5.6", + "bytes", "fnv", "futures-core", "futures-sink", @@ -402,7 +667,6 @@ dependencies = [ "tokio", "tokio-util", "tracing", - "tracing-futures", ] [[package]] @@ -432,25 +696,32 @@ version = "0.3.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "443144c8cdadd93ebf52ddb4056d257f5b52c04d3c804e657d19eb73fc33668b" +[[package]] +name = "hex" +version = "0.4.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7f24254aa9a54b5c858eaee2f5bccdb46aaf0e486a595ed5fd8f86ba55232a70" + [[package]] name = "http" version = "0.2.9" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "bd6effc99afb63425aff9b05836f029929e345a6148a14b7ecd5ab67af944482" dependencies = [ - "bytes 1.4.0", + "bytes", "fnv", - "itoa 1.0.9", + "itoa", ] [[package]] name = "http-body" -version = "0.3.1" +version = "0.4.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "13d5ff830006f7646652e057693569bfe0d51760c0085a071769d142a205111b" +checksum = "d5f38f16d184e36f2408a55281cd658ecbd3ca05cce6d6510a176eca393e26d1" dependencies = [ - "bytes 0.5.6", + "bytes", "http", + "pin-project-lite", ] [[package]] @@ -461,9 +732,9 @@ checksum = "d897f394bad6a705d5f4104762e116a75639e470d80901eed05a860a95cb1904" [[package]] name = "httpdate" -version = "0.3.2" +version = "1.0.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "494b4d60369511e7dea41cf646832512a94e542f68bb9c49e54518e0f468eb47" +checksum = "df3b46402a9d5adb4c86a0cf463f42e19994e3ee891101b1841f30a545cb49a9" [[package]] name = "humantime" @@ -476,11 +747,11 @@ dependencies = [ [[package]] name = "hyper" -version = "0.13.10" +version = "0.14.27" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8a6f157065790a3ed2f88679250419b5cdd96e714a0d65f7797fd337186e96bb" +checksum = "ffb1cfd654a8219eaef89881fdb3bb3b1cdc5fa75ded05d6933b2b382e395468" dependencies = [ - "bytes 0.5.6", + "bytes", "futures-channel", "futures-core", "futures-util", @@ -489,26 +760,58 @@ dependencies = [ "http-body", "httparse", "httpdate", - "itoa 0.4.8", - "pin-project", - "socket2", + "itoa", + "pin-project-lite", + "socket2 0.4.9", "tokio", "tower-service", "tracing", "want", ] +[[package]] +name = "hyper-openssl" +version = "0.9.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d6ee5d7a8f718585d1c3c61dfde28ef5b0bb14734b4db13f5ada856cdc6c612b" +dependencies = [ + "http", + "hyper", + "linked_hash_set", + "once_cell", + "openssl", + "openssl-sys", + "parking_lot", + "tokio", + "tokio-openssl", + "tower-layer", +] + +[[package]] +name = "hyper-system-resolver" +version = "0.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6eea26c5d0b6ab9d72219f65000af310f042a740926f7b2fa3553e774036e2e7" +dependencies = [ + "derive_builder", + "dns-lookup", + "hyper", + "tokio", + "tower-service", + "tracing", +] + [[package]] name = "hyper-tls" -version = "0.4.3" +version = "0.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d979acc56dcb5b8dddba3917601745e877576475aa046df3226eabdecef78eed" +checksum = "d6183ddfa99b85da61a140bea0efc93fdf56ceaa041b37d553518030827f9905" dependencies = [ - "bytes 0.5.6", + "bytes", "hyper", "native-tls", "tokio", - "tokio-tls", + "tokio-native-tls", ] [[package]] @@ -534,6 +837,12 @@ dependencies = [ "cc", ] +[[package]] +name = "ident_case" +version = "1.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b9e0384b61958566e926dc50660321d12159025e767c18e043daf26b70104c39" + [[package]] name = "idna" version = "0.2.3" @@ -563,15 +872,18 @@ checksum = "bd070e393353796e801d209ad339e89596eb4c8d430d18ede6a1cced8fafbd99" dependencies = [ "autocfg", "hashbrown", + "serde", ] [[package]] -name = "iovec" -version = "0.1.4" +name = "io-lifetimes" +version = "1.0.11" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b2b3ea6ff95e175473f8ffe6a7eb7c00d054240321b84c57051175fe3c1e075e" +checksum = "eae7b9aee968036d54dce06cebaefd919e4472e753296daccd6d344e3e2df0c2" dependencies = [ + "hermit-abi 0.3.2", "libc", + "windows-sys", ] [[package]] @@ -580,12 +892,6 @@ version = "2.8.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "28b29a3cd74f0f4598934efe3aeba42bae0eb4680554128851ebbecb02af14e6" -[[package]] -name = "itoa" -version = "0.4.8" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b71991ff56294aa922b450139ee08b3bfc70982c6b2c7562771375cf73542dd4" - [[package]] name = "itoa" version = "1.0.9" @@ -601,16 +907,6 @@ dependencies = [ "wasm-bindgen", ] -[[package]] -name = "kernel32-sys" -version = "0.2.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7507624b29483431c0ba2d82aece8ca6cdba9382bff4ddd0f7490560c056098d" -dependencies = [ - "winapi 0.2.8", - "winapi-build", -] - [[package]] name = "lazy_static" version = "1.4.0" @@ -623,12 +919,43 @@ version = "0.2.147" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b4668fb0ea861c1df094127ac5f1da3409a82116a4ba74fca2e58ef927159bb3" +[[package]] +name = "linked-hash-map" +version = "0.5.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0717cef1bc8b636c6e1c1bbdefc09e6322da8a9321966e8928ef80d20f7f770f" + +[[package]] +name = "linked_hash_set" +version = "0.1.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "47186c6da4d81ca383c7c47c1bfc80f4b95f4720514d860a5407aaf4233f9588" +dependencies = [ + "linked-hash-map", +] + +[[package]] +name = "linux-raw-sys" +version = "0.3.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ef53942eb7bf7ff43a617b3e2c1c4a5ecf5944a7c1bc12d7ee39bbb15e5c1519" + [[package]] name = "linux-raw-sys" version = "0.4.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "57bcfdad1b858c2db7c38303a6d2ad4dfaf5eb53dfeb0910128b2c26d6158503" +[[package]] +name = "lock_api" +version = "0.4.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c1cc9717a20b1bb222f333e6a92fd32f7d8a18ddc5a3191a11af45dcbf4dcd16" +dependencies = [ + "autocfg", + "scopeguard", +] + [[package]] name = "log" version = "0.4.20" @@ -643,9 +970,9 @@ checksum = "2532096657941c2fea9c289d370a250971c689d4f143798ff67113ec042024a5" [[package]] name = "memchr" -version = "2.6.2" +version = "2.6.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5486aed0026218e61b8a01d5fbd5a0a134649abb71a0e53b7bc088529dced86e" +checksum = "8f232d6ef707e1956a43342693d2a31e72989554d58299d7a88738cc95b0d35c" [[package]] name = "mime" @@ -653,16 +980,6 @@ version = "0.3.17" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "6877bb514081ee2a7ff5ef9de3281f14a4dd4bceac4c09388074a6b5df8a139a" -[[package]] -name = "mime_guess" -version = "2.0.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4192263c238a5f0d0c6bfd21f336a313a4ce1c450542449ca191bb657b4642ef" -dependencies = [ - "mime", - "unicase", -] - [[package]] name = "miniz_oxide" version = "0.7.1" @@ -674,33 +991,13 @@ dependencies = [ [[package]] name = "mio" -version = "0.6.23" +version = "0.8.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4afd66f5b91bf2a3bc13fad0e21caedac168ca4c707504e75585648ae80e4cc4" +checksum = "927a765cd3fc26206e66b296465fa9d3e5ab003e651c1b3c060e7956d96b19d2" dependencies = [ - "cfg-if 0.1.10", - "fuchsia-zircon", - "fuchsia-zircon-sys", - "iovec", - "kernel32-sys", "libc", - "log", - "miow", - "net2", - "slab", - "winapi 0.2.8", -] - -[[package]] -name = "miow" -version = "0.2.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ebd808424166322d4a38da87083bfddd3ac4c131334ed55856112eb06d46944d" -dependencies = [ - "kernel32-sys", - "net2", - "winapi 0.2.8", - "ws2_32-sys", + "wasi 0.11.0+wasi-snapshot-preview1", + "windows-sys", ] [[package]] @@ -722,22 +1019,14 @@ dependencies = [ ] [[package]] -name = "net2" -version = "0.2.39" +name = "nibble_vec" +version = "0.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b13b648036a2339d06de780866fbdfda0dde886de7b3af2ddeba8b14f4ee34ac" +checksum = "77a5d83df9f36fe23f0c3648c6bbb8b0298bb5f1939c8f2704431371f4b84d43" dependencies = [ - "cfg-if 0.1.10", - "libc", - "winapi 0.3.9", + "smallvec", ] -[[package]] -name = "nibble_vec" -version = "0.0.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c8d77f3db4bce033f4d04db08079b2ef1c3d02b44e86f25d08886fafa7756ffa" - [[package]] name = "num-traits" version = "0.2.16" @@ -759,9 +1048,9 @@ dependencies = [ [[package]] name = "object" -version = "0.32.0" +version = "0.32.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "77ac5bbd07aea88c60a577a1ce218075ffd59208b2d7ca97adf9bfc5aeb21ebe" +checksum = "9cf5f9dd3933bd50a9e1f149ec995f39ae2c496d31fd772c1fd45ebc27e902b0" dependencies = [ "memchr", ] @@ -779,7 +1068,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "bac25ee399abb46215765b1cb35bc0212377e58a061560d8b29b024fd0430e7c" dependencies = [ "bitflags 2.4.0", - "cfg-if 1.0.0", + "cfg-if", "foreign-types", "libc", "once_cell", @@ -795,7 +1084,7 @@ checksum = "a948666b637a0f465e8564c73e89d4dde00d72d4d473cc972f390fc3dcee7d9c" dependencies = [ "proc-macro2", "quote", - "syn 2.0.29", + "syn 2.0.31", ] [[package]] @@ -806,9 +1095,9 @@ checksum = "ff011a302c396a5197692431fc1948019154afc178baf7d8e37367442a4601cf" [[package]] name = "openssl-sys" -version = "0.9.92" +version = "0.9.93" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "db7e971c2c2bba161b2d2fdf37080177eff520b3bc044787c7f1f5f9e78d869b" +checksum = "db4d56a4c0478783083cfafcc42493dd4a981d41669da64b4572a2a089b51b1d" dependencies = [ "cc", "libc", @@ -816,6 +1105,29 @@ dependencies = [ "vcpkg", ] +[[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.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "93f00c865fe7cabf650081affecd3871070f26767e7b2070a3ffae14c654b447" +dependencies = [ + "cfg-if", + "libc", + "redox_syscall", + "smallvec", + "windows-targets", +] + [[package]] name = "percent-encoding" version = "2.3.0" @@ -839,15 +1151,9 @@ checksum = "4359fd9c9171ec6e8c62926d6faaf553a8dc3f64e1507e76da7911b4f6a04405" dependencies = [ "proc-macro2", "quote", - "syn 2.0.29", + "syn 2.0.31", ] -[[package]] -name = "pin-project-lite" -version = "0.1.12" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "257b64915a082f7811703966789728173279bdebb956b143dbcd23f6f970a777" - [[package]] name = "pin-project-lite" version = "0.2.13" @@ -891,6 +1197,44 @@ dependencies = [ "unicode-ident", ] +[[package]] +name = "psl" +version = "2.1.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4a1be0afcd844b15cfce18bf8cccf2dfa887a00a6454a9ea135f122b948cee91" +dependencies = [ + "psl-types", +] + +[[package]] +name = "psl-types" +version = "2.0.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "33cb294fe86a74cbcf50d4445b37da762029549ebeea341421c7c70370f86cac" + +[[package]] +name = "public-ip" +version = "0.2.2" +source = "git+https://github.com/jcgruenhage/rust-public-ip.git?branch=cloudflare-provider#f0f0e68aebf9d796deaa3af04c8c6d4df3c515fe" +dependencies = [ + "dns-lookup", + "futures-core", + "futures-util", + "http", + "hyper", + "hyper-openssl", + "hyper-system-resolver", + "openssl", + "pin-project-lite", + "thiserror", + "tokio", + "tower-layer", + "tracing", + "tracing-futures", + "trust-dns-client", + "trust-dns-proto", +] + [[package]] name = "quick-error" version = "1.2.3" @@ -908,9 +1252,9 @@ dependencies = [ [[package]] name = "radix_trie" -version = "0.1.6" +version = "0.2.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3d3681b28cd95acfb0560ea9441f82d6a4504fa3b15b97bd7b6e952131820e95" +checksum = "c069c179fcdc6a2fe24d8d18305cf085fdbd4f922c041943e203685d6a1c58fd" dependencies = [ "endian-type", "nibble_vec", @@ -918,22 +1262,20 @@ dependencies = [ [[package]] name = "rand" -version = "0.7.3" +version = "0.8.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6a6b1679d49b24bbfe0c803429aa1874472f50d9b363131f0e89fc356b544d03" +checksum = "34af8d1a0e25924bc5b7c43c079c942339d8f0a8b57c39049bef581b46327404" dependencies = [ - "getrandom", "libc", "rand_chacha", "rand_core", - "rand_hc", ] [[package]] name = "rand_chacha" -version = "0.2.2" +version = "0.3.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f4c8ed856279c9737206bf725bf36935d8666ead7aa69b52be55af369d193402" +checksum = "e6c10a63a0fa32252be49d21e7709d4d4baf8d231c2dbce1eaa8141b9b127d88" dependencies = [ "ppv-lite86", "rand_core", @@ -941,22 +1283,13 @@ dependencies = [ [[package]] name = "rand_core" -version = "0.5.1" +version = "0.6.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "90bde5296fc891b0cef12a6d03ddccc162ce7b2aff54160af9338f8d40df6d19" +checksum = "ec0be4795e2f6a28069bec0b5ff3e2ac9bafc99e6a9a7dc3547996c5c816922c" dependencies = [ "getrandom", ] -[[package]] -name = "rand_hc" -version = "0.2.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ca3129af7b92a17112d59ad498c6f81eaf463253766b90396d39ea7a39d6613c" -dependencies = [ - "rand_core", -] - [[package]] name = "redox_syscall" version = "0.3.5" @@ -968,9 +1301,9 @@ dependencies = [ [[package]] name = "regex" -version = "1.9.4" +version = "1.9.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "12de2eff854e5fa4b1295edd650e227e9d8fb0c9e90b12e7f36d6a6811791a29" +checksum = "697061221ea1b4a94a624f67d0ae2bfe4e22b8a17b6a192afb11046542cc8c47" dependencies = [ "aho-corasick", "memchr", @@ -980,9 +1313,9 @@ dependencies = [ [[package]] name = "regex-automata" -version = "0.3.7" +version = "0.3.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "49530408a136e16e5b486e883fbb6ba058e8e4e8ae6621a77b048b314336e629" +checksum = "c2f401f4955220693b56f8ec66ee9c78abffd8d1c4f23dc41a23839eb88f0795" dependencies = [ "aho-corasick", "memchr", @@ -997,33 +1330,34 @@ checksum = "dbb5fb1acd8a1a18b3dd5be62d25485eb770e05afb408a9627d14d451bae12da" [[package]] name = "reqwest" -version = "0.10.10" +version = "0.11.20" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0718f81a8e14c4dbb3b34cf23dc6aaf9ab8a0dfec160c534b3dbca1aaa21f47c" +checksum = "3e9ad3fe7488d7e34558a2033d45a0c90b72d97b4f80705666fea71472e2e6a1" dependencies = [ - "base64", - "bytes 0.5.6", + "base64 0.21.3", + "bytes", "encoding_rs", "futures-core", "futures-util", + "h2", "http", "http-body", "hyper", "hyper-tls", "ipnet", "js-sys", - "lazy_static", "log", "mime", - "mime_guess", "native-tls", + "once_cell", "percent-encoding", - "pin-project-lite 0.2.13", + "pin-project-lite", "serde", "serde_json", "serde_urlencoded", "tokio", - "tokio-tls", + "tokio-native-tls", + "tower-service", "url", "wasm-bindgen", "wasm-bindgen-futures", @@ -1039,14 +1373,28 @@ checksum = "d626bb9dae77e28219937af045c257c28bfd3f69333c512553507f5f9798cb76" [[package]] name = "rustix" -version = "0.38.10" +version = "0.37.23" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4d69718bf81c6127a49dc64e44a742e8bb9213c0ff8869a22c308f84c1d4ab06" +dependencies = [ + "bitflags 1.3.2", + "errno", + "io-lifetimes", + "libc", + "linux-raw-sys 0.3.8", + "windows-sys", +] + +[[package]] +name = "rustix" +version = "0.38.11" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ed6248e1caa625eb708e266e06159f135e8c26f2bb7ceb72dc4b2766d0340964" +checksum = "c0c3dde1fc030af041adc40e79c0e7fbcf431dd24870053d187d7c66e4b87453" dependencies = [ "bitflags 2.4.0", "errno", "libc", - "linux-raw-sys", + "linux-raw-sys 0.4.5", "windows-sys", ] @@ -1065,6 +1413,12 @@ dependencies = [ "windows-sys", ] +[[package]] +name = "scopeguard" +version = "1.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "94143f37725109f92c262ed2cf5e59bce7498c01bcc1502d7b9afe439a4e9f49" + [[package]] name = "security-framework" version = "2.9.2" @@ -1105,7 +1459,7 @@ checksum = "4eca7ac642d82aa35b60049a6eccb4be6be75e599bd2e9adb5f875a737654af2" dependencies = [ "proc-macro2", "quote", - "syn 2.0.29", + "syn 2.0.31", ] [[package]] @@ -1114,11 +1468,22 @@ version = "1.0.105" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "693151e1ac27563d6dbcec9dee9fbd5da8539b20fa14ad3752b2e6d363ace360" dependencies = [ - "itoa 1.0.9", + "itoa", "ryu", "serde", ] +[[package]] +name = "serde_qs" +version = "0.10.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8cac3f1e2ca2fe333923a1ae72caca910b98ed0630bb35ef6f8c8517d6e81afa" +dependencies = [ + "percent-encoding", + "serde", + "thiserror", +] + [[package]] name = "serde_urlencoded" version = "0.7.1" @@ -1126,11 +1491,39 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d3491c14715ca2294c4d6a88f15e84739788c1d030eed8c110436aafdaa2f3fd" dependencies = [ "form_urlencoded", - "itoa 1.0.9", + "itoa", "ryu", "serde", ] +[[package]] +name = "serde_with" +version = "2.3.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "07ff71d2c147a7b57362cead5e22f772cd52f6ab31cfcd9edcd7f6aeb2a0afbe" +dependencies = [ + "base64 0.13.1", + "chrono", + "hex", + "indexmap", + "serde", + "serde_json", + "serde_with_macros", + "time 0.3.28", +] + +[[package]] +name = "serde_with_macros" +version = "2.3.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "881b6f881b17d13214e5d494c939ebab463d01264ce1811e9d4ac3a882e7695f" +dependencies = [ + "darling 0.20.3", + "proc-macro2", + "quote", + "syn 2.0.31", +] + [[package]] name = "slab" version = "0.4.9" @@ -1148,15 +1541,36 @@ checksum = "62bb4feee49fdd9f707ef802e22365a35de4b7b299de4763d44bfea899442ff9" [[package]] name = "socket2" -version = "0.3.19" +version = "0.4.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "64a4a911eed85daf18834cfaa86a79b7d266ff93ff5ba14005426219480ed662" +dependencies = [ + "libc", + "winapi", +] + +[[package]] +name = "socket2" +version = "0.5.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "122e570113d28d773067fab24266b66753f6ea915758651696b6e35e49f88d6e" +checksum = "2538b18701741680e0322a2302176d3253a35388e2e62f172f64f4f16605f877" dependencies = [ - "cfg-if 1.0.0", "libc", - "winapi 0.3.9", + "windows-sys", ] +[[package]] +name = "strsim" +version = "0.9.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6446ced80d6c486436db5c078dde11a9f73d42b57fb273121e160b84f63d894c" + +[[package]] +name = "strsim" +version = "0.10.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "73473c0e59e6d5812c5dfe2a064a6444949f089e20eec9a2e5506596494e4623" + [[package]] name = "syn" version = "1.0.109" @@ -1170,9 +1584,9 @@ dependencies = [ [[package]] name = "syn" -version = "2.0.29" +version = "2.0.31" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c324c494eba9d92503e6f1ef2e6df781e78f6a7705a0202d9801b198807d518a" +checksum = "718fa2415bcb8d8bd775917a1bf12a7931b6dfa890753378538118181e0cb398" dependencies = [ "proc-macro2", "quote", @@ -1185,10 +1599,10 @@ version = "3.8.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "cb94d2f3cc536af71caac6b6fcebf65860b347e7ce0cc9ebe8f70d3e521054ef" dependencies = [ - "cfg-if 1.0.0", + "cfg-if", "fastrand", "redox_syscall", - "rustix", + "rustix 0.38.11", "windows-sys", ] @@ -1201,24 +1615,34 @@ dependencies = [ "winapi-util", ] +[[package]] +name = "terminal_size" +version = "0.2.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8e6bf6f19e9f8ed8d4048dc22981458ebcf406d67e94cd422e5ecd73d63b3237" +dependencies = [ + "rustix 0.37.23", + "windows-sys", +] + [[package]] name = "thiserror" -version = "1.0.47" +version = "1.0.48" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "97a802ec30afc17eee47b2855fc72e0c4cd62be9b4efe6591edde0ec5bd68d8f" +checksum = "9d6d7a740b8a666a7e828dd00da9c0dc290dff53154ea77ac109281de90589b7" dependencies = [ "thiserror-impl", ] [[package]] name = "thiserror-impl" -version = "1.0.47" +version = "1.0.48" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6bb623b56e39ab7dcd4b1b98bb6c8f8d907ed255b18de254088016b27a8ee19b" +checksum = "49922ecae66cc8a249b77e68d1d0623c1b2c514f0060c27cdc68bd62a1219d35" dependencies = [ "proc-macro2", "quote", - "syn 2.0.29", + "syn 2.0.31", ] [[package]] @@ -1229,7 +1653,35 @@ checksum = "1b797afad3f312d1c66a56d11d0316f916356d11bd158fbc6ca6389ff6bf805a" dependencies = [ "libc", "wasi 0.10.0+wasi-snapshot-preview1", - "winapi 0.3.9", + "winapi", +] + +[[package]] +name = "time" +version = "0.3.28" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "17f6bb557fd245c28e6411aa56b6403c689ad95061f50e4be16c274e70a17e48" +dependencies = [ + "deranged", + "itoa", + "serde", + "time-core", + "time-macros", +] + +[[package]] +name = "time-core" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7300fbefb4dadc1af235a9cef3737cea692a9d97e1b9cbcd4ebdae6f8868e6fb" + +[[package]] +name = "time-macros" +version = "0.2.14" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1a942f44339478ef67935ab2bbaec2fb0322496cf3cbe84b261e06ac3814c572" +dependencies = [ + "time-core", ] [[package]] @@ -1249,46 +1701,74 @@ checksum = "1f3ccbac311fea05f86f61904b462b55fb3df8837a366dfc601a0161d0532f20" [[package]] name = "tokio" -version = "0.2.25" +version = "1.32.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6703a273949a90131b290be1fe7b039d0fc884aa1935860dfcbe056f28cd8092" +checksum = "17ed6077ed6cd6c74735e21f37eb16dc3935f96878b1fe961074089cc80893f9" dependencies = [ - "bytes 0.5.6", - "fnv", - "futures-core", - "iovec", - "lazy_static", - "memchr", + "backtrace", + "bytes", + "libc", "mio", "num_cpus", - "pin-project-lite 0.1.12", - "slab", + "pin-project-lite", + "socket2 0.5.3", + "tokio-macros", + "windows-sys", ] [[package]] -name = "tokio-tls" +name = "tokio-macros" +version = "2.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "630bdcf245f78637c13ec01ffae6187cca34625e8c63150d424b59e55af2675e" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.31", +] + +[[package]] +name = "tokio-native-tls" version = "0.3.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9a70f4fcd7b3b24fb194f837560168208f669ca8cb70d0c4b862944452396343" +checksum = "bbae76ab933c85776efabc971569dd6119c580d8f5d448769dec1764bf796ef2" dependencies = [ "native-tls", "tokio", ] +[[package]] +name = "tokio-openssl" +version = "0.6.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c08f9ffb7809f1b20c1b398d92acf4cc719874b3b2b2d9ea2f09b4a80350878a" +dependencies = [ + "futures-util", + "openssl", + "openssl-sys", + "tokio", +] + [[package]] name = "tokio-util" -version = "0.3.1" +version = "0.7.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "be8242891f2b6cbef26a2d7e8605133c2c554cd35b3e4948ea892d6d68436499" +checksum = "806fe8c2c87eccc8b3267cbae29ed3ab2d0bd37fca70ab622e46aaa9375ddb7d" dependencies = [ - "bytes 0.5.6", + "bytes", "futures-core", "futures-sink", - "log", - "pin-project-lite 0.1.12", + "pin-project-lite", "tokio", + "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" @@ -1301,12 +1781,23 @@ version = "0.1.37" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "8ce8c33a8d48bd45d624a6e523445fd21ec13d3653cd51f681abf67418f54eb8" dependencies = [ - "cfg-if 1.0.0", - "log", - "pin-project-lite 0.2.13", + "cfg-if", + "pin-project-lite", + "tracing-attributes", "tracing-core", ] +[[package]] +name = "tracing-attributes" +version = "0.1.26" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5f4f31f56159e98206da9efd823404b79b6ef3143b4a7ab76e67b1751b25a4ab" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.31", +] + [[package]] name = "tracing-core" version = "0.1.31" @@ -1322,48 +1813,54 @@ version = "0.2.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "97d095ae15e245a057c8e8451bab9b3ee1e1f68e9ba2b4fbc18d0ac5237835f2" dependencies = [ + "futures", + "futures-task", "pin-project", "tracing", ] [[package]] name = "trust-dns-client" -version = "0.19.7" +version = "0.22.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e935ae5a26a2745fb5a6b95f0e206e1cfb7f00066892d2cf78a8fee87bc2e0c6" +checksum = "6c408c32e6a9dbb38037cece35740f2cf23c875d8ca134d33631cec83f74d3fe" dependencies = [ - "cfg-if 1.0.0", - "chrono", + "cfg-if", "data-encoding", - "futures", + "futures-channel", + "futures-util", "lazy_static", - "log", "radix_trie", "rand", "thiserror", + "time 0.3.28", "tokio", + "tracing", "trust-dns-proto", ] [[package]] name = "trust-dns-proto" -version = "0.19.7" +version = "0.22.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1cad71a0c0d68ab9941d2fb6e82f8fb2e86d9945b94e1661dd0aaea2b88215a9" +checksum = "4f7f83d1e4a0e4358ac54c5c3681e5d7da5efc5a7a632c90bb6d6669ddd9bc26" dependencies = [ "async-trait", - "backtrace", - "cfg-if 1.0.0", + "cfg-if", "data-encoding", "enum-as-inner", - "futures", + "futures-channel", + "futures-io", + "futures-util", "idna 0.2.3", + "ipnet", "lazy_static", - "log", "rand", "smallvec", "thiserror", + "tinyvec", "tokio", + "tracing", "url", ] @@ -1373,15 +1870,6 @@ version = "0.2.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "3528ecfd12c466c6f163363caf2d02a71161dd5e1cc6ae7b34207ea2d42d81ed" -[[package]] -name = "unicase" -version = "2.7.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f7d2d4dafb69621809a81864c9c1b864479e1235c0dd4e199924b9742439ed89" -dependencies = [ - "version_check", -] - [[package]] name = "unicode-bidi" version = "0.3.13" @@ -1415,16 +1903,26 @@ dependencies = [ ] [[package]] -name = "vcpkg" -version = "0.2.15" +name = "utf8parse" +version = "0.2.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "accd4ea62f7bb7a82fe23066fb0957d48ef677f6eeb8215f372f52e48bb32426" +checksum = "711b9620af191e0cdc7468a8d14e709c3dcdb115b36f838e601583af800a370a" + +[[package]] +name = "uuid" +version = "1.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "79daa5ed5740825c40b389c5e50312b9c86df53fccd33f281df655642b43869d" +dependencies = [ + "getrandom", + "serde", +] [[package]] -name = "version_check" -version = "0.9.4" +name = "vcpkg" +version = "0.2.15" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "49874b5167b65d7193b8aba1567f5c7d93d001cafc34600cee003eda787e483f" +checksum = "accd4ea62f7bb7a82fe23066fb0957d48ef677f6eeb8215f372f52e48bb32426" [[package]] name = "want" @@ -1437,15 +1935,15 @@ dependencies = [ [[package]] name = "wasi" -version = "0.9.0+wasi-snapshot-preview1" +version = "0.10.0+wasi-snapshot-preview1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cccddf32554fecc6acb585f82a32a72e28b48f8c4c1883ddfeeeaa96f7d8e519" +checksum = "1a143597ca7c7793eff794def352d41792a93c481eb1042423ff7ff72ba2c31f" [[package]] name = "wasi" -version = "0.10.0+wasi-snapshot-preview1" +version = "0.11.0+wasi-snapshot-preview1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1a143597ca7c7793eff794def352d41792a93c481eb1042423ff7ff72ba2c31f" +checksum = "9c8d87e72b64a3b4db28d11ce29237c246188f4f51057d65a7eab63b7987e423" [[package]] name = "wasm-bindgen" @@ -1453,9 +1951,7 @@ version = "0.2.87" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "7706a72ab36d8cb1f80ffbf0e071533974a60d0a308d01a5d0375bf60499a342" dependencies = [ - "cfg-if 1.0.0", - "serde", - "serde_json", + "cfg-if", "wasm-bindgen-macro", ] @@ -1470,7 +1966,7 @@ dependencies = [ "once_cell", "proc-macro2", "quote", - "syn 2.0.29", + "syn 2.0.31", "wasm-bindgen-shared", ] @@ -1480,7 +1976,7 @@ version = "0.4.37" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "c02dbc21516f9f1f04f187958890d7e6026df8d16540b7ad9492bc34a67cea03" dependencies = [ - "cfg-if 1.0.0", + "cfg-if", "js-sys", "wasm-bindgen", "web-sys", @@ -1504,7 +2000,7 @@ checksum = "54681b18a46765f095758388f2d0cf16eb8d4169b639ab575a8f5693af210c7b" dependencies = [ "proc-macro2", "quote", - "syn 2.0.29", + "syn 2.0.31", "wasm-bindgen-backend", "wasm-bindgen-shared", ] @@ -1525,12 +2021,6 @@ dependencies = [ "wasm-bindgen", ] -[[package]] -name = "winapi" -version = "0.2.8" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "167dc9d6949a9b857f3451275e911c3f44255842c1f7a76f33c55103a909087a" - [[package]] name = "winapi" version = "0.3.9" @@ -1541,12 +2031,6 @@ dependencies = [ "winapi-x86_64-pc-windows-gnu", ] -[[package]] -name = "winapi-build" -version = "0.1.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2d315eee3b34aca4797b2da6b13ed88266e6d612562a0c46390af8299fc699bc" - [[package]] name = "winapi-i686-pc-windows-gnu" version = "0.4.0" @@ -1559,7 +2043,7 @@ version = "0.1.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "70ec6ce85bb158151cae5e5c87f95a8e97d2c0c4b001223f33a334e3ce5de178" dependencies = [ - "winapi 0.3.9", + "winapi", ] [[package]] @@ -1645,19 +2129,10 @@ checksum = "ed94fce61571a4006852b7389a063ab983c02eb1bb37b47f8272ce92d06d9538" [[package]] name = "winreg" -version = "0.7.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0120db82e8a1e0b9fb3345a539c478767c0048d842860994d96113d5b667bd69" -dependencies = [ - "winapi 0.3.9", -] - -[[package]] -name = "ws2_32-sys" -version = "0.2.1" +version = "0.50.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d59cefebd0c892fa2dd6de581e937301d8552cb44489cdff035c6187cb63fa5e" +checksum = "524e57b2c537c0f9b1e69f1965311ec12182b4122e45035b1508cd24d2adadb1" dependencies = [ - "winapi 0.2.8", - "winapi-build", + "cfg-if", + "windows-sys", ] diff --git a/Cargo.toml b/Cargo.toml index 282e331..c8faf90 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,13 +1,24 @@ [package] name = "cfdyndns" -version = "0.0.3" -authors = ["Cole Mickens "] -edition = "2018" +version = "0.1.1" +authors = ["Cole Mickens ", "Tim DeHerrera "] +edition = "2021" [dependencies] log = "0.4.8" pretty_env_logger = "0.4.0" -reqwest = { version = "0.10.4", features = ["blocking", "json"] } -serde = "1.0.104" serde_json = "1.0.48" -trust-dns-client = "0.19.3" +public-ip = "^0.2" +tokio = { version = "^1", features = ["rt-multi-thread", "macros"] } +cloudflare = "^0.10" +anyhow = "^1" +clap-verbosity-flag = "^2.0" +addr = "^0.15" + +[dependencies.clap] +version = "^4.2" +features = ["wrap_help", "derive", "env"] + +[patch.crates-io] +cloudflare = { git = "https://github.com/jcgruenhage/cloudflare-rs.git", branch = "make-owner-fields-optional" } +public-ip = { git = "https://github.com/jcgruenhage/rust-public-ip.git", branch = "cloudflare-provider" } \ No newline at end of file diff --git a/README.md b/README.md index 2d4f097..44484f9 100644 --- a/README.md +++ b/README.md @@ -6,30 +6,30 @@ Reimplementation of [cloudflare-dyndns](https://github.com/colemickens/cloudflar ## status known issues -* this is barely in maintenance mode, it seems to have been broken at times without many folks noticing, myself included * paging is not implemented -* some basic CI should be added, since I haven't officially abandoned this (yet) -* I'm wary of Cloudflare these days, YMMV +* some basic CI should be added ## building -* use cargo +`cargo build` ## usage -* simple test CLI usage - ```shell -[cole@zeph:~/code/cfdyndns]$ env | grep CLOUDFLARE - -[cole@zeph:~/code/cfdyndns]$ export CLOUDFLARE_RECORDS=test-cfdyndns.mickens.us - -[cole@zeph:~/code/cfdyndns]$ export CLOUDFLARE_APITOKEN="m1D9WwLDE6lz2hYpU_5MtkpzBpFvEYS3ZuOGB2Va" - -[cole@zeph:~/code/cfdyndns]$ cargo run - Finished dev [unoptimized + debuginfo] target(s) in 0.06s - Running `target/debug/cfdyndns` -test-cfdyndns.mickens.us (1.2.3.4 -> 72.209.157.122)... +Usage: cfdyndns [OPTIONS] + +Options: + -r, --records Comma separated DNS records to update with the host's public IP [env: + CLOUDFLARE_RECORDS=panzy.nrd.sh,panzy.nrd.sh,nrd.xp] + -t, --token recommended: The CloudFlare API token to authenticate with deprecated: The CloudFlare + API key to authenticate with, also requires email [env: CLOUDFLARE_APITOKEN] + -k, --key deprecated: The CloudFlare email to authenticate with, also requires API key [env: + CLOUDFLARE_APIKEY] + -e, --email [env: CLOUDFLARE_EMAIL=] + -v, --verbose... More output per occurrence + -q, --quiet... Less output per occurrence + -h, --help Print help + -V, --version Print version ``` ### installing as systemd service @@ -43,36 +43,3 @@ test-cfdyndns.mickens.us (1.2.3.4 -> 72.209.157.122)... ### uninstalling systemd service 1. `make uninstall-systemd` - -### example systemd journalctl log - -``` -Sep 20 15:36:40 chimera systemd[1]: Started Cloudflare-dyndns. -Sep 20 15:36:43 chimera cloudflare-dyndns[22760]: *.mickens.tv (74.125.186.11 -> 66.235.2.123)... done -Sep 20 15:36:44 chimera cloudflare-dyndns[22760]: mickens.tv (74.125.186.11 -> 66.235.2.123)... done -Sep 20 15:36:44 chimera cloudflare-dyndns[22760]: *.mickens.xxx (74.125.186.11 -> 66.235.2.123)... done -Sep 20 15:36:46 chimera cloudflare-dyndns[22760]: mickens.xxx (74.125.186.11 -> 66.235.2.123)... done -Sep 20 15:36:46 chimera cloudflare-dyndns[22760]: cole.mickens.us (74.125.186.11 -> 66.235.2.123)... done -Sep 20 15:36:46 chimera cloudflare-dyndns[22760]: *.mickens.us (74.125.186.11 -> 66.235.2.123)... done -Sep 20 15:36:47 chimera cloudflare-dyndns[22760]: mickens.us (74.125.186.11 -> 66.235.2.123)... done -Sep 20 15:36:47 chimera cloudflare-dyndns[22760]: *.mickens.me (74.125.186.11 -> 66.235.2.123)... done -Sep 20 15:36:48 chimera cloudflare-dyndns[22760]: mickens.me (74.125.186.11 -> 66.235.2.123)... done -Sep 20 15:36:48 chimera cloudflare-dyndns[22760]: recessionomics.us (74.125.186.11 -> 66.235.2.123)... done -Sep 20 15:36:49 chimera cloudflare-dyndns[22760]: www.recessionomics.us (74.125.186.11 -> 66.235.2.123)... done -Sep 20 15:36:49 chimera cloudflare-dyndns[22760]: *.mickens.io (74.125.186.11 -> 66.235.2.123)... done -Sep 20 15:36:49 chimera cloudflare-dyndns[22760]: mickens.io (74.125.186.11 -> 66.235.2.123)... done -Sep 20 15:41:45 chimera systemd[1]: Started Cloudflare-dyndns. -Sep 20 15:41:45 chimera cloudflare-dyndns[23288]: recessionomics.us skipped, up to date -Sep 20 15:41:45 chimera cloudflare-dyndns[23288]: www.recessionomics.us skipped, up to date -Sep 20 15:41:45 chimera cloudflare-dyndns[23288]: *.mickens.tv skipped, up to date -Sep 20 15:41:45 chimera cloudflare-dyndns[23288]: mickens.tv skipped, up to date -Sep 20 15:41:45 chimera cloudflare-dyndns[23288]: *.mickens.io skipped, up to date -Sep 20 15:41:45 chimera cloudflare-dyndns[23288]: mickens.io skipped, up to date -Sep 20 15:41:46 chimera cloudflare-dyndns[23288]: cole.mickens.us skipped, up to date -Sep 20 15:41:46 chimera cloudflare-dyndns[23288]: *.mickens.us skipped, up to date -Sep 20 15:41:46 chimera cloudflare-dyndns[23288]: mickens.us skipped, up to date -Sep 20 15:41:46 chimera cloudflare-dyndns[23288]: *.mickens.xxx skipped, up to date -Sep 20 15:41:46 chimera cloudflare-dyndns[23288]: mickens.xxx skipped, up to date -Sep 20 15:41:46 chimera cloudflare-dyndns[23288]: *.mickens.me skipped, up to date -Sep 20 15:41:46 chimera cloudflare-dyndns[23288]: mickens.me skipped, up to date -``` diff --git a/flake.lock b/flake.lock new file mode 100644 index 0000000..6aec6da --- /dev/null +++ b/flake.lock @@ -0,0 +1,426 @@ +{ + "nodes": { + "blank": { + "locked": { + "lastModified": 1625557891, + "narHash": "sha256-O8/MWsPBGhhyPoPLHZAuoZiiHo9q6FLlEeIDEXuj6T4=", + "owner": "divnix", + "repo": "blank", + "rev": "5a5d2684073d9f563072ed07c871d577a6c614a8", + "type": "github" + }, + "original": { + "owner": "divnix", + "repo": "blank", + "type": "github" + } + }, + "call-flake": { + "locked": { + "lastModified": 1693099034, + "narHash": "sha256-bmhE1TmrJG4ba93l9WQTLuYM53kwGQAjYHRvHOeuxWU=", + "owner": "divnix", + "repo": "call-flake", + "rev": "24473e390c03457fa6c33e5447e9a74999ff4d4f", + "type": "github" + }, + "original": { + "owner": "divnix", + "repo": "call-flake", + "type": "github" + } + }, + "crane": { + "inputs": { + "flake-compat": [], + "flake-utils": "flake-utils", + "nixpkgs": [ + "nixpkgs" + ], + "rust-overlay": [] + }, + "locked": { + "lastModified": 1693163878, + "narHash": "sha256-HXuyMUVaRSoIA602jfFuYGXt6AMZ+WUxuvLq8iJmYTA=", + "owner": "ipetkov", + "repo": "crane", + "rev": "43db881168bc65b568d36ceb614a0fc8b276191b", + "type": "github" + }, + "original": { + "owner": "ipetkov", + "repo": "crane", + "type": "github" + } + }, + "devshell": { + "inputs": { + "nixpkgs": "nixpkgs_2", + "systems": "systems_2" + }, + "locked": { + "lastModified": 1692793255, + "narHash": "sha256-yVyj0AE280JkccDHuG1XO9oGxN6bW8ksr/xttXcXzK0=", + "owner": "numtide", + "repo": "devshell", + "rev": "2aa26972b951bc05c3632d4e5ae683cb6771a7c6", + "type": "github" + }, + "original": { + "owner": "numtide", + "repo": "devshell", + "type": "github" + } + }, + "dmerge": { + "inputs": { + "haumea": [ + "std", + "haumea" + ], + "nixlib": [ + "std", + "haumea", + "nixpkgs" + ], + "yants": [ + "std", + "yants" + ] + }, + "locked": { + "lastModified": 1686862774, + "narHash": "sha256-ojGtRQ9pIOUrxsQEuEPerUkqIJEuod9hIflfNkY+9CE=", + "owner": "divnix", + "repo": "dmerge", + "rev": "9f7f7a8349d33d7bd02e0f2b484b1f076e503a96", + "type": "github" + }, + "original": { + "owner": "divnix", + "ref": "0.2.1", + "repo": "dmerge", + "type": "github" + } + }, + "fenix": { + "inputs": { + "nixpkgs": "nixpkgs", + "rust-analyzer-src": "rust-analyzer-src" + }, + "locked": { + "lastModified": 1693376454, + "narHash": "sha256-DPwnYASe7xGW6mNANEhKHOSFL2ySwIcDNW+SsYYzwmg=", + "owner": "nix-community", + "repo": "fenix", + "rev": "a08c2909476e953bd23a73f2f3ef5bf07bf1ae44", + "type": "github" + }, + "original": { + "owner": "nix-community", + "repo": "fenix", + "type": "github" + } + }, + "flake-utils": { + "inputs": { + "systems": "systems" + }, + "locked": { + "lastModified": 1689068808, + "narHash": "sha256-6ixXo3wt24N/melDWjq70UuHQLxGV8jZvooRanIHXw0=", + "owner": "numtide", + "repo": "flake-utils", + "rev": "919d646de7be200f3bf08cb76ae1f09402b6f9b4", + "type": "github" + }, + "original": { + "owner": "numtide", + "repo": "flake-utils", + "type": "github" + } + }, + "haumea": { + "inputs": { + "nixpkgs": "nixpkgs_3" + }, + "locked": { + "lastModified": 1685133229, + "narHash": "sha256-FePm/Gi9PBSNwiDFq3N+DWdfxFq0UKsVVTJS3cQPn94=", + "owner": "nix-community", + "repo": "haumea", + "rev": "34dd58385092a23018748b50f9b23de6266dffc2", + "type": "github" + }, + "original": { + "owner": "nix-community", + "ref": "v0.2.2", + "repo": "haumea", + "type": "github" + } + }, + "incl": { + "inputs": { + "nixlib": [ + "std", + "haumea", + "nixpkgs" + ] + }, + "locked": { + "lastModified": 1669263024, + "narHash": "sha256-E/+23NKtxAqYG/0ydYgxlgarKnxmDbg6rCMWnOBqn9Q=", + "owner": "divnix", + "repo": "incl", + "rev": "ce7bebaee048e4cd7ebdb4cee7885e00c4e2abca", + "type": "github" + }, + "original": { + "owner": "divnix", + "repo": "incl", + "type": "github" + } + }, + "nixpkgs": { + "locked": { + "lastModified": 1693250523, + "narHash": "sha256-y3up5gXMTbnCsXrNEB5j+7TVantDLUYyQLu/ueiXuyg=", + "owner": "nixos", + "repo": "nixpkgs", + "rev": "3efb0f6f404ec8dae31bdb1a9b17705ce0d6986e", + "type": "github" + }, + "original": { + "owner": "nixos", + "ref": "nixos-unstable", + "repo": "nixpkgs", + "type": "github" + } + }, + "nixpkgs_2": { + "locked": { + "lastModified": 1693355128, + "narHash": "sha256-+ZoAny3ZxLcfMaUoLVgL9Ywb/57wP+EtsdNGuXUJrwg=", + "owner": "NixOS", + "repo": "nixpkgs", + "rev": "a63a64b593dcf2fe05f7c5d666eb395950f36bc9", + "type": "github" + }, + "original": { + "owner": "NixOS", + "ref": "nixpkgs-unstable", + "repo": "nixpkgs", + "type": "github" + } + }, + "nixpkgs_3": { + "locked": { + "lastModified": 1681001314, + "narHash": "sha256-5sDnCLdrKZqxLPK4KA8+f4A3YKO/u6ElpMILvX0g72c=", + "owner": "nix-community", + "repo": "nixpkgs.lib", + "rev": "367c0e1086a4eb4502b24d872cea2c7acdd557f4", + "type": "github" + }, + "original": { + "owner": "nix-community", + "repo": "nixpkgs.lib", + "type": "github" + } + }, + "nosys": { + "locked": { + "lastModified": 1668010795, + "narHash": "sha256-JBDVBnos8g0toU7EhIIqQ1If5m/nyBqtHhL3sicdPwI=", + "owner": "divnix", + "repo": "nosys", + "rev": "feade0141487801c71ff55623b421ed535dbdefa", + "type": "github" + }, + "original": { + "owner": "divnix", + "repo": "nosys", + "type": "github" + } + }, + "paisano": { + "inputs": { + "call-flake": "call-flake", + "nixpkgs": [ + "std", + "nixpkgs" + ], + "nosys": "nosys", + "yants": [ + "std", + "yants" + ] + }, + "locked": { + "lastModified": 1691492062, + "narHash": "sha256-9izEr9crBjoBk4ecuTyFVYwjbXo1VjClRN1eaGITeag=", + "owner": "paisano-nix", + "repo": "core", + "rev": "218a7f50451cbc5c981fc8dfe6f962044041f9aa", + "type": "github" + }, + "original": { + "owner": "paisano-nix", + "repo": "core", + "type": "github" + } + }, + "paisano-tui": { + "flake": false, + "locked": { + "lastModified": 1681847764, + "narHash": "sha256-mdd7PJW1BZvxy0cIKsPfAO+ohVl/V7heE5ZTAHzTdv8=", + "owner": "paisano-nix", + "repo": "tui", + "rev": "3096bad91cae73ab8ab3367d31f8a143d248a244", + "type": "github" + }, + "original": { + "owner": "paisano-nix", + "ref": "0.1.1", + "repo": "tui", + "type": "github" + } + }, + "root": { + "inputs": { + "crane": "crane", + "fenix": "fenix", + "nixpkgs": [ + "fenix", + "nixpkgs" + ], + "std": "std" + } + }, + "rust-analyzer-src": { + "flake": false, + "locked": { + "lastModified": 1693293380, + "narHash": "sha256-ZTkBsglLJ7wmD+MKR67G677jM2x7SA3LqmSdggEv9dg=", + "owner": "rust-lang", + "repo": "rust-analyzer", + "rev": "b06503b6ec98c9ed44698870cbf3302b8560b442", + "type": "github" + }, + "original": { + "owner": "rust-lang", + "ref": "nightly", + "repo": "rust-analyzer", + "type": "github" + } + }, + "std": { + "inputs": { + "arion": [ + "std", + "blank" + ], + "blank": "blank", + "devshell": "devshell", + "dmerge": "dmerge", + "haumea": "haumea", + "incl": "incl", + "makes": [ + "std", + "blank" + ], + "microvm": [ + "std", + "blank" + ], + "n2c": [ + "std", + "blank" + ], + "nixago": [ + "std", + "blank" + ], + "nixpkgs": [ + "nixpkgs" + ], + "paisano": "paisano", + "paisano-tui": "paisano-tui", + "terranix": [ + "std", + "blank" + ], + "yants": "yants" + }, + "locked": { + "lastModified": 1692106836, + "narHash": "sha256-VaNAHPYd/inL0+4O7j4Gx+JfyKHT5RGXWZ3JWU5DPdk=", + "owner": "divnix", + "repo": "std", + "rev": "b12b4df9fd35e803896ff08802a219ec0e8d55db", + "type": "github" + }, + "original": { + "owner": "divnix", + "ref": "v0.24.0-1", + "repo": "std", + "type": "github" + } + }, + "systems": { + "locked": { + "lastModified": 1681028828, + "narHash": "sha256-Vy1rq5AaRuLzOxct8nz4T6wlgyUR7zLU309k9mBC768=", + "owner": "nix-systems", + "repo": "default", + "rev": "da67096a3b9bf56a91d16901293e51ba5b49a27e", + "type": "github" + }, + "original": { + "owner": "nix-systems", + "repo": "default", + "type": "github" + } + }, + "systems_2": { + "locked": { + "lastModified": 1681028828, + "narHash": "sha256-Vy1rq5AaRuLzOxct8nz4T6wlgyUR7zLU309k9mBC768=", + "owner": "nix-systems", + "repo": "default", + "rev": "da67096a3b9bf56a91d16901293e51ba5b49a27e", + "type": "github" + }, + "original": { + "owner": "nix-systems", + "repo": "default", + "type": "github" + } + }, + "yants": { + "inputs": { + "nixpkgs": [ + "std", + "haumea", + "nixpkgs" + ] + }, + "locked": { + "lastModified": 1686863218, + "narHash": "sha256-kooxYm3/3ornWtVBNHM3Zh020gACUyFX2G0VQXnB+mk=", + "owner": "divnix", + "repo": "yants", + "rev": "8f0da0dba57149676aa4817ec0c880fbde7a648d", + "type": "github" + }, + "original": { + "owner": "divnix", + "repo": "yants", + "type": "github" + } + } + }, + "root": "root", + "version": 7 +} diff --git a/flake.nix b/flake.nix new file mode 100644 index 0000000..9664a30 --- /dev/null +++ b/flake.nix @@ -0,0 +1,45 @@ +{ + description = "A very basic flake for Rust development"; + + inputs.std.url = "github:divnix/std/v0.24.0-1"; + inputs.std.inputs.nixpkgs.follows = "nixpkgs"; + + inputs.fenix.url = "github:nix-community/fenix"; + inputs.crane.url = "github:ipetkov/crane"; + inputs.crane.inputs.nixpkgs.follows = "nixpkgs"; + inputs.crane.inputs.flake-compat.follows = ""; + inputs.crane.inputs.rust-overlay.follows = ""; + + inputs.std.inputs.devshell.url = "github:numtide/devshell"; + + inputs.nixpkgs.follows = "fenix/nixpkgs"; + + outputs = inputs @ { + self, + std, + ... + }: + std.growOn { + inherit inputs; + systems = ["x86_64-linux"]; + cellsFrom = ./nix; + cellBlocks = with std.blockTypes; [ + (installables "packages") + # Contribution Environment + (devshells "shells") + (pkgs "rust") + ]; + } { + devShells = std.harvest self ["repo" "shells"]; + packages = std.harvest self ["bin" "packages"]; + }; + + nixConfig = { + extra-substituters = [ + "https://nix-community.cachix.org" + ]; + extra-trusted-public-keys = [ + "nix-community.cachix.org-1:mB9FSh9qf2dCimDSUo8Zy7bkq5CX+/rkCWyvRCYg3Fs=" + ]; + }; +} diff --git a/nix/bin/packages.nix b/nix/bin/packages.nix new file mode 100644 index 0000000..3bcc6f5 --- /dev/null +++ b/nix/bin/packages.nix @@ -0,0 +1,20 @@ +{ + inputs, + cell, +}: let + inherit (inputs) std self cells; + inherit (inputs.nixpkgs) pkgs; + + crane = inputs.crane.lib.overrideToolchain cells.repo.rust.toolchain; +in { + # sane default for a binary package + default = crane.buildPackage { + src = std.incl self [ + "${self}/Cargo.lock" + "${self}/Cargo.toml" + "${self}/src" + ]; + + buildInputs = [pkgs.openssl pkgs.pkgconfig]; + }; +} diff --git a/nix/repo/rust.nix b/nix/repo/rust.nix new file mode 100644 index 0000000..91fa1e1 --- /dev/null +++ b/nix/repo/rust.nix @@ -0,0 +1,23 @@ +# export fenix toolchain as its own package set +{ + inputs, + cell, +}: let + inherit (inputs) fenix; + + # you may change "default" to any of "[minimal|default|complete|latest]" for variants + # see upstream fenix documentation for details + rustPkgs = builtins.removeAttrs fenix.packages.complete ["withComponents" "name" "type"]; +in + # add rust-analyzer from nightly, if not present + if rustPkgs ? rust-analyzer + then rustPkgs + else + rustPkgs + // { + inherit (fenix.packages) rust-analyzer; + toolchain = fenix.packages.combine [ + (builtins.attrValues rustPkgs) + fenix.packages.rust-analyzer + ]; + } diff --git a/nix/repo/shells.nix b/nix/repo/shells.nix new file mode 100644 index 0000000..8c11358 --- /dev/null +++ b/nix/repo/shells.nix @@ -0,0 +1,92 @@ +{ + inputs, + cell, +}: let + inherit (inputs.std) std lib; + inherit (inputs) nixpkgs; + inherit (inputs.cells) bin; + + l = nixpkgs.lib // builtins; + + dev = lib.dev.mkShell { + packages = [ + nixpkgs.pkg-config + ]; + language.rust = { + packageSet = cell.rust; + enableDefaultToolchain = true; + tools = ["toolchain"]; # fenix collates them all in a convenience derivation + }; + + devshell.startup.link-cargo-home = { + deps = []; + text = '' + # ensure CARGO_HOME is populated + mkdir -p $PRJ_DATA_DIR/cargo + ln -snf -t $PRJ_DATA_DIR/cargo $(ls -d ${cell.rust.toolchain}/*) + ''; + }; + + env = [ + { + # ensures subcommands are picked up from the right place + # but also needs to be writable; see link-cargo-home above + name = "CARGO_HOME"; + eval = "$PRJ_DATA_DIR/cargo"; + } + { + # ensure we know where rustup_home will be + name = "RUSTUP_HOME"; + eval = "$PRJ_DATA_DIR/rustup"; + } + { + name = "RUST_SRC_PATH"; + # accessing via toolchain doesn't fail if it's not there + # and rust-analyzer is graceful if it's not set correctly: + # https://github.com/rust-lang/rust-analyzer/blob/7f1234492e3164f9688027278df7e915bc1d919c/crates/project-model/src/sysroot.rs#L196-L211 + value = "${cell.rust.toolchain}/lib/rustlib/src/rust/library"; + } + { + name = "PKG_CONFIG_PATH"; + value = l.makeSearchPath "lib/pkgconfig" bin.packages.default.buildInputs; + } + ]; + imports = [ + "${inputs.std.inputs.devshell}/extra/language/rust.nix" + ]; + + commands = let + rustCmds = + l.map (name: { + inherit name; + package = cell.rust.toolchain; # has all bins + category = "rust dev"; + # fenix doesn't include package descriptions, so pull those out of their equivalents in nixpkgs + help = nixpkgs.${name}.meta.description; + }) [ + "rustc" + "cargo" + "rustfmt" + "rust-analyzer" + ]; + in + [ + { + package = nixpkgs.treefmt; + category = "repo tools"; + } + { + package = nixpkgs.alejandra; + category = "repo tools"; + } + { + package = std.cli.default; + category = "std"; + } + ] + ++ rustCmds; + }; +in { + inherit dev; + default = dev; +} diff --git a/rustfmt.toml b/rustfmt.toml new file mode 100644 index 0000000..16a16a6 --- /dev/null +++ b/rustfmt.toml @@ -0,0 +1,77 @@ +max_width = 80 +hard_tabs = true +tab_spaces = 4 +newline_style = "Unix" +use_small_heuristics = "Default" +fn_call_width = 60 +attr_fn_like_width = 70 +struct_lit_width = 18 +struct_variant_width = 35 +array_width = 60 +chain_width = 60 +single_line_if_else_max_width = 50 +reorder_imports = true +reorder_modules = true +remove_nested_parens = true +short_array_element_width_threshold = 10 +match_arm_leading_pipes = "Never" +fn_params_layout = "Vertical" +match_block_trailing_comma = false +edition = "2021" +merge_derives = true +use_try_shorthand = true +use_field_init_shorthand = true +force_explicit_abi = true +disable_all_formatting = false +# --- unstable settings --- +# indent_style = "Block" +# wrap_comments = false +# format_code_in_doc_comments = false +# doc_comment_code_block_width = 100 +# normalize_comments = false +# normalize_doc_attributes = false +# format_strings = false +# format_macro_matchers = false +# format_macro_bodies = true +# hex_literal_case = "Preserve" +# empty_item_single_line = true +# struct_lit_single_line = true +# fn_single_line = false +# comment_width = 80 +# where_single_line = false +# imports_indent = "Block" +# imports_layout = "Mixed" +# imports_granularity = "Preserve" +# group_imports = "Preserve" +# reorder_impl_items = false +# type_punctuation_density = "Wide" +# space_before_colon = false +# space_after_colon = true +# spaces_around_ranges = false +# binop_separator = "Front" +# combine_control_expr = true +# overflow_delimited_expr = false +# struct_field_align_threshold = 0 +# enum_discrim_align_threshold = 0 +# match_arm_blocks = true +# force_multiline_blocks = false +# brace_style = "SameLineWhere" +# control_brace_style = "AlwaysSameLine" +# trailing_semicolon = true +# trailing_comma = "Vertical" +# version = "One" +# blank_lines_upper_bound = 1 +# blank_lines_lower_bound = 0 +# inline_attribute_width = 0 +# format_generated_files = true +# condense_wildcard_suffixes = false +# color = "Auto" +# required_version = "1.5.1" +# unstable_features = false +# skip_children = false +# hide_parse_errors = false +# error_on_line_overflow = false +# error_on_unformatted = false +# ignore = [] +# emit_mode = "Files" +# make_backup = false diff --git a/src/api.rs b/src/api.rs new file mode 100644 index 0000000..99c5cce --- /dev/null +++ b/src/api.rs @@ -0,0 +1,50 @@ +use clap::Parser; +use clap_verbosity_flag::{InfoLevel, Verbosity}; + +#[derive(Debug, Parser)] +#[clap(author, version, about)] +pub struct Cli { + /// Comma separated DNS records to update with the host's public IP + #[clap( + long, + short, + env = "CLOUDFLARE_RECORDS", + value_name = "RECORDS", + value_delimiter(',') + )] + pub records: Vec, + /// recommended: The CloudFlare API token to authenticate with + #[clap( + long, + short, + env = "CLOUDFLARE_APITOKEN", + hide_env_values = true, + value_name = "TOKEN", + required_unless_present_all(["key", "email"]) + )] + /// deprecated: The CloudFlare API key to authenticate with, also requires email + pub token: Option, + #[clap( + long, + short, + env = "CLOUDFLARE_APIKEY", + hide_env_values = true, + value_name = "KEY", + required_unless_present("token"), + requires("email") + )] + /// deprecated: The CloudFlare email to authenticate with, also requires API key + pub key: Option, + #[clap( + long, + short, + env = "CLOUDFLARE_EMAIL", + value_name = "EMAIL", + required_unless_present("token"), + requires("key") + )] + pub email: Option, + + #[clap(flatten)] + pub verbose: Verbosity, +} diff --git a/src/clone.rs b/src/clone.rs new file mode 100644 index 0000000..bd8555b --- /dev/null +++ b/src/clone.rs @@ -0,0 +1,25 @@ +use cloudflare::endpoints::dns::{DnsRecord, Meta}; +pub trait Clone_ { + fn clone(&self) -> Self; +} + +impl Clone_ for DnsRecord { + fn clone(&self) -> Self { + Self { + name: self.name.to_owned(), + meta: Meta { + auto_added: self.meta.auto_added, + }, + locked: self.locked, + ttl: self.ttl, + zone_id: self.zone_id.to_owned(), + modified_on: self.modified_on, + created_on: self.created_on, + proxiable: self.proxiable, + proxied: self.proxied, + content: self.content.clone(), + id: self.id.to_owned(), + zone_name: self.zone_name.to_owned(), + } + } +} diff --git a/src/fns.rs b/src/fns.rs new file mode 100644 index 0000000..81ff477 --- /dev/null +++ b/src/fns.rs @@ -0,0 +1,181 @@ +use cloudflare::{ + endpoints::{ + dns::{ + DnsContent, DnsRecord, ListDnsRecords, ListDnsRecordsParams, + UpdateDnsRecord, UpdateDnsRecordParams, + }, + zone::{ListZones, ListZonesParams}, + }, + framework::{ + async_api::{ApiClient, Client}, + auth::Credentials, + Environment, HttpApiClientConfig, + }, +}; + +use public_ip::{http, Version}; + +use std::net::IpAddr; + +use anyhow::Result; + +use crate::api::Cli; +use std::sync::Arc; + +use crate::clone::Clone_; + +use std::collections::HashSet; + +pub async fn get_ips() -> Result<(Option, Option)> { + let (ipv4, ipv6) = tokio::join!( + public_ip::addr_with(http::ALL, Version::V4), + public_ip::addr_with(public_ip::ALL, Version::V6) + ); + + if (None, None) == (ipv6, ipv4) { + anyhow::bail!("Could not determine your current public IP address.") + } + + if let Some(ip) = ipv4 { + log::info!("{}", ip); + } + if let Some(ip) = ipv6 { + log::info!("{}", ip); + }; + Ok((ipv4, ipv6)) +} + +pub fn get_client(cli: &Cli) -> Result { + let credentials: Credentials = if let Some(token) = cli.token.clone() { + Credentials::UserAuthToken { token } + } else if let (Some(key), Some(email)) = + (cli.key.clone(), cli.email.clone()) + { + log::warn!("API Key & Email combo is deprecated. Please switch to using an API token"); + Credentials::UserAuthKey { email, key } + } else { + unreachable!() + }; + + Client::new( + credentials, + HttpApiClientConfig::default(), + Environment::Production, + ) +} + +pub async fn get_records( + cli: &Cli, + client: Arc, +) -> Result, Option, Option)>> +{ + let params = ListZones { + params: ListZonesParams::default(), + }; + let zones = client.request(¶ms); + // HACK: make a second call since dns::Zone does not implement Clone upstream + let zones2 = client.request(¶ms).await?.result; + + let mut handles = Vec::with_capacity(zones2.len()); + let mut records = Vec::with_capacity(zones2.len() * 10); + + for zone in zones.await?.result { + let client = client.clone(); + handles.push(tokio::spawn(async move { + client + .request(&ListDnsRecords { + zone_identifier: &zone.id, + params: ListDnsRecordsParams::default(), + }) + .await + })); + } + + for handle in handles { + records.extend(handle.await??.result) + } + + let mut start: HashSet = cli.records.clone().into_iter().collect(); + let mut invalid = vec![]; + start.retain(|name| { + let mut res = false; + if let Ok(n) = addr::parse_domain_name(name) { + res = n.has_known_suffix(); + } + if !res { + invalid.push(name.clone()); + } + res + }); + + for name in invalid { + log::warn!("{} is an invalid domain name; skipping...", name); + } + + let locals = start + .iter() + .map(|r| { + ( + r.to_owned(), + zones2 + .iter() + .find(|z| r.contains(&z.name)) + .map(|z| z.id.to_owned()), + records + .iter() + .find(|rec| { + if let DnsContent::A { content: _ } = rec.content { + return rec.name == *r; + } + false + }) + .map(|r| r.clone()), + records + .iter() + .find(|rec| { + if let DnsContent::AAAA { content: _ } = rec.content { + return rec.name == *r; + } + false + }) + .map(|r| r.clone()), + ) + }) + .collect(); + Ok(locals) +} + +pub async fn update_record( + record: DnsRecord, + record_ip: IpAddr, + public_ip: IpAddr, + client: Arc, +) -> Result<()> { + if public_ip == record_ip { + let kind = match record_ip { + IpAddr::V4(_) => "A", + IpAddr::V6(_) => "AAAA", + }; + log::info!("{} record {} skipped, up to date", kind, record.name); + return Ok(()); + } + + log::info!("{} ({} → {})\n", record.name, record_ip, public_ip); + + client + .request(&UpdateDnsRecord { + zone_identifier: &record.zone_id, + identifier: &record.id, + params: UpdateDnsRecordParams { + name: &record.name, + ttl: record.ttl.into(), + proxied: record.proxied.into(), + content: match public_ip { + IpAddr::V4(ip) => DnsContent::A { content: ip }, + IpAddr::V6(ip) => DnsContent::AAAA { content: ip }, + }, + }, + }) + .await?; + Ok(()) +} diff --git a/src/main.rs b/src/main.rs index c38c6b4..ee64e9a 100644 --- a/src/main.rs +++ b/src/main.rs @@ -1,178 +1,156 @@ -extern crate log; -extern crate pretty_env_logger; -extern crate reqwest; -extern crate serde; -extern crate serde_json; -extern crate trust_dns_client; - -use log::info; - -use serde_json::value::*; - -use std::env; -use std::io; -use std::io::prelude::*; - -use trust_dns_client::client::{Client as _Client, SyncClient}; -use trust_dns_client::rr::dns_class::DNSClass; -use trust_dns_client::rr::domain; -use trust_dns_client::rr::record_data::RData; -use trust_dns_client::rr::record_type::RecordType; -use trust_dns_client::udp::UdpClientConnection; - -const NS1_GOOGLE_COM_IP_ADDR: &'static str = "216.239.32.10:53"; - -fn env_var(n: &str) -> String { - let err = "Environment Variables CLOUDFLARE_RECORDS and either CLOUDFLARE_APITOKEN or CLOUDFLARE_EMAIL and CLOUDFLARE_APIKEY must be set!"; - env::var(n).ok().expect(&err) -} - -// overloaded function. no body is treated as a get, body is treated as a put -fn cloudflare_api( - client: &reqwest::blocking::Client, - url: &str, - body: Option, -) -> Result { - - let request = match body { - Some(body) => client.put(url).body(body), - None => client.get(url), - }; - - let authorized_request = match env::var("CLOUDFLARE_APITOKEN") { - Ok(val) => { - let mut bearer = "Bearer ".to_owned(); - bearer.push_str(&val); - request.header("Authorization", bearer.to_owned()) - } - Err(_e) => { - let cloudflare_apikey = env_var("CLOUDFLARE_APIKEY"); - let cloudflare_email = env_var("CLOUDFLARE_EMAIL"); - request - .header("X-Auth-Key", cloudflare_apikey.to_owned()) - .header("X-Auth-Email", cloudflare_email.to_owned()) - } - }; - - let response_json: Value = authorized_request - .send() - .unwrap() - .json() - .unwrap(); - - let success = response_json - .as_object() - .unwrap() - .get("success") - .unwrap() - .as_bool() - .unwrap(); - if !success { - return Err(format!("Request not successful: {}", response_json)); - } - - Ok(response_json) -} - -fn get_current_ip() -> Result { - let gdns_addr = (NS1_GOOGLE_COM_IP_ADDR) - .parse() - .expect("Couldn't get Google DNS Socket Addr"); - let conn = UdpClientConnection::new(gdns_addr).expect("Couldn't open DNS UDP Connection"); - let client = SyncClient::new(conn); - - let name = domain::Name::new(); - let name = name - .append_label("o-o") - .unwrap() - .append_label("myaddr") - .unwrap() - .append_label("l") - .unwrap() - .append_label("google") - .unwrap() - .append_label("com") - .unwrap(); - let response = client.query(&name, DNSClass::IN, RecordType::TXT).unwrap(); - - let record = &response.answers()[0]; - match record.rdata() { - &RData::TXT(ref txt) => { - let val = txt.txt_data(); - return Ok(String::from_utf8(val[0].to_vec()).unwrap()); - } - _ => return Err(()), - } -} - -fn main() { - pretty_env_logger::init(); - - let current_ip = get_current_ip() - .ok() - .expect("Was unable to determine current IP address."); - info!("{}", current_ip); - let client = reqwest::blocking::Client::new(); - - let cloudflare_records_env = env_var("CLOUDFLARE_RECORDS"); - let cloudflare_records: Vec<&str> = cloudflare_records_env.split(|c: char| c == ',').collect(); - - let zones_url = "https://api.cloudflare.com/client/v4/zones"; - let zones_json = cloudflare_api(&client, zones_url, None).unwrap(); - - let zone_ids = zones_json - .as_object() - .unwrap() - .get("result") - .unwrap() - .as_array() - .unwrap() - .iter() - .map(|ref zone_node| zone_node.get("id").unwrap().as_str().unwrap()); - - for zone_id in zone_ids { - let records_url = format!( - "https://api.cloudflare.com/client/v4/zones/{}/dns_records", - zone_id - ); - let records_json = cloudflare_api(&client, &*records_url, None).unwrap(); - - let records = records_json - .as_object() - .unwrap() - .get("result") - .unwrap() - .as_array() - .unwrap() - .iter(); - - for record in records { - let record_id = record.get("id").unwrap().as_str().unwrap(); - let record_type = record.get("type").unwrap().as_str().unwrap(); - let record_name = record.get("name").unwrap().as_str().unwrap(); - let record_content = record.get("content").unwrap().as_str().unwrap(); - - if !cloudflare_records.contains(&record_name) || record_type != "A" { - continue; - } - - if record_content == current_ip { - info!("{} skipped, up to date", record_name); - continue; - } - - print!("{} ({} -> {})... ", record_name, record_content, current_ip); - io::stdout().flush().ok(); - - let record_url = format!( - "https://api.cloudflare.com/client/v4/zones/{}/dns_records/{}", - zone_id, record_id - ); - let record_update_body = format!( - r#"{{"name": "{}", "content": "{}", "type": "{}", "proxied": true}}"#, - record_name, current_ip, record_type - ); - cloudflare_api(&client, &*record_url, Some(record_update_body.to_string())).unwrap(); - } - } +mod api; +mod clone; +mod fns; + +use cloudflare::endpoints::dns::{ + CreateDnsRecord, CreateDnsRecordParams, DeleteDnsRecord, DnsContent, +}; + +use cloudflare::framework::async_api::ApiClient; +use std::net::IpAddr; + +use anyhow::Result; + +use api::Cli; +use clap::Parser; + +use std::sync::Arc; + +#[tokio::main] +async fn main() -> Result<()> { + let cli = Cli::parse(); + + pretty_env_logger::formatted_builder() + .filter_level(cli.verbose.log_level_filter()) + .init(); + + let (public_ipv4, public_ipv6) = fns::get_ips().await?; + let api_client = Arc::new(fns::get_client(&cli)?); + let records = fns::get_records(&cli, api_client.clone()).await?; + let mut handles = Vec::with_capacity(cli.records.len()); + + for (record, zone, dns_v4, dns_v6) in records { + if let Some(zone) = zone { + if let Some(ip) = public_ipv4 { + let client = api_client.clone(); + if let Some(dns) = dns_v4 { + match dns.content { + DnsContent::A { content: ipv4 } => { + handles.push(tokio::spawn(async move { + fns::update_record( + dns, + IpAddr::V4(ipv4), + ip, + client, + ) + .await + })); + } + _ => continue, + } + } else { + log::info!("{} → {}\n", record, ip); + let name = record.clone(); + let id = zone.clone(); + handles.push(tokio::spawn(async move { + client + .request(&CreateDnsRecord { + zone_identifier: &id, + params: CreateDnsRecordParams { + ttl: Some(1), + priority: None, + proxied: Some(false), + name: &name, + content: DnsContent::A { + content: match ip { + IpAddr::V4(ip) => ip, + _ => unreachable!(), + }, + }, + }, + }) + .await?; + Ok(()) + })); + } + } else if let Some(dns) = dns_v4 { + log::info!("deleting A record: {}\n", record); + let client = api_client.clone(); + let id = zone.clone(); + handles.push(tokio::spawn(async move { + client + .request(&DeleteDnsRecord { + zone_identifier: &id, + identifier: &dns.id, + }) + .await?; + Ok(()) + })) + } + if let Some(ip) = public_ipv6 { + let client = api_client.clone(); + if let Some(dns) = dns_v6 { + match dns.content { + DnsContent::AAAA { content: ipv6 } => { + handles.push(tokio::spawn(async move { + fns::update_record( + dns, + IpAddr::V6(ipv6), + ip, + client, + ) + .await + })); + } + _ => continue, + } + } else { + log::info!("{} → {}\n", record, ip); + handles.push(tokio::spawn(async move { + client + .request(&CreateDnsRecord { + zone_identifier: &zone, + params: CreateDnsRecordParams { + ttl: Some(1), + priority: None, + proxied: Some(false), + name: &record, + content: DnsContent::AAAA { + content: match ip { + IpAddr::V6(ip) => ip, + _ => unreachable!(), + }, + }, + }, + }) + .await?; + Ok(()) + })); + } + } else if let Some(dns) = dns_v6 { + log::info!("deleting AAAA record: {}\n", record); + let client = api_client.clone(); + handles.push(tokio::spawn(async move { + client + .request(&DeleteDnsRecord { + zone_identifier: &zone, + identifier: &dns.id, + }) + .await?; + Ok(()) + })) + } + } + } + + // await all results before handling errors + let mut results = vec![]; + for handle in handles { + results.push(handle.await) + } + for result in results { + result?? + } + + Ok(()) } diff --git a/treefmt.toml b/treefmt.toml new file mode 100644 index 0000000..3bfe4e2 --- /dev/null +++ b/treefmt.toml @@ -0,0 +1,21 @@ +# One CLI to format the code tree - https://github.com/numtide/treefmt +[formatter.nix] +command = "alejandra" +includes = ["*.nix"] + +[formatter.shell] +command = "shfmt" +options = [ + "-i", + "2", # indent 2 + "-s", # simplify the code + "-w", # write back to the file + +] +includes = ["*.sh"] +excludes = [] + +[formatter.rust] +command = "rustfmt" +includes = ["*.rs"] +excludes = []