Skip to content

Commit

Permalink
Merge branch 'develop' into feature/v2ray
Browse files Browse the repository at this point in the history
  • Loading branch information
jurajhilje committed Jun 3, 2024
2 parents a11c1f9 + 1b4e576 commit 92900dd
Show file tree
Hide file tree
Showing 63 changed files with 1,612 additions and 256 deletions.
2 changes: 1 addition & 1 deletion .gitmodules
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
url = https://git.zx2c4.com/wireguard-tools
[submodule "core/src/main/cpp/openvpn"]
path = core/src/main/cpp/openvpn
url = https://github.com/schwabe/openvpn
url = https://github.com/ivpn/android-openvpn
[submodule "core/src/main/cpp/openssl"]
path = core/src/main/cpp/openssl
url = https://github.com/schwabe/platform_external_openssl
Expand Down
12 changes: 12 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,18 @@

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

## Version 2.10.7 - 2024-02-12

[NEW] Device Management
[IMPROVED] Increased timeout for API requests

[Download IVPN Client v2.10.7](https://www.ivpn.net/releases/android/IVPNv2.10.7site.apk)
SHA256: e091ee87d73eda39036854ca02be2c0451502730043fe39a8242403124965ceb

## Version 2.10.6 - 2023-12-18

[FIXED] Crash when opening the app on F-Droid

## Version 2.10.5 - 2023-12-13

[IMPROVED] Show non-launchable and system apps in the Split Tunneling list
Expand Down
6 changes: 3 additions & 3 deletions core/build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -28,10 +28,10 @@ android {

compileSdkVersion 33
defaultConfig {
minSdkVersion 21
minSdkVersion 23
targetSdkVersion 33
versionCode 128
versionName "2.10.5"
versionCode 130
versionName "2.10.7"
ndkVersion "25.1.8937393"

testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"
Expand Down
2 changes: 2 additions & 0 deletions core/src/main/AndroidManifest.xml
Original file line number Diff line number Diff line change
Expand Up @@ -52,6 +52,8 @@
tools:overrideLibrary="com.google.zxing.client.android"
tools:ignore="GoogleAppIndexingWarning, HardcodedDebugMode">

<meta-data android:name="io.sentry.auto-init" android:value="false" />

<activity
android:name="net.ivpn.core.v2.timepicker.TimePickerActivity"
android:theme="@style/AppTheme.Transparent" />
Expand Down
2 changes: 1 addition & 1 deletion core/src/main/cpp/openvpn
12 changes: 12 additions & 0 deletions core/src/main/java/net/ivpn/core/common/Mapper.kt
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,7 @@ import net.ivpn.core.rest.data.ServersListResponse
import net.ivpn.core.rest.data.model.AntiTracker
import net.ivpn.core.rest.data.model.Port
import net.ivpn.core.rest.data.model.Server
import net.ivpn.core.rest.data.session.SessionErrorResponse
import net.ivpn.core.rest.data.wireguard.ErrorResponse
import java.util.*

Expand Down Expand Up @@ -115,4 +116,15 @@ object Mapper {
null
}
}

@JvmStatic
fun sessionErrorResponseFrom(json: String?): SessionErrorResponse? {
return if (json == null || json.isEmpty()) null else try {
Gson().fromJson(json, SessionErrorResponse::class.java)
} catch (jsonSyntaxException: JsonSyntaxException) {
null
} catch (jsonSyntaxException: IllegalStateException) {
null
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -44,6 +44,8 @@ class EncryptedUserPreference @Inject constructor(val preference: Preference) {
private const val SESSION_TOKEN = "SESSION_TOKEN"
private const val SESSION_VPN_USERNAME = "SESSION_VPN_USERNAME"
private const val SESSION_VPN_PASSWORD = "SESSION_VPN_PASSWORD"
private const val DEVICE_MANAGEMENT = "DEVICE_MANAGEMENT"
private const val DEVICE_NAME = "DEVICE_NAME"

private const val BLANK_USERNAME = "BLANK_USERNAME"
private const val BLANK_USERNAME_GENERATED_DATE = "BLANK_USERNAME_GENERATED_DATE"
Expand Down Expand Up @@ -93,6 +95,18 @@ class EncryptedUserPreference @Inject constructor(val preference: Preference) {
.apply()
}

fun putDeviceManagement(deviceManagement: Boolean) {
sharedPreferences.edit()
.putBoolean(DEVICE_MANAGEMENT, deviceManagement)
.apply()
}

fun putDeviceName(deviceName: String?) {
sharedPreferences.edit()
.putString(DEVICE_NAME, deviceName)
.apply()
}

fun putCapabilityMultiHop(isAvailable: Boolean) {
sharedPreferences.edit()
.putBoolean(USER_MULTI_HOP, isAvailable)
Expand Down Expand Up @@ -139,6 +153,14 @@ class EncryptedUserPreference @Inject constructor(val preference: Preference) {
return sharedPreferences.getString(SESSION_VPN_PASSWORD, "")
}

fun getDeviceManagement(): Boolean {
return sharedPreferences.getBoolean(DEVICE_MANAGEMENT, false)
}

fun getDeviceName(): String? {
return sharedPreferences.getString(DEVICE_NAME, "")
}

fun getSessionToken(): String {
return sharedPreferences.getString(SESSION_TOKEN, "") ?: ""
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -37,10 +37,10 @@ import net.ivpn.core.rest.Responses
import net.ivpn.core.rest.data.model.ServiceStatus
import net.ivpn.core.rest.data.model.WireGuard
import net.ivpn.core.rest.data.session.*
import net.ivpn.core.rest.data.wireguard.ErrorResponse
import net.ivpn.core.rest.requests.common.Request
import net.ivpn.core.rest.requests.common.RequestWrapper
import net.ivpn.core.v2.login.LoginViewModel
import net.ivpn.core.v2.viewmodel.AccountViewModel
import net.ivpn.core.v2.viewmodel.ViewModelCleaner
import net.ivpn.core.vpn.Protocol
import net.ivpn.core.vpn.ProtocolController
Expand Down Expand Up @@ -109,7 +109,7 @@ class SessionController @Inject constructor(
}

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

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

override fun onError(error: String) {
LOGGER.error("On create session error = $error")
val errorResponse = Mapper.errorResponseFrom(error)
val errorResponse = Mapper.sessionErrorResponseFrom(error)
if (errorResponse != null) {
errorResponse.isAccountNewStyle = AccountViewModel.isNewStyleAccount(body.username)
}
onCreateError(null, errorResponse)
}
})
Expand All @@ -146,6 +149,7 @@ class SessionController @Inject constructor(
if (response.status != null && response.status == Responses.SUCCESS) {
LOGGER.info("Session status response received successfully")
LOGGER.info(response.toString())
userPreference.putDeviceName(response.deviceName)
saveSessionStatus(response.serviceStatus)
onUpdateSuccess()
}
Expand All @@ -158,14 +162,14 @@ class SessionController @Inject constructor(

override fun onError(error: String) {
LOGGER.error("Error while getting account status to see the confirmation$error")
val errorResponse = Mapper.errorResponseFrom(error)
val errorResponse = Mapper.sessionErrorResponseFrom(error)
errorResponse?.let {
if (it.status == Responses.SERVICE_IS_NOT_ACTIVE) {
userPreference.putIsActive(false)
}
if ((it.status == Responses.SESSION_NOT_FOUND)) {
clearSessionData()
onRemoveSuccess()
onDeviceLoggedOut()
}
}
onUpdateError(null, errorResponse)
Expand All @@ -179,7 +183,7 @@ class SessionController @Inject constructor(

val token = userPreference.getSessionToken()
val requestBody = DeleteSessionRequestBody(token)
deleteSessionRequest = Request(settings, clientFactory, serversRepository, Request.Duration.SHORT, RequestWrapper.IpMode.IPv4)
deleteSessionRequest = Request(settings, clientFactory, serversRepository, Request.Duration.LONG, RequestWrapper.IpMode.IPv4)

deleteSessionRequest?.start({ api: IVPNApi -> api.deleteSession(requestBody) },
object : RequestListener<DeleteSessionResponse?> {
Expand Down Expand Up @@ -234,7 +238,7 @@ class SessionController @Inject constructor(
}
}

private fun onCreateError(throwable: Throwable?, errorResponse: ErrorResponse?) {
private fun onCreateError(throwable: Throwable?, errorResponse: SessionErrorResponse?) {
for (listener in listeners) {
listener.onCreateError(throwable, errorResponse)
}
Expand All @@ -246,12 +250,18 @@ class SessionController @Inject constructor(
}
}

private fun onUpdateError(throwable: Throwable?, errorResponse: ErrorResponse?) {
private fun onUpdateError(throwable: Throwable?, errorResponse: SessionErrorResponse?) {
for (listener in listeners) {
listener.onUpdateError(throwable, errorResponse)
}
}

private fun onDeviceLoggedOut() {
for (listener in listeners) {
listener.onDeviceLoggedOut()
}
}

fun clearData() {
IVPNApplication.appComponent.provideComponentUtil().resetComponents()
ViewModelCleaner().fullClean()
Expand Down Expand Up @@ -292,6 +302,7 @@ class SessionController @Inject constructor(
userPreference.putSessionToken(response.token)
userPreference.putSessionUsername(response.vpnUsername)
userPreference.putSessionPassword(response.vpnPassword)
userPreference.putDeviceName(response.deviceName)
saveSessionStatus(response.serviceStatus)
}

Expand All @@ -304,6 +315,9 @@ class SessionController @Inject constructor(
userPreference.putCurrentPlan(serviceStatus.currentPlan)
userPreference.putPaymentMethod(serviceStatus.paymentMethod)
userPreference.putIsActive(serviceStatus.isActive)
serviceStatus.deviceManagement?.let {
userPreference.putDeviceManagement(it)
}
if (serviceStatus.capabilities != null) {
userPreference.putIsUserOnPrivateEmailBeta(serviceStatus.capabilities.contains(Responses.PRIVATE_EMAILS))
val multiHopCapabilities = serviceStatus.capabilities.contains(Responses.MULTI_HOP)
Expand Down Expand Up @@ -348,15 +362,11 @@ class SessionController @Inject constructor(

interface SessionListener {
fun onRemoveSuccess()

fun onRemoveError()

fun onCreateSuccess(response: SessionNewResponse)

fun onCreateError(throwable: Throwable?, errorResponse: ErrorResponse?)

fun onCreateError(throwable: Throwable?, errorResponse: SessionErrorResponse?)
fun onUpdateSuccess()

fun onUpdateError(throwable: Throwable?, errorResponse: ErrorResponse?)
fun onUpdateError(throwable: Throwable?, errorResponse: SessionErrorResponse?)
fun onDeviceLoggedOut()
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -23,25 +23,22 @@ package net.ivpn.core.common.session
*/

import net.ivpn.core.common.session.SessionController.*
import net.ivpn.core.rest.data.session.SessionErrorResponse
import net.ivpn.core.rest.data.session.SessionNewResponse
import net.ivpn.core.rest.data.wireguard.ErrorResponse

open class SessionListenerImpl: SessionListener {
override fun onRemoveSuccess() {
}

override fun onRemoveError() {
}

override fun onCreateSuccess(response: SessionNewResponse) {
}

override fun onCreateError(throwable: Throwable?, errorResponse: ErrorResponse?) {
override fun onCreateError(throwable: Throwable?, errorResponse: SessionErrorResponse?) {
}

override fun onUpdateSuccess() {
}

override fun onUpdateError(throwable: Throwable?, errorResponse: ErrorResponse?) {
override fun onUpdateError(throwable: Throwable?, errorResponse: SessionErrorResponse?) {
}
override fun onDeviceLoggedOut() {
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -53,6 +53,9 @@ public class ServiceStatus {
@SerializedName("capabilities")
@Expose
private List<String> capabilities = null;
@SerializedName("device_management")
@Expose
private Boolean deviceManagement;

public Boolean getIsActive() {
return isActive;
Expand Down Expand Up @@ -118,6 +121,10 @@ public void setCurrentPlan(String currentPlan) {
this.currentPlan = currentPlan;
}

public Boolean getDeviceManagement() {
return deviceManagement;
}

@Override
public String toString() {
return "ServiceStatus{" +
Expand All @@ -128,6 +135,7 @@ public String toString() {
", isRenewable='" + isRenewable + '\'' +
", willAutoRebill='" + willAutoRebill + '\'' +
", isOnFreeTrial='" + isOnFreeTrial + '\'' +
", deviceManagement='" + deviceManagement + '\'' +
", capabilities=" + capabilities +
'}';
}
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,66 @@
package net.ivpn.core.rest.data.session;

/*
IVPN Android app
https://github.com/ivpn/android-app
Created by Juraj Hilje.
Copyright (c) 2024 IVPN Limited.
This file is part of the IVPN Android app.
The IVPN Android app is free software: you can redistribute it and/or
modify it under the terms of the GNU General Public License as published by the Free
Software Foundation, either version 3 of the License, or (at your option) any later version.
The IVPN Android app is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
details.
You should have received a copy of the GNU General Public License
along with the IVPN Android app. If not, see <https://www.gnu.org/licenses/>.
*/

import com.google.gson.annotations.Expose;
import com.google.gson.annotations.SerializedName;

class SessionErrorData {

@SerializedName("current_plan")
@Expose
var currentPlan: String = ""

@SerializedName("device_management")
@Expose
var deviceManagement: Boolean = false

@SerializedName("device_management_url")
@Expose
var deviceManagementUrl: String = ""

@SerializedName("limit")
@Expose
var limit: Int = 0

@SerializedName("payment_method")
@Expose
var paymentMethod: String = ""

@SerializedName("upgradable")
@Expose
var upgradable: Boolean = false

@SerializedName("upgrade_to_plan")
@Expose
var upgradeToPlan: String = ""

@SerializedName("upgrade_to_url")
@Expose
var upgradeToUrl: String = ""

override fun toString(): String {
return "SessionErrorData(currentPlan='$currentPlan', deviceManagement=$deviceManagement, deviceManagementUrl='$deviceManagementUrl', limit=$limit, paymentMethod='$paymentMethod', upgradable=$upgradable, upgradeToPlan='$upgradeToPlan', upgradeToUrl='$upgradeToUrl')"
}

}
Loading

0 comments on commit 92900dd

Please sign in to comment.