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:
Ursprung
92236394e6
Commit
0cb58add54
5 geänderte Dateien mit 108 neuen und 64 gelöschten Zeilen
|
@ -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)
|
||||||
|
|
|
@ -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,
|
||||||
|
|
|
@ -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());
|
|
||||||
|
new_user.access_all = data.accessAll;
|
||||||
if 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, ¤t_user.uuid, &conn) {
|
||||||
} else {
|
CollectionUsers::delete(¤t_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(¤t_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, ¤t_user.uuid, &conn) {
|
||||||
|
CollectionUsers::delete(¤t_user.uuid, &c.uuid, &conn);
|
||||||
|
}
|
||||||
|
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
|
@ -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
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
|
@ -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,
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
Laden …
In neuem Issue referenzieren