using SharpChat.Misuzu; using SharpChat.S2CPackets; namespace SharpChat.ClientCommands { public class KickBanClientCommand(MisuzuClient msz) : ClientCommand { private readonly MisuzuClient Misuzu = msz ?? throw new ArgumentNullException(nameof(msz)); public bool IsMatch(ClientCommandContext ctx) { return ctx.NameEquals("kick") || ctx.NameEquals("ban"); } public void Dispatch(ClientCommandContext ctx) { bool isBanning = ctx.NameEquals("ban"); long msgId = ctx.Chat.RandomSnowflake.Next(); if(!ctx.User.Can(isBanning ? UserPermissions.BanUser : UserPermissions.KickUser)) { ctx.Chat.SendTo(ctx.User, new CommandResponseS2CPacket(msgId, LCR.COMMAND_NOT_ALLOWED, true, $"/{ctx.Name}")); return; } string? banUserTarget = ctx.Args.ElementAtOrDefault(0); string? banDurationStr = ctx.Args.ElementAtOrDefault(1); int banReasonIndex = 1; User? banUser = null; if(banUserTarget == null || (banUser = ctx.Chat.Users.FirstOrDefault(u => u.NameEquals(banUserTarget))) == null) { ctx.Chat.SendTo(ctx.User, new CommandResponseS2CPacket(msgId, LCR.USER_NOT_FOUND, true, banUserTarget ?? "User")); return; } if(banUser.Rank >= ctx.User.Rank && banUser != ctx.User) { ctx.Chat.SendTo(ctx.User, new CommandResponseS2CPacket(msgId, LCR.KICK_NOT_ALLOWED, true, banUser.LegacyName)); return; } TimeSpan duration = isBanning ? TimeSpan.MaxValue : TimeSpan.Zero; if(!string.IsNullOrWhiteSpace(banDurationStr) && double.TryParse(banDurationStr, out double durationSeconds)) { if(durationSeconds < 0) { ctx.Chat.SendTo(ctx.User, new CommandResponseS2CPacket(msgId, LCR.COMMAND_FORMAT_ERROR)); return; } duration = TimeSpan.FromSeconds(durationSeconds); ++banReasonIndex; } if(duration <= TimeSpan.Zero) { ctx.Chat.BanUser(banUser, duration); return; } string banReason = string.Join(' ', ctx.Args.Skip(banReasonIndex)); Task.Run(async () => { string userId = banUser.UserId.ToString(); string userIp = ctx.Chat.GetRemoteAddresses(banUser).FirstOrDefault()?.ToString() ?? string.Empty; // obviously it makes no sense to only check for one ip address but that's current misuzu limitations MisuzuBanInfo? fbi = await Misuzu.CheckBanAsync(userId, userIp); if(fbi is null) { ctx.Chat.SendTo(ctx.User, new CommandResponseS2CPacket(msgId, LCR.GENERIC_ERROR, true)); return; } if(fbi.IsBanned && !fbi.HasExpired) { ctx.Chat.SendTo(ctx.User, new CommandResponseS2CPacket(msgId, LCR.KICK_NOT_ALLOWED, true, banUser.LegacyName)); return; } await Misuzu.CreateBanAsync( userId, userIp, ctx.User.UserId.ToString(), ctx.Connection.RemoteAddress.ToString(), duration, banReason ); ctx.Chat.BanUser(banUser, duration); }).Wait(); } } }