Extrating OWASP Chapter data via MediaWiki API and viewing it
Here is a script that uses O2′s MediaWiki API to extract OWASP’s chapter information from its WIKI.
Once the data is collected, a mini gui is used to show it:
var topPanel = panel.clear().add_Panel();
var owaspWiki = new OwaspWikiAPI(false);
var treeView = topPanel.add_TreeView();
var textArea = topPanel.insert_Right().add_TextArea();
var webBrowser = textArea.insert_Below().add_WebBrowser_Control();
Action<List<string>,TreeNode, bool> loadArea = null;
var addedCategories = new List<string>();
treeView.afterSelect<string>(
(page)=>{
textArea.set_Text(page);
var wikiText = owaspWiki.wikiText(page);
var htmlCode = owaspWiki.html(page);
textArea.set_Text(wikiText);
webBrowser.open(htmlCode.save());
});
loadArea = (pages, parentNode, addChapters) =>
{
foreach(var page in pages)
{
if (page.contains("Category") && addedCategories.contains(page).isFalse())
{
addedCategories.add(page);
var categoryNode = parentNode.add_Node(page);
var chaptersInArea = owaspWiki.pagesInCategory(page);
loadArea(chaptersInArea, categoryNode , true);
}
else
if (addChapters)
parentNode.add_Node(page);
}
};
var chapters = owaspWiki.pagesInCategory("Category:OWASP Chapter");
//var chapters = @"C:\O2\_tempDir\2-8-2012\tmpA92F.tmp.xml".load<List<string>>();
loadArea(chapters,treeView.rootNode(),false);
treeView.selectFirst();
//return pages.size();
return "ok";
//O2File:OwaspWikiAPI.cs
//O2Ref:O2_Misc_Microsoft_MPL_Libs.dll
Example of creating, consuming and serializing C# classes
I’m currently helping Sarah Baso (from OWASP) to use O2 to streamline a number of OWASP admin tasks, and here are a couple script samples from the code that she is writing on retrieving details from Mailman Mailing lists
Here is the base class with data
// This file is part of the OWASP O2 Platform (http://www.owasp.org/index.php/OWASP_O2_Platform) and is released under the Apache 2.0 License (<a href="http://www.apache.org/licenses/LICENSE-2.0">http://www.apache.org/licenses/LICENSE-2.0</a>)
using System;
using System.Linq;
using System.Collections.Generic;
using System.Windows.Forms;
using System.Text;
using O2.Kernel;
using O2.Kernel.ExtensionMethods;
using O2.DotNetWrappers.DotNet;
using O2.DotNetWrappers.Windows;
using O2.DotNetWrappers.ExtensionMethods;
using O2.Views.ASCX.classes.MainGUI;
using O2.Views.ASCX.ExtensionMethods;
namespace O2.Script
{
public class MailingLists
{
public DateTime DateCollected { get; set;}
public List<MailingList> Lists { get; set; }
public MailingLists()
{
Lists = new List<MailingList>();
}
}
public class MailingList
{
public string Name { get; set; }
public bool Public { get; set; }
public List<Subscriber> Admins { get; set; }
public List<Subscriber> Subscribers { get; set; }
public MailingList()
{
Admins = new List<Subscriber>();
Subscribers = new List<Subscriber>();
}
}
public class Subscriber
{
public string Name { get; set; }
public string Email { get; set; }
}
}
Here is how that data can be consumed
var mailingLists = new MailingLists();</pre>
Action<string, bool> addList =
(listName, isPublic)=>
{
var mailingList = new MailingList();
mailingList.Name = listName;
mailingList.Public = isPublic;
mailingLists.Lists.Add(mailingList);
};
addList("owasp-london", true);
addList("owasp-rh", true);
addList("owasp-chapter", true);
/*var londonList = new MailingList();
londonList.Name = "Owasp-london";
londonList.Public = true;
mailingLists.Lists.Add(londonList);
var chaptersList = new MailingList();
chaptersList.Name = "Owasp-chapter";
chaptersList.Public = true;
mailingLists.Lists.Add(chaptersList);
*/
//return mailingLists;
//return myData;
var result = mailingLists.serialize(false);
panel.clear()
.add_TextArea()
.set_Text(result)
.size(16);
return mailingLists;
//using O2.Script
//O2File:C:\O2\_XRules_Local\Sarah's Test\MyData.cs
Here is how to normalize the email addresses
var url = https://lists.owasp.org/mailman/options/owasp-xyz-list/aaa_at_gmail.com;
if (url.contains("https://lists.owasp.org/mailman/options/"))
{
var items = url.remove("https://lists.owasp.org/mailman/options/").split("/");
var listName = items[0];
var email = items[1].replace("_at_","@");
return email;
}
return "no data";
Automating the Download of a GitHub ZipFile (using IE’s WatiN)
Here is a script that uses WatiN’s FileDownloadHandler to automate the download of a web page in IE (which popups to save it)
var ie = "ie_hLZRz".o2Cache<WatiN_IE>(()=> panel.clear().add_IE()).silent(true);
//using WatiN.Core.DialogHandlers
Func<string,string, string> open_and_HandleFileDownload =
(url, fileName)=>{
var tmpFile = fileName.tempFile();
var waitUntilHandled = 20;
var waitUntilDownload = 300;
var fileDownloadHandler = ie.dialogHandler<FileDownloadHandler>();</pre>
if (fileDownloadHandler.notNull())
{
ie.IE.RemoveDialogHandler(fileDownloadHandler);
}
fileDownloadHandler = new FileDownloadHandler(tmpFile);
ie.IE.AddDialogHandler(fileDownloadHandler);
fileDownloadHandler.field("saveAsFilename",tmpFile);
fileDownloadHandler.field("hasHandledFileDownloadDialog",false);
ie.open_ASync(url);
try
{
fileDownloadHandler.WaitUntilFileDownloadDialogIsHandled(waitUntilHandled);
"after: {0}".info("WaitUntilFileDownloadDialogIsHandled");
fileDownloadHandler.WaitUntilDownloadCompleted(waitUntilDownload);
"after: {0}".info("WaitUntilDownloadCompleted");
}
catch(Exception ex)
{
"[WatiN_IE][open_and_HandleFileDownload] {0}".error(ex.Message);
}
if (fileDownloadHandler.SaveAsFilename.fileExists())
{
"[WatiN_IE] downloaded ok '{0}' into '{1}'".info(url, fileDownloadHandler.SaveAsFilename);
return fileDownloadHandler.SaveAsFilename;
}
"[WatiN_IE] failed to download '{0}' ".info(url);
return null;
};
return open_and_HandleFileDownload("https://github.com/SecurityInnovation/YASAT/zipball/master_", "download.zip");
//O2File:WatiN_IE_ExtensionMethods.cs
//O2Ref:WatiN.Core.1x.dll
//_O2Tag_DontAddExtraO2Files;
//O2File:_Extra_methods_Collections.cs
The example above did a download from a puplic repository, if you need to access a private one (which required GitHub login), here is how to do it:
if(ie.url() != "https://github.com/DinisCruz/TeamMentor-v3.0")
ie.open("https://github.com/DinisCruz/TeamMentor-v3.0");
var githubAccount = @"C:\O2\_USERDATA\accounts.xml".credential("github");
Action loginToGitHub =
()=>{
if(ie.hasLink("Login"))
{
ie.link("Login").click();
ie.field("login_field").value(githubAccount.UserName);
ie.field("password").value(githubAccount.Password);
ie.button("Log in").click();
}
};
loginToGitHub();
return open_and_HandleFileDownload("https://github.com/DinisCruz/TeamMentor-v3.0/zipball/master", "download.zip");
Quickly testing RegExes and “Util – Text RegEx using FuzzDb.h2″ O2 script
If you want to quickly test a RegEx for possible security blind spots, here are a couple script samples that migth help you.
While writing these examples I ended up writing a mini tool which you can now access via the O2 Script Util – Text RegEx using FuzzDb.h2 and looks like this:
Source Code Snippets
Here are a couple script examples on how to test regexes with O2:
Here is a simple example:
var regExString = @"['""].*|[+\-*/%=&|^~'""]";
var payload1 = "this is ok";
var payload2 = "this is' ok";
var result1 = payload1.regEx(regExString);
var result2 = payload2.regEx(regExString);
return "{0} {1}".format(result1, result2);
Now add the fuzzDb payloads
var regExString = @"['""].*|[+\-*/%=&|^~'""]"; var matches = new List<string>(); var fuzzDb = new API_FuzzDB(); foreach(var payload in fuzzDb.payloads_Xss()) if (payload.regEx(regExString).isFalse()) matches.add(payload); foreach(var payload in fuzzDb.payloads_SQLi_Generic()) if (payload.regEx(regExString).isFalse()) matches.add(payload); return matches; //O2File:API_FuzzDB.cs
You can also test for what happens when the payloads are encoded
var regExString = @"['""].*|[+\-*/%=&|^~'""]"; var matches = new List<string>(); var fuzzDb = new API_FuzzDB(); foreach(var payload in fuzzDb.payloads_Xss()) if (payload.regEx(regExString.urlEncode()).isFalse()) matches.add(payload.urlEncode()); return matches; //O2File:API_FuzzDB.cs
Next step is to build a Gui:
var topPanel = panel.clear().add_Panel();
var actionsPanel = topPanel.insert_Above(40,"actions");
var dataGridView = topPanel.add_DataGridView()
.add_Columns("Payload", "Result");
var stop = false;
var sqli_payloads = false;
var xss_payloads = false;
var regExString = @"['""].*[+\-*/%=&|^~'""]";
Action startFuzzing =
()=>{
var fuzzDb = new API_FuzzDB();
var startFuzzingLink = actionsPanel.link("Start Fuzzing").enabled(false);;
var statusLabel = actionsPanel.controls<Label>(true).last();
Action<List<string>> testPayloads =
(payloads)=> {
foreach(var payload in payloads)
{
if (stop)
break;
statusLabel.set_Text("testing payload: {0}".format(payload));
if (payload.regEx(regExString).isFalse())
dataGridView.add_Row(payload, false);
}
};
if (sqli_payloads)
testPayloads(fuzzDb.payloads_Xss());
if (xss_payloads)
testPayloads(fuzzDb.payloads_Xss());
stop = false;
startFuzzingLink.enabled(true);
statusLabel.set_Text("Tests completed");
};
actionsPanel.add_Label("RegEx To test").top(3)
.append_TextBox(regExString).onTextChange((text)=> regExString = text).width(200)
.append_CheckBox("Xss", (value)=> xss_payloads= value).tick().top(1)
.append_CheckBox("Sqli", (value)=> sqli_payloads= value).tick()
.append_Link("Start Fuzzing", ()=> startFuzzing()).font_bold().top(3)
.append_Link("stop", ()=> stop = true)
.append_Link("clear table", ()=> dataGridView.remove_Rows() )
.append_Label("...").autoSize().top(3);
startFuzzing();
return "ok";
//O2File:API_FuzzDB.cs
Final version
Here is a version with a couple more features (see screenshot above)
var topPanel = "Util - Text RegEx using FuzzDb".popupWindow(1000,400);
//var topPanel = panel.clear().add_Panel();
var actionsPanel = topPanel.insert_Above(40,"actions");
var dataGridView = topPanel.add_DataGridView()
.add_Columns("Payload", "Result");
var stop = false;
var sqli_payloads = false;
var xss_payloads = false;
var withUrlEncoding = false;
var regExString = @"['""].*[+\-*/%=&|^~'""]";
Action startFuzzing =
()=>{
var fuzzDb = new API_FuzzDB();
var startFuzzingLink = actionsPanel.link("Start Fuzzing").enabled(false);;
var statusLabel = actionsPanel.controls<Label>(true).last();
Action<List<string>> testPayloads =
(payloads)=> {
foreach(var payload in payloads)
{
if (stop)
break;
statusLabel.set_Text("testing payload: {0}".format(payload));
if (payload.regEx(regExString).isFalse())
dataGridView.add_Row(payload, false);
if (withUrlEncoding)
{
var encodedPayload = payload.urlEncode();
statusLabel.set_Text("testing payload: {0}".format(encodedPayload));
if (encodedPayload.regEx(regExString).isFalse())
dataGridView.add_Row(encodedPayload, false);
this.sleep(100);
}
}
};
if (sqli_payloads)
testPayloads(fuzzDb.payloads_SQLi_Generic());
if (xss_payloads)
testPayloads(fuzzDb.payloads_Xss());
// we could also apply the transformation into the entire list like this
//testPayloads( fuzzDb.payloads_Xss().Select((value)=> value.urlEncode()) );
stop = false;
startFuzzingLink.enabled(true);
statusLabel.set_Text("Tests completed");
};
actionsPanel.add_Label("RegEx To test").top(3)
.append_TextBox(regExString).onTextChange((text)=> regExString = text).width(200)
.append_CheckBox("Xss", (value)=> xss_payloads= value).tick().top(1)
.append_CheckBox("Sqli", (value)=> sqli_payloads= value)//.tick()
.append_CheckBox("with UrlEncoding", (value)=> withUrlEncoding= value)//.tick()
.append_Link("Start Fuzzing", ()=> startFuzzing()).font_bold().top(3)
.append_Link("stop", ()=> stop = true)
.append_Link("clear table", ()=> dataGridView.remove_Rows() )
.append_Label("...").autoSize().top(3);
startFuzzing();
return "ok";
//O2File:API_FuzzDB.cs
Weird behaviour with IE’s about:blank
Usually I use about:blank when wanting to open a blank page in a browser. Today I noticed an interresting behaviour in the embeded IE object that I use in O2 (via WatiN).
What happens is that if we don’t use ‘blank‘ and use other text (for example about:AAAA), that other text will be displayed in the page (in this case AAAA).
What is interresting is that it supports HTML tags, which means that opening the url “about:<h1>hello</h1>” will show the word hello under the h1 style.
Here is a quick O2 script that replicates this behaviour:
var topPanel = panel.clear().add_Panel();
var ie = topPanel.add_IE().silent(false);
ie.open("about:testing");
this.sleep(1000);
ie.open("about:<script>document.write('dynamic script')</script>");
this.sleep(1000);
ie.open("about:<script>alert('interresting...')</script>");
//these ones don't work from here
//ie.open(@"about:<iframe src='http://google.com' width=400 height=100> </iframe>");
//ie.open(@"about:<iframe src='\C:\O2\Demos\testFile.txt' width=400 height=100> </iframe>");
return "done";
//O2File:WatiN_IE_ExtensionMethods.cs
//using O2.XRules.Database.Utils.O2
//O2Ref:WatiN.Core.1x.dll
Note that this doesn’t seem to work on normal IE, Chrome or Firefox (I only saw it in action in the embeded IE)
Decompressing HTTP GZIP responses using GZipStream (via extension methods)
Here is a good example of using Extension Methods to simplify the compressing and decompressing of strings.
This is how it is used:
var originalString = "this is the original string"; var compressedBytes = originalString.gzip_Compress(); var decompressedString = compressedBytes.gzip_Decompress(); return originalString == decompressedString; //O2File:_Extra_methods_Web.cs
Or even more simply:
return "this is a string".gzip_Compress().gzip_Decompress(); //O2File:_Extra_methods_Web.cs
Here is the source code of the gzip_Compress and gzip_Decompress Extension methods used above:
public static class _Extra_Web_ExtensionMethods_GZip
{
public static byte[] gzip_Compress(this string _string)
{
var bytes = Encoding.ASCII.GetBytes (_string);
var outputStream = new MemoryStream();
using (var gzipStream = new GZipStream(outputStream,CompressionMode.Compress))
gzipStream.Write(bytes, 0, bytes.size());
return outputStream.ToArray();
}
public static string gzip_Decompress(this byte[] bytes)
{
var inputStream = new MemoryStream();
inputStream.Write(bytes, 0, bytes.Length);
inputStream.Position = 0;
var outputStream = new MemoryStream();
using (var gzipStream= new GZipStream(inputStream,CompressionMode.Decompress))
{
byte[] buffer = new byte[4096];
int numRead;
while ((numRead = gzipStream.Read(buffer, 0, buffer.Length)) != 0)
outputStream.Write(buffer, 0, numRead);
}
return outputStream.ToArray().ascii();
}
}
Weird Bug with RichTextBox’s ScrollToCaret while using AppendText (trying to fix text flickering)
While tuning the API_ConsoleOut (using a RichTextBox instead of a TextBox), I found a really weird behaviour with the RichTextBox’s ScrollToCaret method.
What happened is that since a call to AppendText didn’t show the last text added, a call to ScrollToCaret is needed. But, if multiple calls to AppendText + ScrollToCaret are made the text view would be (alternatively) on the last line and the line before (this was aligned at the top, which meant that the text would flicker).
After multiple experiements (see O2 Script below) I found that if we set the HideSelection value to false, the AppendText will trigger the correct scroll.
Here is the code that works:
var topPanel = panel.clear().add_Panel();
topPanel.fill(false).height(50);
var richTextBox = topPanel.add_RichTextBox();
richTextBox.set_Text("a".line() +
"b".line() +
"c".line() +
"d".line());
richTextBox.hideSelection(false);
richTextBox.append_Text("123");
richTextBox.append_Text("_");
richTextBox.append_Text("*"); //all now work as expected
Here is the full code of my tests
//var topPanel = O2Gui.open<Panel>("{name}",700,400);
var topPanel = panel.clear().add_Panel();
topPanel.fill(false).height(50);
var richTextBox = topPanel.add_RichTextBox();
richTextBox.set_Text("a".line() +
"b".line() +
"c".line() +
"d".line());
//variation A2)
/*
richTextBox.append_Text("123").scrollToCaret(); // works as expeceted
richTextBox.append_Text("_").scrollToCaret(); // caret is one line up
//richTextBox.append_Text("*").scrollToCaret(); // works as expeceted
*/
//variation A1)
/*richTextBox.append_Text("123").scrollToCaret(); // works as expeceted
this.sleep(300);
richTextBox.append_Text("_").scrollToCaret(); // caret is one line up
this.sleep(300);
richTextBox.append_Text("*").scrollToCaret(); // works as expeceted
*/
//variation B)
/*richTextBox.invokeOnThread(
()=>{
richTextBox.AppendText("123"); // works as expeceted
richTextBox.ScrollToCaret();
richTextBox.AppendText("_"); // caret is one line up
richTextBox.ScrollToCaret();
//richTextBox.AppendText("*"); // works as expeceted
//richTextBox.ScrollToCaret();
});*/
//variation C)
/*Action<string> appendText =
(text)=>{
var before = richTextBox.SelectionStart;
richTextBox.AppendText(text);
var after = richTextBox.SelectionStart;
"text: {0} before: {1} after: {2}".info(text, before, after);
richTextBox.ScrollToCaret();
};
richTextBox.invokeOnThread(
()=>{
appendText("123"); // works as expeceted
appendText("_"); // caret is one line up
appendText("*"); // works as expeceted
appendText("_"); // caret is one line up
});
*/
//the solution for the problem is to set the HideSelection property set to false
//which is now exposed via an O2 Extension Method
richTextBox.hideSelection(false); // richTextBox.showSelection(); also works
richTextBox.append_Text("123");
richTextBox.append_Text("_");
richTextBox.append_Text("*"); //all now work as expectted
/*
//Variation D) using scrollToCaret brings back the problem,
richTextBox.hideSelection(false);
richTextBox.append_Text("123");
richTextBox.append_Text("_");//.scrollToCaret();
richTextBox.append_Text("*").scrollToCaret();
*/
return "done";
It would be great to find out exactly what was causing this behaviour, but I looks that most of the RichTextBox behaviour is triggered by Windows Messages, so its quite a rabbit hole.
API_ConsoleOut.cs – New and InProcess Capture of the Console Output
There are multiple scenarious where it is usefull to capture (via Lambda callbacks) the calls to Console.Write. Most solutions out there are based on using the Process class (via its ProcessStartInfo settings):
- Capturing console output from a .NET application (C#)
- Redirect console output to textbox in separate program C#
- How to run a .EXE file from C# and obtain(pipe) the results from DOS windows back into the C#
- How to get console terminal output text?
- Capture console and output in realtime
- How to redirect the Console’s output to a TextBox in C# (using the Console.SetOut technique)
- Demonstrates redirecting the Console output to a file (using the Console.SetOut technique)
The problem with those solutions is they are able to capture the Console Output of the new process created, NOT the current process (which is what I want since I need to see the Console messages created by an external API/Code that I consuming from O2)
Using O2 to captute Console Output of new processes
Note: If all you want to do is to capture the console output of a new process, there are a bunch of O2 methods/APIs that can help you with it:
Which can be used like this:
run cmd.exe (with params: /c dir) and get its console output
return "cmd.exe".startProcess_getConsoleOut(" /c dir");
run netstat.exe (with params: -na) and redirect its console into a lambda method
"netstat.exe".startProcess("-na", (line)=> line.info());
run netstat.exe and show its results in a table list
var topPanel = panel.clear().add_Panel();
var tableList = topPanel.add_TableList();
var lines = "netstat.exe".startProcess_getConsoleOut("-na")
.lines()
.removeRange(0,2);
var netstatData = (from line in lines
let fragments = line.split(" ").removeEmpty()
select new {
@Type = fragments.value(0) ,
Local_Address = fragments.value(1) ,
Foreign_Address = fragments.value(2) ,
State = fragments.value(3)
});
tableList.show(netstatData);
Using O2 to captute Console Output in the current Process
To capture the Console Output in the current process, I first tried to capture the usage of a MemoryStream in a way simular to how Console actually works (see O2 blog post Dynamically creating private/internal types and delegates (UserCallBack and AsyncStreamReader) ) , but a much easier way is to specify a TextWriter via Console.SetOut.
To make it easier to use, I created the API_ConsoleOut class which can be used like this:
Show Console Ouput in a new window
"Write this to the console :)".open_ConsoleOut();
Console.Write("another");
Console.WriteLine("test");
//O2File:API_ConsoleOut.cs
Which looks like this:
Show Console Output in an existing panel/control
var topPanel = panel.clear().add_Panel();
topPanel.show_ConsoleOut(); //this will open as a child of an existing control
Console.Write("another ");
Console.WriteLine("test");
topPanel.insert_Right().add_SourceCodeViewer().set_Text("<h1>some html<h1>",".html");
Console.WriteLine("now inside a Windows Control");
return "done";
//O2File:API_ConsoleOut.cs
Which looks like this:
Test GUI with Console Input
If you want to test the Console Input and Output, there is also a test GUI that you can use
var apiConsoleOut = new API_ConsoleOut();
apiConsoleOut.show_ConsoleOut_TestGui();
Console.Write("another ");
Console.WriteLine("test");
Console.WriteLine("now with more options");
//O2File:API_ConsoleOut.cs
Which looks like this:
Source code of API_Console_Out.cs
using System;
using System.IO;
using System.Text;
using System.Drawing;
using System.Windows.Forms;
using System.Collections.Generic;
using O2.Interfaces.O2Core;
using O2.Kernel;
using O2.Kernel.ExtensionMethods;
using O2.DotNetWrappers.ExtensionMethods;
using O2.Views.ASCX.classes.MainGUI;
using O2.XRules.Database.Utils;
//O2File:_Extra_methods_Misc.cs
//O2File:_Extra_methods_Windows.cs
//O2File:_Extra_methods_WinForms_Controls.cs
namespace O2.XRules.Database.APIs
{
public class API_ConsoleOut : Control
{
public O2StreamWriter o2StreamWriter;
public API_ConsoleOut()
{
this.o2StreamWriter = new O2StreamWriter();
this.o2StreamWriter.Name = "API_ConsoleOut";
Console.SetOut(this.o2StreamWriter);
}
}
public class O2StreamWriter : TextWriter
{
public StringBuilder ConsoleOut { get; set; }
public StringBuilder CurrentLine { get; set; }
public List<string> Lines { get; set; }
public Action<char> On_NewChar { get; set; }
public Action<string> On_NewLine { get; set; }
public bool LogAllChars { get; set; }
public bool LogAllLines { get; set; }
public string Name { get; set; }
public int PauseBetweenCharWrite { get; set; }
public O2StreamWriter()
{
ConsoleOut = new StringBuilder();
CurrentLine = new StringBuilder();
Lines = new List<string>();
LogAllChars = false;
LogAllLines = true;
Name = "O2StreamWriter";
}
public override void Write(char value)
{
base.Write(value);
this.ConsoleOut.Append(value.ToString());
if (value == '\n')
handleLine();
else
this.CurrentLine.Append(value.ToString());
if (this.LogAllChars)
"[{0}] char: {1}".info(this.Name, value);
if (this.On_NewChar.notNull())
this.On_NewChar(value);
if (PauseBetweenCharWrite > 0)
this.sleep(PauseBetweenCharWrite, false);
}
public void handleLine()
{
var line = this.CurrentLine.str();
if (line.lastChar('\r'))
line = line.removeLastChar();
this.CurrentLine = new StringBuilder();
this.Lines.add(line);
if (this.LogAllLines)
"[{0}]: {1}".info(this.Name, line);
if (this.On_NewLine.notNull())
this.On_NewLine(line);
}
public override Encoding Encoding
{
get { return System.Text.Encoding.UTF8; }
}
}
public static class API_ConsoleOut_ExtensionMethods_TestGuis
{
public static API_ConsoleOut show_ConsoleOut_TestGui(this API_ConsoleOut apiConsoleOut)
{
var topPanel = O2Gui.open<Panel>("Console.Out capture Test",700,200);
return apiConsoleOut.show_ConsoleOut_TestGui(topPanel);
}
public static API_ConsoleOut show_ConsoleOut_TestGui(this API_ConsoleOut apiConsoleOut, Control topPanel)
{
var consoleIn = topPanel.insert_Above(40, "ConsoleIn");
var lines_TextBox = topPanel.clear().add_GroupBox("Console.Out Lines").add_TreeView();
var chars_TextBox = topPanel.insert_Right("Console.Out Chars").add_TextArea();
consoleIn.add_TextBox("Write to send to Console Input ->","")
.onKeyPress_getChar( (_char)=> { if (_char == '\x0d') Console.WriteLine(); else Console.Write(_char); })
.multiLine(true)
.focus();
apiConsoleOut.o2StreamWriter.On_NewChar = (_char) => chars_TextBox.append_Text(_char.str());
apiConsoleOut.o2StreamWriter.On_NewLine = (line) => lines_TextBox.add_Node(line);
//apiConsoleOut.o2StreamWriter.PauseBetweenCharWrite = 1;
Console.WriteLine("Welcome to show_ConsoleOut_TestGui");
Console.Write("Type something on the TextBox above to see it here".line());
return apiConsoleOut;
}
public static API_ConsoleOut open_ConsoleOut(this string message)
{
return message.show_ConsoleOut();
}
public static API_ConsoleOut show_ConsoleOut(this string message)
{
var apiConsoleOut = new API_ConsoleOut();
apiConsoleOut.show_ConsoleOut();
Console.WriteLine(message);
return apiConsoleOut;
}
public static API_ConsoleOut add_ConsoleOut(this Control topPanel)
{
return topPanel.show_ConsoleOut();
}
public static API_ConsoleOut show_ConsoleOut<T>(this T topPanel)
where T : Control
{
return topPanel.show_ConsoleOut("Welcome to O2's console");
}
public static API_ConsoleOut show_ConsoleOut<T>(this T topPanel, string message )
where T : Control
{
var apiConsoleOut = new API_ConsoleOut();
apiConsoleOut.show_ConsoleOut(topPanel);
Console.WriteLine(message);
return apiConsoleOut;
}
public static API_ConsoleOut show_ConsoleOut(this API_ConsoleOut apiConsoleOut)
{
var topPanel = O2Gui.open<Panel>("Console.Out",700,200);
return apiConsoleOut.show_ConsoleOut(topPanel);
}
public static API_ConsoleOut show_ConsoleOut(this API_ConsoleOut apiConsoleOut, Control topPanel)
{
var consoleOut = topPanel.add_TextArea();
consoleOut.backColor(Color.Black);
consoleOut.foreColor(Color.White);
consoleOut.font("Lucida Console");
apiConsoleOut.o2StreamWriter.On_NewChar = (_char) => consoleOut.append_Text(_char.str());
apiConsoleOut.o2StreamWriter.LogAllLines = false;
consoleOut.add_ContextMenu()
.add_MenuItem("Clear", false, ()=> consoleOut.set_Text(""))
.add_MenuItem("Write to Console Input", ()=> Console.WriteLine("Text to send to Console.Input".askUser()));
return apiConsoleOut;
}
}
}
O2 Script: Util – Util – Show Open Ports (via NetStat -afo).h2
Here is are two scripts that show how to parse ‘kind-off’ unstructured data into a table.
In the first example we grab the output from netstat -fa , parse it in order to extract the port numbers and display it on a table. The 2nd example uses netstat-fao which will also contain the process id (which is used by the script to find the process name)
For reference, in netstat
- a = Displays all connections and listening ports
- f = Displays Fully Qualified Domain Names (FQDN) for foreign addresses.
- o = Displays the owning process ID associated with each connection
1st version (netstat -fa)
var topPanel = O2Gui.open<Panel>("Util - Show Open Ports (via NetStat -na)",700,600);
//var topPanel = panel.clear().add_Panel();
var tableList = topPanel.add_TableList();
Action showNetStatOnTable =
()=>{
var lines = "netstat.exe".startProcess_getConsoleOut("-na")
.lines()
.removeRange(0,2);
var netstatData = (from line in lines
let fragments = line.split(" ").removeEmpty()
let value0 = fragments.value(0)
let value1 = fragments.value(1)
let value2 = fragments.value(2)
let value3 = fragments.value(3)
select new {
@Type = value0 ,
//Local_Address = value1,
Local_Address_IP = value1.replace("::","__").split(":")[0].replace("__","::"),
Local_Address_Port = value1.replace("::","__").split(":")[1] ,
//Foreign_Address = value2 ,
Foreign_Address_IP = value2.replace("::","__").split(":")[0].replace("__","::"),
Foreign_Address_Port = value2.replace("::","__").split(":")[1] ,
State = value3
});
tableList.show(netstatData);
};
topPanel.insert_Above(40, "Actions")
.add_Link("Refresh", ()=> showNetStatOnTable())
.click();
2nd version (netstat -fao)

var topPanel = O2Gui.open<Panel>("Util - Show Open Ports (via NetStat -afo)",700,600);
//var topPanel = panel.clear().add_Panel();
var tableList = topPanel.add_TableList();
tableList.title("Table showing parsed version of netstat command");
var selectedProcess = 0;
Action showNetStatOnTable =
()=>{
var lines = "netstat.exe".startProcess_getConsoleOut("-afo")
.lines()
.removeRange(0,2);
var netstatData = (from line in lines
let fragments = line.split(" ").removeEmpty()
let value0 = fragments.value(0)
let value1 = fragments.value(1)
let value2 = fragments.value(2)
let value3 = fragments.value(3)
let value4 = fragments.value(4)
select new {
@Type = value0 ,
//Local_Address = value1,
Local_Address_IP = value1.replace("::","__").split(":")[0].replace("__","::"),
Local_Address_Port = value1.replace("::","__").split(":")[1] ,
//Foreign_Address = value2 ,
Foreign_Address_IP = value2.replace("::","__").split(":")[0].replace("__","::"),
Foreign_Address_Port = value2.replace("::","__").split(":")[1] ,
State = value3,
Process_ID = value4,
Process_Name = Processes.getProcess(value4.toInt()).ProcessName //,
//Executable = value5
});
tableList.show(netstatData);
};
Action stopSelectedProcess =
()=>{
if (selectedProcess ==0)
"Cannot Stop process with ID 0".error();
else
{
var process = Processes.getProcess(selectedProcess);
"Stopping process: {0} (id: {1})".info(process.ProcessName, process.Id);
process.stop()
.WaitForExit();
showNetStatOnTable();
}
};
topPanel.insert_Above(40, "Actions")
.add_Link("Refresh", ()=> showNetStatOnTable())
.append_Link("Stop Selected Process", ()=> stopSelectedProcess()).leftAdd(100);
tableList.add_ContextMenu()
.add_MenuItem("Stop Selected Process", ()=> stopSelectedProcess());
tableList.afterSelect_get_Cell(6,
(value)=> {
selectedProcess = value.toInt();
"selectedProcess: {0}".info(selectedProcess);
});
showNetStatOnTable();
//return "netstat.exe".startProcess_getConsoleOut("-afo");
return "ok";
This script is now part of O2′s Scripts as Util – Show Open Ports (via NetStat -afo).h2
Dynamically creating private/internal types and delegates (UserCallBack and AsyncStreamReader)
When trying to create a callback into Console.Out, I tried to create a instance of the internal class AsyncStreamReader (which has a dependency on the private delegate UserCallBack). This workded ok (see code below), but it didn’t have the expected behaviour (I did get a call into the outputReadNotifyUser Lambda method, but it only happened once and there was no value in its text variable) .
I actually found a better way (see next blog post), but meanwhile here is an example of how to use reflection to create instance of private types and delegates.
//Not currently working, but shows how to create a private Delegate and Type
var currentProcess = Processes.getCurrentProcess();
Action<string> outputReadNotifyUser =
(text)=>{
"outputReadNotifyUser: {0}".info(text);
};
var userCallBackType = PublicDI.reflection.getType("UserCallBack");
var userCallBack = Delegate.CreateDelegate(userCallBackType, outputReadNotifyUser, typeof(Action<string>).method("Invoke"));
var memoryStream = new MemoryStream();
var streamWriter = new StreamWriter(memoryStream);
System.Console.SetOut(streamWriter);
streamWriter.AutoFlush = true;
var oParams = new object[] { currentProcess,memoryStream, userCallBack , Encoding.UTF8};
var asyncStreamReader = PublicDI.reflection.getType("AsyncStreamReader");
var aSyncReader = asyncStreamReader.ctors()[0].Invoke(oParams);
aSyncReader.invoke("BeginReadLine");
Console.Out.WriteLine("aaaa".line());
Console.Out.WriteLine("aaaa".line());
return "ok";
//using System.Text
//using System.IO
//using System.Diagnostics






