1
0
Fork 1
Spiegel von https://github.com/dani-garcia/vaultwarden.git synchronisiert 2024-11-22 05:10:29 +01:00

Implemented some admin methods, inserted CollectionsUsers only when Org accessAll == false, and implemented find_collection when user has access_all in Org

Dieser Commit ist enthalten in:
Daniel García 2018-05-04 19:25:50 +02:00
Ursprung 92236394e6
Commit 0cb58add54
5 geänderte Dateien mit 108 neuen und 64 gelöschten Zeilen

Datei anzeigen

@ -69,6 +69,12 @@ fn get_cipher(uuid: String, headers: Headers, conn: DbConn) -> JsonResult {
Ok(Json(cipher.to_json(&headers.host, &headers.user.uuid, &conn))) Ok(Json(cipher.to_json(&headers.host, &headers.user.uuid, &conn)))
} }
#[get("/ciphers/<uuid>/admin")]
fn get_cipher_admin(uuid: String, headers: Headers, conn: DbConn) -> JsonResult {
// TODO: Implement this correctly
get_cipher(uuid, headers, conn)
}
#[derive(Deserialize, Debug)] #[derive(Deserialize, Debug)]
#[allow(non_snake_case)] #[allow(non_snake_case)]
struct CipherData { struct CipherData {
@ -100,6 +106,7 @@ struct CipherData {
#[post("/ciphers/admin", data = "<data>")] #[post("/ciphers/admin", data = "<data>")]
fn post_ciphers_admin(data: Json<CipherData>, headers: Headers, conn: DbConn) -> JsonResult { fn post_ciphers_admin(data: Json<CipherData>, headers: Headers, conn: DbConn) -> JsonResult {
// TODO: Implement this correctly
post_ciphers(data, headers, conn) post_ciphers(data, headers, conn)
} }
@ -230,8 +237,8 @@ fn post_ciphers_import(data: Json<ImportData>, headers: Headers, conn: DbConn) -
let data: ImportData = data.into_inner(); let data: ImportData = data.into_inner();
// Read and create the folders // Read and create the folders
let folders: Vec<_> = data.folders.iter().map(|folder| { let folders: Vec<_> = data.folders.into_iter().map(|folder| {
let mut folder = Folder::new(headers.user.uuid.clone(), folder.name.clone()); let mut folder = Folder::new(headers.user.uuid.clone(), folder.name);
folder.save(&conn); folder.save(&conn);
folder folder
}).collect(); }).collect();
@ -261,6 +268,12 @@ fn post_ciphers_import(data: Json<ImportData>, headers: Headers, conn: DbConn) -
Ok(()) Ok(())
} }
#[post("/ciphers/<uuid>/admin", data = "<data>")]
fn post_cipher_admin(uuid: String, data: Json<CipherData>, headers: Headers, conn: DbConn) -> JsonResult {
// TODO: Implement this correctly
post_cipher(uuid, data, headers, conn)
}
#[post("/ciphers/<uuid>", data = "<data>")] #[post("/ciphers/<uuid>", data = "<data>")]
fn post_cipher(uuid: String, data: Json<CipherData>, headers: Headers, conn: DbConn) -> JsonResult { fn post_cipher(uuid: String, data: Json<CipherData>, headers: Headers, conn: DbConn) -> JsonResult {
put_cipher(uuid, data, headers, conn) put_cipher(uuid, data, headers, conn)

Datei anzeigen

@ -26,12 +26,14 @@ pub fn routes() -> Vec<Route> {
get_ciphers, get_ciphers,
get_cipher, get_cipher,
get_cipher_admin,
post_ciphers, post_ciphers,
post_ciphers_admin, post_ciphers_admin,
post_ciphers_import, post_ciphers_import,
post_attachment, post_attachment,
delete_attachment_post, delete_attachment_post,
delete_attachment, delete_attachment,
post_cipher_admin,
post_cipher, post_cipher,
put_cipher, put_cipher,
delete_cipher_post, delete_cipher_post,

Datei anzeigen

@ -5,7 +5,7 @@ use rocket_contrib::{Json, Value};
use db::DbConn; use db::DbConn;
use db::models::*; use db::models::*;
use api::{PasswordData, JsonResult, EmptyResult}; use api::{PasswordData, JsonResult, EmptyResult, NumberOrString};
use auth::Headers; use auth::Headers;
@ -41,10 +41,6 @@ fn create_organization(headers: Headers, data: Json<OrgData>, conn: DbConn) -> J
headers.user.uuid.clone(), org.uuid.clone()); headers.user.uuid.clone(), org.uuid.clone());
let mut collection = Collection::new( let mut collection = Collection::new(
org.uuid.clone(), data.collectionName); org.uuid.clone(), data.collectionName);
let mut collection_user = CollectionUsers::new(
headers.user.uuid.clone(),
collection.uuid.clone(),
);
user_org.key = data.key; user_org.key = data.key;
user_org.access_all = true; user_org.access_all = true;
@ -54,7 +50,6 @@ fn create_organization(headers: Headers, data: Json<OrgData>, conn: DbConn) -> J
org.save(&conn); org.save(&conn);
user_org.save(&conn); user_org.save(&conn);
collection.save(&conn); collection.save(&conn);
collection_user.save(&conn);
Ok(Json(org.to_json())) Ok(Json(org.to_json()))
} }
@ -64,6 +59,8 @@ fn delete_organization(org_id: String, data: Json<PasswordData>, headers: Header
let data: PasswordData = data.into_inner(); let data: PasswordData = data.into_inner();
let password_hash = data.masterPasswordHash; let password_hash = data.masterPasswordHash;
// TODO: Delete ciphers from organization, collection_users, collections, organization_users and the org itself
unimplemented!() unimplemented!()
} }
@ -109,7 +106,6 @@ fn get_user_collections(headers: Headers, conn: DbConn) -> JsonResult {
Ok(Json(json!({ Ok(Json(json!({
"Data": "Data":
Collection::find_by_user_uuid(&headers.user.uuid, &conn) Collection::find_by_user_uuid(&headers.user.uuid, &conn)
.expect("Error loading collections")
.iter() .iter()
.map(|collection| { .map(|collection| {
collection.to_json() collection.to_json()
@ -123,7 +119,6 @@ fn get_org_collections(org_id: String, headers: Headers, conn: DbConn) -> JsonRe
Ok(Json(json!({ Ok(Json(json!({
"Data": "Data":
Collection::find_by_organization_and_user_uuid(&org_id, &headers.user.uuid, &conn) Collection::find_by_organization_and_user_uuid(&org_id, &headers.user.uuid, &conn)
.unwrap_or(vec![])
.iter() .iter()
.map(|collection| { .map(|collection| {
collection.to_json() collection.to_json()
@ -136,10 +131,12 @@ fn get_org_collections(org_id: String, headers: Headers, conn: DbConn) -> JsonRe
fn post_organization_collections(org_id: String, headers: Headers, data: Json<NewCollectionData>, conn: DbConn) -> JsonResult { fn post_organization_collections(org_id: String, headers: Headers, data: Json<NewCollectionData>, conn: DbConn) -> JsonResult {
let data: NewCollectionData = data.into_inner(); let data: NewCollectionData = data.into_inner();
match UserOrganization::find_by_user_and_org( &headers.user.uuid, &org_id, &conn) { let org_user = match UserOrganization::find_by_user_and_org( &headers.user.uuid, &org_id, &conn) {
None => err!("User not in Organization or Organization doesn't exist"), None => err!("User not in Organization or Organization doesn't exist"),
Some(org_user) => if org_user.type_ > 1 { // not owner or admin Some(org_user) => if org_user.type_ == UserOrgType::User as i32 {
err!("Only Organization owner and admin can add Collection") err!("Only Organization owner and admin can add Collection")
} else {
org_user
} }
}; };
@ -149,13 +146,12 @@ fn post_organization_collections(org_id: String, headers: Headers, data: Json<Ne
}; };
let mut collection = Collection::new(org.uuid.clone(), data.name); let mut collection = Collection::new(org.uuid.clone(), data.name);
let mut collection_user = CollectionUsers::new(
headers.user.uuid.clone(),
collection.uuid.clone(),
);
collection.save(&conn); collection.save(&conn);
collection_user.save(&conn);
if !org_user.access_all {
CollectionUsers::save(&headers.user.uuid, &collection.uuid, &conn);
}
Ok(Json(collection.to_json())) Ok(Json(collection.to_json()))
} }
@ -267,7 +263,7 @@ struct CollectionData {
struct InviteData { struct InviteData {
emails: Vec<String>, emails: Vec<String>,
#[serde(rename = "type")] #[serde(rename = "type")]
type_: String, type_: NumberOrString,
collections: Vec<CollectionData>, collections: Vec<CollectionData>,
accessAll: bool, accessAll: bool,
} }
@ -285,7 +281,7 @@ fn send_invite(org_id: String, data: Json<InviteData>, headers: Headers, conn: D
err!("Users can't invite other people. Ask an Admin or Owner") err!("Users can't invite other people. Ask an Admin or Owner")
} }
let new_type = match UserOrgType::from_str(data.type_.as_ref()) { let new_type = match UserOrgType::from_str(&data.type_.to_string()) {
Some(new_type) => new_type as i32, Some(new_type) => new_type as i32,
None => err!("Invalid type") None => err!("Invalid type")
}; };
@ -304,18 +300,21 @@ fn send_invite(org_id: String, data: Json<InviteData>, headers: Headers, conn: D
None => () None => ()
} }
let mut new_user = UserOrganization::new( let mut new_user = UserOrganization::new(user.uuid, org_id.clone());
user.uuid, org_id.clone());
if data.accessAll {
new_user.access_all = data.accessAll; new_user.access_all = data.accessAll;
} else {
err!("Select collections unimplemented")
// TODO create Users_collections
}
new_user.type_ = new_type; new_user.type_ = new_type;
// If no accessAll, add the collections received
if !data.accessAll {
for collection in data.collections.iter() {
// TODO: Check that collection is in org
// TODO: Save the readOnly bit
CollectionUsers::save(&headers.user.uuid, &collection.id, &conn);
}
}
new_user.save(&conn); new_user.save(&conn);
} }
} }
@ -381,7 +380,7 @@ fn get_user(org_id: String, user_id: String, headers: Headers, conn: DbConn) ->
#[allow(non_snake_case)] #[allow(non_snake_case)]
struct EditUserData { struct EditUserData {
#[serde(rename = "type")] #[serde(rename = "type")]
type_: String, type_: NumberOrString,
collections: Vec<CollectionData>, collections: Vec<CollectionData>,
accessAll: bool, accessAll: bool,
} }
@ -396,7 +395,7 @@ fn edit_user(org_id: String, user_id: String, data: Json<EditUserData>, headers:
None => err!("The current user isn't member of the organization") None => err!("The current user isn't member of the organization")
}; };
let new_type = match UserOrgType::from_str(data.type_.as_ref()) { let new_type = match UserOrgType::from_str(&data.type_.to_string()) {
Some(new_type) => new_type as i32, Some(new_type) => new_type as i32,
None => err!("Invalid type") None => err!("Invalid type")
}; };
@ -436,10 +435,19 @@ fn edit_user(org_id: String, user_id: String, data: Json<EditUserData>, headers:
user_to_edit.access_all = data.accessAll; user_to_edit.access_all = data.accessAll;
user_to_edit.type_ = new_type; user_to_edit.type_ = new_type;
if data.accessAll { // Delete all the odd collections
// Remove users_collections if there is any for c in Collection::find_by_organization_and_user_uuid(&org_id, &current_user.uuid, &conn) {
} else { CollectionUsers::delete(&current_user.uuid, &c.uuid, &conn);
// TODO create users_collections }
// If no accessAll, add the collections received
if !data.accessAll {
for collection in data.collections.iter() {
// TODO: Check that collection is in org
// TODO: Save the readOnly bit
CollectionUsers::save(&current_user.uuid, &collection.id, &conn);
}
} }
user_to_edit.save(&conn); user_to_edit.save(&conn);
@ -482,7 +490,9 @@ fn delete_user(org_id: String, user_id: String, headers: Headers, conn: DbConn)
user_to_delete.delete(&conn); user_to_delete.delete(&conn);
// TODO Delete users_collections from this org for c in Collection::find_by_organization_and_user_uuid(&org_id, &current_user.uuid, &conn) {
CollectionUsers::delete(&current_user.uuid, &c.uuid, &conn);
}
Ok(()) Ok(())
} }

Datei anzeigen

@ -21,3 +21,19 @@ type EmptyResult = Result<(), BadRequest<Json>>;
struct PasswordData { struct PasswordData {
masterPasswordHash: String masterPasswordHash: String
} }
#[derive(Deserialize)]
#[serde(untagged)]
enum NumberOrString {
Number(i32),
String(String),
}
impl NumberOrString {
fn to_string(self) -> String {
match self {
NumberOrString::Number(n) => n.to_string(),
NumberOrString::String(s) => s
}
}
}

Datei anzeigen

@ -38,7 +38,7 @@ impl Collection {
use diesel; use diesel;
use diesel::prelude::*; use diesel::prelude::*;
use db::DbConn; use db::DbConn;
use db::schema::collections; use db::schema::*;
/// Database methods /// Database methods
impl Collection { impl Collection {
@ -66,19 +66,25 @@ impl Collection {
.first::<Self>(&**conn).ok() .first::<Self>(&**conn).ok()
} }
pub fn find_by_user_uuid(user_uuid: &str, conn: &DbConn) -> Option<Vec<Self>> { pub fn find_by_user_uuid(user_uuid: &str, conn: &DbConn) -> Vec<Self> {
users_collections::table.inner_join(collections::table) let mut all_access_collections = users_organizations::table
.filter(users_organizations::user_uuid.eq(user_uuid))
.filter(users_organizations::access_all.eq(true))
.inner_join(collections::table.on(collections::org_uuid.eq(users_organizations::org_uuid)))
.select(collections::all_columns)
.load::<Self>(&**conn).expect("Error loading collections");
let mut assigned_collections = users_collections::table.inner_join(collections::table)
.filter(users_collections::user_uuid.eq(user_uuid)) .filter(users_collections::user_uuid.eq(user_uuid))
.select(collections::all_columns) .select(collections::all_columns)
.load::<Self>(&**conn).ok() .load::<Self>(&**conn).expect("Error loading collections");
all_access_collections.append(&mut assigned_collections);
all_access_collections
} }
pub fn find_by_organization_and_user_uuid(org_uuid: &str, user_uuid: &str, conn: &DbConn) -> Option<Vec<Self>> { pub fn find_by_organization_and_user_uuid(org_uuid: &str, user_uuid: &str, conn: &DbConn) -> Vec<Self> {
users_collections::table.inner_join(collections::table) Self::find_by_user_uuid(user_uuid, conn).into_iter().filter(|c| c.org_uuid == org_uuid).collect()
.filter(users_collections::user_uuid.eq(user_uuid))
.filter(collections::org_uuid.eq(org_uuid))
.select(collections::all_columns)
.load::<Self>(&**conn).ok()
} }
pub fn find_by_uuid_and_user(uuid: &str, user_uuid: &str, conn: &DbConn) -> Option<Self> { pub fn find_by_uuid_and_user(uuid: &str, user_uuid: &str, conn: &DbConn) -> Option<Self> {
@ -102,29 +108,26 @@ pub struct CollectionUsers {
pub collection_uuid: String, pub collection_uuid: String,
} }
/// Local methods
impl CollectionUsers {
pub fn new(
user_uuid: String,
collection_uuid: String,
) -> Self {
Self {
user_uuid,
collection_uuid,
}
}
}
use db::schema::users_collections;
/// Database methods /// Database methods
impl CollectionUsers { impl CollectionUsers {
pub fn save(&mut self, conn: &DbConn) -> bool { pub fn save(user_uuid: &str, collection_uuid: &str, conn: &DbConn) -> bool {
match diesel::replace_into(users_collections::table) match diesel::replace_into(users_collections::table)
.values(&*self) .values((
.execute(&**conn) { users_collections::user_uuid.eq(user_uuid),
users_collections::collection_uuid.eq(collection_uuid)
)).execute(&**conn) {
Ok(1) => true, // One row inserted Ok(1) => true, // One row inserted
_ => false, _ => false,
} }
} }
pub fn delete(user_uuid: &str, collection_uuid: &str, conn: &DbConn) -> bool {
match diesel::delete(users_collections::table
.filter(users_collections::user_uuid.eq(user_uuid))
.filter(users_collections::collection_uuid.eq(collection_uuid)))
.execute(&**conn) {
Ok(1) => true, // One row deleted
_ => false,
}
}
} }