Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion src/db/models/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -198,7 +198,7 @@ pub struct UserDetails {

impl UserDetails {
pub async fn from_user(pool: &DbPool, user: &User) -> Result<Self, SqlxError> {
let devices = user.devices(pool).await?;
let devices = user.user_devices(pool).await?;
let wallets = user.wallets(pool).await?;
let security_keys = user.security_keys(pool).await?;

Expand Down
35 changes: 23 additions & 12 deletions src/db/models/user.rs
Original file line number Diff line number Diff line change
Expand Up @@ -683,24 +683,35 @@ impl User {
}
}

pub async fn devices(&self, pool: &DbPool) -> Result<Vec<UserDevice>, SqlxError> {
/// Returns a vector of [`UserDevice`]s (hence the name).
/// [`UserDevice`] is a struct containing additional network info about a device.
/// If you only need [`Device`]s, use [`User::devices()`] instead.
pub async fn user_devices(&self, pool: &DbPool) -> Result<Vec<UserDevice>, SqlxError> {
let devices = self.devices(pool).await?;
let mut user_devices = Vec::new();
for device in devices {
if let Some(user_device) = UserDevice::from_device(pool, device).await? {
user_devices.push(user_device);
}
}
Ok(user_devices)
}

/// Returns a vector of [`Device`]s related to a user. If you want to get [`UserDevice`]s (which contain additional network info),
/// use [`User::user_devices()`] instead.
pub async fn devices<'e, E>(&self, executor: E) -> Result<Vec<Device>, SqlxError>
where
E: PgExecutor<'e>,
{
if let Some(id) = self.id {
let devices = query_as!(
query_as!(
Device,
"SELECT device.id \"id?\", name, wireguard_pubkey, user_id, created \
FROM device WHERE user_id = $1",
id
)
.fetch_all(pool)
.await?;

let mut user_devices = Vec::new();
for device in devices {
if let Some(user_device) = UserDevice::from_device(pool, device).await? {
user_devices.push(user_device);
}
}
Ok(user_devices)
.fetch_all(executor)
.await
} else {
Ok(Vec::new())
}
Expand Down
2 changes: 1 addition & 1 deletion src/grpc/enrollment.rs
Original file line number Diff line number Diff line change
Expand Up @@ -573,7 +573,7 @@ impl From<User> for AdminInfo {
impl InitialUserInfo {
async fn from_user(pool: &DbPool, user: User) -> Result<Self, sqlx::Error> {
let enrolled = user.is_enrolled();
let devices = user.devices(pool).await?;
let devices = user.user_devices(pool).await?;
let device_names = devices.into_iter().map(|dev| dev.device.name).collect();
Ok(Self {
first_name: user.first_name,
Expand Down
31 changes: 26 additions & 5 deletions src/handlers/user.rs
Original file line number Diff line number Diff line change
Expand Up @@ -15,9 +15,12 @@ use crate::{
appstate::AppState,
auth::{SessionInfo, UserAdminRole},
db::{
models::enrollment::{Token, PASSWORD_RESET_TOKEN_TYPE},
AppEvent, MFAMethod, OAuth2AuthorizedApp, Settings, User, UserDetails, UserInfo, Wallet,
WebAuthn, WireguardNetwork,
models::{
device::DeviceInfo,
enrollment::{Token, PASSWORD_RESET_TOKEN_TYPE},
},
AppEvent, GatewayEvent, MFAMethod, OAuth2AuthorizedApp, Settings, User, UserDetails,
UserInfo, Wallet, WebAuthn, WireguardNetwork,
},
error::WebError,
ldap::utils::{ldap_add_user, ldap_change_password, ldap_delete_user, ldap_modify_user},
Expand Down Expand Up @@ -710,9 +713,27 @@ pub async fn delete_user(
});
}
if let Some(user) = User::find_by_username(&appstate.pool, &username).await? {
user.delete(&appstate.pool).await?;
let _result = ldap_delete_user(&appstate.pool, &username).await;
// Get rid of all devices of the deleted user from networks first
debug!(
"User {} deleted user {username}, purging their network devices across all networks.",
session.user.username
);
let mut transaction = appstate.pool.begin().await?;
Comment thread
t-aleksander marked this conversation as resolved.
let devices = user.devices(&mut *transaction).await?;
let mut events = Vec::new();
for device in devices {
events.push(GatewayEvent::DeviceDeleted(
DeviceInfo::from_device(&mut *transaction, device).await?,
));
}
appstate.send_multiple_wireguard_events(events);
debug!("Devices of user {username} purged from networks.");

user.delete(&mut *transaction).await?;
let _result = ldap_delete_user(&mut *transaction, &username).await;
appstate.trigger_action(AppEvent::UserDeleted(username.clone()));
transaction.commit().await?;

info!("User {} deleted user {}", session.user.username, &username);
Ok(ApiResponse::default())
} else {
Expand Down