Friday, 31 January 2014

Developing for IE8

I'm sure there are loads of posts out there that are more formal but I wanted to share some things I found out during testing of our site on IE8. We would all like to be blunt and tell our users that IE8 is rubbish and we won't support it but the reality is for most of us, some of our potential customers still use Windows XP and for one reason or another can't get a browser beyond IE8.

We have a medium size corporate who have already ordered our software and it was only then that we found out that our system needed to be IE8 compatible. This sounded easy enough, after all, we used bootstrap and jQuery, both of which already do a great job in working with IE8. The problem was, our site didn't work. It all seemed like a disaster where many pages either looked wrong or didn't work at all but using the IE Developer Tools (F12) and a little time and Bootstrap expertise from a colleague, we tracked down the issues fairly quickly and fixed them all in about 2 days.

1. Reserved words in Javascript

I had written my Javascript in bits and pieces, as is common, and hadn't taken much care over the script itself. I am not very familiar with Javascript. Anyway, IE8 doesn't like it when you use words that are normally reserved for variables. For instance, the word "class" is reserved and whereas most modern browsers can work out the context of the variable and know that "class" refers to a variable name, IE8 simply doesn't like it and crashes. Solution: Rename any reserved words such as "continue" or "class" where they are used for function or variable names.

2. Image widths and heights

I know you are not supposed to use the width and height tags in an image but they are a quick and easy way to make the image the correct size (don't worry I wasn't resizing a massive image into a smaller space!). Anyway, these worked in modern browsers but in IE8, the default CSS supplied by Bootstrap (width: auto) was applied instead. This made the images render at their full size, which in my case was slightly too big and caused things to overwrite. Solution: Pass the sizes in via a CSS class instead.

3. float-left and float-right

I'm not sure why this didn't work on IE8 but in my title bar, I have an icon and title floated into the left corner and a padlock icon floated to the right. I used bootstrap's float-left and float-right classes on the divs and all worked fine on the modern browsers. On IE8, however, the logo image was not taking up any space so the div width on the left was set to the width of the title (i.e. too narrow) and caused the title to flow onto the next line. Removing float-left just makes it go to 100% width as per a normal div and this pushes the float-right div onto the next line. Solution: Remove the float-left class from the left-hand div and then keeping the float-right div with its class name, move it to before the left hand div:
...
left hand content

4. Trailing commas on arrays

IE8 really doesn't like it when you have a comma after the last element in your array (var something = [a,b,c,];). It makes the array count increase and therefore the last element is null and this causes things to crash (funnily enough). Solution: Remove any trailing commas from your arrays.

5. Manual page layouts

This one is a pain if you have manually tweaked positions of elements to fit into a page. For instance, I had manually created a 2 x 2 grid to display 4 images and since IE8 has a different box model than the modern browsers, the layout all went funny. Solution: Stick with bootstrap or another library to provide these types of layout. Using bootstrap I could simply create some span columns, in my case combined with thumbnails functionality and achieve the same thing but with Bootstrap to cope with the older browsers.

6. Unsupported Javascript functionality

This occurs because older browsers don't support some of the functionality we are used to. For instance, event.preventDefault() doesn't work in IE8 with inline Javascript. Having a click handler directly on a button, for instance, will error in IE8 if you use preventDefault() because it doesn't exist on the global event object. You could use return false or event.returnValue = false but these are not cross-browser safe. I had another similar problem with window.innerHeight() which I should have obtained using jQuery width() instead. Solution: In most cases, if you use jQuery instead of inline Javascript, you can hide these problems. Attach a click handler using a jQuery selector in then call e.preventDefault() on the event that is passed to the jQuery function, this event is cross-browser safe and will not error. Obviously, you might have other properties that are not present in IE8, you will just need to test the site and Google the alternatives. Look for a jQuery alternative that will probably have already taken care of this for you.

7. Event Handlers firing twice in ASP.Net

I really don't understand how this would be different in IE8 but when using a button HTML control in an ASP.Net with onserverclick="eventHandler", these fire twice on IE8 but only once in other browsers. I only noticed when receiving two validation emails in IE8 whereas you get only 1 normally. Solution: Set type="button" in the HTML button which avoids the automatic submit behaviour.

8. Padding added to minimum height

This was a bug on older Firefox browsers but was also present in IE8. The IE8 box model was more sensible in that the padding and border were inside the width and height of a control. The W3C box model meant that padding, border and margin were all added outside the width and height which made it a nightmare when trying to adjust elements. The bug meant that if min-height (and min-width?) was set on an input, then the padding was incorrectly added to the outside of the width and height. Solution: Using a great modernizr hack from here adds another class to the html element which can then be used to detect the bug. In your css, you add something like:

.padding-added-to-minheight .input-block-level
{
    padding-top: 0px;
    padding-bottom: 0px;
}

Which removes the padding. You also have to make sure the height and line-height of the input elements are the same otherwise the text is not centred in the box. The first class name in the example is the one added by modernizr and the second one is a bootstrap class that adds the padding to the input elements by default.

Tuesday, 28 January 2014

The active result for the query contains no fields

Ever had this when calling into SQL Server from PDO in PHP? Well I have. It occurs because of the way in which SQL Server returns multiple results if you are calling a stored procedure with multiple statements in it. For instance, INSERT will return the number of rows affected, as will UPDATE. These are returned to PDO (but stripped out automatically when using SQL Server classes in .Net) which means you code, which looks like this:

$results = $command->queryRow();
$mobileEnabled = $results['mobileenabled'];

Even if your stored procedure appears to returning something like SELECT SCOPE_IDENTITY.

You need to do two things.

1) SET NOCOUNT ON at the top of your stored procedure
2) Ensure you use an alias for the returned value: SELECT SCOPE_IDENTITY() as mobileenabled

This should ensure you get no intermediate results and you can use array syntax to retrieve the value returned.

Wednesday, 22 January 2014

Keeping your GitHub project maintained

God bless Python Social Auth, it is useful, providing OAuth/OpenID type functionality to various Python frameworks including Django and Flask, it is laid out in a very useful way for people like myself looking to extend it and most importantly IT IS MAINTAINED.

I am the CTO for PixelPin, we replace passwords with pictures and one of the most important things for any add-on technology is to be compatible with web frameworks to make it as easy as possible for people to integrate. Despite the fact that we could potentially save some companies a LOT of money, if it seems hard to do then it smells like an amateur company and it 'feels' like it will be more of a hassle than a benefit.

One of my jobs therefore is to oversee the creation of various plugins and modules to suit different languages and frameworks. .Net, not a problem, PHP not too bad (although frameworks are more different than I would have thought) but Python? I am not a Python programmer but we really needed a plugin of some sort and I was pointed to Python Social Auth which had a very large and impressive list of providers. This implied it was widely used and widely useable so I spent some time setting up a Django site and downloaded the examples then by modifying the code for a PixelPin provider, managed to get it to work with minimal effort. I was already pleased. What pleased much more however was that once I had pushed my change to Github and created a Pull request, Matias Aguirre contacted me within a few hours, asked for some documentation and then merged the code into his project for everyone to use.

So what? Isn't that how it is supposed to work? Well yes, however, compare this with my experience of HybridAuth. This also looked impressive for PHP frameworks, indeed, it was already supported on many frameworks so adding a PixelPin provider would be straight-forward since the code was also laid out in a friendly manner. I made the changes, pushed and then created a Pull request but - nothing. The project has been dormant for almost a year. The forums are frequented by a few helpful people and lots of people complaining or asking questions, many of which are not answered including my question, "how can I add a new provider". Nothing has happened. This means that for all the HybridAuth based plugins I provide, I have to provide detailed instructions including how to patch the downloaded library with the changes needed for the PixelPin provider. I also have to create various patched versions of the library to provide on the PixelPin web site and all of this becomes very burdensome. Compare with Python Social Auth where the instructions are: Follow the instructions on the Python Social Auth site.

It is sad that the community has these projects which start well and then just stop dead. Will it need another project to carry on where it left off? Is the developer in prison? Did he just get fed up with maintaining it? Presumably others could also be making changes in Github but.....

Ah well. C'est la vie.

Friday, 3 January 2014

RSA Public Key Encryption between .Net, PHP and Java

Introduction

I have the unenviable task of communicating between a Java Android app, via a PHP web service to a .Net web service. This sounds a bit overkill but although I like PHP for simple REST APIs, it cannot handle a specific type of encryption that I decided to use in my database so I have to delegate to a .Net web service instead.

Anyway......one of the things I have been using recently is public/private key encryption to secure communications between the Android app and our web service to prove that the server has been involved with the handshake. One of the difficulties I had was trying to get the various flavours and permutations of encryption to work between the different platforms and languages. One of the major problems with encryption is that often if it doesn't work, you don't get many clues as to what is wrong.

Public Key Encrypt in Java, private key decrypt in PHP


I have already covered this before although I can't find the blog post! The functionality is built into Java so it is fairly straight-forward. Naturally you need a key pair, mine are just plain RSA 4096 bits long exported as .der format (not pem) created using openssl on the command line:

// Get the public key into the byte array keyBytes. Mine is read in directly from a .der file using a FileInputStream
// data can either be raw binary or in my case I call getBytes() on a string
X509EncodedKeySpec spec = new X509EncodedKeySpec(keyBytes);
KeyFactory kf = KeyFactory.getInstance("RSA");
PublicKey pk = kf.generatePublic(spec);
final Cipher cipher = Cipher.getInstance("RSA/ECB/OAEPWithSHA-1AndMGF1Padding");
cipher.init(Cipher.ENCRYPT_MODE, pk);
cipherText = cipher.doFinal(data);
// Optionally base64 encode the cipherText (which I do)

In my case I then send this data to a web service which then uses the private key to decrypt the data I have encrypted.

$key = file_get_contents('path/to/privatekey.pem');
openssl_private_decrypt(base64_decode($data), $decrypted, $key, OPENSSL_PKCS1_OAEP_PADDING)

As you might imagine, data is just the base64 encoded data from the Java app and $decrypted is an output parameter which is filled with the decrypted data. openssl_private_decrypt is a boolean function so you can test whether the decryption worked or not.

Public Key Encrypt in .Net, private key decrypt in Java

 In another scenario, I pass a public key to the .Net web service from the Android app so that the web service can encrypt some data that only the Android app can decrypt. In the .Net web service, I use a .Net port of the OWASP ESAPI security library but I extended it to provide public key encryption/decryption, something not included by default. To ,make this work correctly, however, I ended up having to use the .Net version of the Bouncy Castle encryption library. This meant the code ended up like this:

// public key is a Stream in this case but you can convert a byte[] to a stream using "new MemoryStream(publickey, false)"
// Some of the code is simply to convert between the MS representation of a key and the Bouncy Castle format
var rsaKeyParameters = (RsaKeyParameters)PublicKeyFactory.CreateKey(publickey);
var rsaParameters = new RSAParameters();
rsaParameters.Modulus = rsaKeyParameters.Modulus.ToByteArrayUnsigned();
rsaParameters.Exponent = rsaKeyParameters.Exponent.ToByteArrayUnsigned();
var rsa = new RSACryptoServiceProvider();
rsa.ImportParameters(rsaParameters);
return Convert.ToBase64String(rsa.Encrypt(Encoding.UTF8.GetBytes(plaintext), true));

Naturally, you need appropriate error checking etc. I haven't included it here to keep the examples tidy. This then gets returned ultimately to the Java app which has to decrypt it using its private key. The example is very similar to the first code listing above but it needs to use a different Key Specification and decrypt mode instead of encrypt mode (really?!).

PKCS8EncodedKeySpec spec = new PKCS8EncodedKeySpec(keyBytes);
KeyFactory kf = KeyFactory.getInstance("RSA");
PrivateKey pk = kf.generatePrivate(spec);
final Cipher cipher = Cipher.getInstance("RSA/ECB/OAEPWithSHA-1AndMGF1Padding");
cipher.init(Cipher.DECRYPT_MODE, key);
cipherText = cipher.doFinal(data);

You need to be careful about what is base64 encoded and what is in raw byte form (and add the converters in where needed). This is more confusing when your raw data is actually a string since it would be converted into bytes before encryption and encoding into a different string afterwards!