diff options
author | Arne Schwabe <arne@rfc2549.org> | 2020-05-27 13:39:55 +0200 |
---|---|---|
committer | Arne Schwabe <arne@rfc2549.org> | 2020-05-27 17:01:23 +0200 |
commit | 00b10ed048cc1f6490e7ca3e0530dd4471ca5a40 (patch) | |
tree | 0ffe2af2125fc0a05b05d8e3f55ab40a950724a6 | |
parent | 45d8e94d3b8421018fa86a8ca1439210fedbd8de (diff) |
Implement internal webview for authenticating when OPEN_URL is used
11 files changed, 210 insertions, 45 deletions
diff --git a/main/src/main/AndroidManifest.xml b/main/src/main/AndroidManifest.xml index cfa99452..78b45ef2 100644 --- a/main/src/main/AndroidManifest.xml +++ b/main/src/main/AndroidManifest.xml @@ -228,6 +228,7 @@ android:value="de.blinkt.openvpn.activities.MainActivity" /> </activity> <activity android:name=".api.RemoteAction" /> + <activity android:name=".activities.MainActivity" /> <activity-alias android:name=".api.ConnectVPN" diff --git a/main/src/main/java/de/blinkt/openvpn/VpnProfile.java b/main/src/main/java/de/blinkt/openvpn/VpnProfile.java index e6815dcf..921ea4db 100644 --- a/main/src/main/java/de/blinkt/openvpn/VpnProfile.java +++ b/main/src/main/java/de/blinkt/openvpn/VpnProfile.java @@ -673,7 +673,7 @@ public class VpnProfile implements Serializable, Cloneable { NativeUtils.getNativeAPI(), Build.BRAND, Build.BOARD, Build.MODEL); } - public String getVersionEnvString(Context c) { + static public String getVersionEnvString(Context c) { String version = "unknown"; try { PackageInfo packageinfo = c.getPackageManager().getPackageInfo(c.getPackageName(), 0); diff --git a/main/src/main/java/de/blinkt/openvpn/core/OpenVPNService.java b/main/src/main/java/de/blinkt/openvpn/core/OpenVPNService.java index 51add1cd..eb88e0cc 100644 --- a/main/src/main/java/de/blinkt/openvpn/core/OpenVPNService.java +++ b/main/src/main/java/de/blinkt/openvpn/core/OpenVPNService.java @@ -31,14 +31,15 @@ import android.os.IBinder; import android.os.Message; import android.os.ParcelFileDescriptor; import android.os.RemoteException; -import androidx.annotation.NonNull; -import androidx.annotation.RequiresApi; import android.system.OsConstants; import android.text.TextUtils; import android.util.Base64; import android.util.Log; import android.widget.Toast; +import androidx.annotation.NonNull; +import androidx.annotation.RequiresApi; + import java.io.IOException; import java.lang.reflect.InvocationTargetException; import java.lang.reflect.Method; @@ -77,6 +78,7 @@ public class OpenVPNService extends VpnService implements StateListener, Callbac private static final String RESUME_VPN = "de.blinkt.openvpn.RESUME_VPN"; public static final String EXTRA_CHALLENGE_TXT = "de.blinkt.openvpn.core.CR_TEXT_CHALLENGE"; + public static final String EXTRA_CHALLENGE_OPENURL = "de.blinkt.openvpn.core.OPENURL_CHALLENGE"; private static final int PRIORITY_MIN = -2; private static final int PRIORITY_DEFAULT = 0; @@ -174,8 +176,6 @@ public class OpenVPNService extends VpnService implements StateListener, Callbac return res.getString(R.string.volume_gbyte, bytesUnit); } - - } /** @@ -700,6 +700,8 @@ public class OpenVPNService extends VpnService implements StateListener, Callbac return null; } + + @Override public IBinder asBinder() { return mBinder; @@ -1289,13 +1291,9 @@ public class OpenVPNService extends VpnService implements StateListener, Callbac nbuilder.setContentTitle(getString(reason)); nbuilder.setContentText(url); - - - intent = new Intent(Intent.ACTION_VIEW); + intent = VariantConfig.getOpenUrlIntent(this); intent.setData(Uri.parse(url)); intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK); - - } else if (method.equals("CR_TEXT")) { String challenge = info.split(":", 2)[1]; reason = R.string.crtext_requested; diff --git a/main/src/main/res/values/strings.xml b/main/src/main/res/values/strings.xml index ca7cd0bf..82633350 100755 --- a/main/src/main/res/values/strings.xml +++ b/main/src/main/res/values/strings.xml @@ -497,5 +497,6 @@ <string name="request_autologin">Request autologin profile</string> <string name="import_from_as">Import Profile from Access Server</string> <string name="no_default_vpn_set">Default VPN not set. Please set the Default VPN before enabling this option.</string> + <string name="internal_web_view">Internal WebView</string> </resources> diff --git a/main/src/skeleton/java/de/blinkt/openvpn/core/VariantConfig.java b/main/src/skeleton/java/de/blinkt/openvpn/core/VariantConfig.java new file mode 100644 index 00000000..bbebc2af --- /dev/null +++ b/main/src/skeleton/java/de/blinkt/openvpn/core/VariantConfig.java @@ -0,0 +1,16 @@ +/* + * Copyright (c) 2012-2020 Arne Schwabe + * Distributed under the GNU GPL v2 with additional terms. For full terms see the file doc/LICENSE.txt + */ + +package de.blinkt.openvpn.core; + +import android.content.Context; +import android.content.Intent; + +public class VariantConfig { + static Intent getOpenUrlIntent(Context c) { + return new Intent(Intent.ACTION_VIEW); + } + +} diff --git a/main/src/ui/AndroidManifest.xml b/main/src/ui/AndroidManifest.xml index a4489228..86aa2956 100644 --- a/main/src/ui/AndroidManifest.xml +++ b/main/src/ui/AndroidManifest.xml @@ -4,30 +4,33 @@ --> <manifest xmlns:android="http://schemas.android.com/apk/res/android" - xmlns:tools="http://schemas.android.com/tools" - package="de.blinkt.openvpn"> + xmlns:tools="http://schemas.android.com/tools" + package="de.blinkt.openvpn"> + <uses-feature - android:name="android.software.leanback" - android:required="false" /> + android:name="android.software.leanback" + android:required="false" /> <uses-feature - android:name="android.hardware.touchscreen" - android:required="false" /> + android:name="android.hardware.touchscreen" + android:required="false" /> + <application - android:banner="@mipmap/banner_tv" - > - <activity - android:name=".activities.MainActivity" - tools:ignore="ExportedActivity"> - <intent-filter> - <action android:name="android.intent.action.MAIN" /> + android:banner="@mipmap/banner_tv" + tools:targetApi="lollipop"> + <activity + android:name=".activities.MainActivity" + tools:ignore="ExportedActivity"> + <intent-filter> + <action android:name="android.intent.action.MAIN" /> - <category android:name="android.intent.category.LEANBACK_LAUNCHER" /> - <category android:name="android.intent.category.BROWSABLE" /> - <category android:name="android.intent.category.LAUNCHER" /> - </intent-filter> - <intent-filter> - <action android:name="android.service.quicksettings.action.QS_TILE_PREFERENCES" /> - </intent-filter> - </activity> + <category android:name="android.intent.category.LEANBACK_LAUNCHER" /> + <category android:name="android.intent.category.BROWSABLE" /> + <category android:name="android.intent.category.LAUNCHER" /> + </intent-filter> + <intent-filter> + <action android:name="android.service.quicksettings.action.QS_TILE_PREFERENCES" /> + </intent-filter> + </activity> + <activity android:name=".activities.InternalWebView" /> </application> </manifest> diff --git a/main/src/ui/java/de/blinkt/openvpn/activities/CredentialsPopup.kt b/main/src/ui/java/de/blinkt/openvpn/activities/CredentialsPopup.kt index f5d836b9..6c59ca88 100644 --- a/main/src/ui/java/de/blinkt/openvpn/activities/CredentialsPopup.kt +++ b/main/src/ui/java/de/blinkt/openvpn/activities/CredentialsPopup.kt @@ -5,9 +5,11 @@ package de.blinkt.openvpn.activities import android.content.Intent +import android.net.VpnService import android.os.Bundle import androidx.appcompat.app.AppCompatActivity import androidx.fragment.app.DialogFragment +import de.blinkt.openvpn.core.OpenVPNService import de.blinkt.openvpn.core.PasswordDialogFragment.Companion.newInstance class CredentialsPopup : AppCompatActivity() { diff --git a/main/src/ui/java/de/blinkt/openvpn/activities/InternalWebView.kt b/main/src/ui/java/de/blinkt/openvpn/activities/InternalWebView.kt new file mode 100644 index 00000000..2bad9e81 --- /dev/null +++ b/main/src/ui/java/de/blinkt/openvpn/activities/InternalWebView.kt @@ -0,0 +1,99 @@ +/* + * Copyright (c) 2012-2020 Arne Schwabe + * Distributed under the GNU GPL v2 with additional terms. For full terms see the file doc/LICENSE.txt + */ + +package de.blinkt.openvpn.activities + +import android.annotation.SuppressLint +import android.annotation.TargetApi +import android.content.Intent +import android.os.Build +import android.os.Bundle +import android.util.Log +import android.webkit.JavascriptInterface +import android.webkit.WebResourceRequest +import android.webkit.WebView +import android.webkit.WebViewClient +import android.widget.TextView +import androidx.annotation.RequiresApi +import androidx.appcompat.app.AppCompatActivity +import de.blinkt.openvpn.R +import de.blinkt.openvpn.VpnProfile +import org.json.JSONObject + +class InternalWebView : AppCompatActivity() { + + lateinit var webView: WebView + lateinit var urlTextView: TextView + + @SuppressLint("SetJavaScriptEnabled") + override fun onCreate(savedInstanceState: Bundle?) { + + super.onCreate(savedInstanceState) + setContentView(R.layout.webview_internal) + + webView = findViewById(R.id.internal_webview) + urlTextView = findViewById(R.id.url_textview) + + + if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN_MR1) + attachMessageHandler() + + webView.loadUrl(intent.data.toString()) + + webView.settings.javaScriptEnabled = true + webView.settings.userAgentString = VpnProfile.getVersionEnvString(this) + + webView.webViewClient = object: WebViewClient() { + @RequiresApi(Build.VERSION_CODES.LOLLIPOP) + override fun shouldOverrideUrlLoading(view: WebView?, request: WebResourceRequest?): Boolean { + urlTextView.text = request?.url?.toString(); + return super.shouldOverrideUrlLoading(view, request) + } + + } + urlTextView.text = intent.data.toString() + + setTitle(R.string.internal_web_view) + + } + + @JavascriptInterface + fun postMessage(json: String?, transferList: String?): Boolean { + val jObejct = JSONObject(json) + + val action = jObejct.getString("type") + Log.i("OpenVPN,InternalWebview", json + " ---- " + transferList) + + if (action == "ACTION_REQUIRED") { + // Should show the hidden webview, nothing for us to do + return true + } + + if (action == "CONNECT_SUCCESS" || action == "CONNECT_FAILED") { + runOnUiThread({finish()}) + } + + /* runOnUiThread({ + Toast.makeText(this, json + " ---- " + transferList, Toast.LENGTH_LONG).show() + }) */ + return true + } + + + @TargetApi(Build.VERSION_CODES.JELLY_BEAN_MR1) + private fun attachMessageHandler() { + webView.addJavascriptInterface(this, "appEvent") + } + + override fun onResume() { + super.onResume() + + } + + override fun onNewIntent(intent: Intent?) { + super.onNewIntent(intent) + + } +}
\ No newline at end of file diff --git a/main/src/ui/java/de/blinkt/openvpn/core/VariantConfig.java b/main/src/ui/java/de/blinkt/openvpn/core/VariantConfig.java new file mode 100644 index 00000000..5db8382c --- /dev/null +++ b/main/src/ui/java/de/blinkt/openvpn/core/VariantConfig.java @@ -0,0 +1,18 @@ +/* + * Copyright (c) 2012-2020 Arne Schwabe + * Distributed under the GNU GPL v2 with additional terms. For full terms see the file doc/LICENSE.txt + */ + +package de.blinkt.openvpn.core; + +import android.content.Context; +import android.content.Intent; + +import de.blinkt.openvpn.activities.InternalWebView; + +public class VariantConfig { + /** Return the normal webview or internal webview depending what is available */ + static Intent getOpenUrlIntent(Context c) { + return new Intent(c, InternalWebView.class); + } +} diff --git a/main/src/ui/java/de/blinkt/openvpn/fragments/VPNProfileList.java b/main/src/ui/java/de/blinkt/openvpn/fragments/VPNProfileList.java index 629d65da..3804926f 100644 --- a/main/src/ui/java/de/blinkt/openvpn/fragments/VPNProfileList.java +++ b/main/src/ui/java/de/blinkt/openvpn/fragments/VPNProfileList.java @@ -60,6 +60,7 @@ import de.blinkt.openvpn.core.VpnStatus; import static de.blinkt.openvpn.core.ConnectionStatus.LEVEL_WAITING_FOR_USER_INPUT; import static de.blinkt.openvpn.core.OpenVPNService.DISCONNECT_VPN; +import static de.blinkt.openvpn.core.OpenVPNService.EXTRA_CHALLENGE_TXT; public class VPNProfileList extends ListFragment implements OnClickListener, VpnStatus.StateListener { @@ -80,23 +81,28 @@ public class VPNProfileList extends ListFragment implements OnClickListener, Vpn protected VpnProfile mEditProfile = null; private String mLastStatusMessage; private ArrayAdapter<VpnProfile> mArrayadapter; + private Intent mLastIntent; @Override public void updateState(String state, String logmessage, final int localizedResId, ConnectionStatus level, Intent intent) { requireActivity().runOnUiThread(() -> { mLastStatusMessage = VpnStatus.getLastCleanLogMessage(getActivity()); + mLastIntent = intent; mArrayadapter.notifyDataSetChanged(); showUserRequestDialogIfNeeded(level, intent); }); } - private void showUserRequestDialogIfNeeded(ConnectionStatus level, Intent intent) { + private boolean showUserRequestDialogIfNeeded(ConnectionStatus level, Intent intent) { if (level == LEVEL_WAITING_FOR_USER_INPUT) { - PasswordDialogFragment pwInputFrag = PasswordDialogFragment.Companion.newInstance(intent, false); - - pwInputFrag.show(requireFragmentManager(), "dialog"); + if (intent.getStringExtra(EXTRA_CHALLENGE_TXT) != null) { + PasswordDialogFragment pwInputFrag = PasswordDialogFragment.Companion.newInstance(intent, false); + pwInputFrag.show(getParentFragmentManager(), "dialog"); + return true; + } } + return false; } @Override @@ -105,8 +111,12 @@ public class VPNProfileList extends ListFragment implements OnClickListener, Vpn private void startOrStopVPN(VpnProfile profile) { if (VpnStatus.isVPNActive() && profile.getUUIDString().equals(VpnStatus.getLastConnectedVPNProfile())) { - Intent disconnectVPN = new Intent(getActivity(), DisconnectVPN.class); - startActivity(disconnectVPN); + if (mLastIntent != null) { + startActivity(mLastIntent); + } else { + Intent disconnectVPN = new Intent(getActivity(), DisconnectVPN.class); + startActivity(disconnectVPN); + } } else { startVPN(profile); } @@ -600,14 +610,7 @@ public class VPNProfileList extends ListFragment implements OnClickListener, Vpn }); View settingsview = v.findViewById(R.id.quickedit_settings); - settingsview.setOnClickListener(new OnClickListener() { - - @Override - public void onClick(View v) { - editVPN(profile); - - } - }); + settingsview.setOnClickListener(view -> editVPN(profile)); TextView subtitle = (TextView) v.findViewById(R.id.vpn_item_subtitle); if (profile.getUUIDString().equals(VpnStatus.getLastConnectedVPNProfile())) { diff --git a/main/src/ui/res/layout/webview_internal.xml b/main/src/ui/res/layout/webview_internal.xml new file mode 100644 index 00000000..f1bf17c8 --- /dev/null +++ b/main/src/ui/res/layout/webview_internal.xml @@ -0,0 +1,24 @@ +<?xml version="1.0" encoding="utf-8"?><!-- + ~ Copyright (c) 2012-2020 Arne Schwabe + ~ Distributed under the GNU GPL v2 with additional terms. For full terms see the file doc/LICENSE.txt + --> + +<LinearLayout android:layout_height="match_parent" + android:layout_width="match_parent" + xmlns:tools="http://schemas.android.com/tools" + android:orientation="vertical" + xmlns:android="http://schemas.android.com/apk/res/android"> + + <TextView + android:id="@+id/url_textview" + android:layout_width="match_parent" + android:layout_height="wrap_content" + tools:text="https://foo.bar.baz" /> + + <WebView + android:id="@+id/internal_webview" + android:layout_width="match_parent" + android:layout_height="match_parent" + /> + +</LinearLayout> |