aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorMarvin Borner2019-05-02 22:37:13 +0200
committerMarvin Borner2019-05-02 22:37:13 +0200
commita6fc766d6eb808584c7cebea216f683b53f8e99b (patch)
tree484faadd60a0df0b648a27e130455d800512391d /src
parent22797dde022a398b34a91ba24e2bdd89be3f36f8 (diff)
Added user registration via admin
Co-authored-by: LarsVomMars <lars@kroenner.eu>
Diffstat (limited to 'src')
-rw-r--r--src/main/kotlin/App.kt25
-rw-r--r--src/main/kotlin/DatabaseController.kt44
-rw-r--r--src/main/kotlin/UserHandler.kt53
-rw-r--r--src/main/resources/views/index.rocker.html5
-rw-r--r--src/main/resources/views/login.rocker.html2
-rw-r--r--src/main/resources/views/register.rocker.html32
6 files changed, 146 insertions, 15 deletions
diff --git a/src/main/kotlin/App.kt b/src/main/kotlin/App.kt
index 1aa150b..133c27b 100644
--- a/src/main/kotlin/App.kt
+++ b/src/main/kotlin/App.kt
@@ -81,7 +81,7 @@ fun main() {
/**
* Renders the login page
*/
- get("/login", { ctx ->
+ get("/user/login", { ctx ->
if (userHandler.getVerifiedUserId(ctx) > 0 || !databaseController.isSetup()) ctx.redirect("/")
else ctx.render(
"login.rocker.html",
@@ -92,18 +92,33 @@ fun main() {
/**
* Endpoint for user authentication
*/
- post("/login", userHandler::login, roles(Roles.GUEST))
+ post("/user/login", userHandler::login, roles(Roles.GUEST))
/**
* Logs the user out
*/
- get("/logout", userHandler::logout, roles(Roles.USER))
+ get("/user/logout", userHandler::logout, roles(Roles.USER))
+
+ /**
+ * Renders the registration page
+ */
+ get("/user/register", userHandler::renderRegistration, roles(Roles.GUEST)) // use setup page with additional parameter?
+
+ /**
+ * Registers new user
+ */
+ post("/user/register", userHandler::register, roles(Roles.GUEST))
+
+ /**
+ * Adds part of a new user (username) to database
+ */
+ get("/user/add", databaseController::indexUserRegistration, roles(Roles.ADMIN)) // TODO: Create post request with admin interface
/**
* Renders the setup page (only on initial use)
*/
get("/setup", { ctx ->
- if (databaseController.isSetup()) ctx.redirect("/login")
+ if (databaseController.isSetup()) ctx.redirect("/user/login")
else ctx.render(
"setup.rocker.html",
model("message", "")
@@ -157,7 +172,7 @@ fun roleManager(handler: Handler, ctx: Context, permittedRoles: Set<Role>) {
ctx
)
//ctx.host()!!.contains("localhost") -> handler.handle(ctx) // DEBUG
- else -> ctx.status(401).redirect("/login")
+ else -> ctx.status(401).redirect("/user/login")
}
}
diff --git a/src/main/kotlin/DatabaseController.kt b/src/main/kotlin/DatabaseController.kt
index cce9601..5ab0743 100644
--- a/src/main/kotlin/DatabaseController.kt
+++ b/src/main/kotlin/DatabaseController.kt
@@ -1,6 +1,7 @@
package space.anity
import at.favre.lib.crypto.bcrypt.*
+import io.javalin.*
import org.jetbrains.exposed.sql.*
import org.jetbrains.exposed.sql.transactions.*
import org.joda.time.*
@@ -43,6 +44,14 @@ class DatabaseController(dbFileLocation: String = "main.db") {
}
/**
+ * Database table indexing the soon-to-be registered users by username
+ */
+ object UserRegistration : Table() {
+ val id = integer("id").autoIncrement().primaryKey()
+ val username = varchar("username", 24).uniqueIndex()
+ }
+
+ /**
* Database table declaring available roles
*/
object RolesData : Table() {
@@ -78,6 +87,7 @@ class DatabaseController(dbFileLocation: String = "main.db") {
FileLocation,
UserData,
UserRoles,
+ UserRegistration,
RolesData,
LoginAttempts,
General
@@ -110,6 +120,40 @@ class DatabaseController(dbFileLocation: String = "main.db") {
}
/**
+ * Checks whether the user is allowed to register
+ * TODO: Verify registration via token
+ */
+ fun isUserRegistrationValid(usernameString: String): Boolean {
+ return transaction {
+ try {
+ if (UserData.select { UserData.username eq usernameString }.empty()) {
+ val username = UserRegistration.select { UserRegistration.username eq usernameString }.map { it[UserRegistration.username] }[0]
+ username == usernameString
+ } else false
+ } catch (err: Exception) {
+ false
+ }
+ }
+ }
+
+ /**
+ * Adds a user to the registration table
+ */
+ fun indexUserRegistration(ctx: Context) {
+ transaction {
+ UserRegistration.insert {
+ it[username] = ctx.queryParam("username", "").toString()
+ }
+ }
+ }
+
+ fun removeRegistrationIndex(usernameString: String) {
+ transaction {
+ UserRegistration.deleteWhere { UserRegistration.username eq usernameString }
+ }
+ }
+
+ /**
* Tests whether the password [passwordString] of the user [usernameString] is correct
*/
fun checkUser(usernameString: String, passwordString: String): Boolean {
diff --git a/src/main/kotlin/UserHandler.kt b/src/main/kotlin/UserHandler.kt
index 1309348..5f369b1 100644
--- a/src/main/kotlin/UserHandler.kt
+++ b/src/main/kotlin/UserHandler.kt
@@ -1,7 +1,7 @@
package space.anity
import io.javalin.*
-import io.javalin.rendering.template.*
+import io.javalin.rendering.template.TemplateUtil.model
import org.joda.time.*
import java.util.logging.*
import kotlin.math.*
@@ -41,7 +41,7 @@ class UserHandler {
databaseController.loginAttempt(DateTime(), requestIp)
ctx.render(
"login.rocker.html",
- TemplateUtil.model(
+ model(
"message",
"Login failed!",
"counter", if (nextThreshold / 60 > 60) 3600 else nextThreshold.toInt()
@@ -52,7 +52,7 @@ class UserHandler {
databaseController.loginAttempt(DateTime(), requestIp)
ctx.render(
"login.rocker.html",
- TemplateUtil.model(
+ model(
"message",
"Too many request.",
"counter", if (nextThreshold / 60 > 60) 3600 else nextThreshold.toInt()
@@ -80,17 +80,17 @@ class UserHandler {
if (password == verifyPassword) {
if (databaseController.createUser(username, password, "ADMIN")) {
databaseController.toggleSetup()
- ctx.redirect("/login")
+ ctx.redirect("/user/login")
} else ctx.status(400).render(
"setup.rocker.html",
- TemplateUtil.model("message", "User already exists!")
+ model("message", "User already exists!")
)
} else ctx.status(400).render(
"setup.rocker.html",
- TemplateUtil.model("message", "Passwords do not match!")
+ model("message", "Passwords do not match!")
)
} catch (_: Exception) {
- ctx.status(400).render("setup.rocker.html", TemplateUtil.model("message", "An error occurred!"))
+ ctx.status(400).render("setup.rocker.html", model("message", "An error occurred!"))
}
}
@@ -103,4 +103,43 @@ class UserHandler {
) ctx.cookieStore("userId")
else -1
}
+
+ /**
+ * Renders the registration page
+ */
+ fun renderRegistration(ctx: Context) {
+ val username = ctx.queryParam("username", "")
+ if (username.isNullOrEmpty())
+ ctx.status(403).result("Please provide a valid username!")
+ else {
+ if (databaseController.isUserRegistrationValid(username)) ctx.render(
+ "register.rocker.html",
+ model(
+ "username", username,
+ "message", ""
+ )
+ ) else ctx.redirect("/user/login")
+ }
+ }
+
+ /**
+ * Registers a new user
+ */
+ fun register(ctx: Context) {
+ try {
+ val username = ctx.formParam("username").toString()
+ val password = ctx.formParam("password").toString()
+ val verifyPassword = ctx.formParam("verifyPassword").toString()
+
+ if (password == verifyPassword) {
+ if (databaseController.isUserRegistrationValid(username)) {
+ databaseController.createUser(username, password, "USER")
+ databaseController.removeRegistrationIndex(username)
+ ctx.redirect("/login")
+ } else ctx.status(401).result("This user is not authorized to register.")
+ } else ctx.status(400).result("The passwords don't match!")
+ } catch (_: Exception) {
+ ctx.status(400).result("An exception occured.")
+ }
+ }
}
diff --git a/src/main/resources/views/index.rocker.html b/src/main/resources/views/index.rocker.html
index cab6712..650a4b7 100644
--- a/src/main/resources/views/index.rocker.html
+++ b/src/main/resources/views/index.rocker.html
@@ -7,11 +7,12 @@
<div>
@if(username.length() > 0) {
- <a class="button" href="/logout">Logout</a>
+ <!-- TODO: Fix logout button? -->
+ <a class="button" href="/user/logout">Logout</a>
} else if (!(new DatabaseController()).isSetup()) {
<a class="button" href="/setup">Setup</a>
} else {
- <a class="button" href="/login">Login</a>
+ <a class="button" href="/user/login">Login</a>
}
<a class="button" href="/files/">Files</a>
diff --git a/src/main/resources/views/login.rocker.html b/src/main/resources/views/login.rocker.html
index feddbbc..a8b06be 100644
--- a/src/main/resources/views/login.rocker.html
+++ b/src/main/resources/views/login.rocker.html
@@ -9,7 +9,7 @@
<div class="flex">
<h1>Login</h1>
- <form action="/login" method="post">
+ <form action="/user/login" method="post">
<div>
<label for="username">Username:</label>
<input autocomplete="off" autofocus id="username" name="username" required type="text"/>
diff --git a/src/main/resources/views/register.rocker.html b/src/main/resources/views/register.rocker.html
new file mode 100644
index 0000000..6d314dd
--- /dev/null
+++ b/src/main/resources/views/register.rocker.html
@@ -0,0 +1,32 @@
+@args (String username, String message)
+
+@layout.template("Register", RockerContent.NONE, RockerContent.NONE) -> {
+<div class="flex">
+ <h1>Register</h1>
+
+ <form action="/user/register" method="post">
+ <h3>Please set a password for user "@username"</h3>
+ <div>
+ <input hidden name="username" type="text" value="@username"/>
+ </div>
+ <div>
+ <label for="password">Password:</label>
+ <input id="password" name="password" required type="password"/>
+ </div>
+ <div>
+ <label for="verifyPassword">Verify password:</label>
+ <input id="verifyPassword" name="verifyPassword" required type="password"/>
+ </div>
+
+ <div>
+ @if (message.length() > 0) {
+ <small>@message</small>
+ }
+ </div>
+
+ <div>
+ <button type="submit">Register</button>
+ </div>
+ </form>
+</div>
+}