This commit is contained in:
2024-08-27 21:34:18 +02:00
parent cab12fca92
commit c11eaaee45
13 changed files with 118 additions and 373 deletions
@@ -96,7 +96,7 @@ public class EventFight implements Comparable<EventFight> {
@Getter
@Setter
@Field(nullable = true)
private int spectatePort;
private Integer spectatePort;
@Getter
@Field(def = "0")
private int ergebnis;
@@ -62,7 +62,7 @@ public class EventStarter {
//Don't start EventServer if not the event bungee
String command;
if(VelocityCore.get().getConfig().isEventmode() || next.getSpectatePort() == 0) {
if(VelocityCore.get().getConfig().isEventmode() || next.getSpectatePort() == null) {
ServerStarter starter = new ServerStarter().event(next);
starter.callback(subserver -> {
@@ -102,4 +102,27 @@ Message: ${cause.message}
SWException.log(msg, cause.stackTraceToString())
call.response.headers.append("X-Caught", "1")
}
onCallRespond { call ->
if (call.response.status()?.isSuccess() == true) {
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()}
""".trimIndent()
SWException.log(msg, stack)
}
}
@@ -78,80 +78,6 @@ fun Route.configureAuthRoutes() {
mustAuth = true
}
get {
val auth = call.principal<SWAuthPrincipal>()
if(auth == null) {
call.respond(HttpStatusCode.InternalServerError)
return@get
}
call.respond(Token.listUser(auth.user).map { ResponseToken(it) })
}
post {
val auth = call.principal<SWAuthPrincipal>()
if(auth == null) {
call.respond(HttpStatusCode.InternalServerError)
return@post
}
val request = call.receive<CreateTokenRequest>()
if(request.name.length > 32) {
call.respond(HttpStatusCode.BadRequest, ResponseError("Name too long", "name_too_long"))
return@post
}
if(request.name.length < 3) {
call.respond(HttpStatusCode.BadRequest, ResponseError("Name too short", "name_too_short"))
return@post
}
if(!auth.user.verifyPassword(request.password)) {
call.respond(HttpStatusCode.BadRequest, ResponseError("Invalid password", "invalid_password"))
return@post
}
val token = Token.createToken(request.name, auth.user)
call.respond(AuthTokenResponse(token))
}
route("/{id}") {
delete {
val auth = call.principal<SWAuthPrincipal>()
if(auth == null) {
call.respond(HttpStatusCode.InternalServerError)
return@delete
}
val id = call.parameters["id"]?.toIntOrNull()
if(id == null) {
call.respond(HttpStatusCode.BadRequest)
return@delete
}
val token = Token.get(id)
if(token == null) {
call.respond(HttpStatusCode.NotFound)
return@delete
}
if(token.owner != auth.user) {
call.respond(HttpStatusCode.Forbidden)
return@delete
}
token.delete()
call.respond(HttpStatusCode.OK)
}
}
post("/logout") {
val auth = call.principal<SWAuthPrincipal>()
@@ -70,9 +70,6 @@ data class ResponseUser(val name: String, val uuid: String, val prefix: String,
fun Route.configureDataRoutes() {
route("/data") {
get {
call.respondText("Hello World!")
}
route("/admin") {
install(SWPermissionCheck) {
mustAuth = true
@@ -118,16 +118,7 @@ fun Route.configureEventFightRoutes() {
}
route("/{fight}") {
put {
val fightId = call.parameters["fight"]?.toIntOrNull()
if (fightId == null) {
call.respond(HttpStatusCode.BadRequest, ResponseError("Invalid fight ID"))
return@put
}
val fight = EventFight.get(fightId)
if (fight == null) {
call.respond(HttpStatusCode.NotFound, ResponseError("Fight not found"))
return@put
}
val fight = call.receiveFight() ?: return@put
val updateFight = call.receiveNullable<UpdateEventFight>()
if (updateFight == null) {
call.respond(HttpStatusCode.BadRequest, ResponseError("Invalid body"))
@@ -143,29 +134,35 @@ fun Route.configureEventFightRoutes() {
if (updateFight.group != null) {
if (updateFight.group == "null") {
Groups.resetGroup(fightId, true)
Groups.resetGroup(fight.fightID, true)
} else {
Groups.setGroup(fightId, updateFight.group)
Groups.setGroup(fight.fightID, updateFight.group)
}
}
fight.update(start, spielmodus, map, teamBlue, teamRed, spectatePort)
call.respond(HttpStatusCode.OK, ResponseEventFight(fight))
}
delete {
val fightId = call.parameters["fight"]?.toIntOrNull()
if (fightId == null) {
call.respond(HttpStatusCode.BadRequest, ResponseError("Invalid fight ID"))
return@delete
}
val fight = EventFight.get(fightId)
if (fight == null) {
call.respond(HttpStatusCode.NotFound, ResponseError("Fight not found"))
return@delete
}
val fight = call.receiveFight() ?: return@delete
fight.delete()
call.respond(HttpStatusCode.OK)
}
}
}
}
suspend fun ApplicationCall.receiveFight(fieldName: String = "fight"): EventFight? {
val fightId = parameters[fieldName]?.toIntOrNull()
if (fightId == null) {
respond(HttpStatusCode.BadRequest, ResponseError("Invalid fight ID"))
return null
}
val fight = EventFight.get(fightId)
if (fight == null) {
respond(HttpStatusCode.NotFound, ResponseError("Fight not found"))
return null
}
return fight
}
+19 -20
View File
@@ -154,16 +154,7 @@ fun Route.configureEventsRoute() {
call.respond(EventFight.getEvent(event.eventID).map { ResponseEventFight(it) })
}
get("/csv") {
val id = call.parameters["id"]?.toIntOrNull()
if (id == null) {
call.respond(HttpStatusCode.BadRequest, ResponseError("Invalid ID"))
return@get
}
val event = Event.get(id)
if (event == null) {
call.respond(HttpStatusCode.NotFound, ResponseError("Event not found"))
return@get
}
val event = call.receiveEvent() ?: return@get
val fights = EventFight.getEvent(event.eventID)
val csv = StringBuilder();
@@ -195,16 +186,8 @@ fun Route.configureEventsRoute() {
call.respondText(csv.toString())
}
put {
val id = call.parameters["id"]?.toIntOrNull()
if (id == null) {
call.respond(HttpStatusCode.BadRequest, ResponseError("Invalid ID"))
return@put
}
val event = Event.get(id)
if (event == null) {
call.respond(HttpStatusCode.NotFound, ResponseError("Event not found"))
return@put
}
val event = call.receiveEvent() ?: return@put
val updateEvent = call.receiveNullable<UpdateEvent>()
if (updateEvent == null) {
call.respond(HttpStatusCode.BadRequest, ResponseError("Invalid body"))
@@ -249,4 +232,20 @@ fun Route.configureEventsRoute() {
}
}
}
}
suspend fun ApplicationCall.receiveEvent(fieldName: String = "event"): Event? {
val eventId = parameters[fieldName]?.toIntOrNull()
if (eventId == null) {
respond(HttpStatusCode.BadRequest, ResponseError("Invalid event ID"))
return null
}
val event = Event.get(eventId)
if (event == null) {
respond(HttpStatusCode.NotFound, ResponseError("Event not found"))
return null
}
return event
}
@@ -34,7 +34,6 @@ fun Application.configureRoutes() {
configurePage()
configureSchematic()
configureAuthRoutes()
configureUser()
}
}
}
@@ -74,27 +74,7 @@ data class UploadSchematic(val name: String, val content: String)
fun Route.configureSchematic() {
route("/download/{code}") {
get {
val code = call.parameters["code"] ?: run {
call.respond(HttpStatusCode.BadRequest)
return@get
}
val dl = NodeDownload.get(code) ?: run {
call.respond(HttpStatusCode.NotFound)
return@get
}
dl.delete()
if(dl.timestamp.toInstant().plus(Duration.of(5, ChronoUnit.MINUTES)).isBefore(Instant.now())) {
call.respond(HttpStatusCode.Gone)
return@get
}
val node = SchematicNode.getSchematicNode(dl.nodeId) ?: run {
call.respond(HttpStatusCode.NotFound)
return@get
}
val node = call.receiveSchematic() ?: return@get
val user = call.principal<SWAuthPrincipal>()?.user
if(user != null && !node.accessibleByUser(user)) {
@@ -112,36 +92,13 @@ fun Route.configureSchematic() {
call.respondBytes(data.schemData().readAllBytes(), contentType = ContentType.Application.OctetStream, status = HttpStatusCode.OK)
}
get("/info") {
val code = call.parameters["code"] ?: run {
call.respond(HttpStatusCode.BadRequest)
return@get
}
val dl = NodeDownload.get(code) ?: run {
call.respond(HttpStatusCode.NotFound)
return@get
}
val node = SchematicNode.getSchematicNode(dl.nodeId) ?: run {
call.respond(HttpStatusCode.NotFound)
return@get
}
val node = call.receiveSchematic() ?: return@get
call.respond(ResponseSchematic(node))
}
}
route("/schem") {
install(SWPermissionCheck)
/*get {
val user = call.principal<SWAuthPrincipal>()!!.user
call.respond(ResponseSchematicList(SchematicNode.list(user, null).filter { it.name != "//copy" }.sortedWith { o1, o2 ->
if (o1.isDir || o2.isDir) {
o2.isDir.compareTo(o1.isDir)
} else {
o1.name.compareTo(o2.name)
}
}.map { ResponseSchematic(it) }, listOf()))
}*/
post {
val file = call.receive<UploadSchematic>()
@@ -166,64 +123,33 @@ fun Route.configureSchematic() {
call.respond(ResponseSchematic(node))
}
/*
route("/{id}") {
get {
val user = call.principal<SWAuthPrincipal>()!!.user
val parentId = call.parameters["id"]?.toIntOrNull()
if(parentId == null) {
call.respond(HttpStatusCode.BadRequest)
return@get
}
val parent = SchematicNode.getSchematicNode(parentId)
if(parent == null) {
call.respond(HttpStatusCode.NotFound)
return@get
}
if(!parent.accessibleByUser(user)) {
call.respond(HttpStatusCode.Forbidden)
return@get
}
call.respond(ResponseSchematicLong(parent, parent.generateBreadcrumbs(user)))
}
get("/list") {
val user = call.principal<SWAuthPrincipal>()!!.user
val parentId = call.parameters["id"]?.toIntOrNull()
if(parentId == null) {
call.respond(HttpStatusCode.BadRequest)
return@get
}
val parent = SchematicNode.getSchematicNode(parentId)
if(parent == null) {
call.respond(HttpStatusCode.NotFound)
return@get
}
if(!parent.isDir) {
call.respond(HttpStatusCode.BadRequest)
return@get
}
if(!parent.accessibleByUser(user)) {
call.respond(HttpStatusCode.Forbidden)
return@get
}
call.respond(ResponseSchematicList(SchematicNode.list(user, parent.id).filter { it.name != "//copy" }.sortedWith { o1, o2 ->
if (o1.isDir || o2.isDir) {
o2.isDir.compareTo(o1.isDir)
} else {
o1.name.compareTo(o2.name)
}
}.map { ResponseSchematic(it) }, parent.generateBreadcrumbsMap(user).map { ResponseBreadcrumb(it.key, it.value) }))
}
}*/
}
}
suspend fun ApplicationCall.receiveSchematic(fieldName: String = "code", delete: Boolean = false): SchematicNode? {
val code = parameters[fieldName] ?: run {
respond(HttpStatusCode.BadRequest)
return null
}
val dl = NodeDownload.get(code) ?: run {
respond(HttpStatusCode.NotFound)
return null
}
if(dl.timestamp.toInstant().plus(Duration.of(5, ChronoUnit.MINUTES)).isBefore(Instant.now())) {
respond(HttpStatusCode.Gone)
return null
}
if (delete) {
dl.delete()
}
val node = SchematicNode.getSchematicNode(dl.nodeId) ?: run {
respond(HttpStatusCode.NotFound)
return null
}
return node
}
+4 -15
View File
@@ -59,28 +59,17 @@ fun Route.configureStats() {
call.respond(list.map { Fight(it.first, it.second, it.third) })
}
route("/user/{id}") {
install(SWPermissionCheck) {
userCheck {
val user = it.call.request.getUser()
val auth = it.call.principal<SWAuthPrincipal>()
if (user == null || auth == null) {
return@userCheck false
}
return@userCheck user.id == auth.user.id || auth.user.hasPerm(UserPerm.MODERATION)
}
}
route("/user") {
install(SWPermissionCheck)
get {
val user = call.request.getUser()
val user = call.authentication.principal<SWAuthPrincipal>()
if (user == null) {
call.respond(HttpStatusCode.NotFound, "User not found")
return@get
}
call.respond(UserStats(user))
call.respond(UserStats(user.user))
}
}
}
@@ -1,33 +0,0 @@
/*
* This file is a part of the SteamWar software.
*
* Copyright (C) 2024 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.routes
import de.steamwar.sql.Team
import io.ktor.server.application.*
import io.ktor.server.response.*
import io.ktor.server.routing.*
fun Route.configureTeamRoutes() {
route("/team") {
get {
call.respond(Team.getAll().map { ResponseTeam(it) })
}
}
}
@@ -1,54 +0,0 @@
/*
* This file is a part of the SteamWar software.
*
* Copyright (C) 2024 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.routes
import de.steamwar.plugins.SWPermissionCheck
import de.steamwar.plugins.getUser
import de.steamwar.sql.UserPerm
import io.ktor.http.*
import io.ktor.server.application.*
import io.ktor.server.request.*
import io.ktor.server.response.*
import io.ktor.server.routing.*
fun Route.configureUser() {
route("/user") {
route("/{id}") {
route("/admin") {
install(SWPermissionCheck) {
permission = UserPerm.ADMINISTRATION
}
put("/password") {
val user = call.request.getUser() ?: return@put call.respond(HttpStatusCode.NotFound)
val password = call.receiveText()
if (password.isEmpty()) {
call.respond(HttpStatusCode.BadRequest, "Password too short")
return@put
}
user.setPassword(password)
call.respond(HttpStatusCode.OK)
}
}
}
}
}
@@ -23,7 +23,6 @@ import de.steamwar.plugins.SWPermissionCheck
import de.steamwar.plugins.getUser
import de.steamwar.sql.SteamwarUser
import de.steamwar.sql.UserPerm
import de.steamwar.sql.UserPerm.Prefix
import io.ktor.http.*
import io.ktor.server.application.*
import io.ktor.server.response.*
@@ -42,7 +41,6 @@ data class RespondUserPermsPrefix(val prefix: RespondPrefix, val perms: List<Str
fun Route.configureUserPerms() {
route("/perms") {
install(SWPermissionCheck) {
allowMethod(HttpMethod.Get)
permission = UserPerm.MODERATION
}
get {
@@ -60,11 +58,6 @@ fun Route.configureUserPerms() {
call.respond(RespondUserPerms(prefixes, perms))
}
route("/user/{id}") {
install(SWPermissionCheck) {
allowMethod(HttpMethod.Get)
permission = UserPerm.MODERATION
mustAuth = true
}
get {
val user = call.request.getUser()
if (user == null) {
@@ -86,38 +79,17 @@ fun Route.configureUserPerms() {
call.respond(RespondUserPermsPrefix(RespondPrefix(prefix.name, prefixs.colorCode, prefixs.chatPrefix), perms))
}
put("/prefix/{prefix}") {
val user = call.request.getUser()
if (user == null) {
call.respond(HttpStatusCode.BadRequest)
return@put
}
val (user, prefix) = call.receivePermission("prefix") ?: return@put
val prefix = call.parameters["prefix"]
if (prefix == null || UserPerm.values().find { it.name == prefix } == null) {
call.respond(HttpStatusCode.BadRequest)
return@put
}
user.perms().filter { it.name.startsWith("PREFIX_") }.forEach {
UserPerm.removePerm(user, it)
}
UserPerm.addPerm(user, UserPerm.values().find { it.name == prefix }!!)
UserPerm.addPerm(user, UserPerm.entries.find { it == prefix }!!)
call.respond(HttpStatusCode.Accepted)
}
put("/{perm}") {
val user = call.request.getUser()
if (user == null) {
call.respond(HttpStatusCode.BadRequest)
return@put
}
val perm = call.parameters["perm"]
val permission = UserPerm.values().find { it.name == perm }
if (perm == null || perm.startsWith("PREFIX_") || permission == null) {
call.respond(HttpStatusCode.BadRequest)
return@put
}
val (user, permission) = call.receivePermission() ?: return@put
if (!user.hasPerm(permission)) {
UserPerm.addPerm(user, permission)
@@ -127,20 +99,7 @@ fun Route.configureUserPerms() {
call.respond(HttpStatusCode.NoContent)
}
delete("/{perm}") {
val user = call.request.getUser()
if (user == null) {
call.respond(HttpStatusCode.BadRequest)
return@delete
}
val perm = call.parameters["perm"]
val permission = UserPerm.values().find { it.name == perm }
if (perm == null || perm.startsWith("PREFIX_") || permission == null) {
call.respond(HttpStatusCode.BadRequest)
return@delete
}
val (user, permission) = call.receivePermission() ?: return@delete
if (user.hasPerm(permission)) {
UserPerm.removePerm(user, permission)
@@ -151,4 +110,21 @@ fun Route.configureUserPerms() {
}
}
}
}
suspend fun ApplicationCall.receivePermission(fieldName: String = "perm", isPrefix: Boolean = false): Pair<SteamwarUser, UserPerm>? {
val user = request.getUser()
if (user == null) {
respond(HttpStatusCode.BadRequest)
return null
}
val perm = parameters[fieldName]
val permission = UserPerm.entries.find { it.name == perm }
if (perm == null || perm.startsWith("PREFIX_") == isPrefix || permission == null) {
respond(HttpStatusCode.BadRequest)
return null
}
return user to permission
}