summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--Cargo.lock8
-rw-r--r--Cargo.toml2
-rw-r--r--sqlx-data.json154
-rw-r--r--src/main.rs3
-rw-r--r--src/services/crypto.rs36
-rw-r--r--src/services/db.rs5
-rw-r--r--src/services/mod.rs1
-rw-r--r--src/services/secrets.rs13
8 files changed, 200 insertions, 22 deletions
diff --git a/Cargo.lock b/Cargo.lock
index 1fb82f4..582a115 100644
--- a/Cargo.lock
+++ b/Cargo.lock
@@ -512,6 +512,12 @@ dependencies = [
]
[[package]]
+name = "dotenv"
+version = "0.15.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "77c90badedccf4105eca100756a0b1289e191f6fcbdadd3cee1d2f614f97da8f"
+
+[[package]]
name = "dotenvy"
version = "0.15.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
@@ -1226,7 +1232,9 @@ name = "rust-pw-server"
version = "0.1.0"
dependencies = [
"actix-web",
+ "dotenv",
"exun",
+ "hex",
"raise",
"rand",
"rust-argon2",
diff --git a/Cargo.toml b/Cargo.toml
index 0c40ad7..4366420 100644
--- a/Cargo.toml
+++ b/Cargo.toml
@@ -12,6 +12,8 @@ thiserror = "1"
rust-argon2 = "1"
uuid = { version = "1", features = [ "v4", "fast-rng", "serde" ] }
raise = "2"
+dotenv = "0.15"
rand = "0.8"
sqlx = { version = "0.6", features = [ "runtime-actix-rustls", "mysql", "uuid", "offline" ] }
+hex = "0.4"
exun = "0.1"
diff --git a/sqlx-data.json b/sqlx-data.json
index 187cd79..eab27cc 100644
--- a/sqlx-data.json
+++ b/sqlx-data.json
@@ -1,5 +1,82 @@
{
"db": "MySQL",
+ "016610abc2d730ab748db57c97ea3d7c2cc38d1f3dbc7dfef86742454d4b15f1": {
+ "describe": {
+ "columns": [
+ {
+ "name": "user_id",
+ "ordinal": 0,
+ "type_info": {
+ "char_set": 63,
+ "flags": {
+ "bits": 4231
+ },
+ "max_size": 16,
+ "type": "String"
+ }
+ },
+ {
+ "name": "username",
+ "ordinal": 1,
+ "type_info": {
+ "char_set": 224,
+ "flags": {
+ "bits": 4101
+ },
+ "max_size": 1020,
+ "type": "VarString"
+ }
+ },
+ {
+ "name": "password_hash",
+ "ordinal": 2,
+ "type_info": {
+ "char_set": 63,
+ "flags": {
+ "bits": 4241
+ },
+ "max_size": 255,
+ "type": "Blob"
+ }
+ },
+ {
+ "name": "password_salt",
+ "ordinal": 3,
+ "type_info": {
+ "char_set": 63,
+ "flags": {
+ "bits": 4241
+ },
+ "max_size": 255,
+ "type": "Blob"
+ }
+ },
+ {
+ "name": "password_version",
+ "ordinal": 4,
+ "type_info": {
+ "char_set": 63,
+ "flags": {
+ "bits": 33
+ },
+ "max_size": 10,
+ "type": "Long"
+ }
+ }
+ ],
+ "nullable": [
+ false,
+ false,
+ false,
+ false,
+ false
+ ],
+ "parameters": {
+ "Right": 1
+ }
+ },
+ "query": "SELECT user_id, username, password_hash, password_salt, password_version\n\t\t FROM users WHERE user_id = ?"
+ },
"0e1cd93286d20bbaa3e25dbec43b5e28cfbe6506d2d47432259e228f7f92c867": {
"describe": {
"columns": [
@@ -80,6 +157,83 @@
},
"query": "UPDATE users SET\n\t\tpassword_hash = ?,\n\t\tpassword_salt = ?,\n\t\tpassword_version = ?\n\t\tWHERE user_id = ?"
},
+ "e87cb729ff241fce8e1ddcd43519105910b61184b1ed755a437bd511eac4f9cf": {
+ "describe": {
+ "columns": [
+ {
+ "name": "user_id",
+ "ordinal": 0,
+ "type_info": {
+ "char_set": 63,
+ "flags": {
+ "bits": 4231
+ },
+ "max_size": 16,
+ "type": "String"
+ }
+ },
+ {
+ "name": "username",
+ "ordinal": 1,
+ "type_info": {
+ "char_set": 224,
+ "flags": {
+ "bits": 4101
+ },
+ "max_size": 1020,
+ "type": "VarString"
+ }
+ },
+ {
+ "name": "password_hash",
+ "ordinal": 2,
+ "type_info": {
+ "char_set": 63,
+ "flags": {
+ "bits": 4241
+ },
+ "max_size": 255,
+ "type": "Blob"
+ }
+ },
+ {
+ "name": "password_salt",
+ "ordinal": 3,
+ "type_info": {
+ "char_set": 63,
+ "flags": {
+ "bits": 4241
+ },
+ "max_size": 255,
+ "type": "Blob"
+ }
+ },
+ {
+ "name": "password_version",
+ "ordinal": 4,
+ "type_info": {
+ "char_set": 63,
+ "flags": {
+ "bits": 33
+ },
+ "max_size": 10,
+ "type": "Long"
+ }
+ }
+ ],
+ "nullable": [
+ false,
+ false,
+ false,
+ false,
+ false
+ ],
+ "parameters": {
+ "Right": 1
+ }
+ },
+ "query": "SELECT user_id, username, password_hash, password_salt, password_version\n\t\t FROM users WHERE username = ?"
+ },
"ed4a40d7a9417985e6552d368146f5791717a41c16921f5074dfa14b637a9209": {
"describe": {
"columns": [],
diff --git a/src/main.rs b/src/main.rs
index dff3f3f..d454a8c 100644
--- a/src/main.rs
+++ b/src/main.rs
@@ -9,7 +9,8 @@ use services::*;
#[actix_web::main]
async fn main() -> Result<(), RawUnexpected> {
- let sql_pool = db::initialize("password_database", "dbuser", "Demo1234").await?;
+ let db_url = secrets::database_url()?;
+ let sql_pool = db::initialize(&db_url).await?;
HttpServer::new(move || {
App::new()
diff --git a/src/services/crypto.rs b/src/services/crypto.rs
index 580e83a..7ad2ce0 100644
--- a/src/services/crypto.rs
+++ b/src/services/crypto.rs
@@ -3,24 +3,23 @@ use std::hash::Hash;
use argon2::{hash_raw, verify_raw};
use exun::RawUnexpected;
-/// A custom pepper used to hide passwords
-static PEPPER: [u8; 16] = [
- 0x98, 0x7f, 0x6f, 0xce, 0x20, 0x76, 0x2c, 0x8a, 0xae, 0xf6, 0xee, 0x45, 0xb3, 0x6b, 0x1f, 0x69,
-];
+use crate::services::secrets::pepper;
/// The configuration used for hashing and verifying passwords
-static CONFIG: argon2::Config<'_> = argon2::Config {
- hash_length: 32,
- lanes: 4,
- mem_cost: 5333,
- time_cost: 4,
- secret: &PEPPER,
+fn config<'a>(pepper: &'a [u8]) -> argon2::Config<'a> {
+ argon2::Config {
+ hash_length: 32,
+ lanes: 4,
+ mem_cost: 5333,
+ time_cost: 4,
+ secret: pepper,
- ad: &[],
- thread_mode: argon2::ThreadMode::Sequential,
- variant: argon2::Variant::Argon2i,
- version: argon2::Version::Version13,
-};
+ ad: &[],
+ thread_mode: argon2::ThreadMode::Sequential,
+ variant: argon2::Variant::Argon2i,
+ version: argon2::Version::Version13,
+ }
+}
/// A password hash and salt for a user
#[derive(Debug, Clone, PartialEq, Eq)]
@@ -43,8 +42,8 @@ impl PasswordHash {
let salt: [u8; 16] = rand::random();
let salt = Box::from(salt);
-
- let hash = hash_raw(password, &salt, &CONFIG)?.into_boxed_slice();
+ let pepper = pepper()?;
+ let hash = hash_raw(password, &salt, &config(&pepper))?.into_boxed_slice();
Ok(Self {
hash,
@@ -78,11 +77,12 @@ impl PasswordHash {
/// Check if the given password is the one that was hashed
pub fn check_password(&self, password: &str) -> Result<bool, RawUnexpected> {
+ let pepper = pepper()?;
Ok(verify_raw(
password.as_bytes(),
&self.salt,
&self.hash,
- &CONFIG,
+ &config(&pepper),
)?)
}
}
diff --git a/src/services/db.rs b/src/services/db.rs
index 80335c4..b24c640 100644
--- a/src/services/db.rs
+++ b/src/services/db.rs
@@ -33,9 +33,8 @@ impl TryFrom<UserRow> for User {
}
/// Intialize the connection pool
-pub async fn initialize(db: &str, user: &str, password: &str) -> Result<MySqlPool, RawUnexpected> {
- let url = format!("mysql://{user}:{password}@localhost/{db}");
- MySqlPool::connect(&url).await.unexpect()
+pub async fn initialize(db_url: &str) -> Result<MySqlPool, RawUnexpected> {
+ MySqlPool::connect(db_url).await.unexpect()
}
pub async fn user_id_exists<'c>(
diff --git a/src/services/mod.rs b/src/services/mod.rs
index 57146d8..09d2159 100644
--- a/src/services/mod.rs
+++ b/src/services/mod.rs
@@ -1,3 +1,4 @@
pub mod crypto;
pub mod db;
pub mod id;
+pub mod secrets;
diff --git a/src/services/secrets.rs b/src/services/secrets.rs
new file mode 100644
index 0000000..e4a1ca1
--- /dev/null
+++ b/src/services/secrets.rs
@@ -0,0 +1,13 @@
+use std::env;
+
+use exun::*;
+
+pub fn pepper() -> Result<Box<[u8]>, RawUnexpected> {
+ let pepper = env::var("SECRET_SALT")?;
+ let pepper = hex::decode(pepper)?;
+ Ok(pepper.into_boxed_slice())
+}
+
+pub fn database_url() -> Result<String, RawUnexpected> {
+ env::var("DATABASE_URL").unexpect()
+}