1
0
Fork 1
Spiegel von https://github.com/dani-garcia/vaultwarden.git synchronisiert 2025-01-08 11:55:42 +01:00

introduce user_id newtype

Dieser Commit ist enthalten in:
Stefan Melmuk 2024-12-21 11:41:24 +01:00
Ursprung 64ae0aa386
Commit 16afe10898
Es konnte kein GPG-Schlüssel zu dieser Signatur gefunden werden
GPG-Schlüssel-ID: 817020C608FE9C09
34 geänderte Dateien mit 351 neuen und 257 gelöschten Zeilen

Datei anzeigen

@ -280,7 +280,7 @@ struct InviteData {
email: String, email: String,
} }
async fn get_user_or_404(uuid: &str, conn: &mut DbConn) -> ApiResult<User> { async fn get_user_or_404(uuid: &UserId, conn: &mut DbConn) -> ApiResult<User> {
if let Some(user) = User::find_by_uuid(uuid, conn).await { if let Some(user) = User::find_by_uuid(uuid, conn).await {
Ok(user) Ok(user)
} else { } else {
@ -382,8 +382,8 @@ async fn get_user_by_mail_json(mail: &str, _token: AdminToken, mut conn: DbConn)
} }
#[get("/users/<uuid>")] #[get("/users/<uuid>")]
async fn get_user_json(uuid: &str, _token: AdminToken, mut conn: DbConn) -> JsonResult { async fn get_user_json(uuid: UserId, _token: AdminToken, mut conn: DbConn) -> JsonResult {
let u = get_user_or_404(uuid, &mut conn).await?; let u = get_user_or_404(&uuid, &mut conn).await?;
let mut usr = u.to_json(&mut conn).await; let mut usr = u.to_json(&mut conn).await;
usr["userEnabled"] = json!(u.enabled); usr["userEnabled"] = json!(u.enabled);
usr["createdAt"] = json!(format_naive_datetime_local(&u.created_at, DT_FMT)); usr["createdAt"] = json!(format_naive_datetime_local(&u.created_at, DT_FMT));
@ -391,11 +391,11 @@ async fn get_user_json(uuid: &str, _token: AdminToken, mut conn: DbConn) -> Json
} }
#[post("/users/<uuid>/delete")] #[post("/users/<uuid>/delete")]
async fn delete_user(uuid: &str, token: AdminToken, mut conn: DbConn) -> EmptyResult { async fn delete_user(uuid: UserId, token: AdminToken, mut conn: DbConn) -> EmptyResult {
let user = get_user_or_404(uuid, &mut conn).await?; let user = get_user_or_404(&uuid, &mut conn).await?;
// Get the membership records before deleting the actual user // 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(&uuid, &mut conn).await;
let res = user.delete(&mut conn).await; let res = user.delete(&mut conn).await;
for membership in memberships { for membership in memberships {
@ -415,8 +415,8 @@ async fn delete_user(uuid: &str, token: AdminToken, mut conn: DbConn) -> EmptyRe
} }
#[post("/users/<uuid>/deauth")] #[post("/users/<uuid>/deauth")]
async fn deauth_user(uuid: &str, _token: AdminToken, mut conn: DbConn, nt: Notify<'_>) -> EmptyResult { 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?; let mut user = get_user_or_404(&uuid, &mut conn).await?;
nt.send_logout(&user, None).await; nt.send_logout(&user, None).await;
@ -436,8 +436,8 @@ async fn deauth_user(uuid: &str, _token: AdminToken, mut conn: DbConn, nt: Notif
} }
#[post("/users/<uuid>/disable")] #[post("/users/<uuid>/disable")]
async fn disable_user(uuid: &str, _token: AdminToken, mut conn: DbConn, nt: Notify<'_>) -> EmptyResult { 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?; let mut user = get_user_or_404(&uuid, &mut conn).await?;
Device::delete_all_by_user(&user.uuid, &mut conn).await?; Device::delete_all_by_user(&user.uuid, &mut conn).await?;
user.reset_security_stamp(); user.reset_security_stamp();
user.enabled = false; user.enabled = false;
@ -450,16 +450,16 @@ async fn disable_user(uuid: &str, _token: AdminToken, mut conn: DbConn, nt: Noti
} }
#[post("/users/<uuid>/enable")] #[post("/users/<uuid>/enable")]
async fn enable_user(uuid: &str, _token: AdminToken, mut conn: DbConn) -> EmptyResult { async fn enable_user(uuid: UserId, _token: AdminToken, mut conn: DbConn) -> EmptyResult {
let mut user = get_user_or_404(uuid, &mut conn).await?; let mut user = get_user_or_404(&uuid, &mut conn).await?;
user.enabled = true; user.enabled = true;
user.save(&mut conn).await user.save(&mut conn).await
} }
#[post("/users/<uuid>/remove-2fa")] #[post("/users/<uuid>/remove-2fa")]
async fn remove_2fa(uuid: &str, token: AdminToken, mut conn: DbConn) -> EmptyResult { async fn remove_2fa(uuid: UserId, token: AdminToken, mut conn: DbConn) -> EmptyResult {
let mut user = get_user_or_404(uuid, &mut conn).await?; let mut user = get_user_or_404(&uuid, &mut conn).await?;
TwoFactor::delete_all_by_user(&user.uuid, &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?; two_factor::enforce_2fa_policy(&user, ACTING_ADMIN_USER, 14, &token.ip.ip, &mut conn).await?;
user.totp_recover = None; user.totp_recover = None;
@ -467,8 +467,8 @@ async fn remove_2fa(uuid: &str, token: AdminToken, mut conn: DbConn) -> EmptyRes
} }
#[post("/users/<uuid>/invite/resend")] #[post("/users/<uuid>/invite/resend")]
async fn resend_user_invite(uuid: &str, _token: AdminToken, mut conn: DbConn) -> EmptyResult { 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 { if let Some(user) = User::find_by_uuid(&uuid, &mut conn).await {
//TODO: replace this with user.status check when it will be available (PR#3397) //TODO: replace this with user.status check when it will be available (PR#3397)
if !user.password_hash.is_empty() { if !user.password_hash.is_empty() {
err_code!("User already accepted invitation", Status::BadRequest.code); err_code!("User already accepted invitation", Status::BadRequest.code);
@ -487,7 +487,7 @@ async fn resend_user_invite(uuid: &str, _token: AdminToken, mut conn: DbConn) ->
#[derive(Debug, Deserialize)] #[derive(Debug, Deserialize)]
struct MembershipTypeData { struct MembershipTypeData {
user_type: NumberOrString, user_type: NumberOrString,
user_uuid: String, user_uuid: UserId,
org_uuid: OrganizationId, org_uuid: OrganizationId,
} }

Datei anzeigen

@ -306,8 +306,8 @@ async fn put_avatar(data: Json<AvatarData>, headers: Headers, mut conn: DbConn)
} }
#[get("/users/<uuid>/public-key")] #[get("/users/<uuid>/public-key")]
async fn get_public_keys(uuid: &str, _headers: Headers, mut conn: DbConn) -> JsonResult { async fn get_public_keys(uuid: UserId, _headers: Headers, mut conn: DbConn) -> JsonResult {
let user = match User::find_by_uuid(uuid, &mut conn).await { let user = match User::find_by_uuid(&uuid, &mut conn).await {
Some(user) if user.public_key.is_some() => user, Some(user) if user.public_key.is_some() => user,
Some(_) => err_code!("User has no public_key", Status::NotFound.code), Some(_) => err_code!("User has no public_key", Status::NotFound.code),
None => err_code!("User doesn't exist", Status::NotFound.code), None => err_code!("User doesn't exist", Status::NotFound.code),
@ -793,7 +793,7 @@ async fn post_verify_email(headers: Headers) -> EmptyResult {
#[derive(Deserialize)] #[derive(Deserialize)]
#[serde(rename_all = "camelCase")] #[serde(rename_all = "camelCase")]
struct VerifyEmailTokenData { struct VerifyEmailTokenData {
user_id: String, user_id: UserId,
token: String, token: String,
} }
@ -808,7 +808,7 @@ async fn post_verify_email_token(data: Json<VerifyEmailTokenData>, mut conn: DbC
let Ok(claims) = decode_verify_email(&data.token) else { let Ok(claims) = decode_verify_email(&data.token) else {
err!("Invalid claim") err!("Invalid claim")
}; };
if claims.sub != user.uuid { if claims.sub != *user.uuid {
err!("Invalid claim"); err!("Invalid claim");
} }
user.verified_at = Some(Utc::now().naive_utc()); user.verified_at = Some(Utc::now().naive_utc());
@ -850,7 +850,7 @@ async fn post_delete_recover(data: Json<DeleteRecoverData>, mut conn: DbConn) ->
#[derive(Deserialize)] #[derive(Deserialize)]
#[serde(rename_all = "camelCase")] #[serde(rename_all = "camelCase")]
struct DeleteRecoverTokenData { struct DeleteRecoverTokenData {
user_id: String, user_id: UserId,
token: String, token: String,
} }
@ -866,7 +866,7 @@ async fn post_delete_recover_token(data: Json<DeleteRecoverTokenData>, mut conn:
err!("User doesn't exist") err!("User doesn't exist")
}; };
if claims.sub != user.uuid { if claims.sub != *user.uuid {
err!("Invalid claim"); err!("Invalid claim");
} }
user.delete(&mut conn).await user.delete(&mut conn).await

Datei anzeigen

@ -771,7 +771,7 @@ async fn post_collections_update(
let posted_collections = HashSet::<String>::from_iter(data.collection_ids); let posted_collections = HashSet::<String>::from_iter(data.collection_ids);
let current_collections = let current_collections =
HashSet::<String>::from_iter(cipher.get_collections(headers.user.uuid.clone(), &mut conn).await); HashSet::<String>::from_iter(cipher.get_collections(headers.user.uuid.to_string(), &mut conn).await);
for collection in posted_collections.symmetric_difference(&current_collections) { for collection in posted_collections.symmetric_difference(&current_collections) {
match Collection::find_by_uuid_and_org(collection, cipher.organization_uuid.as_ref().unwrap(), &mut conn).await match Collection::find_by_uuid_and_org(collection, cipher.organization_uuid.as_ref().unwrap(), &mut conn).await
@ -848,7 +848,7 @@ async fn post_collections_admin(
let posted_collections = HashSet::<String>::from_iter(data.collection_ids); let posted_collections = HashSet::<String>::from_iter(data.collection_ids);
let current_collections = let current_collections =
HashSet::<String>::from_iter(cipher.get_admin_collections(headers.user.uuid.clone(), &mut conn).await); HashSet::<String>::from_iter(cipher.get_admin_collections(headers.user.uuid.to_string(), &mut conn).await);
for collection in posted_collections.symmetric_difference(&current_collections) { for collection in posted_collections.symmetric_difference(&current_collections) {
match Collection::find_by_uuid_and_org(collection, cipher.organization_uuid.as_ref().unwrap(), &mut conn).await match Collection::find_by_uuid_and_org(collection, cipher.organization_uuid.as_ref().unwrap(), &mut conn).await
@ -1848,7 +1848,7 @@ pub enum CipherSyncType {
} }
impl CipherSyncData { impl CipherSyncData {
pub async fn new(user_uuid: &str, sync_type: CipherSyncType, conn: &mut DbConn) -> Self { pub async fn new(user_uuid: &UserId, sync_type: CipherSyncType, conn: &mut DbConn) -> Self {
let cipher_folders: HashMap<String, String>; let cipher_folders: HashMap<String, String>;
let cipher_favorites: HashSet<String>; let cipher_favorites: HashSet<String>;
match sync_type { match sync_type {

Datei anzeigen

@ -701,7 +701,7 @@ async fn policies_emergency_access(emer_id: &str, headers: Headers, mut conn: Db
fn is_valid_request( fn is_valid_request(
emergency_access: &EmergencyAccess, emergency_access: &EmergencyAccess,
requesting_user_uuid: &str, requesting_user_uuid: &UserId,
requested_access_type: EmergencyAccessType, requested_access_type: EmergencyAccessType,
) -> bool { ) -> bool {
emergency_access.grantee_uuid.is_some() emergency_access.grantee_uuid.is_some()

Datei anzeigen

@ -8,7 +8,7 @@ use crate::{
api::{EmptyResult, JsonResult}, api::{EmptyResult, JsonResult},
auth::{AdminHeaders, Headers}, auth::{AdminHeaders, Headers},
db::{ db::{
models::{Cipher, Event, Membership, MembershipId, OrganizationId}, models::{Cipher, Event, Membership, MembershipId, OrganizationId, UserId},
DbConn, DbPool, DbConn, DbPool,
}, },
util::parse_date, util::parse_date,
@ -218,7 +218,7 @@ async fn post_events_collect(data: Json<Vec<EventCollection>>, headers: Headers,
Ok(()) Ok(())
} }
pub async fn log_user_event(event_type: i32, user_uuid: &str, device_type: i32, ip: &IpAddr, conn: &mut DbConn) { pub async fn log_user_event(event_type: i32, user_uuid: &UserId, device_type: i32, ip: &IpAddr, conn: &mut DbConn) {
if !CONFIG.org_events_enabled() { if !CONFIG.org_events_enabled() {
return; return;
} }
@ -227,7 +227,7 @@ pub async fn log_user_event(event_type: i32, user_uuid: &str, device_type: i32,
async fn _log_user_event( async fn _log_user_event(
event_type: i32, event_type: i32,
user_uuid: &str, user_uuid: &UserId,
device_type: i32, device_type: i32,
event_date: Option<NaiveDateTime>, event_date: Option<NaiveDateTime>,
ip: &IpAddr, ip: &IpAddr,
@ -238,8 +238,8 @@ async fn _log_user_event(
// Upstream saves the event also without any org_uuid. // Upstream saves the event also without any org_uuid.
let mut event = Event::new(event_type, event_date); let mut event = Event::new(event_type, event_date);
event.user_uuid = Some(String::from(user_uuid)); event.user_uuid = Some(user_uuid.clone());
event.act_user_uuid = Some(String::from(user_uuid)); event.act_user_uuid = Some(user_uuid.to_string());
event.device_type = Some(device_type); event.device_type = Some(device_type);
event.ip_address = Some(ip.to_string()); event.ip_address = Some(ip.to_string());
events.push(event); events.push(event);
@ -247,9 +247,9 @@ async fn _log_user_event(
// For each org a user is a member of store these events per org // For each org a user is a member of store these events per org
for org_uuid in orgs { for org_uuid in orgs {
let mut event = Event::new(event_type, event_date); let mut event = Event::new(event_type, event_date);
event.user_uuid = Some(String::from(user_uuid)); event.user_uuid = Some(user_uuid.clone());
event.org_uuid = Some(org_uuid); event.org_uuid = Some(org_uuid);
event.act_user_uuid = Some(String::from(user_uuid)); event.act_user_uuid = Some(user_uuid.to_string());
event.device_type = Some(device_type); event.device_type = Some(device_type);
event.ip_address = Some(ip.to_string()); event.ip_address = Some(ip.to_string());
events.push(event); events.push(event);

Datei anzeigen

@ -358,7 +358,7 @@ async fn get_org_collections_details(
let users: Vec<Value> = coll_users let users: Vec<Value> = coll_users
.iter() .iter()
.filter(|collection_user| collection_user.collection_uuid == col.uuid) .filter(|collection_user| collection_user.collection_uuid == col.uuid)
.map(|collection_user| SelectionReadOnly::to_collection_user_details_read_only(collection_user).to_json()) .map(|collection_user| UserSelection::to_collection_user_details_read_only(collection_user).to_json())
.collect(); .collect();
// get the group details for the given collection // get the group details for the given collection
@ -667,7 +667,7 @@ async fn get_org_collection_detail(
.await .await
.iter() .iter()
.map(|collection_user| { .map(|collection_user| {
SelectionReadOnly::to_collection_user_details_read_only(collection_user).to_json() UserSelection::to_collection_user_details_read_only(collection_user).to_json()
}) })
.collect(); .collect();
@ -761,7 +761,7 @@ async fn get_org_details(data: OrgIdData, headers: Headers, mut conn: DbConn) ->
}))) })))
} }
async fn _get_org_details(org_id: &OrganizationId, host: &str, user_uuid: &str, conn: &mut DbConn) -> Value { async fn _get_org_details(org_id: &OrganizationId, host: &str, user_uuid: &UserId, conn: &mut DbConn) -> Value {
let ciphers = Cipher::find_by_org(org_id, conn).await; 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_uuid, CipherSyncType::Organization, conn).await;
@ -2384,16 +2384,30 @@ impl SelectionReadOnly {
CollectionGroup::new(self.id.clone(), groups_uuid, self.read_only, self.hide_passwords) CollectionGroup::new(self.id.clone(), groups_uuid, self.read_only, self.hide_passwords)
} }
pub fn to_collection_group_details_read_only(collection_group: &CollectionGroup) -> SelectionReadOnly { pub fn to_collection_group_details_read_only(collection_group: &CollectionGroup) -> Self {
SelectionReadOnly { Self {
id: collection_group.groups_uuid.clone(), id: collection_group.groups_uuid.clone(),
read_only: collection_group.read_only, read_only: collection_group.read_only,
hide_passwords: collection_group.hide_passwords, hide_passwords: collection_group.hide_passwords,
} }
} }
pub fn to_collection_user_details_read_only(collection_user: &CollectionUser) -> SelectionReadOnly { pub fn to_json(&self) -> Value {
SelectionReadOnly { json!(self)
}
}
#[derive(Deserialize, Serialize)]
#[serde(rename_all = "camelCase")]
struct UserSelection {
id: UserId,
read_only: bool,
hide_passwords: bool,
}
impl UserSelection {
pub fn to_collection_user_details_read_only(collection_user: &CollectionUser) -> Self {
Self {
id: collection_user.user_uuid.clone(), id: collection_user.user_uuid.clone(),
read_only: collection_user.read_only, read_only: collection_user.read_only,
hide_passwords: collection_user.hide_passwords, hide_passwords: collection_user.hide_passwords,

Datei anzeigen

@ -106,7 +106,7 @@ async fn enforce_disable_hide_email_policy(data: &SendData, headers: &Headers, c
Ok(()) Ok(())
} }
fn create_send(data: SendData, user_uuid: String) -> ApiResult<Send> { fn create_send(data: SendData, user_uuid: UserId) -> ApiResult<Send> {
let data_val = if data.r#type == SendType::Text as i32 { let data_val = if data.r#type == SendType::Text as i32 {
data.text data.text
} else if data.r#type == SendType::File as i32 { } else if data.r#type == SendType::File as i32 {

Datei anzeigen

@ -7,7 +7,7 @@ use crate::{
auth::{ClientIp, Headers}, auth::{ClientIp, Headers},
crypto, crypto,
db::{ db::{
models::{EventType, TwoFactor, TwoFactorType}, models::{EventType, TwoFactor, TwoFactorType, UserId},
DbConn, DbConn,
}, },
util::NumberOrString, util::NumberOrString,
@ -95,7 +95,7 @@ async fn activate_authenticator_put(data: Json<EnableAuthenticatorData>, headers
} }
pub async fn validate_totp_code_str( pub async fn validate_totp_code_str(
user_uuid: &str, user_uuid: &UserId,
totp_code: &str, totp_code: &str,
secret: &str, secret: &str,
ip: &ClientIp, ip: &ClientIp,
@ -109,7 +109,7 @@ pub async fn validate_totp_code_str(
} }
pub async fn validate_totp_code( pub async fn validate_totp_code(
user_uuid: &str, user_uuid: &UserId,
totp_code: &str, totp_code: &str,
secret: &str, secret: &str,
ip: &ClientIp, ip: &ClientIp,
@ -124,7 +124,7 @@ pub async fn validate_totp_code(
let mut twofactor = let mut twofactor =
match TwoFactor::find_by_user_and_type(user_uuid, TwoFactorType::Authenticator as i32, conn).await { match TwoFactor::find_by_user_and_type(user_uuid, TwoFactorType::Authenticator as i32, conn).await {
Some(tf) => tf, Some(tf) => tf,
_ => TwoFactor::new(user_uuid.to_string(), TwoFactorType::Authenticator, secret.to_string()), _ => TwoFactor::new(user_uuid.clone(), TwoFactorType::Authenticator, secret.to_string()),
}; };
// The amount of steps back and forward in time // The amount of steps back and forward in time

Datei anzeigen

@ -11,7 +11,7 @@ use crate::{
auth::Headers, auth::Headers,
crypto, crypto,
db::{ db::{
models::{EventType, TwoFactor, TwoFactorType, User}, models::{EventType, TwoFactor, TwoFactorType, User, UserId},
DbConn, DbConn,
}, },
error::MapResult, error::MapResult,
@ -228,11 +228,11 @@ const AUTH_PREFIX: &str = "AUTH";
const DUO_PREFIX: &str = "TX"; const DUO_PREFIX: &str = "TX";
const APP_PREFIX: &str = "APP"; const APP_PREFIX: &str = "APP";
async fn get_user_duo_data(uuid: &str, conn: &mut DbConn) -> DuoStatus { async fn get_user_duo_data(user_uuid: &UserId, conn: &mut DbConn) -> DuoStatus {
let type_ = TwoFactorType::Duo as i32; let type_ = TwoFactorType::Duo as i32;
// If the user doesn't have an entry, disabled // If the user doesn't have an entry, disabled
let Some(twofactor) = TwoFactor::find_by_user_and_type(uuid, type_, conn).await else { let Some(twofactor) = TwoFactor::find_by_user_and_type(user_uuid, type_, conn).await else {
return DuoStatus::Disabled(DuoData::global().is_some()); return DuoStatus::Disabled(DuoData::global().is_some());
}; };

Datei anzeigen

@ -10,7 +10,7 @@ use crate::{
auth::Headers, auth::Headers,
crypto, crypto,
db::{ db::{
models::{EventType, TwoFactor, TwoFactorType, User}, models::{EventType, TwoFactor, TwoFactorType, User, UserId},
DbConn, DbConn,
}, },
error::{Error, MapResult}, error::{Error, MapResult},
@ -59,7 +59,7 @@ 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 /// Generate the token, save the data for later verification and send email to user
pub async fn send_token(user_uuid: &str, conn: &mut DbConn) -> EmptyResult { pub async fn send_token(user_uuid: &UserId, conn: &mut DbConn) -> EmptyResult {
let type_ = TwoFactorType::Email as i32; let type_ = TwoFactorType::Email as i32;
let mut twofactor = let mut twofactor =
TwoFactor::find_by_user_and_type(user_uuid, type_, conn).await.map_res("Two factor not found")?; TwoFactor::find_by_user_and_type(user_uuid, type_, conn).await.map_res("Two factor not found")?;
@ -198,7 +198,7 @@ async fn email(data: Json<EmailData>, headers: Headers, mut conn: DbConn) -> Jso
} }
/// Validate the email code when used as TwoFactor token mechanism /// Validate the email code when used as TwoFactor token mechanism
pub async fn validate_email_code_str(user_uuid: &str, token: &str, data: &str, conn: &mut DbConn) -> EmptyResult { pub async fn validate_email_code_str(user_uuid: &UserId, token: &str, data: &str, conn: &mut DbConn) -> EmptyResult {
let mut email_data = EmailTokenData::from_json(data)?; 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_uuid, TwoFactorType::Email as i32, conn)
.await .await
@ -327,7 +327,7 @@ pub fn obscure_email(email: &str) -> String {
format!("{}@{}", new_name, &domain) format!("{}@{}", new_name, &domain)
} }
pub async fn find_and_activate_email_2fa(user_uuid: &str, conn: &mut DbConn) -> EmptyResult { 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 { if let Some(user) = User::find_by_uuid(user_uuid, conn).await {
activate_email_2fa(&user, conn).await activate_email_2fa(&user, conn).await
} else { } else {

Datei anzeigen

@ -6,7 +6,7 @@ use crate::{
auth::Headers, auth::Headers,
crypto, crypto,
db::{ db::{
models::{TwoFactor, TwoFactorType}, models::{TwoFactor, TwoFactorType, UserId},
DbConn, DbConn,
}, },
error::{Error, MapResult}, error::{Error, MapResult},
@ -104,7 +104,7 @@ async fn verify_otp(data: Json<ProtectedActionVerify>, headers: Headers, mut con
pub async fn validate_protected_action_otp( pub async fn validate_protected_action_otp(
otp: &str, otp: &str,
user_uuid: &str, user_uuid: &UserId,
delete_if_valid: bool, delete_if_valid: bool,
conn: &mut DbConn, conn: &mut DbConn,
) -> EmptyResult { ) -> EmptyResult {

Datei anzeigen

@ -11,7 +11,7 @@ use crate::{
}, },
auth::Headers, auth::Headers,
db::{ db::{
models::{EventType, TwoFactor, TwoFactorType}, models::{EventType, TwoFactor, TwoFactorType, UserId},
DbConn, DbConn,
}, },
error::Error, error::Error,
@ -148,7 +148,7 @@ async fn generate_webauthn_challenge(data: Json<PasswordOrOtpData>, headers: Hea
)?; )?;
let type_ = TwoFactorType::WebauthnRegisterChallenge; let type_ = TwoFactorType::WebauthnRegisterChallenge;
TwoFactor::new(user.uuid, type_, serde_json::to_string(&state)?).save(&mut conn).await?; TwoFactor::new(user.uuid.clone(), type_, serde_json::to_string(&state)?).save(&mut conn).await?;
let mut challenge_value = serde_json::to_value(challenge.public_key)?; let mut challenge_value = serde_json::to_value(challenge.public_key)?;
challenge_value["status"] = "ok".into(); challenge_value["status"] = "ok".into();
@ -352,7 +352,7 @@ async fn delete_webauthn(data: Json<DeleteU2FData>, headers: Headers, mut conn:
} }
pub async fn get_webauthn_registrations( pub async fn get_webauthn_registrations(
user_uuid: &str, user_uuid: &UserId,
conn: &mut DbConn, conn: &mut DbConn,
) -> Result<(bool, Vec<WebauthnRegistration>), Error> { ) -> Result<(bool, Vec<WebauthnRegistration>), Error> {
let type_ = TwoFactorType::Webauthn as i32; let type_ = TwoFactorType::Webauthn as i32;
@ -362,7 +362,7 @@ pub async fn get_webauthn_registrations(
} }
} }
pub async fn generate_webauthn_login(user_uuid: &str, conn: &mut DbConn) -> JsonResult { pub async fn generate_webauthn_login(user_uuid: &UserId, conn: &mut DbConn) -> JsonResult {
// Load saved credentials // Load saved credentials
let creds: Vec<Credential> = let creds: Vec<Credential> =
get_webauthn_registrations(user_uuid, conn).await?.1.into_iter().map(|r| r.credential).collect(); get_webauthn_registrations(user_uuid, conn).await?.1.into_iter().map(|r| r.credential).collect();
@ -376,7 +376,7 @@ pub async fn generate_webauthn_login(user_uuid: &str, conn: &mut DbConn) -> Json
let (response, state) = WebauthnConfig::load().generate_challenge_authenticate_options(creds, Some(ext))?; let (response, state) = WebauthnConfig::load().generate_challenge_authenticate_options(creds, Some(ext))?;
// Save the challenge state for later validation // Save the challenge state for later validation
TwoFactor::new(user_uuid.into(), TwoFactorType::WebauthnLoginChallenge, serde_json::to_string(&state)?) TwoFactor::new(user_uuid.clone(), TwoFactorType::WebauthnLoginChallenge, serde_json::to_string(&state)?)
.save(conn) .save(conn)
.await?; .await?;
@ -384,7 +384,7 @@ pub async fn generate_webauthn_login(user_uuid: &str, conn: &mut DbConn) -> Json
Ok(Json(serde_json::to_value(response.public_key)?)) Ok(Json(serde_json::to_value(response.public_key)?))
} }
pub async fn validate_webauthn_login(user_uuid: &str, response: &str, conn: &mut DbConn) -> EmptyResult { pub async fn validate_webauthn_login(user_uuid: &UserId, response: &str, conn: &mut DbConn) -> EmptyResult {
let type_ = TwoFactorType::WebauthnLoginChallenge as i32; 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_uuid, type_, conn).await {
Some(tf) => { Some(tf) => {
@ -413,7 +413,7 @@ pub async fn validate_webauthn_login(user_uuid: &str, response: &str, conn: &mut
if &reg.credential.cred_id == cred_id { if &reg.credential.cred_id == cred_id {
reg.credential.counter = auth_data.counter; reg.credential.counter = auth_data.counter;
TwoFactor::new(user_uuid.to_string(), TwoFactorType::Webauthn, serde_json::to_string(&registrations)?) TwoFactor::new(user_uuid.clone(), TwoFactorType::Webauthn, serde_json::to_string(&registrations)?)
.save(conn) .save(conn)
.await?; .await?;
return Ok(()); return Ok(());

Datei anzeigen

@ -31,7 +31,7 @@ pub fn routes() -> Vec<Route> {
async fn login(data: Form<ConnectData>, client_header: ClientHeaders, mut conn: DbConn) -> JsonResult { async fn login(data: Form<ConnectData>, client_header: ClientHeaders, mut conn: DbConn) -> JsonResult {
let data: ConnectData = data.into_inner(); let data: ConnectData = data.into_inner();
let mut user_uuid: Option<String> = None; let mut user_uuid: Option<UserId> = None;
let login_result = match data.grant_type.as_ref() { let login_result = match data.grant_type.as_ref() {
"refresh_token" => { "refresh_token" => {
@ -141,7 +141,7 @@ struct MasterPasswordPolicy {
async fn _password_login( async fn _password_login(
data: ConnectData, data: ConnectData,
user_uuid: &mut Option<String>, user_uuid: &mut Option<UserId>,
conn: &mut DbConn, conn: &mut DbConn,
ip: &ClientIp, ip: &ClientIp,
) -> JsonResult { ) -> JsonResult {
@ -359,7 +359,7 @@ async fn _password_login(
async fn _api_key_login( async fn _api_key_login(
data: ConnectData, data: ConnectData,
user_uuid: &mut Option<String>, user_uuid: &mut Option<UserId>,
conn: &mut DbConn, conn: &mut DbConn,
ip: &ClientIp, ip: &ClientIp,
) -> JsonResult { ) -> JsonResult {
@ -376,7 +376,7 @@ async fn _api_key_login(
async fn _user_api_key_login( async fn _user_api_key_login(
data: ConnectData, data: ConnectData,
user_uuid: &mut Option<String>, user_uuid: &mut Option<UserId>,
conn: &mut DbConn, conn: &mut DbConn,
ip: &ClientIp, ip: &ClientIp,
) -> JsonResult { ) -> JsonResult {
@ -385,7 +385,8 @@ async fn _user_api_key_login(
let Some(client_user_uuid) = client_id.strip_prefix("user.") else { let Some(client_user_uuid) = client_id.strip_prefix("user.") else {
err!("Malformed client_id", format!("IP: {}.", ip.ip)) err!("Malformed client_id", format!("IP: {}.", ip.ip))
}; };
let Some(user) = User::find_by_uuid(client_user_uuid, conn).await else { let client_user_uuid: UserId = client_user_uuid.to_string().into();
let Some(user) = User::find_by_uuid(&client_user_uuid, conn).await else {
err!("Invalid client_id", format!("IP: {}.", ip.ip)) err!("Invalid client_id", format!("IP: {}.", ip.ip))
}; };
@ -615,7 +616,7 @@ fn _selected_data(tf: Option<TwoFactor>) -> ApiResult<String> {
async fn _json_err_twofactor( async fn _json_err_twofactor(
providers: &[i32], providers: &[i32],
user_uuid: &str, user_uuid: &UserId,
data: &ConnectData, data: &ConnectData,
conn: &mut DbConn, conn: &mut DbConn,
) -> ApiResult<Value> { ) -> ApiResult<Value> {

Datei anzeigen

@ -10,7 +10,7 @@ use rocket_ws::{Message, WebSocket};
use crate::{ use crate::{
auth::{ClientIp, WsAccessTokenHeader}, auth::{ClientIp, WsAccessTokenHeader},
db::{ db::{
models::{Cipher, Folder, Send as DbSend, User}, models::{Cipher, Folder, Send as DbSend, User, UserId},
DbConn, DbConn,
}, },
Error, CONFIG, Error, CONFIG,
@ -53,13 +53,13 @@ struct WsAccessToken {
struct WSEntryMapGuard { struct WSEntryMapGuard {
users: Arc<WebSocketUsers>, users: Arc<WebSocketUsers>,
user_uuid: String, user_uuid: UserId,
entry_uuid: uuid::Uuid, entry_uuid: uuid::Uuid,
addr: IpAddr, addr: IpAddr,
} }
impl WSEntryMapGuard { impl WSEntryMapGuard {
fn new(users: Arc<WebSocketUsers>, user_uuid: String, entry_uuid: uuid::Uuid, addr: IpAddr) -> Self { fn new(users: Arc<WebSocketUsers>, user_uuid: UserId, entry_uuid: uuid::Uuid, addr: IpAddr) -> Self {
Self { Self {
users, users,
user_uuid, user_uuid,
@ -72,7 +72,7 @@ impl WSEntryMapGuard {
impl Drop for WSEntryMapGuard { impl Drop for WSEntryMapGuard {
fn drop(&mut self) { fn drop(&mut self) {
info!("Closing WS connection from {}", self.addr); info!("Closing WS connection from {}", self.addr);
if let Some(mut entry) = self.users.map.get_mut(&self.user_uuid) { if let Some(mut entry) = self.users.map.get_mut(&self.user_uuid.to_string()) {
entry.retain(|(uuid, _)| uuid != &self.entry_uuid); entry.retain(|(uuid, _)| uuid != &self.entry_uuid);
} }
} }
@ -129,7 +129,7 @@ fn websockets_hub<'r>(
// Add a channel to send messages to this client to the map // Add a channel to send messages to this client to the map
let entry_uuid = uuid::Uuid::new_v4(); let entry_uuid = uuid::Uuid::new_v4();
let (tx, rx) = tokio::sync::mpsc::channel::<Message>(100); let (tx, rx) = tokio::sync::mpsc::channel::<Message>(100);
users.map.entry(claims.sub.clone()).or_default().push((entry_uuid, tx)); users.map.entry(claims.sub.to_string()).or_default().push((entry_uuid, tx));
// Once the guard goes out of scope, the connection will have been closed and the entry will be deleted from the map // Once the guard goes out of scope, the connection will have been closed and the entry will be deleted from the map
(rx, WSEntryMapGuard::new(users, claims.sub, entry_uuid, addr)) (rx, WSEntryMapGuard::new(users, claims.sub, entry_uuid, addr))
@ -328,8 +328,8 @@ pub struct WebSocketUsers {
} }
impl WebSocketUsers { impl WebSocketUsers {
async fn send_update(&self, user_uuid: &str, data: &[u8]) { async fn send_update(&self, user_uuid: &UserId, data: &[u8]) {
if let Some(user) = self.map.get(user_uuid).map(|v| v.clone()) { if let Some(user) = self.map.get(user_uuid.as_ref()).map(|v| v.clone()) {
for (_, sender) in user.iter() { for (_, sender) in user.iter() {
if let Err(e) = sender.send(Message::binary(data)).await { if let Err(e) = sender.send(Message::binary(data)).await {
error!("Error sending WS update {e}"); error!("Error sending WS update {e}");
@ -345,7 +345,7 @@ impl WebSocketUsers {
return; return;
} }
let data = create_update( let data = create_update(
vec![("UserId".into(), user.uuid.clone().into()), ("Date".into(), serialize_date(user.updated_at))], vec![("UserId".into(), user.uuid.to_string().into()), ("Date".into(), serialize_date(user.updated_at))],
ut, ut,
None, None,
); );
@ -365,7 +365,7 @@ impl WebSocketUsers {
return; return;
} }
let data = create_update( let data = create_update(
vec![("UserId".into(), user.uuid.clone().into()), ("Date".into(), serialize_date(user.updated_at))], vec![("UserId".into(), user.uuid.to_string().into()), ("Date".into(), serialize_date(user.updated_at))],
UpdateType::LogOut, UpdateType::LogOut,
acting_device_uuid.clone(), acting_device_uuid.clone(),
); );
@ -393,7 +393,7 @@ impl WebSocketUsers {
let data = create_update( let data = create_update(
vec![ vec![
("Id".into(), folder.uuid.clone().into()), ("Id".into(), folder.uuid.clone().into()),
("UserId".into(), folder.user_uuid.clone().into()), ("UserId".into(), folder.user_uuid.to_string().into()),
("RevisionDate".into(), serialize_date(folder.updated_at)), ("RevisionDate".into(), serialize_date(folder.updated_at)),
], ],
ut, ut,
@ -413,7 +413,7 @@ impl WebSocketUsers {
&self, &self,
ut: UpdateType, ut: UpdateType,
cipher: &Cipher, cipher: &Cipher,
user_uuids: &[String], user_uuids: &[UserId],
acting_device_uuid: &String, acting_device_uuid: &String,
collection_uuids: Option<Vec<String>>, collection_uuids: Option<Vec<String>>,
conn: &mut DbConn, conn: &mut DbConn,
@ -432,7 +432,7 @@ impl WebSocketUsers {
serialize_date(Utc::now().naive_utc()), serialize_date(Utc::now().naive_utc()),
) )
} else { } else {
(convert_option(cipher.user_uuid.clone()), Value::Nil, serialize_date(cipher.updated_at)) (convert_option(cipher.user_uuid.as_deref()), Value::Nil, serialize_date(cipher.updated_at))
}; };
let data = create_update( let data = create_update(
@ -462,7 +462,7 @@ impl WebSocketUsers {
&self, &self,
ut: UpdateType, ut: UpdateType,
send: &DbSend, send: &DbSend,
user_uuids: &[String], user_uuids: &[UserId],
acting_device_uuid: &String, acting_device_uuid: &String,
conn: &mut DbConn, conn: &mut DbConn,
) { ) {
@ -470,7 +470,7 @@ impl WebSocketUsers {
if *NOTIFICATIONS_DISABLED { if *NOTIFICATIONS_DISABLED {
return; return;
} }
let user_uuid = convert_option(send.user_uuid.clone()); let user_uuid = convert_option(send.user_uuid.as_deref());
let data = create_update( let data = create_update(
vec![ vec![
@ -494,7 +494,7 @@ impl WebSocketUsers {
pub async fn send_auth_request( pub async fn send_auth_request(
&self, &self,
user_uuid: &String, user_uuid: &UserId,
auth_request_uuid: &String, auth_request_uuid: &String,
acting_device_uuid: &String, acting_device_uuid: &String,
conn: &mut DbConn, conn: &mut DbConn,
@ -504,7 +504,7 @@ impl WebSocketUsers {
return; return;
} }
let data = create_update( let data = create_update(
vec![("Id".into(), auth_request_uuid.clone().into()), ("UserId".into(), user_uuid.clone().into())], vec![("Id".into(), auth_request_uuid.clone().into()), ("UserId".into(), user_uuid.to_string().into())],
UpdateType::AuthRequest, UpdateType::AuthRequest,
Some(acting_device_uuid.to_string()), Some(acting_device_uuid.to_string()),
); );
@ -513,13 +513,13 @@ impl WebSocketUsers {
} }
if CONFIG.push_enabled() { if CONFIG.push_enabled() {
push_auth_request(user_uuid.to_string(), auth_request_uuid.to_string(), conn).await; push_auth_request(user_uuid.clone(), auth_request_uuid.to_string(), conn).await;
} }
} }
pub async fn send_auth_response( pub async fn send_auth_response(
&self, &self,
user_uuid: &String, user_uuid: &UserId,
auth_response_uuid: &str, auth_response_uuid: &str,
approving_device_uuid: String, approving_device_uuid: String,
conn: &mut DbConn, conn: &mut DbConn,
@ -529,17 +529,16 @@ impl WebSocketUsers {
return; return;
} }
let data = create_update( let data = create_update(
vec![("Id".into(), auth_response_uuid.to_owned().into()), ("UserId".into(), user_uuid.clone().into())], vec![("Id".into(), auth_response_uuid.to_owned().into()), ("UserId".into(), user_uuid.to_string().into())],
UpdateType::AuthRequestResponse, UpdateType::AuthRequestResponse,
approving_device_uuid.clone().into(), approving_device_uuid.clone().into(),
); );
if CONFIG.enable_websocket() { if CONFIG.enable_websocket() {
self.send_update(auth_response_uuid, &data).await; self.send_update(user_uuid, &data).await;
} }
if CONFIG.push_enabled() { if CONFIG.push_enabled() {
push_auth_response(user_uuid.to_string(), auth_response_uuid.to_string(), approving_device_uuid, conn) push_auth_response(user_uuid.clone(), auth_response_uuid.to_string(), approving_device_uuid, conn).await;
.await;
} }
} }
} }
@ -558,16 +557,16 @@ impl AnonymousWebSocketSubscriptions {
} }
} }
pub async fn send_auth_response(&self, user_uuid: &String, auth_response_uuid: &str) { pub async fn send_auth_response(&self, user_uuid: &UserId, auth_response_uuid: &str) {
if !CONFIG.enable_websocket() { if !CONFIG.enable_websocket() {
return; return;
} }
let data = create_anonymous_update( let data = create_anonymous_update(
vec![("Id".into(), auth_response_uuid.to_owned().into()), ("UserId".into(), user_uuid.clone().into())], vec![("Id".into(), auth_response_uuid.to_owned().into()), ("UserId".into(), user_uuid.to_string().into())],
UpdateType::AuthRequestResponse, UpdateType::AuthRequestResponse,
user_uuid.to_string(), user_uuid.clone(),
); );
self.send_update(auth_response_uuid, &data).await; self.send_update(user_uuid, &data).await;
} }
} }
@ -604,7 +603,7 @@ fn create_update(payload: Vec<(Value, Value)>, ut: UpdateType, acting_device_uui
serialize(value) serialize(value)
} }
fn create_anonymous_update(payload: Vec<(Value, Value)>, ut: UpdateType, user_id: String) -> Vec<u8> { fn create_anonymous_update(payload: Vec<(Value, Value)>, ut: UpdateType, user_id: UserId) -> Vec<u8> {
use rmpv::Value as V; use rmpv::Value as V;
let value = V::Array(vec![ let value = V::Array(vec![
@ -615,7 +614,7 @@ fn create_anonymous_update(payload: Vec<(Value, Value)>, ut: UpdateType, user_id
V::Array(vec![V::Map(vec![ V::Array(vec![V::Map(vec![
("Type".into(), (ut as i32).into()), ("Type".into(), (ut as i32).into()),
("Payload".into(), payload.into()), ("Payload".into(), payload.into()),
("UserId".into(), user_id.into()), ("UserId".into(), user_id.to_string().into()),
])]), ])]),
]); ]);

Datei anzeigen

@ -7,7 +7,7 @@ use tokio::sync::RwLock;
use crate::{ use crate::{
api::{ApiResult, EmptyResult, UpdateType}, api::{ApiResult, EmptyResult, UpdateType},
db::models::{Cipher, Device, Folder, Send, User}, db::models::{Cipher, Device, Folder, Send, User, UserId},
http_client::make_http_request, http_client::make_http_request,
util::format_date, util::format_date,
CONFIG, CONFIG,
@ -284,8 +284,8 @@ async fn send_to_push_relay(notification_data: Value) {
}; };
} }
pub async fn push_auth_request(user_uuid: String, auth_request_uuid: String, conn: &mut crate::db::DbConn) { 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.as_str(), conn).await { if Device::check_user_has_push_device(&user_uuid, conn).await {
tokio::task::spawn(send_to_push_relay(json!({ tokio::task::spawn(send_to_push_relay(json!({
"userId": user_uuid, "userId": user_uuid,
"organizationId": (), "organizationId": (),
@ -301,12 +301,12 @@ pub async fn push_auth_request(user_uuid: String, auth_request_uuid: String, con
} }
pub async fn push_auth_response( pub async fn push_auth_response(
user_uuid: String, user_uuid: UserId,
auth_request_uuid: String, auth_request_uuid: String,
approving_device_uuid: String, approving_device_uuid: String,
conn: &mut crate::db::DbConn, conn: &mut crate::db::DbConn,
) { ) {
if Device::check_user_has_push_device(user_uuid.as_str(), conn).await { if Device::check_user_has_push_device(&user_uuid, conn).await {
tokio::task::spawn(send_to_push_relay(json!({ tokio::task::spawn(send_to_push_relay(json!({
"userId": user_uuid, "userId": user_uuid,
"organizationId": (), "organizationId": (),

Datei anzeigen

@ -14,7 +14,7 @@ use std::{
net::IpAddr, net::IpAddr,
}; };
use crate::db::models::{MembershipId, OrganizationId}; use crate::db::models::{MembershipId, OrganizationId, UserId};
use crate::{error::Error, CONFIG}; use crate::{error::Error, CONFIG};
const JWT_ALGORITHM: Algorithm = Algorithm::RS256; const JWT_ALGORITHM: Algorithm = Algorithm::RS256;
@ -151,7 +151,7 @@ pub struct LoginJwtClaims {
// Issuer // Issuer
pub iss: String, pub iss: String,
// Subject // Subject
pub sub: String, pub sub: UserId,
pub premium: bool, pub premium: bool,
pub name: String, pub name: String,

Datei anzeigen

@ -3,7 +3,7 @@ use std::io::ErrorKind;
use bigdecimal::{BigDecimal, ToPrimitive}; use bigdecimal::{BigDecimal, ToPrimitive};
use serde_json::Value; use serde_json::Value;
use super::OrganizationId; use super::{OrganizationId, UserId};
use crate::CONFIG; use crate::CONFIG;
db_object! { db_object! {
@ -145,7 +145,7 @@ impl Attachment {
}} }}
} }
pub async fn size_by_user(user_uuid: &str, conn: &mut DbConn) -> i64 { pub async fn size_by_user(user_uuid: &UserId, conn: &mut DbConn) -> i64 {
db_run! { conn: { db_run! { conn: {
let result: Option<BigDecimal> = attachments::table let result: Option<BigDecimal> = attachments::table
.left_join(ciphers::table.on(ciphers::uuid.eq(attachments::cipher_uuid))) .left_join(ciphers::table.on(ciphers::uuid.eq(attachments::cipher_uuid)))
@ -162,7 +162,7 @@ impl Attachment {
}} }}
} }
pub async fn count_by_user(user_uuid: &str, conn: &mut DbConn) -> i64 { pub async fn count_by_user(user_uuid: &UserId, conn: &mut DbConn) -> i64 {
db_run! { conn: { db_run! { conn: {
attachments::table attachments::table
.left_join(ciphers::table.on(ciphers::uuid.eq(attachments::cipher_uuid))) .left_join(ciphers::table.on(ciphers::uuid.eq(attachments::cipher_uuid)))
@ -205,7 +205,7 @@ impl Attachment {
// There is no filtering done here if the user actually has access! // There is no filtering done here if the user actually has access!
// It is used to speed up the sync process, and the matching is done in a different part. // It is used to speed up the sync process, and the matching is done in a different part.
pub async fn find_all_by_user_and_orgs( pub async fn find_all_by_user_and_orgs(
user_uuid: &str, user_uuid: &UserId,
org_uuids: &Vec<OrganizationId>, org_uuids: &Vec<OrganizationId>,
conn: &mut DbConn, conn: &mut DbConn,
) -> Vec<Self> { ) -> Vec<Self> {

Datei anzeigen

@ -1,4 +1,4 @@
use super::OrganizationId; use super::{OrganizationId, UserId};
use crate::crypto::ct_eq; use crate::crypto::ct_eq;
use chrono::{NaiveDateTime, Utc}; use chrono::{NaiveDateTime, Utc};
@ -9,7 +9,7 @@ db_object! {
#[diesel(primary_key(uuid))] #[diesel(primary_key(uuid))]
pub struct AuthRequest { pub struct AuthRequest {
pub uuid: String, pub uuid: String,
pub user_uuid: String, pub user_uuid: UserId,
pub organization_uuid: Option<OrganizationId>, pub organization_uuid: Option<OrganizationId>,
pub request_device_identifier: String, pub request_device_identifier: String,
@ -34,7 +34,7 @@ db_object! {
impl AuthRequest { impl AuthRequest {
pub fn new( pub fn new(
user_uuid: String, user_uuid: UserId,
request_device_identifier: String, request_device_identifier: String,
device_type: i32, device_type: i32,
request_ip: String, request_ip: String,
@ -112,7 +112,7 @@ impl AuthRequest {
}} }}
} }
pub async fn find_by_uuid_and_user(uuid: &str, user_uuid: &str, conn: &mut DbConn) -> Option<Self> { pub async fn find_by_uuid_and_user(uuid: &str, user_uuid: &UserId, conn: &mut DbConn) -> Option<Self> {
db_run! {conn: { db_run! {conn: {
auth_requests::table auth_requests::table
.filter(auth_requests::uuid.eq(uuid)) .filter(auth_requests::uuid.eq(uuid))
@ -123,7 +123,7 @@ impl AuthRequest {
}} }}
} }
pub async fn find_by_user(user_uuid: &str, conn: &mut DbConn) -> Vec<Self> { pub async fn find_by_user(user_uuid: &UserId, conn: &mut DbConn) -> Vec<Self> {
db_run! {conn: { db_run! {conn: {
auth_requests::table auth_requests::table
.filter(auth_requests::user_uuid.eq(user_uuid)) .filter(auth_requests::user_uuid.eq(user_uuid))

Datei anzeigen

@ -5,7 +5,7 @@ use serde_json::Value;
use super::{ use super::{
Attachment, CollectionCipher, Favorite, FolderCipher, Group, Membership, MembershipStatus, MembershipType, Attachment, CollectionCipher, Favorite, FolderCipher, Group, Membership, MembershipStatus, MembershipType,
OrganizationId, User, OrganizationId, User, UserId,
}; };
use crate::api::core::{CipherData, CipherSyncData, CipherSyncType}; use crate::api::core::{CipherData, CipherSyncData, CipherSyncType};
@ -22,7 +22,7 @@ db_object! {
pub created_at: NaiveDateTime, pub created_at: NaiveDateTime,
pub updated_at: NaiveDateTime, pub updated_at: NaiveDateTime,
pub user_uuid: Option<String>, pub user_uuid: Option<UserId>,
pub organization_uuid: Option<OrganizationId>, pub organization_uuid: Option<OrganizationId>,
pub key: Option<String>, pub key: Option<String>,
@ -136,7 +136,7 @@ impl Cipher {
pub async fn to_json( pub async fn to_json(
&self, &self,
host: &str, host: &str,
user_uuid: &str, user_uuid: &UserId,
cipher_sync_data: Option<&CipherSyncData>, cipher_sync_data: Option<&CipherSyncData>,
sync_type: CipherSyncType, sync_type: CipherSyncType,
conn: &mut DbConn, conn: &mut DbConn,
@ -357,7 +357,7 @@ impl Cipher {
json_object json_object
} }
pub async fn update_users_revision(&self, conn: &mut DbConn) -> Vec<String> { pub async fn update_users_revision(&self, conn: &mut DbConn) -> Vec<UserId> {
let mut user_uuids = Vec::new(); let mut user_uuids = Vec::new();
match self.user_uuid { match self.user_uuid {
Some(ref user_uuid) => { Some(ref user_uuid) => {
@ -443,7 +443,7 @@ impl Cipher {
Ok(()) Ok(())
} }
pub async fn delete_all_by_user(user_uuid: &str, conn: &mut DbConn) -> EmptyResult { pub async fn delete_all_by_user(user_uuid: &UserId, conn: &mut DbConn) -> EmptyResult {
for cipher in Self::find_owned_by_user(user_uuid, conn).await { for cipher in Self::find_owned_by_user(user_uuid, conn).await {
cipher.delete(conn).await?; cipher.delete(conn).await?;
} }
@ -461,7 +461,12 @@ impl Cipher {
} }
} }
pub async fn move_to_folder(&self, folder_uuid: Option<String>, user_uuid: &str, conn: &mut DbConn) -> EmptyResult { pub async fn move_to_folder(
&self,
folder_uuid: Option<String>,
user_uuid: &UserId,
conn: &mut DbConn,
) -> EmptyResult {
User::update_uuid_revision(user_uuid, conn).await; User::update_uuid_revision(user_uuid, conn).await;
match (self.get_folder_uuid(user_uuid, conn).await, folder_uuid) { match (self.get_folder_uuid(user_uuid, conn).await, folder_uuid) {
@ -489,14 +494,14 @@ impl Cipher {
} }
/// Returns whether this cipher is directly owned by the user. /// Returns whether this cipher is directly owned by the user.
pub fn is_owned_by_user(&self, user_uuid: &str) -> bool { pub fn is_owned_by_user(&self, user_uuid: &UserId) -> bool {
self.user_uuid.is_some() && self.user_uuid.as_ref().unwrap() == user_uuid self.user_uuid.is_some() && self.user_uuid.as_ref().unwrap() == user_uuid
} }
/// Returns whether this cipher is owned by an org in which the user has full access. /// Returns whether this cipher is owned by an org in which the user has full access.
async fn is_in_full_access_org( async fn is_in_full_access_org(
&self, &self,
user_uuid: &str, user_uuid: &UserId,
cipher_sync_data: Option<&CipherSyncData>, cipher_sync_data: Option<&CipherSyncData>,
conn: &mut DbConn, conn: &mut DbConn,
) -> bool { ) -> bool {
@ -515,7 +520,7 @@ impl Cipher {
/// Returns whether this cipher is owned by an group in which the user has full access. /// Returns whether this cipher is owned by an group in which the user has full access.
async fn is_in_full_access_group( async fn is_in_full_access_group(
&self, &self,
user_uuid: &str, user_uuid: &UserId,
cipher_sync_data: Option<&CipherSyncData>, cipher_sync_data: Option<&CipherSyncData>,
conn: &mut DbConn, conn: &mut DbConn,
) -> bool { ) -> bool {
@ -539,7 +544,7 @@ impl Cipher {
/// the access restrictions. /// the access restrictions.
pub async fn get_access_restrictions( pub async fn get_access_restrictions(
&self, &self,
user_uuid: &str, user_uuid: &UserId,
cipher_sync_data: Option<&CipherSyncData>, cipher_sync_data: Option<&CipherSyncData>,
conn: &mut DbConn, conn: &mut DbConn,
) -> Option<(bool, bool)> { ) -> Option<(bool, bool)> {
@ -599,7 +604,7 @@ impl Cipher {
Some((read_only, hide_passwords)) Some((read_only, hide_passwords))
} }
async fn get_user_collections_access_flags(&self, user_uuid: &str, conn: &mut DbConn) -> Vec<(bool, bool)> { async fn get_user_collections_access_flags(&self, user_uuid: &UserId, conn: &mut DbConn) -> Vec<(bool, bool)> {
db_run! {conn: { db_run! {conn: {
// Check whether this cipher is in any collections accessible to the // Check whether this cipher is in any collections accessible to the
// user. If so, retrieve the access flags for each collection. // user. If so, retrieve the access flags for each collection.
@ -616,7 +621,7 @@ impl Cipher {
}} }}
} }
async fn get_group_collections_access_flags(&self, user_uuid: &str, conn: &mut DbConn) -> Vec<(bool, bool)> { async fn get_group_collections_access_flags(&self, user_uuid: &UserId, conn: &mut DbConn) -> Vec<(bool, bool)> {
if !CONFIG.org_groups_enabled() { if !CONFIG.org_groups_enabled() {
return Vec::new(); return Vec::new();
} }
@ -642,31 +647,31 @@ impl Cipher {
}} }}
} }
pub async fn is_write_accessible_to_user(&self, user_uuid: &str, conn: &mut DbConn) -> bool { pub async fn is_write_accessible_to_user(&self, user_uuid: &UserId, conn: &mut DbConn) -> bool {
match self.get_access_restrictions(user_uuid, None, conn).await { match self.get_access_restrictions(user_uuid, None, conn).await {
Some((read_only, _hide_passwords)) => !read_only, Some((read_only, _hide_passwords)) => !read_only,
None => false, None => false,
} }
} }
pub async fn is_accessible_to_user(&self, user_uuid: &str, conn: &mut DbConn) -> bool { pub async fn is_accessible_to_user(&self, user_uuid: &UserId, conn: &mut DbConn) -> bool {
self.get_access_restrictions(user_uuid, None, conn).await.is_some() self.get_access_restrictions(user_uuid, None, conn).await.is_some()
} }
// Returns whether this cipher is a favorite of the specified user. // Returns whether this cipher is a favorite of the specified user.
pub async fn is_favorite(&self, user_uuid: &str, conn: &mut DbConn) -> bool { pub async fn is_favorite(&self, user_uuid: &UserId, conn: &mut DbConn) -> bool {
Favorite::is_favorite(&self.uuid, user_uuid, conn).await Favorite::is_favorite(&self.uuid, user_uuid, conn).await
} }
// Sets whether this cipher is a favorite of the specified user. // Sets whether this cipher is a favorite of the specified user.
pub async fn set_favorite(&self, favorite: Option<bool>, user_uuid: &str, conn: &mut DbConn) -> EmptyResult { pub async fn set_favorite(&self, favorite: Option<bool>, user_uuid: &UserId, conn: &mut DbConn) -> EmptyResult {
match favorite { match favorite {
None => Ok(()), // No change requested. None => Ok(()), // No change requested.
Some(status) => Favorite::set_favorite(status, &self.uuid, user_uuid, conn).await, Some(status) => Favorite::set_favorite(status, &self.uuid, user_uuid, conn).await,
} }
} }
pub async fn get_folder_uuid(&self, user_uuid: &str, conn: &mut DbConn) -> Option<String> { pub async fn get_folder_uuid(&self, user_uuid: &UserId, conn: &mut DbConn) -> Option<String> {
db_run! {conn: { db_run! {conn: {
folders_ciphers::table folders_ciphers::table
.inner_join(folders::table) .inner_join(folders::table)
@ -711,7 +716,7 @@ impl Cipher {
// true, then the non-interesting ciphers will not be returned. As a // true, then the non-interesting ciphers will not be returned. As a
// result, those ciphers will not appear in "My Vault" for the org // result, those ciphers will not appear in "My Vault" for the org
// owner/admin, but they can still be accessed via the org vault view. // owner/admin, but they can still be accessed via the org vault view.
pub async fn find_by_user(user_uuid: &str, visible_only: bool, conn: &mut DbConn) -> Vec<Self> { pub async fn find_by_user(user_uuid: &UserId, visible_only: bool, conn: &mut DbConn) -> Vec<Self> {
if CONFIG.org_groups_enabled() { if CONFIG.org_groups_enabled() {
db_run! {conn: { db_run! {conn: {
let mut query = ciphers::table let mut query = ciphers::table
@ -793,12 +798,12 @@ impl Cipher {
} }
// Find all ciphers visible to the specified user. // Find all ciphers visible to the specified user.
pub async fn find_by_user_visible(user_uuid: &str, conn: &mut DbConn) -> Vec<Self> { pub async fn find_by_user_visible(user_uuid: &UserId, conn: &mut DbConn) -> Vec<Self> {
Self::find_by_user(user_uuid, true, conn).await Self::find_by_user(user_uuid, true, conn).await
} }
// Find all ciphers directly owned by the specified user. // Find all ciphers directly owned by the specified user.
pub async fn find_owned_by_user(user_uuid: &str, conn: &mut DbConn) -> Vec<Self> { pub async fn find_owned_by_user(user_uuid: &UserId, conn: &mut DbConn) -> Vec<Self> {
db_run! {conn: { db_run! {conn: {
ciphers::table ciphers::table
.filter( .filter(
@ -809,7 +814,7 @@ impl Cipher {
}} }}
} }
pub async fn count_owned_by_user(user_uuid: &str, conn: &mut DbConn) -> i64 { pub async fn count_owned_by_user(user_uuid: &UserId, conn: &mut DbConn) -> i64 {
db_run! {conn: { db_run! {conn: {
ciphers::table ciphers::table
.filter(ciphers::user_uuid.eq(user_uuid)) .filter(ciphers::user_uuid.eq(user_uuid))

Datei anzeigen

@ -1,6 +1,6 @@
use serde_json::Value; use serde_json::Value;
use super::{CollectionGroup, GroupUser, Membership, MembershipStatus, MembershipType, OrganizationId, User}; use super::{CollectionGroup, GroupUser, Membership, MembershipStatus, MembershipType, OrganizationId, User, UserId};
use crate::CONFIG; use crate::CONFIG;
db_object! { db_object! {
@ -18,7 +18,7 @@ db_object! {
#[diesel(table_name = users_collections)] #[diesel(table_name = users_collections)]
#[diesel(primary_key(user_uuid, collection_uuid))] #[diesel(primary_key(user_uuid, collection_uuid))]
pub struct CollectionUser { pub struct CollectionUser {
pub user_uuid: String, pub user_uuid: UserId,
pub collection_uuid: String, pub collection_uuid: String,
pub read_only: bool, pub read_only: bool,
pub hide_passwords: bool, pub hide_passwords: bool,
@ -74,7 +74,7 @@ impl Collection {
pub async fn to_json_details( pub async fn to_json_details(
&self, &self,
user_uuid: &str, user_uuid: &UserId,
cipher_sync_data: Option<&crate::api::core::CipherSyncData>, cipher_sync_data: Option<&crate::api::core::CipherSyncData>,
conn: &mut DbConn, conn: &mut DbConn,
) -> Value { ) -> Value {
@ -208,7 +208,7 @@ impl Collection {
}} }}
} }
pub async fn find_by_user_uuid(user_uuid: String, conn: &mut DbConn) -> Vec<Self> { pub async fn find_by_user_uuid(user_uuid: UserId, conn: &mut DbConn) -> Vec<Self> {
if CONFIG.org_groups_enabled() { if CONFIG.org_groups_enabled() {
db_run! { conn: { db_run! { conn: {
collections::table collections::table
@ -281,7 +281,7 @@ impl Collection {
pub async fn find_by_organization_and_user_uuid( pub async fn find_by_organization_and_user_uuid(
org_uuid: &OrganizationId, org_uuid: &OrganizationId,
user_uuid: &str, user_uuid: &UserId,
conn: &mut DbConn, conn: &mut DbConn,
) -> Vec<Self> { ) -> Vec<Self> {
Self::find_by_user_uuid(user_uuid.to_owned(), conn) Self::find_by_user_uuid(user_uuid.to_owned(), conn)
@ -324,7 +324,7 @@ impl Collection {
}} }}
} }
pub async fn find_by_uuid_and_user(uuid: &str, user_uuid: String, conn: &mut DbConn) -> Option<Self> { pub async fn find_by_uuid_and_user(uuid: &str, user_uuid: UserId, conn: &mut DbConn) -> Option<Self> {
if CONFIG.org_groups_enabled() { if CONFIG.org_groups_enabled() {
db_run! { conn: { db_run! { conn: {
collections::table collections::table
@ -391,7 +391,7 @@ impl Collection {
} }
} }
pub async fn is_writable_by_user(&self, user_uuid: &str, conn: &mut DbConn) -> bool { pub async fn is_writable_by_user(&self, user_uuid: &UserId, conn: &mut DbConn) -> bool {
let user_uuid = user_uuid.to_string(); let user_uuid = user_uuid.to_string();
if CONFIG.org_groups_enabled() { if CONFIG.org_groups_enabled() {
db_run! { conn: { db_run! { conn: {
@ -453,7 +453,7 @@ impl Collection {
} }
} }
pub async fn hide_passwords_for_user(&self, user_uuid: &str, conn: &mut DbConn) -> bool { pub async fn hide_passwords_for_user(&self, user_uuid: &UserId, conn: &mut DbConn) -> bool {
let user_uuid = user_uuid.to_string(); let user_uuid = user_uuid.to_string();
db_run! { conn: { db_run! { conn: {
collections::table collections::table
@ -504,7 +504,7 @@ impl Collection {
impl CollectionUser { impl CollectionUser {
pub async fn find_by_organization_and_user_uuid( pub async fn find_by_organization_and_user_uuid(
org_uuid: &OrganizationId, org_uuid: &OrganizationId,
user_uuid: &str, user_uuid: &UserId,
conn: &mut DbConn, conn: &mut DbConn,
) -> Vec<Self> { ) -> Vec<Self> {
db_run! { conn: { db_run! { conn: {
@ -533,7 +533,7 @@ impl CollectionUser {
} }
pub async fn save( pub async fn save(
user_uuid: &str, user_uuid: &UserId,
collection_uuid: &str, collection_uuid: &str,
read_only: bool, read_only: bool,
hide_passwords: bool, hide_passwords: bool,
@ -632,7 +632,7 @@ impl CollectionUser {
pub async fn find_by_collection_and_user( pub async fn find_by_collection_and_user(
collection_uuid: &str, collection_uuid: &str,
user_uuid: &str, user_uuid: &UserId,
conn: &mut DbConn, conn: &mut DbConn,
) -> Option<Self> { ) -> Option<Self> {
db_run! { conn: { db_run! { conn: {
@ -646,7 +646,7 @@ impl CollectionUser {
}} }}
} }
pub async fn find_by_user(user_uuid: &str, conn: &mut DbConn) -> Vec<Self> { pub async fn find_by_user(user_uuid: &UserId, conn: &mut DbConn) -> Vec<Self> {
db_run! { conn: { db_run! { conn: {
users_collections::table users_collections::table
.filter(users_collections::user_uuid.eq(user_uuid)) .filter(users_collections::user_uuid.eq(user_uuid))
@ -670,7 +670,7 @@ impl CollectionUser {
} }
pub async fn delete_all_by_user_and_org( pub async fn delete_all_by_user_and_org(
user_uuid: &str, user_uuid: &UserId,
org_uuid: &OrganizationId, org_uuid: &OrganizationId,
conn: &mut DbConn, conn: &mut DbConn,
) -> EmptyResult { ) -> EmptyResult {
@ -689,7 +689,7 @@ impl CollectionUser {
}} }}
} }
pub async fn has_access_to_collection_by_user(col_id: &str, user_uuid: &str, conn: &mut DbConn) -> bool { pub async fn has_access_to_collection_by_user(col_id: &str, user_uuid: &UserId, conn: &mut DbConn) -> bool {
Self::find_by_collection_and_user(col_id, user_uuid, conn).await.is_some() Self::find_by_collection_and_user(col_id, user_uuid, conn).await.is_some()
} }
} }

Datei anzeigen

@ -1,5 +1,6 @@
use chrono::{NaiveDateTime, Utc}; use chrono::{NaiveDateTime, Utc};
use super::UserId;
use crate::{crypto, CONFIG}; use crate::{crypto, CONFIG};
use core::fmt; use core::fmt;
@ -13,7 +14,7 @@ db_object! {
pub created_at: NaiveDateTime, pub created_at: NaiveDateTime,
pub updated_at: NaiveDateTime, pub updated_at: NaiveDateTime,
pub user_uuid: String, pub user_uuid: UserId,
pub name: String, pub name: String,
pub atype: i32, // https://github.com/bitwarden/server/blob/dcc199bcce4aa2d5621f6fab80f1b49d8b143418/src/Core/Enums/DeviceType.cs pub atype: i32, // https://github.com/bitwarden/server/blob/dcc199bcce4aa2d5621f6fab80f1b49d8b143418/src/Core/Enums/DeviceType.cs
@ -28,7 +29,7 @@ db_object! {
/// Local methods /// Local methods
impl Device { impl Device {
pub fn new(uuid: String, user_uuid: String, name: String, atype: i32) -> Self { pub fn new(uuid: String, user_uuid: UserId, name: String, atype: i32) -> Self {
let now = Utc::now().naive_utc(); let now = Utc::now().naive_utc();
Self { Self {
@ -150,7 +151,7 @@ impl Device {
} }
} }
pub async fn delete_all_by_user(user_uuid: &str, conn: &mut DbConn) -> EmptyResult { pub async fn delete_all_by_user(user_uuid: &UserId, conn: &mut DbConn) -> EmptyResult {
db_run! { conn: { db_run! { conn: {
diesel::delete(devices::table.filter(devices::user_uuid.eq(user_uuid))) diesel::delete(devices::table.filter(devices::user_uuid.eq(user_uuid)))
.execute(conn) .execute(conn)
@ -158,7 +159,7 @@ impl Device {
}} }}
} }
pub async fn find_by_uuid_and_user(uuid: &str, user_uuid: &str, conn: &mut DbConn) -> Option<Self> { pub async fn find_by_uuid_and_user(uuid: &str, user_uuid: &UserId, conn: &mut DbConn) -> Option<Self> {
db_run! { conn: { db_run! { conn: {
devices::table devices::table
.filter(devices::uuid.eq(uuid)) .filter(devices::uuid.eq(uuid))
@ -169,7 +170,7 @@ impl Device {
}} }}
} }
pub async fn find_by_user(user_uuid: &str, conn: &mut DbConn) -> Vec<Self> { pub async fn find_by_user(user_uuid: &UserId, conn: &mut DbConn) -> Vec<Self> {
db_run! { conn: { db_run! { conn: {
devices::table devices::table
.filter(devices::user_uuid.eq(user_uuid)) .filter(devices::user_uuid.eq(user_uuid))
@ -208,7 +209,7 @@ impl Device {
}} }}
} }
pub async fn find_latest_active_by_user(user_uuid: &str, conn: &mut DbConn) -> Option<Self> { pub async fn find_latest_active_by_user(user_uuid: &UserId, conn: &mut DbConn) -> Option<Self> {
db_run! { conn: { db_run! { conn: {
devices::table devices::table
.filter(devices::user_uuid.eq(user_uuid)) .filter(devices::user_uuid.eq(user_uuid))
@ -219,7 +220,7 @@ impl Device {
}} }}
} }
pub async fn find_push_devices_by_user(user_uuid: &str, conn: &mut DbConn) -> Vec<Self> { pub async fn find_push_devices_by_user(user_uuid: &UserId, conn: &mut DbConn) -> Vec<Self> {
db_run! { conn: { db_run! { conn: {
devices::table devices::table
.filter(devices::user_uuid.eq(user_uuid)) .filter(devices::user_uuid.eq(user_uuid))
@ -230,7 +231,7 @@ impl Device {
}} }}
} }
pub async fn check_user_has_push_device(user_uuid: &str, conn: &mut DbConn) -> bool { pub async fn check_user_has_push_device(user_uuid: &UserId, conn: &mut DbConn) -> bool {
db_run! { conn: { db_run! { conn: {
devices::table devices::table
.filter(devices::user_uuid.eq(user_uuid)) .filter(devices::user_uuid.eq(user_uuid))

Datei anzeigen

@ -3,7 +3,7 @@ use serde_json::Value;
use crate::{api::EmptyResult, db::DbConn, error::MapResult}; use crate::{api::EmptyResult, db::DbConn, error::MapResult};
use super::User; use super::{User, UserId};
db_object! { db_object! {
#[derive(Identifiable, Queryable, Insertable, AsChangeset)] #[derive(Identifiable, Queryable, Insertable, AsChangeset)]
@ -12,8 +12,8 @@ db_object! {
#[diesel(primary_key(uuid))] #[diesel(primary_key(uuid))]
pub struct EmergencyAccess { pub struct EmergencyAccess {
pub uuid: String, pub uuid: String,
pub grantor_uuid: String, pub grantor_uuid: UserId,
pub grantee_uuid: Option<String>, pub grantee_uuid: Option<UserId>,
pub email: Option<String>, pub email: Option<String>,
pub key_encrypted: Option<String>, pub key_encrypted: Option<String>,
pub atype: i32, //EmergencyAccessType pub atype: i32, //EmergencyAccessType
@ -29,7 +29,7 @@ db_object! {
// Local methods // Local methods
impl EmergencyAccess { impl EmergencyAccess {
pub fn new(grantor_uuid: String, email: String, status: i32, atype: i32, wait_time_days: i32) -> Self { pub fn new(grantor_uuid: UserId, email: String, status: i32, atype: i32, wait_time_days: i32) -> Self {
let now = Utc::now().naive_utc(); let now = Utc::now().naive_utc();
Self { Self {
@ -82,7 +82,7 @@ impl EmergencyAccess {
} }
pub async fn to_json_grantee_details(&self, conn: &mut DbConn) -> Option<Value> { pub async fn to_json_grantee_details(&self, conn: &mut DbConn) -> Option<Value> {
let grantee_user = if let Some(grantee_uuid) = self.grantee_uuid.as_deref() { let grantee_user = if let Some(grantee_uuid) = &self.grantee_uuid {
User::find_by_uuid(grantee_uuid, conn).await.expect("Grantee user not found.") User::find_by_uuid(grantee_uuid, conn).await.expect("Grantee user not found.")
} else if let Some(email) = self.email.as_deref() { } else if let Some(email) = self.email.as_deref() {
match User::find_by_mail(email, conn).await { match User::find_by_mail(email, conn).await {
@ -211,7 +211,7 @@ impl EmergencyAccess {
}} }}
} }
pub async fn delete_all_by_user(user_uuid: &str, conn: &mut DbConn) -> EmptyResult { pub async fn delete_all_by_user(user_uuid: &UserId, conn: &mut DbConn) -> EmptyResult {
for ea in Self::find_all_by_grantor_uuid(user_uuid, conn).await { for ea in Self::find_all_by_grantor_uuid(user_uuid, conn).await {
ea.delete(conn).await?; ea.delete(conn).await?;
} }
@ -239,8 +239,8 @@ impl EmergencyAccess {
} }
pub async fn find_by_grantor_uuid_and_grantee_uuid_or_email( pub async fn find_by_grantor_uuid_and_grantee_uuid_or_email(
grantor_uuid: &str, grantor_uuid: &UserId,
grantee_uuid: &str, grantee_uuid: &UserId,
email: &str, email: &str,
conn: &mut DbConn, conn: &mut DbConn,
) -> Option<Self> { ) -> Option<Self> {
@ -262,7 +262,7 @@ impl EmergencyAccess {
}} }}
} }
pub async fn find_by_uuid_and_grantor_uuid(uuid: &str, grantor_uuid: &str, conn: &mut DbConn) -> Option<Self> { pub async fn find_by_uuid_and_grantor_uuid(uuid: &str, grantor_uuid: &UserId, conn: &mut DbConn) -> Option<Self> {
db_run! { conn: { db_run! { conn: {
emergency_access::table emergency_access::table
.filter(emergency_access::uuid.eq(uuid)) .filter(emergency_access::uuid.eq(uuid))
@ -272,7 +272,7 @@ impl EmergencyAccess {
}} }}
} }
pub async fn find_by_uuid_and_grantee_uuid(uuid: &str, grantee_uuid: &str, conn: &mut DbConn) -> Option<Self> { pub async fn find_by_uuid_and_grantee_uuid(uuid: &str, grantee_uuid: &UserId, conn: &mut DbConn) -> Option<Self> {
db_run! { conn: { db_run! { conn: {
emergency_access::table emergency_access::table
.filter(emergency_access::uuid.eq(uuid)) .filter(emergency_access::uuid.eq(uuid))
@ -292,7 +292,7 @@ impl EmergencyAccess {
}} }}
} }
pub async fn find_all_by_grantee_uuid(grantee_uuid: &str, conn: &mut DbConn) -> Vec<Self> { pub async fn find_all_by_grantee_uuid(grantee_uuid: &UserId, conn: &mut DbConn) -> Vec<Self> {
db_run! { conn: { db_run! { conn: {
emergency_access::table emergency_access::table
.filter(emergency_access::grantee_uuid.eq(grantee_uuid)) .filter(emergency_access::grantee_uuid.eq(grantee_uuid))
@ -319,7 +319,7 @@ impl EmergencyAccess {
}} }}
} }
pub async fn find_all_by_grantor_uuid(grantor_uuid: &str, conn: &mut DbConn) -> Vec<Self> { pub async fn find_all_by_grantor_uuid(grantor_uuid: &UserId, conn: &mut DbConn) -> Vec<Self> {
db_run! { conn: { db_run! { conn: {
emergency_access::table emergency_access::table
.filter(emergency_access::grantor_uuid.eq(grantor_uuid)) .filter(emergency_access::grantor_uuid.eq(grantor_uuid))
@ -327,7 +327,12 @@ impl EmergencyAccess {
}} }}
} }
pub async fn accept_invite(&mut self, grantee_uuid: &str, grantee_email: &str, conn: &mut DbConn) -> EmptyResult { pub async fn accept_invite(
&mut self,
grantee_uuid: &UserId,
grantee_email: &str,
conn: &mut DbConn,
) -> EmptyResult {
if self.email.is_none() || self.email.as_ref().unwrap() != grantee_email { if self.email.is_none() || self.email.as_ref().unwrap() != grantee_email {
err!("User email does not match invite."); err!("User email does not match invite.");
} }
@ -337,7 +342,7 @@ impl EmergencyAccess {
} }
self.status = EmergencyAccessStatus::Accepted as i32; self.status = EmergencyAccessStatus::Accepted as i32;
self.grantee_uuid = Some(String::from(grantee_uuid)); self.grantee_uuid = Some(grantee_uuid.clone());
self.email = None; self.email = None;
self.save(conn).await self.save(conn).await
} }

Datei anzeigen

@ -1,7 +1,7 @@
use crate::db::DbConn; use crate::db::DbConn;
use serde_json::Value; use serde_json::Value;
use super::OrganizationId; use super::{OrganizationId, UserId};
use crate::{api::EmptyResult, error::MapResult, CONFIG}; use crate::{api::EmptyResult, error::MapResult, CONFIG};
use chrono::{NaiveDateTime, TimeDelta, Utc}; use chrono::{NaiveDateTime, TimeDelta, Utc};
@ -18,7 +18,7 @@ db_object! {
pub struct Event { pub struct Event {
pub uuid: String, pub uuid: String,
pub event_type: i32, // EventType pub event_type: i32, // EventType
pub user_uuid: Option<String>, pub user_uuid: Option<UserId>,
pub org_uuid: Option<OrganizationId>, pub org_uuid: Option<OrganizationId>,
pub cipher_uuid: Option<String>, pub cipher_uuid: Option<String>,
pub collection_uuid: Option<String>, pub collection_uuid: Option<String>,

Datei anzeigen

@ -1,11 +1,11 @@
use super::User; use super::{User, UserId};
db_object! { db_object! {
#[derive(Identifiable, Queryable, Insertable)] #[derive(Identifiable, Queryable, Insertable)]
#[diesel(table_name = favorites)] #[diesel(table_name = favorites)]
#[diesel(primary_key(user_uuid, cipher_uuid))] #[diesel(primary_key(user_uuid, cipher_uuid))]
pub struct Favorite { pub struct Favorite {
pub user_uuid: String, pub user_uuid: UserId,
pub cipher_uuid: String, pub cipher_uuid: String,
} }
} }
@ -17,7 +17,7 @@ use crate::error::MapResult;
impl Favorite { impl Favorite {
// Returns whether the specified cipher is a favorite of the specified user. // Returns whether the specified cipher is a favorite of the specified user.
pub async fn is_favorite(cipher_uuid: &str, user_uuid: &str, conn: &mut DbConn) -> bool { pub async fn is_favorite(cipher_uuid: &str, user_uuid: &UserId, conn: &mut DbConn) -> bool {
db_run! { conn: { db_run! { conn: {
let query = favorites::table let query = favorites::table
.filter(favorites::cipher_uuid.eq(cipher_uuid)) .filter(favorites::cipher_uuid.eq(cipher_uuid))
@ -29,7 +29,7 @@ impl Favorite {
} }
// Sets whether the specified cipher is a favorite of the specified user. // Sets whether the specified cipher is a favorite of the specified user.
pub async fn set_favorite(favorite: bool, cipher_uuid: &str, user_uuid: &str, conn: &mut DbConn) -> EmptyResult { pub async fn set_favorite(favorite: bool, cipher_uuid: &str, user_uuid: &UserId, conn: &mut DbConn) -> EmptyResult {
let (old, new) = (Self::is_favorite(cipher_uuid, user_uuid, conn).await, favorite); let (old, new) = (Self::is_favorite(cipher_uuid, user_uuid, conn).await, favorite);
match (old, new) { match (old, new) {
(false, true) => { (false, true) => {
@ -71,7 +71,7 @@ impl Favorite {
} }
// Delete all favorite entries associated with the specified user. // Delete all favorite entries associated with the specified user.
pub async fn delete_all_by_user(user_uuid: &str, conn: &mut DbConn) -> EmptyResult { pub async fn delete_all_by_user(user_uuid: &UserId, conn: &mut DbConn) -> EmptyResult {
db_run! { conn: { db_run! { conn: {
diesel::delete(favorites::table.filter(favorites::user_uuid.eq(user_uuid))) diesel::delete(favorites::table.filter(favorites::user_uuid.eq(user_uuid)))
.execute(conn) .execute(conn)
@ -81,7 +81,7 @@ impl Favorite {
/// Return a vec with (cipher_uuid) this will only contain favorite flagged ciphers /// Return a vec with (cipher_uuid) this will only contain favorite flagged ciphers
/// This is used during a full sync so we only need one query for all favorite cipher matches. /// This is used during a full sync so we only need one query for all favorite cipher matches.
pub async fn get_all_cipher_uuid_by_user(user_uuid: &str, conn: &mut DbConn) -> Vec<String> { pub async fn get_all_cipher_uuid_by_user(user_uuid: &UserId, conn: &mut DbConn) -> Vec<String> {
db_run! { conn: { db_run! { conn: {
favorites::table favorites::table
.filter(favorites::user_uuid.eq(user_uuid)) .filter(favorites::user_uuid.eq(user_uuid))

Datei anzeigen

@ -1,7 +1,7 @@
use chrono::{NaiveDateTime, Utc}; use chrono::{NaiveDateTime, Utc};
use serde_json::Value; use serde_json::Value;
use super::User; use super::{User, UserId};
db_object! { db_object! {
#[derive(Identifiable, Queryable, Insertable, AsChangeset)] #[derive(Identifiable, Queryable, Insertable, AsChangeset)]
@ -11,7 +11,7 @@ db_object! {
pub uuid: String, pub uuid: String,
pub created_at: NaiveDateTime, pub created_at: NaiveDateTime,
pub updated_at: NaiveDateTime, pub updated_at: NaiveDateTime,
pub user_uuid: String, pub user_uuid: UserId,
pub name: String, pub name: String,
} }
@ -26,7 +26,7 @@ db_object! {
/// Local methods /// Local methods
impl Folder { impl Folder {
pub fn new(user_uuid: String, name: String) -> Self { pub fn new(user_uuid: UserId, name: String) -> Self {
let now = Utc::now().naive_utc(); let now = Utc::now().naive_utc();
Self { Self {
@ -113,14 +113,14 @@ impl Folder {
}} }}
} }
pub async fn delete_all_by_user(user_uuid: &str, conn: &mut DbConn) -> EmptyResult { pub async fn delete_all_by_user(user_uuid: &UserId, conn: &mut DbConn) -> EmptyResult {
for folder in Self::find_by_user(user_uuid, conn).await { for folder in Self::find_by_user(user_uuid, conn).await {
folder.delete(conn).await?; folder.delete(conn).await?;
} }
Ok(()) Ok(())
} }
pub async fn find_by_uuid_and_user(uuid: &str, user_uuid: &str, conn: &mut DbConn) -> Option<Self> { pub async fn find_by_uuid_and_user(uuid: &str, user_uuid: &UserId, conn: &mut DbConn) -> Option<Self> {
db_run! { conn: { db_run! { conn: {
folders::table folders::table
.filter(folders::uuid.eq(uuid)) .filter(folders::uuid.eq(uuid))
@ -131,7 +131,7 @@ impl Folder {
}} }}
} }
pub async fn find_by_user(user_uuid: &str, conn: &mut DbConn) -> Vec<Self> { pub async fn find_by_user(user_uuid: &UserId, conn: &mut DbConn) -> Vec<Self> {
db_run! { conn: { db_run! { conn: {
folders::table folders::table
.filter(folders::user_uuid.eq(user_uuid)) .filter(folders::user_uuid.eq(user_uuid))
@ -216,7 +216,7 @@ impl FolderCipher {
/// Return a vec with (cipher_uuid, folder_uuid) /// Return a vec with (cipher_uuid, folder_uuid)
/// This is used during a full sync so we only need one query for all folder matches. /// This is used during a full sync so we only need one query for all folder matches.
pub async fn find_by_user(user_uuid: &str, conn: &mut DbConn) -> Vec<(String, String)> { pub async fn find_by_user(user_uuid: &UserId, conn: &mut DbConn) -> Vec<(String, String)> {
db_run! { conn: { db_run! { conn: {
folders_ciphers::table folders_ciphers::table
.inner_join(folders::table) .inner_join(folders::table)

Datei anzeigen

@ -1,4 +1,4 @@
use super::{Membership, MembershipId, OrganizationId, User}; use super::{Membership, MembershipId, OrganizationId, User, UserId};
use crate::api::EmptyResult; use crate::api::EmptyResult;
use crate::db::DbConn; use crate::db::DbConn;
use crate::error::MapResult; use crate::error::MapResult;
@ -222,7 +222,7 @@ impl Group {
}} }}
} }
//Returns all organizations the user has full access to //Returns all organizations the user has full access to
pub async fn get_orgs_by_user_with_full_access(user_uuid: &str, conn: &mut DbConn) -> Vec<OrganizationId> { pub async fn get_orgs_by_user_with_full_access(user_uuid: &UserId, conn: &mut DbConn) -> Vec<OrganizationId> {
db_run! { conn: { db_run! { conn: {
groups_users::table groups_users::table
.inner_join(users_organizations::table.on( .inner_join(users_organizations::table.on(
@ -240,7 +240,7 @@ impl Group {
}} }}
} }
pub async fn is_in_full_access_group(user_uuid: &str, org_uuid: &OrganizationId, conn: &mut DbConn) -> bool { pub async fn is_in_full_access_group(user_uuid: &UserId, org_uuid: &OrganizationId, conn: &mut DbConn) -> bool {
db_run! { conn: { db_run! { conn: {
groups::table groups::table
.inner_join(groups_users::table.on( .inner_join(groups_users::table.on(
@ -353,7 +353,7 @@ impl CollectionGroup {
}} }}
} }
pub async fn find_by_user(user_uuid: &str, conn: &mut DbConn) -> Vec<Self> { pub async fn find_by_user(user_uuid: &UserId, conn: &mut DbConn) -> Vec<Self> {
db_run! { conn: { db_run! { conn: {
collections_groups::table collections_groups::table
.inner_join(groups_users::table.on( .inner_join(groups_users::table.on(

Datei anzeigen

@ -34,4 +34,4 @@ pub use self::send::{Send, SendType};
pub use self::two_factor::{TwoFactor, TwoFactorType}; pub use self::two_factor::{TwoFactor, TwoFactorType};
pub use self::two_factor_duo_context::TwoFactorDuoContext; pub use self::two_factor_duo_context::TwoFactorDuoContext;
pub use self::two_factor_incomplete::TwoFactorIncomplete; pub use self::two_factor_incomplete::TwoFactorIncomplete;
pub use self::user::{Invitation, User, UserKdfType, UserStampException}; pub use self::user::{Invitation, User, UserId, UserKdfType, UserStampException};

Datei anzeigen

@ -5,7 +5,7 @@ use crate::api::EmptyResult;
use crate::db::DbConn; use crate::db::DbConn;
use crate::error::MapResult; use crate::error::MapResult;
use super::{Membership, MembershipId, MembershipStatus, MembershipType, OrganizationId, TwoFactor}; use super::{Membership, MembershipId, MembershipStatus, MembershipType, OrganizationId, TwoFactor, UserId};
db_object! { db_object! {
#[derive(Identifiable, Queryable, Insertable, AsChangeset)] #[derive(Identifiable, Queryable, Insertable, AsChangeset)]
@ -152,7 +152,7 @@ impl OrgPolicy {
}} }}
} }
pub async fn find_confirmed_by_user(user_uuid: &str, conn: &mut DbConn) -> Vec<Self> { pub async fn find_confirmed_by_user(user_uuid: &UserId, conn: &mut DbConn) -> Vec<Self> {
db_run! { conn: { db_run! { conn: {
org_policies::table org_policies::table
.inner_join( .inner_join(
@ -194,7 +194,7 @@ impl OrgPolicy {
} }
pub async fn find_accepted_and_confirmed_by_user_and_active_policy( pub async fn find_accepted_and_confirmed_by_user_and_active_policy(
user_uuid: &str, user_uuid: &UserId,
policy_type: OrgPolicyType, policy_type: OrgPolicyType,
conn: &mut DbConn, conn: &mut DbConn,
) -> Vec<Self> { ) -> Vec<Self> {
@ -221,7 +221,7 @@ impl OrgPolicy {
} }
pub async fn find_confirmed_by_user_and_active_policy( pub async fn find_confirmed_by_user_and_active_policy(
user_uuid: &str, user_uuid: &UserId,
policy_type: OrgPolicyType, policy_type: OrgPolicyType,
conn: &mut DbConn, conn: &mut DbConn,
) -> Vec<Self> { ) -> Vec<Self> {
@ -248,7 +248,7 @@ impl OrgPolicy {
/// and the user is not an owner or admin of that org. This is only useful for checking /// and the user is not an owner or admin of that org. This is only useful for checking
/// applicability of policy types that have these particular semantics. /// applicability of policy types that have these particular semantics.
pub async fn is_applicable_to_user( pub async fn is_applicable_to_user(
user_uuid: &str, user_uuid: &UserId,
policy_type: OrgPolicyType, policy_type: OrgPolicyType,
exclude_org_uuid: Option<&OrganizationId>, exclude_org_uuid: Option<&OrganizationId>,
conn: &mut DbConn, conn: &mut DbConn,
@ -271,7 +271,7 @@ impl OrgPolicy {
} }
pub async fn is_user_allowed( pub async fn is_user_allowed(
user_uuid: &str, user_uuid: &UserId,
org_uuid: &OrganizationId, org_uuid: &OrganizationId,
exclude_current_org: bool, exclude_current_org: bool,
conn: &mut DbConn, conn: &mut DbConn,
@ -316,7 +316,7 @@ impl OrgPolicy {
/// Returns true if the user belongs to an org that has enabled the `DisableHideEmail` /// Returns true if the user belongs to an org that has enabled the `DisableHideEmail`
/// option of the `Send Options` policy, and the user is not an owner or admin of that org. /// option of the `Send Options` policy, and the user is not an owner or admin of that org.
pub async fn is_hide_email_disabled(user_uuid: &str, conn: &mut DbConn) -> bool { pub async fn is_hide_email_disabled(user_uuid: &UserId, conn: &mut DbConn) -> bool {
for policy in for policy in
OrgPolicy::find_confirmed_by_user_and_active_policy(user_uuid, OrgPolicyType::SendOptions, conn).await OrgPolicy::find_confirmed_by_user_and_active_policy(user_uuid, OrgPolicyType::SendOptions, conn).await
{ {

Datei anzeigen

@ -10,7 +10,7 @@ use std::{
ops::Deref, ops::Deref,
}; };
use super::{CollectionUser, Group, GroupUser, OrgPolicy, OrgPolicyType, TwoFactor, User}; use super::{CollectionUser, Group, GroupUser, OrgPolicy, OrgPolicyType, TwoFactor, User, UserId};
use crate::db::models::{Collection, CollectionGroup}; use crate::db::models::{Collection, CollectionGroup};
use crate::CONFIG; use crate::CONFIG;
@ -31,7 +31,7 @@ db_object! {
#[diesel(primary_key(uuid))] #[diesel(primary_key(uuid))]
pub struct Membership { pub struct Membership {
pub uuid: MembershipId, pub uuid: MembershipId,
pub user_uuid: String, pub user_uuid: UserId,
pub org_uuid: OrganizationId, pub org_uuid: OrganizationId,
pub access_all: bool, pub access_all: bool,
@ -204,7 +204,7 @@ impl Organization {
static ACTIVATE_REVOKE_DIFF: i32 = 128; static ACTIVATE_REVOKE_DIFF: i32 = 128;
impl Membership { impl Membership {
pub fn new(user_uuid: String, org_uuid: OrganizationId) -> Self { pub fn new(user_uuid: UserId, org_uuid: OrganizationId) -> Self {
Self { Self {
uuid: MembershipId(crate::util::get_uuid()), uuid: MembershipId(crate::util::get_uuid()),
@ -666,7 +666,7 @@ impl Membership {
Ok(()) Ok(())
} }
pub async fn delete_all_by_user(user_uuid: &str, conn: &mut DbConn) -> EmptyResult { pub async fn delete_all_by_user(user_uuid: &UserId, conn: &mut DbConn) -> EmptyResult {
for member in Self::find_any_state_by_user(user_uuid, conn).await { for member in Self::find_any_state_by_user(user_uuid, conn).await {
member.delete(conn).await?; member.delete(conn).await?;
} }
@ -722,7 +722,7 @@ impl Membership {
}} }}
} }
pub async fn find_confirmed_by_user(user_uuid: &str, conn: &mut DbConn) -> Vec<Self> { pub async fn find_confirmed_by_user(user_uuid: &UserId, conn: &mut DbConn) -> Vec<Self> {
db_run! { conn: { db_run! { conn: {
users_organizations::table users_organizations::table
.filter(users_organizations::user_uuid.eq(user_uuid)) .filter(users_organizations::user_uuid.eq(user_uuid))
@ -732,7 +732,7 @@ impl Membership {
}} }}
} }
pub async fn find_invited_by_user(user_uuid: &str, conn: &mut DbConn) -> Vec<Self> { pub async fn find_invited_by_user(user_uuid: &UserId, conn: &mut DbConn) -> Vec<Self> {
db_run! { conn: { db_run! { conn: {
users_organizations::table users_organizations::table
.filter(users_organizations::user_uuid.eq(user_uuid)) .filter(users_organizations::user_uuid.eq(user_uuid))
@ -742,7 +742,7 @@ impl Membership {
}} }}
} }
pub async fn find_any_state_by_user(user_uuid: &str, conn: &mut DbConn) -> Vec<Self> { pub async fn find_any_state_by_user(user_uuid: &UserId, conn: &mut DbConn) -> Vec<Self> {
db_run! { conn: { db_run! { conn: {
users_organizations::table users_organizations::table
.filter(users_organizations::user_uuid.eq(user_uuid)) .filter(users_organizations::user_uuid.eq(user_uuid))
@ -751,7 +751,7 @@ impl Membership {
}} }}
} }
pub async fn count_accepted_and_confirmed_by_user(user_uuid: &str, conn: &mut DbConn) -> i64 { pub async fn count_accepted_and_confirmed_by_user(user_uuid: &UserId, conn: &mut DbConn) -> i64 {
db_run! { conn: { db_run! { conn: {
users_organizations::table users_organizations::table
.filter(users_organizations::user_uuid.eq(user_uuid)) .filter(users_organizations::user_uuid.eq(user_uuid))
@ -822,7 +822,11 @@ impl Membership {
}} }}
} }
pub async fn find_by_user_and_org(user_uuid: &str, org_uuid: &OrganizationId, conn: &mut DbConn) -> Option<Self> { pub async fn find_by_user_and_org(
user_uuid: &UserId,
org_uuid: &OrganizationId,
conn: &mut DbConn,
) -> Option<Self> {
db_run! { conn: { db_run! { conn: {
users_organizations::table users_organizations::table
.filter(users_organizations::user_uuid.eq(user_uuid)) .filter(users_organizations::user_uuid.eq(user_uuid))
@ -833,7 +837,7 @@ impl Membership {
} }
pub async fn find_confirmed_by_user_and_org( pub async fn find_confirmed_by_user_and_org(
user_uuid: &str, user_uuid: &UserId,
org_uuid: &OrganizationId, org_uuid: &OrganizationId,
conn: &mut DbConn, conn: &mut DbConn,
) -> Option<Self> { ) -> Option<Self> {
@ -849,7 +853,7 @@ impl Membership {
}} }}
} }
pub async fn find_by_user(user_uuid: &str, conn: &mut DbConn) -> Vec<Self> { pub async fn find_by_user(user_uuid: &UserId, conn: &mut DbConn) -> Vec<Self> {
db_run! { conn: { db_run! { conn: {
users_organizations::table users_organizations::table
.filter(users_organizations::user_uuid.eq(user_uuid)) .filter(users_organizations::user_uuid.eq(user_uuid))
@ -858,7 +862,7 @@ impl Membership {
}} }}
} }
pub async fn get_orgs_by_user(user_uuid: &str, conn: &mut DbConn) -> Vec<OrganizationId> { pub async fn get_orgs_by_user(user_uuid: &UserId, conn: &mut DbConn) -> Vec<OrganizationId> {
db_run! { conn: { db_run! { conn: {
users_organizations::table users_organizations::table
.filter(users_organizations::user_uuid.eq(user_uuid)) .filter(users_organizations::user_uuid.eq(user_uuid))
@ -868,7 +872,11 @@ impl Membership {
}} }}
} }
pub async fn find_by_user_and_policy(user_uuid: &str, policy_type: OrgPolicyType, conn: &mut DbConn) -> Vec<Self> { pub async fn find_by_user_and_policy(
user_uuid: &UserId,
policy_type: OrgPolicyType,
conn: &mut DbConn,
) -> Vec<Self> {
db_run! { conn: { db_run! { conn: {
users_organizations::table users_organizations::table
.inner_join( .inner_join(
@ -940,7 +948,7 @@ impl Membership {
}} }}
} }
pub async fn user_has_ge_admin_access_to_cipher(user_uuid: &str, cipher_uuid: &str, conn: &mut DbConn) -> bool { pub async fn user_has_ge_admin_access_to_cipher(user_uuid: &UserId, cipher_uuid: &str, conn: &mut DbConn) -> bool {
db_run! { conn: { db_run! { conn: {
users_organizations::table users_organizations::table
.inner_join(ciphers::table.on(ciphers::uuid.eq(cipher_uuid).and(ciphers::organization_uuid.eq(users_organizations::org_uuid.nullable())))) .inner_join(ciphers::table.on(ciphers::uuid.eq(cipher_uuid).and(ciphers::organization_uuid.eq(users_organizations::org_uuid.nullable()))))

Datei anzeigen

@ -3,7 +3,7 @@ use serde_json::Value;
use crate::util::LowerCase; use crate::util::LowerCase;
use super::{OrganizationId, User}; use super::{OrganizationId, User, UserId};
db_object! { db_object! {
#[derive(Identifiable, Queryable, Insertable, AsChangeset)] #[derive(Identifiable, Queryable, Insertable, AsChangeset)]
@ -13,7 +13,7 @@ db_object! {
pub struct Send { pub struct Send {
pub uuid: String, pub uuid: String,
pub user_uuid: Option<String>, pub user_uuid: Option<UserId>,
pub organization_uuid: Option<OrganizationId>, pub organization_uuid: Option<OrganizationId>,
pub name: String, pub name: String,
@ -242,7 +242,7 @@ impl Send {
} }
} }
pub async fn update_users_revision(&self, conn: &mut DbConn) -> Vec<String> { pub async fn update_users_revision(&self, conn: &mut DbConn) -> Vec<UserId> {
let mut user_uuids = Vec::new(); let mut user_uuids = Vec::new();
match &self.user_uuid { match &self.user_uuid {
Some(user_uuid) => { Some(user_uuid) => {
@ -256,7 +256,7 @@ impl Send {
user_uuids user_uuids
} }
pub async fn delete_all_by_user(user_uuid: &str, conn: &mut DbConn) -> EmptyResult { pub async fn delete_all_by_user(user_uuid: &UserId, conn: &mut DbConn) -> EmptyResult {
for send in Self::find_by_user(user_uuid, conn).await { for send in Self::find_by_user(user_uuid, conn).await {
send.delete(conn).await?; send.delete(conn).await?;
} }
@ -289,7 +289,7 @@ impl Send {
}} }}
} }
pub async fn find_by_uuid_and_user(uuid: &str, user_uuid: &str, conn: &mut DbConn) -> Option<Self> { pub async fn find_by_uuid_and_user(uuid: &str, user_uuid: &UserId, conn: &mut DbConn) -> Option<Self> {
db_run! {conn: { db_run! {conn: {
sends::table sends::table
.filter(sends::uuid.eq(uuid)) .filter(sends::uuid.eq(uuid))
@ -300,7 +300,7 @@ impl Send {
}} }}
} }
pub async fn find_by_user(user_uuid: &str, conn: &mut DbConn) -> Vec<Self> { pub async fn find_by_user(user_uuid: &UserId, conn: &mut DbConn) -> Vec<Self> {
db_run! {conn: { db_run! {conn: {
sends::table sends::table
.filter(sends::user_uuid.eq(user_uuid)) .filter(sends::user_uuid.eq(user_uuid))
@ -308,7 +308,7 @@ impl Send {
}} }}
} }
pub async fn size_by_user(user_uuid: &str, conn: &mut DbConn) -> Option<i64> { pub async fn size_by_user(user_uuid: &UserId, conn: &mut DbConn) -> Option<i64> {
let sends = Self::find_by_user(user_uuid, conn).await; let sends = Self::find_by_user(user_uuid, conn).await;
#[derive(serde::Deserialize)] #[derive(serde::Deserialize)]

Datei anzeigen

@ -1,5 +1,6 @@
use serde_json::Value; use serde_json::Value;
use super::UserId;
use crate::{api::EmptyResult, db::DbConn, error::MapResult}; use crate::{api::EmptyResult, db::DbConn, error::MapResult};
db_object! { db_object! {
@ -8,7 +9,7 @@ db_object! {
#[diesel(primary_key(uuid))] #[diesel(primary_key(uuid))]
pub struct TwoFactor { pub struct TwoFactor {
pub uuid: String, pub uuid: String,
pub user_uuid: String, pub user_uuid: UserId,
pub atype: i32, pub atype: i32,
pub enabled: bool, pub enabled: bool,
pub data: String, pub data: String,
@ -41,7 +42,7 @@ pub enum TwoFactorType {
/// Local methods /// Local methods
impl TwoFactor { impl TwoFactor {
pub fn new(user_uuid: String, atype: TwoFactorType, data: String) -> Self { pub fn new(user_uuid: UserId, atype: TwoFactorType, data: String) -> Self {
Self { Self {
uuid: crate::util::get_uuid(), uuid: crate::util::get_uuid(),
user_uuid, user_uuid,
@ -118,7 +119,7 @@ impl TwoFactor {
}} }}
} }
pub async fn find_by_user(user_uuid: &str, conn: &mut DbConn) -> Vec<Self> { pub async fn find_by_user(user_uuid: &UserId, conn: &mut DbConn) -> Vec<Self> {
db_run! { conn: { db_run! { conn: {
twofactor::table twofactor::table
.filter(twofactor::user_uuid.eq(user_uuid)) .filter(twofactor::user_uuid.eq(user_uuid))
@ -129,7 +130,7 @@ impl TwoFactor {
}} }}
} }
pub async fn find_by_user_and_type(user_uuid: &str, atype: i32, conn: &mut DbConn) -> Option<Self> { pub async fn find_by_user_and_type(user_uuid: &UserId, atype: i32, conn: &mut DbConn) -> Option<Self> {
db_run! { conn: { db_run! { conn: {
twofactor::table twofactor::table
.filter(twofactor::user_uuid.eq(user_uuid)) .filter(twofactor::user_uuid.eq(user_uuid))
@ -140,7 +141,7 @@ impl TwoFactor {
}} }}
} }
pub async fn delete_all_by_user(user_uuid: &str, conn: &mut DbConn) -> EmptyResult { pub async fn delete_all_by_user(user_uuid: &UserId, conn: &mut DbConn) -> EmptyResult {
db_run! { conn: { db_run! { conn: {
diesel::delete(twofactor::table.filter(twofactor::user_uuid.eq(user_uuid))) diesel::delete(twofactor::table.filter(twofactor::user_uuid.eq(user_uuid)))
.execute(conn) .execute(conn)

Datei anzeigen

@ -1,13 +1,19 @@
use chrono::{NaiveDateTime, Utc}; use chrono::{NaiveDateTime, Utc};
use crate::{api::EmptyResult, auth::ClientIp, db::DbConn, error::MapResult, CONFIG}; use crate::{
api::EmptyResult,
auth::ClientIp,
db::{models::UserId, DbConn},
error::MapResult,
CONFIG,
};
db_object! { db_object! {
#[derive(Identifiable, Queryable, Insertable, AsChangeset)] #[derive(Identifiable, Queryable, Insertable, AsChangeset)]
#[diesel(table_name = twofactor_incomplete)] #[diesel(table_name = twofactor_incomplete)]
#[diesel(primary_key(user_uuid, device_uuid))] #[diesel(primary_key(user_uuid, device_uuid))]
pub struct TwoFactorIncomplete { pub struct TwoFactorIncomplete {
pub user_uuid: String, pub user_uuid: UserId,
// This device UUID is simply what's claimed by the device. It doesn't // This device UUID is simply what's claimed by the device. It doesn't
// necessarily correspond to any UUID in the devices table, since a device // necessarily correspond to any UUID in the devices table, since a device
// must complete 2FA login before being added into the devices table. // must complete 2FA login before being added into the devices table.
@ -21,7 +27,7 @@ db_object! {
impl TwoFactorIncomplete { impl TwoFactorIncomplete {
pub async fn mark_incomplete( pub async fn mark_incomplete(
user_uuid: &str, user_uuid: &UserId,
device_uuid: &str, device_uuid: &str,
device_name: &str, device_name: &str,
device_type: i32, device_type: i32,
@ -55,7 +61,7 @@ impl TwoFactorIncomplete {
}} }}
} }
pub async fn mark_complete(user_uuid: &str, device_uuid: &str, conn: &mut DbConn) -> EmptyResult { pub async fn mark_complete(user_uuid: &UserId, device_uuid: &str, conn: &mut DbConn) -> EmptyResult {
if CONFIG.incomplete_2fa_time_limit() <= 0 || !CONFIG.mail_enabled() { if CONFIG.incomplete_2fa_time_limit() <= 0 || !CONFIG.mail_enabled() {
return Ok(()); return Ok(());
} }
@ -63,7 +69,7 @@ impl TwoFactorIncomplete {
Self::delete_by_user_and_device(user_uuid, device_uuid, conn).await Self::delete_by_user_and_device(user_uuid, device_uuid, conn).await
} }
pub async fn find_by_user_and_device(user_uuid: &str, device_uuid: &str, conn: &mut DbConn) -> Option<Self> { pub async fn find_by_user_and_device(user_uuid: &UserId, device_uuid: &str, conn: &mut DbConn) -> Option<Self> {
db_run! { conn: { db_run! { conn: {
twofactor_incomplete::table twofactor_incomplete::table
.filter(twofactor_incomplete::user_uuid.eq(user_uuid)) .filter(twofactor_incomplete::user_uuid.eq(user_uuid))
@ -88,7 +94,7 @@ impl TwoFactorIncomplete {
Self::delete_by_user_and_device(&self.user_uuid, &self.device_uuid, conn).await Self::delete_by_user_and_device(&self.user_uuid, &self.device_uuid, conn).await
} }
pub async fn delete_by_user_and_device(user_uuid: &str, device_uuid: &str, conn: &mut DbConn) -> EmptyResult { pub async fn delete_by_user_and_device(user_uuid: &UserId, device_uuid: &str, conn: &mut DbConn) -> EmptyResult {
db_run! { conn: { db_run! { conn: {
diesel::delete(twofactor_incomplete::table diesel::delete(twofactor_incomplete::table
.filter(twofactor_incomplete::user_uuid.eq(user_uuid)) .filter(twofactor_incomplete::user_uuid.eq(user_uuid))
@ -98,7 +104,7 @@ impl TwoFactorIncomplete {
}} }}
} }
pub async fn delete_all_by_user(user_uuid: &str, conn: &mut DbConn) -> EmptyResult { pub async fn delete_all_by_user(user_uuid: &UserId, conn: &mut DbConn) -> EmptyResult {
db_run! { conn: { db_run! { conn: {
diesel::delete(twofactor_incomplete::table.filter(twofactor_incomplete::user_uuid.eq(user_uuid))) diesel::delete(twofactor_incomplete::table.filter(twofactor_incomplete::user_uuid.eq(user_uuid)))
.execute(conn) .execute(conn)

Datei anzeigen

@ -1,9 +1,23 @@
use crate::util::{format_date, get_uuid, retry};
use chrono::{NaiveDateTime, TimeDelta, Utc}; use chrono::{NaiveDateTime, TimeDelta, Utc};
use rocket::request::FromParam;
use serde_json::Value; use serde_json::Value;
use std::{
borrow::Borrow,
fmt::{Display, Formatter},
ops::Deref,
};
use crate::crypto; use super::{
use crate::CONFIG; Cipher, Device, EmergencyAccess, Favorite, Folder, Membership, MembershipType, TwoFactor, TwoFactorIncomplete,
};
use crate::{
api::EmptyResult,
crypto,
db::DbConn,
error::MapResult,
util::{format_date, get_uuid, retry},
CONFIG,
};
db_object! { db_object! {
#[derive(Identifiable, Queryable, Insertable, AsChangeset)] #[derive(Identifiable, Queryable, Insertable, AsChangeset)]
@ -11,7 +25,7 @@ db_object! {
#[diesel(treat_none_as_null = true)] #[diesel(treat_none_as_null = true)]
#[diesel(primary_key(uuid))] #[diesel(primary_key(uuid))]
pub struct User { pub struct User {
pub uuid: String, pub uuid: UserId,
pub enabled: bool, pub enabled: bool,
pub created_at: NaiveDateTime, pub created_at: NaiveDateTime,
pub updated_at: NaiveDateTime, pub updated_at: NaiveDateTime,
@ -91,7 +105,7 @@ impl User {
let email = email.to_lowercase(); let email = email.to_lowercase();
Self { Self {
uuid: get_uuid(), uuid: UserId(get_uuid()),
enabled: true, enabled: true,
created_at: now, created_at: now,
updated_at: now, updated_at: now,
@ -214,14 +228,6 @@ impl User {
} }
} }
use super::{
Cipher, Device, EmergencyAccess, Favorite, Folder, Membership, MembershipType, Send, TwoFactor, TwoFactorIncomplete,
};
use crate::db::DbConn;
use crate::api::EmptyResult;
use crate::error::MapResult;
/// Database methods /// Database methods
impl User { impl User {
pub async fn to_json(&self, conn: &mut DbConn) -> Value { pub async fn to_json(&self, conn: &mut DbConn) -> Value {
@ -311,7 +317,7 @@ impl User {
} }
} }
Send::delete_all_by_user(&self.uuid, conn).await?; super::Send::delete_all_by_user(&self.uuid, conn).await?;
EmergencyAccess::delete_all_by_user(&self.uuid, conn).await?; EmergencyAccess::delete_all_by_user(&self.uuid, conn).await?;
EmergencyAccess::delete_all_by_grantee_email(&self.email, conn).await?; EmergencyAccess::delete_all_by_grantee_email(&self.email, conn).await?;
Membership::delete_all_by_user(&self.uuid, conn).await?; Membership::delete_all_by_user(&self.uuid, conn).await?;
@ -330,7 +336,7 @@ impl User {
}} }}
} }
pub async fn update_uuid_revision(uuid: &str, conn: &mut DbConn) { pub async fn update_uuid_revision(uuid: &UserId, conn: &mut DbConn) {
if let Err(e) = Self::_update_revision(uuid, &Utc::now().naive_utc(), conn).await { if let Err(e) = Self::_update_revision(uuid, &Utc::now().naive_utc(), conn).await {
warn!("Failed to update revision for {}: {:#?}", uuid, e); warn!("Failed to update revision for {}: {:#?}", uuid, e);
} }
@ -355,7 +361,7 @@ impl User {
Self::_update_revision(&self.uuid, &self.updated_at, conn).await Self::_update_revision(&self.uuid, &self.updated_at, conn).await
} }
async fn _update_revision(uuid: &str, date: &NaiveDateTime, conn: &mut DbConn) -> EmptyResult { async fn _update_revision(uuid: &UserId, date: &NaiveDateTime, conn: &mut DbConn) -> EmptyResult {
db_run! {conn: { db_run! {conn: {
retry(|| { retry(|| {
diesel::update(users::table.filter(users::uuid.eq(uuid))) diesel::update(users::table.filter(users::uuid.eq(uuid)))
@ -377,7 +383,7 @@ impl User {
}} }}
} }
pub async fn find_by_uuid(uuid: &str, conn: &mut DbConn) -> Option<Self> { pub async fn find_by_uuid(uuid: &UserId, conn: &mut DbConn) -> Option<Self> {
db_run! {conn: { db_run! {conn: {
users::table.filter(users::uuid.eq(uuid)).first::<UserDb>(conn).ok().from_db() users::table.filter(users::uuid.eq(uuid)).first::<UserDb>(conn).ok().from_db()
}} }}
@ -456,3 +462,51 @@ impl Invitation {
} }
} }
} }
#[derive(DieselNewType, FromForm, Clone, Debug, Hash, PartialEq, Eq, Serialize, Deserialize)]
pub struct UserId(String);
impl AsRef<str> for UserId {
fn as_ref(&self) -> &str {
&self.0
}
}
impl Deref for UserId {
type Target = str;
fn deref(&self) -> &Self::Target {
&self.0
}
}
impl Borrow<str> for UserId {
fn borrow(&self) -> &str {
&self.0
}
}
impl Display for UserId {
fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
write!(f, "{}", self.0)
}
}
impl From<String> for UserId {
fn from(raw: String) -> Self {
Self(raw)
}
}
impl<'r> FromParam<'r> for UserId {
type Error = ();
#[inline(always)]
fn from_param(param: &'r str) -> Result<Self, Self::Error> {
if param.chars().all(|c| matches!(c, 'a'..='z' | 'A'..='Z' |'0'..='9' | '-')) {
Ok(Self(param.to_string()))
} else {
Err(())
}
}
}

Datei anzeigen

@ -17,7 +17,7 @@ use crate::{
encode_jwt, generate_delete_claims, generate_emergency_access_invite_claims, generate_invite_claims, encode_jwt, generate_delete_claims, generate_emergency_access_invite_claims, generate_invite_claims,
generate_verify_email_claims, generate_verify_email_claims,
}, },
db::models::{Device, DeviceType, MembershipId, OrganizationId, User}, db::models::{Device, DeviceType, MembershipId, OrganizationId, User, UserId},
error::Error, error::Error,
CONFIG, CONFIG,
}; };
@ -166,8 +166,8 @@ pub async fn send_password_hint(address: &str, hint: Option<String>) -> EmptyRes
send_email(address, &subject, body_html, body_text).await send_email(address, &subject, body_html, body_text).await
} }
pub async fn send_delete_account(address: &str, uuid: &str) -> EmptyResult { pub async fn send_delete_account(address: &str, user_id: &UserId) -> EmptyResult {
let claims = generate_delete_claims(uuid.to_string()); let claims = generate_delete_claims(user_id.to_string());
let delete_token = encode_jwt(&claims); let delete_token = encode_jwt(&claims);
let (subject, body_html, body_text) = get_text( let (subject, body_html, body_text) = get_text(
@ -175,7 +175,7 @@ pub async fn send_delete_account(address: &str, uuid: &str) -> EmptyResult {
json!({ json!({
"url": CONFIG.domain(), "url": CONFIG.domain(),
"img_src": CONFIG._smtp_img_src(), "img_src": CONFIG._smtp_img_src(),
"user_id": uuid, "user_id": user_id,
"email": percent_encode(address.as_bytes(), NON_ALPHANUMERIC).to_string(), "email": percent_encode(address.as_bytes(), NON_ALPHANUMERIC).to_string(),
"token": delete_token, "token": delete_token,
}), }),
@ -184,8 +184,8 @@ pub async fn send_delete_account(address: &str, uuid: &str) -> EmptyResult {
send_email(address, &subject, body_html, body_text).await send_email(address, &subject, body_html, body_text).await
} }
pub async fn send_verify_email(address: &str, uuid: &str) -> EmptyResult { pub async fn send_verify_email(address: &str, user_id: &UserId) -> EmptyResult {
let claims = generate_verify_email_claims(uuid.to_string()); let claims = generate_verify_email_claims(user_id.to_string());
let verify_email_token = encode_jwt(&claims); let verify_email_token = encode_jwt(&claims);
let (subject, body_html, body_text) = get_text( let (subject, body_html, body_text) = get_text(
@ -193,7 +193,7 @@ pub async fn send_verify_email(address: &str, uuid: &str) -> EmptyResult {
json!({ json!({
"url": CONFIG.domain(), "url": CONFIG.domain(),
"img_src": CONFIG._smtp_img_src(), "img_src": CONFIG._smtp_img_src(),
"user_id": uuid, "user_id": user_id,
"email": percent_encode(address.as_bytes(), NON_ALPHANUMERIC).to_string(), "email": percent_encode(address.as_bytes(), NON_ALPHANUMERIC).to_string(),
"token": verify_email_token, "token": verify_email_token,
}), }),
@ -214,8 +214,8 @@ pub async fn send_welcome(address: &str) -> EmptyResult {
send_email(address, &subject, body_html, body_text).await send_email(address, &subject, body_html, body_text).await
} }
pub async fn send_welcome_must_verify(address: &str, uuid: &str) -> EmptyResult { pub async fn send_welcome_must_verify(address: &str, user_id: &UserId) -> EmptyResult {
let claims = generate_verify_email_claims(uuid.to_string()); let claims = generate_verify_email_claims(user_id.to_string());
let verify_email_token = encode_jwt(&claims); let verify_email_token = encode_jwt(&claims);
let (subject, body_html, body_text) = get_text( let (subject, body_html, body_text) = get_text(
@ -223,7 +223,7 @@ pub async fn send_welcome_must_verify(address: &str, uuid: &str) -> EmptyResult
json!({ json!({
"url": CONFIG.domain(), "url": CONFIG.domain(),
"img_src": CONFIG._smtp_img_src(), "img_src": CONFIG._smtp_img_src(),
"user_id": uuid, "user_id": user_id,
"token": verify_email_token, "token": verify_email_token,
}), }),
)?; )?;
@ -265,7 +265,7 @@ pub async fn send_invite(
invited_by_email: Option<String>, invited_by_email: Option<String>,
) -> EmptyResult { ) -> EmptyResult {
let claims = generate_invite_claims( let claims = generate_invite_claims(
user.uuid.clone(), user.uuid.to_string(),
user.email.clone(), user.email.clone(),
org_id.clone(), org_id.clone(),
member_id.clone(), member_id.clone(),