ChrisLaffra's Profile

  • Name: Chris Laffra
  • Email: (Private)
  • Member Since: May 1, 2008
  • Last Logged In: Nov 24, 2009 11:06 AM
  • Status Level:  
  • Location: Raleigh, NC, USA
  • Homepage: http://laffra.com

ChrisLaffra's Latest Content

Today, I wrote a game in EGL Rich UI inspired by the well-known web game called "Escape", "Escapa", "The Red Box Game", or whatever name the latest inspired copier decided to give before hosting it on their own homepage. I am still trying to find out who really wrote the original.

Anyway, it looks like this:

escape.jpg
See http://eglplanner.com/escape

The intent of the game is simple. You drag the red box labelled "EGL" around with your mouse. All you need to do is avoid the blue boxes and the walls.

How does the game work?

The game essentially consists of two parts: the UI that draws the boxes and let you drag the red box and a service component that can show the top 10 scores. I will describe the two parts in more detail now.

How to avoid Java, C, PHP, and JavaScript

The main algorithm for this game is the following:
  • place a red box in the middle and allow the user to drag it
  • place four blue boxes elsewhere and give each a unique motion vector
  • start a new job to run each X milliseconds to move each blue box
  • when the red box goes outside the white box or overlaps with a blue box, stop
  • every 10 seconds decrease the value of X so the blue boxes will move faster

The blue boxes shown in the UI are positioned absolutely using a syntax like this:
    new Div {
        position = "absolute", x = 300, y = 330, 
        width = 100, height = 20, 
        color = "white", background = "navy", font = "Arial", 
        innerHTML = "<center style='margin-top: 1px'>JavaScript</center>"        
    }


By making the boxes positioned absolutely, we can place them at any place we want. For this box, the initial location is at x=300 and y=330.

Each time the game timer goes off, we move the blue boxes in a given direction:
    moveEnemy(enemies[2], -12, -20);


For each blue box, we remember its x and y direction. For instance, when it bounces against the right wall, we make its x direction -1. The box is moved simply by giving it a new x and y coordinate. After moving the box, we check to see if we now touch the red box. If so, we stop the game.
    function moveEnemy(enemy Div, x int in, y int in)
        directionX int = enemy.getAttribute("directionX");
        directionY int = enemy.getAttribute("directionY");
        if (touchesVerticalWall(enemy))
            directionX *= -1;
            enemy.setAttribute("directionX", directionX);
        end
        if (touchesHorizontalWall(enemy))
            directionY *= -1;
            enemy.setAttribute("directionY", directionY);
        end
        enemy.x += x * directionX;
        enemy.y += y * directionY;
        if (enemyTouches(enemy))
            stop("a blue box");
        end
    end


The red box itself has drag and drop handlers define on it:
    red Div {
        onStartDrag = startDrag, onDrag = drag, onDropOnTarget = endDrag, 
        cursor = "pointer", 
        position = "absolute", x= 205, y = 205,    width = 40, height = 40, 
        background = "darkred", color = "white", font = "Arial",
        innerHTML = "<center style='margin-top: 9px'>EGL</center>"
    };    


This allows us to start the game and drag the red box while the user moves the mouse:
    function startDrag(widget Widget in, x int in, y int in) returns(boolean)
        dx = x - red.x;
        dy = y - red.y;
        start();
        return (true);
    end
    function drag(widget Widget in, target Widget in, x int in, y int in)
        if (!stopped)
            red.x = x - dx;
            red.y = y - dy;
        end
        if (outsidewhite())
            stop("the black border");
        end
    end
    function endDrag(widget Widget in, target Widget in, x int in, y int in)
    end


Finally, when the game stops, we inform the user and display the top 10 scores:
    function stop(reason String in)
        message.text = "You touched "+reason+". Drag the red box to start.";        
        reset();
        stopped = true;
        top10.score = (browser.currentTimeMillis() - startTime)/1000;
    end


Keeping a Top 10 List

Our top 10 list consists of a little bit of UI, and a service call to report the current score and receive an answer back with the total number of games played and the top 10 games.

The UI is nothing thrilling, other than using a cookie to remember your name:
    nameLabel TextLabel { text = "Your Name: " };
    cookie Cookie { key = "name" };
    nameField TextField { width = 80, text = cookie.value, onKeyUp ::= setName };


That same cookie is updated when the user enters a new name, and stored in the browser's cookie jar. Next time the user returns, the stored value will be automatically picked up. Updating a cookie value is as easy as giving it a new value:
    function setName(e Event in)
        if (nameField.text != "")
            cookie.value = nameField.text;
        end
    end 


The service calls a REST service with 2 URL parameters. It returns a record with inside it an array of top scores. Notice from the definition below that it is not relevant if the service is using XML or JSON to encode its contents. The EGL runtime will determine at runtime how to parse the result.

The service definition looks like this:
    interface HighScores
        function getTop10(name String in, score float in) returns(HighScoresRecord) 
           {@GetRest {
                   uriTemplate="http://eglplanner.com/escape/highscore.php?name={name}&score={score}"
           }};
    end    
    record Result
        total int;
        top10 ScoreRecord[0];
    end
    record Score
        name String;
        value float;
    end


To call the service, we use the EGL call statement identifying the service we want to call and what function we want to use when the response arrives in the future:
    function setScore(score float in)
        this.score = score;
        scoreField.text = "Score: "+score;
        call svc.getTop10(nameField.text, score) returning to handleTop10 onException ServiceLib.serviceExceptionHandler;
    end


The top 10 scores are stored in a div that is given an opacity of 0.8, so it is a little bit transparent:
    top10 Div { 
        position = "absolute", x = -100, y = 5, 
        *opacity = 0.8*, padding = 10, background = "black", 
        borderColor = "red", borderWidth = 12, borderStyle = "solid" 
    };


When the answer comes back from the top10 service it is converted automatically by EGL into a set of nested records and we simply add them to our top10 div. Finally, we show the top10 div in the right position:
    function handleTop10(result HighScoresRecord in)
        s String = "Total plays: <b>"+result.total + "</b>. " +
            "Your score: <b>"+score+"s</b>.<p>" +
            "Here are the Top 10 scores:

" + "<table border=1 width=300 cellpadding=3 style:'margin:10px; opacity: 1.0'>"; for (n int from 1 to result.top10.getSize()) score ScoreRecord = result.top10[n]; s += "<tr><td>" + n + "</td><td>" + score.value + "s</td><td>   " + score.name + "</td></tr>"; end s += "</table>"; top10.innerHTML = s; top10.x = scoreField.x + scoreField.pixelWidth + 15; ui.table.setAttribute("valign", "top"); showTop10(true); end function showTop10(value boolean in) if (value) ui.appendChild(top10); else ui.removeChild(top10); end end



Using PHP to implement the backend service

All the client code is done in EGL. I decided to place the game on an ISP where I took the cheapest plan available. The plan comes standard with PHP and MySQL. So, I decided to try and use MySQL and PHP to store the high scores to see how that worked.

The MySQL table structure is pretty simple:
    name    varchar(64)           
    score    float          
    ip        varchar(32)


I added and IP field to remember where the service came from (which is of course a very limited approach to authentication). I created the table using the phpMyAdmin client that my Internet provider offers.

Then I wrote some PHP and placed it right next to my game's index.html file. Here is what the (insecure) PHP looks like:
<?
   $host = "localhost";
   $user = "*********";
   $pass = "*********";
   $db      = "highscores";

   $name = $_REQUEST['name'];
   $score = $_REQUEST['score'];
   $ip = $_SERVER['REMOTE_ADDR'];

   $connection = mysql_connect($host, $user, $pass) or die ("Unable to connect!");
   mysql_select_db($db) or die ("Cannot open database $db");
 
   if (isset($name) && isset($score)) {      
      $query = "INSERT INTO highscores(name, score, ip) VALUES('$name', '$score', '$ip')";
      $result = mysql_query($query);
   }

   $query = "SELECT * FROM highscores";
   $result = mysql_query($query);
   $total = mysql_num_rows($result);
   $query = "SELECT * FROM highscores ORDER BY score + 0 DESC LIMIT 10";
   $result = mysql_query($query);
   echo "<result><total>$total</total>";
   if (mysql_num_rows($result) > 0) {
      while($row = mysql_fetch_row($result)) {
         echo "<score><name>$row[0]</name><value>$row[1]</value></score>";
      }
   } 
   echo "</result>";
   mysql_close($connection);
?>


Security

My PHP code is highly insecure for various reasons. First, anyone can simply call the URL above and assign any score they like:

Hack your own score

Note that I added some sanity checks so that the above URL no longer works :-)

Using a REST service with URL parameters makes it trivial to call in a browser. Tools like Rational AppScan know this and run a huge number of "worst practice" scenarios on a website to find holes like the one I inserted here.

Some ways of making service hacking more difficult would be:
  • Use a POST and place the arguments in the message body, instead of on the URL.
  • Use some "secret" encoding for the message that only the client and the service know about.
When you use SOAP messages, you already use POST and a secret encoding (in this case a SOAP envelope).

One complicating problem is that our client is written in easy to read JavaScript (compiled from our EGL). That gives hackers a lot of leverage. However, even extreme obfuscation of the JavaScript won't help as hackers can easily use Firebug in Firefox to watch the network traffic and derive what services are used and how to call them. Then they can play the man-in-the-middle game to make the server believe they are the client.

Maybe JavaScript obfuscation combined with service obfuscation has a higher degree of chance of making hackers give up and look for an easier target to hack.

Of course, obscuring thing stops the really silly hacks and even the accidental ones. However, as Andy Tanenbaum used to say when I was stil back in school attending his class on Operating Systems: obscurity is the worst form of security.

Always use SLL and proper authentication to increase security.

Securing the channel and authentication helps to a certain degree. In the end, however, services have to be extremely defensive, paranoid, trace everything, apply statistical analysis, and allow for easy human intervention. Think of your credit card company calling you on your cellphone to verify a suspicious transaction. Also, most comment sections on website have a button to report spam messages or abuse. Any system that runs over the Internet should be assuming the worst and be able to easily recover from abuse.

SQL Injection

One special form of disruptive hacking is to try and make the service run arbitrary code on the hacker's behalf. In our PHP example shown above, we allow for SQL injection very easily.

Then main attack vector in our example is given here:
   $name = $_REQUEST['name'];
   $score = $_REQUEST['score'];
   ...      
   $query = "INSERT INTO highscores(name, score, ip) VALUES('$name', '$score', '$ip')";


We retrieve $name and $score from the request URL, and compose a query out of it. If we pass in 'name=Chris' and 'score=32.351', the resulting query would be:
    INSERT INTO highscores(name, score, ip) VALUES('Chris', '32.351', '192.168.0.1')";


Now, assume someone passes the following parameters to the REST service:
    name=x',1,foo); DROP TABLE highscores; --


Our query would then look like this:
    INSERT INTO highscores(name, score, ip) VALUES('x',1,foo); DROP TABLE highscores; --', '32.351', '192.168.0.1')";


As "--" starts a comment in SQL, the query now becomes the following two separate SQL statements:
    INSERT INTO highscores(name, score, ip) VALUES('x',1,foo); 
    DROP TABLE highscores; 


By naively allowing any arguments to be passed to us we allowed random SQL code to be executed on our database. Hackers do not need access to the PHP to come up with this, as automated tools are available to try random fragments until they find one that works.

The simplest solution is to not allow for the script to insert the ';' character. Namely, without that the SQL injection cannot insert a second statement. To avoid further unintentional modifications to the original select statement, we can also check for the single quote character.

To help fight SQL injection, there is a simple PHP trick to sanitize URL parameters. It looks like this:
   $name = mysql_real_escape_string($_REQUEST['name']);
   $score = mysql_real_escape_string($_REQUEST['score']);


I added that to the PHP that is currently used by the published game.

Monitoring

In our sample above, we do not monitor client access, other than storing the IP address. Additional information may be collected and stored, such as host name, referer page, browser agent, timestamp, etc. Basically, you should record anything that may help the FBI solve your case once someone drained your server from all its data.

How to really solve security problems

Basically the advise is: Don't try this at home, kids!

Enterprise organizations should not use adhoc security models, of course. The recommendation is to use something like Tivoli Access Manager to control access to, and monitor, their services.

Furthermore, instead of using PHP, you should really write your services in EGL, compile them to Java, and run them on WebSphere, which is proven to be much more secure for Enterprise applications. Using EGL will also make it easier for you to write the service as you will not have to struggle with the quirky syntax of both PHP and MySQL.

Download

To take a look at the client code yourself, download the following attachment and import it as an existing project into your workspace.

Attachment: escape.zip

2 Comments Permalink

Why Portals?

One of the most inspiring video games I have ever seen is the Aperture Science Enrichment Center, also known as Portal. It bends the law of physics in very interesting patterns:

http://www-949.ibm.com/software/rational/cafe/servlet/JiveServlet/downloadImage/1735/portal.jpg
Image/article source: Wired Magazine

Now, I am kind of tricking you, as this is not the kind of Portal this blog entry will discuss. However, I cannot help thinking of this game whenever someone asks me if you can do "portals" in EGL Rich UI.

So seriously, when people ask me about Portals there are asking two different questions:

  1. How can I write an EGL Rich UI application and use it inside a WebSphere Portal? In essence a Rich UI application is really an HTML file with some JavaScript embedded inside it. That can be produced by a JSR 286 portlet. We may have time to dive deeper into that in a future blog. What I really want to discuss is the next question...

  1. How can I write a Rich UI application that has a main Rich UI handler and that downloads other RUI handlers on demand and make them appear as being a integral component of the larger application. In other words, how can I make a client-side Portal? That question is really the topic of this blog entry.

How to build a client-side Portal?

Our starting point is the GadgetContainer sample that comes with EGL CE and that can be found in the Dojo samples project that EGL CE automatically creates for you:

http://www-949.ibm.com/software/rational/cafe/servlet/JiveServlet/downloadImage/1736/GadgetContainer.jpg
First step is to reduce that sample to something a bit simpler, and then use other applications (preferably done in EGL Rich UI) to occupy the various portlets.

Here is our most reduced version of our Portal:

Handler Portal Type RUIHandler{ initialUI = [ ui ] }    
    ui GadgetContainer { columns = 2, columnWidth = 150, gadgets = [
        new Gadget { title = "Portlet1", column = 1, children = [] },
        new Gadget { title = "Portlet2", column = 2, children = [] },
        new Gadget { title = "Portlet3", column = 1, children = [] },
        new Gadget { title = "Portlet4", column = 2, children = [] }
    ]};
end


This produces a portal with 4 empty portlets:

http://www-949.ibm.com/software/rational/cafe/servlet/JiveServlet/downloadImage/38-1264-1737/portal1.jpg
Now, we will place an iframe into one of the portlets and insert another EGL Rich UI application inside it:

Handler Portal Type RUIHandler{ initialUI = [ ui ] }    
    ui GadgetContainer { columns = 2, columnWidth = 150, gadgets = [
        new Gadget { title = "Portlet1", column = 1, children = [
            new IFrame {
                width = 135, height = 150, src = getURL("Portlet1")
            }
        ] },
        new Gadget { title = "Portlet2", column = 2, children = [] },
        new Gadget { title = "Portlet3", column = 1, children = [] },
        new Gadget { title = "Portlet4", column = 2, children = [] }
    ]};
    
    function getURL(name String in) returns(String)
        pkg String = "com/ibm/egl/demos";
        baseURL String = document.location;
        baseURL = baseURL[1 : strlib.indexOf(baseURL, pkg)-1];
        return (baseURL + pkg + "/" + name + ".html");        
    end
end


We deployed the second application, in this case Portlet1 in the same location as the main handler, so we use the same base URL to compute the URL for the nested handler. The portlet itself works like a standalone application and can be developed normally using EGL CE. Nothing special is required in its implementation:

handler Portlet1 type RUIhandler {initialUI = [ html ] }
    html HTML {
        padding = 2,
        text = 
"This <b>portlet</b> contains <i>just</i> some HTML. That's it.<p>" +


"Visit <a target=_blank href=http://ibm.com>ibm.com</a>."

    };


The portlets can be dragged around, and here is the result after dragging all the empty ones to the second column:

portal2.JPG
Now let's add a more interesting portlet, such as one where two portlets communicate with each other. We will use the EGL InfoBus, which is based on the standard OpenAjax Hub to send messages between the portal and its portlets.

Our second portlet shows an entry field and a button. Here is the source:

handler Portlet2 type RUIhandler {initialUI = [ html, numberField, goButton ] }
	
	html HTML { 
		margin = 7, font = "Arial", text = "Enter a number:"
	};
	numberField TextField { 
		margin = 7, marginTop = 4, onKeyPress ::= checkEnter, text = "2" 
	};
	goButton DojoButton { 
		text = "Go", margin = 7, onClick ::= go 
	};
	subscription any = InfoBus.subscribe("calculator.result", showResult);
  
	function go(e Event in)
		InfoBus.publish("calculator.calculate", numberField.text);
	end

	function checkEnter(e Event in)
		if (e.ch == 13)
			go(e);
		end
	end
	
	function showResult(msg String in, result any in)
		numberField.text = result;
	end

	fix CrossIFrameInfoBusFix{};
end


Notice it is waiting for calculator requests by subscribing to "calculator.result" messages on the InfoBus. Whenever any handler on the current page does a publish with that message key, Portlet 2 will be notified in its "showResult" function. When the user presses Enter or clicks the Go button, a multiplication request is published on the InfoBus again, to be picked up by Portlet 3 (see below).

Our third portlet implements a calculator that multiplies a number with 2. Here is the source:

handler Portlet3 type RUIhandler {initialUI = [ html ] }
    
    html HTML { font = "Arial", text = "Waiting for Portlet 2..." };
        
    subscription any = InfoBus.subscribe("calculator.calculate", calculate);
    
    function calculate(msg String in, data any in)
    	try 
	    	value bigint = data;
	    	result bigint = 2 * value;
	    	html.text = "2 * " + value + " = " + result;
	    	InfoBus.publish("calculator.result", result as String);
	    onException (e AnyException)
	    	html.text = "Oops: '" + e.message + " " + data + "'";
	    end
    end

    fix CrossIFrameInfoBusFix{};

end


Again, it defines a subscription to the InfoBus, and handles them in its "calculate" function. Once a result is known, we publish it on the InfoBus again. When something unexpected happens, such as arithmetic overflow or the user enters an invalid number, we print a message.

Finally, portlet 4 simply shows another URL, in this case http://ibm.com/

handler Portlet4 type RUIhandler {initialUI = [ frame ] }
	
	frame IFrame { width=1000, height=1000,  src = "http://ibm.com" };
  
end


The end result looks like this:

http://www-949.ibm.com/software/rational/cafe/servlet/JiveServlet/downloadImage/38-1264-1738/portal3.jpg
Inter-portlet Communication

You may have noticed declarations to the following field in some of the portlets:

    fix CrossIFrameInfoBusFix{};


What this does is include a fix for InfoBus to allow it to work across iframes. Normally a parent and its nested iframes are completely isolated from each other. What the fix allows for is communication between these two different documents.

What if I don't want a Portal?

The above sample shows how to build a client-side Portal using iframes for the individual portlets and InfoBus for communication. You can use the same technique for other compositions of multiple "modules". One example could be having a main handler with a tab folder. As that is all it contains, it will start up quickly. Then as tabs are opened over time, more and more sub-modules are downloaded on demand (using the above IFrame approach).

The nested handlers can be kept around (as in the Portal), but a different policy could be to do some form of "garbage collection" by unloading the iframes from the document, and recreating them from scratch again when the user likes.

By decomposing modules into separate application level URLs, complexity goes down, individual files get smaller, and things will faster initially and will benefit usage patterns where a limited breath of functionality is actually activated by the end user. Some application have hundreds, even thousands of "screens", and putting them all in one single mega-application makes little sense as during any session only a few dozen may be actually activated.

To try this out in your own workspace, import the attached archive as "General > Existing projects into Workspace". Open the Portal.egl application and load it in the preview.

To try out the non-Portal approach, check out "AppSwitcher.egl".

Attachments: Portal.zip

9 Comments Permalink

EGL CE has recently shipped, and I decided to write a sample that showcases some of the useful features this new and exciting technology offers.

In short, my sample downloads a workitem from jazz.net and shows it in a UI. Of course, my intent is not to replace the Jazz Web UI, rather I highly simplified it into a small sample that shows off aspects found in many rich web applications.

When the JazzUI handler is loaded, it makes a couple of service calls. The following picture shows what components in the UI are created how (it happens to show Darin Swanson, the creator or workitem 33551):

info.jpg

Use of EGL CE Features

My Jazz workitem UI showcases the following EGL CE features:

  • authentication and session management
  • calling asynchronous services (Ajax)
  • decomposition of complexity by composing reusable handlers
  • Dojo Widgets for some of the UI elements
  • browser cookies for storing userid+passwords
  • XML DOM parsing to efficiently deal with large XML files
  • EGL Jobs to manage future work and improve responsiveness
  • an EGL library to implement the singleton pattern (see LoginForm.egl)
  • the EGL InfoBus to decouple producers and consumers of application events
  • the EGL History support to manage the back button and allow for bookmarkability
  • a Service Monitor to trace and debug service calls
  • aggressive compression and optimization when deploying the application

The code is heavily annotated with comments, so I won't show too much sample code in this blog entry and refer simply to the source code that can be found in the attachment.

Deployment and Compression

When I deployed my application in my workspace, I selected the project and used the context menu to deploy it. Then I create a new target project and deployed it on TomCat 5.5.
After it was deployed, I located the generated HTML file in the target project's WebContent folder.

I then used the context menu to run it on TomCat and used Firefox with Firebug to inspect the size of the end-result.

The following picture shows my Dojo files are cached in the browser already (except for jsapi!). Note that the picture shown for the 'creator' is completely random and really comes from bing.com when you search for Bill :-).

firebug.jpg


The 68K for our application HTML file includes the following:

  • all of the EGL runtime,
  • all the EGL widgets I used and that got compiled into JavaScript,
  • all the EGL code I wrote that is compiled into JavaScript,
  • all my hand-written JavaScript that I wrote to implement a few external types,
  • all EGL-specific JavaScript used by the Dojo widgets

As you see in the image above, the dojo widgets themselves come from Google's CDN.

All EGL debugging information has been stripped from the JavaScript, and then we reduced the left-over JavaScript using Dojo ShrinkSafe. This is all done automatically by the EGL CE tooling. Finally, when the application is deployed on TomCat, we tell TomCat to use gzip encoding to further compress the text. All this is automatic without me needing to think about it at all.

Try it for yourself

To try the sample for yourself, follow these instructions:

  • download the attached archive (do not unzip it)
  • in EGL CE, use the menu option File > Import...
  • select Existing Projects into Workspace
  • select the jazz.net.workitem project
  • open EGLSource/ui/JazzUI.egl and select the Preview tab
  • click on the links How's this done? and Source Code

The import dialog should look something like this:

http://www-949.ibm.com/software/rational/cafe/servlet/JiveServlet/downloadImage/38-1261-1732/import.jpg


Attachments

jazzui.zip (make sure to apply the DojoDialog fix: DojoDialog may be incorrectly sized)

0 Comments Permalink