Ability to block newly installed apps (firewall)

Closes #208
This commit is contained in:
emanuele-f 2022-07-09 19:38:29 +02:00
parent dd98decfec
commit 53b42af3c7
6 changed files with 75 additions and 5 deletions

View File

@ -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();
}

View File

@ -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;

View File

@ -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;

View File

@ -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)); }
}

View File

@ -6,13 +6,21 @@
<item
android:id="@+id/toggle_btn"
android:title=""
android:orderInCategory="20"
android:orderInCategory="10"
app:showAsAction="always"
app:actionViewClass="androidx.appcompat.widget.SwitchCompat" />
<item
android:id="@+id/user_guide"
android:title="@string/user_guide"
android:orderInCategory="10"
android:orderInCategory="20"
android:icon="@drawable/ic_book"
app:showAsAction="ifRoom" />
app:showAsAction="never" />
<item
android:id="@+id/block_new_apps"
android:title="@string/block_new_apps"
android:orderInCategory="30"
android:checkable="true"
app:showAsAction="never" />
</menu>

View File

@ -379,4 +379,7 @@
<string name="cleartext_connection">Cleartext</string>
<string name="unblock_permanently">Unblock permanently</string>
<string name="unblock_for_n_hours">Unblock for %1$dh</string>
<string name="block_new_apps">Block newly installed apps</string>
<string name="app_blocked">App blocked</string>
<string name="app_blocked_info">The %1$s app has been blocked by the firewall</string>
</resources>