From f281c0030144d1439a4e41f1df2f77f0e0070406 Mon Sep 17 00:00:00 2001 From: Arne Schwabe Date: Wed, 15 Jan 2025 07:41:20 +0100 Subject: [PATCH] Implement setting allowed app via app restrictions --- .../blinkt/openvpn/api/AppRestrictions.java | 48 ++++++++++++++++--- main/src/main/res/values/untranslatable.xml | 2 + main/src/main/res/xml/app_restrictions.xml | 5 ++ 3 files changed, 49 insertions(+), 6 deletions(-) diff --git a/main/src/main/java/de/blinkt/openvpn/api/AppRestrictions.java b/main/src/main/java/de/blinkt/openvpn/api/AppRestrictions.java index 9e3764e30b..9133ca0be8 100644 --- a/main/src/main/java/de/blinkt/openvpn/api/AppRestrictions.java +++ b/main/src/main/java/de/blinkt/openvpn/api/AppRestrictions.java @@ -61,13 +61,22 @@ private void removeChangesListener(Context c) { c.unregisterReceiver(mRestrictionsReceiver); } - private String hashConfig(String rawconfig) { + private String hashConfig(String rawconfig, String allowedApps) { String config = prepare(rawconfig); MessageDigest digest; + + if (allowedApps == null) + allowedApps = ""; + + + try { digest = MessageDigest.getInstance("SHA1"); byte[] utf8_bytes = config.getBytes(StandardCharsets.UTF_8); digest.update(utf8_bytes, 0, utf8_bytes.length); + + byte[] apps_bytes = allowedApps.getBytes(StandardCharsets.UTF_8); + digest.update(apps_bytes, 0, apps_bytes.length); return new BigInteger(1, digest.digest()).toString(16); } catch (NoSuchAlgorithmException e) { e.printStackTrace(); @@ -181,6 +190,7 @@ private void importVPNProfiles(Context c, Bundle restrictions, Parcelable[] prof String ovpn = p.getString("ovpn"); String name = p.getString("name"); String certAlias = p.getString("certificate_alias"); + String allowedApps = p.getString("allowed_apps"); if (TextUtils.isEmpty(uuid) || TextUtils.isEmpty(ovpn) || TextUtils.isEmpty(name)) { VpnStatus.logError("App restriction profile misses uuid, ovpn or name key"); @@ -196,13 +206,13 @@ private void importVPNProfiles(Context c, Bundle restrictions, Parcelable[] prof if (uuid.equals(defaultprofile)) defaultprofileProvisioned = true; - String ovpnHash = hashConfig(ovpn); + String ovpnHash = hashConfig(ovpn, allowedApps); provisionedUuids.add(uuid.toLowerCase(Locale.ENGLISH)); // Check if the profile already exists VpnProfile vpnProfile = ProfileManager.get(c, uuid); - + HashSet oldAllowedPackages = null; if (vpnProfile != null) { // Profile exists, check if need to update it if (ovpnHash.equals(vpnProfile.importedProfileHash)) { @@ -211,9 +221,35 @@ private void importVPNProfiles(Context c, Bundle restrictions, Parcelable[] prof // not modified skip to next profile continue; } + oldAllowedPackages = vpnProfile.mAllowedAppsVpn; + } + vpnProfile = addProfile(c, ovpn, uuid, name, vpnProfile, ovpnHash); + if (vpnProfile == null) + { + continue; } - vpnProfile = addProfile(c, ovpn, uuid, name, vpnProfile); + addCertificateAlias(vpnProfile, certAlias, c); + HashSet allowedAppsSet = new HashSet<>(); + if (allowedApps != null && vpnProfile != null){ + for (String app:allowedApps.split("[,: \n\r]")){ + if (!TextUtils.isEmpty(app)) + allowedAppsSet.add(app); + } + if (!allowedAppsSet.equals(vpnProfile.mAllowedAppsVpn)) + { + vpnProfile.mAllowedAppsVpn = allowedAppsSet; + vpnProfile.mAllowedAppsVpnAreDisallowed = false; + pm.saveProfile(c, vpnProfile); + } + + } + if (TextUtils.isEmpty(allowedApps) && oldAllowedPackages != null) + { + vpnProfile.mAllowedAppsVpn = oldAllowedPackages; + pm.saveProfile(c, vpnProfile); + } + } Vector profilesToRemove = new Vector<>(); @@ -318,7 +354,7 @@ private String prepare(String config) { ; - VpnProfile addProfile(Context c, String config, String uuid, String name, VpnProfile vpnProfile) { + VpnProfile addProfile(Context c, String config, String uuid, String name, VpnProfile vpnProfile, String ovpnHash) { config = prepare(config); ConfigParser cp = new ConfigParser(); try { @@ -331,7 +367,7 @@ VpnProfile addProfile(Context c, String config, String uuid, String name, VpnPro vp.mName = name; vp.setUUID(UUID.fromString(uuid)); - vp.importedProfileHash = hashConfig(config); + vp.importedProfileHash = ovpnHash; ProfileManager pm = ProfileManager.getInstance(c); diff --git a/main/src/main/res/values/untranslatable.xml b/main/src/main/res/values/untranslatable.xml index 5caa853db8..560acaae91 100644 --- a/main/src/main/res/values/untranslatable.xml +++ b/main/src/main/res/values/untranslatable.xml @@ -86,6 +86,8 @@ URL Pause VPN when screen is off and less than 64 kB transferred data in 60s Enable the workaround to use an on boot receiver to start the VPN if the Always On VPN functionality is not available + Apps using the VPN + List of packages name (e.g. com.google.chrome) that are should be used with the VPN. Separated by comma, space or newlines Keep the VPN connected even when no network is detected, e.g. when reverse tethering over USB using adb List of apps that are allowed to use the remote AIDL. If this list is in the restrictions, the app will not allowed any changes to the list by the user. Package names of allowed apps separated by comma, space or newlines Remote API access diff --git a/main/src/main/res/xml/app_restrictions.xml b/main/src/main/res/xml/app_restrictions.xml index 9843fada04..d978913221 100644 --- a/main/src/main/res/xml/app_restrictions.xml +++ b/main/src/main/res/xml/app_restrictions.xml @@ -47,6 +47,11 @@ android:key="certificate_alias" android:restrictionType="string" android:title="@string/apprest_certalias" /> +