diff options
Diffstat (limited to 'main/src/main/java/de/blinkt/openvpn/api/AppRestrictions.java')
-rw-r--r-- | main/src/main/java/de/blinkt/openvpn/api/AppRestrictions.java | 157 |
1 files changed, 138 insertions, 19 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 175ecb70..53919216 100644 --- a/main/src/main/java/de/blinkt/openvpn/api/AppRestrictions.java +++ b/main/src/main/java/de/blinkt/openvpn/api/AppRestrictions.java @@ -14,7 +14,7 @@ import android.text.TextUtils; import de.blinkt.openvpn.VpnProfile; import de.blinkt.openvpn.core.ConfigParser; -import de.blinkt.openvpn.core.Connection; +import de.blinkt.openvpn.core.OpenVPNService; import de.blinkt.openvpn.core.Preferences; import de.blinkt.openvpn.core.ProfileManager; import de.blinkt.openvpn.core.VpnStatus; @@ -22,6 +22,7 @@ import de.blinkt.openvpn.core.VpnStatus; import java.io.IOException; import java.io.StringReader; import java.math.BigInteger; +import java.nio.charset.StandardCharsets; import java.security.MessageDigest; import java.security.NoSuchAlgorithmException; import java.util.*; @@ -33,16 +34,15 @@ public class AppRestrictions { final static int CONFIG_VERSION = 1; static boolean alreadyChecked = false; private static AppRestrictions mInstance; - private RestrictionsManager mRestrictionsMgr; private BroadcastReceiver mRestrictionsReceiver; - private AppRestrictions(Context c) { + private AppRestrictions() { } public static AppRestrictions getInstance(Context c) { if (mInstance == null) - mInstance = new AppRestrictions(c); + mInstance = new AppRestrictions(); return mInstance; } @@ -62,11 +62,12 @@ public class AppRestrictions { c.unregisterReceiver(mRestrictionsReceiver); } - private String hashConfig(String config) { + private String hashConfig(String rawconfig) { + String config = prepare(rawconfig); MessageDigest digest; try { digest = MessageDigest.getInstance("SHA1"); - byte utf8_bytes[] = config.getBytes(); + byte[] utf8_bytes = config.getBytes(StandardCharsets.UTF_8); digest.update(utf8_bytes, 0, utf8_bytes.length); return new BigInteger(1, digest.digest()).toString(16); } catch (NoSuchAlgorithmException e) { @@ -76,10 +77,14 @@ public class AppRestrictions { } private void applyRestrictions(Context c) { - mRestrictionsMgr = (RestrictionsManager) c.getSystemService(Context.RESTRICTIONS_SERVICE); - if (mRestrictionsMgr == null) + RestrictionsManager restrictionsMgr = (RestrictionsManager) c.getSystemService(Context.RESTRICTIONS_SERVICE); + if (restrictionsMgr == null) return; - Bundle restrictions = mRestrictionsMgr.getApplicationRestrictions(); + Bundle restrictions = restrictionsMgr.getApplicationRestrictions(); + parseRestrictionsBundle(c, restrictions); + } + public void parseRestrictionsBundle(Context c, Bundle restrictions) + { if (restrictions == null) return; @@ -94,12 +99,57 @@ public class AppRestrictions { VpnStatus.logError(String.format(Locale.US, "App restriction version %s does not match expected version %d", configVersion, CONFIG_VERSION)); return; } - Parcelable[] profileList = restrictions.getParcelableArray(("vpn_configuration_list")); + Parcelable[] profileList = restrictions.getParcelableArray("vpn_configuration_list"); if (profileList == null) { - VpnStatus.logError("App restriction does not contain a profile list (vpn_configuration_list)"); + VpnStatus.logInfo("App restriction does not contain a profile list. Removing previously added profiles. (vpn_configuration_list)"); + profileList = new Parcelable[]{}; + } + + importVPNProfiles(c, restrictions, profileList); + setAllowedRemoteControl(c, restrictions); + + setMiscSettings(c, restrictions); + } + + private void setAllowedRemoteControl(Context c, Bundle restrictions) { + String allowedApps = restrictions.getString("allowed_remote_access", null); + ExternalAppDatabase extapps = new ExternalAppDatabase(c); + + if (allowedApps == null) + { + extapps.setFlagManagedConfiguration(false); return; } + HashSet<String> restrictionApps = new HashSet<>(); + + for (String package_name:allowedApps.split("[, \n\r]")) { + if (!TextUtils.isEmpty(package_name)) { + restrictionApps.add(package_name); + } + } + extapps.setFlagManagedConfiguration(true); + extapps.clearAllApiApps(); + + if(!extapps.getExtAppList().equals(restrictionApps)) + { + extapps.setAllowedApps(restrictionApps); + } + } + + private static void setMiscSettings(Context c, Bundle restrictions) { + SharedPreferences defaultPrefs = Preferences.getDefaultSharedPreferences(c); + + if(restrictions.containsKey("screenoffpausevpn")) + { + boolean pauseVPN = restrictions.getBoolean("screenoffpausevpn"); + SharedPreferences.Editor editor = defaultPrefs.edit(); + editor.putBoolean("screenoff", pauseVPN); + editor.apply(); + } + } + + private void importVPNProfiles(Context c, Bundle restrictions, Parcelable[] profileList) { Set<String> provisionedUuids = new HashSet<>(); String defaultprofile = restrictions.getString("defaultprofile", null); @@ -116,12 +166,19 @@ public class AppRestrictions { String uuid = p.getString("uuid"); String ovpn = p.getString("ovpn"); String name = p.getString("name"); + String certAlias = p.getString("certificate_alias"); - if (uuid == null || ovpn == null || name == null) { + if (TextUtils.isEmpty(uuid) || TextUtils.isEmpty(ovpn) || TextUtils.isEmpty(name)) { VpnStatus.logError("App restriction profile misses uuid, ovpn or name key"); continue; } + /* we always use lower case uuid since Android UUID class will use present + * them that way */ + uuid = uuid.toLowerCase(Locale.US); + if (defaultprofile != null) + defaultprofile = defaultprofile.toLowerCase(Locale.US); + if (uuid.equals(defaultprofile)) defaultprofileProvisioned = true; @@ -134,12 +191,15 @@ public class AppRestrictions { if (vpnProfile != null) { // Profile exists, check if need to update it - if (ovpnHash.equals(vpnProfile.importedProfileHash)) + if (ovpnHash.equals(vpnProfile.importedProfileHash)) { + addCertificateAlias(vpnProfile, certAlias, c); + // not modified skip to next profile continue; - + } } - addProfile(c, ovpn, uuid, name, vpnProfile); + vpnProfile = addProfile(c, ovpn, uuid, name, vpnProfile); + addCertificateAlias(vpnProfile, certAlias, c); } Vector<VpnProfile> profilesToRemove = new Vector<>(); @@ -155,22 +215,79 @@ public class AppRestrictions { pm.removeProfile(c, vp); } + SharedPreferences defaultPrefs = Preferences.getDefaultSharedPreferences(c); + if (!TextUtils.isEmpty(defaultprofile)) { if (!defaultprofileProvisioned) { VpnStatus.logError("App restrictions: Setting a default profile UUID without providing a profile with that UUID"); } else { - SharedPreferences prefs = Preferences.getDefaultSharedPreferences(c); - String uuid = prefs.getString("alwaysOnVpn", null); + String uuid = defaultPrefs.getString("alwaysOnVpn", null); if (!defaultprofile.equals(uuid)) { - SharedPreferences.Editor editor = prefs.edit(); + SharedPreferences.Editor editor = defaultPrefs.edit(); editor.putString("alwaysOnVpn", defaultprofile); editor.apply(); + } } } } + /** + * If certAlias is non-null will modify the profile type to use the keystore variant of + * the authentication method and will also set the keystore alias + */ + private void addCertificateAlias(VpnProfile vpnProfile, String certAlias, Context c) { + if (vpnProfile == null) + return; + + if (certAlias == null) + certAlias = ""; + + int oldType = vpnProfile.mAuthenticationType; + String oldAlias = vpnProfile.mAlias; + + if (!TextUtils.isEmpty(certAlias)) { + switch (vpnProfile.mAuthenticationType) + { + case VpnProfile.TYPE_PKCS12: + case VpnProfile.TYPE_CERTIFICATES: + vpnProfile.mAuthenticationType = VpnProfile.TYPE_KEYSTORE; + break; + case VpnProfile.TYPE_USERPASS_CERTIFICATES: + case VpnProfile.TYPE_USERPASS_PKCS12: + vpnProfile.mAuthenticationType = VpnProfile.TYPE_USERPASS_KEYSTORE; + break; + } + + } else + { + /* Alias is null, return to non keystore method */ + boolean pkcs12present = !TextUtils.isEmpty(vpnProfile.mPKCS12Filename); + switch (vpnProfile.mAuthenticationType) { + case VpnProfile.TYPE_USERPASS_KEYSTORE: + if (pkcs12present) + vpnProfile.mAuthenticationType = VpnProfile.TYPE_USERPASS_PKCS12; + else + vpnProfile.mAuthenticationType = VpnProfile.TYPE_USERPASS_CERTIFICATES; + break; + case VpnProfile.TYPE_KEYSTORE: + if (pkcs12present) + vpnProfile.mAuthenticationType = VpnProfile.TYPE_PKCS12; + else + vpnProfile.mAuthenticationType = VpnProfile.TYPE_CERTIFICATES; + break; + } + } + vpnProfile.mAlias = certAlias; + + if (!certAlias.equals(oldAlias) || oldType != vpnProfile.mAuthenticationType) + { + ProfileManager pm = ProfileManager.getInstance(c); + pm.saveProfile(c, vpnProfile); + } + } + private String prepare(String config) { String newLine = System.getProperty("line.separator"); if (!config.contains(newLine) && !config.contains(" ")) { @@ -187,7 +304,7 @@ public class AppRestrictions { ; - private void addProfile(Context c, String config, String uuid, String name, VpnProfile vpnProfile) { + VpnProfile addProfile(Context c, String config, String uuid, String name, VpnProfile vpnProfile) { config = prepare(config); ConfigParser cp = new ConfigParser(); try { @@ -213,9 +330,11 @@ public class AppRestrictions { pm.addProfile(vp); pm.saveProfile(c, vp); pm.saveProfileList(c); + return vp; } catch (ConfigParser.ConfigParseError | IOException | IllegalArgumentException e) { VpnStatus.logException("Error during import of managed profile", e); + return null; } } |