using OpenQA.Selenium; using OpenQA.Selenium.Chrome; using OpenQA.Selenium.Firefox; using OpenQA.Selenium.Interactions; using RuriLib.LS; using RuriLib.ViewModels; using System; using System.Drawing; using System.IO; using System.Linq; using System.Text.RegularExpressions; using System.Threading; using System.Windows.Media; namespace RuriLib { /// /// The actions that can be performed on a browser. /// public enum BrowserAction { /// Starts the driver and opens the browser. Open, /// Closes the browser but not the driver. Close, /// Closes the browser and disposes the driver. Quit, /// Clears the cookies in the browser. ClearCookies, /// Sends some keystrokes to the browser. Special keys like <ENTER> can be sent, separated by two pipe characters e.g. <TAB>||<ENTER> SendKeys, /// Takes a screenshot of the visible part of the page. Screenshot, /// Scrolls to the top of the page. ScrollToTop, /// Scrolls to the bottom of the page. ScrollToBottom, /// Scrolls down by a given number of pixels from the top of the page. Scroll, /// Switches to the browser tab with a given index. SwitchToTab, /// Refreshes the current page. Refresh, /// Goes to the previous page. Back, /// Goes to the next page. Forward, /// Maximizes the browser window. Maximize, /// Minimizes the browser window. Minimize, /// Sets the browser window as full screen. FullScreen, /// Sets the browser window's width. SetWidth, /// Sets the browser window's height. SetHeight, /// Sets the DOM (the page source modified by the javascript code) into the SOURCE variable. DOMtoSOURCE, /// Transfers the cookies from the browser to the HTTP cookie jar. GetCookies, /// Transfers the cookies from the HTTP cookie jar to the browser. SetCookies, /// Switches to the default content. SwitchToDefault, /// Switches to the alert message. SwitchToAlert, /// Switches to the default frame (useful to get out of an iframe). SwitchToParentFrame } /// /// A block that can interact with a selenium-driven browser. /// public class SBlockBrowserAction : BlockBase { private BrowserAction action = BrowserAction.Open; /// The action that is performed on the browser. public BrowserAction Action { get { return action; } set { action = value; OnPropertyChanged(); } } private string input = ""; /// The input string. public string Input { get { return input; } set { input = value; OnPropertyChanged(); } } // Constructor /// /// Creates a BrowserAction block. /// public SBlockBrowserAction() { Label = "BROWSER ACTION"; } /// public override BlockBase FromLS(string line) { // Trim the line var input = line.Trim(); // Parse the label if (input.StartsWith("#")) Label = LineParser.ParseLabel(ref input); /* * Syntax: * BROWSERACTION ACTION ["INPUT"] * */ Action = (BrowserAction)LineParser.ParseEnum(ref input, "ACTION", typeof(BrowserAction)); if (input != "") Input = LineParser.ParseLiteral(ref input, "INPUT"); return this; } /// public override string ToLS(bool indent = true) { var writer = new BlockWriter(GetType(), indent, Disabled); writer .Label(Label) .Token("BROWSERACTION") .Token(Action) .Literal(Input, "Input"); return writer.ToString(); } /// public override void Process(BotData data) { base.Process(data); if (data.Driver == null && action != BrowserAction.Open) { data.Log(new LogEntry("Open a browser first!", Colors.White)); throw new Exception("Browser not open"); } var replacedInput = ReplaceValues(input, data); switch (action) { case BrowserAction.Open: OpenBrowser(data); try { UpdateSeleniumData(data); } catch { } break; case BrowserAction.Close: data.Driver.Close(); data.BrowserOpen = false; break; case BrowserAction.Quit: data.Driver.Quit(); data.BrowserOpen = false; break; case BrowserAction.ClearCookies: data.Driver.Manage().Cookies.DeleteAllCookies(); break; case BrowserAction.SendKeys: var action = new Actions(data.Driver); foreach(var s in replacedInput.Split(new string[] { "||" }, StringSplitOptions.None)) { switch (s) { case "": action.SendKeys(OpenQA.Selenium.Keys.Tab); break; case "": action.SendKeys(OpenQA.Selenium.Keys.Enter); break; case "": action.SendKeys(OpenQA.Selenium.Keys.Backspace); break; case "": action.SendKeys(OpenQA.Selenium.Keys.Escape); break; default: action.SendKeys(s); break; } } action.Perform(); Thread.Sleep(1000); if(replacedInput.Contains("") || replacedInput.Contains("")) // These might lead to a page change UpdateSeleniumData(data); break; case BrowserAction.Screenshot: var image = data.Driver.GetScreenshot(); SaveScreenshot(image, data); break; case BrowserAction.SwitchToTab: data.Driver.SwitchTo().Window(data.Driver.WindowHandles[int.Parse(replacedInput)]); UpdateSeleniumData(data); break; case BrowserAction.Refresh: data.Driver.Navigate().Refresh(); break; case BrowserAction.Back: data.Driver.Navigate().Back(); break; case BrowserAction.Forward: data.Driver.Navigate().Forward(); break; case BrowserAction.Maximize: data.Driver.Manage().Window.Maximize(); break; case BrowserAction.Minimize: data.Driver.Manage().Window.Minimize(); break; case BrowserAction.FullScreen: data.Driver.Manage().Window.FullScreen(); break; case BrowserAction.SetWidth: data.Driver.Manage().Window.Size = new Size(int.Parse(replacedInput), data.Driver.Manage().Window.Size.Height); break; case BrowserAction.SetHeight: data.Driver.Manage().Window.Size = new Size(data.Driver.Manage().Window.Size.Width, int.Parse(replacedInput)); break; case BrowserAction.DOMtoSOURCE: data.ResponseSource = data.Driver.FindElement(By.TagName("body")).GetAttribute("innerHTML"); break; case BrowserAction.GetCookies: foreach(var cookie in data.Driver.Manage().Cookies.AllCookies) { try { data.Cookies.Add(cookie.Name, cookie.Value); } catch { } } break; case BrowserAction.SetCookies: var baseURL = Regex.Match(ReplaceValues(input, data), "^(?:https?:\\/\\/)?(?:[^@\\/\n]+@)?(?:www\\.)?([^:\\/?\n]+)").Groups[1].Value; foreach (var cookie in data.Cookies) { try { data.Driver.Manage().Cookies.AddCookie(new Cookie(cookie.Key, cookie.Value, baseURL, "/", DateTime.MaxValue)); } catch { } } break; case BrowserAction.SwitchToDefault: data.Driver.SwitchTo().DefaultContent(); break; case BrowserAction.SwitchToAlert: data.Driver.SwitchTo().Alert(); break; case BrowserAction.SwitchToParentFrame: data.Driver.SwitchTo().ParentFrame(); break; } data.Log(new LogEntry(string.Format("Executed browser action {0} on input {1}", action, ReplaceValues(input, data)), Colors.White)); } /// /// Opens a browser of the given type (if not already open) and with the given settings. /// /// The BotData where the settings are stored. public static void OpenBrowser(BotData data) { if (!data.BrowserOpen) { data.Log(new LogEntry("Opening browser...", Colors.White)); switch (data.GlobalSettings.Selenium.Browser) { case BrowserType.Chrome: try { ChromeOptions chromeop = new ChromeOptions(); ChromeDriverService chromeservice = ChromeDriverService.CreateDefaultService(); chromeservice.SuppressInitialDiagnosticInformation = true; chromeservice.HideCommandPromptWindow = true; chromeservice.EnableVerboseLogging = false; chromeop.AddArgument("--log-level=3"); chromeop.BinaryLocation = data.GlobalSettings.Selenium.ChromeBinaryLocation; if (data.GlobalSettings.Selenium.Headless || data.ConfigSettings.ForceHeadless) chromeop.AddArgument("--headless"); else if (data.GlobalSettings.Selenium.ChromeExtensions.Count > 0) // This should only be done when not headless chromeop.AddExtensions(data.GlobalSettings.Selenium.ChromeExtensions .Where(ext => ext.EndsWith(".crx")) .Select(ext => Directory.GetCurrentDirectory() + "\\ChromeExtensions\\" + ext)); if (data.ConfigSettings.DisableNotifications) chromeop.AddArgument("--disable-notifications"); if (data.ConfigSettings.CustomCMDArgs != "") chromeop.AddArgument(data.ConfigSettings.CustomCMDArgs); if (data.ConfigSettings.RandomUA) chromeop.AddArgument("--user-agent=" + BlockFunction.RandomUserAgent(data.rand)); else if (data.ConfigSettings.CustomUserAgent != "") chromeop.AddArgument("--user-agent=" + data.ConfigSettings.CustomUserAgent); if (data.UseProxies) chromeop.AddArgument("--proxy-server=" + data.Proxy.Type.ToString().ToLower() + "://" + data.Proxy.Proxy); data.Driver = new ChromeDriver(chromeservice, chromeop); } catch (Exception ex) { data.Log(new LogEntry(ex.ToString(), Colors.White)); return; } break; case BrowserType.Firefox: try { FirefoxOptions fireop = new FirefoxOptions(); FirefoxDriverService fireservice = FirefoxDriverService.CreateDefaultService(); FirefoxProfile fireprofile = new FirefoxProfile(); fireservice.SuppressInitialDiagnosticInformation = true; fireservice.HideCommandPromptWindow = true; fireop.AddArgument("--log-level=3"); fireop.BrowserExecutableLocation = data.GlobalSettings.Selenium.FirefoxBinaryLocation; if (data.GlobalSettings.Selenium.Headless || data.ConfigSettings.ForceHeadless) fireop.AddArgument("--headless"); if (data.ConfigSettings.DisableNotifications) fireprofile.SetPreference("dom.webnotifications.enabled", false); if (data.ConfigSettings.CustomCMDArgs != "") fireop.AddArgument(data.ConfigSettings.CustomCMDArgs); if (data.ConfigSettings.RandomUA) fireprofile.SetPreference("general.useragent.override", BlockFunction.RandomUserAgent(data.rand)); else if (data.ConfigSettings.CustomUserAgent != "") fireprofile.SetPreference("general.useragent.override", data.ConfigSettings.CustomUserAgent); if (data.UseProxies) { fireprofile.SetPreference("network.proxy.type", 1); if (data.Proxy.Type == Extreme.Net.ProxyType.Http) { fireprofile.SetPreference("network.proxy.http", data.Proxy.Host); fireprofile.SetPreference("network.proxy.http_port", int.Parse(data.Proxy.Port)); fireprofile.SetPreference("network.proxy.ssl", data.Proxy.Host); fireprofile.SetPreference("network.proxy.ssl_port", int.Parse(data.Proxy.Port)); } else { fireprofile.SetPreference("network.proxy.socks", data.Proxy.Host); fireprofile.SetPreference("network.proxy.socks_port", int.Parse(data.Proxy.Port)); if (data.Proxy.Type == Extreme.Net.ProxyType.Socks4) fireprofile.SetPreference("network.proxy.socks_version", 4); else if (data.Proxy.Type == Extreme.Net.ProxyType.Socks5) fireprofile.SetPreference("network.proxy.socks_version", 5); } } fireop.Profile = fireprofile; data.Driver = new FirefoxDriver(fireservice, fireop, new TimeSpan(0, 1, 0)); } catch(Exception ex) { data.Log(new LogEntry(ex.ToString(), Colors.White)); return; } break; } data.Driver.Manage().Timeouts().PageLoad = TimeSpan.FromSeconds(data.GlobalSettings.Selenium.PageLoadTimeout); data.Log(new LogEntry("Opened!", Colors.White)); data.BrowserOpen = true; } else { try { UpdateSeleniumData(data); } catch { } } } } }