commit bef1183c494f2c013beb251cfa110a4918eaa70b
parent f935f5cf467239db1a40a81cc150ccb56157fc87
Author: Daniel GarcĂa <dani-garcia@users.noreply.github.com>
Date: Mon, 28 Jan 2019 00:39:14 +0100
Only send one notification per vault import and purge, improve move ciphers functions
Diffstat:
5 files changed, 83 insertions(+), 83 deletions(-)
diff --git a/src/api/core/ciphers.rs b/src/api/core/ciphers.rs
@@ -306,7 +306,9 @@ pub fn update_cipher_from_data(
cipher.save(&conn)?;
cipher.move_to_folder(data.FolderId, &headers.user.uuid, &conn)?;
- nt.send_cipher_update(ut, &cipher, &cipher.update_users_revision(&conn));
+ if ut != UpdateType::None {
+ nt.send_cipher_update(ut, &cipher, &cipher.update_users_revision(&conn));
+ }
Ok(())
}
@@ -351,25 +353,18 @@ fn post_ciphers_import(data: JsonUpcase<ImportData>, headers: Headers, conn: DbC
}
// Read and create the ciphers
- for (index, cipher_data) in data.Ciphers.into_iter().enumerate() {
+ for (index, mut cipher_data) in data.Ciphers.into_iter().enumerate() {
let folder_uuid = relations_map.get(&index).map(|i| folders[*i].uuid.clone());
+ cipher_data.FolderId = folder_uuid;
let mut cipher = Cipher::new(cipher_data.Type, cipher_data.Name.clone());
- update_cipher_from_data(
- &mut cipher,
- cipher_data,
- &headers,
- false,
- &conn,
- &nt,
- UpdateType::CipherCreate,
- )?;
-
- cipher.move_to_folder(folder_uuid, &headers.user.uuid.clone(), &conn)?;
+ update_cipher_from_data(&mut cipher, cipher_data, &headers, false, &conn, &nt, UpdateType::None)?;
}
let mut user = headers.user;
- user.update_revision(&conn)
+ user.update_revision(&conn)?;
+ nt.send_user_update(UpdateType::Vault, &user);
+ Ok(())
}
#[put("/ciphers/<uuid>/admin", data = "<data>")]
@@ -637,7 +632,14 @@ fn share_cipher_by_uuid(
}
#[post("/ciphers/<uuid>/attachment", format = "multipart/form-data", data = "<data>")]
-fn post_attachment(uuid: String, data: Data, content_type: &ContentType, headers: Headers, conn: DbConn, nt: Notify) -> JsonResult {
+fn post_attachment(
+ uuid: String,
+ data: Data,
+ content_type: &ContentType,
+ headers: Headers,
+ conn: DbConn,
+ nt: Notify,
+) -> JsonResult {
let cipher = match Cipher::find_by_uuid(&uuid, &conn) {
Some(cipher) => cipher,
None => err!("Cipher doesn't exist"),
@@ -816,56 +818,60 @@ fn delete_cipher_selected_post(data: JsonUpcase<Value>, headers: Headers, conn:
delete_cipher_selected(data, headers, conn, nt)
}
+#[derive(Deserialize)]
+#[allow(non_snake_case)]
+struct MoveCipherData {
+ FolderId: Option<String>,
+ Ids: Vec<String>,
+}
+
#[post("/ciphers/move", data = "<data>")]
-fn move_cipher_selected(data: JsonUpcase<Value>, headers: Headers, conn: DbConn, nt: Notify) -> EmptyResult {
+fn move_cipher_selected(data: JsonUpcase<MoveCipherData>, headers: Headers, conn: DbConn, nt: Notify) -> EmptyResult {
let data = data.into_inner().data;
+ let user_uuid = headers.user.uuid;
- let folder_id = match data.get("FolderId") {
- Some(folder_id) => match folder_id.as_str() {
- Some(folder_id) => match Folder::find_by_uuid(folder_id, &conn) {
- Some(folder) => {
- if folder.user_uuid != headers.user.uuid {
- err!("Folder is not owned by user")
- }
- Some(folder.uuid)
+ if let Some(ref folder_id) = data.FolderId {
+ match Folder::find_by_uuid(folder_id, &conn) {
+ Some(folder) => {
+ if folder.user_uuid != user_uuid {
+ err!("Folder is not owned by user")
}
- None => err!("Folder doesn't exist"),
- },
- None => err!("Folder id provided in wrong format"),
- },
- None => None,
- };
-
- let uuids = match data.get("Ids") {
- Some(ids) => match ids.as_array() {
- Some(ids) => ids.iter().filter_map(Value::as_str),
- None => err!("Posted ids field is not an array"),
- },
- None => err!("Request missing ids field"),
- };
+ }
+ None => err!("Folder doesn't exist"),
+ }
+ }
- for uuid in uuids {
- let mut cipher = match Cipher::find_by_uuid(uuid, &conn) {
+ for uuid in data.Ids {
+ let mut cipher = match Cipher::find_by_uuid(&uuid, &conn) {
Some(cipher) => cipher,
None => err!("Cipher doesn't exist"),
};
- if !cipher.is_accessible_to_user(&headers.user.uuid, &conn) {
+ if !cipher.is_accessible_to_user(&user_uuid, &conn) {
err!("Cipher is not accessible by user")
}
// Move cipher
- cipher.move_to_folder(folder_id.clone(), &headers.user.uuid, &conn)?;
+ cipher.move_to_folder(data.FolderId.clone(), &user_uuid, &conn)?;
cipher.save(&conn)?;
- nt.send_cipher_update(UpdateType::CipherUpdate, &cipher, &cipher.update_users_revision(&conn));
+ nt.send_cipher_update(
+ UpdateType::CipherUpdate,
+ &cipher,
+ &User::update_uuid_revision(&user_uuid, &conn),
+ );
}
Ok(())
}
#[put("/ciphers/move", data = "<data>")]
-fn move_cipher_selected_put(data: JsonUpcase<Value>, headers: Headers, conn: DbConn, nt: Notify) -> EmptyResult {
+fn move_cipher_selected_put(
+ data: JsonUpcase<MoveCipherData>,
+ headers: Headers,
+ conn: DbConn,
+ nt: Notify,
+) -> EmptyResult {
move_cipher_selected(data, headers, conn, nt)
}
@@ -874,7 +880,7 @@ fn delete_all(data: JsonUpcase<PasswordData>, headers: Headers, conn: DbConn, nt
let data: PasswordData = data.into_inner().data;
let password_hash = data.MasterPasswordHash;
- let user = headers.user;
+ let mut user = headers.user;
if !user.check_valid_password(&password_hash) {
err!("Invalid password")
@@ -883,15 +889,15 @@ fn delete_all(data: JsonUpcase<PasswordData>, headers: Headers, conn: DbConn, nt
// Delete ciphers and their attachments
for cipher in Cipher::find_owned_by_user(&user.uuid, &conn) {
cipher.delete(&conn)?;
- nt.send_cipher_update(UpdateType::CipherDelete, &cipher, &cipher.update_users_revision(&conn));
}
// Delete folders
for f in Folder::find_by_user(&user.uuid, &conn) {
f.delete(&conn)?;
- nt.send_folder_update(UpdateType::FolderDelete, &f);
}
+ user.update_revision(&conn)?;
+ nt.send_user_update(UpdateType::Vault, &user);
Ok(())
}
diff --git a/src/api/notifications.rs b/src/api/notifications.rs
@@ -240,7 +240,6 @@ impl WebSocketUsers {
}
// NOTE: The last modified date needs to be updated before calling these methods
- #[allow(dead_code)]
pub fn send_user_update(&self, ut: UpdateType, user: &User) {
let data = create_update(
vec![
@@ -325,6 +324,7 @@ fn create_ping() -> Vec<u8> {
}
#[allow(dead_code)]
+#[derive(PartialEq)]
pub enum UpdateType {
CipherUpdate = 0,
CipherCreate = 1,
@@ -340,6 +340,8 @@ pub enum UpdateType {
SyncSettings = 10,
LogOut = 11,
+
+ None = 100,
}
use rocket::State;
diff --git a/src/db/models/cipher.rs b/src/db/models/cipher.rs
@@ -196,40 +196,28 @@ impl Cipher {
}
pub fn move_to_folder(&self, folder_uuid: Option<String>, user_uuid: &str, conn: &DbConn) -> EmptyResult {
- match self.get_folder_uuid(&user_uuid, &conn) {
- None => {
- match folder_uuid {
- Some(new_folder) => {
- self.update_users_revision(conn);
- let folder_cipher = FolderCipher::new(&new_folder, &self.uuid);
- folder_cipher.save(&conn)
- }
- None => Ok(()), //nothing to do
- }
- }
- Some(current_folder) => {
- match folder_uuid {
- Some(new_folder) => {
- if current_folder == new_folder {
- Ok(()) //nothing to do
- } else {
- self.update_users_revision(conn);
- if let Some(current_folder) =
- FolderCipher::find_by_folder_and_cipher(¤t_folder, &self.uuid, &conn)
- {
- current_folder.delete(&conn)?;
- }
- FolderCipher::new(&new_folder, &self.uuid).save(&conn)
- }
- }
- None => {
- self.update_users_revision(conn);
- match FolderCipher::find_by_folder_and_cipher(¤t_folder, &self.uuid, &conn) {
- Some(current_folder) => current_folder.delete(&conn),
- None => err!("Couldn't move from previous folder"),
- }
- }
+ User::update_uuid_revision(user_uuid, &conn);
+
+ match (self.get_folder_uuid(&user_uuid, &conn), folder_uuid) {
+ // No changes
+ (None, None) => Ok(()),
+ (Some(ref old), Some(ref new)) if old == new => Ok(()),
+
+ // Add to folder
+ (None, Some(new)) => FolderCipher::new(&new, &self.uuid).save(&conn),
+
+ // Remove from folder
+ (Some(old), None) => match FolderCipher::find_by_folder_and_cipher(&old, &self.uuid, &conn) {
+ Some(old) => old.delete(&conn),
+ None => err!("Couldn't move from previous folder"),
+ },
+
+ // Move to another folder
+ (Some(old), Some(new)) => {
+ if let Some(old) = FolderCipher::find_by_folder_and_cipher(&old, &self.uuid, &conn) {
+ old.delete(&conn)?;
}
+ FolderCipher::new(&new, &self.uuid).save(&conn)
}
}
}
diff --git a/src/db/models/collection.rs b/src/db/models/collection.rs
@@ -241,7 +241,9 @@ impl CollectionUser {
pub fn delete_all_by_collection(collection_uuid: &str, conn: &DbConn) -> EmptyResult {
CollectionUser::find_by_collection(&collection_uuid, conn)
.iter()
- .for_each(|collection| User::update_uuid_revision(&collection.user_uuid, conn));
+ .for_each(|collection| {
+ User::update_uuid_revision(&collection.user_uuid, conn);
+ });
diesel::delete(users_collections::table.filter(users_collections::collection_uuid.eq(collection_uuid)))
.execute(&**conn)
diff --git a/src/db/models/user.rs b/src/db/models/user.rs
@@ -172,12 +172,14 @@ impl User {
.map_res("Error deleting user")
}
- pub fn update_uuid_revision(uuid: &str, conn: &DbConn) {
+ pub fn update_uuid_revision(uuid: &str, conn: &DbConn) -> Vec<String> {
if let Some(mut user) = User::find_by_uuid(&uuid, conn) {
if user.update_revision(conn).is_err() {
warn!("Failed to update revision for {}", user.email);
};
};
+
+ vec![uuid.to_string()]
}
pub fn update_revision(&mut self, conn: &DbConn) -> EmptyResult {