/** * Actual main function. Wrapped into a separate function so we can catch exceptions. */ private static void StartDeceive(string[] cmdArgs) { // We are supposed to launch league, so if it's already running something is going wrong. if (Utils.IsClientRunning() && cmdArgs.All(x => x.ToLower() != "--allow-multiple-clients")) { var result = MessageBox.Show( "The Riot Client is currently running. In order to mask your online status, the Riot Client needs to be started by Deceive. " + "Do you want Deceive to stop the Riot Client and games launched by it, so that it can restart with the proper configuration?", DeceiveTitle, MessageBoxButtons.YesNo, MessageBoxIcon.Question, MessageBoxDefaultButton.Button1 ); if (result != DialogResult.Yes) { return; } Utils.KillProcesses(); Thread.Sleep(2000); // Riot Client takes a while to die } try { File.WriteAllText(Path.Combine(Utils.DataDir, "debug.log"), string.Empty); Debug.Listeners.Add(new TextWriterTraceListener(Path.Combine(Utils.DataDir, "debug.log"))); Debug.AutoFlush = true; Trace.WriteLine(DeceiveTitle); } catch { // ignored; just don't save logs if file is already being accessed } // Step 0: Check for updates in the background. Utils.CheckForUpdates(); // Step 1: Open a port for our chat proxy, so we can patch chat port into clientconfig. var listener = new TcpListener(IPAddress.Loopback, 0); listener.Start(); var port = ((IPEndPoint)listener.LocalEndpoint).Port; // Step 2: Find the Riot Client. var riotClientPath = Utils.GetRiotClientPath(); // If the riot client doesn't exist, the user is either severely outdated or has a bugged install. if (riotClientPath == null) { MessageBox.Show( "Deceive was unable to find the path to the Riot Client. If you have the game installed and it is working properly, " + "please file a bug report through GitHub (https://github.com/molenzwiebel/deceive) or Discord.", DeceiveTitle, MessageBoxButtons.OK, MessageBoxIcon.Error, MessageBoxDefaultButton.Button1 ); return; } // Step 3: Start proxy web server for clientconfig var proxyServer = new ConfigProxy("https://clientconfig.rpg.riotgames.com", port); // Step 4: Start the Riot Client and wait for a connect. var game = "league_of_legends"; if (cmdArgs.Any(x => x.ToLower() == "lor")) { game = "bacon"; } if (cmdArgs.Any(x => x.ToLower() == "valorant")) { game = "valorant"; } var startArgs = new ProcessStartInfo { FileName = riotClientPath, Arguments = $"--client-config-url=\"http://127.0.0.1:{proxyServer.ConfigPort}\" --launch-product={game} --launch-patchline=live" }; if (cmdArgs.Any(x => x.ToLower() == "--allow-multiple-clients")) { startArgs.Arguments += " --allow-multiple-clients"; } var riotClient = Process.Start(startArgs); // Kill Deceive when Riot Client has exited, so no ghost Deceive exists. if (riotClient != null) { riotClient.EnableRaisingEvents = true; riotClient.Exited += (sender, args) => { Trace.WriteLine("Exiting on Riot Client exit."); Environment.Exit(0); }; } // Step 5: Get chat server and port for this player by listening to event from ConfigProxy. string chatHost = null; var chatPort = 0; proxyServer.PatchedChatServer += (sender, args) => { chatHost = args.ChatHost; chatPort = args.ChatPort; }; var incoming = listener.AcceptTcpClient(); // Step 6: Connect sockets. var sslIncoming = new SslStream(incoming.GetStream()); var cert = new X509Certificate2(Resources.Certificate); sslIncoming.AuthenticateAsServer(cert); if (chatHost == null) { MessageBox.Show( "Deceive was unable to find Riot's chat server, please try again later. " + "If this issue persists and you can connect to chat normally without Deceive, " + "please file a bug report through GitHub (https://github.com/molenzwiebel/deceive) or Discord.", DeceiveTitle, MessageBoxButtons.OK, MessageBoxIcon.Error, MessageBoxDefaultButton.Button1 ); return; } var outgoing = new TcpClient(chatHost, chatPort); var sslOutgoing = new SslStream(outgoing.GetStream()); sslOutgoing.AuthenticateAsClient(chatHost); // Step 7: All sockets are now connected, start tray icon. var mainController = new MainController(); mainController.StartThreads(sslIncoming, sslOutgoing); mainController.ConnectionErrored += (sender, args) => { Trace.WriteLine("Trying to reconnect."); sslIncoming.Close(); sslOutgoing.Close(); incoming.Close(); outgoing.Close(); incoming = listener.AcceptTcpClient(); sslIncoming = new SslStream(incoming.GetStream()); sslIncoming.AuthenticateAsServer(cert); while (true) { try { outgoing = new TcpClient(chatHost, chatPort); break; } catch (SocketException e) { Trace.WriteLine(e); var result = MessageBox.Show( "Unable to reconnect to the chat server. Please check your internet connection." + "If this issue persists and you can connect to chat normally without Deceive, " + "please file a bug report through GitHub (https://github.com/molenzwiebel/deceive) or Discord.", DeceiveTitle, MessageBoxButtons.RetryCancel, MessageBoxIcon.Error, MessageBoxDefaultButton.Button1 ); if (result == DialogResult.Cancel) { Environment.Exit(0); } } } sslOutgoing = new SslStream(outgoing.GetStream()); sslOutgoing.AuthenticateAsClient(chatHost); mainController.StartThreads(sslIncoming, sslOutgoing); }; Application.EnableVisualStyles(); Application.Run(mainController); }
/** * Actual main function. Wrapped into a separate function so we can catch exceptions. */ private static void StartDeceive() { // We are supposed to launch league, so if it's already running something is going wrong. if (Utils.IsLCURunning()) { Utils.InitPathWithRunningLCU(); var result = MessageBox.Show( "League is currently running. In order to mask your online status, League needs to be started by Deceive. Do you want Deceive to stop League, so that it can restart it with the proper configuration?", Resources.DeceiveTitle, MessageBoxButtons.YesNo, MessageBoxIcon.Question, MessageBoxDefaultButton.Button1 ); if (result != DialogResult.Yes) { return; } Utils.KillLCU(); } // Step 1: Open a port for our proxy, so we can patch the port number into the system yaml. var listener = new TcpListener(IPAddress.Loopback, 0); listener.Start(); var port = ((IPEndPoint)listener.LocalEndpoint).Port; // Step 2: Find original system.yaml, patch our localhost proxy in, and save it somewhere. // At the same time, also parse the system.yaml to get the original chat server locations. var sysYamlPath = Utils.GetSystemYamlPath(); if (sysYamlPath == null) // If this is null, it means we canceled something that required manual user input. Just exit. { return; } var contents = File.ReadAllText(sysYamlPath); // Load the stream var yaml = new YamlStream(); yaml.Load(new StringReader(contents)); contents = contents.Replace("allow_self_signed_cert: false", "allow_self_signed_cert: true"); contents = contents.Replace("chat_port: 5223", "chat_port: " + port); contents = new Regex("chat_host: .*?\t?\n").Replace(contents, "chat_host: localhost\n"); // Write this to the league install folder and not the appdata folder. // This is because league segfaults if you give it an override path with unicode characters, // such as some users with a special character in their Windows user name may have. // We put it in the Config folder since the new patcher will nuke any non-league files in the install root. var leaguePath = Utils.GetLCUPath(); var yamlPath = Path.Combine(Path.GetDirectoryName(leaguePath), "Config", "deceive-system.yaml"); File.WriteAllText(yamlPath, contents); // Step 3: Either launch Riot Client or launch League, depending on local configuration. var riotClientPath = Utils.GetRiotClientPath(); ProcessStartInfo startArgs; if (riotClientPath != null && File.Exists(riotClientPath)) { startArgs = new ProcessStartInfo { FileName = riotClientPath, Arguments = "--priority-launch-pid=12345 --priority-launch-path=\"" + leaguePath + "\" -- --system-yaml-override=\"" + yamlPath + "\"" }; } else { startArgs = new ProcessStartInfo { FileName = leaguePath, Arguments = "--system-yaml-override=\"" + yamlPath + "\"" }; } // Step 4: Start the process and wait for a connect. Process.Start(startArgs); var incoming = listener.AcceptTcpClient(); // Step 5: Connect sockets. var sslIncoming = new SslStream(incoming.GetStream()); var cert = new X509Certificate2(Resources.certificates); sslIncoming.AuthenticateAsServer(cert); // Find the chat information of the original system.yaml for that region. var regionDetails = yaml.Documents[0].RootNode["region_data"][Utils.GetLCURegion()]["servers"]["chat"]; var chatHost = regionDetails["chat_host"].ToString(); var chatPort = int.Parse(regionDetails["chat_port"].ToString()); var outgoing = new TcpClient(chatHost, chatPort); var sslOutgoing = new SslStream(outgoing.GetStream()); sslOutgoing.AuthenticateAsClient(chatHost); // Step 6: All sockets are now connected, start tray icon. var mainController = new MainController(); mainController.StartThreads(sslIncoming, sslOutgoing); Application.EnableVisualStyles(); Application.Run(mainController); }