diff --git a/src/org/linphone/purchase/InAppPurchaseActivity.java b/src/org/linphone/purchase/InAppPurchaseActivity.java index 27db5dd46..fd7bdfdd7 100644 --- a/src/org/linphone/purchase/InAppPurchaseActivity.java +++ b/src/org/linphone/purchase/InAppPurchaseActivity.java @@ -25,6 +25,8 @@ import org.linphone.LinphoneManager; import org.linphone.R; import org.linphone.core.LinphoneProxyConfig; import org.linphone.mediastream.Log; +import org.linphone.xmlrpc.XmlRpcHelper; +import org.linphone.xmlrpc.XmlRpcListenerBase; import android.app.Activity; import android.content.Intent; @@ -81,6 +83,7 @@ public class InAppPurchaseActivity extends Activity implements InAppPurchaseList public void onServiceAvailableForQueries() { email.setText(inAppPurchaseHelper.getGmailAccount()); email.setEnabled(false); + inAppPurchaseHelper.getPurchasedItemsAsync(); } @@ -108,9 +111,15 @@ public class InAppPurchaseActivity extends Activity implements InAppPurchaseList } @Override - public void onPurchasedItemConfirmationQueryFinished(Purchasable item) { - if (item != null) { - Log.d("[In-app purchase] Item bought, expires " + item.getExpireDate()); + public void onPurchasedItemConfirmationQueryFinished(boolean success) { + if (success) { + XmlRpcHelper xmlRpcHelper = new XmlRpcHelper(); + xmlRpcHelper.createAccountAsync(new XmlRpcListenerBase() { + @Override + public void onAccountCreated(String result) { + //TODO + } + }, getUsername(), email.getText().toString(), null); } } @@ -118,7 +127,13 @@ public class InAppPurchaseActivity extends Activity implements InAppPurchaseList public void onClick(View v) { Purchasable item = (Purchasable) v.getTag(); if (v.equals(recoverAccountButton)) { - inAppPurchaseHelper.recoverAccount(getUsername(), item.getPayload(), item.getPayloadSignature()); + XmlRpcHelper xmlRpcHelper = new XmlRpcHelper(); + xmlRpcHelper.createAccountAsync(new XmlRpcListenerBase() { + @Override + public void onAccountCreated(String result) { + //TODO + } + }, getUsername(), email.getText().toString(), null); } else { inAppPurchaseHelper.purchaseItemAsync(item.getId(), getUsername()); } @@ -126,7 +141,7 @@ public class InAppPurchaseActivity extends Activity implements InAppPurchaseList @Override protected void onActivityResult(int requestCode, int resultCode, Intent data) { - inAppPurchaseHelper.parseAndVerifyPurchaseItemResultAsync(requestCode, resultCode, data, getUsername()); + inAppPurchaseHelper.parseAndVerifyPurchaseItemResultAsync(requestCode, resultCode, data, getUsername(), email.getText().toString()); } @Override @@ -163,7 +178,13 @@ public class InAppPurchaseActivity extends Activity implements InAppPurchaseList text.setText("Buy account (" + item.getPrice() + ")"); ImageView image = (ImageView) layout.findViewById(R.id.image); image.setTag(item); - image.setOnClickListener(this); + image.setOnClickListener(this);XmlRpcHelper xmlRpcHelper = new XmlRpcHelper(); + xmlRpcHelper.createAccountAsync(new XmlRpcListenerBase() { + @Override + public void onAccountCreated(String result) { + //TODO + } + }, getUsername(), email.getText().toString(), null); buyItemButton = image; buyItemButton.setEnabled(usernameOk); diff --git a/src/org/linphone/purchase/InAppPurchaseHelper.java b/src/org/linphone/purchase/InAppPurchaseHelper.java index 25fbf2f63..de4ad6c78 100644 --- a/src/org/linphone/purchase/InAppPurchaseHelper.java +++ b/src/org/linphone/purchase/InAppPurchaseHelper.java @@ -240,13 +240,13 @@ public class InAppPurchaseHelper { ArrayList purchaseDataList = purchasedItems.getStringArrayList(RESPONSE_INAPP_PURCHASE_DATA_LIST); ArrayList signatureList = purchasedItems.getStringArrayList(RESPONSE_INAPP_SIGNATURE_LIST); continuationToken = purchasedItems.getString(RESPONSE_INAPP_CONTINUATION_TOKEN); - + for (int i = 0; i < purchaseDataList.size(); ++i) { String purchaseData = purchaseDataList.get(i); String signature = signatureList.get(i); Log.d("[In-app purchase] " + purchaseData); - Purchasable item = verifySignatureAndGetExpire(purchaseData, signature); + Purchasable item = verifySignature(purchaseData, signature); if (item != null) { items.add(item); } @@ -269,6 +269,25 @@ public class InAppPurchaseHelper { }).start(); } + public void parseAndVerifyPurchaseItemResultAsync(int requestCode, int resultCode, Intent data, String username, String email) { + if (requestCode == ACTIVITY_RESULT_CODE_PURCHASE_ITEM) { + int responseCode = data.getIntExtra(RESPONSE_CODE, 0); + + if (resultCode == Activity.RESULT_OK && responseCode == RESPONSE_RESULT_OK) { + String payload = data.getStringExtra(RESPONSE_INAPP_PURCHASE_DATA); + String signature = data.getStringExtra(RESPONSE_INAPP_SIGNATURE); + + XmlRpcHelper xmlRpcHelper = new XmlRpcHelper(); + xmlRpcHelper.verifySignatureAsync(new XmlRpcListenerBase() { + @Override + public void onSignatureVerified(boolean success) { + mListener.onPurchasedItemConfirmationQueryFinished(success); + } + }, payload, signature); + } + } + } + private void purchaseItem(String productId, String sipIdentity) { Bundle buyIntentBundle = null; try { @@ -295,48 +314,6 @@ public class InAppPurchaseHelper { }).start(); } - public void parseAndVerifyPurchaseItemResultAsync(int requestCode, int resultCode, Intent data, String username) { - if (requestCode == ACTIVITY_RESULT_CODE_PURCHASE_ITEM) { - int responseCode = data.getIntExtra(RESPONSE_CODE, 0); - String purchaseData = data.getStringExtra(RESPONSE_INAPP_PURCHASE_DATA); - String signature = data.getStringExtra(RESPONSE_INAPP_SIGNATURE); - - if (resultCode == Activity.RESULT_OK && responseCode == RESPONSE_RESULT_OK) { - verifySignatureAndCreateAccountAsync(new VerifiedSignatureListener() { - @Override - public void onParsedAndVerifiedSignatureQueryFinished(Purchasable item) { - if (item != null) { - mListener.onPurchasedItemConfirmationQueryFinished(item); - } - } - }, purchaseData, signature, username); - } else { - Log.e("[In-app purchase] Error: resultCode is " + resultCode + " and responseCode is " + responseCodeToErrorMessage(responseCode)); - mListener.onError(responseCodeToErrorMessage(responseCode)); - } - } - } - - public void recoverAccount(String sipUsername, String purchasedData, String signature) { - XmlRpcHelper helper = new XmlRpcHelper(); - helper.createAccountAsync(new XmlRpcListenerBase() { - @Override - public void onAccountCreated(String result) { - mListener.onRecoverAccountSuccessful(true); - } - }, mGmailAccount, sipUsername, purchasedData, signature, mGmailAccount, null); - } - - public void activateAccount(String sipUsername, String purchasedData, String signature) { - XmlRpcHelper helper = new XmlRpcHelper(); - helper.activateAccountAsync(new XmlRpcListenerBase() { - @Override - public void onAccountActivated(String result) { - mListener.onActivateAccountSuccessful(true); - } - }, mGmailAccount, sipUsername, purchasedData, signature); - } - public void destroy() { mContext.unbindService(mServiceConn); } @@ -359,67 +336,22 @@ public class InAppPurchaseHelper { return emailPattern.matcher(email).matches(); } - private Purchasable verifySignatureAndGetExpire(String purchasedData, String signature) { + private Purchasable verifySignature(String payload, String signature) { XmlRpcHelper helper = new XmlRpcHelper(); - Object result = helper.getAccountExpire(mGmailAccount, purchasedData, signature); - long longExpire = -1; - String expire = (String)result; - - try { - longExpire = Long.parseLong(expire); - } catch (NumberFormatException nfe) { - Log.e("[In-app purchase] Server failure: " + result); - mListener.onError(expire); - return null; - } - - try { - JSONObject json = new JSONObject(purchasedData); - String productId = json.getString(PURCHASE_DETAILS_PRODUCT_ID); - Purchasable item = new Purchasable(productId); - item.setExpire(longExpire); - item.setPayloadAndSignature(purchasedData, signature); - //TODO parse JSON result to get the purchasable in it - return item; - } catch (JSONException e) { - Log.e(e); + if (helper.verifySignature(payload, signature)) { + try { + JSONObject json = new JSONObject(payload); + String productId = json.getString(PURCHASE_DETAILS_PRODUCT_ID); + Purchasable item = new Purchasable(productId); + item.setPayloadAndSignature(payload, signature); + return item; + } catch (JSONException e) { + Log.e(e); + } } return null; } - private void verifySignatureAndCreateAccountAsync(final VerifiedSignatureListener listener, final String purchasedData, final String signature, String username) { - XmlRpcHelper helper = new XmlRpcHelper(); - helper.createAccountAsync(new XmlRpcListenerBase() { - @Override - public void onAccountCreated(String result) { - try { - long longExpire = -1; - String expire = (String)result; - - try { - longExpire = Long.parseLong(expire); - } catch (NumberFormatException nfe) { - Log.e("[In-app purchase] Server failure: " + result); - listener.onParsedAndVerifiedSignatureQueryFinished(null); - mListener.onError(result); - return; - } - - JSONObject json = new JSONObject(purchasedData); - String productId = json.getString(PURCHASE_DETAILS_PRODUCT_ID); - Purchasable item = new Purchasable(productId); - item.setExpire(longExpire); - item.setPayloadAndSignature(purchasedData, signature); - //TODO parse JSON result to get the purchasable in it - listener.onParsedAndVerifiedSignatureQueryFinished(item); - return; - } catch (JSONException e) { - Log.e(e); - } - } - }, mGmailAccount, username, purchasedData, signature, mGmailAccount, null); - } - interface VerifiedSignatureListener { void onParsedAndVerifiedSignatureQueryFinished(Purchasable item); } diff --git a/src/org/linphone/purchase/InAppPurchaseListener.java b/src/org/linphone/purchase/InAppPurchaseListener.java index 8f44ec751..a0f17878a 100644 --- a/src/org/linphone/purchase/InAppPurchaseListener.java +++ b/src/org/linphone/purchase/InAppPurchaseListener.java @@ -43,9 +43,9 @@ public interface InAppPurchaseListener { /** * Callback called when the purchase has been validated by our external server - * @param item the item the user just bought + * @param success true if ok, false otherwise */ - void onPurchasedItemConfirmationQueryFinished(Purchasable item); + void onPurchasedItemConfirmationQueryFinished(boolean success); /** * Callback called when the account has been recovered (or not) diff --git a/src/org/linphone/purchase/InAppPurchaseListenerBase.java b/src/org/linphone/purchase/InAppPurchaseListenerBase.java index 06b054f13..b99a97ddc 100644 --- a/src/org/linphone/purchase/InAppPurchaseListenerBase.java +++ b/src/org/linphone/purchase/InAppPurchaseListenerBase.java @@ -22,7 +22,7 @@ public class InAppPurchaseListenerBase implements InAppPurchaseListener { } @Override - public void onPurchasedItemConfirmationQueryFinished(Purchasable item) { + public void onPurchasedItemConfirmationQueryFinished(boolean success) { // TODO Auto-generated method stub } diff --git a/src/org/linphone/xmlrpc/XmlRpcHelper.java b/src/org/linphone/xmlrpc/XmlRpcHelper.java index 10e3bcfa6..2cd684323 100644 --- a/src/org/linphone/xmlrpc/XmlRpcHelper.java +++ b/src/org/linphone/xmlrpc/XmlRpcHelper.java @@ -12,7 +12,6 @@ import de.timroes.axmlrpc.XMLRPCException; import de.timroes.axmlrpc.XMLRPCServerException; public class XmlRpcHelper { - public static final String OS = "google"; public static final String SERVER_ERROR_INVALID_ACCOUNT = "ERROR_INVALID_ACCOUNT"; public static final String SERVER_ERROR_PURCHASE_CANCELLED = "ERROR_PURCHASE_CANCELLED"; public static final String SERVER_ERROR_RECEIPT_PARSING_FAILED = "ERROR_RECEIPT_PARSING_FAILED"; @@ -34,7 +33,7 @@ public class XmlRpcHelper { } } - public void createAccountAsync(final XmlRpcListener listener, String gmailAccount, String username, String payload, String signature, String email, String password) { + public void createAccountAsync(final XmlRpcListener listener, String username, String email, String password) { if (mXmlRpcClient != null) { mXmlRpcClient.callAsync(new XMLRPCCallback() { @Override @@ -62,17 +61,17 @@ public class XmlRpcHelper { Log.e(error); listener.onError(error.toString()); } - }, "create_account_from_in_app_purchase", gmailAccount, username, payload, signature, OS, email, password == null ? "" : password); + }, "create_account", username, email, password == null ? "" : password); } else { Log.e(CLIENT_ERROR_INVALID_SERVER_URL); listener.onError(CLIENT_ERROR_INVALID_SERVER_URL); } } - public String createAccount(String gmailAccount, String username, String payload, String signature, String email, String password) { + public String createAccount(String username, String email, String password) { if (mXmlRpcClient != null) { try { - Object object = mXmlRpcClient.call("create_account_from_in_app_purchase", gmailAccount, username, payload, signature, OS, email, password == null ? "" : password); + Object object = mXmlRpcClient.call("create_account", username, email, password == null ? "" : password); String result = (String)object; Log.d("createAccount: " + result); @@ -91,63 +90,6 @@ public class XmlRpcHelper { return null; } - public void getAccountExpireAsync(final XmlRpcListener listener, String gmailAccount, String payload, String signature) { - if (mXmlRpcClient != null) { - mXmlRpcClient.callAsync(new XMLRPCCallback() { - @Override - public void onServerError(long id, XMLRPCServerException error) { - Log.e(error); - listener.onError(error.toString()); - } - - @Override - public void onResponse(long id, Object object) { - String result = (String)object; - Log.d("getAccountExpireAsync: " + result); - - if (result.startsWith("ERROR_")) { - Log.e(result); - listener.onError(result); - return; - } - - listener.onAccountExpireFetched(result); - } - - @Override - public void onError(long id, XMLRPCException error) { - Log.e(error); - listener.onError(error.toString()); - } - }, "get_expiration_date", gmailAccount, payload, signature, OS); - } else { - Log.e(CLIENT_ERROR_INVALID_SERVER_URL); - listener.onError(CLIENT_ERROR_INVALID_SERVER_URL); - } - } - - public String getAccountExpire(String gmailAccount, String payload, String signature) { - if (mXmlRpcClient != null) { - try { - Object object = mXmlRpcClient.call("get_expiration_date", gmailAccount, payload, signature, OS); - String result = (String)object; - Log.d("getAccountExpire: " + result); - - if (result.startsWith("ERROR_")) { - Log.e(result); - return null; - } - return result; - - } catch (XMLRPCException e) { - Log.e(e); - } - } else { - Log.e(CLIENT_ERROR_INVALID_SERVER_URL); - } - return null; - } - public void getAccountExpireAsync(final XmlRpcListener listener, String username, String password) { if (mXmlRpcClient != null) { mXmlRpcClient.callAsync(new XMLRPCCallback() { @@ -176,7 +118,7 @@ public class XmlRpcHelper { Log.e(error); listener.onError(error.toString()); } - }, "get_expiration_for_account", username, password, OS); + }, "get_expiration_for_account", username, password); } else { Log.e(CLIENT_ERROR_INVALID_SERVER_URL); listener.onError(CLIENT_ERROR_INVALID_SERVER_URL); @@ -186,7 +128,7 @@ public class XmlRpcHelper { public String getAccountExpire(String username, String password) { if (mXmlRpcClient != null) { try { - Object object = mXmlRpcClient.call("get_expiration_for_account", username, password, OS); + Object object = mXmlRpcClient.call("get_expiration_for_account", username, password); String result = (String)object; Log.d("getAccountExpire: " + result); @@ -205,7 +147,64 @@ public class XmlRpcHelper { return null; } - public void activateAccountAsync(final XmlRpcListener listener, String gmailAccount, String username, String payload, String signature) { + public void updateAccountExpireAsync(final XmlRpcListener listener, String username, String password, String payload, String signature) { + if (mXmlRpcClient != null) { + mXmlRpcClient.callAsync(new XMLRPCCallback() { + @Override + public void onServerError(long id, XMLRPCServerException error) { + Log.e(error); + listener.onError(error.toString()); + } + + @Override + public void onResponse(long id, Object object) { + String result = (String)object; + Log.d("updateAccountExpireAsync: " + result); + + if (result.startsWith("ERROR_")) { + Log.e(result); + listener.onError(result); + return; + } + + listener.onAccountExpireUpdated(result); + } + + @Override + public void onError(long id, XMLRPCException error) { + Log.e(error); + listener.onError(error.toString()); + } + }, "update_expiration_date", username, password, payload, signature); + } else { + Log.e(CLIENT_ERROR_INVALID_SERVER_URL); + listener.onError(CLIENT_ERROR_INVALID_SERVER_URL); + } + } + + public String updateAccountExpire(String username, String password, String payload, String signature) { + if (mXmlRpcClient != null) { + try { + Object object = mXmlRpcClient.call("update_expiration_date", username, password, payload, signature); + String result = (String)object; + Log.d("updateAccountExpire: " + result); + + if (result.startsWith("ERROR_")) { + Log.e(result); + return null; + } + return result; + + } catch (XMLRPCException e) { + Log.e(e); + } + } else { + Log.e(CLIENT_ERROR_INVALID_SERVER_URL); + } + return null; + } + + public void activateAccountAsync(final XmlRpcListener listener, String username, String password) { if (mXmlRpcClient != null) { mXmlRpcClient.callAsync(new XMLRPCCallback() { @Override @@ -234,17 +233,17 @@ public class XmlRpcHelper { Log.e(error); listener.onError(error.toString()); } - }, "activate_account", gmailAccount, username, payload, signature, OS); + }, "activate_account", username, password); } else { Log.e(CLIENT_ERROR_INVALID_SERVER_URL); listener.onError(CLIENT_ERROR_INVALID_SERVER_URL); } } - public String activateAccount(String gmailAccount, String username, String payload, String signature) { + public String activateAccount(String gmailAccount, String username, String password) { if (mXmlRpcClient != null) { try { - Object object = mXmlRpcClient.call("activate_account", gmailAccount, username, payload, signature, OS); + Object object = mXmlRpcClient.call("activate_account", username, password); String result = (String)object; Log.d("activateAccount: " + result); @@ -331,10 +330,10 @@ public class XmlRpcHelper { String result = (String)object; Log.d("isTrialAccountAsync: " + result); - if (!"ERROR_TOKEN_NOT_FOUND".equals(result) && !"OK".equals(result)) { + if (!"NOK".equals(result) && !"OK".equals(result)) { listener.onError(result); } - listener.onAccountFetched("ERROR_TOKEN_NOT_FOUND".equals(result)); + listener.onAccountFetched("OK".equals(result)); } @Override @@ -342,7 +341,7 @@ public class XmlRpcHelper { Log.e(error); listener.onError(error.toString()); } - }, "is_account_paid", username, password, OS); + }, "check_account_trial", username, password); } else { Log.e(CLIENT_ERROR_INVALID_SERVER_URL); listener.onError(CLIENT_ERROR_INVALID_SERVER_URL); @@ -352,11 +351,11 @@ public class XmlRpcHelper { public boolean isTrialAccount(String username, String password) { if (mXmlRpcClient != null) { try { - Object object = mXmlRpcClient.call("is_account_paid", username, password, OS); + Object object = mXmlRpcClient.call("check_account_trial", username, password); String result = (String)object; Log.d("isTrialAccount: " + result); - return "ERROR_TOKEN_NOT_FOUND".equals(result); + return "OK".equals(result); } catch (XMLRPCException e) { Log.e(e); } @@ -451,7 +450,7 @@ public class XmlRpcHelper { Log.e(error); listener.onError(error.toString()); } - }, "change_email", username, password, newEmail, OS); + }, "change_email", username, password, newEmail); } else { Log.e(CLIENT_ERROR_INVALID_SERVER_URL); listener.onError(CLIENT_ERROR_INVALID_SERVER_URL); @@ -461,7 +460,7 @@ public class XmlRpcHelper { public String changeAccountEmail(String username, String password, String newEmail) { if (mXmlRpcClient != null) { try { - Object object = mXmlRpcClient.call("change_email", username, password, newEmail, OS); + Object object = mXmlRpcClient.call("change_email", username, password, newEmail); String result = (String)object; Log.d("changeAccountEmail: " + result); @@ -508,7 +507,7 @@ public class XmlRpcHelper { Log.e(error); listener.onError(error.toString()); } - }, "change_password", username, oldPassword, newPassword, OS); + }, "change_password", username, oldPassword, newPassword); } else { Log.e(CLIENT_ERROR_INVALID_SERVER_URL); listener.onError(CLIENT_ERROR_INVALID_SERVER_URL); @@ -518,7 +517,7 @@ public class XmlRpcHelper { public String changeAccountPassword(String username, String oldPassword, String newPassword) { if (mXmlRpcClient != null) { try { - Object object = mXmlRpcClient.call("change_password", username, oldPassword, newPassword, OS); + Object object = mXmlRpcClient.call("change_password", username, oldPassword, newPassword); String result = (String)object; Log.d("changeAccountPassword: " + result); @@ -650,4 +649,61 @@ public class XmlRpcHelper { } return null; } + + public void verifySignatureAsync(final XmlRpcListener listener, String payload, String signature) { + if (mXmlRpcClient != null) { + mXmlRpcClient.callAsync(new XMLRPCCallback() { + @Override + public void onServerError(long id, XMLRPCServerException error) { + Log.e(error); + listener.onError(error.toString()); + } + + @Override + public void onResponse(long id, Object object) { + String result = (String)object; + Log.d("verifySignatureAsync: " + result); + + if (result.startsWith("ERROR_")) { + Log.e(result); + listener.onError(result); + return; + } + + listener.onSignatureVerified("OK".equals(result)); + } + + @Override + public void onError(long id, XMLRPCException error) { + Log.e(error); + listener.onError(error.toString()); + } + }, "verify_payload_signature", payload, signature); + } else { + Log.e(CLIENT_ERROR_INVALID_SERVER_URL); + listener.onError(CLIENT_ERROR_INVALID_SERVER_URL); + } + } + + public boolean verifySignature(String payload, String signature) { + if (mXmlRpcClient != null) { + try { + Object object = mXmlRpcClient.call("verify_payload_signature", payload, signature); + String result = (String)object; + Log.d("verifySignature: " + result); + + if (result.startsWith("ERROR_")) { + Log.e(result); + return false; + } + return "OK".equals(result); + + } catch (XMLRPCException e) { + Log.e(e); + } + } else { + Log.e(CLIENT_ERROR_INVALID_SERVER_URL); + } + return false; + } } diff --git a/src/org/linphone/xmlrpc/XmlRpcListener.java b/src/org/linphone/xmlrpc/XmlRpcListener.java index 8fbcd1a6a..f44543dcb 100644 --- a/src/org/linphone/xmlrpc/XmlRpcListener.java +++ b/src/org/linphone/xmlrpc/XmlRpcListener.java @@ -4,6 +4,7 @@ public interface XmlRpcListener { public void onError(String error); public void onAccountCreated(String result); public void onAccountExpireFetched(String result); + public void onAccountExpireUpdated(String result); public void onAccountActivated(String result); public void onAccountActivatedFetched(boolean isActivated); public void onTrialAccountFetched(boolean isTrial); @@ -12,4 +13,5 @@ public interface XmlRpcListener { public void onAccountPasswordChanged(String result); public void onRecoverPasswordLinkSent(String result); public void onActivateAccountLinkSent(String result); + public void onSignatureVerified(boolean success); } diff --git a/src/org/linphone/xmlrpc/XmlRpcListenerBase.java b/src/org/linphone/xmlrpc/XmlRpcListenerBase.java index e1752d082..94001cea7 100644 --- a/src/org/linphone/xmlrpc/XmlRpcListenerBase.java +++ b/src/org/linphone/xmlrpc/XmlRpcListenerBase.java @@ -66,4 +66,16 @@ public class XmlRpcListenerBase implements XmlRpcListener { // TODO Auto-generated method stub } + + @Override + public void onAccountExpireUpdated(String result) { + // TODO Auto-generated method stub + + } + + @Override + public void onSignatureVerified(boolean success) { + // TODO Auto-generated method stub + + } }