mirror of
https://github.com/openbullet/openbullet.git
synced 2023-10-21 07:33:42 -05:00
397 lines
16 KiB
C#
397 lines
16 KiB
C#
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
|
|
{
|
|
/// <summary>
|
|
/// The actions that can be performed on a browser.
|
|
/// </summary>
|
|
public enum BrowserAction
|
|
{
|
|
/// <summary>Starts the driver and opens the browser.</summary>
|
|
Open,
|
|
|
|
/// <summary>Closes the browser but not the driver.</summary>
|
|
Close,
|
|
|
|
/// <summary>Closes the browser and disposes the driver.</summary>
|
|
Quit,
|
|
|
|
/// <summary>Clears the cookies in the browser.</summary>
|
|
ClearCookies,
|
|
|
|
/// <summary>Sends some keystrokes to the browser. Special keys like <ENTER> can be sent, separated by two pipe characters e.g. <TAB>||<ENTER></summary>
|
|
SendKeys,
|
|
|
|
/// <summary>Takes a screenshot of the visible part of the page.</summary>
|
|
Screenshot,
|
|
|
|
/// <summary>Scrolls to the top of the page.</summary>
|
|
ScrollToTop,
|
|
|
|
/// <summary>Scrolls to the bottom of the page.</summary>
|
|
ScrollToBottom,
|
|
|
|
/// <summary>Scrolls down by a given number of pixels from the top of the page.</summary>
|
|
Scroll,
|
|
|
|
/// <summary>Switches to the browser tab with a given index.</summary>
|
|
SwitchToTab,
|
|
|
|
/// <summary>Refreshes the current page.</summary>
|
|
Refresh,
|
|
|
|
/// <summary>Goes to the previous page.</summary>
|
|
Back,
|
|
|
|
/// <summary>Goes to the next page.</summary>
|
|
Forward,
|
|
|
|
/// <summary>Maximizes the browser window.</summary>
|
|
Maximize,
|
|
|
|
/// <summary>Minimizes the browser window.</summary>
|
|
Minimize,
|
|
|
|
/// <summary>Sets the browser window as full screen.</summary>
|
|
FullScreen,
|
|
|
|
/// <summary>Sets the browser window's width.</summary>
|
|
SetWidth,
|
|
|
|
/// <summary>Sets the browser window's height.</summary>
|
|
SetHeight,
|
|
|
|
/// <summary>Sets the DOM (the page source modified by the javascript code) into the SOURCE variable.</summary>
|
|
DOMtoSOURCE,
|
|
|
|
/// <summary>Transfers the cookies from the browser to the HTTP cookie jar.</summary>
|
|
GetCookies,
|
|
|
|
/// <summary>Transfers the cookies from the HTTP cookie jar to the browser.</summary>
|
|
SetCookies,
|
|
|
|
/// <summary>Switches to the default content.</summary>
|
|
SwitchToDefault,
|
|
|
|
/// <summary>Switches to the alert message.</summary>
|
|
SwitchToAlert,
|
|
|
|
/// <summary>Switches to the default frame (useful to get out of an iframe).</summary>
|
|
SwitchToParentFrame
|
|
}
|
|
|
|
/// <summary>
|
|
/// A block that can interact with a selenium-driven browser.
|
|
/// </summary>
|
|
public class SBlockBrowserAction : BlockBase
|
|
{
|
|
private BrowserAction action = BrowserAction.Open;
|
|
/// <summary>The action that is performed on the browser.</summary>
|
|
public BrowserAction Action { get { return action; } set { action = value; OnPropertyChanged(); } }
|
|
|
|
private string input = "";
|
|
/// <summary>The input string.</summary>
|
|
public string Input { get { return input; } set { input = value; OnPropertyChanged(); } }
|
|
|
|
// Constructor
|
|
/// <summary>
|
|
/// Creates a BrowserAction block.
|
|
/// </summary>
|
|
public SBlockBrowserAction()
|
|
{
|
|
Label = "BROWSER ACTION";
|
|
}
|
|
|
|
/// <inheritdoc />
|
|
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;
|
|
}
|
|
|
|
/// <inheritdoc />
|
|
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();
|
|
}
|
|
|
|
/// <inheritdoc />
|
|
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 "<TAB>":
|
|
action.SendKeys(OpenQA.Selenium.Keys.Tab);
|
|
break;
|
|
|
|
case "<ENTER>":
|
|
action.SendKeys(OpenQA.Selenium.Keys.Enter);
|
|
break;
|
|
|
|
case "<BACKSPACE>":
|
|
action.SendKeys(OpenQA.Selenium.Keys.Backspace);
|
|
break;
|
|
|
|
case "<ESC>":
|
|
action.SendKeys(OpenQA.Selenium.Keys.Escape);
|
|
break;
|
|
|
|
default:
|
|
action.SendKeys(s);
|
|
break;
|
|
}
|
|
}
|
|
action.Perform();
|
|
Thread.Sleep(1000);
|
|
if(replacedInput.Contains("<ENTER>") || replacedInput.Contains("<BACKSPACE>")) // 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]+@)?([^:\\/?\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));
|
|
}
|
|
|
|
/// <summary>
|
|
/// Opens a browser of the given type (if not already open) and with the given settings.
|
|
/// </summary>
|
|
/// <param name="data">The BotData where the settings are stored.</param>
|
|
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.Random));
|
|
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.Random));
|
|
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 { }
|
|
}
|
|
}
|
|
}
|
|
}
|