├── .github
└── FUNDING.yml
├── .gitignore
├── LICENSE
├── README.md
├── app
├── .gitignore
├── build.gradle
├── frogoboxdev.jks
├── libs
│ └── achartengine-1.2.0.jar
├── proguard-rules.pro
└── src
│ └── main
│ ├── AndroidManifest.xml
│ ├── assets
│ ├── countries.json
│ ├── nopie_openvpn.arm64-v8a
│ ├── nopie_openvpn.armeabi
│ ├── nopie_openvpn.armeabi-v7a
│ ├── nopie_openvpn.mips
│ ├── nopie_openvpn.x86
│ ├── nopie_openvpn.x86_64
│ ├── pie_openvpn.arm64-v8a
│ ├── pie_openvpn.armeabi
│ ├── pie_openvpn.armeabi-v7a
│ ├── pie_openvpn.mips
│ ├── pie_openvpn.x86
│ ├── pie_openvpn.x86_64
│ └── world_map.geo.json
│ ├── java
│ ├── com
│ │ └── frogobox
│ │ │ └── viprox
│ │ │ ├── BaseApplication.kt
│ │ │ ├── base
│ │ │ ├── BaseActivity.kt
│ │ │ └── BaseFragment.kt
│ │ │ ├── source
│ │ │ ├── local
│ │ │ │ └── DBHelper.java
│ │ │ └── model
│ │ │ │ ├── Country.kt
│ │ │ │ ├── GetSpeedTestHostsHandler.java
│ │ │ │ └── Server.kt
│ │ │ ├── ui
│ │ │ ├── AboutUsActivity.kt
│ │ │ ├── CountryActivity.kt
│ │ │ ├── MainActivity.kt
│ │ │ ├── SplashActivity.kt
│ │ │ ├── VPNInfoActivity.kt
│ │ │ └── VPNListActivity.kt
│ │ │ └── util
│ │ │ ├── ConnectionQuality.java
│ │ │ ├── Constant.kt
│ │ │ ├── CountriesNames.java
│ │ │ ├── NetworkState.java
│ │ │ ├── NotificationUtils.java
│ │ │ ├── NotificationVO.java
│ │ │ ├── NumberPickerPreference.java
│ │ │ ├── PropertiesService.java
│ │ │ ├── Stopwatch.java
│ │ │ ├── TotalTraffic.java
│ │ │ ├── dns
│ │ │ ├── HttpDownloadTest.java
│ │ │ ├── HttpUploadTest.java
│ │ │ └── PingTest.java
│ │ │ ├── encoders
│ │ │ ├── Base64.java
│ │ │ ├── Base64Encoder.java
│ │ │ └── Encoder.java
│ │ │ └── io
│ │ │ └── pem
│ │ │ ├── PemGenerationException.java
│ │ │ ├── PemHeader.java
│ │ │ ├── PemObject.java
│ │ │ ├── PemObjectGenerator.java
│ │ │ ├── PemReader.java
│ │ │ └── PemWriter.java
│ └── de
│ │ └── blinkt
│ │ └── openvpn
│ │ ├── VpnProfile.java
│ │ └── core
│ │ ├── CIDRIP.java
│ │ ├── ConfigParser.java
│ │ ├── Connection.java
│ │ ├── DeviceStateReceiver.java
│ │ ├── LogFileHandler.java
│ │ ├── LogItem.java
│ │ ├── NativeUtils.java
│ │ ├── NetworkSpace.java
│ │ ├── OpenVPNManagement.java
│ │ ├── OpenVPNService.java
│ │ ├── OpenVPNThread.java
│ │ ├── OpenVpnManagementThread.java
│ │ ├── PRNGFixes.java
│ │ ├── ProfileManager.java
│ │ ├── ProxyDetection.java
│ │ ├── VPNLaunchHelper.java
│ │ ├── VpnStatus.java
│ │ └── X509Utils.java
│ ├── jniLibs
│ ├── arm64-v8a
│ │ ├── libjbcrypto.so
│ │ ├── libopenvpn.so
│ │ └── libopvpnutil.so
│ ├── armeabi-v7a
│ │ ├── libjbcrypto.so
│ │ ├── libopenvpn.so
│ │ └── libopvpnutil.so
│ ├── armeabi
│ │ ├── libjbcrypto.so
│ │ ├── libopenvpn.so
│ │ └── libopvpnutil.so
│ ├── mips
│ │ ├── libjbcrypto.so
│ │ ├── libopenvpn.so
│ │ └── libopvpnutil.so
│ ├── x86
│ │ ├── libjbcrypto.so
│ │ ├── libopenvpn.so
│ │ └── libopvpnutil.so
│ └── x86_64
│ │ ├── libjbcrypto.so
│ │ ├── libopenvpn.so
│ │ └── libopvpnutil.so
│ └── res
│ ├── drawable
│ ├── bg_button.xml
│ ├── bg_button_connected.xml
│ ├── bg_button_no_connected.xml
│ ├── bg_card_dark.xml
│ ├── bg_card_toolbar.xml
│ ├── bg_card_white.xml
│ ├── ic_btn_connect_vpn.xml
│ ├── ic_connect_good.xml
│ ├── ic_dummy_flag.xml
│ ├── ic_frogobox.png
│ ├── ic_launcher.xml
│ ├── ic_toolbar_about_us.xml
│ ├── ic_toolbar_back_home.xml
│ ├── ic_toolbar_back_home_white.xml
│ ├── ic_toolbar_location.xml
│ └── info_servers_bg.xml
│ ├── font
│ └── montserrat_regular.ttf
│ ├── layout
│ ├── activity_about_us.xml
│ ├── activity_country.xml
│ ├── activity_main.xml
│ ├── activity_splash.xml
│ ├── activity_vpninfo.xml
│ ├── activity_vpnlist.xml
│ ├── ads_banner.xml
│ ├── toolbar_main.xml
│ ├── view_item_country.xml
│ └── view_item_server.xml
│ ├── menu
│ └── menu_toolbar_main.xml
│ ├── values-v21
│ └── styles.xml
│ ├── values
│ ├── colors.xml
│ ├── dimens.xml
│ ├── reference.xml
│ ├── strings.xml
│ └── styles.xml
│ └── xml
│ └── preferences.xml
├── build.gradle
├── docs
└── image
│ ├── ss_1.png
│ ├── ss_2.png
│ └── ss_3.png
├── gradle.properties
├── gradle
└── wrapper
│ ├── gradle-wrapper.jar
│ └── gradle-wrapper.properties
├── gradlew
├── gradlew.bat
├── settings.gradle
└── travis.yml
/.github/FUNDING.yml:
--------------------------------------------------------------------------------
1 | # These are supported funding model platforms
2 |
3 | github: # Replace with up to 4 GitHub Sponsors-enabled usernames e.g., [user1, user2]
4 | patreon: # Replace with a single Patreon username
5 | open_collective: # Replace with a single Open Collective username
6 | ko_fi: # Replace with a single Ko-fi username
7 | tidelift: # Replace with a single Tidelift platform-name/package-name e.g., npm/babel
8 | community_bridge: # Replace with a single Community Bridge project-name e.g., cloud-foundry
9 | liberapay: # Replace with a single Liberapay username
10 | issuehunt: # Replace with a single IssueHunt username
11 | otechie: # Replace with a single Otechie username
12 | custom: https://saweria.co/amirisback
13 |
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | *.iml
2 | /.gradle
3 | .gradle
4 | .idea
5 | /local.properties
6 | /.idea/libraries
7 | /.idea/modules.xml
8 | /.idea/workspace.xml
9 | .DS_Store
10 | build
11 | /build
12 | /captures
13 | .externalNativeBuild
14 |
15 | built application files
16 | .apk
17 | .ap_
18 |
19 | files for the dex VM
20 | *.dex
21 |
22 | Java class files
23 | *.class
24 |
25 | generated files
26 | bin/
27 | gen/
28 | .externalNativeBuild/
29 |
30 | Local configuration file (sdk path, etc)
31 | local.properties
32 | app/version.properties
33 |
34 | # SonarQube
35 | .sonar/
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | 
2 |
3 | ## Viprox VPN
4 | Easy VPN For Reskin
5 |
6 | ## Screen Shoot
7 |
8 | | UI 1 | UI 2 | UI 3 |
9 | |:----:|:----:|:----:|
10 | |
|
|
|
11 |
12 | ## Version Release
13 | This Is Latest Release
14 |
15 | $version_release = 1.0.0
16 |
17 | ## Colaborator
18 | Very open to anyone, I'll write your name under this, please contribute by sending an email to me
19 |
20 | - Mail To faisalamircs@gmail.com
21 | - Subject : Github _ [Github-Username-Account] _ [Language] _ [Repository-Name]
22 | - Example : Github_amirisback_kotlin_admob-helper-implementation
23 |
24 | Name Of Contribute
25 | - Muhammad Faisal Amir
26 | - Waiting List
27 | - Waiting List
28 |
29 | Waiting for your contribute
30 |
31 | ## Attention !!!
32 | - Please enjoy and don't forget fork and give a star
33 | - Don't Forget Follow My Github Account
34 |
--------------------------------------------------------------------------------
/app/.gitignore:
--------------------------------------------------------------------------------
1 | /build
2 |
--------------------------------------------------------------------------------
/app/build.gradle:
--------------------------------------------------------------------------------
1 | apply plugin: 'com.android.application'
2 | apply plugin: 'kotlin-android'
3 | apply plugin: 'kotlin-kapt'
4 |
5 | android {
6 |
7 | // Declaration admob id for release
8 | def releaseAdmobPublisherId = ""
9 | def releaseAdmobBanner = ""
10 | def releaseAdmobInterstitial = ""
11 | def releaseAdmobInterstitialVideo = ""
12 | def releaseAdmobRewarded = ""
13 | def releaseAdmobRewardedInterstitial = ""
14 | def releaseAdmobNativeAdvanced = ""
15 | def releaseAdmobNativeAdvancedVideo = ""
16 |
17 | compileSdk projectCompileSdk
18 |
19 | defaultConfig {
20 | applicationId projectApplicationId
21 | minSdk projectMinSdk
22 | targetSdk projectTargetSdk
23 | versionCode projectVersionCode
24 | versionName projectVersionName
25 |
26 | multiDexEnabled true
27 | vectorDrawables.useSupportLibrary = true
28 |
29 | // Declaration apps name debug mode
30 | def debugAttribute = " Development"
31 | def nameAppDebug = nameApp + debugAttribute
32 |
33 | // Naming APK // AAB
34 | setProperty("archivesBaseName", nameAPK + versionName + "#" + versionCode + "-"
35 | + new Date().format('ddMMyy'))
36 |
37 | resConfigs "en", "id"
38 |
39 | // Inject app name for debug
40 | resValue "string", "app_name", nameAppDebug
41 |
42 | // Declaration admob id for debug
43 | def debugAdmobPublisherId = "ca-app-pub-3940256099942544~3347511713"
44 | def debugAdmobBanner = "ca-app-pub-3940256099942544/6300978111"
45 | def debugAdmobInterstitial = "ca-app-pub-3940256099942544/1033173712"
46 | def debugAdmobInterstitialVideo = "ca-app-pub-3940256099942544/8691691433"
47 | def debugAdmobRewarded = "ca-app-pub-3940256099942544/5224354917"
48 | def debugAdmobRewardedInterstitial = "ca-app-pub-3940256099942544/5354046379"
49 | def debugAdmobNativeAdvanced = "ca-app-pub-3940256099942544/2247696110"
50 | def debugAdmobNativeAdvancedVideo = "ca-app-pub-3940256099942544/1044960115"
51 |
52 | // Inject admob id for debug
53 | resValue "string", "admob_publisher_id", debugAdmobPublisherId
54 | resValue "string", "admob_banner", debugAdmobBanner
55 | resValue "string", "admob_interstitial", debugAdmobInterstitial
56 | resValue "string", "admob_interstitial_video", debugAdmobInterstitialVideo
57 | resValue "string", "admob_rewarded", debugAdmobRewarded
58 | resValue "string", "admob_rewarded_interstitial", debugAdmobRewardedInterstitial
59 | resValue "string", "admob_native_advanced", debugAdmobNativeAdvanced
60 | resValue "string", "admob_native_advanced_video", debugAdmobNativeAdvancedVideo
61 |
62 | }
63 |
64 | signingConfigs {
65 | release {
66 | // You need to specify either an absolute path or include the
67 | // keystore file in the same directory as the build.gradle file.
68 | // [PROJECT FOLDER NAME/app/[COPY YOUT KEY STORE] .jks in here
69 | storeFile file("frogoboxdev.jks")
70 | storePassword "cronoclez"
71 | keyAlias "frogobox"
72 | keyPassword "xeonranger"
73 | }
74 | }
75 |
76 | buildTypes {
77 |
78 | release {
79 | minifyEnabled true
80 | proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
81 |
82 | // Generated Signed APK / AAB
83 | signingConfig signingConfigs.release
84 |
85 | // Inject app name for release
86 | resValue "string", "app_name", nameApp
87 |
88 | // Inject admob id for release
89 | resValue "string", "admob_publisher_id", releaseAdmobPublisherId
90 | resValue "string", "admob_banner", releaseAdmobBanner
91 | resValue "string", "admob_interstitial", releaseAdmobInterstitial
92 | resValue "string", "admob_interstitial_video", releaseAdmobInterstitialVideo
93 | resValue "string", "admob_rewarded", releaseAdmobRewarded
94 | resValue "string", "admob_rewarded_interstitial", releaseAdmobRewardedInterstitial
95 | resValue "string", "admob_native_advanced", releaseAdmobNativeAdvanced
96 | resValue "string", "admob_native_advanced_video", releaseAdmobNativeAdvancedVideo
97 |
98 | }
99 |
100 | }
101 |
102 | buildFeatures {
103 | viewBinding true
104 | compose true
105 | }
106 |
107 | compileOptions {
108 | sourceCompatibility JavaVersion.VERSION_11
109 | targetCompatibility JavaVersion.VERSION_11
110 | }
111 |
112 | composeOptions {
113 | kotlinCompilerExtensionVersion compose_version
114 | kotlinCompilerVersion kotlin_version
115 | }
116 |
117 | kotlinOptions {
118 | jvmTarget = JavaVersion.VERSION_11.toString()
119 | useIR = true
120 | }
121 |
122 | packagingOptions {
123 | resources {
124 | excludes += '/META-INF/{AL2.0,LGPL2.1}'
125 | }
126 | }
127 |
128 | }
129 |
130 | dependencies {
131 | implementation fileTree(dir: 'libs', include: ['*.jar'])
132 | implementation files('libs/achartengine-1.2.0.jar')
133 |
134 | implementation "org.jetbrains.kotlin:kotlin-stdlib-jdk7:$kotlin_version"
135 |
136 | implementation 'androidx.core:core-ktx:1.6.0'
137 | implementation 'androidx.appcompat:appcompat:1.3.1'
138 | implementation 'androidx.constraintlayout:constraintlayout:2.1.1'
139 | implementation "androidx.legacy:legacy-support-v4:1.0.0"
140 |
141 | implementation "androidx.compose.ui:ui:$compose_version"
142 | implementation "androidx.compose.material:material:$compose_version"
143 | implementation "androidx.compose.ui:ui-tooling-preview:$compose_version"
144 |
145 | implementation 'androidx.lifecycle:lifecycle-runtime-ktx:2.3.1'
146 | implementation 'androidx.activity:activity-compose:1.3.1'
147 |
148 | implementation 'com.google.code.gson:gson:2.8.8'
149 | implementation 'com.google.android.material:material:1.4.0'
150 |
151 | implementation "com.google.android.gms:play-services-ads:20.3.0"
152 |
153 | implementation 'com.github.frogobox:frogo-android-sdk:2.0.4'
154 | implementation 'com.github.frogobox:frogo-android-ui-kit:1.0.4'
155 |
156 | implementation 'com.github.amirisback:frogo-admob:4.1.2'
157 | implementation 'com.github.amirisback:frogo-recycler-view:3.8.7'
158 | implementation 'com.github.amirisback:frogo-log:2.0.4'
159 |
160 | implementation "com.github.bumptech.glide:glide:4.12.0"
161 |
162 | implementation "com.daimajia.numberprogressbar:library:1.2@aar"
163 | implementation "com.amitshekhar.android:android-networking:0.2.0"
164 |
165 | kapt "com.github.bumptech.glide:compiler:4.11.0"
166 |
167 | testImplementation 'junit:junit:4.13.2'
168 | androidTestImplementation 'androidx.test.ext:junit:1.1.3'
169 | androidTestImplementation 'androidx.test.espresso:espresso-core:3.4.0'
170 |
171 | androidTestImplementation "androidx.compose.ui:ui-test-junit4:$compose_version"
172 | debugImplementation "androidx.compose.ui:ui-tooling:$compose_version"
173 | }
174 |
--------------------------------------------------------------------------------
/app/frogoboxdev.jks:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/amirisback/vpn/cf6770030bc5d3e289a75e739f2e41a1a1d9e654/app/frogoboxdev.jks
--------------------------------------------------------------------------------
/app/libs/achartengine-1.2.0.jar:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/amirisback/vpn/cf6770030bc5d3e289a75e739f2e41a1a1d9e654/app/libs/achartengine-1.2.0.jar
--------------------------------------------------------------------------------
/app/proguard-rules.pro:
--------------------------------------------------------------------------------
1 | # Add project specific ProGuard rules here.
2 | # By default, the flags in this file are appended to flags specified
3 | # in /Users/Vasilkoff/Library/Android/sdk/tools/proguard/proguard-android.txt
4 | # You can edit the include path and order by changing the proguardFiles
5 | # directive in build.gradle.
6 | #
7 | # For more details, see
8 | # http://developer.android.com/guide/developing/tools/proguard.html
9 |
10 | # Add any project specific keep options here:
11 |
12 | # If your project uses WebView with JS, uncomment the following
13 | # and specify the fully qualified class name to the JavaScript interface
14 | # class:
15 | #-keepclassmembers class fqcn.of.javascript.interface.for.webview {
16 | # public *;
17 | #}
18 |
19 | -dontwarn com.caverock.androidsvg.**
20 | -dontwarn okio.**
--------------------------------------------------------------------------------
/app/src/main/AndroidManifest.xml:
--------------------------------------------------------------------------------
1 |
2 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
21 |
22 |
23 |
24 |
25 |
26 |
27 |
32 |
33 |
34 |
35 |
36 |
37 |
38 |
41 |
42 |
46 |
47 |
51 |
52 |
53 |
54 |
55 |
56 |
59 |
60 |
61 |
62 |
--------------------------------------------------------------------------------
/app/src/main/assets/nopie_openvpn.arm64-v8a:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/amirisback/vpn/cf6770030bc5d3e289a75e739f2e41a1a1d9e654/app/src/main/assets/nopie_openvpn.arm64-v8a
--------------------------------------------------------------------------------
/app/src/main/assets/nopie_openvpn.armeabi:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/amirisback/vpn/cf6770030bc5d3e289a75e739f2e41a1a1d9e654/app/src/main/assets/nopie_openvpn.armeabi
--------------------------------------------------------------------------------
/app/src/main/assets/nopie_openvpn.armeabi-v7a:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/amirisback/vpn/cf6770030bc5d3e289a75e739f2e41a1a1d9e654/app/src/main/assets/nopie_openvpn.armeabi-v7a
--------------------------------------------------------------------------------
/app/src/main/assets/nopie_openvpn.mips:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/amirisback/vpn/cf6770030bc5d3e289a75e739f2e41a1a1d9e654/app/src/main/assets/nopie_openvpn.mips
--------------------------------------------------------------------------------
/app/src/main/assets/nopie_openvpn.x86:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/amirisback/vpn/cf6770030bc5d3e289a75e739f2e41a1a1d9e654/app/src/main/assets/nopie_openvpn.x86
--------------------------------------------------------------------------------
/app/src/main/assets/nopie_openvpn.x86_64:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/amirisback/vpn/cf6770030bc5d3e289a75e739f2e41a1a1d9e654/app/src/main/assets/nopie_openvpn.x86_64
--------------------------------------------------------------------------------
/app/src/main/assets/pie_openvpn.arm64-v8a:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/amirisback/vpn/cf6770030bc5d3e289a75e739f2e41a1a1d9e654/app/src/main/assets/pie_openvpn.arm64-v8a
--------------------------------------------------------------------------------
/app/src/main/assets/pie_openvpn.armeabi:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/amirisback/vpn/cf6770030bc5d3e289a75e739f2e41a1a1d9e654/app/src/main/assets/pie_openvpn.armeabi
--------------------------------------------------------------------------------
/app/src/main/assets/pie_openvpn.armeabi-v7a:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/amirisback/vpn/cf6770030bc5d3e289a75e739f2e41a1a1d9e654/app/src/main/assets/pie_openvpn.armeabi-v7a
--------------------------------------------------------------------------------
/app/src/main/assets/pie_openvpn.mips:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/amirisback/vpn/cf6770030bc5d3e289a75e739f2e41a1a1d9e654/app/src/main/assets/pie_openvpn.mips
--------------------------------------------------------------------------------
/app/src/main/assets/pie_openvpn.x86:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/amirisback/vpn/cf6770030bc5d3e289a75e739f2e41a1a1d9e654/app/src/main/assets/pie_openvpn.x86
--------------------------------------------------------------------------------
/app/src/main/assets/pie_openvpn.x86_64:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/amirisback/vpn/cf6770030bc5d3e289a75e739f2e41a1a1d9e654/app/src/main/assets/pie_openvpn.x86_64
--------------------------------------------------------------------------------
/app/src/main/java/com/frogobox/viprox/BaseApplication.kt:
--------------------------------------------------------------------------------
1 | package com.frogobox.viprox
2 |
3 | import android.app.Application
4 | import android.content.Context
5 |
6 | class BaseApplication : Application() {
7 |
8 | companion object {
9 | lateinit var instance: BaseApplication
10 | }
11 |
12 | override fun onCreate() {
13 | super.onCreate()
14 | instance = this
15 | }
16 |
17 | override fun attachBaseContext(base: Context) {
18 | super.attachBaseContext(base)
19 | }
20 |
21 | fun getResourceString(resId: Int): String {
22 | return instance.getString(resId)
23 | }
24 |
25 | }
--------------------------------------------------------------------------------
/app/src/main/java/com/frogobox/viprox/base/BaseActivity.kt:
--------------------------------------------------------------------------------
1 | package com.frogobox.viprox.base
2 |
3 | import android.content.Intent
4 | import android.os.Bundle
5 | import android.view.Menu
6 | import android.view.MenuItem
7 | import android.view.WindowManager
8 | import androidx.core.content.ContextCompat
9 | import androidx.viewbinding.ViewBinding
10 | import com.androidnetworking.AndroidNetworking
11 | import com.androidnetworking.common.Priority
12 | import com.androidnetworking.error.ANError
13 | import com.androidnetworking.interfaces.JSONArrayRequestListener
14 | import com.frogobox.admob.core.FrogoAdmob
15 | import com.frogobox.sdk.core.FrogoActivity
16 | import com.frogobox.viprox.R
17 | import com.frogobox.viprox.util.Constant.Variable.EXTRA_AUTO_CONNECTION
18 | import com.frogobox.viprox.util.Constant.Variable.EXTRA_FAST_CONNECTION
19 | import com.frogobox.viprox.source.local.DBHelper
20 | import com.frogobox.viprox.source.model.Server
21 | import com.frogobox.viprox.util.CountriesNames
22 | import com.frogobox.viprox.util.PropertiesService
23 | import com.frogobox.viprox.util.TotalTraffic
24 | import com.frogobox.viprox.ui.VPNInfoActivity
25 | import com.google.android.gms.ads.AdView
26 | import com.google.gson.Gson
27 | import org.json.JSONArray
28 | import org.json.JSONException
29 | import org.json.JSONObject
30 | import java.util.*
31 |
32 | /**
33 | * Created by Faisal Amir
34 | * FrogoBox Inc License
35 | * =========================================
36 | * ImplementationAdmob
37 | * Copyright (C) 27/11/2019.
38 | * All rights reserved
39 | * -----------------------------------------
40 | * Name : Muhammad Faisal Amir
41 | * E-mail : faisalamircs@gmail.com
42 | * Github : github.com/amirisback
43 | * LinkedIn : linkedin.com/in/faisalamircs
44 | * -----------------------------------------
45 | * FrogoBox Software Industries
46 | * com.frogobox.evpn.base
47 | *
48 | */
49 | abstract class BaseActivity : FrogoActivity() {
50 |
51 | var connectedServer: Server? = null
52 | protected var hideCurrentConnection = false
53 | protected var dbHelper = DBHelper(this)
54 | protected var localeCountries: MutableMap = CountriesNames.getCountries()
55 |
56 | override fun onCreate(savedInstanceState: Bundle?) {
57 | super.onCreate(savedInstanceState)
58 | setupAdmob()
59 | }
60 |
61 | private fun setupAdmob(){
62 | setPublisher()
63 | setBanner()
64 | setInterstitial()
65 | }
66 |
67 | private fun setupAdsPublisher(mPublisherId: String) {
68 | FrogoAdmob.setupPublisherID(mPublisherId)
69 | FrogoAdmob.Publisher.setupPublisher(this)
70 | }
71 |
72 | private fun setupAdsBanner(mAdUnitId: String) {
73 | FrogoAdmob.setupBannerAdUnitID(mAdUnitId)
74 | }
75 |
76 | private fun setupAdsInterstitial(mAdUnitId: String) {
77 | FrogoAdmob.setupInterstialAdUnitID(mAdUnitId)
78 | FrogoAdmob.Interstitial.setupInterstitial(this)
79 | }
80 |
81 | private fun setPublisher() {
82 | setupAdsPublisher(getString(R.string.admob_publisher_id))
83 | }
84 |
85 | private fun setBanner() {
86 | setupAdsBanner(getString(R.string.admob_banner))
87 | }
88 |
89 | private fun setInterstitial() {
90 | setupAdsInterstitial(getString(R.string.admob_interstitial))
91 | }
92 |
93 | fun setupShowAdsBanner(mAdView: AdView) {
94 | FrogoAdmob.Banner.setupBanner(mAdView)
95 | FrogoAdmob.Banner.showBanner(mAdView)
96 | }
97 |
98 | fun setupShowAdsInterstitial() {
99 | FrogoAdmob.Interstitial.showInterstitial(this)
100 | }
101 |
102 | override fun onPause() {
103 | super.onPause()
104 | TotalTraffic.saveTotal()
105 | }
106 |
107 | protected fun setupNoLimitStatBar() {
108 | val windows = window // in Activity's onCreate() for instance
109 | windows.setFlags(
110 | WindowManager.LayoutParams.FLAG_LAYOUT_NO_LIMITS,
111 | WindowManager.LayoutParams.FLAG_LAYOUT_NO_LIMITS
112 | )
113 | }
114 |
115 | override fun onCreateOptionsMenu(menu: Menu?): Boolean {
116 | return true
117 | }
118 |
119 | override fun onOptionsItemSelected(item: MenuItem): Boolean {
120 | return when (item.itemId) {
121 | android.R.id.home -> {
122 | finish()
123 | true
124 | }
125 | else -> super.onOptionsItemSelected(item)
126 | }
127 | }
128 |
129 | protected fun getRandomServer(): Server? {
130 | return if (PropertiesService.getCountryPriority()) {
131 | dbHelper.getGoodRandomServer(PropertiesService.getSelectedCountry())
132 | } else {
133 | dbHelper.getGoodRandomServer(null)
134 | }
135 | }
136 |
137 | protected open fun newConnecting(server: Server?, fastConnection: Boolean, autoConnection: Boolean) {
138 | if (server != null) {
139 | val intent = Intent(this, VPNInfoActivity::class.java)
140 | intent.putExtra(Server::class.java.canonicalName, Gson().toJson(server))
141 | intent.putExtra(EXTRA_FAST_CONNECTION, fastConnection)
142 | intent.putExtra(EXTRA_AUTO_CONNECTION, autoConnection)
143 | startActivity(intent)
144 | }
145 | }
146 |
147 | protected open fun ipInfoResult(){
148 |
149 | }
150 |
151 | protected fun hasConnectedServer(): Boolean {
152 | return connectedServer != null
153 | }
154 |
155 | protected open fun getIpInfo(server: Server) {
156 | val serverList: MutableList = ArrayList()
157 | serverList.add(server)
158 | getIpInfoFromServerList(serverList)
159 | }
160 |
161 | fun getColorRes(res: Int): Int {
162 | return ContextCompat.getColor(this, res)
163 | }
164 |
165 | protected open fun getIpInfoFromServerList(serverList: List) {
166 | val jsonArray = JSONArray()
167 | for (server in serverList) {
168 | val jsonObject = JSONObject()
169 | try {
170 | jsonObject.put("query", server.ip)
171 | jsonObject.put("lang", Locale.getDefault().language)
172 | jsonArray.put(jsonObject)
173 | } catch (e: JSONException) {
174 | e.printStackTrace()
175 | }
176 | }
177 | AndroidNetworking.post(getString(R.string.url_check_ip_batch))
178 | .addJSONArrayBody(jsonArray)
179 | .setTag("getIpInfo")
180 | .setPriority(Priority.MEDIUM)
181 | .build()
182 | .getAsJSONArray(object : JSONArrayRequestListener {
183 | override fun onResponse(response: JSONArray) {
184 | dbHelper.setIpInfo(response, serverList)
185 | // TODO WHEN VPN CONNECTED
186 | }
187 |
188 | override fun onError(error: ANError) {}
189 | })
190 | }
191 |
192 | }
--------------------------------------------------------------------------------
/app/src/main/java/com/frogobox/viprox/base/BaseFragment.kt:
--------------------------------------------------------------------------------
1 | package com.frogobox.viprox.base
2 |
3 | import android.os.Bundle
4 | import androidx.viewbinding.ViewBinding
5 | import com.frogobox.sdk.core.FrogoFragment
6 |
7 | /**
8 | * Created by Faisal Amir
9 | * FrogoBox Inc License
10 | * =========================================
11 | * ImplementationAdmob
12 | * Copyright (C) 25/11/2019.
13 | * All rights reserved
14 | * -----------------------------------------
15 | * Name : Muhammad Faisal Amir
16 | * E-mail : faisalamircs@gmail.com
17 | * Github : github.com/amirisback
18 | * LinkedIn : linkedin.com/in/faisalamircs
19 | * -----------------------------------------
20 | * FrogoBox Software Industries
21 | * com.frogobox.evpn.activity
22 | *
23 | */
24 | abstract class BaseFragment : FrogoFragment() {
25 |
26 | lateinit var mBaseActivity: BaseActivity<*>
27 |
28 | override fun onCreate(savedInstanceState: Bundle?) {
29 | super.onCreate(savedInstanceState)
30 | mBaseActivity = (activity as BaseActivity<*>)
31 | }
32 |
33 | protected fun setupShowAdsInterstitial() {
34 | mBaseActivity.setupShowAdsInterstitial()
35 | }
36 |
37 | }
--------------------------------------------------------------------------------
/app/src/main/java/com/frogobox/viprox/source/model/Country.kt:
--------------------------------------------------------------------------------
1 | package com.frogobox.viprox.source.model
2 |
3 | data class Country(
4 | val countryName: String,
5 | val capitalName: String,
6 | val capitalLatitude: Double,
7 | val capitalLongitude: Double,
8 | val countryCode: String)
--------------------------------------------------------------------------------
/app/src/main/java/com/frogobox/viprox/source/model/GetSpeedTestHostsHandler.java:
--------------------------------------------------------------------------------
1 | package com.frogobox.viprox.source.model;
2 |
3 | import java.io.BufferedReader;
4 | import java.io.InputStream;
5 | import java.io.InputStreamReader;
6 | import java.net.URL;
7 | import java.util.Arrays;
8 | import java.util.HashMap;
9 | import java.util.List;
10 |
11 |
12 | public class GetSpeedTestHostsHandler extends Thread {
13 |
14 | HashMap mapKey = new HashMap<>();
15 | HashMap> mapValue = new HashMap<>();
16 | double selfLat = 0.0;
17 | double selfLon = 0.0;
18 | boolean finished = false;
19 |
20 |
21 | public HashMap getMapKey() {
22 | return mapKey;
23 | }
24 |
25 | public HashMap> getMapValue() {
26 | return mapValue;
27 | }
28 |
29 | public double getSelfLat() {
30 | return selfLat;
31 | }
32 |
33 | public double getSelfLon() {
34 | return selfLon;
35 | }
36 |
37 | public boolean isFinished() {
38 | return finished;
39 | }
40 |
41 | @Override
42 | public void run() {
43 | //Get latitude, longitude
44 | try {
45 | URL url = new URL("http://www.speedtest.net/speedtest-config.php");
46 | InputStream is = url.openStream();
47 |
48 | int ptr = 0;
49 | StringBuffer buffer = new StringBuffer();
50 | while ((ptr = is.read()) != -1) {
51 | buffer.append((char) ptr);
52 | if (!buffer.toString().contains("isp=")) {
53 | continue;
54 | }
55 | selfLat = Double.parseDouble(buffer.toString().split("lat=\"")[1].split(" ")[0].replace("\"", ""));
56 | selfLon = Double.parseDouble(buffer.toString().split("lon=\"")[1].split(" ")[0].replace("\"", ""));
57 | break;
58 | }
59 | } catch (Exception ex) {
60 | ex.printStackTrace();
61 | return;
62 | }
63 |
64 | String uploadAddress = "";
65 | String name = "";
66 | String country = "";
67 | String cc = "";
68 | String sponsor = "";
69 | String lat = "";
70 | String lon = "";
71 | String host = "";
72 |
73 |
74 | //Best server
75 | int count = 0;
76 | try {
77 | URL url = new URL("http://www.speedtest.net/speedtest-servers-static.php");
78 | InputStream is = url.openStream();
79 |
80 | BufferedReader br = new BufferedReader(new InputStreamReader(is));
81 | String line;
82 | while ((line = br.readLine()) != null) {
83 | if (line.contains(" ls = Arrays.asList(lat, lon, name, country, cc, sponsor, host);
94 | mapKey.put(count, uploadAddress);
95 | mapValue.put(count, ls);
96 |
97 | count++;
98 | }
99 | }
100 |
101 | is.close();
102 | br.close();
103 | } catch (Exception ex) {
104 | ex.printStackTrace();
105 | }
106 |
107 | finished = true;
108 | }
109 | }
--------------------------------------------------------------------------------
/app/src/main/java/com/frogobox/viprox/source/model/Server.kt:
--------------------------------------------------------------------------------
1 | package com.frogobox.viprox.source.model
2 |
3 | /**
4 | * Created by Kusenko on 29.09.2016.
5 | */
6 | data class Server(
7 | var hostName: String? = null,
8 | var ip: String? = null,
9 | var score: String? = null,
10 | var ping: String? = null,
11 | var speed: String? = null,
12 | var countryLong: String? = null,
13 | var countryShort: String? = null,
14 | var numVpnSessions: String? = null,
15 | var uptime: String? = null,
16 | var totalUsers: String? = null,
17 | var totalTraffic: String? = null,
18 | var logType: String? = null,
19 | var operator: String? = null,
20 | var message: String? = null,
21 | var configData: String? = null,
22 | var quality: Int = 0,
23 | var city: String? = null,
24 | var type: Int = 0,
25 | var regionName: String? = null,
26 | var lat: Double = 0.0,
27 | var lon: Double = 0.0
28 | )
--------------------------------------------------------------------------------
/app/src/main/java/com/frogobox/viprox/ui/AboutUsActivity.kt:
--------------------------------------------------------------------------------
1 | package com.frogobox.viprox.ui
2 |
3 | import android.os.Bundle
4 | import com.frogobox.viprox.base.BaseActivity
5 | import com.frogobox.viprox.databinding.ActivityAboutUsBinding
6 |
7 | class AboutUsActivity : BaseActivity() {
8 |
9 | override fun setupViewBinding(): ActivityAboutUsBinding {
10 | return ActivityAboutUsBinding.inflate(layoutInflater)
11 | }
12 |
13 | override fun setupViewModel() {
14 | }
15 |
16 | override fun setupUI(savedInstanceState: Bundle?) {
17 | setupDetailActivity("")
18 | }
19 |
20 | }
21 |
--------------------------------------------------------------------------------
/app/src/main/java/com/frogobox/viprox/ui/CountryActivity.kt:
--------------------------------------------------------------------------------
1 | package com.frogobox.viprox.ui
2 |
3 | import android.content.Context
4 | import android.content.Intent
5 | import android.os.Bundle
6 | import android.view.LayoutInflater
7 | import android.view.ViewGroup
8 | import androidx.recyclerview.widget.RecyclerView
9 | import com.bumptech.glide.Glide
10 | import com.frogobox.recycler.core.FrogoLayoutManager
11 | import com.frogobox.recycler.core.IFrogoBuilderRvBinding
12 | import com.frogobox.viprox.base.BaseActivity
13 | import com.frogobox.viprox.databinding.ActivityCountryBinding
14 | import com.frogobox.viprox.databinding.ViewItemCountryBinding
15 | import com.frogobox.viprox.util.Constant
16 | import com.frogobox.viprox.source.model.Server
17 | import com.frogobox.viprox.util.CountriesNames
18 |
19 | class CountryActivity : BaseActivity() {
20 |
21 | override fun setupViewBinding(): ActivityCountryBinding {
22 | return ActivityCountryBinding.inflate(layoutInflater)
23 | }
24 |
25 | override fun setupViewModel() {
26 |
27 | }
28 |
29 | override fun setupUI(savedInstanceState: Bundle?) {
30 | setupDetailActivity("")
31 | setupShowAdsInterstitial()
32 | setupShowAdsBanner(binding.ads.admobAdview)
33 | setupRecyclerView()
34 | }
35 |
36 | private fun setupRecyclerView() {
37 |
38 | binding.recyclerViewCountry.builderBinding(object :
39 | IFrogoBuilderRvBinding {
40 |
41 | override fun onItemClicked(data: Server) {
42 | val intent = Intent(this@CountryActivity, VPNListActivity::class.java)
43 | intent.putExtra(Constant.Variable.EXTRA_COUNTRY, data.countryShort)
44 | startActivity(intent)
45 | }
46 |
47 | override fun onItemLongClicked(data: Server) {}
48 |
49 | override fun setViewBinding(parent: ViewGroup): ViewItemCountryBinding {
50 | return ViewItemCountryBinding.inflate(
51 | LayoutInflater.from(parent.context),
52 | parent,
53 | false
54 | )
55 | }
56 |
57 | override fun setupData(): List {
58 | return dbHelper.uniqueCountries
59 | }
60 |
61 | override fun setupInitComponent(binding: ViewItemCountryBinding, data: Server) {
62 | binding.apply {
63 | val localeCountries: MutableMap = CountriesNames.getCountries()
64 | val localeCountryName =
65 | if (localeCountries[data.countryShort] != null) localeCountries[data.countryShort] else data.countryLong
66 |
67 | tvCountryName.text = localeCountryName
68 | Glide.with(binding.root.context).load(Constant().getFlagImageUrl(data))
69 | .into(ivServerFlag)
70 | }
71 | }
72 |
73 | override fun setupLayoutManager(context: Context): RecyclerView.LayoutManager {
74 | return FrogoLayoutManager.staggeredGridLayout(2)
75 | }
76 | })
77 |
78 | }
79 |
80 | }
81 |
--------------------------------------------------------------------------------
/app/src/main/java/com/frogobox/viprox/ui/MainActivity.kt:
--------------------------------------------------------------------------------
1 | package com.frogobox.viprox.ui
2 |
3 | import android.os.Bundle
4 | import android.view.Menu
5 | import android.view.MenuItem
6 | import android.view.View
7 | import com.frogobox.viprox.R
8 | import com.frogobox.viprox.base.BaseActivity
9 | import com.frogobox.viprox.databinding.ActivityMainBinding
10 | import com.frogobox.viprox.util.PropertiesService
11 |
12 | class MainActivity : BaseActivity() {
13 |
14 | override fun setupViewBinding(): ActivityMainBinding {
15 | return ActivityMainBinding.inflate(layoutInflater)
16 | }
17 |
18 | override fun setupViewModel() {}
19 |
20 | override fun setupUI(savedInstanceState: Bundle?) {
21 | binding.apply {
22 | setSupportActionBar(toolbar.toolbarMain)
23 | setupShowAdsInterstitial()
24 | setupShowAdsBanner(ads.admobAdview)
25 | setupViewFunction()
26 | }
27 | }
28 |
29 | override fun onCreateOptionsMenu(menu: Menu?): Boolean {
30 | menuInflater.inflate(R.menu.menu_toolbar_main, menu)
31 | return true
32 | }
33 |
34 | override fun onOptionsItemSelected(item: MenuItem): Boolean {
35 | return when (item.itemId) {
36 | R.id.toolbar_menu_about -> {
37 | baseStartActivity()
38 | true
39 | }
40 |
41 | R.id.toolbar_location -> {
42 | baseStartActivity()
43 | true
44 | }
45 |
46 | else -> super.onOptionsItemSelected(item)
47 | }
48 | }
49 |
50 | private fun setupViewFunction() {
51 | binding.btnQuickConnect.setOnClickListener { v: View? ->
52 | if (getRandomServer() != null) {
53 | newConnecting(getRandomServer(), fastConnection = true, autoConnection = true)
54 | } else {
55 | showToast(
56 | String.format(
57 | resources.getString(R.string.error_random_country),
58 | PropertiesService.getSelectedCountry()
59 | )
60 | )
61 | }
62 | }
63 |
64 | }
65 |
66 | }
--------------------------------------------------------------------------------
/app/src/main/java/com/frogobox/viprox/ui/SplashActivity.kt:
--------------------------------------------------------------------------------
1 | package com.frogobox.viprox.ui
2 |
3 | import android.content.DialogInterface
4 | import android.os.Bundle
5 | import android.os.Handler
6 | import android.os.Message
7 | import android.view.View
8 | import androidx.appcompat.app.AlertDialog
9 | import com.androidnetworking.AndroidNetworking
10 | import com.androidnetworking.common.Priority
11 | import com.androidnetworking.error.ANError
12 | import com.androidnetworking.interfaces.DownloadListener
13 | import com.frogobox.viprox.BuildConfig
14 | import com.frogobox.viprox.R
15 | import com.frogobox.viprox.base.BaseActivity
16 | import com.frogobox.viprox.databinding.ActivitySplashBinding
17 | import com.frogobox.viprox.util.Constant.Variable.BASE_FILE_NAME
18 | import com.frogobox.viprox.util.Constant.Variable.BASE_URL
19 | import com.frogobox.viprox.util.Constant.Variable.DOWNLOAD_PROGRESS
20 | import com.frogobox.viprox.util.Constant.Variable.EXTRA_FIRST_PREMIUM_LOAD
21 | import com.frogobox.viprox.util.Constant.Variable.LOADING_SUCCESS
22 | import com.frogobox.viprox.util.Constant.Variable.LOAD_ERROR
23 | import com.frogobox.viprox.util.Constant.Variable.PARSE_PROGRESS
24 | import com.frogobox.viprox.util.Constant.Variable.PRECENTAGE_MAX
25 | import com.frogobox.viprox.util.Constant.Variable.SWITCH_TO_RESULT
26 | import com.frogobox.viprox.util.NetworkState
27 | import com.frogobox.viprox.util.PropertiesService
28 | import okhttp3.OkHttpClient
29 | import java.io.BufferedReader
30 | import java.io.FileReader
31 | import java.io.IOException
32 | import java.util.concurrent.TimeUnit
33 |
34 | class SplashActivity : BaseActivity() {
35 |
36 | private var updateHandler: Handler? = null
37 | private val premiumStage = true
38 | private var percentDownload = 0
39 |
40 | override fun setupViewBinding(): ActivitySplashBinding {
41 | return ActivitySplashBinding.inflate(layoutInflater)
42 | }
43 |
44 | override fun setupViewModel() {}
45 |
46 | override fun setupUI(savedInstanceState: Bundle?) {
47 | runBackgroundProcess()
48 | binding.tvVersionApp.text = "v" + BuildConfig.VERSION_NAME
49 | }
50 |
51 | override fun onResume() {
52 | super.onResume()
53 | downloadCSVFile(BASE_URL, BASE_FILE_NAME)
54 | }
55 |
56 | private fun runBackgroundProcess() {
57 | binding.apply {
58 | if (NetworkState.isOnline()) {
59 | if (loadStatus) {
60 | baseStartActivity()
61 | finish()
62 | } else {
63 | loadStatus = true
64 | }
65 | } else {
66 | val builder = AlertDialog.Builder(this@SplashActivity)
67 | builder.setTitle(getString(R.string.network_error))
68 | .setMessage(getString(R.string.network_error_message))
69 | .setNegativeButton(
70 | getString(R.string.ok)
71 | ) { dialog: DialogInterface, id: Int ->
72 | dialog.cancel()
73 | onBackPressed()
74 | }
75 | builder.create().show()
76 | }
77 | if (intent.getBooleanExtra(EXTRA_FIRST_PREMIUM_LOAD, false)) {
78 | loaderPremiumText.visibility = View.VISIBLE
79 | }
80 | numberProgressBar.max = PRECENTAGE_MAX
81 | updateHandler = Handler(Handler.Callback { msg: Message ->
82 | when (msg.arg1) {
83 | LOAD_ERROR -> {
84 | commentsText.setText(msg.arg2)
85 | numberProgressBar.progress = PRECENTAGE_MAX
86 | }
87 | DOWNLOAD_PROGRESS -> {
88 | commentsText.text = getString(R.string.downloading_csv_text)
89 | numberProgressBar.progress = msg.arg2
90 | }
91 | PARSE_PROGRESS -> {
92 | commentsText.setText(R.string.parsing_csv_text)
93 | numberProgressBar.progress = msg.arg2
94 | }
95 | LOADING_SUCCESS -> {
96 | commentsText.setText(R.string.successfully_loaded)
97 | numberProgressBar.progress = PRECENTAGE_MAX
98 | val end = Message()
99 | end.arg1 = SWITCH_TO_RESULT
100 | updateHandler!!.sendMessageDelayed(end, 500)
101 | }
102 | SWITCH_TO_RESULT -> {
103 | if (PropertiesService.getConnectOnStart()) {
104 | val randomServer = getRandomServer()
105 | if (randomServer != null) {
106 | newConnecting(randomServer, true, true)
107 | } else {
108 | baseStartActivity()
109 | }
110 | } else {
111 | baseStartActivity()
112 | }
113 | }
114 | }
115 | true
116 | })
117 | numberProgressBar.progress = 0
118 | }
119 | }
120 |
121 | private fun downloadCSVFile(url: String, fileName: String) {
122 | val okHttpClient = OkHttpClient().newBuilder()
123 | .connectTimeout(60, TimeUnit.SECONDS)
124 | .readTimeout(60, TimeUnit.SECONDS)
125 | .writeTimeout(60, TimeUnit.SECONDS)
126 | .build()
127 | AndroidNetworking.download(url, cacheDir.path, fileName)
128 | .setTag("downloadCSV")
129 | .setPriority(Priority.MEDIUM)
130 | .setOkHttpClient(okHttpClient)
131 | .build()
132 | .setDownloadProgressListener { bytesDownloaded, totalBytes ->
133 | var totalBytes = totalBytes
134 | if (totalBytes <= 0) { // when we dont know the file size, assume it is 1200000 bytes :)
135 | totalBytes = 1200000
136 | }
137 | percentDownload = (PRECENTAGE_MAX * bytesDownloaded / totalBytes).toInt()
138 | val msg = Message()
139 | msg.arg1 = DOWNLOAD_PROGRESS
140 | msg.arg2 = percentDownload
141 | updateHandler!!.sendMessage(msg)
142 | }
143 | .startDownload(object : DownloadListener {
144 | override fun onDownloadComplete() {
145 | parseCSVFile(BASE_FILE_NAME)
146 | }
147 |
148 | override fun onError(error: ANError) {
149 | val msg = Message()
150 | msg.arg1 = LOAD_ERROR
151 | msg.arg2 = R.string.network_error
152 | updateHandler!!.sendMessage(msg)
153 | }
154 | })
155 | }
156 |
157 | private fun parseCSVFile(fileName: String) {
158 | var reader: BufferedReader? = null
159 | try {
160 | reader = BufferedReader(FileReader(cacheDir.path + "/" + fileName))
161 | } catch (e: IOException) {
162 | e.printStackTrace()
163 | val msg = Message()
164 | msg.arg1 = LOAD_ERROR
165 | msg.arg2 = R.string.csv_file_error
166 | updateHandler!!.sendMessage(msg)
167 | }
168 | if (reader != null) {
169 | try {
170 | val startLine = 2
171 | val type = 0
172 | dbHelper.clearTable()
173 | var counter = 0
174 | var line: String? = null
175 | while (reader.readLine().also { line = it } != null) {
176 | if (counter >= startLine) {
177 | dbHelper.putLine(line, type)
178 | }
179 | counter++
180 | }
181 | val end = Message()
182 | end.arg1 = LOADING_SUCCESS
183 | updateHandler!!.sendMessageDelayed(end, 200)
184 | } catch (e: Exception) {
185 | e.printStackTrace()
186 | val msg = Message()
187 | msg.arg1 = LOAD_ERROR
188 | msg.arg2 = R.string.csv_file_error_parsing
189 | updateHandler!!.sendMessage(msg)
190 | }
191 | }
192 | }
193 |
194 | companion object {
195 | private var loadStatus = false
196 | }
197 |
198 | }
--------------------------------------------------------------------------------
/app/src/main/java/com/frogobox/viprox/ui/VPNListActivity.kt:
--------------------------------------------------------------------------------
1 | package com.frogobox.viprox.ui
2 |
3 | import android.content.Context
4 | import android.os.Bundle
5 | import android.view.LayoutInflater
6 | import android.view.ViewGroup
7 | import androidx.recyclerview.widget.RecyclerView
8 | import com.bumptech.glide.Glide
9 | import com.frogobox.recycler.core.FrogoLayoutManager
10 | import com.frogobox.recycler.core.IFrogoBuilderRvBinding
11 | import com.frogobox.viprox.R
12 | import com.frogobox.viprox.base.BaseActivity
13 | import com.frogobox.viprox.databinding.ActivityVpnlistBinding
14 | import com.frogobox.viprox.databinding.ViewItemServerBinding
15 | import com.frogobox.viprox.util.Constant
16 | import com.frogobox.viprox.util.Constant.Variable.EXTRA_COUNTRY
17 | import com.frogobox.viprox.source.model.Server
18 | import com.frogobox.viprox.util.ConnectionQuality
19 | import de.blinkt.openvpn.core.VpnStatus
20 |
21 | class VPNListActivity : BaseActivity() {
22 |
23 | override fun setupViewBinding(): ActivityVpnlistBinding {
24 | return ActivityVpnlistBinding.inflate(layoutInflater)
25 | }
26 |
27 | override fun setupViewModel() {}
28 |
29 | override fun setupUI(savedInstanceState: Bundle?) {
30 | setupShowAdsBanner(findViewById(R.id.admob_adview))
31 | setupShowAdsInterstitial()
32 | setupDetailActivity("")
33 |
34 | val country = intent.getStringExtra(EXTRA_COUNTRY)
35 |
36 | if (!VpnStatus.isVPNActive()) {
37 | connectedServer = null
38 | }
39 |
40 | if (country != null) {
41 | getIpInfoFromServerList(dbHelper.getServersByCountryCode(country))
42 | setupRecyclerView(country)
43 | }
44 |
45 | }
46 |
47 | private fun setupRecyclerView(country: String) {
48 |
49 | binding.recyclerView.builderBinding(object :
50 | IFrogoBuilderRvBinding {
51 | override fun onItemClicked(data: Server) {
52 | baseStartActivity(Server::class.java.canonicalName!!, data)
53 | }
54 |
55 | override fun onItemLongClicked(data: Server) {}
56 |
57 | override fun setViewBinding(parent: ViewGroup): ViewItemServerBinding {
58 | return ViewItemServerBinding.inflate(
59 | LayoutInflater.from(parent.context),
60 | parent,
61 | false
62 | )
63 | }
64 |
65 | override fun setupData(): List {
66 | return dbHelper.getServersByCountryCode(country)
67 | }
68 |
69 | override fun setupInitComponent(binding: ViewItemServerBinding, data: Server) {
70 | binding.apply {
71 | Glide.with(binding.root.context).load(Constant().getFlagImageUrl(data))
72 | .into(imageFlag)
73 | imageConnect.setImageResource(
74 | binding.root.context.resources.getIdentifier(
75 | ConnectionQuality.getConnectIcon(
76 | data.quality
77 | ), "drawable", binding.root.context.packageName
78 | )
79 | )
80 | textHostName.text = data.hostName
81 | textIP.text = data.ip
82 | textCity.text = data.city
83 | }
84 | }
85 |
86 | override fun setupLayoutManager(context: Context): RecyclerView.LayoutManager {
87 | return FrogoLayoutManager.linearLayoutVertical(context)
88 | }
89 | })
90 |
91 | }
92 |
93 | }
--------------------------------------------------------------------------------
/app/src/main/java/com/frogobox/viprox/util/ConnectionQuality.java:
--------------------------------------------------------------------------------
1 | package com.frogobox.viprox.util;
2 |
3 |
4 |
5 | public class ConnectionQuality {
6 |
7 | private static final String CONNECT_BAD = "ic_connect_bad";
8 | private static final String CONNECT_GOOD = "ic_connect_good";
9 | private static final String CONNECT_EXCELLENT = "ic_connect_excellent";
10 | private static final String CONNECT_INACTIVE = "ic_connect_inactive";
11 |
12 | private static final String POINT_BAD = "ic_point_red";
13 | private static final String POINT_GOOD = "ic_point_yellow";
14 | private static final String POINT_EXCELLENT = "ic_point_green";
15 | private static final String POINT_INACTIVE = "ic_point_grey";
16 |
17 | private static final String SIMPLE_POINT_BAD = "ic_simple_point_red";
18 | private static final String SIMPLE_POINT_GOOD = "ic_simple_point_yellow";
19 | private static final String SIMPLE_POINT_EXCELLENT = "ic_simple_point_green";
20 | private static final String SIMPLE_POINT_INACTIVE = "ic_simple_point_grey";
21 |
22 | public static String getConnectIcon(int quality) {
23 | switch (quality) {
24 | case 0:
25 | return CONNECT_INACTIVE;
26 | case 1:
27 | return CONNECT_BAD;
28 | case 2:
29 | return CONNECT_GOOD;
30 | case 3:
31 | return CONNECT_EXCELLENT;
32 | default:
33 | return CONNECT_INACTIVE;
34 | }
35 | }
36 |
37 | public static String getPointIcon(int quality) {
38 | switch (quality) {
39 | case 0:
40 | return POINT_INACTIVE;
41 | case 1:
42 | return POINT_BAD;
43 | case 2:
44 | return POINT_GOOD;
45 | case 3:
46 | return POINT_EXCELLENT;
47 | default:
48 | return POINT_INACTIVE;
49 | }
50 | }
51 |
52 | public static String getSimplePointIcon(int quality) {
53 | switch (quality) {
54 | case 0:
55 | return SIMPLE_POINT_INACTIVE;
56 | case 1:
57 | return SIMPLE_POINT_BAD;
58 | case 2:
59 | return SIMPLE_POINT_GOOD;
60 | case 3:
61 | return SIMPLE_POINT_EXCELLENT;
62 | default:
63 | return SIMPLE_POINT_INACTIVE;
64 | }
65 | }
66 |
67 | public static int getConnectionQuality(String speedStr, String sessionsStr, String pingStr) {
68 |
69 | int speed = Integer.parseInt(speedStr);
70 | int sessions = Integer.parseInt(sessionsStr);
71 |
72 | int ping = 0;
73 | if (!(pingStr.equals("-") || pingStr.equals(""))) {
74 | ping = Integer.parseInt(pingStr);
75 | }
76 |
77 | if (speed > 10000000 && ping < 30 && (sessions != 0 && sessions < 100)) {
78 | return 3;
79 | } else if (speed < 1000000 || ping > 100 || (sessions == 0 || sessions > 150)) {
80 | return 1;
81 | } else {
82 | return 2;
83 | }
84 | }
85 | }
86 |
--------------------------------------------------------------------------------
/app/src/main/java/com/frogobox/viprox/util/Constant.kt:
--------------------------------------------------------------------------------
1 | package com.frogobox.viprox.util
2 |
3 | import com.frogobox.viprox.util.Constant.Variable.BASE_FLAG_IMAGE_SIZE
4 | import com.frogobox.viprox.util.Constant.Variable.BASE_FLAG_IMAGE_URL
5 | import com.frogobox.viprox.source.model.Server
6 |
7 | /**
8 | * Created by Faisal Amir
9 | * FrogoBox Inc License
10 | * =========================================
11 | * Frogobox-VPN-Hero
12 | * Copyright (C) 25/11/2019.
13 | * All rights reserved
14 | * -----------------------------------------
15 | * Name : Muhammad Faisal Amir
16 | * E-mail : faisalamircs@gmail.com
17 | * Github : github.com/amirisback
18 | * LinkedIn : linkedin.com/in/faisalamircs
19 | * -----------------------------------------
20 | * FrogoBox Software Industries
21 | * com.frogobox.evpn.helper
22 | *
23 | */
24 | class Constant {
25 |
26 | object Variable {
27 |
28 | const val LOAD_ERROR = 0
29 | const val DOWNLOAD_PROGRESS = 1
30 | const val PARSE_PROGRESS = 2
31 | const val LOADING_SUCCESS = 3
32 | const val SWITCH_TO_RESULT = 4
33 |
34 | const val PRECENTAGE_MAX = 100
35 |
36 | const val START_VPN_PROFILE = 70
37 |
38 | const val BASE_URL = "http://www.vpngate.net/api/iphone/"
39 | const val BASE_FILE_NAME = "vpngate.csv"
40 | const val BROADCAST_ACTION = "de.blinkt.openvpn.VPN_STATUS"
41 |
42 | const val EXTRA_COUNTRY = "EXTRA_COUNTRY"
43 | const val EXTRA_FAST_CONNECTION = "EXTRA_FAST_CONNECTION"
44 | const val EXTRA_AUTO_CONNECTION = "EXTRA_AUTO_CONNECTION"
45 | const val EXTRA_FIRST_PREMIUM_LOAD = "firstPremiumLoad"
46 | const val EXTRA_STATUS = "status"
47 |
48 | const val BASE_FLAG_IMAGE_URL = "https://www.countryflags.io/"
49 | const val BASE_FLAG_IMAGE_SIZE = "/flat/64.png"
50 | }
51 |
52 |
53 | fun getFlagImageUrl(data: Server): String {
54 | var code: String = data.countryShort!!.toLowerCase()
55 | if (code == "do") code = "dom"
56 | return "$BASE_FLAG_IMAGE_URL$code$BASE_FLAG_IMAGE_SIZE"
57 | }
58 |
59 |
60 | }
--------------------------------------------------------------------------------
/app/src/main/java/com/frogobox/viprox/util/CountriesNames.java:
--------------------------------------------------------------------------------
1 | package com.frogobox.viprox.util;
2 |
3 | import java.util.HashMap;
4 | import java.util.Locale;
5 | import java.util.Map;
6 |
7 |
8 |
9 | public class CountriesNames {
10 |
11 | public static Map getCountries() {
12 | Map countries = new HashMap();
13 |
14 | String[] isoCountries = Locale.getISOCountries();
15 | for (String country : isoCountries) {
16 | Locale locale = new Locale("", country);
17 | String iso = locale.getISO3Country();
18 | String code = locale.getCountry();
19 | String name = locale.getDisplayCountry();
20 |
21 | if (!"".equals(iso) && !"".equals(code)
22 | && !"".equals(name)) {
23 | countries.put(code, name);
24 | }
25 | }
26 |
27 | return countries;
28 | }
29 | }
30 |
--------------------------------------------------------------------------------
/app/src/main/java/com/frogobox/viprox/util/NetworkState.java:
--------------------------------------------------------------------------------
1 | package com.frogobox.viprox.util;
2 |
3 | import android.content.Context;
4 | import android.net.ConnectivityManager;
5 | import android.net.NetworkInfo;
6 |
7 | import com.frogobox.viprox.BaseApplication;
8 |
9 |
10 | public class NetworkState {
11 |
12 | public static boolean isOnline() {
13 | ConnectivityManager cm =
14 | (ConnectivityManager) BaseApplication.instance.getSystemService(Context.CONNECTIVITY_SERVICE);
15 | NetworkInfo netInfo = cm.getActiveNetworkInfo();
16 | return netInfo != null && netInfo.isConnectedOrConnecting();
17 | }
18 | }
19 |
--------------------------------------------------------------------------------
/app/src/main/java/com/frogobox/viprox/util/NotificationUtils.java:
--------------------------------------------------------------------------------
1 | package com.frogobox.viprox.util;
2 |
3 | import android.app.Notification;
4 | import android.app.NotificationManager;
5 | import android.app.PendingIntent;
6 | import android.content.ContentResolver;
7 | import android.content.Context;
8 | import android.content.Intent;
9 | import android.graphics.Bitmap;
10 | import android.graphics.BitmapFactory;
11 | import android.media.Ringtone;
12 | import android.media.RingtoneManager;
13 | import android.net.Uri;
14 |
15 | import androidx.core.app.NotificationCompat;
16 | import android.text.Html;
17 |
18 | import com.frogobox.viprox.R;
19 | import com.frogobox.viprox.ui.MainActivity;
20 |
21 | import java.io.IOException;
22 | import java.io.InputStream;
23 | import java.net.HttpURLConnection;
24 | import java.net.URL;
25 | import java.util.HashMap;
26 | import java.util.Map;
27 |
28 | public class NotificationUtils {
29 | private static final int NOTIFICATION_ID = 200;
30 | private static final String PUSH_NOTIFICATION = "pushNotification";
31 | private static final String CHANNEL_ID = "myChannel";
32 | private static final String URL = "url";
33 | private static final String ACTIVITY = "activity";
34 | Map activityMap = new HashMap<>();
35 | private Context mContext;
36 |
37 | public NotificationUtils(Context mContext) {
38 | this.mContext = mContext;
39 | //Populate activity map
40 | activityMap.put("MainActivity", MainActivity.class);
41 | // activityMap.put("SecondActivity", SecondActivity.class);
42 | }
43 |
44 | /**
45 | * Displays notification based on parameters
46 | *
47 | * @param notificationVO
48 | * @param resultIntent
49 | */
50 | public void displayNotification(com.frogobox.viprox.util.NotificationVO notificationVO, Intent resultIntent) {
51 | {
52 | String message = notificationVO.getMessage();
53 | String title = notificationVO.getTitle();
54 | String iconUrl = notificationVO.getIconUrl();
55 | String action = notificationVO.getAction();
56 | String destination = notificationVO.getActionDestination();
57 | Bitmap iconBitMap = null;
58 | if (iconUrl != null) {
59 | iconBitMap = getBitmapFromURL(iconUrl);
60 | }
61 | final int icon = R.drawable.ic_launcher;
62 |
63 | PendingIntent resultPendingIntent;
64 |
65 | if (URL.equals(action)) {
66 | Intent notificationIntent = new Intent(Intent.ACTION_VIEW, Uri.parse(destination));
67 |
68 | resultPendingIntent = PendingIntent.getActivity(mContext, 0, notificationIntent, 0);
69 | } else if (ACTIVITY.equals(action) && activityMap.containsKey(destination)) {
70 | resultIntent = new Intent(mContext, activityMap.get(destination));
71 |
72 | resultPendingIntent =
73 | PendingIntent.getActivity(
74 | mContext,
75 | 0,
76 | resultIntent,
77 | PendingIntent.FLAG_CANCEL_CURRENT
78 | );
79 | } else {
80 | resultIntent.setFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP | Intent.FLAG_ACTIVITY_SINGLE_TOP);
81 | resultPendingIntent =
82 | PendingIntent.getActivity(
83 | mContext,
84 | 0,
85 | resultIntent,
86 | PendingIntent.FLAG_CANCEL_CURRENT
87 | );
88 | }
89 |
90 |
91 | final NotificationCompat.Builder mBuilder = new NotificationCompat.Builder(
92 | mContext, CHANNEL_ID);
93 |
94 | Notification notification;
95 |
96 | if (iconBitMap == null) {
97 | //When Inbox Style is applied, user can expand the notification
98 | NotificationCompat.InboxStyle inboxStyle = new NotificationCompat.InboxStyle();
99 |
100 | inboxStyle.addLine(message);
101 | notification = mBuilder.setSmallIcon(icon).setTicker(title).setWhen(0)
102 | .setAutoCancel(true)
103 | .setContentTitle(title)
104 | .setContentIntent(resultPendingIntent)
105 | .setStyle(inboxStyle)
106 | .setSmallIcon(R.drawable.ic_launcher)
107 | .setLargeIcon(BitmapFactory.decodeResource(mContext.getResources(), icon))
108 | .setContentText(message)
109 | .build();
110 |
111 | } else {
112 | //If Bitmap is created from URL, show big icon
113 | NotificationCompat.BigPictureStyle bigPictureStyle = new NotificationCompat.BigPictureStyle();
114 | bigPictureStyle.setBigContentTitle(title);
115 | bigPictureStyle.setSummaryText(Html.fromHtml(message).toString());
116 | bigPictureStyle.bigPicture(iconBitMap);
117 | notification = mBuilder.setSmallIcon(icon).setTicker(title).setWhen(0)
118 | .setAutoCancel(true)
119 | .setContentTitle(title)
120 | .setContentIntent(resultPendingIntent)
121 | .setStyle(bigPictureStyle)
122 | .setSmallIcon(R.drawable.ic_launcher)
123 | .setLargeIcon(BitmapFactory.decodeResource(mContext.getResources(), icon))
124 | .setContentText(message)
125 | .build();
126 | }
127 |
128 | NotificationManager notificationManager = (NotificationManager) mContext.getSystemService(Context.NOTIFICATION_SERVICE);
129 | notificationManager.notify(NOTIFICATION_ID, notification);
130 | }
131 | }
132 |
133 | /**
134 | * Downloads push notification image before displaying it in
135 | * the notification tray
136 | *
137 | * @param strURL : URL of the notification Image
138 | * @return : BitMap representation of notification Image
139 | */
140 | private Bitmap getBitmapFromURL(String strURL) {
141 | try {
142 | URL url = new URL(strURL);
143 | HttpURLConnection connection = (HttpURLConnection) url.openConnection();
144 | connection.setDoInput(true);
145 | connection.connect();
146 | InputStream input = connection.getInputStream();
147 | return BitmapFactory.decodeStream(input);
148 | } catch (IOException e) {
149 | e.printStackTrace();
150 | return null;
151 | }
152 | }
153 |
154 | /**
155 | * Playing notification sound
156 | */
157 | public void playNotificationSound() {
158 | try {
159 | Uri alarmSound = Uri.parse(ContentResolver.SCHEME_ANDROID_RESOURCE
160 | + "://" + mContext.getPackageName() + "/raw/notification");
161 | Ringtone r = RingtoneManager.getRingtone(mContext, alarmSound);
162 | r.play();
163 | } catch (Exception e) {
164 | e.printStackTrace();
165 | }
166 | }
167 | }
168 |
--------------------------------------------------------------------------------
/app/src/main/java/com/frogobox/viprox/util/NotificationVO.java:
--------------------------------------------------------------------------------
1 | package com.frogobox.viprox.util;
2 |
3 | /**
4 | * Created by Abhi on 13 Nov 2017 013.
5 | */
6 |
7 | public class NotificationVO {
8 | private String title;
9 | private String message;
10 | private String iconUrl;
11 | private String action;
12 | private String actionDestination;
13 |
14 | public String getTitle() {
15 | return title;
16 | }
17 |
18 | public void setTitle(String title) {
19 | this.title = title;
20 | }
21 |
22 | public String getMessage() {
23 | return message;
24 | }
25 |
26 | public void setMessage(String message) {
27 | this.message = message;
28 | }
29 |
30 | public String getIconUrl() {
31 | return iconUrl;
32 | }
33 |
34 | public void setIconUrl(String iconUrl) {
35 | this.iconUrl = iconUrl;
36 | }
37 |
38 | public String getAction() {
39 | return action;
40 | }
41 |
42 | public void setAction(String action) {
43 | this.action = action;
44 | }
45 |
46 | public String getActionDestination() {
47 | return actionDestination;
48 | }
49 |
50 | public void setActionDestination(String actionDestination) {
51 | this.actionDestination = actionDestination;
52 | }
53 | }
54 |
--------------------------------------------------------------------------------
/app/src/main/java/com/frogobox/viprox/util/NumberPickerPreference.java:
--------------------------------------------------------------------------------
1 | package com.frogobox.viprox.util;
2 |
3 | import android.content.Context;
4 | import android.content.res.TypedArray;
5 | import android.preference.DialogPreference;
6 | import android.util.AttributeSet;
7 | import android.view.Gravity;
8 | import android.view.View;
9 | import android.view.ViewGroup;
10 | import android.widget.FrameLayout;
11 | import android.widget.NumberPicker;
12 |
13 |
14 |
15 | public class NumberPickerPreference extends DialogPreference {
16 |
17 |
18 | public static final int MAX_VALUE = 120;
19 | public static final int MIN_VALUE = 10;
20 |
21 | public static final boolean WRAP_SELECTOR_WHEEL = true;
22 |
23 | private NumberPicker picker;
24 | private int value;
25 |
26 | public NumberPickerPreference(Context context, AttributeSet attrs) {
27 | super(context, attrs);
28 | }
29 |
30 | public NumberPickerPreference(Context context, AttributeSet attrs, int defStyleAttr) {
31 | super(context, attrs, defStyleAttr);
32 | }
33 |
34 | @Override
35 | protected View onCreateDialogView() {
36 | FrameLayout.LayoutParams layoutParams = new FrameLayout.LayoutParams(
37 | ViewGroup.LayoutParams.WRAP_CONTENT, ViewGroup.LayoutParams.WRAP_CONTENT);
38 | layoutParams.gravity = Gravity.CENTER;
39 |
40 | picker = new NumberPicker(getContext());
41 | picker.setLayoutParams(layoutParams);
42 |
43 | FrameLayout dialogView = new FrameLayout(getContext());
44 | dialogView.addView(picker);
45 |
46 | return dialogView;
47 | }
48 |
49 | @Override
50 | protected void onBindDialogView(View view) {
51 | super.onBindDialogView(view);
52 | picker.setMinValue(MIN_VALUE);
53 | picker.setMaxValue(MAX_VALUE);
54 | picker.setWrapSelectorWheel(WRAP_SELECTOR_WHEEL);
55 | picker.setValue(getValue());
56 | }
57 |
58 | @Override
59 | protected void onDialogClosed(boolean positiveResult) {
60 | if (positiveResult) {
61 | picker.clearFocus();
62 | int newValue = picker.getValue();
63 | if (callChangeListener(newValue)) {
64 | setValue(newValue);
65 | }
66 | }
67 | }
68 |
69 | @Override
70 | protected Object onGetDefaultValue(TypedArray a, int index) {
71 | return a.getInt(index, MIN_VALUE);
72 | }
73 |
74 | @Override
75 | protected void onSetInitialValue(boolean restorePersistedValue, Object defaultValue) {
76 | setValue(restorePersistedValue ? getPersistedInt(MIN_VALUE) : (Integer) defaultValue);
77 | }
78 |
79 | public void setValue(int value) {
80 | this.value = value;
81 | persistInt(this.value);
82 | }
83 |
84 | public int getValue() {
85 | return this.value;
86 | }
87 | }
88 |
--------------------------------------------------------------------------------
/app/src/main/java/com/frogobox/viprox/util/PropertiesService.java:
--------------------------------------------------------------------------------
1 | package com.frogobox.viprox.util;
2 |
3 | import android.content.SharedPreferences;
4 | import android.preference.PreferenceManager;
5 |
6 | import com.frogobox.viprox.BaseApplication;
7 |
8 |
9 |
10 | public class PropertiesService {
11 |
12 | private static SharedPreferences prefs;
13 | private static final String DOWNLOADED_DATA_KEY = "downloaded_data";
14 | private static final String UPLOADED_DATA_KEY = "uploaded_data";
15 | private static final String AUTOMATIC_SWITCHING = "automaticSwitching";
16 | private static final String COUNTRY_PRIORITY = "countryPriority";
17 | private static final String CONNECT_ON_START = "connectOnStart";
18 | private static final String AUTOMATIC_SWITCHING_SECONDS = "automaticSwitchingSeconds";
19 | private static final String SELECTED_COUNTRY = "selectedCountry";
20 | private static final String SHOW_RATING = "show_rating";
21 | private static final String SHOW_NOTE = "show_note";
22 |
23 | private synchronized static SharedPreferences getPrefs(){
24 | if (prefs == null) {
25 | prefs = PreferenceManager.getDefaultSharedPreferences(BaseApplication.instance);
26 | }
27 | return prefs;
28 | }
29 |
30 | public static long getDownloaded(){
31 | return getPrefs().getLong(DOWNLOADED_DATA_KEY, 0);
32 | }
33 |
34 | public static void setDownloaded(long count){
35 | getPrefs().edit().putLong(DOWNLOADED_DATA_KEY, count).apply();
36 | }
37 |
38 | public static long getUploaded(){
39 | return getPrefs().getLong(UPLOADED_DATA_KEY, 0);
40 | }
41 |
42 | public static void setUploaded(long count){
43 | getPrefs().edit().putLong(UPLOADED_DATA_KEY, count).apply();
44 | }
45 |
46 | public static boolean getConnectOnStart(){
47 | return getPrefs().getBoolean(CONNECT_ON_START, false);
48 | }
49 |
50 | public static boolean getAutomaticSwitching(){
51 | return getPrefs().getBoolean(AUTOMATIC_SWITCHING, true);
52 | }
53 |
54 | public static int getAutomaticSwitchingSeconds(){
55 | return getPrefs().getInt(AUTOMATIC_SWITCHING_SECONDS, 40);
56 | }
57 |
58 | public static boolean getCountryPriority(){
59 | return getPrefs().getBoolean(COUNTRY_PRIORITY, false);
60 | }
61 |
62 | public static String getSelectedCountry(){
63 | return getPrefs().getString(SELECTED_COUNTRY, null);
64 | }
65 |
66 | public static boolean getShowRating(){
67 | return getPrefs().getBoolean(SHOW_RATING, true);
68 | }
69 |
70 | public static void setShowRating(boolean showRating){
71 | getPrefs().edit().putBoolean(SHOW_RATING, showRating).apply();
72 | }
73 |
74 | public static boolean getShowNote(){
75 | return getPrefs().getBoolean(SHOW_NOTE, true);
76 | }
77 |
78 | public static void setShowNote(boolean showNote){
79 | getPrefs().edit().putBoolean(SHOW_NOTE, showNote).apply();
80 | }
81 |
82 |
83 | }
84 |
--------------------------------------------------------------------------------
/app/src/main/java/com/frogobox/viprox/util/Stopwatch.java:
--------------------------------------------------------------------------------
1 | package com.frogobox.viprox.util;
2 |
3 | import java.text.SimpleDateFormat;
4 | import java.util.Calendar;
5 | import java.util.TimeZone;
6 |
7 | public class Stopwatch {
8 |
9 | private SimpleDateFormat sdf = new SimpleDateFormat("HH:mm:ss");
10 | private Calendar calendar = Calendar.getInstance();
11 | private long startTime = System.currentTimeMillis();
12 |
13 | public Stopwatch() {
14 | sdf.setTimeZone(TimeZone.getTimeZone("UTC"));
15 | }
16 |
17 | public long getDiff() {
18 | return System.currentTimeMillis() - startTime;
19 | }
20 |
21 | public String getElapsedTime() {
22 | calendar.setTimeInMillis(getDiff());
23 | return sdf.format(calendar.getTime());
24 | }
25 | }
26 |
--------------------------------------------------------------------------------
/app/src/main/java/com/frogobox/viprox/util/TotalTraffic.java:
--------------------------------------------------------------------------------
1 | package com.frogobox.viprox.util;
2 |
3 | import android.content.Context;
4 | import android.content.Intent;
5 |
6 | import java.util.ArrayList;
7 | import java.util.List;
8 |
9 | import de.blinkt.openvpn.core.OpenVPNService;
10 |
11 |
12 |
13 | public class TotalTraffic {
14 |
15 | public static final String TRAFFIC_ACTION = "traffic_action";
16 |
17 | public static final String DOWNLOAD_ALL = "download_all";
18 | public static final String DOWNLOAD_SESSION = "download_session";
19 | public static final String UPLOAD_ALL = "upload_all";
20 | public static final String UPLOAD_SESSION = "upload_session";
21 |
22 | public static long inTotal;
23 | public static long outTotal;
24 |
25 |
26 | public static void calcTraffic(Context context, long in, long out, long diffIn, long diffOut) {
27 | List totalTraffic = getTotalTraffic(diffIn, diffOut);
28 |
29 | Intent traffic = new Intent();
30 | traffic.setAction(TRAFFIC_ACTION);
31 | traffic.putExtra(DOWNLOAD_ALL, totalTraffic.get(0));
32 | traffic.putExtra(DOWNLOAD_SESSION, OpenVPNService.humanReadableByteCount(in, false));
33 | traffic.putExtra(UPLOAD_ALL, totalTraffic.get(1));
34 | traffic.putExtra(UPLOAD_SESSION, OpenVPNService.humanReadableByteCount(out, false));
35 |
36 | context.sendBroadcast(traffic);
37 | }
38 |
39 | public static List getTotalTraffic() {
40 | return getTotalTraffic(0, 0);
41 | }
42 |
43 | public static List getTotalTraffic(long in, long out) {
44 | List totalTraffic = new ArrayList();
45 |
46 | if (inTotal == 0)
47 | inTotal = PropertiesService.getDownloaded();
48 |
49 | if (outTotal == 0)
50 | outTotal = PropertiesService.getUploaded();
51 |
52 | inTotal = inTotal + in;
53 | outTotal = outTotal + out;
54 |
55 | totalTraffic.add(OpenVPNService.humanReadableByteCount(inTotal, false));
56 | totalTraffic.add(OpenVPNService.humanReadableByteCount(outTotal, false));
57 |
58 | return totalTraffic;
59 | }
60 |
61 | public static void saveTotal() {
62 | if (inTotal != 0)
63 | PropertiesService.setDownloaded(inTotal);
64 |
65 | if (outTotal != 0)
66 | PropertiesService.setUploaded(outTotal);
67 | }
68 |
69 | }
70 |
--------------------------------------------------------------------------------
/app/src/main/java/com/frogobox/viprox/util/dns/HttpDownloadTest.java:
--------------------------------------------------------------------------------
1 | package com.frogobox.viprox.util.dns;
2 |
3 | import java.io.InputStream;
4 | import java.math.BigDecimal;
5 | import java.math.RoundingMode;
6 | import java.net.HttpURLConnection;
7 | import java.net.URL;
8 | import java.util.ArrayList;
9 | import java.util.List;
10 |
11 | public class HttpDownloadTest extends Thread {
12 |
13 | public String fileURL = "";
14 | long startTime = 0;
15 | long endTime = 0;
16 | double downloadElapsedTime = 0;
17 | int downloadedByte = 0;
18 | double finalDownloadRate = 0.0;
19 | boolean finished = false;
20 | double instantDownloadRate = 0;
21 | int timeout = 15;
22 |
23 | HttpURLConnection httpConn = null;
24 |
25 | public HttpDownloadTest(String fileURL) {
26 | this.fileURL = fileURL;
27 | }
28 |
29 | private double round(double value, int places) {
30 | if (places < 0) throw new IllegalArgumentException();
31 |
32 | BigDecimal bd;
33 | try {
34 | bd = new BigDecimal(value);
35 | } catch (Exception ex) {
36 | return 0.0;
37 | }
38 | bd = bd.setScale(places, RoundingMode.HALF_UP);
39 | return bd.doubleValue();
40 | }
41 |
42 | public double getInstantDownloadRate() {
43 | return instantDownloadRate;
44 | }
45 |
46 | public void setInstantDownloadRate(int downloadedByte, double elapsedTime) {
47 |
48 | if (downloadedByte >= 0) {
49 | this.instantDownloadRate = round((Double) (((downloadedByte * 8) / (1000 * 1000)) / elapsedTime), 2);
50 | } else {
51 | this.instantDownloadRate = 0.0;
52 | }
53 | }
54 |
55 | public double getFinalDownloadRate() {
56 | return round(finalDownloadRate, 2);
57 | }
58 |
59 | public boolean isFinished() {
60 | return finished;
61 | }
62 |
63 | @Override
64 | public void run() {
65 | URL url = null;
66 | downloadedByte = 0;
67 | int responseCode = 0;
68 |
69 | List fileUrls = new ArrayList<>();
70 | fileUrls.add(fileURL + "random4000x4000.jpg");
71 | fileUrls.add(fileURL + "random3000x3000.jpg");
72 |
73 | startTime = System.currentTimeMillis();
74 |
75 | outer:
76 | for (String link : fileUrls) {
77 | try {
78 | url = new URL(link);
79 | httpConn = (HttpURLConnection) url.openConnection();
80 | responseCode = httpConn.getResponseCode();
81 | } catch (Exception ex) {
82 | ex.printStackTrace();
83 | }
84 |
85 | try {
86 | if (responseCode == HttpURLConnection.HTTP_OK) {
87 | byte[] buffer = new byte[10240];
88 |
89 | InputStream inputStream = httpConn.getInputStream();
90 | int len = 0;
91 |
92 | while ((len = inputStream.read(buffer)) != -1) {
93 | downloadedByte += len;
94 | endTime = System.currentTimeMillis();
95 | downloadElapsedTime = (endTime - startTime) / 1000.0;
96 | setInstantDownloadRate(downloadedByte, downloadElapsedTime);
97 | if (downloadElapsedTime >= timeout) {
98 | break outer;
99 | }
100 | }
101 |
102 | inputStream.close();
103 | httpConn.disconnect();
104 | } else {
105 | System.out.println("Link not found...");
106 | }
107 | } catch (Exception ex) {
108 | ex.printStackTrace();
109 | }
110 | }
111 |
112 | endTime = System.currentTimeMillis();
113 | downloadElapsedTime = (endTime - startTime) / 1000.0;
114 | finalDownloadRate = ((downloadedByte * 8) / (1000 * 1000.0)) / downloadElapsedTime;
115 |
116 | finished = true;
117 | }
118 |
119 | }
--------------------------------------------------------------------------------
/app/src/main/java/com/frogobox/viprox/util/dns/HttpUploadTest.java:
--------------------------------------------------------------------------------
1 | package com.frogobox.viprox.util.dns;
2 |
3 | import static com.frogobox.viprox.util.dns.HttpUploadTest.uploadedKByte;
4 |
5 | import java.io.DataOutputStream;
6 | import java.math.BigDecimal;
7 | import java.math.RoundingMode;
8 | import java.net.HttpURLConnection;
9 | import java.net.URL;
10 | import java.util.concurrent.ExecutorService;
11 | import java.util.concurrent.Executors;
12 |
13 | public class HttpUploadTest extends Thread {
14 |
15 | public String fileURL = "";
16 | static int uploadedKByte = 0;
17 | double uploadElapsedTime = 0;
18 | boolean finished = false;
19 | double elapsedTime = 0;
20 | double finalUploadRate = 0.0;
21 | long startTime;
22 |
23 | public HttpUploadTest(String fileURL) {
24 | this.fileURL = fileURL;
25 | }
26 |
27 | private double round(double value, int places) {
28 | if (places < 0) throw new IllegalArgumentException();
29 |
30 | BigDecimal bd;
31 | try {
32 | bd = new BigDecimal(value);
33 | } catch (Exception ex) {
34 | return 0.0;
35 | }
36 | bd = bd.setScale(places, RoundingMode.HALF_UP);
37 | return bd.doubleValue();
38 | }
39 |
40 | public boolean isFinished() {
41 | return finished;
42 | }
43 |
44 | public double getInstantUploadRate() {
45 | try {
46 | BigDecimal bd = new BigDecimal(uploadedKByte);
47 | } catch (Exception ex) {
48 | return 0.0;
49 | }
50 |
51 | if (uploadedKByte >= 0) {
52 | long now = System.currentTimeMillis();
53 | elapsedTime = (now - startTime) / 1000.0;
54 | return round((Double) (((uploadedKByte / 1000.0) * 8) / elapsedTime), 2);
55 | } else {
56 | return 0.0;
57 | }
58 | }
59 |
60 | public double getFinalUploadRate() {
61 | return round(finalUploadRate, 2);
62 | }
63 |
64 | @Override
65 | public void run() {
66 | try {
67 | URL url = new URL(fileURL);
68 | uploadedKByte = 0;
69 | startTime = System.currentTimeMillis();
70 |
71 | ExecutorService executor = Executors.newFixedThreadPool(4);
72 | for (int i = 0; i < 4; i++) {
73 | executor.execute(new HandlerUpload(url));
74 | }
75 | executor.shutdown();
76 | while (!executor.isTerminated()) {
77 | try {
78 | Thread.sleep(100);
79 | } catch (InterruptedException ex) {
80 | }
81 | }
82 |
83 | long now = System.currentTimeMillis();
84 | uploadElapsedTime = (now - startTime) / 1000.0;
85 | finalUploadRate = (Double) (((uploadedKByte / 1000.0) * 8) / uploadElapsedTime);
86 |
87 | } catch (Exception ex) {
88 | ex.printStackTrace();
89 | }
90 |
91 | finished = true;
92 | }
93 | }
94 |
95 | class HandlerUpload extends Thread {
96 |
97 | URL url;
98 |
99 | public HandlerUpload(URL url) {
100 | this.url = url;
101 | }
102 |
103 | public void run() {
104 | byte[] buffer = new byte[150 * 1024];
105 | long startTime = System.currentTimeMillis();
106 | int timeout = 10;
107 |
108 | while (true) {
109 |
110 | try {
111 | HttpURLConnection conn = null;
112 | conn = (HttpURLConnection) url.openConnection();
113 | conn.setDoOutput(true);
114 | conn.setRequestMethod("POST");
115 | conn.setRequestProperty("Connection", "Keep-Alive");
116 |
117 | DataOutputStream dos = new DataOutputStream(conn.getOutputStream());
118 |
119 |
120 | dos.write(buffer, 0, buffer.length);
121 | dos.flush();
122 |
123 | conn.getResponseCode();
124 |
125 | uploadedKByte += buffer.length / 1024.0;
126 | long endTime = System.currentTimeMillis();
127 | double uploadElapsedTime = (endTime - startTime) / 1000.0;
128 | if (uploadElapsedTime >= timeout) {
129 | break;
130 | }
131 |
132 | dos.close();
133 | conn.disconnect();
134 | } catch (Exception ex) {
135 | ex.printStackTrace();
136 | }
137 | }
138 | }
139 | }
--------------------------------------------------------------------------------
/app/src/main/java/com/frogobox/viprox/util/dns/PingTest.java:
--------------------------------------------------------------------------------
1 | package com.frogobox.viprox.util.dns;
2 |
3 | import java.io.BufferedReader;
4 | import java.io.InputStreamReader;
5 | import java.util.HashMap;
6 |
7 | public class PingTest extends Thread {
8 |
9 | HashMap result = new HashMap<>();
10 | String server = "";
11 | int count;
12 | double instantRtt = 0;
13 | double avgRtt = 0.0;
14 | boolean finished = false;
15 | boolean started = false;
16 |
17 | public PingTest(String serverIpAddress, int pingTryCount) {
18 | this.server = serverIpAddress;
19 | this.count = pingTryCount;
20 | }
21 |
22 | public double getAvgRtt() {
23 | return avgRtt;
24 | }
25 |
26 | public double getInstantRtt() {
27 | return instantRtt;
28 | }
29 |
30 | public boolean isFinished() {
31 | return finished;
32 | }
33 |
34 | @Override
35 | public void run() {
36 | try {
37 | ProcessBuilder ps = new ProcessBuilder("ping", "-c " + count, this.server);
38 |
39 | ps.redirectErrorStream(true);
40 | Process pr = ps.start();
41 |
42 | BufferedReader in = new BufferedReader(new InputStreamReader(pr.getInputStream()));
43 | String line;
44 | String output = "";
45 | while ((line = in.readLine()) != null) {
46 | if (line.contains("icmp_seq")) {
47 | instantRtt = Double.parseDouble(line.split(" ")[line.split(" ").length - 2].replace("time=", ""));
48 | }
49 | if (line.startsWith("rtt ")) {
50 | avgRtt = Double.parseDouble(line.split("/")[4]);
51 | break;
52 | }
53 | }
54 | pr.waitFor();
55 | in.close();
56 |
57 | } catch (Exception e) {
58 | e.printStackTrace();
59 | }
60 |
61 | finished = true;
62 | }
63 |
64 | }
--------------------------------------------------------------------------------
/app/src/main/java/com/frogobox/viprox/util/encoders/Base64.java:
--------------------------------------------------------------------------------
1 |
2 |
3 | package com.frogobox.viprox.util.encoders;
4 |
5 | import java.io.ByteArrayOutputStream;
6 | import java.io.IOException;
7 | import java.io.OutputStream;
8 |
9 | public class Base64
10 | {
11 | private static final Encoder encoder = new Base64Encoder();
12 |
13 |
14 | public static byte[] encode(
15 | byte[] data)
16 | {
17 | int len = (data.length + 2) / 3 * 4;
18 | ByteArrayOutputStream bOut = new ByteArrayOutputStream(len);
19 |
20 | try
21 | {
22 | encoder.encode(data, 0, data.length, bOut);
23 | }
24 | catch (IOException e)
25 | {
26 | throw new RuntimeException("exception encoding base64 string: " + e);
27 | }
28 |
29 | return bOut.toByteArray();
30 | }
31 |
32 |
33 | public static int encode(
34 | byte[] data,
35 | OutputStream out)
36 | throws IOException
37 | {
38 | return encoder.encode(data, 0, data.length, out);
39 | }
40 |
41 |
42 | public static int encode(
43 | byte[] data,
44 | int off,
45 | int length,
46 | OutputStream out)
47 | throws IOException
48 | {
49 | return encoder.encode(data, off, length, out);
50 | }
51 |
52 |
53 | public static byte[] decode(
54 | byte[] data)
55 | {
56 | int len = data.length / 4 * 3;
57 | ByteArrayOutputStream bOut = new ByteArrayOutputStream(len);
58 |
59 | try
60 | {
61 | encoder.decode(data, 0, data.length, bOut);
62 | }
63 | catch (IOException e)
64 | {
65 | throw new RuntimeException("exception decoding base64 string: " + e);
66 | }
67 |
68 | return bOut.toByteArray();
69 | }
70 |
71 |
72 | public static byte[] decode(
73 | String data)
74 | {
75 | int len = data.length() / 4 * 3;
76 | ByteArrayOutputStream bOut = new ByteArrayOutputStream(len);
77 |
78 | try
79 | {
80 | encoder.decode(data, bOut);
81 | }
82 | catch (IOException e)
83 | {
84 | throw new RuntimeException("exception decoding base64 string: " + e);
85 | }
86 |
87 | return bOut.toByteArray();
88 | }
89 |
90 |
91 | public static int decode(
92 | String data,
93 | OutputStream out)
94 | throws IOException
95 | {
96 | return encoder.decode(data, out);
97 | }
98 | }
99 |
--------------------------------------------------------------------------------
/app/src/main/java/com/frogobox/viprox/util/encoders/Base64Encoder.java:
--------------------------------------------------------------------------------
1 |
2 |
3 | package com.frogobox.viprox.util.encoders;
4 |
5 | import java.io.IOException;
6 | import java.io.OutputStream;
7 |
8 | public class Base64Encoder
9 | implements Encoder
10 | {
11 | protected final byte[] encodingTable =
12 | {
13 | (byte)'A', (byte)'B', (byte)'C', (byte)'D', (byte)'E', (byte)'F', (byte)'G',
14 | (byte)'H', (byte)'I', (byte)'J', (byte)'K', (byte)'L', (byte)'M', (byte)'N',
15 | (byte)'O', (byte)'P', (byte)'Q', (byte)'R', (byte)'S', (byte)'T', (byte)'U',
16 | (byte)'V', (byte)'W', (byte)'X', (byte)'Y', (byte)'Z',
17 | (byte)'a', (byte)'b', (byte)'c', (byte)'d', (byte)'e', (byte)'f', (byte)'g',
18 | (byte)'h', (byte)'i', (byte)'j', (byte)'k', (byte)'l', (byte)'m', (byte)'n',
19 | (byte)'o', (byte)'p', (byte)'q', (byte)'r', (byte)'s', (byte)'t', (byte)'u',
20 | (byte)'v',
21 | (byte)'w', (byte)'x', (byte)'y', (byte)'z',
22 | (byte)'0', (byte)'1', (byte)'2', (byte)'3', (byte)'4', (byte)'5', (byte)'6',
23 | (byte)'7', (byte)'8', (byte)'9',
24 | (byte)'+', (byte)'/'
25 | };
26 |
27 | protected byte padding = (byte)'=';
28 |
29 |
30 | protected final byte[] decodingTable = new byte[128];
31 |
32 | protected void initialiseDecodingTable()
33 | {
34 | for (int i = 0; i < encodingTable.length; i++)
35 | {
36 | decodingTable[encodingTable[i]] = (byte)i;
37 | }
38 | }
39 |
40 | public Base64Encoder()
41 | {
42 | initialiseDecodingTable();
43 | }
44 |
45 |
46 | public int encode(
47 | byte[] data,
48 | int off,
49 | int length,
50 | OutputStream out)
51 | throws IOException
52 | {
53 | int modulus = length % 3;
54 | int dataLength = (length - modulus);
55 | int a1, a2, a3;
56 |
57 | for (int i = off; i < off + dataLength; i += 3)
58 | {
59 | a1 = data[i] & 0xff;
60 | a2 = data[i + 1] & 0xff;
61 | a3 = data[i + 2] & 0xff;
62 |
63 | out.write(encodingTable[(a1 >>> 2) & 0x3f]);
64 | out.write(encodingTable[((a1 << 4) | (a2 >>> 4)) & 0x3f]);
65 | out.write(encodingTable[((a2 << 2) | (a3 >>> 6)) & 0x3f]);
66 | out.write(encodingTable[a3 & 0x3f]);
67 | }
68 |
69 |
70 | int b1, b2, b3;
71 | int d1, d2;
72 |
73 | switch (modulus)
74 | {
75 | case 0:
76 | break;
77 | case 1:
78 | d1 = data[off + dataLength] & 0xff;
79 | b1 = (d1 >>> 2) & 0x3f;
80 | b2 = (d1 << 4) & 0x3f;
81 |
82 | out.write(encodingTable[b1]);
83 | out.write(encodingTable[b2]);
84 | out.write(padding);
85 | out.write(padding);
86 | break;
87 | case 2:
88 | d1 = data[off + dataLength] & 0xff;
89 | d2 = data[off + dataLength + 1] & 0xff;
90 |
91 | b1 = (d1 >>> 2) & 0x3f;
92 | b2 = ((d1 << 4) | (d2 >>> 4)) & 0x3f;
93 | b3 = (d2 << 2) & 0x3f;
94 |
95 | out.write(encodingTable[b1]);
96 | out.write(encodingTable[b2]);
97 | out.write(encodingTable[b3]);
98 | out.write(padding);
99 | break;
100 | }
101 |
102 | return (dataLength / 3) * 4 + ((modulus == 0) ? 0 : 4);
103 | }
104 |
105 | private boolean ignore(
106 | char c)
107 | {
108 | return (c == '\n' || c =='\r' || c == '\t' || c == ' ');
109 | }
110 |
111 |
112 | public int decode(
113 | byte[] data,
114 | int off,
115 | int length,
116 | OutputStream out)
117 | throws IOException
118 | {
119 | byte b1, b2, b3, b4;
120 | int outLen = 0;
121 |
122 | int end = off + length;
123 |
124 | while (end > off)
125 | {
126 | if (!ignore((char)data[end - 1]))
127 | {
128 | break;
129 | }
130 |
131 | end--;
132 | }
133 |
134 | int i = off;
135 | int finish = end - 4;
136 |
137 | i = nextI(data, i, finish);
138 |
139 | while (i < finish)
140 | {
141 | b1 = decodingTable[data[i++]];
142 |
143 | i = nextI(data, i, finish);
144 |
145 | b2 = decodingTable[data[i++]];
146 |
147 | i = nextI(data, i, finish);
148 |
149 | b3 = decodingTable[data[i++]];
150 |
151 | i = nextI(data, i, finish);
152 |
153 | b4 = decodingTable[data[i++]];
154 |
155 | out.write((b1 << 2) | (b2 >> 4));
156 | out.write((b2 << 4) | (b3 >> 2));
157 | out.write((b3 << 6) | b4);
158 |
159 | outLen += 3;
160 |
161 | i = nextI(data, i, finish);
162 | }
163 |
164 | outLen += decodeLastBlock(out, (char)data[end - 4], (char)data[end - 3], (char)data[end - 2], (char)data[end - 1]);
165 |
166 | return outLen;
167 | }
168 |
169 | private int nextI(byte[] data, int i, int finish)
170 | {
171 | while ((i < finish) && ignore((char)data[i]))
172 | {
173 | i++;
174 | }
175 | return i;
176 | }
177 |
178 |
179 | public int decode(
180 | String data,
181 | OutputStream out)
182 | throws IOException
183 | {
184 | byte b1, b2, b3, b4;
185 | int length = 0;
186 |
187 | int end = data.length();
188 |
189 | while (end > 0)
190 | {
191 | if (!ignore(data.charAt(end - 1)))
192 | {
193 | break;
194 | }
195 |
196 | end--;
197 | }
198 |
199 | int i = 0;
200 | int finish = end - 4;
201 |
202 | i = nextI(data, i, finish);
203 |
204 | while (i < finish)
205 | {
206 | b1 = decodingTable[data.charAt(i++)];
207 |
208 | i = nextI(data, i, finish);
209 |
210 | b2 = decodingTable[data.charAt(i++)];
211 |
212 | i = nextI(data, i, finish);
213 |
214 | b3 = decodingTable[data.charAt(i++)];
215 |
216 | i = nextI(data, i, finish);
217 |
218 | b4 = decodingTable[data.charAt(i++)];
219 |
220 | out.write((b1 << 2) | (b2 >> 4));
221 | out.write((b2 << 4) | (b3 >> 2));
222 | out.write((b3 << 6) | b4);
223 |
224 | length += 3;
225 |
226 | i = nextI(data, i, finish);
227 | }
228 |
229 | length += decodeLastBlock(out, data.charAt(end - 4), data.charAt(end - 3), data.charAt(end - 2), data.charAt(end - 1));
230 |
231 | return length;
232 | }
233 |
234 | private int decodeLastBlock(OutputStream out, char c1, char c2, char c3, char c4)
235 | throws IOException
236 | {
237 | byte b1, b2, b3, b4;
238 |
239 | if (c3 == padding)
240 | {
241 | b1 = decodingTable[c1];
242 | b2 = decodingTable[c2];
243 |
244 | out.write((b1 << 2) | (b2 >> 4));
245 |
246 | return 1;
247 | }
248 | else if (c4 == padding)
249 | {
250 | b1 = decodingTable[c1];
251 | b2 = decodingTable[c2];
252 | b3 = decodingTable[c3];
253 |
254 | out.write((b1 << 2) | (b2 >> 4));
255 | out.write((b2 << 4) | (b3 >> 2));
256 |
257 | return 2;
258 | }
259 | else
260 | {
261 | b1 = decodingTable[c1];
262 | b2 = decodingTable[c2];
263 | b3 = decodingTable[c3];
264 | b4 = decodingTable[c4];
265 |
266 | out.write((b1 << 2) | (b2 >> 4));
267 | out.write((b2 << 4) | (b3 >> 2));
268 | out.write((b3 << 6) | b4);
269 |
270 | return 3;
271 | }
272 | }
273 |
274 | private int nextI(String data, int i, int finish)
275 | {
276 | while ((i < finish) && ignore(data.charAt(i)))
277 | {
278 | i++;
279 | }
280 | return i;
281 | }
282 | }
283 |
--------------------------------------------------------------------------------
/app/src/main/java/com/frogobox/viprox/util/encoders/Encoder.java:
--------------------------------------------------------------------------------
1 |
2 |
3 | package com.frogobox.viprox.util.encoders;
4 |
5 | import java.io.IOException;
6 | import java.io.OutputStream;
7 |
8 |
9 | public interface Encoder
10 | {
11 | int encode(byte[] data, int off, int length, OutputStream out) throws IOException;
12 |
13 | int decode(byte[] data, int off, int length, OutputStream out) throws IOException;
14 |
15 | int decode(String data, OutputStream out) throws IOException;
16 | }
17 |
--------------------------------------------------------------------------------
/app/src/main/java/com/frogobox/viprox/util/io/pem/PemGenerationException.java:
--------------------------------------------------------------------------------
1 |
2 |
3 | package com.frogobox.viprox.util.io.pem;
4 |
5 | import java.io.IOException;
6 |
7 | @SuppressWarnings("serial")
8 | public class PemGenerationException
9 | extends IOException
10 | {
11 | private Throwable cause;
12 |
13 | public PemGenerationException(String message, Throwable cause)
14 | {
15 | super(message);
16 | this.cause = cause;
17 | }
18 |
19 | public PemGenerationException(String message)
20 | {
21 | super(message);
22 | }
23 |
24 | public Throwable getCause()
25 | {
26 | return cause;
27 | }
28 | }
29 |
--------------------------------------------------------------------------------
/app/src/main/java/com/frogobox/viprox/util/io/pem/PemHeader.java:
--------------------------------------------------------------------------------
1 |
2 |
3 | package com.frogobox.viprox.util.io.pem;
4 |
5 | public class PemHeader
6 | {
7 | private String name;
8 | private String value;
9 |
10 | public PemHeader(String name, String value)
11 | {
12 | this.name = name;
13 | this.value = value;
14 | }
15 |
16 | public String getName()
17 | {
18 | return name;
19 | }
20 |
21 | public String getValue()
22 | {
23 | return value;
24 | }
25 |
26 | public int hashCode()
27 | {
28 | return getHashCode(this.name) + 31 * getHashCode(this.value);
29 | }
30 |
31 | public boolean equals(Object o)
32 | {
33 | if (!(o instanceof PemHeader))
34 | {
35 | return false;
36 | }
37 |
38 | PemHeader other = (PemHeader)o;
39 |
40 | return other == this || (isEqual(this.name, other.name) && isEqual(this.value, other.value));
41 | }
42 |
43 | private int getHashCode(String s)
44 | {
45 | if (s == null)
46 | {
47 | return 1;
48 | }
49 |
50 | return s.hashCode();
51 | }
52 |
53 | private boolean isEqual(String s1, String s2)
54 | {
55 | if (s1 == s2)
56 | {
57 | return true;
58 | }
59 |
60 | if (s1 == null || s2 == null)
61 | {
62 | return false;
63 | }
64 |
65 | return s1.equals(s2);
66 | }
67 |
68 | }
69 |
--------------------------------------------------------------------------------
/app/src/main/java/com/frogobox/viprox/util/io/pem/PemObject.java:
--------------------------------------------------------------------------------
1 |
2 |
3 | package com.frogobox.viprox.util.io.pem;
4 |
5 | import java.util.ArrayList;
6 | import java.util.Collections;
7 | import java.util.List;
8 |
9 | @SuppressWarnings("all")
10 | public class PemObject
11 | implements PemObjectGenerator
12 | {
13 | private static final List EMPTY_LIST = Collections.unmodifiableList(new ArrayList());
14 |
15 | private String type;
16 | private List headers;
17 | private byte[] content;
18 |
19 |
20 | public PemObject(String type, byte[] content)
21 | {
22 | this(type, EMPTY_LIST, content);
23 | }
24 |
25 |
26 | public PemObject(String type, List headers, byte[] content)
27 | {
28 | this.type = type;
29 | this.headers = Collections.unmodifiableList(headers);
30 | this.content = content;
31 | }
32 |
33 | public String getType()
34 | {
35 | return type;
36 | }
37 |
38 | public List getHeaders()
39 | {
40 | return headers;
41 | }
42 |
43 | public byte[] getContent()
44 | {
45 | return content;
46 | }
47 |
48 | public PemObject generate()
49 | throws PemGenerationException
50 | {
51 | return this;
52 | }
53 | }
54 |
--------------------------------------------------------------------------------
/app/src/main/java/com/frogobox/viprox/util/io/pem/PemObjectGenerator.java:
--------------------------------------------------------------------------------
1 |
2 |
3 | package com.frogobox.viprox.util.io.pem;
4 |
5 | public interface PemObjectGenerator
6 | {
7 | PemObject generate()
8 | throws PemGenerationException;
9 | }
10 |
--------------------------------------------------------------------------------
/app/src/main/java/com/frogobox/viprox/util/io/pem/PemReader.java:
--------------------------------------------------------------------------------
1 |
2 |
3 | package com.frogobox.viprox.util.io.pem;
4 |
5 | import java.io.BufferedReader;
6 | import java.io.IOException;
7 | import java.io.Reader;
8 | import java.util.ArrayList;
9 | import java.util.List;
10 |
11 | import com.frogobox.viprox.util.encoders.Base64;
12 |
13 | public class PemReader
14 | extends BufferedReader
15 | {
16 | private static final String BEGIN = "-----BEGIN ";
17 | private static final String END = "-----END ";
18 |
19 | public PemReader(Reader reader)
20 | {
21 | super(reader);
22 | }
23 |
24 | public PemObject readPemObject()
25 | throws IOException
26 | {
27 | String line = readLine();
28 |
29 | while (line != null && !line.startsWith(BEGIN))
30 | {
31 | line = readLine();
32 | }
33 |
34 | if (line != null)
35 | {
36 | line = line.substring(BEGIN.length());
37 | int index = line.indexOf('-');
38 | String type = line.substring(0, index);
39 |
40 | if (index > 0)
41 | {
42 | return loadObject(type);
43 | }
44 | }
45 |
46 | return null;
47 | }
48 |
49 | private PemObject loadObject(String type)
50 | throws IOException
51 | {
52 | String line;
53 | String endMarker = END + type;
54 | StringBuilder buf = new StringBuilder();
55 | List headers = new ArrayList();
56 |
57 | while ((line = readLine()) != null)
58 | {
59 | if (line.indexOf(":") >= 0)
60 | {
61 | int index = line.indexOf(':');
62 | String hdr = line.substring(0, index);
63 | String value = line.substring(index + 1).trim();
64 |
65 | headers.add(new PemHeader(hdr, value));
66 |
67 | continue;
68 | }
69 |
70 | if (line.indexOf(endMarker) != -1)
71 | {
72 | break;
73 | }
74 |
75 | buf.append(line.trim());
76 | }
77 |
78 | if (line == null)
79 | {
80 | throw new IOException(endMarker + " not found");
81 | }
82 |
83 | return new PemObject(type, headers, Base64.decode(buf.toString()));
84 | }
85 |
86 | }
87 |
--------------------------------------------------------------------------------
/app/src/main/java/com/frogobox/viprox/util/io/pem/PemWriter.java:
--------------------------------------------------------------------------------
1 |
2 |
3 | package com.frogobox.viprox.util.io.pem;
4 |
5 | import java.io.BufferedWriter;
6 | import java.io.IOException;
7 | import java.io.Writer;
8 | import java.util.Iterator;
9 |
10 | import com.frogobox.viprox.util.encoders.Base64;
11 |
12 |
13 | @SuppressWarnings("all")
14 | public class PemWriter
15 | extends BufferedWriter
16 | {
17 | private static final int LINE_LENGTH = 64;
18 |
19 | private final int nlLength;
20 | private char[] buf = new char[LINE_LENGTH];
21 |
22 |
23 | public PemWriter(Writer out)
24 | {
25 | super(out);
26 |
27 | String nl = System.getProperty("line.separator");
28 | if (nl != null)
29 | {
30 | nlLength = nl.length();
31 | }
32 | else
33 | {
34 | nlLength = 2;
35 | }
36 | }
37 |
38 |
39 | public int getOutputSize(PemObject obj)
40 | {
41 |
42 | int size = (2 * (obj.getType().length() + 10 + nlLength)) + 6 + 4;
43 |
44 | if (!obj.getHeaders().isEmpty())
45 | {
46 | for (Iterator it = obj.getHeaders().iterator(); it.hasNext();)
47 | {
48 | PemHeader hdr = (PemHeader)it.next();
49 |
50 | size += hdr.getName().length() + ": ".length() + hdr.getValue().length() + nlLength;
51 | }
52 |
53 | size += nlLength;
54 | }
55 |
56 |
57 | int dataLen = ((obj.getContent().length + 2) / 3) * 4;
58 |
59 | size += dataLen + (((dataLen + LINE_LENGTH - 1) / LINE_LENGTH) * nlLength);
60 |
61 | return size;
62 | }
63 |
64 | public void writeObject(PemObjectGenerator objGen)
65 | throws IOException
66 | {
67 | PemObject obj = objGen.generate();
68 |
69 | writePreEncapsulationBoundary(obj.getType());
70 |
71 | if (!obj.getHeaders().isEmpty())
72 | {
73 | for (Iterator it = obj.getHeaders().iterator(); it.hasNext();)
74 | {
75 | PemHeader hdr = (PemHeader)it.next();
76 |
77 | this.write(hdr.getName());
78 | this.write(": ");
79 | this.write(hdr.getValue());
80 | this.newLine();
81 | }
82 |
83 | this.newLine();
84 | }
85 |
86 | writeEncoded(obj.getContent());
87 | writePostEncapsulationBoundary(obj.getType());
88 | }
89 |
90 | private void writeEncoded(byte[] bytes)
91 | throws IOException
92 | {
93 | bytes = Base64.encode(bytes);
94 |
95 | for (int i = 0; i < bytes.length; i += buf.length)
96 | {
97 | int index = 0;
98 |
99 | while (index != buf.length)
100 | {
101 | if ((i + index) >= bytes.length)
102 | {
103 | break;
104 | }
105 | buf[index] = (char)bytes[i + index];
106 | index++;
107 | }
108 | this.write(buf, 0, index);
109 | this.newLine();
110 | }
111 | }
112 |
113 | private void writePreEncapsulationBoundary(
114 | String type)
115 | throws IOException
116 | {
117 | this.write("-----BEGIN " + type + "-----");
118 | this.newLine();
119 | }
120 |
121 | private void writePostEncapsulationBoundary(
122 | String type)
123 | throws IOException
124 | {
125 | this.write("-----END " + type + "-----");
126 | this.newLine();
127 | }
128 | }
129 |
--------------------------------------------------------------------------------
/app/src/main/java/de/blinkt/openvpn/core/CIDRIP.java:
--------------------------------------------------------------------------------
1 | package de.blinkt.openvpn.core;
2 |
3 | import java.util.Locale;
4 |
5 | class CIDRIP {
6 |
7 | String mIp;
8 | int len;
9 |
10 | public CIDRIP(String ip, String mask) {
11 | mIp = ip;
12 | long netmask = getInt(mask);
13 |
14 | netmask += 1l << 32;
15 |
16 | int lenZeros = 0;
17 | while ((netmask & 0x1) == 0) {
18 | lenZeros++;
19 | netmask = netmask >> 1;
20 | }
21 |
22 | if (netmask != (0x1ffffffffl >> lenZeros)) {
23 |
24 | len = 32;
25 | } else {
26 | len = 32 - lenZeros;
27 | }
28 |
29 | }
30 |
31 | public CIDRIP(String address, int prefix_length) {
32 | len = prefix_length;
33 | mIp = address;
34 | }
35 |
36 | static long getInt(String ipaddr) {
37 | String[] ipt = ipaddr.split("\\.");
38 | long ip = 0;
39 |
40 | ip += Long.parseLong(ipt[0]) << 24;
41 | ip += Integer.parseInt(ipt[1]) << 16;
42 | ip += Integer.parseInt(ipt[2]) << 8;
43 | ip += Integer.parseInt(ipt[3]);
44 |
45 | return ip;
46 | }
47 |
48 | @Override
49 | public String toString() {
50 | return String.format(Locale.ENGLISH, "%s/%d", mIp, len);
51 | }
52 |
53 | public boolean normalise() {
54 | long ip = getInt(mIp);
55 |
56 | long newip = ip & (0xffffffffl << (32 - len));
57 | if (newip != ip) {
58 | mIp = String.format("%d.%d.%d.%d", (newip & 0xff000000) >> 24, (newip & 0xff0000) >> 16, (newip & 0xff00) >> 8, newip & 0xff);
59 | return true;
60 | } else {
61 | return false;
62 | }
63 |
64 | }
65 |
66 | public long getInt() {
67 | return getInt(mIp);
68 | }
69 |
70 | }
--------------------------------------------------------------------------------
/app/src/main/java/de/blinkt/openvpn/core/Connection.java:
--------------------------------------------------------------------------------
1 | package de.blinkt.openvpn.core;
2 |
3 | import android.text.TextUtils;
4 |
5 | import java.io.Serializable;
6 |
7 | public class Connection implements Serializable, Cloneable {
8 | public static final int CONNECTION_DEFAULT_TIMEOUT = 120;
9 | private static final long serialVersionUID = 92031902903829089L;
10 | public String mServerName = "de.blinkt.openvpn";
11 | public String mServerPort = "1194";
12 | public boolean mUseUdp = true;
13 | public String mCustomConfiguration = "";
14 | public boolean mUseCustomConfig = false;
15 | public boolean mEnabled = true;
16 | public int mConnectTimeout = 0;
17 |
18 | public String getConnectionBlock() {
19 | String cfg = "";
20 | cfg += "remote ";
21 | cfg += mServerName;
22 | cfg += " ";
23 | cfg += mServerPort;
24 | if (mUseUdp)
25 | cfg += " udp\n";
26 | else
27 | cfg += " tcp-client\n";
28 |
29 | if (mConnectTimeout != 0)
30 | cfg += String.format(" connect-timeout %d\n", mConnectTimeout);
31 |
32 |
33 | if (!TextUtils.isEmpty(mCustomConfiguration) && mUseCustomConfig) {
34 | cfg += mCustomConfiguration;
35 | cfg += "\n";
36 | }
37 | return cfg;
38 | }
39 |
40 | @Override
41 | public Connection clone() throws CloneNotSupportedException {
42 | return (Connection) super.clone();
43 | }
44 |
45 | public boolean isOnlyRemote() {
46 | return TextUtils.isEmpty(mCustomConfiguration) || !mUseCustomConfig;
47 | }
48 |
49 | public int getTimeout() {
50 | if (mConnectTimeout <= 0)
51 | return CONNECTION_DEFAULT_TIMEOUT;
52 | else
53 | return mConnectTimeout;
54 | }
55 | }
56 |
--------------------------------------------------------------------------------
/app/src/main/java/de/blinkt/openvpn/core/LogFileHandler.java:
--------------------------------------------------------------------------------
1 | package de.blinkt.openvpn.core;
2 |
3 | import android.os.Handler;
4 | import android.os.Looper;
5 | import android.os.Message;
6 |
7 | import com.frogobox.viprox.R;
8 |
9 | import java.io.BufferedInputStream;
10 | import java.io.File;
11 | import java.io.FileInputStream;
12 | import java.io.FileNotFoundException;
13 | import java.io.FileOutputStream;
14 | import java.io.IOException;
15 | import java.io.InputStream;
16 | import java.io.OutputStream;
17 | import java.io.UnsupportedEncodingException;
18 | import java.nio.BufferOverflowException;
19 | import java.nio.ByteBuffer;
20 | import java.util.Locale;
21 |
22 | class LogFileHandler extends Handler {
23 | public static final int LOG_MESSAGE = 103;
24 | public static final int MAGIC_BYTE = 0x55;
25 | public static final String LOGFILE_NAME = "logcache.dat";
26 | final protected static char[] hexArray = "0123456789ABCDEF".toCharArray();
27 | static final int TRIM_LOG_FILE = 100;
28 | static final int FLUSH_TO_DISK = 101;
29 | static final int LOG_INIT = 102;
30 | protected OutputStream mLogFile;
31 |
32 |
33 | public LogFileHandler(Looper looper) {
34 | super(looper);
35 | }
36 |
37 | public static String bytesToHex(byte[] bytes, int len) {
38 | len = Math.min(bytes.length, len);
39 | char[] hexChars = new char[len * 2];
40 | for (int j = 0; j < len; j++) {
41 | int v = bytes[j] & 0xFF;
42 | hexChars[j * 2] = hexArray[v >>> 4];
43 | hexChars[j * 2 + 1] = hexArray[v & 0x0F];
44 | }
45 | return new String(hexChars);
46 | }
47 |
48 | @Override
49 | public void handleMessage(Message msg) {
50 | try {
51 | if (msg.what == LOG_INIT) {
52 | if (mLogFile != null)
53 | throw new RuntimeException("mLogFile not null");
54 | readLogCache((File) msg.obj);
55 | openLogFile((File) msg.obj);
56 | } else if (msg.what == LOG_MESSAGE && msg.obj instanceof LogItem) {
57 |
58 | if (mLogFile == null)
59 | return;
60 | writeLogItemToDisk((LogItem) msg.obj);
61 | } else if (msg.what == TRIM_LOG_FILE) {
62 | trimLogFile();
63 | for (LogItem li : VpnStatus.getlogbuffer())
64 | writeLogItemToDisk(li);
65 | } else if (msg.what == FLUSH_TO_DISK) {
66 | flushToDisk();
67 | }
68 |
69 | } catch (IOException | BufferOverflowException e) {
70 | e.printStackTrace();
71 | VpnStatus.logError("Error during log cache: " + msg.what);
72 | VpnStatus.logException(e);
73 | }
74 |
75 | }
76 |
77 | private void flushToDisk() throws IOException {
78 | mLogFile.flush();
79 | }
80 |
81 | private void trimLogFile() {
82 | try {
83 | mLogFile.flush();
84 | ((FileOutputStream) mLogFile).getChannel().truncate(0);
85 | } catch (IOException e) {
86 | e.printStackTrace();
87 | }
88 | }
89 |
90 | private void writeLogItemToDisk(LogItem li) throws IOException {
91 |
92 |
93 | byte[] liBytes = li.getMarschaledBytes();
94 |
95 | writeEscapedBytes(liBytes);
96 | }
97 |
98 | public void writeEscapedBytes(byte[] bytes) throws IOException {
99 | int magic = 0;
100 | for (byte b : bytes)
101 | if (b == MAGIC_BYTE || b == MAGIC_BYTE + 1)
102 | magic++;
103 |
104 | byte eBytes[] = new byte[bytes.length + magic];
105 |
106 | int i = 0;
107 | for (byte b : bytes) {
108 | if (b == MAGIC_BYTE || b == MAGIC_BYTE + 1) {
109 | eBytes[i++] = MAGIC_BYTE + 1;
110 | eBytes[i++] = (byte) (b - MAGIC_BYTE);
111 | } else {
112 | eBytes[i++] = b;
113 | }
114 | }
115 |
116 | byte[] lenBytes = ByteBuffer.allocate(4).putInt(bytes.length).array();
117 | synchronized (mLogFile) {
118 | mLogFile.write(MAGIC_BYTE);
119 | mLogFile.write(lenBytes);
120 | mLogFile.write(eBytes);
121 | }
122 | }
123 |
124 | private void openLogFile(File cacheDir) throws FileNotFoundException {
125 | File logfile = new File(cacheDir, LOGFILE_NAME);
126 | mLogFile = new FileOutputStream(logfile);
127 | }
128 |
129 | private void readLogCache(File cacheDir) {
130 | try {
131 | File logfile = new File(cacheDir, LOGFILE_NAME);
132 |
133 |
134 | if (!logfile.exists() || !logfile.canRead())
135 | return;
136 |
137 | readCacheContents(new FileInputStream(logfile));
138 |
139 | } catch (java.io.IOException | java.lang.RuntimeException e) {
140 | VpnStatus.logError("Reading cached logfile failed");
141 | VpnStatus.logException(e);
142 | e.printStackTrace();
143 |
144 | }
145 | }
146 |
147 | protected void readCacheContents(InputStream in) throws IOException {
148 |
149 |
150 | BufferedInputStream logFile = new BufferedInputStream(in);
151 |
152 | byte[] buf = new byte[16384];
153 | int read = logFile.read(buf, 0, 5);
154 | int itemsRead = 0;
155 |
156 |
157 | readloop:
158 | while (read >= 5) {
159 | int skipped = 0;
160 | while (buf[skipped] != MAGIC_BYTE) {
161 | skipped++;
162 | if (!(logFile.read(buf, skipped + 4, 1) == 1) || skipped + 10 > buf.length) {
163 | VpnStatus.logDebug(String.format(Locale.US, "Skipped %d bytes and no a magic byte found", skipped));
164 | break readloop;
165 | }
166 | }
167 | if (skipped > 0)
168 | VpnStatus.logDebug(String.format(Locale.US, "Skipped %d bytes before finding a magic byte", skipped));
169 |
170 | int len = ByteBuffer.wrap(buf, skipped + 1, 4).asIntBuffer().get();
171 |
172 |
173 | int pos = 0;
174 | byte buf2[] = new byte[buf.length];
175 |
176 | while (pos < len) {
177 | byte b = (byte) logFile.read();
178 | if (b == MAGIC_BYTE) {
179 | VpnStatus.logDebug(String.format(Locale.US, "Unexpected magic byte found at pos %d, abort current log item", pos));
180 | read = logFile.read(buf, 1, 4) + 1;
181 | continue readloop;
182 | } else if (b == MAGIC_BYTE + 1) {
183 | b = (byte) logFile.read();
184 | if (b == 0)
185 | b = MAGIC_BYTE;
186 | else if (b == 1)
187 | b = MAGIC_BYTE + 1;
188 | else {
189 | VpnStatus.logDebug(String.format(Locale.US, "Escaped byte not 0 or 1: %d", b));
190 | read = logFile.read(buf, 1, 4) + 1;
191 | continue readloop;
192 | }
193 | }
194 | buf2[pos++] = b;
195 | }
196 |
197 | restoreLogItem(buf2, len);
198 |
199 |
200 | read = logFile.read(buf, 0, 5);
201 | itemsRead++;
202 | if (itemsRead > 2 * VpnStatus.MAXLOGENTRIES) {
203 | VpnStatus.logError("Too many logentries read from cache, aborting.");
204 | read = 0;
205 | }
206 |
207 | }
208 | VpnStatus.logDebug(R.string.reread_log, itemsRead);
209 | }
210 |
211 | protected void restoreLogItem(byte[] buf, int len) throws UnsupportedEncodingException {
212 |
213 | LogItem li = new LogItem(buf, len);
214 | if (li.verify()) {
215 | VpnStatus.newLogItem(li, true);
216 | } else {
217 | VpnStatus.logError(String.format(Locale.getDefault(),
218 | "Could not read log item from file: %d: %s",
219 | len, bytesToHex(buf, Math.max(len, 80))));
220 | }
221 | }
222 |
223 | }
--------------------------------------------------------------------------------
/app/src/main/java/de/blinkt/openvpn/core/NativeUtils.java:
--------------------------------------------------------------------------------
1 | package de.blinkt.openvpn.core;
2 |
3 | import java.security.InvalidKeyException;
4 |
5 | public class NativeUtils {
6 | static {
7 | System.loadLibrary("opvpnutil");
8 | }
9 |
10 | public static native byte[] rsasign(byte[] input, int pkey) throws InvalidKeyException;
11 |
12 | public static native String[] getIfconfig() throws IllegalArgumentException;
13 |
14 | static native void jniclose(int fdint);
15 |
16 | public static native String getNativeAPI();
17 | }
18 |
--------------------------------------------------------------------------------
/app/src/main/java/de/blinkt/openvpn/core/OpenVPNManagement.java:
--------------------------------------------------------------------------------
1 | package de.blinkt.openvpn.core;
2 |
3 | public interface OpenVPNManagement {
4 | int mBytecountInterval = 2;
5 |
6 | void reconnect();
7 |
8 | void pause(pauseReason reason);
9 |
10 | void resume();
11 |
12 | boolean stopVPN(boolean replaceConnection);
13 |
14 | void networkChange(boolean sameNetwork);
15 |
16 | void setPauseCallback(PausedStateCallback callback);
17 |
18 | enum pauseReason {
19 | noNetwork,
20 | userPause,
21 | screenOff,
22 | }
23 |
24 | interface PausedStateCallback {
25 | boolean shouldBeRunning();
26 | }
27 | }
28 |
--------------------------------------------------------------------------------
/app/src/main/java/de/blinkt/openvpn/core/OpenVPNThread.java:
--------------------------------------------------------------------------------
1 | package de.blinkt.openvpn.core;
2 |
3 | import android.annotation.SuppressLint;
4 | import android.util.Log;
5 |
6 | import com.frogobox.viprox.R;
7 |
8 | import java.io.BufferedReader;
9 | import java.io.BufferedWriter;
10 | import java.io.FileWriter;
11 | import java.io.IOException;
12 | import java.io.InputStream;
13 | import java.io.InputStreamReader;
14 | import java.text.SimpleDateFormat;
15 | import java.util.Collections;
16 | import java.util.Date;
17 | import java.util.LinkedList;
18 | import java.util.Locale;
19 | import java.util.regex.Matcher;
20 | import java.util.regex.Pattern;
21 |
22 | import de.blinkt.openvpn.core.VpnStatus.ConnectionStatus;
23 |
24 | public class OpenVPNThread implements Runnable {
25 | public static final int M_FATAL = (1 << 4);
26 | public static final int M_NONFATAL = (1 << 5);
27 | public static final int M_WARN = (1 << 6);
28 | public static final int M_DEBUG = (1 << 7);
29 | private static final String DUMP_PATH_STRING = "Dump path: ";
30 | @SuppressLint("SdCardPath")
31 | private static final String BROKEN_PIE_SUPPORT = "/data/data/de.blinkt.openvpn/cache/pievpn";
32 | private final static String BROKEN_PIE_SUPPORT2 = "syntax error";
33 | private static final String TAG = "OpenVPN";
34 | private String[] mArgv;
35 | private Process mProcess;
36 | private String mNativeDir;
37 | private OpenVPNService mService;
38 | private String mDumpPath;
39 | private boolean mBrokenPie = false;
40 | private boolean mNoProcessExitStatus = false;
41 |
42 | public OpenVPNThread(OpenVPNService service, String[] argv, String nativelibdir) {
43 | mArgv = argv;
44 | mNativeDir = nativelibdir;
45 | mService = service;
46 | }
47 |
48 | public void stopProcess() {
49 | mProcess.destroy();
50 | }
51 |
52 | void setReplaceConnection() {
53 | mNoProcessExitStatus = true;
54 | }
55 |
56 | @Override
57 | public void run() {
58 | try {
59 | Log.i(TAG, "Starting openvpn");
60 | startOpenVPNThreadArgs(mArgv);
61 | Log.i(TAG, "OpenVPN process exited");
62 | } catch (Exception e) {
63 | VpnStatus.logException("Starting OpenVPN Thread", e);
64 | Log.e(TAG, "OpenVPNThread Got " + e.toString());
65 | } finally {
66 | int exitvalue = 0;
67 | try {
68 | if (mProcess != null)
69 | exitvalue = mProcess.waitFor();
70 | } catch (IllegalThreadStateException ite) {
71 | VpnStatus.logError("Illegal Thread state: " + ite.getLocalizedMessage());
72 | } catch (InterruptedException ie) {
73 | VpnStatus.logError("InterruptedException: " + ie.getLocalizedMessage());
74 | }
75 | if (exitvalue != 0) {
76 | VpnStatus.logError("Process exited with exit value " + exitvalue);
77 | if (mBrokenPie) {
78 |
79 | String[] noPieArgv = VPNLaunchHelper.replacePieWithNoPie(mArgv);
80 |
81 |
82 | if (!noPieArgv.equals(mArgv)) {
83 | mArgv = noPieArgv;
84 | VpnStatus.logInfo("PIE Version could not be executed. Trying no PIE version");
85 | run();
86 | return;
87 | }
88 |
89 | }
90 |
91 | }
92 |
93 | if (!mNoProcessExitStatus)
94 | VpnStatus.updateStateString("NOPROCESS", "No process running.", R.string.state_noprocess, ConnectionStatus.LEVEL_NOTCONNECTED);
95 |
96 | if (mDumpPath != null) {
97 | try {
98 | BufferedWriter logout = new BufferedWriter(new FileWriter(mDumpPath + ".log"));
99 | SimpleDateFormat timeformat = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss", Locale.GERMAN);
100 | for (LogItem li : VpnStatus.getlogbuffer()) {
101 | String time = timeformat.format(new Date(li.getLogtime()));
102 | logout.write(time + " " + li.getString(mService) + "\n");
103 | }
104 | logout.close();
105 | VpnStatus.logError(R.string.minidump_generated);
106 | } catch (IOException e) {
107 | VpnStatus.logError("Writing minidump log: " + e.getLocalizedMessage());
108 | }
109 | }
110 |
111 | mService.processDied();
112 | Log.i(TAG, "Exiting");
113 | }
114 | }
115 |
116 | private void startOpenVPNThreadArgs(String[] argv) {
117 | LinkedList argvlist = new LinkedList();
118 | Collections.addAll(argvlist, argv);
119 | ProcessBuilder pb = new ProcessBuilder(argvlist);
120 | String lbpath = genLibraryPath(argv, pb);
121 | pb.environment().put("LD_LIBRARY_PATH", lbpath);
122 |
123 | pb.redirectErrorStream(true);
124 | try {
125 | mProcess = pb.start();
126 |
127 | mProcess.getOutputStream().close();
128 | InputStream in = mProcess.getInputStream();
129 | BufferedReader br = new BufferedReader(new InputStreamReader(in));
130 |
131 | while (true) {
132 | String logline = br.readLine();
133 | if (logline == null)
134 | return;
135 |
136 | if (logline.startsWith(DUMP_PATH_STRING))
137 | mDumpPath = logline.substring(DUMP_PATH_STRING.length());
138 |
139 | if (logline.startsWith(BROKEN_PIE_SUPPORT) || logline.contains(BROKEN_PIE_SUPPORT2))
140 | mBrokenPie = true;
141 |
142 |
143 | Pattern p = Pattern.compile("(\\d+).(\\d+) ([0-9a-f])+ (.*)");
144 | Matcher m = p.matcher(logline);
145 | if (m.matches()) {
146 | int flags = Integer.parseInt(m.group(3), 16);
147 | String msg = m.group(4);
148 | int logLevel = flags & 0x0F;
149 |
150 | VpnStatus.LogLevel logStatus = VpnStatus.LogLevel.INFO;
151 |
152 | if ((flags & M_FATAL) != 0)
153 | logStatus = VpnStatus.LogLevel.ERROR;
154 | else if ((flags & M_NONFATAL) != 0)
155 | logStatus = VpnStatus.LogLevel.WARNING;
156 | else if ((flags & M_WARN) != 0)
157 | logStatus = VpnStatus.LogLevel.WARNING;
158 | else if ((flags & M_DEBUG) != 0)
159 | logStatus = VpnStatus.LogLevel.VERBOSE;
160 |
161 | if (msg.startsWith("MANAGEMENT: CMD"))
162 | logLevel = Math.max(4, logLevel);
163 |
164 |
165 | VpnStatus.logMessageOpenVPN(logStatus, logLevel, msg);
166 | } else {
167 | VpnStatus.logInfo("P:" + logline);
168 | }
169 | }
170 |
171 |
172 | } catch (IOException e) {
173 | VpnStatus.logException("Error reading from output of OpenVPN process", e);
174 | stopProcess();
175 | }
176 |
177 |
178 | }
179 |
180 | private String genLibraryPath(String[] argv, ProcessBuilder pb) {
181 |
182 | String applibpath = argv[0].replaceFirst("/cache/.*$", "/lib");
183 |
184 | String lbpath = pb.environment().get("LD_LIBRARY_PATH");
185 | if (lbpath == null)
186 | lbpath = applibpath;
187 | else
188 | lbpath = applibpath + ":" + lbpath;
189 |
190 | if (!applibpath.equals(mNativeDir)) {
191 | lbpath = mNativeDir + ":" + lbpath;
192 | }
193 | return lbpath;
194 | }
195 | }
196 |
--------------------------------------------------------------------------------
/app/src/main/java/de/blinkt/openvpn/core/ProfileManager.java:
--------------------------------------------------------------------------------
1 | package de.blinkt.openvpn.core;
2 |
3 | import android.app.Activity;
4 | import android.content.Context;
5 | import android.content.SharedPreferences;
6 | import android.content.SharedPreferences.Editor;
7 | import android.preference.PreferenceManager;
8 |
9 | import java.io.IOException;
10 | import java.io.ObjectInputStream;
11 | import java.io.ObjectOutputStream;
12 | import java.util.Collection;
13 | import java.util.HashMap;
14 | import java.util.HashSet;
15 | import java.util.Set;
16 |
17 | import de.blinkt.openvpn.VpnProfile;
18 |
19 | public class ProfileManager {
20 | private static final String PREFS_NAME = "VPNList";
21 |
22 | private static final String LAST_CONNECTED_PROFILE = "lastConnectedProfile";
23 | private static ProfileManager instance;
24 |
25 | private static VpnProfile mLastConnectedVpn = null;
26 | private static VpnProfile tmpprofile = null;
27 | private HashMap profiles = new HashMap<>();
28 |
29 | private ProfileManager() {
30 | }
31 |
32 | private static VpnProfile get(String key) {
33 | if (tmpprofile != null && tmpprofile.getUUIDString().equals(key))
34 | return tmpprofile;
35 |
36 | if (instance == null)
37 | return null;
38 | return instance.profiles.get(key);
39 |
40 | }
41 |
42 | private static void checkInstance(Context context) {
43 | if (instance == null) {
44 | instance = new ProfileManager();
45 | instance.loadVPNList(context);
46 | }
47 | }
48 |
49 | synchronized public static ProfileManager getInstance(Context context) {
50 | checkInstance(context);
51 | return instance;
52 | }
53 |
54 | public static void setConntectedVpnProfileDisconnected(Context c) {
55 | SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(c);
56 | Editor prefsedit = prefs.edit();
57 | prefsedit.putString(LAST_CONNECTED_PROFILE, null);
58 | prefsedit.apply();
59 |
60 | }
61 |
62 |
63 | public static void setConnectedVpnProfile(Context c, VpnProfile connectedProfile) {
64 | SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(c);
65 | Editor prefsedit = prefs.edit();
66 |
67 | prefsedit.putString(LAST_CONNECTED_PROFILE, connectedProfile.getUUIDString());
68 | prefsedit.apply();
69 | mLastConnectedVpn = connectedProfile;
70 |
71 | }
72 |
73 |
74 | public static VpnProfile getLastConnectedProfile(Context c) {
75 | SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(c);
76 |
77 | String lastConnectedProfile = prefs.getString(LAST_CONNECTED_PROFILE, null);
78 | if (lastConnectedProfile != null)
79 | return get(c, lastConnectedProfile);
80 | else
81 | return null;
82 | }
83 |
84 | public static void setTemporaryProfile(VpnProfile tmp) {
85 | ProfileManager.tmpprofile = tmp;
86 | }
87 |
88 | public static boolean isTempProfile() {
89 | return mLastConnectedVpn == tmpprofile;
90 | }
91 |
92 | public static VpnProfile get(Context context, String profileUUID) {
93 | checkInstance(context);
94 | return get(profileUUID);
95 | }
96 |
97 | public static VpnProfile getLastConnectedVpn() {
98 | return mLastConnectedVpn;
99 | }
100 |
101 | public static VpnProfile getAlwaysOnVPN(Context context) {
102 | checkInstance(context);
103 | SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(context);
104 |
105 | String uuid = prefs.getString("alwaysOnVpn", null);
106 | return get(uuid);
107 |
108 | }
109 |
110 | public Collection getProfiles() {
111 | return profiles.values();
112 | }
113 |
114 | public VpnProfile getProfileByName(String name) {
115 | for (VpnProfile vpnp : profiles.values()) {
116 | if (vpnp.getName().equals(name)) {
117 | return vpnp;
118 | }
119 | }
120 | return null;
121 | }
122 |
123 | public void saveProfileList(Context context) {
124 | SharedPreferences sharedprefs = context.getSharedPreferences(PREFS_NAME, Activity.MODE_PRIVATE);
125 | Editor editor = sharedprefs.edit();
126 | editor.putStringSet("vpnlist", profiles.keySet());
127 |
128 |
129 | int counter = sharedprefs.getInt("counter", 0);
130 | editor.putInt("counter", counter + 1);
131 | editor.apply();
132 |
133 | }
134 |
135 | public void addProfile(VpnProfile profile) {
136 | profiles.put(profile.getUUID().toString(), profile);
137 |
138 | }
139 |
140 | public void saveProfile(Context context, VpnProfile profile) {
141 | ObjectOutputStream vpnfile;
142 | try {
143 | vpnfile = new ObjectOutputStream(context.openFileOutput((profile.getUUID().toString() + ".vp"), Activity.MODE_PRIVATE));
144 |
145 | vpnfile.writeObject(profile);
146 | vpnfile.flush();
147 | vpnfile.close();
148 | } catch (IOException e) {
149 | VpnStatus.logException("saving VPN profile", e);
150 | throw new RuntimeException(e);
151 | }
152 | }
153 |
154 | private void loadVPNList(Context context) {
155 | profiles = new HashMap<>();
156 | SharedPreferences listpref = context.getSharedPreferences(PREFS_NAME, Activity.MODE_PRIVATE);
157 | Set vlist = listpref.getStringSet("vpnlist", null);
158 | if (vlist == null) {
159 | vlist = new HashSet<>();
160 | }
161 |
162 | for (String vpnentry : vlist) {
163 | try {
164 | ObjectInputStream vpnfile = new ObjectInputStream(context.openFileInput(vpnentry + ".vp"));
165 | VpnProfile vp = ((VpnProfile) vpnfile.readObject());
166 |
167 |
168 | if (vp == null || vp.mName == null || vp.getUUID() == null)
169 | continue;
170 |
171 | vp.upgradeProfile();
172 | profiles.put(vp.getUUID().toString(), vp);
173 |
174 | } catch (IOException | ClassNotFoundException e) {
175 | VpnStatus.logException("Loading VPN List", e);
176 | }
177 | }
178 | }
179 |
180 | public void removeProfile(Context context, VpnProfile profile) {
181 | String vpnentry = profile.getUUID().toString();
182 | profiles.remove(vpnentry);
183 | saveProfileList(context);
184 | context.deleteFile(vpnentry + ".vp");
185 | if (mLastConnectedVpn == profile)
186 | mLastConnectedVpn = null;
187 |
188 | }
189 | }
--------------------------------------------------------------------------------
/app/src/main/java/de/blinkt/openvpn/core/ProxyDetection.java:
--------------------------------------------------------------------------------
1 | package de.blinkt.openvpn.core;
2 |
3 | import com.frogobox.viprox.R;
4 |
5 | import java.net.InetSocketAddress;
6 | import java.net.MalformedURLException;
7 | import java.net.Proxy;
8 | import java.net.ProxySelector;
9 | import java.net.SocketAddress;
10 | import java.net.URISyntaxException;
11 | import java.net.URL;
12 | import java.util.List;
13 |
14 | import de.blinkt.openvpn.VpnProfile;
15 |
16 | public class ProxyDetection {
17 | static SocketAddress detectProxy(VpnProfile vp) {
18 | try {
19 | URL url = new URL(String.format("https://%s:%s", vp.mServerName, vp.mServerPort));
20 | Proxy proxy = getFirstProxy(url);
21 |
22 | if (proxy == null)
23 | return null;
24 | SocketAddress addr = proxy.address();
25 | if (addr instanceof InetSocketAddress) {
26 | return addr;
27 | }
28 |
29 | } catch (MalformedURLException e) {
30 | VpnStatus.logError(R.string.getproxy_error, e.getLocalizedMessage());
31 | } catch (URISyntaxException e) {
32 | VpnStatus.logError(R.string.getproxy_error, e.getLocalizedMessage());
33 | }
34 | return null;
35 | }
36 |
37 | static Proxy getFirstProxy(URL url) throws URISyntaxException {
38 | System.setProperty("java.net.useSystemProxies", "true");
39 | List proxylist = ProxySelector.getDefault().select(url.toURI());
40 | if (proxylist != null) {
41 | for (Proxy proxy : proxylist) {
42 | SocketAddress addr = proxy.address();
43 |
44 | if (addr != null) {
45 | return proxy;
46 | }
47 | }
48 |
49 | }
50 | return null;
51 | }
52 | }
--------------------------------------------------------------------------------
/app/src/main/java/de/blinkt/openvpn/core/VPNLaunchHelper.java:
--------------------------------------------------------------------------------
1 | package de.blinkt.openvpn.core;
2 |
3 | import android.annotation.TargetApi;
4 | import android.content.Context;
5 | import android.content.Intent;
6 | import android.os.Build;
7 |
8 | import com.frogobox.viprox.R;
9 |
10 | import java.io.File;
11 | import java.io.FileOutputStream;
12 | import java.io.IOException;
13 | import java.io.InputStream;
14 | import java.util.Arrays;
15 | import java.util.Vector;
16 |
17 | import de.blinkt.openvpn.VpnProfile;
18 |
19 | public class VPNLaunchHelper {
20 | private static final String MININONPIEVPN = "nopie_openvpn";
21 | private static final String MINIPIEVPN = "pie_openvpn";
22 | private static final String OVPNCONFIGFILE = "android.conf";
23 |
24 | private static String writeMiniVPN(Context context) {
25 | String[] abis;
26 | if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP)
27 | abis = getSupportedABIsLollipop();
28 | else
29 | abis = new String[]{Build.CPU_ABI, Build.CPU_ABI2};
30 |
31 | String nativeAPI = NativeUtils.getNativeAPI();
32 | if (!nativeAPI.equals(abis[0])) {
33 | VpnStatus.logWarning(R.string.abi_mismatch, Arrays.toString(abis), nativeAPI);
34 | abis = new String[]{nativeAPI};
35 | }
36 |
37 | for (String abi : abis) {
38 |
39 | File vpnExecutable = new File(context.getCacheDir(), getMiniVPNExecutableName() + "." + abi);
40 | if ((vpnExecutable.exists() && vpnExecutable.canExecute()) || writeMiniVPNBinary(context, abi, vpnExecutable)) {
41 | return vpnExecutable.getPath();
42 | }
43 | }
44 |
45 | return null;
46 | }
47 |
48 | @TargetApi(Build.VERSION_CODES.LOLLIPOP)
49 | private static String[] getSupportedABIsLollipop() {
50 | return Build.SUPPORTED_ABIS;
51 | }
52 |
53 | private static String getMiniVPNExecutableName() {
54 | if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN)
55 | return MINIPIEVPN;
56 | else
57 | return MININONPIEVPN;
58 | }
59 |
60 |
61 | public static String[] replacePieWithNoPie(String[] mArgv) {
62 | mArgv[0] = mArgv[0].replace(MINIPIEVPN, MININONPIEVPN);
63 | return mArgv;
64 | }
65 |
66 |
67 | static String[] buildOpenvpnArgv(Context c) {
68 | Vector args = new Vector<>();
69 |
70 | String binaryName = writeMiniVPN(c);
71 |
72 |
73 | if (binaryName == null) {
74 | VpnStatus.logError("Error writing minivpn binary");
75 | return null;
76 | }
77 |
78 | args.add(binaryName);
79 |
80 | args.add("--config");
81 | args.add(getConfigFilePath(c));
82 |
83 | return args.toArray(new String[args.size()]);
84 | }
85 |
86 | private static boolean writeMiniVPNBinary(Context context, String abi, File mvpnout) {
87 | try {
88 | InputStream mvpn;
89 |
90 | try {
91 | mvpn = context.getAssets().open(getMiniVPNExecutableName() + "." + abi);
92 | } catch (IOException errabi) {
93 | VpnStatus.logInfo("Failed getting assets for archicture " + abi);
94 | return false;
95 | }
96 |
97 |
98 | FileOutputStream fout = new FileOutputStream(mvpnout);
99 |
100 | byte buf[] = new byte[4096];
101 |
102 | int lenread = mvpn.read(buf);
103 | while (lenread > 0) {
104 | fout.write(buf, 0, lenread);
105 | lenread = mvpn.read(buf);
106 | }
107 | fout.close();
108 |
109 | if (!mvpnout.setExecutable(true)) {
110 | VpnStatus.logError("Failed to make OpenVPN executable");
111 | return false;
112 | }
113 |
114 |
115 | return true;
116 | } catch (IOException e) {
117 | VpnStatus.logException(e);
118 | return false;
119 | }
120 |
121 | }
122 |
123 |
124 | public static void startOpenVpn(VpnProfile startprofile, Context context) {
125 | Intent startVPN = startprofile.prepareStartService(context);
126 | if (startVPN != null)
127 | context.startService(startVPN);
128 |
129 | }
130 |
131 | public static String getConfigFilePath(Context context) {
132 | return context.getCacheDir().getAbsolutePath() + "/" + OVPNCONFIGFILE;
133 | }
134 |
135 | }
--------------------------------------------------------------------------------
/app/src/main/java/de/blinkt/openvpn/core/X509Utils.java:
--------------------------------------------------------------------------------
1 | package de.blinkt.openvpn.core;
2 |
3 | import android.content.Context;
4 | import android.content.res.Resources;
5 | import android.text.TextUtils;
6 |
7 | import com.frogobox.viprox.R;
8 | import com.frogobox.viprox.util.io.pem.PemObject;
9 | import com.frogobox.viprox.util.io.pem.PemReader;
10 |
11 | import java.io.ByteArrayInputStream;
12 | import java.io.File;
13 | import java.io.FileInputStream;
14 | import java.io.FileNotFoundException;
15 | import java.io.FileReader;
16 | import java.io.IOException;
17 | import java.io.InputStream;
18 | import java.io.Reader;
19 | import java.io.StringReader;
20 | import java.lang.reflect.InvocationTargetException;
21 | import java.lang.reflect.Method;
22 | import java.security.cert.Certificate;
23 | import java.security.cert.CertificateException;
24 | import java.security.cert.CertificateExpiredException;
25 | import java.security.cert.CertificateFactory;
26 | import java.security.cert.CertificateNotYetValidException;
27 | import java.security.cert.X509Certificate;
28 | import java.util.Date;
29 | import java.util.Hashtable;
30 | import java.util.Vector;
31 |
32 | import javax.security.auth.x500.X500Principal;
33 |
34 | import de.blinkt.openvpn.VpnProfile;
35 |
36 | public class X509Utils {
37 | public static Certificate[] getCertificatesFromFile(String certfilename) throws FileNotFoundException, CertificateException {
38 | CertificateFactory certFact = CertificateFactory.getInstance("X.509");
39 |
40 | Vector certificates = new Vector<>();
41 | if (VpnProfile.isEmbedded(certfilename)) {
42 | int subIndex = certfilename.indexOf("-----BEGIN CERTIFICATE-----");
43 | do {
44 | subIndex = Math.max(0, subIndex);
45 | InputStream inStream = new ByteArrayInputStream(certfilename.substring(subIndex).getBytes());
46 | certificates.add(certFact.generateCertificate(inStream));
47 |
48 | subIndex = certfilename.indexOf("-----BEGIN CERTIFICATE-----", subIndex + 1);
49 | } while (subIndex > 0);
50 | return certificates.toArray(new Certificate[certificates.size()]);
51 | } else {
52 | InputStream inStream = new FileInputStream(certfilename);
53 | return new Certificate[]{certFact.generateCertificate(inStream)};
54 | }
55 |
56 |
57 | }
58 |
59 | public static PemObject readPemObjectFromFile(String keyfilename) throws IOException {
60 |
61 | Reader inStream;
62 |
63 | if (VpnProfile.isEmbedded(keyfilename))
64 | inStream = new StringReader(VpnProfile.getEmbeddedContent(keyfilename));
65 | else
66 | inStream = new FileReader(new File(keyfilename));
67 |
68 | PemReader pr = new PemReader(inStream);
69 | PemObject r = pr.readPemObject();
70 | pr.close();
71 | return r;
72 | }
73 |
74 |
75 | public static String getCertificateFriendlyName(Context c, String filename) {
76 | if (!TextUtils.isEmpty(filename)) {
77 | try {
78 | X509Certificate cert = (X509Certificate) getCertificatesFromFile(filename)[0];
79 | String friendlycn = getCertificateFriendlyName(cert);
80 | friendlycn = getCertificateValidityString(cert, c.getResources()) + friendlycn;
81 | return friendlycn;
82 |
83 | } catch (Exception e) {
84 | VpnStatus.logError("Could not read certificate" + e.getLocalizedMessage());
85 | }
86 | }
87 | return c.getString(R.string.cannotparsecert);
88 | }
89 |
90 | public static String getCertificateValidityString(X509Certificate cert, Resources res) {
91 | try {
92 | cert.checkValidity();
93 | } catch (CertificateExpiredException ce) {
94 | return "EXPIRED: ";
95 | } catch (CertificateNotYetValidException cny) {
96 | return "NOT YET VALID: ";
97 | }
98 |
99 | Date certNotAfter = cert.getNotAfter();
100 | Date now = new Date();
101 | long timeLeft = certNotAfter.getTime() - now.getTime();
102 |
103 |
104 | if (timeLeft > 90l * 24 * 3600 * 1000) {
105 | long months = getMonthsDifference(now, certNotAfter);
106 | return res.getString(R.string.months_left, months);
107 | } else if (timeLeft > 72 * 3600 * 1000) {
108 | long days = timeLeft / (24 * 3600 * 1000);
109 | return res.getString(R.string.days_left, days);
110 | } else {
111 | long hours = timeLeft / (3600 * 1000);
112 |
113 | return res.getString(R.string.hours_left, hours);
114 | }
115 | }
116 |
117 | public static int getMonthsDifference(Date date1, Date date2) {
118 | int m1 = date1.getYear() * 12 + date1.getMonth();
119 | int m2 = date2.getYear() * 12 + date2.getMonth();
120 | return m2 - m1 + 1;
121 | }
122 |
123 | public static String getCertificateFriendlyName(X509Certificate cert) {
124 | X500Principal principal = cert.getSubjectX500Principal();
125 | byte[] encodedSubject = principal.getEncoded();
126 | String friendlyName = null;
127 |
128 |
129 | Exception exp = null;
130 | try {
131 | Class X509NameClass = Class.forName("com.android.org.bouncycastle.asn1.x509.X509Name");
132 | Method getInstance = X509NameClass.getMethod("getInstance", Object.class);
133 |
134 | Hashtable defaultSymbols = (Hashtable) X509NameClass.getField("DefaultSymbols").get(X509NameClass);
135 |
136 | if (!defaultSymbols.containsKey("1.2.840.113549.1.9.1"))
137 | defaultSymbols.put("1.2.840.113549.1.9.1", "eMail");
138 |
139 | Object subjectName = getInstance.invoke(X509NameClass, encodedSubject);
140 |
141 | Method toString = X509NameClass.getMethod("toString", boolean.class, Hashtable.class);
142 |
143 | friendlyName = (String) toString.invoke(subjectName, true, defaultSymbols);
144 |
145 | } catch (ClassNotFoundException e) {
146 | exp = e;
147 | } catch (NoSuchMethodException e) {
148 | exp = e;
149 | } catch (InvocationTargetException e) {
150 | exp = e;
151 | } catch (IllegalAccessException e) {
152 | exp = e;
153 | } catch (NoSuchFieldException e) {
154 | exp = e;
155 | }
156 | if (exp != null)
157 | VpnStatus.logException("Getting X509 Name from certificate", exp);
158 |
159 |
160 | if (friendlyName == null)
161 | friendlyName = principal.getName();
162 |
163 |
164 | String[] parts = friendlyName.split(",");
165 | for (int i = 0; i < parts.length; i++) {
166 | String part = parts[i];
167 | if (part.startsWith("1.2.840.113549.1.9.1=#16")) {
168 | parts[i] = "email=" + ia5decode(part.replace("1.2.840.113549.1.9.1=#16", ""));
169 | }
170 | }
171 | friendlyName = TextUtils.join(",", parts);
172 | return friendlyName;
173 | }
174 |
175 | public static boolean isPrintableChar(char c) {
176 | Character.UnicodeBlock block = Character.UnicodeBlock.of(c);
177 | return (!Character.isISOControl(c)) &&
178 | block != null &&
179 | block != Character.UnicodeBlock.SPECIALS;
180 | }
181 |
182 | private static String ia5decode(String ia5string) {
183 | String d = "";
184 | for (int i = 1; i < ia5string.length(); i = i + 2) {
185 | String hexstr = ia5string.substring(i - 1, i + 1);
186 | char c = (char) Integer.parseInt(hexstr, 16);
187 | if (isPrintableChar(c)) {
188 | d += c;
189 | } else if (i == 1 && (c == 0x12 || c == 0x1b)) {
190 | ;
191 | } else {
192 | d += "\\x" + hexstr;
193 | }
194 | }
195 | return d;
196 | }
197 | }
--------------------------------------------------------------------------------
/app/src/main/jniLibs/arm64-v8a/libjbcrypto.so:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/amirisback/vpn/cf6770030bc5d3e289a75e739f2e41a1a1d9e654/app/src/main/jniLibs/arm64-v8a/libjbcrypto.so
--------------------------------------------------------------------------------
/app/src/main/jniLibs/arm64-v8a/libopenvpn.so:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/amirisback/vpn/cf6770030bc5d3e289a75e739f2e41a1a1d9e654/app/src/main/jniLibs/arm64-v8a/libopenvpn.so
--------------------------------------------------------------------------------
/app/src/main/jniLibs/arm64-v8a/libopvpnutil.so:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/amirisback/vpn/cf6770030bc5d3e289a75e739f2e41a1a1d9e654/app/src/main/jniLibs/arm64-v8a/libopvpnutil.so
--------------------------------------------------------------------------------
/app/src/main/jniLibs/armeabi-v7a/libjbcrypto.so:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/amirisback/vpn/cf6770030bc5d3e289a75e739f2e41a1a1d9e654/app/src/main/jniLibs/armeabi-v7a/libjbcrypto.so
--------------------------------------------------------------------------------
/app/src/main/jniLibs/armeabi-v7a/libopenvpn.so:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/amirisback/vpn/cf6770030bc5d3e289a75e739f2e41a1a1d9e654/app/src/main/jniLibs/armeabi-v7a/libopenvpn.so
--------------------------------------------------------------------------------
/app/src/main/jniLibs/armeabi-v7a/libopvpnutil.so:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/amirisback/vpn/cf6770030bc5d3e289a75e739f2e41a1a1d9e654/app/src/main/jniLibs/armeabi-v7a/libopvpnutil.so
--------------------------------------------------------------------------------
/app/src/main/jniLibs/armeabi/libjbcrypto.so:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/amirisback/vpn/cf6770030bc5d3e289a75e739f2e41a1a1d9e654/app/src/main/jniLibs/armeabi/libjbcrypto.so
--------------------------------------------------------------------------------
/app/src/main/jniLibs/armeabi/libopenvpn.so:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/amirisback/vpn/cf6770030bc5d3e289a75e739f2e41a1a1d9e654/app/src/main/jniLibs/armeabi/libopenvpn.so
--------------------------------------------------------------------------------
/app/src/main/jniLibs/armeabi/libopvpnutil.so:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/amirisback/vpn/cf6770030bc5d3e289a75e739f2e41a1a1d9e654/app/src/main/jniLibs/armeabi/libopvpnutil.so
--------------------------------------------------------------------------------
/app/src/main/jniLibs/mips/libjbcrypto.so:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/amirisback/vpn/cf6770030bc5d3e289a75e739f2e41a1a1d9e654/app/src/main/jniLibs/mips/libjbcrypto.so
--------------------------------------------------------------------------------
/app/src/main/jniLibs/mips/libopenvpn.so:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/amirisback/vpn/cf6770030bc5d3e289a75e739f2e41a1a1d9e654/app/src/main/jniLibs/mips/libopenvpn.so
--------------------------------------------------------------------------------
/app/src/main/jniLibs/mips/libopvpnutil.so:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/amirisback/vpn/cf6770030bc5d3e289a75e739f2e41a1a1d9e654/app/src/main/jniLibs/mips/libopvpnutil.so
--------------------------------------------------------------------------------
/app/src/main/jniLibs/x86/libjbcrypto.so:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/amirisback/vpn/cf6770030bc5d3e289a75e739f2e41a1a1d9e654/app/src/main/jniLibs/x86/libjbcrypto.so
--------------------------------------------------------------------------------
/app/src/main/jniLibs/x86/libopenvpn.so:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/amirisback/vpn/cf6770030bc5d3e289a75e739f2e41a1a1d9e654/app/src/main/jniLibs/x86/libopenvpn.so
--------------------------------------------------------------------------------
/app/src/main/jniLibs/x86/libopvpnutil.so:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/amirisback/vpn/cf6770030bc5d3e289a75e739f2e41a1a1d9e654/app/src/main/jniLibs/x86/libopvpnutil.so
--------------------------------------------------------------------------------
/app/src/main/jniLibs/x86_64/libjbcrypto.so:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/amirisback/vpn/cf6770030bc5d3e289a75e739f2e41a1a1d9e654/app/src/main/jniLibs/x86_64/libjbcrypto.so
--------------------------------------------------------------------------------
/app/src/main/jniLibs/x86_64/libopenvpn.so:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/amirisback/vpn/cf6770030bc5d3e289a75e739f2e41a1a1d9e654/app/src/main/jniLibs/x86_64/libopenvpn.so
--------------------------------------------------------------------------------
/app/src/main/jniLibs/x86_64/libopvpnutil.so:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/amirisback/vpn/cf6770030bc5d3e289a75e739f2e41a1a1d9e654/app/src/main/jniLibs/x86_64/libopvpnutil.so
--------------------------------------------------------------------------------
/app/src/main/res/drawable/bg_button.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 | -
4 |
5 |
6 |
7 |
8 |
9 |
--------------------------------------------------------------------------------
/app/src/main/res/drawable/bg_button_connected.xml:
--------------------------------------------------------------------------------
1 |
2 |
4 |
5 |
12 |
--------------------------------------------------------------------------------
/app/src/main/res/drawable/bg_button_no_connected.xml:
--------------------------------------------------------------------------------
1 |
2 |
4 |
5 |
12 |
--------------------------------------------------------------------------------
/app/src/main/res/drawable/bg_card_dark.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 | -
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
--------------------------------------------------------------------------------
/app/src/main/res/drawable/bg_card_toolbar.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 | -
4 |
5 |
6 |
7 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
26 |
--------------------------------------------------------------------------------
/app/src/main/res/drawable/bg_card_white.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 | -
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
--------------------------------------------------------------------------------
/app/src/main/res/drawable/ic_btn_connect_vpn.xml:
--------------------------------------------------------------------------------
1 |
6 |
9 |
12 |
15 |
18 |
21 |
24 |
27 |
30 |
33 |
36 |
39 |
42 |
43 |
--------------------------------------------------------------------------------
/app/src/main/res/drawable/ic_connect_good.xml:
--------------------------------------------------------------------------------
1 |
4 |
5 |
6 |
7 |
--------------------------------------------------------------------------------
/app/src/main/res/drawable/ic_dummy_flag.xml:
--------------------------------------------------------------------------------
1 |
6 |
9 |
12 |
15 |
18 |
21 |
24 |
27 |
28 |
--------------------------------------------------------------------------------
/app/src/main/res/drawable/ic_frogobox.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/amirisback/vpn/cf6770030bc5d3e289a75e739f2e41a1a1d9e654/app/src/main/res/drawable/ic_frogobox.png
--------------------------------------------------------------------------------
/app/src/main/res/drawable/ic_launcher.xml:
--------------------------------------------------------------------------------
1 |
6 |
9 |
12 |
15 |
18 |
21 |
24 |
27 |
30 |
33 |
36 |
39 |
40 |
--------------------------------------------------------------------------------
/app/src/main/res/drawable/ic_toolbar_about_us.xml:
--------------------------------------------------------------------------------
1 |
6 |
9 |
10 |
--------------------------------------------------------------------------------
/app/src/main/res/drawable/ic_toolbar_back_home.xml:
--------------------------------------------------------------------------------
1 |
6 |
9 |
10 |
--------------------------------------------------------------------------------
/app/src/main/res/drawable/ic_toolbar_back_home_white.xml:
--------------------------------------------------------------------------------
1 |
6 |
9 |
10 |
--------------------------------------------------------------------------------
/app/src/main/res/drawable/ic_toolbar_location.xml:
--------------------------------------------------------------------------------
1 |
6 |
9 |
10 |
--------------------------------------------------------------------------------
/app/src/main/res/drawable/info_servers_bg.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 | -
4 |
5 |
6 |
9 |
10 |
11 |
--------------------------------------------------------------------------------
/app/src/main/res/font/montserrat_regular.ttf:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/amirisback/vpn/cf6770030bc5d3e289a75e739f2e41a1a1d9e654/app/src/main/res/font/montserrat_regular.ttf
--------------------------------------------------------------------------------
/app/src/main/res/layout/activity_about_us.xml:
--------------------------------------------------------------------------------
1 |
2 |
6 |
7 |
13 |
14 |
19 |
20 |
29 |
30 |
31 |
41 |
42 |
51 |
52 |
--------------------------------------------------------------------------------
/app/src/main/res/layout/activity_country.xml:
--------------------------------------------------------------------------------
1 |
2 |
8 |
9 |
19 |
20 |
23 |
24 |
--------------------------------------------------------------------------------
/app/src/main/res/layout/activity_main.xml:
--------------------------------------------------------------------------------
1 |
2 |
9 |
10 |
13 |
14 |
24 |
25 |
35 |
36 |
50 |
51 |
61 |
62 |
65 |
66 |
--------------------------------------------------------------------------------
/app/src/main/res/layout/activity_splash.xml:
--------------------------------------------------------------------------------
1 |
2 |
10 |
11 |
17 |
18 |
29 |
30 |
39 |
40 |
45 |
46 |
56 |
57 |
64 |
65 |
74 |
75 |
76 |
--------------------------------------------------------------------------------
/app/src/main/res/layout/activity_vpnlist.xml:
--------------------------------------------------------------------------------
1 |
2 |
8 |
9 |
17 |
18 |
21 |
22 |
23 |
--------------------------------------------------------------------------------
/app/src/main/res/layout/ads_banner.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
19 |
20 |
--------------------------------------------------------------------------------
/app/src/main/res/layout/toolbar_main.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
19 |
20 |
33 |
--------------------------------------------------------------------------------
/app/src/main/res/layout/view_item_country.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
19 |
20 |
35 |
36 |
41 |
42 |
50 |
51 |
--------------------------------------------------------------------------------
/app/src/main/res/layout/view_item_server.xml:
--------------------------------------------------------------------------------
1 |
2 |
15 |
16 |
22 |
23 |
32 |
33 |
41 |
42 |
48 |
49 |
55 |
56 |
57 |
58 |
67 |
68 |
--------------------------------------------------------------------------------
/app/src/main/res/menu/menu_toolbar_main.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
19 |
20 |
--------------------------------------------------------------------------------
/app/src/main/res/values-v21/styles.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
9 |
10 |
20 |
21 |
--------------------------------------------------------------------------------
/app/src/main/res/values/colors.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 | #00695c
4 | #003d33
5 | #439889
6 |
7 |
8 | #00000000
9 | #2499e0
10 | #F22938
11 | #FF4081
12 | #FFFFFF
13 | #000000
14 | #24D149
15 | #808080
16 | #27282D
17 | #3DB39E
18 | #272A2D
19 | #FF9800
20 | #C62828
21 |
22 | #E9E7E7
23 | @color/colorBaseBlack
24 |
25 | @color/colorBackgroundWhite
26 |
27 | @color/colorBackgroundWhite
28 | @color/colorPrimary
29 | @color/tab_background
30 |
31 | @color/colorBaseRed
32 | @color/colorBaseWhite
33 | @color/colorBaseBlack
34 | @color/colorBaseGreen
35 | @color/colorBaseDarkGrey
36 | @color/colorBaseDarkBlackBlue
37 |
38 | @color/colorBaseWhite
39 | @color/colorBaseRed
40 | @color/colorBaseBlack
41 | @color/colorBaseGreen
42 | @color/colorBaseDarkGrey
43 | @color/colorBaseDarkBlackBlue
44 | @color/colorBaseSeaBlue
45 | @color/colorBaseWhite
46 |
47 | @color/colorBaseGreenTosca
48 |
49 | #109D59
50 | #10CAA1
51 | @android:color/white
52 | #DE000000
53 | #8A000000
54 | #e3e3e3
55 | #cccccc
56 | #EEEEEE
57 | @color/grey_ee
58 | #f0a734
59 | #e93d25
60 | #17d478
61 | #f7fbfb
62 | #747d87
63 | #3af3ff
64 | #242e3a
65 | #00000000
66 |
67 | #d1395c
68 | #14a895
69 | #2278d4
70 | #a854d4
71 |
72 |
73 | #f98da5
74 | #8cf9eb
75 | #93c6fd
76 | #e4b5fc
77 |
78 |
79 | - @color/dot_light_screen1
80 | - @color/dot_light_screen2
81 | - @color/dot_light_screen3
82 | - @color/dot_light_screen4
83 |
84 |
85 |
86 | - @color/dot_dark_screen1
87 | - @color/dot_dark_screen2
88 | - @color/dot_dark_screen3
89 | - @color/dot_dark_screen4
90 |
91 |
92 | #ffffff
93 | #356690
94 |
95 | #1c3f60
96 | #7f7f7f
97 | #71bad2
98 | #ffffff
99 | #ffffff
100 |
101 | #cbecfd
102 | #356690
103 |
104 | #cbecfd
105 | #356690
106 |
107 | #ffffff
108 |
109 | #1c3f61
110 |
111 | #A7A7A7
112 |
113 | #cbecfd
114 | #f1dd77
115 |
116 | #cbecfd
117 | #356690
118 |
119 |
--------------------------------------------------------------------------------
/app/src/main/res/values/dimens.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 | 30dp
4 | 20dp
5 | 120dp
6 | 30dp
7 | 16dp
8 | 40dp
9 |
10 |
11 |
12 |
13 |
14 |
15 | 16dp
16 | 16dp
17 | 8dp
18 | 176dp
19 | 16dp
20 | 60dp
21 |
22 | 12dp
23 | 64dp
24 | 32dp
25 | 24dp
26 | 16dp
27 | 8dp
28 | 4dp
29 |
30 | 180dp
31 |
32 |
33 | 1dp
34 | 0dp
35 |
36 | 50dp
37 | 220dp
38 | 125dp
39 | 60dp
40 | 50dp
41 | 5dip
42 |
43 |
44 | 24sp
45 | 24sp
46 | 20sp
47 | 18sp
48 | 16sp
49 | 12sp
50 | 10sp
51 |
52 | 95dp
53 | 200dp
54 | 150dp
55 | 2dp
56 | 20dp
57 | 100dp
58 | 72dp
59 | 96dp
60 | 360dp
61 | 120dp
62 | 300dp
63 | 200dp
64 | 132dp
65 |
66 | 144dp
67 |
68 |
69 |
70 |
--------------------------------------------------------------------------------
/app/src/main/res/values/reference.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 | @android:drawable/ic_menu_close_clear_cancel
4 | @android:drawable/ic_media_play
5 | @android:drawable/ic_media_pause
6 |
--------------------------------------------------------------------------------
/app/src/main/res/values/styles.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
14 |
15 |
16 |
25 |
26 |
33 |
34 |
37 |
38 |
49 |
50 |
59 |
60 |
67 |
68 |
77 |
78 |
--------------------------------------------------------------------------------
/app/src/main/res/xml/preferences.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
5 |
10 |
15 |
16 |
18 |
23 |
24 |
27 |
32 |
36 |
37 |
--------------------------------------------------------------------------------
/build.gradle:
--------------------------------------------------------------------------------
1 | // Top-level build file where you can add configuration options common to all sub-projects/modules.
2 |
3 | buildscript {
4 |
5 | ext {
6 | // project settings
7 | nameApp = "Viprox VPN"
8 | nameAPK = nameApp.toLowerCase().replace(" ", "-")
9 |
10 | def appDomain = "com"
11 | def appDevConsole = "frogobox"
12 | def appName = "viprox"
13 |
14 | def versionMajor = 1
15 | def versionMinor = 0
16 | def versionPatch = 1
17 |
18 | projectCompileSdk = 31
19 | projectMinSdk = 21
20 | projectTargetSdk = projectCompileSdk
21 |
22 | projectApplicationId = "$appDomain.$appDevConsole.$appName"
23 | projectVersionCode = (versionMajor * 100) + (versionMinor * 10) + (versionPatch * 1)
24 | projectVersionName = "$versionMajor.$versionMinor.$versionPatch"
25 |
26 | // dependencies version
27 | kotlin_version = '1.5.21'
28 | koin_version = "3.1.1"
29 | room_version = "2.3.0"
30 |
31 | compose_version = "1.0.1"
32 | activity_ktx_version = "1.3.1"
33 | fragment_ktx_version = '1.3.6'
34 | }
35 |
36 | repositories {
37 | google()
38 | jcenter()
39 | mavenCentral()
40 | }
41 |
42 | dependencies {
43 | classpath 'com.android.tools.build:gradle:7.0.2'
44 | classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version"
45 |
46 | // NOTE: Do not place your application dependencies here; they belong
47 | // in the individual module build.gradle files
48 | }
49 | }
50 |
51 | allprojects {
52 | repositories {
53 | google()
54 | jcenter()
55 | mavenCentral()
56 | maven { url "https://jitpack.io" }
57 | }
58 | }
59 |
60 | task clean(type: Delete) {
61 | delete rootProject.buildDir
62 | }
63 |
--------------------------------------------------------------------------------
/docs/image/ss_1.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/amirisback/vpn/cf6770030bc5d3e289a75e739f2e41a1a1d9e654/docs/image/ss_1.png
--------------------------------------------------------------------------------
/docs/image/ss_2.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/amirisback/vpn/cf6770030bc5d3e289a75e739f2e41a1a1d9e654/docs/image/ss_2.png
--------------------------------------------------------------------------------
/docs/image/ss_3.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/amirisback/vpn/cf6770030bc5d3e289a75e739f2e41a1a1d9e654/docs/image/ss_3.png
--------------------------------------------------------------------------------
/gradle.properties:
--------------------------------------------------------------------------------
1 | # Project-wide Gradle settings.
2 |
3 | # IDE (e.g. Android Studio) users:
4 | # Gradle settings configured through the IDE *will override*
5 | # any settings specified in this file.
6 |
7 | # For more details on how to configure your build environment visit
8 | # http://www.gradle.org/docs/current/userguide/build_environment.html
9 |
10 | # Specifies the JVM arguments used for the daemon process.
11 | # The setting is particularly useful for tweaking memory settings.
12 | # Default value: -Xmx10248m -XX:MaxPermSize=256m
13 | # org.gradle.jvmargs=-Xmx2048m -XX:MaxPermSize=512m -XX:+HeapDumpOnOutOfMemoryError -Dfile.encoding=UTF-8
14 |
15 | # When configured, Gradle will run in incubating parallel mode.
16 | # This option should only be used with decoupled projects. More details, visit
17 | # http://www.gradle.org/docs/current/userguide/multi_project_builds.html#sec:decoupled_projects
18 | # org.gradle.parallel=true
19 | android.enableJetifier=true
20 | android.useAndroidX=true
--------------------------------------------------------------------------------
/gradle/wrapper/gradle-wrapper.jar:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/amirisback/vpn/cf6770030bc5d3e289a75e739f2e41a1a1d9e654/gradle/wrapper/gradle-wrapper.jar
--------------------------------------------------------------------------------
/gradle/wrapper/gradle-wrapper.properties:
--------------------------------------------------------------------------------
1 | #Sun Oct 27 21:02:38 ICT 2019
2 | distributionBase=GRADLE_USER_HOME
3 | distributionPath=wrapper/dists
4 | zipStoreBase=GRADLE_USER_HOME
5 | zipStorePath=wrapper/dists
6 | distributionUrl=https\://services.gradle.org/distributions/gradle-7.0.2-bin.zip
7 |
--------------------------------------------------------------------------------
/gradlew:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env bash
2 |
3 | ##############################################################################
4 | ##
5 | ## Gradle start up script for UN*X
6 | ##
7 | ##############################################################################
8 |
9 | # Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
10 | DEFAULT_JVM_OPTS=""
11 |
12 | APP_NAME="Gradle"
13 | APP_BASE_NAME=`basename "$0"`
14 |
15 | # Use the maximum available, or set MAX_FD != -1 to use that value.
16 | MAX_FD="maximum"
17 |
18 | warn ( ) {
19 | echo "$*"
20 | }
21 |
22 | die ( ) {
23 | echo
24 | echo "$*"
25 | echo
26 | exit 1
27 | }
28 |
29 | # OS specific support (must be 'true' or 'false').
30 | cygwin=false
31 | msys=false
32 | darwin=false
33 | case "`uname`" in
34 | CYGWIN* )
35 | cygwin=true
36 | ;;
37 | Darwin* )
38 | darwin=true
39 | ;;
40 | MINGW* )
41 | msys=true
42 | ;;
43 | esac
44 |
45 | # Attempt to set APP_HOME
46 | # Resolve links: $0 may be a link
47 | PRG="$0"
48 | # Need this for relative symlinks.
49 | while [ -h "$PRG" ] ; do
50 | ls=`ls -ld "$PRG"`
51 | link=`expr "$ls" : '.*-> \(.*\)$'`
52 | if expr "$link" : '/.*' > /dev/null; then
53 | PRG="$link"
54 | else
55 | PRG=`dirname "$PRG"`"/$link"
56 | fi
57 | done
58 | SAVED="`pwd`"
59 | cd "`dirname \"$PRG\"`/" >/dev/null
60 | APP_HOME="`pwd -P`"
61 | cd "$SAVED" >/dev/null
62 |
63 | CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar
64 |
65 | # Determine the Java command to use to start the JVM.
66 | if [ -n "$JAVA_HOME" ] ; then
67 | if [ -x "$JAVA_HOME/jre/sh/java" ] ; then
68 | # IBM's JDK on AIX uses strange locations for the executables
69 | JAVACMD="$JAVA_HOME/jre/sh/java"
70 | else
71 | JAVACMD="$JAVA_HOME/bin/java"
72 | fi
73 | if [ ! -x "$JAVACMD" ] ; then
74 | die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME
75 |
76 | Please set the JAVA_HOME variable in your environment to match the
77 | location of your Java installation."
78 | fi
79 | else
80 | JAVACMD="java"
81 | which java >/dev/null 2>&1 || die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
82 |
83 | Please set the JAVA_HOME variable in your environment to match the
84 | location of your Java installation."
85 | fi
86 |
87 | # Increase the maximum file descriptors if we can.
88 | if [ "$cygwin" = "false" -a "$darwin" = "false" ] ; then
89 | MAX_FD_LIMIT=`ulimit -H -n`
90 | if [ $? -eq 0 ] ; then
91 | if [ "$MAX_FD" = "maximum" -o "$MAX_FD" = "max" ] ; then
92 | MAX_FD="$MAX_FD_LIMIT"
93 | fi
94 | ulimit -n $MAX_FD
95 | if [ $? -ne 0 ] ; then
96 | warn "Could not set maximum file descriptor limit: $MAX_FD"
97 | fi
98 | else
99 | warn "Could not query maximum file descriptor limit: $MAX_FD_LIMIT"
100 | fi
101 | fi
102 |
103 | # For Darwin, add options to specify how the application appears in the dock
104 | if $darwin; then
105 | GRADLE_OPTS="$GRADLE_OPTS \"-Xdock:name=$APP_NAME\" \"-Xdock:icon=$APP_HOME/media/gradle.icns\""
106 | fi
107 |
108 | # For Cygwin, switch paths to Windows format before running java
109 | if $cygwin ; then
110 | APP_HOME=`cygpath --path --mixed "$APP_HOME"`
111 | CLASSPATH=`cygpath --path --mixed "$CLASSPATH"`
112 | JAVACMD=`cygpath --unix "$JAVACMD"`
113 |
114 | # We build the pattern for arguments to be converted via cygpath
115 | ROOTDIRSRAW=`find -L / -maxdepth 1 -mindepth 1 -type d 2>/dev/null`
116 | SEP=""
117 | for dir in $ROOTDIRSRAW ; do
118 | ROOTDIRS="$ROOTDIRS$SEP$dir"
119 | SEP="|"
120 | done
121 | OURCYGPATTERN="(^($ROOTDIRS))"
122 | # Add a user-defined pattern to the cygpath arguments
123 | if [ "$GRADLE_CYGPATTERN" != "" ] ; then
124 | OURCYGPATTERN="$OURCYGPATTERN|($GRADLE_CYGPATTERN)"
125 | fi
126 | # Now convert the arguments - kludge to limit ourselves to /bin/sh
127 | i=0
128 | for arg in "$@" ; do
129 | CHECK=`echo "$arg"|egrep -c "$OURCYGPATTERN" -`
130 | CHECK2=`echo "$arg"|egrep -c "^-"` ### Determine if an option
131 |
132 | if [ $CHECK -ne 0 ] && [ $CHECK2 -eq 0 ] ; then ### Added a condition
133 | eval `echo args$i`=`cygpath --path --ignore --mixed "$arg"`
134 | else
135 | eval `echo args$i`="\"$arg\""
136 | fi
137 | i=$((i+1))
138 | done
139 | case $i in
140 | (0) set -- ;;
141 | (1) set -- "$args0" ;;
142 | (2) set -- "$args0" "$args1" ;;
143 | (3) set -- "$args0" "$args1" "$args2" ;;
144 | (4) set -- "$args0" "$args1" "$args2" "$args3" ;;
145 | (5) set -- "$args0" "$args1" "$args2" "$args3" "$args4" ;;
146 | (6) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" ;;
147 | (7) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" ;;
148 | (8) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" ;;
149 | (9) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" "$args8" ;;
150 | esac
151 | fi
152 |
153 | # Split up the JVM_OPTS And GRADLE_OPTS values into an array, following the shell quoting and substitution rules
154 | function splitJvmOpts() {
155 | JVM_OPTS=("$@")
156 | }
157 | eval splitJvmOpts $DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS
158 | JVM_OPTS[${#JVM_OPTS[*]}]="-Dorg.gradle.appname=$APP_BASE_NAME"
159 |
160 | exec "$JAVACMD" "${JVM_OPTS[@]}" -classpath "$CLASSPATH" org.gradle.wrapper.GradleWrapperMain "$@"
161 |
--------------------------------------------------------------------------------
/gradlew.bat:
--------------------------------------------------------------------------------
1 | @if "%DEBUG%" == "" @echo off
2 | @rem ##########################################################################
3 | @rem
4 | @rem Gradle startup script for Windows
5 | @rem
6 | @rem ##########################################################################
7 |
8 | @rem Set local scope for the variables with windows NT shell
9 | if "%OS%"=="Windows_NT" setlocal
10 |
11 | @rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
12 | set DEFAULT_JVM_OPTS=
13 |
14 | set DIRNAME=%~dp0
15 | if "%DIRNAME%" == "" set DIRNAME=.
16 | set APP_BASE_NAME=%~n0
17 | set APP_HOME=%DIRNAME%
18 |
19 | @rem Find java.exe
20 | if defined JAVA_HOME goto findJavaFromJavaHome
21 |
22 | set JAVA_EXE=java.exe
23 | %JAVA_EXE% -version >NUL 2>&1
24 | if "%ERRORLEVEL%" == "0" goto init
25 |
26 | echo.
27 | echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
28 | echo.
29 | echo Please set the JAVA_HOME variable in your environment to match the
30 | echo location of your Java installation.
31 |
32 | goto fail
33 |
34 | :findJavaFromJavaHome
35 | set JAVA_HOME=%JAVA_HOME:"=%
36 | set JAVA_EXE=%JAVA_HOME%/bin/java.exe
37 |
38 | if exist "%JAVA_EXE%" goto init
39 |
40 | echo.
41 | echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME%
42 | echo.
43 | echo Please set the JAVA_HOME variable in your environment to match the
44 | echo location of your Java installation.
45 |
46 | goto fail
47 |
48 | :init
49 | @rem Get command-line arguments, handling Windowz variants
50 |
51 | if not "%OS%" == "Windows_NT" goto win9xME_args
52 | if "%@eval[2+2]" == "4" goto 4NT_args
53 |
54 | :win9xME_args
55 | @rem Slurp the command line arguments.
56 | set CMD_LINE_ARGS=
57 | set _SKIP=2
58 |
59 | :win9xME_args_slurp
60 | if "x%~1" == "x" goto execute
61 |
62 | set CMD_LINE_ARGS=%*
63 | goto execute
64 |
65 | :4NT_args
66 | @rem Get arguments from the 4NT Shell from JP Software
67 | set CMD_LINE_ARGS=%$
68 |
69 | :execute
70 | @rem Setup the command line
71 |
72 | set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar
73 |
74 | @rem Execute Gradle
75 | "%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %CMD_LINE_ARGS%
76 |
77 | :end
78 | @rem End local scope for the variables with windows NT shell
79 | if "%ERRORLEVEL%"=="0" goto mainEnd
80 |
81 | :fail
82 | rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of
83 | rem the _cmd.exe /c_ return code!
84 | if not "" == "%GRADLE_EXIT_CONSOLE%" exit 1
85 | exit /b 1
86 |
87 | :mainEnd
88 | if "%OS%"=="Windows_NT" endlocal
89 |
90 | :omega
91 |
--------------------------------------------------------------------------------
/settings.gradle:
--------------------------------------------------------------------------------
1 | include ':app'
2 |
--------------------------------------------------------------------------------
/travis.yml:
--------------------------------------------------------------------------------
1 | language: android
2 |
3 | before_install:
4 | - chmod +x gradlew
5 |
6 | script: ./gradlew
7 |
8 | android:
9 | components:
10 | # Uncomment the lines below if you want to
11 | # use the latest revision of Android SDK Tools
12 | - platform-tools
13 | - tools
14 |
15 | # The BuildTools version used by your project
16 | - build-tools-28.0.3
17 |
18 | # The SDK version used to compile your project
19 | - android-28
20 |
--------------------------------------------------------------------------------