Files
ForkWar/WebsiteBackend/src/de/steamwar/plugins/Auth.kt
T
2025-10-27 18:34:31 +01:00

130 lines
3.9 KiB
Kotlin

/*
* This file is a part of the SteamWar software.
*
* Copyright (C) 2025 SteamWar.de-Serverteam
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
package de.steamwar.plugins
import de.steamwar.sql.SWException
import de.steamwar.sql.SteamwarUser
import de.steamwar.sql.Token
import de.steamwar.sql.UserPerm
import io.ktor.http.*
import io.ktor.server.application.*
import io.ktor.server.application.hooks.*
import io.ktor.server.auth.*
import io.ktor.server.request.*
import io.ktor.server.response.*
import io.ktor.util.*
data class SWAuthPrincipal(val token: Token, val user: SteamwarUser) : Principal
class SWAuthConfig {
var permission: UserPerm? = null
var allowedMethods = mutableListOf<HttpMethod>()
var userCheck: SWAuthPrincipal.(ApplicationRequest) -> Boolean = { true }
var mustAuth: Boolean = false
fun allowMethod(method: HttpMethod) {
allowedMethods.add(method)
}
fun allowMethods(methods: List<HttpMethod>) {
allowedMethods.addAll(methods)
}
fun userCheck(check: SWAuthPrincipal.(ApplicationRequest) -> Boolean) {
userCheck = check
}
}
val SWPermissionCheck = createRouteScopedPlugin("SWAuth", ::SWAuthConfig) {
pluginConfig.apply {
on(AuthenticationChecked) { call ->
if (call.request.httpMethod in allowedMethods) {
if(mustAuth) {
val token = call.principal<SWAuthPrincipal>()
if (token == null) {
call.respond(HttpStatusCode.Unauthorized)
}
}
return@on
}
val token = call.principal<SWAuthPrincipal>()
if (token == null) {
call.respond(HttpStatusCode.Unauthorized)
return@on
}
if (permission != null && !token.user.hasPerm(permission!!)) {
call.respond(HttpStatusCode.Forbidden)
return@on
}
if (!token.userCheck(call.request)) {
call.respond(HttpStatusCode.Forbidden)
return@on
}
}
}
}
val ErrorLogger = createApplicationPlugin("SWLogger") {
on(CallFailed) { call, cause ->
val msg = """
{
URI: ${call.request.uri}
Method: ${call.request.httpMethod.value}
Headers: ${call.request.headers.entries().joinToString("\n ") { "${it.key}: ${it.value}" }}
Message: ${cause.message}
}
"""
SWException.log(msg, cause.stackTraceToString())
call.response.headers.append("X-Caught", "1")
}
/*
onCallRespond { call ->
if ((call.response.status() ?: HttpStatusCode.OK).isSuccess()) {
return@onCallRespond
}
val msg = """
URI: ${call.request.uri}
Method: ${call.request.httpMethod.value}
Response: ${call.response.status()?.value}
IP: ${call.request.headers["X-Forwarded-For"] ?: call.request.local.remoteHost}
UserAgent: ${call.request.headers["User-Agent"]}
""".trimIndent()
val stack = """
Headers:
${call.request.headers.entries().joinToString("\n ") { "${it.key}: ${it.value}" }}
Body:
${call.request.receiveChannel().toByteArray().decodeToString()}
""".trimIndent()
SWException.log(msg, stack)
}*/
}