Integrating Safetynet Recaptcha In Android Application


The SafetyNet service includes a reCAPTCHA API that you can use to protect your app from malicious traffic.

reCAPTCHA is a free service that uses an advanced risk analysis engine to protect your app from spam and other abusive actions. If the service suspects that the user interacting with your app might be a bot instead of a human, it serves a CAPTCHA that a human must solve before your app can continue executing.



Integrating Recaptcha for Android involves two different steps consecutively:

1. Client side verification process

    In client side verification process you will integrate safetynet SDK in your Android studio project and will perform certain steps on Android code itself. Once this process is complete, this will generate a Token, which is a unique string associated with the user verification process.


1. Server side verification process

Once a token is generated, a secondary code has to be run. A server to server response has to be generated from your own server to google recaptcha servers


Once the server side response is received, it is transmitted back to android app for final confirmation.


Complete code:

AndroidManifest.xml:

<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="com.ourcoaching.simplegooglerecaptcha">

<uses-permission android:name="android.permission.INTERNET"></uses-permission>
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />

<application
android:allowBackup="true"
android:icon="@mipmap/ic_launcher"
android:label="@string/app_name"
android:roundIcon="@mipmap/ic_launcher_round"
android:supportsRtl="true"
android:theme="@style/AppTheme">
<activity android:name=".MainActivity">
<intent-filter>
<action android:name="android.intent.action.MAIN" />

<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
</application>

</manifest>


activity_main.xml:

<?xml version="1.0" encoding="utf-8"?>
<android.support.constraint.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:context="com.ourcoaching.simplegooglerecaptcha.MainActivity">

<TextView
android:id="@+id/textView"
android:layout_width="193dp"
android:layout_height="61dp"
android:layout_marginBottom="8dp"
android:layout_marginEnd="8dp"
android:layout_marginStart="8dp"
android:layout_marginTop="8dp"
android:text="TextView"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintHorizontal_bias="0.502"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@+id/checkBox"
app:layout_constraintVertical_bias="0.2" />

<TextView
android:id="@+id/textView2"
android:layout_width="193dp"
android:layout_height="64dp"
android:layout_marginBottom="8dp"
android:layout_marginEnd="8dp"
android:layout_marginStart="8dp"
android:layout_marginTop="8dp"
android:text="TextView"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintHorizontal_bias="0.502"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@+id/textView"
app:layout_constraintVertical_bias="0.258" />

<CheckBox
android:id="@+id/checkBox"
android:layout_width="220dp"
android:layout_height="40dp"
android:layout_marginBottom="8dp"
android:layout_marginEnd="8dp"
android:layout_marginStart="8dp"
android:layout_marginTop="8dp"
android:text="Captcha"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent"
app:layout_constraintVertical_bias="0.205" />

</android.support.constraint.ConstraintLayout>


MainActivity.java:

package com.ourcoaching.simplegooglerecaptcha;

import android.app.AlertDialog;
import android.app.ProgressDialog;
import android.content.DialogInterface;
import android.os.AsyncTask;
import android.support.annotation.NonNull;
import android.support.v7.app.AppCompatActivity;
import android.os.Bundle;
import android.util.Log;
import android.widget.CheckBox;
import android.widget.CompoundButton;
import android.widget.TextView;

import com.google.android.gms.common.api.ApiException;
import com.google.android.gms.common.api.CommonStatusCodes;
import com.google.android.gms.safetynet.SafetyNet;
import com.google.android.gms.safetynet.SafetyNetApi;
import com.google.android.gms.tasks.OnFailureListener;
import com.google.android.gms.tasks.OnSuccessListener;

import java.io.BufferedReader;
import java.io.BufferedWriter;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.OutputStream;
import java.io.OutputStreamWriter;
import java.net.HttpURLConnection;
import java.net.MalformedURLException;
import java.net.URL;
import java.net.URLEncoder;

import javax.net.ssl.HttpsURLConnection;


public class MainActivity extends AppCompatActivity {

private final String url_server_file="https://www.ourcoaching.com/kunal_testCodes/captcha_server_file.php";
private final String TAG="CAPTCHA ";

private CheckBox checkBox;
private TextView textView,textView2;
// Downloaded from https://github.com/KuKapoor02
// Visit https://www.ourcoaching.com/
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);

checkBox=(CheckBox)findViewById(R.id.checkBox);
textView=(TextView)findViewById(R.id.textView);
textView2=(TextView)findViewById(R.id.textView2);

checkBox.setOnCheckedChangeListener(new CompoundButton.OnCheckedChangeListener() {
@Override
public void onCheckedChanged(CompoundButton compoundButton, boolean b) {
CaptchCheckChallenge(b);
}
});
}

private void CaptchCheckChallenge(boolean b){

if (b){
SafetyNet.getClient(this).verifyWithRecaptcha("6Ld4al0UAAAAACHXeuxoMJlv_hT8zoEBqaxnaPN0")
.addOnSuccessListener(this, new OnSuccessListener<SafetyNetApi.RecaptchaTokenResponse>() {
@Override
public void onSuccess(SafetyNetApi.RecaptchaTokenResponse response) {
if (!response.getTokenResult().isEmpty()) {
handleSiteVerify(response.getTokenResult());
}
}
})
.addOnFailureListener(this, new OnFailureListener() {
@Override
public void onFailure(@NonNull Exception e) {
if (e instanceof ApiException) {
ApiException apiException = (ApiException) e;
Log.d(TAG, "Error message: " +
CommonStatusCodes.getStatusCodeString(apiException.getStatusCode()));
} else {
Log.d(TAG, "Unknown type of error: " + e.getMessage());
}
}
});
}

}

private void handleSiteVerify(String tokenResult) {
textView.setText(tokenResult);

CaptchaServerCode captchaServerCode=new CaptchaServerCode();
captchaServerCode.execute(tokenResult);
}



private class CaptchaServerCode extends AsyncTask<String,Void,String>{

URL url;
BufferedWriter bufferedWriter;
BufferedReader bufferedReader;
OutputStream outputStream;
InputStream inputStream;
HttpsURLConnection httpsURLConnection;

String output="";

ProgressDialog progressDialog;

@Override
protected void onPreExecute() {
super.onPreExecute();

progressDialog=new ProgressDialog(MainActivity.this);
progressDialog.setMessage("Loading...Please wait...");
progressDialog.setIndeterminate(true);
progressDialog.setCancelable(false);
progressDialog.setProgressStyle(ProgressDialog.STYLE_SPINNER);

progressDialog.show();

}

@Override
protected String doInBackground(String... strings) {

try {
url=new URL(url_server_file);
httpsURLConnection=(HttpsURLConnection)url.openConnection();
httpsURLConnection.setDoOutput(true);
httpsURLConnection.setDoInput(true);
httpsURLConnection.setRequestMethod("POST");

httpsURLConnection.connect();

String sender_String= URLEncoder.encode("token","UTF-8") + "=" + URLEncoder.encode(strings[0],"UTF-8");

outputStream=httpsURLConnection.getOutputStream();
bufferedWriter=new BufferedWriter(new OutputStreamWriter(outputStream,"UTF-8"));
bufferedWriter.write(sender_String);
bufferedWriter.flush();
bufferedWriter.close();
outputStream.close();


if (httpsURLConnection.getResponseCode()==HttpURLConnection.HTTP_OK){

inputStream=httpsURLConnection.getInputStream();
bufferedReader=new BufferedReader(new InputStreamReader(inputStream,"iso-8859-1"));

output="";

if (bufferedReader.readLine()!=null){
output+=bufferedReader.readLine();
}

bufferedReader.close();
inputStream.close();
httpsURLConnection.disconnect();

return output;
}else {
return "error, connection problem";
}

} catch (MalformedURLException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}

return null;
}

@Override
protected void onPostExecute(String s) {
super.onPostExecute(s);

progressDialog.cancel();

textView2.setText(s);
}
}

}


Download the complete code



Related Tutorials