1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
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(),
        //            )))
        //        }
    }
}