/// <inheritdoc /> public override async Task Process(LSGlobals ls) { var data = ls.BotData; await base.Process(ls); var browser = data.TryGetObject <WebDriver>("selenium"); if (browser == null) { throw new Exception("Open a browser first!"); } data.Logger.Log("Executing JS code!", LogColors.White); var returned = browser.ExecuteScript(ReplaceValues(JavascriptCode, ls)); if (returned != null) { try { InsertVariable(ls, IsCapture, false, new List <string>() { returned.ToString() }, OutputVariable, "", "", false, true); } catch { throw new Exception($"Failed to convert the returned value to a string"); } } data.Logger.Log("... executed!", LogColors.White); UpdateSeleniumData(data); }
/// <inheritdoc /> public override async Task Process(LSGlobals ls) { var data = ls.BotData; await base.Process(ls); var provider = data.Providers.Captcha; data.Logger.Log("WARNING! This block is obsolete and WILL BE REMOVED IN THE FUTURE! Use the SOLVECAPTCHA block!", LogColors.Tomato); data.Logger.Log("Solving reCaptcha...", LogColors.White); var recapResponse = ""; try { var response = await provider.SolveRecaptchaV2Async(ReplaceValues(SiteKey, ls), ReplaceValues(Url, ls)); recapResponse = response.Response; } catch (Exception ex) { data.Logger.Log(ex.Message, LogColors.Tomato); throw; } data.Logger.Log($"Succesfully got the response: {recapResponse}", LogColors.GreenYellow); if (VariableName != string.Empty) { GetVariables(data).Set(new StringVariable(recapResponse) { Name = VariableName }); data.Logger.Log($"Response stored in variable: {VariableName}.", LogColors.White); } }
/// <inheritdoc /> public override async Task Process(LSGlobals ls) { var data = ls.BotData; await base.Process(ls); var provider = data.Providers.Captcha; // If bypass balance check, skip this method. if (!provider.CheckBalanceBeforeSolving) { return; } // Get balance. If balance is under a certain threshold, don't ask for captcha solve Balance = 0; // Reset it or the block will save it for future calls data.Logger.Log("Checking balance...", LogColors.White); Balance = await provider.GetBalanceAsync(); if (Balance <= 0) { throw new Exception($"[{provider.ServiceType}] Bad token/credentials or zero balance!"); } data.Logger.Log($"[{provider.ServiceType}] Current Balance: ${Balance}", LogColors.GreenYellow); data.CaptchaCredit = Balance; }
/// <summary> /// Gets a command Action from a command line. /// </summary> internal static Action Parse(string line, LSGlobals ls) { // Trim the line var input = line.Trim(); // Return an exception if the line is empty if (input == string.Empty) { throw new ArgumentNullException(); } var label = LineParser.ParseToken(ref input, TokenType.Label, false); // Parse the identifier var identifier = ""; try { identifier = LineParser.ParseToken(ref input, TokenType.Parameter, true); } catch { throw new ArgumentException("Missing identifier"); } return((CommandName)Enum.Parse(typeof(CommandName), identifier, true) switch { CommandName.PRINT => new Action(() => ls.BotData.Logger.Log(BlockBase.ReplaceValues(input, ls), LogColors.White)), CommandName.SET => SetParser.Parse(input, ls), CommandName.DELETE => DeleteParser.Parse(input, ls), // TODO: Readd this // CommandName.MOUSEACTION => MouseActionParser.Parse(input, ls), _ => throw new ArgumentException($"Invalid identifier '{identifier}'"), });
/// <inheritdoc /> public override async Task Process(LSGlobals ls) { var data = ls.BotData; await base.Process(ls); var browser = data.TryGetObject <WebDriver>("selenium"); if (browser == null) { throw new Exception("Open a browser first!"); } var replacedUrl = ReplaceValues(Url, ls); data.Logger.Log($"Navigating to {replacedUrl}", LogColors.White); browser.Manage().Timeouts().PageLoad = TimeSpan.FromSeconds(Timeout); try { browser.Navigate().GoToUrl(replacedUrl); data.Logger.Log("Navigated!", LogColors.White); } catch (WebDriverTimeoutException) { data.Logger.Log("Timeout on Page Load", LogColors.Tomato); if (BanOnTimeout) { data.STATUS = "BAN"; } } UpdateSeleniumData(data); }
/// <summary> /// Adds a single or list variable with the given value. /// </summary> protected static void InsertVariable(LSGlobals ls, bool isCapture, bool recursive, IEnumerable <string> values, string variableName, string prefix = "", string suffix = "", bool urlEncode = false, bool createEmpty = true) { var data = ls.BotData; var list = values.Select(v => ReplaceValues(prefix, ls) + v.Trim() + ReplaceValues(suffix, ls)).ToList(); if (urlEncode) { list = list.Select(v => Uri.EscapeDataString(v)).ToList(); } Variable variable = null; if (recursive) { if (list.Count > 0 || createEmpty) { variable = new ListOfStringsVariable(list) { Name = variableName }; } } else { if (list.Count == 0) { if (createEmpty) { variable = new StringVariable(string.Empty) { Name = variableName }; } } else { variable = new StringVariable(list.First()) { Name = variableName }; } } if (variable != null) { GetVariables(data).Set(variable); data.Logger.Log($"Parsed variable | Name: {variable.Name} | Value: {variable.AsString()}", isCapture ? LogColors.OrangeRed : LogColors.Gold); variable.MarkedForCapture = isCapture; } else { data.Logger.Log("Could not parse any data. The variable was not created.", LogColors.White); } }
/// <summary> /// Parses a condition made of left-hand term, condition type and right-hand term and verifies if it's true. /// </summary> /// <param name="cfLine">The reference to the line to parse</param> /// <param name="data">The BotData needed for variable replacement</param> /// <returns></returns> public static bool ParseCheckCondition(ref string cfLine, LSGlobals ls) { var first = LineParser.ParseLiteral(ref cfLine, "STRING"); var Comparer = (Comparer)LineParser.ParseEnum(ref cfLine, "Comparer", typeof(Comparer)); var second = ""; if (Comparer != Comparer.Exists && Comparer != Comparer.DoesNotExist) { second = LineParser.ParseLiteral(ref cfLine, "STRING"); } return(Condition.ReplaceAndVerify(first, Comparer, second, ls)); }
/// <inheritdoc /> public override async Task Process(LSGlobals ls) { var data = ls.BotData; await base.Process(ls); string errorMessage; var provider = data.Providers.Captcha; try { try { var replacedId = ReplaceValues(CaptchaId, ls); await provider.ReportSolution(long.Parse(replacedId), Type); data.Logger.Log($"Captcha reported successfully!", LogColors.GreenYellow); return; } catch (Exception ex) // This unwraps aggregate exceptions { if (ex is AggregateException) { throw ex.InnerException; } else { throw; } } } catch (TaskReportException ex) { errorMessage = $"The captcha report was not accepted! {ex.Message}"; } catch (NotSupportedException ex) { errorMessage = $"The currently selected service ({provider.ServiceType}) does not support reports! {ex.Message}"; } catch (Exception ex) { errorMessage = $"An error occurred! {ex.Message}"; } if (!string.IsNullOrEmpty(errorMessage)) { data.Logger.Log(errorMessage, LogColors.Tomato); } }
/// <inheritdoc /> public override async Task Process(LSGlobals ls) { var data = ls.BotData; await base.Process(ls); string errorMessage; Proxy proxy = data.UseProxy && UseProxy ? proxy = new Proxy { Host = data.Proxy.Host, Port = data.Proxy.Port, Type = (ProxyType)Enum.Parse(typeof(ProxyType), data.Proxy.Type.ToString()), Username = data.Proxy.Username, Password = data.Proxy.Password, UserAgent = UserAgent, Cookies = data.COOKIES.ToList().Concat(ls.GlobalCookies.ToList()).Select(p => (p.Key, p.Value)).ToArray() }
/// <summary> /// Replaces the values and verifies if a condition is true or false. /// </summary> public static bool ReplaceAndVerify(KeycheckCondition kcCond, LSGlobals ls) { var style = NumberStyles.Number | NumberStyles.AllowCurrencySymbol; // Needed when comparing values with a currency symbol var provider = new CultureInfo("en-US"); var L = BlockBase.ReplaceValuesRecursive(kcCond.Left, ls); // The left-hand term can accept recursive values like <LIST[*]> var r = BlockBase.ReplaceValues(kcCond.Right, ls); // The right-hand term cannot switch (kcCond.Comparer) { case Comparer.EqualTo: return(L.Any(l => l == r)); case Comparer.NotEqualTo: return(L.Any(l => l != r)); case Comparer.GreaterThan: return(L.Any(l => decimal.Parse(l.Replace(',', '.'), style, provider) > decimal.Parse(r.Replace(',', '.'), style, provider))); case Comparer.LessThan: return(L.Any(l => decimal.Parse(l.Replace(',', '.'), style, provider) < decimal.Parse(r.Replace(',', '.'), style, provider))); case Comparer.Contains: return(L.Any(l => l.Contains(r))); case Comparer.DoesNotContain: return(L.Any(l => !l.Contains(r))); case Comparer.Exists: return(L.Any(l => l != kcCond.Left)); // Returns true if any replacement took place case Comparer.DoesNotExist: return(L.All(l => l == kcCond.Left)); // Returns true if no replacement took place case Comparer.MatchesRegex: return(L.Any(l => Regex.Match(l, r).Success)); case Comparer.DoesNotMatchRegex: return(L.Any(l => !Regex.Match(l, r).Success)); default: return(false); } }
/// <inheritdoc /> public override async Task Process(LSGlobals ls) { var data = ls.BotData; await base.Process(ls); var original = ReplaceValues(ParseTarget, ls); var list = Type switch { ParseType.LR => ParseLR(original, ReplaceValues(LeftString, ls), ReplaceValues(RightString, ls), UseRegexLR), ParseType.CSS => ParseCSS(original, ReplaceValues(CssSelector, ls), ReplaceValues(AttributeName, ls)), ParseType.JSON => ParseJSON(original, ReplaceValues(JsonField, ls), JTokenParsing), ParseType.REGEX => ParseREGEX(original, ReplaceValues(RegexString, ls), ReplaceValues(RegexOutput, ls), DotMatches, CaseSensitive), _ => throw new NotImplementedException() }; if (!Recursive && Type == ParseType.CSS) { list = new List <string> { list[CssElementIndex] }; } InsertVariable(ls, IsCapture, Recursive, list, VariableName, Prefix, Suffix, EncodeOutput, CreateEmpty); }
/// <summary> /// Executes the actual block logic. /// </summary> public virtual Task Process(LSGlobals ls) { ls.BotData.Logger.Log($">> Executing Block {Label} <<", LogColors.ChromeYellow); return(Task.CompletedTask); }
/// <summary> /// Replaces variables in a given input string. /// </summary> public static string ReplaceValues(string original, LSGlobals ls) { if (original == null) { return(string.Empty); } var data = ls.BotData; var globals = ls.Globals; if (!original.Contains("<") && !original.Contains(">")) { return(original); } var previous = ""; var output = original; do { previous = output; // Replace all the fixed quantities output = output.Replace("<INPUT>", data.Line.Data); output = output.Replace("<STATUS>", data.STATUS); output = output.Replace("<SOURCE>", data.SOURCE); output = output.Replace("<COOKIES>", data.COOKIES.AsString()); output = output.Replace("<HEADERS>", data.HEADERS.AsString()); output = output.Replace("<RESPONSECODE>", data.RESPONSECODE.AsString()); output = output.Replace("<ADDRESS>", data.ADDRESS); output = output.Replace("<RETRIES>", data.Line.Retries.ToString()); var lastCaptchaInfo = data.TryGetObject <CaptchaInfo>("lastCaptchaInfo"); if (lastCaptchaInfo is not null) { output = output.Replace("<CAPTCHAID>", lastCaptchaInfo.Id.ToString()); } // TODO: Readd this // output = output.Replace("<BOTNUM>", data.BotNumber.ToString()); if (data.Proxy != null) { output = output.Replace("<PROXY>", data.Proxy.ToString()); } // Get all the inner (max. 1 level of nesting) variables var matches = Regex.Matches(output, @"<([^<>]*)>"); foreach (Match match in matches) { var full = match.Groups[0].Value; var m = match.Groups[1].Value; // Parse the variable name var name = Regex.Match(m, @"^[^\[\{\(]*").Value; // Try to get the variable (first local, then global, then if none was found go to the next iteration) // We don't throw an error here because it could be some HTML or XML code e.g. <br> that triggers this, and we dont' want to spam the user with unneeded errors var v = GetVariables(data).Get(name); if (v == null) { if (name == "COOKIES") { v = new DictionaryOfStringsVariable(data.COOKIES) { Name = name }; } else if (name == "HEADERS") { v = new DictionaryOfStringsVariable(data.HEADERS) { Name = name }; } else { v = globals.Get(name); } } if (v == null) { continue; } // Parse the arguments var args = m.Replace(name, ""); switch (v) { case StringVariable: output = output.Replace(full, v.AsString()); break; case ListOfStringsVariable: // If it's just the list name, replace it with its string representation if (string.IsNullOrEmpty(args)) { output = output.Replace(full, v.AsString()); break; } var index = 0; int.TryParse(ParseArguments(args, '[', ']')[0], out index); var item = GetListItem(v.AsListOfStrings(), index); // Can return null if (item != null) { output = output.Replace(full, item); } break; case DictionaryOfStringsVariable: var dict = v.AsDictionaryOfStrings(); if (args.Contains("(") && args.Contains(")")) { var key = ParseArguments(args, '(', ')')[0]; if (dict.ContainsKey(key)) { output = output.Replace(full, dict[key]); } } else if (args.Contains("{") && args.Contains("}")) { var value = ParseArguments(args, '{', '}')[0]; if (dict.ContainsValue(value)) { output = output.Replace(full, dict.First(kvp => kvp.Value == value).Key); } } else // If it's just the dictionary name, replace it with its string representation { output = output.Replace(full, v.AsString()); break; } break; } } }while (original.Contains("<") && original.Contains(">") && output != previous); return(output); }
/// <summary> /// Executes a line of the script. /// </summary> /// <param name="data">The BotData needed for variable replacement</param> public async Task TakeStep(LSGlobals ls) { var data = ls.BotData; // TODO: Refactor this with a properly written policy // If we have a custom status without forced continue OR we have a status that is not NONE or SUCCESS or CUSTOM if (!CanContinue(data)) { i = lines.Length; // Go to the end return; } TAKELINE: CurrentLine = lines[i]; // Skip comments and blank lines if (IsEmptyOrCommentOrDisabled(CurrentLine)) { i++; // Go to the next goto TAKELINE; } // Lookahead to compact lines. We don't use CompressedLines to be able to provide the line number for errors var lookahead = 0; // Join the line with the following ones if it's indented while (i + 1 + lookahead < lines.Length) { var nextLine = lines[i + 1 + lookahead]; if (nextLine.StartsWith(" ") || nextLine.StartsWith("\t")) { CurrentLine += $" {nextLine.Trim()}"; } else { break; } lookahead++; } try { // If Block -> Process Block if (BlockParser.IsBlock(CurrentLine)) { BlockBase block = null; try { block = BlockParser.Parse(CurrentLine); CurrentBlock = block.Label; data.ExecutionInfo = $"Executing block: {block.Label}"; if (!block.Disabled) { await block.Process(ls); } } catch (Exception ex) { // We log the error message var errorMessage = data.Providers.GeneralSettings.VerboseMode ? ex.ToString() : ex.Message; data.Logger.Log("ERROR: " + errorMessage, LogColors.Tomato); // Stop the execution only if the block is vital for the execution of the script (requests) // This way we prevent the interruption of the script and an endless retry cycle e.g. if we fail to parse a response given a specific input if (block != null && block is BlockRequest) { data.STATUS = "ERROR"; throw new BlockProcessingException(ex.Message); } } } // If Command -> Process Command else if (CommandParser.IsCommand(CurrentLine)) { try { var action = CommandParser.Parse(CurrentLine, ls); action?.Invoke(); } catch (Exception ex) { var errorMessage = data.Providers.GeneralSettings.VerboseMode ? ex.ToString() : ex.Message; data.Logger.Log("ERROR: " + errorMessage, LogColors.Tomato); data.STATUS = "ERROR"; } } // Try to Process Flow Control else { var cfLine = CurrentLine; var token = LineParser.ParseToken(ref cfLine, TokenType.Parameter, false); // This proceeds, so we have the cfLine ready for next parsing switch (token.ToUpper()) { case "IF": // Check condition, if not true jump to line after first ELSE or ENDIF (check both at the same time on lines, not separately) if (!ParseCheckCondition(ref cfLine, ls)) { i = ScanFor(lines, i, true, new string[] { "ENDIF", "ELSE" }); data.Logger.Log($"Jumping to line {i + 1}", LogColors.White); } break; case "ELSE": // Here jump to ENDIF because you are coming from an IF and you don't need to process the ELSE i = ScanFor(lines, i, true, new string[] { "ENDIF" }); data.Logger.Log($"Jumping to line {i + 1}", LogColors.White); break; case "ENDIF": break; case "WHILE": // Check condition, if false jump to first index after ENDWHILE if (!ParseCheckCondition(ref cfLine, ls)) { i = ScanFor(lines, i, true, new string[] { "ENDWHILE" }); data.Logger.Log($"Jumping to line {i + 1}", LogColors.White); } break; case "ENDWHILE": // Jump back to the previous WHILE index i = ScanFor(lines, i, false, new string[] { "WHILE" }) - 1; data.Logger.Log($"Jumping to line {i + 1}", LogColors.White); break; case "JUMP": var label = ""; try { label = LineParser.ParseToken(ref cfLine, TokenType.Label, true); i = ScanFor(lines, -1, true, new string[] { $"{label}" }) - 1; data.Logger.Log($"Jumping to line {i + 2}", LogColors.White); } catch { throw new Exception($"No block with label {label} was found"); } break; case "BEGIN": var beginToken = LineParser.ParseToken(ref cfLine, TokenType.Parameter, true); switch (beginToken.ToUpper()) { case "SCRIPT": language = (ScriptingLanguage)LineParser.ParseEnum(ref cfLine, "LANGUAGE", typeof(ScriptingLanguage)); var end = 0; try { end = ScanFor(lines, i, true, new string[] { "END" }) - 1; } catch { throw new Exception("No 'END SCRIPT' specified"); } otherScript = string.Join(Environment.NewLine, lines.Skip(i + 1).Take(end - i)); i = end; data.Logger.Log($"Jumping to line {i + 2}", LogColors.White); break; } break; case "END": var endToken = LineParser.ParseToken(ref cfLine, TokenType.Parameter, true); switch (endToken.ToUpper()) { case "SCRIPT": LineParser.EnsureIdentifier(ref cfLine, "->"); LineParser.EnsureIdentifier(ref cfLine, "VARS"); var outputs = LineParser.ParseLiteral(ref cfLine, "OUTPUTS"); try { if (otherScript != string.Empty) { RunScript(otherScript, language, outputs, data); } } catch (Exception ex) { var errorMessage = data.Providers.GeneralSettings.VerboseMode ? ex.ToString() : ex.Message; data.Logger.Log($"The script failed to be executed: {errorMessage}", LogColors.Tomato); } break; } break; default: break; } } } catch (BlockProcessingException) { // Rethrow the Block Processing Exception so the error can be displayed in the view above throw; } catch (Exception e) { // Catch inner and throw line exception throw new Exception($"Parsing Exception on line {i + 1}: {e.Message}"); } i += 1 + lookahead; }
/// <summary> /// Replaces variables recursively, expanding lists or dictionaries with jolly indices. /// </summary> public static List <string> ReplaceValuesRecursive(string original, LSGlobals ls) { var data = ls.BotData; var globals = ls.Globals; var toReplace = new List <string>(); // Regex parse the syntax <LIST[*]> var matches = Regex.Matches(original, @"<([^\[]*)\[\*\]>"); var variables = new List <ListOfStringsVariable>(); foreach (Match m in matches) { var name = m.Groups[1].Value; // Retrieve the variable var variable = GetVariables(data).Get(name); // If it's null, try to get it from the global variables if (variable == null) { variable = globals.Get(name); // If still null, there's nothing to replace, skip it if (variable == null) { continue; } } // Make sure it's a List of strings and add it to the list if (variable is ListOfStringsVariable list) { variables.Add(list); } } // If there's no corresponding variable, just readd the input string and proceed with normal replacement if (variables.Count > 0) { // Example: we have 3 lists of sizes 3, 7 and 5. We need to take 7 var max = variables.Max(v => v.AsListOfStrings().Count); for (var i = 0; i < max; i++) { var replaced = original; foreach (var variable in variables) { var list = variable.AsListOfStrings(); replaced = list.Count > i?replaced.Replace($"<{variable.Name}[*]>", list[i]) : replaced.Replace($"<{variable.Name}[*]>", "NULL"); } toReplace.Add(replaced); } goto END; } // Regex parse the syntax <DICT(*)> (wildcard key -> returns list of all values) var match = Regex.Match(original, @"<([^\(]*)\(\*\)>"); if (match.Success) { var full = match.Groups[0].Value; var name = match.Groups[1].Value; // Retrieve the dictionary var dict = GetVariables(data).Get <DictionaryOfStringsVariable>(name); if (dict == null) { dict = globals.Get <DictionaryOfStringsVariable>(name); } // If there's no corresponding variable, just readd the input string and proceed with normal replacement if (dict == null) { toReplace.Add(original); } else { foreach (var item in dict.AsDictionaryOfStrings()) { toReplace.Add(original.Replace(full, item.Value)); } } goto END; } // Regex parse the syntax <DICT{*}> (wildcard value -> returns list of all keys) match = Regex.Match(original, @"<([^\{]*)\{\*\}>"); if (match.Success) { var full = match.Groups[0].Value; var name = match.Groups[1].Value; // Retrieve the dictionary var dict = GetVariables(data).Get <DictionaryOfStringsVariable>(name); if (dict == null) { if (name == "COOKIES") { dict = new DictionaryOfStringsVariable(data.COOKIES) { Name = name }; } else if (name == "HEADERS") { dict = new DictionaryOfStringsVariable(data.HEADERS) { Name = name }; } else { dict = globals.Get <DictionaryOfStringsVariable>(name); } } // If there's no corresponding variable, just readd the input string and proceed with normal replacement if (dict == null) { toReplace.Add(original); } else { foreach (var item in dict.AsDictionaryOfStrings()) { toReplace.Add(original.Replace(full, item.Key)); } } goto END; } // If no other match was a success, it means there's no recursive value and we simply add the input to the list toReplace.Add(original); END: // Now for each item in the list, do the normal replacement and return the replaced list of strings return(toReplace.Select(i => (string)ReplaceValues(i, ls)).ToList()); }
public async Task Run() { // Build the C# script if in Stack or LoliCode mode if (config.Mode == ConfigMode.Stack || config.Mode == ConfigMode.LoliCode) { config.CSharpScript = config.Mode == ConfigMode.Stack ? Stack2CSharpTranspiler.Transpile(config.Stack, config.Settings) : Loli2CSharpTranspiler.Transpile(config.LoliCodeScript, config.Settings); } if (options.UseProxy && !options.TestProxy.Contains(':')) { throw new InvalidProxyException(options.TestProxy); } if (!options.PersistLog) { logger.Clear(); } // Close any previously opened browsers if (lastPuppeteerBrowser != null) { await lastPuppeteerBrowser.CloseAsync(); } if (lastSeleniumBrowser != null) { lastSeleniumBrowser.Quit(); } options.Variables.Clear(); IsRunning = true; cts = new CancellationTokenSource(); var sw = new Stopwatch(); var wordlistType = RuriLibSettings.Environment.WordlistTypes.First(w => w.Name == options.WordlistType); var dataLine = new DataLine(options.TestData, wordlistType); var proxy = options.UseProxy ? Proxy.Parse(options.TestProxy, options.ProxyType) : null; var providers = new Bots.Providers(RuriLibSettings) { RNG = RNGProvider }; if (!RuriLibSettings.RuriLibSettings.GeneralSettings.UseCustomUserAgentsList) { providers.RandomUA = RandomUAProvider; } // Build the BotData var data = new BotData(providers, config.Settings, logger, dataLine, proxy, options.UseProxy) { CancellationToken = cts.Token }; using var httpClient = new HttpClient(); data.SetObject("httpClient", httpClient); var runtime = Python.CreateRuntime(); var pyengine = runtime.GetEngine("py"); var pco = (PythonCompilerOptions)pyengine.GetCompilerOptions(); pco.Module &= ~ModuleOptions.Optimized; data.SetObject("ironPyEngine", pyengine); data.AsyncLocker = new(); dynamic globals = new ExpandoObject(); var script = new ScriptBuilder() .Build(config.CSharpScript, config.Settings.ScriptSettings, PluginRepo); logger.Log($"Sliced {dataLine.Data} into:"); foreach (var slice in dataLine.GetVariables()) { var sliceValue = data.ConfigSettings.DataSettings.UrlEncodeDataAfterSlicing ? Uri.EscapeDataString(slice.AsString()) : slice.AsString(); logger.Log($"{slice.Name}: {sliceValue}"); } // Initialize resources Dictionary <string, ConfigResource> resources = new(); // Resources will need to be disposed of foreach (var opt in config.Settings.DataSettings.Resources) { try { resources[opt.Name] = opt switch { LinesFromFileResourceOptions x => new LinesFromFileResource(x), RandomLinesFromFileResourceOptions x => new RandomLinesFromFileResource(x), _ => throw new NotImplementedException() }; } catch { logger.Log($"Could not create resource {opt.Name}", LogColors.Tomato); } } // Add resources to global variables globals.Resources = resources; var scriptGlobals = new ScriptGlobals(data, globals); // Set custom inputs foreach (var input in config.Settings.InputSettings.CustomInputs) { (scriptGlobals.input as IDictionary <string, object>).Add(input.VariableName, input.DefaultAnswer); } // [LEGACY] Set up the VariablesList if (config.Mode == ConfigMode.Legacy) { var slices = new List <Variable>(); foreach (var slice in dataLine.GetVariables()) { var sliceValue = data.ConfigSettings.DataSettings.UrlEncodeDataAfterSlicing ? Uri.EscapeDataString(slice.AsString()) : slice.AsString(); slices.Add(new StringVariable(sliceValue) { Name = slice.Name }); } var legacyVariables = new VariablesList(slices); foreach (var input in config.Settings.InputSettings.CustomInputs) { legacyVariables.Set(new StringVariable(input.DefaultAnswer) { Name = input.VariableName }); } data.SetObject("legacyVariables", legacyVariables); } try { sw.Start(); Started?.Invoke(this, EventArgs.Empty); if (config.Mode != ConfigMode.Legacy) { var state = await script.RunAsync(scriptGlobals, null, cts.Token); foreach (var scriptVar in state.Variables) { try { var type = DescriptorsRepository.ToVariableType(scriptVar.Type); if (type.HasValue && !scriptVar.Name.StartsWith("tmp_")) { var variable = DescriptorsRepository.ToVariable(scriptVar.Name, scriptVar.Type, scriptVar.Value); variable.MarkedForCapture = data.MarkedForCapture.Contains(scriptVar.Name); options.Variables.Add(variable); } } catch { // The type is not supported, e.g. it was generated using custom C# code and not blocks // so we just disregard it } } } else { // [LEGACY] Run the LoliScript in the old way var loliScript = new LoliScript(config.LoliScript); var lsGlobals = new LSGlobals(data); do { if (cts.IsCancellationRequested) { break; } await loliScript.TakeStep(lsGlobals); options.Variables.Clear(); var legacyVariables = data.TryGetObject <VariablesList>("legacyVariables"); options.Variables.AddRange(legacyVariables.Variables); options.Variables.AddRange(lsGlobals.Globals.Variables); }while (loliScript.CanProceed); } } catch (OperationCanceledException) { data.STATUS = "ERROR"; logger.Log($"Operation canceled", LogColors.Tomato); } catch (Exception ex) { data.STATUS = "ERROR"; var logErrorMessage = RuriLibSettings.RuriLibSettings.GeneralSettings.VerboseMode ? ex.ToString() : ex.Message; logger.Log($"[{data.ExecutionInfo}] {ex.GetType().Name}: {logErrorMessage}", LogColors.Tomato); IsRunning = false; throw; } finally { sw.Stop(); logger.Log($"BOT ENDED AFTER {sw.ElapsedMilliseconds} ms WITH STATUS: {data.STATUS}"); // Save the browsers for later use lastPuppeteerBrowser = data.TryGetObject <Browser>("puppeteer"); lastSeleniumBrowser = data.TryGetObject <OpenQA.Selenium.WebDriver>("selenium"); // Dispose stuff in data.Objects data.DisposeObjectsExcept(new[] { "puppeteer", "puppeteerPage", "puppeteerFrame", "selenium" }); // Dispose resources foreach (var resource in resources.Where(r => r.Value is IDisposable) .Select(r => r.Value).Cast <IDisposable>()) { resource.Dispose(); } data.AsyncLocker.Dispose(); } IsRunning = false; Stopped?.Invoke(this, EventArgs.Empty); }
/// <summary> /// Verifies if at least one of the provided conditions is true (after replacing). /// </summary> public static bool ReplaceAndVerifyAny(KeycheckCondition[] conditions, LSGlobals ls) => conditions.Any(c => ReplaceAndVerify(c, ls));
/// <summary> /// Replaces the values and verifies if a condition is true or false. /// </summary> public static bool ReplaceAndVerify(string left, Comparer comparer, string right, LSGlobals ls) => ReplaceAndVerify(new KeycheckCondition() { Left = left, Comparer = comparer, Right = right }, ls);
/// <summary> /// Gets the Action that needs to be executed. /// </summary> static internal Action Parse(string line, LSGlobals ls) { var data = ls.BotData; var input = line.Trim(); var field = LineParser.ParseToken(ref input, TokenType.Parameter, true).ToUpper(); return(new Action(() => { var name = ""; var comparer = Comparer.EqualTo; switch (field) { case "COOKIE": if (LineParser.Lookahead(ref input) == TokenType.Parameter) { comparer = (Comparer)LineParser.ParseEnum(ref input, "TYPE", typeof(Comparer)); } name = LineParser.ParseLiteral(ref input, "NAME"); for (var i = 0; i < data.COOKIES.Count; i++) { var curr = data.COOKIES.ToList()[i].Key; if (Condition.ReplaceAndVerify(curr, comparer, name, ls)) { data.COOKIES.Remove(curr); } } break; case "VAR": if (LineParser.Lookahead(ref input) == TokenType.Parameter) { comparer = (Comparer)LineParser.ParseEnum(ref input, "TYPE", typeof(Comparer)); } name = LineParser.ParseLiteral(ref input, "NAME"); BlockBase.GetVariables(data).RemoveAll(comparer, name, ls); break; case "GVAR": if (LineParser.Lookahead(ref input) == TokenType.Parameter) { comparer = (Comparer)LineParser.ParseEnum(ref input, "TYPE", typeof(Comparer)); } name = LineParser.ParseLiteral(ref input, "NAME"); try { ls.Globals.RemoveAll(comparer, name, ls); } catch { } break; default: throw new ArgumentException($"Invalid identifier {field}"); } data.Logger.Log($"DELETE command executed on field {field}", LogColors.White); })); }
/// <inheritdoc /> public override async Task Process(LSGlobals ls) { var data = ls.BotData; await base.Process(ls); var localInputStrings = ReplaceValuesRecursive(InputString, ls); var outputs = new List <string>(); for (var i = 0; i < localInputStrings.Count; i++) { var localInputString = localInputStrings[i]; var outputString = ""; switch (FunctionType) { case Function.Constant: outputString = localInputString; break; case Function.Base64Encode: outputString = Base64Converter.ToBase64String(Encoding.UTF8.GetBytes(localInputString)); break; case Function.Base64Decode: outputString = Encoding.UTF8.GetString(Base64Converter.ToByteArray(localInputString)); break; case Function.HTMLEntityEncode: outputString = WebUtility.HtmlEncode(localInputString); break; case Function.HTMLEntityDecode: outputString = WebUtility.HtmlDecode(localInputString); break; case Function.Hash: outputString = GetHash(localInputString, HashType, InputBase64).ToLower(); break; case Function.HMAC: outputString = Hmac(localInputString, HashType, ReplaceValues(HmacKey, ls), InputBase64, KeyBase64, HmacBase64); break; case Function.Translate: outputString = localInputString; foreach (var entry in TranslationDictionary.OrderBy(e => e.Key.Length).Reverse()) { if (outputString.Contains(entry.Key)) { outputString = outputString.Replace(entry.Key, entry.Value); if (StopAfterFirstMatch) { break; } } } break; case Function.DateToUnixTime: outputString = localInputString.ToDateTime(DateFormat).ToUnixTime().ToString(); break; case Function.Length: outputString = localInputString.Length.ToString(); break; case Function.ToLowercase: outputString = localInputString.ToLower(); break; case Function.ToUppercase: outputString = localInputString.ToUpper(); break; case Function.Replace: outputString = UseRegex ? Regex.Replace(localInputString, ReplaceValues(ReplaceWhat, ls), ReplaceValues(ReplaceWith, ls)) : localInputString.Replace(ReplaceValues(ReplaceWhat, ls), ReplaceValues(ReplaceWith, ls)); break; case Function.RegexMatch: outputString = Regex.Match(localInputString, ReplaceValues(RegexMatch, ls)).Value; break; case Function.Unescape: outputString = Regex.Unescape(localInputString); break; case Function.URLEncode: // The maximum allowed Uri size is 2083 characters, we use 2080 as a precaution outputString = string.Join("", SplitInChunks(localInputString, 2080).Select(s => Uri.EscapeDataString(s))); break; case Function.URLDecode: outputString = Uri.UnescapeDataString(localInputString); break; case Function.UnixTimeToDate: outputString = long.Parse(localInputString).ToDateTimeUtc().ToString(DateFormat); break; case Function.CurrentUnixTime: outputString = DateTime.UtcNow.ToUnixTime().ToString(); break; case Function.UnixTimeToISO8601: outputString = long.Parse(localInputString).ToDateTimeUtc().ToISO8601(); break; case Function.RandomNum: var min = int.Parse(ReplaceValues(RandomMin, ls)); var max = int.Parse(ReplaceValues(RandomMax, ls)); var randomNumString = data.Random.Next(min, max).ToString(); outputString = RandomZeroPad ? randomNumString.PadLeft(max.ToString().Length, '0') : randomNumString; break; case Function.RandomString: outputString = localInputString; outputString = Regex.Replace(outputString, @"\?l", m => _lowercase[data.Random.Next(_lowercase.Length)].ToString()); outputString = Regex.Replace(outputString, @"\?u", m => _uppercase[data.Random.Next(_uppercase.Length)].ToString()); outputString = Regex.Replace(outputString, @"\?d", m => _digits[data.Random.Next(_digits.Length)].ToString()); outputString = Regex.Replace(outputString, @"\?s", m => _symbols[data.Random.Next(_symbols.Length)].ToString()); outputString = Regex.Replace(outputString, @"\?h", m => _hex[data.Random.Next(_hex.Length)].ToString()); outputString = Regex.Replace(outputString, @"\?a", m => _allChars[data.Random.Next(_allChars.Length)].ToString()); outputString = Regex.Replace(outputString, @"\?m", m => _udChars[data.Random.Next(_udChars.Length)].ToString()); outputString = Regex.Replace(outputString, @"\?n", m => _ldChars[data.Random.Next(_ldChars.Length)].ToString()); outputString = Regex.Replace(outputString, @"\?i", m => _ludChars[data.Random.Next(_ludChars.Length)].ToString()); outputString = Regex.Replace(outputString, @"\?f", m => _upperlwr[data.Random.Next(_upperlwr.Length)].ToString()); break; case Function.Ceil: outputString = Math.Ceiling(decimal.Parse(localInputString, _style, _provider)).ToString(); break; case Function.Floor: outputString = Math.Floor(decimal.Parse(localInputString, _style, _provider)).ToString(); break; case Function.Round: outputString = Math.Round(decimal.Parse(localInputString, _style, _provider), 0, MidpointRounding.AwayFromZero).ToString(); break; case Function.Compute: outputString = new DataTable().Compute(localInputString.Replace(',', '.'), null).ToString(); break; case Function.CountOccurrences: outputString = CountStringOccurrences(localInputString, StringToFind).ToString(); break; case Function.ClearCookies: data.COOKIES.Clear(); break; case Function.RSAEncrypt: outputString = Crypto.RSAEncrypt( localInputString, ReplaceValues(RsaN, ls), ReplaceValues(RsaE, ls), RsaOAEP ); break; /* * case Function.RSADecrypt: * outputString = Crypto.RSADecrypt( * localInputString, * ReplaceValues(RsaN, data), * ReplaceValues(RsaD, data), * RsaOAEP * ); * break; */ case Function.RSAPKCS1PAD2: outputString = Crypto.RSAPkcs1Pad2( localInputString, ReplaceValues(RsaN, ls), ReplaceValues(RsaE, ls) ); break; case Function.Delay: try { Thread.Sleep(int.Parse(localInputString)); } catch { } break; case Function.CharAt: outputString = localInputString.ToCharArray()[int.Parse(ReplaceValues(CharIndex, ls))].ToString(); break; case Function.Substring: outputString = localInputString.Substring(int.Parse(ReplaceValues(SubstringIndex, ls)), int.Parse(ReplaceValues(SubstringLength, ls))); break; case Function.ReverseString: var charArray = localInputString.ToCharArray(); Array.Reverse(charArray); outputString = new string(charArray); break; case Function.Trim: outputString = localInputString.Trim(); break; case Function.GetRandomUA: outputString = data.Providers.RandomUA.Generate(); break; case Function.AESEncrypt: outputString = Crypto.AESEncrypt(localInputString, ReplaceValues(AesKey, ls), ReplaceValues(AesIV, ls), AesMode, AesPadding); break; case Function.AESDecrypt: outputString = Crypto.AESDecrypt(localInputString, ReplaceValues(AesKey, ls), ReplaceValues(AesIV, ls), AesMode, AesPadding); break; case Function.PBKDF2PKCS5: outputString = Crypto.PBKDF2PKCS5(localInputString, ReplaceValues(KdfSalt, ls), KdfSaltSize, KdfIterations, KdfKeySize, KdfAlgorithm); break; } data.Logger.Log($"Executed function {FunctionType} on input {localInputString} with outcome {outputString}", LogColors.GreenYellow); // Add to the outputs outputs.Add(outputString); } var isList = outputs.Count > 1 || InputString.Contains("[*]") || InputString.Contains("(*)") || InputString.Contains("{*}"); InsertVariable(ls, IsCapture, isList, outputs, VariableName, "", "", false, true); }
/// <inheritdoc /> public override async Task Process(LSGlobals ls) { var data = ls.BotData; await base.Process(ls); var browser = data.TryGetObject <WebDriver>("selenium"); if (browser == null && Action != BrowserAction.Open) { throw new Exception("Open a browser first!"); } var replacedInput = ReplaceValues(Input, ls); Actions keyActions = null; switch (Action) { case BrowserAction.Open: OpenBrowser(data); UpdateSeleniumData(data); break; case BrowserAction.Close: browser.Close(); data.SetObject("selenium", null); break; case BrowserAction.Quit: browser.Quit(); data.SetObject("selenium", null); break; case BrowserAction.ClearCookies: browser.Manage().Cookies.DeleteAllCookies(); break; case BrowserAction.SendKeys: keyActions = new Actions(browser); foreach (var s in replacedInput.Split(new string[] { "||" }, StringSplitOptions.None)) { switch (s) { case "<TAB>": keyActions.SendKeys(Keys.Tab); break; case "<ENTER>": keyActions.SendKeys(Keys.Enter); break; case "<BACKSPACE>": keyActions.SendKeys(Keys.Backspace); break; case "<ESC>": keyActions.SendKeys(Keys.Escape); break; default: // List of available keys https://github.com/SeleniumHQ/selenium/blob/master/dotnet/src/webdriver/Keys.cs var keyFields = typeof(Keys).GetFields(); var matchingField = keyFields.FirstOrDefault(f => $"<{f.Name}>".Equals(s, StringComparison.InvariantCultureIgnoreCase)); if (matchingField != null) { keyActions.SendKeys(matchingField.GetValue(null).ToString()); } else { keyActions.SendKeys(s); } break; } } keyActions.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 screenshotFile = Utils.GetScreenshotPath(data); browser.GetScreenshot().SaveAsFile(screenshotFile); break; case BrowserAction.OpenNewTab: ((IJavaScriptExecutor)browser).ExecuteScript("window.open();"); browser.SwitchTo().Window(browser.WindowHandles.Last()); break; case BrowserAction.SwitchToTab: browser.SwitchTo().Window(browser.WindowHandles[int.Parse(replacedInput)]); UpdateSeleniumData(data); break; case BrowserAction.CloseCurrentTab: ((IJavaScriptExecutor)browser).ExecuteScript("window.close();"); break; case BrowserAction.Refresh: browser.Navigate().Refresh(); break; case BrowserAction.Back: browser.Navigate().Back(); break; case BrowserAction.Forward: browser.Navigate().Forward(); break; case BrowserAction.Maximize: browser.Manage().Window.Maximize(); break; case BrowserAction.Minimize: browser.Manage().Window.Minimize(); break; case BrowserAction.FullScreen: browser.Manage().Window.FullScreen(); break; case BrowserAction.SetWidth: browser.Manage().Window.Size = new Size(int.Parse(replacedInput), browser.Manage().Window.Size.Height); break; case BrowserAction.SetHeight: browser.Manage().Window.Size = new Size(browser.Manage().Window.Size.Width, int.Parse(replacedInput)); break; case BrowserAction.DOMtoSOURCE: data.SOURCE = browser.FindElement(By.TagName("body")).GetAttribute("innerHTML"); break; case BrowserAction.GetCookies: foreach (var cookie in browser.Manage().Cookies.AllCookies) { if (!string.IsNullOrWhiteSpace(cookie.Name)) { data.COOKIES[cookie.Name] = cookie.Value; } } break; case BrowserAction.SetCookies: var baseURL = Regex.Match(replacedInput, "^(?:https?:\\/\\/)?(?:[^@\\/\n]+@)?([^:\\/?\n]+)").Groups[1].Value; foreach (var cookie in data.COOKIES) { try { browser.Manage().Cookies.AddCookie(new Cookie(cookie.Key, cookie.Value, baseURL, "/", DateTime.MaxValue)); } catch { } } break; case BrowserAction.SwitchToDefault: browser.SwitchTo().DefaultContent(); break; case BrowserAction.SwitchToAlert: browser.SwitchTo().Alert(); break; case BrowserAction.SwitchToParentFrame: browser.SwitchTo().ParentFrame(); break; } data.Logger.Log(string.Format("Executed browser action {0} on input {1}", Action, replacedInput), LogColors.White); }
/// <summary> /// Adds a list variable with the given value. /// </summary> protected static void InsertVariable(LSGlobals ls, bool isCapture, IEnumerable <string> values, string variableName, string prefix = "", string suffix = "", bool urlEncode = false, bool createEmpty = true) => InsertVariable(ls, isCapture, true, values, variableName, prefix, suffix, urlEncode, createEmpty);
/// <summary> /// Parses a literal value from a line. /// </summary> /// <param name="input">The reference to the line of code</param> /// <param name="label">Debug information about the expected literal</param> /// <param name="replace">Whether to perform variable replacement in the literal</param> /// <returns>The literal without the leading and trailing double quotes</returns> public static string ParseLiteral(ref string input, string label, bool replace = false, LSGlobals ls = null) { try { return(replace ? BlockBase.ReplaceValues(ParseToken(ref input, TokenType.Literal, true), ls) : ParseToken(ref input, TokenType.Literal, true)); } catch { throw new ArgumentException($"Expected Literal value for '{label}'"); } }
/// <inheritdoc /> public override async Task Process(LSGlobals ls) { var data = ls.BotData; await base.Process(ls); var provider = data.Providers.Captcha; data.Logger.Log("WARNING! This block is obsolete and WILL BE REMOVED IN THE FUTURE! Use the SOLVECAPTCHA block!", LogColors.Tomato); data.Logger.Log("Downloading image...", LogColors.White); var localUrl = ReplaceValues(Url, ls); var captchaFile = Utils.GetCaptchaPath(data); var screenshotFile = Utils.GetScreenshotPath(data); if (Base64) { var bytes = Convert.FromBase64String(localUrl); using var imageFile = new FileStream(captchaFile, FileMode.Create); imageFile.Write(bytes, 0, bytes.Length); imageFile.Flush(); } else if (SendScreenshot && File.Exists(screenshotFile)) { using var image = new Bitmap(screenshotFile); image.Save(captchaFile); } else { // Try to download the captcha try { var standardOptions = new StandardHttpRequestOptions { CustomCookies = data.COOKIES, CustomHeaders = new Dictionary <string, string> { { "User-Agent", UserAgent }, { "Accept", "*/*" }, { "Pragma", "no-cache" }, { "Accept-Language", "en-US,en;q=0.8" } }, Method = HttpMethod.GET, Url = localUrl, TimeoutMilliseconds = 10000 }; // Back up the old values var oldAddress = data.ADDRESS; var oldSource = data.SOURCE; var oldResponseCode = data.RESPONSECODE; var oldRawSource = data.RAWSOURCE; // Request the captcha data.Logger.Enabled = false; await RuriLib.Blocks.Requests.Http.Methods.HttpRequestStandard(data, standardOptions); data.Logger.Enabled = true; // Save the image File.WriteAllBytes(captchaFile, data.RAWSOURCE); // Put the old values back data.ADDRESS = oldAddress; data.SOURCE = oldSource; data.RAWSOURCE = oldRawSource; data.RESPONSECODE = oldResponseCode; } catch (Exception ex) { data.Logger.Enabled = true; data.Logger.Log(ex.Message, LogColors.Tomato); throw; } } // Now the captcha is inside the file at path 'captchaFile' var response = ""; var bitmap = new Bitmap(captchaFile); try { var converter = new ImageConverter(); var bytes = (byte[])converter.ConvertTo(bitmap, typeof(byte[])); var captchaResponse = await provider.SolveImageCaptchaAsync(Convert.ToBase64String(bytes)); response = captchaResponse.Response; } catch (Exception ex) { data.Logger.Log(ex.Message, LogColors.Tomato); throw; } finally { bitmap.Dispose(); } data.Logger.Log($"Succesfully got the response: {response}", LogColors.GreenYellow); if (VariableName != string.Empty) { GetVariables(data).Set(new StringVariable(response) { Name = VariableName }); data.Logger.Log($"Response stored in variable: {VariableName}.", LogColors.White); } }
/// <inheritdoc /> public override async Task Process(LSGlobals ls) { var data = ls.BotData; await base.Process(ls); var browser = data.TryGetObject <WebDriver>("selenium"); if (browser == null) { throw new Exception("Open a browser first!"); } // Find the element IWebElement element = null; ReadOnlyCollection <IWebElement> elements = null; if (Action != ElementAction.WaitForElement) { elements = FindElements(browser, ReplaceValues(ElementString, ls)); if (ElementIndex + 1 > elements.Count) { throw new Exception("Cannot find the element on the page"); } } var replacedInput = ReplaceValues(Input, ls); var outputs = new List <string>(); switch (Action) { case ElementAction.Clear: element.Clear(); break; case ElementAction.SendKeys: element.SendKeys(replacedInput); break; case ElementAction.Click: element.Click(); UpdateSeleniumData(data); break; case ElementAction.Submit: element.Submit(); UpdateSeleniumData(data); break; case ElementAction.SelectOptionByText: new SelectElement(element).SelectByText(replacedInput); break; case ElementAction.SelectOptionByIndex: new SelectElement(element).SelectByIndex(int.Parse(replacedInput)); break; case ElementAction.SelectOptionByValue: new SelectElement(element).SelectByValue(replacedInput); break; case ElementAction.GetText: if (Recursive) { foreach (var elem in elements) { outputs.Add(elem.Text); } } else { outputs.Add(element.Text); } break; case ElementAction.GetAttribute: if (Recursive) { foreach (var elem in elements) { outputs.Add(elem.GetAttribute(replacedInput)); } } else { outputs.Add(element.GetAttribute(replacedInput)); } break; case ElementAction.IsDisplayed: outputs.Add(element.Displayed.ToString()); break; case ElementAction.IsEnabled: outputs.Add(element.Enabled.ToString()); break; case ElementAction.IsSelected: outputs.Add(element.Selected.ToString()); break; case ElementAction.LocationX: outputs.Add(element.Location.X.ToString()); break; case ElementAction.LocationY: outputs.Add(element.Location.Y.ToString()); break; case ElementAction.SizeX: outputs.Add(element.Size.Width.ToString()); break; case ElementAction.SizeY: outputs.Add(element.Size.Height.ToString()); break; case ElementAction.Screenshot: var image = TakeElementScreenshot(browser, element); image.Save(Utils.GetScreenshotPath(data)); image.Dispose(); break; case ElementAction.ScreenshotBase64: var img = TakeElementScreenshot(browser, element); var ms = new MemoryStream(); img.Save(ms, ImageFormat.Jpeg); var base64 = Convert.ToBase64String(ms.ToArray()); outputs.Add(base64); img.Dispose(); ms.Dispose(); break; case ElementAction.SwitchToFrame: browser.SwitchTo().Frame(element); break; case ElementAction.WaitForElement: var waited = 0; // Currently waited milliseconds var timeout = 10000; try { timeout = int.Parse(replacedInput) * 1000; } catch { } var found = false; while (waited < timeout) { try { FindElements(browser, ReplaceValues(ElementString, ls)); element = elements[0]; found = true; break; } catch { waited += 200; await Task.Delay(200); } } if (!found) { throw new TimeoutException("Timed out while waiting for the element"); } break; case ElementAction.SendKeysHuman: foreach (var c in replacedInput) { element.SendKeys(c.ToString()); await Task.Delay(data.Random.Next(100, 300)); } break; } data.Logger.Log(string.Format("Executed action {0} on the element with input {1}", Action, replacedInput), LogColors.White); if (outputs.Count > 0) { InsertVariable(ls, IsCapture, Recursive, outputs, OutputVariable, "", "", false, true); } }
/// <inheritdoc /> public override async Task Process(LSGlobals ls) { var data = ls.BotData; await base.Process(ls); var replacedInput = ReplaceValues(InputString, ls); var variablesList = GetVariables(data); Variable variableToAdd = null; var logColor = IsCapture ? LogColors.Tomato : LogColors.Yellow; switch (Group) { case UtilityGroup.List: var list = variablesList.Get <ListOfStringsVariable>(ListName)?.AsListOfStrings(); var list2 = variablesList.Get <ListOfStringsVariable>(SecondListName)?.AsListOfStrings(); var item = ReplaceValues(ListItem, ls); var index = int.Parse(ReplaceValues(ListIndex, ls)); switch (ListAction) { case ListAction.Create: variableToAdd = new ListOfStringsVariable(new List <string>()); break; case ListAction.Length: variableToAdd = new StringVariable(list.Count.ToString()); break; case ListAction.Join: variableToAdd = new StringVariable(string.Join(Separator, list)); break; case ListAction.Sort: var sorted = list.Select(e => e).ToList(); // Clone the list so we don't edit the original one if (Numeric) { var nums = sorted.Select(e => double.Parse(e, CultureInfo.InvariantCulture)).ToList(); nums.Sort(); sorted = nums.Select(e => e.ToString()).ToList(); } else { sorted.Sort(); } if (!Ascending) { sorted.Reverse(); } variableToAdd = new ListOfStringsVariable(sorted); break; case ListAction.Concat: variableToAdd = new ListOfStringsVariable(list.Concat(list2).ToList()); break; case ListAction.Zip: variableToAdd = new ListOfStringsVariable(list.Zip(list2, (a, b) => a + b).ToList()); break; case ListAction.Map: variableToAdd = new DictionaryOfStringsVariable(list.Zip(list2, (k, v) => new { k, v }).ToDictionary(x => x.k, x => x.v)); break; case ListAction.Add: // Handle negative indices index = index switch { 0 => 0, < 0 => index + list.Count, _ => index }; list.Insert(index, item); break; case ListAction.Remove: // Handle negative indices index = index switch { 0 => 0, < 0 => index + list.Count, _ => index }; list.RemoveAt(index); break; case ListAction.RemoveValues: variableToAdd = new ListOfStringsVariable(list.Where(l => !Condition.Verify(new KeycheckCondition { Left = ReplaceValues(l, ls), Comparer = ListElementComparer, Right = ListComparisonTerm })).ToList()); break; case ListAction.RemoveDuplicates: variableToAdd = new ListOfStringsVariable(list.Distinct().ToList()); break; case ListAction.Random: variableToAdd = new StringVariable(list[data.Random.Next(list.Count)]); break; case ListAction.Shuffle: // This makes a copy of the original list var listCopy = new List <string>(list); listCopy.Shuffle(data.Random); variableToAdd = new ListOfStringsVariable(listCopy); break; default: break; } data.Logger.Log($"Executed action {ListAction} on list {ListName}", logColor); break; case UtilityGroup.Variable: string single = variablesList.Get <StringVariable>(VarName).AsString(); switch (VarAction) { case VarAction.Split: variableToAdd = new ListOfStringsVariable(single.Split(new string[] { ReplaceValues(SplitSeparator, ls) }, StringSplitOptions.None).ToList()); break; } data.Logger.Log($"Executed action {VarAction} on variable {VarName}", logColor); break; case UtilityGroup.Conversion: var conversionInputBytes = replacedInput.ConvertFrom(ConversionFrom); var conversionResult = conversionInputBytes.ConvertTo(ConversionTo); variableToAdd = new StringVariable(conversionResult); data.Logger.Log($"Executed conversion {ConversionFrom} to {ConversionTo} on input {replacedInput} with outcome {conversionResult}", logColor); break; case UtilityGroup.File: var file = ReplaceValues(FilePath, ls); FileUtils.ThrowIfNotInCWD(file); switch (FileAction) { case FileAction.Exists: variableToAdd = new StringVariable(File.Exists(file).ToString()); break; case FileAction.Read: lock (FileLocker.GetHandle(file)) variableToAdd = new StringVariable(File.ReadAllText(file)); break; case FileAction.ReadLines: lock (FileLocker.GetHandle(file)) variableToAdd = new ListOfStringsVariable(File.ReadAllLines(file).ToList()); break; case FileAction.Write: FileUtils.CreatePath(file); lock (FileLocker.GetHandle(file)) File.WriteAllText(file, replacedInput.Unescape()); break; case FileAction.WriteLines: FileUtils.CreatePath(file); lock (FileLocker.GetHandle(file)) File.WriteAllLines(file, ReplaceValuesRecursive(InputString, ls).Select(i => i.Unescape())); break; case FileAction.Append: FileUtils.CreatePath(file); lock (FileLocker.GetHandle(file)) File.AppendAllText(file, replacedInput.Unescape()); break; case FileAction.AppendLines: FileUtils.CreatePath(file); lock (FileLocker.GetHandle(file)) File.AppendAllLines(file, ReplaceValuesRecursive(InputString, ls).Select(i => i.Unescape())); break; case FileAction.Copy: var fileCopyLocation = ReplaceValues(InputString, ls); FileUtils.ThrowIfNotInCWD(fileCopyLocation); FileUtils.CreatePath(fileCopyLocation); lock (FileLocker.GetHandle(file)) lock (FileLocker.GetHandle(fileCopyLocation)) File.Copy(file, fileCopyLocation); break; case FileAction.Move: var fileMoveLocation = ReplaceValues(InputString, ls); FileUtils.ThrowIfNotInCWD(fileMoveLocation); FileUtils.CreatePath(fileMoveLocation); lock (FileLocker.GetHandle(file)) lock (FileLocker.GetHandle(fileMoveLocation)) File.Move(file, fileMoveLocation); break; case FileAction.Delete: // No deletion if the file is in use (DB/OpenBullet.db cannot be deleted but instead DB/OpenBullet-BackupCopy.db) // If another process is just reading the file it will be deleted lock (FileLocker.GetHandle(file)) File.Delete(file); break; } data.Logger.Log($"Executed action {FileAction} on file {file}", logColor); break; case UtilityGroup.Folder: var folder = ReplaceValues(FolderPath, ls); FileUtils.ThrowIfNotInCWD(folder); switch (FolderAction) { case FolderAction.Exists: variableToAdd = new StringVariable(Directory.Exists(folder).ToString()); break; case FolderAction.Create: variableToAdd = new StringVariable(Directory.CreateDirectory(folder).ToString()); break; case FolderAction.Delete: Directory.Delete(folder, true); break; } data.Logger.Log($"Executed action {FolderAction} on folder {folder}", logColor); break; default: break; } if (variableToAdd is not null) { variableToAdd.Name = VariableName; variableToAdd.MarkedForCapture = IsCapture; variablesList.Set(variableToAdd); } }
/// <summary> /// Removes all variables that meet a given a condition. /// </summary> public void RemoveAll(Comparer comparer, string name, LSGlobals ls) => Variables.RemoveAll(v => Condition.ReplaceAndVerify(v.Name, comparer, name, ls));
/// <summary> /// Adds a single variable with the given value. /// </summary> protected static void InsertVariable(LSGlobals ls, bool isCapture, string value, string variableName, string prefix = "", string suffix = "", bool urlEncode = false, bool createEmpty = true) => InsertVariable(ls, isCapture, false, new string[] { value }, variableName, prefix, suffix, urlEncode, createEmpty);
/// <summary> /// Gets the Action that needs to be executed. /// </summary> static internal Action Parse(string line, LSGlobals ls) { var data = ls.BotData; var input = line.Trim(); var field = LineParser.ParseToken(ref input, TokenType.Parameter, true).ToUpper(); return(new Action(() => { switch (field) { case "SOURCE": data.SOURCE = LineParser.ParseLiteral(ref input, "SOURCE", true, ls); break; case "STATUS": data.STATUS = LineParser.ParseToken(ref input, TokenType.Parameter, true); // E.g. user wrote SET STATUS CUSTOM "TEST" if (data.STATUS == "CUSTOM" && !string.IsNullOrEmpty(input)) { data.STATUS = LineParser.ParseLiteral(ref input, "CUSTOM STATUS"); } break; case "RESPONSECODE": data.RESPONSECODE = LineParser.ParseInt(ref input, "RESPONSECODE"); break; case "COOKIE": var name = LineParser.ParseLiteral(ref input, "NAME", true, ls); data.COOKIES.Add(name, LineParser.ParseLiteral(ref input, "VALUE", true, ls)); break; case "ADDRESS": data.ADDRESS = LineParser.ParseLiteral(ref input, "ADDRESS", true, ls); break; case "USEPROXY": var use = LineParser.ParseToken(ref input, TokenType.Parameter, true).ToUpper(); if (use == "TRUE") { data.UseProxy = true; } else if (use == "FALSE") { data.UseProxy = false; } break; case "PROXY": var prox = LineParser.ParseLiteral(ref input, "PROXY", true, ls); data.Proxy = Proxy.Parse(prox); break; case "PROXYTYPE": data.Proxy.Type = (ProxyType)LineParser.ParseEnum(ref input, "PROXYTYPE", typeof(ProxyType)); break; case "DATA": data.Line.Data = LineParser.ParseLiteral(ref input, "DATA", true, ls); break; case "VAR": var varName = LineParser.ParseLiteral(ref input, "NAME", true, ls); var varValue = LineParser.ParseLiteral(ref input, "VALUE", true, ls); BlockBase.GetVariables(data).Set(new StringVariable(varValue) { Name = varName }); break; case "CAP": var capName = LineParser.ParseLiteral(ref input, "NAME", true, ls); var capValue = LineParser.ParseLiteral(ref input, "VALUE", true, ls); BlockBase.GetVariables(data).Set(new StringVariable(capValue) { Name = capName }); data.MarkForCapture(capName); break; case "GVAR": try { var globalVarName = LineParser.ParseLiteral(ref input, "NAME", true, ls); var globalVarValue = LineParser.ParseLiteral(ref input, "VALUE", true, ls); ls.Globals.Set(new StringVariable(globalVarValue) { Name = globalVarName }); } catch { } break; case "NEWGVAR": try { var globalVarName = LineParser.ParseLiteral(ref input, "NAME", true, ls); var globalVarValue = LineParser.ParseLiteral(ref input, "VALUE", true, ls); ls.Globals.SetIfNew(new StringVariable(globalVarValue) { Name = globalVarName }); } catch { } break; case "GCOOKIES": ls.GlobalCookies.Clear(); foreach (var cookie in data.COOKIES) { ls.GlobalCookies.Add(cookie.Key, cookie.Value); } break; default: throw new ArgumentException($"Invalid identifier {field}"); } data.Logger.Log($"SET command executed on field {field}", LogColors.White); })); }
/// <summary> /// Replaces variables in all items of a list. /// </summary> public static List <string> ReplaceValues(List <string> original, LSGlobals ls) => original.Select(i => ReplaceValues(i, ls)).ToList();