Add function to create a user

Signed-off-by: trivernis <trivernis@protonmail.com>
pull/1/head
trivernis 4 years ago
parent f571f062fa
commit c189b4bef9
Signed by: Trivernis
GPG Key ID: DFFFCC2C7A02DB45

@ -13,7 +13,8 @@
</component>
<component name="ChangeListManager">
<list default="true" id="db10ba0c-1d72-449d-b24f-24b5a4951941" name="Default Changelist" comment="">
<change beforePath="$PROJECT_DIR$/.env" beforeDir="false" afterPath="$PROJECT_DIR$/.env" afterDir="false" />
<change afterPath="$PROJECT_DIR$/src/database/models.rs" afterDir="false" />
<change afterPath="$PROJECT_DIR$/src/utils.rs" afterDir="false" />
<change beforePath="$PROJECT_DIR$/.idea/workspace.xml" beforeDir="false" afterPath="$PROJECT_DIR$/.idea/workspace.xml" afterDir="false" />
<change beforePath="$PROJECT_DIR$/Cargo.lock" beforeDir="false" afterPath="$PROJECT_DIR$/Cargo.lock" afterDir="false" />
<change beforePath="$PROJECT_DIR$/Cargo.toml" beforeDir="false" afterPath="$PROJECT_DIR$/Cargo.toml" afterDir="false" />
@ -23,6 +24,8 @@
<change beforePath="$PROJECT_DIR$/src/database/roles.rs" beforeDir="false" afterPath="$PROJECT_DIR$/src/database/roles.rs" afterDir="false" />
<change beforePath="$PROJECT_DIR$/src/database/user_roles.rs" beforeDir="false" afterPath="$PROJECT_DIR$/src/database/user_roles.rs" afterDir="false" />
<change beforePath="$PROJECT_DIR$/src/database/users.rs" beforeDir="false" afterPath="$PROJECT_DIR$/src/database/users.rs" afterDir="false" />
<change beforePath="$PROJECT_DIR$/src/lib.rs" beforeDir="false" afterPath="$PROJECT_DIR$/src/lib.rs" afterDir="false" />
<change beforePath="$PROJECT_DIR$/src/main.rs" beforeDir="false" afterPath="$PROJECT_DIR$/src/main.rs" afterDir="false" />
</list>
<option name="SHOW_DIALOG" value="false" />
<option name="HIGHLIGHT_CONFLICTS" value="true" />
@ -93,7 +96,7 @@
<option name="number" value="Default" />
<option name="presentableId" value="Default" />
<updated>1599728150675</updated>
<workItem from="1599728152100" duration="5535000" />
<workItem from="1599728152100" duration="9826000" />
</task>
<servers />
</component>
@ -105,22 +108,38 @@
<screen x="0" y="0" width="1920" height="1158" />
</state>
<state x="769" y="295" key="#com.intellij.ide.util.MemberChooser/0.0.1920.1158/1920.0.1680.1050@0.0.1920.1158" timestamp="1599732127954" />
<state width="1874" height="304" key="GridCell.Tab.0.bottom" timestamp="1599733668118">
<state width="1874" height="304" key="GridCell.Tab.0.bottom" timestamp="1599740697819">
<screen x="0" y="0" width="1920" height="1158" />
</state>
<state width="1874" height="304" key="GridCell.Tab.0.bottom/0.0.1920.1158/1920.0.1680.1050@0.0.1920.1158" timestamp="1599733668118" />
<state width="1874" height="304" key="GridCell.Tab.0.center" timestamp="1599733668118">
<state width="1874" height="304" key="GridCell.Tab.0.bottom/0.0.1920.1158/1920.0.1680.1050@0.0.1920.1158" timestamp="1599740697819" />
<state width="1874" height="304" key="GridCell.Tab.0.center" timestamp="1599740697819">
<screen x="0" y="0" width="1920" height="1158" />
</state>
<state width="1874" height="304" key="GridCell.Tab.0.center/0.0.1920.1158/1920.0.1680.1050@0.0.1920.1158" timestamp="1599733668118" />
<state width="1874" height="304" key="GridCell.Tab.0.left" timestamp="1599733668118">
<state width="1874" height="304" key="GridCell.Tab.0.center/0.0.1920.1158/1920.0.1680.1050@0.0.1920.1158" timestamp="1599740697819" />
<state width="1874" height="304" key="GridCell.Tab.0.left" timestamp="1599740697819">
<screen x="0" y="0" width="1920" height="1158" />
</state>
<state width="1874" height="304" key="GridCell.Tab.0.left/0.0.1920.1158/1920.0.1680.1050@0.0.1920.1158" timestamp="1599733668118" />
<state width="1874" height="304" key="GridCell.Tab.0.right" timestamp="1599733668118">
<state width="1874" height="304" key="GridCell.Tab.0.left/0.0.1920.1158/1920.0.1680.1050@0.0.1920.1158" timestamp="1599740697819" />
<state width="1874" height="304" key="GridCell.Tab.0.right" timestamp="1599740697819">
<screen x="0" y="0" width="1920" height="1158" />
</state>
<state width="1874" height="304" key="GridCell.Tab.0.right/0.0.1920.1158/1920.0.1680.1050@0.0.1920.1158" timestamp="1599733668118" />
<state width="1874" height="304" key="GridCell.Tab.0.right/0.0.1920.1158/1920.0.1680.1050@0.0.1920.1158" timestamp="1599740697819" />
<state width="1874" height="374" key="GridCell.Tab.1.bottom" timestamp="1599739654429">
<screen x="0" y="0" width="1920" height="1158" />
</state>
<state width="1874" height="374" key="GridCell.Tab.1.bottom/0.0.1920.1158/1920.0.1680.1050@0.0.1920.1158" timestamp="1599739654429" />
<state width="1874" height="374" key="GridCell.Tab.1.center" timestamp="1599739654428">
<screen x="0" y="0" width="1920" height="1158" />
</state>
<state width="1874" height="374" key="GridCell.Tab.1.center/0.0.1920.1158/1920.0.1680.1050@0.0.1920.1158" timestamp="1599739654428" />
<state width="1874" height="374" key="GridCell.Tab.1.left" timestamp="1599739654428">
<screen x="0" y="0" width="1920" height="1158" />
</state>
<state width="1874" height="374" key="GridCell.Tab.1.left/0.0.1920.1158/1920.0.1680.1050@0.0.1920.1158" timestamp="1599739654428" />
<state width="1874" height="374" key="GridCell.Tab.1.right" timestamp="1599739654428">
<screen x="0" y="0" width="1920" height="1158" />
</state>
<state width="1874" height="374" key="GridCell.Tab.1.right/0.0.1920.1158/1920.0.1680.1050@0.0.1920.1158" timestamp="1599739654428" />
<state x="457" y="211" key="SettingsEditor" timestamp="1599731723387">
<screen x="0" y="0" width="1920" height="1158" />
</state>

76
Cargo.lock generated

@ -252,6 +252,16 @@ dependencies = [
"subtle",
]
[[package]]
name = "crypto-mac"
version = "0.9.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "58bcd97a54c7ca5ce2f6eb16f6bede5b0ab5f0055fedc17d2f0b4466e21671ca"
dependencies = [
"generic-array",
"subtle",
]
[[package]]
name = "digest"
version = "0.9.0"
@ -298,7 +308,11 @@ dependencies = [
"dotenv",
"msgrpc",
"postgres",
"rand",
"redis",
"scrypt",
"serde",
"serde_postgres",
]
[[package]]
@ -469,7 +483,17 @@ version = "0.8.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "126888268dcc288495a26bf004b38c5fdbb31682f992c84ceb046a1f0fe38840"
dependencies = [
"crypto-mac",
"crypto-mac 0.8.0",
"digest",
]
[[package]]
name = "hmac"
version = "0.9.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "deae6d9dbb35ec2c502d62b8f7b1c000a0822c3b0794ba36b3149c0a1c840dff"
dependencies = [
"crypto-mac 0.9.1",
"digest",
]
@ -727,6 +751,15 @@ dependencies = [
"winapi 0.3.9",
]
[[package]]
name = "pbkdf2"
version = "0.5.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "7170d73bf11f39b4ce1809aabc95bf5c33564cdc16fc3200ddda17a5f6e5e48b"
dependencies = [
"crypto-mac 0.9.1",
]
[[package]]
name = "percent-encoding"
version = "2.1.0"
@ -820,7 +853,7 @@ dependencies = [
"byteorder",
"bytes",
"fallible-iterator",
"hmac",
"hmac 0.8.1",
"md5",
"memchr",
"rand",
@ -976,11 +1009,50 @@ version = "1.1.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d29ab0c6d3fc0ee92fe66e2d99f700eab17a8d57d1c1d3b748380fb20baa78cd"
[[package]]
name = "scrypt"
version = "0.4.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "3437654bbbe34054a268b3859fe41f871215069b39f0aef78808d85c37100696"
dependencies = [
"base64",
"hmac 0.9.0",
"pbkdf2",
"rand",
"rand_core",
"sha2",
"subtle",
]
[[package]]
name = "serde"
version = "1.0.115"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "e54c9a88f2da7238af84b5101443f0c0d0a3bbdc455e34a5c9497b1903ed55d5"
dependencies = [
"serde_derive",
]
[[package]]
name = "serde_derive"
version = "1.0.115"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "609feed1d0a73cc36a0182a840a9b37b4a82f0b1150369f0536a9e3f2a31dc48"
dependencies = [
"proc-macro2",
"quote",
"syn",
]
[[package]]
name = "serde_postgres"
version = "0.2.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "05272a9cdfedf1b7b43cd14151bd9566db49b6396254a4cf42aa3cf8df06fe7f"
dependencies = [
"serde",
"tokio-postgres",
]
[[package]]
name = "sha1"

@ -9,5 +9,9 @@ edition = "2018"
[dependencies]
msgrpc = {path = "./msg-rpc"}
postgres = "0.17.5"
serde_postgres = "0.2.0"
dotenv = "0.15.0"
redis = "0.17.0"
redis = "0.17.0"
serde = {version = "1.0.115", features = ["serde_derive"]}
rand = "0.7.3"
scrypt = "0.4.1"

@ -8,6 +8,7 @@ use postgres::{Client, NoTls};
use redis::{RedisError, RedisResult};
use std::sync::{Arc, Mutex};
pub mod models;
pub mod permissions;
pub mod role_permissions;
pub mod roles;
@ -24,7 +25,7 @@ pub type RedisClient = redis::Client;
pub type RedisConnection = redis::Connection;
pub type PostgresError = postgres::Error;
pub trait Model {
pub trait Table {
fn new(
database_connection: Arc<Mutex<DatabaseClient>>,
redis_connection: Arc<Mutex<RedisConnection>>,
@ -36,6 +37,9 @@ pub trait Model {
pub enum Error {
Redis(RedisError),
Postgres(PostgresError),
RecordExists,
ScryptError,
DeserializeError(serde_postgres::DeError),
}
pub type DatabaseError = Error;

@ -0,0 +1,23 @@
use postgres::Row;
use serde::Deserialize;
#[derive(Clone, Debug)]
pub struct UserRecord {
pub id: i32,
pub name: String,
pub email: String,
pub password_hash: Vec<u8>,
pub salt: Vec<u8>,
}
impl UserRecord {
pub fn from_ordered_row(row: &Row) -> Self {
Self {
id: row.get(0),
name: row.get(1),
email: row.get(2),
password_hash: row.get(3),
salt: row.get(4),
}
}
}

@ -1,4 +1,4 @@
use crate::database::{DatabaseClient, DatabaseError, DatabaseResult, Model, RedisConnection};
use crate::database::{DatabaseClient, DatabaseError, DatabaseResult, RedisConnection, Table};
use postgres::Client;
use std::sync::{Arc, Mutex};
@ -8,7 +8,7 @@ pub struct Permissions {
redis_connection: Arc<Mutex<RedisConnection>>,
}
impl Model for Permissions {
impl Table for Permissions {
fn new(
database_connection: Arc<Mutex<Client>>,
redis_connection: Arc<Mutex<RedisConnection>>,

@ -1,4 +1,4 @@
use crate::database::{DatabaseClient, DatabaseError, DatabaseResult, Model, RedisConnection};
use crate::database::{DatabaseClient, DatabaseError, DatabaseResult, RedisConnection, Table};
use postgres::{Client, Error};
use std::sync::{Arc, Mutex};
@ -8,7 +8,7 @@ pub struct RolePermissions {
redis_connection: Arc<Mutex<RedisConnection>>,
}
impl Model for RolePermissions {
impl Table for RolePermissions {
fn new(
database_connection: Arc<Mutex<DatabaseClient>>,
redis_connection: Arc<Mutex<RedisConnection>>,

@ -1,5 +1,5 @@
use crate::database::role_permissions::RolePermissions;
use crate::database::{DatabaseError, DatabaseResult, Model, RedisConnection};
use crate::database::{DatabaseError, DatabaseResult, RedisConnection, Table};
use postgres::{Client, Error};
use std::sync::{Arc, Mutex};
@ -10,7 +10,7 @@ pub struct Roles {
role_permission: RolePermissions,
}
impl Model for Roles {
impl Table for Roles {
fn new(
database_connection: Arc<Mutex<Client>>,
redis_connection: Arc<Mutex<RedisConnection>>,

@ -1,4 +1,4 @@
use crate::database::{DatabaseError, DatabaseResult, Model, RedisConnection};
use crate::database::{DatabaseError, DatabaseResult, RedisConnection, Table};
use postgres::{Client, Error};
use std::sync::{Arc, Mutex};
@ -8,7 +8,7 @@ pub struct UserRoles {
redis_connection: Arc<Mutex<RedisConnection>>,
}
impl Model for UserRoles {
impl Table for UserRoles {
fn new(
database_connection: Arc<Mutex<Client>>,
redis_connection: Arc<Mutex<RedisConnection>>,

@ -1,6 +1,9 @@
use crate::database::models::UserRecord;
use crate::database::user_roles::UserRoles;
use crate::database::{DatabaseError, DatabaseResult, Model, RedisConnection};
use crate::database::{DatabaseError, DatabaseResult, RedisConnection, Table};
use crate::utils::create_salt;
use postgres::{Client, Error};
use scrypt::ScryptParams;
use std::sync::{Arc, Mutex};
#[derive(Clone)]
@ -10,7 +13,9 @@ pub struct Users {
user_roles: UserRoles,
}
impl Model for Users {
const SALT_LENGTH: usize = 16;
impl Table for Users {
fn new(
database_connection: Arc<Mutex<Client>>,
redis_connection: Arc<Mutex<RedisConnection>>,
@ -34,10 +39,43 @@ impl Model for Users {
id SERIAL PRIMARY KEY,
name VARCHAR(255) NOT NULL,
email VARCHAR(255) UNIQUE NOT NULL,
password_hash VARCHAR(32) NOT NULL,
salt VARCHAR(16) NOT NULL
password_hash BYTEA NOT NULL,
salt BYTEA NOT NULL
);",
)
.map_err(|e| DatabaseError::Postgres(e))
}
}
impl Users {
pub fn create_user(
&self,
name: String,
email: String,
password: String,
) -> DatabaseResult<UserRecord> {
let mut connection = self.database_connection.lock().unwrap();
if !connection
.query("SELECT email FROM users WHERE email = $1", &[&email])
.map_err(|e| DatabaseError::Postgres(e))?
.is_empty()
{
return Err(DatabaseError::RecordExists);
}
let salt = create_salt(SALT_LENGTH);
let mut pw_hash = [0u8; 32];
scrypt::scrypt(
password.as_bytes(),
&salt,
&ScryptParams::recommended(),
&mut pw_hash,
)
.map_err(|_| DatabaseError::ScryptError)?;
let row = connection.query_one("
INSERT INTO users (name, email, password_hash, salt) VALUES ($1, $2, $3, $4) RETURNING *;
", &[&name, &email, &pw_hash.to_vec(), &salt.to_vec()]).map_err(|e|DatabaseError::Postgres(e))?;
Ok(UserRecord::from_ordered_row(&row))
}
}

@ -1,2 +1,3 @@
pub mod database;
pub mod server;
pub mod database;
pub mod utils;

@ -3,4 +3,15 @@ use flotte_user_management::database::Database;
fn main() {
let database = Database::new().unwrap();
database.init().unwrap();
println!(
"{:?}",
database
.users
.create_user(
"John Doe".to_string(),
"johndoe@protonmail.com".to_string(),
"ttest".to_string()
)
.unwrap()
)
}

@ -0,0 +1,9 @@
use rand::Rng;
pub fn create_salt(length: usize) -> [u8; 16] {
let mut rng = rand::thread_rng();
let mut salt = [0u8; 16];
rng.fill(&mut salt);
salt
}
Loading…
Cancel
Save