package fuzion24.device.vulnerability.test.ui;
import android.Manifest;
import android.content.Intent;
import android.content.pm.PackageManager;
import android.content.res.Configuration;
import android.graphics.Color;
import android.net.Uri;
import android.os.Bundle;
import android.support.design.widget.CoordinatorLayout;
import android.support.design.widget.FloatingActionButton;
import android.support.design.widget.Snackbar;
import android.support.v4.app.ActivityCompat;
import android.support.v4.content.ContextCompat;
import android.support.v7.app.AppCompatActivity;
import android.support.v7.widget.LinearLayoutManager;
import android.support.v7.widget.RecyclerView;
import android.support.v7.widget.Toolbar;
import android.util.Log;
import android.view.Menu;
import android.view.MenuItem;
import android.view.View;
import android.widget.TextView;
import com.afollestad.materialdialogs.DialogAction;
import com.afollestad.materialdialogs.MaterialDialog;
import com.evernote.android.job.JobManager;
import com.evernote.android.job.JobRequest;
import com.nowsecure.android.vts.R;
import org.json.JSONException;
import org.json.JSONObject;
import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.TimeUnit;
import fuzion24.device.vulnerability.test.ResultsCallback;
import fuzion24.device.vulnerability.test.ShareViaGoogleForm;
import fuzion24.device.vulnerability.test.VulnerabilityTestResult;
import fuzion24.device.vulnerability.test.VulnerabilityTestRunner;
import fuzion24.device.vulnerability.test.adapter.RecyclerAdapter;
import fuzion24.device.vulnerability.test.job.AndroidVTSJobCreator;
import fuzion24.device.vulnerability.test.job.CheckForUpdatesJob;
import fuzion24.device.vulnerability.util.DeviceInfo;
import fuzion24.device.vulnerability.util.SharedPreferencesUtils;
import fuzion24.device.vulnerability.vulnerabilities.VulnerabilityResultSerialzier;
public class MainActivity extends AppCompatActivity {
private static final String SERIALIZABLE_RESULTS = "SERIALIZABLE_RESULTS";
private static final String TAG = "VULN_TEST";
private static final int CREATE_CHECK_FOR_UPDATES_JOB = 1;
private static final int CHECK_FOR_UPDATES = 2;
private DeviceInfo devInfo;
private ArrayList<VulnerabilityTestResult> testResults;
private TextView emptyView;
private CoordinatorLayout coordinatorLayout;
private RecyclerAdapter recyclerAdapter;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
Toolbar toolbar = (Toolbar) findViewById(R.id.toolbar);
toolbar.setTitleTextColor(Color.WHITE);
setSupportActionBar(toolbar);
getSupportActionBar().setTitle(R.string.app_name);
if (savedInstanceState != null && savedInstanceState.containsKey(SERIALIZABLE_RESULTS)) {
testResults = (ArrayList<VulnerabilityTestResult>) savedInstanceState.getSerializable(SERIALIZABLE_RESULTS);
} else {
testResults = new ArrayList<>();
}
RecyclerView recyclerView = (RecyclerView) findViewById(R.id.recyclerView);
coordinatorLayout = (CoordinatorLayout) findViewById(R.id.coordinatorLayout);
emptyView = (TextView) findViewById(R.id.emptyView);
recyclerAdapter = new RecyclerAdapter(MainActivity.this, testResults);
recyclerView.setLayoutManager(new LinearLayoutManager(MainActivity.this));
recyclerView.setAdapter(recyclerAdapter);
final TextView tvKernelVersion = (TextView) findViewById(R.id.kernelVersion);
final TextView tvBuildFingerPrint = (TextView) findViewById(R.id.buildFingerPrint);
final TextView tvBuildID = (TextView) findViewById(R.id.buildID);
final TextView tvBuildBrand = (TextView) findViewById(R.id.buildBrand);
final TextView tvBuildManuf = (TextView) findViewById(R.id.buildManufacturer);
final TextView tvBuildModel = (TextView) findViewById(R.id.buildModel);
final TextView tvBuildRelease = (TextView) findViewById(R.id.buildRelease);
final TextView tvBuildSDK = (TextView) findViewById(R.id.buildSDK);
final TextView tvBuildABIList = (TextView) findViewById(R.id.buildABIList);
devInfo = DeviceInfo.getDeviceInfo();
tvBuildFingerPrint.setText(devInfo.getBuildFingerPrint());
tvBuildID.setText(devInfo.getBuildID());
tvKernelVersion.setText(devInfo.getKernelVersion());
tvBuildBrand.setText(devInfo.getBuildBrand());
tvBuildManuf.setText(devInfo.getBuildManufacturer());
tvBuildModel.setText(devInfo.getBuildModel());
tvBuildRelease.setText(devInfo.getBuildRelease());
tvBuildSDK.setText(devInfo.getBuildSDK());
StringBuilder sb = new StringBuilder();
for (String s : devInfo.getSupportedABIS()) {
sb.append(s);
sb.append(" ");
}
tvBuildABIList.setText(sb.toString());
FloatingActionButton fabStart = (FloatingActionButton) findViewById(R.id.fabStart);
fabStart.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
runTestsSuit();
}
});
// Creates the jobs to check for updates.
JobManager.instance().cancelAllForTag(CheckForUpdatesJob.TAG);
if (ContextCompat.checkSelfPermission(this, Manifest.permission.WRITE_EXTERNAL_STORAGE)
== PackageManager.PERMISSION_GRANTED) {
createCheckForUpdatesJob();
} else {
ActivityCompat.requestPermissions(this, new String[]{Manifest.permission.WRITE_EXTERNAL_STORAGE},
CREATE_CHECK_FOR_UPDATES_JOB);
}
}
@Override
public boolean onCreateOptionsMenu(Menu menu) {
getMenuInflater().inflate(R.menu.main_menu, menu);
menu.getItem(2).setChecked(SharedPreferencesUtils.isAutomaticSharingEnable(MainActivity.this));
return true;
}
@Override
public boolean onOptionsItemSelected(MenuItem item) {
int itemId = item.getItemId();
switch (itemId) {
case R.id.menu_export_results:
case R.id.menu_share_results:
if (testResults == null || testResults.isEmpty()) {
Snackbar.make(coordinatorLayout, R.string.run_tests, Snackbar.LENGTH_LONG).setAction(R.string.start, new View.OnClickListener() {
@Override
public void onClick(View v) {
runTestsSuit();
}
}).show();
return true;
}
Intent intent = null;
try {
JSONObject json = VulnerabilityResultSerialzier.serializeResultsToJson(testResults, devInfo);
if (itemId == R.id.menu_export_results) {
intent = new Intent(Intent.ACTION_SEND);
intent.setType("text/plain");
intent.putExtra(Intent.EXTRA_SUBJECT, "Android VTS Results");
intent.putExtra(Intent.EXTRA_TEXT, json.toString(4));
} else if (itemId == R.id.menu_share_results) {
Uri formUri = new ShareViaGoogleForm(json).buildUri();
intent = new Intent(Intent.ACTION_VIEW, formUri);
}
} catch (JSONException e) {
Log.d(TAG, "Json exception: " + e.getMessage());
Snackbar.make(coordinatorLayout, R.string.error_exporting_results, Snackbar.LENGTH_LONG).show();
}
if (intent != null) {
startActivity(Intent.createChooser(intent, getString(R.string.share_results_via)));
}
return true;
case R.id.menu_automatic_share_results:
new MaterialDialog.Builder(this)
.title(R.string.dialog_automatic_sharing_title)
.content(R.string.dialog_automatic_sharing_description)
.positiveText(R.string.global_sharing)
.negativeText(R.string.global_notsharing)
.onPositive(new MaterialDialog.SingleButtonCallback() {
@Override
public void onClick(MaterialDialog materialDialog, DialogAction dialogAction) {
SharedPreferencesUtils.setIsAutomaticSharingEnable(MainActivity.this, true);
}
})
.onNegative(new MaterialDialog.SingleButtonCallback() {
@Override
public void onClick(MaterialDialog materialDialog, DialogAction dialogAction) {
SharedPreferencesUtils.setIsAutomaticSharingEnable(MainActivity.this, false);
}
})
.onAny(new MaterialDialog.SingleButtonCallback() {
@Override
public void onClick(MaterialDialog materialDialog, DialogAction dialogAction) {
invalidateOptionsMenu();
}
})
.show();
return true;
case R.id.menu_check_updates:
if (ContextCompat.checkSelfPermission(this, Manifest.permission.WRITE_EXTERNAL_STORAGE)
== PackageManager.PERMISSION_GRANTED) {
checkForUpdates();
} else {
ActivityCompat.requestPermissions(this, new String[]{Manifest.permission.WRITE_EXTERNAL_STORAGE},
CHECK_FOR_UPDATES);
}
return true;
case R.id.menu_opensource_licences:
Intent mainIntent = new Intent(MainActivity.this, OpenSourceLicencesActivity.class);
startActivity(mainIntent);
return true;
default:
return super.onOptionsItemSelected(item);
}
}
private void runTestsSuit() {
new VulnerabilityTestRunner(MainActivity.this, true, new ResultsCallback() {
@Override
public void finished(final List<VulnerabilityTestResult> results) {
Log.d(TAG, "Device Vulnerability callback, finished");
testResults.clear();
testResults.addAll(results);
emptyView.setVisibility(View.GONE);
recyclerAdapter.updateResults(results);
showScanResume(results);
}
}).execute();
}
private void showScanResume(final List<VulnerabilityTestResult> results) {
int numberOfFailed = 0;
for (VulnerabilityTestResult result : results) {
if (result.getException() != null) {
continue;
}
if (result.isVulnerable()) {
numberOfFailed++;
}
}
MaterialDialog.Builder dialogBuilder = new MaterialDialog.Builder(this)
.title(R.string.scan_details)
.customView(R.layout.dialog_scan_details_layout, true)
.positiveText(R.string.dismiss)
.onAny(new MaterialDialog.SingleButtonCallback() {
@Override
public void onClick(MaterialDialog materialDialog, DialogAction dialogAction) {
if (SharedPreferencesUtils.isAutomaticSharingEnable(MainActivity.this)) {
try {
JSONObject json = VulnerabilityResultSerialzier.serializeResultsToJson(testResults, devInfo);
Uri formUri = new ShareViaGoogleForm(json).buildUri();
Intent intent = new Intent(Intent.ACTION_VIEW, formUri);
startActivity(Intent.createChooser(intent, getString(R.string.share_results_via)));
} catch (JSONException exception) {
exception.printStackTrace();
}
}
}
});
if (numberOfFailed > 0) {
dialogBuilder.negativeText(R.string.my_device_is_vulnerable_info)
.onNegative(new MaterialDialog.SingleButtonCallback() {
@Override
public void onClick(MaterialDialog materialDialog, DialogAction dialogAction) {
Intent browserIntent = new Intent(Intent.ACTION_VIEW, Uri.parse("https://www.nowsecure.com/blog/2015/11/18/my-device-is-vulnerable-now-what/"));
startActivity(browserIntent);
}
});
}
View view = dialogBuilder.show().getCustomView();
TextView state = (TextView) view.findViewById(R.id.scan_details_device_state);
if (numberOfFailed > 0) {
state.setText(R.string.scan_details_vulnerable_message);
state.setTextColor(getResources().getColor(R.color.red));
} else {
state.setText(R.string.scan_details_secure_message);
state.setTextColor(getResources().getColor(R.color.green));
}
TextView numberOfTests = (TextView) view.findViewById(R.id.scan_details_number_tests);
numberOfTests.setText(String.valueOf(results.size()));
TextView numberOfFailedTests = (TextView) view.findViewById(R.id.scan_details_failed_tests);
numberOfFailedTests.setText(String.valueOf(numberOfFailed));
}
private void createCheckForUpdatesJob() {
new JobRequest.Builder(CheckForUpdatesJob.TAG)
.setPeriodic(TimeUnit.DAYS.toMillis(7))
.setRequirementsEnforced(true)
.setRequiredNetworkType(JobRequest.NetworkType.CONNECTED)
.setPersisted(true)
.build()
.schedule();
}
private void checkForUpdates() {
final MaterialDialog progressDialog = new MaterialDialog.Builder(this)
.title(R.string.loading)
.content(R.string.checking_updates)
.cancelable(false)
.progress(true, 0)
.show();
CheckForUpdatesJob.checkForUpdates(this, progressDialog);
}
@Override
public void onRequestPermissionsResult(int requestCode, String[] permissions, int[] grantResults) {
switch (requestCode) {
case CREATE_CHECK_FOR_UPDATES_JOB:
if (grantResults.length > 0 && grantResults[0] == PackageManager.PERMISSION_GRANTED) {
createCheckForUpdatesJob();
}
break;
case CHECK_FOR_UPDATES:
if (grantResults.length > 0 && grantResults[0] == PackageManager.PERMISSION_GRANTED) {
checkForUpdates();
}
break;
}
}
@Override
public void onConfigurationChanged(Configuration newConfig) {
super.onConfigurationChanged(newConfig);
}
@Override
protected void onSaveInstanceState(final Bundle outState) {
outState.putSerializable(SERIALIZABLE_RESULTS, testResults);
}
}