diff --git a/SharpChat/ChatContext.cs b/SharpChat/ChatContext.cs index eb2852a..09fd9d0 100644 --- a/SharpChat/ChatContext.cs +++ b/SharpChat/ChatContext.cs @@ -28,7 +28,7 @@ namespace SharpChat { public void DispatchEvent(IChatEvent eventInfo) { if(eventInfo is MessageCreateEvent mce) { if(mce.IsBroadcast) { - Send(new LegacyCommandResponse(LCR.BROADCAST, false, mce.MessageText)); + Send(new BroadcastPacket(mce.MessageText)); } else if(mce.IsPrivate) { // The channel name returned by GetDMChannelName should not be exposed to the user, instead @ should be displayed // e.g. nook sees @Arysil and Arysil sees @nook @@ -311,7 +311,7 @@ namespace SharpChat { SendTo(chan, new UserChannelJoinPacket(user.UserId, user.LegacyNameWithStatus, user.Colour, user.Rank, user.Permissions)); Events.AddEvent("chan:join", user, oldChan, flags: StoredEventFlags.Log); - SendTo(user, new ContextClearPacket(ContextClearMode.MessagesUsers)); + SendTo(user, new ContextClearPacket(ContextClearPacket.ClearMode.MessagesUsers)); SendTo(user, new ContextUsersPacket(GetChannelUsers(chan).Except(new[] { user }).Select( user => new ContextUsersPacket.ListEntry(user.UserId, user.LegacyNameWithStatus, user.Colour, user.Rank, user.Permissions, true) ).OrderByDescending(u => u.Rank).ToArray())); diff --git a/SharpChat/Packet/AuthFailPacket.cs b/SharpChat/Packet/AuthFailPacket.cs index b31b988..576c505 100644 --- a/SharpChat/Packet/AuthFailPacket.cs +++ b/SharpChat/Packet/AuthFailPacket.cs @@ -1,35 +1,35 @@ using System; namespace SharpChat.Packet { - public enum AuthFailReason { - AuthInvalid, - MaxSessions, - Banned, - Null, - } - public class AuthFailPacket : ServerPacket { - private readonly AuthFailReason Reason; + public enum FailReason { + AuthInvalid, + MaxSessions, + Banned, + Null, + } + + private readonly FailReason Reason; private readonly DateTimeOffset Expires; - public AuthFailPacket(AuthFailReason reason) { + public AuthFailPacket(FailReason reason) { Reason = reason; } public AuthFailPacket(DateTimeOffset expires) { - Reason = AuthFailReason.Banned; + Reason = FailReason.Banned; Expires = expires; } public override string Pack() { string packet = string.Format("1\tn\t{0}fail", Reason switch { - AuthFailReason.AuthInvalid => "auth", - AuthFailReason.MaxSessions => "sock", - AuthFailReason.Banned => "join", + FailReason.AuthInvalid => "auth", + FailReason.MaxSessions => "sock", + FailReason.Banned => "join", _ => "user", }); - if(Reason == AuthFailReason.Banned) + if(Reason == FailReason.Banned) packet += string.Format("\t{0}", Expires.Year >= 2100 ? -1 : Expires.ToUnixTimeSeconds()); return packet; diff --git a/SharpChat/Packet/BroadcastPacket.cs b/SharpChat/Packet/BroadcastPacket.cs new file mode 100644 index 0000000..fa88167 --- /dev/null +++ b/SharpChat/Packet/BroadcastPacket.cs @@ -0,0 +1,22 @@ +using System; + +namespace SharpChat.Packet { + public class BroadcastPacket : ServerPacket { + private readonly long Timestamp; + private readonly string Body; + + public BroadcastPacket(string body) { + Timestamp = DateTimeOffset.Now.ToUnixTimeSeconds(); + Body = body; + } + + public override string Pack() { + return string.Format( + "2\t{0}\t-1\t0\fsay\f{1}\t{2}\t10010", + Timestamp, + SharpUtil.Sanitise(Body), + SequenceId + ); + } + } +} diff --git a/SharpChat/Packet/ChatMessageAddPacket.cs b/SharpChat/Packet/ChatMessageAddPacket.cs index 69612f1..f4e5a5f 100644 --- a/SharpChat/Packet/ChatMessageAddPacket.cs +++ b/SharpChat/Packet/ChatMessageAddPacket.cs @@ -24,7 +24,7 @@ namespace SharpChat.Packet { } public override string Pack() { - string body = Body.Replace("<", "<").Replace(">", ">").Replace("\n", "
").Replace("\t", " "); + string body = SharpUtil.Sanitise(Body); if(IsAction) body = string.Format("{0}", body); diff --git a/SharpChat/Packet/ChatMessageDeletePacket.cs b/SharpChat/Packet/ChatMessageDeletePacket.cs index 5f82a78..ea6a7b7 100644 --- a/SharpChat/Packet/ChatMessageDeletePacket.cs +++ b/SharpChat/Packet/ChatMessageDeletePacket.cs @@ -1,13 +1,13 @@ namespace SharpChat.Packet { public class ChatMessageDeletePacket : ServerPacket { - private readonly long EventId; + private readonly long MessageId; - public ChatMessageDeletePacket(long eventId) { - EventId = eventId; + public ChatMessageDeletePacket(long msgId) { + MessageId = msgId; } public override string Pack() { - return string.Format("6\t{0}", EventId); + return string.Format("6\t{0}", MessageId); } } } diff --git a/SharpChat/Packet/ContextClearPacket.cs b/SharpChat/Packet/ContextClearPacket.cs index 2440d3b..853de65 100644 --- a/SharpChat/Packet/ContextClearPacket.cs +++ b/SharpChat/Packet/ContextClearPacket.cs @@ -1,16 +1,16 @@ namespace SharpChat.Packet { - public enum ContextClearMode { - Messages = 0, - Users = 1, - Channels = 2, - MessagesUsers = 3, - MessagesUsersChannels = 4, - } - public class ContextClearPacket : ServerPacket { - private readonly ContextClearMode Mode; + public enum ClearMode { + Messages = 0, + Users = 1, + Channels = 2, + MessagesUsers = 3, + MessagesUsersChannels = 4, + } - public ContextClearPacket(ContextClearMode mode) { + private readonly ClearMode Mode; + + public ContextClearPacket(ClearMode mode) { Mode = mode; } diff --git a/SharpChat/Packet/ContextMessagePacket.cs b/SharpChat/Packet/ContextMessagePacket.cs index 52e7873..21b1dd8 100644 --- a/SharpChat/Packet/ContextMessagePacket.cs +++ b/SharpChat/Packet/ContextMessagePacket.cs @@ -49,7 +49,7 @@ namespace SharpChat.Packet { if(isBroadcast) sb.Append("0\fsay\f"); - string body = Event.Data.RootElement.GetProperty("text").GetString()?.Replace("<", "<").Replace(">", ">").Replace("\n", "
").Replace("\t", " ") ?? string.Empty; + string body = SharpUtil.Sanitise(Event.Data.RootElement.GetProperty("text").GetString()); if(isAction) body = string.Format("{0}", body); diff --git a/SharpChat/Packet/LegacyCommandResponse.cs b/SharpChat/Packet/LegacyCommandResponse.cs index 9247625..617c3ba 100644 --- a/SharpChat/Packet/LegacyCommandResponse.cs +++ b/SharpChat/Packet/LegacyCommandResponse.cs @@ -20,34 +20,17 @@ namespace SharpChat.Packet { public override string Pack() { StringBuilder sb = new(); - if(StringId == LCR.WELCOME) - sb.AppendFormat( - "7\t1\t{0}\t-1\tChatBot\tinherit\t\t", - DateTimeOffset.Now.ToUnixTimeSeconds() - ); - else - sb.AppendFormat( - "2\t{0}\t-1\t", - DateTimeOffset.Now.ToUnixTimeSeconds() - ); - sb.AppendFormat( - "{0}\f{1}", + "2\t{0}\t-1\t{1}\f{2}", + DateTimeOffset.Now.ToUnixTimeSeconds(), IsError ? 1 : 0, - StringId == LCR.WELCOME ? LCR.BROADCAST : StringId + StringId ); foreach(object arg in Arguments) sb.AppendFormat("\f{0}", arg); - sb.Append('\t'); - - if(StringId == LCR.WELCOME) - sb.AppendFormat("{0}\t0", StringId); - else - sb.Append(SequenceId); - - sb.Append("\t10010"); + sb.AppendFormat("\t{0}\t10010", SequenceId); return sb.ToString(); } @@ -55,12 +38,8 @@ namespace SharpChat.Packet { // Abbreviated class name because otherwise shit gets wide public static class LCR { - public const string GENERIC_ERROR = "generr"; - public const string COMMAND_NOT_FOUND = "nocmd"; public const string COMMAND_NOT_ALLOWED = "cmdna"; public const string COMMAND_FORMAT_ERROR = "cmderr"; - public const string WELCOME = "welcome"; - public const string BROADCAST = "say"; public const string IP_ADDRESS = "ipaddr"; public const string USER_NOT_FOUND = "usernf"; public const string NAME_IN_USE = "nameinuse"; diff --git a/SharpChat/Packet/MOTDPacket.cs b/SharpChat/Packet/MOTDPacket.cs new file mode 100644 index 0000000..4b0bf33 --- /dev/null +++ b/SharpChat/Packet/MOTDPacket.cs @@ -0,0 +1,20 @@ +using System; + +namespace SharpChat.Packet { + public class MOTDPacket : ServerPacket { + private readonly long Timestamp; + private readonly string Body; + + public MOTDPacket(string body) { + Timestamp = DateTimeOffset.Now.ToUnixTimeSeconds(); + Body = body; + } + + public override string Pack() { + return string.Format( + "7\t1\t{0}\t-1\tChatBot\tinherit\t\t0\fsay\f{1}\twelcome\t0\t10010", + Timestamp, SharpUtil.Sanitise(Body) + ); + } + } +} diff --git a/SharpChat/PacketHandlers/AuthHandler.cs b/SharpChat/PacketHandlers/AuthHandler.cs index 988d22a..e6e5016 100644 --- a/SharpChat/PacketHandlers/AuthHandler.cs +++ b/SharpChat/PacketHandlers/AuthHandler.cs @@ -35,14 +35,14 @@ namespace SharpChat.PacketHandlers { string? authMethod = args.ElementAtOrDefault(1); if(string.IsNullOrWhiteSpace(authMethod)) { - ctx.Connection.Send(new AuthFailPacket(AuthFailReason.AuthInvalid)); + ctx.Connection.Send(new AuthFailPacket(AuthFailPacket.FailReason.AuthInvalid)); ctx.Connection.Dispose(); return; } string? authToken = args.ElementAtOrDefault(2); if(string.IsNullOrWhiteSpace(authToken)) { - ctx.Connection.Send(new AuthFailPacket(AuthFailReason.AuthInvalid)); + ctx.Connection.Send(new AuthFailPacket(AuthFailPacket.FailReason.AuthInvalid)); ctx.Connection.Dispose(); return; } @@ -61,7 +61,7 @@ namespace SharpChat.PacketHandlers { fai = await Misuzu.AuthVerifyAsync(authMethod, authToken, ipAddr); } catch(Exception ex) { Logger.Write($"<{ctx.Connection.Id}> Failed to authenticate: {ex}"); - ctx.Connection.Send(new AuthFailPacket(AuthFailReason.AuthInvalid)); + ctx.Connection.Send(new AuthFailPacket(AuthFailPacket.FailReason.AuthInvalid)); ctx.Connection.Dispose(); #if DEBUG throw; @@ -72,14 +72,14 @@ namespace SharpChat.PacketHandlers { if(fai == null) { Logger.Debug($"<{ctx.Connection.Id}> Auth fail: "); - ctx.Connection.Send(new AuthFailPacket(AuthFailReason.Null)); + ctx.Connection.Send(new AuthFailPacket(AuthFailPacket.FailReason.Null)); ctx.Connection.Dispose(); return; } if(!fai.Success) { Logger.Debug($"<{ctx.Connection.Id}> Auth fail: {fai.Reason}"); - ctx.Connection.Send(new AuthFailPacket(AuthFailReason.AuthInvalid)); + ctx.Connection.Send(new AuthFailPacket(AuthFailPacket.FailReason.AuthInvalid)); ctx.Connection.Dispose(); return; } @@ -89,7 +89,7 @@ namespace SharpChat.PacketHandlers { fbi = await Misuzu.CheckBanAsync(fai.UserId.ToString(), ipAddr); } catch(Exception ex) { Logger.Write($"<{ctx.Connection.Id}> Failed auth ban check: {ex}"); - ctx.Connection.Send(new AuthFailPacket(AuthFailReason.AuthInvalid)); + ctx.Connection.Send(new AuthFailPacket(AuthFailPacket.FailReason.AuthInvalid)); ctx.Connection.Dispose(); #if DEBUG throw; @@ -100,7 +100,7 @@ namespace SharpChat.PacketHandlers { if(fbi == null) { Logger.Debug($"<{ctx.Connection.Id}> Ban check fail: "); - ctx.Connection.Send(new AuthFailPacket(AuthFailReason.Null)); + ctx.Connection.Send(new AuthFailPacket(AuthFailPacket.FailReason.Null)); ctx.Connection.Dispose(); return; } @@ -137,21 +137,21 @@ namespace SharpChat.PacketHandlers { // Enforce a maximum amount of connections per user if(ctx.Chat.Connections.Count(conn => conn.User == user) >= MaxConnections) { - ctx.Connection.Send(new AuthFailPacket(AuthFailReason.MaxSessions)); + ctx.Connection.Send(new AuthFailPacket(AuthFailPacket.FailReason.MaxSessions)); ctx.Connection.Dispose(); return; } ctx.Connection.BumpPing(); ctx.Connection.User = user; - ctx.Connection.Send(new LegacyCommandResponse(LCR.WELCOME, false, $"Welcome to Flashii Chat, {user.UserName}!")); + ctx.Connection.Send(new MOTDPacket($"Welcome to Flashii Chat, {user.UserName}!")); if(File.Exists("welcome.txt")) { IEnumerable lines = File.ReadAllLines("welcome.txt").Where(x => !string.IsNullOrWhiteSpace(x)); string? line = lines.ElementAtOrDefault(RNG.Next(lines.Count())); if(!string.IsNullOrWhiteSpace(line)) - ctx.Connection.Send(new LegacyCommandResponse(LCR.WELCOME, false, line)); + ctx.Connection.Send(new MOTDPacket(line)); } ctx.Chat.HandleJoin(user, DefaultChannel, ctx.Connection, MaxMessageLength); diff --git a/SharpChat/SharpId.cs b/SharpChat/SharpId.cs index ad79736..fdd6ead 100644 --- a/SharpChat/SharpId.cs +++ b/SharpChat/SharpId.cs @@ -6,9 +6,11 @@ namespace SharpChat { private const long EPOCH = 1588377600000; private static int Counter = 0; - public static long Next() - => ((DateTimeOffset.Now.ToUnixTimeMilliseconds() - EPOCH) << 8) - | (ushort)(Interlocked.Increment(ref Counter) & 0xFFFF); + public static long Next() { + long num = DateTimeOffset.Now.ToUnixTimeMilliseconds() - EPOCH; + num <<= 8; + num |= (ushort)(Interlocked.Increment(ref Counter) & 0xFFFF); + return num; + } } - } diff --git a/SharpChat/SharpUtil.cs b/SharpChat/SharpUtil.cs new file mode 100644 index 0000000..0b48faf --- /dev/null +++ b/SharpChat/SharpUtil.cs @@ -0,0 +1,10 @@ +namespace SharpChat { + public static class SharpUtil { + public static string Sanitise(string? body) { + if(string.IsNullOrEmpty(body)) + return string.Empty; + + return body.Replace("<", "<").Replace(">", ">").Replace("\n", "
").Replace("\t", " "); + } + } +}