Sunday, October 12, 2008

JumpStart - version 0.5a3

New version of JumpStart available.
Among some minor fixes here are the new features:
More thumbs
Depending on the your resolution now you can have more thumbs on the page:

Using options menu you can now set number of thumbs you want. If you choose to show smaller thumbs you can fit even more of the thumbs on the screen. I managed to fit 24, however for the screen shot I could not think of more interesting sites so only 13 on this picture.
Note: Thumbs are refreshed after Firefox starts (30 seconds delay), all thumbs are refreshed at the same time so you might experience some slow down if you choose lots of thumbs. More intelligent refresh is scheduled for the next release, hopefully next weekend.

Pin a thumb
Now you can pin a thumb. Pinned thumbs will appear always and will appear at the beginning of the list.


When you hover over a thumb it will show two icons, one like X and one resembling pin. Click on the pin icon to pin the thumb, pin icon will turn red, another click on the pin icon to unpin it.
Note: The pinned items will appear at the beginning of the list on the next Firefox start (will improve that in one of the next versions)

Exclude site from being shown as thumb
You can now exclude sites from appearing as thumbs if you wish. Similarly as with pin, hover over thumb and click on the X icon to mark it for exclusion, click again to un-mark it.


JumpStart removed from the history and closed tabs
Now when you close a tab showing JumpStart it will not appear in the list of closed tabs. Also, it will be removed from history once you navigate off the tab showing JumpStart.

Showing JumpStart on browser start

Once you start browser, if it would normally show blank page or home page (if tabs are not restored), the start page will be replaced by JumpStart. This can be turned off from preferences.
Toolbar button to show JumpStart
There is a convenient toolbar button to show JumpStart in current tab. It is immediately following URL bar. It can be removed or turned back on through preferences. Or it's position can be changed by customizing toolbar.
Menu item for setting options
There is a menu option now for setting JumpStart preferences. Mind though, preferences window is really ugly. I will be working on general apperience of the extension for the next release, I promise.




As you can see, there are two tabs in the preferences: General and Thumbs. In the general section options are:
- Show On New Tab : should JumpStart be shown when you open a new tab
- Show On Startup : should JumpStart be shown immediately when you start the browser
- Show Toolbar Button : show JumpStart toolbar button
Thumbs section is more interesting, it shows:
- Zoom Thumbs : if switched on thumbs will be shown a bit bigger on hover
- Show Small : there are two sizes of thumbs now, if you choose small then you can fit even more of them on the screen
- Numer of Thumbs per Line : how many thumbs you wish to appear on one line
- Number of Thumb Lines : how many thumb lines should be there
All the other things on the panel can be ignored, they are just there to add to ugliness and are not functional (well total number of thumbs is interesting for information purposes)

Plan for the next version is to improve refreshing of thumbs, improve search, and improve overall appearance of the extension. I'll fix some functionality, tighten it up in general.

As always, your feedback is much appreciated. I'll answer all the questions/suggestions as soon as possible.

*** New Screenshot ***
Almost like Chrome
Yes, that's Firefox.

Monday, September 29, 2008

JumpStart - plan for next version

* Updated - Sorry about the delay. I have updated the plan for the next version. I'll try to include some screen shots today too.

Next version of JumpStart is planned for 5th 12th October. Here is the list of things I would like to do until then, and some preview of things already implemented. (I'll add screen shots as I finish each of these)

Showing JumpStart on browser start - DONE
Something that makes sense - if there is only one page and is either blank or homepage JumpStart is shown. This can be overridden through options dialog.
Button to show JumpStart on toolbar - DONE
Sometimes it is useful to show the content without opening new tab.
Menu item for setting options - DONE
In tools menu now there is menu option to show options dialog for the extension.
More thumbs - DONE
Thumbs can now fill the whole useful area of window, there are two sizes to choose from - small and large thumbs. Depending on resolution the number of thumbs will be offered to choose from.
Pin thumb - DONE
Pin your favorite thumbs so they will always appear at the same position
Exclude site from being shown as thumb - DONE
By one click remove site from the list of shown thumbs
JumpStart removed from the history - IN PROGRESS DONE
It won't show up on back button pressed, nor at closed items.
Refresh thumbs - PLANNED NEXT VERSION
At present thumbs are being refreshed after restart of Firefox. New refresh strategies are there now: on some interval, then all at the same time or one-by-one.
Improved search - NEXT VERSION
Search is currently searching only through the history, I want to make it work for all installed search plug-ins. In future I want to improve the whole feature. I'm still thinking about it.
New bookmark features - NEXT VERSION
Google bookmarks?

This all is something I will be working, it might not get into the 0.5a3 version but it will get into the final release pretty soon.

And I promise I'll work on the logo :) My wife absolutely hate it, and I didn't get much better feedback from others. I plan to deliver final 0.5 version at the end of October so by then I should change it.

As always, your feedback is critical. There is a Google group setup so please start a new discussion with ideas, critics or praise.

Monday, September 22, 2008

JumpStart - version 0.5a2

New version of JumpStart is available.
https://addons.mozilla.org/en-US/firefox/addon/8914. If the site does not show New Tab JumpStart 0.5a2 in the name of the add-on then check out: https://addons.mozilla.org/en-US/firefox/addons/versions/8914; sometimes it takes them some time to refresh it, but oddly it shows up in the list of all versions.
Some new stuff there, some fixes too, here is the list off top of my head:
Thumbnails are now clickable.
Delayed thumbnail update - refresh of the thumbnails is initiated about 1 minute after
the browser is started.
Recently closed list fixed and improved, now it shows closed tabs as they happen.
Added some basic preferences
Gmail support - there were issues with Gmail in previous version so it was filtered out, now is showing OK in thumbnails
Support for Firefox 3.1a1
Fixed problem with new window opened from JavaScript
Fixed unicode problem with extension's cache file
Thumbnail zoom - new feature, see screen shots - it has to be turned on from the add-on options.
Lots of other minor tweaks and improved quality.

I created discussion group for the extension where you can post your feedbacks, suggestions, report issues, they are all very much appreciated. The thread regarding the current version is there too so please let me know how do you find this version.
Next version is to be expected in two weeks time, I'll be blogging on what's planned for it soon, so stay tuned.

And now screen shots:



This looks similar to the previous version. But here is some noticeable difference:



It is a kind of zoom, so the thumbnail is better seen. It is turned off by default, you can turn it on by going to menu: Tools -> Add-ons, click Options button of the New Tab JumpStart add-on, check Zoom Thumbs option on the dialog and press OK. Simple :) Here is the previous sentence but in picture:



I'll probably make it by default turned on from the next version unless I get really bad feedback :) This is a step forward to make additional changes in future - more thumbs, more options, etc.

Wednesday, September 17, 2008

JumpStart your web experience

New add-on available for Firefox - New Tab JumpStart. When you open a new tab you will get immediate access to your most frequently used sites, bookmarks, closed tabs, history search. Similar to Google's Chrome new tab feature.
Here are some screen shots:





Features are:
- Preview of your most frequently accessed sites (it has delayed load and thumbnails caching)
- Latest bookmarks
- List of recently closed tabs
- Search your history
All this on opening empty tab.

This is still fresh and thus still needs you to login to add-on site to download it. It is work in progress and expect improvements soon. As soon as I have code in good enough shape I will publish it on Codeplex.

Of course all feedback and comments welcome.


* UPDATE *
I have just got feedback that with Tab Mix Plus add-on the new tab is not showing. Tab Mix Plus is overriding some browser events that JumpStart is using. So if you wish both add-ons to peacefully coexist setup Tab Mix Plus to open: chrome://jumpstart/content/tabView.xul on new tab. Go to Tools -> Tab Mix Plus Options, here's the screen shot of what to do:


After that JumpStart works as it should.

Saturday, August 30, 2008

Ajax.NET: Disable buttons until postback finishes

When developing Web Forms in ASP.NET it is usually the case that we have multiple postbacks on a page. When there are Ajax calls as well it can easily happen that we can have multiple outstanding postbacks - e.g. postback by dropdown list immediately followed by a button click, or simply multiple button clicks. Due to various reasons those calls can end up in different sequence on the server (e.g. network latency). For some we might not care, but for some the sequence might be important.
What I'm showing here is a simple client solution to the problem. It will simply disable buttons while the postback ends thus preventing user to click on them until the postback had finished.


<script language="javascript" type="text/javascript">
//on the page submit we want to disable buttons until the call is finished
// and then reenable them
(function() {
//add on the page load event that will register our scripts
//for all significant events
Sys.Application.add_load(setupButtonDisablers);

function setupButtonDisablers() {
//subscribe to on page load and submit events
//on page load we will enable buttons
Sys.WebForms.PageRequestManager.getInstance().add_pageLoaded(onPageLoad);
//on page submit we will disable them
Sys.WebForms.PageRequestManager.getInstance().add_beginRequest(onSubmit);
//remove setup code so it will never be called again
Sys.Application.remove_load(setupButtonDisablers);
}

//on page load - enable all the relevant buttons
function onPageLoad() {
findAndEnable('<%= MyButton1.ClientId %>');
findAndEnable('<%= MyButton2.ClientId %>');
}

//on page submit - disable all the relevant buttons
function onSubmit() {
findAndDisable('<%= MyButton1.ClientId %>');
findAndDisable('<%= MyButton2.ClientId %>');
}

function findAndDisable(id) {
findAndSetDisabledProperty(id, true);
}

function findAndEnable(id) {
findAndSetDisabledProperty(id, false);
}

//finds and sets disabled property of a searched control
function findAndSetDisabledProperty(id, value) {
var control = $get(id);
if (control) {
control.disabled = value;
}
}
})();
</script>


This is fairly simple code, without comments it would be really short. What it does is subscribing to page submit and load events and is disabling and enabling buttons respectively. Just put it somewhere on a part of the page that will be loaded first time the page loads.
You can make this more complicated if you need to do something specific depending on which element caused the postback by using different signature for onSubmit function. Here is documentation for the beginRequest event. Basically it will accept sender and args and you can use args.get_postBackElement() for example and make decisions what to do with your page elements then - hide them, disable them, animate them, whatever.

And at the end, remember that despite all the effort done on the client side you will always have to handle any eventuality on the server. Always remember, any client input is evil and it has to be validated - in this case postback sequence.

Thursday, August 28, 2008

XML Schema for Install.rdf available on Codeplex

I just published the first version of the XML Schema for the Install.rdf file (Mozilla Add on Install Manifest file) on Codeplex. More information on the file is here: Install.rdf on Mozilla Developer Center. The schemes are published under MPL 1.1 license.
Add on Manager enabled XUL applications (Firefox, Mozilla, Songbird, Flock, ...) are using install.rdf file to get description of the add on being installed. With this schemas you can get better support in your favourite IDE. Here are some screenshots from my Visual Studio:
You can see more screenshots on the project's wiki.
Most of the elements have regex validation, and wherever I could I added some enumeration support as seen on the picture above. However there might be errors so if you find any please report them on project's issue tracking.
All suggestions are welcome. I added discussion thread just for that purpose. If you know how to setup your favourite IDE to use this files add them there and I will update wiki accordingly. I have already added instructions for Visual Studio.
In future I plan to add more features - wizards, possibly some kind of management tools, etc. However this is in probably distant future since I don't have much time. What you could expect in the near future is XUL schema under MPL license. I'm half way there so I hope I'll publish it in next couple of weeks.

Friday, July 18, 2008

Extend JsMock to Support Custom Argument Matcher

I needed some custom argument matching in my mocks today. I am using JSMock for JavaScript mocking and I find it a bit limited when it comes to argument matching. It mostly satisfies my needs but occasionally I need it to be a bit more flexible, generally speaking. Now, what I introduced is not something that xMock frameworks usually have but JavaScript is a dynamic language and some things are simply different compared to "static" languages (OK, I admit, I've used only NMock so far, but I can't be much wrong here).

To use JSMock you need only jsmock.js. The only change required in the original code is in __delegateMatching method of the ArgumentMatcher, changes are marked red:




__delegateMatching: function(expected, actual) {
if( expected == null ) {
return this.__match( expected, actual );
}
else if( expected.constructor == TypeOf ) {
return this.__match(expected.type, actual.constructor);
}
else if( expected.constructor == Array ) {
return this.__matchArrays(expected, actual);
}
else if( expected.constructor == CustomMatch){
if(!expected.match){
throw new Error("Custom matcher not available");
}
return expected.match(expected.object, actual);
}
else {
return this.__match(expected, actual);
}
}


So that was just one added if clause. All I am saying there is if the expected argument is of CustomMatch then use its custom matcher method instead of original matching logic. There is of course the implementation of CustomMatch that is required:




function CustomMatch(object){
this.object = object;
this.Using = function(customMatcher){
if(typeof(customMatcher) != 'function'){
throw new Error("Can only take constructors");
}
this.match = customMatcher;
return this;
}
}

CustomMatch.Match = function(object){
return new CustomMatch(object);
}


Usage is simple, as one of the expected arguments use something like the following construct:
CustomMatch.Match(expectedObject).Using(customMatchFunction)
Where expectedObject is obviously object that you want to match to the actual argument and the customMatchFunction is the function to use for custom matching, it expects two arguments and returns boolean. So usage might look something like this:


var expectedObject = { fieldOne : 1, fieldTwo : 2 };
var customMatchFunction(expected, actual){
return expected.fieldOne == actual.fieldOne && expected.fieldTwo == actual.fieldTwo;
};

someMock.expects().someMethod(CustomMatch.Match(expectedObject).Using(customMatchFunction));

In your custom matching function you can basically do whatever you want, you could use closure and ignore expected object, or extend the CustomMatch to support something like this: CustomMatch.Use(function(actual){ return actual.fieldOne == 1 && actual.fieldTwo == 2;});

If you are using object literals or duck typing this kind of mock functionality might come handy.
That is something you don't have in C# or Java, C# 3.0 comes closest to object literals with anonymous types but they are by far of less usability, and they have nothing close to duck typing.
I hope you find this small extension justified and, more importantly, useful.

Monday, July 7, 2008

Firebug Net Panel History Overlay version 0.3.0

New version of the Firebug Net Panel History Overlay is available. This version requires Firebug version 1.2.0b4; that's the latest version at the moment. The previous version of the history add-on was making Firebug to hang; some functions from Firebug that I used changed as well as some of the NetMonitor and NetPanel behaviours so it was causing hang.
Due to behaviour changes it might happen that with new versions of the Firebug I will have to tweak history add-on but will keep close eye on Firebug changes and if required will update the add-on.

Friday, July 4, 2008

Setup Data-Driven Tests in Visual Studio to use Excel

I prefer simplicity of Excel files for my data-driven unit tests in Visual Studio - both 2005 and 2008. However the new test data source wizard is not supporting Excel files so the connection has to be setup manually.
It is not too hard to set it up, all that is required is addition of DataSourceAttribute to your test method:


[TestMethod]
[DeploymentItem("testData.xls")]
[DataSource(“System.Data.Odbc”,
@”Driver={Microsoft Excel Driver (*.xls)};DriverId=790;Dbq=testData.xls;DefaultDir=.”,
“Sheet1$”, DataAccessMethod.Sequential)]

public void SomeTest(){
//some testing
}




DeploymentItemAttribute is there so testData.xls file would be deployed with the test and thus make the test independent of a machine on which it is run. More about using Excel to drive your unit tests with some tips you can find here: Data-Driven Unit Testing using Excel in Visual Studio.

Saturday, June 28, 2008

Inspired by a book: Planning Extreme Programming

I have just finished reading the book: Planning Extreme Programming (The XP Series) and I have to say I found it brilliant. I read it in a day and could not put it down until I finally finished it around 3 am.
First of all the book is short, some 160 pages long, and that is very good! Simply everything is up to the point, you would not want to take anything out. It is concise, understandable, written in easy to follow language. Every paragraph brings some new value. And at the end it does not have ton of useless code examples, it does not have much of the examples though, but they were enough for me and most possibly any more would just be a distraction.
I strongly believe that any book should not be more then 200 or so pages long. Everything longer just puts me off. It is likely I won't have time to read it in continuation and at the end I won't know what I read in the beginning or at least how the things I'm reading now relate to the things I read two weeks ago. I like the Duplex Book idea, maybe that is why I enjoy reading Martin Fowler's books, it is like they are just the right size (or is it the content ;) )

Let me get back to the book. Even though the book is mostly project manager oriented developers should definitely read it. Sometimes I have difficulties explaining what is wrong with the process to our managers. Sometimes it is just a kind of a gut feeling, however you need far more solid arguments if you want to challenge some decisions regarding your project/process/whatever. The book nicely explains what the agile is all about and now I can safely say that I can easily explain to anyone why something is not agile or something is, and suggest improvements. And that alone is why it is worth reading.
One thing developer will definitely like is chapter about estimates. It just hits the spot. I recognized all the problems I had with my estimates (well more with project managers to be honest) and now I have a working plan how to improve my estimates even when not working on agile projects. And the advice to stop using the phrase: "I don't have enough time" with the phrase "I have too much to do" is simply brilliant, and what is more important it is usually more accurate.

So what have I learned from this book? The key to agile development is communication with the customer. If there is no proper and timely communication with the customer, if the customer is most of the time unavailable for clarifications regarding the functionality, you can't do agile. Without this key ingredient agile is not possible. The second key to agile is response to customer changes - the customer has the right and will change his mind and we should enable him to do so.
What the book also points is that all projects are different and what worked for one might not work for another one. So I guess being flexible when it comes to the process is a must. If something works for your project then use it, don't just blindly follow the process.

What you might notice I did not mention technology, testing, frequent releases, stand-up meetings or pair programming in the key elements? Your technology and practices should be determined by your project and your process, not vice verse. While it is very questionable if you can build software of decent quality without proper unit tests you might very well do without stand-up meetings and pair programming. At the end of the day use what works for you, don't force something that is not going to fit. Being agile should be company's strategy it is not a matter of simply coming and saying: great lets go agile.

Read the book, you'll feel better. I found what mistakes I made and what problems I might have prevented if I had educated arguments. It adds great value in couple of days reading.

Sunday, June 22, 2008

Make JSUnit work in Firefox 3.0

I lost hours figuring out this one. I was getting an error: Permission denied to get property Window.xbDEBUG, and eventually getting timeout on running my test page. The first error was happening on different lines of code while I was debugging in Firebug. At the end it was probably some concurrency issue, timeout was happening due to JSUnit test runner not being able to load my test file.
Now, of course I checked if the file exists, and it did exist. I figured out that it cannot load file since it is stuck in function: isPageLoaded in testContainerController.html. Why? At the end I found an answer in an unlikely place: Why doesn't my test suite run under JSCoverage in Firefox 3?
The problem is in the tightened Firefox security regarding local files, and security.fileuri.origin_policy parameter is not the correct one as suggested by the FAQ, it is new configuration parameter that superseded it:
Security.fileuri.strict_origin_policy, it should be set to false so JSUnit will run correctly. The article is mumbling something about suggesting to keep it true for the improved security sake, but I'm too tired of banging my head of the wall to really pay attention.

*** UPDATE ***
I just realised that the version of JSUnit I'm using ( 2.2alpha11 ) is not working correctly when you brows for the test page. I am getting an error:
Reading Test Page file:///someTest.html timed out.
Make sure that the file exists and is a Test Page.
The page does not exist since I browsed to a different file - file:///c:\temp\someTest.html. So there is a bug with loading page.
However it works if I supply the test page through testPage url parameter like this:
file:///.../testRunner.html?testpage=c:/temp/someTest.html
If the tests were not working after fixing the configuration then this might be the next thing to try out.

Thursday, June 19, 2008

Martin Fowler’s Syntactic Noise in JavaScript

I am closely following Martin Fowler's work on his DSL book. It is very interesting stuff and I wish I had more time to follow it more closely ... His latest post is related to the book and is about Syntactic Noise. This is my humble contribution with attempt to translate his example to JavaScript (btw, you have to read the article to make anything out of this):


var stateMachine = 
new StateMachine(
{
events: {
doorClosed : "D1CL",
drawOpened : "D2OP",
lightOn : "L1ON"
},

commands: {
unlockDoor : "D1UL",
lockPanel : "PNLK"
},

states: {

idle : {
actions : ["unlockDoor", "lockPanel"],
transitions: {
doorClosed : "active"
}
},

active: {
transitions: {
drawOpened : "waitingForLight",
lightOn: "waitingForDraw"
}
}
}
}
);



I know there is lots of red and I don't use => as is used in most of the examples, but I think I got it pretty good, and actually JavaScript is not that bad at all when it comes to internal DSLs. What do you think?
Oh, and I was just thinking, I bet I can do DSL in MPS that will have 0 (zero) syntactic noise! Keep tuned, I really might. That brings up another question: the example and the whole article is based on text based DSLs (blast, he was talking about internal DSLs, and I thought to be a smart a**) and what about graphical DSLs or Language Workbenches? As I said in some more advanced language oriented tools (MPS) we might use no syntactic nose without sacrificing any clarity. Text presented for clarification in this tools is part of the editor and is not there because of the syntax, you type in only significant data.

Tuesday, June 17, 2008

Improving security of JSONP in Chrome

Injecting scripts in chrome are raising security concerns, and JSONP is just that - injecting JavaScript. As I pointed out in Make JSONP Work in Chrome, number of security concerns are arising from the fact that, in chrome, scripts have as much privileges as the user running the browser. That means that if malicious code is injected by JSONP provider it could access private and sensitive data or do some real damage to the system as I will show later on with couple of examples.
Unfortunately Firefox is not offering much control over the privileges of the script execution: in chrome script has all the privileges. netscape.security.PrivilegeManager.disablePrivilege is not working and, correct me if I'm wrong, all you have as alternative is to run the code in the sandbox, where you have limited privileges and again no way to control them. I would much more prefere to have sandbox privileges by default and ask for more privileges I require.

Enough ranting and lets show the code. Here is the old version of the code:


var scriptCollection = document.getElementsByTagName("script");
var reader = new httpReader(scriptCollection[scriptCollection.length - 1].src);

function evaluateJs(aReader){
if(aReader && aReader.mData) {
eval(aReader.mData);
}
}

reader.AsyncLoad(bind(evaluateJs, this, reader));

Basically the first part is getting the URL of the JSONP script to execute - jQuery AJAX function hack. The second one is the function that will evaluate received script. As I pointed out earlier, by doing this the received script is executed in chrome with all the privileges and that is not very good idea if you have internet server serving you the script.

Here is improved script to execute this code in the sandbox:


var scriptCollection = document.getElementsByTagName("script");
var reader = new httpReader(scriptCollection[scriptCollection.length - 1].src);

function runInSandbox(scriptToEval){
//this line is for testing purposes this privilege will be enabled in chrome anyway
//netscape.security.PrivilegeManager.enablePrivilege('UniversalXPConnect');
var safewin = new XPCNativeWrapper(window);

var sandbox = Components.utils.Sandbox(safewin);
sandbox.window = safewin;
sandbox.document = sandbox.window.document;
sandbox.__proto__ = safewin;

//add jsonp method to the safe window
for(var prop in window){
if(typeof window[prop] == "function"
&& prop.substring(0, 5) == "jsonp"){
sandbox.window[prop] = window[prop];
break;
}
}

Components.utils.evalInSandbox(scriptToEval, sandbox);
}

function evaluateJs(aReader){
if(aReader && aReader.mData) {
//eval(aReader.mData);
runInSandbox(aReader.mData);
}
}

reader.AsyncLoad(bind(evaluateJs, this, reader));

This is significantly longer but the only change is usage of runInSandbox function. This code is inspired by Greasemonkey implementation. We are creating safe window using XPCNativeWrapper. Using the safe window we are creating sandbox and setting sandbox properties - window, document and __proto__. The XPCNativeWrapper is wrapping the object and limiting access to its properties and functions. Mainly, it is not allowing access to added or changed properties and functions of the wrapped object. Look at: How the History of Greasemonkey Security Affects You Now for more informati on about possible attacks and pitfalls.
Since after wrapping the window the JSONP function is missing we are adding it by cycling through all the properties of the original window and upon finding the right function we are adding it to the safe window. We know that jQuery created the JSONP function so it is pretty safe to do this. After that evalInSandbox can be called and we have our JSONP function executed in sandbox without possiblity to do any damage.
To illustrate what's been shown so far I will create a couple of simple tests.

Simplistic injection testing

First of all to note that all of this I am showing is done by opening XUL window in Firefox, feel free to wrap it up into extension and test it properly.
Lets prepare our testing ground for exploring vulnerabilities arising. The full source code is here. Please put injection*.js files somewhere on your local web server if you have it so you can access it easily. They are simulating JSONP scripts injection and basically they are simulating what some malicious server might serve to our extension.
The injection1.js is simply showing alert window so we know that we have access to injection files.
Injection2.js is reading C:\temp\security.txt file from the disk (you create some test file) and showing its contents. It is there just to prove the point, it might easily delete your system files if you are running Firefox as admin, or read your Gmail username and password and send it to some 3rd party via web service, etc; the point is it can do anything if called from chrome.
Injection3.js is trying to add click event handler to existing window and attempt to make malicious script pass boundaries of the sandbox.
Injection4.js is using some function we deliberately made unsafe to make the point that even when running in sandbox we have to keep in mind what we are doing and that we might cause voulnerabilities ourselves.
The securityText.xul has 5 buttons and they are doing the following stuff:
Simple test - loads injection1.js - shows alert 'injection', if it shows alert we are injecting scripts as expected
Voulnerability! - executes Injection2.js in chrome and is reading content of C:\temp\security.txt
Safe 1! - executes Injection2.js in sandbox - showing that it will not read the file
Safe ! - on click changes txt to still safe - we are attaching malicious code to click event of the button, but since it is executed on the wrapper it will not read the file
Safe (not really) ! - on click will change the text to Unsafe! since it will use voulnerable function we added to safe window and will actually add malicious code to click event of the button. Click on it again and it will read the contents of the file.

To change the location of the injection files change line 2: var scripturl = 'http://localhost/' + scriptFile; to wherever you put the script files. To change what file is read from the local disk find c:\\\\temp\\\\security.txt in injection scripts and change them to whatever file you want to read.
Hopefuly this helps.

Saturday, June 14, 2008

Intranet Feed Reader 0.2.0 - Support for Atom, and improved security

New version of Intranet Feed Reader add-on - 0.2.0 is available now. Source code is available here.
The add-on now has improved security by executing JSONP in sandbox instead of running it in chrome. This improvement will stop malicious code served by XML2JSON proxy, there is still possibility that unsafe code might leave sandbox but threat surface is much smaller now. Blog entry about that will follow and will continue to work on ways to improve security so stay tuned.
New version brings support for Atom feeds so now you can use: http://feeds.feedburner.com/blogspot/digitalmihailo as XML Url :) I added some HTML cleansing code as well - in our intranet we are using confluence and some feeds are featuring unclosed img tags. What the code does is using very simple algorithm (and un-optimized) to close unclosed tags and remove closing tags without openning tag. These improvements are implemented by following functions in content/sidebar.js of the add-on source code:

desinfictHtml
runInSandbox
adaptData - for Atom to RSS (we are using RSS to render content)
so give it a look.

Sandbox execution is inspired by Greasemonkey implementation.
Converting Atom dates is inspired by Convert Atom documents to JSON document by IBM.


Testing remarks

For setting up testing environment locally one possible solution would be to download feed's XML and put it to your local web server - url something like: http://localhost/testfeed/somefeed.xml. Using XML2JSON proxy is described in the first post on the Intranet Feed Reader Add-on.

Sunday, June 8, 2008

jQuery and dynamic HTML in XUL

There is a problem with doing dynamic HTML in Firefox Extensions using jQuery, actually only if you use XUL windows. This is probably applicable to all JavaScript frameworks that are allowing dynamic manipulation of DOM.
Consider the following example:




<?xml version="1.0"?>
<window id="rootWnd" title="Test"
xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul"
xmlns:html="http://www.w3.org/1999/xhtml" >
<script type="application/x-javascript" src="jquery-1.2.3.js"/>
<script type="application/x-javascript">
function test(){
$("#content").append('&lt;p&gt;test&lt;/p&gt;');
alert('done');
}
</script>
<vbox hidden="false" height="0">
<button label="click me" oncommand="test();"/>
<html:div id="content"></html:div>
</vbox>
</window>




There is nothing special about this code, highlighted text JavaScript should add paragraph to content div and show text "test". That is probably very common statement when using jQuery to change some HTML content (and probably doing something more useful). Nothing special about the code as I said but it does not work. If you try this into web browser it will work though however in XUL it won't.
This example follows a tutorial on adding HTML elements to XUL. It is obvious now that $("#content").append('test') won't work. According to the article it has to be: $("#content").append('test'). Unfortunately it does not work again. The problem is in jQuery.1.2.3.js, more precisely in the line 968:
var tags = jQuery.trim( elem ).toLowerCase(), div = context.createElement("div");
Again if we try to put "html:div" it will not work and now the problem is in the Mozilla's document.createElement implementation which will create the element in the default namespace of http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul since it is XUL document. I think this is not how it should be but non the less it is the way it works so solution to the problem would be:
div = context.createElementNS("http://www.w3.org/1999/xhtml", "html:div")
which will create the element in the correct namespace. Unfortunately it will not work again since exception will be thrown in the line 998: div.innerHTML = wrap[1] + elem + wrap[2]; it does not like html:... part I guess.
So is there a solution? Here it comes:

Solution

If we rewrite the XUL document to look like this:




<?xml version="1.0"?>
<xul:window id="rootWnd" title="Test"
xmlns:xul="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul"
xmlns="http://www.w3.org/1999/xhtml" >
<xul:script type="application/x-javascript" src="jquery-1.2.3.js"/>
<xul:script type="application/x-javascript">
function test(){
$("#content").append('&lt;p&gt;test&lt;/p&gt;');
alert('done');
}
</xul:script>
<xul:vbox hidden="false" height="0">
<xul:button label="click me" oncommand="test();"/>
<div id="content"></div>
</xul:vbox>
</xul:window>




What we are doing here is setting the default namespace to be the XHTML namespace instead of XUL. It requires a bit of rewriting the XUL elements but it will presumably enable us to use any JavaScript framework. however there is another bit that has to be changed in the jQuery script:
line 968 should stand as:
div = context.createElementNS("http://www.w3.org/1999/xhtml", "div")
And of course any createElement calls should be amended.

Another problem

At the end to conclude with another unsolved problem. This will all work if you have control over the html contents you want to change, but if you don't, e.g. showing rss feed, then you might end up with a problem. If you check the namespaces in the XUL document you'll see that namespace is of XHTML and actually the document is XML document. Because of that, sometimes you might end up with error similar to:
[Exception... "Component returned failure code: 0x80004003 (NS_ERROR_INVALID_POINTER) [nsIDOMNSHTMLElement.innerHTML]" nsresult: "0x80004003 (NS_ERROR_INVALID_POINTER)"
Which is Firefox's friendly way to say that your XHTML is invalid. Thanks to this article in Russian (here is the English version, courtasy of the Google language tools, mind that translation is a bit awkward but it can be understood if you badly need it) I managed to decypher the error message.
This message can occure because of many things, unclosed tags, text in elements that are not supposed to have text etc. It can pass in regular browser since browser will do its best to parse whatever you give it but if it ain't proper XHTML it won't work in Firefox. If you have any suggestions on how to clean the HTML to get proper XHTML please let me know.

Tuesday, June 3, 2008

Firebug Net Panel History Overlay version 0.2.1

Just uploaded new version of the Firebug Net Panel History Overlay. The new version is 0.2.1. It adds support for Firefox 3.0.* and adds new menu item Clear History.
I don't know why the addon's main page is not showing the latest version but the file can be downloaded from here, and source code from here. As with the previous version login is required since the addon is in the sandbox. Talking about sandbox, some review/feedback would be highly appreciated so I can nominate it for becoming public. Thanks.

**Update**
The public page of the add on has been updated, seems there is a bit of lag between uploading new version and showing on the site, none the less all links should work.

Tuesday, May 27, 2008

Intranet Feed Reader - Firefox Add On

I just ported Michal Bali's iGoogle gadget: Intranet Feed Reader. The add on can be found here. Again, log in is required for download since it is still in sandbox.

The add on adds capabilities to read intranet feeds into your Firefox's sidebar:


More details can be found at this Michal's blog post:
http://blog.decaresystems.ie/index.php/2008/05/20/google-gadget-intranet-feed-reader/

I will just shortly quote the conclusion of the article:

The intranet feed reader gadget can be used as part of a developer’s dashboard. It can display any intranet feed. Most useful might be information necessary for day-to-day work (e.g. current assigned issues in the bug tracking system, changed resources in company’s wiki or version control system).
Here is in short how to setup and use it:
After installation there will be new menu item added to the Firefox's Tools menu - Internet Feed Reader. It has sub menu items Properties and Show Panel, intuitively Properties are setting up the extension and Show Panel is showing sidebar panel with the feed contents.
Parameters of the Properties dialog are:
  • XML Url: required, url of the rss feed you want to follow
  • XML2JSONP Proxy Url: required, url of the XML to JSONP proxy. The extension uses JSONP to display the feed contents so proxy is required to convert XML feed to JSONP. How to setup the proxy for testing the extension is following up shortly
  • cookiesJson: optional, authentication cookie if required by the feed provider
Test the extension
In order to test extension you will need XML2JSONP Proxy. Basic implementation of the proxy by Michal Bali can be found here:
http://michalbali.googlepages.com/xml2jsonp
I did install the Apach Tomcat 6.0 and setup the xml2json.war from the proxy's site. After installation XML2JSONP Proxy Url parameter would look like something like this:
http://localhost:8080/xml2json/Xml2JsonpProxyServlet
Just put any feed url into XML Url, maybe:
http://blog.decaresystems.ie/index.php/author/mbali/feed/
And after setting up the stuff just click on Tools > Intranet Feed Reader > Show Panel.

IMPORTANT!!!
Use only trusted XML 2 JSONP proxy, ideally from your own machine or from your intranet. JSONP works by injecting Javascript into the page thus using untrusted server might cause injection of malicious code and by doing that in the priviledged mode that the extension is working in can cause serious damage to your computer!

Related articles:
http://digitalmihailo.blogspot.com/2008/05/make-jsonp-work-in-firefox-chrome.html

Sunday, May 25, 2008

Make JSONP work in Firefox Chrome

I have been doing some Firefox extension and I needed to do some JSONP Ajax call in the sidebar and then show the result. jQuery makes it easy, you do something like:




$.ajax({
type: "GET",
dataType: "jsonp",
url: "http://someurl.com",
data: aRequestData,
cache: false,
error: function (XMLHttpRequest, textStatus, errorThrown) {
// typically only one of textStatus or errorThrown
// will have info
alert("Error occured textStatus=" + textStatus + " errorThrown=" + errorThrown);
},
success: function(data) {
alert('success');
}
});




Plain and simple and it works in browser window, however, to my big surprise it did not work in Chrome, never got to the success alert. After turning on Firebug I got an error from jQuery: head is null. OK, What is JSONP?
How it works is that script is injected into the head element of the HTML document. Source of the script is a link to the external server that is providing customized javascript function call with the retrieved data. Upon receiving data jQuery is deleting that script element.
So head is null indeed since document.getElementsByTag("head") is not returning enything since I don't have head element in my XUL file:



<?xml version="1.0"?>
<?xml-stylesheet href="chrome://browser/skin/browser.css" type="text/css" ?>
<?xml-stylesheet href="chrome://intranetfeedreader/skin/sidebar.css" type="text/css"?>
<!DOCTYPE prefwindow SYSTEM "chrome://intranetfeedreader/locale/intranetfeedreader.dtd">

<page id="sbIntranetFeedReaderSidebar" title="&sidebar.title;"
xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul"
>
<script src="jquery-1.2.3.js"/>
<script src="sidebar.js"/>
<vbox flex="1">
<label id="atest" value="&sidebar.title;" />
</vbox>
</page>



So nothing fancy but no head tag. Well lets add head tag and see if we can trick the jQuery:



<?xml version="1.0"?>
<?xml-stylesheet href="chrome://browser/skin/browser.css" type="text/css" ?>
<?xml-stylesheet href="chrome://intranetfeedreader/skin/sidebar.css" type="text/css"?>
<!DOCTYPE prefwindow SYSTEM "chrome://intranetfeedreader/locale/intranetfeedreader.dtd">

<page id="sbIntranetFeedReaderSidebar" title="&sidebar.title;"
xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul"
>
<head>
<script src="jquery-1.2.3.js"/>
<script src="sidebar.js"/>
</head>
<vbox flex="1">
<label id="atest" value="&sidebar.title;" />
</vbox>
</page>



And it worked :) I got rid of the error, but still no success alert. To make the long story short: injection of scripts this way is not working in Chrome. It will allow only urls starting with chrome://. Well it should work that way, working from browser window is pretty harmless (well it depends ...) compared to working in chrome where the code has much more privileges and can do some serious damage. I am not really convinced that getting the data this way is really smart thing to do, simply injecting javascript code from another server is scary - I can imagine that it is not too hard to inject whatever harmful code this way.
So I guess one big warning is due for the reminder of the post:

WARNING!!!! The following code should be used only with trusted servers. Ideally only in intranet. Never, never, never use this code with server that you do not trust 100%. Of course you are using this code on your own risk.

Since the injection of the script by purely adding script element to the document does not work in chrome then we have to do the script loading manually. Idea is to download the script ourselves and then execute it ourselves. That is not hard at all, and here is (almost) all the code:



var scriptCollection = document.getElementsByTagName("script");
var reader = new httpReader(scriptCollection[scriptCollection.length - 1].src);

function evaluateJs(aReader){
if(aReader && aReader.mData)
eval(aReader.mData);
}

reader.AsyncLoad(bind(evaluateJs, this, reader));


The code is really simple, firstly we get all the script elements from the document, then we initialize httpReader object with the source of the last script (jQuery is appending it to the head, well keep all your scripts enclosed in the head tag or modify the code to get the correct script). evaluateJs is simply helper function that is calling eval function on the script we get from the server. And at the end we asyncronuosly load the url with the script.

This code executes javascript code as browser would in the normal html document - get the script and then execute it. Some further testing should probably be involved here to check the code we are going to evaluate but anyhow if you plan on using this approach you should really take security seriously into consideration.

The last bit is httpReader, it is simple implementation from the article: Creating Sandboxed HTTP Connections from the developer.mozilla.org. bind functions are based on Firebug code. And the file is here.

Monday, May 12, 2008

Baby boy Luka

I just got a baby boy Luka:


He was born on 7th May 2008 in Cork University Maternity Hospital. That was the happiest day of my life, and probably the scariest at the same time :)

Just wanted to say one big Thank You! to everyone in CUMH - they were all absolutely brilliant, I have never seen so many nice people in the same place in my life. Everyone was so nice and caring, we've seen like 50 people in three days we've been there and I have no words to describe how nice they all were. Guys we love you all!

Tuesday, April 29, 2008

Network History Support for Firebug

Recently I started developing Firefox add-ons. Firefox is my browser of choice and I use it almost exclusively. Firebug comes handy when you want to analyse what you are getting from site, which I needed to do recently. I needed network history functionality to record the whole conversation but there was no such functionality in Firebug and since I prefer to work in environment/tool I am comfortable with I decided to add overlay to Firebug and add functionality myself.

Here is the add-on on Firefox add-ons: Firebug Net Panel History Overlay, current version 0.2.0. You need to log in to install it since it is still in sandbox/review phase. Here is the screen shot on how it looks like:


The code has lots of comments and it might be worthwhile giving it a look if you want to build your own net panel overlay. Here is the full source code (again log in required), version is 0.2.0, let me know if you have any comments or need any help with it. Files are as follows:

  • chrome.manifest -defines contents of the add on and sets the add on as Firebug overlay
  • install.rdf - file that describes the add on
  • /chrome/firebugNetHistory/NetPanelHistoryOverlay.xul - UI for the add on. Huh, UI is couple of buttons and label to navigate through history
  • /chrome/firebugNetHistory/NetPanelHistoryOverlay.js - main functionality for the add on, defines NetPanelHistoryOverlayModel and registeres it with Firebug
  • /chrome/firebugNetHistory/netHistoryParameters.xul and netHistoryParameters.js - dialog and dialog event handlers for setting parameters
  • defaults/preferences/netHistory.js - configuration for the add on
I tested add on with Firebug 1.1.0b10.

If you want to extend Firebug yourself - Jan Odvarko has a great tutorial on his blog.

At the moment if you have YSlow installed you might not see menu items for the net panel history in the options menu of the net panel. The problem is that YSlow is replacing menu items in the menu instead of just adding its own items.