Scan all the things! Use RecursiveFileObserver from Conversations

This commit is contained in:
Tad 2017-12-16 16:58:43 -05:00
parent 39d8455602
commit e46b1723ef
5 changed files with 123 additions and 41 deletions

View file

@ -11,11 +11,11 @@ android {
} }
buildTypes { buildTypes {
debug { debug {
applicationIdSuffix ".debug"
minifyEnabled true minifyEnabled true
useProguard false useProguard false
zipAlignEnabled true zipAlignEnabled true
proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro' proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
} }
release { release {
shrinkResources true shrinkResources true

View file

@ -46,11 +46,12 @@ class MalwareScanner extends AsyncTask<Set<File>, Object, String> {
if (userFacing) { if (userFacing) {
logOutput.append(result + "\n"); logOutput.append(result + "\n");
} else if (!userFacingOnly) { } else if (!userFacingOnly) {
String[] malwareDetect = result.split(" in ");
NotificationCompat.Builder mBuilder = NotificationCompat.Builder mBuilder =
new NotificationCompat.Builder(context) new NotificationCompat.Builder(context)
.setSmallIcon(R.drawable.ic_notification) .setSmallIcon(R.drawable.ic_notification)
.setContentTitle(context.getText(R.string.lblNotificationRealtimeDetection)) .setContentTitle(context.getText(R.string.lblNotificationRealtimeDetection) + " " + malwareDetect[0])
.setContentText(result) .setContentText(malwareDetect[1])
.setPriority(Notification.PRIORITY_MAX) .setPriority(Notification.PRIORITY_MAX)
.setVisibility(Notification.VISIBILITY_SECRET) .setVisibility(Notification.VISIBILITY_SECRET)
.setDefaults(Notification.DEFAULT_VIBRATE); .setDefaults(Notification.DEFAULT_VIBRATE);

View file

@ -15,7 +15,7 @@ import java.util.Set;
public class MalwareScannerService extends Service { public class MalwareScannerService extends Service {
private ArrayList<MalwareMonitor> malwareMonitors = null; private ArrayList<RecursiveFileObserver> malwareMonitors = new ArrayList<>();
@Override @Override
public final IBinder onBind(Intent intent) { public final IBinder onBind(Intent intent) {
@ -24,14 +24,10 @@ public class MalwareScannerService extends Service {
@Override @Override
public final int onStartCommand(Intent intent, int flags, int startId) { public final int onStartCommand(Intent intent, int flags, int startId) {
malwareMonitors = new ArrayList<>(); malwareMonitors.clear();
malwareMonitors.add(new MalwareMonitor(Environment.getExternalStorageDirectory().toString())); addMalwareMonitor(Environment.getExternalStorageDirectory().toString());
malwareMonitors.add(new MalwareMonitor(Environment.getExternalStorageDirectory() + "/Conversations"));
malwareMonitors.add(new MalwareMonitor(Environment.getExternalStorageDirectory() + "/Documents"));
malwareMonitors.add(new MalwareMonitor(Environment.getExternalStorageDirectory() + "/Download"));
malwareMonitors.add(new MalwareMonitor(Environment.getExternalStorageDirectory() + "/Pictures"));
for (MalwareMonitor malwareMonitor : malwareMonitors) { for (RecursiveFileObserver malwareMonitor : malwareMonitors) {
malwareMonitor.startWatching(); malwareMonitor.startWatching();
} }
//Toast.makeText(this, "Theia: Realtime Scanning Started", Toast.LENGTH_SHORT).show(); //Toast.makeText(this, "Theia: Realtime Scanning Started", Toast.LENGTH_SHORT).show();
@ -39,11 +35,32 @@ public class MalwareScannerService extends Service {
return START_STICKY; return START_STICKY;
} }
private final void addMalwareMonitor(String monitorPath) {
malwareMonitors.add(new RecursiveFileObserver(monitorPath) {
@Override
public void onEvent(int event, String path) {
switch (event) {
case FileObserver.MOVED_TO:
case FileObserver.CLOSE_WRITE:
File file = new File(path);
if (file.exists() && file.length() > 0) {
Set<File> filesToScan = new HashSet<>();
filesToScan.add(file);
new MalwareScanner(null, getApplicationContext(), false).execute(filesToScan);
}
break;
}
}
});
}
@Override @Override
public final void onDestroy() { public final void onDestroy() {
for (MalwareMonitor malwareMonitor : malwareMonitors) { for (RecursiveFileObserver malwareMonitor : malwareMonitors) {
malwareMonitor.stopWatching(); malwareMonitor.stopWatching();
} }
malwareMonitors.clear();
System.gc();
//Toast.makeText(this, "Theia: Realtime Scanning Stopped", Toast.LENGTH_SHORT).show(); //Toast.makeText(this, "Theia: Realtime Scanning Stopped", Toast.LENGTH_SHORT).show();
} }
@ -60,32 +77,4 @@ public class MalwareScannerService extends Service {
startForeground(-1, notification); startForeground(-1, notification);
} }
private final class MalwareMonitor extends FileObserver {
private String rootPath = null;
public MalwareMonitor(String path) {
super(path);
rootPath = path;
if (!rootPath.endsWith("/")) {
rootPath += "/";
}
}
@Override
public final void onEvent(int eventID, String path) {
switch (eventID) {
case FileObserver.MOVED_TO:
case FileObserver.CLOSE_WRITE:
File file = new File(rootPath + path);
if (file.exists() && file.length() > 0) {
Set<File> filesToScan = new HashSet<>();
filesToScan.add(file);
new MalwareScanner(null, getApplicationContext(), false).execute(filesToScan);
}
break;
}
}
}
} }

View file

@ -0,0 +1,92 @@
package us.spotco.malwarescanner;
import android.os.FileObserver;
import java.io.File;
import java.util.ArrayList;
import java.util.List;
import java.util.Stack;
/**
* Copyright (C) 2012 Bartek Przybylski
* Copyright (C) 2015 ownCloud Inc.
* Copyright (C) 2016 Daniel Gultsch
*/
public abstract class RecursiveFileObserver {
private final String path;
private final List<SingleFileObserver> mObservers = new ArrayList<>();
public RecursiveFileObserver(String path) {
this.path = path;
}
public final synchronized void startWatching() {
Stack<String> stack = new Stack<>();
stack.push(path);
while (!stack.empty()) {
String parent = stack.pop();
mObservers.add(new SingleFileObserver(parent));
final File path = new File(parent);
final File[] files = path.listFiles();
if (files == null) {
continue;
}
for(File file : files) {
if (file.isDirectory() && file.getName().charAt(0) != '.') {
final String currentPath = file.getAbsolutePath();
if (depth(file) <= 8 && !stack.contains(currentPath) && !observing(currentPath)) {
stack.push(currentPath);
}
}
}
}
for(FileObserver observer : mObservers) {
observer.startWatching();
}
}
private static int depth(File file) {
int depth = 0;
while((file = file.getParentFile()) != null) {
depth++;
}
return depth;
}
private boolean observing(String path) {
for(SingleFileObserver observer : mObservers) {
if(path.equals(observer.path)) {
return true;
}
}
return false;
}
public final synchronized void stopWatching() {
for(FileObserver observer : mObservers) {
observer.stopWatching();
}
mObservers.clear();
}
abstract public void onEvent(int event, String path);
private class SingleFileObserver extends FileObserver {
private final String path;
public SingleFileObserver(String path) {
super(path);
this.path = path;
}
@Override
public final void onEvent(int event, String filename) {
RecursiveFileObserver.this.onEvent(event, path + '/' + filename);
}
}
}

View file

@ -8,6 +8,6 @@
<string name="lblScanExternal">Scan External Storage</string> <string name="lblScanExternal">Scan External Storage</string>
<string name="lblNotificationRealtimeTitle">Realtime Scanner</string> <string name="lblNotificationRealtimeTitle">Realtime Scanner</string>
<string name="lblNotificationRealtimeText">Malware will be detected in realtime</string> <string name="lblNotificationRealtimeText">Malware will be detected in realtime</string>
<string name="lblNotificationRealtimeDetection">Malware Detected!</string> <string name="lblNotificationRealtimeDetection">Malware Detected:</string>
<string name="lblRealtimeScannerToggle">Realtime Scanner</string> <string name="lblRealtimeScannerToggle">Realtime Scanner</string>
</resources> </resources>