static dir renamed and cookie auth middleware

This commit is contained in:
realaravinth
2021-05-01 11:28:39 +05:30
parent c96f890236
commit 7058af84d6
72 changed files with 270 additions and 57 deletions

View File

@@ -252,7 +252,7 @@ pub async fn signout(id: Identity) -> impl Responder {
if let Some(_) = id.identity() {
id.forget();
}
HttpResponse::TemporaryRedirect()
HttpResponse::Found()
.set_header(header::LOCATION, "/login")
.body("")
}

View File

@@ -130,7 +130,7 @@ async fn auth_works() {
.to_request(),
)
.await;
assert_eq!(signout_resp.status(), StatusCode::TEMPORARY_REDIRECT);
assert_eq!(signout_resp.status(), StatusCode::FOUND);
}
#[actix_rt::test]

View File

@@ -1 +1 @@
{"map":{"./static/img/svg/github.svg":"./prod/img/svg/github.FA9EB1C66F548EC2C7598B94BA6A17275E1EA383D42B6C83351A2388C773E621.svg","./static/img/svg/globe.svg":"./prod/img/svg/globe.44C2A069EBD637663E938ECE7B8E4EC2A8BDE049A8A044EC68D9CB69AE8C592E.svg","./static/img/svg/message-square.svg":"./prod/img/svg/message-square.E246A6B2AAEFCE8A62B9BDD2D155D3B4923C3E48325EAEF099D509A2D7BB4DD1.svg","./static/img/svg/shield.svg":"./prod/img/svg/shield.13AFE15DCB4882B4A940CFDC3E2088A733CD4E6F97F25B211D87C7C9D6DBA2B6.svg","./static/img/svg/filter.svg":"./prod/img/svg/filter.6D5FBD96BA2E2020663AAC4994A991295917D73F3592C07EE103647B655A2275.svg","./static/img/svg/moon.svg":"./prod/img/svg/moon.1E151D68949CA3B2DC7DE34BC25B7586E4175AC3BA7F56DDBB34227334EF7155.svg","./static/img/svg/toggle-left.svg":"./prod/img/svg/toggle-left.E421950C5922E84015F0A86F272AE5637A2ED96E267D2C962543F5994E5D1172.svg","./static/img/svg/menu.svg":"./prod/img/svg/menu.A2C4DD00686F5D23F78885AC4CE3E075FCA78DFBDEA70407667FBBD9801B7A75.svg","./static/img/icon.png":"./prod/img/icon.CC75A040D5F432E5DC9043D10B94BF1FC3BAE1D02A8C2030F655E642EAD4A32C.png","./static/img/svg/key.svg":"./prod/img/svg/key.F0AACBED8D0F7A279977392F92F4DA73C35E905AC73B3C83320D54856E627EEC.svg","./static/img/svg/help-circle.svg":"./prod/img/svg/help-circle.BE230ABD2E05EB05EF6C5B7D04D35A3A43637EF1E046DEF3D244425609B99F81.svg","./static/img/svg/file.svg":"./prod/img/svg/file.F9E376D9F78FFD918D8D592A8B2D97EAAC14E638B5A7AE3C58DDB075375D8E0E.svg","./static/img/icon-trans.png":"./prod/img/icon-trans.7920418313D84DCDB2491E02E52E4BEF374970C216E85BD721274EE51241ECD4.png","./static/img/svg/shield-off.svg":"./prod/img/svg/shield-off.85394A6AD92D550F8EBA72AAB095E078E7A0E3359DF81174532C8D1AF53B5876.svg","./static/img/svg/eye-off.svg":"./prod/img/svg/eye-off.939360B335D1D35B57C3E2070129D14ABB168E4AC137B5BE4F6F8BD450B712F5.svg","./static/img/svg/credit-card.svg":"./prod/img/svg/credit-card.DF612AFE367A7B31410F2F6CD3C7B515B0F1889C0107EA695D840DFFA492E07D.svg","./static/img/svg/settings.svg":"./prod/img/svg/settings.910C6241743C9C694141971BE8E1C4016A1A5BF203E4E9D676D4CE93BD518F4C.svg","./static/img/svg/user.svg":"./prod/img/svg/user.B164ECD2C4A09DC5189F1F252487E2AC6A33646BEA67AF9C528CDA61FE5E146F.svg","./static/img/svg/toggle-right.svg":"./prod/img/svg/toggle-right.15BF49887941593CE3FE09FA73E3CAF1F4B1E8ABCB42A23D85B4FCBC24FDF5AA.svg","./static/img/svg/eye.svg":"./prod/img/svg/eye.9DE4D24D3C9B055D02B94A8AD65E8C0C644852381FDD131A64448B6DA7859167.svg","./static/img/svg/tag.svg":"./prod/img/svg/tag.E0BC111B8E81BBFC62B6A9E7E4AC162B7085A6543D995B7A0030CB7632901BD4.svg","./static/bundle/main.css":"./prod/bundle/main.C7B0ACE647935B5E61BD692A0EB6AFF167CAB2F80483079378CF7A18D7FF9466.css","./static/img/svg/file-text.svg":"./prod/img/svg/file-text.CF57DF252051E7E81C240D36AF1DB8A9DDAF282F9A5E8C338408FE88A6545A02.svg","./static/bundle/main.js":"./prod/bundle/main.736EA02160A042CFB6310C65CB61D8F2578A457254FBDBD1F00009320D8BF903.js","./static/img/svg/bell.svg":"./prod/img/svg/bell.9DA292704EE9907EFDB870F4510C97336977CA27FBFAAD83CF46F8E22D3828F7.svg","./static/img/svg/home.svg":"./prod/img/svg/home.28C26C2D3E4013D24D755A589A80D8DD5C49DA5397032E3F09B76BC3A2C314ED.svg","./static/img/svg/log-out.svg":"./prod/img/svg/log-out.92AB4384FD41D9AFE4735C480361BB64789CD767B7DD0FF3C6F56287B3D4498E.svg"},"base_dir":"./prod"}
{"map":{"./static-assets/img/svg/filter.svg":"./static/img/svg/filter.6D5FBD96BA2E2020663AAC4994A991295917D73F3592C07EE103647B655A2275.svg","./static-assets/img/svg/home.svg":"./static/img/svg/home.28C26C2D3E4013D24D755A589A80D8DD5C49DA5397032E3F09B76BC3A2C314ED.svg","./static-assets/img/svg/shield.svg":"./static/img/svg/shield.13AFE15DCB4882B4A940CFDC3E2088A733CD4E6F97F25B211D87C7C9D6DBA2B6.svg","./static-assets/img/svg/eye.svg":"./static/img/svg/eye.9DE4D24D3C9B055D02B94A8AD65E8C0C644852381FDD131A64448B6DA7859167.svg","./static-assets/img/svg/settings.svg":"./static/img/svg/settings.910C6241743C9C694141971BE8E1C4016A1A5BF203E4E9D676D4CE93BD518F4C.svg","./static-assets/img/svg/message-square.svg":"./static/img/svg/message-square.E246A6B2AAEFCE8A62B9BDD2D155D3B4923C3E48325EAEF099D509A2D7BB4DD1.svg","./static-assets/img/svg/eye-off.svg":"./static/img/svg/eye-off.939360B335D1D35B57C3E2070129D14ABB168E4AC137B5BE4F6F8BD450B712F5.svg","./static-assets/img/svg/toggle-left.svg":"./static/img/svg/toggle-left.E421950C5922E84015F0A86F272AE5637A2ED96E267D2C962543F5994E5D1172.svg","./static-assets/img/svg/user.svg":"./static/img/svg/user.B164ECD2C4A09DC5189F1F252487E2AC6A33646BEA67AF9C528CDA61FE5E146F.svg","./static-assets/img/svg/globe.svg":"./static/img/svg/globe.44C2A069EBD637663E938ECE7B8E4EC2A8BDE049A8A044EC68D9CB69AE8C592E.svg","./static-assets/img/svg/shield-off.svg":"./static/img/svg/shield-off.85394A6AD92D550F8EBA72AAB095E078E7A0E3359DF81174532C8D1AF53B5876.svg","./static-assets/img/svg/tag.svg":"./static/img/svg/tag.E0BC111B8E81BBFC62B6A9E7E4AC162B7085A6543D995B7A0030CB7632901BD4.svg","./static-assets/img/svg/moon.svg":"./static/img/svg/moon.1E151D68949CA3B2DC7DE34BC25B7586E4175AC3BA7F56DDBB34227334EF7155.svg","./static-assets/img/svg/key.svg":"./static/img/svg/key.F0AACBED8D0F7A279977392F92F4DA73C35E905AC73B3C83320D54856E627EEC.svg","./static-assets/img/svg/credit-card.svg":"./static/img/svg/credit-card.DF612AFE367A7B31410F2F6CD3C7B515B0F1889C0107EA695D840DFFA492E07D.svg","./static-assets/img/svg/log-out.svg":"./static/img/svg/log-out.92AB4384FD41D9AFE4735C480361BB64789CD767B7DD0FF3C6F56287B3D4498E.svg","./static-assets/img/svg/bell.svg":"./static/img/svg/bell.9DA292704EE9907EFDB870F4510C97336977CA27FBFAAD83CF46F8E22D3828F7.svg","./static-assets/img/svg/github.svg":"./static/img/svg/github.FA9EB1C66F548EC2C7598B94BA6A17275E1EA383D42B6C83351A2388C773E621.svg","./static-assets/img/svg/menu.svg":"./static/img/svg/menu.A2C4DD00686F5D23F78885AC4CE3E075FCA78DFBDEA70407667FBBD9801B7A75.svg","./static-assets/img/icon.png":"./static/img/icon.CC75A040D5F432E5DC9043D10B94BF1FC3BAE1D02A8C2030F655E642EAD4A32C.png","./static-assets/img/svg/file.svg":"./static/img/svg/file.F9E376D9F78FFD918D8D592A8B2D97EAAC14E638B5A7AE3C58DDB075375D8E0E.svg","./static-assets/bundle/main.js":"./static/bundle/main.47250AD075BB60388779EF82D1C6A084AB82B69A9061D8A4DFCF1C18C07A0C4F.js","./static-assets/bundle/main.css":"./static/bundle/main.C7B0ACE647935B5E61BD692A0EB6AFF167CAB2F80483079378CF7A18D7FF9466.css","./static-assets/img/svg/file-text.svg":"./static/img/svg/file-text.CF57DF252051E7E81C240D36AF1DB8A9DDAF282F9A5E8C338408FE88A6545A02.svg","./static-assets/img/svg/help-circle.svg":"./static/img/svg/help-circle.BE230ABD2E05EB05EF6C5B7D04D35A3A43637EF1E046DEF3D244425609B99F81.svg","./static-assets/img/icon-trans.png":"./static/img/icon-trans.7920418313D84DCDB2491E02E52E4BEF374970C216E85BD721274EE51241ECD4.png","./static-assets/img/svg/toggle-right.svg":"./static/img/svg/toggle-right.15BF49887941593CE3FE09FA73E3CAF1F4B1E8ABCB42A23D85B4FCBC24FDF5AA.svg"},"base_dir":"./static"}

View File

@@ -18,10 +18,9 @@ use std::env;
use actix_identity::{CookieIdentityPolicy, IdentityService};
use actix_web::{
client::Client, error::InternalError, http::StatusCode, middleware, web::JsonConfig, App,
HttpServer,
client::Client, error::InternalError, http::StatusCode, middleware as actix_middleware,
web::JsonConfig, App, HttpServer,
};
use cache_buster::Files as FileMap;
use lazy_static::lazy_static;
use log::info;
@@ -35,19 +34,18 @@ mod templates;
#[cfg(test)]
#[macro_use]
mod tests;
mod middleware;
pub use data::Data;
pub use settings::Settings;
use static_assets::FileMap;
lazy_static! {
pub static ref SETTINGS: Settings = Settings::new().unwrap();
pub static ref S: String = env::var("S").unwrap();
pub static ref FILES: FileMap = {
let map = include_str!("cache_buster_data.json");
FileMap::new(&map)
};
pub static ref JS: &'static str = FILES.get("./static/bundle/main.js").unwrap();
pub static ref CSS: &'static str = FILES.get("./static/bundle/main.css").unwrap();
pub static ref FILES: FileMap = FileMap::new();
pub static ref JS: &'static str = FILES.get("./static-assets/bundle/main.js").unwrap();
pub static ref CSS: &'static str = FILES.get("./static-assets/bundle/main.css").unwrap();
}
pub static OPEN_API_DOC: &str = env!("OPEN_API_DOCS");
@@ -77,19 +75,19 @@ async fn main() -> std::io::Result<()> {
let client = Client::default();
App::new()
.wrap(middleware::Logger::default())
.wrap(actix_middleware::Logger::default())
.wrap(get_identity_service())
.wrap(middleware::Compress::default())
.wrap(actix_middleware::Compress::default())
.data(data.clone())
.data(client.clone())
.wrap(middleware::NormalizePath::new(
middleware::normalize::TrailingSlash::Trim,
.wrap(actix_middleware::NormalizePath::new(
actix_middleware::normalize::TrailingSlash::Trim,
))
.configure(v1::pow::services)
.configure(v1::services)
.configure(docs::services)
.configure(templates::services)
.configure(static_assets::services)
.configure(templates::services)
.app_data(get_json_err())
})
.bind(SETTINGS.server.get_ip())

126
src/middleware/auth.rs Normal file
View File

@@ -0,0 +1,126 @@
/*
* Copyright (C) 2021 Aravinth Manivannan <realaravinth@batsense.net>
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as
* published by the Free Software Foundation, either version 3 of the
* License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
#![allow(clippy::type_complexity)]
use std::task::{Context, Poll};
use actix_identity::Identity;
//use actix_identity::{CookieIdentityPolicy, IdentityService};
use actix_service::{Service, Transform};
use actix_web::dev::{ServiceRequest, ServiceResponse};
use actix_web::{http, Error, FromRequest, HttpResponse};
use futures::future::{ok, Either, Ready};
pub struct CheckLogin;
const LOGIN_ROUTE: &str = "/login";
impl<S, B> Transform<S> for CheckLogin
where
S: Service<Request = ServiceRequest, Response = ServiceResponse<B>, Error = Error>,
S::Future: 'static,
{
type Request = ServiceRequest;
type Response = ServiceResponse<B>;
type Error = Error;
type Transform = CheckLoginMiddleware<S>;
type InitError = ();
type Future = Ready<Result<Self::Transform, Self::InitError>>;
fn new_transform(&self, service: S) -> Self::Future {
ok(CheckLoginMiddleware { service })
}
}
//
//pub fn auto_login(req: &HttpRequest, pl: &mut dev::Payload) -> Option<()> {
// dbg!("login");
// if let Some(_) = Identity::from_request(req, pl)
// .into_inner()
// .map(|x| x.identity())
// .unwrap()
// {
// Some(())
// } else {
// None
// }
//}
//
//fn not_auth(path: &str) -> bool {
// let paths = ["/login", "/css", "/img", "/js"];
// paths.iter().any(|x| path.starts_with(x))
//}
pub struct CheckLoginMiddleware<S> {
service: S,
}
impl<S, B> Service for CheckLoginMiddleware<S>
where
S: Service<Request = ServiceRequest, Response = ServiceResponse<B>, Error = Error>,
S::Future: 'static,
{
type Request = ServiceRequest;
type Response = ServiceResponse<B>;
type Error = Error;
type Future = Either<S::Future, Ready<Result<Self::Response, Self::Error>>>;
fn poll_ready(&mut self, cx: &mut Context) -> Poll<Result<(), Self::Error>> {
self.service.poll_ready(cx)
}
fn call(&mut self, req: ServiceRequest) -> Self::Future {
// if not_auth(req.path()) {
// return Either::Left(self.service.call(req));
// };
let (r, mut pl) = req.into_parts();
// TODO investigate when the bellow statement will
// return error
if let Ok(Some(_)) = Identity::from_request(&r, &mut pl)
.into_inner()
.map(|x| x.identity())
{
let req = ServiceRequest::from_parts(r, pl).ok().unwrap();
Either::Left(self.service.call(req))
// Some(())
} else {
let req = ServiceRequest::from_parts(r, pl).ok().unwrap();
Either::Right(ok(req.into_response(
HttpResponse::Found()
.header(http::header::LOCATION, LOGIN_ROUTE)
.finish()
.into_body(),
)))
//None
}
// let token = auto_login(&r, &mut pl);
// let req = ServiceRequest::from_parts(r, pl).ok().unwrap();
// if token.is_some() {
// Either::Left(self.service.call(req))
// } else {
// Either::Right(ok(req.into_response(
// HttpResponse::Found()
// .header(http::header::LOCATION, LOGIN_ROUTE)
// .finish()
// .into_body(),
// )))
// }
}
}

18
src/middleware/mod.rs Normal file
View File

@@ -0,0 +1,18 @@
/*
* Copyright (C) 2021 Aravinth Manivannan <realaravinth@batsense.net>
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as
* published by the Free Software Foundation, either version 3 of the
* License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
pub mod auth;

View File

@@ -17,13 +17,14 @@
use actix_web::body::Body;
use actix_web::{get, web, HttpResponse, Responder};
use cache_buster::Files;
use mime_guess::from_path;
use rust_embed::RustEmbed;
use std::borrow::Cow;
#[derive(RustEmbed)]
#[folder = "prod/"]
#[folder = "static/"]
struct Asset;
pub fn handle_embedded_file(path: &str) -> HttpResponse {
@@ -41,7 +42,7 @@ pub fn handle_embedded_file(path: &str) -> HttpResponse {
}
}
#[get("/{_:.*}")]
#[get("/static/{_:.*}")]
async fn dist(path: web::Path<String>) -> impl Responder {
handle_embedded_file(&path.0)
}
@@ -50,6 +51,29 @@ pub fn services(cfg: &mut web::ServiceConfig) {
cfg.service(dist);
}
pub struct FileMap {
files: Files,
}
impl FileMap {
pub fn new() -> Self {
let map = include_str!("cache_buster_data.json");
let files = Files::new(&map);
Self { files }
}
pub fn get<'a>(&'a self, path: &'a str) -> Option<&'a str> {
// let file_path = self.files.get(path);
let file_path = self.files.get_full_path(path);
if file_path.is_some() {
let file_path = &file_path.unwrap()[1..];
return Some(file_path);
} else {
return None;
}
}
}
#[cfg(test)]
mod tests {
use actix_web::http::StatusCode;
@@ -69,4 +93,12 @@ mod tests {
.await;
assert_eq!(resp.status(), StatusCode::OK);
}
#[test]
fn filemap_works() {
let files = super::FileMap::new();
let css = files.get("./static-assets/bundle/main.css").unwrap();
println!("{}", css);
assert!(css.contains("/static/bundle/main"));
}
}

View File

@@ -20,13 +20,13 @@ use actix_web::web::ServiceConfig;
mod auth;
mod panel;
pub fn services(cfg: &mut ServiceConfig) {
cfg.service(auth::login::login);
cfg.service(auth::register::join);
pub use crate::middleware::auth::CheckLogin;
// panel
pub fn services(cfg: &mut ServiceConfig) {
cfg.service(panel::panel);
cfg.service(panel::sitekey::add_sitekey);
cfg.service(auth::login::login);
cfg.service(auth::register::join);
}
#[cfg(not(tarpaulin_include))]
@@ -39,18 +39,27 @@ mod tests {
use crate::*;
#[actix_rt::test]
async fn templates_work() {
async fn protected_pages_templates_work() {
let mut app = test::init_service(App::new().configure(services)).await;
let urls = vec!["/", "/join", "/login", "/sitekey/add"];
let urls = vec!["/", "/sitekey/add"];
for url in urls.iter() {
let resp =
test::call_service(&mut app, test::TestRequest::get().uri(url).to_request()).await;
if url == urls.get(0).unwrap() {
assert_eq!(resp.status(), StatusCode::TEMPORARY_REDIRECT);
} else {
assert_eq!(resp.status(), StatusCode::OK);
}
assert_eq!(resp.status(), StatusCode::FOUND);
}
}
#[actix_rt::test]
async fn public_pages_tempaltes_work() {
let mut app = test::init_service(App::new().configure(services)).await;
let urls = vec!["/join", "/login"];
for url in urls.iter() {
let resp =
test::call_service(&mut app, test::TestRequest::get().uri(url).to_request()).await;
assert_eq!(resp.status(), StatusCode::OK);
}
}
}

View File

@@ -21,6 +21,7 @@ use actix_web::{get, HttpResponse, Responder};
use sailfish::TemplateOnce;
use crate::api::v1::auth::is_authenticated;
pub use crate::middleware::auth::CheckLogin;
pub mod sitekey;
@@ -42,7 +43,7 @@ impl<'a> Default for IndexPage<'a> {
}
}
#[get("/")]
#[get("/", wrap = "CheckLogin")]
pub async fn panel(id: Identity) -> impl Responder {
if is_authenticated(&id).is_err() {
return HttpResponse::TemporaryRedirect()

View File

@@ -18,6 +18,8 @@
use actix_web::{get, HttpResponse, Responder};
use sailfish::TemplateOnce;
use super::CheckLogin;
#[derive(TemplateOnce, Clone)]
#[template(path = "panel/add-site-key/index.html")]
pub struct IndexPage<'a> {
@@ -36,7 +38,7 @@ impl<'a> Default for IndexPage<'a> {
}
}
#[get("/sitekey/add")]
#[get("/sitekey/add", wrap = "CheckLogin")]
pub async fn add_sitekey() -> impl Responder {
let body = IndexPage::default().render_once().unwrap();
HttpResponse::Ok()