chore(repo): remove dead code and useless tests (#3375)

This commit is contained in:
Hampus authored and GitHub committed 2026-10-10 21:43:29 +02:00
1 parent 7e177a1c90
commit 1cd62eb661
1391 files changed
+783 -120415

No files matched your search

+1 -8
View File
@@ -6,23 +6,16 @@ license.workspace = true
[dependencies]
anyhow = "1.0.104"
aws-credential-types = "1.3.0"
aws-sigv4 = "1.5.3"
axum = { version = "0.8.9", default-features = false }
maxminddb = "0.32.0"
moka = { version = "0.12.16", features = ["sync"] }
reqwest = { version = "0.13.5", default-features = false, features = ["blocking", "rustls"] }
serde_json = "1.0.151"
tempfile = "3.27.0"
time = { version = "0.3.55", features = ["formatting", "macros", "parsing"] }
tracing = "0.1.44"
tracing-subscriber = { version = "0.3.23", default-features = false, features = ["env-filter"] }
base64 = "0.23"
hex = "0.4.3"
hmac = "0.13.0"
sha2 = "0.11.0"
thiserror = "2"
urlencoding = "2.1.3"
[dev-dependencies]
tempfile = "3.27.0"
url = "2.5.8"
+1 -211
View File
@@ -1,127 +1,6 @@
// SPDX-License-Identifier: AGPL-3.0-or-later
use std::{env, fs, path::Path};
#[derive(Clone, Debug, Eq, PartialEq)]
pub enum GeoipSourceConfig {
Filesystem {
maxmind_db_path: Option<String>,
},
S3 {
maxmind_db_path: String,
s3_bucket: String,
s3_key: String,
},
}
impl GeoipSourceConfig {
pub fn maxmind_db_path(&self) -> Option<String> {
match self {
Self::Filesystem { maxmind_db_path } => maxmind_db_path.clone(),
Self::S3 {
maxmind_db_path, ..
} => Some(maxmind_db_path.clone()),
}
}
}
#[derive(Clone, Debug, Eq, PartialEq)]
pub struct GeoipS3Config {
pub endpoint: String,
pub region: String,
pub access_key_id: String,
pub secret_access_key: String,
}
pub fn read_geoip_s3_config_from_env(source: &GeoipSourceConfig) -> Option<GeoipS3Config> {
read_geoip_s3_config(source, env_value)
}
fn read_geoip_s3_config<F>(source: &GeoipSourceConfig, mut read_var: F) -> Option<GeoipS3Config>
where
F: FnMut(&str) -> Option<String>,
{
match source {
GeoipSourceConfig::S3 { .. } => Some(GeoipS3Config {
endpoint: read_var("FLUXER_S3_ENDPOINT").unwrap_or_default(),
region: read_var("FLUXER_S3_REGION").unwrap_or_default(),
access_key_id: read_var("FLUXER_S3_ACCESS_KEY_ID").unwrap_or_default(),
secret_access_key: read_var("FLUXER_S3_SECRET_ACCESS_KEY").unwrap_or_default(),
}),
GeoipSourceConfig::Filesystem { .. } => None,
}
}
pub fn parse_geoip_source_config(raw_value: &str, service_name: &str) -> GeoipSourceConfig {
let trimmed = raw_value.trim();
if trimmed.is_empty() {
return GeoipSourceConfig::Filesystem {
maxmind_db_path: None,
};
}
if !trimmed.starts_with("s3://") {
return GeoipSourceConfig::Filesystem {
maxmind_db_path: Some(trimmed.to_owned()),
};
}
parse_geoip_s3_source_config(trimmed, service_name)
}
fn parse_geoip_s3_source_config(raw_value: &str, service_name: &str) -> GeoipSourceConfig {
let url = reqwest::Url::parse(raw_value)
.unwrap_or_else(|err| panic!("invalid GeoIP S3 URL {}: {}", raw_value, err));
let s3_bucket = url.host_str().unwrap_or("").to_owned();
if s3_bucket.is_empty() {
panic!("invalid GeoIP S3 URL (missing bucket): {raw_value}");
}
let s3_key = percent_decode(url.path().trim_start_matches('/'));
if s3_key.is_empty() {
panic!("invalid GeoIP S3 URL (missing object key): {raw_value}");
}
let maxmind_db_path =
geoip_runtime_path(&resolve_geoip_download_path(&url, raw_value), service_name);
GeoipSourceConfig::S3 {
maxmind_db_path,
s3_bucket,
s3_key,
}
}
fn resolve_geoip_download_path(url: &reqwest::Url, raw_value: &str) -> String {
let Some(download_path) = url
.query_pairs()
.find(|(key, _)| key == "download_path")
.map(|(_, value)| value.into_owned())
else {
panic!("invalid GeoIP S3 URL (missing query parameter \"download_path\"): {raw_value}");
};
require_absolute_path(&download_path, "download_path", raw_value)
}
fn require_absolute_path(value: &str, param: &str, raw_value: &str) -> String {
if !Path::new(value).is_absolute() {
panic!("GeoIP S3 URL query parameter \"{param}\" must be an absolute path: {raw_value}");
}
value.to_owned()
}
fn geoip_runtime_path(configured_path: &str, service_name: &str) -> String {
let basename = Path::new(configured_path)
.file_name()
.and_then(|value| value.to_str())
.unwrap_or("GeoLite2-City.mmdb");
Path::new("/tmp/fluxer/geoip")
.join(service_name)
.join(basename)
.to_string_lossy()
.into_owned()
}
fn percent_decode(value: &str) -> String {
urlencoding::decode(value)
.map(|value| value.into_owned())
.unwrap_or_else(|_| value.to_owned())
}
use std::{env, fs};
pub fn env_value(name: &str) -> Option<String> {
resolve_env_value(name, |key| env::var(key).ok()).unwrap_or_else(|error| panic!("{error}"))
@@ -355,86 +234,6 @@ pub fn normalize_public_endpoint_from_env(url: &str) -> String {
mod tests {
use super::*;
#[test]
fn parses_filesystem_geoip_source() {
let source = parse_geoip_source_config("/data/GeoLite2-City.mmdb", "test");
assert_eq!(
source,
GeoipSourceConfig::Filesystem {
maxmind_db_path: Some("/data/GeoLite2-City.mmdb".to_owned()),
}
);
}
#[test]
fn parses_empty_geoip_source() {
let source = parse_geoip_source_config("", "test");
assert_eq!(
source,
GeoipSourceConfig::Filesystem {
maxmind_db_path: None,
}
);
}
#[test]
fn parses_s3_geoip_source() {
let source = parse_geoip_source_config(
"s3://geoip/GeoLite2-City.mmdb?download_path=/tmp/city.mmdb",
"test_svc",
);
assert_eq!(
source,
GeoipSourceConfig::S3 {
maxmind_db_path: "/tmp/fluxer/geoip/test_svc/city.mmdb".to_owned(),
s3_bucket: "geoip".to_owned(),
s3_key: "GeoLite2-City.mmdb".to_owned(),
}
);
}
#[test]
fn reads_geoip_s3_config_only_for_s3_source() {
let source = parse_geoip_source_config(
"s3://geoip/GeoLite2-City.mmdb?download_path=/tmp/city.mmdb",
"test_svc",
);
let config = read_geoip_s3_config(&source, |name| {
Some(
match name {
"FLUXER_S3_ENDPOINT" => "https://s3.example.test",
"FLUXER_S3_REGION" => "ewr1",
"FLUXER_S3_ACCESS_KEY_ID" => "access",
"FLUXER_S3_SECRET_ACCESS_KEY" => "secret",
_ => "",
}
.to_owned(),
)
})
.expect("s3 source should read s3 config");
assert_eq!(
config,
GeoipS3Config {
endpoint: "https://s3.example.test".to_owned(),
region: "ewr1".to_owned(),
access_key_id: "access".to_owned(),
secret_access_key: "secret".to_owned(),
}
);
let filesystem_source = parse_geoip_source_config("/tmp/city.mmdb", "test_svc");
assert!(read_geoip_s3_config(&filesystem_source, |_| None).is_none());
}
#[test]
fn normalize_base_path_strips_slashes() {
assert_eq!(normalize_base_path("/foo/bar/"), "/foo/bar");
assert_eq!(normalize_base_path("foo"), "/foo");
assert_eq!(normalize_base_path(""), "");
assert_eq!(normalize_base_path("/"), "");
}
#[test]
fn default_https_install_is_untouched() {
for url in [
@@ -953,13 +752,4 @@ mod tests {
assert!(read_bool_env("FLUXER_COMMON_TEST_BLANK_SPACES", true));
assert!(read_bool_env("FLUXER_COMMON_TEST_BLANK_TRUE", false));
}
#[test]
fn trim_trailing_slash_works() {
assert_eq!(
trim_trailing_slash("https://example.com/"),
"https://example.com"
);
assert_eq!(trim_trailing_slash(""), "");
}
}
-372
View File
@@ -1,372 +0,0 @@
// SPDX-License-Identifier: AGPL-3.0-or-later
use crate::config::{GeoipS3Config, GeoipSourceConfig};
use aws_credential_types::Credentials;
use aws_sigv4::{
http_request::{
PayloadChecksumKind, PercentEncodingMode, SignableBody, SignableRequest, SigningSettings,
UriPathNormalizationMode, sign,
},
sign::v4,
};
use axum::http::HeaderMap;
use maxminddb::{Reader, geoip2};
use moka::sync::Cache;
use std::{
fs::{self, File},
io,
net::IpAddr,
path::Path,
time::{Duration, SystemTime},
};
const DEFAULT_COUNTRY_CODE: &str = "US";
const GEOIP_CACHE_TTL: Duration = Duration::from_secs(10 * 60);
const GEOIP_CACHE_MAX_ENTRIES: u64 = 4096;
pub struct GeoipConfig {
pub geoip_source: GeoipSourceConfig,
pub geoip_s3_config: Option<GeoipS3Config>,
pub trust_client_ip_header: bool,
pub client_ip_header_name: String,
}
#[derive(Clone, Debug, Default)]
pub struct GeoipLookup {
pub country_code: Option<String>,
pub region_code: Option<String>,
pub latitude: Option<f64>,
pub longitude: Option<f64>,
}
#[derive(Debug)]
pub struct GeoipResolver {
reader: Option<Reader<Vec<u8>>>,
cache: Cache<IpAddr, GeoipLookup>,
trust_client_ip_header: bool,
client_ip_header_name: String,
}
impl GeoipResolver {
pub fn from_config(config: &GeoipConfig) -> Self {
let db_path = prepare_geoip_database(&config.geoip_source, config.geoip_s3_config.as_ref())
.unwrap_or_else(|err| panic!("failed to prepare GeoIP database: {err:#}"));
let reader = if let Some(path) = db_path.as_deref() {
open_reader(path)
} else {
None
};
Self {
reader,
cache: Cache::builder()
.max_capacity(GEOIP_CACHE_MAX_ENTRIES)
.time_to_live(GEOIP_CACHE_TTL)
.build(),
trust_client_ip_header: config.trust_client_ip_header,
client_ip_header_name: config.client_ip_header_name.clone(),
}
}
pub fn lookup(&self, headers: &HeaderMap) -> GeoipLookup {
let Some(reader) = self.reader.as_ref() else {
return GeoipLookup::default();
};
let Some(ip) = extract_client_ip(
headers,
self.trust_client_ip_header,
&self.client_ip_header_name,
) else {
return GeoipLookup::default();
};
if let Some(cached) = self.cache.get(&ip) {
return cached;
}
let result = lookup_geoip(reader, ip);
self.cache.insert(ip, result.clone());
result
}
pub fn country_code(&self, headers: &HeaderMap) -> String {
self.lookup(headers)
.country_code
.unwrap_or_else(|| DEFAULT_COUNTRY_CODE.to_owned())
}
}
fn open_reader(path: &str) -> Option<Reader<Vec<u8>>> {
match Reader::open_readfile(path) {
Ok(reader) => Some(reader),
Err(error) => {
tracing::warn!(
geoip_db_path = path,
?error,
"failed to open GeoIP database; geoip will be empty"
);
None
}
}
}
fn lookup_geoip(reader: &Reader<Vec<u8>>, ip: IpAddr) -> GeoipLookup {
let Ok(lookup) = reader.lookup(ip) else {
return GeoipLookup::default();
};
let Ok(Some(city)) = lookup.decode::<geoip2::City<'_>>() else {
return GeoipLookup::default();
};
let country_code = city.country.iso_code.and_then(normalize_country_code);
let region_code = city
.subdivisions
.first()
.and_then(|s| s.iso_code)
.map(|s| s.to_uppercase());
let latitude = city.location.latitude;
let longitude = city.location.longitude;
GeoipLookup {
country_code,
region_code,
latitude,
longitude,
}
}
fn extract_client_ip(
headers: &HeaderMap,
trust_client_ip_header: bool,
header_name: &str,
) -> Option<IpAddr> {
if !trust_client_ip_header {
return None;
}
let header_value = headers.get(header_name)?.to_str().ok()?;
let first_hop = header_value.split(',').next()?.trim();
parse_ip(first_hop)
}
fn parse_ip(value: &str) -> Option<IpAddr> {
if value.is_empty() {
return None;
}
if let Ok(ip) = value.parse() {
return Some(ip);
}
if let Some(stripped) = value
.strip_prefix('[')
.and_then(|value| value.split_once(']').map(|(host, _)| host))
{
return stripped.parse().ok();
}
if value.matches(':').count() == 1
&& let Some((host, _port)) = value.rsplit_once(':')
{
return host.parse().ok();
}
None
}
fn normalize_country_code(value: &str) -> Option<String> {
let country_code = value.trim().to_ascii_uppercase();
if country_code.len() == 2 && country_code.chars().all(|ch| ch.is_ascii_alphabetic()) {
Some(country_code)
} else {
None
}
}
fn prepare_geoip_database(
source: &GeoipSourceConfig,
s3_config: Option<&GeoipS3Config>,
) -> anyhow::Result<Option<String>> {
match source {
GeoipSourceConfig::Filesystem { maxmind_db_path } => Ok(maxmind_db_path.clone()),
GeoipSourceConfig::S3 {
maxmind_db_path,
s3_bucket,
s3_key,
} => {
let s3 = s3_config.ok_or_else(|| {
anyhow::anyhow!("GeoIP is configured for S3 mode, but S3 configuration is missing")
})?;
require_s3_config(s3)?;
download_s3_object(s3, s3_bucket, s3_key, Path::new(maxmind_db_path))?;
tracing::info!(
maxmind_db_path,
s3_bucket,
s3_key,
"GeoIP database downloaded from S3"
);
Ok(Some(maxmind_db_path.clone()))
}
}
}
fn require_s3_config(config: &GeoipS3Config) -> anyhow::Result<()> {
require_s3_value(
&config.endpoint,
"GeoIP S3 startup mode requires s3.endpoint",
)?;
require_s3_value(&config.region, "GeoIP S3 startup mode requires s3.region")?;
require_s3_value(
&config.access_key_id,
"GeoIP S3 startup mode requires s3.access_key_id",
)?;
require_s3_value(
&config.secret_access_key,
"GeoIP S3 startup mode requires s3.secret_access_key",
)
}
fn require_s3_value(value: &str, message: &str) -> anyhow::Result<()> {
if value.trim().is_empty() {
anyhow::bail!("{}", message);
}
Ok(())
}
fn download_s3_object(
config: &GeoipS3Config,
bucket: &str,
key: &str,
destination: &Path,
) -> anyhow::Result<()> {
let Some(parent) = destination.parent() else {
anyhow::bail!(
"GeoIP S3 destination must include a parent directory: {}",
destination.display()
);
};
fs::create_dir_all(parent)?;
let request = signed_s3_get_request(config, bucket, key)?;
let mut response = reqwest::blocking::Client::new()
.get(request.url)
.headers(request.headers)
.send()
.map_err(|err| {
anyhow::anyhow!("failed to download GeoIP database from s3://{bucket}/{key}: {err}")
})?;
if !response.status().is_success() {
let status = response.status();
anyhow::bail!("failed to download GeoIP database from s3://{bucket}/{key}: HTTP {status}");
}
let mut file = tempfile::Builder::new().make_in(parent, |path| File::create_new(path))?;
io::copy(&mut response, &mut file)?;
file.persist(destination).map_err(|err| err.error)?;
Ok(())
}
struct SignedS3Request {
url: reqwest::Url,
headers: reqwest::header::HeaderMap,
}
fn signed_s3_get_request(
config: &GeoipS3Config,
bucket: &str,
key: &str,
) -> anyhow::Result<SignedS3Request> {
let mut url = reqwest::Url::parse(config.endpoint.trim_end_matches('/'))?;
{
let mut segments = url.path_segments_mut().map_err(|_| {
anyhow::anyhow!("S3 endpoint cannot be a base URL: {}", config.endpoint)
})?;
segments.pop_if_empty();
segments.push(bucket);
for segment in key.split('/') {
segments.push(segment);
}
}
let identity = Credentials::new(
config.access_key_id.clone(),
config.secret_access_key.clone(),
None,
None,
"fluxer-geoip",
)
.into();
let mut signing_settings = SigningSettings::default();
signing_settings.percent_encoding_mode = PercentEncodingMode::Single;
signing_settings.payload_checksum_kind = PayloadChecksumKind::XAmzSha256;
signing_settings.uri_path_normalization_mode = UriPathNormalizationMode::Disabled;
let signing_params = v4::SigningParams::builder()
.identity(&identity)
.region(&config.region)
.name("s3")
.time(SystemTime::now())
.settings(signing_settings)
.build()?
.into();
let signable_request = SignableRequest::new(
"GET",
url.as_str(),
std::iter::empty::<(&str, &str)>(),
SignableBody::Bytes(&[]),
)?;
let (signing_instructions, _signature) = sign(signable_request, &signing_params)?.into_parts();
let (signed_headers, signed_params) = signing_instructions.into_parts();
if !signed_params.is_empty() {
anyhow::bail!("S3 GeoIP signing unexpectedly produced query parameters for header signing");
}
let mut headers = reqwest::header::HeaderMap::new();
for header in signed_headers {
let name = reqwest::header::HeaderName::from_bytes(header.name().as_bytes())?;
let mut value = reqwest::header::HeaderValue::from_str(header.value())?;
value.set_sensitive(header.sensitive());
headers.insert(name, value);
}
Ok(SignedS3Request { url, headers })
}
#[cfg(test)]
mod tests {
use super::*;
use axum::http::HeaderValue;
#[test]
fn extracts_first_configured_client_ip_only_when_trusted() {
let mut headers = HeaderMap::new();
headers.insert(
"x-forwarded-for",
HeaderValue::from_static("203.0.113.10, 10.0.0.4"),
);
assert_eq!(
extract_client_ip(&headers, true, "x-forwarded-for"),
Some("203.0.113.10".parse().unwrap())
);
assert_eq!(extract_client_ip(&headers, false, "x-forwarded-for"), None);
}
#[test]
fn parse_ip_handles_ipv4() {
assert_eq!(
parse_ip("203.0.113.10"),
Some("203.0.113.10".parse().unwrap())
);
}
#[test]
fn parse_ip_handles_ipv4_with_port() {
assert_eq!(
parse_ip("203.0.113.10:8080"),
Some("203.0.113.10".parse().unwrap())
);
}
#[test]
fn parse_ip_handles_ipv6_bracketed() {
assert_eq!(parse_ip("[::1]:8080"), Some("::1".parse().unwrap()));
}
#[test]
fn parse_ip_handles_empty() {
assert_eq!(parse_ip(""), None);
}
#[test]
fn normalizes_valid_country_codes() {
assert_eq!(normalize_country_code("se"), Some("SE".to_owned()));
assert_eq!(normalize_country_code("US"), Some("US".to_owned()));
assert_eq!(normalize_country_code("abc"), None);
assert_eq!(normalize_country_code(""), None);
}
}
-1
View File
@@ -3,5 +3,4 @@
pub mod attachment_url_signature;
pub mod config;
pub mod external_media_path;
pub mod geoip;
pub mod user_flags;