Friday 31 August 2012

Microsoft's Azure Mobile Services... and MonoTouch

Microsoft only recently announced a cool new addition to the Azure product offering: Mobile Services. They have done a great job at providing a getting started tutorial that gives you a working Windows 8 app in about 5 minutes (seriously, it's fast and easy).

Azure Mobile Services consist of an underlying REST API, so it didn't take long for someone (Chris Risner :-) to put a simple iOS client together. That was all the inspiration required to get it working with MonoTouch.

Actually there is already a MonoTouch todo-list example called Tasky and it has previously been adapted to use Apple's iCloud storage.

The finished code for TaskyAzure borrows heavily from the existing Tasky samples (eg. it uses MonoTouch.Dialog), and really only borrows the REST API urls and Json from Chris' post. I might be biased, but the C# code looks a lot simpler to me :-)
Visit github for the TaskyAzure code. The app looks like this:

And just to prove that the Windows 8 app and the MonoTouch app are both writing to the same Azure database, here is a screenshot of the Azure Management Portal showing the data storage:
Azure Mobile Services looks pretty interesting - look forward to seeing the official cross-platform APIs :-)

UPDATE: to try the code follow the Microsoft's instructions, including creating a free trial account. Once your Azure Mobile Service has been created, configure the app by updating the constants in the AzureWebService.cs class:

static string subdomain = "xxxxxx"; // your azure subdomain
static string MobileServiceAppId = "xxxxxx"; // your application key

Thursday 23 August 2012

In-app purchase vulnerability & MonoTouch

Earlier this year (around July) Apple announced that a vulnerability had been discovered in the in-app purchasing mechanism, which they discuss here. They provide some Objective-C code which:

  • Checks the information returned matches the information in the SKPayment
  • Checks that new transactions have a unique transaction ID
  • Verifies the SSL certificate
  • Verifies the receipt's signature

I've started a port of that code to MonoTouch, so far it only performs the first two mitigation steps. The VerificationController c# class is a gist.

Adding this code to a simple in-app purchase implementation would turn something like this:

into something like this:

where there is now an additional web request round-trip in your purchase code, plus a pile of comparisons to see whether the the StoreKit receipt matches the one you requested from iTunes directly. It also stores a list of every transaction ID in NSUserDefaults that is used to identify duplicates (which is an indication that the responses are being faked).

WARNING: the c# port currently only performs rudimentary checks comparing the receipt returned by StoreKit to one you've attempted to independently verify with iTunes. Without the SSL certificate and signature checks your code will still be vulnerable to sophisticated hacks on the DNS config to re-route requests and fake the responses. Please consider this a starting point for improving the security of your in-app purchase code.

NOTE: Apple says this vulnerability will be addressed in a future version of the operating system!

Friday 17 August 2012

Image Metadata with MonoTouch

Developers frequently want to know how to extract metadata from an image file on iOS using MonoTouch. One alternative is to use MonoTouch.ImageIO.CGImageSource to query the image (without even having to load it into memory).

Here is an example on gist that shows how to use the CGImageSource class, and a screenshot of how it looks (you'll have to add your own image to the project):

The key lines of code are:

var imageFilename = "img.jpg";
var url = new NSUrl(imageFilename, false);
CGImageSource myImageSource;
myImageSource = CGImageSource.FromUrl (url, null);
var ns = new NSDictionary();
var imageProperties = myImageSource.CopyProperties(ns, 0);
// Output ALL teh things
//Console.WriteLine(imageProperties.DescriptionInStringsFileFormat);

// Basic Properties
var width = imageProperties[CGImageProperties.PixelWidth];
var height = imageProperties[CGImageProperties.PixelHeight];
var orientation = imageProperties[CGImageProperties.Orientation];
var dimensions = String.Format ("Dimensions: {0}x{1} (orientation {2})", width, height, orientation);
Console.WriteLine(dimensions); 

// TIFF Properties
var tiff = imageProperties.ObjectForKey(CGImageProperties.TIFFDictionary) as NSDictionary;
var make = tiff[CGImageProperties.TIFFMake];
var model = tiff[CGImageProperties.TIFFModel];
var dt = tiff[CGImageProperties.TIFFDateTime];
var tprops = String.Format ("TIFF: {0} {1} {2}", make, model, dt);
Console.WriteLine(tprops); 

// GPS Properties
var gps = imageProperties.ObjectForKey(CGImageProperties.GPSDictionary) as NSDictionary;
var lat = gps[CGImageProperties.GPSLatitude];
var latref = gps[CGImageProperties.GPSLatitudeRef];
var lon = gps[CGImageProperties.GPSLongitude];
var lonref = gps[CGImageProperties.GPSLongitudeRef];
var loc = String.Format ("GPS: {0} {1}, {2} {3}", lat, latref, lon, lonref);
Console.WriteLine(loc); 

// EXIF Properties
var exif = imageProperties.ObjectForKey(CGImageProperties.ExifDictionary) as NSDictionary;
var fn = exif[CGImageProperties.ExifFNumber];
var focal = exif[CGImageProperties.ExifFocalLength];
var eprops = String.Format ("EXIF: Fstop {0} FocalLength {1}", fn, focal);
Console.WriteLine(eprops); 
Xamarin already has a recipe explaining how to save a photo with metadata.