Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Java and AppStore receipt verification

I am trying to verify a payment receipt on server side. I am getting a {"status":21002, "exception":"java.lang.IllegalArgumentException"} in return

Here is the code:

private final static String _sandboxUriStr = "https://sandbox.itunes.apple.com/verifyReceipt";

public static void processPayment(final String receipt) throws SystemException
{
    final BASE64Encoder encoder = new BASE64Encoder();
    final String receiptData = encoder.encode(receipt.getBytes());


    final String jsonData = "{\"receipt-data\" : \"" + receiptData + "\"}";

    System.out.println(receipt);
    System.out.println(jsonData);

    try
    {
        final URL url = new URL(_sandboxUriStr);
        final HttpURLConnection conn = (HttpsURLConnection) url.openConnection();
        conn.setRequestMethod("POST");
        conn.setDoOutput(true);
        final OutputStreamWriter wr = new OutputStreamWriter(conn.getOutputStream());
        wr.write(jsonData);
        wr.flush();

        // Get the response
        final BufferedReader rd = new BufferedReader(new InputStreamReader(conn.getInputStream()));
        String line;
        while ((line = rd.readLine()) != null)
        {
            System.out.println(line);
        }
        wr.close();
        rd.close();
    }
    catch (IOException e)
    {
        throw new SystemException("Error when trying to send request to '%s', %s", _sandboxUriStr, e.getMessage());
    }
}

My receipt looks like this:

{\n\t"signature" = "[exactly_1320_characters]";\n\t"purchase-info" =
"[exactly_868_characters]";\n\t"environment" = "Sandbox";\n\t"pod" =
"100";\n\t"signing-status" = "0";\n}

Receipt data with a BASE64 encoded receipt looks like this:

{"receipt-data" : "[Block_of_chars_76x40+44=3084_chars_total]"}

Does someone have an Idea, or sample code how can I get from receipt string to reply JSON, mentioned here?

like image 522
Vetal Avatar asked Sep 14 '12 21:09

Vetal


People also ask

How do I verify my Apple receipt?

Use the production URL https://buy.itunes.apple.com/verifyReceipt when your app is live in the App Store. For more information on these endpoints, see verifyReceipt. Verify your receipt first with the production URL; then verify with the sandbox URL if you receive a 21007 status code.

How do I check if a receipt is valid?

Some stores use watermarked paper, and a fake receipt will be easy to spot because it doesn't have the watermark, or the pattern looks wrong. It is usually necessary to have a valid receipt for comparison. If receipts are too crisp, this can be another sign of a fake receipt.

What is receipt validation in app purchase?

Receipt validation is a way to protect against fraudulent in-app purchases made in the iOS and Android app stores, and is used to ensure transactions occurred as reported.

What is receipt verification?

Receipt verification is a systematic process by which a site verifies that what was specified and ordered is actually what is received.


2 Answers

21002 : The problem was at Base64 encoding inside Java. When I do the encoding inside IOS and use that as the request from server without any encoding in Java, then it worked.

switch (status) {
        case 21000:
            msg = "The App Store could not read the JSON object you provided";
            logger.info("\n  21000 : The App Store could not read the JSON object you provided. ");

        break;
    case 21002:
        msg = "The data in the receipt-data property was malformed.";
        logger.info("\n  21002 : The data in the receipt-data property was malformed..   ");
        break;
    case 21003:
        msg = "The data in the receipt-data property was malformed.";
        logger.info("\n  21003 : The receipt could not be authenticated. ");
        break;
    case 21004:
        msg = "TThe shared secret you provided does not match the shared secret on file for your account.";
        logger.info("\n  21004 : The shared secret you provided does not match the shared secret on file for your account. ");
        break;
    case 21005:
        msg = "The receipt server is not currently available.";
        logger.info("\n  21005 : The receipt server is not currently available. ");
        break;
    case 21006:
        msg = "This receipt is valid but the subscription has expired. When this status code is returned to your server, the receipt data is also decoded and returned as part of the response.";
        logger.info("\n  21006 : This receipt is valid but the subscription has expired. When this status code is returned to your server, the receipt data is also decoded and returned as part of the response. ");
        break;
    case 21007:
        msg = "This receipt is a sandbox receipt, but it was sent to the production service for verification.";
        logger.info("\n  21007 : This receipt is a sandbox receipt, but it was sent to the production service for verification. ");
        break;
    case 21008:
        msg = "This receipt is a production receipt, but it was sent to the sandbox service for verification.";
        logger.info("\n  21008 : This receipt is a production receipt, but it was sent to the sandbox service for verification. ");
        break;

    default:
        msg = "Active subscription.";
        logger.info("\n  0 : valid ....Active subscription. ");
        break;
    }
like image 63
Sameer Kazi Avatar answered Oct 23 '22 07:10

Sameer Kazi


CloseableHttpClient client = HttpClients.createDefault();

JSONObject requestData = new JSONObject();
requestData.put("receipt-data", recept);
requestData.put("password", password);


HttpPost httpPost = new HttpPost("https://sandbox.itunes.apple.com/verifyReceipt");
StringEntity entity = new StringEntity(requestData.toString());
httpPost.setEntity(entity);
httpPost.setHeader("Content-type", "application/x-www-form-urlencoded");

CloseableHttpResponse response = client.execute(httpPost);
BufferedReader rd = new BufferedReader(new InputStreamReader(response.getEntity().getContent()));

StringBuffer result = new StringBuffer();
String line = "";
while ((line = rd.readLine()) != null) {
    result.append(line);
}
System.out.println(result.toString());
response.close();
like image 30
user1827479 Avatar answered Oct 23 '22 07:10

user1827479