package org.commcare.tasks;
import android.content.ContentResolver;
import android.database.Cursor;
import android.net.Uri;
import android.util.Pair;
import org.commcare.tasks.templates.CommCareTask;
import org.commcare.utils.GlobalConstants;
import org.commcare.utils.SigningUtil;
import org.joda.time.DateTime;
/**
* Tries to find an install sms sent to the device of the format:
* [commcare app - do not delete] https://www.commcarehq.org/a/gc/sms/app_info/7c7d49fbef59b703fb468e20d52a21e4/
*
* If found:
* - Follows the http url to get app install info, which is base64-encoded
* - Base64 decodes that result into a string which looks like:
* ccapp: http://bit.ly/2cDCv0e signature: <binary signature>
* - Verifies the url is signed correctly using the signature and returns the
* url to be used to install the app
*/
public abstract class RetrieveParseVerifyMessageTask<R> extends CommCareTask<Void, Void, String, R> {
/**
* How many sms messages to scan over looking for commcare install link
*/
private static final int SMS_CHECK_COUNT = 100;
private Exception exception;
private final RetrieveParseVerifyMessageListener listener;
private final boolean installTriggeredManually;
private final ContentResolver contentResolver;
public RetrieveParseVerifyMessageTask(RetrieveParseVerifyMessageListener listener,
ContentResolver contentResolver,
boolean installTriggeredManually) {
this.listener = listener;
this.contentResolver = contentResolver;
this.installTriggeredManually = installTriggeredManually;
}
@Override
protected String doTaskBackground(Void... params) {
// http://stackoverflow.com/questions/11301046/search-sms-inbox
final Uri SMS_INBOX = Uri.parse("content://sms/inbox");
DateTime oneWeekAgo = (new DateTime()).minusDays(7);
Cursor cursor = contentResolver.query(SMS_INBOX,
null, "date >? ",
new String[]{"" + oneWeekAgo.getMillis()},
"date DESC");
int messageIterationCount = 0;
if (cursor != null) {
try {
while (cursor.moveToNext() && messageIterationCount <= SMS_CHECK_COUNT) { // must check the result to prevent exception
messageIterationCount++;
String textMessageBody = cursor.getString(cursor.getColumnIndex("body"));
if (textMessageBody.contains(GlobalConstants.SMS_INSTALL_KEY_STRING)) {
return processSMS(textMessageBody);
}
}
} finally {
cursor.close();
}
}
return null;
}
private String processSMS(String smsText) {
try {
String url = SigningUtil.trimMessagePayload(smsText);
String messagePayload = SigningUtil.convertEncodedUrlToPayload(url);
byte[] messagePayloadBytes = SigningUtil.getBytesFromString(messagePayload);
Pair<String, byte[]> messageAndBytes = SigningUtil.getUrlAndSignatureFromPayload(messagePayloadBytes);
return SigningUtil.verifyMessageAndBytes(messageAndBytes.first, messageAndBytes.second);
} catch (Exception e) {
this.exception = e;
return null;
}
}
@Override
protected void onPostExecute(String url) {
super.onPostExecute(url);
if (exception != null) {
listener.exceptionReceived(exception, installTriggeredManually);
}
if (installTriggeredManually) {
listener.downloadLinkReceivedAutoInstall(url);
} else {
listener.downloadLinkReceived(url);
}
}
}