Spiegel von
https://github.com/dani-garcia/vaultwarden.git
synchronisiert 2024-12-18 10:40:42 +01:00
Some refactoring and optimizations (#5291)
- Refactored several code to use more modern syntax - Made some checks a bit more strict - Updated crates Signed-off-by: BlackDex <black.dex@gmail.com>
Dieser Commit ist enthalten in:
Ursprung
fd51230044
Commit
9cd400db6c
23 geänderte Dateien mit 414 neuen und 594 gelöschten Zeilen
36
Cargo.lock
generiert
36
Cargo.lock
generiert
|
@ -489,9 +489,9 @@ checksum = "ade8366b8bd5ba243f0a58f036cc0ca8a2f069cff1a2351ef1cac6b083e16fc0"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "cc"
|
name = "cc"
|
||||||
version = "1.2.3"
|
version = "1.2.4"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "27f657647bcff5394bf56c7317665bbf790a137a50eaaa5c6bfbb9e27a518f2d"
|
checksum = "9157bbaa6b165880c27a4293a474c91cdcf265cc68cc829bf10be0964a391caf"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"shlex",
|
"shlex",
|
||||||
]
|
]
|
||||||
|
@ -1524,7 +1524,7 @@ dependencies = [
|
||||||
"http 1.2.0",
|
"http 1.2.0",
|
||||||
"hyper 1.5.1",
|
"hyper 1.5.1",
|
||||||
"hyper-util",
|
"hyper-util",
|
||||||
"rustls 0.23.19",
|
"rustls 0.23.20",
|
||||||
"rustls-pki-types",
|
"rustls-pki-types",
|
||||||
"tokio",
|
"tokio",
|
||||||
"tokio-rustls 0.26.1",
|
"tokio-rustls 0.26.1",
|
||||||
|
@ -2618,9 +2618,9 @@ dependencies = [
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "quanta"
|
name = "quanta"
|
||||||
version = "0.12.3"
|
version = "0.12.4"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "8e5167a477619228a0b284fac2674e3c388cba90631d7b7de620e6f1fcd08da5"
|
checksum = "773ce68d0bb9bc7ef20be3536ffe94e223e1f365bd374108b2659fac0c65cfe6"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"crossbeam-utils",
|
"crossbeam-utils",
|
||||||
"libc",
|
"libc",
|
||||||
|
@ -2704,9 +2704,9 @@ dependencies = [
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "redox_syscall"
|
name = "redox_syscall"
|
||||||
version = "0.5.7"
|
version = "0.5.8"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "9b6dfecf2c74bce2466cabf93f6664d6998a69eb21e39f4207930065b27b771f"
|
checksum = "03a862b389f93e68874fbf580b9de08dd02facb9a788ebadaf4a3fd33cf58834"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"bitflags",
|
"bitflags",
|
||||||
]
|
]
|
||||||
|
@ -3031,9 +3031,9 @@ dependencies = [
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "rustls"
|
name = "rustls"
|
||||||
version = "0.23.19"
|
version = "0.23.20"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "934b404430bb06b3fae2cba809eb45a1ab1aecd64491213d7c3301b88393f8d1"
|
checksum = "5065c3f250cbd332cd894be57c40fa52387247659b14a2d6041d121547903b1b"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"once_cell",
|
"once_cell",
|
||||||
"rustls-pki-types",
|
"rustls-pki-types",
|
||||||
|
@ -3062,9 +3062,9 @@ dependencies = [
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "rustls-pki-types"
|
name = "rustls-pki-types"
|
||||||
version = "1.10.0"
|
version = "1.10.1"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "16f1201b3c9a7ee8039bcadc17b7e605e2945b27eee7631788c1bd2b0643674b"
|
checksum = "d2bf47e6ff922db3825eb750c4e2ff784c6ff8fb9e13046ef6a1d1c5401b0b37"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "rustls-webpki"
|
name = "rustls-webpki"
|
||||||
|
@ -3173,15 +3173,15 @@ dependencies = [
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "semver"
|
name = "semver"
|
||||||
version = "1.0.23"
|
version = "1.0.24"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "61697e0a1c7e512e84a621326239844a24d8207b4669b41bc18b32ea5cbf988b"
|
checksum = "3cb6eb87a131f756572d7fb904f6e7b68633f09cca868c5df1c4b8d1a694bbba"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "serde"
|
name = "serde"
|
||||||
version = "1.0.215"
|
version = "1.0.216"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "6513c1ad0b11a9376da888e3e0baa0077f1aed55c17f50e7b2397136129fb88f"
|
checksum = "0b9781016e935a97e8beecf0c933758c97a5520d32930e460142b4cd80c6338e"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"serde_derive",
|
"serde_derive",
|
||||||
]
|
]
|
||||||
|
@ -3198,9 +3198,9 @@ dependencies = [
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "serde_derive"
|
name = "serde_derive"
|
||||||
version = "1.0.215"
|
version = "1.0.216"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "ad1e866f866923f252f05c889987993144fb74e722403468a4ebd70c3cd756c0"
|
checksum = "46f859dbbf73865c6627ed570e78961cd3ac92407a2d117204c49232485da55e"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"proc-macro2",
|
"proc-macro2",
|
||||||
"quote",
|
"quote",
|
||||||
|
@ -3652,7 +3652,7 @@ version = "0.26.1"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "5f6d0975eaace0cf0fcadee4e4aaa5da15b5c079146f2cffb67c113be122bf37"
|
checksum = "5f6d0975eaace0cf0fcadee4e4aaa5da15b5c079146f2cffb67c113be122bf37"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"rustls 0.23.19",
|
"rustls 0.23.20",
|
||||||
"tokio",
|
"tokio",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
|
|
@ -495,10 +495,10 @@ struct UserOrgTypeData {
|
||||||
async fn update_user_org_type(data: Json<UserOrgTypeData>, token: AdminToken, mut conn: DbConn) -> EmptyResult {
|
async fn update_user_org_type(data: Json<UserOrgTypeData>, token: AdminToken, mut conn: DbConn) -> EmptyResult {
|
||||||
let data: UserOrgTypeData = data.into_inner();
|
let data: UserOrgTypeData = data.into_inner();
|
||||||
|
|
||||||
let mut user_to_edit =
|
let Some(mut user_to_edit) =
|
||||||
match UserOrganization::find_by_user_and_org(&data.user_uuid, &data.org_uuid, &mut conn).await {
|
UserOrganization::find_by_user_and_org(&data.user_uuid, &data.org_uuid, &mut conn).await
|
||||||
Some(user) => user,
|
else {
|
||||||
None => err!("The specified user isn't member of the organization"),
|
err!("The specified user isn't member of the organization")
|
||||||
};
|
};
|
||||||
|
|
||||||
let new_type = match UserOrgType::from_str(&data.user_type.into_string()) {
|
let new_type = match UserOrgType::from_str(&data.user_type.into_string()) {
|
||||||
|
@ -602,9 +602,8 @@ async fn get_json_api<T: DeserializeOwned>(url: &str) -> Result<T, Error> {
|
||||||
}
|
}
|
||||||
|
|
||||||
async fn has_http_access() -> bool {
|
async fn has_http_access() -> bool {
|
||||||
let req = match make_http_request(Method::HEAD, "https://github.com/dani-garcia/vaultwarden") {
|
let Ok(req) = make_http_request(Method::HEAD, "https://github.com/dani-garcia/vaultwarden") else {
|
||||||
Ok(r) => r,
|
return false;
|
||||||
Err(_) => return false,
|
|
||||||
};
|
};
|
||||||
match req.send().await {
|
match req.send().await {
|
||||||
Ok(r) => r.status().is_success(),
|
Ok(r) => r.status().is_success(),
|
||||||
|
|
|
@ -574,9 +574,8 @@ async fn post_rotatekey(data: Json<KeyData>, headers: Headers, mut conn: DbConn,
|
||||||
// Skip `null` folder id entries.
|
// Skip `null` folder id entries.
|
||||||
// See: https://github.com/bitwarden/clients/issues/8453
|
// See: https://github.com/bitwarden/clients/issues/8453
|
||||||
if let Some(folder_id) = folder_data.id {
|
if let Some(folder_id) = folder_data.id {
|
||||||
let saved_folder = match existing_folders.iter_mut().find(|f| f.uuid == folder_id) {
|
let Some(saved_folder) = existing_folders.iter_mut().find(|f| f.uuid == folder_id) else {
|
||||||
Some(folder) => folder,
|
err!("Folder doesn't exist")
|
||||||
None => err!("Folder doesn't exist"),
|
|
||||||
};
|
};
|
||||||
|
|
||||||
saved_folder.name = folder_data.name;
|
saved_folder.name = folder_data.name;
|
||||||
|
@ -586,10 +585,10 @@ async fn post_rotatekey(data: Json<KeyData>, headers: Headers, mut conn: DbConn,
|
||||||
|
|
||||||
// Update emergency access data
|
// Update emergency access data
|
||||||
for emergency_access_data in data.emergency_access_keys {
|
for emergency_access_data in data.emergency_access_keys {
|
||||||
let saved_emergency_access =
|
let Some(saved_emergency_access) =
|
||||||
match existing_emergency_access.iter_mut().find(|ea| ea.uuid == emergency_access_data.id) {
|
existing_emergency_access.iter_mut().find(|ea| ea.uuid == emergency_access_data.id)
|
||||||
Some(emergency_access) => emergency_access,
|
else {
|
||||||
None => err!("Emergency access doesn't exist or is not owned by the user"),
|
err!("Emergency access doesn't exist or is not owned by the user")
|
||||||
};
|
};
|
||||||
|
|
||||||
saved_emergency_access.key_encrypted = Some(emergency_access_data.key_encrypted);
|
saved_emergency_access.key_encrypted = Some(emergency_access_data.key_encrypted);
|
||||||
|
@ -598,10 +597,10 @@ async fn post_rotatekey(data: Json<KeyData>, headers: Headers, mut conn: DbConn,
|
||||||
|
|
||||||
// Update reset password data
|
// Update reset password data
|
||||||
for reset_password_data in data.reset_password_keys {
|
for reset_password_data in data.reset_password_keys {
|
||||||
let user_org = match existing_user_orgs.iter_mut().find(|uo| uo.org_uuid == reset_password_data.organization_id)
|
let Some(user_org) =
|
||||||
{
|
existing_user_orgs.iter_mut().find(|uo| uo.org_uuid == reset_password_data.organization_id)
|
||||||
Some(reset_password) => reset_password,
|
else {
|
||||||
None => err!("Reset password doesn't exist"),
|
err!("Reset password doesn't exist")
|
||||||
};
|
};
|
||||||
|
|
||||||
user_org.reset_password_key = Some(reset_password_data.reset_password_key);
|
user_org.reset_password_key = Some(reset_password_data.reset_password_key);
|
||||||
|
@ -610,9 +609,8 @@ async fn post_rotatekey(data: Json<KeyData>, headers: Headers, mut conn: DbConn,
|
||||||
|
|
||||||
// Update send data
|
// Update send data
|
||||||
for send_data in data.sends {
|
for send_data in data.sends {
|
||||||
let send = match existing_sends.iter_mut().find(|s| &s.uuid == send_data.id.as_ref().unwrap()) {
|
let Some(send) = existing_sends.iter_mut().find(|s| &s.uuid == send_data.id.as_ref().unwrap()) else {
|
||||||
Some(send) => send,
|
err!("Send doesn't exist")
|
||||||
None => err!("Send doesn't exist"),
|
|
||||||
};
|
};
|
||||||
|
|
||||||
update_send_from_data(send, send_data, &headers, &mut conn, &nt, UpdateType::None).await?;
|
update_send_from_data(send, send_data, &headers, &mut conn, &nt, UpdateType::None).await?;
|
||||||
|
@ -623,9 +621,9 @@ async fn post_rotatekey(data: Json<KeyData>, headers: Headers, mut conn: DbConn,
|
||||||
|
|
||||||
for cipher_data in data.ciphers {
|
for cipher_data in data.ciphers {
|
||||||
if cipher_data.organization_id.is_none() {
|
if cipher_data.organization_id.is_none() {
|
||||||
let saved_cipher = match existing_ciphers.iter_mut().find(|c| &c.uuid == cipher_data.id.as_ref().unwrap()) {
|
let Some(saved_cipher) = existing_ciphers.iter_mut().find(|c| &c.uuid == cipher_data.id.as_ref().unwrap())
|
||||||
Some(cipher) => cipher,
|
else {
|
||||||
None => err!("Cipher doesn't exist"),
|
err!("Cipher doesn't exist")
|
||||||
};
|
};
|
||||||
|
|
||||||
// Prevent triggering cipher updates via WebSockets by settings UpdateType::None
|
// Prevent triggering cipher updates via WebSockets by settings UpdateType::None
|
||||||
|
@ -802,14 +800,12 @@ struct VerifyEmailTokenData {
|
||||||
async fn post_verify_email_token(data: Json<VerifyEmailTokenData>, mut conn: DbConn) -> EmptyResult {
|
async fn post_verify_email_token(data: Json<VerifyEmailTokenData>, mut conn: DbConn) -> EmptyResult {
|
||||||
let data: VerifyEmailTokenData = data.into_inner();
|
let data: VerifyEmailTokenData = data.into_inner();
|
||||||
|
|
||||||
let mut user = match User::find_by_uuid(&data.user_id, &mut conn).await {
|
let Some(mut user) = User::find_by_uuid(&data.user_id, &mut conn).await else {
|
||||||
Some(user) => user,
|
err!("User doesn't exist")
|
||||||
None => err!("User doesn't exist"),
|
|
||||||
};
|
};
|
||||||
|
|
||||||
let claims = match decode_verify_email(&data.token) {
|
let Ok(claims) = decode_verify_email(&data.token) else {
|
||||||
Ok(claims) => claims,
|
err!("Invalid claim")
|
||||||
Err(_) => err!("Invalid claim"),
|
|
||||||
};
|
};
|
||||||
if claims.sub != user.uuid {
|
if claims.sub != user.uuid {
|
||||||
err!("Invalid claim");
|
err!("Invalid claim");
|
||||||
|
@ -861,15 +857,14 @@ struct DeleteRecoverTokenData {
|
||||||
async fn post_delete_recover_token(data: Json<DeleteRecoverTokenData>, mut conn: DbConn) -> EmptyResult {
|
async fn post_delete_recover_token(data: Json<DeleteRecoverTokenData>, mut conn: DbConn) -> EmptyResult {
|
||||||
let data: DeleteRecoverTokenData = data.into_inner();
|
let data: DeleteRecoverTokenData = data.into_inner();
|
||||||
|
|
||||||
let user = match User::find_by_uuid(&data.user_id, &mut conn).await {
|
let Ok(claims) = decode_delete(&data.token) else {
|
||||||
Some(user) => user,
|
err!("Invalid claim")
|
||||||
None => err!("User doesn't exist"),
|
|
||||||
};
|
};
|
||||||
|
|
||||||
let claims = match decode_delete(&data.token) {
|
let Some(user) = User::find_by_uuid(&data.user_id, &mut conn).await else {
|
||||||
Ok(claims) => claims,
|
err!("User doesn't exist")
|
||||||
Err(_) => err!("Invalid claim"),
|
|
||||||
};
|
};
|
||||||
|
|
||||||
if claims.sub != user.uuid {
|
if claims.sub != user.uuid {
|
||||||
err!("Invalid claim");
|
err!("Invalid claim");
|
||||||
}
|
}
|
||||||
|
@ -1041,11 +1036,8 @@ impl<'r> FromRequest<'r> for KnownDevice {
|
||||||
|
|
||||||
async fn from_request(req: &'r Request<'_>) -> Outcome<Self, Self::Error> {
|
async fn from_request(req: &'r Request<'_>) -> Outcome<Self, Self::Error> {
|
||||||
let email = if let Some(email_b64) = req.headers().get_one("X-Request-Email") {
|
let email = if let Some(email_b64) = req.headers().get_one("X-Request-Email") {
|
||||||
let email_bytes = match data_encoding::BASE64URL_NOPAD.decode(email_b64.as_bytes()) {
|
let Ok(email_bytes) = data_encoding::BASE64URL_NOPAD.decode(email_b64.as_bytes()) else {
|
||||||
Ok(bytes) => bytes,
|
|
||||||
Err(_) => {
|
|
||||||
return Outcome::Error((Status::BadRequest, "X-Request-Email value failed to decode as base64url"));
|
return Outcome::Error((Status::BadRequest, "X-Request-Email value failed to decode as base64url"));
|
||||||
}
|
|
||||||
};
|
};
|
||||||
match String::from_utf8(email_bytes) {
|
match String::from_utf8(email_bytes) {
|
||||||
Ok(email) => email,
|
Ok(email) => email,
|
||||||
|
@ -1086,9 +1078,9 @@ async fn put_device_token(uuid: &str, data: Json<PushToken>, headers: Headers, m
|
||||||
let data = data.into_inner();
|
let data = data.into_inner();
|
||||||
let token = data.push_token;
|
let token = data.push_token;
|
||||||
|
|
||||||
let mut device = match Device::find_by_uuid_and_user(&headers.device.uuid, &headers.user.uuid, &mut conn).await {
|
let Some(mut device) = Device::find_by_uuid_and_user(&headers.device.uuid, &headers.user.uuid, &mut conn).await
|
||||||
Some(device) => device,
|
else {
|
||||||
None => err!(format!("Error: device {uuid} should be present before a token can be assigned")),
|
err!(format!("Error: device {uuid} should be present before a token can be assigned"))
|
||||||
};
|
};
|
||||||
|
|
||||||
// if the device already has been registered
|
// if the device already has been registered
|
||||||
|
@ -1159,9 +1151,8 @@ async fn post_auth_request(
|
||||||
) -> JsonResult {
|
) -> JsonResult {
|
||||||
let data = data.into_inner();
|
let data = data.into_inner();
|
||||||
|
|
||||||
let user = match User::find_by_mail(&data.email, &mut conn).await {
|
let Some(user) = User::find_by_mail(&data.email, &mut conn).await else {
|
||||||
Some(user) => user,
|
err!("AuthRequest doesn't exist", "User not found")
|
||||||
None => err!("AuthRequest doesn't exist", "User not found"),
|
|
||||||
};
|
};
|
||||||
|
|
||||||
// Validate device uuid and type
|
// Validate device uuid and type
|
||||||
|
@ -1199,15 +1190,10 @@ async fn post_auth_request(
|
||||||
|
|
||||||
#[get("/auth-requests/<uuid>")]
|
#[get("/auth-requests/<uuid>")]
|
||||||
async fn get_auth_request(uuid: &str, headers: Headers, mut conn: DbConn) -> JsonResult {
|
async fn get_auth_request(uuid: &str, headers: Headers, mut conn: DbConn) -> JsonResult {
|
||||||
let auth_request = match AuthRequest::find_by_uuid(uuid, &mut conn).await {
|
let Some(auth_request) = AuthRequest::find_by_uuid_and_user(uuid, &headers.user.uuid, &mut conn).await else {
|
||||||
Some(auth_request) => auth_request,
|
err!("AuthRequest doesn't exist", "Record not found or user uuid does not match")
|
||||||
None => err!("AuthRequest doesn't exist", "Record not found"),
|
|
||||||
};
|
};
|
||||||
|
|
||||||
if headers.user.uuid != auth_request.user_uuid {
|
|
||||||
err!("AuthRequest doesn't exist", "User uuid's do not match")
|
|
||||||
}
|
|
||||||
|
|
||||||
let response_date_utc = auth_request.response_date.map(|response_date| format_date(&response_date));
|
let response_date_utc = auth_request.response_date.map(|response_date| format_date(&response_date));
|
||||||
|
|
||||||
Ok(Json(json!({
|
Ok(Json(json!({
|
||||||
|
@ -1244,15 +1230,10 @@ async fn put_auth_request(
|
||||||
nt: Notify<'_>,
|
nt: Notify<'_>,
|
||||||
) -> JsonResult {
|
) -> JsonResult {
|
||||||
let data = data.into_inner();
|
let data = data.into_inner();
|
||||||
let mut auth_request: AuthRequest = match AuthRequest::find_by_uuid(uuid, &mut conn).await {
|
let Some(mut auth_request) = AuthRequest::find_by_uuid_and_user(uuid, &headers.user.uuid, &mut conn).await else {
|
||||||
Some(auth_request) => auth_request,
|
err!("AuthRequest doesn't exist", "Record not found or user uuid does not match")
|
||||||
None => err!("AuthRequest doesn't exist", "Record not found"),
|
|
||||||
};
|
};
|
||||||
|
|
||||||
if headers.user.uuid != auth_request.user_uuid {
|
|
||||||
err!("AuthRequest doesn't exist", "User uuid's do not match")
|
|
||||||
}
|
|
||||||
|
|
||||||
if auth_request.approved.is_some() {
|
if auth_request.approved.is_some() {
|
||||||
err!("An authentication request with the same device already exists")
|
err!("An authentication request with the same device already exists")
|
||||||
}
|
}
|
||||||
|
@ -1297,9 +1278,8 @@ async fn get_auth_request_response(
|
||||||
client_headers: ClientHeaders,
|
client_headers: ClientHeaders,
|
||||||
mut conn: DbConn,
|
mut conn: DbConn,
|
||||||
) -> JsonResult {
|
) -> JsonResult {
|
||||||
let auth_request = match AuthRequest::find_by_uuid(uuid, &mut conn).await {
|
let Some(auth_request) = AuthRequest::find_by_uuid(uuid, &mut conn).await else {
|
||||||
Some(auth_request) => auth_request,
|
err!("AuthRequest doesn't exist", "User not found")
|
||||||
None => err!("AuthRequest doesn't exist", "User not found"),
|
|
||||||
};
|
};
|
||||||
|
|
||||||
if auth_request.device_type != client_headers.device_type
|
if auth_request.device_type != client_headers.device_type
|
||||||
|
|
|
@ -193,9 +193,8 @@ async fn get_ciphers(headers: Headers, mut conn: DbConn) -> Json<Value> {
|
||||||
|
|
||||||
#[get("/ciphers/<uuid>")]
|
#[get("/ciphers/<uuid>")]
|
||||||
async fn get_cipher(uuid: &str, headers: Headers, mut conn: DbConn) -> JsonResult {
|
async fn get_cipher(uuid: &str, headers: Headers, mut conn: DbConn) -> JsonResult {
|
||||||
let cipher = match Cipher::find_by_uuid(uuid, &mut conn).await {
|
let Some(cipher) = Cipher::find_by_uuid(uuid, &mut conn).await else {
|
||||||
Some(cipher) => cipher,
|
err!("Cipher doesn't exist")
|
||||||
None => err!("Cipher doesn't exist"),
|
|
||||||
};
|
};
|
||||||
|
|
||||||
if !cipher.is_accessible_to_user(&headers.user.uuid, &mut conn).await {
|
if !cipher.is_accessible_to_user(&headers.user.uuid, &mut conn).await {
|
||||||
|
@ -429,14 +428,9 @@ pub async fn update_cipher_from_data(
|
||||||
cipher.user_uuid = Some(headers.user.uuid.clone());
|
cipher.user_uuid = Some(headers.user.uuid.clone());
|
||||||
}
|
}
|
||||||
|
|
||||||
if let Some(ref folder_id) = data.folder_id {
|
if let Some(ref folder_uuid) = data.folder_id {
|
||||||
match Folder::find_by_uuid(folder_id, conn).await {
|
if Folder::find_by_uuid_and_user(folder_uuid, &headers.user.uuid, conn).await.is_none() {
|
||||||
Some(folder) => {
|
err!("Invalid folder", "Folder does not exist or belongs to another user");
|
||||||
if folder.user_uuid != headers.user.uuid {
|
|
||||||
err!("Folder is not owned by user")
|
|
||||||
}
|
|
||||||
}
|
|
||||||
None => err!("Folder doesn't exist"),
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -661,9 +655,8 @@ async fn put_cipher(
|
||||||
) -> JsonResult {
|
) -> JsonResult {
|
||||||
let data: CipherData = data.into_inner();
|
let data: CipherData = data.into_inner();
|
||||||
|
|
||||||
let mut cipher = match Cipher::find_by_uuid(uuid, &mut conn).await {
|
let Some(mut cipher) = Cipher::find_by_uuid(uuid, &mut conn).await else {
|
||||||
Some(cipher) => cipher,
|
err!("Cipher doesn't exist")
|
||||||
None => err!("Cipher doesn't exist"),
|
|
||||||
};
|
};
|
||||||
|
|
||||||
// TODO: Check if only the folder ID or favorite status is being changed.
|
// TODO: Check if only the folder ID or favorite status is being changed.
|
||||||
|
@ -695,19 +688,13 @@ async fn put_cipher_partial(
|
||||||
) -> JsonResult {
|
) -> JsonResult {
|
||||||
let data: PartialCipherData = data.into_inner();
|
let data: PartialCipherData = data.into_inner();
|
||||||
|
|
||||||
let cipher = match Cipher::find_by_uuid(uuid, &mut conn).await {
|
let Some(cipher) = Cipher::find_by_uuid(uuid, &mut conn).await else {
|
||||||
Some(cipher) => cipher,
|
err!("Cipher doesn't exist")
|
||||||
None => err!("Cipher doesn't exist"),
|
|
||||||
};
|
};
|
||||||
|
|
||||||
if let Some(ref folder_id) = data.folder_id {
|
if let Some(ref folder_uuid) = data.folder_id {
|
||||||
match Folder::find_by_uuid(folder_id, &mut conn).await {
|
if Folder::find_by_uuid_and_user(folder_uuid, &headers.user.uuid, &mut conn).await.is_none() {
|
||||||
Some(folder) => {
|
err!("Invalid folder", "Folder does not exist or belongs to another user");
|
||||||
if folder.user_uuid != headers.user.uuid {
|
|
||||||
err!("Folder is not owned by user")
|
|
||||||
}
|
|
||||||
}
|
|
||||||
None => err!("Folder doesn't exist"),
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -774,9 +761,8 @@ async fn post_collections_update(
|
||||||
) -> JsonResult {
|
) -> JsonResult {
|
||||||
let data: CollectionsAdminData = data.into_inner();
|
let data: CollectionsAdminData = data.into_inner();
|
||||||
|
|
||||||
let cipher = match Cipher::find_by_uuid(uuid, &mut conn).await {
|
let Some(cipher) = Cipher::find_by_uuid(uuid, &mut conn).await else {
|
||||||
Some(cipher) => cipher,
|
err!("Cipher doesn't exist")
|
||||||
None => err!("Cipher doesn't exist"),
|
|
||||||
};
|
};
|
||||||
|
|
||||||
if !cipher.is_write_accessible_to_user(&headers.user.uuid, &mut conn).await {
|
if !cipher.is_write_accessible_to_user(&headers.user.uuid, &mut conn).await {
|
||||||
|
@ -788,7 +774,8 @@ async fn post_collections_update(
|
||||||
HashSet::<String>::from_iter(cipher.get_collections(headers.user.uuid.clone(), &mut conn).await);
|
HashSet::<String>::from_iter(cipher.get_collections(headers.user.uuid.clone(), &mut conn).await);
|
||||||
|
|
||||||
for collection in posted_collections.symmetric_difference(¤t_collections) {
|
for collection in posted_collections.symmetric_difference(¤t_collections) {
|
||||||
match Collection::find_by_uuid(collection, &mut conn).await {
|
match Collection::find_by_uuid_and_org(collection, cipher.organization_uuid.as_ref().unwrap(), &mut conn).await
|
||||||
|
{
|
||||||
None => err!("Invalid collection ID provided"),
|
None => err!("Invalid collection ID provided"),
|
||||||
Some(collection) => {
|
Some(collection) => {
|
||||||
if collection.is_writable_by_user(&headers.user.uuid, &mut conn).await {
|
if collection.is_writable_by_user(&headers.user.uuid, &mut conn).await {
|
||||||
|
@ -851,9 +838,8 @@ async fn post_collections_admin(
|
||||||
) -> EmptyResult {
|
) -> EmptyResult {
|
||||||
let data: CollectionsAdminData = data.into_inner();
|
let data: CollectionsAdminData = data.into_inner();
|
||||||
|
|
||||||
let cipher = match Cipher::find_by_uuid(uuid, &mut conn).await {
|
let Some(cipher) = Cipher::find_by_uuid(uuid, &mut conn).await else {
|
||||||
Some(cipher) => cipher,
|
err!("Cipher doesn't exist")
|
||||||
None => err!("Cipher doesn't exist"),
|
|
||||||
};
|
};
|
||||||
|
|
||||||
if !cipher.is_write_accessible_to_user(&headers.user.uuid, &mut conn).await {
|
if !cipher.is_write_accessible_to_user(&headers.user.uuid, &mut conn).await {
|
||||||
|
@ -865,7 +851,8 @@ async fn post_collections_admin(
|
||||||
HashSet::<String>::from_iter(cipher.get_admin_collections(headers.user.uuid.clone(), &mut conn).await);
|
HashSet::<String>::from_iter(cipher.get_admin_collections(headers.user.uuid.clone(), &mut conn).await);
|
||||||
|
|
||||||
for collection in posted_collections.symmetric_difference(¤t_collections) {
|
for collection in posted_collections.symmetric_difference(¤t_collections) {
|
||||||
match Collection::find_by_uuid(collection, &mut conn).await {
|
match Collection::find_by_uuid_and_org(collection, cipher.organization_uuid.as_ref().unwrap(), &mut conn).await
|
||||||
|
{
|
||||||
None => err!("Invalid collection ID provided"),
|
None => err!("Invalid collection ID provided"),
|
||||||
Some(collection) => {
|
Some(collection) => {
|
||||||
if collection.is_writable_by_user(&headers.user.uuid, &mut conn).await {
|
if collection.is_writable_by_user(&headers.user.uuid, &mut conn).await {
|
||||||
|
@ -1043,9 +1030,8 @@ async fn share_cipher_by_uuid(
|
||||||
/// redirects to the same location as before the v2 API.
|
/// redirects to the same location as before the v2 API.
|
||||||
#[get("/ciphers/<uuid>/attachment/<attachment_id>")]
|
#[get("/ciphers/<uuid>/attachment/<attachment_id>")]
|
||||||
async fn get_attachment(uuid: &str, attachment_id: &str, headers: Headers, mut conn: DbConn) -> JsonResult {
|
async fn get_attachment(uuid: &str, attachment_id: &str, headers: Headers, mut conn: DbConn) -> JsonResult {
|
||||||
let cipher = match Cipher::find_by_uuid(uuid, &mut conn).await {
|
let Some(cipher) = Cipher::find_by_uuid(uuid, &mut conn).await else {
|
||||||
Some(cipher) => cipher,
|
err!("Cipher doesn't exist")
|
||||||
None => err!("Cipher doesn't exist"),
|
|
||||||
};
|
};
|
||||||
|
|
||||||
if !cipher.is_accessible_to_user(&headers.user.uuid, &mut conn).await {
|
if !cipher.is_accessible_to_user(&headers.user.uuid, &mut conn).await {
|
||||||
|
@ -1084,9 +1070,8 @@ async fn post_attachment_v2(
|
||||||
headers: Headers,
|
headers: Headers,
|
||||||
mut conn: DbConn,
|
mut conn: DbConn,
|
||||||
) -> JsonResult {
|
) -> JsonResult {
|
||||||
let cipher = match Cipher::find_by_uuid(uuid, &mut conn).await {
|
let Some(cipher) = Cipher::find_by_uuid(uuid, &mut conn).await else {
|
||||||
Some(cipher) => cipher,
|
err!("Cipher doesn't exist")
|
||||||
None => err!("Cipher doesn't exist"),
|
|
||||||
};
|
};
|
||||||
|
|
||||||
if !cipher.is_write_accessible_to_user(&headers.user.uuid, &mut conn).await {
|
if !cipher.is_write_accessible_to_user(&headers.user.uuid, &mut conn).await {
|
||||||
|
@ -1150,9 +1135,8 @@ async fn save_attachment(
|
||||||
err!("Attachment size can't be negative")
|
err!("Attachment size can't be negative")
|
||||||
}
|
}
|
||||||
|
|
||||||
let cipher = match Cipher::find_by_uuid(cipher_uuid, &mut conn).await {
|
let Some(cipher) = Cipher::find_by_uuid(cipher_uuid, &mut conn).await else {
|
||||||
Some(cipher) => cipher,
|
err!("Cipher doesn't exist")
|
||||||
None => err!("Cipher doesn't exist"),
|
|
||||||
};
|
};
|
||||||
|
|
||||||
if !cipher.is_write_accessible_to_user(&headers.user.uuid, &mut conn).await {
|
if !cipher.is_write_accessible_to_user(&headers.user.uuid, &mut conn).await {
|
||||||
|
@ -1545,21 +1529,15 @@ async fn move_cipher_selected(
|
||||||
let data = data.into_inner();
|
let data = data.into_inner();
|
||||||
let user_uuid = headers.user.uuid;
|
let user_uuid = headers.user.uuid;
|
||||||
|
|
||||||
if let Some(ref folder_id) = data.folder_id {
|
if let Some(ref folder_uuid) = data.folder_id {
|
||||||
match Folder::find_by_uuid(folder_id, &mut conn).await {
|
if Folder::find_by_uuid_and_user(folder_uuid, &user_uuid, &mut conn).await.is_none() {
|
||||||
Some(folder) => {
|
err!("Invalid folder", "Folder does not exist or belongs to another user");
|
||||||
if folder.user_uuid != user_uuid {
|
|
||||||
err!("Folder is not owned by user")
|
|
||||||
}
|
|
||||||
}
|
|
||||||
None => err!("Folder doesn't exist"),
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
for uuid in data.ids {
|
for uuid in data.ids {
|
||||||
let cipher = match Cipher::find_by_uuid(&uuid, &mut conn).await {
|
let Some(cipher) = Cipher::find_by_uuid(&uuid, &mut conn).await else {
|
||||||
Some(cipher) => cipher,
|
err!("Cipher doesn't exist")
|
||||||
None => err!("Cipher doesn't exist"),
|
|
||||||
};
|
};
|
||||||
|
|
||||||
if !cipher.is_accessible_to_user(&user_uuid, &mut conn).await {
|
if !cipher.is_accessible_to_user(&user_uuid, &mut conn).await {
|
||||||
|
@ -1667,9 +1645,8 @@ async fn _delete_cipher_by_uuid(
|
||||||
soft_delete: bool,
|
soft_delete: bool,
|
||||||
nt: &Notify<'_>,
|
nt: &Notify<'_>,
|
||||||
) -> EmptyResult {
|
) -> EmptyResult {
|
||||||
let mut cipher = match Cipher::find_by_uuid(uuid, conn).await {
|
let Some(mut cipher) = Cipher::find_by_uuid(uuid, conn).await else {
|
||||||
Some(cipher) => cipher,
|
err!("Cipher doesn't exist")
|
||||||
None => err!("Cipher doesn't exist"),
|
|
||||||
};
|
};
|
||||||
|
|
||||||
if !cipher.is_write_accessible_to_user(&headers.user.uuid, conn).await {
|
if !cipher.is_write_accessible_to_user(&headers.user.uuid, conn).await {
|
||||||
|
@ -1739,9 +1716,8 @@ async fn _delete_multiple_ciphers(
|
||||||
}
|
}
|
||||||
|
|
||||||
async fn _restore_cipher_by_uuid(uuid: &str, headers: &Headers, conn: &mut DbConn, nt: &Notify<'_>) -> JsonResult {
|
async fn _restore_cipher_by_uuid(uuid: &str, headers: &Headers, conn: &mut DbConn, nt: &Notify<'_>) -> JsonResult {
|
||||||
let mut cipher = match Cipher::find_by_uuid(uuid, conn).await {
|
let Some(mut cipher) = Cipher::find_by_uuid(uuid, conn).await else {
|
||||||
Some(cipher) => cipher,
|
err!("Cipher doesn't exist")
|
||||||
None => err!("Cipher doesn't exist"),
|
|
||||||
};
|
};
|
||||||
|
|
||||||
if !cipher.is_write_accessible_to_user(&headers.user.uuid, conn).await {
|
if !cipher.is_write_accessible_to_user(&headers.user.uuid, conn).await {
|
||||||
|
@ -1807,18 +1783,16 @@ async fn _delete_cipher_attachment_by_id(
|
||||||
conn: &mut DbConn,
|
conn: &mut DbConn,
|
||||||
nt: &Notify<'_>,
|
nt: &Notify<'_>,
|
||||||
) -> EmptyResult {
|
) -> EmptyResult {
|
||||||
let attachment = match Attachment::find_by_id(attachment_id, conn).await {
|
let Some(attachment) = Attachment::find_by_id(attachment_id, conn).await else {
|
||||||
Some(attachment) => attachment,
|
err!("Attachment doesn't exist")
|
||||||
None => err!("Attachment doesn't exist"),
|
|
||||||
};
|
};
|
||||||
|
|
||||||
if attachment.cipher_uuid != uuid {
|
if attachment.cipher_uuid != uuid {
|
||||||
err!("Attachment from other cipher")
|
err!("Attachment from other cipher")
|
||||||
}
|
}
|
||||||
|
|
||||||
let cipher = match Cipher::find_by_uuid(uuid, conn).await {
|
let Some(cipher) = Cipher::find_by_uuid(uuid, conn).await else {
|
||||||
Some(cipher) => cipher,
|
err!("Cipher doesn't exist")
|
||||||
None => err!("Cipher doesn't exist"),
|
|
||||||
};
|
};
|
||||||
|
|
||||||
if !cipher.is_write_accessible_to_user(&headers.user.uuid, conn).await {
|
if !cipher.is_write_accessible_to_user(&headers.user.uuid, conn).await {
|
||||||
|
|
|
@ -137,10 +137,10 @@ async fn post_emergency_access(
|
||||||
|
|
||||||
let data: EmergencyAccessUpdateData = data.into_inner();
|
let data: EmergencyAccessUpdateData = data.into_inner();
|
||||||
|
|
||||||
let mut emergency_access =
|
let Some(mut emergency_access) =
|
||||||
match EmergencyAccess::find_by_uuid_and_grantor_uuid(emer_id, &headers.user.uuid, &mut conn).await {
|
EmergencyAccess::find_by_uuid_and_grantor_uuid(emer_id, &headers.user.uuid, &mut conn).await
|
||||||
Some(emergency_access) => emergency_access,
|
else {
|
||||||
None => err!("Emergency access not valid."),
|
err!("Emergency access not valid.")
|
||||||
};
|
};
|
||||||
|
|
||||||
let new_type = match EmergencyAccessType::from_str(&data.r#type.into_string()) {
|
let new_type = match EmergencyAccessType::from_str(&data.r#type.into_string()) {
|
||||||
|
@ -284,24 +284,22 @@ async fn send_invite(data: Json<EmergencyAccessInviteData>, headers: Headers, mu
|
||||||
async fn resend_invite(emer_id: &str, headers: Headers, mut conn: DbConn) -> EmptyResult {
|
async fn resend_invite(emer_id: &str, headers: Headers, mut conn: DbConn) -> EmptyResult {
|
||||||
check_emergency_access_enabled()?;
|
check_emergency_access_enabled()?;
|
||||||
|
|
||||||
let mut emergency_access =
|
let Some(mut emergency_access) =
|
||||||
match EmergencyAccess::find_by_uuid_and_grantor_uuid(emer_id, &headers.user.uuid, &mut conn).await {
|
EmergencyAccess::find_by_uuid_and_grantor_uuid(emer_id, &headers.user.uuid, &mut conn).await
|
||||||
Some(emer) => emer,
|
else {
|
||||||
None => err!("Emergency access not valid."),
|
err!("Emergency access not valid.")
|
||||||
};
|
};
|
||||||
|
|
||||||
if emergency_access.status != EmergencyAccessStatus::Invited as i32 {
|
if emergency_access.status != EmergencyAccessStatus::Invited as i32 {
|
||||||
err!("The grantee user is already accepted or confirmed to the organization");
|
err!("The grantee user is already accepted or confirmed to the organization");
|
||||||
}
|
}
|
||||||
|
|
||||||
let email = match emergency_access.email.clone() {
|
let Some(email) = emergency_access.email.clone() else {
|
||||||
Some(email) => email,
|
err!("Email not valid.")
|
||||||
None => err!("Email not valid."),
|
|
||||||
};
|
};
|
||||||
|
|
||||||
let grantee_user = match User::find_by_mail(&email, &mut conn).await {
|
let Some(grantee_user) = User::find_by_mail(&email, &mut conn).await else {
|
||||||
Some(user) => user,
|
err!("Grantee user not found.")
|
||||||
None => err!("Grantee user not found."),
|
|
||||||
};
|
};
|
||||||
|
|
||||||
let grantor_user = headers.user;
|
let grantor_user = headers.user;
|
||||||
|
@ -356,16 +354,15 @@ async fn accept_invite(emer_id: &str, data: Json<AcceptData>, headers: Headers,
|
||||||
|
|
||||||
// We need to search for the uuid in combination with the email, since we do not yet store the uuid of the grantee in the database.
|
// We need to search for the uuid in combination with the email, since we do not yet store the uuid of the grantee in the database.
|
||||||
// The uuid of the grantee gets stored once accepted.
|
// The uuid of the grantee gets stored once accepted.
|
||||||
let mut emergency_access =
|
let Some(mut emergency_access) =
|
||||||
match EmergencyAccess::find_by_uuid_and_grantee_email(emer_id, &headers.user.email, &mut conn).await {
|
EmergencyAccess::find_by_uuid_and_grantee_email(emer_id, &headers.user.email, &mut conn).await
|
||||||
Some(emer) => emer,
|
else {
|
||||||
None => err!("Emergency access not valid."),
|
err!("Emergency access not valid.")
|
||||||
};
|
};
|
||||||
|
|
||||||
// get grantor user to send Accepted email
|
// get grantor user to send Accepted email
|
||||||
let grantor_user = match User::find_by_uuid(&emergency_access.grantor_uuid, &mut conn).await {
|
let Some(grantor_user) = User::find_by_uuid(&emergency_access.grantor_uuid, &mut conn).await else {
|
||||||
Some(user) => user,
|
err!("Grantor user not found.")
|
||||||
None => err!("Grantor user not found."),
|
|
||||||
};
|
};
|
||||||
|
|
||||||
if emer_id == claims.emer_id
|
if emer_id == claims.emer_id
|
||||||
|
@ -403,10 +400,10 @@ async fn confirm_emergency_access(
|
||||||
let data: ConfirmData = data.into_inner();
|
let data: ConfirmData = data.into_inner();
|
||||||
let key = data.key;
|
let key = data.key;
|
||||||
|
|
||||||
let mut emergency_access =
|
let Some(mut emergency_access) =
|
||||||
match EmergencyAccess::find_by_uuid_and_grantor_uuid(emer_id, &confirming_user.uuid, &mut conn).await {
|
EmergencyAccess::find_by_uuid_and_grantor_uuid(emer_id, &confirming_user.uuid, &mut conn).await
|
||||||
Some(emer) => emer,
|
else {
|
||||||
None => err!("Emergency access not valid."),
|
err!("Emergency access not valid.")
|
||||||
};
|
};
|
||||||
|
|
||||||
if emergency_access.status != EmergencyAccessStatus::Accepted as i32
|
if emergency_access.status != EmergencyAccessStatus::Accepted as i32
|
||||||
|
@ -415,15 +412,13 @@ async fn confirm_emergency_access(
|
||||||
err!("Emergency access not valid.")
|
err!("Emergency access not valid.")
|
||||||
}
|
}
|
||||||
|
|
||||||
let grantor_user = match User::find_by_uuid(&confirming_user.uuid, &mut conn).await {
|
let Some(grantor_user) = User::find_by_uuid(&confirming_user.uuid, &mut conn).await else {
|
||||||
Some(user) => user,
|
err!("Grantor user not found.")
|
||||||
None => err!("Grantor user not found."),
|
|
||||||
};
|
};
|
||||||
|
|
||||||
if let Some(grantee_uuid) = emergency_access.grantee_uuid.as_ref() {
|
if let Some(grantee_uuid) = emergency_access.grantee_uuid.as_ref() {
|
||||||
let grantee_user = match User::find_by_uuid(grantee_uuid, &mut conn).await {
|
let Some(grantee_user) = User::find_by_uuid(grantee_uuid, &mut conn).await else {
|
||||||
Some(user) => user,
|
err!("Grantee user not found.")
|
||||||
None => err!("Grantee user not found."),
|
|
||||||
};
|
};
|
||||||
|
|
||||||
emergency_access.status = EmergencyAccessStatus::Confirmed as i32;
|
emergency_access.status = EmergencyAccessStatus::Confirmed as i32;
|
||||||
|
@ -450,19 +445,18 @@ async fn initiate_emergency_access(emer_id: &str, headers: Headers, mut conn: Db
|
||||||
check_emergency_access_enabled()?;
|
check_emergency_access_enabled()?;
|
||||||
|
|
||||||
let initiating_user = headers.user;
|
let initiating_user = headers.user;
|
||||||
let mut emergency_access =
|
let Some(mut emergency_access) =
|
||||||
match EmergencyAccess::find_by_uuid_and_grantee_uuid(emer_id, &initiating_user.uuid, &mut conn).await {
|
EmergencyAccess::find_by_uuid_and_grantee_uuid(emer_id, &initiating_user.uuid, &mut conn).await
|
||||||
Some(emer) => emer,
|
else {
|
||||||
None => err!("Emergency access not valid."),
|
err!("Emergency access not valid.")
|
||||||
};
|
};
|
||||||
|
|
||||||
if emergency_access.status != EmergencyAccessStatus::Confirmed as i32 {
|
if emergency_access.status != EmergencyAccessStatus::Confirmed as i32 {
|
||||||
err!("Emergency access not valid.")
|
err!("Emergency access not valid.")
|
||||||
}
|
}
|
||||||
|
|
||||||
let grantor_user = match User::find_by_uuid(&emergency_access.grantor_uuid, &mut conn).await {
|
let Some(grantor_user) = User::find_by_uuid(&emergency_access.grantor_uuid, &mut conn).await else {
|
||||||
Some(user) => user,
|
err!("Grantor user not found.")
|
||||||
None => err!("Grantor user not found."),
|
|
||||||
};
|
};
|
||||||
|
|
||||||
let now = Utc::now().naive_utc();
|
let now = Utc::now().naive_utc();
|
||||||
|
@ -488,25 +482,23 @@ async fn initiate_emergency_access(emer_id: &str, headers: Headers, mut conn: Db
|
||||||
async fn approve_emergency_access(emer_id: &str, headers: Headers, mut conn: DbConn) -> JsonResult {
|
async fn approve_emergency_access(emer_id: &str, headers: Headers, mut conn: DbConn) -> JsonResult {
|
||||||
check_emergency_access_enabled()?;
|
check_emergency_access_enabled()?;
|
||||||
|
|
||||||
let mut emergency_access =
|
let Some(mut emergency_access) =
|
||||||
match EmergencyAccess::find_by_uuid_and_grantor_uuid(emer_id, &headers.user.uuid, &mut conn).await {
|
EmergencyAccess::find_by_uuid_and_grantor_uuid(emer_id, &headers.user.uuid, &mut conn).await
|
||||||
Some(emer) => emer,
|
else {
|
||||||
None => err!("Emergency access not valid."),
|
err!("Emergency access not valid.")
|
||||||
};
|
};
|
||||||
|
|
||||||
if emergency_access.status != EmergencyAccessStatus::RecoveryInitiated as i32 {
|
if emergency_access.status != EmergencyAccessStatus::RecoveryInitiated as i32 {
|
||||||
err!("Emergency access not valid.")
|
err!("Emergency access not valid.")
|
||||||
}
|
}
|
||||||
|
|
||||||
let grantor_user = match User::find_by_uuid(&headers.user.uuid, &mut conn).await {
|
let Some(grantor_user) = User::find_by_uuid(&headers.user.uuid, &mut conn).await else {
|
||||||
Some(user) => user,
|
err!("Grantor user not found.")
|
||||||
None => err!("Grantor user not found."),
|
|
||||||
};
|
};
|
||||||
|
|
||||||
if let Some(grantee_uuid) = emergency_access.grantee_uuid.as_ref() {
|
if let Some(grantee_uuid) = emergency_access.grantee_uuid.as_ref() {
|
||||||
let grantee_user = match User::find_by_uuid(grantee_uuid, &mut conn).await {
|
let Some(grantee_user) = User::find_by_uuid(grantee_uuid, &mut conn).await else {
|
||||||
Some(user) => user,
|
err!("Grantee user not found.")
|
||||||
None => err!("Grantee user not found."),
|
|
||||||
};
|
};
|
||||||
|
|
||||||
emergency_access.status = EmergencyAccessStatus::RecoveryApproved as i32;
|
emergency_access.status = EmergencyAccessStatus::RecoveryApproved as i32;
|
||||||
|
@ -525,10 +517,10 @@ async fn approve_emergency_access(emer_id: &str, headers: Headers, mut conn: DbC
|
||||||
async fn reject_emergency_access(emer_id: &str, headers: Headers, mut conn: DbConn) -> JsonResult {
|
async fn reject_emergency_access(emer_id: &str, headers: Headers, mut conn: DbConn) -> JsonResult {
|
||||||
check_emergency_access_enabled()?;
|
check_emergency_access_enabled()?;
|
||||||
|
|
||||||
let mut emergency_access =
|
let Some(mut emergency_access) =
|
||||||
match EmergencyAccess::find_by_uuid_and_grantor_uuid(emer_id, &headers.user.uuid, &mut conn).await {
|
EmergencyAccess::find_by_uuid_and_grantor_uuid(emer_id, &headers.user.uuid, &mut conn).await
|
||||||
Some(emer) => emer,
|
else {
|
||||||
None => err!("Emergency access not valid."),
|
err!("Emergency access not valid.")
|
||||||
};
|
};
|
||||||
|
|
||||||
if emergency_access.status != EmergencyAccessStatus::RecoveryInitiated as i32
|
if emergency_access.status != EmergencyAccessStatus::RecoveryInitiated as i32
|
||||||
|
@ -538,9 +530,8 @@ async fn reject_emergency_access(emer_id: &str, headers: Headers, mut conn: DbCo
|
||||||
}
|
}
|
||||||
|
|
||||||
if let Some(grantee_uuid) = emergency_access.grantee_uuid.as_ref() {
|
if let Some(grantee_uuid) = emergency_access.grantee_uuid.as_ref() {
|
||||||
let grantee_user = match User::find_by_uuid(grantee_uuid, &mut conn).await {
|
let Some(grantee_user) = User::find_by_uuid(grantee_uuid, &mut conn).await else {
|
||||||
Some(user) => user,
|
err!("Grantee user not found.")
|
||||||
None => err!("Grantee user not found."),
|
|
||||||
};
|
};
|
||||||
|
|
||||||
emergency_access.status = EmergencyAccessStatus::Confirmed as i32;
|
emergency_access.status = EmergencyAccessStatus::Confirmed as i32;
|
||||||
|
@ -563,10 +554,10 @@ async fn reject_emergency_access(emer_id: &str, headers: Headers, mut conn: DbCo
|
||||||
async fn view_emergency_access(emer_id: &str, headers: Headers, mut conn: DbConn) -> JsonResult {
|
async fn view_emergency_access(emer_id: &str, headers: Headers, mut conn: DbConn) -> JsonResult {
|
||||||
check_emergency_access_enabled()?;
|
check_emergency_access_enabled()?;
|
||||||
|
|
||||||
let emergency_access =
|
let Some(emergency_access) =
|
||||||
match EmergencyAccess::find_by_uuid_and_grantee_uuid(emer_id, &headers.user.uuid, &mut conn).await {
|
EmergencyAccess::find_by_uuid_and_grantee_uuid(emer_id, &headers.user.uuid, &mut conn).await
|
||||||
Some(emer) => emer,
|
else {
|
||||||
None => err!("Emergency access not valid."),
|
err!("Emergency access not valid.")
|
||||||
};
|
};
|
||||||
|
|
||||||
if !is_valid_request(&emergency_access, &headers.user.uuid, EmergencyAccessType::View) {
|
if !is_valid_request(&emergency_access, &headers.user.uuid, EmergencyAccessType::View) {
|
||||||
|
@ -602,19 +593,18 @@ async fn takeover_emergency_access(emer_id: &str, headers: Headers, mut conn: Db
|
||||||
check_emergency_access_enabled()?;
|
check_emergency_access_enabled()?;
|
||||||
|
|
||||||
let requesting_user = headers.user;
|
let requesting_user = headers.user;
|
||||||
let emergency_access =
|
let Some(emergency_access) =
|
||||||
match EmergencyAccess::find_by_uuid_and_grantee_uuid(emer_id, &requesting_user.uuid, &mut conn).await {
|
EmergencyAccess::find_by_uuid_and_grantee_uuid(emer_id, &requesting_user.uuid, &mut conn).await
|
||||||
Some(emer) => emer,
|
else {
|
||||||
None => err!("Emergency access not valid."),
|
err!("Emergency access not valid.")
|
||||||
};
|
};
|
||||||
|
|
||||||
if !is_valid_request(&emergency_access, &requesting_user.uuid, EmergencyAccessType::Takeover) {
|
if !is_valid_request(&emergency_access, &requesting_user.uuid, EmergencyAccessType::Takeover) {
|
||||||
err!("Emergency access not valid.")
|
err!("Emergency access not valid.")
|
||||||
}
|
}
|
||||||
|
|
||||||
let grantor_user = match User::find_by_uuid(&emergency_access.grantor_uuid, &mut conn).await {
|
let Some(grantor_user) = User::find_by_uuid(&emergency_access.grantor_uuid, &mut conn).await else {
|
||||||
Some(user) => user,
|
err!("Grantor user not found.")
|
||||||
None => err!("Grantor user not found."),
|
|
||||||
};
|
};
|
||||||
|
|
||||||
let result = json!({
|
let result = json!({
|
||||||
|
@ -650,19 +640,18 @@ async fn password_emergency_access(
|
||||||
//let key = &data.Key;
|
//let key = &data.Key;
|
||||||
|
|
||||||
let requesting_user = headers.user;
|
let requesting_user = headers.user;
|
||||||
let emergency_access =
|
let Some(emergency_access) =
|
||||||
match EmergencyAccess::find_by_uuid_and_grantee_uuid(emer_id, &requesting_user.uuid, &mut conn).await {
|
EmergencyAccess::find_by_uuid_and_grantee_uuid(emer_id, &requesting_user.uuid, &mut conn).await
|
||||||
Some(emer) => emer,
|
else {
|
||||||
None => err!("Emergency access not valid."),
|
err!("Emergency access not valid.")
|
||||||
};
|
};
|
||||||
|
|
||||||
if !is_valid_request(&emergency_access, &requesting_user.uuid, EmergencyAccessType::Takeover) {
|
if !is_valid_request(&emergency_access, &requesting_user.uuid, EmergencyAccessType::Takeover) {
|
||||||
err!("Emergency access not valid.")
|
err!("Emergency access not valid.")
|
||||||
}
|
}
|
||||||
|
|
||||||
let mut grantor_user = match User::find_by_uuid(&emergency_access.grantor_uuid, &mut conn).await {
|
let Some(mut grantor_user) = User::find_by_uuid(&emergency_access.grantor_uuid, &mut conn).await else {
|
||||||
Some(user) => user,
|
err!("Grantor user not found.")
|
||||||
None => err!("Grantor user not found."),
|
|
||||||
};
|
};
|
||||||
|
|
||||||
// change grantor_user password
|
// change grantor_user password
|
||||||
|
@ -686,19 +675,18 @@ async fn password_emergency_access(
|
||||||
#[get("/emergency-access/<emer_id>/policies")]
|
#[get("/emergency-access/<emer_id>/policies")]
|
||||||
async fn policies_emergency_access(emer_id: &str, headers: Headers, mut conn: DbConn) -> JsonResult {
|
async fn policies_emergency_access(emer_id: &str, headers: Headers, mut conn: DbConn) -> JsonResult {
|
||||||
let requesting_user = headers.user;
|
let requesting_user = headers.user;
|
||||||
let emergency_access =
|
let Some(emergency_access) =
|
||||||
match EmergencyAccess::find_by_uuid_and_grantee_uuid(emer_id, &requesting_user.uuid, &mut conn).await {
|
EmergencyAccess::find_by_uuid_and_grantee_uuid(emer_id, &requesting_user.uuid, &mut conn).await
|
||||||
Some(emer) => emer,
|
else {
|
||||||
None => err!("Emergency access not valid."),
|
err!("Emergency access not valid.")
|
||||||
};
|
};
|
||||||
|
|
||||||
if !is_valid_request(&emergency_access, &requesting_user.uuid, EmergencyAccessType::Takeover) {
|
if !is_valid_request(&emergency_access, &requesting_user.uuid, EmergencyAccessType::Takeover) {
|
||||||
err!("Emergency access not valid.")
|
err!("Emergency access not valid.")
|
||||||
}
|
}
|
||||||
|
|
||||||
let grantor_user = match User::find_by_uuid(&emergency_access.grantor_uuid, &mut conn).await {
|
let Some(grantor_user) = User::find_by_uuid(&emergency_access.grantor_uuid, &mut conn).await else {
|
||||||
Some(user) => user,
|
err!("Grantor user not found.")
|
||||||
None => err!("Grantor user not found."),
|
|
||||||
};
|
};
|
||||||
|
|
||||||
let policies = OrgPolicy::find_confirmed_by_user(&grantor_user.uuid, &mut conn);
|
let policies = OrgPolicy::find_confirmed_by_user(&grantor_user.uuid, &mut conn);
|
||||||
|
|
|
@ -25,16 +25,10 @@ async fn get_folders(headers: Headers, mut conn: DbConn) -> Json<Value> {
|
||||||
|
|
||||||
#[get("/folders/<uuid>")]
|
#[get("/folders/<uuid>")]
|
||||||
async fn get_folder(uuid: &str, headers: Headers, mut conn: DbConn) -> JsonResult {
|
async fn get_folder(uuid: &str, headers: Headers, mut conn: DbConn) -> JsonResult {
|
||||||
let folder = match Folder::find_by_uuid(uuid, &mut conn).await {
|
match Folder::find_by_uuid_and_user(uuid, &headers.user.uuid, &mut conn).await {
|
||||||
Some(folder) => folder,
|
Some(folder) => Ok(Json(folder.to_json())),
|
||||||
_ => err!("Invalid folder"),
|
_ => err!("Invalid folder", "Folder does not exist or belongs to another user"),
|
||||||
};
|
|
||||||
|
|
||||||
if folder.user_uuid != headers.user.uuid {
|
|
||||||
err!("Folder belongs to another user")
|
|
||||||
}
|
}
|
||||||
|
|
||||||
Ok(Json(folder.to_json()))
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Deserialize)]
|
#[derive(Deserialize)]
|
||||||
|
@ -71,15 +65,10 @@ async fn put_folder(
|
||||||
) -> JsonResult {
|
) -> JsonResult {
|
||||||
let data: FolderData = data.into_inner();
|
let data: FolderData = data.into_inner();
|
||||||
|
|
||||||
let mut folder = match Folder::find_by_uuid(uuid, &mut conn).await {
|
let Some(mut folder) = Folder::find_by_uuid_and_user(uuid, &headers.user.uuid, &mut conn).await else {
|
||||||
Some(folder) => folder,
|
err!("Invalid folder", "Folder does not exist or belongs to another user")
|
||||||
_ => err!("Invalid folder"),
|
|
||||||
};
|
};
|
||||||
|
|
||||||
if folder.user_uuid != headers.user.uuid {
|
|
||||||
err!("Folder belongs to another user")
|
|
||||||
}
|
|
||||||
|
|
||||||
folder.name = data.name;
|
folder.name = data.name;
|
||||||
|
|
||||||
folder.save(&mut conn).await?;
|
folder.save(&mut conn).await?;
|
||||||
|
@ -95,15 +84,10 @@ async fn delete_folder_post(uuid: &str, headers: Headers, conn: DbConn, nt: Noti
|
||||||
|
|
||||||
#[delete("/folders/<uuid>")]
|
#[delete("/folders/<uuid>")]
|
||||||
async fn delete_folder(uuid: &str, headers: Headers, mut conn: DbConn, nt: Notify<'_>) -> EmptyResult {
|
async fn delete_folder(uuid: &str, headers: Headers, mut conn: DbConn, nt: Notify<'_>) -> EmptyResult {
|
||||||
let folder = match Folder::find_by_uuid(uuid, &mut conn).await {
|
let Some(folder) = Folder::find_by_uuid_and_user(uuid, &headers.user.uuid, &mut conn).await else {
|
||||||
Some(folder) => folder,
|
err!("Invalid folder", "Folder does not exist or belongs to another user")
|
||||||
_ => err!("Invalid folder"),
|
|
||||||
};
|
};
|
||||||
|
|
||||||
if folder.user_uuid != headers.user.uuid {
|
|
||||||
err!("Folder belongs to another user")
|
|
||||||
}
|
|
||||||
|
|
||||||
// Delete the actual folder entry
|
// Delete the actual folder entry
|
||||||
folder.delete(&mut conn).await?;
|
folder.delete(&mut conn).await?;
|
||||||
|
|
||||||
|
|
|
@ -267,9 +267,8 @@ async fn post_organization(
|
||||||
) -> JsonResult {
|
) -> JsonResult {
|
||||||
let data: OrganizationUpdateData = data.into_inner();
|
let data: OrganizationUpdateData = data.into_inner();
|
||||||
|
|
||||||
let mut org = match Organization::find_by_uuid(org_id, &mut conn).await {
|
let Some(mut org) = Organization::find_by_uuid(org_id, &mut conn).await else {
|
||||||
Some(organization) => organization,
|
err!("Can't find organization details")
|
||||||
None => err!("Can't find organization details"),
|
|
||||||
};
|
};
|
||||||
|
|
||||||
org.name = data.name;
|
org.name = data.name;
|
||||||
|
@ -318,9 +317,8 @@ async fn get_org_collections(org_id: &str, _headers: ManagerHeadersLoose, mut co
|
||||||
async fn get_org_collections_details(org_id: &str, headers: ManagerHeadersLoose, mut conn: DbConn) -> JsonResult {
|
async fn get_org_collections_details(org_id: &str, headers: ManagerHeadersLoose, mut conn: DbConn) -> JsonResult {
|
||||||
let mut data = Vec::new();
|
let mut data = Vec::new();
|
||||||
|
|
||||||
let user_org = match UserOrganization::find_by_user_and_org(&headers.user.uuid, org_id, &mut conn).await {
|
let Some(user_org) = UserOrganization::find_by_user_and_org(&headers.user.uuid, org_id, &mut conn).await else {
|
||||||
Some(u) => u,
|
err!("User is not part of organization")
|
||||||
None => err!("User is not part of organization"),
|
|
||||||
};
|
};
|
||||||
|
|
||||||
// get all collection memberships for the current organization
|
// get all collection memberships for the current organization
|
||||||
|
@ -387,9 +385,8 @@ async fn post_organization_collections(
|
||||||
) -> JsonResult {
|
) -> JsonResult {
|
||||||
let data: NewCollectionData = data.into_inner();
|
let data: NewCollectionData = data.into_inner();
|
||||||
|
|
||||||
let org = match Organization::find_by_uuid(org_id, &mut conn).await {
|
let Some(org) = Organization::find_by_uuid(org_id, &mut conn).await else {
|
||||||
Some(organization) => organization,
|
err!("Can't find organization details")
|
||||||
None => err!("Can't find organization details"),
|
|
||||||
};
|
};
|
||||||
|
|
||||||
let collection = Collection::new(org.uuid, data.name, data.external_id);
|
let collection = Collection::new(org.uuid, data.name, data.external_id);
|
||||||
|
@ -413,9 +410,8 @@ async fn post_organization_collections(
|
||||||
}
|
}
|
||||||
|
|
||||||
for user in data.users {
|
for user in data.users {
|
||||||
let org_user = match UserOrganization::find_by_uuid(&user.id, &mut conn).await {
|
let Some(org_user) = UserOrganization::find_by_uuid_and_org(&user.id, org_id, &mut conn).await else {
|
||||||
Some(u) => u,
|
err!("User is not part of organization")
|
||||||
None => err!("User is not part of organization"),
|
|
||||||
};
|
};
|
||||||
|
|
||||||
if org_user.access_all {
|
if org_user.access_all {
|
||||||
|
@ -454,20 +450,14 @@ async fn post_organization_collection_update(
|
||||||
) -> JsonResult {
|
) -> JsonResult {
|
||||||
let data: NewCollectionData = data.into_inner();
|
let data: NewCollectionData = data.into_inner();
|
||||||
|
|
||||||
let org = match Organization::find_by_uuid(org_id, &mut conn).await {
|
if Organization::find_by_uuid(org_id, &mut conn).await.is_none() {
|
||||||
Some(organization) => organization,
|
err!("Can't find organization details")
|
||||||
None => err!("Can't find organization details"),
|
|
||||||
};
|
};
|
||||||
|
|
||||||
let mut collection = match Collection::find_by_uuid(col_id, &mut conn).await {
|
let Some(mut collection) = Collection::find_by_uuid_and_org(col_id, org_id, &mut conn).await else {
|
||||||
Some(collection) => collection,
|
err!("Collection not found")
|
||||||
None => err!("Collection not found"),
|
|
||||||
};
|
};
|
||||||
|
|
||||||
if collection.org_uuid != org.uuid {
|
|
||||||
err!("Collection is not owned by organization");
|
|
||||||
}
|
|
||||||
|
|
||||||
collection.name = data.name;
|
collection.name = data.name;
|
||||||
collection.external_id = match data.external_id {
|
collection.external_id = match data.external_id {
|
||||||
Some(external_id) if !external_id.trim().is_empty() => Some(external_id),
|
Some(external_id) if !external_id.trim().is_empty() => Some(external_id),
|
||||||
|
@ -498,9 +488,8 @@ async fn post_organization_collection_update(
|
||||||
CollectionUser::delete_all_by_collection(col_id, &mut conn).await?;
|
CollectionUser::delete_all_by_collection(col_id, &mut conn).await?;
|
||||||
|
|
||||||
for user in data.users {
|
for user in data.users {
|
||||||
let org_user = match UserOrganization::find_by_uuid(&user.id, &mut conn).await {
|
let Some(org_user) = UserOrganization::find_by_uuid_and_org(&user.id, org_id, &mut conn).await else {
|
||||||
Some(u) => u,
|
err!("User is not part of organization")
|
||||||
None => err!("User is not part of organization"),
|
|
||||||
};
|
};
|
||||||
|
|
||||||
if org_user.access_all {
|
if org_user.access_all {
|
||||||
|
@ -521,15 +510,8 @@ async fn delete_organization_collection_user(
|
||||||
_headers: AdminHeaders,
|
_headers: AdminHeaders,
|
||||||
mut conn: DbConn,
|
mut conn: DbConn,
|
||||||
) -> EmptyResult {
|
) -> EmptyResult {
|
||||||
let collection = match Collection::find_by_uuid(col_id, &mut conn).await {
|
let Some(collection) = Collection::find_by_uuid_and_org(col_id, org_id, &mut conn).await else {
|
||||||
None => err!("Collection not found"),
|
err!("Collection not found", "Collection does not exist or does not belong to this organization")
|
||||||
Some(collection) => {
|
|
||||||
if collection.org_uuid == org_id {
|
|
||||||
collection
|
|
||||||
} else {
|
|
||||||
err!("Collection and Organization id do not match")
|
|
||||||
}
|
|
||||||
}
|
|
||||||
};
|
};
|
||||||
|
|
||||||
match UserOrganization::find_by_uuid_and_org(org_user_id, org_id, &mut conn).await {
|
match UserOrganization::find_by_uuid_and_org(org_user_id, org_id, &mut conn).await {
|
||||||
|
@ -560,10 +542,9 @@ async fn _delete_organization_collection(
|
||||||
headers: &ManagerHeaders,
|
headers: &ManagerHeaders,
|
||||||
conn: &mut DbConn,
|
conn: &mut DbConn,
|
||||||
) -> EmptyResult {
|
) -> EmptyResult {
|
||||||
match Collection::find_by_uuid(col_id, conn).await {
|
let Some(collection) = Collection::find_by_uuid_and_org(col_id, org_id, conn).await else {
|
||||||
None => err!("Collection not found"),
|
err!("Collection not found", "Collection does not exist or does not belong to this organization")
|
||||||
Some(collection) => {
|
};
|
||||||
if collection.org_uuid == org_id {
|
|
||||||
log_event(
|
log_event(
|
||||||
EventType::CollectionDeleted as i32,
|
EventType::CollectionDeleted as i32,
|
||||||
&collection.uuid,
|
&collection.uuid,
|
||||||
|
@ -575,11 +556,6 @@ async fn _delete_organization_collection(
|
||||||
)
|
)
|
||||||
.await;
|
.await;
|
||||||
collection.delete(conn).await
|
collection.delete(conn).await
|
||||||
} else {
|
|
||||||
err!("Collection and Organization id do not match")
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#[delete("/organizations/<org_id>/collections/<col_id>")]
|
#[delete("/organizations/<org_id>/collections/<col_id>")]
|
||||||
|
@ -601,12 +577,11 @@ struct DeleteCollectionData {
|
||||||
org_id: String,
|
org_id: String,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[post("/organizations/<org_id>/collections/<col_id>/delete", data = "<_data>")]
|
#[post("/organizations/<org_id>/collections/<col_id>/delete")]
|
||||||
async fn post_organization_collection_delete(
|
async fn post_organization_collection_delete(
|
||||||
org_id: &str,
|
org_id: &str,
|
||||||
col_id: &str,
|
col_id: &str,
|
||||||
headers: ManagerHeaders,
|
headers: ManagerHeaders,
|
||||||
_data: Json<DeleteCollectionData>,
|
|
||||||
mut conn: DbConn,
|
mut conn: DbConn,
|
||||||
) -> EmptyResult {
|
) -> EmptyResult {
|
||||||
_delete_organization_collection(org_id, col_id, &headers, &mut conn).await
|
_delete_organization_collection(org_id, col_id, &headers, &mut conn).await
|
||||||
|
@ -651,9 +626,9 @@ async fn get_org_collection_detail(
|
||||||
err!("Collection is not owned by organization")
|
err!("Collection is not owned by organization")
|
||||||
}
|
}
|
||||||
|
|
||||||
let user_org = match UserOrganization::find_by_user_and_org(&headers.user.uuid, org_id, &mut conn).await {
|
let Some(user_org) = UserOrganization::find_by_user_and_org(&headers.user.uuid, org_id, &mut conn).await
|
||||||
Some(u) => u,
|
else {
|
||||||
None => err!("User is not part of organization"),
|
err!("User is not part of organization")
|
||||||
};
|
};
|
||||||
|
|
||||||
let groups: Vec<Value> = if CONFIG.org_groups_enabled() {
|
let groups: Vec<Value> = if CONFIG.org_groups_enabled() {
|
||||||
|
@ -695,9 +670,8 @@ async fn get_org_collection_detail(
|
||||||
#[get("/organizations/<org_id>/collections/<coll_id>/users")]
|
#[get("/organizations/<org_id>/collections/<coll_id>/users")]
|
||||||
async fn get_collection_users(org_id: &str, coll_id: &str, _headers: ManagerHeaders, mut conn: DbConn) -> JsonResult {
|
async fn get_collection_users(org_id: &str, coll_id: &str, _headers: ManagerHeaders, mut conn: DbConn) -> JsonResult {
|
||||||
// Get org and collection, check that collection is from org
|
// Get org and collection, check that collection is from org
|
||||||
let collection = match Collection::find_by_uuid_and_org(coll_id, org_id, &mut conn).await {
|
let Some(collection) = Collection::find_by_uuid_and_org(coll_id, org_id, &mut conn).await else {
|
||||||
None => err!("Collection not found in Organization"),
|
err!("Collection not found in Organization")
|
||||||
Some(collection) => collection,
|
|
||||||
};
|
};
|
||||||
|
|
||||||
let mut user_list = Vec::new();
|
let mut user_list = Vec::new();
|
||||||
|
@ -731,9 +705,8 @@ async fn put_collection_users(
|
||||||
|
|
||||||
// And then add all the received ones (except if the user has access_all)
|
// And then add all the received ones (except if the user has access_all)
|
||||||
for d in data.iter() {
|
for d in data.iter() {
|
||||||
let user = match UserOrganization::find_by_uuid(&d.id, &mut conn).await {
|
let Some(user) = UserOrganization::find_by_uuid_and_org(&d.id, org_id, &mut conn).await else {
|
||||||
Some(u) => u,
|
err!("User is not part of organization")
|
||||||
None => err!("User is not part of organization"),
|
|
||||||
};
|
};
|
||||||
|
|
||||||
if user.access_all {
|
if user.access_all {
|
||||||
|
@ -1007,18 +980,16 @@ async fn reinvite_user(org_id: &str, user_org: &str, headers: AdminHeaders, mut
|
||||||
}
|
}
|
||||||
|
|
||||||
async fn _reinvite_user(org_id: &str, user_org: &str, invited_by_email: &str, conn: &mut DbConn) -> EmptyResult {
|
async fn _reinvite_user(org_id: &str, user_org: &str, invited_by_email: &str, conn: &mut DbConn) -> EmptyResult {
|
||||||
let user_org = match UserOrganization::find_by_uuid(user_org, conn).await {
|
let Some(user_org) = UserOrganization::find_by_uuid_and_org(user_org, org_id, conn).await else {
|
||||||
Some(user_org) => user_org,
|
err!("The user hasn't been invited to the organization.")
|
||||||
None => err!("The user hasn't been invited to the organization."),
|
|
||||||
};
|
};
|
||||||
|
|
||||||
if user_org.status != UserOrgStatus::Invited as i32 {
|
if user_org.status != UserOrgStatus::Invited as i32 {
|
||||||
err!("The user is already accepted or confirmed to the organization")
|
err!("The user is already accepted or confirmed to the organization")
|
||||||
}
|
}
|
||||||
|
|
||||||
let user = match User::find_by_uuid(&user_org.user_uuid, conn).await {
|
let Some(user) = User::find_by_uuid(&user_org.user_uuid, conn).await else {
|
||||||
Some(user) => user,
|
err!("User not found.")
|
||||||
None => err!("User not found."),
|
|
||||||
};
|
};
|
||||||
|
|
||||||
if !CONFIG.invitations_allowed() && user.password_hash.is_empty() {
|
if !CONFIG.invitations_allowed() && user.password_hash.is_empty() {
|
||||||
|
@ -1059,20 +1030,25 @@ struct AcceptData {
|
||||||
reset_password_key: Option<String>,
|
reset_password_key: Option<String>,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[post("/organizations/<org_id>/users/<_org_user_id>/accept", data = "<data>")]
|
#[post("/organizations/<org_id>/users/<org_user_id>/accept", data = "<data>")]
|
||||||
async fn accept_invite(org_id: &str, _org_user_id: &str, data: Json<AcceptData>, mut conn: DbConn) -> EmptyResult {
|
async fn accept_invite(org_id: &str, org_user_id: &str, data: Json<AcceptData>, mut conn: DbConn) -> EmptyResult {
|
||||||
// The web-vault passes org_id and org_user_id in the URL, but we are just reading them from the JWT instead
|
// The web-vault passes org_id and org_user_id in the URL, but we are just reading them from the JWT instead
|
||||||
let data: AcceptData = data.into_inner();
|
let data: AcceptData = data.into_inner();
|
||||||
let claims = decode_invite(&data.token)?;
|
let claims = decode_invite(&data.token)?;
|
||||||
|
|
||||||
|
// If a claim does not have a user_org_id or it does not match the one in from the URI, something is wrong.
|
||||||
|
match &claims.user_org_id {
|
||||||
|
Some(ou_id) if ou_id.eq(org_user_id) => {}
|
||||||
|
_ => err!("Error accepting the invitation", "Claim does not match the org_user_id"),
|
||||||
|
}
|
||||||
|
|
||||||
match User::find_by_mail(&claims.email, &mut conn).await {
|
match User::find_by_mail(&claims.email, &mut conn).await {
|
||||||
Some(user) => {
|
Some(user) => {
|
||||||
Invitation::take(&claims.email, &mut conn).await;
|
Invitation::take(&claims.email, &mut conn).await;
|
||||||
|
|
||||||
if let (Some(user_org), Some(org)) = (&claims.user_org_id, &claims.org_id) {
|
if let (Some(user_org), Some(org)) = (&claims.user_org_id, &claims.org_id) {
|
||||||
let mut user_org = match UserOrganization::find_by_uuid_and_org(user_org, org, &mut conn).await {
|
let Some(mut user_org) = UserOrganization::find_by_uuid_and_org(user_org, org, &mut conn).await else {
|
||||||
Some(user_org) => user_org,
|
err!("Error accepting the invitation")
|
||||||
None => err!("Error accepting the invitation"),
|
|
||||||
};
|
};
|
||||||
|
|
||||||
if user_org.status != UserOrgStatus::Invited as i32 {
|
if user_org.status != UserOrgStatus::Invited as i32 {
|
||||||
|
@ -1213,9 +1189,8 @@ async fn _confirm_invite(
|
||||||
err!("Key or UserId is not set, unable to process request");
|
err!("Key or UserId is not set, unable to process request");
|
||||||
}
|
}
|
||||||
|
|
||||||
let mut user_to_confirm = match UserOrganization::find_by_uuid_and_org(org_user_id, org_id, conn).await {
|
let Some(mut user_to_confirm) = UserOrganization::find_by_uuid_and_org(org_user_id, org_id, conn).await else {
|
||||||
Some(user) => user,
|
err!("The specified user isn't a member of the organization")
|
||||||
None => err!("The specified user isn't a member of the organization"),
|
|
||||||
};
|
};
|
||||||
|
|
||||||
if user_to_confirm.atype != UserOrgType::User && headers.org_user_type != UserOrgType::Owner {
|
if user_to_confirm.atype != UserOrgType::User && headers.org_user_type != UserOrgType::Owner {
|
||||||
|
@ -1287,9 +1262,8 @@ async fn get_user(
|
||||||
_headers: AdminHeaders,
|
_headers: AdminHeaders,
|
||||||
mut conn: DbConn,
|
mut conn: DbConn,
|
||||||
) -> JsonResult {
|
) -> JsonResult {
|
||||||
let user = match UserOrganization::find_by_uuid_and_org(org_user_id, org_id, &mut conn).await {
|
let Some(user) = UserOrganization::find_by_uuid_and_org(org_user_id, org_id, &mut conn).await else {
|
||||||
Some(user) => user,
|
err!("The specified user isn't a member of the organization")
|
||||||
None => err!("The specified user isn't a member of the organization"),
|
|
||||||
};
|
};
|
||||||
|
|
||||||
// In this case, when groups are requested we also need to include collections.
|
// In this case, when groups are requested we also need to include collections.
|
||||||
|
@ -1331,14 +1305,12 @@ async fn edit_user(
|
||||||
) -> EmptyResult {
|
) -> EmptyResult {
|
||||||
let data: EditUserData = data.into_inner();
|
let data: EditUserData = data.into_inner();
|
||||||
|
|
||||||
let new_type = match UserOrgType::from_str(&data.r#type.into_string()) {
|
let Some(new_type) = UserOrgType::from_str(&data.r#type.into_string()) else {
|
||||||
Some(new_type) => new_type,
|
err!("Invalid type")
|
||||||
None => err!("Invalid type"),
|
|
||||||
};
|
};
|
||||||
|
|
||||||
let mut user_to_edit = match UserOrganization::find_by_uuid_and_org(org_user_id, org_id, &mut conn).await {
|
let Some(mut user_to_edit) = UserOrganization::find_by_uuid_and_org(org_user_id, org_id, &mut conn).await else {
|
||||||
Some(user) => user,
|
err!("The specified user isn't member of the organization")
|
||||||
None => err!("The specified user isn't member of the organization"),
|
|
||||||
};
|
};
|
||||||
|
|
||||||
if new_type != user_to_edit.atype
|
if new_type != user_to_edit.atype
|
||||||
|
@ -1490,9 +1462,8 @@ async fn _delete_user(
|
||||||
conn: &mut DbConn,
|
conn: &mut DbConn,
|
||||||
nt: &Notify<'_>,
|
nt: &Notify<'_>,
|
||||||
) -> EmptyResult {
|
) -> EmptyResult {
|
||||||
let user_to_delete = match UserOrganization::find_by_uuid_and_org(org_user_id, org_id, conn).await {
|
let Some(user_to_delete) = UserOrganization::find_by_uuid_and_org(org_user_id, org_id, conn).await else {
|
||||||
Some(user) => user,
|
err!("User to delete isn't member of the organization")
|
||||||
None => err!("User to delete isn't member of the organization"),
|
|
||||||
};
|
};
|
||||||
|
|
||||||
if user_to_delete.atype != UserOrgType::User && headers.org_user_type != UserOrgType::Owner {
|
if user_to_delete.atype != UserOrgType::User && headers.org_user_type != UserOrgType::Owner {
|
||||||
|
@ -1725,9 +1696,8 @@ async fn list_policies_token(org_id: &str, token: &str, mut conn: DbConn) -> Jso
|
||||||
|
|
||||||
let invite = decode_invite(token)?;
|
let invite = decode_invite(token)?;
|
||||||
|
|
||||||
let invite_org_id = match invite.org_id {
|
let Some(invite_org_id) = invite.org_id else {
|
||||||
Some(invite_org_id) => invite_org_id,
|
err!("Invalid token")
|
||||||
None => err!("Invalid token"),
|
|
||||||
};
|
};
|
||||||
|
|
||||||
if invite_org_id != org_id {
|
if invite_org_id != org_id {
|
||||||
|
@ -1747,9 +1717,8 @@ async fn list_policies_token(org_id: &str, token: &str, mut conn: DbConn) -> Jso
|
||||||
|
|
||||||
#[get("/organizations/<org_id>/policies/<pol_type>")]
|
#[get("/organizations/<org_id>/policies/<pol_type>")]
|
||||||
async fn get_policy(org_id: &str, pol_type: i32, _headers: AdminHeaders, mut conn: DbConn) -> JsonResult {
|
async fn get_policy(org_id: &str, pol_type: i32, _headers: AdminHeaders, mut conn: DbConn) -> JsonResult {
|
||||||
let pol_type_enum = match OrgPolicyType::from_i32(pol_type) {
|
let Some(pol_type_enum) = OrgPolicyType::from_i32(pol_type) else {
|
||||||
Some(pt) => pt,
|
err!("Invalid or unsupported policy type")
|
||||||
None => err!("Invalid or unsupported policy type"),
|
|
||||||
};
|
};
|
||||||
|
|
||||||
let policy = match OrgPolicy::find_by_org_and_type(org_id, pol_type_enum, &mut conn).await {
|
let policy = match OrgPolicy::find_by_org_and_type(org_id, pol_type_enum, &mut conn).await {
|
||||||
|
@ -1778,9 +1747,8 @@ async fn put_policy(
|
||||||
) -> JsonResult {
|
) -> JsonResult {
|
||||||
let data: PolicyData = data.into_inner();
|
let data: PolicyData = data.into_inner();
|
||||||
|
|
||||||
let pol_type_enum = match OrgPolicyType::from_i32(pol_type) {
|
let Some(pol_type_enum) = OrgPolicyType::from_i32(pol_type) else {
|
||||||
Some(pt) => pt,
|
err!("Invalid or unsupported policy type")
|
||||||
None => err!("Invalid or unsupported policy type"),
|
|
||||||
};
|
};
|
||||||
|
|
||||||
// Bitwarden only allows the Reset Password policy when Single Org policy is enabled
|
// Bitwarden only allows the Reset Password policy when Single Org policy is enabled
|
||||||
|
@ -2437,9 +2405,8 @@ async fn put_group(
|
||||||
err!("Group support is disabled");
|
err!("Group support is disabled");
|
||||||
}
|
}
|
||||||
|
|
||||||
let group = match Group::find_by_uuid(group_id, &mut conn).await {
|
let Some(group) = Group::find_by_uuid_and_org(group_id, org_id, &mut conn).await else {
|
||||||
Some(group) => group,
|
err!("Group not found", "Group uuid is invalid or does not belong to the organization")
|
||||||
None => err!("Group not found"),
|
|
||||||
};
|
};
|
||||||
|
|
||||||
let group_request = data.into_inner();
|
let group_request = data.into_inner();
|
||||||
|
@ -2502,15 +2469,14 @@ async fn add_update_group(
|
||||||
})))
|
})))
|
||||||
}
|
}
|
||||||
|
|
||||||
#[get("/organizations/<_org_id>/groups/<group_id>/details")]
|
#[get("/organizations/<org_id>/groups/<group_id>/details")]
|
||||||
async fn get_group_details(_org_id: &str, group_id: &str, _headers: AdminHeaders, mut conn: DbConn) -> JsonResult {
|
async fn get_group_details(org_id: &str, group_id: &str, _headers: AdminHeaders, mut conn: DbConn) -> JsonResult {
|
||||||
if !CONFIG.org_groups_enabled() {
|
if !CONFIG.org_groups_enabled() {
|
||||||
err!("Group support is disabled");
|
err!("Group support is disabled");
|
||||||
}
|
}
|
||||||
|
|
||||||
let group = match Group::find_by_uuid(group_id, &mut conn).await {
|
let Some(group) = Group::find_by_uuid_and_org(group_id, org_id, &mut conn).await else {
|
||||||
Some(group) => group,
|
err!("Group not found", "Group uuid is invalid or does not belong to the organization")
|
||||||
_ => err!("Group could not be found!"),
|
|
||||||
};
|
};
|
||||||
|
|
||||||
Ok(Json(group.to_json_details(&mut conn).await))
|
Ok(Json(group.to_json_details(&mut conn).await))
|
||||||
|
@ -2531,9 +2497,8 @@ async fn _delete_group(org_id: &str, group_id: &str, headers: &AdminHeaders, con
|
||||||
err!("Group support is disabled");
|
err!("Group support is disabled");
|
||||||
}
|
}
|
||||||
|
|
||||||
let group = match Group::find_by_uuid(group_id, conn).await {
|
let Some(group) = Group::find_by_uuid_and_org(group_id, org_id, conn).await else {
|
||||||
Some(group) => group,
|
err!("Group not found", "Group uuid is invalid or does not belong to the organization")
|
||||||
_ => err!("Group not found"),
|
|
||||||
};
|
};
|
||||||
|
|
||||||
log_event(
|
log_event(
|
||||||
|
@ -2569,29 +2534,27 @@ async fn bulk_delete_groups(
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
#[get("/organizations/<_org_id>/groups/<group_id>")]
|
#[get("/organizations/<org_id>/groups/<group_id>")]
|
||||||
async fn get_group(_org_id: &str, group_id: &str, _headers: AdminHeaders, mut conn: DbConn) -> JsonResult {
|
async fn get_group(org_id: &str, group_id: &str, _headers: AdminHeaders, mut conn: DbConn) -> JsonResult {
|
||||||
if !CONFIG.org_groups_enabled() {
|
if !CONFIG.org_groups_enabled() {
|
||||||
err!("Group support is disabled");
|
err!("Group support is disabled");
|
||||||
}
|
}
|
||||||
|
|
||||||
let group = match Group::find_by_uuid(group_id, &mut conn).await {
|
let Some(group) = Group::find_by_uuid_and_org(group_id, org_id, &mut conn).await else {
|
||||||
Some(group) => group,
|
err!("Group not found", "Group uuid is invalid or does not belong to the organization")
|
||||||
_ => err!("Group not found"),
|
|
||||||
};
|
};
|
||||||
|
|
||||||
Ok(Json(group.to_json()))
|
Ok(Json(group.to_json()))
|
||||||
}
|
}
|
||||||
|
|
||||||
#[get("/organizations/<_org_id>/groups/<group_id>/users")]
|
#[get("/organizations/<org_id>/groups/<group_id>/users")]
|
||||||
async fn get_group_users(_org_id: &str, group_id: &str, _headers: AdminHeaders, mut conn: DbConn) -> JsonResult {
|
async fn get_group_users(org_id: &str, group_id: &str, _headers: AdminHeaders, mut conn: DbConn) -> JsonResult {
|
||||||
if !CONFIG.org_groups_enabled() {
|
if !CONFIG.org_groups_enabled() {
|
||||||
err!("Group support is disabled");
|
err!("Group support is disabled");
|
||||||
}
|
}
|
||||||
|
|
||||||
match Group::find_by_uuid(group_id, &mut conn).await {
|
if Group::find_by_uuid_and_org(group_id, org_id, &mut conn).await.is_none() {
|
||||||
Some(_) => { /* Do nothing */ }
|
err!("Group could not be found!", "Group uuid is invalid or does not belong to the organization")
|
||||||
_ => err!("Group could not be found!"),
|
|
||||||
};
|
};
|
||||||
|
|
||||||
let group_users: Vec<String> = GroupUser::find_by_group(group_id, &mut conn)
|
let group_users: Vec<String> = GroupUser::find_by_group(group_id, &mut conn)
|
||||||
|
@ -2615,9 +2578,8 @@ async fn put_group_users(
|
||||||
err!("Group support is disabled");
|
err!("Group support is disabled");
|
||||||
}
|
}
|
||||||
|
|
||||||
match Group::find_by_uuid(group_id, &mut conn).await {
|
if Group::find_by_uuid_and_org(group_id, org_id, &mut conn).await.is_none() {
|
||||||
Some(_) => { /* Do nothing */ }
|
err!("Group could not be found!", "Group uuid is invalid or does not belong to the organization")
|
||||||
_ => err!("Group could not be found!"),
|
|
||||||
};
|
};
|
||||||
|
|
||||||
GroupUser::delete_all_by_group(group_id, &mut conn).await?;
|
GroupUser::delete_all_by_group(group_id, &mut conn).await?;
|
||||||
|
@ -2642,15 +2604,14 @@ async fn put_group_users(
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
#[get("/organizations/<_org_id>/users/<user_id>/groups")]
|
#[get("/organizations/<org_id>/users/<user_id>/groups")]
|
||||||
async fn get_user_groups(_org_id: &str, user_id: &str, _headers: AdminHeaders, mut conn: DbConn) -> JsonResult {
|
async fn get_user_groups(org_id: &str, user_id: &str, _headers: AdminHeaders, mut conn: DbConn) -> JsonResult {
|
||||||
if !CONFIG.org_groups_enabled() {
|
if !CONFIG.org_groups_enabled() {
|
||||||
err!("Group support is disabled");
|
err!("Group support is disabled");
|
||||||
}
|
}
|
||||||
|
|
||||||
match UserOrganization::find_by_uuid(user_id, &mut conn).await {
|
if UserOrganization::find_by_uuid_and_org(user_id, org_id, &mut conn).await.is_none() {
|
||||||
Some(_) => { /* Do nothing */ }
|
err!("User could not be found!")
|
||||||
_ => err!("User could not be found!"),
|
|
||||||
};
|
};
|
||||||
|
|
||||||
let user_groups: Vec<String> =
|
let user_groups: Vec<String> =
|
||||||
|
@ -2688,13 +2649,8 @@ async fn put_user_groups(
|
||||||
err!("Group support is disabled");
|
err!("Group support is disabled");
|
||||||
}
|
}
|
||||||
|
|
||||||
let user_org = match UserOrganization::find_by_uuid(org_user_id, &mut conn).await {
|
if UserOrganization::find_by_uuid_and_org(org_user_id, org_id, &mut conn).await.is_none() {
|
||||||
Some(uo) => uo,
|
err!("User could not be found or does not belong to the organization.");
|
||||||
_ => err!("User could not be found!"),
|
|
||||||
};
|
|
||||||
|
|
||||||
if user_org.org_uuid != org_id {
|
|
||||||
err!("Group doesn't belong to organization");
|
|
||||||
}
|
}
|
||||||
|
|
||||||
GroupUser::delete_all_by_user(org_user_id, &mut conn).await?;
|
GroupUser::delete_all_by_user(org_user_id, &mut conn).await?;
|
||||||
|
@ -2742,22 +2698,12 @@ async fn delete_group_user(
|
||||||
err!("Group support is disabled");
|
err!("Group support is disabled");
|
||||||
}
|
}
|
||||||
|
|
||||||
let user_org = match UserOrganization::find_by_uuid(org_user_id, &mut conn).await {
|
if UserOrganization::find_by_uuid_and_org(org_user_id, org_id, &mut conn).await.is_none() {
|
||||||
Some(uo) => uo,
|
err!("User could not be found or does not belong to the organization.");
|
||||||
_ => err!("User could not be found!"),
|
|
||||||
};
|
|
||||||
|
|
||||||
if user_org.org_uuid != org_id {
|
|
||||||
err!("User doesn't belong to organization");
|
|
||||||
}
|
}
|
||||||
|
|
||||||
let group = match Group::find_by_uuid(group_id, &mut conn).await {
|
if Group::find_by_uuid_and_org(group_id, org_id, &mut conn).await.is_none() {
|
||||||
Some(g) => g,
|
err!("Group could not be found or does not belong to the organization.");
|
||||||
_ => err!("Group could not be found!"),
|
|
||||||
};
|
|
||||||
|
|
||||||
if group.organizations_uuid != org_id {
|
|
||||||
err!("Group doesn't belong to organization");
|
|
||||||
}
|
}
|
||||||
|
|
||||||
log_event(
|
log_event(
|
||||||
|
@ -2794,9 +2740,8 @@ struct OrganizationUserResetPasswordRequest {
|
||||||
// Just add it here in case they will
|
// Just add it here in case they will
|
||||||
#[get("/organizations/<org_id>/public-key")]
|
#[get("/organizations/<org_id>/public-key")]
|
||||||
async fn get_organization_public_key(org_id: &str, _headers: Headers, mut conn: DbConn) -> JsonResult {
|
async fn get_organization_public_key(org_id: &str, _headers: Headers, mut conn: DbConn) -> JsonResult {
|
||||||
let org = match Organization::find_by_uuid(org_id, &mut conn).await {
|
let Some(org) = Organization::find_by_uuid(org_id, &mut conn).await else {
|
||||||
Some(organization) => organization,
|
err!("Organization not found")
|
||||||
None => err!("Organization not found"),
|
|
||||||
};
|
};
|
||||||
|
|
||||||
Ok(Json(json!({
|
Ok(Json(json!({
|
||||||
|
@ -2821,19 +2766,16 @@ async fn put_reset_password(
|
||||||
mut conn: DbConn,
|
mut conn: DbConn,
|
||||||
nt: Notify<'_>,
|
nt: Notify<'_>,
|
||||||
) -> EmptyResult {
|
) -> EmptyResult {
|
||||||
let org = match Organization::find_by_uuid(org_id, &mut conn).await {
|
let Some(org) = Organization::find_by_uuid(org_id, &mut conn).await else {
|
||||||
Some(org) => org,
|
err!("Required organization not found")
|
||||||
None => err!("Required organization not found"),
|
|
||||||
};
|
};
|
||||||
|
|
||||||
let org_user = match UserOrganization::find_by_uuid_and_org(org_user_id, &org.uuid, &mut conn).await {
|
let Some(org_user) = UserOrganization::find_by_uuid_and_org(org_user_id, &org.uuid, &mut conn).await else {
|
||||||
Some(user) => user,
|
err!("User to reset isn't member of required organization")
|
||||||
None => err!("User to reset isn't member of required organization"),
|
|
||||||
};
|
};
|
||||||
|
|
||||||
let user = match User::find_by_uuid(&org_user.user_uuid, &mut conn).await {
|
let Some(user) = User::find_by_uuid(&org_user.user_uuid, &mut conn).await else {
|
||||||
Some(user) => user,
|
err!("User not found")
|
||||||
None => err!("User not found"),
|
|
||||||
};
|
};
|
||||||
|
|
||||||
check_reset_password_applicable_and_permissions(org_id, org_user_id, &headers, &mut conn).await?;
|
check_reset_password_applicable_and_permissions(org_id, org_user_id, &headers, &mut conn).await?;
|
||||||
|
@ -2880,19 +2822,16 @@ async fn get_reset_password_details(
|
||||||
headers: AdminHeaders,
|
headers: AdminHeaders,
|
||||||
mut conn: DbConn,
|
mut conn: DbConn,
|
||||||
) -> JsonResult {
|
) -> JsonResult {
|
||||||
let org = match Organization::find_by_uuid(org_id, &mut conn).await {
|
let Some(org) = Organization::find_by_uuid(org_id, &mut conn).await else {
|
||||||
Some(org) => org,
|
err!("Required organization not found")
|
||||||
None => err!("Required organization not found"),
|
|
||||||
};
|
};
|
||||||
|
|
||||||
let org_user = match UserOrganization::find_by_uuid_and_org(org_user_id, org_id, &mut conn).await {
|
let Some(org_user) = UserOrganization::find_by_uuid_and_org(org_user_id, org_id, &mut conn).await else {
|
||||||
Some(user) => user,
|
err!("User to reset isn't member of required organization")
|
||||||
None => err!("User to reset isn't member of required organization"),
|
|
||||||
};
|
};
|
||||||
|
|
||||||
let user = match User::find_by_uuid(&org_user.user_uuid, &mut conn).await {
|
let Some(user) = User::find_by_uuid(&org_user.user_uuid, &mut conn).await else {
|
||||||
Some(user) => user,
|
err!("User not found")
|
||||||
None => err!("User not found"),
|
|
||||||
};
|
};
|
||||||
|
|
||||||
check_reset_password_applicable_and_permissions(org_id, org_user_id, &headers, &mut conn).await?;
|
check_reset_password_applicable_and_permissions(org_id, org_user_id, &headers, &mut conn).await?;
|
||||||
|
@ -2918,9 +2857,8 @@ async fn check_reset_password_applicable_and_permissions(
|
||||||
) -> EmptyResult {
|
) -> EmptyResult {
|
||||||
check_reset_password_applicable(org_id, conn).await?;
|
check_reset_password_applicable(org_id, conn).await?;
|
||||||
|
|
||||||
let target_user = match UserOrganization::find_by_uuid_and_org(org_user_id, org_id, conn).await {
|
let Some(target_user) = UserOrganization::find_by_uuid_and_org(org_user_id, org_id, conn).await else {
|
||||||
Some(user) => user,
|
err!("Reset target user not found")
|
||||||
None => err!("Reset target user not found"),
|
|
||||||
};
|
};
|
||||||
|
|
||||||
// Resetting user must be higher/equal to user to reset
|
// Resetting user must be higher/equal to user to reset
|
||||||
|
@ -2936,9 +2874,8 @@ async fn check_reset_password_applicable(org_id: &str, conn: &mut DbConn) -> Emp
|
||||||
err!("Password reset is not supported on an email-disabled instance.");
|
err!("Password reset is not supported on an email-disabled instance.");
|
||||||
}
|
}
|
||||||
|
|
||||||
let policy = match OrgPolicy::find_by_org_and_type(org_id, OrgPolicyType::ResetPassword, conn).await {
|
let Some(policy) = OrgPolicy::find_by_org_and_type(org_id, OrgPolicyType::ResetPassword, conn).await else {
|
||||||
Some(p) => p,
|
err!("Policy not found")
|
||||||
None => err!("Policy not found"),
|
|
||||||
};
|
};
|
||||||
|
|
||||||
if !policy.enabled {
|
if !policy.enabled {
|
||||||
|
@ -2956,9 +2893,8 @@ async fn put_reset_password_enrollment(
|
||||||
data: Json<OrganizationUserResetPasswordEnrollmentRequest>,
|
data: Json<OrganizationUserResetPasswordEnrollmentRequest>,
|
||||||
mut conn: DbConn,
|
mut conn: DbConn,
|
||||||
) -> EmptyResult {
|
) -> EmptyResult {
|
||||||
let mut org_user = match UserOrganization::find_by_user_and_org(&headers.user.uuid, org_id, &mut conn).await {
|
let Some(mut org_user) = UserOrganization::find_by_user_and_org(&headers.user.uuid, org_id, &mut conn).await else {
|
||||||
Some(u) => u,
|
err!("User to enroll isn't member of required organization")
|
||||||
None => err!("User to enroll isn't member of required organization"),
|
|
||||||
};
|
};
|
||||||
|
|
||||||
check_reset_password_applicable(org_id, &mut conn).await?;
|
check_reset_password_applicable(org_id, &mut conn).await?;
|
||||||
|
|
|
@ -203,9 +203,8 @@ impl<'r> FromRequest<'r> for PublicToken {
|
||||||
None => err_handler!("No access token provided"),
|
None => err_handler!("No access token provided"),
|
||||||
};
|
};
|
||||||
// Check JWT token is valid and get device and user from it
|
// Check JWT token is valid and get device and user from it
|
||||||
let claims = match auth::decode_api_org(access_token) {
|
let Ok(claims) = auth::decode_api_org(access_token) else {
|
||||||
Ok(claims) => claims,
|
err_handler!("Invalid claim")
|
||||||
Err(_) => err_handler!("Invalid claim"),
|
|
||||||
};
|
};
|
||||||
// Check if time is between claims.nbf and claims.exp
|
// Check if time is between claims.nbf and claims.exp
|
||||||
let time_now = Utc::now().timestamp();
|
let time_now = Utc::now().timestamp();
|
||||||
|
@ -227,13 +226,11 @@ impl<'r> FromRequest<'r> for PublicToken {
|
||||||
Outcome::Success(conn) => conn,
|
Outcome::Success(conn) => conn,
|
||||||
_ => err_handler!("Error getting DB"),
|
_ => err_handler!("Error getting DB"),
|
||||||
};
|
};
|
||||||
let org_uuid = match claims.client_id.strip_prefix("organization.") {
|
let Some(org_uuid) = claims.client_id.strip_prefix("organization.") else {
|
||||||
Some(uuid) => uuid,
|
err_handler!("Malformed client_id")
|
||||||
None => err_handler!("Malformed client_id"),
|
|
||||||
};
|
};
|
||||||
let org_api_key = match OrganizationApiKey::find_by_org_uuid(org_uuid, &conn).await {
|
let Some(org_api_key) = OrganizationApiKey::find_by_org_uuid(org_uuid, &conn).await else {
|
||||||
Some(org_api_key) => org_api_key,
|
err_handler!("Invalid client_id")
|
||||||
None => err_handler!("Invalid client_id"),
|
|
||||||
};
|
};
|
||||||
if org_api_key.org_uuid != claims.client_sub {
|
if org_api_key.org_uuid != claims.client_sub {
|
||||||
err_handler!("Token not issued for this org");
|
err_handler!("Token not issued for this org");
|
||||||
|
|
|
@ -159,16 +159,10 @@ async fn get_sends(headers: Headers, mut conn: DbConn) -> Json<Value> {
|
||||||
|
|
||||||
#[get("/sends/<uuid>")]
|
#[get("/sends/<uuid>")]
|
||||||
async fn get_send(uuid: &str, headers: Headers, mut conn: DbConn) -> JsonResult {
|
async fn get_send(uuid: &str, headers: Headers, mut conn: DbConn) -> JsonResult {
|
||||||
let send = match Send::find_by_uuid(uuid, &mut conn).await {
|
match Send::find_by_uuid_and_user(uuid, &headers.user.uuid, &mut conn).await {
|
||||||
Some(send) => send,
|
Some(send) => Ok(Json(send.to_json())),
|
||||||
None => err!("Send not found"),
|
None => err!("Send not found", "Invalid uuid or does not belong to user"),
|
||||||
};
|
|
||||||
|
|
||||||
if send.user_uuid.as_ref() != Some(&headers.user.uuid) {
|
|
||||||
err!("Send is not owned by user")
|
|
||||||
}
|
}
|
||||||
|
|
||||||
Ok(Json(send.to_json()))
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#[post("/sends", data = "<data>")]
|
#[post("/sends", data = "<data>")]
|
||||||
|
@ -371,22 +365,14 @@ async fn post_send_file_v2_data(
|
||||||
|
|
||||||
let mut data = data.into_inner();
|
let mut data = data.into_inner();
|
||||||
|
|
||||||
let Some(send) = Send::find_by_uuid(send_uuid, &mut conn).await else {
|
let Some(send) = Send::find_by_uuid_and_user(send_uuid, &headers.user.uuid, &mut conn).await else {
|
||||||
err!("Send not found. Unable to save the file.")
|
err!("Send not found. Unable to save the file.", "Invalid uuid or does not belong to user.")
|
||||||
};
|
};
|
||||||
|
|
||||||
if send.atype != SendType::File as i32 {
|
if send.atype != SendType::File as i32 {
|
||||||
err!("Send is not a file type send.");
|
err!("Send is not a file type send.");
|
||||||
}
|
}
|
||||||
|
|
||||||
let Some(send_user_id) = &send.user_uuid else {
|
|
||||||
err!("Sends are only supported for users at the moment.")
|
|
||||||
};
|
|
||||||
|
|
||||||
if send_user_id != &headers.user.uuid {
|
|
||||||
err!("Send doesn't belong to user.");
|
|
||||||
}
|
|
||||||
|
|
||||||
let Ok(send_data) = serde_json::from_str::<SendFileData>(&send.data) else {
|
let Ok(send_data) = serde_json::from_str::<SendFileData>(&send.data) else {
|
||||||
err!("Unable to decode send data as json.")
|
err!("Unable to decode send data as json.")
|
||||||
};
|
};
|
||||||
|
@ -456,9 +442,8 @@ async fn post_access(
|
||||||
ip: ClientIp,
|
ip: ClientIp,
|
||||||
nt: Notify<'_>,
|
nt: Notify<'_>,
|
||||||
) -> JsonResult {
|
) -> JsonResult {
|
||||||
let mut send = match Send::find_by_access_id(access_id, &mut conn).await {
|
let Some(mut send) = Send::find_by_access_id(access_id, &mut conn).await else {
|
||||||
Some(s) => s,
|
err_code!(SEND_INACCESSIBLE_MSG, 404)
|
||||||
None => err_code!(SEND_INACCESSIBLE_MSG, 404),
|
|
||||||
};
|
};
|
||||||
|
|
||||||
if let Some(max_access_count) = send.max_access_count {
|
if let Some(max_access_count) = send.max_access_count {
|
||||||
|
@ -517,9 +502,8 @@ async fn post_access_file(
|
||||||
mut conn: DbConn,
|
mut conn: DbConn,
|
||||||
nt: Notify<'_>,
|
nt: Notify<'_>,
|
||||||
) -> JsonResult {
|
) -> JsonResult {
|
||||||
let mut send = match Send::find_by_uuid(send_id, &mut conn).await {
|
let Some(mut send) = Send::find_by_uuid(send_id, &mut conn).await else {
|
||||||
Some(s) => s,
|
err_code!(SEND_INACCESSIBLE_MSG, 404)
|
||||||
None => err_code!(SEND_INACCESSIBLE_MSG, 404),
|
|
||||||
};
|
};
|
||||||
|
|
||||||
if let Some(max_access_count) = send.max_access_count {
|
if let Some(max_access_count) = send.max_access_count {
|
||||||
|
@ -582,16 +566,15 @@ async fn download_send(send_id: SafeString, file_id: SafeString, t: &str) -> Opt
|
||||||
None
|
None
|
||||||
}
|
}
|
||||||
|
|
||||||
#[put("/sends/<id>", data = "<data>")]
|
#[put("/sends/<uuid>", data = "<data>")]
|
||||||
async fn put_send(id: &str, data: Json<SendData>, headers: Headers, mut conn: DbConn, nt: Notify<'_>) -> JsonResult {
|
async fn put_send(uuid: &str, data: Json<SendData>, headers: Headers, mut conn: DbConn, nt: Notify<'_>) -> JsonResult {
|
||||||
enforce_disable_send_policy(&headers, &mut conn).await?;
|
enforce_disable_send_policy(&headers, &mut conn).await?;
|
||||||
|
|
||||||
let data: SendData = data.into_inner();
|
let data: SendData = data.into_inner();
|
||||||
enforce_disable_hide_email_policy(&data, &headers, &mut conn).await?;
|
enforce_disable_hide_email_policy(&data, &headers, &mut conn).await?;
|
||||||
|
|
||||||
let mut send = match Send::find_by_uuid(id, &mut conn).await {
|
let Some(mut send) = Send::find_by_uuid_and_user(uuid, &headers.user.uuid, &mut conn).await else {
|
||||||
Some(s) => s,
|
err!("Send not found", "Send uuid is invalid or does not belong to user")
|
||||||
None => err!("Send not found"),
|
|
||||||
};
|
};
|
||||||
|
|
||||||
update_send_from_data(&mut send, data, &headers, &mut conn, &nt, UpdateType::SyncSendUpdate).await?;
|
update_send_from_data(&mut send, data, &headers, &mut conn, &nt, UpdateType::SyncSendUpdate).await?;
|
||||||
|
@ -657,17 +640,12 @@ pub async fn update_send_from_data(
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
#[delete("/sends/<id>")]
|
#[delete("/sends/<uuid>")]
|
||||||
async fn delete_send(id: &str, headers: Headers, mut conn: DbConn, nt: Notify<'_>) -> EmptyResult {
|
async fn delete_send(uuid: &str, headers: Headers, mut conn: DbConn, nt: Notify<'_>) -> EmptyResult {
|
||||||
let send = match Send::find_by_uuid(id, &mut conn).await {
|
let Some(send) = Send::find_by_uuid_and_user(uuid, &headers.user.uuid, &mut conn).await else {
|
||||||
Some(s) => s,
|
err!("Send not found", "Invalid send uuid, or does not belong to user")
|
||||||
None => err!("Send not found"),
|
|
||||||
};
|
};
|
||||||
|
|
||||||
if send.user_uuid.as_ref() != Some(&headers.user.uuid) {
|
|
||||||
err!("Send is not owned by user")
|
|
||||||
}
|
|
||||||
|
|
||||||
send.delete(&mut conn).await?;
|
send.delete(&mut conn).await?;
|
||||||
nt.send_send_update(
|
nt.send_send_update(
|
||||||
UpdateType::SyncSendDelete,
|
UpdateType::SyncSendDelete,
|
||||||
|
@ -681,19 +659,14 @@ async fn delete_send(id: &str, headers: Headers, mut conn: DbConn, nt: Notify<'_
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
#[put("/sends/<id>/remove-password")]
|
#[put("/sends/<uuid>/remove-password")]
|
||||||
async fn put_remove_password(id: &str, headers: Headers, mut conn: DbConn, nt: Notify<'_>) -> JsonResult {
|
async fn put_remove_password(uuid: &str, headers: Headers, mut conn: DbConn, nt: Notify<'_>) -> JsonResult {
|
||||||
enforce_disable_send_policy(&headers, &mut conn).await?;
|
enforce_disable_send_policy(&headers, &mut conn).await?;
|
||||||
|
|
||||||
let mut send = match Send::find_by_uuid(id, &mut conn).await {
|
let Some(mut send) = Send::find_by_uuid_and_user(uuid, &headers.user.uuid, &mut conn).await else {
|
||||||
Some(s) => s,
|
err!("Send not found", "Invalid send uuid, or does not belong to user")
|
||||||
None => err!("Send not found"),
|
|
||||||
};
|
};
|
||||||
|
|
||||||
if send.user_uuid.as_ref() != Some(&headers.user.uuid) {
|
|
||||||
err!("Send is not owned by user")
|
|
||||||
}
|
|
||||||
|
|
||||||
send.set_password(None);
|
send.set_password(None);
|
||||||
send.save(&mut conn).await?;
|
send.save(&mut conn).await?;
|
||||||
nt.send_send_update(
|
nt.send_send_update(
|
||||||
|
|
|
@ -117,9 +117,8 @@ pub async fn validate_totp_code(
|
||||||
) -> EmptyResult {
|
) -> EmptyResult {
|
||||||
use totp_lite::{totp_custom, Sha1};
|
use totp_lite::{totp_custom, Sha1};
|
||||||
|
|
||||||
let decoded_secret = match BASE32.decode(secret.as_bytes()) {
|
let Ok(decoded_secret) = BASE32.decode(secret.as_bytes()) else {
|
||||||
Ok(s) => s,
|
err!("Invalid TOTP secret")
|
||||||
Err(_) => err!("Invalid TOTP secret"),
|
|
||||||
};
|
};
|
||||||
|
|
||||||
let mut twofactor =
|
let mut twofactor =
|
||||||
|
|
|
@ -232,9 +232,8 @@ async fn get_user_duo_data(uuid: &str, conn: &mut DbConn) -> DuoStatus {
|
||||||
let type_ = TwoFactorType::Duo as i32;
|
let type_ = TwoFactorType::Duo as i32;
|
||||||
|
|
||||||
// If the user doesn't have an entry, disabled
|
// If the user doesn't have an entry, disabled
|
||||||
let twofactor = match TwoFactor::find_by_user_and_type(uuid, type_, conn).await {
|
let Some(twofactor) = TwoFactor::find_by_user_and_type(uuid, type_, conn).await else {
|
||||||
Some(t) => t,
|
return DuoStatus::Disabled(DuoData::global().is_some());
|
||||||
None => return DuoStatus::Disabled(DuoData::global().is_some()),
|
|
||||||
};
|
};
|
||||||
|
|
||||||
// If the user has the required values, we use those
|
// If the user has the required values, we use those
|
||||||
|
@ -333,14 +332,12 @@ fn parse_duo_values(key: &str, val: &str, ikey: &str, prefix: &str, time: i64) -
|
||||||
err!("Prefixes don't match")
|
err!("Prefixes don't match")
|
||||||
}
|
}
|
||||||
|
|
||||||
let cookie_vec = match BASE64.decode(u_b64.as_bytes()) {
|
let Ok(cookie_vec) = BASE64.decode(u_b64.as_bytes()) else {
|
||||||
Ok(c) => c,
|
err!("Invalid Duo cookie encoding")
|
||||||
Err(_) => err!("Invalid Duo cookie encoding"),
|
|
||||||
};
|
};
|
||||||
|
|
||||||
let cookie = match String::from_utf8(cookie_vec) {
|
let Ok(cookie) = String::from_utf8(cookie_vec) else {
|
||||||
Ok(c) => c,
|
err!("Invalid Duo cookie encoding")
|
||||||
Err(_) => err!("Invalid Duo cookie encoding"),
|
|
||||||
};
|
};
|
||||||
|
|
||||||
let cookie_split: Vec<&str> = cookie.split('|').collect();
|
let cookie_split: Vec<&str> = cookie.split('|').collect();
|
||||||
|
|
|
@ -40,9 +40,8 @@ async fn send_email_login(data: Json<SendEmailLoginData>, mut conn: DbConn) -> E
|
||||||
use crate::db::models::User;
|
use crate::db::models::User;
|
||||||
|
|
||||||
// Get the user
|
// Get the user
|
||||||
let user = match User::find_by_mail(&data.email, &mut conn).await {
|
let Some(user) = User::find_by_mail(&data.email, &mut conn).await else {
|
||||||
Some(user) => user,
|
err!("Username or password is incorrect. Try again.")
|
||||||
None => err!("Username or password is incorrect. Try again."),
|
|
||||||
};
|
};
|
||||||
|
|
||||||
// Check password
|
// Check password
|
||||||
|
@ -174,9 +173,8 @@ async fn email(data: Json<EmailData>, headers: Headers, mut conn: DbConn) -> Jso
|
||||||
|
|
||||||
let mut email_data = EmailTokenData::from_json(&twofactor.data)?;
|
let mut email_data = EmailTokenData::from_json(&twofactor.data)?;
|
||||||
|
|
||||||
let issued_token = match &email_data.last_token {
|
let Some(issued_token) = &email_data.last_token else {
|
||||||
Some(t) => t,
|
err!("No token available")
|
||||||
_ => err!("No token available"),
|
|
||||||
};
|
};
|
||||||
|
|
||||||
if !crypto::ct_eq(issued_token, data.token) {
|
if !crypto::ct_eq(issued_token, data.token) {
|
||||||
|
@ -205,14 +203,13 @@ pub async fn validate_email_code_str(user_uuid: &str, token: &str, data: &str, c
|
||||||
let mut twofactor = TwoFactor::find_by_user_and_type(user_uuid, TwoFactorType::Email as i32, conn)
|
let mut twofactor = TwoFactor::find_by_user_and_type(user_uuid, TwoFactorType::Email as i32, conn)
|
||||||
.await
|
.await
|
||||||
.map_res("Two factor not found")?;
|
.map_res("Two factor not found")?;
|
||||||
let issued_token = match &email_data.last_token {
|
let Some(issued_token) = &email_data.last_token else {
|
||||||
Some(t) => t,
|
err!(
|
||||||
_ => err!(
|
|
||||||
"No token available",
|
"No token available",
|
||||||
ErrorEvent {
|
ErrorEvent {
|
||||||
event: EventType::UserFailedLogIn2fa
|
event: EventType::UserFailedLogIn2fa
|
||||||
}
|
}
|
||||||
),
|
)
|
||||||
};
|
};
|
||||||
|
|
||||||
if !crypto::ct_eq(issued_token, token) {
|
if !crypto::ct_eq(issued_token, token) {
|
||||||
|
|
|
@ -85,9 +85,8 @@ async fn recover(data: Json<RecoverTwoFactor>, client_headers: ClientHeaders, mu
|
||||||
use crate::db::models::User;
|
use crate::db::models::User;
|
||||||
|
|
||||||
// Get the user
|
// Get the user
|
||||||
let mut user = match User::find_by_mail(&data.email, &mut conn).await {
|
let Some(mut user) = User::find_by_mail(&data.email, &mut conn).await else {
|
||||||
Some(user) => user,
|
err!("Username or password is incorrect. Try again.")
|
||||||
None => err!("Username or password is incorrect. Try again."),
|
|
||||||
};
|
};
|
||||||
|
|
||||||
// Check password
|
// Check password
|
||||||
|
|
|
@ -309,17 +309,16 @@ async fn delete_webauthn(data: Json<DeleteU2FData>, headers: Headers, mut conn:
|
||||||
err!("Invalid password");
|
err!("Invalid password");
|
||||||
}
|
}
|
||||||
|
|
||||||
let mut tf =
|
let Some(mut tf) =
|
||||||
match TwoFactor::find_by_user_and_type(&headers.user.uuid, TwoFactorType::Webauthn as i32, &mut conn).await {
|
TwoFactor::find_by_user_and_type(&headers.user.uuid, TwoFactorType::Webauthn as i32, &mut conn).await
|
||||||
Some(tf) => tf,
|
else {
|
||||||
None => err!("Webauthn data not found!"),
|
err!("Webauthn data not found!")
|
||||||
};
|
};
|
||||||
|
|
||||||
let mut data: Vec<WebauthnRegistration> = serde_json::from_str(&tf.data)?;
|
let mut data: Vec<WebauthnRegistration> = serde_json::from_str(&tf.data)?;
|
||||||
|
|
||||||
let item_pos = match data.iter().position(|r| r.id == id) {
|
let Some(item_pos) = data.iter().position(|r| r.id == id) else {
|
||||||
Some(p) => p,
|
err!("Webauthn entry not found")
|
||||||
None => err!("Webauthn entry not found"),
|
|
||||||
};
|
};
|
||||||
|
|
||||||
let removed_item = data.remove(item_pos);
|
let removed_item = data.remove(item_pos);
|
||||||
|
|
|
@ -157,9 +157,8 @@ async fn _password_login(
|
||||||
|
|
||||||
// Get the user
|
// Get the user
|
||||||
let username = data.username.as_ref().unwrap().trim();
|
let username = data.username.as_ref().unwrap().trim();
|
||||||
let mut user = match User::find_by_mail(username, conn).await {
|
let Some(mut user) = User::find_by_mail(username, conn).await else {
|
||||||
Some(user) => user,
|
err!("Username or password is incorrect. Try again", format!("IP: {}. Username: {}.", ip.ip, username))
|
||||||
None => err!("Username or password is incorrect. Try again", format!("IP: {}. Username: {}.", ip.ip, username)),
|
|
||||||
};
|
};
|
||||||
|
|
||||||
// Set the user_uuid here to be passed back used for event logging.
|
// Set the user_uuid here to be passed back used for event logging.
|
||||||
|
@ -180,7 +179,8 @@ async fn _password_login(
|
||||||
|
|
||||||
// If we get an auth request, we don't check the user's password, but the access code of the auth request
|
// If we get an auth request, we don't check the user's password, but the access code of the auth request
|
||||||
if let Some(ref auth_request_uuid) = data.auth_request {
|
if let Some(ref auth_request_uuid) = data.auth_request {
|
||||||
let Some(auth_request) = AuthRequest::find_by_uuid(auth_request_uuid.as_str(), conn).await else {
|
let Some(auth_request) = AuthRequest::find_by_uuid_and_user(auth_request_uuid.as_str(), &user.uuid, conn).await
|
||||||
|
else {
|
||||||
err!(
|
err!(
|
||||||
"Auth request not found. Try again.",
|
"Auth request not found. Try again.",
|
||||||
format!("IP: {}. Username: {}.", ip.ip, username),
|
format!("IP: {}. Username: {}.", ip.ip, username),
|
||||||
|
@ -382,13 +382,11 @@ async fn _user_api_key_login(
|
||||||
) -> JsonResult {
|
) -> JsonResult {
|
||||||
// Get the user via the client_id
|
// Get the user via the client_id
|
||||||
let client_id = data.client_id.as_ref().unwrap();
|
let client_id = data.client_id.as_ref().unwrap();
|
||||||
let client_user_uuid = match client_id.strip_prefix("user.") {
|
let Some(client_user_uuid) = client_id.strip_prefix("user.") else {
|
||||||
Some(uuid) => uuid,
|
err!("Malformed client_id", format!("IP: {}.", ip.ip))
|
||||||
None => err!("Malformed client_id", format!("IP: {}.", ip.ip)),
|
|
||||||
};
|
};
|
||||||
let user = match User::find_by_uuid(client_user_uuid, conn).await {
|
let Some(user) = User::find_by_uuid(client_user_uuid, conn).await else {
|
||||||
Some(user) => user,
|
err!("Invalid client_id", format!("IP: {}.", ip.ip))
|
||||||
None => err!("Invalid client_id", format!("IP: {}.", ip.ip)),
|
|
||||||
};
|
};
|
||||||
|
|
||||||
// Set the user_uuid here to be passed back used for event logging.
|
// Set the user_uuid here to be passed back used for event logging.
|
||||||
|
@ -471,13 +469,11 @@ async fn _user_api_key_login(
|
||||||
async fn _organization_api_key_login(data: ConnectData, conn: &mut DbConn, ip: &ClientIp) -> JsonResult {
|
async fn _organization_api_key_login(data: ConnectData, conn: &mut DbConn, ip: &ClientIp) -> JsonResult {
|
||||||
// Get the org via the client_id
|
// Get the org via the client_id
|
||||||
let client_id = data.client_id.as_ref().unwrap();
|
let client_id = data.client_id.as_ref().unwrap();
|
||||||
let org_uuid = match client_id.strip_prefix("organization.") {
|
let Some(org_uuid) = client_id.strip_prefix("organization.") else {
|
||||||
Some(uuid) => uuid,
|
err!("Malformed client_id", format!("IP: {}.", ip.ip))
|
||||||
None => err!("Malformed client_id", format!("IP: {}.", ip.ip)),
|
|
||||||
};
|
};
|
||||||
let org_api_key = match OrganizationApiKey::find_by_org_uuid(org_uuid, conn).await {
|
let Some(org_api_key) = OrganizationApiKey::find_by_org_uuid(org_uuid, conn).await else {
|
||||||
Some(org_api_key) => org_api_key,
|
err!("Invalid client_id", format!("IP: {}.", ip.ip))
|
||||||
None => err!("Invalid client_id", format!("IP: {}.", ip.ip)),
|
|
||||||
};
|
};
|
||||||
|
|
||||||
// Check API key.
|
// Check API key.
|
||||||
|
@ -676,9 +672,8 @@ async fn _json_err_twofactor(
|
||||||
}
|
}
|
||||||
|
|
||||||
Some(tf_type @ TwoFactorType::YubiKey) => {
|
Some(tf_type @ TwoFactorType::YubiKey) => {
|
||||||
let twofactor = match TwoFactor::find_by_user_and_type(user_uuid, tf_type as i32, conn).await {
|
let Some(twofactor) = TwoFactor::find_by_user_and_type(user_uuid, tf_type as i32, conn).await else {
|
||||||
Some(tf) => tf,
|
err!("No YubiKey devices registered")
|
||||||
None => err!("No YubiKey devices registered"),
|
|
||||||
};
|
};
|
||||||
|
|
||||||
let yubikey_metadata: yubikey::YubikeyMetadata = serde_json::from_str(&twofactor.data)?;
|
let yubikey_metadata: yubikey::YubikeyMetadata = serde_json::from_str(&twofactor.data)?;
|
||||||
|
@ -689,9 +684,8 @@ async fn _json_err_twofactor(
|
||||||
}
|
}
|
||||||
|
|
||||||
Some(tf_type @ TwoFactorType::Email) => {
|
Some(tf_type @ TwoFactorType::Email) => {
|
||||||
let twofactor = match TwoFactor::find_by_user_and_type(user_uuid, tf_type as i32, conn).await {
|
let Some(twofactor) = TwoFactor::find_by_user_and_type(user_uuid, tf_type as i32, conn).await else {
|
||||||
Some(tf) => tf,
|
err!("No twofactor email registered")
|
||||||
None => err!("No twofactor email registered"),
|
|
||||||
};
|
};
|
||||||
|
|
||||||
// Send email immediately if email is the only 2FA option
|
// Send email immediately if email is the only 2FA option
|
||||||
|
|
|
@ -155,12 +155,9 @@ pub async fn push_cipher_update(
|
||||||
if cipher.organization_uuid.is_some() {
|
if cipher.organization_uuid.is_some() {
|
||||||
return;
|
return;
|
||||||
};
|
};
|
||||||
let user_uuid = match &cipher.user_uuid {
|
let Some(user_uuid) = &cipher.user_uuid else {
|
||||||
Some(c) => c,
|
|
||||||
None => {
|
|
||||||
debug!("Cipher has no uuid");
|
debug!("Cipher has no uuid");
|
||||||
return;
|
return;
|
||||||
}
|
|
||||||
};
|
};
|
||||||
|
|
||||||
if Device::check_user_has_push_device(user_uuid, conn).await {
|
if Device::check_user_has_push_device(user_uuid, conn).await {
|
||||||
|
|
20
src/auth.rs
20
src/auth.rs
|
@ -471,9 +471,8 @@ impl<'r> FromRequest<'r> for Headers {
|
||||||
};
|
};
|
||||||
|
|
||||||
// Check JWT token is valid and get device and user from it
|
// Check JWT token is valid and get device and user from it
|
||||||
let claims = match decode_login(access_token) {
|
let Ok(claims) = decode_login(access_token) else {
|
||||||
Ok(claims) => claims,
|
err_handler!("Invalid claim")
|
||||||
Err(_) => err_handler!("Invalid claim"),
|
|
||||||
};
|
};
|
||||||
|
|
||||||
let device_uuid = claims.device;
|
let device_uuid = claims.device;
|
||||||
|
@ -484,23 +483,20 @@ impl<'r> FromRequest<'r> for Headers {
|
||||||
_ => err_handler!("Error getting DB"),
|
_ => err_handler!("Error getting DB"),
|
||||||
};
|
};
|
||||||
|
|
||||||
let device = match Device::find_by_uuid_and_user(&device_uuid, &user_uuid, &mut conn).await {
|
let Some(device) = Device::find_by_uuid_and_user(&device_uuid, &user_uuid, &mut conn).await else {
|
||||||
Some(device) => device,
|
err_handler!("Invalid device id")
|
||||||
None => err_handler!("Invalid device id"),
|
|
||||||
};
|
};
|
||||||
|
|
||||||
let user = match User::find_by_uuid(&user_uuid, &mut conn).await {
|
let Some(user) = User::find_by_uuid(&user_uuid, &mut conn).await else {
|
||||||
Some(user) => user,
|
err_handler!("Device has no user associated")
|
||||||
None => err_handler!("Device has no user associated"),
|
|
||||||
};
|
};
|
||||||
|
|
||||||
if user.security_stamp != claims.sstamp {
|
if user.security_stamp != claims.sstamp {
|
||||||
if let Some(stamp_exception) =
|
if let Some(stamp_exception) =
|
||||||
user.stamp_exception.as_deref().and_then(|s| serde_json::from_str::<UserStampException>(s).ok())
|
user.stamp_exception.as_deref().and_then(|s| serde_json::from_str::<UserStampException>(s).ok())
|
||||||
{
|
{
|
||||||
let current_route = match request.route().and_then(|r| r.name.as_deref()) {
|
let Some(current_route) = request.route().and_then(|r| r.name.as_deref()) else {
|
||||||
Some(name) => name,
|
err_handler!("Error getting current route for stamp exception")
|
||||||
_ => err_handler!("Error getting current route for stamp exception"),
|
|
||||||
};
|
};
|
||||||
|
|
||||||
// Check if the stamp exception has expired first.
|
// Check if the stamp exception has expired first.
|
||||||
|
|
|
@ -111,6 +111,17 @@ impl AuthRequest {
|
||||||
}}
|
}}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub async fn find_by_uuid_and_user(uuid: &str, user_uuid: &str, conn: &mut DbConn) -> Option<Self> {
|
||||||
|
db_run! {conn: {
|
||||||
|
auth_requests::table
|
||||||
|
.filter(auth_requests::uuid.eq(uuid))
|
||||||
|
.filter(auth_requests::user_uuid.eq(user_uuid))
|
||||||
|
.first::<AuthRequestDb>(conn)
|
||||||
|
.ok()
|
||||||
|
.from_db()
|
||||||
|
}}
|
||||||
|
}
|
||||||
|
|
||||||
pub async fn find_by_user(user_uuid: &str, conn: &mut DbConn) -> Vec<Self> {
|
pub async fn find_by_user(user_uuid: &str, conn: &mut DbConn) -> Vec<Self> {
|
||||||
db_run! {conn: {
|
db_run! {conn: {
|
||||||
auth_requests::table
|
auth_requests::table
|
||||||
|
|
|
@ -120,10 +120,11 @@ impl Folder {
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
pub async fn find_by_uuid(uuid: &str, conn: &mut DbConn) -> Option<Self> {
|
pub async fn find_by_uuid_and_user(uuid: &str, user_uuid: &str, conn: &mut DbConn) -> Option<Self> {
|
||||||
db_run! { conn: {
|
db_run! { conn: {
|
||||||
folders::table
|
folders::table
|
||||||
.filter(folders::uuid.eq(uuid))
|
.filter(folders::uuid.eq(uuid))
|
||||||
|
.filter(folders::user_uuid.eq(user_uuid))
|
||||||
.first::<FolderDb>(conn)
|
.first::<FolderDb>(conn)
|
||||||
.ok()
|
.ok()
|
||||||
.from_db()
|
.from_db()
|
||||||
|
|
|
@ -191,10 +191,11 @@ impl Group {
|
||||||
}}
|
}}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub async fn find_by_uuid(uuid: &str, conn: &mut DbConn) -> Option<Self> {
|
pub async fn find_by_uuid_and_org(uuid: &str, org_uuid: &str, conn: &mut DbConn) -> Option<Self> {
|
||||||
db_run! { conn: {
|
db_run! { conn: {
|
||||||
groups::table
|
groups::table
|
||||||
.filter(groups::uuid.eq(uuid))
|
.filter(groups::uuid.eq(uuid))
|
||||||
|
.filter(groups::organizations_uuid.eq(org_uuid))
|
||||||
.first::<GroupDb>(conn)
|
.first::<GroupDb>(conn)
|
||||||
.ok()
|
.ok()
|
||||||
.from_db()
|
.from_db()
|
||||||
|
|
|
@ -142,16 +142,6 @@ impl OrgPolicy {
|
||||||
}}
|
}}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub async fn find_by_uuid(uuid: &str, conn: &mut DbConn) -> Option<Self> {
|
|
||||||
db_run! { conn: {
|
|
||||||
org_policies::table
|
|
||||||
.filter(org_policies::uuid.eq(uuid))
|
|
||||||
.first::<OrgPolicyDb>(conn)
|
|
||||||
.ok()
|
|
||||||
.from_db()
|
|
||||||
}}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub async fn find_by_org(org_uuid: &str, conn: &mut DbConn) -> Vec<Self> {
|
pub async fn find_by_org(org_uuid: &str, conn: &mut DbConn) -> Vec<Self> {
|
||||||
db_run! { conn: {
|
db_run! { conn: {
|
||||||
org_policies::table
|
org_policies::table
|
||||||
|
|
|
@ -268,9 +268,8 @@ impl Send {
|
||||||
use data_encoding::BASE64URL_NOPAD;
|
use data_encoding::BASE64URL_NOPAD;
|
||||||
use uuid::Uuid;
|
use uuid::Uuid;
|
||||||
|
|
||||||
let uuid_vec = match BASE64URL_NOPAD.decode(access_id.as_bytes()) {
|
let Ok(uuid_vec) = BASE64URL_NOPAD.decode(access_id.as_bytes()) else {
|
||||||
Ok(v) => v,
|
return None;
|
||||||
Err(_) => return None,
|
|
||||||
};
|
};
|
||||||
|
|
||||||
let uuid = match Uuid::from_slice(&uuid_vec) {
|
let uuid = match Uuid::from_slice(&uuid_vec) {
|
||||||
|
@ -291,6 +290,17 @@ impl Send {
|
||||||
}}
|
}}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub async fn find_by_uuid_and_user(uuid: &str, user_uuid: &str, conn: &mut DbConn) -> Option<Self> {
|
||||||
|
db_run! {conn: {
|
||||||
|
sends::table
|
||||||
|
.filter(sends::uuid.eq(uuid))
|
||||||
|
.filter(sends::user_uuid.eq(user_uuid))
|
||||||
|
.first::<SendDb>(conn)
|
||||||
|
.ok()
|
||||||
|
.from_db()
|
||||||
|
}}
|
||||||
|
}
|
||||||
|
|
||||||
pub async fn find_by_user(user_uuid: &str, conn: &mut DbConn) -> Vec<Self> {
|
pub async fn find_by_user(user_uuid: &str, conn: &mut DbConn) -> Vec<Self> {
|
||||||
db_run! {conn: {
|
db_run! {conn: {
|
||||||
sends::table
|
sends::table
|
||||||
|
|
10
src/mail.rs
10
src/mail.rs
|
@ -286,9 +286,8 @@ pub async fn send_invite(
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
let query_string = match query.query() {
|
let Some(query_string) = query.query() else {
|
||||||
None => err!("Failed to build invite URL query parameters"),
|
err!("Failed to build invite URL query parameters")
|
||||||
Some(query) => query,
|
|
||||||
};
|
};
|
||||||
|
|
||||||
let (subject, body_html, body_text) = get_text(
|
let (subject, body_html, body_text) = get_text(
|
||||||
|
@ -330,9 +329,8 @@ pub async fn send_emergency_access_invite(
|
||||||
.append_pair("token", &encode_jwt(&claims));
|
.append_pair("token", &encode_jwt(&claims));
|
||||||
}
|
}
|
||||||
|
|
||||||
let query_string = match query.query() {
|
let Some(query_string) = query.query() else {
|
||||||
None => err!("Failed to build emergency invite URL query parameters"),
|
err!("Failed to build emergency invite URL query parameters")
|
||||||
Some(query) => query,
|
|
||||||
};
|
};
|
||||||
|
|
||||||
let (subject, body_html, body_text) = get_text(
|
let (subject, body_html, body_text) = get_text(
|
||||||
|
|
Laden …
In neuem Issue referenzieren