Add geoip data and 451 handler
This commit is contained in:
parent
7ac69b59af
commit
98160a8023
@ -59,6 +59,7 @@ assets = [
|
|||||||
["reminder-dashboard/dist/index.html", "lib/reminder-rs/static/index.html", "644"],
|
["reminder-dashboard/dist/index.html", "lib/reminder-rs/static/index.html", "644"],
|
||||||
["conf/default.env", "etc/reminder-rs/config.env", "600"],
|
["conf/default.env", "etc/reminder-rs/config.env", "600"],
|
||||||
["conf/Rocket.toml", "etc/reminder-rs/Rocket.toml", "600"],
|
["conf/Rocket.toml", "etc/reminder-rs/Rocket.toml", "600"],
|
||||||
|
["conf/geo-asn-country-ipv4.csv", "etc/reminder-rs/geo-asn-country-ipv4.csv", "600"],
|
||||||
# ["nginx/reminder-rs", "etc/nginx/sites-available/reminder-rs", "755"]
|
# ["nginx/reminder-rs", "etc/nginx/sites-available/reminder-rs", "755"]
|
||||||
]
|
]
|
||||||
conf-files = [
|
conf-files = [
|
||||||
|
12676
conf/gb-ipv4.csv
Normal file
12676
conf/gb-ipv4.csv
Normal file
File diff suppressed because it is too large
Load Diff
12676
gb-ipv4.csv
Normal file
12676
gb-ipv4.csv
Normal file
File diff suppressed because it is too large
Load Diff
@ -32,7 +32,6 @@ use poise::{
|
|||||||
};
|
};
|
||||||
use serenity::all::Channel;
|
use serenity::all::Channel;
|
||||||
use sqlx::{Executor, FromRow};
|
use sqlx::{Executor, FromRow};
|
||||||
use std::thread::ThreadId;
|
|
||||||
use std::{
|
use std::{
|
||||||
collections::HashSet,
|
collections::HashSet,
|
||||||
hash::{Hash, Hasher},
|
hash::{Hash, Hasher},
|
||||||
|
@ -29,6 +29,12 @@ pub(crate) async fn not_found() -> Template {
|
|||||||
Template::render("errors/404", &map)
|
Template::render("errors/404", &map)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[catch(451)]
|
||||||
|
pub(crate) async fn legal_reasons() -> Template {
|
||||||
|
let map: HashMap<String, String> = HashMap::new();
|
||||||
|
Template::render("errors/451", &map)
|
||||||
|
}
|
||||||
|
|
||||||
#[catch(413)]
|
#[catch(413)]
|
||||||
pub(crate) async fn payload_too_large() -> JsonValue {
|
pub(crate) async fn payload_too_large() -> JsonValue {
|
||||||
json!({"error": "Data too large.", "errors": ["Data too large."]})
|
json!({"error": "Data too large.", "errors": ["Data too large."]})
|
||||||
|
58
src/web/ip_blocking.rs
Normal file
58
src/web/ip_blocking.rs
Normal file
@ -0,0 +1,58 @@
|
|||||||
|
use std::net::Ipv4Addr;
|
||||||
|
|
||||||
|
struct IpBlocking {
|
||||||
|
upper_ips: Vec<u32>,
|
||||||
|
lower_ips: Vec<u32>,
|
||||||
|
}
|
||||||
|
|
||||||
|
type E = Box<dyn std::error::Error>;
|
||||||
|
|
||||||
|
impl IpBlocking {
|
||||||
|
fn from_path(path: &str) -> Result<Self, E> {
|
||||||
|
let mut upper_ips: Vec<u32> = vec![];
|
||||||
|
let mut lower_ips: Vec<u32> = vec![];
|
||||||
|
let mut reader = csv::Reader::from_path(path)?;
|
||||||
|
|
||||||
|
for record in reader.records() {
|
||||||
|
let record = record?;
|
||||||
|
let ip_range: Option<(u32, u32)> =
|
||||||
|
record.get(0).map(|ip| ip.parse::<Ipv4Addr>().ok()).flatten().and_then(
|
||||||
|
|ip_start| {
|
||||||
|
record
|
||||||
|
.get(1)
|
||||||
|
.map(|ip| ip.parse::<Ipv4Addr>().ok())
|
||||||
|
.flatten()
|
||||||
|
.map(|ip_end| (ip_start.into(), ip_end.into()))
|
||||||
|
},
|
||||||
|
);
|
||||||
|
|
||||||
|
if let Some((ip_start, ip_end)) = ip_range {
|
||||||
|
upper_ips.push(ip_end);
|
||||||
|
lower_ips.push(ip_start);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Should already be sorted but just in case
|
||||||
|
upper_ips.sort_unstable();
|
||||||
|
lower_ips.sort_unstable();
|
||||||
|
|
||||||
|
Ok(Self { upper_ips, lower_ips })
|
||||||
|
}
|
||||||
|
|
||||||
|
fn contains<I: Into<u32>>(&self, ip: I) -> bool {
|
||||||
|
let ip: u32 = ip.into();
|
||||||
|
|
||||||
|
let mut prev_index = self.upper_ips.len() - 1;
|
||||||
|
let mut index = self.upper_ips.len() / 2;
|
||||||
|
loop {
|
||||||
|
if self.upper_ips[index] <= ip && self.lower_ips[index] >= ip {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
let diff = self.upper_ips.len() - index;
|
||||||
|
if self.upper_ips[index] < ip {
|
||||||
|
index += diff / 2;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -4,6 +4,7 @@ mod macros;
|
|||||||
mod catchers;
|
mod catchers;
|
||||||
mod fairings;
|
mod fairings;
|
||||||
mod guards;
|
mod guards;
|
||||||
|
mod ip_blocking;
|
||||||
mod routes;
|
mod routes;
|
||||||
|
|
||||||
pub mod string {
|
pub mod string {
|
||||||
@ -58,8 +59,6 @@ pub mod string_opt {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
use std::{env, path::Path};
|
|
||||||
|
|
||||||
use log::{error, info, warn};
|
use log::{error, info, warn};
|
||||||
use oauth2::{basic::BasicClient, AuthUrl, ClientId, ClientSecret, RedirectUrl, TokenUrl};
|
use oauth2::{basic::BasicClient, AuthUrl, ClientId, ClientSecret, RedirectUrl, TokenUrl};
|
||||||
use poise::serenity_prelude::{
|
use poise::serenity_prelude::{
|
||||||
@ -77,6 +76,8 @@ use rocket::{
|
|||||||
};
|
};
|
||||||
use rocket_dyn_templates::Template;
|
use rocket_dyn_templates::Template;
|
||||||
use sqlx::{MySql, Pool};
|
use sqlx::{MySql, Pool};
|
||||||
|
use std::net::Ipv4Addr;
|
||||||
|
use std::{env, path::Path};
|
||||||
|
|
||||||
use crate::web::{
|
use crate::web::{
|
||||||
consts::{CNC_GUILD, DISCORD_OAUTH_AUTHORIZE, DISCORD_OAUTH_TOKEN, SUBSCRIPTION_ROLES},
|
consts::{CNC_GUILD, DISCORD_OAUTH_AUTHORIZE, DISCORD_OAUTH_TOKEN, SUBSCRIPTION_ROLES},
|
||||||
@ -107,6 +108,10 @@ pub async fn initialize(
|
|||||||
env::var("PATREON_GUILD_ID").expect("`PATREON_GUILD_ID' not supplied");
|
env::var("PATREON_GUILD_ID").expect("`PATREON_GUILD_ID' not supplied");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
info!("Loading GB IP list");
|
||||||
|
|
||||||
|
info!("Loaded {} IP ranges", lower_bounds.len());
|
||||||
|
|
||||||
info!("Done!");
|
info!("Done!");
|
||||||
|
|
||||||
let oauth2_client = BasicClient::new(
|
let oauth2_client = BasicClient::new(
|
||||||
@ -131,6 +136,7 @@ pub async fn initialize(
|
|||||||
catchers::not_authorized,
|
catchers::not_authorized,
|
||||||
catchers::forbidden,
|
catchers::forbidden,
|
||||||
catchers::not_found,
|
catchers::not_found,
|
||||||
|
catchers::legal_reasons,
|
||||||
catchers::internal_server_error,
|
catchers::internal_server_error,
|
||||||
catchers::unprocessable_entity,
|
catchers::unprocessable_entity,
|
||||||
catchers::payload_too_large,
|
catchers::payload_too_large,
|
||||||
|
@ -14,13 +14,8 @@ use crate::web::guards::transaction::Transaction;
|
|||||||
use crate::web::routes::dashboard::create_reminder_template;
|
use crate::web::routes::dashboard::create_reminder_template;
|
||||||
use crate::web::{
|
use crate::web::{
|
||||||
check_authorization,
|
check_authorization,
|
||||||
consts::{
|
|
||||||
MAX_CONTENT_LENGTH, MAX_EMBED_AUTHOR_LENGTH, MAX_EMBED_DESCRIPTION_LENGTH,
|
|
||||||
MAX_EMBED_FIELDS, MAX_EMBED_FIELD_TITLE_LENGTH, MAX_EMBED_FIELD_VALUE_LENGTH,
|
|
||||||
MAX_EMBED_FOOTER_LENGTH, MAX_EMBED_TITLE_LENGTH, MAX_URL_LENGTH, MAX_USERNAME_LENGTH,
|
|
||||||
},
|
|
||||||
routes::{
|
routes::{
|
||||||
dashboard::{template_name_default, DeleteReminderTemplate, ReminderTemplate},
|
dashboard::{DeleteReminderTemplate, ReminderTemplate},
|
||||||
JsonResult,
|
JsonResult,
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
10
templates/errors/451.html.tera
Normal file
10
templates/errors/451.html.tera
Normal file
@ -0,0 +1,10 @@
|
|||||||
|
{% extends "base" %}
|
||||||
|
|
||||||
|
{% block init %}
|
||||||
|
{% set title = "451 Unavailable due to legal reasons" %}
|
||||||
|
|
||||||
|
{% set show_contact = True %}
|
||||||
|
|
||||||
|
{% set page_title = "Unavailable in this region" %}
|
||||||
|
{% set page_subtitle = "This service is unavailable in the UK due to the Online Safety Act. Consider using a VPN to access this service." %}
|
||||||
|
{% endblock %}
|
Loading…
x
Reference in New Issue
Block a user