mirror of
https://github.com/MaintainTeam/Hypatia.git
synced 2025-03-01 05:48:23 +03:00
Database downloader changes
- Store the new database separately and move into place - Check for network connection before trying to download - Don't immediately delete the database on download start - Only delete new database on download failure - Wait until all downloads complete before attempting reload Signed-off-by: Tad <tad@spotco.us>
This commit is contained in:
parent
55305f88f1
commit
fa25395a08
6 changed files with 70 additions and 11 deletions
|
@ -6,8 +6,8 @@ android {
|
||||||
applicationId "us.spotco.malwarescanner"
|
applicationId "us.spotco.malwarescanner"
|
||||||
minSdkVersion 19
|
minSdkVersion 19
|
||||||
targetSdkVersion 32
|
targetSdkVersion 32
|
||||||
versionCode 112
|
versionCode 113
|
||||||
versionName "2.35"
|
versionName "2.36"
|
||||||
resConfigs 'en', 'af', 'de', 'el', 'es', 'fi', 'fr', 'it', 'pl', 'pt', 'ru', 'tr', 'zh-rCN'
|
resConfigs 'en', 'af', 'de', 'el', 'es', 'fi', 'fr', 'it', 'pl', 'pt', 'ru', 'tr', 'zh-rCN'
|
||||||
}
|
}
|
||||||
buildTypes {
|
buildTypes {
|
||||||
|
|
|
@ -2,6 +2,7 @@
|
||||||
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
|
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
|
||||||
package="us.spotco.malwarescanner">
|
package="us.spotco.malwarescanner">
|
||||||
|
|
||||||
|
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
|
||||||
<uses-permission android:name="android.permission.FOREGROUND_SERVICE" />
|
<uses-permission android:name="android.permission.FOREGROUND_SERVICE" />
|
||||||
<uses-permission android:name="android.permission.INTERNET" />
|
<uses-permission android:name="android.permission.INTERNET" />
|
||||||
<uses-permission android:name="android.permission.MANAGE_EXTERNAL_STORAGE" />
|
<uses-permission android:name="android.permission.MANAGE_EXTERNAL_STORAGE" />
|
||||||
|
|
|
@ -53,6 +53,8 @@ class Database {
|
||||||
|
|
||||||
private static final DateFormat dateFormat = DateFormat.getDateInstance();
|
private static final DateFormat dateFormat = DateFormat.getDateInstance();
|
||||||
|
|
||||||
|
private static final ConcurrentLinkedQueue<AsyncTask<?, ?, ?>> downloadFutures = new ConcurrentLinkedQueue<>();
|
||||||
|
|
||||||
public Database(TextView log) {
|
public Database(TextView log) {
|
||||||
Database.log = log;
|
Database.log = log;
|
||||||
}
|
}
|
||||||
|
@ -62,7 +64,15 @@ class Database {
|
||||||
}
|
}
|
||||||
|
|
||||||
public static boolean isDatabaseLoaded() {
|
public static boolean isDatabaseLoaded() {
|
||||||
return areDatabasesAvailable() && databaseFullyLoaded;
|
return areDatabasesAvailable() && !isDatabaseLoading();
|
||||||
|
}
|
||||||
|
|
||||||
|
public static boolean isDatabaseLoading() {
|
||||||
|
return !databaseFullyLoaded && databaseCurrentlyLoading;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static boolean hasDownloadsRunning() {
|
||||||
|
return downloadFutures.size() > 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
public static void updateDatabase(Context context, ConcurrentLinkedQueue<SignatureDatabase> signatureDatabases) {
|
public static void updateDatabase(Context context, ConcurrentLinkedQueue<SignatureDatabase> signatureDatabases) {
|
||||||
|
@ -106,7 +116,7 @@ class Database {
|
||||||
try {
|
try {
|
||||||
boolean validated = verifier.verify(databaseLocation, databaseSigLocation, publicKey);
|
boolean validated = verifier.verify(databaseLocation, databaseSigLocation, publicKey);
|
||||||
if (validated) {
|
if (validated) {
|
||||||
Log.d("Hypatia", "Successfully validated database");
|
Log.d("Hypatia", "Successfully validated database: " + databaseLocation.getName());
|
||||||
FileInputStream databaseLoading = new FileInputStream(databaseLocation);
|
FileInputStream databaseLoading = new FileInputStream(databaseLocation);
|
||||||
switch (databaseLocation.getName()) {
|
switch (databaseLocation.getName()) {
|
||||||
case "hypatia-md5-bloom.bin":
|
case "hypatia-md5-bloom.bin":
|
||||||
|
@ -139,13 +149,29 @@ class Database {
|
||||||
}
|
}
|
||||||
|
|
||||||
public static class Downloader extends AsyncTask<Object, String, String> {
|
public static class Downloader extends AsyncTask<Object, String, String> {
|
||||||
|
@Override
|
||||||
|
protected void onPreExecute() {
|
||||||
|
Database.downloadFutures.add(this);
|
||||||
|
super.onPreExecute();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected void onPostExecute(String s) {
|
||||||
|
Database.downloadFutures.remove(this);
|
||||||
|
super.onPostExecute(s);
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected String doInBackground(Object... objects) {
|
protected String doInBackground(Object... objects) {
|
||||||
boolean onionRouting = (boolean) objects[0];
|
boolean onionRouting = (boolean) objects[0];
|
||||||
String url = (String) objects[1];
|
String url = (String) objects[1];
|
||||||
File out = new File((String) objects[2]);
|
File out = new File((String) objects[2]);
|
||||||
|
File outNew = new File((String) objects[2] + ".new");
|
||||||
String baseURL = (String) objects[3];
|
String baseURL = (String) objects[3];
|
||||||
try {
|
try {
|
||||||
|
if(outNew.exists()) {
|
||||||
|
outNew.delete();
|
||||||
|
}
|
||||||
HttpURLConnection connection;
|
HttpURLConnection connection;
|
||||||
if (onionRouting) {
|
if (onionRouting) {
|
||||||
Utils.waitUntilOrbotIsAvailable();
|
Utils.waitUntilOrbotIsAvailable();
|
||||||
|
@ -167,10 +193,7 @@ class Database {
|
||||||
int res = connection.getResponseCode();
|
int res = connection.getResponseCode();
|
||||||
if (res != 304) {
|
if (res != 304) {
|
||||||
if (res == 200) {
|
if (res == 200) {
|
||||||
if (out.exists()) {
|
FileOutputStream fileOutputStream = new FileOutputStream(outNew);
|
||||||
out.delete();
|
|
||||||
}
|
|
||||||
FileOutputStream fileOutputStream = new FileOutputStream(out);
|
|
||||||
|
|
||||||
final byte[] data = new byte[1024];
|
final byte[] data = new byte[1024];
|
||||||
int count;
|
int count;
|
||||||
|
@ -179,6 +202,8 @@ class Database {
|
||||||
}
|
}
|
||||||
|
|
||||||
fileOutputStream.close();
|
fileOutputStream.close();
|
||||||
|
outNew.renameTo(out); //Move the new file into place
|
||||||
|
|
||||||
publishProgress(url.replaceAll(baseURL, "")
|
publishProgress(url.replaceAll(baseURL, "")
|
||||||
+ "\n\t" + Utils.getContext().getString(R.string.main_database_download_success)
|
+ "\n\t" + Utils.getContext().getString(R.string.main_database_download_success)
|
||||||
+ "\n\t" + Utils.getContext().getString(R.string.main_database_released_on, lastModifiedServer) + "\n");
|
+ "\n\t" + Utils.getContext().getString(R.string.main_database_released_on, lastModifiedServer) + "\n");
|
||||||
|
@ -193,7 +218,9 @@ class Database {
|
||||||
connection.disconnect();
|
connection.disconnect();
|
||||||
} catch (Exception e) {
|
} catch (Exception e) {
|
||||||
e.printStackTrace();
|
e.printStackTrace();
|
||||||
out.delete();
|
if(outNew.exists()) {
|
||||||
|
outNew.delete();
|
||||||
|
}
|
||||||
publishProgress(url.replaceAll(baseURL, "")
|
publishProgress(url.replaceAll(baseURL, "")
|
||||||
+ "\n" + Utils.getContext().getString(R.string.main_database_download_error_logcat) + "\n");
|
+ "\n" + Utils.getContext().getString(R.string.main_database_download_error_logcat) + "\n");
|
||||||
}
|
}
|
||||||
|
|
|
@ -35,6 +35,7 @@ import android.os.Environment;
|
||||||
import android.provider.Settings;
|
import android.provider.Settings;
|
||||||
import android.text.InputType;
|
import android.text.InputType;
|
||||||
import android.text.method.ScrollingMovementMethod;
|
import android.text.method.ScrollingMovementMethod;
|
||||||
|
import android.util.Log;
|
||||||
import android.view.Menu;
|
import android.view.Menu;
|
||||||
import android.view.MenuItem;
|
import android.view.MenuItem;
|
||||||
import android.view.WindowManager;
|
import android.view.WindowManager;
|
||||||
|
@ -152,6 +153,8 @@ public class MainActivity extends Activity {
|
||||||
case R.id.mnuUpdateDatabase:
|
case R.id.mnuUpdateDatabase:
|
||||||
if (malwareScanner.running) {
|
if (malwareScanner.running) {
|
||||||
logView.append(getString(R.string.lblScanRunning) + "\n");
|
logView.append(getString(R.string.lblScanRunning) + "\n");
|
||||||
|
} else if (!Utils.isNetworkAvailable(this)) {
|
||||||
|
logView.append(getString(R.string.lblNoNetwork) + "\n");
|
||||||
} else {
|
} else {
|
||||||
if (prefs.getBoolean("ONION_ROUTING", false)) {
|
if (prefs.getBoolean("ONION_ROUTING", false)) {
|
||||||
Utils.requestStartOrbot(this);
|
Utils.requestStartOrbot(this);
|
||||||
|
@ -276,9 +279,27 @@ public class MainActivity extends Activity {
|
||||||
|
|
||||||
private void updateDatabase() {
|
private void updateDatabase() {
|
||||||
new Database(findViewById(R.id.txtLogOutput));
|
new Database(findViewById(R.id.txtLogOutput));
|
||||||
Database.updateDatabase(this, Database.signatureDatabases);
|
if(!Database.isDatabaseLoading()) {
|
||||||
|
Database.updateDatabase(this, Database.signatureDatabases);
|
||||||
|
} else {
|
||||||
|
Log.w("Hypatia", "Database is loading, not downloading!");
|
||||||
|
}
|
||||||
if (Database.isDatabaseLoaded()) {
|
if (Database.isDatabaseLoaded()) {
|
||||||
Utils.getThreadPoolExecutor().execute(() -> Database.loadDatabase(getApplicationContext(), true, Database.signatureDatabases));
|
Utils.getThreadPoolExecutor().execute(() -> {
|
||||||
|
try {
|
||||||
|
Thread.sleep(500);
|
||||||
|
Log.w("Hypatia", "Invoking database reload!");
|
||||||
|
while (Database.hasDownloadsRunning()) {
|
||||||
|
Thread.sleep(500);
|
||||||
|
Log.w("Hypatia", "Download in progress, waiting!");
|
||||||
|
|
||||||
|
}
|
||||||
|
} catch (InterruptedException e) {
|
||||||
|
throw new RuntimeException(e);
|
||||||
|
}
|
||||||
|
Log.w("Hypatia", "Really reloading database!");
|
||||||
|
Database.loadDatabase(getApplicationContext(), true, Database.signatureDatabases);
|
||||||
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -22,6 +22,8 @@ import android.content.Context;
|
||||||
import android.content.Intent;
|
import android.content.Intent;
|
||||||
import android.content.SharedPreferences;
|
import android.content.SharedPreferences;
|
||||||
import android.content.pm.PackageManager;
|
import android.content.pm.PackageManager;
|
||||||
|
import android.net.ConnectivityManager;
|
||||||
|
import android.net.NetworkInfo;
|
||||||
import android.os.Build;
|
import android.os.Build;
|
||||||
|
|
||||||
import java.io.File;
|
import java.io.File;
|
||||||
|
@ -169,6 +171,13 @@ class Utils {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
//Credit: https://stackoverflow.com/a/4239019
|
||||||
|
public static boolean isNetworkAvailable(Context context) {
|
||||||
|
ConnectivityManager connectivityManager = (ConnectivityManager) context.getSystemService(Context.CONNECTIVITY_SERVICE);
|
||||||
|
NetworkInfo activeNetworkInfo = connectivityManager != null ? connectivityManager.getActiveNetworkInfo() : null;
|
||||||
|
return activeNetworkInfo != null && activeNetworkInfo.isConnected();
|
||||||
|
}
|
||||||
|
|
||||||
public static Context getContext() {
|
public static Context getContext() {
|
||||||
return context;
|
return context;
|
||||||
}
|
}
|
||||||
|
|
|
@ -62,4 +62,5 @@
|
||||||
<string name="scan_control">Scan Control</string>
|
<string name="scan_control">Scan Control</string>
|
||||||
<string name="lblScanRunning">Skipping action, a scan is running!</string>
|
<string name="lblScanRunning">Skipping action, a scan is running!</string>
|
||||||
<string name="lblSigningKey">Database signing key</string>
|
<string name="lblSigningKey">Database signing key</string>
|
||||||
|
<string name="lblNoNetwork">No network connected!</string>
|
||||||
</resources>
|
</resources>
|
||||||
|
|
Loading…
Add table
Reference in a new issue