chore: update to new crates versions and fix sources for it
Some checks are pending
Install / Cargo install on ubuntu-latest (push) Waiting to run
Some checks are pending
Install / Cargo install on ubuntu-latest (push) Waiting to run
This commit is contained in:
parent
7fe3d25788
commit
8ba9afbce3
74
Cargo.toml
74
Cargo.toml
@ -14,65 +14,67 @@ default = "inrepo"
|
|||||||
#rustdoc-args = ["--html-in-header", "rusdoc/header.html"]
|
#rustdoc-args = ["--html-in-header", "rusdoc/header.html"]
|
||||||
|
|
||||||
[dependencies]
|
[dependencies]
|
||||||
log = { version = "0.4.20", features = ["max_level_trace","release_max_level_trace"], package = "log" }
|
log = { version = "0.4.22", features = ["max_level_trace","release_max_level_trace"], package = "log" }
|
||||||
axum = { git = "https://github.com/tokio-rs/axum.git", branch = "main" }
|
#axum = { git = "https://github.com/tokio-rs/axum.git", branch = "main" }
|
||||||
#axum = { version = "0.6.20" } # use wrks axum_6
|
axum = { version = "0.7.5" } # use wrks axum_6
|
||||||
axum-server = { version = "0.5.1", features = ["tls-rustls"] }
|
axum-server = { version = "0.7.1", features = ["tls-rustls"] }
|
||||||
tokio = { version = "1.32.0", features = ["full"] }
|
tokio = { version = "1.39.2", features = ["full"] }
|
||||||
tower = { version = "0.4.13", features = ["util", "filter"] }
|
tower = { version = "0.5.0", features = ["util", "filter"] }
|
||||||
tower-http = { version = "0.4.4", features = ["fs", "cors", "trace", "add-extension", "auth", "compression-full"] }
|
tower-http = { version = "0.5.2", features = ["fs", "cors", "trace", "add-extension", "auth", "compression-full"] }
|
||||||
tower-cookies = "0.9"
|
tower-cookies = "0.10.0"
|
||||||
tracing = "0.1.37"
|
tracing = "0.1.40"
|
||||||
tracing-subscriber = { version = "0.3.17", features = ["env-filter"] }
|
tracing-subscriber = { version = "0.3.18", features = ["env-filter"] }
|
||||||
|
|
||||||
casbin = { version = "2.0.9", features = ["cached","explain","logging"], optional = true}
|
casbin = { version = "2.2.0", features = ["cached","explain","logging"], optional = true}
|
||||||
pasetoken-lib= {path = "./pasetoken", package = "pasetoken-lib" }
|
pasetoken-lib= {path = "./pasetoken", package = "pasetoken-lib" }
|
||||||
pasetors = { version = "0.6.7" }
|
pasetors = { version = "0.6.8" }
|
||||||
|
|
||||||
serde = { version = "1.0.188", features = ["derive"] }
|
serde = { version = "1.0.207", features = ["derive"] }
|
||||||
serde_derive = "1.0.188"
|
serde_derive = "1.0.207"
|
||||||
serde_json = "1.0.107"
|
serde_json = "1.0.124"
|
||||||
toml = "0.8.0"
|
toml = "0.8.19"
|
||||||
|
|
||||||
clap = { version = "4.4.4", features = ["derive"] }
|
clap = { version = "4.5.15", features = ["derive"] }
|
||||||
git-version = "0.3.5"
|
git-version = "0.3.9"
|
||||||
once_cell = "1.18.0"
|
once_cell = "1.19.0"
|
||||||
|
|
||||||
hyper = { version = "0.14.27", features = ["full"] }
|
hyper = { version = "1.4.1", features = ["full"] }
|
||||||
tera = "1.19.1"
|
tera = "1.20.0"
|
||||||
html-minifier = "4.0.0"
|
html-minifier = "5.0.0"
|
||||||
urlencoding = "2.1.3"
|
urlencoding = "2.1.3"
|
||||||
password-hash = { version = "0.5", features = ["alloc", "rand_core"] }
|
password-hash = { version = "0.5", features = ["alloc", "rand_core"] }
|
||||||
rand_core = { version = "0.6", features = ["getrandom"] }
|
rand_core = { version = "0.6.4", features = ["getrandom"] }
|
||||||
argon2 = { version = "0.5", default-features = false, features = ["alloc", "simple"]}
|
argon2 = { version = "0.5", default-features = false, features = ["alloc", "simple"]}
|
||||||
rand_chacha = "0.3.1"
|
rand_chacha = "0.3.1"
|
||||||
async-trait = "0.1.73"
|
async-trait = "0.1.81"
|
||||||
async-session = "3.0.0"
|
async-session = "3.0.0"
|
||||||
async-sqlx-session = { version = "0.4.0", features = ["sqlite"] }
|
async-sqlx-session = { version = "0.4.0", features = ["sqlite"] }
|
||||||
|
|
||||||
forwarded-header-value = "0.1.1"
|
forwarded-header-value = "0.1.1"
|
||||||
lettre = { version = "0.10.4", features = ["smtp-transport", "tokio1", "tokio1-native-tls", "builder"] }
|
lettre = { version = "0.11.7", features = ["smtp-transport", "tokio1", "tokio1-native-tls", "builder"] }
|
||||||
|
|
||||||
chrono = { version = "0.4.*" }
|
chrono = { version = "0.4.38" }
|
||||||
encoding = "0.*"
|
encoding = "0.2.33"
|
||||||
uuid = { version = "1.4.1", features = ["v4", "serde"] }
|
uuid = { version = "1.4.1", features = ["v4", "serde"] }
|
||||||
rand = "0.8.5"
|
rand = "0.8.5"
|
||||||
walkdir = "2.4.0"
|
walkdir = "2.5.0"
|
||||||
binascii = "0.1.4"
|
binascii = "0.1.4"
|
||||||
anyhow = "1.0.75"
|
anyhow = "1.0.86"
|
||||||
|
|
||||||
totp-rs = { version = "5.0.2", features = ["qr","otpauth"] }
|
totp-rs = { version = "5.6.0", features = ["qr","otpauth"] }
|
||||||
base32 = "0.4.0"
|
base32 = "0.5.1"
|
||||||
zxcvbn = "2.2.2"
|
zxcvbn = "3.1.0"
|
||||||
|
|
||||||
futures= "0.3.28"
|
futures= "0.3.30"
|
||||||
|
#sqlx = { version = "0.8.0", features = ["sqlite", "runtime-tokio-native-tls"] }
|
||||||
|
#sqlx = { version = "0.8", features = [ "runtime-tokio", "tls-native-tls" ] }
|
||||||
|
#sqlx = { version = "0.8.0", features = ["all-types", "all-databases","runtime-tokio-native-tls"] }
|
||||||
# async-sqlx-session 0.4.0 still running in 0.6.2
|
# async-sqlx-session 0.4.0 still running in 0.6.2
|
||||||
sqlx = { version = "0.6.3", features = ["all-types", "all-databases","runtime-tokio-native-tls"] }
|
sqlx = { version = "0.6.3", features = ["all-databases","runtime-tokio-native-tls"] }
|
||||||
#sqlx = { version = "0.7.1", features = ["all-databases","runtime-tokio-native-tls"] }
|
|
||||||
|
|
||||||
openidconnect = { version = "3.3.1", default-features = true, features = [] }
|
openidconnect = { version = "3.3.1", default-features = true, features = [] }
|
||||||
url = { version = "2.4", features = [] }
|
url = { version = "2.4", features = [] }
|
||||||
jsonwebtoken = "8"
|
jsonwebtoken = "9.3.0"
|
||||||
|
|
||||||
[dev-dependencies]
|
[dev-dependencies]
|
||||||
async-std = { version = "1.12.0", features = ["default","attributes"] }
|
async-std = { version = "1.12.0", features = ["default","attributes"] }
|
||||||
|
@ -5,6 +5,7 @@ mod filestore;
|
|||||||
mod session;
|
mod session;
|
||||||
#[cfg(feature = "authstore")]
|
#[cfg(feature = "authstore")]
|
||||||
mod authz;
|
mod authz;
|
||||||
|
mod form_defs;
|
||||||
mod appdbs;
|
mod appdbs;
|
||||||
mod req_headermap;
|
mod req_headermap;
|
||||||
mod req_handler;
|
mod req_handler;
|
||||||
@ -15,6 +16,7 @@ mod totp_mode;
|
|||||||
mod totp_algorithm;
|
mod totp_algorithm;
|
||||||
mod app_connect_info;
|
mod app_connect_info;
|
||||||
mod openid;
|
mod openid;
|
||||||
|
mod req_settings;
|
||||||
|
|
||||||
pub(crate) use appdbs::AppDBs;
|
pub(crate) use appdbs::AppDBs;
|
||||||
pub(crate) use session::{
|
pub(crate) use session::{
|
||||||
@ -32,6 +34,7 @@ pub(crate) use filestore::FileStore;
|
|||||||
#[cfg(feature = "authstore")]
|
#[cfg(feature = "authstore")]
|
||||||
pub(crate) use authz::AuthStore;
|
pub(crate) use authz::AuthStore;
|
||||||
pub(crate) use config::{ServPath,Config};
|
pub(crate) use config::{ServPath,Config};
|
||||||
|
pub(crate) use form_defs::FormDefs;
|
||||||
pub(crate) use cli::parse_args;
|
pub(crate) use cli::parse_args;
|
||||||
pub(crate) use req_handler::ReqHandler;
|
pub(crate) use req_handler::ReqHandler;
|
||||||
pub(crate) use req_headermap::ReqHeaderMap;
|
pub(crate) use req_headermap::ReqHeaderMap;
|
||||||
@ -46,6 +49,8 @@ pub(crate) use app_connect_info::AppConnectInfo;
|
|||||||
|
|
||||||
pub(crate) use openid::{OpenidConf,OpenidData,collect_openid_clients,OpenidCli};
|
pub(crate) use openid::{OpenidConf,OpenidData,collect_openid_clients,OpenidCli};
|
||||||
|
|
||||||
|
pub(crate) use req_settings::ReqSettings;
|
||||||
|
|
||||||
pub const TOKEN_KEY_VALUE: &str = "tii-cl";
|
pub const TOKEN_KEY_VALUE: &str = "tii-cl";
|
||||||
pub const TOKEN_AUTH_VALUE: &str = "tii-cl-token";
|
pub const TOKEN_AUTH_VALUE: &str = "tii-cl-token";
|
||||||
pub const CLAIM_UID: &str = "uid";
|
pub const CLAIM_UID: &str = "uid";
|
||||||
|
@ -1,26 +1,28 @@
|
|||||||
use std::net::SocketAddr;
|
use std::net::SocketAddr;
|
||||||
use hyper::server::conn::AddrStream;
|
//use hyper::server::conn::AddrStream;
|
||||||
use axum::extract::connect_info::Connected;
|
use axum::extract::connect_info::Connected;
|
||||||
use axum::serve::IncomingStream;
|
use axum::serve::IncomingStream;
|
||||||
|
|
||||||
#[derive(Clone, Debug)]
|
#[derive(Clone, Debug)]
|
||||||
pub struct AppConnectInfo {
|
pub struct AppConnectInfo {
|
||||||
pub remote_addr: SocketAddr,
|
pub remote_addr: SocketAddr,
|
||||||
pub local_addr: SocketAddr,
|
// pub local_addr: SocketAddr,
|
||||||
}
|
}
|
||||||
impl Connected<IncomingStream<'_>> for AppConnectInfo {
|
impl Connected<IncomingStream<'_>> for AppConnectInfo {
|
||||||
fn connect_info(target: IncomingStream<'_>) -> Self {
|
fn connect_info(target: IncomingStream<'_>) -> Self {
|
||||||
AppConnectInfo {
|
AppConnectInfo {
|
||||||
remote_addr: target.remote_addr(),
|
remote_addr: target.remote_addr(),
|
||||||
local_addr: target.local_addr().unwrap_or(target.remote_addr()),
|
// local_addr: target.local_addr().unwrap_or(target.remote_addr()),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
impl Connected<&AddrStream> for AppConnectInfo {
|
// impl Connected<&AddrStream> for AppConnectInfo {
|
||||||
fn connect_info(target: &AddrStream) -> Self {
|
// fn connect_info(target: &AddrStream) -> Self {
|
||||||
|
impl Connected<SocketAddr> for AppConnectInfo {
|
||||||
|
fn connect_info(target: SocketAddr) -> Self {
|
||||||
AppConnectInfo {
|
AppConnectInfo {
|
||||||
remote_addr: target.remote_addr(),
|
remote_addr: target.to_owned(),
|
||||||
local_addr: target.local_addr(),
|
// local_addr: target.to_owned(),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -14,6 +14,7 @@ use crate::{
|
|||||||
FromFile,
|
FromFile,
|
||||||
load_from_file,
|
load_from_file,
|
||||||
load_dict_from_file,
|
load_dict_from_file,
|
||||||
|
ReqSettings,
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -70,6 +71,9 @@ fn default_web_menu_item_roles() -> Vec<String> {
|
|||||||
fn default_auth_roles() -> Vec<String> {
|
fn default_auth_roles() -> Vec<String> {
|
||||||
Vec::new()
|
Vec::new()
|
||||||
}
|
}
|
||||||
|
fn default_roles() -> Vec<String> {
|
||||||
|
Vec::new()
|
||||||
|
}
|
||||||
fn default_sub_menu_items() -> Vec<SubMenuItem> {
|
fn default_sub_menu_items() -> Vec<SubMenuItem> {
|
||||||
Vec::new()
|
Vec::new()
|
||||||
}
|
}
|
||||||
@ -85,6 +89,9 @@ fn default_config_totp_mode() -> TotpMode {
|
|||||||
fn default_config_password_score() -> u8 {
|
fn default_config_password_score() -> u8 {
|
||||||
0
|
0
|
||||||
}
|
}
|
||||||
|
fn default_config_req_settings() -> ReqSettings {
|
||||||
|
ReqSettings::default()
|
||||||
|
}
|
||||||
fn default_config_trace_level() -> u8 { 1 }
|
fn default_config_trace_level() -> u8 { 1 }
|
||||||
fn default_config_openid_auths() -> HashMap<String,OpenidConf> { HashMap::new() }
|
fn default_config_openid_auths() -> HashMap<String,OpenidConf> { HashMap::new() }
|
||||||
#[derive(Debug, Clone, Serialize, Deserialize,Default)]
|
#[derive(Debug, Clone, Serialize, Deserialize,Default)]
|
||||||
@ -229,6 +236,8 @@ pub struct Config {
|
|||||||
pub user_store_access: String,
|
pub user_store_access: String,
|
||||||
#[serde(default = "default_auth_roles")]
|
#[serde(default = "default_auth_roles")]
|
||||||
pub auth_roles: Vec<String>,
|
pub auth_roles: Vec<String>,
|
||||||
|
#[serde(default = "default_roles")]
|
||||||
|
pub default_roles: Vec<String>,
|
||||||
#[serde(default = "default_config_empty")]
|
#[serde(default = "default_config_empty")]
|
||||||
pub trace_store_uri: String,
|
pub trace_store_uri: String,
|
||||||
#[serde(default = "default_config_trace_level")]
|
#[serde(default = "default_config_trace_level")]
|
||||||
@ -294,6 +303,12 @@ pub struct Config {
|
|||||||
pub openid_access_token_url: String,
|
pub openid_access_token_url: String,
|
||||||
#[serde(default = "default_config_openid_auths")]
|
#[serde(default = "default_config_openid_auths")]
|
||||||
pub openid_auths: HashMap<String,OpenidConf>,
|
pub openid_auths: HashMap<String,OpenidConf>,
|
||||||
|
#[serde(default = "default_config_resource")]
|
||||||
|
pub forms_path: String,
|
||||||
|
#[serde(default = "default_config_resource")]
|
||||||
|
pub forms_responses_path: String,
|
||||||
|
#[serde(default = "default_config_req_settings")]
|
||||||
|
pub req_settings: ReqSettings,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl FromFile for Config {
|
impl FromFile for Config {
|
||||||
@ -372,6 +387,8 @@ impl Config {
|
|||||||
self.paseto.footer = ConfigPaSeToken::make_footer(
|
self.paseto.footer = ConfigPaSeToken::make_footer(
|
||||||
self.paseto.map_footer.to_owned()
|
self.paseto.map_footer.to_owned()
|
||||||
).unwrap_or(Footer::new());
|
).unwrap_or(Footer::new());
|
||||||
|
self.forms_path = self.fix_item_path(self.forms_path.to_owned());
|
||||||
|
self.forms_responses_path = self.fix_item_path(self.forms_responses_path.to_owned());
|
||||||
}
|
}
|
||||||
#[allow(dead_code)]
|
#[allow(dead_code)]
|
||||||
pub fn to_json(&self) -> String {
|
pub fn to_json(&self) -> String {
|
||||||
|
247
src/defs/form_defs.rs
Normal file
247
src/defs/form_defs.rs
Normal file
@ -0,0 +1,247 @@
|
|||||||
|
// use std::collections::HashMap;
|
||||||
|
use std::{
|
||||||
|
io::Write,
|
||||||
|
// sync::Arc,
|
||||||
|
fmt::Debug,
|
||||||
|
fs,
|
||||||
|
path::{Path, PathBuf},
|
||||||
|
io::{Error, ErrorKind},
|
||||||
|
};
|
||||||
|
use serde::{Serialize, Deserialize};
|
||||||
|
//use serde_json::value::{to_value, Value};
|
||||||
|
// use log::error;
|
||||||
|
|
||||||
|
use crate::{
|
||||||
|
defs::{
|
||||||
|
FromFile,
|
||||||
|
load_from_file,
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
|
// use std::path::Path;
|
||||||
|
|
||||||
|
// use crate::tools::generate_uuid;
|
||||||
|
// fn default_server_uid() -> String {
|
||||||
|
// generate_uuid(String::from("abcdef0123456789"))
|
||||||
|
// }
|
||||||
|
|
||||||
|
fn default_form_defs_empty() -> String {
|
||||||
|
"".to_string()
|
||||||
|
}
|
||||||
|
fn default_form_selections() -> Vec<FormSelectItem> {
|
||||||
|
Vec::new()
|
||||||
|
}
|
||||||
|
fn default_form_border() -> bool {
|
||||||
|
false
|
||||||
|
}
|
||||||
|
fn default_form_required() -> bool {
|
||||||
|
false
|
||||||
|
}
|
||||||
|
fn default_form_items_empty() -> Vec<FormField> {
|
||||||
|
Vec::new()
|
||||||
|
}
|
||||||
|
fn default_form_overwrite_response() -> bool {
|
||||||
|
false
|
||||||
|
}
|
||||||
|
#[derive(Debug, Clone, Serialize, Deserialize,Default)]
|
||||||
|
pub struct FormSelectItem {
|
||||||
|
#[serde(default = "default_form_defs_empty")]
|
||||||
|
pub title: String,
|
||||||
|
#[serde(default = "default_form_defs_empty")]
|
||||||
|
pub defs: String,
|
||||||
|
#[serde(default = "default_form_defs_empty")]
|
||||||
|
pub value: String,
|
||||||
|
}
|
||||||
|
#[derive(Debug, Clone, Serialize, Deserialize,Default)]
|
||||||
|
pub struct FormField {
|
||||||
|
#[serde(default = "default_form_defs_empty")]
|
||||||
|
pub name: String,
|
||||||
|
#[serde(default = "default_form_defs_empty")]
|
||||||
|
pub id: String,
|
||||||
|
#[serde(default = "default_form_defs_empty")]
|
||||||
|
pub placeholder: String,
|
||||||
|
#[serde(default = "default_form_defs_empty")]
|
||||||
|
pub typ: String,
|
||||||
|
#[serde(default = "default_form_defs_empty")]
|
||||||
|
pub css: String,
|
||||||
|
#[serde(default = "default_form_border")]
|
||||||
|
pub border: bool,
|
||||||
|
#[serde(default = "default_form_defs_empty")]
|
||||||
|
pub label_top_text: String,
|
||||||
|
#[serde(default = "default_form_defs_empty")]
|
||||||
|
pub label_css: String,
|
||||||
|
#[serde(default = "default_form_selections")]
|
||||||
|
pub selections: Vec<FormSelectItem>,
|
||||||
|
#[serde(default = "default_form_required")]
|
||||||
|
pub required: bool,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Debug, Clone, Serialize, Deserialize,Default)]
|
||||||
|
pub struct FormDefs {
|
||||||
|
#[serde(default = "default_form_defs_empty")]
|
||||||
|
pub title: String,
|
||||||
|
#[serde(default = "default_form_defs_empty")]
|
||||||
|
pub name: String,
|
||||||
|
#[serde(default = "default_form_defs_empty")]
|
||||||
|
pub id: String,
|
||||||
|
#[serde(default = "default_form_defs_empty")]
|
||||||
|
pub css: String,
|
||||||
|
#[serde(default = "default_form_defs_empty")]
|
||||||
|
pub action: String,
|
||||||
|
#[serde(default = "default_form_items_empty")]
|
||||||
|
pub fields: Vec<FormField>,
|
||||||
|
#[serde(default = "default_form_overwrite_response")]
|
||||||
|
pub overwrite_response: bool,
|
||||||
|
}
|
||||||
|
impl FromFile for FormDefs {
|
||||||
|
fn fix_root_path<Config>(&mut self, _root_path: String ) {
|
||||||
|
// if root_path != self.root_path {
|
||||||
|
// self.root_path = root_path.to_owned();
|
||||||
|
// }
|
||||||
|
// if self.root_path.is_empty() || ! Path::new(&self.root_path).exists() {
|
||||||
|
// return;
|
||||||
|
// }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
impl FormDefs {
|
||||||
|
pub fn load_from(path: &str, name: &str) -> Self {
|
||||||
|
load_from_file(path,name).unwrap_or_else(|e|{
|
||||||
|
println!("FormDefs error: {}",e);
|
||||||
|
FormDefs::default()
|
||||||
|
})
|
||||||
|
}
|
||||||
|
pub fn write_data(&self, file_path: &str, data: &str, overwrite: bool) -> std::io::Result<()> {
|
||||||
|
let check_path = |path: &Path| -> std::io::Result<()> {
|
||||||
|
if ! Path::new(&path).exists() {
|
||||||
|
if let Err(e) = std::fs::create_dir(&path) {
|
||||||
|
return Err(Error::new( ErrorKind::InvalidInput,
|
||||||
|
format!("Error create path {}: {}",&path.display(), e)
|
||||||
|
));
|
||||||
|
// std::process::exit(2)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Ok(())
|
||||||
|
};
|
||||||
|
if file_path.is_empty() || data.is_empty() {
|
||||||
|
return Err(Error::new(
|
||||||
|
ErrorKind::InvalidInput,
|
||||||
|
format!("Error save {}",&file_path)
|
||||||
|
));
|
||||||
|
}
|
||||||
|
if ! Path::new(&file_path).exists() {
|
||||||
|
let path = PathBuf::from(&file_path);
|
||||||
|
if let Some(dir_path) = path.parent() {
|
||||||
|
if ! Path::new(&dir_path).exists() {
|
||||||
|
if let Some(parent_dir_path) = dir_path.parent() {
|
||||||
|
if ! Path::new(&parent_dir_path).exists() {
|
||||||
|
let res = check_path(&parent_dir_path);
|
||||||
|
if res.is_err() { return res; }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
let res = check_path(&dir_path);
|
||||||
|
if res.is_err() { return res; }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if overwrite || ! Path::new(&file_path).exists() {
|
||||||
|
fs::write(&file_path, data)?;
|
||||||
|
println!("Overwrite: {}",&file_path);
|
||||||
|
} else {
|
||||||
|
let sid_settings_file = fs::OpenOptions::new()
|
||||||
|
.write(true)
|
||||||
|
.append(true) // This is needed to append to file
|
||||||
|
.open(&file_path);
|
||||||
|
if let Ok(mut file) = sid_settings_file {
|
||||||
|
file.write_all(data.as_bytes())?;
|
||||||
|
}
|
||||||
|
println!("write: {}",&file_path);
|
||||||
|
}
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
/*
|
||||||
|
fn fix_item_path(&mut self, item: String ) -> String {
|
||||||
|
if !item.is_empty() && ! Path::new(&item).exists() {
|
||||||
|
format!("{}/{}",&self.root_path,&item)
|
||||||
|
} else {
|
||||||
|
item
|
||||||
|
}
|
||||||
|
}
|
||||||
|
pub fn load_items(&mut self) {
|
||||||
|
self.fix_root_path::<Config>(self.root_path.to_owned());
|
||||||
|
if !self.path_menu_items.is_empty() {
|
||||||
|
self.path_menu_items = self.fix_item_path(self.path_menu_items.to_owned());
|
||||||
|
let data_menu_items = load_from_file(&self.path_menu_items.to_owned(), "menu_items").unwrap_or_else(|e|{
|
||||||
|
error!("Error loading menu_items from {}: {}",&self.path_menu_items,e);
|
||||||
|
DataMenuItems::default()
|
||||||
|
});
|
||||||
|
self.ui.web_menu_items = data_menu_items.web_menu_items;
|
||||||
|
}
|
||||||
|
if !self.path_serv_paths.is_empty() {
|
||||||
|
self.path_serv_paths = self.fix_item_path(self.path_serv_paths.to_owned());
|
||||||
|
let data_serv_paths = load_from_file(&self.path_serv_paths.to_owned(), "serv_paths").unwrap_or_else(|e|{
|
||||||
|
error!("Error loading serv_paths from {}: {}",&self.path_serv_paths,e);
|
||||||
|
DataServPath::default()
|
||||||
|
});
|
||||||
|
self.serv_paths = data_serv_paths.serv_paths;
|
||||||
|
}
|
||||||
|
if !self.path_locales_config.is_empty() {
|
||||||
|
self.path_locales_config = self.fix_item_path(self.path_locales_config.to_owned());
|
||||||
|
self.locales = load_dict_from_file(&self.path_locales_config.to_owned(), "locales").unwrap_or_else(|e|{
|
||||||
|
error!("Error loading locales from {}: {}",&self.path_locales_config,e);
|
||||||
|
HashMap::new()
|
||||||
|
});
|
||||||
|
}
|
||||||
|
if self.users_store_uri.starts_with(FILE_SCHEME) {
|
||||||
|
self.users_store_uri = format!("{}{}",
|
||||||
|
FILE_SCHEME, self.fix_item_path(self.users_store_uri.replace(FILE_SCHEME,"")));
|
||||||
|
}
|
||||||
|
if self.session_store_uri.starts_with(FILE_SCHEME) {
|
||||||
|
self.session_store_uri = format!("{}{}",
|
||||||
|
FILE_SCHEME, self.fix_item_path(self.session_store_uri.replace(FILE_SCHEME,"")));
|
||||||
|
}
|
||||||
|
if self.trace_store_uri.starts_with(FILE_SCHEME) {
|
||||||
|
self.trace_store_uri = format!("{}{}",
|
||||||
|
FILE_SCHEME, self.fix_item_path(self.trace_store_uri.replace(FILE_SCHEME,"")));
|
||||||
|
}
|
||||||
|
self.cert_file = self.fix_item_path(self.cert_file.to_owned());
|
||||||
|
self.key_file = self.fix_item_path(self.key_file.to_owned());
|
||||||
|
self.templates_path = self.fix_item_path(self.templates_path.to_owned());
|
||||||
|
self.defaults_path = self.fix_item_path(self.defaults_path.to_owned());
|
||||||
|
|
||||||
|
#[cfg(feature = "authstore")]
|
||||||
|
if self.authz_store_uri.starts_with(FILE_SCHEME) {
|
||||||
|
self.authz_store_uri = format!("{}{}",
|
||||||
|
FILE_SCHEME, self.fix_item_path(self.authz_store_uri.replace(FILE_SCHEME,"")));
|
||||||
|
}
|
||||||
|
#[cfg(feature = "casbin")]
|
||||||
|
{
|
||||||
|
self.authz_model_path = self.fix_item_path(self.authz_model_path.to_owned());
|
||||||
|
self.authz_policy_path = self.fix_item_path(self.authz_policy_path.to_owned());
|
||||||
|
}
|
||||||
|
self.paseto.public_path = self.fix_item_path(self.paseto.public_path.to_owned());
|
||||||
|
self.paseto.secret_path = self.fix_item_path(self.paseto.secret_path.to_owned());
|
||||||
|
(self.paseto.public_data, self.paseto.secret_data) = self.paseto.load_data();
|
||||||
|
self.paseto.footer = ConfigPaSeToken::make_footer(
|
||||||
|
self.paseto.map_footer.to_owned()
|
||||||
|
).unwrap_or(Footer::new());
|
||||||
|
}
|
||||||
|
#[allow(dead_code)]
|
||||||
|
pub fn to_json(&self) -> String {
|
||||||
|
serde_json::to_string(self).unwrap_or_else(|e|{
|
||||||
|
println!("Error to convert Config to json: {}",e);
|
||||||
|
String::from("")
|
||||||
|
})
|
||||||
|
}
|
||||||
|
// #[allow(dead_code)]
|
||||||
|
// pub fn st_html_path(&self) -> &'static str {
|
||||||
|
// Box::leak(self.html_path.to_owned().into_boxed_str())
|
||||||
|
// }
|
||||||
|
#[allow(dead_code)]
|
||||||
|
pub fn full_html_url(&self, url: &str) -> String {
|
||||||
|
format!("{}://{}:{}/{}",
|
||||||
|
&self.protocol,&self.bind,&self.port,
|
||||||
|
url
|
||||||
|
)
|
||||||
|
}
|
||||||
|
*/
|
||||||
|
}
|
@ -12,13 +12,18 @@ use openidconnect::{
|
|||||||
CoreProviderMetadata,
|
CoreProviderMetadata,
|
||||||
CoreResponseType,
|
CoreResponseType,
|
||||||
},
|
},
|
||||||
|
http::{
|
||||||
|
HeaderMap,
|
||||||
|
header::CONTENT_TYPE,
|
||||||
|
Method,
|
||||||
|
},
|
||||||
reqwest::async_http_client, HttpRequest,
|
reqwest::async_http_client, HttpRequest,
|
||||||
AuthenticationFlow,
|
AuthenticationFlow,
|
||||||
ClientId, ClientSecret, CsrfToken, IssuerUrl, Nonce,
|
ClientId, ClientSecret, CsrfToken, IssuerUrl, Nonce,
|
||||||
RedirectUrl, Scope, PkceCodeChallenge, PkceCodeVerifier,
|
RedirectUrl, Scope, PkceCodeChallenge, PkceCodeVerifier,
|
||||||
};
|
};
|
||||||
|
|
||||||
use axum::{http::method::Method, http::HeaderMap, http::header::CONTENT_TYPE};
|
// use axum::{http::method::Method, http::HeaderMap, http::header::CONTENT_TYPE};
|
||||||
|
|
||||||
use crate::defs::Config;
|
use crate::defs::Config;
|
||||||
|
|
||||||
|
@ -1,4 +1,4 @@
|
|||||||
use axum::http::{header::{HeaderValue},uri::Uri};
|
use axum::http::{header::HeaderValue,uri::Uri};
|
||||||
use html_minifier::HTMLMinifier;
|
use html_minifier::HTMLMinifier;
|
||||||
use std::{
|
use std::{
|
||||||
error::Error,
|
error::Error,
|
||||||
@ -65,6 +65,7 @@ impl<'a> ReqHandler<'a> {
|
|||||||
context.insert("main_name", &app_dbs.config.ui.main_name);
|
context.insert("main_name", &app_dbs.config.ui.main_name);
|
||||||
context.insert("title", &app_dbs.config.ui.title);
|
context.insert("title", &app_dbs.config.ui.title);
|
||||||
context.insert("subtitle", &app_dbs.config.ui.subtitle);
|
context.insert("subtitle", &app_dbs.config.ui.subtitle);
|
||||||
|
context.insert("req_settings", &app_dbs.config.req_settings);
|
||||||
context.insert("usr_roles", &auth_state.user_roles());
|
context.insert("usr_roles", &auth_state.user_roles());
|
||||||
let user_items = User::hash_items(&auth_state.user_items());
|
let user_items = User::hash_items(&auth_state.user_items());
|
||||||
context.insert("usr_items", &user_items);
|
context.insert("usr_items", &user_items);
|
||||||
@ -98,16 +99,16 @@ impl<'a> ReqHandler<'a> {
|
|||||||
pub fn prepare_response(&mut self) {
|
pub fn prepare_response(&mut self) {
|
||||||
// self.req_header.header.contains_key(axum::http::header::CONTENT_TYPE)
|
// self.req_header.header.contains_key(axum::http::header::CONTENT_TYPE)
|
||||||
if self.req_header.is_browser() || self.req_header.is_wget() {
|
if self.req_header.is_browser() || self.req_header.is_wget() {
|
||||||
self.req_header.header.append(axum::http::header::CONTENT_TYPE,
|
self.req_header.header.append(axum::http::header::CONTENT_TYPE,
|
||||||
HeaderValue::try_from("text/html; charset=utf-8")
|
HeaderValue::try_from("text/html; charset=utf-8")
|
||||||
.expect("URI isn't a valid header value")
|
.expect("URI isn't a valid header value")
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
pub fn render_template(&mut self,template_file: &str, dflt_content: &str) -> String {
|
pub fn render_template(&mut self,template_file: &str, dflt_content: &str) -> String {
|
||||||
self.context.insert("page", &template_file.replace(".j2","").replace("html/", "").as_str());
|
self.context.insert("page", &template_file.replace(".j2","").replace("html/", "").as_str());
|
||||||
if template_file.contains("md") || template_file.contains("sample") || template_file.contains("code") {
|
if template_file.contains("md") || template_file.contains("sample") || template_file.contains("code") {
|
||||||
self.context.insert("with_code", "true");
|
self.context.insert("with_code", "true");
|
||||||
}
|
}
|
||||||
match self.app_dbs.tera.render(&template_file, &self.context) {
|
match self.app_dbs.tera.render(&template_file, &self.context) {
|
||||||
Ok(s) => {
|
Ok(s) => {
|
||||||
@ -125,7 +126,7 @@ impl<'a> ReqHandler<'a> {
|
|||||||
},
|
},
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
s
|
s
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
Err(e) => {
|
Err(e) => {
|
||||||
@ -161,7 +162,7 @@ impl<'a> ReqHandler<'a> {
|
|||||||
}
|
}
|
||||||
#[allow(dead_code)]
|
#[allow(dead_code)]
|
||||||
pub fn get_lang(&self, key: &str) -> Local {
|
pub fn get_lang(&self, key: &str) -> Local {
|
||||||
Local::get_lang(&self.app_dbs.config.locales, key, &self.app_dbs.config.dflt_lang)
|
Local::get_lang(&self.app_dbs.config.locales, key, &self.app_dbs.config.dflt_lang)
|
||||||
}
|
}
|
||||||
pub fn new_token(&self) -> String {
|
pub fn new_token(&self) -> String {
|
||||||
if self.app_dbs.config.use_token {
|
if self.app_dbs.config.use_token {
|
||||||
@ -236,7 +237,7 @@ impl<'a> ReqHandler<'a> {
|
|||||||
pub fn otp_generate(&self) -> Result<TOTP> {
|
pub fn otp_generate(&self) -> Result<TOTP> {
|
||||||
let mut rng = rand::thread_rng();
|
let mut rng = rand::thread_rng();
|
||||||
let data_byte: [u8; 21] = rng.gen();
|
let data_byte: [u8; 21] = rng.gen();
|
||||||
let base32_string = base32::encode(base32::Alphabet::RFC4648 { padding: false }, &data_byte);
|
let base32_string = base32::encode(base32::Alphabet::Rfc4648 { padding: false }, &data_byte);
|
||||||
match self.otp_make(&base32_string, "") {
|
match self.otp_make(&base32_string, "") {
|
||||||
Ok(totp) => Ok(totp),
|
Ok(totp) => Ok(totp),
|
||||||
Err(e) =>
|
Err(e) =>
|
||||||
|
@ -1,5 +1,4 @@
|
|||||||
use serde::{Serialize, Deserialize, Deserializer};
|
use serde::{Serialize, Deserialize };
|
||||||
use std::collections::HashMap;
|
|
||||||
|
|
||||||
fn default_config_resource() -> String {
|
fn default_config_resource() -> String {
|
||||||
String::from("")
|
String::from("")
|
||||||
@ -7,9 +6,6 @@ fn default_config_resource() -> String {
|
|||||||
fn default_sitewith() -> Vec<String> {
|
fn default_sitewith() -> Vec<String> {
|
||||||
Vec::new()
|
Vec::new()
|
||||||
}
|
}
|
||||||
fn default_config_tpls() -> HashMap<String,String> {
|
|
||||||
HashMap::new()
|
|
||||||
}
|
|
||||||
#[derive(Debug, Clone, Serialize, Deserialize, Default)]
|
#[derive(Debug, Clone, Serialize, Deserialize, Default)]
|
||||||
pub struct ReqSettings {
|
pub struct ReqSettings {
|
||||||
pub name: String,
|
pub name: String,
|
||||||
@ -19,6 +15,8 @@ pub struct ReqSettings {
|
|||||||
#[serde(default = "default_config_resource")]
|
#[serde(default = "default_config_resource")]
|
||||||
pub url: String,
|
pub url: String,
|
||||||
#[serde(default = "default_config_resource")]
|
#[serde(default = "default_config_resource")]
|
||||||
|
pub author_url: String,
|
||||||
|
#[serde(default = "default_config_resource")]
|
||||||
pub trace_url: String,
|
pub trace_url: String,
|
||||||
#[serde(default = "default_config_resource")]
|
#[serde(default = "default_config_resource")]
|
||||||
pub title: String,
|
pub title: String,
|
||||||
@ -26,8 +24,6 @@ pub struct ReqSettings {
|
|||||||
pub subtitle: String,
|
pub subtitle: String,
|
||||||
#[serde(default = "default_config_resource")]
|
#[serde(default = "default_config_resource")]
|
||||||
pub pagetitle: String,
|
pub pagetitle: String,
|
||||||
#[serde(default = "default_config_tpls")]
|
|
||||||
pub tpls: HashMap<String,String>,
|
|
||||||
#[serde(default = "default_config_resource")]
|
#[serde(default = "default_config_resource")]
|
||||||
pub sid: String,
|
pub sid: String,
|
||||||
#[serde(default = "default_sitewith")]
|
#[serde(default = "default_sitewith")]
|
||||||
|
@ -13,6 +13,7 @@ pub(crate) use users::{
|
|||||||
users_password_router_handlers,
|
users_password_router_handlers,
|
||||||
users_settings_router_handlers,
|
users_settings_router_handlers,
|
||||||
users_invite_router_handlers,
|
users_invite_router_handlers,
|
||||||
|
forms_router_handlers,
|
||||||
};
|
};
|
||||||
|
|
||||||
pub(crate) use other_handlers::{
|
pub(crate) use other_handlers::{
|
||||||
|
@ -51,12 +51,12 @@ pub async fn add_session_cookie(make: bool, cookies: &Cookies, session_token: &s
|
|||||||
if result_store.is_empty() {
|
if result_store.is_empty() {
|
||||||
eprintln!("Unable to store session {}", &app_dbs.config.session_store_uri);
|
eprintln!("Unable to store session {}", &app_dbs.config.session_store_uri);
|
||||||
} else {
|
} else {
|
||||||
let cookie = Cookie::build(SESSION_COOKIE_NAME, result_store.to_owned())
|
let cookie = Cookie::build((SESSION_COOKIE_NAME, result_store.to_owned()))
|
||||||
// .domain(domain)
|
// .domain(domain)
|
||||||
.path(format!("{}",cookie_path))
|
.path(format!("{}",cookie_path))
|
||||||
.secure(true)
|
.secure(true)
|
||||||
.http_only(true)
|
.http_only(true)
|
||||||
.finish();
|
.build();
|
||||||
if make {
|
if make {
|
||||||
cookies.add(cookie);
|
cookies.add(cookie);
|
||||||
}
|
}
|
||||||
@ -171,7 +171,7 @@ pub async fn rewrite_request_uri(
|
|||||||
// try with email
|
// try with email
|
||||||
let mut lock = enforcer.write().await;
|
let mut lock = enforcer.write().await;
|
||||||
let result = lock.enforce_mut(
|
let result = lock.enforce_mut(
|
||||||
vec![
|
vec![
|
||||||
name,
|
name,
|
||||||
target_path.to_owned(),
|
target_path.to_owned(),
|
||||||
req_method.to_owned()
|
req_method.to_owned()
|
||||||
@ -184,7 +184,7 @@ pub async fn rewrite_request_uri(
|
|||||||
if result { return Ok(next.run(req).await); }
|
if result { return Ok(next.run(req).await); }
|
||||||
let new_uri = format!("{}",serv_path.not_auth);
|
let new_uri = format!("{}",serv_path.not_auth);
|
||||||
let agent = if let Some(user_agent) = req.headers().get(USER_AGENT) {
|
let agent = if let Some(user_agent) = req.headers().get(USER_AGENT) {
|
||||||
user_agent.to_str().unwrap_or("").to_owned()
|
user_agent.to_str().unwrap_or("").to_owned()
|
||||||
} else {
|
} else {
|
||||||
String::from("")
|
String::from("")
|
||||||
};
|
};
|
||||||
|
@ -2,6 +2,7 @@ mod login_handlers;
|
|||||||
mod password_handlers;
|
mod password_handlers;
|
||||||
mod settings_handlers;
|
mod settings_handlers;
|
||||||
mod invite_handlers;
|
mod invite_handlers;
|
||||||
|
mod forms_handlers;
|
||||||
mod login;
|
mod login;
|
||||||
|
|
||||||
pub(crate) use login::login_user;
|
pub(crate) use login::login_user;
|
||||||
@ -9,3 +10,4 @@ pub(crate) use login_handlers::users_login_router_handlers;
|
|||||||
pub(crate) use password_handlers::users_password_router_handlers;
|
pub(crate) use password_handlers::users_password_router_handlers;
|
||||||
pub(crate) use invite_handlers::users_invite_router_handlers;
|
pub(crate) use invite_handlers::users_invite_router_handlers;
|
||||||
pub(crate) use settings_handlers::users_settings_router_handlers;
|
pub(crate) use settings_handlers::users_settings_router_handlers;
|
||||||
|
pub(crate) use forms_handlers::forms_router_handlers;
|
||||||
|
207
src/handlers/users/forms_handlers.rs
Normal file
207
src/handlers/users/forms_handlers.rs
Normal file
@ -0,0 +1,207 @@
|
|||||||
|
use std::sync::Arc;
|
||||||
|
use axum::{
|
||||||
|
http::{
|
||||||
|
StatusCode,
|
||||||
|
Uri,
|
||||||
|
header::HeaderMap,
|
||||||
|
},
|
||||||
|
Json,
|
||||||
|
routing::{get,post},
|
||||||
|
Extension,
|
||||||
|
extract::ConnectInfo,
|
||||||
|
response::{IntoResponse,Response,Redirect},
|
||||||
|
Router,
|
||||||
|
};
|
||||||
|
use serde_json::{json,Value};
|
||||||
|
use tower_cookies::Cookies;
|
||||||
|
//use log::{trace,error};
|
||||||
|
use log::error;
|
||||||
|
|
||||||
|
use crate::{
|
||||||
|
route,
|
||||||
|
defs::{
|
||||||
|
AppDBs,
|
||||||
|
ReqHandler,
|
||||||
|
ReqHeaderMap,
|
||||||
|
Random,
|
||||||
|
AppConnectInfo,
|
||||||
|
FormDefs,
|
||||||
|
},
|
||||||
|
users::{
|
||||||
|
User,
|
||||||
|
// UserData,
|
||||||
|
// UserItem,
|
||||||
|
OpenidUser,
|
||||||
|
},
|
||||||
|
handlers::{
|
||||||
|
// add_session_cookie,
|
||||||
|
get_auth_state,
|
||||||
|
// is_allowed,
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
|
pub fn forms_router_handlers() -> Router {
|
||||||
|
async fn form_handler(
|
||||||
|
header: HeaderMap,
|
||||||
|
uri: Uri,
|
||||||
|
Extension(app_dbs): Extension<Arc<AppDBs>>,
|
||||||
|
Extension(cookies): Extension<Cookies>,
|
||||||
|
Extension(random): Extension<Random>,
|
||||||
|
ConnectInfo(app_connect_info): ConnectInfo<AppConnectInfo>,
|
||||||
|
axum::extract::Path(data): axum::extract::Path<String>,
|
||||||
|
) -> Response {
|
||||||
|
let auth_state = get_auth_state(true, &cookies, &app_dbs).await;
|
||||||
|
if auth_state.session.is_none() {
|
||||||
|
return Redirect::temporary( &format!("/login?o={}",uri.path().to_string())).into_response();
|
||||||
|
}
|
||||||
|
let mut req_handler = ReqHandler::new(
|
||||||
|
ReqHeaderMap::new(header, &format!("{}",&uri.path().to_string()), &app_connect_info),
|
||||||
|
&app_dbs,
|
||||||
|
&uri,
|
||||||
|
&auth_state,
|
||||||
|
&random,
|
||||||
|
"user_settings_handler"
|
||||||
|
);
|
||||||
|
let mut res_headers = HeaderMap::new();
|
||||||
|
if req_handler.req_header.is_browser() {
|
||||||
|
res_headers.append(axum::http::header::CONTENT_TYPE,"text/html; charset=utf-8".parse().unwrap());
|
||||||
|
}
|
||||||
|
let user_id = auth_state.user_id();
|
||||||
|
if user_id.is_empty() {
|
||||||
|
let _ = req_handler.trace_req(format!("user not id found"));
|
||||||
|
// User not exists
|
||||||
|
return Redirect::temporary( &format!("/")).into_response();
|
||||||
|
}
|
||||||
|
let user_sel = User::select("id", &user_id, true, &app_dbs.user_store).await.unwrap_or_default();
|
||||||
|
if user_sel.name.is_empty() {
|
||||||
|
let _ = req_handler.trace_req(format!("Edit user id '{}' not found ",&user_id));
|
||||||
|
// User not exists
|
||||||
|
return Redirect::temporary( &format!("/")).into_response();
|
||||||
|
}
|
||||||
|
let openid_sel = OpenidUser::list_selection("userid", &user_sel.id.to_string(), &app_dbs.user_store, true,false, "|").await.unwrap_or_else(|e| {
|
||||||
|
error!("Error list selection {}: {}", &user_sel.name, e);
|
||||||
|
Vec::new()
|
||||||
|
});
|
||||||
|
|
||||||
|
let form_defs = FormDefs::load_from(&format!("{}/{}.toml",&app_dbs.config.forms_path, &data), &data);
|
||||||
|
|
||||||
|
req_handler.context.insert("openid_sel", &openid_sel);
|
||||||
|
let openid_sel_appkeys = openid_sel.iter().map(|id| id.appkey.to_string()).collect::<Vec<String>>().join(",");
|
||||||
|
req_handler.context.insert("openid_sel_appkeys", &openid_sel_appkeys);
|
||||||
|
req_handler.context.insert("with_menu", "1");
|
||||||
|
req_handler.context.insert("user", &user_sel);
|
||||||
|
req_handler.context.insert("admin_fields", &app_dbs.config.admin_fields);
|
||||||
|
req_handler.context.insert("totp_mode", &format!("{}",&app_dbs.config.totp_mode));
|
||||||
|
// let user_items = User::hash_items(&user_sel.items);
|
||||||
|
// req_handler.context.insert("usr_items", &user_items);
|
||||||
|
req_handler.context.insert("no_edit", "true");
|
||||||
|
req_handler.context.insert("edit_target", "main");
|
||||||
|
req_handler.context.insert("form_defs", &form_defs);
|
||||||
|
let result = if let Some(tpl) = app_dbs.config.tpls.get("form") {
|
||||||
|
req_handler.render_template(&tpl,"form")
|
||||||
|
} else {
|
||||||
|
String::from("user settings")
|
||||||
|
};
|
||||||
|
let _ = req_handler.trace_req(format!("User '{}' form",&user_sel.id));
|
||||||
|
(
|
||||||
|
res_headers,
|
||||||
|
result.to_owned()
|
||||||
|
).into_response()
|
||||||
|
}
|
||||||
|
async fn post_form_handler(
|
||||||
|
header: HeaderMap,
|
||||||
|
uri: Uri,
|
||||||
|
Extension(app_dbs): Extension<Arc<AppDBs>>,
|
||||||
|
Extension(cookies): Extension<Cookies>,
|
||||||
|
Extension(random): Extension<Random>,
|
||||||
|
ConnectInfo(app_connect_info): ConnectInfo<AppConnectInfo>,
|
||||||
|
axum::extract::Path(form): axum::extract::Path<String>,
|
||||||
|
Json(form_data): Json<Value>,
|
||||||
|
|
||||||
|
) -> Response {
|
||||||
|
dbg!(&form_data);
|
||||||
|
let str_data=serde_json::to_string(&form_data).unwrap_or_else(|e|{
|
||||||
|
println!("from_data error: {}",e);
|
||||||
|
String::from("")
|
||||||
|
});
|
||||||
|
dbg!(&str_data);
|
||||||
|
let auth_state = get_auth_state(true, &cookies, &app_dbs).await;
|
||||||
|
if auth_state.session.is_none() {
|
||||||
|
return Redirect::temporary( &format!("/login?o={}",uri.path().to_string())).into_response();
|
||||||
|
}
|
||||||
|
let req_handler = ReqHandler::new(
|
||||||
|
ReqHeaderMap::new(header, &format!("{}",&uri.path().to_string()), &app_connect_info),
|
||||||
|
&app_dbs,
|
||||||
|
&uri,
|
||||||
|
&auth_state,
|
||||||
|
&random,
|
||||||
|
"user_settings_handler"
|
||||||
|
);
|
||||||
|
//let mut res_headers = HeaderMap::new();
|
||||||
|
//if req_handler.req_header.is_browser() {
|
||||||
|
// res_headers.append(axum::http::header::CONTENT_TYPE,"text/html; charset=utf-8".parse().unwrap());
|
||||||
|
//}
|
||||||
|
let user_id = auth_state.user_id();
|
||||||
|
if user_id.is_empty() {
|
||||||
|
let _ = req_handler.trace_req(format!("user not id found"));
|
||||||
|
// User not exists
|
||||||
|
return Redirect::temporary( &format!("/")).into_response();
|
||||||
|
}
|
||||||
|
let user_sel = User::select("id", &user_id, true, &app_dbs.user_store).await.unwrap_or_default();
|
||||||
|
if user_sel.name.is_empty() {
|
||||||
|
let _ = req_handler.trace_req(format!("Edit user id '{}' not found ",&user_id));
|
||||||
|
// User not exists
|
||||||
|
return Redirect::temporary( &format!("/")).into_response();
|
||||||
|
}
|
||||||
|
let response_path = format!("{}/{}/{}.json",&app_dbs.config.forms_responses_path,&user_id,&form);
|
||||||
|
let form_defs = FormDefs::load_from(&format!("{}/{}.toml",&app_dbs.config.forms_path, &form), &form);
|
||||||
|
let write_res = match form_defs.write_data(&response_path, &str_data, form_defs.overwrite_response) {
|
||||||
|
Ok(_) => "done",
|
||||||
|
Err(e) => {
|
||||||
|
println!("Error write {}: {}",&response_path, e);
|
||||||
|
"error"
|
||||||
|
}
|
||||||
|
};
|
||||||
|
let json_result = json!(
|
||||||
|
{
|
||||||
|
"form": form,
|
||||||
|
"status": write_res,
|
||||||
|
}
|
||||||
|
);
|
||||||
|
let result=serde_json::to_string(&json_result).unwrap_or_default();
|
||||||
|
(
|
||||||
|
StatusCode::OK,
|
||||||
|
req_handler.req_header.header,
|
||||||
|
result
|
||||||
|
).into_response()
|
||||||
|
// Redirect::temporary( &format!("/")).into_response()
|
||||||
|
/*
|
||||||
|
//let form_defs = FormDefs::load_from(&format!("{}/{}.toml",&app_dbs.config.forms_path, &data), &data);
|
||||||
|
//req_handler.context.insert("openid_sel", &openid_sel);
|
||||||
|
//let openid_sel_appkeys = openid_sel.iter().map(|id| id.appkey.to_string()).collect::<Vec<String>>().join(",");
|
||||||
|
..req_handler.context.insert("openid_sel_appkeys", &openid_sel_appkeys);
|
||||||
|
req_handler.context.insert("with_menu", "1");
|
||||||
|
req_handler.context.insert("user", &user_sel);
|
||||||
|
req_handler.context.insert("admin_fields", &app_dbs.config.admin_fields);
|
||||||
|
req_handler.context.insert("totp_mode", &format!("{}",&app_dbs.config.totp_mode));
|
||||||
|
// let user_items = User::hash_items(&user_sel.items);
|
||||||
|
// req_handler.context.insert("usr_items", &user_items);
|
||||||
|
req_handler.context.insert("no_edit", "true");
|
||||||
|
req_handler.context.insert("edit_target", "main");
|
||||||
|
req_handler.context.insert("form_defs", &form_defs);
|
||||||
|
let result = if let Some(tpl) = app_dbs.config.tpls.get("form") {
|
||||||
|
req_handler.render_template(&tpl,"form")
|
||||||
|
} else {
|
||||||
|
String::from("user settings")
|
||||||
|
};
|
||||||
|
let _ = req_handler.trace_req(format!("User '{}' form",&user_sel.id));
|
||||||
|
(
|
||||||
|
res_headers,
|
||||||
|
result.to_owned()
|
||||||
|
).into_response()
|
||||||
|
*/
|
||||||
|
}
|
||||||
|
route(
|
||||||
|
"/form/:item", get(form_handler))
|
||||||
|
.route("/form/:item", post(post_form_handler))
|
||||||
|
}
|
@ -18,7 +18,6 @@ use log::{trace,error};
|
|||||||
|
|
||||||
use crate::{
|
use crate::{
|
||||||
SESSION_COOKIE_NAME,
|
SESSION_COOKIE_NAME,
|
||||||
DEFAULT_ROLES,
|
|
||||||
route,
|
route,
|
||||||
defs::{
|
defs::{
|
||||||
AppDBs,
|
AppDBs,
|
||||||
@ -90,8 +89,10 @@ pub fn users_login_router_handlers() -> Router {
|
|||||||
if req_handler.req_header.is_browser() {
|
if req_handler.req_header.is_browser() {
|
||||||
res_headers.append(axum::http::header::CONTENT_TYPE,"text/html; charset=utf-8".parse().unwrap());
|
res_headers.append(axum::http::header::CONTENT_TYPE,"text/html; charset=utf-8".parse().unwrap());
|
||||||
}
|
}
|
||||||
|
req_handler.context.insert("default_roles", &app_dbs.config.default_roles.join(","));
|
||||||
req_handler.context.insert("password_score", &app_dbs.config.password_score);
|
req_handler.context.insert("password_score", &app_dbs.config.password_score);
|
||||||
req_handler.context.insert("totp_mode", &format!("{}",&app_dbs.config.totp_mode));
|
req_handler.context.insert("totp_mode", &format!("{}",&app_dbs.config.totp_mode));
|
||||||
|
req_handler.context.insert("openid_auths", &app_dbs.config.openid_auths.clone().into_keys().collect::<Vec<String>>());
|
||||||
// req_handler.context.insert("with_menu", "1");
|
// req_handler.context.insert("with_menu", "1");
|
||||||
if app_dbs.config.totp_mode != TotpMode::No {
|
if app_dbs.config.totp_mode != TotpMode::No {
|
||||||
match req_handler.otp_generate() {
|
match req_handler.otp_generate() {
|
||||||
@ -229,7 +230,7 @@ pub fn users_login_router_handlers() -> Router {
|
|||||||
let roles = if ! user_data.roles.is_empty() {
|
let roles = if ! user_data.roles.is_empty() {
|
||||||
user_data.roles.to_owned()
|
user_data.roles.to_owned()
|
||||||
} else {
|
} else {
|
||||||
DEFAULT_ROLES.to_owned()
|
app_dbs.config.default_roles.clone().join(",")
|
||||||
};
|
};
|
||||||
let is_admin = if user_data.id == "A" || get_total_users(&app_dbs.user_store).await < 1 {
|
let is_admin = if user_data.id == "A" || get_total_users(&app_dbs.user_store).await < 1 {
|
||||||
true
|
true
|
||||||
@ -256,6 +257,7 @@ pub fn users_login_router_handlers() -> Router {
|
|||||||
status: UserStatus::Created,
|
status: UserStatus::Created,
|
||||||
items: User::json_items(new_items),
|
items: User::json_items(new_items),
|
||||||
isadmin: is_admin,
|
isadmin: is_admin,
|
||||||
|
openids: user_data.openids.to_owned(),
|
||||||
roles,
|
roles,
|
||||||
};
|
};
|
||||||
let usr_sel = User::select("name", &user_data.name, false, &app_dbs.user_store).await.unwrap_or_default();
|
let usr_sel = User::select("name", &user_data.name, false, &app_dbs.user_store).await.unwrap_or_default();
|
||||||
@ -381,7 +383,8 @@ pub fn users_login_router_handlers() -> Router {
|
|||||||
match openid_conf.client().await {
|
match openid_conf.client().await {
|
||||||
Ok(openid_cli) => openid_cli.get_data(&data),
|
Ok(openid_cli) => openid_cli.get_data(&data),
|
||||||
Err(e) => {
|
Err(e) => {
|
||||||
error!("Error openid client data found for {} handler: {}", &data, e);
|
dbg!("Error openid client data found for {} handler: {}", &data, e);
|
||||||
|
// error!("Error openid client data found for {} handler: {}", &data, e);
|
||||||
(String::from(""), String::from("/login"))
|
(String::from(""), String::from("/login"))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -390,6 +393,7 @@ pub fn users_login_router_handlers() -> Router {
|
|||||||
error!("Error no openid client found for: {}", &data);
|
error!("Error no openid client found for: {}", &data);
|
||||||
(String::from(""), String::from("/login"))
|
(String::from(""), String::from("/login"))
|
||||||
};
|
};
|
||||||
|
dbg!(&str_user_data, &url);
|
||||||
let session_token = req_handler.new_token();
|
let session_token = req_handler.new_token();
|
||||||
let session_cookie = add_session_cookie(true,&cookies, &session_token, &str_user_data, 0, &app_dbs, "/").await;
|
let session_cookie = add_session_cookie(true,&cookies, &session_token, &str_user_data, 0, &app_dbs, "/").await;
|
||||||
if app_dbs.config.verbose > 1 { println!("session cookie: {}", &session_cookie) };
|
if app_dbs.config.verbose > 1 { println!("session cookie: {}", &session_cookie) };
|
||||||
|
@ -122,6 +122,7 @@ pub fn users_settings_router_handlers() -> Router {
|
|||||||
// req_handler.context.insert("usr_items", &user_items);
|
// req_handler.context.insert("usr_items", &user_items);
|
||||||
req_handler.context.insert("no_edit", "true");
|
req_handler.context.insert("no_edit", "true");
|
||||||
req_handler.context.insert("edit_target", "main");
|
req_handler.context.insert("edit_target", "main");
|
||||||
|
req_handler.context.insert("openid_auths", &app_dbs.config.openid_auths.clone().into_keys().collect::<Vec<String>>());
|
||||||
let result = if let Some(tpl) = app_dbs.config.tpls.get("user_settings") {
|
let result = if let Some(tpl) = app_dbs.config.tpls.get("user_settings") {
|
||||||
req_handler.render_template(&tpl,"user setting")
|
req_handler.render_template(&tpl,"user setting")
|
||||||
} else {
|
} else {
|
||||||
@ -186,6 +187,7 @@ pub fn users_settings_router_handlers() -> Router {
|
|||||||
req_handler.context.insert("edit_target", &data);
|
req_handler.context.insert("edit_target", &data);
|
||||||
req_handler.context.insert("admin_fields", &app_dbs.config.admin_fields);
|
req_handler.context.insert("admin_fields", &app_dbs.config.admin_fields);
|
||||||
req_handler.context.insert("totp_mode", &format!("{}",&app_dbs.config.totp_mode));
|
req_handler.context.insert("totp_mode", &format!("{}",&app_dbs.config.totp_mode));
|
||||||
|
req_handler.context.insert("openid_auths", &app_dbs.config.openid_auths.clone().into_keys().collect::<Vec<String>>());
|
||||||
if data == "totp" && app_dbs.config.totp_mode != TotpMode::No {
|
if data == "totp" && app_dbs.config.totp_mode != TotpMode::No {
|
||||||
if !user_sel.otp_base32.is_empty() {
|
if !user_sel.otp_base32.is_empty() {
|
||||||
match req_handler.otp_make(&user_sel.otp_base32, &user_sel.otp_defs) {
|
match req_handler.otp_make(&user_sel.otp_base32, &user_sel.otp_defs) {
|
||||||
@ -329,7 +331,7 @@ pub fn users_settings_router_handlers() -> Router {
|
|||||||
user_sel.otp_auth_url = String::from("");
|
user_sel.otp_auth_url = String::from("");
|
||||||
user_sel.otp_defs = String::from("");
|
user_sel.otp_defs = String::from("");
|
||||||
}
|
}
|
||||||
let user_openids = user_data.opendis.to_owned();
|
let user_openid = user_data.openids.to_owned();
|
||||||
user_sel.from_data(user_data);
|
user_sel.from_data(user_data);
|
||||||
let new_id= user_sel.id.to_string();
|
let new_id= user_sel.id.to_string();
|
||||||
let user_data = user_sel.session_data();
|
let user_data = user_sel.session_data();
|
||||||
@ -339,7 +341,7 @@ pub fn users_settings_router_handlers() -> Router {
|
|||||||
let session_cookie = add_session_cookie(true,&cookies, &session_token, &user_data, 0, &app_dbs, "/").await;
|
let session_cookie = add_session_cookie(true,&cookies, &session_token, &user_data, 0, &app_dbs, "/").await;
|
||||||
if app_dbs.config.verbose > 1 { println!("session cookie: {}", &session_cookie) };
|
if app_dbs.config.verbose > 1 { println!("session cookie: {}", &session_cookie) };
|
||||||
let _ = req_handler.trace_req(format!("User '{}' updated",&user_id));
|
let _ = req_handler.trace_req(format!("User '{}' updated",&user_id));
|
||||||
OpenidUser::sync_ids(&new_id, &user_openids, &app_dbs.user_store).await;
|
OpenidUser::sync_ids(&new_id, &user_openid, &app_dbs.user_store).await;
|
||||||
let result =String::from("OK");
|
let result =String::from("OK");
|
||||||
(
|
(
|
||||||
req_handler.req_header.header,
|
req_handler.req_header.header,
|
||||||
|
@ -17,8 +17,8 @@
|
|||||||
// )]
|
// )]
|
||||||
|
|
||||||
extern crate alloc;
|
extern crate alloc;
|
||||||
#[cfg(feature = "std")]
|
//#[cfg(feature = "std")]
|
||||||
extern crate std;
|
//extern crate std;
|
||||||
|
|
||||||
use alloc::string::{String, ToString};
|
use alloc::string::{String, ToString};
|
||||||
use core::fmt;
|
use core::fmt;
|
||||||
|
19
src/main.rs
19
src/main.rs
@ -74,6 +74,7 @@ use handlers::{
|
|||||||
admin_router_handlers,
|
admin_router_handlers,
|
||||||
users_router_handlers,
|
users_router_handlers,
|
||||||
pages_router_handlers,
|
pages_router_handlers,
|
||||||
|
forms_router_handlers,
|
||||||
};
|
};
|
||||||
use crate::tools::get_socket_addr;
|
use crate::tools::get_socket_addr;
|
||||||
|
|
||||||
@ -99,7 +100,6 @@ pub const USERS_TABLENAME: &str = "users";
|
|||||||
pub const OPENID_USERS_TABLENAME: &str = "openid_users";
|
pub const OPENID_USERS_TABLENAME: &str = "openid_users";
|
||||||
pub const USERS_FILESTORE: &str = "users";
|
pub const USERS_FILESTORE: &str = "users";
|
||||||
pub const OPENID_USERS_FILESTORE: &str = "openid_users";
|
pub const OPENID_USERS_FILESTORE: &str = "openid_users";
|
||||||
pub const DEFAULT_ROLES: &str = "user";
|
|
||||||
|
|
||||||
pub fn route(path: &str, method_router: MethodRouter) -> Router {
|
pub fn route(path: &str, method_router: MethodRouter) -> Router {
|
||||||
Router::new().route(path, method_router)
|
Router::new().route(path, method_router)
|
||||||
@ -288,6 +288,7 @@ async fn main() {
|
|||||||
.merge(users_router_handlers())
|
.merge(users_router_handlers())
|
||||||
.merge(admin_router_handlers())
|
.merge(admin_router_handlers())
|
||||||
.merge(pages_router_handlers())
|
.merge(pages_router_handlers())
|
||||||
|
.merge(forms_router_handlers())
|
||||||
.layer(ServiceBuilder::new().layer(middleware))
|
.layer(ServiceBuilder::new().layer(middleware))
|
||||||
.layer(CookieManagerLayer::new())
|
.layer(CookieManagerLayer::new())
|
||||||
.layer(Extension(app_dbs))
|
.layer(Extension(app_dbs))
|
||||||
@ -297,7 +298,7 @@ async fn main() {
|
|||||||
;
|
;
|
||||||
if config.verbose > 2 { dbg!("{:?}",&origins); }
|
if config.verbose > 2 { dbg!("{:?}",&origins); }
|
||||||
if config.allow_origin.len() > 0 {
|
if config.allow_origin.len() > 0 {
|
||||||
web_router = web_router.layer(CorsLayer::new()
|
web_router = web_router.layer(CorsLayer::new()
|
||||||
.allow_origin(origins)
|
.allow_origin(origins)
|
||||||
.allow_methods(vec![Method::GET, Method::POST])
|
.allow_methods(vec![Method::GET, Method::POST])
|
||||||
.allow_headers(tower_http::cors::Any)
|
.allow_headers(tower_http::cors::Any)
|
||||||
@ -313,10 +314,10 @@ async fn main() {
|
|||||||
let listener = tokio::net::TcpListener::bind(addr).await.unwrap();
|
let listener = tokio::net::TcpListener::bind(addr).await.unwrap();
|
||||||
// web_router.into_make_service_with_connect_info::<SocketAddr>()
|
// web_router.into_make_service_with_connect_info::<SocketAddr>()
|
||||||
axum::serve(listener, web_router
|
axum::serve(listener, web_router
|
||||||
.into_make_service_with_connect_info::<AppConnectInfo>()
|
.into_make_service_with_connect_info::<AppConnectInfo>()
|
||||||
)
|
)
|
||||||
.await
|
.await
|
||||||
.unwrap();
|
.unwrap();
|
||||||
} else {
|
} else {
|
||||||
let tls_config = RustlsConfig::from_pem_file(
|
let tls_config = RustlsConfig::from_pem_file(
|
||||||
PathBuf::from(&config.cert_file),
|
PathBuf::from(&config.cert_file),
|
||||||
@ -331,10 +332,8 @@ async fn main() {
|
|||||||
web_router = web_router.layer(TraceLayer::new_for_http());
|
web_router = web_router.layer(TraceLayer::new_for_http());
|
||||||
}
|
}
|
||||||
axum_server::bind_rustls(addr, tls_config)
|
axum_server::bind_rustls(addr, tls_config)
|
||||||
.serve(
|
.serve(
|
||||||
// web_router.layer(TraceLayer::new_for_http())
|
web_router.into_make_service_with_connect_info::<AppConnectInfo>()
|
||||||
web_router
|
|
||||||
.into_make_service_with_connect_info::<AppConnectInfo>()
|
|
||||||
)
|
)
|
||||||
.await
|
.await
|
||||||
.unwrap();
|
.unwrap();
|
||||||
|
19
src/tools.rs
19
src/tools.rs
@ -1,5 +1,6 @@
|
|||||||
use std::net::{IpAddr, Ipv4Addr, SocketAddr, ToSocketAddrs};
|
use std::net::{IpAddr, Ipv4Addr, SocketAddr, ToSocketAddrs};
|
||||||
use chrono::NaiveDateTime;
|
use chrono::DateTime;
|
||||||
|
//use chrono::NaiveDateTime;
|
||||||
//use chrono::{DateTime,Local, Utc,NaiveDateTime};
|
//use chrono::{DateTime,Local, Utc,NaiveDateTime};
|
||||||
//use std::time::{UNIX_EPOCH, Duration};
|
//use std::time::{UNIX_EPOCH, Duration};
|
||||||
|
|
||||||
@ -7,13 +8,13 @@ pub fn get_socket_addr(bind: &str, port: u16) -> SocketAddr {
|
|||||||
let url = format!("{}:{}",&bind,&port);
|
let url = format!("{}:{}",&bind,&port);
|
||||||
match url.to_socket_addrs() {
|
match url.to_socket_addrs() {
|
||||||
Ok(addrs_op) => if let Some(addr) = addrs_op.to_owned().next() {
|
Ok(addrs_op) => if let Some(addr) = addrs_op.to_owned().next() {
|
||||||
addr
|
addr
|
||||||
} else {
|
} else {
|
||||||
SocketAddr::new(IpAddr::V4(Ipv4Addr::new(127, 0, 0, 1)), port.to_owned())
|
SocketAddr::new(IpAddr::V4(Ipv4Addr::new(127, 0, 0, 1)), port.to_owned())
|
||||||
}
|
}
|
||||||
Err(e) => {
|
Err(e) => {
|
||||||
eprintln!("Evironment load error: {} {}", e, url);
|
eprintln!("Evironment load error: {} {}", e, url);
|
||||||
SocketAddr::new(IpAddr::V4(Ipv4Addr::new(127, 0, 0, 1)), port.to_owned())
|
SocketAddr::new(IpAddr::V4(Ipv4Addr::new(127, 0, 0, 1)), port.to_owned())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -50,7 +51,7 @@ pub fn path_timestamp(filepath: &str) -> u32 {
|
|||||||
pub fn str_date_from_timestamp(timestamp: &str) -> String {
|
pub fn str_date_from_timestamp(timestamp: &str) -> String {
|
||||||
if timestamp.is_empty() { return String::from(""); }
|
if timestamp.is_empty() { return String::from(""); }
|
||||||
let val: i64 = timestamp.parse().unwrap_or_default();
|
let val: i64 = timestamp.parse().unwrap_or_default();
|
||||||
let datetime = NaiveDateTime::from_timestamp_opt(val, 0).unwrap_or_default(); // (Local::now());
|
let datetime = DateTime::from_timestamp(val, 0).unwrap_or_default(); // (Local::now());
|
||||||
/*
|
/*
|
||||||
let naive_utc = dt.naive_utc();
|
let naive_utc = dt.naive_utc();
|
||||||
let offset = dt.offset().clone();
|
let offset = dt.offset().clone();
|
||||||
@ -63,5 +64,5 @@ pub fn str_date_from_timestamp(timestamp: &str) -> String {
|
|||||||
// let str_timestamp = UNIX_EPOCH + Duration::from_millis(val);
|
// let str_timestamp = UNIX_EPOCH + Duration::from_millis(val);
|
||||||
// let datetime = DateTime::<Utc>::from(str_timestamp);
|
// let datetime = DateTime::<Utc>::from(str_timestamp);
|
||||||
*/
|
*/
|
||||||
datetime.format("%Y-%m-%d %H:%M:%S").to_string()
|
datetime.format("%Y-%m-%d %H:%M:%S").to_string()
|
||||||
}
|
}
|
||||||
|
@ -489,6 +489,11 @@ impl OpenidUser {
|
|||||||
println!("Error delete {}: {}",&itm.appkey,e);
|
println!("Error delete {}: {}",&itm.appkey,e);
|
||||||
false
|
false
|
||||||
});
|
});
|
||||||
|
} else {
|
||||||
|
let _res = OpenidUser::delete(itm.id, &store).await.unwrap_or_else(|e| {
|
||||||
|
println!("Error delete {}: {}",&itm.appkey,e);
|
||||||
|
false
|
||||||
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -6,6 +6,7 @@ use std::{
|
|||||||
fmt,
|
fmt,
|
||||||
collections::HashMap,
|
collections::HashMap,
|
||||||
};
|
};
|
||||||
|
use zxcvbn::zxcvbn;
|
||||||
// use std::{
|
// use std::{
|
||||||
// // sync::Arc,
|
// // sync::Arc,
|
||||||
// fmt::Debug,
|
// fmt::Debug,
|
||||||
@ -37,7 +38,7 @@ use crate::{
|
|||||||
const DISPLAY_SEPARATOR: &str = "=";
|
const DISPLAY_SEPARATOR: &str = "=";
|
||||||
|
|
||||||
fn default_user_status() -> UserStatus {
|
fn default_user_status() -> UserStatus {
|
||||||
UserStatus::default()
|
UserStatus::default()
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug, Clone, PartialEq, PartialOrd, Serialize, Deserialize,Default)]
|
#[derive(Debug, Clone, PartialEq, PartialOrd, Serialize, Deserialize,Default)]
|
||||||
@ -60,6 +61,7 @@ pub struct User {
|
|||||||
pub status: UserStatus,
|
pub status: UserStatus,
|
||||||
pub items: String,
|
pub items: String,
|
||||||
pub isadmin: bool,
|
pub isadmin: bool,
|
||||||
|
pub openids: String,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl fmt::Display for User {
|
impl fmt::Display for User {
|
||||||
@ -86,7 +88,8 @@ Created{} {}
|
|||||||
Last access{} {}
|
Last access{} {}
|
||||||
Status{} {}
|
Status{} {}
|
||||||
Items{} {}
|
Items{} {}
|
||||||
IsAdmin{} {}",
|
IsAdmin{} {}
|
||||||
|
OpenIds{} {}",
|
||||||
sep, self.id,
|
sep, self.id,
|
||||||
sep, self.name, sep, self.fullname,
|
sep, self.name, sep, self.fullname,
|
||||||
sep, self.description,
|
sep, self.description,
|
||||||
@ -101,7 +104,8 @@ IsAdmin{} {}",
|
|||||||
sep, self.created, sep, self.lastaccess,
|
sep, self.created, sep, self.lastaccess,
|
||||||
sep, self.status,
|
sep, self.status,
|
||||||
sep, self.items,
|
sep, self.items,
|
||||||
sep, self.isadmin
|
sep, self.isadmin,
|
||||||
|
sep, self.openids
|
||||||
);
|
);
|
||||||
write!(f, "{}", content)
|
write!(f, "{}", content)
|
||||||
}
|
}
|
||||||
@ -128,6 +132,7 @@ impl Entry for User {
|
|||||||
status: UserStatus::from_str(&parts[14].to_string()),
|
status: UserStatus::from_str(&parts[14].to_string()),
|
||||||
items: parts[15].to_string(),
|
items: parts[15].to_string(),
|
||||||
isadmin: if parts[16] == "TRUE" { true } else { false},
|
isadmin: if parts[16] == "TRUE" { true } else { false},
|
||||||
|
openids: parts[17].to_string(),
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -142,8 +147,8 @@ impl User {
|
|||||||
otp_base32,
|
otp_base32,
|
||||||
otp_auth_url,
|
otp_auth_url,
|
||||||
otp_defs,
|
otp_defs,
|
||||||
roles, created, lastaccess, status, items, isadmin
|
roles, created, lastaccess, status, items, openids, isadmin
|
||||||
) VALUES ( ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)", USERS_TABLENAME).as_str()
|
) VALUES ( ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)", USERS_TABLENAME).as_str()
|
||||||
)
|
)
|
||||||
.bind(self.name)
|
.bind(self.name)
|
||||||
.bind(self.fullname)
|
.bind(self.fullname)
|
||||||
@ -160,6 +165,7 @@ impl User {
|
|||||||
.bind(self.lastaccess)
|
.bind(self.lastaccess)
|
||||||
.bind(format!("{}",self.status))
|
.bind(format!("{}",self.status))
|
||||||
.bind(self.items)
|
.bind(self.items)
|
||||||
|
.bind(self.openids)
|
||||||
.bind(self.isadmin)
|
.bind(self.isadmin)
|
||||||
.execute(pool).await?;
|
.execute(pool).await?;
|
||||||
Ok(query_result.last_insert_id().unwrap_or_default())
|
Ok(query_result.last_insert_id().unwrap_or_default())
|
||||||
@ -236,6 +242,7 @@ impl User {
|
|||||||
lastaccess,
|
lastaccess,
|
||||||
status,
|
status,
|
||||||
items: row.try_get("items")?,
|
items: row.try_get("items")?,
|
||||||
|
openids: row.try_get("openids")?,
|
||||||
isadmin: row.try_get("isadmin")?,
|
isadmin: row.try_get("isadmin")?,
|
||||||
})
|
})
|
||||||
} else {
|
} else {
|
||||||
@ -258,6 +265,7 @@ impl User {
|
|||||||
"TRUE" => it.isadmin,
|
"TRUE" => it.isadmin,
|
||||||
_ => !it.isadmin,
|
_ => !it.isadmin,
|
||||||
},
|
},
|
||||||
|
"openids" => it.openids == value,
|
||||||
_ => false,
|
_ => false,
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
@ -279,12 +287,12 @@ impl User {
|
|||||||
)
|
)
|
||||||
.bind(id)
|
.bind(id)
|
||||||
.execute(pool).await?;
|
.execute(pool).await?;
|
||||||
Ok(query_result.rows_affected() > 0)
|
Ok(query_result.rows_affected() > 0)
|
||||||
},
|
},
|
||||||
UserStore::File(file_path) => {
|
UserStore::File(file_path) => {
|
||||||
let new_entries: Vec<String> =
|
let new_entries: Vec<String> =
|
||||||
Entries::<User>::new(&file_path).filter(|it| it.id != id).map(|user|
|
Entries::<User>::new(&file_path).filter(|it| it.id != id).map(|user|
|
||||||
user.line_format()
|
user.line_format()
|
||||||
).collect();
|
).collect();
|
||||||
let entries = Entries::<User>::new(&file_path);
|
let entries = Entries::<User>::new(&file_path);
|
||||||
match entries.write(&new_entries) {
|
match entries.write(&new_entries) {
|
||||||
@ -309,8 +317,9 @@ impl User {
|
|||||||
created = ?, lastaccess = ?,
|
created = ?, lastaccess = ?,
|
||||||
status = ?,
|
status = ?,
|
||||||
items = ?,
|
items = ?,
|
||||||
|
openids = ?,
|
||||||
isadmin = ?
|
isadmin = ?
|
||||||
WHERE id = ? ",
|
WHERE id = ? ",
|
||||||
USERS_TABLENAME
|
USERS_TABLENAME
|
||||||
);
|
);
|
||||||
let query_result = sqlx::query(
|
let query_result = sqlx::query(
|
||||||
@ -331,10 +340,11 @@ impl User {
|
|||||||
.bind(self.lastaccess)
|
.bind(self.lastaccess)
|
||||||
.bind(format!("{}",self.status))
|
.bind(format!("{}",self.status))
|
||||||
.bind(self.items)
|
.bind(self.items)
|
||||||
|
.bind(self.openids)
|
||||||
.bind(self.isadmin)
|
.bind(self.isadmin)
|
||||||
.bind(self.id)
|
.bind(self.id)
|
||||||
.execute(pool).await?;
|
.execute(pool).await?;
|
||||||
Ok(query_result.rows_affected() > 0)
|
Ok(query_result.rows_affected() > 0)
|
||||||
},
|
},
|
||||||
UserStore::File(file_path) => {
|
UserStore::File(file_path) => {
|
||||||
let new_entries: Vec<String> = Entries::new(&file_path).map(|user: User|{
|
let new_entries: Vec<String> = Entries::new(&file_path).map(|user: User|{
|
||||||
@ -357,7 +367,7 @@ impl User {
|
|||||||
}
|
}
|
||||||
pub fn show(&self, sep: &str) {
|
pub fn show(&self, sep: &str) {
|
||||||
let content = if sep.is_empty() {
|
let content = if sep.is_empty() {
|
||||||
format!( "{}\n{}\n{}\n{}\n{}\n{}\n{}\n{}\n{}\n{}\n{}\n{}\n{}\n{}\n{}\n{}\n{}",
|
format!( "{}\n{}\n{}\n{}\n{}\n{}\n{}\n{}\n{}\n{}\n{}\n{}\n{}\n{}\n{}\n{}\n{}\n{}",
|
||||||
self.id,
|
self.id,
|
||||||
self.name, self.fullname,
|
self.name, self.fullname,
|
||||||
self.description,
|
self.description,
|
||||||
@ -373,7 +383,8 @@ impl User {
|
|||||||
self.lastaccess,
|
self.lastaccess,
|
||||||
self.status,
|
self.status,
|
||||||
self.items,
|
self.items,
|
||||||
self.isadmin
|
self.isadmin,
|
||||||
|
self.openids
|
||||||
)
|
)
|
||||||
} else {
|
} else {
|
||||||
format!("{}",&self).replace(DISPLAY_SEPARATOR, sep)
|
format!("{}",&self).replace(DISPLAY_SEPARATOR, sep)
|
||||||
@ -425,6 +436,7 @@ impl User {
|
|||||||
status,
|
status,
|
||||||
items: row.try_get("items")?,
|
items: row.try_get("items")?,
|
||||||
isadmin: row.try_get("isadmin")?,
|
isadmin: row.try_get("isadmin")?,
|
||||||
|
openids: row.try_get("openids")?,
|
||||||
};
|
};
|
||||||
if show { user.show(sep); }
|
if show { user.show(sep); }
|
||||||
usrs.push(user);
|
usrs.push(user);
|
||||||
@ -461,7 +473,7 @@ impl User {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
fn line_format(self) -> String {
|
fn line_format(self) -> String {
|
||||||
format!( "{}:{}:{}:{}:{}:{}:{}:{}:{}:{}:{}:{}:{}:{}:{}:{}:{}",
|
format!( "{}:{}:{}:{}:{}:{}:{}:{}:{}:{}:{}:{}:{}:{}:{}:{}:{}:{}",
|
||||||
self.id,
|
self.id,
|
||||||
self.name, self.fullname,
|
self.name, self.fullname,
|
||||||
self.description,
|
self.description,
|
||||||
@ -476,7 +488,8 @@ impl User {
|
|||||||
self.created, self.lastaccess,
|
self.created, self.lastaccess,
|
||||||
self.status,
|
self.status,
|
||||||
self.items,
|
self.items,
|
||||||
self.isadmin
|
self.isadmin,
|
||||||
|
self.openids
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
pub fn hash_items(items: &str) -> HashMap<String,String> {
|
pub fn hash_items(items: &str) -> HashMap<String,String> {
|
||||||
@ -527,6 +540,9 @@ impl User {
|
|||||||
}
|
}
|
||||||
self.items = Self::json_items(items_hash);
|
self.items = Self::json_items(items_hash);
|
||||||
}
|
}
|
||||||
|
if !user_data.openids.is_empty() {
|
||||||
|
self.openids = user_data.openids.to_owned();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
pub fn disable_totp(&mut self) {
|
pub fn disable_totp(&mut self) {
|
||||||
self.otp_base32 = String::from("");
|
self.otp_base32 = String::from("");
|
||||||
@ -587,37 +603,23 @@ impl User {
|
|||||||
)
|
)
|
||||||
}
|
}
|
||||||
pub fn estimate_password(word: &str) -> String {
|
pub fn estimate_password(word: &str) -> String {
|
||||||
match zxcvbn::zxcvbn(word, &[]) {
|
let estimate = zxcvbn(word, &[]);
|
||||||
Ok(estimate) => {
|
if let Some(feedback) = estimate.feedback() {
|
||||||
if let Some(feedback) = estimate.feedback() {
|
let arr_suggestions: Vec<String> = feedback.suggestions().iter().map(|s| format!("{}",s)).collect();
|
||||||
let arr_suggestions: Vec<String> = feedback.suggestions().iter().map(|s| format!("{}",s)).collect();
|
let suggestions = arr_suggestions.join("\n");
|
||||||
let suggestions = arr_suggestions.join("\n");
|
if let Some(warning) = feedback.warning() {
|
||||||
if let Some(warning) = feedback.warning() {
|
let warning = format!("{}", warning);
|
||||||
let warning = format!("{}", warning);
|
format!("{}|{}|{}",estimate.score(),suggestions,warning)
|
||||||
format!("{}|{}|{}",estimate.score(),suggestions,warning)
|
} else {
|
||||||
} else {
|
format!("{}|{}|",estimate.score(),suggestions)
|
||||||
format!("{}|{}|",estimate.score(),suggestions)
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
format!("{}||",estimate.score())
|
|
||||||
}
|
|
||||||
},
|
|
||||||
Err(e) => {
|
|
||||||
println!("Error password strength estimator: {}", e);
|
|
||||||
String::from("-1|||")
|
|
||||||
}
|
}
|
||||||
|
} else {
|
||||||
|
format!("{}||",estimate.score())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
pub fn password_score(word: &str) -> u8 {
|
pub fn password_score(word: &str) -> u8 {
|
||||||
match zxcvbn::zxcvbn(word, &[]) {
|
let estimate = zxcvbn(word, &[]);
|
||||||
Ok(estimate) => {
|
u8::from(estimate.score())
|
||||||
estimate.score()
|
|
||||||
},
|
|
||||||
Err(e) => {
|
|
||||||
println!("Error password strength estimator: {}", e);
|
|
||||||
0
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
#[allow(dead_code)]
|
#[allow(dead_code)]
|
||||||
pub fn has_auth_role(&self, auth_roles: Vec<String>) -> bool {
|
pub fn has_auth_role(&self, auth_roles: Vec<String>) -> bool {
|
||||||
|
@ -57,7 +57,7 @@ pub struct UserData {
|
|||||||
#[serde(default = "default_items")]
|
#[serde(default = "default_items")]
|
||||||
pub items: HashMap<String,String>,
|
pub items: HashMap<String,String>,
|
||||||
#[serde(default = "default_empty")]
|
#[serde(default = "default_empty")]
|
||||||
pub opendis: String,
|
pub openids: String,
|
||||||
}
|
}
|
||||||
// impl UserData {
|
// impl UserData {
|
||||||
// pub fn from_id(id: String, _app_dbs: &AppDBs) -> Self {
|
// pub fn from_id(id: String, _app_dbs: &AppDBs) -> Self {
|
||||||
|
Loading…
Reference in New Issue
Block a user