mirror of
https://github.com/dani-garcia/vaultwarden
synced 2024-12-15 01:53:43 +01:00
Only send one notification per vault import and purge, improve move ciphers functions
This commit is contained in:
parent
f935f5cf46
commit
bef1183c49
5 changed files with 83 additions and 83 deletions
|
@ -306,7 +306,9 @@ pub fn update_cipher_from_data(
|
||||||
cipher.save(&conn)?;
|
cipher.save(&conn)?;
|
||||||
cipher.move_to_folder(data.FolderId, &headers.user.uuid, &conn)?;
|
cipher.move_to_folder(data.FolderId, &headers.user.uuid, &conn)?;
|
||||||
|
|
||||||
|
if ut != UpdateType::None {
|
||||||
nt.send_cipher_update(ut, &cipher, &cipher.update_users_revision(&conn));
|
nt.send_cipher_update(ut, &cipher, &cipher.update_users_revision(&conn));
|
||||||
|
}
|
||||||
|
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
@ -351,25 +353,18 @@ fn post_ciphers_import(data: JsonUpcase<ImportData>, headers: Headers, conn: DbC
|
||||||
}
|
}
|
||||||
|
|
||||||
// Read and create the ciphers
|
// 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());
|
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());
|
let mut cipher = Cipher::new(cipher_data.Type, cipher_data.Name.clone());
|
||||||
update_cipher_from_data(
|
update_cipher_from_data(&mut cipher, cipher_data, &headers, false, &conn, &nt, UpdateType::None)?;
|
||||||
&mut cipher,
|
|
||||||
cipher_data,
|
|
||||||
&headers,
|
|
||||||
false,
|
|
||||||
&conn,
|
|
||||||
&nt,
|
|
||||||
UpdateType::CipherCreate,
|
|
||||||
)?;
|
|
||||||
|
|
||||||
cipher.move_to_folder(folder_uuid, &headers.user.uuid.clone(), &conn)?;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
let mut user = headers.user;
|
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>")]
|
#[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>")]
|
#[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) {
|
let cipher = match Cipher::find_by_uuid(&uuid, &conn) {
|
||||||
Some(cipher) => cipher,
|
Some(cipher) => cipher,
|
||||||
None => err!("Cipher doesn't exist"),
|
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)
|
delete_cipher_selected(data, headers, conn, nt)
|
||||||
}
|
}
|
||||||
|
|
||||||
#[post("/ciphers/move", data = "<data>")]
|
#[derive(Deserialize)]
|
||||||
fn move_cipher_selected(data: JsonUpcase<Value>, headers: Headers, conn: DbConn, nt: Notify) -> EmptyResult {
|
#[allow(non_snake_case)]
|
||||||
let data = data.into_inner().data;
|
struct MoveCipherData {
|
||||||
|
FolderId: Option<String>,
|
||||||
|
Ids: Vec<String>,
|
||||||
|
}
|
||||||
|
|
||||||
let folder_id = match data.get("FolderId") {
|
#[post("/ciphers/move", data = "<data>")]
|
||||||
Some(folder_id) => match folder_id.as_str() {
|
fn move_cipher_selected(data: JsonUpcase<MoveCipherData>, headers: Headers, conn: DbConn, nt: Notify) -> EmptyResult {
|
||||||
Some(folder_id) => match Folder::find_by_uuid(folder_id, &conn) {
|
let data = data.into_inner().data;
|
||||||
|
let user_uuid = headers.user.uuid;
|
||||||
|
|
||||||
|
if let Some(ref folder_id) = data.FolderId {
|
||||||
|
match Folder::find_by_uuid(folder_id, &conn) {
|
||||||
Some(folder) => {
|
Some(folder) => {
|
||||||
if folder.user_uuid != headers.user.uuid {
|
if folder.user_uuid != user_uuid {
|
||||||
err!("Folder is not owned by user")
|
err!("Folder is not owned by user")
|
||||||
}
|
}
|
||||||
Some(folder.uuid)
|
|
||||||
}
|
}
|
||||||
None => err!("Folder doesn't exist"),
|
None => err!("Folder doesn't exist"),
|
||||||
},
|
}
|
||||||
None => err!("Folder id provided in wrong format"),
|
}
|
||||||
},
|
|
||||||
None => None,
|
|
||||||
};
|
|
||||||
|
|
||||||
let uuids = match data.get("Ids") {
|
for uuid in data.Ids {
|
||||||
Some(ids) => match ids.as_array() {
|
let mut cipher = match Cipher::find_by_uuid(&uuid, &conn) {
|
||||||
Some(ids) => ids.iter().filter_map(Value::as_str),
|
|
||||||
None => err!("Posted ids field is not an array"),
|
|
||||||
},
|
|
||||||
None => err!("Request missing ids field"),
|
|
||||||
};
|
|
||||||
|
|
||||||
for uuid in uuids {
|
|
||||||
let mut cipher = match Cipher::find_by_uuid(uuid, &conn) {
|
|
||||||
Some(cipher) => cipher,
|
Some(cipher) => cipher,
|
||||||
None => err!("Cipher doesn't exist"),
|
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")
|
err!("Cipher is not accessible by user")
|
||||||
}
|
}
|
||||||
|
|
||||||
// Move cipher
|
// 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)?;
|
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(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
#[put("/ciphers/move", data = "<data>")]
|
#[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)
|
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 data: PasswordData = data.into_inner().data;
|
||||||
let password_hash = data.MasterPasswordHash;
|
let password_hash = data.MasterPasswordHash;
|
||||||
|
|
||||||
let user = headers.user;
|
let mut user = headers.user;
|
||||||
|
|
||||||
if !user.check_valid_password(&password_hash) {
|
if !user.check_valid_password(&password_hash) {
|
||||||
err!("Invalid password")
|
err!("Invalid password")
|
||||||
|
@ -883,15 +889,15 @@ fn delete_all(data: JsonUpcase<PasswordData>, headers: Headers, conn: DbConn, nt
|
||||||
// Delete ciphers and their attachments
|
// Delete ciphers and their attachments
|
||||||
for cipher in Cipher::find_owned_by_user(&user.uuid, &conn) {
|
for cipher in Cipher::find_owned_by_user(&user.uuid, &conn) {
|
||||||
cipher.delete(&conn)?;
|
cipher.delete(&conn)?;
|
||||||
nt.send_cipher_update(UpdateType::CipherDelete, &cipher, &cipher.update_users_revision(&conn));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Delete folders
|
// Delete folders
|
||||||
for f in Folder::find_by_user(&user.uuid, &conn) {
|
for f in Folder::find_by_user(&user.uuid, &conn) {
|
||||||
f.delete(&conn)?;
|
f.delete(&conn)?;
|
||||||
nt.send_folder_update(UpdateType::FolderDelete, &f);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
user.update_revision(&conn)?;
|
||||||
|
nt.send_user_update(UpdateType::Vault, &user);
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -240,7 +240,6 @@ impl WebSocketUsers {
|
||||||
}
|
}
|
||||||
|
|
||||||
// NOTE: The last modified date needs to be updated before calling these methods
|
// 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) {
|
pub fn send_user_update(&self, ut: UpdateType, user: &User) {
|
||||||
let data = create_update(
|
let data = create_update(
|
||||||
vec![
|
vec![
|
||||||
|
@ -325,6 +324,7 @@ fn create_ping() -> Vec<u8> {
|
||||||
}
|
}
|
||||||
|
|
||||||
#[allow(dead_code)]
|
#[allow(dead_code)]
|
||||||
|
#[derive(PartialEq)]
|
||||||
pub enum UpdateType {
|
pub enum UpdateType {
|
||||||
CipherUpdate = 0,
|
CipherUpdate = 0,
|
||||||
CipherCreate = 1,
|
CipherCreate = 1,
|
||||||
|
@ -340,6 +340,8 @@ pub enum UpdateType {
|
||||||
SyncSettings = 10,
|
SyncSettings = 10,
|
||||||
|
|
||||||
LogOut = 11,
|
LogOut = 11,
|
||||||
|
|
||||||
|
None = 100,
|
||||||
}
|
}
|
||||||
|
|
||||||
use rocket::State;
|
use rocket::State;
|
||||||
|
|
|
@ -196,40 +196,28 @@ impl Cipher {
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn move_to_folder(&self, folder_uuid: Option<String>, user_uuid: &str, conn: &DbConn) -> EmptyResult {
|
pub fn move_to_folder(&self, folder_uuid: Option<String>, user_uuid: &str, conn: &DbConn) -> EmptyResult {
|
||||||
match self.get_folder_uuid(&user_uuid, &conn) {
|
User::update_uuid_revision(user_uuid, &conn);
|
||||||
None => {
|
|
||||||
match folder_uuid {
|
match (self.get_folder_uuid(&user_uuid, &conn), folder_uuid) {
|
||||||
Some(new_folder) => {
|
// No changes
|
||||||
self.update_users_revision(conn);
|
(None, None) => Ok(()),
|
||||||
let folder_cipher = FolderCipher::new(&new_folder, &self.uuid);
|
(Some(ref old), Some(ref new)) if old == new => Ok(()),
|
||||||
folder_cipher.save(&conn)
|
|
||||||
}
|
// Add to folder
|
||||||
None => Ok(()), //nothing to do
|
(None, Some(new)) => FolderCipher::new(&new, &self.uuid).save(&conn),
|
||||||
}
|
|
||||||
}
|
// Remove from folder
|
||||||
Some(current_folder) => {
|
(Some(old), None) => match FolderCipher::find_by_folder_and_cipher(&old, &self.uuid, &conn) {
|
||||||
match folder_uuid {
|
Some(old) => old.delete(&conn),
|
||||||
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"),
|
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)
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -241,7 +241,9 @@ impl CollectionUser {
|
||||||
pub fn delete_all_by_collection(collection_uuid: &str, conn: &DbConn) -> EmptyResult {
|
pub fn delete_all_by_collection(collection_uuid: &str, conn: &DbConn) -> EmptyResult {
|
||||||
CollectionUser::find_by_collection(&collection_uuid, conn)
|
CollectionUser::find_by_collection(&collection_uuid, conn)
|
||||||
.iter()
|
.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)))
|
diesel::delete(users_collections::table.filter(users_collections::collection_uuid.eq(collection_uuid)))
|
||||||
.execute(&**conn)
|
.execute(&**conn)
|
||||||
|
|
|
@ -172,12 +172,14 @@ impl User {
|
||||||
.map_res("Error deleting 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 let Some(mut user) = User::find_by_uuid(&uuid, conn) {
|
||||||
if user.update_revision(conn).is_err() {
|
if user.update_revision(conn).is_err() {
|
||||||
warn!("Failed to update revision for {}", user.email);
|
warn!("Failed to update revision for {}", user.email);
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
|
vec![uuid.to_string()]
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn update_revision(&mut self, conn: &DbConn) -> EmptyResult {
|
pub fn update_revision(&mut self, conn: &DbConn) -> EmptyResult {
|
||||||
|
|
Loading…
Reference in a new issue