using DeluxeBackend.Models; using DeluxeBackend.Services; using Microsoft.AspNetCore.Authorization; using Microsoft.AspNetCore.Http; using Microsoft.AspNetCore.Mvc; using System.IO; using System.ComponentModel.DataAnnotations; using static DeluxeBackend.Enums; using static DeluxeBackend.Extensions.RoomExtensions; namespace DeluxeBackend.Controllers.Rooms { [Route("Rooms/rooms/{roomId:long}")] [ApiController] [Authorize] public class RoomEditController(ILiteDbService db,IJwtService jwt,DiscordBotService discord,INotificationService ws) : ControllerBase { [HttpPut("automute")] public async Task Automute([FromRoute] long roomId, [FromForm] bool disable) { Account? account = await jwt.GetLogin(User); if (account == null) return Unauthorized(); Room? room = db.Rooms.FindById(roomId); if (room == null) return NotFound(); if (!room.HasRole(account.Id, RoomRoleType.CoOwner)) return Forbid(); room.DisableMicAutoMute = disable; db.Rooms.Update(room); await ws.SendToPlayerSubs(account.Id, "RoomUpdate", await room.ToDictionary(discord, db, RoomDetailsMask.StandardDetailsNoDataBlob)); return Ok(new { Success = true, Value = await room.ToDictionary(discord, db, RoomDetailsMask.StandardDetails) }); } [HttpPut("cloning")] public async Task Cloning([FromRoute] long roomId, [FromForm] bool cloningAllowed) { Account? account = await jwt.GetLogin(User); if (account == null) return Unauthorized(); Room? room = db.Rooms.FindById(roomId); if (room == null) return NotFound(); if (!room.HasRole(account.Id, RoomRoleType.CoOwner)) return Forbid(); room.CloningAllowed = cloningAllowed; db.Rooms.Update(room); await ws.SendToPlayerSubs(account.Id, "RoomUpdate", await room.ToDictionary(discord, db, RoomDetailsMask.StandardDetailsNoDataBlob)); return Ok(new { Success = true, Value = await room.ToDictionary(discord, db, RoomDetailsMask.StandardDetails) }); } [HttpPut("creator")] public async Task Creator([FromRoute] long roomId, [FromForm] ulong accountId) { return Ok(new { Success = false, Error = "Room ownership transfers are currently disabled." }); } [HttpPut("comments")] public async Task Comments([FromRoute] long roomId, [FromForm] bool disable) { Account? account = await jwt.GetLogin(User); if (account == null) return Unauthorized(); Room? room = db.Rooms.FindById(roomId); if (room == null) return NotFound(); if (!room.HasRole(account.Id, RoomRoleType.CoOwner)) return Forbid(); room.DisableRoomComments = disable; db.Rooms.Update(room); await ws.SendToPlayerSubs(account.Id, "RoomUpdate", await room.ToDictionary(discord, db, RoomDetailsMask.StandardDetailsNoDataBlob)); return Ok(new { Success = true, Value = await room.ToDictionary(discord, db, RoomDetailsMask.StandardDetails) }); } [HttpPut("voice_chat_encryption")] public async Task VoiceChatEncryption([FromRoute] long roomId, [FromForm] bool encryptVoiceChat) { return Ok(new { Success = false, Error = "Voice chat encryption settings cannot be modified manually." }); } [HttpPut("restrictions")] public async Task Restrictions( [FromRoute] long roomId, [FromForm] bool supportsScreens, [FromForm] bool supportsWalkVR, [FromForm] bool supportsTeleportVR, [FromForm] bool supportsJuniors) { Account? account = await jwt.GetLogin(User); if (account == null) return Unauthorized(); Room? room = db.Rooms.FindById(roomId); if (room == null) return NotFound(); if (!room.HasRole(account.Id, RoomRoleType.CoOwner)) return Forbid(); RoomSupports flags = RoomSupports.None; if (supportsScreens) flags |= RoomSupports.Screens; if (supportsWalkVR) flags |= RoomSupports.WalkVR; if (supportsTeleportVR) flags |= RoomSupports.TeleportVR; if (supportsJuniors) flags |= RoomSupports.Juniors; room.SupportedPlayerTypes = flags; db.Rooms.Update(room); await ws.SendToPlayerSubs(account.Id, "RoomUpdate", await room.ToDictionary(discord, db, RoomDetailsMask.StandardDetailsNoDataBlob)); return Ok(new { Success = true, Value = await room.ToDictionary(discord, db, RoomDetailsMask.StandardDetails) }); } [HttpPut("warning")] public async Task Warning([FromRoute] long roomId, [FromForm] RoomWarningMask warningMask, [FromForm] string customWarning = "") { Account? account = await jwt.GetLogin(User); if (account == null) return Unauthorized(); Room? room = db.Rooms.FindById(roomId); if (room == null) return NotFound(); if (!room.HasRole(account.Id, RoomRoleType.CoOwner)) return Forbid(); // Mitigation: Guard against severe memory buffer bloat / database inflation DoS vectors if (customWarning != null && customWarning.Length > 500) { return BadRequest(new { Success = false, Error = "Custom warning string length cannot exceed 500 characters." }); } room.WarningMask = warningMask; room.CustomWarning = string.IsNullOrWhiteSpace(customWarning) ? string.Empty : customWarning.Trim(); db.Rooms.Update(room); await ws.SendToPlayerSubs(account.Id, "RoomUpdate", await room.ToDictionary(discord, db, RoomDetailsMask.StandardDetailsNoDataBlob)); return Ok(new { Success = true, Value = await room.ToDictionary(discord, db, RoomDetailsMask.StandardDetails) }); } [HttpPut("image")] public async Task Image([FromRoute] long roomId, [FromForm] string imageName = "") { Account? account = await jwt.GetLogin(User); if (account == null) return Unauthorized(); Room? room = db.Rooms.FindById(roomId); if (room == null) return NotFound(); if (!room.HasRole(account.Id, RoomRoleType.CoOwner)) return Forbid(); // Mitigation: Defend against Path Traversal escape sequences (e.g., "../../../etc") string sanitizedImage = Path.GetFileName(imageName); if (imageName != sanitizedImage && !string.IsNullOrWhiteSpace(imageName)) { return BadRequest(new { Success = false, Error = "Invalid room image asset format." }); } room.ImageName = imageName; db.Rooms.Update(room); await ws.SendToPlayerSubs(account.Id, "RoomUpdate", await room.ToDictionary(discord, db, RoomDetailsMask.StandardDetailsNoDataBlob)); return Ok(new { Success = true, Value = await room.ToDictionary(discord, db, RoomDetailsMask.StandardDetails) }); } [HttpPut("accessibility")] public async Task Accessibility([FromRoute] long roomId, [FromForm] RoomAccessibility accessibility) { Account? account = await jwt.GetLogin(User); if (account == null) return Unauthorized(); Room? room = db.Rooms.FindById(roomId); if (room == null) return NotFound(); if (!room.HasRole(account.Id, RoomRoleType.CoOwner)) return Forbid(); room.Accessibility = accessibility; db.Rooms.Update(room); await ws.SendToPlayerSubs(account.Id, "RoomUpdate", await room.ToDictionary(discord, db, RoomDetailsMask.StandardDetailsNoDataBlob)); return Ok(new { Success = true, Value = await room.ToDictionary(discord, db, RoomDetailsMask.StandardDetails) }); } } }