Posts in Category "API tips"

AIR API Tip: Don’t write to File.applicationDirectory

As a number of AIR developers have discovered, it’s hard—but not impossible—to write files in the application’s install directory. That’s the same location given by File.applicationDirectory.

Granted, it’s often a tempting thing to do. For example, many applications include a database or configuration file with some pre-filled data. Once installed, they often want to update that file, say with user-specific data or preferences.

The first problem with this is that it’s not reliable. On some operating systems—Vista, for example—the installation directory is protected by the operating system. Even if AIR lets you write to this location Vista won’t. So if you want to write portable applications, don’t do this.

The second problem with this is that it’s not safe. Any code written into this directory runs with application privilege, which can compromise your application, which can compromise the user’s machine. That’s why Vista protects these directories.

The third problem is that it invalidates your application’s signature. Among other things, that means you won’t have access to the encrypted local store any more.

It’s also unnecessary. A safe and allowable alternative is to write somewhere into the user’s directory. If you still want a starter file, it’s easy to copy one from your install directory to the per-user location. Note that this also avoid problems if there are multiple users on the same machine.

In order to help developers avoid this pattern, AIR will prevent write access to this directory in most cases, and even when the underlying operating system allows it. There are currently ways around this, as it’s advisory—not mandatory. However, the ability to go around this restriction is often misinterpreted as a defect, and we may close this off in a future release. You’ve been warned.

Custom Update UI for Application Updates

I’ve just finished my talk on the Brussels stop of the On AIR tour. I was discussing the importance of the application update mechanism in the context of dealing with security issues and mentioned the <customUpdateUI> feature. According to the show of hands in the audience, no one knows about this feature, which is a real shame.

The feature itself is simple. By default, if your application is already installed and an .air file for your application is opened, AIR will handle the situation. It will display appropriate UI; typically, you’ll see the old and new version numbers and be asked if you wish to upgrade.

That’s less than ideal for two reasons. First, most applications have their own update mechanisms, update UI, and so on. This default behavior circumvents all of that.

Second, it puts the decision about which version of the application is newer in the user’s hands. Assuming you use a straightforward versioning scheme, this is typically not an issue. However, if an attacker can convince a user to install an older version of the application, then they may be able to use a security vulnerability you’ve already patched to compromise the user’s machine.

To avoid these drawbacks, simply declare the <customUpdateUI> element in your descriptor. With that set, any activation of an .air file for your application will cause (a) your application to be started, if it’s not already running and (b) the path to the .air file to be delivered to your application via an InvokeEvent. Your application simply needs to capture that event and handle it. You can likely handle it by re-using the logic for your own auto-update mechanism.

That’s all there is to it. Full documentation is also available.. Give it a try; I hope to see more hands go up next time I ask who’s seen this.

The AIR Browser API and User Events

The AIR browser API lets web applications detect, install, and launch AIR applications. There are some restrictions on its use, however:

  • Applications have to opt-in to the detect and launch capability. This is done by specifying <allowsBrowserInvocation> in the application’s descriptor.
  • Installing and launching applications can only be performed in the context of a user event

“In the context of a user event” means that the method is called during an event handler for some event, such as a mouse click, that’s initiated by a user action, such as clicking on a button. Note that this doesn’t mean all mouse events qualify, as they can also be dispatched programmatically.

Why this restriction? To protect the user against malicious (or just really annoying) web pages. WIthout this restriction, pages could install and launch applications as soon as the page is loaded, over and over again, until you give up in disgust and quit using the Internet.

This restriction occasionally trips people up when using the browser API because it’s tempting to wait for a user event, then call getApplicationVersion() to determine whether or not the application is installed, and finally call installApplication() or launchApplication(). But this won’t work because the getApplicationVersion() call is asynchronous; when the specified callback function executes, the code is no longer part of the original user event.

Note that getApplicationVersion(), however, need not be called during a user event. The trick, then, is to call this method right away, when your web page loads. By the time the user clicks on the button, you’ll already know whether you need to install or launch and can do either immediately within the context of the user event.

One final note: consider calling getApplicationVersion() periodically from a Timer. That way, if the application install state does change while the page is open, subsequent clicks on that button will continue to do the right thing.

AIR API Tip: Use HTTP_RESPONSE_STATUS, not HTTP_STATUS

AIR extends the existing Flash URLLoader, URLStream, and FileReference classes with a new event type, HTTP_RESPONSE_STATUS. If you’re writing an AIR application, you probably want to use this new event instead of HTTP_STATUS. Both events are instances of HTTPStatusEvent, but there are two major differences.

Additional Properties The HTTPStatusEvent has two new properties, responseHeaders and responseURL. These properties are available for HTTP_RESPONSE_STATUS but not HTTP_STATUS.

Earlier Dispatch The HTTP_STATUS event is dispatched after the request is completed and immediately before the COMPLETE event itself is sent. HTTP_RESPONSE_STATUS is dispatched as soon as the headers have been processed, before the data is available. If your request contains a lot of data or is made over a slow link, this can be significantly earlier.

Why did AIR introduce the new event type, instead of just re-using HTTP_STATUS? Compatibility: We didn’t want to break any existing code.

Version Numbers and the Updater API

AIR applications can update themselves via the Updater API. It’s straightforward to use: you just provide an AIR file containing the new version of your application and the version number you’re upgrading to. Downloading the AIR file and displaying any appropriate UI is left to the application.

When we designed this API, I thought we’d get a lot of questions about why the version number had to be provided. After all, the version was itself embedded in the AIR file. Surely we could just grab the version number from there, right?

Disappointingly, few have asked.

Disappointing because that argument exists to help you protect your application from downgrade attacks. Downgrade attacks work like this: some earlier version of your application has a vulnerability, but has since been patched. The attacker tricks your update mechanism into using the Update API to install that old version, thus re-introducing the vulnerability. Then they attack the vulnerability.

To protect against this attack, the application must validate before it begins the update that the version it’s updating to is, in fact, a newer version. During the update process itself, AIR will validate that the version number you’ve validated and passed to the update call does in fact match the version in the AIR file. If they don’t match exactly, the update will fail.

Why doesn’t AIR check that the version is newer? Because we didn’t want to impose a version numbering scheme on anyone.