Admin user can now be properly created
							parent
							
								
									8163217700
								
							
						
					
					
						commit
						0449af66d2
					
				
							
								
								
									
										19
									
								
								Cargo.toml
								
								
								
								
							
							
						
						
									
										19
									
								
								Cargo.toml
								
								
								
								
							| 
						 | 
				
			
			@ -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
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
							
								
								
									
										5
									
								
								Rb.yaml
								
								
								
								
							
							
						
						
									
										5
									
								
								Rb.yaml
								
								
								
								
							| 
						 | 
				
			
			@ -10,8 +10,9 @@ debug:
 | 
			
		|||
  limits:
 | 
			
		||||
    forms: 32768
 | 
			
		||||
 | 
			
		||||
  admin_user: "bever"
 | 
			
		||||
  admin_pass: "bever"
 | 
			
		||||
  admin:
 | 
			
		||||
    username: "bever"
 | 
			
		||||
    password: "bever"
 | 
			
		||||
 | 
			
		||||
  jwt:
 | 
			
		||||
    key: "secret"
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -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
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -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),
 | 
			
		||||
    }
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -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.
 | 
			
		||||
///
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -1,5 +1,6 @@
 | 
			
		|||
#[macro_use]
 | 
			
		||||
extern crate diesel;
 | 
			
		||||
 | 
			
		||||
pub mod auth;
 | 
			
		||||
pub mod db;
 | 
			
		||||
pub(crate) mod schema;
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
							
								
								
									
										70
									
								
								src/main.rs
								
								
								
								
							
							
						
						
									
										70
									
								
								src/main.rs
								
								
								
								
							| 
						 | 
				
			
			@ -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))
 | 
			
		||||
}
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -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?,
 | 
			
		||||
    ))
 | 
			
		||||
}
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
		Reference in New Issue