Worst Firefox feature implementation ever?

by Jason on

A word to the wise: don’t allow Firefox to store your usernames and passwords. This “feature” is incredibly ill conceived and can result in your username and password for various sites being exposed. Frankly unless you’re careful, it will result in this depending on the sites you use.

We’ve been struggling with this on one of our sites for some time, believing (incorrectly) that our code was defaulting the username and password into certain incorrect fields. After doing a thorough review we learned that the behavior was only happening to Firefox users (3.0+ specifically for us, but had no 2.0 users to validate against). Turns out their implementation of cached usernames and passwords is craptastic at best, negligent at worst. Firefox “remembers” your username and password and then attempts to store it into every page that has a “password” type input field that is preceeded by a plain “text” type input field. This means that if a website you visit happens to have multiple fields (for whatever reason) that are of the type “password” Firefox will store your password in it and your username in the field before it (if you are allowing usernames and passwords to be remembered by firefox.)

Here’s a bug report over at bugzilla: https://bugzilla.mozilla.org/show_bug.cgi?id=496838

This bug has been around awhile, but for us only recently reared it’s ugly head.

Why this sucks in the real world: One of our products has an Account Number field that we use to allow the user to store some information that they might want to shield from prying eyes / neighbors. As such it’s of the type “password”. This field is not required and exists on a secondary html element “tab”. Firefox’s stored password “feature” could have caused serious exposure of people’s usernames and passwords had we not been alerted to it and advised users of what was going on. Now we’re faced with a dilemma, code to “blank out” these fields when it’s indeed empty and Firefox has stored info in it, use “autocomplete=off” attribute on those fields (even though it’s super handy to auto complete those fields in other browsers), or switch to plain text fields.

We love Firefox, so much so that we push it on our users at every turn to help them be more productive and, most importantly, more secure. This terrible implementation is a perfect example of how developers can overlook a simple feature while implementing better security and leave their users completely exposed.

Remember though, for whatever it’s flaws, it’s still quite great compared to IE.

Just Read: "Best Kept Secrets of Peer Code Review"

by Jason on

One of our business partners picked up this book at the door64 tech fair in Austin recently and tossed it off to me.

I wanted to mention that I thoroughly enjoyed the book. An easy read (I started and finished it while watching some TV Monday night), the main focus is on lightweight code reviews. For those of us in small development shops it can be hard to justify to management why time on code reviews (personal or peer based) needs to be spent and how it directly saves money for the business. When it comes to books on peer code review there just aren’t that many so I was psyched when this dropped in my lap but a little hesitant as it looked to be basically adware. Luckily I proven wrong.

I’d recommend this short primer to anyone who is struggling with the “code -> test -> deploy” process practiced at a lot of development shops or wants to justify to management the need for peer (or personal) code reviews. When dealing with management it’s often difficult to justify why programmers want to follow process X or process Y and this book is lightweight enough to pass onto any layman.

Above all the best section in this book, for me, deals with how to conduct a personal code review. In a smaller development shop you may be the only one to work on a single product or in a particular language or focus. (For instance in many past ventures I have been the only developer for various products.) This can be a severe disadvantage at times, for while the lone developer has almost complete leeway, they do not always know “is this right” or even “is this going to work.” When coding solo, my process was to to code, personally test, send to testing peeps (if available), patch if necessary and publish. This has sucked beyond all measure at times due to bugs getting to customers and past testing. Occasionally you just need someone to give you a push in the right direction and in my case this book shoved me towards individual checklists to run through when reviewing your own code as well as helping establish the proper amount of time to set aside to do a thorough personal review. While that may sound minor, sometimes even the most minor thing can help push you in a better direction. If formalizing the personal review process helps you catch even 10% more bugs that would be customer facing, then this book was a worthwhile read. Beyond that, keeping a checklist of personal common mistakes and ensuring that you aren’t continually making them will make you a better programmer.

A few caveats: the book isn’t a “how to conduct peer code reviews” however it does arm you with enough knowledge that you can track down the process that would work for your team. They also promote their review software “Code Collaborator” a lot, however that’s ok, everyone has to make a living.

The only drawback (unless you’re one of those that hate advertising in any degree) is that this book is a bit too lightweight. I hope that at some point Cohen expands on the concept with a lot more details, in depth case studies, real world examples and general content. At that point I would probably take this from the “personal reading” stack and shuffle it over to required reading.

Update: Click the image above to order from Amazon or click here to get a free copy from SmartBear

Adobe AIR 1.5 and SQLite example

by Jason on

I’ve been asked a couple of times about how to track an adobe AIR application you’ve developed without disclosing personal information or requiring user interaction.

My answer to this is always the same: I usually store a randomly generated key in the SQLite database when the application is first run.

I’ve decided to upload some code to demonstrate my approach to synchronous database connections in Adobe AIR. The version of the code provided is a bit stripped down from what I usually use (my main code provides for both synchronous and asynchronous connectivity but I stripped a lot out for this example and will provide a seperate example for asynch at some point int he future.)

To reiterate: This code may be overkill for some people and uses my custom namespaces.

Now that I’ve got that out of the way:

Download: SQLiteExample.air OR SQLiteExample.zip License: Creative Commons Attribution 3.0 United States License (Please keep or attribute name in code comments etc.)

Quick and dirty explanation: Since this is a lightweight application I use my trusty airDB javascript namespace. airDB is just a wrapper I wrote to simplify synchronous SQLite connections to the air database. Three main methods are really all you need to understand to get started (see code as well method list below). Those are airDB.init(), airDB.fetchRS and airDB.execute. If you’re just looking for an explanation of how to connect / work with a SQLite database in AIR read the documentation here or check out my source file ns.airDB.js (I’ve heavily commented it hopefully to help explain things but frankly I’m bad at that so the official Adobe help is probably the way to go).

Within the startup method in the index.html file you’ll find that I’m calling airDB.init with an object passed in.

// initiate db connection / test schema etc // see init in ns.airDB.js for more information airDB.init({ databaseName: ‘example.db’, // name of our database fetchJSArray: 1, // force fetchRS to return a javascript array openImmediately: 1, // open the database on init testSchema: 1, // test the database on init traceLog: 1 // verbose log to air.trace });

A little information about ns.airDB.js:

  • airDB.init (options)

    • performs initial setup of connection variables needed to access the SQLite database in synchronous modeSee the init method for default options and their use
    • Returns: null
  • airDB.open()

    • opens the database connection. Requires that airDB.init has specified a filename to connect to
    • [Optional]; can be called directly from init if openImmediately is passed in as 1.
    • Returns: null
  • airDB.close()

    • closes the database connection
    • Returns: null
  • airDB.test(forceFail)

    • performs a basic schema test to see if the database is setup. (set forceFail = true to recreate the database regardless of test results).
    • Note: This method should be rewritten to each specific application as schema will vary per application. The provided one is super simple for examples sake.
    • [Optional]: can be called directly from init if testSchema is passed in as 1.
    • Returns: null
  • airDB.connected

    • Returns: boolean (whether connection is present or not)
  • airDB.fetchRS(sqlStatement)

    • performs a SQL Select statement or other statement that is expected to return a recordset.If fetchJSArray (in init) is = 1, we return a custom javascript object that’s formatted like the following: { rows: number of rows returned, data: array( row 1 => {columnName1: columnValue1, ColumnName2, ColumnValue2} ) } (using this type in the example code)

      if fetchJSArray (in init) is = 0, we return a flash.data object (More information on handling that return type can be found here)

    • Returns: Javascript Object or Flash.Data object dependent on init option “fetchJSArray”
  • airDB.execute(sqlStatement)

    • executes a sql statement (insert / update / delete / drop etc.)
    • Returns: null
  • airDB.sqlText(string)

    • replaces any single quotes in a string with double quotes
    • Returns: string
  • airDB.sqlNumber(number)

    • ensures that a number passed in is numeric / ok to execute in a sql statement
    • Returns: number (returns 0 if number is not numeric)
After init in the “startup” function I call airKey.init airKey is a javascript namespace solely created for generating a random string of however many characters you wish and storing that in the local database. I won’t go into too much detail here because it’s super easy to understand (generate a key if one isn’t present and store it in the database, if one is already present, retrieve it.) (see ns.airKey.js)

I then call a custom function called “getNames()”. getNames is just an example of how to call a select statement and use the custom JS array to output data. In the example provided I fetch the column names as well as the values to generate the table of “names” within the main air window. When looking at the function you might ask why I’m using a custom javascript recorset that fetchRS returns rather than the standard flash.data object. 1 : my custom object returns the number of rows as a static int, so that I never have to calculate that. 2 : I also don’t want to pass flash objects around because it’s caused memory leaks for me in the past that were a pain. (However if that’s your thing, remember you can just set fetchJSArray = 0 (or not pass in that option at all) in init to just use standard access methods. (I do this for large databases because transforming the data on large recordsets is a bad idea)

Other than that, this example is pretty basic. Adding a name using airDB.execute as well as rebuilding the database from scratch is included in the example.

Finally: a bit more about airKey. by storing a random string I can test against that when the application performs URLRequests against an owned web service. This lets me generate reports (or turn off a particular app) without having to be too intrusive to the user. To make this more robust I highly recommend using the local Encrypted Store available to you in AIR applications. (If you’re worried about piracy of your application the encrypted store will help a little but frankly right now AIR is not the platform (for HTML/JS applications) to use if that’s your concern as source code is freely available to the user.)

If you have any questions feel free to ask in the comments and I’ll answer.

Adobe AIR print css and html printing hack

by Jason on

Posting to give an example of how to print using the local browser using Adobe AIR.  This is in response to this AIR forum thread.

I need to have an alternate stylesheet for my application so I embed those styles in an inline style tag from a css file.  I also do not want to include all the scripts and external references that my application may have on the particular page so I strip out only the body and build a new page from it.

This probably isn’t for everyone but might give you a good idea of where to start (or provide an example of how not to do this).

Note this uses jQuery’s .html function, but you could just as easily replace that with document.getElementById(‘MyPrintableStuff’).innerHTML();

 

/
			    Quick and dirty print function for AIR
			    @htmlTitle string    :    text to be placed in <title> tag of the document
			    @printCSSFile    :    css file to parse, should be relative to the app ie ‘stylesheets/print.css’
			/
			function printThis(htmlTitle, printCSSFile)
			{
			    var locFileStream = false,
			        styleFile = air.File.applicationDirectory;
			        locStyles = ‘’;

<span class="rem">/* fetch css definitions for print stylesheet and store in locStyles */</span>
			styleFile = styleFile.resolvePath(printCSSFile);
			
			locFileStream = <span class="kwrd">new</span> air.FileStream();
			locFileStream.open(styleFile, air.FileMode.READ);
			locStyles = locFileStream.readUTFBytes(locFileStream.bytesAvailable);
			locFileStream.close();
			
			<span class="rem">/* HTML to string */</span>
			locHTML = $(<span class="str">'body'</span>).html();
			
			<span class="rem">/* wrap with doc tags, add &quot;window.print&quot; to the onload */</span>
			locHTML = <span class="str">'&lt;!DOCTYPE html PUBLIC &quot;-//W3C//DTD XHTML 1.0 Strict//EN&quot; &quot;http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd&quot;&gt;'</span> +
			        <span class="str">'&lt;html xmlns=&quot;http://www.w3.org/1999/xhtml&quot; xml:lang=&quot;en&quot; lang=&quot;en&quot;&gt;'</span> +
			        <span class="str">'&lt;head&gt;'</span> +
			        <span class="str">'&lt;title&gt;'</span> + htmlTitle + <span class="str">'&lt;/title&gt;'</span> +
			        <span class="str">'&lt;style type=&quot;text/css&quot;&gt;'</span> +
			        locStyles +
			        <span class="str">'&lt;/style&gt;'</span> +
			        <span class="str">'&lt;/head&gt;'</span> +
			        <span class="str">'&lt;body onload=&quot;window.print()&quot;&gt;'</span> +
			            locHTML +
			        <span class="str">'&lt;/body&gt;'</span> +
			        <span class="str">'&lt;/html&gt;'</span>;
			
			
			<span class="rem">/* output the file to a temporary file in user's docs, launch url in native browser</span>
			

TODO: delete tmp file after launch */ var tmpFile = air.File.documentsDirectory; tmpFile = tmpFile.resolvePath("temp.html"); tmpURLToOpen = tmpFile.url;

var tmpFileStream = <span class="kwrd">new</span> air.FileStream();
			tmpFileStream.open(tmpFile, air.FileMode.WRITE);
			tmpFileStream.writeUTFBytes(locHTML);
			tmpFileStream.close();
			
			var locURLReq = <span class="kwrd">new</span> air.URLRequest(tmpURLToOpen);
			air.navigateToURL(locURLReq);
			
			<span class="rem">/* null objects */</span>
			locURLReq = <span class="kwrd">null</span>;
			tmpFileStream = <span class="kwrd">null</span>;
			locFileStream = <span class="kwrd">null</span>;
			styleFile = <span class="kwrd">null</span>;
			

}