diff options
author | Tomasz Kramkowski <tomasz@kramkow.ski> | 2025-07-20 12:31:13 +0100 |
---|---|---|
committer | Tomasz Kramkowski <tomasz@kramkow.ski> | 2025-07-20 12:31:13 +0100 |
commit | 847cfa692b20903a8c6a43c01948ded6db0035a7 (patch) | |
tree | 9aa5eb2751c5e6a360776f9585af37a198dbc11c /src/config/helpers.rs | |
parent | e6ac7b1643e01764c5fccddee985d25bf53494e2 (diff) | |
download | mqttr-847cfa692b20903a8c6a43c01948ded6db0035a7.tar.gz mqttr-847cfa692b20903a8c6a43c01948ded6db0035a7.tar.xz mqttr-847cfa692b20903a8c6a43c01948ded6db0035a7.zip |
Non-UTF8 path/argument support
Diffstat (limited to 'src/config/helpers.rs')
-rw-r--r-- | src/config/helpers.rs | 44 |
1 files changed, 41 insertions, 3 deletions
diff --git a/src/config/helpers.rs b/src/config/helpers.rs index ddf29ad..edf4bd5 100644 --- a/src/config/helpers.rs +++ b/src/config/helpers.rs @@ -1,8 +1,13 @@ // SPDX-FileCopyrightText: 2025 Tomasz Kramkowski <tomasz@kramkow.ski> // SPDX-License-Identifier: GPL-3.0-or-later -use std::time::Duration; +use std::{ + ffi::{OsStr, OsString}, + os::unix::ffi::OsStrExt, + time::Duration, +}; +use base64::{engine::general_purpose::STANDARD, Engine as _}; use rumqttc::QoS; use serde::{de, Deserialize, Deserializer}; @@ -79,12 +84,44 @@ where Ok(helper.map(|Helper(external)| external)) } +pub fn deserialize_box_slice_os_string<'de, D>(deserializer: D) -> Result<Box<[OsString]>, D::Error> +where + D: Deserializer<'de>, +{ + #[derive(Deserialize)] + #[serde(untagged)] + enum Untagged { + String(String), + Base64 { b64: String }, + } + + impl TryInto<OsString> for Untagged { + type Error = String; + fn try_into(self) -> Result<OsString, Self::Error> { + match self { + Untagged::String(s) => Ok(s.into()), + Untagged::Base64 { b64 } => match STANDARD.decode(&b64) { + Err(_) => Err(b64), + Ok(b) => Ok(OsStr::from_bytes(&b).to_owned()), + }, + } + } + } + + Vec::<Untagged>::deserialize(deserializer)? + .into_iter() + .map(TryInto::<OsString>::try_into) + .collect::<Result<_, _>>() + .map_err(|e| de::Error::invalid_value(de::Unexpected::Str(&e), &"valid Base64")) +} + impl<'de> Deserialize<'de> for super::Program { fn deserialize<D: Deserializer<'de>>(deserializer: D) -> Result<Self, D::Error> { #[derive(Deserialize)] #[serde(remote = "super::Program")] struct Helper { - command: Box<[String]>, + #[serde(deserialize_with = "deserialize_box_slice_os_string")] + command: Box<[OsString]>, #[serde(default, deserialize_with = "deserialize_timeout_opt")] timeout: Option<Duration>, } @@ -92,7 +129,8 @@ impl<'de> Deserialize<'de> for super::Program { #[derive(Deserialize)] #[serde(untagged)] enum Untagged { - Short(Box<[String]>), + #[serde(deserialize_with = "deserialize_box_slice_os_string")] + Short(Box<[OsString]>), #[serde(with = "Helper")] Full(super::Program), } |