You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
131 lines
3.9 KiB
131 lines
3.9 KiB
use std::fmt::Display; |
|
|
|
use argon2::password_hash::rand_core::OsRng; |
|
use argon2::password_hash::SaltString; |
|
use argon2::Argon2; |
|
use argon2::PasswordHash; |
|
use argon2::PasswordHasher; |
|
use argon2::PasswordVerifier; |
|
use axum::http::StatusCode; |
|
use entity::link; |
|
use entity::prelude::*; |
|
use entity::user; |
|
use migration::Migrator; |
|
use migration::MigratorTrait; |
|
use sea_orm::{DatabaseConnection, DbErr}; |
|
use sea_orm::entity::prelude::*; |
|
|
|
use serde_json::json; |
|
use tera::{Context, Tera}; |
|
use tokio::sync::OnceCell; |
|
use tracing::error; |
|
use tracing::info; |
|
|
|
pub async fn migrate_and_seed_db(db: &DatabaseConnection) -> Result<(), DbErr> { |
|
Migrator::up(db, None).await?; |
|
match User::find().one(db).await? { |
|
Some(_) => Ok(()), |
|
None => { |
|
User::insert(user::ActiveModel::from_json(json!({ |
|
"name": "admin", |
|
"is_admin": true, |
|
"password": hash_password("adminadmin".as_bytes()), |
|
}))?) |
|
.exec(db) |
|
.await?; |
|
info!("created default admin user. log in as admin / no password on the web interface"); |
|
Ok(()) |
|
} |
|
} |
|
} |
|
|
|
pub async fn insert_dev_test_data(db: &DatabaseConnection, charset: Vec<char>, len: usize) -> Result<(), DbErr> { |
|
if User::find().filter(user::Column::Name.eq("dev")).one(db).await?.is_none() { |
|
|
|
let dev_password = hash_password("a-password".as_bytes()); |
|
let dev_uid = User::insert(user::ActiveModel::from_json(json!({ |
|
"name": "dev", |
|
"is_admin": false, |
|
"password": dev_password, |
|
}))?).exec(db).await?.last_insert_id; |
|
info!("created dev user"); |
|
|
|
let dev_link1 = Link::insert(link::ActiveModel::from_json(json!({ |
|
"source": "example", |
|
"target": "http://example.com", |
|
"user_id": dev_uid, |
|
}))?).exec(db).await?.last_insert_id; |
|
|
|
let dev_link2 = Link::insert(link::ActiveModel::from_json(json!({ |
|
"source": gen_id(len, charset), |
|
"target": "https://random.org", |
|
"user_id": dev_uid, |
|
}))?).exec(db).await?.last_insert_id; |
|
|
|
info!("created two links for dev user"); |
|
} |
|
|
|
Ok(()) |
|
} |
|
|
|
static TERA: OnceCell<Tera> = OnceCell::const_new(); |
|
|
|
pub async fn get_tera() -> &'static Tera { |
|
TERA.get_or_init(|| async { |
|
Tera::new("templates/**/*") |
|
.map_err(|e| format!("Error parsing tera template: {}", e)) |
|
.unwrap() |
|
}) |
|
.await |
|
} |
|
|
|
fn get_default_context() -> Context { |
|
todo!() |
|
} |
|
|
|
pub async fn render_template( |
|
template_name: &str, |
|
context: Option<Context>, |
|
) -> Result<String, tera::Error> { |
|
let tera = get_tera().await; |
|
let rendered = tera.render(template_name, &context.unwrap_or_else(get_default_context))?; |
|
Ok(rendered) |
|
} |
|
|
|
pub async fn render_status_code(sc: StatusCode) -> String { |
|
let tera = get_tera().await; |
|
let mut context = Context::new(); |
|
context.insert("status_int", &sc.as_u16()); |
|
context.insert( |
|
"status_text", |
|
&sc.canonical_reason() |
|
.unwrap_or("<unknown canonical reason>"), |
|
); |
|
context.insert("status_rendered", &format!("{}", sc)); |
|
|
|
tera.render("error.html", &context) |
|
.expect("status code template should be infaliible") |
|
} |
|
|
|
pub fn hash_password(pw: &[u8]) -> String { |
|
let argon2 = Argon2::default(); |
|
let salt = SaltString::generate(&mut OsRng); |
|
argon2 |
|
.hash_password(pw, &salt) |
|
.expect("hell is empty") |
|
.to_string() |
|
} |
|
|
|
pub fn verify_password(pw: &[u8], hash: &str) -> bool { |
|
let parsed_hash = PasswordHash::new(hash).expect("hash in the database ought to be valid"); |
|
Argon2::default().verify_password(pw, &parsed_hash).is_ok() |
|
} |
|
|
|
pub fn log_into_status_code(e: impl Display) -> StatusCode { |
|
error!("{}", e); |
|
StatusCode::INTERNAL_SERVER_ERROR |
|
} |
|
|
|
pub fn gen_id(len: usize, charset: Vec<char>) -> String { |
|
nanoid::nanoid!(len, &charset) |
|
}
|
|
|