mirror of
https://github.com/dani-garcia/vaultwarden.git
synced 2024-11-22 15:16:46 +01:00
Implemented some admin methods, inserted CollectionsUsers only when Org accessAll == false, and implemented find_collection when user has access_all in Org
This commit is contained in:
parent
92236394e6
commit
0cb58add54
5 changed files with 108 additions and 64 deletions
|
@ -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)))
|
||||
}
|
||||
|
||||
#[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)]
|
||||
#[allow(non_snake_case)]
|
||||
struct CipherData {
|
||||
|
@ -100,6 +106,7 @@ struct CipherData {
|
|||
|
||||
#[post("/ciphers/admin", data = "<data>")]
|
||||
fn post_ciphers_admin(data: Json<CipherData>, headers: Headers, conn: DbConn) -> JsonResult {
|
||||
// TODO: Implement this correctly
|
||||
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();
|
||||
|
||||
// Read and create the folders
|
||||
let folders: Vec<_> = data.folders.iter().map(|folder| {
|
||||
let mut folder = Folder::new(headers.user.uuid.clone(), folder.name.clone());
|
||||
let folders: Vec<_> = data.folders.into_iter().map(|folder| {
|
||||
let mut folder = Folder::new(headers.user.uuid.clone(), folder.name);
|
||||
folder.save(&conn);
|
||||
folder
|
||||
}).collect();
|
||||
|
@ -261,6 +268,12 @@ fn post_ciphers_import(data: Json<ImportData>, headers: Headers, conn: DbConn) -
|
|||
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>")]
|
||||
fn post_cipher(uuid: String, data: Json<CipherData>, headers: Headers, conn: DbConn) -> JsonResult {
|
||||
put_cipher(uuid, data, headers, conn)
|
||||
|
|
|
@ -26,12 +26,14 @@ pub fn routes() -> Vec<Route> {
|
|||
|
||||
get_ciphers,
|
||||
get_cipher,
|
||||
get_cipher_admin,
|
||||
post_ciphers,
|
||||
post_ciphers_admin,
|
||||
post_ciphers_import,
|
||||
post_attachment,
|
||||
delete_attachment_post,
|
||||
delete_attachment,
|
||||
post_cipher_admin,
|
||||
post_cipher,
|
||||
put_cipher,
|
||||
delete_cipher_post,
|
||||
|
|
|
@ -5,7 +5,7 @@ use rocket_contrib::{Json, Value};
|
|||
use db::DbConn;
|
||||
use db::models::*;
|
||||
|
||||
use api::{PasswordData, JsonResult, EmptyResult};
|
||||
use api::{PasswordData, JsonResult, EmptyResult, NumberOrString};
|
||||
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());
|
||||
let mut collection = Collection::new(
|
||||
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.access_all = true;
|
||||
|
@ -54,7 +50,6 @@ fn create_organization(headers: Headers, data: Json<OrgData>, conn: DbConn) -> J
|
|||
org.save(&conn);
|
||||
user_org.save(&conn);
|
||||
collection.save(&conn);
|
||||
collection_user.save(&conn);
|
||||
|
||||
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 password_hash = data.masterPasswordHash;
|
||||
|
||||
// TODO: Delete ciphers from organization, collection_users, collections, organization_users and the org itself
|
||||
|
||||
unimplemented!()
|
||||
}
|
||||
|
||||
|
@ -109,7 +106,6 @@ fn get_user_collections(headers: Headers, conn: DbConn) -> JsonResult {
|
|||
Ok(Json(json!({
|
||||
"Data":
|
||||
Collection::find_by_user_uuid(&headers.user.uuid, &conn)
|
||||
.expect("Error loading collections")
|
||||
.iter()
|
||||
.map(|collection| {
|
||||
collection.to_json()
|
||||
|
@ -123,7 +119,6 @@ fn get_org_collections(org_id: String, headers: Headers, conn: DbConn) -> JsonRe
|
|||
Ok(Json(json!({
|
||||
"Data":
|
||||
Collection::find_by_organization_and_user_uuid(&org_id, &headers.user.uuid, &conn)
|
||||
.unwrap_or(vec![])
|
||||
.iter()
|
||||
.map(|collection| {
|
||||
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 {
|
||||
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"),
|
||||
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")
|
||||
} 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_user = CollectionUsers::new(
|
||||
headers.user.uuid.clone(),
|
||||
collection.uuid.clone(),
|
||||
);
|
||||
|
||||
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()))
|
||||
}
|
||||
|
@ -267,7 +263,7 @@ struct CollectionData {
|
|||
struct InviteData {
|
||||
emails: Vec<String>,
|
||||
#[serde(rename = "type")]
|
||||
type_: String,
|
||||
type_: NumberOrString,
|
||||
collections: Vec<CollectionData>,
|
||||
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")
|
||||
}
|
||||
|
||||
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,
|
||||
None => err!("Invalid type")
|
||||
};
|
||||
|
@ -304,18 +300,21 @@ fn send_invite(org_id: String, data: Json<InviteData>, headers: Headers, conn: D
|
|||
None => ()
|
||||
}
|
||||
|
||||
let mut new_user = UserOrganization::new(
|
||||
user.uuid, org_id.clone());
|
||||
|
||||
if data.accessAll {
|
||||
new_user.access_all = data.accessAll;
|
||||
} else {
|
||||
err!("Select collections unimplemented")
|
||||
// TODO create Users_collections
|
||||
}
|
||||
|
||||
let mut new_user = UserOrganization::new(user.uuid, org_id.clone());
|
||||
|
||||
new_user.access_all = data.accessAll;
|
||||
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);
|
||||
}
|
||||
}
|
||||
|
@ -381,7 +380,7 @@ fn get_user(org_id: String, user_id: String, headers: Headers, conn: DbConn) ->
|
|||
#[allow(non_snake_case)]
|
||||
struct EditUserData {
|
||||
#[serde(rename = "type")]
|
||||
type_: String,
|
||||
type_: NumberOrString,
|
||||
collections: Vec<CollectionData>,
|
||||
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")
|
||||
};
|
||||
|
||||
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,
|
||||
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.type_ = new_type;
|
||||
|
||||
if data.accessAll {
|
||||
// Remove users_collections if there is any
|
||||
} else {
|
||||
// TODO create users_collections
|
||||
// Delete all the odd collections
|
||||
for c in Collection::find_by_organization_and_user_uuid(&org_id, ¤t_user.uuid, &conn) {
|
||||
CollectionUsers::delete(¤t_user.uuid, &c.uuid, &conn);
|
||||
}
|
||||
|
||||
// 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(¤t_user.uuid, &collection.id, &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);
|
||||
|
||||
// TODO Delete users_collections from this org
|
||||
for c in Collection::find_by_organization_and_user_uuid(&org_id, ¤t_user.uuid, &conn) {
|
||||
CollectionUsers::delete(¤t_user.uuid, &c.uuid, &conn);
|
||||
}
|
||||
|
||||
Ok(())
|
||||
}
|
|
@ -21,3 +21,19 @@ type EmptyResult = Result<(), BadRequest<Json>>;
|
|||
struct PasswordData {
|
||||
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
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -38,7 +38,7 @@ impl Collection {
|
|||
use diesel;
|
||||
use diesel::prelude::*;
|
||||
use db::DbConn;
|
||||
use db::schema::collections;
|
||||
use db::schema::*;
|
||||
|
||||
/// Database methods
|
||||
impl Collection {
|
||||
|
@ -66,19 +66,25 @@ impl Collection {
|
|||
.first::<Self>(&**conn).ok()
|
||||
}
|
||||
|
||||
pub fn find_by_user_uuid(user_uuid: &str, conn: &DbConn) -> Option<Vec<Self>> {
|
||||
users_collections::table.inner_join(collections::table)
|
||||
pub fn find_by_user_uuid(user_uuid: &str, conn: &DbConn) -> Vec<Self> {
|
||||
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))
|
||||
.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>> {
|
||||
users_collections::table.inner_join(collections::table)
|
||||
.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_organization_and_user_uuid(org_uuid: &str, user_uuid: &str, conn: &DbConn) -> Vec<Self> {
|
||||
Self::find_by_user_uuid(user_uuid, conn).into_iter().filter(|c| c.org_uuid == org_uuid).collect()
|
||||
}
|
||||
|
||||
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,
|
||||
}
|
||||
|
||||
/// 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
|
||||
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)
|
||||
.values(&*self)
|
||||
.execute(&**conn) {
|
||||
.values((
|
||||
users_collections::user_uuid.eq(user_uuid),
|
||||
users_collections::collection_uuid.eq(collection_uuid)
|
||||
)).execute(&**conn) {
|
||||
Ok(1) => true, // One row inserted
|
||||
_ => 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,
|
||||
}
|
||||
}
|
||||
}
|
Loading…
Reference in a new issue