summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--.sqlx/query-e3f7e6a9b6f2413adf4467e112b7aa0170d9d3ad0aa78ddc0580e9d0f23c0f7f.json22
-rw-r--r--Cargo.lock131
-rw-r--r--Cargo.toml1
-rw-r--r--TODO.md2
-rw-r--r--src/main.rs96
5 files changed, 247 insertions, 5 deletions
diff --git a/.sqlx/query-e3f7e6a9b6f2413adf4467e112b7aa0170d9d3ad0aa78ddc0580e9d0f23c0f7f.json b/.sqlx/query-e3f7e6a9b6f2413adf4467e112b7aa0170d9d3ad0aa78ddc0580e9d0f23c0f7f.json
new file mode 100644
index 0000000..77c11b6
--- /dev/null
+++ b/.sqlx/query-e3f7e6a9b6f2413adf4467e112b7aa0170d9d3ad0aa78ddc0580e9d0f23c0f7f.json
@@ -0,0 +1,22 @@
+{
+ "db_name": "PostgreSQL",
+ "query": "select password from users where username = $1",
+ "describe": {
+ "columns": [
+ {
+ "ordinal": 0,
+ "name": "password",
+ "type_info": "Varchar"
+ }
+ ],
+ "parameters": {
+ "Left": [
+ "Text"
+ ]
+ },
+ "nullable": [
+ false
+ ]
+ },
+ "hash": "e3f7e6a9b6f2413adf4467e112b7aa0170d9d3ad0aa78ddc0580e9d0f23c0f7f"
+}
diff --git a/Cargo.lock b/Cargo.lock
index 927a477..58f278c 100644
--- a/Cargo.lock
+++ b/Cargo.lock
@@ -120,6 +120,23 @@ dependencies = [
]
[[package]]
+name = "actix-session"
+version = "0.8.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "2e6a28f813a6671e1847d005cad0be36ae4d016287690f765c303379837c13d6"
+dependencies = [
+ "actix-service",
+ "actix-utils",
+ "actix-web",
+ "anyhow",
+ "async-trait",
+ "derive_more",
+ "serde",
+ "serde_json",
+ "tracing",
+]
+
+[[package]]
name = "actix-utils"
version = "3.0.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
@@ -197,6 +214,41 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "f26201604c87b1e01bd3d98f8d5d9a8fcbb815e8cedb41ffccbeb4bf593a35fe"
[[package]]
+name = "aead"
+version = "0.5.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "d122413f284cf2d62fb1b7db97e02edb8cda96d769b16e443a4f6195e35662b0"
+dependencies = [
+ "crypto-common",
+ "generic-array",
+]
+
+[[package]]
+name = "aes"
+version = "0.8.3"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "ac1f845298e95f983ff1944b728ae08b8cebab80d684f0a832ed0fc74dfa27e2"
+dependencies = [
+ "cfg-if",
+ "cipher",
+ "cpufeatures",
+]
+
+[[package]]
+name = "aes-gcm"
+version = "0.10.3"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "831010a0f742e1209b3bcea8fab6a8e149051ba6099432c8cb2cc117dec3ead1"
+dependencies = [
+ "aead",
+ "aes",
+ "cipher",
+ "ctr",
+ "ghash",
+ "subtle",
+]
+
+[[package]]
name = "ahash"
version = "0.8.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
@@ -239,12 +291,29 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "0942ffc6dcaadf03badf6e6a2d0228460359d5e34b57ccdc720b7382dfbd5ec5"
[[package]]
+name = "anyhow"
+version = "1.0.75"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "a4668cab20f66d8d020e1fbc0ebe47217433c1b6c8f2040faf858554e394ace6"
+
+[[package]]
name = "arc-swap"
version = "1.6.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "bddcadddf5e9015d310179a59bb28c4d4b9920ad0f11e8e14dbadf654890c9a6"
[[package]]
+name = "async-trait"
+version = "0.1.74"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "a66537f1bb974b254c98ed142ff995236e81b9d0fe4db0575f46612cb15eb0f9"
+dependencies = [
+ "proc-macro2",
+ "quote",
+ "syn 2.0.37",
+]
+
+[[package]]
name = "atoi"
version = "2.0.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
@@ -282,6 +351,12 @@ checksum = "9e1b586273c5702936fe7b7d6896644d8be71e6314cfe09d3167c95f712589e8"
[[package]]
name = "base64"
+version = "0.20.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "0ea22880d78093b0cbe17c89f64a7d457941e65759157ec6cb31a31d652b05e5"
+
+[[package]]
+name = "base64"
version = "0.21.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "9ba43ea6f343b788c8764558649e08df62f86c6ef251fdaeb1ffd010a9ae50a2"
@@ -437,7 +512,14 @@ version = "0.16.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "e859cd57d0710d9e06c381b550c06e76992472a8c6d527aecd2fc673dcc231fb"
dependencies = [
+ "aes-gcm",
+ "base64 0.20.0",
+ "hkdf",
+ "hmac",
"percent-encoding",
+ "rand 0.8.5",
+ "sha2",
+ "subtle",
"time",
"version_check",
]
@@ -517,6 +599,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "1bfb12502f3fc46cca1bb51ac28df9d618d813cdc3d2f25b9fe775a34af26bb3"
dependencies = [
"generic-array",
+ "rand_core 0.6.4",
"typenum",
]
@@ -548,6 +631,15 @@ dependencies = [
]
[[package]]
+name = "ctr"
+version = "0.9.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "0369ee1ad671834580515889b80f2ea915f23b8be8d0daa4bbaf2ac5c7590835"
+dependencies = [
+ "cipher",
+]
+
+[[package]]
name = "der"
version = "0.7.8"
source = "registry+https://github.com/rust-lang/crates.io-index"
@@ -859,6 +951,16 @@ dependencies = [
]
[[package]]
+name = "ghash"
+version = "0.5.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "d930750de5717d2dd0b8c0d42c076c0e884c81a73e6cab859bbd2339c71e3e40"
+dependencies = [
+ "opaque-debug",
+ "polyval",
+]
+
+[[package]]
name = "gimli"
version = "0.28.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
@@ -1432,6 +1534,12 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "dd8b5dd2ae5ed71462c540258bedcb51965123ad7e7ccf4b9a8cafaa4a63576d"
[[package]]
+name = "opaque-debug"
+version = "0.3.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "624a8340c38c1b80fd549087862da4ba43e08858af025b236e509b6649fc13d5"
+
+[[package]]
name = "openssl"
version = "0.10.57"
source = "registry+https://github.com/rust-lang/crates.io-index"
@@ -1608,6 +1716,7 @@ checksum = "8b870d8c151b6f2fb93e84a13146138f05d02ed11c7e7c54f8826aaaf7c9f184"
name = "pinussy"
version = "0.1.0"
dependencies = [
+ "actix-session",
"actix-web",
"bcrypt",
"mime",
@@ -1646,6 +1755,18 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "26072860ba924cbfa98ea39c8c19b4dd6a4a25423dbdf219c1eca91aa0cf6964"
[[package]]
+name = "polyval"
+version = "0.6.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "d52cff9d1d4dee5fe6d03729099f4a310a41179e0a10dbf542039873f2e826fb"
+dependencies = [
+ "cfg-if",
+ "cpufeatures",
+ "opaque-debug",
+ "universal-hash",
+]
+
+[[package]]
name = "ppv-lite86"
version = "0.2.17"
source = "registry+https://github.com/rust-lang/crates.io-index"
@@ -2679,6 +2800,16 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "39ec24b3121d976906ece63c9daad25b85969647682eee313cb5779fdd69e14e"
[[package]]
+name = "universal-hash"
+version = "0.5.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "fc1de2c688dc15305988b563c3854064043356019f97a4b46276fe734c4f07ea"
+dependencies = [
+ "crypto-common",
+ "subtle",
+]
+
+[[package]]
name = "url"
version = "2.4.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
diff --git a/Cargo.toml b/Cargo.toml
index 9b847e9..708133b 100644
--- a/Cargo.toml
+++ b/Cargo.toml
@@ -10,6 +10,7 @@ build = "src/build.rs"
ructe = { version = "0.17.0", features = ["sass", "mime03"] }
[dependencies]
+actix-session = { version = "0.8.0", features = ["cookie-session"] }
actix-web = "4.4.0"
bcrypt = "0.15.0"
mime = "0.3.17"
diff --git a/TODO.md b/TODO.md
index 6cc4b51..de0edc9 100644
--- a/TODO.md
+++ b/TODO.md
@@ -3,3 +3,5 @@
- [ ] refactor into different files
- [ ] archive pin web sources
- [ ] salt hashes
+- [ ] proper error handling with custom error type that implements response error, use actix::Result on http handlers
+- [ ] css styling
diff --git a/src/main.rs b/src/main.rs
index c1520ed..2736c5a 100644
--- a/src/main.rs
+++ b/src/main.rs
@@ -3,10 +3,16 @@ mod actix_ructe;
use std::time::{Duration, SystemTime};
+use actix_session::storage::CookieSessionStore;
+use actix_session::{Session, SessionGetError, SessionInsertError, SessionMiddleware};
use actix_web::body::{BoxBody, EitherBody, MessageBody};
+use actix_web::cookie::time::Error;
+use actix_web::cookie::Key;
use actix_web::dev::ServiceResponse;
+use actix_web::http::header::LOCATION;
use actix_web::http::{header, StatusCode};
use actix_web::middleware::{ErrorHandlerResponse, ErrorHandlers};
+use actix_web::web::Redirect;
use actix_web::{get, post, web, App, HttpResponse, HttpServer, Responder, ResponseError};
use bcrypt::{hash, verify, DEFAULT_COST};
use serde::Deserialize;
@@ -37,6 +43,11 @@ async fn main() -> std::io::Result<()> {
HttpServer::new(move || {
App::new()
+ .wrap(SessionMiddleware::new(
+ // TODO: postgres session store
+ CookieSessionStore::default(),
+ Key::generate(),
+ ))
.wrap(
ErrorHandlers::new()
.handler(StatusCode::NOT_FOUND, render_404)
@@ -45,6 +56,7 @@ async fn main() -> std::io::Result<()> {
.app_data(web::Data::new(pinussy.clone()))
.service(web::resource("/static/{filename}").to(static_file))
.service(home)
+ // .service(home_auth)
.service(get_login)
.service(post_login)
.service(get_signup)
@@ -62,8 +74,12 @@ async fn main() -> std::io::Result<()> {
}
#[get("/")]
-async fn home() -> HttpResponse {
- HttpResponse::Ok().body("Hello world!")
+async fn home(session: Session) -> Result<HttpResponse> {
+ if let Some(user_id) = session.get::<i32>("user_id")? {
+ return Ok(HttpResponse::Ok().body(format!("you are logged in as {}", user_id)));
+ } else {
+ return Ok(HttpResponse::Ok().body("Hello world!"));
+ }
}
#[get("/signup")]
@@ -153,8 +169,63 @@ struct LoginForm {
}
#[post("/login")]
-async fn post_login(form: web::Form<LoginForm>) -> Result<HttpResponse> {
- Ok(HttpResponse::Ok().body(render!(templates::login_html, None).unwrap()))
+async fn post_login(
+ state: web::Data<Pinussy>,
+ session: Session,
+ form: web::Form<SignupForm>,
+) -> Result<HttpResponse> {
+ match sqlx::query!(
+ "select id, password from users where username = $1",
+ &form.username
+ )
+ .fetch_one(&state.db)
+ .await
+ {
+ Ok(user) => {
+ let password_hash: String = user.password;
+ if verify(&form.password, &password_hash)? {
+ session.insert("user_id", user.id)?;
+ return Ok(HttpResponse::SeeOther()
+ .insert_header((LOCATION, "/"))
+ .finish());
+ } else {
+ return Ok(HttpResponse::Unauthorized().body(
+ render!(
+ templates::login_html,
+ Some(Notification {
+ kind: NotificationKind::Error,
+ message: "that password is incorrect".to_owned()
+ })
+ )
+ .unwrap(),
+ ));
+ }
+ }
+ Err(sqlx::Error::RowNotFound) => {
+ return Ok(HttpResponse::NotFound().body(
+ render!(
+ templates::login_html,
+ Some(Notification {
+ kind: NotificationKind::Error,
+ message: format!("the user \"{}\" does not exist", &form.username)
+ })
+ )
+ .unwrap(),
+ ));
+ }
+ Err(_) => {
+ return Ok(HttpResponse::InternalServerError().body(
+ render!(
+ templates::login_html,
+ Some(Notification {
+ kind: NotificationKind::Error,
+ message: "internal server error. please try again later".to_owned()
+ })
+ )
+ .unwrap(),
+ ));
+ }
+ }
}
#[derive(sqlx::Type)]
@@ -203,6 +274,7 @@ async fn get_users(state: web::Data<Pinussy>) -> Result<HttpResponse> {
let users: Vec<User> = sqlx::query_as("select * from users")
.fetch_all(&state.db)
.await
+ // TODO: no unwrap
.unwrap();
println!("lol");
Ok(HttpResponse::Ok().body(render!(templates::users_html, users).unwrap()))
@@ -258,9 +330,23 @@ fn error_response(
#[derive(Debug)]
enum PinussyError {
Database(sqlx::Error),
+ SessionInsertError,
+ SessionGetError,
Bcrypt,
}
+impl From<SessionInsertError> for PinussyError {
+ fn from(_: SessionInsertError) -> Self {
+ Self::SessionInsertError
+ }
+}
+
+impl From<SessionGetError> for PinussyError {
+ fn from(_: SessionGetError) -> Self {
+ Self::SessionGetError
+ }
+}
+
impl From<sqlx::Error> for PinussyError {
fn from(e: sqlx::Error) -> Self {
Self::Database(e)
@@ -268,7 +354,7 @@ impl From<sqlx::Error> for PinussyError {
}
impl From<bcrypt::BcryptError> for PinussyError {
- fn from(e: bcrypt::BcryptError) -> Self {
+ fn from(_: bcrypt::BcryptError) -> Self {
Self::Bcrypt
}
}