Archive Page 2

09
Dec

Top security threats to Flash/Flex applications and how to avoid them - series on InsideRIA

Just published the 1st article In the series of articles I will be posting on InsideRIA in regards to Flash/Flex security. The intention of these articles is for you to gain knowledge about security in regards to Flash and Flex applications. In each article I will be covering specific security vulnerabilities, showing examples of how an attacker can abuse Flash/Flex applications, and pointing out ways to help prevent these attacks. The purpose of these articles is to increase awareness so you will take security into consideration when building your applications.

flashsecurity

See the first article that talks about Cross-domain Scripting threat here:
http://www.insideria.com/2009/12/top-security-threats-to-flashf.html

01
Dec

RIABeardOff - charity event for members of the RIA community

In case you didn’t hear, Chuck Freedman started an amazing and generous event called RIA Beard Off. The event is a charity event for members of the RIA community to grow beards and raise money for Marine Toys for Tots Foundation.

I decided to help out and I stopped shaving last Monday. We are looking to reach at least $2,000, but hopefully more, so to entice you to donate I decided to give away prizes.

This is what you need to do: make a donation to #RIABeardoff and mention my name when you make the donation and two lucky people will win the book I co-authored click here to view. The book will be shipped to your preferred address.

In addition to the two books, I am also going to give away a 3rd prize, which is going to be a surprise. Make a donation now! http://firstgiving.com/riabeardoff

    TIMELINE:

  • 11/23 - Monday - Bearder registration starts
  • 11/27 - Friday - Bearder registration ends, Open donations start!
  • 11/30 - Monday - First of many, frequent beader snapshots posted!
  • 12/14 - Monday - Last Bearder update posted!
  • 12/15 - Tuesday - Bearding ends. Bearders can shave & move on with their lives.

Here is the list of the generous Flash developers that agreed to stop shaving:

LordAlex Leon
Stacey Mulcahy ( BitchWhoCodes)
Bernie & Erikka Perkins
Mims H. Wright
Scott Janousek
Chris Allen
Curt Staubach (@curtStaubach)
Paul Gregoire (@mondain)
@BenStucki
Todd Anderson (@bustardcelly)
Robert Hall (@rhall)
Joseph Labrecque (@JosephLabrecque)
Jesse Freeman (@theflashbum)
Kevin Suttle (@kevinSuttle)
Brian Connatser (@connatser)
Elad Elrom (@EladElrom)
Chuck Freedman (@chuckstar)

I want to point out that some have actually shaved beards that were years old, like Robert Hall and Scott Janousek.

This is a great cause and every donation counts, so please donate!

01
Dec

Test Driven Development using Flash Builder 4 beta and FlexUnit on Devnet

There has been a great deal of interest in TDD (and unit testing in general) recently, because it leads to applications that are easier to scale and maintain and less prone to errors. I just published an article on Devnet that covered unit testing and Test Driven Development using Flash Builder 4 and FlexUnit, including some of the new features in the FlexUnit 4 framework.

Check it out here:
http://www.adobe.com/devnet/flex/articles/flashbuilder4_tdd_02.html

05
Nov

Object pooling in Flex / ActionSctipt

Back in March of 2008 I published an object pooling utility class that allow you to place objects into a collection and use them when needed. That class came handy on a recent project where I had to use few instances of DataGrid, which is known to be one of the most expensive components in Flex which many believe should be avoided at all cost. The app I built had to create instances of data grid during runtime and than remove them from the display object. Object pooling is a great design pattern to handle these cases where you need to use the same object over again and again.

The reason is that object creation takes much resources and should be avoided in cases where you need the object often. I looked over the class and although I wrote it in 2008 it is still in good shape. One thing I noticed is that it was using an ArrayCollection. I have upgraded the class to use a Dictionary instead of ArrayCollection using a HashCollection utility class I developed which is using the Dictionary with a weak reference.

Download and look at the ReusablePool utility class:
http://code.google.com/p/eladlib/source/browse/trunk/EladLibFlex/src/com/elad/framework/objectpoolmanager/ReusablePool.as

To implement the class and show you an example I will be using an application that uses three objects: video, image and a list component. When you add the element to the application and then remove it and keep adding these objects agains and again you put a memory expense and you can see a small hickup. However, when you are using Object pool you keep the memory usage low since the objects are cached and you save on the object instantiation cost. As you can see the application is running smoothly while adding and removing objects from the display.

The complete implementation code can be seen below:


<s:Application xmlns:fx="http://ns.adobe.com/mxml/2009"
			   xmlns:s="library://ns.adobe.com/flex/spark"
			   xmlns:mx="library://ns.adobe.com/flex/halo"
			   minWidth="1024" minHeight="768"
			   creationComplete="setObjects()"
			   viewSourceURL="srcview/index.html">	

     <fx:Script>
          <![CDATA[
               import com.elad.framework.objectpoolmanager.Reusable;
               import com.elad.framework.objectpoolmanager.ReusablePool;

               import mx.collections.ArrayCollection;
               import mx.containers.Canvas;
               import mx.controls.Image;
               import mx.controls.VideoDisplay;
               import mx.core.UIComponent;

               import net.hires.debug.Stats;

               private var reusablePool:ReusablePool = ReusablePool.getInstance();
               private var canvas:Canvas = new Canvas;

               private function setObjects():void
               {
                    // adding stats
                    component.addChild( new Stats() );
                    addElement(component);                         

                    // adding the object to the collection
                    reusablePool.setReusable( new Reusable(createUI(), "FlexImage") );

                    // adding an array object
                    reusablePool.setReusable( new Reusable(createArray(), "arrayList") );

                    // adding video UI object
                    reusablePool.setReusable( new Reusable(createVideoUI(), "videoUI") );                                                            

                    this.addElement(canvas);
               }

               private function useUIObject(name:String):void
               {
                    // getting the collection
                    var reusable:Reusable = reusablePool.acquireReusable(name);
                    var component:UIComponent = reusable.object as UIComponent;

                    // use the object
                    canvas.removeAllChildren();
                    canvas.addElement(component);

                    // return collection back to the pool of objects
                    reusablePool.releaseReusable(reusable);
               }

               private function useArrayObject():void
               {
                    // getting the collection
                    var reusable:Reusable = reusablePool.acquireReusable("arrayList");
                    var dp:ArrayCollection = reusable.object as ArrayCollection;

                    list.dataProvider = dp;

                    // return collection back to the pool of objects
                    reusablePool.releaseReusable(reusable);
               }

               private function noCacheArrayObject():void
               {
                    var dp:ArrayCollection = createArray();
                    list.dataProvider = dp;
               }

               private function noCacheUIObject():void
               {
                    canvas.removeAllChildren();
                    canvas.addElement(createUI());
               }

               private function noCacheVideoUIObject():void
               {
                    canvas.removeAllChildren();
                    canvas.addElement(createVideoUI());
               }     

               private function createUI():UIComponent
               {
                    var image : Image = new Image();
                    image.source = "http://blog.digitalbackcountry.com/wp-content/uploads/flash_builder_logo.png";
                    image.width = 400;
                    image.height = 300;
                    image.x=10;
                    image.y=300;                    

                    return image;
               }

               private function createVideoUI():UIComponent
               {
                    var videoDisplay:VideoDisplay = new VideoDisplay();
                    videoDisplay.source = "http://kakonacl.dip.jp/PlayerTry/TestMovies/FLV/FLV4/Flash.flv";
                    videoDisplay.x = 10;
                    videoDisplay.y = 300;
                    videoDisplay.width = 300;
                    videoDisplay.height = 300;

                    return videoDisplay;
               }

               private function createArray():ArrayCollection
               {
                    var array:ArrayCollection = new ArrayCollection();

                    for (var i:int=0; i<10000; i++)
                    {
                         array.addItem({label: i});
                    }

                    return array;
               }               

          ]]>
     </fx:Script>

     <s:Label x="10" y="10"
                text="These examples shows memory usage with using the object pooling collection and without it."
                fontWeight="bold" height="33"/>

     <s:Label x="10" y="61"
                text="Cached Object Pooling" width="200" fontWeight="bold"/>

     <s:Button x="10" y="87"
                 label="UIobject"
                 click="useUIObject('FlexImage');" width="200"/>

     <s:Button x="10" y="117"
                 label="array"
                 click="useArrayObject();" width="200"/>                  

     <s:Button x="10" y="147"
                 label="Video UI"
                 click="useUIObject('videoUI');" width="200"/>

     <s:List id="list"
               x="325" y="79"
               width="126" height="200" />

     <s:Label x="10" y="178"
                text="Regular objects" width="200" fontWeight="bold"/>

     <s:Button x="10" y="202"
                 label="UIobject"
                 click="noCacheUIObject();" width="200"/>

     <s:Button x="10" y="232"
                 label="Array"
                 click="noCacheArrayObject()" width="200"/>          

     <s:Button x="10" y="262"
                 label="Video UI"
                 click="noCacheVideoUIObject()" width="200"/>

     <mx:UIComponent id="component" x="237" y="83" width="70" height="100"/>     

</s:Application>

screen-shot-2009-11-05-at-104133-pm

To measure the memory usage you can use the small statistic class that was developed by Mr.doob. Additionally, you can take a look at the Eclipse Profiler. In first scenario where I add an element to the application and remove it, the profiler shows as if we have a memory leak since the usage peaked to the “red” lines. I am not saying this is a memory leak, but I am pointing out that the memory usage is high since the objects were removed but haven’t been picked up by the GC yet. As you know using the removeAllChildren() remove the object from the component but is not necessarily ensure the GC will come and release the memory right away. See Profiler screen shot below:

screen-shot-2009-11-05-at-105952-pm

In the second scenario, the objects are cached and I am not putting any memory constrains on my application. See figure below.

screen-shot-2009-11-05-at-110137-pm

The utility class can be limited to the amount of objects you want to store, plus you can tie the class to a logic that will clear all the objects when needed.

Let’s take a look at the code to create an instance of the utility class and add an object.

The utility class is a singleton so we can use the same object through the life cycle of the application.


private var reusablePool:ReusablePool = ReusablePool.getInstance();

To add an object you create a Reusable object that holds the object and the name of the object:


// adding the object to the collection
reusablePool.setReusable( new Reusable(createUI(), "FlexImage") );

When you are ready to retrieve the object use the acquireReusable method, which will remove the object from the object collection:


// getting the collection
var reusable:Reusable = reusablePool.acquireReusable(name);
var component:UIComponent = reusable.object as UIComponent;

When you are done and want to send the object back to the object pool collection use:


reusablePool.releaseReusable(reusable);

Cheers :)

05
Nov

Flex (Flash) Camp Wall Street conference in two weeks

I will be speaking this year at the Flex (Flash) Camp Wall Street conference. Although the recession is not over yet, the second edition of the prestige Flex (Flash) Camp Wall Street conference will be held in New York again. The event will be on November 16-17, 2009 and has a recession price of $49!

wallst

I am very excited for the opportunity to participate at the conference.
Speaker includes James Ward, Yakov Fain, Jeff Tapper, Jeffry Houser, Wade Arnold, Christian Saylor, Brian O’Connor, Daniel Holth and Adam Flater.

For more details goto:
http://www.flexcampwallstreet.com

05
Nov

Published two great articles on Flash & Flex Developer’s Magazine (FFD) for the months of November/December

I have two articles published on this month’s addition of Flash & Flex Developer’s Magazine (FFD) for the months of November/December.

Article 1: Building video players for mobile devices
Video is a ubiquitous and key element in compelling web content. It is relied upon by blog, news, music, web TV, social media, amateur, and movie production sites.

Article 2: Designer-Developer Workflow Using Flash Catalyst
In the last few years, designer-developer workflow in conjunction with Rich Internet Applications (RIA) has created debate and uncertainty in the Flash community about how designers and developers are going to work together. Let’s look at how Adobe’s Flash Catalyst (FC) can be used to solve this debate.

Feel free to download the articles from:
http://ffdmag-en.edit.software.alfa.javatech.com.pl/magazine/950-getting-started-with-adobe-open-source-media-framework

Enjoy :)

07
Oct

AIR 2.0 Enhancements Complete Overview

During MAX 2009, Adobe released public information about AIR 2.0 and added new capabilities that better tie with the operation systems which gives your application more control while increasing performance. Below is an application I created that will help you overview the new capabilities. To use the application, click each main category and browse to see the capability.

This small application complimentary to the InsideRIA article I published:
http://www.insideria.com/2009/10/air-2-enhancements-complete-ov.html

26
Sep

Just announced: New York City will be hosting a 3 day conference in May 2010!

FlashAndTheCity (http://flashandthecity.com) is going to be a 3-day “out of the box” Flash conference focusing on RIA technologies. The purpose of the event is to learn, share your knowledge and network with your peers from the Big Apple and other great cities.

The idea of this conference is to bring Flash professionals together and talk about Adobe’s latest technologies such as Flash, Flex, AIR, LCDS and ColdFusion. Starting with the setting, the event will take place in a different and dynamic environment called “3LD Art Technology Center” located in downtown Manhattan. Come evening, the event will then continue with interesting networking opportunities at venues throughout the City! This exciting event will not only be educational, but fun and offering an invaluable opportunity to connect with new and existing people, some of whom you may have only heard their names from working in the field.

If you are a developer, designer, employer, entrepreneur or just interested in learning more about Flash and especially the New York City Flash community, you must check out FlashAndTheCity! Don’t forget to book your ticket early in order to get the early bird pricing. The conference will include breakfast and lunch and we will have discounted prices at a local hotel for those who need accommodations. If you have any questions, comments or any other ideas, please feel free to contact us! We are very open minded and would like to hear from you! Thanks very much, and looking forward to seeing you all at FlashAndTheCity!

FlashAndTheCity Event

12
Sep

AIR SQLite Manager API updated and allow using multiple tables and transactions

Back in January ‘09 I posted an API that makes working with an AIR application that works with an SQLite database and has many SQL commands and multiple tables simple. I have received feedback from developers that are using the API and have found it helpful. I kept getting requests to update the API to support multiple tables.

You need this API because working with an application that has many SQL commands and multiple tables can become challenging.

  • These commands may be initialized from different classes, and
  • we may want to keep the database connection open and avoid duplicating code.

SQLiteManager does just that and allows you to set the database settings and than access the manager from anywhere in your application. It makes the process simpler and integrates very well with micro architecture frameworks.

I finally got around to updating the API, and it now support the following:

  • Password encryption
  • Multiple tables
  • Common SQL commands
  • Transactions and rollback option
  • Better handling of results
  • Improved and optimized code

Let’s look at the implementation code. The application will hold two tables, one for users and one for orders, and we will be able to insert and read information as well as keep track of transactions and rollback in case there are errors or for any other reasons.

AIR SQLite Manager

AIR SQLite Manager

The first step is to set constants with all the names of all the user gesture SQL we will be running. This way we can track requests and use the same result handler for all of our SQL requests.


			// SQL user gestures
			private const READ_ALL_USERS_INFO:String = "readAllUsersInfo";
			private const INSERT_USER_INFO:String = "insertUserInfo";
			private const INSERT_ORDER_INFO:String = "insertOrderInfo";
			private const READ_ALL_ORDERS_INFO:String = "readAllOrdersInfo";

			// holds the database manager singelton instance
			private var database:SQLiteManager = SQLiteManager.getInstance();

The creation CompleteHandler method will be called once the application has completed initialization. We will be setting the database information and starting the connection. Notice that you need to set the array Vector with all of the tables you will have in your application. The way it is working is in case the application doesn’t have the tables created already. They will be generated automatically for the user so you need to specifiy the SQL command to create these tables and the name of each table. The names can be anything; just use unique names.


			// start database
			protected function creationCompleteHandler():void
			{
				var password:String = null; // leave as null to have the database unsecure or set a password for secure connection. Example: "Pa55word";
				var sqliteTables:Vector.<SqliteTableVO> = new Vector.<SqliteTableVO>;

				sqliteTables[0] = new SqliteTableVO( "Users", "CREATE TABLE Users(UserId INTEGER PRIMARY KEY, UserName VARCHAR(150)); " );
				sqliteTables[1] = new SqliteTableVO( "Orders", "CREATE TABLE Orders(OrderId INTEGER PRIMARY KEY, UserId VARCHAR(150), OrderTotal DOUBLE);" );

				addListeners();

				database.start( "Users.sql3", sqliteTables, password, sqliteTables[0].tableName );
			}

Notice that in the previous method we had a call to set the listeners we will be using. Take a look at the events we will be listening to:


			// Set all the listeners
			private function addListeners():void
			{
				database.addEventListener(DatabaseSuccessEvent.DATABASE_CONNECTED_SUCCESSFULLY, function(event:DatabaseSuccessEvent):void
				{
					event.currentTarget.removeEventListener(event.type, arguments.callee);
					database.executeSelectAllCommand( database.sqliteTables[0].tableName, READ_ALL_USERS_INFO );
				});				

				database.addEventListener(DatabaseSuccessEvent.COMMAND_EXEC_SUCCESSFULLY, onSelectResult);

				database.addEventListener(DatabaseSuccessEvent.DATABASE_READY, function(event:DatabaseSuccessEvent):void {
					event.currentTarget.removeEventListener(event.type, arguments.callee);
					trace("database ready!");
				} );
				database.addEventListener(DatabaseFailEvent.COMMAND_EXEC_FAILED, function(event:DatabaseFailEvent):void {
					trace("SQL execution fail: "+event.errorMessage);
				});
				database.addEventListener(DatabaseFailEvent.DATABASE_FAIL, function(event:DatabaseFailEvent):void {
					var message:String = "Database fail: "+event.errorMessage;

					if (event.isRolledBack)
					{
						message += "\nTransaction was rolled back";
					}

					Alert.show(message);
				});
				database.addEventListener(DatabaseSuccessEvent.CREATING_DATABASE, function(event:DatabaseSuccessEvent):void {
					event.currentTarget.removeEventListener(event.type, arguments.callee);
					trace(event.message);
				});
			}

We need two methods to generate the insert SQL command for the two tables we have and make the request.


			protected function insertDataClickHandler(event:MouseEvent):void
			{
				var SQLStatementText:String = "INSERT INTO Users VALUES('" + userId.text + "','" + userName.text + "');'";
				database.executeCustomCommand(SQLStatementText, INSERT_USER_INFO);
			}

			protected function insertOrderClickHandler(event:MouseEvent):void
			{
				var SQLStatementText:String = "INSERT INTO Orders VALUES('" + ordersDataGrid.dataProvider.length+1 + "','" + IdComboBox.selectedItem.label + "','" + orderTotal.text + "');'";
				database.executeCustomCommand(SQLStatementText, INSERT_ORDER_INFO);
			}

Once SQL commands are requested all the results are processed in this implementation with the same handler called onSelectResult. Notice that each request had a unique name so we are able to match the request to the result and update the view as needed.


			// handles results
			private function onSelectResult(event:StatementCompleteEvent):void
			{
				var result:Array = event.results.data;
				var rowsAffected:int = event.results.rowsAffected;  

				switch (event.userGestureName)
				{
					case null:
						break;
					case READ_ALL_USERS_INFO:

						if (result == null)
							break;

						var len:int = result.length;
						var dp:ArrayCollection = new ArrayCollection();

						for (var i:int; i<len; i++)
						{
							dp.addItem( { label: result[i].UserId, UserName: result[i].UserName } );

						}

						IdComboBox.dataProvider =  usersDataGrid.dataProvider = dp;	

						database.executeSelectAllCommand( this.database.sqliteTables[1].tableName, READ_ALL_ORDERS_INFO );

						break;
					case INSERT_USER_INFO:
						database.executeSelectAllCommand( this.database.sqliteTables[0].tableName, READ_ALL_USERS_INFO );
						break;
					case INSERT_ORDER_INFO:
						database.executeSelectAllCommand( this.database.sqliteTables[1].tableName, READ_ALL_ORDERS_INFO );
						break;
					case READ_ALL_ORDERS_INFO:

						if (result == null)
							break;

						len = result.length;
						dp = new ArrayCollection();

						for (i = 0; i<len; i++)
						{
							dp.addItem( { OrderId: result[i].OrderId, OrderTotal: result[i].OrderTotal, UserId: result[i].UserId } );

						}

						ordersDataGrid.dataProvider = dp;	

						break;
				}
			}

The last part is the view. We have two forms to submit data and data grids to show the results.


	<!-- Users Form -->
	<mx:Form width="221" y="5">
		<mx:FormItem label="User ID:">
			<s:TextInput id="userId" width="85"/>
		</mx:FormItem>
		<mx:FormItem label="User Name:">
			<s:TextInput id="userName" width="85"/>
		</mx:FormItem>
		<mx:FormItem>
			<s:Button label="Insert User"
					  click="insertDataClickHandler(event)"/>
		</mx:FormItem>
	</mx:Form>

	<!-- Orders Form -->
	<mx:Form x="239" y="5"
			 width="221">
		<mx:FormItem label="User Id">
			<mx:ComboBox id="IdComboBox" editable="true" width="85"></mx:ComboBox>
		</mx:FormItem>
		<mx:FormItem label="Order Total:">
			<s:TextInput id="orderTotal" width="85"/>
		</mx:FormItem>
		<mx:FormItem>
			<s:Button label="Insert Order"
					  click="insertOrderClickHandler(event)"/>
		</mx:FormItem>
	</mx:Form>			

	<!-- Results -->
	<mx:DataGrid id="usersDataGrid" x="16" y="123" height="145">
		<mx:columns>
			<mx:DataGridColumn headerText="User Id" dataField="label"/>
			<mx:DataGridColumn headerText="User Name" dataField="UserName"/>
		</mx:columns>
	</mx:DataGrid>
	<mx:DataGrid id="ordersDataGrid" x="231" y="123" width="231" height="145">
		<mx:columns>
			<mx:DataGridColumn headerText="Order Id" dataField="OrderId"/>
			<mx:DataGridColumn headerText="User Id" dataField="UserId"/>
			<mx:DataGridColumn headerText="Order Total" dataField="OrderTotal"/>
		</mx:columns>
	</mx:DataGrid>

To handle the transactions we have a check box and a button to roll back in case we need to roll back. There are a few reasons to roll back. For instance, a commit of a few SQL commands that depend on each other failed. For example, in this demo app we have a user and an order, and in case the user couldn’t be created we may want to roll back and remove the user’s order.


	<!-- Transactions -->
	<s:Button id="rollbackBtn"
			  x="119" y="283"
			  label="Rollback"
			  enabled="false"
			  click="database.rollbackTransaction(new Responder(function(event:SQLEvent):void
			  {
			  Alert.show( 'Total number of changes being rolled back: ' + database.connection.totalChanges );
			  }));
			  database.executeSelectAllCommand( this.database.sqliteTables[0].tableName, READ_ALL_USERS_INFO );
			  database.executeSelectAllCommand( this.database.sqliteTables[1].tableName, READ_ALL_ORDERS_INFO );
			  isTransactionCheckBox.selected=false;"/>

	<s:CheckBox id="isTransactionCheckBox" x="18" y="284"
				label="isTransaction"
				selected="false"
				change="if ( isTransactionCheckBox.selected )
				{
					database.beginTransaction();
					rollbackBtn.enabled = true;
					setSavePointBtn.enabled = true;
					releaseSavePointBtn.enabled = true;
					rollbackToSavePoint.enabled = true;
				}
				else
				{
					database.stopTransactionAndCommit();
					rollbackBtn.enabled = false;
					setSavePointBtn.enabled = false;
					releaseSavePointBtn.enabled = false;
					rollbackToSavePoint.enabled = false;
				}"
				/>	

You can download and use the SWC from here (use eladlibair_1.1.swc 37kb):
http://eladlib.googlecode.com/files/SWCs.zip

Or download the source code of the API from here:
http://code.google.com/p/eladlib/source/browse/#svn/trunk/EladLibAIR/src/com/elad/framework/sqlite

The implementation example is here:
http://code.google.com/p/eladlib/source/browse/trunk/EladLibAIR/src/SqliteManager.mxml

01
Sep

Convert ByteArray into an image and NetStream limitation

Flash Player 10 and AIR allow loading files from your local system as well as saving files. Once the files are loaded you have access to the ByteArray.

Convert ByteArray into an image

You can easily convert the ByteArray into an image:


var loader:Loader = new Loader();
loader.contentLoaderInfo.addEventListener(Event.COMPLETE, function(event:Event):void
{
      event.currentTarget.removeEventListener(event.type, arguments.callee);
      image.source=loader.content;
});

loader.loadBytes(event.file.fileContent);

Play ByteArray

Unfortunately, you cannot set the bytes of a video stream through the NetStream Object. What you can do is write the URLStream’s bytes to a local file, and then pass that file to the NetStream object. You can do a workaround such as writing out the URLStream’s bytes as they come in with the help of the “append” method.

What it means is that you cannot play ByteArray in AIR or Flex Application. I know that that feature is on the Adobe’s team list but until they adjust the code you will have to find a workaround.