1
0
Fork 0
mirror of https://github.com/dani-garcia/vaultwarden.git synced 2025-05-30 15:33:56 +00:00

Updated Cipher API with breaking changes, and included backwards compatibility

This commit is contained in:
Daniel García 2018-03-06 00:02:36 +01:00
parent e2f7f56a81
commit 1277cb099d
7 changed files with 153 additions and 80 deletions

View file

@ -72,22 +72,30 @@ fn get_cipher(uuid: String, headers: Headers, conn: DbConn) -> JsonResult {
#[derive(Deserialize, Debug)]
#[allow(non_snake_case)]
struct CipherData {
#[serde(rename = "type")]
type_: i32,
// Folder id is not included in import
folderId: Option<String>,
// TODO: Some of these might appear all the time, no need for Option
organizationId: Option<String>,
name: Option<String>,
notes: Option<String>,
favorite: Option<bool>,
/*
Login = 1,
SecureNote = 2,
Card = 3,
Identity = 4
*/
#[serde(rename = "type")]
type_: i32,
name: String,
notes: Option<String>,
fields: Option<Value>,
// Only one of these should exist, depending on type
login: Option<Value>,
secureNote: Option<Value>,
card: Option<Value>,
identity: Option<Value>,
fields: Option<Vec<Value>>,
favorite: bool,
}
#[post("/ciphers", data = "<data>")]
@ -95,8 +103,8 @@ fn post_ciphers(data: Json<CipherData>, headers: Headers, conn: DbConn) -> JsonR
let data: CipherData = data.into_inner();
let user_uuid = headers.user.uuid.clone();
let favorite = data.favorite.unwrap_or(false);
let mut cipher = Cipher::new(user_uuid, data.type_, favorite);
let favorite = data.favorite;
let mut cipher = Cipher::new(user_uuid, data.type_, data.name.clone(), favorite);
update_cipher_from_data(&mut cipher, data, &headers, &conn)?;
cipher.save(&conn);
@ -118,16 +126,42 @@ fn update_cipher_from_data(cipher: &mut Cipher, data: CipherData, headers: &Head
cipher.folder_uuid = Some(folder_id);
}
if let Some(org_id) = data.organizationId {
if let org_id @ Some(_) = data.organizationId {
// TODO: Check if user in org
cipher.organization_uuid = Some(org_id);
cipher.organization_uuid = org_id;
}
// TODO: ******* Backwards compat start **********
// To remove backwards compatibility, just create an empty values object,
// and remove the compat code from cipher::to_json
let mut values = json!({
"Name": data.name,
"Notes": data.notes
});
if let Some(ref fields) = data.fields {
values["Fields"] = Value::Array(fields.as_array().unwrap().iter().map(|f| {
let mut value = json!({});
// Copy every field object and change the names to the correct case
copy_values(&f, &mut value);
value
}).collect());
} else {
values["Fields"] = Value::Null;
}
// TODO: ******* Backwards compat end **********
if let notes @ Some(_) = data.notes {
cipher.notes = notes;
}
if let Some(fields) = data.fields {
use serde_json::to_string;
cipher.fields = to_string(&fields).ok();
}
let type_data_opt = match data.type_ {
1 => data.login,
2 => data.secureNote,
@ -146,31 +180,11 @@ fn update_cipher_from_data(cipher: &mut Cipher, data: CipherData, headers: &Head
err!("Data invalid")
}
if let Some(ref fields) = data.fields {
values["Fields"] = Value::Array(fields.iter().map(|f| {
let mut value = empty_map_value();
// Copy every field object and change the names to the correct case
copy_values(&f, &mut value);
value
}).collect());
} else {
values["Fields"] = Value::Null;
}
cipher.data = values.to_string();
Ok(())
}
fn empty_map_value() -> Value {
use std::collections::BTreeMap;
use serde_json;
serde_json::to_value(BTreeMap::<String, Value>::new()).unwrap()
}
fn copy_values(from: &Value, to: &mut Value) -> bool {
let map = match from.as_object() {
Some(map) => map,
@ -230,8 +244,8 @@ fn post_ciphers_import(data: Json<ImportData>, headers: Headers, conn: DbConn) -
.map(|i| folders[*i as usize].uuid.clone());
let user_uuid = headers.user.uuid.clone();
let favorite = cipher_data.favorite.unwrap_or(false);
let mut cipher = Cipher::new(user_uuid, cipher_data.type_, favorite);
let favorite = cipher_data.favorite;
let mut cipher = Cipher::new(user_uuid, cipher_data.type_, cipher_data.name.clone(), favorite);
if update_cipher_from_data(&mut cipher, cipher_data, &headers, &conn).is_err() { err!("Error creating cipher") }
@ -262,7 +276,7 @@ fn put_cipher(uuid: String, data: Json<CipherData>, headers: Headers, conn: DbCo
err!("Cipher is not owned by user")
}
cipher.favorite = data.favorite.unwrap_or(false);
cipher.favorite = data.favorite;
update_cipher_from_data(&mut cipher, data, &headers, &conn)?;
cipher.save(&conn);
@ -366,6 +380,14 @@ fn delete_cipher(uuid: String, headers: Headers, conn: DbConn) -> EmptyResult {
Ok(())
}
#[post("/ciphers/delete", data = "<data>")]
fn delete_cipher_selected(data: Json<Value>, headers: Headers, conn: DbConn) -> EmptyResult {
let data: Value = data.into_inner();
println!("{:#?}", data);
unimplemented!()
}
#[post("/ciphers/purge", data = "<data>")]
fn delete_all(data: Json<PasswordData>, headers: Headers, conn: DbConn) -> EmptyResult {
let data: PasswordData = data.into_inner();

View file

@ -32,8 +32,9 @@ pub fn routes() -> Vec<Route> {
delete_attachment,
post_cipher,
put_cipher,
delete_cipher,
delete_cipher_post,
delete_cipher,
delete_cipher_selected,
delete_all,
get_folders,

View file

@ -18,15 +18,25 @@ pub struct Cipher {
pub folder_uuid: Option<String>,
pub organization_uuid: Option<String>,
/*
Login = 1,
SecureNote = 2,
Card = 3,
Identity = 4
*/
pub type_: i32,
pub name: String,
pub notes: Option<String>,
pub fields: Option<String>,
pub data: String,
pub favorite: bool,
}
/// Local methods
impl Cipher {
pub fn new(user_uuid: String, type_: i32, favorite: bool) -> Self {
pub fn new(user_uuid: String, type_: i32, name: String, favorite: bool) -> Self {
let now = Utc::now().naive_utc();
Self {
@ -40,6 +50,10 @@ impl Cipher {
type_,
favorite,
name,
notes: None,
fields: None,
data: String::new(),
}
@ -58,12 +72,25 @@ impl Cipher {
use util::format_date;
use super::Attachment;
let data_json: JsonValue = serde_json::from_str(&self.data).unwrap();
let attachments = Attachment::find_by_cipher(&self.uuid, conn);
let attachments_json: Vec<JsonValue> = attachments.iter().map(|c| c.to_json(host)).collect();
json!({
let fields_json: JsonValue = if let Some(ref fields) = self.fields {
serde_json::from_str(fields).unwrap()
} else { JsonValue::Null };
let mut data_json: JsonValue = serde_json::from_str(&self.data).unwrap();
// TODO: ******* Backwards compat start **********
// To remove backwards compatibility, just remove this entire section
// and remove the compat code from ciphers::update_cipher_from_data
if self.type_ == 1 && data_json["Uris"].is_array() {
let uri = data_json["Uris"][0]["uri"].clone();
data_json["Uri"] = uri;
}
// TODO: ******* Backwards compat end **********
let mut json_object = json!({
"Id": self.uuid,
"Type": self.type_,
"RevisionDate": format_date(&self.updated_at),
@ -72,10 +99,27 @@ impl Cipher {
"OrganizationId": "",
"Attachments": attachments_json,
"OrganizationUseTotp": false,
"Name": self.name,
"Notes": self.notes,
"Fields": fields_json,
"Data": data_json,
"Object": "cipher",
"Edit": true,
})
});
let key = match self.type_ {
1 => "Login",
2 => "SecureNote",
3 => "Card",
4 => "Identity",
_ => panic!("Wrong type"),
};
json_object[key] = data_json;
json_object
}
pub fn save(&mut self, conn: &DbConn) -> bool {

View file

@ -17,6 +17,9 @@ table! {
organization_uuid -> Nullable<Text>,
#[sql_name = "type"]
type_ -> Integer,
name -> Text,
notes -> Nullable<Text>,
fields -> Nullable<Text>,
data -> Text,
favorite -> Bool,
}