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
 | 
					# Reading in configuration files
 | 
				
			||||||
figment = { version = "*", features = [ "yaml" ] }
 | 
					figment = { version = "*", features = [ "yaml" ] }
 | 
				
			||||||
mimalloc = { version = "0.1.26", default_features = false }
 | 
					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:
 | 
					  limits:
 | 
				
			||||||
    forms: 32768
 | 
					    forms: 32768
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  admin_user: "bever"
 | 
					  admin:
 | 
				
			||||||
  admin_pass: "bever"
 | 
					    username: "bever"
 | 
				
			||||||
 | 
					    password: "bever"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  jwt:
 | 
					  jwt:
 | 
				
			||||||
    key: "secret"
 | 
					    key: "secret"
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -7,10 +7,11 @@ use rb::{
 | 
				
			||||||
    auth::JwtConf,
 | 
					    auth::JwtConf,
 | 
				
			||||||
    errors::{RbError, RbResult},
 | 
					    errors::{RbError, RbResult},
 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
use rb_gw::db;
 | 
					 | 
				
			||||||
use serde::{Deserialize, Serialize};
 | 
					use serde::{Deserialize, Serialize};
 | 
				
			||||||
use sha2::Sha256;
 | 
					use sha2::Sha256;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					use crate::db;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#[derive(Serialize)]
 | 
					#[derive(Serialize)]
 | 
				
			||||||
#[serde(rename_all = "camelCase")]
 | 
					#[serde(rename_all = "camelCase")]
 | 
				
			||||||
pub struct JWTResponse
 | 
					pub struct JWTResponse
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -2,7 +2,8 @@ use argon2::verify_encoded;
 | 
				
			||||||
use diesel::PgConnection;
 | 
					use diesel::PgConnection;
 | 
				
			||||||
use rand::{thread_rng, Rng};
 | 
					use rand::{thread_rng, Rng};
 | 
				
			||||||
use rb::errors::{RbError, RbResult};
 | 
					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>
 | 
					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);
 | 
					        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),
 | 
					        Ok(true) => Ok(user),
 | 
				
			||||||
        _ => Err(RbError::AuthInvalidPassword),
 | 
					        _ => Err(RbError::AuthInvalidPassword),
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -3,7 +3,10 @@ use rb::errors::{RbError, RbResult};
 | 
				
			||||||
use serde::{Deserialize, Serialize};
 | 
					use serde::{Deserialize, Serialize};
 | 
				
			||||||
use uuid::Uuid;
 | 
					use uuid::Uuid;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
use crate::schema::{users, users::dsl::*};
 | 
					use crate::{
 | 
				
			||||||
 | 
					    auth::pass::hash_password,
 | 
				
			||||||
 | 
					    schema::{users, users::dsl::*},
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#[derive(Queryable, Serialize)]
 | 
					#[derive(Queryable, Serialize)]
 | 
				
			||||||
pub struct User
 | 
					pub struct User
 | 
				
			||||||
| 
						 | 
					@ -11,12 +14,12 @@ pub struct User
 | 
				
			||||||
    pub id: Uuid,
 | 
					    pub id: Uuid,
 | 
				
			||||||
    pub username: String,
 | 
					    pub username: String,
 | 
				
			||||||
    #[serde(skip_serializing)]
 | 
					    #[serde(skip_serializing)]
 | 
				
			||||||
    pub password: String,
 | 
					    pub password_hash: String,
 | 
				
			||||||
    pub blocked: bool,
 | 
					    pub blocked: bool,
 | 
				
			||||||
    pub admin: bool,
 | 
					    pub admin: bool,
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#[derive(Insertable, Deserialize)]
 | 
					#[derive(Insertable, Deserialize, AsChangeset)]
 | 
				
			||||||
#[table_name = "users"]
 | 
					#[table_name = "users"]
 | 
				
			||||||
pub struct NewUser
 | 
					pub struct NewUser
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
| 
						 | 
					@ -31,7 +34,9 @@ pub struct NewUser
 | 
				
			||||||
pub struct PatchSection
 | 
					pub struct PatchSection
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
    username: Option<String>,
 | 
					    username: Option<String>,
 | 
				
			||||||
 | 
					    password: Option<String>,
 | 
				
			||||||
    admin: Option<bool>,
 | 
					    admin: Option<bool>,
 | 
				
			||||||
 | 
					    blocked: Option<bool>,
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
pub fn get(conn: &PgConnection, offset_: u32, limit_: u32) -> RbResult<Vec<User>>
 | 
					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
 | 
					/// * `conn` - database connection to use
 | 
				
			||||||
/// * `new_user` - user to insert
 | 
					/// * `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)
 | 
					    let count = diesel::insert_into(users)
 | 
				
			||||||
        .values(new_user)
 | 
					        .values(hashed_new_user)
 | 
				
			||||||
        .execute(conn)
 | 
					        .execute(conn)
 | 
				
			||||||
        .map_err(|_| RbError::DbError("Couldn't create user."))?;
 | 
					        .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
 | 
					/// * `conn` - database connection to use
 | 
				
			||||||
/// * `new_user` - user to insert/update
 | 
					/// * `new_user` - user to insert/update
 | 
				
			||||||
// pub fn create_or_update(conn: &PgConnection, new_user: &NewUser) -> RbResult<()>
 | 
					pub fn create_or_update(conn: &PgConnection, new_user: NewUser) -> RbResult<()>
 | 
				
			||||||
// {
 | 
					{
 | 
				
			||||||
//     diesel::insert_into(users)
 | 
					    let hashed_new_user = NewUser {
 | 
				
			||||||
//         .values(new_user)
 | 
					        password: hash_password(&new_user.password)?,
 | 
				
			||||||
//         .on_conflict(username)
 | 
					        ..new_user
 | 
				
			||||||
//         .do_update()
 | 
					    };
 | 
				
			||||||
//         .set(new_user)
 | 
					 | 
				
			||||||
//         .execute(conn)
 | 
					 | 
				
			||||||
//         .map_err(|_| RbError::DbError("Couldn't create or update 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.
 | 
					/// Delete the user with the given ID.
 | 
				
			||||||
///
 | 
					///
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -1,5 +1,6 @@
 | 
				
			||||||
#[macro_use]
 | 
					#[macro_use]
 | 
				
			||||||
extern crate diesel;
 | 
					extern crate diesel;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					pub mod auth;
 | 
				
			||||||
pub mod db;
 | 
					pub mod db;
 | 
				
			||||||
pub(crate) mod schema;
 | 
					pub(crate) mod schema;
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
							
								
								
									
										70
									
								
								src/main.rs
								
								
								
								
							
							
						
						
									
										70
									
								
								src/main.rs
								
								
								
								
							| 
						 | 
					@ -2,24 +2,22 @@
 | 
				
			||||||
extern crate rocket;
 | 
					extern crate rocket;
 | 
				
			||||||
#[macro_use]
 | 
					#[macro_use]
 | 
				
			||||||
extern crate diesel_migrations;
 | 
					extern crate diesel_migrations;
 | 
				
			||||||
#[macro_use]
 | 
					 | 
				
			||||||
extern crate diesel;
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
use figment::{
 | 
					use figment::{
 | 
				
			||||||
    providers::{Env, Format, Yaml},
 | 
					    providers::{Env, Format, Yaml},
 | 
				
			||||||
    Figment,
 | 
					    Figment,
 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
use rb::auth::JwtConf;
 | 
					use rb::{auth::JwtConf, errors::RbError};
 | 
				
			||||||
 | 
					use rb_gw::db;
 | 
				
			||||||
use rocket::{
 | 
					use rocket::{
 | 
				
			||||||
    fairing::AdHoc,
 | 
					    fairing::AdHoc,
 | 
				
			||||||
    http::Status,
 | 
					    http::Status,
 | 
				
			||||||
    serde::json::{json, Value},
 | 
					    serde::json::{json, Value},
 | 
				
			||||||
    Build, Orbit, Request, Rocket,
 | 
					    Build, Ignite, Request, Rocket,
 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
use rocket_sync_db_pools::database;
 | 
					use rocket_sync_db_pools::database;
 | 
				
			||||||
use serde::{Deserialize, Serialize};
 | 
					use serde::{Deserialize, Serialize};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
pub mod auth;
 | 
					 | 
				
			||||||
pub mod v1;
 | 
					pub mod v1;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#[database("postgres_rb")]
 | 
					#[database("postgres_rb")]
 | 
				
			||||||
| 
						 | 
					@ -45,26 +43,41 @@ async fn run_db_migrations(rocket: Rocket<Build>) -> Result<Rocket<Build>, Rocke
 | 
				
			||||||
    .await
 | 
					    .await
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
// async fn create_admin_user<'a>(rocket: &'a Rocket<Orbit>)
 | 
					async fn create_admin_user(rocket: Rocket<Build>) -> Result<Rocket<Build>, Rocket<Build>>
 | 
				
			||||||
// {
 | 
					{
 | 
				
			||||||
//     let config = rocket.state::<RbConfig>().expect("RbConfig instance");
 | 
					    let admin = rocket.state::<AdminConfig>().expect("admin config");
 | 
				
			||||||
//     let admin_user = config.admin_user.clone();
 | 
					 | 
				
			||||||
//     let admin_pass = config.admin_pass.clone();
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
//     let conn = RbDbConn::get_one(&rocket)
 | 
					    let conn = RbDbConn::get_one(&rocket)
 | 
				
			||||||
//         .await
 | 
					        .await
 | 
				
			||||||
//         .expect("database connection");
 | 
					        .expect("database connection");
 | 
				
			||||||
//     conn.run(move |c| {
 | 
					
 | 
				
			||||||
//         admin::create_admin_user(c, &admin_user, &admin_pass).expect("failed to create admin user")
 | 
					    let new_user = db::NewUser {
 | 
				
			||||||
//     })
 | 
					        username: admin.username.clone(),
 | 
				
			||||||
//     .await;
 | 
					        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)]
 | 
					#[derive(Debug, Deserialize, Serialize)]
 | 
				
			||||||
pub struct RbConfig
 | 
					pub struct RbConfig
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
    admin_user: String,
 | 
					    admin: AdminConfig,
 | 
				
			||||||
    admin_pass: String,
 | 
					 | 
				
			||||||
    jwt: JwtConf,
 | 
					    jwt: JwtConf,
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -75,7 +88,7 @@ fn rocket() -> _
 | 
				
			||||||
        .merge(Yaml::file("Rb.yaml").nested())
 | 
					        .merge(Yaml::file("Rb.yaml").nested())
 | 
				
			||||||
        .merge(Env::prefixed("RB_").global());
 | 
					        .merge(Env::prefixed("RB_").global());
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    rocket::custom(figment)
 | 
					    let rocket = rocket::custom(figment)
 | 
				
			||||||
        .attach(RbDbConn::fairing())
 | 
					        .attach(RbDbConn::fairing())
 | 
				
			||||||
        .attach(AdHoc::try_on_ignite(
 | 
					        .attach(AdHoc::try_on_ignite(
 | 
				
			||||||
            "Run database migrations",
 | 
					            "Run database migrations",
 | 
				
			||||||
| 
						 | 
					@ -91,5 +104,18 @@ fn rocket() -> _
 | 
				
			||||||
                v1::auth::login,
 | 
					                v1::auth::login,
 | 
				
			||||||
                v1::auth::refresh_token,
 | 
					                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::{errors::RbResult, guards::User};
 | 
				
			||||||
 | 
					use rb_gw::auth::{
 | 
				
			||||||
 | 
					    jwt::{generate_jwt_token, JWTResponse},
 | 
				
			||||||
 | 
					    pass::verify_user,
 | 
				
			||||||
 | 
					    Credentials,
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
use rocket::{serde::json::Json, State};
 | 
					use rocket::{serde::json::Json, State};
 | 
				
			||||||
use serde::Deserialize;
 | 
					use serde::Deserialize;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
use crate::{
 | 
					use crate::{RbConfig, RbDbConn};
 | 
				
			||||||
    auth::{
 | 
					 | 
				
			||||||
        jwt::{generate_jwt_token, JWTResponse},
 | 
					 | 
				
			||||||
        pass::verify_user,
 | 
					 | 
				
			||||||
        Credentials,
 | 
					 | 
				
			||||||
    },
 | 
					 | 
				
			||||||
    RbConfig, RbDbConn,
 | 
					 | 
				
			||||||
};
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
#[post("/login")]
 | 
					#[post("/login")]
 | 
				
			||||||
pub async fn already_logged_in(_user: User) -> String
 | 
					pub async fn already_logged_in(_user: User) -> String
 | 
				
			||||||
| 
						 | 
					@ -56,7 +54,7 @@ pub async fn refresh_token(
 | 
				
			||||||
    let jwt = conf.jwt.clone();
 | 
					    let jwt = conf.jwt.clone();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    Ok(Json(
 | 
					    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?,
 | 
					            .await?,
 | 
				
			||||||
    ))
 | 
					    ))
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
		Reference in New Issue