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"
|
name = "planetwars-server"
|
||||||
version = "0.0.0"
|
version = "0.0.0"
|
||||||
edition = "2021"
|
edition = "2021"
|
||||||
|
default-run = "planetwars-server"
|
||||||
|
|
||||||
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
|
# 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]
|
[dependencies]
|
||||||
futures = "0.3"
|
futures = "0.3"
|
||||||
|
@ -32,6 +40,7 @@ sha2 = "0.10"
|
||||||
tokio-util = { version="0.7.3", features=["io"] }
|
tokio-util = { version="0.7.3", features=["io"] }
|
||||||
prost = "0.10"
|
prost = "0.10"
|
||||||
tonic = "0.7.2"
|
tonic = "0.7.2"
|
||||||
|
clap = { version = "3.2", features = ["derive", "env"]}
|
||||||
|
|
||||||
# TODO: remove me
|
# TODO: remove me
|
||||||
shlex = "1.1"
|
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 argon_config = argon2_config();
|
||||||
|
|
||||||
let salt: [u8; 32] = rand::thread_rng().gen();
|
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 {
|
let new_user = NewUser {
|
||||||
username: credentials.username,
|
username: credentials.username,
|
||||||
password_salt: &salt,
|
password_salt: &salt,
|
||||||
|
@ -69,6 +75,22 @@ pub fn find_user_by_name(username: &str, db_conn: &PgConnection) -> QueryResult<
|
||||||
.first::<User>(db_conn)
|
.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> {
|
pub fn authenticate_user(credentials: &Credentials, db_conn: &PgConnection) -> Option<User> {
|
||||||
find_user_by_name(credentials.username, db_conn)
|
find_user_by_name(credentials.username, db_conn)
|
||||||
.optional()
|
.optional()
|
||||||
|
|
|
@ -94,11 +94,9 @@ pub async fn seed_simplebot(config: &GlobalConfig, pool: &ConnectionPool) {
|
||||||
|
|
||||||
pub type DbPool = Pool<DieselConnectionManager<PgConnection>>;
|
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 manager = DieselConnectionManager::<PgConnection>::new(&config.database_url);
|
||||||
let pool = bb8::Pool::builder().build(manager).await.unwrap();
|
bb8::Pool::builder().build(manager).await.unwrap()
|
||||||
seed_simplebot(config, &pool).await;
|
|
||||||
pool
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// create all directories required for further operation
|
// 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() {
|
pub async fn run_app() {
|
||||||
let global_config = Arc::new(get_config().unwrap());
|
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();
|
init_directories(&global_config).unwrap();
|
||||||
|
|
||||||
if global_config.ranker_enabled {
|
if global_config.ranker_enabled {
|
||||||
|
|
Loading…
Reference in a new issue