aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorMarvin Borner2019-04-13 19:17:00 +0200
committerMarvin Borner2019-04-13 19:17:00 +0200
commit407cd889cada0154faaa06ff4372e237cf260cf7 (patch)
tree29a7d54576a2872d4fd735022fc3a477ff96d0c3
parenta1e2fe500b3d3947d05e16698488f99e49f29847 (diff)
Added live counter for brute force detection
-rw-r--r--src/main/kotlin/App.kt21
-rw-r--r--src/main/resources/js/login.js7
-rw-r--r--src/main/resources/views/login.rocker.html12
3 files changed, 31 insertions, 9 deletions
diff --git a/src/main/kotlin/App.kt b/src/main/kotlin/App.kt
index a958479..ce964e0 100644
--- a/src/main/kotlin/App.kt
+++ b/src/main/kotlin/App.kt
@@ -49,7 +49,7 @@ fun main() {
*/
get(
"/login",
- { ctx -> ctx.render("login.rocker.html", model("message", "")) },
+ { ctx -> ctx.render("login.rocker.html", model("message", "", "counter", 0)) },
roles(Roles.GUEST)
)
@@ -208,23 +208,32 @@ fun login(ctx: Context) {
val difference = Interval(it.first.toInstant(), Instant()).toDuration().standardMinutes.toInt()
if (difference < 60) lastHourAttempts += 1
}
- val threshold = 4f.pow(lastHourAttempts)
+ val nextThreshold = 4f.pow(lastHourAttempts + 1)
- if (lastAttemptDifference > threshold) {
+ if (lastAttemptDifference > 4f.pow(lastHourAttempts)) {
if (databaseController.checkUser(username, password)) {
ctx.cookieStore("uuid", databaseController.getUUID(username))
ctx.cookieStore("username", username)
- ctx.render("login.rocker.html", model("message", "Login succeeded!"))
+ ctx.render("login.rocker.html", model("message", "Login succeeded!", "counter", 0))
} else {
databaseController.loginAttempt(DateTime(), requestIp)
- ctx.render("login.rocker.html", model("message", "Login failed!"))
+ ctx.render(
+ "login.rocker.html",
+ model(
+ "message",
+ "Login failed!",
+ "counter", if (nextThreshold / 60 > 60) 3600 else nextThreshold.toInt()
+ )
+ )
}
} else {
databaseController.loginAttempt(DateTime(), requestIp)
ctx.render(
"login.rocker.html",
model(
- "message", "Please try again in ${if (threshold / 60 > 60) "3600" else threshold.toString()} seconds."
+ "message",
+ "Too many request.",
+ "counter", if (nextThreshold / 60 > 60) 3600 else nextThreshold.toInt()
)
)
}
diff --git a/src/main/resources/js/login.js b/src/main/resources/js/login.js
new file mode 100644
index 0000000..f4e2bce
--- /dev/null
+++ b/src/main/resources/js/login.js
@@ -0,0 +1,7 @@
+const tryAgain = document.getElementById("tryAgain");
+const countdown = document.getElementById("counter");
+
+setInterval(() => {
+ if (Number(countdown.innerText) === 0) tryAgain.style.display = "none";
+ countdown.innerText = Number(countdown.innerText) - 1;
+}, 1000);
diff --git a/src/main/resources/views/login.rocker.html b/src/main/resources/views/login.rocker.html
index 66d9ba2..23a9aff 100644
--- a/src/main/resources/views/login.rocker.html
+++ b/src/main/resources/views/login.rocker.html
@@ -1,12 +1,17 @@
-@args (String message)
+@args (String message, Integer counter)
+@js => {
+<script>const counter = @counter;</script>
+<script src="/js/login.js"></script>
+}
-@layout.template("Login", RockerContent.NONE, RockerContent.NONE) -> {
+@layout.template("Login", RockerContent.NONE, js) -> {
<form action="login" id="login-form" method="post">
<div>
<label for="username">Username:</label>
<input id="username" name="username" type="text"/>
-
+ </div>
+ <div>
<label for="password">Password:</label>
<input id="password" name="password" type="password"/>
</div>
@@ -15,6 +20,7 @@
@if(message.length() > 0) {
<small>@message</small>
+ <small id="tryAgain">Please try again in <span id="counter">@counter</span> seconds.</small>
}
</form>
}