create password reset utility
Co-authored-by: Wout Schellaert <wout.schellaert@gmail.com>
This commit is contained in:
parent
58c1c5f9fb
commit
406c726601
4 changed files with 92 additions and 8 deletions
|
@ -2,8 +2,16 @@
|
|||
name = "planetwars-server"
|
||||
version = "0.0.0"
|
||||
edition = "2021"
|
||||
default-run = "planetwars-server"
|
||||
|
||||
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
|
||||
[[bin]]
|
||||
name = "planetwars-server"
|
||||
path = "src/main.rs"
|
||||
|
||||
[[bin]]
|
||||
name = "planetwars-server-cli"
|
||||
path = "src/cli.rs"
|
||||
|
||||
[dependencies]
|
||||
futures = "0.3"
|
||||
|
@ -32,6 +40,7 @@ sha2 = "0.10"
|
|||
tokio-util = { version="0.7.3", features=["io"] }
|
||||
prost = "0.10"
|
||||
tonic = "0.7.2"
|
||||
clap = { version = "3.2", features = ["derive", "env"]}
|
||||
|
||||
# TODO: remove me
|
||||
shlex = "1.1"
|
||||
|
|
54
planetwars-server/src/cli.rs
Normal file
54
planetwars-server/src/cli.rs
Normal file
|
@ -0,0 +1,54 @@
|
|||
extern crate planetwars_server;
|
||||
extern crate tokio;
|
||||
|
||||
use clap::Parser;
|
||||
use planetwars_server::db;
|
||||
use planetwars_server::{create_db_pool, get_config};
|
||||
|
||||
#[derive(clap::Parser)]
|
||||
struct Args {
|
||||
#[clap(subcommand)]
|
||||
action: Action,
|
||||
}
|
||||
|
||||
#[derive(clap::Subcommand)]
|
||||
enum Action {
|
||||
SetPassword(SetPassword),
|
||||
}
|
||||
|
||||
impl Action {
|
||||
async fn run(self) {
|
||||
match self {
|
||||
Action::SetPassword(set_password) => set_password.run().await,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(clap::Parser)]
|
||||
struct SetPassword {
|
||||
#[clap(value_parser)]
|
||||
username: String,
|
||||
|
||||
#[clap(value_parser)]
|
||||
new_password: String,
|
||||
}
|
||||
|
||||
impl SetPassword {
|
||||
async fn run(self) {
|
||||
let global_config = get_config().unwrap();
|
||||
let pool = create_db_pool(&global_config).await;
|
||||
|
||||
let conn = pool.get().await.expect("could not get database connection");
|
||||
let credentials = db::users::Credentials {
|
||||
username: &self.username,
|
||||
password: &self.new_password,
|
||||
};
|
||||
db::users::set_user_password(credentials, &conn).expect("could not set password");
|
||||
}
|
||||
}
|
||||
|
||||
#[tokio::main]
|
||||
pub async fn main() {
|
||||
let args = Args::parse();
|
||||
args.action.run().await;
|
||||
}
|
|
@ -42,11 +42,17 @@ fn argon2_config() -> argon2::Config<'static> {
|
|||
}
|
||||
}
|
||||
|
||||
pub fn create_user(credentials: &Credentials, conn: &PgConnection) -> QueryResult<User> {
|
||||
pub fn hash_password(password: &str) -> (Vec<u8>, [u8; 32]) {
|
||||
let argon_config = argon2_config();
|
||||
|
||||
let salt: [u8; 32] = rand::thread_rng().gen();
|
||||
let hash = argon2::hash_raw(credentials.password.as_bytes(), &salt, &argon_config).unwrap();
|
||||
let hash = argon2::hash_raw(password.as_bytes(), &salt, &argon_config).unwrap();
|
||||
|
||||
(hash, salt)
|
||||
}
|
||||
|
||||
pub fn create_user(credentials: &Credentials, conn: &PgConnection) -> QueryResult<User> {
|
||||
let (hash, salt) = hash_password(&credentials.password);
|
||||
|
||||
let new_user = NewUser {
|
||||
username: credentials.username,
|
||||
password_salt: &salt,
|
||||
|
@ -69,6 +75,22 @@ pub fn find_user_by_name(username: &str, db_conn: &PgConnection) -> QueryResult<
|
|||
.first::<User>(db_conn)
|
||||
}
|
||||
|
||||
pub fn set_user_password(credentials: Credentials, db_conn: &PgConnection) -> QueryResult<()> {
|
||||
let (hash, salt) = hash_password(&credentials.password);
|
||||
|
||||
let n_changes = diesel::update(users::table.filter(users::username.eq(&credentials.username)))
|
||||
.set((
|
||||
users::password_salt.eq(salt.as_slice()),
|
||||
users::password_hash.eq(hash.as_slice()),
|
||||
))
|
||||
.execute(db_conn)?;
|
||||
if n_changes == 0 {
|
||||
Err(diesel::result::Error::NotFound)
|
||||
} else {
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
pub fn authenticate_user(credentials: &Credentials, db_conn: &PgConnection) -> Option<User> {
|
||||
find_user_by_name(credentials.username, db_conn)
|
||||
.optional()
|
||||
|
|
|
@ -94,11 +94,9 @@ pub async fn seed_simplebot(config: &GlobalConfig, pool: &ConnectionPool) {
|
|||
|
||||
pub type DbPool = Pool<DieselConnectionManager<PgConnection>>;
|
||||
|
||||
pub async fn prepare_db(config: &GlobalConfig) -> DbPool {
|
||||
pub async fn create_db_pool(config: &GlobalConfig) -> DbPool {
|
||||
let manager = DieselConnectionManager::<PgConnection>::new(&config.database_url);
|
||||
let pool = bb8::Pool::builder().build(manager).await.unwrap();
|
||||
seed_simplebot(config, &pool).await;
|
||||
pool
|
||||
bb8::Pool::builder().build(manager).await.unwrap()
|
||||
}
|
||||
|
||||
// create all directories required for further operation
|
||||
|
@ -165,7 +163,8 @@ async fn run_registry(config: Arc<GlobalConfig>, db_pool: DbPool) {
|
|||
|
||||
pub async fn run_app() {
|
||||
let global_config = Arc::new(get_config().unwrap());
|
||||
let db_pool = prepare_db(&global_config).await;
|
||||
let db_pool = create_db_pool(&global_config).await;
|
||||
seed_simplebot(&global_config, &db_pool).await;
|
||||
init_directories(&global_config).unwrap();
|
||||
|
||||
if global_config.ranker_enabled {
|
||||
|
|
Loading…
Reference in a new issue