mcaptcha/static_assets/
static_files.rs1use std::borrow::Cow;
7
8use actix_web::body::BoxBody;
9use actix_web::{get, http::header, web, HttpResponse, Responder};
10use log::debug;
11use mime_guess::from_path;
12use rust_embed::RustEmbed;
13
14use crate::CACHE_AGE;
15
16pub mod assets {
17 use lazy_static::lazy_static;
18
19 use crate::FILES;
20
21 type Img = (&'static str, &'static str);
22
23 lazy_static! {
24 pub static ref KEY: Img =
25 (FILES.get("./static/cache/img/svg/key.svg").unwrap(), "key");
26 pub static ref GITHUB: Img = (
27 FILES.get("./static/cache/img/svg/github.svg").unwrap(),
28 "Source code"
29 );
30 pub static ref HOME: Img = (
31 FILES.get("./static/cache/img/svg/home.svg").unwrap(),
32 "Home"
33 );
34 pub static ref SETTINGS_ICON: Img = (
35 FILES.get("./static/cache/img/svg/settings.svg").unwrap(),
36 "Settings"
37 );
38 pub static ref CREDIT_CARD: Img = (
39 FILES.get("./static/cache/img/svg/credit-card.svg").unwrap(),
40 "Payment"
41 );
42 pub static ref HELP_CIRCLE: Img = (
43 FILES.get("./static/cache/img/svg/help-circle.svg").unwrap(),
44 "Help"
45 );
46 pub static ref MESSAGE: Img = (
47 FILES
48 .get("./static/cache/img/svg/message-square.svg")
49 .unwrap(),
50 "Message"
51 );
52 pub static ref DOCS_ICON: Img = (
53 FILES.get("./static/cache/img/svg/file-text.svg").unwrap(),
54 "Documentation"
55 );
56 pub static ref MCAPTCHA_TRANS_ICON: Img = (
57 FILES.get("./static/cache/img/icon-trans.png").unwrap(),
58 "Logo"
59 );
60 pub static ref BAR_CHART: Img = (
61 FILES.get("./static/cache/img/svg/bar-chart.svg").unwrap(),
62 "Statistics"
63 );
64 }
65}
66
67#[derive(RustEmbed)]
68#[folder = "assets/"]
69struct Asset;
70
71fn handle_assets(path: &str) -> HttpResponse {
72 match Asset::get(path) {
73 Some(content) => {
74 let body: BoxBody = match content.data {
75 Cow::Borrowed(bytes) => BoxBody::new(bytes),
76 Cow::Owned(bytes) => BoxBody::new(bytes),
77 };
78
79 HttpResponse::Ok()
80 .insert_header(header::CacheControl(vec![
81 header::CacheDirective::Public,
82 header::CacheDirective::Extension("immutable".into(), None),
83 header::CacheDirective::MaxAge(CACHE_AGE),
84 ]))
85 .content_type(from_path(path).first_or_octet_stream().as_ref())
86 .body(body)
87 }
88 None => HttpResponse::NotFound().body("404 Not Found"),
89 }
90}
91
92#[get("/assets/{_:.*}")]
93pub async fn static_files(path: web::Path<String>) -> impl Responder {
94 handle_assets(&path)
95}
96
97#[derive(RustEmbed)]
98#[folder = "static/favicons/"]
99struct Favicons;
100
101fn handle_favicons(path: &str) -> HttpResponse {
102 match Favicons::get(path) {
103 Some(content) => {
104 let body: BoxBody = match content.data {
105 Cow::Borrowed(bytes) => BoxBody::new(bytes),
106 Cow::Owned(bytes) => BoxBody::new(bytes),
107 };
108
109 HttpResponse::Ok()
110 .insert_header(header::CacheControl(vec![
111 header::CacheDirective::Public,
112 header::CacheDirective::Extension("immutable".into(), None),
113 header::CacheDirective::MaxAge(CACHE_AGE),
114 ]))
115 .content_type(from_path(path).first_or_octet_stream().as_ref())
116 .body(body)
117 }
118 None => HttpResponse::NotFound().body("404 Not Found"),
119 }
120}
121
122#[get("/{file}")]
123pub async fn favicons(path: web::Path<String>) -> impl Responder {
124 debug!("searching favicons");
125 handle_favicons(&path)
126}
127
128#[cfg(test)]
129mod tests {
130 use actix_web::http::StatusCode;
131 use actix_web::test;
132
133 use crate::*;
134
135 #[actix_rt::test]
136 async fn static_assets_work() {
137 let app = get_app!().await;
138
139 let urls = [
140 *crate::JS,
141 *crate::VERIFICATIN_WIDGET_JS,
142 *crate::VERIFICATIN_WIDGET_CSS,
143 crate::FILES
144 .get("./static/cache/img/icon-trans.png")
145 .unwrap(),
146 "/favicon.ico",
147 ];
148
149 for u in urls.iter() {
150 println!("[*] Testing static asset at URL: {u}");
151 let resp =
152 test::call_service(&app, test::TestRequest::get().uri(u).to_request())
153 .await;
154 assert_eq!(resp.status(), StatusCode::OK);
155 }
156 }
157}