qrush_engine/services/
basic_auth_service.rs1use actix_web::{
3 dev::{forward_ready, Service, ServiceRequest, ServiceResponse, Transform},
4 Error, HttpRequest, HttpResponse,
5};
6use base64::engine::general_purpose::STANDARD;
7use base64::Engine;
8use futures_util::future::{ready, Either, Ready}; use std::future::Ready as StdReady; use crate::config::get_basic_auth;
11
12pub struct BasicAuthMiddleware;
13
14impl<S> Transform<S, ServiceRequest> for BasicAuthMiddleware
15where
16 S: Service<ServiceRequest, Response = ServiceResponse, Error = Error> + 'static,
17 S::Future: 'static,
18{
19 type Response = ServiceResponse;
20 type Error = Error;
21 type InitError = ();
22 type Transform = BasicAuthMiddlewareService<S>;
23 type Future = StdReady<Result<Self::Transform, Self::InitError>>;
24
25 fn new_transform(&self, service: S) -> Self::Future {
26 std::future::ready(Ok(BasicAuthMiddlewareService { service }))
27 }
28}
29
30pub struct BasicAuthMiddlewareService<S> {
31 service: S,
32}
33
34impl<S> Service<ServiceRequest> for BasicAuthMiddlewareService<S>
35where
36 S: Service<ServiceRequest, Response = ServiceResponse, Error = Error> + 'static,
37 S::Future: 'static,
38{
39 type Response = ServiceResponse;
40 type Error = Error;
41
42 type Future = Either<Ready<Result<Self::Response, Self::Error>>, S::Future>;
44
45 forward_ready!(service);
46
47 fn call(&self, req: ServiceRequest) -> Self::Future {
48 if check_basic_auth(req.request()) {
49 Either::Right(self.service.call(req))
50 } else {
51 let response = req.into_response(unauthorized_response());
52 Either::Left(ready(Ok(response)))
53 }
54 }
55}
56
57pub fn check_basic_auth(req: &HttpRequest) -> bool {
58 if let Some(config) = get_basic_auth() {
59 if let Some(auth_header) = req.headers().get("Authorization") {
60 if let Ok(auth_str) = auth_header.to_str() {
61 if let Some(encoded) = auth_str.strip_prefix("Basic ") {
62 if let Ok(decoded) = STANDARD.decode(encoded) {
63 if let Ok(credentials) = std::str::from_utf8(&decoded) {
64 let mut parts = credentials.splitn(2, ':');
65 let user = parts.next().unwrap_or_default();
66 let pass = parts.next().unwrap_or_default();
67 if user == config.username && pass == config.password {
68 return true;
69 }
70 }
71 }
72 }
73 }
74 }
75 return false;
76 }
77 true
79}
80
81pub fn unauthorized_response() -> HttpResponse {
82 HttpResponse::Unauthorized()
83 .append_header(("WWW-Authenticate", r#"Basic realm="QRush""#))
84 .finish()
85}