refactor(db): moved from mariadb to postgresql
This commit is contained in:
parent
9c3a3b8e26
commit
51c8a7f7fa
2
.env
2
.env
|
@ -1 +1 @@
|
|||
DATABASE_URL="mysql://nerdcult_api:test@localhost/NC_Accounts"
|
||||
DATABASE_URL="postgres://postgres:postgres@localhost/test-db"
|
|
@ -17,7 +17,7 @@ env_logger = "0.10"
|
|||
log = "0.4"
|
||||
clap = { version = "4.3.21", features = ["derive"] }
|
||||
actix-web-httpauth = "0.8.0"
|
||||
sqlx = { version = "0.7.1", features = ["runtime-tokio", "mysql", "chrono"] }
|
||||
sqlx = { version = "0.7.1", features = ["runtime-tokio", "postgres", "chrono"] }
|
||||
uuid = { version = "1.4.1", features = ["v4"] }
|
||||
chrono = "0.4"
|
||||
mail-send = "0.4.0"
|
||||
|
|
|
@ -3,11 +3,11 @@ use pbkdf2::{
|
|||
password_hash::{rand_core::OsRng, PasswordHash, PasswordHasher, PasswordVerifier, SaltString},
|
||||
Pbkdf2,
|
||||
};
|
||||
use sqlx::{mysql::MySqlPool, types::chrono as sqlx_chrono};
|
||||
use sqlx::{postgres::PgPool, types::chrono as sqlx_chrono};
|
||||
|
||||
#[derive(Debug)]
|
||||
pub struct Account {
|
||||
pub id: u64,
|
||||
pub id: i64,
|
||||
pub username: String,
|
||||
pub email: String,
|
||||
pub salt: String,
|
||||
|
@ -19,7 +19,7 @@ pub struct Account {
|
|||
impl Account {
|
||||
/// This doesn't check if an account with that name is already existing!
|
||||
pub async fn new(
|
||||
pool: &MySqlPool,
|
||||
pool: &PgPool,
|
||||
username: &String,
|
||||
email: &String,
|
||||
password: &String,
|
||||
|
@ -33,7 +33,7 @@ impl Account {
|
|||
let joined = sqlx_chrono::Utc::now().naive_utc();
|
||||
|
||||
sqlx::query!(
|
||||
r#"INSERT INTO Accounts (username, email, salt, password, joined, verified) VALUES (?, ?, ?, ?, ?, false);"#,
|
||||
r#"INSERT INTO Accounts (username, email, salt, password, joined, verified) VALUES ($1, $2, $3, $4, $5, false);"#,
|
||||
username,
|
||||
email,
|
||||
salt.to_string(),
|
||||
|
@ -51,10 +51,10 @@ impl Account {
|
|||
}
|
||||
}
|
||||
|
||||
pub async fn from_username(pool: &MySqlPool, username: &String) -> Result<Option<Self>> {
|
||||
pub async fn from_username(pool: &PgPool, username: &String) -> Result<Option<Self>> {
|
||||
match sqlx::query_as!(
|
||||
Self,
|
||||
r#"SELECT id, username, email, salt, password, joined, verified as `verified: bool` FROM Accounts WHERE username = ?;"#,
|
||||
r#"SELECT id, username, email, salt, password, joined, verified as "verified!: bool" FROM Accounts WHERE username = $1;"#,
|
||||
username
|
||||
)
|
||||
.fetch_one(pool)
|
||||
|
@ -66,10 +66,10 @@ impl Account {
|
|||
}
|
||||
}
|
||||
|
||||
pub async fn from_id(pool: &MySqlPool, id: u64) -> Result<Option<Self>> {
|
||||
pub async fn from_id(pool: &PgPool, id: i64) -> Result<Option<Self>> {
|
||||
match sqlx::query_as!(
|
||||
Self,
|
||||
r#"SELECT id, username, email, salt, password, joined, verified as `verified: bool` FROM Accounts WHERE id = ?;"#,
|
||||
r#"SELECT id, username, email, salt, password, joined, verified as "verified!: bool" FROM Accounts WHERE id = $1;"#,
|
||||
id
|
||||
)
|
||||
.fetch_one(pool)
|
||||
|
@ -81,10 +81,10 @@ impl Account {
|
|||
}
|
||||
}
|
||||
|
||||
pub async fn from_email(pool: &MySqlPool, email: &String) -> Result<Option<Self>> {
|
||||
pub async fn from_email(pool: &PgPool, email: &String) -> Result<Option<Self>> {
|
||||
match sqlx::query_as!(
|
||||
Self,
|
||||
r#"SELECT id, username, email, salt, password, joined, verified as `verified: bool` FROM Accounts WHERE email = ?;"#,
|
||||
r#"SELECT id, username, email, salt, password, joined, verified as "verified!: bool" FROM Accounts WHERE email = $1;"#,
|
||||
email
|
||||
)
|
||||
.fetch_one(pool)
|
||||
|
|
|
@ -6,7 +6,7 @@ use crate::{
|
|||
use anyhow::Result;
|
||||
use log::info;
|
||||
use mail_send::{mail_builder::MessageBuilder, SmtpClientBuilder};
|
||||
use sqlx::MySqlPool;
|
||||
use sqlx::PgPool;
|
||||
|
||||
fn is_sql_injection(string: &String) -> bool {
|
||||
match libinjection::sqli(string) {
|
||||
|
@ -26,7 +26,7 @@ impl AlphaExt for String {
|
|||
}
|
||||
|
||||
pub async fn register(
|
||||
pool: &MySqlPool,
|
||||
pool: &PgPool,
|
||||
request: data::RegisterRequest,
|
||||
) -> Result<data::RegisterResponse> {
|
||||
if is_sql_injection(&request.username) || is_sql_injection(&request.email) {
|
||||
|
@ -84,10 +84,7 @@ pub async fn register(
|
|||
Ok(data::RegisterResponse::Success)
|
||||
}
|
||||
|
||||
pub async fn verify(
|
||||
pool: &MySqlPool,
|
||||
request: data::VerifyRequest,
|
||||
) -> Result<data::VerifyResponse> {
|
||||
pub async fn verify(pool: &PgPool, request: data::VerifyRequest) -> Result<data::VerifyResponse> {
|
||||
if !request.token.is_alpha() {
|
||||
return Ok(data::VerifyResponse::Blocked);
|
||||
}
|
||||
|
@ -103,7 +100,7 @@ pub async fn verify(
|
|||
}
|
||||
|
||||
pub async fn authenticate(
|
||||
pool: &MySqlPool,
|
||||
pool: &PgPool,
|
||||
request: data::AuthenticateRequest,
|
||||
) -> Result<data::AuthenticateResponse> {
|
||||
if is_sql_injection(&request.username) {
|
||||
|
@ -130,7 +127,7 @@ pub async fn authenticate(
|
|||
))
|
||||
}
|
||||
|
||||
pub async fn delete(pool: &MySqlPool, auth: String) -> Result<data::DeleteResponse> {
|
||||
pub async fn delete(pool: &PgPool, auth: String) -> Result<data::DeleteResponse> {
|
||||
if !auth.is_alpha() {
|
||||
return Ok(data::DeleteResponse::Blocked);
|
||||
}
|
||||
|
@ -141,13 +138,13 @@ pub async fn delete(pool: &MySqlPool, auth: String) -> Result<data::DeleteRespon
|
|||
};
|
||||
|
||||
sqlx::query!(
|
||||
r#"DELETE FROM AuthTokens WHERE account = ?;"#,
|
||||
r#"DELETE FROM AuthTokens WHERE account = $1;"#,
|
||||
token.account
|
||||
)
|
||||
.execute(pool)
|
||||
.await?;
|
||||
|
||||
sqlx::query!(r#"DELETE FROM Accounts WHERE id = ?;"#, token.account)
|
||||
sqlx::query!(r#"DELETE FROM Accounts WHERE id = $1;"#, token.account)
|
||||
.execute(pool)
|
||||
.await?;
|
||||
|
||||
|
@ -155,7 +152,7 @@ pub async fn delete(pool: &MySqlPool, auth: String) -> Result<data::DeleteRespon
|
|||
}
|
||||
|
||||
pub async fn token_delete(
|
||||
pool: &MySqlPool,
|
||||
pool: &PgPool,
|
||||
auth: String,
|
||||
request: data::TokenDeleteRequest,
|
||||
) -> Result<data::TokenDeleteResponse> {
|
||||
|
@ -184,7 +181,7 @@ pub async fn token_delete(
|
|||
Ok(data::TokenDeleteResponse::Success)
|
||||
}
|
||||
|
||||
pub async fn token_list(pool: &MySqlPool, auth: String) -> Result<data::TokenListResponse> {
|
||||
pub async fn token_list(pool: &PgPool, auth: String) -> Result<data::TokenListResponse> {
|
||||
if !auth.is_alpha() {
|
||||
return Ok(data::TokenListResponse::Blocked);
|
||||
}
|
||||
|
@ -196,7 +193,7 @@ pub async fn token_list(pool: &MySqlPool, auth: String) -> Result<data::TokenLis
|
|||
|
||||
let list: Vec<(String, i64)> = sqlx::query_as!(
|
||||
AuthToken,
|
||||
r#"SELECT * FROM AuthTokens WHERE account = ?;"#,
|
||||
r#"SELECT * FROM AuthTokens WHERE account = $1;"#,
|
||||
token.account
|
||||
)
|
||||
.fetch_all(pool)
|
||||
|
@ -205,5 +202,7 @@ pub async fn token_list(pool: &MySqlPool, auth: String) -> Result<data::TokenLis
|
|||
.map(|t| (t.token.clone(), t.expire.timestamp()))
|
||||
.collect();
|
||||
|
||||
Ok(data::TokenListResponse::Success(data::TokenListSuccess {tokens: list}))
|
||||
Ok(data::TokenListResponse::Success(data::TokenListSuccess {
|
||||
tokens: list,
|
||||
}))
|
||||
}
|
||||
|
|
|
@ -3,24 +3,24 @@ mod account;
|
|||
use actix_web::{web, App, HttpServer};
|
||||
use anyhow::Result;
|
||||
use log::info;
|
||||
use sqlx::mysql::MySqlPool;
|
||||
use sqlx::postgres::PgPool;
|
||||
|
||||
struct ApiState {
|
||||
pool: MySqlPool,
|
||||
pool: PgPool,
|
||||
}
|
||||
|
||||
pub async fn start(port: u16, pool: MySqlPool) -> Result<()> {
|
||||
pub async fn start(port: u16, pool: PgPool) -> Result<()> {
|
||||
info!("HTTP server starting on port {} ...", port);
|
||||
|
||||
sqlx::query!(
|
||||
r#"
|
||||
CREATE TABLE IF NOT EXISTS Accounts (
|
||||
id INT8 UNSIGNED NOT NULL AUTO_INCREMENT UNIQUE,
|
||||
id SERIAL8 NOT NULL,
|
||||
username VARCHAR(32) NOT NULL,
|
||||
email TEXT NOT NULL,
|
||||
salt VARCHAR(22) NOT NULL,
|
||||
password VARCHAR(96) NOT NULL,
|
||||
joined DATETIME NOT NULL,
|
||||
joined TIMESTAMP NOT NULL,
|
||||
verified BOOLEAN NOT NULL,
|
||||
PRIMARY KEY(id)
|
||||
);
|
||||
|
@ -33,8 +33,8 @@ pub async fn start(port: u16, pool: MySqlPool) -> Result<()> {
|
|||
r#"
|
||||
CREATE TABLE IF NOT EXISTS AuthTokens (
|
||||
token VARCHAR(32) NOT NULL,
|
||||
account INT8 UNSIGNED NOT NULL,
|
||||
expire DATETIME NOT NULL
|
||||
account SERIAL8 NOT NULL,
|
||||
expire TIMESTAMP NOT NULL
|
||||
);
|
||||
"#
|
||||
)
|
||||
|
@ -45,8 +45,8 @@ pub async fn start(port: u16, pool: MySqlPool) -> Result<()> {
|
|||
r#"
|
||||
CREATE TABLE IF NOT EXISTS VerificationTokens (
|
||||
token VARCHAR(32) NOT NULL,
|
||||
account INT8 UNSIGNED NOT NULL,
|
||||
expire DATETIME NOT NULL
|
||||
account SERIAL8 NOT NULL,
|
||||
expire TIMESTAMP NOT NULL
|
||||
);
|
||||
"#
|
||||
)
|
||||
|
|
|
@ -5,7 +5,7 @@ mod tokens;
|
|||
use anyhow::Result;
|
||||
use clap::Parser;
|
||||
use log::info;
|
||||
use sqlx::mysql::MySqlPool;
|
||||
use sqlx::postgres::PgPool;
|
||||
|
||||
#[derive(Parser, Debug)]
|
||||
#[command(author, version, about, long_about = None)]
|
||||
|
@ -28,7 +28,7 @@ async fn main() -> Result<()> {
|
|||
port = p;
|
||||
}
|
||||
|
||||
let pool = MySqlPool::connect(&std::env::var("DATABASE_URL").map_err(|_| {
|
||||
let pool = PgPool::connect(&std::env::var("DATABASE_URL").map_err(|_| {
|
||||
anyhow::Error::msg("Environment variable DATABASE_URL needs to be specified!")
|
||||
})?)
|
||||
.await?;
|
||||
|
|
|
@ -1,17 +1,17 @@
|
|||
use anyhow::{Error, Result};
|
||||
use sqlx::{mysql::MySqlPool, types::chrono as sqlx_chrono};
|
||||
use sqlx::{postgres::PgPool, types::chrono as sqlx_chrono};
|
||||
|
||||
#[derive(Debug)]
|
||||
pub struct AuthToken {
|
||||
pub token: String,
|
||||
pub account: u64,
|
||||
pub account: i64,
|
||||
pub expire: sqlx_chrono::NaiveDateTime,
|
||||
}
|
||||
|
||||
impl AuthToken {
|
||||
pub async fn new(
|
||||
pool: &MySqlPool,
|
||||
account_id: u64,
|
||||
pool: &PgPool,
|
||||
account_id: i64,
|
||||
lifetime: chrono::Duration,
|
||||
) -> Result<Self> {
|
||||
let expire = match sqlx_chrono::Utc::now()
|
||||
|
@ -28,7 +28,7 @@ impl AuthToken {
|
|||
|
||||
let mut token = Self {
|
||||
token: uuid::Uuid::new_v4().simple().to_string(),
|
||||
account: account_id as u64,
|
||||
account: account_id,
|
||||
expire,
|
||||
};
|
||||
|
||||
|
@ -38,7 +38,7 @@ impl AuthToken {
|
|||
|
||||
sqlx::query!(
|
||||
r#"
|
||||
INSERT INTO AuthTokens (token, account, expire) VALUES (?, ?, ?);
|
||||
INSERT INTO AuthTokens (token, account, expire) VALUES ($1, $2, $3);
|
||||
"#,
|
||||
token.token,
|
||||
token.account,
|
||||
|
@ -50,10 +50,10 @@ impl AuthToken {
|
|||
Ok(token)
|
||||
}
|
||||
|
||||
pub async fn check(pool: &MySqlPool, alphanumeric_token: &String) -> Result<Option<Self>> {
|
||||
pub async fn check(pool: &PgPool, alphanumeric_token: &String) -> Result<Option<Self>> {
|
||||
let query_result = sqlx::query_as!(
|
||||
Self,
|
||||
r#"SELECT * FROM AuthTokens WHERE token = ?;"#,
|
||||
r#"SELECT * FROM AuthTokens WHERE token = $1;"#,
|
||||
alphanumeric_token
|
||||
)
|
||||
.fetch_one(pool)
|
||||
|
@ -73,8 +73,8 @@ impl AuthToken {
|
|||
}
|
||||
}
|
||||
|
||||
pub async fn delete(&self, pool: &MySqlPool) -> Result<()> {
|
||||
sqlx::query!(r#"DELETE FROM AuthTokens WHERE token = ?;"#, self.token)
|
||||
pub async fn delete(&self, pool: &PgPool) -> Result<()> {
|
||||
sqlx::query!(r#"DELETE FROM AuthTokens WHERE token = $1;"#, self.token)
|
||||
.execute(pool)
|
||||
.await?;
|
||||
Ok(())
|
||||
|
@ -84,14 +84,14 @@ impl AuthToken {
|
|||
#[derive(Debug)]
|
||||
pub struct VerificationToken {
|
||||
pub token: String,
|
||||
pub account: u64,
|
||||
pub account: i64,
|
||||
pub expire: sqlx_chrono::NaiveDateTime,
|
||||
}
|
||||
|
||||
impl VerificationToken {
|
||||
pub async fn new(
|
||||
pool: &MySqlPool,
|
||||
account_id: u64,
|
||||
pool: &PgPool,
|
||||
account_id: i64,
|
||||
lifetime: chrono::Duration,
|
||||
) -> Result<Self> {
|
||||
let expire = match sqlx_chrono::Utc::now()
|
||||
|
@ -108,7 +108,7 @@ impl VerificationToken {
|
|||
|
||||
let mut token = Self {
|
||||
token: uuid::Uuid::new_v4().simple().to_string(),
|
||||
account: account_id as u64,
|
||||
account: account_id,
|
||||
expire,
|
||||
};
|
||||
|
||||
|
@ -121,7 +121,7 @@ impl VerificationToken {
|
|||
|
||||
sqlx::query!(
|
||||
r#"
|
||||
INSERT INTO VerificationTokens (token, account, expire) VALUES (?, ?, ?);
|
||||
INSERT INTO VerificationTokens (token, account, expire) VALUES ($1, $2, $3);
|
||||
"#,
|
||||
token.token,
|
||||
token.account,
|
||||
|
@ -133,10 +133,10 @@ impl VerificationToken {
|
|||
Ok(token)
|
||||
}
|
||||
|
||||
pub async fn check(pool: &MySqlPool, alphanumeric_token: &String) -> Result<Option<Self>> {
|
||||
pub async fn check(pool: &PgPool, alphanumeric_token: &String) -> Result<Option<Self>> {
|
||||
let query_result = sqlx::query_as!(
|
||||
Self,
|
||||
r#"SELECT * FROM VerificationTokens WHERE token = ?;"#,
|
||||
r#"SELECT * FROM VerificationTokens WHERE token = $1;"#,
|
||||
alphanumeric_token
|
||||
)
|
||||
.fetch_one(pool)
|
||||
|
@ -156,9 +156,9 @@ impl VerificationToken {
|
|||
}
|
||||
}
|
||||
|
||||
pub async fn delete(&self, pool: &MySqlPool) -> Result<()> {
|
||||
pub async fn delete(&self, pool: &PgPool) -> Result<()> {
|
||||
sqlx::query!(
|
||||
r#"DELETE FROM VerificationTokens WHERE token = ?;"#,
|
||||
r#"DELETE FROM VerificationTokens WHERE token = $1;"#,
|
||||
self.token
|
||||
)
|
||||
.execute(pool)
|
||||
|
@ -166,11 +166,11 @@ impl VerificationToken {
|
|||
Ok(())
|
||||
}
|
||||
|
||||
pub async fn apply(&self, pool: &MySqlPool) -> Result<()> {
|
||||
pub async fn apply(&self, pool: &PgPool) -> Result<()> {
|
||||
self.delete(pool).await?;
|
||||
|
||||
sqlx::query!(
|
||||
r#"UPDATE Accounts SET verified=true WHERE id = ?;"#,
|
||||
r#"UPDATE Accounts SET verified=true WHERE id = $1;"#,
|
||||
self.account
|
||||
)
|
||||
.execute(pool)
|
||||
|
|
Loading…
Reference in New Issue