Add rate limiting functionality
Introduces a new 'rate_limit' table to track request counts by IP and email. Adds `RateLimitQuery` class for querying and inserting rate limits, and `RateLimitEntryDTO` for passing rate limit data.
This commit is contained in:
parent
4f3db5ae8b
commit
f0c84e809f
|
|
@ -12,8 +12,35 @@ public class Database {
|
||||||
|
|
||||||
public static void createTables() {
|
public static void createTables() {
|
||||||
String[] createTables = {
|
String[] createTables = {
|
||||||
"CREATE TABLE IF NOT EXISTS verify_form (e_mail VARCHAR(256), verification_code INT, formId INT, PRIMARY KEY(e_mail, verification_code))",
|
// language=SQL
|
||||||
"CREATE TABLE IF NOT EXISTS form (formId INT AUTO_INCREMENT, creation_date BIGINT, form_json TEXT, form_class VARCHAR(64), PRIMARY KEY(formId))"
|
"""
|
||||||
|
CREATE TABLE IF NOT EXISTS verify_form(
|
||||||
|
e_mail VARCHAR(256),
|
||||||
|
verification_code INT,
|
||||||
|
formId INT,
|
||||||
|
PRIMARY KEY(e_mail, verification_code)
|
||||||
|
)
|
||||||
|
""",
|
||||||
|
// language=SQL
|
||||||
|
"""
|
||||||
|
CREATE TABLE IF NOT EXISTS form(
|
||||||
|
formId INT AUTO_INCREMENT,
|
||||||
|
creation_date BIGINT,
|
||||||
|
form_json TEXT,
|
||||||
|
form_class VARCHAR(64),
|
||||||
|
PRIMARY KEY(formId)
|
||||||
|
)
|
||||||
|
""",
|
||||||
|
// language=SQL
|
||||||
|
"""
|
||||||
|
CREATE TABLE IF NOT EXISTS rate_limit(
|
||||||
|
id INT AUTO_INCREMENT,
|
||||||
|
time TIMESTAMP,
|
||||||
|
ip VARCHAR(45),
|
||||||
|
mail VARCHAR(256),
|
||||||
|
PRIMARY KEY(id)
|
||||||
|
)
|
||||||
|
"""
|
||||||
};
|
};
|
||||||
Connection connection = DatabaseConnection.getConnection();
|
Connection connection = DatabaseConnection.getConnection();
|
||||||
for (String query : createTables) {
|
for (String query : createTables) {
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,6 @@
|
||||||
|
package com.alttd.forms.mail.rate_limitter;
|
||||||
|
|
||||||
|
import java.time.Instant;
|
||||||
|
|
||||||
|
public record RateLimitEntryDTO(Instant time, String ip, String mail) {
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,59 @@
|
||||||
|
package com.alttd.forms.mail.rate_limitter;
|
||||||
|
|
||||||
|
import org.slf4j.Logger;
|
||||||
|
import org.slf4j.LoggerFactory;
|
||||||
|
|
||||||
|
import java.sql.*;
|
||||||
|
import java.time.Instant;
|
||||||
|
|
||||||
|
public class RateLimitQuery {
|
||||||
|
|
||||||
|
private static final Logger logger = LoggerFactory.getLogger(RateLimitQuery.class);
|
||||||
|
|
||||||
|
public int getIpHits(Connection connection, String ip, Instant after) throws SQLException {
|
||||||
|
String sql = "SELECT COUNT(*) AS hits FROM rate_limit WHERE ip = ? AND time > ?";
|
||||||
|
try (PreparedStatement stmt = connection.prepareStatement(sql)) {
|
||||||
|
stmt.setString(1, ip);
|
||||||
|
stmt.setTimestamp(2, Timestamp.from(after));
|
||||||
|
ResultSet resultSet = stmt.executeQuery();
|
||||||
|
if (!resultSet.next()) {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
return resultSet.getInt("hits");
|
||||||
|
} catch (SQLException e) {
|
||||||
|
logger.error("Failed get ip hits query for ip: {}", ip, e);
|
||||||
|
throw e;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public int getMailHits(Connection connection, String mail, Instant after) throws SQLException {
|
||||||
|
String sql = "SELECT COUNT(*) AS hits FROM rate_limit WHERE mail = ? AND time > ?";
|
||||||
|
try (PreparedStatement stmt = connection.prepareStatement(sql)) {
|
||||||
|
stmt.setString(1, mail);
|
||||||
|
stmt.setTimestamp(2, Timestamp.from(after));
|
||||||
|
ResultSet resultSet = stmt.executeQuery();
|
||||||
|
if (!resultSet.next()) {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
return resultSet.getInt("hits");
|
||||||
|
} catch (SQLException e) {
|
||||||
|
logger.error("Failed get mail hits query for ip: {}", mail, e);
|
||||||
|
throw e;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean insertRateLimitEntry(Connection connection, RateLimitEntryDTO entry) throws SQLException {
|
||||||
|
String sql = "INSERT INTO rate_limit (time, ip, mail) VALUES (?, ?, ?)";
|
||||||
|
try {
|
||||||
|
PreparedStatement stmt = connection.prepareStatement(sql);
|
||||||
|
stmt.setTimestamp(1, Timestamp.from(entry.time()));
|
||||||
|
stmt.setString(2, entry.ip());
|
||||||
|
stmt.setString(3, entry.mail());
|
||||||
|
return stmt.executeUpdate() > 0;
|
||||||
|
} catch (SQLException e) {
|
||||||
|
logger.error("Failed to store rate limit for ip: {}, mail: {}, time: {}", entry.ip(), entry.mail(), entry.time(), e);
|
||||||
|
throw e;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
Loading…
Reference in New Issue
Block a user