diff --git a/CMakeLists.txt b/CMakeLists.txt index 321e4f8d..287d92f2 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -2,7 +2,7 @@ cmake_minimum_required(VERSION 3.25.0 FATAL_ERROR) set(PROJECT AmneziaVPN) -project(${PROJECT} VERSION 4.8.0.0 +project(${PROJECT} VERSION 4.8.0.1 DESCRIPTION "AmneziaVPN" HOMEPAGE_URL "https://amnezia.org/" ) diff --git a/client/3rd-prebuilt b/client/3rd-prebuilt index c38a587f..ba580dc5 160000 --- a/client/3rd-prebuilt +++ b/client/3rd-prebuilt @@ -1 +1 @@ -Subproject commit c38a587fcda89bab4009560d36239fa8de74705e +Subproject commit ba580dc5bd7784f7b1e110ff0365f3286e549a61 diff --git a/client/android/awg/src/main/kotlin/Awg.kt b/client/android/awg/src/main/kotlin/Awg.kt index f4175763..fbd1cce0 100644 --- a/client/android/awg/src/main/kotlin/Awg.kt +++ b/client/android/awg/src/main/kotlin/Awg.kt @@ -1,81 +1,28 @@ package org.amnezia.vpn.protocol.awg import org.amnezia.vpn.protocol.wireguard.Wireguard +import org.amnezia.vpn.util.optStringOrNull import org.json.JSONObject -/** - * Config example: - * { - * "protocol": "awg", - * "description": "Server 1", - * "dns1": "1.1.1.1", - * "dns2": "1.0.0.1", - * "hostName": "100.100.100.0", - * "splitTunnelSites": [ - * ], - * "splitTunnelType": 0, - * "awg_config_data": { - * "H1": "969537490", - * "H2": "481688153", - * "H3": "2049399200", - * "H4": "52029755", - * "Jc": "3", - * "Jmax": "1000", - * "Jmin": "50", - * "S1": "49", - * "S2": "60", - * "client_ip": "10.8.1.1", - * "hostName": "100.100.100.0", - * "port": 12345, - * "client_pub_key": "clientPublicKeyBase64", - * "client_priv_key": "privateKeyBase64", - * "psk_key": "presharedKeyBase64", - * "server_pub_key": "publicKeyBase64", - * "config": "[Interface] - * Address = 10.8.1.1/32 - * DNS = 1.1.1.1, 1.0.0.1 - * PrivateKey = privateKeyBase64 - * Jc = 3 - * Jmin = 50 - * Jmax = 1000 - * S1 = 49 - * S2 = 60 - * H1 = 969537490 - * H2 = 481688153 - * H3 = 2049399200 - * H4 = 52029755 - * - * [Peer] - * PublicKey = publicKeyBase64 - * PresharedKey = presharedKeyBase64 - * AllowedIPs = 0.0.0.0/0, ::/0 - * Endpoint = 100.100.100.0:12345 - * PersistentKeepalive = 25 - * " - * } - * } - */ - class Awg : Wireguard() { override val ifName: String = "awg0" override fun parseConfig(config: JSONObject): AwgConfig { - val configDataJson = config.getJSONObject("awg_config_data") - val configData = parseConfigData(configDataJson.getString("config")) + val configData = config.getJSONObject("awg_config_data") return AwgConfig.build { - configWireguard(configData, configDataJson) + configWireguard(config, configData) configSplitTunneling(config) configAppSplitTunneling(config) - configData["Jc"]?.let { setJc(it.toInt()) } - configData["Jmin"]?.let { setJmin(it.toInt()) } - configData["Jmax"]?.let { setJmax(it.toInt()) } - configData["S1"]?.let { setS1(it.toInt()) } - configData["S2"]?.let { setS2(it.toInt()) } - configData["H1"]?.let { setH1(it.toLong()) } - configData["H2"]?.let { setH2(it.toLong()) } - configData["H3"]?.let { setH3(it.toLong()) } - configData["H4"]?.let { setH4(it.toLong()) } + configData.optStringOrNull("Jc")?.let { setJc(it.toInt()) } + configData.optStringOrNull("Jmin")?.let { setJmin(it.toInt()) } + configData.optStringOrNull("Jmax")?.let { setJmax(it.toInt()) } + configData.optStringOrNull("S1")?.let { setS1(it.toInt()) } + configData.optStringOrNull("S2")?.let { setS2(it.toInt()) } + configData.optStringOrNull("H1")?.let { setH1(it.toLong()) } + configData.optStringOrNull("H2")?.let { setH2(it.toLong()) } + configData.optStringOrNull("H3")?.let { setH3(it.toLong()) } + configData.optStringOrNull("H4")?.let { setH4(it.toLong()) } } } } diff --git a/client/android/cloak/src/main/kotlin/Cloak.kt b/client/android/cloak/src/main/kotlin/Cloak.kt index 5a549130..18a5e6c7 100644 --- a/client/android/cloak/src/main/kotlin/Cloak.kt +++ b/client/android/cloak/src/main/kotlin/Cloak.kt @@ -5,36 +5,6 @@ import net.openvpn.ovpn3.ClientAPI_Config import org.amnezia.vpn.protocol.openvpn.OpenVpn import org.json.JSONObject -/** - * Config Example: - * { - * "protocol": "cloak", - * "description": "Server 1", - * "dns1": "1.1.1.1", - * "dns2": "1.0.0.1", - * "hostName": "100.100.100.0", - * "splitTunnelSites": [ - * ], - * "splitTunnelType": 0, - * "openvpn_config_data": { - * "config": "openVpnConfig" - * } - * "cloak_config_data": { - * "BrowserSig": "chrome", - * "EncryptionMethod": "aes-gcm", - * "NumConn": 1, - * "ProxyMethod": "openvpn", - * "PublicKey": "PublicKey=", - * "RemoteHost": "100.100.100.0", - * "RemotePort": "443", - * "ServerName": "servername", - * "StreamTimeout": 300, - * "Transport": "direct", - * "UID": "UID=" - * } - * } - */ - class Cloak : OpenVpn() { override fun parseConfig(config: JSONObject): ClientAPI_Config { diff --git a/client/android/openvpn/src/main/kotlin/org/amnezia/vpn/protocol/openvpn/OpenVpn.kt b/client/android/openvpn/src/main/kotlin/org/amnezia/vpn/protocol/openvpn/OpenVpn.kt index dd096c60..fa0e19f1 100644 --- a/client/android/openvpn/src/main/kotlin/org/amnezia/vpn/protocol/openvpn/OpenVpn.kt +++ b/client/android/openvpn/src/main/kotlin/org/amnezia/vpn/protocol/openvpn/OpenVpn.kt @@ -16,23 +16,6 @@ import org.amnezia.vpn.util.net.getLocalNetworks import org.amnezia.vpn.util.net.parseInetAddress import org.json.JSONObject -/** - * Config Example: - * { - * "protocol": "openvpn", - * "description": "Server 1", - * "dns1": "1.1.1.1", - * "dns2": "1.0.0.1", - * "hostName": "100.100.100.0", - * "splitTunnelSites": [ - * ], - * "splitTunnelType": 0, - * "openvpn_config_data": { - * "config": "openVpnConfig" - * } - * } - */ - open class OpenVpn : Protocol() { private var openVpnClient: OpenVpnClient? = null diff --git a/client/android/utils/src/main/kotlin/JsonExt.kt b/client/android/utils/src/main/kotlin/JsonExt.kt new file mode 100644 index 00000000..45c5bacd --- /dev/null +++ b/client/android/utils/src/main/kotlin/JsonExt.kt @@ -0,0 +1,9 @@ +package org.amnezia.vpn.util + +import org.json.JSONArray +import org.json.JSONObject + +inline fun JSONArray.asSequence(): Sequence = + (0.. { return emptyList() } -fun parseInetAddress(address: String): InetAddress = parseNumericAddressCompat(address) +fun parseInetAddress(address: String): InetAddress = InetAddress.getByName(address) private val parseNumericAddressCompat: (String) -> InetAddress = if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q) { diff --git a/client/android/wireguard/src/main/kotlin/org/amnezia/vpn/protocol/wireguard/Wireguard.kt b/client/android/wireguard/src/main/kotlin/org/amnezia/vpn/protocol/wireguard/Wireguard.kt index b5804a6d..c32ab8c2 100644 --- a/client/android/wireguard/src/main/kotlin/org/amnezia/vpn/protocol/wireguard/Wireguard.kt +++ b/client/android/wireguard/src/main/kotlin/org/amnezia/vpn/protocol/wireguard/Wireguard.kt @@ -14,46 +14,13 @@ import org.amnezia.vpn.protocol.ProtocolState.DISCONNECTED import org.amnezia.vpn.protocol.Statistics import org.amnezia.vpn.protocol.VpnStartException import org.amnezia.vpn.util.Log +import org.amnezia.vpn.util.asSequence import org.amnezia.vpn.util.net.InetEndpoint import org.amnezia.vpn.util.net.InetNetwork import org.amnezia.vpn.util.net.parseInetAddress +import org.amnezia.vpn.util.optStringOrNull import org.json.JSONObject -/** - * Config example: - * { - * "protocol": "wireguard", - * "description": "Server 1", - * "dns1": "1.1.1.1", - * "dns2": "1.0.0.1", - * "hostName": "100.100.100.0", - * "splitTunnelSites": [ - * ], - * "splitTunnelType": 0, - * "wireguard_config_data": { - * "client_ip": "10.8.1.1", - * "hostName": "100.100.100.0", - * "port": 12345, - * "client_pub_key": "clientPublicKeyBase64", - * "client_priv_key": "privateKeyBase64", - * "psk_key": "presharedKeyBase64", - * "server_pub_key": "publicKeyBase64", - * "config": "[Interface] - * Address = 10.8.1.1/32 - * DNS = 1.1.1.1, 1.0.0.1 - * PrivateKey = privateKeyBase64 - * - * [Peer] - * PublicKey = publicKeyBase64 - * PresharedKey = presharedKeyBase64 - * AllowedIPs = 0.0.0.0/0, ::/0 - * Endpoint = 100.100.100.0:12345 - * PersistentKeepalive = 25 - * " - * } - * } - */ - private const val TAG = "Wireguard" open class Wireguard : Protocol() { @@ -123,60 +90,49 @@ open class Wireguard : Protocol() { .inputStream.reader().readText() protected open fun parseConfig(config: JSONObject): WireguardConfig { - val configDataJson = config.getJSONObject("wireguard_config_data") - val configData = parseConfigData(configDataJson.getString("config")) + val configData = config.getJSONObject("wireguard_config_data") return WireguardConfig.build { - configWireguard(configData, configDataJson) + configWireguard(config, configData) configSplitTunneling(config) configAppSplitTunneling(config) } } - protected fun WireguardConfig.Builder.configWireguard(configData: Map, configDataJson: JSONObject) { - configData["Address"]?.split(",")?.map { address -> + protected fun WireguardConfig.Builder.configWireguard(config: JSONObject, configData: JSONObject) { + configData.getString("client_ip").split(",").map { address -> InetNetwork.parse(address.trim()) - }?.forEach(::addAddress) + }.forEach(::addAddress) - configData["DNS"]?.split(",")?.map { dns -> - parseInetAddress(dns.trim()) - }?.forEach(::addDnsServer) + config.optStringOrNull("dns1")?.let { dns -> + addDnsServer(parseInetAddress(dns.trim())) + } + + config.optStringOrNull("dns2")?.let { dns -> + addDnsServer(parseInetAddress(dns.trim())) + } val defRoutes = hashSetOf( InetNetwork("0.0.0.0", 0), InetNetwork("::", 0) ) val routes = hashSetOf() - configData["AllowedIPs"]?.split(",")?.map { route -> + configData.getJSONArray("allowed_ips").asSequence().map { route -> InetNetwork.parse(route.trim()) - }?.forEach(routes::add) + }.forEach(routes::add) // if the allowed IPs list contains at least one non-default route, disable global split tunneling if (routes.any { it !in defRoutes }) disableSplitTunneling() addRoutes(routes) - configDataJson.optString("mtu").let { mtu -> - if (mtu.isNotEmpty()) { - setMtu(mtu.toInt()) - } else { - configData["MTU"]?.let { setMtu(it.toInt()) } - } - } + configData.optStringOrNull("mtu")?.let { setMtu(it.toInt()) } - configData["Endpoint"]?.let { setEndpoint(InetEndpoint.parse(it)) } - configData["PersistentKeepalive"]?.let { setPersistentKeepalive(it.toInt()) } - configData["PrivateKey"]?.let { setPrivateKeyHex(it.base64ToHex()) } - configData["PublicKey"]?.let { setPublicKeyHex(it.base64ToHex()) } - configData["PresharedKey"]?.let { setPreSharedKeyHex(it.base64ToHex()) } - } + val host = configData.getString("hostName").let { parseInetAddress(it.trim()) } + val port = configData.getInt("port") + setEndpoint(InetEndpoint(host, port)) - protected fun parseConfigData(data: String): Map { - val parsedData = TreeMap(String.CASE_INSENSITIVE_ORDER) - data.lineSequence() - .filter { it.isNotEmpty() && !it.startsWith('[') } - .forEach { line -> - val attr = line.split("=", limit = 2) - parsedData[attr.first().trim()] = attr.last().trim() - } - return parsedData + configData.optStringOrNull("persistent_keep_alive")?.let { setPersistentKeepalive(it.toInt()) } + configData.getString("client_priv_key").let { setPrivateKeyHex(it.base64ToHex()) } + configData.getString("server_pub_key").let { setPublicKeyHex(it.base64ToHex()) } + configData.optStringOrNull("psk_key")?.let { setPreSharedKeyHex(it.base64ToHex()) } } private fun start(config: WireguardConfig, vpnBuilder: Builder, protect: (Int) -> Boolean) { diff --git a/client/android/xray/src/main/kotlin/Xray.kt b/client/android/xray/src/main/kotlin/Xray.kt index 94afec2a..ec22a4bd 100644 --- a/client/android/xray/src/main/kotlin/Xray.kt +++ b/client/android/xray/src/main/kotlin/Xray.kt @@ -20,69 +20,6 @@ import org.amnezia.vpn.util.net.InetNetwork import org.amnezia.vpn.util.net.parseInetAddress import org.json.JSONObject -/** - * Config example: - * { - * "appSplitTunnelType": 0, - * "config_version": 0, - * "description": "Server 1", - * "dns1": "1.1.1.1", - * "dns2": "1.0.0.1", - * "hostName": "100.100.100.0", - * "protocol": "xray", - * "splitTunnelApps": [], - * "splitTunnelSites": [], - * "splitTunnelType": 0, - * "xray_config_data": { - * "inbounds": [ - * { - * "listen": "127.0.0.1", - * "port": 8080, - * "protocol": "socks", - * "settings": { - * "udp": true - * } - * } - * ], - * "log": { - * "loglevel": "error" - * }, - * "outbounds": [ - * { - * "protocol": "vless", - * "settings": { - * "vnext": [ - * { - * "address": "100.100.100.0", - * "port": 443, - * "users": [ - * { - * "encryption": "none", - * "flow": "xtls-rprx-vision", - * "id": "id" - * } - * ] - * } - * ] - * }, - * "streamSettings": { - * "network": "tcp", - * "realitySettings": { - * "fingerprint": "chrome", - * "publicKey": "publicKey", - * "serverName": "google.com", - * "shortId": "id", - * "spiderX": "" - * }, - * "security": "reality" - * } - * } - * ] - * } - * } - * - */ - private const val TAG = "Xray" private const val LIBXRAY_TAG = "libXray" diff --git a/client/configurators/wireguard_configurator.cpp b/client/configurators/wireguard_configurator.cpp index f7faaa52..0d083742 100644 --- a/client/configurators/wireguard_configurator.cpp +++ b/client/configurators/wireguard_configurator.cpp @@ -95,6 +95,18 @@ WireguardConfigurator::ConnectionData WireguardConfigurator::prepareWireguardCon stdOut.replace("/32", ""); QStringList ips = stdOut.split("\n", Qt::SkipEmptyParts); + // remove extra IPs from each line for case when user manually edited the wg0.conf + // and added there more IPs for route his itnernal networks, like: + // ... + // AllowedIPs = 10.8.1.6/32, 192.168.1.0/24, 192.168.2.0/24, ... + // ... + // without this code - next IP would be 1 if last item in 'ips' has format above + QStringList vpnIps; + for (const auto &ip : ips) { + vpnIps.append(ip.split(",", Qt::SkipEmptyParts).first().trimmed()); + } + ips = vpnIps; + // Calc next IP address if (ips.isEmpty()) { nextIpNumber = "2"; @@ -187,6 +199,10 @@ QString WireguardConfigurator::createConfig(const ServerCredentials &credentials jConfig[config_key::server_pub_key] = connData.serverPubKey; jConfig[config_key::mtu] = wireguarConfig.value(config_key::mtu).toString(protocols::wireguard::defaultMtu); + jConfig[config_key::persistent_keep_alive] = 25; + QJsonArray allowedIps { "0.0.0.0/0", "::/0" }; + jConfig[config_key::allowed_ips] = allowedIps; + jConfig[config_key::clientId] = connData.clientPubKey; return QJsonDocument(jConfig).toJson(); diff --git a/client/core/controllers/serverController.cpp b/client/core/controllers/serverController.cpp index 9a745e3d..b6795a01 100644 --- a/client/core/controllers/serverController.cpp +++ b/client/core/controllers/serverController.cpp @@ -104,7 +104,8 @@ ErrorCode ServerController::runContainerScript(const ServerCredentials &credenti if (e) return e; - QString runner = QString("sudo docker exec -i $CONTAINER_NAME %2 %1 ").arg(fileName, (container == DockerContainer::Socks5Proxy ? "sh" : "bash")); + QString runner = + QString("sudo docker exec -i $CONTAINER_NAME %2 %1 ").arg(fileName, (container == DockerContainer::Socks5Proxy ? "sh" : "bash")); e = runScript(credentials, replaceVars(runner, genVarsForScript(credentials, container)), cbReadStdOut, cbReadStdErr); QString remover = QString("sudo docker exec -i $CONTAINER_NAME rm %1 ").arg(fileName); @@ -424,7 +425,7 @@ ErrorCode ServerController::buildContainerWorker(const ServerCredentials &creden if (errorCode) return errorCode; - errorCode = uploadFileToHost(credentials, amnezia::scriptData(ProtocolScriptType::dockerfile, container).toUtf8(),dockerFilePath); + errorCode = uploadFileToHost(credentials, amnezia::scriptData(ProtocolScriptType::dockerfile, container).toUtf8(), dockerFilePath); if (errorCode) return errorCode; @@ -435,9 +436,10 @@ ErrorCode ServerController::buildContainerWorker(const ServerCredentials &creden return ErrorCode::NoError; }; - errorCode = runScript(credentials, - replaceVars(amnezia::scriptData(SharedScriptType::build_container), genVarsForScript(credentials, container, config)), - cbReadStdOut); + errorCode = + runScript(credentials, + replaceVars(amnezia::scriptData(SharedScriptType::build_container), genVarsForScript(credentials, container, config)), + cbReadStdOut); if (errorCode) return errorCode; @@ -619,13 +621,15 @@ ServerController::Vars ServerController::genVarsForScript(const ServerCredential // Socks5 proxy vars vars.append({ { "$SOCKS5_PROXY_PORT", socks5ProxyConfig.value(config_key::port).toString(protocols::socks5Proxy::defaultPort) } }); - auto username = socks5ProxyConfig.value(config_key:: userName).toString(); + auto username = socks5ProxyConfig.value(config_key::userName).toString(); auto password = socks5ProxyConfig.value(config_key::password).toString(); QString socks5user = (!username.isEmpty() && !password.isEmpty()) ? QString("users %1:CL:%2").arg(username, password) : ""; - vars.append({ { "$SOCKS5_USER", socks5user } }); - vars.append({ { "$SOCKS5_AUTH_TYPE", socks5user.isEmpty() ? "none" : "strong" } }); + vars.append({ { "$SOCKS5_USER", socks5user } }); + vars.append({ { "$SOCKS5_AUTH_TYPE", socks5user.isEmpty() ? "none" : "strong" } }); - QString serverIp = NetworkUtilities::getIPAddress(credentials.hostName); + QString serverIp = (container != DockerContainer::Awg && container != DockerContainer::WireGuard && container != DockerContainer::Xray) + ? NetworkUtilities::getIPAddress(credentials.hostName) + : credentials.hostName; if (!serverIp.isEmpty()) { vars.append({ { "$SERVER_IP_ADDRESS", serverIp } }); } else { @@ -711,7 +715,8 @@ ErrorCode ServerController::isServerPortBusy(const ServerCredentials &credential udpProtoScript.append("' | grep -i udp"); tcpProtoScript.append(" | grep LISTEN"); - ErrorCode errorCode = runScript(credentials, replaceVars(tcpProtoScript, genVarsForScript(credentials, container)), cbReadStdOut, cbReadStdErr); + ErrorCode errorCode = + runScript(credentials, replaceVars(tcpProtoScript, genVarsForScript(credentials, container)), cbReadStdOut, cbReadStdErr); if (errorCode != ErrorCode::NoError) { return errorCode; } diff --git a/client/core/controllers/vpnConfigurationController.cpp b/client/core/controllers/vpnConfigurationController.cpp index 818cf57e..52f42c42 100644 --- a/client/core/controllers/vpnConfigurationController.cpp +++ b/client/core/controllers/vpnConfigurationController.cpp @@ -100,7 +100,13 @@ QJsonObject VpnConfigurationsController::createVpnConfiguration(const QPairprocessConfigWithLocalSettings(dns, isApiConfig, protocolConfigString); QJsonObject vpnConfigData = QJsonDocument::fromJson(protocolConfigString.toUtf8()).object(); - vpnConfigData = QJsonDocument::fromJson(protocolConfigString.toUtf8()).object(); + if (container == DockerContainer::Awg || container == DockerContainer::WireGuard) { + // add mtu for old configs + if (vpnConfigData[config_key::mtu].toString().isEmpty()) { + vpnConfigData[config_key::mtu] = container == DockerContainer::Awg ? protocols::awg::defaultMtu : protocols::wireguard::defaultMtu; + } + } + vpnConfiguration.insert(ProtocolProps::key_proto_config_data(proto), vpnConfigData); } diff --git a/client/core/networkUtilities.cpp b/client/core/networkUtilities.cpp index 7ffd4c41..a5825f0d 100644 --- a/client/core/networkUtilities.cpp +++ b/client/core/networkUtilities.cpp @@ -109,7 +109,10 @@ QStringList NetworkUtilities::summarizeRoutes(const QStringList &ips, const QStr QString NetworkUtilities::getIPAddress(const QString &host) { - if (ipAddressRegExp().match(host).hasMatch()) { + QHostAddress address(host); + if (QAbstractSocket::IPv4Protocol == address.protocol()) { + return host; + } else if (QAbstractSocket::IPv6Protocol == address.protocol()) { return host; } diff --git a/client/mozilla/localsocketcontroller.cpp b/client/mozilla/localsocketcontroller.cpp index 0502facc..4d040288 100644 --- a/client/mozilla/localsocketcontroller.cpp +++ b/client/mozilla/localsocketcontroller.cpp @@ -149,7 +149,7 @@ void LocalSocketController::activate(const QJsonObject &rawConfig) { QJsonArray jsAllowedIPAddesses; QJsonArray plainAllowedIP = wgConfig.value(amnezia::config_key::allowed_ips).toArray(); - QJsonArray defaultAllowedIP = QJsonArray::fromStringList(QString("0.0.0.0/0, ::/0").split(",")); + QJsonArray defaultAllowedIP = { "0.0.0.0/0", "::/0" }; if (plainAllowedIP != defaultAllowedIP && !plainAllowedIP.isEmpty()) { // Use AllowedIP list from WG config because of higher priority diff --git a/client/platforms/ios/ios_controller.mm b/client/platforms/ios/ios_controller.mm index f4ba2798..6abae584 100644 --- a/client/platforms/ios/ios_controller.mm +++ b/client/platforms/ios/ios_controller.mm @@ -351,8 +351,6 @@ void IosController::vpnStatusDidChange(void *pNotification) } } } - } else { - qDebug() << "Disconnect error is absent"; } }]; } else { @@ -835,7 +833,7 @@ QString IosController::openFile() { void IosController::requestInetAccess() { NSURL *url = [NSURL URLWithString:@"http://captive.apple.com/generate_204"]; - if (url) { + if (!url) { qDebug() << "IosController::requestInetAccess URL error"; return; } @@ -847,7 +845,6 @@ void IosController::requestInetAccess() { } else { NSHTTPURLResponse *httpResponse = (NSHTTPURLResponse *)response; QString responseBody = QString::fromUtf8((const char*)data.bytes, data.length); - qDebug() << "IosController::requestInetAccess server response:" << httpResponse.statusCode << "\n\n" < #include -#include "logger.h" -#include "utilities.h" #include "wireguardprotocol.h" +#include "core/networkUtilities.h" #include "mozilla/localsocketcontroller.h" @@ -37,6 +36,12 @@ void WireguardProtocol::stop() ErrorCode WireguardProtocol::startMzImpl() { + QString protocolName = m_rawConfig.value("protocol").toString(); + QJsonObject vpnConfigData = m_rawConfig.value(protocolName + "_config_data").toObject(); + vpnConfigData[config_key::hostName] = NetworkUtilities::getIPAddress(vpnConfigData.value(config_key::hostName).toString()); + m_rawConfig.insert(protocolName + "_config_data", vpnConfigData); + m_rawConfig[config_key::hostName] = NetworkUtilities::getIPAddress(m_rawConfig[config_key::hostName].toString()); + m_impl->activate(m_rawConfig); return ErrorCode::NoError; } diff --git a/client/protocols/xrayprotocol.cpp b/client/protocols/xrayprotocol.cpp index 15106c51..a45be887 100644 --- a/client/protocols/xrayprotocol.cpp +++ b/client/protocols/xrayprotocol.cpp @@ -43,7 +43,9 @@ ErrorCode XrayProtocol::start() m_xrayCfgFile.setAutoRemove(false); #endif m_xrayCfgFile.open(); - m_xrayCfgFile.write(QJsonDocument(m_xrayConfig).toJson()); + QString config = QJsonDocument(m_xrayConfig).toJson(); + config.replace(m_remoteHost, m_remoteAddress); + m_xrayCfgFile.write(config.toUtf8()); m_xrayCfgFile.close(); QStringList args = QStringList() << "-c" << m_xrayCfgFile.fileName() << "-format=json"; @@ -238,7 +240,8 @@ void XrayProtocol::readXrayConfiguration(const QJsonObject &configuration) } m_xrayConfig = xrayConfiguration; m_localPort = QString(amnezia::protocols::xray::defaultLocalProxyPort).toInt(); - m_remoteAddress = configuration.value(amnezia::config_key::hostName).toString(); + m_remoteHost = configuration.value(amnezia::config_key::hostName).toString(); + m_remoteAddress = NetworkUtilities::getIPAddress(m_remoteHost); m_routeMode = configuration.value(amnezia::config_key::splitTunnelType).toInt(); m_primaryDNS = configuration.value(amnezia::config_key::dns1).toString(); m_secondaryDNS = configuration.value(amnezia::config_key::dns2).toString(); diff --git a/client/protocols/xrayprotocol.h b/client/protocols/xrayprotocol.h index 8df2afb2..c1d62897 100644 --- a/client/protocols/xrayprotocol.h +++ b/client/protocols/xrayprotocol.h @@ -26,6 +26,7 @@ private: static QString tun2SocksExecPath(); private: int m_localPort; + QString m_remoteHost; QString m_remoteAddress; int m_routeMode; QJsonObject m_configData; diff --git a/client/resources.qrc b/client/resources.qrc index fed42a00..a10a784d 100644 --- a/client/resources.qrc +++ b/client/resources.qrc @@ -199,6 +199,8 @@ server_scripts/socks5_proxy/Dockerfile server_scripts/socks5_proxy/configure_container.sh server_scripts/socks5_proxy/start.sh + ui/qml/Pages2/PageProtocolAwgClientSettings.qml + ui/qml/Pages2/PageProtocolWireGuardClientSettings.qml ui/qml/Pages2/PageSetupWizardApiServicesList.qml ui/qml/Pages2/PageSetupWizardApiServiceInfo.qml ui/qml/Controls2/CardWithIconsType.qml diff --git a/client/server_scripts/xray/run_container.sh b/client/server_scripts/xray/run_container.sh index bd00b992..40cc6a09 100644 --- a/client/server_scripts/xray/run_container.sh +++ b/client/server_scripts/xray/run_container.sh @@ -13,5 +13,5 @@ sudo docker network connect amnezia-dns-net $CONTAINER_NAME 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' # 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" +#sudo docker exec -i $CONTAINER_NAME sh -c "ifconfig eth0:0 $SERVER_IP_ADDRESS netmask 255.255.255.255 up" diff --git a/client/server_scripts/xray/start.sh b/client/server_scripts/xray/start.sh index 2ebce5ed..0148552f 100644 --- a/client/server_scripts/xray/start.sh +++ b/client/server_scripts/xray/start.sh @@ -3,7 +3,7 @@ # This scripts copied from Amnezia client to Docker container to /opt/amnezia and launched every time container starts echo "Container startup" -ifconfig eth0:0 $SERVER_IP_ADDRESS netmask 255.255.255.255 up +#ifconfig eth0:0 $SERVER_IP_ADDRESS netmask 255.255.255.255 up iptables -A INPUT -i lo -j ACCEPT iptables -A INPUT -m conntrack --ctstate ESTABLISHED,RELATED -j ACCEPT diff --git a/client/translations/amneziavpn_ar_EG.ts b/client/translations/amneziavpn_ar_EG.ts index be37275f..e176d8eb 100644 --- a/client/translations/amneziavpn_ar_EG.ts +++ b/client/translations/amneziavpn_ar_EG.ts @@ -4,47 +4,52 @@ ApiServicesModel - + Classic VPN for comfortable work, downloading large files and watching videos. Works for any sites. Speed up to %1 MBit/s شبكة VPN كلاسيكية للعمل المريح وتنزيل الملفات الكبيرة ومشاهدة مقاطع الفيديو. تعمل مع أي موقع. تصل السرعة إلى %1 ميجابت/ثانية - + VPN to access blocked sites in regions with high levels of Internet censorship. شبكة VPN للولوج للمواقع المحظورة في بلاد ذو مستوي عالي من الرقابة علي الانترنت. - + + <p><a style="color: #EB5757;">Not available in your region. If you have VPN enabled, disable it, return to the previous screen, and try again.</a> + + + + Amnezia Premium - A classic VPN for comfortable work, downloading large files, and watching videos in high resolution. It works for all websites, even in countries with the highest level of internet censorship. Amenzia Premium - شبكة VPN للعمل المريح, تحميل ملفات كبيرة الحجم, ومشاهدة مقاطع الفيديو ب جودة عالية. تعمل لجميع المواقع, حتي في البلاد ذو مستوي عالي من الرقابة علي الانترنت - + Amnezia Free is a free VPN to bypass blocking in countries with high levels of internet censorship Amnezia Free هو VPN مجاني لتخطي الحظر في البلاد ذو مستوي عالي من الرقابة علي الانترنت - + %1 MBit/s %1 ميجابت/ثانية - + %1 days %1 ايام - + VPN will open only popular sites blocked in your region, such as Instagram, Facebook, Twitter and others. Other sites will be opened from your real IP address, <a href="%1/free" style="color: #FBB26A;">more details on the website.</a> سيقوم VPN فقط بفتح المواقع المشهورة المحظورة في بلدك, مثل Instagram, Facebook, Twitter و مواقع اخري. المواقع الاخري ستٌفتح من عنوان ال IP الحقيقي الخاص بك, <a href="%1/free" style="color: #FBB26A;">معلومات اخري علي الموقع.</a> - + Free مجاني - + %1 $/month %1 دولار/الشهر @@ -75,7 +80,7 @@ ConnectButton - + Unable to disconnect during configuration preparation غير قادر علي قطع الاتصال اثناء إعداد التكوين @@ -186,9 +191,8 @@ ExportController - Access error! - خطأ في الوصول! + خطأ في الوصول! @@ -254,18 +258,18 @@ Can't be disabled for current server غير قادر علي فتح الملف - - + + Invalid configuration file ملف تكوين غير صحيح - + Scanned %1 of %2. تم فحص%1 من %2. - + In the imported configuration, potentially dangerous lines were found: في التكوين المستورد، تم العثور على سطور يحتمل أن تكون خطرة: @@ -443,6 +447,11 @@ Already installed containers were found on the server. All installed containers Gateway endpoint نقطة نهاية البوابة + + + Dev gateway environment + + PageHome @@ -477,10 +486,63 @@ Already installed containers were found on the server. All installed containers لا يمكن تغير الخادم بينما هناك اتصال مفعل + + PageProtocolAwgClientSettings + + + AmneziaWG settings + اعدادات AmneziaWG + + + + MTU + + + + + Server settings + + + + + Port + منفذ + + + + Save + احفظ + + + + Save settings? + احفظ الإعدادات؟ + + + + Only the settings for this device will be changed + + + + + Continue + واصل + + + + Cancel + إلغاء + + + + Unable change settings while there is an active connection + لا يمكن تغيير الإعدادات أثناء وجود اتصال نشط + + PageProtocolAwgSettings - + AmneziaWG settings اعدادات AmneziaWG @@ -490,92 +552,87 @@ Already installed containers were found on the server. All installed containers منفذ - - MTU - - - - + All users with whom you shared a connection with will no longer be able to connect to it. جميع المستخدمين الذين شاركت معهم اتصال لن يكونو قادرين علي الاتصال مرة اخري. - + Save احفظ - + Jc - Junk packet count Jc - عدد الحزم غير المرغوب فيها - + Jmin - Junk packet minimum size Jmin - الحجم الادني للحزم الغير مرغوب فيها - + Jmax - Junk packet maximum size Jmax - الحجم الاقصي للحزم الغير مرغوب فيها - + S1 - Init packet junk size S1 - حجم حزمة البيانات العشوائية الأولية - + S2 - Response packet junk size S2 - حجم حزمة الاستجابة غير المرغوب فيها - + H1 - Init packet magic header H1 - حزمة رأس سحرية مبدئية - + H2 - Response packet magic header H2 - رأس حزمة الاستجابة السحرية - + H4 - Transport packet magic header H4 - رأس حزمة النقل السحرية - + H3 - Underload packet magic header H3 - رأس حزمة السحر غير المحمل - + The values of the H1-H4 fields must be unique يجب أن تكون قيم الحقول H1-H4 فريدة - + The value of the field S1 + message initiation size (148) must not equal S2 + message response size (92) يجب ألا تساوي قيمة الحقل S1 + حجم بدء الرسالة (148) S2 + حجم استجابة الرسالة (92) - + Save settings? احفظ الإعدادات؟ - + Continue واصل - + Cancel إلغاء - + Unable change settings while there is an active connection لا يمكن تغيير الإعدادات أثناء وجود اتصال نشط @@ -862,30 +919,98 @@ Already installed containers were found on the server. All installed containers لا يمكن تغيير الإعدادات أثناء وجود اتصال نشط + + PageProtocolWireGuardClientSettings + + + WG settings + إعدادات WG + + + + MTU + + + + + Server settings + + + + + Port + منفذ + + + + Save + احفظ + + + + Save settings? + احفظ الإعدادات؟ + + + + Only the settings for this device will be changed + + + + + Continue + واصل + + + + Cancel + إلغاء + + + + Unable change settings while there is an active connection + لا يمكن تغيير الإعدادات أثناء وجود اتصال نشط + + PageProtocolWireGuardSettings - + WG settings إعدادات WG - + Port منفذ - - MTU - + + Save settings? + احفظ الإعدادات؟ - + + All users with whom you shared a connection with will no longer be able to connect to it. + جميع المستخدمين الذين شاركت معهم اتصال لن يكونو قادرين علي الاتصال مرة اخري. + + + + Continue + واصل + + + + Cancel + إلغاء + + + Unable change settings while there is an active connection لا يمكن تغيير الإعدادات أثناء وجود اتصال نشط - + Save احفظ @@ -1205,9 +1330,13 @@ Already installed containers were found on the server. All installed containers - Mail - البريد + البريد + + + + support@amnezia.org + @@ -1215,32 +1344,37 @@ Already installed containers were found on the server. All installed containers لل مراجعات والابلاغات عن المشاكل - + + Copied + + + + GitHub GitHub - + https://github.com/amnezia-vpn/amnezia-client - + Website موقع - + Software version: %1 %1 :إصدار البرنامج - + Check for updates تحقق من وجود تحديثات - + Privacy Policy سياسات الخصوصية @@ -1689,72 +1823,108 @@ Already installed containers were found on the server. All installed containers PageSettingsLogging - Logging is enabled. Note that logs will be automatically disabled after 14 days, and all log files will be deleted. - تم تمكين التسجيل. لاحظ أنه سيتم تعطيل السجلات تلقائيًا بعد 14 يومًا، وسيتم حذف جميع ملفات السجل. + تم تمكين التسجيل. لاحظ أنه سيتم تعطيل السجلات تلقائيًا بعد 14 يومًا، وسيتم حذف جميع ملفات السجل. - + Logging التسجيل - + Enabling this function will save application's logs automatically. By default, logging functionality is disabled. Enable log saving in case of application malfunction. سيتم حفظ سجلات البرنامج بشكل تلقائي عند تفعيل هذه الميزة, بشكل افتراضي, هذه الميزة مٌعطلة. قم بتفعيل هذه الميزة في حالة هناك خلل في التطبيق. - Save logs - احفظ السجلات + احفظ السجلات - Open folder with logs - افتح مجلد يحتوي علي سجلات + افتح مجلد يحتوي علي سجلات - + + Save احفظ - + + Logs files (*.log) ملفات الولوج (*.log) - + + Logs file saved تم حفظ ملف السجل - Save logs to file - احفظ السجلات في ملف + احفظ السجلات في ملف - + + Enable logs + + + + Clear logs? مسح السجلات؟ - + Continue واصل - + Cancel إلغاء - + Logs have been cleaned up تم مسح السجلات - + + Client logs + + + + + AmneziaVPN logs + + + + + + Open logs folder + + + + + + Export logs + + + + + Service logs + + + + + AmneziaVPN-service logs + + + + Clear logs احذف السجلات @@ -1914,12 +2084,11 @@ Already installed containers were found on the server. All installed containers الإعدادات - Clear %1 profile - مسح ملف تعريف %1 + مسح ملف تعريف %1 - + Clear %1 profile? مسح ملف تعريف %1؟ @@ -1929,39 +2098,64 @@ Already installed containers were found on the server. All installed containers - + Unable to clear %1 profile while there is an active connection غير قادر على مسح ملف تعريف %1 أثناء وجود اتصال نشط - + Remove احذف - + Remove %1 from server? احذف %1 من الخادم؟ - + All users with whom you shared a connection will no longer be able to connect to it. جميع المستخدمين الذين شاركت معاهم اتصال لن يستطيعو الاتصال بعد الان. - + Cannot remove active container لا يمكن إزالة الحاوية النشطة - - + + Continue واصل - - + + connection settings + + + + + Click the "connect" button to create a connection configuration + + + + + server settings + + + + + Clear profile + + + + + The connection configuration will be deleted for this device only + + + + + Cancel إلغاء @@ -2129,82 +2323,92 @@ Already installed containers were found on the server. All installed containers الاتصال - + + Settings + إعدادات + + + + Enable logs + + + + Insert the key, add a configuration file or scan the QR-code أدخل المفتاح، أضف ملف تكوين أو امسح رمز الاستجابة السريعة - + Insert key أدخل مفتاح - + Insert أدخل - + Continue واصل - + Other connection options اختيارات اتصال اخري - + VPN by Amnezia VPN بواسطة Amnezia - + Connect to classic paid and free VPN services from Amnezia اتصل بخدمات VPN الكلاسيكية المدفوعة والمجانية من Amnezia - + Self-hosted VPN VPN ذاتية الاستضافة - + Configure Amnezia VPN on your own server قم بتكوين Amnezia VPN على الخادم الخاص بك - + Restore from backup استرجاع من ملف يحتوي علي نسخة احتياطية - + Open backup file افتح ملف نسخ احتياطي - + Backup files (*.backup) ملفات نٌسخ احتياطية (*.backup) - + File with connection settings ملف إعدادات اتصال - + Open config file افتح ملف تكوين - + QR code رمز QR - + I have nothing ليس لدي اي شئ @@ -2717,12 +2921,17 @@ Already installed containers were found on the server. All installed containers مشاركة - + + Access error! + خطأ في الوصول! + + + Connection to اتصال إلي - + File with connection settings to معلف مع إعدادات الاتصال إلي @@ -2739,6 +2948,11 @@ Already installed containers were found on the server. All installed containers Settings restored from backup file تم تحميل الإعدادات من ملف نسخة احتياطية + + + Logging is enabled. Note that logs will be automaticallydisabled after 14 days, and all log files will be deleted. + + PopupType @@ -2777,12 +2991,12 @@ Already installed containers were found on the server. All installed containers لم يتم العثور علي كلمة المرور - + Could not open keystore فشل فتح مخزن المفاتيح - + Could not remove private key from keystore فشل حذف المفتاح الخاص من مخزن المفاتيح @@ -2958,27 +3172,27 @@ Already installed containers were found on the server. All installed containers فشل في فتح مخزن المفاتيح - + Could not create private key generator فشل ف إنشاء مولد المفاتيح الخاصة - + Could not generate new private key فشل في إنشاء مفتاح خاص جديد - + Could not retrieve private key from keystore فشل في استرداد مفتاح خاص من مخزن المفاتيح - + Could not create encryption cipher فشل في إنشاء شفرة التشفير - + Could not encrypt data فشل في تشفير الداتا @@ -3675,12 +3889,12 @@ While it offers a blend of security, stability, and speed, it's essential t SettingsController - + Backup file is corrupted ملف النسخه الاحتياطيه تالف - + All settings have been reset to default values تم استرجاع جميع الإعدادات للإعدادات الافتراضية @@ -3812,7 +4026,7 @@ While it offers a blend of security, stability, and speed, it's essential t VpnConnection - + Mbps diff --git a/client/translations/amneziavpn_fa_IR.ts b/client/translations/amneziavpn_fa_IR.ts index 26c4f810..6cd78e77 100644 --- a/client/translations/amneziavpn_fa_IR.ts +++ b/client/translations/amneziavpn_fa_IR.ts @@ -4,47 +4,52 @@ ApiServicesModel - + Classic VPN for comfortable work, downloading large files and watching videos. Works for any sites. Speed up to %1 MBit/s برای کار راحت، دانلود فایل‌های بزرگ و تماشای ویدیوها، از VPN کلاسیک استفاده کنید. این VPN برای هر سایتی کار می‌کند و سرعت آن تا %1 مگابیت بر ثانیه است. - + VPN to access blocked sites in regions with high levels of Internet censorship. وی پی ان برای دسترسی به سایت‌های مسدود شده در مناطق با سانسور شدید اینترنت. - + + <p><a style="color: #EB5757;">Not available in your region. If you have VPN enabled, disable it, return to the previous screen, and try again.</a> + + + + Amnezia Premium - A classic VPN for comfortable work, downloading large files, and watching videos in high resolution. It works for all websites, even in countries with the highest level of internet censorship. امنزیا پریمیوم - یک وی پی ان کلاسیک برای کار راحت، دانلود فایل‌های بزرگ و تماشای ویدیو با کیفیت بالا. قابل استفاده برای تمامی سایت‌ها، حتی در کشورهایی با بالاترین سطح سانسور اینترنت. - + Amnezia Free is a free VPN to bypass blocking in countries with high levels of internet censorship امنزیا رایگان یک وی پی ان رایگان برای دور زدن مسدودیت‌ها در کشورهایی با سطح بالای سانسور اینترنت است. - + %1 MBit/s %1 MBit/s - + %1 days %1 روز - + VPN will open only popular sites blocked in your region, such as Instagram, Facebook, Twitter and others. Other sites will be opened from your real IP address, <a href="%1/free" style="color: #FBB26A;">more details on the website.</a> وی پی ان فقط سایت‌های محبوبی را که در منطقه شما مسدود شده‌اند، مانند اینستاگرام، فیسبوک، توییتر و غیره باز می‌کند. سایر سایت‌ها با آدرس آی‌پی واقعی شما باز خواهند شد. <a href="%1/free" style="color: #FBB26A;">more details on the website.</a> - + Free رایگان - + %1 $/month %1 $/ماه @@ -75,7 +80,7 @@ ConnectButton - + Unable to disconnect during configuration preparation در هنگام آماده‌سازی پیکربندی، نمی‌توان از اتصال خارج شد. @@ -188,9 +193,8 @@ ExportController - Access error! - خطای دسترسی! + خطای دسترسی! @@ -259,18 +263,18 @@ Can't be disabled for current server نمی‌توان فایل را باز کرد. - - + + Invalid configuration file فایل پیکربندی نامعتبر است. - + Scanned %1 of %2. ارزیابی %1 از %2. - + In the imported configuration, potentially dangerous lines were found: در پیکربندی وارد شده، خطوطی که ممکن است خطرناک باشند، یافت شدند: @@ -447,6 +451,11 @@ Already installed containers were found on the server. All installed containers Gateway endpoint + + + Dev gateway environment + + PageHome @@ -481,10 +490,63 @@ Already installed containers were found on the server. All installed containers امکان تغییر سرور در هنگام متصل بودن وجود ندارد + + PageProtocolAwgClientSettings + + + AmneziaWG settings + تنظیمات AmneziaWG + + + + MTU + + + + + Server settings + + + + + Port + پورت + + + + Save + ذخیره + + + + Save settings? + تنظیمات را ذخیره کن? + + + + Only the settings for this device will be changed + + + + + Continue + + + + + Cancel + + + + + Unable change settings while there is an active connection + نمی‌توان تنظیمات را تغییر داد در حالی که اتصال فعال است. + + PageProtocolAwgSettings - + AmneziaWG settings تنظیمات AmneziaWG @@ -493,11 +555,6 @@ Already installed containers were found on the server. All installed containers Port پورت - - - MTU - - Remove AmneziaWG حذف AmneziaWG @@ -507,87 +564,87 @@ Already installed containers were found on the server. All installed containers آیا میخواهید AmneziaWG از سرور حذف شود؟ - + All users with whom you shared a connection with will no longer be able to connect to it. همه کاربرانی که با آن‌ها ارتباطی به اشتراک گذاشته‌اید دیگر قادر به اتصال به آن نخواهند بود. - + Save ذخیره - + Jc - Junk packet count - + Jmin - Junk packet minimum size - + Jmax - Junk packet maximum size - + S1 - Init packet junk size - + S2 - Response packet junk size - + H1 - Init packet magic header - + H2 - Response packet magic header - + H4 - Transport packet magic header - + H3 - Underload packet magic header - + The values of the H1-H4 fields must be unique - + The value of the field S1 + message initiation size (148) must not equal S2 + message response size (92) - + Save settings? تنظیمات را ذخیره کن? - + Continue ادامه - + Cancel کنسل - + Unable change settings while there is an active connection نمی‌توان تنظیمات را تغییر داد در حالی که اتصال فعال است. @@ -898,25 +955,88 @@ Already installed containers were found on the server. All installed containers نمی‌توان تنظیمات را تغییر داد در حالی که اتصال فعال است. + + PageProtocolWireGuardClientSettings + + + WG settings + تنظیمات WG + + + + MTU + + + + + Server settings + + + + + Port + پورت + + + + Save + ذخیره + + + + Save settings? + تنظیمات را ذخیره کن? + + + + Only the settings for this device will be changed + + + + + Continue + + + + + Cancel + + + + + Unable change settings while there is an active connection + نمی‌توان تنظیمات را تغییر داد در حالی که اتصال فعال است. + + PageProtocolWireGuardSettings - + WG settings تنظیمات WG - + Port پورت - - MTU - + + Save settings? + تنظیمات را ذخیره کن? - + + All users with whom you shared a connection with will no longer be able to connect to it. + همه کاربرانی که با آن‌ها ارتباطی به اشتراک گذاشته‌اید دیگر قادر به اتصال به آن نخواهند بود. + + + + Continue + + + + Unable change settings while there is an active connection نمی‌توان تنظیمات را تغییر داد در حالی که اتصال فعال است. @@ -925,11 +1045,12 @@ Already installed containers were found on the server. All installed containers تمام کاربرانی که این ارتباط را با آنها به اشتراک گذاشته‎اید دیگر نمی‎توانند به آن متصل شوند. + Cancel - کنسل + کنسل - + Save ذخیره @@ -1289,8 +1410,12 @@ Already installed containers were found on the server. All installed containers + support@amnezia.org + + + Mail - ایمیل + ایمیل @@ -1298,17 +1423,22 @@ Already installed containers were found on the server. All installed containers برای ارائه نظرات و گزارشات باگ - + + Copied + کپی شد + + + GitHub GitHub - + https://github.com/amnezia-vpn/amnezia-client https://github.com/amnezia-vpn/amnezia-client - + Website وب سایت @@ -1317,17 +1447,17 @@ Already installed containers were found on the server. All installed containers https://amnezia.org - + Software version: %1 %1 :نسخه نرم‎افزار - + Check for updates بررسی بروز‎رسانی - + Privacy Policy @@ -1776,72 +1906,108 @@ Already installed containers were found on the server. All installed containers PageSettingsLogging - Logging is enabled. Note that logs will be automatically disabled after 14 days, and all log files will be deleted. - ثبت وقایع فعال است. توجه داشته باشید که ثبت وقایع به‌طور خودکار پس از ۱۴ روز غیرفعال شده و تمام فایل‌های ثبت وقایع حذف خواهند شد. + ثبت وقایع فعال است. توجه داشته باشید که ثبت وقایع به‌طور خودکار پس از ۱۴ روز غیرفعال شده و تمام فایل‌های ثبت وقایع حذف خواهند شد. - + Logging گزارشات - + Enabling this function will save application's logs automatically. By default, logging functionality is disabled. Enable log saving in case of application malfunction. فعال کردن این عملکرد باعث ذخیره خودکار لاگ‌های برنامه می‌شود. به طور پیش‌فرض، قابلیت ثبت لاگ غیرفعال است. در صورت بروز خطا در برنامه، ذخیره لاگ را فعال کنید. - Save logs - ذخیره گزارشات + ذخیره گزارشات - Open folder with logs - باز کردن پوشه گزارشات + باز کردن پوشه گزارشات - + + Save ذخیره - + + Logs files (*.log) Logs files (*.log) - + + Logs file saved فایل گزارشات ذخیره شد - Save logs to file - ذخیره گزارشات در فایل + ذخیره گزارشات در فایل - + + Enable logs + + + + Clear logs? پاک کردن گزارشات؟ - + Continue ادامه - + Cancel کنسل - + Logs have been cleaned up گزارشات پاک شدند - + + Client logs + + + + + AmneziaVPN logs + + + + + + Open logs folder + + + + + + Export logs + + + + + Service logs + + + + + AmneziaVPN-service logs + + + + Clear logs پاک کردن گزارشات @@ -2013,12 +2179,11 @@ Already installed containers were found on the server. All installed containers تنظیمات - Clear %1 profile - پاک کردن پروفایل %1 + پاک کردن پروفایل %1 - + Clear %1 profile? آیا می‌خواهید پروفایل %1 را پاک کنید؟ @@ -2028,39 +2193,64 @@ Already installed containers were found on the server. All installed containers - + Unable to clear %1 profile while there is an active connection نمی‌توان پروفایل %1 را در حین اتصال فعال پاک کرد. - + Remove حذف - + Remove %1 from server? حذف %1 از سرور؟ - + All users with whom you shared a connection will no longer be able to connect to it. تمام کاربرانی که این ارتباط را با آنها به اشتراک گذاشته‎اید دیگر نمی‎توانند به آن متصل شوند. - + Cannot remove active container نمی‌توان کانتینر فعال را حذف کرد. - - + + Continue ادامه - - + + connection settings + + + + + Click the "connect" button to create a connection configuration + + + + + server settings + + + + + Clear profile + + + + + The connection configuration will be deleted for this device only + + + + + Cancel کنسل @@ -2243,7 +2433,7 @@ It's okay as long as it's from someone you trust. چی داری؟ - + File with connection settings فایل شامل تنظیمات اتصال @@ -2257,77 +2447,87 @@ It's okay as long as it's from someone you trust. ارتباط - + + Settings + تنظیمات + + + + Enable logs + + + + Insert the key, add a configuration file or scan the QR-code کلید را وارد کنید، فایل پیکربندی را اضافه کنید یا کد QR را اسکن کنید - + Insert key کلید را وارد کنید - + Insert وارد کردن - + Continue ادامه دهید - + Other connection options گزینه‌های اتصال دیگر - + VPN by Amnezia VPN توسط Amnezia - + Connect to classic paid and free VPN services from Amnezia اتصال به سرویس‌های VPN کلاسیک پولی و رایگان از Amnezia - + Self-hosted VPN Self-hosted VPN - + Configure Amnezia VPN on your own server پیکربندی VPN Amnezia بر روی سرور خودتان - + Restore from backup بازیابی از پشتیبان - + Open backup file باز کردن فایل پشتیبان - + Backup files (*.backup) Backup files (*.backup) - + Open config file باز کردن فایل تنظیمات - + QR code QR-Code - + I have nothing من هیچی ندارم @@ -2499,7 +2699,7 @@ It's okay as long as it's from someone you trust. نصب - + The port must be in the range of 1 to 65535 پورت باید در محدوده ۱ تا ۶۵۵۳۵ باشد @@ -2867,12 +3067,17 @@ It's okay as long as it's from someone you trust. اشتراک‎گذاری - + + Access error! + خطای دسترسی! + + + Connection to ارتباط با - + File with connection settings to فایل شامل تنظیمات ارتباط با @@ -2889,6 +3094,11 @@ It's okay as long as it's from someone you trust. Settings restored from backup file تنظیمات از فایل پشتیبان بازیابی شد + + + Logging is enabled. Note that logs will be automaticallydisabled after 14 days, and all log files will be deleted. + + PopupType @@ -2927,12 +3137,12 @@ It's okay as long as it's from someone you trust. Password not found - + Could not open keystore Could not open keystore - + Could not remove private key from keystore Could not remove private key from keystore @@ -3108,27 +3318,27 @@ It's okay as long as it's from someone you trust. Could not open keystore - + Could not create private key generator Could not create private key generator - + Could not generate new private key Could not generate new private key - + Could not retrieve private key from keystore Could not retrieve private key from keystore - + Could not create encryption cipher Could not create encryption cipher - + Could not encrypt data Could not encrypt data @@ -3883,7 +4093,7 @@ For more detailed information, you can SettingsController - + All settings have been reset to default values تمام تنظیمات به مقادیر پیش فرض ریست شد @@ -3892,7 +4102,7 @@ For more detailed information, you can پروفایل ذخیره شده پاک شد - + Backup file is corrupted فایل بک‎آپ خراب شده است @@ -4024,7 +4234,7 @@ For more detailed information, you can VpnConnection - + Mbps Mbps diff --git a/client/translations/amneziavpn_hi_IN.ts b/client/translations/amneziavpn_hi_IN.ts index e5cd57d8..ab459b7c 100644 --- a/client/translations/amneziavpn_hi_IN.ts +++ b/client/translations/amneziavpn_hi_IN.ts @@ -4,47 +4,52 @@ ApiServicesModel - + Classic VPN for comfortable work, downloading large files and watching videos. Works for any sites. Speed up to %1 MBit/s - + VPN to access blocked sites in regions with high levels of Internet censorship. - + + <p><a style="color: #EB5757;">Not available in your region. If you have VPN enabled, disable it, return to the previous screen, and try again.</a> + + + + Amnezia Premium - A classic VPN for comfortable work, downloading large files, and watching videos in high resolution. It works for all websites, even in countries with the highest level of internet censorship. - + Amnezia Free is a free VPN to bypass blocking in countries with high levels of internet censorship - + %1 MBit/s - + %1 days - + VPN will open only popular sites blocked in your region, such as Instagram, Facebook, Twitter and others. Other sites will be opened from your real IP address, <a href="%1/free" style="color: #FBB26A;">more details on the website.</a> - + Free - + %1 $/month @@ -75,7 +80,7 @@ ConnectButton - + Unable to disconnect during configuration preparation कॉन्फ़िगरेशन तैयारी के दौरान डिस्कनेक्ट करने में असमर्थ @@ -187,9 +192,8 @@ ExportController - Access error! - प्रवेश त्रुटि! + प्रवेश त्रुटि! @@ -255,18 +259,18 @@ Can't be disabled for current server फाइल खोलने में असमर्थ - - + + Invalid configuration file अमान्य कॉन्फ़िगरेशन फ़ाइल - + Scanned %1 of %2. %2 में से %1 स्कैन किया गया. - + In the imported configuration, potentially dangerous lines were found: @@ -443,6 +447,11 @@ Already installed containers were found on the server. All installed containers Gateway endpoint + + + Dev gateway environment + + PageHome @@ -477,10 +486,63 @@ Already installed containers were found on the server. All installed containers सक्रिय कनेक्शन होने पर सर्वर बदलने में असमर्थ + + PageProtocolAwgClientSettings + + + AmneziaWG settings + Amneziaडब्ल्यूजी सेटिंग्स + + + + MTU + एमटीयू + + + + Server settings + + + + + Port + + + + + Save + सहेजें + + + + Save settings? + सेटिंग्स सेव करें? + + + + Only the settings for this device will be changed + + + + + Continue + जारी रखना + + + + Cancel + रद्द करना + + + + Unable change settings while there is an active connection + सक्रिय कनेक्शन होने पर सेटिंग बदलने में असमर्थ + + PageProtocolAwgSettings - + AmneziaWG settings Amneziaडब्ल्यूजी सेटिंग्स @@ -490,92 +552,91 @@ Already installed containers were found on the server. All installed containers पोर्ट - MTU - एमटीयू + एमटीयू - + Jc - Junk packet count - + Jmin - Junk packet minimum size - + Jmax - Junk packet maximum size - + S1 - Init packet junk size - + S2 - Response packet junk size - + H1 - Init packet magic header - + H2 - Response packet magic header - + H4 - Transport packet magic header - + H3 - Underload packet magic header - + Save सहेजें - + The values of the H1-H4 fields must be unique H1-H4 फ़ील्ड का मान अद्वितीय होना चाहिए - + The value of the field S1 + message initiation size (148) must not equal S2 + message response size (92) फ़ील्ड S1 + संदेश आरंभ आकार (148) का मान S2 + संदेश प्रतिक्रिया आकार (92) के बराबर नहीं होना चाहिए - + Save settings? सेटिंग्स सेव करें? - + All users with whom you shared a connection with will no longer be able to connect to it. वे सभी उपयोगकर्ता जिनके साथ आपने कनेक्शन साझा किया था, वे अब इससे कनेक्ट नहीं हो पाएंगे. - + Unable change settings while there is an active connection सक्रिय कनेक्शन होने पर सेटिंग बदलने में असमर्थ - + Continue जारी रखना - + Cancel रद्द करना @@ -862,30 +923,102 @@ Already installed containers were found on the server. All installed containers सक्रिय कनेक्शन होने पर सेटिंग बदलने में असमर्थ + + PageProtocolWireGuardClientSettings + + + WG settings + डब्ल्यूजी सेटिंग्स + + + + MTU + एमटीयू + + + + Server settings + + + + + Port + + + + + Save + सहेजें + + + + Save settings? + सेटिंग्स सेव करें? + + + + Only the settings for this device will be changed + + + + + Continue + जारी रखना + + + + Cancel + रद्द करना + + + + Unable change settings while there is an active connection + सक्रिय कनेक्शन होने पर सेटिंग बदलने में असमर्थ + + PageProtocolWireGuardSettings - + WG settings डब्ल्यूजी सेटिंग्स - + Port बंदरगाह - MTU - एमटीयू + एमटीयू - + Save सहेजें - + + Save settings? + सेटिंग्स सेव करें? + + + + All users with whom you shared a connection with will no longer be able to connect to it. + वे सभी उपयोगकर्ता जिनके साथ आपने कनेक्शन साझा किया था, वे अब इससे कनेक्ट नहीं हो पाएंगे. + + + + Continue + जारी रखना + + + + Cancel + रद्द करना + + + Unable change settings while there is an active connection सक्रिय कनेक्शन होने पर सेटिंग बदलने में असमर्थ @@ -1237,9 +1370,13 @@ Already installed containers were found on the server. All installed containers - Mail - मेल + मेल + + + + support@amnezia.org + @@ -1247,32 +1384,37 @@ Already installed containers were found on the server. All installed containers समीक्षाओं और बग रिपोर्टों के लिए - + + Copied + कॉपी किया गया + + + GitHub GitHub - + https://github.com/amnezia-vpn/amnezia-client https://github.com/amnezia-vpn/amnezia-client - + Website वेबसाइट - + Software version: %1 सॉफ़्टवेयर संस्करण: %1 - + Check for updates अद्यतन के लिए जाँच - + Privacy Policy गोपनीयता नीति @@ -1729,72 +1871,108 @@ Already installed containers were found on the server. All installed containers PageSettingsLogging - Logging is enabled. Note that logs will be automatically disabled after 14 days, and all log files will be deleted. - लॉगिंग सक्षम है. ध्यान दें कि 14 दिनों के बाद लॉग स्वचालित रूप से अक्षम हो जाएंगे, और सभी लॉग फ़ाइलें हटा दी जाएंगी. + लॉगिंग सक्षम है. ध्यान दें कि 14 दिनों के बाद लॉग स्वचालित रूप से अक्षम हो जाएंगे, और सभी लॉग फ़ाइलें हटा दी जाएंगी. - + Logging लॉगिंग - + Enabling this function will save application's logs automatically. By default, logging functionality is disabled. Enable log saving in case of application malfunction. इस फ़ंक्शन को सक्षम करने से एप्लिकेशन के लॉग स्वचालित रूप से सहेजे जाएंगे, डिफ़ॉल्ट रूप से, लॉगिंग कार्यक्षमता अक्षम है। एप्लिकेशन की खराबी की स्थिति में लॉग सेविंग सक्षम करें. - Save logs - लॉग सहेजें + लॉग सहेजें - Open folder with logs - लॉग के साथ फ़ोल्डर खोलें + लॉग के साथ फ़ोल्डर खोलें - + + Save सहेजें - + + Logs files (*.log) लॉग फ़ाइलें (*.log) - + + Logs file saved लॉग फ़ाइल सहेजी गई - Save logs to file - फ़ाइल में लॉग सहेजें + फ़ाइल में लॉग सहेजें - + + Enable logs + + + + Clear logs? लॉग साफ़ करें? - + Continue जारी रखना - + Cancel रद्द करना - + Logs have been cleaned up लॉग साफ़ कर दिए गए हैं - + + Client logs + + + + + AmneziaVPN logs + + + + + + Open logs folder + + + + + + Export logs + + + + + Service logs + + + + + AmneziaVPN-service logs + + + + Clear logs लॉग साफ़ करें @@ -1954,12 +2132,11 @@ Already installed containers were found on the server. All installed containers समायोजन - Clear %1 profile - %1 प्रोफ़ाइल साफ़ करें + %1 प्रोफ़ाइल साफ़ करें - + Clear %1 profile? %1 प्रोफ़ाइल साफ़ करें? @@ -1969,39 +2146,64 @@ Already installed containers were found on the server. All installed containers - + Unable to clear %1 profile while there is an active connection सक्रिय कनेक्शन होने पर %1 प्रोफ़ाइल साफ़ करने में असमर्थ - + Remove निकालना - + All users with whom you shared a connection will no longer be able to connect to it. वे सभी उपयोगकर्ता जिनके साथ आपने कनेक्शन साझा किया था, वे अब इससे कनेक्ट नहीं हो पाएंगे. - + Cannot remove active container सक्रिय कंटेनर को हटाया नहीं जा सकता - + Remove %1 from server? सर्वर से %1 हटाएँ? - - + + connection settings + + + + + Click the "connect" button to create a connection configuration + + + + + server settings + + + + + Clear profile + + + + + The connection configuration will be deleted for this device only + + + + + Continue जारी रखना - - + + Cancel रद्द करना @@ -2185,82 +2387,92 @@ Already installed containers were found on the server. All installed containers कनेक्शन - + + Settings + समायोजन + + + + Enable logs + + + + Insert the key, add a configuration file or scan the QR-code - + Insert key - + Insert डालना - + Continue जारी रखना - + Other connection options - + VPN by Amnezia - + Connect to classic paid and free VPN services from Amnezia - + Self-hosted VPN - + Configure Amnezia VPN on your own server - + Restore from backup बैकअप से बहाल करना - + Open backup file बैकअप फ़ाइल खोलें - + Backup files (*.backup) बैकअप फ़ाइलें (*.backup) - + File with connection settings कनेक्शन सेटिंग्स वाली फ़ाइल - + Open config file कॉन्फ़िग फ़ाइल खोलें - + QR code क्यू आर संहिता - + I have nothing मेरे पास कुछ नहीं है @@ -2432,7 +2644,7 @@ Already installed containers were found on the server. All installed containers स्थापित करना - + The port must be in the range of 1 to 65535 @@ -2804,12 +3016,17 @@ Already installed containers were found on the server. All installed containers शेयर करना - + + Access error! + प्रवेश त्रुटि! + + + Connection to के लिए कनेक्शन - + File with connection settings to कनेक्शन सेटिंग्स वाली फ़ाइल @@ -2826,6 +3043,11 @@ Already installed containers were found on the server. All installed containers Settings restored from backup file बैकअप फ़ाइल से सेटिंग्स पुनर्स्थापित की गईं + + + Logging is enabled. Note that logs will be automaticallydisabled after 14 days, and all log files will be deleted. + + PopupType @@ -2864,12 +3086,12 @@ Already installed containers were found on the server. All installed containers पासवर्ड नहीं मिला - + Could not open keystore कीस्टोर नहीं खुल सका - + Could not remove private key from keystore कीस्टोर से निजी कुंजी नहीं हटाई जा सकी @@ -3045,27 +3267,27 @@ Already installed containers were found on the server. All installed containers कीस्टोर नहीं खुल सका - + Could not create private key generator निजी कुंजी जेनरेटर नहीं बनाया जा सका - + Could not generate new private key नई निजी कुंजी उत्पन्न नहीं हो सकी - + Could not retrieve private key from keystore कीस्टोर से निजी कुंजी पुनर्प्राप्त नहीं की जा सकी - + Could not create encryption cipher एन्क्रिप्शन सिफर नहीं बनाया जा सका - + Could not encrypt data डेटा एन्क्रिप्ट नहीं किया जा सका @@ -3763,12 +3985,12 @@ While it offers a blend of security, stability, and speed, it's essential t SettingsController - + Backup file is corrupted बैकअप फ़ाइल दूषित है - + All settings have been reset to default values सभी सेटिंग्स को डिफ़ॉल्ट मानों पर रीसेट कर दिया गया है @@ -3900,7 +4122,7 @@ While it offers a blend of security, stability, and speed, it's essential t VpnConnection - + Mbps diff --git a/client/translations/amneziavpn_my_MM.ts b/client/translations/amneziavpn_my_MM.ts index 473c97f8..3e964cc9 100644 --- a/client/translations/amneziavpn_my_MM.ts +++ b/client/translations/amneziavpn_my_MM.ts @@ -4,47 +4,52 @@ ApiServicesModel - + Classic VPN for comfortable work, downloading large files and watching videos. Works for any sites. Speed up to %1 MBit/s သက်တောင့်သက်သာအလုပ်လုပ်နိုင်ဖို့အတွက်နှင့် ကြီးမားသောဖိုင်များကိုဒေါင်းလုဒ်လုပ်ခြင်းနှင့် ဗီဒီယိုများကြည့်ရှုခြင်းတို့အတွက် အသုံးပြုနိုင်သော VPN ဖြစ်ပါတယ်။ မည်သည့်ဆိုက်များအတွက်မဆိုအလုပ်လုပ်ပြီး လိုင်းအရှိန် %1 MBit/s အထိအသုံးပြုနိုင်ပါတယ်။ - + VPN to access blocked sites in regions with high levels of Internet censorship. အင်တာနက် ဆင်ဆာဖြတ်တောက်မှု မြင့်မားသော ဒေသများရှိ ပိတ်ဆို့ထားသော ဆိုက်များကို ဝင်ရောက်ရန် VPN။. - + + <p><a style="color: #EB5757;">Not available in your region. If you have VPN enabled, disable it, return to the previous screen, and try again.</a> + + + + Amnezia Premium - A classic VPN for comfortable work, downloading large files, and watching videos in high resolution. It works for all websites, even in countries with the highest level of internet censorship. Amnezia Premium - သက်တောင့်သက်သာအလုပ်လုပ်နိုင်ဖို့အတွက်နှင့် ကြီးမားသောဖိုင်များကိုဒေါင်းလုဒ်လုပ်ခြင်းနှင့် ဗီဒီယိုများကိုကြည်လင်ပြတ်သားစွာကြည့်ရှုခြင်းတို့အတွက် အသုံးပြုနိုင်သော VPN ဖြစ်ပါတယ်။ အင်တာနက်ဆင်ဆာဖြတ်မှု အဆင့်အမြင့်ဆုံးနိုင်ငံများတွင်ပင် မည်သည့်ဆိုက်များအတွက်မဆို အလုပ်လုပ်ပါသည်။. - + Amnezia Free is a free VPN to bypass blocking in countries with high levels of internet censorship Amnezia Free သည် အင်တာနက်ဆင်ဆာဖြတ်တောက်မှု မြင့်မားသောနိုင်ငံများတွင် ပိတ်ဆို့ခြင်းကို ကျော်ဖြတ်ရန်အတွက် အခမဲ့ VPN တစ်ခုဖြစ်ပါသည်။ - + %1 MBit/s %1 MBit/s - + %1 days %1 ရက် - + VPN will open only popular sites blocked in your region, such as Instagram, Facebook, Twitter and others. Other sites will be opened from your real IP address, <a href="%1/free" style="color: #FBB26A;">more details on the website.</a> ဤ VPN သည် သင့်ဒေသရှိ Instagram၊ Facebook၊ Twitter နှင့် အခြားသော လူကြိုက်များသော ဆိုက်များကိုသာ ဖွင့်ပေးပါမည်။ အခြားဝဘ်ဆိုက်များကိုမူ သင်၏ IP လိပ်စာအစစ်အမှန်ဖြင့်သာ ဖွင့်ပေးပါမည်၊ <a href="%1/free" style="color: #FBB26A;">နောက်ထပ်အသေးစိတ်အချက်အလက်များကို ဝဘ်ဆိုဒ်ပေါ်တွင်ကြည့်ရန်</a> - + Free အခမဲ့ - + %1 $/month %1 $/တစ်လ @@ -75,7 +80,7 @@ ConnectButton - + Unable to disconnect during configuration preparation Configuration ပြင်ဆင်ခြင်းလုပ်ဆောင်နေချိန်အတွင်း ချိတ်ဆက်မှုဖြတ်တောက်၍မရပါ @@ -187,9 +192,8 @@ ExportController - Access error! - အသုံးပြုခွင့်တွင်အမှားပါနေပါသည်! + အသုံးပြုခွင့်တွင်အမှားပါနေပါသည်! @@ -255,18 +259,18 @@ Can't be disabled for current server ဖိုင်ကိုဖွင့်၍မရပါ - - + + Invalid configuration file Configuration ဖိုင် မမှန်ကန်ပါ - + Scanned %1 of %2. %2 ၏ %1 ကို စကင်န်ဖတ်ထားသည်. - + In the imported configuration, potentially dangerous lines were found: တင်သွင်းသည့် configuration တွင်၊ အန္တရာယ်ရှိနိုင်သည့်စာလိုင်းများကို တွေ့ရှိခဲ့သည်: @@ -443,6 +447,11 @@ Already installed containers were found on the server. All installed containers Gateway endpoint Gateway အဆုံးမှတ် + + + Dev gateway environment + + PageHome @@ -477,10 +486,63 @@ Already installed containers were found on the server. All installed containers လက်ရှိချိတ်ဆက်မှုတစ်ခုရှိနေချိန်တွင် ဆာဗာကို ပြောင်းလဲ၍မရပါ + + PageProtocolAwgClientSettings + + + AmneziaWG settings + AmneziaWG ဆက်တင်များ + + + + MTU + MTU + + + + Server settings + + + + + Port + Port + + + + Save + သိမ်းဆည်းမည် + + + + Save settings? + ဆက်တင်များကို သိမ်းဆည်းမည်လား? + + + + Only the settings for this device will be changed + + + + + Continue + ဆက်လက်လုပ်ဆောင်မည် + + + + Cancel + ပယ်ဖျက်မည် + + + + Unable change settings while there is an active connection + လက်ရှိချိတ်ဆက်မှုတစ်ခုရှိနေချိန်တွင် ဆက်တင်များကို ပြောင်းလဲ၍မရပါ + + PageProtocolAwgSettings - + AmneziaWG settings AmneziaWG ဆက်တင်များ @@ -490,92 +552,91 @@ Already installed containers were found on the server. All installed containers Port - MTU - MTU + MTU - + All users with whom you shared a connection with will no longer be able to connect to it. သင်နှင့်အတူချိတ်ဆက်မှုတစ်ခုကို မျှဝေထားသည့် အသုံးပြုသူအားလုံး ချိတ်ဆက်နိုင်တော့မည်မဟုတ်ပါ. - + Save သိမ်းဆည်းမည် - + Jc - Junk packet count Jc - Junk packet အရေအတွက် - + Jmin - Junk packet minimum size Jmin - Junk packet အသေးငယ်ဆုံးလက်ခံနိုင်မှုအရွယ်အစား - + Jmax - Junk packet maximum size Jmax - Junk packet အကြီးဆုံးလက်ခံနိုင်မှုအရွယ်အစား - + S1 - Init packet junk size S1 - Init packet junk အရွယ်အစား - + S2 - Response packet junk size S2 - Response packet junk အရွယ်အစား - + H1 - Init packet magic header H1 - Init packet magic header - + H2 - Response packet magic header H2 - Response packet magic header - + H4 - Transport packet magic header H4 - Transport packet magic header - + H3 - Underload packet magic header H3 - Underload packet magic header - + The values of the H1-H4 fields must be unique H1-H4 အကွက်များ၏ တန်ဖိုးများသည် အခြားတန်ဖိုးများနှင့်မတူ တမူထူးခြားနေရပါမည် - + The value of the field S1 + message initiation size (148) must not equal S2 + message response size (92) အကွက် S1 + မက်ဆေ့ချ် စတင်ခြင်း အရွယ်အစား (148) ၏ တန်ဖိုးသည် S2 + မက်ဆေ့ချ် တုံ့ပြန်မှု အရွယ်အစား (92) နှင့် မညီမျှရပါ - + Save settings? ဆက်တင်များကို သိမ်းဆည်းမည်လား? - + Continue ဆက်လက်လုပ်ဆောင်မည် - + Cancel ပယ်ဖျက်မည် - + Unable change settings while there is an active connection လက်ရှိချိတ်ဆက်မှုတစ်ခုရှိနေချိန်တွင် ဆက်တင်များကို ပြောင်းလဲ၍မရပါ @@ -862,30 +923,102 @@ Already installed containers were found on the server. All installed containers လက်ရှိချိတ်ဆက်မှုတစ်ခုရှိနေချိန်တွင် ဆက်တင်များကို ပြောင်းလဲ၍မရပါ + + PageProtocolWireGuardClientSettings + + + WG settings + WG ဆက်တင်များ + + + + MTU + MTU + + + + Server settings + + + + + Port + Port + + + + Save + သိမ်းဆည်းမည် + + + + Save settings? + ဆက်တင်များကို သိမ်းဆည်းမည်လား? + + + + Only the settings for this device will be changed + + + + + Continue + ဆက်လက်လုပ်ဆောင်မည် + + + + Cancel + ပယ်ဖျက်မည် + + + + Unable change settings while there is an active connection + လက်ရှိချိတ်ဆက်မှုတစ်ခုရှိနေချိန်တွင် ဆက်တင်များကို ပြောင်းလဲ၍မရပါ + + PageProtocolWireGuardSettings - + WG settings WG ဆက်တင်များ - + Port Port - - MTU - MTU + + Save settings? + ဆက်တင်များကို သိမ်းဆည်းမည်လား? - + + All users with whom you shared a connection with will no longer be able to connect to it. + သင်နှင့်အတူချိတ်ဆက်မှုတစ်ခုကို မျှဝေထားသည့် အသုံးပြုသူအားလုံး ချိတ်ဆက်နိုင်တော့မည်မဟုတ်ပါ. + + + + Continue + ဆက်လက်လုပ်ဆောင်မည် + + + + Cancel + ပယ်ဖျက်မည် + + + MTU + MTU + + + Unable change settings while there is an active connection လက်ရှိချိတ်ဆက်မှုတစ်ခုရှိနေချိန်တွင် ဆက်တင်များကို ပြောင်းလဲ၍မရပါ - + Save သိမ်းဆည်းမည် @@ -1205,9 +1338,13 @@ Already installed containers were found on the server. All installed containers https://t.me/amnezia_vpn - Mail - မေးလ် + မေးလ် + + + + support@amnezia.org + @@ -1215,32 +1352,37 @@ Already installed containers were found on the server. All installed containers သုံးသပ်ချက်များနှင့် ချွတ်ယွင်းချက်အစီရင်ခံစာများအတွက် - + + Copied + ကူးယူပြီးပါပြီ + + + GitHub GitHub - + https://github.com/amnezia-vpn/amnezia-client https://github.com/amnezia-vpn/amnezia-client - + Website ဝဘ်ဆိုက် - + Software version: %1 ဆော့ဖ်ဝဲဗားရှင်း: %1 - + Check for updates အပ်ဒိတ်များရှိမရှိ စစ်ဆေးမည် - + Privacy Policy ကိုယ်ရေးအချက်အလက်မူဝါဒ @@ -1689,73 +1831,109 @@ Already installed containers were found on the server. All installed containers PageSettingsLogging - Logging is enabled. Note that logs will be automatically disabled after 14 days, and all log files will be deleted. - Logging ကို ဖွင့်ထားသည်။ မှတ်တမ်းများကို ၁၄ ရက်အကြာတွင် အလိုအလျောက်ပိတ်ထားမည်ဖြစ်ပြီး မှတ်တမ်းဖိုင်များအားလုံး ပျက်သွားမည်ဖြစ်ကြောင်း သတိပြုပါ။. + Logging ကို ဖွင့်ထားသည်။ မှတ်တမ်းများကို ၁၄ ရက်အကြာတွင် အလိုအလျောက်ပိတ်ထားမည်ဖြစ်ပြီး မှတ်တမ်းဖိုင်များအားလုံး ပျက်သွားမည်ဖြစ်ကြောင်း သတိပြုပါ။. - + Logging Logging - + Enabling this function will save application's logs automatically. By default, logging functionality is disabled. Enable log saving in case of application malfunction. ဤလုပ်ဆောင်ချက်ကို ဖွင့်ခြင်းဖြင့် အပလီကေးရှင်း၏ မှတ်တမ်းများကို အလိုအလျောက် သိမ်းဆည်းပေးမည် ဖြစ်သည်။ ပုံမှန်အတိုင်းဆိုလျှင် Logging လုပ်ဆောင်ချက်ကို ပိတ်ထားမည်ဖြစ်သည်။ အပလီကေးရှင်းချို့ယွင်းချက်ရှိခဲ့ပါသော် မှတ်တမ်းကိုပြန်လည်ကြည့်ရှုနိုင်ရန် မှတ်တမ်းသိမ်းဆည်းမှုကို ဖွင့်ထားလိုက်ပါ။. - Save logs - မှတ်တမ်းများကိုသိမ်းဆည်းမည် + မှတ်တမ်းများကိုသိမ်းဆည်းမည် - Open folder with logs - မှတ်တမ်းများရှိသောဖိုင်တွဲကိုဖွင့်မည် + မှတ်တမ်းများရှိသောဖိုင်တွဲကိုဖွင့်မည် - + + Save သိမ်းဆည်းမည် - + + Logs files (*.log) မှတ်တမ်းဖိုင်များ (*.log) မှတ်တမ်းဖိုင်များ (*.log) - + + Logs file saved မှတ်တမ်းဖိုင်များသိမ်းဆည်းပြီးပါပြီ - Save logs to file - မှတ်တမ်းများကို ဖိုင်တွင်သိမ်းဆည်းမည် + မှတ်တမ်းများကို ဖိုင်တွင်သိမ်းဆည်းမည် - + + Enable logs + + + + Clear logs? မှတ်တမ်းများရှင်းလင်းမည်လား? - + Continue ဆက်လက်လုပ်ဆောင်မည် - + Cancel ပယ်ဖျက်မည် - + Logs have been cleaned up မှတ်တမ်းများကို ရှင်းလင်းပြီးပါပြီ - + + Client logs + + + + + AmneziaVPN logs + + + + + + Open logs folder + + + + + + Export logs + + + + + Service logs + + + + + AmneziaVPN-service logs + + + + Clear logs မှတ်တမ်းများရှင်းလင်းမည် @@ -1915,12 +2093,11 @@ Already installed containers were found on the server. All installed containers ဆက်တင်များ - Clear %1 profile - %1 ပရိုဖိုင်ကို ရှင်းလင်းမည် + %1 ပရိုဖိုင်ကို ရှင်းလင်းမည် - + Clear %1 profile? %1 ပရိုဖိုင်ကို ရှင်းလင်းမည်လား? @@ -1930,39 +2107,64 @@ Already installed containers were found on the server. All installed containers - + Unable to clear %1 profile while there is an active connection လက်ရှိချိတ်ဆက်မှုတစ်ခုရှိနေချိန်တွင် %1 ပရိုဖိုင်ကို ရှင်းလင်း၍မရပါ - + Remove ဖယ်ရှားမည် - + Remove %1 from server? %1 ကို ဆာဗာမှ ဖယ်ရှားမည်လား? - + All users with whom you shared a connection will no longer be able to connect to it. သင်နှင့်အတူချိတ်ဆက်မှုတစ်ခုကို မျှဝေထားသည့် အသုံးပြုသူအားလုံး ဤချိတ်ဆက်မှုကိုချိတ်ဆက်နိုင်တော့မည်မဟုတ်ပါ. - + Cannot remove active container Active container ကိုဖယ်ရှား၍မရပါ - - + + Continue ဆက်လက်လုပ်ဆောင်မည် - - + + connection settings + + + + + Click the "connect" button to create a connection configuration + + + + + server settings + + + + + Clear profile + + + + + The connection configuration will be deleted for this device only + + + + + Cancel ပယ်ဖျက်မည် @@ -2125,7 +2327,7 @@ Already installed containers were found on the server. All installed containers PageSetupWizardConfigSource - + File with connection settings ချိတ်ဆက်မှုဆက်တင်များပါဝင်သောဖိုင် @@ -2135,77 +2337,87 @@ Already installed containers were found on the server. All installed containers ချိတ်ဆက်မှု - + + Settings + ဆက်တင်များ + + + + Enable logs + + + + Insert the key, add a configuration file or scan the QR-code Key ကိုထည့်မည်၊ ဖွဲ့စည်းမှုဖိုင်တစ်ခုကိုထည့်မည် သို့မဟုတ် QR-ကုဒ်ကို စကင်န်ဖတ်မည် - + Insert key Key ကိုထည့်သွင်းမည် - + Insert ထည့်သွင်းမည် - + Continue ဆက်လက်လုပ်ဆောင်မည် - + Other connection options အခြားချိတ်ဆက်မှုရွေးချယ်စရာများ - + VPN by Amnezia Amnezia မှ VPN - + Connect to classic paid and free VPN services from Amnezia Amnezia မှ အခပေးနှင့် အခမဲ့ မူလ VPN ဝန်ဆောင်မှုများသို့ ချိတ်ဆက်မည် - + Self-hosted VPN ကိုယ်တိုင် host လုပ်ထားသော VPN - + Configure Amnezia VPN on your own server Amnezia VPN ကို သင်၏ကိုယ်ပိုင်ဆာဗာပေါ်တွင် စီစဥ်ချိန်ညှိမည် - + Restore from backup အရံဖိုင်မှ ပြန်လည်ရယူမည် - + Open backup file အရံဖိုင်ကို ဖွင့်မည် - + Backup files (*.backup) အရံဖိုင်များ (*.backup) - + Open config file config ဖိုင်ကိုဖွင့်မည် - + QR code QR-ကုဒ် - + I have nothing ကျွန်ုပ်တွင်ဘာမှမရှိပါ @@ -2717,12 +2929,17 @@ Already installed containers were found on the server. All installed containers မျှဝေမည် - + + Access error! + အသုံးပြုခွင့်တွင်အမှားပါနေပါသည်! + + + Connection to ဤဆာဗာသို့ချိတ်ဆက်မှု - + File with connection settings to ဤဆာဗာနှင့်ချိတ်ဆက်မှု ဆက်တင်များပါရှိသော ဖိုင် @@ -2739,6 +2956,11 @@ Already installed containers were found on the server. All installed containers Settings restored from backup file ဆက်တင်များကို အရံဖိုင်မှ ပြန်လည်ရယူပြီးပါပြီ + + + Logging is enabled. Note that logs will be automaticallydisabled after 14 days, and all log files will be deleted. + + PopupType @@ -2777,12 +2999,12 @@ Already installed containers were found on the server. All installed containers စကားဝှက်ကို ရှာမတွေ့ပါ - + Could not open keystore keystore ကို ဖွင့်၍မရပါ - + Could not remove private key from keystore Key store မှ ကိုယ်ပိုင် key ကို ဖယ်ရှား၍မရပါ @@ -2958,27 +3180,27 @@ Already installed containers were found on the server. All installed containers keystore ကို ဖွင့်၍မရပါ - + Could not create private key generator ကိုယ်ပိုင် key ဖန်တီးမှုစက်ကိုမဖန်တီးနိုင်ပါ - + Could not generate new private key ကိုယ်ပိုင် key အသစ် မထုတ်ပေးနိုင်ပါ - + Could not retrieve private key from keystore Key store မှ ကိုယ်ပိုင် key ကို ထုတ်ယူ၍မရပါ - + Could not create encryption cipher ကုတ်ဝှက်ဖြည်ခြင်းဖန်တီး၍မရပါ - + Could not encrypt data ဒေတာကို ကုတ်ဝှက်၍မရပါ @@ -3672,12 +3894,12 @@ For more detailed information, you can SettingsController - + All settings have been reset to default values ဆက်တင်အားလုံးကို မူရင်းတန်ဖိုးများအဖြစ် ပြန်လည်သတ်မှတ်ထားသည် - + Backup file is corrupted အရံဖိုင်ပျက်ဆီးနေသည် @@ -3809,7 +4031,7 @@ For more detailed information, you can VpnConnection - + Mbps Mbps diff --git a/client/translations/amneziavpn_ru_RU.ts b/client/translations/amneziavpn_ru_RU.ts index f616c3ae..2fb21259 100644 --- a/client/translations/amneziavpn_ru_RU.ts +++ b/client/translations/amneziavpn_ru_RU.ts @@ -4,47 +4,52 @@ ApiServicesModel - + Classic VPN for comfortable work, downloading large files and watching videos. Works for any sites. Speed up to %1 MBit/s Классический VPN для комфортной работы, загрузки больших файлов и просмотра видео. Работает для любых сайтов. Скорость до %1 Мбит/с - + VPN to access blocked sites in regions with high levels of Internet censorship. VPN для доступа к заблокированным сайтам в регионах с высоким уровнем интернет-цензуры. - + + <p><a style="color: #EB5757;">Not available in your region. If you have VPN enabled, disable it, return to the previous screen, and try again.</a> + + + + Amnezia Premium - A classic VPN for comfortable work, downloading large files, and watching videos in high resolution. It works for all websites, even in countries with the highest level of internet censorship. Amnezia Premium — классический VPN для комфортной работы, загрузки больших файлов и просмотра видео в высоком разрешении. Работает на всех сайтах, даже в странах с самым высоким уровнем интернет-цензуры. - + Amnezia Free is a free VPN to bypass blocking in countries with high levels of internet censorship Amnezia Free - это бесплатный VPN для обхода блокировок в странах с высоким уровнем интернет-цензуры - + %1 MBit/s - + %1 days %1 дней - + VPN will open only popular sites blocked in your region, such as Instagram, Facebook, Twitter and others. Other sites will be opened from your real IP address, <a href="%1/free" style="color: #FBB26A;">more details on the website.</a> Через VPN будут открываться только популярные сайты, заблокированные в вашем регионе, такие как Instagram, Facebook, Twitter и другие. Остальные сайты будут открываться с вашего реального IP-адреса, <a href="%1/free" style="color: #FBB26A;">подробности на сайте.</a> - + Free Бесплатно - + %1 $/month %1 $/месяц @@ -75,7 +80,7 @@ ConnectButton - + Unable to disconnect during configuration preparation Невозможно отключиться во время подготовки конфигурации @@ -187,9 +192,8 @@ ExportController - Access error! - Ошибка доступа! + Ошибка доступа! @@ -259,18 +263,18 @@ Can't be disabled for current server Невозможно открыть файл - - + + Invalid configuration file Неверный файл конфигурации - + Scanned %1 of %2. Отсканировано %1 из %2. - + In the imported configuration, potentially dangerous lines were found: В импортированной конфигурации были обнаружены потенциально опасные строки: @@ -447,6 +451,11 @@ Already installed containers were found on the server. All installed containers Gateway endpoint + + + Dev gateway environment + + PageHome @@ -481,10 +490,63 @@ Already installed containers were found on the server. All installed containers Невозможно изменить сервер во время активного соединения + + PageProtocolAwgClientSettings + + + AmneziaWG settings + Настройки AmneziaWG + + + + MTU + MTU + + + + Server settings + + + + + Port + Порт + + + + Save + Сохранить + + + + Save settings? + Сохранить настройки? + + + + Only the settings for this device will be changed + + + + + Continue + Продолжить + + + + Cancel + Отменить + + + + Unable change settings while there is an active connection + Невозможно изменить настройки во время активного соединения + + PageProtocolAwgSettings - + AmneziaWG settings Настройки AmneziaWG @@ -494,9 +556,8 @@ Already installed containers were found on the server. All installed containers Порт - MTU - MTU + MTU Remove AmneziaWG @@ -507,87 +568,87 @@ Already installed containers were found on the server. All installed containers Удалить AmneziaWG с сервера? - + All users with whom you shared a connection with will no longer be able to connect to it. Все пользователи, с которыми вы поделились конфигурацией вашего VPN, больше не смогут к нему подключаться. - + Save Сохранить - + Jc - Junk packet count - + Jmin - Junk packet minimum size - + Jmax - Junk packet maximum size - + S1 - Init packet junk size - + S2 - Response packet junk size - + H1 - Init packet magic header - + H2 - Response packet magic header - + H4 - Transport packet magic header - + H3 - Underload packet magic header - + The values of the H1-H4 fields must be unique Значения в полях H1-H4 должны быть уникальными - + The value of the field S1 + message initiation size (148) must not equal S2 + message response size (92) Значение в поле S1 + размер инициации сообщения (148) не должно равняться значению в поле S2 + размер ответа на сообщение (92) - + Save settings? Сохранить настройки? - + Continue Продолжить - + Cancel Отменить - + Unable change settings while there is an active connection Невозможно изменить настройки во время активного соединения @@ -898,25 +959,87 @@ Already installed containers were found on the server. All installed containers Невозможно изменить настройки во время активного соединения + + PageProtocolWireGuardClientSettings + + + WG settings + Настройки WG + + + + MTU + MTU + + + + Server settings + + + + + Port + Порт + + + + Save + Сохранить + + + + Save settings? + Сохранить настройки? + + + + Only the settings for this device will be changed + + + + + Continue + Продолжить + + + + Cancel + Отменить + + + + Unable change settings while there is an active connection + Невозможно изменить настройки во время активного соединения + + PageProtocolWireGuardSettings - + WG settings Настройки WG - + Port Порт - - MTU - MTU + + Save settings? + Сохранить настройки? - + + All users with whom you shared a connection with will no longer be able to connect to it. + Все пользователи, с которыми вы поделились конфигурацией вашего VPN, больше не смогут к нему подключаться. + + + MTU + MTU + + + Unable change settings while there is an active connection Невозможно изменить настройки во время активного соединения @@ -933,15 +1056,17 @@ Already installed containers were found on the server. All installed containers Все пользователи, с которыми вы поделились конфигурацией вашего VPN, больше не смогут к нему подключаться. + Continue - Продолжить + Продолжить + Cancel - Отменить + Отменить - + Save Сохранить @@ -1305,8 +1430,12 @@ Already installed containers were found on the server. All installed containers + support@amnezia.org + + + Mail - Почта + Почта @@ -1314,17 +1443,22 @@ Already installed containers were found on the server. All installed containers Для отзывов и сообщений об ошибках - + + Copied + Скопировано + + + GitHub GitHub - + https://github.com/amnezia-vpn/amnezia-client https://github.com/amnezia-vpn/amnezia-client - + Website Веб-сайт @@ -1333,17 +1467,17 @@ Already installed containers were found on the server. All installed containers https://amnezia.org - + Software version: %1 Версия ПО: %1 - + Check for updates Проверить обновления - + Privacy Policy Политика конфиденциальности @@ -1816,72 +1950,108 @@ Already installed containers were found on the server. All installed containers PageSettingsLogging - Logging is enabled. Note that logs will be automatically disabled after 14 days, and all log files will be deleted. - Логирование включено. Обратите внимание, что логирование будет автоматически отключено через 14 дней, и все логи будут удалены. + Логирование включено. Обратите внимание, что логирование будет автоматически отключено через 14 дней, и все логи будут удалены. - + Logging Логирование - + Enabling this function will save application's logs automatically. By default, logging functionality is disabled. Enable log saving in case of application malfunction. Включение этой функции позволяет сохранять логи на вашем устройстве. По умолчанию она отключена. Включите сохранение логов в случае сбоев в работе приложения. - Save logs - Сохранять логи + Сохранять логи - Open folder with logs - Открыть папку с логами + Открыть папку с логами - + + Save Сохранить - + + Logs files (*.log) Файлы логов (*.log) - + + Logs file saved Файл с логами сохранен - Save logs to file - Сохранить логи в файл + Сохранить логи в файл - + + Enable logs + + + + Clear logs? Очистить логи? - + Continue Продолжить - + Cancel Отменить - + Logs have been cleaned up Логи очищены - + + Client logs + + + + + AmneziaVPN logs + + + + + + Open logs folder + + + + + + Export logs + + + + + Service logs + + + + + AmneziaVPN-service logs + + + + Clear logs Очистить логи @@ -2069,12 +2239,11 @@ Already installed containers were found on the server. All installed containers настройки - Clear %1 profile - Очистить профиль %1 + Очистить профиль %1 - + Clear %1 profile? Очистить профиль %1? @@ -2084,27 +2253,52 @@ Already installed containers were found on the server. All installed containers - + + connection settings + + + + + Click the "connect" button to create a connection configuration + + + + + server settings + + + + + Clear profile + + + + + The connection configuration will be deleted for this device only + + + + Unable to clear %1 profile while there is an active connection Невозможно очистить профиль %1 во время активного соединения - + Remove Удалить - + Remove %1 from server? Удалить %1 с сервера? - + All users with whom you shared a connection will no longer be able to connect to it. Все пользователи, с которыми вы поделились конфигурацией вашего VPN, больше не смогут к нему подключаться. - + Cannot remove active container Невозможно удалить активный контейнер @@ -2113,14 +2307,14 @@ Already installed containers were found on the server. All installed containers Все пользователи, с которыми вы поделились VPN, больше не смогут к нему подключаться. - - + + Continue Продолжить - - + + Cancel Отменить @@ -2311,7 +2505,7 @@ It's okay as long as it's from someone you trust. Что у вас есть? - + File with connection settings Файл с настройками подключения @@ -2325,77 +2519,87 @@ It's okay as long as it's from someone you trust. Соединение - + + Settings + Настройки + + + + Enable logs + + + + Insert the key, add a configuration file or scan the QR-code Вставьте ключ, добавьте файл конфигурации или отсканируйте QR-код - + Insert key Вставьте ключ - + Insert Вставить - + Continue Продолжить - + Other connection options Другие варианты подключения - + VPN by Amnezia VPN от Amnezia - + Connect to classic paid and free VPN services from Amnezia Подключайтесь к классическим платным и бесплатным VPN-сервисам от Amnezia - + Self-hosted VPN Self-hosted VPN - + Configure Amnezia VPN on your own server Настроить VPN на собственном сервере - + Restore from backup Восстановить из резервной копии - + Open backup file Открыть резервную копию - + Backup files (*.backup) Файлы резервных копий (*.backup) - + Open config file Открыть файл с конфигурацией - + QR code QR-код - + I have nothing У меня ничего нет @@ -2600,7 +2804,7 @@ and will not be shared or disclosed to the Amnezia or any third parties Установить - + The port must be in the range of 1 to 65535 Порт должен быть в диапазоне от 1 до 65535 @@ -2996,12 +3200,17 @@ and will not be shared or disclosed to the Amnezia or any third parties Поделиться - + + Access error! + Ошибка доступа! + + + Connection to Подключение к - + File with connection settings to Файл с настройками подключения к @@ -3018,6 +3227,11 @@ and will not be shared or disclosed to the Amnezia or any third parties Settings restored from backup file Настройки восстановлены из бэкап файла + + + Logging is enabled. Note that logs will be automaticallydisabled after 14 days, and all log files will be deleted. + + PopupType @@ -3056,12 +3270,12 @@ and will not be shared or disclosed to the Amnezia or any third parties Пароль не найден - + Could not open keystore Не удалось открыть хранилище ключей - + Could not remove private key from keystore Не удалось удалить закрытый ключ из хранилища ключей @@ -3237,27 +3451,27 @@ and will not be shared or disclosed to the Amnezia or any third parties Не удалось открыть хранилище ключей - + Could not create private key generator Не удалось создать генератор закрытых ключей - + Could not generate new private key Не удалось сгенерировать новый закрытый ключ - + Could not retrieve private key from keystore Не удалось получить закрытый ключ из хранилища ключей - + Could not create encryption cipher Не удалось создать шифр шифрования - + Could not encrypt data Не удалось зашифровать данные @@ -4094,7 +4308,7 @@ This means that AmneziaWG keeps the fast performance of the original while addin SettingsController - + All settings have been reset to default values Все настройки сброшены до значений по умолчанию @@ -4103,7 +4317,7 @@ This means that AmneziaWG keeps the fast performance of the original while addin Закэшированные профили очищены - + Backup file is corrupted Файл резервной копии поврежден @@ -4235,7 +4449,7 @@ This means that AmneziaWG keeps the fast performance of the original while addin VpnConnection - + Mbps Мбит/с diff --git a/client/translations/amneziavpn_uk_UA.ts b/client/translations/amneziavpn_uk_UA.ts index 11377c4d..c7195119 100644 --- a/client/translations/amneziavpn_uk_UA.ts +++ b/client/translations/amneziavpn_uk_UA.ts @@ -27,47 +27,52 @@ ApiServicesModel - + Classic VPN for comfortable work, downloading large files and watching videos. Works for any sites. Speed up to %1 MBit/s Звичайний VPN для комфортної роботи, завантаження великих файлів та перегляду відео. Працює для будь-яких сайтів. Швидкість до %1 MBit/s - + VPN to access blocked sites in regions with high levels of Internet censorship. VPN для доступу до заблокованих сайтів у регіонах з високим рівнем інтернет-цензури. - + + <p><a style="color: #EB5757;">Not available in your region. If you have VPN enabled, disable it, return to the previous screen, and try again.</a> + + + + Amnezia Premium - A classic VPN for comfortable work, downloading large files, and watching videos in high resolution. It works for all websites, even in countries with the highest level of internet censorship. Amnezia Premium - звичайний VPN для комфортної роботи, завантаження великих файлів та перегляду відео у високій роздільній здатності. Працює для всіх вебсайтів, навіть у країнах з найвищим рівнем інтернет-цензури. - + Amnezia Free is a free VPN to bypass blocking in countries with high levels of internet censorship Amnezia Free — це безкоштовний VPN для обходу блокувань у країнах з високим рівнем інтернет-цензури - + %1 MBit/s %1 MBit/s - + %1 days %1 днів - + VPN will open only popular sites blocked in your region, such as Instagram, Facebook, Twitter and others. Other sites will be opened from your real IP address, <a href="%1/free" style="color: #FBB26A;">more details on the website.</a> Лише популярні сайти, які заблоковані у вашому регіоні, будуть відкриватись за допомогою VPN підключення (Instagram, Facebook, Twitter та ін.). Звичайні сайти будуть відкриватися без використання VPN, <a href="%1/free" style="color: #FBB26A;">більш детально на нашому сайті.</a> - + Free Безкоштовно - + %1 $/month %1 $/місяць @@ -98,7 +103,7 @@ ConnectButton - + Unable to disconnect during configuration preparation Неможливо відключитися під час підготовки конфігурації @@ -210,9 +215,8 @@ ExportController - Access error! - Помилка доступу! + Помилка доступу! @@ -286,18 +290,18 @@ Can't be disabled for current server Неможливо відкрити файл - - + + Invalid configuration file Недійсний файл конфігурації - + Scanned %1 of %2. Відскановано %1 з %2. - + In the imported configuration, potentially dangerous lines were found: У імпортованій конфігурації знайдено потенційно небезпечні рядки: @@ -400,7 +404,7 @@ Already installed containers were found on the server. All installed containers application name назва застосунку - + Add selected Додати вибране @@ -473,6 +477,11 @@ Already installed containers were found on the server. All installed containers Gateway endpoint + + + Dev gateway environment + + PageHome @@ -507,10 +516,63 @@ Already installed containers were found on the server. All installed containers Не можна змінити сервер при активному підключенні + + PageProtocolAwgClientSettings + + + AmneziaWG settings + налаштування AmneziaWG + + + + MTU + MTU + + + + Server settings + + + + + Port + Порт + + + + Save + Зберегти + + + + Save settings? + Зберегти налаштування? + + + + Only the settings for this device will be changed + + + + + Continue + Продовжити + + + + Cancel + Відмінити + + + + Unable change settings while there is an active connection + Неможливо змінити налаштування, поки є активне підключення + + PageProtocolAwgSettings - + AmneziaWG settings налаштування AmneziaWG @@ -521,81 +583,76 @@ Already installed containers were found on the server. All installed containers - MTU - - - - Jc - Junk packet count - + Jmin - Junk packet minimum size - + Jmax - Junk packet maximum size - + S1 - Init packet junk size - + S2 - Response packet junk size - + H1 - Init packet magic header - + H2 - Response packet magic header - + H4 - Transport packet magic header - + H3 - Underload packet magic header - + Save Зберегти - + The values of the H1-H4 fields must be unique Значення полів H1-H4 мають бути унікальними - + The value of the field S1 + message initiation size (148) must not equal S2 + message response size (92) Значення поля S1 + розмір повідомлення ініціалізації (148) не має бути рівним значенню S2 + розмір повідомлення відповіді (92) - + Save settings? Зберегти налаштування? - + All users with whom you shared a connection with will no longer be able to connect to it. Усі користувачі, з якими ви поділилися підключенням, більше не зможуть підключитися до нього. - + Unable change settings while there is an active connection Неможливо змінити налаштування, поки є активне підключення @@ -616,12 +673,12 @@ Already installed containers were found on the server. All installed containers Користувачі, з якими ви поділились цим протоколм, більше не зможуть до нього підключитись. - + Continue Продовжити - + Cancel Відмінити @@ -960,30 +1017,102 @@ Already installed containers were found on the server. All installed containers Зберегти і перезавантажити + + PageProtocolWireGuardClientSettings + + + WG settings + + + + + MTU + MTU + + + + Server settings + + + + + Port + Порт + + + + Save + Зберегти + + + + Save settings? + Зберегти налаштування? + + + + Only the settings for this device will be changed + + + + + Continue + Продовжити + + + + Cancel + Відмінити + + + + Unable change settings while there is an active connection + Неможливо змінити налаштування, поки є активне підключення + + PageProtocolWireGuardSettings - + WG settings - + Port Порт - MTU - MTU + MTU - + Save Зберегти - + + Save settings? + Зберегти налаштування? + + + + All users with whom you shared a connection with will no longer be able to connect to it. + Усі користувачі, з якими ви поділилися підключенням, більше не зможуть підключитися до нього. + + + + Continue + Продовжити + + + + Cancel + Відмінити + + + Unable change settings while there is an active connection Неможливо змінити налаштування, поки є активне підключення @@ -1000,7 +1129,7 @@ Already installed containers were found on the server. All installed containers Disguised as traffic from Замаскувати трафік під - + Save Зберегти @@ -1375,8 +1504,12 @@ Already installed containers were found on the server. All installed containers + support@amnezia.org + + + Mail - Пошта + Пошта @@ -1384,17 +1517,22 @@ Already installed containers were found on the server. All installed containers Для відгуків і повідомлень про помилки - + + Copied + Скопійовано + + + GitHub GitHub - + https://github.com/amnezia-vpn/amnezia-client https://github.com/amnezia-vpn/amnezia-client - + Website Веб-сайт @@ -1403,17 +1541,17 @@ Already installed containers were found on the server. All installed containers https://amnezia.org - + Software version: %1 Версія ПЗ: %1 - + Check for updates Перевірити оновлення - + Privacy Policy Політика конфіденційності @@ -1604,7 +1742,7 @@ Already installed containers were found on the server. All installed containers Запускати застосунок в згорнутому вигляді - + Language Мова @@ -1886,72 +2024,108 @@ Already installed containers were found on the server. All installed containers PageSettingsLogging - Logging is enabled. Note that logs will be automatically disabled after 14 days, and all log files will be deleted. - Логування увімкнене. Зверніть увагу, що логування буде автоматично вимкнене через 14 днів, а всі файли журналів будуть видалені. + Логування увімкнене. Зверніть увагу, що логування буде автоматично вимкнене через 14 днів, а всі файли журналів будуть видалені. - + Logging Логування - + Enabling this function will save application's logs automatically. By default, logging functionality is disabled. Enable log saving in case of application malfunction. Увімкнення цієї функції автоматично зберігатиме журнали додатка. За замовчуванням функція логування вимкнена. Увімкніть збереження журналів у випадку збою додатка. - Save logs - Зберегти логи + Зберегти логи - Open folder with logs - Відкрити папку з логами + Відкрити папку з логами - + + Save Зберегти - + + Logs files (*.log) Logs files (*.log) - + + Logs file saved Файл з логами збережено - Save logs to file - Зберегти логи в файл + Зберегти логи в файл - + + Enable logs + + + + Clear logs? Очистити логи? - + Continue Продовжити - + Cancel Відмінити - + Logs have been cleaned up Логи видалено - + + Client logs + + + + + AmneziaVPN logs + + + + + + Open logs folder + + + + + + Export logs + + + + + Service logs + + + + + AmneziaVPN-service logs + + + + Clear logs Видалити логи @@ -2151,22 +2325,46 @@ Already installed containers were found on the server. All installed containers Налаштування - Clear %1 profile - Очистити профіль %1 + Очистити профіль %1 - + + connection settings + + + + + Click the "connect" button to create a connection configuration + + + + + server settings + + + + + Clear profile + + + + Clear %1 profile? Очистити профіль %1? - + + The connection configuration will be deleted for this device only + + + + Unable to clear %1 profile while there is an active connection Неможливо очистити профіль %1 під час активного підключення - + Cannot remove active container Неможливо видалити активний контейнер @@ -2176,17 +2374,17 @@ Already installed containers were found on the server. All installed containers - + Remove Видалити - + Remove %1 from server? Видалити %1 з сервера? - + All users with whom you shared a connection will no longer be able to connect to it. Користувачі, з якими ви поділились цим протоколм, більше не зможуть до нього підключитись. @@ -2195,14 +2393,14 @@ Already installed containers were found on the server. All installed containers Користувачі, з якими ви поділились цим протоколм, більше не зможуть до нього підключитись. - - + + Continue Продовжити - - + + Cancel Відмінити @@ -2393,7 +2591,7 @@ It's okay as long as it's from someone you trust. Виберіть що у вас є - + File with connection settings Файл з налаштуваннями підключення @@ -2407,77 +2605,87 @@ It's okay as long as it's from someone you trust. Підключення - + + Settings + Налаштування + + + + Enable logs + + + + Insert the key, add a configuration file or scan the QR-code Вставте ключ, додайте файл конфігурації або відскануйте QR-код - + Insert key Вставити ключ - + Insert Вставити - + Continue Продовжити - + Other connection options Інші параметри підключення - + VPN by Amnezia VPN від Amnezia - + Connect to classic paid and free VPN services from Amnezia Підключайтеся до звичайних платних та безкоштовних VPN-сервісів від Amnezia - + Self-hosted VPN Self-hosted VPN - + Configure Amnezia VPN on your own server Налаштуйте Amnezia VPN на власному сервері - + Restore from backup Відновити із бекапа - + Open backup file Відкрити бекап файл - + Backup files (*.backup) Файли резервної копії (*.backup) - + Open config file Відкрити файл з конфігурацією - + QR code QR-код - + I have nothing У мене нічого нема @@ -2691,7 +2899,7 @@ and will not be shared or disclosed to the Amnezia or any third parties Встановити - + The port must be in the range of 1 to 65535 Порт повинен бути в межах від 1 до 65535 @@ -3009,7 +3217,7 @@ and will not be shared or disclosed to the Amnezia or any third parties Користувач більше не зможе підключатись до вашого сервера - + Continue Продовжити @@ -3086,12 +3294,17 @@ and will not be shared or disclosed to the Amnezia or any third parties Поділитись - + + Access error! + Помилка доступу! + + + Connection to Підключення до - + File with connection settings to Файл з налаштуванням доступу до @@ -3108,6 +3321,11 @@ and will not be shared or disclosed to the Amnezia or any third parties Settings restored from backup file Відновлення налаштувань із бекап файлу + + + Logging is enabled. Note that logs will be automaticallydisabled after 14 days, and all log files will be deleted. + + PopupType @@ -3146,12 +3364,12 @@ and will not be shared or disclosed to the Amnezia or any third parties Пароль не знайдено - + Could not open keystore Could not open keystore - + Could not remove private key from keystore Could not remove private key from keystore @@ -3327,27 +3545,27 @@ and will not be shared or disclosed to the Amnezia or any third parties Could not open keystore - + Could not create private key generator Could not create private key generator - + Could not generate new private key Could not generate new private key - + Could not retrieve private key from keystore Could not retrieve private key from keystore - + Could not create encryption cipher Could not create encryption cipher - + Could not encrypt data Could not encrypt data @@ -4167,7 +4385,7 @@ This means that AmneziaWG keeps the fast performance of the original while addin SettingsController - + All settings have been reset to default values Всі налаштування були скинуті до значення "По замовчуванню" @@ -4176,7 +4394,7 @@ This means that AmneziaWG keeps the fast performance of the original while addin Кеш профілю очищено - + Backup file is corrupted Backup файл пошкодженно @@ -4308,7 +4526,7 @@ This means that AmneziaWG keeps the fast performance of the original while addin VpnConnection - + Mbps Mbps diff --git a/client/translations/amneziavpn_ur_PK.ts b/client/translations/amneziavpn_ur_PK.ts index b18d60e7..cf445bfa 100644 --- a/client/translations/amneziavpn_ur_PK.ts +++ b/client/translations/amneziavpn_ur_PK.ts @@ -4,47 +4,52 @@ ApiServicesModel - + Classic VPN for comfortable work, downloading large files and watching videos. Works for any sites. Speed up to %1 MBit/s - + VPN to access blocked sites in regions with high levels of Internet censorship. - + + <p><a style="color: #EB5757;">Not available in your region. If you have VPN enabled, disable it, return to the previous screen, and try again.</a> + + + + Amnezia Premium - A classic VPN for comfortable work, downloading large files, and watching videos in high resolution. It works for all websites, even in countries with the highest level of internet censorship. - + Amnezia Free is a free VPN to bypass blocking in countries with high levels of internet censorship - + %1 MBit/s - + %1 days - + VPN will open only popular sites blocked in your region, such as Instagram, Facebook, Twitter and others. Other sites will be opened from your real IP address, <a href="%1/free" style="color: #FBB26A;">more details on the website.</a> - + Free - + %1 $/month @@ -75,7 +80,7 @@ ConnectButton - + Unable to disconnect during configuration preparation تشکیل کی تیاری کے دوران منقطع ہونا ممکن نہیں ہے @@ -186,9 +191,8 @@ ExportController - Access error! - رساءی ناممکن! + رساءی ناممکن! @@ -253,18 +257,18 @@ Can't be disabled for current server فائل کو کھولنے سے قاصر ہے - - + + Invalid configuration file غلط کنفیگریشن فائل - + Scanned %1 of %2. سکین%1 کی%2. - + In the imported configuration, potentially dangerous lines were found: @@ -443,6 +447,11 @@ Already installed containers were found on the server. All installed containers Gateway endpoint + + + Dev gateway environment + + PageHome @@ -477,10 +486,63 @@ Already installed containers were found on the server. All installed containers فعال کنکشن موجود ہونے کی وجہ سے سرور تبدیل کرنے میں ناکام ہیں + + PageProtocolAwgClientSettings + + + AmneziaWG settings + امنیزیا وی جی کی ترتیبات + + + + MTU + ام ٹی یو + + + + Server settings + + + + + Port + پورٹ + + + + Save + + + + + Save settings? + ترتیبات محفوظ کریں? + + + + Only the settings for this device will be changed + + + + + Continue + + + + + Cancel + + + + + Unable change settings while there is an active connection + جب ایک فعال کنکشن موجود ہو تو ترتیبات کو تبدیل نہیں کیا جا سکتا + + PageProtocolAwgSettings - + AmneziaWG settings امنیزیا وی جی کی ترتیبات @@ -490,92 +552,91 @@ Already installed containers were found on the server. All installed containers پورٹ - MTU - ام ٹی یو + ام ٹی یو - + All users with whom you shared a connection with will no longer be able to connect to it. آپ جن لوگوں کے ساتھ آپ نے اس کنکشن کا اشتراک کیا تھا، وہ اس سے مزید جڑ نہیں سکیں گے۔ - + Save محفوظ کریں - + Jc - Junk packet count - + Jmin - Junk packet minimum size - + Jmax - Junk packet maximum size - + S1 - Init packet junk size - + S2 - Response packet junk size - + H1 - Init packet magic header - + H2 - Response packet magic header - + H4 - Transport packet magic header - + H3 - Underload packet magic header - + The values of the H1-H4 fields must be unique H1 تا H4 فیلڈز کی قیمتیں مخصوص ہونی چاہیے - + The value of the field S1 + message initiation size (148) must not equal S2 + message response size (92) S1 + پیغام شروع کار (148) کے فیلڈ کی قیمت S2 + پیغام جواب (92) کے سائز کے برابر نہیں ہونی چاہئے - + Save settings? ترتیبات محفوظ کریں? - + Continue جاری رکھیں - + Cancel منسوخ کریں - + Unable change settings while there is an active connection جب ایک فعال کنکشن موجود ہو تو ترتیبات کو تبدیل نہیں کیا جا سکتا @@ -862,30 +923,102 @@ Already installed containers were found on the server. All installed containers جب ایک فعال کنکشن موجود ہو تو ترتیبات کو تبدیل نہیں کیا جا سکتا + + PageProtocolWireGuardClientSettings + + + WG settings + وائر گارڈ ترتیبات + + + + MTU + ام ٹی یو + + + + Server settings + + + + + Port + پورٹ + + + + Save + + + + + Save settings? + ترتیبات محفوظ کریں? + + + + Only the settings for this device will be changed + + + + + Continue + + + + + Cancel + + + + + Unable change settings while there is an active connection + جب ایک فعال کنکشن موجود ہو تو ترتیبات کو تبدیل نہیں کیا جا سکتا + + PageProtocolWireGuardSettings - + WG settings وائر گارڈ ترتیبات - + Port پورٹ - - MTU - ام ٹی یو + + Save settings? + ترتیبات محفوظ کریں? - + + All users with whom you shared a connection with will no longer be able to connect to it. + + + + + Continue + + + + + Cancel + + + + MTU + ام ٹی یو + + + Unable change settings while there is an active connection جب ایک فعال کنکشن موجود ہو تو ترتیبات کو تبدیل نہیں کیا جا سکتا - + Save محفوظ کریں @@ -1241,9 +1374,13 @@ Already installed containers were found on the server. All installed containers - Mail - میل + میل + + + + support@amnezia.org + @@ -1251,32 +1388,37 @@ Already installed containers were found on the server. All installed containers جائزہ اور بگ رپورٹس کے لئے - + + Copied + + + + GitHub گِٹ ہَب - + https://github.com/amnezia-vpn/amnezia-client https://github.com/amnezia-vpn/amnezia-client - + Website ویب سائٹ - + Software version: %1 سافٹ ویئر ورژن: %1 - + Check for updates اپ ڈیٹس چیک کریں - + Privacy Policy رازداری کی پالیسی @@ -1733,72 +1875,108 @@ Already installed containers were found on the server. All installed containers PageSettingsLogging - Logging is enabled. Note that logs will be automatically disabled after 14 days, and all log files will be deleted. - لاگنگ فعال ہے۔ یاد رہے کہ لاگوں کو 14 دنوں کے بعد خود بخود غیر فعال کر دیا جائے گا، اور تمام لاگ فائلیں حذف کردی جائیں گی. + لاگنگ فعال ہے۔ یاد رہے کہ لاگوں کو 14 دنوں کے بعد خود بخود غیر فعال کر دیا جائے گا، اور تمام لاگ فائلیں حذف کردی جائیں گی. - + Logging لاگنگ - + Enabling this function will save application's logs automatically. By default, logging functionality is disabled. Enable log saving in case of application malfunction. اس فعل کو فعال کرنے سے، ایپلیکیشن کے لاگ خود بخود محفوظ ہوجائیں گے۔ پہلے سے، لاگنگ کی فعالیت غیر فعال ہوتی ہے۔ اگر ایپلیکیشن میں کوئی خرابی ہو، تو لاگ کو بچانا فعال کریں. - Save logs - لاگوں کو محفوظ کریں + لاگوں کو محفوظ کریں - Open folder with logs - فائلوں کے فولڈر کو کھولیں + فائلوں کے فولڈر کو کھولیں - + + Save محفوظ - + + Logs files (*.log) لاگ فائلیں (*.log) - + + Logs file saved لاگ فائل محفوظ ہوگئی - Save logs to file - لاگوں کو فائل میں محفوظ کریں + لاگوں کو فائل میں محفوظ کریں - + + Enable logs + + + + Clear logs? کیا آپ لاگوں کو صاف کرنا چاہتے ہیں؟ - + Continue براہ کرم جاری رکھیں - + Cancel منسوخ - + Logs have been cleaned up تم مسح السجلاتلاگوں کو صاف کر دیا گیا ہے - + + Client logs + + + + + AmneziaVPN logs + + + + + + Open logs folder + + + + + + Export logs + + + + + Service logs + + + + + AmneziaVPN-service logs + + + + Clear logs لاگوں کو صاف کریں @@ -1958,22 +2136,21 @@ Already installed containers were found on the server. All installed containers ترتیبات - Clear %1 profile - %1 پروفائل کو صاف کریں + %1 پروفائل کو صاف کریں - + Clear %1 profile? کیا آپ واقعی %1 پروفائل کو صاف کرنا چاہتے ہیں؟ - + Unable to clear %1 profile while there is an active connection فعال کنکشن کے دوران %1 پروفائل کو صاف نہیں کیا جا سکتا - + Cannot remove active container فعال کنٹینر کو ہٹانا ممکن نہیں @@ -1983,29 +2160,54 @@ Already installed containers were found on the server. All installed containers - + Remove ہٹائیں - + All users with whom you shared a connection will no longer be able to connect to it. آپ نے جن کے ساتھ کنکشن شئیر کیا تھا، ان تمام صارفین کو اس سے جڑنے کی اجازت نہیں ہوگی. - + Remove %1 from server? کیا آپ سرور سے %1 کو ہٹانا چاہتے ہیں؟ - - + + connection settings + + + + + Click the "connect" button to create a connection configuration + + + + + server settings + + + + + Clear profile + + + + + The connection configuration will be deleted for this device only + + + + + Continue براہ کرم جاری رکھیں - - + + Cancel منسوخ @@ -2189,82 +2391,92 @@ Already installed containers were found on the server. All installed containers کنکشن - + + Settings + ترتیبات + + + + Enable logs + + + + Insert the key, add a configuration file or scan the QR-code - + Insert key - + Insert داخل کریں - + Continue - + Other connection options - + VPN by Amnezia - + Connect to classic paid and free VPN services from Amnezia - + Self-hosted VPN - + Configure Amnezia VPN on your own server - + Restore from backup بیک اپ سے بحال کریں - + Open backup file بیک اپ فائل کو کھولیں - + Backup files (*.backup) بیک اپ فائلیں (*.backup) - + File with connection settings کنکشن کی ترتیبات والی فائل - + Open config file کنفیگ فائل کو کھولیں - + QR code QR کوڈ - + I have nothing میرے پاس کچھ نہیں ہے @@ -2436,7 +2648,7 @@ Already installed containers were found on the server. All installed containers انسٹال - + The port must be in the range of 1 to 65535 @@ -2808,12 +3020,17 @@ Already installed containers were found on the server. All installed containers شیئر - + + Access error! + رساءی ناممکن! + + + Connection to کنکشن کو - + File with connection settings to کنکشن کی ترتیبات کی فائل @@ -2830,6 +3047,11 @@ Already installed containers were found on the server. All installed containers Settings restored from backup file ترتیبات بیک اپ فائل سے بحال کردی گئی ہیں + + + Logging is enabled. Note that logs will be automaticallydisabled after 14 days, and all log files will be deleted. + + PopupType @@ -2868,12 +3090,12 @@ Already installed containers were found on the server. All installed containers پاس ورڈ نہیں ملا - + Could not open keystore کی اسٹور کھولا نہیں جا سکا - + Could not remove private key from keystore خصوصی کلید کو کی اسٹور سے ہٹانا نہیں ہو سکا @@ -3049,27 +3271,27 @@ Already installed containers were found on the server. All installed containers کی اسٹور کھولنے میں ناکام - + Could not create private key generator پرائیویٹ کلید جنریٹر تخلیق نہیں کیا - + Could not generate new private key نیا نجی کلید تخلیق نہیں کیا جا سکا - + Could not retrieve private key from keystore کی اسٹور سے نجی کلید حاصل نہیں کیا - + Could not create encryption cipher تشکیل تشکیل نہیں کر سکا - + Could not encrypt data ڈیٹا کو محفوظ کرنے میں ناکام @@ -3709,12 +3931,12 @@ While it offers a blend of security, stability, and speed, it's essential t SettingsController - + Backup file is corrupted بیک اپ فائل خراب ہو گئی ہے - + All settings have been reset to default values تمام ترتیبات کو ڈیفالٹ اقدار پر دوبارہ ترتیب دیا گیا ہے @@ -3846,7 +4068,7 @@ While it offers a blend of security, stability, and speed, it's essential t VpnConnection - + Mbps ایم بی پی ایس diff --git a/client/translations/amneziavpn_zh_CN.ts b/client/translations/amneziavpn_zh_CN.ts index 423c9e00..39b6bee0 100644 --- a/client/translations/amneziavpn_zh_CN.ts +++ b/client/translations/amneziavpn_zh_CN.ts @@ -4,47 +4,52 @@ ApiServicesModel - + Classic VPN for comfortable work, downloading large files and watching videos. Works for any sites. Speed up to %1 MBit/s - + VPN to access blocked sites in regions with high levels of Internet censorship. - + + <p><a style="color: #EB5757;">Not available in your region. If you have VPN enabled, disable it, return to the previous screen, and try again.</a> + + + + Amnezia Premium - A classic VPN for comfortable work, downloading large files, and watching videos in high resolution. It works for all websites, even in countries with the highest level of internet censorship. - + Amnezia Free is a free VPN to bypass blocking in countries with high levels of internet censorship - + %1 MBit/s - + %1 days - + VPN will open only popular sites blocked in your region, such as Instagram, Facebook, Twitter and others. Other sites will be opened from your real IP address, <a href="%1/free" style="color: #FBB26A;">more details on the website.</a> - + Free - + %1 $/month @@ -75,7 +80,7 @@ ConnectButton - + Unable to disconnect during configuration preparation @@ -186,9 +191,8 @@ ExportController - Access error! - 访问错误 + 访问错误 @@ -258,18 +262,18 @@ Can't be disabled for current server - - + + Invalid configuration file - + Scanned %1 of %2. 扫描 %1 of %2. - + In the imported configuration, potentially dangerous lines were found: @@ -469,6 +473,11 @@ Already installed containers were found on the server. All installed containers Gateway endpoint + + + Dev gateway environment + + PageHome @@ -503,10 +512,63 @@ Already installed containers were found on the server. All installed containers 已建立连接时无法更改服务器配置 + + PageProtocolAwgClientSettings + + + AmneziaWG settings + AmneziaWG 配置 + + + + MTU + + + + + Server settings + + + + + Port + 端口 + + + + Save + 保存 + + + + Save settings? + 保存设置? + + + + Only the settings for this device will be changed + + + + + Continue + 继续 + + + + Cancel + 取消 + + + + Unable change settings while there is an active connection + + + PageProtocolAwgSettings - + AmneziaWG settings AmneziaWG 配置 @@ -515,11 +577,6 @@ Already installed containers were found on the server. All installed containers Port 端口 - - - MTU - - Remove AmneziaWG 移除AmneziaWG @@ -529,87 +586,87 @@ Already installed containers were found on the server. All installed containers 从服务上移除AmneziaWG? - + All users with whom you shared a connection with will no longer be able to connect to it. 与您共享连接的所有用户将无法再连接到该连接。 - + Save 保存 - + Jc - Junk packet count - + Jmin - Junk packet minimum size - + Jmax - Junk packet maximum size - + S1 - Init packet junk size - + S2 - Response packet junk size - + H1 - Init packet magic header - + H2 - Response packet magic header - + H4 - Transport packet magic header - + H3 - Underload packet magic header - + The values of the H1-H4 fields must be unique - + The value of the field S1 + message initiation size (148) must not equal S2 + message response size (92) - + Save settings? 保存设置? - + Continue 继续 - + Cancel 取消 - + Unable change settings while there is an active connection @@ -933,24 +990,82 @@ Already installed containers were found on the server. All installed containers - PageProtocolWireGuardSettings + PageProtocolWireGuardClientSettings - + WG settings - - Port - 端口 - - - + MTU - + + Server settings + + + + + Port + 端口 + + + + Save + 保存 + + + + Save settings? + 保存设置? + + + + Only the settings for this device will be changed + + + + + Continue + 继续 + + + + Cancel + 取消 + + + + Unable change settings while there is an active connection + + + + + PageProtocolWireGuardSettings + + + WG settings + + + + + Port + 端口 + + + + Save settings? + 保存设置? + + + + All users with whom you shared a connection with will no longer be able to connect to it. + 与您共享连接的所有用户将无法再连接到该连接。 + + + Unable change settings while there is an active connection @@ -959,15 +1074,17 @@ Already installed containers were found on the server. All installed containers 与您共享连接的所有用户将无法再连接到该连接。 + Continue - 继续 + 继续 + Cancel - 取消 + 取消 - + Save 保存 @@ -1329,9 +1446,13 @@ And if you don't like the app, all the more support it - the donation will - Mail - 邮件 + 邮件 + + + + support@amnezia.org + @@ -1339,32 +1460,37 @@ And if you don't like the app, all the more support it - the donation will 用于评论和提交软件的缺陷 - + + Copied + + + + GitHub GitHub - + https://github.com/amnezia-vpn/amnezia-client https://github.com/amnezia-vpn/amnezia-client - + Website 官网 - + Software version: %1 软件版本: %1 - + Check for updates 检查更新 - + Privacy Policy 隐私政策 @@ -1849,72 +1975,104 @@ And if you don't like the app, all the more support it - the donation will PageSettingsLogging - - Logging is enabled. Note that logs will be automatically disabled after 14 days, and all log files will be deleted. - - - - + Logging 日志 - + Enabling this function will save application's logs automatically. By default, logging functionality is disabled. Enable log saving in case of application malfunction. 默认情况下,日志功能是禁用的。如果应用程序出现故障,则启用日志保存功能。 - Save logs - 记录日志 + 记录日志 - Open folder with logs - 打开日志文件夹 + 打开日志文件夹 - + + Save 保存 - + + Logs files (*.log) - + + Logs file saved 日志文件已保存 - Save logs to file - 保存日志到文件 + 保存日志到文件 - + + Enable logs + + + + Clear logs? 清理日志? - + Continue 继续 - + Cancel 取消 - + Logs have been cleaned up 日志已清理 - + + Client logs + + + + + AmneziaVPN logs + + + + + + Open logs folder + + + + + + Export logs + + + + + Service logs + + + + + AmneziaVPN-service logs + + + + Clear logs 清理日志 @@ -2102,12 +2260,7 @@ And if you don't like the app, all the more support it - the donation will 配置 - - Clear %1 profile - - - - + Clear %1 profile? @@ -2117,22 +2270,47 @@ And if you don't like the app, all the more support it - the donation will - + + connection settings + + + + + Click the "connect" button to create a connection configuration + + + + + server settings + + + + + Clear profile + + + + + The connection configuration will be deleted for this device only + + + + Unable to clear %1 profile while there is an active connection - + Remove 移除 - + All users with whom you shared a connection will no longer be able to connect to it. 与您共享连接的所有用户将无法再连接到该连接。 - + Cannot remove active container @@ -2145,7 +2323,7 @@ And if you don't like the app, all the more support it - the donation will 从服务器 - + Remove %1 from server? 从服务器移除 %1 ? @@ -2154,14 +2332,14 @@ And if you don't like the app, all the more support it - the donation will 与您共享连接的所有用户将无法再连接到此链接 - - + + Continue 继续 - - + + Cancel 取消 @@ -2376,82 +2554,92 @@ It's okay as long as it's from someone you trust. 连接 - + + Settings + 设置 + + + + Enable logs + + + + Insert the key, add a configuration file or scan the QR-code - + Insert key - + Insert 插入 - + Continue 继续 - + Other connection options - + VPN by Amnezia - + Connect to classic paid and free VPN services from Amnezia - + Self-hosted VPN - + Configure Amnezia VPN on your own server - + Restore from backup 从备份还原 - + Open backup file 打开备份文件 - + Backup files (*.backup) - + File with connection settings 包含连接配置的文件 - + Open config file 打开配置文件 - + QR code 二维码 - + I have nothing 我没有 @@ -2661,7 +2849,7 @@ and will not be shared or disclosed to the Amnezia or any third parties 安装 - + The port must be in the range of 1 to 65535 @@ -3077,12 +3265,17 @@ and will not be shared or disclosed to the Amnezia or any third parties 共享 - + + Access error! + 访问错误 + + + Connection to 连接到 - + File with connection settings to 连接配置文件的内容为 @@ -3099,6 +3292,11 @@ and will not be shared or disclosed to the Amnezia or any third parties Settings restored from backup file 从备份文件还原配置 + + + Logging is enabled. Note that logs will be automaticallydisabled after 14 days, and all log files will be deleted. + + PopupType @@ -3137,12 +3335,12 @@ and will not be shared or disclosed to the Amnezia or any third parties 未发现密码 - + Could not open keystore 无法打开密钥库 - + Could not remove private key from keystore 无法从密钥库中删除私钥 @@ -3318,27 +3516,27 @@ and will not be shared or disclosed to the Amnezia or any third parties 无法打开密钥库 - + Could not create private key generator 无法创建私钥生成器 - + Could not generate new private key 无法生成新的私钥 - + Could not retrieve private key from keystore 无法从密钥库检索私钥 - + Could not create encryption cipher 无法创建加密密码 - + Could not encrypt data 无法加密数据 @@ -4169,12 +4367,12 @@ While it offers a blend of security, stability, and speed, it's essential t SettingsController - + Backup file is corrupted 备份文件已损坏 - + All settings have been reset to default values 所配置恢复为默认值 @@ -4314,7 +4512,7 @@ While it offers a blend of security, stability, and speed, it's essential t VpnConnection - + Mbps diff --git a/client/ui/controllers/importController.cpp b/client/ui/controllers/importController.cpp index 7ffcedd7..32170fb6 100644 --- a/client/ui/controllers/importController.cpp +++ b/client/ui/controllers/importController.cpp @@ -4,12 +4,12 @@ #include #include #include -#include #include +#include -#include "utilities.h" -#include "core/serialization/serialization.h" #include "core/errorstrings.h" +#include "core/serialization/serialization.h" +#include "utilities.h" #ifdef Q_OS_ANDROID #include "platforms/android/android_controller.h" @@ -96,36 +96,40 @@ bool ImportController::extractConfigFromData(QString data) if (config.startsWith("vless://")) { m_configType = ConfigTypes::Xray; - m_config = extractXrayConfig(Utils::JsonToString(serialization::vless::Deserialize(config, &prefix, &errormsg), - QJsonDocument::JsonFormat::Compact), prefix); + m_config = extractXrayConfig( + Utils::JsonToString(serialization::vless::Deserialize(config, &prefix, &errormsg), QJsonDocument::JsonFormat::Compact), + prefix); return m_config.empty() ? false : true; } if (config.startsWith("vmess://") && config.contains("@")) { m_configType = ConfigTypes::Xray; - m_config = extractXrayConfig(Utils::JsonToString(serialization::vmess_new::Deserialize(config, &prefix, &errormsg), - QJsonDocument::JsonFormat::Compact), prefix); + m_config = extractXrayConfig( + Utils::JsonToString(serialization::vmess_new::Deserialize(config, &prefix, &errormsg), QJsonDocument::JsonFormat::Compact), + prefix); return m_config.empty() ? false : true; } if (config.startsWith("vmess://")) { m_configType = ConfigTypes::Xray; - m_config = extractXrayConfig(Utils::JsonToString(serialization::vmess::Deserialize(config, &prefix, &errormsg), - QJsonDocument::JsonFormat::Compact), prefix); + m_config = extractXrayConfig( + Utils::JsonToString(serialization::vmess::Deserialize(config, &prefix, &errormsg), QJsonDocument::JsonFormat::Compact), + prefix); return m_config.empty() ? false : true; } if (config.startsWith("trojan://")) { m_configType = ConfigTypes::Xray; - m_config = extractXrayConfig(Utils::JsonToString(serialization::trojan::Deserialize(config, &prefix, &errormsg), - QJsonDocument::JsonFormat::Compact), prefix); + m_config = extractXrayConfig( + Utils::JsonToString(serialization::trojan::Deserialize(config, &prefix, &errormsg), QJsonDocument::JsonFormat::Compact), + prefix); return m_config.empty() ? false : true; } if (config.startsWith("ss://") && !config.contains("plugin=")) { m_configType = ConfigTypes::ShadowSocks; - m_config = extractXrayConfig(Utils::JsonToString(serialization::ss::Deserialize(config, &prefix, &errormsg), - QJsonDocument::JsonFormat::Compact), prefix); + m_config = extractXrayConfig( + Utils::JsonToString(serialization::ss::Deserialize(config, &prefix, &errormsg), QJsonDocument::JsonFormat::Compact), prefix); return m_config.empty() ? false : true; } @@ -173,6 +177,7 @@ bool ImportController::extractConfigFromData(QString data) } case ConfigTypes::Amnezia: { m_config = QJsonDocument::fromJson(config.toUtf8()).object(); + processAmneziaConfig(m_config); if (!m_config.empty()) { checkForMaliciousStrings(m_config); return true; @@ -353,20 +358,19 @@ QJsonObject ImportController::extractWireGuardConfig(const QString &data) QJsonObject lastConfig; lastConfig[config_key::config] = data; - const static QRegularExpression hostNameAndPortRegExp("Endpoint = (.*):([0-9]*)"); - QRegularExpressionMatch hostNameAndPortMatch = hostNameAndPortRegExp.match(data); + auto url { QUrl::fromUserInput(configMap.value("Endpoint")) }; QString hostName; QString port; - if (hostNameAndPortMatch.hasCaptured(1)) { - hostName = hostNameAndPortMatch.captured(1); + if (!url.host().isEmpty()) { + hostName = url.host(); } else { - qDebug() << "Key parameter 'Endpoint' is missing"; + qDebug() << "Key parameter 'Endpoint' is missing or has an invalid format"; emit importErrorOccurred(ErrorCode::ImportInvalidConfigError, false); return QJsonObject(); } - if (hostNameAndPortMatch.hasCaptured(2)) { - port = hostNameAndPortMatch.captured(2); + if (url.port() != -1) { + port = QString::number(url.port()); } else { port = protocols::wireguard::defaultPort; } @@ -395,7 +399,11 @@ QJsonObject ImportController::extractWireGuardConfig(const QString &data) lastConfig[config_key::mtu] = configMap.value("MTU"); } - QJsonArray allowedIpsJsonArray = QJsonArray::fromStringList(configMap.value("AllowedIPs").split(",")); + if (!configMap.value("PersistentKeepalive").isEmpty()) { + lastConfig[config_key::persistent_keep_alive] = configMap.value("PersistentKeepalive"); + } + + QJsonArray allowedIpsJsonArray = QJsonArray::fromStringList(configMap.value("AllowedIPs").split(", ")); lastConfig[config_key::allowed_ips] = allowedIpsJsonArray; @@ -419,6 +427,12 @@ QJsonObject ImportController::extractWireGuardConfig(const QString &data) m_configType = ConfigTypes::Awg; } + if (!configMap.value("MTU").isEmpty()) { + lastConfig[config_key::mtu] = configMap.value("MTU"); + } else { + lastConfig[config_key::mtu] = protocolName == "awg" ? protocols::awg::defaultMtu : protocols::wireguard::defaultMtu; + } + QJsonObject wireguardConfig; wireguardConfig[config_key::last_config] = QString(QJsonDocument(lastConfig).toJson()); wireguardConfig[config_key::isThirdPartyConfig] = true; @@ -488,7 +502,7 @@ QJsonObject ImportController::extractXrayConfig(const QString &data, const QStri if (m_configType == ConfigTypes::ShadowSocks) { config[config_key::defaultContainer] = "amnezia-ssxray"; } else { - config[config_key::defaultContainer] = "amnezia-xray"; + config[config_key::defaultContainer] = "amnezia-xray"; } if (description.isEmpty()) { config[config_key::description] = m_settings->nextAvailableServerName(); @@ -646,3 +660,28 @@ void ImportController::checkForMaliciousStrings(const QJsonObject &serverConfig) } } } + +void ImportController::processAmneziaConfig(QJsonObject &config) +{ + auto containers = config.value(config_key::containers).toArray(); + for (auto i = 0; i < containers.size(); i++) { + auto container = containers.at(i).toObject(); + auto dockerContainer = ContainerProps::containerFromString(container.value(config_key::container).toString()); + if (dockerContainer == DockerContainer::Awg || dockerContainer == DockerContainer::WireGuard) { + auto containerConfig = container.value(ContainerProps::containerTypeToString(dockerContainer)).toObject(); + auto protocolConfig = containerConfig.value(config_key::last_config).toString(); + if (protocolConfig.isEmpty()) { + return; + } + + QJsonObject jsonConfig = QJsonDocument::fromJson(protocolConfig.toUtf8()).object(); + jsonConfig[config_key::mtu] = dockerContainer == DockerContainer::Awg ? protocols::awg::defaultMtu : protocols::wireguard::defaultMtu; + + containerConfig[config_key::last_config] = QString(QJsonDocument(jsonConfig).toJson()); + + container[ContainerProps::containerTypeToString(dockerContainer)] = containerConfig; + containers.replace(i, container); + config.insert(config_key::containers, containers); + } + } +} diff --git a/client/ui/controllers/importController.h b/client/ui/controllers/importController.h index ea1ba6b0..61205253 100644 --- a/client/ui/controllers/importController.h +++ b/client/ui/controllers/importController.h @@ -68,6 +68,8 @@ private: void checkForMaliciousStrings(const QJsonObject &protocolConfig); + void processAmneziaConfig(QJsonObject &config); + #if defined Q_OS_ANDROID || defined Q_OS_IOS void stopDecodingQr(); #endif diff --git a/client/ui/controllers/pageController.cpp b/client/ui/controllers/pageController.cpp index 9daca272..bbcc55a1 100644 --- a/client/ui/controllers/pageController.cpp +++ b/client/ui/controllers/pageController.cpp @@ -112,7 +112,7 @@ void PageController::showOnStartup() if (!m_settings->isStartMinimized()) { emit raiseMainWindow(); } else { -#if defined(Q_OS_WIN) || defined(Q_OS_LINUX) +#if defined(Q_OS_WIN) || (defined(Q_OS_LINUX) && !defined(Q_OS_ANDROID)) emit hideMainWindow(); #elif defined Q_OS_MACX setDockIconVisible(false); diff --git a/client/ui/controllers/pageController.h b/client/ui/controllers/pageController.h index 2cc2d983..f89d39a1 100644 --- a/client/ui/controllers/pageController.h +++ b/client/ui/controllers/pageController.h @@ -59,6 +59,9 @@ namespace PageLoader PageProtocolIKev2Settings, PageProtocolRaw, + PageProtocolWireGuardClientSettings, + PageProtocolAwgClientSettings, + PageShareFullAccess, PageDevMenu diff --git a/client/ui/models/clientManagementModel.cpp b/client/ui/models/clientManagementModel.cpp index f2117f75..7d3be2cb 100644 --- a/client/ui/models/clientManagementModel.cpp +++ b/client/ui/models/clientManagementModel.cpp @@ -20,6 +20,7 @@ namespace constexpr char latestHandshake[] = "latestHandshake"; constexpr char dataReceived[] = "dataReceived"; constexpr char dataSent[] = "dataSent"; + constexpr char allowedIps[] = "allowedIps"; } } @@ -49,6 +50,7 @@ QVariant ClientManagementModel::data(const QModelIndex &index, int role) const case LatestHandshakeRole: return userData.value(configKey::latestHandshake).toString(); case DataReceivedRole: return userData.value(configKey::dataReceived).toString(); case DataSentRole: return userData.value(configKey::dataSent).toString(); + case AllowedIpsRole: return userData.value(configKey::allowedIps).toString(); } return QVariant(); @@ -141,6 +143,10 @@ ErrorCode ClientManagementModel::updateModel(const DockerContainer container, co userData[configKey::dataSent] = client.dataSent; } + if (!client.allowedIps.isEmpty()) { + userData[configKey::allowedIps] = client.allowedIps; + } + obj[configKey::userData] = userData; m_clientsTable.replace(i, obj); break; @@ -266,8 +272,9 @@ ErrorCode ClientManagementModel::wgShow(const DockerContainer container, const S const auto peerList = parts.filter("peer:"); const auto latestHandshakeList = parts.filter("latest handshake:"); const auto transferredDataList = parts.filter("transfer:"); + const auto allowedIpsList = parts.filter("allowed ips:"); - if (latestHandshakeList.isEmpty() || transferredDataList.isEmpty() || peerList.isEmpty()) { + if (allowedIpsList.isEmpty() || latestHandshakeList.isEmpty() || transferredDataList.isEmpty() || peerList.isEmpty()) { return error; } @@ -281,19 +288,20 @@ ErrorCode ClientManagementModel::wgShow(const DockerContainer container, const S } }; - for (int i = 0; i < peerList.size() && i < transferredDataList.size() && i < latestHandshakeList.size(); ++i) { + for (int i = 0; i < peerList.size() && i < transferredDataList.size() && i < latestHandshakeList.size() && i < allowedIpsList.size(); ++i) { const auto transferredData = getStrValue(transferredDataList[i]).split(","); auto latestHandshake = getStrValue(latestHandshakeList[i]); auto serverBytesReceived = transferredData.front().trimmed(); auto serverBytesSent = transferredData.back().trimmed(); + auto allowedIps = getStrValue(allowedIpsList[i]); changeHandshakeFormat(latestHandshake); serverBytesReceived.chop(QStringLiteral(" received").length()); serverBytesSent.chop(QStringLiteral(" sent").length()); - data.push_back({ getStrValue(peerList[i]), latestHandshake, serverBytesSent, serverBytesReceived }); + data.push_back({ getStrValue(peerList[i]), latestHandshake, serverBytesSent, serverBytesReceived, allowedIps }); } return error; diff --git a/client/ui/models/clientManagementModel.h b/client/ui/models/clientManagementModel.h index d64280a3..60132abe 100644 --- a/client/ui/models/clientManagementModel.h +++ b/client/ui/models/clientManagementModel.h @@ -17,7 +17,8 @@ public: CreationDateRole, LatestHandshakeRole, DataReceivedRole, - DataSentRole + DataSentRole, + AllowedIpsRole }; struct WgShowData @@ -26,6 +27,7 @@ public: QString latestHandshake; QString dataReceived; QString dataSent; + QString allowedIps; }; ClientManagementModel(std::shared_ptr settings, QObject *parent = nullptr); diff --git a/client/ui/models/protocols/awgConfigModel.cpp b/client/ui/models/protocols/awgConfigModel.cpp index 658658df..3a245ebe 100644 --- a/client/ui/models/protocols/awgConfigModel.cpp +++ b/client/ui/models/protocols/awgConfigModel.cpp @@ -21,17 +21,30 @@ bool AwgConfigModel::setData(const QModelIndex &index, const QVariant &value, in } switch (role) { - case Roles::PortRole: m_protocolConfig.insert(config_key::port, value.toString()); break; - case Roles::MtuRole: m_protocolConfig.insert(config_key::mtu, value.toString()); break; - case Roles::JunkPacketCountRole: m_protocolConfig.insert(config_key::junkPacketCount, value.toString()); break; - case Roles::JunkPacketMinSizeRole: m_protocolConfig.insert(config_key::junkPacketMinSize, value.toString()); break; - case Roles::JunkPacketMaxSizeRole: m_protocolConfig.insert(config_key::junkPacketMaxSize, value.toString()); break; - case Roles::InitPacketJunkSizeRole: m_protocolConfig.insert(config_key::initPacketJunkSize, value.toString()); break; - case Roles::ResponsePacketJunkSizeRole: m_protocolConfig.insert(config_key::responsePacketJunkSize, value.toString()); break; - case Roles::InitPacketMagicHeaderRole: m_protocolConfig.insert(config_key::initPacketMagicHeader, value.toString()); break; - case Roles::ResponsePacketMagicHeaderRole: m_protocolConfig.insert(config_key::responsePacketMagicHeader, value.toString()); break; - case Roles::UnderloadPacketMagicHeaderRole: m_protocolConfig.insert(config_key::underloadPacketMagicHeader, value.toString()); break; - case Roles::TransportPacketMagicHeaderRole: m_protocolConfig.insert(config_key::transportPacketMagicHeader, value.toString()); break; + case Roles::PortRole: m_serverProtocolConfig.insert(config_key::port, value.toString()); break; + + case Roles::ClientMtuRole: m_clientProtocolConfig.insert(config_key::mtu, value.toString()); break; + case Roles::ClientJunkPacketCountRole: m_clientProtocolConfig.insert(config_key::junkPacketCount, value.toString()); break; + case Roles::ClientJunkPacketMinSizeRole: m_clientProtocolConfig.insert(config_key::junkPacketMinSize, value.toString()); break; + case Roles::ClientJunkPacketMaxSizeRole: m_clientProtocolConfig.insert(config_key::junkPacketMaxSize, value.toString()); break; + + case Roles::ServerJunkPacketCountRole: m_serverProtocolConfig.insert(config_key::junkPacketCount, value.toString()); break; + case Roles::ServerJunkPacketMinSizeRole: m_serverProtocolConfig.insert(config_key::junkPacketMinSize, value.toString()); break; + case Roles::ServerJunkPacketMaxSizeRole: m_serverProtocolConfig.insert(config_key::junkPacketMaxSize, value.toString()); break; + case Roles::ServerInitPacketJunkSizeRole: m_serverProtocolConfig.insert(config_key::initPacketJunkSize, value.toString()); break; + case Roles::ServerResponsePacketJunkSizeRole: + m_serverProtocolConfig.insert(config_key::responsePacketJunkSize, value.toString()); + break; + case Roles::ServerInitPacketMagicHeaderRole: m_serverProtocolConfig.insert(config_key::initPacketMagicHeader, value.toString()); break; + case Roles::ServerResponsePacketMagicHeaderRole: + m_serverProtocolConfig.insert(config_key::responsePacketMagicHeader, value.toString()); + break; + case Roles::ServerUnderloadPacketMagicHeaderRole: + m_serverProtocolConfig.insert(config_key::underloadPacketMagicHeader, value.toString()); + break; + case Roles::ServerTransportPacketMagicHeaderRole: + m_serverProtocolConfig.insert(config_key::transportPacketMagicHeader, value.toString()); + break; } emit dataChanged(index, index, QList { role }); @@ -45,17 +58,22 @@ QVariant AwgConfigModel::data(const QModelIndex &index, int role) const } switch (role) { - case Roles::PortRole: return m_protocolConfig.value(config_key::port).toString(); - case Roles::MtuRole: return m_protocolConfig.value(config_key::mtu).toString(); - case Roles::JunkPacketCountRole: return m_protocolConfig.value(config_key::junkPacketCount); - case Roles::JunkPacketMinSizeRole: return m_protocolConfig.value(config_key::junkPacketMinSize); - case Roles::JunkPacketMaxSizeRole: return m_protocolConfig.value(config_key::junkPacketMaxSize); - case Roles::InitPacketJunkSizeRole: return m_protocolConfig.value(config_key::initPacketJunkSize); - case Roles::ResponsePacketJunkSizeRole: return m_protocolConfig.value(config_key::responsePacketJunkSize); - case Roles::InitPacketMagicHeaderRole: return m_protocolConfig.value(config_key::initPacketMagicHeader); - case Roles::ResponsePacketMagicHeaderRole: return m_protocolConfig.value(config_key::responsePacketMagicHeader); - case Roles::UnderloadPacketMagicHeaderRole: return m_protocolConfig.value(config_key::underloadPacketMagicHeader); - case Roles::TransportPacketMagicHeaderRole: return m_protocolConfig.value(config_key::transportPacketMagicHeader); + case Roles::PortRole: return m_serverProtocolConfig.value(config_key::port).toString(); + + case Roles::ClientMtuRole: return m_clientProtocolConfig.value(config_key::mtu); + case Roles::ClientJunkPacketCountRole: return m_clientProtocolConfig.value(config_key::junkPacketCount); + case Roles::ClientJunkPacketMinSizeRole: return m_clientProtocolConfig.value(config_key::junkPacketMinSize); + case Roles::ClientJunkPacketMaxSizeRole: return m_clientProtocolConfig.value(config_key::junkPacketMaxSize); + + case Roles::ServerJunkPacketCountRole: return m_serverProtocolConfig.value(config_key::junkPacketCount); + case Roles::ServerJunkPacketMinSizeRole: return m_serverProtocolConfig.value(config_key::junkPacketMinSize); + case Roles::ServerJunkPacketMaxSizeRole: return m_serverProtocolConfig.value(config_key::junkPacketMaxSize); + case Roles::ServerInitPacketJunkSizeRole: return m_serverProtocolConfig.value(config_key::initPacketJunkSize); + case Roles::ServerResponsePacketJunkSizeRole: return m_serverProtocolConfig.value(config_key::responsePacketJunkSize); + case Roles::ServerInitPacketMagicHeaderRole: return m_serverProtocolConfig.value(config_key::initPacketMagicHeader); + case Roles::ServerResponsePacketMagicHeaderRole: return m_serverProtocolConfig.value(config_key::responsePacketMagicHeader); + case Roles::ServerUnderloadPacketMagicHeaderRole: return m_serverProtocolConfig.value(config_key::underloadPacketMagicHeader); + case Roles::ServerTransportPacketMagicHeaderRole: return m_serverProtocolConfig.value(config_key::transportPacketMagicHeader); } return QVariant(); @@ -68,51 +86,63 @@ void AwgConfigModel::updateModel(const QJsonObject &config) m_fullConfig = config; - QJsonObject protocolConfig = config.value(config_key::awg).toObject(); + QJsonObject serverProtocolConfig = config.value(config_key::awg).toObject(); auto defaultTransportProto = ProtocolProps::transportProtoToString(ProtocolProps::defaultTransportProto(Proto::Awg), Proto::Awg); - m_protocolConfig.insert(config_key::transport_proto, protocolConfig.value(config_key::transport_proto).toString(defaultTransportProto)); - m_protocolConfig[config_key::last_config] = protocolConfig.value(config_key::last_config); - m_protocolConfig[config_key::port] = protocolConfig.value(config_key::port).toString(protocols::awg::defaultPort); - m_protocolConfig[config_key::mtu] = protocolConfig.value(config_key::mtu).toString(protocols::awg::defaultMtu); - m_protocolConfig[config_key::junkPacketCount] = - protocolConfig.value(config_key::junkPacketCount).toString(protocols::awg::defaultJunkPacketCount); - m_protocolConfig[config_key::junkPacketMinSize] = - protocolConfig.value(config_key::junkPacketMinSize).toString(protocols::awg::defaultJunkPacketMinSize); - m_protocolConfig[config_key::junkPacketMaxSize] = - protocolConfig.value(config_key::junkPacketMaxSize).toString(protocols::awg::defaultJunkPacketMaxSize); - m_protocolConfig[config_key::initPacketJunkSize] = - protocolConfig.value(config_key::initPacketJunkSize).toString(protocols::awg::defaultInitPacketJunkSize); - m_protocolConfig[config_key::responsePacketJunkSize] = - protocolConfig.value(config_key::responsePacketJunkSize).toString(protocols::awg::defaultResponsePacketJunkSize); - m_protocolConfig[config_key::initPacketMagicHeader] = - protocolConfig.value(config_key::initPacketMagicHeader).toString(protocols::awg::defaultInitPacketMagicHeader); - m_protocolConfig[config_key::responsePacketMagicHeader] = - protocolConfig.value(config_key::responsePacketMagicHeader).toString(protocols::awg::defaultResponsePacketMagicHeader); - m_protocolConfig[config_key::underloadPacketMagicHeader] = - protocolConfig.value(config_key::underloadPacketMagicHeader).toString(protocols::awg::defaultUnderloadPacketMagicHeader); - m_protocolConfig[config_key::transportPacketMagicHeader] = - protocolConfig.value(config_key::transportPacketMagicHeader).toString(protocols::awg::defaultTransportPacketMagicHeader); + m_serverProtocolConfig.insert(config_key::transport_proto, + serverProtocolConfig.value(config_key::transport_proto).toString(defaultTransportProto)); + m_serverProtocolConfig[config_key::last_config] = serverProtocolConfig.value(config_key::last_config); + m_serverProtocolConfig[config_key::port] = serverProtocolConfig.value(config_key::port).toString(protocols::awg::defaultPort); + m_serverProtocolConfig[config_key::junkPacketCount] = + serverProtocolConfig.value(config_key::junkPacketCount).toString(protocols::awg::defaultJunkPacketCount); + m_serverProtocolConfig[config_key::junkPacketMinSize] = + serverProtocolConfig.value(config_key::junkPacketMinSize).toString(protocols::awg::defaultJunkPacketMinSize); + m_serverProtocolConfig[config_key::junkPacketMaxSize] = + serverProtocolConfig.value(config_key::junkPacketMaxSize).toString(protocols::awg::defaultJunkPacketMaxSize); + m_serverProtocolConfig[config_key::initPacketJunkSize] = + serverProtocolConfig.value(config_key::initPacketJunkSize).toString(protocols::awg::defaultInitPacketJunkSize); + m_serverProtocolConfig[config_key::responsePacketJunkSize] = + serverProtocolConfig.value(config_key::responsePacketJunkSize).toString(protocols::awg::defaultResponsePacketJunkSize); + m_serverProtocolConfig[config_key::initPacketMagicHeader] = + serverProtocolConfig.value(config_key::initPacketMagicHeader).toString(protocols::awg::defaultInitPacketMagicHeader); + m_serverProtocolConfig[config_key::responsePacketMagicHeader] = + serverProtocolConfig.value(config_key::responsePacketMagicHeader).toString(protocols::awg::defaultResponsePacketMagicHeader); + m_serverProtocolConfig[config_key::underloadPacketMagicHeader] = + serverProtocolConfig.value(config_key::underloadPacketMagicHeader).toString(protocols::awg::defaultUnderloadPacketMagicHeader); + m_serverProtocolConfig[config_key::transportPacketMagicHeader] = + serverProtocolConfig.value(config_key::transportPacketMagicHeader).toString(protocols::awg::defaultTransportPacketMagicHeader); + auto lastConfig = m_serverProtocolConfig.value(config_key::last_config).toString(); + QJsonObject clientProtocolConfig = QJsonDocument::fromJson(lastConfig.toUtf8()).object(); + m_clientProtocolConfig[config_key::mtu] = clientProtocolConfig[config_key::mtu].toString(protocols::awg::defaultMtu); + m_clientProtocolConfig[config_key::junkPacketCount] = + clientProtocolConfig.value(config_key::junkPacketCount).toString(m_serverProtocolConfig[config_key::junkPacketCount].toString()); + m_clientProtocolConfig[config_key::junkPacketMinSize] = + clientProtocolConfig.value(config_key::junkPacketMinSize).toString(m_serverProtocolConfig[config_key::junkPacketMinSize].toString()); + m_clientProtocolConfig[config_key::junkPacketMaxSize] = + clientProtocolConfig.value(config_key::junkPacketMaxSize).toString(m_serverProtocolConfig[config_key::junkPacketMaxSize].toString()); endResetModel(); } QJsonObject AwgConfigModel::getConfig() { const AwgConfig oldConfig(m_fullConfig.value(config_key::awg).toObject()); - const AwgConfig newConfig(m_protocolConfig); + const AwgConfig newConfig(m_serverProtocolConfig); if (!oldConfig.hasEqualServerSettings(newConfig)) { - m_protocolConfig.remove(config_key::last_config); + m_serverProtocolConfig.remove(config_key::last_config); } else { - auto lastConfig = m_protocolConfig.value(config_key::last_config).toString(); + auto lastConfig = m_serverProtocolConfig.value(config_key::last_config).toString(); QJsonObject jsonConfig = QJsonDocument::fromJson(lastConfig.toUtf8()).object(); - jsonConfig[config_key::mtu] = newConfig.mtu; + jsonConfig[config_key::mtu] = m_clientProtocolConfig[config_key::mtu]; + jsonConfig[config_key::junkPacketCount] = m_clientProtocolConfig[config_key::junkPacketCount]; + jsonConfig[config_key::junkPacketMinSize] = m_clientProtocolConfig[config_key::junkPacketMinSize]; + jsonConfig[config_key::junkPacketMaxSize] = m_clientProtocolConfig[config_key::junkPacketMaxSize]; - m_protocolConfig[config_key::last_config] = QString(QJsonDocument(jsonConfig).toJson()); + m_serverProtocolConfig[config_key::last_config] = QString(QJsonDocument(jsonConfig).toJson()); } - m_fullConfig.insert(config_key::awg, m_protocolConfig); + m_fullConfig.insert(config_key::awg, m_serverProtocolConfig); return m_fullConfig; } @@ -126,50 +156,73 @@ bool AwgConfigModel::isPacketSizeEqual(const int s1, const int s2) return (AwgConstant::messageInitiationSize + s1 == AwgConstant::messageResponseSize + s2); } +bool AwgConfigModel::isServerSettingsEqual() +{ + const AwgConfig oldConfig(m_fullConfig.value(config_key::awg).toObject()); + const AwgConfig newConfig(m_serverProtocolConfig); + + return oldConfig.hasEqualServerSettings(newConfig); +} + QHash AwgConfigModel::roleNames() const { QHash roles; roles[PortRole] = "port"; - roles[MtuRole] = "mtu"; - roles[JunkPacketCountRole] = "junkPacketCount"; - roles[JunkPacketMinSizeRole] = "junkPacketMinSize"; - roles[JunkPacketMaxSizeRole] = "junkPacketMaxSize"; - roles[InitPacketJunkSizeRole] = "initPacketJunkSize"; - roles[ResponsePacketJunkSizeRole] = "responsePacketJunkSize"; - roles[InitPacketMagicHeaderRole] = "initPacketMagicHeader"; - roles[ResponsePacketMagicHeaderRole] = "responsePacketMagicHeader"; - roles[UnderloadPacketMagicHeaderRole] = "underloadPacketMagicHeader"; - roles[TransportPacketMagicHeaderRole] = "transportPacketMagicHeader"; + + roles[ClientMtuRole] = "clientMtu"; + roles[ClientJunkPacketCountRole] = "clientJunkPacketCount"; + roles[ClientJunkPacketMinSizeRole] = "clientJunkPacketMinSize"; + roles[ClientJunkPacketMaxSizeRole] = "clientJunkPacketMaxSize"; + + roles[ServerJunkPacketCountRole] = "serverJunkPacketCount"; + roles[ServerJunkPacketMinSizeRole] = "serverJunkPacketMinSize"; + roles[ServerJunkPacketMaxSizeRole] = "serverJunkPacketMaxSize"; + roles[ServerInitPacketJunkSizeRole] = "serverInitPacketJunkSize"; + roles[ServerResponsePacketJunkSizeRole] = "serverResponsePacketJunkSize"; + roles[ServerInitPacketMagicHeaderRole] = "serverInitPacketMagicHeader"; + roles[ServerResponsePacketMagicHeaderRole] = "serverResponsePacketMagicHeader"; + roles[ServerUnderloadPacketMagicHeaderRole] = "serverUnderloadPacketMagicHeader"; + roles[ServerTransportPacketMagicHeaderRole] = "serverTransportPacketMagicHeader"; return roles; } -AwgConfig::AwgConfig(const QJsonObject &jsonConfig) +AwgConfig::AwgConfig(const QJsonObject &serverProtocolConfig) { - port = jsonConfig.value(config_key::port).toString(protocols::awg::defaultPort); - mtu = jsonConfig.value(config_key::mtu).toString(protocols::awg::defaultMtu); - junkPacketCount = jsonConfig.value(config_key::junkPacketCount).toString(protocols::awg::defaultJunkPacketCount); - junkPacketMinSize = jsonConfig.value(config_key::junkPacketMinSize).toString(protocols::awg::defaultJunkPacketMinSize); - junkPacketMaxSize = jsonConfig.value(config_key::junkPacketMaxSize).toString(protocols::awg::defaultJunkPacketMaxSize); - initPacketJunkSize = jsonConfig.value(config_key::initPacketJunkSize).toString(protocols::awg::defaultInitPacketJunkSize); - responsePacketJunkSize = jsonConfig.value(config_key::responsePacketJunkSize).toString(protocols::awg::defaultResponsePacketJunkSize); - initPacketMagicHeader = jsonConfig.value(config_key::initPacketMagicHeader).toString(protocols::awg::defaultInitPacketMagicHeader); - responsePacketMagicHeader = - jsonConfig.value(config_key::responsePacketMagicHeader).toString(protocols::awg::defaultResponsePacketMagicHeader); - underloadPacketMagicHeader = - jsonConfig.value(config_key::underloadPacketMagicHeader).toString(protocols::awg::defaultUnderloadPacketMagicHeader); - transportPacketMagicHeader = - jsonConfig.value(config_key::transportPacketMagicHeader).toString(protocols::awg::defaultTransportPacketMagicHeader); + auto lastConfig = serverProtocolConfig.value(config_key::last_config).toString(); + QJsonObject clientProtocolConfig = QJsonDocument::fromJson(lastConfig.toUtf8()).object(); + clientMtu = clientProtocolConfig[config_key::mtu].toString(protocols::awg::defaultMtu); + clientJunkPacketCount = clientProtocolConfig.value(config_key::junkPacketCount).toString(protocols::awg::defaultJunkPacketCount); + clientJunkPacketMinSize = clientProtocolConfig.value(config_key::junkPacketMinSize).toString(protocols::awg::defaultJunkPacketMinSize); + clientJunkPacketMaxSize = clientProtocolConfig.value(config_key::junkPacketMaxSize).toString(protocols::awg::defaultJunkPacketMaxSize); + + port = serverProtocolConfig.value(config_key::port).toString(protocols::awg::defaultPort); + serverJunkPacketCount = serverProtocolConfig.value(config_key::junkPacketCount).toString(protocols::awg::defaultJunkPacketCount); + serverJunkPacketMinSize = serverProtocolConfig.value(config_key::junkPacketMinSize).toString(protocols::awg::defaultJunkPacketMinSize); + serverJunkPacketMaxSize = serverProtocolConfig.value(config_key::junkPacketMaxSize).toString(protocols::awg::defaultJunkPacketMaxSize); + serverInitPacketJunkSize = serverProtocolConfig.value(config_key::initPacketJunkSize).toString(protocols::awg::defaultInitPacketJunkSize); + serverResponsePacketJunkSize = + serverProtocolConfig.value(config_key::responsePacketJunkSize).toString(protocols::awg::defaultResponsePacketJunkSize); + serverInitPacketMagicHeader = + serverProtocolConfig.value(config_key::initPacketMagicHeader).toString(protocols::awg::defaultInitPacketMagicHeader); + serverResponsePacketMagicHeader = + serverProtocolConfig.value(config_key::responsePacketMagicHeader).toString(protocols::awg::defaultResponsePacketMagicHeader); + serverUnderloadPacketMagicHeader = + serverProtocolConfig.value(config_key::underloadPacketMagicHeader).toString(protocols::awg::defaultUnderloadPacketMagicHeader); + serverTransportPacketMagicHeader = + serverProtocolConfig.value(config_key::transportPacketMagicHeader).toString(protocols::awg::defaultTransportPacketMagicHeader); } bool AwgConfig::hasEqualServerSettings(const AwgConfig &other) const { - if (port != other.port || junkPacketCount != other.junkPacketCount || junkPacketMinSize != other.junkPacketMinSize - || junkPacketMaxSize != other.junkPacketMaxSize || initPacketJunkSize != other.initPacketJunkSize - || responsePacketJunkSize != other.responsePacketJunkSize || initPacketMagicHeader != other.initPacketMagicHeader - || responsePacketMagicHeader != other.responsePacketMagicHeader || underloadPacketMagicHeader != other.underloadPacketMagicHeader - || transportPacketMagicHeader != other.transportPacketMagicHeader) { + if (port != other.port || serverJunkPacketCount != other.serverJunkPacketCount + || serverJunkPacketMinSize != other.serverJunkPacketMinSize || serverJunkPacketMaxSize != other.serverJunkPacketMaxSize + || serverInitPacketJunkSize != other.serverInitPacketJunkSize || serverResponsePacketJunkSize != other.serverResponsePacketJunkSize + || serverInitPacketMagicHeader != other.serverInitPacketMagicHeader + || serverResponsePacketMagicHeader != other.serverResponsePacketMagicHeader + || serverUnderloadPacketMagicHeader != other.serverUnderloadPacketMagicHeader + || serverTransportPacketMagicHeader != other.serverTransportPacketMagicHeader) { return false; } return true; @@ -177,7 +230,8 @@ bool AwgConfig::hasEqualServerSettings(const AwgConfig &other) const bool AwgConfig::hasEqualClientSettings(const AwgConfig &other) const { - if (mtu != other.mtu) { + if (clientMtu != other.clientMtu || clientJunkPacketCount != other.clientJunkPacketCount + || clientJunkPacketMinSize != other.clientJunkPacketMinSize || clientJunkPacketMaxSize != other.clientJunkPacketMaxSize) { return false; } return true; diff --git a/client/ui/models/protocols/awgConfigModel.h b/client/ui/models/protocols/awgConfigModel.h index 80375d38..06475bf5 100644 --- a/client/ui/models/protocols/awgConfigModel.h +++ b/client/ui/models/protocols/awgConfigModel.h @@ -16,16 +16,21 @@ struct AwgConfig AwgConfig(const QJsonObject &jsonConfig); QString port; - QString mtu; - QString junkPacketCount; - QString junkPacketMinSize; - QString junkPacketMaxSize; - QString initPacketJunkSize; - QString responsePacketJunkSize; - QString initPacketMagicHeader; - QString responsePacketMagicHeader; - QString underloadPacketMagicHeader; - QString transportPacketMagicHeader; + + QString clientMtu; + QString clientJunkPacketCount; + QString clientJunkPacketMinSize; + QString clientJunkPacketMaxSize; + + QString serverJunkPacketCount; + QString serverJunkPacketMinSize; + QString serverJunkPacketMaxSize; + QString serverInitPacketJunkSize; + QString serverResponsePacketJunkSize; + QString serverInitPacketMagicHeader; + QString serverResponsePacketMagicHeader; + QString serverUnderloadPacketMagicHeader; + QString serverTransportPacketMagicHeader; bool hasEqualServerSettings(const AwgConfig &other) const; bool hasEqualClientSettings(const AwgConfig &other) const; @@ -39,16 +44,21 @@ class AwgConfigModel : public QAbstractListModel public: enum Roles { PortRole = Qt::UserRole + 1, - MtuRole, - JunkPacketCountRole, - JunkPacketMinSizeRole, - JunkPacketMaxSizeRole, - InitPacketJunkSizeRole, - ResponsePacketJunkSizeRole, - InitPacketMagicHeaderRole, - ResponsePacketMagicHeaderRole, - UnderloadPacketMagicHeaderRole, - TransportPacketMagicHeaderRole + + ClientMtuRole, + ClientJunkPacketCountRole, + ClientJunkPacketMinSizeRole, + ClientJunkPacketMaxSizeRole, + + ServerJunkPacketCountRole, + ServerJunkPacketMinSizeRole, + ServerJunkPacketMaxSizeRole, + ServerInitPacketJunkSizeRole, + ServerResponsePacketJunkSizeRole, + ServerInitPacketMagicHeaderRole, + ServerResponsePacketMagicHeaderRole, + ServerUnderloadPacketMagicHeaderRole, + ServerTransportPacketMagicHeaderRole }; explicit AwgConfigModel(QObject *parent = nullptr); @@ -65,12 +75,15 @@ public slots: bool isHeadersEqual(const QString &h1, const QString &h2, const QString &h3, const QString &h4); bool isPacketSizeEqual(const int s1, const int s2); + bool isServerSettingsEqual(); + protected: QHash roleNames() const override; private: DockerContainer m_container; - QJsonObject m_protocolConfig; + QJsonObject m_serverProtocolConfig; + QJsonObject m_clientProtocolConfig; QJsonObject m_fullConfig; }; diff --git a/client/ui/models/protocols/wireguardConfigModel.cpp b/client/ui/models/protocols/wireguardConfigModel.cpp index 65bf2bb3..555915de 100644 --- a/client/ui/models/protocols/wireguardConfigModel.cpp +++ b/client/ui/models/protocols/wireguardConfigModel.cpp @@ -21,8 +21,8 @@ bool WireGuardConfigModel::setData(const QModelIndex &index, const QVariant &val } switch (role) { - case Roles::PortRole: m_protocolConfig.insert(config_key::port, value.toString()); break; - case Roles::MtuRole: m_protocolConfig.insert(config_key::mtu, value.toString()); break; + case Roles::PortRole: m_serverProtocolConfig.insert(config_key::port, value.toString()); break; + case Roles::ClientMtuRole: m_clientProtocolConfig.insert(config_key::mtu, value.toString()); break; } emit dataChanged(index, index, QList { role }); @@ -36,8 +36,8 @@ QVariant WireGuardConfigModel::data(const QModelIndex &index, int role) const } switch (role) { - case Roles::PortRole: return m_protocolConfig.value(config_key::port).toString(); - case Roles::MtuRole: return m_protocolConfig.value(config_key::mtu).toString(); + case Roles::PortRole: return m_serverProtocolConfig.value(config_key::port).toString(); + case Roles::ClientMtuRole: return m_clientProtocolConfig.value(config_key::mtu); } return QVariant(); @@ -49,17 +49,18 @@ void WireGuardConfigModel::updateModel(const QJsonObject &config) m_container = ContainerProps::containerFromString(config.value(config_key::container).toString()); m_fullConfig = config; - QJsonObject protocolConfig = config.value(config_key::wireguard).toObject(); + QJsonObject serverProtocolConfig = config.value(config_key::wireguard).toObject(); - auto defaultTransportProto = ProtocolProps::transportProtoToString(ProtocolProps::defaultTransportProto(Proto::WireGuard), Proto::WireGuard); - m_protocolConfig.insert(config_key::transport_proto, - protocolConfig.value(config_key::transport_proto).toString(defaultTransportProto)); - m_protocolConfig[config_key::last_config] = protocolConfig.value(config_key::last_config); - m_protocolConfig[config_key::port] = - protocolConfig.value(config_key::port).toString(protocols::wireguard::defaultPort); + auto defaultTransportProto = + ProtocolProps::transportProtoToString(ProtocolProps::defaultTransportProto(Proto::WireGuard), Proto::WireGuard); + m_serverProtocolConfig.insert(config_key::transport_proto, + serverProtocolConfig.value(config_key::transport_proto).toString(defaultTransportProto)); + m_serverProtocolConfig[config_key::last_config] = serverProtocolConfig.value(config_key::last_config); + m_serverProtocolConfig[config_key::port] = serverProtocolConfig.value(config_key::port).toString(protocols::wireguard::defaultPort); - m_protocolConfig[config_key::mtu] = - protocolConfig.value(config_key::mtu).toString(protocols::wireguard::defaultMtu); + auto lastConfig = m_serverProtocolConfig.value(config_key::last_config).toString(); + QJsonObject clientProtocolConfig = QJsonDocument::fromJson(lastConfig.toUtf8()).object(); + m_clientProtocolConfig[config_key::mtu] = clientProtocolConfig[config_key::mtu].toString(protocols::wireguard::defaultMtu); endResetModel(); } @@ -67,36 +68,47 @@ void WireGuardConfigModel::updateModel(const QJsonObject &config) QJsonObject WireGuardConfigModel::getConfig() { const WgConfig oldConfig(m_fullConfig.value(config_key::wireguard).toObject()); - const WgConfig newConfig(m_protocolConfig); + const WgConfig newConfig(m_serverProtocolConfig); if (!oldConfig.hasEqualServerSettings(newConfig)) { - m_protocolConfig.remove(config_key::last_config); + m_serverProtocolConfig.remove(config_key::last_config); } else { - auto lastConfig = m_protocolConfig.value(config_key::last_config).toString(); + auto lastConfig = m_serverProtocolConfig.value(config_key::last_config).toString(); QJsonObject jsonConfig = QJsonDocument::fromJson(lastConfig.toUtf8()).object(); - jsonConfig[config_key::mtu] = newConfig.mtu; + jsonConfig[config_key::mtu] = m_clientProtocolConfig[config_key::mtu]; - m_protocolConfig[config_key::last_config] = QString(QJsonDocument(jsonConfig).toJson()); + m_serverProtocolConfig[config_key::last_config] = QString(QJsonDocument(jsonConfig).toJson()); } - m_fullConfig.insert(config_key::wireguard, m_protocolConfig); + m_fullConfig.insert(config_key::wireguard, m_serverProtocolConfig); return m_fullConfig; } +bool WireGuardConfigModel::isServerSettingsEqual() +{ + const WgConfig oldConfig(m_fullConfig.value(config_key::wireguard).toObject()); + const WgConfig newConfig(m_serverProtocolConfig); + + return oldConfig.hasEqualServerSettings(newConfig); +} + QHash WireGuardConfigModel::roleNames() const { QHash roles; roles[PortRole] = "port"; - roles[MtuRole] = "mtu"; + roles[ClientMtuRole] = "clientMtu"; return roles; } -WgConfig::WgConfig(const QJsonObject &jsonConfig) +WgConfig::WgConfig(const QJsonObject &serverProtocolConfig) { - port = jsonConfig.value(config_key::port).toString(protocols::wireguard::defaultPort); - mtu = jsonConfig.value(config_key::mtu).toString(protocols::wireguard::defaultMtu); + auto lastConfig = serverProtocolConfig.value(config_key::last_config).toString(); + QJsonObject clientProtocolConfig = QJsonDocument::fromJson(lastConfig.toUtf8()).object(); + clientMtu = clientProtocolConfig[config_key::mtu].toString(protocols::wireguard::defaultMtu); + + port = serverProtocolConfig.value(config_key::port).toString(protocols::wireguard::defaultPort); } bool WgConfig::hasEqualServerSettings(const WgConfig &other) const @@ -109,7 +121,7 @@ bool WgConfig::hasEqualServerSettings(const WgConfig &other) const bool WgConfig::hasEqualClientSettings(const WgConfig &other) const { - if (mtu != other.mtu) { + if (clientMtu != other.clientMtu) { return false; } return true; diff --git a/client/ui/models/protocols/wireguardConfigModel.h b/client/ui/models/protocols/wireguardConfigModel.h index 6cec76dd..a02bea5a 100644 --- a/client/ui/models/protocols/wireguardConfigModel.h +++ b/client/ui/models/protocols/wireguardConfigModel.h @@ -11,7 +11,7 @@ struct WgConfig WgConfig(const QJsonObject &jsonConfig); QString port; - QString mtu; + QString clientMtu; bool hasEqualServerSettings(const WgConfig &other) const; bool hasEqualClientSettings(const WgConfig &other) const; @@ -25,7 +25,7 @@ class WireGuardConfigModel : public QAbstractListModel public: enum Roles { PortRole = Qt::UserRole + 1, - MtuRole + ClientMtuRole }; explicit WireGuardConfigModel(QObject *parent = nullptr); @@ -39,12 +39,15 @@ public slots: void updateModel(const QJsonObject &config); QJsonObject getConfig(); + bool isServerSettingsEqual(); + protected: QHash roleNames() const override; private: DockerContainer m_container; - QJsonObject m_protocolConfig; + QJsonObject m_serverProtocolConfig; + QJsonObject m_clientProtocolConfig; QJsonObject m_fullConfig; }; diff --git a/client/ui/models/protocols_model.cpp b/client/ui/models/protocols_model.cpp index 32447cd4..019b2d2f 100644 --- a/client/ui/models/protocols_model.cpp +++ b/client/ui/models/protocols_model.cpp @@ -16,9 +16,11 @@ QHash ProtocolsModel::roleNames() const QHash roles; roles[ProtocolNameRole] = "protocolName"; - roles[ProtocolPageRole] = "protocolPage"; + roles[ServerProtocolPageRole] = "serverProtocolPage"; + roles[ClientProtocolPageRole] = "clientProtocolPage"; roles[ProtocolIndexRole] = "protocolIndex"; roles[RawConfigRole] = "rawConfig"; + roles[IsClientProtocolExistsRole] = "isClientProtocolExists"; return roles; } @@ -34,8 +36,10 @@ QVariant ProtocolsModel::data(const QModelIndex &index, int role) const amnezia::Proto proto = ProtocolProps::protoFromString(m_content.keys().at(index.row())); return ProtocolProps::protocolHumanNames().value(proto); } - case ProtocolPageRole: - return static_cast(protocolPage(ProtocolProps::protoFromString(m_content.keys().at(index.row())))); + case ServerProtocolPageRole: + return static_cast(serverProtocolPage(ProtocolProps::protoFromString(m_content.keys().at(index.row())))); + case ClientProtocolPageRole: + return static_cast(clientProtocolPage(ProtocolProps::protoFromString(m_content.keys().at(index.row())))); case ProtocolIndexRole: return ProtocolProps::protoFromString(m_content.keys().at(index.row())); case RawConfigRole: { auto protocolConfig = m_content.value(ContainerProps::containerTypeToString(m_container)).toObject(); @@ -50,6 +54,15 @@ QVariant ProtocolsModel::data(const QModelIndex &index, int role) const } return rawConfig; } + case IsClientProtocolExistsRole: { + auto protocolConfig = m_content.value(ContainerProps::containerTypeToString(m_container)).toObject(); + auto lastConfigJsonDoc = + QJsonDocument::fromJson(protocolConfig.value(config_key::last_config).toString().toUtf8()); + auto lastConfigJson = lastConfigJsonDoc.object(); + + auto configString = lastConfigJson.value(config_key::config).toString(); + return !configString.isEmpty(); + } } return QVariant(); @@ -70,7 +83,7 @@ QJsonObject ProtocolsModel::getConfig() return config; } -PageLoader::PageEnum ProtocolsModel::protocolPage(Proto protocol) const +PageLoader::PageEnum ProtocolsModel::serverProtocolPage(Proto protocol) const { switch (protocol) { case Proto::OpenVpn: return PageLoader::PageEnum::PageProtocolOpenVpnSettings; @@ -90,3 +103,12 @@ PageLoader::PageEnum ProtocolsModel::protocolPage(Proto protocol) const default: return PageLoader::PageEnum::PageProtocolOpenVpnSettings; } } + +PageLoader::PageEnum ProtocolsModel::clientProtocolPage(Proto protocol) const +{ + switch (protocol) { + case Proto::WireGuard: return PageLoader::PageEnum::PageProtocolWireGuardClientSettings; + case Proto::Awg: return PageLoader::PageEnum::PageProtocolAwgClientSettings; + default: return PageLoader::PageEnum::PageProtocolOpenVpnSettings; + } +} diff --git a/client/ui/models/protocols_model.h b/client/ui/models/protocols_model.h index 5ee8a3dd..5c52ee86 100644 --- a/client/ui/models/protocols_model.h +++ b/client/ui/models/protocols_model.h @@ -13,9 +13,11 @@ class ProtocolsModel : public QAbstractListModel public: enum Roles { ProtocolNameRole = Qt::UserRole + 1, - ProtocolPageRole, + ServerProtocolPageRole, + ClientProtocolPageRole, ProtocolIndexRole, - RawConfigRole + RawConfigRole, + IsClientProtocolExistsRole }; ProtocolsModel(std::shared_ptr settings, QObject *parent = nullptr); @@ -33,7 +35,8 @@ protected: QHash roleNames() const override; private: - PageLoader::PageEnum protocolPage(Proto protocol) const; + PageLoader::PageEnum serverProtocolPage(Proto protocol) const; + PageLoader::PageEnum clientProtocolPage(Proto protocol) const; std::shared_ptr m_settings; diff --git a/client/ui/qml/Pages2/PageProtocolAwgClientSettings.qml b/client/ui/qml/Pages2/PageProtocolAwgClientSettings.qml new file mode 100644 index 00000000..2b912f18 --- /dev/null +++ b/client/ui/qml/Pages2/PageProtocolAwgClientSettings.qml @@ -0,0 +1,312 @@ +import QtQuick +import QtQuick.Controls +import QtQuick.Layouts + +import SortFilterProxyModel 0.2 + +import PageEnum 1.0 + +import "./" +import "../Controls2" +import "../Controls2/TextTypes" +import "../Config" +import "../Components" + + +PageType { + id: root + + defaultActiveFocusItem: listview.currentItem.mtuTextField.textField + + Item { + id: focusItem + onFocusChanged: { + if (activeFocus) { + fl.ensureVisible(focusItem) + } + } + KeyNavigation.tab: backButton + } + + ColumnLayout { + id: backButtonLayout + + anchors.top: parent.top + anchors.left: parent.left + anchors.right: parent.right + + anchors.topMargin: 20 + + BackButtonType { + id: backButton + KeyNavigation.tab: listview.currentItem.mtuTextField.textField + } + } + + FlickableType { + id: fl + anchors.top: backButtonLayout.bottom + anchors.bottom: parent.bottom + contentHeight: content.implicitHeight + saveButton.implicitHeight + saveButton.anchors.bottomMargin + saveButton.anchors.topMargin + + Column { + id: content + + anchors.top: parent.top + anchors.left: parent.left + anchors.right: parent.right + + ListView { + id: listview + + width: parent.width + height: listview.contentItem.height + + clip: true + interactive: false + + model: AwgConfigModel + + delegate: Item { + id: delegateItem + implicitWidth: listview.width + implicitHeight: col.implicitHeight + + property alias mtuTextField: mtuTextField + property bool isSaveButtonEnabled: mtuTextField.errorText === "" && + junkPacketMaxSizeTextField.errorText === "" && + junkPacketMinSizeTextField.errorText === "" && + junkPacketCountTextField.errorText === "" + + ColumnLayout { + id: col + + anchors.top: parent.top + anchors.left: parent.left + anchors.right: parent.right + + anchors.leftMargin: 16 + anchors.rightMargin: 16 + + spacing: 0 + + HeaderType { + Layout.fillWidth: true + + headerText: qsTr("AmneziaWG settings") + } + + TextFieldWithHeaderType { + id: mtuTextField + Layout.fillWidth: true + Layout.topMargin: 40 + + headerText: qsTr("MTU") + textFieldText: clientMtu + textField.validator: IntValidator { bottom: 576; top: 65535 } + + textField.onEditingFinished: { + if (textFieldText !== clientMtu) { + clientMtu = textFieldText + } + } + checkEmptyText: true + KeyNavigation.tab: junkPacketCountTextField.textField + } + + TextFieldWithHeaderType { + id: junkPacketCountTextField + Layout.fillWidth: true + Layout.topMargin: 16 + + headerText: "Jc - Junk packet count" + textFieldText: clientJunkPacketCount + textField.validator: IntValidator { bottom: 0 } + parentFlickable: fl + + textField.onEditingFinished: { + if (textFieldText !== clientJunkPacketCount) { + clientJunkPacketCount = textFieldText + } + } + + checkEmptyText: true + + KeyNavigation.tab: junkPacketMinSizeTextField.textField + } + + TextFieldWithHeaderType { + id: junkPacketMinSizeTextField + Layout.fillWidth: true + Layout.topMargin: 16 + + headerText: "Jmin - Junk packet minimum size" + textFieldText: clientJunkPacketMinSize + textField.validator: IntValidator { bottom: 0 } + parentFlickable: fl + + textField.onEditingFinished: { + if (textFieldText !== clientJunkPacketMinSize) { + clientJunkPacketMinSize = textFieldText + } + } + + checkEmptyText: true + + KeyNavigation.tab: junkPacketMaxSizeTextField.textField + } + + TextFieldWithHeaderType { + id: junkPacketMaxSizeTextField + Layout.fillWidth: true + Layout.topMargin: 16 + + headerText: "Jmax - Junk packet maximum size" + textFieldText: clientJunkPacketMaxSize + textField.validator: IntValidator { bottom: 0 } + parentFlickable: fl + + textField.onEditingFinished: { + if (textFieldText !== clientJunkPacketMaxSize) { + clientJunkPacketMaxSize = textFieldText + } + } + + checkEmptyText: true + + Keys.onTabPressed: saveButton.forceActiveFocus() + } + + Header2TextType { + Layout.fillWidth: true + Layout.topMargin: 16 + + text: qsTr("Server settings") + } + + TextFieldWithHeaderType { + id: portTextField + Layout.fillWidth: true + Layout.topMargin: 8 + + enabled: false + + headerText: qsTr("Port") + textFieldText: port + } + + TextFieldWithHeaderType { + id: initPacketJunkSizeTextField + Layout.fillWidth: true + Layout.topMargin: 16 + + enabled: false + + headerText: "S1 - Init packet junk size" + textFieldText: serverInitPacketJunkSize + } + + TextFieldWithHeaderType { + id: responsePacketJunkSizeTextField + Layout.fillWidth: true + Layout.topMargin: 16 + + enabled: false + + headerText: "S2 - Response packet junk size" + textFieldText: serverResponsePacketJunkSize + } + + TextFieldWithHeaderType { + id: initPacketMagicHeaderTextField + Layout.fillWidth: true + Layout.topMargin: 16 + + enabled: false + + headerText: "H1 - Init packet magic header" + textFieldText: serverInitPacketMagicHeader + } + + TextFieldWithHeaderType { + id: responsePacketMagicHeaderTextField + Layout.fillWidth: true + Layout.topMargin: 16 + + enabled: false + + headerText: "H2 - Response packet magic header" + textFieldText: serverResponsePacketMagicHeader + } + + TextFieldWithHeaderType { + id: underloadPacketMagicHeaderTextField + Layout.fillWidth: true + Layout.topMargin: 16 + parentFlickable: fl + + enabled: false + + headerText: "H3 - Underload packet magic header" + textFieldText: serverUnderloadPacketMagicHeader + } + + TextFieldWithHeaderType { + id: transportPacketMagicHeaderTextField + Layout.fillWidth: true + Layout.topMargin: 16 + + enabled: false + + headerText: "H4 - Transport packet magic header" + textFieldText: serverTransportPacketMagicHeader + } + } + } + } + } + } + + BasicButtonType { + id: saveButton + + anchors.right: root.right + anchors.left: root.left + anchors.bottom: root.bottom + + anchors.topMargin: 24 + anchors.bottomMargin: 24 + anchors.rightMargin: 16 + anchors.leftMargin: 16 + + enabled: listview.currentItem.isSaveButtonEnabled + + text: qsTr("Save") + + Keys.onTabPressed: lastItemTabClicked(focusItem) + + clickedFunc: function() { + forceActiveFocus() + var headerText = qsTr("Save settings?") + var descriptionText = qsTr("Only the settings for this device will be changed") + var yesButtonText = qsTr("Continue") + var noButtonText = qsTr("Cancel") + + var yesButtonFunction = function() { + if (ConnectionController.isConnected && ServersModel.getDefaultServerData("defaultContainer") === ContainersModel.getProcessedContainerIndex()) { + PageController.showNotificationMessage(qsTr("Unable change settings while there is an active connection")) + return + } + + PageController.goToPage(PageEnum.PageSetupWizardInstalling); + InstallController.updateContainer(AwgConfigModel.getConfig()) + } + var noButtonFunction = function() { + if (!GC.isMobile()) { + saveButton.forceActiveFocus() + } + } + showQuestionDrawer(headerText, descriptionText, yesButtonText, noButtonText, yesButtonFunction, noButtonFunction) + } + } +} diff --git a/client/ui/qml/Pages2/PageProtocolAwgSettings.qml b/client/ui/qml/Pages2/PageProtocolAwgSettings.qml index 8651fa27..27ea66f9 100644 --- a/client/ui/qml/Pages2/PageProtocolAwgSettings.qml +++ b/client/ui/qml/Pages2/PageProtocolAwgSettings.qml @@ -57,8 +57,6 @@ PageType { anchors.left: parent.left anchors.right: parent.right - enabled: ServersModel.isProcessedServerHasWriteAccess() - ListView { id: listview @@ -71,12 +69,12 @@ PageType { model: AwgConfigModel delegate: Item { - id: _delegate - + id: delegateItem implicitWidth: listview.width implicitHeight: col.implicitHeight - property alias portTextField:portTextField + property alias portTextField: portTextField + property bool isEnabled: ServersModel.isProcessedServerHasWriteAccess() ColumnLayout { id: col @@ -101,6 +99,8 @@ PageType { Layout.fillWidth: true Layout.topMargin: 40 + enabled: delegateItem.isEnabled + headerText: qsTr("Port") textFieldText: port textField.maximumLength: 5 @@ -115,27 +115,6 @@ PageType { checkEmptyText: true - KeyNavigation.tab: mtuTextField.textField - } - - TextFieldWithHeaderType { - id: mtuTextField - Layout.fillWidth: true - Layout.topMargin: 16 - - headerText: qsTr("MTU") - textFieldText: mtu - textField.validator: IntValidator { bottom: 576; top: 65535 } - - textField.onEditingFinished: { - if (textFieldText === "") { - textFieldText = "0" - } - if (textFieldText !== mtu) { - mtu = textFieldText - } - } - checkEmptyText: true KeyNavigation.tab: junkPacketCountTextField.textField } @@ -145,7 +124,7 @@ PageType { Layout.topMargin: 16 headerText: qsTr("Jc - Junk packet count") - textFieldText: junkPacketCount + textFieldText: serverJunkPacketCount textField.validator: IntValidator { bottom: 0 } parentFlickable: fl @@ -154,8 +133,8 @@ PageType { textFieldText = "0" } - if (textFieldText !== junkPacketCount) { - junkPacketCount = textFieldText + if (textFieldText !== serverJunkPacketCount) { + serverJunkPacketCount = textFieldText } } @@ -170,13 +149,13 @@ PageType { Layout.topMargin: 16 headerText: qsTr("Jmin - Junk packet minimum size") - textFieldText: junkPacketMinSize + textFieldText: serverJunkPacketMinSize textField.validator: IntValidator { bottom: 0 } parentFlickable: fl textField.onEditingFinished: { - if (textFieldText !== junkPacketMinSize) { - junkPacketMinSize = textFieldText + if (textFieldText !== serverJunkPacketMinSize) { + serverJunkPacketMinSize = textFieldText } } @@ -191,13 +170,13 @@ PageType { Layout.topMargin: 16 headerText: qsTr("Jmax - Junk packet maximum size") - textFieldText: junkPacketMaxSize + textFieldText: serverJunkPacketMaxSize textField.validator: IntValidator { bottom: 0 } parentFlickable: fl textField.onEditingFinished: { - if (textFieldText !== junkPacketMaxSize) { - junkPacketMaxSize = textFieldText + if (textFieldText !== serverJunkPacketMaxSize) { + serverJunkPacketMaxSize = textFieldText } } @@ -212,13 +191,13 @@ PageType { Layout.topMargin: 16 headerText: qsTr("S1 - Init packet junk size") - textFieldText: initPacketJunkSize + textFieldText: serverInitPacketJunkSize textField.validator: IntValidator { bottom: 0 } parentFlickable: fl textField.onEditingFinished: { - if (textFieldText !== initPacketJunkSize) { - initPacketJunkSize = textFieldText + if (textFieldText !== serverInitPacketJunkSize) { + serverInitPacketJunkSize = textFieldText } } @@ -233,13 +212,13 @@ PageType { Layout.topMargin: 16 headerText: qsTr("S2 - Response packet junk size") - textFieldText: responsePacketJunkSize + textFieldText: serverResponsePacketJunkSize textField.validator: IntValidator { bottom: 0 } parentFlickable: fl textField.onEditingFinished: { - if (textFieldText !== responsePacketJunkSize) { - responsePacketJunkSize = textFieldText + if (textFieldText !== serverResponsePacketJunkSize) { + serverResponsePacketJunkSize = textFieldText } } @@ -254,13 +233,13 @@ PageType { Layout.topMargin: 16 headerText: qsTr("H1 - Init packet magic header") - textFieldText: initPacketMagicHeader + textFieldText: serverInitPacketMagicHeader textField.validator: IntValidator { bottom: 0 } parentFlickable: fl textField.onEditingFinished: { - if (textFieldText !== initPacketMagicHeader) { - initPacketMagicHeader = textFieldText + if (textFieldText !== serverInitPacketMagicHeader) { + serverInitPacketMagicHeader = textFieldText } } @@ -275,13 +254,13 @@ PageType { Layout.topMargin: 16 headerText: qsTr("H2 - Response packet magic header") - textFieldText: responsePacketMagicHeader + textFieldText: serverResponsePacketMagicHeader textField.validator: IntValidator { bottom: 0 } parentFlickable: fl textField.onEditingFinished: { - if (textFieldText !== responsePacketMagicHeader) { - responsePacketMagicHeader = textFieldText + if (textFieldText !== serverResponsePacketMagicHeader) { + serverResponsePacketMagicHeader = textFieldText } } @@ -296,13 +275,13 @@ PageType { Layout.topMargin: 16 headerText: qsTr("H4 - Transport packet magic header") - textFieldText: transportPacketMagicHeader + textFieldText: serverTransportPacketMagicHeader textField.validator: IntValidator { bottom: 0 } parentFlickable: fl textField.onEditingFinished: { - if (textFieldText !== transportPacketMagicHeader) { - transportPacketMagicHeader = textFieldText + if (textFieldText !== serverTransportPacketMagicHeader) { + serverTransportPacketMagicHeader = textFieldText } } @@ -318,12 +297,12 @@ PageType { parentFlickable: fl headerText: qsTr("H3 - Underload packet magic header") - textFieldText: underloadPacketMagicHeader + textFieldText: serverUnderloadPacketMagicHeader textField.validator: IntValidator { bottom: 0 } textField.onEditingFinished: { - if (textFieldText !== underloadPacketMagicHeader) { - underloadPacketMagicHeader = textFieldText + if (textFieldText !== serverUnderloadPacketMagicHeader) { + serverUnderloadPacketMagicHeader = textFieldText } } @@ -356,18 +335,22 @@ PageType { Keys.onTabPressed: lastItemTabClicked(focusItem) clickedFunc: function() { - if (AwgConfigModel.isHeadersEqual(underloadPacketMagicHeaderTextField.textField.text, - transportPacketMagicHeaderTextField.textField.text, - responsePacketMagicHeaderTextField.textField.text, - initPacketMagicHeaderTextField.textField.text)) { - PageController.showErrorMessage(qsTr("The values of the H1-H4 fields must be unique")) - return - } + forceActiveFocus() - if (AwgConfigModel.isPacketSizeEqual(parseInt(initPacketJunkSizeTextField.textField.text), - parseInt(responsePacketJunkSizeTextField.textField.text))) { - PageController.showErrorMessage(qsTr("The value of the field S1 + message initiation size (148) must not equal S2 + message response size (92)")) - return + if (delegateItem.isEnabled) { + if (AwgConfigModel.isHeadersEqual(underloadPacketMagicHeaderTextField.textField.text, + transportPacketMagicHeaderTextField.textField.text, + responsePacketMagicHeaderTextField.textField.text, + initPacketMagicHeaderTextField.textField.text)) { + PageController.showErrorMessage(qsTr("The values of the H1-H4 fields must be unique")) + return + } + + if (AwgConfigModel.isPacketSizeEqual(parseInt(initPacketJunkSizeTextField.textField.text), + parseInt(responsePacketJunkSizeTextField.textField.text))) { + PageController.showErrorMessage(qsTr("The value of the field S1 + message initiation size (148) must not equal S2 + message response size (92)")) + return + } } var headerText = qsTr("Save settings?") @@ -376,8 +359,6 @@ PageType { var noButtonText = qsTr("Cancel") var yesButtonFunction = function() { - forceActiveFocus() - if (ConnectionController.isConnected && ServersModel.getDefaultServerData("defaultContainer") === ContainersModel.getProcessedContainerIndex()) { PageController.showNotificationMessage(qsTr("Unable change settings while there is an active connection")) return diff --git a/client/ui/qml/Pages2/PageProtocolWireGuardClientSettings.qml b/client/ui/qml/Pages2/PageProtocolWireGuardClientSettings.qml new file mode 100644 index 00000000..007de5ca --- /dev/null +++ b/client/ui/qml/Pages2/PageProtocolWireGuardClientSettings.qml @@ -0,0 +1,179 @@ +import QtQuick +import QtQuick.Controls +import QtQuick.Layouts + +import SortFilterProxyModel 0.2 + +import PageEnum 1.0 + +import "./" +import "../Controls2" +import "../Controls2/TextTypes" +import "../Config" +import "../Components" + + +PageType { + id: root + + defaultActiveFocusItem: listview.currentItem.mtuTextField.textField + + Item { + id: focusItem + onFocusChanged: { + if (activeFocus) { + fl.ensureVisible(focusItem) + } + } + KeyNavigation.tab: backButton + } + + ColumnLayout { + id: backButtonLayout + + anchors.top: parent.top + anchors.left: parent.left + anchors.right: parent.right + + anchors.topMargin: 20 + + BackButtonType { + id: backButton + KeyNavigation.tab: listview.currentItem.mtuTextField.textField + } + } + + FlickableType { + id: fl + anchors.top: backButtonLayout.bottom + anchors.bottom: parent.bottom + contentHeight: content.implicitHeight + saveButton.implicitHeight + saveButton.anchors.bottomMargin + saveButton.anchors.topMargin + + Column { + id: content + + anchors.top: parent.top + anchors.left: parent.left + anchors.right: parent.right + + ListView { + id: listview + + width: parent.width + height: listview.contentItem.height + + clip: true + interactive: false + + model: WireGuardConfigModel + + delegate: Item { + id: delegateItem + implicitWidth: listview.width + implicitHeight: col.implicitHeight + + property alias mtuTextField: mtuTextField + property bool isSaveButtonEnabled: mtuTextField.errorText === "" + + ColumnLayout { + id: col + + anchors.top: parent.top + anchors.left: parent.left + anchors.right: parent.right + + anchors.leftMargin: 16 + anchors.rightMargin: 16 + + spacing: 0 + + HeaderType { + Layout.fillWidth: true + + headerText: qsTr("WG settings") + } + + TextFieldWithHeaderType { + id: mtuTextField + Layout.fillWidth: true + Layout.topMargin: 40 + + headerText: qsTr("MTU") + textFieldText: clientMtu + textField.validator: IntValidator { bottom: 576; top: 65535 } + + textField.onEditingFinished: { + if (textFieldText !== clientMtu) { + clientMtu = textFieldText + } + } + checkEmptyText: true + KeyNavigation.tab: saveButton + } + + Header2TextType { + Layout.fillWidth: true + Layout.topMargin: 16 + + text: qsTr("Server settings") + } + + TextFieldWithHeaderType { + id: portTextField + Layout.fillWidth: true + Layout.topMargin: 8 + + enabled: false + + headerText: qsTr("Port") + textFieldText: port + } + } + } + } + } + } + + BasicButtonType { + id: saveButton + + anchors.right: root.right + anchors.left: root.left + anchors.bottom: root.bottom + + anchors.topMargin: 24 + anchors.bottomMargin: 24 + anchors.rightMargin: 16 + anchors.leftMargin: 16 + + enabled: listview.currentItem.isSaveButtonEnabled + + text: qsTr("Save") + + Keys.onTabPressed: lastItemTabClicked(focusItem) + + clickedFunc: function() { + forceActiveFocus() + var headerText = qsTr("Save settings?") + var descriptionText = qsTr("Only the settings for this device will be changed") + var yesButtonText = qsTr("Continue") + var noButtonText = qsTr("Cancel") + + var yesButtonFunction = function() { + if (ConnectionController.isConnected && ServersModel.getDefaultServerData("defaultContainer") === ContainersModel.getProcessedContainerIndex()) { + PageController.showNotificationMessage(qsTr("Unable change settings while there is an active connection")) + return + } + + PageController.goToPage(PageEnum.PageSetupWizardInstalling); + InstallController.updateContainer(WireGuardConfigModel.getConfig()) + } + var noButtonFunction = function() { + if (!GC.isMobile()) { + saveButton.forceActiveFocus() + } + } + showQuestionDrawer(headerText, descriptionText, yesButtonText, noButtonText, yesButtonFunction, noButtonFunction) + } + } +} diff --git a/client/ui/qml/Pages2/PageProtocolWireGuardSettings.qml b/client/ui/qml/Pages2/PageProtocolWireGuardSettings.qml index 758375b1..b5d08132 100644 --- a/client/ui/qml/Pages2/PageProtocolWireGuardSettings.qml +++ b/client/ui/qml/Pages2/PageProtocolWireGuardSettings.qml @@ -72,7 +72,10 @@ PageType { } delegate: Item { + id: delegateItem + property alias focusItemId: portTextField.textField + property bool isEnabled: ServersModel.isProcessedServerHasWriteAccess() implicitWidth: listview.width implicitHeight: col.implicitHeight @@ -99,12 +102,14 @@ PageType { Layout.fillWidth: true Layout.topMargin: 40 + enabled: delegateItem.isEnabled + headerText: qsTr("Port") textFieldText: port textField.maximumLength: 5 textField.validator: IntValidator { bottom: 1; top: 65535 } - KeyNavigation.tab: mtuTextField.textField + KeyNavigation.tab: saveButton textField.onEditingFinished: { if (textFieldText !== port) { @@ -115,52 +120,41 @@ PageType { checkEmptyText: true } - TextFieldWithHeaderType { - id: mtuTextField - Layout.fillWidth: true - Layout.topMargin: 16 - - headerText: qsTr("MTU") - textFieldText: mtu - textField.validator: IntValidator { bottom: 576; top: 65535 } - - KeyNavigation.tab: saveButton - - textField.onEditingFinished: { - if (textFieldText === "") { - textFieldText = "0" - } - if (textFieldText !== mtu) { - mtu = textFieldText - } - } - checkEmptyText: true - } - BasicButtonType { id: saveButton Layout.fillWidth: true Layout.topMargin: 24 Layout.bottomMargin: 24 - enabled: mtuTextField.errorText === "" && - portTextField.errorText === "" + enabled: portTextField.errorText === "" text: qsTr("Save") Keys.onTabPressed: lastItemTabClicked(focusItem) - onClicked: { + onClicked: function() { forceActiveFocus() - if (ConnectionController.isConnected && ServersModel.getDefaultServerData("defaultContainer") === ContainersModel.getProcessedContainerIndex()) { - PageController.showNotificationMessage(qsTr("Unable change settings while there is an active connection")) - return - } + var headerText = qsTr("Save settings?") + var descriptionText = qsTr("All users with whom you shared a connection with will no longer be able to connect to it.") + var yesButtonText = qsTr("Continue") + var noButtonText = qsTr("Cancel") - PageController.goToPage(PageEnum.PageSetupWizardInstalling); - InstallController.updateContainer(WireGuardConfigModel.getConfig()) - focusItem.forceActiveFocus() + var yesButtonFunction = function() { + if (ConnectionController.isConnected && ServersModel.getDefaultServerData("defaultContainer") === ContainersModel.getProcessedContainerIndex()) { + PageController.showNotificationMessage(qsTr("Unable change settings while there is an active connection")) + return + } + + PageController.goToPage(PageEnum.PageSetupWizardInstalling); + InstallController.updateContainer(WireGuardConfigModel.getConfig()) + } + var noButtonFunction = function() { + if (!GC.isMobile()) { + saveRestartButton.forceActiveFocus() + } + } + showQuestionDrawer(headerText, descriptionText, yesButtonText, noButtonText, yesButtonFunction, noButtonFunction) } Keys.onEnterPressed: saveButton.clicked() diff --git a/client/ui/qml/Pages2/PageSettingsServerProtocol.qml b/client/ui/qml/Pages2/PageSettingsServerProtocol.qml index 6410156d..dcdf01af 100644 --- a/client/ui/qml/Pages2/PageSettingsServerProtocol.qml +++ b/client/ui/qml/Pages2/PageSettingsServerProtocol.qml @@ -79,7 +79,7 @@ PageType { } delegate: Item { - property var focusItem: button.rightButton + property var focusItem: clientSettings.rightButton implicitWidth: protocols.width implicitHeight: delegateContent.implicitHeight @@ -89,13 +89,49 @@ PageType { anchors.fill: parent + property bool isClientSettingsVisible: protocolIndex === ProtocolEnum.WireGuard || protocolIndex === ProtocolEnum.Awg + property bool isServerSettingsVisible: ServersModel.isProcessedServerHasWriteAccess() + LabelWithButtonType { - id: button + id: clientSettings Layout.fillWidth: true - text: protocolName + text: protocolName + qsTr(" connection settings") rightImageSource: "qrc:/images/controls/chevron-right.svg" + visible: delegateContent.isClientSettingsVisible + + clickedFunction: function() { + if (isClientProtocolExists) { + switch (protocolIndex) { + case ProtocolEnum.WireGuard: WireGuardConfigModel.updateModel(ProtocolsModel.getConfig()); break; + case ProtocolEnum.Awg: AwgConfigModel.updateModel(ProtocolsModel.getConfig()); break; + } + PageController.goToPage(clientProtocolPage); + } else { + PageController.showNotificationMessage(qsTr("Click the \"connect\" button to create a connection configuration")) + } + } + + MouseArea { + anchors.fill: clientSettings + cursorShape: Qt.PointingHandCursor + enabled: false + } + } + + DividerType { + visible: delegateContent.isClientSettingsVisible + } + + LabelWithButtonType { + id: serverSettings + + Layout.fillWidth: true + + text: protocolName + qsTr(" server settings") + rightImageSource: "qrc:/images/controls/chevron-right.svg" + visible: delegateContent.isServerSettingsVisible clickedFunction: function() { switch (protocolIndex) { @@ -109,17 +145,19 @@ PageType { case ProtocolEnum.Ipsec: Ikev2ConfigModel.updateModel(ProtocolsModel.getConfig()); break; case ProtocolEnum.Socks5Proxy: Socks5ProxyConfigModel.updateModel(ProtocolsModel.getConfig()); break; } - PageController.goToPage(protocolPage); + PageController.goToPage(serverProtocolPage); } MouseArea { - anchors.fill: button + anchors.fill: serverSettings cursorShape: Qt.PointingHandCursor enabled: false } } - DividerType {} + DividerType { + visible: delegateContent.isServerSettingsVisible + } } } } @@ -132,11 +170,11 @@ PageType { visible: root.isClearCacheVisible KeyNavigation.tab: removeButton - text: qsTr("Clear %1 profile").arg(ContainersModel.getProcessedContainerName()) + text: qsTr("Clear profile") clickedFunction: function() { var headerText = qsTr("Clear %1 profile?").arg(ContainersModel.getProcessedContainerName()) - var descriptionText = qsTr("") + var descriptionText = qsTr("The connection configuration will be deleted for this device only") var yesButtonText = qsTr("Continue") var noButtonText = qsTr("Cancel") @@ -183,7 +221,7 @@ PageType { visible: ServersModel.isProcessedServerHasWriteAccess() Keys.onTabPressed: lastItemTabClicked(focusItem) - text: qsTr("Remove ") + ContainersModel.getProcessedContainerName() + text: qsTr("Remove ") textColor: AmneziaStyle.color.vibrantRed clickedFunction: function() { diff --git a/client/ui/qml/Pages2/PageSetupWizardCredentials.qml b/client/ui/qml/Pages2/PageSetupWizardCredentials.qml index 7f1c3eed..aced12b1 100644 --- a/client/ui/qml/Pages2/PageSetupWizardCredentials.qml +++ b/client/ui/qml/Pages2/PageSetupWizardCredentials.qml @@ -60,9 +60,6 @@ PageType { Layout.fillWidth: true headerText: qsTr("Server IP address [:port]") textFieldPlaceholderText: qsTr("255.255.255.255:22") - textField.validator: RegularExpressionValidator { - regularExpression: InstallController.ipAddressPortRegExp() - } textField.onFocusChanged: { textField.text = textField.text.replace(/^\s+|\s+$/g, '') diff --git a/client/ui/qml/Pages2/PageShare.qml b/client/ui/qml/Pages2/PageShare.qml index 33577d74..6640df36 100644 --- a/client/ui/qml/Pages2/PageShare.qml +++ b/client/ui/qml/Pages2/PageShare.qml @@ -840,6 +840,14 @@ PageType { text: qsTr("Data sent: %1").arg(dataSent) } + + ParagraphTextType { + color: textColumn.textColor + visible: allowedIps + Layout.fillWidth: true + + text: qsTr("Allowed IPs: %1").arg(allowedIps) + } } Item { diff --git a/client/vpnconnection.cpp b/client/vpnconnection.cpp index daff1187..591e396f 100644 --- a/client/vpnconnection.cpp +++ b/client/vpnconnection.cpp @@ -1,16 +1,16 @@ #include "qtimer.h" #include +#include #include #include #include -#include +#include "core/controllers/serverController.h" #include #include #include #include -#include "core/controllers/serverController.h" #ifdef AMNEZIA_DESKTOP #include "core/ipcclient.h" @@ -34,8 +34,7 @@ VpnConnection::VpnConnection(std::shared_ptr settings, QObject *parent { m_checkTimer.setInterval(1000); #ifdef Q_OS_IOS - connect(IosController::Instance(), &IosController::connectionStateChanged, this, - &VpnConnection::onConnectionStateChanged); + connect(IosController::Instance(), &IosController::connectionStateChanged, this, &VpnConnection::onConnectionStateChanged); connect(IosController::Instance(), &IosController::bytesChanged, this, &VpnConnection::onBytesChanged); #endif @@ -58,7 +57,7 @@ void VpnConnection::onConnectionStateChanged(Vpn::ConnectionState state) #ifdef AMNEZIA_DESKTOP QString proto = m_settings->defaultContainerName(m_settings->defaultServerIndex()); - + if (IpcClient::Interface()) { if (state == Vpn::ConnectionState::Connected) { IpcClient::Interface()->resetIpStack(); @@ -72,7 +71,7 @@ void VpnConnection::onConnectionStateChanged(Vpn::ConnectionState state) if (m_settings->isSitesSplitTunnelingEnabled()) { IpcClient::Interface()->routeDeleteList(m_vpnProtocol->vpnGateway(), QStringList() << "0.0.0.0"); - // qDebug() << "VpnConnection::onConnectionStateChanged :: adding custom routes, count:" << forwardIps.size(); + // qDebug() << "VpnConnection::onConnectionStateChanged :: adding custom routes, count:" << forwardIps.size(); if (m_settings->routeMode() == Settings::VpnOnlyForwardSites) { QTimer::singleShot(1000, m_vpnProtocol.data(), [this]() { addSitesRoutes(m_vpnProtocol->vpnGateway(), m_settings->routeMode()); }); @@ -234,7 +233,7 @@ void VpnConnection::connectToVpn(int serverIndex, const ServerCredentials &crede } #endif - m_remoteAddress = credentials.hostName; + m_remoteAddress = NetworkUtilities::getIPAddress(credentials.hostName); emit connectionStateChanged(Vpn::ConnectionState::Connecting); m_vpnConfiguration = vpnConfiguration; @@ -291,27 +290,62 @@ void VpnConnection::appendKillSwitchConfig() void VpnConnection::appendSplitTunnelingConfig() { - if (m_vpnConfiguration.value(config_key::configVersion).toInt()) { - auto protocolName = m_vpnConfiguration.value(config_key::vpnproto).toString(); - if (protocolName == ProtocolProps::protoToString(Proto::Awg)) { - auto configData = m_vpnConfiguration.value(protocolName + "_config_data").toObject(); - QJsonArray allowedIpsJsonArray = QJsonArray::fromStringList(configData.value("allowed_ips").toString().split(",")); - QJsonArray defaultAllowedIP = QJsonArray::fromStringList(QString("0.0.0.0/0, ::/0").split(",")); + bool allowSiteBasedSplitTunneling = true; - if (allowedIpsJsonArray != defaultAllowedIP) { - allowedIpsJsonArray.append(m_vpnConfiguration.value(config_key::dns1).toString()); - allowedIpsJsonArray.append(m_vpnConfiguration.value(config_key::dns2).toString()); - - m_vpnConfiguration.insert(config_key::splitTunnelType, Settings::RouteMode::VpnOnlyForwardSites); - m_vpnConfiguration.insert(config_key::splitTunnelSites, allowedIpsJsonArray); + // this block is for old native configs and for old self-hosted configs + auto protocolName = m_vpnConfiguration.value(config_key::vpnproto).toString(); + if (protocolName == ProtocolProps::protoToString(Proto::Awg) || protocolName == ProtocolProps::protoToString(Proto::WireGuard)) { + allowSiteBasedSplitTunneling = false; + auto configData = m_vpnConfiguration.value(protocolName + "_config_data").toObject(); + if (configData.value(config_key::allowed_ips).isString()) { + QJsonArray allowedIpsJsonArray = QJsonArray::fromStringList(configData.value(config_key::allowed_ips).toString().split(", ")); + configData.insert(config_key::allowed_ips, allowedIpsJsonArray); + m_vpnConfiguration.insert(protocolName + "_config_data", configData); + } else if (configData.value(config_key::allowed_ips).isUndefined()) { + auto nativeConfig = configData.value(config_key::config).toString(); + auto nativeConfigLines = nativeConfig.split("\n"); + for (auto &line : nativeConfigLines) { + if (line.contains("AllowedIPs")) { + auto allowedIpsString = line.split(" = "); + if (allowedIpsString.size() < 1) { + break; + } + QJsonArray allowedIpsJsonArray = QJsonArray::fromStringList(allowedIpsString.at(1).split(", ")); + configData.insert(config_key::allowed_ips, allowedIpsJsonArray); + m_vpnConfiguration.insert(protocolName + "_config_data", configData); + break; + } } } - } else { - Settings::RouteMode routeMode = Settings::RouteMode::VpnAllSites; - QJsonArray sitesJsonArray; - if (m_settings->isSitesSplitTunnelingEnabled()) { - routeMode = m_settings->routeMode(); + if (configData.value(config_key::persistent_keep_alive).isUndefined()) { + auto nativeConfig = configData.value(config_key::config).toString(); + auto nativeConfigLines = nativeConfig.split("\n"); + for (auto &line : nativeConfigLines) { + if (line.contains("PersistentKeepalive")) { + auto persistentKeepaliveString = line.split(" = "); + if (persistentKeepaliveString.size() < 1) { + break; + } + configData.insert(config_key::persistent_keep_alive, persistentKeepaliveString.at(1)); + m_vpnConfiguration.insert(protocolName + "_config_data", configData); + break; + } + } + } + + QJsonArray allowedIpsJsonArray = configData.value(config_key::allowed_ips).toArray(); + if (allowedIpsJsonArray.contains("0.0.0.0/0") && allowedIpsJsonArray.contains("::/0")) { + allowSiteBasedSplitTunneling = true; + } + } + + Settings::RouteMode routeMode = Settings::RouteMode::VpnAllSites; + QJsonArray sitesJsonArray; + if (m_settings->isSitesSplitTunnelingEnabled()) { + routeMode = m_settings->routeMode(); + + if (allowSiteBasedSplitTunneling) { auto sites = m_settings->getVpnIps(routeMode); for (const auto &site : sites) { sitesJsonArray.append(site); @@ -323,11 +357,11 @@ void VpnConnection::appendSplitTunnelingConfig() sitesJsonArray.append(m_vpnConfiguration.value(config_key::dns2).toString()); } } - - m_vpnConfiguration.insert(config_key::splitTunnelType, routeMode); - m_vpnConfiguration.insert(config_key::splitTunnelSites, sitesJsonArray); } + m_vpnConfiguration.insert(config_key::splitTunnelType, routeMode); + m_vpnConfiguration.insert(config_key::splitTunnelSites, sitesJsonArray); + Settings::AppsRouteMode appsRouteMode = Settings::AppsRouteMode::VpnAllApps; QJsonArray appsJsonArray; if (m_settings->isAppsSplitTunnelingEnabled()) { @@ -359,8 +393,7 @@ void VpnConnection::createAndroidConnections() connect(AndroidController::instance(), &AndroidController::connectionStateChanged, androidVpnProtocol, &AndroidVpnProtocol::setConnectionState); - connect(AndroidController::instance(), &AndroidController::statisticsUpdated, androidVpnProtocol, - &AndroidVpnProtocol::setBytesChanged); + connect(AndroidController::instance(), &AndroidController::statisticsUpdated, androidVpnProtocol, &AndroidVpnProtocol::setBytesChanged); } AndroidVpnProtocol *VpnConnection::createDefaultAndroidVpnProtocol()