using SharpChat.Events; using SharpChat.Misuzu; using SharpChat.SockChat.PacketsS2C; using System; using System.Linq; using System.Threading.Tasks; namespace SharpChat.SockChat.Commands { public class KickBanCommand : ISockChatClientCommand { private readonly MisuzuClient Misuzu; public KickBanCommand(MisuzuClient msz) { Misuzu = msz; } public bool IsMatch(SockChatClientCommandContext ctx) { return ctx.NameEquals("kick") || ctx.NameEquals("ban"); } public void Dispatch(SockChatClientCommandContext ctx) { bool isBanning = ctx.NameEquals("ban"); if(!ctx.User.Permissions.HasFlag(isBanning ? UserPermissions.BanUser : UserPermissions.KickUser)) { ctx.Chat.SendTo(ctx.User, new CommandNotAllowedErrorS2CPacket(ctx.Name)); return; } string banUserTarget = ctx.Args.ElementAtOrDefault(0) ?? string.Empty; string? banDurationStr = ctx.Args.ElementAtOrDefault(1); int banReasonIndex = 1; UserInfo? banUser = null; (string name, UsersContext.NameTarget target) = SockChatUtility.ExplodeUserName(banUserTarget); if(string.IsNullOrEmpty(name) || (banUser = ctx.Chat.Users.Get(name: name, nameTarget: target)) == null) { ctx.Chat.SendTo(ctx.User, new UserNotFoundErrorS2CPacket(banUserTarget)); return; } if(!ctx.User.IsSuper && banUser.Rank >= ctx.User.Rank && banUser != ctx.User) { ctx.Chat.SendTo(ctx.User, new KickBanNotAllowedErrorS2CPacket(SockChatUtility.GetUserName(banUser))); 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 CommandFormatErrorS2CPacket()); return; } duration = TimeSpan.FromSeconds(durationSeconds); ++banReasonIndex; } if(duration <= TimeSpan.Zero) { ctx.Chat.Events.Dispatch("user:kickban", banUser, UserKickBanEventData.OfDuration(UserDisconnectReason.Kicked, TimeSpan.Zero)); return; } string banReason = string.Join(' ', ctx.Args.Skip(banReasonIndex)); Task.Run(async () => { string userId = banUser.UserId.ToString(); MisuzuBanInfo? fbi = await Misuzu.CheckBanAsync(userId); if(fbi != null && fbi.IsBanned && !fbi.HasExpired) { ctx.Chat.SendTo(ctx.User, new KickBanNotAllowedErrorS2CPacket(SockChatUtility.GetUserName(banUser))); return; } string[] userRemoteAddrs = ctx.Chat.Connections.GetUserRemoteAddresses(banUser); string userRemoteAddr = string.Format(", ", userRemoteAddrs); // Misuzu only stores the IP address in private comment and doesn't do any checking, so this is fine. await Misuzu.CreateBanAsync( userId, userRemoteAddr, ctx.User.UserId.ToString(), ctx.Connection.RemoteAddress, duration, banReason ); ctx.Chat.Events.Dispatch("user:kickban", banUser, UserKickBanEventData.OfDuration(UserDisconnectReason.Kicked, duration)); }).Wait(); } } }