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:
Ursprung
64ae0aa386
Commit
16afe10898
34 geänderte Dateien mit 351 neuen und 257 gelöschten Zeilen
|
@ -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,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -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
|
||||||
|
|
|
@ -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(¤t_collections) {
|
for collection in posted_collections.symmetric_difference(¤t_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(¤t_collections) {
|
for collection in posted_collections.symmetric_difference(¤t_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 {
|
||||||
|
|
|
@ -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()
|
||||||
|
|
|
@ -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);
|
||||||
|
|
|
@ -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,
|
||||||
|
|
|
@ -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 {
|
||||||
|
|
|
@ -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
|
||||||
|
|
|
@ -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());
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
@ -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 {
|
||||||
|
|
|
@ -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 {
|
||||||
|
|
|
@ -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 ®.credential.cred_id == cred_id {
|
if ®.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(®istrations)?)
|
TwoFactor::new(user_uuid.clone(), TwoFactorType::Webauthn, serde_json::to_string(®istrations)?)
|
||||||
.save(conn)
|
.save(conn)
|
||||||
.await?;
|
.await?;
|
||||||
return Ok(());
|
return Ok(());
|
||||||
|
|
|
@ -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> {
|
||||||
|
|
|
@ -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()),
|
||||||
])]),
|
])]),
|
||||||
]);
|
]);
|
||||||
|
|
||||||
|
|
|
@ -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": (),
|
||||||
|
|
|
@ -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,
|
||||||
|
|
|
@ -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> {
|
||||||
|
|
|
@ -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))
|
||||||
|
|
|
@ -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))
|
||||||
|
|
|
@ -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()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -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))
|
||||||
|
|
|
@ -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
|
||||||
}
|
}
|
||||||
|
|
|
@ -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>,
|
||||||
|
|
|
@ -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))
|
||||||
|
|
|
@ -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)
|
||||||
|
|
|
@ -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(
|
||||||
|
|
|
@ -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};
|
||||||
|
|
|
@ -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
|
||||||
{
|
{
|
||||||
|
|
|
@ -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()))))
|
||||||
|
|
|
@ -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)]
|
||||||
|
|
|
@ -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)
|
||||||
|
|
|
@ -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)
|
||||||
|
|
|
@ -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(())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
22
src/mail.rs
22
src/mail.rs
|
@ -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(),
|
||||||
|
|
Laden …
In neuem Issue referenzieren