Display the list of registered clients
This commit is contained in:
parent
28b64b4475
commit
2c14281ae3
62
Cargo.lock
generated
62
Cargo.lock
generated
@ -290,6 +290,21 @@ dependencies = [
|
|||||||
"alloc-no-stdlib",
|
"alloc-no-stdlib",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "android-tzdata"
|
||||||
|
version = "0.1.1"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "e999941b234f3131b00bc13c22d06e8c5ff726d1b6318ac7eb276997bbb4fef0"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "android_system_properties"
|
||||||
|
version = "0.1.5"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "819e7219dbd41043ac279b19830f2efc897156490d7fd6ea916720117ee66311"
|
||||||
|
dependencies = [
|
||||||
|
"libc",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "anstream"
|
name = "anstream"
|
||||||
version = "0.6.18"
|
version = "0.6.18"
|
||||||
@ -584,6 +599,20 @@ version = "1.0.0"
|
|||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd"
|
checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "chrono"
|
||||||
|
version = "0.4.39"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "7e36cc9d416881d2e24f9a963be5fb1cd90966419ac844274161d10488b3e825"
|
||||||
|
dependencies = [
|
||||||
|
"android-tzdata",
|
||||||
|
"iana-time-zone",
|
||||||
|
"js-sys",
|
||||||
|
"num-traits",
|
||||||
|
"wasm-bindgen",
|
||||||
|
"windows-targets",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "cipher"
|
name = "cipher"
|
||||||
version = "0.4.4"
|
version = "0.4.4"
|
||||||
@ -1314,6 +1343,29 @@ dependencies = [
|
|||||||
"tracing",
|
"tracing",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "iana-time-zone"
|
||||||
|
version = "0.1.61"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "235e081f3925a06703c2d0117ea8b91f042756fd6e7a6e5d901e8ca1a996b220"
|
||||||
|
dependencies = [
|
||||||
|
"android_system_properties",
|
||||||
|
"core-foundation-sys",
|
||||||
|
"iana-time-zone-haiku",
|
||||||
|
"js-sys",
|
||||||
|
"wasm-bindgen",
|
||||||
|
"windows-core",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "iana-time-zone-haiku"
|
||||||
|
version = "0.1.2"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "f31827a206f56af32e590ba56d5d2d085f558508192593743f16b2306495269f"
|
||||||
|
dependencies = [
|
||||||
|
"cc",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "icu_collections"
|
name = "icu_collections"
|
||||||
version = "1.5.0"
|
version = "1.5.0"
|
||||||
@ -1609,6 +1661,7 @@ dependencies = [
|
|||||||
"actix-web",
|
"actix-web",
|
||||||
"anyhow",
|
"anyhow",
|
||||||
"askama",
|
"askama",
|
||||||
|
"chrono",
|
||||||
"clap",
|
"clap",
|
||||||
"env_logger",
|
"env_logger",
|
||||||
"ipnet",
|
"ipnet",
|
||||||
@ -3051,6 +3104,15 @@ dependencies = [
|
|||||||
"windows-sys 0.59.0",
|
"windows-sys 0.59.0",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "windows-core"
|
||||||
|
version = "0.52.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "33ab640c8d7e35bf8ba19b884ba838ceb4fba93a4e8c65a9059d08afcfc683d9"
|
||||||
|
dependencies = [
|
||||||
|
"windows-targets",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "windows-registry"
|
name = "windows-registry"
|
||||||
version = "0.2.0"
|
version = "0.2.0"
|
||||||
|
@ -23,3 +23,4 @@ askama = "0.12.1"
|
|||||||
urlencoding = "2.1.3"
|
urlencoding = "2.1.3"
|
||||||
uuid = { version = "1.12.1", features = ["v4", "serde"] }
|
uuid = { version = "1.12.1", features = ["v4", "serde"] }
|
||||||
ipnet = { version = "2.11.0", features = ["serde"] }
|
ipnet = { version = "2.11.0", features = ["serde"] }
|
||||||
|
chrono = "0.4.39"
|
@ -1,5 +1,5 @@
|
|||||||
.body-content {
|
.body-content {
|
||||||
max-width: 700px;
|
max-width: 900px;
|
||||||
margin: 50px auto;
|
margin: 50px auto;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -3,3 +3,6 @@ pub const STATE_KEY: &str = "oidc-state";
|
|||||||
|
|
||||||
/// Session key for user information
|
/// Session key for user information
|
||||||
pub const USER_SESSION_KEY: &str = "user";
|
pub const USER_SESSION_KEY: &str = "user";
|
||||||
|
|
||||||
|
/// Token length
|
||||||
|
pub const TOKEN_LEN: usize = 20;
|
||||||
|
@ -34,6 +34,7 @@ pub async fn static_file(path: web::Path<String>) -> HttpResult {
|
|||||||
struct HomeTemplate {
|
struct HomeTemplate {
|
||||||
name: String,
|
name: String,
|
||||||
matrix_token: String,
|
matrix_token: String,
|
||||||
|
clients: Vec<APIClient>,
|
||||||
success_message: Option<String>,
|
success_message: Option<String>,
|
||||||
error_message: Option<String>,
|
error_message: Option<String>,
|
||||||
}
|
}
|
||||||
@ -122,6 +123,7 @@ pub async fn home(session: Session, form_req: Option<web::Form<FormRequest>>) ->
|
|||||||
HomeTemplate {
|
HomeTemplate {
|
||||||
name: user.name,
|
name: user.name,
|
||||||
matrix_token: config.obfuscated_matrix_token(),
|
matrix_token: config.obfuscated_matrix_token(),
|
||||||
|
clients: config.clients,
|
||||||
success_message,
|
success_message,
|
||||||
error_message,
|
error_message,
|
||||||
}
|
}
|
||||||
|
25
src/user.rs
25
src/user.rs
@ -4,7 +4,8 @@ use s3::{Bucket, BucketConfiguration};
|
|||||||
use thiserror::Error;
|
use thiserror::Error;
|
||||||
|
|
||||||
use crate::app_config::AppConfig;
|
use crate::app_config::AppConfig;
|
||||||
use crate::utils::{curr_time, rand_str};
|
use crate::constants::TOKEN_LEN;
|
||||||
|
use crate::utils::{curr_time, format_time, rand_str};
|
||||||
|
|
||||||
#[derive(Error, Debug)]
|
#[derive(Error, Debug)]
|
||||||
pub enum UserError {
|
pub enum UserError {
|
||||||
@ -42,16 +43,34 @@ pub struct APIClient {
|
|||||||
|
|
||||||
/// Client secret
|
/// Client secret
|
||||||
pub secret: String,
|
pub secret: String,
|
||||||
|
|
||||||
|
/// Client creation time
|
||||||
|
pub created: u64,
|
||||||
|
|
||||||
|
/// Client last usage time
|
||||||
|
pub used: u64,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl APIClient {
|
||||||
|
pub fn fmt_created(&self) -> String {
|
||||||
|
format_time(self.created).unwrap_or_default()
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn fmt_used(&self) -> String {
|
||||||
|
format_time(self.used).unwrap_or_default()
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl APIClient {
|
impl APIClient {
|
||||||
/// Generate a new API client
|
/// Generate a new API client
|
||||||
pub fn generate(description: String, network: Option<ipnet::IpNet>) -> Self {
|
pub fn generate(description: String, network: Option<ipnet::IpNet>) -> Self {
|
||||||
Self {
|
Self {
|
||||||
id: Default::default(),
|
id: uuid::Uuid::new_v4(),
|
||||||
description,
|
description,
|
||||||
network,
|
network,
|
||||||
secret: rand_str(20),
|
secret: rand_str(TOKEN_LEN),
|
||||||
|
created: curr_time().unwrap(),
|
||||||
|
used: curr_time().unwrap(),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -12,3 +12,9 @@ pub fn curr_time() -> anyhow::Result<u64> {
|
|||||||
.duration_since(UNIX_EPOCH)
|
.duration_since(UNIX_EPOCH)
|
||||||
.map(|t| t.as_secs())?)
|
.map(|t| t.as_secs())?)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Format time
|
||||||
|
pub fn format_time(time: u64) -> Option<String> {
|
||||||
|
let time = chrono::DateTime::from_timestamp(time as i64, 0)?;
|
||||||
|
Some(time.naive_local().to_string())
|
||||||
|
}
|
||||||
|
@ -14,7 +14,7 @@
|
|||||||
<header data-bs-theme="dark">
|
<header data-bs-theme="dark">
|
||||||
<div class="navbar navbar-dark bg-dark shadow-sm">
|
<div class="navbar navbar-dark bg-dark shadow-sm">
|
||||||
<div class="container">
|
<div class="container">
|
||||||
<a href="#" class="navbar-brand d-flex align-items-center">
|
<a href="/" class="navbar-brand d-flex align-items-center">
|
||||||
<svg xxmlns="http://www.w3.org/2000/svg" width="20" height="20" fill="none" stroke="currentColor"
|
<svg xxmlns="http://www.w3.org/2000/svg" width="20" height="20" fill="none" stroke="currentColor"
|
||||||
stroke-linecap="round" stroke-linejoin="round" stroke-width="1" aria-hidden="true" class="me-2"
|
stroke-linecap="round" stroke-linejoin="round" stroke-width="1" aria-hidden="true" class="me-2"
|
||||||
viewBox="0 0 24 24">
|
viewBox="0 0 24 24">
|
||||||
@ -46,6 +46,51 @@
|
|||||||
</div>
|
</div>
|
||||||
{% endif %}
|
{% endif %}
|
||||||
|
|
||||||
|
<!-- Display clients list -->
|
||||||
|
<div class="card border-light mb-3">
|
||||||
|
<div class="card-header">Registered clients</div>
|
||||||
|
<div class="card-body">
|
||||||
|
{% if clients.len() > 0 %}
|
||||||
|
<table class="table table-hover">
|
||||||
|
<thead>
|
||||||
|
<tr>
|
||||||
|
<th scope="col">ID</th>
|
||||||
|
<th scope="col">Description</th>
|
||||||
|
<th scope="col">Network</th>
|
||||||
|
<th scope="col">Created</th>
|
||||||
|
<th scope="col">Used</th>
|
||||||
|
<th scope="col"></th>
|
||||||
|
</tr>
|
||||||
|
</thead>
|
||||||
|
<tbody>
|
||||||
|
{% for client in clients %}
|
||||||
|
<tr>
|
||||||
|
<th scope="row">{{ client.id }}</th>
|
||||||
|
<td>{{ client.description }}</td>
|
||||||
|
<td>
|
||||||
|
{% if let Some(net) = client.network %}
|
||||||
|
{{ net }}
|
||||||
|
{% else %}
|
||||||
|
<i>Unrestricted</i>
|
||||||
|
{% endif %}
|
||||||
|
</td>
|
||||||
|
<td>{{ client.fmt_created() }}</td>
|
||||||
|
<td>{{ client.fmt_used() }}</td>
|
||||||
|
<td>
|
||||||
|
<button type="button" class="btn btn-danger btn-sm">Delete</button>
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
|
{% endfor %}
|
||||||
|
</tbody>
|
||||||
|
</table>
|
||||||
|
{% endif %}
|
||||||
|
|
||||||
|
{% if clients.len() == 0 %}
|
||||||
|
<p>No client registered yet!</p>
|
||||||
|
{% endif %}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
<!-- New client -->
|
<!-- New client -->
|
||||||
<div class="card border-light mb-3">
|
<div class="card border-light mb-3">
|
||||||
<div class="card-header">New client</div>
|
<div class="card-header">New client</div>
|
||||||
@ -54,13 +99,14 @@
|
|||||||
<div>
|
<div>
|
||||||
<label for="new_client_desc" class="form-label">Description</label>
|
<label for="new_client_desc" class="form-label">Description</label>
|
||||||
<input type="text" class="form-control" id="new_client_desc" required minlength="3"
|
<input type="text" class="form-control" id="new_client_desc" required minlength="3"
|
||||||
aria-describedby="new_client_desc" placeholder="New client description..." name="new_client_desc" />
|
aria-describedby="new_client_desc" placeholder="New client description..."
|
||||||
|
name="new_client_desc"/>
|
||||||
<small class="form-text text-muted">Client description helps with identification.</small>
|
<small class="form-text text-muted">Client description helps with identification.</small>
|
||||||
</div>
|
</div>
|
||||||
<div>
|
<div>
|
||||||
<label for="ip_network" class="form-label">Allowed IP network</label>
|
<label for="ip_network" class="form-label">Allowed IP network</label>
|
||||||
<input type="text" class="form-control" id="ip_network" aria-describedby="ip_network"
|
<input type="text" class="form-control" id="ip_network" aria-describedby="ip_network"
|
||||||
placeholder="Client network (x.x.x.x/x or x:x:x:x:x:x/x" name="ip_network" />
|
placeholder="Client network (x.x.x.x/x or x:x:x:x:x:x/x" name="ip_network"/>
|
||||||
<small class="form-text text-muted">Restrict the networks this IP address can be used from.</small>
|
<small class="form-text text-muted">Restrict the networks this IP address can be used from.</small>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
Loading…
x
Reference in New Issue
Block a user