ezidam: admin settings: added security page: logout everyone
This commit is contained in:
parent
d3e88b1f7b
commit
8ab88ae4e1
5 changed files with 177 additions and 5 deletions
|
|
@ -37,10 +37,16 @@ impl AdminMenu {
|
|||
label: "Server settings",
|
||||
link: uri!(routes::admin::settings::settings_branding).to_string(),
|
||||
icon: icons::SETTINGS,
|
||||
sub: Some(vec![SubItem {
|
||||
sub: Some(vec![
|
||||
SubItem {
|
||||
label: "Branding",
|
||||
link: uri!(routes::admin::settings::settings_branding).to_string(),
|
||||
}]),
|
||||
},
|
||||
SubItem {
|
||||
label: "Security",
|
||||
link: uri!(routes::admin::settings::settings_security).to_string(),
|
||||
},
|
||||
]),
|
||||
},
|
||||
]
|
||||
}
|
||||
|
|
|
|||
|
|
@ -16,6 +16,7 @@ pub enum Page {
|
|||
Redirect(Redirect),
|
||||
AdminDashboard(AdminDashboard),
|
||||
AdminSettingsBranding(AdminSettingsBranding),
|
||||
AdminSettingsSecurity(AdminSettingsSecurity),
|
||||
}
|
||||
|
||||
impl Page {
|
||||
|
|
@ -29,6 +30,7 @@ impl Page {
|
|||
Page::Redirect(_) => "pages/oauth/redirect",
|
||||
Page::AdminDashboard(_) => "pages/admin/dashboard",
|
||||
Page::AdminSettingsBranding(_) => "pages/admin/settings_branding",
|
||||
Page::AdminSettingsSecurity(_) => "pages/admin/settings_security",
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -42,6 +44,7 @@ impl Page {
|
|||
Page::Redirect(_) => "Redirecting",
|
||||
Page::AdminDashboard(_) => "Admin dashboard",
|
||||
Page::AdminSettingsBranding(_) => "Server branding",
|
||||
Page::AdminSettingsSecurity(_) => "Server security",
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -57,6 +60,7 @@ impl Page {
|
|||
Page::Redirect(_) => None,
|
||||
Page::AdminDashboard(_) => Some(AdminMenu::Dashboard.into()),
|
||||
Page::AdminSettingsBranding(_) => Some(AdminMenu::Settings.into()),
|
||||
Page::AdminSettingsSecurity(_) => Some(AdminMenu::Settings.into()),
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -70,6 +74,7 @@ impl Page {
|
|||
Page::Redirect(redirect) => Box::new(redirect),
|
||||
Page::AdminDashboard(dashboard) => Box::new(dashboard),
|
||||
Page::AdminSettingsBranding(branding) => Box::new(branding),
|
||||
Page::AdminSettingsSecurity(security) => Box::new(security),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -6,7 +6,13 @@ pub mod dashboard;
|
|||
pub mod settings;
|
||||
|
||||
pub fn routes() -> Vec<Route> {
|
||||
routes![admin_dashboard, settings_branding, settings_update_branding]
|
||||
routes![
|
||||
admin_dashboard,
|
||||
settings_branding,
|
||||
settings_update_branding,
|
||||
settings_security,
|
||||
settings_security_form,
|
||||
]
|
||||
}
|
||||
|
||||
pub mod content {
|
||||
|
|
@ -27,4 +33,11 @@ pub mod content {
|
|||
pub user: JwtClaims,
|
||||
pub business_name: String,
|
||||
}
|
||||
|
||||
#[derive(Serialize)]
|
||||
#[serde(crate = "rocket::serde")]
|
||||
#[derive(Clone)]
|
||||
pub struct AdminSettingsSecurity {
|
||||
pub user: JwtClaims,
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,7 +1,13 @@
|
|||
use crate::routes::prelude::*;
|
||||
use crate::tokens::{generate_jwt, generate_refresh_token};
|
||||
use apps::App;
|
||||
use refresh_tokens::RefreshToken;
|
||||
use rocket::fs::TempFile;
|
||||
use rocket::http::CookieJar;
|
||||
use rocket::{get, post};
|
||||
use settings::Settings;
|
||||
use std::net::IpAddr;
|
||||
use users::User;
|
||||
|
||||
#[get("/admin/settings/branding")]
|
||||
pub async fn settings_branding(mut db: Connection<Database>, admin: JwtAdmin) -> Result<Page> {
|
||||
|
|
@ -59,3 +65,85 @@ pub async fn settings_update_branding(
|
|||
|
||||
Ok(Redirect::to(uri!(settings_branding)))
|
||||
}
|
||||
|
||||
#[get("/admin/settings/security")]
|
||||
pub async fn settings_security(admin: JwtAdmin) -> Result<Page> {
|
||||
Ok(Page::AdminSettingsSecurity(
|
||||
super::content::AdminSettingsSecurity { user: admin.0 },
|
||||
))
|
||||
}
|
||||
|
||||
#[derive(Debug, FromForm)]
|
||||
pub struct SecurityForm {
|
||||
pub logout_everyone: Option<bool>,
|
||||
}
|
||||
|
||||
#[post("/admin/settings/security", data = "<form>")]
|
||||
pub async fn settings_security_form(
|
||||
mut db: Connection<Database>,
|
||||
admin: JwtAdmin,
|
||||
form: Form<SecurityForm>,
|
||||
ip_address: IpAddr,
|
||||
cookie_jar: &CookieJar<'_>,
|
||||
) -> Result<Redirect> {
|
||||
let mut transaction = db.begin().await?;
|
||||
|
||||
if let Some(logout_everyone) = form.logout_everyone {
|
||||
if logout_everyone {
|
||||
// Generate key id
|
||||
let key_id = task::spawn_blocking(id::KeyID::default).await?;
|
||||
|
||||
// Generate key
|
||||
let key_id_for_generation = key_id.clone();
|
||||
let (private_key, public_key) =
|
||||
task::spawn_blocking(move || jwt::generate(&key_id_for_generation)).await??;
|
||||
|
||||
// Insert keys in database
|
||||
jwt::database::save_new_keys(&mut transaction, &key_id, &private_key, &public_key)
|
||||
.await?;
|
||||
|
||||
// Revoke all keys except new one
|
||||
jwt::database::revoke_all_except_one(&mut transaction, &key_id).await?;
|
||||
|
||||
// Get app
|
||||
let app = App::get_one_by_id(&mut transaction, "ezidam")
|
||||
.await?
|
||||
.ok_or_else(|| Error::not_found("Could not find application"))?;
|
||||
|
||||
// Get user info
|
||||
let user = User::get_by_login(&mut transaction, &admin.0.subject)
|
||||
.await?
|
||||
.ok_or_else(|| Error::not_found("Could not find user"))?;
|
||||
|
||||
// Revoke all refresh tokens
|
||||
RefreshToken::revoke_all(&mut transaction).await?;
|
||||
|
||||
// Generate refresh token
|
||||
generate_refresh_token(&mut transaction, ip_address, user.id(), cookie_jar)
|
||||
.await
|
||||
.map_err(Error::internal_server_error)?;
|
||||
|
||||
// Get base url
|
||||
let settings = Settings::get(&mut transaction).await?;
|
||||
let home_page = settings
|
||||
.url()
|
||||
.map(String::from)
|
||||
.ok_or_else(|| Error::bad_request("Server url is not set"))?;
|
||||
|
||||
// Generate jwt
|
||||
generate_jwt(
|
||||
&mut transaction,
|
||||
&private_key,
|
||||
&home_page,
|
||||
&app.id().0,
|
||||
&user,
|
||||
cookie_jar,
|
||||
)
|
||||
.await
|
||||
.map_err(Error::internal_server_error)?;
|
||||
}
|
||||
}
|
||||
transaction.commit().await?;
|
||||
|
||||
Ok(Redirect::to(uri!(settings_security)))
|
||||
}
|
||||
|
|
|
|||
|
|
@ -0,0 +1,60 @@
|
|||
{% extends "shell" %}
|
||||
|
||||
{% block content %}
|
||||
<!-- Page header -->
|
||||
<div class="page-header d-print-none">
|
||||
<div class="container-xl">
|
||||
<div class="row g-2 align-items-center">
|
||||
<div class="col">
|
||||
<h2 class="page-title">
|
||||
Server settings
|
||||
</h2>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<!-- Page body -->
|
||||
<div class="page-body">
|
||||
<div class="container-xl">
|
||||
<div class="card">
|
||||
<div class="row g-0">
|
||||
<div class="col-3 d-none d-md-block border-end">
|
||||
<div class="card-body">
|
||||
<div class="list-group list-group-transparent">
|
||||
<a href="./branding"
|
||||
class="list-group-item list-group-item-action d-flex align-items-center">Branding</a>
|
||||
<a href="./security"
|
||||
class="list-group-item list-group-item-action d-flex align-items-center active">Security</a>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="col d-flex flex-column">
|
||||
<div class="card-body">
|
||||
<h2 class="mb-4">Security</h2>
|
||||
|
||||
<h3 class="card-title">Logout everyone</h3>
|
||||
<p class="card-subtitle">
|
||||
This will force all logged-in users to log in again.<br>
|
||||
This action will become effective immediately.
|
||||
</p>
|
||||
<p>This might take some time, but should not be long.</p>
|
||||
|
||||
<div class="row align-items-center">
|
||||
|
||||
<!-- Logout everyone -->
|
||||
<div class="col-auto">
|
||||
<form action="" method="post">
|
||||
<button class="btn btn-danger" type="submit" name="logout_everyone" value="true">
|
||||
Logout everyone
|
||||
</button>
|
||||
</form>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
{% endblock content %}
|
||||
Loading…
Add table
Add a link
Reference in a new issue