aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorMarvin Borner2019-05-04 19:10:18 +0200
committerMarvin Borner2019-05-04 19:10:18 +0200
commitb7540fb2b1bbe016d23b8a7f3e7ab3edafb219c8 (patch)
treeda32ba6ac7467bc7d39f5209c7734ded79911260
parent04d0cb43f6a3ede1a61309cf17d78d189caa9dd4 (diff)
Fixed major security issues
Co-authored-by: LarsVomMars <lars@kroenner.eu>
-rw-r--r--src/main/kotlin/App.kt36
-rw-r--r--src/main/kotlin/DatabaseController.kt27
-rw-r--r--src/main/kotlin/FileController.kt2
-rw-r--r--src/main/kotlin/UserHandler.kt10
-rw-r--r--src/main/resources/js/files.js4
-rw-r--r--src/main/resources/views/index.rocker.html1
-rw-r--r--src/main/resources/views/register.rocker.html3
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>