public inbox for pbs-devel@lists.proxmox.com
 help / color / mirror / Atom feed
From: Wolfgang Bumiller <w.bumiller@proxmox.com>
To: pbs-devel@lists.proxmox.com
Subject: [pbs-devel] [RFC backup 1/6] add tools::serde_filter submodule
Date: Thu, 19 Nov 2020 15:56:03 +0100	[thread overview]
Message-ID: <20201119145608.16866-2-w.bumiller@proxmox.com> (raw)
In-Reply-To: <20201119145608.16866-1-w.bumiller@proxmox.com>

can be used to perform filtering at parse time

Signed-off-by: Wolfgang Bumiller <w.bumiller@proxmox.com>
---
 src/tools.rs              |  1 +
 src/tools/serde_filter.rs | 97 +++++++++++++++++++++++++++++++++++++++
 2 files changed, 98 insertions(+)
 create mode 100644 src/tools/serde_filter.rs

diff --git a/src/tools.rs b/src/tools.rs
index 08f9d22f..8cc446dd 100644
--- a/src/tools.rs
+++ b/src/tools.rs
@@ -32,6 +32,7 @@ pub mod loopdev;
 pub mod lru_cache;
 pub mod nom;
 pub mod runtime;
+pub mod serde_filter;
 pub mod socket;
 pub mod statistics;
 pub mod subscription;
diff --git a/src/tools/serde_filter.rs b/src/tools/serde_filter.rs
new file mode 100644
index 00000000..b8402696
--- /dev/null
+++ b/src/tools/serde_filter.rs
@@ -0,0 +1,97 @@
+use std::marker::PhantomData;
+
+use serde::Deserialize;
+
+/// Helper to filter data while deserializing it.
+///
+/// An example use case is filtering out expired registration challenges at load time of our TFA
+/// config:
+///
+/// ```
+/// # use proxmox_backup::tools::serde_filter::FilteredVecVisitor;
+/// # use serde::{Deserialize, Deserializer, Serialize};
+/// # const CHALLENGE_TIMEOUT: i64 = 2 * 60;
+/// #[derive(Deserialize)]
+/// struct Challenge {
+///     /// Expiration time as unix epoch.
+///     expires: i64,
+///
+///     // ...other entries...
+/// }
+///
+/// #[derive(Default, Deserialize)]
+/// #[serde(deny_unknown_fields)]
+/// #[serde(rename_all = "kebab-case")]
+/// pub struct TfaUserData {
+///     // ...other entries...
+///
+///     #[serde(skip_serializing_if = "Vec::is_empty", default)]
+///     #[serde(deserialize_with = "filter_expired_registrations")]
+///     registrations: Vec<Challenge>,
+/// }
+///
+/// fn filter_expired_registrations<'de, D>(deserializer: D) -> Result<Vec<Challenge>, D::Error>
+/// where
+///     D: Deserializer<'de>,
+/// {
+///     let expire_before = proxmox::tools::time::epoch_i64() - CHALLENGE_TIMEOUT;
+///
+///     Ok(deserializer.deserialize_seq(
+///         FilteredVecVisitor::new(
+///             "a u2f registration challenge entry",
+///             move |c: &Challenge| c.expires < expire_before,
+///         )
+///     )?)
+/// }
+/// ```
+pub struct FilteredVecVisitor<F, T>
+where
+    F: Fn(&T) -> bool
+{
+    filter: F,
+    expecting: &'static str,
+    _ty: PhantomData<T>,
+}
+
+impl<F, T> FilteredVecVisitor<F, T>
+where
+    F: Fn(&T) -> bool,
+{
+    pub fn new(expecting: &'static str, filter: F) -> Self {
+        Self {
+            filter,
+            expecting,
+            _ty: PhantomData,
+        }
+    }
+}
+
+impl<'de, F, T> serde::de::Visitor<'de> for FilteredVecVisitor<F, T>
+where
+    F: Fn(&T) -> bool,
+    T: Deserialize<'de>,
+{
+    type Value = Vec<T>;
+
+    fn expecting(&self, formatter: &mut std::fmt::Formatter) -> std::fmt::Result {
+        formatter.write_str(self.expecting)
+    }
+
+    fn visit_seq<A>(self, mut seq: A) -> Result<Self::Value, A::Error>
+    where
+        A: serde::de::SeqAccess<'de>,
+    {
+        let mut out = match seq.size_hint() {
+            Some(hint) => Vec::with_capacity(hint),
+            None => Vec::new(),
+        };
+
+        while let Some(entry) = seq.next_element::<T>()? {
+            if (self.filter)(&entry) {
+                out.push(entry);
+            }
+        }
+
+        Ok(out)
+    }
+}
-- 
2.20.1





  reply	other threads:[~2020-11-19 14:56 UTC|newest]

Thread overview: 23+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2020-11-19 14:56 [pbs-devel] [RFC backup 0/6] Two factor authentication Wolfgang Bumiller
2020-11-19 14:56 ` Wolfgang Bumiller [this message]
2020-11-19 14:56 ` [pbs-devel] [RFC backup 2/6] config: add tfa configuration Wolfgang Bumiller
2020-11-19 14:56 ` [pbs-devel] [RFC backup 3/6] api: tfa management and login Wolfgang Bumiller
2020-11-19 14:56 ` [pbs-devel] [RFC backup 4/6] depend on libjs-qrcodejs Wolfgang Bumiller
2020-11-19 14:56 ` [pbs-devel] [RFC backup 5/6] proxy: expose qrcodejs Wolfgang Bumiller
2020-11-19 14:56 ` [pbs-devel] [RFC backup 6/6] gui: tfa support Wolfgang Bumiller
2020-11-24  9:42   ` Wolfgang Bumiller
2020-11-24  9:51     ` Thomas Lamprecht
2020-12-02 10:56 ` [pbs-devel] [RFC backup 0/6] Two factor authentication Oguz Bektas
2020-12-02 12:27   ` Thomas Lamprecht
2020-12-02 12:34     ` Thomas Lamprecht
2020-12-02 12:48       ` Oguz Bektas
2020-12-02 12:59         ` Wolfgang Bumiller
2020-12-02 13:08           ` Oguz Bektas
2020-12-02 12:35     ` Oguz Bektas
2020-12-02 12:51       ` Wolfgang Bumiller
2020-12-02 13:15         ` Thomas Lamprecht
2020-12-02 13:07       ` Thomas Lamprecht
2020-12-02 13:35         ` Oguz Bektas
2020-12-02 14:05           ` Thomas Lamprecht
2020-12-02 14:21             ` Oguz Bektas
2020-12-02 14:29               ` Wolfgang Bumiller

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=20201119145608.16866-2-w.bumiller@proxmox.com \
    --to=w.bumiller@proxmox.com \
    --cc=pbs-devel@lists.proxmox.com \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox
Service provided by Proxmox Server Solutions GmbH | Privacy | Legal