Working example

This commit is contained in:
Imbus 2023-10-10 17:12:47 +02:00
parent 83345afe04
commit f514fd741c
10 changed files with 446 additions and 81 deletions

228
server/Cargo.lock generated
View file

@ -30,7 +30,7 @@ dependencies = [
"actix-service",
"actix-utils",
"ahash",
"base64",
"base64 0.21.4",
"bitflags 2.4.0",
"brotli",
"bytes",
@ -238,6 +238,21 @@ version = "0.2.16"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "0942ffc6dcaadf03badf6e6a2d0228460359d5e34b57ccdc720b7382dfbd5ec5"
[[package]]
name = "android-tzdata"
version = "0.1.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "e999941b234f3131b00bc13c22d06e8c5ff726d1b6318ac7eb276997bbb4fef0"
[[package]]
name = "android_system_properties"
version = "0.1.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "819e7219dbd41043ac279b19830f2efc897156490d7fd6ea916720117ee66311"
dependencies = [
"libc",
]
[[package]]
name = "anstream"
version = "0.5.0"
@ -329,6 +344,12 @@ dependencies = [
"rustc-demangle",
]
[[package]]
name = "base64"
version = "0.13.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "9e1b586273c5702936fe7b7d6896644d8be71e6314cfe09d3167c95f712589e8"
[[package]]
name = "base64"
version = "0.21.4"
@ -395,6 +416,12 @@ dependencies = [
"alloc-stdlib",
]
[[package]]
name = "bumpalo"
version = "3.14.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "7f30e7476521f6f8af1a1c4c0b8cc94f0bee37d91763d0ca2665f299b6cd8aec"
[[package]]
name = "byteorder"
version = "1.4.3"
@ -432,6 +459,21 @@ version = "1.0.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd"
[[package]]
name = "chrono"
version = "0.4.31"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "7f2c685bad3eb3d45a01354cedb7d5faa66194d1d58ba6e267a8de788f79db38"
dependencies = [
"android-tzdata",
"iana-time-zone",
"js-sys",
"num-traits",
"serde",
"wasm-bindgen",
"windows-targets",
]
[[package]]
name = "clap"
version = "4.4.5"
@ -501,6 +543,12 @@ dependencies = [
"version_check",
]
[[package]]
name = "core-foundation-sys"
version = "0.8.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "e496a50fda8aacccc86d7529e2c1e0892dbd0f898a6b5645b5561b89c3210efa"
[[package]]
name = "cpufeatures"
version = "0.2.9"
@ -986,6 +1034,29 @@ version = "2.1.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "9a3a5bfb195931eeb336b2a7b4d761daec841b97f947d34394601737a7bba5e4"
[[package]]
name = "iana-time-zone"
version = "0.1.57"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "2fad5b825842d2b38bd206f3e81d6957625fd7f0a361e345c30e01a0ae2dd613"
dependencies = [
"android_system_properties",
"core-foundation-sys",
"iana-time-zone-haiku",
"js-sys",
"wasm-bindgen",
"windows",
]
[[package]]
name = "iana-time-zone-haiku"
version = "0.1.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "f31827a206f56af32e590ba56d5d2d085f558508192593743f16b2306495269f"
dependencies = [
"cc",
]
[[package]]
name = "idna"
version = "0.4.0"
@ -1060,6 +1131,29 @@ dependencies = [
"libc",
]
[[package]]
name = "js-sys"
version = "0.3.64"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "c5f195fe497f702db0f318b07fdd68edb16955aed830df8363d837542f8f935a"
dependencies = [
"wasm-bindgen",
]
[[package]]
name = "jsonwebtoken"
version = "8.3.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "6971da4d9c3aa03c3d8f3ff0f4155b534aad021292003895a469716b2a230378"
dependencies = [
"base64 0.21.4",
"pem",
"ring",
"serde",
"serde_json",
"simple_asn1",
]
[[package]]
name = "language-tags"
version = "0.3.2"
@ -1205,6 +1299,17 @@ dependencies = [
"minimal-lexical",
]
[[package]]
name = "num-bigint"
version = "0.4.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "608e7659b5c3d7cba262d894801b9ec9d00de989e8a82bd4bef91d08da45cdc0"
dependencies = [
"autocfg",
"num-integer",
"num-traits",
]
[[package]]
name = "num-bigint-dig"
version = "0.8.4"
@ -1333,6 +1438,15 @@ version = "1.0.14"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "de3145af08024dea9fa9914f381a17b8fc6034dfb00f3a84013f7ff43f29ed4c"
[[package]]
name = "pem"
version = "1.1.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "a8835c273a76a90455d7344889b0964598e3316e2a79ede8e36f16bdcf2228b8"
dependencies = [
"base64 0.13.1",
]
[[package]]
name = "pem-rfc7468"
version = "0.7.0"
@ -1488,6 +1602,21 @@ version = "0.7.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "dbb5fb1acd8a1a18b3dd5be62d25485eb770e05afb408a9627d14d451bae12da"
[[package]]
name = "ring"
version = "0.16.20"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "3053cf52e236a3ed746dfc745aa9cacf1b791d846bdaf412f60a8d7d6e17c8fc"
dependencies = [
"cc",
"libc",
"once_cell",
"spin 0.5.2",
"untrusted",
"web-sys",
"winapi",
]
[[package]]
name = "rsa"
version = "0.9.2"
@ -1605,8 +1734,10 @@ version = "0.1.0"
dependencies = [
"actix-web",
"argon2",
"chrono",
"clap",
"env_logger",
"jsonwebtoken",
"log",
"serde",
"serde_json",
@ -1656,6 +1787,18 @@ dependencies = [
"rand_core",
]
[[package]]
name = "simple_asn1"
version = "0.6.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "adc4e5204eb1910f40f9cfa375f6f05b68c3abac4b6fd879c8ff5e7ae8a0a085"
dependencies = [
"num-bigint",
"num-traits",
"thiserror",
"time",
]
[[package]]
name = "slab"
version = "0.4.9"
@ -1831,7 +1974,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "864b869fdf56263f4c95c45483191ea0af340f9f3e3e7b4d57a61c7c87a970db"
dependencies = [
"atoi",
"base64",
"base64 0.21.4",
"bitflags 2.4.0",
"byteorder",
"bytes",
@ -1873,7 +2016,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "eb7ae0e6a97fb3ba33b23ac2671a5ce6e3cabe003f451abd5a56e7951d975624"
dependencies = [
"atoi",
"base64",
"base64 0.21.4",
"bitflags 2.4.0",
"byteorder",
"crc",
@ -2171,6 +2314,12 @@ version = "0.1.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "39ec24b3121d976906ece63c9daad25b85969647682eee313cb5779fdd69e14e"
[[package]]
name = "untrusted"
version = "0.7.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "a156c684c91ea7d62626509bce3cb4e1d9ed5c4d978f7b4352658f96a4c26b4a"
[[package]]
name = "url"
version = "2.4.1"
@ -2216,6 +2365,70 @@ version = "0.11.0+wasi-snapshot-preview1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "9c8d87e72b64a3b4db28d11ce29237c246188f4f51057d65a7eab63b7987e423"
[[package]]
name = "wasm-bindgen"
version = "0.2.87"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "7706a72ab36d8cb1f80ffbf0e071533974a60d0a308d01a5d0375bf60499a342"
dependencies = [
"cfg-if",
"wasm-bindgen-macro",
]
[[package]]
name = "wasm-bindgen-backend"
version = "0.2.87"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "5ef2b6d3c510e9625e5fe6f509ab07d66a760f0885d858736483c32ed7809abd"
dependencies = [
"bumpalo",
"log",
"once_cell",
"proc-macro2",
"quote",
"syn 2.0.37",
"wasm-bindgen-shared",
]
[[package]]
name = "wasm-bindgen-macro"
version = "0.2.87"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "dee495e55982a3bd48105a7b947fd2a9b4a8ae3010041b9e0faab3f9cd028f1d"
dependencies = [
"quote",
"wasm-bindgen-macro-support",
]
[[package]]
name = "wasm-bindgen-macro-support"
version = "0.2.87"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "54681b18a46765f095758388f2d0cf16eb8d4169b639ab575a8f5693af210c7b"
dependencies = [
"proc-macro2",
"quote",
"syn 2.0.37",
"wasm-bindgen-backend",
"wasm-bindgen-shared",
]
[[package]]
name = "wasm-bindgen-shared"
version = "0.2.87"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "ca6ad05a4870b2bf5fe995117d3728437bd27d7cd5f06f13c17443ef369775a1"
[[package]]
name = "web-sys"
version = "0.3.64"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "9b85cbef8c220a6abc02aefd892dfc0fc23afb1c6a426316ec33253a3877249b"
dependencies = [
"js-sys",
"wasm-bindgen",
]
[[package]]
name = "whoami"
version = "1.4.1"
@ -2253,6 +2466,15 @@ version = "0.4.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f"
[[package]]
name = "windows"
version = "0.48.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "e686886bc078bc1b0b600cac0147aadb815089b6e4da64016cbd754b6342700f"
dependencies = [
"windows-targets",
]
[[package]]
name = "windows-sys"
version = "0.48.0"

View file

@ -8,8 +8,10 @@ edition = "2021"
[dependencies]
actix-web = "4.4.0"
argon2 = { version = "0.5.2", features = ["zeroize"] }
chrono = { version = "0.4.31", features = ["serde"] }
clap = { version = "4.4.5", features = ["derive"] }
env_logger = "0.10.0"
jsonwebtoken = "8.3.0"
log = "0.4.20"
serde = { version = "1.0.188", features = ["derive"] }
serde_json = "1.0.107"

60
server/src/jwt.rs Executable file
View file

@ -0,0 +1,60 @@
// use crate::{
// config::{DAYS_VALID, JWT_SECRET},
// Claims,
// };
use jsonwebtoken::{
decode, encode, errors::Result as JwtResult, DecodingKey, EncodingKey, Header, Validation,
};
use log::*;
use serde::{Deserialize, Serialize};
const DAYS_VALID: i64 = 7;
const JWT_SECRET: &[u8] = "secret".as_bytes();
#[derive(Debug, Serialize, Deserialize)]
pub struct Claims {
pub sub: String,
pub iss: String,
pub aud: String,
pub iat: usize,
pub exp: usize,
}
// JwtResult is just a predefined error from the jsonwebtoken crate
pub fn token_factory(user: &str) -> JwtResult<String> {
info!("Issuing JWT token for {}", user);
let token = encode(
&Header::default(),
&Claims {
sub: user.to_string(),
iss: "localhost".to_string(),
aud: "localhost".to_string(),
iat: chrono::Utc::now().timestamp() as usize,
exp: (chrono::Utc::now() + chrono::Duration::days(DAYS_VALID)).timestamp() as usize,
},
&EncodingKey::from_secret(JWT_SECRET),
)
.unwrap();
Ok(token)
}
pub fn validate_token(token: &str) -> JwtResult<Claims> {
let token_data = decode::<Claims>(
token,
&DecodingKey::from_secret(JWT_SECRET),
&Validation::default(),
);
match token_data {
Ok(token_data) => {
info!("Token validated for {}", token_data.claims.sub);
Ok(token_data.claims)
}
Err(e) => {
error!("Token validation failed: {}", e);
Err(e)
}
}
}

View file

@ -4,11 +4,12 @@ use actix_web::{web::scope, App, HttpServer};
use log::info;
// use uuid::Uuid;
mod jwt;
mod routes;
mod state;
mod types;
use routes::{get_posts, new_post, register, test};
use routes::{get_posts, login, new_post, register, test};
use sqlx::ConnectOptions;
use state::AppState;
@ -33,6 +34,7 @@ async fn main() -> std::io::Result<()> {
.service(new_post)
.service(routes::vote)
.service(test)
.service(login)
.service(register)
.app_data(Data::new(data.clone())),
)

View file

@ -1,7 +1,7 @@
use crate::types::{NewPost, Post};
use crate::AppState;
use actix_web::web::{Data, Path};
use actix_web::web::{to, Data, Path};
use actix_web::{get, post, web::Json, HttpResponse, Responder, Result};
use argon2::password_hash::SaltString;
use log::*;
@ -137,3 +137,55 @@ pub async fn register(data: Json<RegisterData>, state: Data<AppState>) -> Result
Ok(HttpResponse::Ok().json("User registered"))
}
#[derive(Debug, Serialize, Deserialize)]
pub struct LoginData {
username: String,
password: String,
}
use sqlx::Row;
#[derive(Debug, Serialize, Deserialize)]
struct LoginResponse {
username: String,
token: String,
}
use crate::jwt::token_factory;
#[post("/login")]
pub async fn login(data: Json<LoginData>, state: Data<AppState>) -> Result<impl Responder> {
let q = "SELECT password FROM users WHERE username = ?";
let query = sqlx::query(q).bind(&data.username);
let result = query.fetch_one(&state.pool).await.ok();
if let Some(row) = result {
let phc_from_db = row.get::<String, _>("password");
let pwhash = PasswordHash::new(&phc_from_db).unwrap_or_else(|_| {
warn!(
"Invalid hash for user {} fetched from database (not a valid PHC string)",
data.username
);
panic!();
});
match Argon2::default().verify_password(data.password.as_bytes(), &pwhash) {
Ok(some) => {
info!("User {} logged in", data.username);
let token = token_factory(&data.username).unwrap();
println!("{:?}", token);
return Ok(HttpResponse::Ok().json(LoginResponse {
username: data.username.clone(),
token: token,
}));
// Sign jwt with user claims
}
Err(e) => {
info!("User \"{}\" failed to log in", data.username);
return Ok(HttpResponse::BadRequest().json("Error"));
}
}
}
Ok(HttpResponse::Ok().json("What happens here???"))
}