Compare commits

...

3 commits

Author SHA1 Message Date
f61a91234b
chore(deps): lock file maintenance
Some checks failed
/ build (push) Successful in 1m5s
/ check (clippy) (push) Successful in 15s
/ check (module-ipv4-only-test) (push) Successful in 32s
/ check (module-ipv4-test) (push) Successful in 30s
/ check (module-ipv6-only-test) (push) Failing after 20s
/ check (module-ipv6-test) (push) Failing after 22s
/ check (module-nginx-test) (push) Failing after 20s
/ check (nextest) (push) Successful in 3s
/ check (treefmt) (push) Successful in 3s
/ report-size (push) Successful in 7s
2025-01-31 21:30:31 +01:00
bf8c16f565
fix(tests): add case for when query has empty string
Some checks failed
/ build (push) Successful in 1s
/ check (clippy) (push) Successful in 2s
/ check (module-ipv4-only-test) (push) Successful in 7s
/ check (module-ipv4-test) (push) Successful in 7s
/ check (module-ipv6-only-test) (push) Failing after 15s
/ check (module-ipv6-test) (push) Failing after 15s
/ check (module-nginx-test) (push) Failing after 15s
/ check (nextest) (push) Successful in 2s
/ check (treefmt) (push) Successful in 3s
/ report-size (push) Successful in 1s
This is produced by the FRITZ!Box DDNS client.
2025-01-31 21:17:51 +01:00
82012066e8
fix(webnsupdate): make IP none when query is empty
This happens when one of the IPs hasn't changed (but the other has) in
the FRITZ!Box DDNS client.
2025-01-31 21:17:50 +01:00
4 changed files with 27 additions and 9 deletions

4
Cargo.lock generated
View file

@ -185,9 +185,9 @@ checksum = "325918d6fe32f23b19878fe4b34794ae41fc19ddbe53b10571a4874d44ffd39b"
[[package]] [[package]]
name = "cc" name = "cc"
version = "1.2.10" version = "1.2.11"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "13208fcbb66eaeffe09b99fffbe1af420f00a7b35aa99ad683dfc1aa76145229" checksum = "e4730490333d58093109dc02c23174c3f4d490998c3fed3cc8e82d57afedb9cf"
dependencies = [ dependencies = [
"shlex", "shlex",
] ]

View file

@ -237,9 +237,9 @@
if IPV4 and IPV6: if IPV4 and IPV6:
update_records("127.0.0.1", domain="test", ipv4="1.2.3.4", ipv6="::1234") update_records("127.0.0.1", domain="test", ipv4="1.2.3.4", ipv6="::1234")
elif IPV4: elif IPV4:
update_records("127.0.0.1", ipv4="1.2.3.4") update_records("127.0.0.1", ipv4="1.2.3.4", ipv6="")
elif IPV6: elif IPV6:
update_records("[::1]", ipv6="::1234") update_records("[::1]", ipv4="", ipv6="::1234")
for domain in DYNAMIC_DOMAINS: for domain in DYNAMIC_DOMAINS:
if IPV4: if IPV4:

6
flake.lock generated
View file

@ -37,11 +37,11 @@
}, },
"nixpkgs": { "nixpkgs": {
"locked": { "locked": {
"lastModified": 1738021509, "lastModified": 1738142207,
"narHash": "sha256-JNUiceGsr7cVBUQxLBF1ILCe99E0qLxsVuet6GsZUuw=", "narHash": "sha256-NGqpVVxNAHwIicXpgaVqJEJWeyqzoQJ9oc8lnK9+WC4=",
"owner": "NixOS", "owner": "NixOS",
"repo": "nixpkgs", "repo": "nixpkgs",
"rev": "9db269672dbdbb519e0bd3ea24f01506c135e46f", "rev": "9d3ae807ebd2981d593cddd0080856873139aa40",
"type": "github" "type": "github"
}, },
"original": { "original": {

View file

@ -414,6 +414,24 @@ fn main() -> Result<()> {
.wrap_err("failed to run main loop") .wrap_err("failed to run main loop")
} }
/// Serde deserialization decorator to map empty Strings to None,
///
/// Adapted from: <https://github.com/tokio-rs/axum/blob/main/examples/query-params-with-empty-strings/src/main.rs>
fn empty_string_as_none<'de, D, T>(de: D) -> Result<Option<T>, D::Error>
where
D: serde::Deserializer<'de>,
T: std::str::FromStr,
T::Err: std::fmt::Display,
{
use serde::Deserialize;
let opt = Option::<&'de str>::deserialize(de)?;
match opt {
None | Some("") => Ok(None),
Some(s) => s.parse::<T>().map_err(serde::de::Error::custom).map(Some),
}
}
#[derive(Debug, serde::Deserialize)] #[derive(Debug, serde::Deserialize)]
#[serde(deny_unknown_fields)] #[serde(deny_unknown_fields)]
struct FritzBoxUpdateParams { struct FritzBoxUpdateParams {
@ -422,10 +440,10 @@ struct FritzBoxUpdateParams {
#[serde(default)] #[serde(default)]
domain: Option<String>, domain: Option<String>,
/// IPv4 address for the domain /// IPv4 address for the domain
#[serde(default)] #[serde(default, deserialize_with = "empty_string_as_none")]
ipv4: Option<Ipv4Addr>, ipv4: Option<Ipv4Addr>,
/// IPv6 address for the domain /// IPv6 address for the domain
#[serde(default)] #[serde(default, deserialize_with = "empty_string_as_none")]
ipv6: Option<Ipv6Addr>, ipv6: Option<Ipv6Addr>,
/// IPv6 prefix for the home network /// IPv6 prefix for the home network
#[allow(unused)] #[allow(unused)]