Admin user can now be properly created

main
Jef Roosens 2021-11-25 10:19:01 +01:00
parent 8163217700
commit 0449af66d2
Signed by: Jef Roosens
GPG Key ID: 955C0660072F691F
8 changed files with 114 additions and 52 deletions

View File

@ -39,3 +39,22 @@ base64 = "0.13.0"
# Reading in configuration files
figment = { version = "*", features = [ "yaml" ] }
mimalloc = { version = "0.1.26", default_features = false }
[profile.dev]
lto = "off"
incremental = true
[profile.test]
lto = "off"
incremental = true
[profile.release]
lto = "fat"
incremental = true
codegen-units = 1
# For releases also try to max optimizations for dependencies:
[profile.release.build-override]
opt-level = 3
[profile.release.package."*"]
opt-level = 3

View File

@ -10,8 +10,9 @@ debug:
limits:
forms: 32768
admin_user: "bever"
admin_pass: "bever"
admin:
username: "bever"
password: "bever"
jwt:
key: "secret"

View File

@ -7,10 +7,11 @@ use rb::{
auth::JwtConf,
errors::{RbError, RbResult},
};
use rb_gw::db;
use serde::{Deserialize, Serialize};
use sha2::Sha256;
use crate::db;
#[derive(Serialize)]
#[serde(rename_all = "camelCase")]
pub struct JWTResponse

View File

@ -2,7 +2,8 @@ use argon2::verify_encoded;
use diesel::PgConnection;
use rand::{thread_rng, Rng};
use rb::errors::{RbError, RbResult};
use rb_gw::db;
use crate::db;
pub fn verify_user(conn: &PgConnection, username: &str, password: &str) -> RbResult<db::User>
{
@ -14,7 +15,7 @@ pub fn verify_user(conn: &PgConnection, username: &str, password: &str) -> RbRes
return Err(RbError::AuthBlockedUser);
}
match verify_encoded(user.password.as_str(), password.as_bytes()) {
match verify_encoded(user.password_hash.as_str(), password.as_bytes()) {
Ok(true) => Ok(user),
_ => Err(RbError::AuthInvalidPassword),
}

View File

@ -3,7 +3,10 @@ use rb::errors::{RbError, RbResult};
use serde::{Deserialize, Serialize};
use uuid::Uuid;
use crate::schema::{users, users::dsl::*};
use crate::{
auth::pass::hash_password,
schema::{users, users::dsl::*},
};
#[derive(Queryable, Serialize)]
pub struct User
@ -11,12 +14,12 @@ pub struct User
pub id: Uuid,
pub username: String,
#[serde(skip_serializing)]
pub password: String,
pub password_hash: String,
pub blocked: bool,
pub admin: bool,
}
#[derive(Insertable, Deserialize)]
#[derive(Insertable, Deserialize, AsChangeset)]
#[table_name = "users"]
pub struct NewUser
{
@ -31,7 +34,9 @@ pub struct NewUser
pub struct PatchSection
{
username: Option<String>,
password: Option<String>,
admin: Option<bool>,
blocked: Option<bool>,
}
pub fn get(conn: &PgConnection, offset_: u32, limit_: u32) -> RbResult<Vec<User>>
@ -62,10 +67,15 @@ pub fn find_by_username(conn: &PgConnection, username_: &str) -> RbResult<User>
///
/// * `conn` - database connection to use
/// * `new_user` - user to insert
pub fn create(conn: &PgConnection, new_user: &NewUser) -> RbResult<()>
pub fn create(conn: &PgConnection, new_user: NewUser) -> RbResult<()>
{
let hashed_new_user = NewUser {
password: hash_password(&new_user.password)?,
..new_user
};
let count = diesel::insert_into(users)
.values(new_user)
.values(hashed_new_user)
.execute(conn)
.map_err(|_| RbError::DbError("Couldn't create user."))?;
@ -82,18 +92,23 @@ pub fn create(conn: &PgConnection, new_user: &NewUser) -> RbResult<()>
///
/// * `conn` - database connection to use
/// * `new_user` - user to insert/update
// pub fn create_or_update(conn: &PgConnection, new_user: &NewUser) -> RbResult<()>
// {
// diesel::insert_into(users)
// .values(new_user)
// .on_conflict(username)
// .do_update()
// .set(new_user)
// .execute(conn)
// .map_err(|_| RbError::DbError("Couldn't create or update user."))?;
pub fn create_or_update(conn: &PgConnection, new_user: NewUser) -> RbResult<()>
{
let hashed_new_user = NewUser {
password: hash_password(&new_user.password)?,
..new_user
};
// Ok(())
// }
diesel::insert_into(users)
.values(&hashed_new_user)
.on_conflict(username)
.do_update()
.set(&hashed_new_user)
.execute(conn)
.map_err(|_| RbError::DbError("Couldn't create or update user."))?;
Ok(())
}
/// Delete the user with the given ID.
///

View File

@ -1,5 +1,6 @@
#[macro_use]
extern crate diesel;
pub mod auth;
pub mod db;
pub(crate) mod schema;

View File

@ -2,24 +2,22 @@
extern crate rocket;
#[macro_use]
extern crate diesel_migrations;
#[macro_use]
extern crate diesel;
use figment::{
providers::{Env, Format, Yaml},
Figment,
};
use rb::auth::JwtConf;
use rb::{auth::JwtConf, errors::RbError};
use rb_gw::db;
use rocket::{
fairing::AdHoc,
http::Status,
serde::json::{json, Value},
Build, Orbit, Request, Rocket,
Build, Ignite, Request, Rocket,
};
use rocket_sync_db_pools::database;
use serde::{Deserialize, Serialize};
pub mod auth;
pub mod v1;
#[database("postgres_rb")]
@ -45,26 +43,41 @@ async fn run_db_migrations(rocket: Rocket<Build>) -> Result<Rocket<Build>, Rocke
.await
}
// async fn create_admin_user<'a>(rocket: &'a Rocket<Orbit>)
// {
// let config = rocket.state::<RbConfig>().expect("RbConfig instance");
// let admin_user = config.admin_user.clone();
// let admin_pass = config.admin_pass.clone();
async fn create_admin_user(rocket: Rocket<Build>) -> Result<Rocket<Build>, Rocket<Build>>
{
let admin = rocket.state::<AdminConfig>().expect("admin config");
// let conn = RbDbConn::get_one(&rocket)
// .await
// .expect("database connection");
// conn.run(move |c| {
// admin::create_admin_user(c, &admin_user, &admin_pass).expect("failed to create admin user")
// })
// .await;
// }
let conn = RbDbConn::get_one(&rocket)
.await
.expect("database connection");
let new_user = db::NewUser {
username: admin.username.clone(),
password: admin.password.clone(),
admin: true,
};
match conn
.run(move |c| db::users::create_or_update(c, new_user))
.await
{
Ok(_) => Ok(rocket),
Err(RbError::UMDuplicateUser) => Ok(rocket),
Err(_) => Err(rocket),
}
}
#[derive(Debug, Deserialize, Serialize)]
pub struct AdminConfig
{
username: String,
password: String,
}
#[derive(Debug, Deserialize, Serialize)]
pub struct RbConfig
{
admin_user: String,
admin_pass: String,
admin: AdminConfig,
jwt: JwtConf,
}
@ -75,7 +88,7 @@ fn rocket() -> _
.merge(Yaml::file("Rb.yaml").nested())
.merge(Env::prefixed("RB_").global());
rocket::custom(figment)
let rocket = rocket::custom(figment)
.attach(RbDbConn::fairing())
.attach(AdHoc::try_on_ignite(
"Run database migrations",
@ -91,5 +104,18 @@ fn rocket() -> _
v1::auth::login,
v1::auth::refresh_token,
],
)
);
// This let's the guards properly access the JWT credentials when needed
let new_figment = rocket.figment();
let jwt_conf: JwtConf = new_figment.extract_inner("jwt").expect("jwt config");
// We do the same thing here so we can access the admin credentials for initially creating the
// admin user
let admin_conf: AdminConfig = new_figment.extract_inner("admin").expect("admin config");
rocket
.manage(jwt_conf)
.manage(admin_conf)
.attach(AdHoc::try_on_ignite("Create admin user", create_admin_user))
}

View File

@ -1,15 +1,13 @@
use rb::{errors::RbResult, guards::User};
use rb_gw::auth::{
jwt::{generate_jwt_token, JWTResponse},
pass::verify_user,
Credentials,
};
use rocket::{serde::json::Json, State};
use serde::Deserialize;
use crate::{
auth::{
jwt::{generate_jwt_token, JWTResponse},
pass::verify_user,
Credentials,
},
RbConfig, RbDbConn,
};
use crate::{RbConfig, RbDbConn};
#[post("/login")]
pub async fn already_logged_in(_user: User) -> String
@ -56,7 +54,7 @@ pub async fn refresh_token(
let jwt = conf.jwt.clone();
Ok(Json(
conn.run(move |c| crate::auth::jwt::refresh_token(c, &jwt, &refresh_token))
conn.run(move |c| rb_gw::auth::jwt::refresh_token(c, &jwt, &refresh_token))
.await?,
))
}