Compare commits

..

2 Commits

147 changed files with 5453 additions and 2483 deletions

4
.gitattributes vendored
View File

@@ -1,4 +0,0 @@
deploy/data/windows/x64/tap/windows_7/OemVista.inf eol=crlf
deploy/data/windows/x64/tap/windows_10/OemVista.inf eol=crlf
deploy/data/windows/x32/tap/windows_7/OemVista.inf eol=crlf
deploy/data/windows/x32/tap/windows_10/OemVista.inf eol=crlf

View File

@@ -2,5 +2,5 @@ TEMPLATE = subdirs
SUBDIRS = client
!ios:!android {
SUBDIRS += service
SUBDIRS += service platform
}

View File

@@ -1,12 +1,12 @@
<?xml version="1.0"?>
<manifest package="org.amnezia.vpn" xmlns:android="http://schemas.android.com/apk/res/android" android:versionName="-- %%INSERT_VERSION_NAME%% --" android:versionCode="-- %%INSERT_VERSION_CODE%% --" android:installLocation="auto">
<uses-permission android:name="android.permission.INTERNET"/>
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE"/>
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"/>
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE"/>
<uses-permission android:name="android.permission.FOREGROUND_SERVICE"/>
<uses-permission android:name="android.permission.RECEIVE_BOOT_COMPLETED"/>
<uses-permission android:name="android.permission.INTERNET" />
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" />
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
<uses-permission android:name="android.permission.FOREGROUND_SERVICE" />
<uses-permission android:name="android.permission.RECEIVE_BOOT_COMPLETED" />
<uses-permission android:name="android.permission.QUERY_ALL_PACKAGES"/>
<uses-permission android:name="android.permission.CAMERA"/>
@@ -15,15 +15,27 @@
<!-- %%INSERT_FEATURES -->
<supports-screens android:largeScreens="true" android:normalScreens="true" android:anyDensity="true" android:smallScreens="true"/>
<application android:hardwareAccelerated="true" android:name="org.qtproject.qt5.android.bindings.QtApplication" android:label="-- %%INSERT_APP_NAME%% --" android:extractNativeLibs="true" android:icon="@drawable/icon">
<activity android:configChanges="orientation|uiMode|screenLayout|screenSize|smallestScreenSize|layoutDirection|locale|fontScale|keyboard|keyboardHidden|navigation|mcc|mnc|density" android:name="org.qtproject.qt5.android.bindings.QtActivity" android:label="-- %%INSERT_APP_NAME%% --" android:screenOrientation="unspecified" android:launchMode="singleTop" android:theme="@style/splashScreenTheme">
<application
android:hardwareAccelerated="true"
android:name="org.qtproject.qt5.android.bindings.QtApplication"
android:label="-- %%INSERT_APP_NAME%% --"
android:extractNativeLibs="true"
android:icon="@drawable/icon">
<activity android:configChanges="orientation|uiMode|screenLayout|screenSize|smallestScreenSize|layoutDirection|locale|fontScale|keyboard|keyboardHidden|navigation|mcc|mnc|density"
android:name="org.qtproject.qt5.android.bindings.QtActivity"
android:label="-- %%INSERT_APP_NAME%% --"
android:screenOrientation="unspecified"
android:launchMode="singleTop">
<intent-filter>
<action android:name="android.intent.action.MAIN"/>
<category android:name="android.intent.category.LAUNCHER"/>
</intent-filter>
<!-- Application arguments -->
<!-- meta-data android:name="android.app.arguments" android:value="arg1 arg2 arg3"/ -->
<!-- Application arguments -->
<meta-data android:name="android.app.lib_name" android:value="-- %%INSERT_APP_LIB_NAME%% --"/>
<meta-data android:name="android.app.qt_sources_resource_id" android:resource="@array/qt_sources"/>
<meta-data android:name="android.app.repository" android:value="default"/>
@@ -31,6 +43,7 @@
<meta-data android:name="android.app.bundled_libs_resource_id" android:resource="@array/bundled_libs"/>
<!-- Deploy Qt libs as part of package -->
<meta-data android:name="android.app.bundle_local_qt_libs" android:value="-- %%BUNDLE_LOCAL_QT_LIBS%% --"/>
<!-- Run with local libs -->
<meta-data android:name="android.app.use_local_qt_libs" android:value="-- %%USE_LOCAL_QT_LIBS%% --"/>
<meta-data android:name="android.app.libs_prefix" android:value="/data/local/tmp/qt/"/>
@@ -45,6 +58,7 @@
<meta-data android:value="@string/fatal_error_msg" android:name="android.app.fatal_error_msg"/>
<meta-data android:value="@string/unsupported_android_version" android:name="android.app.unsupported_android_version"/>
<!-- Messages maps -->
<!-- Splash screen -->
<!-- Orientation-specific (portrait/landscape) data is checked first. If not available for current orientation,
then android.app.splash_screen_drawable. For best results, use together with splash_screen_sticky and
@@ -55,6 +69,7 @@
<!-- meta-data android:name="android.app.splash_screen_drawable" android:resource="@drawable/logo"/ -->
<!-- meta-data android:name="android.app.splash_screen_sticky" android:value="true"/ -->
<!-- Splash screen -->
<!-- Background running -->
<!-- Warning: changing this value to true may cause unexpected crashes if the
application still try to draw after
@@ -62,9 +77,11 @@
signal is sent! -->
<meta-data android:name="android.app.background_running" android:value="false"/>
<!-- Background running -->
<!-- auto screen scale factor -->
<meta-data android:name="android.app.auto_screen_scale_factor" android:value="false"/>
<!-- auto screen scale factor -->
<!-- extract android style -->
<!-- available android:values :
* default - In most cases this will be the same as "full", but it can also be something else if needed, e.g., for compatibility reasons
@@ -75,20 +92,24 @@
<meta-data android:name="android.app.extract_android_style" android:value="default"/>
<!-- extract android style -->
<meta-data android:name="android.app.splash_screen_drawable" android:resource="@drawable/splashscreen"/>
</activity>
<service android:name=".VPNService"
android:process=":QtOnlyProcess"
android:permission="android.permission.BIND_VPN_SERVICE">
<intent-filter>
<action android:name="android.net.VpnService"/>
</intent-filter>
</service>
</activity>
<service android:name=".VPNService"
android:permission="android.permission.BIND_VPN_SERVICE">
<intent-filter>
<action android:name="android.net.VpnService"/>
</intent-filter>
</service>
<service android:name="org.amnezia.vpn.qt.VPNPermissionHelper"
android:permission="android.permission.BIND_VPN_SERVICE">
</service>
<!-- For adding service(s) please check: https://wiki.qt.io/AndroidServices -->
<service android:name="org.amnezia.vpn.qt.VPNPermissionHelper"
android:permission="android.permission.BIND_VPN_SERVICE">
</service>
<!-- For adding service(s) please check: https://wiki.qt.io/AndroidServices -->
</application>
</manifest>

View File

@@ -102,8 +102,8 @@ android {
resConfig "en"
minSdkVersion = 24
targetSdkVersion = 30
versionCode 10 // Change to a higher number
versionName "2.0.10" // Change to a higher number
versionCode 7 // Change to a higher number
versionName "2.0.7" // Change to a higher number
}
buildTypes {

View File

@@ -37,13 +37,12 @@ class VPNService : android.net.VpnService() {
SharedLibraryLoader.loadSharedLibrary(this, "ovpn3")
Log.i(tag, "Loaded libs")
Log.e(tag, "Wireguard Version ${wgVersion()}")
mOpenVPNThreadv3 = OpenVPNThreadv3(this)
mOpenVPNThreadv3 = OpenVPNThreadv3 (this)
mAlreadyInitialised = true
}
override fun onUnbind(intent: Intent?): Boolean {
Log.v(tag, "Got Unbind request")
if (!isUp) {
// If the Qt Client got closed while we were not connected
// we do not need to stay as a foreground service.
@@ -53,9 +52,9 @@ class VPNService : android.net.VpnService() {
}
/**
* EntryPoint for the Service, gets Called when AndroidController.cpp
* calles bindService. Returns the [VPNServiceBinder] so QT can send Requests to it.
*/
* EntryPoint for the Service, gets Called when AndroidController.cpp
* calles bindService. Returns the [VPNServiceBinder] so QT can send Requests to it.
*/
override fun onBind(intent: Intent?): IBinder? {
Log.v(tag, "Got Bind request")
init()
@@ -63,10 +62,10 @@ class VPNService : android.net.VpnService() {
}
/**
* Might be the entryPoint if the Service gets Started via an
* Service Intent: Might be from Always-On-Vpn from Settings
* or from Booting the device and having "connect on boot" enabled.
*/
* Might be the entryPoint if the Service gets Started via an
* Service Intent: Might be from Always-On-Vpn from Settings
* or from Booting the device and having "connect on boot" enabled.
*/
override fun onStartCommand(intent: Intent?, flags: Int, startId: Int): Int {
init()
intent?.let {
@@ -85,28 +84,28 @@ class VPNService : android.net.VpnService() {
Log.e(
tag,
"VPN service was triggered without defining a Server or having a tunnel"
)
return super.onStartCommand(intent, flags, startId)
)
return super.onStartCommand(intent, flags, startId)
}
this.mConfig = JSONObject(lastConfString)
}
this.mConfig = JSONObject(lastConfString)
return super.onStartCommand(intent, flags, startId)
}
return super.onStartCommand(intent, flags, startId)
}
// Invoked when the application is revoked.
// At this moment, the VPN interface is already deactivated by the system.
override fun onRevoke() {
this.turnOff()
super.onRevoke()
}
// Invoked when the application is revoked.
// At this moment, the VPN interface is already deactivated by the system.
override fun onRevoke() {
this.turnOff()
super.onRevoke()
}
var connectionTime: Long = 0
var connectionTime: Long = 0
get() {
return mConnectionTime
}
var isUp: Boolean
var isUp: Boolean
get() {
return currentTunnelHandle >= 0
}
@@ -119,7 +118,7 @@ class VPNService : android.net.VpnService() {
mBinder.dispatchEvent(VPNServiceBinder.EVENTS.disconnected, "")
mConnectionTime = 0
}
val status: JSONObject
val status: JSONObject
get() {
val deviceIpv4: String = ""
return JSONObject().apply {
@@ -129,307 +128,299 @@ class VPNService : android.net.VpnService() {
putOpt("deviceIpv4", mConfig?.getJSONObject("device")?.getString("ipv4Address"))
}
}
/*
* Checks if the VPN Permission is given.
* If the permission is given, returns true
* Requests permission and returns false if not.
*/
fun checkPermissions(): Boolean {
// See https://developer.android.com/guide/topics/connectivity/vpn#connect_a_service
// Call Prepare, if we get an Intent back, we dont have the VPN Permission
// from the user. So we need to pass this to our main Activity and exit here.
val intent = prepare(this)
if (intent == null) {
Log.e(tag, "VPN Permission Already Present")
return true
/*
* Checks if the VPN Permission is given.
* If the permission is given, returns true
* Requests permission and returns false if not.
*/
fun checkPermissions(): Boolean {
// See https://developer.android.com/guide/topics/connectivity/vpn#connect_a_service
// Call Prepare, if we get an Intent back, we dont have the VPN Permission
// from the user. So we need to pass this to our main Activity and exit here.
val intent = prepare(this)
if (intent == null) {
Log.e(tag, "VPN Permission Already Present")
return true
}
Log.e(tag, "Requesting VPN Permission")
return false
}
Log.e(tag, "Requesting VPN Permission")
return false
}
fun turnOn(json: JSONObject?): Int {
if (!checkPermissions()) {
Log.e(tag, "turn on was called without no permissions present!")
isUp = false
return 0
}
Log.i(tag, "Permission okay")
mConfig = json!!
mProtocol = mConfig!!.getString("protocol")
when (mProtocol) {
"openvpn" -> startOpenVpn()
"wireguard" -> startWireGuard()
else -> {
Log.e(tag, "No protocol")
fun turnOn(json: JSONObject?): Int {
if (!checkPermissions()) {
Log.e(tag, "turn on was called without no permissions present!")
isUp = false
return 0
}
}
NotificationUtil.show(this) // Go foreground
return 1
}
fun establish(): ParcelFileDescriptor? {
mbuilder.allowFamily(OsConstants.AF_INET)
mbuilder.allowFamily(OsConstants.AF_INET6)
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q) mbuilder.setMetered(false)
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) setUnderlyingNetworks(null)
return mbuilder.establish()
}
fun setMtu(mtu: Int) {
mbuilder.setMtu(mtu)
}
fun addAddress(ip: String, len: Int) {
Log.v(tag, "mbuilder.addAddress($ip, $len)")
mbuilder.addAddress(ip, len)
}
fun addRoute(ip: String, len: Int) {
Log.v(tag, "mbuilder.addRoute($ip, $len)")
mbuilder.addRoute(ip, len)
}
fun addDNS(ip: String) {
Log.v(tag, "mbuilder.addDnsServer($ip)")
mbuilder.addDnsServer(ip)
if ("samsung".equals(Build.BRAND) && Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
mbuilder.addRoute(ip, 32)
}
}
fun setSessionName(name: String) {
Log.v(tag, "mbuilder.setSession($name)")
mbuilder.setSession(name)
}
fun addHttpProxy(host: String, port: Int): Boolean {
val proxyInfo = ProxyInfo.buildDirectProxy(host, port)
Log.v(tag, "mbuilder.addHttpProxy($host, $port)")
mbuilder.setHttpProxy(proxyInfo)
return true
}
fun setDomain(domain: String) {
Log.v(tag, "mbuilder.setDomain($domain)")
mbuilder.addSearchDomain(domain)
}
fun turnOff() {
Log.v(tag, "Try to disable tunnel")
when (mProtocol) {
"wireguard" -> wgTurnOff(currentTunnelHandle)
"openvpn" -> ovpnTurnOff()
else -> {
Log.e(tag, "No protocol")
}
}
currentTunnelHandle = -1
stopForeground(true)
isUp = false
stopSelf();
}
private fun ovpnTurnOff() {
mOpenVPNThreadv3?.stop()
mOpenVPNThreadv3 = null
Log.e(tag, "mOpenVPNThreadv3 stop!")
}
/**
* Configures an Android VPN Service Tunnel
* with a given Wireguard Config
*/
private fun setupBuilder(config: Config, builder: Builder) {
// Setup Split tunnel
for (excludedApplication in config.`interface`.excludedApplications)
builder.addDisallowedApplication(excludedApplication)
// Device IP
for (addr in config.`interface`.addresses) builder.addAddress(addr.address, addr.mask)
// DNS
for (addr in config.`interface`.dnsServers) builder.addDnsServer(addr.hostAddress)
// Add All routes the VPN may route tos
for (peer in config.peers) {
for (addr in peer.allowedIps) {
builder.addRoute(addr.address, addr.mask)
}
}
builder.allowFamily(OsConstants.AF_INET)
builder.allowFamily(OsConstants.AF_INET6)
builder.setMtu(config.`interface`.mtu.orElse(1280))
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q) builder.setMetered(false)
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) setUnderlyingNetworks(null)
builder.setBlocking(true)
}
/**
* Gets config value for {key} from the Current
* running Wireguard tunnel
*/
private fun getConfigValue(key: String): String? {
if (!isUp) {
return null
}
val config = wgGetConfig(currentTunnelHandle) ?: return null
val lines = config.split("\n")
for (line in lines) {
val parts = line.split("=")
val k = parts.first()
val value = parts.last()
if (key == k) {
return value
}
}
return null
}
private fun parseConfigData(data: String): Map<String, Map<String, String>> {
val parseData = mutableMapOf<String, Map<String, String>>()
var currentSection: Pair<String, MutableMap<String, String>>? = null
data.lines().forEach { line ->
if (line.isNotEmpty()) {
if (line.startsWith('[')) {
currentSection?.let {
parseData.put(it.first, it.second)
}
currentSection =
line.substring(1, line.indexOfLast { it == ']' }) to mutableMapOf()
} else {
val parameter = line.split("=", limit = 2)
currentSection!!.second.put(parameter.first().trim(), parameter.last().trim())
Log.i(tag, "Permission okay")
mConfig = json!!
mProtocol = mConfig!!.getString("protocol")
when (mProtocol) {
"openvpn" -> startOpenVpn()
"wireguard" -> startWireGuard()
else -> {
Log.e(tag, "No protocol")
return 0
}
}
return 1
}
currentSection?.let {
parseData.put(it.first, it.second)
}
return parseData
}
/**
* Create a Wireguard [Config] from a [json] string -
* The [json] will be created in AndroidVpnProtocol.cpp
*/
private fun buildWireugardConfig(obj: JSONObject): Config {
val confBuilder = Config.Builder()
val wireguardConfigData = obj.getJSONObject("wireguard_config_data")
val config = parseConfigData(wireguardConfigData.getString("config"))
val peerBuilder = Peer.Builder()
val peerConfig = config["Peer"]!!
peerBuilder.setPublicKey(Key.fromBase64(peerConfig["PublicKey"]))
peerConfig["PresharedKey"]?.let {
peerBuilder.setPreSharedKey(Key.fromBase64(it))
fun establish(): ParcelFileDescriptor? {
mbuilder.allowFamily(OsConstants.AF_INET)
mbuilder.allowFamily(OsConstants.AF_INET6)
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q) mbuilder.setMetered(false)
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) setUnderlyingNetworks(null)
return mbuilder.establish()
}
val allowedIPList = peerConfig["AllowedIPs"]?.split(",") ?: emptyList()
if (allowedIPList.isEmpty()) {
val internet = InetNetwork.parse("0.0.0.0/0") // aka The whole internet.
peerBuilder.addAllowedIp(internet)
} else {
allowedIPList.forEach {
val network = InetNetwork.parse(it.trim())
peerBuilder.addAllowedIp(network)
fun setMtu(mtu: Int) {
mbuilder.setMtu(mtu)
}
fun addAddress(ip: String, len: Int){
Log.v(tag, "mbuilder.addAddress($ip, $len)")
mbuilder.addAddress(ip, len)
}
fun addRoute(ip: String, len: Int){
Log.v(tag, "mbuilder.addRoute($ip, $len)")
mbuilder.addRoute(ip, len)
}
fun addDNS(ip: String){
Log.v(tag, "mbuilder.addDnsServer($ip)")
mbuilder.addDnsServer(ip)
if ("samsung".equals(Build.BRAND) && Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP){
mbuilder.addRoute(ip, 32)
}
}
peerBuilder.setEndpoint(InetEndpoint.parse(peerConfig["Endpoint"]))
peerConfig["PersistentKeepalive"]?.let {
peerBuilder.setPersistentKeepalive(it.toInt())
fun setSessionName(name: String){
Log.v(tag, "mbuilder.setSession($name)")
mbuilder.setSession(name)
}
confBuilder.addPeer(peerBuilder.build())
val ifaceBuilder = Interface.Builder()
val ifaceConfig = config["Interface"]!!
ifaceBuilder.parsePrivateKey(ifaceConfig["PrivateKey"])
ifaceBuilder.addAddress(InetNetwork.parse(ifaceConfig["Address"]))
ifaceConfig["DNS"]!!.split(",").forEach {
ifaceBuilder.addDnsServer(InetNetwork.parse(it.trim()).address)
fun addHttpProxy(host: String, port: Int): Boolean{
val proxyInfo = ProxyInfo.buildDirectProxy(host, port)
Log.v(tag, "mbuilder.addHttpProxy($host, $port)")
mbuilder.setHttpProxy(proxyInfo)
return true
}
/*val jExcludedApplication = obj.getJSONArray("excludedApps")
(0 until jExcludedApplication.length()).toList().forEach {
val appName = jExcludedApplication.get(it).toString()
ifaceBuilder.excludeApplication(appName)
}*/
confBuilder.setInterface(ifaceBuilder.build())
return confBuilder.build()
}
fun getVpnConfig(): JSONObject {
return mConfig!!
}
private fun startOpenVpn() {
mOpenVPNThreadv3 = OpenVPNThreadv3(this)
Thread({
mOpenVPNThreadv3?.run()
}).start()
}
private fun startWireGuard() {
val wireguard_conf = buildWireugardConfig(mConfig!!)
if (currentTunnelHandle != -1) {
Log.e(tag, "Tunnel already up")
// Turn the tunnel down because this might be a switch
wgTurnOff(currentTunnelHandle)
fun setDomain(domain: String) {
Log.v(tag, "mbuilder.setDomain($domain)")
mbuilder.addSearchDomain(domain)
}
val wgConfig: String = wireguard_conf!!.toWgUserspaceString()
val builder = Builder()
setupBuilder(wireguard_conf, builder)
builder.setSession("avpn0")
builder.establish().use { tun ->
if (tun == null) return
Log.i(tag, "Go backend " + wgVersion())
currentTunnelHandle = wgTurnOn("avpn0", tun.detachFd(), wgConfig)
}
if (currentTunnelHandle < 0) {
Log.e(tag, "Activation Error Code -> $currentTunnelHandle")
fun turnOff() {
Log.v(tag, "Try to disable tunnel")
when(mProtocol){
"wireguard" -> wgTurnOff(currentTunnelHandle)
"openvpn" -> ovpnTurnOff()
else -> {
Log.e(tag, "No protocol")
}
}
currentTunnelHandle = -1
stopForeground(true)
isUp = false
return
}
protect(wgGetSocketV4(currentTunnelHandle))
protect(wgGetSocketV6(currentTunnelHandle))
isUp = true
// Store the config in case the service gets
// asked boot vpn from the OS
val prefs = Prefs.get(this)
prefs.edit()
.putString("lastConf", mConfig.toString())
.apply()
}
companion object {
@JvmStatic
fun startService(c: Context) {
c.applicationContext.startService(
Intent(c.applicationContext, VPNService::class.java).apply {
putExtra("startOnly", true)
})
stopSelf();
}
@JvmStatic
private external fun wgGetConfig(handle: Int): String?
@JvmStatic
private external fun wgGetSocketV4(handle: Int): Int
private fun ovpnTurnOff() {
mOpenVPNThreadv3?.stop()
mOpenVPNThreadv3 = null
Log.e(tag, "mOpenVPNThreadv3 stop!")
}
/**
* Configures an Android VPN Service Tunnel
* with a given Wireguard Config
*/
private fun setupBuilder(config: Config, builder: Builder) {
// Setup Split tunnel
for (excludedApplication in config.`interface`.excludedApplications)
builder.addDisallowedApplication(excludedApplication)
@JvmStatic
private external fun wgGetSocketV6(handle: Int): Int
// Device IP
for (addr in config.`interface`.addresses) builder.addAddress(addr.address, addr.mask)
// DNS
for (addr in config.`interface`.dnsServers) builder.addDnsServer(addr.hostAddress)
// Add All routes the VPN may route tos
for (peer in config.peers) {
for (addr in peer.allowedIps) {
builder.addRoute(addr.address, addr.mask)
}
}
builder.allowFamily(OsConstants.AF_INET)
builder.allowFamily(OsConstants.AF_INET6)
builder.setMtu(config.`interface`.mtu.orElse(1280))
@JvmStatic
private external fun wgTurnOff(handle: Int)
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q) builder.setMetered(false)
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) setUnderlyingNetworks(null)
@JvmStatic
private external fun wgTurnOn(ifName: String, tunFd: Int, settings: String): Int
builder.setBlocking(true)
}
@JvmStatic
private external fun wgVersion(): String?
}
}
/**
* Gets config value for {key} from the Current
* running Wireguard tunnel
*/
private fun getConfigValue(key: String): String? {
if (!isUp) {
return null
}
val config = wgGetConfig(currentTunnelHandle) ?: return null
val lines = config.split("\n")
for (line in lines) {
val parts = line.split("=")
val k = parts.first()
val value = parts.last()
if (key == k) {
return value
}
}
return null
}
private fun parseConfigData(data: String): Map<String, Map<String, String>> {
val parseData = mutableMapOf<String, Map<String, String>>()
var currentSection: Pair<String, MutableMap<String, String>>? = null
data.lines().forEach { line ->
if (line.isNotEmpty()) {
if (line.startsWith('[')) {
currentSection?.let {
parseData.put(it.first, it.second)
}
currentSection = line.substring(1, line.indexOfLast { it == ']' }) to mutableMapOf()
} else {
val parameter = line.split("=", limit = 2)
currentSection!!.second.put(parameter.first().trim(), parameter.last().trim())
}
}
}
currentSection?.let {
parseData.put(it.first, it.second)
}
return parseData
}
/**
* Create a Wireguard [Config] from a [json] string -
* The [json] will be created in AndroidVpnProtocol.cpp
*/
private fun buildWireugardConfig(obj: JSONObject): Config {
val confBuilder = Config.Builder()
val wireguardConfigData = obj.getJSONObject("wireguard_config_data")
val config = parseConfigData(wireguardConfigData.getString("config"))
val peerBuilder = Peer.Builder()
val peerConfig = config["Peer"]!!
peerBuilder.setPublicKey(Key.fromBase64(peerConfig["PublicKey"]))
peerConfig["PresharedKey"]?.let {
peerBuilder.setPreSharedKey(Key.fromBase64(it))
}
val allowedIPList = peerConfig["AllowedIPs"]?.split(",") ?: emptyList()
if (allowedIPList.isEmpty()) {
val internet = InetNetwork.parse("0.0.0.0/0") // aka The whole internet.
peerBuilder.addAllowedIp(internet)
} else {
allowedIPList.forEach {
val network = InetNetwork.parse(it.trim())
peerBuilder.addAllowedIp(network)
}
}
peerBuilder.setEndpoint(InetEndpoint.parse(peerConfig["Endpoint"]))
peerConfig["PersistentKeepalive"]?.let {
peerBuilder.setPersistentKeepalive(it.toInt())
}
confBuilder.addPeer(peerBuilder.build())
val ifaceBuilder = Interface.Builder()
val ifaceConfig = config["Interface"]!!
ifaceBuilder.parsePrivateKey(ifaceConfig["PrivateKey"])
ifaceBuilder.addAddress(InetNetwork.parse(ifaceConfig["Address"]))
ifaceConfig["DNS"]!!.split(",").forEach {
ifaceBuilder.addDnsServer(InetNetwork.parse(it.trim()).address)
}
/*val jExcludedApplication = obj.getJSONArray("excludedApps")
(0 until jExcludedApplication.length()).toList().forEach {
val appName = jExcludedApplication.get(it).toString()
ifaceBuilder.excludeApplication(appName)
}*/
confBuilder.setInterface(ifaceBuilder.build())
return confBuilder.build()
}
fun getVpnConfig(): JSONObject {
return mConfig!!
}
private fun startOpenVpn() {
mOpenVPNThreadv3 = OpenVPNThreadv3 (this)
Thread ({
mOpenVPNThreadv3?.run()
}).start()
}
private fun startWireGuard(){
val wireguard_conf = buildWireugardConfig(mConfig!!)
if (currentTunnelHandle != -1) {
Log.e(tag, "Tunnel already up")
// Turn the tunnel down because this might be a switch
wgTurnOff(currentTunnelHandle)
}
val wgConfig: String = wireguard_conf!!.toWgUserspaceString()
val builder = Builder()
setupBuilder(wireguard_conf, builder)
builder.setSession("avpn0")
builder.establish().use { tun ->
if (tun == null)return
Log.i(tag, "Go backend " + wgVersion())
currentTunnelHandle = wgTurnOn("avpn0", tun.detachFd(), wgConfig)
}
if (currentTunnelHandle < 0) {
Log.e(tag, "Activation Error Code -> $currentTunnelHandle")
isUp = false
return
}
protect(wgGetSocketV4(currentTunnelHandle))
protect(wgGetSocketV6(currentTunnelHandle))
isUp = true
// Store the config in case the service gets
// asked boot vpn from the OS
val prefs = Prefs.get(this)
prefs.edit()
.putString("lastConf", mConfig.toString())
.apply()
NotificationUtil.show(this) // Go foreground
}
companion object {
@JvmStatic
fun startService(c: Context) {
c.applicationContext.startService(
Intent(c.applicationContext, VPNService::class.java).apply {
putExtra("startOnly", true)
})
}
@JvmStatic
private external fun wgGetConfig(handle: Int): String?
@JvmStatic
private external fun wgGetSocketV4(handle: Int): Int
@JvmStatic
private external fun wgGetSocketV6(handle: Int): Int
@JvmStatic
private external fun wgTurnOff(handle: Int)
@JvmStatic
private external fun wgTurnOn(ifName: String, tunFd: Int, settings: String): Int
@JvmStatic
private external fun wgVersion(): String?
}
}

View File

@@ -1,4 +1,4 @@
QT += widgets core gui network xml remoteobjects quick svg
QT += widgets core gui network xml remoteobjects quick
TARGET = AmneziaVPN
TEMPLATE = app
@@ -31,7 +31,9 @@ HEADERS += \
containers/containers_defs.h \
core/defs.h \
core/errorstrings.h \
core/ipcclient.h \
configurators/openvpn_configurator.h \
core/privileged_process.h \
core/scripts_registry.h \
core/server_defs.h \
core/servercontroller.h \
@@ -86,7 +88,9 @@ SOURCES += \
configurators/wireguard_configurator.cpp \
containers/containers_defs.cpp \
core/errorstrings.cpp \
core/ipcclient.cpp \
configurators/openvpn_configurator.cpp \
core/privileged_process.cpp \
core/scripts_registry.cpp \
core/server_defs.cpp \
core/servercontroller.cpp \
@@ -196,11 +200,8 @@ linux:!android {
}
win32|macx|linux:!android {
DEFINES += AMNEZIA_DESKTOP
HEADERS += \
core/ipcclient.h \
core/privileged_process.h \
ui/systemtray_notificationhandler.h \
protocols/openvpnprotocol.h \
protocols/openvpnovercloakprotocol.h \
@@ -208,16 +209,11 @@ win32|macx|linux:!android {
protocols/wireguardprotocol.h \
SOURCES += \
core/ipcclient.cpp \
core/privileged_process.cpp \
ui/systemtray_notificationhandler.cpp \
protocols/openvpnprotocol.cpp \
protocols/openvpnovercloakprotocol.cpp \
protocols/shadowsocksvpnprotocol.cpp \
protocols/wireguardprotocol.cpp \
REPC_REPLICA += ../ipc/ipc_interface.rep
REPC_REPLICA += ../ipc/ipc_process_interface.rep
}
android {
@@ -368,4 +364,6 @@ ios {
}
REPC_REPLICA += ../ipc/ipc_interface.rep
!ios: REPC_REPLICA += ../ipc/ipc_process_interface.rep

View File

@@ -10,7 +10,6 @@
#include <QJsonDocument>
#include "containers/containers_defs.h"
#include "utils.h"
Settings &VpnConfigurator::m_settings()
{
@@ -42,59 +41,24 @@ QString VpnConfigurator::genVpnProtocolConfig(const ServerCredentials &credentia
}
}
QPair<QString, QString> VpnConfigurator::getDnsForConfig(int serverIndex)
QString VpnConfigurator::processConfigWithLocalSettings(DockerContainer container, Proto proto, QString config)
{
QPair<QString, QString> dns;
bool useAmneziaDns = m_settings().useAmneziaDns();
const QJsonObject &server = m_settings().server(serverIndex);
dns.first = server.value(config_key::dns1).toString();
dns.second = server.value(config_key::dns2).toString();
if (dns.first.isEmpty() || !Utils::checkIPv4Format(dns.first)) {
if (useAmneziaDns && m_settings().containers(serverIndex).contains(DockerContainer::Dns)) {
dns.first = protocols::dns::amneziaDnsIp;
}
else dns.first = m_settings().primaryDns();
}
if (dns.second.isEmpty() || !Utils::checkIPv4Format(dns.second)) {
dns.second = m_settings().secondaryDns();
}
qDebug() << "VpnConfigurator::getDnsForConfig" << dns.first << dns.second;
return dns;
}
QString &VpnConfigurator::processConfigWithDnsSettings(int serverIndex, DockerContainer container,
Proto proto, QString &config)
{
auto dns = getDnsForConfig(serverIndex);
config.replace("$PRIMARY_DNS", dns.first);
config.replace("$SECONDARY_DNS", dns.second);
return config;
}
QString &VpnConfigurator::processConfigWithLocalSettings(int serverIndex, DockerContainer container,
Proto proto, QString &config)
{
processConfigWithDnsSettings(serverIndex, container, proto, config);
config.replace("$PRIMARY_DNS", m_settings().primaryDns());
config.replace("$SECONDARY_DNS", m_settings().secondaryDns());
if (proto == Proto::OpenVpn) {
config = OpenVpnConfigurator::processConfigWithLocalSettings(config);
return OpenVpnConfigurator::processConfigWithLocalSettings(config);
}
return config;
}
QString &VpnConfigurator::processConfigWithExportSettings(int serverIndex, DockerContainer container,
Proto proto, QString &config)
QString VpnConfigurator::processConfigWithExportSettings(DockerContainer container, Proto proto, QString config)
{
processConfigWithDnsSettings(serverIndex, container, proto, config);
config.replace("$PRIMARY_DNS", m_settings().primaryDns());
config.replace("$SECONDARY_DNS", m_settings().secondaryDns());
if (proto == Proto::OpenVpn) {
config = OpenVpnConfigurator::processConfigWithExportSettings(config);
return OpenVpnConfigurator::processConfigWithExportSettings(config);
}
return config;
}

View File

@@ -15,11 +15,8 @@ public:
static QString genVpnProtocolConfig(const ServerCredentials &credentials, DockerContainer container,
const QJsonObject &containerConfig, Proto proto, ErrorCode *errorCode = nullptr);
static QPair<QString, QString> getDnsForConfig(int serverIndex);
static QString &processConfigWithDnsSettings(int serverIndex, DockerContainer container, Proto proto, QString &config);
static QString &processConfigWithLocalSettings(int serverIndex, DockerContainer container, Proto proto, QString &config);
static QString &processConfigWithExportSettings(int serverIndex, DockerContainer container, Proto proto, QString &config);
static QString processConfigWithLocalSettings(DockerContainer container, Proto proto, QString config);
static QString processConfigWithExportSettings(DockerContainer container, Proto proto, QString config);
// workaround for containers which is not support normal configaration
static void updateContainerConfigAfterInstallation(DockerContainer container,

View File

@@ -136,7 +136,7 @@ Proto ContainerProps::defaultProtocol(DockerContainer c)
}
}
bool ContainerProps::isSupportedByCurrentPlatform(DockerContainer c)
bool ContainerProps::isWorkingOnPlatform(DockerContainer c)
{
#ifdef Q_OS_WINDOWS
return true;
@@ -148,11 +148,7 @@ bool ContainerProps::isSupportedByCurrentPlatform(DockerContainer c)
default: return false;
}
#elif defined (Q_OS_MAC)
switch (c) {
case DockerContainer::WireGuard: return false;
case DockerContainer::Ipsec: return false;
default: return true;
}
return false;
#elif defined (Q_OS_ANDROID)
switch (c) {

View File

@@ -54,7 +54,7 @@ public:
// it may be changed fot future containers :)
Q_INVOKABLE static Proto defaultProtocol(DockerContainer c);
Q_INVOKABLE static bool isSupportedByCurrentPlatform(DockerContainer c);
Q_INVOKABLE static bool isWorkingOnPlatform(DockerContainer c);
};

View File

@@ -65,6 +65,7 @@ bool IpcClient::init(IpcClient *instance)
QSharedPointer<PrivilegedProcess> IpcClient::CreatePrivilegedProcess()
{
#ifndef Q_OS_IOS
if (! Instance()->m_ipcClient || ! Instance()->m_ipcClient->isReplicaValid()) {
qWarning() << "IpcClient::createPrivilegedProcess : IpcClient IpcClient replica is not valid";
return nullptr;
@@ -106,6 +107,9 @@ QSharedPointer<PrivilegedProcess> IpcClient::CreatePrivilegedProcess()
auto proccessReplica = QSharedPointer<PrivilegedProcess>(pd->ipcProcess);
return proccessReplica;
#else
return QSharedPointer<PrivilegedProcess>();
#endif
}

View File

@@ -1,5 +1,6 @@
#include "privileged_process.h"
#ifndef Q_OS_IOS
PrivilegedProcess::PrivilegedProcess() :
IpcProcessInterfaceReplica()
{
@@ -25,3 +26,4 @@ void PrivilegedProcess::waitForFinished(int msecs)
loop->exec();
}
#endif // Q_OS_IOS

View File

@@ -3,6 +3,7 @@
#include <QObject>
#ifndef Q_OS_IOS
#include "rep_ipc_process_interface_replica.h"
// This class is dangerous - instance of this class casted from base class,
// so it support only functions
@@ -19,6 +20,11 @@ public:
};
#else // defined Q_OS_IOS
class IpcProcessInterfaceReplica {};
class PrivilegedProcess {};
#endif // Q_OS_IOS
#endif // PRIVILEGED_PROCESS_H

View File

@@ -79,8 +79,6 @@ ErrorCode ServerController::runScript(const ServerCredentials &credentials, QStr
}
qDebug().noquote() << "EXEC" << lineToExec;
Debug::appendSshLog("Run command:" + lineToExec);
QSharedPointer<SshRemoteProcess> proc = client->createRemoteProcess(lineToExec.toUtf8());
if (!proc) {
@@ -103,9 +101,7 @@ ErrorCode ServerController::runScript(const ServerCredentials &credentials, QStr
QObject::connect(proc.data(), &SshRemoteProcess::readyReadStandardOutput, &wait, [proc, cbReadStdOut](){
QString s = proc->readAllStandardOutput();
if (s != "." && !s.isEmpty()) {
Debug::appendSshLog("Output: " + s);
qDebug().noquote() << "stdout" << s;
}
if (cbReadStdOut) cbReadStdOut(s, proc);
@@ -114,7 +110,6 @@ ErrorCode ServerController::runScript(const ServerCredentials &credentials, QStr
QObject::connect(proc.data(), &SshRemoteProcess::readyReadStandardError, &wait, [proc, cbReadStdErr](){
QString s = proc->readAllStandardError();
if (s != "." && !s.isEmpty()) {
Debug::appendSshLog("Output: " + s);
qDebug().noquote() << "stderr" << s;
}
if (cbReadStdErr) cbReadStdErr(s, proc);
@@ -140,7 +135,6 @@ ErrorCode ServerController::runContainerScript(const ServerCredentials &credenti
const std::function<void (const QString &, QSharedPointer<QSsh::SshRemoteProcess>)> &cbReadStdErr)
{
QString fileName = "/opt/amnezia/" + Utils::getRandomString(16) + ".sh";
Debug::appendSshLog("Run container script for " + ContainerProps::containerToString(container) + ":\n" + script);
ErrorCode e = uploadTextFileToContainer(container, credentials, script, fileName);
if (e) return e;

View File

@@ -5,7 +5,6 @@
#include <QObject>
#include "sshconnection.h"
#include "sshremoteprocess.h"
#include "debug.h"
#include "defs.h"
#include "settings.h"

View File

@@ -1,4 +1,3 @@
#include <QDateTime>
#include <QDebug>
#include <QDesktopServices>
#include <QDir>
@@ -11,13 +10,9 @@
#include "defines.h"
#include "utils.h"
#ifdef AMNEZIA_DESKTOP
#include <core/ipcclient.h>
#endif
QFile Debug::m_file;
QTextStream Debug::m_textStream;
QString Debug::m_logFileName = QString("%1.log").arg(APPLICATION_NAME);
QString Debug::m_logFileName;
void debugMessageHandler(QtMsgType type, const QMessageLogContext& context, const QString& msg)
{
@@ -31,30 +26,10 @@ void debugMessageHandler(QtMsgType type, const QMessageLogContext& context, cons
}
Debug::m_textStream << qFormatLogMessage(type, context, msg) << endl << flush;
Debug::appendAllLog(qFormatLogMessage(type, context, msg));
std::cout << qFormatLogMessage(type, context, msg).toStdString() << std::endl << std::flush;
}
Debug &Debug::Instance()
{
static Debug s;
return s;
}
void Debug::appendSshLog(const QString &log)
{
QString dt = QDateTime::currentDateTime().toString();
Instance().m_sshLog.append(dt + ": " + log + "\n");
emit Instance().sshLogChanged(Instance().sshLog());
}
void Debug::appendAllLog(const QString &log)
{
Instance().m_allLog.append(log + "\n");
emit Instance().allLogChanged(Instance().allLog());
}
bool Debug::init()
{
qSetMessagePattern("%{time yyyy-MM-dd hh:mm:ss} %{type} %{message}");
@@ -65,8 +40,11 @@ bool Debug::init()
return false;
}
m_logFileName = QString("%1.log").arg(APPLICATION_NAME);
m_file.setFileName(appDir.filePath(m_logFileName));
if (!m_file.open(QIODevice::Append)) {
if (!m_file.open(QIODevice::WriteOnly | QIODevice::Truncate)) {
qWarning() << "Cannot open log file:" << m_logFileName;
return false;
}
@@ -85,20 +63,6 @@ QString Debug::userLogsDir()
return QStandardPaths::writableLocation(QStandardPaths::AppDataLocation) + "/log";
}
QString Debug::userLogsFilePath()
{
return userLogsDir() + QDir::separator() + m_logFileName;
}
QString Debug::getLogFile()
{
m_file.flush();
QFile file(userLogsFilePath());
file.open(QIODevice::ReadOnly);
return file.readAll();
}
bool Debug::openLogsFolder()
{
QString path = userLogsDir();
@@ -124,50 +88,3 @@ QString Debug::appLogFileNamePath()
{
return m_file.fileName();
}
void Debug::clearLogs()
{
bool isLogActive = m_file.isOpen();
m_file.close();
QFile file(userLogsFilePath());
file.open(QIODevice::WriteOnly | QIODevice::Truncate);
file.resize(0);
file.close();
if (isLogActive) {
init();
}
}
void Debug::clearServiceLogs()
{
#ifdef AMNEZIA_DESKTOP
IpcClient *m_IpcClient = new IpcClient;
if (!m_IpcClient->isSocketConnected()) {
if (!IpcClient::init(m_IpcClient)) {
qWarning() << "Error occured when init IPC client";
return;
}
}
if (m_IpcClient->Interface()) {
m_IpcClient->Interface()->setLogsEnabled(false);
m_IpcClient->Interface()->cleanUp();
}
else {
qWarning() << "Error occured cleaning up service logs";
}
#endif
}
void Debug::cleanUp()
{
clearLogs();
QDir dir(QStandardPaths::writableLocation(QStandardPaths::AppDataLocation));
dir.removeRecursively();
clearServiceLogs();
}

View File

@@ -7,37 +7,15 @@
#include <QString>
#include <QTextStream>
#include "ui/property_helper.h"
class Debug : public QObject
class Debug
{
Q_OBJECT
AUTO_PROPERTY(QString, sshLog)
AUTO_PROPERTY(QString, allLog)
public:
static Debug& Instance();
static void appendSshLog(const QString &log);
static void appendAllLog(const QString &log);
static bool init();
static bool openLogsFolder();
static bool openServiceLogsFolder();
static QString appLogFileNamePath();
static void clearLogs();
static void clearServiceLogs();
static void cleanUp();
static QString userLogsFilePath();
static QString getLogFile();
private:
Debug() {}
Debug(Debug const &) = delete;
Debug& operator= (Debug const&) = delete;
static QString userLogsDir();
static QFile m_file;

View File

@@ -4,7 +4,7 @@
#define APPLICATION_NAME "AmneziaVPN"
#define SERVICE_NAME "AmneziaVPN-service"
#define ORGANIZATION_NAME "AmneziaVPN.ORG"
#define APP_MAJOR_VERSION "2.0.10"
#define APP_VERSION "2.0.10.0"
#define APP_MAJOR_VERSION "2.0.7"
#define APP_VERSION "2.0.7.0"
#endif // DEFINES_H

BIN
client/images/plus.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 324 B

BIN
client/images/reload.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 690 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 454 B

View File

@@ -1 +0,0 @@
<svg xmlns="http://www.w3.org/2000/svg" height="24px" viewBox="0 0 24 24" width="24px" fill="#000000"><path d="M0 0h24v24H0V0z" fill="none"/><path d="M19 6.41L17.59 5 12 10.59 6.41 5 5 6.41 10.59 12 5 17.59 6.41 19 12 13.41 17.59 19 19 17.59 13.41 12 19 6.41z"/></svg>

Before

Width:  |  Height:  |  Size: 268 B

View File

@@ -1 +0,0 @@
<svg xmlns="http://www.w3.org/2000/svg" height="24px" viewBox="0 0 24 24" width="24px" fill="#000000"><path d="M0 0h24v24H0V0z" fill="none"/><path d="M13 7h-2v4H7v2h4v4h2v-4h4v-2h-4V7zm-1-5C6.49 2 2 6.49 2 12s4.49 10 10 10 10-4.49 10-10S17.51 2 12 2zm0 18c-4.41 0-8-3.59-8-8s3.59-8 8-8 8 3.59 8 8-3.59 8-8 8z"/></svg>

Before

Width:  |  Height:  |  Size: 317 B

View File

@@ -1 +0,0 @@
<svg xmlns="http://www.w3.org/2000/svg" height="24px" viewBox="0 0 24 24" width="24px" fill="#000000"><path d="M0 0h24v24H0V0z" fill="none"/><path d="M16 9v10H8V9h8m-1.5-6h-5l-1 1H5v2h14V4h-3.5l-1-1zM18 7H6v12c0 1.1.9 2 2 2h8c1.1 0 2-.9 2-2V7z"/></svg>

Before

Width:  |  Height:  |  Size: 252 B

View File

@@ -1 +0,0 @@
<svg xmlns="http://www.w3.org/2000/svg" enable-background="new 0 0 24 24" height="24px" viewBox="0 0 24 24" width="24px" fill="#000000"><g><rect fill="none" height="24" width="24"/></g><g><g><rect height="2" width="18" x="3" y="2"/><rect height="2" width="18" x="3" y="20"/><rect height="2" width="18" x="3" y="14"/><rect height="2" width="18" x="3" y="8"/></g></g></svg>

Before

Width:  |  Height:  |  Size: 371 B

View File

@@ -1 +0,0 @@
<svg xmlns="http://www.w3.org/2000/svg" height="24px" viewBox="0 0 24 24" width="24px" fill="#000000"><path d="M0 0h24v24H0V0z" fill="none"/><path d="M9 16.2L4.8 12l-1.4 1.4L9 19 21 7l-1.4-1.4L9 16.2z"/></svg>

Before

Width:  |  Height:  |  Size: 209 B

View File

@@ -1 +0,0 @@
<svg xmlns="http://www.w3.org/2000/svg" height="24px" viewBox="0 0 24 24" width="24px" fill="#000000"><path d="M0 0h24v24H0V0z" fill="none"/><path d="M4 10.5c-.83 0-1.5.67-1.5 1.5s.67 1.5 1.5 1.5 1.5-.67 1.5-1.5-.67-1.5-1.5-1.5zm0-6c-.83 0-1.5.67-1.5 1.5S3.17 7.5 4 7.5 5.5 6.83 5.5 6 4.83 4.5 4 4.5zm0 12c-.83 0-1.5.68-1.5 1.5s.68 1.5 1.5 1.5 1.5-.68 1.5-1.5-.67-1.5-1.5-1.5zM7 19h14v-2H7v2zm0-6h14v-2H7v2zm0-8v2h14V5H7z"/></svg>

Before

Width:  |  Height:  |  Size: 430 B

View File

@@ -1 +0,0 @@
<svg xmlns="http://www.w3.org/2000/svg" enable-background="new 0 0 24 24" height="24px" viewBox="0 0 24 24" width="24px" fill="#000000"><g><path d="M0,0h24v24H0V0z" fill="none"/></g><g><path d="M12,2L4,5v6.09c0,5.05,3.41,9.76,8,10.91c4.59-1.15,8-5.86,8-10.91V5L12,2z M18,11.09c0,4-2.55,7.7-6,8.83 c-3.45-1.13-6-4.82-6-8.83V6.31l6-2.12l6,2.12V11.09z M8.82,10.59L7.4,12l3.54,3.54l5.66-5.66l-1.41-1.41l-4.24,4.24L8.82,10.59z"/></g></svg>

Before

Width:  |  Height:  |  Size: 434 B

View File

@@ -1 +0,0 @@
<svg xmlns="http://www.w3.org/2000/svg" enable-background="new 0 0 24 24" height="24px" viewBox="0 0 24 24" width="24px" fill="#000000"><g><path d="M0,0h24v24H0V0z" fill="none"/></g><g><g><path d="M12,2L4,5v6.09c0,5.05,3.41,9.76,8,10.91c4.59-1.15,8-5.86,8-10.91V5L12,2z M18,11.09c0,4-2.55,7.7-6,8.83 c-3.45-1.13-6-4.82-6-8.83v-4.7l6-2.25l6,2.25V11.09z"/><rect height="2" width="2" x="11" y="14"/><rect height="5" width="2" x="11" y="7"/></g></g></svg>

Before

Width:  |  Height:  |  Size: 451 B

View File

@@ -1 +0,0 @@
<svg xmlns="http://www.w3.org/2000/svg" enable-background="new 0 0 24 24" height="24px" viewBox="0 0 24 24" width="24px" fill="#000000"><g><path d="M0,0h24v24H0V0z" fill="none"/></g><g><path d="M17,8l-1.41,1.41L17.17,11H9v2h8.17l-1.58,1.58L17,16l4-4L17,8z M5,5h7V3H5C3.9,3,3,3.9,3,5v14c0,1.1,0.9,2,2,2h7v-2H5V5z"/></g></svg>

Before

Width:  |  Height:  |  Size: 324 B

View File

@@ -1 +0,0 @@
<svg xmlns="http://www.w3.org/2000/svg" enable-background="new 0 0 24 24" height="24px" viewBox="0 0 24 24" width="24px" fill="#000000"><g><rect fill="none" height="24" width="24"/></g><g><g><path d="M14.17,13.71l1.4-2.42c0.09-0.15,0.05-0.34-0.08-0.45l-1.48-1.16c0.03-0.22,0.05-0.45,0.05-0.68s-0.02-0.46-0.05-0.69 l1.48-1.16c0.13-0.11,0.17-0.3,0.08-0.45l-1.4-2.42c-0.09-0.15-0.27-0.21-0.43-0.15L12,4.83c-0.36-0.28-0.75-0.51-1.18-0.69 l-0.26-1.85C10.53,2.13,10.38,2,10.21,2h-2.8C7.24,2,7.09,2.13,7.06,2.3L6.8,4.15C6.38,4.33,5.98,4.56,5.62,4.84l-1.74-0.7 c-0.16-0.06-0.34,0-0.43,0.15l-1.4,2.42C1.96,6.86,2,7.05,2.13,7.16l1.48,1.16C3.58,8.54,3.56,8.77,3.56,9s0.02,0.46,0.05,0.69 l-1.48,1.16C2,10.96,1.96,11.15,2.05,11.3l1.4,2.42c0.09,0.15,0.27,0.21,0.43,0.15l1.74-0.7c0.36,0.28,0.75,0.51,1.18,0.69 l0.26,1.85C7.09,15.87,7.24,16,7.41,16h2.8c0.17,0,0.32-0.13,0.35-0.3l0.26-1.85c0.42-0.18,0.82-0.41,1.18-0.69l1.74,0.7 C13.9,13.92,14.08,13.86,14.17,13.71z M8.81,11c-1.1,0-2-0.9-2-2c0-1.1,0.9-2,2-2s2,0.9,2,2C10.81,10.1,9.91,11,8.81,11z"/><path d="M21.92,18.67l-0.96-0.74c0.02-0.14,0.04-0.29,0.04-0.44c0-0.15-0.01-0.3-0.04-0.44l0.95-0.74 c0.08-0.07,0.11-0.19,0.05-0.29l-0.9-1.55c-0.05-0.1-0.17-0.13-0.28-0.1l-1.11,0.45c-0.23-0.18-0.48-0.33-0.76-0.44l-0.17-1.18 C18.73,13.08,18.63,13,18.53,13h-1.79c-0.11,0-0.21,0.08-0.22,0.19l-0.17,1.18c-0.27,0.12-0.53,0.26-0.76,0.44l-1.11-0.45 c-0.1-0.04-0.22,0-0.28,0.1l-0.9,1.55c-0.05,0.1-0.04,0.22,0.05,0.29l0.95,0.74c-0.02,0.14-0.03,0.29-0.03,0.44 c0,0.15,0.01,0.3,0.03,0.44l-0.95,0.74c-0.08,0.07-0.11,0.19-0.05,0.29l0.9,1.55c0.05,0.1,0.17,0.13,0.28,0.1l1.11-0.45 c0.23,0.18,0.48,0.33,0.76,0.44l0.17,1.18c0.02,0.11,0.11,0.19,0.22,0.19h1.79c0.11,0,0.21-0.08,0.22-0.19l0.17-1.18 c0.27-0.12,0.53-0.26,0.75-0.44l1.12,0.45c0.1,0.04,0.22,0,0.28-0.1l0.9-1.55C22.03,18.86,22,18.74,21.92,18.67z M17.63,18.83 c-0.74,0-1.35-0.6-1.35-1.35s0.6-1.35,1.35-1.35s1.35,0.6,1.35,1.35S18.37,18.83,17.63,18.83z"/></g></g></svg>

Before

Width:  |  Height:  |  Size: 1.9 KiB

View File

@@ -1 +0,0 @@
<svg xmlns="http://www.w3.org/2000/svg" height="24px" viewBox="0 0 24 24" width="24px" fill="#000000"><path d="M0 0h24v24H0V0z" fill="none"/><path d="M17.65 6.35C16.2 4.9 14.21 4 12 4c-4.42 0-7.99 3.58-7.99 8s3.57 8 7.99 8c3.73 0 6.84-2.55 7.73-6h-2.08c-.82 2.33-3.04 4-5.65 4-3.31 0-6-2.69-6-6s2.69-6 6-6c1.66 0 3.14.69 4.22 1.78L13 11h7V4l-2.35 2.35z"/></svg>

Before

Width:  |  Height:  |  Size: 361 B

View File

@@ -1 +0,0 @@
<svg xmlns="http://www.w3.org/2000/svg" height="24px" viewBox="0 0 24 24" width="24px" fill="#000000"><path d="M0 0h24v24H0V0z" fill="none"/><path d="M19.43 12.98c.04-.32.07-.64.07-.98 0-.34-.03-.66-.07-.98l2.11-1.65c.19-.15.24-.42.12-.64l-2-3.46c-.09-.16-.26-.25-.44-.25-.06 0-.12.01-.17.03l-2.49 1c-.52-.4-1.08-.73-1.69-.98l-.38-2.65C14.46 2.18 14.25 2 14 2h-4c-.25 0-.46.18-.49.42l-.38 2.65c-.61.25-1.17.59-1.69.98l-2.49-1c-.06-.02-.12-.03-.18-.03-.17 0-.34.09-.43.25l-2 3.46c-.13.22-.07.49.12.64l2.11 1.65c-.04.32-.07.65-.07.98 0 .33.03.66.07.98l-2.11 1.65c-.19.15-.24.42-.12.64l2 3.46c.09.16.26.25.44.25.06 0 .12-.01.17-.03l2.49-1c.52.4 1.08.73 1.69.98l.38 2.65c.03.24.24.42.49.42h4c.25 0 .46-.18.49-.42l.38-2.65c.61-.25 1.17-.59 1.69-.98l2.49 1c.06.02.12.03.18.03.17 0 .34-.09.43-.25l2-3.46c.12-.22.07-.49-.12-.64l-2.11-1.65zm-1.98-1.71c.04.31.05.52.05.73 0 .21-.02.43-.05.73l-.14 1.13.89.7 1.08.84-.7 1.21-1.27-.51-1.04-.42-.9.68c-.43.32-.84.56-1.25.73l-1.06.43-.16 1.13-.2 1.35h-1.4l-.19-1.35-.16-1.13-1.06-.43c-.43-.18-.83-.41-1.23-.71l-.91-.7-1.06.43-1.27.51-.7-1.21 1.08-.84.89-.7-.14-1.13c-.03-.31-.05-.54-.05-.74s.02-.43.05-.73l.14-1.13-.89-.7-1.08-.84.7-1.21 1.27.51 1.04.42.9-.68c.43-.32.84-.56 1.25-.73l1.06-.43.16-1.13.2-1.35h1.39l.19 1.35.16 1.13 1.06.43c.43.18.83.41 1.23.71l.91.7 1.06-.43 1.27-.51.7 1.21-1.07.85-.89.7.14 1.13zM12 8c-2.21 0-4 1.79-4 4s1.79 4 4 4 4-1.79 4-4-1.79-4-4-4zm0 6c-1.1 0-2-.9-2-2s.9-2 2-2 2 .9 2 2-.9 2-2 2z"/></svg>

Before

Width:  |  Height:  |  Size: 1.4 KiB

View File

@@ -1 +0,0 @@
<svg xmlns="http://www.w3.org/2000/svg" enable-background="new 0 0 24 24" height="24px" viewBox="0 0 24 24" width="24px" fill="#000000"><rect fill="none" height="24" width="24"/><path d="M10,13c0.55,0,1,0.45,1,1s-0.45,1-1,1s-1-0.45-1-1S9.45,13,10,13 M10,11c-1.66,0-3,1.34-3,3s1.34,3,3,3s3-1.34,3-3 S11.66,11,10,11L10,11z M18.5,9l1.09-2.41L22,5.5l-2.41-1.09L18.5,2l-1.09,2.41L15,5.5l2.41,1.09L18.5,9z M21.28,12.72L20.5,11 l-0.78,1.72L18,13.5l1.72,0.78L20.5,16l0.78-1.72L23,13.5L21.28,12.72z M16.25,14c0-0.12,0-0.25-0.01-0.37l1.94-1.47l-2.5-4.33 l-2.24,0.94c-0.2-0.13-0.42-0.26-0.64-0.37L12.5,6h-5L7.2,8.41C6.98,8.52,6.77,8.65,6.56,8.78L4.32,7.83l-2.5,4.33l1.94,1.47 C3.75,13.75,3.75,13.88,3.75,14s0,0.25,0.01,0.37l-1.94,1.47l2.5,4.33l2.24-0.94c0.2,0.13,0.42,0.26,0.64,0.37L7.5,22h5l0.3-2.41 c0.22-0.11,0.43-0.23,0.64-0.37l2.24,0.94l2.5-4.33l-1.94-1.47C16.25,14.25,16.25,14.12,16.25,14z M14.83,17.64l-1.73-0.73 c-0.56,0.6-1.3,1.04-2.13,1.23L10.73,20H9.27l-0.23-1.86c-0.83-0.19-1.57-0.63-2.13-1.23l-1.73,0.73l-0.73-1.27l1.49-1.13 c-0.12-0.39-0.18-0.8-0.18-1.23c0-0.43,0.06-0.84,0.18-1.23l-1.49-1.13l0.73-1.27l1.73,0.73c0.56-0.6,1.3-1.04,2.13-1.23L9.27,8 h1.47l0.23,1.86c0.83,0.19,1.57,0.63,2.13,1.23l1.73-0.73l0.73,1.27l-1.49,1.13c0.12,0.39,0.18,0.8,0.18,1.23 c0,0.43-0.06,0.84-0.18,1.23l1.49,1.13L14.83,17.64z"/></svg>

Before

Width:  |  Height:  |  Size: 1.3 KiB

View File

@@ -1 +0,0 @@
<svg xmlns="http://www.w3.org/2000/svg" height="24px" viewBox="0 0 24 24" width="24px" fill="#000000"><path d="M0 0h24v24H0V0z" fill="none"/><path d="M18 16.08c-.76 0-1.44.3-1.96.77L8.91 12.7c.05-.23.09-.46.09-.7s-.04-.47-.09-.7l7.05-4.11c.54.5 1.25.81 2.04.81 1.66 0 3-1.34 3-3s-1.34-3-3-3-3 1.34-3 3c0 .24.04.47.09.7L8.04 9.81C7.5 9.31 6.79 9 6 9c-1.66 0-3 1.34-3 3s1.34 3 3 3c.79 0 1.5-.31 2.04-.81l7.12 4.16c-.05.21-.08.43-.08.65 0 1.61 1.31 2.92 2.92 2.92s2.92-1.31 2.92-2.92c0-1.61-1.31-2.92-2.92-2.92zM18 4c.55 0 1 .45 1 1s-.45 1-1 1-1-.45-1-1 .45-1 1-1zM6 13c-.55 0-1-.45-1-1s.45-1 1-1 1 .45 1 1-.45 1-1 1zm12 7.02c-.55 0-1-.45-1-1s.45-1 1-1 1 .45 1 1-.45 1-1 1z"/></svg>

Before

Width:  |  Height:  |  Size: 679 B

View File

@@ -1 +0,0 @@
<svg xmlns="http://www.w3.org/2000/svg" height="24px" viewBox="0 0 24 24" width="24px" fill="#000000"><path d="M0 0h24v24H0V0z" fill="none"/><path d="M22 19h-6v-4h-2.68c-1.14 2.42-3.6 4-6.32 4-3.86 0-7-3.14-7-7s3.14-7 7-7c2.72 0 5.17 1.58 6.32 4H24v6h-2v4zm-4-2h2v-4h2v-2H11.94l-.23-.67C11.01 8.34 9.11 7 7 7c-2.76 0-5 2.24-5 5s2.24 5 5 5c2.11 0 4.01-1.34 4.71-3.33l.23-.67H18v4zM7 15c-1.65 0-3-1.35-3-3s1.35-3 3-3 3 1.35 3 3-1.35 3-3 3zm0-4c-.55 0-1 .45-1 1s.45 1 1 1 1-.45 1-1-.45-1-1-1z"/></svg>

Before

Width:  |  Height:  |  Size: 498 B

View File

@@ -86,15 +86,15 @@ int main(int argc, char *argv[])
QApplication app(argc, argv);
#endif
#if defined(Q_OS_ANDROID)
NativeHelpers::registerApplicationInstance(&app);
#endif
#ifdef Q_OS_WIN
AllowSetForegroundWindow(0);
#endif
#if defined(Q_OS_ANDROID)
NativeHelpers::registerApplicationInstance(&app);
#endif
loadTranslator();
QFontDatabase::addApplicationFont(":/fonts/Lato-Black.ttf");
@@ -120,26 +120,10 @@ int main(int argc, char *argv[])
QCommandLineOption c_autostart {{"a", "autostart"}, "System autostart"};
parser.addOption(c_autostart);
QCommandLineOption c_cleanup {{"c", "cleanup"}, "Cleanup logs"};
parser.addOption(c_cleanup);
parser.process(app);
if (parser.isSet(c_cleanup)) {
Debug::cleanUp();
QTimer::singleShot(100,[&app]{
app.quit();
});
app.exec();
return 0;
}
Settings settings;
if (settings.isSaveLogs()) {
if (!Debug::init()) {
qWarning() << "Initialization of debug subsystem failed";
}
if (!Debug::init()) {
qWarning() << "Initialization of debug subsystem failed";
}
app.setQuitOnLastWindowClosed(false);
@@ -181,8 +165,6 @@ int main(int argc, char *argv[])
QCoreApplication::exit(-1);
}, Qt::QueuedConnection);
engine->rootContext()->setContextProperty("Debug", &Debug::Instance());
engine->rootContext()->setContextProperty("UiLogic", uiLogic);
engine->rootContext()->setContextProperty("AppSettingsLogic", uiLogic->appSettingsLogic());
@@ -214,23 +196,26 @@ int main(int argc, char *argv[])
uiLogic->setQmlRoot(engine->rootObjects().at(0));
}
#ifdef Q_OS_WIN
if (parser.isSet("a")) uiLogic->showOnStartup();
else emit uiLogic->show();
#else
uiLogic->showOnStartup();
#endif
// TODO - fix
#if !defined(Q_OS_ANDROID) && !defined(Q_OS_IOS)
if (app.isPrimary()) {
QObject::connect(&app, &SingleApplication::instanceStarted, uiLogic, [&](){
qDebug() << "Secondary instance started, showing this window instead";
emit uiLogic->show();
emit uiLogic->raise();
});
}
#endif
//#ifdef Q_OS_WIN
// if (parser.isSet("a")) mainWindow.showOnStartup();
// else mainWindow.show();
//#else
// mainWindow.showOnStartup();
//#endif
// TODO - fix
//#if !defined(Q_OS_ANDROID) && !defined(Q_OS_IOS)
// if (app.isPrimary()) {
// QObject::connect(&app, &SingleApplication::instanceStarted, &mainWindow, [&](){
// qDebug() << "Secondary instance started, showing this window instead";
// mainWindow.show();
// mainWindow.showNormal();
// mainWindow.raise();
// });
// }
//#endif
return app.exec();
}

View File

@@ -159,8 +159,8 @@ ErrorCode OpenVpnProtocol::start()
return lastError();
}
// QString vpnLogFileNamePath = Utils::systemLogPath() + "/openvpn.log";
// Utils::createEmptyFile(vpnLogFileNamePath);
QString vpnLogFileNamePath = Utils::systemLogPath() + "/openvpn.log";
Utils::createEmptyFile(vpnLogFileNamePath);
if (!m_managementServer.start(m_managementHost, m_managementPort)) {
setLastError(ErrorCode::OpenVpnManagementServerError);
@@ -186,7 +186,8 @@ ErrorCode OpenVpnProtocol::start()
m_openVpnProcess->setProgram(openVpnExecPath());
QStringList arguments({"--config" , configPath(),
"--management", m_managementHost, QString::number(m_managementPort),
"--management-client"/*, "--log", vpnLogFileNamePath */
"--management-client",
"--log", vpnLogFileNamePath
});
m_openVpnProcess->setArguments(arguments);

View File

@@ -15,10 +15,6 @@ constexpr char password[] = "password";
constexpr char port[] = "port";
constexpr char local_port[] = "local_port";
constexpr char dns1[] = "dns1";
constexpr char dns2[] = "dns2";
constexpr char description[] = "description";
constexpr char cert[] = "cert";
constexpr char config[] = "config";
@@ -59,9 +55,6 @@ constexpr char last_config[] = "last_config";
namespace protocols {
namespace dns {
constexpr char amneziaDnsIp[] = "172.29.172.254";
}
namespace openvpn {
constexpr char defaultSubnetAddress[] = "10.8.0.0";
@@ -97,7 +90,7 @@ constexpr char ckBypassUidKeyPath[] = "/opt/amnezia/cloak/cloak_bypass_uid.key";
constexpr char ckAdminKeyPath[] = "/opt/amnezia/cloak/cloak_admin_uid.key";
constexpr char defaultPort[] = "443";
constexpr char defaultRedirSite[] = "tile.openstreetmap.org";
constexpr char defaultCipher[] = "chacha20-poly1305";
constexpr char defaultCipher[] = "chacha20-ietf-poly1305";
}

View File

@@ -103,14 +103,12 @@ QString VpnProtocol::vpnGateway() const
VpnProtocol *VpnProtocol::factory(DockerContainer container, const QJsonObject& configuration)
{
switch (container) {
#if defined(Q_OS_WINDOWS)
case DockerContainer::Ipsec: return new Ikev2Protocol(configuration);
#endif
#if defined(Q_OS_WINDOWS) || defined(Q_OS_MACX) || (defined(Q_OS_LINUX) && !defined(Q_OS_ANDROID))
case DockerContainer::OpenVpn: return new OpenVpnProtocol(configuration);
case DockerContainer::Cloak: return new OpenVpnOverCloakProtocol(configuration);
case DockerContainer::ShadowSocks: return new ShadowSocksVpnProtocol(configuration);
case DockerContainer::WireGuard: return new WireguardProtocol(configuration);
case DockerContainer::Ipsec: return new Ikev2Protocol(configuration);
#endif
default: return nullptr;
}

View File

@@ -27,9 +27,11 @@
<file>fonts/Lato-Thin.ttf</file>
<file>fonts/Lato-ThinItalic.ttf</file>
<file>images/AmneziaVPN.png</file>
<file>images/server_settings.png</file>
<file>images/share.png</file>
<file>server_scripts/remove_container.sh</file>
<file>server_scripts/setup_host_firewall.sh</file>
<file>images/reload.png</file>
<file>server_scripts/openvpn_cloak/Dockerfile</file>
<file>server_scripts/openvpn_cloak/configure_container.sh</file>
<file>server_scripts/openvpn_cloak/start.sh</file>
@@ -40,6 +42,7 @@
<file>images/check.png</file>
<file>images/uncheck.png</file>
<file>images/settings_grey.png</file>
<file>images/plus.png</file>
<file>server_scripts/check_connection.sh</file>
<file>server_scripts/remove_all_containers.sh</file>
<file>server_scripts/openvpn_cloak/run_container.sh</file>
@@ -139,23 +142,5 @@
<file>images/connected.png</file>
<file>images/disconnected.png</file>
<file>ui/qml/Pages/PageQrDecoder.qml</file>
<file>ui/qml/Pages/PageAbout.qml</file>
<file>ui/qml/Controls/RichLabelType.qml</file>
<file>images/svg/gpp_good_black_24dp.svg</file>
<file>ui/qml/Controls/SvgImageType.qml</file>
<file>images/svg/gpp_maybe_black_24dp.svg</file>
<file>images/svg/close_black_24dp.svg</file>
<file>images/svg/delete_black_24dp.svg</file>
<file>images/svg/done_black_24dp.svg</file>
<file>images/svg/format_list_bulleted_black_24dp.svg</file>
<file>images/svg/logout_black_24dp.svg</file>
<file>images/svg/miscellaneous_services_black_24dp.svg</file>
<file>images/svg/refresh_black_24dp.svg</file>
<file>images/svg/settings_black_24dp.svg</file>
<file>images/svg/share_black_24dp.svg</file>
<file>images/svg/vpn_key_black_24dp.svg</file>
<file>images/svg/control_point_black_24dp.svg</file>
<file>images/svg/settings_suggest_black_24dp.svg</file>
<file>ui/qml/Controls/SvgButtonType.qml</file>
</qresource>
</RCC>

View File

@@ -1,2 +1,2 @@
# Run container
sudo docker run -d --restart always --network amnezia-dns-net --ip=172.29.172.254 --name $CONTAINER_NAME $CONTAINER_NAME
sudo docker run -d --restart always --cap-add=NET_ADMIN -p 53:53/udp -p 53:53/tcp --name $CONTAINER_NAME $CONTAINER_NAME

View File

@@ -5,4 +5,3 @@ sudo docker run \
-d --privileged \
--name $CONTAINER_NAME $CONTAINER_NAME
sudo docker network connect amnezia-dns-net $CONTAINER_NAME

View File

@@ -1,4 +1,4 @@
FROM alpine:3.15
FROM alpine:latest
LABEL maintainer="AmneziaVPN"

View File

@@ -1,11 +1,5 @@
# Run container
sudo docker run \
-d --restart always \
--cap-add=NET_ADMIN \
-p $OPENVPN_PORT:$OPENVPN_PORT/$OPENVPN_TRANSPORT_PROTO \
--name $CONTAINER_NAME $CONTAINER_NAME
sudo docker network connect amnezia-dns-net $CONTAINER_NAME
sudo docker run -d --restart always --cap-add=NET_ADMIN -p $OPENVPN_PORT:$OPENVPN_PORT/$OPENVPN_TRANSPORT_PROTO --name $CONTAINER_NAME $CONTAINER_NAME
# Create tun device if not exist
sudo docker exec -i $CONTAINER_NAME bash -c 'mkdir -p /dev/net; if [ ! -c /dev/net/tun ]; then mknod /dev/net/tun c 10 200; fi'

View File

@@ -14,12 +14,9 @@ iptables -A OUTPUT -o tun0 -j ACCEPT
# Allow forwarding traffic only from the VPN.
iptables -A FORWARD -i tun0 -o eth0 -s $OPENVPN_SUBNET_IP/$OPENVPN_SUBNET_CIDR -j ACCEPT
iptables -A FORWARD -i tun0 -o eth1 -s $OPENVPN_SUBNET_IP/$OPENVPN_SUBNET_CIDR -j ACCEPT
iptables -A FORWARD -m state --state ESTABLISHED,RELATED -j ACCEPT
iptables -t nat -A POSTROUTING -s $OPENVPN_SUBNET_IP/$OPENVPN_SUBNET_CIDR -o eth0 -j MASQUERADE
iptables -t nat -A POSTROUTING -s $OPENVPN_SUBNET_IP/$OPENVPN_SUBNET_CIDR -o eth1 -j MASQUERADE
# kill daemons in case of restart
killall -KILL openvpn

View File

@@ -1,11 +1,7 @@
FROM alpine:3.15
FROM alpine:latest
LABEL maintainer="AmneziaVPN"
ARG SS_RELEASE="v1.13.1"
ARG CLOAK_RELEASE="v2.5.5"
ARG SERVER_ARCH
#Install required packages
RUN apk add --no-cache curl openvpn easy-rsa bash netcat-openbsd dumb-init rng-tools
RUN apk --update upgrade --no-cache
@@ -17,16 +13,10 @@ RUN mkdir -p /opt/amnezia
RUN echo -e "#!/bin/bash\ntail -f /dev/null" > /opt/amnezia/start.sh
RUN chmod a+x /opt/amnezia/start.sh
RUN if [ $SERVER_ARCH="x86_64" ]; then CK_ARCH="amd64"; \
elif [ $SERVER_ARCH="i686" ]; then CK_ARCH="386"; \
elif [ $SERVER_ARCH="aarch64" ]; then CK_ARCH="arm64"; \
elif [ $SERVER_ARCH="arm" ]; then CK_ARCH="arm"; \
else exit -1; fi && \
curl -L https://github.com/cbeuw/Cloak/releases/download/${CLOAK_RELEASE}/ck-server-linux-${CK_ARCH}-${CLOAK_RELEASE} > /usr/bin/ck-server
RUN curl -L https://github.com/cbeuw/Cloak/releases/download/v2.5.3/ck-server-linux-amd64-v2.5.3 > /usr/bin/ck-server
RUN chmod a+x /usr/bin/ck-server
RUN curl -L https://github.com/shadowsocks/shadowsocks-rust/releases/download/${SS_RELEASE}/shadowsocks-${SS_RELEASE}.${SERVER_ARCH}-unknown-linux-musl.tar.xz > /usr/bin/ss.tar.xz
RUN curl -L https://github.com/shadowsocks/shadowsocks-rust/releases/download/v1.10.9/shadowsocks-v1.10.9.x86_64-unknown-linux-musl.tar.xz > /usr/bin/ss.tar.xz
RUN tar -Jxvf /usr/bin/ss.tar.xz -C /usr/bin/
RUN chmod a+x /usr/bin/ssserver

View File

@@ -1,11 +1,5 @@
# Run container
sudo docker run \
-d --restart always \
--cap-add=NET_ADMIN \
-p $CLOAK_SERVER_PORT:443/tcp \
--name $CONTAINER_NAME $CONTAINER_NAME
sudo docker network connect amnezia-dns-net $CONTAINER_NAME
sudo docker run -d --restart always --cap-add=NET_ADMIN -p $CLOAK_SERVER_PORT:443/tcp --name $CONTAINER_NAME $CONTAINER_NAME
# Create tun device if not exist
sudo docker exec -i $CONTAINER_NAME bash -c 'mkdir -p /dev/net; if [ ! -c /dev/net/tun ]; then mknod /dev/net/tun c 10 200; fi'

View File

@@ -14,12 +14,9 @@ iptables -A OUTPUT -o tun0 -j ACCEPT
# Allow forwarding traffic only from the VPN.
iptables -A FORWARD -i tun0 -o eth0 -s $OPENVPN_SUBNET_IP/$OPENVPN_SUBNET_CIDR -j ACCEPT
iptables -A FORWARD -i tun0 -o eth1 -s $OPENVPN_SUBNET_IP/$OPENVPN_SUBNET_CIDR -j ACCEPT
iptables -A FORWARD -m state --state ESTABLISHED,RELATED -j ACCEPT
iptables -t nat -A POSTROUTING -s $OPENVPN_SUBNET_IP/$OPENVPN_SUBNET_CIDR -o eth0 -j MASQUERADE
iptables -t nat -A POSTROUTING -s $OPENVPN_SUBNET_IP/$OPENVPN_SUBNET_CIDR -o eth1 -j MASQUERADE
# kill daemons in case of restart
killall -KILL openvpn

View File

@@ -1,7 +1,7 @@
FROM alpine:3.15
FROM alpine:latest
LABEL maintainer="AmneziaVPN"
ARG SS_RELEASE="v1.13.1"
ARG SS_RELEASE="v1.11.2"
ARG SERVER_ARCH
#Install required packages

View File

@@ -1,11 +1,5 @@
# Run container
sudo docker run \
-d --restart always \
--cap-add=NET_ADMIN \
-p $SHADOWSOCKS_SERVER_PORT:$SHADOWSOCKS_SERVER_PORT/tcp \
--name $CONTAINER_NAME $CONTAINER_NAME
sudo docker network connect amnezia-dns-net $CONTAINER_NAME
sudo docker run -d --restart always --cap-add=NET_ADMIN -p $SHADOWSOCKS_SERVER_PORT:$SHADOWSOCKS_SERVER_PORT/tcp --name $CONTAINER_NAME $CONTAINER_NAME
# Create tun device if not exist
sudo docker exec -i $CONTAINER_NAME bash -c 'mkdir -p /dev/net; if [ ! -c /dev/net/tun ]; then mknod /dev/net/tun c 10 200; fi'

View File

@@ -14,12 +14,9 @@ iptables -A OUTPUT -o tun0 -j ACCEPT
# Allow forwarding traffic only from the VPN.
iptables -A FORWARD -i tun0 -o eth0 -s $OPENVPN_SUBNET_IP/$OPENVPN_SUBNET_CIDR -j ACCEPT
iptables -A FORWARD -i tun0 -o eth1 -s $OPENVPN_SUBNET_IP/$OPENVPN_SUBNET_CIDR -j ACCEPT
iptables -A FORWARD -m state --state ESTABLISHED,RELATED -j ACCEPT
iptables -t nat -A POSTROUTING -s $OPENVPN_SUBNET_IP/$OPENVPN_SUBNET_CIDR -o eth0 -j MASQUERADE
iptables -t nat -A POSTROUTING -s $OPENVPN_SUBNET_IP/$OPENVPN_SUBNET_CIDR -o eth1 -j MASQUERADE
# kill daemons in case of restart
killall -KILL openvpn

View File

@@ -1,4 +1,3 @@
CUR_USER=$(whoami);\
sudo mkdir -p $DOCKERFILE_FOLDER;\
sudo chown $CUR_USER $DOCKERFILE_FOLDER
if ! sudo docker network ls | grep -q amnezia-dns-net; then sudo docker network create --driver bridge --subnet=172.29.172.0/24 --opt com.docker.network.bridge.name=amn0 amnezia-dns-net; fi

View File

@@ -1,4 +1,4 @@
FROM alpine:3.15
FROM alpine:latest
LABEL maintainer="AmneziaVPN"

View File

@@ -10,8 +10,6 @@ sudo docker run -d \
--name $CONTAINER_NAME \
$CONTAINER_NAME
sudo docker network connect amnezia-dns-net $CONTAINER_NAME
# Prevent to route packets outside of the container in case if server behind of the NAT
#sudo docker exec -i $CONTAINER_NAME sh -c "ifconfig eth0:0 $SERVER_IP_ADDRESS netmask 255.255.255.255 up"

View File

@@ -18,11 +18,8 @@ iptables -A OUTPUT -o wg0 -j ACCEPT
# Allow forwarding traffic only from the VPN.
iptables -A FORWARD -i wg0 -o eth0 -s $WIREGUARD_SUBNET_IP/$WIREGUARD_SUBNET_CIDR -j ACCEPT
iptables -A FORWARD -i wg0 -o eth1 -s $WIREGUARD_SUBNET_IP/$WIREGUARD_SUBNET_CIDR -j ACCEPT
iptables -A FORWARD -m state --state ESTABLISHED,RELATED -j ACCEPT
iptables -t nat -A POSTROUTING -s $WIREGUARD_SUBNET_IP/$WIREGUARD_SUBNET_CIDR -o eth0 -j MASQUERADE
iptables -t nat -A POSTROUTING -s $WIREGUARD_SUBNET_IP/$WIREGUARD_SUBNET_CIDR -o eth1 -j MASQUERADE
tail -f /dev/null

View File

@@ -228,21 +228,6 @@ void Settings::addVpnSite(RouteMode mode, const QString &site, const QString &ip
setVpnSites(mode, sites);
}
void Settings::addVpnSites(RouteMode mode, const QMap<QString, QString> &sites)
{
QVariantMap allSites = vpnSites(mode);
for (auto i = sites.constBegin(); i != sites.constEnd(); ++i) {
const QString &site = i.key();
const QString &ip = i.value();
if (allSites.contains(site) && allSites.value(site) == ip) continue;
allSites.insert(site, ip);
}
setVpnSites(mode, allSites);
}
QStringList Settings::getVpnIps(RouteMode mode) const
{
QStringList ips;

View File

@@ -67,9 +67,6 @@ public:
bool isStartMinimized() const { return m_settings.value("Conf/startMinimized", false).toBool(); }
void setStartMinimized(bool enabled) { m_settings.setValue("Conf/startMinimized", enabled); }
bool isSaveLogs() const { return m_settings.value("Conf/saveLogs", false).toBool(); }
void setSaveLogs(bool enabled) { m_settings.setValue("Conf/saveLogs", enabled); }
enum RouteMode {
VpnAllSites,
VpnOnlyForwardSites,
@@ -85,15 +82,12 @@ public:
QVariantMap vpnSites(RouteMode mode) const { return m_settings.value("Conf/" + routeModeString(mode)).toMap(); }
void setVpnSites(RouteMode mode, const QVariantMap &sites) { m_settings.setValue("Conf/"+ routeModeString(mode), sites); m_settings.sync(); }
void addVpnSite(RouteMode mode, const QString &site, const QString &ip= "");
void addVpnSites(RouteMode mode, const QMap<QString, QString> &sites); // map <site, ip>
QStringList getVpnIps(RouteMode mode) const;
void removeVpnSite(RouteMode mode, const QString &site);
void addVpnIps(RouteMode mode, const QStringList &ip);
void removeVpnSites(RouteMode mode, const QStringList &sites);
bool useAmneziaDns() const { return m_settings.value("Conf/useAmneziaDns", true).toBool(); }
void setUseAmneziaDns(bool enabled) { m_settings.setValue("Conf/useAmneziaDns", enabled); }
QString primaryDns() const;
QString secondaryDns() const;

2383
client/ui/mainwindow.cpp Normal file

File diff suppressed because it is too large Load Diff

View File

@@ -24,7 +24,7 @@ enum class Page {Start = 0, NewServer, NewServerProtocols, Vpn,
Wizard, WizardLow, WizardMedium, WizardHigh, WizardVpnMode, ServerConfiguringProgress,
GeneralSettings, AppSettings, NetworkSettings, ServerSettings,
ServerContainers, ServersList, ShareConnection, Sites,
ProtocolSettings, ProtocolShare, QrDecoder, About};
ProtocolSettings, ProtocolShare, QrDecoder};
Q_ENUM_NS(Page)
static void declareQmlPageEnum() {

View File

@@ -3,11 +3,6 @@
#include "debug.h"
#include "defines.h"
#include "ui/qautostart.h"
#include "ui/uilogic.h"
#include <QDesktopServices>
#include <QFileDialog>
#include <QStandardPaths>
using namespace amnezia;
using namespace PageEnumNS;
@@ -16,8 +11,7 @@ AppSettingsLogic::AppSettingsLogic(UiLogic *logic, QObject *parent):
PageLogicBase(logic, parent),
m_checkBoxAutostartChecked{false},
m_checkBoxAutoConnectChecked{false},
m_checkBoxStartMinimizedChecked{false},
m_checkBoxSaveLogsChecked{false}
m_checkBoxStartMinimizedChecked{false}
{
}
@@ -27,7 +21,6 @@ void AppSettingsLogic::onUpdatePage()
set_checkBoxAutostartChecked(Autostart::isAutostart());
set_checkBoxAutoConnectChecked(m_settings.isAutoConnect());
set_checkBoxStartMinimizedChecked(m_settings.isStartMinimized());
set_checkBoxSaveLogsChecked(m_settings.isSaveLogs());
QString ver = QString("%1: %2 (%3)")
.arg(tr("Software version"))
@@ -54,23 +47,7 @@ void AppSettingsLogic::onCheckBoxStartMinimizedToggled(bool checked)
m_settings.setStartMinimized(checked);
}
void AppSettingsLogic::onCheckBoxSaveLogsCheckedToggled(bool checked)
{
m_settings.setSaveLogs(checked);
}
void AppSettingsLogic::onPushButtonOpenLogsClicked()
{
Debug::openLogsFolder();
}
void AppSettingsLogic::onPushButtonExportLogsClicked()
{
uiLogic()->saveTextFile(tr("Save log"), "AmneziaVPN.log", ".log", Debug::getLogFile());
}
void AppSettingsLogic::onPushButtonClearLogsClicked()
{
Debug::clearLogs();
Debug::clearServiceLogs();
}

View File

@@ -11,7 +11,6 @@ class AppSettingsLogic : public PageLogicBase
AUTO_PROPERTY(bool, checkBoxAutostartChecked)
AUTO_PROPERTY(bool, checkBoxAutoConnectChecked)
AUTO_PROPERTY(bool, checkBoxStartMinimizedChecked)
AUTO_PROPERTY(bool, checkBoxSaveLogsChecked)
AUTO_PROPERTY(QString, labelVersionText)
public:
@@ -20,10 +19,7 @@ public:
Q_INVOKABLE void onCheckBoxAutostartToggled(bool checked);
Q_INVOKABLE void onCheckBoxAutoconnectToggled(bool checked);
Q_INVOKABLE void onCheckBoxStartMinimizedToggled(bool checked);
Q_INVOKABLE void onCheckBoxSaveLogsCheckedToggled(bool checked);
Q_INVOKABLE void onPushButtonOpenLogsClicked();
Q_INVOKABLE void onPushButtonExportLogsClicked();
Q_INVOKABLE void onPushButtonClearLogsClicked();
public:
explicit AppSettingsLogic(UiLogic *uiLogic, QObject *parent = nullptr);

View File

@@ -5,7 +5,6 @@
NetworkSettingsLogic::NetworkSettingsLogic(UiLogic *logic, QObject *parent):
PageLogicBase(logic, parent),
m_checkBoxUseAmneziaDnsChecked{false},
m_ipAddressRegex{Utils::ipAddressRegExp()}
{
@@ -13,8 +12,6 @@ NetworkSettingsLogic::NetworkSettingsLogic(UiLogic *logic, QObject *parent):
void NetworkSettingsLogic::onUpdatePage()
{
set_checkBoxUseAmneziaDnsChecked(m_settings.useAmneziaDns());
set_lineEditDns1Text(m_settings.primaryDns());
set_lineEditDns2Text(m_settings.secondaryDns());
}
@@ -44,8 +41,3 @@ void NetworkSettingsLogic::onPushButtonResetDns2Clicked()
m_settings.setSecondaryDns(m_settings.cloudFlareNs2);
onUpdatePage();
}
void NetworkSettingsLogic::onCheckBoxUseAmneziaDnsToggled(bool checked)
{
m_settings.setUseAmneziaDns(checked);
}

View File

@@ -9,8 +9,6 @@ class NetworkSettingsLogic : public PageLogicBase
{
Q_OBJECT
AUTO_PROPERTY(bool, checkBoxUseAmneziaDnsChecked)
AUTO_PROPERTY(QString, lineEditDns1Text)
AUTO_PROPERTY(QString, lineEditDns2Text)
READONLY_PROPERTY(QRegExp, ipAddressRegex)
@@ -23,8 +21,6 @@ public:
Q_INVOKABLE void onPushButtonResetDns1Clicked();
Q_INVOKABLE void onPushButtonResetDns2Clicked();
Q_INVOKABLE void onCheckBoxUseAmneziaDnsToggled(bool checked);
public:
explicit NetworkSettingsLogic(UiLogic *uiLogic, QObject *parent = nullptr);
~NetworkSettingsLogic() = default;

View File

@@ -38,6 +38,8 @@ void QrDecoderLogic::onDetectedQrCode(const QString &code)
if (magic == amnezia::qrMagicCode) {
qDebug() << "QrDecoderLogic::onDetectedQrCode magic code detected" << magic << ba.size();
quint8 chunksCount; s >> chunksCount;
if (totalChunksCount() != chunksCount) {
m_chunks.clear();

View File

@@ -12,9 +12,6 @@
#include <functional>
#include "../uilogic.h"
#include "../pages_logic/VpnLogic.h"
#include "vpnconnection.h"
ServerContainersLogic::ServerContainersLogic(UiLogic *logic, QObject *parent):
PageLogicBase(logic, parent)
@@ -45,17 +42,8 @@ void ServerContainersLogic::onPushButtonProtoSettingsClicked(DockerContainer c,
void ServerContainersLogic::onPushButtonDefaultClicked(DockerContainer c)
{
if (m_settings.defaultContainer(uiLogic()->selectedServerIndex) == c) return;
m_settings.setDefaultContainer(uiLogic()->selectedServerIndex, c);
uiLogic()->onUpdateAllPages();
if (uiLogic()->selectedServerIndex != m_settings.defaultServerIndex()) return;
if (!uiLogic()->m_vpnConnection) return;
if (!uiLogic()->m_vpnConnection->isConnected()) return;
uiLogic()->vpnLogic()->onDisconnect();
uiLogic()->vpnLogic()->onConnect();
}
void ServerContainersLogic::onPushButtonShareClicked(DockerContainer c)

View File

@@ -8,7 +8,6 @@
#include "core/errorstrings.h"
#include <core/servercontroller.h>
#include <QTimer>
ServerSettingsLogic::ServerSettingsLogic(UiLogic *logic, QObject *parent):
PageLogicBase(logic, parent),
@@ -29,8 +28,8 @@ void ServerSettingsLogic::onUpdatePage()
set_pushButtonClearVisible(m_settings.haveAuthData(uiLogic()->selectedServerIndex));
set_pushButtonClearClientCacheVisible(m_settings.haveAuthData(uiLogic()->selectedServerIndex));
set_pushButtonShareFullVisible(m_settings.haveAuthData(uiLogic()->selectedServerIndex));
const QJsonObject &server = m_settings.server(uiLogic()->selectedServerIndex);
const QString &port = server.value(config_key::port).toString();
QJsonObject server = m_settings.server(uiLogic()->selectedServerIndex);
QString port = server.value(config_key::port).toString();
set_labelServerText(QString("%1@%2%3%4")
.arg(server.value(config_key::userName).toString())
.arg(server.value(config_key::hostName).toString())

View File

@@ -1,13 +1,9 @@
#include <QBuffer>
#include <QImage>
#include <QDataStream>
//#include <QZXing>
#include <QZXing>
#include <QMessageBox>
#include "QZXing.h"
#include "QZXingImageProvider.h"
#include "QZXingFilter.h"
#include "ShareConnectionLogic.h"
#include "configurators/cloak_configurator.h"
@@ -64,24 +60,21 @@ void ShareConnectionLogic::onPushButtonShareAmneziaGenerateClicked()
set_shareAmneziaQrCodeTextSeriesLength(0);
QJsonObject serverConfig;
int serverIndex = uiLogic()->selectedServerIndex;
DockerContainer container = uiLogic()->selectedDockerContainer;
// Full access
if (shareFullAccess()) {
serverConfig = m_settings.server(serverIndex);
serverConfig = m_settings.server(uiLogic()->selectedServerIndex);
}
// Container share
else {
ServerCredentials credentials = m_settings.serverCredentials(serverIndex);
QJsonObject containerConfig = m_settings.containerConfig(serverIndex, container);
containerConfig.insert(config_key::container, ContainerProps::containerToString(container));
ServerCredentials credentials = m_settings.serverCredentials(uiLogic()->selectedServerIndex);
QJsonObject containerConfig = m_settings.containerConfig(uiLogic()->selectedServerIndex, uiLogic()->selectedDockerContainer);
containerConfig.insert(config_key::container, ContainerProps::containerToString(uiLogic()->selectedDockerContainer));
ErrorCode e = ErrorCode::NoError;
for (Proto p: ContainerProps::protocolsForContainer(container)) {
QJsonObject protoConfig = m_settings.protocolConfig(serverIndex, container, p);
for (Proto p: ContainerProps::protocolsForContainer(uiLogic()->selectedDockerContainer)) {
QJsonObject protoConfig = m_settings.protocolConfig(uiLogic()->selectedServerIndex, uiLogic()->selectedDockerContainer, p);
QString cfg = VpnConfigurator::genVpnProtocolConfig(credentials, container, containerConfig, p, &e);
QString cfg = VpnConfigurator::genVpnProtocolConfig(credentials, uiLogic()->selectedDockerContainer, containerConfig, p, &e);
if (e) {
cfg = "Error generating config";
break;
@@ -92,17 +85,12 @@ void ShareConnectionLogic::onPushButtonShareAmneziaGenerateClicked()
QByteArray ba;
if (!e) {
serverConfig = m_settings.server(serverIndex);
serverConfig = m_settings.server(uiLogic()->selectedServerIndex);
serverConfig.remove(config_key::userName);
serverConfig.remove(config_key::password);
serverConfig.remove(config_key::port);
serverConfig.insert(config_key::containers, QJsonArray {containerConfig});
serverConfig.insert(config_key::defaultContainer, ContainerProps::containerToString(container));
auto dns = VpnConfigurator::getDnsForConfig(serverIndex);
serverConfig.insert(config_key::dns1, dns.first);
serverConfig.insert(config_key::dns2, dns.second);
serverConfig.insert(config_key::defaultContainer, ContainerProps::containerToString(uiLogic()->selectedDockerContainer));
}
else {
set_textEditShareAmneziaCodeText(tr("Error while generating connection profile"));
@@ -123,15 +111,12 @@ void ShareConnectionLogic::onPushButtonShareAmneziaGenerateClicked()
void ShareConnectionLogic::onPushButtonShareOpenVpnGenerateClicked()
{
int serverIndex = uiLogic()->selectedServerIndex;
DockerContainer container = uiLogic()->selectedDockerContainer;
ServerCredentials credentials = m_settings.serverCredentials(serverIndex);
const QJsonObject &containerConfig = m_settings.containerConfig(serverIndex, container);
ServerCredentials credentials = m_settings.serverCredentials(uiLogic()->selectedServerIndex);
const QJsonObject &containerConfig = m_settings.containerConfig(uiLogic()->selectedServerIndex, uiLogic()->selectedDockerContainer);
ErrorCode e = ErrorCode::NoError;
QString cfg = OpenVpnConfigurator::genOpenVpnConfig(credentials, container, containerConfig, &e);
cfg = VpnConfigurator::processConfigWithExportSettings(serverIndex, container, Proto::OpenVpn, cfg);
QString cfg = OpenVpnConfigurator::genOpenVpnConfig(credentials, uiLogic()->selectedDockerContainer, containerConfig, &e);
cfg = VpnConfigurator::processConfigWithExportSettings(uiLogic()->selectedDockerContainer, Proto::OpenVpn, cfg);
set_textEditShareOpenVpnCodeText(QJsonDocument::fromJson(cfg.toUtf8()).object()[config_key::config].toString());
}
@@ -217,7 +202,7 @@ void ShareConnectionLogic::onPushButtonShareWireGuardGenerateClicked()
errorString(e));
return;
}
cfg = VpnConfigurator::processConfigWithExportSettings(serverIndex, container, Proto::WireGuard, cfg);
cfg = VpnConfigurator::processConfigWithExportSettings(container, Proto::WireGuard, cfg);
cfg = QJsonDocument::fromJson(cfg.toUtf8()).object()[config_key::config].toString();
set_textEditShareWireGuardCodeText(cfg);
@@ -238,7 +223,7 @@ void ShareConnectionLogic::onPushButtonShareIkev2GenerateClicked()
Ikev2Configurator::ConnectionData connData = Ikev2Configurator::prepareIkev2Config(credentials, container);
QString cfg = Ikev2Configurator::genIkev2Config(connData);
cfg = VpnConfigurator::processConfigWithExportSettings(serverIndex, container, Proto::Ikev2, cfg);
cfg = VpnConfigurator::processConfigWithExportSettings(container, Proto::Ikev2, cfg);
cfg = QJsonDocument::fromJson(cfg.toUtf8()).object()[config_key::cert].toString();
set_textEditShareIkev2CertText(cfg);

View File

@@ -98,32 +98,27 @@ void SitesLogic::onPushButtonAddCustomSitesClicked()
}
}
void SitesLogic::onPushButtonSitesDeleteClicked(QStringList items)
void SitesLogic::onPushButtonSitesDeleteClicked(int row)
{
Settings::RouteMode mode = m_settings.routeMode();
auto siteModel = qobject_cast<SitesModel*> (tableViewSitesModel());
if (!siteModel || items.isEmpty()) {
if (!siteModel) {
return;
}
if (row < 0 || row >= siteModel->rowCount()) {
return;
}
QStringList sites;
QStringList ips;
for (const QString &s: items) {
bool ok;
int row = s.toInt(&ok);
if (!ok || row < 0 || row >= siteModel->rowCount()) return;
{
QStringList sites;
sites.append(siteModel->data(row, 0).toString());
if (uiLogic()->m_vpnConnection->connectionState() == VpnProtocol::Connected) {
ips.append(siteModel->data(row, 1).toString());
}
m_settings.removeVpnSites(mode, sites);
}
m_settings.removeVpnSites(mode, sites);
if (uiLogic()->m_vpnConnection->connectionState() == VpnProtocol::Connected) {
QStringList ips;
ips.append(siteModel->data(row, 1).toString());
uiLogic()->m_vpnConnection->deleteRoutes(ips);
uiLogic()->m_vpnConnection->flushDns();
}
@@ -142,53 +137,18 @@ void SitesLogic::onPushButtonSitesImportClicked(const QString& fileName)
Settings::RouteMode mode = m_settings.routeMode();
QStringList ips;
QMap<QString, QString> sites;
while (!file.atEnd()) {
QString line = file.readLine();
QStringList line_ips;
QStringList line_sites;
int posDomain = 0;
QRegExp domainRx = Utils::domainRegExp();
while ((posDomain = domainRx.indexIn(line, posDomain)) != -1) {
line_sites.append(domainRx.cap(0));
posDomain += domainRx.matchedLength();
int pos = 0;
QRegExp rx = Utils::ipAddressWithSubnetRegExp();
while ((pos = rx.indexIn(line, pos)) != -1) {
ips << rx.cap(0);
pos += rx.matchedLength();
}
int posIp = 0;
QRegExp ipRx = Utils::ipAddressWithSubnetRegExp();
while ((posIp = ipRx.indexIn(line, posIp)) != -1) {
line_ips.append(ipRx.cap(0));
posIp += ipRx.matchedLength();
}
// domain regex cover ip regex, so remove ips from sites
for (const QString& ip: line_ips) {
line_sites.removeAll(ip);
}
if (line_sites.size() == 1 && line_ips.size() == 1) {
sites.insert(line_sites.at(0), line_ips.at(0));
}
else if (line_sites.size() > 0 && line_ips.size() == 0) {
for (const QString& site: line_sites) {
sites.insert(site, "");
}
}
else {
for (const QString& site: line_sites) {
sites.insert(site, "");
}
for (const QString& ip: line_ips) {
ips.append(ip);
}
}
}
m_settings.addVpnIps(mode, ips);
m_settings.addVpnSites(mode, sites);
uiLogic()->m_vpnConnection->addRoutes(QStringList() << ips);
uiLogic()->m_vpnConnection->flushDns();
@@ -196,16 +156,3 @@ void SitesLogic::onPushButtonSitesImportClicked(const QString& fileName)
onUpdatePage();
}
void SitesLogic::onPushButtonSitesExportClicked()
{
Settings::RouteMode mode = m_settings.routeMode();
QVariantMap sites = m_settings.vpnSites(mode);
QString data;
for (auto s : sites.keys()) {
data += s + "\t" + sites.value(s).toString() + "\n";
}
uiLogic()->saveTextFile("Export Sites", "sites.txt", ".txt", data);
}

View File

@@ -18,10 +18,8 @@ public:
Q_INVOKABLE void onUpdatePage() override;
Q_INVOKABLE void onPushButtonAddCustomSitesClicked();
Q_INVOKABLE void onPushButtonSitesDeleteClicked(QStringList items);
Q_INVOKABLE void onPushButtonSitesDeleteClicked(int row);
Q_INVOKABLE void onPushButtonSitesImportClicked(const QString &fileName);
Q_INVOKABLE void onPushButtonSitesExportClicked();
public:
explicit SitesLogic(UiLogic *uiLogic, QObject *parent = nullptr);

View File

@@ -1,14 +1,10 @@
#include <QApplication>
#include "VpnLogic.h"
#include "core/errorstrings.h"
#include "vpnconnection.h"
#include <QTimer>
#include <functional>
#include "../uilogic.h"
#include "defines.h"
#include <configurators/vpn_configurator.h>
VpnLogic::VpnLogic(UiLogic *logic, QObject *parent):
@@ -22,8 +18,6 @@ VpnLogic::VpnLogic(UiLogic *logic, QObject *parent):
m_labelSpeedReceivedText{tr("0 Mbps")},
m_labelSpeedSentText{tr("0 Mbps")},
m_labelStateText{},
m_isContainerHaveAuthData{false},
m_isContainerSupportedByCurrentPlatform{false},
m_widgetVpnModeEnabled{false}
{
connect(uiLogic()->m_vpnConnection, &VpnConnection::bytesChanged, this, &VpnLogic::onBytesChanged);
@@ -39,26 +33,15 @@ VpnLogic::VpnLogic(UiLogic *logic, QObject *parent):
onConnect();
});
}
else {
onConnectionStateChanged(VpnProtocol::Disconnected);
}
}
void VpnLogic::onUpdatePage()
{
Settings::RouteMode mode = m_settings.routeMode();
DockerContainer selectedContainer = m_settings.defaultContainer(m_settings.defaultServerIndex());
set_isCustomRoutesSupported (selectedContainer == DockerContainer::OpenVpn ||
selectedContainer == DockerContainer::ShadowSocks||
selectedContainer == DockerContainer::Cloak);
set_isContainerHaveAuthData(m_settings.haveAuthData(m_settings.defaultServerIndex()));
set_radioButtonVpnModeAllSitesChecked(mode == Settings::VpnAllSites || !isCustomRoutesSupported());
set_radioButtonVpnModeForwardSitesChecked(mode == Settings::VpnOnlyForwardSites && isCustomRoutesSupported());
set_radioButtonVpnModeExceptSitesChecked(mode == Settings::VpnAllExceptSites && isCustomRoutesSupported());
set_radioButtonVpnModeAllSitesChecked(mode == Settings::VpnAllSites);
set_radioButtonVpnModeForwardSitesChecked(mode == Settings::VpnOnlyForwardSites);
set_radioButtonVpnModeExceptSitesChecked(mode == Settings::VpnAllExceptSites);
const QJsonObject &server = uiLogic()->m_settings.defaultServer();
QString serverString = QString("%2 (%3)")
@@ -66,21 +49,12 @@ void VpnLogic::onUpdatePage()
.arg(server.value(config_key::hostName).toString());
set_labelCurrentServer(serverString);
DockerContainer selectedContainer = m_settings.defaultContainer(m_settings.defaultServerIndex());
QString selectedContainerName = ContainerProps::containerHumanNames().value(selectedContainer);
set_labelCurrentService(selectedContainerName);
auto dns = VpnConfigurator::getDnsForConfig(m_settings.defaultServerIndex());
set_amneziaDnsEnabled(dns.first == protocols::dns::amneziaDnsIp);
if (dns.first == protocols::dns::amneziaDnsIp) {
set_labelCurrentDns("On your server");
}
else {
set_labelCurrentDns(dns.first + ", " + dns.second);
}
set_isContainerSupportedByCurrentPlatform(ContainerProps::isSupportedByCurrentPlatform(selectedContainer));
if (!isContainerSupportedByCurrentPlatform()) {
set_isContainerWorkingOnPlatform(ContainerProps::isWorkingOnPlatform(selectedContainer));
if (!isContainerWorkingOnPlatform()) {
set_labelErrorText(tr("AmneziaVPN not supporting selected protocol on this device. Select another protocol."));
}
else {
@@ -242,6 +216,6 @@ void VpnLogic::onConnectWorker(int serverIndex, const ServerCredentials &credent
void VpnLogic::onDisconnect()
{
onConnectionStateChanged(VpnProtocol::Disconnected);
set_pushButtonConnectChecked(false);
emit disconnectFromVpn();
}

View File

@@ -16,20 +16,14 @@ class VpnLogic : public PageLogicBase
AUTO_PROPERTY(QString, labelStateText)
AUTO_PROPERTY(QString, labelCurrentServer)
AUTO_PROPERTY(QString, labelCurrentService)
AUTO_PROPERTY(QString, labelCurrentDns)
AUTO_PROPERTY(bool, amneziaDnsEnabled)
AUTO_PROPERTY(bool, pushButtonConnectEnabled)
AUTO_PROPERTY(bool, pushButtonConnectVisible)
AUTO_PROPERTY(bool, widgetVpnModeEnabled)
AUTO_PROPERTY(bool, isContainerSupportedByCurrentPlatform)
AUTO_PROPERTY(bool, isContainerHaveAuthData)
AUTO_PROPERTY(bool, isContainerWorkingOnPlatform)
AUTO_PROPERTY(QString, labelErrorText)
AUTO_PROPERTY(QString, labelVersionText)
AUTO_PROPERTY(bool, isCustomRoutesSupported)
AUTO_PROPERTY(bool, radioButtonVpnModeAllSitesChecked)
AUTO_PROPERTY(bool, radioButtonVpnModeForwardSitesChecked)
AUTO_PROPERTY(bool, radioButtonVpnModeExceptSitesChecked)

View File

@@ -2,7 +2,6 @@
#include <QTimer>
#include <QProcess>
#include <QStorageInfo>
#include <QStandardPaths>
#include "OtherProtocolsLogic.h"
#include "core/servercontroller.h"
@@ -18,9 +17,7 @@ using namespace amnezia;
using namespace PageEnumNS;
OtherProtocolsLogic::OtherProtocolsLogic(UiLogic *logic, QObject *parent):
PageProtocolLogicBase(logic, parent),
m_checkBoxSftpRestoreChecked{false}
PageProtocolLogicBase(logic, parent)
{
}
@@ -44,12 +41,17 @@ void OtherProtocolsLogic::updateProtocolPage(const QJsonObject &config, DockerCo
set_labelTftpPortText(config.value(config_key::port).toString());
set_labelTorWebSiteAddressText(config.value(config_key::site).toString());
set_pushButtonSftpMountEnabled(true);
}
#ifdef Q_OS_WINDOWS
QString OtherProtocolsLogic::getNextDriverLetter() const
//QJsonObject OtherProtocolsLogic::getProtocolConfigFromPage(QJsonObject oldConfig)
//{
//}
void OtherProtocolsLogic::onPushButtonSftpMountDriveClicked()
{
#ifdef Q_OS_WINDOWS
QProcess drivesProc;
drivesProc.start("wmic logicaldisk get caption");
drivesProc.waitForFinished();
@@ -66,93 +68,53 @@ QString OtherProtocolsLogic::getNextDriverLetter() const
if (letter == "C:") {
// set err info
qDebug() << "Can't find free drive letter";
return "";
}
return letter;
}
#endif
//QJsonObject OtherProtocolsLogic::getProtocolConfigFromPage(QJsonObject oldConfig)
//{
//}
void OtherProtocolsLogic::onPushButtonSftpMountDriveClicked()
{
QString mountPath;
QString cmd;
QString host = m_settings.serverCredentials(uiLogic()->selectedServerIndex).hostName;
#ifdef Q_OS_WINDOWS
mountPath = getNextDriverLetter() + ":";
// QString cmd = QString("net use \\\\sshfs\\%1@x.x.x.x!%2 /USER:%1 %3")
// .arg(labelTftpUserNameText())
// .arg(labelTftpPortText())
// .arg(labelTftpPasswordText());
cmd = "C:\\Program Files\\SSHFS-Win\\bin\\sshfs.exe";
#elif defined AMNEZIA_DESKTOP
mountPath = QString("%1/sftp:%2:%3")
.arg(QStandardPaths::writableLocation(QStandardPaths::HomeLocation))
.arg(host)
.arg(labelTftpPortText());
QDir dir(mountPath);
if (!dir.exists()){
dir.mkpath(mountPath);
return;
}
cmd = "/usr/local/bin/sshfs";
#endif
#ifdef AMNEZIA_DESKTOP
set_pushButtonSftpMountEnabled(false);
QProcess *p = new QProcess;
m_sftpMountProcesses.append(p);
p->setProcessChannelMode(QProcess::MergedChannels);
connect(p, &QProcess::readyRead, this, [this, p, mountPath](){
connect(p, &QProcess::readyRead, this, [this, p, letter](){
QString s = p->readAll();
if (s.contains("The service sshfs has been started")) {
QDesktopServices::openUrl(QUrl("file:///" + mountPath));
QDesktopServices::openUrl(QUrl("file:///" + letter + ":"));
set_pushButtonSftpMountEnabled(true);
}
qDebug() << s;
});
// QString cmd = QString("net use \\\\sshfs\\%1@51.77.32.168!%2 /USER:%1 %3")
// .arg(labelTftpUserNameText())
// .arg(labelTftpPortText())
// .arg(labelTftpPasswordText());
p->setProgram("C:\\Program Files\\SSHFS-Win\\bin\\sshfs.exe");
p->setProgram(cmd);
QString host = m_settings.serverCredentials(uiLogic()->selectedServerIndex).hostName;
QString args = QString(
"%1@%2:/ %3 "
"%1@%2:/ %3: "
"-o port=%4 "
"-f "
"-o reconnect "
"-o rellinks "
"-o fstypename=SSHFS "
"-o reconnect"
"-orellinks "
"-ofstypename=SSHFS "
"-o ssh_command=/usr/bin/ssh.exe "
"-o UserKnownHostsFile=/dev/null "
"-o StrictHostKeyChecking=no "
"-oUserKnownHostsFile=/dev/null "
"-oStrictHostKeyChecking=no "
"-o password_stdin")
.arg(labelTftpUserNameText())
.arg(host)
.arg(mountPath)
.arg(letter)
.arg(labelTftpPortText());
// args.replace("\n", " ");
// args.replace("\r", " ");
//#ifndef Q_OS_WIN
// args.replace("reconnect-orellinks", "");
//#endif
p->setArguments(args.split(" ", QString::SkipEmptyParts));
p->setNativeArguments(args);
p->start();
p->waitForStarted(50);
if (p->state() != QProcess::Running) {
qDebug() << "onPushButtonSftpMountDriveClicked process not started";
qDebug() << args;
}
else {
p->write((labelTftpPasswordText() + "\n").toUtf8());
@@ -161,6 +123,7 @@ void OtherProtocolsLogic::onPushButtonSftpMountDriveClicked()
//qDebug().noquote() << "onPushButtonSftpMountDriveClicked" << args;
set_pushButtonSftpMountEnabled(true);
#endif
}

View File

@@ -34,12 +34,8 @@ private:
Settings m_settings;
UiLogic *m_uiLogic;
#ifdef AMNEZIA_DESKTOP
QList <QProcess *> m_sftpMountProcesses;
#endif
#ifdef Q_OS_WINDOWS
QString getNextDriverLetter() const;
QList <QProcess *> m_sftpMountProcesses;
#endif
};

View File

@@ -3,13 +3,11 @@ import QtQuick.Controls 2.12
CheckBox {
id: root
property int imageWidth : 20
property int imageHeight : 20
indicator: Image {
id: indicator
// y: 5
anchors.verticalCenter: root.verticalCenter
height: imageHeight
width: imageWidth
height: 20
width: 20
source: root.checked ? "qrc:/images/controls/check_on.png"
: "qrc:/images/controls/check_off.png"
}

View File

@@ -5,13 +5,11 @@ BasicButtonType {
id: root
property alias iconMargin: img.anchors.margins
property alias img: img
property int imgMargin: 4
property int imgMarginHover: 3
background: Item {}
contentItem: Image {
id: img
source: root.icon.source
anchors.fill: root
anchors.margins: root.containsMouse ? imgMarginHover : imgMargin
anchors.margins: root.containsMouse ? 3 : 4
}
}

View File

@@ -28,7 +28,7 @@ RadioButton {
font.family: "Lato"
font.styleName: "normal"
font.pixelSize: 16
color: enabled ? "#181922" : "#686972"
color: "#181922"
verticalAlignment: Text.AlignVCenter
leftPadding: root.indicator.width + root.spacing
}

View File

@@ -1,17 +0,0 @@
import QtQuick 2.12
LabelType {
id: label_connection_code
width: parent.width - 60
x: 30
font.pixelSize: 14
textFormat: Text.RichText
onLinkActivated: Qt.openUrlExternally(link)
MouseArea {
anchors.fill: parent
cursorShape: parent.hoveredLink ? Qt.PointingHandCursor : Qt.ArrowCursor
acceptedButtons: Qt.NoButton
}
}

View File

@@ -4,18 +4,14 @@ import QtQuick.Controls 2.12
BasicButtonType {
id: root
property alias textItem: textItem
height: 30
background: Item {}
contentItem: Item {
anchors.fill: parent
SvgImageType {
Image {
source: root.icon.source
anchors.left: parent.left
anchors.verticalCenter: parent.verticalCenter
svg.source: root.icon.source
color: "#100A44"
width: 25
height: 25
}
Text {
id: textItem

View File

@@ -1,16 +0,0 @@
import QtQuick 2.12
import QtQuick.Controls 2.12
import "."
BasicButtonType {
id: root
icon.color: "#181922"
background: Item {}
contentItem: SvgImageType {
svg.source: icon.source
color: icon.color
anchors.fill: parent
anchors.margins: parent.containsMouse ? 0 : 1
}
}

View File

@@ -1,23 +0,0 @@
import QtQuick 2.12
import QtQuick.Controls 2.12
import QtGraphicalEffects 1.15
Item {
id: root
property color color: "#181922"
property alias svg: image
Image {
anchors.fill: parent
id: image
sourceSize: Qt.size(root.width, root.height)
antialiasing: true
visible: false
}
ColorOverlay {
anchors.fill: image
source: image
color: root.color
}
}

View File

@@ -1,90 +0,0 @@
import QtQuick 2.12
import QtQuick.Controls 2.12
import PageEnum 1.0
import "./"
import "../Controls"
import "../Config"
PageBase {
id: root
page: PageEnum.About
BackButton {
id: back_from_start
}
Caption {
id: caption
font.pixelSize: 22
text: qsTr("About Amnezia")
}
RichLabelType {
id: label_about
anchors.top: caption.bottom
text: qsTr("AmneziaVPN is opensource software, it's free forever. Our goal is to make the best VPN client in the world.
<ul>
<li>Sources on <a href=\"https://github.com/amnezia-vpn/desktop-client\">GitHub</a></li>
<li><a href=\"https://amnezia.org/\">Web Site</a></li>
<li><a href=\"https://t.me/amnezia_vpn_en\">Telegram group</a></li>
<li><a href=\"https://signal.group/#CjQKIB2gUf8QH_IXnOJMGQWMDjYz9cNfmRQipGWLFiIgc4MwEhAKBONrSiWHvoUFbbD0xwdh\">Signal group</a></li>
</ul>
")
}
Caption {
id: caption2
anchors.topMargin: 20
font.pixelSize: 22
text: qsTr("Support")
anchors.top: label_about.bottom
}
RichLabelType {
id: label_support
anchors.top: caption2.bottom
text: qsTr("Have questions? You can get support by:
<ul>
<li><a href=\"https://t.me/amnezia_vpn_en\">Telegram group</a> (preferred way)</li>
<li>Create issue on <a href=\"https://github.com/amnezia-vpn/desktop-client/issues\">GitHub</a></li>
<li>Email to: <a href=\"support@amnezia.org\">support@amnezia.org</a></li>
</ul>")
}
Caption {
id: caption3
anchors.topMargin: 20
font.pixelSize: 22
text: qsTr("Donate")
width: undefined
anchors.top: label_support.bottom
}
LabelType {
anchors.bottom: caption3.bottom
anchors.left: caption3.right
anchors.leftMargin: 5
font.pixelSize: 24
text: "♥"
color: "red"
}
RichLabelType {
id: label_donate
anchors.top: caption3.bottom
text: qsTr("Please support Amnezia project by donation, we really need it now more than ever.
<ul>
<li>By credit card on <a href=\"https://www.patreon.com/amneziavpn\">Patreon</a> (starting from $1)</li>
<li>Send some coins to addresses listed <a href=\"https://github.com/amnezia-vpn/desktop-client/blob/master/README.md\">on GitHub page</a></li>
</ul>
")
}
Logo {
id: logo
anchors.bottom: parent.bottom
}
}

View File

@@ -1,6 +1,5 @@
import QtQuick 2.12
import QtQuick.Controls 2.12
import QtQuick.Layouts 1.15
import PageEnum 1.0
import "./"
import "../Controls"
@@ -15,131 +14,75 @@ PageBase {
id: back
}
Caption {
id: caption
text: qsTr("Application Settings")
}
Flickable {
id: fl
width: root.width
anchors.top: caption.bottom
anchors.topMargin: 20
anchors.bottom: logo.top
anchors.bottomMargin: 20
anchors.left: root.left
anchors.leftMargin: 30
anchors.right: root.right
anchors.rightMargin: 30
contentHeight: content.height
clip: true
ColumnLayout {
id: content
enabled: logic.pageEnabled
anchors.top: parent.top
anchors.left: parent.left
anchors.right: parent.right
CheckBoxType {
visible: !GC.isMobile()
Layout.fillWidth: true
text: qsTr("Auto connect")
checked: AppSettingsLogic.checkBoxAutoConnectChecked
onCheckedChanged: {
AppSettingsLogic.checkBoxAutoConnectChecked = checked
AppSettingsLogic.onCheckBoxAutoconnectToggled(checked)
}
}
CheckBoxType {
visible: !GC.isMobile()
Layout.fillWidth: true
text: qsTr("Auto start")
checked: AppSettingsLogic.checkBoxAutostartChecked
onCheckedChanged: {
AppSettingsLogic.checkBoxAutostartChecked = checked
AppSettingsLogic.onCheckBoxAutostartToggled(checked)
}
}
CheckBoxType {
visible: !GC.isMobile()
Layout.fillWidth: true
text: qsTr("Start minimized")
checked: AppSettingsLogic.checkBoxStartMinimizedChecked
onCheckedChanged: {
AppSettingsLogic.checkBoxStartMinimizedChecked = checked
AppSettingsLogic.onCheckBoxStartMinimizedToggled(checked)
}
}
LabelType {
Layout.fillWidth: true
Layout.topMargin: 15
text: AppSettingsLogic.labelVersionText
}
BlueButtonType {
visible: !GC.isMobile()
Layout.fillWidth: true
Layout.preferredHeight: 41
text: qsTr("Check for updates")
onClicked: {
Qt.openUrlExternally("https://github.com/amnezia-vpn/desktop-client/releases/latest")
}
}
CheckBoxType {
Layout.fillWidth: true
Layout.topMargin: 15
text: qsTr("Keep logs")
checked: AppSettingsLogic.checkBoxSaveLogsChecked
onCheckedChanged: {
AppSettingsLogic.checkBoxSaveLogsChecked = checked
AppSettingsLogic.onCheckBoxSaveLogsCheckedToggled(checked)
}
}
BlueButtonType {
Layout.fillWidth: true
Layout.preferredHeight: 41
text: qsTr("Open logs folder")
onClicked: {
AppSettingsLogic.onPushButtonOpenLogsClicked()
}
}
BlueButtonType {
Layout.fillWidth: true
Layout.topMargin: 15
Layout.preferredHeight: 41
text: qsTr("Export logs")
onClicked: {
AppSettingsLogic.onPushButtonExportLogsClicked()
}
}
BlueButtonType {
Layout.fillWidth: true
Layout.topMargin: 15
Layout.preferredHeight: 41
property string start_text: qsTr("Clear logs")
property string end_text: qsTr("Cleared")
text: start_text
Timer {
id: timer
interval: 1000; running: false; repeat: false
onTriggered: parent.text = parent.start_text
}
onClicked: {
text = end_text
timer.running = true
AppSettingsLogic.onPushButtonClearLogsClicked()
}
}
CheckBoxType {
x: 30
y: 140
width: 211
height: 31
text: qsTr("Auto connect")
checked: AppSettingsLogic.checkBoxAutoConnectChecked
onCheckedChanged: {
AppSettingsLogic.checkBoxAutoConnectChecked = checked
AppSettingsLogic.onCheckBoxAutoconnectToggled(checked)
}
}
CheckBoxType {
x: 30
y: 100
width: 211
height: 31
text: qsTr("Auto start")
checked: AppSettingsLogic.checkBoxAutostartChecked
onCheckedChanged: {
AppSettingsLogic.checkBoxAutostartChecked = checked
AppSettingsLogic.onCheckBoxAutostartToggled(checked)
}
}
CheckBoxType {
x: 30
y: 180
width: 211
height: 31
text: qsTr("Start minimized")
checked: AppSettingsLogic.checkBoxStartMinimizedChecked
onCheckedChanged: {
AppSettingsLogic.checkBoxStartMinimizedChecked = checked
AppSettingsLogic.onCheckBoxStartMinimizedToggled(checked)
}
}
LabelType {
x: 30
y: 240
width: 281
height: 21
text: AppSettingsLogic.labelVersionText
}
BlueButtonType {
x: 30
y: 280
anchors.horizontalCenter: parent.horizontalCenter
width: parent.width - 40
height: 41
text: qsTr("Check for updates")
onClicked: {
Qt.openUrlExternally("https://github.com/amnezia-vpn/desktop-client/releases/latest")
}
}
BlueButtonType {
x: 30
y: 340
anchors.horizontalCenter: parent.horizontalCenter
width: parent.width - 40
height: 41
text: qsTr("Open logs folder")
onClicked: {
AppSettingsLogic.onPushButtonOpenLogsClicked()
}
}
Logo {
id: logo
anchors.bottom: parent.bottom
}
}

View File

@@ -1,7 +1,5 @@
import QtQuick 2.12
import QtQuick.Controls 2.12
import QtQuick.Layouts 1.15
import QtGraphicalEffects 1.15
import PageEnum 1.0
import "./"
import "../Controls"
@@ -14,155 +12,176 @@ PageBase {
BackButton {
id: back
z: -1
}
Flickable {
id: fl
width: root.width
// ---------- App settings ------------
Rectangle {
id: l1
visible: !GC.isMobile()
anchors.top: back.bottom
anchors.topMargin: 0
anchors.bottom: root.bottom
anchors.bottomMargin: 10
anchors.left: root.left
anchors.leftMargin: 30
anchors.right: root.right
anchors.rightMargin: 30
x: 20
width: parent.width - 40
height: GC.isMobile() ? 0: 1
color: "#DDDDDD"
}
contentHeight: content.height
clip: true
ColumnLayout {
id: content
enabled: logic.pageEnabled
anchors.top: parent.top
anchors.topMargin: 10
anchors.left: parent.left
anchors.right: parent.right
spacing: 15
// ---------- App settings ------------
Rectangle {
Layout.fillWidth: true
Layout.preferredHeight: 1
color: "#DDDDDD"
}
SettingButtonType {
Layout.fillWidth: true
Layout.preferredHeight: 30
icon.source: "qrc:/images/svg/settings_black_24dp.svg"
text: qsTr("App settings")
onClicked: {
UiLogic.goToPage(PageEnum.AppSettings)
}
}
// ---------- Network settings ------------
Rectangle {
Layout.fillWidth: true
Layout.preferredHeight: 1
color: "#DDDDDD"
}
SettingButtonType {
Layout.fillWidth: true
Layout.preferredHeight: 30
icon.source: "qrc:/images/svg/settings_suggest_black_24dp.svg"
text: qsTr("Network settings")
onClicked: {
UiLogic.goToPage(PageEnum.NetworkSettings)
}
}
// ---------- Server settings ------------
Rectangle {
Layout.fillWidth: true
Layout.preferredHeight: 1
color: "#DDDDDD"
}
SettingButtonType {
Layout.fillWidth: true
Layout.preferredHeight: 30
icon.source: "qrc:/images/svg/vpn_key_black_24dp.svg"
text: qsTr("Server Settings")
onClicked: {
GeneralSettingsLogic.onPushButtonGeneralSettingsServerSettingsClicked()
}
}
// ---------- Share connection ------------
Rectangle {
Layout.fillWidth: true
Layout.preferredHeight: 1
color: "#DDDDDD"
}
SettingButtonType {
Layout.fillWidth: true
Layout.preferredHeight: 30
icon.source: "qrc:/images/svg/share_black_24dp.svg"
text: qsTr("Share connection")
enabled: GeneralSettingsLogic.pushButtonGeneralSettingsShareConnectionEnable
onClicked: {
GeneralSettingsLogic.onPushButtonGeneralSettingsShareConnectionClicked()
}
}
// ---------- Servers ------------
Rectangle {
Layout.fillWidth: true
Layout.preferredHeight: 1
color: "#DDDDDD"
}
SettingButtonType {
Layout.fillWidth: true
Layout.preferredHeight: 30
icon.source: "qrc:/images/svg/format_list_bulleted_black_24dp.svg"
text: qsTr("Servers")
onClicked: {
UiLogic.goToPage(PageEnum.ServersList)
}
}
// ---------- Add server ------------
Rectangle {
Layout.fillWidth: true
Layout.preferredHeight: 1
color: "#DDDDDD"
}
SettingButtonType {
Layout.fillWidth: true
Layout.preferredHeight: 30
icon.source: "qrc:/images/svg/control_point_black_24dp.svg"
text: qsTr("Add server")
onClicked: {
UiLogic.goToPage(PageEnum.Start)
}
}
Rectangle {
Layout.fillWidth: true
Layout.preferredHeight: 1
color: "#DDDDDD"
}
Rectangle {
Layout.fillWidth: true
Layout.preferredHeight: fl.height > (75+1) * 6 ? fl.height - (75+1) * 6 : 0
}
SettingButtonType {
Layout.fillWidth: true
Layout.preferredHeight: 30
Layout.bottomMargin: 20
icon.source: "qrc:/images/svg/logout_black_24dp.svg"
text: qsTr("Exit")
onClicked: {
Qt.quit()
}
}
SettingButtonType {
id: b1
visible: !GC.isMobile()
anchors.top: l1.bottom
anchors.topMargin: GC.isMobile() ? 0: 15
x: 30
width: parent.width - 40
height: GC.isMobile() ? 0: 30
icon.source: "qrc:/images/settings.png"
text: qsTr("App settings")
onClicked: {
UiLogic.goToPage(PageEnum.AppSettings)
}
}
// ---------- Network settings ------------
Rectangle {
id: l2
anchors.top: b1.bottom
anchors.topMargin: 15
x: 20
width: parent.width - 40
height: 1
color: "#DDDDDD"
}
SettingButtonType {
id: b2
x: 30
anchors.top: l2.bottom
anchors.topMargin: 15
width: parent.width - 40
height: 30
icon.source: "qrc:/images/settings.png"
text: qsTr("Network settings")
onClicked: {
UiLogic.goToPage(PageEnum.NetworkSettings)
}
}
// ---------- Server settings ------------
Rectangle {
id: l3
anchors.top: b2.bottom
anchors.topMargin: 15
x: 20
width: parent.width - 40
height: 1
color: "#DDDDDD"
}
SettingButtonType {
id: b3
x: 30
anchors.top: l3.bottom
anchors.topMargin: 15
width: 330
height: 30
icon.source: "qrc:/images/server_settings.png"
text: qsTr("Server Settings")
onClicked: {
GeneralSettingsLogic.onPushButtonGeneralSettingsServerSettingsClicked()
}
}
// ---------- Share connection ------------
Rectangle {
id: l4
anchors.top: b3.bottom
anchors.topMargin: 15
x: 20
width: parent.width - 40
height: 1
color: "#DDDDDD"
}
SettingButtonType {
id: b4
x: 30
anchors.top: l4.bottom
anchors.topMargin: 15
width: 330
height: 30
icon.source: "qrc:/images/share.png"
text: qsTr("Share connection")
enabled: GeneralSettingsLogic.pushButtonGeneralSettingsShareConnectionEnable
onClicked: {
GeneralSettingsLogic.onPushButtonGeneralSettingsShareConnectionClicked()
}
}
// ---------- Servers ------------
Rectangle {
id: l5
anchors.top: b4.bottom
anchors.topMargin: 15
x: 20
width: parent.width - 40
height: 1
color: "#DDDDDD"
}
SettingButtonType {
id: b5
x: 30
anchors.top: l5.bottom
anchors.topMargin: 15
width: 330
height: 30
icon.source: "qrc:/images/server_settings.png"
text: qsTr("Servers")
onClicked: {
UiLogic.goToPage(PageEnum.ServersList)
}
}
// ---------- Add server ------------
Rectangle {
id: l6
anchors.top: b5.bottom
anchors.topMargin: 15
x: 20
width: parent.width - 40
height: 1
color: "#DDDDDD"
}
SettingButtonType {
id: b6
x: 30
anchors.top: l6.bottom
anchors.topMargin: 15
width: 330
height: 30
icon.source: "qrc:/images/plus.png"
text: qsTr("Add server")
onClicked: {
UiLogic.goToPage(PageEnum.Start)
}
}
Rectangle {
id: l7
anchors.top: b6.bottom
anchors.topMargin: 15
x: 20
width: parent.width - 40
height: 1
color: "#DDDDDD"
}
SettingButtonType {
x: 30
anchors.bottom: parent.bottom
anchors.bottomMargin: 20
width: 330
height: 30
icon.source: "qrc:/images/settings.png"
text: qsTr("Exit")
onClicked: {
Qt.quit()
}
}
}

View File

@@ -17,42 +17,17 @@ PageBase {
id: caption
text: qsTr("DNS Servers")
}
CheckBoxType {
id: cb_amnezia_dns
anchors.top: caption.bottom
x: 30
width: parent.width - 60
text: qsTr("Use AmneziaDNS service (recommended)")
checked: NetworkSettingsLogic.checkBoxUseAmneziaDnsChecked
onCheckedChanged: {
NetworkSettingsLogic.checkBoxUseAmneziaDnsChecked = checked
NetworkSettingsLogic.onCheckBoxUseAmneziaDnsToggled(checked)
UiLogic.onUpdateAllPages()
}
}
LabelType {
id: lb_amnezia_dns
x: 30
anchors.top: cb_amnezia_dns.bottom
width: parent.width - 60
text: qsTr("Use AmneziaDNS container on your server, when it installed.\n
Your AmneziaDNS server available only when it installed and VPN connected, it has internal IP address 172.29.172.254\n
If AmneziaDNS service is not installed on the same server, or this option is unchecked, the following DNS servers will be used:")
}
LabelType {
id: l1
x: 30
anchors.top: lb_amnezia_dns.bottom
width: parent.width - 30
x: 40
anchors.top: caption.bottom
width: parent.width - 40
height: 21
text: qsTr("Primary DNS server")
}
TextFieldType {
id: dns1
x: 30
x: 40
anchors.top: l1.bottom
width: parent.width - 90
height: 40
@@ -60,38 +35,36 @@ If AmneziaDNS service is not installed on the same server, or this option is unc
onEditingFinished: {
NetworkSettingsLogic.lineEditDns1Text = text
NetworkSettingsLogic.onLineEditDns1EditFinished(text)
UiLogic.onUpdateAllPages()
}
validator: RegExpValidator {
regExp: NetworkSettingsLogic.ipAddressRegex
}
}
SvgButtonType {
ImageButtonType {
id: resetDNS1
anchors. left: dns1.right
anchors.leftMargin: 10
anchors.verticalCenter: dns1.verticalCenter
width: 24
height: 24
icon.source: "qrc:/images/svg/refresh_black_24dp.svg"
icon.source: "qrc:/images/reload.png"
onClicked: {
NetworkSettingsLogic.onPushButtonResetDns1Clicked()
UiLogic.onUpdateAllPages()
}
}
LabelType {
id: l2
x: 30
x: 40
anchors.top: dns1.bottom
anchors.topMargin: 20
width: parent.width - 60
width: parent.width - 40
height: 21
text: qsTr("Secondray DNS server")
}
TextFieldType {
id: dns2
x: 30
x: 40
anchors.top: l2.bottom
width: parent.width - 90
height: 40
@@ -99,23 +72,21 @@ If AmneziaDNS service is not installed on the same server, or this option is unc
onEditingFinished: {
NetworkSettingsLogic.lineEditDns2Text = text
NetworkSettingsLogic.onLineEditDns2EditFinished(text)
UiLogic.onUpdateAllPages()
}
validator: RegExpValidator {
regExp: NetworkSettingsLogic.ipAddressRegex
}
}
SvgButtonType {
ImageButtonType {
id: resetDNS2
anchors. left: dns2.right
anchors.leftMargin: 10
anchors.verticalCenter: dns2.verticalCenter
width: 24
height: 24
icon.source: "qrc:/images/svg/refresh_black_24dp.svg"
icon.source: "qrc:/images/reload.png"
onClicked: {
NetworkSettingsLogic.onPushButtonResetDns2Clicked()
UiLogic.onUpdateAllPages()
}
}

View File

@@ -59,10 +59,6 @@ PageBase {
SelectContainer {
id: container_selector
onAboutToHide: {
pageLoader.focus = true
}
onContainerSelected: {
var containerProto = ContainerProps.defaultProtocol(c_index)

View File

@@ -41,10 +41,6 @@ PageBase {
SelectContainer {
id: container_selector
onAboutToHide: {
pageLoader.focus = true
}
onContainerSelected: {
var containerProto = ContainerProps.defaultProtocol(c_index)

View File

@@ -16,23 +16,20 @@ PageBase {
}
Caption {
id: caption
text: qsTr("Servers")
text: qsTr("Servers list")
width: undefined
}
SvgButtonType {
anchors.verticalCenter: caption.verticalCenter
ImageButtonType {
anchors.bottom: caption.bottom
anchors.leftMargin: 10
anchors.left: caption.right
width: 27
height: 27
icon.source: "qrc:/images/svg/control_point_black_24dp.svg"
width: 24
height: 24
icon.source: "qrc:/images/plus.png"
onClicked: {
UiLogic.goToPage(PageEnum.Start);
}
}
ListView {
id: listWidget_servers
x: 20
@@ -127,13 +124,13 @@ PageBase {
checked: is_default
enabled: !is_default
}
SvgButtonType {
ImageButtonType {
id: pushButtonSetting
x: parent.width - 70
y: 15
width: 30
height: 30
icon.source: "qrc:/images/svg/settings_black_24dp.svg"
icon.source: "qrc:/images/settings.png"
opacity: 0
OpacityAnimator {

View File

@@ -28,16 +28,7 @@ PageBase {
horizontalAlignment: Text.AlignHCenter
text: ServerSettingsLogic.labelCurrentVpnProtocolText
}
// LabelType {
// anchors.horizontalCenter: parent.horizontalCenter
// y: 120
// width: 341
// height: 31
// font.pixelSize: 20
// horizontalAlignment: Text.AlignHCenter
// text: ServerSettingsLogic.labelServerText
// }
TextFieldType {
LabelType {
anchors.horizontalCenter: parent.horizontalCenter
y: 120
width: 341
@@ -45,10 +36,7 @@ PageBase {
font.pixelSize: 20
horizontalAlignment: Text.AlignHCenter
text: ServerSettingsLogic.labelServerText
readOnly: true
background: Item {}
}
LabelType {
anchors.horizontalCenter: parent.horizontalCenter
y: 530

View File

@@ -1,6 +1,5 @@
import QtQuick 2.12
import QtQuick.Controls 2.12
import QtQuick.Layouts 1.15
import PageEnum 1.0
import "./"
import "../Controls"
@@ -15,99 +14,93 @@ PageBase {
id: back_from_setup_wizard
}
Caption {
id: caption
text: qsTr("Setup your server to use VPN")
}
Flickable {
id: fl
width: root.width
anchors.top: caption.bottom
anchors.topMargin: 20
anchors.bottom: root.bottom
anchors.bottomMargin: 20
anchors.left: root.left
anchors.leftMargin: 30
anchors.right: root.right
anchors.rightMargin: 30
contentHeight: content.height
clip: true
ColumnLayout {
id: content
enabled: logic.pageEnabled
anchors.top: parent.top
anchors.left: parent.left
anchors.right: parent.right
RadioButtonType {
id: radioButton_setup_wizard_high
Layout.fillWidth: true
text: qsTr("High censorship level")
checked: WizardLogic.radioButtonHighChecked
onCheckedChanged: {
WizardLogic.radioButtonHighChecked = checked
Item {
x: 10
y: 70
width: 361
height: 561
LabelType {
horizontalAlignment: Text.AlignLeft
verticalAlignment: Text.AlignTop
text: qsTr("I'm living in country with high censorship level. Many of foreign web sites and VPNs blocked by my government. I want to setup reliable VPN, which is invisible for government.")
wrapMode: Text.Wrap
x: 30
y: 40
width: 321
height: 121
}
LabelType {
horizontalAlignment: Text.AlignLeft
verticalAlignment: Text.AlignTop
text: qsTr("I'm living in country with medium censorship level. Some web sites blocked by my government, but VPNs are not blocked at all. I want to setup flexible solution.")
wrapMode: Text.Wrap
x: 30
y: 210
width: 321
height: 121
}
LabelType {
horizontalAlignment: Text.AlignLeft
verticalAlignment: Text.AlignTop
text: qsTr("I just want to improve my privacy in internet.")
wrapMode: Text.Wrap
x: 30
y: 360
width: 321
height: 121
}
BlueButtonType {
anchors.horizontalCenter: parent.horizontalCenter
y: 490
width: 321
height: 40
text: qsTr("Next")
onClicked: {
if (radioButton_setup_wizard_high.checked) {
UiLogic.goToPage(PageEnum.WizardHigh);
} else if (radioButton_setup_wizard_medium.checked) {
UiLogic.goToPage(PageEnum.WizardMedium);
} else if (radioButton_setup_wizard_low.checked) {
UiLogic.goToPage(PageEnum.WizardLow);
}
}
LabelType {
Layout.fillWidth: true
Layout.leftMargin: 25
verticalAlignment: Text.AlignTop
text: qsTr("I'm living in a country with a high censorship level. Many of the foreign websites and VPNs are blocked by my government. I want to setup a reliable VPN, which can not be detected by my internet provider and my government.
OpenVPN and ShadowSocks over Cloak (VPN obfuscation) profiles will be installed.\n")
}
RadioButtonType {
id: radioButton_setup_wizard_high
x: 10
y: 10
width: 331
height: 25
text: qsTr("High censorship level")
checked: WizardLogic.radioButtonHighChecked
onCheckedChanged: {
WizardLogic.radioButtonHighChecked = checked
}
RadioButtonType {
id: radioButton_setup_wizard_medium
Layout.fillWidth: true
text: qsTr("Medium censorship level")
checked: WizardLogic.radioButtonMediumChecked
onCheckedChanged: {
WizardLogic.radioButtonMediumChecked = checked
}
}
RadioButtonType {
id: radioButton_setup_wizard_medium
x: 10
y: 330
width: 331
height: 25
text: qsTr("Low censorship level")
checked: WizardLogic.radioButtonLowChecked
onCheckedChanged: {
WizardLogic.radioButtonLowChecked = checked
}
LabelType {
Layout.fillWidth: true
Layout.leftMargin: 25
verticalAlignment: Text.AlignTop
text: qsTr("I'm living in a country with a medium censorship level. Some websites are blocked by my government, but VPNs are not blocked at all. I want to setup a flexible solution.
OpenVPN over ShadowSocks profile will be installed.\n")
}
RadioButtonType {
id: radioButton_setup_wizard_low
Layout.fillWidth: true
text: qsTr("Low censorship level")
checked: WizardLogic.radioButtonLowChecked
onCheckedChanged: {
WizardLogic.radioButtonLowChecked = checked
}
}
LabelType {
Layout.fillWidth: true
Layout.leftMargin: 25
verticalAlignment: Text.AlignTop
text: qsTr("I want to improve my privacy on the internet.
OpenVPN profile will be installed.\n")
}
BlueButtonType {
Layout.fillWidth: true
Layout.preferredHeight: 41
text: qsTr("Next")
onClicked: {
if (radioButton_setup_wizard_high.checked) {
UiLogic.goToPage(PageEnum.WizardHigh, false);
} else if (radioButton_setup_wizard_medium.checked) {
UiLogic.goToPage(PageEnum.WizardMedium, false);
} else if (radioButton_setup_wizard_low.checked) {
UiLogic.goToPage(PageEnum.WizardLow, false);
}
}
}
RadioButtonType {
id: radioButton_setup_wizard_low
x: 10
y: 180
width: 331
height: 25
text: qsTr("Medium censorship level")
checked: WizardLogic.radioButtonMediumChecked
onCheckedChanged: {
WizardLogic.radioButtonMediumChecked = checked
}
}
}

View File

@@ -1,6 +1,5 @@
import QtQuick 2.12
import QtQuick.Controls 2.12
import QtQuick.Layouts 1.15
import PageEnum 1.0
import "./"
import "../Controls"
@@ -15,90 +14,69 @@ PageBase {
id: back_from_setup_wizard
}
Caption {
id: caption
text: qsTr("Setup Wizard")
}
Flickable {
id: fl
width: root.width
anchors.top: caption.bottom
anchors.topMargin: 20
anchors.bottom: root.bottom
anchors.bottomMargin: 20
anchors.left: root.left
anchors.leftMargin: 30
anchors.right: root.right
anchors.rightMargin: 30
contentHeight: content.height
clip: true
ColumnLayout {
id: content
enabled: logic.pageEnabled
anchors.top: parent.top
anchors.left: parent.left
anchors.right: parent.right
LabelType {
Layout.fillWidth: true
verticalAlignment: Text.AlignTop
text: qsTr("AmneziaVPN will install a VPN protocol which is not visible to your internet provider and government firewall. Your VPN connection will be seen by your internet provider as regular web traffic to a particular website.
You SHOULD set this website address to some foreign website which is not blocked by your internet provider. In other words, you need to type some foreign website address which is accessible to you without a VPN.")
}
LabelType {
Layout.fillWidth: true
Layout.topMargin: 15
verticalAlignment: Text.AlignTop
text: qsTr("Type another web site address for masking or keep it by default. Your internet provider will think you working on this web site when you connected to VPN.")
}
TextFieldType {
id: website_masking
Layout.fillWidth: true
text: WizardLogic.lineEditHighWebsiteMaskingText
onEditingFinished: {
let _text = website_masking.text
_text.replace("http://", "");
_text.replace("https://", "");
if (!_text) {
return
}
_text = _text.split("/").first();
WizardLogic.lineEditHighWebsiteMaskingText = _text
}
onAccepted: {
next_button.clicked()
}
}
LabelType {
Layout.fillWidth: true
Layout.topMargin: 15
verticalAlignment: Text.AlignTop
text: qsTr("OpenVPN and ShadowSocks over Cloak (VPN obfuscation) profiles will be installed.
This protocol support exporting connection profiles to mobile devices by exporting ShadowSocks and Cloak configs (you should launch the 3rd party open source VPN client - ShadowSocks VPN and install Cloak plugin).")
}
BlueButtonType {
id: next_button
Layout.fillWidth: true
Layout.topMargin: 15
Layout.preferredHeight: 41
text: qsTr("Next")
onClicked: {
let domain = website_masking.text;
if (!domain || !domain.includes(".")) {
return
}
UiLogic.goToPage(PageEnum.WizardVpnMode, false)
}
}
Item {
x: 10
y: 70
width: 361
height: 561
LabelType {
x: 30
y: 10
width: 321
height: 321
text: qsTr("AmneziaVPN will install VPN protocol which is not visible for your internet provider and government firewall. Your VPN connection will be detected by your provider as regular web traffic to particular web site.\n\nYou SHOULD set this web site address to some foreign web site which is updatesnot blocked by your internet provider. Other words you need to type below some foreign web site address which is accessible without VPN.\n\nPlease note, this protocol still does not support export connection profile to mobile devices. Keep for updates.")
}
LabelType {
x: 30
y: 400
width: 321
height: 71
text: qsTr("OpenVPN over Cloak (VPN obfuscation) profile will be installed")
}
LabelType {
x: 30
y: 330
width: 291
height: 21
text: qsTr("Type web site address for mask")
}
TextFieldType {
id: website_masking
x: 30
y: 360
width: 301
height: 41
text: WizardLogic.lineEditHighWebsiteMaskingText
onEditingFinished: {
let _text = website_masking.text
_text.replace("http://", "");
_text.replace("https://", "");
if (!_text) {
return
}
_text = _text.split("/").first();
WizardLogic.lineEditHighWebsiteMaskingText = _text
}
onAccepted: {
next_button.clicked()
}
}
BlueButtonType {
id: next_button
x: 30
y: 490
width: 301
height: 40
text: qsTr("Next")
onClicked: {
let domain = website_masking.text;
if (!domain || !domain.includes(".")) {
return
}
UiLogic.goToPage(PageEnum.WizardVpnMode)
}
}
}
}

View File

@@ -1,6 +1,5 @@
import QtQuick 2.12
import QtQuick.Controls 2.12
import QtQuick.Layouts 1.15
import PageEnum 1.0
import "./"
import "../Controls"
@@ -15,56 +14,38 @@ PageBase {
id: back_from_setup_wizard
}
Caption {
id: caption
text: qsTr("Setup Wizard")
}
Flickable {
id: fl
width: root.width
anchors.top: caption.bottom
anchors.topMargin: 20
anchors.bottom: root.bottom
anchors.bottomMargin: 20
anchors.left: root.left
anchors.leftMargin: 30
anchors.right: root.right
anchors.rightMargin: 30
contentHeight: content.height
clip: true
ColumnLayout {
id: content
enabled: logic.pageEnabled
anchors.top: parent.top
anchors.left: parent.left
anchors.right: parent.right
LabelType {
Layout.fillWidth: true
verticalAlignment: Text.AlignTop
text: qsTr('AmneziaVPN will install the OpenVPN protocol with public/private key pairs generated on both server and client sides.
You can also configure the connection on your mobile device by copying the exported ".ovpn" file to your device, and setting up the official OpenVPN client.
We recommend not to use messaging applications for sending the connection profile - it contains VPN private keys.')
}
LabelType {
Layout.fillWidth: true
Layout.topMargin: 15
text: qsTr('OpenVPN profile will be installed')
verticalAlignment: Text.AlignBottom
}
BlueButtonType {
id: next_button
Layout.fillWidth: true
Layout.topMargin: 15
Layout.preferredHeight: 41
text: qsTr("Start configuring")
onClicked: {
WizardLogic.onPushButtonLowFinishClicked()
}
Item {
x: 10
y: 70
width: 361
height: 561
LabelType {
x: 30
y: 10
width: 321
height: 341
verticalAlignment: Text.AlignTop
text: qsTr('AmneziaVPN will install OpenVPN protocol with public/private key pairs generated on server and client sides. You can also configure connection on your mobile device by copying exported ".ovpn" file to your device and setting up official OpenVPN client. We recommend do not use messengers for sending connection profile - it contains VPN private keys.')
}
LabelType {
x: 30
y: 400
width: 321
height: 71
text: qsTr('OpenVPN profile will be installed')
verticalAlignment: Text.AlignBottom
}
BlueButtonType {
id: next_button
x: 30
y: 490
width: 301
height: 40
text: qsTr("Start configuring")
onClicked: {
WizardLogic.onPushButtonLowFinishClicked()
}
}
}

View File

@@ -1,6 +1,5 @@
import QtQuick 2.12
import QtQuick.Controls 2.12
import QtQuick.Layouts 1.15
import PageEnum 1.0
import "./"
import "../Controls"
@@ -15,51 +14,38 @@ PageBase {
id: back_from_setup_wizard
}
Caption {
id: caption
text: qsTr("Setup Wizard")
}
Flickable {
id: fl
width: root.width
anchors.top: caption.bottom
anchors.topMargin: 20
anchors.bottom: root.bottom
anchors.bottomMargin: 20
anchors.left: root.left
anchors.leftMargin: 30
anchors.right: root.right
anchors.rightMargin: 30
contentHeight: content.height
clip: true
ColumnLayout {
id: content
enabled: logic.pageEnabled
anchors.top: parent.top
anchors.left: parent.left
anchors.right: parent.right
LabelType {
Layout.fillWidth: true
verticalAlignment: Text.AlignTop
text: qsTr('AmneziaVPN will install a VPN protocol which is difficult to detect by your internet provider and government firewall (but possible). In most cases, this is the most suitable protocol. This protocol is faster compared to the VPN protocols with "VPN masking".\n\nThis protocol supports exporting connection profiles to mobile devices by using QR codes (you should launch the 3rd party open source VPN client - ShadowSocks VPN).')
}
LabelType {
Layout.fillWidth: true
Layout.topMargin: 15
text: qsTr('OpenVPN over ShadowSocks profile will be installed')
}
BlueButtonType {
id: next_button
Layout.fillWidth: true
Layout.topMargin: 15
Layout.preferredHeight: 41
text: qsTr("Next")
onClicked: {
UiLogic.goToPage(PageEnum.WizardVpnMode, false)
}
Item {
x: 10
y: 70
width: 361
height: 561
LabelType {
x: 30
y: 10
width: 321
height: 341
verticalAlignment: Text.AlignTop
text: qsTr('AmneziaVPN will install VPN protocol which is difficult to detect by your internet provider and government firewall (but possible). In most cases, this is the most suitable protocol. This protocol is faster compared to the VPN protocols with "web traffic masking".\n\nThis protocol support export connection profile to mobile devices using QR code (you should launch 3rd party opensource VPN client - ShadowSocks VPN).')
}
LabelType {
x: 30
y: 400
width: 321
height: 71
text: qsTr('OpenVPN over ShadowSocks profile will be installed')
verticalAlignment: Text.AlignBottom
}
BlueButtonType {
id: next_button
x: 30
y: 490
width: 301
height: 40
text: qsTr("Next")
onClicked: {
UiLogic.goToPage(PageEnum.WizardVpnMode)
}
}
}

View File

@@ -1,6 +1,5 @@
import QtQuick 2.12
import QtQuick.Controls 2.12
import QtQuick.Layouts 1.15
import PageEnum 1.0
import "./"
import "../Controls"
@@ -15,57 +14,40 @@ PageBase {
id: back_from_setup_wizard
}
Caption {
id: caption
text: qsTr("Setup Wizard")
}
Flickable {
id: fl
width: root.width
anchors.top: caption.bottom
anchors.topMargin: 20
anchors.bottom: root.bottom
anchors.bottomMargin: 20
anchors.left: root.left
anchors.leftMargin: 30
anchors.right: root.right
anchors.rightMargin: 30
contentHeight: content.height
clip: true
ColumnLayout {
id: content
enabled: logic.pageEnabled
anchors.top: parent.top
anchors.left: parent.left
anchors.right: parent.right
LabelType {
Layout.fillWidth: true
verticalAlignment: Text.AlignTop
text: qsTr('Optional.\n
You can enable VPN mode "For selected sites" and add blocked sites you need to visit manually. If you will choose this option, you will need add every bloked site you want to visit to the access list. You may switch between modes later.\n\nPlease note, you should add addresses to the list after VPN connection established. You may add any domain, URL or IP address, it will be resolved to IP address.')
Item {
x: 10
y: 70
width: 361
height: 561
CheckBoxType {
x: 30
y: 350
width: 301
height: 71
text: qsTr('Turn on mode "VPN for selected sites"')
checked: WizardLogic.checkBoxVpnModeChecked
onCheckedChanged: {
WizardLogic.checkBoxVpnModeChecked = checked
}
CheckBoxType {
Layout.fillWidth: true
text: qsTr('Turn on mode "VPN for selected sites"')
checked: WizardLogic.checkBoxVpnModeChecked
onCheckedChanged: {
WizardLogic.checkBoxVpnModeChecked = checked
}
}
BlueButtonType {
id: vpn_mode_finish
Layout.fillWidth: true
Layout.topMargin: 15
Layout.preferredHeight: 41
text: qsTr("Start configuring")
onClicked: {
WizardLogic.onPushButtonVpnModeFinishClicked()
}
}
LabelType {
x: 30
y: 10
width: 321
height: 341
text: qsTr('Optional.\n\nWe recommend to enable VPN mode "For selected sites" and add blocked sites you need to visit manually. If you will choose this option, you will need add every bloked site you want to visit to the access list. You may switch between modes later.\n\nPlease note, you should add addresses to the list after VPN connection established. You may add any domain, URL or IP address, it will be resolved to IP address.')
}
BlueButtonType {
id: vpn_mode_finish
x: 30
y: 490
width: 301
height: 40
text: qsTr("Start configuring")
onClicked: {
WizardLogic.onPushButtonVpnModeFinishClicked()
}
}
}

View File

@@ -1,6 +1,5 @@
import QtQuick 2.15
import QtQuick.Controls 2.15
import QtQml.Models 2.15
import QtQuick 2.12
import QtQuick.Controls 2.12
import Qt.labs.platform 1.0
import QtQuick.Dialogs 1.0
import PageEnum 1.0
@@ -13,8 +12,6 @@ PageBase {
page: PageEnum.Sites
logic: SitesLogic
property int lastIndex: 0
BackButton {
id: back
}
@@ -107,32 +104,20 @@ PageBase {
}
}
DelegateModel {
id: visualModel
ListView {
id: tb
x: 20
anchors.top: sites_add.bottom
anchors.topMargin: 10
width: parent.width - 40
anchors.bottom: sites_delete.top
anchors.bottomMargin: 10
spacing: 1
clip: true
property int currentRow: -1
model: SitesLogic.tableViewSitesModel
groups: [
DelegateModelGroup {
id : delegateModelGroup
name: "multiSelect"
function removeAll(){
var count = delegateModelGroup.count;
if (count !== 0){
delegateModelGroup.remove(0,count);
}
}
function selectAll(){
for(var i = 0; i < visualModel.count; i++){
visualModel.items.get(i).inMultiSelect = true
}
}
}
]
delegate: Rectangle {
id: item
focus: true
height: 25
width: root.width
color: item.DelegateModel.inMultiSelect ? '#63b4fb' : 'transparent'
delegate: Item {
implicitWidth: 170 * 2
implicitHeight: 30
Item {
@@ -186,130 +171,23 @@ PageBase {
}
MouseArea {
anchors.fill: parent
acceptedButtons: Qt.LeftButton | Qt.RightButton
onClicked:{
tb.focus = true
if(mouse.button === Qt.RightButton){
//copyPasteMenu.popup()
console.log("RightButton")
}
if(mouse.button === Qt.LeftButton){
switch(mouse.modifiers){
case Qt.ControlModifier :
item.DelegateModel.inMultiSelect = !item.DelegateModel.inMultiSelect
break;
case Qt.ShiftModifier :
delegateModelGroup.removeAll();
var start = lastIndex <= index? lastIndex: index;
var end = lastIndex >= index? lastIndex: index;
for(var i = start;i <= end;i++){
visualModel.items.get(i).inMultiSelect = true
}
break;
default:
delegateModelGroup.removeAll();
item.DelegateModel.inMultiSelect = true
lastIndex = index
break;
}
}
onClicked: {
tb.currentRow = index
}
}
}
}
ListView {
id: tb
x: 20
anchors.top: sites_add.bottom
anchors.topMargin: 10
width: parent.width - 40
anchors.bottom: sites_delete.top
anchors.bottomMargin: 10
spacing: 1
clip: true
focus: true
activeFocusOnTab: true
keyNavigationEnabled: true
property int currentRow: -1
model: visualModel
Keys.onPressed: {
if (event.key === Qt.Key_PageUp) {
let idx = tb.indexAt(1, tb.contentY)
tb.positionViewAtIndex(idx-20, ListView.Beginning)
event.accepted = true
}
else if (event.key === Qt.Key_PageDown) {
let idx = tb.indexAt(1, tb.contentY)
tb.positionViewAtIndex(idx+20, ListView.Beginning)
event.accepted = true
}
else if (event.key === Qt.Key_Home) {
tb.positionViewAtBeginning()
event.accepted = true
}
else if (event.key === Qt.Key_End) {
tb.positionViewAtEnd()
event.accepted = true
}
else if (event.key === Qt.Key_Delete) {
let items = []
for(let i = 0; i < visualModel.count; i++){
if (visualModel.items.get(i).inMultiSelect) items.push(i)
}
SitesLogic.onPushButtonSitesDeleteClicked(items)
event.accepted = true
}
else if (event.key === Qt.Key_A) {
delegateModelGroup.selectAll()
event.accepted = true
}
}
}
BlueButtonType {
id: sites_delete
anchors.bottom: select_all.top
anchors.bottomMargin: 10
anchors.horizontalCenter: parent.horizontalCenter
height: 31
font.pixelSize: 16
text: qsTr("Delete selected")
onClicked: {
let items = []
for(let i = 0; i < visualModel.count; i++){
if (visualModel.items.get(i).inMultiSelect) items.push(i)
}
SitesLogic.onPushButtonSitesDeleteClicked(items)
}
}
BlueButtonType {
id: select_all
anchors.bottom: sites_export.top
anchors.bottomMargin: 10
anchors.horizontalCenter: parent.horizontalCenter
height: 31
font.pixelSize: 16
text: qsTr("Select all")
onClicked: {
delegateModelGroup.selectAll()
}
}
BlueButtonType {
id: sites_export
anchors.bottom: parent.bottom
anchors.bottomMargin: 20
anchors.horizontalCenter: parent.horizontalCenter
height: 31
font.pixelSize: 16
text: qsTr("Export all")
text: qsTr("Delete selected")
onClicked: {
SitesLogic.onPushButtonSitesExportClicked()
SitesLogic.onPushButtonSitesDeleteClicked(tb.currentRow)
}
}
}

View File

@@ -240,7 +240,8 @@ PageBase {
anchors.horizontalCenter: parent.horizontalCenter
height: 71
font.pixelSize: 10
echoMode: TextInput.Password
font.pixelSize: 9
verticalAlignment: Text.AlignTop
text: StartPageLogic.textEditSshKeyText
onEditingFinished: {
@@ -263,7 +264,6 @@ PageBase {
id: new_sever_connect
anchors.horizontalCenter: parent.horizontalCenter
anchors.top: new_server_ssh_key.bottom
anchors.topMargin: 10
text: StartPageLogic.pushButtonConnectText
visible: StartPageLogic.pushButtonConnectVisible

View File

@@ -22,7 +22,7 @@ PageBase {
LabelType {
x: 10
y: 10
y: 5
width: 100
height: 21
text: VpnLogic.labelVersionText
@@ -30,40 +30,11 @@ PageBase {
font.pixelSize: 12
}
BasicButtonType {
y: 10
anchors.horizontalCenter: parent.horizontalCenter
height: 21
background: Item {}
contentItem: Text {
anchors.fill: parent
font.family: "Lato"
font.styleName: "normal"
font.pixelSize: 18
font.underline: true
text: qsTr("Donate")
color: "#D4D4D4"
horizontalAlignment: Text.AlignHCenter
verticalAlignment: Text.AlignVCenter
}
onClicked: {
UiLogic.goToPage(PageEnum.About)
}
}
ImageButtonType {
x: parent.width - 40
y: 0
width: 41
height: 41
imgMarginHover: 8
imgMargin: 9
y: 10
width: 31
height: 31
icon.source: "qrc:/images/settings_grey.png"
onClicked: {
UiLogic.goToPage(PageEnum.GeneralSettings)
@@ -100,7 +71,7 @@ PageBase {
}
contentItem: Item {}
antialiasing: true
enabled: VpnLogic.pushButtonConnectEnabled && VpnLogic.isContainerSupportedByCurrentPlatform
enabled: VpnLogic.pushButtonConnectEnabled && VpnLogic.isContainerWorkingOnPlatform
opacity: VpnLogic.pushButtonConnectVisible ? 1 : 0
// transitions: Transition {
@@ -130,14 +101,14 @@ PageBase {
LabelType {
Layout.alignment: Qt.AlignRight
height: 21
text: ( VpnLogic.isContainerHaveAuthData ? qsTr("Server") : qsTr("Profile")) + ": "
text: qsTr("Server") + ": "
}
BasicButtonType {
Layout.alignment: Qt.AlignLeft
height: 21
background: Item {}
text: VpnLogic.labelCurrentServer + (VpnLogic.isContainerHaveAuthData ? " →" : "")
text: VpnLogic.labelCurrentServer
font.family: "Lato"
font.styleName: "normal"
font.pixelSize: 16
@@ -158,63 +129,27 @@ PageBase {
LabelType {
Layout.alignment: Qt.AlignRight
height: 21
text: qsTr("Proto") + ": "
text: qsTr("Service") + ": "
}
BasicButtonType {
Layout.alignment: Qt.AlignLeft
height: 21
background: Item {}
text: VpnLogic.labelCurrentService + (VpnLogic.isContainerHaveAuthData ? " →" : "")
text: VpnLogic.labelCurrentService
font.family: "Lato"
font.styleName: "normal"
font.pixelSize: 16
onClicked: {
if (VpnLogic.isContainerHaveAuthData) UiLogic.onGotoCurrentProtocolsPage()
UiLogic.onGotoCurrentProtocolsPage()
}
}
}
RowLayout {
id: layout3
anchors.top: layout2.bottom
anchors.topMargin: 5
anchors.horizontalCenter: parent.horizontalCenter
height: 21
LabelType {
Layout.alignment: Qt.AlignRight
height: 21
text: qsTr("DNS") + ": "
}
BasicButtonType {
Layout.alignment: Qt.AlignLeft
height: 21
implicitWidth: implicitContentWidth > root.width * 0.6 ? root.width * 0.6 : implicitContentWidth + leftPadding + rightPadding
background: Item {}
text: VpnLogic.labelCurrentDns + (VpnLogic.isContainerHaveAuthData ? " →" : "")
font.family: "Lato"
font.styleName: "normal"
font.pixelSize: 16
onClicked: {
if (VpnLogic.isContainerHaveAuthData) UiLogic.goToPage(PageEnum.NetworkSettings)
}
}
SvgImageType {
svg.source: VpnLogic.amneziaDnsEnabled ? "qrc:/images/svg/gpp_good_black_24dp.svg" : "qrc:/images/svg/gpp_maybe_black_24dp.svg"
color: VpnLogic.amneziaDnsEnabled ? "#22aa33" : "orange"
width: 25
height: 25
}
}
LabelType {
id: error_text
anchors.top: layout3.bottom
anchors.top: layout2.bottom
anchors.horizontalCenter: parent.horizontalCenter
anchors.topMargin: 20
width: parent.width - 20
@@ -324,7 +259,6 @@ PageBase {
onClicked: VpnLogic.onRadioButtonVpnModeAllSitesClicked(true)
}
RadioButtonType {
enabled: VpnLogic.isCustomRoutesSupported
x: 0
y: 60
width: 341
@@ -334,7 +268,6 @@ PageBase {
onClicked: VpnLogic.onRadioButtonVpnModeExceptSitesClicked(true)
}
RadioButtonType {
enabled: VpnLogic.isCustomRoutesSupported
x: 0
y: 30
width: 341

View File

@@ -16,7 +16,7 @@ PageProtocolBase {
Caption {
id: caption
text: qsTr("SFTP settings")
text: qsTr("SFTF settings")
}
Rectangle {
@@ -77,42 +77,40 @@ PageProtocolBase {
}
}
RichLabelType {
LabelType {
anchors.bottom: check_persist.top
anchors.bottomMargin: 10
width: parent.width - 60
x: 30
font.pixelSize: 14
textFormat: Text.RichText
readonly property string windows_text: "In order to mount remote SFTP folder as local drive, perform following steps:
MouseArea {
anchors.fill: parent
cursorShape: parent.hoveredLink ? Qt.PointingHandCursor : Qt.ArrowCursor
acceptedButtons: Qt.NoButton
}
// text: "In order to mount remote SFTP folder as local drive, perform following steps:
//- Install the latest version of WinFsp [https://github.com/billziss-gh/winfsp/releases/latest].
//- Install the latest version of SSHFS-Win. Choose the x64 or x86 installer according to your computer's architecture [https://github.com/billziss-gh/sshfs-win/releases]"
onLinkActivated: Qt.openUrlExternally(link)
text:"In order to mount remote SFTP folder as local drive, perform following steps:
<ul>
<li>Install the latest version of <a href=\"https://github.com/billziss-gh/winfsp/releases/latest\">WinFsp</a>.</li>
<li>Install the latest version of <a href=\"https://github.com/billziss-gh/sshfs-win/releases\">SSHFS-Win</a>. Choose the x64 or x86 installer according to your computer's architecture.</li>
</ul>"
readonly property string macos_text: "In order to mount remote SFTP folder as local folder, perform following steps:
<ul>
<li>Install the latest version of <a href=\"https://osxfuse.github.io/\">macFUSE</a>.</li>
<li>Install the latest version of <a href=\"https://osxfuse.github.io/\">SSHFS</a>.</li>
</ul>"
text: {
if (Qt.platform.os == "windows") return windows_text
else if (Qt.platform.os == "osx") return macos_text
else if (Qt.platform.os == "linux") return ""
else return ""
}
}
CheckBoxType {
id: check_persist
visible: false
anchors.bottom: pb_mount.top
anchors.bottomMargin: 10
x: 30
width: parent.width
height: 21
text: qsTr("Restore drive when client starts")
text: qsTr("Restore drive after restart")
checked: logic.checkBoxSftpRestoreChecked
onCheckedChanged: {
logic.checkBoxSftpRestoreChecked = checked
@@ -124,7 +122,6 @@ PageProtocolBase {
BlueButtonType {
id: pb_mount
visible: GC.isDesktop()
enabled: logic.pushButtonSftpMountEnabled
anchors.horizontalCenter: parent.horizontalCenter
anchors.bottom: parent.bottom

View File

@@ -11,6 +11,7 @@ PageProtocolBase {
protocol: ProtocolEnum.ShadowSocks
logic: UiLogic.protocolLogic(protocol)
enabled: logic.pageEnabled
BackButton {
id: back
}

View File

@@ -117,7 +117,7 @@ New encryption keys pair will be generated.")
visible: tfShareCode.textArea.length > 0
onClicked: {
UiLogic.saveTextFile(qsTr("Save AmneziaVPN config"), "amnezia_config.vpn", "*.vpn", tfShareCode.textArea.text)
UiLogic.saveTextFile(qsTr("Save AmneziaVPN config"), "*.vpn", tfShareCode.textArea.text)
}
}

Some files were not shown because too many files have changed in this diff Show More