From f5fbf4399165068f062ce8781604a3280c56fbb7 Mon Sep 17 00:00:00 2001 From: MinhPhan8803 <82825427+MinhPhan8803@users.noreply.github.com> Date: Wed, 29 Mar 2023 20:41:52 -0500 Subject: [PATCH] Be non empty vec (#1501) --- Cargo.lock | 10 + Cargo.toml | 2 + server/lib/Cargo.toml | 1 + server/lib/src/be/dbentry.rs | 618 +++++++++++++++++------------------ 4 files changed, 310 insertions(+), 321 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index ce72a3137..149d3c251 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -2429,6 +2429,7 @@ dependencies = [ "ldap3_proto", "libc", "libsqlite3-sys", + "nonempty", "num_enum", "openssl", "openssl-sys", @@ -2888,6 +2889,15 @@ dependencies = [ "memchr", ] +[[package]] +name = "nonempty" +version = "0.8.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "aeaf4ad7403de93e699c191202f017118df734d3850b01e13a3a8b2e6953d3c9" +dependencies = [ + "serde", +] + [[package]] name = "nss_kanidm" version = "1.1.0-alpha.12-dev" diff --git a/Cargo.toml b/Cargo.toml index 2cdc6048d..420f775dd 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -179,6 +179,8 @@ yew = "^0.20.0" yew-router = "^0.17.0" zxcvbn = "^2.2.2" +nonempty = "0.8.1" + # enshrinken the WASMs [profile.release.package.kanidmd_web_ui] # optimization over all codebase ( better optimization, slower build ) diff --git a/server/lib/Cargo.toml b/server/lib/Cargo.toml index c965ad67b..fd5d36e30 100644 --- a/server/lib/Cargo.toml +++ b/server/lib/Cargo.toml @@ -59,6 +59,7 @@ tokio = { workspace = true, features = ["net", "sync", "time", "rt"] } tokio-util = { workspace = true, features = ["codec"] } toml.workspace = true touch.workspace = true +nonempty = { workspace = true, features = ["serialize"] } tracing = { workspace = true, features = ["attributes"] } diff --git a/server/lib/src/be/dbentry.rs b/server/lib/src/be/dbentry.rs index f74853f05..3e7eaa1d5 100644 --- a/server/lib/src/be/dbentry.rs +++ b/server/lib/src/be/dbentry.rs @@ -1,6 +1,7 @@ use std::collections::BTreeMap; use std::time::Duration; +use nonempty::NonEmpty; use serde::{Deserialize, Serialize}; use smartstring::alias::String as AttrString; use uuid::Uuid; @@ -10,7 +11,7 @@ use crate::prelude::OperationError; #[derive(Serialize, Deserialize, Debug)] pub struct DbEntryV1 { - pub attrs: BTreeMap>, + pub attrs: BTreeMap>, } #[derive(Serialize, Deserialize, Debug)] @@ -57,219 +58,199 @@ pub enum DbBackup { }, } -fn from_vec_dbval1(attr_val: Vec) -> Result { - // ======================== - // - let mut viter = attr_val.into_iter().peekable(); - - match viter.peek() { - Some(DbValueV1::Utf8(_)) => { - let vs: Result, _> = viter - .map(|dbv| { - if let DbValueV1::Utf8(s) = dbv { - Ok(s) - } else { - Err(OperationError::InvalidValueState) - } - }) - .collect(); - vs.map(DbValueSetV2::Utf8) - } - Some(DbValueV1::Iutf8(_)) => { - let vs: Result, _> = viter - .map(|dbv| { - if let DbValueV1::Iutf8(s) = dbv { - Ok(s) - } else { - Err(OperationError::InvalidValueState) - } - }) - .collect(); - vs.map(DbValueSetV2::Iutf8) - } - Some(DbValueV1::Iname(_)) => { - let vs: Result, _> = viter - .map(|dbv| { - if let DbValueV1::Iname(s) = dbv { - Ok(s) - } else { - Err(OperationError::InvalidValueState) - } - }) - .collect(); - vs.map(DbValueSetV2::Iname) - } - Some(DbValueV1::Uuid(_)) => { - let vs: Result, _> = viter - .map(|dbv| { - if let DbValueV1::Uuid(s) = dbv { - Ok(s) - } else { - Err(OperationError::InvalidValueState) - } - }) - .collect(); - vs.map(DbValueSetV2::Uuid) - } - Some(DbValueV1::Bool(_)) => { - let vs: Result, _> = viter - .map(|dbv| { - if let DbValueV1::Bool(s) = dbv { - Ok(s) - } else { - Err(OperationError::InvalidValueState) - } - }) - .collect(); - vs.map(DbValueSetV2::Bool) - } - Some(DbValueV1::SyntaxType(_)) => { - let vs: Result, _> = viter - .map(|dbv| { - if let DbValueV1::SyntaxType(s) = dbv { - Ok(s) - } else { - Err(OperationError::InvalidValueState) - } - }) - .collect(); - vs.map(DbValueSetV2::SyntaxType) - } - Some(DbValueV1::IndexType(_)) => { - let vs: Result, _> = viter - .map(|dbv| { - if let DbValueV1::IndexType(s) = dbv { - u16::try_from(s).map_err(|_| OperationError::InvalidValueState) - } else { - Err(OperationError::InvalidValueState) - } - }) - .collect(); - vs.map(DbValueSetV2::IndexType) - } - Some(DbValueV1::Reference(_)) => { - let vs: Result, _> = viter - .map(|dbv| { - if let DbValueV1::Reference(s) = dbv { - Ok(s) - } else { - Err(OperationError::InvalidValueState) - } - }) - .collect(); - vs.map(DbValueSetV2::Reference) - } - Some(DbValueV1::JsonFilter(_)) => { - let vs: Result, _> = viter - .map(|dbv| { - if let DbValueV1::JsonFilter(s) = dbv { - Ok(s) - } else { - Err(OperationError::InvalidValueState) - } - }) - .collect(); - vs.map(DbValueSetV2::JsonFilter) - } - Some(DbValueV1::Credential(_)) => { - let vs: Result, _> = viter - .map(|dbv| { - if let DbValueV1::Credential(s) = dbv { - Ok(s) - } else { - Err(OperationError::InvalidValueState) - } - }) - .collect(); - vs.map(DbValueSetV2::Credential) - } - Some(DbValueV1::SecretValue(_)) => { - let vs: Result, _> = viter - .map(|dbv| { - if let DbValueV1::SecretValue(s) = dbv { - Ok(s) - } else { - Err(OperationError::InvalidValueState) - } - }) - .collect(); - vs.map(DbValueSetV2::SecretValue) - } - Some(DbValueV1::SshKey(_)) => { - let vs: Result, _> = viter - .map(|dbv| { - if let DbValueV1::SshKey(s) = dbv { - Ok(s) - } else { - Err(OperationError::InvalidValueState) - } - }) - .collect(); - vs.map(DbValueSetV2::SshKey) - } - Some(DbValueV1::Spn(_, _)) => { - let vs: Result, _> = viter - .map(|dbv| { - if let DbValueV1::Spn(n, d) = dbv { - Ok((n, d)) - } else { - Err(OperationError::InvalidValueState) - } - }) - .collect(); - vs.map(DbValueSetV2::Spn) - } - Some(DbValueV1::Uint32(_)) => { - let vs: Result, _> = viter - .map(|dbv| { - if let DbValueV1::Uint32(s) = dbv { - Ok(s) - } else { - Err(OperationError::InvalidValueState) - } - }) - .collect(); - vs.map(DbValueSetV2::Uint32) - } - Some(DbValueV1::Cid(_)) => { - let vs: Result, _> = viter - .map(|dbv| { - if let DbValueV1::Cid(s) = dbv { - Ok(s) - } else { - Err(OperationError::InvalidValueState) - } - }) - .collect(); - vs.map(DbValueSetV2::Cid) - } - Some(DbValueV1::NsUniqueId(_)) => { - let vs: Result, _> = viter - .map(|dbv| { - if let DbValueV1::NsUniqueId(s) = dbv { - Ok(s) - } else { - Err(OperationError::InvalidValueState) - } - }) - .collect(); - vs.map(DbValueSetV2::NsUniqueId) - } - Some(DbValueV1::DateTime(_)) => { - let vs: Result, _> = viter - .map(|dbv| { - if let DbValueV1::DateTime(s) = dbv { - Ok(s) - } else { - Err(OperationError::InvalidValueState) - } - }) - .collect(); - vs.map(DbValueSetV2::DateTime) - } - Some(DbValueV1::EmailAddress(_)) => { +fn from_vec_dbval1(attr_val: NonEmpty) -> Result { + match attr_val.first() { + DbValueV1::Utf8(_) => attr_val + .into_iter() + .map(|dbv| { + if let DbValueV1::Utf8(s) = dbv { + Ok(s) + } else { + Err(OperationError::InvalidValueState) + } + }) + .collect::, _>>() + .map(DbValueSetV2::Utf8), + DbValueV1::Iutf8(_) => attr_val + .into_iter() + .map(|dbv| { + if let DbValueV1::Iutf8(s) = dbv { + Ok(s) + } else { + Err(OperationError::InvalidValueState) + } + }) + .collect::, _>>() + .map(DbValueSetV2::Iutf8), + DbValueV1::Iname(_) => attr_val + .into_iter() + .map(|dbv| { + if let DbValueV1::Iname(s) = dbv { + Ok(s) + } else { + Err(OperationError::InvalidValueState) + } + }) + .collect::, _>>() + .map(DbValueSetV2::Iname), + DbValueV1::Uuid(_) => attr_val + .into_iter() + .map(|dbv| { + if let DbValueV1::Uuid(s) = dbv { + Ok(s) + } else { + Err(OperationError::InvalidValueState) + } + }) + .collect::, _>>() + .map(DbValueSetV2::Uuid), + DbValueV1::Bool(_) => attr_val + .into_iter() + .map(|dbv| { + if let DbValueV1::Bool(s) = dbv { + Ok(s) + } else { + Err(OperationError::InvalidValueState) + } + }) + .collect::, _>>() + .map(DbValueSetV2::Bool), + DbValueV1::SyntaxType(_) => attr_val + .into_iter() + .map(|dbv| { + if let DbValueV1::SyntaxType(s) = dbv { + Ok(s) + } else { + Err(OperationError::InvalidValueState) + } + }) + .collect::, _>>() + .map(DbValueSetV2::SyntaxType), + DbValueV1::IndexType(_) => attr_val + .into_iter() + .map(|dbv| { + if let DbValueV1::IndexType(s) = dbv { + u16::try_from(s).map_err(|_| OperationError::InvalidValueState) + } else { + Err(OperationError::InvalidValueState) + } + }) + .collect::, _>>() + .map(DbValueSetV2::IndexType), + DbValueV1::Reference(_) => attr_val + .into_iter() + .map(|dbv| { + if let DbValueV1::Reference(s) = dbv { + Ok(s) + } else { + Err(OperationError::InvalidValueState) + } + }) + .collect::, _>>() + .map(DbValueSetV2::Reference), + DbValueV1::JsonFilter(_) => attr_val + .into_iter() + .map(|dbv| { + if let DbValueV1::JsonFilter(s) = dbv { + Ok(s) + } else { + Err(OperationError::InvalidValueState) + } + }) + .collect::, _>>() + .map(DbValueSetV2::JsonFilter), + DbValueV1::Credential(_) => attr_val + .into_iter() + .map(|dbv| { + if let DbValueV1::Credential(s) = dbv { + Ok(s) + } else { + Err(OperationError::InvalidValueState) + } + }) + .collect::, _>>() + .map(DbValueSetV2::Credential), + DbValueV1::SecretValue(_) => attr_val + .into_iter() + .map(|dbv| { + if let DbValueV1::SecretValue(s) = dbv { + Ok(s) + } else { + Err(OperationError::InvalidValueState) + } + }) + .collect::, _>>() + .map(DbValueSetV2::SecretValue), + DbValueV1::SshKey(_) => attr_val + .into_iter() + .map(|dbv| { + if let DbValueV1::SshKey(s) = dbv { + Ok(s) + } else { + Err(OperationError::InvalidValueState) + } + }) + .collect::, _>>() + .map(DbValueSetV2::SshKey), + DbValueV1::Spn(_, _) => attr_val + .into_iter() + .map(|dbv| { + if let DbValueV1::Spn(n, d) = dbv { + Ok((n, d)) + } else { + Err(OperationError::InvalidValueState) + } + }) + .collect::, _>>() + .map(DbValueSetV2::Spn), + DbValueV1::Uint32(_) => attr_val + .into_iter() + .map(|dbv| { + if let DbValueV1::Uint32(s) = dbv { + Ok(s) + } else { + Err(OperationError::InvalidValueState) + } + }) + .collect::, _>>() + .map(DbValueSetV2::Uint32), + DbValueV1::Cid(_) => attr_val + .into_iter() + .map(|dbv| { + if let DbValueV1::Cid(s) = dbv { + Ok(s) + } else { + Err(OperationError::InvalidValueState) + } + }) + .collect::, _>>() + .map(DbValueSetV2::Cid), + DbValueV1::NsUniqueId(_) => attr_val + .into_iter() + .map(|dbv| { + if let DbValueV1::NsUniqueId(s) = dbv { + Ok(s) + } else { + Err(OperationError::InvalidValueState) + } + }) + .collect::, _>>() + .map(DbValueSetV2::NsUniqueId), + DbValueV1::DateTime(_) => attr_val + .into_iter() + .map(|dbv| { + if let DbValueV1::DateTime(s) = dbv { + Ok(s) + } else { + Err(OperationError::InvalidValueState) + } + }) + .collect::, _>>() + .map(DbValueSetV2::DateTime), + DbValueV1::EmailAddress(_) => { let mut primary = None; - let vs: Result, _> = viter + let vs: Result, _> = attr_val + .into_iter() .map(|dbv| { if let DbValueV1::EmailAddress(DbValueEmailAddressV1 { d, p }) = dbv { if p { @@ -284,9 +265,10 @@ fn from_vec_dbval1(attr_val: Vec) -> Result { + DbValueV1::PhoneNumber(_) => { let mut primary = None; - let vs: Result, _> = viter + let vs: Result, _> = attr_val + .into_iter() .map(|dbv| { if let DbValueV1::PhoneNumber(DbValuePhoneNumberV1 { d, p }) = dbv { if p { @@ -301,107 +283,106 @@ fn from_vec_dbval1(attr_val: Vec) -> Result { - let vs: Result, _> = viter - .map(|dbv| { - if let DbValueV1::Address(s) = dbv { - Ok(s) - } else { - Err(OperationError::InvalidValueState) - } - }) - .collect(); - vs.map(DbValueSetV2::Address) - } - Some(DbValueV1::Url(_)) => { - let vs: Result, _> = viter - .map(|dbv| { - if let DbValueV1::Url(s) = dbv { - Ok(s) - } else { - Err(OperationError::InvalidValueState) - } - }) - .collect(); - vs.map(DbValueSetV2::Url) - } - Some(DbValueV1::OauthScope(_)) => { - let vs: Result, _> = viter - .map(|dbv| { - if let DbValueV1::OauthScope(s) = dbv { - Ok(s) - } else { - Err(OperationError::InvalidValueState) - } - }) - .collect(); - vs.map(DbValueSetV2::OauthScope) - } - Some(DbValueV1::OauthScopeMap(_)) => { - let vs: Result, _> = viter - .map(|dbv| { - if let DbValueV1::OauthScopeMap(s) = dbv { - Ok(s) - } else { - Err(OperationError::InvalidValueState) - } - }) - .collect(); - vs.map(DbValueSetV2::OauthScopeMap) - } - Some(DbValueV1::PrivateBinary(_)) => { - let vs: Result, _> = viter - .map(|dbv| { - if let DbValueV1::PrivateBinary(s) = dbv { - Ok(s) - } else { - Err(OperationError::InvalidValueState) - } - }) - .collect(); - vs.map(DbValueSetV2::PrivateBinary) - } - Some(DbValueV1::PublicBinary(_, _)) => { - let vs: Result, _> = viter - .map(|dbv| { - if let DbValueV1::PublicBinary(t, s) = dbv { - Ok((t, s)) - } else { - Err(OperationError::InvalidValueState) - } - }) - .collect(); - vs.map(DbValueSetV2::PublicBinary) - } - Some(DbValueV1::RestrictedString(_)) => { - let vs: Result, _> = viter - .map(|dbv| { - if let DbValueV1::RestrictedString(s) = dbv { - Ok(s) - } else { - Err(OperationError::InvalidValueState) - } - }) - .collect(); - vs.map(DbValueSetV2::RestrictedString) - } - Some(DbValueV1::IntentToken { u: _, s: _ }) => { - let vs: Result, _> = viter - .map(|dbv| { - if let DbValueV1::IntentToken { u, s } = dbv { - Ok((u.as_hyphenated().to_string(), s)) - } else { - Err(OperationError::InvalidValueState) - } - }) - .collect(); - vs.map(DbValueSetV2::IntentToken) - } - // Neither of these should exist yet. - Some(DbValueV1::TrustedDeviceEnrollment { u: _ }) - | Some(DbValueV1::Session { u: _ }) - | None => { - // Shiiiiii + DbValueV1::Address(_) => attr_val + .into_iter() + .map(|dbv| { + if let DbValueV1::Address(s) = dbv { + Ok(s) + } else { + Err(OperationError::InvalidValueState) + } + }) + .collect::, _>>() + .map(DbValueSetV2::Address), + DbValueV1::Url(_) => attr_val + .into_iter() + .map(|dbv| { + if let DbValueV1::Url(s) = dbv { + Ok(s) + } else { + Err(OperationError::InvalidValueState) + } + }) + .collect::, _>>() + .map(DbValueSetV2::Url), + DbValueV1::OauthScope(_) => attr_val + .into_iter() + .map(|dbv| { + if let DbValueV1::OauthScope(s) = dbv { + Ok(s) + } else { + Err(OperationError::InvalidValueState) + } + }) + .collect::, _>>() + .map(DbValueSetV2::OauthScope), + DbValueV1::OauthScopeMap(_) => attr_val + .into_iter() + .map(|dbv| { + if let DbValueV1::OauthScopeMap(s) = dbv { + Ok(s) + } else { + Err(OperationError::InvalidValueState) + } + }) + .collect::, _>>() + .map(DbValueSetV2::OauthScopeMap), + DbValueV1::PrivateBinary(_) => attr_val + .into_iter() + .map(|dbv| { + if let DbValueV1::PrivateBinary(s) = dbv { + Ok(s) + } else { + Err(OperationError::InvalidValueState) + } + }) + .collect::, _>>() + .map(DbValueSetV2::PrivateBinary), + DbValueV1::PublicBinary(_, _) => attr_val + .into_iter() + .map(|dbv| { + if let DbValueV1::PublicBinary(t, s) = dbv { + Ok((t, s)) + } else { + Err(OperationError::InvalidValueState) + } + }) + .collect::, _>>() + .map(DbValueSetV2::PublicBinary), + DbValueV1::RestrictedString(_) => attr_val + .into_iter() + .map(|dbv| { + if let DbValueV1::RestrictedString(s) = dbv { + Ok(s) + } else { + Err(OperationError::InvalidValueState) + } + }) + .collect::, _>>() + .map(DbValueSetV2::RestrictedString), + DbValueV1::IntentToken { u: _, s: _ } => attr_val + .into_iter() + .map(|dbv| { + if let DbValueV1::IntentToken { u, s } = dbv { + Ok((u.as_hyphenated().to_string(), s)) + } else { + Err(OperationError::InvalidValueState) + } + }) + .collect::, _>>() + .map(DbValueSetV2::IntentToken), + DbValueV1::TrustedDeviceEnrollment { u: _ } => attr_val + .into_iter() + .map(|dbv| { + if let DbValueV1::TrustedDeviceEnrollment { u } = dbv { + Ok(u) + } else { + Err(OperationError::InvalidValueState) + } + }) + .collect::, _>>() + .map(DbValueSetV2::TrustedDeviceEnrollment), + DbValueV1::Session { u: _ } => { debug_assert!(false); Err(OperationError::InvalidState) } @@ -413,11 +394,6 @@ impl DbEntry { if let DbEntryVers::V1(dbe) = self.ent { dbe.attrs .into_iter() - .filter(|(_attr_name, attr_val)| { - // Skip anything that is empty, because our from impl - // can't handle it, neither can our dbvaluesetv2 - !attr_val.is_empty() - }) .map(|(attr_name, attr_val)| { from_vec_dbval1(attr_val).map(|attr_val_2| (attr_name, attr_val_2)) })