diff --git a/actix/Cargo.lock b/actix/Cargo.lock index 82d4a5d..6cc0065 100644 --- a/actix/Cargo.lock +++ b/actix/Cargo.lock @@ -53,7 +53,7 @@ dependencies = [ "actix-service", "actix-utils", "ahash 0.8.3", - "base64", + "base64 0.21.0", "bitflags 1.3.2", "brotli", "bytes", @@ -88,7 +88,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "465a6172cf69b960917811022d8f29bc0b7fa1398bc4f78b3c466673db1213b6" dependencies = [ "quote", - "syn", + "syn 1.0.109", ] [[package]] @@ -143,6 +143,23 @@ dependencies = [ "pin-project-lite", ] +[[package]] +name = "actix-session" +version = "0.7.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "43da8b818ae1f11049a4d218975345fe8e56ce5a5f92c11f972abcff5ff80e87" +dependencies = [ + "actix-service", + "actix-utils", + "actix-web", + "anyhow", + "async-trait", + "derive_more", + "serde", + "serde_json", + "tracing", +] + [[package]] name = "actix-utils" version = "3.0.1" @@ -203,7 +220,7 @@ dependencies = [ "actix-router", "proc-macro2", "quote", - "syn", + "syn 1.0.109", ] [[package]] @@ -212,6 +229,41 @@ version = "1.0.2" 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.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "433cfd6710c9986c576a25ca913c39d66a6474107b406f34f91d4a8923395241" +dependencies = [ + "cfg-if", + "cipher", + "cpufeatures", +] + +[[package]] +name = "aes-gcm" +version = "0.10.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "82e1366e0c69c9f927b1fa5ce2c7bf9eafc8f9268c0b9800729e8b267612447c" +dependencies = [ + "aead", + "aes", + "cipher", + "ctr", + "ghash", + "subtle", +] + [[package]] name = "ahash" version = "0.7.6" @@ -259,18 +311,41 @@ dependencies = [ "alloc-no-stdlib", ] +[[package]] +name = "anyhow" +version = "1.0.70" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7de8ce5e0f9f8d88245311066a578d72b7af3e7088f32783804676302df237e4" + [[package]] name = "askama_escape" version = "0.10.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "619743e34b5ba4e9703bba34deac3427c72507c7159f5fd030aea8cac0cfe341" +[[package]] +name = "async-trait" +version = "0.1.68" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b9ccdd8f2a161be9bd5c023df56f1b2a0bd1d83872ae53b71a84a12c9bf6e842" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.13", +] + [[package]] name = "autocfg" version = "1.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d468802bab17cbc0cc575e9b053f41e72aa36bfa6b7f55e3529ffa43161b97fa" +[[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.0" @@ -349,6 +424,16 @@ version = "1.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd" +[[package]] +name = "cipher" +version = "0.4.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "773f3b9af64447d2ce9850330c473515014aa235e6a783b02db81ff39e4a3dad" +dependencies = [ + "crypto-common", + "inout", +] + [[package]] name = "convert_case" version = "0.4.0" @@ -361,7 +446,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", + "sha2", + "subtle", "time", "version_check", ] @@ -391,9 +483,19 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "1bfb12502f3fc46cca1bb51ac28df9d618d813cdc3d2f25b9fe775a34af26bb3" dependencies = [ "generic-array", + "rand_core", "typenum", ] +[[package]] +name = "ctr" +version = "0.9.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0369ee1ad671834580515889b80f2ea915f23b8be8d0daa4bbaf2ac5c7590835" +dependencies = [ + "cipher", +] + [[package]] name = "derive_more" version = "0.99.17" @@ -404,7 +506,7 @@ dependencies = [ "proc-macro2", "quote", "rustc_version", - "syn", + "syn 1.0.109", ] [[package]] @@ -415,6 +517,7 @@ checksum = "8168378f4e5023e7218c89c891c0fd8ecdb5e5e4f18cb78f38cf245dd021e76f" dependencies = [ "block-buffer", "crypto-common", + "subtle", ] [[package]] @@ -514,6 +617,16 @@ dependencies = [ "wasi", ] +[[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 = "h2" version = "0.3.16" @@ -560,6 +673,24 @@ dependencies = [ "libc", ] +[[package]] +name = "hkdf" +version = "0.12.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "791a029f6b9fc27657f6f188ec6e5e43f6911f6f878e0dc5501396e09809d437" +dependencies = [ + "hmac", +] + +[[package]] +name = "hmac" +version = "0.12.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6c49c37c09c17a53d937dfbb742eb3a961d65a994e6bcdcf37e7399d0cc8ab5e" +dependencies = [ + "digest", +] + [[package]] name = "http" version = "0.2.9" @@ -609,6 +740,15 @@ dependencies = [ "hashbrown", ] +[[package]] +name = "inout" +version = "0.1.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a0c10553d664a4d0bcff9f4215d0aac67a639cc68ef660840afe309b807bc9f5" +dependencies = [ + "generic-array", +] + [[package]] name = "itoa" version = "1.0.6" @@ -742,6 +882,12 @@ version = "1.17.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b7e5500299e16ebb147ae15a00a942af264cf3688f47923b8fc2cd5858f23ad3" +[[package]] +name = "opaque-debug" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "624a8340c38c1b80fd549087862da4ba43e08858af025b236e509b6649fc13d5" + [[package]] name = "parking_lot" version = "0.12.1" @@ -795,6 +941,18 @@ version = "0.3.26" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "6ac9a59f73473f1b8d852421e59e64809f025994837ef743615c6d0c5b305160" +[[package]] +name = "polyval" +version = "0.6.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7ef234e08c11dfcb2e56f79fd70f6f2eb7f025c0ce2333e82f4f0518ecad30c6" +dependencies = [ + "cfg-if", + "cpufeatures", + "opaque-debug", + "universal-hash", +] + [[package]] name = "ppv-lite86" version = "0.2.17" @@ -956,6 +1114,17 @@ dependencies = [ "digest", ] +[[package]] +name = "sha2" +version = "0.10.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "82e6b795fe2e3b1e845bafcb27aa35405c4d47cdfc92af5fc8d3002f76cebdc0" +dependencies = [ + "cfg-if", + "cpufeatures", + "digest", +] + [[package]] name = "signal-hook-registry" version = "1.4.1" @@ -970,6 +1139,7 @@ name = "simply-shorten" version = "0.1.0" dependencies = [ "actix-files", + "actix-session", "actix-web", "rand", "regex", @@ -1001,6 +1171,12 @@ dependencies = [ "winapi", ] +[[package]] +name = "subtle" +version = "2.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6bdef32e8150c2a081110b42772ffe7d7c9032b606bc226c8260fd97e0976601" + [[package]] name = "syn" version = "1.0.109" @@ -1012,6 +1188,17 @@ dependencies = [ "unicode-ident", ] +[[package]] +name = "syn" +version = "2.0.13" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4c9da457c5285ac1f936ebd076af6dac17a61cfe7826f2076b4d015cf47bc8ec" +dependencies = [ + "proc-macro2", + "quote", + "unicode-ident", +] + [[package]] name = "time" version = "0.3.20" @@ -1142,6 +1329,16 @@ dependencies = [ "tinyvec", ] +[[package]] +name = "universal-hash" +version = "0.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7d3160b73c9a19f7e2939a2fdad446c57c1bbbbf4d919d3213ff1267a580d8b5" +dependencies = [ + "crypto-common", + "subtle", +] + [[package]] name = "url" version = "2.3.1" diff --git a/actix/Cargo.toml b/actix/Cargo.toml index 23bee14..2b06a26 100644 --- a/actix/Cargo.toml +++ b/actix/Cargo.toml @@ -11,3 +11,4 @@ actix-files = "0.6.2" rusqlite = "0.29.0" regex = "1.7.3" rand = "0.8.5" +actix-session = {version = "0.7.2", features = ["cookie-session"]} diff --git a/actix/resources/js/main.js b/actix/resources/js/main.js index 7f29ec5..354a490 100644 --- a/actix/resources/js/main.js +++ b/actix/resources/js/main.js @@ -9,8 +9,22 @@ const getSiteUrl = async () => await fetch("/api/siteurl") } }); +const auth_fetch = async (link) => { + let reply = await fetch(link).then(res => res.text()); + if (reply == "logged_out") { + pass = prompt("Please enter passkey to access this website"); + await fetch("/api/login", { + method: "POST", + body: pass + }); + return auth_fetch(link); + } else { + return reply; + } +} + const refreshData = async () => { - let data = await fetch("/api/all").then(res => res.text()); + let data = await auth_fetch("/api/all"); data = data .split("\n") .filter(line => line !== "") diff --git a/actix/src/auth.rs b/actix/src/auth.rs new file mode 100644 index 0000000..0bf495d --- /dev/null +++ b/actix/src/auth.rs @@ -0,0 +1,22 @@ +use actix_session::Session; + +pub fn validate(session: Session) -> bool { + let token = session.get::("session-token"); + if token.is_err() { + false + } else if !check(token.unwrap()) { + false + } else { + true + } +} + +fn check(token: Option) -> bool { + if token.is_none() { + false + } else if token.unwrap() != 123 { + false + } else { + true + } +} diff --git a/actix/src/main.rs b/actix/src/main.rs index 5e63ad7..085ba9d 100644 --- a/actix/src/main.rs +++ b/actix/src/main.rs @@ -1,12 +1,15 @@ use std::env; use actix_files::{Files, NamedFile}; +use actix_session::{storage::CookieSessionStore, Session, SessionMiddleware}; use actix_web::{ + cookie::Key, delete, get, middleware, post, web::{self, Redirect}, App, HttpResponse, HttpServer, Responder, }; use rusqlite::Connection; +mod auth; mod database; mod utils; @@ -19,26 +22,38 @@ struct AppState { // Add new links #[post("/api/new")] -async fn add_link(req: String, data: web::Data) -> HttpResponse { - let out = utils::add_link(req, &data.db); - if out.0 { - HttpResponse::Ok().body(out.1) +async fn add_link(req: String, data: web::Data, session: Session) -> HttpResponse { + if auth::validate(session) { + let out = utils::add_link(req, &data.db); + if out.0 { + HttpResponse::Ok().body(out.1) + } else { + HttpResponse::BadRequest().body(out.1) + } } else { - HttpResponse::BadRequest().body(out.1) + HttpResponse::Forbidden().body("logged_out") } } // Return all active links #[get("/api/all")] -async fn getall(data: web::Data) -> HttpResponse { - HttpResponse::Ok().body(utils::getall(&data.db)) +async fn getall(data: web::Data, session: Session) -> HttpResponse { + if auth::validate(session) { + HttpResponse::Ok().body(utils::getall(&data.db)) + } else { + HttpResponse::Forbidden().body("logged_out") + } } // Get the site URL #[get("/api/siteurl")] -async fn siteurl() -> HttpResponse { - let site_url = env::var("site_url").unwrap_or("unset".to_string()); - HttpResponse::Ok().body(site_url) +async fn siteurl(session: Session) -> HttpResponse { + if auth::validate(session) { + let site_url = env::var("site_url").unwrap_or("unset".to_string()); + HttpResponse::Ok().body(site_url) + } else { + HttpResponse::Forbidden().body("logged_out") + } } // 404 error page @@ -60,17 +75,42 @@ async fn link_handler(shortlink: web::Path, data: web::Data) - } } +// Handle login +#[post("/api/login")] +async fn login(req: String, session: Session) -> HttpResponse { + if req == "ssssss".to_string() { + session.insert("session-token", 123).unwrap(); + HttpResponse::Ok().body("Correct password!") + } else { + eprintln!("Failed login attempt!"); + HttpResponse::Forbidden().body("Wrong password!") + } +} + // Delete a given shortlink #[delete("/api/del/{shortlink}")] -async fn delete_link(shortlink: web::Path, data: web::Data) -> HttpResponse { - database::delete_link(shortlink.to_string(), &data.db); - HttpResponse::Ok().body("") +async fn delete_link( + shortlink: web::Path, + data: web::Data, + session: Session, +) -> HttpResponse { + if auth::validate(session) { + database::delete_link(shortlink.to_string(), &data.db); + HttpResponse::Ok().body("") + } else { + HttpResponse::Forbidden().body("Wrong password!") + } } #[actix_web::main] async fn main() -> std::io::Result<()> { - HttpServer::new(|| { + let secret_key = Key::generate(); + HttpServer::new(move || { App::new() + .wrap(SessionMiddleware::new( + CookieSessionStore::default(), + secret_key.clone(), + )) .app_data(web::Data::new(AppState { db: database::open_db(env::var("db_url").unwrap_or("./urls.sqlite".to_string())), })) @@ -81,6 +121,7 @@ async fn main() -> std::io::Result<()> { .service(siteurl) .service(add_link) .service(delete_link) + .service(login) .default_service(Files::new("/", "./resources/").index_file("index.html")) }) .bind(("0.0.0.0", 2000))?