{{ item.ip }}
+ {{ item.reason|markdown|safe }}
+
+ diff --git a/crates/app/src/assets.rs b/crates/app/src/assets.rs index 225c842..6036787 100644 --- a/crates/app/src/assets.rs +++ b/crates/app/src/assets.rs @@ -57,6 +57,7 @@ pub const TIMELINES_POPULAR: &str = include_str!("./public/html/timelines/popula pub const MOD_AUDIT_LOG: &str = include_str!("./public/html/mod/audit_log.html"); pub const MOD_REPORTS: &str = include_str!("./public/html/mod/reports.html"); pub const MOD_FILE_REPORT: &str = include_str!("./public/html/mod/file_report.html"); +pub const MOD_IP_BANS: &str = include_str!("./public/html/mod/ip_bans.html"); // langs pub const LANG_EN_US: &str = include_str!("./langs/en-US.toml"); @@ -180,6 +181,7 @@ pub(crate) async fn write_assets(config: &Config) -> PathBufD { write_template!(html_path->"mod/audit_log.html"(crate::assets::MOD_AUDIT_LOG) -d "mod" --config=config); write_template!(html_path->"mod/reports.html"(crate::assets::MOD_REPORTS) --config=config); write_template!(html_path->"mod/file_report.html"(crate::assets::MOD_FILE_REPORT) --config=config); + write_template!(html_path->"mod/ip_bans.html"(crate::assets::MOD_IP_BANS) --config=config); html_path } diff --git a/crates/app/src/langs/en-US.toml b/crates/app/src/langs/en-US.toml index 6a6c1cc..c6cf324 100644 --- a/crates/app/src/langs/en-US.toml +++ b/crates/app/src/langs/en-US.toml @@ -11,6 +11,7 @@ version = "1.0.0" "general:link.reference" = "Reference" "general:link.audit_log" = "Audit log" "general:link.reports" = "Reports" +"general:link.ip_bans" = "IP bans" "general:action.save" = "Save" "general:action.delete" = "Delete" "general:action.back" = "Back" diff --git a/crates/app/src/public/html/macros.html b/crates/app/src/public/html/macros.html index 4969c27..a90103f 100644 --- a/crates/app/src/public/html/macros.html +++ b/crates/app/src/public/html/macros.html @@ -87,6 +87,11 @@ show_lhs=true) -%} {{ icon "flag" }} {{ text "general:link.reports" }} + + + {{ icon "ban" }} + {{ text "general:link.ip_bans" }} + {% endif %} {{ config.name }} diff --git a/crates/app/src/public/html/mod/ip_bans.html b/crates/app/src/public/html/mod/ip_bans.html new file mode 100644 index 0000000..c1f32bf --- /dev/null +++ b/crates/app/src/public/html/mod/ip_bans.html @@ -0,0 +1,70 @@ +{% import "macros.html" as macros %} {% extends "root.html" %} {% block head %} +
{{ item.ip }}
+ {{ item.reason|markdown|safe }}
+
+ {{ token[0] }}
+
+ {% else %}
+ {{ token[0] }}
+ {% endif %}
+
{{ token[2] }}
diff --git a/crates/app/src/public/html/root.html b/crates/app/src/public/html/root.html
index df44a98..ff0fe51 100644
--- a/crates/app/src/public/html/root.html
+++ b/crates/app/src/public/html/root.html
@@ -104,7 +104,7 @@
atto["hooks::long_text.init"]();
atto["hooks::alt"]();
atto["hooks::online_indicator"]();
- // atto["hooks::ips"]();
+ atto["hooks::ips"]();
atto["hooks::check_reactions"]();
atto["hooks::tabs"]();
atto["hooks::partial_embeds"]();
diff --git a/crates/app/src/public/js/atto.js b/crates/app/src/public/js/atto.js
index ccf7757..f519e2c 100644
--- a/crates/app/src/public/js/atto.js
+++ b/crates/app/src/public/js/atto.js
@@ -408,6 +408,62 @@ media_theme_pref();
}
});
+ self.define("hooks::ips", ({ $ }) => {
+ for (const anchor of Array.from(document.querySelectorAll("a"))) {
+ try {
+ const href = new URL(anchor.href);
+
+ if (
+ href.pathname.startsWith("/api/v1/auth/profile/find_by_ip/")
+ ) {
+ const ban_button = document.createElement("button");
+ ban_button.innerText = "Ban IP";
+ ban_button.className = "quaternary red small";
+ anchor.parentElement.parentElement.appendChild(ban_button);
+
+ ban_button.addEventListener("click", async (e) => {
+ e.preventDefault();
+
+ $.ban_ip(
+ href.pathname.replace(
+ "/api/v1/auth/profile/find_by_ip/",
+ "",
+ ),
+ );
+ });
+ }
+ } catch {}
+ }
+ });
+
+ self.define("ban_ip", async ({ $ }, ip) => {
+ const reason = await $.prompt(
+ "Please explain your reason for banning this IP below:",
+ );
+
+ if (!reason) {
+ return;
+ }
+
+ fetch(`/api/v1/bans/${ip}`, {
+ method: "POST",
+ headers: {
+ "Content-Type": "application/json",
+ },
+ body: JSON.stringify({
+ ip,
+ reason,
+ }),
+ })
+ .then((res) => res.json())
+ .then((res) => {
+ trigger("app::toast", [
+ res.success ? "success" : "error",
+ res.message,
+ ]);
+ });
+ });
+
self.define(
"hooks::attach_to_partial",
({ $ }, partial, full, attach, wrapper, page, run_on_load) => {
diff --git a/crates/app/src/routes/api/v1/auth/profile.rs b/crates/app/src/routes/api/v1/auth/profile.rs
index c2d5006..11ded2b 100644
--- a/crates/app/src/routes/api/v1/auth/profile.rs
+++ b/crates/app/src/routes/api/v1/auth/profile.rs
@@ -33,6 +33,27 @@ pub async fn redirect_from_id(
}
}
+pub async fn redirect_from_ip(
+ jar: CookieJar,
+ Extension(data): Extension