From fc47c839a2beaa24bad0e52ca0935947b05cdc4b Mon Sep 17 00:00:00 2001 From: Alec Obradovich Date: Sun, 3 Mar 2019 14:04:39 -0600 Subject: [PATCH] the wow --- interop.sln | 22 ++ interop/App.config | 6 + interop/Program.cs | 341 +++++++++++++++++++++++ interop/Properties/AssemblyInfo.cs | 36 +++ interop/Properties/Resources.Designer.cs | 141 ++++++++++ interop/Properties/Resources.resx | 189 +++++++++++++ interop/interop.csproj | 71 +++++ interop/packages.config | 5 + 8 files changed, 811 insertions(+) create mode 100644 interop.sln create mode 100644 interop/App.config create mode 100644 interop/Program.cs create mode 100644 interop/Properties/AssemblyInfo.cs create mode 100644 interop/Properties/Resources.Designer.cs create mode 100644 interop/Properties/Resources.resx create mode 100644 interop/interop.csproj create mode 100644 interop/packages.config diff --git a/interop.sln b/interop.sln new file mode 100644 index 0000000..48e856b --- /dev/null +++ b/interop.sln @@ -0,0 +1,22 @@ + +Microsoft Visual Studio Solution File, Format Version 12.00 +# Visual Studio 15 +VisualStudioVersion = 15.0.26430.6 +MinimumVisualStudioVersion = 10.0.40219.1 +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "interop", "interop\interop.csproj", "{E67C0218-5911-4ACC-8449-E4A791200B78}" +EndProject +Global + GlobalSection(SolutionConfigurationPlatforms) = preSolution + Debug|Any CPU = Debug|Any CPU + Release|Any CPU = Release|Any CPU + EndGlobalSection + GlobalSection(ProjectConfigurationPlatforms) = postSolution + {E67C0218-5911-4ACC-8449-E4A791200B78}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {E67C0218-5911-4ACC-8449-E4A791200B78}.Debug|Any CPU.Build.0 = Debug|Any CPU + {E67C0218-5911-4ACC-8449-E4A791200B78}.Release|Any CPU.ActiveCfg = Release|Any CPU + {E67C0218-5911-4ACC-8449-E4A791200B78}.Release|Any CPU.Build.0 = Release|Any CPU + EndGlobalSection + GlobalSection(SolutionProperties) = preSolution + HideSolutionNode = FALSE + EndGlobalSection +EndGlobal diff --git a/interop/App.config b/interop/App.config new file mode 100644 index 0000000..4543795 --- /dev/null +++ b/interop/App.config @@ -0,0 +1,6 @@ + + + + + + diff --git a/interop/Program.cs b/interop/Program.cs new file mode 100644 index 0000000..9bcae44 --- /dev/null +++ b/interop/Program.cs @@ -0,0 +1,341 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Text.RegularExpressions; +using System.Threading.Tasks; +using System.Timers; +using WebSocketSharp; +using Newtonsoft.Json; +using System.IO; +using System.Runtime.InteropServices; +using System.Security.Cryptography; + +namespace interop { + class Program { + const Int32 SW_MINIMIZE = 6; + + [DllImport("Kernel32.dll", CallingConvention = CallingConvention.StdCall, SetLastError = true)] + private static extern IntPtr GetConsoleWindow(); + + [DllImport("User32.dll", CallingConvention = CallingConvention.StdCall, SetLastError = true)] + [return: MarshalAs(UnmanagedType.Bool)] + private static extern bool ShowWindow([In] IntPtr hWnd, [In] Int32 nCmdShow); + + private static int UserId = -1; + private static object IOLock = new object(); + private static List Logs = new List(); + private static Dictionary Users = new Dictionary(); + private static WebSocket Sock; + private static bool Shown = true; + private static Timer pingTimer; + + private static Dictionary BotDefs = new Dictionary(); + private static Dictionary BotErrorDefs = new Dictionary(); + + private static string Username; + private static string Password; + + static void MoveCursor(int x, int y) { + Console.CursorLeft = x; + Console.CursorTop = y + (Shown ? 0 : Console.WindowHeight); + } + + static string Pack(int id, params string[] data) { + var newData = data.ToList(); + newData.Insert(0, id.ToString()); + return String.Join("\t", newData); + } + + static Packet Unpack(string data) { + var parts = data.Split('\t'); + return new Packet { + Id = Int32.Parse(parts[0]), + Data = parts.Skip(1).ToList() + }; + } + + static string ShortenName(string name) { + return name.Length < 8 ? name.PadLeft(8, ' ') : name.Substring(0, 8); + } + + static int GetLineCount(Message message) { + var lines = message.Contents.Split(new[] { "\r\n" }, StringSplitOptions.None); + int lineCount = 0; + for(int i = 0; i < lines.Length; ++i) { + int lineLength = lines[i].Length + (i == 0 ? 15 : 0); + lineCount += (int)Math.Ceiling((double)lineLength / (double)Console.WindowWidth); + } + + return lineCount + (lines.Length > 1 ? 1 : 0); + } + + static void CorrectMessage(ref Message message) { + message.Sender = ShortenName(message.Sender); + message.Contents = Regex.Replace(message.Contents, @"\[.*?\]", ""); + message.Contents = message.Contents.Replace("\r", ""); + message.Contents = message.Contents.Replace("
", "\r\n"); + message.Contents = message.Contents.Replace("<", "<"); + message.Contents = message.Contents.Replace(">", ">"); + } + + static void LoadLanguageFile(string raw) { + var data = JsonConvert.DeserializeObject>>(raw); + + foreach(var pair in data["botText"]) + BotDefs.Add(pair.Key, pair.Value); + foreach(var pair in data["botErrText"]) + BotErrorDefs.Add(pair.Key, pair.Value); + } + + static string ParseBotMessage(string raw) { + var parts = raw.Split('\f'); + + bool isErr = parts[0] == "1"; + var outMsg = raw; + if((isErr ? BotErrorDefs : BotDefs).ContainsKey(parts[1])) { + outMsg = (isErr ? BotErrorDefs : BotDefs)[parts[1]]; + for(int i = 2; i < parts.Length; ++i) + outMsg = outMsg.Replace("{"+ (i - 2) +"}", parts[i]); + } + + return outMsg; + } + + static void WriteMessage(Message message) { + CorrectMessage(ref message); + + lock(IOLock) { + int cx = Console.CursorLeft, cy = Console.CursorTop; + + var lineCount = GetLineCount(message); + if(lineCount > Console.WindowHeight - 3) + message.Contents = "This message was too long to show."; + + if(Shown) + Console.MoveBufferArea(0, lineCount, Console.WindowWidth, Console.WindowHeight - lineCount - 3, 0, 0); + else + Console.MoveBufferArea(0, Console.WindowHeight + lineCount, Console.WindowWidth, Console.WindowHeight - lineCount - 3, 0, Console.WindowHeight); + MoveCursor(0, Console.WindowHeight - 3 - lineCount); + + Console.Write(message.Sent.ToString("HHmm")); + Console.Write(" "); + Console.Write(message.Sender); + Console.Write(": "); + Console.Write(message.Contents); + + Console.CursorLeft = cx; + Console.CursorTop = cy; + } + } + + static string HashToString(byte[] hash) { + var sb = new StringBuilder(hash.Length * 2); + foreach(var b in hash) + sb.Append(b.ToString("x2")); + + return sb.ToString(); + } + + static void Main(string[] args) { + Console.Write("Enter username: "); + Username = Console.ReadLine(); + + using(var sha = new SHA1Managed()) { + Console.Write("Enter password: "); + Password = HashToString(sha.ComputeHash(Encoding.UTF8.GetBytes(HashToString(sha.ComputeHash(Encoding.UTF8.GetBytes(Console.ReadLine())))))); + } + + LoadLanguageFile(Properties.Resources.CommonLang); + LoadLanguageFile(Properties.Resources.CoreLang); + + Console.CursorLeft = 0; + Console.CursorTop = Console.WindowHeight - 3; + Console.Write(new String('~', Console.WindowWidth)); + Console.Write("> "); + + Console.SetBufferSize(Console.WindowWidth, Console.WindowHeight * 2); + using(Sock = new WebSocket(Properties.Resources.ConnectionAddress)) { + Users.Add(-1, "ChatBot"); + Sock.OnOpen += OnOpen; + Sock.OnMessage += OnMessage; + Sock.OnClose += Sock_OnClose; + Sock.Connect(); + + string message = ""; + while(true) { + var key = Console.ReadKey(true); + + lock(IOLock) { + switch(key.KeyChar) { + case '\x08': + if(!Shown) + break; + if(message.Length == 0) + break; + + message = message.Substring(0, message.Length - 1); + if(Console.CursorLeft == 0) { + Console.CursorTop--; + Console.CursorLeft = Console.WindowWidth; + Console.Write(' '); + + Console.CursorTop--; + Console.CursorLeft = Console.WindowWidth; + } else { + Console.CursorLeft--; + Console.Write(' '); + Console.CursorLeft--; + } + break; + case '\x0A': + case '\x0D': + if(!Shown) + break; + + Console.CursorTop = Console.WindowHeight - 2; + Console.CursorLeft = 0; + + Console.Write(">"); + Console.Write(new String(' ', Console.WindowWidth * 2 - 5)); + Console.CursorTop = Console.WindowHeight - 2; + Console.CursorLeft = 2; + + //message = message.Trim() + " de geso~"; + Sock.Send(Pack(2, UserId.ToString(), message)); + message = ""; + break; + case '\x1B': + Sock.Send(Pack(2, UserId.ToString(), "brb (auto)")); + var hwndCli = GetConsoleWindow(); + ShowWindow(hwndCli, SW_MINIMIZE); + break; + default: + if(!Shown) + break; + + message += key.KeyChar; + Console.Write(key.KeyChar); + break; + } + } + } + + Sock.Close(); + } + } + + private static void Sock_OnClose(object sender, CloseEventArgs e) { + Environment.Exit(0); + } + + static void OnOpen(object sender, EventArgs e) { + Sock.Send(Pack(1, Username, Password)); + + /* +#if DEBUG + Sock.Send(Pack(1, Properties.Resources.ConnectionUserDebug, Properties.Resources.ConnectionPwd)); +#else + Sock.Send(Pack(1, Properties.Resources.ConnectionUserRelease, Properties.Resources.ConnectionPwd)); +#endif + */ + } + + private static void PingTimer_Elapsed(object sender, ElapsedEventArgs e) { + Sock.Send(Pack(0, UserId.ToString())); + } + + static void OnMessage(object sender, MessageEventArgs e) { + var msg = Unpack(e.Data); + Message message; + + switch(msg.Id) { + case 1: + if(UserId == -1) { + UserId = Int32.Parse(msg.Data[1]); + Users.Add(UserId, msg.Data[2]); + + pingTimer = new Timer(30000); + pingTimer.AutoReset = true; + pingTimer.Elapsed += PingTimer_Elapsed; + pingTimer.Enabled = true; + } else { + var userId = Int32.Parse(msg.Data[1]); + try { + Users.Add(userId, msg.Data[2]); + } catch { } + + message = new Message { + Sent = DateTime.Now, + Sender = Users[-1], + Contents = $"{Users[userId]} joined." + }; + Logs.Add(message); + WriteMessage(message); + } + break; + case 2: + var userIdd = Int32.Parse(msg.Data[1]); + + message = new Message { + Sent = DateTimeOffset.FromUnixTimeSeconds(Int64.Parse(msg.Data[0])).ToLocalTime().DateTime, + Sender = Users[userIdd], + Contents = userIdd == -1 + ? ParseBotMessage(msg.Data[2]) + : msg.Data[2] + }; + + Logs.Add(message); + WriteMessage(message); + break; + case 3: + message = new Message { + Sent = DateTime.Now, + Sender = Users[-1], + Contents = $"{msg.Data[1]} " + (msg.Data[2] == "leave" ? "left." : "was kicked.") + }; + + Logs.Add(message); + WriteMessage(message); + break; + case 7: + if(msg.Data[0] == "0") { + int count = Int32.Parse(msg.Data[1]); + + for(int i = 0; i < count; ++i) { + int ix = 2 + 5*i; + try { + Users.Add(Int32.Parse(msg.Data[ix]), msg.Data[ix + 1]); + } catch { } + } + } else { + message = new Message { + Sent = DateTimeOffset.FromUnixTimeSeconds(Int64.Parse(msg.Data[1])).ToLocalTime().DateTime, + Sender = msg.Data[3], + Contents = msg.Data[2] == "-1" + ? ParseBotMessage(msg.Data[6]) + : msg.Data[6] + }; + + Logs.Add(message); + WriteMessage(message); + } + break; + case 10: + Users[Int32.Parse(msg.Data[0])] = msg.Data[1]; + break; + } + } + + class Message { + public DateTime Sent { get; set; } + public string Sender { get; set; } + public string Contents { get; set; } + } + + class Packet { + public int Id { get; set; } + public List Data { get; set; } + } + } +} diff --git a/interop/Properties/AssemblyInfo.cs b/interop/Properties/AssemblyInfo.cs new file mode 100644 index 0000000..ae18c7f --- /dev/null +++ b/interop/Properties/AssemblyInfo.cs @@ -0,0 +1,36 @@ +using System.Reflection; +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; + +// General Information about an assembly is controlled through the following +// set of attributes. Change these attribute values to modify the information +// associated with an assembly. +[assembly: AssemblyTitle("interop")] +[assembly: AssemblyDescription("")] +[assembly: AssemblyConfiguration("")] +[assembly: AssemblyCompany("")] +[assembly: AssemblyProduct("interop")] +[assembly: AssemblyCopyright("Copyright © 2018")] +[assembly: AssemblyTrademark("")] +[assembly: AssemblyCulture("")] + +// Setting ComVisible to false makes the types in this assembly not visible +// to COM components. If you need to access a type in this assembly from +// COM, set the ComVisible attribute to true on that type. +[assembly: ComVisible(false)] + +// The following GUID is for the ID of the typelib if this project is exposed to COM +[assembly: Guid("e67c0218-5911-4acc-8449-e4a791200b78")] + +// Version information for an assembly consists of the following four values: +// +// Major Version +// Minor Version +// Build Number +// Revision +// +// You can specify all the values or you can default the Build and Revision Numbers +// by using the '*' as shown below: +// [assembly: AssemblyVersion("1.0.*")] +[assembly: AssemblyVersion("1.0.0.0")] +[assembly: AssemblyFileVersion("1.0.0.0")] diff --git a/interop/Properties/Resources.Designer.cs b/interop/Properties/Resources.Designer.cs new file mode 100644 index 0000000..6f51a5b --- /dev/null +++ b/interop/Properties/Resources.Designer.cs @@ -0,0 +1,141 @@ +//------------------------------------------------------------------------------ +// +// This code was generated by a tool. +// Runtime Version:4.0.30319.42000 +// +// Changes to this file may cause incorrect behavior and will be lost if +// the code is regenerated. +// +//------------------------------------------------------------------------------ + +namespace interop.Properties { + using System; + + + /// + /// A strongly-typed resource class, for looking up localized strings, etc. + /// + // This class was auto-generated by the StronglyTypedResourceBuilder + // class via a tool like ResGen or Visual Studio. + // To add or remove a member, edit your .ResX file then rerun ResGen + // with the /str option, or rebuild your VS project. + [global::System.CodeDom.Compiler.GeneratedCodeAttribute("System.Resources.Tools.StronglyTypedResourceBuilder", "4.0.0.0")] + [global::System.Diagnostics.DebuggerNonUserCodeAttribute()] + [global::System.Runtime.CompilerServices.CompilerGeneratedAttribute()] + internal class Resources { + + private static global::System.Resources.ResourceManager resourceMan; + + private static global::System.Globalization.CultureInfo resourceCulture; + + [global::System.Diagnostics.CodeAnalysis.SuppressMessageAttribute("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")] + internal Resources() { + } + + /// + /// Returns the cached ResourceManager instance used by this class. + /// + [global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)] + internal static global::System.Resources.ResourceManager ResourceManager { + get { + if (object.ReferenceEquals(resourceMan, null)) { + global::System.Resources.ResourceManager temp = new global::System.Resources.ResourceManager("interop.Properties.Resources", typeof(Resources).Assembly); + resourceMan = temp; + } + return resourceMan; + } + } + + /// + /// Overrides the current thread's CurrentUICulture property for all + /// resource lookups using this strongly typed resource class. + /// + [global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)] + internal static global::System.Globalization.CultureInfo Culture { + get { + return resourceCulture; + } + set { + resourceCulture = value; + } + } + + /// + /// Looks up a localized string similar to { + /// "botText": { + /// "say" : "{0}", + /// "join" : "{0} has joined the chat.", + /// "leave" : "{0} has disconnected.", + /// "jchan" : "{0} entered the channel.", + /// "lchan" : "{0} left the channel.", + /// "kick" : "{0} has been kicked.", + /// "nick" : "{0} is now known as {1}.", + /// "crchan" : "{0} has been created.", + /// "delchan" : "{0} has been deleted.", + /// "cpwdchan" : "Password changed successfully.", + /// "cpr [rest of string was truncated]";. + /// + internal static string CommonLang { + get { + return ResourceManager.GetString("CommonLang", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to ws://aroltd.com:17777. + /// + internal static string ConnectionAddress { + get { + return ResourceManager.GetString("ConnectionAddress", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to e25c69c67adfc9e62fcd661b3e825cb3d5357652. + /// + internal static string ConnectionPwd { + get { + return ResourceManager.GetString("ConnectionPwd", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to malloc2. + /// + internal static string ConnectionUserDebug { + get { + return ResourceManager.GetString("ConnectionUserDebug", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to malloc. + /// + internal static string ConnectionUserRelease { + get { + return ResourceManager.GetString("ConnectionUserRelease", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to { + /// "botText": { + /// "silence": "You have been silenced!", + /// "unsil": "You have been unsilenced!", + /// "usilok": "{0} has been unsilenced.", + /// "silok": "{0} has been silenced." + /// }, + /// "botErrText": { + /// "silerr": "Error: User is already silenced!", + /// "usilerr": "Error: User is not silenced!", + /// "silperr": "Error: You are not allowed to silence this user!", + /// "usilperr": "Error: You are not allowed to unsilence this user!", + /// "si [rest of string was truncated]";. + /// + internal static string CoreLang { + get { + return ResourceManager.GetString("CoreLang", resourceCulture); + } + } + } +} diff --git a/interop/Properties/Resources.resx b/interop/Properties/Resources.resx new file mode 100644 index 0000000..ec7c4b5 --- /dev/null +++ b/interop/Properties/Resources.resx @@ -0,0 +1,189 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + text/microsoft-resx + + + 2.0 + + + System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + { + "botText": { + "say" : "{0}", + "join" : "{0} has joined the chat.", + "leave" : "{0} has disconnected.", + "jchan" : "{0} entered the channel.", + "lchan" : "{0} left the channel.", + "kick" : "{0} has been kicked.", + "nick" : "{0} is now known as {1}.", + "crchan" : "{0} has been created.", + "delchan" : "{0} has been deleted.", + "cpwdchan" : "Password changed successfully.", + "cprivchan" : "Channel privilege changed successfully.", + "ipaddr" : "User {0} - IP Address: {1}" + }, + "botErrText": { + "nolang" : "Error: Chatbot sent {1} id '{0}' with no definition in this language!", + "nocmd" : "Error: Command {0} not found!", + "cmdna" : "Error: Not allowed to use {0}!", + "cmderr" : "Error: Command formatted incorrectly!", + "usernf" : "Error: User {0} not found!", + "kickna" : "Error: Not allowed to kick {0}!", + "samechan" : "Error: You are already in {0}!", + "nochan" : "Error: Channel {0} does not exist!", + "ipchan" : "Error: You are not allowed to join {0}!", + "nopwchan" : "Error: Channel {0} is password-protected! Use '/join {0} [password]'.", + "ipwchan" : "Error: Password to channel {0} is incorrect!", + "inchan" : "Error: Channel name cannot start with a @ or *!", + "nischan" : "Error: Channel {0} already exists!", + "ndchan" : "Error: You are not allowed to delete channel {0}!", + "namchan" : "Error: You are not allowed to modify channel {0}!", + "nameinuse" : "Error: Username {0} in use!", + "rankerr" : "Error: Cannot set channel privilege higher than your own!", + "reconnect" : "Connection lost! Attempting to reconnect automatically...", + "logerr" : "Server uses the flat file database implementation and cannot serve logs to clients. To view chat logs, open the logs.txt file in the ffdb folder in the server's root directory.", + "generr" : "An error has occurred!" + } +} + + + ws://aroltd.com:17777 + + + e25c69c67adfc9e62fcd661b3e825cb3d5357652 + + + malloc2 + + + malloc + + + { + "botText": { + "silence": "You have been silenced!", + "unsil": "You have been unsilenced!", + "usilok": "{0} has been unsilenced.", + "silok": "{0} has been silenced." + }, + "botErrText": { + "silerr": "Error: User is already silenced!", + "usilerr": "Error: User is not silenced!", + "silperr": "Error: You are not allowed to silence this user!", + "usilperr": "Error: You are not allowed to unsilence this user!", + "silself": "Error: You cannot silence yourself!" + } +} + + \ No newline at end of file diff --git a/interop/interop.csproj b/interop/interop.csproj new file mode 100644 index 0000000..68bfd63 --- /dev/null +++ b/interop/interop.csproj @@ -0,0 +1,71 @@ + + + + + Debug + AnyCPU + {E67C0218-5911-4ACC-8449-E4A791200B78} + Exe + interop + interop + v4.6.1 + 512 + true + + + + AnyCPU + true + full + false + bin\Debug\ + DEBUG;TRACE + prompt + 4 + + + AnyCPU + pdbonly + true + bin\Release\ + TRACE + prompt + 4 + + + + ..\packages\Newtonsoft.Json.11.0.2\lib\net45\Newtonsoft.Json.dll + + + + + + + + + + + ..\packages\WebSocketSharp.1.0.3-rc11\lib\websocket-sharp.dll + + + + + + + True + True + Resources.resx + + + + + + + + + ResXFileCodeGenerator + Resources.Designer.cs + + + + \ No newline at end of file diff --git a/interop/packages.config b/interop/packages.config new file mode 100644 index 0000000..cdb65c2 --- /dev/null +++ b/interop/packages.config @@ -0,0 +1,5 @@ + + + + + \ No newline at end of file