Firefox 4 AppTabs : Preparing with dynamic favicons

Firefox 4 is rapidly approaching release and there are numerous interface enhancements already included in the current nightlies. One is the addition of AppTabs; sticky tabs that remain at the left of your tab bar that are meant to serve as a place to keep your web “applications” like GMail or Twitter.

There’s still a lot that hasn’t yet determined about AppTabs yet, like how navigation is handled, when a link will open in the AppTab and when in a new tab and so on, but that it will only display the favicons with no title is reasonably certain. Since all your user will see of your website is a favicon it’s important to keep the user up-to-date using only this limited space, for example by showing the number of unread mails as part of the favicon.

This may seem like a difficult task, but thanks to Canvas it’s actually very simple. Assuming you already have a function somewhere in your code that gets notified when the number of new events changes, all you have to do is add code to that function that will create a Canvas, draw the number to it, remove the old favicon, create a new one and finally set it to the url you get from Canvas’ toDataURL.

One by one:

assuming you have a function onNewEvent(newEvents){} that is called with the number of events

function onNewEvent(newEvents){
  /* Create a canvas to draw the icon */
  var c=document.createElement("canvas"); 
  c.height=c.width=16; 
  var cx=c.getContext("2d"); 

  /* Formatting */
  cx.font="18px bold Calibri";
  cx.fillStyle="#000";

  /* Draw nothing if number is 0, "9+" for 10
    or more, otherwise the number */
  if(newEvents)
    cx.fillText(newEvents>9?"9+":newEvents,0,16,16); 
}

This will create a Canvas with the content we want (you’ll probably want to draw your usual favicon in the background as well and make the text a bit prettier, but this works for now). Now we need to assign it

For some reason setting the href value on an existing link[rel=”icon”] element doesn’t have any effect, so we have to create a new one to replace the existing one. First, let’s remove the old one(s):

  var oldicons=document.querySelectorAll(
    'link[rel="icon"], link[rel="shortcut icon"]'); 
  for(var i=0;i<oldicons.length;i++)
    oldicons[i].parentNode.removeChild(oldicons[i]);

And finally we create a new one and attach it to the head.

  var newicon=document.createElement("link"); 
  newicon.setAttribute("rel","icon"); 
  newicon.setAttribute("href",c.toDataURL()); 
  document.querySelector("head").appendChild(newicon);

The whole function now looks like this:

function onNewEvent(newEvents){
  /* Create a canvas to draw the icon */
  var c=document.createElement("canvas"); 
  c.height=c.width=16; 
  var cx=c.getContext("2d"); 

  /* Formatting */
  cx.font="18px bold Calibri";
  cx.fillStyle="#000";


  /* Draw nothing if number is 0, "9+" for 10
    or more, otherwise the number */
  if(newEvents)
    cx.fillText(newEvents>9?"9+":newEvents,0,16,16);

  /* Remove old icons and add node for new
    one (just setting the href won't work) */
  var oldicons=document.querySelectorAll(
    'link[rel="icon"], link[rel="shortcut icon"]'); 
  for(var i=0;i<oldicons.length;i++)
    oldicons[i].parentNode.removeChild(oldicons[i]); 
	
  var newicon=document.createElement("link"); 
  newicon.setAttribute("rel","icon"); 
  newicon.setAttribute("href",c.toDataURL()); 
  document.querySelector("head").appendChild(newicon); 
}

That’s all there is to it. No big framework, just a good dozen lines of code and you’re set.

Here’s a bookmarklet that will let you try it on GMail now. It’s Firefox-only since it hooks into GMail using the Gecko-only __defineSetter__ method on the title, but that’s only for the wrapper. The actual code works on any browser as long as it supports Canvas. Just drag this link to your bookmark toolbar, then click it while you’re using GMail (it will persist for your current session, but not if you refresh, restart and so on)

FireStation: Firefox on (an unhacked) PSP

Note: this is (for now) released under a proprietary license. You are allowed to install and use this on any number of systems, however you are not allowed to distribute it. As usual, it comes with absolutely no warranty. Should local raw require any warranty, then you are not allowed to download or use. The license thing is simply because I don’t want to see clones popping up yet. I didn’t submit it to the Mozilla Addon Directory because I don’t feel it’s ready yet and I don’t want others to do it instead. If you really do want to polish it to the point where it would be ready for mainstream use, drop me a line.

Source and installation (FireStation.xpi): Link (only tested in Firefox 4 betas so far).

Install it (and restart Firefox), then choose Tools/FireStation on the Firefox menu (make sure you don’t have any other web servers running). Finally, navigate to your PC’s IPv4 address using your PSP. You can find it by opening a command prompt and running “ipconfig” (should look similar to 192.168.2.86). Make sure that your router is configured to not expose port 80 to the outside world, since there is no authentication inside FireStation yet.

Thanks first to the good people over at the moznet #extdev channel, without whom I would never have gotten the Firefox sockets API to work properly.

OK, now on to the description to what this actually is: This Firefox Addon lets you remote control your Firefox from any PSP. It works by implementing a simple HTTP server with sockets, then feeding an it screen captures (generated with Canvas, drawWindow and toDataUrl), while sending scrolling, clicks and keystroke data back from the PSP to the PC and simulating it there.

It’s not optimized in any way, but it works surprisingly well already (for reading; it’s not exactly perfect as a video player). You can scroll using the PSP Square-button and Firefox will capture the rectangle you’re currently looking at and transmit that, instead of forcing you to fiddle around with scrollbars. There’s a location bar that you can click to enter a new location and a simplified keyboard that you can use for anything on the page, like search fields. There’s no right click, or support for multiple windows yet (they will open, but you won’t see them on the PSP).

The PSP browser (NetFront) is a user’s (and developer’s) nightmare, so the challenge here was twofold:

  1. Getting Firefox to work as a webserver
  2. Getting Netfront to show it

It may seem like getting the webserver running would be the hard part, but getting NetFront to behave is actually a good deal harder. The webserver is contained in a few easy to use classes in content/server.js. To use it, you simply throw it a configuration object and that’s that:

new HttpServer({
  "/screen":function(req){
    var res=new HttpResponse("","text/html");
    ...
    return res;
  },
  "/blank":new HttpResponse("empty","text/plain")
},80);

With Netfront, there is nothing easy or clean. Any code that is supposed to run on it will inevitably turn into one huge hack.

  1. There are no frame url setters, like myIframe.src=”http://www.google.com”. While it won’t throw an error, it simply won’t do anything
  2. No XMLHttpRequest. Not much of a surprise, but still inconvenient.
  3. Very little event support (no scroll or even a good load event).
  4. Very strange CSS/JS interaction (it doesn’t try to apply all CSS at once like normal browsers, but will update the screen between commands)
  5. Only a modal keyboard
  6. No way to create or remove any elements, other than document.write
  7. Tons of other stuff that I have forgotten about.

You overcome #1 and #2 using the legacy frames API, window.location and JS callbacks. #3 requires you to basically recheck manually from time to time and #4 simply means shuffling your CSS-applying JS code around until you get what you want. #5 is annoying because if you need to have something onscreen while the user is typing, you need to create your own and finally #6 means that you’ll be hacking around with iframes where you’d normally have a DIV, since that’s the only way to actually create new nodes.

This basically works, but it’s going to take a lot more hacking to make it pleasant to use. Clicks and Key-presses are ridiculously slow so far since the image takes up nearly all bandwidth, even when it’s transmitting the same image over and over again (detecting mozAfterPaint could fix this). Dynamic zoom and multi-tab support are really musts at some point as well.

Security: GMail vulnerability: Arbitrary script execution with SVG

Note: this vulnerability has long been fixed. I was just waiting for the confirmation from Google.

I could now tell a story of magic and wonder, how I spent day and night analyzing GMail and finally after weeks of hard work found this vulnerability. But the truth is that I was simply using GMail as I usually do when I came across this vulnerability.

GMail has had the “View Image” functionality for a while and I’ve often lamented that it doesn’t extend to SVG documents, which are eventually viewed through Firefox anyway. So when I finally noticed the “View Image” link next to an SVG that I had sent to my address for quick access on another computer, I happily clicked on it and was more than a little surprised when it opened on the mail.google.com domain.

You see, hosting any kind of unknown document on your own domain is extremely risky. Even a seemingly harmless PNG or JPEG can be a threat unless you really verify that it is what it claims to be and/or serve it from an unpredictable location. If it’s not and you didn’t notice, then all it takes is a browser trying to act smart and ignoring the MIME type for an attacker to take complete control of the user’s account. SVG is especially dangerous since, just like HTML, it can contain or link in script code. So, seeing the SVG open on mail.google.com was worrying.

On the other hand, GMail also displays HTML on mail.google.com by preprocessing it and removing anything that is not text or formatting-related (which is also an extremely dangerous task since every new release of a web browser includes new ways to load remote data, but apparently Google feels that it’s worth the risk: even allowing the loading of CSS can cause code execution), so there was some hope.

The problem is that in difference to HTML it is nearly impossible to preserve the majority of information in an SVG document if you strip it of tags that can be used to include data, since a lot of SVG’s core functionality relies on linking in fragments that can either be part of the local or any other document.

I started throwing some slightly obfuscated SVGs at it and was surprised to find that it didn’t filter any code at all, no matter how it was included. Using this knowledge and another attack vector (that I’m not going to describe yet since it’s still being worked on) I was able to deliver a harmful mail and open it by leading the user onto a specifically created webpage. With a bit of other black magic I was able to read the address book and all mails from there and have them delivered to my doorstep.

There’s not much more to this story. I reported it, the “View Image” link got disabled for SVG documents and we’re safe once again. But how can such a big issue ever slip through the cracks of Google’s testing and could this happen elsewhere? Well, I can only guess, but this is what it looks like from my perspective:

When you create any kind of software that may be an attack target, you define how potentially dangerous each component is. This may happen informally by people simply watching changes in certain files more closely or through a dedicated process that requires additional reviews for files marked “critical”, but it always happens.

So, how would you rate a file containing a list of image file formats, especially when there are only non-interactive formats like GIF, JPEG or PNG around (as was the case when GMail was initially created)? You’d probably mark it as “safe” and allow patches with minimal or no reviewing. Now, someone learns about this new “image format” SVG, not realizing that it is in fact a document format and adds it to the list of image files and voilà, you’ve got a class A untrusted code execution vulnerability.

What can we learn from this?

  1. Anything that ends up serving untrusted content from your servers really is security relevant
  2. Any assumption on the danger of a particular action should be rechecked regularly, to see if it still applies
  3. A little knowledge is a dangerous thing when it comes to file formats
  4. When in doubt, serve untrusted content from a separate domain.

Thanks to Adam from the Google Security Team for the good cooperation and being an all-around nice guy 🙂

Javascript Object Notation is a strange beast

I’m never quite sure whether the Javascript Object Notation is a blessing or a curse. Of course, it does allow for quick creation of lists, but the way it is implemented I always find myself adding a few extra brackets just to make sure it is really treated as an object definition, not a code block.

Take his for example:

{title:'Hello World'}['title'];

Looks an awful lot like an object definition with an immediate access to the title property, doesn’t it? Well try to run it.

Huh? “title”? The problem is that this statement is ambiguous: It could either mean “Create object title set to Hello World” or “Code block with label title and string Hello World”. The meaning of [‘title’] then would mean “Access title property” for the first interpretation and “Create new Array with string title”. In this case, the second meaning is chosen and [‘title’] turns into the string “title” during output.

Now, this doesn’t happen nearly as often outside javascript: urls since the code grammar usually dictates how to interpret the block, but it still occasionally pops up.

What do we learn from this? Don’t forget to quote the identifiers, don’t hold back on brackets and don’t forget the semicolon:

({'title':'Hello World'})['title'];

Flash 3D – a welcome fallback

Apparently Adobe is getting more and more comfortable with being a fallback for modern standards in out-of-date browsers. After adding VP8 to the list of supported codecs, they are apparently now working on 3D support. While we can be reasonably certain that Adobe wants to sell their approach to 3D as “unique” and will offer a proprietary 3D scene DOM to prove it, I would be very surprised if they blocked low-level access to that DOM entirely, since that would make WebGL more powerful and that’s a headline they definitely don’t want to see.

And where there’s low level-access there’s always a way to use it to emulate another API. So maybe in a not too far-away future we’ll see WebGL, SVG, WOFF, Canvas emulated via Flash in legacy browsers, so we can stop focusing on fallbacks and just let the dominant plugin (Flash) deal with the dominant legacy platform (InternetExplorer) while we are finally free to focus on content.

Update on the simplistic 3D renderer for Canvas 2D: TinyDim

Demo

You control the demo mainly by left/right dragging the mouse, but some basic, unoptimized support for keyboard navigation is in there as well (Arrow Key/PgUp/PgDn). If you click on a face it will light up briefly and you can now enter a new color in the fields below the canvas.

A guy named Luke recently posted a comment on a three year old post that I honestly had mostly forgotten about: “Canvas 3D Renderer updated“. It was about one of the first Javascript programs capable of rendering a file exported from a 3D program without a plugin.

There are by now several such engines using Canvas 2D, a good deal of them more advanced, faster and better supported. However: TinyDim, which was the name I used when I compiled that sample into a sort of generic Javascript library has its advantages in being small, simple, easy to understand and therefore easy to hack and extend.

So this is a sort of update what has happened since then: I’ve actually used TinyDim sometimes and it has received some level of basic optimization at the code level (it’s still missing any structural optimizations like caching or viz-areas), but I never got around to post about it. It now has support for one global light and has its own mouse navigation class for when you just want to view a static 3D model. Support for colored faces is still only hacked in with a proprietary format (although that would be easy to change, you just have to write a MAT file parser) and It can return the face you’ve clicked on.

So, if you want to hack in texture support using this technique or anything else, be my guest 🙂

Dock-style zooming icon bar in pure HTML+CSS

Update: The initial post mentioned transforms, which were used in the initial version, but later replaced by simple absolute positioning.

Demo

An OSX-style icon bar in pure CSS, without any Javascript. Not much to say except: Enjoy 🙂

This sample uses CSS transitions, meaning that it requires a Firefox 4 preview build.

Webkit manages to do … something (Webkit tries to do some transitions in sequence instead of simultanously). Opera apparently has no support for pointer-events in HTML yet.

Try to disable the stylesheet (View/Page Style/No Style in Firefox): The document remains usable. Ugly, but usable.

Fixing HTML5 YouTube’s fullscreen playback with AdBlock+

I haven’t used AdBlock+ for quite a while… ever since I entered the realm of Flash-less web browsing thanks to Adobe’s inability to produce a 64 bit Windows version of the Flash plugin. However when Beta 1 of Firefox 4 was released I had to answer the question “Does AdBlock+ work?” quite often (the nightly does), so I more or less had to install it.

I used the opportunity to get rid of the biggest annoyance of YouTube’s HTML5 player: the broken full screen mode. YouTube overlays the video with a transparent div in order to block users from right-clicking on a video, since this offers the option to save the video (YouTube’s videos may be free, but they are still copyrighted and you don’t automatically get the right to distribute them).

Getting rid of this overlay with AdBlock+ is easy since it has a unique class attribute: “video-blocker”. Just Go to AdBlock+ preferences window (Tools -> Adblock Plus Preferences…), click “Add filter…” in the lower right and enter the selector “youtube.com##.video-blocker” (without quotes). This hides the overlay and you’re now free to right click on any YouTube HTML5 video to access the fullscreen option.

Here’s a link to the Coraline trailer: Try it. Link.

Using the real full screen mode instead of YouTube’s normal pseudo full-screen mode also means that Firefox can now use hardware acceleration (via OpenGL and Direct3D), even if you don’t have Direct2D enabled. Even my old laptop can play HD WebM video this way.

Texturing with Transform, without WebGL or Canvas

Update: I’ve checked it in Firefox 3.6.6 and to my surprise it works perfectly.

Demo

With the maturing of Direct2D support in Firefox I feel that it’s time to revisit transformations. Transformations let you rotate, skew and so on arbitrary elements on a page. They are relatively slow to do in software but really fast in hardware.

After a long discussion that I had recently, I should point out that this is a DEMO, meaning that it’s supposed to show what you CAN do with HTML+Transformations, rather than what you SHOULD do. A demo is not useful on it’s own, it’s just meant to illustrate a concept.

In this case, it shows a very simple approach to doing free-form deformation of bitmaps. I tried it in pure HTML+JS+CSS here, but the concept and quickly and easily be applied to other drawing systems like Canvas2D, where it could be used to provide a fallback for WebGL.

Aaah, the web in its purest form

I don’t know about you, but right now, I’m having a blast using the web. Even more than I used to have. The reason:

Mozilla has started releasing x64 builds of Firefox. And I’m having a lot of fun using it, but probably not for the reasons you’d imagine.

First off, the x64 builds are not really any faster yet than the standard x32 builds, due to some optimizations not working on x64 yet. And even then, the speed difference would probably be negligible. X64 is no magic bullet that suddenly makes an application twice as fast.

So why am I having so much fun? Because my plugin list is EMPTY. ZIP. NADA. For the last two months or so I’ve been surfing on pure Firefox goodness. There simply are no plugins for Firefox x64 builds available yet. I’ve been using Flashblock before, but even with Flashblock, the Flash plugin still gets loaded… it’s just removed immediately afterwards.

Now, I like watching a YouTube video every once in a while as much as the next guy and I’m glad that I still have x32 builds available for when YouTube has no WebM available (hint: create a link to your x32 firefox.exe and an empty directory somewhere on your HDD, then modify the link to read “firefox.exe -no-remote -profile c:\my\directory”, so you can start it without having to close your normal Firefox first) , but separating video browsing from my main browsing experience has increased the quality of my browsing experience tremendously, to the point where it outweighs the inconvenience of launching another Firefox instance by a wide margin.

(Yes, I could have disabled Flash before, but just like the rest of the world I never imagined that it would have such an impact on my browsing experience).

You can find current Firefox x64 trunk builds at ftp://ftp.mozilla.org/pub/mozilla.org/firefox/nightly/latest-mozilla-central/ , labeled win64-x86_64