From 920ded9003a10a61ad0bd756345be24f729f13a5 Mon Sep 17 00:00:00 2001 From: SV Date: Sun, 5 Apr 2020 14:57:41 +0200 Subject: [PATCH 01/10] Update all the things --- app/build.gradle | 54 ++++++----------- app/src/main/AndroidManifest.xml | 2 +- .../de/blinkt/openvpn/core/NetworkSpace.java | 57 +----------------- .../openvpn/core/OpenVpnManagementThread.java | 5 +- .../java/ht/vpn/android/VPNhtApplication.java | 3 - .../vpn/android/activities/BaseActivity.java | 10 +-- .../vpn/android/activities/LogActivity.java | 3 +- .../vpn/android/activities/LoginActivity.java | 5 +- .../vpn/android/activities/MainActivity.java | 7 --- .../activities/PreferencesActivity.java | 9 ++- .../content/adapters/LogListAdapter.java | 3 +- .../adapters/PreferencesListAdapter.java | 3 +- .../ht/vpn/android/fragment/BaseFragment.java | 3 +- .../ht/vpn/android/fragment/LogFragment.java | 7 ++- .../ht/vpn/android/fragment/VPNFragment.java | 7 ++- .../dialog/ConnectingDialogFragment.java | 9 +-- .../dialog/DisconnectingDialogFragment.java | 9 +-- .../dialog/LoadingDialogFragment.java | 9 +-- .../fragment/dialog/RebootDialogFragment.java | 9 +-- .../StringArraySelectorDialogFragment.java | 5 +- app/src/main/res/layout/activity_login.xml | 16 ++--- app/src/main/res/layout/activity_main.xml | 2 +- .../main/res/layout/activity_preferences.xml | 2 +- app/src/main/res/layout/fragment_log.xml | 2 +- app/src/main/res/layout/fragment_vpn.xml | 26 ++++---- .../res/layout/list_icon_twoline_item.xml | 4 +- app/src/main/res/layout/list_subheader.xml | 2 +- app/src/main/res/layout/toolbar.xml | 2 +- app/src/main/res/layout/userpass.xml | 8 +-- app/src/main/res/values-fr/.DS_Store | Bin 6148 -> 0 bytes app/src/main/res/values-fr/strings.xml | 2 +- app/src/main/res/values/styles.xml | 2 +- app/src/main/res/values/vpn_strings.xml | 0 .../main/res/values/vpn_untranslatable.xml | 0 build.gradle | 4 +- gradle.properties | 20 +++--- gradle/wrapper/gradle-wrapper.properties | 4 +- 37 files changed, 121 insertions(+), 194 deletions(-) delete mode 100644 app/src/main/res/values-fr/.DS_Store mode change 100755 => 100644 app/src/main/res/values/vpn_strings.xml mode change 100755 => 100644 app/src/main/res/values/vpn_untranslatable.xml diff --git a/app/build.gradle b/app/build.gradle index ef526c2..a4710d7 100644 --- a/app/build.gradle +++ b/app/build.gradle @@ -1,35 +1,19 @@ import groovy.swing.SwingBuilder -buildscript { - repositories { - jcenter() - maven { url 'https://maven.fabric.io/public' } - } - - dependencies { - classpath 'io.fabric.tools:gradle:1.19.1' - } -} - plugins { id 'com.github.ben-manes.versions' version '0.13.0' } apply plugin: 'com.android.application' -apply plugin: 'io.fabric' - -repositories { - maven { url 'https://maven.fabric.io/public' } -} android { - compileSdkVersion 24 - buildToolsVersion "24.0.0" + compileSdkVersion 28 + buildToolsVersion "28.0.3" defaultConfig { applicationId "ht.vpn.android.app" - minSdkVersion 15 - targetSdkVersion 24 + minSdkVersion 23 + targetSdkVersion 28 versionCode 15 versionName "1.3.0" resValue "string", "geokey", System.getenv("VPNHT_GEO_KEY").toString() @@ -57,27 +41,23 @@ android { } ext { - supportLibVersion = "24.0.0" + supportLibVersion = "28.0.0" } // ./gradlew(.bat) dependencyUpdates -Drevision=release dependencies { - compile fileTree(dir: 'libs', include: ['*.jar']) - compile "com.android.support:support-v13:${supportLibVersion}" - compile "com.android.support:appcompat-v7:${supportLibVersion}" - compile "com.android.support:cardview-v7:${supportLibVersion}" - compile "com.android.support:recyclerview-v7:${supportLibVersion}" - compile "com.android.support:design:${supportLibVersion}" - compile "com.android.support:support-annotations:${supportLibVersion}" - compile 'com.google.android.gms:play-services-maps:9.2.1' - compile 'com.github.johnkil.android-robototextview:robototextview:2.4.0' - compile 'com.jakewharton:butterknife:7.0.1' - compile 'com.mobsandgeeks:android-saripaar:2.0.2' - compile 'com.squareup.retrofit:retrofit:1.9.0' - compile 'com.jakewharton.timber:timber:3.1.0' - compile('com.crashlytics.sdk.android:crashlytics:2.5.2@aar') { - transitive = true; - } + implementation fileTree(dir: 'libs', include: ['*.jar']) + implementation "androidx.appcompat:appcompat:1.1.0" + implementation "androidx.recyclerview:recyclerview:1.1.0" + implementation "androidx.cardview:cardview:1.0.0" + implementation "androidx.annotation:annotation:1.1.0" + implementation "com.google.android.material:material:1.1.0" + implementation 'com.google.android.gms:play-services-maps:17.0.0' + implementation 'com.mobsandgeeks:android-saripaar:2.0.2' + implementation 'com.squareup.retrofit:retrofit:1.9.0' + implementation 'com.jakewharton.timber:timber:3.1.0' + annotationProcessor 'com.jakewharton:butterknife:7.0.1' + implementation 'com.jakewharton:butterknife:7.0.1' } gradle.taskGraph.whenReady { taskGraph -> diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml index 3cef701..152556b 100644 --- a/app/src/main/AndroidManifest.xml +++ b/app/src/main/AndroidManifest.xml @@ -53,7 +53,7 @@ tools:ignore="ExportedActivity"> - - + diff --git a/app/src/main/java/de/blinkt/openvpn/core/NetworkSpace.java b/app/src/main/java/de/blinkt/openvpn/core/NetworkSpace.java index 26219e0..b1b788b 100644 --- a/app/src/main/java/de/blinkt/openvpn/core/NetworkSpace.java +++ b/app/src/main/java/de/blinkt/openvpn/core/NetworkSpace.java @@ -6,10 +6,9 @@ package de.blinkt.openvpn.core; import android.os.Build; -import android.support.annotation.NonNull; import android.text.TextUtils; -import junit.framework.Assert; +import androidx.annotation.NonNull; import java.math.BigInteger; import java.net.Inet6Address; @@ -145,22 +144,15 @@ public String toString() { public ipAddress[] split() { ipAddress firstHalf = new ipAddress(getFirstAddress(), networkMask + 1, included, isV4); ipAddress secondHalf = new ipAddress(firstHalf.getLastAddress().add(BigInteger.ONE), networkMask + 1, included, isV4); - if (BuildConfig.DEBUG) Assert.assertTrue(secondHalf.getLastAddress().equals(getLastAddress())); return new ipAddress[]{firstHalf, secondHalf}; } String getIPv4Address() { - if (BuildConfig.DEBUG) { - Assert.assertTrue (isV4); - Assert.assertTrue (netAddress.longValue() <= 0xffffffffl); - Assert.assertTrue (netAddress.longValue() >= 0); - } long ip = netAddress.longValue(); return String.format(Locale.US, "%d.%d.%d.%d", (ip >> 24) % 256, (ip >> 16) % 256, (ip >> 8) % 256, ip % 256); } String getIPv6Address() { - if (BuildConfig.DEBUG) Assert.assertTrue (!isV4); BigInteger r = netAddress; if (r.compareTo(BigInteger.ZERO)==0 && networkMask==0) return "::"; @@ -236,7 +228,6 @@ TreeSet generateIPList() { // Check if it and the next of it are compatible ipAddress nextNet = networks.poll(); - if (BuildConfig.DEBUG) Assert.assertNotNull(currentNet); if (nextNet== null || currentNet.getLastAddress().compareTo(nextNet.getFirstAddress()) == -1) { // Everything good, no overlapping nothing to do ipsDone.add(currentNet); @@ -260,21 +251,13 @@ TreeSet generateIPList() { if (!networks.contains(newNets[1])) networks.add(newNets[1]); - if (newNets[0].getLastAddress().equals(currentNet.getLastAddress())) { - if (BuildConfig.DEBUG) Assert.assertEquals (newNets[0].networkMask, currentNet.networkMask); - // Don't add the lower half that would conflict with currentNet - } else { + if (!newNets[0].getLastAddress().equals(currentNet.getLastAddress())) { if (!networks.contains(newNets[0])) networks.add(newNets[0]); } // Keep currentNet as is } } else { - if (BuildConfig.DEBUG) { - Assert.assertTrue(currentNet.networkMask < nextNet.networkMask); - Assert.assertTrue (nextNet.getFirstAddress().compareTo(currentNet.getFirstAddress()) == 1); - Assert.assertTrue (currentNet.getLastAddress().compareTo(nextNet.getLastAddress()) != -1); - } // This network is bigger than the next and last ip of current >= next //noinspection StatementWithEmptyBody @@ -287,11 +270,6 @@ TreeSet generateIPList() { if (newNets[1].networkMask == nextNet.networkMask) { - if (BuildConfig.DEBUG) { - Assert.assertTrue (newNets[1].getFirstAddress().equals(nextNet.getFirstAddress())); - Assert.assertTrue (newNets[1].getLastAddress().equals(currentNet.getLastAddress())); - // split second equal the next network, do not add it - } networks.add(nextNet); } else { // Add the smaller network first @@ -312,41 +290,12 @@ TreeSet generateIPList() { Collection getPositiveIPList() { TreeSet ipsSorted = generateIPList(); - Vector ips = new Vector(); + Vector ips = new Vector<>(); for (ipAddress ia : ipsSorted) { if (ia.included) ips.add(ia); } - if (Build.VERSION.SDK_INT < Build.VERSION_CODES.KITKAT) { - // Include postive routes from the original set under < 4.4 since these might overrule the local - // network but only if no smaller negative route exists - for(ipAddress origIp: mIpAddresses){ - if (!origIp.included) - continue; - - // The netspace exists - if(ipsSorted.contains(origIp)) - continue; - - boolean skipIp=false; - // If there is any smaller net that is excluded we may not add the positive route back - - for (ipAddress calculatedIp: ipsSorted) { - if(!calculatedIp.included && origIp.containsNet(calculatedIp)) { - skipIp=true; - break; - } - } - if (skipIp) - continue; - - // It is safe to include the IP - ips.add(origIp); - } - - } - return ips; } diff --git a/app/src/main/java/de/blinkt/openvpn/core/OpenVpnManagementThread.java b/app/src/main/java/de/blinkt/openvpn/core/OpenVpnManagementThread.java index 3af3ec0..16cba52 100644 --- a/app/src/main/java/de/blinkt/openvpn/core/OpenVpnManagementThread.java +++ b/app/src/main/java/de/blinkt/openvpn/core/OpenVpnManagementThread.java @@ -12,10 +12,10 @@ import android.net.LocalSocketAddress; import android.os.ParcelFileDescriptor; import android.preference.PreferenceManager; -import android.support.annotation.NonNull; import android.util.Log; -import junit.framework.Assert; + +import androidx.annotation.NonNull; import java.io.FileDescriptor; import java.io.IOException; @@ -407,7 +407,6 @@ private void processNeedCommand(String argument) { */ if (routeparts.length == 5) { - if (BuildConfig.DEBUG) Assert.assertEquals("dev", routeparts[3]); mOpenVPNService.addRoute(routeparts[0], routeparts[1], routeparts[2], routeparts[4]); } else if (routeparts.length >= 3) { mOpenVPNService.addRoute(routeparts[0], routeparts[1], routeparts[2], null); diff --git a/app/src/main/java/ht/vpn/android/VPNhtApplication.java b/app/src/main/java/ht/vpn/android/VPNhtApplication.java index 7fd6683..6346afc 100644 --- a/app/src/main/java/ht/vpn/android/VPNhtApplication.java +++ b/app/src/main/java/ht/vpn/android/VPNhtApplication.java @@ -2,12 +2,10 @@ import android.app.Application; -import com.crashlytics.android.Crashlytics; import de.blinkt.openvpn.core.PRNGFixes; import de.blinkt.openvpn.core.VpnStatus; import ht.vpn.android.utils.PrefUtils; -import io.fabric.sdk.android.Fabric; import timber.log.Timber; public class VPNhtApplication extends Application implements VpnStatus.StateListener { @@ -19,7 +17,6 @@ public class VPNhtApplication extends Application implements VpnStatus.StateList public void onCreate() { super.onCreate(); PRNGFixes.apply(); - Fabric.with(this, new Crashlytics()); sThis = this; if (BuildConfig.DEBUG) { diff --git a/app/src/main/java/ht/vpn/android/activities/BaseActivity.java b/app/src/main/java/ht/vpn/android/activities/BaseActivity.java index 667361a..7b02190 100644 --- a/app/src/main/java/ht/vpn/android/activities/BaseActivity.java +++ b/app/src/main/java/ht/vpn/android/activities/BaseActivity.java @@ -1,16 +1,16 @@ package ht.vpn.android.activities; import android.os.Bundle; -import android.os.PersistableBundle; -import android.support.annotation.Nullable; -import android.support.v7.app.AppCompatActivity; -import android.support.v7.widget.Toolbar; + +import androidx.annotation.Nullable; +import androidx.appcompat.app.AppCompatActivity; +import androidx.appcompat.widget.Toolbar; import butterknife.ButterKnife; import butterknife.Bind; import ht.vpn.android.R; -public class BaseActivity extends AppCompatActivity { +public abstract class BaseActivity extends AppCompatActivity { @Nullable @Bind(R.id.toolbar) diff --git a/app/src/main/java/ht/vpn/android/activities/LogActivity.java b/app/src/main/java/ht/vpn/android/activities/LogActivity.java index 646dc52..6ed1666 100755 --- a/app/src/main/java/ht/vpn/android/activities/LogActivity.java +++ b/app/src/main/java/ht/vpn/android/activities/LogActivity.java @@ -1,7 +1,8 @@ package ht.vpn.android.activities; import android.os.Bundle; -import android.support.v7.app.ActionBar; + +import androidx.appcompat.app.ActionBar; import ht.vpn.android.R; import ht.vpn.android.fragment.LogFragment; diff --git a/app/src/main/java/ht/vpn/android/activities/LoginActivity.java b/app/src/main/java/ht/vpn/android/activities/LoginActivity.java index 809d859..bf99462 100644 --- a/app/src/main/java/ht/vpn/android/activities/LoginActivity.java +++ b/app/src/main/java/ht/vpn/android/activities/LoginActivity.java @@ -1,13 +1,15 @@ package ht.vpn.android.activities; +import android.annotation.SuppressLint; import android.content.Intent; import android.net.Uri; import android.os.Bundle; -import android.support.annotation.NonNull; import android.view.View; import android.widget.EditText; import android.widget.Toast; +import androidx.annotation.NonNull; + import com.mobsandgeeks.saripaar.ValidationError; import com.mobsandgeeks.saripaar.Validator; import com.mobsandgeeks.saripaar.annotation.NotEmpty; @@ -40,6 +42,7 @@ public class LoginActivity extends BaseActivity implements Validator.ValidationL @Bind(R.id.passwordEdit) EditText mPassword; + @SuppressLint("MissingSuperCall") @Override public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState, R.layout.activity_login); diff --git a/app/src/main/java/ht/vpn/android/activities/MainActivity.java b/app/src/main/java/ht/vpn/android/activities/MainActivity.java index b6019da..dd18e80 100644 --- a/app/src/main/java/ht/vpn/android/activities/MainActivity.java +++ b/app/src/main/java/ht/vpn/android/activities/MainActivity.java @@ -1,18 +1,12 @@ package ht.vpn.android.activities; -import android.app.Activity; -import android.content.ActivityNotFoundException; import android.content.ComponentName; import android.content.Context; import android.content.Intent; import android.content.ServiceConnection; -import android.content.SharedPreferences; -import android.net.VpnService; import android.os.Bundle; import android.os.IBinder; -import android.preference.PreferenceManager; import android.view.Menu; -import android.view.MenuInflater; import android.view.MenuItem; import android.widget.Toast; @@ -20,7 +14,6 @@ import de.blinkt.openvpn.core.VpnStatus; import ht.vpn.android.Preferences; import ht.vpn.android.R; -import ht.vpn.android.VPNhtApplication; import ht.vpn.android.utils.NetworkUtils; import ht.vpn.android.utils.PrefUtils; diff --git a/app/src/main/java/ht/vpn/android/activities/PreferencesActivity.java b/app/src/main/java/ht/vpn/android/activities/PreferencesActivity.java index ffc3d60..b1f3dbb 100644 --- a/app/src/main/java/ht/vpn/android/activities/PreferencesActivity.java +++ b/app/src/main/java/ht/vpn/android/activities/PreferencesActivity.java @@ -3,14 +3,14 @@ import android.content.DialogInterface; import android.content.Intent; import android.content.SharedPreferences; -import android.graphics.Color; import android.os.Bundle; -import android.support.v7.app.ActionBar; -import android.support.v7.widget.LinearLayoutManager; -import android.support.v7.widget.RecyclerView; import android.view.MenuItem; import android.view.View; +import androidx.appcompat.app.ActionBar; +import androidx.recyclerview.widget.LinearLayoutManager; +import androidx.recyclerview.widget.RecyclerView; + import java.util.ArrayList; import java.util.Arrays; import java.util.List; @@ -18,7 +18,6 @@ import butterknife.Bind; import ht.vpn.android.Preferences; import ht.vpn.android.R; -import ht.vpn.android.VpnProfile; import ht.vpn.android.content.PrefItem; import ht.vpn.android.content.adapters.PreferencesListAdapter; import ht.vpn.android.fragment.dialog.StringArraySelectorDialogFragment; diff --git a/app/src/main/java/ht/vpn/android/content/adapters/LogListAdapter.java b/app/src/main/java/ht/vpn/android/content/adapters/LogListAdapter.java index 0eb4e39..56ee804 100644 --- a/app/src/main/java/ht/vpn/android/content/adapters/LogListAdapter.java +++ b/app/src/main/java/ht/vpn/android/content/adapters/LogListAdapter.java @@ -2,11 +2,12 @@ import android.content.Context; import android.graphics.Color; -import android.support.v7.widget.RecyclerView; import android.view.View; import android.view.ViewGroup; import android.widget.TextView; +import androidx.recyclerview.widget.RecyclerView; + import java.text.SimpleDateFormat; import java.util.Collections; import java.util.Date; diff --git a/app/src/main/java/ht/vpn/android/content/adapters/PreferencesListAdapter.java b/app/src/main/java/ht/vpn/android/content/adapters/PreferencesListAdapter.java index 37e0a09..2efc5ae 100644 --- a/app/src/main/java/ht/vpn/android/content/adapters/PreferencesListAdapter.java +++ b/app/src/main/java/ht/vpn/android/content/adapters/PreferencesListAdapter.java @@ -1,7 +1,6 @@ package ht.vpn.android.content.adapters; import android.graphics.PorterDuff; -import android.support.v7.widget.RecyclerView; import android.view.LayoutInflater; import android.view.View; import android.view.ViewGroup; @@ -9,6 +8,8 @@ import android.widget.ImageView; import android.widget.TextView; +import androidx.recyclerview.widget.RecyclerView; + import java.util.List; import butterknife.ButterKnife; diff --git a/app/src/main/java/ht/vpn/android/fragment/BaseFragment.java b/app/src/main/java/ht/vpn/android/fragment/BaseFragment.java index 32e7842..c1e1c25 100644 --- a/app/src/main/java/ht/vpn/android/fragment/BaseFragment.java +++ b/app/src/main/java/ht/vpn/android/fragment/BaseFragment.java @@ -1,9 +1,10 @@ package ht.vpn.android.fragment; import android.os.Bundle; -import android.support.v4.app.Fragment; import android.view.View; +import androidx.fragment.app.Fragment; + import butterknife.ButterKnife; public abstract class BaseFragment extends Fragment { diff --git a/app/src/main/java/ht/vpn/android/fragment/LogFragment.java b/app/src/main/java/ht/vpn/android/fragment/LogFragment.java index 0cc51cf..4848910 100644 --- a/app/src/main/java/ht/vpn/android/fragment/LogFragment.java +++ b/app/src/main/java/ht/vpn/android/fragment/LogFragment.java @@ -2,9 +2,6 @@ import android.content.Intent; import android.os.Bundle; -import android.support.annotation.Nullable; -import android.support.v7.widget.LinearLayoutManager; -import android.support.v7.widget.RecyclerView; import android.view.LayoutInflater; import android.view.Menu; import android.view.MenuInflater; @@ -12,6 +9,10 @@ import android.view.View; import android.view.ViewGroup; +import androidx.annotation.Nullable; +import androidx.recyclerview.widget.LinearLayoutManager; +import androidx.recyclerview.widget.RecyclerView; + import butterknife.Bind; import ht.vpn.android.R; import ht.vpn.android.content.adapters.LogListAdapter; diff --git a/app/src/main/java/ht/vpn/android/fragment/VPNFragment.java b/app/src/main/java/ht/vpn/android/fragment/VPNFragment.java index fab3a00..afaa82a 100644 --- a/app/src/main/java/ht/vpn/android/fragment/VPNFragment.java +++ b/app/src/main/java/ht/vpn/android/fragment/VPNFragment.java @@ -8,9 +8,6 @@ import android.os.Bundle; import android.os.Handler; import android.os.Looper; -import android.support.annotation.Nullable; -import android.support.design.widget.Snackbar; -import android.support.v7.widget.CardView; import android.view.LayoutInflater; import android.view.View; import android.view.ViewGroup; @@ -21,6 +18,9 @@ import android.widget.TextView; import android.widget.Toast; +import androidx.annotation.Nullable; +import androidx.cardview.widget.CardView; + import com.google.android.gms.maps.CameraUpdateFactory; import com.google.android.gms.maps.GoogleMap; import com.google.android.gms.maps.OnMapReadyCallback; @@ -29,6 +29,7 @@ import com.google.android.gms.maps.model.LatLng; import com.google.android.gms.maps.model.Marker; import com.google.android.gms.maps.model.MarkerOptions; +import com.google.android.material.snackbar.Snackbar; import java.io.IOException; import java.io.StringReader; diff --git a/app/src/main/java/ht/vpn/android/fragment/dialog/ConnectingDialogFragment.java b/app/src/main/java/ht/vpn/android/fragment/dialog/ConnectingDialogFragment.java index 2fc924f..7cf5c34 100644 --- a/app/src/main/java/ht/vpn/android/fragment/dialog/ConnectingDialogFragment.java +++ b/app/src/main/java/ht/vpn/android/fragment/dialog/ConnectingDialogFragment.java @@ -5,10 +5,11 @@ import android.app.Dialog; import android.app.ProgressDialog; import android.os.Bundle; -import android.support.annotation.NonNull; -import android.support.v4.app.DialogFragment; -import android.support.v4.app.Fragment; -import android.support.v4.app.FragmentManager; + +import androidx.annotation.NonNull; +import androidx.fragment.app.DialogFragment; +import androidx.fragment.app.Fragment; +import androidx.fragment.app.FragmentManager; import de.blinkt.openvpn.core.VpnStatus; import ht.vpn.android.R; diff --git a/app/src/main/java/ht/vpn/android/fragment/dialog/DisconnectingDialogFragment.java b/app/src/main/java/ht/vpn/android/fragment/dialog/DisconnectingDialogFragment.java index 45ed80f..63ef6ce 100644 --- a/app/src/main/java/ht/vpn/android/fragment/dialog/DisconnectingDialogFragment.java +++ b/app/src/main/java/ht/vpn/android/fragment/dialog/DisconnectingDialogFragment.java @@ -4,10 +4,11 @@ import android.app.Dialog; import android.app.ProgressDialog; import android.os.Bundle; -import android.support.annotation.NonNull; -import android.support.v4.app.DialogFragment; -import android.support.v4.app.Fragment; -import android.support.v4.app.FragmentManager; + +import androidx.annotation.NonNull; +import androidx.fragment.app.DialogFragment; +import androidx.fragment.app.Fragment; +import androidx.fragment.app.FragmentManager; import ht.vpn.android.R; diff --git a/app/src/main/java/ht/vpn/android/fragment/dialog/LoadingDialogFragment.java b/app/src/main/java/ht/vpn/android/fragment/dialog/LoadingDialogFragment.java index 630e4e1..a9ee9d4 100644 --- a/app/src/main/java/ht/vpn/android/fragment/dialog/LoadingDialogFragment.java +++ b/app/src/main/java/ht/vpn/android/fragment/dialog/LoadingDialogFragment.java @@ -4,10 +4,11 @@ import android.app.Dialog; import android.app.ProgressDialog; import android.os.Bundle; -import android.support.annotation.NonNull; -import android.support.v4.app.DialogFragment; -import android.support.v4.app.Fragment; -import android.support.v4.app.FragmentManager; + +import androidx.annotation.NonNull; +import androidx.fragment.app.DialogFragment; +import androidx.fragment.app.Fragment; +import androidx.fragment.app.FragmentManager; import ht.vpn.android.R; diff --git a/app/src/main/java/ht/vpn/android/fragment/dialog/RebootDialogFragment.java b/app/src/main/java/ht/vpn/android/fragment/dialog/RebootDialogFragment.java index f846bb6..4133205 100644 --- a/app/src/main/java/ht/vpn/android/fragment/dialog/RebootDialogFragment.java +++ b/app/src/main/java/ht/vpn/android/fragment/dialog/RebootDialogFragment.java @@ -4,10 +4,11 @@ import android.app.AlertDialog; import android.app.Dialog; import android.os.Bundle; -import android.support.annotation.NonNull; -import android.support.v4.app.DialogFragment; -import android.support.v4.app.Fragment; -import android.support.v4.app.FragmentManager; + +import androidx.annotation.NonNull; +import androidx.fragment.app.DialogFragment; +import androidx.fragment.app.Fragment; +import androidx.fragment.app.FragmentManager; import ht.vpn.android.R; diff --git a/app/src/main/java/ht/vpn/android/fragment/dialog/StringArraySelectorDialogFragment.java b/app/src/main/java/ht/vpn/android/fragment/dialog/StringArraySelectorDialogFragment.java index dde6718..3835f29 100644 --- a/app/src/main/java/ht/vpn/android/fragment/dialog/StringArraySelectorDialogFragment.java +++ b/app/src/main/java/ht/vpn/android/fragment/dialog/StringArraySelectorDialogFragment.java @@ -5,8 +5,9 @@ import android.app.Dialog; import android.content.DialogInterface; import android.os.Bundle; -import android.support.v4.app.DialogFragment; -import android.support.v4.app.FragmentManager; + +import androidx.fragment.app.DialogFragment; +import androidx.fragment.app.FragmentManager; import java.util.List; diff --git a/app/src/main/res/layout/activity_login.xml b/app/src/main/res/layout/activity_login.xml index ae4f93c..c1c39a6 100644 --- a/app/src/main/res/layout/activity_login.xml +++ b/app/src/main/res/layout/activity_login.xml @@ -17,7 +17,7 @@ android:contentDescription="@string/app_name" android:scaleType="fitCenter" /> - - - + - - - + - - - - - \ No newline at end of file diff --git a/app/src/main/res/layout/fragment_vpn.xml b/app/src/main/res/layout/fragment_vpn.xml index cf961ac..0a2cf30 100644 --- a/app/src/main/res/layout/fragment_vpn.xml +++ b/app/src/main/res/layout/fragment_vpn.xml @@ -12,7 +12,7 @@ android:layout_marginTop="@dimen/activity_vertical_margin" android:orientation="vertical"> - - - + - - + - - + - - + - - - - - - - - + - - + H1@V-^m;4Wg<&0T*E43hX&L&p$$qDprKhvt+--jT7}7np#A3 zem<@ulZcFPQ@L2!n>{z**++&mCkOWA81W14cNZlEfg7;MkzE(HCqgga^y>{tEnwC%0;vJ&^%eQ zLs35+`xjp>T0Mot de passe Connexion Enregistrement - L'identifiant ou le mot de passe est erroné + L\'identifiant ou le mot de passe est erroné Préférences diff --git a/app/src/main/res/values/styles.xml b/app/src/main/res/values/styles.xml index 07cb50a..5ebf4eb 100644 --- a/app/src/main/res/values/styles.xml +++ b/app/src/main/res/values/styles.xml @@ -1,7 +1,7 @@ - - - - - - - - diff --git a/app/src/main/res/values/vpn_plurals.xml b/app/src/main/res/values/vpn_plurals.xml new file mode 100644 index 0000000..1c5a03b --- /dev/null +++ b/app/src/main/res/values/vpn_plurals.xml @@ -0,0 +1,19 @@ + + + + One month left + %d months left + + + One day left + %d days left + + + One hour left + %d hours left + + + One minute left + %d minutes left + + \ No newline at end of file diff --git a/app/src/main/res/values/vpn_strings.xml b/app/src/main/res/values/vpn_strings.xml index e9b6f82..5180b7f 100644 --- a/app/src/main/res/values/vpn_strings.xml +++ b/app/src/main/res/values/vpn_strings.xml @@ -1,5 +1,5 @@ @@ -17,7 +17,7 @@ PKCS12 File CA Certificate You must select a certificate - Source code and issue tracker available at http://code.google.com/p/ics-openvpn/ + Source code and issue tracker available at https://github.com/schwabe/ics-openvpn/ This program uses the following components; see the source code for full details on the licenses About Profiles @@ -41,13 +41,14 @@ Please enter a unique Profile Name Profile Name You must select a User certificate + You must select a CA certificate No error found Error in Configuration Error parsing the IPv4 address Error parsing the custom routes (leave empty to query on demand) OpenVPN Shortcut - Connect to VPN + Connecting to VPN… Profile specified in shortcut not found Random Host Prefix Adds 6 random chars in front of hostname @@ -80,7 +81,7 @@ Secondary DNS Server used if the normal DNS Server cannot be reached. Backup DNS Server Ignore pushed routes - Ignore routed pushed by the server. + Ignore routes pushed by the server. Redirects all Traffic over the VPN Use default Route Enter custom routes. Only enter destination in CIDR format. \"10.0.0.0/8 2002::/16\" would direct the networks 10.0.0.0/8 and 2002::/16 over the VPN. @@ -110,12 +111,12 @@ %1$s %2$s Send log file Send - VPN.ht log file + ICS OpenVPN log file Copied log entry to clip board Tap Mode Tap Mode is not possible with the non root VPN API. Therefore this application cannot provide tap support Again? Are you kidding? No, tap mode is really not supported and sending more mail asking if it will be supported will not help. - A third time? Actually, one could write a a tap emulator based on tun that would add layer2 information on send and strip layer2 information on receive. But this tap emulator would also have to implement ARP and possibly a DHCP client. I am not aware of anybody doing any work in this direction. Contact me if you want to start coding on this. + A third time? Actually, one could write a tap emulator based on tun that would add layer2 information on send and strip layer2 information on receive. But this tap emulator would also have to implement ARP and possibly a DHCP client. I am not aware of anybody doing any work in this direction. Contact me if you want to start coding on this. FAQ Copying log entries To copy a single log entry press and hold on the log entry. To copy/send the whole log use the Send Log option. Use the hardware menu button, if the button is not visible in the GUI. @@ -135,7 +136,7 @@ Refusing to open tun device without IP information Import Profile from ovpn file Import - Could not read Profile to import + Could not read profile to import Error reading config file add Profile Could not find file %1$s mentioned in the imported config file @@ -156,11 +157,11 @@ imported profile imported profile %d Broken Images - <p>Official HTC images are known to have a strange routing problem causing traffic not to flow through the tunnel (See also <a href="http://code.google.com/p/ics-openvpn/issues/detail?id=18">Issue 18</a> in the bug tracker.)</p><p>Older official SONY images from Xperia Arc S and Xperia Ray have been reported to be missing the VPNService completely from the image. (See also <a href="http://code.google.com/p/ics-openvpn/issues/detail?id=29">Issue 29</a> in the bug tracker.)</p><p>On custom build images the tun module might be missing or the rights of /dev/tun might be wrong. Some CM9 images need the "Fix ownership" option under "Device specific hacks" enabled.</p><p>Most importantly: If your device has a broken Android image, report it to your vendor. The more people who report an issue to the vendor, the more likely they are to fix it.</p> + <p>Official HTC images are known to have a strange routing problem causing traffic not to flow through the tunnel (See also <a href="https://github.com/schwabe/ics-openvpn/issues/18">Issue 18</a> in the bug tracker.)</p><p>Older official SONY images from Xperia Arc S and Xperia Ray have been reported to be missing the VPNService completely from the image. (See also <a href="https://github.com/schwabe/ics-openvpn/issues/29">Issue 29</a> in the bug tracker.)</p><p>On custom build images the tun module might be missing or the rights of /dev/tun might be wrong. Some CM9 images need the "Fix ownership" option under "Device specific hacks" enabled.</p><p>Most importantly: If your device has a broken Android image, report it to your vendor. The more people who report an issue to the vendor, the more likely they are to fix it.</p> PKCS12 File Encryption Key Private Key Password file icon - TLS Authentication + TLS Authentication/Encryption Generated Config Settings Tries to set the owner of /dev/tun to system. Some CM9 images need this to make the VPNService API work. Requires root. @@ -176,8 +177,9 @@ No CA Certificate returned while reading from Android keystore. Authentication will probably fail. Shows the log window on connect. The log window can always be accessed from the notification status. Show log window - Running on %1$s (%2$s) %3$s, Android API %4$d + %10$s %9$s running on %3$s %1$s (%2$s), Android %6$s (%7$s) API %4$d, ABI %5$s, (%8$s) Error signing with Android keystore key %1$s: %2$s + Error signing with external authenticator app (%3$s): %1$s: %2$s The VPN connection warning telling you that this app can intercept all traffic is imposed by the system to prevent abuse of the VPNService API.\nThe VPN connection notification (The key symbol) is also imposed by the Android system to signal an ongoing VPN connection. On some images this notification plays a sound.\nAndroid introduced these system dialogs for your own safety and made sure that they cannot be circumvented. (On some images this unfortunately includes a notification sound) Connection warning and notification sound English translation by Arne Schwabe<arne@rfc2549.org> @@ -186,22 +188,21 @@ Routing Obscure OpenVPN Settings. Normally not needed. Advanced - VPN.ht Config + ICS Openvpn Config No DNS servers being used. Name resolution may not work. Consider setting custom DNS Servers. Please also note that Android will keep using your proxy settings specified for your mobile/Wi-Fi connection when no DNS servers are set. Could not add DNS Server \"%1$s\", rejected by the system: %2$s Could not configure IP Address \"%1$s\", rejected by the system: %2$s - <p>Get a working config (tested on your computer or download from your provider/organisation)</p><p>If it is a single file with no extra pem/pks12 files you can email the file yourself and open the attachment. If you have multiple files put them on your sd card.</p><p>Click on the email attachment/Use the folder icon in the vpn list to import the config file</p><p>If there are errors about missing files put the missing files on your sd card.</p><p>Click on the save symbol to add the imported VPN to your VPN list</p><p>Connect the VPN by clicking on the name of the VPN</p><p>If there are error or warnings in the log try to understand the warnings/error and try to fix them</p> + <p>Get a working config (tested on your computer or download from your provider/organisation)</p><p>If it is a single file with no extra pem/pkcs12 files you can email the file yourself and open the attachment. If you have multiple files put them on your sd card.</p><p>Click on the email attachment/Use the folder icon in the vpn list to import the config file</p><p>If there are errors about missing files put the missing files on your sd card.</p><p>Click on the save symbol to add the imported VPN to your VPN list</p><p>Connect the VPN by clicking on the name of the VPN</p><p>If there are error or warnings in the log try to understand the warnings/error and try to fix them</p> Quick Start Try to load the tun.ko kernel module before trying to connect. Needs rooted devices. Load tun module Import PKCS12 from configuration into Android Keystore Error getting proxy settings: %s - Using proxy %1$s %2$d + Using proxy %1$s %2$s Use system proxy Use the system wide configuration for HTTP/HTTPS proxies to connect. - You can <a href=\"https://www.paypal.com/cgi-bin/webscr?hosted_button_id=R2M6ZP9AF25LS&amp;cmd=_s-xclick\">donate with PayPal</a> - OpenVPN will reconnect a VPN if it was active on system reboot/shutdown. Please read the Connection warning FAQ before using this option. - Reconnect on reboot + OpenVPN will connect the specified VPN if it was active on system boot. Please read the connection warning FAQ before using this option on Android < 5.0. + Connect on boot Ignore Restart Configuration changes are applied after restarting the VPN. (Re)start the VPN now? @@ -220,17 +221,17 @@ OpenVPN Log Import OpenVPN configuration Battery consumption - In my personal tests the main reason for high battery consumption of OpenVPN are the keepalive packets. Most OpenVPN servers have a configuration directive like \'keepalive 10 60\' which causes the client and server to exchange keepalive packets every ten seconds. <p> While these packets are small and do not use much traffic, they keep the mobile radio network busy and increase the energy consumption. (See also <a href="http://developer.android.com/training/efficient-downloads/efficient-network-access.html#RadioStateMachine">The Radio State Machine | Android Developers</a>) <p> This keepalive setting cannot be changed on the client. Only the system administrator of the OpenVPN can change the setting. <p> Unfortunately using a keepalive larger than 60 seconds with UDP can cause some NAT gateways to drop the connection due to an inactivity timeout. Using TCP with a long keep alive timeout works, but tunneling TCP over TCP performs extremely poorly on connections with high packet loss. (See <a href="http://sites.inka.de/bigred/devel/tcp-tcp.html">Why TCP Over TCP Is A Bad Idea</a>) - The Android Tethering feature (over WiFi, USB or Bluetooth) and the VPNService API (used by this program) do not work together. For more details see the <a href=\"http://code.google.com/p/ics-openvpn/issues/detail?id=34\">issue #34</a> + In my personal tests the main reason for high battery consumption of OpenVPN are the keepalive packets. Most OpenVPN servers have a configuration directive like \'keepalive 10 60\' which causes the client and server to exchange keepalive packets every ten seconds. <p> While these packets are small and do not use much traffic, they keep the mobile radio network busy and increase the energy consumption. (See also <a href="https://developer.android.com/training/efficient-downloads/efficient-network-access.html#RadioStateMachine">The Radio State Machine | Android Developers</a>) <p> This keepalive setting cannot be changed on the client. Only the system administrator of the OpenVPN can change the setting. <p> Unfortunately using a keepalive larger than 60 seconds with UDP can cause some NAT gateways to drop the connection due to an inactivity timeout. Using TCP with a long keep alive timeout works, but tunneling TCP over TCP performs extremely poorly on connections with high packet loss. (See <a href="http://sites.inka.de/bigred/devel/tcp-tcp.html">Why TCP Over TCP Is A Bad Idea</a>) + The Android Tethering feature (over WiFi, USB or Bluetooth) and the VPNService API (used by this program) do not work together. For more details see the <a href=\"https://github.com/schwabe/ics-openvpn/issues/34\">issue #34</a> VPN and Tethering Connection retries Reconnection settings Number of seconds to wait between connection attempts. Seconds between connections - VPN.ht crashed unexpectedly. Please consider using the send Minidump option in the main menu + OpenVPN crashed unexpectedly. Please consider using the send Minidump option in the main menu Send Minidump to developer Sends debugging information about last crash to developer - VPN.ht - %s + OpenVPN - %s %1$s - %2$s %1$s - %3$s, %2$s Connecting @@ -248,7 +249,8 @@ Connecting (TCP) Authentication failed Waiting for usable network - ↓%2$s/s %1$s - ↑%4$s/s %3$s + Waiting for Orbot to start + ↓%2$s %1$s - ↑%4$s %3$s Not connected Connecting to VPN %s Connecting to VPN %s @@ -256,7 +258,6 @@ Encryption cipher Packet authentication Enter packet authentication method - Running on %1$s (%2$s) %3$s, Android API %4$d, version %5$s, %6$s built by %s debug build official build @@ -269,18 +270,18 @@ RDN (common name) RDN prefix tls-remote (DEPRECATED) - You can help translating by visiting http://crowdin.net/project/ics-openvpn/invite + You can help translating by visiting https://crowdin.net/project/ics-openvpn/invite %1$s attempts to control %2$s By proceeding, you are giving the application permission to completely control OpenVPN for Android and to intercept all network traffic.Do NOT accept unless you trust the application. Otherwise, you run the risk of having your data compromised by malicious software." I trust this application. No app allowed to use external API Allowed apps: %s Clear list of allowed external apps?\nCurrent list of allowed apps:\n\n%s - "Pause VPN when screen is off and less than 64 kB transferred data in 60s. When the \"Persistent Tun\" option is enabled pausing the VPN will leave your device with NO network connectivity. Without the \"Persistent Tun\" option the device will have no VPN connection/protection. + Pause VPN when screen is off and less than 64 kB transferred data in 60s. When the \"Persistent Tun\" option is enabled pausing the VPN will leave your device with NO network connectivity. Without the \"Persistent Tun\" option the device will have no VPN connection/protection. Pause VPN connection after screen off Pausing connection in screen off state: less than %1$s in %2$ss Warning: Persistent tun not enabled for this VPN. Traffic will use the normal Internet connection when the screen is off. - Save credentials + Save Password Pause VPN Resume VPN VPN pause requested by user @@ -292,7 +293,7 @@ Allow changes to VPN Profiles Hardware Keystore: Icon of app trying to use OpenVPN for Android - "Starting with Android 4.3 the VPN confirmation is guarded against \"overlaying apps\". This results in the dialog not reacting to touch input. If you have an app that uses overlays it may cause this behaviour. If you find an offending app contact the author of the app. This problem affect all VPN applications on Android 4.3 and later. See also <a href=\"http://code.google.com/p/ics-openvpn/issues/detail?id=185\">Issue 185<a> for additional details" + "Starting with Android 4.3 the VPN confirmation is guarded against \"overlaying apps\". This results in the dialog not reacting to touch input. If you have an app that uses overlays it may cause this behaviour. If you find an offending app contact the author of the app. This problem affect all VPN applications on Android 4.3 and later. See also <a href=\"https://github.com/schwabe/ics-openvpn/issues/185\">Issue 185<a> for additional details" Vpn Confirmation Dialog Alternatively you can send me a donation with the Play Store: Thanks for donating %s! @@ -309,17 +310,18 @@ View options Unhandled exception: %1$s\n\n%2$s %3$s: %1$s\n\n%2$s - If you have rooted your Android device you can install the <a href=\"http://xposed.info/\">Xposed framework</a> and a the <a href=\"http://repo.xposed.info/module/de.blinkt.vpndialogxposed\">VPN Dialog confirm module</a> at your own risk" + If you have rooted your Android device you can install the <a href=\"http://xposed.info/\">Xposed framework</a> and the <a href=\"http://repo.xposed.info/module/de.blinkt.vpndialogxposed\">VPN Dialog confirm module</a> at your own risk" Full licenses - Networks directly connected to the local interfaces will not be routed over the VPN. Deselecting this option will redirect all traffic indented for local networks to the VPN. + Networks directly connected to the local interfaces will not be routed over the VPN. Deselecting this option will redirect all traffic intented for local networks to the VPN. Bypass VPN for local networks Username/Password file [Imported from: %s] Some files could not be found. Please select the files to import the profile: - To use this app you need a VPN provider/VPN gateway supporting OpenVPN (often provided by your employer). Check out http://community.openvpn.net/ for more information on OpenVPN and how to setup your own OpenVPN server. + To use this app you need a VPN provider/VPN gateway supporting OpenVPN (often provided by your employer). Check out https://community.openvpn.net/ for more information on OpenVPN and how to setup your own OpenVPN server. Import log: Vpn topology \"%3$s\" specified but ifconfig %1$s %2$s looks more like an IP address with a network mask. Assuming \"subnet\" topology. The MSS override value has to be a integer between 0 and 9000 + The MTU override value has to be a integer between 64 and 9000 Announce to TCP sessions running over the tunnel that they should limit their send packet sizes such that after OpenVPN has encapsulated them, the resulting UDP packet size that OpenVPN sends to its peer will not exceed this number of bytes. (default is 1450) Override MSS value of TCP payload Set MSS of TCP payload @@ -331,6 +333,7 @@ Package %s is no longer installed, removing it from app allow/disallow list VPN is used for all apps but exclude selected VPN is used for only for selected apps + Allow apps to bypass the VPN Remove remote server entry? Keep Delete @@ -346,13 +349,13 @@ Duplicate VPN profile Duplicating profile: %s Show log - Multiple OpenVPN clients for Android exist. The most common ones are OpenVPN for Android (this client), OpenVPN Connect and OpenVPN Settings.<p>The clients can be grouped into two groups: OpenVPN for Android and OpenVPN Connect use the official VPNService API (Android 4.0+) and require no root and OpenVPN Settings which uses root.<p>OpenVPN for Android is an open source client and developed by Arne Schwabe. It is targeted at more advanced users and offers many settings and the ability to import profiles from files and to configure/change profiles inside the app. The client is based on the community version of OpenVPN. It is based on the OpenVPN 2.x source code. This client can be seen as the semi officially client of the community. <p>OpenVPN Connect is non open source client that is developed by OpenVPN Technologies, Inc. The client is indented to be general use client and moree targeted at the average user and allows the import of OpenVPN profiles. This client is based on the OpenVPN C++ reimplementation of the OpenVPN protocol (This was required to allow OpenVPN Technologies, Inc to publish an iOS OpenVPN app). This client is the official client of the OpenVPN technologies <p> OpenVPN Settings is the oldest of the clients and also a UI for the open source OpenVPN. In contrast to OpenVPN for Android it requires root and does not use the VPNService API. It does not depend on Android 4.0+ + Multiple OpenVPN clients for Android exist. The most common ones are OpenVPN for Android (this client), OpenVPN Connect and OpenVPN Settings.<p>The clients can be grouped into two groups: OpenVPN for Android and OpenVPN Connect use the official VPNService API (Android 4.0+) and require no root and OpenVPN Settings which uses root.<p>OpenVPN for Android is an open source client and developed by Arne Schwabe. It is targeted at more advanced users and offers many settings and the ability to import profiles from files and to configure/change profiles inside the app. The client is based on the community version of OpenVPN. It is based on the OpenVPN 2.x source code. This client can be seen as the semi officially client of the community. <p>OpenVPN Connect is non open source client that is developed by OpenVPN Technologies, Inc. The client is indented to be general use client and more targeted at the average user and allows the import of OpenVPN profiles. This client is based on the OpenVPN C++ reimplementation of the OpenVPN protocol (This was required to allow OpenVPN Technologies, Inc to publish an iOS OpenVPN app). This client is the official client of the OpenVPN technologies <p> OpenVPN Settings is the oldest of the clients and also a UI for the open source OpenVPN. In contrast to OpenVPN for Android it requires root and does not use the VPNService API. It does not depend on Android 4.0+ Differences between the OpenVPN Android clients Ignoring multicast route: %s Android supports only CIDR routes to the VPN. Since non-CIDR routes are almost never used, OpenVPN for Android will use a /32 for routes that are not CIDR and issue a warning. Tethering works while the VPN is active. The tethered connection will NOT use the VPN. Early KitKat version set the wrong MSS value on TCP connections (#61948). Try to enable the mssfix option to workaround this bug. - Android will keep using your proxy settings specified for the mobile/Wi-Fi connection when no DNS servers are set. OpenVPN for Android will warn you about this in the log.

When a VPN sets a DNS server Android will not a proxy. There is no API to set a proxy for a VPN connection.

+ Android will keep using your proxy settings specified for the mobile/Wi-Fi connection when no DNS servers are set. OpenVPN for Android will warn you about this in the log.

When a VPN sets a DNS server Android will not use a proxy. There is no API to set a proxy for a VPN connection.

VPN apps may stop working when uninstalled and reinstalled again. For details see #80074 The configured client IP and the IPs in its network mask are not routed to the VPN. OpenVPN works around this bug by explicitly adding a route that corrosponds to the client IP and its netmask Opening a tun device while another tun device is active, which is used for persist-tun support, crashes the VPNServices on the device. A reboot is required to make VPN work again. OpenVPN for Android tries to avoid reopening the tun device and if really needed first closes the current TUN before opening the new TUN device to avoid to crash. This may lead to a short window where packets are sent over the non-VPN connection. Even with this workaround the VPNServices sometimes crashes and requires a reboot of the device. @@ -375,9 +378,121 @@ Persist tun mode %s and later Connections fails with SSL23_GET_SERVER_HELLO:sslv3 alert handshake failure - Newer OpenVPN for Android versions (0.6.29/March 2015) use a more secure default for the allowed cipher suites (tls-cipher \"DEFAULT:!EXP:!PSK:!SRP:!kRSA\"). Unfortunately, omitting the less secure cipher suites and export cipher suites, especially the omission of cipher suites that do not support Perfect Forward Secrecy (Diffie-Hellman) causes some problems. This usually caused by an well-intentioned but poorly executed attempts to strengthen TLS security by setting tls-cipher on the server.\nTo solve this problem the problem, set the tls-cipher settings on the server to reasonable default like tls-cipher \"DEFAULT:!EXP:!PSK:!SRP:!kRSA\". To work around the problem on the client add the custom option tls-cipher DEFAULT on the Android client. + Newer OpenVPN for Android versions (0.6.29/March 2015) use a more secure default for the allowed cipher suites (tls-cipher \"DEFAULT:!EXP:!PSK:!SRP:!kRSA\"). Unfortunately, omitting the less secure cipher suites and export cipher suites, especially the omission of cipher suites that do not support Perfect Forward Secrecy (Diffie-Hellman) causes some problems. This usually caused by an well-intentioned but poorly executed attempt to strengthen TLS security by setting tls-cipher on the server or some embedded OSes with stripped down SSL (e.g. MikroTik).\nTo solve this problem the problem, set the tls-cipher settings on the server to reasonable default like tls-cipher \"DEFAULT:!EXP:!PSK:!SRP:!kRSA\". To work around the problem on the client add the custom option tls-cipher DEFAULT on the Android client. This profile has been added from an external app (%s) and has been marked as not user editable. Certificate Revocation List - Service restarted + Restarting OpenVPN Service (App crashed probably crashed or killed for memory pressure) + Importing the config yielded an error, cannot save it + Search + (Last dump is %1$d:%2$dh old (%3$s)) + Clear log on new connection + Connect Timeout + No allowed app added. Adding ourselves (%s) to have at least one app in the allowed app list to not allow all apps + OpenVPN for Android can try to discover the missing file(s) on the sdcard automatically. Tap this message start the permission request. + Protocol + Enabled + Preferred native ABI precedence of this device (%1$s) and ABI reported by native libraries (%2$s) mismatch + VPN permission revoked by OS (e.g. other VPN program started), stopping VPN + Push Peer info + Send extra information to the server, e.g. SSL version and Android version + Need %1$s + Please enter the password for profile %1$s + Use inline data + Export configuration file + tls-auth file is missing + Missing user certificate or user certifcate key file + Missing CA certificate + Certifcate Revoke List (optional) + Reread (%d) log items from log cache file + Even though Samsung phones are among the most selling Android phones, Samsung\'s firmware are also among the most buggy Android firmwares. The bugs are not limited to the VPN operation on these devices but many of them can be workarounded. In the following some of these bugs are described.\n\nDNS does not work unless the DNS server in the VPN range.\n\nOn many Samsung 5.x devices the allowed/disallowed apps feature does not work.\nOn Samsung 6.x VPN is reported not to work unless the VPN app is exempted from Powersave features. + Samsung phones + No VPN selected. + Default VPN + VPN used in places where a default VPN needed. These are currently on boot, for Always-On and the Quick Settings Tile. + Currently selected VPN: \'%s\' + Reconnect + Toggle VPN + Connect to %s + Disconnect %s + Enter the maximum time between connection attempts. OpenVPN will slowly raise its waiting time after an unsuccessful connection attempt up to this value. Defaults to 300s. + Maximum time between connection attempts + Waiting %ss seconds between connection attempt + Networks more .. -> VPNS]]> + Connection to OpenVPN closed (%s) + Change sorting + Sort + Profiles sorted by last recently used + Profiles sorted by name + Config uses option tls-remote that was deprecated in 2.3 and finally removed in 2.4 + Behaviour on AUTH_FAILED + Graph + Use logarithmic scale + Not enough data + Average per hour + Average per minute + Last 5 minutes + In + Out + %.0f bit/s + %.1f kbit/s + %.1f Mbit/s + %.1f Gbit/s + <p>Starting with OpenSSL version 1.1, OpenSSL rejects weak signatures in certificates like + MD5.</p><p><b>MD5 signatures are completely insecure and should not be used anymore.</b> MD5 + collisions can be created in <a + href="https://natmchugh.blogspot.de/2015/02/create-your-own-md5-collisions.html">few hours at a minimal cost.</a>. + You should update the VPN certificates as soon as possible.</p><p>Unfortunately, older easy-rsa + distributions included the config option "default_md md5". If you are using an old easy-rsa version, update to + the <a href="https://github.com/OpenVPN/easy-rsa/releases">latest version</a>) or change md5 to sha256 and + regenerate your certificates.</p><p>If you really want to use old and broken certificates use the custom + configuration option tls-cipher "DEFAULT:@SECLEVEL=0" under advanced configuration or as additional line in your + imported configuration</p> + + %.0f B + %.1f kB + %.1f MB + %.1f GB + Connection statistics + Ongoing statistics of the established OpenVPN connection + Connection status change + Status changes of the OpenVPN connection (Connecting, authenticating,…) + Weak (MD5) hashes in certificate signature (SSL_CTX_use_certificate md too weak) + OpenSSL Speed Test + OpenSSL cipher names + OpenSSL Crypto Speed test + OpenSSL returned an error + Running test… + Test selected algorithms + An external app tries to control %s. The app requesting access cannot be determined. Allowing this app grants ALL apps access. + The OpenVPN 3 C++ implementation does not support static keys. Please change to OpenVPN 2.x under general settings. + Using PKCS12 files directly with OpenVPN 3 C++ implementation is not supported. Please import the pkcs12 files into the Android keystore or change to OpenVPN 2.x under general settings. + Proxy + None + Tor (Orbot) + OpenVPN 3 C++ implementation does not support connecting via Socks proxy + Orbot application cannot be found. Please install Orbot or use manual Socks v5 integration. + Remote API + OpenVPN for Android supports two remote APIs, a sophisticated API using AIDL (remoteEXample in the git repository) and a simple one using Intents. <p>Examples using adb shell and the intents. Replace profilname with your profile name<p><p> adb shell am start-activity -a android.intent.action.MAIN de.blinkt.openvpn/.api.DisconnectVPN<p> adb shell am start-activity -a android.intent.action.MAIN -e de.blinkt.openvpn.api.profileName Blinkt de.blinkt.openvpn/.api.ConnectVPN + Enable Proxy Authentication + Cannot use extra http-proxy-option statement and Orbot integration at the same time + Info from server: \'%s\' + User interaction required + OpenVPN connection requires a user input, e.g. two factor + authentification + + Open URL to continue VPN authentication + Answer challenge to continue VPN authentication + Authentication pending + External Authenticator + Configure + External Authneticator not configured + Block non VPN connection (\"Killswitch\") + It is often desired to block connections without VPN. Other apps often use markting terms like \"Killswitch\" or \"Seamless tunnel\" for this feature. OpenVPN and this app offer persist-tun, a feature to implement this functionality.<p>The problem with all these methods offered by apps is that they can only provide best effort and are no complete solutions. On boot, app crashing and other corner cases the app cannot ensure that this block of non VPN connection works. Thus giving the user a false sense of security.<p>The <b>only</b> reliable way to ensure non VPN connections are blocked is to use Android 8.0 or later and use the \"block connections without VPN\" setting that can be found under Settings > Network & Internet > Advanced/VPN > OpenVPN for Android > Enable Always ON VPN, Enable Block Connections without VPN + This option instructs Android to not allow protocols (IPv4/IPv6) if the VPN does not set any IPv4 or IPv6 addresses. + Block IPv6 (or IPv4) if not used by the VPN + Install new certificate + AS servername + Request autologin profile + Import Profile from Access Server
diff --git a/app/src/main/res/values/vpn_untranslatable.xml b/app/src/main/res/values/vpn_untranslatable.xml index 629514a..2823dd0 100644 --- a/app/src/main/res/values/vpn_untranslatable.xml +++ b/app/src/main/res/values/vpn_untranslatable.xml @@ -1,23 +1,31 @@ - - - Copyright 2012–2014 Arne Schwabe <arne@rfc2549.org> + Copyright 2012–2018 Arne Schwabe <arne@rfc2549.org> + + App Logo design by Helen Beierling + <helbeierling@t-online.de> + + Copyright © 2002–2010 OpenVPN Technologies, Inc. <sales@openvpn.net>\n - "OpenVPN" is a trademark of OpenVPN Technologies, Inc.\n + "OpenVPN" is a trademark of OpenVPN Technologies, Inc.\n + openvpn.uni-paderborn.de 1194 File Dialog based on work by Alexander Ponomarev - Copyright © 1996 – 2011 Markus Franz Xaver Johannes Oberhumer - This product includes software developed by the OpenSSL Project for use in the OpenSSL Toolkit\n + Copyright © 1996 – 2011 Markus Franz Xaver Johannes Oberhumer + + This product includes software developed by the OpenSSL + Project for use in the OpenSSL Toolkit\n Copyright © 1998-2008 The OpenSSL Project. All rights reserved.\n\n This product includes cryptographic software written by Eric Young (eay@cryptsoft.com)\n - Copyright © 1995-1998 Eric Young (eay@cryptsoft.com) All rights reserved. + Copyright © 1995-1998 Eric Young (eay@cryptsoft.com) All rights reserved. + OpenVPN File Dialog LZO @@ -25,12 +33,16 @@ Unknown state Allows another app to control OpenVPN Bouncy Castle Crypto APIs - Copyright © 2000–2012 The Legion Of The Bouncy Castle (http://www.bouncycastle.org) + Copyright © 2000–2012 The Legion Of The Bouncy Castle + (http://www.bouncycastle.org) + 0 1 + tls-crypt + tls-crypt-v2 1 @@ -40,11 +52,25 @@ -1 OpenVPN for Android crashed, crash reported - + Waiting for user permission to use VPN API Waiting for user VPN password VPN password input dialog cancelled VPN API permission dialog cancelled + aes-256-gcm bf-cbc sha1 + + + Unique UUID that identifies the profile (example: + 0E910C15–9A85-4DD9-AE0D-E6862392E638). Generate using uuidgen or similar tools + + UUID + Content of the OpenVPN configuration file. These files are usually have the extension .ovpn (sometimes also .conf) and are plain text multi line configuration files. If your MDM does not support multiline configuration entries, you can also use a base64 encoded string here. A text file can be converted to base64 using openssl base64 -A -in + Config + Name of the VPN profile + Name + List of VPN configurations + VPN configuration + Version of the managed configuration schema From e48682932ff2469a07176362451140e8c621f7d2 Mon Sep 17 00:00:00 2001 From: SV Date: Sun, 5 Apr 2020 16:34:56 +0200 Subject: [PATCH 03/10] Target Android 29 --- app/build.gradle | 11 ++++------- 1 file changed, 4 insertions(+), 7 deletions(-) diff --git a/app/build.gradle b/app/build.gradle index a4710d7..a9e3296 100644 --- a/app/build.gradle +++ b/app/build.gradle @@ -7,16 +7,17 @@ plugins { apply plugin: 'com.android.application' android { - compileSdkVersion 28 - buildToolsVersion "28.0.3" + compileSdkVersion 29 + buildToolsVersion "29.0.0" defaultConfig { applicationId "ht.vpn.android.app" minSdkVersion 23 - targetSdkVersion 28 + targetSdkVersion 29 versionCode 15 versionName "1.3.0" resValue "string", "geokey", System.getenv("VPNHT_GEO_KEY").toString() + buildConfigField("boolean", "openvpn3", "true") } signingConfigs { @@ -40,10 +41,6 @@ android { } } -ext { - supportLibVersion = "28.0.0" -} - // ./gradlew(.bat) dependencyUpdates -Drevision=release dependencies { implementation fileTree(dir: 'libs', include: ['*.jar']) From 72cc6e32f9c8300aceb9bb846b26020b4fadae50 Mon Sep 17 00:00:00 2001 From: SV Date: Sun, 5 Apr 2020 16:41:46 +0200 Subject: [PATCH 04/10] Update butterknife --- app/build.gradle | 8 +++++-- .../vpn/android/activities/BaseActivity.java | 4 ++-- .../vpn/android/activities/LoginActivity.java | 6 ++--- .../activities/PreferencesActivity.java | 4 ++-- .../adapters/PreferencesListAdapter.java | 10 ++++----- .../ht/vpn/android/fragment/LogFragment.java | 4 ++-- .../ht/vpn/android/fragment/VPNFragment.java | 22 +++++++++---------- 7 files changed, 31 insertions(+), 27 deletions(-) diff --git a/app/build.gradle b/app/build.gradle index a9e3296..0f5677d 100644 --- a/app/build.gradle +++ b/app/build.gradle @@ -39,6 +39,10 @@ android { applicationIdSuffix ".dev" } } + compileOptions { + sourceCompatibility JavaVersion.VERSION_1_8 + targetCompatibility JavaVersion.VERSION_1_8 + } } // ./gradlew(.bat) dependencyUpdates -Drevision=release @@ -53,8 +57,8 @@ dependencies { implementation 'com.mobsandgeeks:android-saripaar:2.0.2' implementation 'com.squareup.retrofit:retrofit:1.9.0' implementation 'com.jakewharton.timber:timber:3.1.0' - annotationProcessor 'com.jakewharton:butterknife:7.0.1' - implementation 'com.jakewharton:butterknife:7.0.1' + implementation 'com.jakewharton:butterknife:10.2.1' + annotationProcessor 'com.jakewharton:butterknife-compiler:10.2.1' } gradle.taskGraph.whenReady { taskGraph -> diff --git a/app/src/main/java/ht/vpn/android/activities/BaseActivity.java b/app/src/main/java/ht/vpn/android/activities/BaseActivity.java index 7b02190..00435ef 100644 --- a/app/src/main/java/ht/vpn/android/activities/BaseActivity.java +++ b/app/src/main/java/ht/vpn/android/activities/BaseActivity.java @@ -7,13 +7,13 @@ import androidx.appcompat.widget.Toolbar; import butterknife.ButterKnife; -import butterknife.Bind; +import butterknife.BindView; import ht.vpn.android.R; public abstract class BaseActivity extends AppCompatActivity { @Nullable - @Bind(R.id.toolbar) + @BindView(R.id.toolbar) Toolbar mToolbar; protected void onCreate(Bundle savedInstanceState, int layoutRes) { diff --git a/app/src/main/java/ht/vpn/android/activities/LoginActivity.java b/app/src/main/java/ht/vpn/android/activities/LoginActivity.java index bf99462..3fa5f6c 100644 --- a/app/src/main/java/ht/vpn/android/activities/LoginActivity.java +++ b/app/src/main/java/ht/vpn/android/activities/LoginActivity.java @@ -16,7 +16,7 @@ import java.util.List; -import butterknife.Bind; +import butterknife.BindView; import butterknife.OnClick; import ht.vpn.android.Preferences; import ht.vpn.android.R; @@ -36,10 +36,10 @@ public class LoginActivity extends BaseActivity implements Validator.ValidationL private boolean mDoNotSave = false; @NotEmpty - @Bind(R.id.usernameEdit) + @BindView(R.id.usernameEdit) EditText mUsername; @NotEmpty - @Bind(R.id.passwordEdit) + @BindView(R.id.passwordEdit) EditText mPassword; @SuppressLint("MissingSuperCall") diff --git a/app/src/main/java/ht/vpn/android/activities/PreferencesActivity.java b/app/src/main/java/ht/vpn/android/activities/PreferencesActivity.java index b1f3dbb..3d3b3a8 100644 --- a/app/src/main/java/ht/vpn/android/activities/PreferencesActivity.java +++ b/app/src/main/java/ht/vpn/android/activities/PreferencesActivity.java @@ -15,7 +15,7 @@ import java.util.Arrays; import java.util.List; -import butterknife.Bind; +import butterknife.BindView; import ht.vpn.android.Preferences; import ht.vpn.android.R; import ht.vpn.android.content.PrefItem; @@ -28,7 +28,7 @@ public class PreferencesActivity extends BaseActivity { private List mPrefItems = new ArrayList<>(); private LinearLayoutManager mLayoutManager; - @Bind(R.id.recyclerView) + @BindView(R.id.recyclerView) RecyclerView mRecyclerView; @Override diff --git a/app/src/main/java/ht/vpn/android/content/adapters/PreferencesListAdapter.java b/app/src/main/java/ht/vpn/android/content/adapters/PreferencesListAdapter.java index 2efc5ae..4f2b091 100644 --- a/app/src/main/java/ht/vpn/android/content/adapters/PreferencesListAdapter.java +++ b/app/src/main/java/ht/vpn/android/content/adapters/PreferencesListAdapter.java @@ -12,8 +12,8 @@ import java.util.List; +import butterknife.BindView; import butterknife.ButterKnife; -import butterknife.Bind; import ht.vpn.android.R; import ht.vpn.android.VPNhtApplication; import ht.vpn.android.content.PrefItem; @@ -80,13 +80,13 @@ public int getItemViewType(int position) { public class ViewHolder extends RecyclerView.ViewHolder implements View.OnClickListener { View itemView; - @Bind(android.R.id.icon) + @BindView(android.R.id.icon) ImageView icon; - @Bind(android.R.id.text1) + @BindView(android.R.id.text1) TextView text1; - @Bind(android.R.id.text2) + @BindView(android.R.id.text2) TextView text2; - @Bind(android.R.id.checkbox) + @BindView(android.R.id.checkbox) CheckBox checkBox; public ViewHolder(View itemView) { diff --git a/app/src/main/java/ht/vpn/android/fragment/LogFragment.java b/app/src/main/java/ht/vpn/android/fragment/LogFragment.java index 4848910..3665469 100644 --- a/app/src/main/java/ht/vpn/android/fragment/LogFragment.java +++ b/app/src/main/java/ht/vpn/android/fragment/LogFragment.java @@ -13,7 +13,7 @@ import androidx.recyclerview.widget.LinearLayoutManager; import androidx.recyclerview.widget.RecyclerView; -import butterknife.Bind; +import butterknife.BindView; import ht.vpn.android.R; import ht.vpn.android.content.adapters.LogListAdapter; @@ -21,7 +21,7 @@ public class LogFragment extends BaseFragment { private LogListAdapter mAdapter; - @Bind(R.id.recyclerView) + @BindView(R.id.recyclerView) RecyclerView mRecyclerView; public LogFragment() { diff --git a/app/src/main/java/ht/vpn/android/fragment/VPNFragment.java b/app/src/main/java/ht/vpn/android/fragment/VPNFragment.java index 519d839..82a9757 100644 --- a/app/src/main/java/ht/vpn/android/fragment/VPNFragment.java +++ b/app/src/main/java/ht/vpn/android/fragment/VPNFragment.java @@ -40,7 +40,7 @@ import java.util.List; import java.util.Locale; -import butterknife.Bind; +import butterknife.BindView; import butterknife.OnClick; import de.blinkt.openvpn.VpnProfile; import de.blinkt.openvpn.core.ConfigParser; @@ -91,23 +91,23 @@ public class VPNFragment extends BaseFragment implements VpnStatus.LogListener, private ConnectionStatus mCurrentVPNState = ConnectionStatus.LEVEL_NOTCONNECTED; private Marker mCurrentPosMarker; - @Bind(R.id.scrollView) + @BindView(R.id.scrollView) TouchableScrollView mScrollView; - @Bind(R.id.connectedCard) + @BindView(R.id.connectedCard) CardView mConnectedCard; - @Bind(R.id.connectCard) + @BindView(R.id.connectCard) CardView mConnectCard; - @Bind(R.id.connectButton) + @BindView(R.id.connectButton) Button mConnectButton; - @Bind(R.id.disconnectButton) + @BindView(R.id.disconnectButton) Button mDisconnectButton; - @Bind(R.id.locationSpinner) + @BindView(R.id.locationSpinner) Spinner mLocationSpinner; - @Bind(R.id.firewallSwitch) + @BindView(R.id.firewallSwitch) CheckBox mFirewallSwitch; - @Bind(R.id.ipText) + @BindView(R.id.ipText) TextView mIPText; - @Bind(R.id.locationText) + @BindView(R.id.locationText) TextView mLocationText; @Nullable @@ -331,6 +331,7 @@ public void run() { @Override public void failure(RetrofitError error) { + Timber.e(error.getMessage()); if (error.getResponse() != null && error.getResponse().getStatus() == 401) { mActivity.startLoginActivity(); } else if (error.getCause() instanceof SocketTimeoutException){ @@ -380,7 +381,6 @@ public void run() { @Override public void failure(RetrofitError error) { - Timber.e(error, error.getMessage()); Toast.makeText(mActivity, R.string.unknown_error, Toast.LENGTH_SHORT).show(); if(error.getResponse() != null && error.getResponse().getStatus() == 401) From a91daa15611829a453ef5fafe9aa0c5b0b2d8400 Mon Sep 17 00:00:00 2001 From: SV Date: Sun, 5 Apr 2020 16:41:55 +0200 Subject: [PATCH 05/10] Set IP API to https --- app/src/main/java/ht/vpn/android/network/IPService.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/src/main/java/ht/vpn/android/network/IPService.java b/app/src/main/java/ht/vpn/android/network/IPService.java index d1333c0..668b5d9 100644 --- a/app/src/main/java/ht/vpn/android/network/IPService.java +++ b/app/src/main/java/ht/vpn/android/network/IPService.java @@ -5,7 +5,7 @@ import retrofit.http.GET; public class IPService { - private static final String API_URL = "http://myip.ht/"; + private static final String API_URL = "https://myip.ht/"; private Client mClient; private IPService() { From a10b92f9216c381f1929116e67b1123f0e20e822 Mon Sep 17 00:00:00 2001 From: SV Date: Sun, 5 Apr 2020 17:02:26 +0200 Subject: [PATCH 06/10] Use different config param --- app/src/main/java/ht/vpn/android/content/VPNHTConfig.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/src/main/java/ht/vpn/android/content/VPNHTConfig.java b/app/src/main/java/ht/vpn/android/content/VPNHTConfig.java index a3e4094..6afeeeb 100644 --- a/app/src/main/java/ht/vpn/android/content/VPNHTConfig.java +++ b/app/src/main/java/ht/vpn/android/content/VPNHTConfig.java @@ -37,7 +37,7 @@ public static String generate(SharedPreferences preferences, Server server, Bool stringList.add("ping 15"); stringList.add("ping-restart 45"); stringList.add("ping-timer-rem"); - stringList.add("ns-cert-type server"); + stringList.add("remote-cert-tls server"); stringList.add("mute 10"); stringList.add("comp-lzo"); stringList.add("verb 3"); From ca2d2095db617e3c5a7ffed0dfcc30665e9d1a1d Mon Sep 17 00:00:00 2001 From: SV Date: Sun, 5 Apr 2020 17:42:27 +0200 Subject: [PATCH 07/10] Add check fallback and remove BF-CBC --- .../android/activities/PreferencesActivity.java | 2 +- .../java/ht/vpn/android/content/VPNHTConfig.java | 4 ++++ .../java/ht/vpn/android/fragment/VPNFragment.java | 14 ++++++++++++-- .../java/ht/vpn/android/network/IPService.java | 11 ++++++++--- 4 files changed, 25 insertions(+), 6 deletions(-) diff --git a/app/src/main/java/ht/vpn/android/activities/PreferencesActivity.java b/app/src/main/java/ht/vpn/android/activities/PreferencesActivity.java index 3d3b3a8..467ce9a 100644 --- a/app/src/main/java/ht/vpn/android/activities/PreferencesActivity.java +++ b/app/src/main/java/ht/vpn/android/activities/PreferencesActivity.java @@ -93,7 +93,7 @@ public String get(PrefItem item) { mPrefItems.add(getString(R.string.connection)); - final List options = Arrays.asList("BF-CBC", "AES-128-CBC", "AES-256-CBC"); + final List options = Arrays.asList("AES-128-CBC", "AES-256-CBC"); mPrefItems.add(new PrefItem(this, R.drawable.ic_prefs_encryption, R.string.cipher, Preferences.ENC_TYPE, "AES-128-CBC", new PrefItem.OnClickListener() { @Override diff --git a/app/src/main/java/ht/vpn/android/content/VPNHTConfig.java b/app/src/main/java/ht/vpn/android/content/VPNHTConfig.java index 6afeeeb..c0c6abb 100644 --- a/app/src/main/java/ht/vpn/android/content/VPNHTConfig.java +++ b/app/src/main/java/ht/vpn/android/content/VPNHTConfig.java @@ -4,12 +4,16 @@ import java.util.ArrayList; +import de.blinkt.openvpn.core.VpnStatus; import ht.vpn.android.Preferences; import ht.vpn.android.network.responses.Server; public class VPNHTConfig { public static String generate(SharedPreferences preferences, Server server, Boolean firewall) { + VpnStatus.logInfo("Connecting to server: " + server.hostname + " " + server.countryCode); + VpnStatus.logInfo("Firewall option enabled: " + firewall); + ArrayList stringList = new ArrayList<>(); stringList.add("client"); diff --git a/app/src/main/java/ht/vpn/android/fragment/VPNFragment.java b/app/src/main/java/ht/vpn/android/fragment/VPNFragment.java index 82a9757..9824fc1 100644 --- a/app/src/main/java/ht/vpn/android/fragment/VPNFragment.java +++ b/app/src/main/java/ht/vpn/android/fragment/VPNFragment.java @@ -35,6 +35,7 @@ import java.io.IOException; import java.io.StringReader; import java.net.SocketTimeoutException; +import java.net.UnknownHostException; import java.util.ArrayList; import java.util.HashMap; import java.util.List; @@ -231,6 +232,7 @@ public void run() { mCurrentPosMarker.setVisible(false); } }); + IPService.get().status(mIPCallback); } @@ -269,7 +271,11 @@ public void onMapReady(GoogleMap googleMap) { private Callback mIPCallback = new Callback() { @Override public void success(final IPService.Data data, Response response) { - if(mActivity == null) return; + Timber.d("Updated IP data"); + if(mActivity == null) { + Timber.d("Returning because mActivity is null"); + return; + } if(response != null && response.getStatus() == 200) { mShowsConnected = data.connected; @@ -331,9 +337,13 @@ public void run() { @Override public void failure(RetrofitError error) { - Timber.e(error.getMessage()); + Timber.e("Error getting IP data %s %s", error.getMessage(), error.getCause()); if (error.getResponse() != null && error.getResponse().getStatus() == 401) { mActivity.startLoginActivity(); + } else if (error.getCause() instanceof UnknownHostException) { + if (!error.getMessage().contains("check")) { + IPService.getFallback().status(mIPCallback); + } } else if (error.getCause() instanceof SocketTimeoutException){ updateIPData(); } diff --git a/app/src/main/java/ht/vpn/android/network/IPService.java b/app/src/main/java/ht/vpn/android/network/IPService.java index 668b5d9..72dd234 100644 --- a/app/src/main/java/ht/vpn/android/network/IPService.java +++ b/app/src/main/java/ht/vpn/android/network/IPService.java @@ -6,15 +6,20 @@ public class IPService { private static final String API_URL = "https://myip.ht/"; + private static final String API_FALLBACK_URL = "https://check.myip.ht:8080/"; private Client mClient; - private IPService() { - RestAdapter restAdapter = new RestAdapter.Builder().setEndpoint(API_URL).setRequestInterceptor(new UserAgentInterceptor()).build(); + private IPService(String url) { + RestAdapter restAdapter = new RestAdapter.Builder().setEndpoint(url).setRequestInterceptor(new UserAgentInterceptor()).build(); mClient = restAdapter.create(Client.class); } public static IPService.Client get() { - return new IPService().mClient; + return new IPService(API_URL).mClient; + } + + public static IPService.Client getFallback() { + return new IPService(API_FALLBACK_URL).mClient; } public interface Client { From 9c0de6bd805320280aa6e51a82e85913c3f9ef97 Mon Sep 17 00:00:00 2001 From: SV Date: Sun, 5 Apr 2020 17:45:17 +0200 Subject: [PATCH 08/10] Remove SmartDNS option --- .../main/java/ht/vpn/android/Preferences.java | 2 -- .../android/activities/PreferencesActivity.java | 16 ---------------- .../java/ht/vpn/android/content/VPNHTConfig.java | 11 ----------- .../java/ht/vpn/android/network/VPNService.java | 3 --- .../network/responses/SmartDNSResponse.java | 7 ------- 5 files changed, 39 deletions(-) delete mode 100644 app/src/main/java/ht/vpn/android/network/responses/SmartDNSResponse.java diff --git a/app/src/main/java/ht/vpn/android/Preferences.java b/app/src/main/java/ht/vpn/android/Preferences.java index 2004bd3..4776adb 100644 --- a/app/src/main/java/ht/vpn/android/Preferences.java +++ b/app/src/main/java/ht/vpn/android/Preferences.java @@ -5,9 +5,7 @@ public class Preferences { public final static String PASSWORD = "password"; public final static String ENC_TYPE = "encryption"; public final static String KILLSWITCH = "killswitch"; - public final static String RECONNECT_NETCHANGE = "netchangereconnect"; public final static String RECONNECT_REBOOT = "rebootreconnect"; - public final static String SMARTDNS = "smartdns"; public final static String LOG_VERBOSITY = "log_verbosity"; public final static String LAST_CONNECTED_HOSTNAME = "hostname_last"; public final static String LAST_CONNECTED_COUNTRY = "country_latest"; diff --git a/app/src/main/java/ht/vpn/android/activities/PreferencesActivity.java b/app/src/main/java/ht/vpn/android/activities/PreferencesActivity.java index 467ce9a..b620770 100644 --- a/app/src/main/java/ht/vpn/android/activities/PreferencesActivity.java +++ b/app/src/main/java/ht/vpn/android/activities/PreferencesActivity.java @@ -114,22 +114,6 @@ public String get(PrefItem item) { ) ); - mPrefItems.add(new PrefItem(this, R.drawable.ic_prefs_smartdns, R.string.smartdns, Preferences.SMARTDNS, true, - new PrefItem.OnClickListener() { - @Override - public void onClick(PrefItem item) { - item.saveValue(!(Boolean) item.getValue()); - } - }, - new PrefItem.SubTitleGenerator() { - @Override - public String get(PrefItem item) { - return getString(R.string.smartdns_summary); - } - } - ) - ); - mPrefItems.add(getResources().getString(R.string.account)); mPrefItems.add(new PrefItem(this, R.drawable.ic_prefs_logout, R.string.logout, Preferences.USERNAME, 0, new PrefItem.OnClickListener() { diff --git a/app/src/main/java/ht/vpn/android/content/VPNHTConfig.java b/app/src/main/java/ht/vpn/android/content/VPNHTConfig.java index c0c6abb..912f8ea 100644 --- a/app/src/main/java/ht/vpn/android/content/VPNHTConfig.java +++ b/app/src/main/java/ht/vpn/android/content/VPNHTConfig.java @@ -49,12 +49,6 @@ public static String generate(SharedPreferences preferences, Server server, Bool stringList.add("fast-io"); stringList.add("auth-nocache"); - if(!preferences.getBoolean(Preferences.SMARTDNS, true)) { - stringList.add("route-nopull"); - stringList.add("redirect-gateway def1"); - stringList.add("dhcp-option DNS 10.11.0.1"); - } - if(firewall) { stringList.add(String.format("cipher %s", "AES-128-CBC")); } else { @@ -152,11 +146,6 @@ private static String[] getPortsByProtocol(String protocol) { stringList.add(Integer.toString(i)); } break; - case "BF-CBC": - for(int i = 1202; i < 1206; i++) { - stringList.add(Integer.toString(i)); - } - break; } return stringList.toArray(new String[stringList.size()]); } diff --git a/app/src/main/java/ht/vpn/android/network/VPNService.java b/app/src/main/java/ht/vpn/android/network/VPNService.java index e22f5b5..7099fe9 100644 --- a/app/src/main/java/ht/vpn/android/network/VPNService.java +++ b/app/src/main/java/ht/vpn/android/network/VPNService.java @@ -3,7 +3,6 @@ import android.util.Base64; import ht.vpn.android.network.responses.ServersResponse; -import ht.vpn.android.network.responses.SmartDNSResponse; import retrofit.Callback; import retrofit.RequestInterceptor; import retrofit.RestAdapter; @@ -43,7 +42,5 @@ public static VPNService.Client get(String username, String password) { public interface Client { @GET("/servers") void servers(Callback callback); - @GET("/smartdns") - void smartdns(Callback callback); } } diff --git a/app/src/main/java/ht/vpn/android/network/responses/SmartDNSResponse.java b/app/src/main/java/ht/vpn/android/network/responses/SmartDNSResponse.java deleted file mode 100644 index 8479801..0000000 --- a/app/src/main/java/ht/vpn/android/network/responses/SmartDNSResponse.java +++ /dev/null @@ -1,7 +0,0 @@ -package ht.vpn.android.network.responses; - -public class SmartDNSResponse extends BaseResponse { - - public String[] dns; - -} From 219ebad93780e866c2e854a9764a53eadf996280 Mon Sep 17 00:00:00 2001 From: SV Date: Sun, 5 Apr 2020 18:10:43 +0200 Subject: [PATCH 09/10] Change API url --- app/src/main/java/ht/vpn/android/OnBootReceiver.java | 2 +- app/src/main/java/ht/vpn/android/fragment/VPNFragment.java | 6 +++++- app/src/main/java/ht/vpn/android/network/VPNService.java | 2 +- 3 files changed, 7 insertions(+), 3 deletions(-) diff --git a/app/src/main/java/ht/vpn/android/OnBootReceiver.java b/app/src/main/java/ht/vpn/android/OnBootReceiver.java index 747be86..c96dcf4 100755 --- a/app/src/main/java/ht/vpn/android/OnBootReceiver.java +++ b/app/src/main/java/ht/vpn/android/OnBootReceiver.java @@ -42,7 +42,7 @@ void launchVPN(Context context) { ConfigParser configParser = new ConfigParser(); try { Server server = new Server(); - server.hostname = PrefUtils.get(context, Preferences.LAST_CONNECTED_HOSTNAME, "hub.vpn.ht"); + server.hostname = PrefUtils.get(context, Preferences.LAST_CONNECTED_HOSTNAME, "hub.digital.ht"); server.country = PrefUtils.get(context, Preferences.LAST_CONNECTED_COUNTRY, "Nearest"); configParser.parseConfig(new StringReader(VPNHTConfig.generate(PrefUtils.getPrefs(context), server, PrefUtils.get(context, Preferences.LAST_CONNECTED_FIREWALL, false)))); VpnProfile profile = configParser.convertProfile(); diff --git a/app/src/main/java/ht/vpn/android/fragment/VPNFragment.java b/app/src/main/java/ht/vpn/android/fragment/VPNFragment.java index 9824fc1..b44623e 100644 --- a/app/src/main/java/ht/vpn/android/fragment/VPNFragment.java +++ b/app/src/main/java/ht/vpn/android/fragment/VPNFragment.java @@ -371,7 +371,11 @@ public void success(ServersResponse serversResponse, Response response) { } mMarkers.put(marker, spinnerList.size()); - spinnerList.add(server.country); + if (server.countryCode != null && server.location != null) { + spinnerList.add(String.format("%s, %s", server.location, server.country)); + } else { + spinnerList.add(server.country); + } } final ArrayAdapter arrayAdapter = new ArrayAdapter<>(mActivity, R.layout.simple_spinner_item, spinnerList); diff --git a/app/src/main/java/ht/vpn/android/network/VPNService.java b/app/src/main/java/ht/vpn/android/network/VPNService.java index 7099fe9..95f7537 100644 --- a/app/src/main/java/ht/vpn/android/network/VPNService.java +++ b/app/src/main/java/ht/vpn/android/network/VPNService.java @@ -9,7 +9,7 @@ import retrofit.http.GET; public class VPNService { - private static final String API_URL = "https://api.vpn.ht/"; + private static final String API_URL = "https://api.digital.ht/"; private Client mClient; private VPNService(String username, String password) { From 7fc34b8caf14ec8651c6484dce3f05262def62a6 Mon Sep 17 00:00:00 2001 From: SV Date: Sun, 5 Apr 2020 21:05:52 +0200 Subject: [PATCH 10/10] Fix external app API --- app/build.gradle | 6 +- app/src/main/AndroidManifest.xml | 26 +- .../ht/vpn/android/api/APIVpnProfile.aidl | 0 .../vpn/android/api/IOpenVPNAPIService.aidl | 132 +-- .../android/api/IOpenVPNStatusCallback.aidl | 26 +- .../blinkt/openvpn/core/OpenVPNService.java | 5 +- .../main/java/ht/vpn/android/LaunchVPN.java | 58 +- .../ht/vpn/android/api/APIVpnProfile.java | 120 +-- .../ht/vpn/android/api/ConfirmDialog.java | 179 ---- .../vpn/android/api/ExternalAppDatabase.java | 141 +-- .../android/api/ExternalOpenVPNService.java | 804 +++++++++--------- .../android/api/GrantPermissionsActivity.java | 31 - .../java/ht/vpn/android/api/RemoteAction.java | 105 --- .../android/api/SecurityRemoteException.java | 34 +- app/src/main/res/layout/activity_main.xml | 2 +- app/src/main/res/layout/fragment_vpn.xml | 7 +- app/src/main/res/layout/toolbar.xml | 2 +- app/src/main/res/layout/userpass.xml | 4 +- app/src/main/res/values/styles.xml | 10 - 19 files changed, 645 insertions(+), 1047 deletions(-) mode change 100644 => 100755 app/src/main/aidl/ht/vpn/android/api/APIVpnProfile.aidl mode change 100644 => 100755 app/src/main/aidl/ht/vpn/android/api/IOpenVPNAPIService.aidl mode change 100644 => 100755 app/src/main/aidl/ht/vpn/android/api/IOpenVPNStatusCallback.aidl mode change 100644 => 100755 app/src/main/java/ht/vpn/android/api/APIVpnProfile.java delete mode 100644 app/src/main/java/ht/vpn/android/api/ConfirmDialog.java mode change 100644 => 100755 app/src/main/java/ht/vpn/android/api/ExternalAppDatabase.java mode change 100644 => 100755 app/src/main/java/ht/vpn/android/api/ExternalOpenVPNService.java delete mode 100644 app/src/main/java/ht/vpn/android/api/GrantPermissionsActivity.java delete mode 100644 app/src/main/java/ht/vpn/android/api/RemoteAction.java mode change 100644 => 100755 app/src/main/java/ht/vpn/android/api/SecurityRemoteException.java diff --git a/app/build.gradle b/app/build.gradle index 0f5677d..0c66820 100644 --- a/app/build.gradle +++ b/app/build.gradle @@ -11,11 +11,11 @@ android { buildToolsVersion "29.0.0" defaultConfig { - applicationId "ht.vpn.android.app" + applicationId "ht.vpn.android" minSdkVersion 23 targetSdkVersion 29 - versionCode 15 - versionName "1.3.0" + versionCode 16 + versionName "1.4.0" resValue "string", "geokey", System.getenv("VPNHT_GEO_KEY").toString() buildConfigField("boolean", "openvpn3", "true") } diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml index 324d168..ee3c8ff 100644 --- a/app/src/main/AndroidManifest.xml +++ b/app/src/main/AndroidManifest.xml @@ -5,12 +5,14 @@ + - - - - - - - - - - - - - - - - - diff --git a/app/src/main/aidl/ht/vpn/android/api/APIVpnProfile.aidl b/app/src/main/aidl/ht/vpn/android/api/APIVpnProfile.aidl old mode 100644 new mode 100755 diff --git a/app/src/main/aidl/ht/vpn/android/api/IOpenVPNAPIService.aidl b/app/src/main/aidl/ht/vpn/android/api/IOpenVPNAPIService.aidl old mode 100644 new mode 100755 index 5cc8880..4ea0d57 --- a/app/src/main/aidl/ht/vpn/android/api/IOpenVPNAPIService.aidl +++ b/app/src/main/aidl/ht/vpn/android/api/IOpenVPNAPIService.aidl @@ -1,66 +1,68 @@ -// IOpenVPNAPIService.aidl -package ht.vpn.android.api; - -import ht.vpn.android.api.APIVpnProfile; -import ht.vpn.android.api.IOpenVPNStatusCallback; - -import android.content.Intent; -import android.os.ParcelFileDescriptor; - -interface IOpenVPNAPIService { - List getProfiles(); - - void startProfile (String profileUUID); - - /** Use a profile with all certificates etc. embedded, - * old version which does not return the UUID of the addded profile, see - * below for a version that return the UUID on add */ - boolean addVPNProfile (String name, String config); - - /** start a profile using a config as inline string. Make sure that all needed data is inlined, - * e.g., using ... or ... - * See the OpenVPN manual page for more on inlining files */ - void startVPN (in String inlineconfig); - - /** This permission framework is used to avoid confused deputy style attack to the VPN - * calling this will give null if the app is allowed to use the external API and an Intent - * that can be launched to request permissions otherwise */ - Intent prepare (in String packagename); - - /** Used to trigger to the Android VPN permission dialog (VPNService.prepare()) in advance, - * if this return null OpenVPN for ANdroid already has the permissions otherwise you can start the returned Intent - * to let OpenVPN for Android request the permission */ - Intent prepareVPNService (); - - /* Disconnect the VPN */ - void disconnect(); - - /* Pause the VPN (same as using the pause feature in the notifcation bar) */ - void pause(); - - /* Resume the VPN (same as using the pause feature in the notifcation bar) */ - void resume(); - - /** - * Registers to receive OpenVPN Status Updates - */ - void registerStatusCallback(in IOpenVPNStatusCallback cb); - - /** - * Remove a previously registered callback interface. - */ - void unregisterStatusCallback(in IOpenVPNStatusCallback cb); - - /** Remove a profile by UUID */ - void removeProfile (in String profileUUID); - - /** Request a socket to be protected as a VPN socket would be. Useful for creating - * a helper socket for an app controlling OpenVPN - * Before calling this function you should make sure OpenVPN for Android may actually - * this function by checking if prepareVPNService returns null; */ - boolean protectSocket(in ParcelFileDescriptor fd); - - - /** Use a profile with all certificates etc. embedded */ - APIVpnProfile addNewVPNProfile (String name, boolean userEditable, String config); +// IOpenVPNAPIService.aidl +package ht.vpn.android.api; + +import ht.vpn.android.api.APIVpnProfile; +import ht.vpn.android.api.IOpenVPNStatusCallback; + +import android.content.Intent; +import android.os.ParcelFileDescriptor; + +interface IOpenVPNAPIService { + List getProfiles(); + + void startProfile (String profileUUID); + + /** Use a profile with all certificates etc. embedded, + * old version which does not return the UUID of the addded profile, see + * below for a version that return the UUID on add */ + boolean addVPNProfile (String name, String config); + + /** start a profile using a config as inline string. Make sure that all needed data is inlined, + * e.g., using ... or ... + * See the OpenVPN manual page for more on inlining files */ + void startVPN (String name, String inlineconfig); + + /** This permission framework is used to avoid confused deputy style attack to the VPN + * calling this will give null if the app is allowed to use the external API and an Intent + * that can be launched to request permissions otherwise */ + Intent prepare (String packagename); + + /** Used to trigger to the Android VPN permission dialog (VPNService.prepare()) in advance, + * if this return null OpenVPN for ANdroid already has the permissions otherwise you can start the returned Intent + * to let OpenVPN for Android request the permission */ + Intent prepareVPNService (); + + /* Disconnect the VPN */ + void disconnect(); + + /* Pause the VPN (same as using the pause feature in the notifcation bar) */ + void pause(); + + /* Resume the VPN (same as using the pause feature in the notifcation bar) */ + void resume(); + + boolean isConnectedOrConnecting(); + + /** + * Registers to receive OpenVPN Status Updates + */ + void registerStatusCallback(IOpenVPNStatusCallback cb); + + /** + * Remove a previously registered callback interface. + */ + void unregisterStatusCallback(IOpenVPNStatusCallback cb); + + /** Remove a profile by UUID */ + void removeProfile (String profileUUID); + + /** Request a socket to be protected as a VPN socket would be. Useful for creating + * a helper socket for an app controlling OpenVPN + * Before calling this function you should make sure OpenVPN for Android may actually + * this function by checking if prepareVPNService returns null; */ + boolean protectSocket(in ParcelFileDescriptor fd); + + + /** Use a profile with all certificates etc. embedded */ + APIVpnProfile addNewVPNProfile (String name, boolean userEditable, String config); } \ No newline at end of file diff --git a/app/src/main/aidl/ht/vpn/android/api/IOpenVPNStatusCallback.aidl b/app/src/main/aidl/ht/vpn/android/api/IOpenVPNStatusCallback.aidl old mode 100644 new mode 100755 index 42847b3..0c832a6 --- a/app/src/main/aidl/ht/vpn/android/api/IOpenVPNStatusCallback.aidl +++ b/app/src/main/aidl/ht/vpn/android/api/IOpenVPNStatusCallback.aidl @@ -1,13 +1,13 @@ -package ht.vpn.android.api; - -/** - * Example of a callback interface used by IRemoteService to send - * synchronous notifications back to its clients. Note that this is a - * one-way interface so the server does not block waiting for the client. - */ -interface IOpenVPNStatusCallback { - /** - * Called when the service has a new status for you. - */ - oneway void newStatus(in String uuid, in String state, in String message, in String level); -} +package ht.vpn.android.api; + +/** + * Example of a callback interface used by IRemoteService to send + * synchronous notifications back to its clients. Note that this is a + * one-way interface so the server does not block waiting for the client. + */ +oneway interface IOpenVPNStatusCallback { + /** + * Called when the service has a new status for you. + */ + void newStatus(String uuid, String state, String message, String level); +} diff --git a/app/src/main/java/de/blinkt/openvpn/core/OpenVPNService.java b/app/src/main/java/de/blinkt/openvpn/core/OpenVPNService.java index b030e51..97ed932 100644 --- a/app/src/main/java/de/blinkt/openvpn/core/OpenVPNService.java +++ b/app/src/main/java/de/blinkt/openvpn/core/OpenVPNService.java @@ -57,6 +57,7 @@ import ht.vpn.android.api.ExternalAppDatabase; import de.blinkt.openvpn.core.VpnStatus.ByteCountListener; import de.blinkt.openvpn.core.VpnStatus.StateListener; +import de.blinkt.openvpn.core.IOpenVPNServiceInternal; import static de.blinkt.openvpn.core.ConnectionStatus.LEVEL_CONNECTED; import static de.blinkt.openvpn.core.ConnectionStatus.LEVEL_WAITING_FOR_USER_INPUT; @@ -124,7 +125,6 @@ public void addAllowedExternalApp(String packagename) throws RemoteException { @Override public boolean isAllowedExternalApp(String packagename) throws RemoteException { return OpenVPNService.this.isAllowedExternalApp(packagename); - } @Override @@ -195,8 +195,7 @@ public void addAllowedExternalApp(String packagename) throws RemoteException { @Override public boolean isAllowedExternalApp(String packagename) throws RemoteException { - ExternalAppDatabase extapps = new ExternalAppDatabase(OpenVPNService.this); - return extapps.checkRemoteActionPermission(this, packagename); + return false; } @Override diff --git a/app/src/main/java/ht/vpn/android/LaunchVPN.java b/app/src/main/java/ht/vpn/android/LaunchVPN.java index cce7b7c..f110f3b 100644 --- a/app/src/main/java/ht/vpn/android/LaunchVPN.java +++ b/app/src/main/java/ht/vpn/android/LaunchVPN.java @@ -25,11 +25,14 @@ import android.text.InputType; import android.text.TextUtils; import android.text.method.PasswordTransformationMethod; +import android.view.LayoutInflater; import android.view.View; import android.widget.CheckBox; import android.widget.CompoundButton; import android.widget.EditText; +import androidx.appcompat.view.ContextThemeWrapper; + import java.io.IOException; import de.blinkt.openvpn.VpnProfile; @@ -138,13 +141,8 @@ protected void startVpnFromIntent() { mhideLog = intent.getBooleanExtra(EXTRA_HIDELOG, false); VpnProfile profileToConnect = ProfileManager.get(this, shortcutUUID); - if (shortcutName != null && profileToConnect == null) { + if (shortcutName != null && profileToConnect == null) profileToConnect = ProfileManager.getInstance(this).getProfileByName(shortcutName); - if (!(new ExternalAppDatabase(this).checkRemoteActionPermission(this, getCallingPackage()))) { - finish(); - return; - } - } if (profileToConnect == null) { @@ -171,8 +169,8 @@ private void askForPW(final int type) { dialog.setTitle(getString(R.string.pw_request_dialog_title, getString(type))); dialog.setMessage(getString(R.string.pw_request_dialog_prompt, mSelectedProfile.mName)); - - @SuppressLint("InflateParams") final View userpwlayout = getLayoutInflater().inflate(R.layout.userpass, null, false); + LayoutInflater inflater = LayoutInflater.from(new ContextThemeWrapper(getApplicationContext(), R.style.Theme_VPNht)); + @SuppressLint("InflateParams") final View userpwlayout = inflater.inflate(R.layout.userpass, null, false); if (type == R.string.password) { ((EditText) userpwlayout.findViewById(R.id.username)).setText(mSelectedProfile.mUsername); @@ -193,37 +191,29 @@ public void onCheckedChanged(CompoundButton buttonView, boolean isChecked) { dialog.setView(entry); } - AlertDialog.Builder builder = dialog.setPositiveButton(android.R.string.ok, - new OnClickListener() { - @Override - public void onClick(DialogInterface dialog, int which) { - - if (type == R.string.password) { - mSelectedProfile.mUsername = ((EditText) userpwlayout.findViewById(R.id.username)).getText().toString(); - - String pw = ((EditText) userpwlayout.findViewById(R.id.password)).getText().toString(); - if (((CheckBox) userpwlayout.findViewById(R.id.savePassword)).isChecked()) { - mSelectedProfile.mPassword = pw; - } else { - mSelectedProfile.mPassword = null; - mTransientAuthPW = pw; - } + dialog.setPositiveButton(android.R.string.ok, + (callingDialog, which) -> { + if (type == R.string.password) { + mSelectedProfile.mUsername = ((EditText) userpwlayout.findViewById(R.id.username)).getText().toString(); + + String pw = ((EditText) userpwlayout.findViewById(R.id.password)).getText().toString(); + if (((CheckBox) userpwlayout.findViewById(R.id.savePassword)).isChecked()) { + mSelectedProfile.mPassword = pw; } else { - mTransientCertOrPCKS12PW = entry.getText().toString(); + mSelectedProfile.mPassword = null; + mTransientAuthPW = pw; } - Intent intent = new Intent(LaunchVPN.this, OpenVPNStatusService.class); - bindService(intent, mConnection, Context.BIND_AUTO_CREATE); + } else { + mTransientCertOrPCKS12PW = entry.getText().toString(); } - + Intent intent = new Intent(LaunchVPN.this, OpenVPNStatusService.class); + bindService(intent, mConnection, Context.BIND_AUTO_CREATE); }); dialog.setNegativeButton(android.R.string.cancel, - new DialogInterface.OnClickListener() { - @Override - public void onClick(DialogInterface dialog, int which) { - VpnStatus.updateStateString("USER_VPN_PASSWORD_CANCELLED", "", R.string.state_user_vpn_password_cancelled, - ConnectionStatus.LEVEL_NOTCONNECTED); - finish(); - } + (callingDialog, which) -> { + VpnStatus.updateStateString("USER_VPN_PASSWORD_CANCELLED", "", R.string.state_user_vpn_password_cancelled, + ConnectionStatus.LEVEL_NOTCONNECTED); + finish(); }); dialog.create().show(); diff --git a/app/src/main/java/ht/vpn/android/api/APIVpnProfile.java b/app/src/main/java/ht/vpn/android/api/APIVpnProfile.java old mode 100644 new mode 100755 index 7e18ef4..9763c51 --- a/app/src/main/java/ht/vpn/android/api/APIVpnProfile.java +++ b/app/src/main/java/ht/vpn/android/api/APIVpnProfile.java @@ -1,60 +1,60 @@ -/* - * Copyright (c) 2012-2016 Arne Schwabe - * Distributed under the GNU GPL v2 with additional terms. For full terms see the file doc/LICENSE.txt - */ - -package ht.vpn.android.api; - -import android.os.Parcel; -import android.os.Parcelable; - -public class APIVpnProfile implements Parcelable { - - public final String mUUID; - public final String mName; - public final boolean mUserEditable; - //public final String mProfileCreator; - - public APIVpnProfile(Parcel in) { - mUUID = in.readString(); - mName = in.readString(); - mUserEditable = in.readInt() != 0; - //mProfileCreator = in.readString(); - } - - public APIVpnProfile(String uuidString, String name, boolean userEditable, String profileCreator) { - mUUID = uuidString; - mName = name; - mUserEditable = userEditable; - //mProfileCreator = profileCreator; - } - - @Override - public int describeContents() { - return 0; - } - - @Override - public void writeToParcel(Parcel dest, int flags) { - dest.writeString(mUUID); - dest.writeString(mName); - if (mUserEditable) - dest.writeInt(0); - else - dest.writeInt(1); - //dest.writeString(mProfileCreator); - } - - public static final Parcelable.Creator CREATOR - = new Parcelable.Creator() { - public APIVpnProfile createFromParcel(Parcel in) { - return new APIVpnProfile(in); - } - - public APIVpnProfile[] newArray(int size) { - return new APIVpnProfile[size]; - } - }; - - -} +/* + * Copyright (c) 2012-2014 Arne Schwabe + * Distributed under the GNU GPL v2 with additional terms. For full terms see the file doc/LICENSE.txt + */ + +package ht.vpn.android.api; + +import android.os.Parcel; +import android.os.Parcelable; + +public class APIVpnProfile implements Parcelable { + + public final String mUUID; + public final String mName; + public final boolean mUserEditable; + //public final String mProfileCreator; + + public APIVpnProfile(Parcel in) { + mUUID = in.readString(); + mName = in.readString(); + mUserEditable = in.readInt() != 0; + //mProfileCreator = in.readString(); + } + + public APIVpnProfile(String uuidString, String name, boolean userEditable, String profileCreator) { + mUUID = uuidString; + mName = name; + mUserEditable = userEditable; + //mProfileCreator = profileCreator; + } + + @Override + public int describeContents() { + return 0; + } + + @Override + public void writeToParcel(Parcel dest, int flags) { + dest.writeString(mUUID); + dest.writeString(mName); + if (mUserEditable) + dest.writeInt(0); + else + dest.writeInt(1); + //dest.writeString(mProfileCreator); + } + + public static final Parcelable.Creator CREATOR + = new Parcelable.Creator() { + public APIVpnProfile createFromParcel(Parcel in) { + return new APIVpnProfile(in); + } + + public APIVpnProfile[] newArray(int size) { + return new APIVpnProfile[size]; + } + }; + + +} diff --git a/app/src/main/java/ht/vpn/android/api/ConfirmDialog.java b/app/src/main/java/ht/vpn/android/api/ConfirmDialog.java deleted file mode 100644 index 55cbb0b..0000000 --- a/app/src/main/java/ht/vpn/android/api/ConfirmDialog.java +++ /dev/null @@ -1,179 +0,0 @@ -/* - * Copyright (C) 2011 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package ht.vpn.android.api; - -import android.app.Activity; -import android.app.AlertDialog; -import android.app.AlertDialog.Builder; -import android.content.ComponentName; -import android.content.Context; -import android.content.DialogInterface; -import android.content.DialogInterface.OnShowListener; -import android.content.Intent; -import android.content.ServiceConnection; -import android.content.pm.ApplicationInfo; -import android.content.pm.PackageManager; -import android.os.IBinder; -import android.os.RemoteException; -import android.util.Log; -import android.view.View; -import android.widget.Button; -import android.widget.CompoundButton; -import android.widget.ImageView; -import android.widget.TextView; - -import ht.vpn.android.R; -import de.blinkt.openvpn.core.IOpenVPNServiceInternal; -import de.blinkt.openvpn.core.OpenVPNService; - - -public class ConfirmDialog extends Activity implements - CompoundButton.OnCheckedChangeListener, DialogInterface.OnClickListener { - private static final String TAG = "OpenVPNVpnConfirm"; - - public static final String EXTRA_PACKAGE_NAME = "android.intent.extra.PACKAGE_NAME"; - - public static final String ANONYMOUS_PACKAGE = "de.blinkt.openvpn.ANYPACKAGE"; - - private String mPackage; - - private Button mButton; - - private AlertDialog mAlert; - - private IOpenVPNServiceInternal mService; - private ServiceConnection mConnection = new ServiceConnection() { - @Override - public void onServiceConnected(ComponentName className, - IBinder service) { - mService = IOpenVPNServiceInternal.Stub.asInterface(service); - } - - @Override - public void onServiceDisconnected(ComponentName arg0) { - mService = null; - } - - }; - - @Override - protected void onResume() { - super.onResume(); - - Intent serviceintent = new Intent(this, OpenVPNService.class); - serviceintent.setAction(OpenVPNService.START_SERVICE); - bindService(serviceintent, mConnection, Context.BIND_AUTO_CREATE); - - Intent intent = getIntent(); - if (intent.getStringExtra(EXTRA_PACKAGE_NAME) != null) { - mPackage = intent.getStringExtra(EXTRA_PACKAGE_NAME); - } else { - mPackage = getCallingPackage(); - if (mPackage == null) { - finish(); - return; - } - } - - try { - View view = View.inflate(this, R.layout.api_confirm, null); - CharSequence appString; - if (mPackage.equals(ANONYMOUS_PACKAGE)) { - appString = getString(R.string.all_app_prompt, getString(R.string.app)); - } else { - PackageManager pm = getPackageManager(); - ApplicationInfo app = pm.getApplicationInfo(mPackage, 0); - appString = getString(R.string.prompt, app.loadLabel(pm), getString(R.string.app)); - ((ImageView) view.findViewById(R.id.icon)).setImageDrawable(app.loadIcon(pm)); - } - - - ((TextView) view.findViewById(R.id.prompt)).setText(appString); - ((CompoundButton) view.findViewById(R.id.check)).setOnCheckedChangeListener(this); - - - Builder builder = new AlertDialog.Builder(this); - - builder.setView(view); - - builder.setIconAttribute(android.R.attr.alertDialogIcon); - builder.setTitle(android.R.string.dialog_alert_title); - builder.setPositiveButton(android.R.string.ok, this); - builder.setNegativeButton(android.R.string.cancel, this); - - mAlert = builder.create(); - mAlert.setCanceledOnTouchOutside(false); - - mAlert.setOnShowListener(new OnShowListener() { - @Override - public void onShow(DialogInterface dialog) { - mButton = mAlert.getButton(DialogInterface.BUTTON_POSITIVE); - mButton.setEnabled(false); - - } - }); - - //setCloseOnTouchOutside(false); - - mAlert.show(); - - } catch (Exception e) { - Log.e(TAG, "onResume", e); - finish(); - } - } - - @Override - public void onBackPressed() { - setResult(RESULT_CANCELED); - finish(); - } - - @Override - public void onCheckedChanged(CompoundButton button, boolean checked) { - mButton.setEnabled(checked); - } - - @Override - protected void onPause() { - super.onPause(); - unbindService(mConnection); - - } - - @Override - public void onClick(DialogInterface dialog, int which) { - - if (which == DialogInterface.BUTTON_POSITIVE) { - try { - mService.addAllowedExternalApp(mPackage); - } catch (RemoteException e) { - e.printStackTrace(); - throw new RuntimeException(e); - } - setResult(RESULT_OK); - finish(); - } - - if (which == DialogInterface.BUTTON_NEGATIVE) { - setResult(RESULT_CANCELED); - finish(); - } - } - -} - diff --git a/app/src/main/java/ht/vpn/android/api/ExternalAppDatabase.java b/app/src/main/java/ht/vpn/android/api/ExternalAppDatabase.java old mode 100644 new mode 100755 index c3bc979..d448840 --- a/app/src/main/java/ht/vpn/android/api/ExternalAppDatabase.java +++ b/app/src/main/java/ht/vpn/android/api/ExternalAppDatabase.java @@ -1,111 +1,62 @@ /* - * Copyright (c) 2012-2016 Arne Schwabe + * Copyright (c) 2012-2014 Arne Schwabe * Distributed under the GNU GPL v2 with additional terms. For full terms see the file doc/LICENSE.txt */ package ht.vpn.android.api; -import android.app.Activity; import android.content.Context; -import android.content.Intent; import android.content.SharedPreferences; import android.content.SharedPreferences.Editor; -import android.content.pm.ApplicationInfo; -import android.content.pm.PackageManager; -import android.os.Binder; +import android.preference.PreferenceManager; import java.util.HashSet; import java.util.Set; -import de.blinkt.openvpn.core.Preferences; - -import static android.content.Intent.FLAG_ACTIVITY_NEW_TASK; - public class ExternalAppDatabase { - Context mContext; - - public ExternalAppDatabase(Context c) { - mContext =c; - } - - private final String PREFERENCES_KEY = "allowed_apps"; - - boolean isAllowed(String packagename) { - Set allowedapps = getExtAppList(); - - return allowedapps.contains(packagename); - - } - - public Set getExtAppList() { - SharedPreferences prefs = Preferences.getDefaultSharedPreferences(mContext); - Set apps = prefs.getStringSet(PREFERENCES_KEY, new HashSet()); - apps.add("pct.droid"); - apps.add("pct.droid.dev"); - return apps; - } - - public void addApp(String packagename) - { - Set allowedapps = getExtAppList(); - allowedapps.add(packagename); - saveExtAppList(allowedapps); - } - - private void saveExtAppList( Set allowedapps) { - SharedPreferences prefs = Preferences.getDefaultSharedPreferences(mContext); - Editor prefedit = prefs.edit(); - - // Workaround for bug - prefedit.putStringSet(PREFERENCES_KEY, allowedapps); - int counter = prefs.getInt("counter", 0); - prefedit.putInt("counter", counter + 1); - prefedit.apply(); - } - - public void clearAllApiApps() { - saveExtAppList(new HashSet()); - } - - public void removeApp(String packagename) { - Set allowedapps = getExtAppList(); - allowedapps.remove(packagename); - saveExtAppList(allowedapps); - } - - - public String checkOpenVPNPermission(PackageManager pm) throws SecurityRemoteException { - - for (String appPackage : getExtAppList()) { - ApplicationInfo app; - try { - app = pm.getApplicationInfo(appPackage, 0); - if (Binder.getCallingUid() == app.uid) { - return appPackage; - } - } catch (PackageManager.NameNotFoundException e) { - // App not found. Remove it from the list - removeApp(appPackage); - } - - } - throw new SecurityException("Unauthorized OpenVPN API Caller"); - } - - - public boolean checkRemoteActionPermission(Context c, String callingPackage) { - if (callingPackage == null) - callingPackage = ConfirmDialog.ANONYMOUS_PACKAGE; - - if (isAllowed(callingPackage)) { - return true; - } else { - Intent confirmDialog = new Intent(c, ConfirmDialog.class); - confirmDialog.addFlags(FLAG_ACTIVITY_NEW_TASK); - confirmDialog.putExtra(ConfirmDialog.EXTRA_PACKAGE_NAME, callingPackage); - c.startActivity(confirmDialog); - return false; - } - } + private Context mContext; + + public ExternalAppDatabase(Context c) { + mContext = c; + } + + private final String PREFERENCES_KEY = "PREFERENCES_KEY"; + + boolean isAllowed(String packagename) { + Set allowedapps = getExtAppList(); + return allowedapps.contains(packagename); + + } + + Set getExtAppList() { + SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(mContext); + Set apps = prefs.getStringSet(PREFERENCES_KEY, new HashSet()); + apps.add("pct.droid"); + apps.add("pct.droid.dev"); + return apps; + } + + public void addApp(String packagename) { + Set allowedapps = getExtAppList(); + allowedapps.add(packagename); + saveExtAppList(allowedapps); + } + + private void saveExtAppList(Set allowedapps) { + SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(mContext); + Editor prefedit = prefs.edit(); + prefedit.putStringSet(PREFERENCES_KEY, allowedapps); + prefedit.apply(); + } + + public void clearAllApiApps() { + saveExtAppList(new HashSet()); + } + + void removeApp(String packagename) { + Set allowedapps = getExtAppList(); + allowedapps.remove(packagename); + saveExtAppList(allowedapps); + } } diff --git a/app/src/main/java/ht/vpn/android/api/ExternalOpenVPNService.java b/app/src/main/java/ht/vpn/android/api/ExternalOpenVPNService.java old mode 100644 new mode 100755 index 8ad7bf1..2b1954f --- a/app/src/main/java/ht/vpn/android/api/ExternalOpenVPNService.java +++ b/app/src/main/java/ht/vpn/android/api/ExternalOpenVPNService.java @@ -1,403 +1,403 @@ -/* - * Copyright (c) 2012-2016 Arne Schwabe - * Distributed under the GNU GPL v2 with additional terms. For full terms see the file doc/LICENSE.txt - */ - -package ht.vpn.android.api; - -import android.annotation.TargetApi; -import android.app.Service; -import android.content.BroadcastReceiver; -import android.content.ComponentName; -import android.content.Context; -import android.content.Intent; -import android.content.IntentFilter; -import android.content.ServiceConnection; -import android.net.VpnService; -import android.os.Build; -import android.os.Handler; -import android.os.IBinder; -import android.os.Message; -import android.os.ParcelFileDescriptor; -import android.os.RemoteCallbackList; -import android.os.RemoteException; - -import java.io.IOException; -import java.io.StringReader; -import java.lang.ref.WeakReference; -import java.util.LinkedList; -import java.util.List; - -import de.blinkt.openvpn.VpnProfile; -import de.blinkt.openvpn.core.ConfigParser; -import de.blinkt.openvpn.core.ConfigParser.ConfigParseError; -import de.blinkt.openvpn.core.ConnectionStatus; -import de.blinkt.openvpn.core.IOpenVPNServiceInternal; -import de.blinkt.openvpn.core.OpenVPNService; -import de.blinkt.openvpn.core.ProfileManager; -import de.blinkt.openvpn.core.VPNLaunchHelper; -import de.blinkt.openvpn.core.VpnStatus; -import de.blinkt.openvpn.core.VpnStatus.StateListener; -import ht.vpn.android.LaunchVPN; -import ht.vpn.android.R; - -import ht.vpn.android.api.IOpenVPNStatusCallback; -import ht.vpn.android.api.IOpenVPNAPIService; - -@TargetApi(Build.VERSION_CODES.ICE_CREAM_SANDWICH_MR1) -public class ExternalOpenVPNService extends Service implements StateListener { - - private static final int SEND_TOALL = 0; - - final RemoteCallbackList mCallbacks = - new RemoteCallbackList<>(); - - private IOpenVPNServiceInternal mService; - private ExternalAppDatabase mExtAppDb; - - - private ServiceConnection mConnection = new ServiceConnection() { - - - @Override - public void onServiceConnected(ComponentName className, - IBinder service) { - // We've bound to LocalService, cast the IBinder and get LocalService instance - mService = (IOpenVPNServiceInternal) (service); - } - - @Override - public void onServiceDisconnected(ComponentName arg0) { - mService = null; - } - - }; - - private BroadcastReceiver mBroadcastReceiver = new BroadcastReceiver() { - @Override - public void onReceive(Context context, Intent intent) { - if (intent != null && Intent.ACTION_UNINSTALL_PACKAGE.equals(intent.getAction())){ - // Check if the running config is temporary and installed by the app being uninstalled - VpnProfile vp = ProfileManager.getLastConnectedVpn(); - if (ProfileManager.isTempProfile()) { - if(intent.getPackage().equals(vp.mProfileCreator)) { - if (mService != null) - try { - mService.stopVPN(false); - } catch (RemoteException e) { - e.printStackTrace(); - } - } - } - } - } - }; - - @Override - public void onCreate() { - super.onCreate(); - VpnStatus.addStateListener(this); - mExtAppDb = new ExternalAppDatabase(this); - - Intent intent = new Intent(getBaseContext(), OpenVPNService.class); - intent.setAction(OpenVPNService.START_SERVICE); - - bindService(intent, mConnection, Context.BIND_AUTO_CREATE); - mHandler.setService(this); - IntentFilter uninstallBroadcast = new IntentFilter(Intent.ACTION_PACKAGE_REMOVED ); - registerReceiver(mBroadcastReceiver, uninstallBroadcast); - - } - - private final IOpenVPNAPIService.Stub mBinder = new IOpenVPNAPIService.Stub() { - - @Override - public List getProfiles() throws RemoteException { - mExtAppDb.checkOpenVPNPermission(getPackageManager()); - - ProfileManager pm = ProfileManager.getInstance(getBaseContext()); - - List profiles = new LinkedList<>(); - - for (VpnProfile vp : pm.getProfiles()) { - if (!vp.profileDeleted) - profiles.add(new APIVpnProfile(vp.getUUIDString(), vp.mName, vp.mUserEditable, vp.mProfileCreator)); - } - - return profiles; - } - - - private void startProfile(VpnProfile vp) - { - Intent vpnPermissionIntent = VpnService.prepare(ExternalOpenVPNService.this); - /* Check if we need to show the confirmation dialog, - * Check if we need to ask for username/password */ - - int neddPassword = vp.needUserPWInput(null, null); - - if(vpnPermissionIntent != null || neddPassword != 0){ - Intent shortVPNIntent = new Intent(Intent.ACTION_MAIN); - shortVPNIntent.setClass(getBaseContext(), LaunchVPN.class); - shortVPNIntent.putExtra(LaunchVPN.EXTRA_KEY, vp.getUUIDString()); - shortVPNIntent.putExtra(LaunchVPN.EXTRA_HIDELOG, true); - shortVPNIntent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK); - startActivity(shortVPNIntent); - } else { - VPNLaunchHelper.startOpenVpn(vp, getBaseContext()); - } - - } - - @Override - public void startProfile(String profileUUID) throws RemoteException { - mExtAppDb.checkOpenVPNPermission(getPackageManager()); - - VpnProfile vp = ProfileManager.get(getBaseContext(), profileUUID); - if (vp.checkProfile(getApplicationContext()) != R.string.no_error_found) - throw new RemoteException(getString(vp.checkProfile(getApplicationContext()))); - - startProfile(vp); - } - - public void startVPN(String inlineConfig) throws RemoteException { - String callingApp = mExtAppDb.checkOpenVPNPermission(getPackageManager()); - - ConfigParser cp = new ConfigParser(); - try { - cp.parseConfig(new StringReader(inlineConfig)); - VpnProfile vp = cp.convertProfile(); - vp.mName = "Remote APP VPN"; - if (vp.checkProfile(getApplicationContext()) != R.string.no_error_found) - throw new RemoteException(getString(vp.checkProfile(getApplicationContext()))); - - vp.mProfileCreator = callingApp; - - /*int needpw = vp.needUserPWInput(false); - if(needpw !=0) - throw new RemoteException("The inline file would require user input: " + getString(needpw)); - */ - - ProfileManager.setTemporaryProfile(ExternalOpenVPNService.this, vp); - - startProfile(vp); - - } catch (IOException | ConfigParseError e) { - throw new RemoteException(e.getMessage()); - } - } - - - @Override - public boolean addVPNProfile(String name, String config) throws RemoteException { - return addNewVPNProfile(name, true, config) != null; - } - - - @Override - public APIVpnProfile addNewVPNProfile(String name, boolean userEditable, String config) throws RemoteException { - String callingPackage = mExtAppDb.checkOpenVPNPermission(getPackageManager()); - - ConfigParser cp = new ConfigParser(); - try { - cp.parseConfig(new StringReader(config)); - VpnProfile vp = cp.convertProfile(); - vp.mName = name; - vp.mProfileCreator = callingPackage; - vp.mUserEditable = userEditable; - ProfileManager pm = ProfileManager.getInstance(getBaseContext()); - pm.addProfile(vp); - pm.saveProfile(ExternalOpenVPNService.this, vp); - pm.saveProfileList(ExternalOpenVPNService.this); - return new APIVpnProfile(vp.getUUIDString(), vp.mName, vp.mUserEditable, vp.mProfileCreator); - } catch (IOException e) { - VpnStatus.logException(e); - return null; - } catch (ConfigParseError e) { - VpnStatus.logException(e); - return null; - } - } - - @Override - public void removeProfile(String profileUUID) throws RemoteException { - mExtAppDb.checkOpenVPNPermission(getPackageManager()); - ProfileManager pm = ProfileManager.getInstance(getBaseContext()); - VpnProfile vp = ProfileManager.get(getBaseContext(), profileUUID); - pm.removeProfile(ExternalOpenVPNService.this, vp); - } - - @Override - public boolean protectSocket(ParcelFileDescriptor pfd) throws RemoteException { - mExtAppDb.checkOpenVPNPermission(getPackageManager()); - try { - boolean success= mService.protect(pfd.getFd()); - pfd.close(); - return success; - } catch (IOException e) { - throw new RemoteException(e.getMessage()); - } - } - - - @Override - public Intent prepare(String packageName) { - if (new ExternalAppDatabase(ExternalOpenVPNService.this).isAllowed(packageName)) - return null; - - Intent intent = new Intent(); - intent.setClass(ExternalOpenVPNService.this, ConfirmDialog.class); - return intent; - } - - @Override - public Intent prepareVPNService() throws RemoteException { - mExtAppDb.checkOpenVPNPermission(getPackageManager()); - - if (VpnService.prepare(ExternalOpenVPNService.this) == null) - return null; - else - return new Intent(getBaseContext(), GrantPermissionsActivity.class); - } - - - @Override - public void registerStatusCallback(IOpenVPNStatusCallback cb) - throws RemoteException { - mExtAppDb.checkOpenVPNPermission(getPackageManager()); - - if (cb != null) { - cb.newStatus(mMostRecentState.vpnUUID, mMostRecentState.state, - mMostRecentState.logmessage, mMostRecentState.level.name()); - mCallbacks.register(cb); - } - - - } - - @Override - public void unregisterStatusCallback(IOpenVPNStatusCallback cb) - throws RemoteException { - mExtAppDb.checkOpenVPNPermission(getPackageManager()); - - if (cb != null) - mCallbacks.unregister(cb); - } - - @Override - public void disconnect() throws RemoteException { - mExtAppDb.checkOpenVPNPermission(getPackageManager()); - if (mService != null) - mService.stopVPN(false); - } - - @Override - public void pause() throws RemoteException { - mExtAppDb.checkOpenVPNPermission(getPackageManager()); - if (mService != null) - mService.userPause(true); - } - - @Override - public void resume() throws RemoteException { - mExtAppDb.checkOpenVPNPermission(getPackageManager()); - if (mService != null) - mService.userPause(false); - - } - }; - - - private UpdateMessage mMostRecentState; - - @Override - public IBinder onBind(Intent intent) { - return mBinder; - } - - @Override - public void onDestroy() { - super.onDestroy(); - mCallbacks.kill(); - unbindService(mConnection); - VpnStatus.removeStateListener(this); - unregisterReceiver(mBroadcastReceiver); - } - - - - class UpdateMessage { - public String state; - public String logmessage; - public ConnectionStatus level; - String vpnUUID; - - UpdateMessage(String state, String logmessage, ConnectionStatus level) { - this.state = state; - this.logmessage = logmessage; - this.level = level; - } - } - - @Override - public void updateState(String state, String logmessage, int resid, ConnectionStatus level, Intent intent) { - mMostRecentState = new UpdateMessage(state, logmessage, level); - if (ProfileManager.getLastConnectedVpn() != null) - mMostRecentState.vpnUUID = ProfileManager.getLastConnectedVpn().getUUIDString(); - - Message msg = mHandler.obtainMessage(SEND_TOALL, mMostRecentState); - msg.sendToTarget(); - - } - - @Override - public void setConnectedVPN(String uuid) { - - } - - private static final OpenVPNServiceHandler mHandler = new OpenVPNServiceHandler(); - - - static class OpenVPNServiceHandler extends Handler { - WeakReference service = null; - - private void setService(ExternalOpenVPNService eos) { - service = new WeakReference<>(eos); - } - - @Override - public void handleMessage(Message msg) { - - RemoteCallbackList callbacks; - switch (msg.what) { - case SEND_TOALL: - if (service == null || service.get() == null) - return; - - callbacks = service.get().mCallbacks; - - - // Broadcast to all clients the new value. - final int N = callbacks.beginBroadcast(); - for (int i = 0; i < N; i++) { - try { - sendUpdate(callbacks.getBroadcastItem(i), (UpdateMessage) msg.obj); - } catch (RemoteException e) { - // The RemoteCallbackList will take care of removing - // the dead object for us. - } - } - callbacks.finishBroadcast(); - break; - } - } - - private void sendUpdate(IOpenVPNStatusCallback broadcastItem, - UpdateMessage um) throws RemoteException { - broadcastItem.newStatus(um.vpnUUID, um.state, um.logmessage, um.level.name()); - } - } - - - +/* + * Copyright (c) 2012-2014 Arne Schwabe + * Distributed under the GNU GPL v2 with additional terms. For full terms see the file doc/LICENSE.txt + */ + +package ht.vpn.android.api; + +import android.annotation.TargetApi; +import android.app.Service; +import android.content.ComponentName; +import android.content.Context; +import android.content.Intent; +import android.content.ServiceConnection; +import android.content.pm.ApplicationInfo; +import android.content.pm.PackageManager; +import android.content.pm.PackageManager.NameNotFoundException; +import android.net.VpnService; +import android.os.Binder; +import android.os.Build; +import android.os.Handler; +import android.os.IBinder; +import android.os.Message; +import android.os.ParcelFileDescriptor; +import android.os.RemoteCallbackList; +import android.os.RemoteException; + +import java.io.IOException; +import java.io.StringReader; +import java.lang.ref.WeakReference; +import java.util.HashSet; +import java.util.LinkedList; +import java.util.List; +import java.util.Set; + +import de.blinkt.openvpn.VpnProfile; +import de.blinkt.openvpn.core.ConnectionStatus; +import de.blinkt.openvpn.core.IOpenVPNServiceInternal; +import ht.vpn.android.Preferences; +import ht.vpn.android.R; +import de.blinkt.openvpn.core.ConfigParser; +import de.blinkt.openvpn.core.ConfigParser.ConfigParseError; +import de.blinkt.openvpn.core.OpenVPNService; +import de.blinkt.openvpn.core.ProfileManager; +import de.blinkt.openvpn.core.VPNLaunchHelper; +import de.blinkt.openvpn.core.VpnStatus; +import de.blinkt.openvpn.core.VpnStatus.StateListener; +import ht.vpn.android.VPNhtApplication; +import ht.vpn.android.activities.ConfirmAPIActivity; +import ht.vpn.android.activities.GrantPermissionsActivity; +import ht.vpn.android.api.IOpenVPNAPIService; +import ht.vpn.android.api.IOpenVPNStatusCallback; +import ht.vpn.android.utils.PrefUtils; + +@TargetApi(Build.VERSION_CODES.ICE_CREAM_SANDWICH_MR1) +public class ExternalOpenVPNService extends Service implements StateListener { + + private static final int SEND_TOALL = 0; + + final RemoteCallbackList mCallbacks = + new RemoteCallbackList<>(); + + private IOpenVPNServiceInternal mService; + private ExternalAppDatabase mExtAppDb; + + + private ServiceConnection mConnection = new ServiceConnection() { + + + @Override + public void onServiceConnected(ComponentName className, + IBinder service) { + mService = IOpenVPNServiceInternal.Stub.asInterface(service); + } + + @Override + public void onServiceDisconnected(ComponentName arg0) { + mService = null; + } + + }; + + @Override + public void onCreate() { + super.onCreate(); + VpnStatus.addStateListener(this); + mExtAppDb = new ExternalAppDatabase(this); + + Intent intent = new Intent(getBaseContext(), OpenVPNService.class); + intent.setAction(OpenVPNService.START_SERVICE); + + bindService(intent, mConnection, Context.BIND_AUTO_CREATE); + mHandler.setService(this); + } + + private final IOpenVPNAPIService.Stub mBinder = new IOpenVPNAPIService.Stub() { + + private String checkOpenVPNPermission() throws SecurityRemoteException { + PackageManager pm = getPackageManager(); + + Set set = new HashSet<>(mExtAppDb.getExtAppList()); + for (String appPackage : set) { + ApplicationInfo app; + try { + app = pm.getApplicationInfo(appPackage, 0); + if (Binder.getCallingUid() == app.uid) { + return appPackage; + } + } catch (NameNotFoundException e) { + // App not found. Remove it from the list + mExtAppDb.removeApp(appPackage); + } + } + throw new SecurityException("Unauthorized OpenVPN API Caller"); + } + + public boolean isConnectedOrConnecting() { + return mMostRecentState.level == ConnectionStatus.LEVEL_CONNECTED || mMostRecentState.level == ConnectionStatus.LEVEL_CONNECTING_NO_SERVER_REPLY_YET || mMostRecentState.level == ConnectionStatus.LEVEL_CONNECTING_SERVER_REPLIED; + } + + @Override + public List getProfiles() throws RemoteException { + checkOpenVPNPermission(); + + ProfileManager pm = ProfileManager.getInstance(getBaseContext()); + + List profiles = new LinkedList<>(); + + for (VpnProfile vp : pm.getProfiles()) { + if (!vp.profileDeleted) + profiles.add(new APIVpnProfile(vp.getUUIDString(), vp.mName, vp.mUserEditable, vp.mProfileCreator)); + } + + return profiles; + } + + + private void startProfile(VpnProfile vp) { + Intent vpnPermissionIntent = VpnService.prepare(ExternalOpenVPNService.this); + /* Check if we need to show the confirmation dialog, + * Check if we need to ask for username/password */ + + int needpw = vp.needUserPWInput(null, null); + + if (vpnPermissionIntent != null || needpw != 0) { + Intent shortVPNIntent = new Intent(Intent.ACTION_MAIN); + shortVPNIntent.setClass(getBaseContext(), ht.vpn.android.LaunchVPN.class); + shortVPNIntent.putExtra(ht.vpn.android.LaunchVPN.EXTRA_KEY, vp.getUUIDString()); + shortVPNIntent.putExtra(ht.vpn.android.LaunchVPN.EXTRA_HIDELOG, true); + shortVPNIntent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK); + startActivity(shortVPNIntent); + } else { + VPNLaunchHelper.startOpenVpn(vp, getBaseContext()); + } + + } + + @Override + public void startProfile(String profileUUID) throws RemoteException { + checkOpenVPNPermission(); + + VpnProfile vp = ProfileManager.get(getBaseContext(), profileUUID); + if (vp.checkProfile(getApplicationContext()) != R.string.no_error_found) + throw new RemoteException(getString(vp.checkProfile(getApplicationContext()))); + + startProfile(vp); + } + + public void startVPN(String name, String inlineConfig) throws RemoteException { + checkOpenVPNPermission(); + + ConfigParser cp = new ConfigParser(); + try { + cp.parseConfig(new StringReader(inlineConfig)); + VpnProfile vp = cp.convertProfile(); + vp.mName = name; + if (vp.checkProfile(getApplicationContext()) != R.string.no_error_found) + throw new RemoteException(getString(vp.checkProfile(getApplicationContext()))); + + /*int needpw = vp.needUserPWInput(false); + if(needpw !=0) + throw new RemoteException("The inline file would require user input: " + getString(needpw)); + */ + + vp.mUsername = PrefUtils.get(ExternalOpenVPNService.this, Preferences.USERNAME, ""); + vp.mPassword = PrefUtils.get(ExternalOpenVPNService.this, Preferences.PASSWORD, ""); + + ProfileManager.setTemporaryProfile(ExternalOpenVPNService.this, vp); + startProfile(vp); + } catch (IOException | ConfigParseError e) { + throw new RemoteException(e.getMessage()); + } + } + + + @Override + public boolean addVPNProfile(String name, String config) throws RemoteException { + return addNewVPNProfile(name, true, config) != null; + } + + + @Override + public APIVpnProfile addNewVPNProfile(String name, boolean userEditable, String config) throws RemoteException { + String callingPackage = checkOpenVPNPermission(); + + ConfigParser cp = new ConfigParser(); + try { + cp.parseConfig(new StringReader(config)); + VpnProfile vp = cp.convertProfile(); + vp.mName = name; + vp.mProfileCreator = callingPackage; + vp.mUserEditable = userEditable; + ProfileManager pm = ProfileManager.getInstance(getBaseContext()); + pm.addProfile(vp); + pm.saveProfile(ExternalOpenVPNService.this, vp); + pm.saveProfileList(ExternalOpenVPNService.this); + return new APIVpnProfile(vp.getUUIDString(), vp.mName, vp.mUserEditable, vp.mProfileCreator); + } catch (IOException e) { + VpnStatus.logException(e); + return null; + } catch (ConfigParseError e) { + VpnStatus.logException(e); + return null; + } + } + + @Override + public void removeProfile(String profileUUID) throws RemoteException { + checkOpenVPNPermission(); + ProfileManager pm = ProfileManager.getInstance(getBaseContext()); + VpnProfile vp = ProfileManager.get(getBaseContext(), profileUUID); + pm.removeProfile(ExternalOpenVPNService.this, vp); + } + + @Override + public boolean protectSocket(ParcelFileDescriptor pfd) throws RemoteException { + checkOpenVPNPermission(); + try { + boolean success = mService.protect(pfd.getFd()); + pfd.close(); + return success; + } catch (IOException e) { + throw new RemoteException(e.getMessage()); + } + } + + + @Override + public Intent prepare(String packageName) { + if (new ExternalAppDatabase(ExternalOpenVPNService.this).isAllowed(packageName)) + return null; + + Intent intent = new Intent(); + intent.setClass(ExternalOpenVPNService.this, ConfirmAPIActivity.class); + return intent; + } + + @Override + public Intent prepareVPNService() throws RemoteException { + checkOpenVPNPermission(); + + if (VpnService.prepare(ExternalOpenVPNService.this) == null) + return null; + else + return new Intent(getBaseContext(), GrantPermissionsActivity.class); + } + + + @Override + public void registerStatusCallback(IOpenVPNStatusCallback cb) + throws RemoteException { + checkOpenVPNPermission(); + + if (cb != null) { + cb.newStatus(mMostRecentState.vpnUUID, mMostRecentState.state, + mMostRecentState.logmessage, mMostRecentState.level.name()); + mCallbacks.register(cb); + } + + + } + + @Override + public void unregisterStatusCallback(IOpenVPNStatusCallback cb) + throws RemoteException { + checkOpenVPNPermission(); + + if (cb != null) + mCallbacks.unregister(cb); + } + + @Override + public void disconnect() throws RemoteException { + checkOpenVPNPermission(); + if (mService != null) + mService.stopVPN(false); + } + + @Override + public void pause() throws RemoteException { + checkOpenVPNPermission(); + if (mService != null) + mService.userPause(true); + } + + @Override + public void resume() throws RemoteException { + checkOpenVPNPermission(); + if (mService != null) + mService.userPause(false); + + } + }; + + + private UpdateMessage mMostRecentState; + + @Override + public IBinder onBind(Intent intent) { + return mBinder; + } + + @Override + public void onDestroy() { + super.onDestroy(); + mCallbacks.kill(); + unbindService(mConnection); + VpnStatus.removeStateListener(this); + } + + @Override + public void setConnectedVPN(String uuid) { + + } + + class UpdateMessage { + public String state; + public String logmessage; + public ConnectionStatus level; + public String vpnUUID; + + public UpdateMessage(String state, String logmessage, ConnectionStatus level) { + this.state = state; + this.logmessage = logmessage; + this.level = level; + } + } + + @Override + public void updateState(String state, String logmessage, int resid, ConnectionStatus level, Intent intent) { + mMostRecentState = new UpdateMessage(state, logmessage, level); + if (ProfileManager.getLastConnectedVpn() != null) + mMostRecentState.vpnUUID = ProfileManager.getLastConnectedVpn().getUUIDString(); + + Message msg = mHandler.obtainMessage(SEND_TOALL, mMostRecentState); + msg.sendToTarget(); + + } + + private static final OpenVPNServiceHandler mHandler = new OpenVPNServiceHandler(); + + + static class OpenVPNServiceHandler extends Handler { + WeakReference service = null; + + private void setService(ExternalOpenVPNService eos) { + service = new WeakReference<>(eos); + } + + @Override + public void handleMessage(Message msg) { + + RemoteCallbackList callbacks; + switch (msg.what) { + case SEND_TOALL: + if (service == null || service.get() == null) + return; + + callbacks = service.get().mCallbacks; + + + // Broadcast to all clients the new value. + final int N = callbacks.beginBroadcast(); + for (int i = 0; i < N; i++) { + try { + sendUpdate(callbacks.getBroadcastItem(i), (UpdateMessage) msg.obj); + } catch (RemoteException e) { + // The RemoteCallbackList will take care of removing + // the dead object for us. + } + } + callbacks.finishBroadcast(); + break; + } + } + + private void sendUpdate(IOpenVPNStatusCallback broadcastItem, + UpdateMessage um) throws RemoteException { + broadcastItem.newStatus(um.vpnUUID, um.state, um.logmessage, um.level.name()); + } + } + + } \ No newline at end of file diff --git a/app/src/main/java/ht/vpn/android/api/GrantPermissionsActivity.java b/app/src/main/java/ht/vpn/android/api/GrantPermissionsActivity.java deleted file mode 100644 index d90280f..0000000 --- a/app/src/main/java/ht/vpn/android/api/GrantPermissionsActivity.java +++ /dev/null @@ -1,31 +0,0 @@ -/* - * Copyright (c) 2012-2016 Arne Schwabe - * Distributed under the GNU GPL v2 with additional terms. For full terms see the file doc/LICENSE.txt - */ - -package ht.vpn.android.api; - -import android.app.Activity; -import android.content.Intent; -import android.net.VpnService; - -public class GrantPermissionsActivity extends Activity { - private static final int VPN_PREPARE = 0; - - @Override - protected void onStart() { - super.onStart(); - Intent i= VpnService.prepare(this); - if(i==null) - onActivityResult(VPN_PREPARE, RESULT_OK, null); - else - startActivityForResult(i, VPN_PREPARE); - } - - @Override - protected void onActivityResult(int requestCode, int resultCode, Intent data) { - super.onActivityResult(requestCode, resultCode, data); - setResult(resultCode); - finish(); - } -} diff --git a/app/src/main/java/ht/vpn/android/api/RemoteAction.java b/app/src/main/java/ht/vpn/android/api/RemoteAction.java deleted file mode 100644 index 811a41e..0000000 --- a/app/src/main/java/ht/vpn/android/api/RemoteAction.java +++ /dev/null @@ -1,105 +0,0 @@ -/* - * Copyright (c) 2012-2017 Arne Schwabe - * Distributed under the GNU GPL v2 with additional terms. For full terms see the file doc/LICENSE.txt - */ - -package ht.vpn.android.api; - -import android.app.Activity; -import android.content.ComponentName; -import android.content.Context; -import android.content.Intent; -import android.content.ServiceConnection; -import android.os.Bundle; -import android.os.IBinder; -import android.os.RemoteException; -import android.widget.Toast; - -import de.blinkt.openvpn.VpnProfile; -import de.blinkt.openvpn.core.IOpenVPNServiceInternal; -import de.blinkt.openvpn.core.OpenVPNService; -import de.blinkt.openvpn.core.ProfileManager; -import ht.vpn.android.LaunchVPN; - -public class RemoteAction extends Activity { - - public static final String EXTRA_NAME = "de.blinkt.openvpn.api.profileName"; - private ExternalAppDatabase mExtAppDb; - private boolean mDoDisconnect; - private IOpenVPNServiceInternal mService; - private ServiceConnection mConnection = new ServiceConnection() { - @Override - public void onServiceConnected(ComponentName className, - IBinder service) { - - mService = IOpenVPNServiceInternal.Stub.asInterface(service); - try { - performAction(); - } catch (RemoteException e) { - e.printStackTrace(); - } - } - - @Override - public void onServiceDisconnected(ComponentName arg0) { - //mService = null; - } - - }; - - @Override - protected void onCreate(Bundle savedInstanceState) { - super.onCreate(savedInstanceState); - - mExtAppDb = new ExternalAppDatabase(this); - } - - @Override - protected void onResume() { - super.onResume(); - - Intent intent = new Intent(this, OpenVPNService.class); - intent.setAction(OpenVPNService.START_SERVICE); - getApplicationContext().bindService(intent, mConnection, Context.BIND_AUTO_CREATE); - - } - - private void performAction() throws RemoteException { - - if (!mService.isAllowedExternalApp(getCallingPackage())) { - finish(); - return; - } - - Intent intent = getIntent(); - setIntent(null); - ComponentName component = intent.getComponent(); - if (component.getShortClassName().equals(".api.DisconnectVPN")) { - mService.stopVPN(false); - } else if (component.getShortClassName().equals(".api.ConnectVPN")) { - String vpnName = intent.getStringExtra(EXTRA_NAME); - VpnProfile profile = ProfileManager.getInstance(this).getProfileByName(vpnName); - if (profile == null) { - Toast.makeText(this, String.format("Vpn profile %s from API call not found", vpnName), Toast.LENGTH_LONG).show(); - } else { - Intent startVPN = new Intent(this, LaunchVPN.class); - startVPN.putExtra(LaunchVPN.EXTRA_KEY, profile.getUUID().toString()); - startVPN.setAction(Intent.ACTION_MAIN); - startActivity(startVPN); - } - } - finish(); - - - - } - - @Override - public void finish() { - if(mService!=null) { - mService = null; - getApplicationContext().unbindService(mConnection); - } - super.finish(); - } -} diff --git a/app/src/main/java/ht/vpn/android/api/SecurityRemoteException.java b/app/src/main/java/ht/vpn/android/api/SecurityRemoteException.java old mode 100644 new mode 100755 index 73d2482..eaf08b6 --- a/app/src/main/java/ht/vpn/android/api/SecurityRemoteException.java +++ b/app/src/main/java/ht/vpn/android/api/SecurityRemoteException.java @@ -1,17 +1,17 @@ -/* - * Copyright (c) 2012-2016 Arne Schwabe - * Distributed under the GNU GPL v2 with additional terms. For full terms see the file doc/LICENSE.txt - */ - -package ht.vpn.android.api; - -import android.os.RemoteException; - -public class SecurityRemoteException extends RemoteException { - - /** - * - */ - private static final long serialVersionUID = 1L; - -} +/* + * Copyright (c) 2012-2014 Arne Schwabe + * Distributed under the GNU GPL v2 with additional terms. For full terms see the file doc/LICENSE.txt + */ + +package ht.vpn.android.api; + +import android.os.RemoteException; + +public class SecurityRemoteException extends RemoteException { + + /** + * + */ + private static final long serialVersionUID = 1L; + +} diff --git a/app/src/main/res/layout/activity_main.xml b/app/src/main/res/layout/activity_main.xml index 68ea08c..fbaedc7 100644 --- a/app/src/main/res/layout/activity_main.xml +++ b/app/src/main/res/layout/activity_main.xml @@ -10,7 +10,7 @@ android:minHeight="?attr/actionBarSize" android:background="?attr/colorPrimary" android:title="@string/app_name" - android:theme="@style/ThemeOverlay.AppCompat.Dark.ActionBar" + android:elevation="2dp" /> + android:textColor="@android:color/white" + android:backgroundTint="@color/green" /> + android:textColor="@android:color/white" + android:backgroundTint="@color/red" /> \ No newline at end of file diff --git a/app/src/main/res/layout/toolbar.xml b/app/src/main/res/layout/toolbar.xml index 848b264..7ffb8da 100644 --- a/app/src/main/res/layout/toolbar.xml +++ b/app/src/main/res/layout/toolbar.xml @@ -6,5 +6,5 @@ android:minHeight="?attr/actionBarSize" android:background="?attr/colorPrimary" android:title="@string/app_name" - android:theme="@style/ThemeOverlay.AppCompat.Dark.ActionBar" + android:elevation="2dp" /> \ No newline at end of file diff --git a/app/src/main/res/layout/userpass.xml b/app/src/main/res/layout/userpass.xml index d49bc79..fdca464 100644 --- a/app/src/main/res/layout/userpass.xml +++ b/app/src/main/res/layout/userpass.xml @@ -13,7 +13,7 @@ android:layout_marginLeft="4dp" android:layout_marginRight="4dp" android:layout_marginBottom="4dp"> - - @color/secondary - - - -