diff --git a/.gitignore b/.gitignore index 5ff581a1e24da15230971df48659d552a6ff8a6c..fb10e3e29f3e7f6eee35f44f2921a94121f901a7 100644 --- a/.gitignore +++ b/.gitignore @@ -87,3 +87,22 @@ go/lib/bitmask-core-sources.jar go/lib/bitmask-core.aar go/lib/bitmask-web-core-sources.jar go/lib/bitmask-web-core.aar + +lib-bitmask-core-arm64/build +lib-bitmask-core-armv7/build +lib-bitmask-core-web/build +lib-bitmask-core-x86/build +lib-bitmask-core-x86_64/build +lib-bitmask-core/build +lib-bitmask-core-arm64/bitmaskcore_arm64-sources.jar +lib-bitmask-core-arm64/bitmaskcore_arm64.aar +lib-bitmask-core-armv7/bitmaskcore_arm-sources.jar +lib-bitmask-core-armv7/bitmaskcore_arm.aar +lib-bitmask-core-web/bitmaskcore_web-sources.jar +lib-bitmask-core-web/bitmaskcore_web.aar +lib-bitmask-core-x86/bitmaskcore_x86-sources.jar +lib-bitmask-core-x86/bitmaskcore_x86.aar +lib-bitmask-core-x86_64/bitmaskcore_x86_64-sources.jar +lib-bitmask-core-x86_64/bitmaskcore_x86_64.aar +lib-bitmask-core/bitmaskcore-sources.jar +lib-bitmask-core/bitmaskcore.aar diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml index 5cc25a02ef979c260b88a42df7b1882530f6bbb4..286e6d45cd364d2a42172a9ebd410b22b6370540 100644 --- a/.gitlab-ci.yml +++ b/.gitlab-ci.yml @@ -55,6 +55,7 @@ unit_test: image: "0xacab.org:4567/leap/bitmask_android/android-ndk:latest" stage: test script: + - ./scripts/prepareForTests.sh - ./gradlew testCustomProductionFatReleaseUnitTest testNormalProductionFatReleaseUnitTest artifacts: paths: diff --git a/.tx/config b/.tx/config index 736d0c15ecf89feb383be2b5e7ca68ff0512c4df..197fe03ae9d82abfe0a2a3ead100654759e09994 100644 --- a/.tx/config +++ b/.tx/config @@ -1,18 +1,18 @@ [main] host = https://www.transifex.com -lang_map = es_AR:es-rAR, fa_IR:fa-rIR, kn_IN:kn-rIN, pt_BR:pt-rBR, pt_PT:pt-rPT, zh_CN:zh-rCN, zh_TW:zh-rTW, nb:no +lang_map = es_AR: es-rAR, fa_IR: fa-rIR, kn_IN: kn-rIN, pt_BR: pt-rBR, pt_PT: pt-rPT, zh: zh-rCN, zh_TW: zh-rTW, nb: no -[bitmask-android.strings] +[bitmask.strings] file_filter = app/src/main/res/values-<lang>/strings.xml -minimum_perc = 25 +minimum_perc = 75 source_file = app/src/main/res/values/strings.xml source_lang = en type = ANDROID -[bitmask-android.riseupvpn] +[bitmask.riseupvpn] file_filter = app/src/custom/res/values-<lang>/strings.xml -minimum_perc = 25 +minimum_perc = 75 source_file = app/src/custom/res/values/strings.xml source_lang = en -type = ANDROID \ No newline at end of file +type = ANDROID diff --git a/CHANGELOG b/CHANGELOG index 4486ac580fc84508348e46cf49d82e31111df1b1..8402b13574b6e18882f260a1d884c6d2b102ea90 100644 --- a/CHANGELOG +++ b/CHANGELOG @@ -1,3 +1,75 @@ +1.1.7 new year release #2 +bugfixes: +* hide debugging entries in settings in releases + +1.1.6 new year release +features: +* updated snowflake, tor, openvpn +* updated UI +* circumvention improvements +* updated translations +* support for the Message of the Day: providers can inform users about important events + +bugfixes: +* fixed app crashes +* fixed memory leaks +* fixed empty gateway selection screen +* fixed manual provider addition + +1.1.6RC2 Beta +bugfixes: +* fixed memory leaks: less memory consumption +* fixed empty gateway selection screen +* fixed manual provider addition +* improved UI regarding the new design + +features: +* improved and updated circumvention mechanism to protect provider bootstrapping +* updated translations + +1.1.6RC1 Beta +* updated UI +* support for Android 12's new splash screen design +* Message of the day: allows the provider to show a message on app start + +1.1.5RC2 Beta +* improvements of obfuscation proxy pinning +* support for Android API 31 (Android S) +* updated dependencies (ics-openvpn, OpenSSL, Asio, IPtProxy, Snowflake) +* show option to disable blocking if the client fails to connect to any gateway of a given transport +* disable donation page for Bitmask for now +* fix notification not disappearing after vpn has been turned off + +1.1.5 Beta +* integrate obfsvpn - a new pluggable transports library +* pin single obfuscation proxies +* allow to pin a single gateway from a given provider for better debugging (only in Debug Builds available) +* support new TLS ciphers TLS-ECDHE-ECDSA-WITH-AES-256-GCM-SHA384 and DHE-RSA-AES128-SHA +* hide tethering entry if client runs on CalyxOS (Android 11+), since CalyxOS has system level support for tethering that doesn't require root permissions + +bugfixes: +* fix auto-updating eip-service.json, app update check and certificate updates +* fix notification sound bug when downloading a new app version on older Android versions (app update check feature is only available in apks downloaded from bitmask.net / riseup.net) + +1.1.4 +features: +* improve censorship circumvention if VPN certificate needs to be fetched +* point donation link to Riseup Labs +* updated translations + +bugfixes: +* fix notifications not disappearing after disconnecting the VPN from the quick tile settings +* fix some app crashes +* fix icon colors in advanced settings screen + +1.1.3 +features: +* set donation nagging to 7 days +* point all donation links to Riseup + +bugfixes: +* fix crash in tile service on some devices + 1.1.2 - Snowflakes winter wonder release features: * Tor on Snowflake: use new circumvention tech to unblock the communication from Bitmask to it's configuration servers diff --git a/Code of conduct.md b/Code of conduct.md new file mode 100644 index 0000000000000000000000000000000000000000..09f414fc9300eab37a112f72957980bd025d5062 --- /dev/null +++ b/Code of conduct.md @@ -0,0 +1,49 @@ +# Contributor Covenant Code of Conduct + +## Our Pledge + +In the interest of fostering an open and welcoming environment, we as contributors and maintainers pledge to making participation in our project and our community a harassment-free experience for everyone, regardless of age, body size, disability, ethnicity, gender identity and expression, level of experience, nationality, personal appearance, race, religion, or sexual identity and orientation. + +## Our Standards + +Examples of behavior that contributes to creating a positive environment +include: + + +* Using welcoming and inclusive language +* Being respectful of differing viewpoints and experiences +* Gracefully accepting constructive criticism +* Focusing on what is best for the community +* Showing empathy towards other community members + + +## Examples of unacceptable behavior by participants include: + + +* The use of sexualized language or imagery and unwelcome sexual attention or advances +* Trolling, insulting/derogatory comments, and personal or political attacks +* Public or private harassment +* Publishing others private information, such as a physical or electronic address, without explicit permission +* Other conduct which could reasonably be considered inappropriate in a professional setting + +## Our Responsibilities + +Project maintainers are responsible for clarifying the standards of acceptable behavior and are expected to take appropriate and fair corrective action in response to any instances of unacceptable behavior. + +Project maintainers have the right and responsibility to remove, edit, or reject comments, commits, code, wiki edits, issues, and other contributions that are not aligned to this Code of Conduct, or to ban temporarily or +permanently any contributor for other behaviors that they deem inappropriate, threatening, offensive, or harmful. + +## Scope + +This Code of Conduct applies both within project spaces and in public spaces when an individual is representing the project or its community. Examples of representing a project or community include using an official project e-mail address, posting via an official social media account, or acting as an appointed representative at an online or offline event. Representation of a project may be further defined and clarified by project maintainers. + +## Enforcement + +Instances of abusive, harassing, or otherwise unacceptable behavior may be reported by contacting the project team at community@leap.se. All complaints will be reviewed and investigated and will result in a response that is deemed necessary and appropriate to the circumstances. The project team is obligated to maintain confidentiality with regard to the reporter of an incident. +Further details of specific enforcement policies may be posted separately. + +Project maintainers who do not follow or enforce the Code of Conduct in good faith may face temporary or permanent repercussions as determined by other members of the project's leadership. + +## Attribution + +This Code of Conduct is adapted from the Contributor Covenant, version 1.4, available at https://www.contributor-covenant.org/version/1/4/code-of-conduct.html diff --git a/Privacy-policy.md b/Privacy-policy.md new file mode 100644 index 0000000000000000000000000000000000000000..d808088b5d42cda6c24f5b34762ebbfd5eeeff8f --- /dev/null +++ b/Privacy-policy.md @@ -0,0 +1,15 @@ +Privacy Policy for Bitmask +=========================== + +Bitmask does not communicate with any server other than the servers of the selected LEAP VPN provider. + +The authors don't collect any data nor logs. Logs that are created don't leave the app's storage and are deleted by default with each new successful connection. They are only accessible in the app. + +For the privacy policy of the LEAP VPN service you are using, please refer to the respective privacy policy. + +End of service +============== +The program and its components are under open-source licenses that allow you to use this app forever according to terms of the open-source licenses for details. + +However, the author reserves the right to suspend development or stop publishing the app or updates to it at any time. + diff --git a/README.md b/README.md index 4602a8ec0bca80b171faea90507dcfa8d7e61804..823eb48ba36ce3a35666460ed56d5d7ff1b3e2bc 100644 --- a/README.md +++ b/README.md @@ -23,15 +23,7 @@ Please see the [issues](https://0xacab.org/leap/bitmask_android/issues) section * [Debug APKs](#debug-apks) * [Release APKs](#release-apks) * [Signed Release APKs](#signed-release-apks) -* [Running Tests](#running-tests) -* [Debugging in an Emulator](#debugging-in-an-emulator) - * [From Android Studio](#from-android-studio) - * [From The Shell](#from-the-shell) - * [Debian Gotchas](#debian-gotchas) - * [Virtualization Not Enabled](#virtualization-not-enabled) - * [Unpatched Filepaths Bug](#unpatched-filepaths-bug) - * [Outdated GL Libraries](#outdated-gl-libraries) -* [Updating Submodules](#updating-submodules) +* [Supported Versions](#supported-versions) * [Acknowledgments](#acknowledgments) * [Contributing](#contributing) @@ -46,19 +38,20 @@ We will assume for convenience that you are installing on a Debian- or Ubuntu-ba The Bitmask Android Client has the following system-level dependencies: -* JDK v. 1.8 -* Assorted 32-bit C libraries -* Android SDK Tools, v. 27.0.3, with these packages: - * Platform-Tools, v. 27.0.3 - * Build-Tools, API v. 23-27 - * Platforms 23-27 +* JDK 11 +* Android SDK Tools, v. 30.0.3, with these packages: + * Platform-Tools, v. 30.0.3 + * Build-Tools, API v. 30 + * Platforms 30 * Android Support Repository * Google Support Repository - * NDK v. r16b (enables C code in Android) + * NDK v. r21e (enables C code in Android) * For running the app in an emulator, you will also need these packages: * Android Emulator - * System Images for Android APIs 23-27 -* The ICS-OpenVpn submodule + * System Images for Android APIs 30 +* ics-openvpn submodule +* tor-android submodule +* bitmaskcore submodule You can install them as follows: @@ -67,15 +60,16 @@ You can install them as follows: Install with: ```bash -sudo apt install default-jdk +sudo apt-get update -qq && \ + apt-get install -y openjdk-11-jdk ``` ### C Libraries <a name="c-libraries"></a> -These are necessary to make sure the program cross-compiles to 32-bit architectures successfully from 64-bit GNU/Linux machines. If you don't have the lib32stdc++, try for example lib32stdc++-8-dev-x32-cross or whatever version is current on your system. +These are necessary to make sure the program cross-compiles openssl, openvpn, tor etc. for Bitmask Android. ``` -sudo apt install make gcc file lib32stdc++ lib32z1 +sudo apt-get -y install make gcc swig file lib32stdc++6 lib32z1 autoconf autogen automake autopoint autotools-dev gettext-base libtool patch pkg-config mesa-utils ``` ### Android SDK <a name="android-sdk"></a> @@ -88,54 +82,11 @@ You can download Android studio here: https://developer.android.com/studio/index.html -Once you've got it installed, use the `SDK Manager` tool (Android figure Icon with blue arrow second from the right in the tool pane) to download all the Android SDK and NDK depencencies listed above. +Once you've got it installed, use the `SDK Manager` tool (Android figure Icon with blue arrow second from the right in the tool pane) to download all the Android SDK and NDK dependencies listed above. #### With Bash <a name="with-bash"></a> -Alternatively (eg: for build machines), you may download and unzip the `android-sdk` bundle from Google as follows (assuming an install location of `/opt/android-sdk-linux`: - -``` -curl -L https://dl.google.com/android/repository/sdk-tools-linux-3859397.zip -o sdk-tools.zip \ - && unzip -q sdk-tools.zip -d /opt/android-sdk-linux \ - && rm -f sdk-tools.zip -``` - -To download the NDK (for cross-compiling and running the C code used in `ics-openvpn`), use: - -``` -curl -L http://dl.google.com/android/repository/android-ndk-r16b-linux-x86_64.zip -o ndk.zip \ - && unzip ndk.zip -d /opt/android-sdk-linux/android-ndk-r16b \ - && rm -rf ndk.zip -``` - -After updating your PATH (see next step), you may now use the `sdkmanager` tool bundled with `android-sdk` to browse and install new sdk packages from Google. - -To browse all available packages, run: - -```shell -sdkmanager --list -``` - -To search for available packages of a certain type (eg: `tools`), run: - -```shell -sdkmanager --list | grep tools -``` - -To install all of the dependencies listed above (targetting SDK versions 23 - 26), run: - -```shell -sdkmanager tools -sdkmanager platform-tools -sdkmanager extras;android;m2repository -sdkmanager extras;google;m2repository -sdkmanager build-tools;27.0.3 -sdkmanager build-tools;25.0.2 -sdkmanager build-tools;23.0.3 -sdkmanager platforms;android-27 -sdkmanager platforms;android-25 -sdkmanager platforms;android-23 -``` +Alternatively (eg: for build machines), you may have a look at our docker build files in [the docker directory](/docker/) #### Updating Your Path <a name="updating-your-path"></a> @@ -143,44 +94,44 @@ Once you've installed Android SDK & NDK packages, you need to modify your PATH s ```shell export ANDROID_HOME=<path/where/you/installed/android/sdk> -export ANDROID_NDK_HOME=$ANDROID_HOME/ndk-bundle +export ANDROID_NDK_HOME=$ANDROID_HOME/ndk/21.4.7075529 export PATH=$ANDROID_NDK_HOME:$PATH export PATH=$ANDROID_HOME/platform-tools:$PATH export PATH=$ANDROID_HOME/tools/bin:$PATH ``` -NOTE: On GNU/Linux machines, Android Studio installs the Android SDK in `~/Android/Sdk/`. Our dockerfile installs it in `/opt/android-sdk-linux`. You can install it wherever you want! Just be sure to remember where so you can add it to your PATH! :) - #### With Docker <a name="with-docker"></a> Geesh! If all that above seems like a lot, it is! -To keep ourselves from messing it up all the time everyone someone new joins the project, we made a Dockerfile that creates the above environment with one line. You can pull the image and run builds from inside it, or consult the [Dockerfile](/docker/android-sdk.dockerfile) itself for requirements that your system might need but be missing. +To keep ourselves from messing it up all the time someone new joins the project, we made a Dockerfile that creates the above environment with one line. You can pull the image and run builds from inside it, or consult [android-sdk Dockerfile](/docker/android-sdk/Dockerfile) and [android-ndk Dockerfile](/docker/android-ndk/Dockerfile) itself for requirements that your system might need but be missing. Assuming you've already [installed docker](https://docs.docker.com/engine/installation/), you can pull the image with: ``` shell -docker pull 0xacab.org:4567/leap/bitmask_android/android-ndk:latest +docker pull registry.0xacab.org/leap/bitmask_android/android-ndk:latest ``` Run the image with: ``` shell -docker run --rm -it 0xacab.org:4567/leap/bitmask_android/android-ndk:latest +docker run --rm -it registry.0xacab.org/leap/bitmask_android/android-ndk:latest ``` More likely than not, you'll want to run the image with the source code mounted. You can do that with: ``` shell cd <path/to/bitmask_android> -docker run --rm -it -v`pwd`:/bitmask_android -t 0xacab.org:4567/leap/bitmask_android/android-ndk:latest +docker run --rm -it -v`pwd`:/bitmask_android -t registry.0xacab.org/leap/bitmask_android/android-ndk:latest ``` ### Submodules <a name="submodules"></a> -We depend on [ics-openvpn](https://github.com/schwabe/ics-openvpn) as an interface to Android's OpenVPN implementation. We include it as a [git submodule](https://git-scm.com/book/en/v2/Git-Tools-Submodules) in our project, which requires that we initialize and update it (and its respective upstream submodule dependencies) in order to compile and run Bitmask Android. - -We do so with: +We depend on several [git submodules](https://git-scm.com/book/en/v2/Git-Tools-Submodules) to build Bitmask Android: +* [ics-openvpn](https://github.com/schwabe/ics-openvpn) as an interface to Android's OpenVPN implementation. +* [bitmaskcore](https://0xacab.org/leap/android_libs/bitmaskcore.git) mainly as a library for Pluggable Transports (censorship circumvention functionality), +* [tor-android](https://0xacab.org/leap/android_libs/tor-android.git) to protect the communication to configuration servers from being blocked. +In order to initialize and update these submodules run: ```bash cd <path/to/bitmask_android> @@ -190,281 +141,66 @@ git submodule update --init --recursive ## Compiling <a name="compiling"></a> -You have lots of options for compiling, all of which will output Android-executable `apk` packages to `/bitmask_android/app/build/outputs/apk/`. - ### Just Build It! <a name="just-build-it"></a> -If you compile the project for the first time you'll have to compile the dependencies. This can be done with: - -``` -./build_deps.sh -``` -This command will create all libs we need for Bitmask. - -If you want to to have a clean build of all submodules run +If you compile the project for the first time you'll have to compile the dependencies. +In order to get a clean build and fetch all submodules run: ``` ./cleanProject.sh ``` -before you call `./build_deps.sh`. That script removes all build files and does the git submodule init and update job for you. - -You are then welcome to run: +The following command will create all libs we need for Bitmask. ``` -./gradlew build +./scripts/build_deps.sh +``` + +If you run into errors, you may miss some dependencies on your system. Again, please check the `RUN apt-get` commands of [android-sdk Dockerfile](/docker/android-sdk/Dockerfile) and [android-ndk Dockerfile](/docker/android-ndk/Dockerfile) to get an idea what might be missing. +Please note that tor-android can only be build on Linux machines right now. Fixes for Windows and MacOS are more than welcome! +In order to temporarily disable building tor you can run: +``` +BUILD_TOR=false ./scripts/build_deps.sh ``` - -This will compile the code and run the tests, but not output any `apk` packages. As such, it's not all that useful. :) ### Debug APKs <a name="debug-apks"></a> -To assemble debug packages for running locally or testing in CI, run: - +After having run `./build_deps.sh`, you can assemble debug packages for running locally or testing in CI: ```bash -./build_deps.sh -./gradlew assembleDebug +./gradlew assembleNormalProductionFatDebug ``` -This will output `app-insecure-debug.apk` and `app-production-debug.apk` to `/bitmask_android/app/build/outputs/apk/`. - -### Release APKs <a name="release-apks"></a> - -To assemble release packages, run: - +In order to build a custom branded version of Bitmask you can run: ```bash -./build_deps.sh -./gradlew assembleRelease -``` - -This will output `app-insecure-release.apk` and `app-production-release.apk` to `/bitmask_android/app/build/outputs/apk/`. - -### Signed Release APKs <a name="signed-release-apks"></a> - -If you want to release a signed APK (which you *must* do to publish the app to the Google Play store), you'll have to create a gradle.properties file in the project root with the following structure: - -```properties -storeFileProperty=<fullPath> -storePasswordProperty=<store password without quotation marks> -keyAliasProperty=<key alias without quotation marks> -keyPasswordProperty=<key password without quotation marks> -``` - -### Building In Docker <a name="building-in-docker"></a> - -If you want to make sure the environment you use to build APKs matches exactly the environment that Gitlab will use to build and publish artifacts, you can run any of the above build commands from inside Docker. To assemble a release build this way, run the following commands: - -``` shell -$ cd <path/to/bitmask_android> -$ sudo docker run --rm -it -v `pwd`:/bitmask_android 0xacab.org:4567/leap/bitmask_android/android-ndk:latest -# cd /bitmask_android -# ./cleanProject.sh -# ./build_deps.sh -# ./gradlew assembleRelease -``` - -## Running Tests <a name="running-tests"></a> - -To run the automated tests: - - 1. Run an emulator - 2. Unlock Android - 3. Issue the command ./gradlew connectedCheck - 4. Pay attention and check the "Trust this app" checkbox, if you don't do so tests won't run. - - -## Debugging in an Emulator <a name="debugging-in-an-emulator"></a> - -You can run the app in an emulator running any version of Android and simulating (almost) any device. To run it you'll have to create an emulator, run the emulator, and then load an assembled APK of the app onto the emulator. (You can then use all sort of nifty tools in [Anroid Debug Bridge](https://developer.android.com/studio/command-line/adb.html) to tail the logs and debug the app.) - -Assuming you've already tackled (or don't need to tackle) the [Debian Gotchas](#debian-gotchas) listed below, you can do that using either Android Studio or a bash shell as follows: - -### From Android Studio <a name="from-android-studio"></a> - -To create an emulator: - -* Select `Tools/Android/AVD Manager` from the application menu -* Follow the instructions - -To run a pre-existing emulator: - -* Open the `AVD Manager` as above -* Press the "Play" button next to the emulator you want to run - -To run the app: - -* Ensure you have an emulator running -* Open the left-hand project pane (Meta-1 or Cmd-1, depending on your keybindings) -* Navigate to `bitmask_android/app/src/main/java/se/leap/bitmaskclient/StartActivity` -* Right-click over the `StartActivity` filename and click the `Run 'StartActivity'` option (or use Shift-Ctl-F10 or Shift-Ctl-R, depending on your keybindings) -* After you have done this once, you should be able to simply select `StartActivity` from the dropdown menu next to the big green arrow in the toolbar, then click the green arrow to run the app. - -### From the Shell <a name="from-the-shell"></a> - -To list the available avd images for creating an emulator: - -``` shell -avdmanager list -``` - -To create an emulator: - -``` shell -avdmanager create avd +./gradlew assembleCustomProductionFatDebug ``` -To list the emulators you have already created: +If everything went fine, you will find the debug apks in `/bitmask_android/app/build/outputs/apk/`. -``` shell -avdmanager list avd -``` - -To run a pre-existing emulator called `Nexus_5_API_25`: - -``` shell -emulator @Nexus_5_API_15 -``` - -Verify the device is running with: - -``` shell -adb devices -``` - -You should see something like: - -``` shell -List of devices attached -emulator-5554 device -``` -Install APK with: - -``` shell -abd install <path/to/your>.apk -``` - -Uninstall with: - -``` shell -abd uninstall se.leap.bitmaskclient -``` -Install with option to reinstall: - -``` shell -abd install -r <path/to/your/apk> -``` - -### Debian Gotchas <a name="debian-gotchas"></a> - -If you are running Debian on a 64-bit machine, your emulator will likely not work out of the gate. Test to see if this is the case by: - -* first creating an emulator in Android Studio (with name, eg, `Nexus_5_API_25`) -* then running: - ```shell - cd ~/ - emulator @<name_of_your_emulator> - ``` -If you can launch an emulator, HUZZAH! If not, you likely have one of 3 problems: - -#### 1. Virtualization Not Enabled <a name="virtualization-not-enabled"></a> - -Boo! Try turning it on. The second half of [this article](https://docs.fedoraproject.org/en-US/Fedora/13/html/Virtualization_Guide/sect-Virtualization-Troubleshooting-Enabling_Intel_VT_and_AMD_V_virtualization_hardware_extensions_in_BIOS.html) is a decent enough guide. - -#### 2. Unpatched Filepaths Bug <a name="unpatched-filepaths-bug"></a> - -**Symptoms:** If you have this bug, you will see something like the following when you try to spin up an emulator: - -``` shell -[140500439390016]:ERROR:./android/qt/qt_setup.cpp:28:Qt library not found at ../emulator/lib64/qt/lib -Could not launch '../emulator/qemu/linux-x86_64/qemu-system-i386': No such file or directory -``` -As [documented here](https://stackoverflow.com/questions/42554337/cannot-launch-avd-in-emulatorqt-library-not-found), there is a standing bug in the version of `emulator` packaged for emulator that assumes it always runs from within the `$ANDROID_HOME/emulator` directory, and can thus safely use relative filepaths, when in fact this is almost never the case. (Cool bug!) - -**Fixes:** - -You have a couple options. The second is more robust: - -1. Always run emulator from within its own directory (clunky!): - -``` shell - cd "$(dirname "$(which emulator)")" - emulator <name_of_your_emulator> -``` - -2. Insert a line in your `~/.bashrc` to automatically navigate to the correct directory (and back) whenever you invoke `emulator`: - - ```shell -function emulator { pushd `pwd`; cd "$(dirname "$(which emulator)")" && ./emulator "$@"; popd;} -``` - -#### 3. Outdated GL Libraries <a name="outdated-gl-libraries"></a> - -**Symptoms:** If you have this bug, you will see something like the following: - -``` shell -libGL error: failed to load driver: swrast -X Error of failed request: BadValue (integer parameter out of range for operation) -# redacted incredibly long stack trace -``` - -As documented [here](http://stackoverflow.com/questions/36554322/cannot-start-emulator-in-android-studio-2-0), the current emulator package ships without outdated versions of LibGL libraries. To work around this: - -1. Install modern GL libriaries with: - -``` shell -sudo apt-get install mesa-utils -``` - -2. Ensure that `emulator` always uses the correct libraries by either: - - a. always calling `emulator` with the `-use-system-libs` flag, like so: - - ``` shell - emulator -use-system-libs -avd Nexus_5_API_25 - ``` - b. adding the following line to your ~/.bashrc or ~/.bash_profile: - - ```shell - export ANDROID_EMULATOR_USE_SYSTEM_LIBS=1 - ``` - -**Special Android Studio Debian Bonus Gotcha:** +### Release APKs <a name="release-apks"></a> -Assuming you have made all the above fixes (great job!), to be able to launch emulators from Android Studio, you must either: +To build releases, a script comes to the rescue: [prepareForDistribution.sh](/scripts/prepareForDistribution.sh) ` -1. Use the environment variable solution above (option a), then *always* launch Android Studio from a bash shell with: +Before you can actually build a release make sure you have setup a keystore with your Android signing key. Additionally you can sign your software with your PGP key using this script. -``` shell -studio +If you want to build and sign apks and aab bundles for the current commit, run: +```bash + ./scripts/prepareForDistribution.sh build sign -ks ~/path/to/bitmask-android.keystore -ka <yourKeystoreKeyAlias> ``` -This means never using the desktop launcher. :( +Please check `./prepareFordistribution.sh -h` for all options! -2. If you want to use the desktop launcher: +### Running unit tests - * You must *always* launch emulators from the terminal. :( - * But: you can quickly access a terminal inside of Android Studio with `OPTION-F12` +Unit tests should always run against release builds, it is expected that some tests fail in debug builds. -## Updating Submodules <a name="updating-submodules"></a> +You can execute all unit tests from the command line with: -If you need to refresh of our upstream dependency on ics-openvpn, you may do so with: - -``` shell -cd <path/to/bitmask_android> -./gradlew updateIcsOpenVpn +```bash + ./gradlew testCustomProductionFatReleaseUnitTest testNormalProductionFatReleaseUnitTest ``` -Alternately: - -```shell -cd <path/to/bitmask_android> -cd ics-openvpn -git remote add upstream https://github.com/schwabe/ics-openvpn.git -git pull --rebase upstream master -``` -A bunch of conflicts may arise. The guidelines are: +## Supported Versions <a name="supported-versions"></a> - 1. Methods in HEAD (upstream) completely removed from Bitmask should be removed again (e.g. askPW) - 2. Sometimes, Dashboard.class is in Bitmask while in ics-openvpn it is replaced by MainActivity.class and other classes. Keep removing them to keep Dashboard.class in there. - 3. Some resources files are stripped from several entries. Remove them if possible (check the code we compile is not using anything else new). +Currently API 16 (Android 4.1) - API 30 (Android 11) are officially supported. Keep backwards compatibility in mind if you plan to contribute new features. ## Acknowledgments <a name="acknowledgments"></a> @@ -477,6 +213,6 @@ Please file bug tickets on our main [development platform](https://0xacab.org/le Please fork this repository and contribute back using [pull requests](https://0xacab.org/leap/bitmask_android/merge_requests). -Our preferred method for receiving translations is our [Transifex project](https://www.transifex.com/projects/p/bitmask-android). +Our preferred method for receiving translations is our [Transifex project](https://www.transifex.com/otf/bitmask). Localization Lab helps us with on-boarding volunteers. If you are new to translations and Transifex we've got a [short how-to](https://wiki.localizationlab.org/index.php/Bitmask). Any contributions, large or small, major features, bug fixes, additional language translations, unit/integration tests are welcomed and appreciated but will be thoroughly reviewed and discussed. diff --git a/app/build.gradle b/app/build.gradle index 5b4804320c869af4eb5f652a33c3e52e1fea0c92..8c555a7f2157ecb32e8661b27c5aae08a2d985fd 100644 --- a/app/build.gradle +++ b/app/build.gradle @@ -4,23 +4,28 @@ import java.util.regex.Pattern apply plugin: 'com.android.application' android { - compileSdkVersion 30 + compileSdkVersion 31 ndkVersion "21.4.7075529" - buildToolsVersion '30.0.3' + buildToolsVersion '31.0.0' compileOptions { targetCompatibility 1.8 sourceCompatibility 1.8 } + viewBinding { + enabled = true + } + defaultConfig { applicationId "se.leap.bitmaskclient" // the factor 1000 is used so that gplay users can upgrade from split apks ((current version number - 1) * 1000) + n // to extracted bundle apks, supplied by google - versionCode 160 * 1000 - versionName "1.1.2" - minSdkVersion 16 - targetSdkVersion 30 + // however we don't calculate the versionCode here, because F-Droid doesn't like that + versionCode 169000 + versionName "1.1.8" + minSdkVersion 21 + targetSdkVersion 31 vectorDrawables.useSupportLibrary = true buildConfigField 'boolean', 'openvpn3', 'false' @@ -29,19 +34,26 @@ android { //This is the default donation URL and should be set to the donation page of LEAP // and this should not be set/altered anywhere else. - buildConfigField 'String', 'default_donation_url', '"https://leap.se/donate/"' + buildConfigField 'String', 'default_donation_url', '"https://riseuplabs.org/leap"' //The field to enable donations in the app. buildConfigField 'boolean', 'enable_donation', 'false' //The field to enable donation reminder popup in the app if enable_donation is set to 'false' this will be disabled. - buildConfigField 'boolean', 'enable_donation_reminder', 'false' + buildConfigField 'boolean', 'enable_donation_reminder', 'true' //The duration in days to trigger the donation reminder - buildConfigField 'int', 'donation_reminder_duration', '30' + buildConfigField 'int', 'donation_reminder_duration', '7' //skip the account creation / login screen if the provider offers anonymous vpn usage, use directly the anonymous cert instead buildConfigField 'boolean', 'priotize_anonymous_usage', 'false' //allow manual gateway selection buildConfigField 'boolean', 'allow_manual_gateway_selection', 'true' - // grey out background in EipFragment (main screen) if VPN is not running - buildConfigField 'boolean', 'use_color_filter', 'true' + // decide if we use obfsvpn or shapeshifter as obfs4 lib + buildConfigField 'boolean', 'use_obfsvpn', 'true' + // obfsvpn Debugging config fields to pin and configure a particular proxy + buildConfigField "String", "obfsvpn_port", '""' + buildConfigField "String", "obfsvpn_ip", '""' + buildConfigField "String", "obfsvpn_cert", '""' + buildConfigField 'boolean', 'obfsvpn_use_kcp', 'false' + // default to UDP usage + buildConfigField 'boolean', 'prefer_udp', 'false' // static update url pointing to the latest stable release apk buildConfigField "String", "update_apk_url", '"https://dl.bitmask.net/client/android/Bitmask-Android-latest.apk"' @@ -50,12 +62,17 @@ android { // the version file contains the versionCode of the latest release buildConfigField "String", "version_file_url", '"https://dl.bitmask.net/client/android/versioncode.txt"' + // if center_actionbar_title is set to true, the actionbar title and subtitle will be centered, otherwise default + buildConfigField 'boolean', 'actionbar_center_title', 'true' + buildConfigField 'boolean', 'actionbar_capitalize_title', 'true' + //ignore the following configs, only used in custom flavor buildConfigField 'String', 'donation_url', 'null' buildConfigField "String", "customProviderUrl", '""' buildConfigField "String", "customProviderIp", '""' buildConfigField "String", "customProviderApiIp", '""' buildConfigField "String", "geoipUrl", '""' + buildConfigField "String", "customProviderMotdUrl", '""' testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner" dexOptions { @@ -114,13 +131,16 @@ android { def customProviderUrl = '"https://calyx.net"' buildConfigField "String", "customProviderUrl", customProviderUrl //static ip address of provider, using a commercially validated CA certificate to serve the provider.json - def customProviderIp = '"198.252.153.70"' + def customProviderIp = '""' buildConfigField "String", "customProviderIp", customProviderIp //static ip address of the provider api, using a self signed certificate to serve provider.json, eip-service.json etc. - def customProviderApiIp = '"198.252.153.107"' + def customProviderApiIp = '""' buildConfigField "String", "customProviderApiIp", customProviderApiIp - def geoipUrl = '"https://api.black.riseup.net:9001/json"' + def geoipUrl = '"https://menshen.riseup.net/json"' buildConfigField "String", "geoipUrl", geoipUrl + //URL for the message of the day, see https://0xacab.org/leap/motd#motd-message-of-the-day + //def customProviderMotdUrl = '"https://static.riseup.net/vpn/motd.json"' + //buildConfigField "String", "customProviderMotdUrl", customProviderMotdUrl //Change the versionCode as needed //versionCode 1 //Change the versionName as needed @@ -130,8 +150,15 @@ android { buildConfigField 'boolean', 'priotize_anonymous_usage', 'true' //allow manual gateway selection buildConfigField 'boolean', 'allow_manual_gateway_selection', 'true' - // grey out background in EipFragment (main screen) if VPN is not running - buildConfigField 'boolean', 'use_color_filter', 'false' + // decide if we use obfsvpn or shapeshifter as obfs4 lib + buildConfigField 'boolean', 'use_obfsvpn', 'true' + // obfsvpn Debugging config fields to pin and configure a particular proxy + buildConfigField "String", "obfsvpn_port", '"443"' + buildConfigField "String", "obfsvpn_ip", '"159.223.173.205"' + buildConfigField "String", "obfsvpn_cert", '"8nuAbPJwFrKc/29KcCfL5LBuEWxQrjBASYXdUbwcm9d9pKseGK4r2Tg47e23+t6WghxGGw"' + buildConfigField 'boolean', 'obfsvpn_use_kcp', 'true' + // default to UDP usage + buildConfigField 'boolean', 'prefer_udp', 'true' //Build Config Fields for automatic apk update checks @@ -153,7 +180,13 @@ android { //The field to enable donation reminder popup in the app if enable_donation is set to 'false' this will be disabled. buildConfigField 'boolean', 'enable_donation_reminder', 'true' //The duration in days to trigger the donation reminder - buildConfigField 'int', 'donation_reminder_duration', '30' + buildConfigField 'int', 'donation_reminder_duration', '7' + + // ActionBar design + + // if center_actionbar_title is set to true, the actionbar title and subtitle will be centered, otherwise default + buildConfigField 'boolean', 'actionbar_center_title', 'true' + buildConfigField 'boolean', 'actionbar_capitalize_title', 'false' // Build apks for each architecture, in addition to one 'fat' apk containing libraries for all all architectures // enable this if you're publishing in gplay @@ -262,15 +295,13 @@ android { assets.srcDirs = ['assets', 'ovpnlibs/assets', '../ics-openvpn/main/build/ovpnassets', - // '../go/out' TODO: uncomment this line as soon as we want to use PT in production ] jniLibs.srcDirs = ['../ics-openvpn/main/build/intermediates/cmake/skeletonRelease/obj/'] jni.srcDirs = [] //disable automatic ndk-build } debug { - assets.srcDirs = ['src/debug/assets', - /*'../go/out'*/] + assets.srcDirs = ['src/debug/assets'] } test { @@ -317,7 +348,6 @@ android { * normalProductionFatDebug -> Bitmask development build, includes all ABIS * customProductionFatwebDebug -> branded development build, includes all ABIs, for distribution through a download page * normalProductionFatWebDebug -> Bitmask development build, includes all ABIS, for distribution through a download page - * customInsecureFatDebug -> branded development build, doesn't checks certificates (for test server setup w/o valid certificates), includes all ABIs * normalInsecureFatDebug -> Bitmask development build, doesn't checks certificates (for test server setup w/o valid certificates), includes all ABIs * * Branded Releases: @@ -350,10 +380,12 @@ android { def buildTypeName = variant.buildType.name // flavorDimensions "branding" -> 0, "implementation" -> 1, "abi" -> 2 def supportsSplitApk = variant.flavors[0].splitApk + def branding = variant.flavors[0].name // To check for a certain build type, use variant.buildType.name == "<buildType>" if (((names.contains("insecure") && !names.contains("fat")) || (names.contains("insecure") && buildTypeName.contains("beta")) || (names.contains("insecure") && buildTypeName.contains("release")) || + (names.contains("insecure") && branding.contains("custom")) || (buildTypeName.contains("debug") && !(names.contains("fatweb") || names.contains("fat"))) || (names.contains("fatweb") && buildTypeName.contains("beta")) || (!supportsSplitApk && !names.contains("fat"))) @@ -385,9 +417,7 @@ dependencies { //TODO: remove that library androidTestImplementation 'com.jayway.android.robotium:robotium-solo:5.6.3' testImplementation 'org.json:json:20180813' - debugImplementation 'com.squareup.leakcanary:leakcanary-android:1.6.2' - releaseImplementation 'com.squareup.leakcanary:leakcanary-android-no-op:1.6.2' - betaImplementation 'com.squareup.leakcanary:leakcanary-android-no-op:1.6.2' + debugImplementation 'com.squareup.leakcanary:leakcanary-android:2.9.1' annotationProcessor 'com.jakewharton:butterknife-compiler:10.2.3' annotationProcessor 'com.squareup.dagger:dagger-compiler:1.2.2' implementation 'com.jakewharton:butterknife:10.2.1' @@ -397,15 +427,15 @@ dependencies { implementation 'com.google.code.gson:gson:2.8.6' implementation 'com.squareup.okhttp3:okhttp:3.12.12' implementation 'androidx.legacy:legacy-support-core-utils:1.0.0' - implementation 'androidx.annotation:annotation:1.1.0' + implementation 'androidx.annotation:annotation:1.4.0' implementation 'androidx.legacy:legacy-support-v4:1.0.0' - implementation 'androidx.appcompat:appcompat:1.2.0' - implementation 'com.google.android.material:material:1.2.1' - implementation 'androidx.fragment:fragment:1.2.5' - implementation 'androidx.constraintlayout:constraintlayout:2.0.4' + implementation 'androidx.appcompat:appcompat:1.4.2' + implementation 'com.google.android.material:material:1.6.1' + implementation 'androidx.fragment:fragment:1.5.1' + implementation 'androidx.constraintlayout:constraintlayout:2.1.4' implementation 'androidx.multidex:multidex:2.0.1' implementation 'androidx.cardview:cardview:1.0.0' - implementation 'androidx.localbroadcastmanager:localbroadcastmanager:1.0.0' + implementation 'androidx.localbroadcastmanager:localbroadcastmanager:1.1.0' implementation 'de.hdodenhof:circleimageview:3.1.0' @@ -467,23 +497,11 @@ android.applicationVariants.all { variant -> } } - -// Ensure the no-op dependency is always used in JVM tests. -configurations.all { config -> - if (config.name.contains('UnitTest')) { - config.resolutionStrategy.eachDependency { details -> - if (details.requested.group == 'com.squareup.leakcanary' && details.requested.name == 'leakcanary-android') { - details.useTarget(group: details.requested.group, name: 'leakcanary-android-no-op', version: details.requested.version) - } - } - } -} - subprojects { afterEvaluate {project -> if (project.hasProperty("android")) { android { - compileSdkVersion 30 + compileSdkVersion 31 } } } diff --git a/app/src/custom/res/animator/alpha1.xml b/app/src/custom/res/animator/alpha1.xml new file mode 100644 index 0000000000000000000000000000000000000000..94192a0b271bf44f2a4fa216e344c8f4e2252eb9 --- /dev/null +++ b/app/src/custom/res/animator/alpha1.xml @@ -0,0 +1,11 @@ +<?xml version="1.0" encoding="utf-8"?> +<set xmlns:android="http://schemas.android.com/apk/res/android"> + <objectAnimator + android:duration="1000" + android:propertyName="fillColor" + android:valueFrom="#00000000" + android:valueTo="#000000" + android:valueType="colorType" + /> +</set> + diff --git a/app/src/custom/res/animator/alpha2.xml b/app/src/custom/res/animator/alpha2.xml new file mode 100644 index 0000000000000000000000000000000000000000..b66ef59c7de558524a4b66ff274bf720eb9dcf11 --- /dev/null +++ b/app/src/custom/res/animator/alpha2.xml @@ -0,0 +1,12 @@ +<?xml version="1.0" encoding="utf-8"?> +<set xmlns:android="http://schemas.android.com/apk/res/android"> + <objectAnimator + android:duration="1000" + android:propertyName="fillColor" + android:valueFrom="#00000000" + android:valueTo="#000000" + android:startOffset="1000" + android:valueType="colorType" + /> +</set> + diff --git a/app/src/custom/res/animator/alpha3.xml b/app/src/custom/res/animator/alpha3.xml new file mode 100644 index 0000000000000000000000000000000000000000..2a1e0ba433a94a05edc47bac9af45c8e896a105f --- /dev/null +++ b/app/src/custom/res/animator/alpha3.xml @@ -0,0 +1,11 @@ +<?xml version="1.0" encoding="utf-8"?> +<set xmlns:android="http://schemas.android.com/apk/res/android"> + <objectAnimator + android:duration="1000" + android:propertyName="fillColor" + android:valueFrom="#00000000" + android:valueTo="#000000" + android:valueType="colorType" + android:startOffset="2000" + /> +</set> diff --git a/app/src/custom/res/animator/alpha4.xml b/app/src/custom/res/animator/alpha4.xml new file mode 100644 index 0000000000000000000000000000000000000000..75dc9c78fd98d49e3cbb28ff2158112da80129eb --- /dev/null +++ b/app/src/custom/res/animator/alpha4.xml @@ -0,0 +1,10 @@ +<?xml version="1.0" encoding="utf-8"?> +<set xmlns:android="http://schemas.android.com/apk/res/android"> + <objectAnimator + android:propertyName="alpha" + android:duration="1000" + android:startOffset="4000" + android:valueFrom="1" + android:valueTo="0" /> +</set> + diff --git a/app/src/custom/res/animator/state_transition_connceted_disconnected.xml b/app/src/custom/res/animator/state_transition_connceted_disconnected.xml new file mode 100644 index 0000000000000000000000000000000000000000..751d2da5ea0ee4c842ac1276fc9fec602a07e837 --- /dev/null +++ b/app/src/custom/res/animator/state_transition_connceted_disconnected.xml @@ -0,0 +1,4 @@ +<?xml version="1.0" encoding="utf-8"?> +<set xmlns:android="http://schemas.android.com/apk/res/android"> + +</set> \ No newline at end of file diff --git a/app/src/custom/res/drawable-anydpi-v24/bg_connected.xml b/app/src/custom/res/drawable-anydpi-v24/bg_connected.xml new file mode 100644 index 0000000000000000000000000000000000000000..f851203d54f11034ac37757e42abee818bb8bce8 --- /dev/null +++ b/app/src/custom/res/drawable-anydpi-v24/bg_connected.xml @@ -0,0 +1,13 @@ +<?xml version="1.0" encoding="utf-8"?> +<layer-list xmlns:android="http://schemas.android.com/apk/res/android"> + <item android:gravity="fill"> + <shape android:shape="rectangle"> + <solid android:color="@color/bg_running"/> + </shape> + </item> + <item android:gravity="fill" + android:bottom="80dp" + android:drawable="@drawable/bg_connected_effect" + > + </item> +</layer-list> \ No newline at end of file diff --git a/app/src/custom/res/drawable-anydpi-v24/bg_connected_effect.xml b/app/src/custom/res/drawable-anydpi-v24/bg_connected_effect.xml new file mode 100644 index 0000000000000000000000000000000000000000..75e79573db658fabebaa9403e778ae8aaf0859f3 --- /dev/null +++ b/app/src/custom/res/drawable-anydpi-v24/bg_connected_effect.xml @@ -0,0 +1,25 @@ +<vector xmlns:android="http://schemas.android.com/apk/res/android" xmlns:aapt="http://schemas.android.com/aapt" + android:viewportWidth="375" + android:viewportHeight="622" + android:width="375dp" + android:height="622dp"> + <path + android:pathData="M185.501 621.837C315.565 621.837 421.003 346.305 421.003 6.4184C421.003 -333.468 315.565 -609 185.501 -609C55.4376 -609 -50 -333.468 -50 6.4184C-50 346.305 55.4376 621.837 185.501 621.837Z"> + <aapt:attr + name="android:fillColor"> + <gradient + android:startX="289.514" + android:startY="184.89" + android:endX="289.514" + android:endY="564.398" + android:tileMode="clamp"> + <item + android:color="#00A6C28A" + android:offset="0" /> + <item + android:color="#36669933" + android:offset="1" /> + </gradient> + </aapt:attr> + </path> +</vector> \ No newline at end of file diff --git a/app/src/custom/res/drawable-anydpi-v24/bg_connecting.xml b/app/src/custom/res/drawable-anydpi-v24/bg_connecting.xml new file mode 100644 index 0000000000000000000000000000000000000000..8482d30eb9fcd338995856dc384bd642c00e56b2 --- /dev/null +++ b/app/src/custom/res/drawable-anydpi-v24/bg_connecting.xml @@ -0,0 +1,13 @@ +<?xml version="1.0" encoding="utf-8"?> +<layer-list xmlns:android="http://schemas.android.com/apk/res/android"> + <item android:gravity="fill"> + <shape android:shape="rectangle"> + <solid android:color="@color/bg_connecting"/> + </shape> + </item> + <item android:gravity="fill" + android:bottom="80dp" + android:drawable="@drawable/bg_connecting_effect" + > + </item> +</layer-list> \ No newline at end of file diff --git a/app/src/custom/res/drawable-anydpi-v24/bg_connecting_effect.xml b/app/src/custom/res/drawable-anydpi-v24/bg_connecting_effect.xml new file mode 100644 index 0000000000000000000000000000000000000000..fd462a54c3c4c5e5975dc0515492f1060b3d7d0d --- /dev/null +++ b/app/src/custom/res/drawable-anydpi-v24/bg_connecting_effect.xml @@ -0,0 +1,44 @@ +<vector xmlns:android="http://schemas.android.com/apk/res/android" xmlns:aapt="http://schemas.android.com/aapt" + android:viewportWidth="375" + android:viewportHeight="629" + android:width="375dp" + android:height="629dp"> + <path + android:pathData="M96.6338 471.305C226.719 515.286 420.512 289.654 529.484 -32.658C638.456 -354.97 621.341 -651.909 491.256 -695.89C361.172 -739.871 167.378 -514.239 58.4058 -191.927C-50.5662 130.385 -33.4509 427.324 96.6338 471.305Z"> + <aapt:attr + name="android:fillColor"> + <gradient + android:startX="132.695" + android:startY="21.7787" + android:endX="11.0197" + android:endY="381.664" + android:tileMode="clamp"> + <item + android:color="#00FFAA33" + android:offset="0" /> + <item + android:color="#33FFAA33" + android:offset="1" /> + </gradient> + </aapt:attr> + </path> + <path + android:pathData="M183.501 628.837C313.565 628.837 419.003 353.304 419.003 13.4182C419.003 -326.468 313.565 -602 183.501 -602C53.4376 -602 -52 -326.468 -52 13.4182C-52 353.304 53.4376 628.837 183.501 628.837Z"> + <aapt:attr + name="android:fillColor"> + <gradient + android:startX="183.501" + android:startY="255.483" + android:endX="183.501" + android:endY="634.991" + android:tileMode="clamp"> + <item + android:color="#00FFAA33" + android:offset="0" /> + <item + android:color="#33FFAA33" + android:offset="1" /> + </gradient> + </aapt:attr> + </path> +</vector> \ No newline at end of file diff --git a/app/src/custom/res/drawable-anydpi-v24/bg_disconnected.xml b/app/src/custom/res/drawable-anydpi-v24/bg_disconnected.xml new file mode 100644 index 0000000000000000000000000000000000000000..bfc3c1d1b72d7686ca61012d0d57fffc615dc4c0 --- /dev/null +++ b/app/src/custom/res/drawable-anydpi-v24/bg_disconnected.xml @@ -0,0 +1,15 @@ +<?xml version="1.0" encoding="utf-8"?> +<layer-list xmlns:android="http://schemas.android.com/apk/res/android"> + <item android:gravity="fill"> + <shape android:shape="rectangle"> + <solid android:color="@color/bg_disconnected"/> + </shape> + </item> + <item + android:top="-40dp" + android:gravity="fill" + android:drawable="@drawable/bg_disconnected_effect" + android:bottom="80dp" + > + </item> +</layer-list> \ No newline at end of file diff --git a/app/src/custom/res/drawable-anydpi-v24/bg_disconnected_effect.xml b/app/src/custom/res/drawable-anydpi-v24/bg_disconnected_effect.xml new file mode 100644 index 0000000000000000000000000000000000000000..d19c2f7f7ece136629e8408c401dd7792334300d --- /dev/null +++ b/app/src/custom/res/drawable-anydpi-v24/bg_disconnected_effect.xml @@ -0,0 +1,45 @@ +<vector xmlns:android="http://schemas.android.com/apk/res/android" xmlns:aapt="http://schemas.android.com/aapt" + android:viewportWidth="375" + android:viewportHeight="636" + android:width="375dp" + android:height="636dp" + > + <path + android:pathData="M183.528 635.43C313.591 635.43 419.029 359.898 419.029 20.0117C419.029 -319.875 313.591 -595.407 183.528 -595.407C53.4638 -595.407 -51.9738 -319.875 -51.9738 20.0117C-51.9738 359.898 53.4638 635.43 183.528 635.43Z"> + <aapt:attr + name="android:fillColor"> + <gradient + android:startX="79.5145" + android:startY="198.483" + android:endX="79.5145" + android:endY="577.991" + android:tileMode="clamp"> + <item + android:color="#00FFAA33" + android:offset="0" /> + <item + android:color="#33AF0909" + android:offset="1" /> + </gradient> + </aapt:attr> + </path> + <path + android:pathData="M183.514 458.837C313.578 458.837 419.016 183.305 419.016 -156.582C419.016 -496.468 313.578 -772 183.514 -772C53.4506 -772 -51.9869 -496.468 -51.9869 -156.582C-51.9869 183.305 53.4506 458.837 183.514 458.837Z"> + <aapt:attr + name="android:fillColor"> + <gradient + android:startX="183.514" + android:startY="85.483" + android:endX="183.514" + android:endY="464.991" + android:tileMode="clamp"> + <item + android:color="#00FFAA33" + android:offset="0" /> + <item + android:color="#33AF0909" + android:offset="1" /> + </gradient> + </aapt:attr> + </path> +</vector> \ No newline at end of file diff --git a/app/src/custom/res/drawable-anydpi-v24/ic_motd.xml b/app/src/custom/res/drawable-anydpi-v24/ic_motd.xml new file mode 100644 index 0000000000000000000000000000000000000000..85c9e58aafc9fcd16bcc5c0108c385b46a3ab9f1 --- /dev/null +++ b/app/src/custom/res/drawable-anydpi-v24/ic_motd.xml @@ -0,0 +1,18 @@ +<?xml version="1.0" encoding="utf-8"?> +<vector xmlns:android="http://schemas.android.com/apk/res/android" xmlns:aapt="http://schemas.android.com/aapt" + android:viewportWidth="288" + android:viewportHeight="288" + android:width="288dp" + android:height="288dp"> + <group + android:scaleX="1" + android:scaleY="1" + android:translateX="82" + android:translateY="52" + > + <path + android:pathData="M69.8243 44.3636C69.8243 44.3636 66.935 38.7879 66.6942 38.0606C66.4534 37.3333 65.0088 29.3333 65.0088 29.3333L66.935 25.9394L71.2689 19.6364L77.2882 14.7879L78.7328 14.303L93.42 8.72727L94.8647 7.27273L93.42 4.84849L91.2531 3.63636L87.4007 2.66666L77.7698 1.69697H70.3058L65.2496 2.90909L60.6749 1.21212L54.8963 0.484846L46.4692 0.242421L42.1353 0L35.1529 2.66666L24.3181 15.2727L22.8735 20.1212L22.1511 24.4848L18.5395 32.4848L16.1318 40L14.9279 48V49.697L9.39016 58.1818L6.26011 64.4848V73.4545L7.2232 92.1212L8.90861 98.9091L12.2794 105.212L16.6134 109.333L18.5395 117.333L25.7627 133.576L34.4306 144L34.9121 144.485L38.0422 160.242L27.4482 179.636L24.0773 182.303L21.6696 184.242H17.3357L14.9279 185.455L12.0387 185.697L10.3533 187.394L6.74165 186.909L3.13006 186.667L0.481548 188.606L0 192L1.92619 189.818L5.05624 188.848L5.29701 192L10.3533 190.303L13.2425 190.061L18.2988 190.788C18.2988 190.788 22.6327 190.545 23.355 190.303C24.0773 190.303 28.8928 190.788 28.8928 190.788L32.2636 190.303L34.1898 191.03L36.5975 190.303L39.246 191.515L43.0984 191.03L43.58 188.364L43.3392 186.909L45.9877 187.879L48.1547 189.576L49.5993 191.515V189.091L47.9139 186.182C47.9139 186.182 46.71 184.485 45.9877 184.727C45.2654 184.727 42.3761 184.242 42.3761 184.242L40.4499 184.97L38.283 184L36.116 185.212L34.1898 184.485L33.2267 182.545L31.7821 182.061L33.2267 178.182L36.5975 173.333L41.1722 165.576L45.2654 160.727L46.71 158.788C46.71 158.788 48.6362 155.879 48.6362 155.152C48.6362 154.424 49.1178 146.182 49.1178 146.182L46.71 140.848L45.5061 136.485L67.6573 141.818H68.8612L87.8823 155.636L90.5308 159.03L91.4938 172.848L91.0123 176L89.5677 178.424L88.6046 179.879L87.8823 182.061L87.4007 183.515L83.7891 184.727L80.1775 184L78.0106 183.758L73.9174 184.242L72.232 185.939L71.5097 188.121L71.9912 190.303L72.7135 188.121L73.9174 186.667L75.1213 186.424V188.364L76.5659 189.333L79.696 187.879L81.1406 187.636L81.6221 189.818H86.1968L89.3269 188.848L91.9754 189.333L95.8278 189.818L97.0316 189.333L97.9947 188.364L99.6801 191.758V187.879L97.9947 183.515L95.587 182.061L96.0686 180.848L94.3831 177.455L94.6239 164.849L104.255 176.242L117.016 186.182C117.016 186.182 125.684 189.333 126.406 189.333C127.128 189.333 133.148 188.606 133.148 188.606L137 182.303L134.111 173.576L135.315 170.667L129.295 162.667L116.293 149.333L113.163 138.909L113.404 131.879L110.515 124.364L107.385 118.788L109.311 112.727L107.866 104L101.366 89.2121L103.773 88.7273L99.4394 81.9394L102.088 81.2121L97.5132 73.697L99.4394 72.7273L96.0686 66.9091L97.2724 66.1818L92.9385 62.5455L94.3831 61.8182L83.5483 54.0606L69.8243 44.3636Z" + android:fillColor="#000000" /> + </group> + +</vector> \ No newline at end of file diff --git a/app/src/custom/res/drawable-anydpi-v24/ravens.xml b/app/src/custom/res/drawable-anydpi-v24/ravens.xml new file mode 100644 index 0000000000000000000000000000000000000000..a4c3023d3950549911b195dd5a37c6bb081a6903 --- /dev/null +++ b/app/src/custom/res/drawable-anydpi-v24/ravens.xml @@ -0,0 +1,41 @@ +<vector xmlns:android="http://schemas.android.com/apk/res/android" xmlns:aapt="http://schemas.android.com/aapt" + android:viewportWidth="342" + android:viewportHeight="206" + android:width="342dp" + android:name="ravens" + android:alpha="1" + android:height="206dp"> + <group + android:name="raven1" + android:scaleX="0.8" + android:scaleY="0.8" + android:translateX="-224.2934" + android:translateY="11.72371"> + <path + android:name="raven1path" + android:pathData="M385.13834 197.43106c-0.72897 -1.36208 -0.61597 -2.15071 0.51401 -3.58724l1.0109 -1.28515 -2.7045 -3.53096c-1.67306 -2.18432 -3.16903 -3.64755 -3.92253 -3.83667 -0.78962 -0.19818 -1.46242 -0.8906 -1.91284 -1.96862 -0.78944 -1.88939 -0.68998 -1.87306 -7.21616 -1.18532 -3.17774 0.33487 -5.21281 0.85767 -7.44 1.9113 -3.28857 1.55574 -5.44061 1.80404 -6.78577 0.78292 -1.02537 -0.77836 -1.06491 -1.42761 -0.13401 -2.20019 0.38829 -0.32225 0.65829 -1.03611 0.6 -1.58634 -0.0805 -0.75951 0.24078 -1.07485 1.33401 -1.3095 0.792 -0.17 1.87322 -0.54195 2.40272 -0.82656 0.66764 -0.35886 1.7028 -0.37114 3.37723 -0.0401 3.1702 0.62683 7.16506 -0.46946 9.11061 -2.50018 0.98579 -1.02893 1.81957 -1.42897 2.97837 -1.42897 0.88512 0 2.4561 -0.432 3.49107 -0.96 1.03497 -0.528 2.21436 -0.96 2.62088 -0.96 0.40651 0 0.73912 -0.30839 0.73912 -0.68532 0 -0.54071 -0.53763 -0.62982 -2.54805 -0.42233 -3.2514 0.33557 -4.17195 -0.44353 -4.17195 -3.53092 0 -1.44319 -0.32154 -2.57878 -0.96 -3.39045 -0.528 -0.67124 -0.96 -1.49047 -0.96 -1.8205 0 -0.33004 -0.54 -0.95389 -1.2 -1.38634 -0.7646 -0.50098 -1.2 -1.23373 -1.2 -2.01949 0 -0.67827 -0.432 -1.78243 -0.96 -2.45367 -0.528 -0.67124 -0.96 -1.5865 -0.96 -2.03391 0 -0.44741 -1.15388 -2.09228 -2.56419 -3.65527 -2.97648 -3.29873 -3.67581 -4.47263 -3.67581 -6.17024 0 -1.04577 -0.21517 -1.23156 -1.42631 -1.23156 -0.78448 0 -2.67448 -0.56194 -4.2 -1.24877 -3.87341 -1.74389 -9.21645 -3.55123 -10.49851 -3.55123 -1.57962 0 -2.59518 -0.491 -2.59518 -1.2547 0 -0.53914 0.68803 -0.61839 3.48 -0.40086 3.2635 0.25428 3.40535 0.22572 2.28 -0.45912 -0.66 -0.40165 -2.226 -0.87399 -3.48 -1.04964 -2.96604 -0.41545 -2.93747 -1.15568 0.0446 -1.15568 1.92868 0 9.64234 2.10373 13.15539 3.58785 0.50332 0.21263 0.84 0.14513 0.84 -0.16841 0 -0.28779 -1.13158 -1.09668 -2.51463 -1.79753 -2.92533 -1.48238 -12.13912 -7.58751 -12.61637 -8.35971 -1.35099 -2.18595 3.01241 -0.0675 12.14639 5.89721 3.24247 2.1174 6.04388 3.70133 6.22536 3.51984 0.18149 -0.18148 -0.38708 -0.89116 -1.26349 -1.57704 -2.20209 -1.7234 -10.13726 -10.73208 -10.13726 -11.50869 0 -1.14242 0.85579 -0.66795 2.72266 1.5095 2.27855 2.65762 9.24491 8.66726 13.01433 11.22703 2.8929 1.96453 11.64578 6.78995 12.31636 6.78995 0.20542 0 0.23167 -0.756 0.0583 -1.68 -0.22647 -1.20719 -0.14019 -1.69436 0.30658 -1.73102 0.34197 -0.0281 1.03481 -0.0821 1.53965 -0.12 1.86068 -0.13982 1.16626 -1.06327 -1.60872 -2.13929 -1.56874 -0.6083 -3.78307 -1.85532 -4.92072 -2.77115 -1.13765 -0.91584 -3.09446 -2.43544 -4.34846 -3.37688 -4.34658 -3.2632 -1.75366 -4.17202 3.18156 -1.11514 2.26983 1.40594 3.91431 1.53202 1.97844 0.15169 -6.31808 -4.50497 -6.96 -5.05256 -6.96 -5.93721 0 -0.52855 0.11494 -0.961 0.25542 -0.961 0.78964 0 4.15067 1.74166 8.39825 4.35188 2.65524 1.63171 4.93892 2.85554 5.07483 2.71963 0.13591 -0.13592 -1.94842 -2.37661 -4.63184 -4.97931 -5.53891 -5.37229 -7.03228 -7.22857 -6.35791 -7.90295 0.56718 -0.56718 1.61175 0.22173 8.939 6.7512 3.12276 2.78275 5.93076 5.14466 6.24 5.24868 0.30924 0.10402 -1.50978 -1.95528 -4.04226 -4.57623 -4.62994 -4.79166 -7.54368 -8.5847 -7.00693 -9.12146 0.15897 -0.15897 2.25393 1.41143 4.65545 3.48976 4.14801 3.58979 5.79244 4.76276 5.09498 3.63424 -0.17306 -0.28001 -0.11466 -0.6327 0.12976 -0.78376 0.64416 -0.39811 17.86024 17.63295 19.07981 19.98301 1.60753 3.09765 1.75025 5.81492 0.61158 11.64343 -0.65753 3.36572 -0.90221 5.90827 -0.699 7.26344 0.29317 1.95498 0.42327 2.10307 2.08577 2.37409 0.9752 0.15898 2.42109 0.39924 3.21309 0.5339 5.1256 0.87155 13.65736 4.80211 12.94067 5.96174 -0.15253 0.24679 -1.93858 0.44985 -3.969 0.45124 -3.88293 0.003 -3.90932 0.0128 -8.39867 3.23101 -1.6107 1.15463 -3.37986 1.81494 -6.89008 2.5716 -4.81503 1.03793 -7.97908 2.51326 -12.88292 6.00704 -4.80978 3.42677 -4.95621 3.84823 -2.4 6.90782 2.66507 3.18989 2.14762 5.66217 -1.51355 7.23153 -2.68358 1.15032 -2.89394 1.15032 -3.50956 0.00003zm4.78311 -5.20219c0 -0.57904 -2.89719 -3.94937 -3.39495 -3.94937 -0.77051 0 -0.49203 0.68428 1.0299 2.53064 1.38291 1.67772 2.36505 2.26687 2.36505 1.41873z" + android:fillColor="#00000000" /> + </group> + <group + android:name="raven3" + android:scaleX="0.8" + android:scaleY="0.8" + android:translateX="-77.92102" + android:translateY="-54.82651"> + <path + android:name="raven3path" + android:pathData="M447.80204 216.9559c-0.72269 -0.39213 -1.64623 -1.35548 -2.05233 -2.14078 -0.92258 -1.78409 -1.47725 -1.82526 -1.45263 -0.10784 0.0256 1.78611 -1.56103 1.9993 -3.05379 0.41034 -0.92579 -0.98546 -1.26967 -1.09461 -2.00395 -0.63604 -0.71993 0.4496 -1.15887 0.3521 -2.33731 -0.51916 -1.20317 -0.88954 -1.60809 -0.97455 -2.37139 -0.49787 -0.73689 0.4602 -1.14575 0.42723 -2.0501 -0.16532 -0.64725 -0.42409 -1.74409 -0.64998 -2.56857 -0.52897 -1.09407 0.16058 -1.71749 -0.0853 -2.60113 -1.02589 -0.6392 -0.6804 -1.5772 -1.23709 -2.08445 -1.23709 -0.50725 0 -1.49559 -0.32252 -2.19633 -0.71671 -0.70073 -0.39419 -1.81406 -0.93368 -2.47406 -1.19885 -0.66 -0.26518 -1.524 -0.66225 -1.92 -0.88239 -2.1004 -1.1676 -3.9862 -2.00205 -4.5245 -2.00205 -0.33369 0 -0.99766 -0.432 -1.4755 -0.96 -0.47783 -0.528 -1.16856 -0.96 -1.53495 -0.96 -0.77161 0 -6.74173 -3.13454 -7.86284 -4.12828 -0.89689 -0.79501 -2.53748 -0.86858 -3.83877 -0.17215 -0.51341 0.27477 -1.88229 2.38077 -3.04196 4.68 -1.15968 2.29924 -2.72649 4.76604 -3.4818 5.48179 -1.40184 1.32842 -5.12659 2.93173 -5.63342 2.4249 -0.1543 -0.15429 -1.70398 -0.32663 -3.44374 -0.38296 -2.32752 -0.0754 -3.51734 -0.36424 -4.50361 -1.09342 -0.81562 -0.60301 -1.73721 -0.88722 -2.35394 -0.72594 -1.35459 0.35423 -3.92189 -0.18553 -5.09262 -1.0707 -0.66178 -0.50036 -0.98915 -1.4008 -1.08522 -2.98487 -0.0757 -1.2476 -0.25951 -4.04558 -0.40856 -6.21772 -0.25931 -3.77896 -0.21836 -3.99814 0.94896 -5.07999 1.35121 -1.25225 4.13171 -1.97137 10.61247 -2.74472 5.3395 -0.63715 6.25903 -0.85126 8.52 -1.98381 1.76578 -0.8845 2.45969 -2.32213 1.12084 -2.32213 -0.37355 0 -1.5596 -1.134 -2.63568 -2.52 -2.13022 -2.74373 -2.50653 -3.16958 -3.62217 -4.09893 -0.40864 -0.3404 -0.74299 -1.12556 -0.74299 -1.74479 0 -0.67126 -0.48454 -1.44336 -1.2 -1.91214 -0.66 -0.43245 -1.2 -1.23621 -1.2 -1.78612 0 -0.54992 -0.54 -1.42462 -1.2 -1.94378 -0.66 -0.51916 -1.2 -1.34367 -1.2 -1.83225 0 -0.48859 -0.54 -1.53009 -1.2 -2.31445 -0.66 -0.78437 -1.2 -1.85934 -1.2 -2.38883 0 -0.52949 -0.756 -1.71871 -1.68 -2.64271 -0.924 -0.924 -1.68 -2.09595 -1.68 -2.60433 0 -0.50838 -0.55232 -1.44321 -1.22738 -2.07739 -0.81219 -0.76302 -1.14213 -1.47902 -0.97538 -2.11669 0.17148 -0.65575 -0.2374 -1.46856 -1.27973 -2.54398 -1.31288 -1.35454 -1.4494 -1.71218 -0.95549 -2.50306 0.48388 -0.77482 0.38564 -1.14926 -0.61288 -2.33593 -1.29697 -1.54136 -1.48117 -2.47059 -0.65374 -3.29802 0.39386 -0.39386 0.19307 -0.98422 -0.75958 -2.2332 -0.88414 -1.15917 -1.19604 -2.00954 -0.98311 -2.68042 0.2246 -0.70765 -0.16728 -1.56735 -1.40042 -3.07223 -2.52054 -3.076 -2.28628 -3.69399 0.92771 -2.44729 0.528 0.20481 -0.498 -1.15368 -2.28 -3.01887 -2.97172 -3.11045 -3.98593 -4.92459 -2.75312 -4.92459 0.26778 0 2.38692 1.48253 4.7092 3.29452 6.33422 4.94234 8.3162 5.80749 3.95158 1.7249 -4.36141 -4.07959 -8.0677 -9.81942 -6.34054 -9.81942 0.28116 0 2.49842 2.05416 4.92723 4.5648 2.42882 2.51065 4.49954 4.48131 4.60161 4.37925 0.10205 -0.10206 -0.98133 -1.73668 -2.40752 -3.63249 -1.42619 -1.89581 -2.85494 -4.32096 -3.17499 -5.38921 -0.32005 -1.06825 -0.69762 -2.24379 -0.83904 -2.61231 -0.72243 -1.88264 1.03187 -0.1508 4.3051 4.24996 2.01269 2.706 4.67913 5.892 5.92543 7.08l2.266 2.16 -1.79464 -2.4c-2.2233 -2.97326 -4.5686 -7.73418 -4.94128 -10.03072 -0.44513 -2.74301 0.50313 -2.04466 2.37988 1.75269 1.66581 3.37055 8.26211 12.81454 9.47338 13.56314 0.32795 0.20269 0.50635 0.17645 0.39644 -0.0583 -0.1099 -0.23474 -1.00191 -2.04072 -1.98227 -4.01327 -0.98034 -1.97255 -1.78245 -3.86255 -1.78245 -4.2 0 -1.51072 0.98617 -0.31134 2.75157 3.34646 2.25366 4.66945 5.11203 8.56401 10.59899 14.44126 4.9305 5.28122 8.54604 10.06515 10.94256 14.47874 6.17495 11.37222 8.31949 13.01948 14.29789 10.98244 2.27587 -0.77547 3.24479 -0.75419 9.27398 0.20364 2.25404 0.35809 4.45501 1.59731 4.45501 2.50832 0 0.19008 -0.60035 0.46567 -1.3341 0.61242 -0.73377 0.14675 -1.86777 0.78823 -2.52 1.42549 -1.81377 1.77213 -5.26658 5.9971 -5.26039 6.43677 0.006 0.39975 0.80419 0.80728 7.34031 3.74603 4.42236 1.98837 8.73868 4.82625 10.41418 6.84709 2.22226 2.68029 9.70388 8.73695 12.42297 10.05689 2.10404 1.02137 2.46767 1.34537 1.65388 1.47363 -0.57373 0.0904 -1.97773 -0.30571 -3.12 -0.88029l-2.07685 -1.04469 1.3513 1.43507c0.74321 0.78928 2.79521 2.15598 4.56 3.03711 2.62921 1.31274 3.00331 1.63456 2.07139 1.78197 -0.62552 0.099 -2.40778 -0.44981 -3.96059 -1.21945 -2.26132 -1.12081 -2.65597 -1.21281 -1.9827 -0.4622 0.46233 0.51543 1.9746 1.57936 3.3606 2.36428 1.386 0.78492 2.52 1.65077 2.52 1.92411 0 0.83627 -3.35317 0.0235 -5.34728 -1.29618 -2.37621 -1.5725 -2.35309 -0.95606 0.0673 1.79363 2.28368 2.59439 2.44317 3.37594 0.6 2.94004 -1.49775 -0.3542 -4.44 -2.40221 -4.44 -3.09054 0 -0.25057 -0.23446 -0.45558 -0.52103 -0.45558 -0.28658 0 0.0374 0.99921 0.72 2.22046 0.68257 1.22125 1.24103 2.40925 1.24103 2.64 0 0.63619 -1.52046 0.46767 -2.99396 -0.33184z" + android:fillColor="#00000000" /> + </group> + <group + android:name="raven2" + android:scaleX="0.8" + android:scaleY="0.8" + android:translateX="-14.21506" + android:translateY="22.70211"> + <path + android:name="raven2path" + android:pathData="M242.17687 151.65225c-1.74028 -2.28162 -2.178 -4.03768 -2.178 -8.73776 0 -2.17974 -0.18432 -3.96317 -0.4096 -3.96317 -0.22529 0 -0.71129 2.81516 -1.08 6.25591 -0.36872 3.44074 -0.8864 6.28072 -1.1504 6.31105 -1.04841 0.12049 -2.28619 -3.10071 -2.57984 -6.71376l-0.30016 -3.6932 -1.07056 1.81145c-2.08936 3.5353 -3.47008 2.84679 -3.48209 -1.73638 -0.006 -2.37601 -0.1508 -2.84246 -0.94546 -3.05027 -0.61539 -0.16092 -1.21919 -1.09153 -1.75512 -2.70506 -0.44935 -1.35286 -1.32319 -2.85792 -1.94188 -3.34458 -0.78894 -0.62057 -1.12489 -1.37616 -1.12489 -2.53 0 -2.06355 -0.60376 -2.09129 -1.85358 -0.0852 -1.18439 1.90109 -2.71192 2.89912 -3.87313 2.53057 -0.64166 -0.20366 -1.0246 0.1062 -1.47495 1.19345 -0.7302 1.76286 -2.63143 3.35598 -4.00504 3.35598 -0.54848 0 -1.46581 0.58765 -2.03851 1.30588 -0.89827 1.12654 -1.14794 1.21735 -1.81803 0.66123 -0.42722 -0.35456 -0.77543 -1.32021 -0.7738 -2.14588 0.003 -1.54988 0.31834 -2.30174 2.59201 -6.18123 2.37785 -4.05724 0.51183 -2.41446 -2.48575 2.18836 -3.12365 4.79641 -4.09991 5.87182 -4.88819 5.38464 -1.17655 -0.72715 -0.0446 -4.77763 2.18334 -7.813 1.22554 -1.66965 0.0938 -1.27585 -1.72437 0.6 -2.65534 2.73963 -4.34104 1.74204 -2.45575 -1.4533 0.93339 -1.58198 0.94531 -1.72299 0.1698 -2.00903 -1.26447 -0.4664 -1.46738 -1.03369 -1.04291 -2.91573 0.30278 -1.34248 0.21909 -1.84412 -0.38085 -2.28281 -0.75536 -0.55233 -0.9059 -1.41732 -1.24948 -7.17913 -0.20592 -3.45317 -1.35998 -10.32002 -1.73441 -10.31993 -0.14652 0.00003 -3.1824 0.88931 -6.7464 1.97616 -3.564 1.08684 -6.8656 2.086 -7.33688 2.22033 -0.47128 0.13433 -2.09128 -0.15192 -3.6 -0.63611 -1.50872 -0.48419 -3.01312 -0.8259 -3.34312 -0.75935 -1.2262 0.24726 -0.53956 -1.304 1.32139 -2.98524 1.05676 -0.95472 2.08554 -1.73586 2.28617 -1.73586 0.20064 0 0.57802 -0.486 0.83862 -1.08 0.54254 -1.23661 2.67944 -1.701199 8.15382 -1.772749 5.57725 -0.0729 9.57243 -1.17346 13.90516 -3.83049 4.52997 -2.77799 15.85234 -6.751008 22.57484 -7.921507 2.65339 -0.462 7.19029 -0.754493 11.76 -0.758165 7.33879 -0.0059 7.50857 0.01795 12.48 1.754669 4.64388 1.622275 7.89361 3.607435 7.55725 4.616496 -0.0759 0.227717 -1.8631 0.454018 -3.97155 0.502891 -3.40039 0.07882 -4.27825 0.305799 -7.76936 2.008856 -2.16469 1.056 -3.93825 2.136 -3.94123 2.4 -0.003 0.264 0.9368 1.1895 2.0884 2.056649 1.1516 0.86716 2.32074 2.16316 2.59809 2.88 0.61481 1.58903 2.47015 14.53738 2.49976 17.44571 0.0373 3.66931 1.70932 11.11002 3.22173 14.33764 1.81937 3.88271 1.28959 4.93466 -1.08652 2.15745 -0.90229 -1.05459 -1.64863 -1.65817 -1.65854 -1.34126 -0.0271 0.86542 3.28286 9.82211 4.07847 11.03636 0.38106 0.58156 0.50275 1.17487 0.27043 1.31845 -0.59625 0.3685 -3.42187 -2.90311 -4.8461 -5.611 -0.65955 -1.254 -1.36566 -2.28 -1.56915 -2.28 -0.40909 0 -0.35407 0.31827 1.09899 6.35685 1.05557 4.3867 0.95137 5.67912 -0.36978 4.58646 -0.90254 -0.74644 -2.98958 -5.08951 -2.9962 -6.23498 -0.002 -0.44642 -0.2554 -0.96662 -0.56182 -1.156 -0.41664 -0.2575 -0.47655 0.88529 -0.23759 4.53167 0.18049 2.75413 0.13441 4.876 -0.1059 4.876 -0.23399 0 -1.00861 -0.76458 -1.72138 -1.69907z" + android:fillColor="#00000000" /> + </group> +</vector> \ No newline at end of file diff --git a/app/src/custom/res/drawable-anydpi-v24/rotate_progress_image.xml b/app/src/custom/res/drawable-anydpi-v24/rotate_progress_image.xml new file mode 100644 index 0000000000000000000000000000000000000000..f84f90342f3c59901af0da61189d28eb11ec30f2 --- /dev/null +++ b/app/src/custom/res/drawable-anydpi-v24/rotate_progress_image.xml @@ -0,0 +1,14 @@ +<vector xmlns:android="http://schemas.android.com/apk/res/android" xmlns:aapt="http://schemas.android.com/aapt" + android:name="circle" + android:viewportWidth="91" + android:viewportHeight="91" + android:width="91dp" + android:height="91dp"> + <path + android:pathData="M0 0" + android:fillColor="#00000000" /> + <!-- + Implement your progress animation vector graphic here. + The graphic will rotate behind the cancel button in EipFragment. + --> +</vector> \ No newline at end of file diff --git a/app/src/custom/res/drawable-anydpi-v24/state_connected.xml b/app/src/custom/res/drawable-anydpi-v24/state_connected.xml new file mode 100644 index 0000000000000000000000000000000000000000..e0a9005f6c6000d7a81e7ccd922d2477efe537a3 --- /dev/null +++ b/app/src/custom/res/drawable-anydpi-v24/state_connected.xml @@ -0,0 +1,27 @@ +<vector xmlns:android="http://schemas.android.com/apk/res/android" xmlns:aapt="http://schemas.android.com/aapt" + android:viewportWidth="166" + android:viewportHeight="220" + android:width="166dp" + android:height="220dp"> + + <path + android:name="shield1" + android:pathData="M75.7916 211.927C37.7611 190.779 9.33369 157.386 2.89166 126.295C1.07036 117.505 0.998811 115.374 1.00089 69.9755L1.0025 26.6083L4.76437 24.1851C20.6619 13.9449 37.4788 7.09821 54.6105 3.64229C89.5868 -3.41322 125.875 3.66238 158.333 24.8539L161 26.5952V70.1783C161 115.754 160.927 117.944 159.119 126.65C152.713 157.49 128.092 187.572 91.7515 208.96C81.1937 215.174 81.5205 215.113 75.7916 211.927Z" + android:fillColor="#739B4C" /> + <path + android:name="shield2" + android:pathData="M81.0089 1.00082C72.1811 0.99767 63.3554 1.87831 54.6114 3.64218C37.4796 7.09809 20.6622 13.9447 4.76468 24.185L1.00318 26.608L1.00002 69.9756C0.998421 115.374 1.06949 117.505 2.89058 126.295C9.3326 157.386 37.76 190.778 75.7905 211.927H75.7913C78.2626 213.301 79.6075 214.092 81.1849 214.051V1.00327C81.1259 1.00314 81.0673 1 81.008 1L81.0089 1.00082Z" + android:fillColor="#81A55D" /> + <group + android:scaleX="0.65" + android:scaleY="0.65" + android:translateX="42" + android:translateY="30" + > + <path + android:pathData="M69.8243 44.3636C69.8243 44.3636 66.935 38.7879 66.6942 38.0606C66.4534 37.3333 65.0088 29.3333 65.0088 29.3333L66.935 25.9394L71.2689 19.6364L77.2882 14.7879L78.7328 14.303L93.42 8.72727L94.8647 7.27273L93.42 4.84849L91.2531 3.63636L87.4007 2.66666L77.7698 1.69697H70.3058L65.2496 2.90909L60.6749 1.21212L54.8963 0.484846L46.4692 0.242421L42.1353 0L35.1529 2.66666L24.3181 15.2727L22.8735 20.1212L22.1511 24.4848L18.5395 32.4848L16.1318 40L14.9279 48V49.697L9.39016 58.1818L6.26011 64.4848V73.4545L7.2232 92.1212L8.90861 98.9091L12.2794 105.212L16.6134 109.333L18.5395 117.333L25.7627 133.576L34.4306 144L34.9121 144.485L38.0422 160.242L27.4482 179.636L24.0773 182.303L21.6696 184.242H17.3357L14.9279 185.455L12.0387 185.697L10.3533 187.394L6.74165 186.909L3.13006 186.667L0.481548 188.606L0 192L1.92619 189.818L5.05624 188.848L5.29701 192L10.3533 190.303L13.2425 190.061L18.2988 190.788C18.2988 190.788 22.6327 190.545 23.355 190.303C24.0773 190.303 28.8928 190.788 28.8928 190.788L32.2636 190.303L34.1898 191.03L36.5975 190.303L39.246 191.515L43.0984 191.03L43.58 188.364L43.3392 186.909L45.9877 187.879L48.1547 189.576L49.5993 191.515V189.091L47.9139 186.182C47.9139 186.182 46.71 184.485 45.9877 184.727C45.2654 184.727 42.3761 184.242 42.3761 184.242L40.4499 184.97L38.283 184L36.116 185.212L34.1898 184.485L33.2267 182.545L31.7821 182.061L33.2267 178.182L36.5975 173.333L41.1722 165.576L45.2654 160.727L46.71 158.788C46.71 158.788 48.6362 155.879 48.6362 155.152C48.6362 154.424 49.1178 146.182 49.1178 146.182L46.71 140.848L45.5061 136.485L67.6573 141.818H68.8612L87.8823 155.636L90.5308 159.03L91.4938 172.848L91.0123 176L89.5677 178.424L88.6046 179.879L87.8823 182.061L87.4007 183.515L83.7891 184.727L80.1775 184L78.0106 183.758L73.9174 184.242L72.232 185.939L71.5097 188.121L71.9912 190.303L72.7135 188.121L73.9174 186.667L75.1213 186.424V188.364L76.5659 189.333L79.696 187.879L81.1406 187.636L81.6221 189.818H86.1968L89.3269 188.848L91.9754 189.333L95.8278 189.818L97.0316 189.333L97.9947 188.364L99.6801 191.758V187.879L97.9947 183.515L95.587 182.061L96.0686 180.848L94.3831 177.455L94.6239 164.849L104.255 176.242L117.016 186.182C117.016 186.182 125.684 189.333 126.406 189.333C127.128 189.333 133.148 188.606 133.148 188.606L137 182.303L134.111 173.576L135.315 170.667L129.295 162.667L116.293 149.333L113.163 138.909L113.404 131.879L110.515 124.364L107.385 118.788L109.311 112.727L107.866 104L101.366 89.2121L103.773 88.7273L99.4394 81.9394L102.088 81.2121L97.5132 73.697L99.4394 72.7273L96.0686 66.9091L97.2724 66.1818L92.9385 62.5455L94.3831 61.8182L83.5483 54.0606L69.8243 44.3636Z" + android:fillColor="#000000" /> + </group> + + +</vector> \ No newline at end of file diff --git a/app/src/custom/res/drawable-anydpi-v24/state_connecting.xml b/app/src/custom/res/drawable-anydpi-v24/state_connecting.xml new file mode 100644 index 0000000000000000000000000000000000000000..77207966b8909eb7c9e308766ffd157778a78d63 --- /dev/null +++ b/app/src/custom/res/drawable-anydpi-v24/state_connecting.xml @@ -0,0 +1,18 @@ +<?xml version="1.0" encoding="utf-8"?> +<animated-vector xmlns:android="http://schemas.android.com/apk/res/android" + android:drawable="@drawable/ravens" + > + <target + android:animation="@animator/alpha4" + android:name="ravens" /> + <target + android:animation="@animator/alpha1" + android:name="raven1path"/> + <target + android:animation="@animator/alpha2" + android:name="raven2path"/> + <target + android:animation="@animator/alpha3" + android:name="raven3path"/> + +</animated-vector> \ No newline at end of file diff --git a/app/src/custom/res/drawable-anydpi-v24/state_disconnected.xml b/app/src/custom/res/drawable-anydpi-v24/state_disconnected.xml new file mode 100644 index 0000000000000000000000000000000000000000..7c49a53715f9c8aade082042c09958ffeec6b43a --- /dev/null +++ b/app/src/custom/res/drawable-anydpi-v24/state_disconnected.xml @@ -0,0 +1,17 @@ +<vector xmlns:android="http://schemas.android.com/apk/res/android" xmlns:aapt="http://schemas.android.com/aapt" + android:viewportWidth="166" + android:viewportHeight="220" + android:width="166dp" + android:height="220dp"> + <group + android:scaleX="0.725" + android:scaleY="0.725" + android:translateX="36" + android:translateY="36" + > + <path + android:pathData="M69.8243 44.3636C69.8243 44.3636 66.935 38.7879 66.6942 38.0606C66.4534 37.3333 65.0088 29.3333 65.0088 29.3333L66.935 25.9394L71.2689 19.6364L77.2882 14.7879L78.7328 14.303L93.42 8.72727L94.8647 7.27273L93.42 4.84849L91.2531 3.63636L87.4007 2.66666L77.7698 1.69697H70.3058L65.2496 2.90909L60.6749 1.21212L54.8963 0.484846L46.4692 0.242421L42.1353 0L35.1529 2.66666L24.3181 15.2727L22.8735 20.1212L22.1511 24.4848L18.5395 32.4848L16.1318 40L14.9279 48V49.697L9.39016 58.1818L6.26011 64.4848V73.4545L7.2232 92.1212L8.90861 98.9091L12.2794 105.212L16.6134 109.333L18.5395 117.333L25.7627 133.576L34.4306 144L34.9121 144.485L38.0422 160.242L27.4482 179.636L24.0773 182.303L21.6696 184.242H17.3357L14.9279 185.455L12.0387 185.697L10.3533 187.394L6.74165 186.909L3.13006 186.667L0.481548 188.606L0 192L1.92619 189.818L5.05624 188.848L5.29701 192L10.3533 190.303L13.2425 190.061L18.2988 190.788C18.2988 190.788 22.6327 190.545 23.355 190.303C24.0773 190.303 28.8928 190.788 28.8928 190.788L32.2636 190.303L34.1898 191.03L36.5975 190.303L39.246 191.515L43.0984 191.03L43.58 188.364L43.3392 186.909L45.9877 187.879L48.1547 189.576L49.5993 191.515V189.091L47.9139 186.182C47.9139 186.182 46.71 184.485 45.9877 184.727C45.2654 184.727 42.3761 184.242 42.3761 184.242L40.4499 184.97L38.283 184L36.116 185.212L34.1898 184.485L33.2267 182.545L31.7821 182.061L33.2267 178.182L36.5975 173.333L41.1722 165.576L45.2654 160.727L46.71 158.788C46.71 158.788 48.6362 155.879 48.6362 155.152C48.6362 154.424 49.1178 146.182 49.1178 146.182L46.71 140.848L45.5061 136.485L67.6573 141.818H68.8612L87.8823 155.636L90.5308 159.03L91.4938 172.848L91.0123 176L89.5677 178.424L88.6046 179.879L87.8823 182.061L87.4007 183.515L83.7891 184.727L80.1775 184L78.0106 183.758L73.9174 184.242L72.232 185.939L71.5097 188.121L71.9912 190.303L72.7135 188.121L73.9174 186.667L75.1213 186.424V188.364L76.5659 189.333L79.696 187.879L81.1406 187.636L81.6221 189.818H86.1968L89.3269 188.848L91.9754 189.333L95.8278 189.818L97.0316 189.333L97.9947 188.364L99.6801 191.758V187.879L97.9947 183.515L95.587 182.061L96.0686 180.848L94.3831 177.455L94.6239 164.849L104.255 176.242L117.016 186.182C117.016 186.182 125.684 189.333 126.406 189.333C127.128 189.333 133.148 188.606 133.148 188.606L137 182.303L134.111 173.576L135.315 170.667L129.295 162.667L116.293 149.333L113.163 138.909L113.404 131.879L110.515 124.364L107.385 118.788L109.311 112.727L107.866 104L101.366 89.2121L103.773 88.7273L99.4394 81.9394L102.088 81.2121L97.5132 73.697L99.4394 72.7273L96.0686 66.9091L97.2724 66.1818L92.9385 62.5455L94.3831 61.8182L83.5483 54.0606L69.8243 44.3636Z" + android:fillColor="#000000" /> + </group> + +</vector> \ No newline at end of file diff --git a/app/src/custom/res/drawable-anydpi-v24/state_transition_connected_disconnected.xml b/app/src/custom/res/drawable-anydpi-v24/state_transition_connected_disconnected.xml new file mode 100644 index 0000000000000000000000000000000000000000..0496e7295569b5204fb44882dbc734fe8573c560 --- /dev/null +++ b/app/src/custom/res/drawable-anydpi-v24/state_transition_connected_disconnected.xml @@ -0,0 +1,89 @@ +<animated-vector + xmlns:android="http://schemas.android.com/apk/res/android" + xmlns:aapt="http://schemas.android.com/aapt"> + <aapt:attr name="android:drawable"> + <vector + android:name="vector" + android:width="166dp" + android:height="220dp" + android:viewportWidth="166" + android:viewportHeight="220"> + <path + android:name="shield1" + android:pathData="M 75.792 211.927 C 37.761 190.779 9.334 157.386 2.892 126.295 C 1.07 117.505 0.999 115.374 1.001 69.975 L 1.002 26.608 L 4.764 24.185 C 20.662 13.945 37.479 7.098 54.611 3.642 C 89.587 -3.413 125.875 3.662 158.333 24.854 L 161 26.595 L 161 70.178 C 161 115.754 160.927 117.944 159.119 126.65 C 152.713 157.49 128.092 187.572 91.751 208.96 C 81.194 215.174 81.52 215.113 75.792 211.927 Z" + android:fillColor="#739B4C"/> + <path + android:name="shield2" + android:pathData="M 81.009 1.001 C 72.181 0.998 63.355 1.878 54.611 3.642 C 37.48 7.098 20.662 13.945 4.765 24.185 L 1.003 26.608 L 1 69.976 C 0.998 115.374 1.069 117.505 2.891 126.295 C 9.333 157.386 37.76 190.778 75.79 211.927 L 75.791 211.927 C 78.263 213.301 79.608 214.092 81.185 214.051 L 81.185 1.003 C 81.126 1.003 81.067 1 81.008 1 L 81.009 1.001 Z" + android:fillColor="#81A55D"/> + <group + android:name="ravenGroup" + android:scaleX="0.65" + android:scaleY="0.65" + android:translateX="42" + android:translateY="30" + > + <path + android:pathData="M69.8243 44.3636C69.8243 44.3636 66.935 38.7879 66.6942 38.0606C66.4534 37.3333 65.0088 29.3333 65.0088 29.3333L66.935 25.9394L71.2689 19.6364L77.2882 14.7879L78.7328 14.303L93.42 8.72727L94.8647 7.27273L93.42 4.84849L91.2531 3.63636L87.4007 2.66666L77.7698 1.69697H70.3058L65.2496 2.90909L60.6749 1.21212L54.8963 0.484846L46.4692 0.242421L42.1353 0L35.1529 2.66666L24.3181 15.2727L22.8735 20.1212L22.1511 24.4848L18.5395 32.4848L16.1318 40L14.9279 48V49.697L9.39016 58.1818L6.26011 64.4848V73.4545L7.2232 92.1212L8.90861 98.9091L12.2794 105.212L16.6134 109.333L18.5395 117.333L25.7627 133.576L34.4306 144L34.9121 144.485L38.0422 160.242L27.4482 179.636L24.0773 182.303L21.6696 184.242H17.3357L14.9279 185.455L12.0387 185.697L10.3533 187.394L6.74165 186.909L3.13006 186.667L0.481548 188.606L0 192L1.92619 189.818L5.05624 188.848L5.29701 192L10.3533 190.303L13.2425 190.061L18.2988 190.788C18.2988 190.788 22.6327 190.545 23.355 190.303C24.0773 190.303 28.8928 190.788 28.8928 190.788L32.2636 190.303L34.1898 191.03L36.5975 190.303L39.246 191.515L43.0984 191.03L43.58 188.364L43.3392 186.909L45.9877 187.879L48.1547 189.576L49.5993 191.515V189.091L47.9139 186.182C47.9139 186.182 46.71 184.485 45.9877 184.727C45.2654 184.727 42.3761 184.242 42.3761 184.242L40.4499 184.97L38.283 184L36.116 185.212L34.1898 184.485L33.2267 182.545L31.7821 182.061L33.2267 178.182L36.5975 173.333L41.1722 165.576L45.2654 160.727L46.71 158.788C46.71 158.788 48.6362 155.879 48.6362 155.152C48.6362 154.424 49.1178 146.182 49.1178 146.182L46.71 140.848L45.5061 136.485L67.6573 141.818H68.8612L87.8823 155.636L90.5308 159.03L91.4938 172.848L91.0123 176L89.5677 178.424L88.6046 179.879L87.8823 182.061L87.4007 183.515L83.7891 184.727L80.1775 184L78.0106 183.758L73.9174 184.242L72.232 185.939L71.5097 188.121L71.9912 190.303L72.7135 188.121L73.9174 186.667L75.1213 186.424V188.364L76.5659 189.333L79.696 187.879L81.1406 187.636L81.6221 189.818H86.1968L89.3269 188.848L91.9754 189.333L95.8278 189.818L97.0316 189.333L97.9947 188.364L99.6801 191.758V187.879L97.9947 183.515L95.587 182.061L96.0686 180.848L94.3831 177.455L94.6239 164.849L104.255 176.242L117.016 186.182C117.016 186.182 125.684 189.333 126.406 189.333C127.128 189.333 133.148 188.606 133.148 188.606L137 182.303L134.111 173.576L135.315 170.667L129.295 162.667L116.293 149.333L113.163 138.909L113.404 131.879L110.515 124.364L107.385 118.788L109.311 112.727L107.866 104L101.366 89.2121L103.773 88.7273L99.4394 81.9394L102.088 81.2121L97.5132 73.697L99.4394 72.7273L96.0686 66.9091L97.2724 66.1818L92.9385 62.5455L94.3831 61.8182L83.5483 54.0606L69.8243 44.3636Z" + android:fillColor="#000000" /> + </group> + + </vector> + </aapt:attr> + <target android:name="shield1"> + <aapt:attr name="android:animation"> + <objectAnimator + android:propertyName="fillAlpha" + android:duration="300" + android:valueFrom="1" + android:valueTo="0" + android:valueType="floatType" + android:interpolator="@android:interpolator/fast_out_slow_in"/> + </aapt:attr> + </target> + <target android:name="shield2"> + <aapt:attr name="android:animation"> + <objectAnimator + android:propertyName="fillAlpha" + android:duration="300" + android:valueFrom="1" + android:valueTo="0" + android:valueType="floatType" + android:interpolator="@android:interpolator/fast_out_slow_in"/> + </aapt:attr> + </target> + <target android:name="ravenGroup"> + <aapt:attr name="android:animation"> + <set> + <objectAnimator + android:propertyName="scaleX" + android:duration="300" + android:valueFrom="0.65" + android:valueTo="0.725" + android:valueType="floatType" + android:interpolator="@android:interpolator/fast_out_slow_in"/> + <objectAnimator + android:propertyName="scaleY" + android:duration="300" + android:valueFrom="0.65" + android:valueTo="0.725" + android:valueType="floatType" + android:interpolator="@android:interpolator/fast_out_slow_in"/> + <objectAnimator + android:propertyName="translateX" + android:duration="300" + android:valueFrom="42" + android:valueTo="36" + android:valueType="floatType" + android:interpolator="@android:interpolator/fast_out_slow_in"/> + <objectAnimator + android:propertyName="translateY" + android:duration="300" + android:valueFrom="30" + android:valueTo="36" + android:valueType="floatType" + android:interpolator="@android:interpolator/fast_out_slow_in"/> + </set> + </aapt:attr> + </target> +</animated-vector> diff --git a/app/src/custom/res/drawable-hdpi/bg_connected.png b/app/src/custom/res/drawable-hdpi/bg_connected.png new file mode 100644 index 0000000000000000000000000000000000000000..aa29fd908b5cfd3c0d78199a688b6f76b49d4d91 Binary files /dev/null and b/app/src/custom/res/drawable-hdpi/bg_connected.png differ diff --git a/app/src/custom/res/drawable-hdpi/bg_connecting.png b/app/src/custom/res/drawable-hdpi/bg_connecting.png new file mode 100644 index 0000000000000000000000000000000000000000..49620c2c9c407fa192cb177ed9d730a99fb8b536 Binary files /dev/null and b/app/src/custom/res/drawable-hdpi/bg_connecting.png differ diff --git a/app/src/custom/res/drawable-hdpi/bg_disconnected.png b/app/src/custom/res/drawable-hdpi/bg_disconnected.png new file mode 100644 index 0000000000000000000000000000000000000000..35180222f4a4638b374c1221d352636fb9ff7e60 Binary files /dev/null and b/app/src/custom/res/drawable-hdpi/bg_disconnected.png differ diff --git a/app/src/custom/res/drawable-xhdpi/bg_connected.png b/app/src/custom/res/drawable-xhdpi/bg_connected.png new file mode 100644 index 0000000000000000000000000000000000000000..f9588d56599a1729b515b5fdb37cf5cead69705d Binary files /dev/null and b/app/src/custom/res/drawable-xhdpi/bg_connected.png differ diff --git a/app/src/custom/res/drawable-xhdpi/bg_connecting.png b/app/src/custom/res/drawable-xhdpi/bg_connecting.png new file mode 100644 index 0000000000000000000000000000000000000000..294e4708c5adf7d9688009c88e46ebb59ea63b57 Binary files /dev/null and b/app/src/custom/res/drawable-xhdpi/bg_connecting.png differ diff --git a/app/src/custom/res/drawable-xhdpi/bg_disconnected.png b/app/src/custom/res/drawable-xhdpi/bg_disconnected.png new file mode 100644 index 0000000000000000000000000000000000000000..d18bc78ea95fb877e1f583947b6e4927afa9230b Binary files /dev/null and b/app/src/custom/res/drawable-xhdpi/bg_disconnected.png differ diff --git a/app/src/custom/res/drawable-xxhdpi/bg_connected.png b/app/src/custom/res/drawable-xxhdpi/bg_connected.png new file mode 100644 index 0000000000000000000000000000000000000000..14c58b031419f1f5dd7ae731b95b976a2e797e6f Binary files /dev/null and b/app/src/custom/res/drawable-xxhdpi/bg_connected.png differ diff --git a/app/src/custom/res/drawable-xxhdpi/bg_connecting.png b/app/src/custom/res/drawable-xxhdpi/bg_connecting.png new file mode 100644 index 0000000000000000000000000000000000000000..062e84c45837f6f2bd49a3a8142abf56eec75cc6 Binary files /dev/null and b/app/src/custom/res/drawable-xxhdpi/bg_connecting.png differ diff --git a/app/src/custom/res/drawable-xxhdpi/bg_disconnected.png b/app/src/custom/res/drawable-xxhdpi/bg_disconnected.png new file mode 100644 index 0000000000000000000000000000000000000000..cd014703e46159a3abc36632b893fce8811e2d40 Binary files /dev/null and b/app/src/custom/res/drawable-xxhdpi/bg_disconnected.png differ diff --git a/app/src/custom/res/drawable/background_eip.xml b/app/src/custom/res/drawable/background_eip.xml deleted file mode 100644 index a2364794420239e4cda2605bae97a0ca852c8543..0000000000000000000000000000000000000000 --- a/app/src/custom/res/drawable/background_eip.xml +++ /dev/null @@ -1,11 +0,0 @@ -<?xml version="1.0" encoding="utf-8"?> -<!-- - ***************************************************** - Background image for the main vpn screem - example: <item android:drawable="@drawable/mybackground" /> - ***************************************************** ---> - -<layer-list xmlns:android="http://schemas.android.com/apk/res/android"> - <item android:drawable="@drawable/background_main" /> -</layer-list> \ No newline at end of file diff --git a/app/src/custom/res/drawable/bg_connected.png b/app/src/custom/res/drawable/bg_connected.png new file mode 100644 index 0000000000000000000000000000000000000000..78a09caeba1d6390e7b12196a4ef18cbae025296 Binary files /dev/null and b/app/src/custom/res/drawable/bg_connected.png differ diff --git a/app/src/custom/res/drawable/bg_connecting.png b/app/src/custom/res/drawable/bg_connecting.png new file mode 100644 index 0000000000000000000000000000000000000000..d85ddd4b6510bd5f3ef6994be1c9749dabd8c40e Binary files /dev/null and b/app/src/custom/res/drawable/bg_connecting.png differ diff --git a/app/src/custom/res/drawable/bg_disconnected.png b/app/src/custom/res/drawable/bg_disconnected.png new file mode 100644 index 0000000000000000000000000000000000000000..029c5d5a1f7d99a3cb55169411bf3a3ba8ae7c1f Binary files /dev/null and b/app/src/custom/res/drawable/bg_disconnected.png differ diff --git a/app/src/custom/res/drawable/ic_motd.png b/app/src/custom/res/drawable/ic_motd.png new file mode 100644 index 0000000000000000000000000000000000000000..5d2efea4be7cada5146677dcf12b55443448cb89 Binary files /dev/null and b/app/src/custom/res/drawable/ic_motd.png differ diff --git a/app/src/custom/res/drawable/motd_img.xml b/app/src/custom/res/drawable/motd_img.xml new file mode 100644 index 0000000000000000000000000000000000000000..d27db1a0302dd810de2bd01830927183c2d150ce --- /dev/null +++ b/app/src/custom/res/drawable/motd_img.xml @@ -0,0 +1,13 @@ +<?xml version="1.0" encoding="utf-8"?> + + <!-- + ***************************************************** + Used to create the image to be shown in the motd fragment + example: <item android:drawable="@drawable/mybackground" /> + ***************************************************** + --> +<layer-list xmlns:android="http://schemas.android.com/apk/res/android"> + <item android:drawable="@drawable/ic_motd" + android:gravity="fill_horizontal|fill_vertical"/> +</layer-list> + diff --git a/app/src/custom/res/drawable/rotate_progress_image.png b/app/src/custom/res/drawable/rotate_progress_image.png new file mode 100644 index 0000000000000000000000000000000000000000..ca160d00c4b368adafb9f132c925a202d9b4547a Binary files /dev/null and b/app/src/custom/res/drawable/rotate_progress_image.png differ diff --git a/app/src/custom/res/drawable/splash_branding.xml b/app/src/custom/res/drawable/splash_branding.xml new file mode 100644 index 0000000000000000000000000000000000000000..8bbd83ca113f9d9ce2bd1aa2781dc222b47fab92 --- /dev/null +++ b/app/src/custom/res/drawable/splash_branding.xml @@ -0,0 +1,47 @@ +<vector + android:height="80dp" + android:viewportHeight="80" + android:viewportWidth="160" + android:width="160dp" + xmlns:android="http://schemas.android.com/apk/res/android"> + <group + android:translateX="-47" + android:translateY="0" + android:scaleX="0.25" + android:scaleY="0.25" + > + <path android:fillColor="#000000" android:fillType="evenOdd" + android:pathData="m264.7,196.6 l-3.6,-37.6 -0.7,-28.1 12.8,-1.4 1.4,10.9 8.8,-8.8 18.3,-2.7 7.5,2.7 -1.4,14.6 -9.5,-2 -7.7,1.1 -6.9,7.6 -5,6.6 1.8,25.2 0.9,14.1z" + android:strokeColor="#00000000" android:strokeWidth="0.6"/> + <path android:fillColor="#000000" android:fillType="evenOdd" + android:pathData="m315.4,156.4 l-4.2,42.3l19,0l0,-27.9 0,-14z" + android:strokeColor="#00000000" android:strokeWidth="0.6"/> + <path android:fillColor="#000000" android:fillType="evenOdd" + android:pathData="m383.1,150.1 l5.7,-11.5 -10.4,-4.1 -11.1,-3.4 -17.4,6.9 -9.1,14.4 2.8,14.4 17.4,5.5 15.3,6.9 -1.1,7.7 -7.8,3.9 -16.2,-0.7 -7.7,-6.9 -7,11 9.1,8.2 27.9,2.7 14.6,-2.7 2.1,-14.4 1.4,-18.5 -17.4,-8.9 -12.5,-2.7 -0.7,-8.2 8.4,-4.8z" + android:strokeColor="#00000000" android:strokeWidth="0.6"/> + <path android:fillColor="#000000" android:fillType="evenOdd" + android:pathData="m408.5,164.9 l19.2,-0.9 21.1,-0.7 -0.7,-17.8 -10.9,-8.9 -25.2,-3.4 -15,8.2 -3.4,18.5l0,20.5l10.9,13.7 25.9,8.9l16.3,0l6.1,-7.5 -7.5,-11 -6.8,4.8 -19.7,-2.7 -7.5,-4.8 -4.1,-8.9z" + android:strokeColor="#00000000" android:strokeWidth="0.6"/> + <path android:fillColor="#000000" android:fillType="evenOdd" + android:pathData="m457.2,141.6l0,25.1l3.4,19.2 9.6,13 7.6,4.1l18.6,0l13.8,-8.9 3.4,-19.8 0.7,-26l0,-12.3l-14.8,-0.7l0,16.4l-0.3,22.6 -4.1,15.7 -8.3,2.1 -9.6,-4.8 -4.1,-10.9 -1.3,-22.5 0.5,-14.4z" + android:strokeColor="#00000000" android:strokeWidth="0.6"/> + <path android:fillColor="#000000" android:fillType="evenOdd" + android:pathData="m522.8,135.3 l-0.5,32.3 -1.6,29.4 1.3,3.8 13.2,-1.2 1.2,-35.5 20.4,-1.8 6.4,-6.6 1.9,-14.5 -6.2,-9.6 -23,-2.7z" + android:strokeColor="#00000000" android:strokeWidth="0.6"/> + <path android:fillColor="#000000" android:fillType="evenOdd" + android:pathData="m594.7,200.9 l-2.1,-30.4L592.6,139.5l14.8,0l0,12.4l11,-11 19.5,-3.4 13.2,10.3 -0.7,25.5 1.4,27.6 -16,-1.4 0.7,-26.9 -3.5,-15.2 -8.4,2.1 -9.8,2.8 -7.5,9.7l0,16.6 0,12.4z" + android:strokeColor="#00000000" android:strokeWidth="0.6"/> + <path android:fillColor="#000000" android:fillType="evenOdd" + android:pathData="m681.5,171.2 l22.9,-1.8 13.1,-2.1 -2.1,-19.6 -27.6,-14.7 -16.5,9.8 -8.3,16.1 -4.8,22.4 10.3,20.3 16.5,3.5 19.3,-0.7 11.7,-8.4 -9.6,-12.6 -3.4,4.2 -17.9,4.2 -11,-11.2 1.4,-6.3z" + android:strokeColor="#00000000" android:strokeWidth="0.6"/> + <path android:fillColor="#000000" android:fillType="evenOdd" + android:pathData="m723.8,135.3 l12.5,-0.2 -0.4,-14.6 13.5,2.1 1.4,12.8 15.3,-0.5l0,14.2l-16.3,-0.3 -0.7,11.6l0,14.5 0,11l3.6,6 10.6,-0.9 2,11.3 2.9,11.2 -21,-8.5 -10.7,-9.7 -2.7,-11.8 -0.1,-13.5 1.1,-21.7 -11.2,-0.4 0.1,-12.8z" + android:strokeColor="#00000000" android:strokeWidth="0.6"/> + <path android:fillColor="#000000" + android:pathData="m332.4,152.2 l-13,-1 -1.3,-14c0,0 -6.6,-13.1 -10.7,-15.1 -4.1,-2 -8.8,-6.1 -8.8,-6.1 0,0 5.4,-4.7 10.2,-1.3 4.8,3.4 4.8,4 4.8,4 0,0 5.4,2 6.8,-8.1 1.4,-10.1 5.3,-24.8 5.3,-24.8 0,0 2.7,-4 4.8,-1.3 2,2.7 -4,25.5 -4,25.5l11.9,-25.2c0,0 3.4,-3.4 4.1,0.7 0.7,4 -8.5,25.2 -8.5,25.2l11.7,-17.5c0,0 4.8,-2.7 4.8,1.3 0,4 -11,18.2 -11,18.2l14.4,-8.6c0,0 4.8,-1.3 4.1,2.7 -0.7,4 -14.2,7.4 -17.8,16 -3.9,8.6 -7.6,29.5 -7.6,29.5z" + android:strokeColor="#00000000" android:strokeWidth="0.6"/> + <path android:fillColor="#000000" android:fillType="evenOdd" + android:pathData="m567.2,186 l-2.1,14.8 14.8,-1.3 -2.7,-13.5z" + android:strokeColor="#00000000" android:strokeWidth="0.6"/> + </group> +</vector> diff --git a/app/src/custom/res/drawable/splash_icon.xml b/app/src/custom/res/drawable/splash_icon.xml new file mode 100644 index 0000000000000000000000000000000000000000..e8335bc6a8cc2af8a535fd39525df464ab4dbf78 --- /dev/null +++ b/app/src/custom/res/drawable/splash_icon.xml @@ -0,0 +1,17 @@ +<vector xmlns:android="http://schemas.android.com/apk/res/android" xmlns:aapt="http://schemas.android.com/aapt" + android:viewportWidth="288" + android:viewportHeight="288" + android:width="288dp" + android:height="288dp"> + <group + android:scaleX="0.9" + android:scaleY="0.9" + android:translateX="86" + android:translateY="56" + > + <path + android:pathData="M69.8243 44.3636C69.8243 44.3636 66.935 38.7879 66.6942 38.0606C66.4534 37.3333 65.0088 29.3333 65.0088 29.3333L66.935 25.9394L71.2689 19.6364L77.2882 14.7879L78.7328 14.303L93.42 8.72727L94.8647 7.27273L93.42 4.84849L91.2531 3.63636L87.4007 2.66666L77.7698 1.69697H70.3058L65.2496 2.90909L60.6749 1.21212L54.8963 0.484846L46.4692 0.242421L42.1353 0L35.1529 2.66666L24.3181 15.2727L22.8735 20.1212L22.1511 24.4848L18.5395 32.4848L16.1318 40L14.9279 48V49.697L9.39016 58.1818L6.26011 64.4848V73.4545L7.2232 92.1212L8.90861 98.9091L12.2794 105.212L16.6134 109.333L18.5395 117.333L25.7627 133.576L34.4306 144L34.9121 144.485L38.0422 160.242L27.4482 179.636L24.0773 182.303L21.6696 184.242H17.3357L14.9279 185.455L12.0387 185.697L10.3533 187.394L6.74165 186.909L3.13006 186.667L0.481548 188.606L0 192L1.92619 189.818L5.05624 188.848L5.29701 192L10.3533 190.303L13.2425 190.061L18.2988 190.788C18.2988 190.788 22.6327 190.545 23.355 190.303C24.0773 190.303 28.8928 190.788 28.8928 190.788L32.2636 190.303L34.1898 191.03L36.5975 190.303L39.246 191.515L43.0984 191.03L43.58 188.364L43.3392 186.909L45.9877 187.879L48.1547 189.576L49.5993 191.515V189.091L47.9139 186.182C47.9139 186.182 46.71 184.485 45.9877 184.727C45.2654 184.727 42.3761 184.242 42.3761 184.242L40.4499 184.97L38.283 184L36.116 185.212L34.1898 184.485L33.2267 182.545L31.7821 182.061L33.2267 178.182L36.5975 173.333L41.1722 165.576L45.2654 160.727L46.71 158.788C46.71 158.788 48.6362 155.879 48.6362 155.152C48.6362 154.424 49.1178 146.182 49.1178 146.182L46.71 140.848L45.5061 136.485L67.6573 141.818H68.8612L87.8823 155.636L90.5308 159.03L91.4938 172.848L91.0123 176L89.5677 178.424L88.6046 179.879L87.8823 182.061L87.4007 183.515L83.7891 184.727L80.1775 184L78.0106 183.758L73.9174 184.242L72.232 185.939L71.5097 188.121L71.9912 190.303L72.7135 188.121L73.9174 186.667L75.1213 186.424V188.364L76.5659 189.333L79.696 187.879L81.1406 187.636L81.6221 189.818H86.1968L89.3269 188.848L91.9754 189.333L95.8278 189.818L97.0316 189.333L97.9947 188.364L99.6801 191.758V187.879L97.9947 183.515L95.587 182.061L96.0686 180.848L94.3831 177.455L94.6239 164.849L104.255 176.242L117.016 186.182C117.016 186.182 125.684 189.333 126.406 189.333C127.128 189.333 133.148 188.606 133.148 188.606L137 182.303L134.111 173.576L135.315 170.667L129.295 162.667L116.293 149.333L113.163 138.909L113.404 131.879L110.515 124.364L107.385 118.788L109.311 112.727L107.866 104L101.366 89.2121L103.773 88.7273L99.4394 81.9394L102.088 81.2121L97.5132 73.697L99.4394 72.7273L96.0686 66.9091L97.2724 66.1818L92.9385 62.5455L94.3831 61.8182L83.5483 54.0606L69.8243 44.3636Z" + android:fillColor="#000000" /> + </group> + +</vector> \ No newline at end of file diff --git a/app/src/custom/res/drawable/splash_page.xml b/app/src/custom/res/drawable/splash_page.xml index 4c72dfe2e7e1dc19a927ecb71cf905fd2c9efa07..48a622acc38857af201af6fe6053cdb3a528ade3 100644 --- a/app/src/custom/res/drawable/splash_page.xml +++ b/app/src/custom/res/drawable/splash_page.xml @@ -1,4 +1,14 @@ <?xml version="1.0" encoding="utf-8"?> +<!-- +******************************************************************** +Splash screen for Android 4.1 - Android 11 + +You need to adapt: +> splash_branding.xml +> splash_icon.xml +for Android 12+. +******************************************************************** +--> <layer-list xmlns:android="http://schemas.android.com/apk/res/android"> <!--Replace custom/res/drawable-hdpi/ic_splash_background with background image--> diff --git a/app/src/custom/res/drawable/state_connected.png b/app/src/custom/res/drawable/state_connected.png new file mode 100644 index 0000000000000000000000000000000000000000..0fbb82f291c5f2096983dc4bf1dfc4b04a52e126 Binary files /dev/null and b/app/src/custom/res/drawable/state_connected.png differ diff --git a/app/src/custom/res/drawable/state_connecting.png b/app/src/custom/res/drawable/state_connecting.png new file mode 100644 index 0000000000000000000000000000000000000000..7d78587ebf36c22ae01b8a0b41edcfc9b7a821af Binary files /dev/null and b/app/src/custom/res/drawable/state_connecting.png differ diff --git a/app/src/custom/res/drawable/state_disconnected.xml b/app/src/custom/res/drawable/state_disconnected.xml new file mode 100644 index 0000000000000000000000000000000000000000..ee11473d373698a35569057c4bcdd05c0d8155a5 --- /dev/null +++ b/app/src/custom/res/drawable/state_disconnected.xml @@ -0,0 +1,6 @@ +<?xml version="1.0" encoding="utf-8"?> +<selector xmlns:android="http://schemas.android.com/apk/res/android"> + <item> + <bitmap android:src="@drawable/ic_motd"/> + </item> +</selector> \ No newline at end of file diff --git a/app/src/custom/res/values-de/strings.xml b/app/src/custom/res/values-de/strings.xml index 0114a6ed23789e6ada1122b92a48426b38920d79..a52d3040ed83df382fe129a6f2db4b06b626a8fb 100644 --- a/app/src/custom/res/values-de/strings.xml +++ b/app/src/custom/res/values-de/strings.xml @@ -1,5 +1,5 @@ <?xml version='1.0' encoding='UTF-8'?> <resources> - <string name="donate_message">RiseupVPN ist ein leicht benutzbarer, schneller und sicherer VPN-Dienst von riseup.net. RiseupVPN benötigt keinen Benutzer*innenkonto, es speichert keine Logs und keine Daten über dich. Der Service wird ausschließlich über Spenden finanziert von Nutzer*innen wie du. Bitte spende an https://riseup.net/vpn/donate.</string> + <string name="donate_message">RiseupVPN ist ein leicht benutzbarer, schneller und sicherer VPN-Dienst von riseup.net. RiseupVPN benötigt keinen Benutzer*innenkonto, es speichert keine Logs und keine Daten von dir. Der Service wird ausschließlich über Spenden von Nutzer*innen wie dir finanziert. Bitte spende an https://riseup.net/vpn/donate.</string> <string name="terms_of_service">Mit der Nutzung dieser Anwendung stimmst du den Nutzungsbedingungen unter https://riseup.net/tos zu. Dieser Service wird ohne Mängelgewähr bereitgestellt und ist für Menschen gedacht, die daran arbeiten, die Welt zu einem besseren Ort zu machen.</string> </resources> diff --git a/app/src/custom/res/values-fi/strings.xml b/app/src/custom/res/values-fi/strings.xml new file mode 100644 index 0000000000000000000000000000000000000000..ea1204d5eacaeff29414554640690753b5e53a92 --- /dev/null +++ b/app/src/custom/res/values-fi/strings.xml @@ -0,0 +1,5 @@ +<?xml version='1.0' encoding='UTF-8'?> +<resources> + <string name="donate_message">RiseupVPN on helppo, nopea ja turvallinen VPN-palvelu riseup.net:ltä. RiseupVPN ei vaadi käyttäjätiliä, pidä lokeja tai seuraa sinua millään tavalla. Tämä palvelu maksetaan kokonaan kaltaistesi käyttäjien lahjoituksilla. Lahjoita https://riseup.net/vpn/donate:ssa.</string> + <string name="terms_of_service">Käyttämällä tätä sovellusta hyväksyt palveluehdot, jotka ovat saatavilla https://riseup.net/tos:sta. Tämä palvelu tarjotaan sellaisenaan, ilman takuuta, ja se on tarkoitettu ihmisille, jotka työskentelevät tehdäkseen maailmasta paremman paikan.</string> +</resources> diff --git a/app/src/custom/res/values-it/strings.xml b/app/src/custom/res/values-it/strings.xml new file mode 100644 index 0000000000000000000000000000000000000000..385eb7e7549d9b416cb959ea814d7d43d92d08ce --- /dev/null +++ b/app/src/custom/res/values-it/strings.xml @@ -0,0 +1,5 @@ +<?xml version='1.0' encoding='UTF-8'?> +<resources> + <string name="donate_message">RiseupVPN è un servizio facile, veloce e sicuro di VPN da riseup.net. RiseupVPN non richiede un account utente, non tiene traccia e non ti registra in alcun modo. Questo servizio è pagato interamente dalle donazioni di utenti come te. Per favore dona a https://riseup.net/vpn/donate.</string> + <string name="terms_of_service">Utilizzando questa applicazione aderisci alle Condizioni di Utilizzo disponibili a https://riseup.net/tos. Questo servizio viene fornito così com\'è, senza nessuna garanzia ed è inteso per persone che si impegnano a rendere il mondo un posto migliore.</string> +</resources> diff --git a/app/src/custom/res/values-pt-rBR/strings.xml b/app/src/custom/res/values-pt-rBR/strings.xml index 4d42ea1cee4c7cd8545e4f44937be22bf8216b01..43a64de058e8e5454df973b846555392fe358d55 100644 --- a/app/src/custom/res/values-pt-rBR/strings.xml +++ b/app/src/custom/res/values-pt-rBR/strings.xml @@ -1,5 +1,5 @@ <?xml version='1.0' encoding='UTF-8'?> <resources> - <string name="donate_message">RiseupVPN é um serviço VPN fácil, rápido e seguro da riseup.net. RiseupVPN não requer uma conta de usuário, nem mantém registros ou rastreia você de qualquer forma. Este serviço é pago inteiramente por doações de usuários como você. Por favor, doe em https://riseup.net/vpn/donate.</string> - <string name="terms_of_service">Ao usar esse aplicativo você concorda com os Termos de Serviço disponíveis em https://riseup.net/tos. Esse serviço é fornecido da maneira que está, sem garantia, e destina-se a pessoas que trabalham para tornar o mundo um lugar melhor.</string> + <string name="donate_message">RiseupVPN é um serviço de VPN fácil, rápido e seguro mantido por riseup.net. RiseupVPN não requer a criação de uma conta, não mantém logs nem te rastreia de forma alguma. O serviço é financiado inteiramente por doações de pessoas como você.Por favor, faça uma doação em https://riseup.net/vpn/donate.</string> + <string name="terms_of_service">Ao usar este aplicativo, você concorda com os Termos de Serviço disponível em https://riseup.net/tos. Este serviço é fornecido \"no estado\", sem nenhuma garantia, e tem como público alvo pessoas que trabalham para tornar o mundo um lugar melhor.</string> </resources> diff --git a/app/src/custom/res/values-th/strings.xml b/app/src/custom/res/values-th/strings.xml new file mode 100644 index 0000000000000000000000000000000000000000..d094c9d763ae0a3c547fb7c266b9cd7f550dded9 --- /dev/null +++ b/app/src/custom/res/values-th/strings.xml @@ -0,0 +1,5 @@ +<?xml version='1.0' encoding='UTF-8'?> +<resources> + <string name="donate_message">RiseupVPN เป็นบริการ VPN ที่ง่าย รวดเร็วและปลอดภัยจาก riseup.net RiseupVPN ไม่ต้องการบัญชีผู้ใช้ เก็บบันทึกหรือติดตามคุณในทางใดทางหนึ่ง บริการนี้จ่ายทั้งหมดโดยการบริจาคจากผู้ใช้เช่นคุณ โปรดบริจาคได้ที่ https://riseup.net/vpn/donate</string> + <string name="terms_of_service">ในการใช้แอปพลิเคชันนี้แสดงว่าคุณยอมรับข้อกำหนดในการให้บริการที่ https://riseup.net/tos บริการนี้มีให้ตามที่เป็นอยู่ โดยไม่มีการรับประกัน และมีไว้สำหรับผู้ที่ทำงานเพื่อทำให้โลกนี้น่าอยู่ขึ้น</string> +</resources> diff --git a/app/src/custom/res/values-vi/strings.xml b/app/src/custom/res/values-vi/strings.xml new file mode 100644 index 0000000000000000000000000000000000000000..2e223abda27b8f6514f03977c32301736349b89d --- /dev/null +++ b/app/src/custom/res/values-vi/strings.xml @@ -0,0 +1,5 @@ +<?xml version='1.0' encoding='UTF-8'?> +<resources> + <string name="donate_message">RiseupVPN là một dịch vụ VPN dễ dàng, nhanh và bảo mật từ riseup.net. RiseupVPN không yêu cầu tài khoản người dùng, giữ nhật ký hoặc theo dõi bạn theo bất kỳ cách nào. Dịch vụ này được trả tiền hoàn toàn từ các khoản quyên góp từ những người dùng như bạn. Vui lòng quyên góp tại https://riseup.net/vpn/donate. </string> + <string name="terms_of_service">Bằng cách sử dụng ứng dụng này, bạn đồng ý với Điều khoản dịch vụ có sẵn tại https://riseup.net/tos. Dịch vụ này được cung cấp theo kiểu \"có thế dùng thế\", không có sự đảm bảo nào và dành cho những người hoạt động để biến thế giới thành một nơi tốt hơn.</string> +</resources> diff --git a/app/src/custom/res/values-zh-rCN/strings.xml b/app/src/custom/res/values-zh-rCN/strings.xml new file mode 100644 index 0000000000000000000000000000000000000000..0fb1482418158c8789dd558a526f2c94cfd9de01 --- /dev/null +++ b/app/src/custom/res/values-zh-rCN/strings.xml @@ -0,0 +1,5 @@ +<?xml version='1.0' encoding='UTF-8'?> +<resources> + <string name="donate_message">RiseupVPN 是由 riseup.net 制作的一款易于使用,快速又安全的 VPN 服务。RiseupVPN 无需注册账号即可使用,也绝不会以任何手段保存日志或追踪您的踪迹。此服务的费用完全由像您一样的用户捐助支付。请在 https://riseup.net/vpn/donate 进行捐助。</string> + <string name="terms_of_service">您必须同意地址为 https://riseup.net/tos 的服务条款才能使用本应用。此服务按原样提供,不提供任何保证,且旨在提供给那些不平则鸣的人们。</string> +</resources> diff --git a/app/src/custom/res/values/custom-theme.xml b/app/src/custom/res/values/custom-theme.xml index 12c828db5df9174fe5c5d361f664a997551c3fd7..68c6a3c860efc88b9707e929bbee09902eb1d099 100644 --- a/app/src/custom/res/values/custom-theme.xml +++ b/app/src/custom/res/values/custom-theme.xml @@ -9,13 +9,21 @@ <color name="colorActionBarTitleFont">#ffffff</color> <!--Font color of the action bar subtitle--> <color name="colorActionBarSubtitleFont">#cccccc</color> + <!-- action bar text colors for per state colored action bar --> + <color name="actionbar_connectivity_state_text_color_dark">@color/black800_dark</color> + <color name="actionbar_connectivity_state_text_color_light">@color/white</color> <!-- Font color of labels in EipFragment (main screen)--> - <color name="colorEipFragmentFont">#ffffff</color> + <color name="colorEipFragmentFont">@color/black800_dark</color> <!-- glow effect color of the on / off button --> <color name="colorMainBtnHighlight">#58FFA9</color> <!-- glow effect color of the on / off button if no network / traffic blocked --> <color name="colorMainBtnError">#eF2222</color> <!-- location button icon tint color --> - <color name="colorLocationButtonTint">#ffffff</color> - <color name="colorLocationButtonTintTransparent">#22ffffff</color> + <color name="colorLocationButtonTint">@color/black</color> + <color name="colorLocationButtonTintTransparent">@color/black800_transparent</color> + <!-- pill style button text colors --> + <color name="color_font_btn_primary">@color/white</color> + <color name="color_font_btn_secondary">@color/black800</color> + <!-- button text colors in Alerts --> + <color name="color_font_btn">@color/black800</color> </resources> diff --git a/app/src/fatweb/java/se.leap.bitmaskclient/appUpdate/DownloadNotificationManager.java b/app/src/fatweb/java/se.leap.bitmaskclient/appUpdate/DownloadNotificationManager.java index e7e871fd5b9a71be3a00e5504c0ca5b391727593..687fc66a218ea3e5a785562c67e31f34e9274faf 100644 --- a/app/src/fatweb/java/se.leap.bitmaskclient/appUpdate/DownloadNotificationManager.java +++ b/app/src/fatweb/java/se.leap.bitmaskclient/appUpdate/DownloadNotificationManager.java @@ -1,5 +1,5 @@ /** - * Copyright (c) 2020 LEAP Encryption Access Project and contributers + * Copyright (c) 2022 LEAP Encryption Access Project and contributers * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -33,6 +33,7 @@ import se.leap.bitmaskclient.R; import static android.content.Intent.CATEGORY_DEFAULT; import static se.leap.bitmaskclient.appUpdate.DownloadBroadcastReceiver.ACTION_DOWNLOAD; +import static se.leap.bitmaskclient.base.utils.ConfigHelper.getPendingIntentFlags; public class DownloadNotificationManager { private Context context; @@ -84,6 +85,7 @@ public class DownloadNotificationManager { notificationBuilder .setDefaults(Notification.DEFAULT_ALL) .setAutoCancel(false) + .setNotificationSilent() .setOngoing(true) .setSmallIcon(android.R.drawable.stat_sys_download) .setContentTitle(context.getString(R.string.version_update_apk_description, context.getString(R.string.app_name))) @@ -129,12 +131,13 @@ public class DownloadNotificationManager { private PendingIntent getDownloadIntent() { Intent downloadIntent = new Intent(context, DownloadBroadcastReceiver.class); downloadIntent.setAction(ACTION_DOWNLOAD); - return PendingIntent.getBroadcast(context, 0, downloadIntent, PendingIntent.FLAG_CANCEL_CURRENT); + + return PendingIntent.getBroadcast(context, 0, downloadIntent, getPendingIntentFlags()); } private PendingIntent getInstallIntent() { Intent installIntent = new Intent(context, InstallActivity.class); - return PendingIntent.getActivity(context, 0, installIntent, PendingIntent.FLAG_CANCEL_CURRENT); + return PendingIntent.getActivity(context, 0, installIntent, getPendingIntentFlags()); } public void cancelNotifications() { diff --git a/app/src/fatweb/java/se.leap.bitmaskclient/appUpdate/DownloadServiceCommand.java b/app/src/fatweb/java/se.leap.bitmaskclient/appUpdate/DownloadServiceCommand.java index 4e0d90794a5d8fbd251de9b25da4ebcea1ebe06f..41efd6218f5a10d91367e4d5b0dd088c950f2fe2 100644 --- a/app/src/fatweb/java/se.leap.bitmaskclient/appUpdate/DownloadServiceCommand.java +++ b/app/src/fatweb/java/se.leap.bitmaskclient/appUpdate/DownloadServiceCommand.java @@ -18,6 +18,7 @@ package se.leap.bitmaskclient.appUpdate; import android.content.Context; import android.content.Intent; +import android.os.Bundle; import android.os.ResultReceiver; import androidx.annotation.NonNull; @@ -31,18 +32,27 @@ public class DownloadServiceCommand { CHECK_VERSION_FILE = "checkVersionFile", DOWNLOAD_UPDATE = "downloadUpdate"; - private Context context; - private String action; - private ResultReceiver resultReceiver; + private final Context context; + private final String action; + private Bundle parameters; + private final ResultReceiver resultReceiver; private DownloadServiceCommand(@NonNull Context context, @NonNull String action) { - this(context.getApplicationContext(), action, null); + this(context.getApplicationContext(), action, null, null); } + private DownloadServiceCommand(@NonNull Context context, @NonNull String action, @Nullable Bundle parameters) { + this(context.getApplicationContext(), action, parameters, null); + } private DownloadServiceCommand(@NonNull Context context, @NonNull String action, @Nullable ResultReceiver resultReceiver) { + this(context.getApplicationContext(), action, null, resultReceiver); + } + + private DownloadServiceCommand(@NonNull Context context, @NonNull String action, @Nullable Bundle parameters, @Nullable ResultReceiver resultReceiver) { super(); this.context = context; this.action = action; + this.parameters = parameters; this.resultReceiver = resultReceiver; } @@ -53,6 +63,10 @@ public class DownloadServiceCommand { if (resultReceiver != null) { command.putExtra(ProviderAPI.RECEIVER_KEY, resultReceiver); } + if (parameters == null) { + parameters = Bundle.EMPTY; + } + command.putExtra(ProviderAPI.PARAMETERS, parameters); return command; } @@ -73,7 +87,12 @@ public class DownloadServiceCommand { command.execute(); } - public static void execute(Context context, String action, ResultReceiver resultReceiver) { + public static void execute(Context context, String action, Bundle parameters) { + DownloadServiceCommand command = new DownloadServiceCommand(context, action, parameters); + command.execute(); + } + + public static void execute(Context context, String action, Bundle parameters, ResultReceiver resultReceiver) { DownloadServiceCommand command = new DownloadServiceCommand(context, action, resultReceiver); command.execute(); } diff --git a/app/src/fatweb/java/se.leap.bitmaskclient/appUpdate/UpdateDownloadManager.java b/app/src/fatweb/java/se.leap.bitmaskclient/appUpdate/UpdateDownloadManager.java index b50c587cb39ae7095bb0ae9e50aa9e410331e420..109164c5fa6eb674598b7b59ef1f93528fdfb9af 100644 --- a/app/src/fatweb/java/se.leap.bitmaskclient/appUpdate/UpdateDownloadManager.java +++ b/app/src/fatweb/java/se.leap.bitmaskclient/appUpdate/UpdateDownloadManager.java @@ -48,6 +48,8 @@ import static se.leap.bitmaskclient.base.models.Constants.BROADCAST_DOWNLOAD_SER import static se.leap.bitmaskclient.base.models.Constants.BROADCAST_RESULT_CODE; import static se.leap.bitmaskclient.base.models.Constants.BROADCAST_RESULT_KEY; import static se.leap.bitmaskclient.base.utils.FileHelper.readPublicKey; +import static se.leap.bitmaskclient.providersetup.ProviderAPI.DELAY; +import static se.leap.bitmaskclient.providersetup.ProviderAPI.PARAMETERS; import static se.leap.bitmaskclient.providersetup.ProviderAPI.RECEIVER_KEY; public class UpdateDownloadManager implements Logger, DownloadConnector.DownloadProgress { @@ -93,6 +95,15 @@ public class UpdateDownloadManager implements Logger, DownloadConnector.Download receiver = command.getParcelableExtra(RECEIVER_KEY); } String action = command.getAction(); + Bundle parameters = command.getBundleExtra(PARAMETERS); + + if (parameters.containsKey(DELAY)) { + try { + Thread.sleep(parameters.getLong(DELAY)); + } catch (InterruptedException e) { + e.printStackTrace(); + } + } Bundle result = new Bundle(); switch (action) { diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml index 75b166d905773e9f219713087ecb75d421ba6f09..6a9de68dd8e9c9990d6bd291ea5441e4ad736303 100644 --- a/app/src/main/AndroidManifest.xml +++ b/app/src/main/AndroidManifest.xml @@ -41,6 +41,7 @@ android:theme="@style/BitmaskTheme"> <service android:name="de.blinkt.openvpn.core.OpenVPNService" + android:exported="false" android:permission="android.permission.BIND_VPN_SERVICE"> <intent-filter> <action android:name="android.net.VpnService" /> @@ -48,6 +49,7 @@ </service> <service android:name=".eip.VoidVpnService" + android:exported="false" android:permission="android.permission.BIND_VPN_SERVICE"> <intent-filter> <action android:name="android.net.VpnService" /> @@ -62,7 +64,8 @@ <receiver android:name=".base.OnBootReceiver" android:enabled="true" - android:permission="android.permission.RECEIVE_BOOT_COMPLETED" > + android:permission="android.permission.RECEIVE_BOOT_COMPLETED" + android:exported="true"> <intent-filter android:priority="999"> <action android:name="android.intent.action.BOOT_COMPLETED" /> </intent-filter> @@ -79,6 +82,7 @@ android:label="@string/app_name" android:launchMode="singleTop" android:theme="@style/SplashTheme" + android:exported="true" > <intent-filter android:label="@string/app_name"> @@ -126,6 +130,7 @@ android:icon="@drawable/vpn_disconnected" android:label="@string/qs_title" android:permission="android.permission.BIND_QUICK_SETTINGS_TILE" + android:exported="true" android:value="true"> <intent-filter> <action android:name="android.service.quicksettings.action.QS_TILE" /> diff --git a/app/src/main/java/de/blinkt/openvpn/VpnProfile.java b/app/src/main/java/de/blinkt/openvpn/VpnProfile.java index f2da0838091bb3da28c0067fa6ded5481b98f6f9..83cde85e7ccd7dba24ca8f546d0f0ce0894a8883 100644 --- a/app/src/main/java/de/blinkt/openvpn/VpnProfile.java +++ b/app/src/main/java/de/blinkt/openvpn/VpnProfile.java @@ -70,6 +70,8 @@ import se.leap.bitmaskclient.BuildConfig; import se.leap.bitmaskclient.R; import static de.blinkt.openvpn.core.connection.Connection.TransportType.OBFS4; +import static de.blinkt.openvpn.core.connection.Connection.TransportType.OBFS4_KCP; +import static de.blinkt.openvpn.core.connection.Connection.TransportType.OPENVPN; import static se.leap.bitmaskclient.base.models.Constants.PROVIDER_PROFILE; import static se.leap.bitmaskclient.base.utils.ConfigHelper.stringEqual; @@ -191,7 +193,8 @@ public class VpnProfile implements Serializable, Cloneable { private int mProfileVersion; public boolean mBlockUnusedAddressFamilies = true; public String mGatewayIp; - public boolean mUsePluggableTransports; + private boolean mUseObfs4; + private boolean mUseObfs4Kcp; public VpnProfile(String name, Connection.TransportType transportType) { mUuid = UUID.randomUUID(); @@ -200,7 +203,8 @@ public class VpnProfile implements Serializable, Cloneable { mConnections = new Connection[1]; mLastUsed = System.currentTimeMillis(); - mUsePluggableTransports = transportType == OBFS4; + mUseObfs4 = transportType == OBFS4; + mUseObfs4Kcp = transportType == OBFS4_KCP; } public static String openVpnEscape(String unescaped) { @@ -229,7 +233,7 @@ public class VpnProfile implements Serializable, Cloneable { //! Put inline data inline and other data as normal escaped filename public static String insertFileData(String cfgentry, String filedata) { if (filedata == null) { - return String.format("%s %s\n", cfgentry, "file missing in config profile"); + return String.format("# %s %s\n", cfgentry, "file missing in config profile"); } else if (isEmbedded(filedata)) { String dataWithOutHeader = getEmbeddedContent(filedata); return String.format(Locale.ENGLISH, "<%s>\n%s\n</%s>\n", cfgentry, dataWithOutHeader, cfgentry); @@ -266,7 +270,8 @@ public class VpnProfile implements Serializable, Cloneable { if (obj instanceof VpnProfile) { VpnProfile vp = (VpnProfile) obj; return stringEqual(vp.mGatewayIp, mGatewayIp) && - vp.mUsePluggableTransports == mUsePluggableTransports; + vp.mUseObfs4 == mUseObfs4 && + vp.mUseObfs4Kcp == mUseObfs4Kcp; } return false; } @@ -296,6 +301,20 @@ public class VpnProfile implements Serializable, Cloneable { mUuid = uuid; } + public boolean usePluggableTransports() { + return mUseObfs4Kcp || mUseObfs4; + } + + public Connection.TransportType getTransportType() { + if (mUseObfs4) { + return OBFS4; + } else if (mUseObfs4Kcp) { + return OBFS4_KCP; + } else { + return OPENVPN; + } + } + public String getName() { if (TextUtils.isEmpty(mName)) return "No profile name"; @@ -454,9 +473,6 @@ public class VpnProfile implements Serializable, Cloneable { cfg.append("management-external-key nopadding\n"); } else { cfg.append(context.getString(R.string.keychain_access)).append("\n"); - if (Build.VERSION.SDK_INT == Build.VERSION_CODES.JELLY_BEAN) - if (!mAlias.matches("^[a-zA-Z0-9]$")) - cfg.append(context.getString(R.string.jelly_keystore_alphanumeric_bug)).append("\n"); } } break; @@ -478,7 +494,7 @@ public class VpnProfile implements Serializable, Cloneable { cfg.append(insertFileData("crl-verify", mCrlFilename)); // compression does not work in conjunction with shapeshifter-dispatcher so far - if (mUseLzo && !mUsePluggableTransports) { + if (mUseLzo && !usePluggableTransports()) { cfg.append("comp-lzo\n"); } @@ -913,11 +929,6 @@ public class VpnProfile implements Serializable, Cloneable { VpnStatus.logError(R.string.keyChainAccessError, e.getLocalizedMessage()); VpnStatus.logError(R.string.keychain_access); - if (Build.VERSION.SDK_INT == Build.VERSION_CODES.JELLY_BEAN) { - if (!mAlias.matches("^[a-zA-Z0-9]$")) { - VpnStatus.logError(R.string.jelly_keystore_alphanumeric_bug); - } - } return null; } catch (AssertionError e) { @@ -1177,12 +1188,6 @@ public class VpnProfile implements Serializable, Cloneable { private byte[] getKeyChainSignedData(byte[] data, boolean pkcs1padding) { PrivateKey privkey = getKeystoreKey(); - // The Jelly Bean *evil* Hack - // 4.2 implements the RSA/ECB/PKCS1PADDING in the OpenSSLprovider - if (Build.VERSION.SDK_INT == Build.VERSION_CODES.JELLY_BEAN) { - return processSignJellyBeans(privkey, data); - } - try { @SuppressLint("GetInstance") @@ -1219,32 +1224,6 @@ public class VpnProfile implements Serializable, Cloneable { } } - private byte[] processSignJellyBeans(PrivateKey privkey, byte[] data) { - try { - Method getKey = privkey.getClass().getSuperclass().getDeclaredMethod("getOpenSSLKey"); - getKey.setAccessible(true); - - // Real object type is OpenSSLKey - Object opensslkey = getKey.invoke(privkey); - - getKey.setAccessible(false); - - Method getPkeyContext = opensslkey.getClass().getDeclaredMethod("getPkeyContext"); - - // integer pointer to EVP_pkey - getPkeyContext.setAccessible(true); - int pkey = (Integer) getPkeyContext.invoke(opensslkey); - getPkeyContext.setAccessible(false); - - // 112 with TLS 1.2 (172 back with 4.3), 36 with TLS 1.0 - return NativeUtils.rsasign(data, pkey); - - } catch (NoSuchMethodException | InvalidKeyException | InvocationTargetException | IllegalAccessException | IllegalArgumentException e) { - VpnStatus.logError(R.string.error_rsa_sign, e.getClass().toString(), e.getLocalizedMessage()); - return null; - } - } - private boolean usesExtraProxyOptions() { if (mUseCustomConfig && mCustomConfigOptions != null && mCustomConfigOptions.contains("http-proxy-option ")) return true; diff --git a/app/src/main/java/de/blinkt/openvpn/core/ConfigParser.java b/app/src/main/java/de/blinkt/openvpn/core/ConfigParser.java index 4a8bcf99c3aebd88173f5ad292039efc0de6f861..6063ea538a91e6541636ec4ee29f5b04ab6b6d0f 100644 --- a/app/src/main/java/de/blinkt/openvpn/core/ConfigParser.java +++ b/app/src/main/java/de/blinkt/openvpn/core/ConfigParser.java @@ -5,10 +5,13 @@ package de.blinkt.openvpn.core; +import static de.blinkt.openvpn.core.connection.Connection.TransportType.PT; + import android.os.Build; -import androidx.core.util.Pair; import android.text.TextUtils; +import androidx.core.util.Pair; + import java.io.BufferedReader; import java.io.IOException; import java.io.Reader; @@ -27,8 +30,6 @@ import de.blinkt.openvpn.core.connection.Obfs4Connection; import de.blinkt.openvpn.core.connection.OpenvpnConnection; import se.leap.bitmaskclient.pluggableTransports.Obfs4Options; -import static de.blinkt.openvpn.core.connection.Connection.TransportType.OBFS4; - //! Openvpn Config FIle Parser, probably not 100% accurate but close enough // And remember, this is valid :) @@ -561,7 +562,11 @@ public class ConfigParser { } } else if (!TextUtils.isEmpty(np.mCipher) && !np.mCipher.equals("AES-128-GCM") && !np.mCipher.equals("AES-256")) { - np.mDataCiphers += "AES-256-GCM:AES-128-GCM:" + np.mCipher; + if (np.mCipher.contains("AES-256-GCM")) { + np.mDataCiphers += np.mCipher; + } else { + np.mDataCiphers += "AES-256-GCM:AES-128-GCM:" + np.mCipher; + } } Vector<String> auth = getOption("auth", 1, 1); @@ -803,7 +808,7 @@ public class ConfigParser { return null; } else - conn = transportType == OBFS4 ? new Obfs4Connection(obfs4Options) : new OpenvpnConnection(); + conn = transportType.getMetaType() == PT ? new Obfs4Connection(obfs4Options) : new OpenvpnConnection(); Vector<String> port = getOption("port", 1, 1); if (port != null) { diff --git a/app/src/main/java/de/blinkt/openvpn/core/DeviceStateReceiver.java b/app/src/main/java/de/blinkt/openvpn/core/DeviceStateReceiver.java index 2b0c785e994147a74d72613cf5acb3e84e453bb5..219c13949f253a6386e1d7081726b763b4109551 100644 --- a/app/src/main/java/de/blinkt/openvpn/core/DeviceStateReceiver.java +++ b/app/src/main/java/de/blinkt/openvpn/core/DeviceStateReceiver.java @@ -13,6 +13,7 @@ import android.net.ConnectivityManager; import android.net.NetworkInfo; import android.net.NetworkInfo.State; import android.os.Handler; +import android.os.Looper; import android.preference.PreferenceManager; import se.leap.bitmaskclient.R; @@ -133,7 +134,7 @@ public class DeviceStateReceiver extends BroadcastReceiver implements ByteCountL trafficdata = new LinkedList<>(); mManagement = management; mManagement.setPauseCallback(this); - mDisconnectHandler = new Handler(); + mDisconnectHandler = new Handler(Looper.getMainLooper()); } diff --git a/app/src/main/java/de/blinkt/openvpn/core/NativeUtils.java b/app/src/main/java/de/blinkt/openvpn/core/NativeUtils.java index 5a1757ac6eab9e342cb59db6542477c1f9fed5d7..f769b38e6c4284c28498a686509c650557164e9f 100644 --- a/app/src/main/java/de/blinkt/openvpn/core/NativeUtils.java +++ b/app/src/main/java/de/blinkt/openvpn/core/NativeUtils.java @@ -38,8 +38,6 @@ public class NativeUtils { static { if (!isRoboUnitTest() && !isUnitTest()) { System.loadLibrary("ovpnutil"); - if (Build.VERSION.SDK_INT == Build.VERSION_CODES.JELLY_BEAN) - System.loadLibrary("jbcrypto"); } } diff --git a/app/src/main/java/de/blinkt/openvpn/core/NetworkSpace.java b/app/src/main/java/de/blinkt/openvpn/core/NetworkSpace.java index 860897db440a625a1783bf0e40637a120d892470..457ae9714d417368a4aba89d41b8a3359362add1 100644 --- a/app/src/main/java/de/blinkt/openvpn/core/NetworkSpace.java +++ b/app/src/main/java/de/blinkt/openvpn/core/NetworkSpace.java @@ -336,35 +336,6 @@ public class NetworkSpace { ips.add(ia); } - if (Build.VERSION.SDK_INT < Build.VERSION_CODES.KITKAT) { - // Include postive routes from the original set under < 4.4 since these might overrule the local - // network but only if no smaller negative route exists - for (IpAddress origIp : mIpAddresses) { - if (!origIp.included) - continue; - - // The netspace exists - if (ipsSorted.contains(origIp)) - continue; - - boolean skipIp = false; - // If there is any smaller net that is excluded we may not add the positive route back - - for (IpAddress calculatedIp : ipsSorted) { - if (!calculatedIp.included && origIp.containsNet(calculatedIp)) { - skipIp = true; - break; - } - } - if (skipIp) - continue; - - // It is safe to include the IP - ips.add(origIp); - } - - } - return ips; } diff --git a/app/src/main/java/de/blinkt/openvpn/core/NetworkUtils.java b/app/src/main/java/de/blinkt/openvpn/core/NetworkUtils.java index 5b11c0a074d5ddb850f2a089209c4c08e02ef3d6..25af6121cbe0c8b5c2ab2cc6020db32bea0633e3 100644 --- a/app/src/main/java/de/blinkt/openvpn/core/NetworkUtils.java +++ b/app/src/main/java/de/blinkt/openvpn/core/NetworkUtils.java @@ -24,63 +24,35 @@ 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); - if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) { - Network[] networks = conn.getAllNetworks(); - for (Network network : networks) { - try { - NetworkInfo ni = conn.getNetworkInfo(network); - LinkProperties li = conn.getLinkProperties(network); + Network[] networks = conn.getAllNetworks(); + for (Network network : networks) { + try { + NetworkInfo ni = conn.getNetworkInfo(network); + LinkProperties li = conn.getLinkProperties(network); - NetworkCapabilities nc = conn.getNetworkCapabilities(network); + NetworkCapabilities nc = conn.getNetworkCapabilities(network); - if (nc == null) { - continue; - } - - // Skip VPN networks like ourselves - if (nc.hasTransport(NetworkCapabilities.TRANSPORT_VPN)) - continue; - - // Also skip mobile networks - if (nc.hasTransport(NetworkCapabilities.TRANSPORT_CELLULAR)) - continue; - - - for (LinkAddress la : li.getLinkAddresses()) { - if ((la.getAddress() instanceof Inet4Address && !ipv6) || - (la.getAddress() instanceof Inet6Address && ipv6)) - nets.add(la.toString()); - } - } catch (SecurityException se) { - se.printStackTrace(); + if (nc == null) { + continue; } - } - } else { - // Old Android Version, use native utils via ifconfig instead - // Add local network interfaces - if (ipv6) - return nets; - String[] localRoutes = NativeUtils.getIfconfig(); - - // The format of mLocalRoutes is kind of broken because I don't really like JNI - for (int i = 0; i < localRoutes.length; i += 3) { - String intf = localRoutes[i]; - String ipAddr = localRoutes[i + 1]; - String netMask = localRoutes[i + 2]; - - if (intf == null || intf.equals("lo") || - intf.startsWith("tun") || intf.startsWith("rmnet")) + // Skip VPN networks like ourselves + if (nc.hasTransport(NetworkCapabilities.TRANSPORT_VPN)) continue; - if (ipAddr == null || netMask == null) { - VpnStatus.logError("Local routes are broken?! (Report to author) " + TextUtils.join("|", localRoutes)); + // Also skip mobile networks + if (nc.hasTransport(NetworkCapabilities.TRANSPORT_CELLULAR)) continue; - } - nets.add(ipAddr + "/" + CIDRIP.calculateLenFromMask(netMask)); - } + for (LinkAddress la : li.getLinkAddresses()) { + if ((la.getAddress() instanceof Inet4Address && !ipv6) || + (la.getAddress() instanceof Inet6Address && ipv6)) + nets.add(la.toString()); + } + } catch (SecurityException se) { + se.printStackTrace(); + } } return nets; } diff --git a/app/src/main/java/de/blinkt/openvpn/core/OpenVPNService.java b/app/src/main/java/de/blinkt/openvpn/core/OpenVPNService.java index d624af801833cc4bfd1325362c82fde558baef41..0ae7639e40d08df1f66dfe857afb5ec628b33f42 100644 --- a/app/src/main/java/de/blinkt/openvpn/core/OpenVPNService.java +++ b/app/src/main/java/de/blinkt/openvpn/core/OpenVPNService.java @@ -5,6 +5,12 @@ package de.blinkt.openvpn.core; +import static de.blinkt.openvpn.core.ConnectionStatus.LEVEL_CONNECTED; +import static de.blinkt.openvpn.core.ConnectionStatus.LEVEL_WAITING_FOR_USER_INPUT; +import static de.blinkt.openvpn.core.NetworkSpace.IpAddress; +import static se.leap.bitmaskclient.base.models.Constants.PROVIDER_PROFILE; +import static se.leap.bitmaskclient.base.utils.ConfigHelper.ObfsVpnHelper.useObfsVpn; + import android.Manifest.permission; import android.annotation.TargetApi; import android.app.Notification; @@ -47,12 +53,8 @@ import se.leap.bitmaskclient.R; import se.leap.bitmaskclient.eip.EipStatus; import se.leap.bitmaskclient.eip.VpnNotificationManager; import se.leap.bitmaskclient.firewall.FirewallManager; -import se.leap.bitmaskclient.pluggableTransports.Shapeshifter; - -import static de.blinkt.openvpn.core.ConnectionStatus.LEVEL_CONNECTED; -import static de.blinkt.openvpn.core.ConnectionStatus.LEVEL_WAITING_FOR_USER_INPUT; -import static de.blinkt.openvpn.core.NetworkSpace.IpAddress; -import static se.leap.bitmaskclient.base.models.Constants.PROVIDER_PROFILE; +import se.leap.bitmaskclient.pluggableTransports.ObfsVpnClient; +import se.leap.bitmaskclient.pluggableTransports.ShapeshifterClient; public class OpenVPNService extends VpnService implements StateListener, Callback, ByteCountListener, IOpenVPNServiceInternal, VpnNotificationManager.VpnServiceCallback { @@ -88,7 +90,8 @@ public class OpenVPNService extends VpnService implements StateListener, Callbac private Toast mlastToast; private Runnable mOpenVPNThread; private VpnNotificationManager notificationManager; - private Shapeshifter shapeshifter; + private ShapeshifterClient shapeshifter; + private ObfsVpnClient obfsVpnClient; private FirewallManager firewallManager; private final IBinder mBinder = new IOpenVPNServiceInternal.Stub() { @@ -241,6 +244,9 @@ public class OpenVPNService extends VpnService implements StateListener, Callbac if (shapeshifter != null) { shapeshifter.stop(); shapeshifter = null; + } else if (obfsVpnClient != null && obfsVpnClient.isStarted()) { + obfsVpnClient.stop(); + obfsVpnClient = null; } VpnStatus.updateStateString("NOPROCESS", "VPN STOPPED", R.string.state_noprocess, ConnectionStatus.LEVEL_NOTCONNECTED); } @@ -311,7 +317,7 @@ public class OpenVPNService extends VpnService implements StateListener, Callbac VpnStatus.updateStateString("VPN_GENERATE_CONFIG", "", R.string.building_configration, ConnectionStatus.LEVEL_START); notificationManager.buildOpenVpnNotification( mProfile != null ? mProfile.mName : "", - mProfile != null && mProfile.mUsePluggableTransports, + mProfile != null && mProfile.usePluggableTransports(), VpnStatus.getLastCleanLogMessage(this), VpnStatus.getLastCleanLogMessage(this), ConnectionStatus.LEVEL_START, @@ -410,10 +416,17 @@ public class OpenVPNService extends VpnService implements StateListener, Callbac // An old running VPN should now be exited mStarting = false; - if (mProfile.mUsePluggableTransports && connection instanceof Obfs4Connection) { + if (mProfile.usePluggableTransports() && connection instanceof Obfs4Connection) { Obfs4Connection obfs4Connection = (Obfs4Connection) connection; - if (shapeshifter == null) { - shapeshifter = new Shapeshifter(obfs4Connection.getDispatcherOptions()); + if (useObfsVpn()) { + if (obfsVpnClient != null && obfsVpnClient.isStarted()) { + obfsVpnClient.stop(); + } + obfsVpnClient = new ObfsVpnClient(obfs4Connection.getDispatcherOptions()); + int runningSocksPort = obfsVpnClient.start(); + connection.setProxyPort(String.valueOf(runningSocksPort)); + } else if (shapeshifter == null) { + shapeshifter = new ShapeshifterClient(obfs4Connection.getDispatcherOptions()); shapeshifter.start(); } } @@ -474,6 +487,10 @@ public class OpenVPNService extends VpnService implements StateListener, Callbac Log.d(TAG, "-> stop shapeshifter"); shapeshifter.stop(); shapeshifter = null; + } else if (obfsVpnClient != null && obfsVpnClient.isStarted()) { + Log.d(TAG, "-> stop obfsvpnClient"); + obfsVpnClient.stop(); + obfsVpnClient = null; } try { Thread.sleep(1000); @@ -572,7 +589,7 @@ public class OpenVPNService extends VpnService implements StateListener, Callbac VpnStatus.logInfo(R.string.last_openvpn_tun_config); - boolean allowUnsetAF = Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP && !mProfile.mBlockUnusedAddressFamilies; + boolean allowUnsetAF = !mProfile.mBlockUnusedAddressFamilies; if (allowUnsetAF) { allowAllAFFamilies(builder); } @@ -614,20 +631,12 @@ public class OpenVPNService extends VpnService implements StateListener, Callbac } } - String release = Build.VERSION.RELEASE; - if ((Build.VERSION.SDK_INT == Build.VERSION_CODES.KITKAT && !release.startsWith("4.4.3") - && !release.startsWith("4.4.4") && !release.startsWith("4.4.5") && !release.startsWith("4.4.6")) - && mMtu < 1280) { - VpnStatus.logInfo(String.format(Locale.US, "Forcing MTU to 1280 instead of %d to workaround Android Bug #70916", mMtu)); - builder.setMtu(1280); - } else { - builder.setMtu(mMtu); - } + builder.setMtu(mMtu); Collection<IpAddress> positiveIPv4Routes = mRoutes.getPositiveIPList(); Collection<IpAddress> positiveIPv6Routes = mRoutesv6.getPositiveIPList(); - if ("samsung".equals(Build.BRAND) && Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP && mDnslist.size() >= 1) { + if ("samsung".equals(Build.BRAND) && 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); @@ -708,9 +717,8 @@ public class OpenVPNService extends VpnService implements StateListener, Callbac 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))); VpnStatus.logDebug(R.string.routes_debug, TextUtils.join(", ", positiveIPv4Routes), TextUtils.join(", ", positiveIPv6Routes)); - if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) { - setAllowedVpnPackages(builder); - } + + setAllowedVpnPackages(builder); if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP_MR1) { // VPN always uses the default network builder.setUnderlyingNetworks(null); @@ -756,9 +764,6 @@ public class OpenVPNService extends VpnService implements StateListener, Callbac } catch (Exception e) { VpnStatus.logError(R.string.tun_open_error); VpnStatus.logError(getString(R.string.error) + e.getLocalizedMessage()); - if (Build.VERSION.SDK_INT <= Build.VERSION_CODES.JELLY_BEAN_MR1) { - VpnStatus.logError(R.string.tun_error_helpful); - } return null; } @@ -773,7 +778,6 @@ public class OpenVPNService extends VpnService implements StateListener, Callbac } } - @TargetApi(Build.VERSION_CODES.LOLLIPOP) private void allowAllAFFamilies(Builder builder) { builder.allowFamily(OsConstants.AF_INET); builder.allowFamily(OsConstants.AF_INET6); @@ -788,11 +792,9 @@ public class OpenVPNService extends VpnService implements StateListener, Callbac if (ipAddr.equals(mLocalIP.mIp)) continue; - if (Build.VERSION.SDK_INT < Build.VERSION_CODES.KITKAT && !mProfile.mAllowLocalLAN) { - mRoutes.addIPSplit(new CIDRIP(ipAddr, netMask), true); - - } else if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT && mProfile.mAllowLocalLAN) + if (mProfile.mAllowLocalLAN) { mRoutes.addIP(new CIDRIP(ipAddr, netMask), false); + } } // IPv6 is Lollipop+ only so we can skip the lower than KITKAT case @@ -806,7 +808,6 @@ public class OpenVPNService extends VpnService implements StateListener, Callbac } - @TargetApi(Build.VERSION_CODES.LOLLIPOP) private void setAllowedVpnPackages(Builder builder) { boolean profileUsesOrBot = false; @@ -1016,7 +1017,7 @@ public class OpenVPNService extends VpnService implements StateListener, Callbac notificationManager.buildOpenVpnNotification( mProfile != null ? mProfile.mName : "", - mProfile != null && mProfile.mUsePluggableTransports, + mProfile != null && mProfile.usePluggableTransports(), VpnStatus.getLastCleanLogMessage(this), VpnStatus.getLastCleanLogMessage(this), level, @@ -1047,7 +1048,7 @@ public class OpenVPNService extends VpnService implements StateListener, Callbac humanReadableByteCount(diffOut / OpenVPNManagement.mBytecountInterval, true, getResources())); notificationManager.buildOpenVpnNotification( mProfile != null ? mProfile.mName : "", - mProfile != null && mProfile.mUsePluggableTransports, + mProfile != null && mProfile.usePluggableTransports(), netstat, null, LEVEL_CONNECTED, @@ -1077,13 +1078,7 @@ public class OpenVPNService extends VpnService implements StateListener, Callbac if (currentConfiguration.equals(mLastTunCfg)) { return "NOACTION"; } else { - String release = Build.VERSION.RELEASE; - if (Build.VERSION.SDK_INT == Build.VERSION_CODES.KITKAT && !release.startsWith("4.4.3") - && !release.startsWith("4.4.4") && !release.startsWith("4.4.5") && !release.startsWith("4.4.6")) - // There will be probably no 4.4.4 or 4.4.5 version, so don't waste effort to do parsing here - return "OPEN_AFTER_CLOSE"; - else - return "OPEN_BEFORE_CLOSE"; + return "OPEN_BEFORE_CLOSE"; } } @@ -1091,7 +1086,7 @@ public class OpenVPNService extends VpnService implements StateListener, Callbac VpnStatus.updateStateString("NEED", "need " + needed, resid, LEVEL_WAITING_FOR_USER_INPUT); notificationManager.buildOpenVpnNotification( mProfile != null ? mProfile.mName : "", - mProfile != null && mProfile.mUsePluggableTransports, + mProfile != null && mProfile.usePluggableTransports(), getString(resid), getString(resid), LEVEL_WAITING_FOR_USER_INPUT, diff --git a/app/src/main/java/de/blinkt/openvpn/core/OpenVpnManagementThread.java b/app/src/main/java/de/blinkt/openvpn/core/OpenVpnManagementThread.java index 0014782817acfb6fce28de271b20820ec95036b6..a02e7e277b24f04ed507f155025086bc9cf093ef 100644 --- a/app/src/main/java/de/blinkt/openvpn/core/OpenVpnManagementThread.java +++ b/app/src/main/java/de/blinkt/openvpn/core/OpenVpnManagementThread.java @@ -242,12 +242,10 @@ public class OpenVpnManagementThread implements Runnable, OpenVPNManagement { VpnStatus.logWarning("Could not protect VPN socket"); - //ParcelFileDescriptor pfd = ParcelFileDescriptor.fromFd(fdint); - //pfd.close(); - if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) { - fdCloseLollipop(fd); - } else { - NativeUtils.jniclose(fdint); + try { + Os.close(fd); + } catch (Exception e) { + VpnStatus.logException("Failed to close fd (" + fd + ")", e); } return; } catch ( NoSuchMethodException | IllegalArgumentException | InvocationTargetException | IllegalAccessException | NullPointerException e) { @@ -258,15 +256,6 @@ public class OpenVpnManagementThread implements Runnable, OpenVPNManagement { } - @RequiresApi(api = Build.VERSION_CODES.LOLLIPOP) - private void fdCloseLollipop(FileDescriptor fd) { - try { - Os.close(fd); - } catch (Exception e) { - VpnStatus.logException("Failed to close fd (" + fd + ")", e); - } - } - private String processInput(String pendingInput) { @@ -457,7 +446,7 @@ public class OpenVpnManagementThread implements Runnable, OpenVPNManagement { } // atuo detection of proxy - if (proxyType == Connection.ProxyType.NONE) { + if (proxyType == Connection.ProxyType.NONE && mProfile != null) { SocketAddress proxyaddr = ProxyDetection.detectProxy(mProfile); if (proxyaddr instanceof InetSocketAddress) { InetSocketAddress isa = (InetSocketAddress) proxyaddr; diff --git a/app/src/main/java/de/blinkt/openvpn/core/VPNLaunchHelper.java b/app/src/main/java/de/blinkt/openvpn/core/VPNLaunchHelper.java index 540ca0431cf19159b792b9126493576658a58040..80427a031c54a0c73eca997fcbdd5942f3c2d19e 100644 --- a/app/src/main/java/de/blinkt/openvpn/core/VPNLaunchHelper.java +++ b/app/src/main/java/de/blinkt/openvpn/core/VPNLaunchHelper.java @@ -30,11 +30,7 @@ public class VPNLaunchHelper { if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.P) return new File(context.getApplicationInfo().nativeLibraryDir, "libovpnexec.so").getPath(); String[] abis; - if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) - abis = getSupportedABIsLollipop(); - else - //noinspection deprecation - abis = new String[]{Build.CPU_ABI, Build.CPU_ABI2}; + abis = getSupportedABIsLollipop(); if (!nativeAPI.equals(abis[0])) { VpnStatus.logWarning(R.string.abi_mismatch, Arrays.toString(abis), nativeAPI); @@ -49,22 +45,17 @@ public class VPNLaunchHelper { } } - throw new RuntimeException("Cannot find any execulte for this device's ABIs " + abis.toString()); + throw new RuntimeException("Cannot find any execute for this device's ABIs " + abis.toString()); } - @TargetApi(Build.VERSION_CODES.LOLLIPOP) private static String[] getSupportedABIsLollipop() { return Build.SUPPORTED_ABIS; } private static String getMiniVPNExecutableName() { - if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN) - return MINIPIEVPN; - else - return MININONPIEVPN; + return MINIPIEVPN; } - public static String[] replacePieWithNoPie(String[] mArgv) { mArgv[0] = mArgv[0].replace(MINIPIEVPN, MININONPIEVPN); return mArgv; diff --git a/app/src/main/java/de/blinkt/openvpn/core/VpnStatus.java b/app/src/main/java/de/blinkt/openvpn/core/VpnStatus.java index 4fa5a7b629e32d660664e631329317b14777edea..f28651f382251839a1182d3d2ead11930fdbd6cd 100644 --- a/app/src/main/java/de/blinkt/openvpn/core/VpnStatus.java +++ b/app/src/main/java/de/blinkt/openvpn/core/VpnStatus.java @@ -543,6 +543,6 @@ public class VpnStatus { } public static boolean isUsingBridges() { - return lastConnectedProfile != null && lastConnectedProfile.mUsePluggableTransports; + return lastConnectedProfile != null && lastConnectedProfile.usePluggableTransports(); } } diff --git a/app/src/main/java/de/blinkt/openvpn/core/connection/Connection.java b/app/src/main/java/de/blinkt/openvpn/core/connection/Connection.java index 4cb9c0c76844e7b5a3409e69753d0833d95d659f..f60e7333f3564f6b816c15c886ffcbb9bb3bb626 100644 --- a/app/src/main/java/de/blinkt/openvpn/core/connection/Connection.java +++ b/app/src/main/java/de/blinkt/openvpn/core/connection/Connection.java @@ -39,7 +39,10 @@ public abstract class Connection implements Serializable, Cloneable { public enum TransportType { OBFS4("obfs4"), - OPENVPN("openvpn"); + OPENVPN("openvpn"), + OBFS4_KCP("obfs4-1"), + + PT("metaTransport"); String transport; @@ -51,6 +54,17 @@ public abstract class Connection implements Serializable, Cloneable { public String toString() { return transport; } + + public boolean isPluggableTransport() { + return this == OBFS4 || this == OBFS4_KCP || this == PT; + } + + public TransportType getMetaType() { + if (this == OBFS4 || this == OBFS4_KCP || this == PT) { + return PT; + } + return OPENVPN; + } } diff --git a/app/src/main/java/de/blinkt/openvpn/core/connection/Obfs4Connection.java b/app/src/main/java/de/blinkt/openvpn/core/connection/Obfs4Connection.java index 82a7a6aaabe3429b1fce1b943b2685b336de2197..c77c23fd15ca8247a0d00c39f1dcc676522aa4d9 100644 --- a/app/src/main/java/de/blinkt/openvpn/core/connection/Obfs4Connection.java +++ b/app/src/main/java/de/blinkt/openvpn/core/connection/Obfs4Connection.java @@ -1,9 +1,11 @@ package de.blinkt.openvpn.core.connection; -import se.leap.bitmaskclient.pluggableTransports.Obfs4Options; +import static se.leap.bitmaskclient.base.utils.ConfigHelper.ObfsVpnHelper.useObfsVpn; +import static se.leap.bitmaskclient.pluggableTransports.ShapeshifterClient.DISPATCHER_IP; +import static se.leap.bitmaskclient.pluggableTransports.ShapeshifterClient.DISPATCHER_PORT; -import static se.leap.bitmaskclient.pluggableTransports.Shapeshifter.DISPATCHER_IP; -import static se.leap.bitmaskclient.pluggableTransports.Shapeshifter.DISPATCHER_PORT; +import se.leap.bitmaskclient.pluggableTransports.Obfs4Options; +import se.leap.bitmaskclient.pluggableTransports.ObfsVpnClient; /** @@ -16,14 +18,24 @@ public class Obfs4Connection extends Connection { private Obfs4Options options; public Obfs4Connection(Obfs4Options options) { + if (useObfsVpn()) { + setServerName(options.remoteIP); + setServerPort(options.remotePort); + setProxyName(ObfsVpnClient.SOCKS_IP); + setProxyPort(String.valueOf(ObfsVpnClient.SOCKS_PORT.get())); + setProxyType(ProxyType.SOCKS5); + } else { + setServerName(DISPATCHER_IP); + setServerPort(DISPATCHER_PORT); + setProxyName(""); + setProxyPort(""); + setProxyType(ProxyType.NONE); + } + // while udp/kcp might be used on the wire, + // we don't use udp for openvpn in case of a obfs4 connection setUseUdp(false); - setServerName(DISPATCHER_IP); - setServerPort(DISPATCHER_PORT); - setProxyName(""); - setProxyPort(""); setProxyAuthUser(null); setProxyAuthPassword(null); - setProxyType(ProxyType.NONE); setUseProxyAuth(false); this.options = options; } diff --git a/app/src/main/java/se/leap/bitmaskclient/base/BitmaskApp.java b/app/src/main/java/se/leap/bitmaskclient/base/BitmaskApp.java index 60c28a9a9c9a37baf11aabf04181fc27919a497b..828ef27d64643a5d91819b20e7d7f4955c1817c1 100644 --- a/app/src/main/java/se/leap/bitmaskclient/base/BitmaskApp.java +++ b/app/src/main/java/se/leap/bitmaskclient/base/BitmaskApp.java @@ -1,5 +1,5 @@ /** - * Copyright (c) 2020 LEAP Encryption Access Project and contributers + * Copyright (c) 2021 LEAP Encryption Access Project and contributers * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -17,6 +17,15 @@ package se.leap.bitmaskclient.base; +import static android.content.Intent.CATEGORY_DEFAULT; +import static se.leap.bitmaskclient.appUpdate.DownloadBroadcastReceiver.ACTION_DOWNLOAD; +import static se.leap.bitmaskclient.appUpdate.DownloadServiceCommand.CHECK_VERSION_FILE; +import static se.leap.bitmaskclient.appUpdate.DownloadServiceCommand.DOWNLOAD_UPDATE; +import static se.leap.bitmaskclient.base.models.Constants.BROADCAST_DOWNLOAD_SERVICE_EVENT; +import static se.leap.bitmaskclient.base.models.Constants.SHARED_PREFERENCES; +import static se.leap.bitmaskclient.base.utils.ConfigHelper.isCalyxOSWithTetheringSupport; +import static se.leap.bitmaskclient.base.utils.PreferenceHelper.getSavedProviderFromSharedPreferences; + import android.content.Context; import android.content.IntentFilter; import android.content.SharedPreferences; @@ -25,26 +34,14 @@ import androidx.appcompat.app.AppCompatDelegate; import androidx.localbroadcastmanager.content.LocalBroadcastManager; import androidx.multidex.MultiDexApplication; -import com.squareup.leakcanary.LeakCanary; -import com.squareup.leakcanary.RefWatcher; - import se.leap.bitmaskclient.BuildConfig; import se.leap.bitmaskclient.appUpdate.DownloadBroadcastReceiver; -import se.leap.bitmaskclient.eip.EipSetupObserver; import se.leap.bitmaskclient.base.models.ProviderObservable; -import se.leap.bitmaskclient.tethering.TetheringStateManager; import se.leap.bitmaskclient.base.utils.PRNGFixes; -import se.leap.bitmaskclient.tor.TorNotificationManager; +import se.leap.bitmaskclient.eip.EipSetupObserver; +import se.leap.bitmaskclient.tethering.TetheringStateManager; import se.leap.bitmaskclient.tor.TorStatusObservable; -import static android.content.Intent.CATEGORY_DEFAULT; -import static se.leap.bitmaskclient.base.models.Constants.BROADCAST_DOWNLOAD_SERVICE_EVENT; -import static se.leap.bitmaskclient.base.models.Constants.SHARED_PREFERENCES; -import static se.leap.bitmaskclient.appUpdate.DownloadBroadcastReceiver.ACTION_DOWNLOAD; -import static se.leap.bitmaskclient.appUpdate.DownloadServiceCommand.CHECK_VERSION_FILE; -import static se.leap.bitmaskclient.appUpdate.DownloadServiceCommand.DOWNLOAD_UPDATE; -import static se.leap.bitmaskclient.base.utils.PreferenceHelper.getSavedProviderFromSharedPreferences; - /** * Created by cyberta on 24.10.17. */ @@ -52,7 +49,6 @@ import static se.leap.bitmaskclient.base.utils.PreferenceHelper.getSavedProvider public class BitmaskApp extends MultiDexApplication { private final static String TAG = BitmaskApp.class.getSimpleName(); - private RefWatcher refWatcher; private ProviderObservable providerObservable; private DownloadBroadcastReceiver downloadBroadcastReceiver; private TorStatusObservable torStatusObservable; @@ -61,12 +57,6 @@ public class BitmaskApp extends MultiDexApplication { @Override public void onCreate() { super.onCreate(); - if (LeakCanary.isInAnalyzerProcess(this)) { - // This process is dedicated to LeakCanary for heap analysis. - // You should not init your app in this process. - return; - } - refWatcher = LeakCanary.install(this); // Normal app init code...*/ PRNGFixes.apply(); SharedPreferences preferences = getSharedPreferences(SHARED_PREFERENCES, MODE_PRIVATE); @@ -75,7 +65,9 @@ public class BitmaskApp extends MultiDexApplication { torStatusObservable = TorStatusObservable.getInstance(); EipSetupObserver.init(this, preferences); AppCompatDelegate.setCompatVectorFromResourcesEnabled(true); - TetheringStateManager.getInstance().init(this); + if (!isCalyxOSWithTetheringSupport(this)) { + TetheringStateManager.getInstance().init(this); + } if (BuildConfig.FLAVOR.contains("Fatweb")) { downloadBroadcastReceiver = new DownloadBroadcastReceiver(); IntentFilter intentFilter = new IntentFilter(BROADCAST_DOWNLOAD_SERVICE_EVENT); @@ -86,17 +78,4 @@ public class BitmaskApp extends MultiDexApplication { LocalBroadcastManager.getInstance(this.getApplicationContext()).registerReceiver(downloadBroadcastReceiver, intentFilter); } } - - /** - * Use this method to get a RefWatcher object that checks for memory leaks in the given context. - * Call refWatcher.watch(this) to check if all references get garbage collected. - * @param context - * @return the RefWatcher object - */ - public static RefWatcher getRefWatcher(Context context) { - BitmaskApp application = (BitmaskApp) context.getApplicationContext(); - return application.refWatcher; - } - - } diff --git a/app/src/main/java/se/leap/bitmaskclient/base/BitmaskTileService.java b/app/src/main/java/se/leap/bitmaskclient/base/BitmaskTileService.java index 65355a67d9da7cc58df7cde16ec55d06f79d9695..370a7af61773d432fbac75ad43d6f956950e1589 100644 --- a/app/src/main/java/se/leap/bitmaskclient/base/BitmaskTileService.java +++ b/app/src/main/java/se/leap/bitmaskclient/base/BitmaskTileService.java @@ -71,6 +71,11 @@ public class BitmaskTileService extends TileService implements Observer { @Override public void update(Observable o, Object arg) { Tile t = getQsTile(); + // Tile t should never be null according to https://developer.android.com/reference/kotlin/android/service/quicksettings/TileService. + // Hovever we've got crash reports. + if (t == null) { + return; + } if (o instanceof EipStatus) { EipStatus status = (EipStatus) o; diff --git a/app/src/main/java/se/leap/bitmaskclient/base/MainActivity.java b/app/src/main/java/se/leap/bitmaskclient/base/MainActivity.java index aea397fb7c608400481568d0d2ca147fbdff16da..9225755ecdf1e99accadaab05af86cb203729b5c 100644 --- a/app/src/main/java/se/leap/bitmaskclient/base/MainActivity.java +++ b/app/src/main/java/se/leap/bitmaskclient/base/MainActivity.java @@ -1,5 +1,5 @@ /** - * Copyright (c) 2018 LEAP Encryption Access Project and contributers + * Copyright (c) 2021 LEAP Encryption Access Project and contributers * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -17,14 +17,46 @@ package se.leap.bitmaskclient.base; +import static androidx.appcompat.app.ActionBar.DISPLAY_SHOW_CUSTOM; +import static se.leap.bitmaskclient.R.string.downloading_vpn_certificate_failed; +import static se.leap.bitmaskclient.R.string.vpn_certificate_user_message; +import static se.leap.bitmaskclient.base.models.Constants.ASK_TO_CANCEL_VPN; +import static se.leap.bitmaskclient.base.models.Constants.BROADCAST_RESULT_CODE; +import static se.leap.bitmaskclient.base.models.Constants.BROADCAST_RESULT_KEY; +import static se.leap.bitmaskclient.base.models.Constants.EIP_ACTION_LAUNCH_VPN; +import static se.leap.bitmaskclient.base.models.Constants.EIP_ACTION_PREPARE_VPN; +import static se.leap.bitmaskclient.base.models.Constants.EIP_ACTION_START; +import static se.leap.bitmaskclient.base.models.Constants.EIP_REQUEST; +import static se.leap.bitmaskclient.base.models.Constants.EXTRA_MOTD_MSG; +import static se.leap.bitmaskclient.base.models.Constants.LOCATION; +import static se.leap.bitmaskclient.base.models.Constants.PROVIDER_KEY; +import static se.leap.bitmaskclient.base.models.Constants.REQUEST_CODE_CONFIGURE_LEAP; +import static se.leap.bitmaskclient.base.models.Constants.REQUEST_CODE_LOG_IN; +import static se.leap.bitmaskclient.base.models.Constants.REQUEST_CODE_SWITCH_PROVIDER; +import static se.leap.bitmaskclient.base.models.Constants.SHARED_PREFERENCES; +import static se.leap.bitmaskclient.base.utils.PreferenceHelper.storeProviderInPreferences; +import static se.leap.bitmaskclient.eip.EIP.EIPErrors.ERROR_INVALID_VPN_CERTIFICATE; +import static se.leap.bitmaskclient.eip.EIP.EIPErrors.ERROR_VPN_PREPARE; +import static se.leap.bitmaskclient.providersetup.ProviderAPI.ERRORID; +import static se.leap.bitmaskclient.providersetup.ProviderAPI.ERRORS; +import static se.leap.bitmaskclient.providersetup.ProviderAPI.INCORRECTLY_DOWNLOADED_EIP_SERVICE; +import static se.leap.bitmaskclient.providersetup.ProviderAPI.INCORRECTLY_UPDATED_INVALID_VPN_CERTIFICATE; +import static se.leap.bitmaskclient.providersetup.ProviderAPI.TOR_EXCEPTION; +import static se.leap.bitmaskclient.providersetup.ProviderAPI.TOR_TIMEOUT; +import static se.leap.bitmaskclient.providersetup.ProviderAPI.UPDATE_INVALID_VPN_CERTIFICATE; +import static se.leap.bitmaskclient.providersetup.ProviderAPI.USER_MESSAGE; + +import android.content.Context; import android.content.Intent; import android.content.SharedPreferences; import android.os.Bundle; import android.util.Log; +import android.view.Gravity; -import androidx.annotation.StringRes; +import androidx.annotation.ColorInt; import androidx.appcompat.app.ActionBar; import androidx.appcompat.app.AppCompatActivity; +import androidx.core.content.ContextCompat; import androidx.fragment.app.DialogFragment; import androidx.fragment.app.Fragment; import androidx.fragment.app.FragmentTransaction; @@ -35,48 +67,27 @@ import org.json.JSONObject; import java.util.Observable; import java.util.Observer; +import se.leap.bitmaskclient.BuildConfig; import se.leap.bitmaskclient.R; import se.leap.bitmaskclient.base.fragments.EipFragment; import se.leap.bitmaskclient.base.fragments.ExcludeAppsFragment; import se.leap.bitmaskclient.base.fragments.LogFragment; import se.leap.bitmaskclient.base.fragments.MainActivityErrorDialog; +import se.leap.bitmaskclient.base.fragments.MotdFragment; import se.leap.bitmaskclient.base.fragments.NavigationDrawerFragment; import se.leap.bitmaskclient.base.fragments.SettingsFragment; import se.leap.bitmaskclient.base.models.Provider; import se.leap.bitmaskclient.base.models.ProviderObservable; import se.leap.bitmaskclient.base.utils.PreferenceHelper; +import se.leap.bitmaskclient.base.views.ActionBarTitle; import se.leap.bitmaskclient.eip.EIP; import se.leap.bitmaskclient.eip.EipCommand; import se.leap.bitmaskclient.eip.EipSetupListener; import se.leap.bitmaskclient.eip.EipSetupObserver; +import se.leap.bitmaskclient.providersetup.ProviderAPI; import se.leap.bitmaskclient.providersetup.activities.LoginActivity; import se.leap.bitmaskclient.providersetup.models.LeapSRPSession; -import static se.leap.bitmaskclient.R.string.downloading_vpn_certificate_failed; -import static se.leap.bitmaskclient.R.string.vpn_certificate_user_message; -import static se.leap.bitmaskclient.base.models.Constants.ASK_TO_CANCEL_VPN; -import static se.leap.bitmaskclient.base.models.Constants.BROADCAST_RESULT_CODE; -import static se.leap.bitmaskclient.base.models.Constants.BROADCAST_RESULT_KEY; -import static se.leap.bitmaskclient.base.models.Constants.EIP_ACTION_LAUNCH_VPN; -import static se.leap.bitmaskclient.base.models.Constants.EIP_ACTION_PREPARE_VPN; -import static se.leap.bitmaskclient.base.models.Constants.EIP_ACTION_START; -import static se.leap.bitmaskclient.base.models.Constants.EIP_REQUEST; -import static se.leap.bitmaskclient.base.models.Constants.LOCATION; -import static se.leap.bitmaskclient.base.models.Constants.PROVIDER_KEY; -import static se.leap.bitmaskclient.base.models.Constants.REQUEST_CODE_CONFIGURE_LEAP; -import static se.leap.bitmaskclient.base.models.Constants.REQUEST_CODE_LOG_IN; -import static se.leap.bitmaskclient.base.models.Constants.REQUEST_CODE_SWITCH_PROVIDER; -import static se.leap.bitmaskclient.base.models.Constants.SHARED_PREFERENCES; -import static se.leap.bitmaskclient.base.utils.PreferenceHelper.storeProviderInPreferences; -import static se.leap.bitmaskclient.eip.EIP.EIPErrors.ERROR_INVALID_VPN_CERTIFICATE; -import static se.leap.bitmaskclient.eip.EIP.EIPErrors.ERROR_VPN_PREPARE; -import static se.leap.bitmaskclient.providersetup.ProviderAPI.ERRORID; -import static se.leap.bitmaskclient.providersetup.ProviderAPI.ERRORS; -import static se.leap.bitmaskclient.providersetup.ProviderAPI.INCORRECTLY_DOWNLOADED_EIP_SERVICE; -import static se.leap.bitmaskclient.providersetup.ProviderAPI.INCORRECTLY_UPDATED_INVALID_VPN_CERTIFICATE; -import static se.leap.bitmaskclient.providersetup.ProviderAPI.USER_MESSAGE; - - public class MainActivity extends AppCompatActivity implements EipSetupListener, Observer { public final static String TAG = MainActivity.class.getSimpleName(); @@ -88,6 +99,7 @@ public class MainActivity extends AppCompatActivity implements EipSetupListener, public final static String ACTION_SHOW_VPN_FRAGMENT = "action_show_vpn_fragment"; public final static String ACTION_SHOW_LOG_FRAGMENT = "action_show_log_fragment"; public final static String ACTION_SHOW_DIALOG_FRAGMENT = "action_show_dialog_fragment"; + public final static String ACTION_SHOW_MOTD_FRAGMENT = "action_show_motd_fragment"; /** * Fragment managing the behaviors, interactions and presentation of the navigation drawer. @@ -97,8 +109,7 @@ public class MainActivity extends AppCompatActivity implements EipSetupListener, protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.a_main); - setSupportActionBar(findViewById(R.id.toolbar)); - + setupActionBar(); navigationDrawerFragment = (NavigationDrawerFragment) getSupportFragmentManager().findFragmentById(R.id.navigation_drawer); @@ -127,7 +138,6 @@ public class MainActivity extends AppCompatActivity implements EipSetupListener, newFragment.setArguments(bundle); } fragmentManagerEnhanced.replace(R.id.main_container, newFragment, MainActivity.TAG); - hideActionBarSubTitle(); } else { super.onBackPressed(); } @@ -155,11 +165,20 @@ public class MainActivity extends AppCompatActivity implements EipSetupListener, } bundle.putParcelable(PROVIDER_KEY, provider); fragment.setArguments(bundle); - hideActionBarSubTitle(); + showActionBar(); + break; + case ACTION_SHOW_MOTD_FRAGMENT: + fragment = new MotdFragment(); + Bundle motdBundle = new Bundle(); + if (intent.hasExtra(EXTRA_MOTD_MSG)) { + motdBundle.putString(EXTRA_MOTD_MSG, intent.getStringExtra(EXTRA_MOTD_MSG)); + } + fragment.setArguments(motdBundle); + hideActionBar(); break; case ACTION_SHOW_LOG_FRAGMENT: fragment = new LogFragment(); - setActionBarTitle(R.string.log_fragment_title); + showActionBar(); break; case ACTION_SHOW_DIALOG_FRAGMENT: if (intent.hasExtra(EIP.ERRORID)) { @@ -181,19 +200,46 @@ public class MainActivity extends AppCompatActivity implements EipSetupListener, } } - private void hideActionBarSubTitle() { + private void setupActionBar() { + setSupportActionBar(findViewById(R.id.toolbar)); + final ActionBar actionBar = getSupportActionBar(); + Context context = actionBar.getThemedContext(); + actionBar.setDisplayOptions(DISPLAY_SHOW_CUSTOM); + + ActionBarTitle actionBarTitle = new ActionBarTitle(context); + actionBarTitle.setTitleCaps(BuildConfig.actionbar_capitalize_title); + actionBarTitle.setTitle(getString(R.string.app_name)); + + @ColorInt int titleColor = ContextCompat.getColor(context, R.color.colorActionBarTitleFont); + actionBarTitle.setTitleTextColor(titleColor); + + actionBarTitle.setCentered(BuildConfig.actionbar_center_title); + if (BuildConfig.actionbar_center_title) { + ActionBar.LayoutParams params = new ActionBar.LayoutParams( + ActionBar.LayoutParams.WRAP_CONTENT, + ActionBar.LayoutParams.MATCH_PARENT, + Gravity.CENTER); + actionBar.setCustomView(actionBarTitle, params); + } else { + actionBar.setCustomView(actionBarTitle); + } + } + + private void hideActionBar() { ActionBar actionBar = getSupportActionBar(); if (actionBar != null) { - actionBar.setSubtitle(null); + actionBar.hide(); } } - private void setActionBarTitle(@StringRes int stringId) { + + private void showActionBar() { ActionBar actionBar = getSupportActionBar(); if (actionBar != null) { - actionBar.setSubtitle(stringId); + actionBar.show(); } } + @Override protected void onActivityResult(int requestCode, int resultCode, Intent data) { super.onActivityResult(requestCode, resultCode, data); @@ -236,7 +282,6 @@ public class MainActivity extends AppCompatActivity implements EipSetupListener, fragment.setArguments(arguments); new FragmentManagerEnhanced(getSupportFragmentManager()) .replace(R.id.main_container, fragment, MainActivity.TAG); - hideActionBarSubTitle(); } @Override @@ -303,6 +348,19 @@ public class MainActivity extends AppCompatActivity implements EipSetupListener, askUserToLogIn(getString(vpn_certificate_user_message)); } break; + case TOR_TIMEOUT: + case TOR_EXCEPTION: + try { + Bundle resultData = intent.getParcelableExtra(BROADCAST_RESULT_KEY); + JSONObject jsonObject = new JSONObject(resultData.getString(ProviderAPI.ERRORS)); + String initialAction = jsonObject.optString(ProviderAPI.INITIAL_ACTION); + if (UPDATE_INVALID_VPN_CERTIFICATE.equals(initialAction)) { + showMainActivityErrorDialog(getString(downloading_vpn_certificate_failed)); + } + } catch (Exception e) { + //ignore + } + break; } } @@ -327,7 +385,6 @@ public class MainActivity extends AppCompatActivity implements EipSetupListener, JSONObject errorJson = new JSONObject(reasonToFail); newFragment = MainActivityErrorDialog.newInstance(provider, errorJson); } catch (JSONException e) { - e.printStackTrace(); newFragment = MainActivityErrorDialog.newInstance(provider, reasonToFail); } newFragment.show(fragmentTransaction, MainActivityErrorDialog.TAG); diff --git a/app/src/main/java/se/leap/bitmaskclient/base/StartActivity.java b/app/src/main/java/se/leap/bitmaskclient/base/StartActivity.java index 1ea574ff31c5e64347650a0741dae2fa71255952..58b057b7a990d0debcb8de2775548192e35cce86 100644 --- a/app/src/main/java/se/leap/bitmaskclient/base/StartActivity.java +++ b/app/src/main/java/se/leap/bitmaskclient/base/StartActivity.java @@ -16,6 +16,19 @@ */ package se.leap.bitmaskclient.base; +import static se.leap.bitmaskclient.base.MainActivity.ACTION_SHOW_MOTD_FRAGMENT; +import static se.leap.bitmaskclient.base.MainActivity.ACTION_SHOW_VPN_FRAGMENT; +import static se.leap.bitmaskclient.base.models.Constants.APP_ACTION_CONFIGURE_ALWAYS_ON_PROFILE; +import static se.leap.bitmaskclient.base.models.Constants.EIP_RESTART_ON_BOOT; +import static se.leap.bitmaskclient.base.models.Constants.EXTRA_MOTD_MSG; +import static se.leap.bitmaskclient.base.models.Constants.PREFERENCES_APP_VERSION; +import static se.leap.bitmaskclient.base.models.Constants.PROVIDER_EIP_DEFINITION; +import static se.leap.bitmaskclient.base.models.Constants.PROVIDER_KEY; +import static se.leap.bitmaskclient.base.models.Constants.REQUEST_CODE_CONFIGURE_LEAP; +import static se.leap.bitmaskclient.base.models.Constants.SHARED_PREFERENCES; +import static se.leap.bitmaskclient.base.utils.ConfigHelper.isDefaultBitmask; +import static se.leap.bitmaskclient.base.utils.PreferenceHelper.storeProviderInPreferences; + import android.app.Activity; import android.content.Intent; import android.content.SharedPreferences; @@ -28,27 +41,22 @@ import androidx.annotation.Nullable; import java.lang.annotation.Retention; import java.lang.annotation.RetentionPolicy; +import java.util.Set; import de.blinkt.openvpn.core.VpnStatus; +import motd.IMessage; +import motd.IMessages; +import motd.IStringCollection; +import motd.Motd; import se.leap.bitmaskclient.BuildConfig; -import se.leap.bitmaskclient.providersetup.ProviderListActivity; -import se.leap.bitmaskclient.eip.EipCommand; import se.leap.bitmaskclient.base.models.FeatureVersionCode; import se.leap.bitmaskclient.base.models.Provider; import se.leap.bitmaskclient.base.models.ProviderObservable; -import se.leap.bitmaskclient.providersetup.activities.CustomProviderSetupActivity; +import se.leap.bitmaskclient.base.utils.DateHelper; import se.leap.bitmaskclient.base.utils.PreferenceHelper; - -import static se.leap.bitmaskclient.base.models.Constants.APP_ACTION_CONFIGURE_ALWAYS_ON_PROFILE; -import static se.leap.bitmaskclient.base.models.Constants.EIP_RESTART_ON_BOOT; -import static se.leap.bitmaskclient.base.models.Constants.PREFERENCES_APP_VERSION; -import static se.leap.bitmaskclient.base.models.Constants.PROVIDER_EIP_DEFINITION; -import static se.leap.bitmaskclient.base.models.Constants.PROVIDER_KEY; -import static se.leap.bitmaskclient.base.models.Constants.REQUEST_CODE_CONFIGURE_LEAP; -import static se.leap.bitmaskclient.base.models.Constants.SHARED_PREFERENCES; -import static se.leap.bitmaskclient.base.MainActivity.ACTION_SHOW_VPN_FRAGMENT; -import static se.leap.bitmaskclient.base.utils.ConfigHelper.isDefaultBitmask; -import static se.leap.bitmaskclient.base.utils.PreferenceHelper.storeProviderInPreferences; +import se.leap.bitmaskclient.eip.EipCommand; +import se.leap.bitmaskclient.providersetup.ProviderListActivity; +import se.leap.bitmaskclient.providersetup.activities.CustomProviderSetupActivity; /** * Activity shown at startup. Evaluates if App is started for the first time or has been upgraded @@ -89,7 +97,6 @@ public class StartActivity extends Activity{ case UPGRADE: executeUpgrade(); - // TODO show donation dialog break; } @@ -154,7 +161,22 @@ public class StartActivity extends Activity{ Provider provider = ProviderObservable.getInstance().getCurrentProvider(); if (provider != null && !provider.isDefault()) { PreferenceHelper.deleteProviderDetailsFromPreferences(preferences, provider.getDomain()); - ProviderObservable.getInstance().updateProvider(null); + ProviderObservable.getInstance().updateProvider(new Provider()); + } + } + + if ((hasNewFeature(FeatureVersionCode.CALYX_PROVIDER_LILYPAD_UPDATE) && ( + getPackageName().equals("org.calyxinstitute.vpn") || + ProviderObservable.getInstance().getCurrentProvider().getDomain().equals("calyx.net"))) || + hasNewFeature(FeatureVersionCode.RISEUP_PROVIDER_LILYPAD_UPDATE) && ( + getPackageName().equals("se.leap.riseupvpn") || + ProviderObservable.getInstance().getCurrentProvider().getDomain().equals("riseup.net"))) { + // deletion of current configured provider so that a new provider setup is triggered + Provider provider = ProviderObservable.getInstance().getCurrentProvider(); + if (provider != null && !provider.isDefault()) { + PreferenceHelper.deleteProviderDetailsFromPreferences(preferences, provider.getDomain()); + PreferenceHelper.deleteCurrentProviderDetailsFromPreferences(preferences); + ProviderObservable.getInstance().updateProvider(new Provider()); } } @@ -181,24 +203,20 @@ public class StartActivity extends Activity{ } private void prepareEIP() { - boolean providerExists = ProviderObservable.getInstance().getCurrentProvider() != null; - if (providerExists) { - Provider provider = ProviderObservable.getInstance().getCurrentProvider(); - if(!provider.isConfigured()) { - configureLeapProvider(); + Provider provider = ProviderObservable.getInstance().getCurrentProvider(); + if (provider.isConfigured()) { + Log.d(TAG, "vpn provider is configured"); + if (getIntent() != null && getIntent().getBooleanExtra(EIP_RESTART_ON_BOOT, false)) { + EipCommand.startVPN(this, true); + finish(); + } else if (PreferenceHelper.getRestartOnUpdate(this.getApplicationContext())) { + // This is relevant for web build flavor apks + PreferenceHelper.restartOnUpdate(this.getApplicationContext(), false); + EipCommand.startVPN(this, false); + showNextActivity(provider); + finish(); } else { - Log.d(TAG, "vpn provider is configured"); - if (getIntent() != null && getIntent().getBooleanExtra(EIP_RESTART_ON_BOOT, false)) { - EipCommand.startVPN(this, true); - finish(); - } else if (PreferenceHelper.getRestartOnUpdate(this.getApplicationContext())) { - PreferenceHelper.restartOnUpdate(this.getApplicationContext(), false); - EipCommand.startVPN(this, false); - showMainActivity(); - finish(); - } else { - showMainActivity(); - } + showNextActivity(provider); } } else { configureLeapProvider(); @@ -225,18 +243,60 @@ public class StartActivity extends Activity{ storeProviderInPreferences(preferences, provider); ProviderObservable.getInstance().updateProvider(provider); EipCommand.startVPN(this, false); - showMainActivity(); + showNextActivity(provider); } else if (resultCode == RESULT_CANCELED) { finish(); } } } - private void showMainActivity() { + private void showNextActivity(Provider provider) { + if (provider.shouldShowMotdSeen()) { + try { + IMessages messages = Motd.newMessages(provider.getMotdJsonString()); + + IStringCollection stringCollection = Motd.newStringCollection(); //provider.getMotdLastSeenHashCollection(); + String formattedDate = DateHelper.getFormattedDateWithTimezone(provider.getLastMotdSeen()); + IMessage message = messages.getFirstMessage(formattedDate, stringCollection); + if (message != null) { + IMessage imessage = Motd.newMessage(message.toJson()); + showMotd(provider, imessage); + return; + } + } catch (IllegalArgumentException e) { + Log.e(TAG, "Couldn't show Motd. Invalid timestamp."); + } + } + showVPNFragment(); + } + + private void showMotd(Provider p, IMessage message) { + if (message.mType().equals(Motd.MESSAGE_TYPE_ONCE)) { + Set<String> lastSeenHashes = p.getMotdLastSeenHashes(); + String hash = message.hash(); + lastSeenHashes.add(hash); + p.setMotdLastSeenHashes(lastSeenHashes); + p.setLastMotdSeen(System.currentTimeMillis()); + PreferenceHelper.persistProviderAsync(this, p); + ProviderObservable.getInstance().updateProvider(p); + } + showMotdFragment(message); + } + + private void showVPNFragment() { Intent intent = new Intent(this, MainActivity.class); intent.setFlags(Intent.FLAG_ACTIVITY_SINGLE_TOP | Intent.FLAG_ACTIVITY_CLEAR_TOP); intent.setAction(ACTION_SHOW_VPN_FRAGMENT); startActivity(intent); finish(); } + + private void showMotdFragment(IMessage message) { + Intent intent = new Intent(this, MainActivity.class); + intent.setFlags(Intent.FLAG_ACTIVITY_SINGLE_TOP | Intent.FLAG_ACTIVITY_CLEAR_TOP); + intent.setAction(ACTION_SHOW_MOTD_FRAGMENT); + intent.putExtra(EXTRA_MOTD_MSG, message.toJson()); + startActivity(intent); + finish(); + } } diff --git a/app/src/main/java/se/leap/bitmaskclient/base/fragments/AboutFragment.java b/app/src/main/java/se/leap/bitmaskclient/base/fragments/AboutFragment.java index 10dd3189153c641a88873061eba025b343e85ed8..37ae26563f20e84d257f2734a8253cd2d24bf69c 100644 --- a/app/src/main/java/se/leap/bitmaskclient/base/fragments/AboutFragment.java +++ b/app/src/main/java/se/leap/bitmaskclient/base/fragments/AboutFragment.java @@ -18,7 +18,7 @@ import se.leap.bitmaskclient.R; import static android.view.View.VISIBLE; import static se.leap.bitmaskclient.R.string.about_fragment_title; -import static se.leap.bitmaskclient.base.utils.ViewHelper.setActionBarTitle; +import static se.leap.bitmaskclient.base.utils.ViewHelper.setActionBarSubtitle; public class AboutFragment extends Fragment { @@ -36,7 +36,7 @@ public class AboutFragment extends Fragment { public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) { View view = inflater.inflate(R.layout.f_about, container, false); unbinder = ButterKnife.bind(this, view); - setActionBarTitle(this, about_fragment_title); + setActionBarSubtitle(this, about_fragment_title); return view; } diff --git a/app/src/main/java/se/leap/bitmaskclient/base/fragments/EipFragment.java b/app/src/main/java/se/leap/bitmaskclient/base/fragments/EipFragment.java index dfa456148f67b1311fd5baedd6c150066cea82e0..a2fb26836ceb84a1e9a4467c600c1092ebd5ccef 100644 --- a/app/src/main/java/se/leap/bitmaskclient/base/fragments/EipFragment.java +++ b/app/src/main/java/se/leap/bitmaskclient/base/fragments/EipFragment.java @@ -16,56 +16,69 @@ */ package se.leap.bitmaskclient.base.fragments; +import static se.leap.bitmaskclient.R.string.vpn_certificate_user_message; +import static se.leap.bitmaskclient.base.models.Constants.ASK_TO_CANCEL_VPN; +import static se.leap.bitmaskclient.base.models.Constants.EIP_ACTION_START; +import static se.leap.bitmaskclient.base.models.Constants.EIP_EARLY_ROUTES; +import static se.leap.bitmaskclient.base.models.Constants.EIP_RESTART_ON_BOOT; +import static se.leap.bitmaskclient.base.models.Constants.PROVIDER_KEY; +import static se.leap.bitmaskclient.base.models.Constants.REQUEST_CODE_CONFIGURE_LEAP; +import static se.leap.bitmaskclient.base.models.Constants.REQUEST_CODE_LOG_IN; +import static se.leap.bitmaskclient.base.models.Constants.REQUEST_CODE_SWITCH_PROVIDER; +import static se.leap.bitmaskclient.base.models.Constants.SHARED_PREFERENCES; +import static se.leap.bitmaskclient.base.utils.ConfigHelper.isDefaultBitmask; +import static se.leap.bitmaskclient.base.utils.PreferenceHelper.getPreferredCity; +import static se.leap.bitmaskclient.eip.EipSetupObserver.reconnectingWithDifferentGateway; +import static se.leap.bitmaskclient.eip.GatewaysManager.Load.UNKNOWN; +import static se.leap.bitmaskclient.providersetup.ProviderAPI.DOWNLOAD_GEOIP_JSON; +import static se.leap.bitmaskclient.providersetup.ProviderAPI.UPDATE_INVALID_VPN_CERTIFICATE; +import static se.leap.bitmaskclient.providersetup.ProviderAPI.USER_MESSAGE; + import android.app.Activity; -import android.content.ComponentName; import android.content.Context; import android.content.Intent; -import android.content.ServiceConnection; import android.content.SharedPreferences; -import android.graphics.ColorMatrix; -import android.graphics.ColorMatrixColorFilter; +import android.graphics.drawable.Animatable; +import android.graphics.drawable.Drawable; import android.os.Bundle; -import android.os.IBinder; -import android.os.Vibrator; +import android.text.Spannable; +import android.text.SpannableString; import android.text.TextUtils; +import android.text.style.RelativeSizeSpan; import android.util.Log; -import android.view.Gravity; import android.view.LayoutInflater; import android.view.View; import android.view.ViewGroup; -import android.widget.TextView; -import android.widget.Toast; +import androidx.annotation.ColorRes; +import androidx.annotation.DrawableRes; import androidx.annotation.NonNull; import androidx.appcompat.app.AlertDialog; -import androidx.appcompat.widget.AppCompatButton; import androidx.appcompat.widget.AppCompatImageView; import androidx.appcompat.widget.AppCompatTextView; +import androidx.core.content.ContextCompat; import androidx.fragment.app.DialogFragment; import androidx.fragment.app.Fragment; import androidx.fragment.app.FragmentTransaction; +import androidx.vectordrawable.graphics.drawable.Animatable2Compat.AnimationCallback; +import androidx.vectordrawable.graphics.drawable.AnimatedVectorDrawableCompat; import java.util.Observable; import java.util.Observer; -import butterknife.BindView; -import butterknife.ButterKnife; -import butterknife.OnClick; -import butterknife.Unbinder; import de.blinkt.openvpn.core.ConnectionStatus; -import de.blinkt.openvpn.core.IOpenVPNServiceInternal; -import de.blinkt.openvpn.core.OpenVPNService; import de.blinkt.openvpn.core.VpnStatus; import de.blinkt.openvpn.core.connection.Connection; -import se.leap.bitmaskclient.BuildConfig; import se.leap.bitmaskclient.R; import se.leap.bitmaskclient.base.FragmentManagerEnhanced; import se.leap.bitmaskclient.base.MainActivity; import se.leap.bitmaskclient.base.models.Provider; import se.leap.bitmaskclient.base.models.ProviderObservable; import se.leap.bitmaskclient.base.utils.PreferenceHelper; +import se.leap.bitmaskclient.base.utils.ViewHelper; import se.leap.bitmaskclient.base.views.LocationButton; import se.leap.bitmaskclient.base.views.MainButton; +import se.leap.bitmaskclient.databinding.FEipBinding; import se.leap.bitmaskclient.eip.EipCommand; import se.leap.bitmaskclient.eip.EipStatus; import se.leap.bitmaskclient.eip.GatewaysManager; @@ -74,29 +87,8 @@ import se.leap.bitmaskclient.providersetup.ProviderListActivity; import se.leap.bitmaskclient.providersetup.activities.CustomProviderSetupActivity; import se.leap.bitmaskclient.providersetup.activities.LoginActivity; import se.leap.bitmaskclient.providersetup.models.LeapSRPSession; - -import static android.view.View.INVISIBLE; -import static android.view.View.VISIBLE; -import static de.blinkt.openvpn.core.ConnectionStatus.LEVEL_NONETWORK; -import static se.leap.bitmaskclient.R.string.vpn_certificate_user_message; -import static se.leap.bitmaskclient.base.models.Constants.ASK_TO_CANCEL_VPN; -import static se.leap.bitmaskclient.base.models.Constants.EIP_ACTION_START; -import static se.leap.bitmaskclient.base.models.Constants.EIP_EARLY_ROUTES; -import static se.leap.bitmaskclient.base.models.Constants.EIP_RESTART_ON_BOOT; -import static se.leap.bitmaskclient.base.models.Constants.PROVIDER_KEY; -import static se.leap.bitmaskclient.base.models.Constants.REQUEST_CODE_CONFIGURE_LEAP; -import static se.leap.bitmaskclient.base.models.Constants.REQUEST_CODE_LOG_IN; -import static se.leap.bitmaskclient.base.models.Constants.REQUEST_CODE_SWITCH_PROVIDER; -import static se.leap.bitmaskclient.base.models.Constants.SHARED_PREFERENCES; -import static se.leap.bitmaskclient.base.utils.ConfigHelper.isDefaultBitmask; -import static se.leap.bitmaskclient.base.utils.PreferenceHelper.getPreferredCity; -import static se.leap.bitmaskclient.base.utils.ViewHelper.convertDimensionToPx; -import static se.leap.bitmaskclient.eip.EipSetupObserver.gatewayOrder; -import static se.leap.bitmaskclient.eip.EipSetupObserver.reconnectingWithDifferentGateway; -import static se.leap.bitmaskclient.eip.GatewaysManager.Load.UNKNOWN; -import static se.leap.bitmaskclient.providersetup.ProviderAPI.DOWNLOAD_GEOIP_JSON; -import static se.leap.bitmaskclient.providersetup.ProviderAPI.UPDATE_INVALID_VPN_CERTIFICATE; -import static se.leap.bitmaskclient.providersetup.ProviderAPI.USER_MESSAGE; +import se.leap.bitmaskclient.tor.TorServiceCommand; +import se.leap.bitmaskclient.tor.TorStatusObservable; public class EipFragment extends Fragment implements Observer { @@ -106,24 +98,19 @@ public class EipFragment extends Fragment implements Observer { private SharedPreferences preferences; private Provider provider; - @BindView(R.id.background) AppCompatImageView background; - - @BindView(R.id.main_button) + AppCompatImageView stateView; MainButton mainButton; - - @BindView(R.id.gateway_location_button) LocationButton locationButton; - - @BindView(R.id.main_description) AppCompatTextView mainDescription; - - @BindView(R.id.sub_description) AppCompatTextView subDescription; - private Unbinder unbinder; + private EipStatus.EipLevel previousEipLevel = EipStatus.EipLevel.UNKNOWN; private EipStatus eipStatus; + private ProviderObservable providerObservable; + private TorStatusObservable torStatusObservable; + private @DrawableRes int pendingAnimationState; private GatewaysManager gatewaysManager; //---saved Instance ------- @@ -134,9 +121,6 @@ public class EipFragment extends Fragment implements Observer { //------------------------ AlertDialog alertDialog; - private IOpenVPNServiceInternal mService; - private ServiceConnection openVpnConnection; - @Override public void onAttach(Context context) { super.onAttach(context); @@ -170,8 +154,9 @@ public class EipFragment extends Fragment implements Observer { @Override public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); - openVpnConnection = new EipFragmentServiceConnection(); eipStatus = EipStatus.getInstance(); + providerObservable = ProviderObservable.getInstance(); + torStatusObservable = TorStatusObservable.getInstance(); Activity activity = getActivity(); if (activity != null) { preferences = getActivity().getSharedPreferences(SHARED_PREFERENCES, Context.MODE_PRIVATE); @@ -180,15 +165,23 @@ public class EipFragment extends Fragment implements Observer { } gatewaysManager = new GatewaysManager(getContext()); - - } @Override public View onCreateView(@NonNull LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) { + FEipBinding binding = FEipBinding.inflate(LayoutInflater.from(getContext()), container, false); + background = binding.background; + mainButton = binding.mainButton; + locationButton = binding.gatewayLocationButton; + locationButton.setTextColor(R.color.black800); + mainDescription = binding.mainDescription; + subDescription = binding.subDescription; + stateView = binding.stateView; + ViewHelper.setActionBarTitle(this, R.string.app_name); + eipStatus.addObserver(this); - View view = inflater.inflate(R.layout.f_eip, container, false); - unbinder = ButterKnife.bind(this, view); + torStatusObservable.addObserver(this); + providerObservable.addObserver(this); try { Bundle arguments = getArguments(); @@ -208,7 +201,11 @@ public class EipFragment extends Fragment implements Observer { Fragment fragment = new GatewaySelectionFragment(); fragmentManager.replace(R.id.main_container, fragment, MainActivity.TAG); }); - return view; + + mainButton.setOnClickListener(v -> { + handleIcon(); + }); + return binding.getRoot(); } @Override @@ -222,19 +219,19 @@ public class EipFragment extends Fragment implements Observer { @Override public void onResume() { super.onResume(); - //FIXME: avoid race conditions while checking certificate an logging in at about the same time - //eipCommand(Constants.EIP_ACTION_CHECK_CERT_VALIDITY); - bindOpenVpnService(); + Log.d(TAG, "onResume"); handleNewState(); } @Override public void onPause() { super.onPause(); - - Activity activity = getActivity(); - if (activity != null) { - getActivity().unbindService(openVpnConnection); + Log.d(TAG, "onPause"); + if (stateView.getDrawable() instanceof Animatable) { + Animatable animatedDrawable = (Animatable) stateView.getDrawable(); + if (animatedDrawable.isRunning()) { + animatedDrawable.stop(); + } } } @@ -263,21 +260,26 @@ public class EipFragment extends Fragment implements Observer { @Override public void onDestroyView() { super.onDestroyView(); + Log.d(TAG, "onDestroyView"); + + ViewHelper.setDefaultActivityBarColor(getActivity()); eipStatus.deleteObserver(this); - unbinder.unbind(); + providerObservable.deleteObserver(this); + torStatusObservable.deleteObserver(this); + background = null; + mainButton = null; + locationButton = null; + mainDescription = null; + subDescription = null; + stateView = null; } private void saveStatus(boolean restartOnBoot) { preferences.edit().putBoolean(EIP_RESTART_ON_BOOT, restartOnBoot).apply(); } - @OnClick(R.id.main_button) - void onButtonClick() { - handleIcon(); - } - void handleIcon() { - if (isOpenVpnRunningWithoutNetwork() || eipStatus.isConnected() || eipStatus.isConnecting()) + if (eipStatus.isVPNRunningWithoutNetwork() || eipStatus.isConnected() || eipStatus.isConnecting() || eipStatus.isUpdatingVpnCert()) handleSwitchOff(); else handleSwitchOn(); @@ -313,7 +315,7 @@ public class EipFragment extends Fragment implements Observer { } private void handleSwitchOff() { - if (isOpenVpnRunningWithoutNetwork() || eipStatus.isConnecting()) { + if (eipStatus.isVPNRunningWithoutNetwork() || eipStatus.isConnecting() || eipStatus.isUpdatingVpnCert()) { askPendingStartCancellation(); } else if (eipStatus.isConnected()) { askToStopEIP(); @@ -364,7 +366,14 @@ public class EipFragment extends Fragment implements Observer { showPendingStartCancellation = true; alertDialog = alertBuilder.setTitle(activity.getString(R.string.eip_cancel_connect_title)) .setMessage(activity.getString(R.string.eip_cancel_connect_text)) - .setPositiveButton((android.R.string.yes), (dialog, which) -> stopEipIfPossible()) + .setPositiveButton((android.R.string.yes), (dialog, which) -> { + Context context = getContext(); + if (context != null && eipStatus.isUpdatingVpnCert() && + TorStatusObservable.isRunning()) { + TorServiceCommand.stopTorServiceAsync(context.getApplicationContext()); + } + stopEipIfPossible(); + }) .setNegativeButton(activity.getString(android.R.string.no), (dialog, which) -> { }).setOnDismissListener(dialog -> showPendingStartCancellation = false).show(); } catch (IllegalStateException e) { @@ -396,18 +405,30 @@ public class EipFragment extends Fragment implements Observer { @Override public void update(Observable observable, Object data) { if (observable instanceof EipStatus) { + previousEipLevel = eipStatus.getEipLevel(); eipStatus = (EipStatus) observable; - Activity activity = getActivity(); - if (activity != null) { - activity.runOnUiThread(this::handleNewState); - } else { - Log.e("EipFragment", "activity is null"); - } + handleNewStateOnMain(); + } else if (observable instanceof ProviderObservable) { provider = ((ProviderObservable) observable).getCurrentProvider(); + } else if (observable instanceof TorStatusObservable && EipStatus.getInstance().isUpdatingVpnCert()) { + handleNewStateOnMain(); } } + private void handleNewStateOnMain() { + Activity activity = getActivity(); + if (activity != null) { + activity.runOnUiThread(this::handleNewState); + } else { + Log.e("EipFragment", "activity is null"); + } + } + + private void setActivityBarColor(@ColorRes int primaryColor, @ColorRes int secondaryColor) { + ViewHelper.setActivityBarColor(getActivity(), primaryColor, secondaryColor, R.color.actionbar_connectivity_state_text_color_dark); + } + private void handleNewState() { Activity activity = getActivity(); if (activity == null) { @@ -416,164 +437,168 @@ public class EipFragment extends Fragment implements Observer { } Log.d(TAG, "eip fragment eipStatus state: " + eipStatus.getState() + " - level: " + eipStatus.getLevel() + " - is reconnecting: " + eipStatus.isReconnecting()); - if (eipStatus.isConnecting()) { + if (eipStatus.isUpdatingVpnCert()) { setMainButtonEnabled(true); - showConnectionTransitionLayout(true); - locationButton.setText(getString(R.string.eip_status_start_pending)); + String city = getPreferredCity(getContext()); + String locationName = VpnStatus.getCurrentlyConnectingVpnName() != null ? + VpnStatus.getCurrentlyConnectingVpnName() : + city == null ? getString(R.string.gateway_selection_recommended_location) : city; + locationButton.setText(locationName); locationButton.setLocationLoad(UNKNOWN); locationButton.showBridgeIndicator(false); locationButton.showRecommendedIndicator(false); - mainDescription.setText(null); + mainDescription.setText(R.string.eip_status_connecting); + String torStatus = TorStatusObservable.getStringForCurrentStatus(getContext()); + if (!TextUtils.isEmpty(torStatus)) { + Spannable spannable = new SpannableString(torStatus); + spannable.setSpan(new RelativeSizeSpan(0.75f), 0, spannable.length(), Spannable.SPAN_EXCLUSIVE_EXCLUSIVE); + subDescription.setText(TextUtils.concat(getString(R.string.updating_certificate_message) + "\n", spannable)); + } else { + subDescription.setText(getString(R.string.updating_certificate_message)); + } + background.setImageResource(R.drawable.bg_connecting); + animateState(R.drawable.state_connecting); + mainButton.updateState(false, true); + setActivityBarColor(R.color.bg_connecting_top, R.color.bg_connecting_top_light_transparent); + } else if (eipStatus.isConnecting()) { + setMainButtonEnabled(true); + String city = getPreferredCity(getContext()); + String locationName = VpnStatus.getCurrentlyConnectingVpnName() != null ? + VpnStatus.getCurrentlyConnectingVpnName() : + city == null ? getString(R.string.gateway_selection_recommended_location) : city; + locationButton.setText(locationName); + locationButton.setLocationLoad(UNKNOWN); + locationButton.showBridgeIndicator(false); + locationButton.showRecommendedIndicator(false); + mainDescription.setText(R.string.eip_status_connecting); subDescription.setText(null); + background.setImageResource(R.drawable.bg_connecting); + animateState(R.drawable.state_connecting); + mainButton.updateState(false, true); + setActivityBarColor(R.color.bg_connecting_top, R.color.bg_connecting_top_light_transparent); } else if (eipStatus.isConnected()) { setMainButtonEnabled(true); - mainButton.updateState(true, false, false); + mainButton.updateState(true, false); Connection.TransportType transportType = PreferenceHelper.getUseBridges(getContext()) ? Connection.TransportType.OBFS4 : Connection.TransportType.OPENVPN; - locationButton.setLocationLoad(gatewaysManager.getLoadForLocation(VpnStatus.getLastConnectedVpnName(), transportType)); + locationButton.setLocationLoad(PreferenceHelper.useObfuscationPinning(getContext()) ? GatewaysManager.Load.UNKNOWN : gatewaysManager.getLoadForLocation(VpnStatus.getLastConnectedVpnName(), transportType)); locationButton.setText(VpnStatus.getLastConnectedVpnName()); locationButton.showBridgeIndicator(VpnStatus.isUsingBridges()); - locationButton.showRecommendedIndicator(getPreferredCity(getContext())== null); - mainDescription.setText(R.string.eip_state_connected); + locationButton.showRecommendedIndicator(getPreferredCity(getContext()) == null); + mainDescription.setText(R.string.eip_status_secured); subDescription.setText(null); - colorBackground(); - } else if(isOpenVpnRunningWithoutNetwork()) { + background.setImageResource(R.drawable.bg_connected); + animateState(R.drawable.state_connected); + setActivityBarColor(R.color.bg_running_top, R.color.bg_running_top_light_transparent); + } else if(eipStatus.isVPNRunningWithoutNetwork()) { Log.d(TAG, "eip fragment eipStatus - isOpenVpnRunningWithoutNetwork"); setMainButtonEnabled(true); - mainButton.updateState(true, false, true); + mainButton.updateState(false, true); locationButton.setText(VpnStatus.getCurrentlyConnectingVpnName()); locationButton.showBridgeIndicator(VpnStatus.isUsingBridges()); locationButton.showBridgeIndicator(VpnStatus.isUsingBridges()); locationButton.showRecommendedIndicator(getPreferredCity(getContext())== null); - colorBackgroundALittle(); mainDescription.setText(R.string.eip_state_connected); subDescription.setText(R.string.eip_state_no_network); + background.setImageResource(R.drawable.bg_connecting); + animateState(R.drawable.state_connecting); + setActivityBarColor(R.color.bg_connecting_top, R.color.bg_connecting_top_light_transparent); } else if (eipStatus.isDisconnected() && reconnectingWithDifferentGateway()) { - showConnectionTransitionLayout(true); - // showRetryToast(activity); - locationButton.setText(getString(R.string.eip_status_start_pending)); + setMainButtonEnabled(true); + mainButton.updateState(false, true); + locationButton.setText(VpnStatus.getCurrentlyConnectingVpnName()); locationButton.setLocationLoad(UNKNOWN); locationButton.showBridgeIndicator(false); locationButton.showRecommendedIndicator(false); - mainDescription.setText(null); + mainDescription.setText(R.string.eip_status_connecting); subDescription.setText(R.string.reconnecting); + background.setImageResource(R.drawable.bg_connecting); + animateState(R.drawable.state_connecting); + setActivityBarColor(R.color.bg_connecting_top, R.color.bg_connecting_top_light_transparent); } else if (eipStatus.isDisconnecting()) { setMainButtonEnabled(false); - showConnectionTransitionLayout(false); - mainDescription.setText(R.string.eip_state_insecure); + mainButton.updateState(false, false); + mainDescription.setText(R.string.eip_status_unsecured); + background.setImageResource(R.drawable.bg_disconnected); + if (previousEipLevel == EipStatus.EipLevel.CONNECTED) { + animateState(R.drawable.state_transition_connected_disconnected); + } else { + animateState(R.drawable.state_disconnected); + } + setActivityBarColor(R.color.bg_disconnected_top, R.color.bg_disconnected_top_light_transparent); } else if (eipStatus.isBlocking()) { setMainButtonEnabled(true); - mainButton.updateState(true, false, true); - colorBackgroundALittle(); - locationButton.setText(getString(R.string.no_location)); + mainButton.updateState(false, true); + locationButton.setText(R.string.no_location); locationButton.setLocationLoad(UNKNOWN); locationButton.showBridgeIndicator(false); locationButton.showRecommendedIndicator(false); mainDescription.setText(R.string.eip_state_connected); subDescription.setText(getString(R.string.eip_state_blocking, getString(R.string.app_name))); + background.setImageResource(R.drawable.bg_connecting); + animateState(R.drawable.state_connecting); + setActivityBarColor(R.color.bg_connecting_top, R.color.bg_connecting_top_light_transparent); } else { - locationButton.setText(activity.getString(R.string.vpn_button_turn_on)); + locationButton.setText(R.string.vpn_button_turn_on); setMainButtonEnabled(true); - mainButton.updateState(false, false, false); - greyscaleBackground(); + mainButton.updateState(false, false); locationButton.setLocationLoad(UNKNOWN); locationButton.showBridgeIndicator(false); String city = getPreferredCity(getContext()); locationButton.setText(city == null ? getString(R.string.gateway_selection_recommended_location) : city); locationButton.showRecommendedIndicator(false); - mainDescription.setText(R.string.eip_state_insecure); - subDescription.setText(R.string.connection_not_connected); - } - } - - private void showToast(Activity activity, String message, boolean vibrateLong) { - LayoutInflater inflater = getLayoutInflater(); - View layout = inflater.inflate(R.layout.custom_toast, - activity.findViewById(R.id.custom_toast_container)); - - AppCompatTextView text = layout.findViewById(R.id.text); - text.setText(message); - - Vibrator v = (Vibrator) activity.getSystemService(Context.VIBRATOR_SERVICE); - if (vibrateLong) { - v.vibrate(100); - v.vibrate(200); - } else { - v.vibrate(100); - } - - Toast toast = new Toast(activity.getApplicationContext()); - toast.setGravity(Gravity.BOTTOM, 0, convertDimensionToPx(this.getContext(), R.dimen.stdpadding)); - toast.setDuration(Toast.LENGTH_LONG); - toast.setView(layout); - toast.show(); - } - - private void showRetryToast(Activity activity) { - int nClosestGateway = gatewayOrder(); - String message = String.format("Server number " + nClosestGateway + " not reachable. Trying next gateway."); - showToast(activity, message, true ); - } + mainDescription.setText(R.string.eip_status_unsecured); + subDescription.setText(null); + background.setImageResource(R.drawable.bg_disconnected); - private void showConnectionTransitionLayout(boolean isConnecting) { - mainButton.updateState(true, isConnecting, false); - if (isConnecting) { - colorBackgroundALittle(); - } else { - greyscaleBackground(); + animateState(R.drawable.state_disconnected); + setActivityBarColor(R.color.bg_disconnected_top, R.color.bg_disconnected_top_light_transparent); } } - private boolean isOpenVpnRunningWithoutNetwork() { - boolean isRunning = false; + private void animateState(@DrawableRes int drawableRes) { + @DrawableRes int lastDrawableId; try { - isRunning = eipStatus.getLevel() == LEVEL_NONETWORK && - mService.isVpnRunning(); - } catch (Exception e) { - //eat me - e.printStackTrace(); - } - - return isRunning; - } - - private void bindOpenVpnService() { - Activity activity = getActivity(); - if (activity == null) { - Log.e(TAG, "activity is null when binding OpenVpn"); - return; - } - - Intent intent = new Intent(activity, OpenVPNService.class); - intent.setAction(OpenVPNService.START_SERVICE); - activity.bindService(intent, openVpnConnection, Context.BIND_AUTO_CREATE); - - } - - private void greyscaleBackground() { - if (BuildConfig.use_color_filter) { - ColorMatrix matrix = new ColorMatrix(); - matrix.setSaturation(0); - ColorMatrixColorFilter cf = new ColorMatrixColorFilter(matrix); - background.setColorFilter(cf); - background.setImageAlpha(255); - } - } + lastDrawableId = (int) stateView.getTag(); + if (lastDrawableId == drawableRes) { + return; + } - private void colorBackgroundALittle() { - if (BuildConfig.use_color_filter) { - background.setColorFilter(null); - background.setImageAlpha(144); - } - } + Drawable lastDrawable = ContextCompat.getDrawable(getContext(), lastDrawableId); + if (lastDrawable instanceof Animatable && ((Animatable) lastDrawable).isRunning()) { + pendingAnimationState = drawableRes; + } - private void colorBackground() { - if (BuildConfig.use_color_filter) { - background.setColorFilter(null); - background.setImageAlpha(210); + } catch (NullPointerException | ClassCastException e) { + // eat me + } + + + stateView.setImageResource(drawableRes); + stateView.setTag(drawableRes); + if (stateView.getDrawable() instanceof Animatable) { + Animatable animatedDrawable = (Animatable) stateView.getDrawable(); + AnimatedVectorDrawableCompat.registerAnimationCallback(stateView.getDrawable(), new AnimationCallback() { + @Override + public void onAnimationEnd(Drawable drawable) { + super.onAnimationEnd(drawable); + if (!isResumed()) { + return; + } + if (pendingAnimationState != 0) { + int newAnimationRes = pendingAnimationState; + pendingAnimationState = 0; + animateState(newAnimationRes); + } else if (drawable instanceof Animatable){ + ((Animatable) drawable).start(); + } + } + }); + animatedDrawable.start(); } } private void updateInvalidVpnCertificate() { + eipStatus.setUpdatingVpnCert(true); ProviderAPICommand.execute(getContext(), UPDATE_INVALID_VPN_CERTIFICATE, provider); } @@ -591,20 +616,6 @@ public class EipFragment extends Fragment implements Observer { } } - private class EipFragmentServiceConnection implements ServiceConnection { - @Override - public void onServiceConnected(ComponentName className, - IBinder service) { - mService = IOpenVPNServiceInternal.Stub.asInterface(service); - handleNewState(); - } - - @Override - public void onServiceDisconnected(ComponentName arg0) { - mService = null; - } - } - public void showDonationReminderDialog() { try { FragmentTransaction fragmentTransaction = new FragmentManagerEnhanced( diff --git a/app/src/main/java/se/leap/bitmaskclient/base/fragments/ExcludeAppsFragment.java b/app/src/main/java/se/leap/bitmaskclient/base/fragments/ExcludeAppsFragment.java index 1574dbb03f9c57420d6d8db9dcd33d1a4a19b0c3..98c2e4381d3c343322f51e2a7da5b0f64c985c55 100644 --- a/app/src/main/java/se/leap/bitmaskclient/base/fragments/ExcludeAppsFragment.java +++ b/app/src/main/java/se/leap/bitmaskclient/base/fragments/ExcludeAppsFragment.java @@ -312,7 +312,7 @@ public class ExcludeAppsFragment extends Fragment implements AdapterView.OnItemC mListView.setOnItemClickListener(this); mListView.setEmptyView(v.findViewById(R.id.loading_container)); - ViewHelper.setActionBarTitle(this, exclude_apps_fragment_title); + ViewHelper.setActionBarSubtitle(this, exclude_apps_fragment_title); new Thread(() -> mListAdapter.populateList(getActivity())).start(); diff --git a/app/src/main/java/se/leap/bitmaskclient/base/fragments/GatewaySelectionFragment.java b/app/src/main/java/se/leap/bitmaskclient/base/fragments/GatewaySelectionFragment.java index f2c3b2d6f5ef24c7ff71a2c791849f349c7f5fba..749ffd9fc34d97349f9ba5d7908fdf3d6e2a89c4 100644 --- a/app/src/main/java/se/leap/bitmaskclient/base/fragments/GatewaySelectionFragment.java +++ b/app/src/main/java/se/leap/bitmaskclient/base/fragments/GatewaySelectionFragment.java @@ -51,16 +51,15 @@ import se.leap.bitmaskclient.eip.GatewaysManager; import static android.content.Context.MODE_PRIVATE; import static android.view.View.GONE; -import static android.view.View.INVISIBLE; import static android.view.View.VISIBLE; -import static de.blinkt.openvpn.core.connection.Connection.TransportType.OBFS4; import static de.blinkt.openvpn.core.connection.Connection.TransportType.OPENVPN; +import static de.blinkt.openvpn.core.connection.Connection.TransportType.PT; import static se.leap.bitmaskclient.base.MainActivity.ACTION_SHOW_VPN_FRAGMENT; import static se.leap.bitmaskclient.base.models.Constants.SHARED_PREFERENCES; import static se.leap.bitmaskclient.base.models.Constants.USE_BRIDGES; import static se.leap.bitmaskclient.base.utils.PreferenceHelper.getUseBridges; import static se.leap.bitmaskclient.base.utils.PreferenceHelper.useBridges; -import static se.leap.bitmaskclient.base.utils.ViewHelper.setActionBarTitle; +import static se.leap.bitmaskclient.base.utils.ViewHelper.setActionBarSubtitle; interface LocationListSelectionListener { void onLocationManuallySelected(Location location); @@ -90,16 +89,16 @@ public class GatewaySelectionFragment extends Fragment implements Observer, Loca super.onCreate(savedInstanceState); gatewaysManager = new GatewaysManager(getContext()); eipStatus = EipStatus.getInstance(); - eipStatus.addObserver(this); preferences = getContext().getSharedPreferences(SHARED_PREFERENCES, MODE_PRIVATE); - selectedTransport = getUseBridges(preferences) ? OBFS4 : OPENVPN; - preferences.registerOnSharedPreferenceChangeListener(this); } @Override public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) { // Inflate the layout for this fragment + selectedTransport = getUseBridges(preferences) ? PT : OPENVPN; + preferences.registerOnSharedPreferenceChangeListener(this); + eipStatus.addObserver(this); return inflater.inflate(R.layout.f_gateway_selection, container, false); } @@ -109,7 +108,7 @@ public class GatewaySelectionFragment extends Fragment implements Observer, Loca initRecyclerView(); initRecommendedLocationEntry(); initBridgesHint(view); - setActionBarTitle(this, R.string.gateway_selection_title); + setActionBarSubtitle(this, R.string.gateway_selection_title); } @Override @@ -211,7 +210,7 @@ public class GatewaySelectionFragment extends Fragment implements Observer, Loca public void onSharedPreferenceChanged(SharedPreferences sharedPreferences, String key) { if (key.equals(USE_BRIDGES)) { boolean showBridges = getUseBridges(sharedPreferences); - selectedTransport = showBridges ? OBFS4 : OPENVPN; + selectedTransport = showBridges ? PT : OPENVPN; gatewaysManager.updateTransport(selectedTransport); locationListAdapter.updateTransport(selectedTransport, gatewaysManager); bridgesHint.setVisibility(showBridges ? VISIBLE : GONE); diff --git a/app/src/main/java/se/leap/bitmaskclient/base/fragments/LogFragment.java b/app/src/main/java/se/leap/bitmaskclient/base/fragments/LogFragment.java index 6f0f29ef6b5e71cd2f4c29406299dcd6600ec1a4..8f73595dc71747945c78186c5e34aef0b705beca 100644 --- a/app/src/main/java/se/leap/bitmaskclient/base/fragments/LogFragment.java +++ b/app/src/main/java/se/leap/bitmaskclient/base/fragments/LogFragment.java @@ -5,6 +5,10 @@ package se.leap.bitmaskclient.base.fragments; +import static de.blinkt.openvpn.core.OpenVPNService.humanReadableByteCount; +import static se.leap.bitmaskclient.R.string.log_fragment_title; +import static se.leap.bitmaskclient.base.utils.ViewHelper.setActionBarSubtitle; + import android.animation.Animator; import android.animation.AnimatorListenerAdapter; import android.animation.ObjectAnimator; @@ -59,10 +63,6 @@ import de.blinkt.openvpn.core.VpnStatus.StateListener; import se.leap.bitmaskclient.R; import se.leap.bitmaskclient.base.models.Constants; -import static de.blinkt.openvpn.core.OpenVPNService.humanReadableByteCount; -import static se.leap.bitmaskclient.R.string.log_fragment_title; -import static se.leap.bitmaskclient.base.utils.ViewHelper.setActionBarTitle; - public class LogFragment extends ListFragment implements StateListener, SeekBar.OnSeekBarChangeListener, RadioGroup.OnCheckedChangeListener, VpnStatus.ByteCountListener { public static final String TAG = LogFragment.class.getSimpleName(); private static final String LOGTIMEFORMAT = "logtimeformat"; @@ -533,7 +533,7 @@ public class LogFragment extends ListFragment implements StateListener, SeekBar. if (mShowOptionsLayout) mOptionsLayout.setVisibility(View.VISIBLE); - setActionBarTitle(this, log_fragment_title); + setActionBarSubtitle(this, log_fragment_title); return v; } @@ -557,7 +557,6 @@ public class LogFragment extends ListFragment implements StateListener, SeekBar. @Override public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); - } diff --git a/app/src/main/java/se/leap/bitmaskclient/base/fragments/MainActivityErrorDialog.java b/app/src/main/java/se/leap/bitmaskclient/base/fragments/MainActivityErrorDialog.java index 27d61a690f28f28ff0da32d3edf68873d7534f3d..ae25c61c6b92b93281597849a8ed7cf7e930eae5 100644 --- a/app/src/main/java/se/leap/bitmaskclient/base/fragments/MainActivityErrorDialog.java +++ b/app/src/main/java/se/leap/bitmaskclient/base/fragments/MainActivityErrorDialog.java @@ -16,8 +16,22 @@ */ package se.leap.bitmaskclient.base.fragments; +import static se.leap.bitmaskclient.R.string.warning_option_try_ovpn; +import static se.leap.bitmaskclient.R.string.warning_option_try_pt; +import static se.leap.bitmaskclient.base.models.Constants.EIP_ACTION_STOP_BLOCKING_VPN; +import static se.leap.bitmaskclient.base.utils.PreferenceHelper.getPreferredCity; +import static se.leap.bitmaskclient.base.utils.PreferenceHelper.getUseBridges; +import static se.leap.bitmaskclient.base.utils.PreferenceHelper.setPreferredCity; +import static se.leap.bitmaskclient.base.utils.PreferenceHelper.useBridges; +import static se.leap.bitmaskclient.eip.EIP.EIPErrors.UNKNOWN; +import static se.leap.bitmaskclient.eip.EIP.EIPErrors.valueOf; +import static se.leap.bitmaskclient.eip.EIP.ERRORID; +import static se.leap.bitmaskclient.eip.EIP.ERRORS; +import static se.leap.bitmaskclient.providersetup.ProviderAPI.UPDATE_INVALID_VPN_CERTIFICATE; + import android.app.Dialog; import android.content.Context; +import android.content.Intent; import android.os.Bundle; import androidx.annotation.NonNull; @@ -31,20 +45,9 @@ import se.leap.bitmaskclient.R; import se.leap.bitmaskclient.base.models.Provider; import se.leap.bitmaskclient.eip.EIP; import se.leap.bitmaskclient.eip.EipCommand; +import se.leap.bitmaskclient.eip.VoidVpnService; import se.leap.bitmaskclient.providersetup.ProviderAPICommand; -import static se.leap.bitmaskclient.R.string.warning_option_try_ovpn; -import static se.leap.bitmaskclient.R.string.warning_option_try_pt; -import static se.leap.bitmaskclient.base.utils.PreferenceHelper.getPreferredCity; -import static se.leap.bitmaskclient.base.utils.PreferenceHelper.getUseBridges; -import static se.leap.bitmaskclient.base.utils.PreferenceHelper.setPreferredCity; -import static se.leap.bitmaskclient.base.utils.PreferenceHelper.useBridges; -import static se.leap.bitmaskclient.eip.EIP.EIPErrors.UNKNOWN; -import static se.leap.bitmaskclient.eip.EIP.EIPErrors.valueOf; -import static se.leap.bitmaskclient.eip.EIP.ERRORID; -import static se.leap.bitmaskclient.eip.EIP.ERRORS; -import static se.leap.bitmaskclient.providersetup.ProviderAPI.UPDATE_INVALID_VPN_CERTIFICATE; - /** * Implements an error dialog for the main activity. * @@ -56,6 +59,8 @@ public class MainActivityErrorDialog extends DialogFragment { final public static String TAG = "downloaded_failed_dialog"; final private static String KEY_REASON_TO_FAIL = "key reason to fail"; final private static String KEY_PROVIDER = "key provider"; + final private static String KEY_DOWNLOAD_ERROR = "key_download_error"; + final private static String KEY_ARGS = "key_args"; private String reasonToFail; private String[] args; private EIP.EIPErrors downloadError = UNKNOWN; @@ -124,7 +129,11 @@ public class MainActivityErrorDialog extends DialogFragment { builder.setNegativeButton(R.string.cancel, (dialog, id) -> {}); break; case NO_MORE_GATEWAYS: - builder.setNegativeButton(R.string.cancel, (dialog, id) -> {}); + builder.setNegativeButton(R.string.vpn_button_turn_off_blocking, (dialog, id) -> { + Intent stopVoidVpnIntent = new Intent (getContext(), VoidVpnService.class); + stopVoidVpnIntent.setAction(EIP_ACTION_STOP_BLOCKING_VPN); + getContext().startService(stopVoidVpnIntent); + }); if (getPreferredCity(applicationContext) != null) { builder.setPositiveButton(R.string.warning_option_try_best, (dialog, which) -> { new Thread(() -> { @@ -166,6 +175,10 @@ public class MainActivityErrorDialog extends DialogFragment { super.onSaveInstanceState(outState); outState.putString(KEY_REASON_TO_FAIL, reasonToFail); outState.putParcelable(KEY_PROVIDER, provider); + outState.putString(KEY_DOWNLOAD_ERROR, downloadError.toString()); + if (args != null) { + outState.putStringArray(KEY_ARGS, args); + } } private void restoreFromSavedInstance(Bundle savedInstanceState) { @@ -178,6 +191,12 @@ public class MainActivityErrorDialog extends DialogFragment { if (savedInstanceState.containsKey(KEY_REASON_TO_FAIL)) { this.reasonToFail = savedInstanceState.getString(KEY_REASON_TO_FAIL); } + if (savedInstanceState.containsKey(KEY_DOWNLOAD_ERROR)) { + this.downloadError = EIP.EIPErrors.valueOf(savedInstanceState.getString(KEY_DOWNLOAD_ERROR)); + } + if (savedInstanceState.containsKey(KEY_ARGS)) { + this.args = savedInstanceState.getStringArray(KEY_ARGS); + } } } diff --git a/app/src/main/java/se/leap/bitmaskclient/base/fragments/MotdFragment.java b/app/src/main/java/se/leap/bitmaskclient/base/fragments/MotdFragment.java new file mode 100644 index 0000000000000000000000000000000000000000..16834ab5e0de3421e35212d603cf0259a6e80646 --- /dev/null +++ b/app/src/main/java/se/leap/bitmaskclient/base/fragments/MotdFragment.java @@ -0,0 +1,103 @@ +package se.leap.bitmaskclient.base.fragments; + +import static se.leap.bitmaskclient.base.MainActivity.ACTION_SHOW_VPN_FRAGMENT; +import static se.leap.bitmaskclient.base.models.Constants.EXTRA_MOTD_MSG; + +import android.content.Context; +import android.content.Intent; +import android.os.Bundle; +import android.text.Html; +import android.text.TextUtils; +import android.text.method.LinkMovementMethod; +import android.util.Log; +import android.view.LayoutInflater; +import android.view.View; +import android.view.ViewGroup; + +import androidx.annotation.NonNull; +import androidx.annotation.Nullable; +import androidx.appcompat.widget.AppCompatImageButton; +import androidx.appcompat.widget.AppCompatTextView; +import androidx.fragment.app.Fragment; + +import java.util.Locale; + +import de.blinkt.openvpn.core.VpnStatus; +import motd.IMessage; +import motd.Motd; +import se.leap.bitmaskclient.base.MainActivity; +import se.leap.bitmaskclient.databinding.FMotdBinding; + + +public class MotdFragment extends Fragment { + + private static final String TAG = MotdFragment.class.getSimpleName(); + private IMessage message; + FMotdBinding binding; + AppCompatTextView messageView; + AppCompatImageButton nextButton; + + public MotdFragment() { + // Required empty public constructor + } + + @Override + public void onCreate(Bundle savedInstanceState) { + super.onCreate(savedInstanceState); + if (getArguments() != null) { + String messageString = getArguments().getString(EXTRA_MOTD_MSG); + if (messageString != null) { + Log.d(TAG, "MotdFragment received: " + messageString); + message = Motd.newMessage(messageString); + } + } + } + + @Override + public View onCreateView(LayoutInflater inflater, ViewGroup container, + Bundle savedInstanceState) { + // Inflate the layout for this fragment + binding = FMotdBinding.inflate(getLayoutInflater()); + return binding.getRoot(); + } + + @Override + public void onViewCreated(@NonNull View view, @Nullable @org.jetbrains.annotations.Nullable Bundle savedInstanceState) { + super.onViewCreated(view, savedInstanceState); + messageView = binding.motdContent; + nextButton = binding.nextBtn; + String currentLang = Locale.getDefault().getLanguage(); + String text = message.getLocalizedText(currentLang); + if (TextUtils.isEmpty(text)) { + text = message.getLocalizedText("en"); + } + + if (TextUtils.isEmpty(text)) { + String error = "Message of the day cannot be shown. Unsupported app language and unknown default langauge."; + Log.e(TAG, error); + VpnStatus.logError(error); + showVpnFragment(view.getContext()); + return; + } + + Log.d(TAG, "set motd text: " + text); + messageView.setText(Html.fromHtml(text)); + messageView.setMovementMethod(LinkMovementMethod.getInstance()); + nextButton.setOnClickListener(v -> { + showVpnFragment(v.getContext()); + }); + + } + + private void showVpnFragment(Context context) { + try { + Intent intent = new Intent(context, MainActivity.class); + intent.setFlags(Intent.FLAG_ACTIVITY_SINGLE_TOP | Intent.FLAG_ACTIVITY_CLEAR_TOP); + intent.setAction(ACTION_SHOW_VPN_FRAGMENT); + context.startActivity(intent); + } catch (NullPointerException npe) { + npe.printStackTrace(); + } + + } +} \ No newline at end of file diff --git a/app/src/main/java/se/leap/bitmaskclient/base/fragments/NavigationDrawerFragment.java b/app/src/main/java/se/leap/bitmaskclient/base/fragments/NavigationDrawerFragment.java index ae9613666b8ea2ef75635da337c7595bc37914b2..68435fec6cad061b684b660195c8a82bcd4ebfde 100644 --- a/app/src/main/java/se/leap/bitmaskclient/base/fragments/NavigationDrawerFragment.java +++ b/app/src/main/java/se/leap/bitmaskclient/base/fragments/NavigationDrawerFragment.java @@ -1,5 +1,5 @@ /** - * Copyright (c) 2019 LEAP Encryption Access Project and contributers + * Copyright (c) 2021 LEAP Encryption Access Project and contributers * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -17,6 +17,20 @@ package se.leap.bitmaskclient.base.fragments; +import static android.content.Context.MODE_PRIVATE; +import static android.view.View.GONE; +import static android.view.View.VISIBLE; +import static se.leap.bitmaskclient.base.models.Constants.DONATION_URL; +import static se.leap.bitmaskclient.base.models.Constants.ENABLE_DONATION; +import static se.leap.bitmaskclient.base.models.Constants.PREFERRED_CITY; +import static se.leap.bitmaskclient.base.models.Constants.PROVIDER_KEY; +import static se.leap.bitmaskclient.base.models.Constants.REQUEST_CODE_SWITCH_PROVIDER; +import static se.leap.bitmaskclient.base.models.Constants.SHARED_PREFERENCES; +import static se.leap.bitmaskclient.base.utils.ConfigHelper.isDefaultBitmask; +import static se.leap.bitmaskclient.base.utils.PreferenceHelper.getPreferredCity; +import static se.leap.bitmaskclient.base.utils.PreferenceHelper.getSaveBattery; +import static se.leap.bitmaskclient.base.utils.PreferenceHelper.saveBattery; + import android.app.Activity; import android.content.Intent; import android.content.SharedPreferences; @@ -32,8 +46,6 @@ import android.view.View; import android.view.ViewGroup; import androidx.annotation.NonNull; -import androidx.annotation.StringRes; -import androidx.appcompat.app.ActionBar; import androidx.appcompat.app.ActionBarDrawerToggle; import androidx.appcompat.app.AlertDialog; import androidx.appcompat.app.AppCompatActivity; @@ -57,21 +69,6 @@ import se.leap.bitmaskclient.eip.EipStatus; import se.leap.bitmaskclient.providersetup.ProviderListActivity; import se.leap.bitmaskclient.tethering.TetheringObservable; -import static android.content.Context.MODE_PRIVATE; -import static android.view.View.GONE; -import static android.view.View.VISIBLE; -import static se.leap.bitmaskclient.base.BitmaskApp.getRefWatcher; -import static se.leap.bitmaskclient.base.models.Constants.DONATION_URL; -import static se.leap.bitmaskclient.base.models.Constants.ENABLE_DONATION; -import static se.leap.bitmaskclient.base.models.Constants.PREFERRED_CITY; -import static se.leap.bitmaskclient.base.models.Constants.PROVIDER_KEY; -import static se.leap.bitmaskclient.base.models.Constants.REQUEST_CODE_SWITCH_PROVIDER; -import static se.leap.bitmaskclient.base.models.Constants.SHARED_PREFERENCES; -import static se.leap.bitmaskclient.base.utils.ConfigHelper.isDefaultBitmask; -import static se.leap.bitmaskclient.base.utils.PreferenceHelper.getPreferredCity; -import static se.leap.bitmaskclient.base.utils.PreferenceHelper.getSaveBattery; -import static se.leap.bitmaskclient.base.utils.PreferenceHelper.saveBattery; - /** * Fragment used for managing interactions for and presentation of a navigation drawer. * See the <a href="https://developer.android.com/design/patterns/navigation-drawer.html#Interaction"> @@ -174,7 +171,6 @@ public class NavigationDrawerFragment extends Fragment implements SharedPreferen this.drawerLayout.setDrawerShadow(R.drawable.drawer_shadow, GravityCompat.START); toolbar = this.drawerLayout.findViewById(R.id.toolbar); - setupActionBar(); setupEntries(); setupActionBarDrawerToggle(activity); @@ -235,7 +231,6 @@ public class NavigationDrawerFragment extends Fragment implements SharedPreferen Bundle arguments = new Bundle(); arguments.putParcelable(PROVIDER_KEY, currentProvider); fragment.setArguments(arguments); - hideActionBarSubTitle(); fragmentManager.replace(R.id.main_container, fragment, MainActivity.TAG); closeDrawer(); }); @@ -302,6 +297,10 @@ public class NavigationDrawerFragment extends Fragment implements SharedPreferen manualGatewaySelection.setOnClickListener(v -> { FragmentManagerEnhanced fragmentManager = new FragmentManagerEnhanced(getActivity().getSupportFragmentManager()); closeDrawer(); + Fragment current = fragmentManager.findFragmentByTag(MainActivity.TAG); + if (current instanceof GatewaySelectionFragment) { + return; + } Fragment fragment = new GatewaySelectionFragment(); fragmentManager.replace(R.id.main_container, fragment, MainActivity.TAG); }); @@ -346,15 +345,7 @@ public class NavigationDrawerFragment extends Fragment implements SharedPreferen } } - private ActionBar setupActionBar() { - AppCompatActivity activity = (AppCompatActivity) getActivity(); - activity.setSupportActionBar(toolbar); - final ActionBar actionBar = activity.getSupportActionBar(); - actionBar.setDisplayHomeAsUpEnabled(true); - actionBar.setHomeButtonEnabled(true); - actionBar.setDisplayShowTitleEnabled(true); - return actionBar; - } + @NonNull private void closeDrawerWithDelay() { @@ -415,14 +406,6 @@ public class NavigationDrawerFragment extends Fragment implements SharedPreferen drawerToggle.onConfigurationChanged(newConfig); } - @Override - public void onCreateOptionsMenu(Menu menu, MenuInflater inflater) { - if (drawerLayout != null && isDrawerOpen()) { - showGlobalContextActionBar(); - } - super.onCreateOptionsMenu(menu, inflater); - } - @Override public boolean onOptionsItemSelected(MenuItem item) { if (drawerToggle.onOptionsItemSelected(item)) { @@ -434,31 +417,9 @@ public class NavigationDrawerFragment extends Fragment implements SharedPreferen @Override public void onDestroy() { super.onDestroy(); - getRefWatcher(getActivity()).watch(this); preferences.unregisterOnSharedPreferenceChangeListener(this); } - /** - * Per the navigation drawer design guidelines, updates the action bar to show the global app - * 'context', rather than just what's in the current screen. - */ - private void showGlobalContextActionBar() { - ActionBar actionBar = getActionBar(); - actionBar.setDisplayShowTitleEnabled(true); - actionBar.setTitle(R.string.app_name); - } - - private ActionBar getActionBar() { - return ((AppCompatActivity) getActivity()).getSupportActionBar(); - } - - private void hideActionBarSubTitle() { - ActionBar actionBar = getActionBar(); - if (actionBar != null) { - actionBar.setSubtitle(null); - } - } - public void refresh() { Provider currentProvider = ProviderObservable.getInstance().getCurrentProvider(); account.setText(currentProvider.getName()); diff --git a/app/src/main/java/se/leap/bitmaskclient/base/fragments/ObfuscationProxyDialog.java b/app/src/main/java/se/leap/bitmaskclient/base/fragments/ObfuscationProxyDialog.java new file mode 100644 index 0000000000000000000000000000000000000000..2c0fdd69f31207a554ca549ead249b1dfc615854 --- /dev/null +++ b/app/src/main/java/se/leap/bitmaskclient/base/fragments/ObfuscationProxyDialog.java @@ -0,0 +1,94 @@ +package se.leap.bitmaskclient.base.fragments; + +import static android.view.View.GONE; +import static android.view.View.VISIBLE; + +import android.app.Dialog; +import android.os.Bundle; +import android.text.TextUtils; +import android.view.View; + +import androidx.annotation.NonNull; +import androidx.annotation.Nullable; +import androidx.appcompat.app.AlertDialog; +import androidx.appcompat.app.AppCompatDialogFragment; +import androidx.appcompat.widget.AppCompatButton; +import androidx.appcompat.widget.AppCompatEditText; + +import se.leap.bitmaskclient.base.utils.ConfigHelper.ObfsVpnHelper; +import se.leap.bitmaskclient.base.utils.PreferenceHelper; +import se.leap.bitmaskclient.base.views.IconSwitchEntry; +import se.leap.bitmaskclient.databinding.DObfuscationProxyBinding; +import se.leap.bitmaskclient.eip.GatewaysManager; + +public class ObfuscationProxyDialog extends AppCompatDialogFragment { + public static final String TAG = ObfuscationProxyDialog.class.getSimpleName(); + DObfuscationProxyBinding binding; + AppCompatEditText ipField; + AppCompatEditText portField; + AppCompatEditText certificateField; + AppCompatButton saveButton; + AppCompatButton useDefaultsButton; + AppCompatButton cancelButton; + IconSwitchEntry kcpSwitch; + + @NonNull + @Override + public Dialog onCreateDialog(@Nullable Bundle savedInstanceState) { + super.onCreate(savedInstanceState); + binding = DObfuscationProxyBinding.inflate(getLayoutInflater()); + View view = binding.getRoot(); + AlertDialog.Builder builder = new AlertDialog.Builder(getActivity()); + builder.setView(view); + ipField = binding.ipField; + portField = binding.portField; + certificateField = binding.certField; + saveButton = binding.buttonSave; + useDefaultsButton = binding.buttonDefaults; + cancelButton = binding.buttonCancel; + kcpSwitch = binding.kcpSwitch; + + ipField.setText(PreferenceHelper.getObfuscationPinningIP(getContext())); + portField.setText(PreferenceHelper.getObfuscationPinningPort(getContext())); + certificateField.setText(PreferenceHelper.getObfuscationPinningCert(getContext())); + kcpSwitch.setChecked(PreferenceHelper.getObfuscationPinningKCP(getContext())); + + GatewaysManager gatewaysManager = new GatewaysManager(getContext()); + + saveButton.setOnClickListener(v -> { + String ip = TextUtils.isEmpty(ipField.getText()) ? null : ipField.getText().toString(); + PreferenceHelper.setObfuscationPinningIP(v.getContext(), ip); + String port = TextUtils.isEmpty(portField.getText()) ? null : portField.getText().toString(); + PreferenceHelper.setObfuscationPinningPort(v.getContext(), port); + String cert = TextUtils.isEmpty(certificateField.getText()) ? null : certificateField.getText().toString(); + PreferenceHelper.setObfuscationPinningCert(v.getContext(), cert); + PreferenceHelper.setObfuscationPinningKCP(v.getContext(), kcpSwitch.isChecked()); + PreferenceHelper.setUseObfuscationPinning(v.getContext(), ip != null && port != null && cert != null); + PreferenceHelper.setObfuscationPinningGatewayLocation(v.getContext(), gatewaysManager.getLocationNameForIP(ip, v.getContext())); + dismiss(); + }); + + useDefaultsButton.setVisibility(ObfsVpnHelper.hasObfuscationPinningDefaults() ? VISIBLE : GONE); + useDefaultsButton.setOnClickListener(v -> { + ipField.setText(ObfsVpnHelper.obfsvpnIP()); + portField.setText(ObfsVpnHelper.obfsvpnPort()); + certificateField.setText(ObfsVpnHelper.obfsvpnCert()); + kcpSwitch.setChecked(ObfsVpnHelper.useKcp()); + }); + + cancelButton.setOnClickListener(v -> { + boolean allowPinning = !TextUtils.isEmpty(ipField.getText()) && !TextUtils.isEmpty(portField.getText()) && !TextUtils.isEmpty(certificateField.getText()); + PreferenceHelper.setUseObfuscationPinning( + v.getContext(), allowPinning); + dismiss(); + }); + + return builder.create(); + } + + @Override + public void onDestroyView() { + super.onDestroyView(); + binding = null; + } +} diff --git a/app/src/main/java/se/leap/bitmaskclient/base/fragments/SettingsFragment.java b/app/src/main/java/se/leap/bitmaskclient/base/fragments/SettingsFragment.java index be2fe4f41474c11422551ae38414da5d4716c684..40bc256cae84aba144bcb74848251a28b127ea69 100644 --- a/app/src/main/java/se/leap/bitmaskclient/base/fragments/SettingsFragment.java +++ b/app/src/main/java/se/leap/bitmaskclient/base/fragments/SettingsFragment.java @@ -1,12 +1,42 @@ package se.leap.bitmaskclient.base.fragments; +import static android.content.Context.MODE_PRIVATE; +import static android.view.View.GONE; +import static android.view.View.VISIBLE; +import static se.leap.bitmaskclient.R.string.advanced_settings; +import static se.leap.bitmaskclient.base.models.Constants.GATEWAY_PINNING; +import static se.leap.bitmaskclient.base.models.Constants.PREFER_UDP; +import static se.leap.bitmaskclient.base.models.Constants.SHARED_PREFERENCES; +import static se.leap.bitmaskclient.base.models.Constants.USE_BRIDGES; +import static se.leap.bitmaskclient.base.models.Constants.USE_IPv6_FIREWALL; +import static se.leap.bitmaskclient.base.models.Constants.USE_OBFUSCATION_PINNING; +import static se.leap.bitmaskclient.base.utils.ConfigHelper.ObfsVpnHelper.useObfsVpn; +import static se.leap.bitmaskclient.base.utils.ConfigHelper.isCalyxOSWithTetheringSupport; +import static se.leap.bitmaskclient.base.utils.PreferenceHelper.allowExperimentalTransports; +import static se.leap.bitmaskclient.base.utils.PreferenceHelper.getPreferUDP; +import static se.leap.bitmaskclient.base.utils.PreferenceHelper.getShowAlwaysOnDialog; +import static se.leap.bitmaskclient.base.utils.PreferenceHelper.getUseBridges; +import static se.leap.bitmaskclient.base.utils.PreferenceHelper.getUseSnowflake; +import static se.leap.bitmaskclient.base.utils.PreferenceHelper.hasSnowflakePrefs; +import static se.leap.bitmaskclient.base.utils.PreferenceHelper.preferUDP; +import static se.leap.bitmaskclient.base.utils.PreferenceHelper.setAllowExperimentalTransports; +import static se.leap.bitmaskclient.base.utils.PreferenceHelper.setUseObfuscationPinning; +import static se.leap.bitmaskclient.base.utils.PreferenceHelper.useBridges; +import static se.leap.bitmaskclient.base.utils.PreferenceHelper.useObfuscationPinning; +import static se.leap.bitmaskclient.base.utils.PreferenceHelper.useSnowflake; +import static se.leap.bitmaskclient.base.utils.ViewHelper.setActionBarSubtitle; + +import android.app.AlertDialog; +import android.content.Context; import android.content.Intent; import android.content.SharedPreferences; import android.os.Build; import android.os.Bundle; +import android.text.TextUtils; import android.view.LayoutInflater; import android.view.View; import android.view.ViewGroup; +import android.widget.EditText; import android.widget.Toast; import androidx.annotation.NonNull; @@ -18,6 +48,7 @@ import androidx.fragment.app.FragmentTransaction; import java.util.Set; import de.blinkt.openvpn.core.VpnStatus; +import se.leap.bitmaskclient.BuildConfig; import se.leap.bitmaskclient.R; import se.leap.bitmaskclient.base.FragmentManagerEnhanced; import se.leap.bitmaskclient.base.MainActivity; @@ -28,24 +59,6 @@ import se.leap.bitmaskclient.base.views.IconTextEntry; import se.leap.bitmaskclient.eip.EipCommand; import se.leap.bitmaskclient.firewall.FirewallManager; -import static android.content.Context.MODE_PRIVATE; -import static android.view.View.GONE; -import static android.view.View.VISIBLE; -import static se.leap.bitmaskclient.R.string.advanced_settings; -import static se.leap.bitmaskclient.base.models.Constants.PREFER_UDP; -import static se.leap.bitmaskclient.base.models.Constants.SHARED_PREFERENCES; -import static se.leap.bitmaskclient.base.models.Constants.USE_BRIDGES; -import static se.leap.bitmaskclient.base.models.Constants.USE_IPv6_FIREWALL; -import static se.leap.bitmaskclient.base.utils.PreferenceHelper.getPreferUDP; -import static se.leap.bitmaskclient.base.utils.PreferenceHelper.getShowAlwaysOnDialog; -import static se.leap.bitmaskclient.base.utils.PreferenceHelper.getUseBridges; -import static se.leap.bitmaskclient.base.utils.PreferenceHelper.getUseSnowflake; -import static se.leap.bitmaskclient.base.utils.PreferenceHelper.hasSnowflakePrefs; -import static se.leap.bitmaskclient.base.utils.PreferenceHelper.preferUDP; -import static se.leap.bitmaskclient.base.utils.PreferenceHelper.useBridges; -import static se.leap.bitmaskclient.base.utils.PreferenceHelper.useSnowflake; -import static se.leap.bitmaskclient.base.utils.ViewHelper.setActionBarTitle; - public class SettingsFragment extends Fragment implements SharedPreferences.OnSharedPreferenceChangeListener { private FirewallManager firewallManager; @@ -74,7 +87,10 @@ public class SettingsFragment extends Fragment implements SharedPreferences.OnSh initUseSnowflakeEntry(view); initFirewallEntry(view); initTetheringEntry(view); - setActionBarTitle(this, advanced_settings); + initGatewayPinningEntry(view); + initExperimentalTransportsEntry(view); + initObfuscationPinningEntry(view); + setActionBarSubtitle(this, advanced_settings); return view; } @@ -158,19 +174,17 @@ public class SettingsFragment extends Fragment implements SharedPreferences.OnSh } private void initExcludeAppsEntry(View rootView) { - if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) { - IconTextEntry excludeApps = rootView.findViewById(R.id.exclude_apps); - excludeApps.setVisibility(VISIBLE); - Set<String> apps = PreferenceHelper.getExcludedApps(this.getContext()); - if (apps != null) { - updateExcludeAppsSubtitle(excludeApps, apps.size()); - } - FragmentManagerEnhanced fragmentManager = new FragmentManagerEnhanced(getActivity().getSupportFragmentManager()); - excludeApps.setOnClickListener((buttonView) -> { - Fragment fragment = new ExcludeAppsFragment(); - fragmentManager.replace(R.id.main_container, fragment, MainActivity.TAG); - }); + IconTextEntry excludeApps = rootView.findViewById(R.id.exclude_apps); + excludeApps.setVisibility(VISIBLE); + Set<String> apps = PreferenceHelper.getExcludedApps(this.getContext()); + if (apps != null) { + updateExcludeAppsSubtitle(excludeApps, apps.size()); } + FragmentManagerEnhanced fragmentManager = new FragmentManagerEnhanced(getActivity().getSupportFragmentManager()); + excludeApps.setOnClickListener((buttonView) -> { + Fragment fragment = new ExcludeAppsFragment(); + fragmentManager.replace(R.id.main_container, fragment, MainActivity.TAG); + }); } private void updateExcludeAppsSubtitle(IconTextEntry excludeApps, int number) { @@ -202,11 +216,111 @@ public class SettingsFragment extends Fragment implements SharedPreferences.OnSh private void initTetheringEntry(View rootView) { tethering = rootView.findViewById(R.id.tethering); + + if (isCalyxOSWithTetheringSupport(this.getContext())) { + tethering.setVisibility(GONE); + return; + } + tethering.setOnClickListener((buttonView) -> { showTetheringAlert(); }); } + private void initGatewayPinningEntry(View rootView) { + IconTextEntry gatewayPinning = rootView.findViewById(R.id.gateway_pinning); + if (!BuildConfig.BUILD_TYPE.equals("debug")) { + gatewayPinning.setVisibility(GONE); + return; + } + Context context = this.getContext(); + if (context == null) { + return; + } + String pinnedGateway = PreferenceHelper.getPinnedGateway(rootView.getContext()); + gatewayPinning.setSubtitle(pinnedGateway != null ? pinnedGateway : "Connect to a specific Gateway for debugging purposes"); + + gatewayPinning.setOnClickListener(v -> { + EditText gatewayPinningEditText = new EditText(rootView.getContext()); + gatewayPinningEditText.setText(pinnedGateway); + new AlertDialog.Builder(context) + .setTitle("Gateway Pinning") + .setMessage("Enter the domain name of the gateway") + .setView(gatewayPinningEditText) + .setPositiveButton(android.R.string.ok, (dialogInterface, i) -> { + if (gatewayPinningEditText.getText() != null) { + String editTextInput = gatewayPinningEditText.getText().toString(); + if (!TextUtils.isEmpty(editTextInput)) { + PreferenceHelper.setPreferredCity(context, null); + PreferenceHelper.pinGateway(context, editTextInput); + } else { + PreferenceHelper.pinGateway(context, null); + } + } + }) + .setNegativeButton(android.R.string.cancel, null) + .create().show(); + }); + } + + public void initObfuscationPinningEntry(View rootView) { + IconSwitchEntry obfuscationPinning = rootView.findViewById(R.id.obfuscation_proxy_pinning); + if (!BuildConfig.BUILD_TYPE.equals("debug") || !useObfsVpn()) { + obfuscationPinning.setVisibility(GONE); + return; + } + obfuscationPinning.setVisibility(VISIBLE); + boolean useBridges = getUseBridges(getContext()); + obfuscationPinning.setEnabled(useBridges); + obfuscationPinning.setSubtitle(useBridges ? "Connect to a specific obfuscation proxy for debugging purposes" : "Enable Bridges to use this option"); + obfuscationPinning.setChecked(useObfuscationPinning(getContext())); + obfuscationPinning.setOnCheckedChangeListener((buttonView, isChecked) -> { + if (!buttonView.isPressed()) { + return; + } + if (!isChecked) { + setUseObfuscationPinning(getContext(), false); + } else { + showObfuscationPinningDialog(); + } + }); + obfuscationPinning.setOnClickListener(v -> { + if (obfuscationPinning.isChecked()) { + showObfuscationPinningDialog(); + } + }); + } + + public void showObfuscationPinningDialog() { + try { + FragmentTransaction fragmentTransaction = new FragmentManagerEnhanced( + getActivity().getSupportFragmentManager()).removePreviousFragment( + ObfuscationProxyDialog.TAG); + DialogFragment newFragment = new ObfuscationProxyDialog(); + newFragment.setCancelable(false); + newFragment.show(fragmentTransaction, ObfuscationProxyDialog.TAG); + } catch (IllegalStateException | NullPointerException e) { + e.printStackTrace(); + } + } + + public void initExperimentalTransportsEntry(View rootView) { + IconSwitchEntry experimentalTransports = rootView.findViewById(R.id.experimental_transports); + if (useObfsVpn() && ProviderObservable.getInstance().getCurrentProvider().supportsExperimentalPluggableTransports()) { + experimentalTransports.setVisibility(VISIBLE); + experimentalTransports.setChecked(allowExperimentalTransports(this.getContext())); + experimentalTransports.setOnCheckedChangeListener((buttonView, isChecked) -> { + if (!buttonView.isPressed()) { + return; + } + setAllowExperimentalTransports(getContext(), isChecked); + }); + } else { + experimentalTransports.setVisibility(GONE); + } + + } + public void showTetheringAlert() { try { @@ -245,6 +359,12 @@ public class SettingsFragment extends Fragment implements SharedPreferences.OnSh initPreferUDPEntry(rootView); } else if (key.equals(USE_IPv6_FIREWALL)) { initFirewallEntry(getView()); + } else if (key.equals(GATEWAY_PINNING)) { + initGatewayPinningEntry(rootView); + } + + if (key.equals(USE_OBFUSCATION_PINNING) || key.equals(USE_BRIDGES)) { + initObfuscationPinningEntry(rootView); } } diff --git a/app/src/main/java/se/leap/bitmaskclient/base/fragments/TetheringDialog.java b/app/src/main/java/se/leap/bitmaskclient/base/fragments/TetheringDialog.java index 675f1a61f7f5477918dd4bd69950fb404333edd2..e747d5b4c253407c636821e6252c07c222ef782b 100644 --- a/app/src/main/java/se/leap/bitmaskclient/base/fragments/TetheringDialog.java +++ b/app/src/main/java/se/leap/bitmaskclient/base/fragments/TetheringDialog.java @@ -209,10 +209,18 @@ public class TetheringDialog extends AppCompatDialogFragment implements Observer int endIndex = 0; if (matcher.matches()) { startIndex = matcher.start(2); - endIndex = startIndex + matcher.group(3).length(); + try { + endIndex = startIndex + matcher.group(3).length(); + } catch (NullPointerException npe) { + endIndex = -1; + } } systemSettingsMessage = systemSettingsMessage.replace("<b>", "").replace("</b>", ""); String wholeMessage = systemSettingsMessage + "\n\n" + tetheringMessage; + if (startIndex == -1 || endIndex == -1) { + Log.e(TAG, "Tethering string has wrong formatting!"); + return wholeMessage; + } Spannable spannable = new SpannableString(wholeMessage); spannable.setSpan(new ClickableSpan() { @Override diff --git a/app/src/main/java/se/leap/bitmaskclient/base/models/Constants.java b/app/src/main/java/se/leap/bitmaskclient/base/models/Constants.java index 468b1b0174fa724ba039ba728b4315e168329dfe..ee5bd2a79aa1c3519ea6f965176b5f217c12ed96 100644 --- a/app/src/main/java/se/leap/bitmaskclient/base/models/Constants.java +++ b/app/src/main/java/se/leap/bitmaskclient/base/models/Constants.java @@ -1,5 +1,5 @@ /** - * Copyright (c) 2020 LEAP Encryption Access Project and contributers + * Copyright (c) 2021 LEAP Encryption Access Project and contributers * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -43,9 +43,17 @@ public interface Constants { String PREFERRED_CITY = "preferred_city"; String USE_SNOWFLAKE = "use_snowflake"; String PREFER_UDP = "prefer_UDP"; + String GATEWAY_PINNING = "gateway_pinning"; + String ALLOW_EXPERIMENTAL_TRANSPORTS = "allow_experimental_transports"; + String USE_OBFUSCATION_PINNING = "use_obfuscation_pinning"; + String OBFUSCATION_PINNING_IP = "obfuscation_pinning_ip"; + String OBFUSCATION_PINNING_PORT = "obfuscation_pinning_port"; + String OBFUSCATION_PINNING_CERT = "obfuscation_pinning_cert"; + String OBFUSCATION_PINNING_KCP = "obfuscation_pinning_udp"; + String OBFUSCATION_PINNING_LOCATION = "obfuscation_pinning_location"; - ////////////////////////////////////////////// + ////////////////////////////////////////////// // REQUEST CODE CONSTANTS ///////////////////////////////////////////// @@ -69,6 +77,7 @@ public interface Constants { String ASK_TO_CANCEL_VPN = "ask_to_cancel_vpn"; + String EXTRA_MOTD_MSG = "extra_motd_message"; ////////////////////////////////////////////// @@ -106,6 +115,10 @@ public interface Constants { String PROVIDER_EIP_DEFINITION = "Constants.EIP_DEFINITION"; String PROVIDER_PROFILE_UUID = "Constants.PROVIDER_PROFILE_UUID"; String PROVIDER_PROFILE = "Constants.PROVIDER_PROFILE"; + String PROVIDER_MOTD = "Constants.PROVIDER_MOTD"; + String PROVIDER_MOTD_HASHES = "Constants.PROVIDER_MOTD_HASHES"; + String PROVIDER_MOTD_LAST_SEEN = "Constants.PROVIDER_MOTD_LAST_SEEN"; + String PROVIDER_MOTD_LAST_UPDATED = "Constants.PROVIDER_MOTD_LAST_UPDATED"; //////////////////////////////////////////////// // PRESHIPPED PROVIDER CONFIG @@ -162,6 +175,7 @@ public interface Constants { String IP_ADDRESS = "ip_address"; String IP_ADDRESS6 = "ip_address6"; String REMOTE = "remote"; + String SOCKS_PROXY = "socks-proxy"; String PORTS = "ports"; String PROTOCOLS = "protocols"; String UDP = "udp"; diff --git a/app/src/main/java/se/leap/bitmaskclient/base/models/FeatureVersionCode.java b/app/src/main/java/se/leap/bitmaskclient/base/models/FeatureVersionCode.java index 7b3f1888b907b1caf7aafebe9ecec3398a71781b..f7251acb7c69a831eba380277bcd4ff5d31ef587 100644 --- a/app/src/main/java/se/leap/bitmaskclient/base/models/FeatureVersionCode.java +++ b/app/src/main/java/se/leap/bitmaskclient/base/models/FeatureVersionCode.java @@ -3,4 +3,6 @@ package se.leap.bitmaskclient.base.models; public interface FeatureVersionCode { int RENAMED_EIP_IN_PREFERENCES = 132; int GEOIP_SERVICE = 148; + int CALYX_PROVIDER_LILYPAD_UPDATE = 165000; + int RISEUP_PROVIDER_LILYPAD_UPDATE = 165000; } diff --git a/app/src/main/java/se/leap/bitmaskclient/base/models/GatewayJson.java b/app/src/main/java/se/leap/bitmaskclient/base/models/GatewayJson.java new file mode 100644 index 0000000000000000000000000000000000000000..8aca58c6369906d16f30636406716cba29ec1951 --- /dev/null +++ b/app/src/main/java/se/leap/bitmaskclient/base/models/GatewayJson.java @@ -0,0 +1,61 @@ +package se.leap.bitmaskclient.base.models; + +import androidx.annotation.NonNull; + +import com.google.gson.Gson; +import com.google.gson.GsonBuilder; +import com.google.gson.annotations.SerializedName; + +import org.json.JSONObject; + +public class GatewayJson { + private String location; + @SerializedName(value = "ip_address") + private String ipAddress; + @SerializedName(value = "ip_address6") + private String ipAddress6; + private String host; + private Capabilities capabilities; + + public GatewayJson(String location, String ipAddress, String ipAddress6, String host, Capabilities capabilities) { + this.location = location; + this.ipAddress = ipAddress; + this.ipAddress6 = ipAddress6; + this.host = host; + this.capabilities = capabilities; + } + + @NonNull + @Override + public String toString() { + return new Gson().toJson(this); + } + + public static GatewayJson fromJson(JSONObject json) { + GsonBuilder builder = new GsonBuilder(); + return builder.create().fromJson(json.toString(), GatewayJson.class); + } + + public static class Capabilities { + private Boolean adblock; + @SerializedName(value = "filter_dns") + private Boolean filterDns; + private Boolean limited; + private Transport[] transport; + @SerializedName(value = "user_ips") + private Boolean userIps; + + public Capabilities(Boolean adblock, Boolean filterDns, Boolean limited, Transport[] transport, Boolean userIps) { + this.adblock = adblock; + this.filterDns = filterDns; + this.limited = limited; + this.transport = transport; + this.userIps = userIps; + } + @NonNull + @Override + public String toString() { + return new Gson().toJson(this); + } + } +} diff --git a/app/src/main/java/se/leap/bitmaskclient/base/models/Location.java b/app/src/main/java/se/leap/bitmaskclient/base/models/Location.java index 064f25c0cfbc0c2fb909c7f60988698ab621fe99..26f6b14a1ee6f8ce4bce30e39ec39dfca7403302 100644 --- a/app/src/main/java/se/leap/bitmaskclient/base/models/Location.java +++ b/app/src/main/java/se/leap/bitmaskclient/base/models/Location.java @@ -21,10 +21,7 @@ import androidx.annotation.NonNull; import java.util.Comparator; import java.util.HashMap; -import java.util.HashSet; -import java.util.function.ToDoubleFunction; -import de.blinkt.openvpn.core.connection.Connection; import de.blinkt.openvpn.core.connection.Connection.TransportType; public class Location implements Cloneable { @@ -50,27 +47,27 @@ public class Location implements Cloneable { } public boolean supportsTransport(TransportType transportType) { - return numberOfGateways.containsKey(transportType); + return numberOfGateways.containsKey(transportType.getMetaType()); } public void setAverageLoad(TransportType transportType, double load) { - averageLoad.put(transportType, load); + averageLoad.put(transportType.getMetaType(), load); } public double getAverageLoad(TransportType transportType) { - if (averageLoad.containsKey(transportType)) { - return averageLoad.get(transportType); + if (averageLoad.containsKey(transportType.getMetaType())) { + return averageLoad.get(transportType.getMetaType()); } return 0; } public void setNumberOfGateways(TransportType transportType, int numbers) { - numberOfGateways.put(transportType, numbers); + numberOfGateways.put(transportType.getMetaType(), numbers); } public int getNumberOfGateways(TransportType transportType) { - if (numberOfGateways.containsKey(transportType)) { - return numberOfGateways.get(transportType); + if (numberOfGateways.containsKey(transportType.getMetaType())) { + return numberOfGateways.get(transportType.getMetaType()); } return 0; } @@ -112,7 +109,7 @@ public class Location implements Cloneable { public static class SortByAverageLoad implements Comparator<Location> { TransportType transportType; public SortByAverageLoad(TransportType transportType) { - this.transportType = transportType; + this.transportType = transportType.getMetaType(); } @Override diff --git a/app/src/main/java/se/leap/bitmaskclient/base/models/Pair.java b/app/src/main/java/se/leap/bitmaskclient/base/models/Pair.java new file mode 100644 index 0000000000000000000000000000000000000000..e2ef4622f453cc4a258760a879b49acca6792492 --- /dev/null +++ b/app/src/main/java/se/leap/bitmaskclient/base/models/Pair.java @@ -0,0 +1,57 @@ +package se.leap.bitmaskclient.base.models; + +import java.util.Objects; + +/** + * Container to ease passing around a tuple of two objects. This object provides a sensible + * implementation of equals(), returning true if equals() is true on each of the contained + * objects. + */ +public class Pair<F, S> { + public final F first; + public final S second; + + /** + * Constructor for a Pair. + * + * @param first the first object in the Pair + * @param second the second object in the pair + */ + public Pair(F first, S second) { + this.first = first; + this.second = second; + } + + /** + * Checks the two objects for equality by delegating to their respective + * {@link Object#equals(Object)} methods. + * + * @param o the {@link Pair} to which this one is to be checked for equality + * @return true if the underlying objects of the Pair are both considered + * equal + */ + @Override + public boolean equals(Object o) { + if (!(o instanceof Pair)) { + return false; + } + Pair<?, ?> p = (Pair<?, ?>) o; + return Objects.equals(p.first, first) && Objects.equals(p.second, second); + } + + /** + * Compute a hash code using the hash codes of the underlying objects + * + * @return a hashcode of the Pair + */ + @Override + public int hashCode() { + return (first == null ? 0 : first.hashCode()) ^ (second == null ? 0 : second.hashCode()); + } + + @Override + public String toString() { + return "Pair{" + String.valueOf(first) + " " + String.valueOf(second) + "}"; + } + +} diff --git a/app/src/main/java/se/leap/bitmaskclient/base/models/Provider.java b/app/src/main/java/se/leap/bitmaskclient/base/models/Provider.java index 974aef80d1c2aa4758c5ccc99338c283a1d16982..53f864cf74cf54ec99493a9ef955d650ea96020c 100644 --- a/app/src/main/java/se/leap/bitmaskclient/base/models/Provider.java +++ b/app/src/main/java/se/leap/bitmaskclient/base/models/Provider.java @@ -16,9 +16,23 @@ */ package se.leap.bitmaskclient.base.models; +import static de.blinkt.openvpn.core.connection.Connection.TransportType.OBFS4; +import static de.blinkt.openvpn.core.connection.Connection.TransportType.OBFS4_KCP; +import static se.leap.bitmaskclient.base.models.Constants.CAPABILITIES; +import static se.leap.bitmaskclient.base.models.Constants.GATEWAYS; +import static se.leap.bitmaskclient.base.models.Constants.LOCATIONS; +import static se.leap.bitmaskclient.base.models.Constants.PROVIDER_ALLOWED_REGISTERED; +import static se.leap.bitmaskclient.base.models.Constants.PROVIDER_ALLOW_ANONYMOUS; +import static se.leap.bitmaskclient.base.models.Constants.TRANSPORT; +import static se.leap.bitmaskclient.base.models.Constants.TYPE; +import static se.leap.bitmaskclient.base.utils.ConfigHelper.ObfsVpnHelper.useObfsVpn; +import static se.leap.bitmaskclient.providersetup.ProviderAPI.ERRORS; + import android.os.Parcel; import android.os.Parcelable; +import androidx.annotation.NonNull; + import com.google.gson.Gson; import org.json.JSONArray; @@ -27,17 +41,14 @@ import org.json.JSONObject; import java.net.MalformedURLException; import java.net.URL; +import java.util.ArrayList; +import java.util.HashSet; import java.util.Locale; +import java.util.Set; -import static de.blinkt.openvpn.core.connection.Connection.TransportType.OBFS4; -import static se.leap.bitmaskclient.base.models.Constants.CAPABILITIES; -import static se.leap.bitmaskclient.base.models.Constants.GATEWAYS; -import static se.leap.bitmaskclient.base.models.Constants.LOCATIONS; -import static se.leap.bitmaskclient.base.models.Constants.PROVIDER_ALLOWED_REGISTERED; -import static se.leap.bitmaskclient.base.models.Constants.PROVIDER_ALLOW_ANONYMOUS; -import static se.leap.bitmaskclient.base.models.Constants.TRANSPORT; -import static se.leap.bitmaskclient.base.models.Constants.TYPE; -import static se.leap.bitmaskclient.providersetup.ProviderAPI.ERRORS; +import de.blinkt.openvpn.core.connection.Connection.TransportType; +import motd.IStringCollection; +import motd.Motd; /** * @author Sean Leonard <meanderingcode@aetherislands.net> @@ -45,14 +56,18 @@ import static se.leap.bitmaskclient.providersetup.ProviderAPI.ERRORS; */ public final class Provider implements Parcelable { - private static long EIP_SERVICE_TIMEOUT = 1000 * 60 * 60 * 24 * 3; - private static long GEOIP_SERVICE_TIMEOUT = 1000 * 60 * 60; + private static final long EIP_SERVICE_TIMEOUT = 1000 * 60 * 60 * 24 * 3; + private static final long GEOIP_SERVICE_TIMEOUT = 1000 * 60 * 60; + private static final long MOTD_TIMEOUT = 1000 * 60 * 60 * 24; private JSONObject definition = new JSONObject(); // Represents our Provider's provider.json private JSONObject eipServiceJson = new JSONObject(); private JSONObject geoIpJson = new JSONObject(); + private JSONObject motdJson = new JSONObject(); private DefaultedURL mainUrl = new DefaultedURL(); private DefaultedURL apiUrl = new DefaultedURL(); private DefaultedURL geoipUrl = new DefaultedURL(); + private DefaultedURL motdUrl = new DefaultedURL(); + private String domain = ""; private String providerIp = ""; // ip of the provider main url private String providerApiIp = ""; // ip of the provider api url private String certificatePin = ""; @@ -63,6 +78,10 @@ public final class Provider implements Parcelable { private String vpnCertificate = ""; private long lastEipServiceUpdate = 0L; private long lastGeoIpUpdate = 0L; + private long lastMotdUpdate = 0L; + private long lastMotdSeen = 0L; + private Set<String> lastMotdSeenHashes = new HashSet<>(); + private boolean shouldUpdateVpnCertificate; private boolean allowAnonymous; private boolean allowRegistered; @@ -83,7 +102,8 @@ public final class Provider implements Parcelable { MAIN_URL = "main_url", PROVIDER_IP = "provider_ip", PROVIDER_API_IP = "provider_api_ip", - GEOIP_URL = "geoip_url"; + GEOIP_URL = "geoip_url", + MOTD_URL = "motd_url"; private static final String API_TERM_NAME = "name"; @@ -103,10 +123,10 @@ public final class Provider implements Parcelable { } public Provider(String mainUrl, String providerIp, String providerApiIp) { - this(mainUrl, null, providerIp, providerApiIp); + this(mainUrl, null, null, providerIp, providerApiIp); } - public Provider(String mainUrl, String geoipUrl, String providerIp, String providerApiIp) { + public Provider(String mainUrl, String geoipUrl, String motdUrl, String providerIp, String providerApiIp) { try { this.mainUrl.setUrl(new URL(mainUrl)); if (providerIp != null) { @@ -120,11 +140,11 @@ public final class Provider implements Parcelable { return; } setGeoipUrl(geoipUrl); + setMotdUrl(motdUrl); } - - public Provider(String mainUrl, String geoipUrl, String providerIp, String providerApiIp, String caCert, String definition) { - this(mainUrl, geoipUrl, providerIp, providerApiIp); + public Provider(String mainUrl, String geoipUrl, String motdUrl, String providerIp, String providerApiIp, String caCert, String definition) { + this(mainUrl, geoipUrl, motdUrl, providerIp, providerApiIp); if (caCert != null) { this.caCert = caCert; } @@ -160,6 +180,17 @@ public final class Provider implements Parcelable { } public boolean supportsPluggableTransports() { + if (useObfsVpn()) { + return supportsTransports(new TransportType[]{OBFS4, OBFS4_KCP}); + } + return supportsTransports(new TransportType[]{OBFS4}); + } + + public boolean supportsExperimentalPluggableTransports() { + return supportsTransports(new TransportType[]{OBFS4_KCP}); + } + + private boolean supportsTransports(TransportType[] transportTypes) { try { JSONArray gatewayJsons = eipServiceJson.getJSONArray(GATEWAYS); for (int i = 0; i < gatewayJsons.length(); i++) { @@ -167,15 +198,18 @@ public final class Provider implements Parcelable { getJSONObject(CAPABILITIES). getJSONArray(TRANSPORT); for (int j = 0; j < transports.length(); j++) { - if (OBFS4.toString().equals(transports.getJSONObject(j).getString(TYPE))) { - return true; + String supportedTransportType = transports.getJSONObject(j).getString(TYPE); + for (TransportType transportType : transportTypes) { + if (transportType.toString().equals(supportedTransportType)) { + return true; + } } } } } catch (Exception e) { - // ignore + // ignore } - return false; + return false; } public String getIpForHostname(String host) { @@ -233,7 +267,7 @@ public final class Provider implements Parcelable { } public String getDomain() { - return mainUrl.getDomain(); + return domain; } public String getMainUrlString() { @@ -260,6 +294,18 @@ public final class Provider implements Parcelable { } } + public DefaultedURL getMotdUrl() { + return this.motdUrl; + } + + public void setMotdUrl(String url) { + try { + this.motdUrl.setUrl(new URL(url)); + } catch (MalformedURLException e) { + this.motdUrl = new DefaultedURL(); + } + } + public String getApiUrlWithVersion() { return getApiUrlString() + "/" + getApiVersion(); } @@ -349,24 +395,32 @@ public final class Provider implements Parcelable { @Override public void writeToParcel(Parcel parcel, int i) { + parcel.writeString(getDomain()); parcel.writeString(getMainUrlString()); parcel.writeString(getProviderIp()); parcel.writeString(getProviderApiIp()); parcel.writeString(getGeoipUrl().toString()); + parcel.writeString(getMotdUrl().toString()); parcel.writeString(getDefinitionString()); parcel.writeString(getCaCert()); parcel.writeString(getEipServiceJsonString()); parcel.writeString(getGeoIpJsonString()); + parcel.writeString(getMotdJsonString()); parcel.writeString(getPrivateKey()); parcel.writeString(getVpnCertificate()); parcel.writeLong(lastEipServiceUpdate); parcel.writeLong(lastGeoIpUpdate); + parcel.writeLong(lastMotdUpdate); + parcel.writeLong(lastMotdSeen); + parcel.writeStringList(new ArrayList<>(lastMotdSeenHashes)); + parcel.writeInt(shouldUpdateVpnCertificate ? 0 : 1); } //TODO: write a test for marshalling! private Provider(Parcel in) { try { + domain = in.readString(); mainUrl.setUrl(new URL(in.readString())); String tmpString = in.readString(); if (!tmpString.isEmpty()) { @@ -381,6 +435,10 @@ public final class Provider implements Parcelable { geoipUrl.setUrl(new URL(tmpString)); } tmpString = in.readString(); + if (!tmpString.isEmpty()) { + motdUrl.setUrl(new URL(tmpString)); + } + tmpString = in.readString(); if (!tmpString.isEmpty()) { definition = new JSONObject((tmpString)); parseDefinition(definition); @@ -398,6 +456,10 @@ public final class Provider implements Parcelable { this.setGeoIpJson(new JSONObject(tmpString)); } tmpString = in.readString(); + if (!tmpString.isEmpty()) { + this.setMotdJson(new JSONObject(tmpString)); + } + tmpString = in.readString(); if (!tmpString.isEmpty()) { this.setPrivateKey(tmpString); } @@ -407,6 +469,12 @@ public final class Provider implements Parcelable { } this.lastEipServiceUpdate = in.readLong(); this.lastGeoIpUpdate = in.readLong(); + this.lastMotdUpdate = in.readLong(); + this.lastMotdSeen = in.readLong(); + ArrayList<String> lastMotdSeenHashes = new ArrayList<>(); + in.readStringList(lastMotdSeenHashes); + this.lastMotdSeenHashes = new HashSet<>(lastMotdSeenHashes); + this.shouldUpdateVpnCertificate = in.readInt() == 0; } catch (MalformedURLException | JSONException e) { e.printStackTrace(); } @@ -417,14 +485,17 @@ public final class Provider implements Parcelable { public boolean equals(Object o) { if (o instanceof Provider) { Provider p = (Provider) o; - return p.getDomain().equals(getDomain()) && + return getDomain().equals(p.getDomain()) && + mainUrl.getDomain().equals(p.mainUrl.getDomain()) && definition.toString().equals(p.getDefinition().toString()) && eipServiceJson.toString().equals(p.getEipServiceJsonString()) && geoIpJson.toString().equals(p.getGeoIpJsonString()) && + motdJson.toString().equals(p.getMotdJsonString()) && providerIp.equals(p.getProviderIp()) && providerApiIp.equals(p.getProviderApiIp()) && apiUrl.equals(p.getApiUrl()) && geoipUrl.equals(p.getGeoipUrl()) && + motdUrl.equals(p.getMotdUrl()) && certificatePin.equals(p.getCertificatePin()) && certificatePinEncoding.equals(p.getCertificatePinEncoding()) && caCert.equals(p.getCaCert()) && @@ -449,7 +520,7 @@ public final class Provider implements Parcelable { @Override public int hashCode() { - return getDomain().hashCode(); + return getMainUrlString().hashCode(); } @Override @@ -466,6 +537,7 @@ public final class Provider implements Parcelable { this.allowAnonymous = definition.getJSONObject(Provider.SERVICE).getBoolean(PROVIDER_ALLOW_ANONYMOUS); this.allowRegistered = definition.getJSONObject(Provider.SERVICE).getBoolean(PROVIDER_ALLOWED_REGISTERED); this.apiVersion = getDefinition().getString(Provider.API_VERSION); + this.domain = getDefinition().getString(Provider.DOMAIN); return true; } catch (JSONException | ArrayIndexOutOfBoundsException | MalformedURLException e) { return false; @@ -492,6 +564,77 @@ public final class Provider implements Parcelable { return System.currentTimeMillis() - lastEipServiceUpdate >= EIP_SERVICE_TIMEOUT; } + public void setShouldUpdateVpnCertificate(Boolean update) { + shouldUpdateVpnCertificate = update; + } + + public boolean shouldUpdateVpnCertificate() { + return shouldUpdateVpnCertificate; + } + + public void setLastMotdSeen(long timestamp) { + lastMotdSeen = timestamp; + } + + public long getLastMotdSeen() { + return lastMotdSeen; + } + + /** + * shouldShowMotdSeen + * @return true if last message of the day was shown more than 24h ago + */ + public boolean shouldShowMotdSeen() { + return !motdUrl.isDefault() && System.currentTimeMillis() - lastMotdSeen >= MOTD_TIMEOUT; + } + + /** + * setLastSeenHashes + * @param hashes hashes of messages of type 'once' that have already been seen + */ + public void setMotdLastSeenHashes(Set<String> hashes) { + lastMotdSeenHashes = hashes; + } + + public Set<String> getMotdLastSeenHashes() { + return lastMotdSeenHashes; + } + + /** + * getLastSeenHashCollection + * @return go ffi compatible IStringCollection interface of message hashes of type 'once' + */ + public IStringCollection getMotdLastSeenHashCollection() { + IStringCollection stringCollection = Motd.newStringCollection(); + for (String hash : lastMotdSeenHashes) { + stringCollection.add(hash); + } + return stringCollection; + } + + public void setLastMotdUpdate(long timestamp) { + lastMotdUpdate = timestamp; + } + + public long getLastMotdUpdate() { + return lastMotdUpdate; + } + + public boolean shouldUpdateMotdJson() { + return !motdUrl.isDefault() && System.currentTimeMillis() - lastMotdUpdate >= MOTD_TIMEOUT; + } + + public void setMotdJson(@NonNull JSONObject motdJson) { + this.motdJson = motdJson; + } + + public JSONObject getMotdJson() { + return motdJson; + } + + public String getMotdJsonString() { + return motdJson.toString(); + } public void setLastGeoIpUpdate(long timestamp) { lastGeoIpUpdate = timestamp; @@ -587,6 +730,7 @@ public final class Provider implements Parcelable { definition = new JSONObject(); eipServiceJson = new JSONObject(); geoIpJson = new JSONObject(); + motdJson = new JSONObject(); apiUrl = new DefaultedURL(); certificatePin = ""; certificatePinEncoding = ""; diff --git a/app/src/main/java/se/leap/bitmaskclient/base/models/ProviderObservable.java b/app/src/main/java/se/leap/bitmaskclient/base/models/ProviderObservable.java index 19555504d0af464bd5160a64cdf24ad6af98200d..3e1e1fcc53a0fffa6327e2bf665850112af1d571 100644 --- a/app/src/main/java/se/leap/bitmaskclient/base/models/ProviderObservable.java +++ b/app/src/main/java/se/leap/bitmaskclient/base/models/ProviderObservable.java @@ -1,5 +1,7 @@ package se.leap.bitmaskclient.base.models; +import androidx.annotation.NonNull; + import java.util.Observable; /** @@ -17,7 +19,7 @@ public class ProviderObservable extends Observable { return instance; } - public synchronized void updateProvider(Provider provider) { + public synchronized void updateProvider(@NonNull Provider provider) { instance.currentProvider = provider; instance.providerForDns = null; instance.setChanged(); diff --git a/app/src/main/java/se/leap/bitmaskclient/base/models/Transport.java b/app/src/main/java/se/leap/bitmaskclient/base/models/Transport.java new file mode 100644 index 0000000000000000000000000000000000000000..90a033ddb85f9fa538c7fe2909da40f46e57bb64 --- /dev/null +++ b/app/src/main/java/se/leap/bitmaskclient/base/models/Transport.java @@ -0,0 +1,49 @@ +package se.leap.bitmaskclient.base.models; + +import com.google.gson.Gson; +import com.google.gson.GsonBuilder; + +import org.json.JSONObject; + +public class Transport { + private String type; + private String[] protocols; + private String[] ports; + private Options options; + + public Transport(String type, String[] protocols, String[] ports, String cert) { + this.type = type; + this.protocols = protocols; + this.ports = ports; + this.options = new Options(cert); + } + + @Override + public String toString() { + return new Gson().toJson(this); + } + + public static Transport fromJson(JSONObject json) { + GsonBuilder builder = new GsonBuilder(); + return builder.create().fromJson(json.toString(), Transport.class); + } + + public static class Options { + private String cert; + private String iatMode; + + public Options(String cert) { + this.cert = cert; + this.iatMode = "0"; + } + + @Override + public String toString() { + return new Gson().toJson(this); + } + } + + +} + + diff --git a/app/src/main/java/se/leap/bitmaskclient/base/utils/Cmd.java b/app/src/main/java/se/leap/bitmaskclient/base/utils/Cmd.java index affceacf0f015ea0bd06fda4a2a3cc653373ff53..e25ab58e87e52107d046692e071e823c6db9eaf6 100644 --- a/app/src/main/java/se/leap/bitmaskclient/base/utils/Cmd.java +++ b/app/src/main/java/se/leap/bitmaskclient/base/utils/Cmd.java @@ -1,5 +1,5 @@ /** - * Copyright (c) 2019 LEAP Encryption Access Project and contributers + * Copyright (c) 2020 LEAP Encryption Access Project and contributers * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by diff --git a/app/src/main/java/se/leap/bitmaskclient/base/utils/ConfigHelper.java b/app/src/main/java/se/leap/bitmaskclient/base/utils/ConfigHelper.java index 2794302291bab374422ef86feb414f78053e8d66..d65f6b52d8c5aef0bd4bbc8ce80064bf32f1f37d 100644 --- a/app/src/main/java/se/leap/bitmaskclient/base/utils/ConfigHelper.java +++ b/app/src/main/java/se/leap/bitmaskclient/base/utils/ConfigHelper.java @@ -16,6 +16,9 @@ */ package se.leap.bitmaskclient.base.utils; +import static se.leap.bitmaskclient.base.models.Constants.DEFAULT_BITMASK; + +import android.app.PendingIntent; import android.content.Context; import android.content.res.Resources; import android.os.Build; @@ -37,7 +40,6 @@ import java.security.KeyFactory; import java.security.MessageDigest; import java.security.NoSuchAlgorithmException; import java.security.NoSuchProviderException; -import java.security.cert.Certificate; import java.security.cert.CertificateEncodingException; import java.security.cert.CertificateException; import java.security.cert.CertificateFactory; @@ -47,28 +49,28 @@ import java.security.spec.InvalidKeySpecException; import java.security.spec.PKCS8EncodedKeySpec; import java.util.ArrayList; import java.util.Calendar; -import java.util.Collection; import java.util.regex.Matcher; import java.util.regex.Pattern; +import okhttp3.internal.publicsuffix.PublicSuffixDatabase; import se.leap.bitmaskclient.BuildConfig; import se.leap.bitmaskclient.R; import se.leap.bitmaskclient.providersetup.ProviderAPI; -import static se.leap.bitmaskclient.base.models.Constants.DEFAULT_BITMASK; - /** * Stores constants, and implements auxiliary methods used across all Bitmask Android classes. * Wraps BuildConfigFields for to support easier unit testing * * @author parmegv * @author MeanderingCode + * @author cyberta */ public class ConfigHelper { final public static String NG_1024 = "eeaf0ab9adb38dd69c33f80afa8fc5e86072618775ff3c0b9ea2314c9c256576d674df7496ea81d3383b4813d692c6e0e0d5d8e250b98be48e495c1d6089dad15dc7d7b46154d6b6ce8ef4ad69b15d4982559b297bcf1885c529f566660e57ec68edbc3c05726cc02fd4cbf4976eaa9afd5138fe8376435b9fc61d2fc0eb06e3"; final public static BigInteger G = new BigInteger("2"); final public static Pattern IPv4_PATTERN = Pattern.compile("^(?:(?:25[0-5]|2[0-4][0-9]|1[0-9][0-9]|[1-9][0-9]|[0-9])\\.){3}(?:25[0-5]|2[0-4][0-9]|1[0-9][0-9]|[1-9][0-9]|[0-9])$"); + final public static Pattern PEM_CERTIFICATE_PATTERN = Pattern.compile("((-----BEGIN CERTIFICATE-----)([A-Za-z0-9+/=\\n]+)(-----END CERTIFICATE-----)+)"); public static boolean checkErroneousDownload(String downloadedString) { try { @@ -103,23 +105,26 @@ public class ConfigHelper { } public static ArrayList<X509Certificate> parseX509CertificatesFromString(String certificateString) { - Collection<? extends Certificate> certificates; + ArrayList<X509Certificate> certificates = new ArrayList<>(); CertificateFactory cf; try { cf = CertificateFactory.getInstance("X.509"); - certificateString = certificateString.replaceAll("-----BEGIN CERTIFICATE-----", "").trim().replaceAll("-----END CERTIFICATE-----", "").trim(); - byte[] certBytes = Base64.decode(certificateString); - try (InputStream caInput = new ByteArrayInputStream(certBytes)) { - certificates = cf.generateCertificates(caInput); - if (certificates != null) { - for (Certificate cert : certificates) { - System.out.println("ca=" + ((X509Certificate) cert).getSubjectDN()); - } - return (ArrayList<X509Certificate>) certificates; + Matcher matcher = PEM_CERTIFICATE_PATTERN.matcher(certificateString); + while (matcher.find()) { + String certificate = matcher.group(3); + if (certificate == null) continue; + byte[] certBytes = Base64.decode(certificate.trim()); + try (InputStream caInput = new ByteArrayInputStream(certBytes)) { + X509Certificate x509certificate = (X509Certificate) cf.generateCertificate(caInput); + certificates.add(x509certificate); + System.out.println("ca=" + x509certificate.getSubjectDN() + ", SAN= " + x509certificate.getSubjectAlternativeNames()); + } catch (IOException | CertificateException | NullPointerException | IllegalArgumentException | ClassCastException e) { + e.printStackTrace(); } } - } catch (NullPointerException | CertificateException | IOException | IllegalArgumentException | ClassCastException e) { + return certificates; + } catch (CertificateException e) { e.printStackTrace(); } @@ -271,4 +276,49 @@ public class ConfigHelper { return matcher.matches(); } + public static String getDomainFromMainURL(@NonNull String mainUrl) throws NullPointerException { + return PublicSuffixDatabase.get().getEffectiveTldPlusOne(mainUrl).replaceFirst("http[s]?://", "").replaceFirst("/.*", ""); + } + + public static boolean isCalyxOSWithTetheringSupport(Context context) { + return SystemPropertiesHelper.contains("ro.calyxos.version", context) && + Build.VERSION.SDK_INT >= Build.VERSION_CODES.R; + } + + // ObfsVpnHelper class allows us to mock BuildConfig.use_obfsvpn while + // not mocking the whole ConfigHelper class + public static class ObfsVpnHelper { + public static boolean useObfsVpn() { + return BuildConfig.use_obfsvpn; + } + + public static boolean hasObfuscationPinningDefaults() { + return BuildConfig.obfsvpn_ip != null && + BuildConfig.obfsvpn_port != null && + BuildConfig.obfsvpn_cert != null && + !BuildConfig.obfsvpn_ip.isEmpty() && + !BuildConfig.obfsvpn_port.isEmpty() && + !BuildConfig.obfsvpn_cert.isEmpty(); + } + public static String obfsvpnIP() { + return BuildConfig.obfsvpn_ip; + } + public static String obfsvpnPort() { + return BuildConfig.obfsvpn_port; + } + public static String obfsvpnCert() { + return BuildConfig.obfsvpn_cert; + } + public static boolean useKcp() { + return BuildConfig.obfsvpn_use_kcp; + } + } + + public static int getPendingIntentFlags() { + int flags = PendingIntent.FLAG_CANCEL_CURRENT; + if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.S) { + flags |= PendingIntent.FLAG_IMMUTABLE; + } + return flags; + } } diff --git a/app/src/main/java/se/leap/bitmaskclient/base/utils/DateHelper.java b/app/src/main/java/se/leap/bitmaskclient/base/utils/DateHelper.java index 0476bf12feb3ff612b6214f0c1e5885245e5c685..2e9c2b24f7a0da3760f133f1f7e6f7b578f5a2ed 100644 --- a/app/src/main/java/se/leap/bitmaskclient/base/utils/DateHelper.java +++ b/app/src/main/java/se/leap/bitmaskclient/base/utils/DateHelper.java @@ -12,6 +12,7 @@ import java.util.Locale; */ public class DateHelper { private static final String DATE_PATTERN = "dd/MM/yyyy"; + private static final String DATE_PATTERN_RFC822_NUMERIC_ZONE = "dd MMM yy hh:mm Z"; // RFC822 with numeric zone private static final int ONE_DAY = 86400000; //1000*60*60*24 public static long getDateDiffToCurrentDateInDays(String startDate) throws ParseException { @@ -26,4 +27,14 @@ public class DateHelper { Date lastDate = new Date(); return sdf.format(lastDate); } + + /** + * Return date in a specific format bitmaskcore can handle. + * @param milliSeconds Date in milliseconds + * @return String representing date in specified format + */ + public static String getFormattedDateWithTimezone(long milliSeconds) throws IllegalArgumentException { + SimpleDateFormat sdf = new SimpleDateFormat(DATE_PATTERN_RFC822_NUMERIC_ZONE, Locale.US); + return sdf.format(milliSeconds); + } } diff --git a/app/src/main/java/se/leap/bitmaskclient/base/utils/PreferenceHelper.java b/app/src/main/java/se/leap/bitmaskclient/base/utils/PreferenceHelper.java index fe9100cb0e562d8b0f9ffdedf43df80aa4805af6..9cba221acc779234fa0a05091465713ef2524273 100644 --- a/app/src/main/java/se/leap/bitmaskclient/base/utils/PreferenceHelper.java +++ b/app/src/main/java/se/leap/bitmaskclient/base/utils/PreferenceHelper.java @@ -1,37 +1,29 @@ package se.leap.bitmaskclient.base.utils; -import android.content.Context; -import android.content.SharedPreferences; -import android.preference.Preference; - -import androidx.annotation.NonNull; -import androidx.annotation.WorkerThread; - -import org.json.JSONException; -import org.json.JSONObject; - -import java.net.MalformedURLException; -import java.net.URL; -import java.util.HashSet; -import java.util.Set; - -import de.blinkt.openvpn.VpnProfile; -import se.leap.bitmaskclient.base.models.Provider; -import se.leap.bitmaskclient.tor.TorStatusObservable; - import static android.content.Context.MODE_PRIVATE; +import static se.leap.bitmaskclient.base.models.Constants.ALLOW_EXPERIMENTAL_TRANSPORTS; import static se.leap.bitmaskclient.base.models.Constants.ALLOW_TETHERING_BLUETOOTH; import static se.leap.bitmaskclient.base.models.Constants.ALLOW_TETHERING_USB; import static se.leap.bitmaskclient.base.models.Constants.ALLOW_TETHERING_WIFI; import static se.leap.bitmaskclient.base.models.Constants.ALWAYS_ON_SHOW_DIALOG; import static se.leap.bitmaskclient.base.models.Constants.DEFAULT_SHARED_PREFS_BATTERY_SAVER; import static se.leap.bitmaskclient.base.models.Constants.EXCLUDED_APPS; +import static se.leap.bitmaskclient.base.models.Constants.GATEWAY_PINNING; import static se.leap.bitmaskclient.base.models.Constants.LAST_UPDATE_CHECK; import static se.leap.bitmaskclient.base.models.Constants.LAST_USED_PROFILE; +import static se.leap.bitmaskclient.base.models.Constants.OBFUSCATION_PINNING_CERT; +import static se.leap.bitmaskclient.base.models.Constants.OBFUSCATION_PINNING_IP; +import static se.leap.bitmaskclient.base.models.Constants.OBFUSCATION_PINNING_KCP; +import static se.leap.bitmaskclient.base.models.Constants.OBFUSCATION_PINNING_LOCATION; +import static se.leap.bitmaskclient.base.models.Constants.OBFUSCATION_PINNING_PORT; import static se.leap.bitmaskclient.base.models.Constants.PREFERRED_CITY; import static se.leap.bitmaskclient.base.models.Constants.PREFER_UDP; import static se.leap.bitmaskclient.base.models.Constants.PROVIDER_CONFIGURED; import static se.leap.bitmaskclient.base.models.Constants.PROVIDER_EIP_DEFINITION; +import static se.leap.bitmaskclient.base.models.Constants.PROVIDER_MOTD; +import static se.leap.bitmaskclient.base.models.Constants.PROVIDER_MOTD_HASHES; +import static se.leap.bitmaskclient.base.models.Constants.PROVIDER_MOTD_LAST_SEEN; +import static se.leap.bitmaskclient.base.models.Constants.PROVIDER_MOTD_LAST_UPDATED; import static se.leap.bitmaskclient.base.models.Constants.PROVIDER_PRIVATE_KEY; import static se.leap.bitmaskclient.base.models.Constants.PROVIDER_VPN_CERTIFICATE; import static se.leap.bitmaskclient.base.models.Constants.RESTART_ON_UPDATE; @@ -39,8 +31,29 @@ import static se.leap.bitmaskclient.base.models.Constants.SHARED_PREFERENCES; import static se.leap.bitmaskclient.base.models.Constants.SHOW_EXPERIMENTAL; import static se.leap.bitmaskclient.base.models.Constants.USE_BRIDGES; import static se.leap.bitmaskclient.base.models.Constants.USE_IPv6_FIREWALL; +import static se.leap.bitmaskclient.base.models.Constants.USE_OBFUSCATION_PINNING; import static se.leap.bitmaskclient.base.models.Constants.USE_SNOWFLAKE; +import android.content.Context; +import android.content.SharedPreferences; +import android.text.TextUtils; + +import androidx.annotation.NonNull; +import androidx.annotation.WorkerThread; + +import org.json.JSONException; +import org.json.JSONObject; + +import java.net.MalformedURLException; +import java.net.URL; +import java.util.HashSet; +import java.util.Set; + +import de.blinkt.openvpn.VpnProfile; +import se.leap.bitmaskclient.BuildConfig; +import se.leap.bitmaskclient.base.models.Provider; +import se.leap.bitmaskclient.tor.TorStatusObservable; + /** * Created by cyberta on 18.03.18. */ @@ -54,11 +67,16 @@ public class PreferenceHelper { provider.setProviderIp(preferences.getString(Provider.PROVIDER_IP, "")); provider.setProviderApiIp(preferences.getString(Provider.PROVIDER_API_IP, "")); provider.setGeoipUrl(preferences.getString(Provider.GEOIP_URL, "")); + provider.setMotdUrl(preferences.getString(Provider.MOTD_URL, "")); provider.define(new JSONObject(preferences.getString(Provider.KEY, ""))); provider.setCaCert(preferences.getString(Provider.CA_CERT, "")); provider.setVpnCertificate(preferences.getString(PROVIDER_VPN_CERTIFICATE, "")); provider.setPrivateKey(preferences.getString(PROVIDER_PRIVATE_KEY, "")); provider.setEipServiceJson(new JSONObject(preferences.getString(PROVIDER_EIP_DEFINITION, ""))); + provider.setMotdJson(new JSONObject(preferences.getString(PROVIDER_MOTD, ""))); + provider.setLastMotdSeen(preferences.getLong(PROVIDER_MOTD_LAST_SEEN, 0L)); + provider.setLastMotdUpdate(preferences.getLong(PROVIDER_MOTD_LAST_UPDATED, 0L)); + provider.setMotdLastSeenHashes(preferences.getStringSet(PROVIDER_MOTD_HASHES, new HashSet<>())); } catch (MalformedURLException | JSONException e) { e.printStackTrace(); } @@ -70,12 +88,31 @@ public class PreferenceHelper { return preferences.getString(toFetch + "." + providerDomain, ""); } + public static long getLongFromPersistedProvider(String toFetch, String providerDomain, SharedPreferences preferences) { + return preferences.getLong(toFetch + "." + providerDomain, 0L); + } + + public static Set<String> getStringSetFromPersistedProvider(String toFetch, String providerDomain, SharedPreferences preferences) { + return preferences.getStringSet(toFetch + "." + providerDomain, new HashSet<>()); + } + + public static void persistProviderAsync(Context context, Provider provider) { + SharedPreferences preferences = context.getSharedPreferences(SHARED_PREFERENCES, MODE_PRIVATE); + storeProviderInPreferences(preferences, provider, true); + } + + public static void storeProviderInPreferences(SharedPreferences preferences, Provider provider) { + storeProviderInPreferences(preferences, provider, false); + } + // TODO: replace commit with apply after refactoring EIP //FIXME: don't save private keys in shared preferences! use the keystore - public static void storeProviderInPreferences(SharedPreferences preferences, Provider provider) { - preferences.edit().putBoolean(PROVIDER_CONFIGURED, true). + public static void storeProviderInPreferences(SharedPreferences preferences, Provider provider, boolean async) { + SharedPreferences.Editor editor = preferences.edit(); + editor.putBoolean(PROVIDER_CONFIGURED, true). putString(Provider.PROVIDER_IP, provider.getProviderIp()). putString(Provider.GEOIP_URL, provider.getGeoipUrl().toString()). + putString(Provider.MOTD_URL, provider.getMotdUrl().toString()). putString(Provider.PROVIDER_API_IP, provider.getProviderApiIp()). putString(Provider.MAIN_URL, provider.getMainUrlString()). putString(Provider.KEY, provider.getDefinitionString()). @@ -83,7 +120,15 @@ public class PreferenceHelper { putString(PROVIDER_EIP_DEFINITION, provider.getEipServiceJsonString()). putString(PROVIDER_PRIVATE_KEY, provider.getPrivateKey()). putString(PROVIDER_VPN_CERTIFICATE, provider.getVpnCertificate()). - commit(); + putString(PROVIDER_MOTD, provider.getMotdJsonString()). + putStringSet(PROVIDER_MOTD_HASHES, provider.getMotdLastSeenHashes()). + putLong(PROVIDER_MOTD_LAST_SEEN, provider.getLastMotdSeen()). + putLong(PROVIDER_MOTD_LAST_UPDATED, provider.getLastMotdUpdate()); + if (async) { + editor.apply(); + } else { + editor.commit(); + } String providerDomain = provider.getDomain(); preferences.edit().putBoolean(PROVIDER_CONFIGURED, true). @@ -91,9 +136,14 @@ public class PreferenceHelper { putString(Provider.PROVIDER_API_IP + "." + providerDomain, provider.getProviderApiIp()). putString(Provider.MAIN_URL + "." + providerDomain, provider.getMainUrlString()). putString(Provider.GEOIP_URL + "." + providerDomain, provider.getGeoipUrl().toString()). + putString(Provider.MOTD_URL + "." + providerDomain, provider.getMotdUrl().toString()). putString(Provider.KEY + "." + providerDomain, provider.getDefinitionString()). putString(Provider.CA_CERT + "." + providerDomain, provider.getCaCert()). putString(PROVIDER_EIP_DEFINITION + "." + providerDomain, provider.getEipServiceJsonString()). + putString(PROVIDER_MOTD + "." + providerDomain, provider.getMotdJsonString()). + putStringSet(PROVIDER_MOTD_HASHES + "." + providerDomain, provider.getMotdLastSeenHashes()). + putLong(PROVIDER_MOTD_LAST_SEEN + "." + providerDomain, provider.getLastMotdSeen()). + putLong(PROVIDER_MOTD_LAST_UPDATED + "." + providerDomain, provider.getLastMotdUpdate()). apply(); } @@ -124,9 +174,33 @@ public class PreferenceHelper { remove(Provider.PROVIDER_API_IP + "." + providerDomain). remove(Provider.MAIN_URL + "." + providerDomain). remove(Provider.GEOIP_URL + "." + providerDomain). + remove(Provider.MOTD_URL + "." + providerDomain). remove(PROVIDER_EIP_DEFINITION + "." + providerDomain). remove(PROVIDER_PRIVATE_KEY + "." + providerDomain). remove(PROVIDER_VPN_CERTIFICATE + "." + providerDomain). + remove(PROVIDER_MOTD + "." + providerDomain). + remove(PROVIDER_MOTD_HASHES + "." + providerDomain). + remove(PROVIDER_MOTD_LAST_SEEN + "." + providerDomain). + remove(PROVIDER_MOTD_LAST_UPDATED + "." + providerDomain). + apply(); + } + + public static void deleteCurrentProviderDetailsFromPreferences(@NonNull SharedPreferences preferences) { + preferences.edit(). + remove(Provider.KEY). + remove(Provider.CA_CERT). + remove(Provider.PROVIDER_IP). + remove(Provider.PROVIDER_API_IP). + remove(Provider.MAIN_URL). + remove(Provider.GEOIP_URL). + remove(Provider.MOTD_URL). + remove(PROVIDER_EIP_DEFINITION). + remove(PROVIDER_PRIVATE_KEY). + remove(PROVIDER_VPN_CERTIFICATE). + remove(PROVIDER_MOTD). + remove(PROVIDER_MOTD_HASHES). + remove(PROVIDER_MOTD_LAST_SEEN). + remove(PROVIDER_MOTD_LAST_UPDATED). apply(); } @@ -147,13 +221,21 @@ public class PreferenceHelper { } public static boolean getPreferUDP(Context context) { - return getBoolean(context, PREFER_UDP, false); + return getBoolean(context, PREFER_UDP, BuildConfig.prefer_udp); } public static void preferUDP(Context context, boolean prefer) { putBoolean(context, PREFER_UDP, prefer); } + public static String getPinnedGateway(Context context) { + return getString(context, GATEWAY_PINNING, null); + } + + public static void pinGateway(Context context, String value) { + putString(context, GATEWAY_PINNING, value); + } + public static boolean getUseBridges(SharedPreferences preferences) { return preferences.getBoolean(USE_BRIDGES, false); } @@ -229,6 +311,67 @@ public class PreferenceHelper { return getBoolean(context, SHOW_EXPERIMENTAL, false); } + public static void setAllowExperimentalTransports(Context context, boolean show) { + putBoolean(context, ALLOW_EXPERIMENTAL_TRANSPORTS, show); + } + + public static boolean allowExperimentalTransports(Context context) { + return getBoolean(context, ALLOW_EXPERIMENTAL_TRANSPORTS, false); + } + + public static void setUseObfuscationPinning(Context context, Boolean pinning) { + putBoolean(context, USE_OBFUSCATION_PINNING, pinning); + } + + public static boolean useObfuscationPinning(Context context) { + return ConfigHelper.ObfsVpnHelper.useObfsVpn() && + getUseBridges(context) && + getBoolean(context, USE_OBFUSCATION_PINNING, false) && + !TextUtils.isEmpty(getObfuscationPinningIP(context)) && + !TextUtils.isEmpty(getObfuscationPinningCert(context)) && + !TextUtils.isEmpty(getObfuscationPinningPort(context)); + } + + public static void setObfuscationPinningIP(Context context, String ip) { + putString(context, OBFUSCATION_PINNING_IP, ip); + } + + public static String getObfuscationPinningIP(Context context) { + return getString(context, OBFUSCATION_PINNING_IP, null); + } + + public static void setObfuscationPinningPort(Context context, String port) { + putString(context, OBFUSCATION_PINNING_PORT, port); + } + + public static String getObfuscationPinningPort(Context context) { + return getString(context, OBFUSCATION_PINNING_PORT, null); + } + + public static void setObfuscationPinningCert(Context context, String cert) { + putString(context, OBFUSCATION_PINNING_CERT, cert); + } + + public static String getObfuscationPinningCert(Context context) { + return getString(context, OBFUSCATION_PINNING_CERT, null); + } + + public static void setObfuscationPinningGatewayLocation(Context context, String location) { + putString(context, OBFUSCATION_PINNING_LOCATION, location); + } + + public static String getObfuscationPinningGatewayLocation(Context context) { + return getString(context, OBFUSCATION_PINNING_LOCATION, null); + } + + public static Boolean getObfuscationPinningKCP(Context context) { + return getBoolean(context, OBFUSCATION_PINNING_KCP, false); + } + + public static void setObfuscationPinningKCP(Context context, boolean isKCP) { + putBoolean(context, OBFUSCATION_PINNING_KCP, isKCP); + } + public static void setUseIPv6Firewall(Context context, boolean useFirewall) { putBoolean(context, USE_IPv6_FIREWALL, useFirewall); } @@ -246,7 +389,7 @@ public class PreferenceHelper { } public static String getPreferredCity(Context context) { - return getString(context, PREFERRED_CITY, null); + return useObfuscationPinning(context) ? null : getString(context, PREFERRED_CITY, null); } @WorkerThread @@ -269,10 +412,7 @@ public class PreferenceHelper { } public static void setExcludedApps(Context context, Set<String> apps) { - SharedPreferences prefs = context.getSharedPreferences(SHARED_PREFERENCES, MODE_PRIVATE); - SharedPreferences.Editor prefsedit = prefs.edit(); - prefsedit.putStringSet(EXCLUDED_APPS, apps); - prefsedit.apply(); + putStringSet(context, EXCLUDED_APPS, apps); } public static Set<String> getExcludedApps(Context context) { @@ -324,6 +464,14 @@ public class PreferenceHelper { preferences.edit().putString(key, value).apply(); } + public static void putStringSet(Context context, String key, Set<String> value) { + if (context == null) { + return; + } + SharedPreferences preferences = context.getSharedPreferences(SHARED_PREFERENCES, MODE_PRIVATE); + preferences.edit().putStringSet(key, value).apply(); + } + public static boolean getBoolean(Context context, String key, Boolean defValue) { if (context == null) { return false; diff --git a/app/src/main/java/se/leap/bitmaskclient/base/utils/SystemPropertiesHelper.java b/app/src/main/java/se/leap/bitmaskclient/base/utils/SystemPropertiesHelper.java new file mode 100644 index 0000000000000000000000000000000000000000..ecef77d63c4f36501004e2e435500d6419389f12 --- /dev/null +++ b/app/src/main/java/se/leap/bitmaskclient/base/utils/SystemPropertiesHelper.java @@ -0,0 +1,36 @@ +package se.leap.bitmaskclient.base.utils; + +import android.content.Context; + +import java.lang.reflect.Method; + + +public class SystemPropertiesHelper { + + /** + * Checks if SystemProperties contains a given key using reflection + * @return true if reflection was successful and the key was found + */ + public static boolean contains(String key, Context context) { + String result = null; + try { + ClassLoader cl = context.getClassLoader(); + @SuppressWarnings("rawtypes") + Class SystemProperties = cl.loadClass("android.os.SystemProperties"); + @SuppressWarnings("rawtypes") + Class[] paramTypes= new Class[1]; + paramTypes[0]= String.class; + + Method get = SystemProperties.getMethod("get", paramTypes); + Object[] params= new Object[1]; + params[0]= key; + + result = (String) get.invoke(SystemProperties, params); + } catch (Exception e) { + e.printStackTrace(); + } + + return result != null && !result.isEmpty(); + } +} + diff --git a/app/src/main/java/se/leap/bitmaskclient/base/utils/ViewHelper.java b/app/src/main/java/se/leap/bitmaskclient/base/utils/ViewHelper.java index 7410172f6c8de9eed14455ff182132302cbc6135..51bcb2b10cac924559e2c589b30409a2d21187fa 100644 --- a/app/src/main/java/se/leap/bitmaskclient/base/utils/ViewHelper.java +++ b/app/src/main/java/se/leap/bitmaskclient/base/utils/ViewHelper.java @@ -1,23 +1,63 @@ package se.leap.bitmaskclient.base.utils; +import android.app.Activity; +import android.app.Notification; import android.content.Context; +import android.graphics.Color; +import android.graphics.drawable.ColorDrawable; +import android.os.Build; +import android.text.Spannable; +import android.text.SpannableString; +import android.text.style.ForegroundColorSpan; +import android.util.Log; +import android.view.View; +import android.view.Window; +import android.view.WindowManager; +import androidx.annotation.ColorRes; import androidx.annotation.DimenRes; import androidx.annotation.StringRes; import androidx.appcompat.app.ActionBar; import androidx.appcompat.app.AppCompatActivity; +import androidx.appcompat.widget.AppCompatTextView; +import androidx.core.content.ContextCompat; import androidx.fragment.app.Fragment; +import se.leap.bitmaskclient.R; +import se.leap.bitmaskclient.base.views.ActionBarTitle; + /** * Created by cyberta on 29.06.18. */ public class ViewHelper { + private static final String TAG = ViewHelper.class.getSimpleName(); + public static int convertDimensionToPx(Context context, @DimenRes int dimension) { return context.getResources().getDimensionPixelSize(dimension); } + /** + * Sets the subtitle of an activities action bar. The activity needs to be an AppCompatActivity. + * @param fragment + * @param stringId + */ + public static void setActionBarSubtitle(Fragment fragment, @StringRes int stringId) { + AppCompatActivity appCompatActivity = (AppCompatActivity) fragment.getActivity(); + if (appCompatActivity != null) { + ActionBar actionBar = appCompatActivity.getSupportActionBar(); + if (actionBar != null) { + View customView = actionBar.getCustomView(); + if (customView instanceof ActionBarTitle) { + ActionBarTitle actionBarTitle = (ActionBarTitle) customView; + actionBarTitle.setSubtitle(stringId); + actionBarTitle.showSubtitle(true); + } + } + } + } + /** * Sets the subtitle of an activities action bar. The activity needs to be an AppCompatActivity. * @param fragment @@ -28,9 +68,82 @@ public class ViewHelper { if (appCompatActivity != null) { ActionBar actionBar = appCompatActivity.getSupportActionBar(); if (actionBar != null) { - actionBar.setSubtitle(stringId); + View customView = actionBar.getCustomView(); + if (customView instanceof ActionBarTitle) { + ActionBarTitle actionBarTitle = (ActionBarTitle) customView; + actionBarTitle.setTitle(stringId); + actionBarTitle.showSubtitle(false); + } else { + Log.e(TAG, "ActionBar has no custom action title!"); + } } } } + + public static void setDefaultActivityBarColor(Activity activity) { + setActivityBarColor(activity, R.color.colorPrimary, R.color.colorPrimaryDark, R.color.colorActionBarTitleFont); + } + + public static void setActivityBarColor(Activity activity, @ColorRes int primaryColor, @ColorRes int secondaryColor, @ColorRes int textColor) { + if (!(activity instanceof AppCompatActivity)) { + return; + } + + ActionBar bar = ((AppCompatActivity) activity).getSupportActionBar(); + if (bar == null) { + return; + } + int color = ContextCompat.getColor(activity, secondaryColor); + bar.setBackgroundDrawable(new ColorDrawable(color)); + Window window = activity.getWindow(); + window.clearFlags(WindowManager.LayoutParams.FLAG_TRANSLUCENT_STATUS); + window.addFlags(WindowManager.LayoutParams.FLAG_DRAWS_SYSTEM_BAR_BACKGROUNDS); + window.setStatusBarColor(ContextCompat.getColor(activity, primaryColor)); + + int actionBarTextColor; + if (textColor == 0) { + actionBarTextColor = isBrightColor(color) ? R.color.actionbar_connectivity_state_text_color_dark : R.color.actionbar_connectivity_state_text_color_light; + } else { + actionBarTextColor = textColor; + } + + View customView = bar.getCustomView(); + if (customView instanceof ActionBarTitle) { + ActionBarTitle actionBarTitle = (ActionBarTitle) customView; + actionBarTitle.setTitleTextColor(ContextCompat.getColor(bar.getThemedContext(), actionBarTextColor)); + } + } + + + public static boolean isBrightColor(int color) { + if (android.R.color.transparent == color) + return true; + + boolean rtnValue = false; + + int[] rgb = { Color.red(color), Color.green(color), Color.blue(color) }; + + int brightness = (int) Math.sqrt(rgb[0] * rgb[0] * .241 + rgb[1] + * rgb[1] * .691 + rgb[2] * rgb[2] * .068); + + // color is light + if (brightness >= 200) { + rtnValue = true; + } + + return rtnValue; + } + + public static void setActionBarTextColor(ActionBar bar, @ColorRes int titleColor) { + CharSequence titleCharSequence = bar.getTitle(); + if (titleCharSequence == null || titleCharSequence.length() == 0) { + return; + } + String title = titleCharSequence.toString(); + Spannable spannableTitle = new SpannableString(title); + spannableTitle.setSpan(new ForegroundColorSpan(ContextCompat.getColor(bar.getThemedContext(), titleColor)), 0, spannableTitle.length(), Spannable.SPAN_EXCLUSIVE_EXCLUSIVE); + bar.setTitle(spannableTitle); + } + } diff --git a/app/src/main/java/se/leap/bitmaskclient/base/views/ActionBarTitle.java b/app/src/main/java/se/leap/bitmaskclient/base/views/ActionBarTitle.java new file mode 100644 index 0000000000000000000000000000000000000000..a151305ecfda6cb054968157be7e5e2099b1662b --- /dev/null +++ b/app/src/main/java/se/leap/bitmaskclient/base/views/ActionBarTitle.java @@ -0,0 +1,96 @@ +package se.leap.bitmaskclient.base.views; + +import android.content.Context; +import android.util.AttributeSet; +import android.view.Gravity; +import android.view.LayoutInflater; +import android.widget.RelativeLayout; + +import androidx.annotation.ColorInt; +import androidx.annotation.NonNull; +import androidx.annotation.Nullable; +import androidx.annotation.StringRes; +import androidx.appcompat.widget.AppCompatTextView; +import androidx.appcompat.widget.LinearLayoutCompat; + +import se.leap.bitmaskclient.databinding.VActionbarTitleBinding; + +public class ActionBarTitle extends LinearLayoutCompat { + private AppCompatTextView actionBarTitle; + private AppCompatTextView actionBarSubtitle; + private LinearLayoutCompat container; + + public ActionBarTitle(@NonNull Context context) { + super(context); + initLayout(context); + } + + public ActionBarTitle(@NonNull Context context, @Nullable AttributeSet attrs) { + super(context, attrs); + initLayout(context); + } + + public ActionBarTitle(@NonNull Context context, @Nullable AttributeSet attrs, int defStyleAttr) { + super(context, attrs, defStyleAttr); + initLayout(context); + } + + public void initLayout(Context context) { + VActionbarTitleBinding binding = VActionbarTitleBinding.inflate(LayoutInflater.from(context), this, true); + actionBarTitle = binding.actionBarTitle; + actionBarSubtitle = binding.actionBarSubtitle; + container = binding.actionBarTitleContainer; + } + + public void setTitle(CharSequence text) { + actionBarTitle.setText(text); + } + + public void setTitleCaps(boolean caps) { + actionBarTitle.setAllCaps(caps); + } + + public void setSubtitle(CharSequence text) { + actionBarSubtitle.setText(text); + } + + public void setTitle(@StringRes int resId) { + actionBarTitle.setText(resId); + } + + public void setSubtitle(@StringRes int resId) { + actionBarSubtitle.setText(resId); + } + + public void setTitleTextColor(@ColorInt int color) { + actionBarTitle.setTextColor(color); + } + + public void setSubtitleTextColor(@ColorInt int color) { + actionBarSubtitle.setTextColor(color); + } + + public void showSubtitle(boolean show) { + actionBarSubtitle.setVisibility(show ? VISIBLE : GONE); + } + + public void setCentered(boolean centered) { + LayoutParams titleLayoutParams = (LayoutParams) actionBarTitle.getLayoutParams(); + LayoutParams subtitleLayoutParams = (LayoutParams) actionBarSubtitle.getLayoutParams(); + LayoutParams containerLayoutParams = (LayoutParams) container.getLayoutParams(); + if (centered) { + titleLayoutParams.gravity = Gravity.CENTER; + subtitleLayoutParams.gravity = Gravity.CENTER; + containerLayoutParams.gravity = Gravity.CENTER; + } else { + titleLayoutParams.gravity = Gravity.NO_GRAVITY; + subtitleLayoutParams.gravity = Gravity.NO_GRAVITY; + containerLayoutParams.gravity = Gravity.NO_GRAVITY; + } + actionBarTitle.setLayoutParams(titleLayoutParams); + actionBarSubtitle.setLayoutParams(subtitleLayoutParams); + container.setLayoutParams(containerLayoutParams); + + + } +} diff --git a/app/src/main/java/se/leap/bitmaskclient/base/views/LocationButton.java b/app/src/main/java/se/leap/bitmaskclient/base/views/LocationButton.java index b2182d6129d53286ad9ce0e2a46bde383f694e3f..ae77d60e80627c9580f2dc2568487aebf7ab623e 100644 --- a/app/src/main/java/se/leap/bitmaskclient/base/views/LocationButton.java +++ b/app/src/main/java/se/leap/bitmaskclient/base/views/LocationButton.java @@ -3,15 +3,17 @@ package se.leap.bitmaskclient.base.views; import android.content.Context; import android.util.AttributeSet; import android.view.LayoutInflater; -import android.view.View; import android.widget.RelativeLayout; +import androidx.annotation.ColorRes; import androidx.annotation.NonNull; import androidx.annotation.Nullable; +import androidx.annotation.StringRes; import androidx.appcompat.widget.AppCompatImageView; import androidx.appcompat.widget.AppCompatTextView; +import androidx.core.content.ContextCompat; -import se.leap.bitmaskclient.R; +import se.leap.bitmaskclient.databinding.VLocationButtonBinding; import se.leap.bitmaskclient.eip.GatewaysManager; public class LocationButton extends RelativeLayout { @@ -31,13 +33,16 @@ public class LocationButton extends RelativeLayout { } private void initLayout(Context context) { - LayoutInflater inflater = (LayoutInflater) context - .getSystemService(Context.LAYOUT_INFLATER_SERVICE); - View rootview = inflater.inflate(R.layout.v_location_button, this, true); - locationIndicator = rootview.findViewById(R.id.load_indicator); - textView = rootview.findViewById(R.id.text_location); - bridgeView = rootview.findViewById(R.id.bridge_icn); - recommendedView = rootview.findViewById(R.id.recommended_icn); + VLocationButtonBinding binding = VLocationButtonBinding.inflate(LayoutInflater.from(context), this, true); + locationIndicator = binding.loadIndicator; + textView = binding.textLocation; + bridgeView = binding.bridgeIcn; + recommendedView = binding.recommendedIcn; + + } + + public void setTextColor(@ColorRes int color) { + textView.setTextColor(ContextCompat.getColor(getContext(), color)); } public void setLocationLoad(GatewaysManager.Load load) { @@ -48,6 +53,10 @@ public class LocationButton extends RelativeLayout { textView.setText(text); } + public void setText(@StringRes int resId) { + textView.setText(resId); + } + public void showBridgeIndicator(boolean show) { bridgeView.setVisibility(show ? VISIBLE : GONE); } diff --git a/app/src/main/java/se/leap/bitmaskclient/base/views/MainButton.java b/app/src/main/java/se/leap/bitmaskclient/base/views/MainButton.java index c5ac45446c2a677cdd59cea58f8a4df38978effd..fc86fc0bc409f1cdde4b27451b1b7b3d6def638a 100644 --- a/app/src/main/java/se/leap/bitmaskclient/base/views/MainButton.java +++ b/app/src/main/java/se/leap/bitmaskclient/base/views/MainButton.java @@ -2,34 +2,21 @@ package se.leap.bitmaskclient.base.views; import android.annotation.TargetApi; import android.content.Context; -import android.graphics.PorterDuff; -import android.graphics.drawable.AnimationDrawable; import android.util.AttributeSet; import android.view.LayoutInflater; -import android.view.View; -import android.view.animation.AlphaAnimation; -import android.view.animation.Animation; import android.widget.RelativeLayout; -import androidx.annotation.ColorRes; -import androidx.annotation.DrawableRes; import androidx.appcompat.widget.AppCompatImageView; import androidx.core.content.ContextCompat; import se.leap.bitmaskclient.R; +import se.leap.bitmaskclient.databinding.VMainButtonBinding; public class MainButton extends RelativeLayout { private static final String TAG = MainButton.class.getSimpleName(); - AppCompatImageView glow; - AppCompatImageView shadowLight; - AnimationDrawable glowAnimation; - - private boolean isOn = false; - private boolean isProcessing = false; - private boolean isError = true; - + AppCompatImageView button; public MainButton(Context context) { super(context); @@ -54,71 +41,17 @@ public class MainButton extends RelativeLayout { } private void initLayout(Context context) { - LayoutInflater inflater = (LayoutInflater) context.getSystemService(Context.LAYOUT_INFLATER_SERVICE); - View rootview = inflater.inflate(R.layout.v_main_btn, this, true); - - glow = rootview.findViewById(R.id.vpn_btn_glow); - glowAnimation = (AnimationDrawable) glow.getBackground(); - shadowLight = rootview.findViewById(R.id.vpn_btn_shadow_light); - } - - - private void stopGlowAnimation() { - AlphaAnimation fadeOutAnimation = new AlphaAnimation(1.0f, 0.0f); - fadeOutAnimation.setDuration(300); - fadeOutAnimation.setAnimationListener(new Animation.AnimationListener() { - @Override - public void onAnimationStart(Animation animation) {} - - @Override - public void onAnimationEnd(Animation animation) { - glow.setVisibility(GONE); - glowAnimation.stop(); - } - - @Override - public void onAnimationRepeat(Animation animation) {} - }); - glow.startAnimation(fadeOutAnimation); - } - - private void startGlowAnimation() { - glow.setAlpha(1.0f); - glow.setVisibility(VISIBLE); - glowAnimation.start(); + VMainButtonBinding binding = VMainButtonBinding.inflate(LayoutInflater.from(context), this, true); + button = binding.button; } - public void updateState(boolean isOn, boolean isProcessing, boolean isError) { - if (this.isOn != isOn) { - this.isOn = isOn; - shadowLight.setVisibility(isOn ? VISIBLE : GONE); - } - - if (this.isProcessing != isProcessing) { - if (!isProcessing) { - stopGlowAnimation(); - } else { - startGlowAnimation(); - } - this.isProcessing = isProcessing; - } - - if (this.isError != isError) { - @DrawableRes int drawableResource = isOn ? R.drawable.on_off_btn_start_2_enabled : R.drawable.on_off_btn_start_2_disabled; - if (!isError) { - setImageWithTint(shadowLight, drawableResource, R.color.colorMainBtnHighlight); - } else { - setImageWithTint(shadowLight, drawableResource, R.color.colorMainBtnError); - } - this.isError = isError; + public void updateState(boolean isOn, boolean isProcessing) { + if (isProcessing) { + button.setImageDrawable(ContextCompat.getDrawable(getContext(), R.drawable.button_circle_cancel)); + } else { + button.setImageDrawable( + ContextCompat.getDrawable(getContext(), + isOn ? R.drawable.button_circle_stop : R.drawable.button_circle_start)); } } - - private void setImageWithTint(AppCompatImageView view, @DrawableRes int resourceId, @ColorRes int color) { - view.setImageDrawable(ContextCompat.getDrawable(getContext(), resourceId)); - view.setColorFilter(ContextCompat.getColor(getContext(), color), PorterDuff.Mode.SRC_ATOP); - } - - - } diff --git a/app/src/main/java/se/leap/bitmaskclient/base/views/SelectLocationEntry.java b/app/src/main/java/se/leap/bitmaskclient/base/views/SelectLocationEntry.java index 3d4f93ff6ed5d643597179ed34656e1985ac3482..554fe958404e8dd2fe2e32cda5e4eac74ae5080a 100644 --- a/app/src/main/java/se/leap/bitmaskclient/base/views/SelectLocationEntry.java +++ b/app/src/main/java/se/leap/bitmaskclient/base/views/SelectLocationEntry.java @@ -6,7 +6,6 @@ import android.util.AttributeSet; import android.view.LayoutInflater; import android.view.View; import android.widget.LinearLayout; -import android.widget.RelativeLayout; import androidx.appcompat.widget.AppCompatImageView; import androidx.appcompat.widget.AppCompatTextView; @@ -71,7 +70,7 @@ public class SelectLocationEntry extends LinearLayout { boolean supportsSelectedTransport = location.supportsTransport(transportType); locationText.setVisibility(hasData ? VISIBLE : GONE); locationIndicator.setVisibility(hasData ? VISIBLE : GONE); - bridgesView.setVisibility(transportType == OBFS4 && supportsSelectedTransport ? VISIBLE : GONE); + bridgesView.setVisibility(transportType.isPluggableTransport() && supportsSelectedTransport ? VISIBLE : GONE); locationText.setText(location.getName()); locationIndicator.setLoad(Load.getLoadByValue(location.getAverageLoad(transportType))); selectedView.setChecked(location.selected); diff --git a/app/src/main/java/se/leap/bitmaskclient/base/views/VpnStateImage.java b/app/src/main/java/se/leap/bitmaskclient/base/views/VpnStateImage.java deleted file mode 100644 index 2f8a444892600d5da5391b6cee928fa8ed491eb2..0000000000000000000000000000000000000000 --- a/app/src/main/java/se/leap/bitmaskclient/base/views/VpnStateImage.java +++ /dev/null @@ -1,99 +0,0 @@ -/** - * Copyright (c) 2018 LEAP Encryption Access Project and contributers - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see <http://www.gnu.org/licenses/>. - */ -package se.leap.bitmaskclient.base.views; - -import android.content.Context; -import androidx.constraintlayout.widget.ConstraintLayout; -import androidx.appcompat.widget.AppCompatImageView; -import android.util.AttributeSet; -import android.view.LayoutInflater; -import android.view.View; -import android.view.animation.AlphaAnimation; -import android.view.animation.Animation; -import android.widget.ProgressBar; - -import se.leap.bitmaskclient.R; - -/** - * Created by cyberta on 12.02.18. - */ - - -public class VpnStateImage extends ConstraintLayout { - - ProgressBar progressBar; - AppCompatImageView stateIcon; - - public VpnStateImage(Context context) { - super(context); - initLayout(context); - } - - public VpnStateImage(Context context, AttributeSet attrs) { - super(context, attrs); - initLayout(context); - } - - public VpnStateImage(Context context, AttributeSet attrs, int defStyleAttr) { - super(context, attrs, defStyleAttr); - initLayout(context); - } - - void initLayout(Context context) { - LayoutInflater inflater = (LayoutInflater) context - .getSystemService(Context.LAYOUT_INFLATER_SERVICE); - View rootview = inflater.inflate(R.layout.v_main_button, this, true); - stateIcon = rootview.findViewById(R.id.vpn_state_key); - progressBar = rootview.findViewById(R.id.progressBar); - progressBar.setIndeterminate(true); - } - - public void showProgress() { - progressBar.setVisibility(VISIBLE); - } - - - public void stopProgress(boolean animated) { - if (!animated) { - progressBar.setVisibility(GONE); - return; - } - - AlphaAnimation fadeOutAnimation = new AlphaAnimation(1.0f, 0.0f); - fadeOutAnimation.setDuration(1000); - fadeOutAnimation.setAnimationListener(new Animation.AnimationListener() { - @Override - public void onAnimationStart(Animation animation) {} - - @Override - public void onAnimationEnd(Animation animation) { - progressBar.setVisibility(GONE); - } - - @Override - public void onAnimationRepeat(Animation animation) {} - }); - - progressBar.startAnimation(fadeOutAnimation); - } - - public void setStateIcon(int resource) { - stateIcon.setImageResource(resource); - } - - -} diff --git a/app/src/main/java/se/leap/bitmaskclient/eip/EIP.java b/app/src/main/java/se/leap/bitmaskclient/eip/EIP.java index cf4dc9bf9544cc2552e65965917b4536cbae3495..88cdc715b3a6c42c7286337e37629910a66dacb9 100644 --- a/app/src/main/java/se/leap/bitmaskclient/eip/EIP.java +++ b/app/src/main/java/se/leap/bitmaskclient/eip/EIP.java @@ -16,6 +16,36 @@ */ package se.leap.bitmaskclient.eip; +import static android.app.Activity.RESULT_CANCELED; +import static android.app.Activity.RESULT_OK; +import static se.leap.bitmaskclient.R.string.vpn_certificate_is_invalid; +import static se.leap.bitmaskclient.R.string.warning_client_parsing_error_gateways; +import static se.leap.bitmaskclient.base.models.Constants.BROADCAST_GATEWAY_SETUP_OBSERVER_EVENT; +import static se.leap.bitmaskclient.base.models.Constants.BROADCAST_RESULT_KEY; +import static se.leap.bitmaskclient.base.models.Constants.CLEARLOG; +import static se.leap.bitmaskclient.base.models.Constants.EIP_ACTION_CHECK_CERT_VALIDITY; +import static se.leap.bitmaskclient.base.models.Constants.EIP_ACTION_IS_RUNNING; +import static se.leap.bitmaskclient.base.models.Constants.EIP_ACTION_LAUNCH_VPN; +import static se.leap.bitmaskclient.base.models.Constants.EIP_ACTION_START; +import static se.leap.bitmaskclient.base.models.Constants.EIP_ACTION_START_ALWAYS_ON_VPN; +import static se.leap.bitmaskclient.base.models.Constants.EIP_ACTION_START_BLOCKING_VPN; +import static se.leap.bitmaskclient.base.models.Constants.EIP_ACTION_STOP; +import static se.leap.bitmaskclient.base.models.Constants.EIP_ACTION_STOP_BLOCKING_VPN; +import static se.leap.bitmaskclient.base.models.Constants.EIP_EARLY_ROUTES; +import static se.leap.bitmaskclient.base.models.Constants.EIP_N_CLOSEST_GATEWAY; +import static se.leap.bitmaskclient.base.models.Constants.EIP_RECEIVER; +import static se.leap.bitmaskclient.base.models.Constants.EIP_RESTART_ON_BOOT; +import static se.leap.bitmaskclient.base.models.Constants.PROVIDER_PROFILE; +import static se.leap.bitmaskclient.base.models.Constants.PROVIDER_VPN_CERTIFICATE; +import static se.leap.bitmaskclient.base.models.Constants.SHARED_PREFERENCES; +import static se.leap.bitmaskclient.base.utils.ConfigHelper.ensureNotOnMainThread; +import static se.leap.bitmaskclient.base.utils.PreferenceHelper.getPreferredCity; +import static se.leap.bitmaskclient.eip.EIP.EIPErrors.ERROR_INVALID_PROFILE; +import static se.leap.bitmaskclient.eip.EIP.EIPErrors.ERROR_INVALID_VPN_CERTIFICATE; +import static se.leap.bitmaskclient.eip.EIP.EIPErrors.ERROR_VPN_PREPARE; +import static se.leap.bitmaskclient.eip.EIP.EIPErrors.NO_MORE_GATEWAYS; +import static se.leap.bitmaskclient.eip.EipResultBroadcast.tellToReceiverOrBroadcast; + import android.annotation.SuppressLint; import android.content.ComponentName; import android.content.Context; @@ -31,6 +61,7 @@ import android.os.ResultReceiver; import android.util.Log; import androidx.annotation.NonNull; +import androidx.annotation.Nullable; import androidx.annotation.StringRes; import androidx.annotation.WorkerThread; import androidx.core.app.JobIntentService; @@ -56,42 +87,11 @@ import de.blinkt.openvpn.core.VpnStatus; import de.blinkt.openvpn.core.connection.Connection; import se.leap.bitmaskclient.R; import se.leap.bitmaskclient.base.OnBootReceiver; +import se.leap.bitmaskclient.base.models.Provider; +import se.leap.bitmaskclient.base.models.Pair; import se.leap.bitmaskclient.base.models.ProviderObservable; import se.leap.bitmaskclient.base.utils.PreferenceHelper; -import static android.app.Activity.RESULT_CANCELED; -import static android.app.Activity.RESULT_OK; -import static de.blinkt.openvpn.core.connection.Connection.TransportType.OBFS4; -import static de.blinkt.openvpn.core.connection.Connection.TransportType.OPENVPN; -import static se.leap.bitmaskclient.R.string.vpn_certificate_is_invalid; -import static se.leap.bitmaskclient.R.string.warning_client_parsing_error_gateways; -import static se.leap.bitmaskclient.base.models.Constants.BROADCAST_GATEWAY_SETUP_OBSERVER_EVENT; -import static se.leap.bitmaskclient.base.models.Constants.BROADCAST_RESULT_KEY; -import static se.leap.bitmaskclient.base.models.Constants.CLEARLOG; -import static se.leap.bitmaskclient.base.models.Constants.EIP_ACTION_CHECK_CERT_VALIDITY; -import static se.leap.bitmaskclient.base.models.Constants.EIP_ACTION_IS_RUNNING; -import static se.leap.bitmaskclient.base.models.Constants.EIP_ACTION_LAUNCH_VPN; -import static se.leap.bitmaskclient.base.models.Constants.EIP_ACTION_START; -import static se.leap.bitmaskclient.base.models.Constants.EIP_ACTION_START_ALWAYS_ON_VPN; -import static se.leap.bitmaskclient.base.models.Constants.EIP_ACTION_START_BLOCKING_VPN; -import static se.leap.bitmaskclient.base.models.Constants.EIP_ACTION_STOP; -import static se.leap.bitmaskclient.base.models.Constants.EIP_ACTION_STOP_BLOCKING_VPN; -import static se.leap.bitmaskclient.base.models.Constants.EIP_EARLY_ROUTES; -import static se.leap.bitmaskclient.base.models.Constants.EIP_N_CLOSEST_GATEWAY; -import static se.leap.bitmaskclient.base.models.Constants.EIP_RECEIVER; -import static se.leap.bitmaskclient.base.models.Constants.EIP_RESTART_ON_BOOT; -import static se.leap.bitmaskclient.base.models.Constants.PROVIDER_PROFILE; -import static se.leap.bitmaskclient.base.models.Constants.PROVIDER_VPN_CERTIFICATE; -import static se.leap.bitmaskclient.base.models.Constants.SHARED_PREFERENCES; -import static se.leap.bitmaskclient.base.utils.ConfigHelper.ensureNotOnMainThread; -import static se.leap.bitmaskclient.base.utils.PreferenceHelper.getPreferredCity; -import static se.leap.bitmaskclient.base.utils.PreferenceHelper.getUseBridges; -import static se.leap.bitmaskclient.eip.EIP.EIPErrors.ERROR_INVALID_PROFILE; -import static se.leap.bitmaskclient.eip.EIP.EIPErrors.ERROR_INVALID_VPN_CERTIFICATE; -import static se.leap.bitmaskclient.eip.EIP.EIPErrors.ERROR_VPN_PREPARE; -import static se.leap.bitmaskclient.eip.EIP.EIPErrors.NO_MORE_GATEWAYS; -import static se.leap.bitmaskclient.eip.EipResultBroadcast.tellToReceiverOrBroadcast; - /** * EIP is the abstract base class for interacting with and managing the Encrypted * Internet Proxy connection. Connections are started, stopped, and queried through @@ -242,6 +242,12 @@ public final class EIP extends JobIntentService implements Observer { return; } + if (shouldUpdateVPNCertificate()) { + Provider p = ProviderObservable.getInstance().getCurrentProvider(); + p.setShouldUpdateVpnCertificate(true); + ProviderObservable.getInstance().updateProvider(p); + } + GatewaysManager gatewaysManager = new GatewaysManager(getApplicationContext()); if (gatewaysManager.isEmpty()) { setErrorResult(result, warning_client_parsing_error_gateways, null); @@ -249,8 +255,8 @@ public final class EIP extends JobIntentService implements Observer { return; } - Gateway gateway = gatewaysManager.select(nClosestGateway); - launchActiveGateway(gateway, nClosestGateway, result); + Pair<Gateway, Connection.TransportType> gatewayTransportTypePair = gatewaysManager.select(nClosestGateway); + launchActiveGateway(gatewayTransportTypePair, nClosestGateway, result); if (result.containsKey(BROADCAST_RESULT_KEY) && !result.getBoolean(BROADCAST_RESULT_KEY)) { tellToReceiverOrBroadcast(this, EIP_ACTION_START, RESULT_CANCELED, result); } else { @@ -264,10 +270,16 @@ public final class EIP extends JobIntentService implements Observer { */ private void startEIPAlwaysOnVpn() { GatewaysManager gatewaysManager = new GatewaysManager(getApplicationContext()); - Gateway gateway = gatewaysManager.select(0); + Pair<Gateway, Connection.TransportType> gatewayTransportTypePair = gatewaysManager.select(0); Bundle result = new Bundle(); - launchActiveGateway(gateway, 0, result); + if (shouldUpdateVPNCertificate()) { + Provider p = ProviderObservable.getInstance().getCurrentProvider(); + p.setShouldUpdateVpnCertificate(true); + ProviderObservable.getInstance().updateProvider(p); + } + + launchActiveGateway(gatewayTransportTypePair, 0, result); if (result.containsKey(BROADCAST_RESULT_KEY) && !result.getBoolean(BROADCAST_RESULT_KEY)){ VpnStatus.logWarning("ALWAYS-ON VPN: " + getString(R.string.no_vpn_profiles_defined)); } @@ -311,13 +323,13 @@ public final class EIP extends JobIntentService implements Observer { /** * starts the VPN and connects to the given gateway * - * @param gateway to connect to + * @param gatewayTransportTypePair Pair of Gateway and associated transport used to connect */ - private void launchActiveGateway(Gateway gateway, int nClosestGateway, Bundle result) { + private void launchActiveGateway(@Nullable Pair<Gateway, Connection.TransportType> gatewayTransportTypePair, int nClosestGateway, Bundle result) { VpnProfile profile; - Connection.TransportType transportType = getUseBridges(this) ? OBFS4 : OPENVPN; - if (gateway == null || - (profile = gateway.getProfile(transportType)) == null) { + + if (gatewayTransportTypePair == null || gatewayTransportTypePair.first == null || + (profile = gatewayTransportTypePair.first.getProfile(gatewayTransportTypePair.second)) == null) { String preferredLocation = getPreferredCity(getApplicationContext()); if (preferredLocation != null) { setErrorResult(result, NO_MORE_GATEWAYS.toString(), getStringResourceForNoMoreGateways(), getString(R.string.app_name), preferredLocation); @@ -415,6 +427,12 @@ public final class EIP extends JobIntentService implements Observer { return validator.isValid(); } + private boolean shouldUpdateVPNCertificate() { + VpnCertificateValidator validator = new VpnCertificateValidator(preferences.getString(PROVIDER_VPN_CERTIFICATE, "")); + return validator.shouldBeUpdated(); + } + + /** * helper function to add error to result bundle * @@ -576,7 +594,7 @@ public final class EIP extends JobIntentService implements Observer { } public static class VoidVpnServiceConnection implements Closeable { - private final Context context; + private Context context; private ServiceConnection serviceConnection; private VoidVpnService voidVpnService; @@ -590,6 +608,9 @@ public final class EIP extends JobIntentService implements Observer { @Override public void close() { context.unbindService(serviceConnection); + serviceConnection = null; + voidVpnService = null; + context = null; } private void initSynchronizedServiceConnection(final Context context) throws InterruptedException { @@ -631,7 +652,7 @@ public final class EIP extends JobIntentService implements Observer { */ @WorkerThread public static class OpenVpnServiceConnection implements Closeable { - private final Context context; + private Context context; private ServiceConnection serviceConnection; private IOpenVPNServiceInternal service; @@ -668,6 +689,9 @@ public final class EIP extends JobIntentService implements Observer { @Override public void close() { context.unbindService(serviceConnection); + serviceConnection = null; + service = null; + context = null; } public IOpenVPNServiceInternal getService() { diff --git a/app/src/main/java/se/leap/bitmaskclient/eip/EipSetupObserver.java b/app/src/main/java/se/leap/bitmaskclient/eip/EipSetupObserver.java index beed35d15ac1994defd4d9dc050034c4db480f3b..85cdb06c6b288ac95cfd24a8db080c1107880aaa 100644 --- a/app/src/main/java/se/leap/bitmaskclient/eip/EipSetupObserver.java +++ b/app/src/main/java/se/leap/bitmaskclient/eip/EipSetupObserver.java @@ -1,5 +1,5 @@ /** - * Copyright (c) 2020 LEAP Encryption Access Project and contributers + * Copyright (c) 2021 LEAP Encryption Access Project and contributers * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -17,6 +17,41 @@ package se.leap.bitmaskclient.eip; +import static android.app.Activity.RESULT_CANCELED; +import static android.content.Intent.CATEGORY_DEFAULT; +import static de.blinkt.openvpn.core.ConnectionStatus.LEVEL_CONNECTING_NO_SERVER_REPLY_YET; +import static de.blinkt.openvpn.core.ConnectionStatus.LEVEL_NOTCONNECTED; +import static se.leap.bitmaskclient.appUpdate.DownloadServiceCommand.CHECK_VERSION_FILE; +import static se.leap.bitmaskclient.base.models.Constants.BROADCAST_EIP_EVENT; +import static se.leap.bitmaskclient.base.models.Constants.BROADCAST_GATEWAY_SETUP_OBSERVER_EVENT; +import static se.leap.bitmaskclient.base.models.Constants.BROADCAST_PROVIDER_API_EVENT; +import static se.leap.bitmaskclient.base.models.Constants.BROADCAST_RESULT_CODE; +import static se.leap.bitmaskclient.base.models.Constants.BROADCAST_RESULT_KEY; +import static se.leap.bitmaskclient.base.models.Constants.EIP_ACTION_LAUNCH_VPN; +import static se.leap.bitmaskclient.base.models.Constants.EIP_ACTION_PREPARE_VPN; +import static se.leap.bitmaskclient.base.models.Constants.EIP_ACTION_START; +import static se.leap.bitmaskclient.base.models.Constants.EIP_ACTION_START_ALWAYS_ON_VPN; +import static se.leap.bitmaskclient.base.models.Constants.EIP_EARLY_ROUTES; +import static se.leap.bitmaskclient.base.models.Constants.EIP_N_CLOSEST_GATEWAY; +import static se.leap.bitmaskclient.base.models.Constants.EIP_REQUEST; +import static se.leap.bitmaskclient.base.models.Constants.PROVIDER_KEY; +import static se.leap.bitmaskclient.base.models.Constants.PROVIDER_PROFILE; +import static se.leap.bitmaskclient.providersetup.ProviderAPI.CORRECTLY_DOWNLOADED_EIP_SERVICE; +import static se.leap.bitmaskclient.providersetup.ProviderAPI.CORRECTLY_DOWNLOADED_GEOIP_JSON; +import static se.leap.bitmaskclient.providersetup.ProviderAPI.CORRECTLY_UPDATED_INVALID_VPN_CERTIFICATE; +import static se.leap.bitmaskclient.providersetup.ProviderAPI.DELAY; +import static se.leap.bitmaskclient.providersetup.ProviderAPI.DOWNLOAD_MOTD; +import static se.leap.bitmaskclient.providersetup.ProviderAPI.INCORRECTLY_DOWNLOADED_EIP_SERVICE; +import static se.leap.bitmaskclient.providersetup.ProviderAPI.INCORRECTLY_DOWNLOADED_GEOIP_JSON; +import static se.leap.bitmaskclient.providersetup.ProviderAPI.INCORRECTLY_DOWNLOADED_VPN_CERTIFICATE; +import static se.leap.bitmaskclient.providersetup.ProviderAPI.INCORRECTLY_UPDATED_INVALID_VPN_CERTIFICATE; +import static se.leap.bitmaskclient.providersetup.ProviderAPI.PROVIDER_NOK; +import static se.leap.bitmaskclient.providersetup.ProviderAPI.PROVIDER_OK; +import static se.leap.bitmaskclient.providersetup.ProviderAPI.QUIETLY_UPDATE_VPN_CERTIFICATE; +import static se.leap.bitmaskclient.providersetup.ProviderAPI.TOR_EXCEPTION; +import static se.leap.bitmaskclient.providersetup.ProviderAPI.TOR_TIMEOUT; +import static se.leap.bitmaskclient.providersetup.ProviderAPI.UPDATE_INVALID_VPN_CERTIFICATE; + import android.content.BroadcastReceiver; import android.content.Context; import android.content.Intent; @@ -45,39 +80,8 @@ import se.leap.bitmaskclient.base.utils.PreferenceHelper; import se.leap.bitmaskclient.providersetup.ProviderAPI; import se.leap.bitmaskclient.providersetup.ProviderAPICommand; import se.leap.bitmaskclient.tor.TorServiceCommand; -import se.leap.bitmaskclient.tor.TorServiceConnection; import se.leap.bitmaskclient.tor.TorStatusObservable; -import static android.app.Activity.RESULT_CANCELED; -import static android.content.Intent.CATEGORY_DEFAULT; -import static de.blinkt.openvpn.core.ConnectionStatus.LEVEL_CONNECTING_NO_SERVER_REPLY_YET; -import static de.blinkt.openvpn.core.ConnectionStatus.LEVEL_NOTCONNECTED; -import static se.leap.bitmaskclient.appUpdate.DownloadServiceCommand.CHECK_VERSION_FILE; -import static se.leap.bitmaskclient.base.models.Constants.BROADCAST_EIP_EVENT; -import static se.leap.bitmaskclient.base.models.Constants.BROADCAST_GATEWAY_SETUP_OBSERVER_EVENT; -import static se.leap.bitmaskclient.base.models.Constants.BROADCAST_PROVIDER_API_EVENT; -import static se.leap.bitmaskclient.base.models.Constants.BROADCAST_RESULT_CODE; -import static se.leap.bitmaskclient.base.models.Constants.BROADCAST_RESULT_KEY; -import static se.leap.bitmaskclient.base.models.Constants.EIP_ACTION_LAUNCH_VPN; -import static se.leap.bitmaskclient.base.models.Constants.EIP_ACTION_PREPARE_VPN; -import static se.leap.bitmaskclient.base.models.Constants.EIP_ACTION_START; -import static se.leap.bitmaskclient.base.models.Constants.EIP_ACTION_START_ALWAYS_ON_VPN; -import static se.leap.bitmaskclient.base.models.Constants.EIP_EARLY_ROUTES; -import static se.leap.bitmaskclient.base.models.Constants.EIP_N_CLOSEST_GATEWAY; -import static se.leap.bitmaskclient.base.models.Constants.EIP_REQUEST; -import static se.leap.bitmaskclient.base.models.Constants.PROVIDER_KEY; -import static se.leap.bitmaskclient.base.models.Constants.PROVIDER_PROFILE; -import static se.leap.bitmaskclient.providersetup.ProviderAPI.CORRECTLY_DOWNLOADED_EIP_SERVICE; -import static se.leap.bitmaskclient.providersetup.ProviderAPI.CORRECTLY_DOWNLOADED_GEOIP_JSON; -import static se.leap.bitmaskclient.providersetup.ProviderAPI.CORRECTLY_UPDATED_INVALID_VPN_CERTIFICATE; -import static se.leap.bitmaskclient.providersetup.ProviderAPI.INCORRECTLY_DOWNLOADED_EIP_SERVICE; -import static se.leap.bitmaskclient.providersetup.ProviderAPI.INCORRECTLY_DOWNLOADED_GEOIP_JSON; -import static se.leap.bitmaskclient.providersetup.ProviderAPI.INCORRECTLY_DOWNLOADED_VPN_CERTIFICATE; -import static se.leap.bitmaskclient.providersetup.ProviderAPI.INCORRECTLY_UPDATED_INVALID_VPN_CERTIFICATE; -import static se.leap.bitmaskclient.providersetup.ProviderAPI.PROVIDER_NOK; -import static se.leap.bitmaskclient.providersetup.ProviderAPI.PROVIDER_OK; -import static se.leap.bitmaskclient.tor.TorStatusObservable.TorStatus.OFF; - /** * Created by cyberta on 05.12.18. */ @@ -86,7 +90,7 @@ public class EipSetupObserver extends BroadcastReceiver implements VpnStatus.Sta private static final String TAG = EipSetupObserver.class.getName(); private static final int UPDATE_CHECK_TIMEOUT = 1000*60*60*24*7; - private Context context; + private final Context appContext; private VpnProfile setupVpnProfile; private String observedProfileFromVpnStatus; AtomicInteger reconnectTry = new AtomicInteger(); @@ -97,7 +101,7 @@ public class EipSetupObserver extends BroadcastReceiver implements VpnStatus.Sta private static EipSetupObserver instance; private EipSetupObserver(Context context, SharedPreferences preferences) { - this.context = context; + this.appContext = context.getApplicationContext(); this.preferences = preferences; IntentFilter updateIntentFilter = new IntentFilter(BROADCAST_GATEWAY_SETUP_OBSERVER_EVENT); updateIntentFilter.addAction(BROADCAST_EIP_EVENT); @@ -105,7 +109,7 @@ public class EipSetupObserver extends BroadcastReceiver implements VpnStatus.Sta updateIntentFilter.addAction(TorService.ACTION_STATUS); updateIntentFilter.addAction(TorService.ACTION_ERROR); updateIntentFilter.addCategory(CATEGORY_DEFAULT); - LocalBroadcastManager.getInstance(context.getApplicationContext()).registerReceiver(this, updateIntentFilter); + LocalBroadcastManager.getInstance(context).registerReceiver(this, updateIntentFilter); instance = this; VpnStatus.addLogListener(this); } @@ -174,7 +178,7 @@ public class EipSetupObserver extends BroadcastReceiver implements VpnStatus.Sta Log.d(TAG, "handle Tor status event: " + status); Integer bootstrap = intent.getIntExtra(TorService.EXTRA_STATUS_DETAIL_BOOTSTRAP, -1); String logKey = intent.getStringExtra(TorService.EXTRA_STATUS_DETAIL_LOGKEY); - TorStatusObservable.updateState(context, status, bootstrap, logKey); + TorStatusObservable.updateState(appContext, status, bootstrap, logKey); } @@ -193,14 +197,18 @@ public class EipSetupObserver extends BroadcastReceiver implements VpnStatus.Sta ProviderObservable.getInstance().updateProvider(provider); PreferenceHelper.storeProviderInPreferences(preferences, provider); if (EipStatus.getInstance().isDisconnected()) { - EipCommand.startVPN(context, false); + EipCommand.startVPN(appContext, false); } break; case CORRECTLY_UPDATED_INVALID_VPN_CERTIFICATE: provider = resultData.getParcelable(PROVIDER_KEY); ProviderObservable.getInstance().updateProvider(provider); PreferenceHelper.storeProviderInPreferences(preferences, provider); - EipCommand.startVPN(context, false); + EipCommand.startVPN(appContext, false); + EipStatus.getInstance().setUpdatingVpnCert(false); + if (TorStatusObservable.isRunning()) { + TorServiceCommand.stopTorServiceAsync(appContext); + } break; case CORRECTLY_DOWNLOADED_GEOIP_JSON: provider = resultData.getParcelable(PROVIDER_KEY); @@ -211,18 +219,35 @@ public class EipSetupObserver extends BroadcastReceiver implements VpnStatus.Sta case INCORRECTLY_DOWNLOADED_GEOIP_JSON: maybeStartEipService(resultData); break; - case PROVIDER_NOK: case INCORRECTLY_UPDATED_INVALID_VPN_CERTIFICATE: + EipStatus.getInstance().setUpdatingVpnCert(false); + if (TorStatusObservable.isRunning()) { + TorServiceCommand.stopTorServiceAsync(appContext); + } + break; + case PROVIDER_NOK: case INCORRECTLY_DOWNLOADED_EIP_SERVICE: case INCORRECTLY_DOWNLOADED_VPN_CERTIFICATE: - if (TorStatusObservable.getStatus() != OFF) { - TorServiceCommand.stopTorServiceAsync(context); + if (TorStatusObservable.isRunning()) { + TorServiceCommand.stopTorServiceAsync(appContext); } Log.d(TAG, "PROVIDER NOK - FETCH FAILED"); break; case PROVIDER_OK: Log.d(TAG, "PROVIDER OK - FETCH SUCCESSFUL"); break; + case TOR_TIMEOUT: + case TOR_EXCEPTION: + try { + JSONObject jsonObject = new JSONObject(resultData.getString(ProviderAPI.ERRORS)); + String initialAction = jsonObject.optString(ProviderAPI.INITIAL_ACTION); + if (UPDATE_INVALID_VPN_CERTIFICATE.equals(initialAction)) { + EipStatus.getInstance().setUpdatingVpnCert(false); + } + } catch (Exception e) { + //ignore + } + break; default: break; } @@ -235,7 +260,7 @@ public class EipSetupObserver extends BroadcastReceiver implements VpnStatus.Sta private void maybeStartEipService(Bundle resultData) { if (resultData.getBoolean(EIP_ACTION_START)) { boolean earlyRoutes = resultData.getBoolean(EIP_EARLY_ROUTES); - EipCommand.startVPN(context, earlyRoutes); + EipCommand.startVPN(appContext, earlyRoutes); } } @@ -262,14 +287,14 @@ public class EipSetupObserver extends BroadcastReceiver implements VpnStatus.Sta switch (error) { case NO_MORE_GATEWAYS: finishGatewaySetup(false); - EipCommand.startBlockingVPN(context); + EipCommand.startBlockingVPN(appContext); break; case ERROR_INVALID_PROFILE: selectNextGateway(); break; default: finishGatewaySetup(false); - EipCommand.stopVPN(context); + EipCommand.stopVPN(appContext); EipStatus.refresh(); } } @@ -345,11 +370,27 @@ public class EipSetupObserver extends BroadcastReceiver implements VpnStatus.Sta Provider provider = ProviderObservable.getInstance().getCurrentProvider(); if (setupNClosestGateway.get() > 0 || provider.shouldUpdateEipServiceJson()) { //setupNClostestGateway > 0: at least one failed gateway -> did the provider change it's gateways? - ProviderAPICommand.execute(context, ProviderAPI.DOWNLOAD_SERVICE_JSON, provider); + Bundle parameters = new Bundle(); + parameters.putLong(DELAY, 500); + ProviderAPICommand.execute(appContext, ProviderAPI.DOWNLOAD_SERVICE_JSON, parameters, provider); } if (shouldCheckAppUpdate()) { - DownloadServiceCommand.execute(context, CHECK_VERSION_FILE); + Bundle parameters = new Bundle(); + parameters.putLong(DELAY, 500); + DownloadServiceCommand.execute(appContext, CHECK_VERSION_FILE, parameters); + } + + if (provider.shouldUpdateVpnCertificate()) { + Bundle parameters = new Bundle(); + parameters.putLong(DELAY, 500); + ProviderAPICommand.execute(appContext, QUIETLY_UPDATE_VPN_CERTIFICATE, parameters, provider); + } + + if (provider.shouldUpdateMotdJson()) { + Bundle parameters = new Bundle(); + parameters.putLong(DELAY, 500); + ProviderAPICommand.execute(appContext, DOWNLOAD_MOTD, parameters, provider); } finishGatewaySetup(false); } else if ("TCP_CONNECT".equals(state)) { @@ -358,13 +399,13 @@ public class EipSetupObserver extends BroadcastReceiver implements VpnStatus.Sta } private boolean shouldCheckAppUpdate() { - return System.currentTimeMillis() - PreferenceHelper.getLastAppUpdateCheck(context) >= UPDATE_CHECK_TIMEOUT; + return System.currentTimeMillis() - PreferenceHelper.getLastAppUpdateCheck(appContext) >= UPDATE_CHECK_TIMEOUT; } private void selectNextGateway() { changingGateway.set(true); reconnectTry.set(0); - EipCommand.startVPN(context, false, setupNClosestGateway.get() + 1); + EipCommand.startVPN(appContext, false, setupNClosestGateway.get() + 1); } private void finishGatewaySetup(boolean changingGateway) { @@ -374,8 +415,8 @@ public class EipSetupObserver extends BroadcastReceiver implements VpnStatus.Sta observedProfileFromVpnStatus = null; this.changingGateway.set(changingGateway); this.reconnectTry.set(0); - if (TorStatusObservable.getStatus() != OFF) { - TorServiceCommand.stopTorServiceAsync(context); + if (TorStatusObservable.isRunning()) { + TorServiceCommand.stopTorServiceAsync(appContext); } } @@ -396,9 +437,9 @@ public class EipSetupObserver extends BroadcastReceiver implements VpnStatus.Sta case SHAPESHIFTER: VpnProfile profile = VpnStatus.getLastConnectedVpnProfile(); if (profile == null) { - EipCommand.startVPN(context, false, 0); + EipCommand.startVPN(appContext, false, 0); } else { - GatewaysManager gatewaysManager = new GatewaysManager(context.getApplicationContext()); + GatewaysManager gatewaysManager = new GatewaysManager(appContext); int position = gatewaysManager.getPosition(profile); setupNClosestGateway.set(position >= 0 ? position : 0); selectNextGateway(); diff --git a/app/src/main/java/se/leap/bitmaskclient/eip/EipStatus.java b/app/src/main/java/se/leap/bitmaskclient/eip/EipStatus.java index bc1236833878a1360a5503d331f52443d8c5b34f..9244f531d60f477ec97da8d3f21ed8900ac47f73 100644 --- a/app/src/main/java/se/leap/bitmaskclient/eip/EipStatus.java +++ b/app/src/main/java/se/leap/bitmaskclient/eip/EipStatus.java @@ -16,6 +16,8 @@ */ package se.leap.bitmaskclient.eip; +import static de.blinkt.openvpn.core.ConnectionStatus.LEVEL_NONETWORK; + import android.content.Context; import android.os.AsyncTask; import androidx.annotation.VisibleForTesting; @@ -56,6 +58,7 @@ public class EipStatus extends Observable implements VpnStatus.StateListener { private int lastErrorLine = 0; private String state, logMessage; private int localizedResId; + private boolean isUpdatingVPNCertificate; public static EipStatus getInstance() { if (currentStatus == null) { @@ -91,6 +94,11 @@ public class EipStatus extends Observable implements VpnStatus.StateListener { return "RECONNECTING".equals(currentStatus.getState()); } + public boolean isVPNRunningWithoutNetwork() { + return currentStatus.getLevel() == LEVEL_NONETWORK && + !"NO_PROCESS".equals(currentStatus.getState()); + } + private void setEipLevel(ConnectionStatus level) { switch (level) { case LEVEL_CONNECTED: @@ -128,8 +136,7 @@ public class EipStatus extends Observable implements VpnStatus.StateListener { } } - @VisibleForTesting - EipLevel getEipLevel() { + public EipLevel getEipLevel() { return currentEipLevel; } @@ -178,6 +185,15 @@ public class EipStatus extends Observable implements VpnStatus.StateListener { } } + public void setUpdatingVpnCert(boolean isUpdating) { + isUpdatingVPNCertificate = isUpdating; + refresh(); + } + + public boolean isUpdatingVpnCert() { + return isUpdatingVPNCertificate; + } + public boolean isConnecting() { return currentEipLevel == EipLevel.CONNECTING; } diff --git a/app/src/main/java/se/leap/bitmaskclient/eip/Gateway.java b/app/src/main/java/se/leap/bitmaskclient/eip/Gateway.java index 6050736351c843807608df0be1d65c6c67a8bbf4..929935ebe77452f7320bc89650980253ecf44195 100644 --- a/app/src/main/java/se/leap/bitmaskclient/eip/Gateway.java +++ b/app/src/main/java/se/leap/bitmaskclient/eip/Gateway.java @@ -16,6 +16,26 @@ */ package se.leap.bitmaskclient.eip; +import static se.leap.bitmaskclient.base.models.Constants.FULLNESS; +import static se.leap.bitmaskclient.base.models.Constants.HOST; +import static se.leap.bitmaskclient.base.models.Constants.IP_ADDRESS; +import static se.leap.bitmaskclient.base.models.Constants.LOCATION; +import static se.leap.bitmaskclient.base.models.Constants.LOCATIONS; +import static se.leap.bitmaskclient.base.models.Constants.NAME; +import static se.leap.bitmaskclient.base.models.Constants.OPENVPN_CONFIGURATION; +import static se.leap.bitmaskclient.base.models.Constants.OVERLOAD; +import static se.leap.bitmaskclient.base.models.Constants.TIMEZONE; +import static se.leap.bitmaskclient.base.models.Constants.VERSION; +import static se.leap.bitmaskclient.base.utils.PreferenceHelper.allowExperimentalTransports; +import static se.leap.bitmaskclient.base.utils.PreferenceHelper.getExcludedApps; +import static se.leap.bitmaskclient.base.utils.PreferenceHelper.getObfuscationPinningCert; +import static se.leap.bitmaskclient.base.utils.PreferenceHelper.getObfuscationPinningGatewayLocation; +import static se.leap.bitmaskclient.base.utils.PreferenceHelper.getObfuscationPinningIP; +import static se.leap.bitmaskclient.base.utils.PreferenceHelper.getObfuscationPinningKCP; +import static se.leap.bitmaskclient.base.utils.PreferenceHelper.getObfuscationPinningPort; +import static se.leap.bitmaskclient.base.utils.PreferenceHelper.getPreferUDP; +import static se.leap.bitmaskclient.base.utils.PreferenceHelper.useObfuscationPinning; + import android.content.Context; import androidx.annotation.NonNull; @@ -28,24 +48,12 @@ import org.json.JSONObject; import java.io.IOException; import java.util.HashMap; import java.util.HashSet; -import java.util.Set; import de.blinkt.openvpn.VpnProfile; import de.blinkt.openvpn.core.ConfigParser; import de.blinkt.openvpn.core.connection.Connection; +import se.leap.bitmaskclient.R; import se.leap.bitmaskclient.base.utils.ConfigHelper; -import se.leap.bitmaskclient.base.utils.PreferenceHelper; - -import static se.leap.bitmaskclient.base.models.Constants.FULLNESS; -import static se.leap.bitmaskclient.base.models.Constants.HOST; -import static se.leap.bitmaskclient.base.models.Constants.IP_ADDRESS; -import static se.leap.bitmaskclient.base.models.Constants.LOCATION; -import static se.leap.bitmaskclient.base.models.Constants.LOCATIONS; -import static se.leap.bitmaskclient.base.models.Constants.NAME; -import static se.leap.bitmaskclient.base.models.Constants.OPENVPN_CONFIGURATION; -import static se.leap.bitmaskclient.base.models.Constants.OVERLOAD; -import static se.leap.bitmaskclient.base.models.Constants.TIMEZONE; -import static se.leap.bitmaskclient.base.models.Constants.VERSION; /** * Gateway provides objects defining gateways and their metadata. @@ -87,28 +95,37 @@ public class Gateway { this.secrets = secrets; this.load = load; + apiVersion = getApiVersion(eipDefinition); + VpnConfigGenerator.Configuration configuration = getProfileConfig(context, eipDefinition, apiVersion); generalConfiguration = getGeneralConfiguration(eipDefinition); timezone = getTimezone(eipDefinition); - name = locationAsName(eipDefinition); - apiVersion = getApiVersion(eipDefinition); - vpnProfiles = createVPNProfiles(context); + name = configuration.profileName; + vpnProfiles = createVPNProfiles(configuration); + } + + private VpnConfigGenerator.Configuration getProfileConfig(Context context, JSONObject eipDefinition, int apiVersion) { + VpnConfigGenerator.Configuration config = new VpnConfigGenerator.Configuration(); + config.apiVersion = apiVersion; + config.preferUDP = getPreferUDP(context); + config.experimentalTransports = allowExperimentalTransports(context); + config.excludedApps = getExcludedApps(context); + + config.remoteGatewayIP = config.useObfuscationPinning ? getObfuscationPinningIP(context) : gateway.optString(IP_ADDRESS); + config.useObfuscationPinning = useObfuscationPinning(context); + config.profileName = config.useObfuscationPinning ? getObfuscationPinningGatewayLocation(context) : locationAsName(eipDefinition); + if (config.useObfuscationPinning) { + config.obfuscationProxyIP = getObfuscationPinningIP(context); + config.obfuscationProxyPort = getObfuscationPinningPort(context); + config.obfuscationProxyCert = getObfuscationPinningCert(context); + config.obfuscationProxyKCP = getObfuscationPinningKCP(context); + } + return config; } public void updateLoad(JSONObject load) { this.load = load; } - private void addProfileInfos(Context context, HashMap<Connection.TransportType, VpnProfile> profiles) { - Set<String> excludedAppsVpn = PreferenceHelper.getExcludedApps(context); - for (VpnProfile profile : profiles.values()) { - profile.mName = name; - profile.mGatewayIp = gateway.optString(IP_ADDRESS); - if (excludedAppsVpn != null) { - profile.mAllowedAppsVpn = new HashSet<>(excludedAppsVpn); - } - } - } - private JSONObject getGeneralConfiguration(JSONObject eipDefinition) { try { return eipDefinition.getJSONObject(OPENVPN_CONFIGURATION); @@ -172,12 +189,10 @@ public class Gateway { /** * Create and attach the VpnProfile to our gateway object */ - private @NonNull HashMap<Connection.TransportType, VpnProfile> createVPNProfiles(Context context) + private @NonNull HashMap<Connection.TransportType, VpnProfile> createVPNProfiles(VpnConfigGenerator.Configuration profileConfig) throws ConfigParser.ConfigParseError, IOException, JSONException { - boolean preferUDP = PreferenceHelper.getPreferUDP(context); - VpnConfigGenerator vpnConfigurationGenerator = new VpnConfigGenerator(generalConfiguration, secrets, gateway, apiVersion, preferUDP); + VpnConfigGenerator vpnConfigurationGenerator = new VpnConfigGenerator(generalConfiguration, secrets, gateway, profileConfig); HashMap<Connection.TransportType, VpnProfile> profiles = vpnConfigurationGenerator.generateVpnProfiles(); - addProfileInfos(context, profiles); return profiles; } @@ -194,6 +209,9 @@ public class Gateway { } public boolean supportsTransport(Connection.TransportType transportType) { + if (transportType == Connection.TransportType.PT) { + return supportsPluggableTransports(); + } return vpnProfiles.get(transportType) != null; } @@ -201,6 +219,15 @@ public class Gateway { return new HashSet<>(vpnProfiles.keySet()); } + public boolean supportsPluggableTransports() { + for (Connection.TransportType transportType : vpnProfiles.keySet()) { + if (transportType.isPluggableTransport() && vpnProfiles.get(transportType) != null) { + return true; + } + } + return false; + } + public int getTimezone() { return timezone; } diff --git a/app/src/main/java/se/leap/bitmaskclient/eip/GatewaysManager.java b/app/src/main/java/se/leap/bitmaskclient/eip/GatewaysManager.java index 0dd4c26c71e119f86e3a7a333244789e33409177..521d095ec6f10ecc54cca9fad67fe7fe462e7dd1 100644 --- a/app/src/main/java/se/leap/bitmaskclient/eip/GatewaysManager.java +++ b/app/src/main/java/se/leap/bitmaskclient/eip/GatewaysManager.java @@ -1,5 +1,5 @@ /** - * Copyright (c) 2013 - 2019 LEAP Encryption Access Project and contributors + * Copyright (c) 2013 - 2022 LEAP Encryption Access Project and contributors * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -16,6 +16,22 @@ */ package se.leap.bitmaskclient.eip; +import static de.blinkt.openvpn.core.connection.Connection.TransportType.OBFS4; +import static de.blinkt.openvpn.core.connection.Connection.TransportType.OBFS4_KCP; +import static de.blinkt.openvpn.core.connection.Connection.TransportType.OPENVPN; +import static de.blinkt.openvpn.core.connection.Connection.TransportType.PT; +import static se.leap.bitmaskclient.base.models.Constants.GATEWAYS; +import static se.leap.bitmaskclient.base.models.Constants.HOST; +import static se.leap.bitmaskclient.base.models.Constants.PROVIDER_PRIVATE_KEY; +import static se.leap.bitmaskclient.base.models.Constants.PROVIDER_VPN_CERTIFICATE; +import static se.leap.bitmaskclient.base.models.Constants.SORTED_GATEWAYS; +import static se.leap.bitmaskclient.base.utils.PreferenceHelper.getObfuscationPinningCert; +import static se.leap.bitmaskclient.base.utils.PreferenceHelper.getObfuscationPinningIP; +import static se.leap.bitmaskclient.base.utils.PreferenceHelper.getObfuscationPinningKCP; +import static se.leap.bitmaskclient.base.utils.PreferenceHelper.getObfuscationPinningPort; +import static se.leap.bitmaskclient.base.utils.PreferenceHelper.getPreferredCity; +import static se.leap.bitmaskclient.base.utils.PreferenceHelper.getUseBridges; + import android.content.Context; import android.util.Log; @@ -41,21 +57,16 @@ import de.blinkt.openvpn.core.ConfigParser; import de.blinkt.openvpn.core.VpnStatus; import de.blinkt.openvpn.core.connection.Connection; import de.blinkt.openvpn.core.connection.Connection.TransportType; +import se.leap.bitmaskclient.BuildConfig; +import se.leap.bitmaskclient.R; +import se.leap.bitmaskclient.base.models.GatewayJson; import se.leap.bitmaskclient.base.models.Location; +import se.leap.bitmaskclient.base.models.Pair; import se.leap.bitmaskclient.base.models.Provider; import se.leap.bitmaskclient.base.models.ProviderObservable; +import se.leap.bitmaskclient.base.models.Transport; import se.leap.bitmaskclient.base.utils.PreferenceHelper; -import static de.blinkt.openvpn.core.connection.Connection.TransportType.OBFS4; -import static de.blinkt.openvpn.core.connection.Connection.TransportType.OPENVPN; -import static se.leap.bitmaskclient.base.models.Constants.GATEWAYS; -import static se.leap.bitmaskclient.base.models.Constants.HOST; -import static se.leap.bitmaskclient.base.models.Constants.PROVIDER_PRIVATE_KEY; -import static se.leap.bitmaskclient.base.models.Constants.PROVIDER_VPN_CERTIFICATE; -import static se.leap.bitmaskclient.base.models.Constants.SORTED_GATEWAYS; -import static se.leap.bitmaskclient.base.utils.PreferenceHelper.getPreferredCity; -import static se.leap.bitmaskclient.base.utils.PreferenceHelper.getUseBridges; - /** * @author parmegv */ @@ -93,6 +104,7 @@ public class GatewaysManager { } private static final String TAG = GatewaysManager.class.getSimpleName(); + public static final String PINNED_OBFUSCATION_PROXY = "pinned.obfuscation.proxy"; private final Context context; private final LinkedHashMap<String, Gateway> gateways = new LinkedHashMap<>(); @@ -110,18 +122,29 @@ public class GatewaysManager { * select closest Gateway * @return the n closest Gateway */ - public Gateway select(int nClosest) { + public Pair<Gateway, TransportType> select(int nClosest) { + if (PreferenceHelper.useObfuscationPinning(context)) { + if (nClosest > 2) { + // no need to try again the pinned proxy, probably configuration error + return null; + } + Gateway gateway = gateways.get(PINNED_OBFUSCATION_PROXY); + if (gateway == null) { + return null; + } + return new Pair<>(gateway, getObfuscationPinningKCP(context) ? OBFS4_KCP : OBFS4); + } String selectedCity = getPreferredCity(context); return select(nClosest, selectedCity); } - public Gateway select(int nClosest, String city) { - TransportType transportType = getUseBridges(context) ? OBFS4 : OPENVPN; + public Pair<Gateway, TransportType> select(int nClosest, String city) { + TransportType[] transportTypes = getUseBridges(context) ? new TransportType[]{OBFS4, OBFS4_KCP} : new TransportType[]{OPENVPN}; if (presortedList.size() > 0) { - return getGatewayFromPresortedList(nClosest, transportType, city); + return getGatewayFromPresortedList(nClosest, transportTypes, city); } - return getGatewayFromTimezoneCalculation(nClosest, transportType, city); + return getGatewayFromTimezoneCalculation(nClosest, transportTypes, city); } public void updateTransport(TransportType transportType) { @@ -131,6 +154,23 @@ public class GatewaysManager { } } + public ArrayList<String> getHosts() { + ArrayList<String> hosts = new ArrayList<>(); + for (Gateway gateway : gateways.values()) { + hosts.add(gateway.getHost()); + } + return hosts; + } + + + public String getIpForHost(String gatewayHostName) { + Gateway gateway = gateways.get(gatewayHostName); + if (gateway == null) { + return null; + } + return gateway.getRemoteIP(); + } + public List<Location> getGatewayLocations() { return getSortedGatewayLocations(null); } @@ -157,7 +197,7 @@ public class GatewaysManager { } else { int index = locationNames.get(gateway.getName()); Location location = locations.get(index); - updateLocation(location, gateway, OBFS4); + updateLocation(location, gateway, PT); updateLocation(location, gateway, OPENVPN); locations.set(index, location); } @@ -172,9 +212,9 @@ public class GatewaysManager { private Location initLocation(String name, Gateway gateway, String preferredCity) { HashMap<TransportType, Double> averageLoadMap = new HashMap<>(); HashMap<TransportType, Integer> numberOfGatewaysMap = new HashMap<>(); - if (gateway.getSupportedTransports().contains(OBFS4)) { - averageLoadMap.put(OBFS4, gateway.getFullness()); - numberOfGatewaysMap.put(OBFS4, 1); + if (gateway.supportsPluggableTransports()) { + averageLoadMap.put(PT, gateway.getFullness()); + numberOfGatewaysMap.put(PT, 1); } if (gateway.getSupportedTransports().contains(OPENVPN)) { averageLoadMap.put(OPENVPN, gateway.getFullness()); @@ -188,7 +228,7 @@ public class GatewaysManager { } private void updateLocation(Location location, Gateway gateway, Connection.TransportType transportType) { - if (gateway.getSupportedTransports().contains(transportType)) { + if (gateway.supportsTransport(transportType)) { double averageLoad = location.getAverageLoad(transportType); int numberOfGateways = location.getNumberOfGateways(transportType); averageLoad = (numberOfGateways * averageLoad + gateway.getFullness()) / (numberOfGateways + 1); @@ -198,6 +238,15 @@ public class GatewaysManager { } } + public String getLocationNameForIP(String ip, Context context) { + for (Gateway gateway : gateways.values()) { + if (gateway.getRemoteIP().equals(ip)) { + return gateway.getName(); + } + } + return context.getString(R.string.unknown_location); + } + @Nullable public Location getLocation(String name) { List <Location> locations = getGatewayLocations(); @@ -217,35 +266,40 @@ public class GatewaysManager { return Load.getLoadByValue(location.getAverageLoad(transportType)); } - private Gateway getGatewayFromTimezoneCalculation(int nClosest, TransportType transportType, @Nullable String city) { + private Pair<Gateway, TransportType> getGatewayFromTimezoneCalculation(int nClosest, TransportType[] transportTypes, @Nullable String city) { List<Gateway> list = new ArrayList<>(gateways.values()); GatewaySelector gatewaySelector = new GatewaySelector(list); Gateway gateway; int found = 0; int i = 0; while ((gateway = gatewaySelector.select(i)) != null) { - if ((city == null && gateway.supportsTransport(transportType)) || - (gateway.getName().equals(city) && gateway.supportsTransport(transportType))) { - if (found == nClosest) { - return gateway; + for (TransportType transportType : transportTypes) { + if ((city == null && gateway.supportsTransport(transportType)) || + (gateway.getName().equals(city) && gateway.supportsTransport(transportType))) { + if (found == nClosest) { + return new Pair<>(gateway, transportType); + } + found++; } - found++; } i++; } return null; } - private Gateway getGatewayFromPresortedList(int nClosest, TransportType transportType, @Nullable String city) { + private Pair<Gateway, TransportType> getGatewayFromPresortedList(int nClosest, TransportType[] transportTypes, @Nullable String city) { int found = 0; for (Gateway gateway : presortedList) { - if ((city == null && gateway.supportsTransport(transportType)) || - (gateway.getName().equals(city) && gateway.supportsTransport(transportType))) { - if (found == nClosest) { - return gateway; + for (TransportType transportType : transportTypes) { + if ((city == null && gateway.supportsTransport(transportType)) || + (gateway.getName().equals(city) && gateway.supportsTransport(transportType))) { + if (found == nClosest) { + return new Pair<>(gateway, transportType); + } + found++; } - found++; } + } return null; } @@ -264,7 +318,7 @@ public class GatewaysManager { } private int getPositionFromPresortedList(VpnProfile profile) { - TransportType transportType = profile.mUsePluggableTransports ? OBFS4 : OPENVPN; + TransportType transportType = profile.getTransportType(); int nClosest = 0; for (Gateway gateway : presortedList) { if (gateway.supportsTransport(transportType)) { @@ -276,9 +330,9 @@ public class GatewaysManager { } return -1; } - + private int getPositionFromTimezoneCalculatedList(VpnProfile profile) { - TransportType transportType = profile.mUsePluggableTransports ? OBFS4 : OPENVPN; + TransportType transportType = profile.getTransportType(); GatewaySelector gatewaySelector = new GatewaySelector(new ArrayList<>(gateways.values())); Gateway gateway; int nClosest = 0; @@ -331,16 +385,35 @@ public class GatewaysManager { e.printStackTrace(); } - for (int i = 0; i < gatewaysDefined.length(); i++) { + if (PreferenceHelper.useObfuscationPinning(context)) { try { - JSONObject gw = gatewaysDefined.getJSONObject(i); - Gateway aux = new Gateway(eipDefinition, secrets, gw, this.context); - if (gateways.get(aux.getHost()) == null) { - addGateway(aux); - } + TransportType transportType = getObfuscationPinningKCP(context) ? OBFS4_KCP : OBFS4; + Transport[] transports = new Transport[]{ + new Transport(transportType.toString(), + new String[]{"tcp"}, + new String[]{getObfuscationPinningPort(context)}, + getObfuscationPinningCert(context))}; + GatewayJson.Capabilities capabilities = new GatewayJson.Capabilities(false, false, false, transports, false); + GatewayJson gatewayJson = new GatewayJson(context.getString(R.string.unknown_location), getObfuscationPinningIP(context), null, PINNED_OBFUSCATION_PROXY, capabilities); + Gateway gateway = new Gateway(eipDefinition, secrets, new JSONObject(gatewayJson.toString()), this.context); + addGateway(gateway); } catch (JSONException | ConfigParser.ConfigParseError | IOException e) { e.printStackTrace(); - VpnStatus.logError("Unable to parse gateway config!"); + } + } else { + for (int i = 0; i < gatewaysDefined.length(); i++) { + try { + JSONObject gw = gatewaysDefined.getJSONObject(i); + Gateway aux = new Gateway(eipDefinition, secrets, gw, this.context); + if (gateways.get(aux.getHost()) == null) { + addGateway(aux); + } + } catch (JSONException | IOException e) { + e.printStackTrace(); + VpnStatus.logError("Unable to parse gateway config!"); + } catch (ConfigParser.ConfigParseError e) { + VpnStatus.logError("Unable to parse gateway config: " + e.getLocalizedMessage()); + } } } } catch (NullPointerException npe) { @@ -419,6 +492,9 @@ public class GatewaysManager { private void configureFromCurrentProvider() { Provider provider = ProviderObservable.getInstance().getCurrentProvider(); parseDefaultGateways(provider); + if (BuildConfig.BUILD_TYPE.equals("debug") && handleGatewayPinning()) { + return; + } if (hasSortedGatewaysWithLoad(provider)) { parseGatewaysWithLoad(provider); } else { @@ -427,5 +503,17 @@ public class GatewaysManager { } + private boolean handleGatewayPinning() { + String host = PreferenceHelper.getPinnedGateway(this.context); + if (host == null) { + return false; + } + Gateway gateway = gateways.get(host); + gateways.clear(); + if (gateway != null) { + gateways.put(host, gateway); + } + return true; + } } diff --git a/app/src/main/java/se/leap/bitmaskclient/eip/VoidVpnService.java b/app/src/main/java/se/leap/bitmaskclient/eip/VoidVpnService.java index 645d7b26cb81412ffad97b4fb560d58c85e246fc..79876d501fdcd2bddf94fde3eca6e94ef5d70f06 100644 --- a/app/src/main/java/se/leap/bitmaskclient/eip/VoidVpnService.java +++ b/app/src/main/java/se/leap/bitmaskclient/eip/VoidVpnService.java @@ -91,7 +91,7 @@ public class VoidVpnService extends VpnService implements Observer, VpnNotificat } }); thread.run(); - } else if (action.equals("android.net.VpnService") && Build.VERSION.SDK_INT >= ALWAYS_ON_MIN_API_LEVEL) { + } else if (intent == null || action.equals("android.net.VpnService") && Build.VERSION.SDK_INT >= ALWAYS_ON_MIN_API_LEVEL) { //only always-on feature triggers this startWithForegroundNotification(); thread = new Thread(new Runnable() { @@ -154,15 +154,12 @@ public class VoidVpnService extends VpnService implements Observer, VpnNotificat builder.addRoute("::",0); builder.addAddress("fc00::", 7); - if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) { - allowAllAFFamilies(builder); - } + allowAllAFFamilies(builder); return builder; } - @TargetApi(Build.VERSION_CODES.LOLLIPOP) private void allowAllAFFamilies(Builder builder) { builder.allowFamily(OsConstants.AF_INET); builder.allowFamily(OsConstants.AF_INET6); @@ -174,9 +171,7 @@ public class VoidVpnService extends VpnService implements Observer, VpnNotificat VpnStatus.updateStateString(STATE_ESTABLISH, "", R.string.void_vpn_establish, ConnectionStatus.LEVEL_BLOCKING); Builder builder = prepareBlockingVpnProfile(); - if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) { - builder.addDisallowedApplication(getPackageName()); - } + builder.addDisallowedApplication(getPackageName()); fd = builder.establish(); } catch (Exception e) { @@ -208,7 +203,7 @@ public class VoidVpnService extends VpnService implements Observer, VpnNotificat blockingMessage, blockingMessage, eipStatus.getLevel(), - this + null ); } else { stopForeground(true); diff --git a/app/src/main/java/se/leap/bitmaskclient/eip/VpnCertificateValidator.java b/app/src/main/java/se/leap/bitmaskclient/eip/VpnCertificateValidator.java index 16d1c5ad5819b08e76ffd6227aaa3acc3ca025f3..8841ae94c58b29837aa57b7d618f98b1625a83fa 100644 --- a/app/src/main/java/se/leap/bitmaskclient/eip/VpnCertificateValidator.java +++ b/app/src/main/java/se/leap/bitmaskclient/eip/VpnCertificateValidator.java @@ -45,9 +45,22 @@ public class VpnCertificateValidator { /** * - * @return true if all certificates are valid for more than 15 more days + * @return true if all certificates are valid for 1 more day */ public boolean isValid() { + return isValid(1); + } + + /** + * + * @return return true if certificates will expire in 8 days or less + */ + public boolean shouldBeUpdated() { + return !isValid(8); + } + + + private boolean isValid(int offsetDays) { if (certificate.isEmpty()) { return false; } @@ -57,7 +70,7 @@ public class VpnCertificateValidator { return false; } for (X509Certificate cert : x509Certificates) { - if (!isValid(cert)) { + if (!isValid(cert, offsetDays)) { return false; } } @@ -65,12 +78,12 @@ public class VpnCertificateValidator { } - private boolean isValid(X509Certificate certificate) { + private boolean isValid(X509Certificate certificate, int offsetDays) { if (certificate == null) { return false; } - Calendar offsetDate = calculateOffsetCertificateValidity(certificate); + Calendar offsetDate = calculateOffsetCertificateValidity(certificate, offsetDays); try { certificate.checkValidity(offsetDate.getTime()); return true; @@ -81,15 +94,15 @@ public class VpnCertificateValidator { } } - private Calendar calculateOffsetCertificateValidity(X509Certificate certificate) { + private Calendar calculateOffsetCertificateValidity(X509Certificate certificate, int offsetDays) { Calendar limitDate = calendarProvider.getCalendar(); Date startDate = certificate.getNotBefore(); // if certificates start date is before current date just return the current date without an offset if (startDate.getTime() >= limitDate.getTime().getTime()) { return limitDate; } - // else add an offset of 15 days to the current date - limitDate.add(Calendar.DAY_OF_YEAR, 15); + // else add an offset to the current date + limitDate.add(Calendar.DAY_OF_YEAR, offsetDays); return limitDate; } diff --git a/app/src/main/java/se/leap/bitmaskclient/eip/VpnConfigGenerator.java b/app/src/main/java/se/leap/bitmaskclient/eip/VpnConfigGenerator.java index 5ddb74ab27102b3ef566ee9f2a998060c991b1cc..72a0d80ad2e7bcc9902bb2a9c2a63ac375f97cb4 100644 --- a/app/src/main/java/se/leap/bitmaskclient/eip/VpnConfigGenerator.java +++ b/app/src/main/java/se/leap/bitmaskclient/eip/VpnConfigGenerator.java @@ -16,6 +16,26 @@ */ package se.leap.bitmaskclient.eip; +import static de.blinkt.openvpn.core.connection.Connection.TransportType.OBFS4; +import static de.blinkt.openvpn.core.connection.Connection.TransportType.OBFS4_KCP; +import static de.blinkt.openvpn.core.connection.Connection.TransportType.OPENVPN; +import static de.blinkt.openvpn.core.connection.Connection.TransportType.PT; +import static se.leap.bitmaskclient.base.models.Constants.CAPABILITIES; +import static se.leap.bitmaskclient.base.models.Constants.IP_ADDRESS; +import static se.leap.bitmaskclient.base.models.Constants.IP_ADDRESS6; +import static se.leap.bitmaskclient.base.models.Constants.OPTIONS; +import static se.leap.bitmaskclient.base.models.Constants.PORTS; +import static se.leap.bitmaskclient.base.models.Constants.PROTOCOLS; +import static se.leap.bitmaskclient.base.models.Constants.PROVIDER_PRIVATE_KEY; +import static se.leap.bitmaskclient.base.models.Constants.PROVIDER_VPN_CERTIFICATE; +import static se.leap.bitmaskclient.base.models.Constants.REMOTE; +import static se.leap.bitmaskclient.base.models.Constants.TRANSPORT; +import static se.leap.bitmaskclient.base.models.Constants.TYPE; +import static se.leap.bitmaskclient.base.models.Constants.UDP; +import static se.leap.bitmaskclient.base.utils.ConfigHelper.ObfsVpnHelper.useObfsVpn; +import static se.leap.bitmaskclient.pluggableTransports.ShapeshifterClient.DISPATCHER_IP; +import static se.leap.bitmaskclient.pluggableTransports.ShapeshifterClient.DISPATCHER_PORT; + import androidx.annotation.VisibleForTesting; import org.json.JSONArray; @@ -25,64 +45,88 @@ import org.json.JSONObject; import java.io.IOException; import java.io.StringReader; import java.util.HashMap; +import java.util.HashSet; import java.util.Iterator; +import java.util.Set; import de.blinkt.openvpn.VpnProfile; import de.blinkt.openvpn.core.ConfigParser; import de.blinkt.openvpn.core.VpnStatus; import de.blinkt.openvpn.core.connection.Connection; +import de.blinkt.openvpn.core.connection.Connection.TransportType; import se.leap.bitmaskclient.base.models.Provider; import se.leap.bitmaskclient.base.utils.ConfigHelper; import se.leap.bitmaskclient.pluggableTransports.Obfs4Options; -import static de.blinkt.openvpn.core.connection.Connection.TransportType.OBFS4; -import static de.blinkt.openvpn.core.connection.Connection.TransportType.OPENVPN; -import static se.leap.bitmaskclient.base.models.Constants.CAPABILITIES; -import static se.leap.bitmaskclient.base.models.Constants.IP_ADDRESS; -import static se.leap.bitmaskclient.base.models.Constants.IP_ADDRESS6; -import static se.leap.bitmaskclient.base.models.Constants.OPTIONS; -import static se.leap.bitmaskclient.base.models.Constants.PORTS; -import static se.leap.bitmaskclient.base.models.Constants.PROTOCOLS; -import static se.leap.bitmaskclient.base.models.Constants.PROVIDER_PRIVATE_KEY; -import static se.leap.bitmaskclient.base.models.Constants.PROVIDER_VPN_CERTIFICATE; -import static se.leap.bitmaskclient.base.models.Constants.REMOTE; -import static se.leap.bitmaskclient.base.models.Constants.TRANSPORT; -import static se.leap.bitmaskclient.base.models.Constants.TYPE; -import static se.leap.bitmaskclient.base.models.Constants.UDP; -import static se.leap.bitmaskclient.pluggableTransports.Shapeshifter.DISPATCHER_IP; -import static se.leap.bitmaskclient.pluggableTransports.Shapeshifter.DISPATCHER_PORT; - public class VpnConfigGenerator { - private JSONObject generalConfiguration; - private JSONObject gateway; - private JSONObject secrets; + private final JSONObject generalConfiguration; + private final JSONObject gateway; + private final JSONObject secrets; private JSONObject obfs4Transport; - private int apiVersion; - private boolean preferUDP; + private JSONObject obfs4TKcpTransport; + private final int apiVersion; + private final boolean preferUDP; + private final boolean experimentalTransports; + private final boolean useObfuscationPinning; + private final String obfuscationPinningIP; + private final String obfuscationPinningPort; + private final String obfuscationPinningCert; + private final boolean obfuscationPinningKCP; + private final String remoteGatewayIP; + private final String profileName; + private final Set<String> excludedApps; public final static String TAG = VpnConfigGenerator.class.getSimpleName(); private final String newLine = System.getProperty("line.separator"); // Platform new line - public VpnConfigGenerator(JSONObject generalConfiguration, JSONObject secrets, JSONObject gateway, int apiVersion, boolean preferUDP) throws ConfigParser.ConfigParseError { + public static class Configuration { + int apiVersion; + boolean preferUDP; + boolean experimentalTransports; + String remoteGatewayIP = ""; + String profileName = ""; + Set<String> excludedApps = null; + + boolean useObfuscationPinning; + boolean obfuscationProxyKCP; + String obfuscationProxyIP = ""; + String obfuscationProxyPort = ""; + String obfuscationProxyCert = ""; + } + + public VpnConfigGenerator(JSONObject generalConfiguration, JSONObject secrets, JSONObject gateway, Configuration config) throws ConfigParser.ConfigParseError { this.generalConfiguration = generalConfiguration; this.gateway = gateway; this.secrets = secrets; - this.apiVersion = apiVersion; - this.preferUDP = preferUDP; + this.apiVersion = config.apiVersion; + this.preferUDP = config.preferUDP; + this.experimentalTransports = config.experimentalTransports; + this.useObfuscationPinning = config.useObfuscationPinning; + this.obfuscationPinningIP = config.obfuscationProxyIP; + this.obfuscationPinningPort = config.obfuscationProxyPort; + this.obfuscationPinningCert = config.obfuscationProxyCert; + this.obfuscationPinningKCP = config.obfuscationProxyKCP; + this.remoteGatewayIP = config.remoteGatewayIP; + this.profileName = config.profileName; + this.excludedApps = config.excludedApps; checkCapabilities(); } public void checkCapabilities() throws ConfigParser.ConfigParseError { - try { + if (apiVersion >= 3) { JSONArray supportedTransports = gateway.getJSONObject(CAPABILITIES).getJSONArray(TRANSPORT); for (int i = 0; i < supportedTransports.length(); i++) { JSONObject transport = supportedTransports.getJSONObject(i); if (transport.getString(TYPE).equals(OBFS4.toString())) { obfs4Transport = transport; - break; + if (!experimentalTransports && !obfuscationPinningKCP) { + break; + } + } else if ((experimentalTransports || obfuscationPinningKCP) && transport.getString(TYPE).equals(OBFS4_KCP.toString())) { + obfs4TKcpTransport = transport; } } } @@ -92,13 +136,17 @@ public class VpnConfigGenerator { } } - public HashMap<Connection.TransportType, VpnProfile> generateVpnProfiles() throws + public HashMap<TransportType, VpnProfile> generateVpnProfiles() throws ConfigParser.ConfigParseError, - NumberFormatException, - JSONException, - IOException { + NumberFormatException { HashMap<Connection.TransportType, VpnProfile> profiles = new HashMap<>(); - profiles.put(OPENVPN, createProfile(OPENVPN)); + if (supportsOpenvpn()) { + try { + profiles.put(OPENVPN, createProfile(OPENVPN)); + } catch (ConfigParser.ConfigParseError | NumberFormatException | JSONException | IOException e) { + e.printStackTrace(); + } + } if (supportsObfs4()) { try { profiles.put(OBFS4, createProfile(OBFS4)); @@ -106,14 +154,31 @@ public class VpnConfigGenerator { e.printStackTrace(); } } + if (supportsObfs4Kcp()) { + try { + profiles.put(OBFS4_KCP, createProfile(OBFS4_KCP)); + } catch (ConfigParser.ConfigParseError | NumberFormatException | JSONException | IOException e) { + e.printStackTrace(); + } + } + if (profiles.isEmpty()) { + throw new ConfigParser.ConfigParseError("No supported transports detected."); + } return profiles; } + private boolean supportsOpenvpn() { + return !useObfuscationPinning && !gatewayConfiguration(OPENVPN).isEmpty(); + } private boolean supportsObfs4(){ - return obfs4Transport != null; + return obfs4Transport != null && !(useObfuscationPinning && obfuscationPinningKCP); } - private String getConfigurationString(Connection.TransportType transportType) { + private boolean supportsObfs4Kcp() { + return obfs4TKcpTransport != null && !(useObfuscationPinning && !obfuscationPinningKCP); + } + + private String getConfigurationString(TransportType transportType) { return generalConfiguration() + newLine + gatewayConfiguration(transportType) @@ -124,23 +189,41 @@ public class VpnConfigGenerator { } @VisibleForTesting - protected VpnProfile createProfile(Connection.TransportType transportType) throws IOException, ConfigParser.ConfigParseError, JSONException { + protected VpnProfile createProfile(TransportType transportType) throws IOException, ConfigParser.ConfigParseError, JSONException { String configuration = getConfigurationString(transportType); ConfigParser icsOpenvpnConfigParser = new ConfigParser(); icsOpenvpnConfigParser.parseConfig(new StringReader(configuration)); if (transportType == OBFS4) { - icsOpenvpnConfigParser.setObfs4Options(getObfs4Options()); + icsOpenvpnConfigParser.setObfs4Options(getObfs4Options(obfs4Transport, false)); + } else if (transportType == OBFS4_KCP) { + icsOpenvpnConfigParser.setObfs4Options(getObfs4Options(obfs4TKcpTransport, true)); } - return icsOpenvpnConfigParser.convertProfile(transportType); + + VpnProfile profile = icsOpenvpnConfigParser.convertProfile(transportType); + profile.mName = profileName; + profile.mGatewayIp = remoteGatewayIP; + if (excludedApps != null) { + profile.mAllowedAppsVpn = new HashSet<>(excludedApps); + } + return profile; } - private Obfs4Options getObfs4Options() throws JSONException { - JSONObject transportOptions = obfs4Transport.getJSONObject(OPTIONS); + // TODO: whad does + private Obfs4Options getObfs4Options(JSONObject transportJson, boolean useUdp) throws JSONException { + JSONObject transportOptions = transportJson.getJSONObject(OPTIONS); String iatMode = transportOptions.getString("iatMode"); String cert = transportOptions.getString("cert"); - String port = obfs4Transport.getJSONArray(PORTS).getString(0); + String port = transportJson.getJSONArray(PORTS).getString(0); String ip = gateway.getString(IP_ADDRESS); - return new Obfs4Options(ip, port, cert, iatMode); + boolean udp = useUdp; + + if (useObfuscationPinning) { + cert = obfuscationPinningCert; + port = obfuscationPinningPort; + ip = obfuscationPinningIP; + udp = obfuscationPinningKCP; + } + return new Obfs4Options(ip, port, cert, iatMode, udp); } private String generalConfiguration() { @@ -166,7 +249,7 @@ public class VpnConfigGenerator { return commonOptions; } - private String gatewayConfiguration(Connection.TransportType transportType) { + private String gatewayConfiguration(TransportType transportType) { String remotes = ""; StringBuilder stringBuilder = new StringBuilder(); @@ -187,6 +270,7 @@ public class VpnConfigGenerator { String[] ipAddresses = ipAddress6.isEmpty() ? new String[]{ipAddress} : new String[]{ipAddress6, ipAddress}; + JSONArray transports = capabilities.getJSONArray(TRANSPORT); gatewayConfigMinApiv3(transportType, stringBuilder, ipAddresses, transports); break; @@ -204,9 +288,9 @@ public class VpnConfigGenerator { return remotes; } - private void gatewayConfigMinApiv3(Connection.TransportType transportType, StringBuilder stringBuilder, String[] ipAddresses, JSONArray transports) throws JSONException { - if (transportType == OBFS4) { - obfs4GatewayConfigMinApiv3(stringBuilder, ipAddresses, transports); + private void gatewayConfigMinApiv3(TransportType transportType, StringBuilder stringBuilder, String[] ipAddresses, JSONArray transports) throws JSONException { + if (transportType.getMetaType() == PT) { + ptGatewayConfigMinApiv3(stringBuilder, ipAddresses, transportType, transports); } else { ovpnGatewayConfigMinApi3(stringBuilder, ipAddresses, transports); } @@ -266,7 +350,7 @@ public class VpnConfigGenerator { } } - private JSONObject getTransport(JSONArray transports, Connection.TransportType transportType) throws JSONException { + private JSONObject getTransport(JSONArray transports, TransportType transportType) throws JSONException { JSONObject selectedTransport = new JSONObject(); for (int i = 0; i < transports.length(); i++) { JSONObject transport = transports.getJSONObject(i); @@ -278,9 +362,21 @@ public class VpnConfigGenerator { return selectedTransport; } - private void obfs4GatewayConfigMinApiv3(StringBuilder stringBuilder, String[] ipAddresses, JSONArray transports) throws JSONException { - JSONObject obfs4Transport = getTransport(transports, OBFS4); - JSONArray protocols = obfs4Transport.getJSONArray(PROTOCOLS); + private boolean isAllowedProtocol(TransportType transportType, String protocol) { + switch (transportType) { + case OPENVPN: + return "tcp".equals(protocol) || "udp".equals(protocol); + case OBFS4: + case OBFS4_KCP: + return "tcp".equals(protocol); + } + return false; + } + + private void ptGatewayConfigMinApiv3(StringBuilder stringBuilder, String[] ipAddresses, TransportType transportType, JSONArray transports) throws JSONException { + JSONObject ptTransport = getTransport(transports, transportType); + JSONArray ptProtocols = ptTransport.getJSONArray(PROTOCOLS); + //for now only use ipv4 gateway the syntax route remote_host 255.255.255.255 net_gateway is not yet working // https://community.openvpn.net/openvpn/ticket/1161 /*for (String ipAddress : ipAddresses) { @@ -307,23 +403,58 @@ public class VpnConfigGenerator { return; } - // check if at least one protocol is TCP, UDP is currently not supported for obfs4 - boolean hasTcp = false; - for (int i = 0; i < protocols.length(); i++) { - String protocol = protocols.getString(i); - if (protocol.contains("tcp")) { - hasTcp = true; + if (!useObfuscationPinning) { + // check if at least one openvpn protocol is TCP, openvpn in UDP is currently not supported for obfs4, + // however on the wire UDP might be used + boolean hasOpenvpnTcp = false; + JSONObject openvpnTransport = getTransport(transports, OPENVPN); + JSONArray gatewayProtocols = openvpnTransport.getJSONArray(PROTOCOLS); + for (int i = 0; i < gatewayProtocols.length(); i++) { + String protocol = gatewayProtocols.getString(i); + if (protocol.contains("tcp")) { + hasOpenvpnTcp = true; + break; + } + } + if (!hasOpenvpnTcp) { + VpnStatus.logError("obfs4 currently only allows openvpn in TCP mode! Skipping obfs4 config for ip " + ipAddress); + return; + } + } + + boolean hasAllowedPTProtocol = false; + for (int i = 0; i < ptProtocols.length(); i++) { + String protocol = ptProtocols.getString(i); + if (isAllowedProtocol(transportType, protocol)) { + hasAllowedPTProtocol = true; + break; } } - if (!hasTcp) { - VpnStatus.logError("obfs4 currently only allows TCP! Skipping obfs4 config for ip " + ipAddress); + if (!hasAllowedPTProtocol) { + VpnStatus.logError("Misconfigured provider: wrong protocol defined in " + transportType.toString()+ " transport JSON."); + return; + } + + JSONArray ports = ptTransport.getJSONArray(PORTS); + if (ports.isNull(0)){ + VpnStatus.logError("Misconfigured provider: no ports defined in " + transportType.toString()+ " transport JSON."); return; } String route = "route " + ipAddress + " 255.255.255.255 net_gateway" + newLine; + String remote; + if (useObfsVpn()) { + if (useObfuscationPinning) { + remote = REMOTE + " " + obfuscationPinningIP + " " + obfuscationPinningPort + newLine; + route = "route " + obfuscationPinningIP + " 255.255.255.255 net_gateway" + newLine; + } else { + remote = REMOTE + " " + ipAddress + " " + ports.getString(0) + newLine; + } + } else { + remote = REMOTE + " " + DISPATCHER_IP + " " + DISPATCHER_PORT + " tcp" + newLine; + } stringBuilder.append(route); - String remote = REMOTE + " " + DISPATCHER_IP + " " + DISPATCHER_PORT + " tcp" + newLine; stringBuilder.append(remote); } diff --git a/app/src/main/java/se/leap/bitmaskclient/eip/VpnNotificationManager.java b/app/src/main/java/se/leap/bitmaskclient/eip/VpnNotificationManager.java index d2603533e406203219a5c06acf2b02591e06e130..b4d11f265f883871fb92c5c403b70b30344d96ea 100644 --- a/app/src/main/java/se/leap/bitmaskclient/eip/VpnNotificationManager.java +++ b/app/src/main/java/se/leap/bitmaskclient/eip/VpnNotificationManager.java @@ -16,6 +16,18 @@ */ package se.leap.bitmaskclient.eip; +import static android.os.Build.VERSION_CODES.O; +import static android.text.TextUtils.isEmpty; +import static androidx.core.app.NotificationCompat.PRIORITY_DEFAULT; +import static androidx.core.app.NotificationCompat.PRIORITY_MAX; +import static de.blinkt.openvpn.core.ConnectionStatus.LEVEL_NONETWORK; +import static de.blinkt.openvpn.core.ConnectionStatus.LEVEL_WAITING_FOR_USER_INPUT; +import static se.leap.bitmaskclient.base.MainActivity.ACTION_SHOW_VPN_FRAGMENT; +import static se.leap.bitmaskclient.base.models.Constants.ASK_TO_CANCEL_VPN; +import static se.leap.bitmaskclient.base.models.Constants.EIP_ACTION_START; +import static se.leap.bitmaskclient.base.models.Constants.EIP_ACTION_STOP_BLOCKING_VPN; +import static se.leap.bitmaskclient.base.utils.ConfigHelper.getPendingIntentFlags; + import android.annotation.TargetApi; import android.app.Notification; import android.app.NotificationChannel; @@ -31,7 +43,6 @@ import android.text.Spannable; import android.text.SpannableString; import android.text.TextUtils; import android.text.style.StyleSpan; -import android.widget.RemoteViews; import androidx.annotation.NonNull; import androidx.core.app.NotificationCompat; @@ -45,17 +56,6 @@ import se.leap.bitmaskclient.R; import se.leap.bitmaskclient.base.MainActivity; import se.leap.bitmaskclient.base.StartActivity; -import static android.os.Build.VERSION_CODES.O; -import static android.text.TextUtils.isEmpty; -import static androidx.core.app.NotificationCompat.PRIORITY_DEFAULT; -import static androidx.core.app.NotificationCompat.PRIORITY_MAX; -import static de.blinkt.openvpn.core.ConnectionStatus.LEVEL_NONETWORK; -import static de.blinkt.openvpn.core.ConnectionStatus.LEVEL_WAITING_FOR_USER_INPUT; -import static se.leap.bitmaskclient.base.MainActivity.ACTION_SHOW_VPN_FRAGMENT; -import static se.leap.bitmaskclient.base.models.Constants.ASK_TO_CANCEL_VPN; -import static se.leap.bitmaskclient.base.models.Constants.EIP_ACTION_START; -import static se.leap.bitmaskclient.base.models.Constants.EIP_ACTION_STOP_BLOCKING_VPN; - /** * Created by cyberta on 14.01.18. */ @@ -128,7 +128,7 @@ public class VpnNotificationManager { public void buildOpenVpnNotification(String profileName, boolean isObfuscated, String msg, String tickerText, ConnectionStatus status, long when, - String notificationChannelNewstatusId, VpnServiceCallback vpnServiceCallback) { + String channelId, VpnServiceCallback vpnServiceCallback) { String cancelString; CharSequence bigmessage = null; String bridgeIcon = new String(Character.toChars(0x1f309)); @@ -140,7 +140,7 @@ public class VpnNotificationManager { case LEVEL_CONNECTING_SERVER_REPLIED: case LEVEL_CONNECTING_NO_SERVER_REPLY_YET: cancelString = context.getString(R.string.cancel); - if (isObfuscated && Build.VERSION.SDK_INT > Build.VERSION_CODES.KITKAT) { + if (isObfuscated) { Spannable spannable = new SpannableString(context.getString(R.string.obfuscated_connection_try)); spannable.setSpan(new StyleSpan(Typeface.ITALIC), 0, spannable.length() -1, Spannable.SPAN_EXCLUSIVE_EXCLUSIVE); bigmessage = TextUtils.concat(spannable, " " + bridgeIcon + "\n" + msg); @@ -149,7 +149,7 @@ public class VpnNotificationManager { // show disconnect if connection exists case LEVEL_CONNECTED: - if (isObfuscated && Build.VERSION.SDK_INT > Build.VERSION_CODES.KITKAT) { + if (isObfuscated) { Spannable spannable = new SpannableString(context.getString(R.string.obfuscated_connection)); spannable.setSpan(new StyleSpan(Typeface.ITALIC), 0, spannable.length() -1, Spannable.SPAN_EXCLUSIVE_EXCLUSIVE); bigmessage = TextUtils.concat(spannable, " " + bridgeIcon + "\n" + msg); @@ -183,7 +183,7 @@ public class VpnNotificationManager { bigmessage, tickerText, status, - notificationChannelNewstatusId, + channelId, PRIORITY_DEFAULT, when, contentIntent, @@ -196,7 +196,8 @@ public class VpnNotificationManager { } public void cancelAll() { - compatNotificationManager.cancelAll(); + compatNotificationManager.cancel(OpenVPNService.NOTIFICATION_CHANNEL_NEWSTATUS_ID.hashCode()); + compatNotificationManager.cancel(VoidVpnService.NOTIFICATION_CHANNEL_NEWSTATUS_ID.hashCode()); } @@ -243,40 +244,16 @@ public class VpnNotificationManager { } } - /** - * @return a custom remote view for notifications for API 16 - 19 - */ - private RemoteViews getKitkatCustomRemoteView(ConnectionStatus status, String title, String message) { - int iconResource = getIconByConnectionStatus(status); - RemoteViews remoteViews = new RemoteViews(context.getPackageName(), R.layout.v_custom_notification); - remoteViews.setImageViewResource(R.id.image_icon, iconResource); - remoteViews.setTextViewText(R.id.message, message); - remoteViews.setTextViewText(R.id.title, title); - - return remoteViews; - } - private void buildVpnNotification(String title, String message, CharSequence bigMessage, String tickerText, - ConnectionStatus status, String notificationChannelNewstatusId, int priority, + ConnectionStatus status, String channelId, int priority, long when, PendingIntent contentIntent, NotificationCompat.Action notificationAction, VpnServiceCallback vpnServiceCallback) { - NotificationCompat.Builder nCompatBuilder = new NotificationCompat.Builder(context, notificationChannelNewstatusId); + NotificationCompat.Builder nCompatBuilder = new NotificationCompat.Builder(context, channelId); int icon = getIconByConnectionStatus(status); - // this is a workaround to avoid confusion between the Android's system vpn notification - // showing a filled out key icon and the bitmask icon indicating a different state. - if (Build.VERSION.SDK_INT <= Build.VERSION_CODES.KITKAT && - notificationChannelNewstatusId.equals(OpenVPNService.NOTIFICATION_CHANNEL_NEWSTATUS_ID)) { - if (status != LEVEL_NONETWORK) { - // removes the icon from the system status bar - icon = android.R.color.transparent; - // adds the icon to the notification in the notification drawer - nCompatBuilder.setContent(getKitkatCustomRemoteView(status, title, message)); - } - } else { - nCompatBuilder.setStyle(new NotificationCompat.BigTextStyle(). - setBigContentTitle(title). - bigText(bigMessage)); - } + nCompatBuilder.setStyle(new NotificationCompat.BigTextStyle(). + setBigContentTitle(title). + bigText(bigMessage)); + nCompatBuilder.addAction(notificationAction); nCompatBuilder.setContentTitle(title); nCompatBuilder.setCategory(NotificationCompat.CATEGORY_SERVICE); @@ -294,29 +271,31 @@ public class VpnNotificationManager { } Notification notification = nCompatBuilder.build(); - int notificationId = notificationChannelNewstatusId.hashCode(); + int notificationId = channelId.hashCode(); - compatNotificationManager.notify(notificationId, notification); if (vpnServiceCallback != null) { vpnServiceCallback.onNotificationBuild(notificationId, notification); + } else { + compatNotificationManager.notify(notificationId, notification); + } } private PendingIntent getMainActivityIntent() { Intent startActivity = new Intent(context, StartActivity.class); - return PendingIntent.getActivity(context, 0, startActivity, PendingIntent.FLAG_CANCEL_CURRENT); + return PendingIntent.getActivity(context, 0, startActivity, getPendingIntentFlags()); } private PendingIntent getStartOpenvpnIntent() { Intent startIntent = new Intent(context, EIP.class); startIntent.setAction(EIP_ACTION_START); - return PendingIntent.getService(context, 0, startIntent, PendingIntent.FLAG_CANCEL_CURRENT); + return PendingIntent.getService(context, 0, startIntent, getPendingIntentFlags()); } private PendingIntent getStopVoidVpnIntent() { Intent stopVoidVpnIntent = new Intent (context, VoidVpnService.class); stopVoidVpnIntent.setAction(EIP_ACTION_STOP_BLOCKING_VPN); - return PendingIntent.getService(context, 0, stopVoidVpnIntent, PendingIntent.FLAG_CANCEL_CURRENT); + return PendingIntent.getService(context, 0, stopVoidVpnIntent, getPendingIntentFlags()); } private PendingIntent getDisconnectIntent() { @@ -324,7 +303,7 @@ public class VpnNotificationManager { disconnectVPN.setAction(ACTION_SHOW_VPN_FRAGMENT); disconnectVPN.putExtra(ASK_TO_CANCEL_VPN, true); disconnectVPN.addFlags(Intent.FLAG_ACTIVITY_SINGLE_TOP); - return PendingIntent.getActivity(context, 0, disconnectVPN, PendingIntent.FLAG_CANCEL_CURRENT); + return PendingIntent.getActivity(context, 0, disconnectVPN, getPendingIntentFlags()); } private PendingIntent getUserInputIntent(String needed) { @@ -333,7 +312,7 @@ public class VpnNotificationManager { intent.putExtra("need", needed); Bundle b = new Bundle(); b.putString("need", needed); - PendingIntent pIntent = PendingIntent.getActivity(context, 12, intent, 0); + PendingIntent pIntent = PendingIntent.getActivity(context, 12, intent, getPendingIntentFlags()); return pIntent; } diff --git a/app/src/main/java/se/leap/bitmaskclient/firewall/FirewallCallback.java b/app/src/main/java/se/leap/bitmaskclient/firewall/FirewallCallback.java index 15fa426f19b880ff702b5d27f26e19dd28925fd7..27eb7370f120e8584fce0814593f758ff0bebf07 100644 --- a/app/src/main/java/se/leap/bitmaskclient/firewall/FirewallCallback.java +++ b/app/src/main/java/se/leap/bitmaskclient/firewall/FirewallCallback.java @@ -1,5 +1,5 @@ /** - * Copyright (c) 2019 LEAP Encryption Access Project and contributers + * Copyright (c) 2020 LEAP Encryption Access Project and contributers * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by diff --git a/app/src/main/java/se/leap/bitmaskclient/firewall/FirewallManager.java b/app/src/main/java/se/leap/bitmaskclient/firewall/FirewallManager.java index dcb4a74318c5dde886f5135ce580c83ff8191fb9..0e81ce301794ad54ba9505f3b41d064fe709c728 100644 --- a/app/src/main/java/se/leap/bitmaskclient/firewall/FirewallManager.java +++ b/app/src/main/java/se/leap/bitmaskclient/firewall/FirewallManager.java @@ -1,6 +1,6 @@ package se.leap.bitmaskclient.firewall; /** - * Copyright (c) 2019 LEAP Encryption Access Project and contributers + * Copyright (c) 2020 LEAP Encryption Access Project and contributers * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by diff --git a/app/src/main/java/se/leap/bitmaskclient/motd/MotdClient.java b/app/src/main/java/se/leap/bitmaskclient/motd/MotdClient.java new file mode 100644 index 0000000000000000000000000000000000000000..d80a899262148dcbaa5b36de856c2888f7f69719 --- /dev/null +++ b/app/src/main/java/se/leap/bitmaskclient/motd/MotdClient.java @@ -0,0 +1,47 @@ +package se.leap.bitmaskclient.motd; + +import androidx.annotation.WorkerThread; + +import org.json.JSONException; +import org.json.JSONObject; + +import de.blinkt.openvpn.core.VpnStatus; +import motd.IMessages; +import motd.IMotd; +import motd.Motd; +import se.leap.bitmaskclient.base.models.Provider; + +public class MotdClient { + IMotd motd; + + public MotdClient(Provider provider) { + motd = Motd.newMotd(provider.getMotdUrl().toString(), provider.getName(), "android"); + } + + @WorkerThread + public IMessages fetch() { + if (!VpnStatus.isVPNActive()) { + VpnStatus.logError("Tried to fetch Message of the Day while VPN was off."); + return null; + } + + return Motd.newMessages(motd.fetchLatestAsJson()); + } + + @WorkerThread + public JSONObject fetchJson() { + if (!VpnStatus.isVPNActive()) { + VpnStatus.logError("Tried to fetch Message of the Day while VPN was off."); + return null; + } + + try { + return new JSONObject(motd.fetchLatestAsJson()); + } catch (NullPointerException | JSONException e) { + e.printStackTrace(); + return null; + } + + } + +} diff --git a/app/src/main/java/se/leap/bitmaskclient/pluggableTransports/Obfs4Options.java b/app/src/main/java/se/leap/bitmaskclient/pluggableTransports/Obfs4Options.java index 2f9cb73214b72082ecd47002853486d2b51f8b81..b96f88ca12f6a340bd5b653cb1b2a4d1ea8f5af1 100644 --- a/app/src/main/java/se/leap/bitmaskclient/pluggableTransports/Obfs4Options.java +++ b/app/src/main/java/se/leap/bitmaskclient/pluggableTransports/Obfs4Options.java @@ -7,12 +7,15 @@ public class Obfs4Options implements Serializable { public String iatMode; public String remoteIP; public String remotePort; + // openvpn is still using tcp, obfs4 is wrapped in kcp, if udp == true + public boolean udp; - public Obfs4Options(String remoteIP, String remotePort, String cert, String iatMode) { + public Obfs4Options(String remoteIP, String remotePort, String cert, String iatMode, boolean udp) { this.cert = cert; this.iatMode = iatMode; this.remoteIP = remoteIP; this.remotePort = remotePort; + this.udp = udp; } } diff --git a/app/src/main/java/se/leap/bitmaskclient/pluggableTransports/ObfsVpnClient.java b/app/src/main/java/se/leap/bitmaskclient/pluggableTransports/ObfsVpnClient.java new file mode 100644 index 0000000000000000000000000000000000000000..f6c8837eabc2b4c9844a8bd96e3449577ca57118 --- /dev/null +++ b/app/src/main/java/se/leap/bitmaskclient/pluggableTransports/ObfsVpnClient.java @@ -0,0 +1,127 @@ +package se.leap.bitmaskclient.pluggableTransports; + +import android.util.Log; + +import java.util.Observable; +import java.util.Observer; +import java.util.concurrent.atomic.AtomicBoolean; +import java.util.concurrent.atomic.AtomicInteger; + +import client.Client_; +import de.blinkt.openvpn.core.ConnectionStatus; +import de.blinkt.openvpn.core.VpnStatus; +import se.leap.bitmaskclient.eip.EipStatus; + +public class ObfsVpnClient implements Observer, client.EventLogger { + + public static final AtomicInteger SOCKS_PORT = new AtomicInteger(4430); + public static final String SOCKS_IP = "127.0.0.1"; + private static final String ERR_BIND = "bind: address already in use"; + + private static final String TAG = ObfsVpnClient.class.getSimpleName(); + private volatile boolean noNetwork; + private final AtomicBoolean pendingNetworkErrorHandling = new AtomicBoolean(false); + private final AtomicInteger reconnectRetry = new AtomicInteger(0); + private static final int MAX_RETRY = 5; + + private final client.Client_ obfsVpnClient; + private final Object LOCK = new Object(); + + public ObfsVpnClient(Obfs4Options options) { + obfsVpnClient = new Client_(options.udp, SOCKS_IP+":"+SOCKS_PORT.get(), options.cert); + obfsVpnClient.setEventLogger(this); + } + + /** + * starts the client + * @return the port ObfsVpn is running on + */ + public int start() { + synchronized (LOCK) { + Log.d(TAG, "aquired LOCK"); + new Thread(this::startSync).start(); + waitUntilStarted(); + Log.d(TAG, "returning LOCK after " + (reconnectRetry.get() + 1) * 200 +" ms"); + } + return SOCKS_PORT.get(); + } + + private void waitUntilStarted() { + int count = -1; + try { + while (count < reconnectRetry.get() && reconnectRetry.get() < MAX_RETRY) { + Thread.sleep(200); + count++; + } + } catch (InterruptedException e) { + e.printStackTrace(); + } + } + + private void startSync() { + try { + obfsVpnClient.start(); + } catch (Exception e) { + Log.e(TAG, "[obfsvpn] exception: " + e.getLocalizedMessage()); + VpnStatus.logError("[obfsvpn] " + e.getLocalizedMessage()); + if (e.getLocalizedMessage() != null && e.getLocalizedMessage().contains(ERR_BIND) && reconnectRetry.get() < MAX_RETRY) { + reconnectRetry.addAndGet(1); + SOCKS_PORT.addAndGet(1); + obfsVpnClient.setSocksAddr(SOCKS_IP+":"+SOCKS_PORT.get()); + Log.d(TAG, "[obfsvpn] reconnecting on different port... " + SOCKS_PORT.get()); + VpnStatus.logDebug("[obfsvpn] reconnecting on different port... " + SOCKS_PORT.get()); + startSync(); + } else if (noNetwork) { + pendingNetworkErrorHandling.set(true); + } + } + } + + public void stop() { + synchronized (LOCK) { + Log.d(TAG, "stopping obfsVpnClient..."); + try { + obfsVpnClient.stop(); + reconnectRetry.set(0); + SOCKS_PORT.set(4430); + Thread.sleep(100); + } catch (Exception e) { + e.printStackTrace(); + VpnStatus.logError("[obfsvpn] " + e.getLocalizedMessage()); + } + pendingNetworkErrorHandling.set(false); + Log.d(TAG, "stopping obfsVpnClient releasing LOCK ..."); + } + } + + public boolean isStarted() { + return obfsVpnClient.isStarted(); + } + + @Override + public void update(Observable observable, Object arg) { + if (observable instanceof EipStatus) { + EipStatus status = (EipStatus) observable; + if (status.getLevel() == ConnectionStatus.LEVEL_NONETWORK) { + noNetwork = true; + } else { + noNetwork = false; + if (pendingNetworkErrorHandling.getAndSet(false)) { + stop(); + start(); + } + } + } + } + + @Override + public void error(String s) { + VpnStatus.logError("[obfsvpn] " + s); + } + + @Override + public void log(String state, String message) { + VpnStatus.logDebug("[obfsvpn] " + state + " " + message); + } + +} diff --git a/app/src/main/java/se/leap/bitmaskclient/pluggableTransports/Shapeshifter.java b/app/src/main/java/se/leap/bitmaskclient/pluggableTransports/ShapeshifterClient.java similarity index 90% rename from app/src/main/java/se/leap/bitmaskclient/pluggableTransports/Shapeshifter.java rename to app/src/main/java/se/leap/bitmaskclient/pluggableTransports/ShapeshifterClient.java index 970703cc68c8533bdc3eee0285a8ac7117356e71..f1eb0f1bddc17b4a65550b1368f2cadae2c406cb 100644 --- a/app/src/main/java/se/leap/bitmaskclient/pluggableTransports/Shapeshifter.java +++ b/app/src/main/java/se/leap/bitmaskclient/pluggableTransports/ShapeshifterClient.java @@ -1,5 +1,5 @@ /** - * Copyright (c) 2019 LEAP Encryption Access Project and contributors + * Copyright (c) 2020 LEAP Encryption Access Project and contributors * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -27,17 +27,16 @@ import java.util.Observer; import de.blinkt.openvpn.core.ConnectionStatus; import de.blinkt.openvpn.core.VpnStatus; import se.leap.bitmaskclient.eip.EipStatus; -import shapeshifter.ShapeShifter; -public class Shapeshifter implements Observer { +public class ShapeshifterClient implements Observer { public static final String DISPATCHER_PORT = "4430"; public static final String DISPATCHER_IP = "127.0.0.1"; private static final int MAX_RETRY = 5; private static final int RETRY_TIME = 4000; - private static final String TAG = Shapeshifter.class.getSimpleName(); + private static final String TAG = ShapeshifterClient.class.getSimpleName(); - private final shapeshifter.ShapeShifter shapeShifter; + private final shapeshifter.Shapeshifter_ shapeShifter; private boolean isErrorHandling; private boolean noNetwork; private int retry = 0; @@ -53,15 +52,15 @@ public class Shapeshifter implements Observer { if (retry < MAX_RETRY && !noNetwork) { retry++; - reconnectHandler.postDelayed(Shapeshifter.this::reconnect, RETRY_TIME); + reconnectHandler.postDelayed(ShapeshifterClient.this::reconnect, RETRY_TIME); } else { VpnStatus.logError(VpnStatus.ErrorType.SHAPESHIFTER); } } } - public Shapeshifter(Obfs4Options options) { - shapeShifter = new ShapeShifter(); + public ShapeshifterClient(Obfs4Options options) { + shapeShifter = new shapeshifter.Shapeshifter_(); shapeShifter.setLogger(new ShapeshifterLogger()); setup(options); Looper.prepare(); diff --git a/app/src/main/java/se/leap/bitmaskclient/providersetup/ProviderAPI.java b/app/src/main/java/se/leap/bitmaskclient/providersetup/ProviderAPI.java index 022ad0406dda75615f32bd846892f4d3d5ddf3cd..86ce577b7a7073da846efc13de6400be78752d7a 100644 --- a/app/src/main/java/se/leap/bitmaskclient/providersetup/ProviderAPI.java +++ b/app/src/main/java/se/leap/bitmaskclient/providersetup/ProviderAPI.java @@ -60,12 +60,19 @@ public class ProviderAPI extends JobIntentService implements ProviderApiManagerB SET_UP_PROVIDER = "setUpProvider", UPDATE_PROVIDER_DETAILS = "updateProviderDetails", DOWNLOAD_GEOIP_JSON = "downloadGeoIpJson", + DOWNLOAD_MOTD = "downloadMotd", SIGN_UP = "srpRegister", LOG_IN = "srpAuth", LOG_OUT = "logOut", + // all vpn certificate download commands are used in different scenarios with different error handling + // command key used for the initial vpn certificate download during the provider setup DOWNLOAD_VPN_CERTIFICATE = "downloadUserAuthedVPNCertificate", + // command key used to update soon expiring but yet valid certificates after connecting to the vpn + QUIETLY_UPDATE_VPN_CERTIFICATE = "ProviderAPI.QUIETLY_UPDATE_VPN_CERTIFICATE", + // command key used to update invalid certificates, connecting to the vpn is impossible UPDATE_INVALID_VPN_CERTIFICATE = "ProviderAPI.UPDATE_INVALID_VPN_CERTIFICATE", PARAMETERS = "parameters", + DELAY = "delay", RECEIVER_KEY = "receiver", ERRORS = "errors", ERRORID = "errorId", @@ -93,10 +100,10 @@ public class ProviderAPI extends JobIntentService implements ProviderApiManagerB CORRECTLY_DOWNLOADED_GEOIP_JSON = 17, INCORRECTLY_DOWNLOADED_GEOIP_JSON = 18, TOR_TIMEOUT = 19, - MISSING_NETWORK_CONNECTION = 20; + MISSING_NETWORK_CONNECTION = 20, + TOR_EXCEPTION = 21; ProviderApiManager providerApiManager; - private volatile TorServiceConnection torServiceConnection; //TODO: refactor me, please! //used in insecure flavor only @@ -155,7 +162,7 @@ public class ProviderAPI extends JobIntentService implements ProviderApiManagerB if (Build.VERSION.SDK_INT < Build.VERSION_CODES.Q) { NetworkInfo activeNetwork = cm.getActiveNetworkInfo(); return activeNetwork != null && - activeNetwork.isConnectedOrConnecting(); + activeNetwork.isConnected(); } else { NetworkCapabilities capabilities = cm.getNetworkCapabilities(cm.getActiveNetwork()); if (capabilities != null) { diff --git a/app/src/main/java/se/leap/bitmaskclient/providersetup/ProviderApiManagerBase.java b/app/src/main/java/se/leap/bitmaskclient/providersetup/ProviderApiManagerBase.java index 63cf03cf3b57424d7d450e07e5b4ea067ae871d8..1430887532e9aea04a826522799f2d0a8d42428f 100644 --- a/app/src/main/java/se/leap/bitmaskclient/providersetup/ProviderApiManagerBase.java +++ b/app/src/main/java/se/leap/bitmaskclient/providersetup/ProviderApiManagerBase.java @@ -17,57 +17,6 @@ package se.leap.bitmaskclient.providersetup; -import android.content.Intent; -import android.content.SharedPreferences; -import android.content.res.Resources; -import android.os.Bundle; -import android.os.ResultReceiver; -import android.util.Base64; -import android.util.Log; -import android.util.Pair; - -import androidx.annotation.NonNull; - -import org.json.JSONException; -import org.json.JSONObject; - -import java.io.IOException; -import java.math.BigInteger; -import java.net.ConnectException; -import java.net.MalformedURLException; -import java.net.SocketTimeoutException; -import java.net.UnknownHostException; -import java.net.UnknownServiceException; -import java.security.NoSuchAlgorithmException; -import java.security.cert.CertificateEncodingException; -import java.security.cert.CertificateException; -import java.security.cert.CertificateExpiredException; -import java.security.cert.CertificateNotYetValidException; -import java.security.cert.X509Certificate; -import java.security.interfaces.RSAPrivateKey; -import java.util.ArrayList; -import java.util.List; -import java.util.NoSuchElementException; -import java.util.concurrent.TimeoutException; - -import javax.net.ssl.SSLHandshakeException; -import javax.net.ssl.SSLPeerUnverifiedException; - -import de.blinkt.openvpn.core.VpnStatus; -import okhttp3.OkHttpClient; -import se.leap.bitmaskclient.R; -import se.leap.bitmaskclient.base.models.Constants.CREDENTIAL_ERRORS; -import se.leap.bitmaskclient.base.models.Provider; -import se.leap.bitmaskclient.base.models.ProviderObservable; -import se.leap.bitmaskclient.base.utils.ConfigHelper; -import se.leap.bitmaskclient.base.utils.PreferenceHelper; -import se.leap.bitmaskclient.eip.EipStatus; -import se.leap.bitmaskclient.providersetup.connectivity.OkHttpClientGenerator; -import se.leap.bitmaskclient.providersetup.models.LeapSRPSession; -import se.leap.bitmaskclient.providersetup.models.SrpCredentials; -import se.leap.bitmaskclient.providersetup.models.SrpRegistrationData; -import se.leap.bitmaskclient.tor.TorStatusObservable; - import static se.leap.bitmaskclient.R.string.certificate_error; import static se.leap.bitmaskclient.R.string.error_io_exception_user_message; import static se.leap.bitmaskclient.R.string.error_json_exception_user_message; @@ -86,24 +35,34 @@ import static se.leap.bitmaskclient.base.models.Constants.CREDENTIALS_PASSWORD; import static se.leap.bitmaskclient.base.models.Constants.CREDENTIALS_USERNAME; import static se.leap.bitmaskclient.base.models.Constants.EIP_ACTION_START; import static se.leap.bitmaskclient.base.models.Constants.PROVIDER_KEY; +import static se.leap.bitmaskclient.base.models.Constants.PROVIDER_MOTD; +import static se.leap.bitmaskclient.base.models.Constants.PROVIDER_MOTD_HASHES; +import static se.leap.bitmaskclient.base.models.Constants.PROVIDER_MOTD_LAST_SEEN; +import static se.leap.bitmaskclient.base.models.Constants.PROVIDER_MOTD_LAST_UPDATED; import static se.leap.bitmaskclient.base.models.Constants.PROVIDER_PRIVATE_KEY; import static se.leap.bitmaskclient.base.models.Constants.PROVIDER_VPN_CERTIFICATE; import static se.leap.bitmaskclient.base.models.Provider.CA_CERT; import static se.leap.bitmaskclient.base.models.Provider.GEOIP_URL; +import static se.leap.bitmaskclient.base.models.Provider.MOTD_URL; import static se.leap.bitmaskclient.base.models.Provider.PROVIDER_API_IP; import static se.leap.bitmaskclient.base.models.Provider.PROVIDER_IP; +import static se.leap.bitmaskclient.base.utils.ConfigHelper.getDomainFromMainURL; import static se.leap.bitmaskclient.base.utils.ConfigHelper.getFingerprintFromCertificate; import static se.leap.bitmaskclient.base.utils.ConfigHelper.getProviderFormattedString; import static se.leap.bitmaskclient.base.utils.ConfigHelper.parseRsaKeyFromString; import static se.leap.bitmaskclient.base.utils.PreferenceHelper.deleteProviderDetailsFromPreferences; import static se.leap.bitmaskclient.base.utils.PreferenceHelper.getFromPersistedProvider; +import static se.leap.bitmaskclient.base.utils.PreferenceHelper.getLongFromPersistedProvider; +import static se.leap.bitmaskclient.base.utils.PreferenceHelper.getStringSetFromPersistedProvider; import static se.leap.bitmaskclient.providersetup.ProviderAPI.BACKEND_ERROR_KEY; import static se.leap.bitmaskclient.providersetup.ProviderAPI.BACKEND_ERROR_MESSAGE; import static se.leap.bitmaskclient.providersetup.ProviderAPI.CORRECTLY_DOWNLOADED_EIP_SERVICE; import static se.leap.bitmaskclient.providersetup.ProviderAPI.CORRECTLY_DOWNLOADED_GEOIP_JSON; import static se.leap.bitmaskclient.providersetup.ProviderAPI.CORRECTLY_DOWNLOADED_VPN_CERTIFICATE; import static se.leap.bitmaskclient.providersetup.ProviderAPI.CORRECTLY_UPDATED_INVALID_VPN_CERTIFICATE; +import static se.leap.bitmaskclient.providersetup.ProviderAPI.DELAY; import static se.leap.bitmaskclient.providersetup.ProviderAPI.DOWNLOAD_GEOIP_JSON; +import static se.leap.bitmaskclient.providersetup.ProviderAPI.DOWNLOAD_MOTD; import static se.leap.bitmaskclient.providersetup.ProviderAPI.DOWNLOAD_SERVICE_JSON; import static se.leap.bitmaskclient.providersetup.ProviderAPI.DOWNLOAD_VPN_CERTIFICATE; import static se.leap.bitmaskclient.providersetup.ProviderAPI.ERRORID; @@ -122,12 +81,14 @@ import static se.leap.bitmaskclient.providersetup.ProviderAPI.MISSING_NETWORK_CO import static se.leap.bitmaskclient.providersetup.ProviderAPI.PARAMETERS; import static se.leap.bitmaskclient.providersetup.ProviderAPI.PROVIDER_NOK; import static se.leap.bitmaskclient.providersetup.ProviderAPI.PROVIDER_OK; +import static se.leap.bitmaskclient.providersetup.ProviderAPI.QUIETLY_UPDATE_VPN_CERTIFICATE; import static se.leap.bitmaskclient.providersetup.ProviderAPI.RECEIVER_KEY; import static se.leap.bitmaskclient.providersetup.ProviderAPI.SET_UP_PROVIDER; import static se.leap.bitmaskclient.providersetup.ProviderAPI.SIGN_UP; import static se.leap.bitmaskclient.providersetup.ProviderAPI.SUCCESSFUL_LOGIN; import static se.leap.bitmaskclient.providersetup.ProviderAPI.SUCCESSFUL_LOGOUT; import static se.leap.bitmaskclient.providersetup.ProviderAPI.SUCCESSFUL_SIGNUP; +import static se.leap.bitmaskclient.providersetup.ProviderAPI.TOR_EXCEPTION; import static se.leap.bitmaskclient.providersetup.ProviderAPI.TOR_TIMEOUT; import static se.leap.bitmaskclient.providersetup.ProviderAPI.UPDATE_INVALID_VPN_CERTIFICATE; import static se.leap.bitmaskclient.providersetup.ProviderAPI.UPDATE_PROVIDER_DETAILS; @@ -140,6 +101,59 @@ import static se.leap.bitmaskclient.tor.TorStatusObservable.TorStatus.OFF; import static se.leap.bitmaskclient.tor.TorStatusObservable.TorStatus.ON; import static se.leap.bitmaskclient.tor.TorStatusObservable.getProxyPort; +import android.content.Intent; +import android.content.SharedPreferences; +import android.content.res.Resources; +import android.os.Bundle; +import android.os.ResultReceiver; +import android.util.Base64; +import android.util.Log; +import android.util.Pair; + +import androidx.annotation.NonNull; + +import org.json.JSONException; +import org.json.JSONObject; + +import java.io.IOException; +import java.math.BigInteger; +import java.net.ConnectException; +import java.net.MalformedURLException; +import java.net.SocketTimeoutException; +import java.net.UnknownHostException; +import java.net.UnknownServiceException; +import java.security.NoSuchAlgorithmException; +import java.security.cert.CertificateEncodingException; +import java.security.cert.CertificateException; +import java.security.cert.CertificateExpiredException; +import java.security.cert.CertificateNotYetValidException; +import java.security.cert.X509Certificate; +import java.security.interfaces.RSAPrivateKey; +import java.util.ArrayList; +import java.util.List; +import java.util.NoSuchElementException; +import java.util.Set; +import java.util.concurrent.TimeoutException; + +import javax.net.ssl.SSLHandshakeException; +import javax.net.ssl.SSLPeerUnverifiedException; + +import de.blinkt.openvpn.core.VpnStatus; +import okhttp3.OkHttpClient; +import se.leap.bitmaskclient.R; +import se.leap.bitmaskclient.base.models.Constants.CREDENTIAL_ERRORS; +import se.leap.bitmaskclient.base.models.Provider; +import se.leap.bitmaskclient.base.models.ProviderObservable; +import se.leap.bitmaskclient.base.utils.ConfigHelper; +import se.leap.bitmaskclient.base.utils.PreferenceHelper; +import se.leap.bitmaskclient.eip.EipStatus; +import se.leap.bitmaskclient.motd.MotdClient; +import se.leap.bitmaskclient.providersetup.connectivity.OkHttpClientGenerator; +import se.leap.bitmaskclient.providersetup.models.LeapSRPSession; +import se.leap.bitmaskclient.providersetup.models.SrpCredentials; +import se.leap.bitmaskclient.providersetup.models.SrpRegistrationData; +import se.leap.bitmaskclient.tor.TorStatusObservable; + /** * Implements the logic of the http api calls. The methods of this class needs to be called from * a background thread. @@ -192,6 +206,14 @@ public abstract class ProviderApiManagerBase { return; } + if (parameters.containsKey(DELAY)) { + try { + Thread.sleep(parameters.getLong(DELAY)); + } catch (InterruptedException e) { + e.printStackTrace(); + } + } + if (!serviceCallback.hasNetworkConnection()) { Bundle result = new Bundle(); setErrorResult(result, R.string.error_network_connection, null); @@ -200,11 +222,14 @@ public abstract class ProviderApiManagerBase { } try { - if (PreferenceHelper.hasSnowflakePrefs(preferences)) { + if (PreferenceHelper.hasSnowflakePrefs(preferences) && !VpnStatus.isVPNActive()) { startTorProxy(); } } catch (InterruptedException | IllegalStateException e) { e.printStackTrace(); + Bundle result = new Bundle(); + setErrorResultAction(result, action); + sendToReceiverOrBroadcast(receiver, TOR_EXCEPTION, result, provider); return; } catch (TimeoutException e) { serviceCallback.stopTorService(); @@ -273,6 +298,28 @@ public abstract class ProviderApiManagerBase { } ProviderObservable.getInstance().setProviderForDns(null); break; + case QUIETLY_UPDATE_VPN_CERTIFICATE: + ProviderObservable.getInstance().setProviderForDns(provider); + result = updateVpnCertificate(provider); + if (result.getBoolean(BROADCAST_RESULT_KEY)) { + Log.d(TAG, "successfully downloaded VPN certificate"); + provider.setShouldUpdateVpnCertificate(false); + PreferenceHelper.storeProviderInPreferences(preferences, provider); + ProviderObservable.getInstance().updateProvider(provider); + } + ProviderObservable.getInstance().setProviderForDns(null); + break; + case DOWNLOAD_MOTD: + MotdClient client = new MotdClient(provider); + JSONObject motd = client.fetchJson(); + if (motd != null) { + provider.setMotdJson(motd); + provider.setLastMotdUpdate(System.currentTimeMillis()); + } + PreferenceHelper.storeProviderInPreferences(preferences, provider); + ProviderObservable.getInstance().updateProvider(provider); + break; + case UPDATE_INVALID_VPN_CERTIFICATE: ProviderObservable.getInstance().setProviderForDns(provider); result = updateVpnCertificate(provider); @@ -369,7 +416,7 @@ public abstract class ProviderApiManagerBase { private void addErrorMessageToJson(JSONObject jsonObject, String errorMessage, String errorId, String initialAction) { try { - jsonObject.put(ERRORS, errorMessage); + jsonObject.putOpt(ERRORS, errorMessage); jsonObject.putOpt(ERRORID, errorId); jsonObject.putOpt(INITIAL_ACTION, initialAction); } catch (JSONException e) { @@ -599,6 +646,10 @@ public abstract class ProviderApiManagerBase { case INCORRECTLY_DOWNLOADED_GEOIP_JSON: event = "download menshen service json."; break; + case TOR_TIMEOUT: + case TOR_EXCEPTION: + event = "start tor for censorship circumvention"; + break; default: break; } @@ -884,7 +935,11 @@ public abstract class ProviderApiManagerBase { provider.setVpnCertificate(getPersistedVPNCertificate(providerDomain)); provider.setProviderApiIp(getPersistedProviderApiIp(providerDomain)); provider.setProviderIp(getPersistedProviderIp(providerDomain)); - provider.setGeoipUrl(getPersistedGeoIp(providerDomain)); + provider.setGeoipUrl(getPersistedGeoIp(providerDomain)); // TODO: do we really need to persist the Geoip URL?? + provider.setLastMotdSeen(getPersistedMotdLastSeen(providerDomain)); + provider.setMotdLastSeenHashes(getPersistedMotdHashes(providerDomain)); + provider.setLastMotdUpdate(getPersistedMotdLastUpdate(providerDomain)); + provider.setMotdJson(getPersistedMotd(providerDomain)); } } @@ -959,6 +1014,15 @@ public abstract class ProviderApiManagerBase { return result; } + Bundle setErrorResultAction(Bundle result, String initialAction) { + JSONObject errorJson = new JSONObject(); + addErrorMessageToJson(errorJson, null, null, initialAction); + VpnStatus.logWarning("[API] error: " + initialAction + " failed."); + result.putString(ERRORS, errorJson.toString()); + result.putBoolean(BROADCAST_RESULT_KEY, false); + return result; + } + Bundle setErrorResult(Bundle result, int errorMessageId, String errorId) { return setErrorResult(result, errorMessageId, errorId, null); } @@ -1006,13 +1070,29 @@ public abstract class ProviderApiManagerBase { return getFromPersistedProvider(GEOIP_URL, providerDomain, preferences); } - protected boolean hasUpdatedProviderDetails(String domain) { - return preferences.contains(Provider.KEY + "." + domain) && preferences.contains(CA_CERT + "." + domain); + protected JSONObject getPersistedMotd(String providerDomain) { + try { + return new JSONObject(getFromPersistedProvider(PROVIDER_MOTD, providerDomain, preferences)); + } catch (JSONException e) { + return new JSONObject(); + } + } + + protected long getPersistedMotdLastSeen(String providerDomain) { + return getLongFromPersistedProvider(PROVIDER_MOTD_LAST_SEEN, providerDomain, preferences); + } + + protected long getPersistedMotdLastUpdate(String providerDomain) { + return getLongFromPersistedProvider(PROVIDER_MOTD_LAST_UPDATED, providerDomain, preferences); + } + + protected Set<String> getPersistedMotdHashes(String providerDomain) { + return getStringSetFromPersistedProvider(PROVIDER_MOTD_HASHES, providerDomain, preferences); } - protected String getDomainFromMainURL(String mainUrl) { - return mainUrl.replaceFirst("http[s]?://", "").replaceFirst("/.*", ""); + protected boolean hasUpdatedProviderDetails(String domain) { + return preferences.contains(Provider.KEY + "." + domain) && preferences.contains(CA_CERT + "." + domain); } /** diff --git a/app/src/main/java/se/leap/bitmaskclient/providersetup/ProviderApiSetupBroadcastReceiver.java b/app/src/main/java/se/leap/bitmaskclient/providersetup/ProviderApiSetupBroadcastReceiver.java index cc6ff1499a4ad54de5cfb333c3615b2e22eec4ed..4b7d22fcbf9384e4393556cc4363b3a61d90ef51 100644 --- a/app/src/main/java/se/leap/bitmaskclient/providersetup/ProviderApiSetupBroadcastReceiver.java +++ b/app/src/main/java/se/leap/bitmaskclient/providersetup/ProviderApiSetupBroadcastReceiver.java @@ -38,7 +38,7 @@ import se.leap.bitmaskclient.providersetup.activities.ProviderListBaseActivity; */ public class ProviderApiSetupBroadcastReceiver extends BroadcastReceiver { - private WeakReference<ProviderSetupInterface> setupInterfaceRef; + private final WeakReference<ProviderSetupInterface> setupInterfaceRef; public ProviderApiSetupBroadcastReceiver(ProviderSetupInterface setupInterface) { this.setupInterfaceRef = new WeakReference<>(setupInterface); @@ -62,7 +62,7 @@ public class ProviderApiSetupBroadcastReceiver extends BroadcastReceiver { Provider handledProvider = resultData.getParcelable(Constants.PROVIDER_KEY); if (handledProvider != null && setupInterface.getProvider() != null && - handledProvider.getDomain().equalsIgnoreCase(setupInterface.getProvider().getDomain())) { + handledProvider.getMainUrlString().equalsIgnoreCase(setupInterface.getProvider().getMainUrlString())) { switch (resultCode) { case ProviderAPI.PROVIDER_OK: setupInterface.handleProviderSetUp(handledProvider); diff --git a/app/src/main/java/se/leap/bitmaskclient/providersetup/ProviderManager.java b/app/src/main/java/se/leap/bitmaskclient/providersetup/ProviderManager.java index 88413087aca4159a77a1a961000ef45edd6074cc..1ae2a0337eb47b65584a73a6aa359d979b2c5787 100644 --- a/app/src/main/java/se/leap/bitmaskclient/providersetup/ProviderManager.java +++ b/app/src/main/java/se/leap/bitmaskclient/providersetup/ProviderManager.java @@ -24,6 +24,7 @@ import static se.leap.bitmaskclient.base.models.Constants.EXT_PEM; import static se.leap.bitmaskclient.base.models.Constants.URLS; import static se.leap.bitmaskclient.base.models.Provider.GEOIP_URL; import static se.leap.bitmaskclient.base.models.Provider.MAIN_URL; +import static se.leap.bitmaskclient.base.models.Provider.MOTD_URL; import static se.leap.bitmaskclient.base.models.Provider.PROVIDER_API_IP; import static se.leap.bitmaskclient.base.models.Provider.PROVIDER_IP; import static se.leap.bitmaskclient.base.utils.FileHelper.createFile; @@ -91,6 +92,7 @@ public class ProviderManager implements AdapteeCollection<Provider> { String certificate = null; String providerDefinition = null; String geoipUrl = null; + String motdUrl = null; try { String provider = file.substring(0, file.length() - ".url".length()); InputStream providerFile = assetsManager.open(directory + "/" + file); @@ -98,12 +100,13 @@ public class ProviderManager implements AdapteeCollection<Provider> { providerIp = extractKeyFromInputStream(providerFile, PROVIDER_IP); providerApiIp = extractKeyFromInputStream(providerFile, PROVIDER_API_IP); geoipUrl = extractKeyFromInputStream(providerFile, GEOIP_URL); + motdUrl = extractKeyFromInputStream(providerFile, MOTD_URL); certificate = loadInputStreamAsString(assetsManager.open(provider + EXT_PEM)); providerDefinition = loadInputStreamAsString(assetsManager.open(provider + EXT_JSON)); } catch (IOException e) { e.printStackTrace(); } - providers.add(new Provider(mainUrl, geoipUrl, providerIp, providerApiIp, certificate, providerDefinition)); + providers.add(new Provider(mainUrl, geoipUrl, motdUrl, providerIp, providerApiIp, certificate, providerDefinition)); } return providers; diff --git a/app/src/main/java/se/leap/bitmaskclient/providersetup/activities/ConfigWizardBaseActivity.java b/app/src/main/java/se/leap/bitmaskclient/providersetup/activities/ConfigWizardBaseActivity.java index aaf20647d327d019d196321566a77d4b3fbe9ce9..5cfefb2e8385fcd047a86260d44ca11392a2b51e 100644 --- a/app/src/main/java/se/leap/bitmaskclient/providersetup/activities/ConfigWizardBaseActivity.java +++ b/app/src/main/java/se/leap/bitmaskclient/providersetup/activities/ConfigWizardBaseActivity.java @@ -161,7 +161,6 @@ public abstract class ConfigWizardBaseActivity extends ButterKnifeActivity imple if (provider != null) { setProviderHeaderText(provider.getName()); } - setProgressbarColorForPreLollipop(); setDefaultGuidelineValues(); setGlobalLayoutChangeListener(); } @@ -173,16 +172,6 @@ public abstract class ConfigWizardBaseActivity extends ButterKnifeActivity imple } } - private void setProgressbarColorForPreLollipop() { - if (progressBar == null || Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) { - return; - } - progressBar.getIndeterminateDrawable().setColorFilter( - ContextCompat.getColor(this, R.color.colorPrimary), - PorterDuff.Mode.SRC_IN); - } - - @Override public void onSaveInstanceState(Bundle outState) { super.onSaveInstanceState(outState); diff --git a/app/src/main/java/se/leap/bitmaskclient/providersetup/activities/CustomProviderSetupActivity.java b/app/src/main/java/se/leap/bitmaskclient/providersetup/activities/CustomProviderSetupActivity.java index b90d14f8d66b9f6bd4e505b601aa0847ccbf164b..9cd46049f493916fa15dad8be9248783e55b20da 100644 --- a/app/src/main/java/se/leap/bitmaskclient/providersetup/activities/CustomProviderSetupActivity.java +++ b/app/src/main/java/se/leap/bitmaskclient/providersetup/activities/CustomProviderSetupActivity.java @@ -31,10 +31,12 @@ import java.io.IOException; import se.leap.bitmaskclient.BuildConfig; import se.leap.bitmaskclient.R; import se.leap.bitmaskclient.base.models.Provider; +import se.leap.bitmaskclient.base.utils.ConfigHelper; import se.leap.bitmaskclient.providersetup.ProviderAPICommand; import static se.leap.bitmaskclient.BuildConfig.customProviderApiIp; import static se.leap.bitmaskclient.BuildConfig.customProviderIp; +import static se.leap.bitmaskclient.BuildConfig.customProviderMotdUrl; import static se.leap.bitmaskclient.BuildConfig.customProviderUrl; import static se.leap.bitmaskclient.BuildConfig.geoipUrl; import static se.leap.bitmaskclient.base.models.Constants.EXT_JSON; @@ -71,15 +73,16 @@ public class CustomProviderSetupActivity extends ProviderSetupBaseActivity { private void setDefaultProvider() { try { AssetManager assetsManager = getAssets(); - Provider customProvider = new Provider(customProviderUrl, geoipUrl, customProviderIp, customProviderApiIp); - String certificate = loadInputStreamAsString(assetsManager.open(customProvider.getDomain() + EXT_PEM)); - String providerDefinition = loadInputStreamAsString(assetsManager.open(customProvider.getDomain() + EXT_JSON)); + Provider customProvider = new Provider(customProviderUrl, geoipUrl, customProviderMotdUrl, customProviderIp, customProviderApiIp); + String domain = ConfigHelper.getDomainFromMainURL(customProviderUrl); + String certificate = loadInputStreamAsString(assetsManager.open(domain + EXT_PEM)); + String providerDefinition = loadInputStreamAsString(assetsManager.open(domain + EXT_JSON)); customProvider.setCaCert(certificate); customProvider.define(new JSONObject(providerDefinition)); setProvider(customProvider); } catch (IOException | JSONException e) { e.printStackTrace(); - setProvider(new Provider(customProviderUrl, geoipUrl, customProviderIp, customProviderApiIp)); + setProvider(new Provider(customProviderUrl, geoipUrl, customProviderMotdUrl, customProviderIp, customProviderApiIp)); } } diff --git a/app/src/main/java/se/leap/bitmaskclient/providersetup/activities/ProviderListBaseActivity.java b/app/src/main/java/se/leap/bitmaskclient/providersetup/activities/ProviderListBaseActivity.java index 002335dbc7a4a57079b68019414cc1604bb577ce..90ebfb4d9bf504faaf3df06e2ed4aebaf08aae5f 100644 --- a/app/src/main/java/se/leap/bitmaskclient/providersetup/activities/ProviderListBaseActivity.java +++ b/app/src/main/java/se/leap/bitmaskclient/providersetup/activities/ProviderListBaseActivity.java @@ -95,6 +95,7 @@ public abstract class ProviderListBaseActivity extends ProviderSetupBaseActivity @Override protected void onActivityResult(int requestCode, int resultCode, Intent data) { + super.onActivityResult(requestCode, resultCode, data); if (requestCode == REQUEST_CODE_CONFIGURE_LEAP) { if (resultCode == RESULT_OK) { setResult(resultCode, data); diff --git a/app/src/main/java/se/leap/bitmaskclient/tor/ClientTransportPlugin.java b/app/src/main/java/se/leap/bitmaskclient/tor/ClientTransportPlugin.java index 0b481780d1b4c1e7aeaa4f16456437f5826156ef..b1c4ca83ee31119821f56ef3c49179ad87cdef68 100644 --- a/app/src/main/java/se/leap/bitmaskclient/tor/ClientTransportPlugin.java +++ b/app/src/main/java/se/leap/bitmaskclient/tor/ClientTransportPlugin.java @@ -15,8 +15,14 @@ package se.leap.bitmaskclient.tor; * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ + +import static se.leap.bitmaskclient.tor.TorStatusObservable.SnowflakeStatus.RETRY_AMP_CACHE_RENDEZVOUS; +import static se.leap.bitmaskclient.tor.TorStatusObservable.SnowflakeStatus.RETRY_HTTP_RENDEZVOUS; + import android.content.Context; import android.os.FileObserver; +import android.os.Handler; +import android.os.HandlerThread; import android.util.Log; import androidx.annotation.NonNull; @@ -32,6 +38,9 @@ import java.io.InputStreamReader; import java.lang.ref.WeakReference; import java.util.Collection; import java.util.HashMap; +import java.util.Observable; +import java.util.Observer; +import java.util.Random; import java.util.Scanner; import java.util.Vector; import java.util.concurrent.TimeoutException; @@ -40,7 +49,7 @@ import java.util.regex.Pattern; import IPtProxy.IPtProxy; -public class ClientTransportPlugin implements ClientTransportPluginInterface { +public class ClientTransportPlugin implements ClientTransportPluginInterface, Observer { public static String TAG = ClientTransportPlugin.class.getSimpleName(); private HashMap<String, String> mFronts; @@ -48,9 +57,14 @@ public class ClientTransportPlugin implements ClientTransportPluginInterface { private long snowflakePort = -1; private FileObserver logFileObserver; private static final Pattern SNOWFLAKE_LOG_TIMESTAMP_PATTERN = Pattern.compile("((19|2[0-9])[0-9]{2}\\/\\d{1,2}\\/\\d{1,2} \\d{1,2}:\\d{1,2}:\\d{1,2}) ([\\S|\\s]+)"); + private TorStatusObservable.SnowflakeStatus snowflakeStatus; + private String logfilePath; + Handler handler; + HandlerThread handlerThread; public ClientTransportPlugin(Context context) { this.contextRef = new WeakReference<>(context); + handlerThread = new HandlerThread("clientTransportPlugin", Thread.MIN_PRIORITY); loadCdnFronts(context); } @@ -60,8 +74,10 @@ public class ClientTransportPlugin implements ClientTransportPluginInterface { if (context == null) { return; } + handlerThread.start(); + handler = new Handler(handlerThread.getLooper()); + TorStatusObservable.getInstance().addObserver(this); File logfile = new File(context.getApplicationContext().getCacheDir(), "snowflake.log"); - Log.d(TAG, "logfile at " + logfile.getAbsolutePath()); try { if (logfile.exists()) { logfile.delete(); @@ -70,15 +86,32 @@ public class ClientTransportPlugin implements ClientTransportPluginInterface { } catch (IOException e) { e.printStackTrace(); } + this.logfilePath = logfile.getAbsolutePath(); + Random random = new Random(); + boolean useAmpCache = random.nextInt(2) == 0; + startConnectionAttempt(useAmpCache, logfilePath); + watchLogFile(logfile); + } + private void startConnectionAttempt(boolean useAmpCache, @NonNull String logfilePath) { //this is using the current, default Tor snowflake infrastructure String target = getCdnFront("snowflake-target"); String front = getCdnFront("snowflake-front"); String stunServer = getCdnFront("snowflake-stun"); - Log.d(TAG, "startSnowflake. target: " + target + ", front:" + front + ", stunServer" + stunServer); - snowflakePort = IPtProxy.startSnowflake(stunServer, target, front, null, logfile.getAbsolutePath(), false, false, true, 5); + String ampCache = null; + if (useAmpCache) { + target = "https://snowflake-broker.torproject.net/"; + ampCache = "https://cdn.ampproject.org/"; + front = "www.google.com"; + } + snowflakePort = IPtProxy.startSnowflake(stunServer, target, front, ampCache, logfilePath, false, false, true, 5); Log.d(TAG, "startSnowflake running on port: " + snowflakePort); - watchLogFile(logfile); + } + + private void retryConnectionAttempt(boolean useAmpCache) { + Log.d(TAG, ">> retryConnectionAttempt - " + (useAmpCache ? "amp cache" : "http domain fronting")); + stopConnectionAttempt(); + startConnectionAttempt(useAmpCache, logfilePath); } private void watchLogFile(File logfile) { @@ -112,18 +145,29 @@ public class ClientTransportPlugin implements ClientTransportPluginInterface { @Override public void stop() { + stopConnectionAttempt(); + if (logFileObserver != null) { + logFileObserver.stopWatching(); + logFileObserver = null; + } + TorStatusObservable.getInstance().deleteObserver(this); + handlerThread.quit(); + handler = null; + handlerThread = null; + } + + private void stopConnectionAttempt() { IPtProxy.stopSnowflake(); - try { + try { TorStatusObservable.waitUntil(this::isSnowflakeOff, 10); } catch (InterruptedException | TimeoutException e) { e.printStackTrace(); } snowflakePort = -1; - logFileObserver.stopWatching(); } private boolean isSnowflakeOff() { - return TorStatusObservable.getSnowflakeStatus() == TorStatusObservable.SnowflakeStatus.OFF; + return TorStatusObservable.getSnowflakeStatus() == TorStatusObservable.SnowflakeStatus.STOPPED; } @Override @@ -168,11 +212,27 @@ public class ClientTransportPlugin implements ClientTransportPluginInterface { if (strippedString.length() > 0) { TorStatusObservable.logSnowflakeMessage(contextRef.get(), strippedString); } - } catch (IndexOutOfBoundsException | IllegalStateException e) { + } catch (IndexOutOfBoundsException | IllegalStateException | NullPointerException e) { e.printStackTrace(); } } else { TorStatusObservable.logSnowflakeMessage(contextRef.get(), message); } } + + @Override + public void update(Observable o, Object arg) { + if (o instanceof TorStatusObservable) { + TorStatusObservable.SnowflakeStatus snowflakeStatus = TorStatusObservable.getSnowflakeStatus(); + if (snowflakeStatus == this.snowflakeStatus) { + return; + } + if (snowflakeStatus == RETRY_HTTP_RENDEZVOUS) { + handler.post(() -> retryConnectionAttempt(false)); + } else if (snowflakeStatus == RETRY_AMP_CACHE_RENDEZVOUS) { + handler.post(() -> retryConnectionAttempt(true)); + } + this.snowflakeStatus = snowflakeStatus; + } + } } diff --git a/app/src/main/java/se/leap/bitmaskclient/tor/TorServiceCommand.java b/app/src/main/java/se/leap/bitmaskclient/tor/TorServiceCommand.java index 68988b67ef75bb7b84008dfca466aa700967f157..b99abb3d2d314488b2d3a37e256ce16a697e951d 100644 --- a/app/src/main/java/se/leap/bitmaskclient/tor/TorServiceCommand.java +++ b/app/src/main/java/se/leap/bitmaskclient/tor/TorServiceCommand.java @@ -42,7 +42,9 @@ public class TorServiceCommand { public static boolean startTorService(Context context, String action) throws InterruptedException { Log.d(TAG, "startTorService"); try { - waitUntil(TorServiceCommand::isNotCancelled, 30); + if (TorStatusObservable.isCancelled()) { + waitUntil(TorServiceCommand::isNotCancelled, 30); + } } catch (TimeoutException e) { e.printStackTrace(); } @@ -79,7 +81,8 @@ public class TorServiceCommand { @WorkerThread public static void stopTorService(Context context) { - if (TorStatusObservable.getStatus() == TorStatusObservable.TorStatus.OFF) { + if (TorStatusObservable.getStatus() == TorStatusObservable.TorStatus.STOPPING || + TorStatusObservable.getStatus() == TorStatusObservable.TorStatus.OFF) { return; } TorStatusObservable.markCancelled(); @@ -100,6 +103,9 @@ public class TorServiceCommand { } public static void stopTorServiceAsync(Context context) { + if (!TorStatusObservable.isRunning()) { + return; + } TorStatusObservable.markCancelled(); new Thread(() -> stopTorService(context)).start(); } diff --git a/app/src/main/java/se/leap/bitmaskclient/tor/TorServiceConnection.java b/app/src/main/java/se/leap/bitmaskclient/tor/TorServiceConnection.java index dbfce2b5a18cde7a80c3645f4113a9cb89dce3d1..87d3cad4aa6fb5602f5d68f1a565e0ef0db5abb1 100644 --- a/app/src/main/java/se/leap/bitmaskclient/tor/TorServiceConnection.java +++ b/app/src/main/java/se/leap/bitmaskclient/tor/TorServiceConnection.java @@ -15,6 +15,9 @@ package se.leap.bitmaskclient.tor; * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ + +import static se.leap.bitmaskclient.base.utils.ConfigHelper.ensureNotOnMainThread; + import android.content.ComponentName; import android.content.Context; import android.content.Intent; @@ -30,13 +33,9 @@ import java.io.Closeable; import java.util.concurrent.BlockingQueue; import java.util.concurrent.LinkedBlockingQueue; -import se.leap.bitmaskclient.providersetup.ProviderAPI; - -import static se.leap.bitmaskclient.base.utils.ConfigHelper.ensureNotOnMainThread; - public class TorServiceConnection implements Closeable { private static final String TAG = TorServiceConnection.class.getSimpleName(); - private final Context context; + private Context context; private ServiceConnection serviceConnection; private TorService torService; @@ -50,6 +49,9 @@ public class TorServiceConnection implements Closeable { @Override public void close() { context.unbindService(serviceConnection); + context = null; + serviceConnection = null; + torService = null; } private void initSynchronizedServiceConnection(final Context context) throws InterruptedException { diff --git a/app/src/main/java/se/leap/bitmaskclient/tor/TorStatusObservable.java b/app/src/main/java/se/leap/bitmaskclient/tor/TorStatusObservable.java index c924caeea84417ee165f6deab0213fb868f13c0c..36ab66bf8f5ed7c6074da51b98336bb8b52158d5 100644 --- a/app/src/main/java/se/leap/bitmaskclient/tor/TorStatusObservable.java +++ b/app/src/main/java/se/leap/bitmaskclient/tor/TorStatusObservable.java @@ -15,6 +15,14 @@ package se.leap.bitmaskclient.tor; * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ +import static se.leap.bitmaskclient.tor.TorStatusObservable.SnowflakeStatus.BROKER_REPLIED_SUCCESS; +import static se.leap.bitmaskclient.tor.TorStatusObservable.SnowflakeStatus.NEGOTIATING_RENDEZVOUS_VIA_AMP_CACHE; +import static se.leap.bitmaskclient.tor.TorStatusObservable.SnowflakeStatus.NEGOTIATING_RENDEZVOUS_VIA_HTTP; +import static se.leap.bitmaskclient.tor.TorStatusObservable.SnowflakeStatus.RETRY_AMP_CACHE_RENDEZVOUS; +import static se.leap.bitmaskclient.tor.TorStatusObservable.SnowflakeStatus.RETRY_HTTP_RENDEZVOUS; +import static se.leap.bitmaskclient.tor.TorStatusObservable.SnowflakeStatus.STARTED; +import static se.leap.bitmaskclient.tor.TorStatusObservable.SnowflakeStatus.STOPPED; + import android.content.Context; import android.util.Log; @@ -46,8 +54,13 @@ public class TorStatusObservable extends Observable { } public enum SnowflakeStatus { - ON, - OFF + STARTED, + NEGOTIATING_RENDEZVOUS_VIA_HTTP, + NEGOTIATING_RENDEZVOUS_VIA_AMP_CACHE, + RETRY_HTTP_RENDEZVOUS, + RETRY_AMP_CACHE_RENDEZVOUS, + BROKER_REPLIED_SUCCESS, + STOPPED } // indicates if the user has cancelled Tor, the actual TorStatus can still be different until @@ -60,17 +73,23 @@ public class TorStatusObservable extends Observable { public static final String SNOWFLAKE_STOPPED_COLLECTING = "---- SnowflakeConn: end collecting snowflakes ---"; public static final String SNOWFLAKE_COPY_LOOP_STOPPED = "copy loop ended"; public static final String SNOWFLAKE_SOCKS_ERROR = "SOCKS accept error"; + public static final String SNOWFLAKE_NEGOTIATING_HTTP = "Negotiating via HTTP rendezvous..."; + public static final String SNOWFLAKE_NEGOTIATING_AMP_CACHE = "Negotiating via AMP cache rendezvous..."; + public static final String SNOWFLAKE_CONNECTION_CLOSING = "WebRTC: Closing"; + public static final String SNOWFLAKE_HTTP_RESPONSE_200 = "HTTP rendezvous response: 200"; + public static final String SNOWFLAKE_AMP_CACHE_RESPONSE_200 = "AMP cache rendezvous response: 200"; private static TorStatusObservable instance; private TorStatus status = TorStatus.OFF; - private SnowflakeStatus snowflakeStatus = SnowflakeStatus.OFF; + private SnowflakeStatus snowflakeStatus = STOPPED; private final TorNotificationManager torNotificationManager; private String lastError; private String lastTorLog = ""; private String lastSnowflakeLog = ""; private int port = -1; private int bootstrapPercent = -1; - private Vector<String> lastLogs = new Vector<>(100); + private int retrySnowflakeRendezVous = 0; + private final Vector<String> lastLogs = new Vector<>(100); private TorStatusObservable() { torNotificationManager = new TorNotificationManager(); @@ -128,15 +147,38 @@ public class TorStatusObservable extends Observable { getInstance().torNotificationManager.buildTorNotification(context, getStringForCurrentStatus(context), getNotificationLog(), getBootstrapProgress()); } //TODO: implement proper state signalling in IPtProxy - if (SNOWFLAKE_STARTED.equals(message.trim())) { - Log.d(TAG, "snowflakeStatus ON"); - getInstance().snowflakeStatus = SnowflakeStatus.ON; - } else if (SNOWFLAKE_STOPPED_COLLECTING.equals(message.trim()) || - SNOWFLAKE_COPY_LOOP_STOPPED.equals(message.trim()) || - message.trim().contains(SNOWFLAKE_SOCKS_ERROR)) { - Log.d(TAG, "snowflakeStatus OFF"); - getInstance().snowflakeStatus = SnowflakeStatus.OFF; + message = message.trim(); + if (SNOWFLAKE_STARTED.equals(message)) { + getInstance().snowflakeStatus = STARTED; + } else if (SNOWFLAKE_NEGOTIATING_HTTP.equals(message)) { + getInstance().snowflakeStatus = NEGOTIATING_RENDEZVOUS_VIA_HTTP; + } else if (SNOWFLAKE_NEGOTIATING_AMP_CACHE.equals(message)) { + getInstance().snowflakeStatus = NEGOTIATING_RENDEZVOUS_VIA_AMP_CACHE; + } else if (SNOWFLAKE_STOPPED_COLLECTING.equals(message) || + SNOWFLAKE_COPY_LOOP_STOPPED.equals(message) || + message.contains(SNOWFLAKE_SOCKS_ERROR)) { + getInstance().snowflakeStatus = STOPPED; + } else if (SNOWFLAKE_CONNECTION_CLOSING.equals(message)) { + if (getInstance().snowflakeStatus == NEGOTIATING_RENDEZVOUS_VIA_HTTP) { + if (getInstance().retrySnowflakeRendezVous < 3) { + getInstance().retrySnowflakeRendezVous += 1; + } else { + getInstance().retrySnowflakeRendezVous = 0; + getInstance().snowflakeStatus = RETRY_AMP_CACHE_RENDEZVOUS; + } + } else if (getInstance().snowflakeStatus == NEGOTIATING_RENDEZVOUS_VIA_AMP_CACHE) { + if (getInstance().retrySnowflakeRendezVous < 3) { + getInstance().retrySnowflakeRendezVous += 1; + } else { + getInstance().retrySnowflakeRendezVous = 0; + getInstance().snowflakeStatus = RETRY_HTTP_RENDEZVOUS; + } + } + } else if (SNOWFLAKE_AMP_CACHE_RESPONSE_200.equals(message) || SNOWFLAKE_HTTP_RESPONSE_200.equals(message)) { + getInstance().snowflakeStatus = BROKER_REPLIED_SUCCESS; + getInstance().retrySnowflakeRendezVous = 0; } + Log.d(TAG, "snowflake status " + getInstance().snowflakeStatus); instance.setChanged(); instance.notifyObservers(); } @@ -178,7 +220,6 @@ public class TorStatusObservable extends Observable { if (getInstance().status == TorStatus.OFF) { getInstance().torNotificationManager.cancelNotifications(context); getInstance().cancelled = false; - getInstance().port = -1; } else { if (logKey != null) { getInstance().lastTorLog = getStringFor(context, logKey); @@ -264,6 +305,10 @@ public class TorStatusObservable extends Observable { } public static String getStringForCurrentStatus(Context context) { + if (context == null) { + return ""; + } + switch (getInstance().status) { case ON: return context.getString(R.string.tor_started); @@ -280,6 +325,8 @@ public class TorStatusObservable extends Observable { public static void markCancelled() { if (!getInstance().cancelled) { getInstance().cancelled = true; + getInstance().port = -1; + getInstance().setChanged(); getInstance().notifyObservers(); } } @@ -287,4 +334,9 @@ public class TorStatusObservable extends Observable { public static boolean isCancelled() { return getInstance().cancelled; } + + public static boolean isRunning() { + return !TorStatusObservable.isCancelled() && + TorStatusObservable.getStatus() != TorStatusObservable.TorStatus.OFF; + } } diff --git a/app/src/main/res/color/button_state_font_color.xml b/app/src/main/res/color/button_state_font_color.xml deleted file mode 100644 index f7fed335518e0694d2c975fe334f24a7cd9e0a10..0000000000000000000000000000000000000000 --- a/app/src/main/res/color/button_state_font_color.xml +++ /dev/null @@ -1,5 +0,0 @@ -<?xml version="1.0" encoding="utf-8"?> -<selector xmlns:android="http://schemas.android.com/apk/res/android"> - <item android:color="@color/colorFontBtnEnabled" android:state_enabled="true"/> - <item android:color="@color/colorFontBtn"/> -</selector> \ No newline at end of file diff --git a/app/src/main/res/color/main_button_state_color.xml b/app/src/main/res/color/main_button_state_color.xml deleted file mode 100644 index 9650b033c7a65e5eff28014e364fbf99bdab2369..0000000000000000000000000000000000000000 --- a/app/src/main/res/color/main_button_state_color.xml +++ /dev/null @@ -1,5 +0,0 @@ -<?xml version="1.0" encoding="utf-8"?> -<selector xmlns:android="http://schemas.android.com/apk/res/android"> - <item android:color="@color/colorPrimaryDark" android:state_pressed="true"/> - <item android:color="@color/colorPrimary"/> -</selector> \ No newline at end of file diff --git a/app/src/main/res/drawable-anydpi-v24/ic_btn_cancel.xml b/app/src/main/res/drawable-anydpi-v24/ic_btn_cancel.xml new file mode 100644 index 0000000000000000000000000000000000000000..9870cd4fad321c4bb1bfc0490514e2ed91c9d041 --- /dev/null +++ b/app/src/main/res/drawable-anydpi-v24/ic_btn_cancel.xml @@ -0,0 +1,9 @@ +<vector xmlns:android="http://schemas.android.com/apk/res/android" xmlns:aapt="http://schemas.android.com/aapt" + android:viewportWidth="35" + android:viewportHeight="35" + android:width="35dp" + android:height="35dp"> + <path + android:pathData="M4.9 35L17.5 22.4L30.1 35L35 30.1L22.4 17.5L35 4.9L30.1 0L17.5 12.6L4.9 0L0 4.9L12.6 17.5L0 30.1L4.9 35Z" + android:fillColor="#FFFFFF" /> +</vector> \ No newline at end of file diff --git a/app/src/main/res/drawable-anydpi-v24/ic_btn_on.xml b/app/src/main/res/drawable-anydpi-v24/ic_btn_on.xml new file mode 100644 index 0000000000000000000000000000000000000000..0f3fc0f49637cbe355805558eeb38f2d11e0b189 --- /dev/null +++ b/app/src/main/res/drawable-anydpi-v24/ic_btn_on.xml @@ -0,0 +1,10 @@ +<vector xmlns:android="http://schemas.android.com/apk/res/android" + xmlns:aapt="http://schemas.android.com/aapt" + android:viewportWidth="40" + android:viewportHeight="43" + android:width="40dp" + android:height="43dp"> + <path + android:pathData="M33.0178 7.38594C32.1199 6.61398 30.7913 6.74461 29.9562 7.58411C28.8438 8.70244 29.0811 10.5681 30.2333 11.6454C33.1633 14.3851 35 18.2798 35 22.6203C35 26.6198 33.4196 30.4556 30.6066 33.2836C27.7936 36.1117 23.9782 37.7005 20 37.7005C16.0218 37.7005 12.2064 36.1117 9.3934 33.2836C6.58035 30.4556 5 26.6198 5 22.6203C5 18.2699 6.84513 14.3673 9.77413 11.6139C10.9153 10.5411 11.1444 8.69064 10.0399 7.58018C9.20708 6.74295 7.88204 6.6127 6.98641 7.38232C2.70788 11.0589 0 16.5193 0 22.6203C0 27.953 2.10714 33.0673 5.85786 36.8381C9.60859 40.6089 14.6957 42.7273 20 42.7273C25.3043 42.7273 30.3914 40.6089 34.1421 36.8381C37.8929 33.0673 40 27.953 40 22.6203C40 16.5213 37.2939 11.0625 33.0178 7.38594ZM22.5 0C19.7386 0 17.5 2.23858 17.5 5V20.1337C17.5 22.8951 19.7386 25.1337 22.5 25.1337" + android:fillColor="#FFFFFF" /> +</vector> \ No newline at end of file diff --git a/app/src/main/res/drawable-hdpi/bitmask_text.png b/app/src/main/res/drawable-hdpi/bitmask_text.png new file mode 100644 index 0000000000000000000000000000000000000000..71c0d171384c29d342c000bf94d79224f816da17 Binary files /dev/null and b/app/src/main/res/drawable-hdpi/bitmask_text.png differ diff --git a/app/src/main/res/drawable-hdpi/ic_access_point_36.png b/app/src/main/res/drawable-hdpi/ic_access_point_36.png index 03444d0ff2f6db200217adb22d26797e68fd53fc..4adb83b91513635e1311d9a1d1db35aca4623622 100644 Binary files a/app/src/main/res/drawable-hdpi/ic_access_point_36.png and b/app/src/main/res/drawable-hdpi/ic_access_point_36.png differ diff --git a/app/src/main/res/drawable-hdpi/ic_always_on_36.png b/app/src/main/res/drawable-hdpi/ic_always_on_36.png index 8547b61dd66f79d7fa32d7e1abc34af84d23c2b7..4e4dac99fdfc9ab557052ef94e63d69e82e71fc7 100644 Binary files a/app/src/main/res/drawable-hdpi/ic_always_on_36.png and b/app/src/main/res/drawable-hdpi/ic_always_on_36.png differ diff --git a/app/src/main/res/drawable-hdpi/ic_arrow_right.png b/app/src/main/res/drawable-hdpi/ic_arrow_right.png new file mode 100644 index 0000000000000000000000000000000000000000..2d081384e76a6212a12e48a45b199213dea6d2be Binary files /dev/null and b/app/src/main/res/drawable-hdpi/ic_arrow_right.png differ diff --git a/app/src/main/res/drawable-hdpi/ic_multiple_stop.png b/app/src/main/res/drawable-hdpi/ic_multiple_stop.png index cd67c160df0e0c5c63546bbc332b617874e5011a..8dbd17a73a64cd12af7e103e1c6e9f8302b52862 100644 Binary files a/app/src/main/res/drawable-hdpi/ic_multiple_stop.png and b/app/src/main/res/drawable-hdpi/ic_multiple_stop.png differ diff --git a/app/src/main/res/drawable-hdpi/ic_shield_remove_grey600_36dp.png b/app/src/main/res/drawable-hdpi/ic_shield_remove_grey600_36dp.png index 98dec84c125559ff86a646eb639925f8dc6c5815..6762b5a8783e90c6de8e1e13d066e43db2c53491 100644 Binary files a/app/src/main/res/drawable-hdpi/ic_shield_remove_grey600_36dp.png and b/app/src/main/res/drawable-hdpi/ic_shield_remove_grey600_36dp.png differ diff --git a/app/src/main/res/drawable-hdpi/leap_footer_en.png b/app/src/main/res/drawable-hdpi/leap_footer_en.png new file mode 100644 index 0000000000000000000000000000000000000000..bce90e6a4c2d0cb410e963e15f63e68505d0a45c Binary files /dev/null and b/app/src/main/res/drawable-hdpi/leap_footer_en.png differ diff --git a/app/src/main/res/drawable-ldpi/ic_arrow_right.png b/app/src/main/res/drawable-ldpi/ic_arrow_right.png new file mode 100644 index 0000000000000000000000000000000000000000..7fc572af03883f0d0cb502b745352f3e287a48d3 Binary files /dev/null and b/app/src/main/res/drawable-ldpi/ic_arrow_right.png differ diff --git a/app/src/main/res/drawable-ldpi/ic_multiple_stop.png b/app/src/main/res/drawable-ldpi/ic_multiple_stop.png deleted file mode 100644 index fc0a47e14824f4d43fedc2774b33006b9662aebd..0000000000000000000000000000000000000000 Binary files a/app/src/main/res/drawable-ldpi/ic_multiple_stop.png and /dev/null differ diff --git a/app/src/main/res/drawable-mdpi/ic_access_point_36.png b/app/src/main/res/drawable-mdpi/ic_access_point_36.png index c461a0a5c4cd99344b4a395cbfa96a5b6709a03a..e8c03d2b87fea5fc1ac0c4ca86bd024ad9ab3cfb 100644 Binary files a/app/src/main/res/drawable-mdpi/ic_access_point_36.png and b/app/src/main/res/drawable-mdpi/ic_access_point_36.png differ diff --git a/app/src/main/res/drawable-mdpi/ic_always_on_36.png b/app/src/main/res/drawable-mdpi/ic_always_on_36.png index ea15a06757a4918f1a8ff70d85e885a581115645..16b7d0f9e7a1108edacdd6cbe456ef91ac15a292 100644 Binary files a/app/src/main/res/drawable-mdpi/ic_always_on_36.png and b/app/src/main/res/drawable-mdpi/ic_always_on_36.png differ diff --git a/app/src/main/res/drawable-mdpi/ic_arrow_right.png b/app/src/main/res/drawable-mdpi/ic_arrow_right.png new file mode 100644 index 0000000000000000000000000000000000000000..60702e35ac164e50ac70addeb39d39a622f85fc1 Binary files /dev/null and b/app/src/main/res/drawable-mdpi/ic_arrow_right.png differ diff --git a/app/src/main/res/drawable-mdpi/ic_multiple_stop.png b/app/src/main/res/drawable-mdpi/ic_multiple_stop.png index fc0a47e14824f4d43fedc2774b33006b9662aebd..8b45c9dfc1ea17a5b2e3ea21593c780d3a693e91 100644 Binary files a/app/src/main/res/drawable-mdpi/ic_multiple_stop.png and b/app/src/main/res/drawable-mdpi/ic_multiple_stop.png differ diff --git a/app/src/main/res/drawable-mdpi/ic_shield_remove_grey600_36dp.png b/app/src/main/res/drawable-mdpi/ic_shield_remove_grey600_36dp.png index d4b610303aa5062a4e4876268b17fd782ef7cbb3..3ae1ffc65f3f8d01f08296776e3d5425d657c278 100644 Binary files a/app/src/main/res/drawable-mdpi/ic_shield_remove_grey600_36dp.png and b/app/src/main/res/drawable-mdpi/ic_shield_remove_grey600_36dp.png differ diff --git a/app/src/main/res/drawable-xhdpi/bitmask_text.png b/app/src/main/res/drawable-xhdpi/bitmask_text.png new file mode 100644 index 0000000000000000000000000000000000000000..f0f8f238c5bbe39fbaed72ef452b0bf072955d7a Binary files /dev/null and b/app/src/main/res/drawable-xhdpi/bitmask_text.png differ diff --git a/app/src/main/res/drawable-xhdpi/ic_access_point_36.png b/app/src/main/res/drawable-xhdpi/ic_access_point_36.png index 4ae3d1d90730dda41f5c1ab3e1b66e62d1e04ec3..e0e52ed5383c2dd826c11439fafac9464334d536 100644 Binary files a/app/src/main/res/drawable-xhdpi/ic_access_point_36.png and b/app/src/main/res/drawable-xhdpi/ic_access_point_36.png differ diff --git a/app/src/main/res/drawable-xhdpi/ic_always_on_36.png b/app/src/main/res/drawable-xhdpi/ic_always_on_36.png index 811d64d730333e0b092b334d31530d40aa20bd90..53a7223d0fe6a6a645f9faef29b15015f71229ae 100644 Binary files a/app/src/main/res/drawable-xhdpi/ic_always_on_36.png and b/app/src/main/res/drawable-xhdpi/ic_always_on_36.png differ diff --git a/app/src/main/res/drawable-xhdpi/ic_arrow_right.png b/app/src/main/res/drawable-xhdpi/ic_arrow_right.png new file mode 100644 index 0000000000000000000000000000000000000000..f1f4f691dff91ef256221cfb742d7c10ea83cc14 Binary files /dev/null and b/app/src/main/res/drawable-xhdpi/ic_arrow_right.png differ diff --git a/app/src/main/res/drawable-xhdpi/ic_multiple_stop.png b/app/src/main/res/drawable-xhdpi/ic_multiple_stop.png index c16a18c14dca9bce7b2854b8d5916efe38240d4b..3af7207c19b1be2d6aae9f0919a57a99090f02f5 100644 Binary files a/app/src/main/res/drawable-xhdpi/ic_multiple_stop.png and b/app/src/main/res/drawable-xhdpi/ic_multiple_stop.png differ diff --git a/app/src/main/res/drawable-xhdpi/ic_shield_remove_grey600_36dp.png b/app/src/main/res/drawable-xhdpi/ic_shield_remove_grey600_36dp.png index 3eae1fdc1e8442e6337edd0b54a413b78792bfa3..1b47eec100eff573c465cfb046d8e4cbbb823e23 100644 Binary files a/app/src/main/res/drawable-xhdpi/ic_shield_remove_grey600_36dp.png and b/app/src/main/res/drawable-xhdpi/ic_shield_remove_grey600_36dp.png differ diff --git a/app/src/main/res/drawable-xhdpi/leap_footer_en.png b/app/src/main/res/drawable-xhdpi/leap_footer_en.png new file mode 100644 index 0000000000000000000000000000000000000000..80191c93762c2528bb2e6b0f059bd1d8ad3231c1 Binary files /dev/null and b/app/src/main/res/drawable-xhdpi/leap_footer_en.png differ diff --git a/app/src/main/res/drawable-xxhdpi/bg_switchbar.xml b/app/src/main/res/drawable-xxhdpi/bg_switchbar.xml deleted file mode 100644 index 7af57ad3cb57abd81cfa93d1f5a9341831b92ae3..0000000000000000000000000000000000000000 --- a/app/src/main/res/drawable-xxhdpi/bg_switchbar.xml +++ /dev/null @@ -1,9 +0,0 @@ -<?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 - --> - -<shape xmlns:android="http://schemas.android.com/apk/res/android"> - <solid android:color="@color/switchbar" /> -</shape> \ No newline at end of file diff --git a/app/src/main/res/drawable-xxhdpi/bitmask_text.png b/app/src/main/res/drawable-xxhdpi/bitmask_text.png new file mode 100644 index 0000000000000000000000000000000000000000..411c2946ac0afb6db0b66bfda88f0ac66b525ba3 Binary files /dev/null and b/app/src/main/res/drawable-xxhdpi/bitmask_text.png differ diff --git a/app/src/main/res/drawable-xxhdpi/ic_always_on_36.png b/app/src/main/res/drawable-xxhdpi/ic_always_on_36.png index bfb87c493ed491ac3940800c99e806da8fb3b52c..a73108d525c4341a1328a83ec4e709584405cb4d 100644 Binary files a/app/src/main/res/drawable-xxhdpi/ic_always_on_36.png and b/app/src/main/res/drawable-xxhdpi/ic_always_on_36.png differ diff --git a/app/src/main/res/drawable-xxhdpi/ic_arrow_right.png b/app/src/main/res/drawable-xxhdpi/ic_arrow_right.png new file mode 100644 index 0000000000000000000000000000000000000000..e0031ca875aacb075c8a74c4be55c03e934d86ef Binary files /dev/null and b/app/src/main/res/drawable-xxhdpi/ic_arrow_right.png differ diff --git a/app/src/main/res/drawable-xxhdpi/ic_multiple_stop.png b/app/src/main/res/drawable-xxhdpi/ic_multiple_stop.png index b6fe22a8de19e4fad773ea8c1eca7d1543875ee0..44834b47b7702cb620e3bdfd253f64e9d8afea29 100644 Binary files a/app/src/main/res/drawable-xxhdpi/ic_multiple_stop.png and b/app/src/main/res/drawable-xxhdpi/ic_multiple_stop.png differ diff --git a/app/src/main/res/drawable-xxhdpi/ic_shield_remove_grey600_36dp.png b/app/src/main/res/drawable-xxhdpi/ic_shield_remove_grey600_36dp.png index c6761744095f16c95ddc0a495b2afa37b0646de6..2ef3b56956979e45be3415a136c9f48a7f222ba1 100644 Binary files a/app/src/main/res/drawable-xxhdpi/ic_shield_remove_grey600_36dp.png and b/app/src/main/res/drawable-xxhdpi/ic_shield_remove_grey600_36dp.png differ diff --git a/app/src/main/res/drawable-xxhdpi/leap_footer_en.png b/app/src/main/res/drawable-xxhdpi/leap_footer_en.png new file mode 100644 index 0000000000000000000000000000000000000000..f7c573ca90e20d8d337113190e48552043deb121 Binary files /dev/null and b/app/src/main/res/drawable-xxhdpi/leap_footer_en.png differ diff --git a/app/src/main/res/drawable-xxxhdpi/bitmask_text.png b/app/src/main/res/drawable-xxxhdpi/bitmask_text.png new file mode 100644 index 0000000000000000000000000000000000000000..a73f452642dbb16e55bbfadad7769e72fbbfad67 Binary files /dev/null and b/app/src/main/res/drawable-xxxhdpi/bitmask_text.png differ diff --git a/app/src/main/res/drawable-xxxhdpi/ic_access_point_36.png b/app/src/main/res/drawable-xxxhdpi/ic_access_point_36.png index 4a2f25c1b66befe9f830aa766f74d6189314e9a1..028679c95e6a11232900ab79f7c0122997938f6d 100644 Binary files a/app/src/main/res/drawable-xxxhdpi/ic_access_point_36.png and b/app/src/main/res/drawable-xxxhdpi/ic_access_point_36.png differ diff --git a/app/src/main/res/drawable-xxxhdpi/ic_always_on_36.png b/app/src/main/res/drawable-xxxhdpi/ic_always_on_36.png index f8e2a7907fb98f4cff3fa2707916188202327e70..a49e86a9419658610f42c4e4858a18629537ae0f 100644 Binary files a/app/src/main/res/drawable-xxxhdpi/ic_always_on_36.png and b/app/src/main/res/drawable-xxxhdpi/ic_always_on_36.png differ diff --git a/app/src/main/res/drawable-xxxhdpi/ic_arrow_right.png b/app/src/main/res/drawable-xxxhdpi/ic_arrow_right.png new file mode 100644 index 0000000000000000000000000000000000000000..1b4f4239d4d439bf6f01afa2d867dc196b25a843 Binary files /dev/null and b/app/src/main/res/drawable-xxxhdpi/ic_arrow_right.png differ diff --git a/app/src/main/res/drawable-xxxhdpi/ic_multiple_stop.png b/app/src/main/res/drawable-xxxhdpi/ic_multiple_stop.png index 6cf3f58be07c7cbd89f51ef7c3ce1a3e2e98364b..336003f7a30f9ae6b500aadbf9bf5b33d48088b6 100644 Binary files a/app/src/main/res/drawable-xxxhdpi/ic_multiple_stop.png and b/app/src/main/res/drawable-xxxhdpi/ic_multiple_stop.png differ diff --git a/app/src/main/res/drawable-xxxhdpi/ic_shield_remove_grey600_36dp.png b/app/src/main/res/drawable-xxxhdpi/ic_shield_remove_grey600_36dp.png index ad08be948f6541af7456e8a4de7e170c985f273b..d48ed0d0fc986b52a334eeaa3b2ba714bf679cae 100644 Binary files a/app/src/main/res/drawable-xxxhdpi/ic_shield_remove_grey600_36dp.png and b/app/src/main/res/drawable-xxxhdpi/ic_shield_remove_grey600_36dp.png differ diff --git a/app/src/main/res/drawable-xxxhdpi/leap_footer_en.png b/app/src/main/res/drawable-xxxhdpi/leap_footer_en.png new file mode 100644 index 0000000000000000000000000000000000000000..f4c20d5628afea4d6c288688e740a8b38a795e52 Binary files /dev/null and b/app/src/main/res/drawable-xxxhdpi/leap_footer_en.png differ diff --git a/app/src/main/res/drawable/background_motd.xml b/app/src/main/res/drawable/background_motd.xml new file mode 100644 index 0000000000000000000000000000000000000000..519e02330dbd144a5b98e26f8615b84ae7ac0694 --- /dev/null +++ b/app/src/main/res/drawable/background_motd.xml @@ -0,0 +1,9 @@ +<?xml version="1.0" encoding="utf-8"?> +<shape xmlns:android="http://schemas.android.com/apk/res/android" + android:shape="rectangle" + > + <gradient android:startColor="@color/black_high_transparent" + android:endColor="@color/white_transparent" + android:angle="90" + /> +</shape> \ No newline at end of file diff --git a/app/src/main/res/drawable/bitmask_text.png b/app/src/main/res/drawable/bitmask_text.png new file mode 100644 index 0000000000000000000000000000000000000000..9a13b15052e5443df939d3061946c1353f449120 Binary files /dev/null and b/app/src/main/res/drawable/bitmask_text.png differ diff --git a/app/src/main/res/drawable/button_circle_cancel.xml b/app/src/main/res/drawable/button_circle_cancel.xml new file mode 100644 index 0000000000000000000000000000000000000000..1d94abca5a17e2ba1100908e78783745abdad17e --- /dev/null +++ b/app/src/main/res/drawable/button_circle_cancel.xml @@ -0,0 +1,5 @@ +<?xml version="1.0" encoding="utf-8"?> +<selector xmlns:android="http://schemas.android.com/apk/res/android"> + <item android:drawable="@drawable/button_circle_cancel_pressed" android:state_pressed="true"/> + <item android:drawable="@drawable/button_circle_cancel_released"/> +</selector> \ No newline at end of file diff --git a/app/src/main/res/drawable/button_circle_cancel_pressed.xml b/app/src/main/res/drawable/button_circle_cancel_pressed.xml new file mode 100644 index 0000000000000000000000000000000000000000..6b280959acbe549a86caf6d41075e5f8fe6ac03b --- /dev/null +++ b/app/src/main/res/drawable/button_circle_cancel_pressed.xml @@ -0,0 +1,60 @@ +<?xml version="1.0" encoding="utf-8"?> +<layer-list xmlns:android="http://schemas.android.com/apk/res/android"> + <!-- <item> + <shape android:shape="rectangle"> + <solid android:color="@color/white"/> + <size android:width="250dp" android:height="250dp"/> + </shape> + </item> --> + <item + android:left="-23dp" + android:right="-23dp" + android:top="-8dp" + android:bottom="-8dp" + > + <animated-rotate + android:drawable="@drawable/rotate_progress_image" + android:pivotX="50.0%" + android:pivotY="50.0%" + android:fromDegrees="0.0" + android:toDegrees="360.0" + > + </animated-rotate> + </item> + <item + android:top="18dp" + android:bottom="12dp" + > + <shape android:shape="oval"> + <solid android:color="@color/btn_cancel_dark"/> + <size android:width="250dp" android:height="250dp" /> + </shape> + </item> + <item + android:top="18dp" + android:bottom="12dp" + > + <shape + android:shape="ring" + android:innerRadius="125dp" + android:useLevel="false" + android:thickness="3dp"> + <gradient + android:type="radial" + android:gradientRadius="125dp" + android:centerX="0.50" + android:centerY="0.54" + android:startColor="#000000" + android:centerColor="#000000" + android:endColor="@color/transparent" /> + + </shape> + </item> + <item + android:top="88dp" + android:bottom="82dp" + android:left="70dp" + android:right="70dp" + android:drawable="@drawable/ic_btn_cancel" /> + +</layer-list> \ No newline at end of file diff --git a/app/src/main/res/drawable/button_circle_cancel_released.xml b/app/src/main/res/drawable/button_circle_cancel_released.xml new file mode 100644 index 0000000000000000000000000000000000000000..cd93ab2bb5274be0c924f113c5d685c4ca776b5f --- /dev/null +++ b/app/src/main/res/drawable/button_circle_cancel_released.xml @@ -0,0 +1,61 @@ +<?xml version="1.0" encoding="utf-8"?> +<layer-list xmlns:android="http://schemas.android.com/apk/res/android"> + <!-- <item> + <shape android:shape="rectangle"> + <solid android:color="@color/white"/> + <size android:width="250dp" android:height="250dp"/> + </shape> + </item>--> + + <item + android:left="-25dp" + android:right="-25dp" + android:top="-10dp" + android:bottom="-10dp" + > + <animated-rotate + android:drawable="@drawable/rotate_progress_image" + android:pivotX="50.0%" + android:pivotY="50.0%" + android:fromDegrees="0.0" + android:toDegrees="360.0" + > + </animated-rotate> + </item> + <item + android:bottom="15dp" + android:top="15dp" + > + <shape android:shape="oval"> + <solid android:color="@color/btn_cancel"/> + <size android:width="250dp" android:height="250dp" /> + </shape> + </item> + <item + android:bottom="15dp" + android:top="15dp" + > + <shape + android:shape="ring" + android:innerRadius="123dp" + android:useLevel="false" + android:thickness="15dp"> + <gradient + android:type="radial" + android:gradientRadius="125dp" + android:centerX="0.51" + android:centerY="0.55" + android:startColor="#000000" + android:centerColor="#000000" + android:endColor="@color/transparent" /> + + </shape> + </item> + <item + android:top="85dp" + android:bottom="85dp" + android:left="70dp" + android:right="70dp" + android:drawable="@drawable/ic_btn_cancel" + /> +</layer-list> \ No newline at end of file diff --git a/app/src/main/res/drawable/button_circle_start.xml b/app/src/main/res/drawable/button_circle_start.xml new file mode 100644 index 0000000000000000000000000000000000000000..6d8482f4afff6b7cfb0144b54cec1b736281f6b6 --- /dev/null +++ b/app/src/main/res/drawable/button_circle_start.xml @@ -0,0 +1,7 @@ +<?xml version="1.0" encoding="utf-8"?> +<selector xmlns:android="http://schemas.android.com/apk/res/android"> + <item android:drawable="@drawable/button_circle_start_pressed" android:state_pressed="true"> + </item> + <item android:drawable="@drawable/button_circle_start_released"> + </item> +</selector> \ No newline at end of file diff --git a/app/src/main/res/drawable/button_circle_start_pressed.xml b/app/src/main/res/drawable/button_circle_start_pressed.xml new file mode 100644 index 0000000000000000000000000000000000000000..08712c47eb98a46b2547c591885a07329976837c --- /dev/null +++ b/app/src/main/res/drawable/button_circle_start_pressed.xml @@ -0,0 +1,44 @@ +<?xml version="1.0" encoding="utf-8"?> +<layer-list xmlns:android="http://schemas.android.com/apk/res/android"> + <!--<item> + <shape android:shape="rectangle"> + <solid android:color="@color/white"/> + <size android:width="250dp" android:height="250dp"/> + </shape> + </item>--> + <item + android:top="18dp" + android:bottom="12dp" + > + <shape android:shape="oval"> + <solid android:color="@color/btn_start_dark"/> + <size android:width="250dp" android:height="250dp" /> + </shape> + </item> + <item + android:top="18dp" + android:bottom="12dp" + > + <shape + android:shape="ring" + android:innerRadius="125dp" + android:useLevel="false" + android:thickness="3dp"> + <gradient + android:type="radial" + android:gradientRadius="125dp" + android:centerX="0.50" + android:centerY="0.54" + android:startColor="#000000" + android:centerColor="#000000" + android:endColor="@color/transparent" /> + + </shape> + </item> + <item + android:top="78dp" + android:bottom="72dp" + android:left="60dp" + android:right="60dp" + android:drawable="@drawable/ic_btn_on" /> +</layer-list> \ No newline at end of file diff --git a/app/src/main/res/drawable/button_circle_start_released.xml b/app/src/main/res/drawable/button_circle_start_released.xml new file mode 100644 index 0000000000000000000000000000000000000000..c47d101920b35324d59539723ae88bbecfde53e6 --- /dev/null +++ b/app/src/main/res/drawable/button_circle_start_released.xml @@ -0,0 +1,44 @@ +<?xml version="1.0" encoding="utf-8"?> +<layer-list xmlns:android="http://schemas.android.com/apk/res/android"> + <!--<item> + <shape android:shape="rectangle"> + <solid android:color="@color/white"/> + <size android:width="250dp" android:height="250dp"/> + </shape> + </item>--> + <item + android:bottom="15dp" + android:top="15dp" + > + <shape android:shape="oval"> + <solid android:color="@color/btn_start"/> + <size android:width="250dp" android:height="250dp" /> + </shape> + </item> + <item + android:bottom="15dp" + android:top="15dp" + > + <shape + android:shape="ring" + android:innerRadius="122dp" + android:useLevel="false" + android:thickness="15dp"> + <gradient + android:type="radial" + android:gradientRadius="125dp" + android:centerX="0.51" + android:centerY="0.55" + android:startColor="#000000" + android:centerColor="#000000" + android:endColor="@color/transparent" /> + + </shape> + </item> + <item + android:top="75dp" + android:bottom="75dp" + android:left="60dp" + android:right="60dp" + android:drawable="@drawable/ic_btn_on" /> +</layer-list> \ No newline at end of file diff --git a/app/src/main/res/drawable/main_btn_shadow.xml b/app/src/main/res/drawable/button_circle_stop.xml similarity index 53% rename from app/src/main/res/drawable/main_btn_shadow.xml rename to app/src/main/res/drawable/button_circle_stop.xml index 94cf379f455117dd75d1144fcd36b6fc90531ef0..674cbf15ab130f89bec540fdd84f8660db241dc5 100644 --- a/app/src/main/res/drawable/main_btn_shadow.xml +++ b/app/src/main/res/drawable/button_circle_stop.xml @@ -1,5 +1,5 @@ <?xml version="1.0" encoding="utf-8"?> <selector xmlns:android="http://schemas.android.com/apk/res/android"> - <item android:drawable="@drawable/on_off_btn_start_2_pressed" android:state_pressed="true"/> - <item android:drawable="@drawable/on_off_btn_start_2_enabled"/> + <item android:drawable="@drawable/button_circle_stop_pressed" android:state_pressed="true"/> + <item android:drawable="@drawable/button_circle_stop_released"/> </selector> \ No newline at end of file diff --git a/app/src/main/res/drawable/button_circle_stop_pressed.xml b/app/src/main/res/drawable/button_circle_stop_pressed.xml new file mode 100644 index 0000000000000000000000000000000000000000..52a5a88e194c7b4629b0ae7b60880342186d0a3c --- /dev/null +++ b/app/src/main/res/drawable/button_circle_stop_pressed.xml @@ -0,0 +1,44 @@ +<?xml version="1.0" encoding="utf-8"?> +<layer-list xmlns:android="http://schemas.android.com/apk/res/android"> + <!--<item> + <shape android:shape="rectangle"> + <solid android:color="@color/white"/> + <size android:width="250dp" android:height="250dp"/> + </shape> + </item>--> + <item + android:top="18dp" + android:bottom="12dp" + > + <shape android:shape="oval"> + <solid android:color="@color/btn_stop_dark"/> + <size android:width="250dp" android:height="250dp" /> + </shape> + </item> + <item + android:top="18dp" + android:bottom="12dp" + > + <shape + android:shape="ring" + android:innerRadius="125dp" + android:useLevel="false" + android:thickness="3dp"> + <gradient + android:type="radial" + android:gradientRadius="125dp" + android:centerX="0.51" + android:centerY="0.54" + android:startColor="#000000" + android:centerColor="#000000" + android:endColor="@color/transparent" /> + + </shape> + </item> + <item + android:top="88dp" + android:bottom="82dp" + android:left="70dp" + android:right="70dp" + android:drawable="@drawable/ic_btn_cancel" /> +</layer-list> \ No newline at end of file diff --git a/app/src/main/res/drawable/button_circle_stop_released.xml b/app/src/main/res/drawable/button_circle_stop_released.xml new file mode 100644 index 0000000000000000000000000000000000000000..d29bfe1ea6f8504436ac415db6b0b819f8b2eb09 --- /dev/null +++ b/app/src/main/res/drawable/button_circle_stop_released.xml @@ -0,0 +1,45 @@ +<?xml version="1.0" encoding="utf-8"?> +<layer-list xmlns:android="http://schemas.android.com/apk/res/android"> + <!--<item> + <shape android:shape="rectangle"> + <solid android:color="@color/white"/> + <size android:width="250dp" android:height="250dp"/> + </shape> + </item>--> + <item + android:bottom="15dp" + android:top="15dp" + > + <shape android:shape="oval"> + <solid android:color="@color/btn_stop"/> + <size android:width="250dp" android:height="250dp" /> + </shape> + </item> + <item + android:bottom="15dp" + android:top="15dp" + > + <shape + android:shape="ring" + android:innerRadius="122dp" + android:useLevel="false" + android:thickness="15dp"> + <gradient + android:type="radial" + android:gradientRadius="125dp" + android:centerX="0.51" + android:centerY="0.55" + android:startColor="#000000" + android:centerColor="#000000" + android:endColor="@color/transparent" /> + + </shape> + </item> + <item + android:top="85dp" + android:bottom="85dp" + android:left="70dp" + android:right="70dp" + android:drawable="@drawable/ic_btn_cancel" + /> +</layer-list> \ No newline at end of file diff --git a/app/src/main/res/drawable/cust_button_light_rect.xml b/app/src/main/res/drawable/cust_button_light_rect.xml new file mode 100644 index 0000000000000000000000000000000000000000..9840d7e10934d4d6177da7cb914df7368f4e8e92 --- /dev/null +++ b/app/src/main/res/drawable/cust_button_light_rect.xml @@ -0,0 +1,66 @@ +<?xml version="1.0" encoding="utf-8"?> +<selector xmlns:android="http://schemas.android.com/apk/res/android" > + <item android:state_pressed="true" > + <layer-list + android:paddingLeft="@dimen/button_bevel" + android:paddingRight="@dimen/button_bevel"> + <item> + <shape android:shape="rectangle"> + <solid android:color="@color/black_transparent"/> + <corners android:radius="@dimen/stdpadding"/> + </shape> + </item> + <item> + <shape android:shape="rectangle"> + <solid android:color="@color/btn_light_transparent_dark"/> + <corners android:radius="@dimen/stdpadding"/> + </shape> + </item> + </layer-list> + </item> + <item android:state_focused="true"> + <layer-list + android:paddingLeft="@dimen/button_bevel" + android:paddingRight="@dimen/button_bevel"> + <item> + <shape android:shape="rectangle" > + <solid android:color="@color/black_transparent"/> + <corners android:radius="@dimen/stdpadding"/> + </shape> + </item> + <item> + <shape android:shape="rectangle"> + <solid android:color="@color/btn_light_transparent_dark"/> + <corners android:radius="@dimen/stdpadding"/> + </shape> + </item> + + </layer-list> + </item> + <item > + <layer-list + android:paddingLeft="@dimen/button_bevel" + android:paddingRight="@dimen/button_bevel"> + <!-- shadow --> + <item + android:top="@dimen/button_bevel" + android:left="1dp" + > + <shape android:shape="rectangle" > + <corners android:radius="@dimen/stdpadding" /> + <solid android:color="@color/black_transparent"/> + </shape> + </item> + <!-- fill --> + <item + android:bottom="@dimen/button_bevel" + android:right="1dp" + > + <shape android:shape="rectangle" > + <solid android:color="@color/btn_light_transparent"/> + <corners android:radius="@dimen/stdpadding"/> + </shape> + </item> + </layer-list> + </item> +</selector> \ No newline at end of file diff --git a/app/src/main/res/drawable/footer_text_drawable.xml b/app/src/main/res/drawable/footer_text_drawable.xml new file mode 100644 index 0000000000000000000000000000000000000000..e3ec50051d6a0a376c37681897378202bac5565b --- /dev/null +++ b/app/src/main/res/drawable/footer_text_drawable.xml @@ -0,0 +1,21 @@ +<?xml version="1.0" encoding="utf-8"?> + +<layer-list xmlns:android="http://schemas.android.com/apk/res/android"> + <item + android:gravity="fill_horizontal"> + + <shape android:shape="rectangle" + xmlns:android="http://schemas.android.com/apk/res/android"> + <solid android:color="@android:color/white"/> + </shape> + </item> + <item + android:gravity="center" + android:top="@dimen/footer_text_padding" + android:bottom="@dimen/footer_text_padding" + android:left="20dp" + android:right="20dp" + > + <bitmap android:src="@drawable/leap_footer_en"/> + </item> +</layer-list> diff --git a/app/src/main/res/drawable/ic_btn_cancel.png b/app/src/main/res/drawable/ic_btn_cancel.png new file mode 100644 index 0000000000000000000000000000000000000000..af604d9bf768ed5a5d29888f04087ecd130fe4e9 Binary files /dev/null and b/app/src/main/res/drawable/ic_btn_cancel.png differ diff --git a/app/src/main/res/drawable/ic_btn_on.png b/app/src/main/res/drawable/ic_btn_on.png new file mode 100644 index 0000000000000000000000000000000000000000..d6cfc10b85141cc961c4dbe2e626aeccac39e28d Binary files /dev/null and b/app/src/main/res/drawable/ic_btn_on.png differ diff --git a/app/src/main/res/drawable/ic_btn_on_connecting.xml b/app/src/main/res/drawable/ic_btn_on_connecting.xml deleted file mode 100644 index 4b3d138428dcf1e65d116cbb13bb1e6fb78aeec5..0000000000000000000000000000000000000000 --- a/app/src/main/res/drawable/ic_btn_on_connecting.xml +++ /dev/null @@ -1,22 +0,0 @@ -<vector xmlns:android="http://schemas.android.com/apk/res/android" - android:width="24dp" - android:height="24dp" - android:viewportWidth="24" - android:viewportHeight="24"> - <path - android:pathData="M13,4.0089C13.0002,3.4567 12.5527,3.0088 12.0004,3.0085C11.4481,3.0083 11.0002,3.4559 11,4.0082L10.9968,12.0116C10.9966,12.5639 11.4442,13.0118 11.9965,13.012C12.5487,13.0122 12.9966,12.5647 12.9968,12.0124L13,4.0089Z" - android:strokeColor="@color/colorPrimary_transparent" - android:strokeLineCap="round" - android:strokeWidth="0.3" - android:strokeLineJoin="round" - android:fillAlpha="0.5" - android:fillColor="@color/colorPrimary"/> - <path - android:pathData="M4,12.9917C4,10.7826 4.8954,8.7826 6.3431,7.3349L7.7573,8.7491C6.6715,9.8349 6,11.3349 6,12.9917C6,16.3054 8.6863,18.9917 12,18.9917C15.3137,18.9917 18,16.3054 18,12.9917C18,11.3348 17.3284,9.8348 16.2426,8.749L17.6568,7.3348C19.1046,8.7825 20,10.7825 20,12.9917C20,17.41 16.4183,20.9917 12,20.9917C7.5817,20.9917 4,17.41 4,12.9917Z" - android:strokeColor="@color/colorPrimary_transparent" - android:strokeLineCap="round" - android:strokeWidth="0.3" - android:strokeLineJoin="round" - android:fillAlpha="0.5" - android:fillColor="@color/colorPrimary"/> -</vector> diff --git a/app/src/main/res/drawable/ic_btn_on_disabled.xml b/app/src/main/res/drawable/ic_btn_on_disabled.xml deleted file mode 100644 index 9c83422d0b1367da0822c58a63fcbb96a2e59bc6..0000000000000000000000000000000000000000 --- a/app/src/main/res/drawable/ic_btn_on_disabled.xml +++ /dev/null @@ -1,20 +0,0 @@ -<vector xmlns:android="http://schemas.android.com/apk/res/android" - android:width="24dp" - android:height="24dp" - android:viewportWidth="24" - android:viewportHeight="24"> - <path - android:pathData="M13,4.0089C13.0002,3.4567 12.5527,3.0088 12.0004,3.0085C11.4481,3.0083 11.0002,3.4559 11,4.0082L10.9968,12.0116C10.9966,12.5639 11.4442,13.0118 11.9965,13.012C12.5487,13.0122 12.9966,12.5647 12.9968,12.0124L13,4.0089Z" - android:strokeColor="@color/colorPrimary_transparent" - android:strokeWidth="0.3" - android:fillAlpha="0.5" - android:strokeLineJoin="round" - android:fillColor="@color/white"/> - <path - android:pathData="M4,12.9917C4,10.7826 4.8954,8.7826 6.3431,7.3349L7.7573,8.7491C6.6715,9.8349 6,11.3349 6,12.9917C6,16.3054 8.6863,18.9917 12,18.9917C15.3137,18.9917 18,16.3054 18,12.9917C18,11.3348 17.3284,9.8348 16.2426,8.749L17.6568,7.3348C19.1046,8.7825 20,10.7825 20,12.9917C20,17.41 16.4183,20.9917 12,20.9917C7.5817,20.9917 4,17.41 4,12.9917Z" - android:strokeColor="@color/colorPrimary_transparent" - android:fillAlpha="0.5" - android:strokeWidth="0.3" - android:strokeLineJoin="round" - android:fillColor="@color/white"/> -</vector> diff --git a/app/src/main/res/drawable/ic_btn_on_primary_color.xml b/app/src/main/res/drawable/ic_btn_on_primary_color.xml deleted file mode 100644 index 9f4492999b61bd1606d5034b7d66ddfdc7486396..0000000000000000000000000000000000000000 --- a/app/src/main/res/drawable/ic_btn_on_primary_color.xml +++ /dev/null @@ -1,22 +0,0 @@ -<vector xmlns:android="http://schemas.android.com/apk/res/android" - android:width="24dp" - android:height="24dp" - android:viewportWidth="24" - android:viewportHeight="24"> - <path - android:pathData="M13,4.0089C13.0002,3.4567 12.5527,3.0088 12.0004,3.0085C11.4481,3.0083 11.0002,3.4559 11,4.0082L10.9968,12.0116C10.9966,12.5639 11.4442,13.0118 11.9965,13.012C12.5487,13.0122 12.9966,12.5647 12.9968,12.0124L13,4.0089Z" - android:strokeColor="@color/colorPrimary_transparent" - android:strokeLineCap="round" - android:strokeAlpha="0.8" - android:strokeWidth="0.3" - android:strokeLineJoin="round" - android:fillColor="@color/colorPrimary"/> - <path - android:pathData="M4,12.9917C4,10.7826 4.8954,8.7826 6.3431,7.3349L7.7573,8.7491C6.6715,9.8349 6,11.3349 6,12.9917C6,16.3054 8.6863,18.9917 12,18.9917C15.3137,18.9917 18,16.3054 18,12.9917C18,11.3348 17.3284,9.8348 16.2426,8.749L17.6568,7.3348C19.1046,8.7825 20,10.7825 20,12.9917C20,17.41 16.4183,20.9917 12,20.9917C7.5817,20.9917 4,17.41 4,12.9917Z" - android:strokeColor="@color/colorPrimary_transparent" - android:strokeLineCap="round" - android:strokeAlpha="0.8" - android:strokeWidth="0.3" - android:strokeLineJoin="round" - android:fillColor="@color/colorPrimary"/> -</vector> diff --git a/app/src/main/res/drawable/leap_footer_en.png b/app/src/main/res/drawable/leap_footer_en.png new file mode 100644 index 0000000000000000000000000000000000000000..4881eb29949cc22b1da38cb9f1a359c3d73a8271 Binary files /dev/null and b/app/src/main/res/drawable/leap_footer_en.png differ diff --git a/app/src/main/res/drawable/logo.png b/app/src/main/res/drawable/logo.png new file mode 100644 index 0000000000000000000000000000000000000000..773937ff24fa42f60521202a6dd13bd45d7e3322 Binary files /dev/null and b/app/src/main/res/drawable/logo.png differ diff --git a/app/src/main/res/drawable/main_btn_glow.xml b/app/src/main/res/drawable/main_btn_glow.xml deleted file mode 100644 index 5ed57dd56ac7935d944a6558188015d0acde6ea0..0000000000000000000000000000000000000000 --- a/app/src/main/res/drawable/main_btn_glow.xml +++ /dev/null @@ -1,12 +0,0 @@ -<?xml version="1.0" encoding="utf-8"?> - -<animation-list xmlns:android="http://schemas.android.com/apk/res/android" android:oneshot="false"> - <item android:drawable="@drawable/on_off_btn_start_2_enabled" android:duration="150" /> - <item android:drawable="@drawable/on_off_btn_an4" android:duration="75" /> - <item android:drawable="@drawable/on_off_btn_an3" android:duration="100" /> - <item android:drawable="@drawable/on_off_btn_an2" android:duration="125" /> - <item android:drawable="@drawable/on_off_btn_an1" android:duration="400" /> - <item android:drawable="@drawable/on_off_btn_an2" android:duration="125" /> - <item android:drawable="@drawable/on_off_btn_an3" android:duration="100" /> - <item android:drawable="@drawable/on_off_btn_an4" android:duration="75" /> -</animation-list> \ No newline at end of file diff --git a/app/src/main/res/drawable/motd_img.xml b/app/src/main/res/drawable/motd_img.xml new file mode 100644 index 0000000000000000000000000000000000000000..4a330b8f1e6c8f3a6f9b0b78870e79c2d9ff66b2 --- /dev/null +++ b/app/src/main/res/drawable/motd_img.xml @@ -0,0 +1,18 @@ +<?xml version="1.0" encoding="utf-8"?> +<layer-list xmlns:android="http://schemas.android.com/apk/res/android"> + + <item android:drawable="@drawable/background_main" + android:gravity="fill_horizontal|fill_vertical"/> + + <item + android:top="50dp" + android:bottom="50dp" + android:left="50dp" + android:right="50dp" + > + <bitmap + android:src="@drawable/logo" + android:gravity="center" /> + </item> + +</layer-list> \ No newline at end of file diff --git a/app/src/main/res/drawable/on_off_btn_an1.png b/app/src/main/res/drawable/on_off_btn_an1.png deleted file mode 100644 index c80feeb7cd8b23069f821fd70326f46952824e57..0000000000000000000000000000000000000000 Binary files a/app/src/main/res/drawable/on_off_btn_an1.png and /dev/null differ diff --git a/app/src/main/res/drawable/on_off_btn_an2.png b/app/src/main/res/drawable/on_off_btn_an2.png deleted file mode 100644 index 73f4cb7ed3032fee60cb2ef35da20c12c23abd1f..0000000000000000000000000000000000000000 Binary files a/app/src/main/res/drawable/on_off_btn_an2.png and /dev/null differ diff --git a/app/src/main/res/drawable/on_off_btn_an3.png b/app/src/main/res/drawable/on_off_btn_an3.png deleted file mode 100644 index 98ad02209172e1a26becc10ad4fc088abcd9f8a5..0000000000000000000000000000000000000000 Binary files a/app/src/main/res/drawable/on_off_btn_an3.png and /dev/null differ diff --git a/app/src/main/res/drawable/on_off_btn_an4.png b/app/src/main/res/drawable/on_off_btn_an4.png deleted file mode 100644 index 49070e5fc2c43981660a01bf16e933980c99098b..0000000000000000000000000000000000000000 Binary files a/app/src/main/res/drawable/on_off_btn_an4.png and /dev/null differ diff --git a/app/src/main/res/drawable/on_off_btn_fill.png b/app/src/main/res/drawable/on_off_btn_fill.png deleted file mode 100644 index 8394ccfb2b513858e1c5bb495b9a03999addee74..0000000000000000000000000000000000000000 Binary files a/app/src/main/res/drawable/on_off_btn_fill.png and /dev/null differ diff --git a/app/src/main/res/drawable/on_off_btn_start_2_disabled.png b/app/src/main/res/drawable/on_off_btn_start_2_disabled.png deleted file mode 100644 index 4675e48dff5f7dc8b01823e2c8b04ec44c6696f5..0000000000000000000000000000000000000000 Binary files a/app/src/main/res/drawable/on_off_btn_start_2_disabled.png and /dev/null differ diff --git a/app/src/main/res/drawable/on_off_btn_start_2_enabled.png b/app/src/main/res/drawable/on_off_btn_start_2_enabled.png deleted file mode 100644 index 383e1076d46bfe09ed955ba23b76f1630fe44111..0000000000000000000000000000000000000000 Binary files a/app/src/main/res/drawable/on_off_btn_start_2_enabled.png and /dev/null differ diff --git a/app/src/main/res/drawable/on_off_btn_start_2_no_shadow.png b/app/src/main/res/drawable/on_off_btn_start_2_no_shadow.png deleted file mode 100644 index 941bdef16b2deca6b4987a0d229f7c9a7ee98233..0000000000000000000000000000000000000000 Binary files a/app/src/main/res/drawable/on_off_btn_start_2_no_shadow.png and /dev/null differ diff --git a/app/src/main/res/drawable/on_off_btn_start_2_pressed.png b/app/src/main/res/drawable/on_off_btn_start_2_pressed.png deleted file mode 100644 index 7ff60cdba5cd3c18f74ed2c79a6b2c66f478e2f0..0000000000000000000000000000000000000000 Binary files a/app/src/main/res/drawable/on_off_btn_start_2_pressed.png and /dev/null differ diff --git a/app/src/main/res/drawable/progressbar_circle.xml b/app/src/main/res/drawable/progressbar_circle.xml deleted file mode 100644 index 3d5f6026ae331c4c551a7527beeab9045f877d5e..0000000000000000000000000000000000000000 --- a/app/src/main/res/drawable/progressbar_circle.xml +++ /dev/null @@ -1,24 +0,0 @@ -<?xml version="1.0" encoding="utf-8"?> - -<layer-list xmlns:android="http://schemas.android.com/apk/res/android"> - <item> - <scale - android:scaleHeight="125%" - android:scaleWidth="125%" - android:scaleGravity="center" - > - <shape - android:shape="oval" - android:useLevel="true" - > - <gradient - android:startColor="@color/colorPrimaryDark" - android:centerColor="@color/colorPrimary" - android:endColor="@color/black800_high_transparent" - android:gradientRadius="100dp" - android:type="radial" - /> - </shape> - </scale> - </item> -</layer-list> \ No newline at end of file diff --git a/app/src/main/res/drawable/splash_page.xml b/app/src/main/res/drawable/splash_page.xml index 1740da586f1fefa059cd96d0a65284f972f7188d..92ae59ef3ddd37480af0ded1ec10ff2a71d0fd26 100644 --- a/app/src/main/res/drawable/splash_page.xml +++ b/app/src/main/res/drawable/splash_page.xml @@ -1,13 +1,18 @@ <?xml version="1.0" encoding="utf-8"?> - <layer-list xmlns:android="http://schemas.android.com/apk/res/android"> +<layer-list xmlns:android="http://schemas.android.com/apk/res/android"> <item android:drawable="@drawable/ic_splash_background" android:gravity="fill_horizontal|fill_vertical"/> - <item> + <item + android:top="@dimen/splash_text_top_padding" + > <bitmap - android:src="@drawable/logo" - android:gravity="center" /> + android:src="@drawable/bitmask_text" + android:gravity="center_horizontal|top" /> </item> + <item + android:drawable="@drawable/footer_text_drawable" + android:gravity="bottom|fill_horizontal" /> </layer-list> \ No newline at end of file diff --git a/app/src/main/res/layout-port/f_eip.xml b/app/src/main/res/layout-port/f_eip.xml index 990043879e95447f155f3b13b5e5dfc149f1579f..e14c7a10a122bc83964f61dd1fa9d1f764efcb1d 100644 --- a/app/src/main/res/layout-port/f_eip.xml +++ b/app/src/main/res/layout-port/f_eip.xml @@ -4,73 +4,84 @@ android:layout_width="match_parent" android:layout_height="match_parent" xmlns:tools="http://schemas.android.com/tools" - android:id="@+id/eipServiceFragment"> + android:id="@+id/eipServiceFragment" + > <androidx.constraintlayout.widget.Guideline android:id="@+id/guideline_vertical_left" android:layout_width="0dp" android:layout_height="0dp" android:orientation="vertical" + app:layout_constraintGuide_percent="0.3" + /> + + <androidx.constraintlayout.widget.Guideline + android:id="@+id/guideline_horizontal_center" + android:layout_width="0dp" + android:layout_height="0dp" + android:orientation="horizontal" + app:layout_constraintGuide_percent="0.25" /> + + <androidx.constraintlayout.widget.Guideline + android:id="@+id/guideline_vertical_outer_left" + android:layout_width="0dp" + android:layout_height="0dp" + android:orientation="vertical" app:layout_constraintBottom_toBottomOf="parent" - app:layout_constraintGuide_percent="0.225" + app:layout_constraintGuide_percent="0.125" /> + <androidx.constraintlayout.widget.Guideline + android:id="@+id/guideline_vertical_outer_right" + android:layout_width="0dp" + android:layout_height="0dp" + android:orientation="vertical" + app:layout_constraintGuide_percent="0.875" + /> <androidx.constraintlayout.widget.Guideline android:id="@+id/guideline_horizontal_bottom" android:layout_width="0dp" android:layout_height="0dp" android:orientation="horizontal" - app:layout_constraintBottom_toBottomOf="parent" - app:layout_constraintRight_toRightOf="parent" - app:layout_constraintGuide_percent="0.66" + app:layout_constraintGuide_percent="0.6" /> + <androidx.constraintlayout.widget.Guideline android:id="@+id/guideline_vertical_right" android:layout_width="0dp" android:layout_height="0dp" android:orientation="vertical" - app:layout_constraintBottom_toBottomOf="parent" - app:layout_constraintGuide_percent="0.775" + app:layout_constraintGuide_percent="0.7" /> <androidx.appcompat.widget.AppCompatImageView android:id="@+id/background" android:layout_width="match_parent" android:layout_height="match_parent" + app:srcCompat="@drawable/bg_disconnected" android:scaleType="fitXY" - app:srcCompat="@drawable/background_eip" /> - - <se.leap.bitmaskclient.base.views.MainButton - android:id="@+id/main_button" - android:layout_width="0dp" - android:layout_height="0dp" - android:layout_margin="@dimen/stdpadding" - app:layout_constraintBottom_toTopOf="@+id/guideline_horizontal_bottom" - app:layout_constraintDimensionRatio="1:1" - app:layout_constraintEnd_toStartOf="@+id/guideline_vertical_right" - app:layout_constraintStart_toStartOf="@+id/guideline_vertical_left" - app:layout_constraintTop_toTopOf="parent" - /> + /> <androidx.appcompat.widget.AppCompatTextView android:id="@+id/main_description" android:layout_width="wrap_content" android:layout_height="wrap_content" - app:layout_constraintTop_toBottomOf="@id/main_button" + app:layout_constraintTop_toTopOf="parent" app:layout_constraintStart_toStartOf="parent" app:layout_constraintEnd_toEndOf="parent" app:layout_constraintBottom_toTopOf="@+id/sub_description" android:padding="@dimen/activity_margin" + android:layout_marginTop="@dimen/activity_margin" android:textAppearance="@android:style/TextAppearance.Large" - android:textSize="26sp" android:textStyle="bold" + android:textSize="32sp" android:textColor="@color/colorEipFragmentFont" app:layout_constraintDimensionRatio="1:1" tools:text="Connection secure" android:gravity="center" - android:maxLines="1" + android:maxLines="2" /> <androidx.appcompat.widget.AppCompatTextView @@ -80,8 +91,8 @@ app:layout_constraintTop_toBottomOf="@id/main_description" app:layout_constraintStart_toStartOf="parent" app:layout_constraintEnd_toEndOf="parent" - app:layout_constraintBottom_toTopOf="@+id/gateway_location_button" - android:padding="@dimen/activity_margin" + android:paddingLeft="@dimen/stdpadding" + android:paddingRight="@dimen/stdpadding" android:textAppearance="@android:style/TextAppearance.DeviceDefault.Medium" android:textStyle="bold" android:textColor="@color/colorEipFragmentFont" @@ -92,6 +103,29 @@ android:ellipsize="end" /> + <androidx.appcompat.widget.AppCompatImageView + android:id="@+id/state_view" + android:layout_width="0dp" + android:layout_height="0dp" + app:layout_constraintBottom_toTopOf="@id/guideline_horizontal_bottom" + app:layout_constraintTop_toTopOf="@id/guideline_horizontal_center" + app:layout_constraintLeft_toLeftOf="@id/guideline_vertical_outer_left" + app:layout_constraintRight_toRightOf="@id/guideline_vertical_outer_right" + app:layout_constraintVertical_bias="1" + app:srcCompat="@drawable/state_disconnected" + /> + <se.leap.bitmaskclient.base.views.MainButton + android:id="@+id/main_button" + android:layout_width="0dp" + android:layout_height="0dp" + android:layout_margin="@dimen/mainbutton_padding" + app:layout_constraintTop_toBottomOf="@+id/guideline_horizontal_bottom" + app:layout_constraintBottom_toTopOf="@id/gateway_location_button" + app:layout_constraintDimensionRatio="1:1" + app:layout_constraintEnd_toStartOf="@+id/guideline_vertical_right" + app:layout_constraintStart_toStartOf="@+id/guideline_vertical_left" + /> + <se.leap.bitmaskclient.base.views.LocationButton android:id="@+id/gateway_location_button" android:layout_width="match_parent" @@ -102,7 +136,7 @@ android:layout_marginTop="@dimen/stdpadding" android:layout_marginLeft="@dimen/stdpadding" android:layout_marginRight="@dimen/stdpadding" - app:layout_constraintBottom_toBottomOf="@+id/background" + app:layout_constraintBottom_toBottomOf="parent" app:layout_constraintEnd_toEndOf="parent" app:layout_constraintStart_toStartOf="parent" tools:text="SEATTLE" diff --git a/app/src/main/res/layout-sw600dp-port/f_eip.xml b/app/src/main/res/layout-sw600dp-port/f_eip.xml new file mode 100644 index 0000000000000000000000000000000000000000..88e516524bd204691ac67fc1ea07ecb0bbf3804b --- /dev/null +++ b/app/src/main/res/layout-sw600dp-port/f_eip.xml @@ -0,0 +1,145 @@ +<?xml version="1.0" encoding="utf-8"?> +<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android" + xmlns:app="http://schemas.android.com/apk/res-auto" + android:layout_width="match_parent" + android:layout_height="match_parent" + xmlns:tools="http://schemas.android.com/tools" + android:id="@+id/eipServiceFragment" + > + + <androidx.constraintlayout.widget.Guideline + android:id="@+id/guideline_vertical_left" + android:layout_width="0dp" + android:layout_height="0dp" + android:orientation="vertical" + app:layout_constraintGuide_percent="0.3" + /> + + <androidx.constraintlayout.widget.Guideline + android:id="@+id/guideline_horizontal_center" + android:layout_width="0dp" + android:layout_height="0dp" + android:orientation="horizontal" + app:layout_constraintGuide_percent="0.25" /> + + <androidx.constraintlayout.widget.Guideline + android:id="@+id/guideline_vertical_outer_left" + android:layout_width="0dp" + android:layout_height="0dp" + android:orientation="vertical" + app:layout_constraintBottom_toBottomOf="parent" + app:layout_constraintGuide_percent="0.125" + /> + + <androidx.constraintlayout.widget.Guideline + android:id="@+id/guideline_vertical_outer_right" + android:layout_width="0dp" + android:layout_height="0dp" + android:orientation="vertical" + app:layout_constraintGuide_percent="0.875" + /> + + <androidx.constraintlayout.widget.Guideline + android:id="@+id/guideline_horizontal_bottom" + android:layout_width="0dp" + android:layout_height="0dp" + android:orientation="horizontal" + app:layout_constraintGuide_percent="0.6" + /> + + + <androidx.constraintlayout.widget.Guideline + android:id="@+id/guideline_vertical_right" + android:layout_width="0dp" + android:layout_height="0dp" + android:orientation="vertical" + app:layout_constraintGuide_percent="0.7" + /> + + <androidx.appcompat.widget.AppCompatImageView + android:id="@+id/background" + android:layout_width="match_parent" + android:layout_height="match_parent" + app:srcCompat="@drawable/bg_disconnected" + android:scaleType="fitXY" + /> + + <androidx.appcompat.widget.AppCompatTextView + android:id="@+id/main_description" + android:layout_width="wrap_content" + android:layout_height="wrap_content" + app:layout_constraintTop_toTopOf="parent" + app:layout_constraintStart_toStartOf="parent" + app:layout_constraintEnd_toEndOf="parent" + app:layout_constraintBottom_toTopOf="@+id/guideline_horizontal_center" + android:padding="@dimen/activity_margin" + android:layout_marginTop="@dimen/activity_margin" + android:textAppearance="@android:style/TextAppearance.Large" + android:textStyle="bold" + android:textSize="48sp" + android:textColor="@color/colorEipFragmentFont" + app:layout_constraintDimensionRatio="1:1" + tools:text="Connection secure" + android:gravity="center" + android:maxLines="2" + /> + + <androidx.appcompat.widget.AppCompatTextView + android:id="@+id/sub_description" + android:layout_width="wrap_content" + android:layout_height="wrap_content" + app:layout_constraintTop_toBottomOf="@id/main_description" + app:layout_constraintStart_toStartOf="parent" + app:layout_constraintEnd_toEndOf="parent" + android:paddingLeft="@dimen/stdpadding" + android:paddingRight="@dimen/stdpadding" + android:textAppearance="@android:style/TextAppearance.DeviceDefault.Medium" + android:textStyle="bold" + android:textColor="@color/colorEipFragmentFont" + app:layout_constraintDimensionRatio="1:1" + tools:text="A LONG TEXT WITH SEVERAL THINGS BLABLkk \n kdjfkj \n kjdfkjdf" + android:gravity="center" + android:maxLines="3" + android:ellipsize="end" + /> + + <androidx.appcompat.widget.AppCompatImageView + android:id="@+id/state_view" + android:layout_width="0dp" + android:layout_height="0dp" + app:layout_constraintBottom_toTopOf="@id/guideline_horizontal_bottom" + app:layout_constraintTop_toTopOf="@id/guideline_horizontal_center" + app:layout_constraintLeft_toLeftOf="@id/guideline_vertical_outer_left" + app:layout_constraintRight_toRightOf="@id/guideline_vertical_outer_right" + app:layout_constraintVertical_bias="1" + app:srcCompat="@drawable/state_disconnected" + /> + <se.leap.bitmaskclient.base.views.MainButton + android:id="@+id/main_button" + android:layout_width="0dp" + android:layout_height="0dp" + android:layout_margin="@dimen/mainbutton_padding" + app:layout_constraintTop_toBottomOf="@+id/guideline_horizontal_bottom" + app:layout_constraintBottom_toTopOf="@id/gateway_location_button" + app:layout_constraintDimensionRatio="1:1" + app:layout_constraintEnd_toStartOf="@+id/guideline_vertical_right" + app:layout_constraintStart_toStartOf="@+id/guideline_vertical_left" + /> + + <se.leap.bitmaskclient.base.views.LocationButton + android:id="@+id/gateway_location_button" + android:layout_width="match_parent" + android:layout_height="64dp" + android:layout_marginBottom="@dimen/stdpadding" + android:layout_marginEnd="@dimen/stdpadding" + android:layout_marginStart="@dimen/stdpadding" + android:layout_marginTop="@dimen/stdpadding" + android:layout_marginLeft="@dimen/stdpadding" + android:layout_marginRight="@dimen/stdpadding" + app:layout_constraintBottom_toBottomOf="parent" + app:layout_constraintEnd_toEndOf="parent" + app:layout_constraintStart_toStartOf="parent" + tools:text="SEATTLE" + android:gravity="center_vertical" /> + +</androidx.constraintlayout.widget.ConstraintLayout> diff --git a/app/src/main/res/layout-xlarge-port/a_add_provider.xml b/app/src/main/res/layout-xlarge-port/a_add_provider.xml index 9d1614aa3f632fe9d84b620c8eeddc948f66d3c7..80eef3c3df86bb4b008b5b06d740cb298a99e096 100644 --- a/app/src/main/res/layout-xlarge-port/a_add_provider.xml +++ b/app/src/main/res/layout-xlarge-port/a_add_provider.xml @@ -5,7 +5,8 @@ style="@style/BitmaskActivity" android:layout_width="match_parent" android:layout_height="match_parent" - tools:context=".providersetup.activities.ProviderCredentialsBaseActivity"> + tools:context=".providersetup.activities.ProviderCredentialsBaseActivity" + tools:viewBindingIgnore="true"> <androidx.appcompat.widget.AppCompatImageView android:layout_width="match_parent" diff --git a/app/src/main/res/layout-xlarge-port/a_custom_provider_setup.xml b/app/src/main/res/layout-xlarge-port/a_custom_provider_setup.xml index da813a2366a47c89a3d2aa0a68bab99ac2bd746a..dfb58b8cbe8e313318a456d27766c6abe4fff05e 100644 --- a/app/src/main/res/layout-xlarge-port/a_custom_provider_setup.xml +++ b/app/src/main/res/layout-xlarge-port/a_custom_provider_setup.xml @@ -6,7 +6,8 @@ style="@style/BitmaskActivity" android:layout_width="match_parent" android:layout_height="match_parent" - tools:context=".providersetup.activities.CustomProviderSetupActivity"> + tools:context=".providersetup.activities.CustomProviderSetupActivity" + tools:viewBindingIgnore="true"> <androidx.appcompat.widget.AppCompatImageView android:layout_width="match_parent" diff --git a/app/src/main/res/layout-xlarge-port/a_provider_credentials.xml b/app/src/main/res/layout-xlarge-port/a_provider_credentials.xml index 75f6244abc1e96a70d077a7944af95a7411061dd..e1295853f845fa781c7e4aa95d5a823e56d13a45 100644 --- a/app/src/main/res/layout-xlarge-port/a_provider_credentials.xml +++ b/app/src/main/res/layout-xlarge-port/a_provider_credentials.xml @@ -5,7 +5,8 @@ style="@style/BitmaskActivity" android:layout_width="match_parent" android:layout_height="match_parent" - tools:context=".providersetup.activities.ProviderCredentialsBaseActivity"> + tools:context=".providersetup.activities.ProviderCredentialsBaseActivity" + tools:viewBindingIgnore="true"> <androidx.appcompat.widget.AppCompatImageView android:layout_width="match_parent" diff --git a/app/src/main/res/layout-xlarge-port/a_provider_detail.xml b/app/src/main/res/layout-xlarge-port/a_provider_detail.xml index 7d1e8444bb88d2845d2a134e7f6023c4c501a0d4..34719df924f0317b36cb57a71c9fd1161f9df99c 100644 --- a/app/src/main/res/layout-xlarge-port/a_provider_detail.xml +++ b/app/src/main/res/layout-xlarge-port/a_provider_detail.xml @@ -6,7 +6,8 @@ android:layout_width="match_parent" android:layout_height="match_parent" tools:context=".providersetup.ProviderDetailActivity" - style="@style/BitmaskActivity"> + style="@style/BitmaskActivity" + tools:viewBindingIgnore="true"> <androidx.appcompat.widget.AppCompatImageView android:layout_width="match_parent" diff --git a/app/src/main/res/layout-xlarge-port/a_provider_list.xml b/app/src/main/res/layout-xlarge-port/a_provider_list.xml index 87ca64275c681e6b7c26c3d593fe95aea14066e5..184cbf939b0d6b9d431fcba9630a3ca60a248381 100644 --- a/app/src/main/res/layout-xlarge-port/a_provider_list.xml +++ b/app/src/main/res/layout-xlarge-port/a_provider_list.xml @@ -6,7 +6,8 @@ style="@style/BitmaskActivity" android:layout_width="match_parent" android:layout_height="match_parent" - tools:context=".providersetup.ProviderListActivity"> + tools:context=".providersetup.ProviderListActivity" + tools:viewBindingIgnore="true"> <androidx.appcompat.widget.AppCompatImageView android:layout_width="match_parent" diff --git a/app/src/main/res/layout-xlarge-port/f_eip.xml b/app/src/main/res/layout-xlarge-port/f_eip.xml index c3d3fd369cb748f0e2156eb173a3de97c5d03608..590cf1a4e215e683f7d6f8c8e71fbe04f942fe61 100644 --- a/app/src/main/res/layout-xlarge-port/f_eip.xml +++ b/app/src/main/res/layout-xlarge-port/f_eip.xml @@ -1,29 +1,32 @@ <?xml version="1.0" encoding="utf-8"?> +<!-- + This is the layout for extra large landscape, extra large portrait + can be found in layout-xlarge-port +--> <androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android" xmlns:app="http://schemas.android.com/apk/res-auto" - xmlns:tools="http://schemas.android.com/tools" android:layout_width="match_parent" android:layout_height="match_parent" + xmlns:tools="http://schemas.android.com/tools" android:id="@+id/eipServiceFragment" > + + <androidx.constraintlayout.widget.Guideline - android:id="@+id/guideline_horizontal_top" + android:id="@+id/guideline_horizontal_center" android:layout_width="0dp" android:layout_height="0dp" android:orientation="horizontal" - app:layout_constraintBottom_toBottomOf="parent" - app:layout_constraintGuide_percent="0.0" - app:layout_constraintRight_toRightOf="parent" /> + app:layout_constraintGuide_percent="0.25" + /> <androidx.constraintlayout.widget.Guideline android:id="@+id/guideline_vertical_left" android:layout_width="0dp" android:layout_height="0dp" android:orientation="vertical" - app:layout_constraintBottom_toBottomOf="parent" - app:layout_constraintGuide_percent="0.2" - /> + app:layout_constraintGuide_percent="0.3" /> <androidx.constraintlayout.widget.Guideline @@ -31,9 +34,22 @@ android:layout_width="0dp" android:layout_height="0dp" android:orientation="horizontal" - app:layout_constraintBottom_toBottomOf="parent" - app:layout_constraintRight_toRightOf="parent" - app:layout_constraintGuide_percent="0.7" + app:layout_constraintGuide_percent="0.65" /> + + <androidx.constraintlayout.widget.Guideline + android:id="@+id/guideline_horizontal_button_top" + android:layout_width="0dp" + android:layout_height="0dp" + android:orientation="horizontal" + app:layout_constraintGuide_percent="0.875" + /> + + <androidx.constraintlayout.widget.Guideline + android:id="@+id/guideline_horizontal_button_bottom" + android:layout_width="0dp" + android:layout_height="0dp" + android:orientation="horizontal" + app:layout_constraintGuide_percent="0.98" /> <androidx.constraintlayout.widget.Guideline @@ -42,46 +58,32 @@ android:layout_height="0dp" android:orientation="vertical" app:layout_constraintBottom_toBottomOf="parent" - app:layout_constraintGuide_percent="0.8" - /> + app:layout_constraintGuide_percent="0.7" /> <androidx.appcompat.widget.AppCompatImageView android:id="@+id/background" android:layout_width="match_parent" android:layout_height="match_parent" android:scaleType="fitXY" - app:srcCompat="@drawable/background_eip" /> - + app:srcCompat="@drawable/bg_disconnected" /> - <se.leap.bitmaskclient.base.views.MainButton - android:id="@+id/main_button" - android:layout_width="0dp" - android:layout_height="0dp" - android:layout_margin="@dimen/stdpadding" - app:layout_constraintBottom_toTopOf="@+id/guideline_horizontal_bottom" - app:layout_constraintDimensionRatio="1:1" - app:layout_constraintEnd_toStartOf="@+id/guideline_vertical_right" - app:layout_constraintStart_toStartOf="@+id/guideline_vertical_left" - app:layout_constraintTop_toTopOf="@+id/guideline_horizontal_top" - app:layout_constraintVertical_bias="0.425" /> <androidx.appcompat.widget.AppCompatTextView android:id="@+id/main_description" android:layout_width="wrap_content" android:layout_height="wrap_content" - app:layout_constraintTop_toBottomOf="@id/main_button" + app:layout_constraintTop_toTopOf="parent" app:layout_constraintStart_toStartOf="parent" app:layout_constraintEnd_toEndOf="parent" app:layout_constraintBottom_toTopOf="@+id/sub_description" - android:padding="@dimen/activity_margin" - android:textAppearance="@android:style/TextAppearance.Large" + android:padding="@dimen/stdpadding" + android:textAppearance="@android:style/TextAppearance.DeviceDefault.Large" android:textSize="45sp" android:textStyle="bold" android:textColor="@color/colorEipFragmentFont" app:layout_constraintDimensionRatio="1:1" - tools:text="Connection Secure" - android:gravity="center" - android:maxLines="1" + tools:text="Connection secure" + android:maxLines="2" /> <androidx.appcompat.widget.AppCompatTextView @@ -91,31 +93,60 @@ app:layout_constraintTop_toBottomOf="@id/main_description" app:layout_constraintStart_toStartOf="parent" app:layout_constraintEnd_toEndOf="parent" - app:layout_constraintBottom_toTopOf="@+id/gateway_location_button" - android:padding="@dimen/activity_margin" + app:layout_constraintBottom_toTopOf="@+id/guideline_horizontal_center" android:textAppearance="@android:style/TextAppearance.DeviceDefault.Large" android:textStyle="bold" android:textColor="@color/colorEipFragmentFont" + android:paddingLeft="@dimen/stdpadding" + android:paddingStart="@dimen/stdpadding" + android:paddingRight="@dimen/stdpadding" + android:paddingEnd="@dimen/stdpadding" + android:paddingBottom="@dimen/stdpadding" app:layout_constraintDimensionRatio="1:1" - tools:text="A LONG TEXT WITH SEVERAL THINGS BLABLkk" - android:gravity="center" + tools:text="Your traffic is securly routed through \n another" android:maxLines="2" - android:ellipsize="end" + android:gravity="center" + /> + + <androidx.appcompat.widget.AppCompatImageView + android:id="@+id/state_view" + android:layout_width="0dp" + android:layout_height="0dp" + app:layout_constraintBottom_toTopOf="@id/guideline_horizontal_bottom" + app:layout_constraintTop_toBottomOf="@id/guideline_horizontal_center" + app:layout_constraintLeft_toLeftOf="@id/guideline_vertical_left" + app:layout_constraintRight_toRightOf="@id/guideline_vertical_right" + app:layout_constraintVertical_bias="1" + app:srcCompat="@drawable/state_disconnected" /> + <se.leap.bitmaskclient.base.views.MainButton + android:id="@+id/main_button" + android:layout_width="0dp" + android:layout_height="0dp" + android:layout_margin="@dimen/mainbutton_padding" + app:layout_constraintTop_toBottomOf="@id/guideline_horizontal_bottom" + app:layout_constraintBottom_toTopOf="@+id/guideline_horizontal_button_top" + app:layout_constraintEnd_toStartOf="@+id/guideline_vertical_right" + app:layout_constraintStart_toStartOf="@+id/guideline_vertical_left" + app:layout_constraintDimensionRatio="1:1" + /> + + <se.leap.bitmaskclient.base.views.LocationButton android:id="@+id/gateway_location_button" android:layout_width="match_parent" - android:layout_height="64dp" - android:layout_marginBottom="@dimen/stdpadding" + android:layout_height="0dp" android:layout_marginEnd="@dimen/stdpadding" android:layout_marginStart="@dimen/stdpadding" - android:layout_marginTop="@dimen/stdpadding" + android:layout_marginLeft="@dimen/stdpadding" android:layout_marginRight="@dimen/stdpadding" - app:layout_constraintBottom_toBottomOf="@+id/background" app:layout_constraintEnd_toEndOf="parent" app:layout_constraintStart_toStartOf="parent" + app:layout_constraintTop_toBottomOf="@id/guideline_horizontal_button_top" + app:layout_constraintBottom_toBottomOf="@+id/guideline_horizontal_button_bottom" tools:text="SEATTLE" android:gravity="center_vertical" /> + </androidx.constraintlayout.widget.ConstraintLayout> diff --git a/app/src/main/res/layout-xlarge-port/f_log.xml b/app/src/main/res/layout-xlarge-port/f_log.xml index ebadeb740c5c8205053e297a947fef89d5c909d3..5684820605200eb7b355fd7721faee5aa8072532 100644 --- a/app/src/main/res/layout-xlarge-port/f_log.xml +++ b/app/src/main/res/layout-xlarge-port/f_log.xml @@ -10,7 +10,8 @@ xmlns:tools="http://schemas.android.com/tools" android:orientation="vertical" android:padding="@dimen/activity_margin" - android:id="@+id/log_layout"> + android:id="@+id/log_layout" + tools:viewBindingIgnore="true"> <LinearLayout android:background="@drawable/white_rect" diff --git a/app/src/main/res/layout-xlarge/a_add_provider.xml b/app/src/main/res/layout-xlarge/a_add_provider.xml index e4ebdadfe3effbf2d95223f0daf90bcb4d7328a1..db63b32c512a296c38f155c5e933cba277282aea 100644 --- a/app/src/main/res/layout-xlarge/a_add_provider.xml +++ b/app/src/main/res/layout-xlarge/a_add_provider.xml @@ -5,7 +5,8 @@ style="@style/BitmaskActivity" android:layout_width="match_parent" android:layout_height="match_parent" - tools:context=".providersetup.activities.ProviderCredentialsBaseActivity"> + tools:context=".providersetup.activities.ProviderCredentialsBaseActivity" + tools:viewBindingIgnore="true"> <androidx.appcompat.widget.AppCompatImageView android:layout_width="match_parent" diff --git a/app/src/main/res/layout-xlarge/a_custom_provider_setup.xml b/app/src/main/res/layout-xlarge/a_custom_provider_setup.xml index 23bf7d4061cb8ff6780e2d9a1ab21cfd244d9544..130ad95a2c5e2f7c99daa33669f71936df3eaa6b 100644 --- a/app/src/main/res/layout-xlarge/a_custom_provider_setup.xml +++ b/app/src/main/res/layout-xlarge/a_custom_provider_setup.xml @@ -6,7 +6,8 @@ style="@style/BitmaskActivity" android:layout_width="match_parent" android:layout_height="match_parent" - tools:context=".providersetup.activities.CustomProviderSetupActivity"> + tools:context=".providersetup.activities.CustomProviderSetupActivity" + tools:viewBindingIgnore="true"> <androidx.appcompat.widget.AppCompatImageView android:layout_width="match_parent" diff --git a/app/src/main/res/layout-xlarge/a_provider_credentials.xml b/app/src/main/res/layout-xlarge/a_provider_credentials.xml index c5b35fdce2875e8397642fca41b4660db9d3ad1a..61a638d4bd59123d55a2450bc8d71a318dc033b1 100644 --- a/app/src/main/res/layout-xlarge/a_provider_credentials.xml +++ b/app/src/main/res/layout-xlarge/a_provider_credentials.xml @@ -5,7 +5,8 @@ style="@style/BitmaskActivity" android:layout_width="match_parent" android:layout_height="match_parent" - tools:context=".providersetup.activities.ProviderCredentialsBaseActivity"> + tools:context=".providersetup.activities.ProviderCredentialsBaseActivity" + tools:viewBindingIgnore="true"> <androidx.appcompat.widget.AppCompatImageView android:layout_width="match_parent" diff --git a/app/src/main/res/layout-xlarge/a_provider_detail.xml b/app/src/main/res/layout-xlarge/a_provider_detail.xml index 59e9c18d6d235f7112e0d9ef8e619d650a27d324..74a0c72cd885698fc85378e3ae4cecc8778f58dc 100644 --- a/app/src/main/res/layout-xlarge/a_provider_detail.xml +++ b/app/src/main/res/layout-xlarge/a_provider_detail.xml @@ -6,7 +6,8 @@ android:layout_width="match_parent" android:layout_height="match_parent" tools:context=".providersetup.ProviderDetailActivity" - style="@style/BitmaskActivity"> + style="@style/BitmaskActivity" + tools:viewBindingIgnore="true"> <androidx.appcompat.widget.AppCompatImageView android:layout_width="match_parent" diff --git a/app/src/main/res/layout-xlarge/a_provider_list.xml b/app/src/main/res/layout-xlarge/a_provider_list.xml index 6504db1005a014d2377c6ec0136f203ff7069c9f..c8c7a7633c47f568613da91aaab43aa51b71d251 100644 --- a/app/src/main/res/layout-xlarge/a_provider_list.xml +++ b/app/src/main/res/layout-xlarge/a_provider_list.xml @@ -6,7 +6,8 @@ style="@style/BitmaskActivity" android:layout_width="match_parent" android:layout_height="match_parent" - tools:context=".providersetup.ProviderListActivity"> + tools:context=".providersetup.ProviderListActivity" + tools:viewBindingIgnore="true"> <androidx.appcompat.widget.AppCompatImageView android:layout_width="match_parent" diff --git a/app/src/main/res/layout-xlarge/f_about.xml b/app/src/main/res/layout-xlarge/f_about.xml index f2432e045a7fc8dbce99592205ac3a3c464bb823..ed7f4f1a23f645432fec0be3d20e7a4016f5969e 100644 --- a/app/src/main/res/layout-xlarge/f_about.xml +++ b/app/src/main/res/layout-xlarge/f_about.xml @@ -4,8 +4,12 @@ android:layout_width="match_parent" android:layout_height="match_parent" android:orientation="vertical" - android:layout_marginLeft="12sp" - tools:context=".base.MainActivity" > + android:layout_marginLeft="@dimen/stdpadding" + android:layout_marginStart="@dimen/stdpadding" + android:layout_marginEnd="@dimen/stdpadding" + android:layout_marginRight="@dimen/stdpadding" + tools:context=".base.MainActivity" + tools:viewBindingIgnore="true"> <LinearLayout android:layout_width="match_parent" @@ -20,7 +24,7 @@ <Space android:layout_width="match_parent" - android:layout_height="12sp" /> + android:layout_height="12dp" /> <androidx.appcompat.widget.AppCompatTextView android:id="@+id/terms_of_service" @@ -40,7 +44,7 @@ <Space android:layout_width="match_parent" - android:layout_height="12sp" /> + android:layout_height="12dp" /> <androidx.appcompat.widget.AppCompatTextView android:layout_width="match_parent" @@ -58,7 +62,7 @@ <Space android:layout_width="match_parent" - android:layout_height="18sp" /> + android:layout_height="18dp" /> <androidx.appcompat.widget.AppCompatTextView android:layout_width="match_parent" @@ -69,7 +73,7 @@ <Space android:layout_width="match_parent" - android:layout_height="12sp" /> + android:layout_height="12dp" /> <androidx.appcompat.widget.AppCompatTextView android:layout_width="match_parent" @@ -80,7 +84,7 @@ <Space android:layout_width="match_parent" - android:layout_height="18sp" /> + android:layout_height="18dp" /> <androidx.appcompat.widget.AppCompatTextView android:layout_width="match_parent" @@ -90,7 +94,7 @@ <Space android:layout_width="match_parent" - android:layout_height="20sp" /> + android:layout_height="20dp" /> <androidx.appcompat.widget.AppCompatTextView android:layout_width="match_parent" @@ -114,7 +118,7 @@ <Space android:layout_width="match_parent" - android:layout_height="20sp" /> + android:layout_height="20dp" /> <androidx.appcompat.widget.AppCompatTextView android:layout_width="match_parent" @@ -131,7 +135,7 @@ <Space android:layout_width="match_parent" - android:layout_height="20sp" /> + android:layout_height="20dp" /> <androidx.appcompat.widget.AppCompatTextView android:layout_width="match_parent" @@ -147,7 +151,7 @@ android:text="@string/copyright_openssl" /> <Space android:layout_width="match_parent" - android:layout_height="20sp" /> + android:layout_height="20dp" /> <androidx.appcompat.widget.AppCompatTextView android:layout_width="match_parent" @@ -164,7 +168,7 @@ <Space android:layout_width="match_parent" - android:layout_height="20sp" /> + android:layout_height="20dp" /> <androidx.appcompat.widget.AppCompatTextView android:layout_width="match_parent" @@ -181,7 +185,7 @@ <Space android:layout_width="match_parent" - android:layout_height="20sp" /> + android:layout_height="20dp" /> <androidx.appcompat.widget.AppCompatTextView android:layout_width="match_parent" @@ -198,7 +202,7 @@ <Space android:layout_width="match_parent" - android:layout_height="20sp" /> + android:layout_height="20dp" /> <androidx.appcompat.widget.AppCompatTextView android:layout_width="match_parent" @@ -215,7 +219,7 @@ <Space android:layout_width="match_parent" - android:layout_height="20sp" /> + android:layout_height="20dp" /> <androidx.appcompat.widget.AppCompatTextView android:layout_width="match_parent" @@ -232,7 +236,7 @@ <Space android:layout_width="match_parent" - android:layout_height="20sp" /> + android:layout_height="20dp" /> <androidx.appcompat.widget.AppCompatTextView android:layout_width="match_parent" @@ -249,7 +253,7 @@ <Space android:layout_width="match_parent" - android:layout_height="20sp" /> + android:layout_height="20dp" /> <androidx.appcompat.widget.AppCompatTextView android:layout_width="match_parent" @@ -266,7 +270,7 @@ <Space android:layout_width="match_parent" - android:layout_height="20sp" /> + android:layout_height="20dp" /> <androidx.appcompat.widget.AppCompatTextView android:layout_width="match_parent" @@ -283,7 +287,7 @@ <Space android:layout_width="match_parent" - android:layout_height="20sp" /> + android:layout_height="20dp" /> <androidx.appcompat.widget.AppCompatTextView android:layout_width="match_parent" @@ -300,7 +304,7 @@ <Space android:layout_width="match_parent" - android:layout_height="20sp" /> + android:layout_height="20dp" /> <androidx.appcompat.widget.AppCompatTextView android:layout_width="match_parent" diff --git a/app/src/main/res/layout-xlarge/f_eip.xml b/app/src/main/res/layout-xlarge/f_eip.xml index 4042933edadeee9694c3f84622b7d6bf7a207774..e413319a89aaf9c3bf3e0af6a856273ee77fc09c 100644 --- a/app/src/main/res/layout-xlarge/f_eip.xml +++ b/app/src/main/res/layout-xlarge/f_eip.xml @@ -5,20 +5,20 @@ --> <androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android" xmlns:app="http://schemas.android.com/apk/res-auto" - xmlns:tools="http://schemas.android.com/tools" android:layout_width="match_parent" android:layout_height="match_parent" + xmlns:tools="http://schemas.android.com/tools" android:id="@+id/eipServiceFragment" > + + <androidx.constraintlayout.widget.Guideline - android:id="@+id/guideline_horizontal_top" + android:id="@+id/guideline_horizontal_center" android:layout_width="0dp" android:layout_height="0dp" android:orientation="horizontal" - app:layout_constraintBottom_toBottomOf="parent" - app:layout_constraintRight_toRightOf="parent" - app:layout_constraintGuide_percent="0.0" + app:layout_constraintGuide_percent="0.25" /> <androidx.constraintlayout.widget.Guideline @@ -26,9 +26,7 @@ android:layout_width="0dp" android:layout_height="0dp" android:orientation="vertical" - app:layout_constraintBottom_toBottomOf="parent" - app:layout_constraintGuide_percent="0.2" - /> + app:layout_constraintGuide_percent="0.3" /> <androidx.constraintlayout.widget.Guideline @@ -36,9 +34,22 @@ android:layout_width="0dp" android:layout_height="0dp" android:orientation="horizontal" - app:layout_constraintBottom_toBottomOf="parent" - app:layout_constraintRight_toRightOf="parent" - app:layout_constraintGuide_percent="0.66" + app:layout_constraintGuide_percent="0.6" /> + + <androidx.constraintlayout.widget.Guideline + android:id="@+id/guideline_horizontal_button_top" + android:layout_width="0dp" + android:layout_height="0dp" + android:orientation="horizontal" + app:layout_constraintGuide_percent="0.875" + /> + + <androidx.constraintlayout.widget.Guideline + android:id="@+id/guideline_horizontal_button_bottom" + android:layout_width="0dp" + android:layout_height="0dp" + android:orientation="horizontal" + app:layout_constraintGuide_percent="0.98" /> <androidx.constraintlayout.widget.Guideline @@ -47,33 +58,21 @@ android:layout_height="0dp" android:orientation="vertical" app:layout_constraintBottom_toBottomOf="parent" - app:layout_constraintGuide_percent="0.8" - /> + app:layout_constraintGuide_percent="0.7" /> <androidx.appcompat.widget.AppCompatImageView android:id="@+id/background" android:layout_width="match_parent" android:layout_height="match_parent" android:scaleType="fitXY" - app:srcCompat="@drawable/background_eip" /> - + app:srcCompat="@drawable/bg_disconnected" /> - <se.leap.bitmaskclient.base.views.MainButton - android:id="@+id/main_button" - android:layout_width="0dp" - android:layout_height="0dp" - android:layout_margin="@dimen/stdpadding" - app:layout_constraintBottom_toTopOf="@+id/guideline_horizontal_bottom" - app:layout_constraintEnd_toStartOf="@+id/guideline_vertical_right" - app:layout_constraintStart_toStartOf="@+id/guideline_vertical_left" - app:layout_constraintTop_toTopOf="@+id/guideline_horizontal_top" - app:layout_constraintDimensionRatio="1:1" /> <androidx.appcompat.widget.AppCompatTextView android:id="@+id/main_description" android:layout_width="wrap_content" android:layout_height="wrap_content" - app:layout_constraintTop_toBottomOf="@id/guideline_horizontal_bottom" + app:layout_constraintTop_toTopOf="parent" app:layout_constraintStart_toStartOf="parent" app:layout_constraintEnd_toEndOf="parent" app:layout_constraintBottom_toTopOf="@+id/sub_description" @@ -83,8 +82,7 @@ android:textStyle="bold" android:textColor="@color/colorEipFragmentFont" app:layout_constraintDimensionRatio="1:1" - tools:text="CONNETION SECURE" - android:maxLines="1" + tools:text="Connection secure" /> <androidx.appcompat.widget.AppCompatTextView @@ -94,32 +92,58 @@ app:layout_constraintTop_toBottomOf="@id/main_description" app:layout_constraintStart_toStartOf="parent" app:layout_constraintEnd_toEndOf="parent" - app:layout_constraintBottom_toTopOf="@+id/gateway_location_button" - android:padding="@dimen/stdpadding" + app:layout_constraintBottom_toTopOf="@+id/guideline_horizontal_center" android:textAppearance="@android:style/TextAppearance.DeviceDefault.Large" android:textStyle="bold" android:textColor="@color/colorEipFragmentFont" + android:paddingLeft="@dimen/stdpadding" + android:paddingStart="@dimen/stdpadding" + android:paddingRight="@dimen/stdpadding" + android:paddingEnd="@dimen/stdpadding" + android:paddingBottom="@dimen/stdpadding" app:layout_constraintDimensionRatio="1:1" - android:maxLines="5" - android:ellipsize="end" - tools:text="Your traffic is securly routed through" + tools:text="Your traffic is securly routed through \n another" + android:maxLines="2" android:gravity="center" + /> + <androidx.appcompat.widget.AppCompatImageView + android:id="@+id/state_view" + android:layout_width="0dp" + android:layout_height="0dp" + app:layout_constraintBottom_toTopOf="@id/guideline_horizontal_bottom" + app:layout_constraintTop_toBottomOf="@id/guideline_horizontal_center" + app:layout_constraintLeft_toLeftOf="@id/guideline_vertical_left" + app:layout_constraintRight_toRightOf="@id/guideline_vertical_right" + app:layout_constraintVertical_bias="1" + app:srcCompat="@drawable/state_disconnected" /> + <se.leap.bitmaskclient.base.views.MainButton + android:id="@+id/main_button" + android:layout_width="0dp" + android:layout_height="0dp" + app:layout_constraintTop_toBottomOf="@id/guideline_horizontal_bottom" + app:layout_constraintBottom_toTopOf="@+id/guideline_horizontal_button_top" + app:layout_constraintEnd_toStartOf="@+id/guideline_vertical_right" + app:layout_constraintStart_toStartOf="@+id/guideline_vertical_left" + app:layout_constraintDimensionRatio="1:1" + /> + + <se.leap.bitmaskclient.base.views.LocationButton android:id="@+id/gateway_location_button" android:layout_width="match_parent" - android:layout_height="64dp" - android:layout_marginBottom="@dimen/stdpadding" + android:layout_height="0dp" android:layout_marginEnd="@dimen/stdpadding" android:layout_marginStart="@dimen/stdpadding" - android:layout_marginTop="@dimen/stdpadding" + android:layout_marginLeft="@dimen/stdpadding" android:layout_marginRight="@dimen/stdpadding" - app:layout_constraintBottom_toBottomOf="@+id/background" app:layout_constraintEnd_toEndOf="parent" app:layout_constraintStart_toStartOf="parent" + app:layout_constraintTop_toBottomOf="@id/guideline_horizontal_button_top" + app:layout_constraintBottom_toBottomOf="@+id/guideline_horizontal_button_bottom" tools:text="SEATTLE" android:gravity="center_vertical" /> diff --git a/app/src/main/res/layout-xlarge/f_log.xml b/app/src/main/res/layout-xlarge/f_log.xml index b014ee9d28e2be5f3a2429508eb4aaee21dde81e..f1ccc23abff7241bc8ef979670d33c2fe261aade 100644 --- a/app/src/main/res/layout-xlarge/f_log.xml +++ b/app/src/main/res/layout-xlarge/f_log.xml @@ -5,11 +5,13 @@ --> <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" + xmlns:tools="http://schemas.android.com/tools" android:layout_width="match_parent" android:layout_height="match_parent" android:orientation="horizontal" android:padding="20dp" android:id="@+id/log_layout" + tools:viewBindingIgnore="true" > <LinearLayout diff --git a/app/src/main/res/layout-xlarge/v_icon_text_list_item.xml b/app/src/main/res/layout-xlarge/v_icon_text_list_item.xml index 530660affd96aaeb12db9a6ea40e990c5bf8c64e..dd7dc37aef3bba462798f28f26b3fbb64be37e0a 100644 --- a/app/src/main/res/layout-xlarge/v_icon_text_list_item.xml +++ b/app/src/main/res/layout-xlarge/v_icon_text_list_item.xml @@ -3,7 +3,8 @@ android:layout_height="wrap_content" android:layout_width="match_parent" android:orientation="vertical" - xmlns:tools="http://schemas.android.com/tools"> + xmlns:tools="http://schemas.android.com/tools" + tools:viewBindingIgnore="true"> <LinearLayout android:layout_width="match_parent" android:layout_height="wrap_content" diff --git a/app/src/main/res/layout-xlarge/v_loading_screen.xml b/app/src/main/res/layout-xlarge/v_loading_screen.xml index 2ecb8f423f190c23072fe9a999c793178741124c..22b72f2900c6ec09cabd1c377ed5bdee06cba30c 100644 --- a/app/src/main/res/layout-xlarge/v_loading_screen.xml +++ b/app/src/main/res/layout-xlarge/v_loading_screen.xml @@ -8,6 +8,7 @@ android:orientation="vertical" android:visibility="gone" tools:visibility="visible" + tools:viewBindingIgnore="true" > <androidx.appcompat.widget.AppCompatImageView diff --git a/app/src/main/res/layout-xlarge/v_provider_header.xml b/app/src/main/res/layout-xlarge/v_provider_header.xml index 6d82678372843cbb1ea3b77cfac717191cbc432c..28bcaa6cd95c111d0ff1de0c94fba9ed824dfa1e 100644 --- a/app/src/main/res/layout-xlarge/v_provider_header.xml +++ b/app/src/main/res/layout-xlarge/v_provider_header.xml @@ -2,7 +2,9 @@ <RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android" android:layout_height="wrap_content" android:layout_width="match_parent" - xmlns:app="http://schemas.android.com/apk/res-auto" > + xmlns:app="http://schemas.android.com/apk/res-auto" + xmlns:tools="http://schemas.android.com/tools" + tools:viewBindingIgnore="true"> <androidx.appcompat.widget.AppCompatImageView android:id="@+id/provider_header_logo" diff --git a/app/src/main/res/layout-xlarge/v_provider_list_item.xml b/app/src/main/res/layout-xlarge/v_provider_list_item.xml index eea55be200c096c569a2a20e22cfe0034b5743d3..2e3506b507167708fa96344b3ca5a320545b5d9b 100644 --- a/app/src/main/res/layout-xlarge/v_provider_list_item.xml +++ b/app/src/main/res/layout-xlarge/v_provider_list_item.xml @@ -1,6 +1,7 @@ <?xml version="1.0" encoding="utf-8"?> <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" + xmlns:tools="http://schemas.android.com/tools" android:orientation="vertical" android:paddingTop="2dip" android:paddingBottom="2dip" @@ -8,7 +9,7 @@ android:layout_height="wrap_content" android:background="?android:attr/activatedBackgroundIndicator" android:minHeight="?android:attr/listPreferredItemHeight" -> + tools:viewBindingIgnore="true"> <androidx.appcompat.widget.AppCompatTextView android:id="@+id/provider_domain" android:layout_width="match_parent" diff --git a/app/src/main/res/layout-xlarge/v_single_list_item.xml b/app/src/main/res/layout-xlarge/v_single_list_item.xml index 6a318ff512e70773fe4f41ff2e8d669b655adb07..44cd16e567bd10e0193c373a2cd470740d072999 100644 --- a/app/src/main/res/layout-xlarge/v_single_list_item.xml +++ b/app/src/main/res/layout-xlarge/v_single_list_item.xml @@ -15,6 +15,7 @@ --> <androidx.appcompat.widget.AppCompatTextView xmlns:android="http://schemas.android.com/apk/res/android" + xmlns:tools="http://schemas.android.com/tools" android:id="@android:id/text1" android:layout_width="match_parent" android:layout_height="wrap_content" @@ -25,4 +26,5 @@ android:paddingEnd="?android:attr/listPreferredItemPaddingEnd" android:paddingRight="?android:attr/listPreferredItemPaddingRight" android:background="?android:attr/activatedBackgroundIndicator" - android:minHeight="?android:attr/listPreferredItemHeight" /> + android:minHeight="?android:attr/listPreferredItemHeight" + tools:viewBindingIgnore="true" /> diff --git a/app/src/main/res/layout-xlarge/v_switch_list_item.xml b/app/src/main/res/layout-xlarge/v_switch_list_item.xml index a24f50892c179061451acdf7cb1aabbd15015dbc..4a112139867e8886218b50214672d0501d0986f0 100644 --- a/app/src/main/res/layout-xlarge/v_switch_list_item.xml +++ b/app/src/main/res/layout-xlarge/v_switch_list_item.xml @@ -4,6 +4,7 @@ android:layout_height="wrap_content" android:layout_width="match_parent" android:orientation="vertical" + tools:viewBindingIgnore="true" > <RelativeLayout android:layout_width="match_parent" diff --git a/app/src/main/res/layout-xlarge/v_vpn_status.xml b/app/src/main/res/layout-xlarge/v_vpn_status.xml index ce8e6928e5bab2d7ec7fc4c435db309242cf730e..02f0659a64002adc97026bde826fa9344262121d 100644 --- a/app/src/main/res/layout-xlarge/v_vpn_status.xml +++ b/app/src/main/res/layout-xlarge/v_vpn_status.xml @@ -5,7 +5,8 @@ --> <merge xmlns:tools="http://schemas.android.com/tools" - xmlns:android="http://schemas.android.com/apk/res/android"> + xmlns:android="http://schemas.android.com/apk/res/android" + tools:viewBindingIgnore="true"> <Space android:layout_weight="1" diff --git a/app/src/main/res/layout/a_add_provider.xml b/app/src/main/res/layout/a_add_provider.xml index c78db432643b89e9ac2a8967e2a6898be936bb57..aad6463065f54f19192b90abab5b0f456eb3b6d6 100644 --- a/app/src/main/res/layout/a_add_provider.xml +++ b/app/src/main/res/layout/a_add_provider.xml @@ -6,7 +6,9 @@ android:layout_width="match_parent" android:layout_height="wrap_content" android:padding="@dimen/stdpadding" - tools:context=".providersetup.AddProviderActivity"> + tools:context=".providersetup.AddProviderActivity" + tools:viewBindingIgnore="true" + > <LinearLayout android:id="@+id/content" @@ -68,6 +70,7 @@ android:id="@+id/button_cancel" android:layout_width="wrap_content" android:layout_height="wrap_content" + android:textColor="@color/color_font_btn_primary" android:text="@string/cancel" /> <Button @@ -77,6 +80,7 @@ android:layout_marginLeft="@dimen/add_button_margin" android:layout_marginStart="@dimen/add_button_margin" android:enabled="false" + android:textColor="@color/color_font_btn_primary" android:text="@string/save" /> </LinearLayout> diff --git a/app/src/main/res/layout/a_add_provider_tablet_scrollview.xml b/app/src/main/res/layout/a_add_provider_tablet_scrollview.xml index 4debbf9f81d55c64669604d152133abf7d1bf267..74904f36ddca47c423c26c2d1250aab8a283f898 100644 --- a/app/src/main/res/layout/a_add_provider_tablet_scrollview.xml +++ b/app/src/main/res/layout/a_add_provider_tablet_scrollview.xml @@ -1,6 +1,5 @@ <?xml version="1.0" encoding="utf-8"?> -<ScrollView - android:orientation="vertical" +<ScrollView android:orientation="vertical" style="@style/BitmaskActivity" android:layout_width="0dp" android:layout_height="0dp" @@ -15,7 +14,9 @@ android:isScrollContainer="true" android:fadeScrollbars="false" xmlns:android="http://schemas.android.com/apk/res/android" - xmlns:app="http://schemas.android.com/apk/res-auto"> + xmlns:app="http://schemas.android.com/apk/res-auto" + tools:viewBindingIgnore="true" + xmlns:tools="http://schemas.android.com/tools"> <LinearLayout android:id="@+id/content" @@ -74,6 +75,7 @@ android:layout_width="wrap_content" android:layout_height="wrap_content" android:minWidth="80dp" + android:textColor="@color/color_font_btn_primary" android:text="@string/cancel" /> <Button @@ -83,6 +85,7 @@ android:minWidth="80dp" android:layout_marginLeft="@dimen/add_button_margin" android:layout_marginStart="@dimen/add_button_margin" + android:textColor="@color/color_font_btn_primary" android:enabled="false" android:text="@string/save" /> </LinearLayout> diff --git a/app/src/main/res/layout/a_custom_provider_setup.xml b/app/src/main/res/layout/a_custom_provider_setup.xml index 782537d9e264e491c57b13612e5373eea44ec229..0e4e3edf507f2a50583893b7509d9f54f7bb9c91 100644 --- a/app/src/main/res/layout/a_custom_provider_setup.xml +++ b/app/src/main/res/layout/a_custom_provider_setup.xml @@ -6,7 +6,9 @@ android:layout_height="match_parent" tools:context=".providersetup.activities.CustomProviderSetupActivity" android:padding="@dimen/stdpadding" - style="@style/BitmaskActivity" > + style="@style/BitmaskActivity" + tools:viewBindingIgnore="true" + > <!-- a "content" view that is required for ConfigWizardBaseActivities --> diff --git a/app/src/main/res/layout/a_custom_provider_setup_tablet_linear_layout.xml b/app/src/main/res/layout/a_custom_provider_setup_tablet_linear_layout.xml index 4879c76f08124f918b4e074fa1f5bbe2f8244c43..7e8cd51dce66f4aed7285f1661ae613fab3dd9bb 100644 --- a/app/src/main/res/layout/a_custom_provider_setup_tablet_linear_layout.xml +++ b/app/src/main/res/layout/a_custom_provider_setup_tablet_linear_layout.xml @@ -1,5 +1,6 @@ <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" xmlns:app="http://schemas.android.com/apk/res-auto" + xmlns:tools="http://schemas.android.com/tools" android:orientation="vertical" android:layout_width="0dp" android:layout_height="0dp" @@ -10,7 +11,8 @@ app:layout_constraintEnd_toStartOf="@+id/guideline_right" app:layout_constraintHeight_min="411dp" app:layout_constraintStart_toStartOf="@+id/guideline_left" - app:layout_constraintTop_toTopOf="@+id/guideline_top"> + app:layout_constraintTop_toTopOf="@+id/guideline_top" + tools:viewBindingIgnore="true"> <!-- a "content" view that is required for ConfigWizardBaseActivities --> <LinearLayout diff --git a/app/src/main/res/layout/a_main.xml b/app/src/main/res/layout/a_main.xml index 0e30d2a821d3b4464c0ad73cfe0a63d32c402491..927217f405d67998874dc9fb4a9580044f1bb96e 100644 --- a/app/src/main/res/layout/a_main.xml +++ b/app/src/main/res/layout/a_main.xml @@ -5,7 +5,9 @@ android:id="@+id/drawer_layout" android:layout_width="match_parent" android:layout_height="match_parent" - tools:context="se.leap.bitmaskclient.base.MainActivity"> + tools:context="se.leap.bitmaskclient.base.MainActivity" + tools:viewBindingIgnore="true" + > <!-- As the main content view, the view below consumes the entire @@ -20,8 +22,6 @@ android:minHeight="?attr/actionBarSize" android:layout_width="match_parent" android:layout_height="wrap_content" - app:titleTextColor="@color/colorActionBarTitleFont" - app:subtitleTextColor="@color/colorActionBarSubtitleFont" android:background="?attr/colorPrimary"> </androidx.appcompat.widget.Toolbar> diff --git a/app/src/main/res/layout/a_provider_credentials.xml b/app/src/main/res/layout/a_provider_credentials.xml index b5dfa08874212f7171d1476d00f2e18e9a5e60a4..033aae16aa75a219759b5746b3a61eeabbc64396 100644 --- a/app/src/main/res/layout/a_provider_credentials.xml +++ b/app/src/main/res/layout/a_provider_credentials.xml @@ -1,11 +1,12 @@ <?xml version="1.0" encoding="utf-8"?> -<LinearLayout - xmlns:android="http://schemas.android.com/apk/res/android" +<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" + xmlns:tools="http://schemas.android.com/tools" android:orientation="vertical" android:layout_width="match_parent" android:layout_height="wrap_content" android:padding="@dimen/stdpadding" - style="@style/BitmaskActivity"> + style="@style/BitmaskActivity" + tools:viewBindingIgnore="true"> <include layout="@layout/v_loading_screen" /> @@ -43,6 +44,7 @@ android:layout_height="wrap_content" android:layout_gravity="end" android:enabled="false" + android:textColor="@color/color_font_btn_primary" android:text="@string/login_button" /> </LinearLayout> diff --git a/app/src/main/res/layout/a_provider_credentials_tablet_linear_layout.xml b/app/src/main/res/layout/a_provider_credentials_tablet_linear_layout.xml index ea0b6dd4f368f22e380a9a632e12d8c6a87a4eae..73557853a0542a2e788623397c5c04de67fa8b86 100644 --- a/app/src/main/res/layout/a_provider_credentials_tablet_linear_layout.xml +++ b/app/src/main/res/layout/a_provider_credentials_tablet_linear_layout.xml @@ -1,7 +1,7 @@ <?xml version="1.0" encoding="utf-8"?> -<LinearLayout - xmlns:android="http://schemas.android.com/apk/res/android" +<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" xmlns:app="http://schemas.android.com/apk/res-auto" + xmlns:tools="http://schemas.android.com/tools" android:orientation="vertical" style="@style/BitmaskActivity" android:layout_width="0dp" @@ -13,7 +13,8 @@ app:layout_constraintEnd_toStartOf="@+id/guideline_right" app:layout_constraintHeight_min="411dp" app:layout_constraintStart_toStartOf="@+id/guideline_left" - app:layout_constraintTop_toTopOf="@+id/guideline_top"> + app:layout_constraintTop_toTopOf="@+id/guideline_top" + tools:viewBindingIgnore="true"> <include layout="@layout/v_loading_screen" /> @@ -49,6 +50,7 @@ android:layout_height="wrap_content" android:layout_gravity="end" android:enabled="false" + android:textColor="@color/color_font_btn_primary" android:text="@string/login_button" /> </LinearLayout> diff --git a/app/src/main/res/layout/a_provider_detail.xml b/app/src/main/res/layout/a_provider_detail.xml index bdc17ee91c2309b1cd762fb1bdb70a3dbd1c02c7..4a456c329f988eeb89f6bdb87717b7bdac39d703 100644 --- a/app/src/main/res/layout/a_provider_detail.xml +++ b/app/src/main/res/layout/a_provider_detail.xml @@ -1,11 +1,13 @@ <?xml version="1.0" encoding="utf-8"?> <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" + xmlns:tools="http://schemas.android.com/tools" android:id="@+id/provider_detail_fragment" android:layout_width="match_parent" android:layout_height="match_parent" android:padding="@dimen/stdpadding" android:orientation="vertical" - style="@style/BitmaskActivity" > + style="@style/BitmaskActivity" + tools:viewBindingIgnore="true"> <include layout="@layout/v_loading_screen" /> diff --git a/app/src/main/res/layout/a_provider_detail_tablet_linear_layout.xml b/app/src/main/res/layout/a_provider_detail_tablet_linear_layout.xml index 0c7e02d1c2bf69ed803f62e227f428f609743df6..5601a3d51cd8ad8d1a9653425a4ae8cab836a1fc 100644 --- a/app/src/main/res/layout/a_provider_detail_tablet_linear_layout.xml +++ b/app/src/main/res/layout/a_provider_detail_tablet_linear_layout.xml @@ -1,6 +1,5 @@ <?xml version="1.0" encoding="utf-8"?> -<LinearLayout - android:orientation="vertical" +<LinearLayout android:orientation="vertical" android:padding="@dimen/stdpadding" style="@style/BitmaskActivity" android:layout_width="0dp" @@ -13,7 +12,9 @@ app:layout_constraintStart_toStartOf="@+id/guideline_left" app:layout_constraintTop_toTopOf="@+id/guideline_top" xmlns:android="http://schemas.android.com/apk/res/android" - xmlns:app="http://schemas.android.com/apk/res-auto"> + xmlns:app="http://schemas.android.com/apk/res-auto" + tools:viewBindingIgnore="true" + xmlns:tools="http://schemas.android.com/tools"> <include layout="@layout/v_loading_screen" /> diff --git a/app/src/main/res/layout/a_provider_list.xml b/app/src/main/res/layout/a_provider_list.xml index 5d7efae748fe3d08bda5a5070e1ae30a0890decc..867d6d8d90c4598ad8eca24994abbb1d91c2241c 100644 --- a/app/src/main/res/layout/a_provider_list.xml +++ b/app/src/main/res/layout/a_provider_list.xml @@ -5,7 +5,8 @@ android:layout_height="match_parent" tools:context=".providersetup.ProviderListActivity" android:padding="@dimen/stdpadding" - style="@style/BitmaskActivity" > + style="@style/BitmaskActivity" + tools:viewBindingIgnore="true"> <include layout="@layout/v_loading_screen" /> diff --git a/app/src/main/res/layout/a_provider_list_tablet_linear_layout.xml b/app/src/main/res/layout/a_provider_list_tablet_linear_layout.xml index 487edd1d350d2f0da98c8280d72e34a956da7deb..67f82976fab31fca41e35625c20821cdfb2e3404 100644 --- a/app/src/main/res/layout/a_provider_list_tablet_linear_layout.xml +++ b/app/src/main/res/layout/a_provider_list_tablet_linear_layout.xml @@ -12,7 +12,9 @@ app:layout_constraintStart_toStartOf="@+id/guideline_left" app:layout_constraintTop_toTopOf="@+id/guideline_top" xmlns:android="http://schemas.android.com/apk/res/android" - xmlns:app="http://schemas.android.com/apk/res-auto"> + xmlns:app="http://schemas.android.com/apk/res-auto" + xmlns:tools="http://schemas.android.com/tools" + tools:viewBindingIgnore="true"> <include layout="@layout/v_loading_screen" /> diff --git a/app/src/main/res/layout/allowed_application_layout.xml b/app/src/main/res/layout/allowed_application_layout.xml index 61fc12c378b35d28cbb50d55fd55db0805365a99..bb8e4e5d7f85be1c366d54b73379ec2d7e3b44e9 100644 --- a/app/src/main/res/layout/allowed_application_layout.xml +++ b/app/src/main/res/layout/allowed_application_layout.xml @@ -14,7 +14,9 @@ android:paddingTop="8dip" android:paddingBottom="8dip" android:columnCount="4" - tools:ignore="RtlCompat"> + tools:ignore="RtlCompat" + tools:viewBindingIgnore="true" + > <ImageView android:id="@+id/app_icon" @@ -23,7 +25,6 @@ android:layout_rowSpan="1" android:layout_marginEnd="8dip" android:scaleType="centerInside" - tools:background="@drawable/ic_btn_on_connecting" android:contentDescription="@null" /> <androidx.appcompat.widget.AppCompatTextView diff --git a/app/src/main/res/layout/allowed_vpn_apps.xml b/app/src/main/res/layout/allowed_vpn_apps.xml index f76b5f4f56011f877685f41bcc6e8d2ed68adf5b..1930adf2ec5345a142b20b10c89018079a809fa4 100644 --- a/app/src/main/res/layout/allowed_vpn_apps.xml +++ b/app/src/main/res/layout/allowed_vpn_apps.xml @@ -8,7 +8,9 @@ android:orientation="vertical" android:layout_width="match_parent" tools:ignore="RtlCompat" - android:layout_height="match_parent"> + android:layout_height="match_parent" + tools:viewBindingIgnore="true" + > <androidx.appcompat.widget.AppCompatTextView android:layout_width="match_parent" diff --git a/app/src/main/res/layout/custom_toast.xml b/app/src/main/res/layout/custom_toast.xml index c267fb86580e1f55eb796aae35414ce7ce8926d6..b333a9b0ae8bf7bc0ed76be61e60cf83526535ea 100644 --- a/app/src/main/res/layout/custom_toast.xml +++ b/app/src/main/res/layout/custom_toast.xml @@ -6,7 +6,9 @@ android:layout_width="fill_parent" android:layout_height="fill_parent" android:padding="16dp" - android:background="@drawable/cust_toast_background"> + android:background="@drawable/cust_toast_background" + tools:viewBindingIgnore="true" + > <ImageView android:src="@drawable/retry" android:layout_width="24dp" android:layout_height="24dp" diff --git a/app/src/main/res/layout/d_checkbox_confirm.xml b/app/src/main/res/layout/d_checkbox_confirm.xml index f8aace6ec3b60e70dce6414fe1d1589ef5dfd61e..d8811226e66141145dc1f1dd42ad82519b19a103 100644 --- a/app/src/main/res/layout/d_checkbox_confirm.xml +++ b/app/src/main/res/layout/d_checkbox_confirm.xml @@ -1,7 +1,9 @@ <?xml version="1.0" encoding="utf-8"?> -<ScrollView xmlns:android="http://schemas.android.com/apk/res/android" +<ScrollView xmlns:android="http://schemas.android.com/apk/res/android" android:layout_width="match_parent" - android:layout_height="wrap_content"> + android:layout_height="wrap_content" + xmlns:tools="http://schemas.android.com/tools" + tools:viewBindingIgnore="true"> <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" diff --git a/app/src/main/res/layout/d_list_selection.xml b/app/src/main/res/layout/d_list_selection.xml index d9a1b0135b1db8d12112ab2dcc13ac6e88bed307..908c228f1eed31bc9def3e98323209ae0cd33766 100644 --- a/app/src/main/res/layout/d_list_selection.xml +++ b/app/src/main/res/layout/d_list_selection.xml @@ -1,7 +1,9 @@ <?xml version="1.0" encoding="utf-8"?> <ScrollView xmlns:android="http://schemas.android.com/apk/res/android" android:layout_width="match_parent" - android:layout_height="wrap_content"> + android:layout_height="wrap_content" + xmlns:tools="http://schemas.android.com/tools" + tools:viewBindingIgnore="true"> <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" diff --git a/app/src/main/res/layout/d_obfuscation_proxy.xml b/app/src/main/res/layout/d_obfuscation_proxy.xml new file mode 100644 index 0000000000000000000000000000000000000000..2ce9d7b351722bc9c1f21e2ca65322c7d636d5b5 --- /dev/null +++ b/app/src/main/res/layout/d_obfuscation_proxy.xml @@ -0,0 +1,114 @@ +<?xml version="1.0" encoding="utf-8"?> +<ScrollView xmlns:android="http://schemas.android.com/apk/res/android" + android:layout_width="match_parent" + android:layout_height="match_parent" + xmlns:app="http://schemas.android.com/apk/res-auto" + android:scrollbars="none"> + <androidx.appcompat.widget.LinearLayoutCompat + android:orientation = "vertical" + android:layout_height="wrap_content" + android:layout_width="match_parent" + android:padding="@dimen/activity_margin" + > + <TextView + android:layout_width="match_parent" + android:layout_height="wrap_content" + android:text="Obfuscation Proxy Pinning" + android:textStyle="bold" + android:gravity="center_horizontal" + android:textAppearance="@android:style/TextAppearance.Large" + /> + + <TextView + android:layout_width="match_parent" + android:layout_height="wrap_content" + android:text="Proxy IP" + android:paddingTop="@dimen/activity_margin" + android:textStyle="bold" + android:textAppearance="@android:style/TextAppearance.DeviceDefault" /> + <androidx.appcompat.widget.AppCompatEditText + android:id="@+id/ip_field" + android:layout_width="match_parent" + android:layout_height="wrap_content" + /> + + <TextView + android:layout_width="match_parent" + android:layout_height="wrap_content" + android:text="Proxy Port" + android:paddingTop="@dimen/activity_margin" + android:textStyle="bold" + android:textAppearance="@android:style/TextAppearance.DeviceDefault" + + /> + <androidx.appcompat.widget.AppCompatEditText + android:id="@+id/port_field" + android:layout_width="match_parent" + android:layout_height="wrap_content"/> + + <TextView + android:layout_width="match_parent" + android:layout_height="wrap_content" + android:text="Certificate" + android:textStyle="bold" + android:paddingTop="@dimen/activity_margin" + android:textAppearance="@android:style/TextAppearance.DeviceDefault" /> + <androidx.appcompat.widget.AppCompatEditText + android:id="@+id/cert_field" + android:layout_width="match_parent" + android:layout_height="wrap_content"/> + <se.leap.bitmaskclient.base.views.IconSwitchEntry + android:id="@+id/kcp_switch" + android:layout_width="match_parent" + android:layout_height="wrap_content" + app:text="KCP" + app:subtitle="UDP based network protocol" + app:icon="@drawable/ic_multiple_stop" + > + + </se.leap.bitmaskclient.base.views.IconSwitchEntry> + + <androidx.appcompat.widget.LinearLayoutCompat + android:layout_width="wrap_content" + android:layout_height="wrap_content" + android:layout_gravity="end" + android:layout_marginTop="@dimen/activity_margin" + android:gravity="right" + android:orientation="vertical"> + <androidx.appcompat.widget.AppCompatButton + android:id="@+id/button_defaults" + android:layout_width="wrap_content" + android:layout_height="wrap_content" + android:text="Use defaults" + android:background="@drawable/cust_button_secondary" + android:textColor="@color/color_font_btn_secondary" + android:layout_marginHorizontal="@dimen/stdpadding" + /> + <androidx.appcompat.widget.LinearLayoutCompat + android:layout_width="wrap_content" + android:layout_height="wrap_content" + android:layout_marginTop="@dimen/stdpadding" + android:orientation="horizontal"> + <androidx.appcompat.widget.AppCompatButton + android:id="@+id/button_cancel" + android:layout_width="wrap_content" + android:layout_height="wrap_content" + android:layout_marginHorizontal="@dimen/stdpadding" + android:textColor="@color/color_font_btn_primary" + android:text="@string/cancel" + /> + + <androidx.appcompat.widget.AppCompatButton + android:id="@+id/button_save" + android:layout_width="wrap_content" + android:layout_height="wrap_content" + android:layout_marginHorizontal="@dimen/stdpadding" + android:textColor="@color/color_font_btn_primary" + android:text="@string/save" + /> + </androidx.appcompat.widget.LinearLayoutCompat> + + </androidx.appcompat.widget.LinearLayoutCompat> + + </androidx.appcompat.widget.LinearLayoutCompat> +</ScrollView> \ No newline at end of file diff --git a/app/src/main/res/layout/donation_reminder_dialog.xml b/app/src/main/res/layout/donation_reminder_dialog.xml index f81486f861f6130decff2d4940bd8c9e31ace4eb..491686b52c3cd82a2f10aabc66ed2fc8735d3c07 100644 --- a/app/src/main/res/layout/donation_reminder_dialog.xml +++ b/app/src/main/res/layout/donation_reminder_dialog.xml @@ -3,7 +3,9 @@ android:layout_width="match_parent" android:layout_height="match_parent" xmlns:app="http://schemas.android.com/apk/res-auto" - android:scrollbars="none"> + xmlns:tools="http://schemas.android.com/tools" + android:scrollbars="none" + tools:viewBindingIgnore="true"> <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" android:layout_width="match_parent" @@ -28,7 +30,7 @@ android:id="@+id/tvMessage" android:layout_width="match_parent" android:layout_height="wrap_content" - android:layout_margin="@dimen/standard_margin" + android:layout_margin="@dimen/donation_reminder_padding" android:gravity="center" android:text="@string/donate_message_calyx" /> @@ -48,20 +50,20 @@ android:layout_marginTop="@dimen/add_button_margin" android:background="@drawable/cust_button_primary" android:text="@string/donate_button_donate" - android:textColor="@color/white" + android:textColor="@color/color_font_btn_primary" android:textStyle="bold" /> <Button android:id="@+id/btnLater" android:layout_width="200dp" android:layout_height="38dp" - android:layout_marginBottom="@dimen/mainbutton_padding" + android:layout_marginBottom="20dp" android:layout_marginLeft="@dimen/add_button_margin" android:layout_marginRight="@dimen/add_button_margin" android:layout_marginTop="@dimen/standard_margin" android:background="@drawable/cust_button_secondary" android:text="@string/donate_button_remind_later" - android:textColor="@android:color/tab_indicator_text" + android:textColor="@color/color_font_btn_secondary" android:textStyle="bold" /> </LinearLayout> diff --git a/app/src/main/res/layout/f_about.xml b/app/src/main/res/layout/f_about.xml index acf686eb35fe1c85225413b3b13ed92cba2c17d5..e0193c1b78e5d91fcb784b5c0037de6747fa074d 100644 --- a/app/src/main/res/layout/f_about.xml +++ b/app/src/main/res/layout/f_about.xml @@ -4,8 +4,12 @@ android:layout_width="match_parent" android:layout_height="match_parent" android:orientation="vertical" - android:layout_marginLeft="8sp" - tools:context=".base.MainActivity" > + android:layout_marginLeft="@dimen/stdpadding" + android:layout_marginStart="@dimen/stdpadding" + android:layout_marginRight="@dimen/stdpadding" + android:layout_marginEnd="@dimen/stdpadding" + tools:context=".base.MainActivity" + tools:viewBindingIgnore="true"> <LinearLayout android:layout_width="match_parent" @@ -20,7 +24,7 @@ <Space android:layout_width="match_parent" - android:layout_height="10sp" /> + android:layout_height="10dp" /> <androidx.appcompat.widget.AppCompatTextView android:id="@+id/terms_of_service" @@ -39,7 +43,7 @@ <Space android:layout_width="match_parent" - android:layout_height="10sp" /> + android:layout_height="10dp" /> <androidx.appcompat.widget.AppCompatTextView android:layout_width="match_parent" @@ -50,7 +54,7 @@ <Space android:layout_width="match_parent" - android:layout_height="10sp" /> + android:layout_height="10dp" /> <androidx.appcompat.widget.AppCompatTextView android:layout_width="match_parent" @@ -66,7 +70,7 @@ <Space android:layout_width="match_parent" - android:layout_height="10sp" /> + android:layout_height="10dp" /> <androidx.appcompat.widget.AppCompatTextView android:layout_width="match_parent" @@ -76,7 +80,7 @@ <Space android:layout_width="match_parent" - android:layout_height="10sp" /> + android:layout_height="10dp" /> <androidx.appcompat.widget.AppCompatTextView android:layout_width="match_parent" @@ -86,7 +90,7 @@ <Space android:layout_width="match_parent" - android:layout_height="10sp" /> + android:layout_height="10dp" /> <androidx.appcompat.widget.AppCompatTextView android:layout_width="match_parent" @@ -95,7 +99,7 @@ <Space android:layout_width="match_parent" - android:layout_height="10sp" /> + android:layout_height="10dp" /> <androidx.appcompat.widget.AppCompatTextView android:layout_width="match_parent" @@ -132,7 +136,7 @@ <Space android:layout_width="match_parent" - android:layout_height="20sp" /> + android:layout_height="20dp" /> <androidx.appcompat.widget.AppCompatTextView android:layout_width="match_parent" @@ -147,7 +151,7 @@ <Space android:layout_width="match_parent" - android:layout_height="20sp" /> + android:layout_height="20dp" /> <androidx.appcompat.widget.AppCompatTextView android:layout_width="match_parent" @@ -162,7 +166,7 @@ <Space android:layout_width="match_parent" - android:layout_height="20sp" /> + android:layout_height="20dp" /> <androidx.appcompat.widget.AppCompatTextView android:layout_width="match_parent" @@ -177,7 +181,7 @@ <Space android:layout_width="match_parent" - android:layout_height="20sp" /> + android:layout_height="20dp" /> <androidx.appcompat.widget.AppCompatTextView android:layout_width="match_parent" @@ -192,7 +196,7 @@ <Space android:layout_width="match_parent" - android:layout_height="20sp" /> + android:layout_height="20dp" /> <androidx.appcompat.widget.AppCompatTextView android:layout_width="match_parent" @@ -207,7 +211,7 @@ <Space android:layout_width="match_parent" - android:layout_height="20sp" /> + android:layout_height="20dp" /> <androidx.appcompat.widget.AppCompatTextView android:layout_width="match_parent" @@ -222,7 +226,7 @@ <Space android:layout_width="match_parent" - android:layout_height="20sp" /> + android:layout_height="20dp" /> <androidx.appcompat.widget.AppCompatTextView android:layout_width="match_parent" @@ -237,7 +241,7 @@ <Space android:layout_width="match_parent" - android:layout_height="20sp" /> + android:layout_height="20dp" /> <androidx.appcompat.widget.AppCompatTextView android:layout_width="match_parent" @@ -252,7 +256,7 @@ <Space android:layout_width="match_parent" - android:layout_height="20sp" /> + android:layout_height="20dp" /> <androidx.appcompat.widget.AppCompatTextView android:layout_width="match_parent" @@ -267,7 +271,7 @@ <Space android:layout_width="match_parent" - android:layout_height="20sp" /> + android:layout_height="20dp" /> <androidx.appcompat.widget.AppCompatTextView android:layout_width="match_parent" @@ -282,7 +286,7 @@ <Space android:layout_width="match_parent" - android:layout_height="20sp" /> + android:layout_height="20dp" /> <androidx.appcompat.widget.AppCompatTextView android:layout_width="match_parent" diff --git a/app/src/main/res/layout/f_drawer_main.xml b/app/src/main/res/layout/f_drawer_main.xml index bf418bc0d117253287f62025127c4c27eb36a60c..a948d9cec5d6bb57dea37587a0f452212636cfa3 100644 --- a/app/src/main/res/layout/f_drawer_main.xml +++ b/app/src/main/res/layout/f_drawer_main.xml @@ -8,6 +8,7 @@ android:clickable="true" android:focusable="true" android:fillViewport="true" + tools:viewBindingIgnore="true" > <LinearLayout diff --git a/app/src/main/res/layout/f_eip.xml b/app/src/main/res/layout/f_eip.xml index fa2d4dedadb2fe5b469c71412e4c6b3b7cdc356f..1e1f8e41e9f3585cdae30276258ec815e20057bd 100644 --- a/app/src/main/res/layout/f_eip.xml +++ b/app/src/main/res/layout/f_eip.xml @@ -8,23 +8,30 @@ android:layout_width="match_parent" android:layout_height="match_parent" xmlns:tools="http://schemas.android.com/tools" - android:id="@+id/eipServiceFragment"> + android:id="@+id/eipServiceFragment" + > <androidx.constraintlayout.widget.Guideline android:id="@+id/guideline_horizontal_top" android:layout_width="0dp" android:layout_height="0dp" android:orientation="horizontal" - app:layout_constraintBottom_toBottomOf="parent" app:layout_constraintGuide_percent="0.1" - app:layout_constraintRight_toRightOf="parent" /> + /> + + <androidx.constraintlayout.widget.Guideline + android:id="@+id/guideline_horizontal_center" + android:layout_width="0dp" + android:layout_height="0dp" + android:orientation="horizontal" + app:layout_constraintGuide_percent="0.25" + /> <androidx.constraintlayout.widget.Guideline android:id="@+id/guideline_vertical_left" android:layout_width="0dp" android:layout_height="0dp" android:orientation="vertical" - app:layout_constraintBottom_toBottomOf="parent" app:layout_constraintGuide_percent="0.3" /> @@ -33,16 +40,13 @@ android:layout_width="0dp" android:layout_height="0dp" android:orientation="horizontal" - app:layout_constraintBottom_toBottomOf="parent" - app:layout_constraintGuide_percent="0.55" - app:layout_constraintRight_toRightOf="parent" /> + app:layout_constraintGuide_percent="0.50" /> <androidx.constraintlayout.widget.Guideline android:id="@+id/guideline_horizontal_button_top" android:layout_width="0dp" android:layout_height="0dp" android:orientation="horizontal" - app:layout_constraintBottom_toBottomOf="parent" app:layout_constraintGuide_percent="0.8" /> @@ -51,9 +55,8 @@ android:layout_width="0dp" android:layout_height="0dp" android:orientation="horizontal" - app:layout_constraintBottom_toBottomOf="parent" app:layout_constraintGuide_percent="0.98" - app:layout_constraintRight_toRightOf="parent" /> + /> <androidx.constraintlayout.widget.Guideline android:id="@+id/guideline_vertical_right" @@ -68,26 +71,14 @@ android:layout_width="match_parent" android:layout_height="match_parent" android:scaleType="fitXY" - app:srcCompat="@drawable/background_eip" /> + app:srcCompat="@drawable/bg_disconnected" /> - <se.leap.bitmaskclient.base.views.MainButton - android:id="@+id/main_button" - android:layout_width="0dp" - android:layout_height="0dp" - android:layout_margin="@dimen/stdpadding" - app:layout_constraintTop_toBottomOf="@id/guideline_horizontal_top" - app:layout_constraintBottom_toTopOf="@+id/guideline_horizontal_bottom" - app:layout_constraintEnd_toStartOf="@+id/guideline_vertical_right" - app:layout_constraintStart_toStartOf="@+id/guideline_vertical_left" - app:layout_constraintDimensionRatio="1:1" - /> - <androidx.appcompat.widget.AppCompatTextView android:id="@+id/main_description" android:layout_width="wrap_content" android:layout_height="wrap_content" - app:layout_constraintTop_toBottomOf="@id/guideline_horizontal_bottom" + app:layout_constraintTop_toTopOf="parent" app:layout_constraintStart_toStartOf="parent" app:layout_constraintEnd_toEndOf="parent" app:layout_constraintBottom_toTopOf="@+id/sub_description" @@ -110,7 +101,7 @@ app:layout_constraintTop_toBottomOf="@id/main_description" app:layout_constraintStart_toStartOf="parent" app:layout_constraintEnd_toEndOf="parent" - app:layout_constraintBottom_toTopOf="@+id/gateway_location_button" + app:layout_constraintBottom_toTopOf="@+id/guideline_horizontal_center" android:textAppearance="@android:style/TextAppearance.DeviceDefault.Medium" android:textStyle="bold" android:textColor="@color/colorEipFragmentFont" @@ -125,6 +116,30 @@ android:gravity="center" /> + <androidx.appcompat.widget.AppCompatImageView + android:id="@+id/state_view" + android:layout_width="0dp" + android:layout_height="0dp" + app:layout_constraintBottom_toTopOf="@id/guideline_horizontal_bottom" + app:layout_constraintTop_toBottomOf="@id/guideline_horizontal_center" + app:layout_constraintLeft_toLeftOf="@id/guideline_vertical_left" + app:layout_constraintRight_toRightOf="@id/guideline_vertical_right" + app:layout_constraintVertical_bias="1" + app:srcCompat="@drawable/state_disconnected" + /> + + <se.leap.bitmaskclient.base.views.MainButton + android:id="@+id/main_button" + android:layout_width="0dp" + android:layout_height="0dp" + app:layout_constraintTop_toBottomOf="@id/guideline_horizontal_bottom" + app:layout_constraintBottom_toTopOf="@+id/guideline_horizontal_button_top" + app:layout_constraintEnd_toStartOf="@+id/guideline_vertical_right" + app:layout_constraintStart_toStartOf="@+id/guideline_vertical_left" + app:layout_constraintDimensionRatio="1:1" + /> + + <se.leap.bitmaskclient.base.views.LocationButton android:id="@+id/gateway_location_button" android:layout_width="match_parent" diff --git a/app/src/main/res/layout/f_gateway_selection.xml b/app/src/main/res/layout/f_gateway_selection.xml index 8ab2b1c3bd6508d6ad4e11441721685a8ab52d2d..5a614ce9fc7a15b419bd0bd38c3a457900e0c3dc 100644 --- a/app/src/main/res/layout/f_gateway_selection.xml +++ b/app/src/main/res/layout/f_gateway_selection.xml @@ -4,7 +4,9 @@ android:layout_width="match_parent" android:layout_height="match_parent" android:padding="@dimen/stdpadding" - tools:context=".base.fragments.GatewaySelectionFragment"> + tools:context=".base.fragments.GatewaySelectionFragment" + tools:viewBindingIgnore="true" + > <LinearLayout android:id="@+id/current_location_container" diff --git a/app/src/main/res/layout/f_log.xml b/app/src/main/res/layout/f_log.xml index ac77abd542a06234f75ceded4d740f1dfdcaa514..792770f69abec776b1fcd04d1a6235ff940aacc5 100644 --- a/app/src/main/res/layout/f_log.xml +++ b/app/src/main/res/layout/f_log.xml @@ -11,6 +11,7 @@ android:orientation="vertical" android:padding="16dp" android:id="@+id/log_layout" + tools:viewBindingIgnore="true" > <LinearLayout diff --git a/app/src/main/res/layout/f_log_sliders.xml b/app/src/main/res/layout/f_log_sliders.xml index ea444b3dfeb8aa6a3392b56e2e1f93dd72f5d117..3e4bbee41189ef9fd00e22367f9489c05aa7c731 100644 --- a/app/src/main/res/layout/f_log_sliders.xml +++ b/app/src/main/res/layout/f_log_sliders.xml @@ -14,7 +14,8 @@ android:visibility="gone" tools:visibility="visible" android:layout_width="wrap_content" - android:layout_height="wrap_content"> + android:layout_height="wrap_content" + tools:viewBindingIgnore="true"> <androidx.appcompat.widget.AppCompatTextView android:layout_width="match_parent" diff --git a/app/src/main/res/layout/f_motd.xml b/app/src/main/res/layout/f_motd.xml new file mode 100644 index 0000000000000000000000000000000000000000..6e763c75e3563710736593fcbb89b221f19801a5 --- /dev/null +++ b/app/src/main/res/layout/f_motd.xml @@ -0,0 +1,110 @@ +<?xml version="1.0" encoding="utf-8"?> +<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android" + xmlns:tools="http://schemas.android.com/tools" + android:layout_width="match_parent" + android:layout_height="match_parent" + xmlns:app="http://schemas.android.com/apk/res-auto" + android:theme="@style/BitmaskTheme" + tools:context=".base.fragments.MotdFragment" + android:fitsSystemWindows="true"> + + <androidx.constraintlayout.widget.Guideline + android:id="@+id/guideline_bottom" + android:layout_width="wrap_content" + android:layout_height="wrap_content" + android:orientation="horizontal" + app:layout_constraintBottom_toTopOf="@+id/next_btn" + /> + + <!-- The primary full-screen view. This can be replaced with whatever view + is needed to present your content, e.g. VideoView, SurfaceView, + TextureView, etc. --> + <ScrollView + android:layout_width="0dp" + android:layout_height="0dp" + app:layout_constraintTop_toTopOf="parent" + app:layout_constraintBottom_toBottomOf="@id/guideline_bottom" + app:layout_constraintLeft_toLeftOf="parent" + app:layout_constraintRight_toRightOf="parent" + android:clipChildren="true" + android:fillViewport="true" + android:background="@drawable/background_motd" + > + <androidx.constraintlayout.widget.ConstraintLayout + android:layout_width="match_parent" + android:layout_height="wrap_content" + android:gravity="center_horizontal" + android:orientation="vertical" + > + + + <androidx.constraintlayout.widget.Guideline + android:id="@+id/guideline_sv_left" + android:layout_width="wrap_content" + android:layout_height="wrap_content" + android:orientation="vertical" + app:layout_constraintGuide_percent="0.15" /> + + <androidx.constraintlayout.widget.Guideline + android:id="@+id/guideline_sv_right" + android:layout_width="wrap_content" + android:layout_height="wrap_content" + android:orientation="vertical" + app:layout_constraintGuide_percent="0.85" /> + + <androidx.constraintlayout.widget.Guideline + android:id="@+id/guideline_sv_top" + android:layout_width="wrap_content" + android:layout_height="wrap_content" + android:orientation="horizontal" + app:layout_constraintGuide_percent="0.1" /> + + <androidx.constraintlayout.widget.Guideline + android:id="@+id/guideline_sv_center" + android:layout_width="wrap_content" + android:layout_height="wrap_content" + android:orientation="horizontal" + app:layout_constraintGuide_percent="0.4" /> + + <de.hdodenhof.circleimageview.CircleImageView + android:id="@+id/motd_icon_circle" + android:layout_width="120dp" + android:layout_height="120dp" + app:layout_constraintTop_toTopOf="@id/guideline_sv_top" + app:layout_constraintBottom_toTopOf="@+id/guideline_sv_center" + app:layout_constraintLeft_toLeftOf="parent" + app:layout_constraintRight_toRightOf="parent" + android:src="@drawable/motd_img" + android:visibility="visible" + /> + <androidx.appcompat.widget.AppCompatTextView + android:id="@+id/motd_content" + app:layout_constraintLeft_toLeftOf="@id/guideline_sv_left" + app:layout_constraintRight_toRightOf="@+id/guideline_sv_right" + app:layout_constraintTop_toBottomOf="@+id/guideline_sv_center" + android:layout_width="0dp" + android:layout_height="wrap_content" + android:layout_marginVertical="@dimen/standard_margin" + android:gravity="center_horizontal" + android:keepScreenOn="true" + android:padding="@dimen/stdpadding" + android:elegantTextHeight="true" + android:autoSizeTextType="uniform" + android:text=" aaa aaa aaa aaaaaaaaaaaaaaaaaaaa \n\n\”ssdfsdf Riseup's services are funded by donations from people like you. We try not to ask too often, but we have to ask sometimes. Please consider making a https://riseup.net/donate donation if you value this freely available service, appreciate that we don't track or sell your data, or want to support people around the world working towards liberatory social change." + android:textSize="16sp" + android:textStyle="bold" /> + </androidx.constraintlayout.widget.ConstraintLayout> + </ScrollView> + + <androidx.appcompat.widget.AppCompatImageButton + android:id="@+id/next_btn" + app:layout_constraintBottom_toBottomOf="parent" + android:layout_width="match_parent" + android:layout_height="80dp" + android:layout_alignParentBottom="true" + android:src="@drawable/ic_arrow_right" + android:background="?attr/selectableItemBackground" + android:text="next" + /> + +</androidx.constraintlayout.widget.ConstraintLayout> \ No newline at end of file diff --git a/app/src/main/res/layout/f_settings.xml b/app/src/main/res/layout/f_settings.xml index 398d2c8646dd5c1735167644168334feffba958e..3ce19797943c6f2c8f0a4d9d6a38a4702b176694 100644 --- a/app/src/main/res/layout/f_settings.xml +++ b/app/src/main/res/layout/f_settings.xml @@ -4,8 +4,9 @@ xmlns:app="http://schemas.android.com/apk/res-auto" android:layout_width="match_parent" android:layout_height="match_parent" + xmlns:tools="http://schemas.android.com/tools" android:padding="@dimen/stdpadding" - > + tools:viewBindingIgnore="true"> <LinearLayout android:layout_width="match_parent" android:layout_height="wrap_content" @@ -105,5 +106,33 @@ app:icon="@drawable/ic_access_point_36" /> + <se.leap.bitmaskclient.base.views.IconTextEntry + android:id="@+id/gateway_pinning" + android:layout_width="match_parent" + android:layout_height="wrap_content" + app:text="Gateway pinning" + app:singleLine="false" + app:subtitle="Connect to a specific Gateway for debugging purposes" + /> + + <se.leap.bitmaskclient.base.views.IconSwitchEntry + android:id="@+id/experimental_transports" + android:layout_width="match_parent" + android:layout_height="wrap_content" + app:text="Experimental transports" + app:singleLine="false" + app:subtitle="These transports might circumvent censorship, but are still in a testing phase" + /> + + <se.leap.bitmaskclient.base.views.IconSwitchEntry + android:id="@+id/obfuscation_proxy_pinning" + android:layout_width="match_parent" + android:layout_height="wrap_content" + app:text="Obfuscation proxy pinning" + app:singleLine="false" + app:subtitle="Connect to a specific obfuscation proxy for debugging purposes" + android:visibility="gone" + /> + </LinearLayout> </ScrollView> \ No newline at end of file diff --git a/app/src/main/res/layout/f_test_layout.xml b/app/src/main/res/layout/f_test_layout.xml new file mode 100644 index 0000000000000000000000000000000000000000..6ec91259f1c7a63ee84663e835fb477b1a060949 --- /dev/null +++ b/app/src/main/res/layout/f_test_layout.xml @@ -0,0 +1,8 @@ +<?xml version="1.0" encoding="utf-8"?> +<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android" + android:layout_width="match_parent" + android:layout_height="match_parent" + android:background="@drawable/splash_page" + > + +</FrameLayout> \ No newline at end of file diff --git a/app/src/main/res/layout/v_actionbar_title.xml b/app/src/main/res/layout/v_actionbar_title.xml new file mode 100644 index 0000000000000000000000000000000000000000..1985ef21c08f023dbbf499054dd8cd95a9e155a7 --- /dev/null +++ b/app/src/main/res/layout/v_actionbar_title.xml @@ -0,0 +1,32 @@ +<?xml version="1.0" encoding="utf-8"?> + +<androidx.appcompat.widget.LinearLayoutCompat xmlns:android="http://schemas.android.com/apk/res/android" + xmlns:tools="http://schemas.android.com/tools" + android:id="@+id/action_bar_title_container" + android:layout_width="wrap_content" + android:layout_height="match_parent" + android:orientation="vertical"> + + <androidx.appcompat.widget.AppCompatTextView + android:id="@+id/action_bar_title" + android:layout_width="wrap_content" + tools:text="Bitmask" + android:layout_height="wrap_content" + android:ellipsize="end" + android:maxLines="1" + android:textStyle="normal" + android:textAppearance="@android:style/TextAppearance.DeviceDefault.Widget.ActionBar.Title" + /> + + <androidx.appcompat.widget.AppCompatTextView + android:id="@+id/action_bar_subtitle" + android:layout_width="wrap_content" + tools:text="Advanced Settings" + android:layout_height="wrap_content" + android:ellipsize="end" + android:maxLines="1" + android:textAppearance="@android:style/TextAppearance.DeviceDefault.Widget.ActionBar.Subtitle" + android:textColor="@color/colorActionBarSubtitleFont" + /> + +</androidx.appcompat.widget.LinearLayoutCompat> diff --git a/app/src/main/res/layout/v_custom_notification.xml b/app/src/main/res/layout/v_custom_notification.xml index e97fcbe23edb8c662c791cdb927917f10efe747e..c9854ff3bf6e516cf53a37195ea759f3d7acc2c2 100644 --- a/app/src/main/res/layout/v_custom_notification.xml +++ b/app/src/main/res/layout/v_custom_notification.xml @@ -5,6 +5,7 @@ android:layout_width="match_parent" android:layout_height="match_parent" style="@android:style/TextAppearance.StatusBar.EventContent" + tools:viewBindingIgnore="true" > <ImageView diff --git a/app/src/main/res/layout/v_icon_select_text_list_item.xml b/app/src/main/res/layout/v_icon_select_text_list_item.xml index 801a372a7d74ed7b126656350de379ee33c6c064..60c5908c7610109040117f6ba392faa2c2b7dd29 100644 --- a/app/src/main/res/layout/v_icon_select_text_list_item.xml +++ b/app/src/main/res/layout/v_icon_select_text_list_item.xml @@ -3,7 +3,8 @@ android:layout_height="?android:attr/listPreferredItemHeightSmall" android:layout_width="match_parent" android:orientation="horizontal" - xmlns:tools="http://schemas.android.com/tools"> + xmlns:tools="http://schemas.android.com/tools" + tools:viewBindingIgnore="true"> <androidx.appcompat.widget.AppCompatImageView android:id="@+id/material_icon" diff --git a/app/src/main/res/layout/v_icon_text_list_item.xml b/app/src/main/res/layout/v_icon_text_list_item.xml index d183864d4727c5d48389ebcac0822991471be892..814fd4d5df639a71a677b1449a9853dcefafc6db 100644 --- a/app/src/main/res/layout/v_icon_text_list_item.xml +++ b/app/src/main/res/layout/v_icon_text_list_item.xml @@ -3,7 +3,8 @@ android:layout_height="wrap_content" android:layout_width="match_parent" android:orientation="vertical" - xmlns:tools="http://schemas.android.com/tools"> + xmlns:tools="http://schemas.android.com/tools" + tools:viewBindingIgnore="true"> <LinearLayout android:layout_width="match_parent" android:layout_height="wrap_content" diff --git a/app/src/main/res/layout/v_loading_screen.xml b/app/src/main/res/layout/v_loading_screen.xml index 26ab25cca2e2a99b29d13e4d70c7a4ac4558b584..dd83aa389fa566e2f8696711a20ad83a1250ae0f 100644 --- a/app/src/main/res/layout/v_loading_screen.xml +++ b/app/src/main/res/layout/v_loading_screen.xml @@ -8,6 +8,7 @@ android:orientation="vertical" android:visibility="gone" tools:visibility="visible" + tools:viewBindingIgnore="true" > <androidx.appcompat.widget.AppCompatImageView diff --git a/app/src/main/res/layout/v_location_button.xml b/app/src/main/res/layout/v_location_button.xml index 7f16a6b1b272af28dcbf4a86f723f71a5ce41d72..22712b790bcf54e44fddd4b9cb0cf8e1ce144f26 100644 --- a/app/src/main/res/layout/v_location_button.xml +++ b/app/src/main/res/layout/v_location_button.xml @@ -5,9 +5,11 @@ android:orientation="horizontal" android:layout_width="match_parent" android:layout_gravity="center_vertical" - android:padding="@dimen/stdpadding" - android:background="@drawable/cust_button_primary_rect" - android:layout_height="match_parent"> + android:layout_height="match_parent" + android:paddingLeft="@dimen/stdpadding" + android:paddingRight="@dimen/stdpadding" + android:background="@drawable/cust_button_light_rect" + > <androidx.appcompat.widget.AppCompatImageView android:id="@+id/world_icn" @@ -85,18 +87,15 @@ <se.leap.bitmaskclient.base.views.LocationIndicator android:id="@+id/load_indicator" - android:layout_marginBottom="4dp" android:layout_width="48dp" - android:layout_height="40dp" + android:layout_height="28dp" android:layout_alignParentEnd="true" android:layout_alignParentRight="true" android:layout_centerVertical="true" - android:paddingTop="@dimen/stdpadding" - android:paddingBottom="@dimen/stdpadding" - android:visibility="visible" android:layout_gravity="center_vertical" - app:tint="@color/colorLocationButtonTintTransparent" - /> + android:paddingBottom="4dp" + android:visibility="visible" + app:tint="@color/colorLocationButtonTintTransparent" /> diff --git a/app/src/main/res/layout/v_location_status_indicator.xml b/app/src/main/res/layout/v_location_status_indicator.xml index a8ba905e240b25c11cfd63246fcbb1e4d3c55c49..af831cb0256f4d802da4b00cd1a25a55ba056406 100644 --- a/app/src/main/res/layout/v_location_status_indicator.xml +++ b/app/src/main/res/layout/v_location_status_indicator.xml @@ -5,6 +5,7 @@ android:orientation="horizontal" android:layout_width="match_parent" android:layout_height="match_parent" + tools:viewBindingIgnore="true" > <androidx.constraintlayout.widget.Guideline diff --git a/app/src/main/res/layout/v_log_item.xml b/app/src/main/res/layout/v_log_item.xml index 5f809523cdbcebaf5a71b3a113b7cea13d0ab2ea..91bb99fd9d5e3a2050b2a87f87021816e403fd56 100644 --- a/app/src/main/res/layout/v_log_item.xml +++ b/app/src/main/res/layout/v_log_item.xml @@ -3,6 +3,7 @@ android:orientation="vertical" android:layout_height="wrap_content" android:layout_width="match_parent" + tools:viewBindingIgnore="true" > <androidx.appcompat.widget.AppCompatTextView android:id="@android:id/text1" diff --git a/app/src/main/res/layout/v_main_btn.xml b/app/src/main/res/layout/v_main_btn.xml deleted file mode 100644 index c561e4cd4036db01aa71699bfeed134de404e036..0000000000000000000000000000000000000000 --- a/app/src/main/res/layout/v_main_btn.xml +++ /dev/null @@ -1,53 +0,0 @@ -<?xml version="1.0" encoding="utf-8"?> -<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android" - android:layout_width="wrap_content" - android:layout_height="wrap_content" - android:id="@+id/vpn_btn_container" - xmlns:app="http://schemas.android.com/apk/res-auto" - xmlns:tools="http://schemas.android.com/tools"> - - <androidx.appcompat.widget.AppCompatImageView - android:id="@+id/vpn_btn_glow" - android:layout_width="wrap_content" - android:layout_height="wrap_content" - android:background="@drawable/main_btn_glow" - tools:visibility="visible" - android:visibility="gone" - app:backgroundTint="@color/colorMainBtnHighlight" - /> - - - <androidx.appcompat.widget.AppCompatImageView - android:id="@+id/vpn_btn_shadow_dark" - android:layout_width="wrap_content" - android:layout_height="wrap_content" - app:srcCompat="@drawable/main_btn_shadow" - android:visibility="visible" - /> - - <androidx.appcompat.widget.AppCompatImageView - android:id="@+id/vpn_btn_shadow_light" - android:layout_width="wrap_content" - android:layout_height="wrap_content" - tools:visibility="visible" - tools:tint="@color/colorMainBtnHighlight" - android:visibility="gone" - /> - - <androidx.appcompat.widget.AppCompatImageView - android:id="@+id/vpn_btn_fill" - android:layout_width="wrap_content" - android:layout_height="wrap_content" - app:srcCompat="@drawable/on_off_btn_start_2_no_shadow" - android:visibility="visible" - app:tint="@color/main_button_state_color" - /> - - <androidx.appcompat.widget.AppCompatImageView - android:id="@+id/vpn_btn_fill_overlay" - android:layout_width="wrap_content" - android:layout_height="wrap_content" - app:srcCompat="@drawable/on_off_btn_fill" - tools:visibility="visible" - /> -</RelativeLayout> \ No newline at end of file diff --git a/app/src/main/res/layout/v_main_button.xml b/app/src/main/res/layout/v_main_button.xml index 741fc88f476b2a29637d27cad06e8a2280da1722..729812381c87a7abb2a7af0bd1004ab24429f319 100644 --- a/app/src/main/res/layout/v_main_button.xml +++ b/app/src/main/res/layout/v_main_button.xml @@ -1,9 +1,9 @@ <?xml version="1.0" encoding="utf-8"?> -<androidx.constraintlayout.widget.ConstraintLayout - xmlns:android="http://schemas.android.com/apk/res/android" +<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android" android:layout_width="match_parent" android:layout_height="match_parent" - xmlns:app="http://schemas.android.com/apk/res-auto"> + xmlns:app="http://schemas.android.com/apk/res-auto" + xmlns:tools="http://schemas.android.com/tools"> <androidx.constraintlayout.widget.Guideline @@ -91,27 +91,8 @@ android:orientation="horizontal" app:layout_constraintGuide_percent="0.975" /> - - <ProgressBar - android:id="@+id/progressBar" - style="@style/Widget.AppCompat.ProgressBar.Horizontal" - - android:layout_width="0dp" - android:layout_height="0dp" - app:layout_constraintBottom_toBottomOf="@id/border_guideline_bottom" - app:layout_constraintEnd_toEndOf="@id/border_guideline_right" - app:layout_constraintStart_toStartOf="@id/border_guideline_left" - app:layout_constraintTop_toTopOf="@id/border_guideline_top" - app:layout_constraintDimensionRatio="1:1" - android:indeterminate="true" - android:indeterminateDuration="800" - android:indeterminateDrawable="@drawable/progressbar_circle" - android:interpolator="@android:anim/decelerate_interpolator" - android:indeterminateBehavior="cycle" - /> - <androidx.appcompat.widget.AppCompatImageView - android:id="@+id/circle" + android:id="@+id/button" android:layout_width="0dp" android:layout_height="0dp" app:layout_constraintBottom_toTopOf="@+id/vpn_btn_guideline_bottom" @@ -119,18 +100,11 @@ app:layout_constraintStart_toStartOf="@+id/vpn_btn_guideline_left" app:layout_constraintTop_toTopOf="@+id/vpn_btn_guideline_top" app:layout_constraintDimensionRatio="1:1" - app:srcCompat="@drawable/black_circle" /> + app:srcCompat="@drawable/button_circle_start" + /> + + + - <androidx.appcompat.widget.AppCompatImageView - android:id="@+id/vpn_state_key" - android:layout_width="0dp" - android:layout_height="0dp" - app:layout_constraintBottom_toTopOf="@+id/icn_guideline_bottom" - app:layout_constraintEnd_toStartOf="@+id/icn_guideline_right" - app:layout_constraintStart_toStartOf="@+id/icn_guideline_left" - app:layout_constraintTop_toTopOf="@+id/icn_guideline_top" - app:layout_constraintDimensionRatio="1:1" - app:layout_constraintVertical_bias="0.35" - app:srcCompat="@drawable/ic_btn_on_disabled" /> </androidx.constraintlayout.widget.ConstraintLayout> \ No newline at end of file diff --git a/app/src/main/res/layout/v_provider_credentials.xml b/app/src/main/res/layout/v_provider_credentials.xml index be40c233fba898c73b2f5bb3347b44c17edf89a6..189bace60ef53f6c6ccd4301e1ef7b44f10fb097 100644 --- a/app/src/main/res/layout/v_provider_credentials.xml +++ b/app/src/main/res/layout/v_provider_credentials.xml @@ -1,6 +1,7 @@ <?xml version="1.0" encoding="utf-8"?> <merge xmlns:android="http://schemas.android.com/apk/res/android" - xmlns:app="http://schemas.android.com/apk/res-auto"> + xmlns:app="http://schemas.android.com/apk/res-auto" + xmlns:tools="http://schemas.android.com/tools"> <androidx.appcompat.widget.AppCompatTextView android:id="@+id/provider_credentials_user_message" @@ -9,6 +10,7 @@ style="@style/TextAppearance.Design.Error" android:visibility="gone" android:linksClickable="true" + tools:viewBindingIgnore="true" /> <com.google.android.material.textfield.TextInputLayout diff --git a/app/src/main/res/layout/v_provider_header.xml b/app/src/main/res/layout/v_provider_header.xml index e0961ea67b728ba7157f42e63dfa2db0300bb7fe..42f4f7838545bfa2d083b677201ae1a4d3ed4742 100644 --- a/app/src/main/res/layout/v_provider_header.xml +++ b/app/src/main/res/layout/v_provider_header.xml @@ -2,7 +2,9 @@ <RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android" android:layout_height="wrap_content" android:layout_width="match_parent" - xmlns:app="http://schemas.android.com/apk/res-auto" > + xmlns:app="http://schemas.android.com/apk/res-auto" + xmlns:tools="http://schemas.android.com/tools" + tools:viewBindingIgnore="true"> <androidx.appcompat.widget.AppCompatImageView android:id="@+id/provider_header_logo" diff --git a/app/src/main/res/layout/v_provider_list_item.xml b/app/src/main/res/layout/v_provider_list_item.xml index b4f41793ad1f624a1317a945cb0a5218a5d73fb0..0e7cc7f37959f0a7d48ef474622d3f24edb42695 100644 --- a/app/src/main/res/layout/v_provider_list_item.xml +++ b/app/src/main/res/layout/v_provider_list_item.xml @@ -1,6 +1,7 @@ <?xml version="1.0" encoding="utf-8"?> <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" + xmlns:tools="http://schemas.android.com/tools" android:orientation="vertical" android:paddingTop="2dip" android:paddingBottom="2dip" @@ -8,7 +9,7 @@ android:layout_height="wrap_content" android:background="?android:attr/activatedBackgroundIndicator" android:minHeight="?android:attr/listPreferredItemHeight" -> + tools:viewBindingIgnore="true"> <androidx.appcompat.widget.AppCompatTextView android:id="@+id/provider_domain" android:layout_width="match_parent" diff --git a/app/src/main/res/layout/v_select_text_list_item.xml b/app/src/main/res/layout/v_select_text_list_item.xml index 44e8290673d536c49cf15d0d60b0569607a6f73c..47a1f4adc981e79d43e93ba6bee441407acab78d 100644 --- a/app/src/main/res/layout/v_select_text_list_item.xml +++ b/app/src/main/res/layout/v_select_text_list_item.xml @@ -4,7 +4,8 @@ android:layout_height="wrap_content" android:layout_width="match_parent" android:orientation="vertical" - android:background="?attr/selectableItemBackground"> + android:background="?attr/selectableItemBackground" + tools:viewBindingIgnore="true"> <LinearLayout android:layout_width="match_parent" diff --git a/app/src/main/res/layout/v_simple_checkbox.xml b/app/src/main/res/layout/v_simple_checkbox.xml index 8bae20b94dad654c9bd30a31f24a25d19aa70fb3..a552034111ae8dba09ab5d3848860f33cfcb3052 100644 --- a/app/src/main/res/layout/v_simple_checkbox.xml +++ b/app/src/main/res/layout/v_simple_checkbox.xml @@ -1,8 +1,9 @@ <?xml version="1.0" encoding="utf-8"?> <RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android" xmlns:app="http://schemas.android.com/apk/res-auto" - android:layout_width="match_parent" android:layout_height="match_parent" - > + android:layout_width="match_parent" + android:layout_height="match_parent" + xmlns:tools="http://schemas.android.com/tools"> <View android:layout_width="wrap_content" @@ -18,6 +19,7 @@ android:layout_marginRight="8dp" android:layout_marginBottom="2dp" android:background="@drawable/cust_checkbox" + tools:viewBindingIgnore="true" /> <androidx.appcompat.widget.AppCompatImageView android:id="@+id/check_view" diff --git a/app/src/main/res/layout/v_single_list_item.xml b/app/src/main/res/layout/v_single_list_item.xml index 7b35bf7fc340f5f9954a6cb78fbeb426ad6259d1..7bf772da060ce0521089987fae2708ba00a9e821 100644 --- a/app/src/main/res/layout/v_single_list_item.xml +++ b/app/src/main/res/layout/v_single_list_item.xml @@ -1,4 +1,5 @@ <androidx.appcompat.widget.AppCompatTextView xmlns:android="http://schemas.android.com/apk/res/android" + xmlns:tools="http://schemas.android.com/tools" android:id="@android:id/text1" android:layout_width="match_parent" android:layout_height="wrap_content" @@ -9,4 +10,5 @@ android:paddingEnd="?android:attr/listPreferredItemPaddingEnd" android:paddingRight="?android:attr/listPreferredItemPaddingRight" android:background="?android:attr/activatedBackgroundIndicator" - android:minHeight="?android:attr/listPreferredItemHeightSmall" /> \ No newline at end of file + android:minHeight="?android:attr/listPreferredItemHeightSmall" + tools:viewBindingIgnore="true" /> \ No newline at end of file diff --git a/app/src/main/res/layout/v_switch_list_item.xml b/app/src/main/res/layout/v_switch_list_item.xml index 3ba37b817c6043db03cc285afb4af20c5ec228e0..514f28e7b195294d2435e0ebf28e5f9bcbcfbd79 100644 --- a/app/src/main/res/layout/v_switch_list_item.xml +++ b/app/src/main/res/layout/v_switch_list_item.xml @@ -4,6 +4,7 @@ android:layout_height="wrap_content" android:layout_width="match_parent" android:orientation="vertical" + tools:viewBindingIgnore="true" > <RelativeLayout android:layout_width="match_parent" diff --git a/app/src/main/res/layout/v_vpn_status.xml b/app/src/main/res/layout/v_vpn_status.xml index ce8e6928e5bab2d7ec7fc4c435db309242cf730e..02f0659a64002adc97026bde826fa9344262121d 100644 --- a/app/src/main/res/layout/v_vpn_status.xml +++ b/app/src/main/res/layout/v_vpn_status.xml @@ -5,7 +5,8 @@ --> <merge xmlns:tools="http://schemas.android.com/tools" - xmlns:android="http://schemas.android.com/apk/res/android"> + xmlns:android="http://schemas.android.com/apk/res/android" + tools:viewBindingIgnore="true"> <Space android:layout_weight="1" diff --git a/app/src/main/res/menu/f_log.xml b/app/src/main/res/menu/f_log.xml index d30b13cb0ab616cfe0962e681714bb9c1609ba2a..3a1d51782443d8fe88f69189a3f74aca9cf4e7aa 100644 --- a/app/src/main/res/menu/f_log.xml +++ b/app/src/main/res/menu/f_log.xml @@ -18,13 +18,13 @@ <item android:id="@+id/clearlog" android:icon="@drawable/ic_menu_delete" - app:showAsAction="ifRoom" + app:showAsAction="never" android:title="@string/clear_log" android:titleCondensed="@string/clear"/> <item android:id="@+id/send" android:icon="@drawable/ic_menu_share" - app:showAsAction="ifRoom" + app:showAsAction="never" android:title="@string/send_logfile" android:titleCondensed="@string/send"/> diff --git a/app/src/main/res/values-ar/strings.xml b/app/src/main/res/values-ar/strings.xml index f12a0a74ea5a7bf0ae9bd89c45caf8a0af25e2f5..763e2f997aa4355243d58ed34ca23bf58d20cdd0 100644 --- a/app/src/main/res/values-ar/strings.xml +++ b/app/src/main/res/values-ar/strings.xml @@ -2,8 +2,10 @@ <resources> <string name="retry">حاول مجدداً</string> <string name="repository_url_text">كود المصدر متواجد هنا https://0xacab.org/leap/bitmask_android</string> - <string name="leap_tracker">متتبع الأعطال متوافر هنا https://0xacab.org/leap/bitmask_android/issues</string> - <string name="translation_project_text">يمكنك الترجمة؟ اطلع على مشروع الترجمة الخاص بنا عبر هذا الرابط https://www.transifex.com/projects/p/bitmask-android/</string> + <string name="leap_tracker">متتبع الأعطال متوافر هنا +https://0xacab.org/leap/bitmask_android/issues</string> + <string name="translation_project_text">يمكنك الترجمة؟ اطلع على مشروع الترجمة الخاص بنا عبر هذا الرابط +https://www.transifex.com/projects/p/bitmask/</string> <string name="switch_provider_menu_option">بدّل مزود الخدمة</string> <string name="info">معلومات</string> <string name="show_connection_details">عرض تفاصيل الاتصال</string> diff --git a/app/src/main/res/values-az/strings.xml b/app/src/main/res/values-az/strings.xml index 450bdc1815ec594342d52790d9a88c0a548c2289..2cc74764a49e3d09956b337437eeabb794d7d10f 100644 --- a/app/src/main/res/values-az/strings.xml +++ b/app/src/main/res/values-az/strings.xml @@ -3,7 +3,7 @@ <string name="retry">Təkrar</string> <string name="repository_url_text">Başlanğıc kodunu https://0xacab.org/leap/bitmask_android ünvanından əldə edə bilərsiniz</string> <string name="leap_tracker">Issue tracker available at https://0xacab.org/leap/bitmask_android/issues</string> - <string name="translation_project_text">Tərcümələri xoşlayır və qiymətləndirir. Bizim Transifex layihəsinə https://www.transifex.com/projects/p/bitmask-android/ səhifəsinə baxın.</string> + <string name="translation_project_text">Tərcümələri xoşlayır və qiymətləndirir. Bizim Transifex layihəsinə https://www.transifex.com/projects/p/bitmask/ səhifəsinə baxın.</string> <string name="switch_provider_menu_option">Provayderi dəyiş</string> <string name="info">Məlumat</string> <string name="show_connection_details">Qoşulma məlumatlarını göstər</string> diff --git a/app/src/main/res/values-be/plurals-icsopenvpn.xml b/app/src/main/res/values-be/plurals-icsopenvpn.xml deleted file mode 100755 index 70489fbc5eaa8f4e14ff8d70d126c8ad64ef3632..0000000000000000000000000000000000000000 --- a/app/src/main/res/values-be/plurals-icsopenvpn.xml +++ /dev/null @@ -1,3 +0,0 @@ -<?xml version="1.0" encoding="utf-8"?> -<!--Generated by crowdin.com--> -<resources></resources> diff --git a/app/src/main/res/values-be/strings-icsopenvpn.xml b/app/src/main/res/values-be/strings-icsopenvpn.xml deleted file mode 100755 index 11eb6c76b80a79e0f8b35651b0f1def782889983..0000000000000000000000000000000000000000 --- a/app/src/main/res/values-be/strings-icsopenvpn.xml +++ /dev/null @@ -1,462 +0,0 @@ -<?xml version="1.0" encoding="utf-8"?> -<!--Generated by crowdin.com--> -<!-- - ~ 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> - - <string name="address">Адрас сервера:</string> - <string name="port">Порт сервера:</string> - <string name="location">Размяшчэнне</string> - <string name="cant_read_folder">Не атрымоўваецца прачытаць каталог</string> - <string name="select">Выбраць</string> - <string name="cancel">Адмена</string> - <string name="no_data">Няма дадзеных</string> - <string name="useLZO">Сціск LZO</string> - <string name="client_no_certificate">Няма сертыфіката</string> - <string name="client_certificate_title">Сертыфікат кліента</string> - <string name="client_key_title">Ключ сертыфіката кліента</string> - <string name="client_pkcs12_title">Файл PKCS12</string> - <string name="ca_title">Сертыфікат ЦС</string> - <string name="no_certificate">Трэба выбраць сертыфікат</string> - <string name="copyright_guicode">Зыходны код і адсочванне праблем даступныя на https://github.com/schwabe/ics-openvpn/</string> - <string name="copyright_others">Дадзеная праграма выкарыстоўвае наступныя кампаненты; гледзіце зыходны код для атрымання падрабязнай інфармацыі пра ліцэнзію</string> - <string name="about">Пра дадатак</string> - <string name="vpn_list_title">Профілі</string> - <string name="vpn_type">Тып</string> - <string name="pkcs12pwquery">Пароль для PKCS12</string> - <string name="file_select">Выбраць…</string> - <string name="file_nothing_selected">Вы павінны выбраць файл</string> - <string name="useTLSAuth">Скарыстаць аўтэнтыфікацыю TLS</string> - <string name="tls_direction">Кірунак праверкі TLS</string> - <string name="ipv6_dialog_tile">Увядзіце адрас/маску падсеткі IPv6 у фармаце CIDR (прыкладам, 2000:dd::23/64)</string> - <string name="ipv4_dialog_title">Увядзіце адрас/маску падсеткі IPv4 у фармаце CIDR (прыкладам, 1.2.3.4/24)</string> - <string name="ipv4_address">Адрас IPv4</string> - <string name="ipv6_address">Адрас IPv6</string> - <string name="custom_option_warning">Увядзіце дадатковыя параметры OpenVPN. Выкарыстоўвайце гэту магчымасць з вялікай асцярожнасцю. Калі вы лічыце, што адсутнічае важны параметр, звяжыцеся з аўтарам</string> - <string name="auth_username">Імя карыстача</string> - <string name="auth_pwquery">Пароль</string> - <string name="static_keys_info">Для канфігурацыі са статычнымі сертыфікатамі будуць выкарыстоўвацца ключы TLS</string> - <string name="configure_the_vpn">Налада VPN</string> - <string name="menu_add_profile">Дадаць канфігурацыю</string> - <string name="add_profile_name_prompt">Увядзіце назву новай канфігурацыі</string> - <string name="duplicate_profile_name">Калі ласка, увядзіце ўнікальную назву канфігурацыі</string> - <string name="profilename">Назва канфігурацыі</string> - <string name="no_keystore_cert_selected">Трэба выбраць сертыфікат карыстача</string> - <string name="no_ca_cert_selected">Трэба выбраць сертыфікат ЦС</string> - <string name="no_error_found">Памылак не знойдзена</string> - <string name="config_error_found">Ошибка в конфигурации</string> - <string name="ipv4_format_error">Немагчыма распазнаць IPv4 адрас</string> - <string name="custom_route_format_error">Немагчыма распазнаць карыстацкія маршруты</string> - <string name="pw_query_hint">(пакіньце пустым для запыту па вымозе)</string> - <string name="vpn_shortcut">Цэтлік OpenVPN</string> - <string name="vpn_launch_title">Падключэнне да VPN…</string> - <string name="shortcut_profile_notfound">Не знойдзены профіль, азначаны ў цэтліку</string> - <string name="random_host_prefix">Выпадковы прэфікс вузла</string> - <string name="random_host_summary">Дадае 6 выпадковых знакаў перад іменем хаста</string> - <string name="custom_config_title">Уключыць карыстацкія параметры</string> - <string name="custom_config_summary">Карыстацкія параметры. Скарыстайце з асцярожнасцю!</string> - <string name="route_rejected">Маршрут адхілены Android</string> - <string name="cancel_connection_long">Адключыць VPN</string> - <string name="clear_log">ачысціць журнал</string> - <string name="title_cancel">Пацверджанне скасавання</string> - <string name="cancel_connection_query">Адключыць актыўны VPN/скасаваць спробу падключэння?</string> - <string name="remove_vpn">Выдаліць VPN</string> - <string name="check_remote_tlscert">Правярае, ці выкарыстоўвае сервер сертыфікат з сервернымі пашырэннямі TLS (--remote-cert-tls server)</string> - <string name="check_remote_tlscert_title">Чакаць серверны сертыфікат TLS</string> - <string name="remote_tlscn_check_summary">Праверка DN аб\'екта падаленага сертыфіката</string> - <string name="remote_tlscn_check_title">Праверка імя хаста сертыфіката</string> - <string name="enter_tlscn_dialog">Увядзіце значэнне для праверкі DN выдаленага сертыфіката (прыкладам, C=DE, L=Paderborn, OU=Avian IP Carriers, CN=openvpn.blinkt.de)\n\n \Магчымыя значэнні: поўны DN ці RDN (у прыкладзе вышэй openvpn.blinkt.de) ці толькі прэфікс RDN для праверкі.\n\nПры выкарыстанні прэфікса RDN, «Server» падыдзе для «Server-1» і «Server-2»\n\nПры пустой тэкставай падлозе будзе правярацца, што RDN супадае з іменем вузла.\n\nПадрабязнасці гледзіце ў кіраўніцтве OpenVPN 2.3.1+, падзел --verify-x509-name</string> - <string name="enter_tlscn_title">Аб\'ект падаленага сертыфіката</string> - <string name="tls_key_auth">Уключыць аўтэнтыфікацыю па TLS ключу</string> - <string name="tls_auth_file">Файл аўтэнтыфікацыі TLS</string> - <string name="pull_on_summary">Запыт IP-адраса, маршрутаў і параметраў ад сервера.</string> - <string name="pull_off_summary">Ігнараваць усе параметры сервера. Параметры павінны быць азначаны ніжэй.</string> - <string name="use_pull">Запытваць параметры</string> - <string name="dns">DNS</string> - <string name="override_dns">Перавызначыць параметры DNS ад сервера</string> - <string name="dns_override_summary">Выкарыстоўваць вашы DNS</string> - <string name="searchdomain">Дамен пошуку</string> - <string name="dns1_summary">DNS-сервер для выкарыстання.</string> - <string name="dns_server">DNS-сервер</string> - <string name="secondary_dns_message">Другасны DNS-сервер выкарыстоўваецца, калі не атрыманы адказ ад першага сервера DNS.</string> - <string name="backup_dns">Рэзервовы сервер DNS</string> - <string name="ignored_pushed_routes">Ігнараваць пасыланыя маршруты</string> - <string name="ignore_routes_summary">Ігнараваць маршруты, пасыланыя серверам.</string> - <string name="default_route_summary">Перанакіроўвае ўвесь трафік праз VPN</string> - <string name="use_default_title">Выкарыстоўваць маршрут па змаўчанні</string> - <string name="custom_route_message">Увядзіце карыстальніцкія маршруты. Скарыстайце толькі адрас прызначэння ў фармаце CIDR. \"10.0.0.0/8 2002::/16\" скіруе сеткі 10.0.0.0/8 і 2002::/16 праз VPN.</string> - <string name="custom_route_message_excluded">Маршруты, якія НЕ павінны скіроўвацца праз VPN. Скарыстайце той жа сінтаксіс, што і для ўключаных маршрутаў.</string> - <string name="custom_routes_title">Карыстальніцкія маршруты</string> - <string name="custom_routes_title_excluded">Вынятыя сеткі</string> - <string name="log_verbosity_level">Ровень дэталізацыі журнала</string> - <string name="float_summary">Разрешить аутентифицированные пакеты с любого IP-адреса</string> - <string name="float_title">Дазволіць «плавальны» сервер</string> - <string name="custom_options_title">Карыстальніцкія параметры</string> - <string name="edit_vpn">Рэдагаванне параметраў VPN</string> - <string name="remove_vpn_query">Выдаліць профіль VPN «%s»?</string> - <string name="tun_error_helpful">На некаторых кастамных зборках права на /dev/tun могуць быць няправільнымі ці tun-модуль можа быць не ўключаны. Для прашыўкі CM9 можаце паспрабаваць выправіць уладальніка проста з налад праграмы</string> - <string name="tun_open_error">Не атрымоўваецца адкрыць tun інтэрфейс</string> - <string name="error">"Памылка: "</string> - <string name="clear">Ачысціць</string> - <string name="last_openvpn_tun_config">Адкрыццё tun-інтэрфейсу:</string> - <string name="local_ip_info">Адрас IPv4: %1$s/%2$d IPv6: %3$s MTU: %4$d</string> - <string name="dns_server_info">DNS-сервер: %1$s, Дамен: %2$s</string> - <string name="routes_info_incl">Маршруты: %1$s %2$s</string> - <string name="routes_info_excl">Вынятыя маршруты: %1$s %2$s</string> - <string name="routes_debug">Падлучаныя маршруты сэрвісу Vpn: %1$s %2$s</string> - <string name="ip_not_cidr">Атрымана інфармацыя інтэрфейсу %1$s і %2$s, другі адрас з\'яўляецца падаленым адрасам канала. Выкарыстоўваецца сеткавая маска /32 для лакальнага IP адраса. Рэжым, усталяваны OpenVPN: \"%3$s\".</string> - <string name="route_not_cidr">Немагчыма скарыстаць выразы %1$s і %2$s як маршрут па стандарце CIDR. выкарыстоўваецца /32 як маска падсеткі.</string> - <string name="route_not_netip">Маршрут выпраўлены з %1$s/%2$s на %3$s/%2$s</string> - <string name="keychain_access">Не атрымоўваецца атрымаць доступ да сховішча ключоў і сертыфікатаў Android. Гэта можа быць выклікана абнаўленнем прашыўкі ці аднаўлення старой копіі дадатку ці яго налад. Калі ласка, адрэдагуйце профіль VPN і наноў пакажыце ключы і сертыфікаты ў падзеле Асноўныя параметры.</string> - <string name="version_info">%1$s %2$s</string> - <string name="send_logfile">Адправіць файл журнала</string> - <string name="send">Адправіць</string> - <string name="ics_openvpn_log_file">ICS OpenVPN лог файл</string> - <string name="copied_entry">Запіс журнала скапіяваны ў буфер абмену</string> - <string name="tap_mode">Рэжым TAP</string> - <string name="faq_tap_mode">Рэжым TAP немагчымы на прыладах без root-а. Таму гэты дадатак не падтрымвае TAP</string> - <string name="tap_faq2">Ізноў? Вы здзекуецеся? Не падтрымваецца рэжым TAP і просьбы да аўтара пра гэта не дапамогуць яму рэалізавацца.</string> - <string name="tap_faq3">Трэці раз? Насамрэч можна было б пісаць эмулятар TAP, заснаваныя на tun, які б дадаваў інфармацыю 2 роўні пры адпраўленні і здабываў бы яе пры атрыманні. Але гэты эмулятар запатрабуе таксама ARP і, магчыма, кліента DHCP. Я не ведаю нікога, хто мог бы гэтым заняцца. Звяжыцеся са мной, калі вы хочаце заняцца гэтым.</string> - <string name="faq">Пытанні і адказы</string> - <string name="copying_log_entries">Капіяванне запісамі журнала</string> - <string name="faq_copying">Для капіявання аднаго запісу журнала трэба нажаць на яе і ўтрымваць. Каб скапіяваць/адправіць увесь файл журнала, скарыстайце опцыю «Адправіць файл журнала». Калі яна ўтоена, скарыстайце апаратную кнопку меню.</string> - <string name="faq_shortcut">Цэтлік для запуску</string> - <string name="faq_howto_shortcut">Вы можаце стварыць цэтлік для запуску OpenVPN на працоўным стале. У залежнасці ад вашага асяроддзя трэба дадаць цэтлік ці віджэт.</string> - <string name="no_vpn_support_image">Ваша прашыўка не падтрымвае VPNService API, прабачыце :(</string> - <string name="encryption">Шыфраванне</string> - <string name="cipher_dialog_title">Вызначце метад шыфравання</string> - <string name="chipher_dialog_message">Вызначце алгарытм шыфрацыі, які выкарыстоўваецца OpenVPN. Пакіньце пустым, каб скарыстаць шыфраванне па змаўчанні.</string> - <string name="auth_dialog_message">Увядзіце хэш-функцыю для аўтэнтыфікацыі ў OpenVPN. Пакіньце пустым для выкарыстання значэння па змаўчанні.</string> - <string name="settings_auth">Аўтэнтыфікацыя/шыфраванне</string> - <string name="file_explorer_tab">Агляд файлаў</string> - <string name="inline_file_tab">Убудаваны файл</string> - <string name="error_importing_file">Памылка імпарту файла</string> - <string name="import_error_message">Не атрымалася імпартаваць файл з файлавай сістэмы</string> - <string name="inline_file_data">[[Убудаваны файл дадзеных]]</string> - <string name="opentun_no_ipaddr">Адмова ў адкрыцці прылады tun без інфармацыі пра IP-адрас</string> - <string name="menu_import">Імпарт канфігурацыі з файла .ovpn</string> - <string name="menu_import_short">Імпарт</string> - <string name="import_content_resolve_error">Не атрымалася прачытаць канфігурацыю для імпарту</string> - <string name="error_reading_config_file">Памылка чытання файла канфігурацыі</string> - <string name="add_profile">Дадаць канфігурацыю</string> - <string name="import_could_not_open">Не атрымалася знайсці файл %1$s, азначаны ў файле канфігурацыі</string> - <string name="importing_config">Імпарт файла канфігурацыі з зыходнага %1$s</string> - <string name="import_warning_custom_options">Ваша канфігурацыя мела некалькі параметраў, якія не ўваходзяць у параметры стандартнай канфігурацыі. Гэтыя параметры былі вынесены ў карыстацкую канфігурацыю. Карыстацкая канфігурацыя адлюстроўваецца ніжэй:</string> - <string name="import_done">Файл канфігурацыі паспяхова прачытаны.</string> - <string name="nobind_summary">Не прывязвацца да лакальнага адраса і порта</string> - <string name="no_bind">Не выкарыстоўваць прывязкі</string> - <string name="import_configuration_file">Імпарт файла канфігурацыі</string> - <string name="faq_security_title">Меркаванні бяспекі</string> - <string name="faq_security">"Калі OpenVPN адчувальны да бяспекі, то дарэчныя будуць некалькі заўваг на яе рахунак. Усе дадзеныя на SD-карце ў існасці не абаронены. Кожны дадатак можа прачытаць іх (прыкладам, гэта праграма не патрабуе адмысловых прывілеяў на SD-карту). Дадзеныя гэтага дадатку могуць быць прачытаны толькі ім самім. Пры выкарыстанні опцыі імпарту сертыфікатаў і ключоў у дыялогавым акне дадзеныя захоўваюцца ў профілі VPN. Профілі VPN даступныя толькі гэтаму дадатку. (Не забудзьцеся потым выдаліць копіі на SD-карце). Нягледзячы на тое, што дадзеныя даступныя толькі гэтаму дадатку, яны ўсё яшчэ не зашыфраваны. Пры наяўнасці праў адміністратара (root) на тэлефоне ці праз нейкую ўразлівасць гэтыя дадзеныя можна выняць. Таксама захаваныя паролі захоўваюцца ў звычайным тэкставым выглядзе. Настойліва рэкамендуецца файлы pkcs12 імпартаваць у android keystore."</string> - <string name="import_vpn">Імпарт</string> - <string name="broken_image_cert_title">Памылка адлюстравання выбару сертыфіката</string> - <string name="broken_image_cert">Адбылася памылка пры спробе выкліку сістэмнага дыялогу выбару сертыфікатаў Android 4.0+. Гэтага не павінна было здарыцца на стандартнай прашыўцы. Можа быць у вашай прашыўцы сапсавана сховішча сертыфікатаў</string> - <string name="ipv4">IPv4</string> - <string name="ipv6">IPv6</string> - <string name="speed_waiting">Чаканне паведамлення пра стан…</string> - <string name="converted_profile">імпартаваны профіль</string> - <string name="converted_profile_i">імпартаваны профіль %d</string> - <string name="broken_images">Зламаныя прашыўкі</string> - <string name="broken_images_faq"><p> Вядома, што афіцыйныя прашыўкі HTC маюць дзіўныя праблемы з маршрутызацыяй, што прыводзіць да таго, што трафік не ідзе праз тунэль (гл. <a href=\"https://github.com/schwabe/ics-openvpn/issues/18\">Issue 18</a> у баг-трэкеры).</p><p>Таксама паведамлялася, што ў старых афіцыйных прашыўках SONY ад Xperia Arc S і Xperia Ray цалкам адсутнічае сэрвіс VPNService (гл. <a href=\"https://github.com/schwabe/ics-openvpn/issues/29\">Issue 29</a> у баг-трэкеры).</p><p>У некаторых неафіцыйных прашыўках модуль tun можа адсутнічаць, ці файл прылады /dev/tun можа мець няправільныя правы. Некаторыя прашыўкі CM9 могуць патрабаваць выпраўленні праў на /dev/tun у наладах «Хакі для дадзенай прылады».</p><p>І самае галоўнае: калі ў вас прашыўка з паказанымі праблемамі, паведаміце пра гэта вытворцу прылады. Чым больш за карыстачоў паведаміць пра праблему, тым больш за шанцы, што вытворца яе выправіць.</p></string> - <string name="pkcs12_file_encryption_key">Файл PKCS12-ключа</string> - <string name="private_key_password">Пароль закрытага ключа</string> - <string name="password">Пароль</string> - <string name="file_icon">файл значка</string> - <string name="tls_authentication">Аўтэнтыфікацыя/шыфраванне TLS</string> - <string name="generated_config">Згенераваная канфігурацыя</string> - <string name="generalsettings">Налады</string> - <string name="owner_fix_summary">Паспрабаваць змяніць уладальніка для /dev/tun. Некаторыя прашыўкі CM9 патрабуюць гэтага для карэктнай працы API OpenVPN. Патрабуецца root.</string> - <string name="owner_fix">Выправіць правы для /dev/tun</string> - <string name="generated_config_summary">Паказаць згенераваны файл канфігурацыі OpenVPN</string> - <string name="edit_profile_title">Праўка «%s»</string> - <string name="building_configration">Стварэнне канфігурацыі…</string> - <string name="netchange_summary">Перападлучацца, калі змяняецца стан сеткі (прыкладам, пры пераключэнні з Wi-Fi на мабільную і наадварот)</string> - <string name="netchange">Перападлучацца, калі змяняецца стан сеткі (прыкладам, пры пераключэнні з Wi-Fi на мабільную і наадварот)</string> - <string name="netstatus">Статус сеткі: %s</string> - <string name="extracahint">Сертыфікат ЦС звычайна захоўваецца ў Android Keystore. Вызначце асобны сертыфікат, калі ў вас паўсталі абмылы пры праверцы сертыфіката.</string> - <string name="select_file">Выбраць</string> - <string name="keychain_nocacert">Не атрымалася атрымаць сертыфікат ЦС са сховішча ключоў Android. Напэўна, аўтэнтыфікацыя завершыцца абмылай.</string> - <string name="show_log_summary">Паказвае акно журнала пры падлучэнні. Акно журнала заўсёды даступнае з панэлі апавяшчэнняў.</string> - <string name="show_log_window">Паказаць акно журнала</string> - <string name="mobile_info">%10$s %9$s працуе на %3$s %1$s (%2$s), Android %6$s (%7$s) API %4$d, ABI %5$s, (%8$s)</string> - <string name="error_rsa_sign">Памылка подпісу з выкарыстаннем ключа са сховішча Android %1$s: %2$s</string> - <string name="faq_system_dialogs">Папярэджанне VPN злучэння, што гаворыць, што гэты дадатак можа перахапляць увесь сеткавы трафік, паказваецца сістэмай для прадухілення злоўжывання API VPNService.\nАпавяшчэнне пра VPN злучэнні (знак ключа) таксама фармуецца сістэмай Android для сігналізацыі выходнага VPN злучэння. У некаторых прашыўках гэта апавяшчэнне суправаджаецца гукам.\nAndroid выкарыстоўвае гэтыя сістэмныя апавяшчэнні для вашай жа ўласнай бяспекі і іх няможна абысці. (На жаль, на некаторых прашыўках гэта ставіцца і да гуку апавяшчэння)</string> - <string name="faq_system_dialogs_title">Паведамленне пра падлучэнне і гук апавяшчэння</string> - <string name="translationby">Беларускі пераклад ад MikalaiB <bregid69@gmail.com></string> - <string name="ipdns">IP-адрас і DNS</string> - <string name="basic">Асноўныя</string> - <string name="routing">Маршрутызацыя</string> - <string name="obscure">Утоеныя параметры OpenVPN. Звычайна не патрабуюцца.</string> - <string name="advanced">Пашыраныя</string> - <string name="export_config_title">ICS Openvpn канфігурацыя</string> - <string name="warn_no_dns">Серверы DNS не выкарыстоўваюцца. Дазвол імёнаў можа не працаваць. Разгледзіце магчымасць усталёўкі карыстацкіх DNS-сервераў. Таксама звернеце ўвагу, што Android будзе працягваць скарыстаць параметры, паказаныя для вашага мабільнага/Wi-Fi злучэння, калі не азначаны DNS-серверы.</string> - <string name="dns_add_error">Не атрымалася дадаць DNS-сервер «%1$s», адхілены сістэмай: %2$s</string> - <string name="ip_add_error">Не атрымалася наладзіць IP-адрас «%1$s», адхілены сістэмай: %2$s</string> - <string name="faq_howto"><p>Скарыстайце гатовую канфігурацыю (пратэставаную на вашым кампутары ці атрыманую ад вашага правайдара)</p><p>Калі гэта прастой файл без pem/pkcs12, вы можаце адправіць яго як укладанне па электроннай пошце на сваю прыладу. Калі ж файлаў некалькі, вы можаце скарыстаць іх са сваёй карты памяці.</p><p>Проста адкрыйце .conf файл ці выберыце яго ў дыялогу імпарту (значок тэчкі ў спісе профіляў)</p><p>Калі праграма выдасць памылку пра нястачу некаторых файлаў, проста змесціце гэтыя файлы на карту памяці.</p><p>Націсніце кнопку захавання для дадання імпартаванай канфігурацыі ў праграму</p><p>Запусціце ваш VPN-тунэль, нажаўшы на яго назву ў спісе</p><p>Калі пры запуску выніклі памылкі, паспрабуйце разабрацца і ўхіліць іх.</p> </string> - <string name="faq_howto_title">Хуткі старт</string> - <string name="setting_loadtun_summary">Паспрабуйце загрузіць модуль ядра tun.ko, Перад тым як спрабаваць падлучыцца. Патрабуецца root-доступ на прыладзе.</string> - <string name="setting_loadtun">Загрузіць tun-модуль</string> - <string name="importpkcs12fromconfig">Імпарт PKCS12 са сховішча ключоў Android</string> - <string name="getproxy_error">Памылка пры атрыманні параметраў проксі-сервера: %s</string> - <string name="using_proxy">Выкарыстоўваецца проксі-сервер %1$s %2$s</string> - <string name="use_system_proxy">Выкарыстоўваць проксі-сервер сістэмы</string> - <string name="use_system_proxy_summary">Выкарыстоўваць сістэмную канфігурацыю проксі HTTP/HTTPS для злучэння.</string> - <string name="onbootrestartsummary">OpenVPN будзе падключацца да паказанага VPN, калі ён быў актыўны пры загрузцы сістэмы. Калі ласка, прачытайце FAQ пра папярэджанне пры падлучэнні перад тым, як скарыстаць гэту опцыю на Android < 5.0.</string> - <string name="onbootrestart">Падключэнне пры загрузцы</string> - <string name="ignore">Ігнараваць</string> - <string name="restart">Перазапуск</string> - <string name="restart_vpn_after_change">Змены канфігурацыі ўжываюцца пасля перазапуску VPN. (Пера)запусціць VPN цяпер?</string> - <string name="configuration_changed">Канфігурацыя зменена</string> - <string name="log_no_last_vpn">Не атрымалася вызначыць апошні карыстаны профіль для рэдагавання</string> - <string name="faq_duplicate_notification_title">Апавяшчэнні што дублююцца</string> - <string name="faq_duplicate_notification">Калі ў Android узнікае нястача аператыўнай памяці (RAM), непатрэбныя службы і дадаткі спыняюцца. З-за гэтага перапыняецца ўсталяванае VPN-злучэнне. Каб пазбегнуць гэтага, дадатак трэба запускаць з падвышаным прыярытэтам. Для запуску з высокім прыярытэтам дадатак павінен вывесці апавяшчэнне. Значок ключа паказваецца наверсе панэлі апавяшчэнняў самай сістэмай, як апісана ў папярэднім пытанні. Ён не лічыцца тым апавяшчэннем, якое дадатку патрэбна для запуску з высокім прыярытэтам.</string> - <string name="no_vpn_profiles_defined">Профілі VPN не азначаны.</string> - <string name="add_new_vpn_hint">Выкарыстоўвайце значок <img src=\"ic_menu_add\"/> для дадання новага VPN</string> - <string name="vpn_import_hint">Скарыстайце кнопку <img src=\"ic_menu_archive\"/> для імпарту існавалых профіляў (.ovpn ці .conf) з карты памяці.</string> - <string name="faq_hint">Не забудзьцеся зазірнуць у FAQ. Там ёсць кароткае кіраўніцтва.</string> - <string name="faq_routing_title">Конфигурация маршрутизации/интерфейса</string> - <string name="faq_routing">Канфігурацыя маршрутызацыі і інтэрфейсу вырабляецца не праз традыцыйныя ifconfig/route каманды, а з дапамогай VPNService API. Гэта прыводзіць да стварэння іншай канфігурацыі маршрутызацыі, адрознай ад канфігурацый, што выкарыстоўваюцца на іншых АС. Канфігурацыя VPN-тунэля складаецца з IP-адрасоў і сетак, якія павінны скіроўвацца праз гэты інтэрфейс. Ніякіх адменных партнёрскіх адрасоў ці адрасоў шлюза не патрабуецца. Таксама не патрабуюцца і адмысловыя маршруты для злучэння з VPN-серверам (прыкладам, дададзеныя пры выкарыстанні redirect-gateway). Такім чынам, дадатак будзе ігнараваць гэтыя параметры пры імпарце канфігурацыі. Дадатак з дапамогай VPNService API гарантуе, што падлучэнне да сервера не скіроўваецца праз VPN-тунэль. Падтрымліваецца кірунак праз тунэль толькі пэўных сетак. Дадатак спрабуе вызначыць сеткі, якія не павінны быць скіраваны праз тунэль (прыкладам, маршрут x.x.x.x y.y.y.y net_gateway) і вылічае спіс маршрутаў, у які не ўлучаюцца гэтыя маршруты, каб эмуляваць паводзіны іншых платформаў. Вокны журналаў і логаваў паказваюць канфігурацыю сэрвісу VPN пасля ўсталявання злучэння.</string> - <string name="persisttun_summary">Не выкарыстоўваць звычайнае злучэнне без VPN пры перападлучэнні OpenVPN.</string> - <string name="persistent_tun_title">Заўсёдны tun</string> - <string name="openvpn_log">Журнал OpenVPN</string> - <string name="import_config">Імпарт канфігурацыі OpenVPN</string> - <string name="battery_consumption_title">Спажыванне батарэі</string> - <string name="baterry_consumption">У маіх тэстах галоўнай крыніцай высокага спажывання электраэнергіі батарэі былі пакеты keepalive. Большасць OpenVPN-сервераў утрымваюць дырэктыву накшталт «keepalive 10 60», якая прымушае кліент і сервер мяняцца keepalive-пакетамі кожныя 10 секундаў. <p> Хоць гэтыя пакеты і маленькія, і не расходуюць шмат трафіка, яны прымушаюць радыёмодуль увесь час працаваць, што павялічвае выдатак энергіі. (гл. <a href=\"http://developer.android.com/training/efficient-downloads/efficient-network-access.html#RadioStateMachine\">The Radio State Machine | Android Developers</a>) <p> Налады keepalive не могуць быць зменены на кліенту, гэта можа зрабіць толькі сістэмны адміністратар OpenVPN. <p> На жаль, выкарыстанне keepalive больш, чым 60 секундаў з UDP, можа прывесці да таго, што некаторыя шлюзы NAT будуць абрываць злучэнне з-за адсутнасці актыўнасці. Выкарыстанне TCP з вялікім keepalive-таймаўтам будзе працаваць, але прадукцыйнасць тунэлявання TCP праз TCP у сетках з высокімі стратамі пакетаў вельмі нізкая (гл. <a href=\"http://sites.inka.de/bigred/devel/tcp-tcp.html\">Why TCP Over TCP Is A Bad Idea</a>)</string> - <string name="faq_tethering">Функцыя тэтэрынгу Android (праз WiFi, USB ці Bluetooth) і VPNService API (карыстанае гэтай праграмай) не працуюць разам. Падрабязней у <a href=\"https://github.com/schwabe/ics-openvpn/issues/34\">праблеме №34</a></string> - <string name="vpn_tethering_title">VPN и Tethering</string> - <string name="connection_retries">Спробы падлучэння</string> - <string name="reconnection_settings">Параметры перападлучэння</string> - <string name="connectretrymessage">Колькасць секундаў паміж спробамі падлучэння.</string> - <string name="connectretrywait">Секундаў паміж злучэннямі</string> - <string name="minidump_generated">OpenVPN завяршылася нечакана. Калі ласка, пагледзіце опцыю \"Адправіць Minidump\" у галоўным меню</string> - <string name="send_minidump">Адправіць Minidump распрацоўніку</string> - <string name="send_minidump_summary">Адпраўленне адладкавай інфармацыі распрацоўніку пра апошняе аварыйнае завяршэнне</string> - <string name="notifcation_title">OpenVPN - %s</string> - <string name="session_ipv4string">%1$s - %2$s</string> - <string name="session_ipv6string">%1$s - %3$s, %2$s</string> - <string name="state_connecting">Падключэнне</string> - <string name="state_wait">Чаканне адказу сервера</string> - <string name="state_auth">Праверка сапраўднасці</string> - <string name="state_get_config">Атрыманне канфігурацыі кліента</string> - <string name="state_assign_ip">Прызначэнне IP-адрасоў</string> - <string name="state_add_routes">Даданне маршрутаў</string> - <string name="state_connected">Падлучана</string> - <string name="state_disconnected">Адключыцца</string> - <string name="state_reconnecting">Паўторнае падлучэнне</string> - <string name="state_exiting">Выйсце</string> - <string name="state_noprocess">Не запушчана</string> - <string name="state_resolve">Дазвол імёнаў вузлоў</string> - <string name="state_tcp_connect">Падключэнне (TCP)</string> - <string name="state_auth_failed">Памылка аўтэнтыфікацыі</string> - <string name="state_nonetwork">Чаканне працы сеткі</string> - <string name="statusline_bytecount">↓%2$s %1$s - ↑%4$s %3$s</string> - <string name="notifcation_title_notconnect">Раз\'яднана</string> - <string name="start_vpn_title">Подключение к VPN %s</string> - <string name="start_vpn_ticker">Падключэнне да VPN %s</string> - <string name="jelly_keystore_alphanumeric_bug">У некаторых версіях Android 4.1 ёсць праблемы, калі імя сертыфіката ўтрымвае не літарна-лічбавыя знакі (прыкладам, прабелы, падкрэсленні ці працяжнік). Паспрабуйце пераўсталяваць сертыфікат без выкарыстання адмысловых знакаў.</string> - <string name="encryption_cipher">Алгарытм шыфравання</string> - <string name="packet_auth">Праверка сапраўднасці пакетаў</string> - <string name="auth_dialog_title">Вызначце метад праверкі сапраўднасці пакетаў</string> - <string name="built_by">создан %s</string> - <string name="debug_build">зборка для адладкі</string> - <string name="official_build">афіцыйная зборка</string> - <string name="make_selection_inline">Скапіяваць у профіль</string> - <string name="crashdump">Справаздача пра паданне</string> - <string name="add">Дадаць</string> - <string name="send_config">Адправіць канфігурацыйны файл</string> - <string name="complete_dn">Поўнае DN</string> - <string name="remotetlsnote">Імпартаваная канфігурацыя выкарыстоўвае САСТАРЭЛУЮ опцыю tls-remote, якая мае іншы фармат DN.</string> - <string name="rdn">RDN (поўнае імя)</string> - <string name="rdn_prefix">Прэфікс RDN</string> - <string name="tls_remote_deprecated">tls-remote (САСТАРЭЛАЕ)</string> - <string name="help_translate">Вы можаце палепшыць пераклад, наведаўшы http://crowdin.net/project/ics-openvpn/invite</string> - <string name="prompt">%1$s спрабуе кіраваць %2$s</string> - <string name="remote_warning">Працягваючы, вы даяце дадатку права на кіраванне \"OpenVPN для Android\" і перахоп усяго сеткавага трафіка. <b> Не працягвайце, калі не давяраеце цалкам гэтаму дадатку. </b> У адваротным выпадку вы рызыкуеце збегам і выкарыстаннем вашых дадзеных злачынцамі.</string> - <string name="remote_trust">Я давяраю гэтаму дадатку.</string> - <string name="no_external_app_allowed">Нет приложений, авторизованных для внешнего API</string> - <string name="allowed_apps">Дазволеныя дадаткі: %s</string> - <string name="clearappsdialog">Ачысціць спіс аўтарызаваных вонкавых дадаткаў?\nСпіс дазволеных дадаткаў:\n\n%s</string> - <string name="screenoff_summary">Приостанавливать VPN, если экран выключен и передано меньше 64kb данных за 60 сек. Когда включена опция \"Постоянный туннель\", приостановка VPN оставит ваше устройство без сетевого подключения. Без опции \"Постоянный туннель\" устройство не будет иметь VPN-соединения/защиты.</string> - <string name="screenoff_title">Прыпыніць VPN-злучэнне пры вымкнутым экране</string> - <string name="screenoff_pause">Прыпыненне злучэння пры вымкнутым экране: менш, чым %1$s за %2$sс</string> - <string name="screen_nopersistenttun">Увага: Заўсёдны тунэль не ўключаны для гэтага VPN. Трафік будзе скарыстаць звычайнае інтэрнэт злучэнне, калі экран вымкнуты.</string> - <string name="save_password">Захаваць пароль</string> - <string name="pauseVPN">Прыпыніць VPN</string> - <string name="resumevpn">Працягнуць VPN</string> - <string name="state_userpause">VPN прыпынены па запыце карыстача</string> - <string name="state_screenoff">VPN прыпынены - вымк. экран</string> - <string name="device_specific">Хакі для дадзенай прылады</string> - <string name="cannotparsecert">Не атрымоўваецца адлюстраваць звесткі пра сертыфікат</string> - <string name="appbehaviour">Паводзіны дадатку</string> - <string name="vpnbehaviour">Паводзіны VPN</string> - <string name="allow_vpn_changes">Дазволіць змену профіляў VPN</string> - <string name="hwkeychain">Апаратнае сховішча ключоў:</string> - <string name="permission_icon_app">Абразок дадатку спрабуе скарыстаць OpenVPN для Android</string> - <string name="faq_vpndialog43">"Пачынаючы з Android 4.3, дыялог пацверджання VPN-злучэння абаронены ад дадаткаў, «што накладаюцца паўзверх экрана». Гэта прыводзіць да таго, што дыялогавае акно пацверджання не рэагуе на сэнсорныя націскі. Калі вам трапіцца дадатак, што выкарыстоўвае накладанні і выклікае такія паводзіны, звяжыцеся з аўтарам гэтага дадаткі. Гэта праблема закранае ўсе VPN дадаткі на Android 4.3 і пазнейшых версіях. Гледзіце таксама <a href=\"https://github.com/schwabe/ics-openvpn/issues/185\">Issue 185<a> для атрымання дадатковых звестак"</string> - <string name="faq_vpndialog43_title">Акно пацверджання VPN для Android 4.3 і пазней</string> - <string name="donatePlayStore">Таксама Вы можаце выказаць падзяку ў выглядзе ахвяравання на Краме Play:</string> - <string name="thanks_for_donation">Дзякуй за ахвяраванне %s!</string> - <string name="logCleared">Журнал вычышчаны.</string> - <string name="show_password">Паказаць пароль</string> - <string name="keyChainAccessError">памылка пры доступе да сховішча ключоў: %s</string> - <string name="timestamp_short">Коратка</string> - <string name="timestamp_iso">ISO</string> - <string name="timestamps">Час</string> - <string name="timestamps_none">Не</string> - <string name="uploaded_data">Выгружана</string> - <string name="downloaded_data">Загружана</string> - <string name="vpn_status">Статус VPN</string> - <string name="logview_options">Налады выгляду</string> - <string name="unhandled_exception">Неапазнаная памылка: %1$s\n\n%2$s</string> - <string name="unhandled_exception_context">%3$s: %1$s\n\n%2$s</string> - <string name="faq_system_dialog_xposed">Калі на вашай прыладзе ёсць root, можаце ўсталяваць <a href=\"http://xposed.info/\">Xposed framework</a> і <a href=\"http://repo.xposed.info/module/de.blinkt.vpndialogxposed\">модуль аўтаматычнага пацверджання дыялогу падлучэння VPN</a> на свой страх і рызык</string> - <string name="full_licenses">Поўныя тэксты ліцэнзій</string> - <string name="blocklocal_summary">Сеткі, даступныя наўпрост праз лакальны інтэрфейс, не будуць маршрутызаваны праз VPN. Адключыце гэту опцыю, каб скіраваць трафік праз VPN.</string> - <string name="blocklocal_title">Не выкарыстоўваць VPN для лакальных адрасоў</string> - <string name="userpw_file">Файл логіна і пароля</string> - <string name="imported_from_file">[Імпартавана з: %s]</string> - <string name="files_missing_hint">Некоторые файлы не найдены. Выберите файлы для импорта в профиль:</string> - <string name="openvpn_is_no_free_vpn">Для выкарыстання дадзенага дадатку патрэбен правайдар/шлюз VPN, што падтрымвае OpenVPN (часта падаецца працадаўцам). На http://community.openvpn.net/ можна знайсці інфармацыю пра OpenVPN і як наладзіць уласны сервер OpenVPN.</string> - <string name="import_log">Лог імпарту:</string> - <string name="ip_looks_like_subnet">Указана тапалогія VPN «%3$s», але ifconfig %1$s %2$s больш падобна на IP-адрас з маскай сеткі. Выкарыстоўваецца тапалогія «падсетка».</string> - <string name="mssfix_invalid_value">Значэнне, што перазапісвае MSS, павінна быць цэлым лікам ад 0 да 9000</string> - <string name="mtu_invalid_value">Значэнне, пяравызначальнае MTU, павінна быць цэлым лікам ад 64 да 9000</string> - <string name="mssfix_value_dialog">Абвясціць TCP сесіям, што працуюць праз тунэль, што яны павінны абмежаваць памер сваіх пакетаў так, каб пасля іх інкапсуляцыі OpenVPN выніковы памер UDP-пакета, які OpenVPN пасылае сваім балям, не перавышаў гэты лік байт. (1450 па змаўчанні)</string> - <string name="mssfix_checkbox">Перавызначыць MSS для нагрузкі TCP</string> - <string name="mssfix_dialogtitle">Задаць MSS для нагрузкі TCP</string> - <string name="client_behaviour">Паводзіны кліента</string> - <string name="clear_external_apps">Ачысціць дазволеныя знешнія дадаткі</string> - <string name="loading">Загружаецца…</string> - <string name="allowed_vpn_apps_info">Дазволеныя дадаткі VPN: %1$s</string> - <string name="disallowed_vpn_apps_info">Забароненыя дадаткі VPN: %1$s</string> - <string name="app_no_longer_exists">Пакет %s больш не ўсталяваны, ён падаляецца са спіса дазволеных/забароненых дадаткаў</string> - <string name="vpn_disallow_radio">Выкарыстоўваць VPN для ўсіх дадаткаў, апроч абраных</string> - <string name="vpn_allow_radio">Выкарыстоўваць VPN толькі для абраных дадаткаў</string> - <string name="query_delete_remote">Прыбраць запіс выдаленага сервера?</string> - <string name="keep">Захаваць</string> - <string name="delete">Выдаліць</string> - <string name="add_remote">Дадаць новую падаленку</string> - <string name="remote_random">Выкарыстоўваць спіс падлучэнняў у выпадковым парадку пры злучэнні</string> - <string name="remote_no_server_selected">Вы павінны вызначыць і ўключыць прынамсі адзін выдалены сервер.</string> - <string name="server_list">Спіс сервераў</string> - <string name="vpn_allowed_apps">Дазволеныя дадаткі</string> - <string name="payload_options">Налады карыснай нагрузкі</string> - <string name="tls_settings">Налады TLS</string> - <string name="no_remote_defined">Няма зададзенай падаленкі</string> - <string name="duplicate_vpn">Дубляваць профіль VPN</string> - <string name="duplicate_profile_title">Дубляванне профілю: %s</string> - <string name="show_log">Паказаць акно журнала</string> - <string name="faq_android_clients">Існуюць розныя кліенты OpenVPN для Android. Самыя пашыраныя — OpenVPN для Android (гэты кліент), OpenVPN Connect і OpenVPN Settings.<p>Кліенты можна падзяліць на дзве групы: OpenVPN для Android і OpenVPN Connect скарыстаюць афіцыйны VPNService API (Android 4.0+) і не патрабуюць root-доступ, і OpenVPN Settings, які патрабуе root.<p>OpenVPN для Android — кліент з адкрытым зыходным кодам, які распрацаваў Arne Schwabe. Ён прызначаны для больш за доследных карыстачоў і падае шмат налад, магчымасць імпарту профіляў з файлаў і наладжваць/змяняць профілі ўсярэдзіне дадатку. Гэты кліент заснаваны на грамадскай версіі OpenVPN. А менавіта на выточным кодзе OpenVPN 2.x. Гэты кліент можна ўявіць як напаўафіцыйны кліент супольнасці. <p>OpenVPN Connect — кліент з зачыненым зыходным кодам, які распрацоўваецца OpenVPN Technologies, Inc. Ён закліканы для звычайнага выкарыстання і прызначаны для простых карыстачоў, і дазваляе імпартаваць профілі з OpenVPN. Гэты кліент заснаваны на OpenVPN C++, іншай рэалізацыі пратакола OpenVPN (Гэта запатрабавалася OpenVPN Technologies, Inc, каб апублікаваць дадатак OpenVPN на iOS). Гэты кліент — афіцыйны кліент OpenVPN technologies <p> OpenVPN Settings — найстары з кліентаў, ён таксама UI для OpenVPN з адкрытым зыходным кодам. У адрозненне ад OpenVPN для Android, ён патрабуе root-правы і не выкарыстоўвае VPNService API. Ён не залежыць ад Android 4.0+</string> - <string name="faq_androids_clients_title">Адрозненні паміж кліентамі OpenVPN для Android</string> - <string name="ignore_multicast_route">Ігнаруецца мультыадрасны маршрут: %s</string> - <string name="ab_only_cidr">Android падтрымвае толькі CIDR маршруты да VPN. Бо не CIDR маршруты амаль ніколі не выкарыстоўваюцца, OpenVPN для Android будзе выкарыстоўваць /32 для не CIDR маршрутаў і выдаваць папярэджанне.</string> - <string name="ab_tethering_44">Тэтэрынг/раздача інтэрнэту працуе, калі актыўны VPN. Мадэмнае злучэнне (тэтэрынг) НЕ БУДЗЕ выкарыстоўваць VPN.</string> - <string name="ab_kitkat_mss">Раннія версіі KitKat усталёўваюць няслушнае значэнне MSS для TCP злучэнняў (#61948). Паспрабуйце ўключыць опцыю mssfix, каб абысці гэты баг.</string> - <string name="ab_proxy">Android будзе працягваць скарыстаць вашы налады проксі, паказаныя для мабільнага/Wi-Fi злучэння, калі не ўсталяваны DNS сервер. OpenVPN для Android папярэдзіць вас пра гэта ў журнале.<p>Калі VPN усталёўвае DNS сервер Android не выкарыстоўвае проксі. Для ўсталёўкі проксі для VPN злучэння няма API.</p></string> - <string name="ab_lollipop_reinstall">Приложения VPN могут перестать работать после удаления и повторной установки. Подробности см. #80074</string> - <string name="ab_not_route_to_vpn">Сканфігураваны IP-адрас кліента і IP-адраса ў яго падсеткі (паводле сеткавай маскі) не скіроўваюцца праз VPN. OpenVPN абыходзіць гэты баг, відавочна дадаючы маршрут, які адпавядае кліенцкаму IP і яго сеткавай масцы</string> - <string name="ab_persist_tun">Адкрыццё тунэля, калі тунэль ужо актыўны, для яго нязменнага ўтрымання, можа прывесці да памылкі і VPNServices зачыніцца на прыладзе. Для аднаўлення працы VPN патрабуецца перазагрузка. OpenVPN для Android спрабуе ўнікнуць усталёўкі другога тунэля, і калі сапраўды патрэбна - спачатку зачыняе бягучы тунэль, перад адкрыццём новага, каб пазбегнуць краху праграмы. Гэта можа прывесці да маленькага інтэрвалу, у якім перадача пакетаў адбываецца па звычайным (не VPN) злучэнню. Нават з гэтымі хітрыкамі VPNServices часам падае і патрабуе перазагрузкі прылады.</string> - <string name="ab_secondary_users">VPN зусім не працуе для другасных карыстачоў.</string> - <string name="ab_kitkat_reconnect">"Розныя карыстачы паведамляюць, што мабільная сувязь/мабільная перадача дадзеных часта абрываецца, калі выкарыстоўваецца VPN дадатак. Такія паводзіны, здаецца, закранае толькі некаторыя камбінацыі правайдараў/прылад, і пакуль што не выяўлена прычына/няма абыходу гэтага бага."</string> - <string name="ab_vpn_reachability_44">Адрасы могуць працаваць праз VPN толькі тыя, што даступныя без VPN. IPv6 VPN не працуюць зусім.</string> - <string name="ab_only_cidr_title">Не CIDR маршруты</string> - <string name="ab_proxy_title">Паводзіны проксі для VPN</string> - <string name="ab_lollipop_reinstall_title">Пераўсталяванне дадаткаў VPN</string> - <string name="version_upto">%s і раней</string> - <string name="copy_of_profile">Копія %s</string> - <string name="ab_not_route_to_vpn_title">Маршрут для ўсталяванага IP-адраса</string> - <string name="ab_kitkat_mss_title">Няслушнае значэнне MSS для VPN злучэння</string> - <string name="ab_secondary_users_title">Дадатковыя карыстачы прылады</string> - <string name="custom_connection_options_warng">Вызначце асаблівыя карыстальніцкія параметры падключэння. Выкарыстоўвайце з асцярожнасцю</string> - <string name="custom_connection_options">Карыстальніцкія параметры</string> - <string name="remove_connection_entry">Выдаліць запіс падключэння</string> - <string name="ab_kitkat_reconnect_title">Выпадковыя адключэнні ад мабільнай сеткі</string> - <string name="ab_vpn_reachability_44_title">Падаленыя сеткі недаступныя</string> - <string name="ab_persist_tun_title">Прымусовы рэжым tun</string> - <string name="version_and_later">%s і вышэй</string> - <string name="tls_cipher_alert_title">Няўдалае злучэнне з SSL23_GET_SERVER_HELLO:sslv3 alert handshake failure</string> - <string name="tls_cipher_alert">Новыя версіі OpenVPN для Android (0.6.29/Сакавік 2015) скарыстаюць больш бяспечныя налады па змаўчанні для дазволеных набораў шыфраў (tls-cipher \"DEFAULT:!EXP:!PSK:!SRP:!kRSA\"). На жаль, спыненне выкарыстання менш за бяспечныя і экспартных набораў шыфраў, а асабліва тых набораў шыфраў, што не падтрымваюць Perfect Forward Secrecy (Diffie-Hellman), прыводзіць да некаторых праблем. Звычайна гэта адбываецца з-за добранамернай, але дрэнна рэалізаванай спробы ўзмацнення бяспекі TLS шляхам усталёўкі tls-cipher на серверы ці некаторых убудаваных АС з падрэзаным SSL (прыкладам, MikroTik).\nКаб вырашыць гэту праблему, усталюеце налады tls-cipher на серверы на разумныя па змаўчанні, такія як tls-cipher \"DEFAULT:!EXP:!PSK:!SRP:!kRSA\". Каб абысці праблему на кліенту, дадайце асобную наладу tls-cipher DEFAULT у Android-кліент.</string> - <string name="message_no_user_edit">Дадзены профіль быў дададзены з вонкавага дадатку (%s) і быў адзначаны як непрыдатны да рэдагавання карыстачамі.</string> - <string name="crl_file">Спіс адкліканых сертыфікатаў</string> - <string name="service_restarted">Перазапуск сэрвісу OpenVPN (Дадатак, напэўна, упаў ці быў зачынена з-за нястачы памяці)</string> - <string name="import_config_error">Імпартаванне канфігурацыі прывяло да памылкі, немагчыма захаваць змены</string> - <string name="Search">Пошук</string> - <string name="lastdumpdate">(Апошні дамп створаны %1$d г. і %2$d х. назад (%3$s))</string> - <string name="clear_log_on_connect">Чысціць журнал пры новым злучэнні</string> - <string name="connect_timeout">Час чакання злучэння</string> - <string name="no_allowed_app">Не дададзена дазволеных дадаткаў. Дадаём сябе (%s), каб у спісе дазволеных дадаткаў быў хоць бы адзін дадатак, інакш усе дадаткі дададуцца ў спіс дазволеных</string> - <string name="query_permissions_sdcard">OpenVPN для Android можа паспрабаваць знайсці адсутныя файлы на SD-карце аўтаматычна. Націсніце на гэта паведамленне, каб атрымаць запыт на дазвол.</string> - <string name="protocol">Пратакол</string> - <string name="enabled_connection_entry">Уключана</string> - <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="permission_revoked">Дазвол VPN адкліканы АС (прыкладам, запушчана іншая праграма VPN), спыняем VPN</string> - <string name="pushpeerinfo">Адправіць інфармацыю пра ўдзельніка</string> - <string name="pushpeerinfosummary">Адправіць дадатковую інфармацыю на сервер, прыкладам, версію SSL і версію Android</string> - <string name="pw_request_dialog_title">Патрабуецца %1$s</string> - <string name="pw_request_dialog_prompt">Калі ласка, увядзіце пароль для профілю %1$s</string> - <string name="menu_use_inline_data">Ужыць убудаваныя дадзеныя</string> - <string name="export_config_chooser_title">Экспарт файла канфігурацыі</string> - <string name="missing_tlsauth">файл tls-auth адсутнічае</string> - <string name="missing_certificates">Адсутнічае сертыфікат карыстача ці файл ключа сертыфіката карыстача</string> - <string name="missing_ca_certificate">Отсутствует сертификат ЦС</string> - <string name="crl_title">Спіс адкліканых сертыфікатаў (апцыянальна)</string> - <string name="reread_log">Перачытаць (%d) элементаў лога з файла кэша лога</string> - <string name="samsung_broken">Нават нягледзячы на тое, што тэлефоны Samsung з\'яўляюцца аднымі з найболей прадаваных тэлефонаў на Android, прашыўкі Samsung таксама з\'яўляюцца і найболей праблемнымі прашыўкамі на Android. Памылкі не абмяжоўваюцца толькі працай VPN на гэтых прыладах, але многія з іх можна абысці. Далей апісаны некаторыя з гэтых памылкаў.\n\nDNS не працуе, калі сервер DNS не ў дыяпазоне VPN.\n\nНа многіх прыладах Samsung 5.x функцыя дазволеных/забароненых дадаткаў не працуе.\nНа Samsung 6.x, як паведамляецца, VPN не працуе, пакуль дадатку VPN не дазволена не эканоміць зарад батарэі.</string> - <string name="samsung_broken_title">Тэлефоны Samsung</string> - <string name="novpn_selected">Не абрана VPN.</string> - <string name="defaultvpn">VPN па змаўчанні</string> - <string name="defaultvpnsummary">VPN, які будзе выкарыстоўвацца па змаўчанні, калі гэта патрэбна. А менавіта, пры загрузцы, для «Нязменнай VPN» і для перамыкача ў «Хуткіх наладах».</string> - <string name="vpnselected">У гэты час абраны VPN: \'%s\'</string> - <string name="reconnect">Перадалучыць</string> - <string name="qs_title">Пераключэнне VPN</string> - <string name="qs_connect">Падлучыцца да %s</string> - <string name="qs_disconnect">Адключыцца ад %s</string> - <string name="connectretrymaxmessage">Увядзіце максімальны час паміж спробамі злучэння. OpenVPN будзе павольна падымаць свой час чакання пасля няўдалай спробы падлучэння да гэтага значэння. Па змаўчанні 300 сек.</string> - <string name="connectretrymaxtitle">Максімальны час паміж спробамі злучэння</string> - <string name="state_waitconnectretry">Чаканне %ss секундаў паміж спробай падлучэння</string> - <string name="nought_alwayson_warning"><![CDATA[Калі дыялог пацверджання VPN не адкрыўся, то ў вас абраны іншы дадатак у «Нязменная VPN». Гэта значыць, што толькі дадзенаму дадатку дазволена падключацца да VPN. Праверце Налады -> (Сеткі) Яшчэ -> VPN]]></string> - <string name="management_socket_closed">Падключэнне да OpenVPN зачынена (%s)</string> - <string name="change_sorting">Змяніць сартаванне</string> - <string name="sort">Сартаваць</string> - <string name="sorted_lru">Профілі адсартаваны па парадку апошняга выкарыстання</string> - <string name="sorted_az">Профілі адсартаваны па назве</string> - <string name="deprecated_tls_remote">Файл налады выкарыстоўвае опцыю tls-remote, якая была абвешчана састарэлай у версіі 2.3 і канчаткова выдалена ў версіі 2.4</string> - <string name="auth_failed_behaviour">Паводзіны пры AUTH_FAILED</string> - <string name="graph">Графік</string> - <string name="use_logarithmic_scale">Выкарыстоўваць лагарыфмічную шкалу</string> - <string name="notenoughdata">Недастаткова дадзеных</string> - <string name="avghour">У сярэднім за гадзіну</string> - <string name="avgmin">У сярэднім за хвіліну</string> - <string name="last5minutes">Апошнія 5 хвілін</string> - <string name="data_in">Уваходны</string> - <string name="data_out">Выходны</string> - <string name="bits_per_second">%.0f біт/с</string> - <string name="kbits_per_second">%.1f Кбіт/с</string> - <string name="mbits_per_second">%.1f Мбіт/с</string> - <string name="gbits_per_second">%.1f Гбіт/с</string> - <string name="weakmd"><p> Пачынаючы з OpenSSL версіі 1.1, OpenSSL адхіляе слабыя подпісы ў такіх сертыфікатах, як MD5.</p><p><b>MD5, подпісы цалкам небяспечныя і больш не павінны выкарыстоўвацца.</b> Сутыкненні MD5 могуць быць створаны ў <a - href=\"https://natmchugh.blogspot.de/2015/02/create-your-own-md5-collisions.html\"> праз некалькі гадзін з мінімальнымі выдаткамі.</a>. Вы павінны як мага хутчэй абнавіць сертыфікаты VPN. </p><p>На жаль, старыя дыстрыбутывы easy-rsa улучалі опцыю канфігурацыі «default_md md5». Калі вы скарыстаеце старую версію easy-rsa, абновіце яе да <a href=\"https://github.com/OpenVPN/easy-rsa/releases\">latest версіі</a>) ці зменіце md5 на sha256 і адновіце свае сертыфікаты.</p><p>Калі вы сапраўды хочаце скарыстаць старыя і пашкоджаныя сертыфікаты, скарыстайце наладжвальны параметр канфігурацыі tls-cipher «DEFAULT: @SECLEVEL = 0 \"у пашыранай канфігурацыі ці ў якасці дадатковага радка ў вашай імпартаванай канфігурацыі</p></string> - <string name="volume_byte">%.0f Б</string> - <string name="volume_kbyte">%.1f КБ</string> - <string name="volume_mbyte">%.1f МБ</string> - <string name="volume_gbyte">%.1f ГБ</string> - <string name="channel_name_background">Статыстыка падключэння</string> - <string name="channel_description_background">Бягучая статыстыка ўсталяванага злучэння OpenVPN</string> - <string name="channel_name_status">Изменение статуса соединения</string> - <string name="channel_description_status">Змены стану злучэння OpenVPN (падлучэнне, аўтэнтыфікацыя,...)</string> - <string name="weakmd_title">Слабыя (MD5) хэшы ў сігнатуры сертыфіката (SSL_CTX_use_certificate md занадта слабы)</string> - <string name="title_activity_open_sslspeed">Тэст хуткасці OpenSSL</string> - <string name="openssl_cipher_name">Імёны шыфраў OpenSSL</string> - <string name="osslspeedtest">Тэст хуткасці OpenSSL Crypto</string> - <string name="openssl_error">OpenSSL вярнуў памылку</string> - <string name="running_test">Запуск тэсту…</string> - <string name="test_algoirhtms">Тэставанне абраных алгарытмаў</string> - <string name="all_app_prompt">Вонкавы дадатак спрабуе кантраляваць %s. Дадатак, што запытвае доступ, не можа быць вызначаны. Дазвол гэтага дадатку падае доступ усім дадаткам.</string> - <string name="openvpn3_nostatickeys">Рэалізацыя OpenVPN 3 C ++ не падтрымвае статычныя ключы. Перайдзіце ў OpenVPN 2.x пад агульныя налады.</string> - <string name="openvpn3_pkcs12">Выкарыстанне файлаў PKCS12 наўпрост з дапамогай OpenVPN 3 C ++ не падтрымваецца. Імпартуйце файлы pkcs12 у сховішча ключоў Android ці заменіце OpenVPN 2.x на агульныя налады.</string> - <string name="proxy">Проксі</string> - <string name="Use_no_proxy">Нічога</string> - <string name="tor_orbot">Tor (Orbot)</string> -</resources> diff --git a/app/src/main/res/values-bg/strings.xml b/app/src/main/res/values-bg/strings.xml index b5cb2c4030786f1d742a7bfb6caea3a5f255a727..78e2c4de223bf8bb1b0db0a9dd8b6013d187872a 100644 --- a/app/src/main/res/values-bg/strings.xml +++ b/app/src/main/res/values-bg/strings.xml @@ -8,7 +8,10 @@ <string name="new_provider_uri">Име на домейна</string> <string name="username_hint">потребителско име</string> <string name="username_ask">Моля въведете потребителско име</string> + <string name="password_ask">Моля въведете вашата парола</string> <string name="password_hint">Парола</string> + <string name="password_match">Паролоте съответстват</string> + <string name="password_mismatch">Паролите не съвпадат</string> <string name="user_message">Съобщение за потребителя</string> <string name="about_fragment_title">Относно</string> <string name="login_button">Влизане</string> @@ -19,8 +22,20 @@ <string name="succesful_authentication_message">Удостоверен</string> <string name="authentication_failed_message">Проверката за самоличност е неуспешна</string> <string name="eip_status_start_pending">Започване на връзка</string> + <string name="logging_in">Влизане</string> <string name="log_fragment_title">Лог</string> + <string name="vpn_fragment_title">VPN</string> <string name="action_settings">Настройки</string> + <string name="tethering_wifi">Безжична точка за достъп</string> <string name="donate_title">Дарете</string> <string name="donate_button_donate">Дарете</string> + <string name="nav_drawer_obfuscated_connection">Използвай Бриджове</string> + <string name="gateway_selection_automatic">Автоматично</string> + <string name="log_onehop_create">Осъществяване на връзка с криптираната директория</string> + <string name="log_loading_keys">Зареждане на сертификати от достоверен източник</string> + <string name="log_circuit_create">Осъществяване на Тор верига</string> + <string name="log_done">Изпълнява се</string> + <string name="hide">Скриване</string> + <string name="advanced_settings">Разширени настройки</string> + <string name="cancel_connection">Прекъсване</string> </resources> diff --git a/app/src/main/res/values-bn/strings.xml b/app/src/main/res/values-bn/strings.xml index 3cad442f831a0e8b707c4be04fcc99b0f3cfe9b3..919717b352648835f09ba0027ab02bf7a3384a0a 100644 --- a/app/src/main/res/values-bn/strings.xml +++ b/app/src/main/res/values-bn/strings.xml @@ -3,7 +3,7 @@ <string name="retry">আবার চেষ্টা করুন</string> <string name="repository_url_text">সোর্স কোড উপলব্ধ আছে- https://0xacab.org/leap/bitmask_android</string> <string name="leap_tracker">ইস্যু ট্র্যাকার উপলব্ধ আছে- https://0xacab.org/leap/bitmask_android/issues</string> - <string name="translation_project_text">অনুবাদে স্বাগত জানাই এবং প্রশংসা করি। আমাদের Transifex প্রকল্প দেখুন- https://www.transifex.com/projects/p/bitmask-android/</string> + <string name="translation_project_text">অনুবাদে স্বাগত জানাই এবং প্রশংসা করি। আমাদের Transifex প্রকল্প দেখুন- https://www.transifex.com/projects/p/bitmask/</string> <string name="switch_provider_menu_option">সুইচ প্রদানকারী</string> <string name="info">তথ্য</string> <string name="show_connection_details">সংযোগের তথ্য দেখান</string> @@ -101,6 +101,7 @@ <string name="donate_message">LEAP দান এবং অনুদানের উপর নির্ভরশীল। আপনি যদি নিরাপদ যোগাযোগের মূল্য দেন যা ব্যবহারকারী এবং পরিষেবা সরবরাহকারী উভয়ের জন্য সহজ তবে দান করুন।</string> <string name="donate_button_remind_later">আমাকে পরে মনে করিয়ে দিবেন</string> <string name="donate_button_donate">দান করুন</string> + <string name="gateway_selection_automatic">স্বয়ংক্রিয়</string> <string name="log_onehop_create">Establishing an encrypted directory connection</string> <string name="log_loading_keys">কর্তৃপক্ষ সার্টিফিকেট লোড হচ্ছে</string> <string name="log_circuit_create">একটি টর্ক সার্কিট স্থাপন</string> diff --git a/app/src/main/res/values-br/strings.xml b/app/src/main/res/values-br/strings.xml index 7495cf96787798a3b30a14aaa7e5fafd43340841..41d378ab4fab946f7bc6cf63810232bc12d5452a 100644 --- a/app/src/main/res/values-br/strings.xml +++ b/app/src/main/res/values-br/strings.xml @@ -3,7 +3,7 @@ <string name="retry">Adklask</string> <string name="repository_url_text">Kod mammenn hegerz war https://0xacab.org/leap/bitmask_android</string> <string name="leap_tracker">Heulier kudennoù hegerz war https://0xacab.org/leap/bitmask_android/issues</string> - <string name="translation_project_text">Ouzhpenn mat e vez degemeret an troidigezhioù. Gwelet hor raktres Transifex war https://www.transifex.com/projects/p/bitmask-android/</string> + <string name="translation_project_text">Ouzhpenn mat e vez degemeret an troidigezhioù. Gwelet hor raktres Transifex war https://www.transifex.com/projects/p/bitmask/</string> <string name="switch_provider_menu_option">Pourvezer Switch</string> <string name="info">Titou</string> <string name="show_connection_details">Diskouez munudoù ar c\'hevreañ</string> @@ -92,6 +92,7 @@ <string name="donate_message">LEAP a zepand eus ar roadennoù-arc\'hant hag ar sikourioù. Roit arc\'hant hiziv mar plij ma roit un dalvoudegezh d\'ar c\'hehenterezhioù suraet aes d\'ober ganto evit an implijer fin hag ar pourvezer servijoù.</string> <string name="donate_button_remind_later">Adkas da soñj din</string> <string name="donate_button_donate">Reiñ arc\'hant</string> + <string name="gateway_selection_automatic">Emgefreek</string> <string name="log_done">O vont en-dro</string> <string name="hide">Kuzhaat</string> <string name="advanced_settings">Arventennoù araokaet</string> diff --git a/app/src/main/res/values-brx/strings.xml b/app/src/main/res/values-brx/strings.xml deleted file mode 100644 index ae595246e6127320a9d9fa18b9512d68a66de8c1..0000000000000000000000000000000000000000 --- a/app/src/main/res/values-brx/strings.xml +++ /dev/null @@ -1,7 +0,0 @@ -<?xml version='1.0' encoding='UTF-8'?> -<resources> - <string name="info">खौरां</string> - <string name="save">थिना दोन</string> - <string name="setup_error_close_button">अोंखारलां</string> - <string name="action_settings">सेटिंग्स</string> -</resources> diff --git a/app/src/main/res/values-ca/strings.xml b/app/src/main/res/values-ca/strings.xml index 0005729e4e80d7c1d272fd582081010476c747bb..d0413585bd4f633d39f90388e570db9ba2f7e19d 100644 --- a/app/src/main/res/values-ca/strings.xml +++ b/app/src/main/res/values-ca/strings.xml @@ -3,7 +3,7 @@ <string name="retry">Reintenta</string> <string name="repository_url_text">El codi font està disponible a https://0xacab.org/leap/bitmask_android</string> <string name="leap_tracker">El seguidor d\'incidències està disponible a https://0xacab.org/leap/bitmask_android/issues</string> - <string name="translation_project_text">Les traduccions són benvingudes i apreciades. Vegeu el nostre projecte Transifex a https://www.transifex.com/projects/p/bitmask-android/</string> + <string name="translation_project_text">Les traduccions són benvingudes i apreciades. Vegeu el nostre projecte Transifex a https://www.transifex.com/projects/p/bitmask/</string> <string name="switch_provider_menu_option">Canvia el proveïdor</string> <string name="info">info</string> <string name="show_connection_details">Mostra els detalls de conexió</string> @@ -148,6 +148,7 @@ <string name="version_update_error_pgp_verification">Error de verificació PGP. S\'està ignorant la baixada.</string> <string name="version_update_error">No s\'ha pogut actualitzar.</string> <string name="version_update_error_permissions">No hi ha permisos per instal·lar l\'aplicació.</string> + <string name="gateway_selection_automatic">Automàtic</string> <string name="log_onehop_create">S\'està establint una connexió xifrada amb un directori</string> <string name="log_loading_keys">S\'estan carregant els certificats d\'autoritat</string> <string name="log_circuit_create">S\'està establint un circuit Tor</string> diff --git a/app/src/main/res/values-cs/strings.xml b/app/src/main/res/values-cs/strings.xml index 96170e5d198f8042624a47922bc6e7daf211781e..b12925d74b468b6808c8b725a9fc461c37116664 100644 --- a/app/src/main/res/values-cs/strings.xml +++ b/app/src/main/res/values-cs/strings.xml @@ -29,6 +29,7 @@ <string name="error_json_exception_user_message">Zkuste znovu: Špatná odpověď serveru</string> <string name="login_button">Přihlásit</string> <string name="logout_button">Odhlásit</string> + <string name="signup_button">Registrovat</string> <string name="setup_error_title">Chyba konfigurace</string> <string name="setup_error_configure_button">Konfigurovat</string> <string name="setup_error_close_button">Odejít</string> diff --git a/app/src/main/res/values-da/plurals-icsopenvpn.xml b/app/src/main/res/values-da/plurals-icsopenvpn.xml deleted file mode 100755 index 3fb9d049691fca6f551f90f4e7797bac1ccc93a9..0000000000000000000000000000000000000000 --- a/app/src/main/res/values-da/plurals-icsopenvpn.xml +++ /dev/null @@ -1,20 +0,0 @@ -<?xml version="1.0" encoding="utf-8"?> -<!--Generated by crowdin.com--> -<resources> - <plurals name="months_left"> - <item quantity="one">En måned tilbage</item> - <item quantity="other">%d måneder tilbage</item> - </plurals> - <plurals name="days_left"> - <item quantity="one">En dag tilbage</item> - <item quantity="other">%d dage tilbage</item> - </plurals> - <plurals name="hours_left"> - <item quantity="one">En time tilbage</item> - <item quantity="other">%d timer tilbage</item> - </plurals> - <plurals name="minutes_left"> - <item quantity="one">Et minut tilbage</item> - <item quantity="other">%d minutter tilbage</item> - </plurals> -</resources> diff --git a/app/src/main/res/values-da/strings-icsopenvpn.xml b/app/src/main/res/values-da/strings-icsopenvpn.xml deleted file mode 100755 index 1b750dd92992062910591cdd8ee5b919eacaee62..0000000000000000000000000000000000000000 --- a/app/src/main/res/values-da/strings-icsopenvpn.xml +++ /dev/null @@ -1,463 +0,0 @@ -<?xml version="1.0" encoding="utf-8"?> -<!--Generated by crowdin.com--> -<!-- - ~ 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> - - <string name="address">Server Adresse:</string> - <string name="port">Server Port:</string> - <string name="location">Placering</string> - <string name="cant_read_folder">Kan ikke læse mappen</string> - <string name="select">Vælg</string> - <string name="cancel">Annuller</string> - <string name="no_data">Ingen data</string> - <string name="useLZO">LZO komprimering</string> - <string name="client_no_certificate">Intet certifikat</string> - <string name="client_certificate_title">Klientcertifikat</string> - <string name="client_key_title">Klientcertifikat nøgle</string> - <string name="client_pkcs12_title">PKCS12 fil</string> - <string name="ca_title">CA Certifikat</string> - <string name="no_certificate">Du skal vælge et certifikat</string> - <string name="copyright_guicode">Kildekode og fejl tracker findes på http://code.google.com/p/ics-openvpn/</string> - <string name="copyright_others">Dette program bruger følgende komponenter (se kildekoden for detaljer om licenserne)</string> - <string name="about">Om</string> - <string name="vpn_list_title">Profiler</string> - <string name="vpn_type">Type</string> - <string name="pkcs12pwquery">PKCS12 kodeord</string> - <string name="file_select">Vælg…</string> - <string name="file_nothing_selected">Du skal vælge en fil</string> - <string name="useTLSAuth">Brug TLS-godkendelse</string> - <string name="tls_direction">TLS retning</string> - <string name="ipv6_dialog_tile">Indtast IPv6-adresse /netmaske i CIDR format (fx 2000:dd::23/64)</string> - <string name="ipv4_dialog_title">Indtast IPv4-adresse/netmaske i CIDR format (f.eks 1.2.3.4/24)</string> - <string name="ipv4_address">IPv4-adresse</string> - <string name="ipv6_address">IPv6 adresse</string> - <string name="custom_option_warning">Angiv brugerdefinerede OpenVPN indstillinger. Benyt med forsigtighed. Bemærk også, at mange af tun relateret OpenVPN indstillinger ikke kan understøttes af VPNSettings. Hvis du syntes en vigtig indstilling mangler, så kontakt os</string> - <string name="auth_username">Brugernavn</string> - <string name="auth_pwquery">Kodeord</string> - <string name="static_keys_info">For statisk konfiguration vil TLS autentifikations nøglerne blive brugt som statiske nøgler</string> - <string name="configure_the_vpn">Konfigurer VPN</string> - <string name="menu_add_profile">Tilføj profil</string> - <string name="add_profile_name_prompt">Indtast et navn, der identificerer den nye profil</string> - <string name="duplicate_profile_name">Indtast venligst et unikt profilnavn</string> - <string name="profilename">Profilnavn</string> - <string name="no_keystore_cert_selected">Du skal vælge et bruger certifikat</string> - <string name="no_ca_cert_selected">Du skal vælge et CA-certifikat</string> - <string name="no_error_found">Ingen fejl fundet</string> - <string name="config_error_found">Fejl ved konfiguration</string> - <string name="ipv4_format_error">Fejl ved tolkning af IPv4-adresse</string> - <string name="custom_route_format_error">Fejl med den brugerdefinerede rute</string> - <string name="pw_query_hint">(efterlad tomt for forespørgsel efter efterspørgsel)</string> - <string name="vpn_shortcut">OpenVPN genvej</string> - <string name="vpn_launch_title">Opretter forbindelse til VPN…</string> - <string name="shortcut_profile_notfound">Profil angivet i genvejen ikke fundet</string> - <string name="random_host_prefix">Tilfældig værts præfiks</string> - <string name="random_host_summary">Tilføjer 6 tilfældige tegn foran værtsnavn</string> - <string name="custom_config_title">Aktiver brugerdefinerede indstillinger</string> - <string name="custom_config_summary">Angiv brugerdefinerede indstillinger. Brug med omtanke!</string> - <string name="route_rejected">Rute afvist af Android</string> - <string name="cancel_connection_long">Afbryd VPN</string> - <string name="clear_log">ryd log</string> - <string name="title_cancel">Annuller bekræftelse</string> - <string name="cancel_connection_query">Afbryd den tilsluttede VPN/annuller forbindelses forsøg?</string> - <string name="remove_vpn">Fjern VPN</string> - <string name="check_remote_tlscert">Kontrollerer om serveren bruger et certifikat med TLS Server udvidelser (--remote-CERT-tls server)</string> - <string name="check_remote_tlscert_title">Forvent TLS servercertifikat</string> - <string name="remote_tlscn_check_summary">Kontrollerer Remote Server Certificate Subject DN</string> - <string name="remote_tlscn_check_title">Kontrol af Certifikat Værtsnavn</string> - <string name="enter_tlscn_dialog">Angiv hvilket check der anvendes til at verificere det eksterne certifikat DN (e.g. C=DE, L=Paderborn, OU=Avian IP Carriers, CN=openvpn.blinkt.de)\n\nAngiv den komplette DN eller RDN (f.eks. openvpn.blinkt.de) eller et RDN-præfiks til verificering.\n\nNår der anvendes RDN-præfiks vil \"Server\" matche \"Server-1\" og \"Server-2\"\n\nEfterlades feltet tomt vil RDN tjekkes mod serverens værtsnavn.\n\nFor flere detaljer, se OpenVPN 2.3.1+ manpage\'en under —verify-x509-name</string> - <string name="enter_tlscn_title">Fjerncertifikat emne</string> - <string name="tls_key_auth">Aktiverer TLS Key-godkendelse</string> - <string name="tls_auth_file">TLS godkendelses fil</string> - <string name="pull_on_summary">Anmoder IP-adresser, ruter og tidsindstillingerne fra serveren.</string> - <string name="pull_off_summary">Ingen oplysninger anmodes fra serveren. Indstillinger skal angives nedenfor.</string> - <string name="use_pull">Pull-indstillinger</string> - <string name="dns">DNS</string> - <string name="override_dns">Tilsidesæt DNS-indstillinger fra Server</string> - <string name="dns_override_summary">Brug dine egne DNS-servere</string> - <string name="searchdomain">søgeDomæne</string> - <string name="dns1_summary">DNS-server, som skal anvendes.</string> - <string name="dns_server">DNS-server</string> - <string name="secondary_dns_message">Sekundær DNS-Server som bruges, hvis den normale DNS-serveren ikke kan nås.</string> - <string name="backup_dns">Backup DNS-server</string> - <string name="ignored_pushed_routes">Ignorer modtagne routes</string> - <string name="ignore_routes_summary">Ignorer ruter modtaget fra serveren.</string> - <string name="default_route_summary">Omdiriger al trafik over VPN\'en</string> - <string name="use_default_title">Brug standard Rute</string> - <string name="custom_route_message">Indtast brugerdefinerede ruter. Skriv kun destinationen i CIDR format. \"10.0.0.0/8 2002::/16\" vil dirigere netværkene 10.0.0.0/8 og 2002::/16 gennem VPN\'en.</string> - <string name="custom_route_message_excluded">Ruter der IKKE skal dirigeres gennem VPN\'en. Brug samme syntax som til de inkluderede ruter.</string> - <string name="custom_routes_title">Brugerdefinerede ruter</string> - <string name="custom_routes_title_excluded">Ekskluderede netværk</string> - <string name="log_verbosity_level">Log informationsniveau</string> - <string name="float_summary">Tillad bekræftede pakker fra alle IP\'er</string> - <string name="float_title">Tillad flydende server</string> - <string name="custom_options_title">Brugerdefinerede indstillinger</string> - <string name="edit_vpn">Rediger VPN-indstillinger</string> - <string name="remove_vpn_query">Fjern VPN-profilen \'%s\'?</string> - <string name="tun_error_helpful">På nogle brugerdefinerede ICS images kan rettighederne til /dev/tun være forkerte, eller tun modulet kan mangle fuldstændigt. Til CM9 images kan du prøve \"fix ejerskab\" valgmuligheden under generelle indstillinger</string> - <string name="tun_open_error">Kunne ikke åbne tun grænsefladen</string> - <string name="error">"Fejl: "</string> - <string name="clear">Tøm</string> - <string name="last_openvpn_tun_config">Åbner tun grænseflade:</string> - <string name="local_ip_info">Lokal IPv4: %1$s/%2$d IPv6: %3$s MTU: %4$d</string> - <string name="dns_server_info">DNS-Server: %1$s, Domæne: %2$s</string> - <string name="routes_info_incl">Ruter: %1$s %2$s</string> - <string name="routes_info_excl">Ekskluderede ruter: %1$s %2$s</string> - <string name="routes_debug">VpnService rute installeret: %1$s %2$s</string> - <string name="ip_not_cidr">Fik grænsfladeoplysninger %1$s og %2$s, antager at anden adresse er peer-adressen på fjernserveren. Bruger /32 netmask til lokal IP. Tilstanden givet af OpenVPN er \"%3$s\".</string> - <string name="route_not_cidr">Kan ikke forstå %1$s og %2$s som IP rute med CIDR netmask, bruger /32 som netmask.</string> - <string name="route_not_netip">Rettede rute %1$s/%2$s til %3$s/%2$s</string> - <string name="keychain_access">Kan ikke få adgang til Android Keychain Certifikater. Dette kan skyldes en firmware opdatering eller ved at gendanne en backup af app\'en/app indstillingerne. Rediger venligst VPN\'en og genvælg certifikatet under grund indstillinger for at gendanne rettighederne til at tilgå certifikatet.</string> - <string name="version_info">%1$s %2$s</string> - <string name="send_logfile">Send log fil</string> - <string name="send">Send</string> - <string name="ics_openvpn_log_file">ICS OpenVPN log fil</string> - <string name="copied_entry">Kopierede logpost til udklipsholder</string> - <string name="tap_mode">Tap-tilstand</string> - <string name="faq_tap_mode">Tap-tilstand er ikke muligt med ikke-root VPN API. Programmet kan derfor ikke tilbyde tap-understøttelse</string> - <string name="tap_faq2">Igen? Laver du sjov? Nej, tap-tilstand er virkelig ikke understøttet og det hjælper ikke at sende mig mails og spørge om det bliver understøttet.</string> - <string name="tap_faq3">En tredje gang? Man kunne faktisk skrive en tap-emulator baseret på tun der kunne tilføje layer2 information når den sender og fjerne layer2 information når det modtages. Men en sådan tap-emulator skulle også implementere ARP og muligvis en DHCP-klient. JEg kender ikke nogen der arbejder i denne retning. Kontakt mig hvis du vil begynde at programmere det.</string> - <string name="faq">OFTE STILLEDE SPØRGSMÅL</string> - <string name="copying_log_entries">Kopierer log poster</string> - <string name="faq_copying">For at kopiere en enkelt logpost skal du trykke og holde på logposten. For at kopiere/sende hele log\'en skal du bruge Send Log valgmuligheden. Brug hardware menu knappen hvis den ikke er vist i GUI\'en.</string> - <string name="faq_shortcut">Genvej til start</string> - <string name="faq_howto_shortcut">Du kan placere en genvej til at starte OpenVPN på dit skrivebord. Afhængigt af dit homescreen-program skal du enten tilføje en genvej eller et widget.</string> - <string name="no_vpn_support_image">Dit billede understøtter ikke VPNService API\'en, beklager :(</string> - <string name="encryption">Kryptering</string> - <string name="cipher_dialog_title">Angiv krypterings metode</string> - <string name="chipher_dialog_message">Angiv krypteringsalgoritmen der skal bruges af OpenVPN. Efterlad tom for at anvende standard algoritmen.</string> - <string name="auth_dialog_message">Angiv autentificeringsdigest til brug af OpenVPN. Efterlad tom for at anvende standard digest.</string> - <string name="settings_auth">Autentificering/kryptering</string> - <string name="file_explorer_tab">Stifinder</string> - <string name="inline_file_tab">Indlejret fil</string> - <string name="error_importing_file">Fejl under importering af fil</string> - <string name="import_error_message">Kunne ikke importere fil fra filsytemet</string> - <string name="inline_file_data">[[Data inline fil]]</string> - <string name="opentun_no_ipaddr">Nægter at åbne tun-enhed uden IP-information</string> - <string name="menu_import">Importér profil fra ovpn fil</string> - <string name="menu_import_short">Importér</string> - <string name="import_content_resolve_error">Kunne ikke læse profil fra import</string> - <string name="error_reading_config_file">Fejl under læsning af konfigurationsfil</string> - <string name="add_profile">tilføj profil</string> - <string name="import_could_not_open">Kunne ikke finde fil %1$s nævnt under importen af konfigurationsfil</string> - <string name="importing_config">Importering af konfigurationsfil fra kilde %1$s</string> - <string name="import_warning_custom_options">Din konfiguration havde nogle indstillingsmuligheder der ikke er knyttet til brugerinterface indstillinger. Disse indstillinger blev tilføjet som brugerdefinerede indstillingsmuligheder. De brugerdefinerede indstillinger er vist forneden:</string> - <string name="import_done">Færdig med at læse konfigurationsfil.</string> - <string name="nobind_summary">Bind ikke til lokal adresse eller port</string> - <string name="no_bind">Ingen lokal binding</string> - <string name="import_configuration_file">Importér konfigurationsfil</string> - <string name="faq_security_title">Sikkerhedsovervejelser</string> - <string name="faq_security">"Da OpenVPN er sikkerhedsfølsom er det på sin plads med nogle bemærkninger om sikkerhed. Al data på SD-kortet er usikkert af konstruktion. Alle apps kan læse fra det (f. eks. har denne app ikke behov for SD-kort rettigheder). Dette programs data kan kun læses af programmet selv. Ved at anvende Importér valgmuligheden til cacert/cert/key i fil dialogen bliver data\'en opbevaret i VPN-profilen. VPN-profilerne er kun tilgængelige for denne app. (Glem ikke at slette kopierne fra SD-kortet bagefter). Selvom de kun er tilgængelige for dette program er dataen stadig stadig ukrypteret. Ved at root\'e telefonen eller ved hjælp af andre exploits kan det være muligt at indhente dataen. Gemte passwords bliver også opbevaret ukrypteret. For pkcs12 filer er det særligt anbefalet at du importere dem til Android Keystore."</string> - <string name="import_vpn">Importér</string> - <string name="broken_image_cert_title">Fejl ved visning af certifikat-valg</string> - <string name="broken_image_cert">Fik en undtagelse ved visning af Android 4.0+ certifikat valgsdialog. Dette burde ikke ske da det er en standardfunktion i Android 4.0+. Måske er din Android ROM\'s certifikatopbevaring i stykker</string> - <string name="ipv4">IPv4</string> - <string name="ipv6">IPv6</string> - <string name="speed_waiting">Venter på statusmeddelelse…</string> - <string name="converted_profile">importeret profil</string> - <string name="converted_profile_i">importeret profil %d</string> - <string name="broken_images">Ødelagt Image</string> - <string name="broken_images_faq"><p>Official HTC-afbildning er kendte for at have et mærkelig routing-problem, som betyder, at trafikafvikling ikke sker gennem tunnelen (se også <a href=\"https://github.com/schwabe/ics-openvpn/issues/18\">Problem 18</a> i fejlsporingen.)</p><p>Ældre officielle SONY-afbildninger fra Xperia Arc S og Xperia Ray er blevet rapporteret for helt at mangle VPNService i afbildningen (se også <a href=\"https://github.com/schwabe/ics-openvpn/issues/29\">Problem 29</a> i fejlsporingen.)</p><p>På tilpassede afbildningsversioner kan tun-modulet mangle eller rettigheder for /dev/tun kan være forkerte. Visse CM9-afbildninger behøver aktivering af valgmuligheden \"Korrigér ejerskab\" under \"Enhedsspecifikke hacks\" .</p><p>Og vigtigst: Hvis din enhed har en ødelagt Android-afbildning, så rapportér venligst dette til din salgskanal. Jo flere personer, der rapporterer et problem til salgskanalen, jo større er chancen for, at problemet bliver rettet.</p></string> - <string name="pkcs12_file_encryption_key">PKCS12 fil-krypterings-nøgle</string> - <string name="private_key_password">Private Key adgangskode</string> - <string name="password">Adgangskode</string> - <string name="file_icon">fil ikon</string> - <string name="tls_authentication">TLS-autentificering/kryptering</string> - <string name="generated_config">Genereret konfiguration</string> - <string name="generalsettings">Indstillinger</string> - <string name="owner_fix_summary">Forsøger at indstille ejeren af /dev/tun til system. Nogle CM9 images skal bruge dette for at få VPNService API\'en til at virke. Kræver root.</string> - <string name="owner_fix">Ret ejerskab af /dev/tun</string> - <string name="generated_config_summary">Vis den generede OpenVPN konfigurationsfil</string> - <string name="edit_profile_title">Redigerer \"%s\"</string> - <string name="building_configration">Bygger konfiguration…</string> - <string name="netchange_summary">Hvis dette tilvalg slåes til vil det gennemtvinge en genopretning af forbindelsen hvis netværkstilstanden ændres (f.eks. WIFI til/fra mobildata)</string> - <string name="netchange">Genopret forbindelse ved ændring i netværkstilstand</string> - <string name="netstatus">Netværks status: %s</string> - <string name="extracahint">CA certifikatet fåes som regel fra Android Keystore. Angiv et seperat certifikat hvis du certifikats-verificerings-fejl.</string> - <string name="select_file">Vælg</string> - <string name="keychain_nocacert">Intet CA Certifikat fundet under søgning i Android keystore. Autentificering vil nok mislykkes.</string> - <string name="show_log_summary">Vis logvinduet ved tilslutning. Du kan altid komme til logvinduet fra notifikationen.</string> - <string name="show_log_window">Vis logvindue</string> - <string name="mobile_info">%10$s %9$s kører på %3$s %1$s (%2$s), Android %6$s (%7$s) API %4$d, ABI %5$s, (%8$s)</string> - <string name="error_rsa_sign">Fejl under signering med Android keystore nøgle %1$s: %2$s</string> - <string name="faq_system_dialogs">VPN forbindelses advarslen der fortæller dig at denne app kan aflytte al din internettrafik er pålagt af systemet for at undgå misbrug af VPNService API\'en.\nVPN-forbindelses-notifikationen (nøglesymbolet) er også pålagt af Android systemet for at signalere en aktiv VPN forbindelse. På nogle Images afspiller denne notifikation en lyd.\nAndroid introducerede system dialoger for din sikkerhed og sørgede for at de ikke kunne omgås.</string> - <string name="faq_system_dialogs_title">Forbindelsesadvarsel og notifikationslyd</string> - <string name="translationby">Dansk oversættelse af</string> - <string name="ipdns">IP og DNS</string> - <string name="basic">Grundlæggende</string> - <string name="routing">Routing</string> - <string name="obscure">Tildæk OpenVPN indstillinger. Normalt ikke nødvendigt.</string> - <string name="advanced">Avanceret</string> - <string name="export_config_title">ICS OpenVPN konfiguration</string> - <string name="warn_no_dns">Der anvendes ingen DNS server. Name resolution vil muligvis ikke fungere. Overvej at indstille brugerdefinerede DNS servere. Bemærk også at Android vil fortsætte med at anvende de proxy-indstillinger specificeret i din mobil/WI-FI forbindelse når der ikke er indstillet nogen DNS servere.</string> - <string name="dns_add_error">Kunne ikke tilføje DNS server \"%1$s\", afvist af systemet: %2$s</string> - <string name="ip_add_error">Kunne ikke indstille IP adresse \"%1$s\", afvist af systemet: %2$s</string> - <string name="faq_howto"><>Skaf en funktionel konfiguration (testet den på din computer eller downloadet fra din udbyder/organisation)</p><p>Hvis det er en enkelt fil uden ekstra pem/pkcs12 filer kan du e-maile den til dig selv og åbne vedhæftningen. Hvis du har flere filer kan du putte dem på dit sd-kort.</p><p>Klik på e-mailvedhæftningen/Brug mappe ikonet i VPN-listen for at importere konfigurationsfilen</p><p>Hvis der kommer fejlmeddelelser om manglende filer kan du placere de manglende filer på dit sd-kort.</p><p>Klik på gem symbolet for at tilføje den importerede VPN til din VPN-liste</p><p>Forbind til VPN\'en ved at klikke på dens navn</p><p>Hvis der er fejl eller advarsler i loggen så prøv at forstå adverslerne/fejlene og prøv at fikse dem</p> </string> - <string name="faq_howto_title">Hurtig start</string> - <string name="setting_loadtun_summary">Prøv at indlæse tun.ko kernel-modulet før du forsøger at forbinde. Kræver enheden er rootet.</string> - <string name="setting_loadtun">Indlæs tun-modul</string> - <string name="importpkcs12fromconfig">Importer pkcs12 fra konfigurationen til Android Keystore</string> - <string name="getproxy_error">Fejl under indlæsning af proxy-indstillinger: %s</string> - <string name="using_proxy">Anvender proxy %1$s %2$s</string> - <string name="use_system_proxy">Anvend system-proxy</string> - <string name="use_system_proxy_summary">Anvend systemets globale konfiguration til forbindelse af HTTP/HTTPS proxy\'er.</string> - <string name="onbootrestartsummary">OpenVPN vil forbinde til den angivne VPN hvis den var aktiv under system opstart. Læs venligst forbindelses advarsel FAQ før du bruger demme valgmulighed på Android < 5.0.</string> - <string name="onbootrestart">Forbind ved opstart</string> - <string name="ignore">Ignorer</string> - <string name="restart">Genstart</string> - <string name="restart_vpn_after_change">Konfigurationsændringer træder i kræft efter VPN\'en genstartes. (Gen)start VPN\'en nu?</string> - <string name="configuration_changed">Konfiguration ændret</string> - <string name="log_no_last_vpn">Kunne ikke bestemme den sidst forbundne profil til redigering</string> - <string name="faq_duplicate_notification_title">Duplikerede notifikationer</string> - <string name="faq_duplicate_notification">Hvis Androids system hukommelse (RAM) er under pres, vil apps og tjenester der ikke bruges i øjeblikket blive fjernet fra den aktive hukommelse. Dette afbryder den igangværende VPN-forbindelse. For at sikre at forbindelsen/OpenVPN overlever, kører tjenesten med en højere prioritet. For at køre med en højere prioritet viser programmet en notifikation. Nøgle-ikons-notifikationen bliver vist af systemet som beskrevet i det sidste FAQ indlæg. Den tæller ikke som en notifikation med det formål at køre programmet med højere prioritet.</string> - <string name="no_vpn_profiles_defined">Ingen VPN-profil defineret.</string> - <string name="add_new_vpn_hint">Brug <img src=\"ic_menu_add\"/> ikonet for at tilføje en ny VPN</string> - <string name="vpn_import_hint">Brug <img src=\"ic_menu_archive\"/> ikonet for at importere en eksisterende (.ovpn eller .conf) profil fra dit SD-kort.</string> - <string name="faq_hint">Sørg for også at læse FAQ\'en. Der er en hurtig-start-guide.</string> - <string name="faq_routing_title">Routing/interface konfiguration</string> - <string name="faq_routing">Routing og interface konfigurationen bliver ikke gjort ved hjælp af traditionel ifconfig/route kommandoer, men ved hjælp af VPNService API\'en. Dette resulterer i en anderledes routing konfiguration end i andre styresystemer.\nKonfigurationen af VPN-forbindelsen består af IP-adressen og netværkerne der skal routes gennem interfacet. Specielt er peer partner adresser eller gateway adresser nødvendige. Særlige ruter til at nå VPN-serveren (for eksempel tilføjet når der anvendes redirect-gateway) er heller ikke nødvendige. Programmet vil konsekvent ignorere disse indstillinger når det importere en konfiguration. App\'en sikre ved hjælp af VPNService API\'en at forbindelsen til serveren ikke bliver routet gennem VPN-forbindelsen.\nVPNService API\'en tillader ikke at specificere netværk der ikke skal routes gennem VPN\'en. For at arbejde sig udenom denne begrænsning prøver denne app at finde netværk der ikke skal routes gennem forbindelsen (f.eks. route x.x.x.x y.y.y.y net_gateway) and udregner et sæt ruter der ekskludere disse ruter for at efterligne adfæren på andre platforme. Logvinduet viser konfigurationen af VPNService ved etablering af en forbindelse.\nBag kulissen: Android 4.4+ bruger policy routing. Anvendes route/ifconfig vil det ikke vise de installerede ruter. Brug i stedet IP-reglen, iptables -t mangle -L</string> - <string name="persisttun_summary">Fald ikke tilbage på VPN-løs forbindelse når OpenVPN genforbinder.</string> - <string name="persistent_tun_title">Vedvarende tun</string> - <string name="openvpn_log">OpenVPN log</string> - <string name="import_config">Importér OpenVPN konfiguration</string> - <string name="battery_consumption_title">Batteriforbrug</string> - <string name="baterry_consumption">I mine personlige tests er hovedårsagen til OpenVPNs høje batteriforbrug keepalive-pakker. De fleste OpenVPN-servere har en konfigurationsregel såsom \'keepalive 10 60\', som får klienten og serveren til at udveksle keepalive-pakker hvert tiende sekund. <p> Selvom disse pakker er små og ikke udgør megen trafik, holder de mobilradioenetværk beskæftiget og øger dermed strømforbruget (se evt. <a href=\"http://developer.android.com/training/efficient-downloads/efficient-network-access.html#RadioStateMachine\"> Radio State Machine | Android Developers</a>) <p>. Denne keepalive-indstilling kan ikke ændres på klienten, men kun systemadministratoren for OpenVPN kan ændre denne. <p> Ved at benytte et keepalive-niveau længere end 60 sekunder med UDP kan visse NAT-gateways droppe forbindelsen grundet en inaktivitets-timeout. Brug af TCP med en høj keepalive-tid fungerer, men tunnelering af TCP over TCP udviser en ekstrem ringe ydelse på forbindelser med højt pakketab (se <a href=\"http://sites.inka.de/bigred/devel/tcp-tcp.html\">Why TCP over TCP is a bad idea</a>).</string> - <string name="faq_tethering">Funktionen Android Tethering (via Wi.Fi, USB eller Bluetooth) og VPN-tjeneste-API\'et (som benyttes af denne app) fungerer ikke sammen. For yderligere oplysninger, se venligst <a href=\"https://github.com/schwabe/ics-openvpn/issues/34\">problem #34</a></string> - <string name="vpn_tethering_title">VPN og Tethering</string> - <string name="connection_retries">Forbindelses-forsøg</string> - <string name="reconnection_settings">Gentilslutningindstillinger</string> - <string name="connectretrymessage">Antal sekunder at vente mellem forbindelsesforsøg.</string> - <string name="connectretrywait">Sekunder mellem forbindelser</string> - <string name="minidump_generated">OpenVPN gik uventet ned. Overvej venligst at benytte muligheden Send Minidump i hovedmenuen</string> - <string name="send_minidump">Send Minidump til udvikler</string> - <string name="send_minidump_summary">Sender fejlsøgningsinfo om seneste nedbrud til udvikler</string> - <string name="notifcation_title">OpenVPN - %s</string> - <string name="session_ipv4string">%1$s - %2$s</string> - <string name="session_ipv6string">%1$s - %3$s, %2$s</string> - <string name="state_connecting">Tilslutning</string> - <string name="state_wait">Afventer serversvar</string> - <string name="state_auth">Godkender</string> - <string name="state_get_config">Henter klientkonfiguration</string> - <string name="state_assign_ip">Tildele IP-adresser</string> - <string name="state_add_routes">Tilføjer ruter</string> - <string name="state_connected">Tilsluttet</string> - <string name="state_disconnected">Afbryd</string> - <string name="state_reconnecting">Gentilslutter</string> - <string name="state_exiting">Afslutter</string> - <string name="state_noprocess">Kører ikke</string> - <string name="state_resolve">Opløser værtsnavne</string> - <string name="state_tcp_connect">Tilslutter (TCP)</string> - <string name="state_auth_failed">Godkendelse mislykkedes</string> - <string name="state_nonetwork">Afventer anvendeligt netværk</string> - <string name="statusline_bytecount">↓%2$s %1$s - ↑%4$s %3$s</string> - <string name="notifcation_title_notconnect">Ikke tilsluttet</string> - <string name="start_vpn_title">Forbinder til VPN %s</string> - <string name="start_vpn_ticker">Forbinder til VPN %s</string> - <string name="jelly_keystore_alphanumeric_bug">Nogle versioner af Android 4.1 har problemer, hvis navnet på keystore-certifikatet indeholder ikke-alfanumeriske tegn (som mellemrum, understregninger eller bindestreger). Prøv at genimportere certifikatet uden specialtegn</string> - <string name="encryption_cipher">Krypteringsstreng</string> - <string name="packet_auth">Pakkegodkendelse</string> - <string name="auth_dialog_title">Angiv pakkegodkendelsesmetode</string> - <string name="built_by">bygget af %s</string> - <string name="debug_build">fejlfindingskompilering</string> - <string name="official_build">officiel kompilering</string> - <string name="make_selection_inline">Kopiér til profil</string> - <string name="crashdump">Nedbruds-dump</string> - <string name="add">Tilføj</string> - <string name="send_config">Send opsætningsfil</string> - <string name="complete_dn">Komplet DN</string> - <string name="remotetlsnote">Din importerede konfiguration benytter den gamle DEPRECATED TLS-remote funktion, der benytter et andet DN-format.</string> - <string name="rdn">RDN (almindeligt navn)</string> - <string name="rdn_prefix">RDN-præfiks</string> - <string name="tls_remote_deprecated">TLS-REMOTE (forældet)</string> - <string name="help_translate">Du kan hjælpe med at oversætte ved at gå ind på http://crowdin.net/project/ics-openvpn/invite</string> - <string name="prompt">%1$s forsøger at styre %2$s</string> - <string name="remote_warning">Ved at fortsætte giver du programmet rettighed til at tage komplet kontrol over OpenVPN til Android og til at opsnappe al netværkstrafik.<b>Accepter IKKE medmindre du har tillid til programmet.</b> Ellers løber du risikoen for at få din data kompromiteret af ondsindet software.</string> - <string name="remote_trust">Jeg har tillid til dette program.</string> - <string name="no_external_app_allowed">Ingen app har lov til at anvende ekstern API</string> - <string name="allowed_apps">Tilladte apps: %s</string> - <string name="clearappsdialog">Ryd liste over tilladte eksterne apps?\nNuværende liste over tilladte apps:\n\n%s</string> - <string name="screenoff_summary">Sæt VPN-forbindelsen på pause når skærmen er slukket og mindre end 64 kB data er blevet overført de sidste 60 sekunder. Når \"Vedvarende Tun\" indstillingen er slået til, vil din enhed ikke have forbindelse til netværket når VPN\'en er sat på pause. Uden \"Vedvarende Tun\" indstillingen til enheden ikke have nogen VPN forbindelse/beskyttelse.</string> - <string name="screenoff_title">Sæt VPN-forbindelsen på pause efter skærmen slukkes</string> - <string name="screenoff_pause">Sæt VPN-forbindelsen på pause i slukket-skræm tilstand: Mindre end %1$s på %2$ss</string> - <string name="screen_nopersistenttun">Advarsel: Vedvarende Tun er ikke slået til på denne VPN. Internettrafik vil anvende den normale internetforbindelse når skærmen er slukket.</string> - <string name="save_password">Gem adgangskode</string> - <string name="pauseVPN">Pause VPN</string> - <string name="resumevpn">Genoptag VPN</string> - <string name="state_userpause">VPN pauset af bruger</string> - <string name="state_screenoff">VPN-forbindelsen på pause - Skærmen slukket</string> - <string name="device_specific">Enheds-specifikke hacks</string> - <string name="cannotparsecert">Kan ikke vise certifikatsinformation</string> - <string name="appbehaviour">Program opførsel</string> - <string name="vpnbehaviour">VPN opførsel</string> - <string name="allow_vpn_changes">Tillad ændringer til VPN-profiler</string> - <string name="hwkeychain">Hardware keystore:</string> - <string name="permission_icon_app">En app prøver at bruge OpenVPN til Androids ikon</string> - <string name="faq_vpndialog43">"Fra og med Android 4.3 er VPN-bekræftelsen beskyttet mod \"overlejrede apps\". Dette resulterer i, at dialogen ikke reagerer på berøringsinput. Har du en app, der benytter overlejring, kan det forårsage denne adfærd. Finder du en app, der overtrædende overlejringsbeskyttelsen, skal du kontakte app-udvikleren. Problemet påvirker alle VPN-apps på Android 4.3 og senere. Se også <a href=\"https://github.com/schwabe/ics-openvpn/issues/185\">Issue 185<a> for yderligere oplysninger"</string> - <string name="faq_vpndialog43_title">VPN bekræftelses dialog</string> - <string name="donatePlayStore">Alternativt kan du sende mig en donation med Play Butik:</string> - <string name="thanks_for_donation">Tak for donationen %s!</string> - <string name="logCleared">Log ryddet.</string> - <string name="show_password">Vis adgangskode</string> - <string name="keyChainAccessError">KeyChain adgangsfejl: %s</string> - <string name="timestamp_short">Kort</string> - <string name="timestamp_iso">ISO</string> - <string name="timestamps">Tidsstempler</string> - <string name="timestamps_none">Ingen</string> - <string name="uploaded_data">Upload</string> - <string name="downloaded_data">Download</string> - <string name="vpn_status">VPN status</string> - <string name="logview_options">Indstillinger for visning</string> - <string name="unhandled_exception">Ubehandlet undtagelse: %1$s\n\n%2$s</string> - <string name="unhandled_exception_context">%3$s: %1$s\n\n%2$s</string> - <string name="faq_system_dialog_xposed">Hvis du har rootet din androidenhed kan du installere <a href=\"http://xposed.info/\">Xposed framework</a> og <a href=\"http://repo.xposed.info/module/de.blinkt.vpndialogxposed\">VPN Dialog confirm module</a> på din egen risiko</string> - <string name="full_licenses">Fulde licenser</string> - <string name="blocklocal_summary">Netværk forbundet direkte til det lokale interface vil ikke blive dirigeret gennem VPN\'en. Fravælges denne indstilling vil alt trafik til lokale netværk dirigeres gennem VPN\'en.</string> - <string name="blocklocal_title">Undgå brug af VPN for lokale netværk</string> - <string name="userpw_file">Brugernavn/password fil</string> - <string name="imported_from_file">[Importeret fra: %s]</string> - <string name="files_missing_hint">Nogle filer kunne ikke findes. Vælg venligst filerne for at importere profilen:</string> - <string name="openvpn_is_no_free_vpn">For at anvende denne app skal du bruge en VPN udbydder/VPN gateway der understøtter OpenVPN (som regel givet af din arbejdsgiver). Tjek http://community.openvpn.net/ for yderligere information om OpenVPN og instruktioner til at opsætte din egen OpenVPN server.</string> - <string name="import_log">Importér log:</string> - <string name="ip_looks_like_subnet">VPN topologi \"%3$s\" specificeret, men ifconfig %1$s %2$s ligner mere en IP-adresse med en netværksmaske. Antager \"subnet\" topologi.</string> - <string name="mssfix_invalid_value">MSS override-værdien skal være et heltal mellem 0 og 9000</string> - <string name="mtu_invalid_value">MTU-tilsidesættelsesværdien skal være et helt tal mellem 64 og 9000</string> - <string name="mssfix_value_dialog">Meddel TCP sessioner der kører gennem tunnelen at de skal begrænse deres sendte pakker så, efter at OpenVPN har indkapslet dem, de resulterende UDP-pakker OpenVPN sender til dets modtagere ikker bliver større end de valgte antal bytes. (standarden er 1450)</string> - <string name="mssfix_checkbox">Tilsidesæt MSS-værdi af TCP-nyttelast</string> - <string name="mssfix_dialogtitle">Opsæt MSSfor TCP-dataindhold</string> - <string name="client_behaviour">Klientadfærd</string> - <string name="clear_external_apps">Ryd tilladte eksterne apps</string> - <string name="loading">Indlæser…</string> - <string name="allowed_vpn_apps_info">Tilladte VPN-apps: %1$s</string> - <string name="disallowed_vpn_apps_info">Ikke-tilladte VPN apps: %1$s</string> - <string name="app_no_longer_exists">Pakken %s er ikke længere installeret, fjerner den fra app-listen Tilladte/Ikke-tilladte</string> - <string name="vpn_disallow_radio">VPN benyttes til alle apps, bortset fra de valgte</string> - <string name="vpn_allow_radio">VPN benyttes kun til valgte apps</string> - <string name="query_delete_remote">Fjern fjernserverangivelse?</string> - <string name="keep">Behold</string> - <string name="delete">Slet</string> - <string name="add_remote">Tilføj ny fjernserver</string> - <string name="remote_random">Benyt forbindelsesangivelser i tilfældig rækkefølge ved tilslutning</string> - <string name="remote_no_server_selected">Mindst én fjernserver skal definere og aktiveres.</string> - <string name="server_list">Serverliste</string> - <string name="vpn_allowed_apps">Tilladte apps</string> - <string name="payload_options">Dataindholdsmuligheder</string> - <string name="tls_settings">TLS-indstillinger</string> - <string name="no_remote_defined">Ingen fjernserver defineret</string> - <string name="duplicate_vpn">Duplicér VPN-profil</string> - <string name="duplicate_profile_title">Dupliceringsprofilnavn: %s</string> - <string name="show_log">Vis log</string> - <string name="faq_android_clients">Der findes flere OpenVPN-klienter til Android. De mest almindelige er OpenVPN for Android (denne klient), OpenVPN Connect og OpenVPN Settings.<p>Klienterne kan placeres i to grupper: OpenVPN for Android og OpenVPN Connect bruger den officielle VPN-tjeneste API (Android 4.0+) og kræver ingen root, og OpenVPN Settings, der benytter root.<p>OpenVPN for Android, er en open source-klient udviklet af Arne Schwabe. Den er målrettet mere avancerede brugere og tilbyder mange indstillinger og muligheden for at importere profiler fra filer samt til at konfigurere/ændre profiler i selve i app\'en. Klienten er baseret på fællesskabsversionen af OpenVPN. Den er baseret på OpenVPN 2.x-kildekoden. Denne klient kan ses som fællesskabets semi-officielle klient. <p>OpenVPN Connect er en ikke-open source-klient, der er udviklet af OpenVPN Technologies, Inc. Klienten er tildigtet generelt brug og mere målrettet den gennemsnitlige bruger og tillader import af OpenVPN-profiler. Denne klient er baseret på OpenVPN C ++ genimplementering af OpenVPN-protokollen (dette var påkrævet for at tillade OpenVPN Technologies, Inc at offentliggøre en iOS OpenVPN-app). Denne klient er den officielle klient for OpenVPN-teknologierne <p> OpenVPN Settings er den ældste af klienterne og også en brugerflade til open source OpenVPN. I modsætning til OpenVPN for Android kræver den root og benytter ikke VPN-tjeneste API. Dem afhænger ikke af Android 4.0+</string> - <string name="faq_androids_clients_title">Forskelle mellem OpenVPN Android-klienter</string> - <string name="ignore_multicast_route">Ignorerer multicast-rute: %s</string> - <string name="ab_only_cidr">Android understøtter kun CIDR-ruter til VPN. Da ikke-CIDR-ruter næsten aldrig benyttes, vil OpenVPN for Android benytte en /32 til ruter, som ikke er CIDR, og udstede en advarsel.</string> - <string name="ab_tethering_44">Tøjring fungerer, mens VPN\'en er aktiv. Den kablede forbindelse benytter IKKE VPN\'en.</string> - <string name="ab_kitkat_mss">Tidlige KitKat-versioner indstiller den forkerte MSS-værdi på TCP-forbindelser (#61948). Prøv at aktivere mssfix-indstillingen for at løse denne fejl.</string> - <string name="ab_proxy">Android vil fortsat bruge de proxyindstillinger, som er angivet til mobil/Wi-Fi-forbindelsen, når ingen DNS-servere er opsat. OpenVPN for Android vil advare dig om dette i loggen.<p>Når en VPN indstiller en DNS-server vil Android ikke benytte en proxy. Der er intet API indstilling af en proxy for en VPN-forbindelse.</p></string> - <string name="ab_lollipop_reinstall">VPN-apps stoppe muligvis med at fungere, hvis de afinstalleres og geninstalleres. Se #80074 for yderligere oplysninger</string> - <string name="ab_not_route_to_vpn">Den opsatte klient-IP og IP\'erne i netværksmasken bliver ikke sendt til VPN\'en. OpenVPN kompenserer for denne fejl ved udtrykkeligt at tilføje en rute, der korresponderer med klientens IP og dens netmaske</string> - <string name="ab_persist_tun">Åbning af en tun-enhed, mens en anden tun-enhed, der benyttes til vedvarende tun-understøttelse, er aktiv, medfører fejl i VPN-tjenesten på enheden. En genstart er nødvendig for at gøre VPN funktionel igen. OpenVPN for Android forsøger at undgå at genåbne tun-enheden, og hvis det virkelig er nødvendigt, lukkes først den nuværende TUN, inden den nye TUN-enhed åbnes for at undgå nedbrud. Dette kan medføre et kort interval, hvori pakker sendes over en ikke-VPN-forbindelse. Selv med denne løsning går VPN-tjenesten somme tider ned og kræver genstart af enheden.</string> - <string name="ab_secondary_users">VPN fungerer slet ikke for sekundære brugere.</string> - <string name="ab_kitkat_reconnect">"Flere brugere rapporterer, at mobilforbindelse/-dataforbindelse ofte droppes under brug af VPN-app\'en. Denne adfærd synes kun at påvirke visse kombinationer af mobiludbydere/enheder, og indtil nu har ingen årsag/løsning på fejlen kunnet identificeres."</string> - <string name="ab_vpn_reachability_44">Kun destinationer, der også kan nås uden VPN, kan nås via VPN. IPv6 VPN\'er virker slet ikke.</string> - <string name="ab_only_cidr_title">Ikke-CIDR-ruter</string> - <string name="ab_proxy_title">Proxy-adfærd for VPN\'er</string> - <string name="ab_lollipop_reinstall_title">Geninstallerer VPN-apps</string> - <string name="version_upto">%s og tidligere</string> - <string name="copy_of_profile">Kopi af %s</string> - <string name="ab_not_route_to_vpn_title">Rute til den konfigurerede IP-adresse</string> - <string name="ab_kitkat_mss_title">Forkert MSS-værdi for VPN-forbindelse</string> - <string name="ab_secondary_users_title">Sekundære tabletbrugere</string> - <string name="custom_connection_options_warng">Angiv tilpassede tilslutningsspecifikke indstillinger. Brug med omtanke</string> - <string name="custom_connection_options">Tilpassede indstillinger</string> - <string name="remove_connection_entry">Fjern forbindelsesindgang</string> - <string name="ab_kitkat_reconnect_title">Tilfældige afbrydelser fra mobiltnetværk</string> - <string name="ab_vpn_reachability_44_title">Eksterne netværk kan ikke nås</string> - <string name="ab_persist_tun_title">Fortsæt Tun tilstand</string> - <string name="version_and_later">%s og senere</string> - <string name="tls_cipher_alert_title">Forbindelser fejler SSL23_GET_SERVER_HELLO:sslv3 alert handshake failure</string> - <string name="tls_cipher_alert">Nyere OpenVPN for Android-versioner (0.6.29/marts 2015) benytter en mere sikker standard for de tilladte chiffer-pakker (tls-chiffer \"DEFAULT:! EXP:! PSK:! SRP:! KRSA\"). Uheldigvis afstedkommer udeladelse af de mindre sikre chiffer-pakker og eksportchiffer-pakker, især udeladelsen af chiffer-pakker, som ikke understøtter Perfect Forward Secrecy (Diffie-Hellman), visse problemer. Dette skyldes normalt et velment, men dårligt udført, forsøg på at styrke TLS-sikkerhed ved at opsætte tls-chiffer på serveren eller nogle indlejrede operativsystemer med fjernet SSL (f.eks. MikroTik).\nFor at løse dette problem bør tls-cipher-indstillinger på serverensættes til en rimelig standard såsom tls-chiffer \"DEFAULT:! EXP:! PSK:! SRP:! kRSA\". For at løse problemet på klienten kan den tilpassede indstilling tls-chiffer DEFAULT tilføjes på Android-klienten.</string> - <string name="message_no_user_edit">Denne profil er tilføjet fra en ekstern app (%s) og er blevet markeret som ikke-bruger-redigerbar.</string> - <string name="crl_file">Liste over tilbagekaldte certifikater</string> - <string name="service_restarted">Genstarter OpenVPN Service (App\'en crashede, den crashede sandsynligvis eller blev stoppet på grund a RAM overbelastning)</string> - <string name="import_config_error">Import af konfigurationsfilen gav en fejl, kan ikke gemme</string> - <string name="Search">Søg</string> - <string name="lastdumpdate">(Sidste dump er %1$d:%2$dh gammel (%3$s))</string> - <string name="clear_log_on_connect">Ryd log ved ny forbindelse</string> - <string name="connect_timeout">Forbindelses-timeout</string> - <string name="no_allowed_app">Ingen tilladt app tilføjet. Tilføjer selve appen (%s) for at have mindst én tilladt app, ellers vil alle apps være tilladte</string> - <string name="query_permissions_sdcard">OpenVPN til Android kan forsøge at finde de(n) manglende fil(er) automatisk på SD-kortet. Klik på denne besked for at starte rettighedsanmodningen.</string> - <string name="protocol">Protokol</string> - <string name="enabled_connection_entry">Aktiveret</string> - <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="permission_revoked">VPN tilladelse tilbagekaldt af styresystemet (f.eks. kan et andet VPN program være startet), stopper VPN</string> - <string name="pushpeerinfo">Modtagne Peer info</string> - <string name="pushpeerinfosummary">Send ekstra information til serveren, f.eks. SSL-version og Android-version</string> - <string name="pw_request_dialog_title">Kræver %1$s</string> - <string name="pw_request_dialog_prompt">Angiv adgangskoden for profil %1$s</string> - <string name="menu_use_inline_data">Brug inline data</string> - <string name="export_config_chooser_title">Eksporter konfigurationsfil</string> - <string name="missing_tlsauth">tls-auth-filen mangler</string> - <string name="missing_certificates">Manglende brugercertifikat eller brugercertifikat nøglefil</string> - <string name="missing_ca_certificate">Manglende CA-certifikat</string> - <string name="crl_title">Certifcate Revoke List (valgfrit)</string> - <string name="reread_log">Genlæse (%d) log-linier fra cache</string> - <string name="samsung_broken">Selv om Samsung-telefoner er blandt de mest solgte Android-telefoner, er Samsungs firmware også blandt de mest fejlagtige Android-implementationer. Fejlene er ikke begrænset til VPN-operationer på disse enheder, men mange af dem kan løses. I det følgende beskrives nogle af disse fejl. \n\nDNS virker ikke, medmindre DNS-serveren er i samme VPN-område. \n\nMed mange Samsung 5.x-enheder virker funktionen for tilladte/afviste apps ikke. \nMed Samsung 6.x rapporteres at VPN ikke fungere, medmindre VPN-appen er undtaget fra Powersave-funktioner.</string> - <string name="samsung_broken_title">Samsung telefoner</string> - <string name="novpn_selected">Ingen VPN valgt.</string> - <string name="defaultvpn">Standard VPN</string> - <string name="defaultvpnsummary">VPN bruges i situationer, hvor en standard VPN er påkrævet. Disse er i øjeblikket ved opstart, til Always-On og Quick Settings Tile.</string> - <string name="vpnselected">Aktuelt valgt VPN: \'%s\'</string> - <string name="reconnect">Gentilslutter</string> - <string name="qs_title">Skift VPN</string> - <string name="qs_connect">Opret forbindelse til %s</string> - <string name="qs_disconnect">Afbryd %s</string> - <string name="connectretrymaxmessage">Indtast den maksimale tid mellem forbindelsesforsøg. OpenVPN vil langsomt øge ventetiden efter et mislykket forbindelsesforsøg op til denne værdi. Standard er 300 sekunder.</string> - <string name="connectretrymaxtitle">Maksimal tid mellem forbindelsesforsøg</string> - <string name="state_waitconnectretry">Venter %ssekunder mellem forbindelsesforsøg</string> - <string name="nought_alwayson_warning"><![CDATA[Hvis du ikke fik en VPN-bekræftelsesdialog, har du \"Always on VPN\" aktiveret af en anden app. I så fald må kun den app forbinde til en VPN. Se under Settings-> Networks more .. -> VPNs]]></string> - <string name="management_socket_closed">Forbindelse til OpenVPN lukket (%s)</string> - <string name="change_sorting">Skift sortering</string> - <string name="sort">Sorter</string> - <string name="sorted_lru">Profiler sorteret efter senest anvendelse</string> - <string name="sorted_az">Profiler sorteret efter navn</string> - <string name="deprecated_tls_remote">Konfigurationen bruger \"tls-remote\", understøttelsen af denne er fjernet i 2.4</string> - <string name="auth_failed_behaviour">Handling ved AUTH_FAILED</string> - <string name="graph">Graf</string> - <string name="use_logarithmic_scale">Brug logaritmisk skala</string> - <string name="notenoughdata">Ikke nok data</string> - <string name="avghour">Gennemsnit pr. time</string> - <string name="avgmin">Gennemsnit pr. minut</string> - <string name="last5minutes">Sidste 5 minutter</string> - <string name="data_in">Ind</string> - <string name="data_out">Ud</string> - <string name="bits_per_second">%.0f bit/s</string> - <string name="kbits_per_second">%.1f kbit/s</string> - <string name="mbits_per_second">%.1f Mbit / s</string> - <string name="gbits_per_second">%.1f Gbit / s</string> - <string name="weakmd"><p>Startende med OpenSSL version 1.1 vil OpenSSL afvise svage signaturer i certifikater som f.eks MD5.</p><p><b>MD5 signaturer er usikre og bør ikke længere anvendes.</b> MD5 sammenfald (collisions) kan fremstilles <a - href=\"https://natmchugh.blogspot.de/2015/02/create-your-own-md5-collisions.html\"> på kort tid uden de store ressourcer.</a>. Du skal opdatere dine VPN-certifikaterne så hurtigt som muligt.</p><p>Desværre inkluderede ældre easy-rsa-distributioner config-opsætningen \"default_md md5\". Hvis du bruger en gammel easy-rsa-version, skal du opdatere til den <a href=\"https://github.com/OpenVPN/easy-rsa/releases\">seneste version</a>) eller skifte md5 til sha256 og regenerere dine certifikater.</p><p>Hvis du virkelig vil bruge gamle og usikre certifikater, skal du bruge den tilpassede konfigurationsindstilling tls-cipher \"DEFAULT: @ SECLEVEL = 0\" under avanceret konfiguration eller som ekstra linje i din importerede konfiguration</p> - </string> - <string name="volume_byte">%.0f B</string> - <string name="volume_kbyte">%.1f kB</string> - <string name="volume_mbyte">%.1f MB</string> - <string name="volume_gbyte">%.1f GB</string> - <string name="channel_name_background">Forbindelsesstatistik</string> - <string name="channel_description_background">Løbende statistikker af den etablerede OpenVPN-forbindelse</string> - <string name="channel_name_status">Forbindelses status ændring</string> - <string name="channel_description_status">Status ændringer i OpenVPN-forbindelsen (Tilslutning, godkendelse, etc)</string> - <string name="weakmd_title">Svag (MD5) hashes i certifikat signatur (SSL_CTX_use_certificate md for svag)</string> - <string name="title_activity_open_sslspeed">OpenSSL Speed Test</string> - <string name="openssl_cipher_name">OpenSSL cipher navne</string> - <string name="osslspeedtest">OpenSSL Crypto Speed test</string> - <string name="openssl_error">OpenSSL returnerede en fejl</string> - <string name="running_test">Tester ...</string> - <string name="test_algoirhtms">Test valgte algoritmer</string> - <string name="all_app_prompt">En ekstern app forsøger at styre %s. Appen, der anmoder om adgang, kan ikke bestemmes. Tillad, at denne app giver ALLE apps adgang.</string> - <string name="openvpn3_nostatickeys">OpenVPN 3 C ++ implementeringen understøtter ikke statiske nøgler. Venligst skift til OpenVPN 2.x under generelle indstillinger.</string> - <string name="openvpn3_pkcs12">Brug af PKCS12 filer direkte med OpenVPN 3 C ++ implementering understøttes ikke. Indtast venligst pkcs12-filerne i Android-keystore eller skift til OpenVPN 2.x under generelle indstillinger.</string> - <string name="proxy">Proxy</string> - <string name="Use_no_proxy">Ingen</string> - <string name="tor_orbot">Tor (Orbot)</string> -</resources> diff --git a/app/src/main/res/values-de/strings.xml b/app/src/main/res/values-de/strings.xml index 510e12c73f90841d1c341f40f254d74ef85204c6..7ead4907bd41f594cfff6933a081fa7869a62b1f 100644 --- a/app/src/main/res/values-de/strings.xml +++ b/app/src/main/res/values-de/strings.xml @@ -3,7 +3,7 @@ <string name="retry">Wiederholen</string> <string name="repository_url_text">Quelltext verfügbar unter: https://0xacab.org/leap/bitmask_android</string> <string name="leap_tracker">Fehlerticketsystem zugänglich unter https://0xacab.org/leap/bitmask_android/issues</string> - <string name="translation_project_text">Übersetzungen sind sehr willkommen. Schau dir unser Transifex Projekt unter https://www.transifex.com/projects/p/bitmask-android an.</string> + <string name="translation_project_text">Übersetzungen sind sehr willkommen. Schau dir unser Transifex Projekt unter https://www.transifex.com/projects/p/bitmask an.</string> <string name="switch_provider_menu_option">Provider wechseln</string> <string name="info">Info</string> <string name="show_connection_details">Zeige Verbindungsdetails</string> @@ -67,6 +67,9 @@ <string name="authentication_failed_message">Authentifizierung fehlgeschlagen</string> <string name="registration_failed_message">Registrierung fehlgeschlagen</string> <string name="eip_status_start_pending">Initiiere Verbindung</string> + <string name="eip_status_connecting">Verbinde VPN</string> + <string name="eip_status_unsecured">Ungesicherte Verbindung</string> + <string name="eip_status_secured">Sichere Verbindung</string> <string name="eip_cancel_connect_title">Verbindung abbrechen?</string> <string name="eip_cancel_connect_text">Es existiert ein Verbindungsversuch. Möchten Sie diesen abbrechen?</string> <string name="eip.warning.browser_inconsistency">Vpn Verbindung deaktivieren? Wenn das VPN aus ist, können persönliche Daten gegenüber deinem Internet Provider oder im lokalen Netzwerk ungeschützt sein.</string> @@ -79,7 +82,7 @@ <string name="signing_up">Am Registrieren</string> <string name="vpn.button.turn.on">Einschalten</string> <string name="vpn.button.turn.off">Ausschalten</string> - <string name="vpn_button_turn_off_blocking">Blocken beenden.</string> + <string name="vpn_button_turn_off_blocking">Blocken beenden</string> <string name="vpn_securely_routed">Dein Internetverkehr wird sicher durchgeleitet durch:</string> <string name="vpn_securely_routed_no_internet">Keine Internetverbindung vorhanden. Sobald du wieder online bist verbindest du dich automatisch mit:</string> <string name="log_fragment_title">Log</string> @@ -139,7 +142,7 @@ <string name="warning_no_more_gateways_use_pt">%s konnte sich nicht verbinden. Es kann sein, dass VPN Verkehr geblockt wird. Möchtest du versuchen, eine verschleierte Verbindung herzustellen?</string> <string name="warning_no_more_gateways_no_pt">%s konnte sich nicht verbinden. Möchtest du es noch einmal versuchen?</string> <string name="warning_no_more_gateways_use_ovpn">%s konnte keine verschleierte Verbindung herstellen. Möchtest du versuchen, eine normale VPN Verbindung herzustellen?</string> - <string name="warning_no_more_gateways_manual_gw_selection">%1$skonnte sich nicht mit %2$s verbinden. Möchtest du versuchen, dich automatisch mit dem besten Standort zu verbinden?</string> + <string name="warning_no_more_gateways_manual_gw_selection">%1$s konnte sich nicht mit %2$s verbinden. Möchtest du versuchen, dich automatisch mit dem besten Standort zu verbinden?</string> <string name="warning_option_try_best">Versuche besten Standort</string> <string name="warning_option_try_pt">Teste verschleierte Verbindung</string> <string name="warning_option_try_ovpn">Teste normale Verbindung</string> @@ -201,4 +204,6 @@ <string name="disabled_while_udp_on">Deaktiviert während UDP eingeschaltet ist</string> <string name="advanced_settings">Erweiterte Einstellungen</string> <string name="cancel_connection">Trennen</string> + <string name="unknown_location">Unbekannter Standort</string> + <string name="splash_footer">Entwickelt von: LEAP</string> </resources> diff --git a/app/src/main/res/values-el/strings.xml b/app/src/main/res/values-el/strings.xml index 6f340d084a32a3b4ca603ae6ceb27f22fca804aa..a56891e079798a58212c9ce1c801e50c5bcc2d89 100644 --- a/app/src/main/res/values-el/strings.xml +++ b/app/src/main/res/values-el/strings.xml @@ -3,7 +3,7 @@ <string name="retry">Ξαναδοκίμασε</string> <string name="repository_url_text">Ο πηγαίος κώδικας είναι διαθέσιμος στο https://0xacab.org/leap/bitmask_android</string> <string name="leap_tracker">Ο ιχνηλάτης τεχνικών θεμάτων είναι διαθέσιμος στο https://0xacab.org/leap/bitmask_android/issues</string> - <string name="translation_project_text">Κάθε βοήθεια στις μεταφράσεις είναι ευπρόσδεκτη. Δες το πρότζεκτ μας στο Transifex, στο https://www.transifex.com/projects/p/bitmask-android/</string> + <string name="translation_project_text">Οι μεταφράσεις είναι ευπρόσδεκτες. Δείτε τη σελίδα μας στο Transifex στο https://www.transifex.com/projects/p/bitmask/</string> <string name="switch_provider_menu_option">Αλλαγή παρόχου</string> <string name="info">Πληροφορίες</string> <string name="show_connection_details">Προβολή λεπτομερειών σύνδεσης</string> @@ -67,6 +67,9 @@ <string name="authentication_failed_message">Αποτυχία πιστοποίησης</string> <string name="registration_failed_message">Η εγγραφή απέτυχε</string> <string name="eip_status_start_pending">Έναρξη σύνδεσης</string> + <string name="eip_status_connecting">Σύνδεση σε VPN</string> + <string name="eip_status_unsecured">Μη ασφαλής σύνδεση</string> + <string name="eip_status_secured">Ασφαλής σύνδεση</string> <string name="eip_cancel_connect_title">Ακύρωση σύνδεσης;</string> <string name="eip_cancel_connect_text">Υπάρχει μια προσπάθεια σύνδεσης σε εξέλιξη. Θέλετε να την ακυρώσετε;</string> <string name="eip.warning.browser_inconsistency">Κλείσιμο της σύνδεσης VPN; Όταν το VPN είναι κλειστό, μπορεί να διαρρέουν προσωπικές σας πληροφορίες στον πάροχο σας ή στο τοπικό δίκτυο.</string> @@ -139,7 +142,7 @@ <string name="warning_no_more_gateways_use_pt">Το %s δεν μπόρεσε να συνδεθεί. Ίσως οι συνδέσεις VPN να μπλοκάρονται. Θέλετε να προσπαθήσετε να συνδεθείτε χρησιμοποιώντας καμουφλαρισμένες συνδέσεις;</string> <string name="warning_no_more_gateways_no_pt">Το %s δεν μπόρεσε να συνδεθεί. Θέλετε να προσπαθήσετε ξανά;</string> <string name="warning_no_more_gateways_use_ovpn">Το %s δεν μπόρεσε να συνδεθεί χρησιμοποιώντας καμουφλαρισμένες συνδέσεις VPN. Θέλετε να προσπαθήσετε να συνδεθείτε χρησιμοποιώντας ένα κανονικό VPN;</string> - <string name="warning_no_more_gateways_manual_gw_selection">Το %1$s δεν μπόρεσε να συνδεθεί στο %2$s. Θέλετε να προσπαθήσετε να συνδεθείτε αυτόματα με την καλύτερη τοποθεσία;</string> + <string name="warning_no_more_gateways_manual_gw_selection">Το %1$s δεν μπόρεσε να συνδεθεί στο %2$s. Θέλετε να δοκιμάσετε να συνδεθείτε αυτόματα με την καλύτερη τοποθεσία;</string> <string name="warning_option_try_best">Δοκιμή καλύτερης τοποθεσίας</string> <string name="warning_option_try_pt">Δοκιμή καμουφλαρισμένης σύνδεσης</string> <string name="warning_option_try_ovpn">Δοκιμή κανονικής σύνδεσης</string> @@ -201,4 +204,6 @@ <string name="disabled_while_udp_on">Απενεργοποιημένο όταν είναι ενεργό το UDP.</string> <string name="advanced_settings">Προηγμένες ρυθμίσεις</string> <string name="cancel_connection">Αποσύνδεση</string> + <string name="unknown_location">Άγνωστη τοποθεσία</string> + <string name="splash_footer">Αναπτύχθηκε από την LEAP</string> </resources> diff --git a/app/src/main/res/values-es-rAR/strings.xml b/app/src/main/res/values-es-rAR/strings.xml index d8cee3a33d6b74baa5a6bf157f0144a03899e57c..ae7d4d535f68a9cb8caa6181a4350f028761e251 100644 --- a/app/src/main/res/values-es-rAR/strings.xml +++ b/app/src/main/res/values-es-rAR/strings.xml @@ -3,7 +3,7 @@ <string name="retry">Reintentar</string> <string name="repository_url_text">Código fuente disponible en https://0xacab.org/leap/bitmask_android</string> <string name="leap_tracker">Rastreador de dificultades disponible en https://0xacab.org/leap/bitmask_android/issues</string> - <string name="translation_project_text">Traducciones son bienvenidas y apreciadas. Mirá nuestro proyecto en Transifex en https://www.transifex.com/projects/p/bitmask-android/</string> + <string name="translation_project_text">Traducciones son bienvenidas y apreciadas. Mirá nuestro proyecto en Transifex en https://www.transifex.com/projects/p/bitmask/</string> <string name="switch_provider_menu_option">Intercambiar proveedor</string> <string name="info">información</string> <string name="show_connection_details">Mostrar detalles de conexión</string> @@ -134,12 +134,13 @@ <string name="warning_exclude_apps_message">Tené cuidado de excluir aplicaciones de la VPN. Esto va a revelar tu identidad y comprometer a tu seguridad.</string> <plurals name="subtitle_exclude_apps"> <item quantity="one">%d aplicación desprotegida</item> + <item quantity="many">%d aplicaciones desprotegidas</item> <item quantity="other">%d aplicaciones desprotegidas</item> </plurals> <string name="warning_no_more_gateways_use_pt">%s no se pudo conectar. Puede ser que las conexiones al VPN estén bloqueadas. ¿Querés intentar conectar usando conexiones ofuscadas?</string> <string name="warning_no_more_gateways_no_pt">%s no se pudo conectar. ¿Querés intentarlo de nuevo?</string> <string name="warning_no_more_gateways_use_ovpn">%s no se pudo conectar al VPN usando conexiones ofuscadas. ¿Querés intentar conectar usando VPN estándar? </string> - <string name="warning_no_more_gateways_manual_gw_selection">%1$s no pudo conectarse a %2$s. ¿Querés intentar conectarte automáticamente con la mejor ubicación?</string> + <string name="warning_no_more_gateways_manual_gw_selection">%1$s no pudo conectarse a %2$s. ¿Quieres intentar conectarte automáticamente con la mejor ubicación?</string> <string name="warning_option_try_best">Intentar la mejor ubicación</string> <string name="warning_option_try_pt">Probar conexión ofuscada</string> <string name="warning_option_try_ovpn">Probar conexión estándar</string> diff --git a/app/src/main/res/values-es/strings.xml b/app/src/main/res/values-es/strings.xml index cf8e3485c65a35d9fda0992f1831dc28d7290d58..176207535ccb478cd04551768f47708b92c4a3c8 100644 --- a/app/src/main/res/values-es/strings.xml +++ b/app/src/main/res/values-es/strings.xml @@ -3,7 +3,7 @@ <string name="retry">Reintentar</string> <string name="repository_url_text">El código fuente está disponible en https://0xacab.org/leap/bitmask_android</string> <string name="leap_tracker">Rastreador de problemas disponible en https://0xacab.org/leap/bitmask_android/issues</string> - <string name="translation_project_text">Las traducciones son bienvenidas y apreciadas. Mira nuestro proyecto de Transifex en https://www.transifex.com/projects/p/bitmask-android/</string> + <string name="translation_project_text">Las traducciones son bienvenidas y apreciadas. Mira nuestro proyecto de Transifex en https://www.transifex.com/projects/p/bitmask/</string> <string name="switch_provider_menu_option">Cambiar de proveedor</string> <string name="info">información</string> <string name="show_connection_details">Mostrar detalles de la conexión</string> @@ -67,6 +67,9 @@ <string name="authentication_failed_message">Autentificación fallida</string> <string name="registration_failed_message">El registro falló.</string> <string name="eip_status_start_pending">Iniciando conexión</string> + <string name="eip_status_connecting">Conectando a VPN</string> + <string name="eip_status_unsecured">Conexión Insegura</string> + <string name="eip_status_secured">Conexión Segura</string> <string name="eip_cancel_connect_title">¿Cancelar conexión?</string> <string name="eip_cancel_connect_text">Se está intentando establecer la conexión. ¿Desea cancelarla?</string> <string name="eip.warning.browser_inconsistency">¿Desactivar la conexión VPN? Cuando la VPN está desactivada, su información personal se puede filtrar a su proveedor de Internet o red local.</string> @@ -134,6 +137,7 @@ <string name="warning_exclude_apps_message">Ten cuidado de excluir aplicaciones de la VPN. Esto revelará tu identidad y comprometerá tu seguridad.</string> <plurals name="subtitle_exclude_apps"> <item quantity="one">%d aplicación desprotegida</item> + <item quantity="many">%d aplicaciones desprotegidas</item> <item quantity="other">%d aplicaciones desprotegidas</item> </plurals> <string name="warning_no_more_gateways_use_pt">%s no se pudo conectar. Puede ser que las conexiones al VPN estén bloqueadas. ¿Quieres intentar a conectar usando conexiones ofuscadas?</string> @@ -201,4 +205,6 @@ <string name="disabled_while_udp_on">Deshabilitado mientras UDP está activado.</string> <string name="advanced_settings">Configuración avanzada</string> <string name="cancel_connection">Desconectar</string> + <string name="unknown_location">Ubicación desconocida</string> + <string name="splash_footer">Desarrollado por LEAP</string> </resources> diff --git a/app/src/main/res/values-et/strings.xml b/app/src/main/res/values-et/strings.xml index 9ec76c359f057840d388eb8e18b474dc89e801c5..91e81af14504be018d0a5ccd42708b766d007993 100644 --- a/app/src/main/res/values-et/strings.xml +++ b/app/src/main/res/values-et/strings.xml @@ -3,7 +3,8 @@ <string name="retry">Proovi uuesti</string> <string name="repository_url_text">Lähtekood saadaval aadressil https://0xacab.org/leap/bitmask_android</string> <string name="leap_tracker">Vealoend saadaval aadressil https://0xacab.org/leap/bitmask_android/issues</string> - <string name="translation_project_text">Tõlked on teretulnud ja väärtustatud. Vaata meie Transifexi projekti aadressil https://www.transifex.com/projects/p/bitmask-android/</string> + <string name="translation_project_text">Tõlked on teretulnud ja väärtustatud. Vaata meie Transifexi projekti aadressil https://www.transifex.com/projects/p/bitmask/ +</string> <string name="switch_provider_menu_option">Vaheta pakkujat</string> <string name="info">info</string> <string name="show_connection_details">Näita ühenduse andmeid</string> diff --git a/app/src/main/res/values-eu/strings.xml b/app/src/main/res/values-eu/strings.xml index 65417420793e99816dfeb909cbf9a56d4461412b..59fac074c496ec3842367703d5b906119cbcf8a2 100644 --- a/app/src/main/res/values-eu/strings.xml +++ b/app/src/main/res/values-eu/strings.xml @@ -3,7 +3,7 @@ <string name="retry">Saiatu berriro</string> <string name="repository_url_text">Kode-iturria hemen eskuragarri: https://0xacab.org/leap/bitmask_android</string> <string name="leap_tracker">Aplikazioaren akats kudeatzailea hemen eskuragarri https://0xacab.org/leap/bitmask_android/issues</string> - <string name="translation_project_text">Itzulpenak ongi etorriak eta estimatuak dira. Ikusi gure Transifex proiektua https://www.transifex.com/projects/p/bitmask-android/</string> + <string name="translation_project_text">Itzulpenak ongi etorriak eta estimatuak dira. Ikusi gure Transifex proiektua https://www.transifex.com/projects/p/bitmask/</string> <string name="switch_provider_menu_option">Aldatu hornitzailea</string> <string name="info">informazioa</string> <string name="show_connection_details">Ikusi konexio xehetasunak</string> diff --git a/app/src/main/res/values-fa-rIR/strings.xml b/app/src/main/res/values-fa-rIR/strings.xml index 22f3134655b4d943598238dba2ae92044d73210f..11fb272e30ee9de8374ec8731c5f742d1aa5d3ea 100644 --- a/app/src/main/res/values-fa-rIR/strings.xml +++ b/app/src/main/res/values-fa-rIR/strings.xml @@ -1,12 +1,13 @@ <?xml version='1.0' encoding='UTF-8'?> <resources> <string name="retry">تلاش دوباره</string> - <string name="repository_url_text">دسترسی به منبع کد در https://0xacab.org/leap/bitmask_android </string> - <string name="leap_tracker">نظرات، پیشنهادات و گزارش اشکالات در https://0xacab.org/leap/bitmask_android/issues</string> - <string name="translation_project_text">از همکاری شما برای ترجمه استقبال میکنیم. پروژه Transifex ما در اینجا ببینید: https://www.transifex.com/projects/p/bitmask-android/</string> - <string name="switch_provider_menu_option">تعویض ارائه دهنده</string> + <string name="repository_url_text">منبع کد قابل دسترس در https://0xacab.org/leap/bitmask_android </string> + <string name="leap_tracker">سامانهٔ پیگیری اشکالات قابل دسترس در https://0xacab.org/leap/bitmask_android/issues</string> + <string name="translation_project_text">از همکاری شما برای ترجمه استقبال میکنیم. پروژهٔ Transifex ما را در اینجا ببینید: +https://www.transifex.com/projects/p/bitmask/</string> + <string name="switch_provider_menu_option">تعویض ارائهدهنده</string> <string name="info">اطلاعات</string> - <string name="show_connection_details">نمایش جزئیات ارتباط</string> + <string name="show_connection_details">نمایش جزئیات اتصال</string> <string name="connection_details">جزئیات اتصال</string> <string name="routes_info">مسیرها: %s</string> <string name="routes_info6">مسیرهای IPv6: %s</string> diff --git a/app/src/main/res/values-fi/strings.xml b/app/src/main/res/values-fi/strings.xml index e88ae5c035cc97b2dcc89cfeefa686c60a72d1b4..f589a3d8452e112eb970dd7d114c1bf1180b1815 100644 --- a/app/src/main/res/values-fi/strings.xml +++ b/app/src/main/res/values-fi/strings.xml @@ -1,19 +1,28 @@ <?xml version='1.0' encoding='UTF-8'?> <resources> <string name="retry">Toista</string> + <string name="repository_url_text">Lähdekoodi saatavilla https://0xacab.org/leap/bitmask_android:ssa</string> + <string name="leap_tracker">Ongelmaseuranta saatavilla https://0xacab.org/leap/bitmask_android/issues:sta</string> + <string name="translation_project_text">Käännökset ovat tervetulleita ja arvostettuja. Katso Transifex-hankkeemme https://www.transifex.com/projects/p/bitmask/:ssa</string> <string name="switch_provider_menu_option">Vaihda palvelutarjoajaa</string> <string name="info">tiedot</string> <string name="show_connection_details">Näytä lisätiedot yhteydestä</string> + <string name="connection_details">Yhteyden yksityiskohdat</string> <string name="routes_info">Reitittää: %s</string> + <string name="routes_info6">IPv6-reitit: %s</string> <string name="error_empty_username">Käyttäjätunnus ei saa olla tyhjä.</string> + <string name="cert_from_keystore">Hanki varmenne \'%s\' avainsäilöstä</string> <string name="provider_label">Palvelutarjoaja:</string> <string name="provider_label_none">Yhtään palvelutarjoajaa ei ole asetettu</string> <string name="status_unknown">Tila tuntematon.</string> + <string name="eip_service_label">Salattu VPN:n Internet-yhteys</string> <string name="configuration_wizard_title">Valitse palvelutarjoaja</string> <string name="add_provider">Lisää uusi palvelutarjoaja</string> <string name="introduce_new_provider">Lisää uusi palvelutarjoaja</string> <string name="save">Tallenna</string> <string name="new_provider_uri">Verkkotunnusnimi</string> + <string name="valid_url_entered">URL on kelvollinen</string> + <string name="not_valid_url_entered">Väärin muotoiltu URL</string> <string name="provider_details_title">Palvelutarjoajan lisätiedot</string> <string name="use_anonymously_button">Käytä anonyymisti</string> <string name="username_hint">käyttäjätunnus</string> @@ -24,40 +33,172 @@ <string name="password_mismatch">Salasanat eivät täsmää</string> <string name="user_message">Käyttäjäviesti</string> <string name="about_fragment_title">Tietoja</string> + <string name="exclude_apps_fragment_title">Sulje sovellukset pois VPN:stä</string> + <string name="error_srp_math_error_user_message">Yritä uudelleen: palvelimen matemaattinen virhe</string> <string name="error_bad_user_password_user_message">Väärä käyttäjänimi tai salasana</string> + <string name="error_not_valid_password_user_message">Sen on oltava vähintään 8 merkkiä pitkä</string> <string name="error_client_http_user_message">Yritä uudelleen: Asiakasohjelman HTTP-virhe</string> <string name="error_io_exception_user_message">Yritä uudelleen: Siirräntävirhe</string> <string name="error_json_exception_user_message">Yritä uudelleen: Väärä vastaus palvelimelta</string> + <string name="error_no_such_algorithm_exception_user_message">Salausalgoritmia ei löydy. Päivitä Android!</string> + <string name="signup_or_login_button">Rekisteröidy Kirjaudu sisään</string> <string name="login_button">Kirjaudu</string> + <string name="login_to_profile">Kirjaudu profiiliin</string> <string name="logout_button">Kirjaudu ulos</string> <string name="signup_button">Kirjaudu</string> + <string name="create_profile">Luo profiili</string> + <string name="setup_provider">Määritä palveluntarjoaja</string> <string name="setup_error_title">Asetusvirhe</string> <string name="setup_error_configure_button">Aseta</string> <string name="setup_error_close_button">Poistu</string> + <string name="setup_error_text">Virhe määritettäessä%svalitsemasi palveluntarjoajan kanssa.\n\nVoit määrittää asetukset uudelleen tai poistua ja määrittää palveluntarjoajan seuraavan käynnistyksen yhteydessä.</string> + <string name="setup_error_text_custom"> %s:n määrittämisessä tapahtui virhe.\n\nVoit määrittää uudelleen tai poistua</string> + <string name="server_unreachable_message">Palvelimeen ei saada yhteyttä, yritä uudelleen.</string> + <string name="error.security.pinnedcertificate">Turvallisuusvirhe, päivitä sovellus tai valitse toinen palveluntarjoaja.</string> + <string name="malformed_url">Se ei näytä olevan %s palveluntarjoaja.</string> + <string name="certificate_error">Tämä ei ole luotetttu %s palveluntarjoaja.</string> + <string name="service_is_down_error">Palvelu on poissa.</string> <string name="configuring_provider">Asetetaan palvelutarjoaja</string> + <string name="incorrectly_downloaded_certificate_message">Anonyymia varmennettasi ei ladattu</string> + <string name="downloading_certificate_message">Ladataan VPN-varmennetta</string> + <string name="updating_certificate_message">Päivitetään VPN-varmennetta</string> + <string name="login.riseup.warning">Riseup-käyttäjien on luotava erillinen tili VPN-palvelun käyttöä varten</string> <string name="succesful_authentication_message">Todennettu</string> <string name="authentication_failed_message">Tunnistautuminen epäonnistui</string> + <string name="registration_failed_message">Rekisteröityminen epäonnistui</string> <string name="eip_status_start_pending">Alustetaan yhteys</string> <string name="eip_cancel_connect_title">Perutaanko yhteys?</string> <string name="eip_cancel_connect_text">Yhteysyritys on käynnissä. Haluatko perua sen?</string> + <string name="eip.warning.browser_inconsistency">Kytketäänkö pois VPN-yhteys? Kun VPN on pois päältä, saatat vuotaa henkilökohtaisia tietoja Internet-palveluntarjoajaasi tai paikallisverkkoon.</string> + <string name="eip_state_not_connected">Ei käynnissä! Epävarvullinen yhteys.</string> + <string name="eip_state_connected">Yhteys suojattu</string> + <string name="provider_problem">Vaikuttaa siltä, että palveluntarjoajan kanssa on ongelma.</string> + <string name="try_another_provider">Kokeile toista palveluntarjoajaa tai ota yhteyttä omaasi.</string> <string name="default_username">Anonyymi</string> <string name="logging_in">Kirjaudutaan</string> + <string name="signing_up">Rekisteröiminen</string> + <string name="vpn.button.turn.on">Kytke päälle</string> + <string name="vpn.button.turn.off">Kytke pois päältä</string> + <string name="vpn_button_turn_off_blocking">Lopeta estäminen</string> + <string name="vpn_securely_routed">Liikenne ohjataan turvallisesti seuraavien kautta:</string> + <string name="vpn_securely_routed_no_internet">Internet-yhteyttä ei havaittu, kun se palaa, reititämme liikenteen turvallisesti seuraavien kautta:</string> <string name="log_fragment_title">Loki</string> + <string name="vpn_fragment_title">VPN</string> <string name="navigation_drawer_open">Avaa navigointilaatikko</string> <string name="navigation_drawer_close">Sulje navigointilaatikko</string> + <string name="action_example">Esimerkki toimia</string> <string name="action_settings">Asetukset</string> + <string name="void_vpn_establish">%s estää kaiken lähtevän Internet-liikenteen.</string> + <string name="void_vpn_error_establish">Kaiken Internet-liikenteen estäminen epäonnistui.</string> + <string name="void_vpn_stopped">Kaiken lähtevän Internet-liikenteen estäminen lopetettiin.</string> + <string name="void_vpn_title">Liikenteen estäminen</string> + <string name="update_provider_details">Päivitä palveluntarjoajan yksityiskohdat</string> + <string name="update_certificate">Päivitä varmenne</string> + <string name="warning_eip_json_corrupted">Palveluntarjoajan kokoonpanon päivittäminen epäonnistui.</string> + <string name="eip_json_corrupted_user_message">Palveluntarjoajan kokoonpanon päivittäminen epäonnistui. Kirjaudu sisään ja yritä uudelleen.</string> + <string name="warning_client_parsing_error_gateways">Palveluntarjoajan yhdyskäytäviä ei voitu tunnistaa. Ne voivat olla määritetty väärin.</string> + <string name="warning_corrupted_provider_details">Tallennetut palveluntarjoajan yksityiskohdat ovat vioittuneet. Voit joko päivittää %s (suositus) tai päivittää palveluntarjoajan tiedot kaupallisen CA-varmenteen avulla.</string> + <string name="warning_corrupted_provider_cert">Tallennettu palveluntarjoajan varmenne on virheellinen. Voit joko päivittää %s (suositus) tai päivittää toimittajan varmenteen kaupallisen CA-varmenteen avulla.</string> + <string name="warning_expired_provider_cert">Tallennettu palveluntarjoajan varmenne on vanhentunut. Voit joko päivittää %s (suositus) tai päivittää toimittajan varmenteen kaupallisen CA-varmenteen avulla.</string> + <string name="downloading_vpn_certificate_failed">VPN-varmenteen lataaminen epäonnistui. Yritä uudelleen tai valitse toinen palveluntarjoaja.</string> + <string name="vpn_certificate_is_invalid">VPN-varmenne on virheellinen. Yritä ladata uusi.</string> + <string name="vpn_certificate_user_message">VPN-varmenne on virheellinen. Kirjaudu sisään ladataksesi uuden.</string> + <string name="save_battery">Säästä akkua</string> + <string name="subtitle_save_battery">Pois käytöstä, kun VPN Hotspot on päällä</string> + <string name="save_battery_message">Taustadatayhteydet horrostuvat kun puhelimesi on passiivinen.</string> + <string name="always_on_vpn">Aina-päällä VPN</string> + <string name="subtitle_always_on_vpn">Avaa Android-järjestelmäasetukset</string> + <string name="tethering">VPN Hotspot</string> + <string name="ipv6Firewall">Estä IPv6</string> + <string name="require_root">Vaatii rootin oikeudet</string> + <string name="show_experimental">Näytä kokeelliset ominaisuudet</string> + <string name="hide_experimental">Piilota kokeelliset ominaisuudet</string> + <string name="experimental_features">Kokeelliset ominaisuudet</string> + <string name="tethering_enabled_message">Varmista, että olet ensin ottanut jakamisen käyttöön kohdassa <![CDATA[<b>järjestelmäasetukset</b>]]>.</string> + <string name="tethering_message">Jaa VPN muiden laitteiden kanssa kautta:</string> + <string name="tethering_wifi">Wi-Fi hotspot</string> + <string name="tethering_usb">USB-jako</string> + <string name="tethering_bluetooth">Bluetooth-jako</string> + <string name="do_not_show_again">Älä näytä uudelleen</string> + <string name="always_on_vpn_user_message">Aina-päällä VPN:n käyttöön ottamiseksi, napsauta Android VPN -asetuksissa konfigurointikuvaketta [img src] ja kytke kytkin päälle.</string> + <string name="always_on_blocking_vpn_user_message">Yksityisyytesi optimaalisen suojaamiseksi sinun tulee aktivoida myös vaihtoehto \"Estä yhteydet ilman VPN:ää\".</string> <string name="donate_title">Lahjoita</string> + <string name="donate_default_message">Lahjoita jo tänään, jos arvostat turvallista viestintää, joka on helppoa sekä loppukäyttäjälle että palveluntarjoajalle.</string> + <string name="donate_message">LEAP riippuu lahjoituksista ja apurahoista. Lahjoita jo tänään, jos arvostat turvallista viestintää, joka on helppoa sekä loppukäyttäjälle että palveluntarjoajalle.</string> <string name="donate_button_remind_later">Muistuta minua myöhemmin</string> <string name="donate_button_donate">Lahjoita</string> + <string name="obfuscated_connection">Käyttää hämärää yhteyttä.</string> + <string name="obfuscated_connection_try">Kokeillaan hämärää yhteyttä.</string> <string name="nav_drawer_obfuscated_connection">Käytä siltoja</string> + <string name="nav_drawer_subtitle_obfuscated_connection">Kierrä VPN-suodatus</string> + <string name="warning_exclude_apps_message">Ole varovainen sulkemasta sovelluksia pois VPN:stä. Tämä paljastaa henkilöllisyytesi ja vaarantaa turvallisuutesi.</string> + <plurals name="subtitle_exclude_apps"> + <item quantity="one">%d suojaamaton sovellus</item> + <item quantity="other">%d suojaamatonta sovellusta</item> + </plurals> + <string name="warning_no_more_gateways_use_pt">%sei pystynyt yhdistämään. Voi olla, että VPN-yhteydet estyvät. Haluatko yrittää muodostaa yhteyden käyttämällä hämäriä yhteyksiä?</string> + <string name="warning_no_more_gateways_no_pt">%s ei pystynyt yhdistämään. Haluatko yrittää uudelleen?</string> + <string name="warning_no_more_gateways_use_ovpn">%s ei voinut muodostaa yhteyttä käyttämällä hämäriä VPN-yhteyksiä. Haluatko yrittää muodostaa yhteyden tavallisella VPN:lla?</string> + <string name="warning_no_more_gateways_manual_gw_selection">%1$s ei voi muodostaa yhteyttä %2$s:een. Haluatko yrittää muodostaa yhteyden automaattisesti parhaaseen sijaintiin?</string> + <string name="warning_option_try_best">Kokeile parasta sijaintia</string> + <string name="warning_option_try_pt">Kokeile hämärää yhteyttä</string> + <string name="warning_option_try_ovpn">Kokeile tavallista yhteyttä</string> + <string name="vpn_error_establish">Android ei pystynyt vahvistamaan VPN-palvelua.</string> + <string name="root_permission_error">%s ei voi suorittaa ominaisuuksia, kuten VPN Hotspot tai IPv6-palomuuri ilman rootin oikeuksia.</string> + <string name="qs_enable_vpn">Käynnistä %s</string> + <string name="version_update_found">Tap here to start the download.</string> + <string name="version_update_title">Uusi versio %s :ta on löydetty.</string> + <string name="version_update_apk_description">Ladataan uutta versiota %s :ta</string> + <string name="version_update_download_title">Uusi versio %s :ta on ladattu.</string> + <string name="version_update_download_description">Asenna päivitys napauttamalla tätä</string> + <string name="version_update_error_pgp_verification">PGP-vahvistusvirhe. Ohitetaan lataus.</string> + <string name="version_update_error">Päivitys epäonnistui.</string> + <string name="version_update_error_permissions">Ei oikeuksia sovellusten asentamiseen</string> + <string name="gateway_selection_title">Valitse sijainti</string> + <string name="gateway_selection_recommended_location">Suositeltu sijainti</string> <string name="gateway_selection_recommended">Suositeltu</string> + <string name="gateway_selection_manually">Valitse manuaalisesti</string> + <string name="gateway_selection_automatic_location">Käytä automaattisesti parasta yhteyttä</string> <string name="gateway_selection_automatic">Automaattinen</string> + <string name="reconnecting">Yhdistetään uudelleen.</string> + <string name="tor_starting">Käynnistetään siltoja sensuurin kiertämiseksi.</string> + <string name="tor_stopping">Siltoja pysäytetään</string> + <string name="tor_started">Siltojen käyttäminen sensuurin kiertämiseksi</string> + <string name="log_conn_done_pt">Yhdistetty kytkettävään kuljetukseen</string> + <string name="log_conn_pt">Yhdistetään liitettävään kuljetukseen</string> + <string name="log_conn_done">Kytketty releeseen</string> + <string name="log_handshake">Yhteyden neuvottelu releen kanssa</string> + <string name="log_handshake_done">Yhteys releen kanssa neuvoteltu</string> <string name="log_onehop_create">Muodostetaan suojattu yhteys hakemistoon</string> + <string name="log_requesting_status">Pyydetään konsensusta verkon tilasta</string> + <string name="log_loading_status">Ladataan verkon tilakonsensusta</string> <string name="log_loading_keys">Ladataan juurivarmenteita</string> + <string name="log_requesting_descriptors">Pyydetään relekuvauksia</string> + <string name="log_loading_descriptors">Ladataan releen kuvauksia</string> + <string name="log_enough_dirinfo">Ladattu tarpeeksi hakemistotietoja piirien rakentamiseen</string> + <string name="log_ap_handshake_done">Neuvottelut päättyivät releellä piirien rakentamiseksi</string> <string name="log_circuit_create">Muodostetaan Tor-kiertotie</string> <string name="log_done">Käynnissä</string> + <string name="channel_name_tor_service">%s siltapalvelu</string> + <string name="channel_description_tor_service">Ilmoittaa siltojen käytöstä määritettäessä %s.</string> + <string name="error_tor_timeout">Siltojen käynnistys epäonnistui. Haluatko yrittää uudelleen vai jatkaa suojatulla ei-hämärällä yhteydellä %s:n määrittämistä?</string> + <string name="retry_unobfuscated">Yritä uudelleen ilman hämärtymistä</string> <string name="hide">Piilota</string> + <string name="error_network_connection">%s :lla ei ole internetyhteyttä. Tarkista Wi-Fi- ja mobiilidata-asetukset.</string> + <string name="censorship_circumvention">Sensuurin kiertäminen</string> <string name="use_snowflake">Käytä Snowflakea</string> + <string name="snowflake_description">Suojaa määritysprosessia sensuurilta.</string> + <string name="vpn_settings">VPN-asetukset</string> + <string name="prefer_udp">Käytä UDP:tä, jos mahdollista</string> + <string name="prefer_udp_subtitle">UDP voi olla nopeampi ja parempi suoratoistoon, mutta se ei toimi kaikissa verkoissa.</string> + <string name="disabled_while_bridges_on">Pois käytöstä siltoja käytettäessä.</string> + <string name="hint_bridges">Vain siltoja tukevat sijainnit ovat tällä hetkellä valittavissa.</string> + <string name="option_disable_bridges">Poista sillat käytöstä</string> + <string name="eip_state_insecure">Yhteys epäturvallinen</string> + <string name="connection_not_connected">Saatat vuotaa tietoja Internet-palveluntarjoajaltasi tai paikallisverkkoon.</string> + <string name="eip_state_no_network">Sinulla ei ole toimivaa Internet-yhteyttä. Kun saat sen takaisin, sinut yhdistetään automaattisesti</string> + <string name="eip_state_blocking">%1$s estää kaiken Internet-liikenteen.</string> + <string name="disabled_while_udp_on">Ei käytössä, kun UDP on päällä.</string> <string name="advanced_settings">Lisäasetukset</string> <string name="cancel_connection">Katkaise yhteys</string> </resources> diff --git a/app/src/main/res/values-fil/strings.xml b/app/src/main/res/values-fil/strings.xml deleted file mode 100644 index 261a777f5d22ea6ef5324f143f0311a83e7b30aa..0000000000000000000000000000000000000000 --- a/app/src/main/res/values-fil/strings.xml +++ /dev/null @@ -1,9 +0,0 @@ -<?xml version='1.0' encoding='UTF-8'?> -<resources> - <string name="save">I-save</string> - <string name="about_fragment_title">Tungkol</string> - <string name="setup_error_close_button">Lumabas</string> - <string name="succesful_authentication_message">Napatunayan</string> - <string name="log_fragment_title">Tala</string> - <string name="action_settings">Settings</string> -</resources> diff --git a/app/src/main/res/values-fr/strings.xml b/app/src/main/res/values-fr/strings.xml index d140576778abbdf2551ccf262f40fafc3980d385..47d10ed67d35e64f1ebc9dda53f5402701c48e16 100644 --- a/app/src/main/res/values-fr/strings.xml +++ b/app/src/main/res/values-fr/strings.xml @@ -3,7 +3,7 @@ <string name="retry">Réessayer</string> <string name="repository_url_text">Le code source se trouve sur https://0xacab.org/leap/bitmask_android</string> <string name="leap_tracker">Le système de suivi des problèmes se trouve sur https://0xacab.org/leap/bitmask_android/issues</string> - <string name="translation_project_text">Les traductions sont les bienvenues et nous les valorisons. Consulter notre projet Transifex sur https://www.transifex.com/projects/p/bitmask-android/</string> + <string name="translation_project_text">Les traductions sont les bienvenues et nous les valorisons. Consulter notre projet Transifex sur https://www.transifex.com/projects/p/bitmask/</string> <string name="switch_provider_menu_option">Changer de fournisseur</string> <string name="info">renseignements</string> <string name="show_connection_details">Afficher les détails de connexion</string> @@ -40,7 +40,7 @@ <string name="error_client_http_user_message">Réessayez : erreur HTTP du client</string> <string name="error_io_exception_user_message">Réessayez : erreur E/S</string> <string name="error_json_exception_user_message">Réessayez : mauvaise réponse du serveur</string> - <string name="error_no_such_algorithm_exception_user_message">L’algorithme de chiffrement est introuvable. Veuillez mettre votre Android à niveau !</string> + <string name="error_no_such_algorithm_exception_user_message">L’algorithme de chiffrement est introuvable. Veuillez mettre votre Android à niveau.</string> <string name="signup_or_login_button">Inscription/Connexion</string> <string name="login_button">Connexion</string> <string name="login_to_profile">Connexion au profil</string> @@ -67,10 +67,13 @@ <string name="authentication_failed_message">Échec d’authentification</string> <string name="registration_failed_message">L’inscription a échoué</string> <string name="eip_status_start_pending">Initialisation de la connexion</string> - <string name="eip_cancel_connect_title">Annuler la connexion ?</string> - <string name="eip_cancel_connect_text">Une tentative de connexion est en cours. Voulez-vous l’annuler ?</string> - <string name="eip.warning.browser_inconsistency">Désactiver la connexion RPV ? Si votre RPV est désactivé, vous pourriez divulguer des renseignements personnels à votre fournisseur d’accès à Internet ou à votre réseau local.</string> - <string name="eip_state_not_connected">Ne s’exécute pas ! La connexion n’est pas sécurisée !</string> + <string name="eip_status_connecting">Connecter au RPV</string> + <string name="eip_status_unsecured">Connexion non sécurisée</string> + <string name="eip_status_secured">Connexion sécurisée</string> + <string name="eip_cancel_connect_title">Annuler la connexion ?</string> + <string name="eip_cancel_connect_text">Une tentative de connexion est en cours. Voulez-vous l’annuler ?</string> + <string name="eip.warning.browser_inconsistency">Désactiver la connexion RPV ? Si votre RPV est désactivé, vous pourriez divulguer des renseignements personnels à votre fournisseur d’accès à Internet ou à votre réseau local.</string> + <string name="eip_state_not_connected">Ne s’exécute pas ! La connexion n’est pas sécurisée !</string> <string name="eip_state_connected">La connexion est sécurisée</string> <string name="provider_problem">Il semble que le fournisseur pose un problème.</string> <string name="try_another_provider">Veuillez essayer un autre fournisseur ou nous contacter.</string> @@ -134,12 +137,13 @@ <string name="warning_exclude_apps_message">Soyez prudent en excluant des applis du RPV. Cela divulguera votre identité et compromettra votre sécurité.</string> <plurals name="subtitle_exclude_apps"> <item quantity="one">%d appli non protégée</item> + <item quantity="many">%d applis non protégées</item> <item quantity="other">%d applis non protégées</item> </plurals> - <string name="warning_no_more_gateways_use_pt">%s n’a pas pu se connecter. Les connexions RPV sont peut-être bloquées. Voulez-vous tenter de vous connecter en essayant des connexions brouillées ?</string> - <string name="warning_no_more_gateways_no_pt">%s n’a pas pu se connecter. Voulez-vous réessayer ?</string> - <string name="warning_no_more_gateways_use_ovpn">%s n’a pas pu se connecter en utilisant des connexions RPV brouillées. Voulez-vous tenter de vous connecter en essayant un RPV normal ?</string> - <string name="warning_no_more_gateways_manual_gw_selection">%1$s n’a pas réussi à se connecter à %2$s. Voulez-vous essayer de vous connecter automatiquement avec le meilleur emplacement ?</string> + <string name="warning_no_more_gateways_use_pt">%s n’a pas pu se connecter. Les connexions RPV sont peut-être bloquées. Voulez-vous tenter de vous connecter en essayant des connexions brouillées ?</string> + <string name="warning_no_more_gateways_no_pt">%s n’a pas pu se connecter. Voulez-vous réessayer ?</string> + <string name="warning_no_more_gateways_use_ovpn">%s n’a pas pu se connecter en utilisant des connexions RPV brouillées. Voulez-vous tenter de vous connecter en essayant un RPV normal ?</string> + <string name="warning_no_more_gateways_manual_gw_selection">%1$s n’a pas réussi à se connecter à %2$s. Voulez-vous essayer de vous connecter automatiquement au meilleur emplacement ?</string> <string name="warning_option_try_best">Essayer le meilleur emplacement</string> <string name="warning_option_try_pt">Essayer une connexion brouillée.</string> <string name="warning_option_try_ovpn">Essayer une connexion normal.</string> @@ -181,7 +185,7 @@ <string name="log_done">En fonction</string> <string name="channel_name_tor_service">Service de ponts %s</string> <string name="channel_description_tor_service">Renseigne sur l’utilisation des ponts lors de la configuration %s.</string> - <string name="error_tor_timeout">Échec de démarrage des ponts. Voulez-vous réessayer ou poursuivre avec une connexion sécurisée non brouillée pour configurer %s ?</string> + <string name="error_tor_timeout">Échec de démarrage des ponts. Voulez-vous réessayer ou poursuivre avec une connexion sécurisée non brouillée pour configurer %s ?</string> <string name="retry_unobfuscated">Réessayer sans brouillage</string> <string name="hide">Cacher</string> <string name="error_network_connection">%s n’as pas de connexion Internet. Veuillez vérifier vos paramètres Wi-Fi et de données mobiles.</string> @@ -201,4 +205,6 @@ <string name="disabled_while_udp_on">Désactivé pendant que l’UDP est activé</string> <string name="advanced_settings">Paramètres avancés</string> <string name="cancel_connection">Se déconnecter</string> + <string name="unknown_location">Site inconnu</string> + <string name="splash_footer">Développé par LEAP</string> </resources> diff --git a/app/src/main/res/values-gl/strings.xml b/app/src/main/res/values-gl/strings.xml index d6f8d19c6eb5a2115021082ffea75592fa8934e2..9b0539abcadc9c2089ad44cf035b2b34ae8df78a 100644 --- a/app/src/main/res/values-gl/strings.xml +++ b/app/src/main/res/values-gl/strings.xml @@ -3,7 +3,8 @@ <string name="retry">Intentar de novo</string> <string name="repository_url_text">Código fonte dispoñible en https://0xacab.org/leap/bitmask_android</string> <string name="leap_tracker">Seguimento de incidencias en https://0xacab.org/leap/bitmask_android/issues</string> - <string name="translation_project_text">Agradécese a tradución. Aquí está o noso proxecto en Transifex https://www.transifex.com/projects/p/bitmask-android/</string> + <string name="translation_project_text">Agradécese a tradución. Aquí está o noso proxecto en Transifex https://www.transifex.com/projects/p/bitmask/ +</string> <string name="switch_provider_menu_option">Cambiar provedor</string> <string name="info">info</string> <string name="show_connection_details">Mostrar detalles da conexión</string> @@ -110,7 +111,7 @@ <string name="require_root">Require permiso root</string> <string name="show_experimental">Mostrar funcións experimentais</string> <string name="hide_experimental">Agochar funcións experimentais</string> - <string name="tethering_enabled_message">Asegúrate de ter antes activada a compartición da conexión en <![CDATA[1system settings1]]>.</string> + <string name="tethering_enabled_message">Asegúrate de ter antes activada a compartición da conexión en <![CDATA[<b>system settings</b>]]>.</string> <string name="tethering_message">Comparte a túa VPN con outros dispositivos vía:</string> <string name="tethering_wifi">Punto de acceso Wi-Fi</string> <string name="tethering_usb">Compartición USB</string> diff --git a/app/src/main/res/values-he/strings.xml b/app/src/main/res/values-he/strings.xml index 054b4a207dc8585cffd253eaea0851e1361a87c7..50c32b494cd5ac7321526ef307c88162f04da4fb 100644 --- a/app/src/main/res/values-he/strings.xml +++ b/app/src/main/res/values-he/strings.xml @@ -2,11 +2,13 @@ <resources> <string name="retry">נסה שוב</string> <string name="repository_url_text">קוד מקור זמין בכתובת https://0xacab.org/leap/bitmask_android</string> - <string name="leap_tracker">גשש סוגיות זמין בכתובת https://0xacab.org/leap/bitmask_android/issues</string> - <string name="translation_project_text">תרגומים מבורכים ומוערכים. ראה את מיזם Transifex שלנו בכתובת https://www.transifex.com/projects/p/bitmask-android/</string> + <string name="leap_tracker">גשש סוגיות זמין בכתובת +https://0xacab.org/leap/bitmask_android/issues</string> + <string name="translation_project_text">תרגומים מבורכים ומוערכים. ראה את מיזם Transifex שלנו בכתובת https://www.transifex.com/projects/p/bitmask/</string> <string name="switch_provider_menu_option">החלף ספק</string> <string name="info">מידע</string> <string name="show_connection_details">הראה פרטי חיבור</string> + <string name="connection_details">פרטי חיבור</string> <string name="routes_info">נתיבים: %s</string> <string name="routes_info6">IPv6 נתיבי: %s</string> <string name="error_empty_username">שם המשתמש חייב לא להיות ריק.</string> @@ -51,6 +53,7 @@ <string name="setup_error_configure_button">תצר</string> <string name="setup_error_close_button">צא</string> <string name="setup_error_text">הייתה שגיאה בתיצור %s ם הספק הנבחר שלך.\n\nאתה יכול לבחור לתצר מחדש, או לצאת ולתצר ספק בעת ההפעלה הבאה.</string> + <string name="setup_error_text_custom">הייתה שגיאה בתיצור %s.\n\nאתה יכול לבחור לתצר מחדש, או לצאת.</string> <string name="server_unreachable_message">השרת בלתי נגיש, אנא נסה שוב.</string> <string name="error.security.pinnedcertificate">שגיאת אבטחה. שדרג את היישום או נסה ספק אחר.</string> <string name="malformed_url">נראה שזה לא ספק %s.</string> @@ -87,6 +90,7 @@ <string name="action_example">פעולת דוגמה</string> <string name="action_settings">הגדרות</string> <string name="void_vpn_establish">%s חוסם את כל תעבורת האינטרנט היוצאת.</string> + <string name="void_vpn_error_establish">חסימת כל תעבורת האינטרנט נכשלה.</string> <string name="void_vpn_stopped">הפסיק לחסום את כל תעבורת האינטרנט היוצאת.</string> <string name="void_vpn_title">חוסם תעבורה</string> <string name="update_provider_details">עדכן פרטי ספק</string> @@ -110,11 +114,12 @@ <string name="require_root">דורש הרשאות שורש</string> <string name="show_experimental">הראה מאפיינים ניסיוניים</string> <string name="hide_experimental">הסתר מאפיינים ניסיוניים</string> - <string name="tethering_enabled_message">אנא וודא כי איפשרת שיתוף חיבור ב<![CDATA[<b>הגדרות המערכת</b>]]> תחילה.</string> + <string name="experimental_features">מאפיינים ניסיוניים</string> + <string name="tethering_enabled_message">אנא וודא כי אפשרת מצב מודם ב<![CDATA[<b>הגדרות המערכת</b>]]> תחילה.</string> <string name="tethering_message">שתף את ה־VPN שלך עם מכשירים אחרים דרך:</string> <string name="tethering_wifi">נקודה חמה של Wi-Fi</string> - <string name="tethering_usb">שיתוף חיבור דרך USB</string> - <string name="tethering_bluetooth">שיתוף חיבור דרך Bluetooth</string> + <string name="tethering_usb">מצב מודם דרך USB</string> + <string name="tethering_bluetooth">מצב מודם דרך Bluetooth</string> <string name="do_not_show_again">אל תראה שוב</string> <string name="always_on_vpn_user_message">כדי לאפשר VPN תמיד פועל בהגדרות VPN של Android, לחץ על הצלמית הגדר [img src] והפעל את המתג.</string> <string name="always_on_blocking_vpn_user_message">כדי להגן על פרטיותך באופן הרצוי ביותר, אתה גם צריך להפעיל את האפשרות \"חסום חיבורים ללא VPN\".</string> @@ -137,6 +142,8 @@ <string name="warning_no_more_gateways_use_pt">%s לא היה יכול להתחבר. ייתכן שחיבורי VPN נחסמו. האם אתה רוצה לנסות להתחבר ע״י שימוש בחיבורים מאופלים?</string> <string name="warning_no_more_gateways_no_pt">%s לא היה יכול להתחבר. הם אתה רוצה לנסות מחדש?</string> <string name="warning_no_more_gateways_use_ovpn">%s לא היה יכול להתחבר ע״י שימוש בחיבורי VPN מאורפלים. האם אתה רוצה לנסות להתחבר ע״י שימוש בחיבור VPN תקני?</string> + <string name="warning_no_more_gateways_manual_gw_selection">%1$s לא היה יכול להתחבר אל %2$s. האם אתה רוצה לנסות להתחבר באופן אוטומטי עם המיקום הטוב ביותר?</string> + <string name="warning_option_try_best">נסה את המיקום הטוב ביותר</string> <string name="warning_option_try_pt">נסה חיבור מאופל</string> <string name="warning_option_try_ovpn">נסה חיבור תקני</string> <string name="vpn_error_establish">Android נכשל בהקמת שירות VPN.</string> @@ -150,12 +157,51 @@ <string name="version_update_error_pgp_verification">שגיאת וידוא PGP. מתעלם מהורדה.</string> <string name="version_update_error">עדכון נכשל.</string> <string name="version_update_error_permissions">אין הרשאות להתקין את היישום.</string> + <string name="gateway_selection_title">בחר מיקום</string> + <string name="gateway_selection_recommended_location">מיקום מומלץ</string> + <string name="gateway_selection_recommended">מומלץ</string> + <string name="gateway_selection_manually">בחר באופן ידני</string> + <string name="gateway_selection_automatic_location">השתמש באופן אוטומטי בחיבור הטוב ביותר</string> + <string name="gateway_selection_automatic">אוטומטי</string> + <string name="reconnecting">מתחבר מחדש…</string> + <string name="tor_starting">מתחיל גשרים עבור עקיפת צנזורה…</string> + <string name="tor_stopping">עוצר גשרים</string> + <string name="tor_started">משתמש בגשרים עבור עקיפת צנזורה</string> + <string name="log_conn_done_pt">מחובר אל תחבורה נתיקה</string> + <string name="log_conn_pt">מתחבר אל תחבורה נתיקה</string> + <string name="log_conn_done">מחובר אל ממסר</string> + <string name="log_handshake">מתמקח על חיבור עם ממסר</string> + <string name="log_handshake_done">חיבור עם ממסר התמקח</string> <string name="log_onehop_create">מקים חיבור סיפרייה מוצפן</string> + <string name="log_requesting_status">מבקש הסכמת מעמד רשת</string> + <string name="log_loading_status">טוען הסכמת מעמד רשת</string> <string name="log_loading_keys">טוען אישורי רָשׁוּת</string> + <string name="log_requesting_descriptors">מבקש מתארי ממסר</string> + <string name="log_loading_descriptors">טוען מתארי ממסר</string> + <string name="log_enough_dirinfo">מידע תיקיות מספיק נטען כדי לבנות מעגלים</string> + <string name="log_ap_handshake_done">התמקחות הסתיימה עם ממסר לבנות מעגלים</string> <string name="log_circuit_create">מקים מעגל Tor</string> <string name="log_done">רץ</string> + <string name="channel_name_tor_service">שירות גשרים %s</string> + <string name="channel_description_tor_service">מודיע לגבי שימוש בגשרים בזמן תיצור %s.</string> + <string name="error_tor_timeout">התחלת גשרים נכשלה. האם אתה רוצה לנסות מחדש או להמשיך עם חיבור מאובטח בלתי מאופל כדי לתצר את %s?</string> + <string name="retry_unobfuscated">נסה בלתי מאופל</string> <string name="hide">הסתר</string> + <string name="error_network_connection">אל %s אין חיבור אינטרנט. אנא בדוק את ההגדרות של Wi-Fi וההגדרות של נתונים סלולריים.</string> + <string name="censorship_circumvention">עקיפת צנזורה</string> <string name="use_snowflake">השתמש ב־Snowflake</string> + <string name="snowflake_description">הגן על תהליך תצורה נגד צנזורה.</string> + <string name="vpn_settings">הגדרות VPN</string> + <string name="prefer_udp">השתמש ב־UDP אם זמין</string> + <string name="prefer_udp_subtitle">UDP יכול להיות מהיר יותר וטוב יותר עבור הזרמה, אבל הוא לא עובד עבור כל הרשתות.</string> + <string name="disabled_while_bridges_on">מושבת בזמן שימוש בגשרים.</string> + <string name="hint_bridges">רק מיקומים שתומכים בגשרים ניתנים לבחירה כרגע.</string> + <string name="option_disable_bridges">השבת גשרים</string> + <string name="eip_state_insecure">חיבור בלתי מאובטח</string> + <string name="connection_not_connected">ייתכן שאתה מדליף מידע אל ספק האינטרנט שלך או הרשת המקומית שלך.</string> + <string name="eip_state_no_network">אין לך חיבור עובד של אינטרנט. ברגע שתחזיר אותו, תחובר באופן אוטומטי אל</string> + <string name="eip_state_blocking">%1$s חוסם את כל תעבורת האינטרנט.</string> + <string name="disabled_while_udp_on">מושבת כאשר UDP פועל.</string> <string name="advanced_settings">הגדרות מתקדמות</string> <string name="cancel_connection">התנתק</string> </resources> diff --git a/app/src/main/res/values-hr/strings.xml b/app/src/main/res/values-hr/strings.xml index 5d8eca7506e06f543a659abf3737dce3187c01b3..9ee1a5b1b1f7f3fa18d8bab0b337a677829cae86 100644 --- a/app/src/main/res/values-hr/strings.xml +++ b/app/src/main/res/values-hr/strings.xml @@ -57,6 +57,7 @@ <string name="log_onehop_create">Uspostavljanje šifrirane veze direktorija</string> <string name="log_loading_keys">Učitavanje certifikata autoriteta</string> <string name="log_circuit_create">Uspostavljanje Tor kruga</string> + <string name="log_done">Pokrenuto</string> <string name="hide">Sakrij</string> <string name="use_snowflake">Koristi Snowflake</string> <string name="cancel_connection">Odspoji</string> diff --git a/app/src/main/res/values-hu/strings.xml b/app/src/main/res/values-hu/strings.xml index f3d9bc3a23c2d07d25a988ce459e773e835e3c43..1c20d930dd71fcfb0889de9d178c4b24b4618585 100644 --- a/app/src/main/res/values-hu/strings.xml +++ b/app/src/main/res/values-hu/strings.xml @@ -3,7 +3,7 @@ <string name="retry">Ismétlés</string> <string name="repository_url_text">A forráskód elérhető itt: https://0xacab.org/leap/bitmask_android</string> <string name="leap_tracker">Az Issue tracker elérhető itt: https://0xacab.org/leap/bitmask_android/issues</string> - <string name="translation_project_text">A fordításokat szívesen vesszük. Tekintse meg Transifex projektünket a https://www.transifex.com/projects/p/bitmask-android/ címen.</string> + <string name="translation_project_text">A fordításokat szívesen vesszük. Tekintse meg Transifex projektünket a https://www.transifex.com/projects/p/bitmask/ címen.</string> <string name="switch_provider_menu_option">Szolgáltató váltása</string> <string name="info">Információ</string> <string name="show_connection_details">Kapcsolat adatok mutatása</string> diff --git a/app/src/main/res/values-in/plurals-icsopenvpn.xml b/app/src/main/res/values-in/plurals-icsopenvpn.xml deleted file mode 100755 index 6b7daaefb0e9c6538ca24272d55befaa75d30b4a..0000000000000000000000000000000000000000 --- a/app/src/main/res/values-in/plurals-icsopenvpn.xml +++ /dev/null @@ -1,10 +0,0 @@ -<?xml version="1.0" encoding="utf-8"?> -<!--Generated by crowdin.com--> -<resources> - <plurals name="months_left"> - <item quantity="other">%d bulan kiri</item> - </plurals> - <plurals name="days_left"> - <item quantity="other">%d hari lagi</item> - </plurals> -</resources> diff --git a/app/src/main/res/values-in/strings-icsopenvpn.xml b/app/src/main/res/values-in/strings-icsopenvpn.xml deleted file mode 100755 index e7a044ac208e1c5a33aef110ac0ca12131524e3d..0000000000000000000000000000000000000000 --- a/app/src/main/res/values-in/strings-icsopenvpn.xml +++ /dev/null @@ -1,454 +0,0 @@ -<?xml version="1.0" encoding="utf-8"?> -<!--Generated by crowdin.com--> -<!-- - ~ 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> - - <string name="address">Alamat Server:</string> - <string name="port">Server Port:</string> - <string name="location">Lokasi</string> - <string name="cant_read_folder">Gagal membaca direktori:</string> - <string name="select">Pilih</string> - <string name="cancel">Batal</string> - <string name="no_data">Tidak ada data</string> - <string name="useLZO">Kompresi LZO</string> - <string name="client_no_certificate">Sertifikat CA</string> - <string name="client_certificate_title">Sertifikat Klien</string> - <string name="client_key_title">Kunci Sertifikat Klien</string> - <string name="client_pkcs12_title">Berkas PKCS12</string> - <string name="ca_title">Sertifikat CA</string> - <string name="no_certificate">Anda harus memilih sertifikat</string> - <string name="copyright_guicode">Kode sumber dan pelacak masalah tersedia di https://github.com/schwabe/ics-openvpn/</string> - <string name="copyright_others">Program ini memakai komponen berikut ini. Lihat sumber untuk mengetahui rincian lisensi</string> - <string name="about">Tentang</string> - <string name="vpn_list_title">Profil</string> - <string name="vpn_type">Mengetik</string> - <string name="pkcs12pwquery">Password PKCS12</string> - <string name="file_select">Pilih…</string> - <string name="file_nothing_selected">Anda harus memilih setidaknya satu berkas</string> - <string name="useTLSAuth">Gunakan Autentikasi TLS</string> - <string name="tls_direction">Pengarah TLS</string> - <string name="ipv6_dialog_tile">Masukkan Alamat IPv6/Netmask dalam Format CIDR (contoh: 2000:dd::23/64)</string> - <string name="ipv4_dialog_title">Masukkan IPv4 Address/Netmask dalam format CIDR (contoh: 1.2.3.4/24)</string> - <string name="ipv4_address">Alamat IPv4</string> - <string name="ipv6_address">Alamat IPv6</string> - <string name="custom_option_warning">Masukan pengaturan kustom OpenVPN. Harap gunakan dengan hati-hati. Perlu dicatat bahwa pengaturan yang terkait dengan TUN OpenVPN tidak didukung oleh disain VPNSettings. Jika anda fikir ada hal penting yang belum tersedia segera hubungi pembuatnya</string> - <string name="auth_username">Nama Penguna</string> - <string name="auth_pwquery">Kata Sandi</string> - <string name="static_keys_info">Untuk pengaturan tetap, kunci otentifikasi TLS akan digunakan sebagai kunci statis</string> - <string name="configure_the_vpn">Konfigurasi VPN</string> - <string name="menu_add_profile">Tambah Profil</string> - <string name="add_profile_name_prompt">Masukkan nama profil yang baru</string> - <string name="duplicate_profile_name">Silakan masukan nama profil yang berbeda</string> - <string name="profilename">Nama profil</string> - <string name="no_keystore_cert_selected">Anda harus memilih sertifikat pengguna</string> - <string name="no_ca_cert_selected">Opoeo</string> - <string name="no_error_found">Tidak ada kesalahan</string> - <string name="config_error_found">Konfigurasi Salah</string> - <string name="ipv4_format_error">Kesalahan penulisan alamat IPV4</string> - <string name="custom_route_format_error">Gagal menganalisa rute buatan</string> - <string name="pw_query_hint">(biarkan kosong untuk antrian permintaan)</string> - <string name="vpn_shortcut">Jalan Pintas OpenVPN</string> - <string name="vpn_launch_title">Dyan</string> - <string name="shortcut_profile_notfound">Profil di shrotcut tidak ada</string> - <string name="random_host_prefix">Acak awalan Host </string> - <string name="random_host_summary">Tambahkan 6 karakter acak di depan nama host</string> - <string name="custom_config_title">Aktifkan pilihan buatan (Custom)</string> - <string name="custom_config_summary">Tentukan seting buatan (Custom). Gunakan hati-hati!</string> - <string name="route_rejected">Rute ditolak oleh Android</string> - <string name="cancel_connection_long">Memutuskan sambungan VPN</string> - <string name="clear_log">Bersihkan catatan</string> - <string name="title_cancel">Membatalkan Konfirmasi</string> - <string name="cancel_connection_query">Putuskan sambungan VPN/Batalkan upaya penyambungan VPN?</string> - <string name="remove_vpn">Hapus VPN</string> - <string name="check_remote_tlscert">Memeriksa apakah server menggunakan sertifikat dengan ekstensi TLS Server (--server remote-cert-tls)</string> - <string name="check_remote_tlscert_title">Mengharapkan sertifikat server TLS</string> - <string name="remote_tlscn_check_summary">Memeriksa sertifikat Remote Server dengan Subjek DN</string> - <string name="remote_tlscn_check_title">Cek nama sertifikat Host</string> - <string name="enter_tlscn_dialog">Tentukan nilai yang digunakan untuk memverifikasi sertifikat remote DN (misal C=nama perusahaan, L=Kota lokasi, OU=nama departemen perusahaan, CN=openvpn.blinkt.de. Tentukan DN atau RDN yang lengkap (dalam contoh: openvpn.blinkt.de) atau sebuah awalan RDN untuk verifikasi. Saat memakai RDN awalan \"server\" cocok dengan \"server-1\" dan \"server-2\". Mengosongkan field akan membuat RDN diperiksa dengan nama host server. Lebih jelasnya lihat OpenVPN 2.3.1 manpage di bagian -verify-x509-name</string> - <string name="enter_tlscn_title">Subyek sertifikat remote</string> - <string name="tls_key_auth">Aktifkan otentifikasi kunci TLS</string> - <string name="tls_auth_file">Berkas otintikasi TLS</string> - <string name="pull_on_summary">Meminta pilihan alamat IP, rute dan waktu dari server.</string> - <string name="pull_off_summary">Tidak ada informasi diminta dari server. Seting harus ditentukan di bawah ini</string> - <string name="use_pull">Tarik pengaturan</string> - <string name="dns">DNS</string> - <string name="override_dns">Menimpa pengaturan DNS oleh Server</string> - <string name="dns_override_summary">Gunakan server DNS pribadi</string> - <string name="searchdomain">cari domain</string> - <string name="dns1_summary">Server DNS yang akan digunakan</string> - <string name="dns_server">Server DNS</string> - <string name="secondary_dns_message">Server DNS sekunder digunakan jika Server DNS yang normal tidak dapat dicapai.</string> - <string name="backup_dns">Server DNS cadangan</string> - <string name="ignored_pushed_routes">Abaikan rute yang diberikan</string> - <string name="ignore_routes_summary">Abaikan rute yang diberikan server</string> - <string name="default_route_summary">Alihkan semua lalulintas data melalui VPN</string> - <string name="use_default_title">Gunakan rute standar</string> - <string name="custom_route_message">Masukkan rute butan sendiri. Masukkan tujuan dalam format CIDR. \"10.0.0.0/8 2002:: / 16\" akan mengarahkan jaringan 10.0.0.0/8 dan 2002:: / 16 melalui jaringan VPN</string> - <string name="custom_route_message_excluded">Routes that should NOT be routed over the VPN. Use the same syntax as for included routes.</string> - <string name="custom_routes_title">Rute buatan sendiri</string> - <string name="custom_routes_title_excluded">Jaringan Dikecualikan</string> - <string name="log_verbosity_level">Tingkat rincian catatan</string> - <string name="float_summary">Ijinkan paket terotentifikasi dari semua IP</string> - <string name="float_title">Ijinkan server mengambang</string> - <string name="custom_options_title">Pilihan buatan</string> - <string name="edit_vpn">Ubah seting OpenVPN</string> - <string name="remove_vpn_query">Hapus profil \'%s\'?</string> - <string name="tun_error_helpful">Pada beberapa setelan manual gambar ICS izin pada/dev/tun mungkin salah, atau modul tun mungkin hilang sepenuhnya. Untuk gambar CM9, coba perbaiki pilihan kepemilikannya di bawah pengaturan umum</string> - <string name="tun_open_error">Gagal membuka layanan antarmuka TUN</string> - <string name="error">"Kesalahan: "</string> - <string name="clear">Bersihkan</string> - <string name="last_openvpn_tun_config">Membuka interface tun:</string> - <string name="local_ip_info">IPv4 lokal: %1$s/%2$d IPv6: %3$s MTU: %4$d</string> - <string name="dns_server_info">DNS Server: %1$s, Domain: %2$s</string> - <string name="routes_info_incl">Rute: %1$s %2$s</string> - <string name="routes_info_excl">Rute terkecualikan: %1$s %2$s</string> - <string name="routes_debug">Rute LayananVpn telah terpasang: %1$s %2$s</string> - <string name="ip_not_cidr">Memilki informasi antarmuka %1$s dan %2$s, asumsi alamat kedua adalah alamat remote. Menggunakan netmask /32 untuk IP lokal. Mode yang diberikan oleh OpenVPN adalah \"%3$s\".</string> - <string name="route_not_cidr">Tidak masuk akal membuat %1$s dan %2$s sebagai rute IP dengan netmask CIDR, Gunakan /32 sebagai netmask.</string> - <string name="route_not_netip">Rute yang diperbaiki %1$s/%2$s hingga %3$s/%2$s</string> - <string name="keychain_access">Tidak dapat mengakses sertifikat Keychain Android. Dapat disebabkan karena upgrade firmware atau pengembalian backup pengaturan app. Mohon ubah VPN, dan pilih ulang sertifikat berbasis pengaturan dasar agar izin mengakses sertifikat dapat dibuat ulang.</string> - <string name="version_info">%1$s %2$s</string> - <string name="send_logfile">Kirim berkas catatan</string> - <string name="send">Kirim</string> - <string name="ics_openvpn_log_file">Berkas catatan ICS OpenVPN</string> - <string name="copied_entry">Salin catatan masuk ke clipboard</string> - <string name="tap_mode">Mode Tap</string> - <string name="faq_tap_mode">Mode TAP tidak diijinkan tanpa VPN API non admin/root. Karena itu aplikasi ini tidak dapat memberikan dukungan mode TAP</string> - <string name="tap_faq2">Lagi? Becanda? mode Tap benar-benar tidak didukung dan mengirim email menanyakan apakah akan ada dukungan Tap, tidak akan membantu.</string> - <string name="tap_faq3">Untuk ketiga kalinya? Sebenarnya, seseorang bisa menulis emulator TAP berdasarkan tun yang akan menambahkan lapisan2 informasi pengiriman dan lapisan2 informasi penerimaan. Tapi emulator TAP ini juga harus menerapkan ARP dan mungkin klien DHCP. Saya tidak tau apakah ada yang bekerja ke arah ini. Hubungi saya jika Anda ingin memulai menulis kode2 emulator TAP ini.</string> - <string name="faq">FAQ</string> - <string name="copying_log_entries">Menyalin catatan</string> - <string name="faq_copying">Untuk menyalin satu catatan masuk, Tekan dan tahan di catatan masuk. Untuk meyanlin\mengirim seluruh catatan, gunakan opsi Kirim Log. Gunakan tombol perangkat keras jika tidak terlihat di GUI.</string> - <string name="faq_shortcut">Jalan pintas memulai</string> - <string name="faq_howto_shortcut">Anda dapat menempatkan jalan pintas untuk memulai OpenVPN pada desktop Anda. Tergantung pada program homescreen Anda, Anda harus menambahkan jalan pintas atau widget.</string> - <string name="no_vpn_support_image">Gambar Anda tidak mendukung VPNService API, maaf:(</string> - <string name="encryption">Enkripsi</string> - <string name="cipher_dialog_title">Masukkan metode enkripsi</string> - <string name="chipher_dialog_message">Masukkan sandi enkripsi algoritma yang digunakan oleh OpenVPN. Biarkan kosong untuk menggunakan sandi default.</string> - <string name="auth_dialog_message">Masukkan digest otentikasi yang digunakan OpenVPN. Biarkan kosong untuk menggunakan standar digest.</string> - <string name="settings_auth">Otentikasi/Enkripsi</string> - <string name="file_explorer_tab">Penjelajah berkas</string> - <string name="inline_file_tab">Inline File</string> - <string name="error_importing_file">Gagal mengambil berkas</string> - <string name="import_error_message">Tidak dapat mengambil berkas dari filesystem</string> - <string name="inline_file_data">[[Inline file data]]</string> - <string name="opentun_no_ipaddr">TUN tidak dapat dibuka tanpa informasi IP</string> - <string name="menu_import">Ambil profil dari berkas ovpn</string> - <string name="menu_import_short">Ambil</string> - <string name="import_content_resolve_error">Tidak dapat membaca profil yang akan diambil</string> - <string name="error_reading_config_file">Kesalahan membaca berkas konfigurasi</string> - <string name="add_profile">tambah Profil</string> - <string name="import_could_not_open">Tidak dapat menemukan berkas %1$s yang disebut dalam berkas konfigurasi</string> - <string name="importing_config">Mengambil berkas konfigurasi dari sumber %1$s</string> - <string name="import_warning_custom_options">Konfigurasi Anda memiliki beberapa pilihan konfigurasi yang tidak dipetakan ke konfigurasi UI. Pilihan ini ditambahkan sebagai opsi konfigurasi kustom. Konfigurasi kustom ditampilkan di bawah ini:</string> - <string name="import_done">Berkas konfigurasi selesai dibaca.</string> - <string name="nobind_summary">Jangan kaitkan ke alamat dan port lokal</string> - <string name="no_bind">Tidak ada ikatan lokal</string> - <string name="import_configuration_file">Ambil berkas konfigurasi</string> - <string name="faq_security_title">Pertimbangan Keamanan</string> - <string name="faq_security">"Karena OpenVPN adalah sensitif pada isu keamanan, beberapa catatan tentang keamanan dianggap perlu. Semua data pada sdcard pada dasarnya tidak aman. Setiap app dapat membaca (misalnya program ini tidak perlu hak khusus untuk membaca sd-card). Data dari aplikasi ini hanya dapat dibaca oleh aplikasi itu sendiri. Dengan menggunakan opsi impor untuk cacert/cert/kunci dalam file dialog data yang disimpan dalam profil VPN. Profil VPN hanya dapat diakses oleh aplikasi ini. (Jangan lupa untuk menghapus salinan pada sd-card setelah itu). Bahkan meskipun dapat diakses hanya dengan aplikasi ini data masih tidak terenkripsi. Dengan melakukan rooting atau eksploitasi lainnya maka memungkinkan mengambil data. Sandi-sandi (passwords) juga tersimpan dalam teks biasa. Berkas pkcs12 sangat dianjurkan Anda mengimpornya ke android keystore."</string> - <string name="import_vpn">Impor</string> - <string name="broken_image_cert_title">Kesalahan menampilkan sertifikat</string> - <string name="broken_image_cert">Mendapat pesan kesalahan saat berusaha menampilkan layar pemilihan sertifikat Android 4.0+. Ini seharusnya tidak terjadi karena ini fitur standar Android 4.0 +. Mungkin ROM Android anda yang mengurus penyimpanan sertifikat rusak</string> - <string name="ipv4">IPv4</string> - <string name="ipv6">IPv6</string> - <string name="speed_waiting">Menunggu pesan status…</string> - <string name="converted_profile">Profil yang diambil</string> - <string name="converted_profile_i">profil yang diambil %d</string> - <string name="broken_images">Gambar rusak</string> - <string name="broken_images_faq">Image HTC yang resmi diketahui memiliki masalah routing yang ganjilyang menyebabkan trafik data tidak melalui tunnel (Lihat di <a href=\"http://code.google.com/p/ics-openvpn/issues/detail?id=18\">Issue 18</a> di bagian bug tracker.))</p><p> Image SONY resmi yang lama dari Xperia Arc S and Xperia Ray telah dilaporkan tidak memiliki VPNService dalam Imagenya. (Lihat juga <a href=\"http://code.google.com/p/ics-openvpn/issues/detail?id=29\">Issue 29</a> di bagian bug tracker.))</p><p>Pada image yang dibuat non resmi, modul TUN mungkin tak ada atau hak /dev/tun mungkin salah. Beberapa image CM9 memerlukan pilihan \"Fix ownership\" di bagian \"Device specific hacks\" diaktfikan. .</p><p> Lebih penting lagi, jika device anda memiliki image android yang lengkap, laporkan pada vendor anda. Semakin banyak laporan masuk, semakin tinggi kemungkinan vendor melakukan perbaikan.</p></string> - <string name="pkcs12_file_encryption_key">Berkas kunci enkripsi PKCS12</string> - <string name="private_key_password">Sandi kunci pribadi</string> - <string name="password">Sandi</string> - <string name="file_icon">ikon berkas</string> - <string name="tls_authentication">TLS Authentication / Enkripsi</string> - <string name="generated_config">Konfigurasi Dibuat</string> - <string name="generalsettings">Pengaturan</string> - <string name="owner_fix_summary">Mencoba menetapkan pemilik /dev/tun ke sistem. Beberapa gambar CM9 memerlukan ini untuk membuat API VPNService bekerja. Memerlukan akses Root.</string> - <string name="owner_fix">Perbaiki kepemilikan /dev/tun</string> - <string name="generated_config_summary">Tunjukkan berkas konfigurasi OpenVPN yang dibuat</string> - <string name="edit_profile_title">Mengubah \"%s\"</string> - <string name="building_configration">Membuat konfigurasi…</string> - <string name="netchange_summary">Menyalakan pilihan ini akan memaksa menyambung kembali jika keadaan jaringan berubah (misalnya WiFi dari mobile)</string> - <string name="netchange">Koneksi ulang saat ganti jaringan</string> - <string name="netstatus">Status jaringan: %s</string> - <string name="extracahint">Sertifikat CA biasanya kembali dari Android Keystore. Tentukan sertifikat terpisah jika Anda mendapatkan kesalahan verifikasi sertifikat.</string> - <string name="select_file">Pilih</string> - <string name="keychain_nocacert">Tidak ada sertifikat CA yang didapat saat membaca dari Android Keystore. Otentifikasi mungkin gagal</string> - <string name="show_log_summary">Tampilkan jendela catatan saat terkoneksi. Jendela catatan juga dapat diakses melalui status notifikasi</string> - <string name="show_log_window">Tampilkan jendela catatan</string> - <string name="mobile_info">%10$s %9$s berjalan pada %3$s %1$s (%2$s), Android %6$s (%7$s) API %4$d, ABI %5$s, (%8$s)</string> - <string name="error_rsa_sign">Kesalahan masuk dengan kunci Android keystore %1$s: %2$s</string> - <string name="faq_system_dialogs">Peringatan sambungan VPN yang memberitahukan Anda bahwa aplikasi ini dapat mencegat semua lalu lintas dikeluarkan oleh sistem untuk mencegah penyalahgunaan dari sambungan VPNService API.\nPemberitahuan sambungan VPN (simbol kunci) juga dikeluarkan oleh sistem Android untuk memberitahu VPN yang sedang berlangsung. Pada beberapa gambar pemberitahuan ini memainkan suara. \nAndroid memperkenalkan sistem dialog ini untuk keselamatan Anda sendiri dan memastikan bahwa mereka tidak membuat masalah. (Pada beberapa gambar sayangnya ini termasuk peringatan suara)</string> - <string name="faq_system_dialogs_title">Peringatan sambungan dan pemberitahuan melalui suara</string> - <string name="translationby">Terjemah Bahasa Indonesia oleh Dayro</string> - <string name="ipdns">IP dan DNS</string> - <string name="basic">Dasar</string> - <string name="routing">Rute</string> - <string name="obscure">Mengaburkan pengaturan OpenVPN. Biasanya tidak diperlukan.</string> - <string name="advanced">Lanjutan</string> - <string name="export_config_title">Konfigurasi ICS Openvpn</string> - <string name="warn_no_dns">Tidak DNS server yang digunakan. Name Resolution mungkin akan gagal bekerja. Pertimbangkan pengaturan server DNS. Harap dicatat Android akan terus memakai pengaturan proxy untuk koneksi mobile/wifi saat tidak ada server DNS diatur.</string> - <string name="dns_add_error">Tak bisa menambahkan Server DNS \"%1$s\", ditolak oleh sistem: %2$s</string> - <string name="ip_add_error">Tidak bisa mengkonfigurasi IP Address \"%1$s\", ditolak oleh sistem: %2$s</string> - <string name="faq_howto"><p> Ambil konfigurasi yang dapat berjalan (diuji pada komputer Anda atau download dari penyedia/organisasi) </p> <p> Satu file(berkas) saja tanpa tambahan berkas pem/pks12. Anda dapat kirim imel berkas dan membuka lampirannya. Jika Anda memiliki beberapa berkas, salin ke sd-card </p> <p> klik pada lampiran imel atau gunakan ikon folder dalam daftar vpn untuk mengimpor berkas konfigurasi </p> <p> jika ada berkas yang kurang, salin file hilang ke sd-card. </p> <p> klik pada simbol Simpan untuk menambahkan VPN yang diimpor ke daftar VPN </p> <p > Connect VPN dengan mengklik nama VPN </p> <p> jika ada kesalahan atau peringatan di catatan, coba pahami peringatannya dan coba untuk memperbaikinya </p> </string> - <string name="faq_howto_title">Mulai Cepat</string> - <string name="setting_loadtun_summary">Coba pakai tun.ko kernel sebelum mencoba koneksi. Membutuhkan perangkat yang sudah diroot. Google: android superuser</string> - <string name="setting_loadtun">Pakai modul TUN</string> - <string name="importpkcs12fromconfig">Ambil PKCS12 dari konfigurasi ke Android Keystore</string> - <string name="getproxy_error">Gagal mendapatkan pengaturan proxy: %s</string> - <string name="using_proxy">Menggunakan proxy %1$s %2$s</string> - <string name="use_system_proxy">Gunakan sistem proxy</string> - <string name="use_system_proxy_summary">Gunakan konfigurasi lebih luas untuk menyambung system melalui proxy HTTP/HTTPS</string> - <string name="onbootrestartsummary">OpenVPN akan menghubungkan VPN ditentukan apakah itu aktif di sistem boot. Silakan baca koneksi peringatan FAQ sebelum menggunakan opsi ini pada Android < 5.0.</string> - <string name="onbootrestart">Minatosuki</string> - <string name="ignore">Abaikan</string> - <string name="restart">Restart</string> - <string name="restart_vpn_after_change">Perubahan konfigurasi baru diterapkan setelah restart VPN. Restart VPN sekarang?</string> - <string name="configuration_changed">Konfigurasi berubah</string> - <string name="log_no_last_vpn">Tak bisa menentukan profil terhubung terakhir untuk diubah</string> - <string name="faq_duplicate_notification_title">Pemberitahuan berganda</string> - <string name="faq_duplicate_notification">Jika Android kekurangan sistem memori (RAM), aplikasi dan layanan yang tidak diperlukan pada saat itu akan dihapus dari memori aktif. Sambungan VPN yang sedang aktif juga ditutup. Untuk memastikan bahwa sambungan/OpenVPN tetap berjalan, OpenVPN diberikan prioritas yang lebih tinggi. Untuk menjalankan dengan prioritas lebih tinggi, aplikasi harus menampilkan pemberitahuan. Ikon pemberitahuan dijalankan oleh sistem seperti dijelaskan dalam FAQ entri sebelumnya. Ini tidak dihitung sebagai pemberitahuan app yang berjalan dengan prioritas lebih tinggi.</string> - <string name="no_vpn_profiles_defined">Tak ada profil VPN yang didefinisikan.</string> - <string name="add_new_vpn_hint">Gunakan ikon < img src = \"ic_menu_add\" / > untuk menambah VPN baru</string> - <string name="vpn_import_hint">Gunakan ikon < img src = \"ic_menu_archive\" / > untuk mengimpor profil (.ovpn atau .conf) yang ada dari sdcard Anda.</string> - <string name="faq_hint">Pastikan untuk juga memeriksa FAQ. Ada petunjuk untuk memudahkan anda.</string> - <string name="faq_routing_title">Konfigurasi rute\antarmuka</string> - <string name="faq_routing">Konfigurasi Routing dan antarmuka tidak dilakukan melalui perintah ifconfig/rute tradisional tetapi dengan menggunakan VPNService API. Ini hasil dalam konfigurasi perutean berbeda daripada pada OS lain. \nThe konfigurasi VPN terowongan terdiri dari alamat IP dan jaringan yang harus dialihkan melalui antarmuka ini. Terutama, tidak ada rekan mitra alamat atau alamat gateway adalah diperlukan atau diperlukan. Khusus rute untuk mencapai VPN Server (misalnya ditambahkan dengan menggunakan redirect-gateway) tidak diperlukan baik. Aplikasi akibatnya akan mengabaikan pengaturan ini ketika mengimpor konfigurasi. App menjamin dengan VPNService API bahwa koneksi ke server tidak diarahkan melalui VPN terowongan. \nThe VPNService API tidak memungkinkan menentukan jaringan yang tidak dapat diteruskan melalui VPN. Sebagai solusi app mencoba untuk mendeteksi jaringan yang tidak dapat diteruskan melalui terowongan (misalnya rute x.x.x.x y.y.y.y net_gateway) dan menghitung seperangkat rute yang mengecualikan ini rute untuk meniru perilaku platform lainnya. Jendela log menunjukkan konfigurasi VPNService berdasarkan membangun koneksi. \nBehind adegan: Android 4,4 + menggunakan kebijakan routing. Menggunakan rute ifconfig tidak akan menunjukkan rute yang diinstal. Alih-alih menggunakan aturan ip, iptables -t mangle -L</string> - <string name="persisttun_summary">Jangan kembali ke status tidak ada koneksi VPN ketika OpenVPN mencoba terhubung kembali.</string> - <string name="persistent_tun_title">Paksa mode TUN</string> - <string name="openvpn_log">Catatan OpenVPN</string> - <string name="import_config">Ambil konfigurasi VPN</string> - <string name="battery_consumption_title">Konsumsi baterai</string> - <string name="baterry_consumption">Berdasarkan tes pribadi, alasan utama tingginya konsumsi baterai oleh OpenVPN adalah paket keepalive. Sebagian besar server OpenVPN memiliki parameter konfigurasi seperti \'keepalive 10 60\' yang membuat klien dan server bertukar paket keepalive setiap 10 detik. <p> Dengan kecilnya paket ini dan tidak memakai trafik terlalu banyak, mereka menjaga jaringan radio mobile tetap sibuk dan meningkatkan konsumsi energi. (See also <a href=\"http://developer.android.com/training/efficient-downloads/efficient-network-access.html#RadioStateMachine\">The Radio State Machine | Android Developers</a>) <p> Seting keepalive ini tidak bisa dirubah di klien. Hanya Admin sistem OpenVPN yang dapat merubah seting ini. <p> Sayangnya membuat keepalive lebih besar dari 60 detik tanpa UDP dapat membuat beberapa gateway NAT memutus koneksi karena anggapan tidak ada aktifitas pada periode tertentu (timeout). Memakai TCP dengan waktu timeout lebih lama dapat bekerja, tapi membuat tunnel TCP di jalur TCP menyebabkan koneksi yang buruk dan tingginya angka kehilangan paket data ((See <a href=\"http://sites.inka.de/bigred/devel/tcp-tcp.html\">Why TCP Over TCP Is A Bad Idea</a>)</string> - <string name="faq_tethering">Fitur penggandengan Android (melalui WiFi, USB atau Bluetooth) dan API VPNService (digunakan oleh program ini) tidak bekerja bersama-sama. Untuk keterangan lanjut lihat < href=\"http://code.google.com/p/ics-openvpn/issues/detail?id=34\" > mengeluarkan #34 </a></string> - <string name="vpn_tethering_title">VPN dan penarikan</string> - <string name="connection_retries">Mengulang koneksi</string> - <string name="reconnection_settings">Pengaturan rekoneksi</string> - <string name="connectretrymessage">Jumlah detik untuk menunggu antar usaha koneksi</string> - <string name="connectretrywait">Detik antar koneksi</string> - <string name="minidump_generated">OpenVPN crash tak terduga. Silakan mempertimbangkan mengirim menggunakan pilihan Minidump di Menu Utama</string> - <string name="send_minidump">Mengirim MiniDump untuk pengembang</string> - <string name="send_minidump_summary">Mengirim informasi debug tentang kegagalan aplikasi yang terakhir ke pengembang</string> - <string name="notifcation_title">OpenVPN - %s</string> - <string name="session_ipv4string">%1$s - %2$s</string> - <string name="session_ipv6string">%1$s - %3$s, %2$s</string> - <string name="state_connecting">Menghubungkan</string> - <string name="state_wait">Menunggu jawaban server</string> - <string name="state_auth">Melakukan otentifikasi</string> - <string name="state_get_config">Mengambil konfigurasi klien</string> - <string name="state_assign_ip">Menetapkan alamat IP</string> - <string name="state_add_routes">Menambahkan rute</string> - <string name="state_connected">Terhubung</string> - <string name="state_disconnected">Putus</string> - <string name="state_reconnecting">Menghubungkan kembali</string> - <string name="state_exiting">Keluar</string> - <string name="state_noprocess">Tidak berjalan</string> - <string name="state_resolve">Mengenali nama host</string> - <string name="state_tcp_connect">Menghubungkan (TCP)</string> - <string name="state_auth_failed">Otentifikasi gagal</string> - <string name="state_nonetwork">Menunggu jaringan yang dapat dipakai</string> - <string name="statusline_bytecount">↓%2$s/s %1$s - ↑%4$s/s %3$s</string> - <string name="notifcation_title_notconnect">Tidak terhubung</string> - <string name="start_vpn_title">Menghubungkan ke VPN %s</string> - <string name="start_vpn_ticker">Menghubungkan ke VPN %s</string> - <string name="jelly_keystore_alphanumeric_bug">Beberapa versi Android 4.1 memiliki masalah jika nama sertifikat keystore berisi karakter non alfanumerik (seperti spasi, garis bawah atau tanda hubung). Cobalah import ulang sertifikat tanpa karakter khusus</string> - <string name="encryption_cipher">Enkripsi sandi</string> - <string name="packet_auth">Otentikasi paket</string> - <string name="auth_dialog_title">Masukkan metode otentikasi paket</string> - <string name="built_by">dibangun oleh %s</string> - <string name="debug_build">Pengembangan debug</string> - <string name="official_build">Build Resmi</string> - <string name="make_selection_inline">Salin ke profil</string> - <string name="crashdump">Data saat terjadi crash</string> - <string name="add">Tambahkan</string> - <string name="send_config">Mengirim config file</string> - <string name="complete_dn">DN lengkap</string> - <string name="remotetlsnote">Konfigurasi yang diimpor menggunakan opsi tls-remote DEPRECATED tua dengan menggunakan format DN yang berbeda.</string> - <string name="rdn">RDN (nama umum)</string> - <string name="rdn_prefix">RDN awalan</string> - <string name="tls_remote_deprecated">TLS-remote (DEPRECATED)</string> - <string name="help_translate">Anda dapat membantu menerjemahkan dengan mengunjungi http://crowdin.net/project/ics-openvpn/invite</string> - <string name="prompt">%1$s berusaha mengendalikan %2$s</string> - <string name="remote_warning">Dengan melanjutkan, Anda memberi izin aplikasi untuk sepenuhnya mengontrol OpenVPN untuk Android dan untuk mencegat semua lalu lintas jaringan. <b>Jangan terima kecuali Anda mempercayai aplikasi.</b> Jika tidak, data Anda beresiko diambil oleh perangkat lunak jahat.\"</string> - <string name="remote_trust">Saya percaya aplikasi ini.</string> - <string name="no_external_app_allowed">App tidak diizinkan untuk menggunakan API eksternal</string> - <string name="allowed_apps">apps yang diijinkan : %s</string> - <string name="clearappsdialog">Hapus daftar aplikasi eksternal yang dibolehkan? \nDaftar apps yang dibolehkan terkini:\n\n%s </string> - <string name="screenoff_summary">\"Pause VPN ketika layar off dan data yang ditransfer dalam 60 detik kurang dari 64kB. Ketika opsi \"Persistent Tun\" diaktifkan, memberhentikan VPN akan membuat perangkat Anda tidak memiliki koneksi jaringan. Jika tidak memakai \"Persistent Tun\" maka perangkat akan menampilkan Tidak ada koneksi VPN.</string> - <string name="screenoff_title">Sambungan VPN jeda setelah layar mati</string> - <string name="screenoff_pause">Hentikan sambungan dalam kondisi layar mati: kurang dari %1$s dalam %2$ss</string> - <string name="screen_nopersistenttun">Peringatan: Pemaksaan tun tidak diaktifkan untuk VPN ini. Lalu lintas akan menggunakan koneksi Internet normal ketika layar dimatikan.</string> - <string name="save_password">Menyimpan sandi</string> - <string name="pauseVPN">Jeda VPN</string> - <string name="resumevpn">Lanjutkan VPN</string> - <string name="state_userpause">Pause VPN diminta oleh pengguna</string> - <string name="state_screenoff">VPN dijeda - layar off</string> - <string name="device_specific">Perangkat dengan spesifikasi Hacks</string> - <string name="cannotparsecert">Tidak dapat menampilkan informasi sertifikat</string> - <string name="appbehaviour">Prilaku Aplikasi</string> - <string name="vpnbehaviour">Prilaku VPN</string> - <string name="allow_vpn_changes">Memungkinkan perubahan Profil VPN</string> - <string name="hwkeychain">Hardware Keystore:</string> - <string name="permission_icon_app">Ikon aplikasi mencoba menggunakan OpenVPN untuk Android</string> - <string name="faq_vpndialog43">"Dimulai dengan Android 4.3 konfirmasi VPN dijaga terhadap\" overlay apps \". Hal ini menyebabkan dialog tidak bereaksi menyentuh input. Jika Anda memiliki sebuah aplikasi yang menggunakan lapisan itu dapat menyebabkan perilaku ini. Jika Anda menemukan kontak aplikasi menyinggung penulis app. Masalah ini mempengaruhi semua aplikasi VPN di Android 4.3 dan kemudian. Lihat juga <a href=\"https://github.com/schwabe/ics-openvpn/issues/185\"> Issue 185 <a> untuk rincian tambahan "</string> - <string name="faq_vpndialog43_title">VPN Konfirmasi Dialog</string> - <string name="donatePlayStore">Atau Anda dapat mengirimkan saya donasi dengan Play Store:</string> - <string name="thanks_for_donation">Terima kasih untuk menyumbangkan %s!</string> - <string name="logCleared">Log dibersihkan.</string> - <string name="show_password">Tampilkan sandi</string> - <string name="keyChainAccessError">Keychain Akses error: %s</string> - <string name="timestamp_short">Pendek</string> - <string name="timestamp_iso">ISO</string> - <string name="timestamps">Cap waktu</string> - <string name="timestamps_none">Tak satupun</string> - <string name="uploaded_data">Upload</string> - <string name="downloaded_data">Unduh</string> - <string name="vpn_status">Vpn Status</string> - <string name="logview_options">Lihat pilihan</string> - <string name="unhandled_exception">Tertangani pengecualian: %1$s \ n \ n%2$s</string> - <string name="unhandled_exception_context">%3$s: %1$s \ n \ n%2$s</string> - <string name="faq_system_dialog_xposed">Jika Anda telah berakar perangkat Android Anda Anda dapat menginstal <a href="http://xposed.info/"> Xposed kerangka </a> dan <a href = "http://repo.xposed.info/ modul / de.blinkt.vpndialogxposed "> VPN Dialog mengkonfirmasi modul </a> risiko Anda sendiri\"</string> - <string name="full_licenses">Lisensi penuh</string> - <string name="blocklocal_summary">Jaringan langsung terhubung ke antarmuka lokal tidak akan diarahkan melalui VPN. Tidak memilih opsi ini akan mengarahkan semua lalu lintas menjorok untuk jaringan lokal ke VPN.</string> - <string name="blocklocal_title">Bypass VPN for local networks</string> - <string name="userpw_file">Username Password File /</string> - <string name="imported_from_file">[Impor dari: %s]</string> - <string name="files_missing_hint">Beberapa file tidak dapat ditemukan. Silakan pilih file untuk mengimpor profil:</string> - <string name="openvpn_is_no_free_vpn">Untuk menggunakan aplikasi ini Anda membutuhkan penyedia VPN / gateway VPN mendukung OpenVPN (sering disediakan oleh majikan Anda). Periksa http://community.openvpn.net/ untuk informasi lebih lanjut tentang OpenVPN dan cara men-setup OpenVPN server Anda sendiri.</string> - <string name="import_log">Log impor:</string> - <string name="ip_looks_like_subnet">Vpn topologi \"%3$s\" ditentukan tapi ifconfig %1$s %2$s terlihat lebih seperti alamat IP dengan mask jaringan. Dengan asumsi \"subnet\" topologi.</string> - <string name="mssfix_invalid_value">Nilai menimpa MSS telah menjadi bulat antara 0 dan 9000</string> - <string name="mtu_invalid_value">Nilai penggantian MTU harus bilangan bulat antara 64 dan 9000</string> - <string name="mssfix_value_dialog">Mengumumkan kepada sesi TCP berjalan di atas terowongan bahwa mereka harus membatasi kirim ukuran paket mereka seperti bahwa setelah OpenVPN telah dikemas mereka, sehingga UDP ukuran paket yang OpenVPN mengirim ke rekan-nya tidak akan melebihi jumlah ini byte. (default adalah 1450)</string> - <string name="mssfix_checkbox">Mengganti nilai MSS TCP muatan</string> - <string name="mssfix_dialogtitle">Mengatur muatan MSS TCP</string> - <string name="client_behaviour">Perilaku klien</string> - <string name="clear_external_apps">Menghapus aplikasi eksternal diizinkan</string> - <string name="loading">Memuat…</string> - <string name="allowed_vpn_apps_info">Yang diizinkan aplikasi VPN: %1$s</string> - <string name="disallowed_vpn_apps_info">Batasan VPN apps: %1$s</string> - <string name="app_no_longer_exists">Paket %s tidak lagi diinstall, menghapus itu dari app memungkinkan/melarang daftar</string> - <string name="vpn_disallow_radio">VPN digunakan untuk semua aplikasi tapi mengecualikan yang dipilih</string> - <string name="vpn_allow_radio">VPN digunakan untuk hanya untuk aplikasi yang dipilih</string> - <string name="query_delete_remote">Hapus entri server jauh?</string> - <string name="keep">Biarkan</string> - <string name="delete">Hapus</string> - <string name="add_remote">Menambahkan baru remote</string> - <string name="remote_random">Gunakan entri koneksi secara acak pada koneksi</string> - <string name="remote_no_server_selected">Anda harus menentukan dan memungkinkan setidaknya satu server jauh.</string> - <string name="server_list">Daftar Server</string> - <string name="vpn_allowed_apps">Diizinkan Apps</string> - <string name="payload_options">Muatan pilihan</string> - <string name="tls_settings">Pengaturan TLS</string> - <string name="no_remote_defined">Didefinisikan Tidak ada remote</string> - <string name="duplicate_vpn">Profil duplikat VPN</string> - <string name="duplicate_profile_title">Duplikasi profil: %s</string> - <string name="show_log">Tampilkan log</string> - <string name="faq_android_clients">Ada beberapa klien OpenVPN untuk Android. Yang paling umum adalah OpenVPN untuk Android (ini klien), OpenVPN Connect dan OpenVPN pengaturan. < p > klien dapat dikelompokkan menjadi dua kelompok: OpenVPN untuk Android dan OpenVPN Connect menggunakan API VPNService resmi (Android 4.0 +) dan memerlukan tanpa akar dan pengaturan OpenVPN yang menggunakan akar. < p > OpenVPN untuk Android adalah klien sumber terbuka dan dikembangkan oleh Arne Schwabe. Ini ditargetkan untuk pengguna yang lebih maju dan menawarkan banyak pengaturan dan kemampuan untuk mengimpor profil dari file dan mengkonfigurasi/Ubah profil di dalam app. Klien didasarkan pada versi komunitas OpenVPN. Hal ini didasarkan pada kode sumber 2.x OpenVPN. Klien ini dapat dilihat sebagai semi resmi klien masyarakat. < p > OpenVPN Connect adalah klien sumber terbuka bebas yang dikembangkan oleh OpenVPN Technologies, Inc Klien indentasi untuk penggunaan umum klien dan moree ditargetkan untuk pengguna rata-rata dan memungkinkan impor OpenVPN profil. Klien ini didasarkan pada reimplementation OpenVPN C++ OpenVPN Protokol (ini diperlukan untuk memungkinkan OpenVPN Technologies, Inc untuk menerbitkan sebuah aplikasi OpenVPN iOS). Klien ini adalah resmi klien OpenVPN teknologi < p > OpenVPN pengaturan tertua klien dan juga UI untuk open source OpenVPN. Berbeda dengan OpenVPN untuk Android itu memerlukan akar dan tidak menggunakan VPNService API. Tidak tergantung pada Android 4.0 +</string> - <string name="faq_androids_clients_title">Perbedaan antara klien OpenVPN Android</string> - <string name="ignore_multicast_route">Mengabaikan rute multicast: %s</string> - <string name="ab_only_cidr">Android hanya mendukung rute CIDR ke VPN. Sejak non-CIDR rute yang hampir tidak pernah digunakan, OpenVPN untuk Android akan menggunakan / 32 untuk rute yang tidak CIDR dan mengeluarkan peringatan.</string> - <string name="ab_tethering_44">Penarikan bekerja sementara VPN aktif. Ditambatkan sambungan tidak akan menggunakan VPN.</string> - <string name="ab_kitkat_mss">Versi KitKat awal menetapkan nilai MSS salah pada TCP koneksi (# 61948). OpenVPN untuk secara otomatis mengaktifkan mssfix pilihan untuk solusi bug ini.</string> - <string name="ab_proxy">Android akan tetap menggunakan pengaturan proxy Anda ditentukan untuk mobile koneksi / Wi-Fi ketika tidak ada server DNS diatur. OpenVPN untuk Android akan memperingatkan Anda tentang hal ini dalam log. <p> Ketika VPN menetapkan server DNS Android tidak akan proxy. Tidak ada API untuk mengatur proxy untuk koneksi VPN. </p></string> - <string name="ab_lollipop_reinstall">Aplikasi VPN dapat berhenti bekerja ketika dihapus dan diinstal ulang lagi. Untuk jelasnya lihat # 80074</string> - <string name="ab_not_route_to_vpn">IP klien dikonfigurasi dan IP di topeng jaringan tidak diteruskan ke VPN. OpenVPN bekerja di sekitar bug ini dengan secara eksplisit menambahkan rute yang corrosponds ke IP klien dan netmask nya</string> - <string name="ab_persist_tun">Membuka perangkat tun saat perangkat tun lain sedang aktif, yang digunakan untuk dukungan bertahan-tun, crash VPNServices pada perangkat. A reboot diperlukan untuk membuat pekerjaan VPN lagi. OpenVPN untuk Android mencoba untuk menghindari membuka kembali perangkat tun dan jika benar-benar diperlukan pertama menutup TUN saat sebelum membuka perangkat TUN baru untuk menghindari crash. Hal ini dapat menyebabkan jendela pendek di mana paket dikirim melalui koneksi non-VPN. Bahkan dengan solusi ini VPNServices kadang-kadang crash dan memerlukan reboot perangkat.</string> - <string name="ab_secondary_users">VPN tidak bekerja sama sekali bagi pengguna sekunder.</string> - <string name="ab_kitkat_reconnect">"Beberapa pengguna melaporkan bahwa koneksi mobile / koneksi data mobile sering menjatuhkan saat menggunakan aplikasi VPN. Perilaku tampaknya hanya mempengaruhi beberapa kombinasi perangkat mobile provider / dan sejauh ini tidak ada penyebab / solusi untuk bug dapat diidentifikasi."</string> - <string name="ab_vpn_reachability_44">Hanya tujuan yang bisa dicapai melalui VPN yang bisa dijangkau tanpa VPN. VPN IPv6 tidak bekerja sama sekali.</string> - <string name="ab_only_cidr_title">Rute non CIDR</string> - <string name="ab_proxy_title">Tindakan Proxy untuk VPN</string> - <string name="ab_lollipop_reinstall_title">Menginstal ulang aplikasi VPN</string> - <string name="version_upto">%s dan sebelumnya</string> - <string name="copy_of_profile">Salinan dari %s</string> - <string name="ab_not_route_to_vpn_title">Alihkan ke alamat IP yang telah ditentukan</string> - <string name="ab_kitkat_mss_title">Nilai MSS yang salah untuk koneksi VPN</string> - <string name="ab_secondary_users_title">Pengguna tablet sekunder</string> - <string name="custom_connection_options_warng">Tentukan pengaturan untuk koneksi khusus . Gunakan dengan hati-hati</string> - <string name="custom_connection_options">Pilihan buatan</string> - <string name="remove_connection_entry">Hapus entri koneksi</string> - <string name="ab_kitkat_reconnect_title">Terputus acak dari jaringan selular</string> - <string name="ab_vpn_reachability_44_title">Rangkaian remote tak terjangkau</string> - <string name="ab_persist_tun_title">Modus terowongan bertahan</string> - <string name="version_and_later">%s dan yang lebih baru</string> - <string name="tls_cipher_alert_title">Sambungan gagal dengan peringatan kegagalan jabat tangan SSL23_GET_SERVER_HELLO:sslv3</string> - <string name="tls_cipher_alert">Dyankoclok</string> - <string name="message_no_user_edit">Profil ini telah ditambahkan dari aplikasi eksternal (%s) dan telah ditandai sebagai pengguna tidak dapat diedit.</string> - <string name="crl_file">Certificate Revocation List</string> - <string name="service_restarted">Restart layanan OpenVPN (App jatuh mungkin jatuh atau dibunuh untuk memori tekanan)</string> - <string name="import_config_error">Mengimpor konfigurasi menghasilkan kesalahan, tidak bisa menyimpannya</string> - <string name="Search">Pencarian</string> - <string name="lastdumpdate">(Sampah terakhir adalah %1$d: %2$dh lama (%3$s))</string> - <string name="clear_log_on_connect">Hapus log pada koneksi baru</string> - <string name="connect_timeout">Hubungkan Timeout</string> - <string name="no_allowed_app">Tidak ada aplikasi yang diizinkan ditambahkan Menambahkan diri kita (%s) untuk memiliki setidaknya satu aplikasi dalam daftar aplikasi yang diizinkan agar tidak mengizinkan semua aplikasi</string> - <string name="query_permissions_sdcard">OpenVPN untuk Android dapat mencoba untuk menemukan file yang hilang pada sdcard secara otomatis. Ketuk pesan ini untuk memulai.</string> - <string name="protocol">Protokol</string> - <string name="enabled_connection_entry">Diaktifkan</string> - <string name="abi_mismatch">Preferred native ABI yang diutamakan dari perangkat ini (%1$s) dan ABI dilaporkan oleh perpustakaan asli (%2$s) ketidakcocokan</string> - <string name="permission_revoked">[01.55] Routes excluded: 10.0.0.0/8, *********/32, 172.16.0.0/12, 192.168.0.0/16 </string> - <string name="pushpeerinfo">Info Push Peer</string> - <string name="pushpeerinfosummary">Send extra information to the server, e.g. SSL version and Android version</string> - <string name="pw_request_dialog_title">Butuh %1$s</string> - <string name="pw_request_dialog_prompt">Silakan masukkan sandi untuk profil %1$s</string> - <string name="menu_use_inline_data">Gunakan data inline</string> - <string name="export_config_chooser_title">Ambil berkas konfigurasi</string> - <string name="missing_tlsauth">File tls-auth hilang</string> - <string name="missing_certificates">Sertifikat pengguna atau file kunci pengguna certifcate hilang</string> - <string name="missing_ca_certificate">Sertifikat CA tidak ditemukan</string> - <string name="crl_title">Daftar Pencabutan Certifcate (opsional)</string> - <string name="reread_log">Baca ulang (%d) item log dari file cache log</string> - <string name="samsung_broken">Jjj</string> - <string name="samsung_broken_title">Ponsel Samsung</string> - <string name="novpn_selected">Tidak ada VPN yang dipilih.</string> - <string name="defaultvpn">VPN default</string> - <string name="defaultvpnsummary">VPN digunakan di tempat VPN default dibutuhkan. Ini saat ini sedang boot, Always-On dan Quick Settings Tile.</string> - <string name="vpnselected">VPN yang dipilih saat ini: \'%s\'</string> - <string name="reconnect">Menghubungkan kembali</string> - <string name="qs_title">Toggle VPN</string> - <string name="qs_connect">Menghubungkan ke %s</string> - <string name="qs_disconnect">Memutuskan %s</string> - <string name="connectretrymaxmessage">Masukkan waktu maksimum antara upaya koneksi. OpenVPN secara perlahan akan menaikkan waktu tunggunya setelah usaha koneksi gagal mencapai nilai ini. Default ke 300s.</string> - <string name="connectretrymaxtitle">Waktu maksimum antar upaya koneksi</string> - <string name="state_waitconnectretry">Menunggu %s detik di antara upaya koneksi</string> - <string name="nought_alwayson_warning"><![CDATA[Jika Anda tidak mendapatkan dialog konfirmasi VPN, Anda memiliki \"Always on VPN\" yang diaktifkan untuk aplikasi lain. Dalam hal ini hanya aplikasi yang diizinkan yang terhubung ke VPN. Berikan centang di bawah Settings-> Networks more .. -> VPNS]]></string> - <string name="management_socket_closed">Sambungan ke OpenVPN ditutup (%s)</string> - <string name="change_sorting">Ubah penyortiran</string> - <string name="sort">Urutkan</string> - <string name="sorted_lru">Profil diurutkan berdasarkan terakhir yang terakhir digunakan</string> - <string name="sorted_az">Profil diurutkan berdasarkan nama</string> - <string name="deprecated_tls_remote">Config menggunakan opsi tls-remote yang sudah ditinggalkan di 2.3 dan akhirnya dihapus di 2.4</string> - <string name="auth_failed_behaviour">Perilaku pada AUTH_FAILED</string> - <string name="graph">Grafik</string> - <string name="use_logarithmic_scale">Gunakan skala logaritmik</string> - <string name="notenoughdata">Tidak cukup data</string> - <string name="avghour">Rata-rata per jam</string> - <string name="avgmin">Rata-rata per jam</string> - <string name="last5minutes">5 menit terakhir</string> - <string name="data_in">Masuk</string> - <string name="data_out">Keluar</string> - <string name="bits_per_second">%.0f bit/s</string> - <string name="kbits_per_second">%.1f kbit/s</string> - <string name="mbits_per_second">%.1f Mbit/s</string> - <string name="gbits_per_second">%.1f Gbit/s</string> - <string name="weakmd"><p>Starting with OpenSSL version 1.1, OpenSSL rejects weak signatures in certificates like - MD5.</p><p><b>MD5 signatures are completely insecure and should not be used anymore.</b> MD5 - collisions can be created in <a - href=\"https://natmchugh.blogspot.de/2015/02/create-your-own-md5-collisions.html\">few hours at a minimal cost.</a>. - You should update the VPN certificates as soon as possible.</p><p>Unfortunately, older easy-rsa - distributions included the config option \"default_md md5\". If you are using an old easy-rsa version, update to - the <a href=\"https://github.com/OpenVPN/easy-rsa/releases\">latest version</a>) or change md5 to sha256 and - regenerate your certificates.</p><p>If you really want to use old and broken certificates use the custom - configuration option tls-cipher \"DEFAULT:@SECLEVEL=0\" under advanced configuration or as additional line in your - imported configuration</p> - </string> - <string name="volume_byte">%.0f B</string> - <string name="volume_kbyte">%.1f kB</string> - <string name="volume_mbyte">%.1f MB</string> - <string name="volume_gbyte">%.1f GB</string> -</resources> diff --git a/app/src/main/res/values-in/strings.xml b/app/src/main/res/values-in/strings.xml deleted file mode 100755 index 1d4d6b6659ce7628e0b703d3138c670fbcf4fb11..0000000000000000000000000000000000000000 --- a/app/src/main/res/values-in/strings.xml +++ /dev/null @@ -1,6 +0,0 @@ -<?xml version="1.0" encoding="utf-8"?> -<!--Generated by crowdin.net--> -<!-- Generated by crowdin.net --> -<resources> - <string name="bitmask_log">Catatan Bitmask</string> -</resources> diff --git a/app/src/main/res/values-it/strings.xml b/app/src/main/res/values-it/strings.xml index 2438f7244da1ac31c1971e234c9417f098dfbce9..58ef4de991beb1c5d383b442865e3bc940b89931 100644 --- a/app/src/main/res/values-it/strings.xml +++ b/app/src/main/res/values-it/strings.xml @@ -2,13 +2,15 @@ <resources> <string name="retry">Riprova</string> <string name="repository_url_text">Codice sorgente disponibile all\'indirizzo https://0xacab.org/leap/bitmask_android</string> - <string name="translation_project_text">Le traduzioni sono benvenute e apprezzate. Visitare la pagina del progetto su Transifex https://www.transifex.com/projects/p/bitmask-android/</string> + <string name="translation_project_text">Le traduzioni sono benvenute e apprezzate. Visitare la pagina del progetto su Transifex https://www.transifex.com/projects/p/bitmask/</string> <string name="switch_provider_menu_option">Cambia provider</string> <string name="info">Informazioni</string> <string name="show_connection_details">Visualizza i dettagli della connessione</string> + <string name="connection_details">Dettagli connessione</string> <string name="routes_info">Instradamenti (route): %s</string> <string name="routes_info6">Instradamenti IPv6: %s</string> <string name="error_empty_username">Il nome utente non deve essere vuoto.</string> + <string name="cert_from_keystore">Ottenuto il certificato \'%s\' dal keystore</string> <string name="provider_label">Provider:</string> <string name="provider_label_none">Nessun provider configurato</string> <string name="status_unknown">Stato sconosciuto.</string> @@ -18,6 +20,7 @@ <string name="save">Salva</string> <string name="new_provider_uri">Nome dominio</string> <string name="valid_url_entered">L\'URL è valido</string> + <string name="not_valid_url_entered">URL malformato</string> <string name="provider_details_title">Dettagli provider</string> <string name="use_anonymously_button">Usa in modo anonimo</string> <string name="username_hint">nome utente</string> @@ -28,47 +31,98 @@ <string name="password_mismatch">Le password non corrispondono</string> <string name="user_message">Messaggio utente</string> <string name="about_fragment_title">Informazioni</string> + <string name="error_srp_math_error_user_message">Riprova: Errore matematico del server</string> <string name="error_bad_user_password_user_message">Nome utente o password errati</string> <string name="error_not_valid_password_user_message">Deve essere composta da almeno 8 caratteri</string> <string name="error_client_http_user_message">Riprova: errore Client HTTP</string> <string name="error_io_exception_user_message">Riprova: errore I/O</string> <string name="error_json_exception_user_message">Riprova: risposta errata dal server</string> + <string name="signup_or_login_button">Registrati/Accedi</string> <string name="login_button">Accedi</string> <string name="login_to_profile">Accedi al profilo</string> <string name="logout_button">Disconnetti</string> <string name="signup_button">Iscriviti</string> + <string name="create_profile">Crea profilo</string> <string name="setup_error_title">Errore di Configurazione</string> <string name="setup_error_configure_button">Configura</string> <string name="setup_error_close_button">Esci</string> <string name="malformed_url">Non sembra essere un provider %s.</string> + <string name="service_is_down_error">Il servizio non è disponibile.</string> <string name="configuring_provider">Configurazione provider</string> + <string name="incorrectly_downloaded_certificate_message">Il tuo certificato anonimo non è stato scaricato</string> + <string name="downloading_certificate_message">Download del certificato VPN in corso</string> + <string name="updating_certificate_message">Aggiornamento del certificato VPN in corso</string> <string name="succesful_authentication_message">Autentificato</string> <string name="authentication_failed_message">Autenticazione fallita</string> + <string name="registration_failed_message">Registrazione fallita</string> <string name="eip_status_start_pending">Iniziazione connessione</string> <string name="eip_cancel_connect_title">Annullare la connessione?</string> <string name="eip_cancel_connect_text">C\'è un tentativo di connessione in corso. Vuoi annullarlo?</string> + <string name="eip_state_connected">Connessione sicura</string> + <string name="provider_problem">Sembra esserci stato un problema con il provider.</string> + <string name="try_another_provider">Prova ad usare un altro provider o contatta il tuo.</string> <string name="default_username">Anonimo</string> <string name="logging_in">Accesso in corso</string> + <string name="vpn.button.turn.on">Accendi</string> + <string name="vpn.button.turn.off">Spegni</string> <string name="log_fragment_title">Log</string> <string name="vpn_fragment_title">VPN</string> <string name="navigation_drawer_open">Apri Drawer</string> <string name="navigation_drawer_close">Chiudi drawer</string> <string name="action_settings">Impostazioni</string> + <string name="void_vpn_title">Blocco del traffico in corso</string> + <string name="update_certificate">Aggiorna certificato</string> + <string name="vpn_certificate_is_invalid">Il certificato VPN non è valido. Prova a scaricarne uno nuovo.</string> + <string name="vpn_certificate_user_message">Il certificato VPN non è valido. Accedi per scaricarne uno nuovo.</string> + <string name="save_battery">Risparmio batteria</string> <string name="always_on_vpn">VPN sempre attivo</string> + <string name="subtitle_always_on_vpn">Apri le impostazioni di sistema di Android</string> + <string name="tethering">Hotspot VPN</string> + <string name="ipv6Firewall">Blocca IPv6</string> + <string name="require_root">Richiede i permessi di root</string> + <string name="show_experimental">Mostra funzionalità sperimentali</string> + <string name="hide_experimental">Nascondi funzionalità sperimentali</string> + <string name="experimental_features">Funzionalità sperimentali</string> <string name="tethering_wifi">Hotspot Wi-Fi</string> + <string name="tethering_usb">Tethering USB</string> + <string name="tethering_bluetooth">Tethering Bluetooth</string> + <string name="do_not_show_again">Non mostrare più</string> <string name="donate_title">Fai una donazione</string> <string name="donate_button_remind_later">Ricordamelo più tardi</string> <string name="donate_button_donate">Fai una donazione</string> + <string name="obfuscated_connection_try">Prova di una connessione offuscata in corso</string> <string name="nav_drawer_obfuscated_connection">Utilizza i bridge</string> + <plurals name="subtitle_exclude_apps"> + <item quantity="one">%d app non protetta</item> + <item quantity="other">%d app non protette</item> + </plurals> + <string name="warning_no_more_gateways_no_pt">%s non è riuscito a connettersi. Riprovare?</string> + <string name="warning_option_try_best">Prova la posizione migliore</string> + <string name="warning_option_try_pt">Prova a connetterti in maniera offuscata</string> + <string name="warning_option_try_ovpn">Prova a connetterti normalmente</string> + <string name="qs_enable_vpn">Avvia %s</string> + <string name="version_update_found">Premi qui per iniziare il download.</string> + <string name="version_update_title">Una nuova versione %s è stata trovata.</string> + <string name="version_update_apk_description">Scaricamento della nuova versione %s in corso</string> + <string name="version_update_download_description">Premi qui per installare l\'aggiornamento.</string> + <string name="version_update_error">Aggiornamento fallito.</string> + <string name="version_update_error_permissions">Permessi insufficienti per installare l\'app.</string> <string name="gateway_selection_title">Seleziona il percorso</string> <string name="gateway_selection_recommended">Raccomandate</string> + <string name="gateway_selection_manually">Seleziona manualmente</string> + <string name="gateway_selection_automatic_location">Usa automaticamente la connessione migliore</string> <string name="gateway_selection_automatic">Automatica</string> + <string name="reconnecting">Riconnessione in corso...</string> + <string name="tor_stopping">Arresto dei bridges in corso</string> + <string name="log_conn_done_pt">Connesso ad un pluggable transport</string> <string name="log_onehop_create">Sto creando una connessione cifrata alla directory</string> <string name="log_loading_keys">Caricamento dei certificati delle authority</string> <string name="log_circuit_create">Sto creando un circuito Tor</string> <string name="log_done">Attivo</string> <string name="hide">Nascosto</string> + <string name="censorship_circumvention">Aggirare la censura</string> <string name="use_snowflake">Usa Snowflake</string> + <string name="prefer_udp">Utilizza UDP se disponibile</string> <string name="advanced_settings">Impostazioni avanzate</string> <string name="cancel_connection">Disconnetti</string> </resources> diff --git a/app/src/main/res/values-ja/strings.xml b/app/src/main/res/values-ja/strings.xml index f029bda99fb44b9d0eb77eaee353f6d83742a907..015772ed9ef7e3a6a963c652900d09f097aa7641 100644 --- a/app/src/main/res/values-ja/strings.xml +++ b/app/src/main/res/values-ja/strings.xml @@ -3,7 +3,7 @@ <string name="retry">再試行</string> <string name="repository_url_text">ソースコードは https://0xacab.org/leap/bitmask_android で利用できます</string> <string name="leap_tracker">問題トラッカーは https://0xacab.org/leap/bitmask_android/issues で利用できます</string> - <string name="translation_project_text">翻訳を歓迎、感謝します。 Transifex プロジェクトをご覧ください https://www.transifex.com/projects/p/bitmask-android/</string> + <string name="translation_project_text">翻訳を歓迎、感謝します。 Transifex プロジェクトをご覧ください https://www.transifex.com/projects/p/bitmask/</string> <string name="switch_provider_menu_option">プロバイダーを切り替え</string> <string name="info">情報</string> <string name="show_connection_details">接続の詳細を表示</string> @@ -138,7 +138,7 @@ <string name="warning_no_more_gateways_use_pt">%sは接続できませんでした。 VPN接続がブロックされている可能性があります。難読化された接続を使用して接続を試みますか?</string> <string name="warning_no_more_gateways_no_pt">%s は接続できませんでした。 再試行しますか?</string> <string name="warning_no_more_gateways_use_ovpn">%s は難読化されたVPN接続を使用して接続できませんでした。標準VPNを使用して接続を試みますか?</string> - <string name="warning_no_more_gateways_manual_gw_selection">%1$sは%2$sへ接続できませんでした。最適な場所と自動的な接続を試みますか?</string> + <string name="warning_no_more_gateways_manual_gw_selection">%1$sは%2$sへ接続できませんでした。最適な場所へ自動的な接続を試みますか?</string> <string name="warning_option_try_best">最適な場所を試みる</string> <string name="warning_option_try_pt">難読化された接続を試みる</string> <string name="warning_option_try_ovpn">標準接続を試みる</string> @@ -155,6 +155,7 @@ <string name="version_update_error_permissions">アプリをインストールする権限がありません。</string> <string name="gateway_selection_title">場所を選択</string> <string name="gateway_selection_recommended_location">推奨の場所</string> + <string name="gateway_selection_recommended">推奨</string> <string name="gateway_selection_manually">手動で選択</string> <string name="gateway_selection_automatic_location">自動的に最適な接続を使用</string> <string name="gateway_selection_automatic">自動</string> @@ -162,17 +163,34 @@ <string name="tor_starting">検閲を回避するためにブリッジを起動中…</string> <string name="tor_stopping">ブリッジを停止</string> <string name="tor_started">検閲を回避するためにブリッジを使用</string> + <string name="log_conn_done_pt">pluggable transportへ接続しました</string> + <string name="log_conn_pt">pluggable transportへ接続中です</string> + <string name="log_conn_done">中継へ接続しました</string> + <string name="log_handshake">中継と接続をネゴシエート中です</string> + <string name="log_handshake_done">中継と接続をネゴシエートしました</string> <string name="log_onehop_create">暗号化されたディレクトリとの接続を確立中</string> <string name="log_loading_keys">認証局の署名を読込中</string> + <string name="log_requesting_descriptors">中継の記述子を尋ねています</string> + <string name="log_loading_descriptors">中継の記述子を読み込み中です</string> + <string name="log_ap_handshake_done">中継で回路を構築するネゴシエーションが終了しました</string> <string name="log_circuit_create">Tor サーキットを設置しています</string> <string name="log_done">実行中</string> <string name="hide">隠す</string> + <string name="error_network_connection">%sはインターネット接続がありません。WiFiとセルラーデータの設定を確認してください。</string> <string name="censorship_circumvention">検閲を回避</string> <string name="use_snowflake">Snowflake を使用</string> + <string name="snowflake_description">検閲から設定処理を保護する。</string> <string name="vpn_settings">VPN設定</string> <string name="prefer_udp">利用可能であればUDPを使用</string> <string name="prefer_udp_subtitle">UDPは高速になり、ストリーミングに好ましいですが、ネットワークのすべてには動作しません。</string> <string name="disabled_while_bridges_on">ブリッジ使用中に無効化されます。</string> + <string name="hint_bridges">現在選択できるのは、ブリッジをサポートしている場所のみです。</string> + <string name="option_disable_bridges">ブリッジを無効化</string> + <string name="eip_state_insecure">接続は安全ではありません</string> + <string name="connection_not_connected">あなたのインターネットプロバイダまたはローカルネットワークに情報が漏洩するかもしれません。</string> + <string name="eip_state_no_network">インターネットに接続できない状態です。インターネット接続が戻れば、自動的に接続します</string> + <string name="eip_state_blocking">%1$sはすべてのインターネット転送をプロックしています。</string> + <string name="disabled_while_udp_on">UDPがオンの間は無効化されます。</string> <string name="advanced_settings">詳細な設定</string> <string name="cancel_connection">切断</string> </resources> diff --git a/app/src/main/res/values-kn-rIN/strings.xml b/app/src/main/res/values-kn-rIN/strings.xml deleted file mode 100644 index f41e1aa39d746bfa8fae42572db13f1c9ae8119a..0000000000000000000000000000000000000000 --- a/app/src/main/res/values-kn-rIN/strings.xml +++ /dev/null @@ -1,11 +0,0 @@ -<?xml version='1.0' encoding='UTF-8'?> -<resources> - <string name="retry">ಪುನಃ ಪ್ರಯತ್ನಿಸಿ</string> - <string name="switch_provider_menu_option">ಸೇವೆ ಒದಗಿಸುವವರನ್ನು ಬದಲಾಯಿಸಿ </string> - <string name="info">ಮಾಹಿತಿ</string> - <string name="show_connection_details">ಸಂಪರ್ಕದ ವಿವರಗಳನ್ನು ತೋರಿಸಿ</string> - <string name="routes_info">ಮಾರ್ಗಗಳು: %s</string> - <string name="error_empty_username">ಬಳಕೆದಾರರ ಹೆಸರು ಖಾಲಿ ಇರಬಾರದು.</string> - <string name="succesful_authentication_message">ದೃಢೀಕರಿಸಲಾಗಿದೆ</string> - <string name="eip_cancel_connect_title">ಸಂಪರ್ಕವನ್ನು ರದ್ದುಗೋಳಿಸಿ?</string> -</resources> diff --git a/app/src/main/res/values-ko/arrays.xml b/app/src/main/res/values-ko/arrays.xml deleted file mode 100644 index 045e125f3d8dad8668061d471dd9869e29e4713a..0000000000000000000000000000000000000000 --- a/app/src/main/res/values-ko/arrays.xml +++ /dev/null @@ -1,3 +0,0 @@ -<?xml version="1.0" encoding="utf-8"?> -<resources> -</resources> diff --git a/app/src/main/res/values-ko/plurals-icsopenvpn.xml b/app/src/main/res/values-ko/plurals-icsopenvpn.xml deleted file mode 100755 index 9f02b893ab60d4a627e8bc6a66311b8255c0202c..0000000000000000000000000000000000000000 --- a/app/src/main/res/values-ko/plurals-icsopenvpn.xml +++ /dev/null @@ -1,16 +0,0 @@ -<?xml version="1.0" encoding="utf-8"?> -<!--Generated by crowdin.com--> -<resources> - <plurals name="months_left"> - <item quantity="other">%d 개월 남음</item> - </plurals> - <plurals name="days_left"> - <item quantity="other">%d 일 남음</item> - </plurals> - <plurals name="hours_left"> - <item quantity="other">%d 시간 남음</item> - </plurals> - <plurals name="minutes_left"> - <item quantity="other">%d 분 남음</item> - </plurals> -</resources> diff --git a/app/src/main/res/values-ko/strings-icsopenvpn.xml b/app/src/main/res/values-ko/strings-icsopenvpn.xml deleted file mode 100755 index 4292f0de8682819b82e10a5ed3d858b11eb7e60f..0000000000000000000000000000000000000000 --- a/app/src/main/res/values-ko/strings-icsopenvpn.xml +++ /dev/null @@ -1,473 +0,0 @@ -<?xml version="1.0" encoding="utf-8"?> -<!--Generated by crowdin.com--> -<!-- - ~ 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> - - <string name="address">서버 주소:</string> - <string name="port">서버 포트:</string> - <string name="location">위치</string> - <string name="cant_read_folder">디렉토리를 읽을 수 없습니다</string> - <string name="select">선택</string> - <string name="cancel">취소</string> - <string name="no_data">데이터 없음</string> - <string name="useLZO">LZO 압축</string> - <string name="client_no_certificate">인증서 없음</string> - <string name="client_certificate_title">클라이언트 인증서</string> - <string name="client_key_title">클라이언트 인증서 키</string> - <string name="client_pkcs12_title">PKCS12 파일</string> - <string name="ca_title">CA 인증서</string> - <string name="no_certificate">인증서를 선택해야 합니다</string> - <string name="copyright_guicode">소스 코드와 문제 추적기는 http://code.google.com/p/ics-openvpn/ 에서 사용할 수 있습니다</string> - <string name="copyright_others">이 프로그램은 다음 구성 요소를 사용합니다. 라이선스에 대한 자세한 내용은 소스 코드를 참조하십시오.</string> - <string name="about">소개</string> - <string name="vpn_list_title">프로파일</string> - <string name="vpn_type">유형</string> - <string name="pkcs12pwquery">PKCS12 암호</string> - <string name="file_select">선택…</string> - <string name="file_nothing_selected">파일을 선택해야 합니다</string> - <string name="useTLSAuth">TLS 인증 사용</string> - <string name="tls_direction">TLS 방향</string> - <string name="ipv6_dialog_tile">CIDR 형식의 IPv6 주소/넷마스크를 입력 (예: 2000:dd::23/64)</string> - <string name="ipv4_dialog_title">CIDR 형식의 IPv4 주소/넷마스크를 입력 (예: 1.2.3.4/24)</string> - <string name="ipv4_address">IPv4 주소</string> - <string name="ipv6_address">IPv6 주소</string> - <string name="custom_option_warning">사용자 정의 OpenVPN 옵션을 입력하십시오. 사용시 유의하십시오. 또한 TUN과 연관된 많은 OpenVPN 설정은 안드로이드에서 지원하는 VPN 설정의 한계로 지원되지 않습니다. 중요한 옵션이 누락됐다고 생각되면 개발자에게 연락주십시오.</string> - <string name="auth_username">사용자 이름</string> - <string name="auth_pwquery">암호</string> - <string name="static_keys_info">고정 설정에는 TLS 인증 키가 고정 키로 사용됩니다</string> - <string name="configure_the_vpn">VPN 구성</string> - <string name="menu_add_profile">프로파일 추가</string> - <string name="add_profile_name_prompt">새 프로파일을 식별하는 이름을 입력하세요.</string> - <string name="duplicate_profile_name">고유한 프로파일 이름을 입력하십시오</string> - <string name="profilename">프로파일 이름</string> - <string name="no_keystore_cert_selected">사용자 인증서를 선택해야 합니다</string> - <string name="no_ca_cert_selected">CA 인증서를 선택해야 합니다</string> - <string name="no_error_found">오류 없음</string> - <string name="config_error_found">구성 오류</string> - <string name="ipv4_format_error">IPv4 주소 구문 분석 오류</string> - <string name="custom_route_format_error">사용자 지정 경로 구문 분석 오류</string> - <string name="pw_query_hint">(비워두면 요청시 쿼리됨)</string> - <string name="vpn_shortcut">OpenVPN 바로 가기</string> - <string name="vpn_launch_title">VPN에 연결 중...</string> - <string name="shortcut_profile_notfound">바로가기에 지정된 프로파일을 찾을 수 없습니다.</string> - <string name="random_host_prefix">임의의 호스트 접두사</string> - <string name="random_host_summary">6개 임의의 문자를 호스트 이름 앞에 추가</string> - <string name="custom_config_title">사용자 지정 옵션 사용</string> - <string name="custom_config_summary">사용자 지정 옵션을 지정하세요. 주의해서 사용!</string> - <string name="route_rejected">안드로이드에 의해 거부된 경로</string> - <string name="cancel_connection_long">VPN 연결 끊기</string> - <string name="clear_log">로그 지우기</string> - <string name="title_cancel">취소 확인</string> - <string name="cancel_connection_query">연결된 VPN 끊기/연결 시도 취소?</string> - <string name="remove_vpn">VPN 제거</string> - <string name="check_remote_tlscert">서버가 TLS 서버 확장을 포함한 인증서를 사용하는지 여부 확인 (--remote-cert-tls server)</string> - <string name="check_remote_tlscert_title">TLS 서버 인증서 바람</string> - <string name="remote_tlscn_check_summary">원격 서버 인증서 주체 DN을 확인</string> - <string name="remote_tlscn_check_title">인증서 호스트 이름 확인</string> - <string name="enter_tlscn_dialog">원격 인증서 DN을 확인하는 데 사용하는 검사를 지정 (예: C=DE, L=Paderborn, OU=Avian IP Carriers, CN=openvpn.blinkt.de)\n\n확인을 위해 완전한 DN이나 RDN (예 openvpn.blinkt.de) 또는 RDN 접두사를 지정.\n\nRDN 접두사 \"Server\"를 사용하면 \"Server-1\" 및 \"Server-2\"와 일치합니다.\n\n텍스트 필드를 비워 두면 RDN을 서버의 호스트 이름과 비교합니다\n\n더 자세한 내용은 OpenVPN 2.3.1+ 맨페이지에서 --verify-x509-name 아래를 참조</string> - <string name="enter_tlscn_title">원격 인증서 주체</string> - <string name="tls_key_auth">TLS 키 인증 사용</string> - <string name="tls_auth_file">TLS 인증 파일</string> - <string name="pull_on_summary">서버에 IP 주소와 경로, 타이밍 옵션을 요구합니다.</string> - <string name="pull_off_summary">서버에 어떤 정보도 요구하지 않습니다. 아래에 설정을 지정해야 합니다.</string> - <string name="use_pull">설정 끌어오기</string> - <string name="dns">DNS</string> - <string name="override_dns">서버에서 DNS 설정을 재정의합니다</string> - <string name="dns_override_summary">본인의 DNS 서버 사용하기</string> - <string name="searchdomain">검색 도메인</string> - <string name="dns1_summary">사용할 DNS 서버.</string> - <string name="dns_server">DNS 서버</string> - <string name="secondary_dns_message">보조 DNS 서버는 주 DNS 서버에 닿을 수 없는 경우 사용됩니다.</string> - <string name="backup_dns">보조 DNS 서버</string> - <string name="ignored_pushed_routes">푸시된 경로 무시하기</string> - <string name="ignore_routes_summary">서버로부터 푸시된 경로를 무시합니다.</string> - <string name="default_route_summary">VPN을 통해 모든 트래픽을 보냅니다.</string> - <string name="use_default_title">기본 경로 사용하기</string> - <string name="custom_route_message">사용자 지정 경로를 입력하십시오. 목적지는 CIDR 형식으로만 입력하십시오. \"10.0.0.0/8 2002::/16\"은 10.0.0.0/8 과 2002::/16 네트워크를 VPN으로 보냅니다.</string> - <string name="custom_route_message_excluded">VPN을 통해 라우팅되면 안되는 경로. 포함되는 경로와 동일한 구문을 사용합니다.</string> - <string name="custom_routes_title">사용자 지정 경로</string> - <string name="custom_routes_title_excluded">제외된 네트워크</string> - <string name="log_verbosity_level">로그의 자세한 정도</string> - <string name="float_summary">모든 IP에서 인증된 패킷 허용</string> - <string name="float_title">유동 서버 허용</string> - <string name="custom_options_title">사용자 지정 옵션</string> - <string name="edit_vpn">VPN 설정 편집</string> - <string name="remove_vpn_query">VPN 프로파일 \'%s\'을 삭제할까요?</string> - <string name="tun_error_helpful">일부 커스텀 ICS 이미지에서는 /dev/tun에 대한 권한이 잘못되어 있거나 tun 모듈 자체가 누락될 수 있습니다. CM9 이미지는 일반 설정에 있는 소유권 고치기 옵션을 사용해 보십시오.</string> - <string name="tun_open_error">Tun 인터페이스를 열지 못했습니다</string> - <string name="error">"오류: "</string> - <string name="clear">지우기</string> - <string name="last_openvpn_tun_config">Tun 인터페이스 열기:</string> - <string name="local_ip_info">로컬 IPv4: %1$s/%2$d IPv6: %3$s MTU: %4$d</string> - <string name="dns_server_info">DNS 서버: %1$s, 도메인: %2$s</string> - <string name="routes_info_incl">경로: %1$s %2$s</string> - <string name="routes_info_excl">제외된 경로: %1$s %2$s</string> - <string name="routes_debug">설치된 VpnService 경로: %1$s %2$s</string> - <string name="ip_not_cidr">인터페이스 정보 %1$s와 %2$s를 받았고 두 번째 주소를 원격 피어 주소로 가정합니다. 로컬 IP에 대해 /32 넷마스크를 사용합니다. OpenVPN에 의해 주어진 모드는 \"%3$s\"입니다.</string> - <string name="route_not_cidr">CIDR 넷마스크가 있는 IP 경로로서 %1$s와 %2$s를 이해할 수 없습니다. 넷마스크로 /32를 사용합니다.</string> - <string name="route_not_netip">%1$s/%2$s에서 %3$s/%2$s로 경로 정정</string> - <string name="keychain_access">안드로이드 키체인 인증서에 접근할 수 없습니다. 이는 펌웨어 업그레이드 또는 앱 백업 복구, 앱 설정 복구에 의해 발생할 수 있습니다. 인증서에 접근할 수 있는 권한을 다시 생성하기 위해 VPN을 편집하고 기본 설정 아래에서 인증서를 다시 선택하십시오.</string> - <string name="version_info">%1$s %2$s</string> - <string name="send_logfile">로그 파일 보내기</string> - <string name="send">보내기</string> - <string name="ics_openvpn_log_file">ICS OpenVPN 로그 파일</string> - <string name="copied_entry">클립보드로 로그 복사</string> - <string name="tap_mode">Tap 모드</string> - <string name="faq_tap_mode">TAP 모드는 루트가 아닌 VPN API에서는 불가능합니다. 따라서 본 앱은 TAP 지원을 제공할 수 없습니다</string> - <string name="tap_faq2">또? 농담인가요? 아니요. 정말로 TAP 모드는 지원이 불가능합니다. 계속해서 메일을 보내면서 요구하신다고 도움될 일이 아닙니다.</string> - <string name="tap_faq3">세 번째로? 실제로는 송신 때 레이어2 정보를 추가하고 수신 때 레이어2 정보를 떼내는 TUN을 이용한 TAP 에뮬레이터를 제작하는 것이 가능합니다. 하지만 이것만이 아닌 ARP 그리고 어쩌면 DHCP 클라이언트까지도 구현해야 합니다. 본인은 이 같은 작업을 하는 분을 알고 있지 않습니다. 코딩을 시작하려고 하시는 분이 계시면 제게 연락해 주십시오.</string> - <string name="faq">자주 묻는 질문</string> - <string name="copying_log_entries">로그 항목을 복사</string> - <string name="faq_copying">단일 로그 항목을 복사하려면 로그 항목을 누르고 계세요. 전체 로그를 복사/전송하려면 로그 보내기 옵션을 사용하십시오. GUI에 버튼이 표시되지 않는 경우 하드웨어 메뉴 버튼을 사용하세요.</string> - <string name="faq_shortcut">시작하는 바로 가기</string> - <string name="faq_howto_shortcut">바탕 화면에 OpenVPN을 시작하는 바로 가기를 배치할 수 있습니다. 당신의 홈화면 프로그램에 따라 바로 가기 또는 위젯 추가해야 합니다.</string> - <string name="no_vpn_support_image">당신의 이미지는 VPNService API를 지원하지 않습니다, 죄송합니다 :(</string> - <string name="encryption">암호화</string> - <string name="cipher_dialog_title">암호화 방법 입력</string> - <string name="chipher_dialog_message">OpenVPN이 사용할 암호화 암호 알고리즘을 입력하세요. 기본 암호를 사용하려면 비워 두십시오.</string> - <string name="auth_dialog_message">OpenVPN이 사용할 인증 다이제스트를 입력하세요. 기본 다이제스트를 사용하려면 비워 두십시오.</string> - <string name="settings_auth">인증/암호화</string> - <string name="file_explorer_tab">파일 탐색기</string> - <string name="inline_file_tab">인라인 파일</string> - <string name="error_importing_file">파일 가져오기 오류</string> - <string name="import_error_message">파일 시스템에서 파일을 가져올 수 없습니다.</string> - <string name="inline_file_data">[[인라인 파일 데이터]]</string> - <string name="opentun_no_ipaddr">IP 정보가 없는 tun 장치 열기를 거부합니다</string> - <string name="menu_import">ovpn 파일에서 프로파일 가져오기</string> - <string name="menu_import_short">가져오기</string> - <string name="import_content_resolve_error">가져올 프로파일을 읽을 수 없습니다.</string> - <string name="error_reading_config_file">구성 파일 읽기 오류</string> - <string name="add_profile">프로파일 추가</string> - <string name="import_could_not_open">가져온 구성 파일에 언급된 파일 %1$s를 찾을 수 없습니다.</string> - <string name="importing_config">원본 %1$s에서 구성 파일 가져오기</string> - <string name="import_warning_custom_options">당신의 구성이 UI 구성으로 매핑되지 않은 몇 가지 구성 옵션을 가지고 있었습니다. 이 옵션은 사용자 정의 구성 옵션으로 추가되었습니다. 사용자 정의 구성은 아래에 표시됩니다:</string> - <string name="import_done">구성 파일 읽기 완료.</string> - <string name="nobind_summary">로컬 주소와 포트로 바인드 안 하기</string> - <string name="no_bind">로컬 바인딩 안 함</string> - <string name="import_configuration_file">구성 파일 가져오기</string> - <string name="faq_security_title">보안 고려 사항</string> - <string name="faq_security">"OpenVPN은 보안에 민감하기 때문에 보안에 관한 몇 가지 주의사항은 합리적입니다. SD 카드에 있는 데이터는 필연적으로 안전하지 않습니다. 모든 앱이 그것을 읽을 수 있습니다(예를 들어 이 프로그램은 특별한 SD 카드 권한을 가질 필요가 없습니다). 이 앱의 데이터는 이 앱만 읽을 수 있습니다. 파일 대화창에서 CA 인증서/인증서/키를 가져옴으로써 데이터는 VPN 프로파일 내에 저장됩니다. 이 VPN 프로파일은 이 앱만 접근할 수 있습니다. (잊지 말고 SD 카드에 남아있는 파일들을 삭제하세요.) 접근은 이 OpenVPN 앱만 가능하더라도 데이터는 암호화가 되어 있지 않습니다. 루팅이나 다른 취약점을 이용해서 데이터를 빼낼 수 있습니다. 저장된 암호 또한 일반 텍스트로 저장되어 있습니다. pkcs12 파일은 안드로이드 키 저장소에 보관할 것을 강력하게 추천합니다."</string> - <string name="import_vpn">가져오기</string> - <string name="broken_image_cert_title">인증서 선택 표시 오류</string> - <string name="broken_image_cert">안드로이드 4.0+의 인증서 선택 대화창을 보여주려는 과정에서 예외가 발생했습니다. 안드로이드 4.0+의 표준 기능이므로 이 같은 일은 일어나면 안 됩니다. 어쩌면 귀하의 안드로이드 롬의 인증서 저장소에 대한 지원이 깨졌을 수 있습니다.</string> - <string name="ipv4">IPv4</string> - <string name="ipv6">IPv6</string> - <string name="speed_waiting">상태 메시지를 기다리는 중…</string> - <string name="converted_profile">가져온 프로파일</string> - <string name="converted_profile_i">가져온 프로파일 %d</string> - <string name="broken_images">깨진 이미지</string> - <string name="broken_images_faq"><p>공식 HTC 이미지에서는 이상한 라우팅 문제로 트래픽이 터널로 통과하지 않는 경우가 있는 것으로 알려져 있습니다. (버그 추적기의 <a href=\"http://code.google.com/p/ics-openvpn/issues/detail?id=18\">문제 18</a> 참조.)</p><p>Xperia Arc S 와 Xperia Ray의 오래된 공식 SONY 이미지에서는 VPNService 자체가 전혀 없는 것으로 보고되었습니다. (버그 추적기의 <a href=\"http://code.google.com/p/ics-openvpn/issues/detail?id=29\">문제 29</a> 참조.)</p><p>커스텀 빌드 이미지에서는 tun 모듈 자체가 없거나 /dev/tun의 권한이 틀려 있기도 합니다. 일부 CM9 이미지는 \"기기별 해킹\" 아래에 있는 \"소유권 고치기\" 옵션을 사용해야 합니다.</p><p>가장 중요한 부분: 만약 깨진 이미지를 사용하는 경우라면 해당 공급 업체에 보고해야 합니다. 업체에 문제를 보고하는 사람들이 많아야 수정될 가능성도 높아집니다.</p></string> - <string name="pkcs12_file_encryption_key">PKCS12 파일 암호화 키</string> - <string name="private_key_password">개인 키 암호</string> - <string name="password">암호</string> - <string name="file_icon">파일 아이콘</string> - <string name="tls_authentication">TLS 인증/암호화</string> - <string name="generated_config">생성된 설정</string> - <string name="generalsettings">설정</string> - <string name="owner_fix_summary">/dev/tun의 소유권을 system으로 설정하려고 합니다. 일부 CM9 이미지에서 VPNService API를 사용하기 위해서는 앞의 작업이 요구됩니다. 루트 권한을 가져야 합니다.</string> - <string name="owner_fix">/dev/tun 소유권 고치기</string> - <string name="generated_config_summary">생성된 OpenVPN의 구성 파일 보기</string> - <string name="edit_profile_title">\"%s\" 편집</string> - <string name="building_configration">구성 만드는 중…</string> - <string name="netchange_summary">이 옵션을 켜면 네트워크 상태 변경시 강제로 재접속합니다 (예: WiFi와 모바일 상호 변경)</string> - <string name="netchange">네트워크 변경시 재접속</string> - <string name="netstatus">네트워크 상태: %s</string> - <string name="extracahint">CA 인증서는 일반적으로 안드로이드 키 저장소에 있는 것을 사용합니다. 인증서 오류 발생시 별도의 인증서를 지정하세요.</string> - <string name="select_file">선택</string> - <string name="keychain_nocacert">안드로이드 키 저장소에서 CA 인증서를 찾지 못했습니다. 인증은 아마 실패할 것입니다.</string> - <string name="show_log_summary">연결시 로그 창을 보여드립니다. 로그 창은 항상 알림 상태바에서 접근이 가능합니다.</string> - <string name="show_log_window">로그 창 보기</string> - <string name="mobile_info">%3$s %1$s (%2$s)에서 %10$s %9$s 작동, 안드로이드 %6$s (%7$s) API %4$d, ABI %5$s, (%8$s)</string> - <string name="error_rsa_sign">안드로이드 키 저장소 키로 서명 오류 %1$s: %2$s</string> - <string name="faq_system_dialogs">시스템에서는 VPN 연결 경고를 통해 당신에게 본 앱이 모든 트래픽을 가로챌 수 있다는 점을 알리게 되어 있는데 이는 VPNService API가 남용되는 것을 막기 위함입니다.\nVPN 연결 알림 (열쇠 기호) 또한 안드로이드 시스템에서 부과하는 부분이며 이는 VPN 연결을 알리는 신호입니다. 어떤 이미지에서는 이 알림이 소리를 내기도 합니다.\n안드로이드는 당신의 안전을 위해서 이 대화창을 도입했으며 회피할 수 없게 하였습니다. (어떤 이미지에서는 유감스럽게도 알림 소리 또한 포함됩니다.)</string> - <string name="faq_system_dialogs_title">연결 경고 및 알림 소리</string> - <string name="translationby">한국어 번역: 안규태<ktdann@gmail.com>, 강현진<peaceb></string> - <string name="ipdns">IP와 DNS</string> - <string name="basic">기본</string> - <string name="routing">라우팅</string> - <string name="obscure">모호한 OpenVPN 설정. 일반적으로 필요하지 않습니다.</string> - <string name="advanced">고급</string> - <string name="export_config_title">ICS Openvpn 구성</string> - <string name="warn_no_dns">사용 중인 DNS 서버가 없습니다. 이름 변환이 작동하지 않을 수 있습니다. 사용자 지정 DNS 서버를 설정하는 것이 좋습니다. 또한 안드로이드는 DNS 서버가 설정되지 않은 경우 모바일/Wi-Fi 연결에 당신의 프록시 설정을 계속해서 사용한다는 점을 유의하세요.</string> - <string name="dns_add_error">DNS 서버 \"%1$s\"는 시스템에 의해 거부돼 추가할 수 없습니다: %2$s</string> - <string name="ip_add_error">시스템에 의해 거부되어 IP 주소 \"%1$s\"를 설정하지 못하였습니다: %2$s</string> - <string name="faq_howto"><p>작동하는 구성을 얻기 (당신의 컴퓨터에서 검증된 것 또는 공급자/조직에서 내려받은 것)</p><p>이것이 추가 pem/pks12 파일이 없는 단일 파일인 경우 본인에게 이메일로 보내어 첨부 파일을 열면 됩니다. 여러 파일인 경우 SD 카드에 넣으세요.</p><p>이메일 첨부 파일을 클릭하거나 또는 VPN 목록에 있는, 구성 파일을 가져오는 폴더 모양 아이콘을 사용하세요.</p><p>파일 누락 오류 발생시 누락된 파일을 SD 카드에 복사하세요.</p><p>저장 기호를 클릭하여 가져온 VPN을 VPN 목록에 추가하세요.</p><p>VPN 이름을 클릭하여 VPN에 연결하세요.</p><p>오류 또는 경고가 로그에 있는 경우 오류/경고를 이해하여 이들을 해결하십시오.</p></string> - <string name="faq_howto_title">빠른 시작</string> - <string name="setting_loadtun_summary">연결을 시도하기 전에 tun.ko 커널 모듈을 로드합니다. 루팅된 장치이어야만 합니다.</string> - <string name="setting_loadtun">TUN 모듈 로드하기</string> - <string name="importpkcs12fromconfig">구성에 있는 PKCS12를 안드로이드 키 저장소로 가져오기</string> - <string name="getproxy_error">프록시 설정 가져오기 오류: %s</string> - <string name="using_proxy">%1$s</string> - <string name="use_system_proxy">시스템 프록시를 사용</string> - <string name="use_system_proxy_summary">연결할 HTTP/HTTPS 프록시로 시스템 범위의 설정을 사용합니다.</string> - <string name="onbootrestartsummary">OpenVPN이 시스템 부팅시에 활성화되면 지정된 VPN에 연결합니다. 안드로이드 5.0 이전 버전에 이 옵션을 사용하기 전에 연결 경고 FAQ를 읽어 보시기 바랍니다.</string> - <string name="onbootrestart">부팅시 연결</string> - <string name="ignore">무시</string> - <string name="restart">다시 시작</string> - <string name="restart_vpn_after_change">VPN을 다시 시작한 후 구성 변경 내용이 적용됩니다. VPN을 지금 (재)시작?</string> - <string name="configuration_changed">구성 변경됨</string> - <string name="log_no_last_vpn">편집하려는 마지막으로 연결된 프로파일을 확인할 수 없습니다.</string> - <string name="faq_duplicate_notification_title">중복 알림</string> - <string name="faq_duplicate_notification">안드로이드는 시스템의 메모리(램)가 부족한 경우, 현재 필요하지 않는 앱들과 서비스들을 활성 메모리에서 삭제합니다. 이 과정에서 진행중인 VPN 연결이 끊어집니다. 이렇게 되지 않기 위해서 OpenVPN 서비스는 더 높은 우선 순위로 실행됩니다. 더 높은 우선 순위로 실행되기 위해서는 앱이 알림을 표시해야 합니다. 열쇠 알림 아이콘은 이전 FAQ에서 설명된 대로 시스템에서 강요하는 것입니다. 이것은 더 높은 우선 순위로 실행되기 위한 앱 알림이 아닙니다.</string> - <string name="no_vpn_profiles_defined">정의된 VPN 프로파일이 없습니다.</string> - <string name="add_new_vpn_hint">이 <img src=\"ic_menu_add\"/> 아이콘을 사용하여 VPN을 추가하세요</string> - <string name="vpn_import_hint">이 <img src=\"ic_menu_archive\"/> 아이콘을 사용하여 귀하의 Sd 카드에서 기존 (.ovpn 또는 .conf) 프로파일을 가져오세요.</string> - <string name="faq_hint">꼭 FAQ를 확인하세요. 빠른 시작 가이드가 있습니다.</string> - <string name="faq_routing_title">라우팅/인터페이스 구성</string> - <string name="faq_routing">라우팅 및 인터페이스 구성은 기존 ifconfig/route 명령을 통하지 않고 VPNService API를 사용하여 수행됩니다. 그 결과 다른 OS와 다른 라우팅 구성이 생깁니다.\nVPN 터널의 구성은 IP 주소와 이 인터페이스를 통해 라우팅되어야 하는 네트워크들로 이루어져 있습니다. 특히 피어 파트너 주소 또는 게이트웨이 주소가 필요하거나 요구되지 않습니다. VPN 서버에 이르는 특수 경로들(예컨대 redirect-gateway 사용시 추가되는 것)도 필요하지 않습니다. 따라서 앱은 구성을 가져올 때 이러한 설정을 무시합니다. 이 앱은 VPNService API를 사용하여 서버에 대한 연결이 VPN 터널을 통해 라우팅되지 않도록 합니다.\nVPNService API는 VPN을 통해 라우트하지 않아야 할 네트워크들을 지정하는 걸 허용하지 않습니다. 우회 방법으로서 앱이 터널을 통해 라우팅해서는 안 되는 네트워크들(예: route x.x.x.x y.y.y.y net_gateway)을 감지하고 다른 플랫폼의 동작을 모방하기 위해 이 경로들을 제외한 일련의 경로들을 계산합니다. 로그 창은 연결을 수립할 때 VPNService의 설정을 보여줍니다.\n무대 뒤에서: Android 4.4 이상은 정책 라우팅을 사용합니다. route/ifconfig를 사용해선 설치된 경로를 볼 수 없을 것입니다. 대신 ip rule, iptables -t mangle -L을 사용하십시오.</string> - <string name="persisttun_summary">OpenVPN을 다시 연결할 때 VPN 연결이 없는 상태로 빠지지 않습니다.</string> - <string name="persistent_tun_title">지속적인 TUN</string> - <string name="openvpn_log">OpenVPN 로그</string> - <string name="import_config">OpenVPN 구성 가져오기</string> - <string name="battery_consumption_title">배터리 소모</string> - <string name="baterry_consumption">제 개인적인 테스트에서 Openvpn의 높은 배터리 소비에 대한 주요 이유는 keepalive 패킷 때문이었습니다. 대부분의 OpenVPN 서버 설정에는 \'keepalive 10 60\' 와 같은 문구가 있는데 이는 클라이언트에서 서버로 서버에서 클라이언트로 keepalive 패킷을 10 초마다 보냅니다. <p>이러한 패킷은 작고 많은 트래픽을 사용하지 않습니다만 이들은 모바일 라디오 네트워크를 계속 유지하게 만들게 되고 따라서 에너지 소비가 증가합니다. (참조 <a href=\"http://developer.android.com/training/efficient-downloads/efficient-network-access.html#RadioStateMachine\">The Radio State Machine | Android Developers</a>) <p>이 keepalive 설정을 클라이언트에서 변경할 수 없습니다. OpenVPN의 시스템 관리자만 설정을 변경할 수 있습니다. <p>불행히도 udp를 사용할 때 keepalive값을 60 초 이상으로 하면 일부의 NAT 게이트웨이에서는 비활성 타임아웃 때문에 연결을 끊어버리게 됩니다. TCP와 긴 keepalive 만료기간을 함께 사용할 수는 있지만 패킷 손실이 높은 연결 구간에서는 TCP over TCP의 성능이 매우 저조합니다. (참조 <a href=\"http://sites.inka.de/bigred/devel/tcp-tcp.html\">왜 TCP를 통한 TCP는 안 좋은 방법인가</a>)</string> - <string name="faq_tethering">안드로이드의 (WiFi, USB 또는 블루투스를 통한) 테더링 기능과 (이 프로그램에서 사용되는) VPNService API 는 함께 작동하지 않습니다. 자세한 내용은 <a href=\"http://code.google.com/p/ics-openvpn/issues/detail?id=34\">문제 #34</a>를 참조하십시오</string> - <string name="vpn_tethering_title">VPN과 테더링</string> - <string name="connection_retries">연결 재시도</string> - <string name="reconnection_settings">다시 연결 설정</string> - <string name="connectretrymessage">연결 시도 사이에 대기하는 초 단위 시간입니다.</string> - <string name="connectretrywait">연결 사이의 초 단위 시간</string> - <string name="minidump_generated">OpenVPN이 예기치 않게 종료됐습니다. 메인 메뉴에 있는 미니 덤프 보내기 옵션의 사용을 고려하시기 바랍니다.</string> - <string name="send_minidump">미니 덤프를 개발자에게 보내기</string> - <string name="send_minidump_summary">개발자에게 마지막 비정상 종료에 대한 디버깅 정보를 보냅니다</string> - <string name="notifcation_title">OpenVPN - %s</string> - <string name="session_ipv4string">%1$s - %2$s</string> - <string name="session_ipv6string">%1$s - %3$s, %2$s</string> - <string name="state_connecting">연결중</string> - <string name="state_wait">서버 응답 대기중</string> - <string name="state_auth">인증중</string> - <string name="state_get_config">클라이언트 구성 가져오는 중</string> - <string name="state_assign_ip">IP 주소 할당중</string> - <string name="state_add_routes">경로 추가중</string> - <string name="state_connected">연결됨</string> - <string name="state_disconnected">연결 끊기</string> - <string name="state_reconnecting">재연결중</string> - <string name="state_exiting">종료중</string> - <string name="state_noprocess">실행 안 됨</string> - <string name="state_resolve">호스트 이름 변환중</string> - <string name="state_tcp_connect">연결중 (TCP)</string> - <string name="state_auth_failed">인증 실패</string> - <string name="state_nonetwork">사용 가능한 네트워크 대기중</string> - <string name="statusline_bytecount">↓%2$s %1$s - ↑%4$s %3$s</string> - <string name="notifcation_title_notconnect">연결되지 않음</string> - <string name="start_vpn_title">VPN %s 연결중</string> - <string name="start_vpn_ticker">VPN %s 연결중</string> - <string name="jelly_keystore_alphanumeric_bug">일부 버전의 안드로이드 4.1에서는 키 저장소 인증서의 이름에 비영숫자 문자(공백, 밑줄 또는 대시)가 포함된 경우 문제가 있습니다. 특수 문자 없는 인증서를 다시 가져와 보세요.</string> - <string name="encryption_cipher">암호화 알고리즘</string> - <string name="packet_auth">패킷 인증</string> - <string name="auth_dialog_title">패킷 인증 방법 입력</string> - <string name="built_by">%s가 빌드</string> - <string name="debug_build">디버그 빌드</string> - <string name="official_build">공식 빌드</string> - <string name="make_selection_inline">프로파일에 복사</string> - <string name="crashdump">크래시 덤프</string> - <string name="add">추가</string> - <string name="send_config">구성 파일 보내기</string> - <string name="complete_dn">완전한 DN</string> - <string name="remotetlsnote">가져온 구성에는 다른 DN 형식을 사용하는 오래된 tls-remote 옵션이 있는데 이는 더이상 지원되지 않습니다.</string> - <string name="rdn">RDN (공통 이름)</string> - <string name="rdn_prefix">RDN 접두사</string> - <string name="tls_remote_deprecated">tls-remote (지원되지 않음)</string> - <string name="help_translate">http://crowdin.net/project/ics-openvpn/invite 를 방문하여 번역을 도울 수 있습니다</string> - <string name="prompt">%1$s가 %2$s를 제어하려고 합니다</string> - <string name="remote_warning">계속 진행하면, 당신은 해당 앱에 OpenVPN for Android의 완벽한 제어권과 모든 네트워크 트래픽을 가로챌 수 있는 권한을 허락합니다.<b>그 앱을 신뢰하지 않는다면 허락하지 마십시오.</b> 그렇지 않으면 악성 소프트웨어가 당신의 데이터를 유출할 수 있습니다.</string> - <string name="remote_trust">나는 이 앱을 신뢰합니다.</string> - <string name="no_external_app_allowed">어떤 앱도 외부 API를 사용할 수 없습니다</string> - <string name="allowed_apps">허용된 앱: %s</string> - <string name="clearappsdialog">허용된 외부 앱 목록을 비우겠습니까?\n현재 허용된 외부 앱:\n\n%s</string> - <string name="screenoff_summary">\"화면이 꺼져 있고 60 초 동안 64kB 미만의 데이터가 전송되면 VPN 일시 정지. \"지속적인 TUN\" 옵션이 활성화되어 있으면 VPN 일시 정지시 당신의 장비는 네트워크 연결이 없는 상태가 됩니다. \"지속적인 TUN\" 옵션이 없는 경우 기기는 VPN 연결/보호를 잃습니다.</string> - <string name="screenoff_title">화면 꺼짐 후 VPN 연결 일시 정지</string> - <string name="screenoff_pause">화면이 꺼진 상태에서 연결 일시 정지: %2$s 초 안에 %1$s 미만</string> - <string name="screen_nopersistenttun">경고: 이 VPN은 지속적인 TUN이 비활성화 되어있습니다. 화면이 꺼졌을 때 트래픽은 터널을 사용하지 않고 보통 인터넷을 사용합니다.</string> - <string name="save_password">암호 저장</string> - <string name="pauseVPN">VPN 일시 정지</string> - <string name="resumevpn">VPN 재개하기</string> - <string name="state_userpause">사용자가 요청한 VPN 일시 정지</string> - <string name="state_screenoff">VPN 일시 정지됨 - 화면 끄기</string> - <string name="device_specific">기기별 해킹</string> - <string name="cannotparsecert">인증서 정보를 표시할 수 없습니다</string> - <string name="appbehaviour">앱 동작</string> - <string name="vpnbehaviour">VPN 동작</string> - <string name="allow_vpn_changes">VPN 프로파일 변경을 허용</string> - <string name="hwkeychain">하드웨어 키 저장소:</string> - <string name="permission_icon_app">OpenVPN for Android를 사용하려고 하는 앱의 아이콘</string> - <string name="faq_vpndialog43">"안드로이드 4.3부터는 VPN 확인이 \"오버레이하는 앱\"으로부터 보호받습니다. 이 경우 대화창이 터치 입력에 반응하지 않게 됩니다. 사용하는 앱 중에서 오버레이를 사용하는 경우 이러한 문제가 발생될 수 있습니다. 문제의 앱을 발견하면 그 앱의 제작자에게 연락하십시오. 이 문제는 안드로이드 4.3과 이상의 버전에서 모든 VPN 앱에 영향을 줍니다. 상세한 사항은 <a href=\"http://code.google.com/p/ics-openvpn/issues/detail?id=185\">문제 185<a> 참조"</string> - <string name="faq_vpndialog43_title">VPN 확인 대화창</string> - <string name="donatePlayStore">또는 당신은 플레이 스토어에서 나에게 기부금을 보낼 수 있습니다:</string> - <string name="thanks_for_donation">%s를 기부해 주셔서 감사합니다!</string> - <string name="logCleared">로그가 삭제되었습니다.</string> - <string name="show_password">암호 표시</string> - <string name="keyChainAccessError">키체인 접근 오류: %s</string> - <string name="timestamp_short">간결하게</string> - <string name="timestamp_iso">ISO</string> - <string name="timestamps">타임 스탬프</string> - <string name="timestamps_none">없음</string> - <string name="uploaded_data">업로드</string> - <string name="downloaded_data">다운로드</string> - <string name="vpn_status">VPN 상태</string> - <string name="logview_options">옵션 보기</string> - <string name="unhandled_exception">처리되지 않은 예외: %1$s\n\n%2$s</string> - <string name="unhandled_exception_context">%3$s: %1$s\n\n%2$s</string> - <string name="faq_system_dialog_xposed">만약 당신의 안드로이드 기기가 루팅되어 있다면 <a href=\"http://xposed.info/\">Xposed framework</a>와 <a href=\"http://repo.xposed.info/module/de.blinkt.vpndialogxposed\">VPN Dialog confirm module</a>을 자신의 책임 하에 설치할 수 있습니다.</string> - <string name="full_licenses">전체 라이선스</string> - <string name="blocklocal_summary">로컬 네트워크에 직접 연결된 인터페이스는 VPN을 통해 접속하지 않습니다. 이 옵션의 선택을 취소하면 로컬 네트워크의 모든 트래픽이 VPN으로 리디렉션됩니다.</string> - <string name="blocklocal_title">로컬 네트워크에선 VPN 우회</string> - <string name="userpw_file">사용자 이름/암호 파일</string> - <string name="imported_from_file">[%s에서 가져옴]</string> - <string name="files_missing_hint">일부 파일을 찾을 수 없습니다. 프로파일을 가져올 파일을 선택하십시오:</string> - <string name="openvpn_is_no_free_vpn">이 앱을 사용하려면 OpenVPN을 지원하는 VPN 공급자/VPN 게이트웨이가 필요합니다(종종 고용주가 제공함). OpenVPN에 대한 자세한 내용과 자신의 OpenVPN 서버를 설정하는 방법은 http://community.openvpn.net/ 를 참조하십시오.</string> - <string name="import_log">로그 가져 오기:</string> - <string name="ip_looks_like_subnet">VPN 토폴로지 \"%3$s\"가 지정되었지만 ifconfig %1$s %2$s는 네트워크 마스크가 있는 IP 주소와 더 유사합니다. \"subnet\" 토폴로지를 가정합니다.</string> - <string name="mssfix_invalid_value">MSS 재정의 값은 0과 9000 사이의 정수이어야 합니다</string> - <string name="mtu_invalid_value">MTU 재정의 값은 64과 9000 사이의 정수이어야 합니다</string> - <string name="mssfix_value_dialog">송신 패킷을 OpenVPN이 캡슐화하여 만들어지는, OpenVPN이 피어에게 보낼 UDP 패킷 크기가 이 바이트 수를 넘지 않도록 송신 패킷 크기를 제한하도록 터널 상의 TCP 세션들에 알립니다. (기본값 1450)</string> - <string name="mssfix_checkbox">TCP 페이로드의 MSS 값 재정의</string> - <string name="mssfix_dialogtitle">TCP 페이로드의 MSS 설정</string> - <string name="client_behaviour">클라이언트 동작</string> - <string name="clear_external_apps">허용된 외부 앱 비우기</string> - <string name="loading">로드 중...</string> - <string name="allowed_vpn_apps_info">VPN을 사용할 앱들: %1$s</string> - <string name="disallowed_vpn_apps_info">VPN을 사용하지 않을 앱들: %1$s</string> - <string name="app_no_longer_exists">%s 패키지가 더이상 설치되어 있지 않으며 앱 허용/거부 목록에서 제거함</string> - <string name="vpn_disallow_radio">VPN은 모든 앱에 사용되지만 선택된 앱은 제외합니다.</string> - <string name="vpn_allow_radio">VPN은 선택된 앱에만 사용됩니다.</string> - <string name="query_delete_remote">원격 서버 항목을 제거하시겠습니까?</string> - <string name="keep">유지</string> - <string name="delete">삭제</string> - <string name="add_remote">새 원격 서버 추가</string> - <string name="remote_random">연결시 임의의 순서로 연결 항목을 사용</string> - <string name="remote_no_server_selected">하나 이상의 원격 서버를 정의하고 활성화해야 합니다.</string> - <string name="server_list">서버 목록</string> - <string name="vpn_allowed_apps">허용된 앱</string> - <string name="payload_options">페이로드 옵션</string> - <string name="tls_settings">TLS 설정</string> - <string name="no_remote_defined">정의된 원격 서버 없음</string> - <string name="duplicate_vpn">VPN 프로파일 복제</string> - <string name="duplicate_profile_title">프로파일 복제: %s</string> - <string name="show_log">로그 보기</string> - <string name="faq_android_clients">Android용 OpenVPN 클라이언트가 여러 개 있습니다. 가장 일반적으로 사용되는 것은 OpenVPN for Android (이 클라이언트), OpenVPN Connect 및 OpenVPN Settings입니다. <p>클라이언트들을 두 그룹으로 나눌 수 있습니다. OpenVPN for Android와 OpenVPN Connect는 공식 VPNService API(Android 4.0 이상)를 사용하고 루트가 필요하지 않으며 OpenVPN Settings는 루트를 사용합니다.<p>OpenVPN for Android는 오픈 소스 클라이언트이며 Arne Schwabe에 의해 개발되었습니다. 고급 사용자를 대상으로 하며 많은 설정을 제공하고 파일에서 프로필을 가져오고 앱 내에서 프로필을 구성/변경하는 기능을 제공합니다. 이 클라이언트는 OpenVPN의 커뮤니티 버전을 기반으로 하는데 OpenVPN 2.x 소스 코드를 기반으로 합니다. 이 클라이언트는 커뮤니티의 반 공식 클라이언트로 볼 수 있습니다. <p>OpenVPN Connect는 OpenVPN Technologies, Inc.에서 개발한 비공개 소스 클라이언트입니다. 이 클라이언트는 일반 사용을 목적으로 하고 평균적인 사용자를 대상으로 하며 OpenVPN 프로파일을 가져올 수 있습니다. 이 클라이언트는 OpenVPN 프로토콜의 OpenVPN C++ 재구현을 기반으로 합니다(이는 OpenVPN Technologies, Inc.에서 iOS용 OpenVPN 앱을 내놓는 데 필요했습니다). 이 클라이언트는 OpenVPN 기술의 공식 클라이언트입니다. <p>OpenVPN Settings는 이 클라이언트들 중 가장 오래된 클라이언트이며 오픈 소스 OpenVPN의 UI입니다. OpenVPN for Android와 달리 루트가 필요하며 VPNService API를 사용하지 않습니다. Android 4.0 이상에 의존하지 않습니다.</string> - <string name="faq_androids_clients_title">안드로이드 OpenVPN 클라이언트 간의 차이</string> - <string name="ignore_multicast_route">멀티캐스트 경로 무시: %s</string> - <string name="ab_only_cidr">Android는 VPN에 대한 CIDR 경로만 지원합니다. 비 CIDR 경로는 거의 사용되지 않기 때문에 OpenVPN for Android는 CIDR이 아닌 경로에 /32를 사용하고 경고를 보냅니다.</string> - <string name="ab_tethering_44">테더링은 VPN이 활성화되어있는 동안 작동합니다. 테더링된 연결은 VPN을 사용하지 않을 것입니다.</string> - <string name="ab_kitkat_mss">초기 킷캣 버전은 TCP 연결에서 잘못된 MSS 값을 설정합니다(# 61948). 이 버그를 우회하려면 MSS 재정의 옵션을 활성화하십시오.</string> - <string name="ab_proxy">Android는 DNS 서버가 설정되지 않은 경우 모바일/Wi-Fi 연결에 지정된 프록시 설정을 계속 사용합니다. OpenVPN for Android는 로그에 이에 대해 경고할 것입니다. <p>VPN이 DNS 서버를 설정할 때 안드로이드는 프록시를 사용하지 않을 것입니다. VPN 연결을 위한 프록시를 설정하는 API는 없습니다.</p></string> - <string name="ab_lollipop_reinstall">VPN 앱이 제거되고 다시 설치되면 작동을 멈출 수 있습니다. 자세한 내용은 #80074를 참조하십시오.</string> - <string name="ab_not_route_to_vpn">구성된 클라이언트 IP와 해당 네트워크 마스크에 있는 IP들은 VPN으로 라우팅되지 않습니다. OpenVPN은 클라이언트 IP와 넷마스크에 해당하는 경로를 명시적으로 추가함으로써 이 버그를 우회합니다.</string> - <string name="ab_persist_tun">지속적인 TUN 지원에 사용되는 다른 TUN 장치가 활성화된 상태에서 한 TUN 장치를 열면 기기의 VPNServices가 죽습니다. VPN을 다시 작동 시키려면 재부팅해야 합니다. OpenVPN for Android는 TUN 장치를 다시 열지 않으려고 시도합니다. 정말 필요하면 충돌이 발생하지 않도록 새로운 TUN 장치를 열기 전에 먼저 현재 TUN을 닫습니다. 이 경우 짧은 순간 VPN이 아닌 연결을 통해 패킷이 전송될 수 있습니다. 이 우회 방법으로도 VPNServices가 죽고 기기를 재부팅해야 하는 경우가 있습니다.</string> - <string name="ab_secondary_users">VPN은 부차적인 사용자에게는 전혀 작동하지 않습니다.</string> - <string name="ab_kitkat_reconnect">"여러 사용자가 VPN 앱을 사용하는 동안 모바일 연결/모바일 데이터 연결이 자주 끊어지는 것으로 보고합니다. 이 반응은 일부 모바일 공급자/기기 조합에만 영향을 미치는 것으로 보이며 지금까지 버그에 대한 원인/해결 방법을 알 수 없습니다."</string> - <string name="ab_vpn_reachability_44">VPN 없이 도달할 수 있는 목적지만 VPN을 통해서 도달할 수 있습니다. IPv6 VPN은 전혀 작동하지 않습니다.</string> - <string name="ab_only_cidr_title">비 CIDR 경로</string> - <string name="ab_proxy_title">VPN을 위한 프록시 동작</string> - <string name="ab_lollipop_reinstall_title">VPN 앱들을 재설치</string> - <string name="version_upto">%s 및 이전 버전</string> - <string name="copy_of_profile">%s의 사본</string> - <string name="ab_not_route_to_vpn_title">구성된 IP 주소로의 경로</string> - <string name="ab_kitkat_mss_title">VPN 연결에 대한 잘못된 MSS 값</string> - <string name="ab_secondary_users_title">부차적인 태블릿 사용자들</string> - <string name="custom_connection_options_warng">사용자 지정 연결별 옵션을 지정하십시오. 조심해서 사용하십시오.</string> - <string name="custom_connection_options">사용자 지정 옵션</string> - <string name="remove_connection_entry">연결 항목 제거</string> - <string name="ab_kitkat_reconnect_title">모바일 네트워크에서 임의 연결 해제</string> - <string name="ab_vpn_reachability_44_title">원격 네트워크에 도달할 수 없음</string> - <string name="ab_persist_tun_title">지속적인 TUN 모드</string> - <string name="version_and_later">%s 및 이후 버전</string> - <string name="tls_cipher_alert_title">SSL23_GET_SERVER_HELLO:sslv3 alert handshake failure로 연결 실패</string> - <string name="tls_cipher_alert">새로운 OpenVPN for Android 버전들(0.6.29/2015년 3월)은 허용된 암호화 스위트(tls-cipher \"DEFAULT:!EXP:!PSK:!SRP:!kRSA\")에 더 안전한 기본값을 사용합니다. 안타깝게도 보안 수준이 낮은 암호화 스위트와 수출용 암호화 스위트를 생략하면, 특히 완벽 전달 보안(Diffie-Hellman)을 지원하지 않는 암호화 스위트를 생략하면 몇 가지 문제가 발생합니다. 이것은 보통 불필요한 요소를 제거한 SSL(예: MikroTik)을 쓰는 서버나 몇 임베디드 OS에서 tls-cipher을설정하여 TLS 보안을 강화하려는 좋은 의도를 가지고 했으나 불완전하게 실행됨으로써 발생합니다.\n이 문제를 해결하려면 서버에서 tls-cipher 설정을 tls-cipher \"DEFAULT:!EXP:!PSK:!SRP:!kRSA\"와 같은 적절한 기본값으로 설정하십시오. 클라이언트에서 문제를 우회하려면 안드로이드 클라이언트의 tls-cipher DEFAULT 사용자 정의 옵션을 추가하십시오.</string> - <string name="message_no_user_edit">이 프로파일은 외부 앱(%s)에서 추가되었으며 사용자가 편집할 수 없음으로 표시되었습니다.</string> - <string name="crl_file">인증서 폐기 목록</string> - <string name="service_restarted">OpenVPN 서비스 재시작 (앱이 메모리 부족으로 죽었거나 강제 종료된 것으로 추정)</string> - <string name="import_config_error">구성 가져오기에서 오류가 발생했습니다. 저장할 수 없습니다.</string> - <string name="Search">검색</string> - <string name="lastdumpdate">(마지막 덤프는 %1$d시간 %2$d분 이전 (%3$s))</string> - <string name="clear_log_on_connect">새 연결에 로그 지우기</string> - <string name="connect_timeout">연결 시간 초과</string> - <string name="no_allowed_app">허용된 앱이 추가되지 않았습니다. 모든 앱을 허용하지 않으려면 허용된 앱 목록에 앱이 하나 이상 있어야 하므로 이 앱 자신(%s)을 추가합니다.</string> - <string name="query_permissions_sdcard">OpenVPN for Android는 자동으로 SD 카드에서 누락된 파일을 검색할 수 있습니다. 이 메시지를 탭하여 권한 요청을 시작하십시오.</string> - <string name="protocol">프로토콜</string> - <string name="enabled_connection_entry">사용</string> - <string name="abi_mismatch">이 장치의 고유 ABI 우선 순위(%1$s)와 고유 라이브러리가 보고한 ABI(%2$s)가 불일치</string> - <string name="permission_revoked">운영체제에 의해 취소된 VPN 권한(예: 다른 VPN 프로그램 시작됨), VPN 중지</string> - <string name="pushpeerinfo">피어 정보 푸시</string> - <string name="pushpeerinfosummary">서버에 추가 정보 전송 (예: SSL 버전 및 안드로이드 버전)</string> - <string name="pw_request_dialog_title">%1$s이 필요함</string> - <string name="pw_request_dialog_prompt">프로파일 %1$s의 암호를 입력하십시오</string> - <string name="menu_use_inline_data">인라인 데이터 사용</string> - <string name="export_config_chooser_title">구성 파일 내보내기</string> - <string name="missing_tlsauth">tls-auth 파일이 누락되었습니다</string> - <string name="missing_certificates">사용자 인증서 또는 사용자 인증서 키 파일 누락됨</string> - <string name="missing_ca_certificate">CA 인증서 누락됨</string> - <string name="crl_title">인증서 폐기 목록 (선택 사항)</string> - <string name="reread_log">로그 캐시 파일에서 항목(%d 개)을 다시 읽습니다</string> - <string name="samsung_broken">삼성 휴대폰이 가장 많이 판매되는 안드로이드폰 중 하나이지만, 삼성의 펌웨어는 가장 버그가 많은 안드로이드 펌웨어 중 하나입니다. 버그는 이러한 기기에서의 VPN 작업에만 국한되지 않지만 그 중 많은 수를 우회할 수 있습니다. 다음은 일부 버그에 대한 설명입니다.\n\nDNS는 VPN 범위의 DNS 서버가 아니면 작동하지 않습니다.\n\n많은 삼성 5.x 기기에서 허용/허용되지 않는 앱 기능이 작동하지 않습니다.\n삼성 6.x 기기에서는 VPN 앱이 절전 기능에서 제외되지 않으면 VPN이 작동하지 않는 것으로 보고됩니다.</string> - <string name="samsung_broken_title">삼성 휴대폰</string> - <string name="novpn_selected">VPN이 선택되지 않았습니다.</string> - <string name="defaultvpn">기본 VPN</string> - <string name="defaultvpnsummary">기본 VPN이 필요한 장소(현재로는 부팅 중에 켜기와 연결 유지, 빠른 설정 타일)에서 사용될 VPN</string> - <string name="vpnselected">현재 선택된 VPN: \'%s\'</string> - <string name="reconnect">다시 연결</string> - <string name="qs_title">VPN 토글</string> - <string name="qs_connect">%s에 연결</string> - <string name="qs_disconnect">%s 연결 끊기</string> - <string name="connectretrymaxmessage">연결 시도 사이의 최대 시간을 입력하십시오. OpenVPN은 매 연결 시도 실패 후 대기 시간을 이 값까지 천천히 올립니다. 기본값은 300 초입니다.</string> - <string name="connectretrymaxtitle">연결 시도 사이의 최대 시간</string> - <string name="state_waitconnectretry">연결 시도 사이에 %s 초 기다림</string> - <string name="nought_alwayson_warning"><![CDATA[VPN 확인 대화 상자가 표시되지 않으면 다른 앱에서 \"연결 유지 VPN\"을 켜 놓았을 수 있습니다. 이 경우 해당 앱만 VPN에 연결할 수 있습니다. 설정 -> 네트워크 더보기 .. -> VPN을 확인하세요.]]></string> - <string name="management_socket_closed">OpenVPN에 대한 연결이 끊어졌습니다 (%s)</string> - <string name="change_sorting">정렬 변경</string> - <string name="sort">정렬</string> - <string name="sorted_lru">최근 사용 순으로 프로파일 정렬</string> - <string name="sorted_az">이름 순으로 프로파일 정렬</string> - <string name="deprecated_tls_remote">구성이 2.3에서 제거될 것으로 표시되었고 2.4에서 완전히 제거된 tls-remote 옵션을 사용합니다</string> - <string name="auth_failed_behaviour">AUTH_FAILED에 대한 동작</string> - <string name="graph">그래프</string> - <string name="use_logarithmic_scale">로그 스케일 사용</string> - <string name="notenoughdata">데이터가 충분하지 않습니다</string> - <string name="avghour">시간당 평균</string> - <string name="avgmin">분당 평균</string> - <string name="last5minutes">지난 5 분</string> - <string name="data_in">들어옴</string> - <string name="data_out">나감</string> - <string name="bits_per_second">%.0f bit/s</string> - <string name="kbits_per_second">%.1f kbit/s</string> - <string name="mbits_per_second">%.1f Mbit/s</string> - <string name="gbits_per_second">%.1f Gbit/s</string> - <string name="weakmd"><p>OpenSSL 1.1 버전부터, OpenSSL은 MD5와 같은, 인증서의 약한 서명을 - 거부합니다.</p><p><b>MD5 서명은 완전히 불안전하고 더이상 사용하지 않아야 합니다.</b> MD5 - 충돌은 <a - href=\"https://natmchugh.blogspot.de/2015/02/create-your-own-md5-collisions.html\">매우 적은 비용으로 - 수 시간 안에</a> 만들 수 있습니다. - 가능한 한 빨리 VPN 인증서를 업데이트해야 합니다.</p><p>불행하게도 오래된 easy-rsa 배포판은 - 구성 옵션 \"default_md md5\"가 포함되어 있습니다. 만약 오래된 easy-rsa 버전을 - 사용하신다면 <a href=\"https://github.com/OpenVPN/easy-rsa/releases\">최신 버전</a>으로 업데이트하시거나 - md5를 sha256으로 바꾸고 당신의 인증서를 - 재생성하세요.</p><p>정말 오래되고 깨진 인증서를 사용하고 싶으시다면 - 사용자 지정 구성 옵션 tls-cipher \"DEFAULT:@SECLEVEL=0\"를 고급 구성에서 설정하거나 - 불러오는 구성 파일에 추가해 넣으세요.</p> - </string> - <string name="volume_byte">%.0f B</string> - <string name="volume_kbyte">%.1f kB</string> - <string name="volume_mbyte">%.1f MB</string> - <string name="volume_gbyte">%.1f GB</string> - <string name="channel_name_background">연결 통계</string> - <string name="channel_description_background">수립된 OpenVPN 연결의 진행 통계</string> - <string name="channel_name_status">연결 상태 변화</string> - <string name="channel_description_status">OpenVPN 연결의 상태 변화 (연결중, 인증중,…)</string> - <string name="weakmd_title">인증서 서명에 약한 (MD5) 해시 사용 (SSL_CTX_use_certificate md too weak)</string> - <string name="title_activity_open_sslspeed">OpenSSL 속도 테스트</string> - <string name="openssl_cipher_name">OpenSSL 암호화 알고리즘 이름</string> - <string name="osslspeedtest">OpenSSL 암호화 속도 테스트</string> - <string name="openssl_error">OpenSSL이 오류를 반환함</string> - <string name="running_test">테스트 수행 중…</string> - <string name="test_algoirhtms">선택한 알고리즘 테스트</string> - <string name="all_app_prompt">어떤 외부 앱이 %s를 제어하려고 합니다. 접근을 요청하는 앱을 정해 놓을 수 없습니다. 이 앱을 허용하면 모든 앱의 접근을 승인하게 됩니다.</string> - <string name="openvpn3_nostatickeys">OpenVPN 3 C++ 구현은 고정 키를 지원하지 않습니다. 일반 설정에서 OpenVPN 2.x로 변경해 주세요.</string> - <string name="openvpn3_pkcs12">OpenVPN 3 C++ 구현과 함께 PKCS12 파일을 직접 사용하는 것은 지원되지 않습니다. PKCS12 파일을 안드로이드 키 저장소로 가져 오거나 일반 설정에서 OpenVPN 2.x으로 변경하세요.</string> - <string name="proxy">대리</string> - <string name="Use_no_proxy">없음</string> - <string name="tor_orbot">Tor (Orbot)</string> -</resources> diff --git a/app/src/main/res/values-ko/strings.xml b/app/src/main/res/values-ko/strings.xml deleted file mode 100644 index 935c5f3c9cf9f8aa8c7289df63ed3e25af154885..0000000000000000000000000000000000000000 --- a/app/src/main/res/values-ko/strings.xml +++ /dev/null @@ -1,21 +0,0 @@ -<?xml version='1.0' encoding='UTF-8'?> -<resources> - <string name="retry">재시도</string> - <string name="info">정보</string> - <string name="show_connection_details">연결 세부 정보 보기</string> - <string name="routes_info">라우트: %s</string> - <string name="error_empty_username">사용자 이름이 비어 있지 않아야 합니다.</string> - <string name="save">저장</string> - <string name="password_match">비밀번호 일치</string> - <string name="password_mismatch">비밀번호가 일치하지 않습니다</string> - <string name="about_fragment_title">About</string> - <string name="error_bad_user_password_user_message">비밀번호나 이름이 올바르지 않습니다</string> - <string name="setup_error_configure_button">구성</string> - <string name="setup_error_close_button">종료</string> - <string name="succesful_authentication_message">인증됨</string> - <string name="authentication_failed_message">인증 실패</string> - <string name="log_fragment_title">로그</string> - <string name="action_settings">설정</string> - <string name="donate_title">기부</string> - <string name="donate_button_donate">기부</string> -</resources> diff --git a/app/src/main/res/values-mk/strings.xml b/app/src/main/res/values-mk/strings.xml deleted file mode 100644 index ffb63dac0bc84e443100b6fddbad69eff93f8b23..0000000000000000000000000000000000000000 --- a/app/src/main/res/values-mk/strings.xml +++ /dev/null @@ -1,6 +0,0 @@ -<?xml version='1.0' encoding='UTF-8'?> -<resources> - <string name="save">Зачувај</string> - <string name="setup_error_configure_button">Постави</string> - <string name="setup_error_close_button">Излез</string> -</resources> diff --git a/app/src/main/res/values-my/strings.xml b/app/src/main/res/values-my/strings.xml index a5b8264cd81410b7f8c72e8c55dab68a5d1e125e..17aca9276cfb032084f662c51d5b71b7be24456b 100644 --- a/app/src/main/res/values-my/strings.xml +++ b/app/src/main/res/values-my/strings.xml @@ -3,7 +3,7 @@ <string name="retry">ပြန်စမ်းကြည့်မယ်</string> <string name="repository_url_text">အရင်းအမြစ်ကုဒ် ကိုဤ လင့်တွင်ရရှိနိုင်ပါသည် - https://0xacab.org/leap/bitmask_android</string> <string name="leap_tracker">ခြေရာခံမှတ်တမ်း ကိုဤ လင့်တွင်ရရှိနိုင်ပါသည် - https://0xacab.org/leap/bitmask_android/issues</string> - <string name="translation_project_text">ဘာသာပြန်များကို ကြိုဆိုပြီး တန်ဖိုးထားကြိုဆိုပါသည်။ ကျွန်ုပ်တို့ Transifex စီမံကိန်းကို https://www.transifex.com/projects/p/bitmask-android/ တွင်ကြည့်ရှုနိုင်ပါသည်။</string> + <string name="translation_project_text">ဘာသာပြန်များကို ကြိုဆိုပြီး တန်ဖိုးထားကြိုဆိုပါသည်။ ကျွန်ုပ်တို့ Transifex စီမံကိန်းကို https://www.transifex.com/projects/p/bitmask/ တွင်ကြည့်ရှုနိုင်ပါသည်။</string> <string name="switch_provider_menu_option">ဝန်ဆောင်မှုပေးသူ ပြောင်းမယ်</string> <string name="info">အချက်အလက်များ</string> <string name="show_connection_details">ဆက်သွယ်မှုအချက်အလက်များ ဖော်ပြမယ်</string> @@ -146,6 +146,7 @@ <string name="version_update_error_pgp_verification">PGP အတည်ပြုခြင်း မအောင်မြင်ပါ။ ဒေါင်းလုပ်အား လျစ်လျူရှုနေသည်။</string> <string name="version_update_error">အဆင်မြှင့်ခြင်း မအောင်မြင်ပါ။</string> <string name="version_update_error_permissions">အပ္ပလီကေးရှင်းကို ဒေါင်းလုပ်ဆွဲရန် ခွင့်ပြုချက်မရှိပါ။</string> + <string name="gateway_selection_automatic">အလိုအလျောက်</string> <string name="log_onehop_create">ကုဒ်ဖြင့်စာဝှက်ထားသည့် ဖိုင်လမ်းကြောင်း ချိတ်ဆက်မှု တစ်ခု တည်ဆောက်နေသည်</string> <string name="log_loading_keys">လုပ်ပိုင်ခွင့် လက်မှတ်များကို ရယူနေသည်</string> <string name="log_circuit_create">Tor ဆားကစ် တစ်ခုကို တည်ဆောက်နေသည်</string> diff --git a/app/src/main/res/values-nl/strings.xml b/app/src/main/res/values-nl/strings.xml index 7881f5c8df67d05c272fc75f87b3031737d6e4cc..30965579cd97ab4aa7a4e58739a78069757de479 100644 --- a/app/src/main/res/values-nl/strings.xml +++ b/app/src/main/res/values-nl/strings.xml @@ -3,7 +3,7 @@ <string name="retry">Opnieuw proberen</string> <string name="repository_url_text">Broncode is beschikbaar op https://0xacab.org/leap/bitmask_android</string> <string name="leap_tracker">Issue tracker https://0xacab.org/leap/bitmask_android/issues</string> - <string name="translation_project_text">Vertalingen zijn welkom en worden gewaardeerd. Kijk voor meer info op onze Transifex pagina: https://www.transifex.com/projects/p/bitmask-android/</string> + <string name="translation_project_text">Vertalingen zijnhartelijk welkom. Kijk voor meer info op https://wiki.localizationlab.org/index.php/Bitmask of ga direct naar onze Transifex pagina: https://www.transifex.com/projects/p/bitmask/</string> <string name="switch_provider_menu_option">Provider wisselen</string> <string name="info">info</string> <string name="show_connection_details">Details van de verbinding weergeven</string> @@ -69,6 +69,9 @@ Je kan kiezen om te herconfigureren of af te sluiten en bij de volgende start ee <string name="authentication_failed_message">Authenticatie is mislukt</string> <string name="registration_failed_message">Registratie mislukt</string> <string name="eip_status_start_pending">Verbinding wordt geïnitialiseerd</string> + <string name="eip_status_connecting">Verbinden met VPN</string> + <string name="eip_status_unsecured">Onbeveiligde Verbinding</string> + <string name="eip_status_secured">Beveiligde Verbinding</string> <string name="eip_cancel_connect_title">Verbinding verbreken?</string> <string name="eip_cancel_connect_text">We proberen een verbinding tot stand te brengen. Wil je dit annuleren?</string> <string name="eip.warning.browser_inconsistency">VPN verbinding verbreken? Wanneer de VPN uitstaat, kan je persoonlijke data lekken naar je internetprovider of je lokale netwerk.</string> @@ -203,4 +206,6 @@ Je kan kiezen om te herconfigureren of af te sluiten en bij de volgende start ee <string name="disabled_while_udp_on">Uitgeschakeld wanneer UDP aan is.</string> <string name="advanced_settings">Geavanceerde instellingen</string> <string name="cancel_connection">Verbreek</string> + <string name="unknown_location">Onbekende locatie</string> + <string name="splash_footer">Ontwikkeld door LEAP</string> </resources> diff --git a/app/src/main/res/values-no/strings.xml b/app/src/main/res/values-no/strings.xml index c5fea00d406382f9a5f02d048f2cb9db474135b9..a60189267e090faa200ca7e41d763cb30ea909ad 100644 --- a/app/src/main/res/values-no/strings.xml +++ b/app/src/main/res/values-no/strings.xml @@ -3,7 +3,7 @@ <string name="retry">Prøv på nytt</string> <string name="repository_url_text">Kildekode tilgjengelig på https://0xacab.org/leap/bitmask_android</string> <string name="leap_tracker">Feilsporer tilgjengelig på https://0xacab.org/leap/bitmask_android/issues</string> - <string name="translation_project_text">Oversettelser er velkomne og verdsatt. Se vårt Transifex-prosjekt på https://www.transifex.com/projects/p/bitmask-android/</string> + <string name="translation_project_text">Oversettelser er velkomne og verdsatt. Se vårt Transifex-prosjekt på https://www.transifex.com/projects/p/bitmask/</string> <string name="switch_provider_menu_option">Bytt tilbyder</string> <string name="info">info</string> <string name="show_connection_details">Vis tilkoblingsdetaljer</string> diff --git a/app/src/main/res/values-pl/strings.xml b/app/src/main/res/values-pl/strings.xml index 70a6ed6679a0d4c96485113353c40fbd5b3608d2..809ecd004c7998844fbcace6ee8dc46156b83de0 100644 --- a/app/src/main/res/values-pl/strings.xml +++ b/app/src/main/res/values-pl/strings.xml @@ -3,7 +3,7 @@ <string name="retry">Spróbuj ponownie</string> <string name="repository_url_text">Kod źródłowy dostępny na https://0xacab.org/leap/bitmask_android</string> <string name="leap_tracker">Śledzenie problemów dostępne pod adresem https://0xacab.org/leap/bitmask_android/issues</string> - <string name="translation_project_text">Tłumaczenia mile widziane i doceniane. Zobacz nasz projekt Transifex na https://www.transifex.com/projects/p/bitmask-android/</string> + <string name="translation_project_text">Tłumaczenia mile widziane i doceniane. Zobacz nasz projekt Transifex na https://www.transifex.com/projects/p/bitmask/</string> <string name="switch_provider_menu_option">Zmień dostawcę</string> <string name="info">info</string> <string name="show_connection_details">Pokaż szczegóły połączenia</string> diff --git a/app/src/main/res/values-port/dimens.xml b/app/src/main/res/values-port/dimens.xml new file mode 100644 index 0000000000000000000000000000000000000000..90b6b82bd73c24a1365d44de2c1b91a52bf02391 --- /dev/null +++ b/app/src/main/res/values-port/dimens.xml @@ -0,0 +1,5 @@ +<?xml version="1.0" encoding="utf-8"?> +<resources> + <dimen name="footer_text_padding">20dp</dimen> + <dimen name="splash_text_top_padding">120dp</dimen> +</resources> \ No newline at end of file diff --git a/app/src/main/res/values-pt-rBR/strings.xml b/app/src/main/res/values-pt-rBR/strings.xml index bf0559d4cc13aa29343a866c68f609d0d5ff2d37..9d83ff49fd5a933e6378ee12f8d03944f3c56f4e 100644 --- a/app/src/main/res/values-pt-rBR/strings.xml +++ b/app/src/main/res/values-pt-rBR/strings.xml @@ -1,12 +1,13 @@ <?xml version='1.0' encoding='UTF-8'?> <resources> - <string name="retry">Tente novamente</string> + <string name="retry">Tentar novamente</string> <string name="repository_url_text">Código fonte disponível em https://0xacab.org/leap/bitmask_android</string> <string name="leap_tracker">O gerenciador de bugs está disponível em https://0xacab.org/leap/bitmask_android/issues</string> - <string name="translation_project_text">Traduções são bem-vindas. Veja nosso projeto do Transifex em https://www.transifex.com/projects/p/bitmask-android/</string> + <string name="translation_project_text">Traduções são bem-vindas. Veja nosso projeto do Transifex em https://www.transifex.com/projects/p/bitmask/</string> <string name="switch_provider_menu_option">Trocar provedor</string> <string name="info">info</string> <string name="show_connection_details">Mostrar os detalhes da conexão</string> + <string name="connection_details">Detalhes da conexão</string> <string name="routes_info">Rotas: %s</string> <string name="routes_info6">Rotas IPv6 %s</string> <string name="error_empty_username">O nome do usuário não pode estar vazio.</string> @@ -51,6 +52,7 @@ <string name="setup_error_configure_button">Configurar</string> <string name="setup_error_close_button">Sair</string> <string name="setup_error_text">Houve um erro configurando %s com o provedor escolhido por você.\n\nVocê pode optar por reconfigurar ou sair e configurar um provedor na próxima vez que abrir o programa. </string> + <string name="setup_error_text_custom">Houve um erro ao configurar %s.\n\nVocê pode reconfigurar ou sair.</string> <string name="server_unreachable_message">O servidor está inalcançável, tente novamente.</string> <string name="error.security.pinnedcertificate">Erro de segurança, atualize seu aplicativo ou escolha outro provedor.</string> <string name="malformed_url">Não parece ser um provedor %s.</string> @@ -87,6 +89,7 @@ <string name="action_example">Ação de exemplo</string> <string name="action_settings">Configurações</string> <string name="void_vpn_establish">%s bloqueia todo o tráfego de saída de internet.</string> + <string name="void_vpn_error_establish">Falha ao bloquear todo o tráfego de Internet.</string> <string name="void_vpn_stopped">Parou de bloquear todo o tráfego de saída de internet.</string> <string name="void_vpn_title">Bloqueando tráfego</string> <string name="update_provider_details">Atualizar detalhes do provedor</string> @@ -101,11 +104,21 @@ <string name="vpn_certificate_is_invalid">Certificado VPN inválido. Tente baixar um novo.</string> <string name="vpn_certificate_user_message">O certificado VPN é inválido. Por favor, faça login e baixe um novo.</string> <string name="save_battery">Economizar energia</string> + <string name="subtitle_save_battery">Desabilitado enquanto o Ponto de acesso VPN estiver ligado</string> <string name="save_battery_message">Conexões de dados em segundo plano vão hibernar quando o seu telefone estiver inativo.</string> <string name="always_on_vpn">VPN sempre ativa</string> <string name="subtitle_always_on_vpn">Abrir configurações do Android</string> + <string name="tethering">Ponto de acesso VPN</string> + <string name="ipv6Firewall">Bloquear IPv6</string> + <string name="require_root">Requer permissões de root</string> <string name="show_experimental">Mostrar recursos experimentais</string> <string name="hide_experimental">Esconder recursos experimentais</string> + <string name="experimental_features">Funcionalidades experimentais</string> + <string name="tethering_enabled_message">Por favor tenha certeza de primeiro habilitar tethering nas <![CDATA[<b>configurações de sistema</b>]]>.</string> + <string name="tethering_message">Compartilhe sua VPN com outros dispositivos através de:</string> + <string name="tethering_wifi">Hotspot Wi-Fi</string> + <string name="tethering_usb">Tethering USB</string> + <string name="tethering_bluetooth">Tethering Bluetooth</string> <string name="do_not_show_again">Não mostrar novamente</string> <string name="always_on_vpn_user_message">Para habilitar VPN sempre ativa nas configurações de VPN clique no ícone de configurar [img src] e mude para ligado. </string> <string name="always_on_blocking_vpn_user_message">Para proteger sua privacidade da melhor forma, você deveria ativar também a opção \"Bloqueie conexões sem VPN\"</string> @@ -121,22 +134,72 @@ <string name="warning_exclude_apps_message">Seja cuidadoso ao excluir apps da VPN. Isso pode revelar sua identidade e comprometer sua segurança.</string> <plurals name="subtitle_exclude_apps"> <item quantity="one">%d app desprotegido</item> + <item quantity="many">%d apps desprotegidos</item> <item quantity="other">%d apps desprotegidos</item> </plurals> <string name="warning_no_more_gateways_use_pt">%s não pode se conectar. Isso pode ser devido ao bloqueio de conexões via VPN. Você deseja se conectar usando uma conexão ofuscada?</string> <string name="warning_no_more_gateways_no_pt">%s não pode se conectar. Gostaria de tentar novamente?</string> <string name="warning_no_more_gateways_use_ovpn">%s não pode se conectar usando uma VPN ofuscada. Voce gostaria de tentar usando uma conexão padrão?</string> + <string name="warning_no_more_gateways_manual_gw_selection">%1$s não pôde conectar a %2$s. Você quer tentar conectar automaticamente ao melhor local?</string> + <string name="warning_option_try_best">Tentar o melhor local</string> <string name="warning_option_try_pt">Tentar conexão ofuscada</string> <string name="warning_option_try_ovpn">Tentar conexão padrão</string> <string name="vpn_error_establish">Android falhou ao estabelecer o serviço VPN.</string> + <string name="root_permission_error">%s não pode ativar funcionalidades como Ponto de acesso VPN ou Firewall IPv6 sem permissões de root.</string> + <string name="qs_enable_vpn">Iniciar %s</string> + <string name="version_update_found">Toque aqui para iniciar o download.</string> + <string name="version_update_title">Uma nova versão de %s foi encontrada.</string> + <string name="version_update_apk_description">Baixando uma nova versão de %s</string> + <string name="version_update_download_title">Uma nova versão de %s foi baixada.</string> + <string name="version_update_download_description">Toque aqui para instalar a atualização.</string> + <string name="version_update_error_pgp_verification">Erro de verificação PGP. Ignorando arquivo baixado.</string> + <string name="version_update_error">Falha ao atualizar.</string> + <string name="version_update_error_permissions">Sem permissões para instalar o aplicativo.</string> + <string name="gateway_selection_title">Selecione o local</string> + <string name="gateway_selection_recommended_location">Local recomendado</string> <string name="gateway_selection_recommended">Recomendado</string> + <string name="gateway_selection_manually">Selecione manualmente</string> + <string name="gateway_selection_automatic_location">Use a melhor conexão automaticamente</string> <string name="gateway_selection_automatic">Automático</string> + <string name="reconnecting">Reconectando...</string> + <string name="tor_starting">Iniciando bridges para driblar a censura...</string> + <string name="tor_stopping">Parando bridges</string> + <string name="tor_started">Usando bridges para driblar a censura</string> + <string name="log_conn_done_pt">Conectado a um transporte plugável</string> + <string name="log_conn_pt">Conectando a um transporte plugável</string> + <string name="log_conn_done">Conectando a um relay</string> + <string name="log_handshake">Negociando conexão com um relay</string> + <string name="log_handshake_done">Conexão com relay negociada</string> <string name="log_onehop_create">Estabelecendo uma conexão de diretório criptografado</string> + <string name="log_requesting_status">Solicitando consenso do estado da rede</string> + <string name="log_loading_status">Carregando o consenso do estado da rede</string> <string name="log_loading_keys">Carregando certificados de autoridade</string> + <string name="log_requesting_descriptors">Solicitando descritores de relay</string> + <string name="log_loading_descriptors">Carregando descritores de relay</string> + <string name="log_enough_dirinfo">Informações suficientes sobre diretório foram carregadas para construir circuitos</string> + <string name="log_ap_handshake_done">Negociação finalizada com relay para construção de circuitos</string> <string name="log_circuit_create">Estabelecendo um circuito Tor</string> <string name="log_done">Executando</string> + <string name="channel_name_tor_service">%s Serviço de Bridges</string> + <string name="channel_description_tor_service">Informa sobre o uso de bridges ao configurar %s.</string> + <string name="error_tor_timeout">A inicialização de bridges falhou. Você quer tentar novamente ou continuar com uma conexão segura sem ofuscação para configurar %s?</string> + <string name="retry_unobfuscated">Tentar sem ofuscação</string> <string name="hide">Esconder</string> + <string name="error_network_connection">%s não tem conexão à Internet. Por favor verifique suas configurações de WiFi e dados móveis.</string> + <string name="censorship_circumvention">Driblando censura</string> <string name="use_snowflake">Usar Snowflake</string> + <string name="snowflake_description">Proteger processo de configuração contra censura.</string> + <string name="vpn_settings">Configurações de VPN</string> + <string name="prefer_udp">Usar UDP se disponível</string> + <string name="prefer_udp_subtitle">UDP pode ser mais rápido e melhor para transmissões (streaming), mas não funciona para todas as redes.</string> + <string name="disabled_while_bridges_on">Desabilitado durante o uso de bridges.</string> + <string name="hint_bridges">Apenas locais com suporte a bridges podem ser selecionados.</string> + <string name="option_disable_bridges">Desabilitar bridges</string> + <string name="eip_state_insecure">Conexão insegura</string> + <string name="connection_not_connected">Você pode estar vazando informações para seu provedor de Internet ou rede local.</string> + <string name="eip_state_no_network">Você não tem uma conexão de Internet funcionando. Assim que houver uma, você será automaticamente conectada a</string> + <string name="eip_state_blocking">%1$s está bloqueando todo o tráfego de Internet.</string> + <string name="disabled_while_udp_on">Desabilitado enquanto UDP estiver ligado.</string> <string name="advanced_settings">Configurações avançadas</string> <string name="cancel_connection">Desconectar</string> </resources> diff --git a/app/src/main/res/values-pt-rPT/strings.xml b/app/src/main/res/values-pt-rPT/strings.xml index 5630906e095859a8226da104506d076e7798235c..c74335bb5c458d66574290c8e04552e3fe40eb25 100644 --- a/app/src/main/res/values-pt-rPT/strings.xml +++ b/app/src/main/res/values-pt-rPT/strings.xml @@ -3,7 +3,7 @@ <string name="retry">Repetir</string> <string name="repository_url_text">O código fonte está disponível em https://0xacab.org/leap/bitmask_android</string> <string name="leap_tracker">O rastreador de problemas está disponível em https://0xacab.org/leap/bitmask_android/issues</string> - <string name="translation_project_text">As traduções são bem-vindas e apreciadas. Consulte o nosso projeto na Transifex em https://www.transifex.com/projects/p/bitmask-android/</string> + <string name="translation_project_text">As traduções são bem-vindas e apreciadas. Consulte o nosso projeto na Transifex em https://www.transifex.com/projects/p/bitmask/</string> <string name="switch_provider_menu_option">Mudar Provedor</string> <string name="info">informação</string> <string name="show_connection_details">Mostrar detalhes da ligação</string> diff --git a/app/src/main/res/values-ro/strings.xml b/app/src/main/res/values-ro/strings.xml index c995442c2d4d22a74386d23304eb37e88d4e30d3..8357f1d2e648fbd40b3fed0b7d15bd082a1f436b 100644 --- a/app/src/main/res/values-ro/strings.xml +++ b/app/src/main/res/values-ro/strings.xml @@ -39,6 +39,8 @@ <string name="eip_cancel_connect_text">Există o încercare de conexiune în progres. Doriți să o anulați?</string> <string name="default_username">Anonim</string> <string name="logging_in">Autentificare</string> + <string name="vpn.button.turn.on">Deschidere</string> + <string name="vpn.button.turn.off">Închidere</string> <string name="log_fragment_title">Jurnal</string> <string name="vpn_fragment_title">VPN</string> <string name="navigation_drawer_open">Deschide sertarul de navigare</string> diff --git a/app/src/main/res/values-ru/strings.xml b/app/src/main/res/values-ru/strings.xml index d670989154de151a4f1081e6bf6c2ba5dc7fb2ec..2db7999b158d1cd7e523439e3c123272f8807c56 100644 --- a/app/src/main/res/values-ru/strings.xml +++ b/app/src/main/res/values-ru/strings.xml @@ -4,44 +4,43 @@ <string name="repository_url_text">Исходный код доступен на https://0xacab.org/leap/bitmask_android</string> <string name="leap_tracker">Отслеживание проблем доступно на https://0xacab.org/leap/bitmask_android/issues</string> - <string name="translation_project_text">Переводы приветствуются. Смотрите наш проект Transifex на -https://www.transifex.com/projects/p/bitmask-android/</string> - <string name="switch_provider_menu_option">Смена провайдера</string> - <string name="info">Информация</string> - <string name="show_connection_details">Показать подробности о соединении</string> + <string name="translation_project_text">Переводы приветствуются. Наш проект на Transifex: https://www.transifex.com/projects/p/bitmask/</string> + <string name="switch_provider_menu_option">Сменить провайдера</string> + <string name="info">информация</string> + <string name="show_connection_details">Показать сведения о соединении</string> <string name="connection_details">Сведения о соединении</string> <string name="routes_info">Маршруты: %s</string> <string name="routes_info6">Маршруты IPv6: %s</string> <string name="error_empty_username">Имя пользователя не должно быть пустым</string> <string name="cert_from_keystore">Получен сертификат \"%s\" из хранилища ключей</string> <string name="provider_label">Провайдер:</string> - <string name="provider_label_none">Ни один провайдер не настроен</string> - <string name="status_unknown">Состояние неизвестно.</string> - <string name="eip_service_label">Зашифрованное VPN-соединение с интернетом доступно</string> + <string name="provider_label_none">Провайдер не настроен</string> + <string name="status_unknown">Статус неизвестен.</string> + <string name="eip_service_label">Зашифрованный доступ в интернет через VPN</string> <string name="configuration_wizard_title">Выбрать провайдера</string> <string name="add_provider">Добавить нового провайдера</string> - <string name="introduce_new_provider">Добавить нового провайдера услуг</string> + <string name="introduce_new_provider">Добавить нового провайдера</string> <string name="save">Сохранить</string> - <string name="new_provider_uri">Имя домена</string> + <string name="new_provider_uri">Доменное имя</string> <string name="valid_url_entered">URL действителен</string> - <string name="not_valid_url_entered">Неправильно сформированный URL</string> + <string name="not_valid_url_entered">Неправильный URL</string> <string name="provider_details_title">Информация о провайдере</string> <string name="use_anonymously_button">Использовать анонимно</string> - <string name="username_hint">Имя пользователя</string> + <string name="username_hint">имя пользователя</string> <string name="username_ask">Введите имя пользователя</string> <string name="password_ask">Введите пароль</string> - <string name="password_hint">Пароль</string> + <string name="password_hint">пароль</string> <string name="password_match">Пароли совпадают</string> <string name="password_mismatch">Пароли не совпадают</string> <string name="user_message">Сообщение пользователя</string> <string name="about_fragment_title">О нас</string> <string name="exclude_apps_fragment_title">Исключение приложений</string> - <string name="error_srp_math_error_user_message">Попытайтесь снова: ошибка сервера</string> + <string name="error_srp_math_error_user_message">Повторите попытку: ошибка сервера</string> <string name="error_bad_user_password_user_message">Неправильное имя пользователя или пароль</string> - <string name="error_not_valid_password_user_message">Должно быть не менее 8 символов</string> - <string name="error_client_http_user_message">Попытайтесь снова: ошибка HTTP-клиента</string> - <string name="error_io_exception_user_message">Попытайтесь снова: ошибка ввода/вывода</string> - <string name="error_json_exception_user_message">Попытайтесь снова: некорректный ответ от сервера</string> + <string name="error_not_valid_password_user_message">Длина должна быть не менее 8 символов</string> + <string name="error_client_http_user_message">Повторите попытку: ошибка HTTP-клиента</string> + <string name="error_io_exception_user_message">Повторите попытку: ошибка ввода/вывода</string> + <string name="error_json_exception_user_message">Повторите попытку: некорректный ответ от сервера</string> <string name="error_no_such_algorithm_exception_user_message">Алгоритм шифрования не найден. Обновите Android!</string> <string name="signup_or_login_button">Регистрация/вход</string> <string name="login_button">Войти</string> @@ -53,24 +52,27 @@ https://www.transifex.com/projects/p/bitmask-android/</string> <string name="setup_error_title">Ошибка конфигурации</string> <string name="setup_error_configure_button">Настройка</string> <string name="setup_error_close_button">Выход</string> - <string name="setup_error_text">Произошла ошибка при настройке %s с выбранным провайдером.\n\nВы можете выбрать перенастройку или выход и настройку поставщика при следующем запуске.</string> + <string name="setup_error_text">Произошла ошибка при настройке %s с выбранным вами провайдером.\n\nВы можете выбрать повторную настройку или выйти и настроить провайдера при следующем запуске.</string> <string name="setup_error_text_custom">Произошла ошибка в конфигурации %s.\n\nМожно изменить конфигурацию или выйти.</string> <string name="server_unreachable_message">Сервер недоступен, попробуйте ещё раз.</string> <string name="error.security.pinnedcertificate">Ошибка безопасности, обновите приложение или выберите другого провайдера.</string> - <string name="malformed_url">Не похоже, что %s провайдер.</string> - <string name="certificate_error">Это не доверенный %s провайдер.</string> + <string name="malformed_url">Похоже, %s не провайдер.</string> + <string name="certificate_error">%s не надёжный провайдер.</string> <string name="service_is_down_error">Сервис недоступен.</string> <string name="configuring_provider">Настройка провайдера</string> - <string name="incorrectly_downloaded_certificate_message">Ваш анонимный сертификат не загружен</string> + <string name="incorrectly_downloaded_certificate_message">Ваш анонимный сертификат не был загружен</string> <string name="downloading_certificate_message">Скачивание сертификата VPN</string> <string name="updating_certificate_message">Обновление сертификата VPN</string> - <string name="login.riseup.warning">Пользователям Riseup будет необходимо создать отдельный аккаунт для использования сервиса VPN.</string> + <string name="login.riseup.warning">Пользователям Riseup потребуется создать отдельную учётную запись для использования VPN</string> <string name="succesful_authentication_message">Аутентифицирован</string> <string name="authentication_failed_message">Ошибка аутентификации</string> <string name="registration_failed_message">Регистрация не выполнена</string> <string name="eip_status_start_pending">Установка соединения</string> + <string name="eip_status_connecting">Подключение VPN</string> + <string name="eip_status_unsecured">Небезопасное соединение</string> + <string name="eip_status_secured">Безопасное соединение</string> <string name="eip_cancel_connect_title">Отменить соединение?</string> - <string name="eip_cancel_connect_text">Производится попытка установить соединение. Прервать её?</string> + <string name="eip_cancel_connect_text">Идёт попытка подключения. Вы хотите её отменить?</string> <string name="eip.warning.browser_inconsistency">Отключить VPN-соединение? При отключённой VPN ваша персональная информация может стать доступна провайдеру или в местной сети.</string> <string name="eip_state_not_connected">Не работает! Соединение небезопасно!</string> <string name="eip_state_connected">Безопасное соединение</string> @@ -92,7 +94,7 @@ https://www.transifex.com/projects/p/bitmask-android/</string> <string name="action_settings">Настройки</string> <string name="void_vpn_establish">%s блокирует весь исходящий интернет-трафик.</string> <string name="void_vpn_error_establish">Невозможно блокировать весь интернет-трафик.</string> - <string name="void_vpn_stopped">Перестал блокироваться весь исходящий интернет-трафик.</string> + <string name="void_vpn_stopped">Прекращена блокировка всего исходящего интернет-трафика.</string> <string name="void_vpn_title">Блокирование трафика</string> <string name="update_provider_details">Обновление информации провайдера</string> <string name="update_certificate">Обновление сертификата</string> @@ -100,7 +102,7 @@ https://www.transifex.com/projects/p/bitmask-android/</string> <string name="eip_json_corrupted_user_message">Невозможно обновить конфигурацию провайдера. Войдите, чтобы повторить попытку.</string> <string name="warning_client_parsing_error_gateways">Невозможно распознать шлюзы поставщика. Они могут быть настроены неправильно.</string> <string name="warning_corrupted_provider_details">Сохранённые сведения о провайдере повреждены. Можно либо обновить %s (рекомендуется), либо обновить сведения о поставщике с помощью коммерческого сертификата ЦС.</string> - <string name="warning_corrupted_provider_cert">Сохранённый сертификат провайдера недопустим. Можно либо обновить %s (рекомендуется), либо обновить сертификат поставщика с помощью коммерческого сертификата ЦС.</string> + <string name="warning_corrupted_provider_cert">Сохранённый сертификат провайдера недействителен. Вы можете либо обновить %s (рекомендуется), либо обновить сертификат провайдера используя коммерческий сертификат центра сертификации.</string> <string name="warning_expired_provider_cert">Срок действия сохранённого сертификата провайдера истёк. Можно либо обновить %s (рекомендуется), либо обновить сертификат поставщика с помощью коммерческого сертификата ЦС.</string> <string name="downloading_vpn_certificate_failed">Загрузка сертификата VPN не выполнена. Попробуйте ещё раз или выберите другого провайдера.</string> <string name="vpn_certificate_is_invalid">Сертификат VPN недействителен. Попытайтесь загрузить новый.</string> @@ -117,7 +119,7 @@ https://www.transifex.com/projects/p/bitmask-android/</string> <string name="hide_experimental">Скрыть экспериментальные функции</string> <string name="experimental_features">Экспериментальные функции</string> <string name="tethering_enabled_message">Не забудьте сначала включить модем в <![CDATA[<b>системных настройках</b>]]>.</string> - <string name="tethering_message">Раздавать VPN другим устройствами через:</string> + <string name="tethering_message">Поделиться VPN с другими устройствами через:</string> <string name="tethering_wifi">Точка доступа Wi-Fi</string> <string name="tethering_usb">USB-модем</string> <string name="tethering_bluetooth">Bluetooth-модем</string> @@ -129,23 +131,23 @@ https://www.transifex.com/projects/p/bitmask-android/</string> <string name="donate_message">LEAP зависит от пожертвований и грантов. Пожалуйста, сделайте пожертвование сегодня, если вы цените безопасное общение, простое как для конечного пользователя, так и для поставщика услуг.</string> <string name="donate_button_remind_later">Напомнить позже</string> <string name="donate_button_donate">Пожертвование</string> - <string name="obfuscated_connection">Использование запутанного соединения.</string> - <string name="obfuscated_connection_try">Попытка запутывания соединения.</string> + <string name="obfuscated_connection">Использование обфускации соединения.</string> + <string name="obfuscated_connection_try">Попытка обфускации соединения.</string> <string name="nav_drawer_obfuscated_connection">Использовать мосты</string> <string name="nav_drawer_subtitle_obfuscated_connection">Обход фильтрации VPN</string> <string name="warning_exclude_apps_message">Будьте осторожны, исключая приложения из VPN. Это позволит раскрыть вашу личность и поставить под угрозу вашу безопасность.</string> <plurals name="subtitle_exclude_apps"> - <item quantity="one">%d незащищённое приложение</item> - <item quantity="few">%d незащищённых приложения</item> - <item quantity="many">%d незащищённых приложений</item> + <item quantity="one">%d незащищенное приложение</item> + <item quantity="few">%d незащищенных приложения</item> + <item quantity="many">%d незащищенных приложений</item> <item quantity="other">%d незащищённых приложений</item> </plurals> - <string name="warning_no_more_gateways_use_pt">%s не удалось подключиться. Возможно, что VPN-соединения блокируются. Попробовать подключиться с помощью запутанных соединений?</string> + <string name="warning_no_more_gateways_use_pt">%s не подключается. Возможно, что VPN-соединения блокируются. Попробовать подключиться с помощью обфускации соединения?</string> <string name="warning_no_more_gateways_no_pt">%s не удалось подключиться. Повторить попытку?</string> - <string name="warning_no_more_gateways_use_ovpn">%s не удалось подключиться с помощью запутанных VPN-подключений. Попробовать подключиться с помощью стандартного VPN?</string> + <string name="warning_no_more_gateways_use_ovpn">%s не подключается с помощью обфускации VPN-соединения. Попробовать подключиться с помощью стандартного VPN?</string> <string name="warning_no_more_gateways_manual_gw_selection">%1$s не может подключиться к %2$s. Использовать автоматический выбор лучшего расположения?</string> <string name="warning_option_try_best">Попробовать лучшее расположение</string> - <string name="warning_option_try_pt">Попробовать запутать соединение</string> + <string name="warning_option_try_pt">Попробовать обфускацию соединения</string> <string name="warning_option_try_ovpn">Попробовать стандартное соединение</string> <string name="vpn_error_establish">Android не удалось установить службу VPN.</string> <string name="root_permission_error">%s не может использовать такие функции, как точка доступа VPN или блокировка IPv6, без root-прав.</string> @@ -185,8 +187,8 @@ https://www.transifex.com/projects/p/bitmask-android/</string> <string name="log_done">Запущено</string> <string name="channel_name_tor_service">Служба мостов %s</string> <string name="channel_description_tor_service">Информирует об использовании мостов при конфигурации %s.</string> - <string name="error_tor_timeout">Невозможно запустить мосты. Повторить попытку или продолжить с безопасным соединением без запутывания для настройки %s?</string> - <string name="retry_unobfuscated">Повтор без запутывания</string> + <string name="error_tor_timeout">Невозможно запустить мосты. Повторить попытку или продолжить безопасное соединение без обфускации, чтобы настроить %s?</string> + <string name="retry_unobfuscated">Повтор без обфускации</string> <string name="hide">Скрыть</string> <string name="error_network_connection">%s не имеет подключения к интернету. Проверьте настройки Wi-Fi и сотовой связи.</string> <string name="censorship_circumvention">Обход цензуры</string> @@ -205,4 +207,6 @@ https://www.transifex.com/projects/p/bitmask-android/</string> <string name="disabled_while_udp_on">Отключено при использовании UDP.</string> <string name="advanced_settings">Дополнительно</string> <string name="cancel_connection">Отключить</string> + <string name="unknown_location">Неизвестное местоположение</string> + <string name="splash_footer">Разработано LEAP</string> </resources> diff --git a/app/src/main/res/values-sl/plurals-icsopenvpn.xml b/app/src/main/res/values-sl/plurals-icsopenvpn.xml deleted file mode 100755 index a59750835f697217f48877abe5d5adf9d6ce90ed..0000000000000000000000000000000000000000 --- a/app/src/main/res/values-sl/plurals-icsopenvpn.xml +++ /dev/null @@ -1,28 +0,0 @@ -<?xml version="1.0" encoding="utf-8"?> -<!--Generated by crowdin.com--> -<resources> - <plurals name="months_left"> - <item quantity="one">Preostal je še en mesec</item> - <item quantity="two">Preostala sta še %d meseca</item> - <item quantity="few">Preostali so še %d meseci</item> - <item quantity="other">Preostalo je še %d mesecev</item> - </plurals> - <plurals name="days_left"> - <item quantity="one">Preostal je še en dan</item> - <item quantity="two">Preostala sta še %d dneva</item> - <item quantity="few">Preostali so še %d-je dnevi</item> - <item quantity="other">Preostalih je še %d dni</item> - </plurals> - <plurals name="hours_left"> - <item quantity="one">Preostala je še ena ura</item> - <item quantity="two">Preostali sta še %d uri</item> - <item quantity="few">Preostale so še %d ure</item> - <item quantity="other">Preostalo je še %d ur</item> - </plurals> - <plurals name="minutes_left"> - <item quantity="one">Preostala je še ena minuta</item> - <item quantity="two">Preostali sta še %d minuti</item> - <item quantity="few">Preostale so še %d minute</item> - <item quantity="other">Preostalo je še %d minut</item> - </plurals> -</resources> diff --git a/app/src/main/res/values-sl/strings-icsopenvpn.xml b/app/src/main/res/values-sl/strings-icsopenvpn.xml deleted file mode 100755 index 5232713459445d7e50d09ce6855bf33269034d7a..0000000000000000000000000000000000000000 --- a/app/src/main/res/values-sl/strings-icsopenvpn.xml +++ /dev/null @@ -1,432 +0,0 @@ -<?xml version="1.0" encoding="utf-8"?> -<!--Generated by crowdin.com--> -<!-- - ~ 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> - - <string name="address">Naslov strežnika:</string> - <string name="port">Vrata strežnika:</string> - <string name="location">Mesto</string> - <string name="cant_read_folder">Branje mape ni mogoče</string> - <string name="select">Izberi</string> - <string name="cancel">Prekliči</string> - <string name="no_data">Ni podatkov</string> - <string name="useLZO">Stiskanje LZO</string> - <string name="client_no_certificate">Ni potrdil</string> - <string name="client_certificate_title">Potrdilo odjemalca</string> - <string name="client_key_title">Ključ potrdila odjemalca</string> - <string name="client_pkcs12_title">Datoteka PKCS12</string> - <string name="ca_title">Potrdilo CA</string> - <string name="no_certificate">Izbrati morate potrdilo</string> - <string name="copyright_guicode">Izvorna koda in sledilnik težav sta na voljo na http://code.google.com/p/ics-openvpn/</string> - <string name="copyright_others">Ta program uporablja naslednje sestavne dele; za vse podrobnosti o dovoljenjih glejte izvorno kodo</string> - <string name="about">O programu</string> - <string name="vpn_list_title">Profili</string> - <string name="vpn_type">Vrsta</string> - <string name="pkcs12pwquery">Geslo PKCS12</string> - <string name="file_select">Izberi …</string> - <string name="file_nothing_selected">Izbrati morate datoteko</string> - <string name="useTLSAuth">Uporabi overitev TLS</string> - <string name="tls_direction">Smer TLS</string> - <string name="ipv6_dialog_tile">Vnesite naslov IPv6/masko omrežja v obliki CIDR (npr. 2000:dd::23/64)</string> - <string name="ipv4_dialog_title">Vnesite naslov IPv4/masko omrežja v obliki CIDR (npr. 1.2.3.4/24)</string> - <string name="ipv4_address">Naslov IPv4</string> - <string name="ipv6_address">Naslov IPv6</string> - <string name="custom_option_warning">Vnesite možnosti OpenVPN po meri. Uporabljajte previdno. Upoštevajte tudi, da veliko nastavitev OpenVPN povezanih z napravami TUN ni mogoče podpreti z zasnovo nastavitev VPN. Če mislite, da manjka pomembna možnost, navežite stik z avtorjem.</string> - <string name="auth_username">Uporabniško ime</string> - <string name="auth_pwquery">Geslo</string> - <string name="static_keys_info">Za statično nastavitev bodo ključi overitve TLS uporabljeni kot statični ključi</string> - <string name="configure_the_vpn">Nastavi VPN</string> - <string name="menu_add_profile">Dodaj profil</string> - <string name="add_profile_name_prompt">Vnesite ime, ki bo označevalo nov profil</string> - <string name="duplicate_profile_name">Vnesite edinstveno ime profila</string> - <string name="profilename">Ime profila</string> - <string name="no_keystore_cert_selected">Izbrati morate uporabniško potrdilo</string> - <string name="no_ca_cert_selected">Izbrati morate potrdilo overitelja potrdil</string> - <string name="no_error_found">Ni najdenih napak</string> - <string name="config_error_found">Napaka v nastavitvah</string> - <string name="ipv4_format_error">Napaka pri razčlenjevanju naslova IPv4</string> - <string name="custom_route_format_error">Napaka pri razčlenjevanju poti po meri</string> - <string name="pw_query_hint">(pustite prazno za poizvedbo na zahtevo)</string> - <string name="vpn_shortcut">Bližnjica OpenVPN</string> - <string name="vpn_launch_title">Povezovanje v VPN …</string> - <string name="shortcut_profile_notfound">Profila, določenega v bližnjici, ni bilo mogoče najti</string> - <string name="random_host_prefix">Predpona naključnega gostitelja</string> - <string name="random_host_summary">Doda 6 naključnih znakov pred ime gostitelja</string> - <string name="custom_config_title">Omogoči možnosti po meri</string> - <string name="custom_config_summary">Določite možnosti po meri. Uporabljajte previdno!</string> - <string name="route_rejected">Android je pot zavrnil</string> - <string name="cancel_connection_long">Prekini VPN</string> - <string name="clear_log">Počisti dnevnik</string> - <string name="title_cancel">Prekliči potrditev</string> - <string name="cancel_connection_query">Prekini povezan VPN/Prekliči poizkus povezave?</string> - <string name="remove_vpn">Odstrani VPN</string> - <string name="check_remote_tlscert">Preveri, ali strežnik uporablja potrdilo s strežniškimi končnicami (--remote-cert-tls strežnik)</string> - <string name="check_remote_tlscert_title">Pričakuj potrdilo str. TLS</string> - <string name="remote_tlscn_check_summary">Preveri DN zadeve potrdila oddaljenega strežnika</string> - <string name="remote_tlscn_check_title">Preveri ime gost. potrdila</string> - <string name="enter_tlscn_dialog">Določite preverjanje, ki naj se uporabi za preverjanje DN-a oddaljenega potrdila (npr. C=DE, L=Paderborn, OU=Avian IP Carriers, CN=openvpn.blinkt.de).\n\nDoločite celoten DN ali RDN (npr. openvpn.blinkt.de) ali predpono RDN-a za preverjanje.\n\nKadar uporabljate predpono RDN, se \"Strežnik\" primerja s \"Strežnik-1\" in \"Strežnik-2\".\n\nČe pustite besedilno polje prazno, bo RDN preverjen z imenom gostitelja.\n\nZa več podatkov glejte OpenVPN 2.3.1 + stran man v —verify-x509-name.</string> - <string name="enter_tlscn_title">Zadeva oddaljenega potrdila</string> - <string name="tls_key_auth">Omogoči overitev ključa TLS</string> - <string name="tls_auth_file">Datoteka overitve TLS</string> - <string name="pull_on_summary">Zahteva naslove IP, poti in časovne možnosti od strežnika.</string> - <string name="pull_off_summary">Nobeni podatki niso zahtevani od strežnika. Nastavitve morate določiti spodaj.</string> - <string name="use_pull">Dobi nast.</string> - <string name="dns">DNS</string> - <string name="override_dns">Preglasi nast. DNS str.</string> - <string name="dns_override_summary">Uporabi moje strežnike DNS</string> - <string name="searchdomain">Išči po domeni</string> - <string name="dns1_summary">Strežnik DNS, ki naj se uporabi.</string> - <string name="dns_server">Strežnik DNS</string> - <string name="secondary_dns_message">Dodatni strežnik DNS, ki naj se uporabi, če običajni strežnik DNS ni dosegljiv.</string> - <string name="backup_dns">Pomožni strežnik DNS</string> - <string name="ignored_pushed_routes">Prezri potisnjene poti</string> - <string name="ignore_routes_summary">Prezri poti, ki jih je potisnil strežnik.</string> - <string name="default_route_summary">Preusmeri ves promet preko VPN-a</string> - <string name="use_default_title">Uporabi privzeto pot</string> - <string name="custom_route_message">Vnesite poti po meri. Cilje vnesite v obliki CIDR. \"10.0.0.0/8 2002::/16\" bo usmeril omrežja 10.0.0.0/8 in 2002::/16 preko VPN-a.</string> - <string name="custom_route_message_excluded">Poti, ki ne smejo biti usmerjene preko VPN-a. Uporabite isto skladnost, kot za vključene poti.</string> - <string name="custom_routes_title">Poti po meri</string> - <string name="custom_routes_title_excluded">Izključena omrežja</string> - <string name="log_verbosity_level">Raven podrobnosti dnevnika</string> - <string name="float_summary">Omogoča overjene pakete iz vseh IP-jev</string> - <string name="float_title">Omogoči lebdeči strežnik</string> - <string name="custom_options_title">Možnosti po meri</string> - <string name="edit_vpn">Uredi nastavitve VPN</string> - <string name="remove_vpn_query">Odstrani profil VPN \'%s\'?</string> - <string name="tun_error_helpful">Na nekaterih odtisih ICS je lahko dovoljenje za /dev/tun napačno ali modul TUN v celoti manjka. Za odtise CM9 poizkusite popraviti možnost lastništva v splošnih možnostih.</string> - <string name="tun_open_error">Odpiranje vmesnika TUN je spodletelo</string> - <string name="error">"Napaka: "</string> - <string name="clear">Počisti</string> - <string name="last_openvpn_tun_config">Odpiranje vmesnika TUN:</string> - <string name="local_ip_info">Krajevni IPv4: %1$s/%2$d IPv6: %3$s MTU: %4$d</string> - <string name="dns_server_info">Strežnik DNS: %1$s, domena: %2$s</string> - <string name="routes_info_incl">Poti: %1$s %2$s</string> - <string name="routes_info_excl">Izključene poti: %1$s %2$s</string> - <string name="routes_debug">Nameščene poti storitve VPN: %1$s %2$s</string> - <string name="ip_not_cidr">Dobljeni podatki vmesnika %1$s in %2$s, predpostavlja se, da je drugi naslov naslov oddaljenega soležnika. Za krajevni IP bo uporabljena maska omrežja /32. Način, ki ga dobavi OpenVPN, je \"%3$s\".</string> - <string name="route_not_cidr">%1$s in %2$s kot poti IP z masko omrežja CIDR ni mogoče razumeti, kot masko omrežja se bo uporabil /32.</string> - <string name="route_not_netip">Popravljena pot %1$s/%2$s v %3$s/%2$s</string> - <string name="keychain_access">Dostop do potrdil verige ključev Android ni mogoč. To lahko povzroči nadgradnja strojne programske opreme ali obnovitev var. kopije programov/nastavitev programov. Uredite VPN in ponovno izberite potrdilo v osnovnih nastavitvah, da poustvarite dovoljenje za dostop do potrdila.</string> - <string name="version_info">%1$s %2$s</string> - <string name="send_logfile">Pošlji dnevniško datoteko</string> - <string name="send">Pošlji</string> - <string name="ics_openvpn_log_file">Dnevniška datoteka OpenVPN ICS</string> - <string name="copied_entry">Vnos dnevnika kopiran na odložišče</string> - <string name="tap_mode">Način tapanja</string> - <string name="faq_tap_mode">Način tapanja ni mogoč z API-jem VPN brez skrbniškega dostopa. Zato ta program ne more omogočiti podpore za tapanje.</string> - <string name="tap_faq2">Spet? Ali se hecate? Ne, način tapanja resnično ni podprt in pošiljanje še več pošte z vprašanji, ali bo podprt, ne bo pomagalo.</string> - <string name="tap_faq3">Tretjič? V bistvu bi nekdo lahko napisal posnemovalnik tapanja temelječ na TUN-u, ki bi dodal podatke 2. plasti ob pošiljanju in odstranil podatke 2. plasti ob prejemanju. Vendar bi ta posnemovalnik moral imeti izveden ARP in morda odjemalca DHCP. Nisem še slišal, da bi kdo delal na tem. Navežite stik z mano, če bi radi začeli pisati program o tem.</string> - <string name="faq">Pogosta vprašanja</string> - <string name="copying_log_entries">Kopiranje dnevniških vnosov</string> - <string name="faq_copying">Za kopiranje posameznega dnevniškega vnosa pritisnite in pridržite dnevniški vnos. Za kopiranje/pošiljanje celega dnevnika uporabite možnost Pošlji dnevnik. Če v vmesniku gumb ni viden, uporabite menijski gumb naprave.</string> - <string name="faq_shortcut">Bližnjica za zagon</string> - <string name="faq_howto_shortcut">Za zagon OpenVPN-a lahko na namizje vstavite bližnjico. Odvisno od vašega programa za domači zaslon boste morali dodati ali bližnjico ali pripomoček.</string> - <string name="no_vpn_support_image">Vaš odtis žal ne podpira API-ja storitve VPN :(</string> - <string name="encryption">Šifriranje</string> - <string name="cipher_dialog_title">Vnesite način šifriranja</string> - <string name="chipher_dialog_message">Vnesite šifrirni algoritem, ki naj ga uporabi OpenVPN. Za uporabo privzete šifre pustite prazno.</string> - <string name="auth_dialog_message">Vnesite izvleček overitve, ki naj se uporabi za OpenVPN. Za privzetega pustite prazno.</string> - <string name="settings_auth">Overitev/Šifriranje</string> - <string name="file_explorer_tab">Raziskovalec datotek</string> - <string name="inline_file_tab">Datoteka v besedilu</string> - <string name="error_importing_file">Napaka pri uvažanju datoteke</string> - <string name="import_error_message">Datoteke iz datotečnega sistema ni bilo mogoče uvoziti</string> - <string name="inline_file_data">[[podatki datoteke v besedilu]]</string> - <string name="opentun_no_ipaddr">Zavračanje odpiranja naprave TUN brez podatkov IP</string> - <string name="menu_import">Uvozi profil iz datoteke ovpn</string> - <string name="menu_import_short">Uvozi</string> - <string name="import_content_resolve_error">Profila za uvoz ni bilo mogoče brati</string> - <string name="error_reading_config_file">Napaka pri branju nastavitvene datoteke</string> - <string name="add_profile">dodaj profil</string> - <string name="import_could_not_open">Datoteke %1$s, omenjene v uvoženi nastavitveni datoteki, ni bilo mogoče najti</string> - <string name="importing_config">Uvažanje nastavitvene datoteke iz vira %1$s</string> - <string name="import_warning_custom_options">Vaše nastavitve so imele nekaj možnosti, ki niso bile preslikane v nastavitve uporabniškega vmesnika. Te možnosti so bile dodane kot nastavitvene možnosti po meri. Nastavitve po meri so prikazane spodaj:</string> - <string name="import_done">Branje nastavitvene datoteke je končano.</string> - <string name="nobind_summary">Ne veži na krajevni naslov in vrata</string> - <string name="no_bind">Brez krajevne vezave</string> - <string name="import_configuration_file">Uvozi nastavitveno datoteko</string> - <string name="faq_security_title">Varnostne zahteve</string> - <string name="faq_security">"Ker je OpenVPN občutljiv na varnost, je smiselno povedati nekaj opomb o varnosti. Vsi podatki na kartici SD po svoji naravi niso varni. Vsak program jih lahko bere (npr. ta program ne zahteva posebnih dovoljenj za kartico SD). Podatke tega programa lahko bere samo program sam. Z uporabo možnosti uvoza za potrdila CA/potrdila/ključe v pogovornem oknu datoteke se podatki shranijo v profilu VPN. Do profilov VPN ima dostop samo ta program (ne pozabite potem izbrisati kopij na kartici SD). Čeprav ima do podatkov dostop samo ta program, so ti še vedno nešifrirani. Z omogočanjem skrbniškega dostopa do telefona ali izkoriščanjem drugih varnostnih ranljivosti je možno pridobiti te podatke. Poleg tega so gesla shranjena v golem besedilu. Za datoteke pkcs12 je zelo priporočljivo, da jih uvozite v Androidovo shrambo ključev."</string> - <string name="import_vpn">Uvozi</string> - <string name="broken_image_cert_title">Napaka pri prikazu izbire potrdila</string> - <string name="broken_image_cert">Pri poizkusu prikaza pogovornega okna izbire potrdila Android 4.0+ je prišlo do izjeme. To se ne bi smelo zgoditi, ker je to standardna značilnost Androida 4.0+. Morda je podpora Android ROM za shranjevanje potrdil pokvarjena.</string> - <string name="ipv4">IPv4</string> - <string name="ipv6">IPv6</string> - <string name="speed_waiting">Čakanje na sporočilo stanja …</string> - <string name="converted_profile">uvoženi profil</string> - <string name="converted_profile_i">uvoženi profil %d</string> - <string name="broken_images">Pokvarjeni odtisi</string> - <string name="broken_images_faq"><p>Uradni HTC-jevi odtisi imajo znano čudno težavo pri usmerjanju, ki povzroča, da promet ne teče skozi tunel (glejte <a href=\"http://code.google.com/p/ics-openvpn/issues/detail?id=18\">Težavo 18</a> v sledilniku hroščev.)</p><p>Za starejše uradne Sonyjeve odtise iz Xperie Arc S in Xperie Ray je bilo sporočeno, da jim v celoti manjka storitev VPN (glejte <a href=\"http://code.google.com/p/ics-openvpn/issues/detail?id=18\">Težavo 18</a> v sledilniku hroščev.)</p><p>V odtisih izgrajenih po meri lahko manjka modul TUN ali so dovoljenja za /dev/tun napačna. Nekateri odtisi CM9 potrebujejo omogočeno možnost \"Popravi lastništvo\" v \"Prilagoditvah za naprave\".</p><p>Najbolj pomembno: če ima vaša naprava pokvarjen odtis Android, ga prijavite svojemu proizvajalcu. Več ljudi kot prijavi težavo proizvajalcu, bolj verjetno je, da jo bodo popravili.</p></string> - <string name="pkcs12_file_encryption_key">Ključ za šifriranje datoteke PKCS12</string> - <string name="private_key_password">Geslo zasebnega ključa</string> - <string name="password">Geslo</string> - <string name="file_icon">ikona datoteke</string> - <string name="tls_authentication">Overitev/Šifriranje TLS</string> - <string name="generated_config">Ustvarjene nastavitve</string> - <string name="generalsettings">Nastavitve</string> - <string name="owner_fix_summary">Poizkusi nastaviti lastnika mape /dev/tun na sistem. Nekateri odtisi CM9 to potrebujejo za delovanje API-ja storitve VPN. Zahteva skrbniški dostop.</string> - <string name="owner_fix">Popravi lastništvo mape /dev/tun</string> - <string name="generated_config_summary">Prikaže ustvarjeno nastavitveno datoteko OpenVPN</string> - <string name="edit_profile_title">Urejanje \"%s\"</string> - <string name="building_configration">Izgrajevanje nastavitev …</string> - <string name="netchange_summary">Vklop te storitve bo vsilil ponovno povezavo, če se stanje omrežja spremeni (npr. Wi-Fi v/iz mobilnega omrežja)</string> - <string name="netchange">Pon. povez. ob spr. omr.</string> - <string name="netstatus">Stanje omrežja: %s</string> - <string name="extracahint">Potrdilo CA običajno vrne Androidova shramba ključev. Določite ločeno potrdilo, če dobite napake pri preverjanju potrdil.</string> - <string name="select_file">Izberi</string> - <string name="keychain_nocacert">Nobeno potrdilo ni bilo vrnjeno med branjem Androidove shrambe ključev. Overitev bo verjetno spodletela.</string> - <string name="show_log_summary">Prikaže okno dnevnika ob povezavi. Dostop do okna dnevnika je vedno možen iz stanja obvestila.</string> - <string name="show_log_window">Prikaži okno dnevnika</string> - <string name="mobile_info">%10$s %9$s se izvaja na %3$s %1$s (%2$s), Android %6$s (%7$s) API %4$d, ABI %5$s, (%8$s)</string> - <string name="error_rsa_sign">Napaka pri podpisu s ključem Androidove shrambe ključev %1$s: %2$s</string> - <string name="faq_system_dialogs">Opozorilo o povezavi VPN, ki vam sporoča, da lahko ta naprava prestreže ves promet, vsili sistem, da prepreči zlorabo API-ja storitve VPN.\nObvestilo o povezavi VPN (simbol ključa) tudi vsili sistem Android, da nakaže tekočo povezavo VPN. V nekaterih odtisih to obvestilo predvaja zvok.\nAndroid je vpeljal ta sistemska pogovorna okna zaradi vaše varnosti in je poskrbel, da se jih ne da zaobiti (v nekaterih odtisih to na žalost vključuje zvok obvestila).</string> - <string name="faq_system_dialogs_title">Opozorilo o povezavi in zvok obvestila</string> - <string name="translationby">Angleški prevod: Arne Schwabe<arne@rfc2549.org></string> - <string name="ipdns">IP in DNS</string> - <string name="basic">Osnovno</string> - <string name="routing">Usmerjanje</string> - <string name="obscure">Zamegli OpenVPN Settings. Običajno ni potrebno.</string> - <string name="advanced">Napredno</string> - <string name="export_config_title">Nastavitve OpenVPN ICS</string> - <string name="warn_no_dns">Noben strežnik DNS se ne uporablja. Razrešitev imen morda ne bo delovala. Razmislite o nastavitvi strežnikov DNS po meri. Upoštevajte tudi, da bo Android še naprej uporabljal vaše nastavitve posredniškega strežnika določene za vašo mobilno povezavo/Wi-Fi, ko ni nastavljen noben strežnik DNS.</string> - <string name="dns_add_error">Strežnika DNS \"%1$s\" ni bilo mogoče dodati, zavrnil ga je sistem: %2$s</string> - <string name="ip_add_error">Naslova IP \"%1$s\" ni bilo mogoče nastaviti, zavrnil ga je sistem: %2$s</string> - <string name="faq_howto"><p>Dobite delujoče nastavitve (preizkušene na vašem računalniku ali jih prejmite od vašega ponudnika/organizacije)</p><p>Če je to ena sama datoteka brez dodatnih datotek pem/pks12, jo lahko sami pošljete in odprete prilogo. Če imate več datotek, jih prestavite na svojo kartico SD.</p><p>Kliknite na e-poštno prilogo/uporabite ikono mape na seznamu VPN-ov, da uvozite nastavitveno datoteko.</p><p>Če se pojavijo napake o manjkajočih datotekah, jih vstavite na kartico SD.</p><p>Kliknite na simbol za shranjevanje, da dodate uvoženi VPN na svoj seznam VPN-ov.</p><p>Povežite VPN s klikom na ime VPN-a.</p><p>Če so v dnevniku napake ali opozorila, jih poizkusite razumeti in popraviti.</p> </string> - <string name="faq_howto_title">Hitri zagon</string> - <string name="setting_loadtun_summary">Poizkusite naložiti jedro tun.ko pred poizkusom povezave. Zahteva skrbniški dostop.</string> - <string name="setting_loadtun">Naloži modul TUN</string> - <string name="importpkcs12fromconfig">Uvozi PKCS12 iz nastavitev v Androidovo shrambo ključev</string> - <string name="getproxy_error">Napaka pri dobivanju nastavitev posredniškega strežnika: %s</string> - <string name="use_system_proxy">Uporabi sis. pos. str.</string> - <string name="use_system_proxy_summary">Za povezavo uporabi nastavitve celega sistema za posredniške strežnike HTTP/HTTPS.</string> - <string name="onbootrestartsummary">OpenVPN bo povezal navedeni VPN, če je bil dejaven ob zagonu sistema. Preberite pogosta vprašanja o opozorilih glede povezav pred uporabo te možnosti na Androidu < 5.0.</string> - <string name="onbootrestart">Poveži ob zagonu</string> - <string name="ignore">Prezri</string> - <string name="restart">Ponovno zaženi</string> - <string name="restart_vpn_after_change">Spremembe nastavitev se bodo uporabile po ponovnem zagonu VPN-a. (Ponovno) zaženi VPN zdaj?</string> - <string name="configuration_changed">Nastavitve so bile spremenjene</string> - <string name="log_no_last_vpn">Nazadnje povezanega profila ni bilo mogoče določiti za urejanje</string> - <string name="faq_duplicate_notification_title">Podvojena obvestila</string> - <string name="faq_duplicate_notification">Če Androidu primanjkuje sistemskega pomnilnika (RAM-a), se programi in storitve, ki trenutno niso potrebne, odstranijo iz dejavnega pomnilnika. To uniči delujočo povezavo VPN. Zaradi zagotovitve, da povezava/OpenVPN preživi, se storitev izvaja z višjo prednostjo. Za izvajanje z višjo prednostjo mora program prikazati obvestilo. Ikono obvestila ključa vsili sistem, kot je to opisano v prejšnjem vnosu pogostih vprašanj. Ne šteje kot obvestilo programa za namen izvajanja z višjo prednostjo.</string> - <string name="no_vpn_profiles_defined">Noben profil VPN ni določen.</string> - <string name="add_new_vpn_hint">Uporabite ikono <img src=\"ic_menu_add\"/>, da dodate nov VPN.</string> - <string name="vpn_import_hint">Uporabite ikono <img src=\"ic_menu_archive\"/>, da uvozite obstoječi profil (.ovpn ali .conf) iz svoje kartice SD.</string> - <string name="faq_hint">Prepričajte se, da preverite pogosta vprašanja. Tam je vodnik za hitri začetek.</string> - <string name="faq_routing_title">Nastavitve usmerjanja/vmesnika</string> - <string name="faq_routing">Nastavitve usmerjanja in vmesnika se ne opravijo preko tradicionalnih ukazov ifconfig/route, toda z uporabo API-ja storitve VPN. To se pokaže v drugačnih nastavitvah usmerjanja, kot v drugih OS-ih.\nNastavitve tunela IP so sestavljene iz naslova IP in omrežij, ki jih je treba usmeriti preko tega vmesnika. Pri tem ni potreben ali zahtevan noben družabniški naslov soležnika ali naslov vrat. Posebne poti za doseganje strežnika VPN (npr. dodane med uporabo ukaza redirect-gateway) tudi niso potrebne. Program po zaradi tega ob uvozu nastavitev prezrl te nastavitve. Program z API-jem storitve VPN zagotovi, da povezava s strežnikom ni usmerjena preko tunela VPN.\nAPI storitve VPN ne dovoli določanje omrežij, ki se ne smejo usmeriti preko tunela (npr. pot x.x.x.x y.y.y.y net_gateway) in izračuna nabor poti, ki izključijo te poti, da posnema vedenje drugih okolij. Okno dnevnika prikazuje nastavitve API-ja storitve VPN, ko se povezava vzpostavi.\nNeuradno: Android 4.4+ uporablja pravilnik usmerjanja. Uporaba ukazov route/ifconfig ne bo prikazala nameščene poti. Namesto tega uporabite pravilo IP iptables -t mangle -L.</string> - <string name="persisttun_summary">Ne preidi v stanje brez povezave VPN, ko se OpenVPN povezuje.</string> - <string name="persistent_tun_title">Vztrajni TUN</string> - <string name="openvpn_log">Dnevnik OpenVPN</string> - <string name="import_config">Uvozi nastavitve OpenVPN</string> - <string name="battery_consumption_title">Poraba baterije</string> - <string name="baterry_consumption">V mojih osebnih preizkusih so bili glaven vzrok za visoko porabo baterije OpenVPN-a dejavni paketi. Večina strežnikov OpenVPN ima smernico nastavitev, kot je \'ohrani dejavnost 10 60\', ki povzroči, da si odjemalec in strežnik izmenjata dejavne pakete vsakih 10 sekund. <p>Medtem, ko so ti paketi majhni in ne uporabijo veliko prometa, ohranijo mobilno radijsko omrežje dejavno in povečajo porabo energije (glejte tudi <a href=\"http://developer.android.com/training/efficient-downloads/efficient-network-access.html#RadioStateMachine\">The Radio State Machine | Razvijalci Androida</a>).<p> Te nastavitve ohranjanja dejavnosti odjemalec ne more spremeniti. Spremeni jo lahko samo sistemski skrbnik OpenVPN-a.<p> Na žalost uporaba ohranjanja dejavnosti večje od 60-ih sekund z UDP-jem lahko povzroči, da nekatera vrata NAT prekinejo povezavo zaradi časovne omejitve nedejavnosti. Uporaba TCP-ja z dolgo časovno omejitvijo ohranjanja dejavnosti deluje, vendar se tuneliranje TCP-ja preko TCP-ja izkaže za zelo neučinkovito ob povezavah z visoko izgubo paketov (glejte <a href=\"http://sites.inka.de/bigred/devel/tcp-tcp.html\">Why TCP Over TCP Is A Bad Idea</a>).</string> - <string name="faq_tethering">Androidova značilnost deljenja mobilnega interneta (preko omrežja Wi-Fi, USB-ja ali Bluetootha) in API storitve VPN (ki ga uporablja ta program) skupaj ne delujeta. Za več podrobnosti glejte <a href=\"http://code.google.com/p/ics-openvpn/issues/detail?id=34\">Težavo 34</a>.</string> - <string name="vpn_tethering_title">VPN in deljenje mobilnega interneta</string> - <string name="connection_retries">Ponovni poizkusi povezave</string> - <string name="reconnection_settings">Nastavitve ponovne povezave</string> - <string name="connectretrymessage">Št. sekund čakanja med poizkusi povezave.</string> - <string name="connectretrywait">Sekunde med povezavami</string> - <string name="minidump_generated">OpenVPN se je nepričakovano sesul. Razmislite o uporabi možnosti pošiljanja mini izpisa v glavnem meniju.</string> - <string name="send_minidump">Pošlji mini izpis razvijalcu</string> - <string name="send_minidump_summary">Pošlje podatke razhroščevanja o zadnjem sesutju razvijalcu</string> - <string name="notifcation_title">OpenVPN - %s</string> - <string name="session_ipv4string">%1$s - %2$s</string> - <string name="session_ipv6string">%1$s - %3$s, %2$s</string> - <string name="state_connecting">Povezovanje</string> - <string name="state_wait">Čakanje na odgovor strežnika</string> - <string name="state_auth">Overjanje</string> - <string name="state_get_config">Dobivanje nastavitev odjemalca</string> - <string name="state_assign_ip">Dodeljevanje naslovov IP</string> - <string name="state_add_routes">Dodajanje poti</string> - <string name="state_connected">Povezan</string> - <string name="state_disconnected">Prekini</string> - <string name="state_reconnecting">Ponovno povezovanje</string> - <string name="state_exiting">Izhod</string> - <string name="state_noprocess">Se ne izvaja</string> - <string name="state_resolve">Razreševanje imen gostiteljev</string> - <string name="state_tcp_connect">Povezovanje (TCP)</string> - <string name="state_auth_failed">Overitev je spodletela</string> - <string name="state_nonetwork">Čakanje na uporabno omrežje</string> - <string name="notifcation_title_notconnect">Ni povezan</string> - <string name="start_vpn_title">Povezovanje v VPN %s</string> - <string name="start_vpn_ticker">Povezovanje v VPN %s</string> - <string name="jelly_keystore_alphanumeric_bug">Nekatere različice Androida 4.1 imajo težave, če ime potrdila shrambe ključev vsebuje posebne znake (presledke, podčrtaje ali pomišljaje). Poizkusite ponovno uvoziti potrdilo brez posebnih znakov.</string> - <string name="encryption_cipher">Šifra</string> - <string name="packet_auth">Overitev paketov</string> - <string name="auth_dialog_title">Vnesite način overitve paketov</string> - <string name="built_by">izgradil %s</string> - <string name="debug_build">razhroščevalna izgradnja</string> - <string name="official_build">uradna izgradnja</string> - <string name="make_selection_inline">Kopiraj v profil</string> - <string name="crashdump">Izpis sesutja</string> - <string name="add">Dodaj</string> - <string name="send_config">Pošlji nastavitveno datoteko</string> - <string name="complete_dn">Celoten DN</string> - <string name="remotetlsnote">Vaše uvožene nastavitve uporabljajo staro OPUŠČENO možnost tls-remote, ki uporablja drugo obliko DN.</string> - <string name="rdn">RDN (splošno ime)</string> - <string name="rdn_prefix">Predpona RDN</string> - <string name="tls_remote_deprecated">tls-remote (OPUŠČENO)</string> - <string name="help_translate">Prevajati lahko pomagate z obiskom http://crowdin.net/project/ics-openvpn/invite</string> - <string name="prompt">%1$s poizkuša nadzirati %2$s</string> - <string name="remote_warning">Z nadaljevanjem dajete programu dovoljenje za popoln nadzor OpenVPN-a za Android in prestrezanje vsega omrežnega prometa. <b>NE sprejmite, razen če zaupate programu.</b> V nasprotnem primeru lahko vaši podatki postanejo tarča zlonamerne programske opreme.</string> - <string name="remote_trust">Zaupam temu programu.</string> - <string name="no_external_app_allowed">Noben program ne sme uporabiti zunanjega API-ja</string> - <string name="allowed_apps">Programi z dovoljenjem: %s</string> - <string name="clearappsdialog">Počisti seznam zunanjih programov z dovoljenjem?\nTrenutni seznam:\n\n%s</string> - <string name="screenoff_summary">\"Premor VPN-a, ko je zaslon izklopljen in je v 60 s preneseno manj kot 64 kB. Ko je omogočena možnost \"Vztrajni TUN\", bo premor VPN-a odstranil VSO povezljivost naprave. Brez te možnosti naprava ne bo imela povezave VPN/zaščite.</string> - <string name="screenoff_title">Premor VPN-a po izk. zas.</string> - <string name="screenoff_pause">Premor povezave v stanju izklopljenega zaslona: manj kot %1$s v %2$s s</string> - <string name="screen_nopersistenttun">Opozorilo: Vztrajni TUN za ta VPN ni mogočen. Promet bo uporabil običajno internetno povezavo, ko je zaslon izklopljen.</string> - <string name="save_password">Shrani geslo</string> - <string name="pauseVPN">Premor VPN-a</string> - <string name="resumevpn">Obnovi VPN</string> - <string name="state_userpause">Premor VPN-a je zahteval uporabnik</string> - <string name="state_screenoff">Premor VPN-a - zaslon izklopljen</string> - <string name="device_specific">Prilagoditve za naprave</string> - <string name="cannotparsecert">Podatkov potrdila ni mogoče prikazati</string> - <string name="appbehaviour">Vedenje programa</string> - <string name="vpnbehaviour">Vedenje VPN-a</string> - <string name="allow_vpn_changes">Dovoli spremembe profilov VPN</string> - <string name="hwkeychain">Strojna shramba ključev:</string> - <string name="permission_icon_app">Ikona programa poizkuša uporabiti OpenVPN za Android</string> - <string name="faq_vpndialog43">\"Z začetkom v Androidu 4.3 je potrditev VPN zaščitena proti \"prekrivajočimi programi\". To povzroči, da se pogovorna okna ne odzovejo na vnos z dotikom. Če imate program, ki uporablja prekrivanja, lahko povzroči to vedenje. Če najdete tak program, navežite stik z avtorjem programa. Ta težava vpliva na vse programe VPN na Androidu 4.3 ali kasnejših. Za dodatne podrobnosti glejte tudi <a href=\"http://code.google.com/p/ics-openvpn/issues/detail?id=185\">Težavo 185<a>\".</string> - <string name="faq_vpndialog43_title">Potrditev pogovornega okna VPN</string> - <string name="donatePlayStore">Lahko pa mi darujete s trgovino Play:</string> - <string name="thanks_for_donation">Hvala, da ste darovali %s!</string> - <string name="logCleared">Dnevnik počiščen.</string> - <string name="show_password">Prikaži geslo</string> - <string name="keyChainAccessError">Napaka dostopa do verige ključev: %s</string> - <string name="timestamp_short">Kratko</string> - <string name="timestamp_iso">ISO</string> - <string name="timestamps">Časovni žigi</string> - <string name="timestamps_none">Brez</string> - <string name="uploaded_data">Pošlji</string> - <string name="downloaded_data">Prejmi</string> - <string name="vpn_status">Stanje VPN-a</string> - <string name="logview_options">Možnosti pogleda</string> - <string name="unhandled_exception">Neobravnavana izjema: %1$s\n\n%2$s</string> - <string name="unhandled_exception_context">%3$s: %1$s\n\n%2$s</string> - <string name="faq_system_dialog_xposed">Če imate na svoji napravi skrbniški dostop, lahko na svojo odgovornost namestite <a href=\"http://xposed.info/\">ogrodje Xposed</a> in <a href=\"http://repo.xposed.info/module/de.blinkt.vpndialogxposed\">Modul za potrditev pog. okna VPN</a>.</string> - <string name="full_licenses">Polna dovoljenja</string> - <string name="blocklocal_summary">Omrežja, ki so neposredno povezana s krajevnimi vmesniki, ne bodo usmerjena preko VPN-a. Odstranitev izbire te možnosti bo preusmerila ves promet namenjen krajevnim omrežjem v VPN.</string> - <string name="blocklocal_title">Zaobidi VPN za kraj. omr.</string> - <string name="userpw_file">Datoteka uporabniškega imena/gesla</string> - <string name="imported_from_file">[Uvoženo iz: %s]</string> - <string name="files_missing_hint">Nekaterih datotek ni bilo mogoče najti. Izberite datoteke za uvoz profila:</string> - <string name="openvpn_is_no_free_vpn">Za uporabo tega programa potrebujete ponudnika VPN/vrata VPN, ki podpira OpenVPN (pogosto jih dobavi vaš delodajalec). Za več podatkov o OpenVPN-u in kako nastaviti svoj lasten strežnik OpenVPN preverite http://community.openvpn.net/.</string> - <string name="import_log">Dnevnik uvoza:</string> - <string name="ip_looks_like_subnet">Topologija VPN-a \"%3$s\" je določena, vendar je ifconfig %1$s %2$s videti bolj kot naslov IP z masko omrežja. Uporaba topologije \"podomrežja\".</string> - <string name="mssfix_invalid_value">Vrednost preglasitve MSS mora biti celo število med 0 in 9000.</string> - <string name="mssfix_value_dialog">Najavi sejam TCP, ki se izvajajo preko tunela, da morajo omejiti velikosti svojih paketov, tako da ko jih je OpenVPN zaobjel, nastala velikost paketov UDP, ki jo OpenVPN pošlje svojemu soležniku, ne bo presegla tega števila bajtov (privzeto je 1450).</string> - <string name="mssfix_checkbox">Preglasi vrednost MSS vsebine TCP</string> - <string name="mssfix_dialogtitle">Nastavi MSS vsebine TCP</string> - <string name="client_behaviour">Vedenje odjemalca</string> - <string name="clear_external_apps">Počisti zun. prog. z dov.</string> - <string name="loading">Nalaganje …</string> - <string name="allowed_vpn_apps_info">Programi VPN z dovoljenjem: %1$s</string> - <string name="disallowed_vpn_apps_info">Programi VPN brez dovoljenja: %1$s</string> - <string name="app_no_longer_exists">Paket %s ni več nameščen, odstranjevanje paketa s seznama programov z/brez dovoljenja.</string> - <string name="vpn_disallow_radio">VPN se uporablja za vse programe, vendar izključi izbrane</string> - <string name="vpn_allow_radio">VPN se uporablja samo za izbrane programe</string> - <string name="query_delete_remote">Odstrani vnos oddaljenega strežnika?</string> - <string name="keep">Ohrani</string> - <string name="delete">Izbriši</string> - <string name="add_remote">Dodaj nov oddaljeni strežnik</string> - <string name="remote_random">Uporabi vnose povezave v naključnem vrstnem redu ob povezavi</string> - <string name="remote_no_server_selected">Določiti in omogočiti morate vsaj en oddaljeni strežnik.</string> - <string name="server_list">Seznam strežnikov</string> - <string name="vpn_allowed_apps">Programi z dovoljenjem</string> - <string name="payload_options">Možnosti vsebine</string> - <string name="tls_settings">Nastavitve TLS</string> - <string name="no_remote_defined">Noben oddaljeni strežnik ni določen</string> - <string name="duplicate_vpn">Podvojeni profil VPN</string> - <string name="duplicate_profile_title">Podvajanje profila: %s</string> - <string name="show_log">Prikaži dnevnik</string> - <string name="faq_android_clients">Obstaja več odjemalcev OpenVPN za Android. Najbolj pogosti so OpenVPN za Andorid (ta odjemalec), OpenVPN Connect in OpenVPN Settings.<p>Odjemalce lahko združite v dve skupini: OpenVPN za Android in OpenVPN Connect uporabljata uraden API storitve VPN (Android 4.0+) in ne zahtevata skrbniškega dostopa, in OpenVPN Settings, ki ga zahteva.<p> OpenVPN za Android je odprtokodni odjemalec, ki ga razvija Arne Schwabe. Cilja na bolj napredene uporabnike, in ponuja veliko nastavitev, zmožnost uvoza profilov iz datotek in nastavitev/spreminjanje profilov v programu. Odjemalec temelji na skupnostni različici OpenVPN-a in na izvorni kodi OpenVPN 2.x. Tega odjemalca je mogoče razumeti kot poluradnega odjemalca skupnosti. <p>OpenVPN Connect ni odprtokodni odjemalec in ga razvija OpenVPN Technologies, Inc. Namenjen je za splošno uporabo, cilja na povprečnega uporabnika in omogoča uvoz profilov OpenVPN. Temelji na ponovni izvedbi C++ OpenVPN protokola OpenVPN (to je bilo zahtevano, da je OpenVPN Technologies, Inc lahko izdal program OpenVPN za iOS). Je uradni odjemalec podjetja OpenVPN Technologies. <p> OpenVPN Settings je najstarejši od teh in tudi uporabniški vmesnik za odprtokodni OpenVPN. V nasprotju z OpenVPN-om za Android zahteva skrbniški dostop in ne uporablja API-ja storitve VPN. Ni odvisen od Androida 4.0+.</string> - <string name="faq_androids_clients_title">Razlike med Androidovimi odjemalci OpenVPN</string> - <string name="ignore_multicast_route">Preziranje poti večsmernega oddajanja: %s</string> - <string name="ab_only_cidr">Android podpira samo poti CIDR v VPN. Ker se druge poti skoraj nikoli ne uporabljajo, bo OpenVPN za Android za te poti uporabil /32 in izdal opozorilo.</string> - <string name="ab_tethering_44">Deljenje mobilnega interneta deluje, ko je VPN dejaven. Deljena povezava NE bo uporabila VPN-a.</string> - <string name="ab_kitkat_mss">Zgodnja različica KitKata je nastavila napačno vrednost MSS ob povezavah TCP (#61948). OpenVPN bo samodejno omogočil možnost mssfix, da zaobide ta hrošč.</string> - <string name="ab_proxy">Android bo še naprej uporabljal nastavitve posredniškega strežnika, ki so določene za mobilno povezavo/Wi-Fi, ko ni nastavljenih strežnikov DNS. OpenVPN za Android vas bo o tem opozoril v dnevniku.<p>Ko VPN nastavi strežnik DNS, Android ne bo uporabil posredniškega strežnika. API, ki nastavi posredniški strežnik za povezavo VPN, ne obstaja.</p></string> - <string name="ab_lollipop_reinstall">Programi VPN lahko prenehajo delovati, ko se jih odstrani in ponovno namesti. Za podrobnosti glejte #80074.</string> - <string name="ab_not_route_to_vpn">IP nastavljenega odjemalca in IP-ji v njegovi maski omrežja se ne usmerijo v VPN. OpenVPN zaobide tega hrošča z izrecnim dodajanjem poti, ki ustreza IP-ju odjemalca in njegovi maski omrežja.</string> - <string name="ab_persist_tun">Odpiranje naprave TUN, ko je dejavna druga naprava, kar se uporablja za podporo vztrajnega TUN-a, sesuje storitve VPN na napravi. Za ponovno delovanje VPN-a je zahtevan ponovni zagon. OpenVPN za Android bo poizkusil ponovno odpreti napravo TUN in če je zelo potrebno, pred tem zaprl trenutni TUN, da se izogne sesutju. To lahko privede do kratkega postanka, kjer se paketi pošljejo preko običajne povezave. Tudi pri tem zaobidenju se storitve VPN včasih sesujejo in je zahtevan ponovni zagon naprave.</string> - <string name="ab_secondary_users">VPN sploh ne deluje za sekundarne uporabnike.</string> - <string name="ab_kitkat_reconnect">"Več uporabnikov poroča, da se ob uporabi programa VPN mobilna povezava/podatki pogosto prekinejo. Videti je, da se to nanaša samo na nekatere kombinacije mobilnih ponudnikov/naprav in do sedaj za ta hrošč še ni bilo odkritega vzroka/zaobidenja."</string> - <string name="ab_vpn_reachability_44">Preko VPN-a so dosegljivi samo cilji, ki so dosegljivi tudi brez njega. VPN-i IPv6 sploh ne delujejo.</string> - <string name="ab_only_cidr_title">Poti brez načina CIDR</string> - <string name="ab_proxy_title">Vedenje posredniškega strežnika za VPN-e</string> - <string name="ab_lollipop_reinstall_title">Ponovno nameščenje programov VPN</string> - <string name="version_upto">%s in prejšnji</string> - <string name="copy_of_profile">Kopija %s</string> - <string name="ab_not_route_to_vpn_title">Pot do nastavljenega naslova IP</string> - <string name="ab_kitkat_mss_title">Napačna vrednost MSS za povezavo VPN</string> - <string name="ab_secondary_users_title">Sekundarni uporabniki tabilc</string> - <string name="custom_connection_options_warng">Določite možnosti za povezave po meri. Uporabljajte previdno.</string> - <string name="custom_connection_options">Možnosti po meri</string> - <string name="remove_connection_entry">Odstrani vnos povezave</string> - <string name="ab_kitkat_reconnect_title">Naključne prekinitve mobilnega omrežja</string> - <string name="ab_vpn_reachability_44_title">Oddaljena omrežja niso dosegljiva</string> - <string name="ab_persist_tun_title">Vztrajaj v načinu TUN</string> - <string name="version_and_later">%s in kasnejši</string> - <string name="tls_cipher_alert_title">Povezava je spodletela z opozorilom izmenjave signalov SSL23_GET_SERVER_HELLO:sslv3</string> - <string name="tls_cipher_alert">Novejše različice OpenVPN-a za Android (0.6.29/marec 2015) uporabljajo bolj varne privzete vrednosti za dovoljene šifrirne pakete (tls-cipher \"DEFAULT:!EXP:!PSK:!SRP:!kRSA\"). Na žalost izpuščanje manj varnih šifrirnih paketov in šifrirnih paketov za izvoz, posebno izpuščanje šifrirnih paketov, ki ne podpirajo vnaprejšnje varnosti (Diffie-Hellman), povzroča težave. To običajno povzroči dobronamerni vendar slabo izvedeni poizkus ojačanja varnosti TLS-a z nastavljanjem možnosti tls-cipher na strežniku ali vstavljenih OS-ih z okrnjenim SSL-om (npr. MikroTik).\nZa razrešitev te težave na strežniku nastavite možnosti tls-cipher na razumljive privzete vrednosti, kot je tls-cipher \"DEFAULT:!EXP:!PSK:!SRP:!kRSA\". Za zaobidenje te težave na odjemalcu dodajte možnost po meri tls-cipher DEFAULT na odjemalcu Android.</string> - <string name="message_no_user_edit">Ta profil je bil dodan iz zunanjega programa (%s) in je bil označen kot uporabniško neuredljiv.</string> - <string name="crl_file">Seznam preklicanih potrdil</string> - <string name="service_restarted">Ponovno zaganjanje storitve OpenVPN (program se je verjetno sesul ali je bil uničen zaradi pomanjkanja pomnilnika)</string> - <string name="import_config_error">Pri uvozu nastavitev je prišlo do napake, nastavitev ni mogoče shraniti</string> - <string name="Search">Išči</string> - <string name="lastdumpdate">(zadnji izpis je star %1$d:%2$d ur (%3$s))</string> - <string name="clear_log_on_connect">Počisti dnevnik ob novi povezavi</string> - <string name="connect_timeout">Časovna omejitev povezave</string> - <string name="no_allowed_app">Noben program z dovoljenjem ni bil dodan. Samodejno dodajanje (%s), da se na seznamu programov z dovoljenjem nahaja vsaj en program, da ostali ne dobijo dovoljenja.</string> - <string name="query_permissions_sdcard">OpenVPN za Android lahko samodejno poizkusi odkriti manjkajoče datoteke na kartici SD. Tapnite na to sporočilo, da zahtevate dovoljenje.</string> - <string name="protocol">Protokol</string> - <string name="enabled_connection_entry">Omogočeno</string> - <string name="abi_mismatch">Prednostna izvirna predhodnost ABI (%1$s) in ABI, ki ga sporočajo izvirne knjižnice (%2$s), se ne ujemata.</string> - <string name="permission_revoked">OS je preklical dovoljenje VPN (npr. zagnan je bil drug program VPN), ustavljanje VPN-a</string> - <string name="pushpeerinfo">Potisni podatke o soležniku</string> - <string name="pushpeerinfosummary">Pošlji dodatne podatke na strežnik, npr. različico SSL in Android</string> - <string name="pw_request_dialog_title">Zahtevano %1$s</string> - <string name="pw_request_dialog_prompt">Vnesite geslo za profil %1$s</string> - <string name="menu_use_inline_data">Uporabi podatke v besedilu</string> - <string name="export_config_chooser_title">Izvozi nastavitveno datoteko</string> - <string name="missing_tlsauth">Datoteka tls-auth manjka</string> - <string name="missing_certificates">Manjka uporabniško potrdilo ali datoteka ključa uporabniškega potrdila</string> - <string name="missing_ca_certificate">Manjka potrdilo CA</string> - <string name="crl_title">Seznam preklicanih potrdil (izbirno)</string> - <string name="reread_log">Ponovno preberite predmete dnevnika (%d) iz njegove predpomnjene datoteke</string> - <string name="samsung_broken">Čeprav so Samsungovi telefoni eni najbolj prodajanih telefonov z Androidom, je strojna programska oprema njihovih telefonov ena najbolj hroščastih. Hrošči niso omejeni na delovanje VPN-a in se veliko od njih da zaobiti. Tukaj je opisanih nekaj hroščev.\n\nDNS ne deluje, če strežnik DNS ni v dosegu VPN-a.\n\nNa veliko napravah Samsung 5.x značilnost dovoljeni/nedovoljeni programi ne deluje.\nZa Samsungu 6.x je bilo sporočeno, da VPN ne deluje razen če je program za VPN dodan na seznam izjem značilnosti varčevanja z energijo.</string> - <string name="samsung_broken_title">Telefoni Samsung</string> - <string name="novpn_selected">VPN ni izbran.</string> - <string name="vpnselected">Trenutno izbrani VPN: \'%s\'</string> - <string name="reconnect">Ponovno poveži</string> - <string name="qs_title">Preklopi VPN</string> - <string name="qs_connect">Poveži se v %s</string> - <string name="qs_disconnect">Prekini povezavo s/z %s</string> - <string name="connectretrymaxmessage">Vnesite najdaljši čas med poizkusi povezave. OpenVPN bo po neuspešnem poizkusu povezave počasi povečeval čakalni čas do te vrednosti. Privzeto je 300 s.</string> - <string name="connectretrymaxtitle">Najdaljši čas med poizkusi povezave</string> - <string name="state_waitconnectretry">Čakanje %s s med poizkusi povezave</string> - <string name="nought_alwayson_warning"><![CDATA[Če niste dobili potrditvenega pogovornega okna VPN, imate v drugem programu omogočeno \"Vedno z VPN-om\". V tem primeru se lahko v VPN poveže samo ta program. Preverite v Nastavitve -> Omrežje (več) ... -> VPN-i]]></string> - <string name="management_socket_closed">Povezava v OmenVPN zaprta (%s)</string> - <string name="change_sorting">Spremeni razvrščanje</string> - <string name="sort">Razvrsti</string> - <string name="sorted_lru">Profili, razvrščeni po nazadnje uporabljenem</string> - <string name="sorted_az">Profili, razvrščeni po imenu</string> - <string name="deprecated_tls_remote">Nastavitve uporabljajo možnost tls-remote, ki je bila opuščena v raz. 2.3 in končno odstranjena v raz. 2.4</string> - <string name="graph">Graf</string> - <string name="notenoughdata">Ni dovolj podatkov</string> - <string name="last5minutes">Zadnjih 5 minut</string> - <string name="bits_per_second">%.0f bit/s</string> - <string name="kbits_per_second">%.1f kbit/s</string> - <string name="mbits_per_second">%.1f Mbit/s</string> - <string name="gbits_per_second">%.1f Gbit/s</string> - <string name="volume_byte">%.0f B</string> - <string name="volume_kbyte">%.1f kB</string> - <string name="volume_mbyte">%.1f MB</string> - <string name="volume_gbyte">%.1f GB</string> -</resources> diff --git a/app/src/main/res/values-sr/strings.xml b/app/src/main/res/values-sr/strings.xml deleted file mode 100644 index 9233bd75ba34591bbd3e5898f420d69ae4c6e7e9..0000000000000000000000000000000000000000 --- a/app/src/main/res/values-sr/strings.xml +++ /dev/null @@ -1,12 +0,0 @@ -<?xml version='1.0' encoding='UTF-8'?> -<resources> - <string name="retry">Покушај поново</string> - <string name="save">Сачувај</string> - <string name="about_fragment_title">О нама</string> - <string name="error_bad_user_password_user_message">Неправилно корисничко име или лозинка</string> - <string name="setup_error_configure_button">Конфигуриши</string> - <string name="setup_error_close_button">Излаз</string> - <string name="action_settings">Podešavanja</string> - <string name="donate_title">Донирај</string> - <string name="donate_button_donate">Донирај</string> -</resources> diff --git a/app/src/main/res/values-sv/plurals-icsopenvpn.xml b/app/src/main/res/values-sv/plurals-icsopenvpn.xml deleted file mode 100755 index 9bab8338433af4cfbd31e1cff5e5e935d5d58666..0000000000000000000000000000000000000000 --- a/app/src/main/res/values-sv/plurals-icsopenvpn.xml +++ /dev/null @@ -1,20 +0,0 @@ -<?xml version="1.0" encoding="utf-8"?> -<!--Generated by crowdin.com--> -<resources> - <plurals name="months_left"> - <item quantity="one">En månad kvar</item> - <item quantity="other">%d månader kvar</item> - </plurals> - <plurals name="days_left"> - <item quantity="one">En dag kvar</item> - <item quantity="other">%d dagar kvar</item> - </plurals> - <plurals name="hours_left"> - <item quantity="one">En timme kvar</item> - <item quantity="other">%d timmar kvar</item> - </plurals> - <plurals name="minutes_left"> - <item quantity="one">En minut kvar</item> - <item quantity="other">%d minuter kvar</item> - </plurals> -</resources> diff --git a/app/src/main/res/values-sv/strings-icsopenvpn.xml b/app/src/main/res/values-sv/strings-icsopenvpn.xml deleted file mode 100755 index 7af04354d6940d9ed64ac643bb7fef3890b89140..0000000000000000000000000000000000000000 --- a/app/src/main/res/values-sv/strings-icsopenvpn.xml +++ /dev/null @@ -1,459 +0,0 @@ -<?xml version="1.0" encoding="utf-8"?> -<!--Generated by crowdin.com--> -<!-- - ~ 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> - - <string name="address">Serveradress:</string> - <string name="port">Serverport:</string> - <string name="location">Plats</string> - <string name="cant_read_folder">Katalogen kan inte läsas</string> - <string name="select">Välj</string> - <string name="cancel">Avbryt</string> - <string name="no_data">Inga Data</string> - <string name="useLZO">LZO komprimering</string> - <string name="client_no_certificate">Inget certifikat</string> - <string name="client_certificate_title">Klientcertifikat</string> - <string name="client_key_title">Klientcertifikatsnyckel</string> - <string name="client_pkcs12_title">PKCS12 fil</string> - <string name="ca_title">CA-certifikat</string> - <string name="no_certificate">Du måste välja ett certifikat</string> - <string name="copyright_guicode">Källkod och incidenthantering finns på http://code.google.com/p/ics-openvpn/</string> - <string name="copyright_others">Programmet använder följande komponenter, se källkoden för fullständig information om licenser</string> - <string name="about">Om</string> - <string name="vpn_list_title">Profiler</string> - <string name="vpn_type">Typ</string> - <string name="pkcs12pwquery">PKCS12 lösenord</string> - <string name="file_select">Välj…</string> - <string name="file_nothing_selected">Du måste välja en fil</string> - <string name="useTLSAuth">Använd TLS-autentisering</string> - <string name="tls_direction">TLS riktning</string> - <string name="ipv6_dialog_tile">Ange IPv6-adress/Netmask i CIDR Format (t.ex. 2000:dd::23 / 64)</string> - <string name="ipv4_dialog_title">Ange IPv4-adressen/Netmask i CIDR Format (t.ex. 1.2.3.4/24)</string> - <string name="ipv4_address">IPv4-adress</string> - <string name="ipv6_address">IPv6-adress</string> - <string name="custom_option_warning">Ange anpassade OpenVPN alternativ. Använd med försiktighet! Tänk också på att många av de tun relaterade OpenVPN inställningarna inte kan stödjas genom utformningen av VPNSettings. Om du anser att ett viktigt alternativ saknas kontakta författaren</string> - <string name="auth_username">Användarnamn</string> - <string name="auth_pwquery">Lösenord</string> - <string name="static_keys_info">Vid statisk konfiguration används TLS Auth nycklarna som statiska nycklar</string> - <string name="configure_the_vpn">Konfigurera VPN-anslutningen</string> - <string name="menu_add_profile">Lägga till en profil</string> - <string name="add_profile_name_prompt">Ange ett namn som identifierar den nya profilen</string> - <string name="duplicate_profile_name">Vänligen ange ett unikt Profilnamn</string> - <string name="profilename">Profilnamn</string> - <string name="no_keystore_cert_selected">Du måste välja ett användarcertifikat</string> - <string name="no_ca_cert_selected">Du måste välja ett CA-certifikat</string> - <string name="no_error_found">Inga fel hittades</string> - <string name="config_error_found">Fel i konfigurationen</string> - <string name="ipv4_format_error">Det går inte att tolka IPv4-adressen</string> - <string name="custom_route_format_error">Det går inte att tolka de anpassade rutterna</string> - <string name="pw_query_hint">(lämna tom för förfrågan vid behov)</string> - <string name="vpn_shortcut">OpenVPN genväg</string> - <string name="vpn_launch_title">Ansluter till VPN…</string> - <string name="shortcut_profile_notfound">Profilen som anges i genvägen hittades inte</string> - <string name="random_host_prefix">Slumpmässigt värd-prefix</string> - <string name="random_host_summary">Lägger till 6 slumpmässiga tecken framför hostname</string> - <string name="custom_config_title">Aktivera anpassade alternativ</string> - <string name="custom_config_summary">Ange anpassade inställningar. Använd med försiktighet!</string> - <string name="route_rejected">Rutten avvisades av Android</string> - <string name="cancel_connection_long">Koppla från VPN</string> - <string name="clear_log">rensa loggen</string> - <string name="title_cancel">Avbryt bekräftelse</string> - <string name="cancel_connection_query">Koppla från det anslutna VPN/Avbryt anslutningen?</string> - <string name="remove_vpn">Ta bort VPN</string> - <string name="check_remote_tlscert">Kontrollerar om servern använder ett certifikat med TLS server tillägg (--remote-cert-tls server)</string> - <string name="check_remote_tlscert_title">Förvänta TLS servercertifikat</string> - <string name="remote_tlscn_check_summary">Verifierar Remote Server Certificate Subject DN</string> - <string name="remote_tlscn_check_title">Certifikat Hostname kontroll</string> - <string name="enter_tlscn_dialog">Ange den kontroll som används för att verifiera Fjärrcertifikat DN (e.g. C=DE, L=Paderborn, OU=Avian IP Carriers, CN=openvpn.blinkt.de)\n\nSpecificera en komplett DN eller RDN (openvpn.blinkt.de i exemplet) eller ett RDN prefix för verifiering.\n\nOm RDN prefix används matchar \"Server\" både \"Server-1\" och \"Server-2\" \n\nLämnas textfältet tomt matchas RDN mot server hostname.\n\nFor mer information se OpenVPN 2.3.1+ manpage under —verify-x509-name</string> - <string name="enter_tlscn_title">Fjärrcertifikats ämne</string> - <string name="tls_key_auth">Aktiverar TLS Key Authetication</string> - <string name="tls_auth_file">TLS Auth fil</string> - <string name="pull_on_summary">Begär IP-adresser, rutter och tidsalternativ från servern.</string> - <string name="pull_off_summary">Ingen information begärs från servern. Inställningar behöver specificeras nedan.</string> - <string name="use_pull">Hämta inställningar</string> - <string name="dns">DNS</string> - <string name="override_dns">Använd DNS-inställningarna från servern</string> - <string name="dns_override_summary">Använda dina egen DNS-servrar</string> - <string name="searchdomain">searchDomain</string> - <string name="dns1_summary">DNS-Server som ska användas.</string> - <string name="dns_server">DNS-server</string> - <string name="secondary_dns_message">Sekundära DNS-servern används om den normala DNS-servern inte kan nås.</string> - <string name="backup_dns">Sekundär DNS-Server</string> - <string name="ignored_pushed_routes">Ignorera tilldelade rutter</string> - <string name="ignore_routes_summary">Ignorera rutter tilldelade av servern.</string> - <string name="default_route_summary">Omdirigerar all trafik över VPN-anslutningen</string> - <string name="use_default_title">Använd standardrutt</string> - <string name="custom_route_message">Ange anpassade rutter. Skriv destination i CIDR-format. \"10.0.0.0/8 2002:: / 16\" dirigerar nätverk 10.0.0.0/8 och 2002:: / 16 över VPN.</string> - <string name="custom_route_message_excluded">Rutter som INTE bör dirigeras över VPN. Använd samma syntax som för ingående rutter.</string> - <string name="custom_routes_title">Anpassade rutter</string> - <string name="custom_routes_title_excluded">Exkluderade nätverk</string> - <string name="log_verbosity_level">Utförlighetsnivå för log</string> - <string name="float_summary">Tillåter autentiserade paket från alla IP-adresser</string> - <string name="float_title">Tillåt flytande server</string> - <string name="custom_options_title">Anpassade alternativ</string> - <string name="edit_vpn">Redigera VPN-inställningar</string> - <string name="remove_vpn_query">Ta bort VPN-profilen \'%s\'?</string> - <string name="tun_error_helpful">På vissa anpassade ICS ROM kan behörigheten på /dev/tun vara fel eller så kan tun modulen saknas helt. För CM9 ROM prova alternativet fixa ägande under allmänna inställningar</string> - <string name="tun_open_error">Det gick inte att öppna tun gränssnittet</string> - <string name="error">"Fel:"</string> - <string name="clear">Klart</string> - <string name="last_openvpn_tun_config">Öppnar tun gränssnittet:</string> - <string name="local_ip_info">Lokal IPv4: %1$s/%2$d IPv6: %3$s MTU: %4$d</string> - <string name="dns_server_info">DNS-Server: %1$s, Domän: %2$s</string> - <string name="routes_info_incl">Rutter: %1$s %2$s</string> - <string name="routes_info_excl">Rutter uteslutna: %1$s %2$s</string> - <string name="routes_debug">VpnService rutter installerade: %1$s %2$s</string> - <string name="ip_not_cidr">Fick gränssnitts informationen %1$s och %2$s, förutsätter att andra adressen är peer adressen på fjärrservern. Använder nätmask /32 för lokal IP. Satus på OpenVPN är \"%3$s\".</string> - <string name="route_not_cidr">Förstår inte %1$s och %2$s som IP rutt med CIDR netmask, där /32 används som nätmask.</string> - <string name="route_not_netip">Korrigerad rutt %1$s/%2$s till %3$s/%2$s</string> - <string name="keychain_access">Åtkomst nekas till certifikat i Android nyckelring. Detta kan orsakas av en firmware-uppgradering eller en återställning från säkerhetskopia av app/app inställningar. Vänligen redigera VPN och välj på nytt certifikatet under grundinställningar för att återskapa åtkomstbehörigheten till certifikatet.</string> - <string name="version_info">%1$s %2$s</string> - <string name="send_logfile">Skicka loggfilen</string> - <string name="send">Skicka</string> - <string name="ics_openvpn_log_file">ICS OpenVPN loggfil</string> - <string name="copied_entry">Kopierade loggpost till klippboken</string> - <string name="tap_mode">Tap-läge</string> - <string name="faq_tap_mode">Tap-läge är inte möjligt med icke root VPN-API. Därför kan inte denna applikation stödja tap-läge</string> - <string name="tap_faq2">Igen? Skämtar du? Nej, tap-läge stöds verkligen inte och det hjälper inte att skicka fler mail och fråga om det kommer att stödjas i framtiden.</string> - <string name="tap_faq3">En tredje gång? Man skulle kunda skriva en tap-emulator baserat på tun som skulle lägga till layer2 information vid skicka och ta bort layer2 information vid ta emot. Men denna tap emulator skulle också behöva implementera ARP och eventuellt också en DHCP-klient. Jag är inte medveten om att någon gjort något arbete i denna riktning. Kontakta mig om du vill börja koda på detta.</string> - <string name="faq">FAQ</string> - <string name="copying_log_entries">Kopierar loggposter</string> - <string name="faq_copying">För att kopiera en enda logg post tryck och håll på loggposten. Om du vill kopiera/skicka hela loggen använd alternativet Skicka loggen. Använd hårdvarumenyknappen om menyn inte syns i GUI.</string> - <string name="faq_shortcut">Genväg för att starta</string> - <string name="faq_howto_shortcut">Du kan placera en genväg för att starta OpenVPN på skrivbordet. Beroende på ditt hemskärmsprogram måste du lägga till antingen en genväg eller en widget.</string> - <string name="no_vpn_support_image">Din ROM stöder inte VPNService API, ledsen :(</string> - <string name="encryption">Kryptering</string> - <string name="cipher_dialog_title">Ange krypteringsmetod</string> - <string name="chipher_dialog_message">Ange den krypteringsalogritm som skall användas av OpenVPN. Lämna tomt för att använda standardalgoritm.</string> - <string name="auth_dialog_message">Ange den autentiserings digest som används för OpenVPN. Lämna tom för att använda standard digest.</string> - <string name="settings_auth">Autentisering/kryptering</string> - <string name="file_explorer_tab">Filutforskare</string> - <string name="inline_file_tab">Inline-fil</string> - <string name="error_importing_file">Fel vid import av fil</string> - <string name="import_error_message">Kunde inte importera filen från filsystemet</string> - <string name="inline_file_data">[[Inline-fil data]]</string> - <string name="opentun_no_ipaddr">Vägrar att öppna tun enhet utan IP-information</string> - <string name="menu_import">Importera profil från ovpn fil</string> - <string name="menu_import_short">Import</string> - <string name="import_content_resolve_error">Kunde inte läsa profil att importera</string> - <string name="error_reading_config_file">Fel vid läsning av konfigurationsfil</string> - <string name="add_profile">lägg till profil</string> - <string name="import_could_not_open">Kunde inte hitta filen %1$s som omnämns i den importerade konfigurationsfilen</string> - <string name="importing_config">Importerar konfigurationsfilen från %1$s</string> - <string name="import_warning_custom_options">Din konfiguration hade några konfigurationsalternativ som inte är kopplade till UI konfigurationer. Dessa alternativ lades till som anpassade konfigurationsalternativ. Den anpassade konfigurationen visas nedan:</string> - <string name="import_done">Färdig med att läsa konfigurationsfilen.</string> - <string name="nobind_summary">Bind inte till lokal adress och port</string> - <string name="no_bind">Ingen lokal bindning</string> - <string name="import_configuration_file">Importera konfigurationsfil</string> - <string name="faq_security_title">Säkerhetsaspekter</string> - <string name="faq_security">"Eftersom OpenVPN är säkerhets känslig kan några om säkerhet vara vettiga. Alla data på sd-kortet är potentiellt osäkra. Varje app kan läsa datan (till exempel kräver detta program inga särskilda sd-korts rättigheter). Datat som tillhör denna applikation kan endast läsas av applikationen själv. Genom att använda alternativet import för cacerts/cert/nyckel i fildialogrutan lagras datat i VPN-profilen. VPN-profiler kan bara läsas av denna applikation. (Glöm inte att ta bort kopiorna på sd-kortet efteråt). Även om datat endast är tillgängligt för denna applikation så är data fortfarande okrypterat. Genom att roota telefon eller med andra hack kan det vara möjligt att få åtkomst till datat. Sparade lösenord lagras också i klartext. För pkcs12 filer rekommenderas det starkt att du importerar dem till Android nyckering."</string> - <string name="import_vpn">Import</string> - <string name="broken_image_cert_title">Fel vid visning av certifikatval</string> - <string name="broken_image_cert">Fick ett undantag när Android 4.0+ dialogrutan för val av certifikat försökte visas. Detta bör aldrig ske eftersom detta en standardfunktion hos Android 4.0+. Kanske är stödet för lagring av certifikat i din Android ROM trasigt</string> - <string name="ipv4">IPv4</string> - <string name="ipv6">IPv6</string> - <string name="speed_waiting">Väntar på tillstånds meddelande…</string> - <string name="converted_profile">importerad profil</string> - <string name="converted_profile_i">importerad profil %d</string> - <string name="broken_images">Trasiga ROM</string> - <string name="broken_images_faq"><p>Officiella HTC ROM är kända för att ha ett konstigt rutt problem som orsakar att trafik inte går genom tunneln (Se även <a href=\"http://code.google.com/p/ics-openvpn/issues/detail?id=18\">Ärende 18</a> i äredehanteringen.)</p><p>Äldre officiella SONY ROM för Xperia Arc S och Xperia Ray har rapporterats sakna VPNService helt. (Se även <a href=\"http://code.google.com/p/ics-openvpn/issues/detail?id=29\">Ärende 29</a> i ärendehanteringen.)</p><p>I anpassade/modifierade ROM kan tun modulen saknas eller rättigheterna på /dev/tun kan vara fel. Vissa CM9 ROM behöver alternativet \"Fixa ägande\" under \"Modellanpassade hack\" ikryssat.</p><p>Viktigt: Om du har en trasig ROM, rapportera det till din leverantör. Ju fler människor som rapportera problemet till leverantören desto mer sannolikt är det att det kommer en rättning.</p></string> - <string name="pkcs12_file_encryption_key">Krypteringsnyckel för PKCS12-filen</string> - <string name="private_key_password">Lösenord för privat nyckel</string> - <string name="password">Lösenord</string> - <string name="file_icon">filikon</string> - <string name="tls_authentication">TLS-autentisering/kryptering</string> - <string name="generated_config">Genererad konfiguration</string> - <string name="generalsettings">Inställningar</string> - <string name="owner_fix_summary">Försöker att sätta ägaren av /dev/tun till system. Vissa CM9 ROM behöver detta för att VPNService API ska fungera. Detta kräver root.</string> - <string name="owner_fix">Fixa ägande av /dev/tun</string> - <string name="generated_config_summary">Visar den genererade OpenVPN-konfigurationsfilen</string> - <string name="edit_profile_title">Redigerar \"%s\"</string> - <string name="building_configration">Bygger konfiguration…</string> - <string name="netchange_summary">Aktivering av detta alternativ kommer att tvinga en återanslutning om nätverksanslutningen ändras (t.ex. WiFi <-> mobildata)</string> - <string name="netchange">Återanslut vid förändring av nätverksanslutning</string> - <string name="netstatus">Nätverksstatus: %s</string> - <string name="extracahint">CA certifikat hämtas vanligtvis från Android Keystore. Ange ett separat certifikat om du får verifieringsfel på certifikatet.</string> - <string name="select_file">Välj</string> - <string name="keychain_nocacert">Inget CA certifikat returnerades från Android Keystore. Autenticering kommer troligen att misslyckas.</string> - <string name="show_log_summary">Visar loggfönstret vid anslutning. Loggfönstret kan alltid nås från statusgardinen.</string> - <string name="show_log_window">Visa loggfönstret</string> - <string name="mobile_info">%10$s %9$s körs på %3$s %1$s (%2$s), Android %6$s (%7$s) API %4$d, ABI %5$s, (%8$s)</string> - <string name="error_rsa_sign">Fel vid signering med Android keystore nyckeln %1$s: %2$s</string> - <string name="faq_system_dialogs">Varningen vid VPN-anslutning som berättar att denna app kan avlyssna all trafik utfärdas av systemet för att förhindra missbruk av VPNService API.\nNotifieringen om VPN-anslutning (nyckelsymbolen) tillhandahålles också av Android-systemet för att signalera en pågående VPN-anslutning. På vissa ROM spelar denna notifiering ett ljud.\nAndroid har infört dessa dialogrutor och notifieringar för din egen säkerhet och kan inte undvikas. (På vissa ROM innehåller dessa tyvärr ljud)</string> - <string name="faq_system_dialogs_title">Anslutnings varning och ljud</string> - <string name="translationby">Svensk översättning av Zapp och Mr_Arrow</string> - <string name="ipdns">IP och DNS</string> - <string name="basic">Grundläggande</string> - <string name="routing">Rutter</string> - <string name="obscure">Obskyra OpenVPN inställningar. Behövs normalt inte.</string> - <string name="advanced">Avancerad</string> - <string name="export_config_title">ICS OpenVPN konfiguration</string> - <string name="warn_no_dns">Inga DNS-servrar används. Namnuppslag kommer kanske inte fungera. Överväg att namnge egna DNS-servrar. Observera även att Android kommer att fortsätta att använda dina proxyinställningar som anges för din mobildata/Wi-Fi-anslutning när inga DNS-servrar är konfigurerade.</string> - <string name="dns_add_error">Kunde inte lägga till DNS-servern \"%1$s\", förkastades av systemet: %2$s</string> - <string name="ip_add_error">Det gick inte att konfigurera IP-adress \"%1$s\", avvisades av systemet: %2$s</string> - <string name="faq_howto"><p>Hämta en fungerande konfiguration (testad på din dator eller nerladdad från din leverantör/organisation)</p><p>Om det är en enda fil utan extra pem/pks12 filer kan du maila den till dig själv och öppna den bifogade filen. Om du har flera filer lägg dem på ditt sd-kort.</p><p>Klicka på den i mailet bifogade filen/Användning mappikonen i VPN-listan för att importera konfigurationsfilen</p><p>Om det ger fel ang. saknade filer lägg dessa på ditt sd-kort.</p><p>Klicka på spara symbolen för att lägga till den importerade konfigurationen i VPN-listan</p><p>Anslut din VPN genom att klicka på konfigurationsnamnet</p><p>Om det finns fel eller varningar i loggen försöka förstå dessa varningar/fel och försök att åtgärda dem</p> </string> - <string name="faq_howto_title">Snabbstart</string> - <string name="setting_loadtun_summary">Prova att ladda kärnmodulen tun.ko innan du försöker ansluta. Kräver root.</string> - <string name="setting_loadtun">Ladda tun modul</string> - <string name="importpkcs12fromconfig">Importera PKCS12 från konfigurationen till Android Keystore</string> - <string name="getproxy_error">Fel vid hämtning av proxyinställningar: %s</string> - <string name="using_proxy">Använder proxy %1$s %2$s</string> - <string name="use_system_proxy">Använd system proxy</string> - <string name="use_system_proxy_summary">Använda systemkonfigurationen för HTTP/HTTPS proxy för att ansluta.</string> - <string name="onbootrestartsummary">OpenVPN kommer att ansluta angiven VPN om den var aktivt vid systemets uppstart. Vänligen läs anslutningsvarnings FAQ innan du använder det här alternativet på Android < 5.0.</string> - <string name="onbootrestart">Anslut vid uppstart</string> - <string name="ignore">Ignorera</string> - <string name="restart">Starta om</string> - <string name="restart_vpn_after_change">Konfigurationsändringar tillämpas efter omstart av VPN. Starta(om) VPN nu?</string> - <string name="configuration_changed">Konfigurationen ändrades</string> - <string name="log_no_last_vpn">Kunde inte avgöra vilken den sista anslutna profilen var för redigering</string> - <string name="faq_duplicate_notification_title">Dubbla noteringar</string> - <string name="faq_duplicate_notification">Om Android tillfälligt har brist på systemminne (RAM), tas program och tjänster som inte behövs just nu bort från aktiva minnet. Detta avslutar en pågående VPN-anslutning. För att se till att pågående anslutning/OpenVPN överlever körs denna tjänst med högre prioritet. För att köra med högre prioritet måste applikationen visa en notifikation. Nyckelikonen visas av systemet, som beskrivs i FAQ tidigare, och räknas inte som ett meddelande som ger rättighet att köra med högre prioritet.</string> - <string name="no_vpn_profiles_defined">Inga VPN-profiler har definierats.</string> - <string name="add_new_vpn_hint">Använd <img src=\"ic_menu_add\"/> ikonen för att lägga till en ny VPN</string> - <string name="vpn_import_hint">Använd <img src=\"ic_menu_archive\"/> ikonen för att importera en befintlig (.ovpn eller .conf) profil från ditt sd-kort.</string> - <string name="faq_hint">Tänk på att titta i FAQ\'n. Där finns en snabbstartguide.</string> - <string name="faq_routing_title">Konfiguration för rutter/gränssnitt</string> - <string name="faq_routing">Omdirigering och gränssnittskonfiguration görs inte via traditionella ifconfig/rutt kommandon men med hjälp av VPNService API. Detta resulterar i en annan omdirigering konfigurering än på andra operativsystem. \nKonfiguration av VPN-tunneln består av IP-adressen och de nätverk som ska dirigeras över detta gränssnitt. Speciellt behövs eller krävs ingen inbördes partner adress eller gatewayadress. Särskilda rutter för att nå VPN-server (t.ex. när du använder omdirigera-gateway) behövs inte heller. Applikationen kommer följaktligen ignorera dessa inställningar när du importerar en konfiguration. Applikationen försäkrar med VPNService API att anslutningen till servern inte dirigeras genom VPN-tunnel.\nVPNService API tillåter inte att specificera nätverk som inte ska dirigeras via VPN. Som en lösning försöker applikationen att identifiera nätverk som inte ska dirigeras över tunneln (t.ex. rutt x.x.x.x y.y.y.y net_gateway) och beräknar en uppsättning av rutter som utesluter dessa rutter att efterlikna beteendet hos andra plattformar. Loggnings fönstret visar konfigurationen av VPNService då en upprättning av anslutning.\nBakom kulisserna. Android 4.4+ använder policy omdirigering. Användning av rutt/ifconfig kommer inte att visa installerade rutter. Använd istället ip regel, iptables -t mangle -L</string> - <string name="persisttun_summary">Fall inte tillbaka till ingen VPN-anslutning när OpenVPN återansluter.</string> - <string name="persistent_tun_title">Ihållande tun</string> - <string name="openvpn_log">OpenVPN Log</string> - <string name="import_config">Importera OpenVPN konfiguration</string> - <string name="battery_consumption_title">Batteriförbrukning</string> - <string name="baterry_consumption">I mina personliga tester är den främsta orsaken till hög batteriförbrukning vid användning av OpenVPN hållvidliv-paketen. De flesta OpenVPN servrar har en konfiguration med \"keepalive 10 60\" som leder till att hållvidliv-paket skickas från klienten till servern och från servern till klienten var tionde sekund. <p> Även om dessa paket är små och inte använder mycket datatrafik håller de det mobila radionätet upptaget och ökar på så vis energiförbrukningen. (Se även <a href=\"http://developer.android.com/training/efficient-downloads/efficient-network-access.html#RadioStateMachine\">The Radio State Machine | Android Developers</a>) <p> Denna hållvidliv-inställning kan inte ändras i klienten. Endast systemadministratören för OpenVPN kan ändra inställningen. <p> Tyvärr leder en hållvidliv som är större än 60 sekunder med UDP till att vissa NAT-gateways tappar anslutningen efter en kort timeout (60 sekunder i mina tester). Via TCP med lång hållvidliv fungerar men ger TCP över TCP problem. (Se <a href=\"http://sites.inka.de/bigred/devel/tcp-tcp.html\">varför TCP över TCP är en dålig idé</a>)</string> - <string name="faq_tethering">Funktionen Internetdelning i Android (över WiFi, USB eller Bluetooth) och VPNService API (används av denna applikation) fungerar inte tillsammans. För mer information se <a href=\"http://code.google.com/p/ics-openvpn/issues/detail?id=34\">ärende #34</a></string> - <string name="vpn_tethering_title">VPN och Internetdelning</string> - <string name="connection_retries">Anslutningsförsök</string> - <string name="reconnection_settings">Inställningar för återanslutning</string> - <string name="connectretrymessage">Antal sekunder att vänta mellan anslutningsförsök.</string> - <string name="connectretrywait">Sekunder mellan anslutningar</string> - <string name="minidump_generated">OpenVPN kraschade oväntat. Försök att använda skicka Minidump alternativet i huvudmenyn</string> - <string name="send_minidump">Skicka Minidump till utvecklare</string> - <string name="send_minidump_summary">Skickar felsökningsinformation om senaste krasch till utvecklare</string> - <string name="notifcation_title">OpenVPN - %s</string> - <string name="session_ipv4string">%1$s - %2$s</string> - <string name="session_ipv6string">%1$s - %3$s, %2$s</string> - <string name="state_connecting">Ansluter</string> - <string name="state_wait">Väntar på svar från servern</string> - <string name="state_auth">Autentiserar</string> - <string name="state_get_config">Hämtar klientkonfiguration</string> - <string name="state_assign_ip">Tilldelar IP-adresser</string> - <string name="state_add_routes">Lägger till rutter</string> - <string name="state_connected">Ansluten</string> - <string name="state_disconnected">Koppla ifrån</string> - <string name="state_reconnecting">Återansluter</string> - <string name="state_exiting">Avslutar</string> - <string name="state_noprocess">Kör inte</string> - <string name="state_resolve">Slår upp värdnamn</string> - <string name="state_tcp_connect">Ansluter (TCP)</string> - <string name="state_auth_failed">Autentisering misslyckades</string> - <string name="state_nonetwork">Väntar på användbart nätverk</string> - <string name="statusline_bytecount">↓%2$s %1$s - ↑%4$s %3$s</string> - <string name="notifcation_title_notconnect">Inte ansluten</string> - <string name="start_vpn_title">Ansluter till VPN %s</string> - <string name="start_vpn_ticker">Ansluter till VPN %s</string> - <string name="jelly_keystore_alphanumeric_bug">Vissa versioner av Android 4.1 har problem om namnet på keystore certifikatet innehåller icke alfanumeriska tecken (som mellanslag, understreck eller bindestreck). Försök att omimportera certifikatet utan specialtecken</string> - <string name="encryption_cipher">Krypteringschiffer</string> - <string name="packet_auth">Paketautentisering</string> - <string name="auth_dialog_title">Ange autentiseringsmetod för paket</string> - <string name="built_by">byggd av %s</string> - <string name="debug_build">felsöknings bygge</string> - <string name="official_build">officiellt bygge</string> - <string name="make_selection_inline">Kopiera till profil</string> - <string name="crashdump">Crashdump</string> - <string name="add">Lägg till</string> - <string name="send_config">Skicka konfigurationsfilen</string> - <string name="complete_dn">Komplett DN</string> - <string name="remotetlsnote">Din importerade konfiguration innehåller gamla, ej längre i bruk, tls-remote optioner som använder ett annat DN-format.</string> - <string name="rdn">RDN (vanligt namn)</string> - <string name="rdn_prefix">RDN prefix</string> - <string name="tls_remote_deprecated">TLS-remote (ej längre i bruk)</string> - <string name="help_translate">Du kan hjälpa till med översättningen genom att besöka http://crowdin.net/project/ics-openvpn/invite</string> - <string name="prompt">%1$s försöker styra %2$s</string> - <string name="remote_warning">Genom att fortsätta ger du applikationen tilstånd att fullständigt styra OpenVPN för Android och att avlyssna all nätverkstrafik. <b>Acceptera INTE om du inte litar på applikationen.</b> Annars riskerar du att din data äventyras av skadlig programvara.\"</string> - <string name="remote_trust">Jag litar på denna applikation.</string> - <string name="no_external_app_allowed">Ingen app får använda externa API</string> - <string name="allowed_apps">Tillåtna apps: %s</string> - <string name="clearappsdialog">Rensa lista över tillåtna externa apps? \nNuvarande lista över tillåtna apps:\n\n%s</string> - <string name="screenoff_summary">\"Pause VPN när skärmen är avstängd och mindre än 64 kB överförda data i 60s. När \"Ihållande Tun\" är aktiverat kommer pausning av VPN att lämna enheten UTAN nätverksanslutning. Utan \"Ihållande Tun\" alternativet kommer enheten inte att ha någon VPN-anslutning / skydd.</string> - <string name="screenoff_title">Pausa VPN-anslutningen efter att skärmen stängts av</string> - <string name="screenoff_pause">Pausa anslutning när skärmen är avstängd: mindre än %1$s i %2$ss</string> - <string name="screen_nopersistenttun">Varning: Permanent tun är inte aktiverat för denna VPN. Trafiken kommer att använda den normala Internet-anslutning när skärmen är avstängd.</string> - <string name="save_password">Spara lösenord</string> - <string name="pauseVPN">Pausa VPN</string> - <string name="resumevpn">Återuppta VPN</string> - <string name="state_userpause">VPN paus begärs av användaren</string> - <string name="state_screenoff">VPN paus - skärmen av</string> - <string name="device_specific">Enhetsutförande Hacks</string> - <string name="cannotparsecert">Kan inte visa certifikatinformation</string> - <string name="appbehaviour">Ansökan beteende</string> - <string name="vpnbehaviour">VPN beteende</string> - <string name="allow_vpn_changes">Tillåta ändringar av VPN profiler</string> - <string name="hwkeychain">Hårdvara Keystore:</string> - <string name="permission_icon_app">Ikonen för appen försöker använda OpenVPN för Android</string> - <string name="faq_vpndialog43">"Från och med Android 4.3, så är dialogrutan för att godkänna VPN-anslutning skyddad mot \"appar som lägger sig över\". Detta gör att dialogen spärras mot tryckningar. Om du använder en app som lägger sig över andra appar, så kan detta orsaka det beteendet. Om du hittar den trilskande appen, kontakta skaparen av den appen. Detta problem påverkar alla VPN-appar på Android 4.3 och senare. Se också <a href=\"https://github.com/schwabe/ics-openvpn/issues/185\">Ärende 185<a> för mer information"</string> - <string name="faq_vpndialog43_title">Vpn Bekräftelse Dialog</string> - <string name="donatePlayStore">Alternativt kan du skicka mig en donation med Play Store:</string> - <string name="thanks_for_donation">Tack för att du donerar %s!</string> - <string name="logCleared">Log rensas.</string> - <string name="show_password">Visa lösenord</string> - <string name="keyChainAccessError">Nyckelhanterare fel: %s</string> - <string name="timestamp_short">Kort</string> - <string name="timestamp_iso">ISO</string> - <string name="timestamps">Tidsstämplar</string> - <string name="timestamps_none">Ingen</string> - <string name="uploaded_data">Ladda upp</string> - <string name="downloaded_data">Hämta</string> - <string name="vpn_status">VPN-status</string> - <string name="logview_options">Visa alternativ</string> - <string name="unhandled_exception">Ohanterat undantag: %1$s\n\n%2$s</string> - <string name="unhandled_exception_context">%3$s: %1$s\n\n%2$s</string> - <string name="faq_system_dialog_xposed">Om du har rootat din Android-enhet, så kan du installera <a href=\"http://xposed.info/\">Xposed-ramverket</a> och <a href=\"http://repo.xposed.info/module/de.blinkt.vpndialogxposed\">VPN-bekräftelsemodulen</a> på egen risk\"</string> - <string name="full_licenses">Fullständiga licensavtal</string> - <string name="blocklocal_summary">Nätverk direkt kopplade till lokala gränssnitt kommer inte att dirigeras över VPN. Avmarkering av detta alternativ kommer att omdirigera all trafik avsedda för lokala nätverk till VPN.</string> - <string name="blocklocal_title">Kringgå VPN för lokala nätverk</string> - <string name="userpw_file">Användarnamn / lösenord fil</string> - <string name="imported_from_file">[Importerad från: %s]</string> - <string name="files_missing_hint">Vissa filer kunde inte hittas. Välj filer för att importera profil:</string> - <string name="openvpn_is_no_free_vpn">För att använda denna applikation behöver du en VPN-leverantör/VPN-gateway som stöder OpenVPN (ofta tillhandahållen av din arbetsgivare). Kolla http://community.openvpn.net/ för mer information om OpenVPN och hur man ställer in en egen OpenVPN-server.</string> - <string name="import_log">Importloggen:</string> - <string name="ip_looks_like_subnet">Vpn-topologi \"%3$s\" specifierad, men ifconfig %1$s %2$s ser ut att vara en IP-adress med en nätmask. Antar \"subnet\"-topologi.</string> - <string name="mssfix_invalid_value">MSS överbelastningsvärde måste vara en heltal mellan 0 och 9000</string> - <string name="mtu_invalid_value">MTU-överskridningsvärdet måste vara ett heltal mellan 64 och 9000</string> - <string name="mssfix_value_dialog">Meddela TCP-sessioner som körs över tunneln att de ska begränsa sina sändningspaketstorlekar så att efter OpenVPN har inkapslat dem, kommer den resulterande UDP-paketstorleken som OpenVPN skickar till dess peerer inte överstiga detta antal byte. (Standard är 1450)</string> - <string name="mssfix_checkbox">Kringgå MSS-värdet för innehållet i TCP-paket</string> - <string name="mssfix_dialogtitle">Ställ in MSS för innehållet i TCP-paket</string> - <string name="client_behaviour">Klientens beteende</string> - <string name="clear_external_apps">Rensa tillåtna externa applikationer</string> - <string name="loading">Laddar...</string> - <string name="allowed_vpn_apps_info">Tillåtna VPN-applikationer: %1$s</string> - <string name="disallowed_vpn_apps_info">Otillåtna VPN-applikationer: %1$s</string> - <string name="app_no_longer_exists">Paket %s är inte längre installerat, ta bort den från tillåtna/otillåtna applikationslistan</string> - <string name="vpn_disallow_radio">VPN används för alla applikationer men exkluderar valda</string> - <string name="vpn_allow_radio">VPN används endast för utvalda applikationer</string> - <string name="query_delete_remote">Radera serverpost?</string> - <string name="keep">Ha kvar</string> - <string name="delete">Radera</string> - <string name="add_remote">Lägg till ny server</string> - <string name="remote_random">Använd anslutnings poster i slumpmässig ordning på Anslut</string> - <string name="remote_no_server_selected">Du måste definiera och aktivera åtminstone en fjärrserver.</string> - <string name="server_list">Serverlista</string> - <string name="vpn_allowed_apps">Tillåtna appar</string> - <string name="payload_options">Alternativ för paketinnehåll</string> - <string name="tls_settings">TLS-inställningar</string> - <string name="no_remote_defined">Ingen server specifierad</string> - <string name="duplicate_vpn">Duplicera VPN-profil</string> - <string name="duplicate_profile_title">Duplicerar profil: %s</string> - <string name="show_log">Visa logg</string> - <string name="faq_android_clients">Flera OpenVPN klienter för Android finns. Den vanligaste är OpenVPN för Android (denna klient), OpenVPN Connect och OpenVPN Settings.<p>Klienterna kan delas in i två grupper: OpenVPN för Android och OpenVPN Connect använder den officiella VPNService API:n (Android 4.0+) och kräver ingen rot och OpenVPN Settings som använder rot.<p>OpenVPN for Android är en klient med öppen källkod som har utvecklats av Arne Schwabe. Den riktar sig till mer avancerade användare och erbjuder många inställningar och möjligheten som att importera profiler från filer och konfigurera/ändra profiler inuti appen. Klienten bygger på den gemensamma versionen av OpenVPN. Den är baserad på OpenVPN 2.x källkod. Denna klient kan ses som den halvt officiella klienten i gemenskapen. <p>OpenVPN Connect har inte öppen källkod klient och är utvecklad av OpenVPN Technologies, Inc. Klienten indragen för allmänt bruk och mer inriktad på den genomsnittlige användaren och tillåter importering av OpenVPN profiler. Denna klient är baserad på OpenVPN C ++ reimplementation av OpenVPN protokollet (detta krävdes för att tillåta OpenVPN Technologies, Inc att publicera en iOS OpenVPN app). Denna klient är den officiella klienten av OpenVPN teknik <p> OpenVPN Settings är den äldsta av klienterna och även för UI för OpenVPN öppna källkod. I motsats till OpenVPN för Android kräver den rot och använder inte VPNService API. Den beror inte på Android 4.0+</string> - <string name="faq_androids_clients_title">Skillnader mellan OpenVPN Android klienterna</string> - <string name="ignore_multicast_route">Ignorera multicast rutt: %s</string> - <string name="ab_only_cidr">Android stödjer bara rutter specifierade i CIDR-format för VPNet. Eftersom rutter specifierade utan CIDR nästan aldrig används, så kommer OpenVPN för Android använda /32 för dessa rutter, och ge en varning.</string> - <string name="ab_tethering_44">Internetdelning fungerar medans VPNet är aktivt. Den delade anslutningen kommer INTE gå via VPNet.</string> - <string name="ab_kitkat_mss">Tidigt KitKat version anger fel MSS värdet på TCP-anslutningar (# 61.948). Försök att göra det möjligt för mssfix möjlighet att kringgå denna bugg.</string> - <string name="ab_proxy">Android kommer att använda de proxyinställningar som har ställts in för anslutningen över mobilnät/trådlöst när inga DNS-servrar är inställda. OpenVPN kommer att varna för detta i loggen.<p>När en VPN-anslutning anger en DNS-server, kommer Android att hoppa över proxyn. Det finns inget API för att ange en proxy för en VPN-anslutning.</p></string> - <string name="ab_lollipop_reinstall">VPN appar kan sluta fungera när avinstalleras och installeras igen. För mer information se # 80074</string> - <string name="ab_not_route_to_vpn">Det konfigurerade klient-IPt och de IP-nummer som omfattas av dess nätmask är inte ruttade via VPNet. OpenVPN kommer att motarbeta denna bugg genom att explicit lägga till en rutt som omfattar klient-IPt och dess nätmask</string> - <string name="ab_persist_tun">Att öppna en tun-enhet medans en annan tun-enhet är aktiv, och denna används för ihållande tun, kommer att krascha VPN-funktionen på enheten. Detta innebär att enheten måste startas om för att VPN skall fungera igen. OpenVPN för Android försöker undvika att öppna tun-enheten på nytt, och om det verkligen behövs, då stänga befintliga tun-anslutningar innan den öppnar den nya tun-enheten för att undvika denna krasch. Detta kan leda till ett litet tidsfönster där paket kan läcka ut utanför VPN-anslutningen. Även med denna fix, så kraschar ibland VPN-funktionen, och kräver då att enheten startas om.</string> - <string name="ab_secondary_users">VPN fungerar inte över huvud taget för extra användarkonton.</string> - <string name="ab_kitkat_reconnect">"Flera användare har rapporterat att anslutningen till mobilnätverket går ner då och då medans denna VPN-app används. Detta beteende verkar bara påverka vissa kombinationer av operatörer/enheter, och vi har hittils inte hittat någon orsak/lösning för buggen."</string> - <string name="ab_vpn_reachability_44">Bara destination kan nås över VPN som kan nås utan VPN. IPv6-VPN fungerar inte alls.</string> - <string name="ab_only_cidr_title">Icke CIDR rutter</string> - <string name="ab_proxy_title">Proxy beteende för VPN</string> - <string name="ab_lollipop_reinstall_title">Installera om VPN appar</string> - <string name="version_upto">%s och tidigare</string> - <string name="copy_of_profile">Kopia av %s</string> - <string name="ab_not_route_to_vpn_title">Rutt till den konfigurerade IP-adressen</string> - <string name="ab_kitkat_mss_title">Fel MSS-värde för VPN-anslutning</string> - <string name="ab_secondary_users_title">Sekundära surfplattsanvändare</string> - <string name="custom_connection_options_warng">Ange anpassade anslutningsspecifika alternativ. Används med försiktighet</string> - <string name="custom_connection_options">Anpassade alternativ</string> - <string name="remove_connection_entry">Ta bort anslutningspost</string> - <string name="ab_kitkat_reconnect_title">Intermittienta frånkopplingar från mobilnätverk</string> - <string name="ab_vpn_reachability_44_title">VPN-nätverket är inte nåbart</string> - <string name="ab_persist_tun_title">Ihållande tun-läge</string> - <string name="version_and_later">%s och senare</string> - <string name="tls_cipher_alert_title">Anslutningar misslyckas med SSL23_GET_SERVER_HELLO:SSLv3 alert handskakningsfel</string> - <string name="tls_cipher_alert">Nyare OpenVPN för Android-versioner (0.6.29/mars 2015) använder en säkrare standard för de tillåtna krypteringssviter (tls-chiffer \"DEFAULT:!EXP:!PSK:!SRP:!kRSA\"). Tyvärr, utelämna mindre säker krypteringssviter och exportchiffersviter, särskilt utelämnandet av chiffersviter som inte stöder Perfect Forward Secrecy (Diffie-Hellman) orsakar några problem. Detta orsakas oftast av en välmenande men dåligt utförda försök att stärka TLS-säkerhet genom att tls-chiffer på servern eller några inbäddade operativsystem med avskalad SSL (t.ex. MikroTik).\nFör att lösa problemet, ställa in tls-chiffer inställningar på servern till rimlig standard som tls-siffran \"DEFAULT:!EXP:!PSK:!SRP:!kRSA\". För att komma runt problemet med klienten lägg till anpassad alternativ tls-chiffer DEFAULT i Android-klienten.</string> - <string name="message_no_user_edit">Den här profilen har lagts från en extern app (%s) och har markerats som oredigerbar av användare.</string> - <string name="crl_file">Lista över återkallade certifikat</string> - <string name="service_restarted">Startar om OpenVPN Service (Applikationen har antagligen kraschat eller avlivats för minnespress)</string> - <string name="import_config_error">Importera config gav ett fel, kan inte spara det</string> - <string name="Search">Sök</string> - <string name="lastdumpdate">(Senaste dumpningen är %1$d:%2$dh gamla (%3$s))</string> - <string name="clear_log_on_connect">Rensa loggen vid ny anslutning</string> - <string name="connect_timeout">Anslutningsavbrott</string> - <string name="no_allowed_app">Ingen godkänd app har lagts till. Denna app (%s) läggs till i listan över godkända appar för att inte alla appar skall godkännas</string> - <string name="query_permissions_sdcard">OpenVPN för Android kan försöka upptäcka de saknade fil(erna) på SD-kortet automatiskt. Tryck på det här meddelandet för att ge tillstånd för att starta.</string> - <string name="protocol">Protokoll</string> - <string name="enabled_connection_entry">Aktiverad</string> - <string name="abi_mismatch">Önskemålet av ABI för denna enhet (%1$s) och det ABI som rapporteras av de inlästa biblioteken (%2$s) stämmer inte överens</string> - <string name="permission_revoked">VPN-tillstånd återkallas av operativsystemet (t.ex. andra VPN-program har startats), stoppar VPN</string> - <string name="pushpeerinfo">Skicka klientinformation till servern</string> - <string name="pushpeerinfosummary">Skicka extra information till servern, t.ex. SSL-versionen och Android-version</string> - <string name="pw_request_dialog_title">Behöver %1$s</string> - <string name="pw_request_dialog_prompt">Ange lösenordet för profil %1$s</string> - <string name="menu_use_inline_data">Använd inline-data</string> - <string name="export_config_chooser_title">Exportera konfigurationsfil</string> - <string name="missing_tlsauth">Filen för TLS-autensitering saknas</string> - <string name="missing_certificates">Filen för användarcertifikatet, eller filen för dess privata nyckel, saknas</string> - <string name="missing_ca_certificate">CA-certifikat saknas</string> - <string name="crl_title">Lista över återkallade certifikat (valfri)</string> - <string name="reread_log">Läs in (%d) loggrader från loggens cachefil på nytt</string> - <string name="samsung_broken">Även om Samsung telefoner är bland de mest säljande Android-telefoner, Samsungs mjukvara är också bland de mest buggiga Android mjukvarorna. Buggarna är inte begränsade till VPN driften på dessa enheter, men många av dem kan gås runt. Till följd beskrivs några av dessa buggar.\n\nDNS fungerar inte om inte DNS-servern finns VPN intervallet.\n\nPå många Samsung 5.x enheter fungerar inte de tillåtna/otillåtna programmen.\nSamsung 6.x VPN har rapporteras att inte fungera om VPN-appen är undantagen från energisparfunktioner.</string> - <string name="samsung_broken_title">Samsung-telefoner</string> - <string name="novpn_selected">Ingen VPN-anslutning vald.</string> - <string name="defaultvpn">Förvald VPN</string> - <string name="defaultvpnsummary">VPN används på platser där en förvald VPN behövs. Dessa är för närvarande vid uppstart, för Always-On och Quick Settings Tile.</string> - <string name="vpnselected">För närvarande vald VPN: \'%s\'</string> - <string name="reconnect">Återansluta</string> - <string name="qs_title">Omkoppla VPN</string> - <string name="qs_connect">Anslut till %s</string> - <string name="qs_disconnect">Koppla från %s</string> - <string name="connectretrymaxmessage">Ange den maximala tiden mellan anslutningsförsök. OpenVPN kommer sakta höja dess väntetid efter ett misslyckat anslutningsförsök upp till detta värde. Standardvärdet är 300s.</string> - <string name="connectretrymaxtitle">Maximal tid mellan anslutningsförsök</string> - <string name="state_waitconnectretry">Vänta %ss sekunder mellan anslutningsförsök</string> - <string name="nought_alwayson_warning"><![CDATA[Om du inte fick en VPN-bekräftelsesdialog har du \"Alltid på VPN\" aktiverat för en annan app. I så fall får bara den appen ansluta till en VPN. Kontrollera under Inställningar-> Nätverk mer .. -> VPNS]]></string> - <string name="management_socket_closed">Anslutning till OpenVPN stängd (%s)</string> - <string name="change_sorting">Ändra sortering</string> - <string name="sort">Sortera</string> - <string name="sorted_lru">Profiler sorterade efter senast använt</string> - <string name="sorted_az">Profiler sorterade efter namn</string> - <string name="deprecated_tls_remote">Config använder alternativ tls-fjärrkontroll som avlägsnades i 2.3 och slutligen avlägsnades i 2.4</string> - <string name="auth_failed_behaviour">Beteende vid AUTH_FAILED</string> - <string name="graph">Graf</string> - <string name="use_logarithmic_scale">Använd logaritmisk skala</string> - <string name="notenoughdata">Inte tillräckligt med data</string> - <string name="avghour">Genomsnitt per timme</string> - <string name="avgmin">Genomsnitt per minut</string> - <string name="last5minutes">Senaste 5 minuter</string> - <string name="data_in">In</string> - <string name="data_out">Ut</string> - <string name="bits_per_second">%.0f bit/s</string> - <string name="kbits_per_second">%.1f kbit/s</string> - <string name="mbits_per_second">%.1f Mbit/s</string> - <string name="gbits_per_second">%.1f Gbit/s</string> - <string name="volume_byte">%.0f B</string> - <string name="volume_kbyte">%.1f kB</string> - <string name="volume_mbyte">%.1f MB</string> - <string name="volume_gbyte">%.1f GB</string> - <string name="channel_name_background">Anslutningsstatistik</string> - <string name="channel_description_background">Löpande statistik för den etablerade OpenVPN-anslutningen</string> - <string name="channel_description_status">Statusändringar för OpenVPN-anslutningen (Anslutning, autentisering,...)</string> - <string name="weakmd_title">Svag (MD5) hashes i certifikat signatur (SSL_CTX_use_certificate md för svag)</string> - <string name="title_activity_open_sslspeed">OpenSSL-hastighetstest</string> - <string name="openssl_cipher_name">OpenSSL-ciffernamn</string> - <string name="osslspeedtest">OpenSSL Crypto-hastighetstest</string> - <string name="openssl_error">OpenSSL returnerade ett fel</string> - <string name="running_test">Kör test…</string> - <string name="test_algoirhtms">Testa valda algoritmer</string> - <string name="all_app_prompt">En extern app försöker kontrollera %s. Appen som begär åtkomst kan inte bestämmas. Tillåtelse av den här appen ger åtkomst till ALLA program.</string> - <string name="openvpn3_nostatickeys">OpenVPN 3 C ++-implementeringen stöder inte statiska nycklar. Ändra till OpenVPN 2.x under allmänna inställningar.</string> - <string name="openvpn3_pkcs12">Användning av PKCS12-filer direkt med OpenVPN 3 C++-implementering stöds inte. Vänligen importera pkcs12-filerna till Android-nyckelbutiken eller ändra till OpenVPN 2.x under allmänna inställningar.</string> - <string name="proxy">Proxy</string> - <string name="Use_no_proxy">Ingen</string> - <string name="tor_orbot">Tor (Orbot)</string> -</resources> diff --git a/app/src/main/res/values-sw600dp-port/dimens.xml b/app/src/main/res/values-sw600dp-port/dimens.xml new file mode 100644 index 0000000000000000000000000000000000000000..b631505244086976ec325b79856fa7a017aa7011 --- /dev/null +++ b/app/src/main/res/values-sw600dp-port/dimens.xml @@ -0,0 +1,7 @@ +<?xml version="1.0" encoding="utf-8"?> +<resources> + + <dimen name="footer_text_padding">20dp</dimen> + <dimen name="splash_text_top_padding">240dp</dimen> + +</resources> \ No newline at end of file diff --git a/app/src/main/res/values-sw600dp/dimens.xml b/app/src/main/res/values-sw600dp/dimens.xml index 6dd93e3af2b31130f327ae24b8cabd0da6a02cd7..4c726da59d17aa78839562f28340d67c966cc600 100644 --- a/app/src/main/res/values-sw600dp/dimens.xml +++ b/app/src/main/res/values-sw600dp/dimens.xml @@ -11,5 +11,10 @@ <dimen name="stdpadding">16dp</dimen> <dimen name="compact_padding">6dp</dimen> <dimen name="button_radius">20dp</dimen> + <!-- landscape dimens --> + <dimen name="footer_text_padding">20dp</dimen> + <dimen name="splash_text_top_padding">140dp</dimen> + <dimen name="mainbutton_padding">32dp</dimen> + <dimen name="donation_reminder_padding">24dp</dimen> </resources> \ No newline at end of file diff --git a/app/src/main/res/values-ta/strings.xml b/app/src/main/res/values-ta/strings.xml deleted file mode 100644 index 95ac305f3f245bc18736ba577f10e58441e6f553..0000000000000000000000000000000000000000 --- a/app/src/main/res/values-ta/strings.xml +++ /dev/null @@ -1,24 +0,0 @@ -<?xml version='1.0' encoding='UTF-8'?> -<resources> - <string name="retry">மீண்டும் முயற்சிக்கவும்</string> - <string name="switch_provider_menu_option">சேவை வழங்குநரை மாற்று </string> - <string name="info">தகவல்</string> - <string name="show_connection_details">இணைப்பு விவரங்களை காட்டு</string> - <string name="routes_info">வழிகள்: %s</string> - <string name="provider_label">சேவை வழங்குநர்:</string> - <string name="provider_label_none">சேவை வழங்குநர் கட்டமைக்கப்படவில்லை</string> - <string name="introduce_new_provider">புதிய சேவை வழங்குநரை சேர்க்க</string> - <string name="save">சேமி</string> - <string name="username_hint">பயனர் பெயர்</string> - <string name="username_ask">உங்கள் பயனர் பெயரை உள்ளிடுக</string> - <string name="password_hint">கடவுச்சொல்</string> - <string name="about_fragment_title">பற்றி </string> - <string name="login_button">உள்நுழை</string> - <string name="logout_button">வெளியேறு</string> - <string name="setup_error_configure_button">கட்டமைக்க</string> - <string name="setup_error_close_button">வெளியேறுதல்</string> - <string name="authentication_failed_message">அங்கீகரிப்பு தோல்வியுற்றது</string> - <string name="action_settings">அமைப்புகள்</string> - <string name="donate_title">நன்கொடை அளியுங்கள்</string> - <string name="donate_button_donate">நன்கொடை அளியுங்கள்</string> -</resources> diff --git a/app/src/main/res/values-tr/strings.xml b/app/src/main/res/values-tr/strings.xml index 9002b5eb7186517b32a2d43bfb7fad0572c3decc..4e04197498667b8acb49b8f4efa9ebd44df72d0c 100644 --- a/app/src/main/res/values-tr/strings.xml +++ b/app/src/main/res/values-tr/strings.xml @@ -3,7 +3,7 @@ <string name="retry">Yeniden dene</string> <string name="repository_url_text">Kaynak kodlar https://0xacab.org/leap/bitmask_android adresinde bulunabilir.</string> <string name="leap_tracker">Hata izleme sistemi https://0xacab.org/leap/bitmask_android/issues adresinde bulunabilir.</string> - <string name="translation_project_text">Çevirileri minnettarlıkla kabul ederiz. Transifex projemizi https://www.transifex.com/projects/p/bitmask-android/ adresinde bulabilirsiniz.</string> + <string name="translation_project_text">Çevirileri minnettarlıkla kabul ederiz. Transifex projemizi https://www.transifex.com/projects/p/bitmask/ adresinde bulabilirsiniz.</string> <string name="switch_provider_menu_option">Hizmet sağlayıcı değiştir</string> <string name="info">bilgiler</string> <string name="show_connection_details">Bağlantı bilgilerini görüntüle</string> @@ -67,6 +67,9 @@ <string name="authentication_failed_message">Kimlik doğrulanamadı</string> <string name="registration_failed_message">Hesap açılamadı</string> <string name="eip_status_start_pending">Bağlantı kuruluyor</string> + <string name="eip_status_connecting">VPN bağlantısı kuruluyor</string> + <string name="eip_status_unsecured">Güvenli olmayan bağlantı</string> + <string name="eip_status_secured">Güvenli bağlantı</string> <string name="eip_cancel_connect_title">Bağlantı iptal edilsin mi?</string> <string name="eip_cancel_connect_text">Sürmekte olan bir bağlantı kurma girişimi var. İptal etmek istediğinize emin misiniz?</string> <string name="eip.warning.browser_inconsistency">VPN bağlantısını kapatmak istiyor musunuz? VPN kapalıyken, kişisel bilgileriniz Internet hizmeti sağlayıcınıza veya yerel ağınıza sızabilir.</string> @@ -139,7 +142,7 @@ <string name="warning_no_more_gateways_use_pt">%s bağlantı kuramadı. VPN bağlantıları engelleniyor olabilir. Karartılmış bağlantıları kullanarak bağlantı kurmayı denemek ister misiniz?</string> <string name="warning_no_more_gateways_no_pt">%s bağlantı kuramadı. Yeniden denemek ister misiniz?</string> <string name="warning_no_more_gateways_use_ovpn">%s karartılmış VPN bağlantılarını kullanarak bağlantı kuramadı. Standart VPN bağlantıları kullanarak bağlantı kurmayı denemek ister misiniz?</string> - <string name="warning_no_more_gateways_manual_gw_selection">%1$s ile %2$s bağlantısı kurulamadı. Bağlantı en iyi konumdan kurulmaya çalışılsın mı?</string> + <string name="warning_no_more_gateways_manual_gw_selection">%1$s ile %2$s bağlantısı kurulamadı. En iyi konum ile bağlantı kurulmaya çalışılsın mı?</string> <string name="warning_option_try_best">En iyi konum denensin</string> <string name="warning_option_try_pt">Karartılmış bağlantıyı dene</string> <string name="warning_option_try_ovpn">Standart bağlantıyı dene</string> @@ -192,7 +195,7 @@ <string name="prefer_udp">Olabiliyorsa UDP kullanılsın</string> <string name="prefer_udp_subtitle">UDP akışlar için daha iyi ve daha hızlı olabilir, ancak tüm ağlarda çalışmaz.</string> <string name="disabled_while_bridges_on">Köprüler kullanılırken devre dışıdır.</string> - <string name="hint_bridges">Şu an yalnız köprüleri destekleyen konumlar seçilebilir</string> + <string name="hint_bridges">Şu an yalnızca köprüleri destekleyen konumlar seçilebilir</string> <string name="option_disable_bridges">Köprüleri devre dışı bırak</string> <string name="eip_state_insecure">Güvenli olmayan bağlantı</string> <string name="connection_not_connected">Bilgileriniz İnternet hizmeti sağlayıcınıza ya da yerel ağınıza sızıyor olabilir.</string> @@ -201,4 +204,6 @@ <string name="disabled_while_udp_on">UDP açıkken devre dışı.</string> <string name="advanced_settings">Gelişmiş ayarlar</string> <string name="cancel_connection">Bağlantıyı kes</string> + <string name="unknown_location">Konum bilinmiyor</string> + <string name="splash_footer">LEAP tarafından geliştirildi</string> </resources> diff --git a/app/src/main/res/values-ug/strings.xml b/app/src/main/res/values-ug/strings.xml index 4f60030223043f7ed1e03726a8b459001a3c1f1d..746978f8e9e1f336cd87858948e3eab1d7ca7d53 100644 --- a/app/src/main/res/values-ug/strings.xml +++ b/app/src/main/res/values-ug/strings.xml @@ -3,7 +3,8 @@ <string name="retry">قايتا سىناڭ</string> <string name="repository_url_text">ئەسلى كودى بۇ يەردە https://0xacab.org/leap/bitmask_android</string> <string name="leap_tracker">مەسىلە ئىز قوغلىغۇچى بۇ يەردە https://0xacab.org/leap/bitmask_android/issues</string> - <string name="translation_project_text">تەرجىمىلەرنى قارشى ئالىمىز ۋە رەھمەت ئېيتىمىز. بىزنىڭ Transifex تۈرىمىزنى كۆرۈش ئۈچۈن بۇ يەرگە قاراڭ https://www.transifex.com/projects/p/bitmask-android/</string> + <string name="translation_project_text">تەرجىمىلەرنى قارشى ئالىمىز ۋە رەھمەت ئېيتىمىز. بىزنىڭ Transifex تۈرىمىزنى كۆرۈش ئۈچۈن بۇ يەرگە قاراڭ +https://www.transifex.com/projects/p/bitmask/</string> <string name="switch_provider_menu_option">تەمىنلىگۈچىنى ئالماشتۇرۇش</string> <string name="info">ئۇچۇر</string> <string name="show_connection_details">باغلانمىنىڭ تەپسىلاتىنى كۆرسەت</string> @@ -149,6 +150,7 @@ <string name="version_update_error">يېڭىلاش مەغلۇپ بولدى</string> <string name="version_update_error_permissions">بۇ ئەپنى قاچىلاشقا ھوقۇقىڭىز يوق</string> <string name="gateway_selection_title">ئورنىڭىزنى تاللاڭ</string> + <string name="gateway_selection_recommended">تەۋسىيە</string> <string name="gateway_selection_automatic">ئاپتۇماتىك</string> <string name="log_done">ئىجرا قىلىنىۋاتىدۇ</string> <string name="hide">يوشۇر</string> diff --git a/app/src/main/res/values-uk/strings.xml b/app/src/main/res/values-uk/strings.xml index 5c88a8e37a37a2ef8b890f69dff5928aae5407f0..3497915382595370a1a71da6942bfa98b1689a14 100644 --- a/app/src/main/res/values-uk/strings.xml +++ b/app/src/main/res/values-uk/strings.xml @@ -15,6 +15,7 @@ <string name="about_fragment_title">Про</string> <string name="error_bad_user_password_user_message">Неправильний логін або пароль</string> <string name="login_button">Вхід у систему</string> + <string name="logout_button">Вийти</string> <string name="setup_error_configure_button">Налаштування</string> <string name="setup_error_close_button">Вихід</string> <string name="succesful_authentication_message">Автентифіковано</string> @@ -26,7 +27,18 @@ <string name="navigation_drawer_close">Закрити панель навігації</string> <string name="action_settings">Налаштування</string> <string name="always_on_vpn">Завжди-VPN</string> + <string name="tethering_wifi">Точка доступу Wi-Fi</string> <string name="donate_title">Пожертвування</string> <string name="donate_button_remind_later">Нагадайте мені пізніше</string> <string name="donate_button_donate">Пожертвування</string> + <string name="nav_drawer_obfuscated_connection">Використати Мости</string> + <string name="gateway_selection_automatic">Автоматично</string> + <string name="log_onehop_create">Встановлення зашифрованого з\'єднання до каталогу</string> + <string name="log_loading_keys">Завантаження сертифікатів авторизації</string> + <string name="log_circuit_create">Створення ланцюга Tor </string> + <string name="log_done">Запуск</string> + <string name="hide">Приховати</string> + <string name="use_snowflake">Використовувати Snowflake</string> + <string name="advanced_settings">Додаткові налаштування</string> + <string name="cancel_connection">Від\'єднати</string> </resources> diff --git a/app/src/main/res/values-v31/themes.xml b/app/src/main/res/values-v31/themes.xml new file mode 100644 index 0000000000000000000000000000000000000000..81d6c19eb52c8cbfad091e48370f1f92b902ba0e --- /dev/null +++ b/app/src/main/res/values-v31/themes.xml @@ -0,0 +1,8 @@ +<?xml version="1.0" encoding="utf-8"?> +<resources> + <style name="SplashTheme" parent="Theme.AppCompat.NoActionBar"> + <item name="android:windowSplashScreenBackground">@color/colorPrimary</item> + <item name="android:windowSplashScreenAnimatedIcon">@drawable/splash_icon</item> + <item name="android:windowSplashScreenBrandingImage">@drawable/splash_branding</item> + </style> +</resources> \ No newline at end of file diff --git a/app/src/main/res/values-vi/strings.xml b/app/src/main/res/values-vi/strings.xml index b6abbcddaeb19b1edc0f6079fa6bc4888baa5cdc..2ca41f674811b48ae35efb6cf4488f871d0530a0 100644 --- a/app/src/main/res/values-vi/strings.xml +++ b/app/src/main/res/values-vi/strings.xml @@ -3,7 +3,7 @@ <string name="retry">Thử lại</string> <string name="repository_url_text">Mã nguồn có ở https://0xacab.org/leap/bitmask_android</string> <string name="leap_tracker">Trình theo dõi vấn đề có ở https://0xacab.org/leap/bitmask_android/issues</string> - <string name="translation_project_text">Các bản dịch được chào đón và đánh giá cao. Hãy xem dự án Transifex của chúng tôi ở https://www.transifex.com/projects/p/bitmask-android/</string> + <string name="translation_project_text">Các bản dịch được chào đón và đánh giá cao. Hãy xem dự án Transifex của chúng tôi ở https://www.transifex.com/projects/p/bitmask/</string> <string name="switch_provider_menu_option">Chuyển nhà cung cấp</string> <string name="info">thông tin</string> <string name="show_connection_details">Hiện chi tiết kết nối</string> @@ -52,6 +52,7 @@ <string name="setup_error_configure_button">Thiết lập</string> <string name="setup_error_close_button">Thoát</string> <string name="setup_error_text">Đã xảy ra lỗi khi thiết lập %s với nhà cung cấp đã chọn.\n\nBạn có thể chọn thiết lập lại, hoặc thoát và thiết lập một nhà cung cấp vào lần khởi động sau.</string> + <string name="setup_error_text_custom">Có lỗi khi thiết lập %s.\n\nBạn có thể chọn thiết lập lại hoặc thoát.</string> <string name="server_unreachable_message">Máy chủ không thể kết nối đến được, vui lòng thử lại.</string> <string name="error.security.pinnedcertificate">Lỗi bảo mật, hãy nâng cấp ứng dụng hoặc chọn một nhà cung cấp khác.</string> <string name="malformed_url">Nó không có vẻ là một nhà cung cấp %s.</string> diff --git a/app/src/main/res/values-w820dp/dimens.xml b/app/src/main/res/values-w820dp/dimens.xml index 94bd0ff2e3a68326456c06e84d7a48590e04f554..822259cafc0338a358bc40c1222d88580782c9c0 100644 --- a/app/src/main/res/values-w820dp/dimens.xml +++ b/app/src/main/res/values-w820dp/dimens.xml @@ -8,5 +8,10 @@ <dimen name="compact_padding">6dp</dimen> <dimen name="stdpadding">16dp</dimen> <dimen name="button_radius">20dp</dimen> + <!-- landscape dimens --> + <dimen name="footer_text_padding">12dp</dimen> + <dimen name="splash_text_top_padding">90dp</dimen> + <dimen name="mainbutton_padding">32dp</dimen> + <dimen name="donation_reminder_padding">24dp</dimen> </resources> diff --git a/app/src/main/res/values-zh-rCN/strings.xml b/app/src/main/res/values-zh-rCN/strings.xml index c4f0e1258ffd366724dec593d2b0f258e7a44950..9279450dd07eacf164412fa1da1da601c3b7e776 100644 --- a/app/src/main/res/values-zh-rCN/strings.xml +++ b/app/src/main/res/values-zh-rCN/strings.xml @@ -1,71 +1,208 @@ <?xml version='1.0' encoding='UTF-8'?> <resources> <string name="retry">重试</string> - <string name="repository_url_text">源代码在 https://0xacab.org/leap/bitmask_android 开源可用</string> - <string name="leap_tracker">如果在使用过程中遇到问题,可用到跟踪器 https://0xacab.org/leap/bitmask_android/issues 提交</string> - <string name="translation_project_text">欢迎并赞赏翻译者,在 https://www.transifex.com/projects/p/bitmask-android/ 帮助我们翻译</string> + <string name="repository_url_text">源代码可在 https://0xacab.org/leap/bitmask_android 找到</string> + <string name="leap_tracker">问题追踪器可在 https://0xacab.org/leap/bitmask_android/issues 找到</string> + <string name="translation_project_text">我们鼓励并感谢诸位提供翻译。请在 https://www.transifex.com/projects/p/bitmask/ 参阅我们的 Transifex 项目</string> <string name="switch_provider_menu_option">切换提供商</string> <string name="info">信息</string> - <string name="show_connection_details">显示连接信息</string> - <string name="routes_info">IPv4 路由: %s</string> - <string name="routes_info6">IPv6路由 1%s</string> + <string name="show_connection_details">显示连接详情</string> + <string name="connection_details">连接详情</string> + <string name="routes_info">路由:%s</string> + <string name="routes_info6">IPv6 路由:%s</string> <string name="error_empty_username">用户名不能为空。</string> - <string name="cert_from_keystore">从密钥库获得证书 1%s</string> - <string name="provider_label">提供者:</string> - <string name="provider_label_none">没有已配置的提供者</string> + <string name="cert_from_keystore">获取来自密钥库“%s”证书</string> + <string name="provider_label">提供商:</string> + <string name="provider_label_none">未配置提供商</string> <string name="status_unknown">状态未知。</string> - <string name="eip_service_label">加密的VPN网络访问</string> - <string name="configuration_wizard_title">选择一个服务提供商</string> - <string name="add_provider">添加新的提供者</string> - <string name="introduce_new_provider">添加新的服务提供者</string> + <string name="eip_service_label">接入互联网的加密 VPN</string> + <string name="configuration_wizard_title">选择服务提供商</string> + <string name="add_provider">添加新提供商</string> + <string name="introduce_new_provider">添加新服务提供商</string> <string name="save">保存</string> - <string name="new_provider_uri">域名称</string> - <string name="valid_url_entered">无效的URL</string> - <string name="not_valid_url_entered">异常的URL</string> - <string name="provider_details_title">供应者信息</string> + <string name="new_provider_uri">域名</string> + <string name="valid_url_entered">输入的 URL 有效</string> + <string name="not_valid_url_entered">畸形 URL</string> + <string name="provider_details_title">提供商详情</string> <string name="use_anonymously_button">匿名使用</string> <string name="username_hint">用户名</string> <string name="username_ask">请输入您的用户名</string> <string name="password_ask">请输入您的密码</string> <string name="password_hint">密码</string> - <string name="password_match">密码与您的账户不匹配</string> - <string name="password_mismatch">密码错误</string> - <string name="user_message">用户密码</string> + <string name="password_match">密码匹配</string> + <string name="password_mismatch">密码不匹配</string> + <string name="user_message">用户消息</string> <string name="about_fragment_title">关于</string> - <string name="error_bad_user_password_user_message">用户名或密码无效</string> + <string name="exclude_apps_fragment_title">VPN 应用例外</string> + <string name="error_srp_math_error_user_message">请重试:服务器计算错误</string> + <string name="error_bad_user_password_user_message">密码或用户名错误</string> + <string name="error_not_valid_password_user_message">密码长度必须至少要 8 个字符</string> <string name="error_client_http_user_message">请重试:客户端 HTTP 错误</string> <string name="error_io_exception_user_message">请重试:I/O 错误</string> - <string name="error_json_exception_user_message">请重试:服务器的响应不正确</string> + <string name="error_json_exception_user_message">请重试:服务器无响应</string> + <string name="error_no_such_algorithm_exception_user_message">加密算法未找到。请升级 Android!</string> + <string name="signup_or_login_button">注册/登录</string> <string name="login_button">登录</string> + <string name="login_to_profile">登录配置</string> <string name="logout_button">退出</string> <string name="signup_button">注册</string> + <string name="create_profile">创建配置</string> + <string name="setup_provider">设置提供商</string> <string name="setup_error_title">配置错误</string> <string name="setup_error_configure_button">配置</string> <string name="setup_error_close_button">退出</string> - <string name="configuring_provider">正在配置提供者</string> - <string name="succesful_authentication_message">身份已验证</string> + <string name="setup_error_text">您所选择的提供商 %s 配置错误。\n\n您可选择重新配置,或退出并在下次启动时配置提供商。</string> + <string name="setup_error_text_custom">错误配置 %s 。\n\n您可选择重新配置或退出。</string> + <string name="server_unreachable_message">无法访问服务器,请重试。</string> + <string name="error.security.pinnedcertificate">安全错误,升级应用或选择其他提供商。</string> + <string name="malformed_url">这似乎不是一个 %s 提供商。</string> + <string name="certificate_error">这不是一个信任 %s 提供商。</string> + <string name="service_is_down_error">此服务已下线。</string> + <string name="configuring_provider">正在配置提供商</string> + <string name="incorrectly_downloaded_certificate_message">您的匿名证书未被下载</string> + <string name="downloading_certificate_message">正在下载 VPN 证书</string> + <string name="updating_certificate_message">正在更新 VPN 证书</string> + <string name="login.riseup.warning">使用此 VPN 服务的 Riseup 用户需要创建一个单独的账号</string> + <string name="succesful_authentication_message">已验证</string> <string name="authentication_failed_message">认证失败</string> - <string name="eip_status_start_pending">正在发起连接</string> + <string name="registration_failed_message">注册失败</string> + <string name="eip_status_start_pending">正在初始化连接</string> + <string name="eip_status_connecting">正在连接 VPN</string> + <string name="eip_status_unsecured">不安全连接</string> + <string name="eip_status_secured">安全连接</string> <string name="eip_cancel_connect_title">取消连接?</string> - <string name="eip_cancel_connect_text">目前正在尝试连接。您想取消吗?</string> + <string name="eip_cancel_connect_text">尝试连接中。您希望取消吗?</string> + <string name="eip.warning.browser_inconsistency">是否关闭 VPN 连接?关闭 VPN 可能会造成向您的互联网提供商或本地网络泄露个人信息的后果。</string> + <string name="eip_state_not_connected">未运行!不安全连接!</string> + <string name="eip_state_connected">连接不安全</string> + <string name="provider_problem">提供商似乎出了问题。</string> + <string name="try_another_provider">请尝试使用其他提供商,或联系您的提供商。</string> <string name="default_username">匿名</string> <string name="logging_in">正在登录</string> + <string name="signing_up">正在注册</string> + <string name="vpn.button.turn.on">开启</string> + <string name="vpn.button.turn.off">关闭</string> + <string name="vpn_button_turn_off_blocking">停止屏蔽</string> + <string name="vpn_securely_routed">您的流量安全地途经:</string> + <string name="vpn_securely_routed_no_internet">未检测到互联网连接,连接恢复时将安全地代理您的流量:</string> <string name="log_fragment_title">日志</string> - <string name="navigation_drawer_open">开启导航抽屉</string> - <string name="navigation_drawer_close">关闭导航抽屉</string> + <string name="vpn_fragment_title">VPN</string> + <string name="navigation_drawer_open">打开导航栏</string> + <string name="navigation_drawer_close">关闭导航栏</string> + <string name="action_example">示范操作</string> <string name="action_settings">设置</string> - <string name="donate_title">捐款</string> - <string name="donate_button_donate">捐款</string> + <string name="void_vpn_establish">%s 屏蔽所有出站网络流量。</string> + <string name="void_vpn_error_establish">屏蔽所有互联网流量失败。</string> + <string name="void_vpn_stopped">已停止屏蔽所有出站网络流量。</string> + <string name="void_vpn_title">正在屏蔽流量</string> + <string name="update_provider_details">更新提供商详情</string> + <string name="update_certificate">更新证书</string> + <string name="warning_eip_json_corrupted">更新服务商配置失败。</string> + <string name="eip_json_corrupted_user_message">更新服务商配置失败。请登录后再试。</string> + <string name="warning_client_parsing_error_gateways">无法识别提供商网关。网关配置可能不正确。</string> + <string name="warning_corrupted_provider_details">存储的提供商详情已损坏。您可以更新 %s(推荐),或更新使用商业 CA 证书的提供商详情。</string> + <string name="warning_corrupted_provider_cert">存储的提供商证书无效。您可以更新 %s(推荐),或更新使用商业 CA 证书的提供商详情。</string> + <string name="warning_expired_provider_cert">存储的提供商证书过期。您可以更新 %s(推荐),或更新使用商业 CA 证书的提供商详情。</string> + <string name="downloading_vpn_certificate_failed">下载 VPN 证书失败。请重试或选择其他提供商。</string> + <string name="vpn_certificate_is_invalid">VPN 证书无效。尝试下载新的证书。</string> + <string name="vpn_certificate_user_message">VPN 证书无效。请登录后下载新证书。</string> + <string name="save_battery">省电模式</string> + <string name="subtitle_save_battery"> VPN 热点开启时禁用。</string> + <string name="save_battery_message">您的手机锁屏时,后台数据连接处于休眠状态。</string> + <string name="always_on_vpn">始终开启的 VPN</string> + <string name="subtitle_always_on_vpn">打开 Android 系统设置</string> + <string name="tethering">VPN 热点</string> + <string name="ipv6Firewall">屏蔽 IPv6</string> + <string name="require_root">需要 Root 权限</string> + <string name="show_experimental">显示实验性功能</string> + <string name="hide_experimental">隐藏实验性功能</string> + <string name="experimental_features">实验性功能</string> + <string name="tethering_enabled_message">请先确保在<![CDATA[<b>系统设置</b>]]>启用网络共享。</string> + <string name="tethering_message">通过以下方式与其他设备分享您的 VPN:</string> + <string name="tethering_wifi">Wi-Fi 热点</string> + <string name="tethering_usb">USB 网络共享</string> + <string name="tethering_bluetooth">蓝牙网络共享</string> + <string name="do_not_show_again">不再显示</string> + <string name="always_on_vpn_user_message">在 Android 的 VPN 设置中点击配置图标 [img src] 并启用始终开启的 VPN 开启。</string> + <string name="always_on_blocking_vpn_user_message">为最大程度保障您的隐私,您也应当启用“屏蔽未使用 VPN 的所有连接”选项。</string> + <string name="donate_title">捐助</string> + <string name="donate_default_message">如果您重视为终端用户和服务提供商双方提供便捷的安全通信,请捐助此服务。</string> + <string name="donate_message">LEAP 的运作依赖捐赠和补助。如果您重视为终端用户和服务提供商双方提供便捷的安全通信,请捐助此服务。</string> + <string name="donate_button_remind_later">稍后提醒</string> + <string name="donate_button_donate">捐助</string> + <string name="obfuscated_connection">正在使用混淆连接。</string> + <string name="obfuscated_connection_try">正在尝试混淆连接。</string> <string name="nav_drawer_obfuscated_connection">使用网桥</string> + <string name="nav_drawer_subtitle_obfuscated_connection">规避 VPN 过滤</string> + <string name="warning_exclude_apps_message">请小心 VPN 例外应用。这些应用会泄露您的身份,从而让您在安全问题上作出让步。</string> + <plurals name="subtitle_exclude_apps"> + <item quantity="other">%d 未保护应用</item> + </plurals> + <string name="warning_no_more_gateways_use_pt">%s 无法连接。VPN 连接可能被屏蔽。您是否想使用混淆连接再试?</string> + <string name="warning_no_more_gateways_no_pt">%s 无法连接。您是否想再试?</string> + <string name="warning_no_more_gateways_use_ovpn">%s 无法使用混淆 VPN 连接。您是否想使用标准 VPN 再试?</string> + <string name="warning_no_more_gateways_manual_gw_selection">%1$s 无法连接至 %2$s。您是否想自动连接至最佳位置再试?</string> + <string name="warning_option_try_best">尝试最佳位置</string> + <string name="warning_option_try_pt">尝试混淆连接</string> + <string name="warning_option_try_ovpn">尝试标准连接</string> + <string name="vpn_error_establish">Android 建立 VPN 服务失败。</string> + <string name="root_permission_error">若无 Root 权限,像是 VPN 热点或 IPv6 防火墙的 %s 功能无法使用。</string> + <string name="qs_enable_vpn">启动 %s</string> + <string name="version_update_found">点击这里开始下载。</string> + <string name="version_update_title">已发现新版本 %s。</string> + <string name="version_update_apk_description">正在下载新版本 %s</string> + <string name="version_update_download_title">新版本 %s 已下载。</string> + <string name="version_update_download_description">点击这里安装更新。</string> + <string name="version_update_error_pgp_verification">PGP 验证错误。正在忽略下载。</string> + <string name="version_update_error">升级失败。</string> + <string name="version_update_error_permissions">没有安装应用的权限。</string> <string name="gateway_selection_title">选择位置</string> - <string name="gateway_selection_recommended">(推荐)</string> + <string name="gateway_selection_recommended_location">推荐位置</string> + <string name="gateway_selection_recommended">推荐</string> + <string name="gateway_selection_manually">手动选择</string> + <string name="gateway_selection_automatic_location">自动使用最佳连接</string> <string name="gateway_selection_automatic">自动</string> - <string name="log_onehop_create">正在建立加密的目录连接</string> - <string name="log_loading_keys">正在载入证书颁发机构证书</string> - <string name="log_circuit_create">正在建立 Tor 线路</string> + <string name="reconnecting">正在重新连接…</string> + <string name="tor_starting">正在启用用于审查规避的网桥…</string> + <string name="tor_stopping">正在关闭网桥</string> + <string name="tor_started">正在使用用于审查规避的网桥</string> + <string name="log_conn_done_pt">已连接可插拔传输</string> + <string name="log_conn_pt">正在连接可插拔传输</string> + <string name="log_conn_done">已连接中继</string> + <string name="log_handshake">正在与中继协商连接</string> + <string name="log_handshake_done">与中继协商连接完成</string> + <string name="log_onehop_create">正在建立加密目录连接</string> + <string name="log_requesting_status">正在请求网络状态一致性</string> + <string name="log_loading_status">正在加载网络状态一致性</string> + <string name="log_loading_keys">正在加载颁发机构发放的证书</string> + <string name="log_requesting_descriptors">正在请求中继描述符</string> + <string name="log_loading_descriptors">正在加载中继描述符</string> + <string name="log_enough_dirinfo">已加载足以用于构建链路的目录信息</string> + <string name="log_ap_handshake_done">与用于构建链路的中继协商完成</string> + <string name="log_circuit_create">正在建立 Tor 链路</string> <string name="log_done">正在运行</string> + <string name="channel_name_tor_service">%s 网桥服务</string> + <string name="channel_description_tor_service">配置 %s 时告知有关网桥的使用情况。</string> + <string name="error_tor_timeout">启动网桥失败。您是否想重试或继续使用未经混淆的安全连接来配置 %s?</string> + <string name="retry_unobfuscated">重试未经混淆的连接</string> <string name="hide">隐藏</string> + <string name="error_network_connection">%s 未连网。请检查您的 WiFi 和移动数据设置。</string> + <string name="censorship_circumvention">审查规避</string> <string name="use_snowflake">使用 Snowflake</string> - <string name="advanced_settings">进阶设置</string> - <string name="cancel_connection">断开</string> + <string name="snowflake_description">保护对抗审查的配置进程。</string> + <string name="vpn_settings">VPN 设置</string> + <string name="prefer_udp">可用时使用 UDP</string> + <string name="prefer_udp_subtitle">UDP 对直播更快更好,但并非对所有网络可用。</string> + <string name="disabled_while_bridges_on">使用网桥时禁用。</string> + <string name="hint_bridges">目前仅支持网桥的位置可供选择。</string> + <string name="option_disable_bridges">禁用网桥</string> + <string name="eip_state_insecure">连接不安全</string> + <string name="connection_not_connected">您可能会向您的互联网提供商或本地网络泄露信息。</string> + <string name="eip_state_no_network">您未正常联网。网络恢复后将自动连接。</string> + <string name="eip_state_blocking">%1$s 正在屏蔽所有互联网流量。</string> + <string name="disabled_while_udp_on">UDP 开启时禁用。</string> + <string name="advanced_settings">高级设置</string> + <string name="cancel_connection">中断连接</string> + <string name="unknown_location">未知位置</string> + <string name="splash_footer">由 LEAP 开发</string> </resources> diff --git a/app/src/main/res/values-zh-rTW/strings.xml b/app/src/main/res/values-zh-rTW/strings.xml index 2fff635b6cdc09ba445c742d01ac1523850d293a..fc0eeadd00839e529f550ba0af24a7467c79468f 100644 --- a/app/src/main/res/values-zh-rTW/strings.xml +++ b/app/src/main/res/values-zh-rTW/strings.xml @@ -15,17 +15,34 @@ <string name="about_fragment_title">關於</string> <string name="error_bad_user_password_user_message">不正確的用戶帳號和密碼</string> <string name="login_button">登入</string> + <string name="logout_button">登出</string> <string name="signup_button">註冊</string> <string name="setup_error_configure_button">設定</string> <string name="setup_error_close_button">離開</string> <string name="succesful_authentication_message">已驗證</string> <string name="authentication_failed_message">認證失敗</string> <string name="default_username">匿名</string> + <string name="vpn.button.turn.on">開啟</string> + <string name="vpn.button.turn.off">關閉</string> <string name="log_fragment_title">日誌</string> <string name="vpn_fragment_title">VPN</string> <string name="navigation_drawer_open">開啟導航抽屜</string> <string name="navigation_drawer_close">關閉導航抽屜</string> <string name="action_settings">設定</string> + <string name="always_on_vpn">一直啟用 VPN</string> <string name="donate_title">捐贈</string> <string name="donate_button_donate">捐贈</string> + <string name="nav_drawer_obfuscated_connection">使用網橋</string> + <string name="gateway_selection_recommended">(建議)</string> + <string name="gateway_selection_manually">手動選擇</string> + <string name="gateway_selection_automatic_location">自動使用最佳的連線</string> + <string name="gateway_selection_automatic">竹</string> + <string name="log_onehop_create">正在建立加密的目錄連線</string> + <string name="log_loading_keys">正在載入授權憑證</string> + <string name="log_circuit_create">正在建立洋蔥路由迴路</string> + <string name="log_done">執行</string> + <string name="hide">隱藏</string> + <string name="use_snowflake">使用 Snowflake</string> + <string name="advanced_settings">進階設定</string> + <string name="cancel_connection">中斷連缐</string> </resources> diff --git a/app/src/main/res/values/colors.xml b/app/src/main/res/values/colors.xml index 792db1ee09dc678110b4cef4ec5a0166a9d5fcdc..3e33c72bff24711e9ce51e66523352019dfc28e0 100644 --- a/app/src/main/res/values/colors.xml +++ b/app/src/main/res/values/colors.xml @@ -10,10 +10,13 @@ <color name="colorMainBtnHighlight">#03DAC6</color> <color name="colorMainBtnError">#eF2222</color> + <color name="black">#000000</color> + <color name="black800_dark">#1b1b1b</color> <color name="black800">#424242</color> <color name="black800_secondary">#3b3b3b</color> <color name="black800_transparent">#AA424242</color> <color name="black800_high_transparent">#22424242</color> + <color name="transparent">#00000000</color> <color name="red200">#ef9a9a</color> <color name="pink200">#f48fb1</color> @@ -31,18 +34,50 @@ <color name="amber200">#ffe082</color> <color name="orange200">#ffcc80</color> <color name="deepOrange200">#ffab91</color> - <color name="white">#ffffff</color> <color name="white_transparent">#20ffffff</color> <color name="black_transparent">#20000000</color> + <color name="black_high_transparent">#05000000</color> - <color name="colorActionBarTitleFont">@color/white</color> - <color name="colorActionBarSubtitleFont">@color/black800</color> - <color name="colorEipFragmentFont">@color/black800</color> - <color name="colorFontBtn">@color/black800</color> - <color name="colorFontBtnEnabled">@color/white</color> - <color name="colorLocationButtonTint">@color/black800</color> + <color name="colorEipFragmentFont">@color/black800_dark</color> + <!-- button text colors in Alerts etc. --> + <color name="color_font_btn">@color/black800</color> + <!-- pill style button text colors --> + <color name="color_font_btn_primary">@color/black800</color> + <color name="color_font_btn_secondary">@color/black800</color> + <color name="colorLocationButtonTint">@color/black</color> <color name="colorLocationButtonTintTransparent">@color/black800_high_transparent</color> <color name="colorWarning">#B33A3A</color> + <!-- main UI on/off button colors --> + <color name="btn_start">#FF7D7D</color> + <color name="btn_start_dark">#c84c51</color> + <color name="btn_cancel">#FFBF00</color> + <color name="btn_cancel_dark">#C78F00</color> + <color name="btn_stop">#9FC17F</color> + <color name="btn_stop_dark">#709152</color> + + <!-- location button background colors --> + <color name="btn_light_transparent">#CCFFFEFE</color> + <color name="btn_light_transparent_dark">#CCCCCBCB</color> + + <!-- main UI background colors --> + <color name="bg_disconnected">#DC6F6B</color> + <color name="bg_connecting">#FADD85</color> + <color name="bg_running">#CCDCB8</color> + + <!-- actionbar and status bar colors for different connection states --> + <color name="bg_disconnected_top">#EC6767</color> + <color name="bg_disconnected_top_light_transparent">#CCff9895</color> + <color name="bg_connecting_top">#FADD85</color> + <color name="bg_connecting_top_light_transparent">#CCffffb6</color> + <color name="bg_running_top">#CCDCB8</color> + <color name="bg_running_top_light_transparent">#ffffea</color> + + <!-- action bar text colors for per state colored action bar --> + <color name="actionbar_connectivity_state_text_color_dark">@color/black800</color> + <color name="actionbar_connectivity_state_text_color_light">@color/white</color> + <!-- default action bar colors used in other fragments than EipFragment --> + <color name="colorActionBarTitleFont">@color/white</color> + <color name="colorActionBarSubtitleFont">@color/black800</color> </resources> diff --git a/app/src/main/res/values/dimens.xml b/app/src/main/res/values/dimens.xml index 3adf6cf69fef223f046c46bb9581d2f97140404c..f15fbcf95868d2e3c9c09ef5fa7b6b4634c9b9fa 100644 --- a/app/src/main/res/values/dimens.xml +++ b/app/src/main/res/values/dimens.xml @@ -8,8 +8,10 @@ <dimen name="stdpadding">8dp</dimen> <dimen name="compact_padding">3dp</dimen> <dimen name="standard_margin">8dp</dimen> - <dimen name="mainbutton_padding">20dp</dimen> <bool name="logSildersAlwaysVisible">false</bool> + <!-- landscape layout dimens --> + <dimen name="footer_text_padding">12dp</dimen> + <dimen name="splash_text_top_padding">80dp</dimen> <dimen name="diameter">48dp</dimen> <dimen name="elevation_low">1dp</dimen> @@ -43,4 +45,7 @@ <dimen name="toast_bottom_padding">20dp</dimen> <dimen name="button_bevel">3dp</dimen> <dimen name="button_radius">16dp</dimen> + <dimen name="mainbutton_padding">8dp</dimen> + <dimen name="donation_reminder_padding">8dp</dimen> + </resources> \ No newline at end of file diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml index d1f032883a9e9f691d95055f73b85e4e4f1e9818..cb9a843b7bf910eb0eafaaeb5688deffa20a7017 100644 --- a/app/src/main/res/values/strings.xml +++ b/app/src/main/res/values/strings.xml @@ -3,7 +3,7 @@ <string name="retry">Retry</string> <string name="repository_url_text">Source code available at https://0xacab.org/leap/bitmask_android</string> <string name="leap_tracker">Issue tracker available at https://0xacab.org/leap/bitmask_android/issues</string> - <string name="translation_project_text">Translations welcome and appreciated. See our Transifex project at https://www.transifex.com/projects/p/bitmask-android/</string> + <string name="translation_project_text">Translations welcome and appreciated. See our Transifex project at https://www.transifex.com/projects/p/bitmask/</string> <string name="switch_provider_menu_option">Switch provider</string> <string name="info">info</string> <string name="show_connection_details">Show connection details</string> @@ -67,6 +67,9 @@ <string name="authentication_failed_message">Authentication failed</string> <string name="registration_failed_message">Registration failed</string> <string name="eip_status_start_pending">Initiating connection</string> + <string name="eip_status_connecting">Connecting VPN</string> + <string name="eip_status_unsecured">Unsecured Connection</string> + <string name="eip_status_secured">Secured Connection</string> <string name="eip_cancel_connect_title">Cancel connection?</string> <string name="eip_cancel_connect_text">There is a connection attempt in progress. Do you wish to cancel it?</string> <string name="eip.warning.browser_inconsistency">Turn off VPN connection? When the VPN is off, you may leak personal information to your Internet provider or local network.</string> @@ -139,7 +142,7 @@ <string name="warning_no_more_gateways_use_pt">%s could not connect. It might be that VPN connections get blocked. Do you want to try to connect using obfuscated connections?</string> <string name="warning_no_more_gateways_no_pt">%s could not connect. Do you want to retry?</string> <string name="warning_no_more_gateways_use_ovpn">%s could not connect using obfuscated VPN connections. Do you want to try to connect using a standard VPN?</string> - <string name="warning_no_more_gateways_manual_gw_selection">%1$s could not connect to %2$s. Do you want to try to connect automatically with best location?</string> + <string name="warning_no_more_gateways_manual_gw_selection">%1$s could not connect to %2$s. Do you want to try to connect automatically to the best location?</string> <string name="warning_option_try_best">Try best location</string> <string name="warning_option_try_pt">Try obfuscated connection</string> <string name="warning_option_try_ovpn">Try standard connection</string> @@ -195,11 +198,12 @@ <string name="hint_bridges">Only locations supporting bridges are currently selectable.</string> <string name="option_disable_bridges">Disable bridges</string> <string name="eip_state_insecure">Connection insecure</string> - <string name="connection_not_connected" >You may be leaking information to your internet provider or local network.</string> + <string name="connection_not_connected">You may be leaking information to your internet provider or local network.</string> <string name="eip_state_no_network">You have no working Internet connection. Once you get it back, you will be automatically connected to</string> <string name="eip_state_blocking">%1$s is blocking all internet traffic.</string> <string name="disabled_while_udp_on">Disabled while UDP is on.</string> <string name="advanced_settings">Advanced settings</string> <string name="cancel_connection">Disconnect</string> - + <string name="unknown_location">Unknown location</string> + <string name="splash_footer">Developed by LEAP</string> </resources> diff --git a/app/src/main/res/values/styles.xml b/app/src/main/res/values/styles.xml index 9b05d3feea515db6137c9638bec5a53c90a87502..f42be3c1ce31a13520332a55f3d21ee6a29e29e6 100644 --- a/app/src/main/res/values/styles.xml +++ b/app/src/main/res/values/styles.xml @@ -65,7 +65,7 @@ <item name="android:background">@drawable/cust_button_primary</item> <item name="android:height">36dp</item> <item name="android:minWidth">75dp</item> - <item name="android:textColor">@color/colorFontBtn</item> + <item name="android:textColor">@color/color_font_btn</item> </style> <style name="BitmaskActivity"> diff --git a/app/src/main/res/values/untranslatable.xml b/app/src/main/res/values/untranslatable.xml index 6e1f475990923008abeffbfff7f2f91eaeb89a4c..957788a5c380358c27d06b21d1a1c67591ebea15 100644 --- a/app/src/main/res/values/untranslatable.xml +++ b/app/src/main/res/values/untranslatable.xml @@ -1,7 +1,7 @@ <?xml version="1.0" encoding="utf-8"?> <resources> <string name="notifcation_title_bitmask" translatable="false">%s - %s</string> - <string name="copyright_leapgui" translatable="false">Copyright (c) 2012-2020\nLEAP Encryption Access Project <info@leap.se></string> + <string name="copyright_leapgui" translatable="false">Copyright (c) 2012-2022\nLEAP Encryption Access Project <info@leap.se></string> <string name="opevpn_copyright" translatable="false">Copyright (c) 2002-2019 OpenVPN Technologies, Inc. <sales@openvpn.net>\n "OpenVPN" is a trademark of OpenVPN Technologies, Inc.</string> <string name="lzo_copyright" translatable="false">Copyright (c) 1996 - 2011 Markus Franz Xaver Johannes Oberhumer</string> @@ -55,4 +55,4 @@ <!-- gateway selector, move to strings.xml, once the wording is clear --> <string name="no_location" translatable="false">---</string> -</resources> \ No newline at end of file +</resources> diff --git a/app/src/normal/assets/calyx.net.json b/app/src/normal/assets/calyx.net.json index e3680dee26c305e96ba789045b390a10d0bacd31..876fdaab3ebc50d880adb88a5300d0b705ad6023 100644 --- a/app/src/normal/assets/calyx.net.json +++ b/app/src/normal/assets/calyx.net.json @@ -1,7 +1,7 @@ { "api_uri": "https://api.calyx.net:4430", - "api_version": "1", - "ca_cert_fingerprint": "SHA256: b2ae8b075a0e5634160c4dceec2e651dfabf9e4ea9409cc896cd2e1054c92372", + "api_version": "3", + "ca_cert_fingerprint": "SHA256: 43683c9ba3862c5384a8c1885072fcac40b5d2d4dd67331443f13a3077fa2e69", "ca_cert_uri": "https://calyx.net/ca.crt", "default_language": "en", "description": { @@ -20,7 +20,7 @@ "allow_free": true, "allow_limited_bandwidth": false, "allow_paid": false, - "allow_registration": true, + "allow_registration": false, "allow_unlimited_bandwidth": true, "bandwidth_limit": 102400, "default_service_level": 1, diff --git a/app/src/normal/assets/riseup.net.json b/app/src/normal/assets/riseup.net.json index b72091b4c737bd822f327f7f1fca1f418e6ec62f..ef76482722a46a5d90dafb8aeb2d6e3e79474d3b 100644 --- a/app/src/normal/assets/riseup.net.json +++ b/app/src/normal/assets/riseup.net.json @@ -1,14 +1,14 @@ { "api_uri": "https://api.black.riseup.net:443", "api_version": "3", - "ca_cert_fingerprint": "SHA256: dd919b7513b4a1368faa20e38cd3314156805677f48b787cdd9b4a92dec64eb0", + "ca_cert_fingerprint": "SHA256: a5244308a1374709a9afce95e3ae47c1b44bc2398c0a70ccbf8b3a8a97f29494", "ca_cert_uri": "https://black.riseup.net/ca.crt", "default_language": "en", "description": { "en": "Riseup is a non-profit collective in Seattle that provides online communication tools for people and groups working toward liberatory social change." }, "domain": "riseup.net", - "enrollment_policy": "open", + "enrollment_policy": "closed", "languages": [ "en" ], diff --git a/app/src/normal/assets/urls/riseup.net.url b/app/src/normal/assets/urls/riseup.net.url index 3c1e6b4901ae745c3feb23ea04747087e2023e32..474580daa7fabd0dea145395dbde4d55d86d1769 100644 --- a/app/src/normal/assets/urls/riseup.net.url +++ b/app/src/normal/assets/urls/riseup.net.url @@ -1,6 +1,5 @@ { - "main_url" : "https://riseup.net", - "provider_ip" : "198.252.153.70", - "provider_api_ip" : "198.252.153.107", - "geoip_url" : "https://api.black.riseup.net:9001/json" + "main_url" : "https://black.riseup.net", + "geoip_url" : "https://menshen.riseup.net/json", + "motd_url": "https://static.riseup.net/vpn/motd.json" } diff --git a/app/src/normal/res/drawable/background_main.xml b/app/src/normal/res/drawable-anydpi-v24/background_main.xml similarity index 100% rename from app/src/normal/res/drawable/background_main.xml rename to app/src/normal/res/drawable-anydpi-v24/background_main.xml diff --git a/app/src/normal/res/drawable-anydpi-v24/bg_connected.xml b/app/src/normal/res/drawable-anydpi-v24/bg_connected.xml new file mode 100644 index 0000000000000000000000000000000000000000..19dac1037c8d6e400d5f2b9c6db203bc6ea453e8 --- /dev/null +++ b/app/src/normal/res/drawable-anydpi-v24/bg_connected.xml @@ -0,0 +1,14 @@ +<?xml version="1.0" encoding="utf-8"?> +<layer-list xmlns:android="http://schemas.android.com/apk/res/android"> + <item android:gravity="fill"> + <shape android:shape="rectangle"> + <solid android:color="@color/bg_running"/> + </shape> + </item> + <item + android:top="80dp" + android:gravity="fill" + android:drawable="@drawable/bg_connected_effect" + > + </item> +</layer-list> \ No newline at end of file diff --git a/app/src/normal/res/drawable-anydpi-v24/bg_connected_effect.xml b/app/src/normal/res/drawable-anydpi-v24/bg_connected_effect.xml new file mode 100644 index 0000000000000000000000000000000000000000..08ef8172fbdc91e6a84bb7b57c89067f0c0e5d3d --- /dev/null +++ b/app/src/normal/res/drawable-anydpi-v24/bg_connected_effect.xml @@ -0,0 +1,44 @@ +<vector xmlns:android="http://schemas.android.com/apk/res/android" xmlns:aapt="http://schemas.android.com/aapt" + android:viewportWidth="411" + android:viewportHeight="703" + android:width="411dp" + android:height="703dp"> + <path + android:pathData="M628.549 500.593C751.417 416.034 654.462 61.8767 411.994 -290.44C169.527 -642.756 -126.637 -859.816 -249.505 -775.257C-372.373 -690.697 -275.418 -336.54 -32.9505 15.7764C209.517 368.093 505.681 585.153 628.549 500.593Z"> + <aapt:attr + name="android:fillColor"> + <gradient + android:startX="415.099" + android:startY="-19.956" + android:endX="685.832" + android:endY="373.431" + android:tileMode="clamp"> + <item + android:color="#00A6C28A" + android:offset="0" /> + <item + android:color="#44669933" + android:offset="1" /> + </gradient> + </aapt:attr> + </path> + <path + android:pathData="M-186.124 473.683C-63.0333 557.917 232.557 340.077 474.094 -12.8776C715.632 -365.832 811.653 -720.244 688.562 -804.479C565.471 -888.714 269.881 -670.874 28.3433 -317.919C-213.195 35.0357 -309.215 389.448 -186.124 473.683Z"> + <aapt:attr + name="android:fillColor"> + <gradient + android:startX="222.826" + android:startY="87.2986" + android:endX="-46.8688" + android:endY="481.398" + android:tileMode="clamp"> + <item + android:color="#00A6C28A" + android:offset="0" /> + <item + android:color="#44669933" + android:offset="1" /> + </gradient> + </aapt:attr> + </path> +</vector> diff --git a/app/src/normal/res/drawable-anydpi-v24/bg_connecting.xml b/app/src/normal/res/drawable-anydpi-v24/bg_connecting.xml new file mode 100644 index 0000000000000000000000000000000000000000..8482d30eb9fcd338995856dc384bd642c00e56b2 --- /dev/null +++ b/app/src/normal/res/drawable-anydpi-v24/bg_connecting.xml @@ -0,0 +1,13 @@ +<?xml version="1.0" encoding="utf-8"?> +<layer-list xmlns:android="http://schemas.android.com/apk/res/android"> + <item android:gravity="fill"> + <shape android:shape="rectangle"> + <solid android:color="@color/bg_connecting"/> + </shape> + </item> + <item android:gravity="fill" + android:bottom="80dp" + android:drawable="@drawable/bg_connecting_effect" + > + </item> +</layer-list> \ No newline at end of file diff --git a/app/src/normal/res/drawable-anydpi-v24/bg_connecting_effect.xml b/app/src/normal/res/drawable-anydpi-v24/bg_connecting_effect.xml new file mode 100644 index 0000000000000000000000000000000000000000..fd462a54c3c4c5e5975dc0515492f1060b3d7d0d --- /dev/null +++ b/app/src/normal/res/drawable-anydpi-v24/bg_connecting_effect.xml @@ -0,0 +1,44 @@ +<vector xmlns:android="http://schemas.android.com/apk/res/android" xmlns:aapt="http://schemas.android.com/aapt" + android:viewportWidth="375" + android:viewportHeight="629" + android:width="375dp" + android:height="629dp"> + <path + android:pathData="M96.6338 471.305C226.719 515.286 420.512 289.654 529.484 -32.658C638.456 -354.97 621.341 -651.909 491.256 -695.89C361.172 -739.871 167.378 -514.239 58.4058 -191.927C-50.5662 130.385 -33.4509 427.324 96.6338 471.305Z"> + <aapt:attr + name="android:fillColor"> + <gradient + android:startX="132.695" + android:startY="21.7787" + android:endX="11.0197" + android:endY="381.664" + android:tileMode="clamp"> + <item + android:color="#00FFAA33" + android:offset="0" /> + <item + android:color="#33FFAA33" + android:offset="1" /> + </gradient> + </aapt:attr> + </path> + <path + android:pathData="M183.501 628.837C313.565 628.837 419.003 353.304 419.003 13.4182C419.003 -326.468 313.565 -602 183.501 -602C53.4376 -602 -52 -326.468 -52 13.4182C-52 353.304 53.4376 628.837 183.501 628.837Z"> + <aapt:attr + name="android:fillColor"> + <gradient + android:startX="183.501" + android:startY="255.483" + android:endX="183.501" + android:endY="634.991" + android:tileMode="clamp"> + <item + android:color="#00FFAA33" + android:offset="0" /> + <item + android:color="#33FFAA33" + android:offset="1" /> + </gradient> + </aapt:attr> + </path> +</vector> \ No newline at end of file diff --git a/app/src/normal/res/drawable-anydpi-v24/bg_disconnected.xml b/app/src/normal/res/drawable-anydpi-v24/bg_disconnected.xml new file mode 100644 index 0000000000000000000000000000000000000000..a572918504e50fdb066eb98e90b4fc7548b2d15e --- /dev/null +++ b/app/src/normal/res/drawable-anydpi-v24/bg_disconnected.xml @@ -0,0 +1,13 @@ +<?xml version="1.0" encoding="utf-8"?> +<layer-list xmlns:android="http://schemas.android.com/apk/res/android"> + <item android:gravity="fill"> + <shape android:shape="rectangle"> + <solid android:color="@color/bg_disconnected"/> + </shape> + </item> + <item + android:gravity="fill" + android:drawable="@drawable/bg_disconnected_effect" + > + </item> +</layer-list> \ No newline at end of file diff --git a/app/src/normal/res/drawable-anydpi-v24/bg_disconnected_effect.xml b/app/src/normal/res/drawable-anydpi-v24/bg_disconnected_effect.xml new file mode 100644 index 0000000000000000000000000000000000000000..bcc6064a8bf07fe7cccf114056e27fe406333395 --- /dev/null +++ b/app/src/normal/res/drawable-anydpi-v24/bg_disconnected_effect.xml @@ -0,0 +1,33 @@ +<vector xmlns:android="http://schemas.android.com/apk/res/android" xmlns:aapt="http://schemas.android.com/aapt" + android:viewportWidth="375" + android:viewportHeight="636" + android:width="375dp" + android:height="636dp" + > + <group + android:scaleY="0.8" + android:scaleX="1.25" + android:translateX="-46.875" + > + <path + android:pathData="M183.514 458.837C313.578 458.837 419.016 183.305 419.016 -156.582C419.016 -496.468 313.578 -772 183.514 -772C53.4506 -772 -51.9869 -496.468 -51.9869 -156.582C-51.9869 183.305 53.4506 458.837 183.514 458.837Z"> + <aapt:attr + name="android:fillColor"> + <gradient + android:startX="183.514" + android:startY="0" + android:endX="183.514" + android:endY="212" + android:tileMode="clamp"> + <item + android:color="#55D3635C" + android:offset="0" /> + <item + android:color="#33AF0909" + android:offset="1" /> + </gradient> + </aapt:attr> + </path> + </group> + +</vector> \ No newline at end of file diff --git a/app/src/normal/res/drawable-anydpi-v24/rotate_progress_image.xml b/app/src/normal/res/drawable-anydpi-v24/rotate_progress_image.xml new file mode 100644 index 0000000000000000000000000000000000000000..44a35ba91ba3ca49fc1fbd277a3d9962bca34e76 --- /dev/null +++ b/app/src/normal/res/drawable-anydpi-v24/rotate_progress_image.xml @@ -0,0 +1,103 @@ +<vector xmlns:android="http://schemas.android.com/apk/res/android" xmlns:aapt="http://schemas.android.com/aapt" + android:name="circle" + android:viewportWidth="91" + android:viewportHeight="91" + android:width="91dp" + android:height="91dp"> + <path + android:pathData="M83.9459 61.7492C81.6735 67.1718 78.2509 72.0496 73.9091 76.0535L45.5808 46.0417L83.9459 61.7492Z" + android:fillColor="#FFCC80" /> + <path + android:pathData="M74.9439 75.0657C70.7802 79.1812 65.7785 82.3744 60.2709 84.4334L45.5806 46.0421L74.9439 75.0657Z" + android:fillColor="#FFE082" /> + <path + android:pathData="M61.4719 83.9632C55.9543 86.2222 50.0087 87.2783 44.0406 87.0594L45.5806 46.0421L61.4719 83.9632Z" + android:fillColor="#FFF59D" /> + <path + android:pathData="M45.5803 87.088C39.516 87.088 33.5253 85.7751 28.0292 83.2417L45.5803 46.0425L45.5803 87.088Z" + android:fillColor="#E6EE9C" /> + <path + android:pathData="M29.6888 83.9635C24.2224 81.7254 19.303 78.3586 15.2601 74.0885L45.5801 46.0424L29.6888 83.9635Z" + android:fillColor="#C5E1A5" /> + <path + android:pathData="M16.2165 75.0658C11.9261 70.825 8.62802 65.7065 6.55433 60.0703L45.5798 46.0422L16.2165 75.0658Z" + android:fillColor="#A5D6A7" /> + <path + android:pathData="M7.21455 61.7497C4.89145 56.2061 3.82625 50.2265 4.09398 44.232L45.5796 46.0422L7.21455 61.7497Z" + android:fillColor="#80CBC4" /> + <path + android:pathData="M4.05357 46.0421C4.05357 40.2602 5.28944 34.5435 7.68023 29.2665L45.5796 46.0421L4.05357 46.0421Z" + android:fillColor="#80DEEA" /> + <path + android:pathData="M7.21454 30.3342C9.56893 24.716 13.1569 19.685 17.7191 15.6051L45.5796 46.0416L7.21454 30.3342Z" + android:fillColor="#81D4FA" /> + <path + android:pathData="M16.216 17.0181C20.5162 12.7677 25.7084 9.50267 31.4256 7.45389L45.5793 46.0416L16.216 17.0181Z" + android:fillColor="#90CAF9" /> + <path + android:pathData="M29.6883 8.12016C35.3597 5.79816 41.4814 4.7479 47.6127 5.04498L45.5796 46.0413L29.6883 8.12016Z" + android:fillColor="#9FA8DA" /> + <path + android:pathData="M45.5798 4.99576C51.3771 4.99576 57.1101 6.19555 62.4099 8.51791L45.5798 46.0413L45.5798 4.99576Z" + android:fillColor="#B39DDB" /> + <path + android:pathData="M61.4714 8.11991C66.8116 10.3063 71.6312 13.5706 75.6218 17.7038L45.5801 46.041L61.4714 8.11991Z" + android:fillColor="#CE93D8" /> + <path + android:pathData="M74.9437 17.0175C79.0466 21.0729 82.2441 25.9333 84.3301 31.2851L45.5803 46.041L74.9437 17.0175Z" + android:fillColor="#F48FB1" /> + <path + android:pathData="M83.9456 30.3337C86.2094 35.7356 87.2793 41.5533 87.0839 47.3971L45.5806 46.0411L83.9456 30.3337Z" + android:fillColor="#EF9A9A" /> + <path + android:pathData="M87.1066 46.0416C87.1066 51.4632 86.02 56.831 83.9094 61.8351L45.5806 46.0416L87.1066 46.0416Z" + android:fillColor="#FFAB91" /> + <path + android:pathData="M83.8543 60.835C81.5944 66.2576 78.1907 71.1354 73.8728 75.1393L45.7004 45.1276L83.8543 60.835Z" + android:fillColor="#FFCC80" /> + <path + android:pathData="M74.9019 74.1516C70.7611 78.2671 65.787 81.4604 60.3097 83.5193L45.7002 45.1281L74.9019 74.1516Z" + android:fillColor="#FFE082" /> + <path + android:pathData="M61.5041 83.0491C56.0168 85.3082 50.1039 86.3642 44.1687 86.1453L45.7002 45.1281L61.5041 83.0491Z" + android:fillColor="#FFF59D" /> + <path + android:pathData="M45.7002 86.1734C39.6693 86.1734 33.7115 84.8606 28.2457 82.3272L45.7002 45.1279L45.7002 86.1734Z" + android:fillColor="#E6EE9C" /> + <path + android:pathData="M29.8961 83.049C24.4598 80.811 19.5675 77.4442 15.5469 73.1741L45.7 45.1279L29.8961 83.049Z" + android:fillColor="#C5E1A5" /> + <path + android:pathData="M16.4977 74.1517C12.231 69.911 8.95103 64.7924 6.88875 59.1563L45.6995 45.1282L16.4977 74.1517Z" + android:fillColor="#A5D6A7" /> + <path + android:pathData="M7.54558 60.8351C5.23527 55.2915 4.17593 49.3119 4.44219 43.3175L45.6995 45.1277L7.54558 60.8351Z" + android:fillColor="#80CBC4" /> + <path + android:pathData="M4.40175 45.1277C4.40175 39.3457 5.63082 33.6291 8.00845 28.3521L45.6992 45.1277L4.40175 45.1277Z" + android:fillColor="#80DEEA" /> + <path + android:pathData="M7.54533 29.4201C9.88677 23.8019 13.455 18.7709 17.992 14.691L45.6992 45.1276L7.54533 29.4201Z" + android:fillColor="#81D4FA" /> + <path + android:pathData="M16.4972 16.104C20.7738 11.8536 25.9374 8.5886 31.6231 6.53981L45.699 45.1276L16.4972 16.104Z" + android:fillColor="#90CAF9" /> + <path + android:pathData="M29.8956 7.20611C35.5358 4.88411 41.6238 3.83384 47.7214 4.13092L45.6995 45.1272L29.8956 7.20611Z" + android:fillColor="#9FA8DA" /> + <path + android:pathData="M45.6997 4.08133C51.465 4.08133 57.1665 5.28113 62.4371 7.60349L45.6997 45.1268L45.6997 4.08133Z" + android:fillColor="#B39DDB" /> + <path + android:pathData="M61.5036 7.20587C66.8144 9.39225 71.6074 12.6565 75.576 16.7898L45.6997 45.127L61.5036 7.20587Z" + android:fillColor="#CE93D8" /> + <path + android:pathData="M74.9017 16.1034C78.982 20.1589 82.162 25.0192 84.2365 30.3711L45.7 45.127L74.9017 16.1034Z" + android:fillColor="#F48FB1" /> + <path + android:pathData="M83.8541 29.4196C86.1054 34.8216 87.1695 40.6392 86.9751 46.4831L45.7002 45.1271L83.8541 29.4196Z" + android:fillColor="#EF9A9A" /> + <path + android:pathData="M86.9979 45.1272C86.9979 50.5487 85.9172 55.9166 83.8183 60.9207L45.7004 45.1272L86.9979 45.1272Z" + android:fillColor="#FFAB91" /> +</vector> \ No newline at end of file diff --git a/app/src/normal/res/drawable-anydpi-v24/splash_icon.xml b/app/src/normal/res/drawable-anydpi-v24/splash_icon.xml new file mode 100644 index 0000000000000000000000000000000000000000..f882d322235b010e0823054e1da2fd58ad50d712 --- /dev/null +++ b/app/src/normal/res/drawable-anydpi-v24/splash_icon.xml @@ -0,0 +1,14 @@ +<?xml version="1.0" encoding="utf-8"?> +<layer-list xmlns:android="http://schemas.android.com/apk/res/android"> + <item android:drawable="@drawable/rotate_progress_image" + android:height="198dp" + android:width="198dp" + android:gravity="fill"/> + <item + android:gravity="center" + android:height="52.75dp" + android:width="80dp" + > + <bitmap android:src="@drawable/logo"/> + </item> +</layer-list> \ No newline at end of file diff --git a/app/src/normal/res/drawable-hdpi/bg_connected.png b/app/src/normal/res/drawable-hdpi/bg_connected.png new file mode 100644 index 0000000000000000000000000000000000000000..7c64939a83f31824b6e947494a35e4f67ec147b0 Binary files /dev/null and b/app/src/normal/res/drawable-hdpi/bg_connected.png differ diff --git a/app/src/normal/res/drawable-hdpi/bg_connecting.png b/app/src/normal/res/drawable-hdpi/bg_connecting.png new file mode 100644 index 0000000000000000000000000000000000000000..49620c2c9c407fa192cb177ed9d730a99fb8b536 Binary files /dev/null and b/app/src/normal/res/drawable-hdpi/bg_connecting.png differ diff --git a/app/src/normal/res/drawable-hdpi/bg_disconnected.png b/app/src/normal/res/drawable-hdpi/bg_disconnected.png new file mode 100644 index 0000000000000000000000000000000000000000..36a048d5e217f51b7626e9e3b7fd75a184500426 Binary files /dev/null and b/app/src/normal/res/drawable-hdpi/bg_disconnected.png differ diff --git a/app/src/normal/res/drawable-hdpi/rotate_progress_image.png b/app/src/normal/res/drawable-hdpi/rotate_progress_image.png new file mode 100644 index 0000000000000000000000000000000000000000..d7c85e027e500b071b2fd12bf5622b67563fd41d Binary files /dev/null and b/app/src/normal/res/drawable-hdpi/rotate_progress_image.png differ diff --git a/app/src/normal/res/drawable-hdpi/state_connected.png b/app/src/normal/res/drawable-hdpi/state_connected.png new file mode 100644 index 0000000000000000000000000000000000000000..fccc060aebebb9174fb87077f1c3da8e1c2f2ffe Binary files /dev/null and b/app/src/normal/res/drawable-hdpi/state_connected.png differ diff --git a/app/src/normal/res/drawable-hdpi/state_connecting.png b/app/src/normal/res/drawable-hdpi/state_connecting.png new file mode 100644 index 0000000000000000000000000000000000000000..72e3ae45aec27b662d779de3b302aa124a61294c Binary files /dev/null and b/app/src/normal/res/drawable-hdpi/state_connecting.png differ diff --git a/app/src/normal/res/drawable-hdpi/state_disconnected.png b/app/src/normal/res/drawable-hdpi/state_disconnected.png new file mode 100644 index 0000000000000000000000000000000000000000..d2ef7d99125d28869f565b25728720572bed9821 Binary files /dev/null and b/app/src/normal/res/drawable-hdpi/state_disconnected.png differ diff --git a/app/src/normal/res/drawable-xhdpi/ic_splash_background.png b/app/src/normal/res/drawable-xhdpi/background_main.png similarity index 100% rename from app/src/normal/res/drawable-xhdpi/ic_splash_background.png rename to app/src/normal/res/drawable-xhdpi/background_main.png diff --git a/app/src/normal/res/drawable-xhdpi/bg_connected.png b/app/src/normal/res/drawable-xhdpi/bg_connected.png new file mode 100644 index 0000000000000000000000000000000000000000..ca129080f00a40b6739cea676429e98175751871 Binary files /dev/null and b/app/src/normal/res/drawable-xhdpi/bg_connected.png differ diff --git a/app/src/normal/res/drawable-xhdpi/bg_connecting.png b/app/src/normal/res/drawable-xhdpi/bg_connecting.png new file mode 100644 index 0000000000000000000000000000000000000000..294e4708c5adf7d9688009c88e46ebb59ea63b57 Binary files /dev/null and b/app/src/normal/res/drawable-xhdpi/bg_connecting.png differ diff --git a/app/src/normal/res/drawable-xhdpi/bg_disconnected.png b/app/src/normal/res/drawable-xhdpi/bg_disconnected.png new file mode 100644 index 0000000000000000000000000000000000000000..15bdb108d1414aec3996e07d941ffd5abb00b262 Binary files /dev/null and b/app/src/normal/res/drawable-xhdpi/bg_disconnected.png differ diff --git a/app/src/normal/res/drawable-xhdpi/rotate_progress_image.png b/app/src/normal/res/drawable-xhdpi/rotate_progress_image.png new file mode 100644 index 0000000000000000000000000000000000000000..d6eb6b65f3034694f8e9fe32331bd5ab1c63dc40 Binary files /dev/null and b/app/src/normal/res/drawable-xhdpi/rotate_progress_image.png differ diff --git a/app/src/normal/res/drawable-xhdpi/state_connected.png b/app/src/normal/res/drawable-xhdpi/state_connected.png new file mode 100644 index 0000000000000000000000000000000000000000..c852459d95f29c12de120a23a0c63a986793b163 Binary files /dev/null and b/app/src/normal/res/drawable-xhdpi/state_connected.png differ diff --git a/app/src/normal/res/drawable-xhdpi/state_connecting.png b/app/src/normal/res/drawable-xhdpi/state_connecting.png new file mode 100644 index 0000000000000000000000000000000000000000..d81190fef3006d362232e22ee9513f1f24a5de96 Binary files /dev/null and b/app/src/normal/res/drawable-xhdpi/state_connecting.png differ diff --git a/app/src/normal/res/drawable-xhdpi/state_disconnected.png b/app/src/normal/res/drawable-xhdpi/state_disconnected.png new file mode 100644 index 0000000000000000000000000000000000000000..c0d57a03eae89fb7cf91a38e61996ac341b68ac9 Binary files /dev/null and b/app/src/normal/res/drawable-xhdpi/state_disconnected.png differ diff --git a/app/src/normal/res/drawable-xxhdpi/rotate_progress_image.png b/app/src/normal/res/drawable-xxhdpi/rotate_progress_image.png new file mode 100644 index 0000000000000000000000000000000000000000..893b074b02d2329c111c06b04fda9cb97166d5b3 Binary files /dev/null and b/app/src/normal/res/drawable-xxhdpi/rotate_progress_image.png differ diff --git a/app/src/normal/res/drawable-xxhdpi/state_connected.png b/app/src/normal/res/drawable-xxhdpi/state_connected.png new file mode 100644 index 0000000000000000000000000000000000000000..3228617792b9ff0d3687796cbac16241f76ef8f2 Binary files /dev/null and b/app/src/normal/res/drawable-xxhdpi/state_connected.png differ diff --git a/app/src/normal/res/drawable-xxhdpi/state_connecting.png b/app/src/normal/res/drawable-xxhdpi/state_connecting.png new file mode 100644 index 0000000000000000000000000000000000000000..75cf3782e9c7a2d96ab41cb21cf50f99c5a3f000 Binary files /dev/null and b/app/src/normal/res/drawable-xxhdpi/state_connecting.png differ diff --git a/app/src/normal/res/drawable-xxhdpi/state_disconnected.png b/app/src/normal/res/drawable-xxhdpi/state_disconnected.png new file mode 100644 index 0000000000000000000000000000000000000000..ac560317166d1ecbf59f576197ff6c4ada147a99 Binary files /dev/null and b/app/src/normal/res/drawable-xxhdpi/state_disconnected.png differ diff --git a/app/src/normal/res/drawable-xxxhdpi/ic_splash_background.png b/app/src/normal/res/drawable-xxxhdpi/background_main.png similarity index 100% rename from app/src/normal/res/drawable-xxxhdpi/ic_splash_background.png rename to app/src/normal/res/drawable-xxxhdpi/background_main.png diff --git a/app/src/normal/res/drawable-xxxhdpi/state_connected.png b/app/src/normal/res/drawable-xxxhdpi/state_connected.png new file mode 100644 index 0000000000000000000000000000000000000000..f5a5adaffe01508f8dce1add9913f9bdb8a5ded7 Binary files /dev/null and b/app/src/normal/res/drawable-xxxhdpi/state_connected.png differ diff --git a/app/src/normal/res/drawable-xxxhdpi/state_connecting.png b/app/src/normal/res/drawable-xxxhdpi/state_connecting.png new file mode 100644 index 0000000000000000000000000000000000000000..806dcbf455c0818447ace9560ff47804da947c0d Binary files /dev/null and b/app/src/normal/res/drawable-xxxhdpi/state_connecting.png differ diff --git a/app/src/normal/res/drawable-xxxhdpi/state_disconnected.png b/app/src/normal/res/drawable-xxxhdpi/state_disconnected.png new file mode 100644 index 0000000000000000000000000000000000000000..9e216955ca6faecbc7747bb218ce1b7d90d17872 Binary files /dev/null and b/app/src/normal/res/drawable-xxxhdpi/state_disconnected.png differ diff --git a/app/src/normal/res/drawable/background_eip.xml b/app/src/normal/res/drawable/background_eip.xml deleted file mode 100644 index 9b20a8fda803f95bc74d64334c3d9f2e264aface..0000000000000000000000000000000000000000 --- a/app/src/normal/res/drawable/background_eip.xml +++ /dev/null @@ -1,52 +0,0 @@ -<vector android:height="24dp" android:viewportHeight="100.0" - android:viewportWidth="100.0" android:width="24dp" xmlns:android="http://schemas.android.com/apk/res/android"> - <path android:pathData="M50,33m-82000,0a82000,82000 0,1 1,164000 0a82000,82000 0,1 1,-164000 0"/> - <path android:fillAlpha="1" android:fillColor="#b39ddb" - android:pathData="M50,33 L30664.67,-73860.37A80000,80000 0,0 0,50 -79950Z" - android:strokeColor="#b39ddb" android:strokeWidth="0"/> - <path android:fillAlpha="1" android:fillColor="#9fa8da" - android:pathData="m50,33 l56568.54,-56568.54a80000,80000 0,0 0,-25953.87 -17341.82z" - android:strokeColor="#9fa8da" android:strokeWidth="0"/> - <path android:fillAlpha="1" android:fillColor="#90caf9" - android:pathData="m50,33 l73910.37,-30614.67a80000,80000 0,0 0,-17341.82 -25953.87z" - android:strokeColor="#90caf9" android:strokeWidth="0"/> - <path android:fillAlpha="1" android:fillColor="#81d4fa" - android:pathData="M50,33L80050,50A80000,80000 0,0 0,73960.37 -30564.67Z" - android:strokeColor="#81d4fa" android:strokeWidth="0"/> - <path android:fillAlpha="1" android:fillColor="#80deea" - android:pathData="M50,33 L73960.37,30664.67A80000,80000 0,0 0,80050 50Z" - android:strokeColor="#80deea" android:strokeWidth="0"/> - <path android:fillAlpha="1" android:fillColor="#80cbc4" - android:pathData="m50,33 l56568.54,56568.54a80000,80000 0,0 0,17341.82 -25953.87z" - android:strokeColor="#80cbc4" android:strokeWidth="0"/> - <path android:fillAlpha="1" android:fillColor="#a5d6a7" - android:pathData="m50,33 l30614.67,73910.37a80000,80000 0,0 0,25953.87 -17341.82z" - android:strokeColor="#a5d6a7" android:strokeWidth="0"/> - <path android:fillAlpha="1" android:fillColor="#c5e1a5" - android:pathData="M50,33L50,80050A80000,80000 0,0 0,30664.67 73960.37Z" - android:strokeColor="#c5e1a5" android:strokeWidth="0"/> - <path android:fillAlpha="1" android:fillColor="#e6ee9c" - android:pathData="M50,33 L-30564.67,73960.37A80000,80000 0,0 0,50 80050Z" - android:strokeColor="#e6ee9c" android:strokeWidth="0"/> - <path android:fillAlpha="1" android:fillColor="#fff59d" - android:pathData="m50,33 l-56568.54,56568.54a80000,80000 0,0 0,25953.87 17341.82z" - android:strokeColor="#fff59d" android:strokeWidth="0"/> - <path android:fillAlpha="1" android:fillColor="#ffe082" - android:pathData="m50,33 l-73910.37,30614.67a80000,80000 0,0 0,17341.82 25953.87z" - android:strokeColor="#ffe082" android:strokeWidth="0"/> - <path android:fillAlpha="1" android:fillColor="#ffcc80" - android:pathData="m50,33l-80000,0a80000,80000 0,0 0,6089.64 30614.67z" - android:strokeColor="#ffcc80" android:strokeWidth="0"/> - <path android:fillAlpha="1" android:fillColor="#ffab91" - android:pathData="M50,33 L-73860.37,-30564.67A80000,80000 0,0 0,-79950 50Z" - android:strokeColor="#ffab91" android:strokeWidth="0"/> - <path android:fillAlpha="1" android:fillColor="#ef9a9a" - android:pathData="m50,33 l-56568.54,-56568.54a80000,80000 0,0 0,-17341.82 25953.87z" - android:strokeColor="#ef9a9a" android:strokeWidth="0"/> - <path android:fillAlpha="1" android:fillColor="#f48fb1" - android:pathData="m50,33 l-30614.67,-73910.37a80000,80000 0,0 0,-25953.87 17341.82z" - android:strokeColor="#f48fb1" android:strokeWidth="0"/> - <path android:fillAlpha="1" android:fillColor="#ce93d8" - android:pathData="m50,33l0,-80000a80000,80000 0,0 0,-30614.67 6089.64z" - android:strokeColor="#ce93d8" android:strokeWidth="0"/> -</vector> diff --git a/app/src/normal/res/drawable-hdpi/ic_splash_background.png b/app/src/normal/res/drawable/background_main.png similarity index 100% rename from app/src/normal/res/drawable-hdpi/ic_splash_background.png rename to app/src/normal/res/drawable/background_main.png diff --git a/app/src/normal/res/drawable/bg_connected.png b/app/src/normal/res/drawable/bg_connected.png new file mode 100644 index 0000000000000000000000000000000000000000..9741dcbaea8b63abd3093425301f5440e4107492 Binary files /dev/null and b/app/src/normal/res/drawable/bg_connected.png differ diff --git a/app/src/normal/res/drawable/bg_connecting.png b/app/src/normal/res/drawable/bg_connecting.png new file mode 100644 index 0000000000000000000000000000000000000000..d85ddd4b6510bd5f3ef6994be1c9749dabd8c40e Binary files /dev/null and b/app/src/normal/res/drawable/bg_connecting.png differ diff --git a/app/src/normal/res/drawable/bg_disconnected.png b/app/src/normal/res/drawable/bg_disconnected.png new file mode 100644 index 0000000000000000000000000000000000000000..a22b7097e466d2ff51cb1997878a5092b92c7262 Binary files /dev/null and b/app/src/normal/res/drawable/bg_disconnected.png differ diff --git a/app/src/normal/res/drawable/ic_splash_background.xml b/app/src/normal/res/drawable/ic_splash_background.xml new file mode 100644 index 0000000000000000000000000000000000000000..aa2618c1309c717ce8683c3794b41bcfb9173e5d --- /dev/null +++ b/app/src/normal/res/drawable/ic_splash_background.xml @@ -0,0 +1,4 @@ +<?xml version="1.0" encoding="utf-8"?> +<selector xmlns:android="http://schemas.android.com/apk/res/android"> + <item android:drawable="@drawable/background_main"/> +</selector> \ No newline at end of file diff --git a/app/src/normal/res/drawable/rotate_progress_image.png b/app/src/normal/res/drawable/rotate_progress_image.png new file mode 100644 index 0000000000000000000000000000000000000000..fe7f3526668441755ec06dfab483b4708368d4d9 Binary files /dev/null and b/app/src/normal/res/drawable/rotate_progress_image.png differ diff --git a/app/src/normal/res/drawable/splash_branding.xml b/app/src/normal/res/drawable/splash_branding.xml new file mode 100644 index 0000000000000000000000000000000000000000..8c4ee21c14b8450535540b185ba512640950028a --- /dev/null +++ b/app/src/normal/res/drawable/splash_branding.xml @@ -0,0 +1,3 @@ +<layer-list xmlns:android="http://schemas.android.com/apk/res/android"> + <item android:drawable="@drawable/footer_text_drawable" /> +</layer-list> \ No newline at end of file diff --git a/app/src/normal/res/drawable/state_connected.png b/app/src/normal/res/drawable/state_connected.png new file mode 100644 index 0000000000000000000000000000000000000000..e515f3f5944c6745c63bac91495aa690388b8647 Binary files /dev/null and b/app/src/normal/res/drawable/state_connected.png differ diff --git a/app/src/normal/res/drawable/state_connecting.png b/app/src/normal/res/drawable/state_connecting.png new file mode 100644 index 0000000000000000000000000000000000000000..98dd7978b02b715fcbe28df5e26e85e4dc79c320 Binary files /dev/null and b/app/src/normal/res/drawable/state_connecting.png differ diff --git a/app/src/normal/res/drawable/state_disconnected.png b/app/src/normal/res/drawable/state_disconnected.png new file mode 100644 index 0000000000000000000000000000000000000000..a4bd4a788263bf4125ebd82e54d10807c1846de2 Binary files /dev/null and b/app/src/normal/res/drawable/state_disconnected.png differ diff --git a/app/src/normal/res/drawable/state_transition_connected_disconnected.png b/app/src/normal/res/drawable/state_transition_connected_disconnected.png new file mode 100644 index 0000000000000000000000000000000000000000..a4bd4a788263bf4125ebd82e54d10807c1846de2 Binary files /dev/null and b/app/src/normal/res/drawable/state_transition_connected_disconnected.png differ diff --git a/app/src/normal/res/values-v31/themes.xml b/app/src/normal/res/values-v31/themes.xml new file mode 100644 index 0000000000000000000000000000000000000000..7ea174241e317f3664d3126e6181022a4fff0966 --- /dev/null +++ b/app/src/normal/res/values-v31/themes.xml @@ -0,0 +1,8 @@ +<?xml version="1.0" encoding="utf-8"?> +<resources> + <style name="SplashTheme" parent="Theme.AppCompat.NoActionBar"> + <item name="android:windowSplashScreenBackground">@color/white</item> + <item name="android:windowSplashScreenAnimatedIcon">@drawable/splash_icon</item> + <item name="android:windowSplashScreenBrandingImage">@drawable/splash_branding</item> + </style> +</resources> \ No newline at end of file diff --git a/app/src/normalProductionFatDebug/assets/urls/riseup.net.url b/app/src/normalProductionFatDebug/assets/urls/riseup.net.url index 3c1e6b4901ae745c3feb23ea04747087e2023e32..ad24ee994e4c16a9d1573c14f0884bc68cfa16c8 100644 --- a/app/src/normalProductionFatDebug/assets/urls/riseup.net.url +++ b/app/src/normalProductionFatDebug/assets/urls/riseup.net.url @@ -1,6 +1,7 @@ { - "main_url" : "https://riseup.net", + "main_url" : "https://black.riseup.net", "provider_ip" : "198.252.153.70", "provider_api_ip" : "198.252.153.107", - "geoip_url" : "https://api.black.riseup.net:9001/json" + "geoip_url" : "https://api.black.riseup.net:9001/json", + "motd_url": "https://static.riseup.net/vpn/motd.json" } diff --git a/app/src/notFatweb/java/se/leap/bitmaskclient/appUpdate/DownloadServiceCommand.java b/app/src/notFatweb/java/se/leap/bitmaskclient/appUpdate/DownloadServiceCommand.java index 157f04fe6cc4d54b0925799a6aa17c4a34a3915c..02a830ca830654500d17ebebeaa21bd937080edc 100644 --- a/app/src/notFatweb/java/se/leap/bitmaskclient/appUpdate/DownloadServiceCommand.java +++ b/app/src/notFatweb/java/se/leap/bitmaskclient/appUpdate/DownloadServiceCommand.java @@ -1,6 +1,10 @@ package se.leap.bitmaskclient.appUpdate; import android.content.Context; +import android.os.Bundle; + +import androidx.annotation.NonNull; +import androidx.annotation.Nullable; /** * DownloadServiceCommand is only implemented in Fatweb builds @@ -16,4 +20,8 @@ public class DownloadServiceCommand { public static void execute(Context context, String action) { // DO NOTHING. } + + public static void execute(@NonNull Context context, @NonNull String action, @Nullable Bundle parameters) { + // DO NOTHING. + } } diff --git a/app/src/production/java/se/leap/bitmaskclient/providersetup/ProviderApiManager.java b/app/src/production/java/se/leap/bitmaskclient/providersetup/ProviderApiManager.java index d1de62a021a7e5c1336ec27d055c766c149d4f5f..0fa89bf2fd94f71c1db9911581e35f877da5d960 100644 --- a/app/src/production/java/se/leap/bitmaskclient/providersetup/ProviderApiManager.java +++ b/app/src/production/java/se/leap/bitmaskclient/providersetup/ProviderApiManager.java @@ -25,7 +25,6 @@ import android.util.Pair; import org.json.JSONException; import org.json.JSONObject; -import java.io.IOException; import java.net.URL; import java.util.List; import java.util.concurrent.TimeoutException; @@ -199,29 +198,22 @@ public class ProviderApiManager extends ProviderApiManagerBase { @Override protected Bundle updateVpnCertificate(Provider provider) { Bundle result = new Bundle(); - try { - URL newCertStringUrl = new URL(provider.getApiUrlWithVersion() + "/" + PROVIDER_VPN_CERTIFICATE); - - String certString = downloadWithProviderCA(provider.getCaCert(), newCertStringUrl.toString()); - if (DEBUG_MODE) { - VpnStatus.logDebug("[API] VPN CERT: " + certString); - } - if (ConfigHelper.checkErroneousDownload(certString)) { - if (certString == null || certString.isEmpty()) { - // probably 204 - setErrorResult(result, error_io_exception_user_message, null); - } else { - setErrorResult(result, certString); - return result; - } + String certString = downloadFromVersionedApiUrlWithProviderCA("/" + PROVIDER_VPN_CERTIFICATE, provider); + if (DEBUG_MODE) { + VpnStatus.logDebug("[API] VPN CERT: " + certString); + } + if (ConfigHelper.checkErroneousDownload(certString)) { + if (TorStatusObservable.isRunning()) { + setErrorResult(result, downloading_vpn_certificate_failed, null); + } else if (certString == null || certString.isEmpty() ){ + // probably 204 + setErrorResult(result, error_io_exception_user_message, null); + } else { + setErrorResult(result, certString); } - return loadCertificate(provider, certString); - } catch (IOException e) { - // TODO try to get Provider Json - setErrorResult(result, downloading_vpn_certificate_failed, null); - e.printStackTrace(); + return result; } - return result; + return loadCertificate(provider, certString); } /** @@ -271,7 +263,7 @@ public class ProviderApiManager extends ProviderApiManagerBase { Bundle result = new Bundle(); try { String caCertUrl = provider.getDefinition().getString(Provider.CA_CERT_URI); - String providerDomain = getDomainFromMainURL(provider.getMainUrlString()); + String providerDomain = provider.getDomain(); String certString = downloadWithCommercialCA(caCertUrl, provider); if (validCertificate(provider, certString)) { @@ -352,6 +344,17 @@ public class ProviderApiManager extends ProviderApiManagerBase { return downloadFromUrlWithProviderCA(urlString, provider); } + /** + * Tries to download the contents of $base_url/$version/$path using not commercially validated CA certificate from chosen provider. + * + * @return an empty string if it fails, the response body if not. + */ + private String downloadFromVersionedApiUrlWithProviderCA(String path, Provider provider) { + String baseUrl = provider.getApiUrlWithVersion(); + String urlString = baseUrl + path; + return downloadFromUrlWithProviderCA(urlString, provider); + } + private String downloadFromUrlWithProviderCA(String urlString, Provider provider) { return downloadFromUrlWithProviderCA(urlString, provider, true); } diff --git a/app/src/production/res/layout-xlarge/d_new_provider.xml b/app/src/production/res/layout-xlarge/d_new_provider.xml index 12616625b56ef0ed2a5f8b97192c2edc28f6a43a..6e64c8c0713655d9b0d9a1d0fa48b411f2ee8b72 100644 --- a/app/src/production/res/layout-xlarge/d_new_provider.xml +++ b/app/src/production/res/layout-xlarge/d_new_provider.xml @@ -1,9 +1,12 @@ <?xml version="1.0" encoding="utf-8"?> <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" + xmlns:tools="http://schemas.android.com/tools" android:layout_width="wrap_content" android:layout_height="wrap_content" android:orientation="vertical" - android:textSize="24sp" > + android:textSize="24sp" + tools:viewBindingIgnore="true" + > <EditText android:id="@+id/new_provider_url" diff --git a/app/src/production/res/layout/d_new_provider.xml b/app/src/production/res/layout/d_new_provider.xml index 36eb0d6a0754d51310bd05a837821c66c796da14..e58db08a99649cf6d9545638dcb3e86586b28ca5 100644 --- a/app/src/production/res/layout/d_new_provider.xml +++ b/app/src/production/res/layout/d_new_provider.xml @@ -1,8 +1,10 @@ <?xml version="1.0" encoding="utf-8"?> <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" + xmlns:tools="http://schemas.android.com/tools" android:layout_width="wrap_content" android:layout_height="wrap_content" - android:orientation="vertical" > + android:orientation="vertical" + tools:viewBindingIgnore="true"> <EditText android:id="@+id/new_provider_url" diff --git a/app/src/sharedTest/java/se.leap.bitmaskclient/testutils/TestSetupHelper.java b/app/src/sharedTest/java/se.leap.bitmaskclient/testutils/TestSetupHelper.java index 0fdc94ca3a637f74796d4ae1ae37c645b4f00d5b..72791ba65929a9d8e1a698c503b4b165ce5d4862 100644 --- a/app/src/sharedTest/java/se.leap.bitmaskclient/testutils/TestSetupHelper.java +++ b/app/src/sharedTest/java/se.leap.bitmaskclient/testutils/TestSetupHelper.java @@ -84,6 +84,7 @@ public class TestSetupHelper { Provider p = new Provider( domain, geoipUrl, + null, providerIp, providerApiIp, getInputAsString(TestSetupHelper.class.getClassLoader().getResourceAsStream(caCertFile)), diff --git a/app/src/test/java/de/blinkt/openvpn/VpnProfileTest.java b/app/src/test/java/de/blinkt/openvpn/VpnProfileTest.java index e8a93b75398f27ad5543af81abab2377da5cae4c..9675c877966de7663936af6ee1e69fbdee56b1d8 100644 --- a/app/src/test/java/de/blinkt/openvpn/VpnProfileTest.java +++ b/app/src/test/java/de/blinkt/openvpn/VpnProfileTest.java @@ -1,32 +1,43 @@ package de.blinkt.openvpn; +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertFalse; +import static org.junit.Assert.assertNotNull; +import static org.junit.Assert.assertTrue; +import static org.powermock.api.mockito.PowerMockito.mockStatic; +import static org.powermock.api.mockito.PowerMockito.when; +import static de.blinkt.openvpn.core.connection.Connection.TransportType.OBFS4; +import static de.blinkt.openvpn.core.connection.Connection.TransportType.OBFS4_KCP; +import static de.blinkt.openvpn.core.connection.Connection.TransportType.OPENVPN; + import org.json.JSONException; import org.json.JSONObject; import org.junit.Before; import org.junit.Test; +import org.junit.runner.RunWith; import org.powermock.core.classloader.annotations.PrepareForTest; +import org.powermock.modules.junit4.PowerMockRunner; import java.util.UUID; import de.blinkt.openvpn.core.connection.Obfs4Connection; import de.blinkt.openvpn.core.connection.OpenvpnConnection; +import se.leap.bitmaskclient.base.utils.ConfigHelper; import se.leap.bitmaskclient.pluggableTransports.Obfs4Options; -import static de.blinkt.openvpn.core.connection.Connection.TransportType.OBFS4; -import static de.blinkt.openvpn.core.connection.Connection.TransportType.OPENVPN; -import static org.junit.Assert.assertEquals; -import static org.junit.Assert.assertFalse; -import static org.junit.Assert.assertNotNull; -import static org.powermock.api.mockito.PowerMockito.mockStatic; - -@PrepareForTest({UUID.class}) +@RunWith(PowerMockRunner.class) +@PrepareForTest({UUID.class, ConfigHelper.ObfsVpnHelper.class}) public class VpnProfileTest { - private static final String OPENVPNCONNECTION_PROFILE = "{\"mAuthenticationType\":2,\"mName\":\"mockProfile\",\"mTLSAuthDirection\":\"\",\"mUseLzo\":false,\"mUseTLSAuth\":false,\"mDNS1\":\"8.8.8.8\",\"mDNS2\":\"8.8.4.4\",\"mOverrideDNS\":false,\"mSearchDomain\":\"blinkt.de\",\"mUseDefaultRoute\":true,\"mUsePull\":true,\"mCheckRemoteCN\":true,\"mExpectTLSCert\":false,\"mRemoteCN\":\"\",\"mPassword\":\"\",\"mUsername\":\"\",\"mRoutenopull\":false,\"mUseRandomHostname\":false,\"mUseFloat\":false,\"mUseCustomConfig\":false,\"mCustomConfigOptions\":\"\",\"mVerb\":\"1\",\"mCipher\":\"\",\"mDataCiphers\":\"\",\"mNobind\":true,\"mUseDefaultRoutev6\":true,\"mCustomRoutesv6\":\"\",\"mKeyPassword\":\"\",\"mPersistTun\":false,\"mConnectRetryMax\":\"-1\",\"mConnectRetry\":\"2\",\"mConnectRetryMaxTime\":\"300\",\"mUserEditable\":true,\"mAuth\":\"\",\"mX509AuthType\":3,\"mAllowLocalLAN\":false,\"mMssFix\":0,\"mConnections\":[{\"mServerName\":\"openvpn.example.com\",\"mServerPort\":\"1194\",\"mUseUdp\":false,\"mCustomConfiguration\":\"\",\"mUseCustomConfig\":false,\"mEnabled\":true,\"mConnectTimeout\":0,\"mProxyType\":\"NONE\",\"mProxyName\":\"proxy.example.com\",\"mProxyPort\":\"8080\",\"mUseProxyAuth\":false,\"ConnectionAdapter.META_TYPE\":\"de.blinkt.openvpn.core.connection.OpenvpnConnection\"}],\"mRemoteRandom\":false,\"mAllowedAppsVpn\":[],\"mAllowedAppsVpnAreDisallowed\":true,\"mAllowAppVpnBypass\":false,\"mAuthRetry\":0,\"mTunMtu\":0,\"mPushPeerInfo\":false,\"mVersion\":0,\"mLastUsed\":0,\"mServerName\":\"openvpn.example.com\",\"mServerPort\":\"1194\",\"mUseUdp\":true,\"mTemporaryProfile\":false,\"mUuid\":\"9d295ca2-3789-48dd-996e-f731dbf50fdc\",\"mProfileVersion\":7,\"mBlockUnusedAddressFamilies\":true,\"mUsePluggableTransports\":false}"; - private static final String OBFS4CONNECTION_PROFILE = "{\"mAuthenticationType\":2,\"mName\":\"mockProfile\",\"mTLSAuthDirection\":\"\",\"mUseLzo\":false,\"mUseTLSAuth\":false,\"mDNS1\":\"8.8.8.8\",\"mDNS2\":\"8.8.4.4\",\"mOverrideDNS\":false,\"mSearchDomain\":\"blinkt.de\",\"mUseDefaultRoute\":true,\"mUsePull\":true,\"mCheckRemoteCN\":true,\"mExpectTLSCert\":false,\"mRemoteCN\":\"\",\"mPassword\":\"\",\"mUsername\":\"\",\"mRoutenopull\":false,\"mUseRandomHostname\":false,\"mUseFloat\":false,\"mUseCustomConfig\":false,\"mCustomConfigOptions\":\"\",\"mVerb\":\"1\",\"mCipher\":\"\",\"mDataCiphers\":\"\",\"mNobind\":true,\"mUseDefaultRoutev6\":true,\"mCustomRoutesv6\":\"\",\"mKeyPassword\":\"\",\"mPersistTun\":false,\"mConnectRetryMax\":\"-1\",\"mConnectRetry\":\"2\",\"mConnectRetryMaxTime\":\"300\",\"mUserEditable\":true,\"mAuth\":\"\",\"mX509AuthType\":3,\"mAllowLocalLAN\":false,\"mMssFix\":0,\"mConnections\":[{\"options\":{\"cert\":\"CERT\",\"iatMode\":\"1\",\"remoteIP\":\"192.168.0.1\",\"remotePort\":\"1234\"},\"mServerName\":\"127.0.0.1\",\"mServerPort\":\"4430\",\"mUseUdp\":false,\"mCustomConfiguration\":\"\",\"mUseCustomConfig\":false,\"mEnabled\":true,\"mConnectTimeout\":0,\"mProxyType\":\"NONE\",\"mProxyName\":\"\",\"mProxyPort\":\"\",\"mUseProxyAuth\":false,\"ConnectionAdapter.META_TYPE\":\"de.blinkt.openvpn.core.connection.Obfs4Connection\"}],\"mRemoteRandom\":false,\"mAllowedAppsVpn\":[],\"mAllowedAppsVpnAreDisallowed\":true,\"mAllowAppVpnBypass\":false,\"mAuthRetry\":0,\"mTunMtu\":0,\"mPushPeerInfo\":false,\"mVersion\":0,\"mLastUsed\":0,\"mServerName\":\"openvpn.example.com\",\"mServerPort\":\"1194\",\"mUseUdp\":true,\"mTemporaryProfile\":false,\"mUuid\":\"9d295ca2-3789-48dd-996e-f731dbf50fdc\",\"mProfileVersion\":7,\"mBlockUnusedAddressFamilies\":true,\"mUsePluggableTransports\":true}"; + private static final String OPENVPNCONNECTION_PROFILE = "{\"mCipher\":\"\",\"mProfileVersion\":7,\"mLastUsed\":0,\"mCheckRemoteCN\":true,\"mVerb\":\"1\",\"mRemoteRandom\":false,\"mRoutenopull\":false,\"mConnectRetry\":\"2\",\"mAllowedAppsVpn\":[],\"mUserEditable\":true,\"mUseUdp\":true,\"mAllowedAppsVpnAreDisallowed\":true,\"mDNS1\":\"8.8.8.8\",\"mDNS2\":\"8.8.4.4\",\"mUseCustomConfig\":false,\"mUseFloat\":false,\"mUseDefaultRoute\":true,\"mConnectRetryMaxTime\":\"300\",\"mNobind\":true,\"mVersion\":0,\"mConnectRetryMax\":\"-1\",\"mOverrideDNS\":false,\"mAuth\":\"\",\"mTunMtu\":0,\"mUseObfs4\":false,\"mPassword\":\"\",\"mTLSAuthDirection\":\"\",\"mKeyPassword\":\"\",\"mUseObfs4Kcp\":false,\"mCustomConfigOptions\":\"\",\"mName\":\"mockProfile\",\"mExpectTLSCert\":false,\"mUsername\":\"\",\"mAllowLocalLAN\":false,\"mDataCiphers\":\"\",\"mSearchDomain\":\"blinkt.de\",\"mTemporaryProfile\":false,\"mUseTLSAuth\":false,\"mRemoteCN\":\"\",\"mCustomRoutesv6\":\"\",\"mPersistTun\":false,\"mX509AuthType\":3,\"mUuid\":\"9d295ca2-3789-48dd-996e-f731dbf50fdc\",\"mServerName\":\"openvpn.example.com\",\"mMssFix\":0,\"mPushPeerInfo\":false,\"mAuthenticationType\":2,\"mBlockUnusedAddressFamilies\":true,\"mServerPort\":\"1194\",\"mUseDefaultRoutev6\":true,\"mConnections\":[{\"mCustomConfiguration\":\"\",\"mUseUdp\":false,\"mServerName\":\"openvpn.example.com\",\"mProxyType\":\"NONE\",\"mProxyPort\":\"8080\",\"mUseCustomConfig\":false,\"mConnectTimeout\":0,\"mProxyName\":\"proxy.example.com\",\"mUseProxyAuth\":false,\"ConnectionAdapter.META_TYPE\":\"de.blinkt.openvpn.core.connection.OpenvpnConnection\",\"mServerPort\":\"1194\",\"mEnabled\":true}],\"mUseLzo\":false,\"mAllowAppVpnBypass\":false,\"mUsePull\":true,\"mUseRandomHostname\":false,\"mAuthRetry\":0}"; + private static final String OBFS4CONNECTION_PROFILE = "{\"mCipher\":\"\",\"mProfileVersion\":7,\"mLastUsed\":0,\"mCheckRemoteCN\":true,\"mVerb\":\"1\",\"mRemoteRandom\":false,\"mRoutenopull\":false,\"mConnectRetry\":\"2\",\"mAllowedAppsVpn\":[],\"mUserEditable\":true,\"mUseUdp\":true,\"mAllowedAppsVpnAreDisallowed\":true,\"mDNS1\":\"8.8.8.8\",\"mDNS2\":\"8.8.4.4\",\"mUseCustomConfig\":false,\"mUseFloat\":false,\"mUseDefaultRoute\":true,\"mConnectRetryMaxTime\":\"300\",\"mNobind\":true,\"mVersion\":0,\"mConnectRetryMax\":\"-1\",\"mOverrideDNS\":false,\"mAuth\":\"\",\"mTunMtu\":0,\"mUseObfs4\":true,\"mPassword\":\"\",\"mTLSAuthDirection\":\"\",\"mKeyPassword\":\"\",\"mUseObfs4Kcp\":false,\"mCustomConfigOptions\":\"\",\"mName\":\"mockProfile\",\"mExpectTLSCert\":false,\"mUsername\":\"\",\"mAllowLocalLAN\":false,\"mDataCiphers\":\"\",\"mSearchDomain\":\"blinkt.de\",\"mTemporaryProfile\":false,\"mUseTLSAuth\":false,\"mRemoteCN\":\"\",\"mCustomRoutesv6\":\"\",\"mPersistTun\":false,\"mX509AuthType\":3,\"mUuid\":\"9d295ca2-3789-48dd-996e-f731dbf50fdc\",\"mServerName\":\"openvpn.example.com\",\"mMssFix\":0,\"mPushPeerInfo\":false,\"mAuthenticationType\":2,\"mBlockUnusedAddressFamilies\":true,\"mServerPort\":\"1194\",\"mUseDefaultRoutev6\":true,\"mConnections\":[{\"mCustomConfiguration\":\"\",\"mServerName\":\"127.0.0.1\",\"mProxyType\":\"NONE\",\"mConnectTimeout\":0,\"mServerPort\":\"4430\",\"mUseUdp\":false,\"mProxyPort\":\"\",\"mUseCustomConfig\":false,\"options\":{\"udp\":false,\"remoteIP\":\"192.168.0.1\",\"iatMode\":\"1\",\"remotePort\":\"1234\",\"cert\":\"CERT\"},\"mProxyName\":\"\",\"mUseProxyAuth\":false,\"ConnectionAdapter.META_TYPE\":\"de.blinkt.openvpn.core.connection.Obfs4Connection\",\"mEnabled\":true}],\"mUseLzo\":false,\"mAllowAppVpnBypass\":false,\"mUsePull\":true,\"mUseRandomHostname\":false,\"mAuthRetry\":0}"; + private static final String OBFS4CONNECTION_PROFILE_OBFSVPN = "{\"mCipher\":\"\",\"mProfileVersion\":7,\"mLastUsed\":0,\"mCheckRemoteCN\":true,\"mVerb\":\"1\",\"mRemoteRandom\":false,\"mRoutenopull\":false,\"mConnectRetry\":\"2\",\"mAllowedAppsVpn\":[],\"mUserEditable\":true,\"mUseUdp\":true,\"mAllowedAppsVpnAreDisallowed\":true,\"mDNS1\":\"8.8.8.8\",\"mDNS2\":\"8.8.4.4\",\"mUseCustomConfig\":false,\"mUseFloat\":false,\"mUseDefaultRoute\":true,\"mConnectRetryMaxTime\":\"300\",\"mNobind\":true,\"mVersion\":0,\"mConnectRetryMax\":\"-1\",\"mOverrideDNS\":false,\"mAuth\":\"\",\"mTunMtu\":0,\"mUseObfs4\":true,\"mPassword\":\"\",\"mTLSAuthDirection\":\"\",\"mKeyPassword\":\"\",\"mUseObfs4Kcp\":false,\"mCustomConfigOptions\":\"\",\"mName\":\"mockProfile\",\"mExpectTLSCert\":false,\"mUsername\":\"\",\"mAllowLocalLAN\":false,\"mDataCiphers\":\"\",\"mSearchDomain\":\"blinkt.de\",\"mTemporaryProfile\":false,\"mUseTLSAuth\":false,\"mRemoteCN\":\"\",\"mCustomRoutesv6\":\"\",\"mPersistTun\":false,\"mX509AuthType\":3,\"mUuid\":\"9d295ca2-3789-48dd-996e-f731dbf50fdc\",\"mServerName\":\"openvpn.example.com\",\"mMssFix\":0,\"mPushPeerInfo\":false,\"mAuthenticationType\":2,\"mBlockUnusedAddressFamilies\":true,\"mServerPort\":\"1194\",\"mUseDefaultRoutev6\":true,\"mConnections\":[{\"mCustomConfiguration\":\"\",\"mServerName\":\"192.168.0.1\",\"mProxyType\":\"SOCKS5\",\"mConnectTimeout\":0,\"mServerPort\":\"1234\",\"mUseUdp\":false,\"mProxyPort\":\"4430\",\"mUseCustomConfig\":false,\"options\":{\"udp\":false,\"remoteIP\":\"192.168.0.1\",\"iatMode\":\"1\",\"remotePort\":\"1234\",\"cert\":\"CERT\"},\"mProxyName\":\"127.0.0.1\",\"mUseProxyAuth\":false,\"ConnectionAdapter.META_TYPE\":\"de.blinkt.openvpn.core.connection.Obfs4Connection\",\"mEnabled\":true}],\"mUseLzo\":false,\"mAllowAppVpnBypass\":false,\"mUsePull\":true,\"mUseRandomHostname\":false,\"mAuthRetry\":0}"; + private static final String OBFS4CONNECTION_PROFILE_OBFSVPN_KCP = "{\"mCipher\":\"\",\"mProfileVersion\":7,\"mLastUsed\":0,\"mCheckRemoteCN\":true,\"mVerb\":\"1\",\"mRemoteRandom\":false,\"mRoutenopull\":false,\"mConnectRetry\":\"2\",\"mAllowedAppsVpn\":[],\"mUserEditable\":true,\"mUseUdp\":true,\"mAllowedAppsVpnAreDisallowed\":true,\"mDNS1\":\"8.8.8.8\",\"mDNS2\":\"8.8.4.4\",\"mUseCustomConfig\":false,\"mUseFloat\":false,\"mUseDefaultRoute\":true,\"mConnectRetryMaxTime\":\"300\",\"mNobind\":true,\"mVersion\":0,\"mConnectRetryMax\":\"-1\",\"mOverrideDNS\":false,\"mAuth\":\"\",\"mTunMtu\":0,\"mUseObfs4\":false,\"mPassword\":\"\",\"mTLSAuthDirection\":\"\",\"mKeyPassword\":\"\",\"mUseObfs4Kcp\":true,\"mCustomConfigOptions\":\"\",\"mName\":\"mockProfile\",\"mExpectTLSCert\":false,\"mUsername\":\"\",\"mAllowLocalLAN\":false,\"mDataCiphers\":\"\",\"mSearchDomain\":\"blinkt.de\",\"mTemporaryProfile\":false,\"mUseTLSAuth\":false,\"mRemoteCN\":\"\",\"mCustomRoutesv6\":\"\",\"mPersistTun\":false,\"mX509AuthType\":3,\"mUuid\":\"9d295ca2-3789-48dd-996e-f731dbf50fdc\",\"mServerName\":\"openvpn.example.com\",\"mMssFix\":0,\"mPushPeerInfo\":false,\"mAuthenticationType\":2,\"mBlockUnusedAddressFamilies\":true,\"mServerPort\":\"1194\",\"mUseDefaultRoutev6\":true,\"mConnections\":[{\"mCustomConfiguration\":\"\",\"mServerName\":\"192.168.0.1\",\"mProxyType\":\"SOCKS5\",\"mConnectTimeout\":0,\"mServerPort\":\"1234\",\"mUseUdp\":false,\"mProxyPort\":\"4430\",\"mUseCustomConfig\":false,\"options\":{\"udp\":true,\"remoteIP\":\"192.168.0.1\",\"iatMode\":\"1\",\"remotePort\":\"1234\",\"cert\":\"CERT\"},\"mProxyName\":\"127.0.0.1\",\"mUseProxyAuth\":false,\"ConnectionAdapter.META_TYPE\":\"de.blinkt.openvpn.core.connection.Obfs4Connection\",\"mEnabled\":true}],\"mUseLzo\":false,\"mAllowAppVpnBypass\":false,\"mUsePull\":true,\"mUseRandomHostname\":false,\"mAuthRetry\":0}\n"; + @Before public void setup() { mockStatic(UUID.class); + mockStatic(ConfigHelper.ObfsVpnHelper.class); } @Test @@ -58,9 +69,10 @@ public class VpnProfileTest { @Test public void toJson_obfs4() throws JSONException { + when(ConfigHelper.ObfsVpnHelper.useObfsVpn()).thenReturn(false); + VpnProfile mockVpnProfile = new VpnProfile("mockProfile", OBFS4); - mockVpnProfile.mConnections[0] = new Obfs4Connection(new Obfs4Options("192.168.0.1", "1234", "CERT", "1")); - mockVpnProfile.mConnections[0].setUseUdp(false); + mockVpnProfile.mConnections[0] = new Obfs4Connection(new Obfs4Options("192.168.0.1", "1234", "CERT", "1", false)); mockVpnProfile.mLastUsed = 0; String s = mockVpnProfile.toJson(); System.out.println(s); @@ -73,18 +85,92 @@ public class VpnProfileTest { assertEquals(expectation.toString(),actual.toString()); } + @Test + public void toJson_obfs4_obfsvpn() throws JSONException { + when(ConfigHelper.ObfsVpnHelper.useObfsVpn()).thenReturn(true); + VpnProfile mockVpnProfile = new VpnProfile("mockProfile", OBFS4); + mockVpnProfile.mConnections[0] = new Obfs4Connection(new Obfs4Options("192.168.0.1", "1234", "CERT", "1", false)); + mockVpnProfile.mLastUsed = 0; + String s = mockVpnProfile.toJson(); + System.out.println(s); + + //ignore UUID in comparison -> set it to fixed value + JSONObject actual = new JSONObject(s); + actual.put("mUuid", "9d295ca2-3789-48dd-996e-f731dbf50fdc"); + JSONObject expectation = new JSONObject(OBFS4CONNECTION_PROFILE_OBFSVPN); + + assertEquals(expectation.toString(),actual.toString()); + } + + @Test + public void toJson_obfs4_obfsvpn_kcp() throws JSONException { + when(ConfigHelper.ObfsVpnHelper.useObfsVpn()).thenReturn(true); + + VpnProfile mockVpnProfile = new VpnProfile("mockProfile", OBFS4_KCP); + mockVpnProfile.mConnections[0] = new Obfs4Connection(new Obfs4Options("192.168.0.1", "1234", "CERT", "1", true)); + mockVpnProfile.mLastUsed = 0; + String s = mockVpnProfile.toJson(); + System.out.println(s); + + //ignore UUID in comparison -> set it to fixed value + JSONObject actual = new JSONObject(s); + actual.put("mUuid", "9d295ca2-3789-48dd-996e-f731dbf50fdc"); + JSONObject expectation = new JSONObject(OBFS4CONNECTION_PROFILE_OBFSVPN_KCP); + + assertEquals(expectation.toString(),actual.toString()); + } + @Test public void fromJson_obfs4() { + when(ConfigHelper.ObfsVpnHelper.useObfsVpn()).thenReturn(false); + VpnProfile mockVpnProfile = VpnProfile.fromJson(OBFS4CONNECTION_PROFILE); assertNotNull(mockVpnProfile); assertNotNull(mockVpnProfile.mConnections); assertNotNull(mockVpnProfile.mConnections[0]); assertFalse(mockVpnProfile.mConnections[0].isUseUdp()); Obfs4Connection obfs4Connection = (Obfs4Connection) mockVpnProfile.mConnections[0]; - assertEquals(obfs4Connection.getTransportType(), OBFS4); - assertEquals(obfs4Connection.getDispatcherOptions().cert, "CERT"); - assertEquals(obfs4Connection.getDispatcherOptions().iatMode, "1"); - assertEquals(obfs4Connection.getDispatcherOptions().remoteIP, "192.168.0.1"); - assertEquals(obfs4Connection.getDispatcherOptions().remotePort, "1234"); + assertEquals(OBFS4, obfs4Connection.getTransportType()); + assertFalse(obfs4Connection.getDispatcherOptions().udp); + assertEquals("CERT", obfs4Connection.getDispatcherOptions().cert); + assertEquals("1", obfs4Connection.getDispatcherOptions().iatMode); + assertEquals("192.168.0.1", obfs4Connection.getDispatcherOptions().remoteIP); + assertEquals("1234", obfs4Connection.getDispatcherOptions().remotePort); + } + + @Test + public void fromJson_obfs4_obfsvpn() { + when(ConfigHelper.ObfsVpnHelper.useObfsVpn()).thenReturn(true); + + VpnProfile mockVpnProfile = VpnProfile.fromJson(OBFS4CONNECTION_PROFILE_OBFSVPN); + assertNotNull(mockVpnProfile); + assertNotNull(mockVpnProfile.mConnections); + assertNotNull(mockVpnProfile.mConnections[0]); + assertFalse(mockVpnProfile.mConnections[0].isUseUdp()); + Obfs4Connection obfs4Connection = (Obfs4Connection) mockVpnProfile.mConnections[0]; + assertEquals(OBFS4, obfs4Connection.getTransportType()); + assertFalse(obfs4Connection.getDispatcherOptions().udp); + assertEquals("CERT", obfs4Connection.getDispatcherOptions().cert); + assertEquals("1", obfs4Connection.getDispatcherOptions().iatMode); + assertEquals("192.168.0.1", obfs4Connection.getDispatcherOptions().remoteIP); + assertEquals("1234", obfs4Connection.getDispatcherOptions().remotePort); + } + + @Test + public void fromJson_obfs4_obfsvpn_kcp() { + when(ConfigHelper.ObfsVpnHelper.useObfsVpn()).thenReturn(true); + + VpnProfile mockVpnProfile = VpnProfile.fromJson(OBFS4CONNECTION_PROFILE_OBFSVPN_KCP); + assertNotNull(mockVpnProfile); + assertNotNull(mockVpnProfile.mConnections); + assertNotNull(mockVpnProfile.mConnections[0]); + assertFalse(mockVpnProfile.mConnections[0].isUseUdp()); + Obfs4Connection obfs4Connection = (Obfs4Connection) mockVpnProfile.mConnections[0]; + assertEquals(OBFS4, obfs4Connection.getTransportType()); + assertTrue(obfs4Connection.getDispatcherOptions().udp); + assertEquals("CERT", obfs4Connection.getDispatcherOptions().cert); + assertEquals("1", obfs4Connection.getDispatcherOptions().iatMode); + assertEquals("192.168.0.1", obfs4Connection.getDispatcherOptions().remoteIP); + assertEquals("1234", obfs4Connection.getDispatcherOptions().remotePort); } } \ No newline at end of file diff --git a/app/src/test/java/se/leap/bitmaskclient/base/models/GatewayJsonTest.java b/app/src/test/java/se/leap/bitmaskclient/base/models/GatewayJsonTest.java new file mode 100644 index 0000000000000000000000000000000000000000..612753781d5e17048579d0ad269a64e5db7bf9c3 --- /dev/null +++ b/app/src/test/java/se/leap/bitmaskclient/base/models/GatewayJsonTest.java @@ -0,0 +1,29 @@ +package se.leap.bitmaskclient.base.models; + +import static org.junit.Assert.assertEquals; +import static de.blinkt.openvpn.core.connection.Connection.TransportType.OBFS4; +import static se.leap.bitmaskclient.eip.GatewaysManager.PINNED_OBFUSCATION_PROXY; + +import org.junit.Test; + +import de.blinkt.openvpn.core.connection.Connection; + +public class GatewayJsonTest { + + @Test + public void testToString() { + String gatewayJSON = "{\"location\":\"Unknown Location\",\"ip_address\":\"1.2.3.4\",\"host\":\"pinned.obfuscation.proxy\",\"capabilities\":{\"adblock\":false,\"filter_dns\":false,\"limited\":false,\"transport\":[{\"type\":\"obfs4\",\"protocols\":[\"tcp\"],\"ports\":[\"1194\"],\"options\":{\"cert\":\"xxxxxxx\",\"iatMode\":\"0\"}}],\"user_ips\":false}}"; + + Connection.TransportType transportType = OBFS4; + Transport[] transports = new Transport[]{ + new Transport(transportType.toString(), + new String[]{"tcp"}, + new String[]{"1194"}, + "xxxxxxx")}; + GatewayJson.Capabilities capabilities = new GatewayJson.Capabilities(false, false, false, transports, false); + GatewayJson gatewayJson = new GatewayJson("Unknown Location", "1.2.3.4", null, PINNED_OBFUSCATION_PROXY, capabilities); + + assertEquals(gatewayJSON, gatewayJson.toString()); + } + +} \ No newline at end of file diff --git a/app/src/test/java/se/leap/bitmaskclient/base/models/ProviderTest.java b/app/src/test/java/se/leap/bitmaskclient/base/models/ProviderTest.java index aaf3f255fc8a242adb5cb557e8fae8619df495ab..8bff690ba2929eb5b30f967253fe4006a83a9713 100644 --- a/app/src/test/java/se/leap/bitmaskclient/base/models/ProviderTest.java +++ b/app/src/test/java/se/leap/bitmaskclient/base/models/ProviderTest.java @@ -1,21 +1,36 @@ package se.leap.bitmaskclient.base.models; +import static junit.framework.Assert.assertFalse; +import static org.junit.Assert.assertTrue; +import static org.mockito.Mockito.when; +import static org.powermock.api.mockito.PowerMockito.mockStatic; + +import org.junit.Before; import org.junit.Test; +import org.junit.runner.RunWith; +import org.powermock.core.classloader.annotations.PrepareForTest; +import org.powermock.modules.junit4.PowerMockRunner; import java.util.HashSet; import java.util.Set; -import se.leap.bitmaskclient.base.models.Provider; +import se.leap.bitmaskclient.base.utils.ConfigHelper; import se.leap.bitmaskclient.testutils.TestSetupHelper; -import static junit.framework.Assert.assertFalse; -import static org.junit.Assert.assertTrue; - /** * Created by cyberta on 12.02.18. */ + +@RunWith(PowerMockRunner.class) +@PrepareForTest({ConfigHelper.ObfsVpnHelper.class}) public class ProviderTest { + @Before + public void setup() { + mockStatic(ConfigHelper.ObfsVpnHelper.class); + when(ConfigHelper.ObfsVpnHelper.useObfsVpn()).thenReturn(false); + } + @Test public void testEquals_sameFields_returnsTrue() throws Exception { Provider p1 = TestSetupHelper.getConfiguredProvider(); @@ -84,4 +99,64 @@ public class ProviderTest { assertFalse(p1.supportsPluggableTransports()); } + @Test + public void testIsExperimentalPluggableTransportsSupported_Obfs4_returnsFalse() throws Exception { + Provider p1 = TestSetupHelper.getProvider( + "https://pt.demo.bitmask.net", + null, + null, + null, + null, + null, + "ptdemo.bitmask.eip-service.json", + null); + assertFalse(p1.supportsExperimentalPluggableTransports()); + } + + @Test + public void testIsExperimentalPluggableTransportsSupported_Obfs4Kcp_returnsTrue() throws Exception { + Provider p1 = TestSetupHelper.getProvider( + "https://pt.demo.bitmask.net", + null, + null, + null, + null, + null, + "ptdemo_kcp_gateways.json", + null); + assertTrue(p1.supportsExperimentalPluggableTransports()); + } + + @Test + public void testSupportsPluggableTransports_Obfs4Kcp_noObsvpn_returnsFalse() throws Exception { + when(ConfigHelper.ObfsVpnHelper.useObfsVpn()).thenReturn(false); + + Provider p1 = TestSetupHelper.getProvider( + "https://pt.demo.bitmask.net", + null, + null, + null, + null, + null, + "ptdemo_only_experimental_transports_gateways.json", + null); + assertFalse(p1.supportsPluggableTransports()); + } + + @Test + public void testSupportsPluggableTransports_Obfs4Kcp_obsvpn_returnsTrue() throws Exception { + when(ConfigHelper.ObfsVpnHelper.useObfsVpn()).thenReturn(true); + + Provider p1 = TestSetupHelper.getProvider( + "https://pt.demo.bitmask.net", + null, + null, + null, + null, + null, + "ptdemo_only_experimental_transports_gateways.json", + null); + assertTrue(p1.supportsPluggableTransports()); + } + } diff --git a/app/src/test/java/se/leap/bitmaskclient/base/utils/ConfigHelperTest.java b/app/src/test/java/se/leap/bitmaskclient/base/utils/ConfigHelperTest.java index 75552226d09d2fdd93c5698cb6c3313e5abaea68..6e0ceb56a65704bb00ff63af98b4bd93a8fccf37 100644 --- a/app/src/test/java/se/leap/bitmaskclient/base/utils/ConfigHelperTest.java +++ b/app/src/test/java/se/leap/bitmaskclient/base/utils/ConfigHelperTest.java @@ -1,5 +1,7 @@ package se.leap.bitmaskclient.base.utils; +import static org.junit.Assert.assertEquals; + import com.tngtech.java.junit.dataprovider.DataProvider; import com.tngtech.java.junit.dataprovider.DataProviderRunner; import com.tngtech.java.junit.dataprovider.UseDataProvider; @@ -9,8 +11,6 @@ import org.junit.runner.RunWith; import org.powermock.modules.junit4.PowerMockRunner; import org.powermock.modules.junit4.PowerMockRunnerDelegate; -import static org.junit.Assert.assertEquals; - @RunWith(PowerMockRunner.class) @PowerMockRunnerDelegate(DataProviderRunner.class) public class ConfigHelperTest { @@ -45,4 +45,16 @@ public class ConfigHelperTest { public void testisIPv4_validIPs_returnsTrue(String ip, boolean isValidExpected) { assertEquals(isValidExpected, ConfigHelper.isIPv4(ip)); } + + @Test + public void testGetDomainFromMainURL_ignoreSubdomain() { + assertEquals("riseup.net", ConfigHelper.getDomainFromMainURL("https://black.riseup.net")); + assertEquals("riseup.net", ConfigHelper.getDomainFromMainURL("https://riseup.net")); + } + + @Test + public void testGetDomainFromMainURL_handleSuffix() { + assertEquals("domain.co.uk", ConfigHelper.getDomainFromMainURL("https://subdomain.domain.co.uk")); + assertEquals("domain.co.uk", ConfigHelper.getDomainFromMainURL("https://domain.co.uk")); + } } \ No newline at end of file diff --git a/app/src/test/java/se/leap/bitmaskclient/base/utils/DateHelperTest.java b/app/src/test/java/se/leap/bitmaskclient/base/utils/DateHelperTest.java new file mode 100644 index 0000000000000000000000000000000000000000..2651a64d058834a20860f6ad32326a66e8ca764f --- /dev/null +++ b/app/src/test/java/se/leap/bitmaskclient/base/utils/DateHelperTest.java @@ -0,0 +1,20 @@ +package se.leap.bitmaskclient.base.utils; + +import static org.junit.Assert.*; + +import org.junit.Test; + +import java.util.regex.Matcher; +import java.util.regex.Pattern; + +public class DateHelperTest { + + @Test + public void getFormattedDateWithTimezone() { + Pattern datePattern = Pattern.compile("^10 Nov 22 [1]?[0-9]:26 [+-][0-9]{4}$"); + String formattedDate = DateHelper.getFormattedDateWithTimezone(1668075969744L); + Matcher matcher = datePattern.matcher(formattedDate); + System.out.println(formattedDate); + assertTrue("date should be formatted similar to 10 Nov 22 11:26 +0100", matcher.find()); + } +} \ No newline at end of file diff --git a/app/src/test/java/se/leap/bitmaskclient/eip/GatewaysManagerTest.java b/app/src/test/java/se/leap/bitmaskclient/eip/GatewaysManagerTest.java index 729abcdf8b2e7750970912ac63deac9a611ae904..3b0d5552727705cfdb10db2c9de5a1ba9238fd82 100644 --- a/app/src/test/java/se/leap/bitmaskclient/eip/GatewaysManagerTest.java +++ b/app/src/test/java/se/leap/bitmaskclient/eip/GatewaysManagerTest.java @@ -22,6 +22,7 @@ import de.blinkt.openvpn.VpnProfile; import de.blinkt.openvpn.core.ConfigParser; import de.blinkt.openvpn.core.connection.Connection; import se.leap.bitmaskclient.base.models.Location; +import se.leap.bitmaskclient.base.models.Pair; import se.leap.bitmaskclient.base.models.Provider; import se.leap.bitmaskclient.base.models.ProviderObservable; import se.leap.bitmaskclient.base.utils.ConfigHelper; @@ -31,6 +32,7 @@ import se.leap.bitmaskclient.testutils.MockSharedPreferences; import se.leap.bitmaskclient.testutils.TestSetupHelper; import static de.blinkt.openvpn.core.connection.Connection.TransportType.OBFS4; +import static de.blinkt.openvpn.core.connection.Connection.TransportType.OBFS4_KCP; import static de.blinkt.openvpn.core.connection.Connection.TransportType.OPENVPN; import static junit.framework.Assert.assertEquals; import static junit.framework.Assert.assertNull; @@ -115,9 +117,11 @@ public class GatewaysManagerTest { MockHelper.mockProviderObservable(provider); GatewaysManager gatewaysManager = new GatewaysManager(mockContext); - VpnConfigGenerator configGenerator = new VpnConfigGenerator(provider.getDefinition(), secrets, gateway1, 3, false); + VpnConfigGenerator.Configuration configuration = new VpnConfigGenerator.Configuration(); + configuration.apiVersion = 3; + configuration.remoteGatewayIP = "37.218.247.60"; + VpnConfigGenerator configGenerator = new VpnConfigGenerator(provider.getDefinition(), secrets, gateway1, configuration); VpnProfile profile = configGenerator.createProfile(OBFS4); - profile.mGatewayIp = "37.218.247.60"; assertEquals(0, gatewaysManager.getPosition(profile)); } @@ -130,9 +134,11 @@ public class GatewaysManagerTest { MockHelper.mockProviderObservable(provider); GatewaysManager gatewaysManager = new GatewaysManager(mockContext); - VpnConfigGenerator configGenerator = new VpnConfigGenerator(provider.getDefinition(), secrets, gateway1, 3, false); + VpnConfigGenerator.Configuration configuration = new VpnConfigGenerator.Configuration(); + configuration.apiVersion = 3; + configuration.remoteGatewayIP = "37.218.247.60"; + VpnConfigGenerator configGenerator = new VpnConfigGenerator(provider.getDefinition(), secrets, gateway1, configuration); VpnProfile profile = configGenerator.createProfile(OPENVPN); - profile.mGatewayIp = "37.218.247.60"; assertEquals(0, gatewaysManager.getPosition(profile)); } @@ -145,9 +151,11 @@ public class GatewaysManagerTest { MockHelper.mockProviderObservable(provider); GatewaysManager gatewaysManager = new GatewaysManager(mockContext); - VpnConfigGenerator configGenerator = new VpnConfigGenerator(provider.getDefinition(), secrets, gateway1, 3, false); + VpnConfigGenerator.Configuration configuration = new VpnConfigGenerator.Configuration(); + configuration.apiVersion = 3; + configuration.remoteGatewayIP = "37.218.247.60"; + VpnConfigGenerator configGenerator = new VpnConfigGenerator(provider.getDefinition(), secrets, gateway1, configuration); VpnProfile profile = configGenerator.createProfile(OBFS4); - profile.mGatewayIp = "37.218.247.60"; assertEquals(1, gatewaysManager.getPosition(profile)); } @@ -160,9 +168,11 @@ public class GatewaysManagerTest { MockHelper.mockProviderObservable(provider); GatewaysManager gatewaysManager = new GatewaysManager(mockContext); - VpnConfigGenerator configGenerator = new VpnConfigGenerator(provider.getDefinition(), secrets, gateway1, 3, false); + VpnConfigGenerator.Configuration configuration = new VpnConfigGenerator.Configuration(); + configuration.apiVersion = 3; + configuration.remoteGatewayIP = "37.218.247.60"; + VpnConfigGenerator configGenerator = new VpnConfigGenerator(provider.getDefinition(), secrets, gateway1, configuration); VpnProfile profile = configGenerator.createProfile(OPENVPN); - profile.mGatewayIp = "37.218.247.60"; assertEquals(2, gatewaysManager.getPosition(profile)); } @@ -175,9 +185,11 @@ public class GatewaysManagerTest { MockHelper.mockProviderObservable(provider); GatewaysManager gatewaysManager = new GatewaysManager(mockContext); - VpnConfigGenerator configGenerator = new VpnConfigGenerator(provider.getDefinition(), secrets, gateway1, 3, false); + VpnConfigGenerator.Configuration configuration = new VpnConfigGenerator.Configuration(); + configuration.apiVersion = 3; + configuration.remoteGatewayIP = "37.218.247.61"; + VpnConfigGenerator configGenerator = new VpnConfigGenerator(provider.getDefinition(), secrets, gateway1, configuration); VpnProfile profile = configGenerator.createProfile(OBFS4); - profile.mGatewayIp = "37.218.247.61"; assertEquals(-1, gatewaysManager.getPosition(profile)); } @@ -190,9 +202,11 @@ public class GatewaysManagerTest { MockHelper.mockProviderObservable(provider); GatewaysManager gatewaysManager = new GatewaysManager(mockContext); - VpnConfigGenerator configGenerator = new VpnConfigGenerator(provider.getDefinition(), secrets, gateway1, 3, false); + VpnConfigGenerator.Configuration configuration = new VpnConfigGenerator.Configuration(); + configuration.apiVersion = 3; + configuration.remoteGatewayIP = "3.21.247.89"; + VpnConfigGenerator configGenerator = new VpnConfigGenerator(provider.getDefinition(), secrets, gateway1, configuration); VpnProfile profile = configGenerator.createProfile(OBFS4); - profile.mGatewayIp = "3.21.247.89"; assertEquals(1, gatewaysManager.getPosition(profile)); } @@ -206,7 +220,7 @@ public class GatewaysManagerTest { when(PreferenceHelper.getUseBridges(any(Context.class))).thenReturn(true); GatewaysManager gatewaysManager = new GatewaysManager(mockContext); - assertEquals("37.12.247.10", gatewaysManager.select(0).getRemoteIP()); + assertEquals("37.12.247.10", gatewaysManager.select(0).first.getRemoteIP()); } @Test @@ -219,9 +233,9 @@ public class GatewaysManagerTest { when(PreferenceHelper.getUseBridges(any(Context.class))).thenReturn(false); GatewaysManager gatewaysManager = new GatewaysManager(mockContext); - assertEquals("manila.bitmask.net", gatewaysManager.select(0).getHost()); - assertEquals("moscow.bitmask.net", gatewaysManager.select(1).getHost()); - assertEquals("pt.demo.bitmask.net", gatewaysManager.select(2).getHost()); + assertEquals("manila.bitmask.net", gatewaysManager.select(0).first.getHost()); + assertEquals("moscow.bitmask.net", gatewaysManager.select(1).first.getHost()); + assertEquals("pt.demo.bitmask.net", gatewaysManager.select(2).first.getHost()); } @Test @@ -234,8 +248,8 @@ public class GatewaysManagerTest { when(PreferenceHelper.getUseBridges(any(Context.class))).thenReturn(true); GatewaysManager gatewaysManager = new GatewaysManager(mockContext); - assertEquals("moscow.bitmask.net", gatewaysManager.select(0).getHost()); - assertEquals("pt.demo.bitmask.net", gatewaysManager.select(1).getHost()); + assertEquals("moscow.bitmask.net", gatewaysManager.select(0).first.getHost()); + assertEquals("pt.demo.bitmask.net", gatewaysManager.select(1).first.getHost()); assertNull(gatewaysManager.select(2)); } @@ -251,9 +265,9 @@ public class GatewaysManagerTest { when(PreferenceHelper.getPreferredCity(any(Context.class))).thenReturn("Paris"); GatewaysManager gatewaysManager = new GatewaysManager(mockContext); - assertEquals("mouette.riseup.net", gatewaysManager.select(0).getHost()); - assertEquals("hoatzin.riseup.net", gatewaysManager.select(1).getHost()); - assertEquals("zarapito.riseup.net", gatewaysManager.select(2).getHost()); + assertEquals("mouette.riseup.net", gatewaysManager.select(0).first.getHost()); + assertEquals("hoatzin.riseup.net", gatewaysManager.select(1).first.getHost()); + assertEquals("zarapito.riseup.net", gatewaysManager.select(2).first.getHost()); } @Test @@ -267,9 +281,9 @@ public class GatewaysManagerTest { when(PreferenceHelper.getPreferredCity(any(Context.class))).thenReturn("Paris"); GatewaysManager gatewaysManager = new GatewaysManager(mockContext); - assertEquals("mouette.riseup.net", gatewaysManager.select(0).getHost()); - assertEquals("hoatzin.riseup.net", gatewaysManager.select(1).getHost()); - assertEquals("zarapito.riseup.net", gatewaysManager.select(2).getHost()); + assertEquals("mouette.riseup.net", gatewaysManager.select(0).first.getHost()); + assertEquals("hoatzin.riseup.net", gatewaysManager.select(1).first.getHost()); + assertEquals("zarapito.riseup.net", gatewaysManager.select(2).first.getHost()); } @Test @@ -284,9 +298,9 @@ public class GatewaysManagerTest { when(PreferenceHelper.getPreferredCity(any(Context.class))).thenReturn("Paris"); GatewaysManager gatewaysManager = new GatewaysManager(mockContext); - assertEquals("Paris", gatewaysManager.select(0).getName()); - assertEquals("Paris", gatewaysManager.select(1).getName()); - assertEquals("Paris", gatewaysManager.select(2).getName()); + assertEquals("Paris", gatewaysManager.select(0).first.getName()); + assertEquals("Paris", gatewaysManager.select(1).first.getName()); + assertEquals("Paris", gatewaysManager.select(2).first.getName()); assertEquals(null, gatewaysManager.select(3)); } @@ -300,9 +314,9 @@ public class GatewaysManagerTest { when(PreferenceHelper.getUseBridges(any(Context.class))).thenReturn(false); GatewaysManager gatewaysManager = new GatewaysManager(mockContext); - assertEquals("mouette.riseup.net", gatewaysManager.select(0, "Paris").getHost()); - assertEquals("hoatzin.riseup.net", gatewaysManager.select(1, "Paris").getHost()); - assertEquals("zarapito.riseup.net", gatewaysManager.select(2, "Paris").getHost()); + assertEquals("mouette.riseup.net", gatewaysManager.select(0, "Paris").first.getHost()); + assertEquals("hoatzin.riseup.net", gatewaysManager.select(1, "Paris").first.getHost()); + assertEquals("zarapito.riseup.net", gatewaysManager.select(2, "Paris").first.getHost()); } @Test @@ -315,9 +329,9 @@ public class GatewaysManagerTest { when(PreferenceHelper.getUseBridges(any(Context.class))).thenReturn(false); GatewaysManager gatewaysManager = new GatewaysManager(mockContext); - assertEquals("mouette.riseup.net", gatewaysManager.select(0, "Paris").getHost()); - assertEquals("hoatzin.riseup.net", gatewaysManager.select(1, "Paris").getHost()); - assertEquals("zarapito.riseup.net", gatewaysManager.select(2, "Paris").getHost()); + assertEquals("mouette.riseup.net", gatewaysManager.select(0, "Paris").first.getHost()); + assertEquals("hoatzin.riseup.net", gatewaysManager.select(1, "Paris").first.getHost()); + assertEquals("zarapito.riseup.net", gatewaysManager.select(2, "Paris").first.getHost()); } @Test @@ -331,9 +345,9 @@ public class GatewaysManagerTest { when(PreferenceHelper.getUseBridges(any(Context.class))).thenReturn(false); GatewaysManager gatewaysManager = new GatewaysManager(mockContext); - assertEquals("Paris", gatewaysManager.select(0, "Paris").getName()); - assertEquals("Paris", gatewaysManager.select(1, "Paris").getName()); - assertEquals("Paris", gatewaysManager.select(2, "Paris").getName()); + assertEquals("Paris", gatewaysManager.select(0, "Paris").first.getName()); + assertEquals("Paris", gatewaysManager.select(1, "Paris").first.getName()); + assertEquals("Paris", gatewaysManager.select(2, "Paris").first.getName()); assertEquals(null, gatewaysManager.select(3, "Paris")); } @@ -509,6 +523,38 @@ public class GatewaysManagerTest { assertEquals("Amsterdam", locations.get(2).getName()); } + // Currently all pluggable transports are handled the same, there's no UI to select a specific one + // when requesting a sorted list for any pluggabled transport, a sorted list of all pluiggable transports + // will be returned + @Test + public void testGetSortedLocations_obfs4kcp_generalizedAsPT() { + Provider provider = getProvider(null, null, null, null, null, null, "v4/riseup_eipservice_for_geoip_v4.json", "v4/riseup_geoip_v4_bad_obfs4_gateway.json"); + + MockHelper.mockProviderObservable(provider); + mockStatic(PreferenceHelper.class); + when(PreferenceHelper.getUseBridges(any(Context.class))).thenReturn(false); + GatewaysManager gatewaysManager = new GatewaysManager(mockContext); + List<Location> locations = gatewaysManager.getSortedGatewayLocations(OBFS4_KCP); + + assertEquals(3, locations.size()); + } + + @Test + public void testgetAverageLoad_isSameForAllTransports() { + Provider provider = getProvider(null, null, null, null, null, null, "ptdemo_kcp_gateways.json", "ptdemo_kcp_gateways_geoip.json"); + + MockHelper.mockProviderObservable(provider); + mockStatic(PreferenceHelper.class); + when(PreferenceHelper.getUseBridges(any(Context.class))).thenReturn(false); + GatewaysManager gatewaysManager = new GatewaysManager(mockContext); + + assertEquals(0.3, gatewaysManager.getLocation("Amsterdam").getAverageLoad(OBFS4_KCP)); + assertEquals(0.3, gatewaysManager.getLocation("Amsterdam").getAverageLoad(OBFS4)); + assertEquals(0.3, gatewaysManager.getLocation("Amsterdam").getAverageLoad(OPENVPN)); + } + + + @Test public void testGetLoadForLocation_() { MockHelper.mockProviderObservable(null); diff --git a/app/src/test/java/se/leap/bitmaskclient/eip/ProviderApiManagerTest.java b/app/src/test/java/se/leap/bitmaskclient/eip/ProviderApiManagerTest.java index 31d6ae89ae4443972f2b20ed4ea1a4c4a08df9eb..45a20b1cf6705b6bd15c301c4ff5f4708fc8752b 100644 --- a/app/src/test/java/se/leap/bitmaskclient/eip/ProviderApiManagerTest.java +++ b/app/src/test/java/se/leap/bitmaskclient/eip/ProviderApiManagerTest.java @@ -54,6 +54,7 @@ import se.leap.bitmaskclient.testutils.MockSharedPreferences; import se.leap.bitmaskclient.tor.TorStatusObservable; import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertNotEquals; import static org.mockito.Mockito.when; import static se.leap.bitmaskclient.base.models.Constants.BROADCAST_RESULT_KEY; import static se.leap.bitmaskclient.base.models.Constants.EIP_ACTION_START; @@ -61,12 +62,15 @@ import static se.leap.bitmaskclient.base.models.Constants.PROVIDER_KEY; import static se.leap.bitmaskclient.base.models.Constants.USE_BRIDGES; import static se.leap.bitmaskclient.base.models.Constants.USE_SNOWFLAKE; import static se.leap.bitmaskclient.providersetup.ProviderAPI.CORRECTLY_DOWNLOADED_GEOIP_JSON; +import static se.leap.bitmaskclient.providersetup.ProviderAPI.CORRECTLY_UPDATED_INVALID_VPN_CERTIFICATE; import static se.leap.bitmaskclient.providersetup.ProviderAPI.ERRORS; import static se.leap.bitmaskclient.providersetup.ProviderAPI.INCORRECTLY_DOWNLOADED_GEOIP_JSON; +import static se.leap.bitmaskclient.providersetup.ProviderAPI.INCORRECTLY_UPDATED_INVALID_VPN_CERTIFICATE; import static se.leap.bitmaskclient.providersetup.ProviderAPI.MISSING_NETWORK_CONNECTION; import static se.leap.bitmaskclient.providersetup.ProviderAPI.PARAMETERS; import static se.leap.bitmaskclient.providersetup.ProviderAPI.PROVIDER_NOK; import static se.leap.bitmaskclient.providersetup.ProviderAPI.PROVIDER_OK; +import static se.leap.bitmaskclient.providersetup.ProviderAPI.TOR_EXCEPTION; import static se.leap.bitmaskclient.providersetup.ProviderAPI.TOR_TIMEOUT; import static se.leap.bitmaskclient.testutils.BackendMockResponses.BackendMockProvider.TestBackendErrorCase.ERROR_CASE_FETCH_EIP_SERVICE_CERTIFICATE_INVALID; import static se.leap.bitmaskclient.testutils.BackendMockResponses.BackendMockProvider.TestBackendErrorCase.ERROR_CASE_MICONFIGURED_PROVIDER; @@ -76,10 +80,10 @@ import static se.leap.bitmaskclient.testutils.BackendMockResponses.BackendMockPr import static se.leap.bitmaskclient.testutils.BackendMockResponses.BackendMockProvider.TestBackendErrorCase.ERROR_GEOIP_SERVICE_IS_DOWN_TOR_FALLBACK; import static se.leap.bitmaskclient.testutils.BackendMockResponses.BackendMockProvider.TestBackendErrorCase.NO_ERROR; import static se.leap.bitmaskclient.testutils.BackendMockResponses.BackendMockProvider.TestBackendErrorCase.NO_ERROR_API_V4; +import static se.leap.bitmaskclient.testutils.MockHelper.mockBase64; import static se.leap.bitmaskclient.testutils.MockHelper.mockBundle; import static se.leap.bitmaskclient.testutils.MockHelper.mockClientGenerator; import static se.leap.bitmaskclient.testutils.MockHelper.mockConfigHelper; -import static se.leap.bitmaskclient.testutils.MockHelper.mockConfigHelper; import static se.leap.bitmaskclient.testutils.MockHelper.mockIntent; import static se.leap.bitmaskclient.testutils.MockHelper.mockPreferenceHelper; import static se.leap.bitmaskclient.testutils.MockHelper.mockProviderApiConnector; @@ -98,7 +102,7 @@ import static se.leap.bitmaskclient.testutils.TestSetupHelper.getProvider; */ @RunWith(PowerMockRunner.class) -@PrepareForTest({ProviderApiManager.class, TextUtils.class, ConfigHelper.class, ProviderApiConnector.class, PreferenceHelper.class, TorStatusObservable.class}) +@PrepareForTest({ProviderApiManager.class, TextUtils.class, ConfigHelper.class, ProviderApiConnector.class, PreferenceHelper.class, TorStatusObservable.class, android.util.Base64.class}) public class ProviderApiManagerTest { private SharedPreferences mockPreferences; @@ -180,6 +184,7 @@ public class ProviderApiManagerTest { providerApiCommand.setAction(ProviderAPI.SET_UP_PROVIDER); providerApiCommand.putExtra(ProviderAPI.RECEIVER_KEY, mockResultReceiver(PROVIDER_NOK, expectedResult)); providerApiCommand.putExtra(PROVIDER_KEY, provider); + providerApiCommand.putExtra(PARAMETERS, mockBundle()); providerApiManager.handleIntent(providerApiCommand); } @@ -201,6 +206,7 @@ public class ProviderApiManagerTest { providerApiCommand.putExtra(PROVIDER_KEY, provider); providerApiCommand.setAction(ProviderAPI.SET_UP_PROVIDER); providerApiCommand.putExtra(ProviderAPI.RECEIVER_KEY, mockResultReceiver(PROVIDER_OK, expectedResult)); + providerApiCommand.putExtra(PARAMETERS, mockBundle()); providerApiManager.handleIntent(providerApiCommand); } @@ -222,6 +228,7 @@ public class ProviderApiManagerTest { providerApiCommand.setAction(ProviderAPI.SET_UP_PROVIDER); providerApiCommand.putExtra(ProviderAPI.RECEIVER_KEY, mockResultReceiver(PROVIDER_OK, expectedResult)); providerApiCommand.putExtra(PROVIDER_KEY, provider); + providerApiCommand.putExtra(PARAMETERS, mockBundle()); providerApiManager.handleIntent(providerApiCommand); } @@ -243,7 +250,7 @@ public class ProviderApiManagerTest { Intent providerApiCommand = mockIntent(); providerApiCommand.setAction(ProviderAPI.SET_UP_PROVIDER); providerApiCommand.putExtra(ProviderAPI.RECEIVER_KEY, mockResultReceiver(PROVIDER_OK, expectedResult)); - + providerApiCommand.putExtra(PARAMETERS, mockBundle()); providerApiCommand.putExtra(PROVIDER_KEY, provider); providerApiManager.handleIntent(providerApiCommand); @@ -264,6 +271,7 @@ public class ProviderApiManagerTest { providerApiCommand.setAction(ProviderAPI.SET_UP_PROVIDER); providerApiCommand.putExtra(ProviderAPI.RECEIVER_KEY, mockResultReceiver(PROVIDER_NOK, expectedResult)); + providerApiCommand.putExtra(PARAMETERS, mockBundle()); providerApiCommand.putExtra(PROVIDER_KEY, provider); @@ -286,6 +294,7 @@ public class ProviderApiManagerTest { providerApiCommand.setAction(ProviderAPI.SET_UP_PROVIDER); providerApiCommand.putExtra(ProviderAPI.RECEIVER_KEY, mockResultReceiver(PROVIDER_NOK, expectedResult)); + providerApiCommand.putExtra(PARAMETERS, mockBundle()); providerApiCommand.putExtra(PROVIDER_KEY, provider); @@ -312,7 +321,7 @@ public class ProviderApiManagerTest { providerApiCommand.setAction(ProviderAPI.SET_UP_PROVIDER); providerApiCommand.putExtra(ProviderAPI.RECEIVER_KEY, mockResultReceiver(PROVIDER_NOK, expectedResult)); - + providerApiCommand.putExtra(PARAMETERS, mockBundle()); providerApiCommand.putExtra(PROVIDER_KEY, provider); providerApiManager.handleIntent(providerApiCommand); @@ -335,7 +344,7 @@ public class ProviderApiManagerTest { providerApiCommand.setAction(ProviderAPI.SET_UP_PROVIDER); providerApiCommand.putExtra(ProviderAPI.RECEIVER_KEY, mockResultReceiver(PROVIDER_NOK, expectedResult)); - + providerApiCommand.putExtra(PARAMETERS, mockBundle()); providerApiCommand.putExtra(PROVIDER_KEY, provider); providerApiManager.handleIntent(providerApiCommand); @@ -359,7 +368,7 @@ public class ProviderApiManagerTest { providerApiCommand.setAction(ProviderAPI.SET_UP_PROVIDER); providerApiCommand.putExtra(ProviderAPI.RECEIVER_KEY, mockResultReceiver(PROVIDER_NOK, expectedResult)); - + providerApiCommand.putExtra(PARAMETERS, mockBundle()); providerApiCommand.putExtra(PROVIDER_KEY, provider); providerApiManager.handleIntent(providerApiCommand); @@ -382,6 +391,7 @@ public class ProviderApiManagerTest { providerApiCommand.setAction(ProviderAPI.SET_UP_PROVIDER); providerApiCommand.putExtra(ProviderAPI.RECEIVER_KEY, mockResultReceiver(PROVIDER_NOK, expectedResult)); + providerApiCommand.putExtra(PARAMETERS, mockBundle()); providerApiCommand.putExtra(PROVIDER_KEY, provider); @@ -407,6 +417,7 @@ public class ProviderApiManagerTest { providerApiCommand.setAction(ProviderAPI.SET_UP_PROVIDER); providerApiCommand.putExtra(ProviderAPI.RECEIVER_KEY, mockResultReceiver(PROVIDER_NOK, expectedResult)); + providerApiCommand.putExtra(PARAMETERS, mockBundle()); providerApiCommand.putExtra(PROVIDER_KEY, provider); @@ -427,12 +438,12 @@ public class ProviderApiManagerTest { expectedResult.putString(ERRORS, "{\"errors\":\"There was an error configuring Bitmask with your chosen provider.\"}"); expectedResult.putParcelable(PROVIDER_KEY, provider); - Intent providerApiCommand = mockIntent(); providerApiCommand.putExtra(PROVIDER_KEY, provider); providerApiCommand.setAction(ProviderAPI.SET_UP_PROVIDER); providerApiCommand.putExtra(ProviderAPI.RECEIVER_KEY, mockResultReceiver(PROVIDER_NOK, expectedResult)); + providerApiCommand.putExtra(PARAMETERS, mockBundle()); providerApiManager.handleIntent(providerApiCommand); } @@ -455,12 +466,12 @@ public class ProviderApiManagerTest { expectedResult.putString(ERRORS, "{\"errors\":\"There was an error configuring RiseupVPN.\"}"); expectedResult.putParcelable(PROVIDER_KEY, provider); - Intent providerApiCommand = mockIntent(); providerApiCommand.putExtra(PROVIDER_KEY, provider); providerApiCommand.setAction(ProviderAPI.SET_UP_PROVIDER); providerApiCommand.putExtra(ProviderAPI.RECEIVER_KEY, mockResultReceiver(PROVIDER_NOK, expectedResult)); + providerApiCommand.putExtra(PARAMETERS, mockBundle()); providerApiManager.handleIntent(providerApiCommand); } @@ -478,12 +489,12 @@ public class ProviderApiManagerTest { expectedResult.putBoolean(BROADCAST_RESULT_KEY, true); expectedResult.putParcelable(PROVIDER_KEY, provider); - Intent providerApiCommand = mockIntent(); providerApiCommand.putExtra(PROVIDER_KEY, provider); providerApiCommand.setAction(ProviderAPI.SET_UP_PROVIDER); providerApiCommand.putExtra(ProviderAPI.RECEIVER_KEY, mockResultReceiver(PROVIDER_OK, expectedResult)); + providerApiCommand.putExtra(PARAMETERS, mockBundle()); providerApiManager.handleIntent(providerApiCommand); } @@ -504,12 +515,12 @@ public class ProviderApiManagerTest { expectedResult.putBoolean(BROADCAST_RESULT_KEY, false); expectedResult.putParcelable(PROVIDER_KEY, provider); expectedResult.putString(ERRORS, "This is not a trusted Bitmask provider."); - Intent providerApiCommand = mockIntent(); providerApiCommand.setAction(ProviderAPI.SET_UP_PROVIDER); providerApiCommand.putExtra(ProviderAPI.RECEIVER_KEY, mockResultReceiver(PROVIDER_NOK, expectedResult)); providerApiCommand.putExtra(PROVIDER_KEY, provider); + providerApiCommand.putExtra(PARAMETERS, mockBundle()); providerApiManager.handleIntent(providerApiCommand); } @@ -679,20 +690,16 @@ public class ProviderApiManagerTest { expectedResult.putBoolean(BROADCAST_RESULT_KEY, true); expectedResult.putParcelable(PROVIDER_KEY, provider); - Intent providerApiCommand = mockIntent(); providerApiCommand.putExtra(PROVIDER_KEY, provider); providerApiCommand.setAction(ProviderAPI.SET_UP_PROVIDER); providerApiCommand.putExtra(ProviderAPI.RECEIVER_KEY, mockResultReceiver(PROVIDER_OK, expectedResult)); + providerApiCommand.putExtra(PARAMETERS, mockBundle()); providerApiManager.handleIntent(providerApiCommand); } - /** - * Disabled as long as we hide snowflake in the UI - */ - /* @Test public void test_handleIntentSetupProvider_TorFallback_SecondTryHappyPath() throws IOException, CertificateEncodingException, NoSuchAlgorithmException, TimeoutException, InterruptedException { Provider provider = getConfiguredProviderAPIv4(); @@ -705,17 +712,15 @@ public class ProviderApiManagerTest { providerApiCommand.putExtra(PROVIDER_KEY, provider); providerApiCommand.setAction(ProviderAPI.SET_UP_PROVIDER); providerApiCommand.putExtra(ProviderAPI.RECEIVER_KEY, mockResultReceiver(PROVIDER_OK)); - + providerApiCommand.putExtra(PARAMETERS, mockBundle()); mockTorStatusObservable(null); providerApiManager.handleIntent(providerApiCommand); assertEquals(8118, TorStatusObservable.getProxyPort()); - }*/ + } + - /** - * Disabled as long as we hide snowflake in the UI - */ - /* @Test + @Test public void test_handleIntentSetupProvider_TorFallbackStartServiceException_SecondTryFailed() throws IOException, CertificateEncodingException, NoSuchAlgorithmException, TimeoutException, InterruptedException { Provider provider = getConfiguredProviderAPIv4(); @@ -727,12 +732,12 @@ public class ProviderApiManagerTest { providerApiCommand.putExtra(PROVIDER_KEY, provider); providerApiCommand.setAction(ProviderAPI.SET_UP_PROVIDER); providerApiCommand.putExtra(ProviderAPI.RECEIVER_KEY, mockResultReceiver(PROVIDER_NOK)); - + providerApiCommand.putExtra(PARAMETERS, mockBundle()); mockTorStatusObservable(null); providerApiManager.handleIntent(providerApiCommand); assertEquals(-1, TorStatusObservable.getProxyPort()); - } */ + } @Test public void test_handleIntentSetupProvider_TorFallbackTimeoutException_SecondTryFailed() throws IOException, CertificateEncodingException, NoSuchAlgorithmException, TimeoutException, InterruptedException { @@ -746,7 +751,7 @@ public class ProviderApiManagerTest { providerApiCommand.putExtra(PROVIDER_KEY, provider); providerApiCommand.setAction(ProviderAPI.SET_UP_PROVIDER); providerApiCommand.putExtra(ProviderAPI.RECEIVER_KEY, mockResultReceiver(PROVIDER_NOK)); - + providerApiCommand.putExtra(PARAMETERS, mockBundle()); mockTorStatusObservable(new TimeoutException("Tor took too long to start.")); providerApiManager.handleIntent(providerApiCommand); @@ -767,7 +772,7 @@ public class ProviderApiManagerTest { providerApiCommand.putExtra(PROVIDER_KEY, provider); providerApiCommand.setAction(ProviderAPI.SET_UP_PROVIDER); providerApiCommand.putExtra(ProviderAPI.RECEIVER_KEY, mockResultReceiver(PROVIDER_OK)); - + providerApiCommand.putExtra(PARAMETERS, mockBundle()); mockTorStatusObservable(null); providerApiManager.handleIntent(providerApiCommand); @@ -788,13 +793,105 @@ public class ProviderApiManagerTest { providerApiCommand.putExtra(PROVIDER_KEY, provider); providerApiCommand.setAction(ProviderAPI.SET_UP_PROVIDER); providerApiCommand.putExtra(ProviderAPI.RECEIVER_KEY, mockResultReceiver(PROVIDER_OK)); + providerApiCommand.putExtra(PARAMETERS, mockBundle()); + mockTorStatusObservable(new TimeoutException("This timeout exception is never thrown")); + + providerApiManager.handleIntent(providerApiCommand); + assertEquals(-1, TorStatusObservable.getProxyPort()); + } + + @Test + public void test_handleIntentUpdateVPNCertificate_TorBridgesPreferencesNotConfigured_TorStartedAndSuccess() throws IOException, CertificateEncodingException, NoSuchAlgorithmException, TimeoutException, InterruptedException { + Provider provider = getConfiguredProviderAPIv4(); + + mockConfigHelper(" a5244308a1374709a9afce95e3ae47c1b44bc2398c0a70ccbf8b3a8a97f29494"); + mockBase64(); + mockProviderApiConnector(ERROR_DNS_RESUOLUTION_TOR_FALLBACK); + + providerApiManager = new ProviderApiManager(mockPreferences, mockResources, mockClientGenerator(), new TestProviderApiServiceCallback()); + + Intent providerApiCommand = mockIntent(); + providerApiCommand.putExtra(PROVIDER_KEY, provider); + providerApiCommand.setAction(ProviderAPI.UPDATE_INVALID_VPN_CERTIFICATE); + providerApiCommand.putExtra(ProviderAPI.RECEIVER_KEY, mockResultReceiver(CORRECTLY_UPDATED_INVALID_VPN_CERTIFICATE)); + providerApiCommand.putExtra(PARAMETERS, mockBundle()); + mockTorStatusObservable(null); + + providerApiManager.handleIntent(providerApiCommand); + assertNotEquals(-1, TorStatusObservable.getProxyPort()); + } + @Test + public void test_handleIntentUpdateVPNCertificate_TorBridgesPreferencesFalse_TorNotStartedAndFailure() throws IOException, CertificateEncodingException, NoSuchAlgorithmException, TimeoutException, InterruptedException { + Provider provider = getConfiguredProviderAPIv4(); + + mockConfigHelper(" a5244308a1374709a9afce95e3ae47c1b44bc2398c0a70ccbf8b3a8a97f29494"); + mockBase64(); + mockProviderApiConnector(ERROR_DNS_RESUOLUTION_TOR_FALLBACK); + mockPreferences.edit().putBoolean(USE_BRIDGES, false).putBoolean(USE_SNOWFLAKE, false).commit(); + + providerApiManager = new ProviderApiManager(mockPreferences, mockResources, mockClientGenerator(), new TestProviderApiServiceCallback()); + + Intent providerApiCommand = mockIntent(); + providerApiCommand.putExtra(PROVIDER_KEY, provider); + providerApiCommand.setAction(ProviderAPI.UPDATE_INVALID_VPN_CERTIFICATE); + providerApiCommand.putExtra(ProviderAPI.RECEIVER_KEY, mockResultReceiver(INCORRECTLY_UPDATED_INVALID_VPN_CERTIFICATE)); + providerApiCommand.putExtra(PARAMETERS, mockBundle()); mockTorStatusObservable(new TimeoutException("This timeout exception is never thrown")); providerApiManager.handleIntent(providerApiCommand); assertEquals(-1, TorStatusObservable.getProxyPort()); } + @Test + public void test_handleIntentUpdateVPNCertificate_TorBridgesPreferencesTrue_TorStartedAndSuccess() throws IOException, CertificateEncodingException, NoSuchAlgorithmException, TimeoutException, InterruptedException { + Provider provider = getConfiguredProviderAPIv4(); + + mockConfigHelper(" a5244308a1374709a9afce95e3ae47c1b44bc2398c0a70ccbf8b3a8a97f29494"); + mockBase64(); + mockProviderApiConnector(NO_ERROR_API_V4); + mockPreferences.edit().putBoolean(USE_BRIDGES, true).putBoolean(USE_SNOWFLAKE, true).commit(); + + providerApiManager = new ProviderApiManager(mockPreferences, mockResources, mockClientGenerator(), new TestProviderApiServiceCallback()); + + Intent providerApiCommand = mockIntent(); + providerApiCommand.putExtra(PROVIDER_KEY, provider); + providerApiCommand.setAction(ProviderAPI.UPDATE_INVALID_VPN_CERTIFICATE); + providerApiCommand.putExtra(ProviderAPI.RECEIVER_KEY, mockResultReceiver(CORRECTLY_UPDATED_INVALID_VPN_CERTIFICATE)); + providerApiCommand.putExtra(PARAMETERS, mockBundle()); + mockTorStatusObservable(null); + + providerApiManager.handleIntent(providerApiCommand); + assertNotEquals(-1, TorStatusObservable.getProxyPort()); + } + + @Test + public void test_handleIntentUpdateVPNCertificate_TorBridgesPreferencesTrue_TorException_Failure() throws IOException, CertificateEncodingException, NoSuchAlgorithmException, TimeoutException, InterruptedException { + Provider provider = getConfiguredProviderAPIv4(); + + mockConfigHelper(" a5244308a1374709a9afce95e3ae47c1b44bc2398c0a70ccbf8b3a8a97f29494"); + mockBase64(); + mockProviderApiConnector(NO_ERROR_API_V4); + mockPreferences.edit().putBoolean(USE_BRIDGES, true).putBoolean(USE_SNOWFLAKE, true).commit(); + + providerApiManager = new ProviderApiManager(mockPreferences, mockResources, mockClientGenerator(), new TestProviderApiServiceCallback()); + + Bundle expectedResult = mockBundle(); + expectedResult.putBoolean(BROADCAST_RESULT_KEY, false); + expectedResult.putString(ERRORS, "{\"initalAction\":\"ProviderAPI.UPDATE_INVALID_VPN_CERTIFICATE\"}"); + expectedResult.putParcelable(PROVIDER_KEY, provider); + + Intent providerApiCommand = mockIntent(); + providerApiCommand.putExtra(PROVIDER_KEY, provider); + providerApiCommand.setAction(ProviderAPI.UPDATE_INVALID_VPN_CERTIFICATE); + providerApiCommand.putExtra(ProviderAPI.RECEIVER_KEY, mockResultReceiver(TOR_EXCEPTION, expectedResult)); + providerApiCommand.putExtra(PARAMETERS, mockBundle()); + mockTorStatusObservable(new InterruptedException("Tor thread was interrupted.")); + + providerApiManager.handleIntent(providerApiCommand); + assertEquals(-1, TorStatusObservable.getProxyPort()); + } + @Test public void test_handleIntentSetupProvider_TorBridgesPreferencesEnabledTimeout_TimeoutError() throws IOException, CertificateEncodingException, NoSuchAlgorithmException, TimeoutException, InterruptedException { Provider provider = getConfiguredProviderAPIv4(); @@ -811,7 +908,7 @@ public class ProviderApiManagerTest { providerApiCommand.putExtra(PROVIDER_KEY, provider); providerApiCommand.setAction(ProviderAPI.SET_UP_PROVIDER); providerApiCommand.putExtra(ProviderAPI.RECEIVER_KEY, mockResultReceiver(TOR_TIMEOUT, expectedResult)); - + providerApiCommand.putExtra(PARAMETERS, mockBundle()); mockTorStatusObservable(new TimeoutException("Tor took too long to start.")); providerApiManager.handleIntent(providerApiCommand); @@ -836,7 +933,7 @@ public class ProviderApiManagerTest { providerApiCommand.setAction(ProviderAPI.SET_UP_PROVIDER); providerApiCommand.putExtra(ProviderAPI.RECEIVER_KEY, mockResultReceiver(MISSING_NETWORK_CONNECTION, expectedResult)); providerApiCommand.putExtra(PROVIDER_KEY, provider); - + providerApiCommand.putExtra(PARAMETERS, mockBundle()); providerApiManager.handleIntent(providerApiCommand); } diff --git a/app/src/test/java/se/leap/bitmaskclient/eip/VpnCertificateValidatorTest.java b/app/src/test/java/se/leap/bitmaskclient/eip/VpnCertificateValidatorTest.java index 32c0d0e44b88c4179484d8c2a525ceb32e3674b7..1cb47f43ea9f20902aaa8f01bba17b2f8bba5592 100644 --- a/app/src/test/java/se/leap/bitmaskclient/eip/VpnCertificateValidatorTest.java +++ b/app/src/test/java/se/leap/bitmaskclient/eip/VpnCertificateValidatorTest.java @@ -38,9 +38,9 @@ public class VpnCertificateValidatorTest { } @Test - public void test_isValid_lessThan15days_returnFalse() throws NoSuchAlgorithmException, CertificateEncodingException, IOException { + public void test_isValid_lessThan1day_returnFalse() throws NoSuchAlgorithmException, CertificateEncodingException, IOException { String cert = getInputAsString(getClass().getClassLoader().getResourceAsStream("riseup.net.pem")); - Calendar c = new Calendar.Builder().setDate(2024, 4, 14).setCalendarType("gregorian").build(); + Calendar c = new Calendar.Builder().setDate(2024, 3, 28).setCalendarType("gregorian").build(); mockConfigHelper("falseFingerPrint"); VpnCertificateValidator validator = new VpnCertificateValidator(cert); validator.setCalendarProvider(new TestCalendarProvider(c.getTimeInMillis())); @@ -50,7 +50,7 @@ public class VpnCertificateValidatorTest { @Test public void test_isValid_multipleCerts_failIfOneExpires() throws NoSuchAlgorithmException, CertificateEncodingException, IOException { String cert = getInputAsString(getClass().getClassLoader().getResourceAsStream("float.hexacab.org.pem")); - Calendar c = new Calendar.Builder().setDate(2024, 4, 14).setCalendarType("gregorian").build(); + Calendar c = new Calendar.Builder().setDate(2024, 3, 28).setCalendarType("gregorian").build(); mockConfigHelper("falseFingerPrint"); VpnCertificateValidator validator = new VpnCertificateValidator(cert); validator.setCalendarProvider(new TestCalendarProvider(c.getTimeInMillis())); @@ -60,10 +60,30 @@ public class VpnCertificateValidatorTest { @Test public void test_isValid_multipleCerts_allValid() throws NoSuchAlgorithmException, CertificateEncodingException, IOException { String cert = getInputAsString(getClass().getClassLoader().getResourceAsStream("float.hexacab.org.pem")); - Calendar c = new Calendar.Builder().setDate(2024, 4, 13).setCalendarType("gregorian").build(); + Calendar c = new Calendar.Builder().setDate(2024, 3, 27).setCalendarType("gregorian").build(); mockConfigHelper("falseFingerPrint"); VpnCertificateValidator validator = new VpnCertificateValidator(cert); validator.setCalendarProvider(new TestCalendarProvider(c.getTimeInMillis())); - assertFalse(validator.isValid()); + assertTrue(validator.isValid()); + } + + @Test + public void test_shouldBeUpdated_lessThan8days_returnTrue() throws NoSuchAlgorithmException, CertificateEncodingException, IOException { + String cert = getInputAsString(getClass().getClassLoader().getResourceAsStream("float.hexacab.org.pem")); + Calendar c = new Calendar.Builder().setDate(2024, 3, 21).setCalendarType("gregorian").build(); + mockConfigHelper("falseFingerPrint"); + VpnCertificateValidator validator = new VpnCertificateValidator(cert); + validator.setCalendarProvider(new TestCalendarProvider(c.getTimeInMillis())); + assertTrue(validator.shouldBeUpdated()); + } + + @Test + public void test_shouldBeUpdated_moreThan8days_returnFalse() throws NoSuchAlgorithmException, CertificateEncodingException, IOException { + String cert = getInputAsString(getClass().getClassLoader().getResourceAsStream("float.hexacab.org.pem")); + Calendar c = new Calendar.Builder().setDate(2024, 3, 20).setCalendarType("gregorian").build(); + mockConfigHelper("falseFingerPrint"); + VpnCertificateValidator validator = new VpnCertificateValidator(cert); + validator.setCalendarProvider(new TestCalendarProvider(c.getTimeInMillis())); + assertFalse(validator.shouldBeUpdated()); } } \ No newline at end of file diff --git a/app/src/test/java/se/leap/bitmaskclient/eip/VpnConfigGeneratorTest.java b/app/src/test/java/se/leap/bitmaskclient/eip/VpnConfigGeneratorTest.java index 4bacd81a3889a45af551288d15f831f066b29fba..4fb178fce1aabc48110603aa0d4842b0355de750 100644 --- a/app/src/test/java/se/leap/bitmaskclient/eip/VpnConfigGeneratorTest.java +++ b/app/src/test/java/se/leap/bitmaskclient/eip/VpnConfigGeneratorTest.java @@ -1,5 +1,19 @@ package se.leap.bitmaskclient.eip; +import static junit.framework.Assert.assertEquals; +import static junit.framework.Assert.assertFalse; +import static junit.framework.Assert.assertTrue; +import static org.mockito.ArgumentMatchers.any; +import static org.mockito.Mockito.RETURNS_DEEP_STUBS; +import static org.mockito.Mockito.mock; +import static org.powermock.api.mockito.PowerMockito.mockStatic; +import static org.powermock.api.mockito.PowerMockito.when; +import static de.blinkt.openvpn.core.connection.Connection.TransportType.OBFS4; +import static de.blinkt.openvpn.core.connection.Connection.TransportType.OBFS4_KCP; +import static de.blinkt.openvpn.core.connection.Connection.TransportType.OPENVPN; +import static se.leap.bitmaskclient.base.models.Constants.OPENVPN_CONFIGURATION; +import static se.leap.bitmaskclient.testutils.MockHelper.mockTextUtils; + import android.content.Context; import android.content.SharedPreferences; import android.preference.PreferenceManager; @@ -20,27 +34,15 @@ import java.util.HashMap; import de.blinkt.openvpn.VpnProfile; import de.blinkt.openvpn.core.connection.Connection; +import se.leap.bitmaskclient.base.utils.ConfigHelper; import se.leap.bitmaskclient.testutils.MockHelper; import se.leap.bitmaskclient.testutils.TestSetupHelper; -import static de.blinkt.openvpn.core.connection.Connection.TransportType.OBFS4; -import static de.blinkt.openvpn.core.connection.Connection.TransportType.OPENVPN; -import static junit.framework.Assert.assertEquals; -import static junit.framework.Assert.assertFalse; -import static junit.framework.Assert.assertTrue; -import static org.mockito.ArgumentMatchers.any; -import static org.mockito.Mockito.RETURNS_DEEP_STUBS; -import static org.mockito.Mockito.mock; -import static org.powermock.api.mockito.PowerMockito.mockStatic; -import static org.powermock.api.mockito.PowerMockito.when; -import static se.leap.bitmaskclient.base.models.Constants.OPENVPN_CONFIGURATION; -import static se.leap.bitmaskclient.testutils.MockHelper.mockTextUtils; - /** * Created by cyberta on 03.10.17. */ @RunWith(PowerMockRunner.class) -@PrepareForTest({Log.class, TextUtils.class, PreferenceManager.class}) +@PrepareForTest({Log.class, TextUtils.class, PreferenceManager.class, ConfigHelper.ObfsVpnHelper.class}) public class VpnConfigGeneratorTest { @Mock(answer = Answers.RETURNS_DEEP_STUBS) @@ -156,7 +158,7 @@ public class VpnConfigGeneratorTest { "K2ZoknT+Nno5jgjFuUR3fZseNizEfx7BteooKQ==\n" + "-----END CERTIFICATE-----\n" + "</cert>\n" + - "crl-verify file missing in config profile\n" + + "# crl-verify file missing in config profile\n" + "remote-cert-tls server\n" + "data-ciphers AES-128-CBC\n" + "cipher AES-128-CBC\n" + @@ -164,6 +166,8 @@ public class VpnConfigGeneratorTest { "persist-tun\n" + "# persist-tun also enables pre resolving to avoid DNS resolve problem\n" + "preresolve\n" + + "# Use system proxy setting\n" + + "management-query-proxy\n" + "# Custom configuration options\n" + "# You are on your on own here :)\n" + "# These options found in the config file do not map to config settings:\n" + @@ -275,7 +279,7 @@ public class VpnConfigGeneratorTest { "K2ZoknT+Nno5jgjFuUR3fZseNizEfx7BteooKQ==\n" + "-----END CERTIFICATE-----\n" + "</cert>\n" + - "crl-verify file missing in config profile\n" + + "# crl-verify file missing in config profile\n" + "remote-cert-tls server\n" + "data-ciphers AES-128-CBC\n" + "cipher AES-128-CBC\n" + @@ -283,6 +287,8 @@ public class VpnConfigGeneratorTest { "persist-tun\n" + "# persist-tun also enables pre resolving to avoid DNS resolve problem\n" + "preresolve\n" + + "# Use system proxy setting\n" + + "management-query-proxy\n" + "# Custom configuration options\n" + "# You are on your on own here :)\n" + "# These options found in the config file do not map to config settings:\n" + @@ -393,7 +399,7 @@ public class VpnConfigGeneratorTest { "K2ZoknT+Nno5jgjFuUR3fZseNizEfx7BteooKQ==\n" + "-----END CERTIFICATE-----\n" + "</cert>\n" + - "crl-verify file missing in config profile\n" + + "# crl-verify file missing in config profile\n" + "route 37.218.247.60 255.255.255.255 net_gateway\n"+ "remote-cert-tls server\n" + "data-ciphers AES-128-CBC\n" + @@ -402,6 +408,129 @@ public class VpnConfigGeneratorTest { "persist-tun\n" + "# persist-tun also enables pre resolving to avoid DNS resolve problem\n" + "preresolve\n" + + "# Use system proxy setting\n" + + "management-query-proxy\n" + + "# Custom configuration options\n" + + "# You are on your on own here :)\n" + + "# These options found in the config file do not map to config settings:\n" + + "keepalive 10 30 \n" + + "tls-cipher DHE-RSA-AES128-SHA \n"; + + String expectedVPNConfig_v3_obfsvpn_obfs4 = "# Config for OpenVPN 2.x\n" + + "# Enables connection to GUI\n" + + "management /data/data/se.leap.bitmask/mgmtsocket unix\n" + + "management-client\n" + + "management-query-passwords\n" + + "management-hold\n" + + "\n" + + "setenv IV_GUI_VER \"se.leap.bitmaskclient 0.9.10\" \n" + + "setenv IV_PLAT_VER \"0 null JUNIT null null null\"\n" + + "machine-readable-output\n" + + "allow-recursive-routing\n" + + "ifconfig-nowarn\n" + + "client\n" + + "verb 4\n" + + "connect-retry 2 300\n" + + "resolv-retry 60\n" + + "dev tun\n" + + "remote 37.218.247.60 23049 tcp-client\n" + + "<ca>\n" + + "-----BEGIN CERTIFICATE-----\n" + + "MIIFbzCCA1egAwIBAgIBATANBgkqhkiG9w0BAQ0FADBKMRgwFgYDVQQDDA9CaXRt\n" + + "YXNrIFJvb3QgQ0ExEDAOBgNVBAoMB0JpdG1hc2sxHDAaBgNVBAsME2h0dHBzOi8v\n" + + "Yml0bWFzay5uZXQwHhcNMTIxMTA2MDAwMDAwWhcNMjIxMTA2MDAwMDAwWjBKMRgw\n" + + "FgYDVQQDDA9CaXRtYXNrIFJvb3QgQ0ExEDAOBgNVBAoMB0JpdG1hc2sxHDAaBgNV\n" + + "BAsME2h0dHBzOi8vYml0bWFzay5uZXQwggIiMA0GCSqGSIb3DQEBAQUAA4ICDwAw\n" + + "ggIKAoICAQC1eV4YvayaU+maJbWrD4OHo3d7S1BtDlcvkIRS1Fw3iYDjsyDkZxai\n" + + "dHp4EUasfNQ+EVtXUvtk6170EmLco6Elg8SJBQ27trE6nielPRPCfX3fQzETRfvB\n" + + "7tNvGw4Jn2YKiYoMD79kkjgyZjkJ2r/bEHUSevmR09BRp86syHZerdNGpXYhcQ84\n" + + "CA1+V+603GFIHnrP+uQDdssW93rgDNYu+exT+Wj6STfnUkugyjmPRPjL7wh0tzy+\n" + + "znCeLl4xiV3g9sjPnc7r2EQKd5uaTe3j71sDPF92KRk0SSUndREz+B1+Dbe/RGk4\n" + + "MEqGFuOzrtsgEhPIX0hplhb0Tgz/rtug+yTT7oJjBa3u20AAOQ38/M99EfdeJvc4\n" + + "lPFF1XBBLh6X9UKF72an2NuANiX6XPySnJgZ7nZ09RiYZqVwu/qt3DfvLfhboq+0\n" + + "bQvLUPXrVDr70onv5UDjpmEA/cLmaIqqrduuTkFZOym65/PfAPvpGnt7crQj/Ibl\n" + + "DEDYZQmP7AS+6zBjoOzNjUGE5r40zWAR1RSi7zliXTu+yfsjXUIhUAWmYR6J3KxB\n" + + "lfsiHBQ+8dn9kC3YrUexWoOqBiqJOAJzZh5Y1tqgzfh+2nmHSB2dsQRs7rDRRlyy\n" + + "YMbkpzL9ZsOUO2eTP1mmar6YjCN+rggYjRrX71K2SpBG6b1zZxOG+wIDAQABo2Aw\n" + + "XjAdBgNVHQ4EFgQUuYGDLL2sswnYpHHvProt1JU+D48wDgYDVR0PAQH/BAQDAgIE\n" + + "MAwGA1UdEwQFMAMBAf8wHwYDVR0jBBgwFoAUuYGDLL2sswnYpHHvProt1JU+D48w\n" + + "DQYJKoZIhvcNAQENBQADggIBADeG67vaFcbITGpi51264kHPYPEWaXUa5XYbtmBl\n" + + "cXYyB6hY5hv/YNuVGJ1gWsDmdeXEyj0j2icGQjYdHRfwhrbEri+h1EZOm1cSBDuY\n" + + "k/P5+ctHyOXx8IE79DBsZ6IL61UKIaKhqZBfLGYcWu17DVV6+LT+AKtHhOrv3TSj\n" + + "RnAcKnCbKqXLhUPXpK0eTjPYS2zQGQGIhIy9sQXVXJJJsGrPgMxna1Xw2JikBOCG\n" + + "htD/JKwt6xBmNwktH0GI/LVtVgSp82Clbn9C4eZN9E5YbVYjLkIEDhpByeC71QhX\n" + + "EIQ0ZR56bFuJA/CwValBqV/G9gscTPQqd+iETp8yrFpAVHOW+YzSFbxjTEkBte1J\n" + + "aF0vmbqdMAWLk+LEFPQRptZh0B88igtx6tV5oVd+p5IVRM49poLhuPNJGPvMj99l\n" + + "mlZ4+AeRUnbOOeAEuvpLJbel4rhwFzmUiGoeTVoPZyMevWcVFq6BMkS+jRR2w0jK\n" + + "G6b0v5XDHlcFYPOgUrtsOBFJVwbutLvxdk6q37kIFnWCd8L3kmES5q4wjyFK47Co\n" + + "Ja8zlx64jmMZPg/t3wWqkZgXZ14qnbyG5/lGsj5CwVtfDljrhN0oCWK1FZaUmW3d\n" + + "69db12/g4f6phldhxiWuGC/W6fCW5kre7nmhshcltqAJJuU47iX+DarBFiIj816e\n" + + "yV8e\n" + + "-----END CERTIFICATE-----\n" + + "\n" + + "</ca>\n" + + "<key>\n" + + "-----BEGIN RSA PRIVATE KEY-----\n" + + "MIIEwAIBADANBgkqhkiG9w0BAQEFAASCBKowggSmAgEAAoIBAQDUTYWeGgsHS+fjijmziniNqw6h\n" + + "MBpyK4S/cM6PxV28C33VuOWPTMcIYesctjZANWFCggfFTQSjV5Qaxq9UK4i27tayLbCdlVS6hpbl\n" + + "Vf4DuI3Gj1Pv1rtITBShtvCf3T7yBnjW4wVpOpsUAAOViKUSvUU3kPPMFWhiGQw8yHYr82ts6XMo\n" + + "jwMoonW5Ml4e7C7Cr22QesC63q7emNcpUd0pZGT9C33RgDAHZDMrlyjo4HEp1JbUfB0gbmXElJbE\n" + + "1TNdZ62HhgmMjzTUN1GGrQ1t91AEoEQwaK65o4YSj+yFv6KXZZz5OWaz94tKiN9v26EXtBFmRlyb\n" + + "6+D9ynSd9LghAgMBAAECggEBANPHLRXkhsHVj1EkzqBx7gXr8CEMmiTvknFh9zvltrZhhDoRQjWr\n" + + "chPDkcRHY2Cznvy4N0YyqQDD2ULIlZdSAgPxxothFoBruWSD47yMBmLx08ORsDpcqt/YvPAATJI8\n" + + "IpFNsXcyaXBp/M57oRemgnxp/8UJPJmFdWX99H4hvffh/jdj7POgYiWUaAl37XTYZKZ4nzKU2wpL\n" + + "EDLj9RKPz9gG7CYp2zrLC9LaAsrXVrKwPBw6g+XwbClaqFj97db3mrY4lr6mTo89qmus1AU+fBDH\n" + + "3Xlpmc8JwB+30TvhRNKrpLx9cEjuEj7K1gm8Y4dWCjPi+lNbtAyUBcgPJFa/81ECgYEA7pLoBU/Y\n" + + "ZYjyHFca8FvDBcBh6haHfqJr9doXWtgjDrbi3o2n5wHqfKhFWOH6vPEQozkOVeX1ze6HOiRmGBpW\n" + + "r+r7x8TD25L7I6HJw3M351RWOAfkF0w/RTVdetcTgduQtfN1u6BDhYSVceXMjyQYx7MhfETWI8Gh\n" + + "KSYm8OEDYiUCgYEA489fmbrCcUnXzpTsbswJ5NmSoEXbcX8cLxnQuzE0z9GHhQdrMjOpXR76reTW\n" + + "6jcuudarNcwRUYSWWhjCDKHhpx4HhasWPaHgr7jIzcRw8yZSJRSxKr8sl1qh6g7s47JcmfXOMWLt\n" + + "yuyE933XrT19Th4ODZHY40Uv35mPjMi9d00CgYEAyRNAQtndBRa7GG/B4Ls2T+6pl+aNJIo4e+no\n" + + "rURlp800wWabEPRocdBRQmyULBLxduBr2LIMzhgwGSz8b2wji/l9ZA3PFY135bxClVzSzUIjuO3N\n" + + "rGUzHl2wAAyuAFDSUshzfkPBJRNt8aVBF5PQ3t93ZYmPAmv8LPZe875yX5ECgYEAsUEcwK/ZNW7g\n" + + "dQPZR4iJNkC4Xu6cBZ6Cnn92swBheEYvLSoNlX0vDZ7aLE3/jzQqrjzC8NP8sbH5jtbuvgeDXZX3\n" + + "AmGRp5j6C6A61ihAPmEVz3ZfN8SSfJ3vl//PAIg6lyz0J+cy4Q7RkwSeuVQ72Hl4M8TEvmmKC3Af\n" + + "ispy6Y0CgYEAgl1o2lo+ACyk+oVQPaaPqK3d7WOBFp4eR2nXFor/vsx9igQOlZUgzRDQsR8jo1o9\n" + + "efOSBf87igrZGgssys89pWa2dnXnz5PMmzkKr6bw4D9Ez6u6Puc9UZhGw/8wDYg6fSosdB9utspm\n" + + "M698ycef7jBNMDgmhpSvfw5GctoNQ4s=\n" + + "-----END RSA PRIVATE KEY-----\n" + + "</key>\n" + + "<cert>\n" + + "-----BEGIN CERTIFICATE-----\n" + + "MIIEjDCCAnSgAwIBAgIQG6MBp/cd9DlY+7cdvp3R3jANBgkqhkiG9w0BAQsFADBmMRAwDgYDVQQK\n" + + "DAdCaXRtYXNrMRwwGgYDVQQLDBNodHRwczovL2JpdG1hc2submV0MTQwMgYDVQQDDCtCaXRtYXNr\n" + + "IFJvb3QgQ0EgKGNsaWVudCBjZXJ0aWZpY2F0ZXMgb25seSEpMB4XDTE0MTIwNTAwMDAwMFoXDTE1\n" + + "MDMwNTAwMDAwMFowLTErMCkGA1UEAwwiVU5MSU1JVEVEZDBwZDdkMzE4eTNtOHNkeXllaTFqYmZl\n" + + "eDCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBANRNhZ4aCwdL5+OKObOKeI2rDqEwGnIr\n" + + "hL9wzo/FXbwLfdW45Y9Mxwhh6xy2NkA1YUKCB8VNBKNXlBrGr1QriLbu1rItsJ2VVLqGluVV/gO4\n" + + "jcaPU+/Wu0hMFKG28J/dPvIGeNbjBWk6mxQAA5WIpRK9RTeQ88wVaGIZDDzIdivza2zpcyiPAyii\n" + + "dbkyXh7sLsKvbZB6wLrert6Y1ylR3SlkZP0LfdGAMAdkMyuXKOjgcSnUltR8HSBuZcSUlsTVM11n\n" + + "rYeGCYyPNNQ3UYatDW33UASgRDBorrmjhhKP7IW/opdlnPk5ZrP3i0qI32/boRe0EWZGXJvr4P3K\n" + + "dJ30uCECAwEAAaNvMG0wHQYDVR0OBBYEFK8bMVAM4GBB5sHptoIOAaIvlYueMAsGA1UdDwQEAwIH\n" + + "gDATBgNVHSUEDDAKBggrBgEFBQcDAjAJBgNVHRMEAjAAMB8GA1UdIwQYMBaAFId+E7bsWFsUWah9\n" + + "vZuPvZ7O+aJsMA0GCSqGSIb3DQEBCwUAA4ICAQAQOX81csVhvP422NKkZH7+g3npBpl+sEHedaGR\n" + + "xYPOu4HrA4TVF9h44sljRoRJyenGNdBZCXcLKHg889eePTf8Z5K3lTojp6hvwyA6tgxOMHT1kESW\n" + + "PfqnRw8mHfHJuE3g+4YNUMwggzwc/VZATdV/7M33sarVN9AUOHou9n9BizgCC+UnYlS+F2POumE3\n" + + "FbOhKo5uubI02MwBYlN2JVO2TBt1Q20w8wc6cU07Xi5Epp+1mkgFiOShkNtPcJmEyBWJhxDtSDOW\n" + + "2doqWYNqH2kq7B5R/kyyfcpFJqAnBTV7xs+C5rTS1mW7LpxfdCUMbYuLCpyxpO3A/DhAm8n47tUH\n" + + "lBtmo8Avdb8VdFpYiGBpB0o9kTFcsWFb2GkWFBduGfSEB8jUI7QtqhgZqocAKK/cweSRV8FwyUcn\n" + + "R0prRm3QEi9fbXqEddzjSY9y/lqWYzT7u+IOAQpKroeZ4wzgYperDNOUFuYk1rP7yuvjP2pV5rcN\n" + + "yPoBP60TPVWMRM4WJm6nTogAz2qBrFsf/XwT/ajzbsjT6HNB7QbRE+wkFkqspoXG5Agp7KQ8lW3L\n" + + "SKCDGOQJz7VIE85pD0tg7QEXBEw8oaRZtMjQ0Gvs25mxXAKka4wGasaWfYH6d0E+iKYcWn86V1rH\n" + + "K2ZoknT+Nno5jgjFuUR3fZseNizEfx7BteooKQ==\n" + + "-----END CERTIFICATE-----\n" + + "</cert>\n" + + "# crl-verify file missing in config profile\n" + + "route 37.218.247.60 255.255.255.255 net_gateway\n"+ + "remote-cert-tls server\n" + + "data-ciphers AES-128-CBC\n" + + "cipher AES-128-CBC\n" + + "auth SHA1\n" + + "persist-tun\n" + + "# persist-tun also enables pre resolving to avoid DNS resolve problem\n" + + "preresolve\n" + + "# Use system proxy setting\n" + + "management-query-proxy\n" + "# Custom configuration options\n" + "# You are on your on own here :)\n" + "# These options found in the config file do not map to config settings:\n" + @@ -513,7 +642,7 @@ public class VpnConfigGeneratorTest { "K2ZoknT+Nno5jgjFuUR3fZseNizEfx7BteooKQ==\n" + "-----END CERTIFICATE-----\n" + "</cert>\n" + - "crl-verify file missing in config profile\n" + + "# crl-verify file missing in config profile\n" + "remote-cert-tls server\n" + "data-ciphers AES-128-CBC\n" + "cipher AES-128-CBC\n" + @@ -521,6 +650,8 @@ public class VpnConfigGeneratorTest { "persist-tun\n" + "# persist-tun also enables pre resolving to avoid DNS resolve problem\n" + "preresolve\n" + + "# Use system proxy setting\n" + + "management-query-proxy\n" + "# Custom configuration options\n" + "# You are on your on own here :)\n" + "# These options found in the config file do not map to config settings:\n" + @@ -632,7 +763,7 @@ public class VpnConfigGeneratorTest { "K2ZoknT+Nno5jgjFuUR3fZseNizEfx7BteooKQ==\n" + "-----END CERTIFICATE-----\n" + "</cert>\n" + - "crl-verify file missing in config profile\n" + + "# crl-verify file missing in config profile\n" + "remote-cert-tls server\n" + "data-ciphers AES-128-CBC\n" + "cipher AES-128-CBC\n" + @@ -640,6 +771,8 @@ public class VpnConfigGeneratorTest { "persist-tun\n" + "# persist-tun also enables pre resolving to avoid DNS resolve problem\n" + "preresolve\n" + + "# Use system proxy setting\n" + + "management-query-proxy\n" + "# Custom configuration options\n" + "# You are on your on own here :)\n" + "# These options found in the config file do not map to config settings:\n" + @@ -751,7 +884,7 @@ public class VpnConfigGeneratorTest { "K2ZoknT+Nno5jgjFuUR3fZseNizEfx7BteooKQ==\n" + "-----END CERTIFICATE-----\n" + "</cert>\n" + - "crl-verify file missing in config profile\n" + + "# crl-verify file missing in config profile\n" + "remote-cert-tls server\n" + "data-ciphers AES-256-GCM:AES-128-GCM:AES-128-CBC\n" + "cipher AES-128-CBC\n" + @@ -759,6 +892,8 @@ public class VpnConfigGeneratorTest { "persist-tun\n" + "# persist-tun also enables pre resolving to avoid DNS resolve problem\n" + "preresolve\n" + + "# Use system proxy setting\n" + + "management-query-proxy\n" + "# Custom configuration options\n" + "# You are on your on own here :)\n" + "# These options found in the config file do not map to config settings:\n" + @@ -872,7 +1007,7 @@ public class VpnConfigGeneratorTest { "K2ZoknT+Nno5jgjFuUR3fZseNizEfx7BteooKQ==\n" + "-----END CERTIFICATE-----\n" + "</cert>\n" + - "crl-verify file missing in config profile\n" + + "# crl-verify file missing in config profile\n" + "comp-lzo\n" + "nobind\n"+ "remote-cert-tls server\n" + @@ -882,6 +1017,8 @@ public class VpnConfigGeneratorTest { "persist-tun\n" + "# persist-tun also enables pre resolving to avoid DNS resolve problem\n" + "preresolve\n" + + "# Use system proxy setting\n" + + "management-query-proxy\n" + "# Custom configuration options\n" + "# You are on your on own here :)\n" + "# These options found in the config file do not map to config settings:\n" + @@ -997,7 +1134,7 @@ public class VpnConfigGeneratorTest { "K2ZoknT+Nno5jgjFuUR3fZseNizEfx7BteooKQ==\n" + "-----END CERTIFICATE-----\n" + "</cert>\n" + - "crl-verify file missing in config profile\n" + + "# crl-verify file missing in config profile\n" + "comp-lzo\n" + "nobind\n"+ "remote-cert-tls server\n" + @@ -1007,6 +1144,8 @@ public class VpnConfigGeneratorTest { "persist-tun\n" + "# persist-tun also enables pre resolving to avoid DNS resolve problem\n" + "preresolve\n" + + "# Use system proxy setting\n" + + "management-query-proxy\n" + "# Custom configuration options\n" + "# You are on your on own here :)\n" + "# These options found in the config file do not map to config settings:\n" + @@ -1130,7 +1269,7 @@ public class VpnConfigGeneratorTest { "K2ZoknT+Nno5jgjFuUR3fZseNizEfx7BteooKQ==\n" + "-----END CERTIFICATE-----\n" + "</cert>\n" + - "crl-verify file missing in config profile\n" + + "# crl-verify file missing in config profile\n" + "comp-lzo\n" + "nobind\n"+ "remote-cert-tls server\n" + @@ -1140,6 +1279,8 @@ public class VpnConfigGeneratorTest { "persist-tun\n" + "# persist-tun also enables pre resolving to avoid DNS resolve problem\n" + "preresolve\n" + + "# Use system proxy setting\n" + + "management-query-proxy\n" + "# Custom configuration options\n" + "# You are on your on own here :)\n" + "# These options found in the config file do not map to config settings:\n" + @@ -1149,6 +1290,135 @@ public class VpnConfigGeneratorTest { "rcvbuf 0 \n"; + String expectedVPNConfig_v4_ovpn_tcp_udp_new_ciphers = "# Config for OpenVPN 2.x\n" + + "# Enables connection to GUI\n" + + "management /data/data/se.leap.bitmask/mgmtsocket unix\n" + + "management-client\n" + + "management-query-passwords\n" + + "management-hold\n" + + "\n" + + "setenv IV_GUI_VER \"se.leap.bitmaskclient 0.9.10\" \n" + + "setenv IV_PLAT_VER \"0 null JUNIT null null null\"\n" + + "machine-readable-output\n" + + "allow-recursive-routing\n" + + "ifconfig-nowarn\n" + + "client\n" + + "verb 4\n" + + "connect-retry 2 300\n" + + "resolv-retry 60\n" + + "dev tun\n" + + "remote 2001:db8:123::1056 1195 tcp-client\n" + + "remote 37.218.247.60 1195 tcp-client\n" + + "remote 2001:db8:123::1056 1195 udp\n" + + "remote 37.218.247.60 1195 udp\n" + + "<ca>\n" + + "-----BEGIN CERTIFICATE-----\n" + + "MIIFbzCCA1egAwIBAgIBATANBgkqhkiG9w0BAQ0FADBKMRgwFgYDVQQDDA9CaXRt\n" + + "YXNrIFJvb3QgQ0ExEDAOBgNVBAoMB0JpdG1hc2sxHDAaBgNVBAsME2h0dHBzOi8v\n" + + "Yml0bWFzay5uZXQwHhcNMTIxMTA2MDAwMDAwWhcNMjIxMTA2MDAwMDAwWjBKMRgw\n" + + "FgYDVQQDDA9CaXRtYXNrIFJvb3QgQ0ExEDAOBgNVBAoMB0JpdG1hc2sxHDAaBgNV\n" + + "BAsME2h0dHBzOi8vYml0bWFzay5uZXQwggIiMA0GCSqGSIb3DQEBAQUAA4ICDwAw\n" + + "ggIKAoICAQC1eV4YvayaU+maJbWrD4OHo3d7S1BtDlcvkIRS1Fw3iYDjsyDkZxai\n" + + "dHp4EUasfNQ+EVtXUvtk6170EmLco6Elg8SJBQ27trE6nielPRPCfX3fQzETRfvB\n" + + "7tNvGw4Jn2YKiYoMD79kkjgyZjkJ2r/bEHUSevmR09BRp86syHZerdNGpXYhcQ84\n" + + "CA1+V+603GFIHnrP+uQDdssW93rgDNYu+exT+Wj6STfnUkugyjmPRPjL7wh0tzy+\n" + + "znCeLl4xiV3g9sjPnc7r2EQKd5uaTe3j71sDPF92KRk0SSUndREz+B1+Dbe/RGk4\n" + + "MEqGFuOzrtsgEhPIX0hplhb0Tgz/rtug+yTT7oJjBa3u20AAOQ38/M99EfdeJvc4\n" + + "lPFF1XBBLh6X9UKF72an2NuANiX6XPySnJgZ7nZ09RiYZqVwu/qt3DfvLfhboq+0\n" + + "bQvLUPXrVDr70onv5UDjpmEA/cLmaIqqrduuTkFZOym65/PfAPvpGnt7crQj/Ibl\n" + + "DEDYZQmP7AS+6zBjoOzNjUGE5r40zWAR1RSi7zliXTu+yfsjXUIhUAWmYR6J3KxB\n" + + "lfsiHBQ+8dn9kC3YrUexWoOqBiqJOAJzZh5Y1tqgzfh+2nmHSB2dsQRs7rDRRlyy\n" + + "YMbkpzL9ZsOUO2eTP1mmar6YjCN+rggYjRrX71K2SpBG6b1zZxOG+wIDAQABo2Aw\n" + + "XjAdBgNVHQ4EFgQUuYGDLL2sswnYpHHvProt1JU+D48wDgYDVR0PAQH/BAQDAgIE\n" + + "MAwGA1UdEwQFMAMBAf8wHwYDVR0jBBgwFoAUuYGDLL2sswnYpHHvProt1JU+D48w\n" + + "DQYJKoZIhvcNAQENBQADggIBADeG67vaFcbITGpi51264kHPYPEWaXUa5XYbtmBl\n" + + "cXYyB6hY5hv/YNuVGJ1gWsDmdeXEyj0j2icGQjYdHRfwhrbEri+h1EZOm1cSBDuY\n" + + "k/P5+ctHyOXx8IE79DBsZ6IL61UKIaKhqZBfLGYcWu17DVV6+LT+AKtHhOrv3TSj\n" + + "RnAcKnCbKqXLhUPXpK0eTjPYS2zQGQGIhIy9sQXVXJJJsGrPgMxna1Xw2JikBOCG\n" + + "htD/JKwt6xBmNwktH0GI/LVtVgSp82Clbn9C4eZN9E5YbVYjLkIEDhpByeC71QhX\n" + + "EIQ0ZR56bFuJA/CwValBqV/G9gscTPQqd+iETp8yrFpAVHOW+YzSFbxjTEkBte1J\n" + + "aF0vmbqdMAWLk+LEFPQRptZh0B88igtx6tV5oVd+p5IVRM49poLhuPNJGPvMj99l\n" + + "mlZ4+AeRUnbOOeAEuvpLJbel4rhwFzmUiGoeTVoPZyMevWcVFq6BMkS+jRR2w0jK\n" + + "G6b0v5XDHlcFYPOgUrtsOBFJVwbutLvxdk6q37kIFnWCd8L3kmES5q4wjyFK47Co\n" + + "Ja8zlx64jmMZPg/t3wWqkZgXZ14qnbyG5/lGsj5CwVtfDljrhN0oCWK1FZaUmW3d\n" + + "69db12/g4f6phldhxiWuGC/W6fCW5kre7nmhshcltqAJJuU47iX+DarBFiIj816e\n" + + "yV8e\n" + + "-----END CERTIFICATE-----\n" + + "\n" + + "</ca>\n" + + "<key>\n" + + "-----BEGIN RSA PRIVATE KEY-----\n" + + "MIIEwAIBADANBgkqhkiG9w0BAQEFAASCBKowggSmAgEAAoIBAQDUTYWeGgsHS+fjijmziniNqw6h\n" + + "MBpyK4S/cM6PxV28C33VuOWPTMcIYesctjZANWFCggfFTQSjV5Qaxq9UK4i27tayLbCdlVS6hpbl\n" + + "Vf4DuI3Gj1Pv1rtITBShtvCf3T7yBnjW4wVpOpsUAAOViKUSvUU3kPPMFWhiGQw8yHYr82ts6XMo\n" + + "jwMoonW5Ml4e7C7Cr22QesC63q7emNcpUd0pZGT9C33RgDAHZDMrlyjo4HEp1JbUfB0gbmXElJbE\n" + + "1TNdZ62HhgmMjzTUN1GGrQ1t91AEoEQwaK65o4YSj+yFv6KXZZz5OWaz94tKiN9v26EXtBFmRlyb\n" + + "6+D9ynSd9LghAgMBAAECggEBANPHLRXkhsHVj1EkzqBx7gXr8CEMmiTvknFh9zvltrZhhDoRQjWr\n" + + "chPDkcRHY2Cznvy4N0YyqQDD2ULIlZdSAgPxxothFoBruWSD47yMBmLx08ORsDpcqt/YvPAATJI8\n" + + "IpFNsXcyaXBp/M57oRemgnxp/8UJPJmFdWX99H4hvffh/jdj7POgYiWUaAl37XTYZKZ4nzKU2wpL\n" + + "EDLj9RKPz9gG7CYp2zrLC9LaAsrXVrKwPBw6g+XwbClaqFj97db3mrY4lr6mTo89qmus1AU+fBDH\n" + + "3Xlpmc8JwB+30TvhRNKrpLx9cEjuEj7K1gm8Y4dWCjPi+lNbtAyUBcgPJFa/81ECgYEA7pLoBU/Y\n" + + "ZYjyHFca8FvDBcBh6haHfqJr9doXWtgjDrbi3o2n5wHqfKhFWOH6vPEQozkOVeX1ze6HOiRmGBpW\n" + + "r+r7x8TD25L7I6HJw3M351RWOAfkF0w/RTVdetcTgduQtfN1u6BDhYSVceXMjyQYx7MhfETWI8Gh\n" + + "KSYm8OEDYiUCgYEA489fmbrCcUnXzpTsbswJ5NmSoEXbcX8cLxnQuzE0z9GHhQdrMjOpXR76reTW\n" + + "6jcuudarNcwRUYSWWhjCDKHhpx4HhasWPaHgr7jIzcRw8yZSJRSxKr8sl1qh6g7s47JcmfXOMWLt\n" + + "yuyE933XrT19Th4ODZHY40Uv35mPjMi9d00CgYEAyRNAQtndBRa7GG/B4Ls2T+6pl+aNJIo4e+no\n" + + "rURlp800wWabEPRocdBRQmyULBLxduBr2LIMzhgwGSz8b2wji/l9ZA3PFY135bxClVzSzUIjuO3N\n" + + "rGUzHl2wAAyuAFDSUshzfkPBJRNt8aVBF5PQ3t93ZYmPAmv8LPZe875yX5ECgYEAsUEcwK/ZNW7g\n" + + "dQPZR4iJNkC4Xu6cBZ6Cnn92swBheEYvLSoNlX0vDZ7aLE3/jzQqrjzC8NP8sbH5jtbuvgeDXZX3\n" + + "AmGRp5j6C6A61ihAPmEVz3ZfN8SSfJ3vl//PAIg6lyz0J+cy4Q7RkwSeuVQ72Hl4M8TEvmmKC3Af\n" + + "ispy6Y0CgYEAgl1o2lo+ACyk+oVQPaaPqK3d7WOBFp4eR2nXFor/vsx9igQOlZUgzRDQsR8jo1o9\n" + + "efOSBf87igrZGgssys89pWa2dnXnz5PMmzkKr6bw4D9Ez6u6Puc9UZhGw/8wDYg6fSosdB9utspm\n" + + "M698ycef7jBNMDgmhpSvfw5GctoNQ4s=\n" + + "-----END RSA PRIVATE KEY-----\n" + + "</key>\n" + + "<cert>\n" + + "-----BEGIN CERTIFICATE-----\n" + + "MIIEjDCCAnSgAwIBAgIQG6MBp/cd9DlY+7cdvp3R3jANBgkqhkiG9w0BAQsFADBmMRAwDgYDVQQK\n" + + "DAdCaXRtYXNrMRwwGgYDVQQLDBNodHRwczovL2JpdG1hc2submV0MTQwMgYDVQQDDCtCaXRtYXNr\n" + + "IFJvb3QgQ0EgKGNsaWVudCBjZXJ0aWZpY2F0ZXMgb25seSEpMB4XDTE0MTIwNTAwMDAwMFoXDTE1\n" + + "MDMwNTAwMDAwMFowLTErMCkGA1UEAwwiVU5MSU1JVEVEZDBwZDdkMzE4eTNtOHNkeXllaTFqYmZl\n" + + "eDCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBANRNhZ4aCwdL5+OKObOKeI2rDqEwGnIr\n" + + "hL9wzo/FXbwLfdW45Y9Mxwhh6xy2NkA1YUKCB8VNBKNXlBrGr1QriLbu1rItsJ2VVLqGluVV/gO4\n" + + "jcaPU+/Wu0hMFKG28J/dPvIGeNbjBWk6mxQAA5WIpRK9RTeQ88wVaGIZDDzIdivza2zpcyiPAyii\n" + + "dbkyXh7sLsKvbZB6wLrert6Y1ylR3SlkZP0LfdGAMAdkMyuXKOjgcSnUltR8HSBuZcSUlsTVM11n\n" + + "rYeGCYyPNNQ3UYatDW33UASgRDBorrmjhhKP7IW/opdlnPk5ZrP3i0qI32/boRe0EWZGXJvr4P3K\n" + + "dJ30uCECAwEAAaNvMG0wHQYDVR0OBBYEFK8bMVAM4GBB5sHptoIOAaIvlYueMAsGA1UdDwQEAwIH\n" + + "gDATBgNVHSUEDDAKBggrBgEFBQcDAjAJBgNVHRMEAjAAMB8GA1UdIwQYMBaAFId+E7bsWFsUWah9\n" + + "vZuPvZ7O+aJsMA0GCSqGSIb3DQEBCwUAA4ICAQAQOX81csVhvP422NKkZH7+g3npBpl+sEHedaGR\n" + + "xYPOu4HrA4TVF9h44sljRoRJyenGNdBZCXcLKHg889eePTf8Z5K3lTojp6hvwyA6tgxOMHT1kESW\n" + + "PfqnRw8mHfHJuE3g+4YNUMwggzwc/VZATdV/7M33sarVN9AUOHou9n9BizgCC+UnYlS+F2POumE3\n" + + "FbOhKo5uubI02MwBYlN2JVO2TBt1Q20w8wc6cU07Xi5Epp+1mkgFiOShkNtPcJmEyBWJhxDtSDOW\n" + + "2doqWYNqH2kq7B5R/kyyfcpFJqAnBTV7xs+C5rTS1mW7LpxfdCUMbYuLCpyxpO3A/DhAm8n47tUH\n" + + "lBtmo8Avdb8VdFpYiGBpB0o9kTFcsWFb2GkWFBduGfSEB8jUI7QtqhgZqocAKK/cweSRV8FwyUcn\n" + + "R0prRm3QEi9fbXqEddzjSY9y/lqWYzT7u+IOAQpKroeZ4wzgYperDNOUFuYk1rP7yuvjP2pV5rcN\n" + + "yPoBP60TPVWMRM4WJm6nTogAz2qBrFsf/XwT/ajzbsjT6HNB7QbRE+wkFkqspoXG5Agp7KQ8lW3L\n" + + "SKCDGOQJz7VIE85pD0tg7QEXBEw8oaRZtMjQ0Gvs25mxXAKka4wGasaWfYH6d0E+iKYcWn86V1rH\n" + + "K2ZoknT+Nno5jgjFuUR3fZseNizEfx7BteooKQ==\n" + + "-----END CERTIFICATE-----\n" + + "</cert>\n" + + "# crl-verify file missing in config profile\n" + + "nobind\n"+ + "remote-cert-tls server\n" + + "data-ciphers AES-256-GCM:AES-128-CBC\n" + + "cipher AES-256-GCM:AES-128-CBC\n" + + "auth SHA1\n" + + "float\n"+ + "persist-tun\n" + + "# persist-tun also enables pre resolving to avoid DNS resolve problem\n" + + "preresolve\n" + + "# Use system proxy setting\n" + + "management-query-proxy\n" + + "# Custom configuration options\n" + + "# You are on your on own here :)\n" + + "# These options found in the config file do not map to config settings:\n" + + "keepalive 10 30 \n" + + "tls-cipher TLS-ECDHE-ECDSA-WITH-AES-256-GCM-SHA384:DHE-RSA-AES128-SHA \n" + + "sndbuf 0 \n" + + "rcvbuf 0 \n" + + "tls-version-min 1.2 \n"; + + @Before public void setUp() throws Exception { generalConfig = new JSONObject(TestSetupHelper.getInputAsString(getClass().getClassLoader().getResourceAsStream("general_configuration.json"))); @@ -1159,78 +1429,108 @@ public class VpnConfigGeneratorTest { mockStatic(PreferenceManager.class); SharedPreferences preferences = mock(SharedPreferences.class, RETURNS_DEEP_STUBS); when(PreferenceManager.getDefaultSharedPreferences(any(Context.class))).thenReturn(preferences); + when(preferences.getBoolean("usesystemproxy", true)).thenReturn(true); when(context.getCacheDir()).thenReturn(new File("/data/data/se.leap.bitmask")); - + mockStatic(ConfigHelper.ObfsVpnHelper.class); } @Test public void testGenerateVpnProfile_v1_tcp_udp() throws Exception { gateway = new JSONObject(TestSetupHelper.getInputAsString(getClass().getClassLoader().getResourceAsStream("gateway_tcp_udp.json"))); - vpnConfigGenerator = new VpnConfigGenerator(generalConfig, secrets, gateway, 1, false); + VpnConfigGenerator.Configuration configuration = new VpnConfigGenerator.Configuration(); + configuration.apiVersion = 1; + vpnConfigGenerator = new VpnConfigGenerator(generalConfig, secrets, gateway, configuration); HashMap<Connection.TransportType, VpnProfile> vpnProfiles = vpnConfigGenerator.generateVpnProfiles(); assertFalse(vpnProfiles.containsKey(OBFS4)); - assertTrue(vpnProfiles.get(OPENVPN).getConfigFile(context, false).trim().equals(expectedVPNConfig_v1_tcp_udp.trim())); + assertEquals(expectedVPNConfig_v1_tcp_udp.trim(), vpnProfiles.get(OPENVPN).getConfigFile(context, false).trim()); } @Test public void testGenerateVpnProfile_v1_udp_tcp() throws Exception { gateway = new JSONObject(TestSetupHelper.getInputAsString(getClass().getClassLoader().getResourceAsStream("gateway_udp_tcp.json"))); - vpnConfigGenerator = new VpnConfigGenerator(generalConfig, secrets, gateway, 1, false); + VpnConfigGenerator.Configuration configuration = new VpnConfigGenerator.Configuration(); + configuration.apiVersion = 1; + vpnConfigGenerator = new VpnConfigGenerator(generalConfig, secrets, gateway, configuration); HashMap<Connection.TransportType, VpnProfile> vpnProfiles = vpnConfigGenerator.generateVpnProfiles(); assertFalse(vpnProfiles.containsKey(OBFS4)); - assertTrue(vpnProfiles.get(OPENVPN).getConfigFile(context, false).trim().equals(expectedVPNConfig_v1_udp_tcp.trim())); + assertEquals(expectedVPNConfig_v1_udp_tcp.trim(), vpnProfiles.get(OPENVPN).getConfigFile(context, false).trim()); } @Test public void testGenerateVpnProfile_v2_tcp_udp() throws Exception { gateway = new JSONObject(TestSetupHelper.getInputAsString(getClass().getClassLoader().getResourceAsStream("gateway_tcp_udp.json"))); - vpnConfigGenerator = new VpnConfigGenerator(generalConfig, secrets, gateway, 2, false); + VpnConfigGenerator.Configuration configuration = new VpnConfigGenerator.Configuration(); + configuration.apiVersion = 2; + vpnConfigGenerator = new VpnConfigGenerator(generalConfig, secrets, gateway, configuration); HashMap<Connection.TransportType, VpnProfile> vpnProfiles = vpnConfigGenerator.generateVpnProfiles(); assertFalse(vpnProfiles.containsKey(OBFS4)); - assertTrue(vpnProfiles.get(OPENVPN).getConfigFile(context, false).trim().equals(expectedVPNConfig_v1_tcp_udp.trim())); + assertEquals(expectedVPNConfig_v1_tcp_udp.trim(), vpnProfiles.get(OPENVPN).getConfigFile(context, false).trim()); } @Test public void testGenerateVpnProfile_v2_udp_tcp() throws Exception { gateway = new JSONObject(TestSetupHelper.getInputAsString(getClass().getClassLoader().getResourceAsStream("gateway_udp_tcp.json"))); - vpnConfigGenerator = new VpnConfigGenerator(generalConfig, secrets, gateway, 2, false); + VpnConfigGenerator.Configuration configuration = new VpnConfigGenerator.Configuration(); + configuration.apiVersion = 2; + vpnConfigGenerator = new VpnConfigGenerator(generalConfig, secrets, gateway, configuration); HashMap<Connection.TransportType, VpnProfile> vpnProfiles = vpnConfigGenerator.generateVpnProfiles(); assertFalse(vpnProfiles.containsKey(OBFS4)); - assertTrue(vpnProfiles.get(OPENVPN).getConfigFile(context, false).trim().equals(expectedVPNConfig_v1_udp_tcp.trim())); + assertEquals(expectedVPNConfig_v1_udp_tcp.trim(), vpnProfiles.get(OPENVPN).getConfigFile(context, false).trim()); } @Test public void testGenerateVpnProfile_v3_obfs4() throws Exception { + when(ConfigHelper.ObfsVpnHelper.useObfsVpn()).thenReturn(false); gateway = new JSONObject(TestSetupHelper.getInputAsString(getClass().getClassLoader().getResourceAsStream("ptdemo.bitmask.eip-service.json"))).getJSONArray("gateways").getJSONObject(0); - vpnConfigGenerator = new VpnConfigGenerator(generalConfig, secrets, gateway, 3, false); + VpnConfigGenerator.Configuration configuration = new VpnConfigGenerator.Configuration(); + configuration.apiVersion = 3; + vpnConfigGenerator = new VpnConfigGenerator(generalConfig, secrets, gateway, configuration); HashMap<Connection.TransportType, VpnProfile> vpnProfiles = vpnConfigGenerator.generateVpnProfiles(); assertTrue(vpnProfiles.containsKey(OBFS4)); assertTrue(vpnProfiles.containsKey(OPENVPN)); System.out.println(vpnProfiles.get(OBFS4).getConfigFile(context, false)); - assertTrue(vpnProfiles.get(OBFS4).getConfigFile(context, false).trim().equals(expectedVPNConfig_v3_obfs4.trim())); + assertEquals(expectedVPNConfig_v3_obfs4.trim(), vpnProfiles.get(OBFS4).getConfigFile(context, false).trim()); + } + + @Test + public void testGenerateVpnProfile_v3_obfs4_obfsvpn() throws Exception { + when(ConfigHelper.ObfsVpnHelper.useObfsVpn()).thenReturn(true); + gateway = new JSONObject(TestSetupHelper.getInputAsString(getClass().getClassLoader().getResourceAsStream("ptdemo.bitmask.eip-service.json"))).getJSONArray("gateways").getJSONObject(0); + VpnConfigGenerator.Configuration configuration = new VpnConfigGenerator.Configuration(); + configuration.apiVersion = 3; + vpnConfigGenerator = new VpnConfigGenerator(generalConfig, secrets, gateway, configuration); + HashMap<Connection.TransportType, VpnProfile> vpnProfiles = vpnConfigGenerator.generateVpnProfiles(); + assertTrue(vpnProfiles.containsKey(OBFS4)); + assertTrue(vpnProfiles.containsKey(OPENVPN)); + System.out.println(vpnProfiles.get(OBFS4).getConfigFile(context, false)); + assertEquals(expectedVPNConfig_v3_obfsvpn_obfs4.trim(), vpnProfiles.get(OBFS4).getConfigFile(context, false).trim()); } @Test public void testGenerateVpnProfile_v3_ovpn_tcp_udp() throws Exception { gateway = new JSONObject(TestSetupHelper.getInputAsString(getClass().getClassLoader().getResourceAsStream("ptdemo_pt_tcp_udp.eip-service.json"))).getJSONArray("gateways").getJSONObject(0); - vpnConfigGenerator = new VpnConfigGenerator(generalConfig, secrets, gateway, 3, false); + VpnConfigGenerator.Configuration configuration = new VpnConfigGenerator.Configuration(); + configuration.apiVersion = 3; + vpnConfigGenerator = new VpnConfigGenerator(generalConfig, secrets, gateway, configuration); HashMap<Connection.TransportType, VpnProfile> vpnProfiles = vpnConfigGenerator.generateVpnProfiles(); assertTrue(vpnProfiles.containsKey(OBFS4)); assertTrue(vpnProfiles.containsKey(OPENVPN)); System.out.println(vpnProfiles.get(OPENVPN).getConfigFile(context, false)); - assertTrue(vpnProfiles.get(OPENVPN).getConfigFile(context, false).trim().equals(expectedVPNConfig_v3_ovpn_tcp_udp.trim())); + assertEquals(expectedVPNConfig_v3_ovpn_tcp_udp.trim(), vpnProfiles.get(OPENVPN).getConfigFile(context, false).trim()); } @Test public void testGenerateVpnProfile_v3_ovpn_udp_tcp() throws Exception { gateway = new JSONObject(TestSetupHelper.getInputAsString(getClass().getClassLoader().getResourceAsStream("ptdemo_pt_udp_tcp.eip-service.json"))).getJSONArray("gateways").getJSONObject(0); - vpnConfigGenerator = new VpnConfigGenerator(generalConfig, secrets, gateway, 3, false); + VpnConfigGenerator.Configuration configuration = new VpnConfigGenerator.Configuration(); + configuration.apiVersion = 3; + vpnConfigGenerator = new VpnConfigGenerator(generalConfig, secrets, gateway, configuration); HashMap<Connection.TransportType, VpnProfile> vpnProfiles = vpnConfigGenerator.generateVpnProfiles(); assertTrue(vpnProfiles.containsKey(OBFS4)); assertTrue(vpnProfiles.containsKey(OPENVPN)); System.out.println(vpnProfiles.get(OPENVPN).getConfigFile(context, false)); - assertTrue(vpnProfiles.get(OPENVPN).getConfigFile(context, false).trim().equals(expectedVPNConfig_v3_ovpn_udp_tcp.trim())); + assertEquals(expectedVPNConfig_v3_ovpn_udp_tcp.trim(), vpnProfiles.get(OPENVPN).getConfigFile(context, false).trim()); } @Test @@ -1238,44 +1538,51 @@ public class VpnConfigGeneratorTest { gateway = new JSONObject(TestSetupHelper.getInputAsString(getClass().getClassLoader().getResourceAsStream("ptdemo_pt_udp_tcp.eip-service.json"))).getJSONArray("gateways").getJSONObject(0); //delete "data-ciphers" from config to test if the resulting openvpn config file will contain the default value taken from "cipher" flag generalConfig.put("data-ciphers", null); - vpnConfigGenerator = new VpnConfigGenerator(generalConfig, secrets, gateway, 3, false); + VpnConfigGenerator.Configuration configuration = new VpnConfigGenerator.Configuration(); + configuration.apiVersion = 3; + vpnConfigGenerator = new VpnConfigGenerator(generalConfig, secrets, gateway, configuration); HashMap<Connection.TransportType, VpnProfile> vpnProfiles = vpnConfigGenerator.generateVpnProfiles(); assertTrue(vpnProfiles.containsKey(OBFS4)); assertTrue(vpnProfiles.containsKey(OPENVPN)); System.out.println(vpnProfiles.get(OPENVPN).getConfigFile(context, false)); - assertTrue(vpnProfiles.get(OPENVPN).getConfigFile(context, false).trim().equals(expectedVPNConfig_v3_ovpn_udp_tcp_defaultDataCiphers.trim())); + assertEquals(expectedVPNConfig_v3_ovpn_udp_tcp_defaultDataCiphers.trim(), vpnProfiles.get(OPENVPN).getConfigFile(context, false).trim()); } @Test public void testGenerateVpnProfile_v4_ovpn_tcp_udp() throws Exception { gateway = new JSONObject(TestSetupHelper.getInputAsString(getClass().getClassLoader().getResourceAsStream("v4/ptdemo_pt_tcp_udp.eip-service.json"))).getJSONArray("gateways").getJSONObject(0); generalConfig = new JSONObject(TestSetupHelper.getInputAsString(getClass().getClassLoader().getResourceAsStream("v4/ptdemo_pt_tcp_udp.eip-service.json"))).getJSONObject(OPENVPN_CONFIGURATION); - vpnConfigGenerator = new VpnConfigGenerator(generalConfig, secrets, gateway, 4, false); + VpnConfigGenerator.Configuration configuration = new VpnConfigGenerator.Configuration(); + configuration.apiVersion = 4; + vpnConfigGenerator = new VpnConfigGenerator(generalConfig, secrets, gateway, configuration); HashMap<Connection.TransportType, VpnProfile> vpnProfiles = vpnConfigGenerator.generateVpnProfiles(); assertTrue(vpnProfiles.containsKey(OBFS4)); assertTrue(vpnProfiles.containsKey(OPENVPN)); System.out.println(vpnProfiles.get(OPENVPN).getConfigFile(context, false)); - assertTrue(vpnProfiles.get(OPENVPN).getConfigFile(context, false).trim().equals(expectedVPNConfig_v4_ovpn_tcp_udp.trim())); + assertEquals(expectedVPNConfig_v4_ovpn_tcp_udp.trim(), vpnProfiles.get(OPENVPN).getConfigFile(context, false).trim()); } @Test public void testGenerateVpnProfile_v4_ovpn_udp_tcp() throws Exception { gateway = new JSONObject(TestSetupHelper.getInputAsString(getClass().getClassLoader().getResourceAsStream("v4/ptdemo_pt_udp_tcp.eip-service.json"))).getJSONArray("gateways").getJSONObject(0); generalConfig = new JSONObject(TestSetupHelper.getInputAsString(getClass().getClassLoader().getResourceAsStream("v4/ptdemo_pt_udp_tcp.eip-service.json"))).getJSONObject(OPENVPN_CONFIGURATION); - vpnConfigGenerator = new VpnConfigGenerator(generalConfig, secrets, gateway, 4, false); + VpnConfigGenerator.Configuration configuration = new VpnConfigGenerator.Configuration(); + configuration.apiVersion = 4; + vpnConfigGenerator = new VpnConfigGenerator(generalConfig, secrets, gateway, configuration); HashMap<Connection.TransportType, VpnProfile> vpnProfiles = vpnConfigGenerator.generateVpnProfiles(); assertTrue(vpnProfiles.containsKey(OBFS4)); assertTrue(vpnProfiles.containsKey(OPENVPN)); System.out.println(vpnProfiles.get(OPENVPN).getConfigFile(context, false)); - System.out.println(expectedVPNConfig_v4_ovpn_udp_tcp.trim()); - assertTrue(vpnProfiles.get(OPENVPN).getConfigFile(context, false).trim().equals(expectedVPNConfig_v4_ovpn_udp_tcp.trim())); + assertEquals(expectedVPNConfig_v4_ovpn_udp_tcp.trim(), vpnProfiles.get(OPENVPN).getConfigFile(context, false).trim()); } @Test public void testGenerateVpnProfile_v3_ipv6only_allowOpenvpnIPv6Only() throws Exception { gateway = new JSONObject(TestSetupHelper.getInputAsString(getClass().getClassLoader().getResourceAsStream("ptdemo_misconfigured_ipv6.json"))).getJSONArray("gateways").getJSONObject(0); generalConfig = new JSONObject(TestSetupHelper.getInputAsString(getClass().getClassLoader().getResourceAsStream("ptdemo_misconfigured_ipv6.json"))).getJSONObject(OPENVPN_CONFIGURATION); - vpnConfigGenerator = new VpnConfigGenerator(generalConfig, secrets, gateway, 3, false); + VpnConfigGenerator.Configuration configuration = new VpnConfigGenerator.Configuration(); + configuration.apiVersion = 3; + vpnConfigGenerator = new VpnConfigGenerator(generalConfig, secrets, gateway, configuration); HashMap<Connection.TransportType, VpnProfile> vpnProfiles = vpnConfigGenerator.generateVpnProfiles(); assertTrue(vpnProfiles.containsKey(OPENVPN)); } @@ -1284,7 +1591,9 @@ public class VpnConfigGeneratorTest { public void testGenerateVpnProfile_v3_obfs4IPv6_skip() throws Exception { gateway = new JSONObject(TestSetupHelper.getInputAsString(getClass().getClassLoader().getResourceAsStream("ptdemo_misconfigured_ipv6.json"))).getJSONArray("gateways").getJSONObject(0); generalConfig = new JSONObject(TestSetupHelper.getInputAsString(getClass().getClassLoader().getResourceAsStream("ptdemo_misconfigured_ipv6.json"))).getJSONObject(OPENVPN_CONFIGURATION); - vpnConfigGenerator = new VpnConfigGenerator(generalConfig, secrets, gateway, 3, false); + VpnConfigGenerator.Configuration configuration = new VpnConfigGenerator.Configuration(); + configuration.apiVersion = 3; + vpnConfigGenerator = new VpnConfigGenerator(generalConfig, secrets, gateway, configuration); HashMap<Connection.TransportType, VpnProfile> vpnProfiles = vpnConfigGenerator.generateVpnProfiles(); assertFalse(vpnProfiles.containsKey(OBFS4)); } @@ -1296,7 +1605,9 @@ public class VpnConfigGeneratorTest { public void testGenerateVpnProfile_v3_obfs4IPv4AndIPv6_skipIPv6() throws Exception { gateway = new JSONObject(TestSetupHelper.getInputAsString(getClass().getClassLoader().getResourceAsStream("ptdemo_misconfigured_ipv4ipv6.json"))).getJSONArray("gateways").getJSONObject(0); generalConfig = new JSONObject(TestSetupHelper.getInputAsString(getClass().getClassLoader().getResourceAsStream("ptdemo_misconfigured_ipv4ipv6.json"))).getJSONObject(OPENVPN_CONFIGURATION); - vpnConfigGenerator = new VpnConfigGenerator(generalConfig, secrets, gateway, 3, false); + VpnConfigGenerator.Configuration configuration = new VpnConfigGenerator.Configuration(); + configuration.apiVersion = 3; + vpnConfigGenerator = new VpnConfigGenerator(generalConfig, secrets, gateway, configuration); HashMap<Connection.TransportType, VpnProfile> vpnProfiles = vpnConfigGenerator.generateVpnProfiles(); assertTrue(vpnProfiles.containsKey(OBFS4)); assertTrue(vpnProfiles.containsKey(OPENVPN)); @@ -1311,7 +1622,24 @@ public class VpnConfigGeneratorTest { public void testGenerateVpnProfile_v3_obfs4udp_skip() throws Exception { gateway = new JSONObject(TestSetupHelper.getInputAsString(getClass().getClassLoader().getResourceAsStream("ptdemo_misconfigured_udp.json"))).getJSONArray("gateways").getJSONObject(0); generalConfig = new JSONObject(TestSetupHelper.getInputAsString(getClass().getClassLoader().getResourceAsStream("ptdemo_misconfigured_udp.json"))).getJSONObject(OPENVPN_CONFIGURATION); - vpnConfigGenerator = new VpnConfigGenerator(generalConfig, secrets, gateway, 3, false); + VpnConfigGenerator.Configuration configuration = new VpnConfigGenerator.Configuration(); + configuration.apiVersion = 3; + vpnConfigGenerator = new VpnConfigGenerator(generalConfig, secrets, gateway, configuration); + HashMap<Connection.TransportType, VpnProfile> vpnProfiles = vpnConfigGenerator.generateVpnProfiles(); + assertFalse(vpnProfiles.containsKey(OBFS4)); + assertTrue(vpnProfiles.containsKey(OPENVPN)); + } + + /** + * obfs4 cannot be used with UDP, openvpn needs to support TCP + */ + @Test + public void testGenerateVpnProfile_v3_obfs4TCP_openvpnUDP_skip() throws Exception { + gateway = new JSONObject(TestSetupHelper.getInputAsString(getClass().getClassLoader().getResourceAsStream("ptdemo_misconfigured_udp2.json"))).getJSONArray("gateways").getJSONObject(0); + generalConfig = new JSONObject(TestSetupHelper.getInputAsString(getClass().getClassLoader().getResourceAsStream("ptdemo_misconfigured_udp2.json"))).getJSONObject(OPENVPN_CONFIGURATION); + VpnConfigGenerator.Configuration configuration = new VpnConfigGenerator.Configuration(); + configuration.apiVersion = 3; + vpnConfigGenerator = new VpnConfigGenerator(generalConfig, secrets, gateway, configuration); HashMap<Connection.TransportType, VpnProfile> vpnProfiles = vpnConfigGenerator.generateVpnProfiles(); assertFalse(vpnProfiles.containsKey(OBFS4)); assertTrue(vpnProfiles.containsKey(OPENVPN)); @@ -1321,7 +1649,9 @@ public class VpnConfigGeneratorTest { public void testGenerateVpnProfile_v3_obfs4UDPAndTCP_skipUDP() throws Exception { gateway = new JSONObject(TestSetupHelper.getInputAsString(getClass().getClassLoader().getResourceAsStream("ptdemo_misconfigured_udptcp.json"))).getJSONArray("gateways").getJSONObject(0); generalConfig = new JSONObject(TestSetupHelper.getInputAsString(getClass().getClassLoader().getResourceAsStream("ptdemo_misconfigured_udptcp.json"))).getJSONObject(OPENVPN_CONFIGURATION); - vpnConfigGenerator = new VpnConfigGenerator(generalConfig, secrets, gateway, 3, false); + VpnConfigGenerator.Configuration configuration = new VpnConfigGenerator.Configuration(); + configuration.apiVersion = 3; + vpnConfigGenerator = new VpnConfigGenerator(generalConfig, secrets, gateway, configuration); HashMap<Connection.TransportType, VpnProfile> vpnProfiles = vpnConfigGenerator.generateVpnProfiles(); assertTrue(vpnProfiles.containsKey(OBFS4)); assertTrue(vpnProfiles.containsKey(OPENVPN)); @@ -1333,13 +1663,111 @@ public class VpnConfigGeneratorTest { public void testGenerateVpnProfile_preferUDP_firstRemotesUDP() throws Exception { gateway = new JSONObject(TestSetupHelper.getInputAsString(getClass().getClassLoader().getResourceAsStream("v4/multiport_tcpudp_eip-service.json"))).getJSONArray("gateways").getJSONObject(0); generalConfig = new JSONObject(TestSetupHelper.getInputAsString(getClass().getClassLoader().getResourceAsStream("v4/multiport_tcpudp_eip-service.json"))).getJSONObject(OPENVPN_CONFIGURATION); - vpnConfigGenerator = new VpnConfigGenerator(generalConfig, secrets, gateway, 3, true); + VpnConfigGenerator.Configuration configuration = new VpnConfigGenerator.Configuration(); + configuration.apiVersion = 3; + configuration.preferUDP = true; + vpnConfigGenerator = new VpnConfigGenerator(generalConfig, secrets, gateway, configuration); HashMap<Connection.TransportType, VpnProfile> vpnProfiles = vpnConfigGenerator.generateVpnProfiles(); assertTrue(vpnProfiles.containsKey(OBFS4)); assertTrue(vpnProfiles.containsKey(OPENVPN)); System.out.println(vpnProfiles.get(OPENVPN).getConfigFile(context, false)); - System.out.println(expectedVPNConfig_v4_ovpn_multiport_tcpudp.trim()); - assertTrue(vpnProfiles.get(OPENVPN).getConfigFile(context, false).trim().equals(expectedVPNConfig_v4_ovpn_multiport_tcpudp.trim())); + assertEquals(expectedVPNConfig_v4_ovpn_multiport_tcpudp.trim(), vpnProfiles.get(OPENVPN).getConfigFile(context, false).trim()); + } + + @Test + public void testGenerateVpnProfile_testNewCiphers() throws Exception { + gateway = new JSONObject(TestSetupHelper.getInputAsString(getClass().getClassLoader().getResourceAsStream("v4/ptdemo_pt_tcp_udp_new_ciphers.eip-service.json"))).getJSONArray("gateways").getJSONObject(0); + generalConfig = new JSONObject(TestSetupHelper.getInputAsString(getClass().getClassLoader().getResourceAsStream("v4/ptdemo_pt_tcp_udp_new_ciphers.eip-service.json"))).getJSONObject(OPENVPN_CONFIGURATION); + VpnConfigGenerator.Configuration configuration = new VpnConfigGenerator.Configuration(); + configuration.apiVersion = 4; + vpnConfigGenerator = new VpnConfigGenerator(generalConfig, secrets, gateway, configuration); + HashMap<Connection.TransportType, VpnProfile> vpnProfiles = vpnConfigGenerator.generateVpnProfiles(); + System.out.println(vpnProfiles.get(OPENVPN).getConfigFile(context, false)); + assertEquals(expectedVPNConfig_v4_ovpn_tcp_udp_new_ciphers.trim(), vpnProfiles.get(OPENVPN).getConfigFile(context, false).trim()); + } + + @Test + public void testGenerateVpnProfileExperimentalTransportsEnabled () throws Exception { + gateway = new JSONObject(TestSetupHelper.getInputAsString(getClass().getClassLoader().getResourceAsStream("ptdemo_kcp_gateways.json"))).getJSONArray("gateways").getJSONObject(0); + generalConfig = new JSONObject(TestSetupHelper.getInputAsString(getClass().getClassLoader().getResourceAsStream("ptdemo_kcp_gateways.json"))).getJSONObject(OPENVPN_CONFIGURATION); + VpnConfigGenerator.Configuration configuration = new VpnConfigGenerator.Configuration(); + configuration.apiVersion = 3; + configuration.experimentalTransports = true; + configuration.preferUDP = true; + vpnConfigGenerator = new VpnConfigGenerator(generalConfig, secrets, gateway, configuration); + HashMap<Connection.TransportType, VpnProfile> vpnProfiles = vpnConfigGenerator.generateVpnProfiles(); + assertTrue(vpnProfiles.containsKey(OBFS4)); + assertTrue(vpnProfiles.containsKey(OBFS4_KCP)); + assertTrue(vpnProfiles.containsKey(OPENVPN)); + + } + + @Test + public void testGenerateVpnProfile_experimentalTransportsEnabled_KCPMisconfiguredWithUDP_SkippingObfsKCP () throws Exception { + gateway = new JSONObject(TestSetupHelper.getInputAsString(getClass().getClassLoader().getResourceAsStream("ptdemo_misconfigured_kcp_gateways.json"))).getJSONArray("gateways").getJSONObject(0); + generalConfig = new JSONObject(TestSetupHelper.getInputAsString(getClass().getClassLoader().getResourceAsStream("ptdemo_misconfigured_kcp_gateways.json"))).getJSONObject(OPENVPN_CONFIGURATION); + VpnConfigGenerator.Configuration configuration = new VpnConfigGenerator.Configuration(); + configuration.apiVersion = 3; + configuration.experimentalTransports = true; + vpnConfigGenerator = new VpnConfigGenerator(generalConfig, secrets, gateway, configuration); + HashMap<Connection.TransportType, VpnProfile> vpnProfiles = vpnConfigGenerator.generateVpnProfiles(); + assertTrue(vpnProfiles.containsKey(OBFS4)); + assertFalse(vpnProfiles.containsKey(OBFS4_KCP)); + assertTrue(vpnProfiles.containsKey(OPENVPN)); + } + + @Test + public void testGenerateVpnProfile_ObfuscationPinningEnabled_obfs4AndOpenvpnProfile () throws Exception { + gateway = new JSONObject(TestSetupHelper.getInputAsString(getClass().getClassLoader().getResourceAsStream("ptdemo_kcp_gateways.json"))).getJSONArray("gateways").getJSONObject(0); + generalConfig = new JSONObject(TestSetupHelper.getInputAsString(getClass().getClassLoader().getResourceAsStream("ptdemo_kcp_gateways.json"))).getJSONObject(OPENVPN_CONFIGURATION); + VpnConfigGenerator.Configuration configuration = new VpnConfigGenerator.Configuration(); + configuration.apiVersion = 3; + configuration.useObfuscationPinning = true; + configuration.remoteGatewayIP = "1.2.3.4"; + vpnConfigGenerator = new VpnConfigGenerator(generalConfig, secrets, gateway, configuration); + HashMap<Connection.TransportType, VpnProfile> vpnProfiles = vpnConfigGenerator.generateVpnProfiles(); + assertFalse("has no openvpn profile", vpnProfiles.containsKey(OPENVPN)); + assertTrue("has obfs4 profile", vpnProfiles.containsKey(OBFS4)); + assertFalse("has no obfs4 kcp profile", vpnProfiles.containsKey(OBFS4_KCP)); + } + + @Test + public void testGenerateVpnProfile_ObfuscationPinningEnabled_obfs4Profile () throws Exception { + gateway = new JSONObject(TestSetupHelper.getInputAsString(getClass().getClassLoader().getResourceAsStream("ptdemo_kcp_gateways.json"))).getJSONArray("gateways").getJSONObject(0); + generalConfig = new JSONObject(TestSetupHelper.getInputAsString(getClass().getClassLoader().getResourceAsStream("ptdemo_kcp_gateways.json"))).getJSONObject(OPENVPN_CONFIGURATION); + VpnConfigGenerator.Configuration configuration = new VpnConfigGenerator.Configuration(); + configuration.apiVersion = 3; + configuration.useObfuscationPinning = true; + configuration.obfuscationProxyKCP = true; + configuration.obfuscationProxyPort = "443"; + configuration.obfuscationProxyIP = "5.6.7.8"; + configuration.obfuscationProxyCert = "asdfasdf"; + configuration.remoteGatewayIP = "1.2.3.4"; + vpnConfigGenerator = new VpnConfigGenerator(generalConfig, secrets, gateway, configuration); + HashMap<Connection.TransportType, VpnProfile> vpnProfiles = vpnConfigGenerator.generateVpnProfiles(); + assertTrue("has obfs4_kcp profile", vpnProfiles.containsKey(OBFS4_KCP)); + assertFalse("has openvpn profile", vpnProfiles.containsKey(OPENVPN)); + assertFalse("has no obfs4 profile", vpnProfiles.containsKey(OBFS4)); + } + + @Test + public void testGenerateVpnProfile_ObfuscationPinningEnabled_kcp_obfs4KcpProfile () throws Exception { + gateway = new JSONObject(TestSetupHelper.getInputAsString(getClass().getClassLoader().getResourceAsStream("ptdemo_kcp_gateways.json"))).getJSONArray("gateways").getJSONObject(0); + generalConfig = new JSONObject(TestSetupHelper.getInputAsString(getClass().getClassLoader().getResourceAsStream("ptdemo_kcp_gateways.json"))).getJSONObject(OPENVPN_CONFIGURATION); + VpnConfigGenerator.Configuration configuration = new VpnConfigGenerator.Configuration(); + configuration.apiVersion = 3; + configuration.useObfuscationPinning = true; + configuration.obfuscationProxyKCP = true; + configuration.obfuscationProxyPort = "443"; + configuration.obfuscationProxyIP = "5.6.7.8"; + configuration.obfuscationProxyCert = "asdfasdf"; + configuration.remoteGatewayIP = "1.2.3.4"; + + vpnConfigGenerator = new VpnConfigGenerator(generalConfig, secrets, gateway, configuration); + HashMap<Connection.TransportType, VpnProfile> vpnProfiles = vpnConfigGenerator.generateVpnProfiles(); + assertTrue("has obfs4_kcp profile", vpnProfiles.containsKey(OBFS4_KCP)); + assertFalse("has openvpn profile", vpnProfiles.containsKey(OPENVPN)); + assertFalse("has no obfs4 profile", vpnProfiles.containsKey(OBFS4)); } } \ No newline at end of file diff --git a/app/src/test/java/se/leap/bitmaskclient/testutils/BackendMockResponses/NoErrorBackendResponseAPIv4.java b/app/src/test/java/se/leap/bitmaskclient/testutils/BackendMockResponses/NoErrorBackendResponseAPIv4.java index 3b77834f830f6fd4526eb518e85889e18f28937e..b9dc26b19bcdfc540e480199bb6d9f3b37817c54 100644 --- a/app/src/test/java/se/leap/bitmaskclient/testutils/BackendMockResponses/NoErrorBackendResponseAPIv4.java +++ b/app/src/test/java/se/leap/bitmaskclient/testutils/BackendMockResponses/NoErrorBackendResponseAPIv4.java @@ -53,6 +53,9 @@ public class NoErrorBackendResponseAPIv4 extends BaseBackendResponse { } else if (url.contains(":9001/json")) { // download geoip json, containing a sorted list of gateways return getInputAsString(getClass().getClassLoader().getResourceAsStream("riseup.geoip.json")); + } else if (url.contains("/cert")) { + // download vpn key and cert + return getInputAsString(getClass().getClassLoader().getResourceAsStream("v4/riseup.net.cert")); } else if (url.contains("/users.json")) { //create new user //TODO: implement me diff --git a/app/src/test/java/se/leap/bitmaskclient/testutils/BackendMockResponses/TorFallbackBackendResponse.java b/app/src/test/java/se/leap/bitmaskclient/testutils/BackendMockResponses/TorFallbackBackendResponse.java index dc12ae891842acc4b147e7206bd5fbeeb150ad6e..c3779a21e11026938cc70bed8bc098a450088aab 100644 --- a/app/src/test/java/se/leap/bitmaskclient/testutils/BackendMockResponses/TorFallbackBackendResponse.java +++ b/app/src/test/java/se/leap/bitmaskclient/testutils/BackendMockResponses/TorFallbackBackendResponse.java @@ -49,6 +49,14 @@ public class TorFallbackBackendResponse extends BaseBackendResponse { } // download geoip json, containing a sorted list of gateways return getInputAsString(getClass().getClassLoader().getResourceAsStream("riseup.geoip.json")); + } else if (url.contains("/cert")) { + if (requestAttempt == 0) { + requestAttempt++; + throw new UnknownHostException("DNS blocked by censor ;)"); + } + // download vpn certificate for authentication + return getInputAsString(getClass().getClassLoader().getResourceAsStream("v4/riseup.net.cert")); + } return null; diff --git a/app/src/test/java/se/leap/bitmaskclient/testutils/MockHelper.java b/app/src/test/java/se/leap/bitmaskclient/testutils/MockHelper.java index 8d76fd4106a2e4a54cf3a07e5fc5dc1943bfbb77..651aa345ad3c8b980870fcfb5219fd4cb976e925 100644 --- a/app/src/test/java/se/leap/bitmaskclient/testutils/MockHelper.java +++ b/app/src/test/java/se/leap/bitmaskclient/testutils/MockHelper.java @@ -1,5 +1,29 @@ package se.leap.bitmaskclient.testutils; +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertThat; +import static org.mockito.ArgumentMatchers.any; +import static org.mockito.ArgumentMatchers.anyBoolean; +import static org.mockito.ArgumentMatchers.anyInt; +import static org.mockito.ArgumentMatchers.anyString; +import static org.mockito.ArgumentMatchers.eq; +import static org.mockito.Mockito.RETURNS_DEEP_STUBS; +import static org.mockito.Mockito.doAnswer; +import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.when; +import static org.powermock.api.mockito.PowerMockito.mockStatic; +import static se.leap.bitmaskclient.base.models.Constants.PROVIDER_MOTD; +import static se.leap.bitmaskclient.base.models.Constants.PROVIDER_MOTD_HASHES; +import static se.leap.bitmaskclient.base.models.Constants.PROVIDER_MOTD_LAST_SEEN; +import static se.leap.bitmaskclient.base.models.Constants.PROVIDER_MOTD_LAST_UPDATED; +import static se.leap.bitmaskclient.base.models.Constants.PROVIDER_PRIVATE_KEY; +import static se.leap.bitmaskclient.base.models.Constants.PROVIDER_VPN_CERTIFICATE; +import static se.leap.bitmaskclient.base.utils.FileHelper.createFile; +import static se.leap.bitmaskclient.base.utils.PreferenceHelper.getEipDefinitionFromPreferences; +import static se.leap.bitmaskclient.base.utils.PreferenceHelper.getFromPersistedProvider; +import static se.leap.bitmaskclient.base.utils.PreferenceHelper.getLongFromPersistedProvider; +import static se.leap.bitmaskclient.base.utils.PreferenceHelper.getStringSetFromPersistedProvider; + import android.content.Context; import android.content.Intent; import android.content.SharedPreferences; @@ -23,11 +47,15 @@ import java.io.File; import java.io.FileNotFoundException; import java.io.IOException; import java.io.InputStream; +import java.math.BigInteger; import java.net.UnknownHostException; import java.security.NoSuchAlgorithmException; import java.security.cert.CertificateEncodingException; import java.security.cert.X509Certificate; +import java.security.interfaces.RSAPrivateKey; import java.util.ArrayList; +import java.util.Arrays; +import java.util.Base64; import java.util.HashMap; import java.util.HashSet; import java.util.Iterator; @@ -51,24 +79,6 @@ import se.leap.bitmaskclient.testutils.BackendMockResponses.BackendMockProvider; import se.leap.bitmaskclient.testutils.matchers.BundleMatcher; import se.leap.bitmaskclient.tor.TorStatusObservable; -import static org.junit.Assert.assertEquals; -import static org.junit.Assert.assertThat; -import static org.mockito.ArgumentMatchers.any; -import static org.mockito.ArgumentMatchers.anyBoolean; -import static org.mockito.ArgumentMatchers.anyInt; -import static org.mockito.ArgumentMatchers.anyString; -import static org.mockito.ArgumentMatchers.eq; -import static org.mockito.Mockito.RETURNS_DEEP_STUBS; -import static org.mockito.Mockito.doAnswer; -import static org.mockito.Mockito.mock; -import static org.mockito.Mockito.when; -import static org.powermock.api.mockito.PowerMockito.mockStatic; -import static se.leap.bitmaskclient.base.models.Constants.PROVIDER_PRIVATE_KEY; -import static se.leap.bitmaskclient.base.models.Constants.PROVIDER_VPN_CERTIFICATE; -import static se.leap.bitmaskclient.base.utils.FileHelper.createFile; -import static se.leap.bitmaskclient.base.utils.PreferenceHelper.getEipDefinitionFromPreferences; -import static se.leap.bitmaskclient.base.utils.PreferenceHelper.getFromPersistedProvider; - /** * Created by cyberta on 29.01.18. */ @@ -408,6 +418,10 @@ public class MockHelper { when(createFile(any(File.class), anyString())).thenReturn(mockedFile); } + public static void mockBase64() { + mockStatic(android.util.Base64.class); + when(android.util.Base64.encodeToString(any(), anyInt())).thenAnswer(invocation -> Arrays.toString(Base64.getEncoder().encode((byte[]) invocation.getArguments()[0]))); + } public static void mockConfigHelper(String mockedFingerprint) throws CertificateEncodingException, NoSuchAlgorithmException { mockStatic(ConfigHelper.class); when(ConfigHelper.getFingerprintFromCertificate(any(X509Certificate.class), anyString())).thenReturn(mockedFingerprint); @@ -417,6 +431,33 @@ public class MockHelper { when(ConfigHelper.timezoneDistance(anyInt(), anyInt())).thenCallRealMethod(); when(ConfigHelper.isIPv4(anyString())).thenCallRealMethod(); when(ConfigHelper.isDefaultBitmask()).thenReturn(true); + when(ConfigHelper.getDomainFromMainURL(anyString())).thenCallRealMethod(); + when(ConfigHelper.parseRsaKeyFromString(anyString())).thenReturn(new RSAPrivateKey() { + @Override + public BigInteger getPrivateExponent() { + return BigInteger.TEN; + } + + @Override + public String getAlgorithm() { + return "RSA"; + } + + @Override + public String getFormat() { + return null; + } + + @Override + public byte[] getEncoded() { + return new byte[0]; + } + + @Override + public BigInteger getModulus() { + return BigInteger.ONE; + } + }); } public static void mockPreferenceHelper(final Provider providerFromPrefs) { @@ -439,11 +480,39 @@ public class MockHelper { return providerFromPrefs.getCaCert(); case Provider.GEOIP_URL: return providerFromPrefs.getGeoipUrl().toString(); + case Provider.MOTD_URL: + return providerFromPrefs.getMotdUrl().toString(); + case PROVIDER_MOTD: + return providerFromPrefs.getMotdJsonString(); } return null; } }); + when(getLongFromPersistedProvider(anyString(), anyString(), any(SharedPreferences.class))).thenAnswer(new Answer<Long>() { + @Override + public Long answer(InvocationOnMock invocation) throws Throwable { + String key = (String) invocation.getArguments()[0]; + switch (key) { + case PROVIDER_MOTD_LAST_SEEN: + return providerFromPrefs.getLastMotdSeen(); + case PROVIDER_MOTD_LAST_UPDATED: + return providerFromPrefs.getLastMotdUpdate(); + } + return 0L; + } + }); + when(getStringSetFromPersistedProvider(anyString(), anyString(), any(SharedPreferences.class))).thenAnswer(new Answer<Set<String>>() { + @Override + public Set<String> answer(InvocationOnMock invocation) throws Throwable { + String key = (String) invocation.getArguments()[0]; + switch (key) { + case PROVIDER_MOTD_HASHES: + return providerFromPrefs.getMotdLastSeenHashes(); + } + return null; + } + }); } public static void mockPreferenceHelper(MockSharedPreferences preferences) { @@ -481,9 +550,9 @@ public class MockHelper { }); when(TorStatusObservable.getSnowflakeStatus()).thenAnswer((Answer<TorStatusObservable.SnowflakeStatus>) invocation -> { if (waitUntilSuccess.get()) { - return TorStatusObservable.SnowflakeStatus.ON; + return TorStatusObservable.SnowflakeStatus.STARTED; } - return TorStatusObservable.SnowflakeStatus.OFF; + return TorStatusObservable.SnowflakeStatus.STOPPED; }); if (exception != null) { diff --git a/app/src/test/java/se/leap/bitmaskclient/testutils/MockSharedPreferences.java b/app/src/test/java/se/leap/bitmaskclient/testutils/MockSharedPreferences.java index be0cf41f54c1e441f3a7ec5ea1fe831597741576..4fabc2c0dd9c92ee809589dfe314bf36c2464fb3 100644 --- a/app/src/test/java/se/leap/bitmaskclient/testutils/MockSharedPreferences.java +++ b/app/src/test/java/se/leap/bitmaskclient/testutils/MockSharedPreferences.java @@ -21,6 +21,7 @@ import android.content.SharedPreferences; import androidx.annotation.Nullable; import java.util.HashMap; +import java.util.HashSet; import java.util.Map; import java.util.Set; @@ -48,7 +49,7 @@ public class MockSharedPreferences implements SharedPreferences { @Nullable @Override public Set<String> getStringSet(String key, @Nullable Set<String> defValues) { - return null; + return new HashSet<>(); } @Override diff --git a/app/src/test/resources/ptdemo_kcp_gateways.json b/app/src/test/resources/ptdemo_kcp_gateways.json new file mode 100644 index 0000000000000000000000000000000000000000..332c8c11e2b471d05baaa59a6e77a7285a8c31f1 --- /dev/null +++ b/app/src/test/resources/ptdemo_kcp_gateways.json @@ -0,0 +1,160 @@ +{ + "gateways":[ + { + "capabilities":{ + "adblock":false, + "filter_dns":false, + "limited":false, + "transport":[ + { + "type":"obfs4", + "protocols":[ + "tcp" + ], + "ports":[ + "23049" + ], + "options": { + "cert": "XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX1", + "iatMode": "0" + } + }, + { + "type":"obfs4-1", + "protocols":[ + "tcp" + ], + "ports":[ + "23050" + ], + "options": { + "cert": "XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX1", + "iatMode": "0" + } + }, + { + "type":"openvpn", + "protocols":[ + "tcp" + ], + "ports":[ + "1195" + ] + } + ], + "user_ips":false + }, + "host":"pt.demo.bitmask.net", + "ip_address":"37.218.247.60", + "location":"Amsterdam" + }, + { + "capabilities":{ + "adblock":false, + "filter_dns":false, + "limited":false, + "transport":[ + { + "type":"obfs4", + "protocols":[ + "tcp" + ], + "ports":[ + "443" + ], + "options": { + "cert": "XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX2", + "iatMode": "0" + } + }, + { + "type":"openvpn", + "protocols":[ + "tcp" + ], + "ports":[ + "1195" + ] + } + ], + "user_ips":false + }, + "host":"moscow.bitmask.net", + "ip_address":"3.21.247.89", + "location":"moscow" + }, + { + "capabilities":{ + "adblock":false, + "filter_dns":false, + "limited":false, + "transport":[ + { + "type":"openvpn", + "protocols":[ + "tcp", + "udp" + ], + + "ports":[ + "1195" + ] + }, + { + "type":"obfs4-1", + "protocols":[ + "tcp" + ], + "ports":[ + "23050" + ], + "options": { + "cert": "XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX1", + "iatMode": "0" + } + } + ], + "user_ips":false + }, + "host":"manila.bitmask.net", + "ip_address":"37.12.247.10", + "location":"manila" + } + ], + "locations":{ + "Amsterdam":{ + "country_code":"NL", + "hemisphere":"N", + "name":"Amsterdam", + "timezone":"-1" + }, + "moscow": { + "country_code": "RU", + "hemisphere": "N", + "name": "Moscow", + "timezone": "+3" + }, + "manila": { + "country_code": "PH", + "hemisphere": "N", + "name": "Manila", + "timezone": "+8" + } + }, + "openvpn_configuration":{ + "auth":"SHA1", + "cipher":"AES-256-CBC", + "keepalive":"10 30", + "tls-cipher":"DHE-RSA-AES128-SHA", + "tun-ipv6":true, + "dev" : "tun", + "sndbuf" : "0", + "rcvbuf" : "0", + "nobind" : true, + "persist-key" : true, + "key-direction" : "1", + "verb" : "3" + }, + "serial":2, + "version":3 +} \ No newline at end of file diff --git a/app/src/test/resources/ptdemo_kcp_gateways_geoip.json b/app/src/test/resources/ptdemo_kcp_gateways_geoip.json new file mode 100644 index 0000000000000000000000000000000000000000..9ac7257d33fb383d8ffe397b84ca3926c3bb5bbe --- /dev/null +++ b/app/src/test/resources/ptdemo_kcp_gateways_geoip.json @@ -0,0 +1,29 @@ +{ + "ip":"51.158.144.32", + "cc":"FR", + "city":"Paris", + "lat":48.8628, + "lon":2.3292, + "gateways":[ + "pt.demo.bitmask.net", + "moscow.bitmask.net", + "manila.bitmask.net" + ], + "sortedGateways": [ + { + "host": "pt.demo.bitmask.net", + "fullness": 0.3, + "overload": false + }, + { + "host": "moscow.bitmask.net", + "fullness": 0.36, + "overload": false + }, + { + "host": "manila.bitmask.net", + "fullness": 0.59, + "overload": false + } + ] +} \ No newline at end of file diff --git a/app/src/test/resources/ptdemo_misconfigured_kcp_gateways.json b/app/src/test/resources/ptdemo_misconfigured_kcp_gateways.json new file mode 100644 index 0000000000000000000000000000000000000000..94a1eafd1bc1b79b228652f9af7cee674ddbf5df --- /dev/null +++ b/app/src/test/resources/ptdemo_misconfigured_kcp_gateways.json @@ -0,0 +1,160 @@ +{ + "gateways":[ + { + "capabilities":{ + "adblock":false, + "filter_dns":false, + "limited":false, + "transport":[ + { + "type":"obfs4", + "protocols":[ + "tcp" + ], + "ports":[ + "23049" + ], + "options": { + "cert": "XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX1", + "iatMode": "0" + } + }, + { + "type":"obfs4-1", + "protocols":[ + "udp" + ], + "ports":[ + "23050" + ], + "options": { + "cert": "XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX1", + "iatMode": "0" + } + }, + { + "type":"openvpn", + "protocols":[ + "tcp" + ], + "ports":[ + "1195" + ] + } + ], + "user_ips":false + }, + "host":"pt.demo.bitmask.net", + "ip_address":"37.218.247.60", + "location":"Amsterdam" + }, + { + "capabilities":{ + "adblock":false, + "filter_dns":false, + "limited":false, + "transport":[ + { + "type":"obfs4", + "protocols":[ + "tcp" + ], + "ports":[ + "443" + ], + "options": { + "cert": "XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX2", + "iatMode": "0" + } + }, + { + "type":"openvpn", + "protocols":[ + "tcp" + ], + "ports":[ + "1195" + ] + } + ], + "user_ips":false + }, + "host":"moscow.bitmask.net", + "ip_address":"3.21.247.89", + "location":"moscow" + }, + { + "capabilities":{ + "adblock":false, + "filter_dns":false, + "limited":false, + "transport":[ + { + "type":"openvpn", + "protocols":[ + "tcp", + "udp" + ], + + "ports":[ + "1195" + ] + }, + { + "type":"obfs4-1", + "protocols":[ + "udp" + ], + "ports":[ + "23050" + ], + "options": { + "cert": "XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX1", + "iatMode": "0" + } + } + ], + "user_ips":false + }, + "host":"manila.bitmask.net", + "ip_address":"37.12.247.10", + "location":"manila" + } + ], + "locations":{ + "Amsterdam":{ + "country_code":"NL", + "hemisphere":"N", + "name":"Amsterdam", + "timezone":"-1" + }, + "moscow": { + "country_code": "RU", + "hemisphere": "N", + "name": "Moscow", + "timezone": "+3" + }, + "manila": { + "country_code": "PH", + "hemisphere": "N", + "name": "Manila", + "timezone": "+8" + } + }, + "openvpn_configuration":{ + "auth":"SHA1", + "cipher":"AES-256-CBC", + "keepalive":"10 30", + "tls-cipher":"DHE-RSA-AES128-SHA", + "tun-ipv6":true, + "dev" : "tun", + "sndbuf" : "0", + "rcvbuf" : "0", + "nobind" : true, + "persist-key" : true, + "key-direction" : "1", + "verb" : "3" + }, + "serial":2, + "version":3 +} \ No newline at end of file diff --git a/app/src/test/resources/ptdemo_misconfigured_udp2.json b/app/src/test/resources/ptdemo_misconfigured_udp2.json new file mode 100644 index 0000000000000000000000000000000000000000..d2a54cef541adbd086e4e51fd84d23482a4d3c3a --- /dev/null +++ b/app/src/test/resources/ptdemo_misconfigured_udp2.json @@ -0,0 +1,65 @@ +{ + "gateways":[ + { + "capabilities":{ + "adblock":false, + "filter_dns":false, + "limited":false, + "transport":[ + { + "type":"obfs4", + "protocols":[ + "tcp" + ], + "ports":[ + "23049" + ], + "options": { + "cert": "XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX", + "iatMode": "0" + } + }, + { + "type":"openvpn", + "protocols":[ + "udp" + ], + "ports":[ + "1195" + ] + } + ], + "user_ips":false + }, + "host":"pt.demo.bitmask.net", + "ip_address6":"2001:db8:123::1058", + "ip_address":"37.218.247.60", + "location":"Amsterdam" + } + ], + "locations":{ + "Amsterdam":{ + "country_code":"NL", + "hemisphere":"N", + "name":"Amsterdam", + "timezone":"-1" + } + }, + "openvpn_configuration":{ + "auth":"SHA1", + "cipher":"AES-256-CBC", + "keepalive":"10 30", + "tls-cipher":"DHE-RSA-AES128-SHA", + "tun-ipv6":true, + "dev" : "tun", + "sndbuf" : "0", + "rcvbuf" : "0", + "nobind" : true, + "persist-key" : true, + "comp-lzo" : true, + "key-direction" : "1", + "verb" : "3" + }, + "serial":2, + "version":3 +} \ No newline at end of file diff --git a/app/src/test/resources/ptdemo_only_experimental_transports_gateways.json b/app/src/test/resources/ptdemo_only_experimental_transports_gateways.json new file mode 100644 index 0000000000000000000000000000000000000000..31c919e722b23cfe95c4f3993da193dcbb98fa33 --- /dev/null +++ b/app/src/test/resources/ptdemo_only_experimental_transports_gateways.json @@ -0,0 +1,134 @@ +{ + "gateways":[ + { + "capabilities":{ + "adblock":false, + "filter_dns":false, + "limited":false, + "transport":[ + { + "type":"obfs4-1", + "protocols":[ + "tcp" + ], + "ports":[ + "23050" + ], + "options": { + "cert": "XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX1", + "iatMode": "0" + } + }, + { + "type":"openvpn", + "protocols":[ + "tcp" + ], + "ports":[ + "1195" + ] + } + ], + "user_ips":false + }, + "host":"pt.demo.bitmask.net", + "ip_address":"37.218.247.60", + "location":"Amsterdam" + }, + { + "capabilities":{ + "adblock":false, + "filter_dns":false, + "limited":false, + "transport":[ + { + "type":"openvpn", + "protocols":[ + "tcp" + ], + "ports":[ + "1195" + ] + } + ], + "user_ips":false + }, + "host":"moscow.bitmask.net", + "ip_address":"3.21.247.89", + "location":"moscow" + }, + { + "capabilities":{ + "adblock":false, + "filter_dns":false, + "limited":false, + "transport":[ + { + "type":"openvpn", + "protocols":[ + "tcp", + "udp" + ], + + "ports":[ + "1195" + ] + }, + { + "type":"obfs4-1", + "protocols":[ + "tcp" + ], + "ports":[ + "23050" + ], + "options": { + "cert": "XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX1", + "iatMode": "0" + } + } + ], + "user_ips":false + }, + "host":"manila.bitmask.net", + "ip_address":"37.12.247.10", + "location":"manila" + } + ], + "locations":{ + "Amsterdam":{ + "country_code":"NL", + "hemisphere":"N", + "name":"Amsterdam", + "timezone":"-1" + }, + "moscow": { + "country_code": "RU", + "hemisphere": "N", + "name": "Moscow", + "timezone": "+3" + }, + "manila": { + "country_code": "PH", + "hemisphere": "N", + "name": "Manila", + "timezone": "+8" + } + }, + "openvpn_configuration":{ + "auth":"SHA1", + "cipher":"AES-256-CBC", + "keepalive":"10 30", + "tls-cipher":"DHE-RSA-AES128-SHA", + "tun-ipv6":true, + "dev" : "tun", + "sndbuf" : "0", + "rcvbuf" : "0", + "nobind" : true, + "persist-key" : true, + "key-direction" : "1", + "verb" : "3" + }, + "serial":2, + "version":3 +} \ No newline at end of file diff --git a/app/src/test/resources/v4/ptdemo_pt_tcp_udp_new_ciphers.eip-service.json b/app/src/test/resources/v4/ptdemo_pt_tcp_udp_new_ciphers.eip-service.json new file mode 100644 index 0000000000000000000000000000000000000000..10f5b4d3603f1ff1dbe6d7cd13497ba765b25875 --- /dev/null +++ b/app/src/test/resources/v4/ptdemo_pt_tcp_udp_new_ciphers.eip-service.json @@ -0,0 +1,66 @@ +{ + "gateways":[ + { + "capabilities":{ + "adblock":false, + "filter_dns":false, + "limited":false, + "transport":[ + { + "type":"obfs4", + "protocols":[ + "tcp" + ], + "ports":[ + "23049" + ], + "options": { + "cert": "XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX", + "iatMode": "0" + } + }, + { + "type":"openvpn", + "protocols":[ + "tcp", + "udp" + ], + "ports":[ + "1195" + ] + } + ], + "user_ips":false + }, + "host":"pt.demo.bitmask.net", + "ip_address":"37.218.247.60", + "ip_address6":"2001:db8:123::1056", + "location":"Amsterdam" + } + ], + "locations":{ + "Amsterdam":{ + "country_code":"NL", + "hemisphere":"N", + "name":"Amsterdam", + "timezone":"-1" + } + }, + "openvpn_configuration":{ + "auth": "SHA1", + "cipher": "AES-256-GCM:AES-128-CBC", + "dev": "tun", + "float": "", + "keepalive": "10 30", + "key-direction": "1", + "nobind": true, + "persist-key": true, + "rcvbuf": "0", + "sndbuf": "0", + "tls-cipher": "TLS-ECDHE-ECDSA-WITH-AES-256-GCM-SHA384:DHE-RSA-AES128-SHA", + "tls-version-min": "1.2", + "verb": "3" + }, + "serial":4, + "version":4 +} \ No newline at end of file diff --git a/app/src/test/resources/v4/riseup.net.cert b/app/src/test/resources/v4/riseup.net.cert new file mode 100644 index 0000000000000000000000000000000000000000..1beff4bd128b54ef4104b199d194d971aab5c1fa --- /dev/null +++ b/app/src/test/resources/v4/riseup.net.cert @@ -0,0 +1,54 @@ +-----BEGIN RSA PRIVATE KEY----- +MIIEowIBAAKCAQEAqSkd5UbKh+HbWSH603MJNgSkomeBnPooE0dlxYXIOQa/HnTl +5+7CV47JDWjFWSj1h+zeAmXcgkQxDRF1rbZ+oov26SYyGingBQgn9qvoCZwIdesE +N5Xhdvt23FK8edanCMN/tn1CnyaO5xvHdWRvhpmEf9zAsVwo9qfx1vmRsJfzvcnH +rHoCgH3nxzK1VZm5xNGRdAm9jA2odYYIuSKN1hSYgjcnXVvNHm3bWs+B4RzgtrZG +vy+vsSSd6AaYGQ4sCj3DOuKNOWqXZ8yFpfjbi0rYsOmzxEFiZiequxhrafSM+2uy +NbdPsPXKd0veZh1ApDEHW/6I+qP0bnHE6Dtr+wIDAQABAoIBABnwxjbcrj48Mmju +vwoh/+2atKx69vNdoTujnUW3CEdGc5R2FLOGd6L5sHcv8+OCVnSrrDft6uzHDEaW +wNcMv0qp8Ak85D4C4emjoI1BO2oN1XZPvevQPi0Czu1meqSseBzt7e3MM6U4Qn3K +UsH7zuZzMFBzR9Fq8pUwl/OBfgf4ZWF0IeHFx1/T+3A/lCTdki2wZ8M7pN7djED1 +fqmbwXt3KSnhhOAjZm17qhVM6K+kA3EInsijShbeUTtQMyZCifIrtj5EHYf/sr3f +mlXdspIaR5Wh5tKQo9TRrBNgmMxg+GhBz7fwaM2P1uZXVWTAK4L35vz17o0AQR0P +aItWxyECgYEA3fEGWgH53tATZklxiXaEInCve+XNpE2m80g1hNkIS36D676e0Mxm +L1PlgO+YDRgLBAQVbSdUbfQrcc8Zlcn7R2a0X1a12OH/4pKFXNM4doS/3k5wN1TI +Zr7+AqP4vaLVNt8fjYBhRYpOdwpr5PTjJCpP9dh3ItuIOyH/w+2k4iMCgYEAwx6Y +Cjkn7IaBJOr0kK5JORlGx10jfUmMLMiaJATs49vAcgxt7rKTiEUNvS1YArR4Vh/n +hAYmsC76folGTeZjotmzQbUkm/yZ3OMTSrcja85uM7NJbt9CnUPiDkKDEY4Exhuh +K/Ls+Lp6/eIyJ+b4/xpFEzlUQyY4WiZ6UWcEUEkCgYEAxsqVYtd0RQPg7HSKMpMq +RWLje7lZWXqIOE6MSWLQUDaQ2P6TZ/g86tVdswBoFApeC4nQ20UoFZhntXfHtegF +n225z89t8EZ1mS6eL4etglLjPK7LSnQxT/5wrFLMgKcyDQULUQYVmmEIaQ23mItU +TFdt6YmrJFi4jCam3YqlbjsCgYACzTSnqOxu0/uUuR7r2OTKQhenEypIST8PAY5d +CAkSuHwJ5y3I6J1/rmYlGjqSR18W9XxQg/oYO4RzPqtYwP8bPn75aY1uA/F9n3EO +eJS0npEsgt2CDwiY03mydLgHD3/4DDuDMwi+BYdwj8filMlseEcXoJIaKLlUagsF +kjIYqQKBgEDDiM51YU2V1k4rzdzICdfo5mqa7FiQ2JiRs3yG20gNg3nDReQZk0Q4 +poJkZksuojQabDOnHzWc2jfUehll6gC1ijtRzaoSeRH2m8X5JXb3vfAe5/TFZHBg +bErDqPo+En9Y72LIcGG5vlzQHfE0l24C0oQ64cssLHA9+VnYmwhw +-----END RSA PRIVATE KEY----- +-----BEGIN CERTIFICATE----- +MIIEmzCCAoOgAwIBAgIQejc1yqfKGehUKDMdybDH+DANBgkqhkiG9w0BAQsFADB1 +MRgwFgYDVQQKDA9SaXNldXAgTmV0d29ya3MxGzAZBgNVBAsMEmh0dHBzOi8vcmlz +ZXVwLm5ldDE8MDoGA1UEAwwzUmlzZXVwIE5ldHdvcmtzIFJvb3QgQ0EgKGNsaWVu +dCBjZXJ0aWZpY2F0ZXMgb25seSEpMB4XDTIyMTAxNDAwMDAwMFoXDTIzMDExNDAw +MDAwMFowLTErMCkGA1UEAwwiVU5MSU1JVEVEMTMxaXF4cHB0cHljYnN3eGRueXRu +aHhiMDCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAKkpHeVGyofh21kh ++tNzCTYEpKJngZz6KBNHZcWFyDkGvx505efuwleOyQ1oxVko9Yfs3gJl3IJEMQ0R +da22fqKL9ukmMhop4AUIJ/ar6AmcCHXrBDeV4Xb7dtxSvHnWpwjDf7Z9Qp8mjucb +x3Vkb4aZhH/cwLFcKPan8db5kbCX873Jx6x6AoB958cytVWZucTRkXQJvYwNqHWG +CLkijdYUmII3J11bzR5t21rPgeEc4La2Rr8vr7EknegGmBkOLAo9wzrijTlql2fM +haX424tK2LDps8RBYmYnqrsYa2n0jPtrsjW3T7D1yndL3mYdQKQxB1v+iPqj9G5x +xOg7a/sCAwEAAaNvMG0wHQYDVR0OBBYEFEFB2IaA9Z5TOAPtMw3vgKvRR+tpMAsG +A1UdDwQEAwIHgDATBgNVHSUEDDAKBggrBgEFBQcDAjAJBgNVHRMEAjAAMB8GA1Ud +IwQYMBaAFBf0G9XlKgEBTWuiXTYKKQmWZYBGMA0GCSqGSIb3DQEBCwUAA4ICAQB0 +x+RhbfmWuKQ7clT2oBhLOep1USJ9y98BLMsEmqZ84q0CnG+tI2QLhZvaMiGiMplI +saHhK1lIHbO/UATHOhE+ZbY9vAaGK1JaBdlOTshjo+cijZ2nWwfwa9Qj/Cx64sSO +cee3Lbg5IcsFc/0KGCTw0k9PheD/CudRSnLCxImA8DmJO+1w1NUoBBm48tdD6usD +fLU35FvChvNwW/7GO/q3TGXF/jrreBnrJZMjsffwFOJC8SWZIAScmF/OrqWyruYb +ZS9/0ZXR21TT1mvUFjIs+0uY2crfli/f91ZbB9eRoiyHkck8RtotiH9PrmYt7j02 +5cwos2BqRs+kZ7AgYvZjWErwIyCsXSzrk0WztLa2vslqZSZSt12VlW5iIyKTyx8T +snQLEdHwzRT5C+9daq3PneOvD5KhgyySlwWSoMuJdg2n3cTs/0uMDQE7FIim11XM +Fz8liZf4PcWv8YLFUBHQ367SvbAiyZLzpXZETQyDaYNYGTwYBCGs9Yhq3KM85Kmz +f0rgrBpm61ujLQ/OBSCq6/RA9BN8UYdO+YS0vengYtIdc+aw1PzLhcC9dLLXC4ef +zH25zfe7vkt58UcuG+YCsaIR8Hy3I/yDQWVkbNawEYUboEHHRd8pQmUIkHLaYibt +eq1SXtuulUUDIkyfRATiA/GkPVPPnJImL8XK12WFPQ== +-----END CERTIFICATE----- diff --git a/bitmaskcore b/bitmaskcore index 5e5b3ebebc5437e83f3bc5f0afce46b6b4aa4655..1040f75b4fcb9db89ad9c17120f11bab2c99085d 160000 --- a/bitmaskcore +++ b/bitmaskcore @@ -1 +1 @@ -Subproject commit 5e5b3ebebc5437e83f3bc5f0afce46b6b4aa4655 +Subproject commit 1040f75b4fcb9db89ad9c17120f11bab2c99085d diff --git a/build.gradle b/build.gradle index a995fd04055875b8fcd7f67b8c1283f616c711a1..6fbe32075de06b285fa246a90437894de45428b4 100644 --- a/build.gradle +++ b/build.gradle @@ -5,11 +5,10 @@ buildscript { name 'Google' } mavenCentral() - jcenter() - google() + google() } dependencies { - classpath 'com.android.tools.build:gradle:4.1.2' + classpath 'com.android.tools.build:gradle:7.2.2' } } @@ -24,6 +23,5 @@ allprojects { name 'Google' } mavenCentral() - jcenter() } } diff --git a/docker/android-emulator/Dockerfile b/docker/android-emulator/Dockerfile index b5f5f32b0a9401f2ed6ed45d707dd8f01bb1659e..1c12cb6d9df1f7eb07e605a8977628316754a08f 100644 --- a/docker/android-emulator/Dockerfile +++ b/docker/android-emulator/Dockerfile @@ -1,7 +1,7 @@ FROM registry.0xacab.org/leap/bitmask_android/android-sdk:latest MAINTAINER LEAP Encryption Access Project <info@leap.se> -LABEL Description="Android SDK baseimage based on debian:bullseye" Vendor="LEAP" Version="27" +LABEL Description="Android SDK baseimage based on debian:bullseye" Vendor="LEAP" Version="31" # Make sure debconf doesn't complain about lack of interactivity ENV DEBIAN_FRONTEND noninteractive @@ -30,9 +30,9 @@ RUN apt-get update -qq && \ RUN echo y | sdkmanager "emulator" # Install System Images for emulators -RUN echo y | sdkmanager "system-images;android-30;google_apis;x86" +RUN echo y | sdkmanager "system-images;android-31;google_apis;x86_64" # RUN echo y | sdkmanager "system-images;android-27;google_apis;x86" # RUN echo y | sdkmanager "system-images;android-25;google_apis;x86_64" # RUN echo y | sdkmanager "system-images;android-23;google_apis;x86_64" -RUN echo no | avdmanager create avd --force --name testApi30 --abi google_apis/x86 --package 'system-images;android-30;google_apis;x86' +RUN echo no | avdmanager create avd --force --name testApi31 --abi google_apis/x86_64 --package 'system-images;android-31;google_apis;x86_64' diff --git a/docker/android-ndk/Dockerfile b/docker/android-ndk/Dockerfile index 8fe535f50b1e9aaf8ab6ee2a495160d4882d68ca..ffe189b3b7b751f59bc6cb7991641bdb461db930 100644 --- a/docker/android-ndk/Dockerfile +++ b/docker/android-ndk/Dockerfile @@ -24,7 +24,7 @@ RUN apt-get update -qq && \ # JNI build dependencies w/ 32-bit compatible C libs RUN apt-get update -qq && \ apt-get -y install docker-ce docker-ce-cli make gcc swig file lib32stdc++6 lib32z1 \ - autoconf autogen automake autopoint autotools-dev gettext-base libtool patch pkg-config && \ + autoconf autogen automake autopoint autotools-dev gettext-base libtool patch pkg-config po4a && \ apt-get clean && \ apt-get autoclean && \ rm -rf /var/lib/apt/lists/* /tmp/* /var/tmp/* diff --git a/docker/android-sdk/Dockerfile b/docker/android-sdk/Dockerfile index 6093cf1877c9f507228eb5baf1162dd15041d7ce..6f996616a4c31dd98c9fba38d83a9a36c8692b5a 100644 --- a/docker/android-sdk/Dockerfile +++ b/docker/android-sdk/Dockerfile @@ -1,7 +1,7 @@ FROM 0xacab.org:4567/leap/docker/debian:bullseye_amd64 MAINTAINER LEAP Encryption Access Project <info@leap.se> -LABEL Description="Android SDK baseimage based on debian:bullseye" Vendor="LEAP" Version="27.0.0" +LABEL Description="Android SDK baseimage based on debian:bullseye" Vendor="LEAP" Version="31.0.0" # ------------------------------------------------------ # --- Install System Dependencies @@ -77,18 +77,10 @@ RUN echo y | sdkmanager "platform-tools" # echo y to accept google licenses RUN sdkmanager "extras;android;m2repository" # Install Build Tools (Please keep in descending order) -RUN sdkmanager "build-tools;30.0.3" -# RUN sdkmanager "build-tools;28.0.3" -# RUN sdkmanager "build-tools;27.0.3" -# RUN sdkmanager "build-tools;25.0.2" -# RUN sdkmanager "build-tools;23.0.3" +RUN sdkmanager "build-tools;31.0.0" # Install Target SDK Packages (Please keep in descending order) -RUN sdkmanager "platforms;android-30" -# RUN sdkmanager "platforms;android-28" -# RUN sdkmanager "platforms;android-27" -# RUN sdkmanager "platforms;android-25" -# RUN sdkmanager "platforms;android-23" +RUN sdkmanager "platforms;android-31" RUN echo "accept all licenses" # Accept all licenses diff --git a/docs/PrivacyPolicy.md b/docs/PrivacyPolicy.md new file mode 100644 index 0000000000000000000000000000000000000000..ac961ca2b3c644e09b2c0273ed260a81ca34ebab --- /dev/null +++ b/docs/PrivacyPolicy.md @@ -0,0 +1,32 @@ +# Privacy Policy + +Last update: November 8 2022 + +This document explains how we process personal data and how you, as an individual, can exercise your rights. + +## Overview + +Our first objective is to avoid having any personal data at all. However, given that you use this app to connect to a service provider, you should be made aware that their privacy policies apply to the traffic you send at said provider. Within the app we don't gather and thus don't process personal data. There are some corner cases where we do get data, when debugging a demo provider, when you write bug or in support requests. + +## No Logs + +We go by the motto: "No masters, no logs." + +## No accounts + +Thus no email address, no payment information, no account data. Nil. + +## Debugging and abuse + +When you participate in the beta program or use the demo.bitmask.net provider, we reserve the right to occasionally collect some traffic data for development, debugging and abuse reasons. This is limited to: + +IP address, country details (derived from IP address), network connection (think of TLS errors or congestion debugging). This data is ephemeral. + +## Support + +Any support or bug requests are outside of the app. When you submit bug reports or give feedback the amount of data stored is what you shared. When this is done over e-mail, we use a third party: riseup.net. The bug tracker and software development are kindly hosted by riseup as well: 0xacab.org. Their privacy policies apply (https://riseup.net/en/privacy-policy ). Google Play store privacy policy apply when giving feedback through Play Store reviews. + +# Updates + +This Privacy policy may be updated and, in such case, a new version will be published on Bitmasks website. + diff --git a/docs/Troubleshooting.md b/docs/Troubleshooting.md new file mode 100644 index 0000000000000000000000000000000000000000..5c4b42f1a4d0009f1d61a99f2503740e6818e4a3 --- /dev/null +++ b/docs/Troubleshooting.md @@ -0,0 +1,113 @@ +### Debian Gotchas <a name="debian-gotchas"></a> + +If you are running Debian on a 64-bit machine, your emulator will likely not work out of the gate. Test to see if this is the case by: + +* first creating an emulator in Android Studio (with name, eg, `Nexus_5_API_25`) +* then running: + ```shell + cd ~/ + emulator @<name_of_your_emulator> + ``` +If you can launch an emulator, HUZZAH! If not, you likely have one of 3 problems: + +#### 1. Virtualization Not Enabled <a name="virtualization-not-enabled"></a> + +Boo! Try turning it on. The second half of [this article](https://docs.fedoraproject.org/en-US/Fedora/13/html/Virtualization_Guide/sect-Virtualization-Troubleshooting-Enabling_Intel_VT_and_AMD_V_virtualization_hardware_extensions_in_BIOS.html) is a decent enough guide. + +#### 2. Unpatched Filepaths Bug <a name="unpatched-filepaths-bug"></a> + +**Symptoms:** If you have this bug, you will see something like the following when you try to spin up an emulator: + +``` shell +[140500439390016]:ERROR:./android/qt/qt_setup.cpp:28:Qt library not found at ../emulator/lib64/qt/lib +Could not launch '../emulator/qemu/linux-x86_64/qemu-system-i386': No such file or directory +``` +As [documented here](https://stackoverflow.com/questions/42554337/cannot-launch-avd-in-emulatorqt-library-not-found), there is a standing bug in the version of `emulator` packaged for emulator that assumes it always runs from within the `$ANDROID_HOME/emulator` directory, and can thus safely use relative filepaths, when in fact this is almost never the case. (Cool bug!) + +**Fixes:** + +You have a couple options. The fist is more robust: + +1. Insert a line in your `~/.bashrc` to automatically navigate to the correct directory (and back) whenever you invoke `emulator`: + + ```shell +function emulator { pushd `pwd`; cd "$(dirname "$(which emulator)")" && ./emulator "$@"; popd;} +``` + +2. Always run emulator from within its own directory (clunky!): + +``` shell + cd "$(dirname "$(which emulator)")" + emulator <name_of_your_emulator> +``` + +#### 3. Outdated GL Libraries <a name="outdated-gl-libraries"></a> + +**Symptoms:** If you have this bug, you will see something like the following: + +``` shell +libGL error: failed to load driver: swrast +X Error of failed request: BadValue (integer parameter out of range for operation) +# redacted incredibly long stack trace +``` + +As documented [here](http://stackoverflow.com/questions/36554322/cannot-start-emulator-in-android-studio-2-0), the current emulator package ships without outdated versions of LibGL libraries. To work around this: + +1. Install modern GL libriaries with: + +``` shell +sudo apt-get install mesa-utils +``` + +2. Ensure that `emulator` always uses the correct libraries by either: + +a. always calling `emulator` with the `-use-system-libs` flag, like so: + + ``` shell + emulator -use-system-libs -avd Nexus_5_API_25 + ``` +b. adding the following line to your ~/.bashrc or ~/.bash_profile: + + ```shell + export ANDROID_EMULATOR_USE_SYSTEM_LIBS=1 + ``` + +**Special Android Studio Debian Bonus Gotcha:** + +Assuming you have made all the above fixes (great job!), to be able to launch emulators from Android Studio, you must either: + +1. Use the environment variable solution above (option a), then *always* launch Android Studio from a bash shell with: + +``` shell +studio +``` + +This means never using the desktop launcher. :( + +2. If you want to use the desktop launcher: + +* You must *always* launch emulators from the terminal. :( +* But: you can quickly access a terminal inside of Android Studio with `OPTION-F12` + +## Updating Submodules <a name="updating-submodules"></a> + +If you need to refresh our upstream dependency on ics-openvpn, you may do so with: + +``` shell +cd <path/to/bitmask_android> +./gradlew updateIcsOpenVpn +``` + +Alternately: + +```shell +cd <path/to/bitmask_android> +cd ics-openvpn +git remote add upstream https://github.com/schwabe/ics-openvpn.git +git pull --rebase upstream master +``` +A bunch of conflicts may arise. The guidelines are: + + 1. Methods in HEAD (upstream) completely removed from Bitmask should be removed again (e.g. askPW) + 2. Sometimes, Dashboard.class is in Bitmask while in ics-openvpn it is replaced by MainActivity.class and other classes. Keep removing them to keep Dashboard.class in there. + 3. Some resources files are stripped from several entries. Remove them if possible (check the code we compile is not using anything else new). diff --git a/gradle/wrapper/gradle-wrapper.properties b/gradle/wrapper/gradle-wrapper.properties index 5e689c007fff70908234b93a0c7c2d8da6d0f27e..aaa09975c0cf24c88dc9e81a97375402dad8fe29 100644 --- a/gradle/wrapper/gradle-wrapper.properties +++ b/gradle/wrapper/gradle-wrapper.properties @@ -1,6 +1,6 @@ -#Thu Feb 11 23:53:25 CET 2021 +#Sun Aug 07 23:06:29 CEST 2022 distributionBase=GRADLE_USER_HOME +distributionUrl=https\://services.gradle.org/distributions/gradle-7.3.3-bin.zip distributionPath=wrapper/dists -zipStoreBase=GRADLE_USER_HOME zipStorePath=wrapper/dists -distributionUrl=https\://services.gradle.org/distributions/gradle-6.5-all.zip +zipStoreBase=GRADLE_USER_HOME diff --git a/ics-openvpn b/ics-openvpn index a9dc600d98c2549fd05019449c0990f057174547..08ec76072a374ba2bdd2ef09df7cffc74652ee01 160000 --- a/ics-openvpn +++ b/ics-openvpn @@ -1 +1 @@ -Subproject commit a9dc600d98c2549fd05019449c0990f057174547 +Subproject commit 08ec76072a374ba2bdd2ef09df7cffc74652ee01 diff --git a/lib-bitmask-core-arm64/bitmaskcore_arm64-sources.jar b/lib-bitmask-core-arm64/bitmaskcore_arm64-sources.jar deleted file mode 100644 index 5b475b1ffe4239c07fa799cca493688cee0313e7..0000000000000000000000000000000000000000 Binary files a/lib-bitmask-core-arm64/bitmaskcore_arm64-sources.jar and /dev/null differ diff --git a/lib-bitmask-core-arm64/bitmaskcore_arm64.aar b/lib-bitmask-core-arm64/bitmaskcore_arm64.aar deleted file mode 100644 index 5a12115c971616d26cfef25ce5674eb0b69fb1ac..0000000000000000000000000000000000000000 Binary files a/lib-bitmask-core-arm64/bitmaskcore_arm64.aar and /dev/null differ diff --git a/lib-bitmask-core-armv7/bitmaskcore_arm-sources.jar b/lib-bitmask-core-armv7/bitmaskcore_arm-sources.jar deleted file mode 100644 index 5b475b1ffe4239c07fa799cca493688cee0313e7..0000000000000000000000000000000000000000 Binary files a/lib-bitmask-core-armv7/bitmaskcore_arm-sources.jar and /dev/null differ diff --git a/lib-bitmask-core-armv7/bitmaskcore_arm.aar b/lib-bitmask-core-armv7/bitmaskcore_arm.aar deleted file mode 100644 index d947ed88271a08d011875fdc0bbe792ad2636f23..0000000000000000000000000000000000000000 Binary files a/lib-bitmask-core-armv7/bitmaskcore_arm.aar and /dev/null differ diff --git a/lib-bitmask-core-web/bitmaskcore_web-sources.jar b/lib-bitmask-core-web/bitmaskcore_web-sources.jar deleted file mode 100644 index 9bbe2dff2caf87bcfa5d59455626f954616f176c..0000000000000000000000000000000000000000 Binary files a/lib-bitmask-core-web/bitmaskcore_web-sources.jar and /dev/null differ diff --git a/lib-bitmask-core-web/bitmaskcore_web.aar b/lib-bitmask-core-web/bitmaskcore_web.aar deleted file mode 100644 index b5c931d6aa0f737666387bc52b6e3e1432617cc8..0000000000000000000000000000000000000000 Binary files a/lib-bitmask-core-web/bitmaskcore_web.aar and /dev/null differ diff --git a/lib-bitmask-core-x86/bitmaskcore_x86-sources.jar b/lib-bitmask-core-x86/bitmaskcore_x86-sources.jar deleted file mode 100644 index 5b475b1ffe4239c07fa799cca493688cee0313e7..0000000000000000000000000000000000000000 Binary files a/lib-bitmask-core-x86/bitmaskcore_x86-sources.jar and /dev/null differ diff --git a/lib-bitmask-core-x86/bitmaskcore_x86.aar b/lib-bitmask-core-x86/bitmaskcore_x86.aar deleted file mode 100644 index eb0ae96360f9fae9d3fb2eb94cbfd9cc3dd5725e..0000000000000000000000000000000000000000 Binary files a/lib-bitmask-core-x86/bitmaskcore_x86.aar and /dev/null differ diff --git a/lib-bitmask-core-x86_64/bitmaskcore_x86_64-sources.jar b/lib-bitmask-core-x86_64/bitmaskcore_x86_64-sources.jar deleted file mode 100644 index 5b475b1ffe4239c07fa799cca493688cee0313e7..0000000000000000000000000000000000000000 Binary files a/lib-bitmask-core-x86_64/bitmaskcore_x86_64-sources.jar and /dev/null differ diff --git a/lib-bitmask-core-x86_64/bitmaskcore_x86_64.aar b/lib-bitmask-core-x86_64/bitmaskcore_x86_64.aar deleted file mode 100644 index 7f428f45ac21e6993d8901d743a55c9db8b57574..0000000000000000000000000000000000000000 Binary files a/lib-bitmask-core-x86_64/bitmaskcore_x86_64.aar and /dev/null differ diff --git a/lib-bitmask-core/bitmaskcore-sources.jar b/lib-bitmask-core/bitmaskcore-sources.jar deleted file mode 100644 index 5b475b1ffe4239c07fa799cca493688cee0313e7..0000000000000000000000000000000000000000 Binary files a/lib-bitmask-core/bitmaskcore-sources.jar and /dev/null differ diff --git a/lib-bitmask-core/bitmaskcore.aar b/lib-bitmask-core/bitmaskcore.aar deleted file mode 100644 index fe28f633e8c3ca063648619fa6deb37fdd9b4e46..0000000000000000000000000000000000000000 Binary files a/lib-bitmask-core/bitmaskcore.aar and /dev/null differ diff --git a/scripts/build_deps.sh b/scripts/build_deps.sh index 83fed5e8f37569116595a41f255e282178ccbdb3..d1d425766d5aa976f9c54bc4cf8d284600c23d8f 100755 --- a/scripts/build_deps.sh +++ b/scripts/build_deps.sh @@ -8,14 +8,15 @@ function quit { SCRIPT_DIR=$(dirname "$0") BASE_DIR="$SCRIPT_DIR/.." DIR_OVPNASSETS=./ics-openvpn/main/build/ovpnassets -DIR_OVPNLIBS=./ics-openvpn/main/build/intermediates/cmake/noovpn3/release/obj +DIR_OVPNLIBS=./ics-openvpn/main/build/intermediates/cmake/skeletonRelease/obj DIR_GOLIBS=./bitmaskcore/lib/ #FILE_X86=./go/out/x86/piedispatcherlib #FILE_ARM=./go/out/armeabi-v7a/piedispatcherlib DIR_TORLIBS=./tor-android/external/lib EXPECTED_NDK_VERSION="21.4.7075529" EXPECTED_ANDROID_NDK_RELEASE_VERSION="r21e" -BUILD_TOR=true +if [[ -z $BUILD_TOR ]]; then BUILD_TOR=true; fi +if [[ -z $BUILD_OPENVPN_LIBS ]]; then BUILD_OPENVPN_LIBS=true; fi # init # look for empty dir @@ -26,6 +27,9 @@ cd $BASE_DIR if [[ $(ls -A ${ANDROID_HOME}/ndk/${EXPECTED_NDK_VERSION}) ]] then ANDROID_NDK_HOME=${ANDROID_HOME}/ndk/${EXPECTED_NDK_VERSION} +elif [[ -f ${ANDROID_HOME/android-ndk-}${EXPECTED_ANDOID_NDK_RELEASE_VERSION }} ]]; then + echo "make sure you have the right ndk version installed and paths are set correctly" + exit 1 else # ndk was manually downloaded from http://dl.google.com/android/repository ANDROID_NDK_HOME=${ANDROID_HOME}/android-ndk-${EXPECTED_ANDROID_NDK_RELEASE_VERSION} @@ -60,8 +64,9 @@ else fi # build openvpn libs -if [[ $(ls -A ${DIR_OVPNASSETS}) && $(ls -A ${DIR_OVPNLIBS}) ]] -then +if [[ ${BUILD_OPENVPN_LIBS} == false ]]; then + echo "skipping openvpn" +elif [[ $(ls -A ${DIR_OVPNASSETS}) && $(ls -A ${DIR_OVPNLIBS}) ]]; then echo "Dirty build: skipped externalNativeBuild - reusing existing libs" else echo "Clean build: starting externalNativeBuild" @@ -96,4 +101,4 @@ else cp lib/bitmaskcore_x86_64.aar ../lib-bitmask-core-x86_64/. cp lib/bitmaskcore_x86_64-sources.jar ../lib-bitmask-core-x86_64/. cd .. -fi \ No newline at end of file +fi diff --git a/scripts/cleanProject.sh b/scripts/cleanProject.sh index e7d8460e7ab1aeb717fa9bf2ae6d0a2e118f8193..49e2db4494eba27abcbb0392327d725871f542e7 100755 --- a/scripts/cleanProject.sh +++ b/scripts/cleanProject.sh @@ -6,6 +6,8 @@ BASE_DIR="$SCRIPT_DIR/.." git checkout -- \* git checkout -- \.\* +git clean -xfd +git submodule foreach --recursive git clean -xfd rm -r $BASE_DIR/ics-openvpn rm -r $BASE_DIR/build rm -r $BASE_DIR/app/build @@ -18,6 +20,7 @@ rm -r $BASE_DIR/tor-android/external/bin rm -r $BASE_DIR/tor-android/external/include/ rm -r $BASE_DIR/tor-android/external/*.build-stamp rm -r $BASE_DIR/tor-android/external/lib +git reset --hard git submodule foreach --recursive git reset --hard HEAD git submodule sync --recursive git submodule update --init --recursive diff --git a/scripts/prepareForDistribution.sh b/scripts/prepareForDistribution.sh index afdccb37d32d4d473cf60475e1fc68240437a790..b89b73aacee9376503f17645c63401f5dfcbd038 100755 --- a/scripts/prepareForDistribution.sh +++ b/scripts/prepareForDistribution.sh @@ -1,6 +1,6 @@ #!/bin/bash -# Copyright (c) 2019 LEAP Encryption Access Project and contributers +# Copyright (c) 2022 LEAP Encryption Access Project and contributers # # This program is free software: you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by @@ -409,7 +409,7 @@ if [[ ${DO_BUILD} == true ]]; then fi else # default: neither -aab nor -apk is passed: build apks - if ([[ -z ${BUILD_BUNDLE} ]] && [[-z ${BUILD_APK} ]]) || ([[ -n ${BUILD_APK} ]]); then + if ([[ -z ${BUILD_BUNDLE} ]] && [[ -z ${BUILD_APK} ]]) || ([[ -n ${BUILD_APK} ]]); then if [[ -z ${FLAVOR2} ]]; then echo -e "${GREEN} -> build stable releases (.apk) for flavor ${FLAVOR}${NC}" else diff --git a/scripts/prepareForTests.sh b/scripts/prepareForTests.sh new file mode 100755 index 0000000000000000000000000000000000000000..d10a04b7adcfde4e6af7d4240323935cc1866817 --- /dev/null +++ b/scripts/prepareForTests.sh @@ -0,0 +1,28 @@ +#!/bin/bash + +# Copyright (c) 2022 LEAP Encryption Access Project and contributors +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program. If not, see <http://www.gnu.org/licenses/>. + +SCRIPT_DIR=$(dirname "$0") +BASE_DIR="$SCRIPT_DIR/.." + +git checkout -- \* +git checkout -- \.\* +rm -r $BASE_DIR/bitmaskcore/lib/* +git submodule foreach --recursive git reset --hard HEAD +git submodule sync --recursive +git submodule update --init --recursive + +BUILD_TOR=false BUILD_OPENVPN_LIBS=false ./scripts/build_deps.sh \ No newline at end of file diff --git a/tor-android b/tor-android index 0173fc7610a69b8282ffad680e36f1105e872d67..c1c015af8d20ae44d045264c9b98dbf78caa4336 160000 --- a/tor-android +++ b/tor-android @@ -1 +1 @@ -Subproject commit 0173fc7610a69b8282ffad680e36f1105e872d67 +Subproject commit c1c015af8d20ae44d045264c9b98dbf78caa4336