diff options
author | Marvin Borner | 2019-04-13 19:17:00 +0200 |
---|---|---|
committer | Marvin Borner | 2019-04-13 19:17:00 +0200 |
commit | 407cd889cada0154faaa06ff4372e237cf260cf7 (patch) | |
tree | 29a7d54576a2872d4fd735022fc3a477ff96d0c3 | |
parent | a1e2fe500b3d3947d05e16698488f99e49f29847 (diff) |
Added live counter for brute force detection
-rw-r--r-- | src/main/kotlin/App.kt | 21 | ||||
-rw-r--r-- | src/main/resources/js/login.js | 7 | ||||
-rw-r--r-- | src/main/resources/views/login.rocker.html | 12 |
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> } |