finished move from warp to axum, added nav

This commit is contained in:
emilis 2022-09-13 15:56:10 +01:00
parent a5eef831c7
commit 779e4aa2ea
22 changed files with 524 additions and 459 deletions

329
Cargo.lock generated
View File

@ -170,16 +170,6 @@ dependencies = [
"generic-array",
]
[[package]]
name = "buf_redux"
version = "0.8.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "b953a6887648bb07a535631f2bc00fbdb2a2216f135552cb3f534ed136b9c07f"
dependencies = [
"memchr",
"safemem",
]
[[package]]
name = "bumpalo"
version = "3.11.0"
@ -210,6 +200,17 @@ version = "1.0.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd"
[[package]]
name = "cookie"
version = "0.16.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "94d4706de1b0fa5b132270cddffa8585166037822e260a944fe161acd137ca05"
dependencies = [
"percent-encoding",
"time",
"version_check",
]
[[package]]
name = "cpufeatures"
version = "0.2.5"
@ -277,15 +278,6 @@ version = "0.2.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "4443176a9f2c162692bd3d352d745ef9413eec5782a80d8fd6f8a1ac692a07f7"
[[package]]
name = "fastrand"
version = "1.8.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "a7a407cfaa3385c4ae6b23e84623d48c2798d06e3e6a1878f7f59f17b3f86499"
dependencies = [
"instant",
]
[[package]]
name = "flabk"
version = "0.0.1"
@ -304,7 +296,7 @@ dependencies = [
"serde_json",
"tokio",
"tokio-postgres",
"warp",
"tower-cookies",
]
[[package]]
@ -403,25 +395,6 @@ version = "0.26.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "22030e2c5a68ec659fde1e949a745124b48e6fa8b045b7ed5bd1fe4ccc5c4e5d"
[[package]]
name = "h2"
version = "0.3.14"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "5ca32592cf21ac7ccab1825cd87f6c9b3d9022c44d086172ed0966bec8af30be"
dependencies = [
"bytes",
"fnv",
"futures-core",
"futures-sink",
"futures-util",
"http",
"indexmap",
"slab",
"tokio",
"tokio-util 0.7.4",
"tracing",
]
[[package]]
name = "handlebars"
version = "4.3.3"
@ -436,37 +409,6 @@ dependencies = [
"thiserror",
]
[[package]]
name = "hashbrown"
version = "0.12.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "8a9ee70c43aaf417c914396645a0fa852624801b24ebb7ae78fe8272889ac888"
[[package]]
name = "headers"
version = "0.3.8"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "f3e372db8e5c0d213e0cd0b9be18be2aca3d44cf2fe30a9d46a65581cd454584"
dependencies = [
"base64",
"bitflags",
"bytes",
"headers-core",
"http",
"httpdate",
"mime",
"sha1",
]
[[package]]
name = "headers-core"
version = "0.2.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "e7f66481bfee273957b1f20485a4ff3362987f85b2c236580d81b4eb7a326429"
dependencies = [
"http",
]
[[package]]
name = "hermit-abi"
version = "0.1.19"
@ -535,7 +477,6 @@ dependencies = [
"futures-channel",
"futures-core",
"futures-util",
"h2",
"http",
"http-body",
"httparse",
@ -549,35 +490,6 @@ dependencies = [
"want",
]
[[package]]
name = "idna"
version = "0.3.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "e14ddfc70884202db2244c223200c204c2bda1bc6e0998d11b5e024d657209e6"
dependencies = [
"unicode-bidi",
"unicode-normalization",
]
[[package]]
name = "indexmap"
version = "1.9.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "10a35a97730320ffe8e2d410b5d3b69279b98d2c14bdb8b70ea89ecf7888d41e"
dependencies = [
"autocfg",
"hashbrown",
]
[[package]]
name = "instant"
version = "0.1.12"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "7a5bbe824c507c5da5956355e86a746d82e0e1464f65d862cc5e71da70e94b2c"
dependencies = [
"cfg-if",
]
[[package]]
name = "itoa"
version = "1.0.3"
@ -690,24 +602,6 @@ dependencies = [
"windows-sys",
]
[[package]]
name = "multipart"
version = "0.18.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "00dec633863867f29cb39df64a397cdf4a6354708ddd7759f70c7fb51c5f9182"
dependencies = [
"buf_redux",
"httparse",
"log",
"mime",
"mime_guess",
"quick-error",
"rand",
"safemem",
"tempfile",
"twoway",
]
[[package]]
name = "num-bigint"
version = "0.2.6"
@ -879,7 +773,7 @@ checksum = "1538eb784f07615c6d9a8ab061089c6c54a344c5b4301db51990ca1c241e8c04"
dependencies = [
"once_cell",
"pest",
"sha-1 0.10.0",
"sha-1",
]
[[package]]
@ -978,12 +872,6 @@ dependencies = [
"unicode-ident",
]
[[package]]
name = "quick-error"
version = "1.2.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "a1d01941d82fa2ab50be1e79e6714289dd7cde78eba4c074bc5a4374f650dfe0"
[[package]]
name = "quote"
version = "1.0.21"
@ -1032,15 +920,6 @@ dependencies = [
"bitflags",
]
[[package]]
name = "remove_dir_all"
version = "0.5.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "3acd125665422973a33ac9d3dd2df85edad0f4ae9b00dafb1a05e43a9f5ef8e7"
dependencies = [
"winapi",
]
[[package]]
name = "ring"
version = "0.16.20"
@ -1102,12 +981,6 @@ version = "1.0.11"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "4501abdff3ae82a1c1b477a17252eb69cee9e66eb915c1abaa4f44d873df9f09"
[[package]]
name = "safemem"
version = "0.3.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "ef703b7cb59335eae2eb93ceb664c0eb7ea6bf567079d843e09420219668e072"
[[package]]
name = "same-file"
version = "1.0.6"
@ -1117,12 +990,6 @@ dependencies = [
"winapi-util",
]
[[package]]
name = "scoped-tls"
version = "1.0.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "ea6a9290e3c9cf0f18145ef7ffa62d68ee0bf5fcd651017e586dc7fd5da448c2"
[[package]]
name = "scopeguard"
version = "1.1.0"
@ -1172,19 +1039,6 @@ dependencies = [
"serde",
]
[[package]]
name = "sha-1"
version = "0.9.8"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "99cd6713db3cf16b6c84e06321e049a9b9f699826e16096d23bbcc44d15d51a6"
dependencies = [
"block-buffer 0.9.0",
"cfg-if",
"cpufeatures",
"digest 0.9.0",
"opaque-debug",
]
[[package]]
name = "sha-1"
version = "0.10.0"
@ -1196,17 +1050,6 @@ dependencies = [
"digest 0.10.3",
]
[[package]]
name = "sha1"
version = "0.10.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "006769ba83e921b3085caa8334186b00cf92b4cb1a6cf4632fbccc8eff5c7549"
dependencies = [
"cfg-if",
"cpufeatures",
"digest 0.10.3",
]
[[package]]
name = "sha2"
version = "0.9.9"
@ -1334,20 +1177,6 @@ dependencies = [
"unicode-xid",
]
[[package]]
name = "tempfile"
version = "3.3.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "5cdb1ef4eaeeaddc8fbd371e5017057064af0911902ef36b39801f67cc6d79e4"
dependencies = [
"cfg-if",
"fastrand",
"libc",
"redox_syscall",
"remove_dir_all",
"winapi",
]
[[package]]
name = "thiserror"
version = "1.0.34"
@ -1454,45 +1283,7 @@ dependencies = [
"postgres-types",
"socket2",
"tokio",
"tokio-util 0.7.4",
]
[[package]]
name = "tokio-stream"
version = "0.1.9"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "df54d54117d6fdc4e4fea40fe1e4e566b3505700e148a6827e59b34b0d2600d9"
dependencies = [
"futures-core",
"pin-project-lite",
"tokio",
]
[[package]]
name = "tokio-tungstenite"
version = "0.15.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "511de3f85caf1c98983545490c3d09685fa8eb634e57eec22bb4db271f46cbd8"
dependencies = [
"futures-util",
"log",
"pin-project",
"tokio",
"tungstenite",
]
[[package]]
name = "tokio-util"
version = "0.6.10"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "36943ee01a6d67977dd3f84a5a1d2efeb4ada3a1ae771cadfaa535d9d9fc6507"
dependencies = [
"bytes",
"futures-core",
"futures-sink",
"log",
"pin-project-lite",
"tokio",
"tokio-util",
]
[[package]]
@ -1525,6 +1316,23 @@ dependencies = [
"tracing",
]
[[package]]
name = "tower-cookies"
version = "0.7.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "19833e336396f3953e5ab1513d72b5e5ea51d5ad39b78d306766a05740b48b97"
dependencies = [
"async-trait",
"axum-core",
"cookie",
"futures-util",
"http",
"parking_lot",
"pin-project-lite",
"tower-layer",
"tower-service",
]
[[package]]
name = "tower-http"
version = "0.3.4"
@ -1583,34 +1391,6 @@ version = "0.2.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "59547bce71d9c38b83d9c0e92b6066c4253371f15005def0c30d9657f50c7642"
[[package]]
name = "tungstenite"
version = "0.14.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "a0b2d8558abd2e276b0a8df5c05a2ec762609344191e5fd23e292c910e9165b5"
dependencies = [
"base64",
"byteorder",
"bytes",
"http",
"httparse",
"log",
"rand",
"sha-1 0.9.8",
"thiserror",
"url",
"utf-8",
]
[[package]]
name = "twoway"
version = "0.1.8"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "59b11b2b5241ba34be09c3cc85a36e56e48f9888862e19cedf23336d35316ed1"
dependencies = [
"memchr",
]
[[package]]
name = "typenum"
version = "1.15.0"
@ -1665,23 +1445,6 @@ version = "0.7.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "a156c684c91ea7d62626509bce3cb4e1d9ed5c4d978f7b4352658f96a4c26b4a"
[[package]]
name = "url"
version = "2.3.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "0d68c799ae75762b8c3fe375feb6600ef5602c883c5d21eb51c09f22b83c4643"
dependencies = [
"form_urlencoded",
"idna",
"percent-encoding",
]
[[package]]
name = "utf-8"
version = "0.7.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "09cc8ee72d2a9becf2f2febe0205bbed8fc6615b7cb429ad062dc7b7ddd036a9"
[[package]]
name = "version_check"
version = "0.9.4"
@ -1709,36 +1472,6 @@ dependencies = [
"try-lock",
]
[[package]]
name = "warp"
version = "0.3.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "3cef4e1e9114a4b7f1ac799f16ce71c14de5778500c5450ec6b7b920c55b587e"
dependencies = [
"bytes",
"futures-channel",
"futures-util",
"headers",
"http",
"hyper",
"log",
"mime",
"mime_guess",
"multipart",
"percent-encoding",
"pin-project",
"scoped-tls",
"serde",
"serde_json",
"serde_urlencoded",
"tokio",
"tokio-stream",
"tokio-tungstenite",
"tokio-util 0.6.10",
"tower-service",
"tracing",
]
[[package]]
name = "wasi"
version = "0.11.0+wasi-snapshot-preview1"

View File

@ -20,4 +20,4 @@ serde = { version = "1.0.144", features = ["derive", "std", "serde_derive"]}
serde_json = "1.0.85"
tokio = { version = "1", features = ["full"] }
tokio-postgres = { version = "0.7.7", features = ["with-serde_json-1"] }
warp = { version = "0.3.2" }
tower-cookies = "0.7.0"

148
flabk_icon_placeholder.svg Normal file
View File

@ -0,0 +1,148 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<!-- Created with Inkscape (http://www.inkscape.org/) -->
<svg
width="130.52438mm"
height="130.52438mm"
viewBox="0 0 130.52438 130.52438"
version="1.1"
id="svg5"
inkscape:version="1.2.1 (9c6d41e410, 2022-07-14, custom)"
sodipodi:docname="flabk_icon_placeholder.svg"
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
xmlns="http://www.w3.org/2000/svg"
xmlns:svg="http://www.w3.org/2000/svg">
<sodipodi:namedview
id="namedview7"
pagecolor="#ffffff"
bordercolor="#666666"
borderopacity="1.0"
inkscape:showpageshadow="2"
inkscape:pageopacity="0.0"
inkscape:pagecheckerboard="0"
inkscape:deskcolor="#d1d1d1"
inkscape:document-units="mm"
showgrid="false"
inkscape:zoom="0.54866744"
inkscape:cx="-78.371699"
inkscape:cy="260.63147"
inkscape:window-width="1914"
inkscape:window-height="1041"
inkscape:window-x="0"
inkscape:window-y="16"
inkscape:window-maximized="0"
inkscape:current-layer="layer2" />
<defs
id="defs2">
<rect
x="238.94496"
y="545.79144"
width="291.11197"
height="295.74161"
id="rect1130" />
<filter
style="color-interpolation-filters:sRGB"
inkscape:label="Roughen"
id="filter1273"
x="0"
y="0"
width="1"
height="1">
<feTurbulence
type="fractalNoise"
numOctaves="5"
seed="145"
baseFrequency="0.001 10"
result="turbulence"
id="feTurbulence1269" />
<feDisplacementMap
in="SourceGraphic"
in2="turbulence"
scale="1.68439"
yChannelSelector="G"
xChannelSelector="R"
id="feDisplacementMap1271" />
</filter>
<rect
x="238.94496"
y="545.79144"
width="291.11197"
height="295.74161"
id="rect1130-3" />
<filter
style="color-interpolation-filters:sRGB"
inkscape:label="Roughen"
id="filter1273-6"
x="0"
y="0"
width="1"
height="1">
<feTurbulence
type="fractalNoise"
numOctaves="5"
seed="145"
baseFrequency="0.001 10"
result="turbulence"
id="feTurbulence1269-7" />
<feDisplacementMap
in="SourceGraphic"
in2="turbulence"
scale="1.68439"
yChannelSelector="G"
xChannelSelector="R"
id="feDisplacementMap1271-5" />
</filter>
</defs>
<g
inkscape:label="Layer 1"
inkscape:groupmode="layer"
id="layer1"
style="display:inline"
transform="translate(-38.320595,-110.90324)">
<circle
style="display:inline;fill:#663399;fill-opacity:1;stroke-width:0.264583"
id="path1074"
cx="103.58279"
cy="176.16544"
r="65.262192" />
</g>
<g
inkscape:groupmode="layer"
id="layer2"
inkscape:label="Layer 2"
transform="translate(-38.320595,-110.90324)">
<circle
style="display:inline;fill:#0f0617;fill-opacity:1;stroke-width:0.224394;stroke-dasharray:none"
id="path1074-5"
cx="103.58279"
cy="176.16544"
r="55.262001" />
</g>
<g
inkscape:groupmode="layer"
id="layer3"
inkscape:label="Layer 3"
transform="translate(-38.320595,-110.90324)">
<g
id="g2829"
transform="matrix(0.88602282,0,0,0.87606946,13.533885,21.962211)">
<text
xml:space="preserve"
transform="matrix(2.0837961,0,0,2.645293,-442.06366,-1321.3309)"
id="text1128-3"
style="font-style:normal;font-weight:normal;font-size:40px;line-height:1.25;font-family:sans-serif;white-space:pre;shape-inside:url(#rect1130-3);display:inline;fill:#482464;fill-opacity:1;stroke:none;stroke-width:1.00008;stroke-dasharray:none;filter:url(#filter1273-6)"><tspan
x="238.94531"
y="581.18164"
id="tspan2868">fK</tspan></text>
<text
xml:space="preserve"
transform="matrix(2.0837961,0,0,2.645293,-438.16349,-1321.0342)"
id="text1128"
style="font-style:normal;font-weight:normal;font-size:40px;line-height:1.25;font-family:sans-serif;white-space:pre;shape-inside:url(#rect1130);fill:#ffffff;fill-opacity:1;stroke:none;filter:url(#filter1273)"><tspan
x="238.94531"
y="581.18164"
id="tspan2870">fK</tspan></text>
</g>
</g>
</svg>

After

Width:  |  Height:  |  Size: 4.5 KiB

View File

@ -52,7 +52,7 @@ impl Users {
.await
.query(
format!(
"select id, username, host, display_name, password_hash from users where {}",
"select id, username, host, display_name, password_hash, email from users where {}",
where_clause
)
.as_str(),

View File

@ -1,20 +0,0 @@
use warp::hyper::StatusCode;
pub(crate) fn html_with_status(body: String, status: StatusCode) -> warp::http::Response<String> {
warp::http::Response::builder()
.header("Content-Type", "text/html; charset=utf-8")
.status(status)
.body(body)
.expect("failed marshalling html response")
}
pub(crate) fn html(body: String) -> warp::http::Response<String> {
html_with_status(body, StatusCode::OK)
}
// pub(crate) fn html(body: String) -> Result<warp::http::Response<String>, warp::http::Error> {
// warp::http::Response::builder()
// .header("Content-Type", "text/html; charset=utf-8")
// .status(StatusCode::OK)
// .body(body)
// }

View File

@ -1,5 +1,4 @@
mod database;
mod model;
mod sec;
mod servek;
mod svc;

View File

@ -1 +0,0 @@

View File

@ -4,52 +4,114 @@ use axum::{
body::Full,
extract::Path,
handler::Handler,
http::{header, StatusCode},
response::{self, Html, IntoResponse, Redirect, Response},
http::{header, HeaderValue, StatusCode},
response::{self, Html, IntoResponse, Response},
routing, Extension, Form, Json, Router,
};
use warp::{http::HeaderValue, hyper::Uri, path::Tail, Filter, Rejection, Reply};
use mime_guess::mime;
use tower_cookies::{Cookie, Cookies};
use crate::svc::auth::AuthError;
use crate::svc::{
auth::{AuthError, Claims},
profiles,
};
use super::{
servek::{Server, ServerError},
CreateProfileRequest, LoginRequest, Notification,
CreateProfileRequest, LoginRequest, NavType, Notification, Redirect, WithNav,
};
use rust_embed::RustEmbed;
const AUTH_COOKIE_NAME: &str = "flabk_token";
#[derive(RustEmbed)]
#[folder = "static"]
struct StaticData;
impl Server {
async fn index() -> impl IntoResponse {
(
StatusCode::OK,
response::Html(include_str!("../../templates/html/index.html")),
)
}
pub(super) fn register_html(&self, router: &Router) -> Router {
router
.clone()
.route("/favicon.svg", routing::get(Self::favicon))
.route("/", routing::get(Self::index))
.route("/login", routing::get(Self::login_page))
.route("/login", routing::get(Self::login_page).post(Self::login))
.route("/logout", routing::get(Self::logout))
.route(
"/signup",
routing::get(Self::signup_page).post(Self::create_user),
)
.route("/@/:username", routing::get(Self::profile))
.route("/static/*file", routing::get(Self::static_handler))
.fallback(routing::get(Self::handler_404))
}
async fn handler_404() -> impl IntoResponse {
fn from_cookie(&self, cookie: Option<Cookie>) -> Result<WithNav<Option<Claims>>, ServerError> {
if let Some(cookie) = cookie {
let claims = self.auth.get_claims(cookie.value().to_owned())?;
Ok(WithNav::new(Some(claims.clone()), claims.into()))
} else {
Ok(WithNav {
nav_type: NavType::LoggedOut,
obj: None,
})
}
}
async fn index(
Extension(srv): Extension<Server>,
cookies: Cookies,
) -> Result<impl IntoResponse, ServerError> {
let user = srv.from_cookie(cookies.get(AUTH_COOKIE_NAME))?;
Ok((
StatusCode::OK,
response::Html(srv.hb.render("index", &user)?),
))
}
async fn favicon() -> impl IntoResponse {
(
StatusCode::OK,
response::Html(include_str!("../../templates/html/404.html")),
(
[(
header::CONTENT_TYPE,
HeaderValue::from_static(mime::IMAGE_SVG.as_ref()),
)],
axum::body::boxed(Full::from(
include_bytes!("../../flabk_icon_placeholder.svg").as_ref(),
)),
),
)
}
async fn handler_404(
Extension(srv): Extension<Server>,
cookies: Cookies,
) -> Result<impl IntoResponse, ServerError> {
Ok((
StatusCode::OK,
response::Html(
srv.hb
.render("404", &srv.from_cookie(cookies.get(AUTH_COOKIE_NAME))?)?,
),
))
}
async fn logout(
Extension(srv): Extension<Server>,
cookies: Cookies,
) -> Result<impl IntoResponse, ServerError> {
cookies.remove(Cookie::new(AUTH_COOKIE_NAME, ""));
Ok((
StatusCode::OK,
response::Html(srv.hb.render(
"redirect",
&Redirect {
location: "/".to_owned(),
},
)?),
))
}
fn login_page_with(
&self,
tag_name: String,
@ -73,68 +135,54 @@ impl Server {
))
}
// async fn login(
// Extension(srv): Extension<Server>,
// Form(login): Form<LoginRequest>,
// ) -> Result<impl IntoResponse, ServerError> {
// if login.username == "" || login.password == "" {
// return srv.login_page_with(
// "error-partial".to_owned(),
// "credentials required".to_owned(),
// );
// }
// let token = srv.auth.login(login.username, login.password).await?;
// }
async fn login(
cookies: Cookies,
Extension(srv): Extension<Server>,
Form(login): Form<LoginRequest>,
) -> Result<impl IntoResponse, ServerError> {
if login.username == "" || login.password == "" {
return Ok((
StatusCode::BAD_REQUEST,
srv.login_page_with(
"error-partial".to_owned(),
"credentials required".to_owned(),
)?,
));
}
let token = srv.auth.login(login.username, login.password).await?;
// async fn login(
// srv: Server,
// Form(body): Form<HashMap<String, String>>,
// ) -> Result<response::Html<String>, ServerError> {
// let user = body
// .get("username")
// .ok_or(ServerError::BadRequest("no username provided".to_owned()))?;
// let pass = body
// .get("password")
// .ok_or(ServerError::BadRequest("no password provided".to_owned()))?;
if cookies.get(AUTH_COOKIE_NAME).is_some() {
cookies.remove(Cookie::new(AUTH_COOKIE_NAME, ""));
}
cookies.add(Cookie::new(AUTH_COOKIE_NAME, token));
// let token = srv
// .auth
// .login(user.clone(), pass.clone())
// .await
// .map(|html| response::Html(html));
// if let Err(e) = &token {
// if let AuthError::InvalidCredentials = e {
// return srv.login_with_error("invalid credentials".to_owned());
// }
// }
// Ok(token?)
// }
fn with_server(
srv: Server,
) -> impl Filter<Extract = (Server,), Error = std::convert::Infallible> + Clone {
warp::any().map(move || srv.clone())
Ok((
StatusCode::OK,
response::Html(srv.hb.render(
"redirect",
&Redirect {
location: "/".to_owned(),
},
)?),
))
}
// fn profile(&self) -> impl Filter<Extract = impl Reply, Error = Rejection> + Clone {
// warp::get().and(
// warp::path!("@" / String)
// .and(Self::with_server(self.clone()))
// .and_then(|username: String, srv: Server| async move {
// srv.hb
// .render(
// "profile",
// &serde_json::json!(srv
// .profiler
// .profile(username)
// .await
// .map_err(|e| ServerError::from(e))?),
// )
// .map(|html| warp::reply::html(html))
// .map_err(|e| ServerError::from(e).rejection())
// }),
// )
// }
async fn profile(
cookies: Cookies,
Extension(srv): Extension<Server>,
Path(username): Path<String>,
) -> Result<impl IntoResponse, ServerError> {
Ok((
StatusCode::OK,
response::Html(srv.hb.render(
"profile",
&WithNav::new(
srv.profiler.profile(username).await?,
srv.from_cookie(cookies.get(AUTH_COOKIE_NAME))?.nav_type,
),
)?),
))
}
async fn create_user(
Extension(srv): Extension<Server>,

View File

@ -1,4 +1,11 @@
use axum::response::{Html, IntoResponse};
use serde::{Deserialize, Serialize};
use tower_cookies::{Cookie, Cookies};
use crate::svc::{
auth::{Auth, AuthError, Claims},
profiles::User,
};
mod html;
pub mod servek;
@ -22,7 +29,59 @@ pub struct CreateProfileRequest {
pub email: String,
}
// pub enum HtmlOrRedirect {
// Html(Html<String>),
// Redirect(()),
// }
#[derive(Debug, Clone, Serialize)]
pub struct Login {
pub token: String,
pub struct Redirect {
pub location: String,
}
#[derive(Debug, Clone, Serialize)]
pub enum NavType {
LoggedIn,
LoggedOut,
}
impl From<Result<Claims, AuthError>> for NavType {
fn from(claims: Result<Claims, AuthError>) -> Self {
if claims.map(|c| c.expired()).unwrap_or(true) {
NavType::LoggedOut
} else {
NavType::LoggedIn
}
}
}
impl From<Claims> for NavType {
fn from(c: Claims) -> Self {
if c.expired() {
NavType::LoggedOut
} else {
NavType::LoggedIn
}
}
}
#[derive(Debug, Clone, Serialize)]
pub struct WithNav<T> {
pub nav_type: NavType,
pub obj: T,
}
impl<T> WithNav<T> {
pub fn new(obj: T, nav_type: NavType) -> WithNav<T> {
WithNav { nav_type, obj }
}
}
impl<T> Into<serde_json::Value> for WithNav<T>
where
T: Serialize,
{
fn into(self) -> serde_json::Value {
serde_json::json!(self)
}
}

View File

@ -2,23 +2,16 @@ use core::panic;
use std::{convert::Infallible, fmt::Display, net::SocketAddr};
use axum::{
http::uri::InvalidUri,
http::{uri::InvalidUri, StatusCode},
response::{self, IntoResponse, Response},
routing, Extension, Router,
};
use handlebars::{Handlebars, RenderError};
use warp::{
hyper::StatusCode,
reject::{MethodNotAllowed, Reject},
Filter, Rejection, Reply,
};
use tower_cookies::CookieManagerLayer;
use crate::{
model,
svc::{
auth::{Auth, AuthError},
profiles::{Profiler, UserError},
},
use crate::svc::{
auth::{Auth, AuthError},
profiles::{Profiler, UserError},
};
#[derive(Clone)]
@ -37,10 +30,29 @@ impl Server {
.expect("login template");
hb.register_template_string("signup", include_str!("../../templates/html/signup.html"))
.expect("login template");
hb.register_template_string(
"redirect",
include_str!("../../templates/html/html-redirect.html"),
)
.expect("redirect template");
hb.register_template_string("error-partial", r#"<h2 class="error">{{message}}</h2>"#)
.expect("error-partial");
hb.register_template_string("success-partial", r#"<h2 class="success">{{message}}</h2>"#)
.expect("success-partial");
hb.register_template_string("index", include_str!("../../templates/html/index.html"))
.expect("index");
hb.register_template_string("404", include_str!("../../templates/html/404.html"))
.expect("404");
hb.register_partial(
"LoggedOut",
include_str!("../../templates/html/nav-loggedout.html"),
)
.expect("LoggedOut");
hb.register_partial(
"LoggedIn",
include_str!("../../templates/html/nav-loggedin.html"),
)
.expect("LoggedIn");
Self { hb, profiler, auth }
}
@ -48,7 +60,8 @@ impl Server {
let router = Router::new();
let router = self
.register_html(&router)
.layer(Extension::<Server>(self.clone()));
.layer(Extension::<Server>(self.clone()))
.layer(CookieManagerLayer::new());
let addr = SocketAddr::from(([127, 0, 0, 1], port));
println!("listening on {}", addr);
@ -69,8 +82,6 @@ pub(super) enum ServerError {
BadRequest(String),
}
impl Reject for ServerError {}
impl From<RenderError> for ServerError {
fn from(r: RenderError) -> Self {
Self::Internal(r.to_string())
@ -108,7 +119,11 @@ impl IntoResponse for ServerError {
fn into_response(self) -> axum::response::Response {
match self {
ServerError::Internal(err) => (StatusCode::INTERNAL_SERVER_ERROR, err).into_response(),
ServerError::NotFound => (StatusCode::NOT_FOUND, "").into_response(),
ServerError::NotFound => (
StatusCode::NOT_FOUND,
response::Html(include_str!("../../templates/html/404.html")),
)
.into_response(),
ServerError::BadRequest(err) => (StatusCode::BAD_REQUEST, err).into_response(),
}
}

View File

@ -1,7 +1,8 @@
use std::time::SystemTime;
use jsonwebtoken::{EncodingKey, Header};
use jsonwebtoken::{Algorithm, DecodingKey, EncodingKey, Header, TokenData, Validation};
use serde::{Deserialize, Serialize};
use tower_cookies::Cookie;
use crate::{
database::{
@ -47,18 +48,38 @@ impl Auth {
Ok(jsonwebtoken::encode(
&Header::default(),
&Claims::from(user),
&EncodingKey::from_secret("secret".as_ref()),
&EncodingKey::from_secret(self.secret.as_ref()),
)?)
}
pub fn get_claims(&self, token: String) -> Result<Claims, AuthError> {
Ok(jsonwebtoken::decode::<Claims>(
token.as_str(),
&DecodingKey::from_secret(self.secret.as_ref()),
&Validation::new(Algorithm::HS256),
)?
.claims)
}
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct Claims {
pub sub: String,
pub username: String,
pub exp: u64,
pub iat: u64,
}
impl Claims {
pub fn expired(&self) -> bool {
SystemTime::now()
.duration_since(SystemTime::UNIX_EPOCH)
.unwrap()
.as_secs()
>= self.exp
}
}
impl From<users::User> for Claims {
fn from(u: users::User) -> Self {
let now = SystemTime::now()
@ -67,6 +88,7 @@ impl From<users::User> for Claims {
.as_secs();
Claims {
sub: u.id,
username: u.username,
exp: now + SECS_JWT_EXPIRE,
iat: now,
}

View File

@ -1,5 +1,4 @@
use serde::Serialize;
use warp::{reject::Reject, Rejection};
use crate::{
database::{
@ -95,5 +94,3 @@ impl ToString for UserError {
}
}
}
impl Reject for UserError {}

View File

@ -3,10 +3,26 @@ body {
color: rebeccapurple;
}
p,
h1,
h2,
label {
font-size: 160%;
}
h1 {
text-align: center;
}
/* .big {
font-size: 200%;
} */
.big>input {
font-size: 180%;
margin: 5%;
}
input {
background-color: black;
@ -14,10 +30,6 @@ input {
border-color: rebeccapurple;
}
form>div {
width: 80%;
}
.error {
color: rgba(255, 0, 0, 0.7);
font-weight: bold;
@ -33,7 +45,7 @@ form>div {
}
#central {
width: 30%;
width: 40%;
border: 5px solid rebeccapurple;
height: 30vw;
padding: 10px;
@ -43,10 +55,35 @@ form>div {
justify-content: center;
align-items: center;
background-color: rgba(13, 6, 19, 0.4);
font-size: large;
font-weight: bold;
}
a {
color: rebeccapurple;
}
nav {
/* background-color: #333; */
margin: 0;
overflow: hidden;
}
nav ul {
margin: 0;
padding: 0;
}
nav ul li {
display: inline-block;
list-style-type: none;
}
nav>ul>li>a {
/* color: #aaa; */
/* background-color:#FF0; */
display: block;
line-height: 2em;
padding: 0.5em 0.5em;
text-decoration: none;
}

View File

@ -4,9 +4,11 @@
<head>
<title>flabk - not found</title>
<link rel="stylesheet" href="/static/style/main.css">
<link rel="icon" type="image/svg+xml" href="/favicon.svg">
</head>
<body>
{{> (lookup this "nav_type") }}
<h1>404 not found</h1>
<br />
<h1><a href="/">return</a></h1>

View File

@ -0,0 +1,18 @@
<!DOCTYPE html>
<html>
<head>
<title>redirecting</title>
<style>
body {
background-color: black;
}
</style>
<meta http-equiv="refresh" content="time; URL={{location}}" />
</head>
<body>
</body>
</html>

View File

@ -4,12 +4,12 @@
<head>
<title>flabk</title>
<link rel="stylesheet" href="/static/style/main.css">
<link rel="icon" type="image/svg+xml" href="/favicon.svg">
</head>
<body>
<h1>hi</h1>
<h1><a href="/login">login</a></h1>
<h1><a href="/signup">sign up</a></h1>
{{> (lookup this "nav_type") }}
<h1>hi {{obj.username}}</h1>
</body>
</html>

View File

@ -4,14 +4,16 @@
<head>
<title>flabk - login</title>
<link rel="stylesheet" href="/static/style/main.css">
<link rel="icon" type="image/svg+xml" href="/favicon.svg">
</head>
<body>
{{> LoggedOut }}
<h1>login</h1>
<div id="central">
<p>login form</p>
{{> (lookup this "tag_name")}}
<form id="login" method="post" action="/login">
<form class="big" id="login" method="post" action="/login">
<input type="text" name="username">
<input type="password" name="password">
<input type="submit" value="Submit" hidden>

View File

@ -0,0 +1,13 @@
<nav>
<ul>
<li>
<a href="/">home</a>
</li>
<li>
<a href="/@/{{obj.username}}">me</a>
</li>
<li>
<a href="/logout">log out</a>
</li>
</ul>
</nav>

View File

@ -0,0 +1,13 @@
<nav>
<ul>
<li>
<a href="/">home</a>
</li>
<li>
<a href="/login">login</a>
</li>
<li>
<a href="/signup">sign up</a>
</li>
</ul>
</nav>

View File

@ -1,15 +0,0 @@
<!DOCTYPE html>
<html>
<head>
<title>logging in</title>
</head>
<body>
<script>
window.localStorage.setItem('token', '{{token}}');
document.location.href = "/";
</script>
</body>
</html>

View File

@ -4,10 +4,12 @@
<head>
<title>@{{username}}</title>
<link rel="stylesheet" href="/static/style/main.css">
<link rel="icon" type="image/svg+xml" href="/favicon.svg">
</head>
<body>
<h1>hi {{username}}, your id is {{id}}</h1>
{{> (lookup this "nav_type") }}
<h1>hi {{obj.username}}, your id is {{obj.id}}</h1>
</body>
</html>

View File

@ -4,28 +4,21 @@
<head>
<title>flabk - signup</title>
<link rel="stylesheet" href="/static/style/main.css">
<link rel="icon" type="image/svg+xml" href="/favicon.svg">
</head>
<body>
{{> LoggedOut }}
<h1>signup</h1>
<div id="central">
<p>signup form</p>
{{> (lookup this "tag_name")}}
<form id="signup" method="post" action="/signup">
<div>
<label for="username">username</label>
<input type="text" name="username">
</div>
<br />
<div>
<label for="email">email</label>
<input type="email" name="email">
</div>
<br />
<div>
<label for="password">password</label>
<input type="password" name="password">
</div>
<form class="big" id="signup" method="post" action="/signup">
<input type="text" name="username" placeholder="username">
<br>
<input type="email" name="email" placeholder="email">
<br>
<input type="password" name="password" placeholder="password">
<input type="submit" value="Submit" hidden>
</form>
</div>