Can register new clients
This commit is contained in:
parent
bfbc2a690b
commit
28b64b4475
15
Cargo.lock
generated
15
Cargo.lock
generated
@ -1483,6 +1483,9 @@ name = "ipnet"
|
||||
version = "2.11.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "469fb0b9cefa57e3ef31275ee7cacb78f2fdca44e4765491884a2b119d4eb130"
|
||||
dependencies = [
|
||||
"serde",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "is_terminal_polyfill"
|
||||
@ -1608,6 +1611,7 @@ dependencies = [
|
||||
"askama",
|
||||
"clap",
|
||||
"env_logger",
|
||||
"ipnet",
|
||||
"lazy_static",
|
||||
"light-openid",
|
||||
"log",
|
||||
@ -1619,6 +1623,7 @@ dependencies = [
|
||||
"serde_json",
|
||||
"thiserror 2.0.11",
|
||||
"urlencoding",
|
||||
"uuid",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@ -2887,6 +2892,16 @@ version = "0.2.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "06abde3611657adf66d383f00b093d7faecc7fa57071cce2578660c9f1010821"
|
||||
|
||||
[[package]]
|
||||
name = "uuid"
|
||||
version = "1.12.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "b3758f5e68192bb96cc8f9b7e2c2cfdabb435499a28499a42f8f984092adad4b"
|
||||
dependencies = [
|
||||
"getrandom 0.2.15",
|
||||
"serde",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "vcpkg"
|
||||
version = "0.2.15"
|
||||
|
@ -21,3 +21,5 @@ rust-embed = "8.5.0"
|
||||
mime_guess = "2.0.5"
|
||||
askama = "0.12.1"
|
||||
urlencoding = "2.1.3"
|
||||
uuid = { version = "1.12.1", features = ["v4", "serde"] }
|
||||
ipnet = { version = "2.11.0", features = ["serde"] }
|
@ -1,8 +1,3 @@
|
||||
# This compose file is compatible with Compose itself, it might need some
|
||||
# adjustments to run properly with stack.
|
||||
|
||||
version: "3"
|
||||
|
||||
services:
|
||||
synapse:
|
||||
image: docker.io/matrixdotorg/synapse:latest
|
||||
|
@ -1,12 +1,14 @@
|
||||
use crate::app_config::AppConfig;
|
||||
use crate::constants::{STATE_KEY, USER_SESSION_KEY};
|
||||
use crate::server::{HttpFailure, HttpResult};
|
||||
use crate::user::{User, UserConfig, UserID};
|
||||
use crate::user::{APIClient, User, UserConfig, UserID};
|
||||
use crate::utils;
|
||||
use actix_session::Session;
|
||||
use actix_web::{web, HttpResponse};
|
||||
use askama::Template;
|
||||
use ipnet::IpNet;
|
||||
use light_openid::primitives::OpenIDConfig;
|
||||
use std::str::FromStr;
|
||||
|
||||
/// Static assets
|
||||
#[derive(rust_embed::Embed)]
|
||||
@ -36,17 +38,21 @@ struct HomeTemplate {
|
||||
error_message: Option<String>,
|
||||
}
|
||||
|
||||
/// Update matrix token request
|
||||
/// HTTP form request
|
||||
#[derive(serde::Deserialize)]
|
||||
pub struct UpdateMatrixToken {
|
||||
pub struct FormRequest {
|
||||
/// Update matrix token
|
||||
new_matrix_token: Option<String>,
|
||||
|
||||
/// Create a new client
|
||||
new_client_desc: Option<String>,
|
||||
|
||||
/// Restrict new client to a given network
|
||||
ip_network: Option<String>,
|
||||
}
|
||||
|
||||
/// Main route
|
||||
pub async fn home(
|
||||
session: Session,
|
||||
update_matrix_token: Option<web::Form<UpdateMatrixToken>>,
|
||||
) -> HttpResult {
|
||||
pub async fn home(session: Session, form_req: Option<web::Form<FormRequest>>) -> HttpResult {
|
||||
// Get user information, requesting authentication if information is missing
|
||||
let Some(user): Option<User> = session.get(USER_SESSION_KEY)? else {
|
||||
// Generate auth state
|
||||
@ -73,9 +79,9 @@ pub async fn home(
|
||||
.await
|
||||
.map_err(HttpFailure::FetchUserConfig)?;
|
||||
|
||||
if let Some(form_req) = form_req {
|
||||
// Update matrix token, if requested
|
||||
if let Some(update_matrix_token) = update_matrix_token {
|
||||
if let Some(t) = update_matrix_token.0.new_matrix_token {
|
||||
if let Some(t) = form_req.0.new_matrix_token {
|
||||
if t.len() < 3 {
|
||||
error_message = Some("Specified Matrix token is too short!".to_string());
|
||||
} else {
|
||||
@ -85,6 +91,28 @@ pub async fn home(
|
||||
success_message = Some("Matrix token was successfully updated!".to_string());
|
||||
}
|
||||
}
|
||||
|
||||
// Create a new client, if requested
|
||||
if let Some(new_token_desc) = form_req.0.new_client_desc {
|
||||
let ip_net = match form_req.0.ip_network.as_deref() {
|
||||
None | Some("") => None,
|
||||
Some(e) => match IpNet::from_str(e) {
|
||||
Ok(n) => Some(n),
|
||||
Err(e) => {
|
||||
log::error!("Failed to parse IP network provided by user: {e}");
|
||||
error_message = Some(format!("Failed to parse restricted IP network: {e}"));
|
||||
None
|
||||
}
|
||||
},
|
||||
};
|
||||
|
||||
if error_message.is_none() {
|
||||
let token = APIClient::generate(new_token_desc, ip_net);
|
||||
success_message = Some(format!("The secret of your new token is '{}'. Be sure to write it somewhere as you will not be able to recover it later!", token.secret));
|
||||
config.clients.push(token);
|
||||
config.save().await?;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Render page
|
||||
|
37
src/user.rs
37
src/user.rs
@ -1,10 +1,11 @@
|
||||
use crate::app_config::AppConfig;
|
||||
use crate::utils::curr_time;
|
||||
use s3::error::S3Error;
|
||||
use s3::request::ResponseData;
|
||||
use s3::{Bucket, BucketConfiguration};
|
||||
use thiserror::Error;
|
||||
|
||||
use crate::app_config::AppConfig;
|
||||
use crate::utils::{curr_time, rand_str};
|
||||
|
||||
#[derive(Error, Debug)]
|
||||
pub enum UserError {
|
||||
#[error("failed to fetch user configuration: {0}")]
|
||||
@ -27,6 +28,34 @@ pub struct User {
|
||||
pub email: String,
|
||||
}
|
||||
|
||||
/// Single API client information
|
||||
#[derive(serde::Serialize, serde::Deserialize)]
|
||||
pub struct APIClient {
|
||||
/// Client unique ID
|
||||
pub id: uuid::Uuid,
|
||||
|
||||
/// Client description
|
||||
pub description: String,
|
||||
|
||||
/// Restricted API network for token
|
||||
pub network: Option<ipnet::IpNet>,
|
||||
|
||||
/// Client secret
|
||||
pub secret: String,
|
||||
}
|
||||
|
||||
impl APIClient {
|
||||
/// Generate a new API client
|
||||
pub fn generate(description: String, network: Option<ipnet::IpNet>) -> Self {
|
||||
Self {
|
||||
id: Default::default(),
|
||||
description,
|
||||
network,
|
||||
secret: rand_str(20),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(serde::Serialize, serde::Deserialize)]
|
||||
pub struct UserConfig {
|
||||
/// Target user ID
|
||||
@ -40,6 +69,9 @@ pub struct UserConfig {
|
||||
|
||||
/// Current user matrix token
|
||||
pub matrix_token: String,
|
||||
|
||||
/// API clients
|
||||
pub clients: Vec<APIClient>,
|
||||
}
|
||||
|
||||
impl UserConfig {
|
||||
@ -97,6 +129,7 @@ impl UserConfig {
|
||||
created: curr_time()?,
|
||||
updated: curr_time()?,
|
||||
matrix_token: "".to_string(),
|
||||
clients: vec![],
|
||||
})
|
||||
}
|
||||
Err(e) => Err(UserError::FetchUserConfig(e).into()),
|
||||
|
@ -46,6 +46,29 @@
|
||||
</div>
|
||||
{% endif %}
|
||||
|
||||
<!-- New client -->
|
||||
<div class="card border-light mb-3">
|
||||
<div class="card-header">New client</div>
|
||||
<div class="card-body">
|
||||
<form action="/" method="post">
|
||||
<div>
|
||||
<label for="new_client_desc" class="form-label">Description</label>
|
||||
<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" />
|
||||
<small class="form-text text-muted">Client description helps with identification.</small>
|
||||
</div>
|
||||
<div>
|
||||
<label for="ip_network" class="form-label">Allowed IP network</label>
|
||||
<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" />
|
||||
<small class="form-text text-muted">Restrict the networks this IP address can be used from.</small>
|
||||
</div>
|
||||
|
||||
<input type="submit" class="btn btn-primary" value="Create client"/>
|
||||
</form>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Matrix authentication token -->
|
||||
<div class="card border-light mb-3">
|
||||
<div class="card-header">Matrix authentication token</div>
|
||||
|
Loading…
x
Reference in New Issue
Block a user