diff options
author | Marvin Borner | 2019-05-02 22:37:13 +0200 |
---|---|---|
committer | Marvin Borner | 2019-05-02 22:37:13 +0200 |
commit | a6fc766d6eb808584c7cebea216f683b53f8e99b (patch) | |
tree | 484faadd60a0df0b648a27e130455d800512391d /src | |
parent | 22797dde022a398b34a91ba24e2bdd89be3f36f8 (diff) |
Added user registration via admin
Co-authored-by: LarsVomMars <lars@kroenner.eu>
Diffstat (limited to 'src')
-rw-r--r-- | src/main/kotlin/App.kt | 25 | ||||
-rw-r--r-- | src/main/kotlin/DatabaseController.kt | 44 | ||||
-rw-r--r-- | src/main/kotlin/UserHandler.kt | 53 | ||||
-rw-r--r-- | src/main/resources/views/index.rocker.html | 5 | ||||
-rw-r--r-- | src/main/resources/views/login.rocker.html | 2 | ||||
-rw-r--r-- | src/main/resources/views/register.rocker.html | 32 |
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> +} |