Compare commits
2 Commits
2.0.10
...
dev-killsw
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
7bc520819a | ||
|
|
858537df1f |
4
.gitattributes
vendored
@@ -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
|
||||
@@ -2,5 +2,5 @@ TEMPLATE = subdirs
|
||||
SUBDIRS = client
|
||||
|
||||
!ios:!android {
|
||||
SUBDIRS += service
|
||||
SUBDIRS += service platform
|
||||
}
|
||||
|
||||
@@ -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>
|
||||
|
||||
@@ -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 {
|
||||
|
||||
@@ -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?
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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
|
||||
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
@@ -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,
|
||||
|
||||
@@ -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) {
|
||||
|
||||
@@ -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);
|
||||
};
|
||||
|
||||
|
||||
|
||||
@@ -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
|
||||
}
|
||||
|
||||
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -5,7 +5,6 @@
|
||||
#include <QObject>
|
||||
#include "sshconnection.h"
|
||||
#include "sshremoteprocess.h"
|
||||
#include "debug.h"
|
||||
#include "defs.h"
|
||||
#include "settings.h"
|
||||
|
||||
|
||||
@@ -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();
|
||||
}
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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
|
After Width: | Height: | Size: 324 B |
BIN
client/images/reload.png
Normal file
|
After Width: | Height: | Size: 690 B |
BIN
client/images/server_settings.png
Normal file
|
After Width: | Height: | Size: 454 B |
@@ -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 |
@@ -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 |
@@ -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 |
@@ -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 |
@@ -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 |
@@ -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 |
@@ -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 |
@@ -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 |
@@ -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 |
@@ -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 |
@@ -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 |
@@ -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 |
@@ -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 |
@@ -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 |
@@ -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 |
@@ -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();
|
||||
}
|
||||
|
||||
@@ -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);
|
||||
|
||||
|
||||
@@ -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";
|
||||
|
||||
}
|
||||
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
@@ -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>
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -5,4 +5,3 @@ sudo docker run \
|
||||
-d --privileged \
|
||||
--name $CONTAINER_NAME $CONTAINER_NAME
|
||||
|
||||
sudo docker network connect amnezia-dns-net $CONTAINER_NAME
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
FROM alpine:3.15
|
||||
FROM alpine:latest
|
||||
|
||||
LABEL maintainer="AmneziaVPN"
|
||||
|
||||
|
||||
@@ -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'
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
|
||||
@@ -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'
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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'
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
FROM alpine:3.15
|
||||
FROM alpine:latest
|
||||
|
||||
LABEL maintainer="AmneziaVPN"
|
||||
|
||||
|
||||
@@ -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"
|
||||
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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
@@ -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() {
|
||||
|
||||
@@ -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();
|
||||
}
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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();
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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())
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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();
|
||||
}
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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
|
||||
}
|
||||
|
||||
|
||||
@@ -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
|
||||
|
||||
};
|
||||
|
||||
@@ -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"
|
||||
}
|
||||
|
||||
@@ -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
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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
|
||||
}
|
||||
|
||||
@@ -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
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
}
|
||||
}
|
||||
@@ -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
|
||||
}
|
||||
}
|
||||
@@ -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
|
||||
}
|
||||
}
|
||||
@@ -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
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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()
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -59,10 +59,6 @@ PageBase {
|
||||
|
||||
SelectContainer {
|
||||
id: container_selector
|
||||
onAboutToHide: {
|
||||
pageLoader.focus = true
|
||||
}
|
||||
|
||||
onContainerSelected: {
|
||||
var containerProto = ContainerProps.defaultProtocol(c_index)
|
||||
|
||||
|
||||
@@ -41,10 +41,6 @@ PageBase {
|
||||
SelectContainer {
|
||||
id: container_selector
|
||||
|
||||
onAboutToHide: {
|
||||
pageLoader.focus = true
|
||||
}
|
||||
|
||||
onContainerSelected: {
|
||||
var containerProto = ContainerProps.defaultProtocol(c_index)
|
||||
|
||||
|
||||
@@ -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 {
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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)
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -11,6 +11,7 @@ PageProtocolBase {
|
||||
protocol: ProtocolEnum.ShadowSocks
|
||||
logic: UiLogic.protocolLogic(protocol)
|
||||
|
||||
enabled: logic.pageEnabled
|
||||
BackButton {
|
||||
id: back
|
||||
}
|
||||
|
||||
@@ -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)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||