mirror of
https://github.com/lennart-k/rustical.git
synced 2025-12-13 22:52:22 +00:00
Add authentication with session cookie
This commit is contained in:
@@ -16,4 +16,4 @@ thiserror = { workspace = true }
|
|||||||
tokio = { workspace = true }
|
tokio = { workspace = true }
|
||||||
actix-web = { workspace = true }
|
actix-web = { workspace = true }
|
||||||
rustical_store = { workspace = true }
|
rustical_store = { workspace = true }
|
||||||
actix-files = "0.6.6"
|
actix-files = "0.6"
|
||||||
|
|||||||
@@ -1,2 +1,2 @@
|
|||||||
[general]
|
[general]
|
||||||
dirs = ["frontend/dist/src/templates"]
|
dirs = ["frontend/dist/templates"]
|
||||||
|
|||||||
@@ -6,6 +6,11 @@
|
|||||||
<meta name="viewport" content="width=device-width, initial-scale=1">
|
<meta name="viewport" content="width=device-width, initial-scale=1">
|
||||||
<title>{% block title %}RustiCal{% endblock %}</title>
|
<title>{% block title %}RustiCal{% endblock %}</title>
|
||||||
<script type="module" src="htmx.org"></script>
|
<script type="module" src="htmx.org"></script>
|
||||||
|
<style>
|
||||||
|
* {
|
||||||
|
box-sizing: border-box;
|
||||||
|
}
|
||||||
|
</style>
|
||||||
{% block imports %}{% endblock %}
|
{% block imports %}{% endblock %}
|
||||||
</head>
|
</head>
|
||||||
|
|
||||||
|
|||||||
@@ -0,0 +1,9 @@
|
|||||||
|
{% extends "layouts/default.html" %}
|
||||||
|
|
||||||
|
{% block imports %}
|
||||||
|
{% endblock %}
|
||||||
|
|
||||||
|
{% block content %}
|
||||||
|
<h1>Test</h1>
|
||||||
|
<a href="/frontend/user/{{ calendar.principal }}">Back</a>
|
||||||
|
{% endblock %}
|
||||||
@@ -1,20 +1,21 @@
|
|||||||
{% extends "layouts/default.html" %}
|
{% extends "layouts/default.html" %}
|
||||||
|
|
||||||
{% block imports %}
|
{% block imports %}
|
||||||
|
{% endblock %}
|
||||||
|
|
||||||
|
{% block content %}
|
||||||
<style>
|
<style>
|
||||||
li {
|
li {
|
||||||
list-style: none;
|
list-style: none;
|
||||||
display: block;
|
display: block;
|
||||||
margin: 12px;
|
margin: 12px;
|
||||||
height: 80px;
|
min-height: 80px;
|
||||||
background: #EEE;
|
background: #EEE;
|
||||||
padding: 8px;
|
padding: 8px;
|
||||||
|
border-radius: 12px;
|
||||||
}
|
}
|
||||||
</style>
|
</style>
|
||||||
{% endblock %}
|
<h2>Welcome {{ user_id }}!</h2>
|
||||||
|
|
||||||
{% block content %}
|
|
||||||
<h2>Welcome {{ owner }}!</h2>
|
|
||||||
<ul>
|
<ul>
|
||||||
{% for calendar in calendars %}
|
{% for calendar in calendars %}
|
||||||
<li>
|
<li>
|
||||||
@@ -23,9 +24,12 @@ li {
|
|||||||
{% else %}
|
{% else %}
|
||||||
{{ calendar.id }}
|
{{ calendar.id }}
|
||||||
{% endif %}
|
{% endif %}
|
||||||
<p>
|
{% let color = calendar.color.to_owned().unwrap_or("red".to_owned()) %}
|
||||||
|
<p style="color: {{ color }}">
|
||||||
{% if let Some(description) = calendar.description %}{{ description }}{% endif %}
|
{% if let Some(description) = calendar.description %}{{ description }}{% endif %}
|
||||||
</p>
|
</p>
|
||||||
|
<!-- <a href="{{ calendar.id}}">Test</a> -->
|
||||||
|
<a href="/frontend/user/{{ user_id }}/{{ calendar.id}}">Test</a>
|
||||||
</li>
|
</li>
|
||||||
{% endfor %}
|
{% endfor %}
|
||||||
</ul>
|
</ul>
|
||||||
|
|||||||
@@ -3,19 +3,9 @@ import { globSync } from 'glob'
|
|||||||
import path from 'node:path'
|
import path from 'node:path'
|
||||||
import { fileURLToPath } from 'node:url'
|
import { fileURLToPath } from 'node:url'
|
||||||
|
|
||||||
console.log(
|
|
||||||
Object.fromEntries(globSync('src/templates/**/*.html').map(file => [
|
|
||||||
path.relative(
|
|
||||||
'src',
|
|
||||||
file.slice(0, file.length - path.extname(file).length)
|
|
||||||
),
|
|
||||||
// This expands the relative paths to absolute paths, so e.g.
|
|
||||||
// src/nested/foo becomes /project/src/nested/foo.js
|
|
||||||
fileURLToPath(new URL(file, import.meta.url))
|
|
||||||
])),
|
|
||||||
)
|
|
||||||
|
|
||||||
export default defineConfig({
|
export default defineConfig({
|
||||||
|
root: "src",
|
||||||
|
base: "/frontend",
|
||||||
build: {
|
build: {
|
||||||
modulePreload: {
|
modulePreload: {
|
||||||
polyfill: false
|
polyfill: false
|
||||||
|
|||||||
@@ -8,7 +8,7 @@ use actix_web::{
|
|||||||
use askama::Template;
|
use askama::Template;
|
||||||
use routes::login::{route_get_login, route_post_login};
|
use routes::login::{route_get_login, route_post_login};
|
||||||
use rustical_store::{
|
use rustical_store::{
|
||||||
auth::{AuthenticationMiddleware, AuthenticationProvider},
|
auth::{AuthenticationMiddleware, AuthenticationProvider, User},
|
||||||
model::Calendar,
|
model::Calendar,
|
||||||
CalendarStore,
|
CalendarStore,
|
||||||
};
|
};
|
||||||
@@ -23,19 +23,39 @@ pub use config::FrontendConfig;
|
|||||||
#[derive(Template)]
|
#[derive(Template)]
|
||||||
#[template(path = "pages/user.html")]
|
#[template(path = "pages/user.html")]
|
||||||
struct UserPage {
|
struct UserPage {
|
||||||
pub owner: String,
|
pub user_id: String,
|
||||||
pub calendars: Vec<Calendar>,
|
pub calendars: Vec<Calendar>,
|
||||||
}
|
}
|
||||||
|
|
||||||
async fn route_user<C: CalendarStore + ?Sized>(
|
async fn route_user<C: CalendarStore + ?Sized>(
|
||||||
path: Path<String>,
|
path: Path<String>,
|
||||||
store: Data<RwLock<C>>,
|
store: Data<RwLock<C>>,
|
||||||
|
user: User,
|
||||||
) -> impl Responder {
|
) -> impl Responder {
|
||||||
let store = store.read().await;
|
let store = store.read().await;
|
||||||
let owner = path.into_inner();
|
let user_id = path.into_inner();
|
||||||
UserPage {
|
UserPage {
|
||||||
|
calendars: store.get_calendars(&user.id).await.unwrap(),
|
||||||
|
user_id: user.id,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Template)]
|
||||||
|
#[template(path = "pages/calendar.html")]
|
||||||
|
struct CalendarPage {
|
||||||
|
owner: String,
|
||||||
|
calendar: Calendar,
|
||||||
|
}
|
||||||
|
|
||||||
|
async fn route_calendar<C: CalendarStore + ?Sized>(
|
||||||
|
path: Path<(String, String)>,
|
||||||
|
store: Data<RwLock<C>>,
|
||||||
|
) -> impl Responder {
|
||||||
|
let store = store.read().await;
|
||||||
|
let (owner, cid) = path.into_inner();
|
||||||
|
CalendarPage {
|
||||||
owner: owner.to_owned(),
|
owner: owner.to_owned(),
|
||||||
calendars: store.get_calendars(&owner).await.unwrap(),
|
calendar: store.get_calendar(&owner, &cid).await.unwrap(),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -63,6 +83,10 @@ pub fn configure_frontend<AP: AuthenticationProvider, C: CalendarStore + ?Sized>
|
|||||||
.service(
|
.service(
|
||||||
web::resource("/user/{user}").route(web::method(Method::GET).to(route_user::<C>)),
|
web::resource("/user/{user}").route(web::method(Method::GET).to(route_user::<C>)),
|
||||||
)
|
)
|
||||||
|
.service(
|
||||||
|
web::resource("/user/{user}/{calendar}")
|
||||||
|
.route(web::method(Method::GET).to(route_calendar::<C>)),
|
||||||
|
)
|
||||||
.service(
|
.service(
|
||||||
web::resource("/login")
|
web::resource("/login")
|
||||||
.route(web::method(Method::GET).to(route_get_login))
|
.route(web::method(Method::GET).to(route_get_login))
|
||||||
|
|||||||
@@ -23,6 +23,7 @@ rstest_reuse = { workspace = true }
|
|||||||
thiserror = { workspace = true }
|
thiserror = { workspace = true }
|
||||||
password-auth = { workspace = true }
|
password-auth = { workspace = true }
|
||||||
actix-web = { workspace = true }
|
actix-web = { workspace = true }
|
||||||
|
actix-session = { workspace = true }
|
||||||
actix-web-httpauth = { workspace = true }
|
actix-web-httpauth = { workspace = true }
|
||||||
tracing = { workspace = true }
|
tracing = { workspace = true }
|
||||||
pbkdf2 = { workspace = true }
|
pbkdf2 = { workspace = true }
|
||||||
|
|||||||
@@ -1,8 +1,9 @@
|
|||||||
use super::AuthenticationProvider;
|
use super::{AuthenticationProvider, User};
|
||||||
|
use actix_session::Session;
|
||||||
use actix_web::{
|
use actix_web::{
|
||||||
dev::{forward_ready, Service, ServiceRequest, ServiceResponse, Transform},
|
dev::{forward_ready, Service, ServiceRequest, ServiceResponse, Transform},
|
||||||
http::header::Header,
|
http::header::Header,
|
||||||
HttpMessage,
|
FromRequest, HttpMessage,
|
||||||
};
|
};
|
||||||
use actix_web_httpauth::headers::authorization::{Authorization, Basic};
|
use actix_web_httpauth::headers::authorization::{Authorization, Basic};
|
||||||
use std::{
|
use std::{
|
||||||
@@ -77,6 +78,20 @@ where
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Extract user from session cookie
|
||||||
|
if let Ok(session) = Session::extract(req.request()).await {
|
||||||
|
println!("There's a session!");
|
||||||
|
match session.get::<User>("user") {
|
||||||
|
Ok(Some(user)) => {
|
||||||
|
req.extensions_mut().insert(user);
|
||||||
|
}
|
||||||
|
Ok(None) => {}
|
||||||
|
Err(err) => {
|
||||||
|
dbg!(err);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
service.call(req).await
|
service.call(req).await
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user