diff --git a/app/src/main/java/com/emanuelef/remote_capture/CaptureService.java b/app/src/main/java/com/emanuelef/remote_capture/CaptureService.java
index ecfeda02..d7e066fc 100644
--- a/app/src/main/java/com/emanuelef/remote_capture/CaptureService.java
+++ b/app/src/main/java/com/emanuelef/remote_capture/CaptureService.java
@@ -25,8 +25,10 @@ import android.app.NotificationChannel;
import android.app.NotificationManager;
import android.app.PendingIntent;
import android.app.Service;
+import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
+import android.content.IntentFilter;
import android.content.SharedPreferences;
import android.content.pm.PackageManager;
import android.net.ConnectivityManager;
@@ -98,6 +100,7 @@ public class CaptureService extends VpnService implements Runnable {
private static final int VPN_MTU = 10000;
private static final int NOTIFY_ID_VPNSERVICE = 1;
private static final int NOTIFY_ID_LOW_MEMORY = 2;
+ private static final int NOTIFY_ID_APP_BLOCKED = 3;
private static CaptureService INSTANCE;
final ReentrantLock mLock = new ReentrantLock();
final Condition mCaptureStopped = mLock.newCondition();
@@ -147,6 +150,7 @@ public class CaptureService extends VpnService implements Runnable {
private String mSocks5Auth;
private CaptureStats mLastStats;
private boolean mLowMemory;
+ private BroadcastReceiver mNewAppsInstallReceiver;
/* The maximum connections to log into the ConnectionsRegister. Older connections are dropped.
* Max estimated memory usage: less than 4 MB (+8 MB with payload mode minimal). */
@@ -464,6 +468,50 @@ public class CaptureService extends VpnService implements Runnable {
mDumperThread.start();
}
+ if(mFirewallEnabled) {
+ mNewAppsInstallReceiver = new BroadcastReceiver() {
+ @Override
+ public void onReceive(Context context, Intent intent) {
+ // executed on the main thread
+ if (Intent.ACTION_PACKAGE_ADDED.equals(intent.getAction())) {
+ boolean newInstall = !intent.getBooleanExtra(Intent.EXTRA_REPLACING, false);
+ String packageName = intent.getData().getSchemeSpecificPart();
+ Log.d(TAG, "ACTION_PACKAGE_ADDED [new=" + newInstall + "]: " + packageName);
+
+ if(newInstall && Prefs.blockNewApps(mPrefs)) {
+ Log.i(TAG, "Blocking newly installed app: " + packageName);
+ mBlocklist.addApp(packageName);
+ mBlocklist.save();
+ reloadBlocklist();
+
+ AppDescriptor app = appsResolver.getByPackage(packageName, 0);
+ String label = (app != null) ? app.getName() : packageName;
+
+ // Notify the user
+ NotificationManagerCompat man = NotificationManagerCompat.from(context);
+ if(man.areNotificationsEnabled()) {
+ Notification notification = new NotificationCompat.Builder(CaptureService.this, NOTIFY_CHAN_OTHER)
+ .setSmallIcon(R.drawable.ic_logo)
+ .setColor(ContextCompat.getColor(CaptureService.this, R.color.colorPrimary))
+ .setVisibility(NotificationCompat.VISIBILITY_PUBLIC)
+ .setCategory(NotificationCompat.CATEGORY_STATUS)
+ .setContentTitle(getString(R.string.app_blocked))
+ .setContentText(getString(R.string.app_blocked_info, label))
+ .build();
+
+ man.notify(NOTIFY_ID_APP_BLOCKED, notification);
+ }
+ }
+ }
+ }
+ };
+
+ IntentFilter filter = new IntentFilter();
+ filter.addAction(Intent.ACTION_PACKAGE_ADDED);
+ filter.addDataScheme("package");
+ registerReceiver(mNewAppsInstallReceiver, filter);
+ }
+
// Start the native capture thread
mQueueFull = false;
mCaptureThread = new Thread(this, "PacketCapture");
@@ -493,7 +541,10 @@ public class CaptureService extends VpnService implements Runnable {
if(mBlacklistsUpdateThread != null)
mBlacklistsUpdateThread.interrupt();
- unregisterNetworkCallbacks();
+ if(mNewAppsInstallReceiver != null) {
+ unregisterReceiver(mNewAppsInstallReceiver);
+ mNewAppsInstallReceiver = null;
+ }
super.onDestroy();
}
diff --git a/app/src/main/java/com/emanuelef/remote_capture/activities/MainActivity.java b/app/src/main/java/com/emanuelef/remote_capture/activities/MainActivity.java
index 25d94518..2250498b 100644
--- a/app/src/main/java/com/emanuelef/remote_capture/activities/MainActivity.java
+++ b/app/src/main/java/com/emanuelef/remote_capture/activities/MainActivity.java
@@ -62,7 +62,6 @@ import android.view.View;
import android.widget.TextView;
import com.emanuelef.remote_capture.Billing;
-import com.emanuelef.remote_capture.BuildConfig;
import com.emanuelef.remote_capture.CaptureHelper;
import com.emanuelef.remote_capture.MitmReceiver;
import com.emanuelef.remote_capture.fragments.ConnectionsFragment;
diff --git a/app/src/main/java/com/emanuelef/remote_capture/fragments/FirewallStatus.java b/app/src/main/java/com/emanuelef/remote_capture/fragments/FirewallStatus.java
index ff3b6a80..2d4beb44 100644
--- a/app/src/main/java/com/emanuelef/remote_capture/fragments/FirewallStatus.java
+++ b/app/src/main/java/com/emanuelef/remote_capture/fragments/FirewallStatus.java
@@ -133,6 +133,8 @@ public class FirewallStatus extends Fragment {
updateStatus();
});
+ menu.findItem(R.id.block_new_apps).setChecked(Prefs.blockNewApps(mPrefs));
+
updateStatus();
}
@@ -144,6 +146,11 @@ public class FirewallStatus extends Fragment {
Intent browserIntent = new Intent(Intent.ACTION_VIEW, Uri.parse(MainActivity.FIREWALL_DOCS_URL));
Utils.startActivity(requireContext(), browserIntent);
return true;
+ } else if(id == R.id.block_new_apps) {
+ boolean checked = !item.isChecked();
+ item.setChecked(checked);
+ mPrefs.edit().putBoolean(Prefs.PREF_BLOCK_NEW_APPS, checked).apply();
+ return true;
}
return false;
diff --git a/app/src/main/java/com/emanuelef/remote_capture/model/Prefs.java b/app/src/main/java/com/emanuelef/remote_capture/model/Prefs.java
index 2d78e164..7e94de89 100644
--- a/app/src/main/java/com/emanuelef/remote_capture/model/Prefs.java
+++ b/app/src/main/java/com/emanuelef/remote_capture/model/Prefs.java
@@ -75,6 +75,7 @@ public class Prefs {
public static final String PREF_APP_VERSION = "appver";
public static final String PREF_LOCKDOWN_VPN_NOTICE_SHOWN = "vpn_lockdown_notice";
public static final String PREF_VPN_EXCEPTIONS = "vpn_exceptions";
+ public static final String PREF_BLOCK_NEW_APPS = "block_new_apps";
public enum DumpMode {
NONE,
@@ -163,4 +164,5 @@ public class Prefs {
public static boolean blockQuic(SharedPreferences p) { return(getTlsDecryptionEnabled(p) && p.getBoolean(PREF_BLOCK_QUIC, false)); }
public static boolean isPrivateDnsBlockingEnabled(SharedPreferences p) { return(p.getBoolean(PREF_AUTO_BLOCK_PRIVATE_DNS, true)); }
public static boolean lockdownVpnNoticeShown(SharedPreferences p) { return(p.getBoolean(PREF_LOCKDOWN_VPN_NOTICE_SHOWN, false)); }
+ public static boolean blockNewApps(SharedPreferences p) { return(p.getBoolean(PREF_BLOCK_NEW_APPS, false)); }
}
diff --git a/app/src/main/res/menu/firewall_menu.xml b/app/src/main/res/menu/firewall_menu.xml
index c2f41ad1..fc059855 100644
--- a/app/src/main/res/menu/firewall_menu.xml
+++ b/app/src/main/res/menu/firewall_menu.xml
@@ -6,13 +6,21 @@
+
+ app:showAsAction="never" />
+
+
\ No newline at end of file
diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml
index 96984559..dd4ce31c 100644
--- a/app/src/main/res/values/strings.xml
+++ b/app/src/main/res/values/strings.xml
@@ -379,4 +379,7 @@
Cleartext
Unblock permanently
Unblock for %1$dh
+ Block newly installed apps
+ App blocked
+ The %1$s app has been blocked by the firewall