When an user purchases your app, the delivery engine at the Firefox Marketplace generates a receipt, which is a specific binary signature uniquely identifying this deal. This series of bytes is downloaded to the mobile of the buyer, added to the code of your app.
Verifying that a running App has been legally installed simply consists in checking the validity of the several fields of the receipt, which, again, is specific and unique to each installed instance of your app.
The simplest way to verify a receipt is to use the well-documented receiptVerifier library. If you decide to take this path, then you may stop reading me, or you may pursue if you are interested in understanding the underlying mechanism.
Another reason is that the receiptVerifier library is purely JavaScript. Hence, if, like me, you choose to extend the receipt checking on the Server Side using java only, stay here. But if your app is HTML-only, and the Server doesn't do anything but serve static files, consider using the receiptVerifier library.
navigator.mozApps.getSelf()
is the preferred way
for accessing to the contents of the receipt.
mozApps
is a property of the
Navigator
interface pointing at
an Apps
object.
The Apps
object collects infos for all applications "Open Web"
that are installed in the app's repository on the user's device.
Hence,
navigator.mozApps.getSelf()
gets the
App
object for the app currently running, that is, your app.
In the App
object, receipts
is a field
that gathers all receipts pertaining to your app.
And, if this field is null
, you may definitively assert
that the running application is not genuine!
Here is a simple javascript example for reading receipts:
var request = window.navigator.mozApps.getSelf(); request.onsuccess = function() { if ( !request.result || // the app is not installed !request.result.receipts // the app has no receipts ) { alert("Impostor intrusion. Call the Police."); }else { var receipts = request.result.receipts; // pursue with more fancy checks } }; request.onerror = function() { alert("Error: " + request.error.name); };
Of course, a non-null receipt doesn't mean it is a valid receipt, and more tests are required at a finer granularity.
As stated above, the verification is done Server Side, in pure Java.
This is what was chosen.
Therefore, Client Side, the javascript code in our app does the minimum.
It reads the App object and issues an XMLHttpRequest
to our Server, passing the entire App
record in Jason.
The Server checks the validity, and returns with a 402 code if
the receipt was detected being invalid.
Below is the Javascript code:
function verifyReceipt() { var request = window.navigator.mozApps.getSelf(); request.onsuccess = function() { if ( !request.result || // the app is not installed !request.result.receipts // the app has no receipts ) { alert("Warning: Invalid Receipt")); }else { checkCredentials(request.results); // pursue more fancy checks } }; request.onerror = function() { alert("Error: " + request.error.name); }; } function checkCredentials(app) { var appRecord = ""; if (app) { var appObject = {}; for (var name in app) appObject[name] = app[name]; appRecord = JSON.stringify(appObject); } var xhr = new XMLHttpRequest({'mozSystem': true}); xhr.withCredentials = true; xhr.open("POST", "http://myserver.jaxo.com?OP=checkReceipt", true); xhr.onreadystatechange = function () { if ((this.readyState === 4) && (this.status !== 200) && (this.status !== 0) ) { if (this.status === 402) { // Payment Required var obj = JSON.parse(this.responseText); alert("Warning: " + obj["msg"] + "\nInvalid Receipt")); }else { alert("Error: ", "Server code " + this.status); } } }; xhr.send(appRecord); }
Assuming a Java Servlet handles the HTTP request, the introductory code might look something as:
import java.io.IOException; import java.io.InputStream; import javax.servlet.http.HttpServlet; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; import org.apache.commons.io.IOUtils; import com.jaxo.mozutil.ReceiptVerifier.java; @SuppressWarnings("serial") public class MyServlet extends HttpServlet { public void doPost(HttpServletRequest req, HttpServletResponse resp) throws IOException { String op = req.getParameter("OP"); if (op.equals("checkReceipt")) { InputStream in = req.getInputStream(); String appRecord = IOUtils.toString(in); IOUtils.closeQuietly(in); ReceiptVerifier.Status status = ReceiptVerifier.verify(appRecord); if (status == ReceiptVerifier.Status.OK) { resp.setStatus(HttpServletResponse.SC_OK); }else { resp.setStatus(HttpServletResponse.SC_PAYMENT_REQUIRED); } }else { resp.setStatus(HttpServletResponse.SC_BAD_REQUEST); } } }
ReceiptVerifier
is the class that performs the verification
of the Receipt, and here is the source code:
ReceiptVerifier.java (which makes use of
Json.java.)
The verification is made of two steps:
This chapter would be incomplete without saying a word on "testing".
Why just "a word"?
Simply because
Firefox OS Simulator 4.0 has it all.
It is well documented.
Using it will fulfill all your needs.
You may get the latest version in here.