Split some packets out of LegacyCommandResponse.

This commit is contained in:
flash 2024-05-13 20:55:54 +00:00
parent 8cc00fe1a8
commit 907711e753
12 changed files with 104 additions and 71 deletions

View file

@ -28,7 +28,7 @@ namespace SharpChat {
public void DispatchEvent(IChatEvent eventInfo) { public void DispatchEvent(IChatEvent eventInfo) {
if(eventInfo is MessageCreateEvent mce) { if(eventInfo is MessageCreateEvent mce) {
if(mce.IsBroadcast) { if(mce.IsBroadcast) {
Send(new LegacyCommandResponse(LCR.BROADCAST, false, mce.MessageText)); Send(new BroadcastPacket(mce.MessageText));
} else if(mce.IsPrivate) { } else if(mce.IsPrivate) {
// The channel name returned by GetDMChannelName should not be exposed to the user, instead @<Target User> should be displayed // The channel name returned by GetDMChannelName should not be exposed to the user, instead @<Target User> should be displayed
// e.g. nook sees @Arysil and Arysil sees @nook // 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)); SendTo(chan, new UserChannelJoinPacket(user.UserId, user.LegacyNameWithStatus, user.Colour, user.Rank, user.Permissions));
Events.AddEvent("chan:join", user, oldChan, flags: StoredEventFlags.Log); 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( 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) user => new ContextUsersPacket.ListEntry(user.UserId, user.LegacyNameWithStatus, user.Colour, user.Rank, user.Permissions, true)
).OrderByDescending(u => u.Rank).ToArray())); ).OrderByDescending(u => u.Rank).ToArray()));

View file

@ -1,35 +1,35 @@
using System; using System;
namespace SharpChat.Packet { namespace SharpChat.Packet {
public enum AuthFailReason {
AuthInvalid,
MaxSessions,
Banned,
Null,
}
public class AuthFailPacket : ServerPacket { public class AuthFailPacket : ServerPacket {
private readonly AuthFailReason Reason; public enum FailReason {
AuthInvalid,
MaxSessions,
Banned,
Null,
}
private readonly FailReason Reason;
private readonly DateTimeOffset Expires; private readonly DateTimeOffset Expires;
public AuthFailPacket(AuthFailReason reason) { public AuthFailPacket(FailReason reason) {
Reason = reason; Reason = reason;
} }
public AuthFailPacket(DateTimeOffset expires) { public AuthFailPacket(DateTimeOffset expires) {
Reason = AuthFailReason.Banned; Reason = FailReason.Banned;
Expires = expires; Expires = expires;
} }
public override string Pack() { public override string Pack() {
string packet = string.Format("1\tn\t{0}fail", Reason switch { string packet = string.Format("1\tn\t{0}fail", Reason switch {
AuthFailReason.AuthInvalid => "auth", FailReason.AuthInvalid => "auth",
AuthFailReason.MaxSessions => "sock", FailReason.MaxSessions => "sock",
AuthFailReason.Banned => "join", FailReason.Banned => "join",
_ => "user", _ => "user",
}); });
if(Reason == AuthFailReason.Banned) if(Reason == FailReason.Banned)
packet += string.Format("\t{0}", Expires.Year >= 2100 ? -1 : Expires.ToUnixTimeSeconds()); packet += string.Format("\t{0}", Expires.Year >= 2100 ? -1 : Expires.ToUnixTimeSeconds());
return packet; return packet;

View file

@ -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
);
}
}
}

View file

@ -24,7 +24,7 @@ namespace SharpChat.Packet {
} }
public override string Pack() { public override string Pack() {
string body = Body.Replace("<", "&lt;").Replace(">", "&gt;").Replace("\n", " <br/> ").Replace("\t", " "); string body = SharpUtil.Sanitise(Body);
if(IsAction) if(IsAction)
body = string.Format("<i>{0}</i>", body); body = string.Format("<i>{0}</i>", body);

View file

@ -1,13 +1,13 @@
namespace SharpChat.Packet { namespace SharpChat.Packet {
public class ChatMessageDeletePacket : ServerPacket { public class ChatMessageDeletePacket : ServerPacket {
private readonly long EventId; private readonly long MessageId;
public ChatMessageDeletePacket(long eventId) { public ChatMessageDeletePacket(long msgId) {
EventId = eventId; MessageId = msgId;
} }
public override string Pack() { public override string Pack() {
return string.Format("6\t{0}", EventId); return string.Format("6\t{0}", MessageId);
} }
} }
} }

View file

@ -1,16 +1,16 @@
namespace SharpChat.Packet { namespace SharpChat.Packet {
public enum ContextClearMode {
Messages = 0,
Users = 1,
Channels = 2,
MessagesUsers = 3,
MessagesUsersChannels = 4,
}
public class ContextClearPacket : ServerPacket { 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; Mode = mode;
} }

View file

@ -49,7 +49,7 @@ namespace SharpChat.Packet {
if(isBroadcast) if(isBroadcast)
sb.Append("0\fsay\f"); sb.Append("0\fsay\f");
string body = Event.Data.RootElement.GetProperty("text").GetString()?.Replace("<", "&lt;").Replace(">", "&gt;").Replace("\n", " <br/> ").Replace("\t", " ") ?? string.Empty; string body = SharpUtil.Sanitise(Event.Data.RootElement.GetProperty("text").GetString());
if(isAction) if(isAction)
body = string.Format("<i>{0}</i>", body); body = string.Format("<i>{0}</i>", body);

View file

@ -20,34 +20,17 @@ namespace SharpChat.Packet {
public override string Pack() { public override string Pack() {
StringBuilder sb = new(); 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( sb.AppendFormat(
"{0}\f{1}", "2\t{0}\t-1\t{1}\f{2}",
DateTimeOffset.Now.ToUnixTimeSeconds(),
IsError ? 1 : 0, IsError ? 1 : 0,
StringId == LCR.WELCOME ? LCR.BROADCAST : StringId StringId
); );
foreach(object arg in Arguments) foreach(object arg in Arguments)
sb.AppendFormat("\f{0}", arg); sb.AppendFormat("\f{0}", arg);
sb.Append('\t'); sb.AppendFormat("\t{0}\t10010", SequenceId);
if(StringId == LCR.WELCOME)
sb.AppendFormat("{0}\t0", StringId);
else
sb.Append(SequenceId);
sb.Append("\t10010");
return sb.ToString(); return sb.ToString();
} }
@ -55,12 +38,8 @@ namespace SharpChat.Packet {
// Abbreviated class name because otherwise shit gets wide // Abbreviated class name because otherwise shit gets wide
public static class LCR { 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_NOT_ALLOWED = "cmdna";
public const string COMMAND_FORMAT_ERROR = "cmderr"; 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 IP_ADDRESS = "ipaddr";
public const string USER_NOT_FOUND = "usernf"; public const string USER_NOT_FOUND = "usernf";
public const string NAME_IN_USE = "nameinuse"; public const string NAME_IN_USE = "nameinuse";

View file

@ -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)
);
}
}
}

View file

@ -35,14 +35,14 @@ namespace SharpChat.PacketHandlers {
string? authMethod = args.ElementAtOrDefault(1); string? authMethod = args.ElementAtOrDefault(1);
if(string.IsNullOrWhiteSpace(authMethod)) { if(string.IsNullOrWhiteSpace(authMethod)) {
ctx.Connection.Send(new AuthFailPacket(AuthFailReason.AuthInvalid)); ctx.Connection.Send(new AuthFailPacket(AuthFailPacket.FailReason.AuthInvalid));
ctx.Connection.Dispose(); ctx.Connection.Dispose();
return; return;
} }
string? authToken = args.ElementAtOrDefault(2); string? authToken = args.ElementAtOrDefault(2);
if(string.IsNullOrWhiteSpace(authToken)) { if(string.IsNullOrWhiteSpace(authToken)) {
ctx.Connection.Send(new AuthFailPacket(AuthFailReason.AuthInvalid)); ctx.Connection.Send(new AuthFailPacket(AuthFailPacket.FailReason.AuthInvalid));
ctx.Connection.Dispose(); ctx.Connection.Dispose();
return; return;
} }
@ -61,7 +61,7 @@ namespace SharpChat.PacketHandlers {
fai = await Misuzu.AuthVerifyAsync(authMethod, authToken, ipAddr); fai = await Misuzu.AuthVerifyAsync(authMethod, authToken, ipAddr);
} catch(Exception ex) { } catch(Exception ex) {
Logger.Write($"<{ctx.Connection.Id}> Failed to authenticate: {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(); ctx.Connection.Dispose();
#if DEBUG #if DEBUG
throw; throw;
@ -72,14 +72,14 @@ namespace SharpChat.PacketHandlers {
if(fai == null) { if(fai == null) {
Logger.Debug($"<{ctx.Connection.Id}> Auth fail: <null>"); Logger.Debug($"<{ctx.Connection.Id}> Auth fail: <null>");
ctx.Connection.Send(new AuthFailPacket(AuthFailReason.Null)); ctx.Connection.Send(new AuthFailPacket(AuthFailPacket.FailReason.Null));
ctx.Connection.Dispose(); ctx.Connection.Dispose();
return; return;
} }
if(!fai.Success) { if(!fai.Success) {
Logger.Debug($"<{ctx.Connection.Id}> Auth fail: {fai.Reason}"); 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(); ctx.Connection.Dispose();
return; return;
} }
@ -89,7 +89,7 @@ namespace SharpChat.PacketHandlers {
fbi = await Misuzu.CheckBanAsync(fai.UserId.ToString(), ipAddr); fbi = await Misuzu.CheckBanAsync(fai.UserId.ToString(), ipAddr);
} catch(Exception ex) { } catch(Exception ex) {
Logger.Write($"<{ctx.Connection.Id}> Failed auth ban check: {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(); ctx.Connection.Dispose();
#if DEBUG #if DEBUG
throw; throw;
@ -100,7 +100,7 @@ namespace SharpChat.PacketHandlers {
if(fbi == null) { if(fbi == null) {
Logger.Debug($"<{ctx.Connection.Id}> Ban check fail: <null>"); Logger.Debug($"<{ctx.Connection.Id}> Ban check fail: <null>");
ctx.Connection.Send(new AuthFailPacket(AuthFailReason.Null)); ctx.Connection.Send(new AuthFailPacket(AuthFailPacket.FailReason.Null));
ctx.Connection.Dispose(); ctx.Connection.Dispose();
return; return;
} }
@ -137,21 +137,21 @@ namespace SharpChat.PacketHandlers {
// Enforce a maximum amount of connections per user // Enforce a maximum amount of connections per user
if(ctx.Chat.Connections.Count(conn => conn.User == user) >= MaxConnections) { 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(); ctx.Connection.Dispose();
return; return;
} }
ctx.Connection.BumpPing(); ctx.Connection.BumpPing();
ctx.Connection.User = user; 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")) { if(File.Exists("welcome.txt")) {
IEnumerable<string> lines = File.ReadAllLines("welcome.txt").Where(x => !string.IsNullOrWhiteSpace(x)); IEnumerable<string> lines = File.ReadAllLines("welcome.txt").Where(x => !string.IsNullOrWhiteSpace(x));
string? line = lines.ElementAtOrDefault(RNG.Next(lines.Count())); string? line = lines.ElementAtOrDefault(RNG.Next(lines.Count()));
if(!string.IsNullOrWhiteSpace(line)) 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); ctx.Chat.HandleJoin(user, DefaultChannel, ctx.Connection, MaxMessageLength);

View file

@ -6,9 +6,11 @@ namespace SharpChat {
private const long EPOCH = 1588377600000; private const long EPOCH = 1588377600000;
private static int Counter = 0; private static int Counter = 0;
public static long Next() public static long Next() {
=> ((DateTimeOffset.Now.ToUnixTimeMilliseconds() - EPOCH) << 8) long num = DateTimeOffset.Now.ToUnixTimeMilliseconds() - EPOCH;
| (ushort)(Interlocked.Increment(ref Counter) & 0xFFFF); num <<= 8;
num |= (ushort)(Interlocked.Increment(ref Counter) & 0xFFFF);
return num;
}
} }
} }

10
SharpChat/SharpUtil.cs Normal file
View file

@ -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("<", "&lt;").Replace(">", "&gt;").Replace("\n", " <br/> ").Replace("\t", " ");
}
}
}