diff options
author | Marvin Borner | 2019-05-04 19:10:18 +0200 |
---|---|---|
committer | Marvin Borner | 2019-05-04 19:10:18 +0200 |
commit | b7540fb2b1bbe016d23b8a7f3e7ab3edafb219c8 (patch) | |
tree | da32ba6ac7467bc7d39f5209c7734ded79911260 | |
parent | 04d0cb43f6a3ede1a61309cf17d78d189caa9dd4 (diff) |
Fixed major security issues
Co-authored-by: LarsVomMars <lars@kroenner.eu>
-rw-r--r-- | src/main/kotlin/App.kt | 36 | ||||
-rw-r--r-- | src/main/kotlin/DatabaseController.kt | 27 | ||||
-rw-r--r-- | src/main/kotlin/FileController.kt | 2 | ||||
-rw-r--r-- | src/main/kotlin/UserHandler.kt | 10 | ||||
-rw-r--r-- | src/main/resources/js/files.js | 4 | ||||
-rw-r--r-- | src/main/resources/views/index.rocker.html | 1 | ||||
-rw-r--r-- | src/main/resources/views/register.rocker.html | 3 |
7 files changed, 48 insertions, 35 deletions
diff --git a/src/main/kotlin/App.kt b/src/main/kotlin/App.kt index 95dfdca..f3cb8a0 100644 --- a/src/main/kotlin/App.kt +++ b/src/main/kotlin/App.kt @@ -46,20 +46,20 @@ fun main(args: Array<String>) { ctx.contentType("text/css") ctx.result(Thread.currentThread().contextClassLoader.getResourceAsStream("css/" + ctx.splat(0))) }, - roles(Roles.GUEST) + roles(Roles.GUEST, Roles.USER) ) get( "/js/*", { ctx -> ctx.contentType("text/js") ctx.result(Thread.currentThread().contextClassLoader.getResourceAsStream("js/" + ctx.splat(0))) }, - roles(Roles.GUEST) + roles(Roles.GUEST, Roles.USER) ) get( "/fonts/*", { ctx -> ctx.result(Thread.currentThread().contextClassLoader.getResourceAsStream("fonts/" + ctx.splat(0))) }, - roles(Roles.GUEST) + roles(Roles.GUEST, Roles.USER) ) /** @@ -70,12 +70,12 @@ fun main(args: Array<String>) { "index.rocker.html", model("username", databaseController.getUsername(userHandler.getVerifiedUserId(ctx))) ) - }, roles(Roles.GUEST)) + }, roles(Roles.GUEST, Roles.USER)) /** * Renders the login page */ - get("/user/login", userHandler::renderLogin, roles(Roles.GUEST)) + get("/user/login", userHandler::renderLogin, roles(Roles.GUEST, Roles.USER)) /** * Endpoint for user authentication @@ -99,12 +99,9 @@ fun main(args: Array<String>) { /** * Adds part of a new user (username) to database + * TODO: Create post request with admin interface */ - get( - "/user/add", - databaseController::indexUserRegistration, - roles(Roles.ADMIN) - ) // TODO: Create post request with admin interface + get("/user/add", databaseController::indexUserRegistration, roles(Roles.ADMIN)) /** * Renders the setup page (only on initial use) @@ -139,12 +136,12 @@ fun main(args: Array<String>) { /** * Shares file in directory */ - post("/share", fileController::handleSharedFile, roles(Roles.GUEST)) + post("/share", fileController::handleSharedFile, roles(Roles.USER)) /** * Shows the shared file */ - get("/shared", fileController::renderShared, roles(Roles.GUEST)) + get("/shared", fileController::renderShared, roles(Roles.GUEST, Roles.USER)) } } @@ -152,14 +149,13 @@ fun main(args: Array<String>) { * Sets up the roles with the database and declares the handling of roles */ fun roleManager(handler: Handler, ctx: Context, permittedRoles: Set<Role>) { - when { - userHandler.getVerifiedUserId(ctx) == ctx.cookieStore("userId") ?: "userId" -> handler.handle(ctx) - databaseController.getRoles(userHandler.getVerifiedUserId(ctx)).any { it in permittedRoles } -> handler.handle( - ctx - ) - // ctx.host()!!.contains("localhost") -> handler.handle(ctx) // DEBUG - else -> ctx.status(401).redirect("/user/login") - } + if (userHandler.getVerifiedUserId(ctx) == ctx.cookieStore("userId") ?: "userId" + && databaseController.getRoles(userHandler.getVerifiedUserId(ctx)).any { it in permittedRoles } + ) handler.handle(ctx) + else if (userHandler.getVerifiedUserId(ctx) != ctx.cookieStore("userId") ?: "userId" + && databaseController.getRoles(userHandler.getVerifiedUserId(ctx)).any { it in permittedRoles } + ) handler.handle(ctx) + else ctx.status(401).redirect("/user/login") } /** diff --git a/src/main/kotlin/DatabaseController.kt b/src/main/kotlin/DatabaseController.kt index 8c0550a..4b444ef 100644 --- a/src/main/kotlin/DatabaseController.kt +++ b/src/main/kotlin/DatabaseController.kt @@ -49,6 +49,7 @@ class DatabaseController(dbFileLocation: String = "main.db") { object UserRegistration : Table() { val id = integer("id").autoIncrement().primaryKey() val username = varchar("username", 24).uniqueIndex() + val token = varchar("token", 64).uniqueIndex() } /** @@ -121,12 +122,13 @@ class DatabaseController(dbFileLocation: String = "main.db") { /** * Checks whether the user is allowed to register - * TODO: Verify registration via token */ - fun isUserRegistrationValid(usernameString: String): Boolean { + fun isUserRegistrationValid(usernameString: String, tokenString: String): Boolean { return transaction { try { - if (UserData.select { UserData.username eq usernameString }.empty()) { + if (UserData.select { UserData.username eq usernameString }.empty() && + UserRegistration.select { UserRegistration.token eq tokenString }.map { it[UserRegistration.token] }[0] == tokenString + ) { usernameString == UserRegistration.select { UserRegistration.username eq usernameString }.map { it[UserRegistration.username] }[0] } else false } catch (_: Exception) { @@ -139,11 +141,25 @@ class DatabaseController(dbFileLocation: String = "main.db") { * Adds a user to the registration table */ fun indexUserRegistration(ctx: Context) { + val usernameString = ctx.queryParam("username", "").toString() + val tokenString = generateRandomString() + var error = false + transaction { - UserRegistration.insert { - it[username] = ctx.queryParam("username", "").toString() + try { + UserRegistration.insert { + it[username] = usernameString + it[token] = tokenString + } + } catch (_: Exception) { + error = true } } + + if (error) ctx.result("User already exists") + else ctx.result( + "Registration url: " + "http://${ctx.host()}/user/register?username=$usernameString&token=$tokenString" + ) } /** @@ -237,7 +253,6 @@ class DatabaseController(dbFileLocation: String = "main.db") { userRoles.add(Roles.GUEST) } Roles.USER -> { - userRoles.add(Roles.GUEST) userRoles.add(Roles.USER) } Roles.ADMIN -> { diff --git a/src/main/kotlin/FileController.kt b/src/main/kotlin/FileController.kt index 9c2ee78..806cb59 100644 --- a/src/main/kotlin/FileController.kt +++ b/src/main/kotlin/FileController.kt @@ -223,7 +223,7 @@ class FileController { } /** - * Returns the access id of a file + * Returns the access id of the directory */ fun handleSharedFile(ctx: Context) { val filename = ctx.formParam("filename").toString() diff --git a/src/main/kotlin/UserHandler.kt b/src/main/kotlin/UserHandler.kt index a950860..1a81812 100644 --- a/src/main/kotlin/UserHandler.kt +++ b/src/main/kotlin/UserHandler.kt @@ -112,10 +112,13 @@ class UserHandler { */ fun renderRegistration(ctx: Context) { val username = ctx.queryParam("username", "") + val token = ctx.queryParam("token", "") + if (username.isNullOrEmpty()) ctx.status(403).result("Please provide a valid username!") + else if (token.isNullOrEmpty()) ctx.status(403).result("Please provide a valid token!") else { - if (databaseController.isUserRegistrationValid(username)) - ctx.render("register.rocker.html", model("username", username, "message", "")) + if (databaseController.isUserRegistrationValid(username, token)) + ctx.render("register.rocker.html", model("username", username, "token", token, "message", "")) else ctx.redirect("/user/login") } } @@ -126,11 +129,12 @@ class UserHandler { fun register(ctx: Context) { try { val username = ctx.formParam("username").toString() + val token = ctx.formParam("token").toString() val password = ctx.formParam("password").toString() val verifyPassword = ctx.formParam("verifyPassword").toString() if (password == verifyPassword) { - if (databaseController.isUserRegistrationValid(username)) { + if (databaseController.isUserRegistrationValid(username, token)) { databaseController.createUser(username, password, "USER") databaseController.removeRegistrationIndex(username) ctx.redirect("/user/login") diff --git a/src/main/resources/js/files.js b/src/main/resources/js/files.js index 16b59cb..0102296 100644 --- a/src/main/resources/js/files.js +++ b/src/main/resources/js/files.js @@ -23,9 +23,7 @@ drop.addEventListener('drop', e => { for (let i = 0; i < items.length; i++) { const item = items[i].webkitGetAsEntry(); const file = items[i].getAsFile(); - - // TODO: Consider using current date due to updated lastModified state at upload - const date = new Date(file.lastModified); + const date = new Date(); const row = document.getElementById("table").insertRow(-1); row.setAttribute("data-href", file.name); diff --git a/src/main/resources/views/index.rocker.html b/src/main/resources/views/index.rocker.html index 650a4b7..98a659e 100644 --- a/src/main/resources/views/index.rocker.html +++ b/src/main/resources/views/index.rocker.html @@ -7,7 +7,6 @@ <div> @if(username.length() > 0) { - <!-- TODO: Fix logout button? --> <a class="button" href="/user/logout">Logout</a> } else if (!(new DatabaseController()).isSetup()) { <a class="button" href="/setup">Setup</a> diff --git a/src/main/resources/views/register.rocker.html b/src/main/resources/views/register.rocker.html index 6d314dd..af3d127 100644 --- a/src/main/resources/views/register.rocker.html +++ b/src/main/resources/views/register.rocker.html @@ -1,4 +1,4 @@ -@args (String username, String message) +@args (String username, String token, String message) @layout.template("Register", RockerContent.NONE, RockerContent.NONE) -> { <div class="flex"> @@ -8,6 +8,7 @@ <h3>Please set a password for user "@username"</h3> <div> <input hidden name="username" type="text" value="@username"/> + <input hidden name="token" type="text" value="@token"/> </div> <div> <label for="password">Password:</label> |