diff options
author | Marvin Borner | 2019-04-10 17:03:15 +0200 |
---|---|---|
committer | Marvin Borner | 2019-04-10 17:03:15 +0200 |
commit | a177d54b4bde907ca5b155a5fb1541402e494218 (patch) | |
tree | 17c7404718a77792cd7a5cc87856e4fc414bc4e7 /src/main | |
parent | c88b980118b6bc99d631e35c332596848da4ff37 (diff) |
Added permanent login via cookies
Diffstat (limited to 'src/main')
-rw-r--r-- | src/main/kotlin/App.kt | 51 | ||||
-rw-r--r-- | src/main/kotlin/DatabaseController.kt | 58 | ||||
-rw-r--r-- | src/main/resources/views/login.rocker.html | 20 |
3 files changed, 112 insertions, 17 deletions
diff --git a/src/main/kotlin/App.kt b/src/main/kotlin/App.kt index 9cba0db..cf44bd2 100644 --- a/src/main/kotlin/App.kt +++ b/src/main/kotlin/App.kt @@ -22,7 +22,7 @@ private val log = Logger.getLogger("App.kt") fun main() { val app = Javalin.create() .enableStaticFiles("../resources/") - .accessManager { handler, ctx, permittedRoles -> setupRoles(handler, ctx, permittedRoles) } + .accessManager { handler, ctx, permittedRoles -> roleManager(handler, ctx, permittedRoles) } .start(7000) // Set up templating @@ -48,8 +48,19 @@ fun main() { //} }, roles(Roles.GUEST)) - get("/login", { ctx -> ctx.render("login.rocker.html") }, roles(Roles.GUEST)) - //post("/login", { ctx -> login(ctx) }) + /** + * Renders the login page + */ + get( + "/login", + { ctx -> ctx.render("login.rocker.html", model("message", "")) }, + roles(Roles.GUEST) + ) + + /** + * Endpoint for user authentication + */ + post("/login", { ctx -> login(ctx) }, roles(Roles.GUEST)) // TODO: brute-force protection /** * Sends a json object of filenames in [fileHome]s @@ -73,19 +84,25 @@ fun main() { /** * Sets up the roles with the database and declares the handling of roles */ -fun setupRoles(handler: Handler, ctx: Context, permittedRoles: Set<Role>) { - val userRole = databaseController.getRole("melvin") +fun roleManager(handler: Handler, ctx: Context, permittedRoles: Set<Role>) { + val userRole = databaseController.getRole(getUsername(ctx)) when { + getUsername(ctx) == ctx.cookieStore("username") ?: "username" -> handler.handle(ctx) permittedRoles.contains(userRole) -> handler.handle(ctx) - ctx.host()!!.contains("localhost") -> handler.handle(ctx) - else -> ctx.status(401).json("This site isn't available for you.") + //ctx.host()!!.contains("localhost") -> handler.handle(ctx) // DEBUG + else -> ctx.status(401).result("This site isn't available for you.") } } -/*private val Context.userRoles: List<Roles> - get() = this.basicAuthCredentials()?.let { (username, password) -> - userRoleMap[Pair(username, password)] ?: listOf() - } ?: listOf()*/ +/** + * Gets the username and verifies its identity + */ +fun getUsername(ctx: Context): String { + return if (databaseController.getUsernameByUUID(ctx.cookieStore("uuid") ?: "uuid") + == ctx.cookieStore("username") ?: "username" + ) ctx.cookieStore("username") + else "" +} /** * Crawls the requested file and either renders the directory view or the file view @@ -158,6 +175,18 @@ private fun isHumanReadable(filePath: String): Boolean { return d > 0.95 } +fun login(ctx: Context) { + val username = ctx.formParam("username").toString() + val password = ctx.formParam("password").toString() + + if (databaseController.checkUser(username, password)) { + ctx.cookieStore("uuid", databaseController.getUUID(username)) + ctx.cookieStore("username", username) + ctx.render("login.rocker.html", model("message", "Login succeeded!")) + } else + ctx.render("login.rocker.html", model("message", "Login failed!")) +} + /** * Declares the roles in which a user can be in diff --git a/src/main/kotlin/DatabaseController.kt b/src/main/kotlin/DatabaseController.kt index a51c00d..1ecb8bb 100644 --- a/src/main/kotlin/DatabaseController.kt +++ b/src/main/kotlin/DatabaseController.kt @@ -4,6 +4,7 @@ import at.favre.lib.crypto.bcrypt.* import org.jetbrains.exposed.sql.* import org.jetbrains.exposed.sql.transactions.* import java.sql.* +import java.util.* import java.util.logging.* class DatabaseController(dbFileLocation: String = "main.db") { @@ -26,6 +27,7 @@ class DatabaseController(dbFileLocation: String = "main.db") { val id = integer("id").autoIncrement().primaryKey() val username = varchar("username", 24).uniqueIndex() val password = varchar("password", 64) + val uuid = varchar("uuid", 64) } /** @@ -72,6 +74,7 @@ class DatabaseController(dbFileLocation: String = "main.db") { val usersId = UserData.insert { it[username] = usernameString it[password] = BCrypt.withDefaults().hashToString(12, passwordString.toCharArray()) + it[uuid] = UUID.randomUUID().toString() }[UserData.id] UserRoles.insert { roles -> @@ -89,8 +92,39 @@ class DatabaseController(dbFileLocation: String = "main.db") { */ fun checkUser(usernameString: String, passwordString: String): Boolean { return transaction { - val passwordHash = UserData.select { UserData.username eq usernameString }.map { it[UserData.password] }[0] - BCrypt.verifyer().verify(passwordString.toCharArray(), passwordHash).verified + try { + val passwordHash = + UserData.select { UserData.username eq usernameString }.map { it[UserData.password] }[0] + BCrypt.verifyer().verify(passwordString.toCharArray(), passwordHash).verified + } catch (_: Exception) { + false + } + } + } + + /** + * Returns the corresponding username using [uuid] + */ + fun getUsernameByUUID(uuid: String): String { + return transaction { + try { + UserData.select { UserData.uuid eq uuid }.map { it[UserData.username] }[0] + } catch (_: Exception) { + "" + } + } + } + + /** + * Returns the corresponding uuid using [usernameString] + */ + fun getUUID(usernameString: String): String { + return transaction { + try { + UserData.select { UserData.username eq usernameString }.map { it[UserData.uuid] }[0] + } catch (_: Exception) { + "" + } } } @@ -99,10 +133,14 @@ class DatabaseController(dbFileLocation: String = "main.db") { */ fun getRole(usernameString: String): Roles { return transaction { - val userId = UserData.select { UserData.username eq usernameString }.map { it[UserData.id] }[0] - val userRoleId = UserRoles.select { UserRoles.userId eq userId }.map { it[UserRoles.roleId] }[0] - val userRole = RolesData.select { RolesData.id eq userRoleId }.map { it[RolesData.role] }[0] - if (userRole == "ADMIN") Roles.ADMIN else Roles.USER + try { + val userId = UserData.select { UserData.username eq usernameString }.map { it[UserData.id] }[0] + val userRoleId = UserRoles.select { UserRoles.userId eq userId }.map { it[UserRoles.roleId] }[0] + val userRole = RolesData.select { RolesData.id eq userRoleId }.map { it[RolesData.role] }[0] + if (userRole == "ADMIN") Roles.ADMIN else Roles.USER + } catch (_: Exception) { + Roles.GUEST + } } } @@ -123,6 +161,14 @@ class DatabaseController(dbFileLocation: String = "main.db") { } /** + * Checks whether the site has been set up + */ + fun isInitialUse(): Boolean { + val initialUseRow = transaction { General.selectAll().map { it[General.initialUse] } }[0] + return initialUseRow == 1 + } + + /** * Initializes the database */ fun initDatabase() { diff --git a/src/main/resources/views/login.rocker.html b/src/main/resources/views/login.rocker.html new file mode 100644 index 0000000..389d82b --- /dev/null +++ b/src/main/resources/views/login.rocker.html @@ -0,0 +1,20 @@ +@args (String message) + +@layout.template("Login", RockerContent.NONE, RockerContent.NONE) -> { +<form action="login" 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> + + <button type="submit">Login</button> + + @if(message.length() > 0) { + <small>@message</small> + } +</form> +} |