diff --git a/apk/controller/app/src/main/java/org/iiab/controller/MainActivity.java b/apk/controller/app/src/main/java/org/iiab/controller/MainActivity.java index 40dd13a..8316a19 100644 --- a/apk/controller/app/src/main/java/org/iiab/controller/MainActivity.java +++ b/apk/controller/app/src/main/java/org/iiab/controller/MainActivity.java @@ -78,6 +78,7 @@ public class MainActivity extends AppCompatActivity implements View.OnClickListe private CheckBox checkbox_udp_in_tcp; private CheckBox checkbox_remote_dns; private CheckBox checkbox_global; + private CheckBox checkbox_maintenance; private CheckBox checkbox_ipv4; private CheckBox checkbox_ipv6; private Button button_apps; @@ -170,6 +171,8 @@ public class MainActivity extends AppCompatActivity implements View.OnClickListe checkbox_global = findViewById(R.id.global); checkbox_udp_in_tcp = findViewById(R.id.udp_in_tcp); checkbox_remote_dns = findViewById(R.id.remote_dns); + checkbox_maintenance = findViewById(R.id.checkbox_maintenance); + checkbox_maintenance.setOnClickListener(this); button_apps = findViewById(R.id.apps); button_save = findViewById(R.id.save); button_control = findViewById(R.id.control); @@ -196,7 +199,7 @@ public class MainActivity extends AppCompatActivity implements View.OnClickListe btnClearLog.setOnClickListener(this); btnCopyLog.setOnClickListener(this); themeToggle.setOnClickListener(v -> toggleTheme()); - configLabel.setOnClickListener(v -> toggleVisibility(configLayout, configLabel, getString(R.string.configuration_label))); + configLabel.setOnClickListener(v -> handleConfigToggle()); advConfigLabel.setOnClickListener(v -> toggleVisibility(advancedConfig, advConfigLabel, getString(R.string.advanced_settings_label))); logLabel.setOnClickListener(v -> handleLogToggle()); checkbox_udp_in_tcp.setOnClickListener(this); @@ -525,7 +528,7 @@ public class MainActivity extends AppCompatActivity implements View.OnClickListe @Override public void onClick(View view) { - if (view == checkbox_global || view == checkbox_remote_dns) { + if (view == checkbox_global || view == checkbox_remote_dns || view == checkbox_maintenance) { savePrefs(); updateUI(); } else if (view == button_apps) { @@ -571,8 +574,9 @@ public class MainActivity extends AppCompatActivity implements View.OnClickListe } private void handleWatchdogClick() { - if (prefs.getWatchdogEnable()) showWatchdogBiometricPrompt(); - else toggleWatchdog(false); +// if (prefs.getWatchdogEnable()) showWatchdogBiometricPrompt(); +// else toggleWatchdog(false); + toggleWatchdog(prefs.getWatchdogEnable()); } private void toggleWatchdog(boolean stop) { @@ -629,6 +633,53 @@ public class MainActivity extends AppCompatActivity implements View.OnClickListe bp.authenticate(new BiometricPrompt.PromptInfo.Builder().setTitle(getString(R.string.auth_required_title)).setSubtitle(getString(R.string.auth_required_subtitle)).setAllowedAuthenticators(auth).build()); } + // --- Secure Advanced Settings Menu --- + private void handleConfigToggle() { + if (configLayout.getVisibility() == View.GONE) { + // The menu is closed. We want to open it, so we check for security first. + BiometricManager bm = BiometricManager.from(this); + int auth = BiometricManager.Authenticators.BIOMETRIC_STRONG | BiometricManager.Authenticators.DEVICE_CREDENTIAL; + if (Build.VERSION.SDK_INT < Build.VERSION_CODES.R) { + auth = BiometricManager.Authenticators.BIOMETRIC_WEAK | BiometricManager.Authenticators.DEVICE_CREDENTIAL; + } + android.app.KeyguardManager km = (android.app.KeyguardManager) getSystemService(Context.KEYGUARD_SERVICE); + + if (bm.canAuthenticate(auth) == BiometricManager.BIOMETRIC_SUCCESS || (km != null && km.isDeviceSecure())) { + showConfigBiometricPrompt(); + } else { + showEnrollmentDialog(); // Forces user to set a PIN if device has no security + } + } else { + // The menu is open. Just close it without asking for fingerprint. + toggleVisibility(configLayout, configLabel, getString(R.string.advanced_settings_label)); + } + } + + private void showConfigBiometricPrompt() { + Executor ex = ContextCompat.getMainExecutor(this); + BiometricPrompt bp = new BiometricPrompt(this, ex, new BiometricPrompt.AuthenticationCallback() { + @Override + public void onAuthenticationSucceeded(@NonNull BiometricPrompt.AuthenticationResult result) { + super.onAuthenticationSucceeded(result); + // Auth successful! Open the menu. + toggleVisibility(configLayout, configLabel, getString(R.string.advanced_settings_label)); + } + }); + + int auth = BiometricManager.Authenticators.BIOMETRIC_STRONG | BiometricManager.Authenticators.DEVICE_CREDENTIAL; + if (Build.VERSION.SDK_INT < Build.VERSION_CODES.R) { + auth = BiometricManager.Authenticators.BIOMETRIC_WEAK | BiometricManager.Authenticators.DEVICE_CREDENTIAL; + } + + // Reusing your existing strings to avoid compilation errors + bp.authenticate(new BiometricPrompt.PromptInfo.Builder() + .setTitle(getString(R.string.auth_required_title)) + .setSubtitle(getString(R.string.auth_required_subtitle)) + .setAllowedAuthenticators(auth) + .build()); + } + // ------------------------------------------------ + private void showWatchdogBiometricPrompt() { Executor ex = ContextCompat.getMainExecutor(this); BiometricPrompt bp = new BiometricPrompt(this, new BiometricPrompt.AuthenticationCallback() { @@ -685,27 +736,51 @@ public class MainActivity extends AppCompatActivity implements View.OnClickListe checkbox_global.setChecked(prefs.getGlobal()); checkbox_udp_in_tcp.setChecked(prefs.getUdpInTcp()); checkbox_remote_dns.setChecked(prefs.getRemoteDns()); + checkbox_maintenance.setChecked(prefs.getMaintenanceMode()); boolean editable = !vpnActive; edittext_socks_addr.setEnabled(editable); edittext_socks_port.setEnabled(editable); button_save.setEnabled(editable); } + //DEFAULT VALUES ON ORIGINAL INTERFACE +// private void savePrefs() { +// prefs.setSocksAddress(edittext_socks_addr.getText().toString()); +// prefs.setSocksPort(Integer.parseInt(edittext_socks_port.getText().toString())); +// prefs.setSocksUdpAddress(edittext_socks_udp_addr.getText().toString()); +// prefs.setSocksUsername(edittext_socks_user.getText().toString()); +// prefs.setSocksPassword(edittext_socks_pass.getText().toString()); +// prefs.setDnsIpv4(edittext_dns_ipv4.getText().toString()); +// prefs.setDnsIpv6(edittext_dns_ipv6.getText().toString()); +// prefs.setIpv4(checkbox_ipv4.isChecked()); +// prefs.setIpv6(checkbox_ipv6.isChecked()); +// prefs.setGlobal(checkbox_global.isChecked()); +// prefs.setUdpInTcp(checkbox_udp_in_tcp.isChecked()); +// prefs.setRemoteDns(checkbox_remote_dns.isChecked()); +// prefs.setMaintenanceMode(checkbox_maintenance.isChecked()); +// } + private void savePrefs() { - prefs.setSocksAddress(edittext_socks_addr.getText().toString()); - prefs.setSocksPort(Integer.parseInt(edittext_socks_port.getText().toString())); - prefs.setSocksUdpAddress(edittext_socks_udp_addr.getText().toString()); - prefs.setSocksUsername(edittext_socks_user.getText().toString()); - prefs.setSocksPassword(edittext_socks_pass.getText().toString()); + // 1. Hardcoded / Hidden Secure Values (Walled Garden defaults) + prefs.setSocksAddress("127.0.0.1"); + prefs.setSocksPort(1080); + prefs.setSocksUdpAddress(""); // Empty by default + prefs.setSocksUsername(""); + prefs.setSocksPassword(""); + prefs.setIpv4(true); + prefs.setIpv6(true); + prefs.setUdpInTcp(false); + prefs.setRemoteDns(true); + + // CRITICAL: Force Global to TRUE so the tunnel catches ALL system traffic + prefs.setGlobal(true); + + // 2. User Editable Values (The only things read from the UI) prefs.setDnsIpv4(edittext_dns_ipv4.getText().toString()); prefs.setDnsIpv6(edittext_dns_ipv6.getText().toString()); - prefs.setIpv4(checkbox_ipv4.isChecked()); - prefs.setIpv6(checkbox_ipv6.isChecked()); - prefs.setGlobal(checkbox_global.isChecked()); - prefs.setUdpInTcp(checkbox_udp_in_tcp.isChecked()); - prefs.setRemoteDns(checkbox_remote_dns.isChecked()); + prefs.setMaintenanceMode(checkbox_maintenance.isChecked()); } - + private void addToLog(String message) { runOnUiThread(() -> { SimpleDateFormat sdf = new SimpleDateFormat("HH:mm:ss", Locale.getDefault()); diff --git a/apk/controller/app/src/main/java/org/iiab/controller/Preferences.java b/apk/controller/app/src/main/java/org/iiab/controller/Preferences.java index db563ed..7a7b73c 100644 --- a/apk/controller/app/src/main/java/org/iiab/controller/Preferences.java +++ b/apk/controller/app/src/main/java/org/iiab/controller/Preferences.java @@ -32,6 +32,7 @@ public class Preferences public static final String APPS = "Apps"; public static final String ENABLE = "Enable"; public static final String WATCHDOG_ENABLE = "WatchdogEnable"; + public static final String MAINTENANCE_MODE = "MaintenanceMode"; private SharedPreferences prefs; @@ -193,6 +194,16 @@ public class Preferences editor.commit(); } + public boolean getMaintenanceMode() { + return prefs.getBoolean(MAINTENANCE_MODE, false); + } + + public void setMaintenanceMode(boolean enable) { + SharedPreferences.Editor editor = prefs.edit(); + editor.putBoolean(MAINTENANCE_MODE, enable); + editor.commit(); + } + public int getTunnelMtu() { return 8500; } diff --git a/apk/controller/app/src/main/java/org/iiab/controller/TProxyService.java b/apk/controller/app/src/main/java/org/iiab/controller/TProxyService.java index 5bfb258..141c30a 100644 --- a/apk/controller/app/src/main/java/org/iiab/controller/TProxyService.java +++ b/apk/controller/app/src/main/java/org/iiab/controller/TProxyService.java @@ -226,6 +226,10 @@ public class TProxyService extends VpnService { String selfName = getApplicationContext().getPackageName(); try { builder.addDisallowedApplication(selfName); + if (prefs.getMaintenanceMode()) { // Verify if the maintenance mode is enabled + builder.addDisallowedApplication("com.termux"); + Log.i(TAG, "Maintenance mode enabled: Termux has direct Internet access"); + } } catch (NameNotFoundException e) { } } diff --git a/apk/controller/app/src/main/res/layout/main.xml b/apk/controller/app/src/main/res/layout/main.xml index 1bdc060..3f6f209 100644 --- a/apk/controller/app/src/main/res/layout/main.xml +++ b/apk/controller/app/src/main/res/layout/main.xml @@ -125,23 +125,11 @@ android:elevation="4dp" android:visibility="gone" /> -