Merge pull request #643 from BlackDex/icon-security
Updated icon blacklisting.
This commit is contained in:
commit
99a635d327
|
@ -1,12 +1,13 @@
|
||||||
use std::fs::{create_dir_all, remove_file, symlink_metadata, File};
|
use std::fs::{create_dir_all, remove_file, symlink_metadata, File};
|
||||||
use std::io::prelude::*;
|
use std::io::prelude::*;
|
||||||
|
use std::net::ToSocketAddrs;
|
||||||
use std::time::{Duration, SystemTime};
|
use std::time::{Duration, SystemTime};
|
||||||
|
|
||||||
use rocket::http::ContentType;
|
use rocket::http::ContentType;
|
||||||
use rocket::response::Content;
|
use rocket::response::Content;
|
||||||
use rocket::Route;
|
use rocket::Route;
|
||||||
|
|
||||||
use reqwest::{header::HeaderMap, Client, Response};
|
use reqwest::{header::HeaderMap, Client, Response, Url};
|
||||||
|
|
||||||
use rocket::http::Cookie;
|
use rocket::http::Cookie;
|
||||||
|
|
||||||
|
@ -60,22 +61,47 @@ fn icon(domain: String) -> Content<Vec<u8>> {
|
||||||
return Content(icon_type, FALLBACK_ICON.to_vec());
|
return Content(icon_type, FALLBACK_ICON.to_vec());
|
||||||
}
|
}
|
||||||
|
|
||||||
if let Some(blacklist) = CONFIG.icon_blacklist_regex() {
|
if check_icon_domain_is_blacklisted(&domain) {
|
||||||
info!("Icon blacklist enabled: {:#?}", blacklist);
|
warn!("Domain is blacklisted: {:#?}", domain);
|
||||||
|
|
||||||
let regex = Regex::new(&blacklist).expect("Valid Regex");
|
|
||||||
|
|
||||||
if regex.is_match(&domain) {
|
|
||||||
warn!("Blacklisted domain: {:#?}", domain);
|
|
||||||
return Content(icon_type, FALLBACK_ICON.to_vec());
|
return Content(icon_type, FALLBACK_ICON.to_vec());
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
let icon = get_icon(&domain);
|
let icon = get_icon(&domain);
|
||||||
|
|
||||||
Content(icon_type, icon)
|
Content(icon_type, icon)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn check_icon_domain_is_blacklisted(domain: &str) -> bool {
|
||||||
|
let mut is_blacklisted = false;
|
||||||
|
if CONFIG.icon_blacklist_non_global_ips() {
|
||||||
|
is_blacklisted = (domain, 0)
|
||||||
|
.to_socket_addrs()
|
||||||
|
.map(|x| {
|
||||||
|
for ip_port in x {
|
||||||
|
if !ip_port.ip().is_global() {
|
||||||
|
warn!("IP {} for domain '{}' is not a global IP!", ip_port.ip(), domain);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
false
|
||||||
|
})
|
||||||
|
.unwrap_or(false);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Skip the regex check if the previous one is true already
|
||||||
|
if !is_blacklisted {
|
||||||
|
if let Some(blacklist) = CONFIG.icon_blacklist_regex() {
|
||||||
|
let regex = Regex::new(&blacklist).expect("Valid Regex");
|
||||||
|
if regex.is_match(&domain) {
|
||||||
|
warn!("Blacklisted domain: {:#?} matched {:#?}", domain, blacklist);
|
||||||
|
is_blacklisted = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
is_blacklisted
|
||||||
|
}
|
||||||
|
|
||||||
fn get_icon(domain: &str) -> Vec<u8> {
|
fn get_icon(domain: &str) -> Vec<u8> {
|
||||||
let path = format!("{}/{}.png", CONFIG.icon_cache_folder(), domain);
|
let path = format!("{}/{}.png", CONFIG.icon_cache_folder(), domain);
|
||||||
|
|
||||||
|
@ -202,6 +228,7 @@ fn get_icon_url(domain: &str) -> Result<(Vec<Icon>, String), Error> {
|
||||||
if let Ok(content) = resp {
|
if let Ok(content) = resp {
|
||||||
// Extract the URL from the respose in case redirects occured (like @ gitlab.com)
|
// Extract the URL from the respose in case redirects occured (like @ gitlab.com)
|
||||||
let url = content.url().clone();
|
let url = content.url().clone();
|
||||||
|
|
||||||
let raw_cookies = content.headers().get_all("set-cookie");
|
let raw_cookies = content.headers().get_all("set-cookie");
|
||||||
cookie_str = raw_cookies
|
cookie_str = raw_cookies
|
||||||
.iter()
|
.iter()
|
||||||
|
@ -253,6 +280,10 @@ fn get_page(url: &str) -> Result<Response, Error> {
|
||||||
}
|
}
|
||||||
|
|
||||||
fn get_page_with_cookies(url: &str, cookie_str: &str) -> Result<Response, Error> {
|
fn get_page_with_cookies(url: &str, cookie_str: &str) -> Result<Response, Error> {
|
||||||
|
if check_icon_domain_is_blacklisted(Url::parse(url).unwrap().host_str().unwrap_or_default()) {
|
||||||
|
err!("Favicon rel linked to a non blacklisted domain!");
|
||||||
|
}
|
||||||
|
|
||||||
if cookie_str.is_empty() {
|
if cookie_str.is_empty() {
|
||||||
CLIENT
|
CLIENT
|
||||||
.get(url)
|
.get(url)
|
||||||
|
|
|
@ -267,6 +267,9 @@ make_config! {
|
||||||
/// Icon blacklist Regex |> Any domains or IPs that match this regex won't be fetched by the icon service.
|
/// Icon blacklist Regex |> Any domains or IPs that match this regex won't be fetched by the icon service.
|
||||||
/// Useful to hide other servers in the local network. Check the WIKI for more details
|
/// Useful to hide other servers in the local network. Check the WIKI for more details
|
||||||
icon_blacklist_regex: String, true, option;
|
icon_blacklist_regex: String, true, option;
|
||||||
|
/// Icon blacklist non global IPs |> Any IP which is not defined as a global IP will be blacklisted.
|
||||||
|
/// Usefull to secure your internal environment: See https://en.wikipedia.org/wiki/Reserved_IP_addresses for a list of IPs which it will block
|
||||||
|
icon_blacklist_non_global_ips: bool, true, def, true;
|
||||||
|
|
||||||
/// Disable Two-Factor remember |> Enabling this would force the users to use a second factor to login every time.
|
/// Disable Two-Factor remember |> Enabling this would force the users to use a second factor to login every time.
|
||||||
/// Note that the checkbox would still be present, but ignored.
|
/// Note that the checkbox would still be present, but ignored.
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
#![feature(proc_macro_hygiene, decl_macro, vec_remove_item, try_trait)]
|
#![feature(proc_macro_hygiene, decl_macro, vec_remove_item, try_trait, ip)]
|
||||||
#![recursion_limit = "256"]
|
#![recursion_limit = "256"]
|
||||||
|
|
||||||
#[cfg(feature = "openssl")]
|
#[cfg(feature = "openssl")]
|
||||||
|
|
Loading…
Reference in New Issue