mirror of
https://git.verdigado.com/NB-Public/simple-wkd.git
synced 2024-10-30 01:25:53 +01:00
Revamp logging
This commit is contained in:
parent
c341cdb83f
commit
ab10c7f9e9
6 changed files with 84 additions and 46 deletions
|
@ -1,11 +1,12 @@
|
||||||
use chrono::Utc;
|
use chrono::Utc;
|
||||||
use lettre::message::header::ContentType;
|
use lettre::message::header::ContentType;
|
||||||
|
use log::{warn, debug};
|
||||||
|
|
||||||
use crate::errors::SpecialErrors;
|
use crate::errors::SpecialErrors;
|
||||||
use crate::management::{delete_key, Action, Pending};
|
use crate::management::{delete_key, Action, Pending};
|
||||||
use crate::pending_path;
|
|
||||||
use crate::settings::{MAILER, ROOT_FOLDER, SETTINGS};
|
use crate::settings::{MAILER, ROOT_FOLDER, SETTINGS};
|
||||||
use crate::utils::{get_email_from_cert, parse_pem, read_file};
|
use crate::utils::{extract_domain, get_email_from_cert, parse_pem, read_file};
|
||||||
|
use crate::{log_err, pending_path};
|
||||||
use anyhow::Result;
|
use anyhow::Result;
|
||||||
|
|
||||||
use lettre::{Message, Transport};
|
use lettre::{Message, Transport};
|
||||||
|
@ -15,20 +16,20 @@ use std::path::Path;
|
||||||
pub fn confirm_action(token: &str) -> Result<(Action, String)> {
|
pub fn confirm_action(token: &str) -> Result<(Action, String)> {
|
||||||
let pending_path = pending_path().join(token);
|
let pending_path = pending_path().join(token);
|
||||||
let content = read_file(&pending_path)?;
|
let content = read_file(&pending_path)?;
|
||||||
let key = toml::from_str::<Pending>(&content)?;
|
let key = log_err!(toml::from_str::<Pending>(&content), warn)?;
|
||||||
if Utc::now().timestamp() - key.timestamp() > SETTINGS.max_age {
|
if Utc::now().timestamp() - key.timestamp() > SETTINGS.max_age {
|
||||||
fs::remove_file(&pending_path)?;
|
log_err!(fs::remove_file(&pending_path), warn)?;
|
||||||
Err(SpecialErrors::ExpiredRequest)?
|
Err(SpecialErrors::ExpiredRequest)?
|
||||||
} else {
|
} else {
|
||||||
let address = match key.action() {
|
let address = match key.action() {
|
||||||
Action::Add => {
|
Action::Add => {
|
||||||
let cert = parse_pem(key.data())?;
|
let cert = parse_pem(key.data())?;
|
||||||
let email = get_email_from_cert(&cert)?;
|
let email = get_email_from_cert(&cert)?;
|
||||||
let domain = match email.split('@').last() {
|
let domain = extract_domain(&email)?;
|
||||||
Some(domain) => domain.to_string(),
|
log_err!(
|
||||||
None => Err(SpecialErrors::MalformedEmail)?,
|
sequoia_net::wkd::insert(ROOT_FOLDER, domain, SETTINGS.variant, &cert),
|
||||||
};
|
warn
|
||||||
sequoia_net::wkd::insert(ROOT_FOLDER, domain, SETTINGS.variant, &cert)?;
|
)?;
|
||||||
email
|
email
|
||||||
}
|
}
|
||||||
Action::Delete => {
|
Action::Delete => {
|
||||||
|
@ -57,7 +58,7 @@ pub fn send_confirmation_email(address: &str, action: &Action, token: &str) -> R
|
||||||
panic!("Unable to parse the email in the settings!")
|
panic!("Unable to parse the email in the settings!")
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
.to(match address.parse() {
|
.to(match log_err!(address.parse(), debug) {
|
||||||
Ok(mbox) => mbox,
|
Ok(mbox) => mbox,
|
||||||
Err(_) => Err(SpecialErrors::MalformedEmail)?,
|
Err(_) => Err(SpecialErrors::MalformedEmail)?,
|
||||||
})
|
})
|
||||||
|
@ -72,8 +73,10 @@ pub fn send_confirmation_email(address: &str, action: &Action, token: &str) -> R
|
||||||
template
|
template
|
||||||
.replace("{{%u}}", url.as_ref())
|
.replace("{{%u}}", url.as_ref())
|
||||||
.replace("{{%a}}", &action.to_string().to_lowercase()),
|
.replace("{{%a}}", &action.to_string().to_lowercase()),
|
||||||
)?;
|
);
|
||||||
|
|
||||||
MAILER.send(&email)?;
|
let email = log_err!(email, warn)?;
|
||||||
|
|
||||||
|
log_err!(MAILER.send(&email), warn)?;
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
|
@ -10,7 +10,11 @@ macro_rules! log_err {
|
||||||
($var: expr, $level: ident) => {{
|
($var: expr, $level: ident) => {{
|
||||||
let test = $var;
|
let test = $var;
|
||||||
if test.is_err() {
|
if test.is_err() {
|
||||||
$level!("{} {}", $crate::settings::ERROR_TEXT, test.as_ref().unwrap_err());
|
$level!(
|
||||||
|
"{} {}",
|
||||||
|
$crate::settings::ERROR_TEXT,
|
||||||
|
test.as_ref().unwrap_err()
|
||||||
|
);
|
||||||
test
|
test
|
||||||
} else {
|
} else {
|
||||||
test
|
test
|
||||||
|
|
|
@ -6,6 +6,7 @@ mod utils;
|
||||||
|
|
||||||
use crate::confirmation::{confirm_action, send_confirmation_email};
|
use crate::confirmation::{confirm_action, send_confirmation_email};
|
||||||
use crate::errors::CompatErr;
|
use crate::errors::CompatErr;
|
||||||
|
use crate::errors::SpecialErrors;
|
||||||
use crate::management::{clean_stale, store_pending_addition, store_pending_deletion, Action};
|
use crate::management::{clean_stale, store_pending_addition, store_pending_deletion, Action};
|
||||||
use crate::settings::{ROOT_FOLDER, SETTINGS};
|
use crate::settings::{ROOT_FOLDER, SETTINGS};
|
||||||
use crate::utils::{
|
use crate::utils::{
|
||||||
|
@ -18,9 +19,8 @@ use actix_web::http::StatusCode;
|
||||||
use actix_web::{
|
use actix_web::{
|
||||||
get, post, web, App, HttpRequest, HttpResponse, HttpResponseBuilder, HttpServer, Result,
|
get, post, web, App, HttpRequest, HttpResponse, HttpResponseBuilder, HttpServer, Result,
|
||||||
};
|
};
|
||||||
use errors::SpecialErrors;
|
use log::{debug, error, info, trace};
|
||||||
use serde::Deserialize;
|
use serde::Deserialize;
|
||||||
use std::env;
|
|
||||||
use std::fs;
|
use std::fs;
|
||||||
use std::path::Path;
|
use std::path::Path;
|
||||||
use tokio::{task, time};
|
use tokio::{task, time};
|
||||||
|
@ -43,21 +43,21 @@ struct Email {
|
||||||
|
|
||||||
#[actix_web::main]
|
#[actix_web::main]
|
||||||
async fn main() -> std::io::Result<()> {
|
async fn main() -> std::io::Result<()> {
|
||||||
if let Ok(value) = env::var("RUST_LOG") {
|
|
||||||
env::set_var("RUST_LOG", format!("simple_wkd={}", value));
|
|
||||||
}
|
|
||||||
if init_logger().is_err() {
|
if init_logger().is_err() {
|
||||||
panic!("Could not set up logger!")
|
panic!("Could not set up logger!")
|
||||||
};
|
};
|
||||||
fs::create_dir_all(pending_path())?;
|
log_err!(fs::create_dir_all(pending_path()), error)?;
|
||||||
task::spawn(async {
|
task::spawn(async {
|
||||||
let mut metronome = time::interval(time::Duration::from_secs(SETTINGS.cleanup_interval));
|
let mut metronome = time::interval(time::Duration::from_secs(SETTINGS.cleanup_interval));
|
||||||
loop {
|
loop {
|
||||||
metronome.tick().await;
|
metronome.tick().await;
|
||||||
|
debug!("Cleaning up stale data...");
|
||||||
clean_stale(SETTINGS.max_age);
|
clean_stale(SETTINGS.max_age);
|
||||||
|
debug!("Cleanup completed!")
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
HttpServer::new(|| {
|
debug!("Starting server...");
|
||||||
|
let server = HttpServer::new(|| {
|
||||||
App::new()
|
App::new()
|
||||||
.service(submit)
|
.service(submit)
|
||||||
.service(confirm)
|
.service(confirm)
|
||||||
|
@ -69,8 +69,13 @@ async fn main() -> std::io::Result<()> {
|
||||||
.route("/{filename:.*}", web::get().to(index))
|
.route("/{filename:.*}", web::get().to(index))
|
||||||
})
|
})
|
||||||
.bind((SETTINGS.bind_host.to_string(), SETTINGS.port))?
|
.bind((SETTINGS.bind_host.to_string(), SETTINGS.port))?
|
||||||
.run()
|
.run();
|
||||||
.await
|
debug!("Server started successfully!");
|
||||||
|
info!(
|
||||||
|
"Listening on: {}:{} (External url: {})",
|
||||||
|
SETTINGS.bind_host, SETTINGS.port, SETTINGS.external_url
|
||||||
|
);
|
||||||
|
server.await
|
||||||
}
|
}
|
||||||
|
|
||||||
async fn index(req: HttpRequest) -> Result<HttpResponse, CompatErr> {
|
async fn index(req: HttpRequest) -> Result<HttpResponse, CompatErr> {
|
||||||
|
@ -89,6 +94,7 @@ async fn index(req: HttpRequest) -> Result<HttpResponse, CompatErr> {
|
||||||
.body(page));
|
.body(page));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
trace!("The requested file {} could not be found", path.display());
|
||||||
Err(SpecialErrors::MissingFile)?
|
Err(SpecialErrors::MissingFile)?
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -99,13 +105,16 @@ async fn submit(pem: web::Form<Key>) -> Result<HttpResponse, CompatErr> {
|
||||||
is_email_allowed(&email)?;
|
is_email_allowed(&email)?;
|
||||||
let token = gen_random_token();
|
let token = gen_random_token();
|
||||||
store_pending_addition(pem.key.clone(), &email, &token)?;
|
store_pending_addition(pem.key.clone(), &email, &token)?;
|
||||||
|
debug!("Sending email to {} to add a key... (Request token: {})", email, token);
|
||||||
send_confirmation_email(&email, &Action::Add, &token)?;
|
send_confirmation_email(&email, &Action::Add, &token)?;
|
||||||
|
info!("User {} requested to add a key successfully!", email);
|
||||||
Ok(return_outcome(Ok("You submitted your key successfully!"))?)
|
Ok(return_outcome(Ok("You submitted your key successfully!"))?)
|
||||||
}
|
}
|
||||||
|
|
||||||
#[get("/api/confirm")]
|
#[get("/api/confirm")]
|
||||||
async fn confirm(token: web::Query<Token>) -> Result<HttpResponse, CompatErr> {
|
async fn confirm(token: web::Query<Token>) -> Result<HttpResponse, CompatErr> {
|
||||||
let (action, _email) = confirm_action(&token.token)?;
|
let (action, email) = confirm_action(&token.token)?;
|
||||||
|
info!("User {} confirmed to {} his key successfully!", email, action.to_string().to_lowercase());
|
||||||
match action {
|
match action {
|
||||||
Action::Add => Ok(return_outcome(Ok("Your key was added successfully!"))?),
|
Action::Add => Ok(return_outcome(Ok("Your key was added successfully!"))?),
|
||||||
Action::Delete => Ok(return_outcome(Ok("Your key was deleted successfully!"))?),
|
Action::Delete => Ok(return_outcome(Ok("Your key was deleted successfully!"))?),
|
||||||
|
@ -116,7 +125,9 @@ async fn confirm(token: web::Query<Token>) -> Result<HttpResponse, CompatErr> {
|
||||||
async fn delete(email: web::Query<Email>) -> Result<HttpResponse, CompatErr> {
|
async fn delete(email: web::Query<Email>) -> Result<HttpResponse, CompatErr> {
|
||||||
let token = gen_random_token();
|
let token = gen_random_token();
|
||||||
store_pending_deletion(email.email.clone(), &token)?;
|
store_pending_deletion(email.email.clone(), &token)?;
|
||||||
|
debug!("Sending email to {} to add a key... (Request token: {})", email.email, token);
|
||||||
send_confirmation_email(&email.email, &Action::Delete, &token)?;
|
send_confirmation_email(&email.email, &Action::Delete, &token)?;
|
||||||
|
info!("User {} requested to delete his key successfully!", email.email);
|
||||||
Ok(return_outcome(Ok(
|
Ok(return_outcome(Ok(
|
||||||
"You requested the deletion of your key successfully!",
|
"You requested the deletion of your key successfully!",
|
||||||
))?)
|
))?)
|
||||||
|
|
|
@ -1,8 +1,10 @@
|
||||||
use crate::settings::ROOT_FOLDER;
|
use crate::log_err;
|
||||||
use crate::utils::{get_user_file_path, key_exists, read_file, pending_path};
|
use crate::settings::{ERROR_TEXT, ROOT_FOLDER};
|
||||||
|
use crate::utils::{get_user_file_path, key_exists, pending_path, read_file};
|
||||||
|
|
||||||
use anyhow::Result;
|
use anyhow::Result;
|
||||||
use chrono::Utc;
|
use chrono::Utc;
|
||||||
|
use log::{debug, warn};
|
||||||
use serde::{Deserialize, Serialize};
|
use serde::{Deserialize, Serialize};
|
||||||
use std::{fmt::Display, fs, path::Path};
|
use std::{fmt::Display, fs, path::Path};
|
||||||
|
|
||||||
|
@ -53,8 +55,8 @@ impl Pending {
|
||||||
}
|
}
|
||||||
|
|
||||||
fn store_pending(pending: &Pending, token: &str) -> Result<()> {
|
fn store_pending(pending: &Pending, token: &str) -> Result<()> {
|
||||||
let serialized = toml::to_string(pending)?;
|
let serialized = log_err!(toml::to_string(pending), warn)?;
|
||||||
fs::write(pending_path().join(token), serialized)?;
|
log_err!(fs::write(pending_path().join(token), serialized), warn)?;
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -82,19 +84,23 @@ pub fn clean_stale(max_age: i64) {
|
||||||
};
|
};
|
||||||
let key = match toml::from_str::<Pending>(&content) {
|
let key = match toml::from_str::<Pending>(&content) {
|
||||||
Ok(key) => key,
|
Ok(key) => key,
|
||||||
Err(_) => {
|
Err(error) => {
|
||||||
|
warn!("{} {}", ERROR_TEXT, error);
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
let now = Utc::now().timestamp();
|
let now = Utc::now().timestamp();
|
||||||
if now - key.timestamp() > max_age {
|
if now - key.timestamp() > max_age {
|
||||||
let _ = fs::remove_file(&file_path);
|
match fs::remove_file(&file_path) {
|
||||||
|
Ok(_) => debug!("Deleted {}, since it was stale", file_path.display()),
|
||||||
|
Err(error) => warn!("{} {}", ERROR_TEXT, error),
|
||||||
|
};
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn delete_key(email: &str) -> Result<()> {
|
pub fn delete_key(email: &str) -> Result<()> {
|
||||||
let path = Path::new(&ROOT_FOLDER).join(get_user_file_path(email)?);
|
let path = Path::new(&ROOT_FOLDER).join(get_user_file_path(email)?);
|
||||||
fs::remove_file(path)?;
|
log_err!(fs::remove_file(path), warn)?;
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,4 +1,5 @@
|
||||||
use lettre::{transport::smtp::authentication::Credentials, SmtpTransport};
|
use lettre::{transport::smtp::authentication::Credentials, SmtpTransport};
|
||||||
|
use log::error;
|
||||||
use once_cell::sync::Lazy;
|
use once_cell::sync::Lazy;
|
||||||
use sequoia_net::wkd::Variant;
|
use sequoia_net::wkd::Variant;
|
||||||
use sequoia_openpgp::policy::StandardPolicy;
|
use sequoia_openpgp::policy::StandardPolicy;
|
||||||
|
@ -6,7 +7,7 @@ use serde::{Deserialize, Serialize};
|
||||||
use std::path::PathBuf;
|
use std::path::PathBuf;
|
||||||
use url::Url;
|
use url::Url;
|
||||||
|
|
||||||
use crate::utils::read_file;
|
use crate::{log_err, utils::read_file};
|
||||||
|
|
||||||
#[derive(Serialize, Deserialize, Debug)]
|
#[derive(Serialize, Deserialize, Debug)]
|
||||||
pub struct Settings {
|
pub struct Settings {
|
||||||
|
@ -52,7 +53,7 @@ fn get_settings() -> Settings {
|
||||||
panic!("Unable to access settings file!")
|
panic!("Unable to access settings file!")
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
let settings = match toml::from_str(&content) {
|
let settings = match log_err!(toml::from_str(&content), error) {
|
||||||
Ok(settings) => settings,
|
Ok(settings) => settings,
|
||||||
Err(_) => {
|
Err(_) => {
|
||||||
panic!("Unable to parse settings from file!")
|
panic!("Unable to parse settings from file!")
|
||||||
|
|
|
@ -1,5 +1,6 @@
|
||||||
use crate::errors::CompatErr;
|
use crate::errors::CompatErr;
|
||||||
use crate::errors::SpecialErrors;
|
use crate::errors::SpecialErrors;
|
||||||
|
use crate::log_err;
|
||||||
use crate::settings::ROOT_FOLDER;
|
use crate::settings::ROOT_FOLDER;
|
||||||
use crate::settings::SETTINGS;
|
use crate::settings::SETTINGS;
|
||||||
|
|
||||||
|
@ -9,9 +10,10 @@ use actix_web::{
|
||||||
HttpResponse, HttpResponseBuilder,
|
HttpResponse, HttpResponseBuilder,
|
||||||
};
|
};
|
||||||
use anyhow::Result;
|
use anyhow::Result;
|
||||||
use flexi_logger::{
|
use flexi_logger::{style, DeferredNow, FileSpec, FlexiLoggerError, Logger, LoggerHandle, Record};
|
||||||
style, DeferredNow, FileSpec, FlexiLoggerError, Logger, LoggerHandle, Record,
|
use log::debug;
|
||||||
};
|
use log::trace;
|
||||||
|
use log::warn;
|
||||||
use rand::{distributions::Alphanumeric, thread_rng, Rng};
|
use rand::{distributions::Alphanumeric, thread_rng, Rng};
|
||||||
use sequoia_net::wkd::Url;
|
use sequoia_net::wkd::Url;
|
||||||
use sequoia_openpgp::{parse::Parse, Cert};
|
use sequoia_openpgp::{parse::Parse, Cert};
|
||||||
|
@ -23,14 +25,13 @@ use std::{
|
||||||
#[macro_export]
|
#[macro_export]
|
||||||
macro_rules! validate_cert {
|
macro_rules! validate_cert {
|
||||||
( $x:expr ) => {
|
( $x:expr ) => {
|
||||||
match $x.with_policy($crate::settings::POLICY, None) {
|
match log_err!($x.with_policy($crate::settings::POLICY, None), debug) {
|
||||||
Ok(validcert) => Ok(validcert),
|
Ok(validcert) => Ok(validcert),
|
||||||
Err(_) => Err($crate::errors::SpecialErrors::InvalidCert),
|
Err(_) => Err($crate::errors::SpecialErrors::InvalidCert),
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
pub fn pending_path() -> PathBuf {
|
pub fn pending_path() -> PathBuf {
|
||||||
Path::new(&ROOT_FOLDER).join("pending")
|
Path::new(&ROOT_FOLDER).join("pending")
|
||||||
}
|
}
|
||||||
|
@ -41,25 +42,25 @@ pub fn webpage_path() -> PathBuf {
|
||||||
|
|
||||||
pub fn read_file(path: &PathBuf) -> Result<String> {
|
pub fn read_file(path: &PathBuf) -> Result<String> {
|
||||||
if path.is_file() {
|
if path.is_file() {
|
||||||
Ok(fs::read_to_string(path)?)
|
Ok(log_err!(fs::read_to_string(path), warn)?)
|
||||||
} else {
|
} else {
|
||||||
|
trace!("The requested file {} does not exist", path.display());
|
||||||
Err(SpecialErrors::MissingFile)?
|
Err(SpecialErrors::MissingFile)?
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn is_email_allowed(email: &str) -> Result<()> {
|
pub fn is_email_allowed(email: &str) -> Result<()> {
|
||||||
let allowed = match email.split('@').last() {
|
let domain = extract_domain(email)?;
|
||||||
Some(domain) => SETTINGS.allowed_domains.contains(&domain.to_string()),
|
let allowed = SETTINGS.allowed_domains.contains(&domain);
|
||||||
None => Err(SpecialErrors::MalformedEmail)?,
|
|
||||||
};
|
|
||||||
if !allowed {
|
if !allowed {
|
||||||
|
debug!("User {} was rejected: domain not whitelisted", email);
|
||||||
Err(SpecialErrors::UnallowedDomain)?;
|
Err(SpecialErrors::UnallowedDomain)?;
|
||||||
}
|
}
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn parse_pem(pemfile: &str) -> Result<Cert> {
|
pub fn parse_pem(pemfile: &str) -> Result<Cert> {
|
||||||
let cert = match sequoia_openpgp::Cert::from_bytes(pemfile.as_bytes()) {
|
let cert = match log_err!(sequoia_openpgp::Cert::from_bytes(pemfile.as_bytes()), debug) {
|
||||||
Ok(cert) => cert,
|
Ok(cert) => cert,
|
||||||
Err(_) => Err(SpecialErrors::MalformedCert)?,
|
Err(_) => Err(SpecialErrors::MalformedCert)?,
|
||||||
};
|
};
|
||||||
|
@ -74,22 +75,34 @@ pub fn gen_random_token() -> String {
|
||||||
|
|
||||||
pub fn get_email_from_cert(cert: &Cert) -> Result<String> {
|
pub fn get_email_from_cert(cert: &Cert) -> Result<String> {
|
||||||
let validcert = validate_cert!(cert)?;
|
let validcert = validate_cert!(cert)?;
|
||||||
let userid_opt = validcert.primary_userid()?;
|
let userid_opt = log_err!(validcert.primary_userid(), debug)?;
|
||||||
let email_opt = userid_opt.email()?;
|
let email_opt = userid_opt.email()?;
|
||||||
match email_opt {
|
match email_opt {
|
||||||
Some(email) => Ok(email),
|
Some(email) => Ok(email),
|
||||||
None => Err(SpecialErrors::EmailMissing)?,
|
None => log_err!(Err(SpecialErrors::EmailMissing), debug)?,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn extract_domain(email: &str) -> Result<String> {
|
||||||
|
let domain = match email.split('@').last() {
|
||||||
|
Some(domain) => domain.to_string(),
|
||||||
|
None => {
|
||||||
|
debug!("Unable to extract domain from {}, email malformed", email);
|
||||||
|
Err(SpecialErrors::MalformedEmail)?
|
||||||
|
}
|
||||||
|
};
|
||||||
|
Ok(domain)
|
||||||
|
}
|
||||||
|
|
||||||
pub fn get_user_file_path(email: &str) -> Result<PathBuf> {
|
pub fn get_user_file_path(email: &str) -> Result<PathBuf> {
|
||||||
let wkd_url = Url::from(email)?;
|
let wkd_url = log_err!(Url::from(email), debug)?;
|
||||||
wkd_url.to_file_path(SETTINGS.variant)
|
wkd_url.to_file_path(SETTINGS.variant)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn key_exists(email: &str) -> Result<bool> {
|
pub fn key_exists(email: &str) -> Result<bool> {
|
||||||
let path = get_user_file_path(email)?;
|
let path = get_user_file_path(email)?;
|
||||||
if !Path::new(&ROOT_FOLDER).join(path).is_file() {
|
if !Path::new(&ROOT_FOLDER).join(path).is_file() {
|
||||||
|
debug!("No key found for user {}", email);
|
||||||
Err(SpecialErrors::InexistingUser)?
|
Err(SpecialErrors::InexistingUser)?
|
||||||
}
|
}
|
||||||
Ok(true)
|
Ok(true)
|
||||||
|
|
Loading…
Reference in a new issue