Better logging and error handling
This commit is contained in:
parent
76b1f53120
commit
5950fa7370
539
Cargo.lock
generated
539
Cargo.lock
generated
File diff suppressed because it is too large
Load Diff
@ -25,7 +25,7 @@ dotenv = "0.15.0"
|
||||
actix-identity = "0.3"
|
||||
chrono = { version = "0.4", features = ["serde"] }
|
||||
argonautica = "0.2"
|
||||
slog = "2"
|
||||
slog = { version = "2", features = ["max_level_trace", "release_max_level_info"] }
|
||||
slog-term = "2"
|
||||
slog-async = "2"
|
||||
qrcode = "0.12"
|
||||
|
@ -223,7 +223,7 @@ pub(crate) async fn setup() -> Result<Option<crate::ServerConfig>, ServerError>
|
||||
|
||||
// Print launch info
|
||||
slog_info!(log, "Launching Pslink a 'Private short link generator'");
|
||||
slog_info!(log, "logging initialized");
|
||||
slog_trace!(log, "logging initialized");
|
||||
|
||||
let app = generate_cli();
|
||||
|
||||
@ -239,6 +239,7 @@ pub(crate) async fn setup() -> Result<Option<crate::ServerConfig>, ServerError>
|
||||
.parse::<PathBuf>()
|
||||
.expect("Failed to parse Database path.");
|
||||
if !db.exists() {
|
||||
slog_trace!(log, "No database file found {}", db.display());
|
||||
if config.subcommand_matches("migrate-database").is_none() {
|
||||
let msg = format!(
|
||||
concat!(
|
||||
@ -252,8 +253,9 @@ pub(crate) async fn setup() -> Result<Option<crate::ServerConfig>, ServerError>
|
||||
eprintln!("{}", msg);
|
||||
return Ok(None);
|
||||
}
|
||||
slog_trace!(log, "Creating database: {}", db.display());
|
||||
|
||||
// create an empty database file the if above makes sure that this file does not exist.
|
||||
// create an empty database file. The if above makes sure that this file does not exist.
|
||||
File::create(db)?;
|
||||
};
|
||||
|
||||
@ -290,8 +292,10 @@ pub(crate) async fn setup() -> Result<Option<crate::ServerConfig>, ServerError>
|
||||
" Create a user with `pslink create-admin`"
|
||||
)
|
||||
);
|
||||
} else {
|
||||
slog_trace!(&server_config.log, "At least one admin user is found.");
|
||||
}
|
||||
slog_info!(
|
||||
slog_trace!(
|
||||
&server_config.log,
|
||||
"Initialization finished starting the service."
|
||||
);
|
||||
|
@ -2,6 +2,7 @@ extern crate sqlx;
|
||||
#[allow(unused_imports)]
|
||||
#[macro_use(
|
||||
slog_o,
|
||||
slog_trace,
|
||||
slog_info,
|
||||
slog_warn,
|
||||
slog_error,
|
||||
@ -82,25 +83,26 @@ fn build_tera() -> Result<Tera> {
|
||||
Ok(tera)
|
||||
}
|
||||
|
||||
#[allow(clippy::future_not_send)]
|
||||
#[allow(clippy::future_not_send, clippy::too_many_lines)]
|
||||
async fn webservice(server_config: ServerConfig) -> Result<()> {
|
||||
let host_port = format!("{}:{}", &server_config.internal_ip, &server_config.port);
|
||||
|
||||
let cfg = server_config.clone();
|
||||
slog_info!(
|
||||
server_config.log,
|
||||
cfg.log,
|
||||
"Running on: {}://{}/admin/login/",
|
||||
&server_config.protocol,
|
||||
host_port
|
||||
);
|
||||
slog_info!(
|
||||
server_config.log,
|
||||
cfg.log,
|
||||
"If the public url is set up correctly it should be accessible via: {}://{}/admin/login/",
|
||||
&server_config.protocol,
|
||||
&server_config.public_url
|
||||
);
|
||||
let tera = build_tera()?;
|
||||
slog_trace!(cfg.log, "The tera templates are ready");
|
||||
|
||||
HttpServer::new(move || {
|
||||
let tera = build_tera(); //Tera::new("templates/**/*").expect("failed to initialize the templates");
|
||||
let generated = generate();
|
||||
App::new()
|
||||
.data(server_config.clone())
|
||||
@ -112,7 +114,7 @@ async fn webservice(server_config: ServerConfig) -> Result<()> {
|
||||
.name("auth-cookie")
|
||||
.secure(false),
|
||||
))
|
||||
.data(tera)
|
||||
.data(tera.clone())
|
||||
.service(actix_web_static_files::ResourceFiles::new(
|
||||
"/static", generated,
|
||||
))
|
||||
@ -187,7 +189,11 @@ async fn webservice(server_config: ServerConfig) -> Result<()> {
|
||||
.route("/{redirect_id}", web::get().to(views::redirect))
|
||||
})
|
||||
.bind(host_port)
|
||||
.context("Failed to bind to port")?
|
||||
.context("Failed to bind to port")
|
||||
.map_err(|e| {
|
||||
slog_error!(cfg.log, "Failed to bind to port!");
|
||||
e
|
||||
})?
|
||||
.run()
|
||||
.await
|
||||
.context("Failed to run the webservice")
|
||||
|
@ -13,6 +13,7 @@ use fluent_langneg::{
|
||||
use fluent_templates::LanguageIdentifier;
|
||||
use image::{DynamicImage, ImageOutputFormat, Luma};
|
||||
use qrcode::{render::svg, QrCode};
|
||||
use queries::{authenticate, Role};
|
||||
use tera::{Context, Tera};
|
||||
|
||||
use pslink::forms::LinkForm;
|
||||
@ -57,14 +58,13 @@ fn detect_language(request: &HttpRequest) -> Result<String, ServerError> {
|
||||
let languagecode = supported
|
||||
.get(0)
|
||||
.map_or("en".to_string(), std::string::ToString::to_string);
|
||||
println!("Detected the language: {}", &languagecode);
|
||||
Ok(languagecode)
|
||||
}
|
||||
|
||||
/// Show the list of all available links if a user is authenticated
|
||||
pub async fn index(
|
||||
tera: web::Data<Tera>,
|
||||
config: web::Data<crate::ServerConfig>,
|
||||
config: web::Data<pslink::ServerConfig>,
|
||||
id: Identity,
|
||||
) -> Result<HttpResponse, ServerError> {
|
||||
if let Ok(links) = queries::list_all_allowed(&id, &config).await {
|
||||
@ -82,7 +82,7 @@ pub async fn index(
|
||||
/// Show the list of all available links if a user is authenticated
|
||||
pub async fn index_users(
|
||||
tera: web::Data<Tera>,
|
||||
config: web::Data<crate::ServerConfig>,
|
||||
config: web::Data<pslink::ServerConfig>,
|
||||
id: Identity,
|
||||
) -> Result<HttpResponse, ServerError> {
|
||||
if let Ok(users) = queries::list_users(&id, &config).await {
|
||||
@ -99,7 +99,7 @@ pub async fn index_users(
|
||||
}
|
||||
pub async fn view_link_empty(
|
||||
tera: web::Data<Tera>,
|
||||
config: web::Data<crate::ServerConfig>,
|
||||
config: web::Data<pslink::ServerConfig>,
|
||||
id: Identity,
|
||||
) -> Result<HttpResponse, ServerError> {
|
||||
view_link(tera, config, id, web::Path::from("".to_owned())).await
|
||||
@ -107,7 +107,7 @@ pub async fn view_link_empty(
|
||||
|
||||
pub async fn view_link(
|
||||
tera: web::Data<Tera>,
|
||||
config: web::Data<crate::ServerConfig>,
|
||||
config: web::Data<pslink::ServerConfig>,
|
||||
id: Identity,
|
||||
link_id: web::Path<String>,
|
||||
) -> Result<HttpResponse, ServerError> {
|
||||
@ -146,7 +146,7 @@ pub async fn view_link(
|
||||
|
||||
pub async fn view_profile(
|
||||
tera: web::Data<Tera>,
|
||||
config: web::Data<crate::ServerConfig>,
|
||||
config: web::Data<pslink::ServerConfig>,
|
||||
id: Identity,
|
||||
user_id: web::Path<String>,
|
||||
) -> Result<HttpResponse, ServerError> {
|
||||
@ -173,7 +173,7 @@ pub async fn view_profile(
|
||||
|
||||
pub async fn edit_profile(
|
||||
tera: web::Data<Tera>,
|
||||
config: web::Data<crate::ServerConfig>,
|
||||
config: web::Data<pslink::ServerConfig>,
|
||||
id: Identity,
|
||||
user_id: web::Path<String>,
|
||||
) -> Result<HttpResponse, ServerError> {
|
||||
@ -199,7 +199,7 @@ pub async fn edit_profile(
|
||||
|
||||
pub async fn process_edit_profile(
|
||||
data: web::Form<NewUser>,
|
||||
config: web::Data<crate::ServerConfig>,
|
||||
config: web::Data<pslink::ServerConfig>,
|
||||
id: Identity,
|
||||
user_id: web::Path<String>,
|
||||
) -> Result<HttpResponse, ServerError> {
|
||||
@ -215,7 +215,7 @@ pub async fn process_edit_profile(
|
||||
|
||||
pub async fn download_png(
|
||||
id: Identity,
|
||||
config: web::Data<crate::ServerConfig>,
|
||||
config: web::Data<pslink::ServerConfig>,
|
||||
link_code: web::Path<String>,
|
||||
) -> Result<HttpResponse, ServerError> {
|
||||
match queries::get_link(&id, &link_code.0, &config).await {
|
||||
@ -239,7 +239,7 @@ pub async fn download_png(
|
||||
|
||||
pub async fn signup(
|
||||
tera: web::Data<Tera>,
|
||||
config: web::Data<crate::ServerConfig>,
|
||||
config: web::Data<pslink::ServerConfig>,
|
||||
id: Identity,
|
||||
) -> Result<HttpResponse, ServerError> {
|
||||
match queries::authenticate(&id, &config).await? {
|
||||
@ -259,7 +259,7 @@ pub async fn signup(
|
||||
|
||||
pub async fn process_signup(
|
||||
data: web::Form<NewUser>,
|
||||
config: web::Data<crate::ServerConfig>,
|
||||
config: web::Data<pslink::ServerConfig>,
|
||||
id: Identity,
|
||||
) -> Result<HttpResponse, ServerError> {
|
||||
slog_info!(config.log, "Creating a User: {:?}", &data);
|
||||
@ -272,7 +272,7 @@ pub async fn process_signup(
|
||||
|
||||
pub async fn toggle_admin(
|
||||
data: web::Path<String>,
|
||||
config: web::Data<crate::ServerConfig>,
|
||||
config: web::Data<pslink::ServerConfig>,
|
||||
id: Identity,
|
||||
) -> Result<HttpResponse, ServerError> {
|
||||
let update = queries::toggle_admin(&id, &data.0, &config).await?;
|
||||
@ -284,7 +284,7 @@ pub async fn toggle_admin(
|
||||
|
||||
pub async fn set_language(
|
||||
data: web::Path<String>,
|
||||
config: web::Data<crate::ServerConfig>,
|
||||
config: web::Data<pslink::ServerConfig>,
|
||||
id: Identity,
|
||||
) -> Result<HttpResponse, ServerError> {
|
||||
queries::set_language(&id, &data.0, &config).await?;
|
||||
@ -294,7 +294,7 @@ pub async fn set_language(
|
||||
pub async fn login(
|
||||
tera: web::Data<Tera>,
|
||||
id: Identity,
|
||||
config: web::Data<crate::ServerConfig>,
|
||||
config: web::Data<pslink::ServerConfig>,
|
||||
req: HttpRequest,
|
||||
) -> Result<HttpResponse, ServerError> {
|
||||
let language_code = detect_language(&req)?;
|
||||
@ -303,9 +303,23 @@ pub async fn login(
|
||||
data.insert("title", "Login");
|
||||
data.insert("language", &language_code);
|
||||
|
||||
if let Some(_id) = id.identity() {
|
||||
if id.identity().is_some() {
|
||||
if let Ok(r) = authenticate(&id, &config).await {
|
||||
match r {
|
||||
Role::Admin { user } | Role::Regular { user } => {
|
||||
slog_trace!(
|
||||
config.log,
|
||||
"This user ({}) is already logged in redirecting to /admin/index/",
|
||||
user.username
|
||||
);
|
||||
return Ok(redirect_builder("/admin/index/"));
|
||||
}
|
||||
Role::Disabled | Role::NotAuthenticated => (),
|
||||
}
|
||||
}
|
||||
slog_warn!(config.log, "Invalid user session. The user might be deleted or something tampered with the cookies.");
|
||||
id.forget();
|
||||
}
|
||||
|
||||
let rendered = tera.render("login.html", &data)?;
|
||||
Ok(HttpResponse::Ok().body(rendered))
|
||||
@ -313,7 +327,7 @@ pub async fn login(
|
||||
|
||||
pub async fn process_login(
|
||||
data: web::Form<LoginUser>,
|
||||
config: web::Data<crate::ServerConfig>,
|
||||
config: web::Data<pslink::ServerConfig>,
|
||||
id: Identity,
|
||||
) -> Result<HttpResponse, ServerError> {
|
||||
let user = queries::get_user_by_name(&data.username, &config).await;
|
||||
@ -350,7 +364,7 @@ pub async fn logout(id: Identity) -> Result<HttpResponse, ServerError> {
|
||||
|
||||
pub async fn redirect(
|
||||
tera: web::Data<Tera>,
|
||||
config: web::Data<crate::ServerConfig>,
|
||||
config: web::Data<pslink::ServerConfig>,
|
||||
data: web::Path<String>,
|
||||
req: HttpRequest,
|
||||
) -> Result<HttpResponse, ServerError> {
|
||||
@ -382,14 +396,14 @@ pub async fn redirect(
|
||||
}
|
||||
|
||||
pub async fn redirect_empty(
|
||||
config: web::Data<crate::ServerConfig>,
|
||||
config: web::Data<pslink::ServerConfig>,
|
||||
) -> Result<HttpResponse, ServerError> {
|
||||
Ok(redirect_builder(&config.empty_forward_url))
|
||||
}
|
||||
|
||||
pub async fn create_link(
|
||||
tera: web::Data<Tera>,
|
||||
config: web::Data<crate::ServerConfig>,
|
||||
config: web::Data<pslink::ServerConfig>,
|
||||
id: Identity,
|
||||
) -> Result<HttpResponse, ServerError> {
|
||||
match queries::authenticate(&id, &config).await? {
|
||||
@ -409,7 +423,7 @@ pub async fn create_link(
|
||||
|
||||
pub async fn process_link_creation(
|
||||
data: web::Form<LinkForm>,
|
||||
config: web::Data<crate::ServerConfig>,
|
||||
config: web::Data<pslink::ServerConfig>,
|
||||
id: Identity,
|
||||
) -> Result<HttpResponse, ServerError> {
|
||||
let new_link = queries::create_link(&id, data, &config).await?;
|
||||
@ -421,7 +435,7 @@ pub async fn process_link_creation(
|
||||
|
||||
pub async fn edit_link(
|
||||
tera: web::Data<Tera>,
|
||||
config: web::Data<crate::ServerConfig>,
|
||||
config: web::Data<pslink::ServerConfig>,
|
||||
id: Identity,
|
||||
link_id: web::Path<String>,
|
||||
) -> Result<HttpResponse, ServerError> {
|
||||
@ -438,7 +452,7 @@ pub async fn edit_link(
|
||||
}
|
||||
pub async fn process_link_edit(
|
||||
data: web::Form<LinkForm>,
|
||||
config: web::Data<crate::ServerConfig>,
|
||||
config: web::Data<pslink::ServerConfig>,
|
||||
id: Identity,
|
||||
link_code: web::Path<String>,
|
||||
) -> Result<HttpResponse, ServerError> {
|
||||
@ -453,7 +467,7 @@ pub async fn process_link_edit(
|
||||
|
||||
pub async fn process_link_delete(
|
||||
id: Identity,
|
||||
config: web::Data<crate::ServerConfig>,
|
||||
config: web::Data<pslink::ServerConfig>,
|
||||
link_code: web::Path<String>,
|
||||
) -> Result<HttpResponse, ServerError> {
|
||||
queries::delete_link(&id, &link_code.0, &config).await?;
|
||||
|
79
src/lib.rs
79
src/lib.rs
@ -51,25 +51,86 @@ impl From<argonautica::Error> for ServerError {
|
||||
}
|
||||
}
|
||||
|
||||
impl ServerError {
|
||||
fn render_error(title: &str, content: &str) -> String {
|
||||
format!(
|
||||
"<!DOCTYPE html>
|
||||
<html lang=\"en\">
|
||||
<head>
|
||||
<meta charset=\"utf-8\">
|
||||
<title>{0}</title>
|
||||
<meta name=\"author\" content=\"Franz Dietrich\">
|
||||
<meta http-equiv=\"robots\" content=\"[noindex|nofollow]\">
|
||||
<link rel=\"stylesheet\" href=\"/static/style.css\">
|
||||
</head>
|
||||
<body>
|
||||
<section class=\"centered\">
|
||||
<h1>{0}</h1>
|
||||
<div class=\"container\">
|
||||
{1}
|
||||
</div>
|
||||
</section>
|
||||
</body>
|
||||
</html>",
|
||||
title, content
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
impl actix_web::error::ResponseError for ServerError {
|
||||
fn error_response(&self) -> HttpResponse {
|
||||
match self {
|
||||
Self::Argonautica(_) => HttpResponse::InternalServerError().json("Argonautica Error"),
|
||||
Self::Database(e) => {
|
||||
HttpResponse::InternalServerError().json(format!("Database Error: {:?}", e))
|
||||
Self::Argonautica(e) => {
|
||||
eprintln!("Argonautica Error happened: {:?}", e);
|
||||
HttpResponse::InternalServerError()
|
||||
.body("Failed to encrypt the password - Aborting!")
|
||||
}
|
||||
Self::DatabaseMigration(_) => {
|
||||
Self::Database(e) => {
|
||||
eprintln!("Database Error happened: {:?}", e);
|
||||
HttpResponse::InternalServerError().body(&Self::render_error(
|
||||
"Server Error",
|
||||
"Database could not be accessed! - It could be that this value already was in the database! If you are the admin look into the logs for a more detailed error.",
|
||||
))
|
||||
}
|
||||
Self::DatabaseMigration(e) => {
|
||||
eprintln!("Migration Error happened: {:?}", e);
|
||||
unimplemented!("A migration error should never be rendered")
|
||||
}
|
||||
Self::Environment(_) => HttpResponse::InternalServerError().json("Environment Error"),
|
||||
Self::Environment(e) => {
|
||||
eprintln!("Environment Error happened: {:?}", e);
|
||||
HttpResponse::InternalServerError().body(&Self::render_error(
|
||||
"Server Error",
|
||||
"This Server is not properly configured, if you are the admin look into the installation- or update instructions!",
|
||||
))
|
||||
}
|
||||
Self::Template(e) => {
|
||||
HttpResponse::InternalServerError().json(format!("Template Error: {:?}", e))
|
||||
eprintln!("Template Error happened: {:?}", e);
|
||||
HttpResponse::InternalServerError().body(&Self::render_error(
|
||||
"Server Error",
|
||||
"The templates could not be rendered.",
|
||||
))
|
||||
}
|
||||
Self::Qr(e) => {
|
||||
HttpResponse::InternalServerError().json(format!("Qr Code Error: {:?}", e))
|
||||
eprintln!("QR Error happened: {:?}", e);
|
||||
HttpResponse::InternalServerError().body(&Self::render_error(
|
||||
"Server Error",
|
||||
"Could not generate the QR-code!",
|
||||
))
|
||||
}
|
||||
Self::Io(e) => {
|
||||
eprintln!("Io Error happened: {:?}", e);
|
||||
HttpResponse::InternalServerError().body(&Self::render_error(
|
||||
"Server Error",
|
||||
"Some Files could not be read or written. If you are the admin look into the logfiles for more details.",
|
||||
))
|
||||
}
|
||||
Self::User(data) => {
|
||||
eprintln!("User Error happened: {:?}", data);
|
||||
HttpResponse::InternalServerError().body(&Self::render_error(
|
||||
"Server Error",
|
||||
&format!("An error happened: {}", data),
|
||||
))
|
||||
}
|
||||
Self::Io(e) => HttpResponse::InternalServerError().json(format!("IO Error: {:?}", e)),
|
||||
Self::User(data) => HttpResponse::InternalServerError().json(data),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user