handle sign in
This commit is contained in:
parent
7b3014b44d
commit
86d4b2c6de
57
Cargo.lock
generated
57
Cargo.lock
generated
@ -758,6 +758,33 @@ version = "1.1.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "d468802bab17cbc0cc575e9b053f41e72aa36bfa6b7f55e3529ffa43161b97fa"
|
||||
|
||||
[[package]]
|
||||
name = "autometrics"
|
||||
version = "0.5.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "6fd5718a452b060adfb2402004a5ebd67ea90e926da637259748de0ca654ea37"
|
||||
dependencies = [
|
||||
"autometrics-macros",
|
||||
"cfg_aliases",
|
||||
"once_cell",
|
||||
"spez",
|
||||
"thiserror",
|
||||
"tracing",
|
||||
"tracing-subscriber",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "autometrics-macros"
|
||||
version = "0.5.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "0beb4214dae229373b9f437afe2c954a1c8cfb8a64ac753a47285a759ae80284"
|
||||
dependencies = [
|
||||
"percent-encoding",
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"syn 1.0.109",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "backtrace"
|
||||
version = "0.3.68"
|
||||
@ -894,7 +921,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "4114279215a005bc675e386011e594e1d9b800918cea18fcadadcce864a2046b"
|
||||
dependencies = [
|
||||
"borsh-derive",
|
||||
"hashbrown 0.13.2",
|
||||
"hashbrown 0.12.3",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@ -1027,6 +1054,12 @@ version = "1.0.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd"
|
||||
|
||||
[[package]]
|
||||
name = "cfg_aliases"
|
||||
version = "0.1.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "fd16c4719339c4530435d38e511904438d07cce7950afa3718a84ac36c10e89e"
|
||||
|
||||
[[package]]
|
||||
name = "chrono"
|
||||
version = "0.4.26"
|
||||
@ -1669,15 +1702,6 @@ dependencies = [
|
||||
"ahash 0.7.6",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "hashbrown"
|
||||
version = "0.13.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "43a3c133739dddd0d2990f9a4bdf8eb4b21ef50e4851ca85ab661199821d510e"
|
||||
dependencies = [
|
||||
"ahash 0.8.3",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "hashbrown"
|
||||
version = "0.14.0"
|
||||
@ -2296,6 +2320,8 @@ dependencies = [
|
||||
"actix-web",
|
||||
"argon2",
|
||||
"askama",
|
||||
"askama_actix",
|
||||
"autometrics",
|
||||
"futures",
|
||||
"jsonwebtoken",
|
||||
"oswilno-contract",
|
||||
@ -3294,6 +3320,17 @@ dependencies = [
|
||||
"winapi",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "spez"
|
||||
version = "0.1.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "c87e960f4dca2788eeb86bbdde8dd246be8948790b7618d656e68f9b720a86e8"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"syn 2.0.28",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "spin"
|
||||
version = "0.5.2"
|
||||
|
@ -10,9 +10,9 @@ path = "src/lib.rs"
|
||||
|
||||
[dependencies]
|
||||
async-std = { version = "1", features = ["attributes", "tokio1"] }
|
||||
tokio = { version = "1.29.1", features = ["full"] }
|
||||
oswilno-contract = { path = "../oswilno-contract" }
|
||||
sea-orm = { version = "0.11", features = ["runtime-actix-rustls", "sqlx-postgres", "postgres-array", "sqlx"] }
|
||||
tokio = { version = "1.29.1", features = ["full"] }
|
||||
|
||||
[dependencies.sea-orm-migration]
|
||||
version = "0.11.0"
|
||||
|
@ -11,6 +11,6 @@ actix-web = "4.3.1"
|
||||
actix-web-grants = "3.0.2"
|
||||
askama = "0.12.0"
|
||||
chrono = "0.4.26"
|
||||
oswilno-contract = { path = "../oswilno-contract" }
|
||||
tera = "1.17.1"
|
||||
uuid = { version = "1.4.1", features = ["v4"] }
|
||||
oswilno-contract = { path = "../oswilno-contract" }
|
||||
|
@ -10,8 +10,8 @@ actix = "0.13.0"
|
||||
actix-admin = { git = "https://code.ita-prog.pl/Tsumanu/actix-admin.git", features = ['enable-tracing'] }
|
||||
actix-rt = { version = "2.8.0", features = [] }
|
||||
chrono = "0.4.26"
|
||||
oswilno-actix-admin = { path = "../oswilno-actix-admin" }
|
||||
regex = "1.9.1"
|
||||
sea-orm = { version = "0.11", features = ["postgres-array", "runtime-actix-rustls", "sqlx-postgres", "macros", "sqlx"] }
|
||||
serde = { version = "1.0.175", features = ["derive"] }
|
||||
uuid = { version = "1.4.1", features = ["v4"] }
|
||||
oswilno-actix-admin = { path = "../oswilno-actix-admin" }
|
||||
|
@ -8,9 +8,9 @@ edition = "2021"
|
||||
actix = "0.13.0"
|
||||
actix-web = "4.3.1"
|
||||
askama = { version = "0.12.0", features = ["serde", "with-actix-web", "comrak", "mime"] }
|
||||
tokio = { version = "1.29.1", features = ["full"] }
|
||||
askama_actix = "0.14.0"
|
||||
oswilno-contract = { path = "../oswilno-contract" }
|
||||
sea-orm = { version = "0.11.1", features = ["runtime-actix-rustls", "sqlx", "sqlx-postgres", "debug-print"] }
|
||||
serde = { version = "1.0.176", features = ["derive"] }
|
||||
serde_json = "1.0.104"
|
||||
askama_actix = "0.14.0"
|
||||
tokio = { version = "1.29.1", features = ["full"] }
|
||||
|
@ -23,6 +23,7 @@ struct AllParkingSpace {
|
||||
parking_space_by_id: HashMap<i32, parking_spaces::Model>,
|
||||
account_by_id: HashMap<i32, accounts::Model>,
|
||||
}
|
||||
|
||||
#[derive(Template)]
|
||||
#[template(path = "../templates/parking-spaces/all-partial.html")]
|
||||
struct AllPartialParkingSpace {
|
||||
|
@ -1,4 +1,5 @@
|
||||
{% extends "../base.html" %}
|
||||
|
||||
{% block body %}
|
||||
{% include "./all-partial.html" %}
|
||||
{% endblock %}
|
||||
|
@ -10,19 +10,19 @@ actix-web = "4.3.1"
|
||||
actix-web-grants = "3.0.2"
|
||||
askama = { version = "0.12.0", features = ["serde", "with-actix-web", "comrak", "mime"] }
|
||||
futures = { version = "0.3.28", features = ["futures-executor"] }
|
||||
oswilno-admin = { path = "../oswilno-admin" }
|
||||
oswilno-config = { path = "../oswilno-config" }
|
||||
oswilno-parking-space = { path = "../oswilno-parking-space" }
|
||||
oswilno-view = { path = "../oswilno-view" }
|
||||
oswilno-admin = { path = "../oswilno-admin" }
|
||||
oswilno-session = { path = "../oswilno-session" }
|
||||
web-assets = { path = "../web-assets" }
|
||||
oswilno-view = { path = "../oswilno-view" }
|
||||
sea-orm = { version = "0.11", features = ["postgres-array", "runtime-actix-rustls", "sqlx-postgres"] }
|
||||
serde = { version = "1.0.175", features = ["derive"] }
|
||||
serde_json = "1.0.103"
|
||||
tokio = { version = "1.29.1", features = ["full"] }
|
||||
toml = "0.7.6"
|
||||
tracing-subscriber = { version = "0.3.17", features = ["env-filter", "json"] }
|
||||
tracing = "0.1.37"
|
||||
tracing-subscriber = { version = "0.3.17", features = ["env-filter", "json"] }
|
||||
web-assets = { path = "../web-assets" }
|
||||
|
||||
[dev-dependencies]
|
||||
insta = { version = "1.31.0", features = ["ron"] }
|
||||
|
@ -7,17 +7,19 @@ edition = "2021"
|
||||
actix-http = "3.3.1"
|
||||
actix-jwt-authc = { version = "0.2.0", features = ["tracing", "session"] }
|
||||
actix-web = "4.3.1"
|
||||
argon2 = "0.5.1"
|
||||
askama = { version = "0.12.0", features = ["serde", "with-actix-web", "comrak", "mime"] }
|
||||
askama_actix = { version = "0.14.0" }
|
||||
autometrics = { version = "0.5.0", features = ["tracing", "tracing-subscriber", "thiserror"] }
|
||||
futures = { version = "0.3.28", features = ["thread-pool"] }
|
||||
jsonwebtoken = "8.3.0"
|
||||
oswilno-contract = { path = "../oswilno-contract" }
|
||||
oswilno-view = { path = "../oswilno-view" }
|
||||
rand = "0.8.5"
|
||||
ring = "0.16.20"
|
||||
sea-orm = { version = "0.11", features = ["postgres-array", "runtime-actix-rustls", "sqlx-postgres", "macros", "sqlx"] }
|
||||
serde = { version = "1.0.180", features = ["derive"] }
|
||||
time = "0.3.24"
|
||||
tokio = { version = "1.29.1", features = ["full"] }
|
||||
uuid = { version = "1.4.1", features = ["v4"] }
|
||||
sea-orm = { version = "0.11", features = ["postgres-array", "runtime-actix-rustls", "sqlx-postgres", "macros", "sqlx"] }
|
||||
oswilno-contract = { path = "../oswilno-contract" }
|
||||
tracing = "0.1.37"
|
||||
argon2 = "0.5.1"
|
||||
askama = { version = "0.12.0", features = ["serde", "with-actix-web", "comrak", "mime"] }
|
||||
oswilno-view = { path = "../oswilno-view" }
|
||||
uuid = { version = "1.4.1", features = ["v4"] }
|
||||
|
@ -2,8 +2,9 @@ use std::ops::Add;
|
||||
use std::sync::Arc;
|
||||
|
||||
use actix_jwt_authc::*;
|
||||
use actix_web::web::{Data, Json, ServiceConfig};
|
||||
use actix_web::web::{Data, Json, ServiceConfig, Query, Form};
|
||||
use actix_web::{get, post, HttpResponse};
|
||||
use autometrics::autometrics;
|
||||
use futures::channel::{mpsc, mpsc::Sender};
|
||||
use futures::stream::Stream;
|
||||
use futures::SinkExt;
|
||||
@ -15,6 +16,7 @@ use serde::{Deserialize, Serialize};
|
||||
use time::ext::*;
|
||||
use time::OffsetDateTime;
|
||||
use tokio::sync::Mutex;
|
||||
use askama_actix::Template;
|
||||
|
||||
mod hashing;
|
||||
|
||||
@ -68,6 +70,7 @@ impl SessionConfigurator {
|
||||
.app_data(self.encoding_key)
|
||||
.app_data(self.jwt_ttl)
|
||||
.service(login)
|
||||
.service(login_view)
|
||||
.service(logout)
|
||||
.service(session_info);
|
||||
}
|
||||
@ -77,13 +80,18 @@ impl SessionConfigurator {
|
||||
}
|
||||
|
||||
pub fn translations(&self, l10n: &mut oswilno_view::TranslationStorage) {
|
||||
l10n.with_lang("en")
|
||||
l10n
|
||||
// English
|
||||
.with_lang("en")
|
||||
.add("Sign in", "Sign in")
|
||||
.add("Sign up", "Sign up")
|
||||
.add("Bad credentials", "Bad credentials")
|
||||
.done()
|
||||
// Polish
|
||||
.with_lang("pl")
|
||||
.add("Sign in", "Logowanie")
|
||||
.add("Sign up", "Rejestracja")
|
||||
.add("Bad credentials", "Złe dane uwierzytelniające")
|
||||
.done();
|
||||
}
|
||||
|
||||
@ -110,21 +118,61 @@ impl SessionConfigurator {
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, Serialize, Deserialize, Clone, Eq, PartialEq)]
|
||||
pub struct SignInPayload {
|
||||
login: String,
|
||||
password: String,
|
||||
#[derive(Template)]
|
||||
#[template(path = "./sign-in/full.html")]
|
||||
struct SignInTemplate {
|
||||
form: SignInPayload,
|
||||
}
|
||||
|
||||
#[derive(Template)]
|
||||
#[template(path = "./sign-in/partial.html")]
|
||||
struct SignInPartialTemplate {
|
||||
form: SignInPayload,
|
||||
}
|
||||
|
||||
#[derive(Debug, Serialize, Deserialize, Clone, Eq, PartialEq, Default)]
|
||||
pub struct SignInPayload {
|
||||
#[serde(skip, default)]
|
||||
errors: Vec<String>,
|
||||
|
||||
login: String,
|
||||
#[serde(skip, default)]
|
||||
login_errors: Vec<String>,
|
||||
|
||||
password: String,
|
||||
#[serde(skip, default)]
|
||||
password_errors: Vec<String>,
|
||||
}
|
||||
|
||||
#[get("/login")]
|
||||
async fn login_view() -> SignInTemplate {
|
||||
SignInTemplate { form: SignInPayload::default() }
|
||||
}
|
||||
|
||||
#[autometrics]
|
||||
#[post("/login")]
|
||||
async fn login(
|
||||
jwt_encoding_key: Data<EncodingKey>,
|
||||
jwt_ttl: Data<JWTTtl>,
|
||||
db: Data<DatabaseConnection>,
|
||||
payload: Json<SignInPayload>,
|
||||
payload: Form<SignInPayload>,
|
||||
t: Data<oswilno_view::TranslationStorage>,
|
||||
) -> Result<HttpResponse, Error> {
|
||||
match login_inner(jwt_encoding_key, jwt_ttl, db, payload, t).await {
|
||||
Ok(res) => Ok(HttpResponse::Ok().json(res)),
|
||||
Err(form) => Ok(HttpResponse::Ok().body(SignInPartialTemplate { form }.render().unwrap())),
|
||||
}
|
||||
}
|
||||
|
||||
async fn login_inner(
|
||||
jwt_encoding_key: Data<EncodingKey>,
|
||||
jwt_ttl: Data<JWTTtl>,
|
||||
db: Data<DatabaseConnection>,
|
||||
payload: Form<SignInPayload>,
|
||||
t: Data<oswilno_view::TranslationStorage>,
|
||||
) -> Result<LoginResponse, SignInPayload> {
|
||||
let db = db.into_inner();
|
||||
let payload = payload.into_inner();
|
||||
let mut payload = payload.into_inner();
|
||||
|
||||
let iat = OffsetDateTime::now_utc().unix_timestamp() as usize;
|
||||
let expires_at = OffsetDateTime::now_utc().add(jwt_ttl.0);
|
||||
@ -138,15 +186,18 @@ async fn login(
|
||||
{
|
||||
Ok(Some(a)) => a,
|
||||
Ok(None) => {
|
||||
return Err(Error::InternalError);
|
||||
payload.errors.push(t.to_lang("pl", "Bad credentials"));
|
||||
return Err(payload);
|
||||
}
|
||||
Err(e) => {
|
||||
tracing::warn!("Failed to find account: {e}");
|
||||
return Err(Error::InternalError);
|
||||
payload.errors.push(t.to_lang("pl", "Bad credentials"));
|
||||
return Err(payload);
|
||||
}
|
||||
};
|
||||
if hashing::verify(account.pass_hash.as_str(), payload.password.as_str()).is_err() {
|
||||
return Ok(HttpResponse::Unauthorized().body(""));
|
||||
payload.errors.push(t.to_lang("pl", "Bad credentials"));
|
||||
return Err(payload);
|
||||
}
|
||||
|
||||
let jwt_claims = Claims {
|
||||
@ -161,20 +212,23 @@ async fn login(
|
||||
&jwt_claims,
|
||||
&jwt_encoding_key,
|
||||
)
|
||||
.map_err(|_| Error::InternalError)?;
|
||||
let login_response = LoginResponse {
|
||||
.map_err(|_| {
|
||||
payload.errors.push(t.to_lang("pl", "Bad credentials"));
|
||||
payload
|
||||
})?;
|
||||
Ok(LoginResponse {
|
||||
bearer_token: jwt_token,
|
||||
claims: jwt_claims,
|
||||
};
|
||||
|
||||
Ok(HttpResponse::Ok().json(login_response))
|
||||
})
|
||||
}
|
||||
|
||||
#[autometrics]
|
||||
#[get("/session")]
|
||||
async fn session_info(authenticated: UserSession) -> Result<HttpResponse, Error> {
|
||||
Ok(HttpResponse::Ok().json(authenticated))
|
||||
}
|
||||
|
||||
#[autometrics]
|
||||
#[get("/logout")]
|
||||
async fn logout(
|
||||
invalidated_jwts: Data<InvalidatedJWTStore>,
|
||||
@ -190,10 +244,11 @@ struct AccountInfo {
|
||||
password: String,
|
||||
}
|
||||
|
||||
#[autometrics]
|
||||
#[post("/register")]
|
||||
async fn register(
|
||||
db: Data<DatabaseConnection>,
|
||||
payload: Json<AccountInfo>,
|
||||
payload: Query<AccountInfo>,
|
||||
) -> Result<HttpResponse, Error> {
|
||||
use oswilno_contract::accounts::*;
|
||||
use sea_orm::ActiveValue::NotSet;
|
||||
|
@ -1,18 +0,0 @@
|
||||
<!DOCTYPE html>
|
||||
<html>
|
||||
<head>
|
||||
<title>OS Wilno</title>
|
||||
<meta charset="UTF-8" />
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||
<script src="/assets/build.js" type="module"></script>
|
||||
{% block head %}
|
||||
{% endblock %}
|
||||
</head>
|
||||
<body>
|
||||
<base url="/" />
|
||||
<main>
|
||||
{% block body %}
|
||||
{% endblock %}
|
||||
</main>
|
||||
</body>
|
||||
</html>
|
@ -1,22 +0,0 @@
|
||||
{% extends "../base.html" %}
|
||||
{% block body %}
|
||||
<section>
|
||||
<form>
|
||||
<div>
|
||||
<label for="login">Login</label>
|
||||
<input id="login" name="login" />
|
||||
</div>
|
||||
<div>
|
||||
<label for="email">E-Mail</label>
|
||||
<input id="email" name="email" type="email" />
|
||||
</div>
|
||||
<div>
|
||||
<label for="password">Password</label>
|
||||
<input id="password" name="password" type="password" />
|
||||
</div>
|
||||
<div>
|
||||
<input type="submit" value="Sign Up" />
|
||||
</div>
|
||||
</form>
|
||||
</section>
|
||||
{% endblock %}
|
@ -1,18 +0,0 @@
|
||||
{% extends "../base.html" %}
|
||||
{% block body %}
|
||||
<section>
|
||||
<form>
|
||||
<div>
|
||||
<label for="login">Login</label>
|
||||
<input id="login" name="login" />
|
||||
</div>
|
||||
<div>
|
||||
<label for="password">Password</label>
|
||||
<input id="password" name="password" type="password" />
|
||||
</div>
|
||||
<div>
|
||||
<input type="submit" value="Sign In" />
|
||||
</div>
|
||||
</form>
|
||||
</section>
|
||||
{% endblock %}
|
@ -7,6 +7,6 @@ edition = "2021"
|
||||
actix = "0.13.0"
|
||||
actix-web = "4.3.1"
|
||||
askama = { version = "0.12.0", features = ["serde", "with-actix-web", "comrak", "mime"] }
|
||||
tokio = { version = "1.29.1", features = ["full"] }
|
||||
serde = { version = "1.0.176", features = ["derive"] }
|
||||
serde_json = "1.0.104"
|
||||
tokio = { version = "1.29.1", features = ["full"] }
|
||||
|
@ -1 +1,2 @@
|
||||
import './elements/oswilno-price.js';
|
||||
import("https://unpkg.com/htmx.org@1.9.4/dist/htmx.min.js");
|
||||
|
@ -9,5 +9,6 @@ cd ${ROOT}
|
||||
mkdir assets
|
||||
|
||||
cd ${WEB_ASSETS_ROOT}
|
||||
npm install esbuild
|
||||
yarn add esbuild
|
||||
yarn add htmx
|
||||
${WEB_ASSETS_ROOT}/node_modules/.bin/esbuild --bundle ${WEB_ASSETS_ROOT}/assets/app.js --outfile=${ROOT}/assets/build.js --minify --sourcemap
|
||||
|
@ -1,5 +1,7 @@
|
||||
{
|
||||
"dependencies": {
|
||||
"esbuild": "^0.18.17"
|
||||
"esbuild": "^0.18.17",
|
||||
"htmlx": "^0.1.0",
|
||||
"htmx": "^0.0.2"
|
||||
}
|
||||
}
|
||||
|
@ -1,8 +1,7 @@
|
||||
[toolchain]
|
||||
# channel = "nightly-2022-10-29"
|
||||
channel = "stable"
|
||||
components = ['rust-analyzer', "rustfmt"]
|
||||
targets = []
|
||||
profile = "default"
|
||||
|
||||
# rustc 1.66.0-nightly (5e9772042 2022-10-29)
|
||||
# channel = "nightly-2023-08-02"
|
||||
channel = "stable"
|
||||
# channel = "stable-2022-09-22"
|
||||
components = ['rust-analyzer', "rustfmt"]
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user