diff options
Diffstat (limited to 'main/src/main')
115 files changed, 1468 insertions, 434 deletions
diff --git a/main/src/main/AndroidManifest.xml b/main/src/main/AndroidManifest.xml index 61d96c4b..ab8654b5 100644 --- a/main/src/main/AndroidManifest.xml +++ b/main/src/main/AndroidManifest.xml @@ -1,13 +1,14 @@ <?xml version="1.0" encoding="utf-8"?> <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"> <uses-permission android:name="android.permission.INTERNET" /> <uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" /> <uses-permission android:name="android.permission.RECEIVE_BOOT_COMPLETED" /> <uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" /> <uses-permission android:name="android.permission.FOREGROUND_SERVICE" /> + <uses-permission android:name="android.permission.POST_NOTIFICATIONS" /> + <uses-permission android:name="android.permission.FOREGROUND_SERVICE_SPECIAL_USE" /> <!-- Used to show all apps in the allowed Apps selection, this app needs the list the app in the allow/deny apps over the VPN --> @@ -28,8 +29,8 @@ android:name=".core.ICSOpenVPNApplication" android:allowBackup="true" android:appCategory="productivity" - android:extractNativeLibs="true" android:icon="@mipmap/ic_launcher" + android:roundIcon="@mipmap/ic_launcher_round" android:label="@string/app" android:supportsRtl="true" android:theme="@style/blinkt" @@ -51,11 +52,13 @@ android:name=".core.OpenVPNService" android:exported="true" android:permission="android.permission.BIND_VPN_SERVICE" - android:foregroundServiceType="connectedDevice" + android:foregroundServiceType="specialUse" android:process=":openvpn"> <intent-filter> <action android:name="android.net.VpnService" /> </intent-filter> + <property android:name="android.app.PROPERTY_SPECIAL_USE_FGS_SUBTYPE" android:value="vpn"/> + </service> <service android:name=".api.ExternalOpenVPNService" @@ -92,6 +95,11 @@ </intent-filter> </receiver> + <service android:name=".core.keepVPNAlive" + android:process=":openvpn" + android:exported="true" + android:permission="android.permission.BIND_JOB_SERVICE"/> + <activity android:name=".LaunchVPN" @@ -115,7 +123,14 @@ </intent-filter> </receiver> --> - <activity android:name=".api.RemoteAction" /> + <activity android:name=".api.RemoteAction" + android:launchMode="singleInstance" + android:autoRemoveFromRecents="true" + android:excludeFromRecents="true" + android:taskAffinity=".LaunchVPN" + android:theme="@style/blinkt.dialog" + android:noHistory="true" + /> <activity-alias android:name=".api.ConnectVPN" diff --git a/main/src/main/assets/full_licenses.html b/main/src/main/assets/full_licenses.html index a32190df..fd87dd49 100644 --- a/main/src/main/assets/full_licenses.html +++ b/main/src/main/assets/full_licenses.html @@ -167,120 +167,209 @@ DEALINGS IN THE SOFTWARE. <p>END OF TERMS AND CONDITIONS</p> <h2 id="#openssl">OpenSSL</h2> -<p> The OpenSSL toolkit stays under a dual license, i.e. both the conditions of - the OpenSSL License and the original SSLeay license apply to the toolkit. - See below for the actual license texts. Actually both licenses are BSD-style - Open Source licenses. In case of any license issues related to OpenSSL - please contact openssl-core@openssl.org.</p> - -<p>/* ==================================================================== -<br> * Copyright (c) 1998-2003 The OpenSSL Project. All rights reserved. -<br> * -<br>* Redistribution and use in source and binary forms, with or without -<br> * modification, are permitted provided that the following conditions -<br> * are met: -<br> * -<br> * 1. Redistributions of source code must retain the above copyright -<br> * notice, this list of conditions and the following disclaimer. -<br> * -<br> * 2. Redistributions in binary form must reproduce the above copyright -<br> * notice, this list of conditions and the following disclaimer in -<br> * the documentation and/or other materials provided with the -<br> * distribution. -<br> * -<br> * 3. All advertising materials mentioning features or use of this -<br> * software must display the following acknowledgment: -<br> * "This product includes software developed by the OpenSSL Project -<br> * for use in the OpenSSL Toolkit. (http://www.openssl.org/)" -<br> * -<br> * 4. The names "OpenSSL Toolkit" and "OpenSSL Project" must not be used to -<br> * endorse or promote products derived from this software without -<br> * prior written permission. For written permission, please contact -<br> * openssl-core@openssl.org. -<br> * -<br> * 5. Products derived from this software may not be called "OpenSSL" -<br> * nor may "OpenSSL" appear in their names without prior written -<br> * permission of the OpenSSL Project. -<br> * -<br> * 6. Redistributions of any form whatsoever must retain the following -<br> * acknowledgment: -<br> * "This product includes software developed by the OpenSSL Project -<br> * for use in the OpenSSL Toolkit (http://www.openssl.org/)" -<br> * -<br> * THIS SOFTWARE IS PROVIDED BY THE OpenSSL PROJECT ``AS IS'' AND ANY -<br> * EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE -<br> * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR -<br> * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE OpenSSL PROJECT OR -<br> * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, -<br> * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT -<br> * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; -<br> * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) -<br> * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, -<br> * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) -<br> * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED -<br> * OF THE POSSIBILITY OF SUCH DAMAGE. -<br> * ==================================================================== -<br> * -<br> * This product includes cryptographic software written by Eric Young -<br> * (eay@cryptsoft.com). This product includes software written by Tim -<br> * Hudson (tjh@cryptsoft.com). -<br> * -<br> */ - -<h3> Original SSLeay License</h3> -<br> /* Copyright (C) 1995-1998 Eric Young (eay@cryptsoft.com) -<br> * All rights reserved. -<br> * -<br> * This package is an SSL implementation written -<br> * by Eric Young (eay@cryptsoft.com). -<br> * The implementation was written so as to conform with Netscapes SSL. -<br> * -<br> * This library is free for commercial and non-commercial use as long as -<br> * the following conditions are aheared to. The following conditions -<br> * apply to all code found in this distribution, be it the RC4, RSA, -<br> * lhash, DES, etc., code; not just the SSL code. The SSL documentation -<br> * included with this distribution is covered by the same copyright terms -<br> * except that the holder is Tim Hudson (tjh@cryptsoft.com). -<br> * -<br> * Copyright remains Eric Young's, and as such any Copyright notices in -<br> * the code are not to be removed. -<br> * If this package is used in a product, Eric Young should be given attribution -<br> * as the author of the parts of the library used. -<br> * This can be in the form of a textual message at program startup or -<br> * in documentation (online or textual) provided with the package. -<br> * -<br> * Redistribution and use in source and binary forms, with or without -<br> * modification, are permitted provided that the following conditions -<br> * are met: -<br> * 1. Redistributions of source code must retain the copyright -<br> * notice, this list of conditions and the following disclaimer. -<br> * 2. Redistributions in binary form must reproduce the above copyright -<br> * notice, this list of conditions and the following disclaimer in the -<br> * documentation and/or other materials provided with the distribution. -<br> * 3. All advertising materials mentioning features or use of this software -<br> * must display the following acknowledgement: -<br> * "This product includes cryptographic software written by -<br> * Eric Young (eay@cryptsoft.com)" -<br> * The word 'cryptographic' can be left out if the rouines from the library -<br> * being used are not cryptographic related :-). -<br> * 4. If you include any Windows specific code (or a derivative thereof) from -<br> * the apps directory (application code) you must include an acknowledgement: -<br> * "This product includes software written by Tim Hudson (tjh@cryptsoft.com)" -<br> * -<br> * THIS SOFTWARE IS PROVIDED BY ERIC YOUNG ``AS IS'' AND -<br> * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE -<br> * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE -<br> * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE -<br> * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL -<br> * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS -<br> * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) -<br> * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT -<br> * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY -<br> * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF -<br> * SUCH DAMAGE. -<br> * -<br> * The licence and distribution terms for any publically available version or -<br> * derivative of this code cannot be changed. i.e. this code cannot simply be -<br> * copied and put under another distribution licence -<br> * [including the GNU Public Licence.] -<br> */ +<p> + + Apache License +</p> +<p></p> Version 2.0, January 2004</p> +<p></p>https://www.apache.org/licenses/</p> + +<p><strong> TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION</strong></p> +<p><strong>1.</strong> Definitions. +</p> +<p> + "License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. +</p> +<p> + "Licensor" shall mean the copyright owner or entity authorized by + the copyright owner that is granting the License. +</p> +<p> + "Legal Entity" shall mean the union of the acting entity and all + other entities that control, are controlled by, or are under common + control with that entity. For the purposes of this definition, + "control" means (i) the power, direct or indirect, to cause the + direction or management of such entity, whether by contract or + otherwise, or (ii) ownership of fifty percent (50%) or more of the + outstanding shares, or (iii) beneficial ownership of such entity. +</p> +<p> + "You" (or "Your") shall mean an individual or Legal Entity + exercising permissions granted by this License. +</p> +<p> + "Source" form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation + source, and configuration files. +</p> +<p> + "Object" form shall mean any form resulting from mechanical + transformation or translation of a Source form, including but + not limited to compiled object code, generated documentation, + and conversions to other media types. +</p> +<p> + "Work" shall mean the work of authorship, whether in Source or + Object form, made available under the License, as indicated by a + copyright notice that is included in or attached to the work + (an example is provided in the Appendix below). +</p> +<p> + "Derivative Works" shall mean any work, whether in Source or Object + form, that is based on (or derived from) the Work and for which the + editorial revisions, annotations, elaborations, or other modifications + represent, as a whole, an original work of authorship. For the purposes + of this License, Derivative Works shall not include works that remain + separable from, or merely link (or bind by name) to the interfaces of, + the Work and Derivative Works thereof. +</p> +<p> + "Contribution" shall mean any work of authorship, including + the original version of the Work and any modifications or additions + to that Work or Derivative Works thereof, that is intentionally + submitted to Licensor for inclusion in the Work by the copyright owner + or by an individual or Legal Entity authorized to submit on behalf of + the copyright owner. For the purposes of this definition, "submitted" + means any form of electronic, verbal, or written communication sent + to the Licensor or its representatives, including but not limited to + communication on electronic mailing lists, source code control systems, + and issue tracking systems that are managed by, or on behalf of, the + Licensor for the purpose of discussing and improving the Work, but + excluding communication that is conspicuously marked or otherwise + designated in writing by the copyright owner as "Not a Contribution." +</p> +<p> + "Contributor" shall mean Licensor and any individual or Legal Entity + on behalf of whom a Contribution has been received by Licensor and + subsequently incorporated within the Work. +</p> +<p> + <strong>2.</strong> Grant of Copyright License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + copyright license to reproduce, prepare Derivative Works of, + publicly display, publicly perform, sublicense, and distribute the + Work and such Derivative Works in Source or Object form. +</p> +<p> + <strong>3.</strong> Grant of Patent License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + (except as stated in this section) patent license to make, have made, + use, offer to sell, sell, import, and otherwise transfer the Work, + where such license applies only to those patent claims licensable + by such Contributor that are necessarily infringed by their + Contribution(s) alone or by combination of their Contribution(s) + with the Work to which such Contribution(s) was submitted. If You + institute patent litigation against any entity (including a + cross-claim or counterclaim in a lawsuit) alleging that the Work + or a Contribution incorporated within the Work constitutes direct + or contributory patent infringement, then any patent licenses + granted to You under this License for that Work shall terminate + as of the date such litigation is filed. +</p> +<p> + + <strong>4.</strong> Redistribution. You may reproduce and distribute copies of the + Work or Derivative Works thereof in any medium, with or without + modifications, and in Source or Object form, provided that You + meet the following conditions: +</p> +<p> + <strong>(a)</strong> You must give any other recipients of the Work or + Derivative Works a copy of this License; and +</p> +<p> + <strong>(b)</strong> You must cause any modified files to carry prominent notices + stating that You changed the files; and +</p> +<p> + <strong>(c)</strong> You must retain, in the Source form of any Derivative Works + that You distribute, all copyright, patent, trademark, and + attribution notices from the Source form of the Work, + excluding those notices that do not pertain to any part of + the Derivative Works; and +</p> +<p> + <strong>(d)</strong> If the Work includes a "NOTICE" text file as part of its + distribution, then any Derivative Works that You distribute must + include a readable copy of the attribution notices contained + within such NOTICE file, excluding those notices that do not + pertain to any part of the Derivative Works, in at least one + of the following places: within a NOTICE text file distributed + as part of the Derivative Works; within the Source form or + documentation, if provided along with the Derivative Works; or, + within a display generated by the Derivative Works, if and + wherever such third-party notices normally appear. The contents + of the NOTICE file are for informational purposes only and + do not modify the License. You may add Your own attribution + notices within Derivative Works that You distribute, alongside + or as an addendum to the NOTICE text from the Work, provided + that such additional attribution notices cannot be construed + as modifying the License. +</p> +<p> + You may add Your own copyright statement to Your modifications and + may provide additional or different license terms and conditions + for use, reproduction, or distribution of Your modifications, or + for any such Derivative Works as a whole, provided Your use, + reproduction, and distribution of the Work otherwise complies with + the conditions stated in this License. +</p> +<p> + + <strong>5.</strong> Submission of Contributions. Unless You explicitly state otherwise, + any Contribution intentionally submitted for inclusion in the Work + by You to the Licensor shall be under the terms and conditions of + this License, without any additional terms or conditions. + Notwithstanding the above, nothing herein shall supersede or modify + the terms of any separate license agreement you may have executed + with Licensor regarding such Contributions. +</p> +<p> + <strong>6.</strong> Trademarks. This License does not grant permission to use the trade + names, trademarks, service marks, or product names of the Licensor, + except as required for reasonable and customary use in describing the + origin of the Work and reproducing the content of the NOTICE file. +</p> +<p> + + <strong>7.</strong> Disclaimer of Warranty. Unless required by applicable law or + agreed to in writing, Licensor provides the Work (and each + Contributor provides its Contributions) on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied, including, without limitation, any warranties or conditions + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + PARTICULAR PURPOSE. You are solely responsible for determining the + appropriateness of using or redistributing the Work and assume any + risks associated with Your exercise of permissions under this License. +</p> +<p> + + <strong>8.</strong> Limitation of Liability. In no event and under no legal theory, + whether in tort (including negligence), contract, or otherwise, + unless required by applicable law (such as deliberate and grossly + negligent acts) or agreed to in writing, shall any Contributor be + liable to You for damages, including any direct, indirect, special, + incidental, or consequential damages of any character arising as a + result of this License or out of the use or inability to use the + Work (including but not limited to damages for loss of goodwill, + work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses), even if such Contributor + has been advised of the possibility of such damages. +</p> +<p> + + <strong>9.</strong> Accepting Warranty or Additional Liability. While redistributing + the Work or Derivative Works thereof, You may choose to offer, + and charge a fee for, acceptance of support, warranty, indemnity, + or other liability obligations and/or rights consistent with this + License. However, in accepting such obligations, You may act only + on Your own behalf and on Your sole responsibility, not on behalf + of any other Contributor, and only if You agree to indemnify, + defend, and hold each Contributor harmless for any liability + incurred by, or claims asserted against, such Contributor by reason + of your accepting any such warranty or additional liability. + </ol> + END OF TERMS AND CONDITIONS diff --git a/main/src/main/cpp/CMakeLists.txt b/main/src/main/cpp/CMakeLists.txt index 5347d049..fae64f33 100644 --- a/main/src/main/cpp/CMakeLists.txt +++ b/main/src/main/cpp/CMakeLists.txt @@ -1,4 +1,5 @@ cmake_minimum_required(VERSION 3.4.1) +project("ics-openvpn") # Git version string include(GetGitRevisionDescription.cmake) @@ -92,7 +93,7 @@ include(openssl/openssl.cmake) # -DHAVE_LZ4 # -DASIO_STANDALONE # -DUSE_ASIO - # -DGIT_VERSION_STRING=\"${OPENVPN3_GIT}\" + # -DOPENVPN_CORE_GIT_VERSION=\"${OPENVPN3_GIT}\" # -DOPENVPN_SHOW_SESSION_TOKEN # -DOPENSSL_API_COMPAT=0x10200000L # -DOPENVPN_ALLOW_INSECURE_CERTPROFILE @@ -109,8 +110,8 @@ target_compile_definitions(ovpnutil PRIVATE -DTARGET_ARCH_ABI=\"${ANDROID_ABI}\" ) target_link_libraries(ovpnutil log) -#add_library(rsapss SHARED ovpnutil/rsapss.cpp) -#target_link_libraries(rsapss log crypto ssl) +#add_library(osslutil SHARED ovpnutil/osslutil.cpp) +#target_link_libraries(osslutil log crypto ssl) #if (NOT ${CMAKE_LIBRARY_OUTPUT_DIRECTORY} MATCHES "build/intermediates/cmake/.*skeleton.*/") # message("Building SSLSpeedTest for output dir ${CMAKE_LIBRARY_OUTPUT_DIRECTORY}") @@ -167,6 +168,7 @@ set(openvpn_srcs src/openvpn/occ.c src/openvpn/openvpn.c src/openvpn/options.c + src/openvpn/options_util.c src/openvpn/otime.c src/openvpn/packet_id.c src/openvpn/perf.c @@ -180,6 +182,7 @@ set(openvpn_srcs src/openvpn/proxy.c src/openvpn/ps.c src/openvpn/push.c + src/openvpn/reflect_filter.c src/openvpn/reliable.c src/openvpn/route.c src/openvpn/run_command.c diff --git a/main/src/main/cpp/asio b/main/src/main/cpp/asio -Subproject 4915cfd8a1653c157a1480162ae5601318553eb +Subproject 1f8d154829b902dbc45a651587c6c6df948358e diff --git a/main/src/main/cpp/lz4 b/main/src/main/cpp/lz4 -Subproject d44371841a2f1728a3f36839fd4b7e872d0927d +Subproject 5ff839680134437dbf4678f3d0c7b371d84f496 diff --git a/main/src/main/cpp/openssl b/main/src/main/cpp/openssl -Subproject 5a6a7d0c955b168ccaecbd16d5a8ae4d20304ff +Subproject bf2a6facba08b980a00f2f2c4e46487471b17f6 diff --git a/main/src/main/cpp/openvpn b/main/src/main/cpp/openvpn -Subproject 7e5f410745eeda7d08d83445429ecd70035b730 +Subproject a80f21b133ebf10bc3c36577fedef024c6ed303 diff --git a/main/src/main/cpp/openvpn-config/config.h b/main/src/main/cpp/openvpn-config/config.h index ca33c91e..989e439a 100644 --- a/main/src/main/cpp/openvpn-config/config.h +++ b/main/src/main/cpp/openvpn-config/config.h @@ -21,27 +21,15 @@ /* Use dmalloc memory debugging library */ /* #undef DMALLOC */ -/* Dimension to use for empty array declaration */ -#define EMPTY_ARRAY_SIZE 0 - -/* Enable client capability only */ -#define ENABLE_CLIENT_ONLY 1 - /* Enable debugging support */ #define ENABLE_DEBUG 1 /* Enable internal fragmentation support */ #define ENABLE_FRAGMENT 1 -/* Enable HTTP proxy support */ -#define ENABLE_HTTP_PROXY 1 - /* Enable management server capability */ #define ENABLE_MANAGEMENT 1 -/* Enable multi-homed UDP server capability */ -#define ENABLE_MULTIHOME 0 - /* Allow --askpass and --auth-user-pass passwords to be read from a file */ #define ENABLE_PASSWORD_SAVE 1 @@ -450,13 +438,13 @@ #define PACKAGE_NAME "OpenVPN" /* Define to the full name and version of this package. */ -#define PACKAGE_STRING "OpenVPN 2.6-icsopenvpn" +#define PACKAGE_STRING "OpenVPN 2.7-icsopenvpn" /* Define to the one symbol short name of this package. */ #define PACKAGE_TARNAME "openvpn" /* Define to the version of this package. */ -#define PACKAGE_VERSION "2.6_master" +#define PACKAGE_VERSION "2.7_master" /* Define to the necessary symbol if this constant uses a non-standard name on your system. */ diff --git a/main/src/main/cpp/openvpn3 b/main/src/main/cpp/openvpn3 -Subproject a6296185ec5d6f604ed2c66a3e1c81ff99e387f +Subproject f159710100e1442c7354b4f24cbfe742abc8c89 diff --git a/main/src/main/cpp/ovpnutil/jniglue.c b/main/src/main/cpp/ovpnutil/jniglue.c index 65a13406..b70deac0 100644 --- a/main/src/main/cpp/ovpnutil/jniglue.c +++ b/main/src/main/cpp/ovpnutil/jniglue.c @@ -3,7 +3,6 @@ #include <stdlib.h> #include <unistd.h> - #include "jniglue.h" jint JNI_OnLoad(JavaVM *vm, void *reserved) { @@ -37,4 +36,4 @@ jstring Java_de_blinkt_openvpn_core_NativeUtils_getOpenVPN3GitVersion(JNIEnv *en { return (*env)->NewStringUTF(env, OPENVPN3_GIT_REVISION); -} +}
\ No newline at end of file diff --git a/main/src/main/cpp/ovpnutil/rsapss.cpp b/main/src/main/cpp/ovpnutil/osslutil.cpp index 112c2fe4..6a33338e 100644 --- a/main/src/main/cpp/ovpnutil/rsapss.cpp +++ b/main/src/main/cpp/ovpnutil/osslutil.cpp @@ -13,9 +13,16 @@ #include <openssl/evp.h> #include <openssl/rand.h> #include <openssl/rsa.h> +#include <openssl/opensslv.h> #include <array> + +extern "C" jstring Java_de_blinkt_openvpn_core_NativeUtils_getOpenSSLVersionString(JNIEnv *env, jclass jo) +{ + return env->NewStringUTF(OPENSSL_VERSION_TEXT); +} + static const unsigned char zeroes[] = {0, 0, 0, 0, 0, 0, 0, 0}; static char opensslerr[1024]; diff --git a/main/src/main/java/de/blinkt/openvpn/LaunchVPN.java b/main/src/main/java/de/blinkt/openvpn/LaunchVPN.java index 86eef35a..90ea053a 100644 --- a/main/src/main/java/de/blinkt/openvpn/LaunchVPN.java +++ b/main/src/main/java/de/blinkt/openvpn/LaunchVPN.java @@ -73,6 +73,7 @@ public class LaunchVPN extends Activity { public static final String EXTRA_KEY = "de.blinkt.openvpn.shortcutProfileUUID"; public static final String EXTRA_NAME = "de.blinkt.openvpn.shortcutProfileName"; public static final String EXTRA_HIDELOG = "de.blinkt.openvpn.showNoLogWindow"; + public static final String EXTRA_START_REASON = "de.blinkt.openvpn.start_reason"; public static final String CLEARLOG = "clearlogconnect"; @@ -85,6 +86,7 @@ public class LaunchVPN extends Activity { private boolean mCmfixed = false; private String mTransientAuthPW; private String mTransientCertOrPCKS12PW; + private String mSelectedProfileReason; @Override public void onCreate(Bundle icicle) { @@ -99,7 +101,6 @@ public class LaunchVPN extends Activity { IServiceStatus service = IServiceStatus.Stub.asInterface(binder); try { if (mTransientAuthPW != null) - service.setCachedPassword(mSelectedProfile.getUUIDString(), PasswordCache.AUTHPASSWORD, mTransientAuthPW); if (mTransientCertOrPCKS12PW != null) service.setCachedPassword(mSelectedProfile.getUUIDString(), PasswordCache.PCKS12ORCERTPASSWORD, mTransientCertOrPCKS12PW); @@ -126,38 +127,41 @@ public class LaunchVPN extends Activity { final String action = intent.getAction(); // If the intent is a request to create a shortcut, we'll do that and exit + if (!Intent.ACTION_MAIN.equals(action)) { + return; + } + // Check if we need to clear the log + if (Preferences.getDefaultSharedPreferences(this).getBoolean(CLEARLOG, true)) + VpnStatus.clearLog(); - if (Intent.ACTION_MAIN.equals(action)) { - // Check if we need to clear the log - if (Preferences.getDefaultSharedPreferences(this).getBoolean(CLEARLOG, true)) - VpnStatus.clearLog(); - - // we got called to be the starting point, most likely a shortcut - String shortcutUUID = intent.getStringExtra(EXTRA_KEY); - String shortcutName = intent.getStringExtra(EXTRA_NAME); - mhideLog = intent.getBooleanExtra(EXTRA_HIDELOG, false); + // we got called to be the starting point, most likely a shortcut + String shortcutUUID = intent.getStringExtra(EXTRA_KEY); + String shortcutName = intent.getStringExtra(EXTRA_NAME); + String startReason = intent.getStringExtra(EXTRA_START_REASON); + mhideLog = intent.getBooleanExtra(EXTRA_HIDELOG, false); - VpnProfile profileToConnect = ProfileManager.get(this, shortcutUUID); - if (shortcutName != null && profileToConnect == null) { - profileToConnect = ProfileManager.getInstance(this).getProfileByName(shortcutName); - if (!(new ExternalAppDatabase(this).checkRemoteActionPermission(this, getCallingPackage()))) { - finish(); - return; - } + VpnProfile profileToConnect = ProfileManager.get(this, shortcutUUID); + if (shortcutName != null && profileToConnect == null) { + profileToConnect = ProfileManager.getInstance(this).getProfileByName(shortcutName); + if (!(new ExternalAppDatabase(this).checkRemoteActionPermission(this, getCallingPackage()))) { + finish(); + return; } + } - if (profileToConnect == null) { - VpnStatus.logError(R.string.shortcut_profile_notfound); - // show Log window to display error - showLogWindow(); - finish(); - } else { - mSelectedProfile = profileToConnect; - launchVPN(); - } + if (profileToConnect == null) { + VpnStatus.logError(R.string.shortcut_profile_notfound); + // show Log window to display error + showLogWindow(); + finish(); + } else { + mSelectedProfile = profileToConnect; + mSelectedProfileReason = startReason; + launchVPN(); } + } private void askForPW(final int type) { @@ -251,7 +255,7 @@ public class LaunchVPN extends Activity { if (!mhideLog && showLogWindow) showLogWindow(); ProfileManager.updateLRU(this, mSelectedProfile); - VPNLaunchHelper.startOpenVpn(mSelectedProfile, getBaseContext()); + VPNLaunchHelper.startOpenVpn(mSelectedProfile, getBaseContext(), mSelectedProfileReason); finish(); } } else if (resultCode == Activity.RESULT_CANCELED) { diff --git a/main/src/main/java/de/blinkt/openvpn/OnBootReceiver.java b/main/src/main/java/de/blinkt/openvpn/OnBootReceiver.java index ebfab5b2..58c954c9 100644 --- a/main/src/main/java/de/blinkt/openvpn/OnBootReceiver.java +++ b/main/src/main/java/de/blinkt/openvpn/OnBootReceiver.java @@ -12,12 +12,10 @@ import android.content.SharedPreferences; import de.blinkt.openvpn.core.Preferences; import de.blinkt.openvpn.core.ProfileManager; +import de.blinkt.openvpn.core.VPNLaunchHelper; public class OnBootReceiver extends BroadcastReceiver { - - - // Debug: am broadcast -a android.intent.action.BOOT_COMPLETED @Override public void onReceive(Context context, Intent intent) { @@ -25,8 +23,8 @@ public class OnBootReceiver extends BroadcastReceiver { final String action = intent.getAction(); SharedPreferences prefs = Preferences.getDefaultSharedPreferences(context); - boolean useStartOnBoot = prefs.getBoolean("restartvpnonboot", false); - if (!useStartOnBoot) + boolean alwaysActive = prefs.getBoolean("restartvpnonboot", false); + if (!alwaysActive) return; if(Intent.ACTION_BOOT_COMPLETED.equals(action) || Intent.ACTION_MY_PACKAGE_REPLACED.equals(action)) { @@ -38,12 +36,6 @@ public class OnBootReceiver extends BroadcastReceiver { } void launchVPN(VpnProfile profile, Context context) { - Intent startVpnIntent = new Intent(Intent.ACTION_MAIN); - startVpnIntent.setClass(context, LaunchVPN.class); - startVpnIntent.putExtra(LaunchVPN.EXTRA_KEY,profile.getUUIDString()); - startVpnIntent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK); - startVpnIntent.putExtra(LaunchVPN.EXTRA_HIDELOG, true); - - context.startActivity(startVpnIntent); + VPNLaunchHelper.startOpenVpn(profile, context.getApplicationContext(), "on Boot receiver"); } } diff --git a/main/src/main/java/de/blinkt/openvpn/VpnProfile.java b/main/src/main/java/de/blinkt/openvpn/VpnProfile.java index 3163bf27..0da09eb0 100644 --- a/main/src/main/java/de/blinkt/openvpn/VpnProfile.java +++ b/main/src/main/java/de/blinkt/openvpn/VpnProfile.java @@ -809,18 +809,6 @@ public class VpnProfile implements Serializable, Cloneable { return parts[0] + " " + netmask; } - public Intent prepareStartService(Context context) { - Intent intent = getStartServiceIntent(context); - - // TODO: Handle this?! -// if (mAuthenticationType == VpnProfile.TYPE_KEYSTORE || mAuthenticationType == VpnProfile.TYPE_USERPASS_KEYSTORE) { -// if (getKeyStoreCertificates(context) == null) -// return null; -// } - - return intent; - } - public void writeConfigFileOutput(Context context, OutputStream out) throws IOException { OutputStreamWriter cfg = new OutputStreamWriter(out); cfg.write(getConfigFile(context, false)); @@ -828,12 +816,14 @@ public class VpnProfile implements Serializable, Cloneable { cfg.close(); } - public Intent getStartServiceIntent(Context context) { + public Intent getStartServiceIntent(Context context, String startReason) { String prefix = context.getPackageName(); Intent intent = new Intent(context, OpenVPNService.class); intent.putExtra(prefix + ".profileUUID", mUuid.toString()); intent.putExtra(prefix + ".profileVersion", mVersion); + if (startReason != null) + intent.putExtra(prefix + ".startReason", startReason); return intent; } diff --git a/main/src/main/java/de/blinkt/openvpn/activities/DisconnectVPN.java b/main/src/main/java/de/blinkt/openvpn/activities/DisconnectVPN.java index 01dacfcd..6cc170fa 100644 --- a/main/src/main/java/de/blinkt/openvpn/activities/DisconnectVPN.java +++ b/main/src/main/java/de/blinkt/openvpn/activities/DisconnectVPN.java @@ -27,7 +27,7 @@ import de.blinkt.openvpn.core.VpnStatus; */ public class DisconnectVPN extends Activity implements DialogInterface.OnClickListener, DialogInterface.OnCancelListener { private IOpenVPNServiceInternal mService; - private ServiceConnection mConnection = new ServiceConnection() { + private final ServiceConnection mConnection = new ServiceConnection() { @@ -86,6 +86,7 @@ public class DisconnectVPN extends Activity implements DialogInterface.OnClickLi } else if (which == DialogInterface.BUTTON_NEUTRAL) { Intent intent = new Intent(this, LaunchVPN.class); intent.putExtra(LaunchVPN.EXTRA_KEY, VpnStatus.getLastConnectedVPNProfile()); + intent.putExtra(LaunchVPN.EXTRA_START_REASON, "Reconnect button pressed."); intent.setAction(Intent.ACTION_MAIN); startActivity(intent); } diff --git a/main/src/main/java/de/blinkt/openvpn/api/AppRestrictions.java b/main/src/main/java/de/blinkt/openvpn/api/AppRestrictions.java index 175ecb70..53919216 100644 --- a/main/src/main/java/de/blinkt/openvpn/api/AppRestrictions.java +++ b/main/src/main/java/de/blinkt/openvpn/api/AppRestrictions.java @@ -14,7 +14,7 @@ import android.text.TextUtils; import de.blinkt.openvpn.VpnProfile; import de.blinkt.openvpn.core.ConfigParser; -import de.blinkt.openvpn.core.Connection; +import de.blinkt.openvpn.core.OpenVPNService; import de.blinkt.openvpn.core.Preferences; import de.blinkt.openvpn.core.ProfileManager; import de.blinkt.openvpn.core.VpnStatus; @@ -22,6 +22,7 @@ import de.blinkt.openvpn.core.VpnStatus; import java.io.IOException; import java.io.StringReader; import java.math.BigInteger; +import java.nio.charset.StandardCharsets; import java.security.MessageDigest; import java.security.NoSuchAlgorithmException; import java.util.*; @@ -33,16 +34,15 @@ public class AppRestrictions { final static int CONFIG_VERSION = 1; static boolean alreadyChecked = false; private static AppRestrictions mInstance; - private RestrictionsManager mRestrictionsMgr; private BroadcastReceiver mRestrictionsReceiver; - private AppRestrictions(Context c) { + private AppRestrictions() { } public static AppRestrictions getInstance(Context c) { if (mInstance == null) - mInstance = new AppRestrictions(c); + mInstance = new AppRestrictions(); return mInstance; } @@ -62,11 +62,12 @@ public class AppRestrictions { c.unregisterReceiver(mRestrictionsReceiver); } - private String hashConfig(String config) { + private String hashConfig(String rawconfig) { + String config = prepare(rawconfig); MessageDigest digest; try { digest = MessageDigest.getInstance("SHA1"); - byte utf8_bytes[] = config.getBytes(); + byte[] utf8_bytes = config.getBytes(StandardCharsets.UTF_8); digest.update(utf8_bytes, 0, utf8_bytes.length); return new BigInteger(1, digest.digest()).toString(16); } catch (NoSuchAlgorithmException e) { @@ -76,10 +77,14 @@ public class AppRestrictions { } private void applyRestrictions(Context c) { - mRestrictionsMgr = (RestrictionsManager) c.getSystemService(Context.RESTRICTIONS_SERVICE); - if (mRestrictionsMgr == null) + RestrictionsManager restrictionsMgr = (RestrictionsManager) c.getSystemService(Context.RESTRICTIONS_SERVICE); + if (restrictionsMgr == null) return; - Bundle restrictions = mRestrictionsMgr.getApplicationRestrictions(); + Bundle restrictions = restrictionsMgr.getApplicationRestrictions(); + parseRestrictionsBundle(c, restrictions); + } + public void parseRestrictionsBundle(Context c, Bundle restrictions) + { if (restrictions == null) return; @@ -94,12 +99,57 @@ public class AppRestrictions { VpnStatus.logError(String.format(Locale.US, "App restriction version %s does not match expected version %d", configVersion, CONFIG_VERSION)); return; } - Parcelable[] profileList = restrictions.getParcelableArray(("vpn_configuration_list")); + Parcelable[] profileList = restrictions.getParcelableArray("vpn_configuration_list"); if (profileList == null) { - VpnStatus.logError("App restriction does not contain a profile list (vpn_configuration_list)"); + VpnStatus.logInfo("App restriction does not contain a profile list. Removing previously added profiles. (vpn_configuration_list)"); + profileList = new Parcelable[]{}; + } + + importVPNProfiles(c, restrictions, profileList); + setAllowedRemoteControl(c, restrictions); + + setMiscSettings(c, restrictions); + } + + private void setAllowedRemoteControl(Context c, Bundle restrictions) { + String allowedApps = restrictions.getString("allowed_remote_access", null); + ExternalAppDatabase extapps = new ExternalAppDatabase(c); + + if (allowedApps == null) + { + extapps.setFlagManagedConfiguration(false); return; } + HashSet<String> restrictionApps = new HashSet<>(); + + for (String package_name:allowedApps.split("[, \n\r]")) { + if (!TextUtils.isEmpty(package_name)) { + restrictionApps.add(package_name); + } + } + extapps.setFlagManagedConfiguration(true); + extapps.clearAllApiApps(); + + if(!extapps.getExtAppList().equals(restrictionApps)) + { + extapps.setAllowedApps(restrictionApps); + } + } + + private static void setMiscSettings(Context c, Bundle restrictions) { + SharedPreferences defaultPrefs = Preferences.getDefaultSharedPreferences(c); + + if(restrictions.containsKey("screenoffpausevpn")) + { + boolean pauseVPN = restrictions.getBoolean("screenoffpausevpn"); + SharedPreferences.Editor editor = defaultPrefs.edit(); + editor.putBoolean("screenoff", pauseVPN); + editor.apply(); + } + } + + private void importVPNProfiles(Context c, Bundle restrictions, Parcelable[] profileList) { Set<String> provisionedUuids = new HashSet<>(); String defaultprofile = restrictions.getString("defaultprofile", null); @@ -116,12 +166,19 @@ public class AppRestrictions { String uuid = p.getString("uuid"); String ovpn = p.getString("ovpn"); String name = p.getString("name"); + String certAlias = p.getString("certificate_alias"); - if (uuid == null || ovpn == null || name == null) { + if (TextUtils.isEmpty(uuid) || TextUtils.isEmpty(ovpn) || TextUtils.isEmpty(name)) { VpnStatus.logError("App restriction profile misses uuid, ovpn or name key"); continue; } + /* we always use lower case uuid since Android UUID class will use present + * them that way */ + uuid = uuid.toLowerCase(Locale.US); + if (defaultprofile != null) + defaultprofile = defaultprofile.toLowerCase(Locale.US); + if (uuid.equals(defaultprofile)) defaultprofileProvisioned = true; @@ -134,12 +191,15 @@ public class AppRestrictions { if (vpnProfile != null) { // Profile exists, check if need to update it - if (ovpnHash.equals(vpnProfile.importedProfileHash)) + if (ovpnHash.equals(vpnProfile.importedProfileHash)) { + addCertificateAlias(vpnProfile, certAlias, c); + // not modified skip to next profile continue; - + } } - addProfile(c, ovpn, uuid, name, vpnProfile); + vpnProfile = addProfile(c, ovpn, uuid, name, vpnProfile); + addCertificateAlias(vpnProfile, certAlias, c); } Vector<VpnProfile> profilesToRemove = new Vector<>(); @@ -155,22 +215,79 @@ public class AppRestrictions { pm.removeProfile(c, vp); } + SharedPreferences defaultPrefs = Preferences.getDefaultSharedPreferences(c); + if (!TextUtils.isEmpty(defaultprofile)) { if (!defaultprofileProvisioned) { VpnStatus.logError("App restrictions: Setting a default profile UUID without providing a profile with that UUID"); } else { - SharedPreferences prefs = Preferences.getDefaultSharedPreferences(c); - String uuid = prefs.getString("alwaysOnVpn", null); + String uuid = defaultPrefs.getString("alwaysOnVpn", null); if (!defaultprofile.equals(uuid)) { - SharedPreferences.Editor editor = prefs.edit(); + SharedPreferences.Editor editor = defaultPrefs.edit(); editor.putString("alwaysOnVpn", defaultprofile); editor.apply(); + } } } } + /** + * If certAlias is non-null will modify the profile type to use the keystore variant of + * the authentication method and will also set the keystore alias + */ + private void addCertificateAlias(VpnProfile vpnProfile, String certAlias, Context c) { + if (vpnProfile == null) + return; + + if (certAlias == null) + certAlias = ""; + + int oldType = vpnProfile.mAuthenticationType; + String oldAlias = vpnProfile.mAlias; + + if (!TextUtils.isEmpty(certAlias)) { + switch (vpnProfile.mAuthenticationType) + { + case VpnProfile.TYPE_PKCS12: + case VpnProfile.TYPE_CERTIFICATES: + vpnProfile.mAuthenticationType = VpnProfile.TYPE_KEYSTORE; + break; + case VpnProfile.TYPE_USERPASS_CERTIFICATES: + case VpnProfile.TYPE_USERPASS_PKCS12: + vpnProfile.mAuthenticationType = VpnProfile.TYPE_USERPASS_KEYSTORE; + break; + } + + } else + { + /* Alias is null, return to non keystore method */ + boolean pkcs12present = !TextUtils.isEmpty(vpnProfile.mPKCS12Filename); + switch (vpnProfile.mAuthenticationType) { + case VpnProfile.TYPE_USERPASS_KEYSTORE: + if (pkcs12present) + vpnProfile.mAuthenticationType = VpnProfile.TYPE_USERPASS_PKCS12; + else + vpnProfile.mAuthenticationType = VpnProfile.TYPE_USERPASS_CERTIFICATES; + break; + case VpnProfile.TYPE_KEYSTORE: + if (pkcs12present) + vpnProfile.mAuthenticationType = VpnProfile.TYPE_PKCS12; + else + vpnProfile.mAuthenticationType = VpnProfile.TYPE_CERTIFICATES; + break; + } + } + vpnProfile.mAlias = certAlias; + + if (!certAlias.equals(oldAlias) || oldType != vpnProfile.mAuthenticationType) + { + ProfileManager pm = ProfileManager.getInstance(c); + pm.saveProfile(c, vpnProfile); + } + } + private String prepare(String config) { String newLine = System.getProperty("line.separator"); if (!config.contains(newLine) && !config.contains(" ")) { @@ -187,7 +304,7 @@ public class AppRestrictions { ; - private void addProfile(Context c, String config, String uuid, String name, VpnProfile vpnProfile) { + VpnProfile addProfile(Context c, String config, String uuid, String name, VpnProfile vpnProfile) { config = prepare(config); ConfigParser cp = new ConfigParser(); try { @@ -213,9 +330,11 @@ public class AppRestrictions { pm.addProfile(vp); pm.saveProfile(c, vp); pm.saveProfileList(c); + return vp; } catch (ConfigParser.ConfigParseError | IOException | IllegalArgumentException e) { VpnStatus.logException("Error during import of managed profile", e); + return null; } } diff --git a/main/src/main/java/de/blinkt/openvpn/api/ExternalAppDatabase.java b/main/src/main/java/de/blinkt/openvpn/api/ExternalAppDatabase.java index 57e82778..fe0afdb6 100644 --- a/main/src/main/java/de/blinkt/openvpn/api/ExternalAppDatabase.java +++ b/main/src/main/java/de/blinkt/openvpn/api/ExternalAppDatabase.java @@ -13,11 +13,13 @@ import android.content.SharedPreferences.Editor; import android.content.pm.ApplicationInfo; import android.content.pm.PackageManager; import android.os.Binder; +import android.widget.Toast; import java.util.HashSet; import java.util.Set; import de.blinkt.openvpn.core.Preferences; +import de.blinkt.openvpn.core.VpnStatus; import static android.content.Intent.FLAG_ACTIVITY_NEW_TASK; @@ -30,12 +32,34 @@ public class ExternalAppDatabase { } private final static String PREFERENCES_KEY = "allowed_apps"; + private final static String PREFERENCES_KEY_MANAGED_CONFIG = "allowed_apps_managed"; + + public void setFlagManagedConfiguration(boolean managed) + { + SharedPreferences prefs = Preferences.getDefaultSharedPreferences(mContext); + Editor prefedit = prefs.edit(); + + prefedit.putBoolean(PREFERENCES_KEY_MANAGED_CONFIG, managed); + increaseWorkaroundCounter(prefs, prefedit); + prefedit.apply(); + } + + public boolean isManagedConfiguration() + { + SharedPreferences prefs = Preferences.getDefaultSharedPreferences(mContext); + return prefs.getBoolean(PREFERENCES_KEY_MANAGED_CONFIG, false); + } + + private static void increaseWorkaroundCounter(SharedPreferences prefs, Editor prefedit) { + // Workaround for bug + int counter = prefs.getInt("counter", 0); + prefedit.putInt("counter", counter + 1); + } boolean isAllowed(String packagename) { Set<String> allowedapps = getExtAppList(); - return allowedapps.contains(packagename); - + return allowedapps.contains(packagename); } public Set<String> getExtAppList() { @@ -50,14 +74,22 @@ public class ExternalAppDatabase { saveExtAppList(allowedapps); } + public boolean checkAllowingModifyingRemoteControl(Context c) { + if (isManagedConfiguration()) { + Toast.makeText(c, "Remote control apps are manged by managed configuration, cannot change", Toast.LENGTH_LONG).show(); + VpnStatus.logError("Remote control apps are manged by managed configuration, cannot change"); + return false; + } + return true; + } + private void saveExtAppList( Set<String> 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); + increaseWorkaroundCounter(prefs, prefedit); prefedit.apply(); } @@ -83,9 +115,9 @@ public class ExternalAppDatabase { } } catch (PackageManager.NameNotFoundException e) { // App not found. Remove it from the list - removeApp(appPackage); + if (!isManagedConfiguration()) + removeApp(appPackage); } - } throw new SecurityException("Unauthorized OpenVPN API Caller"); } @@ -105,4 +137,8 @@ public class ExternalAppDatabase { return false; } } + + public void setAllowedApps(Set<String> restrictionApps) { + saveExtAppList(restrictionApps); + } } diff --git a/main/src/main/java/de/blinkt/openvpn/api/ExternalOpenVPNService.java b/main/src/main/java/de/blinkt/openvpn/api/ExternalOpenVPNService.java index 690c349e..ab71f00b 100644 --- a/main/src/main/java/de/blinkt/openvpn/api/ExternalOpenVPNService.java +++ b/main/src/main/java/de/blinkt/openvpn/api/ExternalOpenVPNService.java @@ -139,16 +139,18 @@ public class ExternalOpenVPNService extends Service implements StateListener { * Check if we need to ask for username/password */
int neddPassword = vp.needUserPWInput(null, null);
+ String startReason = "external OpenVPN service by uid: " + Binder.getCallingUid();
if(vpnPermissionIntent != null || neddPassword != 0){
Intent shortVPNIntent = new Intent(Intent.ACTION_MAIN);
shortVPNIntent.setClass(getBaseContext(), de.blinkt.openvpn.LaunchVPN.class);
shortVPNIntent.putExtra(de.blinkt.openvpn.LaunchVPN.EXTRA_KEY, vp.getUUIDString());
shortVPNIntent.putExtra(de.blinkt.openvpn.LaunchVPN.EXTRA_HIDELOG, true);
+ shortVPNIntent.putExtra(de.blinkt.openvpn.LaunchVPN.EXTRA_START_REASON, startReason);
shortVPNIntent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
startActivity(shortVPNIntent);
} else {
- VPNLaunchHelper.startOpenVpn(vp, getBaseContext());
+ VPNLaunchHelper.startOpenVpn(vp, getBaseContext(), startReason);
}
}
@@ -237,6 +239,8 @@ public class ExternalOpenVPNService extends Service implements StateListener { mExtAppDb.checkOpenVPNPermission(getPackageManager());
ProfileManager pm = ProfileManager.getInstance(getBaseContext());
VpnProfile vp = ProfileManager.get(getBaseContext(), profileUUID);
+ if (vp == null)
+ throw new RemoteException("Profile not found");
pm.removeProfile(ExternalOpenVPNService.this, vp);
}
@@ -244,7 +248,7 @@ public class ExternalOpenVPNService extends Service implements StateListener { public boolean protectSocket(ParcelFileDescriptor pfd) throws RemoteException {
mExtAppDb.checkOpenVPNPermission(getPackageManager());
try {
- boolean success= mService.protect(pfd.getFd());
+ boolean success = mService.protect(pfd.getFd());
pfd.close();
return success;
} catch (IOException e) {
@@ -339,7 +343,7 @@ public class ExternalOpenVPNService extends Service implements StateListener { - class UpdateMessage {
+ static class UpdateMessage {
public String state;
public String logmessage;
public ConnectionStatus level;
diff --git a/main/src/main/java/de/blinkt/openvpn/api/RemoteAction.java b/main/src/main/java/de/blinkt/openvpn/api/RemoteAction.java index 0554b88c..22110ad0 100644 --- a/main/src/main/java/de/blinkt/openvpn/api/RemoteAction.java +++ b/main/src/main/java/de/blinkt/openvpn/api/RemoteAction.java @@ -93,6 +93,7 @@ public class RemoteAction extends Activity { } else { Intent startVPN = new Intent(this, LaunchVPN.class); startVPN.putExtra(LaunchVPN.EXTRA_KEY, profile.getUUID().toString()); + startVPN.putExtra(LaunchVPN.EXTRA_START_REASON, ".api.ConnectVPN call"); startVPN.setAction(Intent.ACTION_MAIN); startActivity(startVPN); } diff --git a/main/src/main/java/de/blinkt/openvpn/core/ExtAuthHelper.java b/main/src/main/java/de/blinkt/openvpn/core/ExtAuthHelper.java index d102dce2..39151646 100644 --- a/main/src/main/java/de/blinkt/openvpn/core/ExtAuthHelper.java +++ b/main/src/main/java/de/blinkt/openvpn/core/ExtAuthHelper.java @@ -42,7 +42,6 @@ public class ExtAuthHelper { public static void setExternalAuthProviderSpinnerList(Spinner spinner, String selectedApp) { Context c = spinner.getContext(); - final PackageManager pm = c.getPackageManager(); ArrayList<ExternalAuthProvider> extProviders = getExternalAuthProviderList(c); int selectedPos = -1; diff --git a/main/src/main/java/de/blinkt/openvpn/core/ICSOpenVPNApplication.java b/main/src/main/java/de/blinkt/openvpn/core/ICSOpenVPNApplication.java index 1df46525..271ec139 100644 --- a/main/src/main/java/de/blinkt/openvpn/core/ICSOpenVPNApplication.java +++ b/main/src/main/java/de/blinkt/openvpn/core/ICSOpenVPNApplication.java @@ -128,5 +128,4 @@ public class ICSOpenVPNApplication extends Application { mChannel.setLightColor(Color.CYAN); mNotificationManager.createNotificationChannel(mChannel); } - } diff --git a/main/src/main/java/de/blinkt/openvpn/core/LocaleHelper.java b/main/src/main/java/de/blinkt/openvpn/core/LocaleHelper.java index 516e025d..ea9bf9e3 100644 --- a/main/src/main/java/de/blinkt/openvpn/core/LocaleHelper.java +++ b/main/src/main/java/de/blinkt/openvpn/core/LocaleHelper.java @@ -15,11 +15,23 @@ import java.util.Locale; public class LocaleHelper { static private Locale desiredLocale = null; - public static void setDesiredLocale(Context c) - { + public static void setDesiredLocale(Context c) { Locale current = Locale.getDefault(); boolean defForce = true; - if (current.getLanguage().equals(new Locale("de").getLanguage())) + + /* Languages that have proofreaders */ + String[] whitelisted = {new Locale("de").getLanguage(), new Locale("ja").getLanguage(), + new Locale("tr").getLanguage(), new Locale("zh-TW").getLanguage()}; + + String currentLanguage = current.getLanguage(); + for (String lang : whitelisted) { + if (lang.equals(currentLanguage)) { + defForce = false; + break; + } + } + + if (current.toLanguageTag().startsWith("zh-Hant")) defForce = false; boolean allow_translation = Preferences.getDefaultSharedPreferences(c).getBoolean("allow_translation", defForce); diff --git a/main/src/main/java/de/blinkt/openvpn/core/LogItem.java b/main/src/main/java/de/blinkt/openvpn/core/LogItem.java index c61cbc44..65714c43 100644 --- a/main/src/main/java/de/blinkt/openvpn/core/LogItem.java +++ b/main/src/main/java/de/blinkt/openvpn/core/LogItem.java @@ -13,11 +13,14 @@ import android.content.pm.Signature; import android.content.res.Resources; import android.os.Parcel; import android.os.Parcelable; +import android.text.TextUtils; import java.io.ByteArrayInputStream; import java.io.UnsupportedEncodingException; +import java.lang.reflect.Array; import java.nio.BufferOverflowException; import java.nio.ByteBuffer; +import java.nio.charset.StandardCharsets; import java.security.MessageDigest; import java.security.NoSuchAlgorithmException; import java.security.cert.CertificateException; @@ -26,7 +29,9 @@ import java.security.cert.X509Certificate; import java.util.Arrays; import java.util.FormatFlagsConversionMismatchException; import java.util.Locale; +import java.util.MissingFormatArgumentException; import java.util.UnknownFormatConversionException; +import java.util.Vector; import de.blinkt.openvpn.R; @@ -47,6 +52,14 @@ public class LogItem implements Parcelable { mArgs = args; } + public LogItem(VpnStatus.LogLevel level, int verblevel, String message, long eventLogTime) { + mMessage = message; + mLevel = level; + mVerbosityLevel = verblevel; + logtime = eventLogTime; + } + + public LogItem(VpnStatus.LogLevel level, int verblevel, String message) { mMessage = message; mLevel = level; @@ -84,8 +97,6 @@ public class LogItem implements Parcelable { other.mLevel.equals(mLevel)) && mVerbosityLevel == other.mVerbosityLevel && logtime == other.logtime; - - } public byte[] getMarschaledBytes() throws UnsupportedEncodingException, BufferOverflowException { @@ -195,7 +206,7 @@ public class LogItem implements Parcelable { } private void marschalString(String str, ByteBuffer bb) throws UnsupportedEncodingException { - byte[] utf8bytes = str.getBytes("UTF-8"); + byte[] utf8bytes = str.getBytes(StandardCharsets.UTF_8); bb.putInt(utf8bytes.length); bb.put(utf8bytes); } @@ -204,7 +215,7 @@ public class LogItem implements Parcelable { int len = bb.getInt(); byte[] utf8bytes = new byte[len]; bb.get(utf8bytes); - return new String(utf8bytes, "UTF-8"); + return new String(utf8bytes, StandardCharsets.UTF_8); } @@ -240,6 +251,11 @@ public class LogItem implements Parcelable { mMessage = msg; } + public LogItem(VpnStatus.LogLevel loglevel, String msg, long logEventTime) { + mLevel = loglevel; + mMessage = msg; + logtime = logEventTime; + } public LogItem(VpnStatus.LogLevel loglevel, int ressourceId) { mRessourceId = ressourceId; @@ -258,7 +274,11 @@ public class LogItem implements Parcelable { if (mArgs == null) return c.getString(mRessourceId); else - return c.getString(mRessourceId, mArgs); + try { + return c.getString(mRessourceId, mArgs); + } catch (MissingFormatArgumentException ie) { + return "ERROR MISSING ARGUMENT(" + ie.getMessage() + "): " + getString(null); + } } catch (Resources.NotFoundException re) { return getString(null); } @@ -324,10 +344,15 @@ public class LogItem implements Parcelable { CertificateFactory cf = CertificateFactory.getInstance("X.509"); X509Certificate cert = (X509Certificate) cf.generateCertificate(new ByteArrayInputStream(raw.toByteArray())); MessageDigest md = MessageDigest.getInstance("SHA-1"); + MessageDigest mdsha256 = MessageDigest.getInstance("SHA-256"); + byte[] der = cert.getEncoded(); md.update(der); byte[] digest = md.digest(); + mdsha256.update(der); + byte[] digestSha256 = mdsha256.digest(); + if (Arrays.equals(digest, VpnStatus.officalkey)) apksign = c.getString(R.string.official_build); else if (Arrays.equals(digest, VpnStatus.officaldebugkey)) @@ -336,8 +361,15 @@ public class LogItem implements Parcelable { apksign = "amazon version"; else if (Arrays.equals(digest, VpnStatus.fdroidkey)) apksign = "F-Droid built and signed version"; - else - apksign = c.getString(R.string.built_by, cert.getSubjectX500Principal().getName()); + else if (Arrays.equals(digestSha256, VpnStatus.officialO2Key)) + apksign = c.getString(R.string.official_o2build); + else { + Vector<String> hexnums = new Vector<>(); + for (byte b: digestSha256) { + hexnums.add(String.format(Locale.US, "%02x", b)); + } + apksign = c.getString(R.string.built_by, cert.getSubjectX500Principal().getName(), TextUtils.join(":", hexnums)); + } PackageInfo packageinfo = c.getPackageManager().getPackageInfo(c.getPackageName(), 0); version = packageinfo.versionName; diff --git a/main/src/main/java/de/blinkt/openvpn/core/NativeUtils.java b/main/src/main/java/de/blinkt/openvpn/core/NativeUtils.java index 72b2b784..9bfa5e67 100644 --- a/main/src/main/java/de/blinkt/openvpn/core/NativeUtils.java +++ b/main/src/main/java/de/blinkt/openvpn/core/NativeUtils.java @@ -30,18 +30,28 @@ public class NativeUtils { public static native String getOpenVPN3GitVersion(); - static boolean rsspssloaded = false; + private static native String getOpenSSLVersionString(); + + public static String getOpenSSLVersion() { + loadOsslUtil(); + return getOpenSSLVersionString(); + } + + static boolean osslutilloaded = false; public static byte[] addRssPssPadding(int hashtype, int MSBits, int rsa_size, byte[] from) { - if (!rsspssloaded) { - rsspssloaded = true; - System.loadLibrary("rsapss"); - } - + loadOsslUtil(); return rsapss(hashtype, MSBits, rsa_size, from); } + private static void loadOsslUtil() { + if (!osslutilloaded) { + osslutilloaded = true; + System.loadLibrary("osslutil"); + } + } + private static native byte[] rsapss(int hashtype, int MSBits, int rsa_size, byte[] from); public final static int[] openSSLlengths = { diff --git a/main/src/main/java/de/blinkt/openvpn/core/NetworkSpace.java b/main/src/main/java/de/blinkt/openvpn/core/NetworkSpace.java index 9c8cf363..da53831b 100644 --- a/main/src/main/java/de/blinkt/openvpn/core/NetworkSpace.java +++ b/main/src/main/java/de/blinkt/openvpn/core/NetworkSpace.java @@ -5,11 +5,13 @@ package de.blinkt.openvpn.core; +import android.annotation.TargetApi; import android.net.IpPrefix; +import android.os.Build; import androidx.annotation.NonNull; -import java.lang.reflect.Array; +import java.lang.annotation.Target; import java.math.BigInteger; import java.net.Inet4Address; import java.net.Inet6Address; @@ -132,6 +134,7 @@ public class NetworkSpace { } + @NonNull @Override public String toString() { //String in = included ? "+" : "-"; @@ -210,6 +213,7 @@ public class NetworkSpace { } + @TargetApi(Build.VERSION_CODES.TIRAMISU) public IpPrefix getPrefix() throws UnknownHostException { if (isV4){ /* add 0x01 00 00 00 00, so that all representations are 5 byte otherwise diff --git a/main/src/main/java/de/blinkt/openvpn/core/NetworkUtils.java b/main/src/main/java/de/blinkt/openvpn/core/NetworkUtils.java index 00f45ed4..f104d3b0 100644 --- a/main/src/main/java/de/blinkt/openvpn/core/NetworkUtils.java +++ b/main/src/main/java/de/blinkt/openvpn/core/NetworkUtils.java @@ -14,14 +14,18 @@ import android.text.TextUtils; import java.net.Inet4Address; import java.net.Inet6Address; +import java.net.InetAddress; +import java.net.UnknownHostException; import java.util.Vector; +import de.blinkt.openvpn.R; + public class NetworkUtils { public static Vector<String> getLocalNetworks(Context c, boolean ipv6) { - Vector<String> nets = new Vector<>(); ConnectivityManager conn = (ConnectivityManager) c.getSystemService(Context.CONNECTIVITY_SERVICE); + Vector<String> nets = new Vector<>(); Network[] networks = conn.getAllNetworks(); for (Network network : networks) { NetworkInfo ni = conn.getNetworkInfo(network); @@ -29,6 +33,10 @@ public class NetworkUtils { NetworkCapabilities nc = conn.getNetworkCapabilities(network); + // Ignore network if it has no capabilities + if (nc == null) + continue; + // Skip VPN networks like ourselves if (nc.hasTransport(NetworkCapabilities.TRANSPORT_VPN)) continue; @@ -40,8 +48,16 @@ public class NetworkUtils { for (LinkAddress la : li.getLinkAddresses()) { if ((la.getAddress() instanceof Inet4Address && !ipv6) || - (la.getAddress() instanceof Inet6Address && ipv6)) - nets.add(la.toString()); + (la.getAddress() instanceof Inet6Address && ipv6)) { + //nets.add(la.toString()); + NetworkSpace.IpAddress ipaddress; + if (la.getAddress() instanceof Inet6Address) + ipaddress = new NetworkSpace.IpAddress((Inet6Address) la.getAddress(), la.getPrefixLength(), true); + else + ipaddress = new NetworkSpace.IpAddress(new CIDRIP(la.getAddress().getHostAddress(), la.getPrefixLength()), true); + + nets.add(ipaddress.toString()); + } } } 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 d3de35f9..0e8793e4 100644 --- a/main/src/main/java/de/blinkt/openvpn/core/OpenVPNService.java +++ b/main/src/main/java/de/blinkt/openvpn/core/OpenVPNService.java @@ -14,16 +14,18 @@ import android.app.Notification; import android.app.NotificationManager; import android.app.PendingIntent; import android.app.UiModeManager; +import android.app.job.JobInfo; +import android.app.job.JobScheduler; import android.content.ComponentName; import android.content.Context; import android.content.Intent; import android.content.IntentFilter; +import android.content.SharedPreferences; import android.content.pm.PackageManager; import android.content.pm.ShortcutManager; import android.content.res.Configuration; import android.content.res.Resources; import android.net.ConnectivityManager; -import android.net.IpPrefix; import android.net.ProxyInfo; import android.net.Uri; import android.net.VpnService; @@ -35,6 +37,7 @@ import android.os.HandlerThread; import android.os.IBinder; import android.os.Message; import android.os.ParcelFileDescriptor; +import android.os.PersistableBundle; import android.os.RemoteException; import android.system.OsConstants; import android.text.TextUtils; @@ -84,17 +87,27 @@ public class OpenVPNService extends VpnService implements StateListener, Callbac private static final int PRIORITY_DEFAULT = 0; private static final int PRIORITY_MAX = 2; private static boolean mNotificationAlwaysVisible = false; - private final Vector<String> mDnslist = new Vector<>(); - private final NetworkSpace mRoutes = new NetworkSpace(); - private final NetworkSpace mRoutesv6 = new NetworkSpace(); + + static class TunConfig { + private final Vector<String> mDnslist = new Vector<>(); + private final NetworkSpace mRoutes = new NetworkSpace(); + private final NetworkSpace mRoutesv6 = new NetworkSpace(); + private String mDomain = null; + private CIDRIP mLocalIP = null; + private int mMtu; + private String mLocalIPv6 = null; + + private ProxyInfo mProxyInfo; + }; + + private TunConfig tunConfig = new TunConfig(); + private final Object mProcessLock = new Object(); private String lastChannel; private Thread mProcessThread = null; private VpnProfile mProfile; - private String mDomain = null; - private CIDRIP mLocalIP = null; - private int mMtu; - private String mLocalIPv6 = null; + + private DeviceStateReceiver mDeviceStateReceiver; private boolean mDisplayBytecount = false; private boolean mStarting = false; @@ -135,12 +148,11 @@ public class OpenVPNService extends VpnService implements StateListener, Callbac }; - private String mLastTunCfg; + private TunConfig mLastTunCfg; private String mRemoteGW; private Handler guiHandler; private Toast mlastToast; private Runnable mOpenVPNThread; - private ProxyInfo mProxyInfo; private HandlerThread mCommandHandlerThread; private Handler mCommandHandler; @@ -180,10 +192,14 @@ public class OpenVPNService extends VpnService implements StateListener, Callbac } } + + @Override public void addAllowedExternalApp(String packagename) throws RemoteException { ExternalAppDatabase extapps = new ExternalAppDatabase(OpenVPNService.this); - extapps.addApp(packagename); + if(extapps.checkAllowingModifyingRemoteControl(this)) { + extapps.addApp(packagename); + } } @Override @@ -213,7 +229,9 @@ public class OpenVPNService extends VpnService implements StateListener, Callbac @Override public void onRevoke() { VpnStatus.logError(R.string.permission_revoked); - mManagement.stopVPN(false); + final OpenVPNManagement managment = mManagement; + mCommandHandler.post(() -> managment.stopVPN(false)); + endVpnService(); } @@ -222,7 +240,25 @@ public class OpenVPNService extends VpnService implements StateListener, Callbac endVpnService(); } + private boolean isAlwaysActiveEnabled() + { + SharedPreferences prefs = Preferences.getDefaultSharedPreferences(this); + return prefs.getBoolean("restartvpnonboot", false); + } + + boolean isVpnAlwaysOnEnabled() { + if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q) { + return isAlwaysOn(); + } + return false; + } + + private void endVpnService() { + if (!isVpnAlwaysOnEnabled() && !isAlwaysActiveEnabled()) { + /* if we should be an always on VPN, keep the timer running */ + keepVPNAlive.unscheduleKeepVPNAliveJobService(this); + } synchronized (mProcessLock) { mProcessThread = null; } @@ -519,9 +555,13 @@ public class OpenVPNService extends VpnService implements StateListener, Callbac private VpnProfile fetchVPNProfile(Intent intent) { + String startReason; if (intent != null && intent.hasExtra(getPackageName() + ".profileUUID")) { String profileUUID = intent.getStringExtra(getPackageName() + ".profileUUID"); int profileVersion = intent.getIntExtra(getPackageName() + ".profileVersion", 0); + startReason = intent.getStringExtra(getPackageName() + ".startReason"); + if (startReason == null) + startReason = "(unknown)"; // Try for 10s to get current version of the profile mProfile = ProfileManager.get(this, profileUUID, profileVersion, 100); if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N_MR1) { @@ -531,10 +571,13 @@ public class OpenVPNService extends VpnService implements StateListener, Callbac } else { /* The intent is null when we are set as always-on or the service has been restarted. */ mProfile = ProfileManager.getLastConnectedProfile(this); + startReason = "Using last connected profile (started with null intent, always-on or restart after crash)"; VpnStatus.logInfo(R.string.service_restarted); /* Got no profile, just stop */ if (mProfile == null) { + startReason = "could not get last connected profile, using default (started with null intent, always-on or restart after crash)"; + Log.d("OpenVPN", "Got no last connected profile on null intent. Assuming always on."); mProfile = ProfileManager.getAlwaysOnVPN(this); @@ -546,6 +589,10 @@ public class OpenVPNService extends VpnService implements StateListener, Callbac /* Do the asynchronous keychain certificate stuff */ mProfile.checkForRestart(this); } + String name = "(null)"; + if (mProfile != null) + name = mProfile.getName(); + VpnStatus.logDebug(String.format("Fetched VPN profile (%s) triggered by %s", name, startReason)); return mProfile; } @@ -558,6 +605,7 @@ public class OpenVPNService extends VpnService implements StateListener, Callbac ProfileManager.setConnectedVpnProfile(this, mProfile); VpnStatus.setConnectedVPNProfile(mProfile.getUUIDString()); + keepVPNAlive.scheduleKeepVPNAliveJobService(this, vp); String nativeLibraryDirectory = getApplicationInfo().nativeLibraryDir; String tmpDir; @@ -575,8 +623,7 @@ public class OpenVPNService extends VpnService implements StateListener, Callbac // Set a flag that we are starting a new VPN mStarting = true; // Stop the previous session by interrupting the thread. - - stopOldOpenVPNProcess(); + stopOldOpenVPNProcess(mManagement, mOpenVPNThread); // An old running VPN should now be exited mStarting = false; @@ -635,11 +682,12 @@ public class OpenVPNService extends VpnService implements StateListener, Callbac } - private void stopOldOpenVPNProcess() { - if (mManagement != null) { - if (mOpenVPNThread != null) - ((OpenVPNThread) mOpenVPNThread).setReplaceConnection(); - if (mManagement.stopVPN(true)) { + private void stopOldOpenVPNProcess(OpenVPNManagement management, + Runnable mamanagmentThread) { + if (management != null) { + if (mamanagmentThread != null) + ((OpenVPNThread) mamanagmentThread).setReplaceConnection(); + if (management.stopVPN(true)) { // an old was asked to exit, wait 1s try { Thread.sleep(1000); @@ -708,27 +756,38 @@ public class OpenVPNService extends VpnService implements StateListener, Callbac VpnStatus.flushLog(); } - private String getTunConfigString() { + private static String getTunConfigString(TunConfig tc) { // The format of the string is not important, only that // two identical configurations produce the same result + if (tc == null) + return "NULL"; + String cfg = "TUNCFG UNQIUE STRING ips:"; - if (mLocalIP != null) - cfg += mLocalIP.toString(); - if (mLocalIPv6 != null) - cfg += mLocalIPv6; + if (tc.mLocalIP != null) + cfg += tc.mLocalIP.toString(); + if (tc.mLocalIPv6 != null) + cfg += tc.mLocalIPv6; - cfg += "routes: " + TextUtils.join("|", mRoutes.getNetworks(true)) + TextUtils.join("|", mRoutesv6.getNetworks(true)); - cfg += "excl. routes:" + TextUtils.join("|", mRoutes.getNetworks(false)) + TextUtils.join("|", mRoutesv6.getNetworks(false)); - cfg += "dns: " + TextUtils.join("|", mDnslist); - cfg += "domain: " + mDomain; - cfg += "mtu: " + mMtu; - cfg += "proxyInfo: " + mProxyInfo; + cfg += "routes: " + TextUtils.join("|", tc.mRoutes.getNetworks(true)) + TextUtils.join("|", tc.mRoutesv6.getNetworks(true)); + cfg += "excl. routes:" + TextUtils.join("|", tc.mRoutes.getNetworks(false)) + TextUtils.join("|", tc.mRoutesv6.getNetworks(false)); + cfg += "dns: " + TextUtils.join("|", tc.mDnslist); + cfg += "domain: " + tc.mDomain; + cfg += "mtu: " + tc.mMtu; + cfg += "proxyInfo: " + tc.mProxyInfo; return cfg; } public ParcelFileDescriptor openTun() { + ParcelFileDescriptor pfd = openTun(tunConfig); + + // Reset information + mLastTunCfg = tunConfig; + tunConfig = new TunConfig(); + return pfd; + } + private ParcelFileDescriptor openTun(TunConfig tc) { //Debug.startMethodTracing(getExternalFilesDir(null).toString() + "/opentun.trace", 40* 1024 * 1024); @@ -747,36 +806,36 @@ public class OpenVPNService extends VpnService implements StateListener, Callbac allowAllAFFamilies(builder); } - if (mLocalIP == null && mLocalIPv6 == null) { + if (tc.mLocalIP == null && tc.mLocalIPv6 == null) { VpnStatus.logError(getString(R.string.opentun_no_ipaddr)); return null; } - if (mLocalIP != null) { + if (tc.mLocalIP != null) { // OpenVPN3 manages excluded local networks by callback if (!VpnProfile.doUseOpenVPN3(this)) - addLocalNetworksToRoutes(); + addLocalNetworksToRoutes(tc); try { - builder.addAddress(mLocalIP.mIp, mLocalIP.len); + builder.addAddress(tc.mLocalIP.mIp, tc.mLocalIP.len); } catch (IllegalArgumentException iae) { - VpnStatus.logError(R.string.dns_add_error, mLocalIP, iae.getLocalizedMessage()); + VpnStatus.logError(R.string.dns_add_error, tc.mLocalIP, iae.getLocalizedMessage()); return null; } } - if (mLocalIPv6 != null) { - String[] ipv6parts = mLocalIPv6.split("/"); + if (tc.mLocalIPv6 != null) { + String[] ipv6parts = tc.mLocalIPv6.split("/"); try { builder.addAddress(ipv6parts[0], Integer.parseInt(ipv6parts[1])); } catch (IllegalArgumentException iae) { - VpnStatus.logError(R.string.ip_add_error, mLocalIPv6, iae.getLocalizedMessage()); + VpnStatus.logError(R.string.ip_add_error, tc.mLocalIPv6, iae.getLocalizedMessage()); return null; } } - for (String dns : mDnslist) { + for (String dns : tc.mDnslist) { try { builder.addDnsServer(dns); } catch (IllegalArgumentException iae) { @@ -785,15 +844,15 @@ public class OpenVPNService extends VpnService implements StateListener, Callbac } String release = Build.VERSION.RELEASE; - builder.setMtu(mMtu); + builder.setMtu(tc.mMtu); - Collection<IpAddress> positiveIPv4Routes = mRoutes.getPositiveIPList(); - Collection<IpAddress> positiveIPv6Routes = mRoutesv6.getPositiveIPList(); + Collection<IpAddress> positiveIPv4Routes = tc.mRoutes.getPositiveIPList(); + Collection<IpAddress> positiveIPv6Routes = tc.mRoutesv6.getPositiveIPList(); - if ("samsung".equals(Build.BRAND) && mDnslist.size() >= 1) { + if ("samsung".equals(Build.BRAND) && tc.mDnslist.size() >= 1) { // Check if the first DNS Server is in the VPN range try { - IpAddress dnsServer = new IpAddress(new CIDRIP(mDnslist.get(0), 32), true); + IpAddress dnsServer = new IpAddress(new CIDRIP(tc.mDnslist.get(0), 32), true); boolean dnsIncluded = false; for (IpAddress net : positiveIPv4Routes) { if (net.containsNet(dnsServer)) { @@ -801,28 +860,28 @@ public class OpenVPNService extends VpnService implements StateListener, Callbac } } if (!dnsIncluded) { - String samsungwarning = String.format("Warning Samsung Android 5.0+ devices ignore DNS servers outside the VPN range. To enable DNS resolution a route to your DNS Server (%s) has been added.", mDnslist.get(0)); + String samsungwarning = String.format("Warning Samsung Android 5.0+ devices ignore DNS servers outside the VPN range. To enable DNS resolution a route to your DNS Server (%s) has been added.", tc.mDnslist.get(0)); VpnStatus.logWarning(samsungwarning); positiveIPv4Routes.add(dnsServer); } } catch (Exception e) { // If it looks like IPv6 ignore error - if (!mDnslist.get(0).contains(":")) - VpnStatus.logError("Error parsing DNS Server IP: " + mDnslist.get(0)); + if (!tc.mDnslist.get(0).contains(":")) + VpnStatus.logError("Error parsing DNS Server IP: " + tc.mDnslist.get(0)); } } if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.TIRAMISU) { - installRoutesExcluded(builder, mRoutes); - installRoutesExcluded(builder, mRoutesv6); + installRoutesExcluded(builder, tc.mRoutes); + installRoutesExcluded(builder, tc.mRoutesv6); } else { installRoutesPostiveOnly(builder, positiveIPv4Routes, positiveIPv6Routes); } - if (mDomain != null) - builder.addSearchDomain(mDomain); + if (tc.mDomain != null) + builder.addSearchDomain(tc.mDomain); String ipv4info; String ipv6info; @@ -835,32 +894,34 @@ public class OpenVPNService extends VpnService implements StateListener, Callbac } int ipv4len; - if (mLocalIP != null) { - ipv4len = mLocalIP.len; - ipv4info = mLocalIP.mIp; + if (tc.mLocalIP != null) { + ipv4len = tc.mLocalIP.len; + ipv4info = tc.mLocalIP.mIp; } else { ipv4len = -1; } - if (mLocalIPv6 != null) { - ipv6info = mLocalIPv6; + if (tc.mLocalIPv6 != null) { + ipv6info = tc.mLocalIPv6; } - if ((!mRoutes.getNetworks(false).isEmpty() || !mRoutesv6.getNetworks(false).isEmpty()) && isLockdownEnabledCompat()) { + if ((!tc.mRoutes.getNetworks(false).isEmpty() || !tc.mRoutesv6.getNetworks(false).isEmpty()) && isLockdownEnabledCompat()) { VpnStatus.logInfo("VPN lockdown enabled (do not allow apps to bypass VPN) enabled. Route exclusion will not allow apps to bypass VPN (e.g. bypass VPN for local networks)"); } - VpnStatus.logInfo(R.string.local_ip_info, ipv4info, ipv4len, ipv6info, mMtu); - VpnStatus.logInfo(R.string.dns_server_info, TextUtils.join(", ", mDnslist), mDomain); - VpnStatus.logInfo(R.string.routes_info_incl, TextUtils.join(", ", mRoutes.getNetworks(true)), TextUtils.join(", ", mRoutesv6.getNetworks(true))); - VpnStatus.logInfo(R.string.routes_info_excl, TextUtils.join(", ", mRoutes.getNetworks(false)), TextUtils.join(", ", mRoutesv6.getNetworks(false))); - if (mProxyInfo != null) { - VpnStatus.logInfo(R.string.proxy_info, mProxyInfo.getHost(), mProxyInfo.getPort()); + VpnStatus.logInfo(R.string.local_ip_info, ipv4info, ipv4len, ipv6info, tc.mMtu); + VpnStatus.logInfo(R.string.dns_server_info, TextUtils.join(", ", tc.mDnslist), tc.mDomain); + VpnStatus.logInfo(R.string.routes_info_incl, TextUtils.join(", ", tc.mRoutes.getNetworks(true)), TextUtils.join(", ", tc.mRoutesv6.getNetworks(true))); + VpnStatus.logInfo(R.string.routes_info_excl, TextUtils.join(", ", tc.mRoutes.getNetworks(false)), TextUtils.join(", ", tc.mRoutesv6.getNetworks(false))); + if (tc.mProxyInfo != null) { + VpnStatus.logInfo(R.string.proxy_info, tc.mProxyInfo.getHost(), tc.mProxyInfo.getPort()); } if (Build.VERSION.SDK_INT < Build.VERSION_CODES.TIRAMISU) { /* On Tiramisu we install the routes exactly like promised */ VpnStatus.logDebug(R.string.routes_debug, TextUtils.join(", ", positiveIPv4Routes), TextUtils.join(", ", positiveIPv6Routes)); } + //VpnStatus.logInfo(String.format("Always active %s", isAlwaysOn() ? "on" : "off")); + setAllowedVpnPackages(builder); if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP_MR1) { // VPN always uses the default network @@ -874,31 +935,20 @@ public class OpenVPNService extends VpnService implements StateListener, Callbac } String session = mProfile.mName; - if (mLocalIP != null && mLocalIPv6 != null) - session = getString(R.string.session_ipv6string, session, mLocalIP, mLocalIPv6); - else if (mLocalIP != null) - session = getString(R.string.session_ipv4string, session, mLocalIP); + if (tc.mLocalIP != null && tc.mLocalIPv6 != null) + session = getString(R.string.session_ipv6string, session, tc.mLocalIP, tc.mLocalIPv6); + else if (tc.mLocalIP != null) + session = getString(R.string.session_ipv4string, session, tc.mLocalIP); else - session = getString(R.string.session_ipv4string, session, mLocalIPv6); + session = getString(R.string.session_ipv4string, session, tc.mLocalIPv6); builder.setSession(session); // No DNS Server, log a warning - if (mDnslist.size() == 0) + if (tc.mDnslist.size() == 0) VpnStatus.logInfo(R.string.warn_no_dns); - setHttpProxy(builder); - - mLastTunCfg = getTunConfigString(); - - // Reset information - mDnslist.clear(); - mRoutes.clear(); - mRoutesv6.clear(); - mLocalIP = null; - mLocalIPv6 = null; - mDomain = null; - mProxyInfo = null; + setHttpProxy(builder, tc); builder.setConfigureIntent(getGraphPendingIntent()); @@ -959,10 +1009,10 @@ public class OpenVPNService extends VpnService implements StateListener, Callbac } } - private void setHttpProxy(Builder builder) { - if (mProxyInfo != null && Build.VERSION.SDK_INT >= 29) { - builder.setHttpProxy(mProxyInfo); - } else if (mProxyInfo != null) { + private void setHttpProxy(Builder builder, TunConfig tc) { + if (tc.mProxyInfo != null && Build.VERSION.SDK_INT >= 29) { + builder.setHttpProxy(tc.mProxyInfo); + } else if (tc.mProxyInfo != null) { VpnStatus.logWarning("HTTP Proxy needs Android 10 or later."); } } @@ -982,27 +1032,24 @@ public class OpenVPNService extends VpnService implements StateListener, Callbac builder.allowFamily(OsConstants.AF_INET6); } - private void addLocalNetworksToRoutes() { + private void addLocalNetworksToRoutes(TunConfig tc) { for (String net : NetworkUtils.getLocalNetworks(this, false)) { String[] netparts = net.split("/"); String ipAddr = netparts[0]; int netMask = Integer.parseInt(netparts[1]); - if (ipAddr.equals(mLocalIP.mIp)) + if (ipAddr.equals(tc.mLocalIP.mIp)) continue; if(mProfile.mAllowLocalLAN) - mRoutes.addIP(new CIDRIP(ipAddr, netMask), false); + tc.mRoutes.addIP(new CIDRIP(ipAddr, netMask), false); } - // IPv6 is Lollipop+ only so we can skip the lower than KITKAT case if (mProfile.mAllowLocalLAN) { for (String net : NetworkUtils.getLocalNetworks(this, true)) { addRoutev6(net, false); ; } } - - } private void setAllowedVpnPackages(Builder builder) { @@ -1065,12 +1112,12 @@ public class OpenVPNService extends VpnService implements StateListener, Callbac } public void addDNS(String dns) { - mDnslist.add(dns); + tunConfig.mDnslist.add(dns); } public void setDomain(String domain) { - if (mDomain == null) { - mDomain = domain; + if (tunConfig.mDomain == null) { + tunConfig.mDomain = domain; } } @@ -1078,12 +1125,12 @@ public class OpenVPNService extends VpnService implements StateListener, Callbac * Route that is always included, used by the v3 core */ public void addRoute(CIDRIP route, boolean include) { - mRoutes.addIP(route, include); + tunConfig.mRoutes.addIP(route, include); } public boolean addHttpProxy(String proxy, int port) { try { - mProxyInfo = ProxyInfo.buildDirectProxy(proxy, port); + tunConfig.mProxyInfo = ProxyInfo.buildDirectProxy(proxy, port); } catch (Exception e) { VpnStatus.logError("Could not set proxy" + e.getLocalizedMessage()); return false; @@ -1097,11 +1144,11 @@ public class OpenVPNService extends VpnService implements StateListener, Callbac IpAddress gatewayIP = new IpAddress(new CIDRIP(gateway, 32), false); - if (mLocalIP == null) { + if (tunConfig.mLocalIP == null) { VpnStatus.logError("Local IP address unset and received. Neither pushed server config nor local config specifies an IP addresses. Opening tun device is most likely going to fail."); return; } - IpAddress localNet = new IpAddress(mLocalIP, true); + IpAddress localNet = new IpAddress(tunConfig.mLocalIP, true); if (localNet.containsNet(gatewayIP)) include = true; @@ -1117,7 +1164,7 @@ public class OpenVPNService extends VpnService implements StateListener, Callbac if (route.normalise()) VpnStatus.logWarning(R.string.route_not_netip, dest, route.len, route.mIp); - mRoutes.addIP(route, include); + tunConfig.mRoutes.addIP(route, include); } public void addRoutev6(String network, String device) { @@ -1132,7 +1179,7 @@ public class OpenVPNService extends VpnService implements StateListener, Callbac try { Inet6Address ip = (Inet6Address) InetAddress.getAllByName(v6parts[0])[0]; int mask = Integer.parseInt(v6parts[1]); - mRoutesv6.addIPv6(ip, mask, included); + tunConfig.mRoutesv6.addIPv6(ip, mask, included); } catch (UnknownHostException e) { VpnStatus.logException(e); @@ -1147,21 +1194,21 @@ public class OpenVPNService extends VpnService implements StateListener, Callbac } public void setMtu(int mtu) { - mMtu = mtu; + tunConfig.mMtu = mtu; } public void setLocalIP(CIDRIP cdrip) { - mLocalIP = cdrip; + tunConfig.mLocalIP = cdrip; } public void setLocalIP(String local, String netmask, int mtu, String mode) { - mLocalIP = new CIDRIP(local, netmask); - mMtu = mtu; + tunConfig.mLocalIP = new CIDRIP(local, netmask); + tunConfig.mMtu = mtu; mRemoteGW = null; long netMaskAsInt = CIDRIP.getInt(netmask); - if (mLocalIP.len == 32 && !netmask.equals("255.255.255.255")) { + if (tunConfig.mLocalIP.len == 32 && !netmask.equals("255.255.255.255")) { // get the netmask as IP int masklen; @@ -1175,22 +1222,22 @@ public class OpenVPNService extends VpnService implements StateListener, Callbac } // Netmask is Ip address +/-1, assume net30/p2p with small net - if ((netMaskAsInt & mask) == (mLocalIP.getInt() & mask)) { - mLocalIP.len = masklen; + if ((netMaskAsInt & mask) == (tunConfig.mLocalIP.getInt() & mask)) { + tunConfig.mLocalIP.len = masklen; } else { - mLocalIP.len = 32; + tunConfig.mLocalIP.len = 32; if (!"p2p".equals(mode)) VpnStatus.logWarning(R.string.ip_not_cidr, local, netmask, mode); } } - if (("p2p".equals(mode) && mLocalIP.len < 32) || ("net30".equals(mode) && mLocalIP.len < 30)) { + if (("p2p".equals(mode) && tunConfig.mLocalIP.len < 32) || ("net30".equals(mode) && tunConfig.mLocalIP.len < 30)) { VpnStatus.logWarning(R.string.ip_looks_like_subnet, local, netmask, mode); } /* Workaround for Lollipop and higher, it does not route traffic to the VPNs own network mask */ - if (mLocalIP.len <= 31) { - CIDRIP interfaceRoute = new CIDRIP(mLocalIP.mIp, mLocalIP.len); + if (tunConfig.mLocalIP.len <= 31) { + CIDRIP interfaceRoute = new CIDRIP(tunConfig.mLocalIP.mIp, tunConfig.mLocalIP.len); interfaceRoute.normalise(); addRoute(interfaceRoute, true); } @@ -1201,7 +1248,7 @@ public class OpenVPNService extends VpnService implements StateListener, Callbac } public void setLocalIPv6(String ipv6addr) { - mLocalIPv6 = ipv6addr; + tunConfig.mLocalIPv6 = ipv6addr; } @Override @@ -1279,8 +1326,8 @@ public class OpenVPNService extends VpnService implements StateListener, Callbac } public String getTunReopenStatus() { - String currentConfiguration = getTunConfigString(); - if (currentConfiguration.equals(mLastTunCfg)) { + String currentConfiguration = getTunConfigString(tunConfig); + if (currentConfiguration.equals(getTunConfigString(mLastTunCfg))) { return "NOACTION"; } else { return "OPEN_BEFORE_CLOSE"; diff --git a/main/src/main/java/de/blinkt/openvpn/core/OpenVPNThread.java b/main/src/main/java/de/blinkt/openvpn/core/OpenVPNThread.java index 51fc58eb..37eb34dd 100644 --- a/main/src/main/java/de/blinkt/openvpn/core/OpenVPNThread.java +++ b/main/src/main/java/de/blinkt/openvpn/core/OpenVPNThread.java @@ -15,6 +15,7 @@ import java.io.IOException; import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.OutputStream;
+import java.nio.charset.StandardCharsets;
import java.text.SimpleDateFormat;
import java.util.Collections;
import java.util.Date;
@@ -135,7 +136,7 @@ public class OpenVPNThread implements Runnable { InputStream in = mProcess.getInputStream();
OutputStream out = mProcess.getOutputStream();
- BufferedReader br = new BufferedReader(new InputStreamReader(in));
+ BufferedReader br = new BufferedReader(new InputStreamReader(in, StandardCharsets.UTF_8));
mOutputStream = out;
mStreamFuture.run();
diff --git a/main/src/main/java/de/blinkt/openvpn/core/OpenVpnManagementThread.java b/main/src/main/java/de/blinkt/openvpn/core/OpenVpnManagementThread.java index 11b2608b..8edae328 100644 --- a/main/src/main/java/de/blinkt/openvpn/core/OpenVpnManagementThread.java +++ b/main/src/main/java/de/blinkt/openvpn/core/OpenVpnManagementThread.java @@ -47,12 +47,12 @@ public class OpenVpnManagementThread implements Runnable, OpenVPNManagement { private pauseReason lastPauseReason = pauseReason.noNetwork;
private PausedStateCallback mPauseCallback;
private boolean mShuttingDown;
- private Runnable mResumeHoldRunnable = () -> {
+ private final Runnable mResumeHoldRunnable = () -> {
if (shouldBeRunning()) {
releaseHoldCmd();
}
};
- private Runnable orbotStatusTimeOutRunnable = new Runnable() {
+ private final Runnable orbotStatusTimeOutRunnable = new Runnable() {
@Override
public void run() {
sendProxyCMD(Connection.ProxyType.SOCKS5, "127.0.0.1", Integer.toString(OrbotHelper.SOCKS_PROXY_PORT_DEFAULT), false);
@@ -148,8 +148,6 @@ public class OpenVpnManagementThread implements Runnable, OpenVPNManagement { VpnStatus.logException(e);
}
return false;
-
-
}
/**
@@ -402,7 +400,7 @@ public class OpenVpnManagementThread implements Runnable, OpenVPNManagement { if (waittime > 1)
VpnStatus.updateStateString("CONNECTRETRY", String.valueOf(waittime),
R.string.state_waitconnectretry, ConnectionStatus.LEVEL_CONNECTING_NO_SERVER_REPLY_YET);
- mResumeHandler.postDelayed(mResumeHoldRunnable, waittime * 1000);
+ mResumeHandler.postDelayed(mResumeHoldRunnable, waittime * 1000L);
if (waittime > 5)
VpnStatus.logInfo(R.string.state_waitconnectretry, String.valueOf(waittime));
else
@@ -618,14 +616,8 @@ public class OpenVpnManagementThread implements Runnable, OpenVPNManagement { managmentCommand(cmd);
}
- private boolean sendTunFD(String needed, String extra) {
- if (!extra.equals("tun")) {
- // We only support tun
- VpnStatus.logError(String.format("Device type %s requested, but only tun is possible with the Android API, sorry!", extra));
- return false;
- }
- ParcelFileDescriptor pfd = mOpenVPNService.openTun();
+ private boolean sendCommandWithFd(String cmd, ParcelFileDescriptor pfd) {
if (pfd == null)
return false;
@@ -638,26 +630,38 @@ public class OpenVpnManagementThread implements Runnable, OpenVPNManagement { setInt.invoke(fdtosend, fdint);
FileDescriptor[] fds = {fdtosend};
- mSocket.setFileDescriptorsForSend(fds);
// Trigger a send so we can close the fd on our side of the channel
// The API documentation fails to mention that it will not reset the file descriptor to
// be send and will happily send the file descriptor on every write ...
- String cmd = String.format("needok '%s' %s\n", needed, "ok");
+ mSocket.setFileDescriptorsForSend(fds);
+
managmentCommand(cmd);
// Set the FileDescriptor to null to stop this mad behavior
mSocket.setFileDescriptorsForSend(null);
-
pfd.close();
- return true;
- } catch (NoSuchMethodException | IllegalArgumentException | InvocationTargetException |
- IOException | IllegalAccessException exp) {
+
+ } catch (InvocationTargetException | NoSuchMethodException | IllegalAccessException |
+ IOException exp) {
VpnStatus.logException("Could not send fd over socket", exp);
+ return false;
}
+ return true;
+ }
- return false;
+ private boolean sendTunFD(String needed, String extra) {
+ if (!extra.equals("tun")) {
+ // We only support tun
+ VpnStatus.logError(String.format("Device type %s requested, but only tun is possible with the Android API, sorry!", extra));
+
+ return false;
+ }
+ ParcelFileDescriptor pfd = mOpenVPNService.openTun();
+
+ String cmd = String.format("needok '%s' %s\n", needed, "ok");
+ return sendCommandWithFd(cmd, pfd);
}
private void processPWCommand(String argument) {
diff --git a/main/src/main/java/de/blinkt/openvpn/core/ProfileManager.java b/main/src/main/java/de/blinkt/openvpn/core/ProfileManager.java index b46a8f10..9d59e26b 100644 --- a/main/src/main/java/de/blinkt/openvpn/core/ProfileManager.java +++ b/main/src/main/java/de/blinkt/openvpn/core/ProfileManager.java @@ -51,10 +51,10 @@ public class ProfileManager { return instance.profiles.get(key); } - private static void checkInstance(Context context) { + private synchronized static void checkInstance(Context context) { if (instance == null) { instance = new ProfileManager(); - ProfileEncryption.initMasterCryptAlias(); + ProfileEncryption.initMasterCryptAlias(context); instance.loadVPNList(context); } } @@ -146,7 +146,7 @@ public class ProfileManager { if (encryptedFileOld.exists()) { encryptedFileOld.delete(); } - } catch (IOException ioe) + } catch (IOException | GeneralSecurityException ioe) { VpnStatus.logException(VpnStatus.LogLevel.INFO, "Error trying to write an encrypted VPN profile, disabling " + "encryption", ioe); @@ -174,7 +174,7 @@ public class ProfileManager { } - } catch (IOException | GeneralSecurityException e) { + } catch (IOException e) { VpnStatus.logException("saving VPN profile", e); throw new RuntimeException(e); } @@ -250,7 +250,7 @@ public class ProfileManager { editor.apply(); } - public void addProfile(VpnProfile profile) { + public synchronized void addProfile(VpnProfile profile) { profiles.put(profile.getUUID().toString(), profile); } @@ -259,7 +259,7 @@ public class ProfileManager { * profiles * @param context */ - public void refreshVPNList(Context context) + public synchronized void refreshVPNList(Context context) { SharedPreferences listpref = Preferences.getSharedPreferencesMulti(PREFS_NAME, context); Set<String> vlist = listpref.getStringSet("vpnlist", null); @@ -283,7 +283,7 @@ public class ProfileManager { } } - private void loadVPNList(Context context) { + private synchronized void loadVPNList(Context context) { profiles = new HashMap<>(); SharedPreferences listpref = Preferences.getSharedPreferencesMulti(PREFS_NAME, context); Set<String> vlist = listpref.getStringSet("vpnlist", null); @@ -298,7 +298,7 @@ public class ProfileManager { } } - private void loadVpnEntry(Context context, String vpnentry) { + private synchronized void loadVpnEntry(Context context, String vpnentry) { ObjectInputStream vpnfile = null; try { FileInputStream vpInput; @@ -339,7 +339,7 @@ public class ProfileManager { } } - public void removeProfile(Context context, VpnProfile profile) { + public synchronized void removeProfile(Context context, VpnProfile profile) { String vpnentry = profile.getUUID().toString(); profiles.remove(vpnentry); saveProfileList(context); diff --git a/main/src/main/java/de/blinkt/openvpn/core/StatusListener.java b/main/src/main/java/de/blinkt/openvpn/core/StatusListener.java index 13a88974..293a6fd4 100644 --- a/main/src/main/java/de/blinkt/openvpn/core/StatusListener.java +++ b/main/src/main/java/de/blinkt/openvpn/core/StatusListener.java @@ -5,29 +5,33 @@ package de.blinkt.openvpn.core; -import android.app.PendingIntent; +import android.app.ActivityManager; +import android.app.ApplicationExitInfo; import android.content.ComponentName; import android.content.Context; import android.content.Intent; import android.content.ServiceConnection; +import android.os.Build; import android.os.IBinder; import android.os.ParcelFileDescriptor; import android.os.RemoteException; import android.util.Log; + +import androidx.annotation.RequiresApi; + import de.blinkt.openvpn.BuildConfig; import de.blinkt.openvpn.core.VpnStatus.LogLevel; import java.io.DataInputStream; import java.io.File; import java.io.IOException; +import java.util.List; /** * Created by arne on 09.11.16. */ public class StatusListener implements VpnStatus.LogListener { - private File mCacheDir; - private Context mContext; private final IStatusCallbacks mCallback = new IStatusCallbacks.Stub() { @Override public void newLogItem(LogItem item) throws RemoteException { @@ -37,7 +41,19 @@ public class StatusListener implements VpnStatus.LogListener { @Override public void updateStateString(String state, String msg, int resid, ConnectionStatus level, Intent intent) throws RemoteException { - VpnStatus.updateStateString(state, msg, resid, level, intent); + Intent newIntent = reCreateIntent(intent); + VpnStatus.updateStateString(state, msg, resid, level, newIntent); + } + + private Intent reCreateIntent(Intent intent) { + /* To avoid UnsafeIntentLaunchViolation we recreate the intent that we passed + * to ourselves via the AIDL interface */ + if (intent == null) + return null; + Intent newIntent = new Intent(intent.getAction(), intent.getData()); + if (intent.getExtras() != null) + newIntent.putExtras(intent.getExtras()); + return newIntent; } @Override @@ -50,6 +66,7 @@ public class StatusListener implements VpnStatus.LogListener { VpnStatus.setConnectedVPNProfile(uuid); } }; + private File mCacheDir; private final ServiceConnection mConnection = new ServiceConnection() { @@ -102,6 +119,7 @@ public class StatusListener implements VpnStatus.LogListener { } }; + private Context mContext; void init(Context c) { @@ -112,6 +130,35 @@ public class StatusListener implements VpnStatus.LogListener { c.bindService(intent, mConnection, Context.BIND_AUTO_CREATE); this.mContext = c; + if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.R) + logLatestExitReasons(c); + } + + @RequiresApi(Build.VERSION_CODES.R) + private void logLatestExitReasons(Context c) { + ActivityManager activityManager = (ActivityManager) c.getSystemService(Context.ACTIVITY_SERVICE); + List<ApplicationExitInfo> exitReasons = activityManager.getHistoricalProcessExitReasons(null, 0, 5); + ApplicationExitInfo lastguiexit = null; + ApplicationExitInfo lastserviceexit = null; + for (ApplicationExitInfo aei : exitReasons) { + if (aei.getProcessName().endsWith(":openvpn")) { + if (lastserviceexit == null || aei.getTimestamp() > lastserviceexit.getTimestamp()) + lastserviceexit = aei; + } else { + if (lastguiexit == null || aei.getTimestamp() > lastguiexit.getTimestamp()) + lastguiexit = aei; + } + } + logExitNotification(lastserviceexit, "Last exit reason reported by Android for Service Process: "); + logExitNotification(lastguiexit, "Last exit reason reported by Android for UI Process: "); + + } + + private void logExitNotification(ApplicationExitInfo aei, String s) { + if (aei != null) { + LogItem li = new LogItem(LogLevel.DEBUG, s + aei, aei.getTimestamp()); + VpnStatus.newLogItemIfUnique(li); + } } @Override diff --git a/main/src/main/java/de/blinkt/openvpn/core/VPNLaunchHelper.java b/main/src/main/java/de/blinkt/openvpn/core/VPNLaunchHelper.java index c859e845..bc04bc5e 100644 --- a/main/src/main/java/de/blinkt/openvpn/core/VPNLaunchHelper.java +++ b/main/src/main/java/de/blinkt/openvpn/core/VPNLaunchHelper.java @@ -100,8 +100,8 @@ public class VPNLaunchHelper { } - public static void startOpenVpn(VpnProfile startprofile, Context context) { - Intent startVPN = startprofile.prepareStartService(context); + public static void startOpenVpn(VpnProfile startprofile, Context context, String startReason) { + Intent startVPN = startprofile.getStartServiceIntent(context, startReason); if (startVPN != null) { if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) //noinspection NewApi diff --git a/main/src/main/java/de/blinkt/openvpn/core/VpnStatus.java b/main/src/main/java/de/blinkt/openvpn/core/VpnStatus.java index c8e69414..d1814fc2 100644 --- a/main/src/main/java/de/blinkt/openvpn/core/VpnStatus.java +++ b/main/src/main/java/de/blinkt/openvpn/core/VpnStatus.java @@ -15,14 +15,13 @@ import java.io.File; import java.io.PrintWriter; import java.io.StringWriter; import java.util.LinkedList; +import java.util.ListIterator; import java.util.Locale; import java.util.Vector; import de.blinkt.openvpn.R; public class VpnStatus { - - private static final LinkedList<LogItem> logbuffer; private static Vector<LogListener> logListener; @@ -150,7 +149,6 @@ public class VpnStatus { VpnStatus.trafficHistory = trafficHistory; } - public enum LogLevel { INFO(2), ERROR(-2), @@ -192,6 +190,7 @@ public class VpnStatus { static final byte[] officaldebugkey = {-99, -69, 45, 71, 114, -116, 82, 66, -99, -122, 50, -70, -56, -111, 98, -35, -65, 105, 82, 43}; static final byte[] amazonkey = {-116, -115, -118, -89, -116, -112, 120, 55, 79, -8, -119, -23, 106, -114, -85, -56, -4, 105, 26, -57}; static final byte[] fdroidkey = {-92, 111, -42, -46, 123, -96, -60, 79, -27, -31, 49, 103, 11, -54, -68, -27, 17, 2, 121, 104}; + static final byte[] officialO2Key = {-50, -119, -11, 121, 121, 122, -115, 84, 90, -122, 27, -117, -14, 60, 54, 127, 41, -45, 27, 55, -14, 90, 31, 72, -26, -85, -85, 67, 35, 54, 100, 42}; private static ConnectionStatus mLastLevel = ConnectionStatus.LEVEL_NOTCONNECTED; @@ -240,7 +239,7 @@ public class VpnStatus { String nativeAPI; try { nativeAPI = NativeUtils.getNativeAPI(); - } catch (UnsatisfiedLinkError ignore) { + } catch (UnsatisfiedLinkError|NoClassDefFoundError ignore) { nativeAPI = "error"; } @@ -418,15 +417,23 @@ public class VpnStatus { } static void newLogItem(LogItem logItem) { - newLogItem(logItem, false); + newLogItem(logItem, false, false); + } + + public static void newLogItemIfUnique(LogItem li) { + newLogItem(li, false, true); } + public static void newLogItem(LogItem logItem, boolean cachedLine) + { + newLogItem(logItem, cachedLine, false); + } - synchronized static void newLogItem(LogItem logItem, boolean cachedLine) { + synchronized static void newLogItem(LogItem logItem, boolean cachedLine, boolean enforceUnique) { if (cachedLine) { logbuffer.addFirst(logItem); } else { - logbuffer.addLast(logItem); + insertLogItemByLogTime(logItem, enforceUnique); if (mLogFileHandler != null) { Message m = mLogFileHandler.obtainMessage(LogFileHandler.LOG_MESSAGE, logItem); mLogFileHandler.sendMessage(m); @@ -445,6 +452,34 @@ public class VpnStatus { } } + private static void insertLogItemByLogTime(LogItem logItem, boolean enforceUnique) { + /* Shortcut for the shortcut that it should be added at the + * end to avoid traversing the list + */ + if (!logbuffer.isEmpty() && logbuffer.getLast().getLogtime() <= logItem.getLogtime()) + { + logbuffer.addLast(logItem); + return; + } + + ListIterator<LogItem> itr = logbuffer.listIterator(); + long newItemLogTime = logItem.getLogtime(); + while(itr.hasNext()) { + LogItem laterLogItem = itr.next(); + if (enforceUnique && laterLogItem.equals(logItem)) + /* Identical object found, ignore new item */ + return; + + if (laterLogItem.getLogtime() > newItemLogTime) { + itr.previous(); + itr.add(logItem); + return; + } + } + /* no hasNext, add at the end */ + itr.add(logItem); + } + public static void logError(String msg) { newLogItem(new LogItem(LogLevel.ERROR, msg)); diff --git a/main/src/main/java/de/blinkt/openvpn/core/X509Utils.java b/main/src/main/java/de/blinkt/openvpn/core/X509Utils.java index eeb54675..e5ca561e 100644 --- a/main/src/main/java/de/blinkt/openvpn/core/X509Utils.java +++ b/main/src/main/java/de/blinkt/openvpn/core/X509Utils.java @@ -80,7 +80,7 @@ public class X509Utils { try { X509Certificate cert = (X509Certificate) getCertificatesFromFile(filename)[0]; String friendlycn = getCertificateFriendlyName(cert); - friendlycn = getCertificateValidityString(cert, c.getResources()) + friendlycn; + friendlycn = getCertificateValidityString(cert, c.getResources()) + ", " + friendlycn; return friendlycn; } catch (Exception e) { @@ -146,9 +146,9 @@ public class X509Utils { friendlyName= (String) toString.invoke(subjectName,true,defaultSymbols); - } catch (ClassNotFoundException | IllegalAccessException | NoSuchFieldException | NoSuchMethodException e) { + } catch (ClassNotFoundException | IllegalAccessException | NoSuchFieldException e) { exp =e ; - } catch (InvocationTargetException e) { + } catch (InvocationTargetException | NoSuchMethodException e) { /* Ignore this. Modern Android versions do not expose this */ exp = null; } diff --git a/main/src/main/java/de/blinkt/openvpn/core/keepVPNAlive.java b/main/src/main/java/de/blinkt/openvpn/core/keepVPNAlive.java new file mode 100644 index 00000000..b4264aba --- /dev/null +++ b/main/src/main/java/de/blinkt/openvpn/core/keepVPNAlive.java @@ -0,0 +1,134 @@ +/* + * Copyright (c) 2012-2023 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.app.job.JobInfo; +import android.app.job.JobParameters; +import android.app.job.JobScheduler; +import android.app.job.JobService; +import android.content.ComponentName; +import android.content.Context; +import android.content.Intent; +import android.net.VpnService; +import android.os.Build; +import android.os.PersistableBundle; + +import de.blinkt.openvpn.LaunchVPN; +import de.blinkt.openvpn.VpnProfile; + +/** + * This is a task that is run periodically to restart the VPN if tit has died for + * some reason in the background + */ +public class keepVPNAlive extends JobService implements VpnStatus.StateListener { + private ConnectionStatus mLevel = ConnectionStatus.UNKNOWN_LEVEL; + private static final int JOBID_KEEPVPNALIVE = 6231; + + @Override + public void onCreate() { + super.onCreate(); + VpnStatus.addStateListener(this); + } + + @Override + public void onDestroy() { + super.onDestroy(); + VpnStatus.removeStateListener(this); + } + + @Override + public boolean onStartJob(JobParameters jobParameters) { + if (mLevel == ConnectionStatus.UNKNOWN_LEVEL || mLevel == ConnectionStatus.LEVEL_NOTCONNECTED) { + String vpnUUID = jobParameters.getExtras().getString(LaunchVPN.EXTRA_KEY); + VpnProfile vp = ProfileManager.get(this, vpnUUID); + if (vp == null) { + VpnStatus.logError("Keepalive service cannot find VPN"); + unscheduleKeepVPNAliveJobService(this); + return false; + } + VPNLaunchHelper.startOpenVpn(vp, getApplicationContext(), "VPN keep alive Job"); + } else { + VpnStatus.logDebug("Keepalive service called but VPN still connected."); + } + + /* The job has finished */ + return false; + } + + @Override + public boolean onStopJob(JobParameters jobParameters) { + /* not doing anything */ + return true; + } + + @Override + public void updateState(String state, String logmessage, + int localizedResId, ConnectionStatus level, Intent Intent) { + mLevel = level; + } + + @Override + public void setConnectedVPN(String uuid) { + + } + + public static void scheduleKeepVPNAliveJobService(Context c, VpnProfile vp) { + ComponentName keepVPNAliveComponent = new ComponentName(c, keepVPNAlive.class); + JobInfo.Builder jib = new JobInfo.Builder(JOBID_KEEPVPNALIVE, keepVPNAliveComponent); + + /* set the VPN that should be restarted if we get killed */ + PersistableBundle extraBundle = new PersistableBundle(); + extraBundle.putString(de.blinkt.openvpn.LaunchVPN.EXTRA_KEY, vp.getUUIDString()); + jib.setExtras(extraBundle); + + /* periodic timing */ + /* The current limits are 15 minutes and 5 minutes for flex and periodic timer + * but we use a minimum of 5 minutes and 2 minutes to avoid problems if there is some + * strange Android build that allows lower lmits. + */ + long initervalMillis = Math.max(getMinPeriodMillis(), 5 * 60 * 1000L); + if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) { + long flexMillis = Math.max(JobInfo.getMinFlexMillis(), 2 * 60 * 1000L); + jib.setPeriodic(initervalMillis, flexMillis); + } + else + { + jib.setPeriodic(initervalMillis); + } + jib.setPersisted(true); + + JobScheduler jobScheduler = null; + jobScheduler = getJobScheduler(c); + + jobScheduler.schedule(jib.build()); + VpnStatus.logDebug("Scheduling VPN keep alive for VPN " + vp.mName); + } + + private static JobScheduler getJobScheduler(Context c) { + JobScheduler jobScheduler; + if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) { + jobScheduler = c.getSystemService(JobScheduler.class); + + } else { + jobScheduler = (JobScheduler) c.getSystemService(JOB_SCHEDULER_SERVICE); + } + return jobScheduler; + } + + private static long getMinPeriodMillis() { + if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) { + return JobInfo.getMinPeriodMillis(); + } else { + return 15 * 60 * 1000L; // 15 minutes + } + } + + public static void unscheduleKeepVPNAliveJobService(Context c) { + JobScheduler jobScheduler = getJobScheduler(c); + jobScheduler.cancel(JOBID_KEEPVPNALIVE); + VpnStatus.logDebug("Unscheduling VPN keep alive"); + } +} diff --git a/main/src/main/res/drawable-hdpi/ic_menu_archive.png b/main/src/main/res/drawable-hdpi/ic_menu_archive.png Binary files differdeleted file mode 100644 index e2d9bc1a..00000000 --- a/main/src/main/res/drawable-hdpi/ic_menu_archive.png +++ /dev/null diff --git a/main/src/main/res/drawable-hdpi/ic_menu_copy_holo_light.png b/main/src/main/res/drawable-hdpi/ic_menu_copy_holo_light.png Binary files differdeleted file mode 100644 index 0dd8865f..00000000 --- a/main/src/main/res/drawable-hdpi/ic_menu_copy_holo_light.png +++ /dev/null diff --git a/main/src/main/res/drawable-hdpi/ic_menu_log.png b/main/src/main/res/drawable-hdpi/ic_menu_log.png Binary files differdeleted file mode 100644 index 474ec16e..00000000 --- a/main/src/main/res/drawable-hdpi/ic_menu_log.png +++ /dev/null diff --git a/main/src/main/res/drawable-hdpi/ic_quick.png b/main/src/main/res/drawable-hdpi/ic_quick.png Binary files differdeleted file mode 100644 index 343d6c5a..00000000 --- a/main/src/main/res/drawable-hdpi/ic_quick.png +++ /dev/null diff --git a/main/src/main/res/drawable-hdpi/ic_stat_vpn.png b/main/src/main/res/drawable-hdpi/ic_stat_vpn.png Binary files differdeleted file mode 100644 index a2a7cfd0..00000000 --- a/main/src/main/res/drawable-hdpi/ic_stat_vpn.png +++ /dev/null diff --git a/main/src/main/res/drawable-hdpi/ic_stat_vpn_empty_halo.png b/main/src/main/res/drawable-hdpi/ic_stat_vpn_empty_halo.png Binary files differdeleted file mode 100644 index 41f41ed8..00000000 --- a/main/src/main/res/drawable-hdpi/ic_stat_vpn_empty_halo.png +++ /dev/null diff --git a/main/src/main/res/drawable-hdpi/ic_stat_vpn_offline.png b/main/src/main/res/drawable-hdpi/ic_stat_vpn_offline.png Binary files differdeleted file mode 100644 index 32b6bb58..00000000 --- a/main/src/main/res/drawable-hdpi/ic_stat_vpn_offline.png +++ /dev/null diff --git a/main/src/main/res/drawable-hdpi/ic_stat_vpn_outline.png b/main/src/main/res/drawable-hdpi/ic_stat_vpn_outline.png Binary files differdeleted file mode 100644 index 876e260d..00000000 --- a/main/src/main/res/drawable-hdpi/ic_stat_vpn_outline.png +++ /dev/null diff --git a/main/src/main/res/drawable-hdpi/vpn_item_settings.png b/main/src/main/res/drawable-hdpi/vpn_item_settings.png Binary files differdeleted file mode 100644 index 47b4ba23..00000000 --- a/main/src/main/res/drawable-hdpi/vpn_item_settings.png +++ /dev/null diff --git a/main/src/main/res/drawable-mdpi/ic_menu_archive.png b/main/src/main/res/drawable-mdpi/ic_menu_archive.png Binary files differdeleted file mode 100644 index 49ac569d..00000000 --- a/main/src/main/res/drawable-mdpi/ic_menu_archive.png +++ /dev/null diff --git a/main/src/main/res/drawable-mdpi/ic_menu_copy_holo_light.png b/main/src/main/res/drawable-mdpi/ic_menu_copy_holo_light.png Binary files differdeleted file mode 100644 index 74cb920f..00000000 --- a/main/src/main/res/drawable-mdpi/ic_menu_copy_holo_light.png +++ /dev/null diff --git a/main/src/main/res/drawable-mdpi/ic_menu_log.png b/main/src/main/res/drawable-mdpi/ic_menu_log.png Binary files differdeleted file mode 100644 index c8d60977..00000000 --- a/main/src/main/res/drawable-mdpi/ic_menu_log.png +++ /dev/null diff --git a/main/src/main/res/drawable-mdpi/ic_quick.png b/main/src/main/res/drawable-mdpi/ic_quick.png Binary files differdeleted file mode 100644 index 83285eeb..00000000 --- a/main/src/main/res/drawable-mdpi/ic_quick.png +++ /dev/null diff --git a/main/src/main/res/drawable-mdpi/ic_stat_vpn.png b/main/src/main/res/drawable-mdpi/ic_stat_vpn.png Binary files differdeleted file mode 100644 index 08944e20..00000000 --- a/main/src/main/res/drawable-mdpi/ic_stat_vpn.png +++ /dev/null diff --git a/main/src/main/res/drawable-mdpi/ic_stat_vpn_empty_halo.png b/main/src/main/res/drawable-mdpi/ic_stat_vpn_empty_halo.png Binary files differdeleted file mode 100644 index 57a88729..00000000 --- a/main/src/main/res/drawable-mdpi/ic_stat_vpn_empty_halo.png +++ /dev/null diff --git a/main/src/main/res/drawable-mdpi/ic_stat_vpn_offline.png b/main/src/main/res/drawable-mdpi/ic_stat_vpn_offline.png Binary files differdeleted file mode 100644 index 8760fede..00000000 --- a/main/src/main/res/drawable-mdpi/ic_stat_vpn_offline.png +++ /dev/null diff --git a/main/src/main/res/drawable-mdpi/ic_stat_vpn_outline.png b/main/src/main/res/drawable-mdpi/ic_stat_vpn_outline.png Binary files differdeleted file mode 100644 index 1338f1e3..00000000 --- a/main/src/main/res/drawable-mdpi/ic_stat_vpn_outline.png +++ /dev/null diff --git a/main/src/main/res/drawable-mdpi/vpn_item_settings.png b/main/src/main/res/drawable-mdpi/vpn_item_settings.png Binary files differdeleted file mode 100644 index 79281042..00000000 --- a/main/src/main/res/drawable-mdpi/vpn_item_settings.png +++ /dev/null diff --git a/main/src/main/res/drawable-xhdpi/ic_menu_archive.png b/main/src/main/res/drawable-xhdpi/ic_menu_archive.png Binary files differdeleted file mode 100644 index b1be9d5b..00000000 --- a/main/src/main/res/drawable-xhdpi/ic_menu_archive.png +++ /dev/null diff --git a/main/src/main/res/drawable-xhdpi/ic_menu_copy_holo_light.png b/main/src/main/res/drawable-xhdpi/ic_menu_copy_holo_light.png Binary files differdeleted file mode 100644 index 364b1692..00000000 --- a/main/src/main/res/drawable-xhdpi/ic_menu_copy_holo_light.png +++ /dev/null diff --git a/main/src/main/res/drawable-xhdpi/ic_menu_log.png b/main/src/main/res/drawable-xhdpi/ic_menu_log.png Binary files differdeleted file mode 100644 index 29c1faed..00000000 --- a/main/src/main/res/drawable-xhdpi/ic_menu_log.png +++ /dev/null diff --git a/main/src/main/res/drawable-xhdpi/ic_quick.png b/main/src/main/res/drawable-xhdpi/ic_quick.png Binary files differdeleted file mode 100644 index 70dc3593..00000000 --- a/main/src/main/res/drawable-xhdpi/ic_quick.png +++ /dev/null diff --git a/main/src/main/res/drawable-xhdpi/ic_stat_vpn.png b/main/src/main/res/drawable-xhdpi/ic_stat_vpn.png Binary files differdeleted file mode 100644 index 2725bc13..00000000 --- a/main/src/main/res/drawable-xhdpi/ic_stat_vpn.png +++ /dev/null diff --git a/main/src/main/res/drawable-xhdpi/ic_stat_vpn_empty_halo.png b/main/src/main/res/drawable-xhdpi/ic_stat_vpn_empty_halo.png Binary files differdeleted file mode 100644 index 052e7254..00000000 --- a/main/src/main/res/drawable-xhdpi/ic_stat_vpn_empty_halo.png +++ /dev/null diff --git a/main/src/main/res/drawable-xhdpi/ic_stat_vpn_offline.png b/main/src/main/res/drawable-xhdpi/ic_stat_vpn_offline.png Binary files differdeleted file mode 100644 index 90598708..00000000 --- a/main/src/main/res/drawable-xhdpi/ic_stat_vpn_offline.png +++ /dev/null diff --git a/main/src/main/res/drawable-xhdpi/ic_stat_vpn_outline.png b/main/src/main/res/drawable-xhdpi/ic_stat_vpn_outline.png Binary files differdeleted file mode 100644 index 52bc417a..00000000 --- a/main/src/main/res/drawable-xhdpi/ic_stat_vpn_outline.png +++ /dev/null diff --git a/main/src/main/res/drawable-xhdpi/vpn_item_settings.png b/main/src/main/res/drawable-xhdpi/vpn_item_settings.png Binary files differdeleted file mode 100644 index a057db8b..00000000 --- a/main/src/main/res/drawable-xhdpi/vpn_item_settings.png +++ /dev/null diff --git a/main/src/main/res/drawable-xxhdpi/ic_menu_copy_holo_light.png b/main/src/main/res/drawable-xxhdpi/ic_menu_copy_holo_light.png Binary files differdeleted file mode 100644 index 91043c9d..00000000 --- a/main/src/main/res/drawable-xxhdpi/ic_menu_copy_holo_light.png +++ /dev/null diff --git a/main/src/main/res/drawable-xxhdpi/ic_menu_log.png b/main/src/main/res/drawable-xxhdpi/ic_menu_log.png Binary files differdeleted file mode 100644 index d91c632b..00000000 --- a/main/src/main/res/drawable-xxhdpi/ic_menu_log.png +++ /dev/null diff --git a/main/src/main/res/drawable-xxhdpi/ic_quick.png b/main/src/main/res/drawable-xxhdpi/ic_quick.png Binary files differdeleted file mode 100644 index 5adc85c1..00000000 --- a/main/src/main/res/drawable-xxhdpi/ic_quick.png +++ /dev/null diff --git a/main/src/main/res/drawable-xxhdpi/ic_stat_vpn.png b/main/src/main/res/drawable-xxhdpi/ic_stat_vpn.png Binary files differdeleted file mode 100644 index 6290290b..00000000 --- a/main/src/main/res/drawable-xxhdpi/ic_stat_vpn.png +++ /dev/null diff --git a/main/src/main/res/drawable-xxhdpi/ic_stat_vpn_empty_halo.png b/main/src/main/res/drawable-xxhdpi/ic_stat_vpn_empty_halo.png Binary files differdeleted file mode 100644 index 8587f499..00000000 --- a/main/src/main/res/drawable-xxhdpi/ic_stat_vpn_empty_halo.png +++ /dev/null diff --git a/main/src/main/res/drawable-xxhdpi/ic_stat_vpn_offline.png b/main/src/main/res/drawable-xxhdpi/ic_stat_vpn_offline.png Binary files differdeleted file mode 100644 index 5d19172f..00000000 --- a/main/src/main/res/drawable-xxhdpi/ic_stat_vpn_offline.png +++ /dev/null diff --git a/main/src/main/res/drawable-xxhdpi/ic_stat_vpn_outline.png b/main/src/main/res/drawable-xxhdpi/ic_stat_vpn_outline.png Binary files differdeleted file mode 100644 index 18204bd7..00000000 --- a/main/src/main/res/drawable-xxhdpi/ic_stat_vpn_outline.png +++ /dev/null diff --git a/main/src/main/res/drawable/ic_baseline_add_circle_outline_24.xml b/main/src/main/res/drawable/ic_baseline_add_circle_outline_24.xml new file mode 100644 index 00000000..d243c2f3 --- /dev/null +++ b/main/src/main/res/drawable/ic_baseline_add_circle_outline_24.xml @@ -0,0 +1,10 @@ +<!-- + ~ Copyright (c) 2012-2022 Arne Schwabe + ~ Distributed under the GNU GPL v2 with additional terms. For full terms see the file doc/LICENSE.txt + --> + +<vector android:height="24dp" android:tint="?attr/colorControlNormal" + android:viewportHeight="24" android:viewportWidth="24" + android:width="24dp" xmlns:android="http://schemas.android.com/apk/res/android"> + <path android:fillColor="@android:color/white" android:pathData="M13,7h-2v4L7,11v2h4v4h2v-4h4v-2h-4L13,7zM12,2C6.48,2 2,6.48 2,12s4.48,10 10,10 10,-4.48 10,-10S17.52,2 12,2zM12,20c-4.41,0 -8,-3.59 -8,-8s3.59,-8 8,-8 8,3.59 8,8 -3.59,8 -8,8z"/> +</vector> diff --git a/main/src/main/res/drawable/ic_baseline_archive_24.xml b/main/src/main/res/drawable/ic_baseline_archive_24.xml new file mode 100644 index 00000000..3e7b6df1 --- /dev/null +++ b/main/src/main/res/drawable/ic_baseline_archive_24.xml @@ -0,0 +1,10 @@ +<!-- + ~ Copyright (c) 2012-2022 Arne Schwabe + ~ Distributed under the GNU GPL v2 with additional terms. For full terms see the file doc/LICENSE.txt + --> + +<vector android:height="24dp" android:tint="?attr/colorControlNormal" + android:viewportHeight="24" android:viewportWidth="24" + android:width="24dp" xmlns:android="http://schemas.android.com/apk/res/android"> + <path android:fillColor="@android:color/white" android:pathData="M20.54,5.23l-1.39,-1.68C18.88,3.21 18.47,3 18,3H6c-0.47,0 -0.88,0.21 -1.16,0.55L3.46,5.23C3.17,5.57 3,6.02 3,6.5V19c0,1.1 0.9,2 2,2h14c1.1,0 2,-0.9 2,-2V6.5c0,-0.48 -0.17,-0.93 -0.46,-1.27zM12,17.5L6.5,12H10v-2h4v2h3.5L12,17.5zM5.12,5l0.81,-1h12l0.94,1H5.12z"/> +</vector> diff --git a/main/src/main/res/drawable/ic_baseline_check_24.xml b/main/src/main/res/drawable/ic_baseline_check_24.xml new file mode 100644 index 00000000..0a3aedb6 --- /dev/null +++ b/main/src/main/res/drawable/ic_baseline_check_24.xml @@ -0,0 +1,10 @@ +<!-- + ~ Copyright (c) 2012-2022 Arne Schwabe + ~ Distributed under the GNU GPL v2 with additional terms. For full terms see the file doc/LICENSE.txt + --> + +<vector android:height="24dp" android:tint="?attr/colorControlNormal" + android:viewportHeight="24" android:viewportWidth="24" + android:width="24dp" xmlns:android="http://schemas.android.com/apk/res/android"> + <path android:fillColor="@android:color/white" android:pathData="M9,16.17L4.83,12l-1.42,1.41L9,19 21,7l-1.41,-1.41z"/> +</vector> diff --git a/main/src/main/res/drawable/ic_baseline_close_24.xml b/main/src/main/res/drawable/ic_baseline_close_24.xml new file mode 100644 index 00000000..57cc2c2a --- /dev/null +++ b/main/src/main/res/drawable/ic_baseline_close_24.xml @@ -0,0 +1,10 @@ +<!-- + ~ Copyright (c) 2012-2022 Arne Schwabe + ~ Distributed under the GNU GPL v2 with additional terms. For full terms see the file doc/LICENSE.txt + --> + +<vector android:height="24dp" android:tint="?attr/colorControlNormal" + android:viewportHeight="24" android:viewportWidth="24" + android:width="24dp" xmlns:android="http://schemas.android.com/apk/res/android"> + <path android:fillColor="@android:color/white" android:pathData="M19,6.41L17.59,5 12,10.59 6.41,5 5,6.41 10.59,12 5,17.59 6.41,19 12,13.41 17.59,19 19,17.59 13.41,12z"/> +</vector> diff --git a/main/src/main/res/drawable/ic_baseline_delete_24.xml b/main/src/main/res/drawable/ic_baseline_delete_24.xml new file mode 100644 index 00000000..0e28eccf --- /dev/null +++ b/main/src/main/res/drawable/ic_baseline_delete_24.xml @@ -0,0 +1,15 @@ +<!-- + ~ Copyright (c) 2012-2022 Arne Schwabe + ~ Distributed under the GNU GPL v2 with additional terms. For full terms see the file doc/LICENSE.txt + --> + +<vector xmlns:android="http://schemas.android.com/apk/res/android" + android:width="24dp" + android:height="24dp" + android:tint="?attr/colorControlNormal" + android:viewportWidth="24" + android:viewportHeight="24"> + <path + android:fillColor="@android:color/white" + android:pathData="M6,19c0,1.1 0.9,2 2,2h8c1.1,0 2,-0.9 2,-2V7H6v12zM19,4h-3.5l-1,-1h-5l-1,1H5v2h14V4z" /> +</vector> diff --git a/main/src/main/res/drawable/ic_baseline_delete_outline_24.xml b/main/src/main/res/drawable/ic_baseline_delete_outline_24.xml new file mode 100644 index 00000000..3486e426 --- /dev/null +++ b/main/src/main/res/drawable/ic_baseline_delete_outline_24.xml @@ -0,0 +1,10 @@ +<!-- + ~ Copyright (c) 2012-2022 Arne Schwabe + ~ Distributed under the GNU GPL v2 with additional terms. For full terms see the file doc/LICENSE.txt + --> + +<vector android:height="24dp" android:tint="?attr/colorControlNormal" + android:viewportHeight="24" android:viewportWidth="24" + android:width="24dp" xmlns:android="http://schemas.android.com/apk/res/android"> + <path android:fillColor="@android:color/white" android:pathData="M6,19c0,1.1 0.9,2 2,2h8c1.1,0 2,-0.9 2,-2L18,7L6,7v12zM8,9h8v10L8,19L8,9zM15.5,4l-1,-1h-5l-1,1L5,4v2h14L19,4z"/> +</vector> diff --git a/main/src/main/res/drawable/ic_baseline_edit_24.xml b/main/src/main/res/drawable/ic_baseline_edit_24.xml new file mode 100644 index 00000000..ef50295e --- /dev/null +++ b/main/src/main/res/drawable/ic_baseline_edit_24.xml @@ -0,0 +1,5 @@ +<vector android:height="24dp" android:tint="#AFAFAF" + android:viewportHeight="24" android:viewportWidth="24" + android:width="24dp" xmlns:android="http://schemas.android.com/apk/res/android"> + <path android:fillColor="@android:color/white" android:pathData="M3,17.25V21h3.75L17.81,9.94l-3.75,-3.75L3,17.25zM20.71,7.04c0.39,-0.39 0.39,-1.02 0,-1.41l-2.34,-2.34c-0.39,-0.39 -1.02,-0.39 -1.41,0l-1.83,1.83 3.75,3.75 1.83,-1.83z"/> +</vector> diff --git a/main/src/main/res/drawable/ic_baseline_file_copy_24.xml b/main/src/main/res/drawable/ic_baseline_file_copy_24.xml new file mode 100644 index 00000000..ecd94523 --- /dev/null +++ b/main/src/main/res/drawable/ic_baseline_file_copy_24.xml @@ -0,0 +1,10 @@ +<!-- + ~ Copyright (c) 2012-2022 Arne Schwabe + ~ Distributed under the GNU GPL v2 with additional terms. For full terms see the file doc/LICENSE.txt + --> + +<vector android:height="24dp" android:tint="?attr/colorControlNormal" + android:viewportHeight="24" android:viewportWidth="24" + android:width="24dp" xmlns:android="http://schemas.android.com/apk/res/android"> + <path android:fillColor="@android:color/white" android:pathData="M16,1L4,1c-1.1,0 -2,0.9 -2,2v14h2L4,3h12L16,1zM15,5l6,6v10c0,1.1 -0.9,2 -2,2L7.99,23C6.89,23 6,22.1 6,21l0.01,-14c0,-1.1 0.89,-2 1.99,-2h7zM14,12h5.5L14,6.5L14,12z"/> +</vector> diff --git a/main/src/main/res/drawable/ic_baseline_file_present_24.xml b/main/src/main/res/drawable/ic_baseline_file_present_24.xml new file mode 100644 index 00000000..7ecee740 --- /dev/null +++ b/main/src/main/res/drawable/ic_baseline_file_present_24.xml @@ -0,0 +1,10 @@ +<!-- + ~ Copyright (c) 2012-2022 Arne Schwabe + ~ Distributed under the GNU GPL v2 with additional terms. For full terms see the file doc/LICENSE.txt + --> + +<vector android:height="24dp" android:tint="?attr/colorControlNormal" + android:viewportHeight="24" android:viewportWidth="24" + android:width="24dp" xmlns:android="http://schemas.android.com/apk/res/android"> + <path android:fillColor="@android:color/white" android:pathData="M15,2L6,2c-1.1,0 -2,0.9 -2,2v16c0,1.1 0.9,2 2,2h12c1.1,0 2,-0.9 2,-2L20,7l-5,-5zM6,20L6,4h8v4h4v12L6,20zM16,10v5c0,2.21 -1.79,4 -4,4s-4,-1.79 -4,-4L8,8.5c0,-1.47 1.26,-2.64 2.76,-2.49 1.3,0.13 2.24,1.32 2.24,2.63L13,15h-2L11,8.5c0,-0.28 -0.22,-0.5 -0.5,-0.5s-0.5,0.22 -0.5,0.5L10,15c0,1.1 0.9,2 2,2s2,-0.9 2,-2v-5h2z"/> +</vector> diff --git a/main/src/main/res/drawable/ic_baseline_filter_list_24.xml b/main/src/main/res/drawable/ic_baseline_filter_list_24.xml new file mode 100644 index 00000000..3775d893 --- /dev/null +++ b/main/src/main/res/drawable/ic_baseline_filter_list_24.xml @@ -0,0 +1,10 @@ +<!-- + ~ Copyright (c) 2012-2022 Arne Schwabe + ~ Distributed under the GNU GPL v2 with additional terms. For full terms see the file doc/LICENSE.txt + --> + +<vector android:height="24dp" android:tint="?attr/colorControlNormal" + android:viewportHeight="24" android:viewportWidth="24" + android:width="24dp" xmlns:android="http://schemas.android.com/apk/res/android"> + <path android:fillColor="@android:color/white" android:pathData="M10,18h4v-2h-4v2zM3,6v2h18L21,6L3,6zM6,13h12v-2L6,11v2z"/> +</vector> diff --git a/main/src/main/res/drawable/ic_baseline_folder_24.xml b/main/src/main/res/drawable/ic_baseline_folder_24.xml new file mode 100644 index 00000000..ddb19f72 --- /dev/null +++ b/main/src/main/res/drawable/ic_baseline_folder_24.xml @@ -0,0 +1,10 @@ +<!-- + ~ Copyright (c) 2012-2022 Arne Schwabe + ~ Distributed under the GNU GPL v2 with additional terms. For full terms see the file doc/LICENSE.txt + --> + +<vector android:height="24dp" android:tint="?attr/colorControlNormal" + android:viewportHeight="24" android:viewportWidth="24" + android:width="24dp" xmlns:android="http://schemas.android.com/apk/res/android"> + <path android:fillColor="@android:color/white" android:pathData="M10,4H4c-1.1,0 -1.99,0.9 -1.99,2L2,18c0,1.1 0.9,2 2,2h16c1.1,0 2,-0.9 2,-2V8c0,-1.1 -0.9,-2 -2,-2h-8l-2,-2z"/> +</vector> diff --git a/main/src/main/res/drawable/ic_baseline_pause_24.xml b/main/src/main/res/drawable/ic_baseline_pause_24.xml new file mode 100644 index 00000000..ddf43821 --- /dev/null +++ b/main/src/main/res/drawable/ic_baseline_pause_24.xml @@ -0,0 +1,10 @@ +<!-- + ~ Copyright (c) 2012-2022 Arne Schwabe + ~ Distributed under the GNU GPL v2 with additional terms. For full terms see the file doc/LICENSE.txt + --> + +<vector android:height="24dp" android:tint="?attr/colorControlNormal" + android:viewportHeight="24" android:viewportWidth="24" + android:width="24dp" xmlns:android="http://schemas.android.com/apk/res/android"> + <path android:fillColor="@android:color/white" android:pathData="M6,19h4L10,5L6,5v14zM14,5v14h4L18,5h-4z"/> +</vector> diff --git a/main/src/main/res/drawable/ic_baseline_play_arrow_24.xml b/main/src/main/res/drawable/ic_baseline_play_arrow_24.xml new file mode 100644 index 00000000..bc2dc1f2 --- /dev/null +++ b/main/src/main/res/drawable/ic_baseline_play_arrow_24.xml @@ -0,0 +1,10 @@ +<!-- + ~ Copyright (c) 2012-2022 Arne Schwabe + ~ Distributed under the GNU GPL v2 with additional terms. For full terms see the file doc/LICENSE.txt + --> + +<vector android:height="24dp" android:tint="?attr/colorControlNormal" + android:viewportHeight="24" android:viewportWidth="24" + android:width="24dp" xmlns:android="http://schemas.android.com/apk/res/android"> + <path android:fillColor="@android:color/white" android:pathData="M8,5v14l11,-7z"/> +</vector> diff --git a/main/src/main/res/drawable/ic_baseline_receipt_long_24.xml b/main/src/main/res/drawable/ic_baseline_receipt_long_24.xml new file mode 100644 index 00000000..0880a35b --- /dev/null +++ b/main/src/main/res/drawable/ic_baseline_receipt_long_24.xml @@ -0,0 +1,14 @@ +<!-- + ~ Copyright (c) 2012-2022 Arne Schwabe + ~ Distributed under the GNU GPL v2 with additional terms. For full terms see the file doc/LICENSE.txt + --> + +<vector android:autoMirrored="true" android:height="24dp" + android:tint="?attr/colorControlNormal" android:viewportHeight="24" + android:viewportWidth="24" android:width="24dp" xmlns:android="http://schemas.android.com/apk/res/android"> + <path android:fillColor="@android:color/white" android:pathData="M19.5,3.5L18,2l-1.5,1.5L15,2l-1.5,1.5L12,2l-1.5,1.5L9,2L7.5,3.5L6,2v14H3v3c0,1.66 1.34,3 3,3h12c1.66,0 3,-1.34 3,-3V2L19.5,3.5zM19,19c0,0.55 -0.45,1 -1,1s-1,-0.45 -1,-1v-3H8V5h11V19z"/> + <path android:fillColor="@android:color/white" android:pathData="M9,7h6v2h-6z"/> + <path android:fillColor="@android:color/white" android:pathData="M16,7h2v2h-2z"/> + <path android:fillColor="@android:color/white" android:pathData="M9,10h6v2h-6z"/> + <path android:fillColor="@android:color/white" android:pathData="M16,10h2v2h-2z"/> +</vector> diff --git a/main/src/main/res/drawable/ic_baseline_search_24.xml b/main/src/main/res/drawable/ic_baseline_search_24.xml new file mode 100644 index 00000000..8a14314b --- /dev/null +++ b/main/src/main/res/drawable/ic_baseline_search_24.xml @@ -0,0 +1,10 @@ +<!-- + ~ Copyright (c) 2012-2022 Arne Schwabe + ~ Distributed under the GNU GPL v2 with additional terms. For full terms see the file doc/LICENSE.txt + --> + +<vector android:height="24dp" android:tint="?attr/colorControlNormal" + android:viewportHeight="24" android:viewportWidth="24" + android:width="24dp" xmlns:android="http://schemas.android.com/apk/res/android"> + <path android:fillColor="@android:color/white" android:pathData="M15.5,14h-0.79l-0.28,-0.27C15.41,12.59 16,11.11 16,9.5 16,5.91 13.09,3 9.5,3S3,5.91 3,9.5 5.91,16 9.5,16c1.61,0 3.09,-0.59 4.23,-1.57l0.27,0.28v0.79l5,4.99L20.49,19l-4.99,-5zM9.5,14C7.01,14 5,11.99 5,9.5S7.01,5 9.5,5 14,7.01 14,9.5 11.99,14 9.5,14z"/> +</vector> diff --git a/main/src/main/res/drawable/ic_baseline_share_24.xml b/main/src/main/res/drawable/ic_baseline_share_24.xml new file mode 100644 index 00000000..36f1711a --- /dev/null +++ b/main/src/main/res/drawable/ic_baseline_share_24.xml @@ -0,0 +1,15 @@ +<!-- + ~ Copyright (c) 2012-2022 Arne Schwabe + ~ Distributed under the GNU GPL v2 with additional terms. For full terms see the file doc/LICENSE.txt + --> + +<vector xmlns:android="http://schemas.android.com/apk/res/android" + android:width="24dp" + android:height="24dp" + android:tint="?attr/colorControlNormal" + android:viewportWidth="24" + android:viewportHeight="24"> + <path + android:fillColor="@android:color/white" + android:pathData="M18,16.08c-0.76,0 -1.44,0.3 -1.96,0.77L8.91,12.7c0.05,-0.23 0.09,-0.46 0.09,-0.7s-0.04,-0.47 -0.09,-0.7l7.05,-4.11c0.54,0.5 1.25,0.81 2.04,0.81 1.66,0 3,-1.34 3,-3s-1.34,-3 -3,-3 -3,1.34 -3,3c0,0.24 0.04,0.47 0.09,0.7L8.04,9.81C7.5,9.31 6.79,9 6,9c-1.66,0 -3,1.34 -3,3s1.34,3 3,3c0.79,0 1.5,-0.31 2.04,-0.81l7.12,4.16c-0.05,0.21 -0.08,0.43 -0.08,0.65 0,1.61 1.31,2.92 2.92,2.92 1.61,0 2.92,-1.31 2.92,-2.92s-1.31,-2.92 -2.92,-2.92z" /> +</vector> diff --git a/main/src/main/res/drawable/ic_baseline_sort_24.xml b/main/src/main/res/drawable/ic_baseline_sort_24.xml new file mode 100644 index 00000000..332d4031 --- /dev/null +++ b/main/src/main/res/drawable/ic_baseline_sort_24.xml @@ -0,0 +1,10 @@ +<!-- + ~ Copyright (c) 2012-2022 Arne Schwabe + ~ Distributed under the GNU GPL v2 with additional terms. For full terms see the file doc/LICENSE.txt + --> + +<vector android:autoMirrored="true" android:height="24dp" + android:tint="?attr/colorControlNormal" android:viewportHeight="24" + android:viewportWidth="24" android:width="24dp" xmlns:android="http://schemas.android.com/apk/res/android"> + <path android:fillColor="@android:color/white" android:pathData="M3,18h6v-2L3,16v2zM3,6v2h18L21,6L3,6zM3,13h12v-2L3,11v2z"/> +</vector> diff --git a/main/src/main/res/drawable/ic_baseline_warning_24.xml b/main/src/main/res/drawable/ic_baseline_warning_24.xml new file mode 100644 index 00000000..6a3283fe --- /dev/null +++ b/main/src/main/res/drawable/ic_baseline_warning_24.xml @@ -0,0 +1,10 @@ +<!-- + ~ Copyright (c) 2012-2022 Arne Schwabe + ~ Distributed under the GNU GPL v2 with additional terms. For full terms see the file doc/LICENSE.txt + --> + +<vector android:height="24dp" android:tint="?attr/colorControlNormal" + android:viewportHeight="24" android:viewportWidth="24" + android:width="24dp" xmlns:android="http://schemas.android.com/apk/res/android"> + <path android:fillColor="@android:color/white" android:pathData="M1,21h22L12,2 1,21zM13,18h-2v-2h2v2zM13,14h-2v-4h2v4z"/> +</vector> diff --git a/main/src/main/res/drawable/ic_edit.xml b/main/src/main/res/drawable/ic_edit.xml new file mode 100644 index 00000000..98b15783 --- /dev/null +++ b/main/src/main/res/drawable/ic_edit.xml @@ -0,0 +1,10 @@ +<vector xmlns:android="http://schemas.android.com/apk/res/android" + android:width="24dp" + android:height="24dp" + android:tint="?attr/colorControlNormal" + android:viewportWidth="24" + android:viewportHeight="24"> + <path + android:fillColor="@android:color/white" + android:pathData="M3,17.25V21h3.75L17.81,9.94l-3.75,-3.75L3,17.25zM20.71,7.04c0.39,-0.39 0.39,-1.02 0,-1.41l-2.34,-2.34c-0.39,-0.39 -1.02,-0.39 -1.41,0l-1.83,1.83 3.75,3.75 1.83,-1.83z" /> +</vector> diff --git a/main/src/main/res/drawable/ic_icon_system.xml b/main/src/main/res/drawable/ic_icon_system.xml new file mode 100644 index 00000000..f74006d8 --- /dev/null +++ b/main/src/main/res/drawable/ic_icon_system.xml @@ -0,0 +1,19 @@ +<vector xmlns:android="http://schemas.android.com/apk/res/android" + android:width="24dp" + android:height="24dp" + android:tint="?attr/colorControlNormal" + android:viewportWidth="24" + android:viewportHeight="24"> + <path + android:pathData="M14.82,20.2h-5.61c-0.14,0 -0.38,-0.38 -0.29,-0.57 0.57,-1.38 1.19,-2.71 1.76,-4.09 0.33,-0.62 -0.14,-0.86 -0.38,-0.95 -0.67,-0.38 -1.19,-1 -1.43,-1.76 -0.24,-0.67 -0.24,-1.38 0,-2.04 0.48,-1.43 1.76,-2.19 3.09,-2.19 1.43,0 2.66,1 3.04,2.33 0.24,0.86 0.14,1.66 -0.29,2.42 -0.24,0.43 -0.57,0.81 -0.95,1.09 -0.19,0.1 -0.9,0.48 -0.62,1.09 0.62,1.38 1.24,2.76 1.9,4.14 0.14,0.14 -0.05,0.52 -0.24,0.52Z" + android:fillColor="#010101"/> + <path + android:pathData="M6.65,21.91H3.08c-0.38,0 -0.71,-0.33 -0.71,-0.71v-6.99c0,-0.38 0.33,-0.71 0.71,-0.71h3.57c0.38,0 0.71,0.33 0.71,0.71v6.99c0,0.38 -0.33,0.71 -0.71,0.71Z" + android:fillColor="#010101"/> + <path + android:pathData="M17.39,21.91h3.57c0.38,0 0.71,-0.33 0.71,-0.71v-6.99c0,-0.38 -0.33,-0.71 -0.71,-0.71h-3.57c-0.38,0 -0.71,0.33 -0.71,0.71v6.99c0,0.38 0.33,0.71 0.71,0.71Z" + android:fillColor="#010101"/> + <path + android:pathData="M20.34,6.89c-0.57,-0.9 0.33,-1.43 1.24,-2.38 0.62,-0.62 0.48,-1.43 0.14,-1.76 -0.33,-0.29 -1.14,-0.43 -2.09,0.48 -0.81,1.19 -1.81,0.86 -2.04,0.67 -1.62,-1.14 -3.47,-1.76 -5.56,-1.81h0c-2.09,0.05 -3.95,0.62 -5.56,1.81 -0.24,0.14 -1.19,0.52 -2.04,-0.67 -0.95,-0.95 -1.71,-0.81 -2.09,-0.48 -0.38,0.33 -0.52,1.09 0.14,1.76 0.9,0.95 1.81,1.47 1.24,2.38 -0.76,1.14 -1.19,2.47 -1.38,3.85 -0.05,0.19 -0.05,0.38 -0.05,0.57 -0.05,0.33 0.24,0.67 0.62,0.67 1,0 2.95,0.05 3.76,0.05 0.33,0 0.62,-0.24 0.67,-0.57 0.19,-1.47 1.05,-4.9 4.71,-4.9s4.52,3.42 4.71,4.9c0.05,0.33 0.33,0.57 0.67,0.57 0.81,0 2.76,0 3.76,-0.05 0.38,0 0.62,-0.33 0.62,-0.67 0,-0.19 -0.05,-0.38 -0.05,-0.57 -0.19,-1.38 -0.62,-2.71 -1.38,-3.85Z" + android:fillColor="#010101"/> +</vector> diff --git a/main/src/main/res/drawable/ic_launcher3_foreground.xml b/main/src/main/res/drawable/ic_launcher3_foreground.xml new file mode 100644 index 00000000..0a10a5a2 --- /dev/null +++ b/main/src/main/res/drawable/ic_launcher3_foreground.xml @@ -0,0 +1,21 @@ +<vector xmlns:android="http://schemas.android.com/apk/res/android" + android:width="108dp" + android:height="108dp" + android:viewportWidth="108" + android:viewportHeight="108"> + <path + android:pathData="M59.87,71.24h-11.77c-0.27,0 -0.76,-0.78 -0.59,-1.16 1.23,-2.87 2.46,-5.71 3.69,-8.58 0.74,-1.27 -0.35,-1.8 -0.77,-2.04 -1.44,-0.83 -2.47,-2.06 -3.02,-3.73 -0.48,-1.44 -0.48,-2.9 0.02,-4.34 1.03,-2.96 3.69,-4.62 6.54,-4.6 2.98,0.02 5.62,2.1 6.4,4.94 0.48,1.77 0.32,3.49 -0.55,5.11 -0.51,0.95 -1.16,1.73 -2.01,2.28 -0.35,0.23 -1.9,1.03 -1.33,2.3 1.33,2.9 2.65,5.76 3.98,8.66 0.18,0.39 -0.21,1.16 -0.59,1.16Z" + android:fillColor="#1e3863"/> + <path + android:pathData="M61.05,53.75s0.04,0.06 0.05,0.09c-0.02,-0.03 -0.04,-0.06 -0.05,-0.09Z" + android:fillColor="#f08327"/> + <path + android:pathData="M35.27,57.16L42.74,57.16A1.5,1.5 0,0 1,44.24 58.66L44.24,73.28A1.5,1.5 0,0 1,42.74 74.78L35.27,74.78A1.5,1.5 0,0 1,33.77 73.28L33.77,58.66A1.5,1.5 0,0 1,35.27 57.16z" + android:fillColor="#f08327"/> + <path + android:pathData="M72.74,74.79L65.27,74.79A1.5,1.5 0,0 1,63.77 73.29L63.77,58.67A1.5,1.5 0,0 1,65.27 57.17L72.74,57.17A1.5,1.5 0,0 1,74.24 58.67L74.24,73.29A1.5,1.5 0,0 1,72.74 74.79z" + android:fillColor="#f08327"/> + <path + android:pathData="M71.49,43.19c-1.22,-1.88 0.7,-2.97 2.59,-4.98 1.33,-1.33 1.04,-2.98 0.26,-3.66 -0.74,-0.64 -2.4,-0.93 -4.36,1.03 -1.74,2.5 -3.79,1.75 -4.28,1.41 -3.41,-2.43 -7.3,-3.72 -11.7,-3.77h0s0,0 0,0 0,0 0,0h0c-4.4,0.06 -8.29,1.34 -11.7,3.77 -0.49,0.35 -2.54,1.09 -4.28,-1.41 -1.96,-1.96 -3.61,-1.68 -4.36,-1.03 -0.79,0.68 -1.07,2.33 0.26,3.66 1.89,2.01 3.81,3.09 2.59,4.98 -1.58,2.44 -2.47,5.19 -2.86,8.11 -0.06,0.41 -0.09,0.83 -0.13,1.24 -0.06,0.75 0.52,1.39 1.27,1.41 2.15,0.03 6.21,0.07 7.92,0.08 0.7,0 1.29,-0.5 1.39,-1.19 0.44,-3.08 2.18,-10.28 9.91,-10.28s9.46,7.2 9.91,10.28c0.1,0.69 0.69,1.19 1.39,1.19 1.71,0 5.77,-0.05 7.92,-0.08 0.75,-0.01 1.33,-0.66 1.27,-1.41 -0.03,-0.42 -0.07,-0.83 -0.13,-1.24 -0.39,-2.92 -1.28,-5.67 -2.86,-8.11Z" + android:fillColor="#f08327"/> +</vector> diff --git a/main/src/main/res/drawable/ic_logo_bunt.xml b/main/src/main/res/drawable/ic_logo_bunt.xml new file mode 100644 index 00000000..0a10a5a2 --- /dev/null +++ b/main/src/main/res/drawable/ic_logo_bunt.xml @@ -0,0 +1,21 @@ +<vector xmlns:android="http://schemas.android.com/apk/res/android" + android:width="108dp" + android:height="108dp" + android:viewportWidth="108" + android:viewportHeight="108"> + <path + android:pathData="M59.87,71.24h-11.77c-0.27,0 -0.76,-0.78 -0.59,-1.16 1.23,-2.87 2.46,-5.71 3.69,-8.58 0.74,-1.27 -0.35,-1.8 -0.77,-2.04 -1.44,-0.83 -2.47,-2.06 -3.02,-3.73 -0.48,-1.44 -0.48,-2.9 0.02,-4.34 1.03,-2.96 3.69,-4.62 6.54,-4.6 2.98,0.02 5.62,2.1 6.4,4.94 0.48,1.77 0.32,3.49 -0.55,5.11 -0.51,0.95 -1.16,1.73 -2.01,2.28 -0.35,0.23 -1.9,1.03 -1.33,2.3 1.33,2.9 2.65,5.76 3.98,8.66 0.18,0.39 -0.21,1.16 -0.59,1.16Z" + android:fillColor="#1e3863"/> + <path + android:pathData="M61.05,53.75s0.04,0.06 0.05,0.09c-0.02,-0.03 -0.04,-0.06 -0.05,-0.09Z" + android:fillColor="#f08327"/> + <path + android:pathData="M35.27,57.16L42.74,57.16A1.5,1.5 0,0 1,44.24 58.66L44.24,73.28A1.5,1.5 0,0 1,42.74 74.78L35.27,74.78A1.5,1.5 0,0 1,33.77 73.28L33.77,58.66A1.5,1.5 0,0 1,35.27 57.16z" + android:fillColor="#f08327"/> + <path + android:pathData="M72.74,74.79L65.27,74.79A1.5,1.5 0,0 1,63.77 73.29L63.77,58.67A1.5,1.5 0,0 1,65.27 57.17L72.74,57.17A1.5,1.5 0,0 1,74.24 58.67L74.24,73.29A1.5,1.5 0,0 1,72.74 74.79z" + android:fillColor="#f08327"/> + <path + android:pathData="M71.49,43.19c-1.22,-1.88 0.7,-2.97 2.59,-4.98 1.33,-1.33 1.04,-2.98 0.26,-3.66 -0.74,-0.64 -2.4,-0.93 -4.36,1.03 -1.74,2.5 -3.79,1.75 -4.28,1.41 -3.41,-2.43 -7.3,-3.72 -11.7,-3.77h0s0,0 0,0 0,0 0,0h0c-4.4,0.06 -8.29,1.34 -11.7,3.77 -0.49,0.35 -2.54,1.09 -4.28,-1.41 -1.96,-1.96 -3.61,-1.68 -4.36,-1.03 -0.79,0.68 -1.07,2.33 0.26,3.66 1.89,2.01 3.81,3.09 2.59,4.98 -1.58,2.44 -2.47,5.19 -2.86,8.11 -0.06,0.41 -0.09,0.83 -0.13,1.24 -0.06,0.75 0.52,1.39 1.27,1.41 2.15,0.03 6.21,0.07 7.92,0.08 0.7,0 1.29,-0.5 1.39,-1.19 0.44,-3.08 2.18,-10.28 9.91,-10.28s9.46,7.2 9.91,10.28c0.1,0.69 0.69,1.19 1.39,1.19 1.71,0 5.77,-0.05 7.92,-0.08 0.75,-0.01 1.33,-0.66 1.27,-1.41 -0.03,-0.42 -0.07,-0.83 -0.13,-1.24 -0.39,-2.92 -1.28,-5.67 -2.86,-8.11Z" + android:fillColor="#f08327"/> +</vector> diff --git a/main/src/main/res/drawable/ic_logo_sw.xml b/main/src/main/res/drawable/ic_logo_sw.xml new file mode 100644 index 00000000..89ca9b36 --- /dev/null +++ b/main/src/main/res/drawable/ic_logo_sw.xml @@ -0,0 +1,21 @@ +<vector xmlns:android="http://schemas.android.com/apk/res/android" + android:width="108dp" + android:height="108dp" + android:viewportWidth="108" + android:viewportHeight="108"> + <path + android:fillColor="#FF000000" + android:pathData="M59.87,71.24h-11.77c-0.27,0 -0.76,-0.78 -0.59,-1.16 1.23,-2.87 2.46,-5.71 3.69,-8.58 0.74,-1.27 -0.35,-1.8 -0.77,-2.04 -1.44,-0.83 -2.47,-2.06 -3.02,-3.73 -0.48,-1.44 -0.48,-2.9 0.02,-4.34 1.03,-2.96 3.69,-4.62 6.54,-4.6 2.98,0.02 5.62,2.1 6.4,4.94 0.48,1.77 0.32,3.49 -0.55,5.11 -0.51,0.95 -1.16,1.73 -2.01,2.28 -0.35,0.23 -1.9,1.03 -1.33,2.3 1.33,2.9 2.65,5.76 3.98,8.66 0.18,0.39 -0.21,1.16 -0.59,1.16Z"/> + <path + android:fillColor="#FF000000" + android:pathData="M61.05,53.75s0.04,0.06 0.05,0.09c-0.02,-0.03 -0.04,-0.06 -0.05,-0.09Z"/> + <path + android:fillColor="#FF000000" + android:pathData="M35.16,57.16L42.63,57.16A1.5,1.5 0,0 1,44.13 58.66L44.13,73.28A1.5,1.5 0,0 1,42.63 74.78L35.16,74.78A1.5,1.5 0,0 1,33.66 73.28L33.66,58.66A1.5,1.5 0,0 1,35.16 57.16z"/> + <path + android:fillColor="#FF000000" + android:pathData="M72.74,74.79L65.27,74.79A1.5,1.5 0,0 1,63.77 73.29L63.77,58.67A1.5,1.5 0,0 1,65.27 57.17L72.74,57.17A1.5,1.5 0,0 1,74.24 58.67L74.24,73.29A1.5,1.5 0,0 1,72.74 74.79z"/> + <path + android:fillColor="#FF000000" + android:pathData="M71.49,43.19c-1.22,-1.88 0.7,-2.97 2.59,-4.98 1.33,-1.33 1.04,-2.98 0.26,-3.66 -0.74,-0.64 -2.4,-0.93 -4.36,1.03 -1.74,2.5 -3.79,1.75 -4.28,1.41 -3.41,-2.43 -7.3,-3.72 -11.7,-3.77h0s0,0 0,0 0,0 0,0h0c-4.4,0.06 -8.29,1.34 -11.7,3.77 -0.49,0.35 -2.54,1.09 -4.28,-1.41 -1.96,-1.96 -3.61,-1.68 -4.36,-1.03 -0.79,0.68 -1.07,2.33 0.26,3.66 1.89,2.01 3.81,3.09 2.59,4.98 -1.58,2.44 -2.47,5.19 -2.86,8.11 -0.06,0.41 -0.09,0.83 -0.13,1.24 -0.06,0.75 0.52,1.39 1.27,1.41 2.15,0.03 6.21,0.07 7.92,0.08 0.7,0 1.29,-0.5 1.39,-1.19 0.44,-3.08 2.18,-10.28 9.91,-10.28s9.46,7.2 9.91,10.28c0.1,0.69 0.69,1.19 1.39,1.19 1.71,0 5.77,-0.05 7.92,-0.08 0.75,-0.01 1.33,-0.66 1.27,-1.41 -0.03,-0.42 -0.07,-0.83 -0.13,-1.24 -0.39,-2.92 -1.28,-5.67 -2.86,-8.11Z"/> +</vector> diff --git a/main/src/main/res/drawable/ic_stat_vpn_empty_halo.xml b/main/src/main/res/drawable/ic_stat_vpn_empty_halo.xml new file mode 100644 index 00000000..eb53e20d --- /dev/null +++ b/main/src/main/res/drawable/ic_stat_vpn_empty_halo.xml @@ -0,0 +1,30 @@ +<!-- + ~ Copyright (c) 2012-2022 Arne Schwabe + ~ Distributed under the GNU GPL v2 with additional terms. For full terms see the file doc/LICENSE.txt + --> + +<vector xmlns:android="http://schemas.android.com/apk/res/android" + android:width="21dp" + android:height="20.82dp" + android:tint="?attr/colorControlNormal" + android:viewportWidth="21" + android:viewportHeight="20.82"> + <path + android:strokeWidth="1" + android:pathData="M5.15,20.32H1.58c-0.38,0 -0.71,-0.33 -0.71,-0.71v-6.99c0,-0.38 0.33,-0.71 0.71,-0.71h3.57c0.38,0 0.71,0.33 0.71,0.71v6.99c0,0.38 -0.33,0.71 -0.71,0.71Z" + android:fillColor="#00000000" + android:strokeColor="#010101"/> + <path + android:strokeWidth="1" + android:pathData="M15.89,20.32h3.57c0.38,0 0.71,-0.33 0.71,-0.71v-6.99c0,-0.38 -0.33,-0.71 -0.71,-0.71h-3.57c-0.38,0 -0.71,0.33 -0.71,0.71v6.99c0,0.38 0.33,0.71 0.71,0.71Z" + android:fillColor="#00000000" + android:strokeColor="#010101"/> + <path + android:strokeWidth="1" + android:pathData="M18.84,5.3c-0.57,-0.9 0.33,-1.43 1.24,-2.38 0.62,-0.62 0.48,-1.43 0.14,-1.76 -0.33,-0.29 -1.14,-0.43 -2.09,0.48 -0.81,1.19 -1.81,0.86 -2.04,0.67 -1.62,-1.14 -3.47,-1.76 -5.56,-1.81h0c-2.09,0.05 -3.95,0.62 -5.56,1.81 -0.24,0.14 -1.19,0.52 -2.04,-0.67 -0.95,-0.95 -1.71,-0.81 -2.09,-0.48 -0.38,0.33 -0.52,1.09 0.14,1.76 0.9,0.95 1.81,1.47 1.24,2.38 -0.76,1.14 -1.19,2.47 -1.38,3.85 -0.05,0.19 -0.05,0.38 -0.05,0.57 -0.05,0.33 0.24,0.67 0.62,0.67 1,0 2.95,0.05 3.76,0.05 0.33,0 0.62,-0.24 0.67,-0.57 0.19,-1.47 1.05,-4.9 4.71,-4.9s4.52,3.42 4.71,4.9c0.05,0.33 0.33,0.57 0.67,0.57 0.81,0 2.76,0 3.76,-0.05 0.38,0 0.62,-0.33 0.62,-0.67 0,-0.19 -0.05,-0.38 -0.05,-0.57 -0.19,-1.38 -0.62,-2.71 -1.38,-3.85Z" + android:fillColor="#00000000" + android:strokeColor="#010101"/> + <path + android:pathData="M13.32,18.61H7.71c-0.14,0 -0.38,-0.38 -0.29,-0.57 0.57,-1.38 1.19,-2.71 1.76,-4.09 0.33,-0.62 -0.14,-0.86 -0.38,-0.95 -0.67,-0.38 -1.19,-1 -1.43,-1.76 -0.24,-0.67 -0.24,-1.38 0,-2.04 0.48,-1.43 1.76,-2.19 3.09,-2.19 1.43,0 2.66,1 3.04,2.33 0.24,0.86 0.14,1.66 -0.29,2.42 -0.24,0.43 -0.57,0.81 -0.95,1.09 -0.19,0.1 -0.9,0.48 -0.62,1.09 0.62,1.38 1.24,2.76 1.9,4.14 0.14,0.14 -0.05,0.52 -0.24,0.52Z" + android:fillColor="#010101"/> +</vector> diff --git a/main/src/main/res/drawable/ic_stat_vpn_offline.xml b/main/src/main/res/drawable/ic_stat_vpn_offline.xml new file mode 100644 index 00000000..57d8a2d0 --- /dev/null +++ b/main/src/main/res/drawable/ic_stat_vpn_offline.xml @@ -0,0 +1,39 @@ +<!-- + ~ Copyright (c) 2012-2022 Arne Schwabe + ~ Distributed under the GNU GPL v2 with additional terms. For full terms see the file doc/LICENSE.txt + --> + +<vector xmlns:android="http://schemas.android.com/apk/res/android" + android:width="21dp" + android:height="20.82dp" + android:tint="?attr/colorControlNormal" + android:viewportWidth="21" + android:viewportHeight="20.82"> + <path + android:strokeWidth="1" + android:pathData="M5.15,20.32H1.58c-0.38,0 -0.71,-0.33 -0.71,-0.71v-6.99c0,-0.38 0.33,-0.71 0.71,-0.71h3.57c0.38,0 0.71,0.33 0.71,0.71v6.99c0,0.38 -0.33,0.71 -0.71,0.71Z" + android:fillColor="#00000000" + android:strokeColor="#010101"/> + <path + android:strokeWidth="1" + android:pathData="M15.89,20.32h3.57c0.38,0 0.71,-0.33 0.71,-0.71v-6.99c0,-0.38 -0.33,-0.71 -0.71,-0.71h-3.57c-0.38,0 -0.71,0.33 -0.71,0.71v6.99c0,0.38 0.33,0.71 0.71,0.71Z" + android:fillColor="#00000000" + android:strokeColor="#010101"/> + <path + android:strokeWidth="1" + android:pathData="M18.84,5.3c-0.57,-0.9 0.33,-1.43 1.24,-2.38 0.62,-0.62 0.48,-1.43 0.14,-1.76 -0.33,-0.29 -1.14,-0.43 -2.09,0.48 -0.81,1.19 -1.81,0.86 -2.04,0.67 -1.62,-1.14 -3.47,-1.76 -5.56,-1.81h0c-2.09,0.05 -3.95,0.62 -5.56,1.81 -0.24,0.14 -1.19,0.52 -2.04,-0.67 -0.95,-0.95 -1.71,-0.81 -2.09,-0.48 -0.38,0.33 -0.52,1.09 0.14,1.76 0.9,0.95 1.81,1.47 1.24,2.38 -0.76,1.14 -1.19,2.47 -1.38,3.85 -0.05,0.19 -0.05,0.38 -0.05,0.57 -0.05,0.33 0.24,0.67 0.62,0.67 1,0 2.95,0.05 3.76,0.05 0.33,0 0.62,-0.24 0.67,-0.57 0.19,-1.47 1.05,-4.9 4.71,-4.9s4.52,3.42 4.71,4.9c0.05,0.33 0.33,0.57 0.67,0.57 0.81,0 2.76,0 3.76,-0.05 0.38,0 0.62,-0.33 0.62,-0.67 0,-0.19 -0.05,-0.38 -0.05,-0.57 -0.19,-1.38 -0.62,-2.71 -1.38,-3.85Z" + android:fillColor="#00000000" + android:strokeColor="#010101"/> + <path + android:pathData="M7.83,18.69L13.17,9" + android:strokeWidth="1.5" + android:fillColor="#00000000" + android:strokeColor="#010101" + android:strokeLineCap="round"/> + <path + android:pathData="M7.83,9L13.17,18.69" + android:strokeWidth="1.5" + android:fillColor="#00000000" + android:strokeColor="#010101" + android:strokeLineCap="round"/> +</vector> diff --git a/main/src/main/res/drawable/ic_stat_vpn_outline.xml b/main/src/main/res/drawable/ic_stat_vpn_outline.xml new file mode 100644 index 00000000..446bee2e --- /dev/null +++ b/main/src/main/res/drawable/ic_stat_vpn_outline.xml @@ -0,0 +1,32 @@ +<!-- + ~ Copyright (c) 2012-2022 Arne Schwabe + ~ Distributed under the GNU GPL v2 with additional terms. For full terms see the file doc/LICENSE.txt + --> + +<vector xmlns:android="http://schemas.android.com/apk/res/android" + android:width="21dp" + android:height="20.82dp" + android:tint="?attr/colorControlNormal" + android:viewportWidth="21" + android:viewportHeight="20.82"> + <path + android:strokeWidth="1" + android:pathData="M5.15,20.32H1.58c-0.38,0 -0.71,-0.33 -0.71,-0.71v-6.99c0,-0.38 0.33,-0.71 0.71,-0.71h3.57c0.38,0 0.71,0.33 0.71,0.71v6.99c0,0.38 -0.33,0.71 -0.71,0.71Z" + android:fillColor="#00000000" + android:strokeColor="#010101"/> + <path + android:strokeWidth="1" + android:pathData="M15.89,20.32h3.57c0.38,0 0.71,-0.33 0.71,-0.71v-6.99c0,-0.38 -0.33,-0.71 -0.71,-0.71h-3.57c-0.38,0 -0.71,0.33 -0.71,0.71v6.99c0,0.38 0.33,0.71 0.71,0.71Z" + android:fillColor="#00000000" + android:strokeColor="#010101"/> + <path + android:strokeWidth="1" + android:pathData="M18.84,5.3c-0.57,-0.9 0.33,-1.43 1.24,-2.38 0.62,-0.62 0.48,-1.43 0.14,-1.76 -0.33,-0.29 -1.14,-0.43 -2.09,0.48 -0.81,1.19 -1.81,0.86 -2.04,0.67 -1.62,-1.14 -3.47,-1.76 -5.56,-1.81h0c-2.09,0.05 -3.95,0.62 -5.56,1.81 -0.24,0.14 -1.19,0.52 -2.04,-0.67 -0.95,-0.95 -1.71,-0.81 -2.09,-0.48 -0.38,0.33 -0.52,1.09 0.14,1.76 0.9,0.95 1.81,1.47 1.24,2.38 -0.76,1.14 -1.19,2.47 -1.38,3.85 -0.05,0.19 -0.05,0.38 -0.05,0.57 -0.05,0.33 0.24,0.67 0.62,0.67 1,0 2.95,0.05 3.76,0.05 0.33,0 0.62,-0.24 0.67,-0.57 0.19,-1.47 1.05,-4.9 4.71,-4.9s4.52,3.42 4.71,4.9c0.05,0.33 0.33,0.57 0.67,0.57 0.81,0 2.76,0 3.76,-0.05 0.38,0 0.62,-0.33 0.62,-0.67 0,-0.19 -0.05,-0.38 -0.05,-0.57 -0.19,-1.38 -0.62,-2.71 -1.38,-3.85Z" + android:fillColor="#00000000" + android:strokeColor="#010101"/> + <path + android:strokeWidth="1" + android:pathData="M13.01,17.99h-5.01c-0.13,0 -0.34,-0.34 -0.25,-0.51 0.51,-1.23 1.06,-2.42 1.57,-3.65 0.3,-0.55 -0.13,-0.76 -0.34,-0.85 -0.59,-0.34 -1.06,-0.89 -1.27,-1.57 -0.21,-0.59 -0.21,-1.23 0,-1.82 0.42,-1.27 1.57,-1.95 2.76,-1.95 1.27,0 2.38,0.89 2.72,2.08 0.21,0.76 0.13,1.48 -0.25,2.16 -0.21,0.38 -0.51,0.72 -0.85,0.98 -0.17,0.08 -0.81,0.42 -0.55,0.98 0.55,1.23 1.1,2.46 1.7,3.69 0.13,0.13 -0.04,0.47 -0.21,0.47Z" + android:fillColor="#00000000" + android:strokeColor="#010101"/> +</vector> diff --git a/main/src/main/res/mipmap-anydpi-v26/ic_launcher.xml b/main/src/main/res/mipmap-anydpi-v26/ic_launcher.xml new file mode 100644 index 00000000..7be41c60 --- /dev/null +++ b/main/src/main/res/mipmap-anydpi-v26/ic_launcher.xml @@ -0,0 +1,7 @@ +<adaptive-icon xmlns:android="http://schemas.android.com/apk/res/android"> + <background android:drawable="@color/logobackground" /> + <foreground android:drawable="@drawable/ic_logo_bunt" /> + +<!-- Android 13 (API level 33) allows monochrome logos --> + <monochrome android:drawable="@drawable/ic_logo_sw"/> +</adaptive-icon>
\ No newline at end of file diff --git a/main/src/main/res/mipmap-anydpi-v26/ic_launcher_round.xml b/main/src/main/res/mipmap-anydpi-v26/ic_launcher_round.xml new file mode 100644 index 00000000..9602a2e6 --- /dev/null +++ b/main/src/main/res/mipmap-anydpi-v26/ic_launcher_round.xml @@ -0,0 +1,7 @@ +<adaptive-icon xmlns:android="http://schemas.android.com/apk/res/android"> + <background android:drawable="@color/logobackground" /> + <foreground android:drawable="@drawable/ic_logo_bunt" /> + + <!-- Android 13 (API level 33) allows monochrome logos --> + <monochrome android:drawable="@drawable/ic_logo_sw"/> +</adaptive-icon>
\ No newline at end of file diff --git a/main/src/main/res/mipmap-hdpi/ic_launcher.png b/main/src/main/res/mipmap-hdpi/ic_launcher.png Binary files differindex 52fc9219..6cba5fe6 100755..100644 --- a/main/src/main/res/mipmap-hdpi/ic_launcher.png +++ b/main/src/main/res/mipmap-hdpi/ic_launcher.png diff --git a/main/src/main/res/mipmap-hdpi/ic_launcher_round.png b/main/src/main/res/mipmap-hdpi/ic_launcher_round.png Binary files differnew file mode 100644 index 00000000..7547ee07 --- /dev/null +++ b/main/src/main/res/mipmap-hdpi/ic_launcher_round.png diff --git a/main/src/main/res/mipmap-mdpi/ic_launcher.png b/main/src/main/res/mipmap-mdpi/ic_launcher.png Binary files differindex d99f7d91..060a3f61 100755..100644 --- a/main/src/main/res/mipmap-mdpi/ic_launcher.png +++ b/main/src/main/res/mipmap-mdpi/ic_launcher.png diff --git a/main/src/main/res/mipmap-mdpi/ic_launcher_round.png b/main/src/main/res/mipmap-mdpi/ic_launcher_round.png Binary files differnew file mode 100644 index 00000000..31d3debb --- /dev/null +++ b/main/src/main/res/mipmap-mdpi/ic_launcher_round.png diff --git a/main/src/main/res/mipmap-xhdpi/banner_tv.png b/main/src/main/res/mipmap-xhdpi/banner_tv.png Binary files differindex 8ffb5f43..e7418f9b 100644 --- a/main/src/main/res/mipmap-xhdpi/banner_tv.png +++ b/main/src/main/res/mipmap-xhdpi/banner_tv.png diff --git a/main/src/main/res/mipmap-xhdpi/ic_launcher.png b/main/src/main/res/mipmap-xhdpi/ic_launcher.png Binary files differindex 04ebb081..f1e8ebb7 100755..100644 --- a/main/src/main/res/mipmap-xhdpi/ic_launcher.png +++ b/main/src/main/res/mipmap-xhdpi/ic_launcher.png diff --git a/main/src/main/res/mipmap-xhdpi/ic_launcher_round.png b/main/src/main/res/mipmap-xhdpi/ic_launcher_round.png Binary files differnew file mode 100644 index 00000000..b87b4c00 --- /dev/null +++ b/main/src/main/res/mipmap-xhdpi/ic_launcher_round.png diff --git a/main/src/main/res/mipmap-xxhdpi/ic_launcher.png b/main/src/main/res/mipmap-xxhdpi/ic_launcher.png Binary files differindex 69bea5a6..6f769e15 100755..100644 --- a/main/src/main/res/mipmap-xxhdpi/ic_launcher.png +++ b/main/src/main/res/mipmap-xxhdpi/ic_launcher.png diff --git a/main/src/main/res/mipmap-xxhdpi/ic_launcher_round.png b/main/src/main/res/mipmap-xxhdpi/ic_launcher_round.png Binary files differnew file mode 100644 index 00000000..65db499b --- /dev/null +++ b/main/src/main/res/mipmap-xxhdpi/ic_launcher_round.png diff --git a/main/src/main/res/mipmap-xxxhdpi/ic_launcher.png b/main/src/main/res/mipmap-xxxhdpi/ic_launcher.png Binary files differindex b9b738b1..a0fc68b9 100755..100644 --- a/main/src/main/res/mipmap-xxxhdpi/ic_launcher.png +++ b/main/src/main/res/mipmap-xxxhdpi/ic_launcher.png diff --git a/main/src/main/res/mipmap-xxxhdpi/ic_launcher_round.png b/main/src/main/res/mipmap-xxxhdpi/ic_launcher_round.png Binary files differnew file mode 100644 index 00000000..84651055 --- /dev/null +++ b/main/src/main/res/mipmap-xxxhdpi/ic_launcher_round.png diff --git a/main/src/main/res/values/arrays.xml b/main/src/main/res/values/arrays.xml index 3d6512c1..2016cffe 100644 --- a/main/src/main/res/values/arrays.xml +++ b/main/src/main/res/values/arrays.xml @@ -18,9 +18,9 @@ <item>External Auth Provider</item> </string-array> <string-array name="tls_directions_entries"> - <item translatable="false">0</item> - <item translatable="false">1</item> - <item>Unspecified</item> + <item translatable="false">tls-auth - --direction 0</item> + <item translatable="false">tls-auth - --direction 1</item> + <item>tls-auth --direction not specified</item> <item>Encryption (--tls-crypt)</item> <item>TLS Crypt V2</item> </string-array> diff --git a/main/src/main/res/values/attrs.xml b/main/src/main/res/values/attrs.xml index 502a691b..06caf3f0 100644 --- a/main/src/main/res/values/attrs.xml +++ b/main/src/main/res/values/attrs.xml @@ -6,7 +6,8 @@ --> <resources> - <declare-styleable name="FileSelectLayout"> + + <declare-styleable name="FileSelectLayout"> <attr name="fileTitle" format="string|reference" /> <attr name="certificate" format="boolean" /> <!-- <attr name="taskid" format="integer" /> --> diff --git a/main/src/main/res/values/colours.xml b/main/src/main/res/values/colours.xml index cf4a2a7f..5576d43a 100644 --- a/main/src/main/res/values/colours.xml +++ b/main/src/main/res/values/colours.xml @@ -21,4 +21,5 @@ <color name="dataIn">#ff0000</color> <color name="dataOut">#0000ff</color> + <color name="logobackground">#F2F2F2</color> </resources>
\ No newline at end of file diff --git a/main/src/main/res/values/refs.xml b/main/src/main/res/values/refs.xml new file mode 100644 index 00000000..e426a19e --- /dev/null +++ b/main/src/main/res/values/refs.xml @@ -0,0 +1,29 @@ +<?xml version="1.0" encoding="utf-8"?><!-- + ~ Copyright (c) 2012-2016 Arne Schwabe + ~ Distributed under the GNU GPL v2 with additional terms. For full terms see the file doc/LICENSE.txt + --> + +<resources> + <drawable name="ic_menu_close_clear_cancel">@drawable/ic_baseline_close_24</drawable> + <drawable name="ic_menu_play">@drawable/ic_baseline_play_arrow_24</drawable> + <drawable name="ic_menu_pause">@drawable/ic_baseline_pause_24</drawable> + <drawable name="ic_menu_share">@drawable/ic_baseline_share_24</drawable> + <drawable name="ic_menu_save">@drawable/ic_baseline_check_24</drawable> + <drawable name="ic_menu_view">@drawable/ic_baseline_filter_list_24</drawable> + <drawable name="ic_menu_delete">@drawable/ic_baseline_delete_outline_24</drawable> + <drawable name="ic_menu_copy">@drawable/ic_baseline_file_copy_24</drawable> + <drawable name="ic_menu_delete_grey">@drawable/ic_baseline_delete_outline_24</drawable> + <drawable name="ic_search">@drawable/ic_baseline_search_24</drawable> + <drawable name="ic_stat_vpn">@drawable/ic_icon_system</drawable> + <drawable name="ic_quick">@drawable/ic_icon_system</drawable> + + <drawable name="ic_menu_edit">@drawable/ic_edit</drawable> + <drawable name="ic_menu_import">@drawable/ic_baseline_archive_24</drawable> + <drawable name="ic_menu_add">@drawable/ic_baseline_add_circle_outline_24</drawable> + <drawable name="ic_dialog_alert">@drawable/ic_baseline_warning_24</drawable> + <drawable name="ic_menu_add_grey">@drawable/ic_baseline_add_circle_outline_24</drawable> + <drawable name="ic_menu_import_grey">@drawable/ic_baseline_archive_24</drawable> + <drawable name="ic_receipt">@drawable/ic_baseline_receipt_long_24</drawable> + <drawable name="ic_sort">@drawable/ic_baseline_sort_24</drawable> + +</resources>
\ No newline at end of file diff --git a/main/src/main/res/values/strings.xml b/main/src/main/res/values/strings.xml index da32ec9e..575933ed 100755 --- a/main/src/main/res/values/strings.xml +++ b/main/src/main/res/values/strings.xml @@ -26,8 +26,8 @@ <string name="pkcs12pwquery">PKCS12 Password</string> <string name="file_select">Select…</string> <string name="file_nothing_selected">You must select a file</string> - <string name="useTLSAuth">Use TLS Authentication</string> - <string name="tls_direction">TLS Direction</string> + <string name="useTLSAuth">Use Control Channel Authentication/Encryption</string> + <string name="tls_direction">Authentication/encryption method</string> <string name="ipv6_dialog_tile">Enter IPv6 Address/Netmask in CIDR Format (e.g. 2000:dd::23/64)</string> <string name="ipv4_dialog_title">Enter IPv4 Address/Netmask in CIDR Format (e.g. 1.2.3.4/24)</string> <string name="ipv4_address">IPv4 Address</string> @@ -68,8 +68,8 @@ <string name="remote_tlscn_check_title">Certificate Hostname Check</string> <string name="enter_tlscn_dialog">Specify the check used to verify the remote certificate DN (e.g. C=DE, L=Paderborn, OU=Avian IP Carriers, CN=openvpn.blinkt.de)\n\nSpecify the complete DN or the RDN (openvpn.blinkt.de in the example) or an RDN prefix for verification.\n\nWhen using RDN prefix \"Server\" matches \"Server-1\" and \"Server-2\"\n\nLeaving the text field empty will check the RDN against the server hostname.\n\nFor more details see the OpenVPN 2.3.1+ manpage under —verify-x509-name</string> <string name="enter_tlscn_title">Remote certificate subject</string> - <string name="tls_key_auth">Enables the TLS Key Authentication</string> - <string name="tls_auth_file">TLS Auth File</string> + <string name="tls_key_auth">Enables an additional authentication/encryption layer for the OpenVPN control channel</string> + <string name="tls_auth_file">TLS Auth/TLS Encryption File</string> <string name="pull_on_summary">Requests IP addresses, routes and timing options from the server.</string> <string name="pull_off_summary">No information is requested from the server. Settings need to be specified below.</string> <string name="use_pull">Pull Settings</string> @@ -203,8 +203,8 @@ <string name="using_proxy">Using proxy %1$s %2$s</string> <string name="use_system_proxy">Use system proxy</string> <string name="use_system_proxy_summary">Use the system wide configuration for HTTP/HTTPS proxies to connect.</string> - <string name="onbootrestartsummary">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.</string> - <string name="onbootrestart">Connect on boot</string> + <string name="keep_vpn_connected_summary">OpenVPN will connect the specified VPN on system boot and will try to keep the VPN connected.</string> + <string name="keep_vpn_connected">Keep VPN connected</string> <string name="ignore">Ignore</string> <string name="restart">Restart</string> <string name="restart_vpn_after_change">Configuration changes are applied after restarting the VPN. (Re)start the VPN now?</string> @@ -260,9 +260,10 @@ <string name="encryption_cipher">Encryption ciphers</string> <string name="packet_auth">Packet authentication</string> <string name="auth_dialog_title">Enter packet authentication method</string> - <string name="built_by">built by %s</string> + <string name="built_by">built by %1$s (FP: %2$s)</string> <string name="debug_build">debug build</string> <string name="official_build">official build</string> + <string name="official_o2build">official OpenVPN2 only build</string> <string name="make_selection_inline">Copy into profile</string> <string name="crashdump">Crashdump</string> <string name="add">Add</string> @@ -505,5 +506,7 @@ <string name="allow_translations_summary">Allows the app to be translated with translations contributed by the community. Requires a restart of the app to activate.</string> <string name="tls_profile">TLS Security Profile</string> <string name="encrypt_profiles">Try to encrypt profiles on storage (if supported by Android OS)</string> + <string name="missing_notification_permission">Notification permission missing. This is used to display the status of the VPN and to notify about required user interaction like multi factor authorisation.\n\nClick this message to give the app notification permissions</string> + <string name="proxy_auth_username">Username</string> </resources> diff --git a/main/src/main/res/values/untranslatable.xml b/main/src/main/res/values/untranslatable.xml index 0260de8d..6b3c1f70 100644 --- a/main/src/main/res/values/untranslatable.xml +++ b/main/src/main/res/values/untranslatable.xml @@ -73,6 +73,8 @@ <string name="apprest_name">Name</string> <string name="apprest_vpnlist">List of VPN configurations</string> <string name="apprest_vpnconf">VPN configuration</string> + <string name="apprest_certalias">Certificate Alias</string> + <string name="apprest_certalias_desc">Alias of a certificate in the Android keystore to use. Leave empty to not use the certificate store.</string> <string name="apprest_ver">Version of the managed configuration schema (Currently always 1)</string> <string name="apprest_defprof">UUID of the profile that should be selected as default profile in the app</string> <string name="privacy_policy">The app OpenVPN for Android does not communicate to any server other than the OpenVPN servers provided in configuration files. The author himself does not collect any data and no therefore also no data is saved. For the privacy policy for the OpenVPN server/VPN service you are using (or other services related to the project like GitHub), please refer to their respective privacy policy.</string> @@ -82,6 +84,9 @@ <string name="abi_mismatch">Preferred native ABI precedence of this device (%1$s) and ABI reported by native libraries (%2$s) mismatch</string> <string name="faq_title_ncp">Failed to negotiate cipher with server</string> <string name="import_from_URL">URL</string> + <string name="restriction_pausevpn">Pause VPN when screen is off and less than 64 kB transferred data in 60s</string> + <string name="apprest_aidl_list">List of apps that are allowed to use the remote AIDL. If this list is in the restrictions, the app will not allowed any changes to the list by the user. Package names of allowed apps separated by comma, space or newlines</string> + <string name="apprest_remoteaidl">Remote API access</string> <string-array name="tls_profile_values" translatable="false"> <item>insecure</item> diff --git a/main/src/main/res/xml/app_restrictions.xml b/main/src/main/res/xml/app_restrictions.xml index 813e9bd3..b3258b50 100644 --- a/main/src/main/res/xml/app_restrictions.xml +++ b/main/src/main/res/xml/app_restrictions.xml @@ -1,5 +1,4 @@ -<?xml version="1.0" encoding="utf-8"?> -<!-- +<?xml version="1.0" encoding="utf-8"?><!-- ~ Copyright (c) 2012-2018 Arne Schwabe ~ Distributed under the GNU GPL v2 with additional terms. For full terms see the file doc/LICENSE.txt --> @@ -7,43 +6,47 @@ <restrictions xmlns:android="http://schemas.android.com/apk/res/android"> <restriction + android:defaultValue="1" android:key="version" - android:title="@string/apprest_ver" android:restrictionType="string" - android:defaultValue="1" - /> + android:title="@string/apprest_ver" /> <restriction android:key="vpn_configuration_list" - android:title="@string/apprest_vpnlist" - android:restrictionType="bundle_array"> + android:restrictionType="bundle_array" + android:title="@string/apprest_vpnlist"> <restriction - android:title="@string/apprest_vpnconf" android:key="vpn_configuration" - android:restrictionType="bundle"> + android:restrictionType="bundle" + android:title="@string/apprest_vpnconf"> <restriction + android:description="@string/apprest_uuid_desc" android:key="uuid" android:restrictionType="string" - android:description="@string/apprest_uuid_desc" - android:title="@string/apprest_uuid" - /> + android:title="@string/apprest_uuid" /> <restriction + android:description="@string/apprest_name_desc" android:key="name" android:restrictionType="string" android:title="@string/apprest_name" - android:description="@string/apprest_name_desc" - /> + /> <restriction - android:key="ovpn" - android:title="@string/apprest_ovpn" android:description="@string/apprest_ovpn_desc" - android:restrictionType="string"/> + android:key="ovpn" + android:restrictionType="string" + android:title="@string/apprest_ovpn" /> + <restriction + android:defaultValue="" + android:description="@string/apprest_certalias_desc" + android:key="certificate_alias" + android:restrictionType="string" + android:title="@string/apprest_certalias" /> <!-- <restriction android:key="ovpn_list" @@ -61,9 +64,17 @@ </restriction> <restriction + android:defaultValue="" android:key="defaultprofile" - android:title="@string/apprest_defprof" android:restrictionType="string" - android:defaultValue="" - /> + android:title="@string/apprest_defprof" /> + <restriction + android:key="screenoffpausevpn" + android:restrictionType="bool" + android:title="@string/restriction_pausevpn" /> + <restriction + android:description="@string/apprest_aidl_list" + android:key="allowed_remote_access" + android:restrictionType="string" + android:title="@string/apprest_remoteaidl" /> </restrictions>
\ No newline at end of file |