Added basic spam protection.
This commit is contained in:
parent
59e60885a8
commit
7af0708c40
86
source/app.d
86
source/app.d
|
@ -41,19 +41,43 @@ void main() {
|
|||
}
|
||||
|
||||
void handleVisitorLog(ref HttpRequestContext ctx) {
|
||||
infoF!"Got visitor log from %s"(ctx.request.remoteAddress);
|
||||
JSONValue logBody = ctx.request.readBodyAsJson();
|
||||
string name = logBody.object["name"].str;
|
||||
if (name.length > 32) {
|
||||
ctx.response.setStatus(HttpStatus.BAD_REQUEST);
|
||||
ctx.response.writeBodyString("Name is too long.");
|
||||
return;
|
||||
}
|
||||
string message = logBody.object["message"].str;
|
||||
string remoteAddress = "UNKNOWN";
|
||||
if (ctx.request.remoteAddress !is null) {
|
||||
remoteAddress = ctx.request.remoteAddress.toString();
|
||||
if (message.length > 255) {
|
||||
ctx.response.setStatus(HttpStatus.BAD_REQUEST);
|
||||
ctx.response.writeBodyString("Message is too long.");
|
||||
return;
|
||||
}
|
||||
if (!ctx.request.hasHeader("X-Forwarded-For")) {
|
||||
ctx.response.setStatus(HttpStatus.FORBIDDEN);
|
||||
ctx.response.writeBodyString("Missing remote IP");
|
||||
return;
|
||||
}
|
||||
string remoteAddress = ctx.request.getHeader("X-Forwarded-For");
|
||||
LogEntry[] recentLogsByThisAddress = getRecentLogEntriesByRemoteAddress(remoteAddress);
|
||||
SysTime now = Clock.currTime();
|
||||
if (recentLogsByThisAddress.length > 0 && now - recentLogsByThisAddress[0].createdAt < minutes(1)) {
|
||||
ctx.response.setStatus(HttpStatus.TOO_MANY_REQUESTS);
|
||||
return;
|
||||
}
|
||||
insertLogEntry(remoteAddress, name, message);
|
||||
}
|
||||
|
||||
void handleLogbookRequest(ref HttpRequestContext ctx) {
|
||||
LogEntry[] entries = getRecentLogEntries();
|
||||
uint limit = ctx.request.getParamAs!uint("limit", 5);
|
||||
if (limit > 100) {
|
||||
ctx.response.setStatus(HttpStatus.BAD_REQUEST);
|
||||
ctx.response.writeBodyString("Limit is too large.");
|
||||
return;
|
||||
}
|
||||
uint offset = ctx.request.getParamAs!uint("offset", 0);
|
||||
LogEntry[] entries = getRecentLogEntries(limit, offset);
|
||||
JSONValue entriesJson = JSONValue(JSONValue[].init);
|
||||
foreach (LogEntry entry; entries) {
|
||||
entriesJson.array ~= entry.toJson();
|
||||
|
@ -79,6 +103,19 @@ struct LogEntry {
|
|||
obj["message"] = JSONValue(message);
|
||||
return obj;
|
||||
}
|
||||
|
||||
static LogEntry fromDbRow(ref Row row) {
|
||||
LogEntry entry;
|
||||
entry.id = row.peek!ulong(0);
|
||||
string createdAtStr = row.peek!string(1);
|
||||
string isoCreatedAt = createdAtStr[0 .. 4] ~ createdAtStr[5 .. 7] ~ createdAtStr[8 .. 10] ~ 'T' ~
|
||||
createdAtStr[11 .. 13] ~ createdAtStr[14 .. 16] ~ createdAtStr[17 .. $];
|
||||
entry.createdAt = SysTime.fromISOString(isoCreatedAt);
|
||||
entry.remoteAddress = row.peek!string(2);
|
||||
entry.name = row.peek!string(3);
|
||||
entry.message = row.peek!string(4);
|
||||
return entry;
|
||||
}
|
||||
}
|
||||
|
||||
void initDb() {
|
||||
|
@ -111,21 +148,32 @@ SQL");
|
|||
infoF!"Added log entry for %s @ %s"(name, remoteAddress);
|
||||
}
|
||||
|
||||
LogEntry[] getRecentLogEntries() {
|
||||
LogEntry[] findAllByQuery(string query) {
|
||||
import std.array : Appender, appender;
|
||||
Database db = Database("logbook.sqlite");
|
||||
ResultRange results = db.execute("SELECT * FROM log_entry ORDER BY created_at DESC LIMIT 5");
|
||||
LogEntry[] entries;
|
||||
ResultRange results = db.execute(query);
|
||||
Appender!(LogEntry[]) app = appender!(LogEntry[])();
|
||||
foreach (Row row; results) {
|
||||
LogEntry entry;
|
||||
entry.id = row.peek!ulong(0);
|
||||
string createdAtStr = row.peek!string(1);
|
||||
string isoCreatedAt = createdAtStr[0 .. 4] ~ createdAtStr[5 .. 7] ~ createdAtStr[8 .. 10] ~ 'T' ~
|
||||
createdAtStr[11 .. 13] ~ createdAtStr[14 .. 16] ~ createdAtStr[17 .. $];
|
||||
entry.createdAt = SysTime.fromISOString(isoCreatedAt);
|
||||
entry.remoteAddress = row.peek!string(2);
|
||||
entry.name = row.peek!string(3);
|
||||
entry.message = row.peek!string(4);
|
||||
entries ~= entry;
|
||||
app ~= LogEntry.fromDbRow(row);
|
||||
}
|
||||
return entries;
|
||||
return app.data();
|
||||
}
|
||||
|
||||
LogEntry[] getRecentLogEntries(uint limit, uint offset) {
|
||||
import std.format;
|
||||
string query = format!"SELECT * FROM log_entry ORDER BY created_at DESC LIMIT %d OFFSET %d"(limit, offset);
|
||||
return findAllByQuery(query);
|
||||
}
|
||||
|
||||
LogEntry[] getRecentLogEntriesByRemoteAddress(string remoteAddress) {
|
||||
import std.array : Appender, appender;
|
||||
Database db = Database("logbook.sqlite");
|
||||
Statement stmt = db.prepare("SELECT * FROM log_entry WHERE remote_address = :addr ORDER BY created_at DESC LIMIT 10");
|
||||
stmt.bind(0, remoteAddress);
|
||||
ResultRange results = stmt.execute();
|
||||
Appender!(LogEntry[]) app = appender!(LogEntry[])();
|
||||
foreach (Row row; results) {
|
||||
app ~= LogEntry.fromDbRow(row);
|
||||
}
|
||||
return app.data();
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue