mirror of
https://github.com/dani-garcia/vaultwarden.git
synced 2026-04-02 15:19:21 -07:00
Fix empty string FolderId (#7048)
In newer versions of Bitwarden Clients instead of using `null` the folder_id will be an empty string. This commit adds a special deserialize_with function to keep the same way of working code-wise. Fixes #6962 Signed-off-by: BlackDex <black.dex@gmail.com>
This commit is contained in:
committed by
GitHub
parent
787822854c
commit
f07a91141a
@@ -22,7 +22,7 @@ use crate::{
|
|||||||
DbConn,
|
DbConn,
|
||||||
},
|
},
|
||||||
mail,
|
mail,
|
||||||
util::{format_date, NumberOrString},
|
util::{deser_opt_nonempty_str, format_date, NumberOrString},
|
||||||
CONFIG,
|
CONFIG,
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -649,6 +649,7 @@ struct UpdateFolderData {
|
|||||||
// There is a bug in 2024.3.x which adds a `null` item.
|
// There is a bug in 2024.3.x which adds a `null` item.
|
||||||
// To bypass this we allow a Option here, but skip it during the updates
|
// To bypass this we allow a Option here, but skip it during the updates
|
||||||
// See: https://github.com/bitwarden/clients/issues/8453
|
// See: https://github.com/bitwarden/clients/issues/8453
|
||||||
|
#[serde(default, deserialize_with = "deser_opt_nonempty_str")]
|
||||||
id: Option<FolderId>,
|
id: Option<FolderId>,
|
||||||
name: String,
|
name: String,
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -11,7 +11,7 @@ use rocket::{
|
|||||||
use serde_json::Value;
|
use serde_json::Value;
|
||||||
|
|
||||||
use crate::auth::ClientVersion;
|
use crate::auth::ClientVersion;
|
||||||
use crate::util::{save_temp_file, NumberOrString};
|
use crate::util::{deser_opt_nonempty_str, save_temp_file, NumberOrString};
|
||||||
use crate::{
|
use crate::{
|
||||||
api::{self, core::log_event, EmptyResult, JsonResult, Notify, PasswordOrOtpData, UpdateType},
|
api::{self, core::log_event, EmptyResult, JsonResult, Notify, PasswordOrOtpData, UpdateType},
|
||||||
auth::{Headers, OrgIdGuard, OwnerHeaders},
|
auth::{Headers, OrgIdGuard, OwnerHeaders},
|
||||||
@@ -248,6 +248,7 @@ pub struct CipherData {
|
|||||||
// Id is optional as it is included only in bulk share
|
// Id is optional as it is included only in bulk share
|
||||||
pub id: Option<CipherId>,
|
pub id: Option<CipherId>,
|
||||||
// Folder id is not included in import
|
// Folder id is not included in import
|
||||||
|
#[serde(default, deserialize_with = "deser_opt_nonempty_str")]
|
||||||
pub folder_id: Option<FolderId>,
|
pub folder_id: Option<FolderId>,
|
||||||
// TODO: Some of these might appear all the time, no need for Option
|
// TODO: Some of these might appear all the time, no need for Option
|
||||||
#[serde(alias = "organizationID")]
|
#[serde(alias = "organizationID")]
|
||||||
@@ -297,6 +298,7 @@ pub struct CipherData {
|
|||||||
#[derive(Debug, Deserialize)]
|
#[derive(Debug, Deserialize)]
|
||||||
#[serde(rename_all = "camelCase")]
|
#[serde(rename_all = "camelCase")]
|
||||||
pub struct PartialCipherData {
|
pub struct PartialCipherData {
|
||||||
|
#[serde(default, deserialize_with = "deser_opt_nonempty_str")]
|
||||||
folder_id: Option<FolderId>,
|
folder_id: Option<FolderId>,
|
||||||
favorite: bool,
|
favorite: bool,
|
||||||
}
|
}
|
||||||
@@ -1569,6 +1571,7 @@ async fn restore_cipher_selected(
|
|||||||
#[derive(Deserialize)]
|
#[derive(Deserialize)]
|
||||||
#[serde(rename_all = "camelCase")]
|
#[serde(rename_all = "camelCase")]
|
||||||
struct MoveCipherData {
|
struct MoveCipherData {
|
||||||
|
#[serde(default, deserialize_with = "deser_opt_nonempty_str")]
|
||||||
folder_id: Option<FolderId>,
|
folder_id: Option<FolderId>,
|
||||||
ids: Vec<CipherId>,
|
ids: Vec<CipherId>,
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -8,6 +8,7 @@ use crate::{
|
|||||||
models::{Folder, FolderId},
|
models::{Folder, FolderId},
|
||||||
DbConn,
|
DbConn,
|
||||||
},
|
},
|
||||||
|
util::deser_opt_nonempty_str,
|
||||||
};
|
};
|
||||||
|
|
||||||
pub fn routes() -> Vec<rocket::Route> {
|
pub fn routes() -> Vec<rocket::Route> {
|
||||||
@@ -38,6 +39,7 @@ async fn get_folder(folder_id: FolderId, headers: Headers, conn: DbConn) -> Json
|
|||||||
#[serde(rename_all = "camelCase")]
|
#[serde(rename_all = "camelCase")]
|
||||||
pub struct FolderData {
|
pub struct FolderData {
|
||||||
pub name: String,
|
pub name: String,
|
||||||
|
#[serde(default, deserialize_with = "deser_opt_nonempty_str")]
|
||||||
pub id: Option<FolderId>,
|
pub id: Option<FolderId>,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
15
src/util.rs
15
src/util.rs
@@ -634,6 +634,21 @@ fn _process_key(key: &str) -> String {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn deser_opt_nonempty_str<'de, D, T>(deserializer: D) -> Result<Option<T>, D::Error>
|
||||||
|
where
|
||||||
|
D: Deserializer<'de>,
|
||||||
|
T: From<String>,
|
||||||
|
{
|
||||||
|
use serde::Deserialize;
|
||||||
|
Ok(Option::<String>::deserialize(deserializer)?.and_then(|s| {
|
||||||
|
if s.is_empty() {
|
||||||
|
None
|
||||||
|
} else {
|
||||||
|
Some(T::from(s))
|
||||||
|
}
|
||||||
|
}))
|
||||||
|
}
|
||||||
|
|
||||||
#[derive(Clone, Debug, Deserialize)]
|
#[derive(Clone, Debug, Deserialize)]
|
||||||
#[serde(untagged)]
|
#[serde(untagged)]
|
||||||
pub enum NumberOrString {
|
pub enum NumberOrString {
|
||||||
|
|||||||
Reference in New Issue
Block a user