Skip to content

Commit 92900dd

Browse files
committed
Merge branch 'develop' into feature/v2ray
2 parents a11c1f9 + 1b4e576 commit 92900dd

63 files changed

Lines changed: 1612 additions & 256 deletions

File tree

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

.gitmodules

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@
33
url = https://git.zx2c4.com/wireguard-tools
44
[submodule "core/src/main/cpp/openvpn"]
55
path = core/src/main/cpp/openvpn
6-
url = https://github.com/schwabe/openvpn
6+
url = https://github.com/ivpn/android-openvpn
77
[submodule "core/src/main/cpp/openssl"]
88
path = core/src/main/cpp/openssl
99
url = https://github.com/schwabe/platform_external_openssl

CHANGELOG.md

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,18 @@
22

33
All notable changes to this project will be documented in this file.
44

5+
## Version 2.10.7 - 2024-02-12
6+
7+
[NEW] Device Management
8+
[IMPROVED] Increased timeout for API requests
9+
10+
[Download IVPN Client v2.10.7](https://www.ivpn.net/releases/android/IVPNv2.10.7site.apk)
11+
SHA256: e091ee87d73eda39036854ca02be2c0451502730043fe39a8242403124965ceb
12+
13+
## Version 2.10.6 - 2023-12-18
14+
15+
[FIXED] Crash when opening the app on F-Droid
16+
517
## Version 2.10.5 - 2023-12-13
618

719
[IMPROVED] Show non-launchable and system apps in the Split Tunneling list

core/build.gradle

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -28,10 +28,10 @@ android {
2828

2929
compileSdkVersion 33
3030
defaultConfig {
31-
minSdkVersion 21
31+
minSdkVersion 23
3232
targetSdkVersion 33
33-
versionCode 128
34-
versionName "2.10.5"
33+
versionCode 130
34+
versionName "2.10.7"
3535
ndkVersion "25.1.8937393"
3636

3737
testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"

core/src/main/AndroidManifest.xml

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -52,6 +52,8 @@
5252
tools:overrideLibrary="com.google.zxing.client.android"
5353
tools:ignore="GoogleAppIndexingWarning, HardcodedDebugMode">
5454

55+
<meta-data android:name="io.sentry.auto-init" android:value="false" />
56+
5557
<activity
5658
android:name="net.ivpn.core.v2.timepicker.TimePickerActivity"
5759
android:theme="@style/AppTheme.Transparent" />

core/src/main/java/net/ivpn/core/common/Mapper.kt

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,7 @@ import net.ivpn.core.rest.data.ServersListResponse
3030
import net.ivpn.core.rest.data.model.AntiTracker
3131
import net.ivpn.core.rest.data.model.Port
3232
import net.ivpn.core.rest.data.model.Server
33+
import net.ivpn.core.rest.data.session.SessionErrorResponse
3334
import net.ivpn.core.rest.data.wireguard.ErrorResponse
3435
import java.util.*
3536

@@ -115,4 +116,15 @@ object Mapper {
115116
null
116117
}
117118
}
119+
120+
@JvmStatic
121+
fun sessionErrorResponseFrom(json: String?): SessionErrorResponse? {
122+
return if (json == null || json.isEmpty()) null else try {
123+
Gson().fromJson(json, SessionErrorResponse::class.java)
124+
} catch (jsonSyntaxException: JsonSyntaxException) {
125+
null
126+
} catch (jsonSyntaxException: IllegalStateException) {
127+
null
128+
}
129+
}
118130
}

core/src/main/java/net/ivpn/core/common/prefs/EncryptedUserPreference.kt

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -44,6 +44,8 @@ class EncryptedUserPreference @Inject constructor(val preference: Preference) {
4444
private const val SESSION_TOKEN = "SESSION_TOKEN"
4545
private const val SESSION_VPN_USERNAME = "SESSION_VPN_USERNAME"
4646
private const val SESSION_VPN_PASSWORD = "SESSION_VPN_PASSWORD"
47+
private const val DEVICE_MANAGEMENT = "DEVICE_MANAGEMENT"
48+
private const val DEVICE_NAME = "DEVICE_NAME"
4749

4850
private const val BLANK_USERNAME = "BLANK_USERNAME"
4951
private const val BLANK_USERNAME_GENERATED_DATE = "BLANK_USERNAME_GENERATED_DATE"
@@ -93,6 +95,18 @@ class EncryptedUserPreference @Inject constructor(val preference: Preference) {
9395
.apply()
9496
}
9597

98+
fun putDeviceManagement(deviceManagement: Boolean) {
99+
sharedPreferences.edit()
100+
.putBoolean(DEVICE_MANAGEMENT, deviceManagement)
101+
.apply()
102+
}
103+
104+
fun putDeviceName(deviceName: String?) {
105+
sharedPreferences.edit()
106+
.putString(DEVICE_NAME, deviceName)
107+
.apply()
108+
}
109+
96110
fun putCapabilityMultiHop(isAvailable: Boolean) {
97111
sharedPreferences.edit()
98112
.putBoolean(USER_MULTI_HOP, isAvailable)
@@ -139,6 +153,14 @@ class EncryptedUserPreference @Inject constructor(val preference: Preference) {
139153
return sharedPreferences.getString(SESSION_VPN_PASSWORD, "")
140154
}
141155

156+
fun getDeviceManagement(): Boolean {
157+
return sharedPreferences.getBoolean(DEVICE_MANAGEMENT, false)
158+
}
159+
160+
fun getDeviceName(): String? {
161+
return sharedPreferences.getString(DEVICE_NAME, "")
162+
}
163+
142164
fun getSessionToken(): String {
143165
return sharedPreferences.getString(SESSION_TOKEN, "") ?: ""
144166
}

core/src/main/java/net/ivpn/core/common/session/SessionController.kt

Lines changed: 25 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -37,10 +37,10 @@ import net.ivpn.core.rest.Responses
3737
import net.ivpn.core.rest.data.model.ServiceStatus
3838
import net.ivpn.core.rest.data.model.WireGuard
3939
import net.ivpn.core.rest.data.session.*
40-
import net.ivpn.core.rest.data.wireguard.ErrorResponse
4140
import net.ivpn.core.rest.requests.common.Request
4241
import net.ivpn.core.rest.requests.common.RequestWrapper
4342
import net.ivpn.core.v2.login.LoginViewModel
43+
import net.ivpn.core.v2.viewmodel.AccountViewModel
4444
import net.ivpn.core.v2.viewmodel.ViewModelCleaner
4545
import net.ivpn.core.vpn.Protocol
4646
import net.ivpn.core.vpn.ProtocolController
@@ -109,7 +109,7 @@ class SessionController @Inject constructor(
109109
}
110110

111111
private fun innerCreateSession(body: SessionNewRequestBody, keys: Keypair?) {
112-
sessionNewRequest = Request(settings, clientFactory, serversRepository, Request.Duration.SHORT, RequestWrapper.IpMode.IPv4)
112+
sessionNewRequest = Request(settings, clientFactory, serversRepository, Request.Duration.LONG, RequestWrapper.IpMode.IPv4)
113113

114114
sessionNewRequest?.start({ api: IVPNApi -> api.newSession(body) },
115115
object : RequestListener<SessionNewResponse> {
@@ -125,7 +125,10 @@ class SessionController @Inject constructor(
125125

126126
override fun onError(error: String) {
127127
LOGGER.error("On create session error = $error")
128-
val errorResponse = Mapper.errorResponseFrom(error)
128+
val errorResponse = Mapper.sessionErrorResponseFrom(error)
129+
if (errorResponse != null) {
130+
errorResponse.isAccountNewStyle = AccountViewModel.isNewStyleAccount(body.username)
131+
}
129132
onCreateError(null, errorResponse)
130133
}
131134
})
@@ -146,6 +149,7 @@ class SessionController @Inject constructor(
146149
if (response.status != null && response.status == Responses.SUCCESS) {
147150
LOGGER.info("Session status response received successfully")
148151
LOGGER.info(response.toString())
152+
userPreference.putDeviceName(response.deviceName)
149153
saveSessionStatus(response.serviceStatus)
150154
onUpdateSuccess()
151155
}
@@ -158,14 +162,14 @@ class SessionController @Inject constructor(
158162

159163
override fun onError(error: String) {
160164
LOGGER.error("Error while getting account status to see the confirmation$error")
161-
val errorResponse = Mapper.errorResponseFrom(error)
165+
val errorResponse = Mapper.sessionErrorResponseFrom(error)
162166
errorResponse?.let {
163167
if (it.status == Responses.SERVICE_IS_NOT_ACTIVE) {
164168
userPreference.putIsActive(false)
165169
}
166170
if ((it.status == Responses.SESSION_NOT_FOUND)) {
167171
clearSessionData()
168-
onRemoveSuccess()
172+
onDeviceLoggedOut()
169173
}
170174
}
171175
onUpdateError(null, errorResponse)
@@ -179,7 +183,7 @@ class SessionController @Inject constructor(
179183

180184
val token = userPreference.getSessionToken()
181185
val requestBody = DeleteSessionRequestBody(token)
182-
deleteSessionRequest = Request(settings, clientFactory, serversRepository, Request.Duration.SHORT, RequestWrapper.IpMode.IPv4)
186+
deleteSessionRequest = Request(settings, clientFactory, serversRepository, Request.Duration.LONG, RequestWrapper.IpMode.IPv4)
183187

184188
deleteSessionRequest?.start({ api: IVPNApi -> api.deleteSession(requestBody) },
185189
object : RequestListener<DeleteSessionResponse?> {
@@ -234,7 +238,7 @@ class SessionController @Inject constructor(
234238
}
235239
}
236240

237-
private fun onCreateError(throwable: Throwable?, errorResponse: ErrorResponse?) {
241+
private fun onCreateError(throwable: Throwable?, errorResponse: SessionErrorResponse?) {
238242
for (listener in listeners) {
239243
listener.onCreateError(throwable, errorResponse)
240244
}
@@ -246,12 +250,18 @@ class SessionController @Inject constructor(
246250
}
247251
}
248252

249-
private fun onUpdateError(throwable: Throwable?, errorResponse: ErrorResponse?) {
253+
private fun onUpdateError(throwable: Throwable?, errorResponse: SessionErrorResponse?) {
250254
for (listener in listeners) {
251255
listener.onUpdateError(throwable, errorResponse)
252256
}
253257
}
254258

259+
private fun onDeviceLoggedOut() {
260+
for (listener in listeners) {
261+
listener.onDeviceLoggedOut()
262+
}
263+
}
264+
255265
fun clearData() {
256266
IVPNApplication.appComponent.provideComponentUtil().resetComponents()
257267
ViewModelCleaner().fullClean()
@@ -292,6 +302,7 @@ class SessionController @Inject constructor(
292302
userPreference.putSessionToken(response.token)
293303
userPreference.putSessionUsername(response.vpnUsername)
294304
userPreference.putSessionPassword(response.vpnPassword)
305+
userPreference.putDeviceName(response.deviceName)
295306
saveSessionStatus(response.serviceStatus)
296307
}
297308

@@ -304,6 +315,9 @@ class SessionController @Inject constructor(
304315
userPreference.putCurrentPlan(serviceStatus.currentPlan)
305316
userPreference.putPaymentMethod(serviceStatus.paymentMethod)
306317
userPreference.putIsActive(serviceStatus.isActive)
318+
serviceStatus.deviceManagement?.let {
319+
userPreference.putDeviceManagement(it)
320+
}
307321
if (serviceStatus.capabilities != null) {
308322
userPreference.putIsUserOnPrivateEmailBeta(serviceStatus.capabilities.contains(Responses.PRIVATE_EMAILS))
309323
val multiHopCapabilities = serviceStatus.capabilities.contains(Responses.MULTI_HOP)
@@ -348,15 +362,11 @@ class SessionController @Inject constructor(
348362

349363
interface SessionListener {
350364
fun onRemoveSuccess()
351-
352365
fun onRemoveError()
353-
354366
fun onCreateSuccess(response: SessionNewResponse)
355-
356-
fun onCreateError(throwable: Throwable?, errorResponse: ErrorResponse?)
357-
367+
fun onCreateError(throwable: Throwable?, errorResponse: SessionErrorResponse?)
358368
fun onUpdateSuccess()
359-
360-
fun onUpdateError(throwable: Throwable?, errorResponse: ErrorResponse?)
369+
fun onUpdateError(throwable: Throwable?, errorResponse: SessionErrorResponse?)
370+
fun onDeviceLoggedOut()
361371
}
362372
}

core/src/main/java/net/ivpn/core/common/session/SessionListenerImpl.kt

Lines changed: 5 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -23,25 +23,22 @@ package net.ivpn.core.common.session
2323
*/
2424

2525
import net.ivpn.core.common.session.SessionController.*
26+
import net.ivpn.core.rest.data.session.SessionErrorResponse
2627
import net.ivpn.core.rest.data.session.SessionNewResponse
27-
import net.ivpn.core.rest.data.wireguard.ErrorResponse
2828

2929
open class SessionListenerImpl: SessionListener {
3030
override fun onRemoveSuccess() {
3131
}
32-
3332
override fun onRemoveError() {
3433
}
35-
3634
override fun onCreateSuccess(response: SessionNewResponse) {
3735
}
38-
39-
override fun onCreateError(throwable: Throwable?, errorResponse: ErrorResponse?) {
36+
override fun onCreateError(throwable: Throwable?, errorResponse: SessionErrorResponse?) {
4037
}
41-
4238
override fun onUpdateSuccess() {
4339
}
44-
45-
override fun onUpdateError(throwable: Throwable?, errorResponse: ErrorResponse?) {
40+
override fun onUpdateError(throwable: Throwable?, errorResponse: SessionErrorResponse?) {
41+
}
42+
override fun onDeviceLoggedOut() {
4643
}
4744
}

core/src/main/java/net/ivpn/core/rest/data/model/ServiceStatus.java

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -53,6 +53,9 @@ public class ServiceStatus {
5353
@SerializedName("capabilities")
5454
@Expose
5555
private List<String> capabilities = null;
56+
@SerializedName("device_management")
57+
@Expose
58+
private Boolean deviceManagement;
5659

5760
public Boolean getIsActive() {
5861
return isActive;
@@ -118,6 +121,10 @@ public void setCurrentPlan(String currentPlan) {
118121
this.currentPlan = currentPlan;
119122
}
120123

124+
public Boolean getDeviceManagement() {
125+
return deviceManagement;
126+
}
127+
121128
@Override
122129
public String toString() {
123130
return "ServiceStatus{" +
@@ -128,6 +135,7 @@ public String toString() {
128135
", isRenewable='" + isRenewable + '\'' +
129136
", willAutoRebill='" + willAutoRebill + '\'' +
130137
", isOnFreeTrial='" + isOnFreeTrial + '\'' +
138+
", deviceManagement='" + deviceManagement + '\'' +
131139
", capabilities=" + capabilities +
132140
'}';
133141
}

0 commit comments

Comments
 (0)