admin/security: show flash, confirm action with modal
This commit is contained in:
parent
19840b31e6
commit
11e2894621
2 changed files with 137 additions and 71 deletions
|
|
@ -72,10 +72,15 @@ pub async fn settings_update_branding(
|
||||||
}
|
}
|
||||||
|
|
||||||
#[get("/admin/settings/security")]
|
#[get("/admin/settings/security")]
|
||||||
pub async fn settings_security(admin: JwtAdmin) -> Result<Page> {
|
pub async fn settings_security(
|
||||||
Ok(Page::AdminSettingsSecurity(
|
admin: JwtAdmin,
|
||||||
super::content::AdminSettingsSecurity { user: admin.0 },
|
flash: Option<FlashMessage<'_>>,
|
||||||
))
|
) -> Result<Template> {
|
||||||
|
let page = Page::AdminSettingsSecurity(super::content::AdminSettingsSecurity { user: admin.0 });
|
||||||
|
|
||||||
|
Ok(flash
|
||||||
|
.map(|flash| Page::with_flash(page.clone(), flash))
|
||||||
|
.unwrap_or_else(|| page.into()))
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug, FromForm)]
|
#[derive(Debug, FromForm)]
|
||||||
|
|
@ -90,81 +95,93 @@ pub async fn settings_security_form(
|
||||||
form: Form<SecurityForm>,
|
form: Form<SecurityForm>,
|
||||||
ip_address: IpAddr,
|
ip_address: IpAddr,
|
||||||
cookie_jar: &CookieJar<'_>,
|
cookie_jar: &CookieJar<'_>,
|
||||||
) -> Result<Redirect> {
|
) -> Result<Flash<Redirect>> {
|
||||||
let mut transaction = db.begin().await?;
|
let mut transaction = db.begin().await?;
|
||||||
|
|
||||||
if let Some(logout_everyone) = form.logout_everyone {
|
let (flash_kind, flash_message) = match form.logout_everyone {
|
||||||
if logout_everyone {
|
Some(logout_everyone) => {
|
||||||
// Generate key id
|
if logout_everyone {
|
||||||
let key_id = task::spawn_blocking(id::KeyID::default).await?;
|
// Generate key id
|
||||||
|
let key_id = task::spawn_blocking(id::KeyID::default).await?;
|
||||||
|
|
||||||
// Generate key
|
// Generate key
|
||||||
let key_id_for_generation = key_id.clone();
|
let key_id_for_generation = key_id.clone();
|
||||||
let (private_key, public_key) =
|
let (private_key, public_key) =
|
||||||
task::spawn_blocking(move || jwt::generate(&key_id_for_generation)).await??;
|
task::spawn_blocking(move || jwt::generate(&key_id_for_generation)).await??;
|
||||||
|
|
||||||
// Insert keys in database
|
// Insert keys in database
|
||||||
jwt::database::save_new_keys(&mut transaction, &key_id, &private_key, &public_key)
|
jwt::database::save_new_keys(&mut transaction, &key_id, &private_key, &public_key)
|
||||||
.await?;
|
.await?;
|
||||||
|
|
||||||
// Revoke all keys except new one
|
// Revoke all keys except new one
|
||||||
jwt::database::revoke_all_except_one(&mut transaction, &key_id).await?;
|
jwt::database::revoke_all_except_one(&mut transaction, &key_id).await?;
|
||||||
|
|
||||||
// Get app
|
// Get app
|
||||||
let app = App::get_one_by_id(&mut transaction, "ezidam")
|
let app = App::get_one_by_id(&mut transaction, "ezidam")
|
||||||
.await?
|
.await?
|
||||||
.ok_or_else(|| Error::not_found("Could not find application"))?;
|
.ok_or_else(|| Error::not_found("Could not find application"))?;
|
||||||
|
|
||||||
// Get user info
|
// Get user info
|
||||||
let user = User::get_by_login(&mut transaction, &admin.0.subject)
|
let user = User::get_by_login(&mut transaction, &admin.0.subject)
|
||||||
.await?
|
.await?
|
||||||
.ok_or_else(|| Error::not_found("Could not find user"))?;
|
.ok_or_else(|| Error::not_found("Could not find user"))?;
|
||||||
|
|
||||||
// Revoke all refresh tokens
|
// Revoke all refresh tokens
|
||||||
RefreshToken::revoke_all(&mut transaction).await?;
|
RefreshToken::revoke_all(&mut transaction).await?;
|
||||||
|
|
||||||
// Generate refresh token
|
// Generate refresh token
|
||||||
let refresh_token =
|
let refresh_token =
|
||||||
generate_refresh_token(&mut transaction, ip_address, user.id(), app.id())
|
generate_refresh_token(&mut transaction, ip_address, user.id(), app.id())
|
||||||
.await
|
.await
|
||||||
.map_err(Error::internal_server_error)?;
|
.map_err(Error::internal_server_error)?;
|
||||||
|
|
||||||
// Add refresh token as a cookie
|
// Add refresh token as a cookie
|
||||||
let mut cookie = Cookie::new(REFRESH_TOKEN_COOKIE_NAME, refresh_token);
|
let mut cookie = Cookie::new(REFRESH_TOKEN_COOKIE_NAME, refresh_token);
|
||||||
cookie.set_secure(true);
|
cookie.set_secure(true);
|
||||||
cookie.set_http_only(true);
|
cookie.set_http_only(true);
|
||||||
cookie.set_same_site(SameSite::Strict);
|
cookie.set_same_site(SameSite::Strict);
|
||||||
cookie.set_max_age(Duration::days(REFRESH_TOKEN_DURATION_DAYS));
|
cookie.set_max_age(Duration::days(REFRESH_TOKEN_DURATION_DAYS));
|
||||||
cookie_jar.add(cookie);
|
cookie_jar.add(cookie);
|
||||||
|
|
||||||
// Get base url
|
// Get base url
|
||||||
let settings = Settings::get(&mut transaction).await?;
|
let settings = Settings::get(&mut transaction).await?;
|
||||||
let home_page = settings
|
let home_page = settings
|
||||||
.url()
|
.url()
|
||||||
.map(String::from)
|
.map(String::from)
|
||||||
.ok_or_else(|| Error::bad_request("Server url is not set"))?;
|
.ok_or_else(|| Error::bad_request("Server url is not set"))?;
|
||||||
|
|
||||||
// Generate jwt
|
// Generate jwt
|
||||||
let jwt = generate_jwt(
|
let jwt = generate_jwt(
|
||||||
&mut transaction,
|
&mut transaction,
|
||||||
&private_key,
|
&private_key,
|
||||||
&home_page,
|
&home_page,
|
||||||
&app.id().0,
|
&app.id().0,
|
||||||
&user,
|
&user,
|
||||||
)
|
)
|
||||||
.await
|
.await
|
||||||
.map_err(Error::internal_server_error)?;
|
.map_err(Error::internal_server_error)?;
|
||||||
|
|
||||||
// Add jwt as a cookie
|
// Add jwt as a cookie
|
||||||
let mut cookie = Cookie::new(JWT_COOKIE_NAME, jwt);
|
let mut cookie = Cookie::new(JWT_COOKIE_NAME, jwt);
|
||||||
cookie.set_secure(true);
|
cookie.set_secure(true);
|
||||||
cookie.set_http_only(true);
|
cookie.set_http_only(true);
|
||||||
cookie.set_same_site(SameSite::Strict);
|
cookie.set_same_site(SameSite::Strict);
|
||||||
cookie.set_max_age(Duration::minutes(JWT_DURATION_MINUTES));
|
cookie.set_max_age(Duration::minutes(JWT_DURATION_MINUTES));
|
||||||
cookie_jar.add(cookie);
|
cookie_jar.add(cookie);
|
||||||
|
|
||||||
|
(FlashKind::Success, "Everyone has been logged out.")
|
||||||
|
} else {
|
||||||
|
(FlashKind::Warning, "Nothing to do.")
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
None => (FlashKind::Warning, "Nothing to do."),
|
||||||
|
};
|
||||||
|
|
||||||
transaction.commit().await?;
|
transaction.commit().await?;
|
||||||
|
|
||||||
Ok(Redirect::to(uri!(settings_security)))
|
Ok(Flash::new(
|
||||||
|
Redirect::to(uri!(settings_security)),
|
||||||
|
flash_kind,
|
||||||
|
flash_message,
|
||||||
|
))
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -16,6 +16,13 @@
|
||||||
<!-- Page body -->
|
<!-- Page body -->
|
||||||
<div class="page-body">
|
<div class="page-body">
|
||||||
<div class="container-xl">
|
<div class="container-xl">
|
||||||
|
|
||||||
|
{% if flash %}
|
||||||
|
<div class="alert alert-{{flash.0}}" role="alert">
|
||||||
|
<h4 class="alert-title">{{ flash.1 | safe }}</h4>
|
||||||
|
</div>
|
||||||
|
{% endif %}
|
||||||
|
|
||||||
<div class="card">
|
<div class="card">
|
||||||
<div class="row g-0">
|
<div class="row g-0">
|
||||||
<div class="col-3 d-none d-md-block border-end">
|
<div class="col-3 d-none d-md-block border-end">
|
||||||
|
|
@ -39,15 +46,13 @@
|
||||||
</p>
|
</p>
|
||||||
<p>This might take some time, but should not be long.</p>
|
<p>This might take some time, but should not be long.</p>
|
||||||
|
|
||||||
<div class="row align-items-center">
|
<div class="row align-items-center mb-4">
|
||||||
|
|
||||||
<!-- Logout everyone -->
|
<!-- Logout everyone -->
|
||||||
<div class="col-auto">
|
<div class="col-auto">
|
||||||
<form action="" method="post">
|
<a class="btn btn-danger" data-bs-toggle="modal" data-bs-target="#modal-logout-confirm">
|
||||||
<button class="btn btn-danger" type="submit" name="logout_everyone" value="true">
|
Logout everyone
|
||||||
Logout everyone
|
</a>
|
||||||
</button>
|
|
||||||
</form>
|
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
</div>
|
</div>
|
||||||
|
|
@ -57,4 +62,48 @@
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
|
||||||
|
<!-- Logout everyone modal -->
|
||||||
|
<div class="modal modal-blur" tabindex="-1" id="modal-logout-confirm">
|
||||||
|
<div class="modal-dialog modal-sm modal-dialog-centered" role="document">
|
||||||
|
<div class="modal-content">
|
||||||
|
|
||||||
|
<div class="modal-status bg-danger"></div>
|
||||||
|
|
||||||
|
<div class="modal-body text-center py-4">
|
||||||
|
|
||||||
|
<div class="text-danger mb-2">
|
||||||
|
{% include "icons/alert-triangle-large" %}
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<h3>Do you want to log out everyone?</h3>
|
||||||
|
<div class="mt-2">All users will be logged out.</div>
|
||||||
|
<div class="mt-2">This might take some time, but should not be long.</div>
|
||||||
|
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="modal-footer">
|
||||||
|
<div class="w-100">
|
||||||
|
<div class="row">
|
||||||
|
|
||||||
|
<div class="col">
|
||||||
|
<a href="#" class="btn w-100" data-bs-dismiss="modal">Cancel</a>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="col">
|
||||||
|
<form action="" method="post">
|
||||||
|
<button type="submit" name="logout_everyone" value="true" class="btn btn-danger w-100">
|
||||||
|
Logout everyone
|
||||||
|
</button>
|
||||||
|
</form>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
{% endblock content %}
|
{% endblock content %}
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue