Spiegel von
https://github.com/dani-garcia/vaultwarden.git
synchronisiert 2025-01-07 11:45:40 +01:00
use id names more consistently
Dieser Commit ist enthalten in:
Ursprung
1397392699
Commit
6355985539
21 geänderte Dateien mit 442 neuen und 424 gelöschten Zeilen
|
@ -280,8 +280,8 @@ struct InviteData {
|
|||
email: String,
|
||||
}
|
||||
|
||||
async fn get_user_or_404(uuid: &UserId, conn: &mut DbConn) -> ApiResult<User> {
|
||||
if let Some(user) = User::find_by_uuid(uuid, conn).await {
|
||||
async fn get_user_or_404(user_id: &UserId, conn: &mut DbConn) -> ApiResult<User> {
|
||||
if let Some(user) = User::find_by_uuid(user_id, conn).await {
|
||||
Ok(user)
|
||||
} else {
|
||||
err_code!("User doesn't exist", Status::NotFound.code);
|
||||
|
@ -381,21 +381,21 @@ async fn get_user_by_mail_json(mail: &str, _token: AdminToken, mut conn: DbConn)
|
|||
}
|
||||
}
|
||||
|
||||
#[get("/users/<uuid>")]
|
||||
async fn get_user_json(uuid: UserId, _token: AdminToken, mut conn: DbConn) -> JsonResult {
|
||||
let u = get_user_or_404(&uuid, &mut conn).await?;
|
||||
#[get("/users/<user_id>")]
|
||||
async fn get_user_json(user_id: UserId, _token: AdminToken, mut conn: DbConn) -> JsonResult {
|
||||
let u = get_user_or_404(&user_id, &mut conn).await?;
|
||||
let mut usr = u.to_json(&mut conn).await;
|
||||
usr["userEnabled"] = json!(u.enabled);
|
||||
usr["createdAt"] = json!(format_naive_datetime_local(&u.created_at, DT_FMT));
|
||||
Ok(Json(usr))
|
||||
}
|
||||
|
||||
#[post("/users/<uuid>/delete")]
|
||||
async fn delete_user(uuid: UserId, token: AdminToken, mut conn: DbConn) -> EmptyResult {
|
||||
let user = get_user_or_404(&uuid, &mut conn).await?;
|
||||
#[post("/users/<user_id>/delete")]
|
||||
async fn delete_user(user_id: UserId, token: AdminToken, mut conn: DbConn) -> EmptyResult {
|
||||
let user = get_user_or_404(&user_id, &mut conn).await?;
|
||||
|
||||
// Get the membership records before deleting the actual user
|
||||
let memberships = Membership::find_any_state_by_user(&uuid, &mut conn).await;
|
||||
let memberships = Membership::find_any_state_by_user(&user_id, &mut conn).await;
|
||||
let res = user.delete(&mut conn).await;
|
||||
|
||||
for membership in memberships {
|
||||
|
@ -414,9 +414,9 @@ async fn delete_user(uuid: UserId, token: AdminToken, mut conn: DbConn) -> Empty
|
|||
res
|
||||
}
|
||||
|
||||
#[post("/users/<uuid>/deauth")]
|
||||
async fn deauth_user(uuid: UserId, _token: AdminToken, mut conn: DbConn, nt: Notify<'_>) -> EmptyResult {
|
||||
let mut user = get_user_or_404(&uuid, &mut conn).await?;
|
||||
#[post("/users/<user_id>/deauth")]
|
||||
async fn deauth_user(user_id: UserId, _token: AdminToken, mut conn: DbConn, nt: Notify<'_>) -> EmptyResult {
|
||||
let mut user = get_user_or_404(&user_id, &mut conn).await?;
|
||||
|
||||
nt.send_logout(&user, None).await;
|
||||
|
||||
|
@ -435,9 +435,9 @@ async fn deauth_user(uuid: UserId, _token: AdminToken, mut conn: DbConn, nt: Not
|
|||
user.save(&mut conn).await
|
||||
}
|
||||
|
||||
#[post("/users/<uuid>/disable")]
|
||||
async fn disable_user(uuid: UserId, _token: AdminToken, mut conn: DbConn, nt: Notify<'_>) -> EmptyResult {
|
||||
let mut user = get_user_or_404(&uuid, &mut conn).await?;
|
||||
#[post("/users/<user_id>/disable")]
|
||||
async fn disable_user(user_id: UserId, _token: AdminToken, mut conn: DbConn, nt: Notify<'_>) -> EmptyResult {
|
||||
let mut user = get_user_or_404(&user_id, &mut conn).await?;
|
||||
Device::delete_all_by_user(&user.uuid, &mut conn).await?;
|
||||
user.reset_security_stamp();
|
||||
user.enabled = false;
|
||||
|
@ -449,26 +449,26 @@ async fn disable_user(uuid: UserId, _token: AdminToken, mut conn: DbConn, nt: No
|
|||
save_result
|
||||
}
|
||||
|
||||
#[post("/users/<uuid>/enable")]
|
||||
async fn enable_user(uuid: UserId, _token: AdminToken, mut conn: DbConn) -> EmptyResult {
|
||||
let mut user = get_user_or_404(&uuid, &mut conn).await?;
|
||||
#[post("/users/<user_id>/enable")]
|
||||
async fn enable_user(user_id: UserId, _token: AdminToken, mut conn: DbConn) -> EmptyResult {
|
||||
let mut user = get_user_or_404(&user_id, &mut conn).await?;
|
||||
user.enabled = true;
|
||||
|
||||
user.save(&mut conn).await
|
||||
}
|
||||
|
||||
#[post("/users/<uuid>/remove-2fa")]
|
||||
async fn remove_2fa(uuid: UserId, token: AdminToken, mut conn: DbConn) -> EmptyResult {
|
||||
let mut user = get_user_or_404(&uuid, &mut conn).await?;
|
||||
#[post("/users/<user_id>/remove-2fa")]
|
||||
async fn remove_2fa(user_id: UserId, token: AdminToken, mut conn: DbConn) -> EmptyResult {
|
||||
let mut user = get_user_or_404(&user_id, &mut conn).await?;
|
||||
TwoFactor::delete_all_by_user(&user.uuid, &mut conn).await?;
|
||||
two_factor::enforce_2fa_policy(&user, ACTING_ADMIN_USER, 14, &token.ip.ip, &mut conn).await?;
|
||||
user.totp_recover = None;
|
||||
user.save(&mut conn).await
|
||||
}
|
||||
|
||||
#[post("/users/<uuid>/invite/resend")]
|
||||
async fn resend_user_invite(uuid: UserId, _token: AdminToken, mut conn: DbConn) -> EmptyResult {
|
||||
if let Some(user) = User::find_by_uuid(&uuid, &mut conn).await {
|
||||
#[post("/users/<user_id>/invite/resend")]
|
||||
async fn resend_user_invite(user_id: UserId, _token: AdminToken, mut conn: DbConn) -> EmptyResult {
|
||||
if let Some(user) = User::find_by_uuid(&user_id, &mut conn).await {
|
||||
//TODO: replace this with user.status check when it will be available (PR#3397)
|
||||
if !user.password_hash.is_empty() {
|
||||
err_code!("User already accepted invitation", Status::BadRequest.code);
|
||||
|
@ -570,9 +570,9 @@ async fn organizations_overview(_token: AdminToken, mut conn: DbConn) -> ApiResu
|
|||
Ok(Html(text))
|
||||
}
|
||||
|
||||
#[post("/organizations/<org_uuid>/delete")]
|
||||
async fn delete_organization(org_uuid: OrganizationId, _token: AdminToken, mut conn: DbConn) -> EmptyResult {
|
||||
let org = Organization::find_by_uuid(&org_uuid, &mut conn).await.map_res("Organization doesn't exist")?;
|
||||
#[post("/organizations/<org_id>/delete")]
|
||||
async fn delete_organization(org_id: OrganizationId, _token: AdminToken, mut conn: DbConn) -> EmptyResult {
|
||||
let org = Organization::find_by_uuid(&org_id, &mut conn).await.map_res("Organization doesn't exist")?;
|
||||
org.delete(&mut conn).await
|
||||
}
|
||||
|
||||
|
|
|
@ -305,9 +305,9 @@ async fn put_avatar(data: Json<AvatarData>, headers: Headers, mut conn: DbConn)
|
|||
Ok(Json(user.to_json(&mut conn).await))
|
||||
}
|
||||
|
||||
#[get("/users/<uuid>/public-key")]
|
||||
async fn get_public_keys(uuid: UserId, _headers: Headers, mut conn: DbConn) -> JsonResult {
|
||||
let user = match User::find_by_uuid(&uuid, &mut conn).await {
|
||||
#[get("/users/<user_id>/public-key")]
|
||||
async fn get_public_keys(user_id: UserId, _headers: Headers, mut conn: DbConn) -> JsonResult {
|
||||
let user = match User::find_by_uuid(&user_id, &mut conn).await {
|
||||
Some(user) if user.public_key.is_some() => user,
|
||||
Some(_) => err_code!("User has no public_key", Status::NotFound.code),
|
||||
None => err_code!("User doesn't exist", Status::NotFound.code),
|
||||
|
@ -549,17 +549,17 @@ async fn post_rotatekey(data: Json<KeyData>, headers: Headers, mut conn: DbConn,
|
|||
// TODO: See if we can optimize the whole cipher adding/importing and prevent duplicate code and checks.
|
||||
Cipher::validate_cipher_data(&data.ciphers)?;
|
||||
|
||||
let user_uuid = &headers.user.uuid;
|
||||
let user_id = &headers.user.uuid;
|
||||
|
||||
// TODO: Ideally we'd do everything after this point in a single transaction.
|
||||
|
||||
let mut existing_ciphers = Cipher::find_owned_by_user(user_uuid, &mut conn).await;
|
||||
let mut existing_folders = Folder::find_by_user(user_uuid, &mut conn).await;
|
||||
let mut existing_emergency_access = EmergencyAccess::find_all_by_grantor_uuid(user_uuid, &mut conn).await;
|
||||
let mut existing_memberships = Membership::find_by_user(user_uuid, &mut conn).await;
|
||||
let mut existing_ciphers = Cipher::find_owned_by_user(user_id, &mut conn).await;
|
||||
let mut existing_folders = Folder::find_by_user(user_id, &mut conn).await;
|
||||
let mut existing_emergency_access = EmergencyAccess::find_all_by_grantor_uuid(user_id, &mut conn).await;
|
||||
let mut existing_memberships = Membership::find_by_user(user_id, &mut conn).await;
|
||||
// We only rotate the reset password key if it is set.
|
||||
existing_memberships.retain(|m| m.reset_password_key.is_some());
|
||||
let mut existing_sends = Send::find_by_user(user_uuid, &mut conn).await;
|
||||
let mut existing_sends = Send::find_by_user(user_id, &mut conn).await;
|
||||
|
||||
validate_keydata(
|
||||
&data,
|
||||
|
|
|
@ -191,9 +191,9 @@ async fn get_ciphers(headers: Headers, mut conn: DbConn) -> Json<Value> {
|
|||
}))
|
||||
}
|
||||
|
||||
#[get("/ciphers/<uuid>")]
|
||||
async fn get_cipher(uuid: CipherId, headers: Headers, mut conn: DbConn) -> JsonResult {
|
||||
let Some(cipher) = Cipher::find_by_uuid(&uuid, &mut conn).await else {
|
||||
#[get("/ciphers/<cipher_id>")]
|
||||
async fn get_cipher(cipher_id: CipherId, headers: Headers, mut conn: DbConn) -> JsonResult {
|
||||
let Some(cipher) = Cipher::find_by_uuid(&cipher_id, &mut conn).await else {
|
||||
err!("Cipher doesn't exist")
|
||||
};
|
||||
|
||||
|
@ -204,15 +204,15 @@ async fn get_cipher(uuid: CipherId, headers: Headers, mut conn: DbConn) -> JsonR
|
|||
Ok(Json(cipher.to_json(&headers.host, &headers.user.uuid, None, CipherSyncType::User, &mut conn).await))
|
||||
}
|
||||
|
||||
#[get("/ciphers/<uuid>/admin")]
|
||||
async fn get_cipher_admin(uuid: CipherId, headers: Headers, conn: DbConn) -> JsonResult {
|
||||
#[get("/ciphers/<cipher_id>/admin")]
|
||||
async fn get_cipher_admin(cipher_id: CipherId, headers: Headers, conn: DbConn) -> JsonResult {
|
||||
// TODO: Implement this correctly
|
||||
get_cipher(uuid, headers, conn).await
|
||||
get_cipher(cipher_id, headers, conn).await
|
||||
}
|
||||
|
||||
#[get("/ciphers/<uuid>/details")]
|
||||
async fn get_cipher_details(uuid: CipherId, headers: Headers, conn: DbConn) -> JsonResult {
|
||||
get_cipher(uuid, headers, conn).await
|
||||
#[get("/ciphers/<cipher_id>/details")]
|
||||
async fn get_cipher_details(cipher_id: CipherId, headers: Headers, conn: DbConn) -> JsonResult {
|
||||
get_cipher(cipher_id, headers, conn).await
|
||||
}
|
||||
|
||||
#[derive(Debug, Deserialize)]
|
||||
|
@ -355,9 +355,9 @@ async fn enforce_personal_ownership_policy(
|
|||
conn: &mut DbConn,
|
||||
) -> EmptyResult {
|
||||
if data.is_none() || data.unwrap().organization_id.is_none() {
|
||||
let user_uuid = &headers.user.uuid;
|
||||
let user_id = &headers.user.uuid;
|
||||
let policy_type = OrgPolicyType::PersonalOwnership;
|
||||
if OrgPolicy::is_applicable_to_user(user_uuid, policy_type, None, conn).await {
|
||||
if OrgPolicy::is_applicable_to_user(user_id, policy_type, None, conn).await {
|
||||
err!("Due to an Enterprise Policy, you are restricted from saving items to your personal vault.")
|
||||
}
|
||||
}
|
||||
|
@ -428,8 +428,8 @@ pub async fn update_cipher_from_data(
|
|||
cipher.user_uuid = Some(headers.user.uuid.clone());
|
||||
}
|
||||
|
||||
if let Some(ref folder_uuid) = data.folder_id {
|
||||
if Folder::find_by_uuid_and_user(folder_uuid, &headers.user.uuid, conn).await.is_none() {
|
||||
if let Some(ref folder_id) = data.folder_id {
|
||||
if Folder::find_by_uuid_and_user(folder_id, &headers.user.uuid, conn).await.is_none() {
|
||||
err!("Invalid folder", "Folder does not exist or belongs to another user");
|
||||
}
|
||||
}
|
||||
|
@ -513,7 +513,7 @@ pub async fn update_cipher_from_data(
|
|||
|
||||
if ut != UpdateType::None {
|
||||
// Only log events for organizational ciphers
|
||||
if let Some(org_uuid) = &cipher.organization_uuid {
|
||||
if let Some(org_id) = &cipher.organization_uuid {
|
||||
let event_type = match (&ut, transfer_cipher) {
|
||||
(UpdateType::SyncCipherCreate, true) => EventType::CipherCreated,
|
||||
(UpdateType::SyncCipherUpdate, true) => EventType::CipherShared,
|
||||
|
@ -523,7 +523,7 @@ pub async fn update_cipher_from_data(
|
|||
log_event(
|
||||
event_type as i32,
|
||||
&cipher.uuid,
|
||||
org_uuid,
|
||||
org_id,
|
||||
&headers.user.uuid,
|
||||
headers.device.atype,
|
||||
&headers.ip.ip,
|
||||
|
@ -583,7 +583,7 @@ async fn post_ciphers_import(
|
|||
Folder::find_by_user(&headers.user.uuid, &mut conn).await.into_iter().map(|f| Some(f.uuid)).collect();
|
||||
let mut folders: Vec<FolderId> = Vec::with_capacity(data.folders.len());
|
||||
for folder in data.folders.into_iter() {
|
||||
let folder_uuid = if existing_folders.contains(&folder.id) {
|
||||
let folder_id = if existing_folders.contains(&folder.id) {
|
||||
folder.id.unwrap()
|
||||
} else {
|
||||
let mut new_folder = Folder::new(headers.user.uuid.clone(), folder.name);
|
||||
|
@ -591,7 +591,7 @@ async fn post_ciphers_import(
|
|||
new_folder.uuid
|
||||
};
|
||||
|
||||
folders.push(folder_uuid);
|
||||
folders.push(folder_id);
|
||||
}
|
||||
|
||||
// Read the relations between folders and ciphers
|
||||
|
@ -603,8 +603,8 @@ async fn post_ciphers_import(
|
|||
|
||||
// Read and create the ciphers
|
||||
for (index, mut cipher_data) in data.ciphers.into_iter().enumerate() {
|
||||
let folder_uuid = relations_map.get(&index).map(|i| folders[*i].clone());
|
||||
cipher_data.folder_id = folder_uuid;
|
||||
let folder_id = relations_map.get(&index).map(|i| folders[*i].clone());
|
||||
cipher_data.folder_id = folder_id;
|
||||
|
||||
let mut cipher = Cipher::new(cipher_data.r#type, cipher_data.name.clone());
|
||||
update_cipher_from_data(&mut cipher, cipher_data, &headers, None, &mut conn, &nt, UpdateType::None).await?;
|
||||
|
@ -618,42 +618,42 @@ async fn post_ciphers_import(
|
|||
}
|
||||
|
||||
/// Called when an org admin modifies an existing org cipher.
|
||||
#[put("/ciphers/<uuid>/admin", data = "<data>")]
|
||||
#[put("/ciphers/<cipher_id>/admin", data = "<data>")]
|
||||
async fn put_cipher_admin(
|
||||
uuid: CipherId,
|
||||
cipher_id: CipherId,
|
||||
data: Json<CipherData>,
|
||||
headers: Headers,
|
||||
conn: DbConn,
|
||||
nt: Notify<'_>,
|
||||
) -> JsonResult {
|
||||
put_cipher(uuid, data, headers, conn, nt).await
|
||||
put_cipher(cipher_id, data, headers, conn, nt).await
|
||||
}
|
||||
|
||||
#[post("/ciphers/<uuid>/admin", data = "<data>")]
|
||||
#[post("/ciphers/<cipher_id>/admin", data = "<data>")]
|
||||
async fn post_cipher_admin(
|
||||
uuid: CipherId,
|
||||
cipher_id: CipherId,
|
||||
data: Json<CipherData>,
|
||||
headers: Headers,
|
||||
conn: DbConn,
|
||||
nt: Notify<'_>,
|
||||
) -> JsonResult {
|
||||
post_cipher(uuid, data, headers, conn, nt).await
|
||||
post_cipher(cipher_id, data, headers, conn, nt).await
|
||||
}
|
||||
|
||||
#[post("/ciphers/<uuid>", data = "<data>")]
|
||||
#[post("/ciphers/<cipher_id>", data = "<data>")]
|
||||
async fn post_cipher(
|
||||
uuid: CipherId,
|
||||
cipher_id: CipherId,
|
||||
data: Json<CipherData>,
|
||||
headers: Headers,
|
||||
conn: DbConn,
|
||||
nt: Notify<'_>,
|
||||
) -> JsonResult {
|
||||
put_cipher(uuid, data, headers, conn, nt).await
|
||||
put_cipher(cipher_id, data, headers, conn, nt).await
|
||||
}
|
||||
|
||||
#[put("/ciphers/<uuid>", data = "<data>")]
|
||||
#[put("/ciphers/<cipher_id>", data = "<data>")]
|
||||
async fn put_cipher(
|
||||
uuid: CipherId,
|
||||
cipher_id: CipherId,
|
||||
data: Json<CipherData>,
|
||||
headers: Headers,
|
||||
mut conn: DbConn,
|
||||
|
@ -661,7 +661,7 @@ async fn put_cipher(
|
|||
) -> JsonResult {
|
||||
let data: CipherData = data.into_inner();
|
||||
|
||||
let Some(mut cipher) = Cipher::find_by_uuid(&uuid, &mut conn).await else {
|
||||
let Some(mut cipher) = Cipher::find_by_uuid(&cipher_id, &mut conn).await else {
|
||||
err!("Cipher doesn't exist")
|
||||
};
|
||||
|
||||
|
@ -679,32 +679,32 @@ async fn put_cipher(
|
|||
Ok(Json(cipher.to_json(&headers.host, &headers.user.uuid, None, CipherSyncType::User, &mut conn).await))
|
||||
}
|
||||
|
||||
#[post("/ciphers/<uuid>/partial", data = "<data>")]
|
||||
#[post("/ciphers/<cipher_id>/partial", data = "<data>")]
|
||||
async fn post_cipher_partial(
|
||||
uuid: CipherId,
|
||||
cipher_id: CipherId,
|
||||
data: Json<PartialCipherData>,
|
||||
headers: Headers,
|
||||
conn: DbConn,
|
||||
) -> JsonResult {
|
||||
put_cipher_partial(uuid, data, headers, conn).await
|
||||
put_cipher_partial(cipher_id, data, headers, conn).await
|
||||
}
|
||||
|
||||
// Only update the folder and favorite for the user, since this cipher is read-only
|
||||
#[put("/ciphers/<uuid>/partial", data = "<data>")]
|
||||
#[put("/ciphers/<cipher_id>/partial", data = "<data>")]
|
||||
async fn put_cipher_partial(
|
||||
uuid: CipherId,
|
||||
cipher_id: CipherId,
|
||||
data: Json<PartialCipherData>,
|
||||
headers: Headers,
|
||||
mut conn: DbConn,
|
||||
) -> JsonResult {
|
||||
let data: PartialCipherData = data.into_inner();
|
||||
|
||||
let Some(cipher) = Cipher::find_by_uuid(&uuid, &mut conn).await else {
|
||||
let Some(cipher) = Cipher::find_by_uuid(&cipher_id, &mut conn).await else {
|
||||
err!("Cipher doesn't exist")
|
||||
};
|
||||
|
||||
if let Some(ref folder_uuid) = data.folder_id {
|
||||
if Folder::find_by_uuid_and_user(folder_uuid, &headers.user.uuid, &mut conn).await.is_none() {
|
||||
if let Some(ref folder_id) = data.folder_id {
|
||||
if Folder::find_by_uuid_and_user(folder_id, &headers.user.uuid, &mut conn).await.is_none() {
|
||||
err!("Invalid folder", "Folder does not exist or belongs to another user");
|
||||
}
|
||||
}
|
||||
|
@ -724,26 +724,26 @@ struct CollectionsAdminData {
|
|||
collection_ids: Vec<CollectionId>,
|
||||
}
|
||||
|
||||
#[put("/ciphers/<uuid>/collections_v2", data = "<data>")]
|
||||
#[put("/ciphers/<cipher_id>/collections_v2", data = "<data>")]
|
||||
async fn put_collections2_update(
|
||||
uuid: CipherId,
|
||||
cipher_id: CipherId,
|
||||
data: Json<CollectionsAdminData>,
|
||||
headers: Headers,
|
||||
conn: DbConn,
|
||||
nt: Notify<'_>,
|
||||
) -> JsonResult {
|
||||
post_collections2_update(uuid, data, headers, conn, nt).await
|
||||
post_collections2_update(cipher_id, data, headers, conn, nt).await
|
||||
}
|
||||
|
||||
#[post("/ciphers/<uuid>/collections_v2", data = "<data>")]
|
||||
#[post("/ciphers/<cipher_id>/collections_v2", data = "<data>")]
|
||||
async fn post_collections2_update(
|
||||
uuid: CipherId,
|
||||
cipher_id: CipherId,
|
||||
data: Json<CollectionsAdminData>,
|
||||
headers: Headers,
|
||||
conn: DbConn,
|
||||
nt: Notify<'_>,
|
||||
) -> JsonResult {
|
||||
let cipher_details = post_collections_update(uuid, data, headers, conn, nt).await?;
|
||||
let cipher_details = post_collections_update(cipher_id, data, headers, conn, nt).await?;
|
||||
Ok(Json(json!({ // AttachmentUploadDataResponseModel
|
||||
"object": "optionalCipherDetails",
|
||||
"unavailable": false,
|
||||
|
@ -751,20 +751,20 @@ async fn post_collections2_update(
|
|||
})))
|
||||
}
|
||||
|
||||
#[put("/ciphers/<uuid>/collections", data = "<data>")]
|
||||
#[put("/ciphers/<cipher_id>/collections", data = "<data>")]
|
||||
async fn put_collections_update(
|
||||
uuid: CipherId,
|
||||
cipher_id: CipherId,
|
||||
data: Json<CollectionsAdminData>,
|
||||
headers: Headers,
|
||||
conn: DbConn,
|
||||
nt: Notify<'_>,
|
||||
) -> JsonResult {
|
||||
post_collections_update(uuid, data, headers, conn, nt).await
|
||||
post_collections_update(cipher_id, data, headers, conn, nt).await
|
||||
}
|
||||
|
||||
#[post("/ciphers/<uuid>/collections", data = "<data>")]
|
||||
#[post("/ciphers/<cipher_id>/collections", data = "<data>")]
|
||||
async fn post_collections_update(
|
||||
uuid: CipherId,
|
||||
cipher_id: CipherId,
|
||||
data: Json<CollectionsAdminData>,
|
||||
headers: Headers,
|
||||
mut conn: DbConn,
|
||||
|
@ -772,7 +772,7 @@ async fn post_collections_update(
|
|||
) -> JsonResult {
|
||||
let data: CollectionsAdminData = data.into_inner();
|
||||
|
||||
let Some(cipher) = Cipher::find_by_uuid(&uuid, &mut conn).await else {
|
||||
let Some(cipher) = Cipher::find_by_uuid(&cipher_id, &mut conn).await else {
|
||||
err!("Cipher doesn't exist")
|
||||
};
|
||||
|
||||
|
@ -828,20 +828,20 @@ async fn post_collections_update(
|
|||
Ok(Json(cipher.to_json(&headers.host, &headers.user.uuid, None, CipherSyncType::User, &mut conn).await))
|
||||
}
|
||||
|
||||
#[put("/ciphers/<uuid>/collections-admin", data = "<data>")]
|
||||
#[put("/ciphers/<cipher_id>/collections-admin", data = "<data>")]
|
||||
async fn put_collections_admin(
|
||||
uuid: CipherId,
|
||||
cipher_id: CipherId,
|
||||
data: Json<CollectionsAdminData>,
|
||||
headers: Headers,
|
||||
conn: DbConn,
|
||||
nt: Notify<'_>,
|
||||
) -> EmptyResult {
|
||||
post_collections_admin(uuid, data, headers, conn, nt).await
|
||||
post_collections_admin(cipher_id, data, headers, conn, nt).await
|
||||
}
|
||||
|
||||
#[post("/ciphers/<uuid>/collections-admin", data = "<data>")]
|
||||
#[post("/ciphers/<cipher_id>/collections-admin", data = "<data>")]
|
||||
async fn post_collections_admin(
|
||||
uuid: CipherId,
|
||||
cipher_id: CipherId,
|
||||
data: Json<CollectionsAdminData>,
|
||||
headers: Headers,
|
||||
mut conn: DbConn,
|
||||
|
@ -849,7 +849,7 @@ async fn post_collections_admin(
|
|||
) -> EmptyResult {
|
||||
let data: CollectionsAdminData = data.into_inner();
|
||||
|
||||
let Some(cipher) = Cipher::find_by_uuid(&uuid, &mut conn).await else {
|
||||
let Some(cipher) = Cipher::find_by_uuid(&cipher_id, &mut conn).await else {
|
||||
err!("Cipher doesn't exist")
|
||||
};
|
||||
|
||||
|
@ -914,9 +914,9 @@ struct ShareCipherData {
|
|||
collection_ids: Vec<CollectionId>,
|
||||
}
|
||||
|
||||
#[post("/ciphers/<uuid>/share", data = "<data>")]
|
||||
#[post("/ciphers/<cipher_id>/share", data = "<data>")]
|
||||
async fn post_cipher_share(
|
||||
uuid: CipherId,
|
||||
cipher_id: CipherId,
|
||||
data: Json<ShareCipherData>,
|
||||
headers: Headers,
|
||||
mut conn: DbConn,
|
||||
|
@ -924,12 +924,12 @@ async fn post_cipher_share(
|
|||
) -> JsonResult {
|
||||
let data: ShareCipherData = data.into_inner();
|
||||
|
||||
share_cipher_by_uuid(&uuid, data, &headers, &mut conn, &nt).await
|
||||
share_cipher_by_uuid(&cipher_id, data, &headers, &mut conn, &nt).await
|
||||
}
|
||||
|
||||
#[put("/ciphers/<uuid>/share", data = "<data>")]
|
||||
#[put("/ciphers/<cipher_id>/share", data = "<data>")]
|
||||
async fn put_cipher_share(
|
||||
uuid: CipherId,
|
||||
cipher_id: CipherId,
|
||||
data: Json<ShareCipherData>,
|
||||
headers: Headers,
|
||||
mut conn: DbConn,
|
||||
|
@ -937,7 +937,7 @@ async fn put_cipher_share(
|
|||
) -> JsonResult {
|
||||
let data: ShareCipherData = data.into_inner();
|
||||
|
||||
share_cipher_by_uuid(&uuid, data, &headers, &mut conn, &nt).await
|
||||
share_cipher_by_uuid(&cipher_id, data, &headers, &mut conn, &nt).await
|
||||
}
|
||||
|
||||
#[derive(Deserialize)]
|
||||
|
@ -986,13 +986,13 @@ async fn put_cipher_share_selected(
|
|||
}
|
||||
|
||||
async fn share_cipher_by_uuid(
|
||||
uuid: &CipherId,
|
||||
cipher_id: &CipherId,
|
||||
data: ShareCipherData,
|
||||
headers: &Headers,
|
||||
conn: &mut DbConn,
|
||||
nt: &Notify<'_>,
|
||||
) -> JsonResult {
|
||||
let mut cipher = match Cipher::find_by_uuid(uuid, conn).await {
|
||||
let mut cipher = match Cipher::find_by_uuid(cipher_id, conn).await {
|
||||
Some(cipher) => {
|
||||
if cipher.is_write_accessible_to_user(&headers.user.uuid, conn).await {
|
||||
cipher
|
||||
|
@ -1005,9 +1005,9 @@ async fn share_cipher_by_uuid(
|
|||
|
||||
let mut shared_to_collections = vec![];
|
||||
|
||||
if let Some(organization_uuid) = &data.cipher.organization_id {
|
||||
for uuid in &data.collection_ids {
|
||||
match Collection::find_by_uuid_and_org(uuid, organization_uuid, conn).await {
|
||||
if let Some(organization_id) = &data.cipher.organization_id {
|
||||
for col_id in &data.collection_ids {
|
||||
match Collection::find_by_uuid_and_org(col_id, organization_id, conn).await {
|
||||
None => err!("Invalid collection ID provided"),
|
||||
Some(collection) => {
|
||||
if collection.is_writable_by_user(&headers.user.uuid, conn).await {
|
||||
|
@ -1039,9 +1039,14 @@ async fn share_cipher_by_uuid(
|
|||
/// Upstream added this v2 API to support direct download of attachments from
|
||||
/// their object storage service. For self-hosted instances, it basically just
|
||||
/// redirects to the same location as before the v2 API.
|
||||
#[get("/ciphers/<uuid>/attachment/<attachment_id>")]
|
||||
async fn get_attachment(uuid: CipherId, attachment_id: AttachmentId, headers: Headers, mut conn: DbConn) -> JsonResult {
|
||||
let Some(cipher) = Cipher::find_by_uuid(&uuid, &mut conn).await else {
|
||||
#[get("/ciphers/<cipher_id>/attachment/<attachment_id>")]
|
||||
async fn get_attachment(
|
||||
cipher_id: CipherId,
|
||||
attachment_id: AttachmentId,
|
||||
headers: Headers,
|
||||
mut conn: DbConn,
|
||||
) -> JsonResult {
|
||||
let Some(cipher) = Cipher::find_by_uuid(&cipher_id, &mut conn).await else {
|
||||
err!("Cipher doesn't exist")
|
||||
};
|
||||
|
||||
|
@ -1050,7 +1055,7 @@ async fn get_attachment(uuid: CipherId, attachment_id: AttachmentId, headers: He
|
|||
}
|
||||
|
||||
match Attachment::find_by_id(&attachment_id, &mut conn).await {
|
||||
Some(attachment) if uuid == attachment.cipher_uuid => Ok(Json(attachment.to_json(&headers.host))),
|
||||
Some(attachment) if cipher_id == attachment.cipher_uuid => Ok(Json(attachment.to_json(&headers.host))),
|
||||
Some(_) => err!("Attachment doesn't belong to cipher"),
|
||||
None => err!("Attachment doesn't exist"),
|
||||
}
|
||||
|
@ -1074,14 +1079,14 @@ enum FileUploadType {
|
|||
/// This redirects the client to the API it should use to upload the attachment.
|
||||
/// For upstream's cloud-hosted service, it's an Azure object storage API.
|
||||
/// For self-hosted instances, it's another API on the local instance.
|
||||
#[post("/ciphers/<uuid>/attachment/v2", data = "<data>")]
|
||||
#[post("/ciphers/<cipher_id>/attachment/v2", data = "<data>")]
|
||||
async fn post_attachment_v2(
|
||||
uuid: CipherId,
|
||||
cipher_id: CipherId,
|
||||
data: Json<AttachmentRequestData>,
|
||||
headers: Headers,
|
||||
mut conn: DbConn,
|
||||
) -> JsonResult {
|
||||
let Some(cipher) = Cipher::find_by_uuid(&uuid, &mut conn).await else {
|
||||
let Some(cipher) = Cipher::find_by_uuid(&cipher_id, &mut conn).await else {
|
||||
err!("Cipher doesn't exist")
|
||||
};
|
||||
|
||||
|
@ -1131,7 +1136,7 @@ struct UploadData<'f> {
|
|||
/// database record, which is passed in as `attachment`.
|
||||
async fn save_attachment(
|
||||
mut attachment: Option<Attachment>,
|
||||
cipher_uuid: CipherId,
|
||||
cipher_id: CipherId,
|
||||
data: Form<UploadData<'_>>,
|
||||
headers: &Headers,
|
||||
mut conn: DbConn,
|
||||
|
@ -1146,7 +1151,7 @@ async fn save_attachment(
|
|||
err!("Attachment size can't be negative")
|
||||
}
|
||||
|
||||
let Some(cipher) = Cipher::find_by_uuid(&cipher_uuid, &mut conn).await else {
|
||||
let Some(cipher) = Cipher::find_by_uuid(&cipher_id, &mut conn).await else {
|
||||
err!("Cipher doesn't exist")
|
||||
};
|
||||
|
||||
|
@ -1161,11 +1166,11 @@ async fn save_attachment(
|
|||
Some(a) => a.file_size, // v2 API
|
||||
};
|
||||
|
||||
let size_limit = if let Some(ref user_uuid) = cipher.user_uuid {
|
||||
let size_limit = if let Some(ref user_id) = cipher.user_uuid {
|
||||
match CONFIG.user_attachment_limit() {
|
||||
Some(0) => err!("Attachments are disabled"),
|
||||
Some(limit_kb) => {
|
||||
let already_used = Attachment::size_by_user(user_uuid, &mut conn).await;
|
||||
let already_used = Attachment::size_by_user(user_id, &mut conn).await;
|
||||
let left = limit_kb
|
||||
.checked_mul(1024)
|
||||
.and_then(|l| l.checked_sub(already_used))
|
||||
|
@ -1183,11 +1188,11 @@ async fn save_attachment(
|
|||
}
|
||||
None => None,
|
||||
}
|
||||
} else if let Some(ref org_uuid) = cipher.organization_uuid {
|
||||
} else if let Some(ref org_id) = cipher.organization_uuid {
|
||||
match CONFIG.org_attachment_limit() {
|
||||
Some(0) => err!("Attachments are disabled"),
|
||||
Some(limit_kb) => {
|
||||
let already_used = Attachment::size_by_org(org_uuid, &mut conn).await;
|
||||
let already_used = Attachment::size_by_org(org_id, &mut conn).await;
|
||||
let left = limit_kb
|
||||
.checked_mul(1024)
|
||||
.and_then(|l| l.checked_sub(already_used))
|
||||
|
@ -1260,11 +1265,11 @@ async fn save_attachment(
|
|||
err!("No attachment key provided")
|
||||
}
|
||||
let attachment =
|
||||
Attachment::new(file_id.clone(), cipher_uuid.clone(), encrypted_filename.unwrap(), size, data.key);
|
||||
Attachment::new(file_id.clone(), cipher_id.clone(), encrypted_filename.unwrap(), size, data.key);
|
||||
attachment.save(&mut conn).await.expect("Error saving attachment");
|
||||
}
|
||||
|
||||
let folder_path = tokio::fs::canonicalize(&CONFIG.attachments_folder()).await?.join(cipher_uuid.as_ref());
|
||||
let folder_path = tokio::fs::canonicalize(&CONFIG.attachments_folder()).await?.join(cipher_id.as_ref());
|
||||
let file_path = folder_path.join(file_id.as_ref());
|
||||
tokio::fs::create_dir_all(&folder_path).await?;
|
||||
|
||||
|
@ -1282,11 +1287,11 @@ async fn save_attachment(
|
|||
)
|
||||
.await;
|
||||
|
||||
if let Some(org_uuid) = &cipher.organization_uuid {
|
||||
if let Some(org_id) = &cipher.organization_uuid {
|
||||
log_event(
|
||||
EventType::CipherAttachmentCreated as i32,
|
||||
&cipher.uuid,
|
||||
org_uuid,
|
||||
org_id,
|
||||
&headers.user.uuid,
|
||||
headers.device.atype,
|
||||
&headers.ip.ip,
|
||||
|
@ -1300,11 +1305,11 @@ async fn save_attachment(
|
|||
|
||||
/// v2 API for uploading the actual data content of an attachment.
|
||||
/// This route needs a rank specified so that Rocket prioritizes the
|
||||
/// /ciphers/<uuid>/attachment/v2 route, which would otherwise conflict
|
||||
/// /ciphers/<cipher_id>/attachment/v2 route, which would otherwise conflict
|
||||
/// with this one.
|
||||
#[post("/ciphers/<uuid>/attachment/<attachment_id>", format = "multipart/form-data", data = "<data>", rank = 1)]
|
||||
#[post("/ciphers/<cipher_id>/attachment/<attachment_id>", format = "multipart/form-data", data = "<data>", rank = 1)]
|
||||
async fn post_attachment_v2_data(
|
||||
uuid: CipherId,
|
||||
cipher_id: CipherId,
|
||||
attachment_id: AttachmentId,
|
||||
data: Form<UploadData<'_>>,
|
||||
headers: Headers,
|
||||
|
@ -1312,20 +1317,20 @@ async fn post_attachment_v2_data(
|
|||
nt: Notify<'_>,
|
||||
) -> EmptyResult {
|
||||
let attachment = match Attachment::find_by_id(&attachment_id, &mut conn).await {
|
||||
Some(attachment) if uuid == attachment.cipher_uuid => Some(attachment),
|
||||
Some(attachment) if cipher_id == attachment.cipher_uuid => Some(attachment),
|
||||
Some(_) => err!("Attachment doesn't belong to cipher"),
|
||||
None => err!("Attachment doesn't exist"),
|
||||
};
|
||||
|
||||
save_attachment(attachment, uuid, data, &headers, conn, nt).await?;
|
||||
save_attachment(attachment, cipher_id, data, &headers, conn, nt).await?;
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
/// Legacy API for creating an attachment associated with a cipher.
|
||||
#[post("/ciphers/<uuid>/attachment", format = "multipart/form-data", data = "<data>")]
|
||||
#[post("/ciphers/<cipher_id>/attachment", format = "multipart/form-data", data = "<data>")]
|
||||
async fn post_attachment(
|
||||
uuid: CipherId,
|
||||
cipher_id: CipherId,
|
||||
data: Form<UploadData<'_>>,
|
||||
headers: Headers,
|
||||
conn: DbConn,
|
||||
|
@ -1335,111 +1340,121 @@ async fn post_attachment(
|
|||
// the attachment database record as well as saving the data to disk.
|
||||
let attachment = None;
|
||||
|
||||
let (cipher, mut conn) = save_attachment(attachment, uuid, data, &headers, conn, nt).await?;
|
||||
let (cipher, mut conn) = save_attachment(attachment, cipher_id, data, &headers, conn, nt).await?;
|
||||
|
||||
Ok(Json(cipher.to_json(&headers.host, &headers.user.uuid, None, CipherSyncType::User, &mut conn).await))
|
||||
}
|
||||
|
||||
#[post("/ciphers/<uuid>/attachment-admin", format = "multipart/form-data", data = "<data>")]
|
||||
#[post("/ciphers/<cipher_id>/attachment-admin", format = "multipart/form-data", data = "<data>")]
|
||||
async fn post_attachment_admin(
|
||||
uuid: CipherId,
|
||||
cipher_id: CipherId,
|
||||
data: Form<UploadData<'_>>,
|
||||
headers: Headers,
|
||||
conn: DbConn,
|
||||
nt: Notify<'_>,
|
||||
) -> JsonResult {
|
||||
post_attachment(uuid, data, headers, conn, nt).await
|
||||
post_attachment(cipher_id, data, headers, conn, nt).await
|
||||
}
|
||||
|
||||
#[post("/ciphers/<uuid>/attachment/<attachment_id>/share", format = "multipart/form-data", data = "<data>")]
|
||||
#[post("/ciphers/<cipher_id>/attachment/<attachment_id>/share", format = "multipart/form-data", data = "<data>")]
|
||||
async fn post_attachment_share(
|
||||
uuid: CipherId,
|
||||
cipher_id: CipherId,
|
||||
attachment_id: AttachmentId,
|
||||
data: Form<UploadData<'_>>,
|
||||
headers: Headers,
|
||||
mut conn: DbConn,
|
||||
nt: Notify<'_>,
|
||||
) -> JsonResult {
|
||||
_delete_cipher_attachment_by_id(&uuid, &attachment_id, &headers, &mut conn, &nt).await?;
|
||||
post_attachment(uuid, data, headers, conn, nt).await
|
||||
_delete_cipher_attachment_by_id(&cipher_id, &attachment_id, &headers, &mut conn, &nt).await?;
|
||||
post_attachment(cipher_id, data, headers, conn, nt).await
|
||||
}
|
||||
|
||||
#[post("/ciphers/<uuid>/attachment/<attachment_id>/delete-admin")]
|
||||
#[post("/ciphers/<cipher_id>/attachment/<attachment_id>/delete-admin")]
|
||||
async fn delete_attachment_post_admin(
|
||||
uuid: CipherId,
|
||||
cipher_id: CipherId,
|
||||
attachment_id: AttachmentId,
|
||||
headers: Headers,
|
||||
conn: DbConn,
|
||||
nt: Notify<'_>,
|
||||
) -> EmptyResult {
|
||||
delete_attachment(uuid, attachment_id, headers, conn, nt).await
|
||||
delete_attachment(cipher_id, attachment_id, headers, conn, nt).await
|
||||
}
|
||||
|
||||
#[post("/ciphers/<uuid>/attachment/<attachment_id>/delete")]
|
||||
#[post("/ciphers/<cipher_id>/attachment/<attachment_id>/delete")]
|
||||
async fn delete_attachment_post(
|
||||
uuid: CipherId,
|
||||
cipher_id: CipherId,
|
||||
attachment_id: AttachmentId,
|
||||
headers: Headers,
|
||||
conn: DbConn,
|
||||
nt: Notify<'_>,
|
||||
) -> EmptyResult {
|
||||
delete_attachment(uuid, attachment_id, headers, conn, nt).await
|
||||
delete_attachment(cipher_id, attachment_id, headers, conn, nt).await
|
||||
}
|
||||
|
||||
#[delete("/ciphers/<uuid>/attachment/<attachment_id>")]
|
||||
#[delete("/ciphers/<cipher_id>/attachment/<attachment_id>")]
|
||||
async fn delete_attachment(
|
||||
uuid: CipherId,
|
||||
cipher_id: CipherId,
|
||||
attachment_id: AttachmentId,
|
||||
headers: Headers,
|
||||
mut conn: DbConn,
|
||||
nt: Notify<'_>,
|
||||
) -> EmptyResult {
|
||||
_delete_cipher_attachment_by_id(&uuid, &attachment_id, &headers, &mut conn, &nt).await
|
||||
_delete_cipher_attachment_by_id(&cipher_id, &attachment_id, &headers, &mut conn, &nt).await
|
||||
}
|
||||
|
||||
#[delete("/ciphers/<uuid>/attachment/<attachment_id>/admin")]
|
||||
#[delete("/ciphers/<cipher_id>/attachment/<attachment_id>/admin")]
|
||||
async fn delete_attachment_admin(
|
||||
uuid: CipherId,
|
||||
cipher_id: CipherId,
|
||||
attachment_id: AttachmentId,
|
||||
headers: Headers,
|
||||
mut conn: DbConn,
|
||||
nt: Notify<'_>,
|
||||
) -> EmptyResult {
|
||||
_delete_cipher_attachment_by_id(&uuid, &attachment_id, &headers, &mut conn, &nt).await
|
||||
_delete_cipher_attachment_by_id(&cipher_id, &attachment_id, &headers, &mut conn, &nt).await
|
||||
}
|
||||
|
||||
#[post("/ciphers/<uuid>/delete")]
|
||||
async fn delete_cipher_post(uuid: CipherId, headers: Headers, mut conn: DbConn, nt: Notify<'_>) -> EmptyResult {
|
||||
_delete_cipher_by_uuid(&uuid, &headers, &mut conn, false, &nt).await
|
||||
#[post("/ciphers/<cipher_id>/delete")]
|
||||
async fn delete_cipher_post(cipher_id: CipherId, headers: Headers, mut conn: DbConn, nt: Notify<'_>) -> EmptyResult {
|
||||
_delete_cipher_by_uuid(&cipher_id, &headers, &mut conn, false, &nt).await
|
||||
// permanent delete
|
||||
}
|
||||
|
||||
#[post("/ciphers/<uuid>/delete-admin")]
|
||||
async fn delete_cipher_post_admin(uuid: CipherId, headers: Headers, mut conn: DbConn, nt: Notify<'_>) -> EmptyResult {
|
||||
_delete_cipher_by_uuid(&uuid, &headers, &mut conn, false, &nt).await
|
||||
#[post("/ciphers/<cipher_id>/delete-admin")]
|
||||
async fn delete_cipher_post_admin(
|
||||
cipher_id: CipherId,
|
||||
headers: Headers,
|
||||
mut conn: DbConn,
|
||||
nt: Notify<'_>,
|
||||
) -> EmptyResult {
|
||||
_delete_cipher_by_uuid(&cipher_id, &headers, &mut conn, false, &nt).await
|
||||
// permanent delete
|
||||
}
|
||||
|
||||
#[put("/ciphers/<uuid>/delete")]
|
||||
async fn delete_cipher_put(uuid: CipherId, headers: Headers, mut conn: DbConn, nt: Notify<'_>) -> EmptyResult {
|
||||
_delete_cipher_by_uuid(&uuid, &headers, &mut conn, true, &nt).await
|
||||
#[put("/ciphers/<cipher_id>/delete")]
|
||||
async fn delete_cipher_put(cipher_id: CipherId, headers: Headers, mut conn: DbConn, nt: Notify<'_>) -> EmptyResult {
|
||||
_delete_cipher_by_uuid(&cipher_id, &headers, &mut conn, true, &nt).await
|
||||
// soft delete
|
||||
}
|
||||
|
||||
#[put("/ciphers/<uuid>/delete-admin")]
|
||||
async fn delete_cipher_put_admin(uuid: CipherId, headers: Headers, mut conn: DbConn, nt: Notify<'_>) -> EmptyResult {
|
||||
_delete_cipher_by_uuid(&uuid, &headers, &mut conn, true, &nt).await
|
||||
#[put("/ciphers/<cipher_id>/delete-admin")]
|
||||
async fn delete_cipher_put_admin(
|
||||
cipher_id: CipherId,
|
||||
headers: Headers,
|
||||
mut conn: DbConn,
|
||||
nt: Notify<'_>,
|
||||
) -> EmptyResult {
|
||||
_delete_cipher_by_uuid(&cipher_id, &headers, &mut conn, true, &nt).await
|
||||
}
|
||||
|
||||
#[delete("/ciphers/<uuid>")]
|
||||
async fn delete_cipher(uuid: CipherId, headers: Headers, mut conn: DbConn, nt: Notify<'_>) -> EmptyResult {
|
||||
_delete_cipher_by_uuid(&uuid, &headers, &mut conn, false, &nt).await
|
||||
#[delete("/ciphers/<cipher_id>")]
|
||||
async fn delete_cipher(cipher_id: CipherId, headers: Headers, mut conn: DbConn, nt: Notify<'_>) -> EmptyResult {
|
||||
_delete_cipher_by_uuid(&cipher_id, &headers, &mut conn, false, &nt).await
|
||||
// permanent delete
|
||||
}
|
||||
|
||||
#[delete("/ciphers/<uuid>/admin")]
|
||||
async fn delete_cipher_admin(uuid: CipherId, headers: Headers, mut conn: DbConn, nt: Notify<'_>) -> EmptyResult {
|
||||
_delete_cipher_by_uuid(&uuid, &headers, &mut conn, false, &nt).await
|
||||
#[delete("/ciphers/<cipher_id>/admin")]
|
||||
async fn delete_cipher_admin(cipher_id: CipherId, headers: Headers, mut conn: DbConn, nt: Notify<'_>) -> EmptyResult {
|
||||
_delete_cipher_by_uuid(&cipher_id, &headers, &mut conn, false, &nt).await
|
||||
// permanent delete
|
||||
}
|
||||
|
||||
|
@ -1503,14 +1518,19 @@ async fn delete_cipher_selected_put_admin(
|
|||
_delete_multiple_ciphers(data, headers, conn, true, nt).await // soft delete
|
||||
}
|
||||
|
||||
#[put("/ciphers/<uuid>/restore")]
|
||||
async fn restore_cipher_put(uuid: CipherId, headers: Headers, mut conn: DbConn, nt: Notify<'_>) -> JsonResult {
|
||||
_restore_cipher_by_uuid(&uuid, &headers, &mut conn, &nt).await
|
||||
#[put("/ciphers/<cipher_id>/restore")]
|
||||
async fn restore_cipher_put(cipher_id: CipherId, headers: Headers, mut conn: DbConn, nt: Notify<'_>) -> JsonResult {
|
||||
_restore_cipher_by_uuid(&cipher_id, &headers, &mut conn, &nt).await
|
||||
}
|
||||
|
||||
#[put("/ciphers/<uuid>/restore-admin")]
|
||||
async fn restore_cipher_put_admin(uuid: CipherId, headers: Headers, mut conn: DbConn, nt: Notify<'_>) -> JsonResult {
|
||||
_restore_cipher_by_uuid(&uuid, &headers, &mut conn, &nt).await
|
||||
#[put("/ciphers/<cipher_id>/restore-admin")]
|
||||
async fn restore_cipher_put_admin(
|
||||
cipher_id: CipherId,
|
||||
headers: Headers,
|
||||
mut conn: DbConn,
|
||||
nt: Notify<'_>,
|
||||
) -> JsonResult {
|
||||
_restore_cipher_by_uuid(&cipher_id, &headers, &mut conn, &nt).await
|
||||
}
|
||||
|
||||
#[put("/ciphers/restore", data = "<data>")]
|
||||
|
@ -1538,30 +1558,30 @@ async fn move_cipher_selected(
|
|||
nt: Notify<'_>,
|
||||
) -> EmptyResult {
|
||||
let data = data.into_inner();
|
||||
let user_uuid = headers.user.uuid;
|
||||
let user_id = headers.user.uuid;
|
||||
|
||||
if let Some(ref folder_uuid) = data.folder_id {
|
||||
if Folder::find_by_uuid_and_user(folder_uuid, &user_uuid, &mut conn).await.is_none() {
|
||||
if let Some(ref folder_id) = data.folder_id {
|
||||
if Folder::find_by_uuid_and_user(folder_id, &user_id, &mut conn).await.is_none() {
|
||||
err!("Invalid folder", "Folder does not exist or belongs to another user");
|
||||
}
|
||||
}
|
||||
|
||||
for uuid in data.ids {
|
||||
let Some(cipher) = Cipher::find_by_uuid(&uuid, &mut conn).await else {
|
||||
for cipher_id in data.ids {
|
||||
let Some(cipher) = Cipher::find_by_uuid(&cipher_id, &mut conn).await else {
|
||||
err!("Cipher doesn't exist")
|
||||
};
|
||||
|
||||
if !cipher.is_accessible_to_user(&user_uuid, &mut conn).await {
|
||||
if !cipher.is_accessible_to_user(&user_id, &mut conn).await {
|
||||
err!("Cipher is not accessible by user")
|
||||
}
|
||||
|
||||
// Move cipher
|
||||
cipher.move_to_folder(data.folder_id.clone(), &user_uuid, &mut conn).await?;
|
||||
cipher.move_to_folder(data.folder_id.clone(), &user_id, &mut conn).await?;
|
||||
|
||||
nt.send_cipher_update(
|
||||
UpdateType::SyncCipherUpdate,
|
||||
&cipher,
|
||||
&[user_uuid.clone()],
|
||||
&[user_id.clone()],
|
||||
&headers.device.uuid,
|
||||
None,
|
||||
&mut conn,
|
||||
|
@ -1650,13 +1670,13 @@ async fn delete_all(
|
|||
}
|
||||
|
||||
async fn _delete_cipher_by_uuid(
|
||||
uuid: &CipherId,
|
||||
cipher_id: &CipherId,
|
||||
headers: &Headers,
|
||||
conn: &mut DbConn,
|
||||
soft_delete: bool,
|
||||
nt: &Notify<'_>,
|
||||
) -> EmptyResult {
|
||||
let Some(mut cipher) = Cipher::find_by_uuid(uuid, conn).await else {
|
||||
let Some(mut cipher) = Cipher::find_by_uuid(cipher_id, conn).await else {
|
||||
err!("Cipher doesn't exist")
|
||||
};
|
||||
|
||||
|
@ -1689,13 +1709,13 @@ async fn _delete_cipher_by_uuid(
|
|||
.await;
|
||||
}
|
||||
|
||||
if let Some(org_uuid) = cipher.organization_uuid {
|
||||
if let Some(org_id) = cipher.organization_uuid {
|
||||
let event_type = match soft_delete {
|
||||
true => EventType::CipherSoftDeleted as i32,
|
||||
false => EventType::CipherDeleted as i32,
|
||||
};
|
||||
|
||||
log_event(event_type, &cipher.uuid, &org_uuid, &headers.user.uuid, headers.device.atype, &headers.ip.ip, conn)
|
||||
log_event(event_type, &cipher.uuid, &org_id, &headers.user.uuid, headers.device.atype, &headers.ip.ip, conn)
|
||||
.await;
|
||||
}
|
||||
|
||||
|
@ -1717,8 +1737,8 @@ async fn _delete_multiple_ciphers(
|
|||
) -> EmptyResult {
|
||||
let data = data.into_inner();
|
||||
|
||||
for uuid in data.ids {
|
||||
if let error @ Err(_) = _delete_cipher_by_uuid(&uuid, &headers, &mut conn, soft_delete, &nt).await {
|
||||
for cipher_id in data.ids {
|
||||
if let error @ Err(_) = _delete_cipher_by_uuid(&cipher_id, &headers, &mut conn, soft_delete, &nt).await {
|
||||
return error;
|
||||
};
|
||||
}
|
||||
|
@ -1726,8 +1746,13 @@ async fn _delete_multiple_ciphers(
|
|||
Ok(())
|
||||
}
|
||||
|
||||
async fn _restore_cipher_by_uuid(uuid: &CipherId, headers: &Headers, conn: &mut DbConn, nt: &Notify<'_>) -> JsonResult {
|
||||
let Some(mut cipher) = Cipher::find_by_uuid(uuid, conn).await else {
|
||||
async fn _restore_cipher_by_uuid(
|
||||
cipher_id: &CipherId,
|
||||
headers: &Headers,
|
||||
conn: &mut DbConn,
|
||||
nt: &Notify<'_>,
|
||||
) -> JsonResult {
|
||||
let Some(mut cipher) = Cipher::find_by_uuid(cipher_id, conn).await else {
|
||||
err!("Cipher doesn't exist")
|
||||
};
|
||||
|
||||
|
@ -1748,11 +1773,11 @@ async fn _restore_cipher_by_uuid(uuid: &CipherId, headers: &Headers, conn: &mut
|
|||
)
|
||||
.await;
|
||||
|
||||
if let Some(org_uuid) = &cipher.organization_uuid {
|
||||
if let Some(org_id) = &cipher.organization_uuid {
|
||||
log_event(
|
||||
EventType::CipherRestored as i32,
|
||||
&cipher.uuid.clone(),
|
||||
org_uuid,
|
||||
org_id,
|
||||
&headers.user.uuid,
|
||||
headers.device.atype,
|
||||
&headers.ip.ip,
|
||||
|
@ -1773,8 +1798,8 @@ async fn _restore_multiple_ciphers(
|
|||
let data = data.into_inner();
|
||||
|
||||
let mut ciphers: Vec<Value> = Vec::new();
|
||||
for uuid in data.ids {
|
||||
match _restore_cipher_by_uuid(&uuid, headers, conn, nt).await {
|
||||
for cipher_id in data.ids {
|
||||
match _restore_cipher_by_uuid(&cipher_id, headers, conn, nt).await {
|
||||
Ok(json) => ciphers.push(json.into_inner()),
|
||||
err => return err,
|
||||
}
|
||||
|
@ -1788,7 +1813,7 @@ async fn _restore_multiple_ciphers(
|
|||
}
|
||||
|
||||
async fn _delete_cipher_attachment_by_id(
|
||||
uuid: &CipherId,
|
||||
cipher_id: &CipherId,
|
||||
attachment_id: &AttachmentId,
|
||||
headers: &Headers,
|
||||
conn: &mut DbConn,
|
||||
|
@ -1798,11 +1823,11 @@ async fn _delete_cipher_attachment_by_id(
|
|||
err!("Attachment doesn't exist")
|
||||
};
|
||||
|
||||
if &attachment.cipher_uuid != uuid {
|
||||
if &attachment.cipher_uuid != cipher_id {
|
||||
err!("Attachment from other cipher")
|
||||
}
|
||||
|
||||
let Some(cipher) = Cipher::find_by_uuid(uuid, conn).await else {
|
||||
let Some(cipher) = Cipher::find_by_uuid(cipher_id, conn).await else {
|
||||
err!("Cipher doesn't exist")
|
||||
};
|
||||
|
||||
|
@ -1822,11 +1847,11 @@ async fn _delete_cipher_attachment_by_id(
|
|||
)
|
||||
.await;
|
||||
|
||||
if let Some(org_uuid) = cipher.organization_uuid {
|
||||
if let Some(org_id) = cipher.organization_uuid {
|
||||
log_event(
|
||||
EventType::CipherAttachmentDeleted as i32,
|
||||
&cipher.uuid,
|
||||
&org_uuid,
|
||||
&org_id,
|
||||
&headers.user.uuid,
|
||||
headers.device.atype,
|
||||
&headers.ip.ip,
|
||||
|
@ -1859,17 +1884,17 @@ pub enum CipherSyncType {
|
|||
}
|
||||
|
||||
impl CipherSyncData {
|
||||
pub async fn new(user_uuid: &UserId, sync_type: CipherSyncType, conn: &mut DbConn) -> Self {
|
||||
pub async fn new(user_id: &UserId, sync_type: CipherSyncType, conn: &mut DbConn) -> Self {
|
||||
let cipher_folders: HashMap<CipherId, FolderId>;
|
||||
let cipher_favorites: HashSet<CipherId>;
|
||||
match sync_type {
|
||||
// User Sync supports Folders and Favorites
|
||||
CipherSyncType::User => {
|
||||
// Generate a HashMap with the Cipher UUID as key and the Folder UUID as value
|
||||
cipher_folders = FolderCipher::find_by_user(user_uuid, conn).await.into_iter().collect();
|
||||
cipher_folders = FolderCipher::find_by_user(user_id, conn).await.into_iter().collect();
|
||||
|
||||
// Generate a HashSet of all the Cipher UUID's which are marked as favorite
|
||||
cipher_favorites = Favorite::get_all_cipher_uuid_by_user(user_uuid, conn).await.into_iter().collect();
|
||||
cipher_favorites = Favorite::get_all_cipher_uuid_by_user(user_id, conn).await.into_iter().collect();
|
||||
}
|
||||
// Organization Sync does not support Folders and Favorites.
|
||||
// If these are set, it will cause issues in the web-vault.
|
||||
|
@ -1880,15 +1905,15 @@ impl CipherSyncData {
|
|||
}
|
||||
|
||||
// Generate a list of Cipher UUID's containing a Vec with one or more Attachment records
|
||||
let orgs = Membership::get_orgs_by_user(user_uuid, conn).await;
|
||||
let attachments = Attachment::find_all_by_user_and_orgs(user_uuid, &orgs, conn).await;
|
||||
let orgs = Membership::get_orgs_by_user(user_id, conn).await;
|
||||
let attachments = Attachment::find_all_by_user_and_orgs(user_id, &orgs, conn).await;
|
||||
let mut cipher_attachments: HashMap<CipherId, Vec<Attachment>> = HashMap::with_capacity(attachments.len());
|
||||
for attachment in attachments {
|
||||
cipher_attachments.entry(attachment.cipher_uuid.clone()).or_default().push(attachment);
|
||||
}
|
||||
|
||||
// Generate a HashMap with the Cipher UUID as key and one or more Collection UUID's
|
||||
let user_cipher_collections = Cipher::get_collections_with_cipher_by_user(user_uuid.clone(), conn).await;
|
||||
let user_cipher_collections = Cipher::get_collections_with_cipher_by_user(user_id.clone(), conn).await;
|
||||
let mut cipher_collections: HashMap<CipherId, Vec<CollectionId>> =
|
||||
HashMap::with_capacity(user_cipher_collections.len());
|
||||
for (cipher, collection) in user_cipher_collections {
|
||||
|
@ -1897,10 +1922,10 @@ impl CipherSyncData {
|
|||
|
||||
// Generate a HashMap with the Organization UUID as key and the Membership record
|
||||
let members: HashMap<OrganizationId, Membership> =
|
||||
Membership::find_by_user(user_uuid, conn).await.into_iter().map(|m| (m.org_uuid.clone(), m)).collect();
|
||||
Membership::find_by_user(user_id, conn).await.into_iter().map(|m| (m.org_uuid.clone(), m)).collect();
|
||||
|
||||
// Generate a HashMap with the User_Collections UUID as key and the CollectionUser record
|
||||
let user_collections: HashMap<CollectionId, CollectionUser> = CollectionUser::find_by_user(user_uuid, conn)
|
||||
let user_collections: HashMap<CollectionId, CollectionUser> = CollectionUser::find_by_user(user_id, conn)
|
||||
.await
|
||||
.into_iter()
|
||||
.map(|uc| (uc.collection_uuid.clone(), uc))
|
||||
|
@ -1908,7 +1933,7 @@ impl CipherSyncData {
|
|||
|
||||
// Generate a HashMap with the collections_uuid as key and the CollectionGroup record
|
||||
let user_collections_groups: HashMap<CollectionId, CollectionGroup> = if CONFIG.org_groups_enabled() {
|
||||
CollectionGroup::find_by_user(user_uuid, conn)
|
||||
CollectionGroup::find_by_user(user_id, conn)
|
||||
.await
|
||||
.into_iter()
|
||||
.map(|collection_group| (collection_group.collections_uuid.clone(), collection_group))
|
||||
|
@ -1919,7 +1944,7 @@ impl CipherSyncData {
|
|||
|
||||
// Get all organizations that the given user has full access to via group assignment
|
||||
let user_group_full_access_for_organizations: HashSet<OrganizationId> = if CONFIG.org_groups_enabled() {
|
||||
Group::get_orgs_by_user_with_full_access(user_uuid, conn).await.into_iter().collect()
|
||||
Group::get_orgs_by_user_with_full_access(user_id, conn).await.into_iter().collect()
|
||||
} else {
|
||||
HashSet::new()
|
||||
};
|
||||
|
|
|
@ -701,11 +701,11 @@ async fn policies_emergency_access(emer_id: &str, headers: Headers, mut conn: Db
|
|||
|
||||
fn is_valid_request(
|
||||
emergency_access: &EmergencyAccess,
|
||||
requesting_user_uuid: &UserId,
|
||||
requesting_user_id: &UserId,
|
||||
requested_access_type: EmergencyAccessType,
|
||||
) -> bool {
|
||||
emergency_access.grantee_uuid.is_some()
|
||||
&& emergency_access.grantee_uuid.as_ref().unwrap() == requesting_user_uuid
|
||||
&& emergency_access.grantee_uuid.as_ref().unwrap() == requesting_user_id
|
||||
&& emergency_access.status == EmergencyAccessStatus::RecoveryApproved as i32
|
||||
&& emergency_access.atype == requested_access_type as i32
|
||||
}
|
||||
|
|
|
@ -180,11 +180,11 @@ async fn post_events_collect(data: Json<Vec<EventCollection>>, headers: Headers,
|
|||
.await;
|
||||
}
|
||||
1600..=1699 => {
|
||||
if let Some(org_uuid) = &event.organization_id {
|
||||
if let Some(org_id) = &event.organization_id {
|
||||
_log_event(
|
||||
event.r#type,
|
||||
org_uuid,
|
||||
org_uuid,
|
||||
org_id,
|
||||
org_id,
|
||||
&headers.user.uuid,
|
||||
headers.device.atype,
|
||||
Some(event_date),
|
||||
|
@ -197,11 +197,11 @@ async fn post_events_collect(data: Json<Vec<EventCollection>>, headers: Headers,
|
|||
_ => {
|
||||
if let Some(cipher_uuid) = &event.cipher_id {
|
||||
if let Some(cipher) = Cipher::find_by_uuid(cipher_uuid, &mut conn).await {
|
||||
if let Some(org_uuid) = cipher.organization_uuid {
|
||||
if let Some(org_id) = cipher.organization_uuid {
|
||||
_log_event(
|
||||
event.r#type,
|
||||
cipher_uuid,
|
||||
&org_uuid,
|
||||
&org_id,
|
||||
&headers.user.uuid,
|
||||
headers.device.atype,
|
||||
Some(event_date),
|
||||
|
@ -218,38 +218,38 @@ async fn post_events_collect(data: Json<Vec<EventCollection>>, headers: Headers,
|
|||
Ok(())
|
||||
}
|
||||
|
||||
pub async fn log_user_event(event_type: i32, user_uuid: &UserId, device_type: i32, ip: &IpAddr, conn: &mut DbConn) {
|
||||
pub async fn log_user_event(event_type: i32, user_id: &UserId, device_type: i32, ip: &IpAddr, conn: &mut DbConn) {
|
||||
if !CONFIG.org_events_enabled() {
|
||||
return;
|
||||
}
|
||||
_log_user_event(event_type, user_uuid, device_type, None, ip, conn).await;
|
||||
_log_user_event(event_type, user_id, device_type, None, ip, conn).await;
|
||||
}
|
||||
|
||||
async fn _log_user_event(
|
||||
event_type: i32,
|
||||
user_uuid: &UserId,
|
||||
user_id: &UserId,
|
||||
device_type: i32,
|
||||
event_date: Option<NaiveDateTime>,
|
||||
ip: &IpAddr,
|
||||
conn: &mut DbConn,
|
||||
) {
|
||||
let orgs = Membership::get_orgs_by_user(user_uuid, conn).await;
|
||||
let orgs = Membership::get_orgs_by_user(user_id, conn).await;
|
||||
let mut events: Vec<Event> = Vec::with_capacity(orgs.len() + 1); // We need an event per org and one without an org
|
||||
|
||||
// Upstream saves the event also without any org_uuid.
|
||||
// Upstream saves the event also without any org_id.
|
||||
let mut event = Event::new(event_type, event_date);
|
||||
event.user_uuid = Some(user_uuid.clone());
|
||||
event.act_user_uuid = Some(user_uuid.to_string());
|
||||
event.user_uuid = Some(user_id.clone());
|
||||
event.act_user_uuid = Some(user_id.to_string());
|
||||
event.device_type = Some(device_type);
|
||||
event.ip_address = Some(ip.to_string());
|
||||
events.push(event);
|
||||
|
||||
// For each org a user is a member of store these events per org
|
||||
for org_uuid in orgs {
|
||||
for org_id in orgs {
|
||||
let mut event = Event::new(event_type, event_date);
|
||||
event.user_uuid = Some(user_uuid.clone());
|
||||
event.org_uuid = Some(org_uuid);
|
||||
event.act_user_uuid = Some(user_uuid.to_string());
|
||||
event.user_uuid = Some(user_id.clone());
|
||||
event.org_uuid = Some(org_id);
|
||||
event.act_user_uuid = Some(user_id.to_string());
|
||||
event.device_type = Some(device_type);
|
||||
event.ip_address = Some(ip.to_string());
|
||||
events.push(event);
|
||||
|
@ -261,8 +261,8 @@ async fn _log_user_event(
|
|||
pub async fn log_event(
|
||||
event_type: i32,
|
||||
source_uuid: &str,
|
||||
org_uuid: &OrganizationId,
|
||||
act_user_uuid: &str,
|
||||
org_id: &OrganizationId,
|
||||
act_user_id: &str,
|
||||
device_type: i32,
|
||||
ip: &IpAddr,
|
||||
conn: &mut DbConn,
|
||||
|
@ -270,15 +270,15 @@ pub async fn log_event(
|
|||
if !CONFIG.org_events_enabled() {
|
||||
return;
|
||||
}
|
||||
_log_event(event_type, source_uuid, org_uuid, act_user_uuid, device_type, None, ip, conn).await;
|
||||
_log_event(event_type, source_uuid, org_id, act_user_id, device_type, None, ip, conn).await;
|
||||
}
|
||||
|
||||
#[allow(clippy::too_many_arguments)]
|
||||
async fn _log_event(
|
||||
event_type: i32,
|
||||
source_uuid: &str,
|
||||
org_uuid: &OrganizationId,
|
||||
act_user_uuid: &str,
|
||||
org_id: &OrganizationId,
|
||||
act_user_id: &str,
|
||||
device_type: i32,
|
||||
event_date: Option<NaiveDateTime>,
|
||||
ip: &IpAddr,
|
||||
|
@ -313,8 +313,8 @@ async fn _log_event(
|
|||
_ => {}
|
||||
}
|
||||
|
||||
event.org_uuid = Some(org_uuid.clone());
|
||||
event.act_user_uuid = Some(String::from(act_user_uuid));
|
||||
event.org_uuid = Some(org_id.clone());
|
||||
event.act_user_uuid = Some(String::from(act_user_id));
|
||||
event.device_type = Some(device_type);
|
||||
event.ip_address = Some(ip.to_string());
|
||||
event.save(conn).await.unwrap_or(());
|
||||
|
|
|
@ -23,9 +23,9 @@ async fn get_folders(headers: Headers, mut conn: DbConn) -> Json<Value> {
|
|||
}))
|
||||
}
|
||||
|
||||
#[get("/folders/<uuid>")]
|
||||
async fn get_folder(uuid: FolderId, headers: Headers, mut conn: DbConn) -> JsonResult {
|
||||
match Folder::find_by_uuid_and_user(&uuid, &headers.user.uuid, &mut conn).await {
|
||||
#[get("/folders/<folder_id>")]
|
||||
async fn get_folder(folder_id: FolderId, headers: Headers, mut conn: DbConn) -> JsonResult {
|
||||
match Folder::find_by_uuid_and_user(&folder_id, &headers.user.uuid, &mut conn).await {
|
||||
Some(folder) => Ok(Json(folder.to_json())),
|
||||
_ => err!("Invalid folder", "Folder does not exist or belongs to another user"),
|
||||
}
|
||||
|
@ -50,20 +50,20 @@ async fn post_folders(data: Json<FolderData>, headers: Headers, mut conn: DbConn
|
|||
Ok(Json(folder.to_json()))
|
||||
}
|
||||
|
||||
#[post("/folders/<uuid>", data = "<data>")]
|
||||
#[post("/folders/<folder_id>", data = "<data>")]
|
||||
async fn post_folder(
|
||||
uuid: FolderId,
|
||||
folder_id: FolderId,
|
||||
data: Json<FolderData>,
|
||||
headers: Headers,
|
||||
conn: DbConn,
|
||||
nt: Notify<'_>,
|
||||
) -> JsonResult {
|
||||
put_folder(uuid, data, headers, conn, nt).await
|
||||
put_folder(folder_id, data, headers, conn, nt).await
|
||||
}
|
||||
|
||||
#[put("/folders/<uuid>", data = "<data>")]
|
||||
#[put("/folders/<folder_id>", data = "<data>")]
|
||||
async fn put_folder(
|
||||
uuid: FolderId,
|
||||
folder_id: FolderId,
|
||||
data: Json<FolderData>,
|
||||
headers: Headers,
|
||||
mut conn: DbConn,
|
||||
|
@ -71,7 +71,7 @@ async fn put_folder(
|
|||
) -> JsonResult {
|
||||
let data: FolderData = data.into_inner();
|
||||
|
||||
let Some(mut folder) = Folder::find_by_uuid_and_user(&uuid, &headers.user.uuid, &mut conn).await else {
|
||||
let Some(mut folder) = Folder::find_by_uuid_and_user(&folder_id, &headers.user.uuid, &mut conn).await else {
|
||||
err!("Invalid folder", "Folder does not exist or belongs to another user")
|
||||
};
|
||||
|
||||
|
@ -83,14 +83,14 @@ async fn put_folder(
|
|||
Ok(Json(folder.to_json()))
|
||||
}
|
||||
|
||||
#[post("/folders/<uuid>/delete")]
|
||||
async fn delete_folder_post(uuid: FolderId, headers: Headers, conn: DbConn, nt: Notify<'_>) -> EmptyResult {
|
||||
delete_folder(uuid, headers, conn, nt).await
|
||||
#[post("/folders/<folder_id>/delete")]
|
||||
async fn delete_folder_post(folder_id: FolderId, headers: Headers, conn: DbConn, nt: Notify<'_>) -> EmptyResult {
|
||||
delete_folder(folder_id, headers, conn, nt).await
|
||||
}
|
||||
|
||||
#[delete("/folders/<uuid>")]
|
||||
async fn delete_folder(uuid: FolderId, headers: Headers, mut conn: DbConn, nt: Notify<'_>) -> EmptyResult {
|
||||
let Some(folder) = Folder::find_by_uuid_and_user(&uuid, &headers.user.uuid, &mut conn).await else {
|
||||
#[delete("/folders/<folder_id>")]
|
||||
async fn delete_folder(folder_id: FolderId, headers: Headers, mut conn: DbConn, nt: Notify<'_>) -> EmptyResult {
|
||||
let Some(folder) = Folder::find_by_uuid_and_user(&folder_id, &headers.user.uuid, &mut conn).await else {
|
||||
err!("Invalid folder", "Folder does not exist or belongs to another user")
|
||||
};
|
||||
|
||||
|
|
|
@ -753,14 +753,13 @@ async fn get_org_details(data: OrgIdData, headers: Headers, mut conn: DbConn) ->
|
|||
})))
|
||||
}
|
||||
|
||||
async fn _get_org_details(org_id: &OrganizationId, host: &str, user_uuid: &UserId, conn: &mut DbConn) -> Value {
|
||||
async fn _get_org_details(org_id: &OrganizationId, host: &str, user_id: &UserId, conn: &mut DbConn) -> Value {
|
||||
let ciphers = Cipher::find_by_org(org_id, conn).await;
|
||||
let cipher_sync_data = CipherSyncData::new(user_uuid, CipherSyncType::Organization, conn).await;
|
||||
let cipher_sync_data = CipherSyncData::new(user_id, CipherSyncType::Organization, conn).await;
|
||||
|
||||
let mut ciphers_json = Vec::with_capacity(ciphers.len());
|
||||
for c in ciphers {
|
||||
ciphers_json
|
||||
.push(c.to_json(host, user_uuid, Some(&cipher_sync_data), CipherSyncType::Organization, conn).await);
|
||||
ciphers_json.push(c.to_json(host, user_id, Some(&cipher_sync_data), CipherSyncType::Organization, conn).await);
|
||||
}
|
||||
json!(ciphers_json)
|
||||
}
|
||||
|
|
|
@ -219,11 +219,11 @@ impl<'r> FromRequest<'r> for PublicToken {
|
|||
Outcome::Success(conn) => conn,
|
||||
_ => err_handler!("Error getting DB"),
|
||||
};
|
||||
let Some(org_uuid) = claims.client_id.strip_prefix("organization.") else {
|
||||
let Some(org_id) = claims.client_id.strip_prefix("organization.") else {
|
||||
err_handler!("Malformed client_id")
|
||||
};
|
||||
let org_uuid: OrganizationId = org_uuid.to_string().into();
|
||||
let Some(org_api_key) = OrganizationApiKey::find_by_org_uuid(&org_uuid, &conn).await else {
|
||||
let org_id: OrganizationId = org_id.to_string().into();
|
||||
let Some(org_api_key) = OrganizationApiKey::find_by_org_uuid(&org_id, &conn).await else {
|
||||
err_handler!("Invalid client_id")
|
||||
};
|
||||
if org_api_key.org_uuid != claims.client_sub {
|
||||
|
|
|
@ -79,9 +79,9 @@ pub struct SendData {
|
|||
/// There is also a Vaultwarden-specific `sends_allowed` config setting that
|
||||
/// controls this policy globally.
|
||||
async fn enforce_disable_send_policy(headers: &Headers, conn: &mut DbConn) -> EmptyResult {
|
||||
let user_uuid = &headers.user.uuid;
|
||||
let user_id = &headers.user.uuid;
|
||||
if !CONFIG.sends_allowed()
|
||||
|| OrgPolicy::is_applicable_to_user(user_uuid, OrgPolicyType::DisableSend, None, conn).await
|
||||
|| OrgPolicy::is_applicable_to_user(user_id, OrgPolicyType::DisableSend, None, conn).await
|
||||
{
|
||||
err!("Due to an Enterprise Policy, you are only able to delete an existing Send.")
|
||||
}
|
||||
|
@ -95,9 +95,9 @@ async fn enforce_disable_send_policy(headers: &Headers, conn: &mut DbConn) -> Em
|
|||
///
|
||||
/// Ref: https://bitwarden.com/help/article/policies/#send-options
|
||||
async fn enforce_disable_hide_email_policy(data: &SendData, headers: &Headers, conn: &mut DbConn) -> EmptyResult {
|
||||
let user_uuid = &headers.user.uuid;
|
||||
let user_id = &headers.user.uuid;
|
||||
let hide_email = data.hide_email.unwrap_or(false);
|
||||
if hide_email && OrgPolicy::is_hide_email_disabled(user_uuid, conn).await {
|
||||
if hide_email && OrgPolicy::is_hide_email_disabled(user_id, conn).await {
|
||||
err!(
|
||||
"Due to an Enterprise Policy, you are not allowed to hide your email address \
|
||||
from recipients when creating or editing a Send."
|
||||
|
@ -106,7 +106,7 @@ async fn enforce_disable_hide_email_policy(data: &SendData, headers: &Headers, c
|
|||
Ok(())
|
||||
}
|
||||
|
||||
fn create_send(data: SendData, user_uuid: UserId) -> ApiResult<Send> {
|
||||
fn create_send(data: SendData, user_id: UserId) -> ApiResult<Send> {
|
||||
let data_val = if data.r#type == SendType::Text as i32 {
|
||||
data.text
|
||||
} else if data.r#type == SendType::File as i32 {
|
||||
|
@ -129,7 +129,7 @@ fn create_send(data: SendData, user_uuid: UserId) -> ApiResult<Send> {
|
|||
}
|
||||
|
||||
let mut send = Send::new(data.r#type, data.name, data_str, data.key, data.deletion_date.naive_utc());
|
||||
send.user_uuid = Some(user_uuid);
|
||||
send.user_uuid = Some(user_id);
|
||||
send.notes = data.notes;
|
||||
send.max_access_count = match data.max_access_count {
|
||||
Some(m) => Some(m.into_i32()?),
|
||||
|
@ -157,11 +157,11 @@ async fn get_sends(headers: Headers, mut conn: DbConn) -> Json<Value> {
|
|||
}))
|
||||
}
|
||||
|
||||
#[get("/sends/<uuid>")]
|
||||
async fn get_send(uuid: SendId, headers: Headers, mut conn: DbConn) -> JsonResult {
|
||||
match Send::find_by_uuid_and_user(&uuid, &headers.user.uuid, &mut conn).await {
|
||||
#[get("/sends/<send_id>")]
|
||||
async fn get_send(send_id: SendId, headers: Headers, mut conn: DbConn) -> JsonResult {
|
||||
match Send::find_by_uuid_and_user(&send_id, &headers.user.uuid, &mut conn).await {
|
||||
Some(send) => Ok(Json(send.to_json())),
|
||||
None => err!("Send not found", "Invalid uuid or does not belong to user"),
|
||||
None => err!("Send not found", "Invalid send uuid or does not belong to user"),
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -352,9 +352,9 @@ pub struct SendFileData {
|
|||
}
|
||||
|
||||
// https://github.com/bitwarden/server/blob/66f95d1c443490b653e5a15d32977e2f5a3f9e32/src/Api/Tools/Controllers/SendsController.cs#L250
|
||||
#[post("/sends/<uuid>/file/<file_id>", format = "multipart/form-data", data = "<data>")]
|
||||
#[post("/sends/<send_id>/file/<file_id>", format = "multipart/form-data", data = "<data>")]
|
||||
async fn post_send_file_v2_data(
|
||||
uuid: SendId,
|
||||
send_id: SendId,
|
||||
file_id: SendFileId,
|
||||
data: Form<UploadDataV2<'_>>,
|
||||
headers: Headers,
|
||||
|
@ -365,8 +365,8 @@ async fn post_send_file_v2_data(
|
|||
|
||||
let mut data = data.into_inner();
|
||||
|
||||
let Some(send) = Send::find_by_uuid_and_user(&uuid, &headers.user.uuid, &mut conn).await else {
|
||||
err!("Send not found. Unable to save the file.", "Invalid uuid or does not belong to user.")
|
||||
let Some(send) = Send::find_by_uuid_and_user(&send_id, &headers.user.uuid, &mut conn).await else {
|
||||
err!("Send not found. Unable to save the file.", "Invalid send uuid or does not belong to user.")
|
||||
};
|
||||
|
||||
if send.atype != SendType::File as i32 {
|
||||
|
@ -402,7 +402,7 @@ async fn post_send_file_v2_data(
|
|||
err!("Send file size does not match.", format!("Expected a file size of {} got {size}", send_data.size));
|
||||
}
|
||||
|
||||
let folder_path = tokio::fs::canonicalize(&CONFIG.sends_folder()).await?.join(uuid);
|
||||
let folder_path = tokio::fs::canonicalize(&CONFIG.sends_folder()).await?.join(send_id);
|
||||
let file_path = folder_path.join(file_id);
|
||||
|
||||
// Check if the file already exists, if that is the case do not overwrite it
|
||||
|
@ -493,16 +493,16 @@ async fn post_access(
|
|||
Ok(Json(send.to_json_access(&mut conn).await))
|
||||
}
|
||||
|
||||
#[post("/sends/<uuid>/access/file/<file_id>", data = "<data>")]
|
||||
#[post("/sends/<send_id>/access/file/<file_id>", data = "<data>")]
|
||||
async fn post_access_file(
|
||||
uuid: SendId,
|
||||
send_id: SendId,
|
||||
file_id: SendFileId,
|
||||
data: Json<SendAccessData>,
|
||||
host: Host,
|
||||
mut conn: DbConn,
|
||||
nt: Notify<'_>,
|
||||
) -> JsonResult {
|
||||
let Some(mut send) = Send::find_by_uuid(&uuid, &mut conn).await else {
|
||||
let Some(mut send) = Send::find_by_uuid(&send_id, &mut conn).await else {
|
||||
err_code!(SEND_INACCESSIBLE_MSG, 404)
|
||||
};
|
||||
|
||||
|
@ -547,28 +547,28 @@ async fn post_access_file(
|
|||
)
|
||||
.await;
|
||||
|
||||
let token_claims = crate::auth::generate_send_claims(&uuid, &file_id);
|
||||
let token_claims = crate::auth::generate_send_claims(&send_id, &file_id);
|
||||
let token = crate::auth::encode_jwt(&token_claims);
|
||||
Ok(Json(json!({
|
||||
"object": "send-fileDownload",
|
||||
"id": file_id,
|
||||
"url": format!("{}/api/sends/{}/{}?t={}", &host.host, uuid, file_id, token)
|
||||
"url": format!("{}/api/sends/{}/{}?t={}", &host.host, send_id, file_id, token)
|
||||
})))
|
||||
}
|
||||
|
||||
#[get("/sends/<uuid>/<file_id>?<t>")]
|
||||
async fn download_send(uuid: SendId, file_id: SendFileId, t: &str) -> Option<NamedFile> {
|
||||
#[get("/sends/<send_id>/<file_id>?<t>")]
|
||||
async fn download_send(send_id: SendId, file_id: SendFileId, t: &str) -> Option<NamedFile> {
|
||||
if let Ok(claims) = crate::auth::decode_send(t) {
|
||||
if claims.sub == format!("{uuid}/{file_id}") {
|
||||
return NamedFile::open(Path::new(&CONFIG.sends_folder()).join(uuid).join(file_id)).await.ok();
|
||||
if claims.sub == format!("{send_id}/{file_id}") {
|
||||
return NamedFile::open(Path::new(&CONFIG.sends_folder()).join(send_id).join(file_id)).await.ok();
|
||||
}
|
||||
}
|
||||
None
|
||||
}
|
||||
|
||||
#[put("/sends/<uuid>", data = "<data>")]
|
||||
#[put("/sends/<send_id>", data = "<data>")]
|
||||
async fn put_send(
|
||||
uuid: SendId,
|
||||
send_id: SendId,
|
||||
data: Json<SendData>,
|
||||
headers: Headers,
|
||||
mut conn: DbConn,
|
||||
|
@ -579,8 +579,8 @@ async fn put_send(
|
|||
let data: SendData = data.into_inner();
|
||||
enforce_disable_hide_email_policy(&data, &headers, &mut conn).await?;
|
||||
|
||||
let Some(mut send) = Send::find_by_uuid_and_user(&uuid, &headers.user.uuid, &mut conn).await else {
|
||||
err!("Send not found", "Send uuid is invalid or does not belong to user")
|
||||
let Some(mut send) = Send::find_by_uuid_and_user(&send_id, &headers.user.uuid, &mut conn).await else {
|
||||
err!("Send not found", "Send send_id is invalid or does not belong to user")
|
||||
};
|
||||
|
||||
update_send_from_data(&mut send, data, &headers, &mut conn, &nt, UpdateType::SyncSendUpdate).await?;
|
||||
|
@ -646,9 +646,9 @@ pub async fn update_send_from_data(
|
|||
Ok(())
|
||||
}
|
||||
|
||||
#[delete("/sends/<uuid>")]
|
||||
async fn delete_send(uuid: SendId, headers: Headers, mut conn: DbConn, nt: Notify<'_>) -> EmptyResult {
|
||||
let Some(send) = Send::find_by_uuid_and_user(&uuid, &headers.user.uuid, &mut conn).await else {
|
||||
#[delete("/sends/<send_id>")]
|
||||
async fn delete_send(send_id: SendId, headers: Headers, mut conn: DbConn, nt: Notify<'_>) -> EmptyResult {
|
||||
let Some(send) = Send::find_by_uuid_and_user(&send_id, &headers.user.uuid, &mut conn).await else {
|
||||
err!("Send not found", "Invalid send uuid, or does not belong to user")
|
||||
};
|
||||
|
||||
|
@ -665,11 +665,11 @@ async fn delete_send(uuid: SendId, headers: Headers, mut conn: DbConn, nt: Notif
|
|||
Ok(())
|
||||
}
|
||||
|
||||
#[put("/sends/<uuid>/remove-password")]
|
||||
async fn put_remove_password(uuid: SendId, headers: Headers, mut conn: DbConn, nt: Notify<'_>) -> JsonResult {
|
||||
#[put("/sends/<send_id>/remove-password")]
|
||||
async fn put_remove_password(send_id: SendId, headers: Headers, mut conn: DbConn, nt: Notify<'_>) -> JsonResult {
|
||||
enforce_disable_send_policy(&headers, &mut conn).await?;
|
||||
|
||||
let Some(mut send) = Send::find_by_uuid_and_user(&uuid, &headers.user.uuid, &mut conn).await else {
|
||||
let Some(mut send) = Send::find_by_uuid_and_user(&send_id, &headers.user.uuid, &mut conn).await else {
|
||||
err!("Send not found", "Invalid send uuid, or does not belong to user")
|
||||
};
|
||||
|
||||
|
|
|
@ -95,7 +95,7 @@ async fn activate_authenticator_put(data: Json<EnableAuthenticatorData>, headers
|
|||
}
|
||||
|
||||
pub async fn validate_totp_code_str(
|
||||
user_uuid: &UserId,
|
||||
user_id: &UserId,
|
||||
totp_code: &str,
|
||||
secret: &str,
|
||||
ip: &ClientIp,
|
||||
|
@ -105,11 +105,11 @@ pub async fn validate_totp_code_str(
|
|||
err!("TOTP code is not a number");
|
||||
}
|
||||
|
||||
validate_totp_code(user_uuid, totp_code, secret, ip, conn).await
|
||||
validate_totp_code(user_id, totp_code, secret, ip, conn).await
|
||||
}
|
||||
|
||||
pub async fn validate_totp_code(
|
||||
user_uuid: &UserId,
|
||||
user_id: &UserId,
|
||||
totp_code: &str,
|
||||
secret: &str,
|
||||
ip: &ClientIp,
|
||||
|
@ -121,11 +121,11 @@ pub async fn validate_totp_code(
|
|||
err!("Invalid TOTP secret")
|
||||
};
|
||||
|
||||
let mut twofactor =
|
||||
match TwoFactor::find_by_user_and_type(user_uuid, TwoFactorType::Authenticator as i32, conn).await {
|
||||
Some(tf) => tf,
|
||||
_ => TwoFactor::new(user_uuid.clone(), TwoFactorType::Authenticator, secret.to_string()),
|
||||
};
|
||||
let mut twofactor = match TwoFactor::find_by_user_and_type(user_id, TwoFactorType::Authenticator as i32, conn).await
|
||||
{
|
||||
Some(tf) => tf,
|
||||
_ => TwoFactor::new(user_id.clone(), TwoFactorType::Authenticator, secret.to_string()),
|
||||
};
|
||||
|
||||
// The amount of steps back and forward in time
|
||||
// Also check if we need to disable time drifted TOTP codes.
|
||||
|
|
|
@ -228,11 +228,11 @@ const AUTH_PREFIX: &str = "AUTH";
|
|||
const DUO_PREFIX: &str = "TX";
|
||||
const APP_PREFIX: &str = "APP";
|
||||
|
||||
async fn get_user_duo_data(user_uuid: &UserId, conn: &mut DbConn) -> DuoStatus {
|
||||
async fn get_user_duo_data(user_id: &UserId, conn: &mut DbConn) -> DuoStatus {
|
||||
let type_ = TwoFactorType::Duo as i32;
|
||||
|
||||
// If the user doesn't have an entry, disabled
|
||||
let Some(twofactor) = TwoFactor::find_by_user_and_type(user_uuid, type_, conn).await else {
|
||||
let Some(twofactor) = TwoFactor::find_by_user_and_type(user_id, type_, conn).await else {
|
||||
return DuoStatus::Disabled(DuoData::global().is_some());
|
||||
};
|
||||
|
||||
|
|
|
@ -59,10 +59,9 @@ async fn send_email_login(data: Json<SendEmailLoginData>, mut conn: DbConn) -> E
|
|||
}
|
||||
|
||||
/// Generate the token, save the data for later verification and send email to user
|
||||
pub async fn send_token(user_uuid: &UserId, conn: &mut DbConn) -> EmptyResult {
|
||||
pub async fn send_token(user_id: &UserId, conn: &mut DbConn) -> EmptyResult {
|
||||
let type_ = TwoFactorType::Email as i32;
|
||||
let mut twofactor =
|
||||
TwoFactor::find_by_user_and_type(user_uuid, type_, conn).await.map_res("Two factor not found")?;
|
||||
let mut twofactor = TwoFactor::find_by_user_and_type(user_id, type_, conn).await.map_res("Two factor not found")?;
|
||||
|
||||
let generated_token = crypto::generate_email_token(CONFIG.email_token_size());
|
||||
|
||||
|
@ -198,9 +197,9 @@ async fn email(data: Json<EmailData>, headers: Headers, mut conn: DbConn) -> Jso
|
|||
}
|
||||
|
||||
/// Validate the email code when used as TwoFactor token mechanism
|
||||
pub async fn validate_email_code_str(user_uuid: &UserId, token: &str, data: &str, conn: &mut DbConn) -> EmptyResult {
|
||||
pub async fn validate_email_code_str(user_id: &UserId, token: &str, data: &str, conn: &mut DbConn) -> EmptyResult {
|
||||
let mut email_data = EmailTokenData::from_json(data)?;
|
||||
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_id, TwoFactorType::Email as i32, conn)
|
||||
.await
|
||||
.map_res("Two factor not found")?;
|
||||
let Some(issued_token) = &email_data.last_token else {
|
||||
|
@ -327,8 +326,8 @@ pub fn obscure_email(email: &str) -> String {
|
|||
format!("{}@{}", new_name, &domain)
|
||||
}
|
||||
|
||||
pub async fn find_and_activate_email_2fa(user_uuid: &UserId, conn: &mut DbConn) -> EmptyResult {
|
||||
if let Some(user) = User::find_by_uuid(user_uuid, conn).await {
|
||||
pub async fn find_and_activate_email_2fa(user_id: &UserId, conn: &mut DbConn) -> EmptyResult {
|
||||
if let Some(user) = User::find_by_uuid(user_id, conn).await {
|
||||
activate_email_2fa(&user, conn).await
|
||||
} else {
|
||||
err!("User not found!");
|
||||
|
|
|
@ -173,7 +173,7 @@ async fn disable_twofactor_put(data: Json<DisableTwoFactorData>, headers: Header
|
|||
|
||||
pub async fn enforce_2fa_policy(
|
||||
user: &User,
|
||||
act_uuid: &str,
|
||||
act_user_id: &str,
|
||||
device_type: i32,
|
||||
ip: &std::net::IpAddr,
|
||||
conn: &mut DbConn,
|
||||
|
@ -195,7 +195,7 @@ pub async fn enforce_2fa_policy(
|
|||
EventType::OrganizationUserRevoked as i32,
|
||||
&member.uuid,
|
||||
&member.org_uuid,
|
||||
act_uuid,
|
||||
act_user_id,
|
||||
device_type,
|
||||
ip,
|
||||
conn,
|
||||
|
@ -208,14 +208,14 @@ pub async fn enforce_2fa_policy(
|
|||
}
|
||||
|
||||
pub async fn enforce_2fa_policy_for_org(
|
||||
org_uuid: &OrganizationId,
|
||||
act_uuid: &str,
|
||||
org_id: &OrganizationId,
|
||||
act_user_id: &str,
|
||||
device_type: i32,
|
||||
ip: &std::net::IpAddr,
|
||||
conn: &mut DbConn,
|
||||
) -> EmptyResult {
|
||||
let org = Organization::find_by_uuid(org_uuid, conn).await.unwrap();
|
||||
for member in Membership::find_confirmed_by_org(org_uuid, conn).await.into_iter() {
|
||||
let org = Organization::find_by_uuid(org_id, conn).await.unwrap();
|
||||
for member in Membership::find_confirmed_by_org(org_id, conn).await.into_iter() {
|
||||
// Don't enforce the policy for Admins and Owners.
|
||||
if member.atype < MembershipType::Admin && TwoFactor::find_by_user(&member.user_uuid, conn).await.is_empty() {
|
||||
if CONFIG.mail_enabled() {
|
||||
|
@ -229,8 +229,8 @@ pub async fn enforce_2fa_policy_for_org(
|
|||
log_event(
|
||||
EventType::OrganizationUserRevoked as i32,
|
||||
&member.uuid,
|
||||
org_uuid,
|
||||
act_uuid,
|
||||
org_id,
|
||||
act_user_id,
|
||||
device_type,
|
||||
ip,
|
||||
conn,
|
||||
|
|
|
@ -104,11 +104,11 @@ async fn verify_otp(data: Json<ProtectedActionVerify>, headers: Headers, mut con
|
|||
|
||||
pub async fn validate_protected_action_otp(
|
||||
otp: &str,
|
||||
user_uuid: &UserId,
|
||||
user_id: &UserId,
|
||||
delete_if_valid: bool,
|
||||
conn: &mut DbConn,
|
||||
) -> EmptyResult {
|
||||
let pa = TwoFactor::find_by_user_and_type(user_uuid, TwoFactorType::ProtectedActions as i32, conn)
|
||||
let pa = TwoFactor::find_by_user_and_type(user_id, TwoFactorType::ProtectedActions as i32, conn)
|
||||
.await
|
||||
.map_res("Protected action token not found, try sending the code again or restart the process")?;
|
||||
let mut pa_data = ProtectedActionData::from_json(&pa.data)?;
|
||||
|
|
|
@ -352,20 +352,20 @@ async fn delete_webauthn(data: Json<DeleteU2FData>, headers: Headers, mut conn:
|
|||
}
|
||||
|
||||
pub async fn get_webauthn_registrations(
|
||||
user_uuid: &UserId,
|
||||
user_id: &UserId,
|
||||
conn: &mut DbConn,
|
||||
) -> Result<(bool, Vec<WebauthnRegistration>), Error> {
|
||||
let type_ = TwoFactorType::Webauthn as i32;
|
||||
match TwoFactor::find_by_user_and_type(user_uuid, type_, conn).await {
|
||||
match TwoFactor::find_by_user_and_type(user_id, type_, conn).await {
|
||||
Some(tf) => Ok((tf.enabled, serde_json::from_str(&tf.data)?)),
|
||||
None => Ok((false, Vec::new())), // If no data, return empty list
|
||||
}
|
||||
}
|
||||
|
||||
pub async fn generate_webauthn_login(user_uuid: &UserId, conn: &mut DbConn) -> JsonResult {
|
||||
pub async fn generate_webauthn_login(user_id: &UserId, conn: &mut DbConn) -> JsonResult {
|
||||
// Load saved credentials
|
||||
let creds: Vec<Credential> =
|
||||
get_webauthn_registrations(user_uuid, conn).await?.1.into_iter().map(|r| r.credential).collect();
|
||||
get_webauthn_registrations(user_id, conn).await?.1.into_iter().map(|r| r.credential).collect();
|
||||
|
||||
if creds.is_empty() {
|
||||
err!("No Webauthn devices registered")
|
||||
|
@ -376,7 +376,7 @@ pub async fn generate_webauthn_login(user_uuid: &UserId, conn: &mut DbConn) -> J
|
|||
let (response, state) = WebauthnConfig::load().generate_challenge_authenticate_options(creds, Some(ext))?;
|
||||
|
||||
// Save the challenge state for later validation
|
||||
TwoFactor::new(user_uuid.clone(), TwoFactorType::WebauthnLoginChallenge, serde_json::to_string(&state)?)
|
||||
TwoFactor::new(user_id.clone(), TwoFactorType::WebauthnLoginChallenge, serde_json::to_string(&state)?)
|
||||
.save(conn)
|
||||
.await?;
|
||||
|
||||
|
@ -384,9 +384,9 @@ pub async fn generate_webauthn_login(user_uuid: &UserId, conn: &mut DbConn) -> J
|
|||
Ok(Json(serde_json::to_value(response.public_key)?))
|
||||
}
|
||||
|
||||
pub async fn validate_webauthn_login(user_uuid: &UserId, response: &str, conn: &mut DbConn) -> EmptyResult {
|
||||
pub async fn validate_webauthn_login(user_id: &UserId, response: &str, conn: &mut DbConn) -> EmptyResult {
|
||||
let type_ = TwoFactorType::WebauthnLoginChallenge as i32;
|
||||
let state = match TwoFactor::find_by_user_and_type(user_uuid, type_, conn).await {
|
||||
let state = match TwoFactor::find_by_user_and_type(user_id, type_, conn).await {
|
||||
Some(tf) => {
|
||||
let state: AuthenticationState = serde_json::from_str(&tf.data)?;
|
||||
tf.delete(conn).await?;
|
||||
|
@ -403,7 +403,7 @@ pub async fn validate_webauthn_login(user_uuid: &UserId, response: &str, conn: &
|
|||
let rsp: PublicKeyCredentialCopy = serde_json::from_str(response)?;
|
||||
let rsp: PublicKeyCredential = rsp.into();
|
||||
|
||||
let mut registrations = get_webauthn_registrations(user_uuid, conn).await?.1;
|
||||
let mut registrations = get_webauthn_registrations(user_id, conn).await?.1;
|
||||
|
||||
// If the credential we received is migrated from U2F, enable the U2F compatibility
|
||||
//let use_u2f = registrations.iter().any(|r| r.migrated && r.credential.cred_id == rsp.raw_id.0);
|
||||
|
@ -413,7 +413,7 @@ pub async fn validate_webauthn_login(user_uuid: &UserId, response: &str, conn: &
|
|||
if ®.credential.cred_id == cred_id {
|
||||
reg.credential.counter = auth_data.counter;
|
||||
|
||||
TwoFactor::new(user_uuid.clone(), TwoFactorType::Webauthn, serde_json::to_string(®istrations)?)
|
||||
TwoFactor::new(user_id.clone(), TwoFactorType::Webauthn, serde_json::to_string(®istrations)?)
|
||||
.save(conn)
|
||||
.await?;
|
||||
return Ok(());
|
||||
|
|
|
@ -92,10 +92,10 @@ async fn generate_yubikey(data: Json<PasswordOrOtpData>, headers: Headers, mut c
|
|||
|
||||
data.validate(&user, false, &mut conn).await?;
|
||||
|
||||
let user_uuid = &user.uuid;
|
||||
let user_id = &user.uuid;
|
||||
let yubikey_type = TwoFactorType::YubiKey as i32;
|
||||
|
||||
let r = TwoFactor::find_by_user_and_type(user_uuid, yubikey_type, &mut conn).await;
|
||||
let r = TwoFactor::find_by_user_and_type(user_id, yubikey_type, &mut conn).await;
|
||||
|
||||
if let Some(r) = r {
|
||||
let yubikey_metadata: YubikeyMetadata = serde_json::from_str(&r.data)?;
|
||||
|
|
|
@ -31,7 +31,7 @@ pub fn routes() -> Vec<Route> {
|
|||
async fn login(data: Form<ConnectData>, client_header: ClientHeaders, mut conn: DbConn) -> JsonResult {
|
||||
let data: ConnectData = data.into_inner();
|
||||
|
||||
let mut user_uuid: Option<UserId> = None;
|
||||
let mut user_id: Option<UserId> = None;
|
||||
|
||||
let login_result = match data.grant_type.as_ref() {
|
||||
"refresh_token" => {
|
||||
|
@ -48,7 +48,7 @@ async fn login(data: Form<ConnectData>, client_header: ClientHeaders, mut conn:
|
|||
_check_is_some(&data.device_name, "device_name cannot be blank")?;
|
||||
_check_is_some(&data.device_type, "device_type cannot be blank")?;
|
||||
|
||||
_password_login(data, &mut user_uuid, &mut conn, &client_header.ip).await
|
||||
_password_login(data, &mut user_id, &mut conn, &client_header.ip).await
|
||||
}
|
||||
"client_credentials" => {
|
||||
_check_is_some(&data.client_id, "client_id cannot be blank")?;
|
||||
|
@ -59,17 +59,17 @@ async fn login(data: Form<ConnectData>, client_header: ClientHeaders, mut conn:
|
|||
_check_is_some(&data.device_name, "device_name cannot be blank")?;
|
||||
_check_is_some(&data.device_type, "device_type cannot be blank")?;
|
||||
|
||||
_api_key_login(data, &mut user_uuid, &mut conn, &client_header.ip).await
|
||||
_api_key_login(data, &mut user_id, &mut conn, &client_header.ip).await
|
||||
}
|
||||
t => err!("Invalid type", t),
|
||||
};
|
||||
|
||||
if let Some(user_uuid) = user_uuid {
|
||||
if let Some(user_id) = user_id {
|
||||
match &login_result {
|
||||
Ok(_) => {
|
||||
log_user_event(
|
||||
EventType::UserLoggedIn as i32,
|
||||
&user_uuid,
|
||||
&user_id,
|
||||
client_header.device_type,
|
||||
&client_header.ip.ip,
|
||||
&mut conn,
|
||||
|
@ -80,7 +80,7 @@ async fn login(data: Form<ConnectData>, client_header: ClientHeaders, mut conn:
|
|||
if let Some(ev) = e.get_event() {
|
||||
log_user_event(
|
||||
ev.event as i32,
|
||||
&user_uuid,
|
||||
&user_id,
|
||||
client_header.device_type,
|
||||
&client_header.ip.ip,
|
||||
&mut conn,
|
||||
|
@ -141,7 +141,7 @@ struct MasterPasswordPolicy {
|
|||
|
||||
async fn _password_login(
|
||||
data: ConnectData,
|
||||
user_uuid: &mut Option<UserId>,
|
||||
user_id: &mut Option<UserId>,
|
||||
conn: &mut DbConn,
|
||||
ip: &ClientIp,
|
||||
) -> JsonResult {
|
||||
|
@ -161,8 +161,8 @@ async fn _password_login(
|
|||
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.
|
||||
*user_uuid = Some(user.uuid.clone());
|
||||
// Set the user_id here to be passed back used for event logging.
|
||||
*user_id = Some(user.uuid.clone());
|
||||
|
||||
// Check if the user is disabled
|
||||
if !user.enabled {
|
||||
|
@ -359,7 +359,7 @@ async fn _password_login(
|
|||
|
||||
async fn _api_key_login(
|
||||
data: ConnectData,
|
||||
user_uuid: &mut Option<UserId>,
|
||||
user_id: &mut Option<UserId>,
|
||||
conn: &mut DbConn,
|
||||
ip: &ClientIp,
|
||||
) -> JsonResult {
|
||||
|
@ -368,7 +368,7 @@ async fn _api_key_login(
|
|||
|
||||
// Validate scope
|
||||
match data.scope.as_ref().unwrap().as_ref() {
|
||||
"api" => _user_api_key_login(data, user_uuid, conn, ip).await,
|
||||
"api" => _user_api_key_login(data, user_id, conn, ip).await,
|
||||
"api.organization" => _organization_api_key_login(data, conn, ip).await,
|
||||
_ => err!("Scope not supported"),
|
||||
}
|
||||
|
@ -376,22 +376,22 @@ async fn _api_key_login(
|
|||
|
||||
async fn _user_api_key_login(
|
||||
data: ConnectData,
|
||||
user_uuid: &mut Option<UserId>,
|
||||
user_id: &mut Option<UserId>,
|
||||
conn: &mut DbConn,
|
||||
ip: &ClientIp,
|
||||
) -> JsonResult {
|
||||
// Get the user via the client_id
|
||||
let client_id = data.client_id.as_ref().unwrap();
|
||||
let Some(client_user_uuid) = client_id.strip_prefix("user.") else {
|
||||
let Some(client_user_id) = client_id.strip_prefix("user.") else {
|
||||
err!("Malformed client_id", format!("IP: {}.", ip.ip))
|
||||
};
|
||||
let client_user_uuid: UserId = client_user_uuid.into();
|
||||
let Some(user) = User::find_by_uuid(&client_user_uuid, conn).await else {
|
||||
let client_user_id: UserId = client_user_id.into();
|
||||
let Some(user) = User::find_by_uuid(&client_user_id, conn).await else {
|
||||
err!("Invalid client_id", format!("IP: {}.", ip.ip))
|
||||
};
|
||||
|
||||
// Set the user_uuid here to be passed back used for event logging.
|
||||
*user_uuid = Some(user.uuid.clone());
|
||||
// Set the user_id here to be passed back used for event logging.
|
||||
*user_id = Some(user.uuid.clone());
|
||||
|
||||
// Check if the user is disabled
|
||||
if !user.enabled {
|
||||
|
@ -470,11 +470,11 @@ async fn _user_api_key_login(
|
|||
async fn _organization_api_key_login(data: ConnectData, conn: &mut DbConn, ip: &ClientIp) -> JsonResult {
|
||||
// Get the org via the client_id
|
||||
let client_id = data.client_id.as_ref().unwrap();
|
||||
let Some(org_uuid) = client_id.strip_prefix("organization.") else {
|
||||
let Some(org_id) = client_id.strip_prefix("organization.") else {
|
||||
err!("Malformed client_id", format!("IP: {}.", ip.ip))
|
||||
};
|
||||
let org_uuid: OrganizationId = org_uuid.to_string().into();
|
||||
let Some(org_api_key) = OrganizationApiKey::find_by_org_uuid(&org_uuid, conn).await else {
|
||||
let org_id: OrganizationId = org_id.to_string().into();
|
||||
let Some(org_api_key) = OrganizationApiKey::find_by_org_uuid(&org_id, conn).await else {
|
||||
err!("Invalid client_id", format!("IP: {}.", ip.ip))
|
||||
};
|
||||
|
||||
|
@ -616,7 +616,7 @@ fn _selected_data(tf: Option<TwoFactor>) -> ApiResult<String> {
|
|||
|
||||
async fn _json_err_twofactor(
|
||||
providers: &[i32],
|
||||
user_uuid: &UserId,
|
||||
user_id: &UserId,
|
||||
data: &ConnectData,
|
||||
conn: &mut DbConn,
|
||||
) -> ApiResult<Value> {
|
||||
|
@ -637,12 +637,12 @@ async fn _json_err_twofactor(
|
|||
Some(TwoFactorType::Authenticator) => { /* Nothing to do for TOTP */ }
|
||||
|
||||
Some(TwoFactorType::Webauthn) if CONFIG.domain_set() => {
|
||||
let request = webauthn::generate_webauthn_login(user_uuid, conn).await?;
|
||||
let request = webauthn::generate_webauthn_login(user_id, conn).await?;
|
||||
result["TwoFactorProviders2"][provider.to_string()] = request.0;
|
||||
}
|
||||
|
||||
Some(TwoFactorType::Duo) => {
|
||||
let email = match User::find_by_uuid(user_uuid, conn).await {
|
||||
let email = match User::find_by_uuid(user_id, conn).await {
|
||||
Some(u) => u.email,
|
||||
None => err!("User does not exist"),
|
||||
};
|
||||
|
@ -674,7 +674,7 @@ async fn _json_err_twofactor(
|
|||
}
|
||||
|
||||
Some(tf_type @ TwoFactorType::YubiKey) => {
|
||||
let Some(twofactor) = TwoFactor::find_by_user_and_type(user_uuid, tf_type as i32, conn).await else {
|
||||
let Some(twofactor) = TwoFactor::find_by_user_and_type(user_id, tf_type as i32, conn).await else {
|
||||
err!("No YubiKey devices registered")
|
||||
};
|
||||
|
||||
|
@ -686,13 +686,13 @@ async fn _json_err_twofactor(
|
|||
}
|
||||
|
||||
Some(tf_type @ TwoFactorType::Email) => {
|
||||
let Some(twofactor) = TwoFactor::find_by_user_and_type(user_uuid, tf_type as i32, conn).await else {
|
||||
let Some(twofactor) = TwoFactor::find_by_user_and_type(user_id, tf_type as i32, conn).await else {
|
||||
err!("No twofactor email registered")
|
||||
};
|
||||
|
||||
// Send email immediately if email is the only 2FA option
|
||||
if providers.len() == 1 {
|
||||
email::send_token(user_uuid, conn).await?
|
||||
email::send_token(user_id, conn).await?
|
||||
}
|
||||
|
||||
let email_data = email::EmailTokenData::from_json(&twofactor.data)?;
|
||||
|
|
|
@ -328,8 +328,8 @@ pub struct WebSocketUsers {
|
|||
}
|
||||
|
||||
impl WebSocketUsers {
|
||||
async fn send_update(&self, user_uuid: &UserId, data: &[u8]) {
|
||||
if let Some(user) = self.map.get(user_uuid.as_ref()).map(|v| v.clone()) {
|
||||
async fn send_update(&self, user_id: &UserId, data: &[u8]) {
|
||||
if let Some(user) = self.map.get(user_id.as_ref()).map(|v| v.clone()) {
|
||||
for (_, sender) in user.iter() {
|
||||
if let Err(e) = sender.send(Message::binary(data)).await {
|
||||
error!("Error sending WS update {e}");
|
||||
|
@ -413,7 +413,7 @@ impl WebSocketUsers {
|
|||
&self,
|
||||
ut: UpdateType,
|
||||
cipher: &Cipher,
|
||||
user_uuids: &[UserId],
|
||||
user_ids: &[UserId],
|
||||
acting_device_uuid: &DeviceId,
|
||||
collection_uuids: Option<Vec<CollectionId>>,
|
||||
conn: &mut DbConn,
|
||||
|
@ -422,10 +422,10 @@ impl WebSocketUsers {
|
|||
if *NOTIFICATIONS_DISABLED {
|
||||
return;
|
||||
}
|
||||
let org_uuid = convert_option(cipher.organization_uuid.as_deref());
|
||||
let org_id = convert_option(cipher.organization_uuid.as_deref());
|
||||
// Depending if there are collections provided or not, we need to have different values for the following variables.
|
||||
// The user_uuid should be `null`, and the revision date should be set to now, else the clients won't sync the collection change.
|
||||
let (user_uuid, collection_uuids, revision_date) = if let Some(collection_uuids) = collection_uuids {
|
||||
let (user_id, collection_uuids, revision_date) = if let Some(collection_uuids) = collection_uuids {
|
||||
(
|
||||
Value::Nil,
|
||||
Value::Array(collection_uuids.into_iter().map(|v| v.to_string().into()).collect::<Vec<Value>>()),
|
||||
|
@ -438,8 +438,8 @@ impl WebSocketUsers {
|
|||
let data = create_update(
|
||||
vec![
|
||||
("Id".into(), cipher.uuid.to_string().into()),
|
||||
("UserId".into(), user_uuid),
|
||||
("OrganizationId".into(), org_uuid),
|
||||
("UserId".into(), user_id),
|
||||
("OrganizationId".into(), org_id),
|
||||
("CollectionIds".into(), collection_uuids),
|
||||
("RevisionDate".into(), revision_date),
|
||||
],
|
||||
|
@ -448,12 +448,12 @@ impl WebSocketUsers {
|
|||
);
|
||||
|
||||
if CONFIG.enable_websocket() {
|
||||
for uuid in user_uuids {
|
||||
for uuid in user_ids {
|
||||
self.send_update(uuid, &data).await;
|
||||
}
|
||||
}
|
||||
|
||||
if CONFIG.push_enabled() && user_uuids.len() == 1 {
|
||||
if CONFIG.push_enabled() && user_ids.len() == 1 {
|
||||
push_cipher_update(ut, cipher, acting_device_uuid, conn).await;
|
||||
}
|
||||
}
|
||||
|
@ -462,7 +462,7 @@ impl WebSocketUsers {
|
|||
&self,
|
||||
ut: UpdateType,
|
||||
send: &DbSend,
|
||||
user_uuids: &[UserId],
|
||||
user_ids: &[UserId],
|
||||
acting_device_uuid: &DeviceId,
|
||||
conn: &mut DbConn,
|
||||
) {
|
||||
|
@ -470,12 +470,12 @@ impl WebSocketUsers {
|
|||
if *NOTIFICATIONS_DISABLED {
|
||||
return;
|
||||
}
|
||||
let user_uuid = convert_option(send.user_uuid.as_deref());
|
||||
let user_id = convert_option(send.user_uuid.as_deref());
|
||||
|
||||
let data = create_update(
|
||||
vec![
|
||||
("Id".into(), send.uuid.to_string().into()),
|
||||
("UserId".into(), user_uuid),
|
||||
("UserId".into(), user_id),
|
||||
("RevisionDate".into(), serialize_date(send.revision_date)),
|
||||
],
|
||||
ut,
|
||||
|
@ -483,18 +483,18 @@ impl WebSocketUsers {
|
|||
);
|
||||
|
||||
if CONFIG.enable_websocket() {
|
||||
for uuid in user_uuids {
|
||||
for uuid in user_ids {
|
||||
self.send_update(uuid, &data).await;
|
||||
}
|
||||
}
|
||||
if CONFIG.push_enabled() && user_uuids.len() == 1 {
|
||||
if CONFIG.push_enabled() && user_ids.len() == 1 {
|
||||
push_send_update(ut, send, acting_device_uuid, conn).await;
|
||||
}
|
||||
}
|
||||
|
||||
pub async fn send_auth_request(
|
||||
&self,
|
||||
user_uuid: &UserId,
|
||||
user_id: &UserId,
|
||||
auth_request_uuid: &String,
|
||||
acting_device_uuid: &DeviceId,
|
||||
conn: &mut DbConn,
|
||||
|
@ -504,22 +504,22 @@ impl WebSocketUsers {
|
|||
return;
|
||||
}
|
||||
let data = create_update(
|
||||
vec![("Id".into(), auth_request_uuid.clone().into()), ("UserId".into(), user_uuid.to_string().into())],
|
||||
vec![("Id".into(), auth_request_uuid.clone().into()), ("UserId".into(), user_id.to_string().into())],
|
||||
UpdateType::AuthRequest,
|
||||
Some(acting_device_uuid.to_string()),
|
||||
);
|
||||
if CONFIG.enable_websocket() {
|
||||
self.send_update(user_uuid, &data).await;
|
||||
self.send_update(user_id, &data).await;
|
||||
}
|
||||
|
||||
if CONFIG.push_enabled() {
|
||||
push_auth_request(user_uuid.clone(), auth_request_uuid.to_string(), conn).await;
|
||||
push_auth_request(user_id.clone(), auth_request_uuid.to_string(), conn).await;
|
||||
}
|
||||
}
|
||||
|
||||
pub async fn send_auth_response(
|
||||
&self,
|
||||
user_uuid: &UserId,
|
||||
user_id: &UserId,
|
||||
auth_response_uuid: &str,
|
||||
approving_device_uuid: DeviceId,
|
||||
conn: &mut DbConn,
|
||||
|
@ -529,16 +529,16 @@ impl WebSocketUsers {
|
|||
return;
|
||||
}
|
||||
let data = create_update(
|
||||
vec![("Id".into(), auth_response_uuid.to_owned().into()), ("UserId".into(), user_uuid.to_string().into())],
|
||||
vec![("Id".into(), auth_response_uuid.to_owned().into()), ("UserId".into(), user_id.to_string().into())],
|
||||
UpdateType::AuthRequestResponse,
|
||||
Some(approving_device_uuid.to_string()),
|
||||
);
|
||||
if CONFIG.enable_websocket() {
|
||||
self.send_update(user_uuid, &data).await;
|
||||
self.send_update(user_id, &data).await;
|
||||
}
|
||||
|
||||
if CONFIG.push_enabled() {
|
||||
push_auth_response(user_uuid.clone(), auth_response_uuid.to_string(), approving_device_uuid, conn).await;
|
||||
push_auth_response(user_id.clone(), auth_response_uuid.to_string(), approving_device_uuid, conn).await;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -557,16 +557,16 @@ impl AnonymousWebSocketSubscriptions {
|
|||
}
|
||||
}
|
||||
|
||||
pub async fn send_auth_response(&self, user_uuid: &UserId, auth_response_uuid: &str) {
|
||||
pub async fn send_auth_response(&self, user_id: &UserId, auth_response_uuid: &str) {
|
||||
if !CONFIG.enable_websocket() {
|
||||
return;
|
||||
}
|
||||
let data = create_anonymous_update(
|
||||
vec![("Id".into(), auth_response_uuid.to_owned().into()), ("UserId".into(), user_uuid.to_string().into())],
|
||||
vec![("Id".into(), auth_response_uuid.to_owned().into()), ("UserId".into(), user_id.to_string().into())],
|
||||
UpdateType::AuthRequestResponse,
|
||||
user_uuid.clone(),
|
||||
user_id.clone(),
|
||||
);
|
||||
self.send_update(user_uuid, &data).await;
|
||||
self.send_update(user_id, &data).await;
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -126,15 +126,15 @@ pub async fn register_push_device(device: &mut Device, conn: &mut crate::db::DbC
|
|||
Ok(())
|
||||
}
|
||||
|
||||
pub async fn unregister_push_device(push_uuid: Option<String>) -> EmptyResult {
|
||||
if !CONFIG.push_enabled() || push_uuid.is_none() {
|
||||
pub async fn unregister_push_device(push_id: Option<String>) -> EmptyResult {
|
||||
if !CONFIG.push_enabled() || push_id.is_none() {
|
||||
return Ok(());
|
||||
}
|
||||
let auth_push_token = get_auth_push_token().await?;
|
||||
|
||||
let auth_header = format!("Bearer {}", &auth_push_token);
|
||||
|
||||
match make_http_request(Method::DELETE, &(CONFIG.push_relay_uri() + "/push/" + &push_uuid.unwrap()))?
|
||||
match make_http_request(Method::DELETE, &(CONFIG.push_relay_uri() + "/push/" + &push_id.unwrap()))?
|
||||
.header(AUTHORIZATION, auth_header)
|
||||
.send()
|
||||
.await
|
||||
|
@ -148,24 +148,24 @@ pub async fn unregister_push_device(push_uuid: Option<String>) -> EmptyResult {
|
|||
pub async fn push_cipher_update(
|
||||
ut: UpdateType,
|
||||
cipher: &Cipher,
|
||||
acting_device_uuid: &DeviceId,
|
||||
acting_device_id: &DeviceId,
|
||||
conn: &mut crate::db::DbConn,
|
||||
) {
|
||||
// We shouldn't send a push notification on cipher update if the cipher belongs to an organization, this isn't implemented in the upstream server too.
|
||||
if cipher.organization_uuid.is_some() {
|
||||
return;
|
||||
};
|
||||
let Some(user_uuid) = &cipher.user_uuid else {
|
||||
let Some(user_id) = &cipher.user_uuid else {
|
||||
debug!("Cipher has no uuid");
|
||||
return;
|
||||
};
|
||||
|
||||
if Device::check_user_has_push_device(user_uuid, conn).await {
|
||||
if Device::check_user_has_push_device(user_id, conn).await {
|
||||
send_to_push_relay(json!({
|
||||
"userId": user_uuid,
|
||||
"userId": user_id,
|
||||
"organizationId": (),
|
||||
"deviceId": acting_device_uuid,
|
||||
"identifier": acting_device_uuid,
|
||||
"deviceId": acting_device_id,
|
||||
"identifier": acting_device_id,
|
||||
"type": ut as i32,
|
||||
"payload": {
|
||||
"Id": cipher.uuid,
|
||||
|
@ -178,14 +178,14 @@ pub async fn push_cipher_update(
|
|||
}
|
||||
}
|
||||
|
||||
pub fn push_logout(user: &User, acting_device_uuid: Option<String>) {
|
||||
let acting_device_uuid: Value = acting_device_uuid.map(|v| v.into()).unwrap_or_else(|| Value::Null);
|
||||
pub fn push_logout(user: &User, acting_device_id: Option<String>) {
|
||||
let acting_device_id: Value = acting_device_id.map(|v| v.into()).unwrap_or_else(|| Value::Null);
|
||||
|
||||
tokio::task::spawn(send_to_push_relay(json!({
|
||||
"userId": user.uuid,
|
||||
"organizationId": (),
|
||||
"deviceId": acting_device_uuid,
|
||||
"identifier": acting_device_uuid,
|
||||
"deviceId": acting_device_id,
|
||||
"identifier": acting_device_id,
|
||||
"type": UpdateType::LogOut as i32,
|
||||
"payload": {
|
||||
"UserId": user.uuid,
|
||||
|
@ -211,15 +211,15 @@ pub fn push_user_update(ut: UpdateType, user: &User) {
|
|||
pub async fn push_folder_update(
|
||||
ut: UpdateType,
|
||||
folder: &Folder,
|
||||
acting_device_uuid: &DeviceId,
|
||||
acting_device_id: &DeviceId,
|
||||
conn: &mut crate::db::DbConn,
|
||||
) {
|
||||
if Device::check_user_has_push_device(&folder.user_uuid, conn).await {
|
||||
tokio::task::spawn(send_to_push_relay(json!({
|
||||
"userId": folder.user_uuid,
|
||||
"organizationId": (),
|
||||
"deviceId": acting_device_uuid,
|
||||
"identifier": acting_device_uuid,
|
||||
"deviceId": acting_device_id,
|
||||
"identifier": acting_device_id,
|
||||
"type": ut as i32,
|
||||
"payload": {
|
||||
"Id": folder.uuid,
|
||||
|
@ -230,19 +230,14 @@ pub async fn push_folder_update(
|
|||
}
|
||||
}
|
||||
|
||||
pub async fn push_send_update(
|
||||
ut: UpdateType,
|
||||
send: &Send,
|
||||
acting_device_uuid: &DeviceId,
|
||||
conn: &mut crate::db::DbConn,
|
||||
) {
|
||||
pub async fn push_send_update(ut: UpdateType, send: &Send, acting_device_id: &DeviceId, conn: &mut crate::db::DbConn) {
|
||||
if let Some(s) = &send.user_uuid {
|
||||
if Device::check_user_has_push_device(s, conn).await {
|
||||
tokio::task::spawn(send_to_push_relay(json!({
|
||||
"userId": send.user_uuid,
|
||||
"organizationId": (),
|
||||
"deviceId": acting_device_uuid,
|
||||
"identifier": acting_device_uuid,
|
||||
"deviceId": acting_device_id,
|
||||
"identifier": acting_device_id,
|
||||
"type": ut as i32,
|
||||
"payload": {
|
||||
"Id": send.uuid,
|
||||
|
@ -289,38 +284,38 @@ async fn send_to_push_relay(notification_data: Value) {
|
|||
};
|
||||
}
|
||||
|
||||
pub async fn push_auth_request(user_uuid: UserId, auth_request_uuid: String, conn: &mut crate::db::DbConn) {
|
||||
if Device::check_user_has_push_device(&user_uuid, conn).await {
|
||||
pub async fn push_auth_request(user_id: UserId, auth_request_id: String, conn: &mut crate::db::DbConn) {
|
||||
if Device::check_user_has_push_device(&user_id, conn).await {
|
||||
tokio::task::spawn(send_to_push_relay(json!({
|
||||
"userId": user_uuid,
|
||||
"userId": user_id,
|
||||
"organizationId": (),
|
||||
"deviceId": null,
|
||||
"identifier": null,
|
||||
"type": UpdateType::AuthRequest as i32,
|
||||
"payload": {
|
||||
"Id": auth_request_uuid,
|
||||
"UserId": user_uuid,
|
||||
"Id": auth_request_id,
|
||||
"UserId": user_id,
|
||||
}
|
||||
})));
|
||||
}
|
||||
}
|
||||
|
||||
pub async fn push_auth_response(
|
||||
user_uuid: UserId,
|
||||
auth_request_uuid: String,
|
||||
approving_device_uuid: DeviceId,
|
||||
user_id: UserId,
|
||||
auth_request_id: String,
|
||||
approving_device_id: DeviceId,
|
||||
conn: &mut crate::db::DbConn,
|
||||
) {
|
||||
if Device::check_user_has_push_device(&user_uuid, conn).await {
|
||||
if Device::check_user_has_push_device(&user_id, conn).await {
|
||||
tokio::task::spawn(send_to_push_relay(json!({
|
||||
"userId": user_uuid,
|
||||
"userId": user_id,
|
||||
"organizationId": (),
|
||||
"deviceId": approving_device_uuid,
|
||||
"identifier": approving_device_uuid,
|
||||
"deviceId": approving_device_id,
|
||||
"identifier": approving_device_id,
|
||||
"type": UpdateType::AuthRequestResponse as i32,
|
||||
"payload": {
|
||||
"Id": auth_request_uuid,
|
||||
"UserId": user_uuid,
|
||||
"Id": auth_request_id,
|
||||
"UserId": user_id,
|
||||
}
|
||||
})));
|
||||
}
|
||||
|
|
|
@ -196,16 +196,16 @@ async fn web_files(p: PathBuf) -> Cached<Option<NamedFile>> {
|
|||
Cached::long(NamedFile::open(Path::new(&CONFIG.web_vault_folder()).join(p)).await.ok(), true)
|
||||
}
|
||||
|
||||
#[get("/attachments/<uuid>/<file_id>?<token>")]
|
||||
async fn attachments(uuid: CipherId, file_id: AttachmentId, token: String) -> Option<NamedFile> {
|
||||
#[get("/attachments/<cipher_id>/<file_id>?<token>")]
|
||||
async fn attachments(cipher_id: CipherId, file_id: AttachmentId, token: String) -> Option<NamedFile> {
|
||||
let Ok(claims) = decode_file_download(&token) else {
|
||||
return None;
|
||||
};
|
||||
if claims.sub != uuid || claims.file_id != file_id {
|
||||
if claims.sub != cipher_id || claims.file_id != file_id {
|
||||
return None;
|
||||
}
|
||||
|
||||
NamedFile::open(Path::new(&CONFIG.attachments_folder()).join(uuid.as_ref()).join(file_id.as_ref())).await.ok()
|
||||
NamedFile::open(Path::new(&CONFIG.attachments_folder()).join(cipher_id.as_ref()).join(file_id.as_ref())).await.ok()
|
||||
}
|
||||
|
||||
// We use DbConn here to let the alive healthcheck also verify the database connection.
|
||||
|
|
|
@ -482,19 +482,19 @@ impl<'r> FromRequest<'r> for Headers {
|
|||
err_handler!("Invalid claim")
|
||||
};
|
||||
|
||||
let device_uuid = claims.device;
|
||||
let user_uuid = claims.sub;
|
||||
let device_id = claims.device;
|
||||
let user_id = claims.sub;
|
||||
|
||||
let mut conn = match DbConn::from_request(request).await {
|
||||
Outcome::Success(conn) => conn,
|
||||
_ => err_handler!("Error getting DB"),
|
||||
};
|
||||
|
||||
let Some(device) = Device::find_by_uuid_and_user(&device_uuid, &user_uuid, &mut conn).await else {
|
||||
let Some(device) = Device::find_by_uuid_and_user(&device_id, &user_id, &mut conn).await else {
|
||||
err_handler!("Invalid device id")
|
||||
};
|
||||
|
||||
let Some(user) = User::find_by_uuid(&user_uuid, &mut conn).await else {
|
||||
let Some(user) = User::find_by_uuid(&user_id, &mut conn).await else {
|
||||
err_handler!("Device has no user associated")
|
||||
};
|
||||
|
||||
|
|
Laden …
In neuem Issue referenzieren