mirror of
https://github.com/amnezia-vpn/amnezia-client.git
synced 2026-08-22 11:09:30 +03:00
Compare commits
6 Commits
dev
...
feat/split
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
6b7d0fdb20 | ||
|
|
844a78c2a9 | ||
|
|
aff0ab7e05 | ||
|
|
c24e2f68bc | ||
|
|
2bf076874d | ||
|
|
025ad6fe1f |
@@ -5,7 +5,7 @@ set(CMAKE_CXX_STANDARD_REQUIRED ON)
|
||||
|
||||
set(PROJECT AmneziaVPN)
|
||||
if(NOT AMNEZIAVPN_VERSION)
|
||||
set(AMNEZIAVPN_VERSION 5.0.1.5 CACHE STRING "Client app version")
|
||||
set(AMNEZIAVPN_VERSION 5.0.1.1 CACHE STRING "Client app version")
|
||||
endif()
|
||||
|
||||
set(QT_CREATOR_SKIP_PACKAGE_MANAGER_SETUP ON CACHE BOOL "" FORCE)
|
||||
@@ -32,7 +32,7 @@ set(RELEASE_DATE "${CURRENT_DATE}")
|
||||
set(APP_MAJOR_VERSION ${CMAKE_PROJECT_VERSION_MAJOR}.${CMAKE_PROJECT_VERSION_MINOR}.${CMAKE_PROJECT_VERSION_PATCH})
|
||||
|
||||
# bump by 2 on every release, because we're releasing two versions on the play store
|
||||
set(APP_ANDROID_VERSION_CODE 2152)
|
||||
set(APP_ANDROID_VERSION_CODE 2148)
|
||||
if(DEFINED APP_ANDROID_VERSION_CODE_OFFSET)
|
||||
math(EXPR APP_ANDROID_VERSION_CODE "${APP_ANDROID_VERSION_CODE} + ${APP_ANDROID_VERSION_CODE_OFFSET}")
|
||||
endif()
|
||||
|
||||
2
client/3rd/amneziawg-apple
vendored
2
client/3rd/amneziawg-apple
vendored
Submodule client/3rd/amneziawg-apple updated: bdaf0b337b...fe2e2d7ebb
@@ -190,6 +190,18 @@ if(APPLE)
|
||||
cmake_policy(SET CMP0099 NEW)
|
||||
cmake_policy(SET CMP0114 NEW)
|
||||
|
||||
if(NOT BUILD_OSX_APP_IDENTIFIER)
|
||||
set(BUILD_OSX_APP_IDENTIFIER org.amnezia.AmneziaVPN CACHE STRING "OSX Application identifier")
|
||||
endif()
|
||||
if(NOT BUILD_IOS_APP_IDENTIFIER)
|
||||
set(BUILD_IOS_APP_IDENTIFIER org.amnezia.AmneziaVPN CACHE STRING "iOS Application identifier")
|
||||
endif()
|
||||
if(NOT BUILD_IOS_GROUP_IDENTIFIER)
|
||||
set(BUILD_IOS_GROUP_IDENTIFIER group.org.amnezia.AmneziaVPN CACHE STRING "iOS Group identifier")
|
||||
endif()
|
||||
if(NOT BUILD_VPN_DEVELOPMENT_TEAM)
|
||||
set(BUILD_VPN_DEVELOPMENT_TEAM X7UJ388FXK CACHE STRING "Amnezia VPN Development Team")
|
||||
endif()
|
||||
|
||||
set(CMAKE_XCODE_GENERATE_SCHEME FALSE)
|
||||
set(CMAKE_XCODE_ATTRIBUTE_DEVELOPMENT_TEAM ${BUILD_VPN_DEVELOPMENT_TEAM})
|
||||
|
||||
@@ -7,16 +7,3 @@ endif()
|
||||
if(NOT CLIENT_NETWORK_EXTENSION_NAME)
|
||||
set(CLIENT_NETWORK_EXTENSION_NAME "${CLIENT_APPLICATION_NAME}NetworkExtension" CACHE STRING "Display name for Apple network extension targets")
|
||||
endif()
|
||||
|
||||
if(NOT BUILD_OSX_APP_IDENTIFIER)
|
||||
set(BUILD_OSX_APP_IDENTIFIER org.amnezia.AmneziaVPN CACHE STRING "OSX Application identifier")
|
||||
endif()
|
||||
if(NOT BUILD_IOS_APP_IDENTIFIER)
|
||||
set(BUILD_IOS_APP_IDENTIFIER org.amnezia.AmneziaVPN CACHE STRING "iOS Application identifier")
|
||||
endif()
|
||||
if(NOT BUILD_IOS_GROUP_IDENTIFIER)
|
||||
set(BUILD_IOS_GROUP_IDENTIFIER group.org.amnezia.AmneziaVPN CACHE STRING "iOS Group identifier")
|
||||
endif()
|
||||
if(NOT BUILD_VPN_DEVELOPMENT_TEAM)
|
||||
set(BUILD_VPN_DEVELOPMENT_TEAM X7UJ388FXK CACHE STRING "Amnezia VPN Development Team")
|
||||
endif()
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -2,6 +2,7 @@
|
||||
#define XRAY_CONFIGURATOR_H
|
||||
|
||||
#include <QObject>
|
||||
#include <QJsonArray>
|
||||
#include <QJsonObject>
|
||||
|
||||
#include "configuratorBase.h"
|
||||
@@ -35,7 +36,23 @@ public:
|
||||
amnezia::ContainerConfig &containerConfig,
|
||||
const amnezia::DnsSettings &dnsSettings);
|
||||
|
||||
bool uploadClientTemplate(const amnezia::ServerCredentials &credentials, amnezia::DockerContainer container,
|
||||
const amnezia::XrayClientTemplate &clientTemplate) const;
|
||||
|
||||
amnezia::XrayClientTemplate readClientTemplate(const amnezia::ServerCredentials &credentials,
|
||||
amnezia::DockerContainer container, bool &outFound) const;
|
||||
|
||||
static bool isSecuritySupportedOnSelfHosted(const amnezia::XrayServerConfig &srv);
|
||||
|
||||
private:
|
||||
QJsonArray collectServerClients(const amnezia::ServerCredentials &credentials,
|
||||
amnezia::DockerContainer container, const QString &flowValue,
|
||||
const QString &fallbackClientId, amnezia::ErrorCode &outError) const;
|
||||
|
||||
amnezia::ErrorCode uploadServerConfigAtomically(const amnezia::ServerCredentials &credentials,
|
||||
amnezia::DockerContainer container, const QString &listenPort,
|
||||
const QJsonObject &serverConfig) const;
|
||||
|
||||
amnezia::ErrorCode readContainerKeyFile(amnezia::DockerContainer container,
|
||||
const amnezia::ServerCredentials &credentials,
|
||||
const QString &path, QString &out) const;
|
||||
@@ -50,18 +67,21 @@ private:
|
||||
amnezia::XrayProtocolConfig buildClientProtocolConfig(const amnezia::ServerCredentials &credentials,
|
||||
amnezia::DockerContainer container,
|
||||
const amnezia::XrayServerConfig &srv,
|
||||
const amnezia::XrayClientTemplate &tpl,
|
||||
const QString &clientId,
|
||||
amnezia::ErrorCode &errorCode,
|
||||
const QString &prefetchedRealityPublicKey = {},
|
||||
const QString &prefetchedRealityShortId = {}) const;
|
||||
const QString &prefetchedRealityShortId = {},
|
||||
const QString &prefetchedTlsPin = {}) const;
|
||||
|
||||
amnezia::ErrorCode readRealityKeyFiles(amnezia::DockerContainer container,
|
||||
const amnezia::ServerCredentials &credentials,
|
||||
QString &outPublicKey,
|
||||
QString &outShortId) const;
|
||||
|
||||
QJsonObject buildStreamSettings(const amnezia::XrayServerConfig &srv,
|
||||
const QString &clientId) const;
|
||||
amnezia::ErrorCode ensureTlsCertificate(const amnezia::ServerCredentials &credentials,
|
||||
amnezia::DockerContainer container,
|
||||
QString &outFingerprint) const;
|
||||
};
|
||||
|
||||
#endif // XRAY_CONFIGURATOR_H
|
||||
|
||||
@@ -200,6 +200,10 @@ GatewayController::DecryptionResult GatewayController::tryDecryptResponseBody(co
|
||||
result.isDecryptionSuccessful = false;
|
||||
}
|
||||
|
||||
qDebug() << "tryDecryptResponseBody: inputBytes=" << encryptedResponseBody.size() << "keyBytes=" << key.size()
|
||||
<< "ivBytes=" << iv.size() << "saltBytes=" << salt.size() << "replyError=" << replyError
|
||||
<< "decrypted=" << result.isDecryptionSuccessful << "outputBytes=" << decrypted.size();
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
@@ -482,7 +486,9 @@ bool GatewayController::shouldBypassProxy(const QNetworkReply::NetworkError &rep
|
||||
apiErrorMessage = jsonObj.value(QStringLiteral("message")).toString().trimmed();
|
||||
}
|
||||
} else {
|
||||
qDebug() << "failed to decrypt the data";
|
||||
qDebug() << "failed to decrypt the data, bypassing the proxy: replyError=" << replyError
|
||||
<< "bodyBytes=" << responseBody.size()
|
||||
<< "(an empty body looks the same here as a wrong key, compare with tryDecryptResponseBody above)";
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -496,6 +502,7 @@ bool GatewayController::shouldBypassProxy(const QNetworkReply::NetworkError &rep
|
||||
return true;
|
||||
}
|
||||
if (apiHttpStatus == httpStatusCodeRequestTimeout) {
|
||||
qDebug() << "keeping the proxy: apiHttpStatus=" << apiHttpStatus;
|
||||
return false;
|
||||
}
|
||||
if (apiHttpStatus == httpStatusCodeNotFound) {
|
||||
@@ -517,18 +524,24 @@ bool GatewayController::shouldBypassProxy(const QNetworkReply::NetworkError &rep
|
||||
}
|
||||
}
|
||||
if (apiHttpStatus == httpStatusCodeConflict) {
|
||||
qDebug() << "keeping the proxy: apiHttpStatus=" << apiHttpStatus;
|
||||
return false;
|
||||
}
|
||||
if (apiHttpStatus == httpStatusCodePaymentRequired) {
|
||||
qDebug() << "keeping the proxy: apiHttpStatus=" << apiHttpStatus;
|
||||
return false;
|
||||
}
|
||||
if (apiHttpStatus == httpStatusCodeUnprocessableEntity) {
|
||||
return apiErrorMessage != unprocessableSubscriptionMessage;
|
||||
const bool bypass = apiErrorMessage != unprocessableSubscriptionMessage;
|
||||
qDebug() << "apiHttpStatus=" << apiHttpStatus << "bypass=" << bypass
|
||||
<< "(decided by the api message, which is not printed)";
|
||||
return bypass;
|
||||
}
|
||||
if (replyError != QNetworkReply::NetworkError::NoError) {
|
||||
qDebug() << replyError;
|
||||
qDebug() << "bypassing the proxy on a reply error:" << replyError << "apiHttpStatus=" << apiHttpStatus;
|
||||
return true;
|
||||
}
|
||||
qDebug() << "keeping the proxy: nothing matched, apiHttpStatus=" << apiHttpStatus << "replyError=" << replyError;
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
@@ -12,6 +12,7 @@
|
||||
|
||||
#include "core/configurators/configuratorBase.h"
|
||||
#include "core/configurators/xrayConfigurator.h"
|
||||
#include "core/models/protocols/xrayProtocolConfig.h"
|
||||
#include "core/utils/containerEnum.h"
|
||||
#include "core/utils/containers/containerUtils.h"
|
||||
#include "core/utils/protocolEnum.h"
|
||||
@@ -59,6 +60,70 @@ namespace
|
||||
{
|
||||
Logger logger("InstallController");
|
||||
|
||||
QString effectiveXrayPort(const XrayProtocolConfig *cfg)
|
||||
{
|
||||
if (!cfg || cfg->serverConfig.port.isEmpty()) {
|
||||
return QString::fromLatin1(protocols::xray::defaultPort);
|
||||
}
|
||||
return cfg->serverConfig.port;
|
||||
}
|
||||
|
||||
QString normalizeXrayRelease(QString raw)
|
||||
{
|
||||
raw = raw.trimmed();
|
||||
if (raw.startsWith(QLatin1String("v"), Qt::CaseInsensitive)) {
|
||||
raw.remove(0, 1);
|
||||
}
|
||||
return raw.trimmed();
|
||||
}
|
||||
|
||||
QString parseXrayVersionOutput(const QString &output)
|
||||
{
|
||||
static const QRegularExpression re(QStringLiteral(R"(Xray\s+v?(\d+\.\d+\.\d+))"),
|
||||
QRegularExpression::CaseInsensitiveOption);
|
||||
const auto match = re.match(output);
|
||||
if (!match.hasMatch()) {
|
||||
return {};
|
||||
}
|
||||
return match.captured(1);
|
||||
}
|
||||
|
||||
enum class XrayBinaryProbeResult {
|
||||
Match,
|
||||
Mismatch,
|
||||
Failed
|
||||
};
|
||||
|
||||
XrayBinaryProbeResult probeXrayServerBinary(const ServerCredentials &credentials, SshSession &sshSession)
|
||||
{
|
||||
const QString expected =
|
||||
normalizeXrayRelease(QString::fromLatin1(protocols::xray::expectedServerXrayRelease));
|
||||
|
||||
QString stdOut;
|
||||
auto collect = [&stdOut](const QString &data, libssh::Client &) {
|
||||
stdOut += data;
|
||||
return ErrorCode::NoError;
|
||||
};
|
||||
const QString script = SshSession::replaceVars(
|
||||
QStringLiteral("sudo docker exec $CONTAINER_NAME xray version 2>/dev/null | head -1"),
|
||||
amnezia::genBaseVars(credentials, DockerContainer::Xray, QString(), QString()));
|
||||
const ErrorCode errorCode = sshSession.runScript(credentials, script, collect, collect);
|
||||
const QString live = parseXrayVersionOutput(stdOut);
|
||||
|
||||
if (errorCode != ErrorCode::NoError || live.isEmpty()) {
|
||||
return XrayBinaryProbeResult::Failed;
|
||||
}
|
||||
if (live != expected) {
|
||||
return XrayBinaryProbeResult::Mismatch;
|
||||
}
|
||||
return XrayBinaryProbeResult::Match;
|
||||
}
|
||||
|
||||
bool xrayServerBinaryMismatchesExpected(const ServerCredentials &credentials, SshSession &sshSession)
|
||||
{
|
||||
return probeXrayServerBinary(credentials, sshSession) != XrayBinaryProbeResult::Match;
|
||||
}
|
||||
|
||||
bool dockerDaemonContainerMissing(const QString &out, const QString &containerDockerName)
|
||||
{
|
||||
if (!out.contains(QLatin1String("Error response from daemon"), Qt::CaseInsensitive)) {
|
||||
@@ -74,15 +139,33 @@ namespace
|
||||
return false;
|
||||
}
|
||||
|
||||
bool containerKeepsIdentityInDataVolume(DockerContainer container)
|
||||
{
|
||||
return container == DockerContainer::MtProxy
|
||||
|| container == DockerContainer::Telemt
|
||||
|| container == DockerContainer::Xray;
|
||||
}
|
||||
|
||||
QString buildRemoveContainerScript(const amnezia::ScriptVars &vars, bool removeDataVolume)
|
||||
{
|
||||
QString script = SshSession::replaceVars(amnezia::scriptData(SharedScriptType::remove_container), vars);
|
||||
if (removeDataVolume) {
|
||||
script += QLatin1String("\nsudo docker volume rm -f $CONTAINER_NAME-data 2>/dev/null || true");
|
||||
script += QLatin1String(
|
||||
"\nfor attempt in 1 2 3 4 5; do"
|
||||
"\n sudo docker volume rm -f $CONTAINER_NAME-data && break"
|
||||
"\n sleep 1"
|
||||
"\ndone"
|
||||
"\necho \"amnezia_volume_left=$(sudo docker volume ls -q -f name=^$CONTAINER_NAME-data$ | head -1)\"");
|
||||
script = SshSession::replaceVars(script, vars);
|
||||
}
|
||||
return script;
|
||||
}
|
||||
|
||||
bool dataVolumeSurvivedRemoval(const QString &out)
|
||||
{
|
||||
static const QRegularExpression reLeft(QStringLiteral("amnezia_volume_left=(\\S+)"));
|
||||
return reLeft.match(out).hasMatch();
|
||||
}
|
||||
}
|
||||
|
||||
InstallController::InstallController(SecureServersRepository *serversRepository,
|
||||
@@ -131,12 +214,30 @@ ErrorCode InstallController::setupContainer(const ServerCredentials &credentials
|
||||
return e;
|
||||
qDebug().noquote() << "InstallController::setupContainer prepareHostWorker finished";
|
||||
|
||||
QMap<QString, QString> xrayStateToMigrate;
|
||||
if (isUpdate) {
|
||||
e = readXrayStateBeforeVolumeMigration(credentials, container, sshSession, xrayStateToMigrate);
|
||||
if (e)
|
||||
return e;
|
||||
}
|
||||
|
||||
const amnezia::ScriptVars removeContainerVars =
|
||||
amnezia::genBaseVars(credentials, container, QString(), QString());
|
||||
const bool removeDataVolume = !isUpdate && (container == DockerContainer::MtProxy || container == DockerContainer::Telemt);
|
||||
sshSession.runScript(credentials, buildRemoveContainerScript(removeContainerVars, removeDataVolume));
|
||||
const bool removeDataVolume = !isUpdate && containerKeepsIdentityInDataVolume(container);
|
||||
QString removeOut;
|
||||
auto collectRemoveOut = [&removeOut](const QString &data, libssh::Client &) {
|
||||
removeOut += data + "\n";
|
||||
return ErrorCode::NoError;
|
||||
};
|
||||
sshSession.runScript(credentials, buildRemoveContainerScript(removeContainerVars, removeDataVolume),
|
||||
collectRemoveOut, collectRemoveOut);
|
||||
qDebug().noquote() << "InstallController::setupContainer removeContainer finished";
|
||||
|
||||
if (removeDataVolume && dataVolumeSurvivedRemoval(removeOut)) {
|
||||
logger.error() << "Data volume survived removal, refusing to install on top of it, output=" << removeOut;
|
||||
return ErrorCode::ServerDataVolumeNotRemoved;
|
||||
}
|
||||
|
||||
qDebug().noquote() << "buildContainerWorker start";
|
||||
e = buildContainerWorker(credentials, container, config, sshSession);
|
||||
if (e)
|
||||
@@ -148,6 +249,10 @@ ErrorCode InstallController::setupContainer(const ServerCredentials &credentials
|
||||
return e;
|
||||
qDebug().noquote() << "InstallController::setupContainer runContainerWorker finished";
|
||||
|
||||
e = restoreXrayStateIntoDataVolume(credentials, container, sshSession, xrayStateToMigrate);
|
||||
if (e)
|
||||
return e;
|
||||
|
||||
e = configureContainerWorker(credentials, container, config, sshSession);
|
||||
if (e)
|
||||
return e;
|
||||
@@ -171,18 +276,46 @@ ErrorCode InstallController::setupContainer(const ServerCredentials &credentials
|
||||
ErrorCode InstallController::updateServerConfig(const QString &serverId, DockerContainer container, const ContainerConfig &oldConfig,
|
||||
ContainerConfig &newConfig)
|
||||
{
|
||||
if (!isUpdateDockerContainerRequired(container, oldConfig, newConfig)) {
|
||||
auto adminConfig = m_serversRepository->selfHostedAdminConfig(serverId);
|
||||
if (!adminConfig.has_value()) {
|
||||
const bool serverSettingsChanged = isUpdateDockerContainerRequired(container, oldConfig, newConfig);
|
||||
|
||||
auto adminConfig = m_serversRepository->selfHostedAdminConfig(serverId);
|
||||
if (!adminConfig.has_value()) {
|
||||
return ErrorCode::InternalError;
|
||||
}
|
||||
ServerCredentials credentials = adminConfig->credentials();
|
||||
SshSession sshSession;
|
||||
|
||||
bool reinstallRequired = false;
|
||||
bool portReinstall = false;
|
||||
bool binaryMismatch = false;
|
||||
if (serverSettingsChanged) {
|
||||
if (!credentials.isValid()) {
|
||||
return ErrorCode::InternalError;
|
||||
}
|
||||
portReinstall = isReinstallContainerRequired(container, oldConfig, newConfig);
|
||||
reinstallRequired = portReinstall;
|
||||
}
|
||||
if (container == DockerContainer::Xray) {
|
||||
if (credentials.isValid()) {
|
||||
binaryMismatch = xrayServerBinaryMismatchesExpected(credentials, sshSession);
|
||||
if (binaryMismatch) {
|
||||
reinstallRequired = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (!serverSettingsChanged && !reinstallRequired) {
|
||||
if (container == DockerContainer::Xray || container == DockerContainer::SSXray) {
|
||||
if (const auto *xray = newConfig.getXrayProtocolConfig()) {
|
||||
if (credentials.isValid()) {
|
||||
XrayConfigurator xrayConfigurator(&sshSession);
|
||||
xrayConfigurator.uploadClientTemplate(credentials, container, xray->clientTemplate);
|
||||
}
|
||||
}
|
||||
}
|
||||
if (container == DockerContainer::MtProxy) {
|
||||
ServerCredentials credentials = adminConfig->credentials();
|
||||
SshSession sshSession;
|
||||
MtProxyInstaller::uploadClientSettingsSnapshot(sshSession, credentials, container, newConfig);
|
||||
} else if (container == DockerContainer::Telemt) {
|
||||
ServerCredentials credentials = adminConfig->credentials();
|
||||
SshSession sshSession;
|
||||
TelemtInstaller::uploadClientSettingsSnapshot(sshSession, credentials, container, newConfig);
|
||||
}
|
||||
adminConfig->updateContainerConfig(container, newConfig);
|
||||
@@ -190,22 +323,37 @@ ErrorCode InstallController::updateServerConfig(const QString &serverId, DockerC
|
||||
return ErrorCode::NoError;
|
||||
}
|
||||
|
||||
auto adminConfig = m_serversRepository->selfHostedAdminConfig(serverId);
|
||||
if (!adminConfig.has_value()) {
|
||||
return ErrorCode::InternalError;
|
||||
}
|
||||
ServerCredentials credentials = adminConfig->credentials();
|
||||
if (!credentials.isValid()) {
|
||||
return ErrorCode::InternalError;
|
||||
}
|
||||
SshSession sshSession;
|
||||
|
||||
bool reinstallRequired = isReinstallContainerRequired(container, oldConfig, newConfig);
|
||||
qDebug() << "InstallController::updateServerConfig for container" << container << "reinstall required is" << reinstallRequired;
|
||||
|
||||
ErrorCode errorCode = ErrorCode::NoError;
|
||||
if (reinstallRequired) {
|
||||
if (container == DockerContainer::Xray) {
|
||||
const QString oldPort = effectiveXrayPort(oldConfig.getXrayProtocolConfig());
|
||||
const QString newPort = effectiveXrayPort(newConfig.getXrayProtocolConfig());
|
||||
if (oldPort != newPort) {
|
||||
errorCode = isServerPortBusy(credentials, container, newConfig, sshSession);
|
||||
if (errorCode != ErrorCode::NoError) {
|
||||
if (errorCode == ErrorCode::ServerPortAlreadyAllocatedError) {
|
||||
logger.error() << "Xray reinstall refused, port busy, error=201";
|
||||
}
|
||||
return errorCode;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
errorCode = setupContainer(credentials, container, newConfig, true);
|
||||
if (container == DockerContainer::Xray) {
|
||||
if (errorCode == ErrorCode::NoError) {
|
||||
if (xrayServerBinaryMismatchesExpected(credentials, sshSession)) {
|
||||
logger.error() << "Xray version probe: still mismatched after recreate";
|
||||
}
|
||||
} else {
|
||||
logger.error() << "Xray version probe: recreate failed, error="
|
||||
<< static_cast<int>(errorCode);
|
||||
}
|
||||
}
|
||||
|
||||
// Reinstall pulls the latest container image, so the server runs the latest protocol version
|
||||
if (errorCode == ErrorCode::NoError && container == DockerContainer::Awg2) {
|
||||
@@ -213,7 +361,17 @@ ErrorCode InstallController::updateServerConfig(const QString &serverId, DockerC
|
||||
awgConfig->serverConfig.protocolVersion = protocols::awg::awgV3;
|
||||
}
|
||||
}
|
||||
} else if (container != DockerContainer::Xray && container != DockerContainer::SSXray) {
|
||||
} else if (container == DockerContainer::Xray) {
|
||||
DnsSettings dnsSettings = { m_appSettingsRepository->primaryDns(), m_appSettingsRepository->secondaryDns() };
|
||||
XrayConfigurator xrayConfigurator(&sshSession);
|
||||
errorCode = xrayConfigurator.writeServerConfigForSetup(credentials, container, newConfig, dnsSettings);
|
||||
if (errorCode == ErrorCode::NoError) {
|
||||
errorCode = sshSession.runScript(
|
||||
credentials,
|
||||
sshSession.replaceVars(QStringLiteral("sudo docker restart $CONTAINER_NAME"),
|
||||
amnezia::genBaseVars(credentials, container, QString(), QString())));
|
||||
}
|
||||
} else if (container != DockerContainer::SSXray) {
|
||||
errorCode = configureContainerWorker(credentials, container, newConfig, sshSession);
|
||||
if (errorCode == ErrorCode::NoError) {
|
||||
errorCode = startupContainerWorker(credentials, container, newConfig, sshSession);
|
||||
@@ -233,7 +391,12 @@ ErrorCode InstallController::updateServerConfig(const QString &serverId, DockerC
|
||||
TelemtInstaller::uploadClientSettingsSnapshot(sshSession, credentials, container, newConfig);
|
||||
}
|
||||
if (reinstallRequired) {
|
||||
clearCachedProfile(serverId, container);
|
||||
// OpenVPN/WireGuard reinstall mints new client keys, so the old profile is revoked.
|
||||
// Xray identity lives in the data volume; the uuid is unchanged. Revoking it here
|
||||
// drops the admin from clients[] (seen after a port change with a shared account).
|
||||
if (container != DockerContainer::Xray) {
|
||||
clearCachedProfile(serverId, container);
|
||||
}
|
||||
}
|
||||
adminConfig->updateContainerConfig(container, newConfig);
|
||||
m_serversRepository->editServer(serverId, adminConfig->toJson(), serverConfigUtils::ConfigType::SelfHostedAdmin);
|
||||
@@ -442,6 +605,11 @@ ErrorCode InstallController::prepareContainerConfig(DockerContainer container, c
|
||||
void InstallController::adminAppendRequested(const QString &serverId, DockerContainer container,
|
||||
const ContainerConfig &containerConfig, const QString &clientName)
|
||||
{
|
||||
// Xray admin identity is the volume uuid; it must stay in server.json and must not
|
||||
// appear in the Share Users list (revoking it emptied the inbound).
|
||||
if (container == DockerContainer::Xray) {
|
||||
return;
|
||||
}
|
||||
if (ContainerUtils::containerService(container) == ServiceType::Other
|
||||
|| !containerConfig.protocolConfig.hasClientConfig()) {
|
||||
return;
|
||||
@@ -605,6 +773,142 @@ ErrorCode InstallController::startupContainerWorker(const ServerCredentials &cre
|
||||
baseVars));
|
||||
}
|
||||
|
||||
ErrorCode InstallController::readXrayStateBeforeVolumeMigration(const ServerCredentials &credentials,
|
||||
DockerContainer container, SshSession &sshSession,
|
||||
QMap<QString, QString> &outFiles)
|
||||
{
|
||||
outFiles.clear();
|
||||
|
||||
if (container != DockerContainer::Xray) {
|
||||
return ErrorCode::NoError;
|
||||
}
|
||||
|
||||
namespace px = amnezia::protocols::xray;
|
||||
|
||||
const amnezia::ScriptVars vars = amnezia::genBaseVars(credentials, container, QString(), QString());
|
||||
|
||||
QString stdOut;
|
||||
auto collect = [&stdOut](const QString &data, libssh::Client &) {
|
||||
stdOut += data + "\n";
|
||||
return ErrorCode::NoError;
|
||||
};
|
||||
|
||||
const QString probe = QStringLiteral(
|
||||
"echo \"amnezia_volume=$(sudo docker volume ls -q -f name=^$CONTAINER_NAME-data$ | head -1)\"\n"
|
||||
"echo \"amnezia_container=$(sudo docker ps -a -q -f name=^$CONTAINER_NAME$ | head -1)\"\n"
|
||||
"if [ -n \"$(sudo docker ps -a -q -f name=^$CONTAINER_NAME$ | head -1)\" ] && "
|
||||
"[ -z \"$(sudo docker ps -q -f name=^$CONTAINER_NAME$ | head -1)\" ]; then\n"
|
||||
" sudo docker start $CONTAINER_NAME > /dev/null 2>&1\n"
|
||||
" sleep 2\n"
|
||||
"fi\n"
|
||||
"echo \"amnezia_running=$(sudo docker ps -q -f name=^$CONTAINER_NAME$ | head -1)\"\n"
|
||||
"echo \"amnezia_mounted=$(sudo docker inspect -f "
|
||||
"'{{range .Mounts}}{{if and (eq .Destination \"%1\") "
|
||||
"(eq .Name \"$CONTAINER_NAME-data\")}}yes{{end}}{{end}}' "
|
||||
"$CONTAINER_NAME 2>/dev/null | head -1)\"")
|
||||
.arg(QString::fromLatin1(px::dataDir));
|
||||
ErrorCode errorCode = sshSession.runScript(credentials, SshSession::replaceVars(probe, vars), collect, collect);
|
||||
if (errorCode != ErrorCode::NoError) {
|
||||
logger.error() << "Xray key migration: could not probe server state";
|
||||
return ErrorCode::XrayKeyMigrationFailed;
|
||||
}
|
||||
|
||||
static const QRegularExpression reContainer(QStringLiteral("amnezia_container=(\\S+)"));
|
||||
static const QRegularExpression reRunning(QStringLiteral("amnezia_running=(\\S+)"));
|
||||
static const QRegularExpression reMounted(QStringLiteral("amnezia_mounted=(\\S+)"));
|
||||
const bool containerExists = reContainer.match(stdOut).hasMatch();
|
||||
const bool containerRunning = reRunning.match(stdOut).hasMatch();
|
||||
const bool dataDirIsVolume = reMounted.match(stdOut).hasMatch();
|
||||
|
||||
if (!containerExists) {
|
||||
return ErrorCode::NoError;
|
||||
}
|
||||
if (dataDirIsVolume) {
|
||||
return ErrorCode::NoError;
|
||||
}
|
||||
if (!containerRunning) {
|
||||
logger.error() << "Xray key migration: container will not start, cannot read the keys out of it";
|
||||
return ErrorCode::XrayKeyMigrationFailed;
|
||||
}
|
||||
|
||||
const QStringList requiredPaths = {
|
||||
QString::fromLatin1(px::PrivateKeyPath),
|
||||
QString::fromLatin1(px::PublicKeyPath),
|
||||
QString::fromLatin1(px::uuidPath),
|
||||
QString::fromLatin1(px::shortidPath),
|
||||
};
|
||||
|
||||
for (const QString &path : requiredPaths) {
|
||||
QString content;
|
||||
bool read = false;
|
||||
for (int attempt = 0; attempt < 3 && !read; ++attempt) {
|
||||
ErrorCode fileError = ErrorCode::NoError;
|
||||
content = QString::fromUtf8(sshSession.getTextFileFromContainer(container, credentials, path, fileError));
|
||||
if (fileError == ErrorCode::NoError && !content.trimmed().isEmpty()) {
|
||||
read = true;
|
||||
break;
|
||||
}
|
||||
if (attempt < 2) {
|
||||
QThread::msleep(500);
|
||||
}
|
||||
}
|
||||
if (!read) {
|
||||
logger.error() << "Xray key migration: failed to read" << path << ", aborting before container removal";
|
||||
return ErrorCode::XrayKeyMigrationFailed;
|
||||
}
|
||||
outFiles.insert(path, content);
|
||||
}
|
||||
|
||||
QString serverConfig;
|
||||
bool configRead = false;
|
||||
for (int attempt = 0; attempt < 3 && !configRead; ++attempt) {
|
||||
ErrorCode configError = ErrorCode::NoError;
|
||||
serverConfig = QString::fromUtf8(sshSession.getTextFileFromContainer(
|
||||
container, credentials, QString::fromLatin1(px::serverConfigPath), configError));
|
||||
if (configError == ErrorCode::NoError && !serverConfig.trimmed().isEmpty()) {
|
||||
configRead = true;
|
||||
break;
|
||||
}
|
||||
if (attempt < 2) {
|
||||
QThread::msleep(500);
|
||||
}
|
||||
}
|
||||
if (!configRead) {
|
||||
logger.error() << "Xray key migration: server config unreadable, aborting before container removal";
|
||||
return ErrorCode::XrayKeyMigrationFailed;
|
||||
}
|
||||
outFiles.insert(QString::fromLatin1(px::serverConfigPath), serverConfig);
|
||||
|
||||
ErrorCode templateError = ErrorCode::NoError;
|
||||
const QString clientTemplate = QString::fromUtf8(sshSession.getTextFileFromContainer(
|
||||
container, credentials, QString::fromLatin1(px::clientTemplatePath), templateError));
|
||||
if (templateError == ErrorCode::NoError && !clientTemplate.trimmed().isEmpty()) {
|
||||
outFiles.insert(QString::fromLatin1(px::clientTemplatePath), clientTemplate);
|
||||
}
|
||||
|
||||
return ErrorCode::NoError;
|
||||
}
|
||||
|
||||
ErrorCode InstallController::restoreXrayStateIntoDataVolume(const ServerCredentials &credentials,
|
||||
DockerContainer container, SshSession &sshSession,
|
||||
const QMap<QString, QString> &files)
|
||||
{
|
||||
if (files.isEmpty()) {
|
||||
return ErrorCode::NoError;
|
||||
}
|
||||
|
||||
for (auto it = files.constBegin(); it != files.constEnd(); ++it) {
|
||||
const ErrorCode errorCode = sshSession.uploadTextFileToContainer(
|
||||
container, credentials, it.value(), it.key(), libssh::ScpOverwriteMode::ScpOverwriteExisting);
|
||||
if (errorCode != ErrorCode::NoError) {
|
||||
logger.error() << "Xray key migration: failed to write back" << it.key();
|
||||
return ErrorCode::XrayKeyMigrationFailed;
|
||||
}
|
||||
}
|
||||
|
||||
return ErrorCode::NoError;
|
||||
}
|
||||
|
||||
ErrorCode InstallController::isServerPortBusy(const ServerCredentials &credentials, DockerContainer container, const ContainerConfig &config, SshSession &sshSession)
|
||||
{
|
||||
if (container == DockerContainer::Dns) {
|
||||
@@ -722,7 +1026,20 @@ bool InstallController::isReinstallContainerRequired(DockerContainer container,
|
||||
}
|
||||
}
|
||||
|
||||
if (container == DockerContainer::Xray || container == DockerContainer::SSXray) {
|
||||
if (container == DockerContainer::Xray) {
|
||||
const auto *oldXrayConfig = oldConfig.getXrayProtocolConfig();
|
||||
const auto *newXrayConfig = newConfig.getXrayProtocolConfig();
|
||||
|
||||
if (oldXrayConfig && newXrayConfig) {
|
||||
const QString oldPort = effectiveXrayPort(oldXrayConfig);
|
||||
const QString newPort = effectiveXrayPort(newXrayConfig);
|
||||
if (oldPort != newPort) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (container == DockerContainer::SSXray) {
|
||||
const auto *oldXrayConfig = oldConfig.getXrayProtocolConfig();
|
||||
const auto *newXrayConfig = newConfig.getXrayProtocolConfig();
|
||||
|
||||
@@ -1010,9 +1327,20 @@ ErrorCode InstallController::removeContainer(const QString &serverId, DockerCont
|
||||
SshSession sshSession;
|
||||
const amnezia::ScriptVars removeContainerVars =
|
||||
amnezia::genBaseVars(credentials, container, QString(), QString());
|
||||
const bool removeDataVolume = (container == DockerContainer::MtProxy || container == DockerContainer::Telemt);
|
||||
ErrorCode errorCode =
|
||||
sshSession.runScript(credentials, buildRemoveContainerScript(removeContainerVars, removeDataVolume));
|
||||
const bool removeDataVolume = containerKeepsIdentityInDataVolume(container);
|
||||
QString removeOut;
|
||||
auto collectRemoveOut = [&removeOut](const QString &data, libssh::Client &) {
|
||||
removeOut += data + "\n";
|
||||
return ErrorCode::NoError;
|
||||
};
|
||||
ErrorCode errorCode = sshSession.runScript(
|
||||
credentials, buildRemoveContainerScript(removeContainerVars, removeDataVolume), collectRemoveOut,
|
||||
collectRemoveOut);
|
||||
|
||||
if (errorCode == ErrorCode::NoError && removeDataVolume && dataVolumeSurvivedRemoval(removeOut)) {
|
||||
logger.error() << "Data volume survived protocol removal, output=" << removeOut;
|
||||
errorCode = ErrorCode::ServerDataVolumeNotRemoved;
|
||||
}
|
||||
|
||||
if (errorCode == ErrorCode::NoError) {
|
||||
QMap<DockerContainer, ContainerConfig> containers = adminConfig->containers;
|
||||
@@ -1087,6 +1415,13 @@ bool InstallController::isUpdateDockerContainerRequired(DockerContainer containe
|
||||
return false;
|
||||
}
|
||||
}
|
||||
} else if (container == DockerContainer::Xray) {
|
||||
const auto *oldXray = oldConfig.getXrayProtocolConfig();
|
||||
const auto *newXray = newConfig.getXrayProtocolConfig();
|
||||
if (oldXray && newXray && oldXray->serverConfig.hasEqualServerSettings(newXray->serverConfig)) {
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
} else if (container == DockerContainer::MtProxy) {
|
||||
const auto *oldMt = oldConfig.getMtProxyProtocolConfig();
|
||||
const auto *newMt = newConfig.getMtProxyProtocolConfig();
|
||||
|
||||
@@ -104,6 +104,11 @@ private:
|
||||
ErrorCode configureContainerWorker(const ServerCredentials &credentials, DockerContainer container, ContainerConfig &config, SshSession &sshSession);
|
||||
ErrorCode startupContainerWorker(const ServerCredentials &credentials, DockerContainer container, const ContainerConfig &config, SshSession &sshSession);
|
||||
|
||||
ErrorCode readXrayStateBeforeVolumeMigration(const ServerCredentials &credentials, DockerContainer container,
|
||||
SshSession &sshSession, QMap<QString, QString> &outFiles);
|
||||
ErrorCode restoreXrayStateIntoDataVolume(const ServerCredentials &credentials, DockerContainer container,
|
||||
SshSession &sshSession, const QMap<QString, QString> &files);
|
||||
|
||||
ErrorCode isServerPortBusy(const ServerCredentials &credentials, DockerContainer container, const ContainerConfig &config, SshSession &sshSession);
|
||||
ErrorCode isUserInSudo(const ServerCredentials &credentials, SshSession &sshSession);
|
||||
ErrorCode isServerDpkgBusy(const ServerCredentials &credentials, SshSession &sshSession);
|
||||
@@ -126,7 +131,7 @@ private:
|
||||
SecureServersRepository* m_serversRepository;
|
||||
SecureAppSettingsRepository* m_appSettingsRepository;
|
||||
bool m_cancelInstallation = false;
|
||||
|
||||
|
||||
#ifndef Q_OS_IOS
|
||||
QList<QSharedPointer<QProcess>> m_sftpMountProcesses;
|
||||
#endif
|
||||
|
||||
@@ -2,6 +2,7 @@
|
||||
|
||||
#include <QJsonDocument>
|
||||
#include <QJsonObject>
|
||||
#include <QJsonArray>
|
||||
#include <QDateTime>
|
||||
|
||||
#include "core/utils/containerEnum.h"
|
||||
@@ -55,6 +56,34 @@ int UsersController::clientIndexById(const QString &clientId, const QJsonArray &
|
||||
return -1;
|
||||
}
|
||||
|
||||
QString UsersController::readXrayVolumeUuid(const DockerContainer container, const ServerCredentials &credentials,
|
||||
SshSession *sshSession) const
|
||||
{
|
||||
ErrorCode error = ErrorCode::NoError;
|
||||
const QString uuid = QString::fromUtf8(sshSession->getTextFileFromContainer(
|
||||
container, credentials, QString::fromLatin1(amnezia::protocols::xray::uuidPath), error));
|
||||
if (error != ErrorCode::NoError) {
|
||||
logger.warning() << "readXrayVolumeUuid: failed, error=" << static_cast<int>(error);
|
||||
return {};
|
||||
}
|
||||
return uuid.trimmed();
|
||||
}
|
||||
|
||||
int UsersController::stripXrayVolumeUuidFromTable(QJsonArray &clientsTable, const QString &volumeUuid)
|
||||
{
|
||||
if (volumeUuid.isEmpty()) {
|
||||
return 0;
|
||||
}
|
||||
int removed = 0;
|
||||
for (int i = clientsTable.size() - 1; i >= 0; --i) {
|
||||
if (clientsTable.at(i).toObject().value(configKey::clientId).toString() == volumeUuid) {
|
||||
clientsTable.removeAt(i);
|
||||
++removed;
|
||||
}
|
||||
}
|
||||
return removed;
|
||||
}
|
||||
|
||||
void UsersController::migration(const QByteArray &clientsTableString, QJsonArray &clientsTable)
|
||||
{
|
||||
QJsonObject clientsTableObj = QJsonDocument::fromJson(clientsTableString).object();
|
||||
@@ -264,6 +293,7 @@ ErrorCode UsersController::getXrayClients(const DockerContainer container, const
|
||||
}
|
||||
|
||||
const QJsonArray clients = settings[protocols::xray::clients].toArray();
|
||||
const QString xrayDefaultUuid = readXrayVolumeUuid(container, credentials, sshSession);
|
||||
for (const auto &clientValue : clients) {
|
||||
const QJsonObject clientObj = clientValue.toObject();
|
||||
if (!clientObj.contains(protocols::xray::id)) {
|
||||
@@ -271,9 +301,6 @@ ErrorCode UsersController::getXrayClients(const DockerContainer container, const
|
||||
continue;
|
||||
}
|
||||
QString clientId = clientObj[protocols::xray::id].toString();
|
||||
|
||||
QString xrayDefaultUuid = sshSession->getTextFileFromContainer(container, credentials, amnezia::protocols::xray::uuidPath, error);
|
||||
xrayDefaultUuid.replace("\n", "");
|
||||
|
||||
if (!isClientExists(clientId, clientsTable) && clientId != xrayDefaultUuid) {
|
||||
QJsonObject client;
|
||||
@@ -297,10 +324,14 @@ ErrorCode UsersController::updateClients(const QString &serverId, const DockerCo
|
||||
SshSession sshSession;
|
||||
auto adminConfig = m_serversRepository->selfHostedAdminConfig(serverId);
|
||||
if (!adminConfig.has_value()) {
|
||||
logger.error() << "updateClients: no admin config for this server, container="
|
||||
<< ContainerUtils::containerTypeToString(container);
|
||||
return ErrorCode::InternalError;
|
||||
}
|
||||
ServerCredentials credentials = adminConfig->credentials();
|
||||
if (!credentials.isValid()) {
|
||||
logger.error() << "updateClients: credentials are not valid, container="
|
||||
<< ContainerUtils::containerTypeToString(container);
|
||||
return ErrorCode::InternalError;
|
||||
}
|
||||
|
||||
@@ -313,7 +344,8 @@ ErrorCode UsersController::updateClients(const QString &serverId, const DockerCo
|
||||
|
||||
const QByteArray clientsTableString = sshSession.getTextFileFromContainer(container, credentials, clientsTableFile, error);
|
||||
if (error != ErrorCode::NoError) {
|
||||
logger.error() << "Failed to get the clientsTable file from the server";
|
||||
logger.error() << "updateClients: failed to read the clientsTable file, error=" << static_cast<int>(error)
|
||||
<< "container=" << ContainerUtils::containerTypeToString(container);
|
||||
emit clientsUpdated(QJsonArray());
|
||||
return error;
|
||||
}
|
||||
@@ -321,6 +353,10 @@ ErrorCode UsersController::updateClients(const QString &serverId, const DockerCo
|
||||
m_clientsTable = QJsonDocument::fromJson(clientsTableString).array();
|
||||
|
||||
if (m_clientsTable.isEmpty()) {
|
||||
logger.info() << "updateClients: the clientsTable is empty, rebuilding it from the server, readBytes="
|
||||
<< clientsTableString.size()
|
||||
<< (clientsTableString.trimmed().isEmpty() ? ", the file was empty"
|
||||
: ", the file had content but did not parse as an array");
|
||||
migration(clientsTableString, m_clientsTable);
|
||||
|
||||
int count = 0;
|
||||
@@ -333,6 +369,8 @@ ErrorCode UsersController::updateClients(const QString &serverId, const DockerCo
|
||||
error = getXrayClients(container, credentials, &sshSession, count, m_clientsTable);
|
||||
}
|
||||
if (error != ErrorCode::NoError) {
|
||||
logger.error() << "updateClients: failed to rebuild the client list from the server, error="
|
||||
<< static_cast<int>(error) << "container=" << ContainerUtils::containerTypeToString(container);
|
||||
emit clientsUpdated(QJsonArray());
|
||||
return error;
|
||||
}
|
||||
@@ -341,7 +379,27 @@ ErrorCode UsersController::updateClients(const QString &serverId, const DockerCo
|
||||
if (clientsTableString != newClientsTableString) {
|
||||
error = sshSession.uploadTextFileToContainer(container, credentials, newClientsTableString, clientsTableFile);
|
||||
if (error != ErrorCode::NoError) {
|
||||
logger.error() << "Failed to upload the clientsTable file to the server";
|
||||
logger.error() << "updateClients: failed to write back the rebuilt clientsTable, error="
|
||||
<< static_cast<int>(error) << "container=" << ContainerUtils::containerTypeToString(container)
|
||||
<< "rows=" << m_clientsTable.size();
|
||||
logger.warning() << "updateClients: the app now holds a client list the server does not have;"
|
||||
<< "this error is returned but every caller discards it";
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (container == DockerContainer::Xray) {
|
||||
const QString volumeUuid = readXrayVolumeUuid(container, credentials, &sshSession);
|
||||
const int stripped = stripXrayVolumeUuidFromTable(m_clientsTable, volumeUuid);
|
||||
if (stripped > 0) {
|
||||
logger.info() << "updateClients: removed the volume uuid from the user list, rows="
|
||||
<< stripped;
|
||||
const QByteArray strippedTable = QJsonDocument(m_clientsTable).toJson();
|
||||
const ErrorCode writeError =
|
||||
sshSession.uploadTextFileToContainer(container, credentials, strippedTable, clientsTableFile);
|
||||
if (writeError != ErrorCode::NoError) {
|
||||
logger.error() << "updateClients: failed to write the user list without the volume uuid, error="
|
||||
<< static_cast<int>(writeError);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -393,18 +451,32 @@ ErrorCode UsersController::appendClient(const QString &serverId, const QString &
|
||||
SshSession sshSession;
|
||||
auto adminConfig = m_serversRepository->selfHostedAdminConfig(serverId);
|
||||
if (!adminConfig.has_value()) {
|
||||
logger.error() << "appendClient: no admin config for this server, container="
|
||||
<< ContainerUtils::containerTypeToString(container);
|
||||
return ErrorCode::InternalError;
|
||||
}
|
||||
ServerCredentials credentials = adminConfig->credentials();
|
||||
if (!credentials.isValid()) {
|
||||
logger.error() << "appendClient: credentials are not valid, container="
|
||||
<< ContainerUtils::containerTypeToString(container);
|
||||
return ErrorCode::InternalError;
|
||||
}
|
||||
|
||||
error = updateClients(serverId, container);
|
||||
if (error != ErrorCode::NoError) {
|
||||
logger.error() << "appendClient: could not read the current client list, error=" << static_cast<int>(error)
|
||||
<< ", the new account will not appear in the user list";
|
||||
return error;
|
||||
}
|
||||
|
||||
if (container == DockerContainer::Xray) {
|
||||
const QString volumeUuid = readXrayVolumeUuid(container, credentials, &sshSession);
|
||||
if (!volumeUuid.isEmpty() && clientId == volumeUuid) {
|
||||
logger.info() << "appendClient: skipped the volume uuid, it is not listed in Share Users";
|
||||
return ErrorCode::NoError;
|
||||
}
|
||||
}
|
||||
|
||||
int existingIndex = clientIndexById(clientId, m_clientsTable);
|
||||
if (existingIndex >= 0) {
|
||||
return renameClient(serverId, existingIndex, clientName, container, true);
|
||||
@@ -430,7 +502,11 @@ ErrorCode UsersController::appendClient(const QString &serverId, const QString &
|
||||
|
||||
error = sshSession.uploadTextFileToContainer(container, credentials, clientsTableString, clientsTableFile);
|
||||
if (error != ErrorCode::NoError) {
|
||||
logger.error() << "Failed to upload the clientsTable file to the server";
|
||||
logger.error() << "appendClient: failed to upload the clientsTable, error=" << static_cast<int>(error)
|
||||
<< "container=" << ContainerUtils::containerTypeToString(container)
|
||||
<< "rows=" << m_clientsTable.size();
|
||||
logger.warning() << "appendClient: the account exists on the server but is missing from the user list;"
|
||||
<< "the caller discards this error, so nothing is reported to the user";
|
||||
return error;
|
||||
}
|
||||
|
||||
@@ -477,7 +553,9 @@ ErrorCode UsersController::renameClient(const QString &serverId, const int row,
|
||||
|
||||
ErrorCode error = sshSession.uploadTextFileToContainer(container, credentials, clientsTableString, clientsTableFile);
|
||||
if (error != ErrorCode::NoError) {
|
||||
logger.error() << "Failed to upload the clientsTable file to the server";
|
||||
logger.error() << "renameClient: failed to upload the clientsTable, error=" << static_cast<int>(error)
|
||||
<< "container=" << ContainerUtils::containerTypeToString(container)
|
||||
<< "rows=" << m_clientsTable.size();
|
||||
return error;
|
||||
}
|
||||
|
||||
@@ -522,7 +600,9 @@ ErrorCode UsersController::revokeOpenVpn(const int row, const DockerContainer co
|
||||
clientsTableFile = clientsTableFile.arg(ContainerUtils::containerTypeToString(DockerContainer::OpenVpn));
|
||||
error = sshSession->uploadTextFileToContainer(container, credentials, clientsTableString, clientsTableFile);
|
||||
if (error != ErrorCode::NoError) {
|
||||
logger.error() << "Failed to upload the clientsTable file to the server";
|
||||
logger.error() << "revokeOpenVpn: failed to upload the clientsTable, error=" << static_cast<int>(error)
|
||||
<< "container=" << ContainerUtils::containerTypeToString(container)
|
||||
<< "rows=" << clientsTable.size();
|
||||
return error;
|
||||
}
|
||||
|
||||
@@ -582,7 +662,9 @@ ErrorCode UsersController::revokeWireGuard(const int row, const DockerContainer
|
||||
}
|
||||
error = sshSession->uploadTextFileToContainer(container, credentials, clientsTableString, clientsTableFile);
|
||||
if (error != ErrorCode::NoError) {
|
||||
logger.error() << "Failed to upload the clientsTable file to the server";
|
||||
logger.error() << "revokeWireGuard: failed to upload the clientsTable, error=" << static_cast<int>(error)
|
||||
<< "container=" << ContainerUtils::containerTypeToString(container)
|
||||
<< "rows=" << clientsTable.size();
|
||||
return error;
|
||||
}
|
||||
|
||||
@@ -615,6 +697,24 @@ ErrorCode UsersController::revokeXray(const int row,
|
||||
|
||||
ErrorCode error = ErrorCode::NoError;
|
||||
|
||||
auto client = clientsTable.at(row).toObject();
|
||||
QString clientId = client.value(configKey::clientId).toString();
|
||||
|
||||
const QString volumeUuid = readXrayVolumeUuid(container, credentials, sshSession);
|
||||
if (!volumeUuid.isEmpty() && clientId == volumeUuid) {
|
||||
logger.info() << "revokeXray: refused, this is the volume uuid";
|
||||
clientsTable.removeAt(row);
|
||||
const QByteArray clientsTableString = QJsonDocument(clientsTable).toJson();
|
||||
const QString clientsTableFile = QString("/opt/amnezia/%1/clientsTable")
|
||||
.arg(ContainerUtils::containerTypeToString(container));
|
||||
error = sshSession->uploadTextFileToContainer(container, credentials, clientsTableString, clientsTableFile);
|
||||
if (error != ErrorCode::NoError) {
|
||||
logger.error() << "revokeXray: refused the volume uuid but failed to drop it from the user list, error="
|
||||
<< static_cast<int>(error);
|
||||
}
|
||||
return ErrorCode::NoError;
|
||||
}
|
||||
|
||||
const QString serverConfigPath = amnezia::protocols::xray::serverConfigPath;
|
||||
const QString configString = sshSession->getTextFileFromContainer(container, credentials, serverConfigPath, error);
|
||||
if (error != ErrorCode::NoError) {
|
||||
@@ -628,9 +728,6 @@ ErrorCode UsersController::revokeXray(const int row,
|
||||
return ErrorCode::InternalError;
|
||||
}
|
||||
|
||||
auto client = clientsTable.at(row).toObject();
|
||||
QString clientId = client.value(configKey::clientId).toString();
|
||||
|
||||
QJsonObject configObj = serverConfig.object();
|
||||
if (!configObj.contains(protocols::xray::inbounds)) {
|
||||
logger.error() << "Missing inbounds in xray config";
|
||||
@@ -669,6 +766,10 @@ ErrorCode UsersController::revokeXray(const int row,
|
||||
}
|
||||
}
|
||||
|
||||
if (clients.isEmpty()) {
|
||||
logger.warning() << "revokeXray: inbound left with zero clients";
|
||||
}
|
||||
|
||||
settings[protocols::xray::clients] = clients;
|
||||
inbound[protocols::xray::settings] = settings;
|
||||
inbounds[0] = inbound;
|
||||
@@ -693,7 +794,11 @@ ErrorCode UsersController::revokeXray(const int row,
|
||||
|
||||
error = sshSession->uploadTextFileToContainer(container, credentials, clientsTableString, clientsTableFile);
|
||||
if (error != ErrorCode::NoError) {
|
||||
logger.error() << "Failed to upload the clientsTable file";
|
||||
logger.error() << "revokeXray: failed to upload the clientsTable, error=" << static_cast<int>(error)
|
||||
<< "container=" << ContainerUtils::containerTypeToString(container)
|
||||
<< "rows=" << clientsTable.size();
|
||||
logger.warning() << "revokeXray: the account is gone from the server config but still listed in the user table;"
|
||||
<< "this error is then overwritten by the container restart below and never reaches the caller";
|
||||
}
|
||||
|
||||
QString restartScript = QString("sudo docker restart $CONTAINER_NAME");
|
||||
@@ -712,16 +817,22 @@ ErrorCode UsersController::revokeXray(const int row,
|
||||
ErrorCode UsersController::revokeClient(const QString &serverId, const int index, const DockerContainer container)
|
||||
{
|
||||
if (index < 0 || index >= m_clientsTable.size()) {
|
||||
logger.error() << "revokeClient: row" << index << "is outside the client table of" << m_clientsTable.size()
|
||||
<< "rows, container=" << ContainerUtils::containerTypeToString(container);
|
||||
return ErrorCode::InternalError;
|
||||
}
|
||||
|
||||
SshSession sshSession;
|
||||
auto adminConfig = m_serversRepository->selfHostedAdminConfig(serverId);
|
||||
if (!adminConfig.has_value()) {
|
||||
logger.error() << "revokeClient: no admin config for this server, container="
|
||||
<< ContainerUtils::containerTypeToString(container);
|
||||
return ErrorCode::InternalError;
|
||||
}
|
||||
ServerCredentials credentials = adminConfig->credentials();
|
||||
if (!credentials.isValid()) {
|
||||
logger.error() << "revokeClient: credentials are not valid, container="
|
||||
<< ContainerUtils::containerTypeToString(container);
|
||||
return ErrorCode::InternalError;
|
||||
}
|
||||
|
||||
@@ -777,16 +888,22 @@ ErrorCode UsersController::revokeClient(const QString &serverId, const Container
|
||||
SshSession sshSession;
|
||||
auto adminConfig = m_serversRepository->selfHostedAdminConfig(serverId);
|
||||
if (!adminConfig.has_value()) {
|
||||
logger.error() << "revokeClient by config: no admin config for this server, container="
|
||||
<< ContainerUtils::containerTypeToString(container);
|
||||
return ErrorCode::InternalError;
|
||||
}
|
||||
ServerCredentials credentials = adminConfig->credentials();
|
||||
if (!credentials.isValid()) {
|
||||
logger.error() << "revokeClient by config: credentials are not valid, container="
|
||||
<< ContainerUtils::containerTypeToString(container);
|
||||
return ErrorCode::InternalError;
|
||||
}
|
||||
|
||||
ErrorCode errorCode = ErrorCode::NoError;
|
||||
errorCode = updateClients(serverId, container);
|
||||
if (errorCode != ErrorCode::NoError) {
|
||||
logger.error() << "revokeClient by config: could not read the current client list, error="
|
||||
<< static_cast<int>(errorCode);
|
||||
return errorCode;
|
||||
}
|
||||
|
||||
@@ -812,6 +929,9 @@ ErrorCode UsersController::revokeClient(const QString &serverId, const Container
|
||||
|
||||
int row = clientIndexById(clientId, m_clientsTable);
|
||||
if (row < 0) {
|
||||
logger.warning() << "revokeClient by config: this account is not in the client table of"
|
||||
<< m_clientsTable.size() << "rows, nothing was revoked and success is reported,"
|
||||
<< "container=" << ContainerUtils::containerTypeToString(container);
|
||||
return errorCode;
|
||||
}
|
||||
|
||||
|
||||
@@ -66,6 +66,10 @@ private:
|
||||
ErrorCode getXrayClients(const DockerContainer container, const ServerCredentials& credentials,
|
||||
SshSession* sshSession, int &count, QJsonArray &clientsTable);
|
||||
|
||||
QString readXrayVolumeUuid(const DockerContainer container, const ServerCredentials &credentials,
|
||||
SshSession *sshSession) const;
|
||||
int stripXrayVolumeUuidFromTable(QJsonArray &clientsTable, const QString &volumeUuid);
|
||||
|
||||
ErrorCode wgShow(const DockerContainer container, const ServerCredentials &credentials,
|
||||
SshSession* sshSession, std::vector<WgShowData> &data);
|
||||
|
||||
|
||||
@@ -86,8 +86,10 @@ ContainerConfig InstallerBase::createBaseConfig(DockerContainer container, int p
|
||||
srv.flow = protocols::xray::defaultFlow;
|
||||
srv.site = protocols::xray::defaultSite;
|
||||
srv.sni = protocols::xray::defaultSni;
|
||||
srv.fingerprint = protocols::xray::defaultFingerprint;
|
||||
srv.alpn = protocols::xray::defaultAlpn;
|
||||
xrayConfig.clientTemplate.fingerprint = protocols::xray::defaultFingerprint;
|
||||
xrayConfig.clientTemplate.uplinkMethod = protocols::xray::defaultXhttpUplinkMethod;
|
||||
xrayConfig.clientTemplate.formatVersion = 1;
|
||||
config.protocolConfig = xrayConfig;
|
||||
break;
|
||||
}
|
||||
|
||||
@@ -1,7 +1,6 @@
|
||||
#include "xrayInstaller.h"
|
||||
|
||||
#include <QJsonDocument>
|
||||
#include <QJsonArray>
|
||||
|
||||
#include "core/utils/containerEnum.h"
|
||||
#include "core/utils/containers/containerUtils.h"
|
||||
@@ -11,6 +10,7 @@
|
||||
#include "core/utils/constants/configKeys.h"
|
||||
#include "core/utils/constants/protocolConstants.h"
|
||||
#include "core/utils/selfhosted/sshSession.h"
|
||||
#include "core/configurators/xrayConfigurator.h"
|
||||
#include "core/models/protocols/xrayProtocolConfig.h"
|
||||
#include "logger.h"
|
||||
|
||||
@@ -18,38 +18,21 @@ namespace
|
||||
{
|
||||
Logger logger("XrayInstaller");
|
||||
|
||||
// Xray expects uTLS preset names (chrome, firefox, …). Old Amnezia/server templates used "Mozilla/5.0".
|
||||
QString normalizeXrayFingerprint(const QString &fp)
|
||||
QString describeServerJsonStatus(amnezia::XrayServerJsonStatus status)
|
||||
{
|
||||
if (fp.isEmpty() || fp.contains(QLatin1String("Mozilla/5.0"), Qt::CaseInsensitive)) {
|
||||
return QString::fromLatin1(protocols::xray::defaultFingerprint);
|
||||
}
|
||||
return fp;
|
||||
}
|
||||
|
||||
// Parse an xray int range: "from-to" string, plain int, or legacy {from,to} object.
|
||||
void parseIntRange(const QJsonValue &v, QString &minOut, QString &maxOut)
|
||||
{
|
||||
if (v.isString()) {
|
||||
const QString s = v.toString().trimmed();
|
||||
const int dash = s.indexOf(QLatin1Char('-'), 1);
|
||||
if (dash > 0) {
|
||||
minOut = s.left(dash).trimmed();
|
||||
maxOut = s.mid(dash + 1).trimmed();
|
||||
} else if (!s.isEmpty()) {
|
||||
minOut = s;
|
||||
maxOut = s;
|
||||
}
|
||||
} else if (v.isDouble()) {
|
||||
minOut = QString::number(v.toInt());
|
||||
maxOut = minOut;
|
||||
} else if (v.isObject()) {
|
||||
const QJsonObject o = v.toObject();
|
||||
if (o.contains(QLatin1String("from")) || o.contains(QLatin1String("to"))) {
|
||||
minOut = QString::number(o.value(QLatin1String("from")).toInt());
|
||||
maxOut = QString::number(o.value(QLatin1String("to")).toInt());
|
||||
}
|
||||
switch (status) {
|
||||
case amnezia::XrayServerJsonStatus::MissingInbounds:
|
||||
return QStringLiteral("server config missing 'inbounds' field");
|
||||
case amnezia::XrayServerJsonStatus::EmptyInbounds:
|
||||
return QStringLiteral("server config has empty 'inbounds' array");
|
||||
case amnezia::XrayServerJsonStatus::MissingStreamSettings:
|
||||
return QStringLiteral("inbound missing 'streamSettings' field");
|
||||
case amnezia::XrayServerJsonStatus::MissingSettings:
|
||||
return QStringLiteral("inbound missing 'settings' field");
|
||||
case amnezia::XrayServerJsonStatus::Ok:
|
||||
break;
|
||||
}
|
||||
return QStringLiteral("ok");
|
||||
}
|
||||
}
|
||||
|
||||
@@ -64,10 +47,12 @@ XrayInstaller::XrayInstaller(QObject *parent)
|
||||
ErrorCode XrayInstaller::extractConfigFromContainer(DockerContainer container, const ServerCredentials &credentials,
|
||||
SshSession* sshSession, ContainerConfig &config)
|
||||
{
|
||||
namespace px = amnezia::protocols::xray;
|
||||
|
||||
ErrorCode errorCode = ErrorCode::NoError;
|
||||
|
||||
|
||||
QString currentConfig = sshSession->getTextFileFromContainer(
|
||||
container, credentials, amnezia::protocols::xray::serverConfigPath, errorCode);
|
||||
container, credentials, px::serverConfigPath, errorCode);
|
||||
|
||||
if (errorCode != ErrorCode::NoError) {
|
||||
return errorCode;
|
||||
@@ -78,267 +63,36 @@ ErrorCode XrayInstaller::extractConfigFromContainer(DockerContainer container, c
|
||||
logger.error() << "Failed to parse server config JSON";
|
||||
return ErrorCode::InternalError;
|
||||
}
|
||||
QJsonObject serverConfig = doc.object();
|
||||
|
||||
if (!serverConfig.contains(protocols::xray::inbounds)) {
|
||||
logger.error() << "Server config missing 'inbounds' field";
|
||||
return ErrorCode::InternalError;
|
||||
}
|
||||
|
||||
QJsonArray inbounds = serverConfig[protocols::xray::inbounds].toArray();
|
||||
if (inbounds.isEmpty()) {
|
||||
logger.error() << "Server config has empty 'inbounds' array";
|
||||
return ErrorCode::InternalError;
|
||||
}
|
||||
|
||||
QJsonObject inbound = inbounds[0].toObject();
|
||||
if (!inbound.contains(protocols::xray::streamSettings)) {
|
||||
logger.error() << "Inbound missing 'streamSettings' field";
|
||||
return ErrorCode::InternalError;
|
||||
}
|
||||
|
||||
QJsonObject streamSettings = inbound[protocols::xray::streamSettings].toObject();
|
||||
auto *xrayConfig = config.getXrayProtocolConfig();
|
||||
if (!xrayConfig) {
|
||||
logger.error() << "No XrayProtocolConfig in ContainerConfig";
|
||||
return ErrorCode::InternalError;
|
||||
}
|
||||
|
||||
XrayServerConfig &srv = xrayConfig->serverConfig;
|
||||
|
||||
// ── Port ─────────────────────────────────────────────────────────
|
||||
if (inbound.contains(protocols::xray::port)) {
|
||||
srv.port = QString::number(inbound[protocols::xray::port].toInt());
|
||||
XrayClientTemplate &tpl = xrayConfig->clientTemplate;
|
||||
const amnezia::XrayServerJsonStatus status =
|
||||
XrayServerConfig::fromServerInboundJson(doc.object(), xrayConfig->serverConfig, tpl);
|
||||
if (status != amnezia::XrayServerJsonStatus::Ok) {
|
||||
logger.error() << "Xray extractConfigFromContainer:" << describeServerJsonStatus(status);
|
||||
return ErrorCode::InternalError;
|
||||
}
|
||||
|
||||
// ── Network (transport) ───────────────────────────────────────────
|
||||
QString networkVal = streamSettings.value(protocols::xray::network).toString("tcp");
|
||||
if (networkVal == "xhttp") {
|
||||
srv.transport = "xhttp";
|
||||
} else if (networkVal == "kcp") {
|
||||
srv.transport = "mkcp";
|
||||
} else {
|
||||
srv.transport = "raw";
|
||||
}
|
||||
logger.info() << "Xray extractConfigFromContainer: extracted server, port=" << xrayConfig->serverConfig.port
|
||||
<< "transport=" << xrayConfig->serverConfig.transport
|
||||
<< "security=" << xrayConfig->serverConfig.security << "site=" << xrayConfig->serverConfig.site
|
||||
<< "sni=" << xrayConfig->serverConfig.sni;
|
||||
|
||||
// ── Security ──────────────────────────────────────────────────────
|
||||
srv.security = streamSettings.value(protocols::xray::security).toString("reality");
|
||||
|
||||
// ── Reality settings ──────────────────────────────────────────────
|
||||
if (srv.security == "reality") {
|
||||
QJsonObject rs = streamSettings.value(protocols::xray::realitySettings).toObject();
|
||||
|
||||
// serverNames array → site + sni
|
||||
if (rs.contains(protocols::xray::serverNames)) {
|
||||
QString sniVal = rs[protocols::xray::serverNames].toArray().first().toString();
|
||||
srv.sni = sniVal;
|
||||
srv.site = sniVal;
|
||||
} else if (rs.contains(protocols::xray::serverName)) {
|
||||
srv.sni = rs[protocols::xray::serverName].toString();
|
||||
srv.site = srv.sni;
|
||||
{
|
||||
XrayConfigurator configurator(sshSession);
|
||||
bool found = false;
|
||||
const XrayClientTemplate stored = configurator.readClientTemplate(credentials, container, found);
|
||||
if (found) {
|
||||
tpl = stored;
|
||||
logger.info() << "Xray extractConfigFromContainer: adopted the client template from the server,"
|
||||
<< "fingerprint=" << tpl.fingerprint << "uplinkMethod=" << tpl.uplinkMethod;
|
||||
} else {
|
||||
logger.info() << "Xray extractConfigFromContainer: no client template on the server to adopt";
|
||||
}
|
||||
|
||||
srv.fingerprint = normalizeXrayFingerprint(rs.value(protocols::xray::fingerprint).toString());
|
||||
}
|
||||
|
||||
// ── TLS settings ──────────────────────────────────────────────────
|
||||
if (srv.security == "tls") {
|
||||
QJsonObject tls = streamSettings.value("tlsSettings").toObject();
|
||||
srv.sni = tls.value(protocols::xray::serverName).toString();
|
||||
srv.fingerprint = normalizeXrayFingerprint(tls.value(protocols::xray::fingerprint).toString());
|
||||
|
||||
QJsonArray alpnArr = tls.value("alpn").toArray();
|
||||
QStringList alpnList;
|
||||
for (const QJsonValue &v : alpnArr) {
|
||||
QString t = v.toString().trimmed();
|
||||
if (t.compare(QLatin1String("HTTP/2"), Qt::CaseInsensitive) == 0)
|
||||
t = QStringLiteral("h2");
|
||||
else if (t.compare(QLatin1String("HTTP/1.1"), Qt::CaseInsensitive) == 0)
|
||||
t = QStringLiteral("http/1.1");
|
||||
if (!t.isEmpty())
|
||||
alpnList << t;
|
||||
}
|
||||
srv.alpn = alpnList.join(",");
|
||||
}
|
||||
|
||||
// ── Flow (from users array) ───────────────────────────────────────
|
||||
if (inbound.contains(protocols::xray::settings)) {
|
||||
QJsonObject s = inbound[protocols::xray::settings].toObject();
|
||||
QJsonArray clientsArr = s.value(protocols::xray::clients).toArray();
|
||||
if (!clientsArr.isEmpty()) {
|
||||
srv.flow = clientsArr[0].toObject().value(protocols::xray::flow).toString();
|
||||
}
|
||||
}
|
||||
|
||||
// ── XHTTP settings (Xray-core SplitHTTPConfig + legacy Amnezia keys) ──
|
||||
if (srv.transport == "xhttp") {
|
||||
QJsonObject xhttpObj = streamSettings.value("xhttpSettings").toObject();
|
||||
{
|
||||
const QString m = xhttpObj.value("mode").toString();
|
||||
if (m.isEmpty() || m == QLatin1String("auto"))
|
||||
srv.xhttp.mode = QStringLiteral("Auto");
|
||||
else if (m == QLatin1String("packet-up"))
|
||||
srv.xhttp.mode = QStringLiteral("Packet-up");
|
||||
else if (m == QLatin1String("stream-up"))
|
||||
srv.xhttp.mode = QStringLiteral("Stream-up");
|
||||
else if (m == QLatin1String("stream-one"))
|
||||
srv.xhttp.mode = QStringLiteral("Stream-one");
|
||||
else
|
||||
srv.xhttp.mode = m;
|
||||
}
|
||||
|
||||
srv.xhttp.host = xhttpObj.value("host").toString();
|
||||
srv.xhttp.path = xhttpObj.value("path").toString();
|
||||
|
||||
if (xhttpObj.contains(QLatin1String("uplinkHTTPMethod")))
|
||||
srv.xhttp.uplinkMethod = xhttpObj.value("uplinkHTTPMethod").toString();
|
||||
else
|
||||
srv.xhttp.uplinkMethod = xhttpObj.value("method").toString();
|
||||
|
||||
srv.xhttp.disableGrpc = xhttpObj.value("noGRPCHeader").toBool(true);
|
||||
srv.xhttp.disableSse = xhttpObj.value("noSSEHeader").toBool(true);
|
||||
|
||||
auto sessionSeqUi = [](const QString &core) -> QString {
|
||||
if (core.isEmpty() || core == QLatin1String("path"))
|
||||
return QStringLiteral("Path");
|
||||
if (core == QLatin1String("cookie"))
|
||||
return QStringLiteral("Cookie");
|
||||
if (core == QLatin1String("header"))
|
||||
return QStringLiteral("Header");
|
||||
if (core == QLatin1String("query"))
|
||||
return QStringLiteral("Query");
|
||||
return core;
|
||||
};
|
||||
QString sess = xhttpObj.value("sessionIDPlacement").toString();
|
||||
if (sess.isEmpty())
|
||||
sess = xhttpObj.value("sessionPlacement").toString();
|
||||
if (sess.isEmpty())
|
||||
sess = xhttpObj.value("scSessionPlacement").toString();
|
||||
srv.xhttp.sessionPlacement = sessionSeqUi(sess);
|
||||
|
||||
QString seq = xhttpObj.value("seqPlacement").toString();
|
||||
if (seq.isEmpty())
|
||||
seq = xhttpObj.value("scSeqPlacement").toString();
|
||||
srv.xhttp.seqPlacement = sessionSeqUi(seq);
|
||||
|
||||
auto uplinkDataUi = [](const QString &core) -> QString {
|
||||
if (core.isEmpty() || core == QLatin1String("body"))
|
||||
return QStringLiteral("Body");
|
||||
if (core == QLatin1String("auto"))
|
||||
return QStringLiteral("Auto");
|
||||
if (core == QLatin1String("header"))
|
||||
return QStringLiteral("Header");
|
||||
if (core == QLatin1String("cookie"))
|
||||
return QStringLiteral("Cookie");
|
||||
return core;
|
||||
};
|
||||
QString udata = xhttpObj.value("uplinkDataPlacement").toString();
|
||||
if (udata.isEmpty())
|
||||
udata = xhttpObj.value("scUplinkDataPlacement").toString();
|
||||
srv.xhttp.uplinkDataPlacement = uplinkDataUi(udata);
|
||||
|
||||
srv.xhttp.sessionKey = xhttpObj.value("sessionIDKey").toString();
|
||||
if (srv.xhttp.sessionKey.isEmpty())
|
||||
srv.xhttp.sessionKey = xhttpObj.value("sessionKey").toString();
|
||||
srv.xhttp.seqKey = xhttpObj.value("seqKey").toString();
|
||||
srv.xhttp.uplinkDataKey = xhttpObj.value("uplinkDataKey").toString();
|
||||
|
||||
if (xhttpObj.contains(QLatin1String("uplinkChunkSize"))) {
|
||||
QString ucMin, ucMax;
|
||||
parseIntRange(xhttpObj.value("uplinkChunkSize"), ucMin, ucMax);
|
||||
if (!ucMin.isEmpty())
|
||||
srv.xhttp.uplinkChunkSize = ucMin;
|
||||
} else if (xhttpObj.contains(QLatin1String("xhttpUplinkChunkSize"))) {
|
||||
srv.xhttp.uplinkChunkSize = QString::number(xhttpObj.value("xhttpUplinkChunkSize").toInt());
|
||||
}
|
||||
if (xhttpObj.contains(QLatin1String("scMaxBufferedPosts"))) {
|
||||
srv.xhttp.scMaxBufferedPosts = QString::number(xhttpObj.value("scMaxBufferedPosts").toVariant().toLongLong());
|
||||
}
|
||||
|
||||
auto readRange = [&](const char *key, QString &minOut, QString &maxOut) {
|
||||
parseIntRange(xhttpObj.value(QLatin1String(key)), minOut, maxOut);
|
||||
};
|
||||
readRange("scMaxEachPostBytes", srv.xhttp.scMaxEachPostBytesMin, srv.xhttp.scMaxEachPostBytesMax);
|
||||
readRange("scMinPostsIntervalMs", srv.xhttp.scMinPostsIntervalMsMin, srv.xhttp.scMinPostsIntervalMsMax);
|
||||
readRange("scStreamUpServerSecs", srv.xhttp.scStreamUpServerSecsMin, srv.xhttp.scStreamUpServerSecsMax);
|
||||
|
||||
auto loadPaddingFromObject = [&](const QJsonObject &pad) {
|
||||
if (pad.contains(QLatin1String("xPaddingObfsMode")))
|
||||
srv.xhttp.xPadding.obfsMode = pad.value("xPaddingObfsMode").toBool(true);
|
||||
srv.xhttp.xPadding.key = pad.value("xPaddingKey").toString();
|
||||
srv.xhttp.xPadding.header = pad.value("xPaddingHeader").toString();
|
||||
srv.xhttp.xPadding.placement = pad.value("xPaddingPlacement").toString();
|
||||
srv.xhttp.xPadding.method = pad.value("xPaddingMethod").toString();
|
||||
QString bytesMin, bytesMax;
|
||||
parseIntRange(pad.value("xPaddingBytes"), bytesMin, bytesMax);
|
||||
if (!bytesMin.isEmpty()) {
|
||||
srv.xhttp.xPadding.bytesMin = bytesMin;
|
||||
srv.xhttp.xPadding.bytesMax = bytesMax;
|
||||
}
|
||||
QString pl = srv.xhttp.xPadding.placement.toLower();
|
||||
if (pl == QLatin1String("cookie"))
|
||||
srv.xhttp.xPadding.placement = QStringLiteral("Cookie");
|
||||
else if (pl == QLatin1String("header"))
|
||||
srv.xhttp.xPadding.placement = QStringLiteral("Header");
|
||||
else if (pl == QLatin1String("query"))
|
||||
srv.xhttp.xPadding.placement = QStringLiteral("Query");
|
||||
else if (pl == QLatin1String("queryinheader"))
|
||||
srv.xhttp.xPadding.placement = QStringLiteral("Query in header");
|
||||
QString met = srv.xhttp.xPadding.method.toLower();
|
||||
if (met == QLatin1String("repeat-x"))
|
||||
srv.xhttp.xPadding.method = QStringLiteral("Repeat-x");
|
||||
else if (met == QLatin1String("tokenish"))
|
||||
srv.xhttp.xPadding.method = QStringLiteral("Tokenish");
|
||||
};
|
||||
if (xhttpObj.contains(QLatin1String("xPaddingObfsMode")) || xhttpObj.contains(QLatin1String("xPaddingKey"))
|
||||
|| xhttpObj.contains(QLatin1String("xPaddingBytes"))) {
|
||||
loadPaddingFromObject(xhttpObj);
|
||||
} else if (xhttpObj.contains(QLatin1String("xPadding")) && xhttpObj.value("xPadding").isObject()) {
|
||||
const QJsonObject nested = xhttpObj.value("xPadding").toObject();
|
||||
if (!nested.isEmpty()) {
|
||||
loadPaddingFromObject(nested);
|
||||
if (!nested.contains(QLatin1String("xPaddingObfsMode")))
|
||||
srv.xhttp.xPadding.obfsMode = true;
|
||||
}
|
||||
}
|
||||
|
||||
if (xhttpObj.contains(QLatin1String("xmux"))) {
|
||||
QJsonObject mux = xhttpObj.value("xmux").toObject();
|
||||
srv.xhttp.xmux.enabled = true;
|
||||
|
||||
auto readMuxRange = [&](const char *key, QString &minOut, QString &maxOut) {
|
||||
parseIntRange(mux.value(QLatin1String(key)), minOut, maxOut);
|
||||
};
|
||||
readMuxRange("maxConcurrency", srv.xhttp.xmux.maxConcurrencyMin, srv.xhttp.xmux.maxConcurrencyMax);
|
||||
readMuxRange("maxConnections", srv.xhttp.xmux.maxConnectionsMin, srv.xhttp.xmux.maxConnectionsMax);
|
||||
readMuxRange("cMaxReuseTimes", srv.xhttp.xmux.cMaxReuseTimesMin, srv.xhttp.xmux.cMaxReuseTimesMax);
|
||||
readMuxRange("hMaxRequestTimes", srv.xhttp.xmux.hMaxRequestTimesMin, srv.xhttp.xmux.hMaxRequestTimesMax);
|
||||
readMuxRange("hMaxReusableSecs", srv.xhttp.xmux.hMaxReusableSecsMin, srv.xhttp.xmux.hMaxReusableSecsMax);
|
||||
|
||||
if (mux.contains(QLatin1String("hKeepAlivePeriod")))
|
||||
srv.xhttp.xmux.hKeepAlivePeriod = QString::number(mux.value("hKeepAlivePeriod").toVariant().toLongLong());
|
||||
}
|
||||
}
|
||||
|
||||
// ── mKCP settings ─────────────────────────────────────────────────
|
||||
if (srv.transport == "mkcp") {
|
||||
QJsonObject kcp = streamSettings.value("kcpSettings").toObject();
|
||||
if (kcp.contains("tti")) {
|
||||
srv.mkcp.tti = QString::number(kcp["tti"].toInt());
|
||||
}
|
||||
if (kcp.contains("uplinkCapacity")) {
|
||||
srv.mkcp.uplinkCapacity = QString::number(kcp["uplinkCapacity"].toInt());
|
||||
}
|
||||
if (kcp.contains("downlinkCapacity")) {
|
||||
srv.mkcp.downlinkCapacity = QString::number(kcp["downlinkCapacity"].toInt());
|
||||
}
|
||||
if (kcp.contains("readBufferSize")) {
|
||||
srv.mkcp.readBufferSize = QString::number(kcp["readBufferSize"].toInt());
|
||||
}
|
||||
if (kcp.contains("writeBufferSize")) {
|
||||
srv.mkcp.writeBufferSize = QString::number(kcp["writeBufferSize"].toInt());
|
||||
}
|
||||
srv.mkcp.congestion = kcp.value("congestion").toBool(true);
|
||||
}
|
||||
|
||||
return ErrorCode::NoError;
|
||||
|
||||
@@ -19,6 +19,14 @@ namespace amnezia
|
||||
|
||||
namespace
|
||||
{
|
||||
// A toggle set to "off" behaves exactly like a missing one, so it is not an AWG 3 marker
|
||||
bool isAwgToggleEnabled(const QString &value)
|
||||
{
|
||||
const QString trimmedValue = value.trimmed();
|
||||
return !trimmedValue.isEmpty()
|
||||
&& trimmedValue.compare(QLatin1String(protocols::awg::awgBoolOff), Qt::CaseInsensitive) != 0;
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
bool hasAwg3Markers(const T &config)
|
||||
{
|
||||
@@ -32,8 +40,7 @@ namespace
|
||||
return true;
|
||||
}
|
||||
|
||||
return AwgProtocolConfig::isToggleEnabled(config.randomTrailers)
|
||||
|| AwgProtocolConfig::isToggleEnabled(config.disableCookies);
|
||||
return isAwgToggleEnabled(config.randomTrailers) || isAwgToggleEnabled(config.disableCookies);
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
@@ -424,13 +431,6 @@ QString AwgProtocolConfig::clientProtocolVersion() const
|
||||
return clientConfig.has_value() ? awgVersionOf(clientConfig.value()) : QString();
|
||||
}
|
||||
|
||||
bool AwgProtocolConfig::isToggleEnabled(const QString &value)
|
||||
{
|
||||
const QString trimmedValue = value.trimmed();
|
||||
return !trimmedValue.isEmpty()
|
||||
&& trimmedValue.compare(QLatin1String(protocols::awg::awgBoolOff), Qt::CaseInsensitive) != 0;
|
||||
}
|
||||
|
||||
QString AwgProtocolConfig::protocolVersionString(const QString &version)
|
||||
{
|
||||
if (version == protocols::awg::awgV3) return QObject::tr(" (version 3.1)");
|
||||
|
||||
@@ -109,7 +109,6 @@ struct AwgProtocolConfig {
|
||||
QString serverProtocolVersion() const;
|
||||
QString clientProtocolVersion() const;
|
||||
static QString protocolVersionString(const QString &version);
|
||||
static bool isToggleEnabled(const QString &value);
|
||||
|
||||
bool hasClientConfig() const;
|
||||
void setClientConfig(const AwgClientConfig& config);
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -1,9 +1,11 @@
|
||||
#ifndef XRAYPROTOCOLCONFIG_H
|
||||
#define XRAYPROTOCOLCONFIG_H
|
||||
|
||||
#include <QJsonArray>
|
||||
#include <QJsonObject>
|
||||
#include "core/utils/constants/protocolConstants.h"
|
||||
#include <QString>
|
||||
#include <QStringList>
|
||||
#include <optional>
|
||||
|
||||
namespace amnezia
|
||||
@@ -43,12 +45,32 @@ struct XrayXmuxConfig {
|
||||
static XrayXmuxConfig fromJson(const QJsonObject &json);
|
||||
};
|
||||
|
||||
struct XrayClientTemplate {
|
||||
int formatVersion = 0;
|
||||
|
||||
QString fingerprint = protocols::xray::defaultFingerprint;
|
||||
QString uplinkMethod = protocols::xray::defaultXhttpUplinkMethod;
|
||||
QString uplinkChunkSize = protocols::xray::defaultXhttpUplinkChunkSize;
|
||||
QString scMinPostsIntervalMsMin = protocols::xray::defaultXhttpScMinPostsIntervalMsMin;
|
||||
QString scMinPostsIntervalMsMax = protocols::xray::defaultXhttpScMinPostsIntervalMsMax;
|
||||
|
||||
XrayXmuxConfig xmux;
|
||||
|
||||
QString updatedAt;
|
||||
|
||||
QJsonObject toJson() const;
|
||||
static XrayClientTemplate fromJson(const QJsonObject &json);
|
||||
|
||||
QString contentFingerprint() const;
|
||||
|
||||
void materializeFromLegacy(const QJsonObject &storedServerJson);
|
||||
};
|
||||
|
||||
// ── XHTTP transport ───────────────────────────────────────────────────────────
|
||||
struct XrayXhttpConfig {
|
||||
QString mode = protocols::xray::defaultXhttpMode; // Auto|Packet-up|Stream-up|Stream-one
|
||||
QString host = protocols::xray::defaultXhttpHost;
|
||||
QString path;
|
||||
QString uplinkMethod = protocols::xray::defaultXhttpUplinkMethod; // POST|PUT|PATCH
|
||||
bool disableGrpc = true;
|
||||
bool disableSse = true;
|
||||
|
||||
@@ -61,17 +83,13 @@ struct XrayXhttpConfig {
|
||||
QString uplinkDataKey;
|
||||
|
||||
// Traffic Shaping
|
||||
QString uplinkChunkSize = protocols::xray::defaultXhttpUplinkChunkSize;
|
||||
QString scMaxBufferedPosts;
|
||||
QString scMaxEachPostBytesMin = protocols::xray::defaultXhttpScMaxEachPostBytesMin;
|
||||
QString scMaxEachPostBytesMax = protocols::xray::defaultXhttpScMaxEachPostBytesMax;
|
||||
QString scMinPostsIntervalMsMin = protocols::xray::defaultXhttpScMinPostsIntervalMsMin;
|
||||
QString scMinPostsIntervalMsMax = protocols::xray::defaultXhttpScMinPostsIntervalMsMax;
|
||||
QString scStreamUpServerSecsMin = protocols::xray::defaultXhttpScStreamUpServerSecsMin;
|
||||
QString scStreamUpServerSecsMax = protocols::xray::defaultXhttpScStreamUpServerSecsMax;
|
||||
|
||||
XrayXPaddingConfig xPadding;
|
||||
XrayXmuxConfig xmux;
|
||||
|
||||
QJsonObject toJson() const;
|
||||
/// Reads only keys present in JSON (no Amnezia UI defaults). Use XrayConfigModel::applyDefaultsToServerConfig for UI.
|
||||
@@ -81,16 +99,47 @@ struct XrayXhttpConfig {
|
||||
// ── mKCP transport ────────────────────────────────────────────────────────────
|
||||
struct XrayMkcpConfig {
|
||||
QString tti;
|
||||
QString mtu;
|
||||
QString uplinkCapacity;
|
||||
QString downlinkCapacity;
|
||||
QString readBufferSize;
|
||||
QString writeBufferSize;
|
||||
bool congestion = true;
|
||||
QString cwndMultiplier;
|
||||
QString maxSendingWindow;
|
||||
|
||||
QJsonObject toJson() const;
|
||||
static XrayMkcpConfig fromJson(const QJsonObject &json);
|
||||
};
|
||||
|
||||
/// Which end of the connection the emitted xray json is meant for. The client
|
||||
/// stream settings are the server ones plus the fields the server never reads.
|
||||
enum class XrayStreamSide {
|
||||
Server,
|
||||
Client,
|
||||
};
|
||||
|
||||
/// Runtime values the server document needs and the structure must not keep:
|
||||
/// the client list of this particular operation and the ssh-read reality secrets.
|
||||
struct XrayServerInboundInputs {
|
||||
QJsonArray clients;
|
||||
QString realityPrivateKey;
|
||||
QString realityShortId;
|
||||
};
|
||||
|
||||
/// Why a server.json could not be read back into the structure. The caller turns
|
||||
/// this into an error code and a log line; parsing itself stays silent.
|
||||
enum class XrayServerJsonStatus {
|
||||
Ok,
|
||||
MissingInbounds,
|
||||
EmptyInbounds,
|
||||
MissingStreamSettings,
|
||||
MissingSettings,
|
||||
};
|
||||
|
||||
/// What to do with account entries that carry no id when the list is rewritten.
|
||||
enum class XrayClientListFilter {
|
||||
KeepAll,
|
||||
DropWithoutId,
|
||||
};
|
||||
|
||||
// ── Server config (settings editable by user) ─────────────────────────────────
|
||||
struct XrayServerConfig {
|
||||
QString port;
|
||||
@@ -101,7 +150,6 @@ struct XrayServerConfig {
|
||||
|
||||
QString security;
|
||||
QString flow;
|
||||
QString fingerprint;
|
||||
QString sni;
|
||||
QString alpn;
|
||||
|
||||
@@ -113,7 +161,77 @@ struct XrayServerConfig {
|
||||
|
||||
static XrayServerConfig fromJson(const QJsonObject &json);
|
||||
|
||||
void applyDefaults(bool fillFlowDefault = false);
|
||||
|
||||
/// Single emitter for both ends. The template is only read on the client side;
|
||||
/// pass anything on the server side, its fields are not written there.
|
||||
QJsonObject streamSettingsJson(XrayStreamSide side, const XrayClientTemplate &clientTemplate) const;
|
||||
|
||||
QJsonObject serverStreamSettings() const;
|
||||
|
||||
QJsonObject clientStreamSettings(const XrayClientTemplate &clientTemplate) const;
|
||||
|
||||
/// The whole server.json this configuration means, ready to be uploaded.
|
||||
QJsonObject toServerInboundJson(const XrayServerInboundInputs &inputs) const;
|
||||
|
||||
/// The way back: a server.json read off the container into the two structures.
|
||||
/// Both are written, because a server document also carries client-side fields
|
||||
/// (the uTLS preset, the uplink method, xmux) that belong in the template.
|
||||
static XrayServerJsonStatus fromServerInboundJson(const QJsonObject &serverJson, XrayServerConfig &outServerConfig,
|
||||
XrayClientTemplate &outClientTemplate);
|
||||
|
||||
/// The account list of a server document. Reading is forgiving: a document with
|
||||
/// no inbounds simply has no accounts. Writing is strict, because putting a list
|
||||
/// into a document that has nowhere to hold it would drop accounts in silence.
|
||||
static QJsonArray clientsFromServerInboundJson(const QJsonObject &serverJson);
|
||||
static XrayServerJsonStatus setClientsInServerInboundJson(QJsonObject &serverJson, const QJsonArray &clients);
|
||||
|
||||
/// One account entry, its position in a list, and the flow rewritten across a list.
|
||||
/// An empty flow means the key is taken out, which is how the raw transport wants it.
|
||||
static QJsonObject makeClientEntry(const QString &clientId, const QString &flowValue);
|
||||
static QJsonObject applyFlowToClient(const QJsonObject &client, const QString &flowValue);
|
||||
static int indexOfClient(const QJsonArray &clients, const QString &clientId);
|
||||
static QString firstClientId(const QJsonArray &clients);
|
||||
static QJsonArray applyFlowToClients(const QJsonArray &clients, const QString &flowValue,
|
||||
XrayClientListFilter filter = XrayClientListFilter::KeepAll);
|
||||
|
||||
QJsonObject serverView() const;
|
||||
|
||||
QJsonObject issuedConfigView() const;
|
||||
|
||||
bool hasEqualServerSettings(const XrayServerConfig &other) const;
|
||||
|
||||
QStringList serverViewDifferences(const XrayServerConfig &other) const;
|
||||
|
||||
bool breaksIssuedConfigs(const XrayServerConfig &other) const;
|
||||
};
|
||||
|
||||
namespace xrayEffective
|
||||
{
|
||||
QString xhttpMode(const QString &mode);
|
||||
QString sessionSeqPlacement(const QString &placement);
|
||||
QString uplinkDataPlacement(const QString &placement);
|
||||
QString xPaddingPlacement(const QString &placement);
|
||||
QString xPaddingMethod(const QString &method);
|
||||
QString range(const QString &minV, const QString &maxV);
|
||||
void putRangeIfAny(QJsonObject &obj, const char *key, QString minV, QString maxV, const char *fallbackMin,
|
||||
const char *fallbackMax);
|
||||
|
||||
QString security(const XrayServerConfig &srv);
|
||||
QString clientFlow(const XrayServerConfig &srv);
|
||||
QString network(const XrayServerConfig &srv);
|
||||
QString xhttpModeSent(const XrayServerConfig &srv);
|
||||
}
|
||||
|
||||
/// Runtime values the client document needs and the structures must not keep:
|
||||
/// the host we connect to, the account this device was given, and the ssh-read
|
||||
/// reality keys / TLS certificate pin.
|
||||
struct XrayClientOutboundInputs {
|
||||
QString serverAddress;
|
||||
QString clientId;
|
||||
QString realityPublicKey;
|
||||
QString realityShortId;
|
||||
QString tlsPinnedPeerCertSha256;
|
||||
};
|
||||
|
||||
// ── Client config (generated, not edited by user) ─────────────────────────────
|
||||
@@ -121,14 +239,20 @@ struct XrayClientConfig {
|
||||
QString nativeConfig;
|
||||
QString localPort;
|
||||
QString id;
|
||||
QString templateFingerprint;
|
||||
|
||||
QJsonObject toJson() const;
|
||||
static XrayClientConfig fromJson(const QJsonObject &json);
|
||||
|
||||
/// The two runtime values read back out of a native client document.
|
||||
static QString idFromNativeJson(const QJsonObject &nativeJson);
|
||||
static QString localPortFromNativeJson(const QJsonObject &nativeJson);
|
||||
};
|
||||
|
||||
// ── Top-level protocol config ──────────────────────────────────────────────────
|
||||
struct XrayProtocolConfig {
|
||||
XrayServerConfig serverConfig;
|
||||
XrayClientTemplate clientTemplate;
|
||||
std::optional<XrayClientConfig> clientConfig;
|
||||
|
||||
QJsonObject toJson() const;
|
||||
@@ -139,8 +263,20 @@ struct XrayProtocolConfig {
|
||||
void clearClientConfig();
|
||||
|
||||
bool needsClientHydration = false;
|
||||
bool needsTemplateMaterialization = false;
|
||||
|
||||
bool templateWasMaterialized = false;
|
||||
|
||||
/// The whole client document this configuration means, ready for the core.
|
||||
QJsonObject toClientOutboundJson(const XrayClientOutboundInputs &inputs) const;
|
||||
|
||||
/// The way back: a client document read into the server config, the template and
|
||||
/// the runtime fields of the cached client config.
|
||||
bool fromClientOutboundJson(const QJsonObject &nativeJson);
|
||||
|
||||
bool hydrateServerConfigFromClientNative();
|
||||
|
||||
bool materializeTemplateFromServerConfig();
|
||||
};
|
||||
|
||||
} // namespace amnezia
|
||||
|
||||
@@ -214,11 +214,11 @@ namespace amnezia
|
||||
|
||||
// Transport — mKCP
|
||||
constexpr QLatin1String mkcpTti("mkcp_tti");
|
||||
constexpr QLatin1String mkcpMtu("mkcp_mtu");
|
||||
constexpr QLatin1String mkcpUplinkCapacity("mkcp_uplink_capacity");
|
||||
constexpr QLatin1String mkcpDownlinkCapacity("mkcp_downlink_capacity");
|
||||
constexpr QLatin1String mkcpReadBufferSize("mkcp_read_buffer_size");
|
||||
constexpr QLatin1String mkcpWriteBufferSize("mkcp_write_buffer_size");
|
||||
constexpr QLatin1String mkcpCongestion("mkcp_congestion"); // bool
|
||||
constexpr QLatin1String mkcpCwndMultiplier("mkcp_cwnd_multiplier");
|
||||
constexpr QLatin1String mkcpMaxSendingWindow("mkcp_max_sending_window");
|
||||
|
||||
// xPadding
|
||||
constexpr QLatin1String xPaddingBytesMin("xpadding_bytes_min");
|
||||
|
||||
@@ -48,11 +48,16 @@ namespace amnezia
|
||||
|
||||
namespace xray
|
||||
{
|
||||
constexpr char dataDir[] = "/opt/amnezia/xray";
|
||||
constexpr char serverConfigPath[] = "/opt/amnezia/xray/server.json";
|
||||
constexpr char expectedServerXrayRelease[] = "v26.7.28";
|
||||
constexpr char uuidPath[] = "/opt/amnezia/xray/xray_uuid.key";
|
||||
constexpr char PublicKeyPath[] = "/opt/amnezia/xray/xray_public.key";
|
||||
constexpr char PrivateKeyPath[] = "/opt/amnezia/xray/xray_private.key";
|
||||
constexpr char shortidPath[] = "/opt/amnezia/xray/xray_short_id.key";
|
||||
constexpr char tlsCertPath[] = "/opt/amnezia/xray/tls_cert.pem";
|
||||
constexpr char tlsKeyPath[] = "/opt/amnezia/xray/tls_key.pem";
|
||||
constexpr char clientTemplatePath[] = "/opt/amnezia/xray/template.json";
|
||||
constexpr char defaultSite[] = "www.googletagmanager.com";
|
||||
|
||||
constexpr char defaultPort[] = "443";
|
||||
@@ -67,7 +72,7 @@ namespace amnezia
|
||||
constexpr char defaultSni[] = "www.googletagmanager.com";
|
||||
constexpr char defaultAlpn[] = "h2";
|
||||
|
||||
constexpr char defaultXhttpMode[] = "Auto";
|
||||
constexpr char defaultXhttpMode[] = "Stream-one";
|
||||
constexpr char defaultXhttpUplinkMethod[] = "POST";
|
||||
constexpr char defaultXhttpSessionPlacement[] = "Path";
|
||||
constexpr char defaultXhttpSessionKey[] = "";
|
||||
@@ -75,9 +80,10 @@ namespace amnezia
|
||||
constexpr char defaultXhttpUplinkDataPlacement[] = "Body";
|
||||
|
||||
constexpr char defaultXhttpHost[] = "www.googletagmanager.com";
|
||||
constexpr char defaultXhttpPath[] = "/";
|
||||
constexpr char defaultXhttpUplinkChunkSize[] = "0";
|
||||
constexpr char defaultXhttpScMaxEachPostBytesMin[] = "1";
|
||||
constexpr char defaultXhttpScMaxEachPostBytesMax[] = "100";
|
||||
constexpr char defaultXhttpScMaxEachPostBytesMin[] = "1000000";
|
||||
constexpr char defaultXhttpScMaxEachPostBytesMax[] = "1000000";
|
||||
constexpr char defaultXhttpScMinPostsIntervalMsMin[] = "100";
|
||||
constexpr char defaultXhttpScMinPostsIntervalMsMax[] = "800";
|
||||
constexpr char defaultXhttpScStreamUpServerSecsMin[] = "1";
|
||||
@@ -93,8 +99,8 @@ namespace amnezia
|
||||
constexpr char defaultMkcpTti[] = "50";
|
||||
constexpr char defaultMkcpUplinkCapacity[] = "5";
|
||||
constexpr char defaultMkcpDownlinkCapacity[] = "20";
|
||||
constexpr char defaultMkcpReadBufferSize[] = "2";
|
||||
constexpr char defaultMkcpWriteBufferSize[] = "2";
|
||||
constexpr char defaultMkcpMtu[] = "1350";
|
||||
constexpr char defaultMkcpCwndMultiplier[] = "1";
|
||||
|
||||
constexpr char outbounds[] = "outbounds";
|
||||
constexpr char inbounds[] = "inbounds";
|
||||
@@ -120,6 +126,100 @@ namespace amnezia
|
||||
constexpr char spiderX[] = "spiderX";
|
||||
constexpr char user[] = "user";
|
||||
constexpr char pass[] = "pass";
|
||||
|
||||
// Envelope of a server.json / client.json document.
|
||||
constexpr char logBlock[] = "log";
|
||||
constexpr char logLevel[] = "loglevel";
|
||||
constexpr char logLevelError[] = "error";
|
||||
constexpr char protocol[] = "protocol";
|
||||
constexpr char protocolVless[] = "vless";
|
||||
constexpr char protocolFreedom[] = "freedom";
|
||||
constexpr char protocolSocks[] = "socks";
|
||||
constexpr char decryption[] = "decryption";
|
||||
constexpr char decryptionNone[] = "none";
|
||||
constexpr char listen[] = "listen";
|
||||
constexpr char udp[] = "udp";
|
||||
|
||||
// streamSettings blocks.
|
||||
constexpr char tlsSettings[] = "tlsSettings";
|
||||
constexpr char xhttpSettings[] = "xhttpSettings";
|
||||
constexpr char kcpSettings[] = "kcpSettings";
|
||||
constexpr char alpn[] = "alpn";
|
||||
constexpr char certificates[] = "certificates";
|
||||
constexpr char certificateFile[] = "certificateFile";
|
||||
constexpr char keyFile[] = "keyFile";
|
||||
constexpr char allowInsecure[] = "allowInsecure";
|
||||
constexpr char pinnedPeerCertSha256[] = "pinnedPeerCertSha256";
|
||||
|
||||
// realitySettings, server side only.
|
||||
constexpr char dest[] = "dest";
|
||||
constexpr char privateKey[] = "privateKey";
|
||||
constexpr char shortIds[] = "shortIds";
|
||||
|
||||
// xhttpSettings fields, Xray-core SplitHTTPConfig.
|
||||
constexpr char xhttpHost[] = "host";
|
||||
constexpr char xhttpPath[] = "path";
|
||||
constexpr char xhttpMode[] = "mode";
|
||||
constexpr char noGrpcHeader[] = "noGRPCHeader";
|
||||
constexpr char noSseHeader[] = "noSSEHeader";
|
||||
constexpr char sessionIdPlacement[] = "sessionIDPlacement";
|
||||
constexpr char sessionIdKey[] = "sessionIDKey";
|
||||
constexpr char seqPlacement[] = "seqPlacement";
|
||||
constexpr char seqKey[] = "seqKey";
|
||||
constexpr char uplinkDataPlacement[] = "uplinkDataPlacement";
|
||||
constexpr char uplinkDataKey[] = "uplinkDataKey";
|
||||
constexpr char uplinkHttpMethod[] = "uplinkHTTPMethod";
|
||||
constexpr char uplinkChunkSize[] = "uplinkChunkSize";
|
||||
constexpr char scMaxBufferedPosts[] = "scMaxBufferedPosts";
|
||||
constexpr char scMaxEachPostBytes[] = "scMaxEachPostBytes";
|
||||
constexpr char scMinPostsIntervalMs[] = "scMinPostsIntervalMs";
|
||||
constexpr char scStreamUpServerSecs[] = "scStreamUpServerSecs";
|
||||
constexpr char xPaddingObfsMode[] = "xPaddingObfsMode";
|
||||
constexpr char xPaddingBytes[] = "xPaddingBytes";
|
||||
constexpr char xPaddingKey[] = "xPaddingKey";
|
||||
constexpr char xPaddingHeader[] = "xPaddingHeader";
|
||||
constexpr char xPaddingPlacement[] = "xPaddingPlacement";
|
||||
constexpr char xPaddingMethod[] = "xPaddingMethod";
|
||||
|
||||
// xmux, client side only.
|
||||
constexpr char xmux[] = "xmux";
|
||||
constexpr char xmuxMaxConcurrency[] = "maxConcurrency";
|
||||
constexpr char xmuxMaxConnections[] = "maxConnections";
|
||||
constexpr char xmuxCMaxReuseTimes[] = "cMaxReuseTimes";
|
||||
constexpr char xmuxHMaxRequestTimes[] = "hMaxRequestTimes";
|
||||
constexpr char xmuxHMaxReusableSecs[] = "hMaxReusableSecs";
|
||||
constexpr char xmuxHKeepAlivePeriod[] = "hKeepAlivePeriod";
|
||||
|
||||
// kcpSettings fields.
|
||||
constexpr char kcpTti[] = "tti";
|
||||
constexpr char kcpMtu[] = "mtu";
|
||||
constexpr char kcpUplinkCapacity[] = "uplinkCapacity";
|
||||
constexpr char kcpDownlinkCapacity[] = "downlinkCapacity";
|
||||
constexpr char kcpCwndMultiplier[] = "cwndMultiplier";
|
||||
constexpr char kcpMaxSendingWindow[] = "maxSendingWindow";
|
||||
|
||||
// Aliases written by older builds, read only.
|
||||
constexpr char legacyXhttpMethod[] = "method";
|
||||
constexpr char legacySessionPlacement[] = "sessionPlacement";
|
||||
constexpr char legacyScSessionPlacement[] = "scSessionPlacement";
|
||||
constexpr char legacyScSeqPlacement[] = "scSeqPlacement";
|
||||
constexpr char legacyScUplinkDataPlacement[] = "scUplinkDataPlacement";
|
||||
constexpr char legacySessionKey[] = "sessionKey";
|
||||
constexpr char legacyUplinkChunkSize[] = "xhttpUplinkChunkSize";
|
||||
constexpr char legacyXPaddingBlock[] = "xPadding";
|
||||
constexpr char legacyRangeFrom[] = "from";
|
||||
constexpr char legacyRangeTo[] = "to";
|
||||
|
||||
// Transport / security values as they appear in xray json.
|
||||
constexpr char networkTcp[] = "tcp";
|
||||
constexpr char networkXhttp[] = "xhttp";
|
||||
constexpr char networkKcp[] = "kcp";
|
||||
constexpr char transportRaw[] = "raw";
|
||||
constexpr char transportXhttp[] = "xhttp";
|
||||
constexpr char transportMkcp[] = "mkcp";
|
||||
constexpr char securityNone[] = "none";
|
||||
constexpr char securityTls[] = "tls";
|
||||
constexpr char securityReality[] = "reality";
|
||||
}
|
||||
|
||||
namespace cloak
|
||||
|
||||
@@ -40,6 +40,12 @@ namespace amnezia
|
||||
XrayRealityKeysReadFailed = 217,
|
||||
ServerContainerRuntimeNotSupported = 218,
|
||||
ContainerRuntimeServiceNotRunning = 219,
|
||||
XrayKeyMigrationFailed = 220,
|
||||
XrayTlsNotSupported = 221,
|
||||
XrayServerConfigRejected = 222,
|
||||
XrayServerConfigRolledBack = 223,
|
||||
XrayServerNotServing = 224,
|
||||
ServerDataVolumeNotRemoved = 225,
|
||||
|
||||
// Ssh connection errors
|
||||
SshRequestDeniedError = 300,
|
||||
|
||||
@@ -39,6 +39,33 @@ QString errorString(ErrorCode code) {
|
||||
case(ErrorCode::XrayRealityKeysReadFailed):
|
||||
errorMessage = QObject::tr("Server error: failed to read XRay Reality keys from the server");
|
||||
break;
|
||||
case(ErrorCode::XrayTlsNotSupported):
|
||||
errorMessage = QObject::tr("Server error: could not create a TLS certificate on the XRay server. "
|
||||
"The previous settings were left unchanged. Try again, or use Reality.");
|
||||
break;
|
||||
case(ErrorCode::XrayServerConfigRejected):
|
||||
errorMessage = QObject::tr("Server error: XRay rejected the new configuration. "
|
||||
"Nothing was changed, the server keeps running with the previous settings.");
|
||||
break;
|
||||
case(ErrorCode::XrayServerConfigRolledBack):
|
||||
errorMessage = QObject::tr("Server error: XRay did not start with the new configuration. "
|
||||
"The previous settings were restored and the server is running again.");
|
||||
break;
|
||||
case(ErrorCode::XrayServerNotServing):
|
||||
errorMessage = QObject::tr("Server error: XRay is not accepting connections and the previous configuration "
|
||||
"could not be restored. The server needs attention: check it over SSH, "
|
||||
"or reinstall the protocol.");
|
||||
break;
|
||||
case(ErrorCode::ServerDataVolumeNotRemoved):
|
||||
errorMessage = QObject::tr("Server error: the previous data volume could not be removed. "
|
||||
"Installing on top of it would reuse the old keys, so the configurations you "
|
||||
"expected to revoke would keep working. Check the server and try again.");
|
||||
break;
|
||||
case(ErrorCode::XrayKeyMigrationFailed):
|
||||
errorMessage = QObject::tr("Server error: could not preserve the XRay keys stored on the server. "
|
||||
"The settings were not changed, so the existing configurations keep working. "
|
||||
"Check that the server is reachable and try again.");
|
||||
break;
|
||||
case(ErrorCode::ServerContainerRuntimeNotSupported): errorMessage = QObject::tr("Server error: The default container runtime available for installation on this server is not supported.\n Install Docker Engine on the server manually and try again."); break;
|
||||
case(ErrorCode::ContainerRuntimeServiceNotRunning): errorMessage = QObject::tr("Container runtime error: The container runtime service is not running.\n Check the container runtime service on the server, or wait about a minute and try again."); break;
|
||||
|
||||
|
||||
@@ -265,10 +265,8 @@ amnezia::ScriptVars amnezia::genAwgVars(const ContainerConfig &containerConfig)
|
||||
vars.append({ { "$REJECT_AFTER_TIME", config.rejectAfterTime } });
|
||||
vars.append({ { "$KEEPALIVE_TIMEOUT", config.keepaliveTimeout } });
|
||||
vars.append({ { "$MAX_HANDSHAKE_ATTEMPTS", config.maxHandshakeAttempts } });
|
||||
vars.append({ { "$RANDOM_TRAILERS", AwgProtocolConfig::isToggleEnabled(config.randomTrailers)
|
||||
? config.randomTrailers : QString() } });
|
||||
vars.append({ { "$DISABLE_COOKIES", AwgProtocolConfig::isToggleEnabled(config.disableCookies)
|
||||
? config.disableCookies : QString() } });
|
||||
vars.append({ { "$RANDOM_TRAILERS", config.randomTrailers } });
|
||||
vars.append({ { "$DISABLE_COOKIES", config.disableCookies } });
|
||||
}
|
||||
|
||||
return vars;
|
||||
|
||||
@@ -38,9 +38,9 @@
|
||||
</dict>
|
||||
|
||||
<key>com.wireguard.ios.app_group_id</key>
|
||||
<string>${BUILD_IOS_GROUP_IDENTIFIER}</string>
|
||||
<string>group.${BUILD_IOS_APP_IDENTIFIER}</string>
|
||||
|
||||
<key>com.wireguard.macos.app_group_id</key>
|
||||
<string>${BUILD_VPN_DEVELOPMENT_TEAM}.${BUILD_IOS_GROUP_IDENTIFIER}</string>
|
||||
<string>${BUILD_VPN_DEVELOPMENT_TEAM}.group.${BUILD_OSX_APP_IDENTIFIER}</string>
|
||||
</dict>
|
||||
</plist>
|
||||
@@ -92,7 +92,7 @@ extension PacketTunnelProvider {
|
||||
}
|
||||
}
|
||||
} catch {
|
||||
wg_log(.error, message: "Can't parse WG config: \(String(describing: error))")
|
||||
wg_log(.error, message: "Can't parse WG config: \(error.localizedDescription)")
|
||||
errorNotifier.notify(PacketTunnelProviderError.savedProtocolConfigurationIsInvalid)
|
||||
completionHandler(PacketTunnelProviderError.savedProtocolConfigurationIsInvalid)
|
||||
return
|
||||
|
||||
@@ -1,18 +1,57 @@
|
||||
cd /opt/amnezia/xray
|
||||
XRAY_CLIENT_ID=$(xray uuid) && echo $XRAY_CLIENT_ID > /opt/amnezia/xray/xray_uuid.key
|
||||
XRAY_SHORT_ID=$(openssl rand -hex 8) && echo $XRAY_SHORT_ID > /opt/amnezia/xray/xray_short_id.key
|
||||
XRAY_DIR=/opt/amnezia/xray
|
||||
|
||||
# Parse x25519 keypair by label (v26.7 output has an extra Hash32 line; line-index parsing breaks).
|
||||
KEYPAIR=$(xray x25519)
|
||||
XRAY_PRIVATE_KEY=$(printf '%s\n' "$KEYPAIR" | sed -n 's/.*[Pp]rivate[ ]*[Kk]ey:[[:space:]]*//p' | head -1)
|
||||
XRAY_PUBLIC_KEY=$(printf '%s\n' "$KEYPAIR" | sed -n 's/.*(PublicKey):[[:space:]]*//p' | head -1)
|
||||
[ -z "$XRAY_PUBLIC_KEY" ] && XRAY_PUBLIC_KEY=$(printf '%s\n' "$KEYPAIR" | sed -n 's/.*[Pp]ublic[ ]*[Kk]ey:[[:space:]]*//p' | head -1)
|
||||
# /opt/amnezia/xray is a docker volume, so these files outlive the container.
|
||||
# Regenerating any of them revokes every config already handed out, so each one is
|
||||
# created only when it is really missing.
|
||||
#
|
||||
# "Really missing" is checked by content, not by file size. A failed generation used
|
||||
# to leave a file holding a single newline, which is one byte, so a size test would
|
||||
# call it present and the key would never be repaired. With the volume that state is
|
||||
# permanent: nothing short of manual SSH would clear it.
|
||||
has_key() {
|
||||
[ -f "$1" ] && [ -n "$(tr -d '[:space:]' < "$1" 2>/dev/null)" ]
|
||||
}
|
||||
|
||||
XRAY_PRIVATE_KEY=$(echo $XRAY_PRIVATE_KEY | tr -d ' ')
|
||||
XRAY_PUBLIC_KEY=$(echo $XRAY_PUBLIC_KEY | tr -d ' ')
|
||||
if ! has_key $XRAY_DIR/xray_uuid.key; then
|
||||
XRAY_CLIENT_ID=$(xray uuid) && [ -n "$XRAY_CLIENT_ID" ] && printf '%s\n' "$XRAY_CLIENT_ID" > $XRAY_DIR/xray_uuid.key
|
||||
fi
|
||||
|
||||
if ! has_key $XRAY_DIR/xray_short_id.key; then
|
||||
XRAY_SHORT_ID=$(openssl rand -hex 8) && [ -n "$XRAY_SHORT_ID" ] && printf '%s\n' "$XRAY_SHORT_ID" > $XRAY_DIR/xray_short_id.key
|
||||
fi
|
||||
|
||||
echo $XRAY_PUBLIC_KEY > /opt/amnezia/xray/xray_public.key
|
||||
echo $XRAY_PRIVATE_KEY > /opt/amnezia/xray/xray_private.key
|
||||
# The private key is the one that must never change: it is what every issued config
|
||||
# is bound to. If only the public half is missing it gets derived from the private
|
||||
# one rather than rotating the pair.
|
||||
if has_key $XRAY_DIR/xray_private.key && ! has_key $XRAY_DIR/xray_public.key; then
|
||||
XRAY_PRIVATE_KEY=$(tr -d '[:space:]' < $XRAY_DIR/xray_private.key)
|
||||
DERIVED=$(xray x25519 -i "$XRAY_PRIVATE_KEY" 2>/dev/null)
|
||||
XRAY_PUBLIC_KEY=$(printf '%s\n' "$DERIVED" | sed -n 's/.*(PublicKey):[[:space:]]*//p' | head -1)
|
||||
[ -z "$XRAY_PUBLIC_KEY" ] && XRAY_PUBLIC_KEY=$(printf '%s\n' "$DERIVED" | sed -n 's/.*[Pp]ublic[ ]*[Kk]ey:[[:space:]]*//p' | head -1)
|
||||
XRAY_PUBLIC_KEY=$(echo $XRAY_PUBLIC_KEY | tr -d ' ')
|
||||
if [ -n "$XRAY_PUBLIC_KEY" ]; then
|
||||
printf '%s\n' "$XRAY_PUBLIC_KEY" > $XRAY_DIR/xray_public.key
|
||||
fi
|
||||
fi
|
||||
|
||||
# server.json is written by the client (writeServerConfigForSetup); this script only makes keys.
|
||||
if ! has_key $XRAY_DIR/xray_private.key || ! has_key $XRAY_DIR/xray_public.key; then
|
||||
KEYPAIR=$(xray x25519)
|
||||
XRAY_PRIVATE_KEY=$(printf '%s\n' "$KEYPAIR" | sed -n 's/.*[Pp]rivate[ ]*[Kk]ey:[[:space:]]*//p' | head -1)
|
||||
XRAY_PUBLIC_KEY=$(printf '%s\n' "$KEYPAIR" | sed -n 's/.*(PublicKey):[[:space:]]*//p' | head -1)
|
||||
[ -z "$XRAY_PUBLIC_KEY" ] && XRAY_PUBLIC_KEY=$(printf '%s\n' "$KEYPAIR" | sed -n 's/.*[Pp]ublic[ ]*[Kk]ey:[[:space:]]*//p' | head -1)
|
||||
|
||||
XRAY_PRIVATE_KEY=$(echo $XRAY_PRIVATE_KEY | tr -d ' ')
|
||||
XRAY_PUBLIC_KEY=$(echo $XRAY_PUBLIC_KEY | tr -d ' ')
|
||||
|
||||
# Both or neither. A half-written pair hands clients a public key the server is
|
||||
# not using, and it would look complete enough never to be repaired.
|
||||
if [ -n "$XRAY_PRIVATE_KEY" ] && [ -n "$XRAY_PUBLIC_KEY" ]; then
|
||||
printf '%s\n' "$XRAY_PRIVATE_KEY" > $XRAY_DIR/xray_private.key.tmp
|
||||
printf '%s\n' "$XRAY_PUBLIC_KEY" > $XRAY_DIR/xray_public.key.tmp
|
||||
mv $XRAY_DIR/xray_private.key.tmp $XRAY_DIR/xray_private.key
|
||||
mv $XRAY_DIR/xray_public.key.tmp $XRAY_DIR/xray_public.key
|
||||
else
|
||||
rm -f $XRAY_DIR/xray_private.key.tmp $XRAY_DIR/xray_public.key.tmp
|
||||
echo "amnezia_xray_keygen=failed"
|
||||
fi
|
||||
fi
|
||||
|
||||
@@ -6,6 +6,7 @@ sudo docker run -d \
|
||||
--cap-add=NET_ADMIN \
|
||||
-p $XRAY_SERVER_PORT:$XRAY_SERVER_PORT/tcp \
|
||||
-p $XRAY_SERVER_PORT:$XRAY_SERVER_PORT/udp \
|
||||
-v $CONTAINER_NAME-data:/opt/amnezia/xray \
|
||||
--name $CONTAINER_NAME $CONTAINER_NAME
|
||||
|
||||
sudo docker network connect amnezia-dns-net $CONTAINER_NAME
|
||||
|
||||
@@ -591,27 +591,27 @@ Already installed containers were found on the server. All installed containers
|
||||
<message>
|
||||
<location filename="../ui/qml/Pages2/PageProtocolAwgClientSettings.qml" line="132"/>
|
||||
<source>I1 - First special junk packet</source>
|
||||
<translation>I1 - First special junk packet</translation>
|
||||
<translation>I1 - أول حزمة بيانات زائفة خاصة</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../ui/qml/Pages2/PageProtocolAwgClientSettings.qml" line="142"/>
|
||||
<source>I2 - Second special junk packet</source>
|
||||
<translation>I2 - Second special junk packet</translation>
|
||||
<translation>I2 - ثاني حزمة بيانات زائفة خاصة</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../ui/qml/Pages2/PageProtocolAwgClientSettings.qml" line="152"/>
|
||||
<source>I3 - Third special junk packet</source>
|
||||
<translation>I3 - Third special junk packet</translation>
|
||||
<translation>I3 - ثالث حزمة بيانات زائفة خاصة</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../ui/qml/Pages2/PageProtocolAwgClientSettings.qml" line="162"/>
|
||||
<source>I4 - Fourth special junk packet</source>
|
||||
<translation>I4 - Fourth special junk packet</translation>
|
||||
<translation>I4 - رابع حزمة بيانات زائفة خاصة</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../ui/qml/Pages2/PageProtocolAwgClientSettings.qml" line="172"/>
|
||||
<source>I5 - Fifth special junk packet</source>
|
||||
<translation>I5 - Fifth special junk packet</translation>
|
||||
<translation>I5 - خامس حزمة بيانات زائفة خاصة</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../ui/qml/Pages2/PageProtocolAwgClientSettings.qml" line="189"/>
|
||||
@@ -621,32 +621,32 @@ Already installed containers were found on the server. All installed containers
|
||||
<message>
|
||||
<location filename="../ui/qml/Pages2/PageProtocolAwgClientSettings.qml" line="199"/>
|
||||
<source>ContentPaddingAddition - Content padding addition</source>
|
||||
<translation>ContentPaddingAddition - Content padding addition</translation>
|
||||
<translation>ContentPaddingAddition - إضافة حشو للمحتوى</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../ui/qml/Pages2/PageProtocolAwgClientSettings.qml" line="211"/>
|
||||
<source>RekeyAfterTime - Rekey after time</source>
|
||||
<translation>RekeyAfterTime - Rekey after time</translation>
|
||||
<translation>RekeyAfterTime - إعادة توليد المفتاح بعد مدة</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../ui/qml/Pages2/PageProtocolAwgClientSettings.qml" line="223"/>
|
||||
<source>RekeyTimeout - Rekey timeout</source>
|
||||
<translation>RekeyTimeout - Rekey timeout</translation>
|
||||
<translation>RekeyTimeout - مدة انتظار إعادة توليد المفتاح</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../ui/qml/Pages2/PageProtocolAwgClientSettings.qml" line="235"/>
|
||||
<source>RejectAfterTime - Reject after time</source>
|
||||
<translation>RejectAfterTime - Reject after time</translation>
|
||||
<translation>RejectAfterTime - الرفض بعد مدة</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../ui/qml/Pages2/PageProtocolAwgClientSettings.qml" line="247"/>
|
||||
<source>KeepaliveTimeout - Keepalive timeout</source>
|
||||
<translation>KeepaliveTimeout - Keepalive timeout</translation>
|
||||
<translation>KeepaliveTimeout - مدة انتظار إبقاء الاتصال</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../ui/qml/Pages2/PageProtocolAwgClientSettings.qml" line="259"/>
|
||||
<source>MaxHandshakeAttempts - Max handshake attempts</source>
|
||||
<translation>MaxHandshakeAttempts - Max handshake attempts</translation>
|
||||
<translation>MaxHandshakeAttempts - أقصى عدد لمحاولات المصافحة</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../ui/qml/Pages2/PageProtocolAwgClientSettings.qml" line="276"/>
|
||||
@@ -719,82 +719,82 @@ Already installed containers were found on the server. All installed containers
|
||||
<message>
|
||||
<location filename="../ui/qml/Pages2/PageProtocolAwgSettings.qml" line="131"/>
|
||||
<source>Jc - Junk packet count</source>
|
||||
<translation>Jc - Junk packet count</translation>
|
||||
<translation>Jc - عدد الحزم غير المرغوب فيها</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../ui/qml/Pages2/PageProtocolAwgSettings.qml" line="141"/>
|
||||
<source>Jmin - Junk packet minimum size</source>
|
||||
<translation>Jmin - Junk packet minimum size</translation>
|
||||
<translation>Jmin - الحجم الادني للحزم الغير مرغوب فيها</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../ui/qml/Pages2/PageProtocolAwgSettings.qml" line="151"/>
|
||||
<source>Jmax - Junk packet maximum size</source>
|
||||
<translation>Jmax - Junk packet maximum size</translation>
|
||||
<translation>Jmax - الحجم الاقصي للحزم الغير مرغوب فيها</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../ui/qml/Pages2/PageProtocolAwgSettings.qml" line="161"/>
|
||||
<source>S1 - Init packet junk size</source>
|
||||
<translation>S1 - Init packet junk size</translation>
|
||||
<translation>S1 - حجم حزمة البيانات العشوائية الأولية</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../ui/qml/Pages2/PageProtocolAwgSettings.qml" line="171"/>
|
||||
<source>S2 - Response packet junk size</source>
|
||||
<translation>S2 - Response packet junk size</translation>
|
||||
<translation>S2 - حجم حزمة الاستجابة غير المرغوب فيها</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../ui/qml/Pages2/PageProtocolAwgSettings.qml" line="183"/>
|
||||
<source>S3 - Cookie reply packet junk size</source>
|
||||
<translation>S3 - Cookie reply packet junk size</translation>
|
||||
<translation>S3 - حجم البيانات الزائفة في حزمة رد الكوكيز</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../ui/qml/Pages2/PageProtocolAwgSettings.qml" line="195"/>
|
||||
<source>S4 - Transport packet junk size</source>
|
||||
<translation>S4 - Transport packet junk size</translation>
|
||||
<translation>S4 - حجم البيانات الزائفة في حزمة النقل</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../ui/qml/Pages2/PageProtocolAwgSettings.qml" line="207"/>
|
||||
<source>H1 - Init packet magic header</source>
|
||||
<translation>H1 - Init packet magic header</translation>
|
||||
<translation>H1 - حزمة رأس سحرية مبدئية</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../ui/qml/Pages2/PageProtocolAwgSettings.qml" line="219"/>
|
||||
<source>H2 - Response packet magic header</source>
|
||||
<translation>H2 - Response packet magic header</translation>
|
||||
<translation>H2 - رأس حزمة الاستجابة السحرية</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../ui/qml/Pages2/PageProtocolAwgSettings.qml" line="231"/>
|
||||
<source>H3 - Underload packet magic header</source>
|
||||
<translation>H3 - Underload packet magic header</translation>
|
||||
<translation>H3 - رأس حزمة السحر غير المحمل</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../ui/qml/Pages2/PageProtocolAwgSettings.qml" line="243"/>
|
||||
<source>H4 - Transport packet magic header</source>
|
||||
<translation>H4 - Transport packet magic header</translation>
|
||||
<translation>H4 - رأس حزمة النقل السحرية</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../ui/qml/Pages2/PageProtocolAwgSettings.qml" line="253"/>
|
||||
<source>I1 - Special junk 1</source>
|
||||
<translation>I1 - Special junk 1</translation>
|
||||
<translation>I1 - بيانات زائفة خاصة 1</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../ui/qml/Pages2/PageProtocolAwgSettings.qml" line="263"/>
|
||||
<source>I2 - Special junk 2</source>
|
||||
<translation>I2 - Special junk 2</translation>
|
||||
<translation>I2 - بيانات زائفة خاصة 2</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../ui/qml/Pages2/PageProtocolAwgSettings.qml" line="273"/>
|
||||
<source>I3 - Special junk 3</source>
|
||||
<translation>I3 - Special junk 3</translation>
|
||||
<translation>I3 - بيانات زائفة خاصة 3</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../ui/qml/Pages2/PageProtocolAwgSettings.qml" line="283"/>
|
||||
<source>I4 - Special junk 4</source>
|
||||
<translation>I4 - Special junk 4</translation>
|
||||
<translation>I4 - بيانات زائفة خاصة 4</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../ui/qml/Pages2/PageProtocolAwgSettings.qml" line="293"/>
|
||||
<source>I5 - Special junk 5</source>
|
||||
<translation>I5 - Special junk 5</translation>
|
||||
<translation>I5 - بيانات زائفة خاصة 5</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../ui/qml/Pages2/PageProtocolAwgSettings.qml" line="310"/>
|
||||
@@ -804,32 +804,32 @@ Already installed containers were found on the server. All installed containers
|
||||
<message>
|
||||
<location filename="../ui/qml/Pages2/PageProtocolAwgSettings.qml" line="326"/>
|
||||
<source>ContentPaddingAddition - Content padding addition</source>
|
||||
<translation>ContentPaddingAddition - Content padding addition</translation>
|
||||
<translation>ContentPaddingAddition - إضافة حشو للمحتوى</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../ui/qml/Pages2/PageProtocolAwgSettings.qml" line="339"/>
|
||||
<source>RekeyAfterTime - Rekey after time</source>
|
||||
<translation>RekeyAfterTime - Rekey after time</translation>
|
||||
<translation>RekeyAfterTime - إعادة توليد المفتاح بعد مدة</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../ui/qml/Pages2/PageProtocolAwgSettings.qml" line="352"/>
|
||||
<source>RekeyTimeout - Rekey timeout</source>
|
||||
<translation>RekeyTimeout - Rekey timeout</translation>
|
||||
<translation>RekeyTimeout - مدة انتظار إعادة توليد المفتاح</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../ui/qml/Pages2/PageProtocolAwgSettings.qml" line="365"/>
|
||||
<source>RejectAfterTime - Reject after time</source>
|
||||
<translation>RejectAfterTime - Reject after time</translation>
|
||||
<translation>RejectAfterTime - الرفض بعد مدة</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../ui/qml/Pages2/PageProtocolAwgSettings.qml" line="378"/>
|
||||
<source>KeepaliveTimeout - Keepalive timeout</source>
|
||||
<translation>KeepaliveTimeout - Keepalive timeout</translation>
|
||||
<translation>KeepaliveTimeout - مدة انتظار إبقاء الاتصال</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../ui/qml/Pages2/PageProtocolAwgSettings.qml" line="391"/>
|
||||
<source>MaxHandshakeAttempts - Max handshake attempts</source>
|
||||
<translation>MaxHandshakeAttempts - Max handshake attempts</translation>
|
||||
<translation>MaxHandshakeAttempts - أقصى عدد لمحاولات المصافحة</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../ui/qml/Pages2/PageProtocolAwgSettings.qml" line="408"/>
|
||||
|
||||
@@ -590,27 +590,27 @@ Se han encontrado contenedores ya instalados en el servidor. Todos ellos se han
|
||||
<message>
|
||||
<location filename="../ui/qml/Pages2/PageProtocolAwgClientSettings.qml" line="132"/>
|
||||
<source>I1 - First special junk packet</source>
|
||||
<translation>I1 - First special junk packet</translation>
|
||||
<translation>I1 - Primer paquete basura especial</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../ui/qml/Pages2/PageProtocolAwgClientSettings.qml" line="142"/>
|
||||
<source>I2 - Second special junk packet</source>
|
||||
<translation>I2 - Second special junk packet</translation>
|
||||
<translation>I2 - Segundo paquete basura especial</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../ui/qml/Pages2/PageProtocolAwgClientSettings.qml" line="152"/>
|
||||
<source>I3 - Third special junk packet</source>
|
||||
<translation>I3 - Third special junk packet</translation>
|
||||
<translation>I3 - Tercer paquete basura especial</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../ui/qml/Pages2/PageProtocolAwgClientSettings.qml" line="162"/>
|
||||
<source>I4 - Fourth special junk packet</source>
|
||||
<translation>I4 - Fourth special junk packet</translation>
|
||||
<translation>I4 - Cuarto paquete basura especial</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../ui/qml/Pages2/PageProtocolAwgClientSettings.qml" line="172"/>
|
||||
<source>I5 - Fifth special junk packet</source>
|
||||
<translation>I5 - Fifth special junk packet</translation>
|
||||
<translation>I5 - Quinto paquete basura especial</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../ui/qml/Pages2/PageProtocolAwgClientSettings.qml" line="189"/>
|
||||
@@ -620,32 +620,32 @@ Se han encontrado contenedores ya instalados en el servidor. Todos ellos se han
|
||||
<message>
|
||||
<location filename="../ui/qml/Pages2/PageProtocolAwgClientSettings.qml" line="199"/>
|
||||
<source>ContentPaddingAddition - Content padding addition</source>
|
||||
<translation>ContentPaddingAddition - Content padding addition</translation>
|
||||
<translation>ContentPaddingAddition - Relleno adicional de contenido</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../ui/qml/Pages2/PageProtocolAwgClientSettings.qml" line="211"/>
|
||||
<source>RekeyAfterTime - Rekey after time</source>
|
||||
<translation>RekeyAfterTime - Rekey after time</translation>
|
||||
<translation>RekeyAfterTime - Renovar la clave tras un tiempo</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../ui/qml/Pages2/PageProtocolAwgClientSettings.qml" line="223"/>
|
||||
<source>RekeyTimeout - Rekey timeout</source>
|
||||
<translation>RekeyTimeout - Rekey timeout</translation>
|
||||
<translation>RekeyTimeout - Tiempo de espera de renovación de clave</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../ui/qml/Pages2/PageProtocolAwgClientSettings.qml" line="235"/>
|
||||
<source>RejectAfterTime - Reject after time</source>
|
||||
<translation>RejectAfterTime - Reject after time</translation>
|
||||
<translation>RejectAfterTime - Rechazar tras un tiempo</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../ui/qml/Pages2/PageProtocolAwgClientSettings.qml" line="247"/>
|
||||
<source>KeepaliveTimeout - Keepalive timeout</source>
|
||||
<translation>KeepaliveTimeout - Keepalive timeout</translation>
|
||||
<translation>KeepaliveTimeout - Tiempo de espera de keepalive</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../ui/qml/Pages2/PageProtocolAwgClientSettings.qml" line="259"/>
|
||||
<source>MaxHandshakeAttempts - Max handshake attempts</source>
|
||||
<translation>MaxHandshakeAttempts - Max handshake attempts</translation>
|
||||
<translation>MaxHandshakeAttempts - Número máximo de intentos de handshake</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../ui/qml/Pages2/PageProtocolAwgClientSettings.qml" line="276"/>
|
||||
@@ -718,82 +718,82 @@ Se han encontrado contenedores ya instalados en el servidor. Todos ellos se han
|
||||
<message>
|
||||
<location filename="../ui/qml/Pages2/PageProtocolAwgSettings.qml" line="131"/>
|
||||
<source>Jc - Junk packet count</source>
|
||||
<translation>Jc - Junk packet count</translation>
|
||||
<translation>Jc - Número de paquetes basura</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../ui/qml/Pages2/PageProtocolAwgSettings.qml" line="141"/>
|
||||
<source>Jmin - Junk packet minimum size</source>
|
||||
<translation>Jmin - Junk packet minimum size</translation>
|
||||
<translation>Jmin - Tamaño mínimo del paquete basura</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../ui/qml/Pages2/PageProtocolAwgSettings.qml" line="151"/>
|
||||
<source>Jmax - Junk packet maximum size</source>
|
||||
<translation>Jmax - Junk packet maximum size</translation>
|
||||
<translation>Jmax - Tamaño máximo del paquete basura</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../ui/qml/Pages2/PageProtocolAwgSettings.qml" line="161"/>
|
||||
<source>S1 - Init packet junk size</source>
|
||||
<translation>S1 - Init packet junk size</translation>
|
||||
<translation>S1 - Tamaño de basura del paquete de inicio</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../ui/qml/Pages2/PageProtocolAwgSettings.qml" line="171"/>
|
||||
<source>S2 - Response packet junk size</source>
|
||||
<translation>S2 - Response packet junk size</translation>
|
||||
<translation>S2 - Tamaño de basura del paquete de respuesta</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../ui/qml/Pages2/PageProtocolAwgSettings.qml" line="183"/>
|
||||
<source>S3 - Cookie reply packet junk size</source>
|
||||
<translation>S3 - Cookie reply packet junk size</translation>
|
||||
<translation>S3 - Tamaño de basura del paquete de respuesta de cookie</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../ui/qml/Pages2/PageProtocolAwgSettings.qml" line="195"/>
|
||||
<source>S4 - Transport packet junk size</source>
|
||||
<translation>S4 - Transport packet junk size</translation>
|
||||
<translation>S4 - Tamaño de basura del paquete de transporte</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../ui/qml/Pages2/PageProtocolAwgSettings.qml" line="207"/>
|
||||
<source>H1 - Init packet magic header</source>
|
||||
<translation>H1 - Init packet magic header</translation>
|
||||
<translation>H1 - Cabecera mágica del paquete de inicio</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../ui/qml/Pages2/PageProtocolAwgSettings.qml" line="219"/>
|
||||
<source>H2 - Response packet magic header</source>
|
||||
<translation>H2 - Response packet magic header</translation>
|
||||
<translation>H2 - Cabecera mágica del paquete de respuesta</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../ui/qml/Pages2/PageProtocolAwgSettings.qml" line="231"/>
|
||||
<source>H3 - Underload packet magic header</source>
|
||||
<translation>H3 - Underload packet magic header</translation>
|
||||
<translation>H3 - Cabecera mágica del paquete de subcarga</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../ui/qml/Pages2/PageProtocolAwgSettings.qml" line="243"/>
|
||||
<source>H4 - Transport packet magic header</source>
|
||||
<translation>H4 - Transport packet magic header</translation>
|
||||
<translation>H4 - Cabecera mágica del paquete de transporte</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../ui/qml/Pages2/PageProtocolAwgSettings.qml" line="253"/>
|
||||
<source>I1 - Special junk 1</source>
|
||||
<translation>I1 - Special junk 1</translation>
|
||||
<translation>I1 - Basura especial 1</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../ui/qml/Pages2/PageProtocolAwgSettings.qml" line="263"/>
|
||||
<source>I2 - Special junk 2</source>
|
||||
<translation>I2 - Special junk 2</translation>
|
||||
<translation>I2 - Basura especial 2</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../ui/qml/Pages2/PageProtocolAwgSettings.qml" line="273"/>
|
||||
<source>I3 - Special junk 3</source>
|
||||
<translation>I3 - Special junk 3</translation>
|
||||
<translation>I3 - Basura especial 3</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../ui/qml/Pages2/PageProtocolAwgSettings.qml" line="283"/>
|
||||
<source>I4 - Special junk 4</source>
|
||||
<translation>I4 - Special junk 4</translation>
|
||||
<translation>I4 - Basura especial 4</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../ui/qml/Pages2/PageProtocolAwgSettings.qml" line="293"/>
|
||||
<source>I5 - Special junk 5</source>
|
||||
<translation>I5 - Special junk 5</translation>
|
||||
<translation>I5 - Basura especial 5</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../ui/qml/Pages2/PageProtocolAwgSettings.qml" line="310"/>
|
||||
@@ -803,32 +803,32 @@ Se han encontrado contenedores ya instalados en el servidor. Todos ellos se han
|
||||
<message>
|
||||
<location filename="../ui/qml/Pages2/PageProtocolAwgSettings.qml" line="326"/>
|
||||
<source>ContentPaddingAddition - Content padding addition</source>
|
||||
<translation>ContentPaddingAddition - Content padding addition</translation>
|
||||
<translation>ContentPaddingAddition - Relleno adicional de contenido</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../ui/qml/Pages2/PageProtocolAwgSettings.qml" line="339"/>
|
||||
<source>RekeyAfterTime - Rekey after time</source>
|
||||
<translation>RekeyAfterTime - Rekey after time</translation>
|
||||
<translation>RekeyAfterTime - Renovar la clave tras un tiempo</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../ui/qml/Pages2/PageProtocolAwgSettings.qml" line="352"/>
|
||||
<source>RekeyTimeout - Rekey timeout</source>
|
||||
<translation>RekeyTimeout - Rekey timeout</translation>
|
||||
<translation>RekeyTimeout - Tiempo de espera de renovación de clave</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../ui/qml/Pages2/PageProtocolAwgSettings.qml" line="365"/>
|
||||
<source>RejectAfterTime - Reject after time</source>
|
||||
<translation>RejectAfterTime - Reject after time</translation>
|
||||
<translation>RejectAfterTime - Rechazar tras un tiempo</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../ui/qml/Pages2/PageProtocolAwgSettings.qml" line="378"/>
|
||||
<source>KeepaliveTimeout - Keepalive timeout</source>
|
||||
<translation>KeepaliveTimeout - Keepalive timeout</translation>
|
||||
<translation>KeepaliveTimeout - Tiempo de espera de keepalive</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../ui/qml/Pages2/PageProtocolAwgSettings.qml" line="391"/>
|
||||
<source>MaxHandshakeAttempts - Max handshake attempts</source>
|
||||
<translation>MaxHandshakeAttempts - Max handshake attempts</translation>
|
||||
<translation>MaxHandshakeAttempts - Número máximo de intentos de handshake</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../ui/qml/Pages2/PageProtocolAwgSettings.qml" line="408"/>
|
||||
|
||||
@@ -590,27 +590,27 @@ Already installed containers were found on the server. All installed containers
|
||||
<message>
|
||||
<location filename="../ui/qml/Pages2/PageProtocolAwgClientSettings.qml" line="132"/>
|
||||
<source>I1 - First special junk packet</source>
|
||||
<translation>I1 - First special junk packet</translation>
|
||||
<translation>I1 - نخستین بسته زائد ویژه</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../ui/qml/Pages2/PageProtocolAwgClientSettings.qml" line="142"/>
|
||||
<source>I2 - Second special junk packet</source>
|
||||
<translation>I2 - Second special junk packet</translation>
|
||||
<translation>I2 - دومین بسته زائد ویژه</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../ui/qml/Pages2/PageProtocolAwgClientSettings.qml" line="152"/>
|
||||
<source>I3 - Third special junk packet</source>
|
||||
<translation>I3 - Third special junk packet</translation>
|
||||
<translation>I3 - سومین بسته زائد ویژه</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../ui/qml/Pages2/PageProtocolAwgClientSettings.qml" line="162"/>
|
||||
<source>I4 - Fourth special junk packet</source>
|
||||
<translation>I4 - Fourth special junk packet</translation>
|
||||
<translation>I4 - چهارمین بسته زائد ویژه</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../ui/qml/Pages2/PageProtocolAwgClientSettings.qml" line="172"/>
|
||||
<source>I5 - Fifth special junk packet</source>
|
||||
<translation>I5 - Fifth special junk packet</translation>
|
||||
<translation>I5 - پنجمین بسته زائد ویژه</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../ui/qml/Pages2/PageProtocolAwgClientSettings.qml" line="189"/>
|
||||
@@ -620,32 +620,32 @@ Already installed containers were found on the server. All installed containers
|
||||
<message>
|
||||
<location filename="../ui/qml/Pages2/PageProtocolAwgClientSettings.qml" line="199"/>
|
||||
<source>ContentPaddingAddition - Content padding addition</source>
|
||||
<translation>ContentPaddingAddition - Content padding addition</translation>
|
||||
<translation>ContentPaddingAddition - افزودن لایهگذاری محتوا</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../ui/qml/Pages2/PageProtocolAwgClientSettings.qml" line="211"/>
|
||||
<source>RekeyAfterTime - Rekey after time</source>
|
||||
<translation>RekeyAfterTime - Rekey after time</translation>
|
||||
<translation>RekeyAfterTime - تولید دوباره کلید پس از زمان</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../ui/qml/Pages2/PageProtocolAwgClientSettings.qml" line="223"/>
|
||||
<source>RekeyTimeout - Rekey timeout</source>
|
||||
<translation>RekeyTimeout - Rekey timeout</translation>
|
||||
<translation>RekeyTimeout - زمان انتظار تولید دوباره کلید</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../ui/qml/Pages2/PageProtocolAwgClientSettings.qml" line="235"/>
|
||||
<source>RejectAfterTime - Reject after time</source>
|
||||
<translation>RejectAfterTime - Reject after time</translation>
|
||||
<translation>RejectAfterTime - رد کردن پس از زمان</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../ui/qml/Pages2/PageProtocolAwgClientSettings.qml" line="247"/>
|
||||
<source>KeepaliveTimeout - Keepalive timeout</source>
|
||||
<translation>KeepaliveTimeout - Keepalive timeout</translation>
|
||||
<translation>KeepaliveTimeout - زمان انتظار keepalive</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../ui/qml/Pages2/PageProtocolAwgClientSettings.qml" line="259"/>
|
||||
<source>MaxHandshakeAttempts - Max handshake attempts</source>
|
||||
<translation>MaxHandshakeAttempts - Max handshake attempts</translation>
|
||||
<translation>MaxHandshakeAttempts - بیشینه تلاشهای دستدهی</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../ui/qml/Pages2/PageProtocolAwgClientSettings.qml" line="276"/>
|
||||
@@ -718,82 +718,82 @@ Already installed containers were found on the server. All installed containers
|
||||
<message>
|
||||
<location filename="../ui/qml/Pages2/PageProtocolAwgSettings.qml" line="131"/>
|
||||
<source>Jc - Junk packet count</source>
|
||||
<translation>Jc - Junk packet count</translation>
|
||||
<translation>Jc - تعداد بستههای زائد</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../ui/qml/Pages2/PageProtocolAwgSettings.qml" line="141"/>
|
||||
<source>Jmin - Junk packet minimum size</source>
|
||||
<translation>Jmin - Junk packet minimum size</translation>
|
||||
<translation>Jmin - کمینه اندازه بسته زائد</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../ui/qml/Pages2/PageProtocolAwgSettings.qml" line="151"/>
|
||||
<source>Jmax - Junk packet maximum size</source>
|
||||
<translation>Jmax - Junk packet maximum size</translation>
|
||||
<translation>Jmax - بیشینه اندازه بسته زائد</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../ui/qml/Pages2/PageProtocolAwgSettings.qml" line="161"/>
|
||||
<source>S1 - Init packet junk size</source>
|
||||
<translation>S1 - Init packet junk size</translation>
|
||||
<translation>S1 - اندازه داده زائد بسته آغازین</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../ui/qml/Pages2/PageProtocolAwgSettings.qml" line="171"/>
|
||||
<source>S2 - Response packet junk size</source>
|
||||
<translation>S2 - Response packet junk size</translation>
|
||||
<translation>S2 - اندازه داده زائد بسته پاسخ</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../ui/qml/Pages2/PageProtocolAwgSettings.qml" line="183"/>
|
||||
<source>S3 - Cookie reply packet junk size</source>
|
||||
<translation>S3 - Cookie reply packet junk size</translation>
|
||||
<translation>S3 - اندازه داده زائد بسته پاسخ کوکی</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../ui/qml/Pages2/PageProtocolAwgSettings.qml" line="195"/>
|
||||
<source>S4 - Transport packet junk size</source>
|
||||
<translation>S4 - Transport packet junk size</translation>
|
||||
<translation>S4 - اندازه داده زائد بسته انتقال</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../ui/qml/Pages2/PageProtocolAwgSettings.qml" line="207"/>
|
||||
<source>H1 - Init packet magic header</source>
|
||||
<translation>H1 - Init packet magic header</translation>
|
||||
<translation>H1 - هدر جادویی بسته آغازین</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../ui/qml/Pages2/PageProtocolAwgSettings.qml" line="219"/>
|
||||
<source>H2 - Response packet magic header</source>
|
||||
<translation>H2 - Response packet magic header</translation>
|
||||
<translation>H2 - هدر جادویی بسته پاسخ</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../ui/qml/Pages2/PageProtocolAwgSettings.qml" line="231"/>
|
||||
<source>H3 - Underload packet magic header</source>
|
||||
<translation>H3 - Underload packet magic header</translation>
|
||||
<translation>H3 - هدر جادویی بسته underload</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../ui/qml/Pages2/PageProtocolAwgSettings.qml" line="243"/>
|
||||
<source>H4 - Transport packet magic header</source>
|
||||
<translation>H4 - Transport packet magic header</translation>
|
||||
<translation>H4 - هدر جادویی بسته انتقال</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../ui/qml/Pages2/PageProtocolAwgSettings.qml" line="253"/>
|
||||
<source>I1 - Special junk 1</source>
|
||||
<translation>I1 - Special junk 1</translation>
|
||||
<translation>I1 - داده زائد ویژه 1</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../ui/qml/Pages2/PageProtocolAwgSettings.qml" line="263"/>
|
||||
<source>I2 - Special junk 2</source>
|
||||
<translation>I2 - Special junk 2</translation>
|
||||
<translation>I2 - داده زائد ویژه 2</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../ui/qml/Pages2/PageProtocolAwgSettings.qml" line="273"/>
|
||||
<source>I3 - Special junk 3</source>
|
||||
<translation>I3 - Special junk 3</translation>
|
||||
<translation>I3 - داده زائد ویژه 3</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../ui/qml/Pages2/PageProtocolAwgSettings.qml" line="283"/>
|
||||
<source>I4 - Special junk 4</source>
|
||||
<translation>I4 - Special junk 4</translation>
|
||||
<translation>I4 - داده زائد ویژه 4</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../ui/qml/Pages2/PageProtocolAwgSettings.qml" line="293"/>
|
||||
<source>I5 - Special junk 5</source>
|
||||
<translation>I5 - Special junk 5</translation>
|
||||
<translation>I5 - داده زائد ویژه 5</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../ui/qml/Pages2/PageProtocolAwgSettings.qml" line="310"/>
|
||||
@@ -803,32 +803,32 @@ Already installed containers were found on the server. All installed containers
|
||||
<message>
|
||||
<location filename="../ui/qml/Pages2/PageProtocolAwgSettings.qml" line="326"/>
|
||||
<source>ContentPaddingAddition - Content padding addition</source>
|
||||
<translation>ContentPaddingAddition - Content padding addition</translation>
|
||||
<translation>ContentPaddingAddition - افزودن لایهگذاری محتوا</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../ui/qml/Pages2/PageProtocolAwgSettings.qml" line="339"/>
|
||||
<source>RekeyAfterTime - Rekey after time</source>
|
||||
<translation>RekeyAfterTime - Rekey after time</translation>
|
||||
<translation>RekeyAfterTime - تولید دوباره کلید پس از زمان</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../ui/qml/Pages2/PageProtocolAwgSettings.qml" line="352"/>
|
||||
<source>RekeyTimeout - Rekey timeout</source>
|
||||
<translation>RekeyTimeout - Rekey timeout</translation>
|
||||
<translation>RekeyTimeout - زمان انتظار تولید دوباره کلید</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../ui/qml/Pages2/PageProtocolAwgSettings.qml" line="365"/>
|
||||
<source>RejectAfterTime - Reject after time</source>
|
||||
<translation>RejectAfterTime - Reject after time</translation>
|
||||
<translation>RejectAfterTime - رد کردن پس از زمان</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../ui/qml/Pages2/PageProtocolAwgSettings.qml" line="378"/>
|
||||
<source>KeepaliveTimeout - Keepalive timeout</source>
|
||||
<translation>KeepaliveTimeout - Keepalive timeout</translation>
|
||||
<translation>KeepaliveTimeout - زمان انتظار keepalive</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../ui/qml/Pages2/PageProtocolAwgSettings.qml" line="391"/>
|
||||
<source>MaxHandshakeAttempts - Max handshake attempts</source>
|
||||
<translation>MaxHandshakeAttempts - Max handshake attempts</translation>
|
||||
<translation>MaxHandshakeAttempts - بیشینه تلاشهای دستدهی</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../ui/qml/Pages2/PageProtocolAwgSettings.qml" line="408"/>
|
||||
|
||||
@@ -590,27 +590,27 @@ Already installed containers were found on the server. All installed containers
|
||||
<message>
|
||||
<location filename="../ui/qml/Pages2/PageProtocolAwgClientSettings.qml" line="132"/>
|
||||
<source>I1 - First special junk packet</source>
|
||||
<translation>I1 - First special junk packet</translation>
|
||||
<translation>I1 - पहला विशेष जंक पैकेट</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../ui/qml/Pages2/PageProtocolAwgClientSettings.qml" line="142"/>
|
||||
<source>I2 - Second special junk packet</source>
|
||||
<translation>I2 - Second special junk packet</translation>
|
||||
<translation>I2 - दूसरा विशेष जंक पैकेट</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../ui/qml/Pages2/PageProtocolAwgClientSettings.qml" line="152"/>
|
||||
<source>I3 - Third special junk packet</source>
|
||||
<translation>I3 - Third special junk packet</translation>
|
||||
<translation>I3 - तीसरा विशेष जंक पैकेट</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../ui/qml/Pages2/PageProtocolAwgClientSettings.qml" line="162"/>
|
||||
<source>I4 - Fourth special junk packet</source>
|
||||
<translation>I4 - Fourth special junk packet</translation>
|
||||
<translation>I4 - चौथा विशेष जंक पैकेट</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../ui/qml/Pages2/PageProtocolAwgClientSettings.qml" line="172"/>
|
||||
<source>I5 - Fifth special junk packet</source>
|
||||
<translation>I5 - Fifth special junk packet</translation>
|
||||
<translation>I5 - पाँचवाँ विशेष जंक पैकेट</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../ui/qml/Pages2/PageProtocolAwgClientSettings.qml" line="189"/>
|
||||
@@ -620,32 +620,32 @@ Already installed containers were found on the server. All installed containers
|
||||
<message>
|
||||
<location filename="../ui/qml/Pages2/PageProtocolAwgClientSettings.qml" line="199"/>
|
||||
<source>ContentPaddingAddition - Content padding addition</source>
|
||||
<translation>ContentPaddingAddition - Content padding addition</translation>
|
||||
<translation>ContentPaddingAddition - कंटेंट पैडिंग जोड़</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../ui/qml/Pages2/PageProtocolAwgClientSettings.qml" line="211"/>
|
||||
<source>RekeyAfterTime - Rekey after time</source>
|
||||
<translation>RekeyAfterTime - Rekey after time</translation>
|
||||
<translation>RekeyAfterTime - समय बाद रीकी</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../ui/qml/Pages2/PageProtocolAwgClientSettings.qml" line="223"/>
|
||||
<source>RekeyTimeout - Rekey timeout</source>
|
||||
<translation>RekeyTimeout - Rekey timeout</translation>
|
||||
<translation>RekeyTimeout - रीकी टाइमआउट</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../ui/qml/Pages2/PageProtocolAwgClientSettings.qml" line="235"/>
|
||||
<source>RejectAfterTime - Reject after time</source>
|
||||
<translation>RejectAfterTime - Reject after time</translation>
|
||||
<translation>RejectAfterTime - समय बाद अस्वीकार</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../ui/qml/Pages2/PageProtocolAwgClientSettings.qml" line="247"/>
|
||||
<source>KeepaliveTimeout - Keepalive timeout</source>
|
||||
<translation>KeepaliveTimeout - Keepalive timeout</translation>
|
||||
<translation>KeepaliveTimeout - कीपअलाइव टाइमआउट</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../ui/qml/Pages2/PageProtocolAwgClientSettings.qml" line="259"/>
|
||||
<source>MaxHandshakeAttempts - Max handshake attempts</source>
|
||||
<translation>MaxHandshakeAttempts - Max handshake attempts</translation>
|
||||
<translation>MaxHandshakeAttempts - अधिकतम हैंडशेक प्रयास</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../ui/qml/Pages2/PageProtocolAwgClientSettings.qml" line="276"/>
|
||||
@@ -718,82 +718,82 @@ Already installed containers were found on the server. All installed containers
|
||||
<message>
|
||||
<location filename="../ui/qml/Pages2/PageProtocolAwgSettings.qml" line="131"/>
|
||||
<source>Jc - Junk packet count</source>
|
||||
<translation>Jc - Junk packet count</translation>
|
||||
<translation>Jc - जंक पैकेट संख्या</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../ui/qml/Pages2/PageProtocolAwgSettings.qml" line="141"/>
|
||||
<source>Jmin - Junk packet minimum size</source>
|
||||
<translation>Jmin - Junk packet minimum size</translation>
|
||||
<translation>Jmin - जंक पैकेट न्यूनतम आकार</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../ui/qml/Pages2/PageProtocolAwgSettings.qml" line="151"/>
|
||||
<source>Jmax - Junk packet maximum size</source>
|
||||
<translation>Jmax - Junk packet maximum size</translation>
|
||||
<translation>Jmax - जंक पैकेट अधिकतम आकार</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../ui/qml/Pages2/PageProtocolAwgSettings.qml" line="161"/>
|
||||
<source>S1 - Init packet junk size</source>
|
||||
<translation>S1 - Init packet junk size</translation>
|
||||
<translation>S1 - init पैकेट जंक आकार</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../ui/qml/Pages2/PageProtocolAwgSettings.qml" line="171"/>
|
||||
<source>S2 - Response packet junk size</source>
|
||||
<translation>S2 - Response packet junk size</translation>
|
||||
<translation>S2 - प्रतिक्रिया पैकेट जंक आकार</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../ui/qml/Pages2/PageProtocolAwgSettings.qml" line="183"/>
|
||||
<source>S3 - Cookie reply packet junk size</source>
|
||||
<translation>S3 - Cookie reply packet junk size</translation>
|
||||
<translation>S3 - कुकी उत्तर पैकेट जंक आकार</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../ui/qml/Pages2/PageProtocolAwgSettings.qml" line="195"/>
|
||||
<source>S4 - Transport packet junk size</source>
|
||||
<translation>S4 - Transport packet junk size</translation>
|
||||
<translation>S4 - ट्रांसपोर्ट पैकेट जंक आकार</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../ui/qml/Pages2/PageProtocolAwgSettings.qml" line="207"/>
|
||||
<source>H1 - Init packet magic header</source>
|
||||
<translation>H1 - Init packet magic header</translation>
|
||||
<translation>H1 - init पैकेट मैजिक हेडर</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../ui/qml/Pages2/PageProtocolAwgSettings.qml" line="219"/>
|
||||
<source>H2 - Response packet magic header</source>
|
||||
<translation>H2 - Response packet magic header</translation>
|
||||
<translation>H2 - प्रतिक्रिया पैकेट मैजिक हेडर</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../ui/qml/Pages2/PageProtocolAwgSettings.qml" line="231"/>
|
||||
<source>H3 - Underload packet magic header</source>
|
||||
<translation>H3 - Underload packet magic header</translation>
|
||||
<translation>H3 - underload पैकेट मैजिक हेडर</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../ui/qml/Pages2/PageProtocolAwgSettings.qml" line="243"/>
|
||||
<source>H4 - Transport packet magic header</source>
|
||||
<translation>H4 - Transport packet magic header</translation>
|
||||
<translation>H4 - ट्रांसपोर्ट पैकेट मैजिक हेडर</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../ui/qml/Pages2/PageProtocolAwgSettings.qml" line="253"/>
|
||||
<source>I1 - Special junk 1</source>
|
||||
<translation>I1 - Special junk 1</translation>
|
||||
<translation>I1 - विशेष जंक 1</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../ui/qml/Pages2/PageProtocolAwgSettings.qml" line="263"/>
|
||||
<source>I2 - Special junk 2</source>
|
||||
<translation>I2 - Special junk 2</translation>
|
||||
<translation>I2 - विशेष जंक 2</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../ui/qml/Pages2/PageProtocolAwgSettings.qml" line="273"/>
|
||||
<source>I3 - Special junk 3</source>
|
||||
<translation>I3 - Special junk 3</translation>
|
||||
<translation>I3 - विशेष जंक 3</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../ui/qml/Pages2/PageProtocolAwgSettings.qml" line="283"/>
|
||||
<source>I4 - Special junk 4</source>
|
||||
<translation>I4 - Special junk 4</translation>
|
||||
<translation>I4 - विशेष जंक 4</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../ui/qml/Pages2/PageProtocolAwgSettings.qml" line="293"/>
|
||||
<source>I5 - Special junk 5</source>
|
||||
<translation>I5 - Special junk 5</translation>
|
||||
<translation>I5 - विशेष जंक 5</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../ui/qml/Pages2/PageProtocolAwgSettings.qml" line="310"/>
|
||||
@@ -803,32 +803,32 @@ Already installed containers were found on the server. All installed containers
|
||||
<message>
|
||||
<location filename="../ui/qml/Pages2/PageProtocolAwgSettings.qml" line="326"/>
|
||||
<source>ContentPaddingAddition - Content padding addition</source>
|
||||
<translation>ContentPaddingAddition - Content padding addition</translation>
|
||||
<translation>ContentPaddingAddition - कंटेंट पैडिंग जोड़</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../ui/qml/Pages2/PageProtocolAwgSettings.qml" line="339"/>
|
||||
<source>RekeyAfterTime - Rekey after time</source>
|
||||
<translation>RekeyAfterTime - Rekey after time</translation>
|
||||
<translation>RekeyAfterTime - समय बाद रीकी</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../ui/qml/Pages2/PageProtocolAwgSettings.qml" line="352"/>
|
||||
<source>RekeyTimeout - Rekey timeout</source>
|
||||
<translation>RekeyTimeout - Rekey timeout</translation>
|
||||
<translation>RekeyTimeout - रीकी टाइमआउट</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../ui/qml/Pages2/PageProtocolAwgSettings.qml" line="365"/>
|
||||
<source>RejectAfterTime - Reject after time</source>
|
||||
<translation>RejectAfterTime - Reject after time</translation>
|
||||
<translation>RejectAfterTime - समय बाद अस्वीकार</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../ui/qml/Pages2/PageProtocolAwgSettings.qml" line="378"/>
|
||||
<source>KeepaliveTimeout - Keepalive timeout</source>
|
||||
<translation>KeepaliveTimeout - Keepalive timeout</translation>
|
||||
<translation>KeepaliveTimeout - कीपअलाइव टाइमआउट</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../ui/qml/Pages2/PageProtocolAwgSettings.qml" line="391"/>
|
||||
<source>MaxHandshakeAttempts - Max handshake attempts</source>
|
||||
<translation>MaxHandshakeAttempts - Max handshake attempts</translation>
|
||||
<translation>MaxHandshakeAttempts - अधिकतम हैंडशेक प्रयास</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../ui/qml/Pages2/PageProtocolAwgSettings.qml" line="408"/>
|
||||
|
||||
@@ -590,27 +590,27 @@ Already installed containers were found on the server. All installed containers
|
||||
<message>
|
||||
<location filename="../ui/qml/Pages2/PageProtocolAwgClientSettings.qml" line="132"/>
|
||||
<source>I1 - First special junk packet</source>
|
||||
<translation>I1 - First special junk packet</translation>
|
||||
<translation>I1 - 첫 번째 특수 정크 패킷</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../ui/qml/Pages2/PageProtocolAwgClientSettings.qml" line="142"/>
|
||||
<source>I2 - Second special junk packet</source>
|
||||
<translation>I2 - Second special junk packet</translation>
|
||||
<translation>I2 - 두 번째 특수 정크 패킷</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../ui/qml/Pages2/PageProtocolAwgClientSettings.qml" line="152"/>
|
||||
<source>I3 - Third special junk packet</source>
|
||||
<translation>I3 - Third special junk packet</translation>
|
||||
<translation>I3 - 세 번째 특수 정크 패킷</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../ui/qml/Pages2/PageProtocolAwgClientSettings.qml" line="162"/>
|
||||
<source>I4 - Fourth special junk packet</source>
|
||||
<translation>I4 - Fourth special junk packet</translation>
|
||||
<translation>I4 - 네 번째 특수 정크 패킷</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../ui/qml/Pages2/PageProtocolAwgClientSettings.qml" line="172"/>
|
||||
<source>I5 - Fifth special junk packet</source>
|
||||
<translation>I5 - Fifth special junk packet</translation>
|
||||
<translation>I5 - 다섯 번째 특수 정크 패킷</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../ui/qml/Pages2/PageProtocolAwgClientSettings.qml" line="189"/>
|
||||
@@ -620,32 +620,32 @@ Already installed containers were found on the server. All installed containers
|
||||
<message>
|
||||
<location filename="../ui/qml/Pages2/PageProtocolAwgClientSettings.qml" line="199"/>
|
||||
<source>ContentPaddingAddition - Content padding addition</source>
|
||||
<translation>ContentPaddingAddition - Content padding addition</translation>
|
||||
<translation>ContentPaddingAddition - 콘텐츠 패딩 추가</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../ui/qml/Pages2/PageProtocolAwgClientSettings.qml" line="211"/>
|
||||
<source>RekeyAfterTime - Rekey after time</source>
|
||||
<translation>RekeyAfterTime - Rekey after time</translation>
|
||||
<translation>RekeyAfterTime - 키 갱신 시간</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../ui/qml/Pages2/PageProtocolAwgClientSettings.qml" line="223"/>
|
||||
<source>RekeyTimeout - Rekey timeout</source>
|
||||
<translation>RekeyTimeout - Rekey timeout</translation>
|
||||
<translation>RekeyTimeout - 키 갱신 시간 제한</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../ui/qml/Pages2/PageProtocolAwgClientSettings.qml" line="235"/>
|
||||
<source>RejectAfterTime - Reject after time</source>
|
||||
<translation>RejectAfterTime - Reject after time</translation>
|
||||
<translation>RejectAfterTime - 거부 시간</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../ui/qml/Pages2/PageProtocolAwgClientSettings.qml" line="247"/>
|
||||
<source>KeepaliveTimeout - Keepalive timeout</source>
|
||||
<translation>KeepaliveTimeout - Keepalive timeout</translation>
|
||||
<translation>KeepaliveTimeout - 연결 유지 시간 제한</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../ui/qml/Pages2/PageProtocolAwgClientSettings.qml" line="259"/>
|
||||
<source>MaxHandshakeAttempts - Max handshake attempts</source>
|
||||
<translation>MaxHandshakeAttempts - Max handshake attempts</translation>
|
||||
<translation>MaxHandshakeAttempts - 최대 핸드셰이크 시도 횟수</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../ui/qml/Pages2/PageProtocolAwgClientSettings.qml" line="276"/>
|
||||
@@ -718,82 +718,82 @@ Already installed containers were found on the server. All installed containers
|
||||
<message>
|
||||
<location filename="../ui/qml/Pages2/PageProtocolAwgSettings.qml" line="131"/>
|
||||
<source>Jc - Junk packet count</source>
|
||||
<translation>Jc - Junk packet count</translation>
|
||||
<translation>Jc - 정크 패킷 수</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../ui/qml/Pages2/PageProtocolAwgSettings.qml" line="141"/>
|
||||
<source>Jmin - Junk packet minimum size</source>
|
||||
<translation>Jmin - Junk packet minimum size</translation>
|
||||
<translation>Jmin - 정크 패킷 최소 크기</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../ui/qml/Pages2/PageProtocolAwgSettings.qml" line="151"/>
|
||||
<source>Jmax - Junk packet maximum size</source>
|
||||
<translation>Jmax - Junk packet maximum size</translation>
|
||||
<translation>Jmax - 정크 패킷 최대 크기</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../ui/qml/Pages2/PageProtocolAwgSettings.qml" line="161"/>
|
||||
<source>S1 - Init packet junk size</source>
|
||||
<translation>S1 - Init packet junk size</translation>
|
||||
<translation>S1 - 초기 패킷 정크 크기</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../ui/qml/Pages2/PageProtocolAwgSettings.qml" line="171"/>
|
||||
<source>S2 - Response packet junk size</source>
|
||||
<translation>S2 - Response packet junk size</translation>
|
||||
<translation>S2 - 응답 패킷 정크 크기</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../ui/qml/Pages2/PageProtocolAwgSettings.qml" line="183"/>
|
||||
<source>S3 - Cookie reply packet junk size</source>
|
||||
<translation>S3 - Cookie reply packet junk size</translation>
|
||||
<translation>S3 - 쿠키 응답 패킷 정크 크기</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../ui/qml/Pages2/PageProtocolAwgSettings.qml" line="195"/>
|
||||
<source>S4 - Transport packet junk size</source>
|
||||
<translation>S4 - Transport packet junk size</translation>
|
||||
<translation>S4 - 전송 패킷 정크 크기</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../ui/qml/Pages2/PageProtocolAwgSettings.qml" line="207"/>
|
||||
<source>H1 - Init packet magic header</source>
|
||||
<translation>H1 - Init packet magic header</translation>
|
||||
<translation>H1 - 초기 패킷 매직 헤더</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../ui/qml/Pages2/PageProtocolAwgSettings.qml" line="219"/>
|
||||
<source>H2 - Response packet magic header</source>
|
||||
<translation>H2 - Response packet magic header</translation>
|
||||
<translation>H2 - 응답 패킷 매직 헤더</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../ui/qml/Pages2/PageProtocolAwgSettings.qml" line="231"/>
|
||||
<source>H3 - Underload packet magic header</source>
|
||||
<translation>H3 - Underload packet magic header</translation>
|
||||
<translation>H3 - 언더로드 패킷 매직 헤더</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../ui/qml/Pages2/PageProtocolAwgSettings.qml" line="243"/>
|
||||
<source>H4 - Transport packet magic header</source>
|
||||
<translation>H4 - Transport packet magic header</translation>
|
||||
<translation>H4 - 전송 패킷 매직 헤더</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../ui/qml/Pages2/PageProtocolAwgSettings.qml" line="253"/>
|
||||
<source>I1 - Special junk 1</source>
|
||||
<translation>I1 - Special junk 1</translation>
|
||||
<translation>I1 - 특수 정크 1</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../ui/qml/Pages2/PageProtocolAwgSettings.qml" line="263"/>
|
||||
<source>I2 - Special junk 2</source>
|
||||
<translation>I2 - Special junk 2</translation>
|
||||
<translation>I2 - 특수 정크 2</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../ui/qml/Pages2/PageProtocolAwgSettings.qml" line="273"/>
|
||||
<source>I3 - Special junk 3</source>
|
||||
<translation>I3 - Special junk 3</translation>
|
||||
<translation>I3 - 특수 정크 3</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../ui/qml/Pages2/PageProtocolAwgSettings.qml" line="283"/>
|
||||
<source>I4 - Special junk 4</source>
|
||||
<translation>I4 - Special junk 4</translation>
|
||||
<translation>I4 - 특수 정크 4</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../ui/qml/Pages2/PageProtocolAwgSettings.qml" line="293"/>
|
||||
<source>I5 - Special junk 5</source>
|
||||
<translation>I5 - Special junk 5</translation>
|
||||
<translation>I5 - 특수 정크 5</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../ui/qml/Pages2/PageProtocolAwgSettings.qml" line="310"/>
|
||||
@@ -803,32 +803,32 @@ Already installed containers were found on the server. All installed containers
|
||||
<message>
|
||||
<location filename="../ui/qml/Pages2/PageProtocolAwgSettings.qml" line="326"/>
|
||||
<source>ContentPaddingAddition - Content padding addition</source>
|
||||
<translation>ContentPaddingAddition - Content padding addition</translation>
|
||||
<translation>ContentPaddingAddition - 콘텐츠 패딩 추가</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../ui/qml/Pages2/PageProtocolAwgSettings.qml" line="339"/>
|
||||
<source>RekeyAfterTime - Rekey after time</source>
|
||||
<translation>RekeyAfterTime - Rekey after time</translation>
|
||||
<translation>RekeyAfterTime - 키 갱신 시간</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../ui/qml/Pages2/PageProtocolAwgSettings.qml" line="352"/>
|
||||
<source>RekeyTimeout - Rekey timeout</source>
|
||||
<translation>RekeyTimeout - Rekey timeout</translation>
|
||||
<translation>RekeyTimeout - 키 갱신 시간 제한</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../ui/qml/Pages2/PageProtocolAwgSettings.qml" line="365"/>
|
||||
<source>RejectAfterTime - Reject after time</source>
|
||||
<translation>RejectAfterTime - Reject after time</translation>
|
||||
<translation>RejectAfterTime - 거부 시간</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../ui/qml/Pages2/PageProtocolAwgSettings.qml" line="378"/>
|
||||
<source>KeepaliveTimeout - Keepalive timeout</source>
|
||||
<translation>KeepaliveTimeout - Keepalive timeout</translation>
|
||||
<translation>KeepaliveTimeout - 연결 유지 시간 제한</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../ui/qml/Pages2/PageProtocolAwgSettings.qml" line="391"/>
|
||||
<source>MaxHandshakeAttempts - Max handshake attempts</source>
|
||||
<translation>MaxHandshakeAttempts - Max handshake attempts</translation>
|
||||
<translation>MaxHandshakeAttempts - 최대 핸드셰이크 시도 횟수</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../ui/qml/Pages2/PageProtocolAwgSettings.qml" line="408"/>
|
||||
|
||||
@@ -590,27 +590,27 @@ Already installed containers were found on the server. All installed containers
|
||||
<message>
|
||||
<location filename="../ui/qml/Pages2/PageProtocolAwgClientSettings.qml" line="132"/>
|
||||
<source>I1 - First special junk packet</source>
|
||||
<translation>I1 - First special junk packet</translation>
|
||||
<translation>I1 - ပထမ အထူး junk packet</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../ui/qml/Pages2/PageProtocolAwgClientSettings.qml" line="142"/>
|
||||
<source>I2 - Second special junk packet</source>
|
||||
<translation>I2 - Second special junk packet</translation>
|
||||
<translation>I2 - ဒုတိယ အထူး junk packet</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../ui/qml/Pages2/PageProtocolAwgClientSettings.qml" line="152"/>
|
||||
<source>I3 - Third special junk packet</source>
|
||||
<translation>I3 - Third special junk packet</translation>
|
||||
<translation>I3 - တတိယ အထူး junk packet</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../ui/qml/Pages2/PageProtocolAwgClientSettings.qml" line="162"/>
|
||||
<source>I4 - Fourth special junk packet</source>
|
||||
<translation>I4 - Fourth special junk packet</translation>
|
||||
<translation>I4 - စတုတ္ထ အထူး junk packet</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../ui/qml/Pages2/PageProtocolAwgClientSettings.qml" line="172"/>
|
||||
<source>I5 - Fifth special junk packet</source>
|
||||
<translation>I5 - Fifth special junk packet</translation>
|
||||
<translation>I5 - ပဉ္စမ အထူး junk packet</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../ui/qml/Pages2/PageProtocolAwgClientSettings.qml" line="189"/>
|
||||
@@ -620,32 +620,32 @@ Already installed containers were found on the server. All installed containers
|
||||
<message>
|
||||
<location filename="../ui/qml/Pages2/PageProtocolAwgClientSettings.qml" line="199"/>
|
||||
<source>ContentPaddingAddition - Content padding addition</source>
|
||||
<translation>ContentPaddingAddition - Content padding addition</translation>
|
||||
<translation>ContentPaddingAddition - အကြောင်းအရာ padding ထပ်ဆောင်းမှု</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../ui/qml/Pages2/PageProtocolAwgClientSettings.qml" line="211"/>
|
||||
<source>RekeyAfterTime - Rekey after time</source>
|
||||
<translation>RekeyAfterTime - Rekey after time</translation>
|
||||
<translation>RekeyAfterTime - အချိန်ပြီးနောက် သော့ပြန်ဖန်တီးမှု</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../ui/qml/Pages2/PageProtocolAwgClientSettings.qml" line="223"/>
|
||||
<source>RekeyTimeout - Rekey timeout</source>
|
||||
<translation>RekeyTimeout - Rekey timeout</translation>
|
||||
<translation>RekeyTimeout - သော့ပြန်ဖန်တီးမှု အချိန်ကုန်ဆုံးချိန်</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../ui/qml/Pages2/PageProtocolAwgClientSettings.qml" line="235"/>
|
||||
<source>RejectAfterTime - Reject after time</source>
|
||||
<translation>RejectAfterTime - Reject after time</translation>
|
||||
<translation>RejectAfterTime - အချိန်ပြီးနောက် ငြင်းဆိုမှု</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../ui/qml/Pages2/PageProtocolAwgClientSettings.qml" line="247"/>
|
||||
<source>KeepaliveTimeout - Keepalive timeout</source>
|
||||
<translation>KeepaliveTimeout - Keepalive timeout</translation>
|
||||
<translation>KeepaliveTimeout - keepalive အချိန်ကုန်ဆုံးချိန်</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../ui/qml/Pages2/PageProtocolAwgClientSettings.qml" line="259"/>
|
||||
<source>MaxHandshakeAttempts - Max handshake attempts</source>
|
||||
<translation>MaxHandshakeAttempts - Max handshake attempts</translation>
|
||||
<translation>MaxHandshakeAttempts - handshake ကြိုးပမ်းမှု အမြင့်ဆုံး</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../ui/qml/Pages2/PageProtocolAwgClientSettings.qml" line="276"/>
|
||||
@@ -718,82 +718,82 @@ Already installed containers were found on the server. All installed containers
|
||||
<message>
|
||||
<location filename="../ui/qml/Pages2/PageProtocolAwgSettings.qml" line="131"/>
|
||||
<source>Jc - Junk packet count</source>
|
||||
<translation>Jc - Junk packet count</translation>
|
||||
<translation>Jc - Junk packet အရေအတွက်</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../ui/qml/Pages2/PageProtocolAwgSettings.qml" line="141"/>
|
||||
<source>Jmin - Junk packet minimum size</source>
|
||||
<translation>Jmin - Junk packet minimum size</translation>
|
||||
<translation>Jmin - Junk packet အသေးငယ်ဆုံးလက်ခံနိုင်မှုအရွယ်အစား</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../ui/qml/Pages2/PageProtocolAwgSettings.qml" line="151"/>
|
||||
<source>Jmax - Junk packet maximum size</source>
|
||||
<translation>Jmax - Junk packet maximum size</translation>
|
||||
<translation>Jmax - Junk packet အကြီးဆုံးလက်ခံနိုင်မှုအရွယ်အစား</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../ui/qml/Pages2/PageProtocolAwgSettings.qml" line="161"/>
|
||||
<source>S1 - Init packet junk size</source>
|
||||
<translation>S1 - Init packet junk size</translation>
|
||||
<translation>S1 - Init packet junk အရွယ်အစား</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../ui/qml/Pages2/PageProtocolAwgSettings.qml" line="171"/>
|
||||
<source>S2 - Response packet junk size</source>
|
||||
<translation>S2 - Response packet junk size</translation>
|
||||
<translation>S2 - Response packet junk အရွယ်အစား</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../ui/qml/Pages2/PageProtocolAwgSettings.qml" line="183"/>
|
||||
<source>S3 - Cookie reply packet junk size</source>
|
||||
<translation>S3 - Cookie reply packet junk size</translation>
|
||||
<translation>S3 - cookie reply packet junk အရွယ်အစား</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../ui/qml/Pages2/PageProtocolAwgSettings.qml" line="195"/>
|
||||
<source>S4 - Transport packet junk size</source>
|
||||
<translation>S4 - Transport packet junk size</translation>
|
||||
<translation>S4 - transport packet junk အရွယ်အစား</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../ui/qml/Pages2/PageProtocolAwgSettings.qml" line="207"/>
|
||||
<source>H1 - Init packet magic header</source>
|
||||
<translation>H1 - Init packet magic header</translation>
|
||||
<translation>H1 - init packet magic header</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../ui/qml/Pages2/PageProtocolAwgSettings.qml" line="219"/>
|
||||
<source>H2 - Response packet magic header</source>
|
||||
<translation>H2 - Response packet magic header</translation>
|
||||
<translation>H2 - တုံ့ပြန်ချက် packet magic header</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../ui/qml/Pages2/PageProtocolAwgSettings.qml" line="231"/>
|
||||
<source>H3 - Underload packet magic header</source>
|
||||
<translation>H3 - Underload packet magic header</translation>
|
||||
<translation>H3 - underload packet magic header</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../ui/qml/Pages2/PageProtocolAwgSettings.qml" line="243"/>
|
||||
<source>H4 - Transport packet magic header</source>
|
||||
<translation>H4 - Transport packet magic header</translation>
|
||||
<translation>H4 - transport packet magic header</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../ui/qml/Pages2/PageProtocolAwgSettings.qml" line="253"/>
|
||||
<source>I1 - Special junk 1</source>
|
||||
<translation>I1 - Special junk 1</translation>
|
||||
<translation>I1 - အထူး junk 1</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../ui/qml/Pages2/PageProtocolAwgSettings.qml" line="263"/>
|
||||
<source>I2 - Special junk 2</source>
|
||||
<translation>I2 - Special junk 2</translation>
|
||||
<translation>I2 - အထူး junk 2</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../ui/qml/Pages2/PageProtocolAwgSettings.qml" line="273"/>
|
||||
<source>I3 - Special junk 3</source>
|
||||
<translation>I3 - Special junk 3</translation>
|
||||
<translation>I3 - အထူး junk 3</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../ui/qml/Pages2/PageProtocolAwgSettings.qml" line="283"/>
|
||||
<source>I4 - Special junk 4</source>
|
||||
<translation>I4 - Special junk 4</translation>
|
||||
<translation>I4 - အထူး junk 4</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../ui/qml/Pages2/PageProtocolAwgSettings.qml" line="293"/>
|
||||
<source>I5 - Special junk 5</source>
|
||||
<translation>I5 - Special junk 5</translation>
|
||||
<translation>I5 - အထူး junk 5</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../ui/qml/Pages2/PageProtocolAwgSettings.qml" line="310"/>
|
||||
@@ -803,32 +803,32 @@ Already installed containers were found on the server. All installed containers
|
||||
<message>
|
||||
<location filename="../ui/qml/Pages2/PageProtocolAwgSettings.qml" line="326"/>
|
||||
<source>ContentPaddingAddition - Content padding addition</source>
|
||||
<translation>ContentPaddingAddition - Content padding addition</translation>
|
||||
<translation>ContentPaddingAddition - အကြောင်းအရာ padding ထပ်ဆောင်းမှု</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../ui/qml/Pages2/PageProtocolAwgSettings.qml" line="339"/>
|
||||
<source>RekeyAfterTime - Rekey after time</source>
|
||||
<translation>RekeyAfterTime - Rekey after time</translation>
|
||||
<translation>RekeyAfterTime - အချိန်ပြီးနောက် သော့ပြန်ဖန်တီးမှု</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../ui/qml/Pages2/PageProtocolAwgSettings.qml" line="352"/>
|
||||
<source>RekeyTimeout - Rekey timeout</source>
|
||||
<translation>RekeyTimeout - Rekey timeout</translation>
|
||||
<translation>RekeyTimeout - သော့ပြန်ဖန်တီးမှု အချိန်ကုန်ဆုံးချိန်</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../ui/qml/Pages2/PageProtocolAwgSettings.qml" line="365"/>
|
||||
<source>RejectAfterTime - Reject after time</source>
|
||||
<translation>RejectAfterTime - Reject after time</translation>
|
||||
<translation>RejectAfterTime - အချိန်ပြီးနောက် ငြင်းဆိုမှု</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../ui/qml/Pages2/PageProtocolAwgSettings.qml" line="378"/>
|
||||
<source>KeepaliveTimeout - Keepalive timeout</source>
|
||||
<translation>KeepaliveTimeout - Keepalive timeout</translation>
|
||||
<translation>KeepaliveTimeout - keepalive အချိန်ကုန်ဆုံးချိန်</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../ui/qml/Pages2/PageProtocolAwgSettings.qml" line="391"/>
|
||||
<source>MaxHandshakeAttempts - Max handshake attempts</source>
|
||||
<translation>MaxHandshakeAttempts - Max handshake attempts</translation>
|
||||
<translation>MaxHandshakeAttempts - handshake ကြိုးပမ်းမှု အမြင့်ဆုံး</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../ui/qml/Pages2/PageProtocolAwgSettings.qml" line="408"/>
|
||||
|
||||
@@ -591,27 +591,27 @@ Already installed containers were found on the server. All installed containers
|
||||
<message>
|
||||
<location filename="../ui/qml/Pages2/PageProtocolAwgClientSettings.qml" line="132"/>
|
||||
<source>I1 - First special junk packet</source>
|
||||
<translation>I1 - First special junk packet</translation>
|
||||
<translation>I1 - первый специальный мусорный пакет</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../ui/qml/Pages2/PageProtocolAwgClientSettings.qml" line="142"/>
|
||||
<source>I2 - Second special junk packet</source>
|
||||
<translation>I2 - Second special junk packet</translation>
|
||||
<translation>I2 - второй специальный мусорный пакет</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../ui/qml/Pages2/PageProtocolAwgClientSettings.qml" line="152"/>
|
||||
<source>I3 - Third special junk packet</source>
|
||||
<translation>I3 - Third special junk packet</translation>
|
||||
<translation>I3 - третий специальный мусорный пакет</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../ui/qml/Pages2/PageProtocolAwgClientSettings.qml" line="162"/>
|
||||
<source>I4 - Fourth special junk packet</source>
|
||||
<translation>I4 - Fourth special junk packet</translation>
|
||||
<translation>I4 - четвёртый специальный мусорный пакет</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../ui/qml/Pages2/PageProtocolAwgClientSettings.qml" line="172"/>
|
||||
<source>I5 - Fifth special junk packet</source>
|
||||
<translation>I5 - Fifth special junk packet</translation>
|
||||
<translation>I5 - пятый специальный мусорный пакет</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../ui/qml/Pages2/PageProtocolAwgClientSettings.qml" line="189"/>
|
||||
@@ -621,32 +621,32 @@ Already installed containers were found on the server. All installed containers
|
||||
<message>
|
||||
<location filename="../ui/qml/Pages2/PageProtocolAwgClientSettings.qml" line="199"/>
|
||||
<source>ContentPaddingAddition - Content padding addition</source>
|
||||
<translation>ContentPaddingAddition - Content padding addition</translation>
|
||||
<translation>ContentPaddingAddition - добавление заполнения содержимого</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../ui/qml/Pages2/PageProtocolAwgClientSettings.qml" line="211"/>
|
||||
<source>RekeyAfterTime - Rekey after time</source>
|
||||
<translation>RekeyAfterTime - Rekey after time</translation>
|
||||
<translation>RekeyAfterTime - смена ключа по истечении времени</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../ui/qml/Pages2/PageProtocolAwgClientSettings.qml" line="223"/>
|
||||
<source>RekeyTimeout - Rekey timeout</source>
|
||||
<translation>RekeyTimeout - Rekey timeout</translation>
|
||||
<translation>RekeyTimeout - тайм-аут смены ключа</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../ui/qml/Pages2/PageProtocolAwgClientSettings.qml" line="235"/>
|
||||
<source>RejectAfterTime - Reject after time</source>
|
||||
<translation>RejectAfterTime - Reject after time</translation>
|
||||
<translation>RejectAfterTime - отклонение по истечении времени</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../ui/qml/Pages2/PageProtocolAwgClientSettings.qml" line="247"/>
|
||||
<source>KeepaliveTimeout - Keepalive timeout</source>
|
||||
<translation>KeepaliveTimeout - Keepalive timeout</translation>
|
||||
<translation>KeepaliveTimeout - тайм-аут keepalive</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../ui/qml/Pages2/PageProtocolAwgClientSettings.qml" line="259"/>
|
||||
<source>MaxHandshakeAttempts - Max handshake attempts</source>
|
||||
<translation>MaxHandshakeAttempts - Max handshake attempts</translation>
|
||||
<translation>MaxHandshakeAttempts - максимум попыток рукопожатия</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../ui/qml/Pages2/PageProtocolAwgClientSettings.qml" line="276"/>
|
||||
@@ -719,82 +719,82 @@ Already installed containers were found on the server. All installed containers
|
||||
<message>
|
||||
<location filename="../ui/qml/Pages2/PageProtocolAwgSettings.qml" line="131"/>
|
||||
<source>Jc - Junk packet count</source>
|
||||
<translation>Jc - Junk packet count</translation>
|
||||
<translation>Jc - количество мусорных пакетов</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../ui/qml/Pages2/PageProtocolAwgSettings.qml" line="141"/>
|
||||
<source>Jmin - Junk packet minimum size</source>
|
||||
<translation>Jmin - Junk packet minimum size</translation>
|
||||
<translation>Jmin - минимальный размер мусорного пакета</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../ui/qml/Pages2/PageProtocolAwgSettings.qml" line="151"/>
|
||||
<source>Jmax - Junk packet maximum size</source>
|
||||
<translation>Jmax - Junk packet maximum size</translation>
|
||||
<translation>Jmax - максимальный размер мусорного пакета</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../ui/qml/Pages2/PageProtocolAwgSettings.qml" line="161"/>
|
||||
<source>S1 - Init packet junk size</source>
|
||||
<translation>S1 - Init packet junk size</translation>
|
||||
<translation>S1 - размер мусора в пакете инициализации</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../ui/qml/Pages2/PageProtocolAwgSettings.qml" line="171"/>
|
||||
<source>S2 - Response packet junk size</source>
|
||||
<translation>S2 - Response packet junk size</translation>
|
||||
<translation>S2 - размер мусора в пакете ответа</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../ui/qml/Pages2/PageProtocolAwgSettings.qml" line="183"/>
|
||||
<source>S3 - Cookie reply packet junk size</source>
|
||||
<translation>S3 - Cookie reply packet junk size</translation>
|
||||
<translation>S3 - размер мусора в пакете cookie reply</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../ui/qml/Pages2/PageProtocolAwgSettings.qml" line="195"/>
|
||||
<source>S4 - Transport packet junk size</source>
|
||||
<translation>S4 - Transport packet junk size</translation>
|
||||
<translation>S4 - размер мусора в транспортном пакете</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../ui/qml/Pages2/PageProtocolAwgSettings.qml" line="207"/>
|
||||
<source>H1 - Init packet magic header</source>
|
||||
<translation>H1 - Init packet magic header</translation>
|
||||
<translation>H1 - магический заголовок пакета инициализации</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../ui/qml/Pages2/PageProtocolAwgSettings.qml" line="219"/>
|
||||
<source>H2 - Response packet magic header</source>
|
||||
<translation>H2 - Response packet magic header</translation>
|
||||
<translation>H2 - магический заголовок пакета ответа</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../ui/qml/Pages2/PageProtocolAwgSettings.qml" line="231"/>
|
||||
<source>H3 - Underload packet magic header</source>
|
||||
<translation>H3 - Underload packet magic header</translation>
|
||||
<translation>H3 - магический заголовок пакета underload</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../ui/qml/Pages2/PageProtocolAwgSettings.qml" line="243"/>
|
||||
<source>H4 - Transport packet magic header</source>
|
||||
<translation>H4 - Transport packet magic header</translation>
|
||||
<translation>H4 - магический заголовок транспортного пакета</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../ui/qml/Pages2/PageProtocolAwgSettings.qml" line="253"/>
|
||||
<source>I1 - Special junk 1</source>
|
||||
<translation>I1 - Special junk 1</translation>
|
||||
<translation>I1 - специальный мусорный пакет 1</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../ui/qml/Pages2/PageProtocolAwgSettings.qml" line="263"/>
|
||||
<source>I2 - Special junk 2</source>
|
||||
<translation>I2 - Special junk 2</translation>
|
||||
<translation>I2 - специальный мусорный пакет 2</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../ui/qml/Pages2/PageProtocolAwgSettings.qml" line="273"/>
|
||||
<source>I3 - Special junk 3</source>
|
||||
<translation>I3 - Special junk 3</translation>
|
||||
<translation>I3 - специальный мусорный пакет 3</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../ui/qml/Pages2/PageProtocolAwgSettings.qml" line="283"/>
|
||||
<source>I4 - Special junk 4</source>
|
||||
<translation>I4 - Special junk 4</translation>
|
||||
<translation>I4 - специальный мусорный пакет 4</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../ui/qml/Pages2/PageProtocolAwgSettings.qml" line="293"/>
|
||||
<source>I5 - Special junk 5</source>
|
||||
<translation>I5 - Special junk 5</translation>
|
||||
<translation>I5 - специальный мусорный пакет 5</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../ui/qml/Pages2/PageProtocolAwgSettings.qml" line="310"/>
|
||||
@@ -804,32 +804,32 @@ Already installed containers were found on the server. All installed containers
|
||||
<message>
|
||||
<location filename="../ui/qml/Pages2/PageProtocolAwgSettings.qml" line="326"/>
|
||||
<source>ContentPaddingAddition - Content padding addition</source>
|
||||
<translation>ContentPaddingAddition - Content padding addition</translation>
|
||||
<translation>ContentPaddingAddition - добавление заполнения содержимого</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../ui/qml/Pages2/PageProtocolAwgSettings.qml" line="339"/>
|
||||
<source>RekeyAfterTime - Rekey after time</source>
|
||||
<translation>RekeyAfterTime - Rekey after time</translation>
|
||||
<translation>RekeyAfterTime - смена ключа по истечении времени</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../ui/qml/Pages2/PageProtocolAwgSettings.qml" line="352"/>
|
||||
<source>RekeyTimeout - Rekey timeout</source>
|
||||
<translation>RekeyTimeout - Rekey timeout</translation>
|
||||
<translation>RekeyTimeout - тайм-аут смены ключа</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../ui/qml/Pages2/PageProtocolAwgSettings.qml" line="365"/>
|
||||
<source>RejectAfterTime - Reject after time</source>
|
||||
<translation>RejectAfterTime - Reject after time</translation>
|
||||
<translation>RejectAfterTime - отклонение по истечении времени</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../ui/qml/Pages2/PageProtocolAwgSettings.qml" line="378"/>
|
||||
<source>KeepaliveTimeout - Keepalive timeout</source>
|
||||
<translation>KeepaliveTimeout - Keepalive timeout</translation>
|
||||
<translation>KeepaliveTimeout - тайм-аут keepalive</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../ui/qml/Pages2/PageProtocolAwgSettings.qml" line="391"/>
|
||||
<source>MaxHandshakeAttempts - Max handshake attempts</source>
|
||||
<translation>MaxHandshakeAttempts - Max handshake attempts</translation>
|
||||
<translation>MaxHandshakeAttempts - максимум попыток рукопожатия</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../ui/qml/Pages2/PageProtocolAwgSettings.qml" line="408"/>
|
||||
|
||||
@@ -590,27 +590,27 @@ Already installed containers were found on the server. All installed containers
|
||||
<message>
|
||||
<location filename="../ui/qml/Pages2/PageProtocolAwgClientSettings.qml" line="132"/>
|
||||
<source>I1 - First special junk packet</source>
|
||||
<translation>I1 - First special junk packet</translation>
|
||||
<translation>I1 - перший спеціальний сміттєвий пакет</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../ui/qml/Pages2/PageProtocolAwgClientSettings.qml" line="142"/>
|
||||
<source>I2 - Second special junk packet</source>
|
||||
<translation>I2 - Second special junk packet</translation>
|
||||
<translation>I2 - другий спеціальний сміттєвий пакет</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../ui/qml/Pages2/PageProtocolAwgClientSettings.qml" line="152"/>
|
||||
<source>I3 - Third special junk packet</source>
|
||||
<translation>I3 - Third special junk packet</translation>
|
||||
<translation>I3 - третій спеціальний сміттєвий пакет</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../ui/qml/Pages2/PageProtocolAwgClientSettings.qml" line="162"/>
|
||||
<source>I4 - Fourth special junk packet</source>
|
||||
<translation>I4 - Fourth special junk packet</translation>
|
||||
<translation>I4 - четвертий спеціальний сміттєвий пакет</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../ui/qml/Pages2/PageProtocolAwgClientSettings.qml" line="172"/>
|
||||
<source>I5 - Fifth special junk packet</source>
|
||||
<translation>I5 - Fifth special junk packet</translation>
|
||||
<translation>I5 - п'ятий спеціальний сміттєвий пакет</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../ui/qml/Pages2/PageProtocolAwgClientSettings.qml" line="189"/>
|
||||
@@ -620,32 +620,32 @@ Already installed containers were found on the server. All installed containers
|
||||
<message>
|
||||
<location filename="../ui/qml/Pages2/PageProtocolAwgClientSettings.qml" line="199"/>
|
||||
<source>ContentPaddingAddition - Content padding addition</source>
|
||||
<translation>ContentPaddingAddition - Content padding addition</translation>
|
||||
<translation>ContentPaddingAddition - додавання заповнення вмісту</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../ui/qml/Pages2/PageProtocolAwgClientSettings.qml" line="211"/>
|
||||
<source>RekeyAfterTime - Rekey after time</source>
|
||||
<translation>RekeyAfterTime - Rekey after time</translation>
|
||||
<translation>RekeyAfterTime - зміна ключа після часу</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../ui/qml/Pages2/PageProtocolAwgClientSettings.qml" line="223"/>
|
||||
<source>RekeyTimeout - Rekey timeout</source>
|
||||
<translation>RekeyTimeout - Rekey timeout</translation>
|
||||
<translation>RekeyTimeout - тайм-аут зміни ключа</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../ui/qml/Pages2/PageProtocolAwgClientSettings.qml" line="235"/>
|
||||
<source>RejectAfterTime - Reject after time</source>
|
||||
<translation>RejectAfterTime - Reject after time</translation>
|
||||
<translation>RejectAfterTime - відхилення після часу</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../ui/qml/Pages2/PageProtocolAwgClientSettings.qml" line="247"/>
|
||||
<source>KeepaliveTimeout - Keepalive timeout</source>
|
||||
<translation>KeepaliveTimeout - Keepalive timeout</translation>
|
||||
<translation>KeepaliveTimeout - тайм-аут keepalive</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../ui/qml/Pages2/PageProtocolAwgClientSettings.qml" line="259"/>
|
||||
<source>MaxHandshakeAttempts - Max handshake attempts</source>
|
||||
<translation>MaxHandshakeAttempts - Max handshake attempts</translation>
|
||||
<translation>MaxHandshakeAttempts - максимум спроб рукостискання</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../ui/qml/Pages2/PageProtocolAwgClientSettings.qml" line="276"/>
|
||||
@@ -718,82 +718,82 @@ Already installed containers were found on the server. All installed containers
|
||||
<message>
|
||||
<location filename="../ui/qml/Pages2/PageProtocolAwgSettings.qml" line="131"/>
|
||||
<source>Jc - Junk packet count</source>
|
||||
<translation>Jc - Junk packet count</translation>
|
||||
<translation>Jc - кількість сміттєвих пакетів</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../ui/qml/Pages2/PageProtocolAwgSettings.qml" line="141"/>
|
||||
<source>Jmin - Junk packet minimum size</source>
|
||||
<translation>Jmin - Junk packet minimum size</translation>
|
||||
<translation>Jmin - мінімальний розмір сміттєвого пакета</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../ui/qml/Pages2/PageProtocolAwgSettings.qml" line="151"/>
|
||||
<source>Jmax - Junk packet maximum size</source>
|
||||
<translation>Jmax - Junk packet maximum size</translation>
|
||||
<translation>Jmax - максимальний розмір сміттєвого пакета</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../ui/qml/Pages2/PageProtocolAwgSettings.qml" line="161"/>
|
||||
<source>S1 - Init packet junk size</source>
|
||||
<translation>S1 - Init packet junk size</translation>
|
||||
<translation>S1 - розмір смiття в пакеті ініціалізації</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../ui/qml/Pages2/PageProtocolAwgSettings.qml" line="171"/>
|
||||
<source>S2 - Response packet junk size</source>
|
||||
<translation>S2 - Response packet junk size</translation>
|
||||
<translation>S2 - розмір смiття в пакеті відповіді</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../ui/qml/Pages2/PageProtocolAwgSettings.qml" line="183"/>
|
||||
<source>S3 - Cookie reply packet junk size</source>
|
||||
<translation>S3 - Cookie reply packet junk size</translation>
|
||||
<translation>S3 - розмір смiття в пакеті cookie reply</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../ui/qml/Pages2/PageProtocolAwgSettings.qml" line="195"/>
|
||||
<source>S4 - Transport packet junk size</source>
|
||||
<translation>S4 - Transport packet junk size</translation>
|
||||
<translation>S4 - розмір смiття в транспортному пакеті</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../ui/qml/Pages2/PageProtocolAwgSettings.qml" line="207"/>
|
||||
<source>H1 - Init packet magic header</source>
|
||||
<translation>H1 - Init packet magic header</translation>
|
||||
<translation>H1 - магічний заголовок пакета ініціалізації</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../ui/qml/Pages2/PageProtocolAwgSettings.qml" line="219"/>
|
||||
<source>H2 - Response packet magic header</source>
|
||||
<translation>H2 - Response packet magic header</translation>
|
||||
<translation>H2 - магічний заголовок пакета відповіді</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../ui/qml/Pages2/PageProtocolAwgSettings.qml" line="231"/>
|
||||
<source>H3 - Underload packet magic header</source>
|
||||
<translation>H3 - Underload packet magic header</translation>
|
||||
<translation>H3 - магічний заголовок пакета underload</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../ui/qml/Pages2/PageProtocolAwgSettings.qml" line="243"/>
|
||||
<source>H4 - Transport packet magic header</source>
|
||||
<translation>H4 - Transport packet magic header</translation>
|
||||
<translation>H4 - магічний заголовок транспортного пакета</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../ui/qml/Pages2/PageProtocolAwgSettings.qml" line="253"/>
|
||||
<source>I1 - Special junk 1</source>
|
||||
<translation>I1 - Special junk 1</translation>
|
||||
<translation>I1 - спеціальний сміттєвий пакет 1</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../ui/qml/Pages2/PageProtocolAwgSettings.qml" line="263"/>
|
||||
<source>I2 - Special junk 2</source>
|
||||
<translation>I2 - Special junk 2</translation>
|
||||
<translation>I2 - спеціальний сміттєвий пакет 2</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../ui/qml/Pages2/PageProtocolAwgSettings.qml" line="273"/>
|
||||
<source>I3 - Special junk 3</source>
|
||||
<translation>I3 - Special junk 3</translation>
|
||||
<translation>I3 - спеціальний сміттєвий пакет 3</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../ui/qml/Pages2/PageProtocolAwgSettings.qml" line="283"/>
|
||||
<source>I4 - Special junk 4</source>
|
||||
<translation>I4 - Special junk 4</translation>
|
||||
<translation>I4 - спеціальний сміттєвий пакет 4</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../ui/qml/Pages2/PageProtocolAwgSettings.qml" line="293"/>
|
||||
<source>I5 - Special junk 5</source>
|
||||
<translation>I5 - Special junk 5</translation>
|
||||
<translation>I5 - спеціальний сміттєвий пакет 5</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../ui/qml/Pages2/PageProtocolAwgSettings.qml" line="310"/>
|
||||
@@ -803,32 +803,32 @@ Already installed containers were found on the server. All installed containers
|
||||
<message>
|
||||
<location filename="../ui/qml/Pages2/PageProtocolAwgSettings.qml" line="326"/>
|
||||
<source>ContentPaddingAddition - Content padding addition</source>
|
||||
<translation>ContentPaddingAddition - Content padding addition</translation>
|
||||
<translation>ContentPaddingAddition - додавання заповнення вмісту</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../ui/qml/Pages2/PageProtocolAwgSettings.qml" line="339"/>
|
||||
<source>RekeyAfterTime - Rekey after time</source>
|
||||
<translation>RekeyAfterTime - Rekey after time</translation>
|
||||
<translation>RekeyAfterTime - зміна ключа після часу</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../ui/qml/Pages2/PageProtocolAwgSettings.qml" line="352"/>
|
||||
<source>RekeyTimeout - Rekey timeout</source>
|
||||
<translation>RekeyTimeout - Rekey timeout</translation>
|
||||
<translation>RekeyTimeout - тайм-аут зміни ключа</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../ui/qml/Pages2/PageProtocolAwgSettings.qml" line="365"/>
|
||||
<source>RejectAfterTime - Reject after time</source>
|
||||
<translation>RejectAfterTime - Reject after time</translation>
|
||||
<translation>RejectAfterTime - відхилення після часу</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../ui/qml/Pages2/PageProtocolAwgSettings.qml" line="378"/>
|
||||
<source>KeepaliveTimeout - Keepalive timeout</source>
|
||||
<translation>KeepaliveTimeout - Keepalive timeout</translation>
|
||||
<translation>KeepaliveTimeout - тайм-аут keepalive</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../ui/qml/Pages2/PageProtocolAwgSettings.qml" line="391"/>
|
||||
<source>MaxHandshakeAttempts - Max handshake attempts</source>
|
||||
<translation>MaxHandshakeAttempts - Max handshake attempts</translation>
|
||||
<translation>MaxHandshakeAttempts - максимум спроб рукостискання</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../ui/qml/Pages2/PageProtocolAwgSettings.qml" line="408"/>
|
||||
|
||||
@@ -590,27 +590,27 @@ Already installed containers were found on the server. All installed containers
|
||||
<message>
|
||||
<location filename="../ui/qml/Pages2/PageProtocolAwgClientSettings.qml" line="132"/>
|
||||
<source>I1 - First special junk packet</source>
|
||||
<translation>I1 - First special junk packet</translation>
|
||||
<translation>I1 - پہلا خصوصی جنک پیکٹ</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../ui/qml/Pages2/PageProtocolAwgClientSettings.qml" line="142"/>
|
||||
<source>I2 - Second special junk packet</source>
|
||||
<translation>I2 - Second special junk packet</translation>
|
||||
<translation>I2 - دوسرا خصوصی جنک پیکٹ</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../ui/qml/Pages2/PageProtocolAwgClientSettings.qml" line="152"/>
|
||||
<source>I3 - Third special junk packet</source>
|
||||
<translation>I3 - Third special junk packet</translation>
|
||||
<translation>I3 - تیسرا خصوصی جنک پیکٹ</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../ui/qml/Pages2/PageProtocolAwgClientSettings.qml" line="162"/>
|
||||
<source>I4 - Fourth special junk packet</source>
|
||||
<translation>I4 - Fourth special junk packet</translation>
|
||||
<translation>I4 - چوتھا خصوصی جنک پیکٹ</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../ui/qml/Pages2/PageProtocolAwgClientSettings.qml" line="172"/>
|
||||
<source>I5 - Fifth special junk packet</source>
|
||||
<translation>I5 - Fifth special junk packet</translation>
|
||||
<translation>I5 - پانچواں خصوصی جنک پیکٹ</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../ui/qml/Pages2/PageProtocolAwgClientSettings.qml" line="189"/>
|
||||
@@ -620,32 +620,32 @@ Already installed containers were found on the server. All installed containers
|
||||
<message>
|
||||
<location filename="../ui/qml/Pages2/PageProtocolAwgClientSettings.qml" line="199"/>
|
||||
<source>ContentPaddingAddition - Content padding addition</source>
|
||||
<translation>ContentPaddingAddition - Content padding addition</translation>
|
||||
<translation>ContentPaddingAddition - کنٹینٹ پیڈنگ اضافہ</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../ui/qml/Pages2/PageProtocolAwgClientSettings.qml" line="211"/>
|
||||
<source>RekeyAfterTime - Rekey after time</source>
|
||||
<translation>RekeyAfterTime - Rekey after time</translation>
|
||||
<translation>RekeyAfterTime - وقت کے بعد ری کی</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../ui/qml/Pages2/PageProtocolAwgClientSettings.qml" line="223"/>
|
||||
<source>RekeyTimeout - Rekey timeout</source>
|
||||
<translation>RekeyTimeout - Rekey timeout</translation>
|
||||
<translation>RekeyTimeout - ری کی ٹائم آؤٹ</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../ui/qml/Pages2/PageProtocolAwgClientSettings.qml" line="235"/>
|
||||
<source>RejectAfterTime - Reject after time</source>
|
||||
<translation>RejectAfterTime - Reject after time</translation>
|
||||
<translation>RejectAfterTime - وقت کے بعد رد</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../ui/qml/Pages2/PageProtocolAwgClientSettings.qml" line="247"/>
|
||||
<source>KeepaliveTimeout - Keepalive timeout</source>
|
||||
<translation>KeepaliveTimeout - Keepalive timeout</translation>
|
||||
<translation>KeepaliveTimeout - کیپ الائیو ٹائم آؤٹ</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../ui/qml/Pages2/PageProtocolAwgClientSettings.qml" line="259"/>
|
||||
<source>MaxHandshakeAttempts - Max handshake attempts</source>
|
||||
<translation>MaxHandshakeAttempts - Max handshake attempts</translation>
|
||||
<translation>MaxHandshakeAttempts - زیادہ سے زیادہ ہینڈشیک کوششیں</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../ui/qml/Pages2/PageProtocolAwgClientSettings.qml" line="276"/>
|
||||
@@ -718,82 +718,82 @@ Already installed containers were found on the server. All installed containers
|
||||
<message>
|
||||
<location filename="../ui/qml/Pages2/PageProtocolAwgSettings.qml" line="131"/>
|
||||
<source>Jc - Junk packet count</source>
|
||||
<translation>Jc - Junk packet count</translation>
|
||||
<translation>Jc - جنک پیکٹ کی تعداد</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../ui/qml/Pages2/PageProtocolAwgSettings.qml" line="141"/>
|
||||
<source>Jmin - Junk packet minimum size</source>
|
||||
<translation>Jmin - Junk packet minimum size</translation>
|
||||
<translation>Jmin - جنک پیکٹ کا کم از کم سائز</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../ui/qml/Pages2/PageProtocolAwgSettings.qml" line="151"/>
|
||||
<source>Jmax - Junk packet maximum size</source>
|
||||
<translation>Jmax - Junk packet maximum size</translation>
|
||||
<translation>Jmax - جنک پیکٹ کا زیادہ سے زیادہ سائز</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../ui/qml/Pages2/PageProtocolAwgSettings.qml" line="161"/>
|
||||
<source>S1 - Init packet junk size</source>
|
||||
<translation>S1 - Init packet junk size</translation>
|
||||
<translation>S1 - init پیکٹ جنک سائز</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../ui/qml/Pages2/PageProtocolAwgSettings.qml" line="171"/>
|
||||
<source>S2 - Response packet junk size</source>
|
||||
<translation>S2 - Response packet junk size</translation>
|
||||
<translation>S2 - جوابی پیکٹ جنک سائز</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../ui/qml/Pages2/PageProtocolAwgSettings.qml" line="183"/>
|
||||
<source>S3 - Cookie reply packet junk size</source>
|
||||
<translation>S3 - Cookie reply packet junk size</translation>
|
||||
<translation>S3 - کوکی جوابی پیکٹ جنک سائز</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../ui/qml/Pages2/PageProtocolAwgSettings.qml" line="195"/>
|
||||
<source>S4 - Transport packet junk size</source>
|
||||
<translation>S4 - Transport packet junk size</translation>
|
||||
<translation>S4 - ٹرانسپورٹ پیکٹ جنک سائز</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../ui/qml/Pages2/PageProtocolAwgSettings.qml" line="207"/>
|
||||
<source>H1 - Init packet magic header</source>
|
||||
<translation>H1 - Init packet magic header</translation>
|
||||
<translation>H1 - init پیکٹ میجک ہیڈر</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../ui/qml/Pages2/PageProtocolAwgSettings.qml" line="219"/>
|
||||
<source>H2 - Response packet magic header</source>
|
||||
<translation>H2 - Response packet magic header</translation>
|
||||
<translation>H2 - جوابی پیکٹ میجک ہیڈر</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../ui/qml/Pages2/PageProtocolAwgSettings.qml" line="231"/>
|
||||
<source>H3 - Underload packet magic header</source>
|
||||
<translation>H3 - Underload packet magic header</translation>
|
||||
<translation>H3 - underload پیکٹ میجک ہیڈر</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../ui/qml/Pages2/PageProtocolAwgSettings.qml" line="243"/>
|
||||
<source>H4 - Transport packet magic header</source>
|
||||
<translation>H4 - Transport packet magic header</translation>
|
||||
<translation>H4 - ٹرانسپورٹ پیکٹ میجک ہیڈر</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../ui/qml/Pages2/PageProtocolAwgSettings.qml" line="253"/>
|
||||
<source>I1 - Special junk 1</source>
|
||||
<translation>I1 - Special junk 1</translation>
|
||||
<translation>I1 - خصوصی جنک 1</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../ui/qml/Pages2/PageProtocolAwgSettings.qml" line="263"/>
|
||||
<source>I2 - Special junk 2</source>
|
||||
<translation>I2 - Special junk 2</translation>
|
||||
<translation>I2 - خصوصی جنک 2</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../ui/qml/Pages2/PageProtocolAwgSettings.qml" line="273"/>
|
||||
<source>I3 - Special junk 3</source>
|
||||
<translation>I3 - Special junk 3</translation>
|
||||
<translation>I3 - خصوصی جنک 3</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../ui/qml/Pages2/PageProtocolAwgSettings.qml" line="283"/>
|
||||
<source>I4 - Special junk 4</source>
|
||||
<translation>I4 - Special junk 4</translation>
|
||||
<translation>I4 - خصوصی جنک 4</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../ui/qml/Pages2/PageProtocolAwgSettings.qml" line="293"/>
|
||||
<source>I5 - Special junk 5</source>
|
||||
<translation>I5 - Special junk 5</translation>
|
||||
<translation>I5 - خصوصی جنک 5</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../ui/qml/Pages2/PageProtocolAwgSettings.qml" line="310"/>
|
||||
@@ -803,32 +803,32 @@ Already installed containers were found on the server. All installed containers
|
||||
<message>
|
||||
<location filename="../ui/qml/Pages2/PageProtocolAwgSettings.qml" line="326"/>
|
||||
<source>ContentPaddingAddition - Content padding addition</source>
|
||||
<translation>ContentPaddingAddition - Content padding addition</translation>
|
||||
<translation>ContentPaddingAddition - کنٹینٹ پیڈنگ اضافہ</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../ui/qml/Pages2/PageProtocolAwgSettings.qml" line="339"/>
|
||||
<source>RekeyAfterTime - Rekey after time</source>
|
||||
<translation>RekeyAfterTime - Rekey after time</translation>
|
||||
<translation>RekeyAfterTime - وقت کے بعد ری کی</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../ui/qml/Pages2/PageProtocolAwgSettings.qml" line="352"/>
|
||||
<source>RekeyTimeout - Rekey timeout</source>
|
||||
<translation>RekeyTimeout - Rekey timeout</translation>
|
||||
<translation>RekeyTimeout - ری کی ٹائم آؤٹ</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../ui/qml/Pages2/PageProtocolAwgSettings.qml" line="365"/>
|
||||
<source>RejectAfterTime - Reject after time</source>
|
||||
<translation>RejectAfterTime - Reject after time</translation>
|
||||
<translation>RejectAfterTime - وقت کے بعد رد</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../ui/qml/Pages2/PageProtocolAwgSettings.qml" line="378"/>
|
||||
<source>KeepaliveTimeout - Keepalive timeout</source>
|
||||
<translation>KeepaliveTimeout - Keepalive timeout</translation>
|
||||
<translation>KeepaliveTimeout - کیپ الائیو ٹائم آؤٹ</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../ui/qml/Pages2/PageProtocolAwgSettings.qml" line="391"/>
|
||||
<source>MaxHandshakeAttempts - Max handshake attempts</source>
|
||||
<translation>MaxHandshakeAttempts - Max handshake attempts</translation>
|
||||
<translation>MaxHandshakeAttempts - زیادہ سے زیادہ ہینڈشیک کوششیں</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../ui/qml/Pages2/PageProtocolAwgSettings.qml" line="408"/>
|
||||
|
||||
@@ -590,27 +590,27 @@ Already installed containers were found on the server. All installed containers
|
||||
<message>
|
||||
<location filename="../ui/qml/Pages2/PageProtocolAwgClientSettings.qml" line="132"/>
|
||||
<source>I1 - First special junk packet</source>
|
||||
<translation>I1 - First special junk packet</translation>
|
||||
<translation>I1 - 第一个特殊垃圾数据包</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../ui/qml/Pages2/PageProtocolAwgClientSettings.qml" line="142"/>
|
||||
<source>I2 - Second special junk packet</source>
|
||||
<translation>I2 - Second special junk packet</translation>
|
||||
<translation>I2 - 第二个特殊垃圾数据包</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../ui/qml/Pages2/PageProtocolAwgClientSettings.qml" line="152"/>
|
||||
<source>I3 - Third special junk packet</source>
|
||||
<translation>I3 - Third special junk packet</translation>
|
||||
<translation>I3 - 第三个特殊垃圾数据包</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../ui/qml/Pages2/PageProtocolAwgClientSettings.qml" line="162"/>
|
||||
<source>I4 - Fourth special junk packet</source>
|
||||
<translation>I4 - Fourth special junk packet</translation>
|
||||
<translation>I4 - 第四个特殊垃圾数据包</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../ui/qml/Pages2/PageProtocolAwgClientSettings.qml" line="172"/>
|
||||
<source>I5 - Fifth special junk packet</source>
|
||||
<translation>I5 - Fifth special junk packet</translation>
|
||||
<translation>I5 - 第五个特殊垃圾数据包</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../ui/qml/Pages2/PageProtocolAwgClientSettings.qml" line="189"/>
|
||||
@@ -620,32 +620,32 @@ Already installed containers were found on the server. All installed containers
|
||||
<message>
|
||||
<location filename="../ui/qml/Pages2/PageProtocolAwgClientSettings.qml" line="199"/>
|
||||
<source>ContentPaddingAddition - Content padding addition</source>
|
||||
<translation>ContentPaddingAddition - Content padding addition</translation>
|
||||
<translation>ContentPaddingAddition - 内容填充增量</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../ui/qml/Pages2/PageProtocolAwgClientSettings.qml" line="211"/>
|
||||
<source>RekeyAfterTime - Rekey after time</source>
|
||||
<translation>RekeyAfterTime - Rekey after time</translation>
|
||||
<translation>RekeyAfterTime - 指定时间后重新协商密钥</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../ui/qml/Pages2/PageProtocolAwgClientSettings.qml" line="223"/>
|
||||
<source>RekeyTimeout - Rekey timeout</source>
|
||||
<translation>RekeyTimeout - Rekey timeout</translation>
|
||||
<translation>RekeyTimeout - 重新协商密钥超时</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../ui/qml/Pages2/PageProtocolAwgClientSettings.qml" line="235"/>
|
||||
<source>RejectAfterTime - Reject after time</source>
|
||||
<translation>RejectAfterTime - Reject after time</translation>
|
||||
<translation>RejectAfterTime - 指定时间后拒绝</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../ui/qml/Pages2/PageProtocolAwgClientSettings.qml" line="247"/>
|
||||
<source>KeepaliveTimeout - Keepalive timeout</source>
|
||||
<translation>KeepaliveTimeout - Keepalive timeout</translation>
|
||||
<translation>KeepaliveTimeout - Keepalive 超时</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../ui/qml/Pages2/PageProtocolAwgClientSettings.qml" line="259"/>
|
||||
<source>MaxHandshakeAttempts - Max handshake attempts</source>
|
||||
<translation>MaxHandshakeAttempts - Max handshake attempts</translation>
|
||||
<translation>MaxHandshakeAttempts - 最大握手尝试次数</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../ui/qml/Pages2/PageProtocolAwgClientSettings.qml" line="276"/>
|
||||
@@ -718,82 +718,82 @@ Already installed containers were found on the server. All installed containers
|
||||
<message>
|
||||
<location filename="../ui/qml/Pages2/PageProtocolAwgSettings.qml" line="131"/>
|
||||
<source>Jc - Junk packet count</source>
|
||||
<translation>Jc - Junk packet count</translation>
|
||||
<translation>Jc - 垃圾数据包数量</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../ui/qml/Pages2/PageProtocolAwgSettings.qml" line="141"/>
|
||||
<source>Jmin - Junk packet minimum size</source>
|
||||
<translation>Jmin - Junk packet minimum size</translation>
|
||||
<translation>Jmin - 垃圾数据包最小大小</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../ui/qml/Pages2/PageProtocolAwgSettings.qml" line="151"/>
|
||||
<source>Jmax - Junk packet maximum size</source>
|
||||
<translation>Jmax - Junk packet maximum size</translation>
|
||||
<translation>Jmax - 垃圾数据包最大大小</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../ui/qml/Pages2/PageProtocolAwgSettings.qml" line="161"/>
|
||||
<source>S1 - Init packet junk size</source>
|
||||
<translation>S1 - Init packet junk size</translation>
|
||||
<translation>S1 - 初始化包垃圾数据大小</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../ui/qml/Pages2/PageProtocolAwgSettings.qml" line="171"/>
|
||||
<source>S2 - Response packet junk size</source>
|
||||
<translation>S2 - Response packet junk size</translation>
|
||||
<translation>S2 - 响应包垃圾数据大小</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../ui/qml/Pages2/PageProtocolAwgSettings.qml" line="183"/>
|
||||
<source>S3 - Cookie reply packet junk size</source>
|
||||
<translation>S3 - Cookie reply packet junk size</translation>
|
||||
<translation>S3 - Cookie 回复包垃圾数据大小</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../ui/qml/Pages2/PageProtocolAwgSettings.qml" line="195"/>
|
||||
<source>S4 - Transport packet junk size</source>
|
||||
<translation>S4 - Transport packet junk size</translation>
|
||||
<translation>S4 - 传输包垃圾数据大小</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../ui/qml/Pages2/PageProtocolAwgSettings.qml" line="207"/>
|
||||
<source>H1 - Init packet magic header</source>
|
||||
<translation>H1 - Init packet magic header</translation>
|
||||
<translation>H1 - 初始化包魔术头</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../ui/qml/Pages2/PageProtocolAwgSettings.qml" line="219"/>
|
||||
<source>H2 - Response packet magic header</source>
|
||||
<translation>H2 - Response packet magic header</translation>
|
||||
<translation>H2 - 响应包魔术头</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../ui/qml/Pages2/PageProtocolAwgSettings.qml" line="231"/>
|
||||
<source>H3 - Underload packet magic header</source>
|
||||
<translation>H3 - Underload packet magic header</translation>
|
||||
<translation>H3 - 低负载包魔术头</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../ui/qml/Pages2/PageProtocolAwgSettings.qml" line="243"/>
|
||||
<source>H4 - Transport packet magic header</source>
|
||||
<translation>H4 - Transport packet magic header</translation>
|
||||
<translation>H4 - 传输包魔术头</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../ui/qml/Pages2/PageProtocolAwgSettings.qml" line="253"/>
|
||||
<source>I1 - Special junk 1</source>
|
||||
<translation>I1 - Special junk 1</translation>
|
||||
<translation>I1 - 特殊垃圾数据 1</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../ui/qml/Pages2/PageProtocolAwgSettings.qml" line="263"/>
|
||||
<source>I2 - Special junk 2</source>
|
||||
<translation>I2 - Special junk 2</translation>
|
||||
<translation>I2 - 特殊垃圾数据 2</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../ui/qml/Pages2/PageProtocolAwgSettings.qml" line="273"/>
|
||||
<source>I3 - Special junk 3</source>
|
||||
<translation>I3 - Special junk 3</translation>
|
||||
<translation>I3 - 特殊垃圾数据 3</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../ui/qml/Pages2/PageProtocolAwgSettings.qml" line="283"/>
|
||||
<source>I4 - Special junk 4</source>
|
||||
<translation>I4 - Special junk 4</translation>
|
||||
<translation>I4 - 特殊垃圾数据 4</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../ui/qml/Pages2/PageProtocolAwgSettings.qml" line="293"/>
|
||||
<source>I5 - Special junk 5</source>
|
||||
<translation>I5 - Special junk 5</translation>
|
||||
<translation>I5 - 特殊垃圾数据 5</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../ui/qml/Pages2/PageProtocolAwgSettings.qml" line="310"/>
|
||||
@@ -803,32 +803,32 @@ Already installed containers were found on the server. All installed containers
|
||||
<message>
|
||||
<location filename="../ui/qml/Pages2/PageProtocolAwgSettings.qml" line="326"/>
|
||||
<source>ContentPaddingAddition - Content padding addition</source>
|
||||
<translation>ContentPaddingAddition - Content padding addition</translation>
|
||||
<translation>ContentPaddingAddition - 内容填充增量</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../ui/qml/Pages2/PageProtocolAwgSettings.qml" line="339"/>
|
||||
<source>RekeyAfterTime - Rekey after time</source>
|
||||
<translation>RekeyAfterTime - Rekey after time</translation>
|
||||
<translation>RekeyAfterTime - 指定时间后重新协商密钥</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../ui/qml/Pages2/PageProtocolAwgSettings.qml" line="352"/>
|
||||
<source>RekeyTimeout - Rekey timeout</source>
|
||||
<translation>RekeyTimeout - Rekey timeout</translation>
|
||||
<translation>RekeyTimeout - 重新协商密钥超时</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../ui/qml/Pages2/PageProtocolAwgSettings.qml" line="365"/>
|
||||
<source>RejectAfterTime - Reject after time</source>
|
||||
<translation>RejectAfterTime - Reject after time</translation>
|
||||
<translation>RejectAfterTime - 指定时间后拒绝</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../ui/qml/Pages2/PageProtocolAwgSettings.qml" line="378"/>
|
||||
<source>KeepaliveTimeout - Keepalive timeout</source>
|
||||
<translation>KeepaliveTimeout - Keepalive timeout</translation>
|
||||
<translation>KeepaliveTimeout - Keepalive 超时</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../ui/qml/Pages2/PageProtocolAwgSettings.qml" line="391"/>
|
||||
<source>MaxHandshakeAttempts - Max handshake attempts</source>
|
||||
<translation>MaxHandshakeAttempts - Max handshake attempts</translation>
|
||||
<translation>MaxHandshakeAttempts - 最大握手尝试次数</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../ui/qml/Pages2/PageProtocolAwgSettings.qml" line="408"/>
|
||||
|
||||
@@ -8,6 +8,16 @@
|
||||
|
||||
namespace {
|
||||
Logger logger("FocusController");
|
||||
|
||||
QString rootObjectName(const QObject *object)
|
||||
{
|
||||
if (object == nullptr) {
|
||||
return QStringLiteral("null");
|
||||
}
|
||||
const QString className = QString::fromLatin1(object->metaObject()->className());
|
||||
const QString name = object->objectName();
|
||||
return name.isEmpty() ? className : className + QLatin1Char('/') + name;
|
||||
}
|
||||
}
|
||||
|
||||
FocusController::FocusController(QQmlApplicationEngine *engine, QObject *parent)
|
||||
@@ -76,6 +86,7 @@ void FocusController::setFocusOnDefaultItem()
|
||||
void FocusController::pushRootObject(QObject *object)
|
||||
{
|
||||
m_rootObjects.push(object);
|
||||
logger.debug() << "pushRootObject:" << rootObjectName(object) << "depth=" << m_rootObjects.size();
|
||||
dropListView();
|
||||
// setFocusOnDefaultItem();
|
||||
}
|
||||
@@ -83,20 +94,29 @@ void FocusController::pushRootObject(QObject *object)
|
||||
void FocusController::dropRootObject(QObject *object)
|
||||
{
|
||||
if (m_rootObjects.empty()) {
|
||||
logger.warning() << "dropRootObject: the stack is already empty, this drop had no matching push, object="
|
||||
<< rootObjectName(object);
|
||||
return;
|
||||
}
|
||||
|
||||
if (m_rootObjects.top() == object) {
|
||||
m_rootObjects.pop();
|
||||
logger.debug() << "dropRootObject:" << rootObjectName(object) << "depth=" << m_rootObjects.size();
|
||||
dropListView();
|
||||
setFocusOnDefaultItem();
|
||||
} else {
|
||||
logger.warning() << "TRY TO DROP WRONG ROOT OBJECT: " << m_rootObjects.top() << " SHOULD BE: " << object;
|
||||
logger.warning() << "TRY TO DROP WRONG ROOT OBJECT: top=" << rootObjectName(m_rootObjects.top())
|
||||
<< "SHOULD BE:" << rootObjectName(object) << "depth=" << m_rootObjects.size()
|
||||
<< ", the stack is left as is and stays out of sync";
|
||||
}
|
||||
}
|
||||
|
||||
void FocusController::resetRootObject()
|
||||
{
|
||||
if (!m_rootObjects.empty()) {
|
||||
logger.debug() << "resetRootObject: dropping" << m_rootObjects.size() << "objects, top="
|
||||
<< rootObjectName(m_rootObjects.top());
|
||||
}
|
||||
m_rootObjects.clear();
|
||||
}
|
||||
|
||||
|
||||
@@ -35,6 +35,11 @@
|
||||
#include "core/models/protocols/wireGuardProtocolConfig.h"
|
||||
#include "core/models/protocols/openVpnProtocolConfig.h"
|
||||
#include "core/models/protocols/xrayProtocolConfig.h"
|
||||
#include "logger.h"
|
||||
|
||||
namespace {
|
||||
Logger logger("InstallUiController");
|
||||
}
|
||||
|
||||
InstallUiController::InstallUiController(InstallController *installController,
|
||||
ServersController *serversController,
|
||||
@@ -306,7 +311,19 @@ void InstallUiController::updateServerConfig(const QString &serverId, int contai
|
||||
const bool asyncUpdate = container == DockerContainer::MtProxy || container == DockerContainer::Telemt
|
||||
|| container == DockerContainer::Xray || container == DockerContainer::SSXray;
|
||||
|
||||
|
||||
if (asyncUpdate) {
|
||||
if (m_serverConfigUpdateInProgress) {
|
||||
if (container == DockerContainer::Xray || container == DockerContainer::SSXray) {
|
||||
logger.warning() << "Xray save rejected, a save is already running";
|
||||
} else {
|
||||
logger.warning() << "InstallUiController: server config save rejected for container"
|
||||
<< ContainerUtils::containerToString(container) << ", an update is already running";
|
||||
}
|
||||
return;
|
||||
}
|
||||
m_serverConfigUpdateInProgress = true;
|
||||
|
||||
const bool emitBusy = container == DockerContainer::MtProxy || container == DockerContainer::Telemt;
|
||||
if (emitBusy)
|
||||
emit serverIsBusy(true);
|
||||
@@ -316,6 +333,7 @@ void InstallUiController::updateServerConfig(const QString &serverId, int contai
|
||||
[this, watcher, serverId, container, closePage, protocolTypeCopy, emitBusy]() {
|
||||
const ErrorCode errorCode = watcher->result();
|
||||
watcher->deleteLater();
|
||||
m_serverConfigUpdateInProgress = false;
|
||||
if (emitBusy)
|
||||
emit serverIsBusy(false);
|
||||
|
||||
@@ -326,6 +344,9 @@ void InstallUiController::updateServerConfig(const QString &serverId, int contai
|
||||
updateProtocolConfigModel(serverId, static_cast<int>(container), static_cast<int>(protocolTypeCopy));
|
||||
emit updateContainerFinished(tr("Settings updated successfully"), closePage);
|
||||
} else {
|
||||
logger.error() << "InstallUiController: async server config save failed for container"
|
||||
<< ContainerUtils::containerToString(container) << ", error="
|
||||
<< static_cast<int>(errorCode);
|
||||
emit installationErrorOccurred(errorCode);
|
||||
}
|
||||
});
|
||||
@@ -352,6 +373,8 @@ void InstallUiController::updateServerConfig(const QString &serverId, int contai
|
||||
return;
|
||||
}
|
||||
|
||||
logger.error() << "InstallUiController: server config save failed for container"
|
||||
<< ContainerUtils::containerToString(container) << ", error=" << static_cast<int>(errorCode);
|
||||
emit installationErrorOccurred(errorCode);
|
||||
}
|
||||
|
||||
|
||||
@@ -160,7 +160,9 @@ private:
|
||||
ServerCredentials m_processedServerCredentials;
|
||||
|
||||
QString m_privateKeyPassphrase;
|
||||
|
||||
|
||||
bool m_serverConfigUpdateInProgress = false;
|
||||
|
||||
void updateProtocolConfigModel(const QString &serverId, int containerIndex, int protocolIndex);
|
||||
|
||||
bool buildContainerConfigFromModel(int containerIndex, int protocolIndex, ContainerConfig &containerConfig);
|
||||
|
||||
@@ -13,14 +13,6 @@
|
||||
using namespace amnezia;
|
||||
using namespace ProtocolUtils;
|
||||
|
||||
namespace
|
||||
{
|
||||
QString awgToggleValue(bool enabled)
|
||||
{
|
||||
return enabled ? QString(protocols::awg::awgBoolOn) : QString();
|
||||
}
|
||||
} // namespace
|
||||
|
||||
AwgConfigModel::AwgConfigModel(QObject *parent) : QAbstractListModel(parent)
|
||||
{
|
||||
}
|
||||
@@ -58,11 +50,9 @@ bool AwgConfigModel::setData(const QModelIndex &index, const QVariant &value, in
|
||||
case Roles::ClientRejectAfterTimeRole: m_protocolConfig.clientConfig->rejectAfterTime = strValue; break;
|
||||
case Roles::ClientKeepaliveTimeoutRole: m_protocolConfig.clientConfig->keepaliveTimeout = strValue; break;
|
||||
case Roles::ClientMaxHandshakeAttemptsRole: m_protocolConfig.clientConfig->maxHandshakeAttempts = strValue; break;
|
||||
case Roles::ClientRandomTrailersRole:
|
||||
m_protocolConfig.clientConfig->randomTrailers = awgToggleValue(value.toBool());
|
||||
break;
|
||||
case Roles::ClientDisableCookiesRole:
|
||||
m_protocolConfig.clientConfig->disableCookies = awgToggleValue(value.toBool());
|
||||
m_protocolConfig.clientConfig->disableCookies =
|
||||
value.toBool() ? QString(protocols::awg::awgBoolOn) : QString(protocols::awg::awgBoolOff);
|
||||
break;
|
||||
case Roles::ServerJunkPacketCountRole: m_protocolConfig.serverConfig.junkPacketCount = strValue; break;
|
||||
case Roles::ServerJunkPacketMinSizeRole: m_protocolConfig.serverConfig.junkPacketMinSize = strValue; break;
|
||||
@@ -99,10 +89,12 @@ bool AwgConfigModel::setData(const QModelIndex &index, const QVariant &value, in
|
||||
break;
|
||||
}
|
||||
case Roles::ServerRandomTrailersRole:
|
||||
m_protocolConfig.serverConfig.randomTrailers = awgToggleValue(value.toBool());
|
||||
m_protocolConfig.serverConfig.randomTrailers =
|
||||
value.toBool() ? QString(protocols::awg::awgBoolOn) : QString(protocols::awg::awgBoolOff);
|
||||
break;
|
||||
case Roles::ServerDisableCookiesRole:
|
||||
m_protocolConfig.serverConfig.disableCookies = awgToggleValue(value.toBool());
|
||||
m_protocolConfig.serverConfig.disableCookies =
|
||||
value.toBool() ? QString(protocols::awg::awgBoolOn) : QString(protocols::awg::awgBoolOff);
|
||||
break;
|
||||
default:
|
||||
return false;
|
||||
|
||||
@@ -5,6 +5,7 @@
|
||||
#include "core/utils/constants/configKeys.h"
|
||||
#include "core/utils/constants/protocolConstants.h"
|
||||
#include "core/utils/networkUtilities.h"
|
||||
#include "core/utils/containers/containerUtils.h"
|
||||
|
||||
#include <QHostAddress>
|
||||
#include <QRegularExpression>
|
||||
@@ -34,10 +35,11 @@ bool XrayConfigModel::setData(const QModelIndex& index, const QVariant& value, i
|
||||
const bool wasUnsavedChanges = hasUnsavedChanges();
|
||||
|
||||
auto& srv = m_protocolConfig.serverConfig;
|
||||
auto& tpl = m_protocolConfig.clientTemplate;
|
||||
auto& xhttp = srv.xhttp;
|
||||
auto& mkcp = srv.mkcp;
|
||||
auto& pad = xhttp.xPadding;
|
||||
auto& mux = xhttp.xmux;
|
||||
auto& mux = tpl.xmux;
|
||||
|
||||
QString str = value.toString();
|
||||
|
||||
@@ -56,9 +58,11 @@ bool XrayConfigModel::setData(const QModelIndex& index, const QVariant& value, i
|
||||
break;
|
||||
|
||||
// ── Security ──────────────────────────────────────────────────────
|
||||
case Roles::FingerprintRole: srv.fingerprint = str;
|
||||
case Roles::FingerprintRole: tpl.fingerprint = str;
|
||||
break;
|
||||
case Roles::SniRole: srv.sni = str;
|
||||
case Roles::SniRole:
|
||||
srv.sni = str;
|
||||
srv.site = str;
|
||||
break;
|
||||
case Roles::AlpnRole: srv.alpn = str;
|
||||
break;
|
||||
@@ -70,7 +74,7 @@ bool XrayConfigModel::setData(const QModelIndex& index, const QVariant& value, i
|
||||
break;
|
||||
case Roles::XhttpPathRole: xhttp.path = str;
|
||||
break;
|
||||
case Roles::XhttpUplinkMethodRole: xhttp.uplinkMethod = str;
|
||||
case Roles::XhttpUplinkMethodRole: tpl.uplinkMethod = str;
|
||||
break;
|
||||
case Roles::XhttpDisableGrpcRole: xhttp.disableGrpc = value.toBool();
|
||||
break;
|
||||
@@ -90,7 +94,7 @@ bool XrayConfigModel::setData(const QModelIndex& index, const QVariant& value, i
|
||||
case Roles::XhttpUplinkDataKeyRole: xhttp.uplinkDataKey = str;
|
||||
break;
|
||||
|
||||
case Roles::XhttpUplinkChunkSizeRole: xhttp.uplinkChunkSize = str;
|
||||
case Roles::XhttpUplinkChunkSizeRole: tpl.uplinkChunkSize = str;
|
||||
break;
|
||||
case Roles::XhttpScMaxBufferedPostsRole: xhttp.scMaxBufferedPosts = str;
|
||||
break;
|
||||
@@ -98,9 +102,9 @@ bool XrayConfigModel::setData(const QModelIndex& index, const QVariant& value, i
|
||||
break;
|
||||
case Roles::XhttpScMaxEachPostBytesMaxRole: xhttp.scMaxEachPostBytesMax = str;
|
||||
break;
|
||||
case Roles::XhttpScMinPostsIntervalMsMinRole: xhttp.scMinPostsIntervalMsMin = str;
|
||||
case Roles::XhttpScMinPostsIntervalMsMinRole: tpl.scMinPostsIntervalMsMin = str;
|
||||
break;
|
||||
case Roles::XhttpScMinPostsIntervalMsMaxRole: xhttp.scMinPostsIntervalMsMax = str;
|
||||
case Roles::XhttpScMinPostsIntervalMsMaxRole: tpl.scMinPostsIntervalMsMax = str;
|
||||
break;
|
||||
case Roles::XhttpScStreamUpServerSecsMinRole: xhttp.scStreamUpServerSecsMin = str;
|
||||
break;
|
||||
@@ -114,11 +118,11 @@ bool XrayConfigModel::setData(const QModelIndex& index, const QVariant& value, i
|
||||
break;
|
||||
case Roles::MkcpDownlinkCapacityRole: mkcp.downlinkCapacity = str;
|
||||
break;
|
||||
case Roles::MkcpReadBufferSizeRole: mkcp.readBufferSize = str;
|
||||
case Roles::MkcpMtuRole: mkcp.mtu = str;
|
||||
break;
|
||||
case Roles::MkcpWriteBufferSizeRole: mkcp.writeBufferSize = str;
|
||||
case Roles::MkcpCwndMultiplierRole: mkcp.cwndMultiplier = str;
|
||||
break;
|
||||
case Roles::MkcpCongestionRole: mkcp.congestion = value.toBool();
|
||||
case Roles::MkcpMaxSendingWindowRole: mkcp.maxSendingWindow = str;
|
||||
break;
|
||||
|
||||
// ── xPadding ──────────────────────────────────────────────────────
|
||||
@@ -181,10 +185,11 @@ QVariant XrayConfigModel::data(const QModelIndex& index, int role) const
|
||||
}
|
||||
|
||||
const auto& srv = m_protocolConfig.serverConfig;
|
||||
const auto& tpl = m_protocolConfig.clientTemplate;
|
||||
const auto& xhttp = srv.xhttp;
|
||||
const auto& mkcp = srv.mkcp;
|
||||
const auto& pad = xhttp.xPadding;
|
||||
const auto& mux = xhttp.xmux;
|
||||
const auto& mux = tpl.xmux;
|
||||
|
||||
switch (role)
|
||||
{
|
||||
@@ -196,7 +201,7 @@ QVariant XrayConfigModel::data(const QModelIndex& index, int role) const
|
||||
case Roles::FlowRole: return srv.flow;
|
||||
|
||||
// ── Security ──────────────────────────────────────────────────────
|
||||
case Roles::FingerprintRole: return srv.fingerprint;
|
||||
case Roles::FingerprintRole: return tpl.fingerprint;
|
||||
case Roles::SniRole: return srv.sni;
|
||||
case Roles::AlpnRole: return srv.alpn;
|
||||
|
||||
@@ -204,7 +209,7 @@ QVariant XrayConfigModel::data(const QModelIndex& index, int role) const
|
||||
case Roles::XhttpModeRole: return xhttp.mode;
|
||||
case Roles::XhttpHostRole: return xhttp.host;
|
||||
case Roles::XhttpPathRole: return xhttp.path;
|
||||
case Roles::XhttpUplinkMethodRole: return xhttp.uplinkMethod;
|
||||
case Roles::XhttpUplinkMethodRole: return tpl.uplinkMethod;
|
||||
case Roles::XhttpDisableGrpcRole: return xhttp.disableGrpc;
|
||||
case Roles::XhttpDisableSseRole: return xhttp.disableSse;
|
||||
|
||||
@@ -215,12 +220,12 @@ QVariant XrayConfigModel::data(const QModelIndex& index, int role) const
|
||||
case Roles::XhttpUplinkDataPlacementRole: return xhttp.uplinkDataPlacement;
|
||||
case Roles::XhttpUplinkDataKeyRole: return xhttp.uplinkDataKey;
|
||||
|
||||
case Roles::XhttpUplinkChunkSizeRole: return xhttp.uplinkChunkSize;
|
||||
case Roles::XhttpUplinkChunkSizeRole: return tpl.uplinkChunkSize;
|
||||
case Roles::XhttpScMaxBufferedPostsRole: return xhttp.scMaxBufferedPosts;
|
||||
case Roles::XhttpScMaxEachPostBytesMinRole: return xhttp.scMaxEachPostBytesMin;
|
||||
case Roles::XhttpScMaxEachPostBytesMaxRole: return xhttp.scMaxEachPostBytesMax;
|
||||
case Roles::XhttpScMinPostsIntervalMsMinRole: return xhttp.scMinPostsIntervalMsMin;
|
||||
case Roles::XhttpScMinPostsIntervalMsMaxRole: return xhttp.scMinPostsIntervalMsMax;
|
||||
case Roles::XhttpScMinPostsIntervalMsMinRole: return tpl.scMinPostsIntervalMsMin;
|
||||
case Roles::XhttpScMinPostsIntervalMsMaxRole: return tpl.scMinPostsIntervalMsMax;
|
||||
case Roles::XhttpScStreamUpServerSecsMinRole: return xhttp.scStreamUpServerSecsMin;
|
||||
case Roles::XhttpScStreamUpServerSecsMaxRole: return xhttp.scStreamUpServerSecsMax;
|
||||
|
||||
@@ -228,9 +233,9 @@ QVariant XrayConfigModel::data(const QModelIndex& index, int role) const
|
||||
case Roles::MkcpTtiRole: return mkcp.tti;
|
||||
case Roles::MkcpUplinkCapacityRole: return mkcp.uplinkCapacity;
|
||||
case Roles::MkcpDownlinkCapacityRole: return mkcp.downlinkCapacity;
|
||||
case Roles::MkcpReadBufferSizeRole: return mkcp.readBufferSize;
|
||||
case Roles::MkcpWriteBufferSizeRole: return mkcp.writeBufferSize;
|
||||
case Roles::MkcpCongestionRole: return mkcp.congestion;
|
||||
case Roles::MkcpMtuRole: return mkcp.mtu;
|
||||
case Roles::MkcpCwndMultiplierRole: return mkcp.cwndMultiplier;
|
||||
case Roles::MkcpMaxSendingWindowRole: return mkcp.maxSendingWindow;
|
||||
|
||||
// ── xPadding ──────────────────────────────────────────────────────
|
||||
case Roles::XPaddingBytesMinRole: return pad.bytesMin;
|
||||
@@ -274,11 +279,18 @@ void XrayConfigModel::updateModel(amnezia::DockerContainer container, const amne
|
||||
|
||||
if (!m_protocolConfig.serverConfig.isThirdPartyConfig) {
|
||||
applyDefaultsToServerConfig(m_protocolConfig.serverConfig, false);
|
||||
if (m_protocolConfig.clientTemplate.fingerprint.isEmpty()) {
|
||||
m_protocolConfig.clientTemplate.fingerprint = protocols::xray::defaultFingerprint;
|
||||
}
|
||||
if (m_protocolConfig.clientTemplate.uplinkMethod.isEmpty()) {
|
||||
m_protocolConfig.clientTemplate.uplinkMethod = protocols::xray::defaultXhttpUplinkMethod;
|
||||
}
|
||||
}
|
||||
|
||||
m_originalProtocolConfig = m_protocolConfig;
|
||||
|
||||
endResetModel();
|
||||
|
||||
if (wasUnsavedChanges != hasUnsavedChanges()) {
|
||||
emit hasUnsavedChangesChanged();
|
||||
}
|
||||
@@ -286,88 +298,54 @@ void XrayConfigModel::updateModel(amnezia::DockerContainer container, const amne
|
||||
|
||||
void XrayConfigModel::applyDefaultsToServerConfig(amnezia::XrayServerConfig &config, bool fillFlowDefault)
|
||||
{
|
||||
if (config.port.isEmpty()) {
|
||||
config.port = protocols::xray::defaultPort;
|
||||
}
|
||||
|
||||
if (config.transportProto.isEmpty()) {
|
||||
config.transportProto = ProtocolUtils::transportProtoToString(
|
||||
ProtocolUtils::defaultTransportProto(amnezia::Proto::Xray), amnezia::Proto::Xray);
|
||||
}
|
||||
|
||||
if (config.site.isEmpty()) {
|
||||
config.site = protocols::xray::defaultSite;
|
||||
}
|
||||
|
||||
if (config.transport.isEmpty()) {
|
||||
config.transport = protocols::xray::defaultTransport;
|
||||
}
|
||||
|
||||
if (config.security.isEmpty()) {
|
||||
config.security = protocols::xray::defaultSecurity;
|
||||
}
|
||||
|
||||
if (fillFlowDefault && config.flow.isEmpty()) {
|
||||
config.flow = protocols::xray::defaultFlow;
|
||||
}
|
||||
|
||||
if (config.fingerprint.isEmpty()) {
|
||||
config.fingerprint = protocols::xray::defaultFingerprint;
|
||||
} else if (config.fingerprint.contains(QLatin1String("Mozilla/5.0"), Qt::CaseInsensitive)) {
|
||||
config.fingerprint = QString::fromLatin1(protocols::xray::defaultFingerprint);
|
||||
}
|
||||
|
||||
if (config.sni.isEmpty()) {
|
||||
config.sni = protocols::xray::defaultSni;
|
||||
}
|
||||
|
||||
if (config.alpn.isEmpty()) {
|
||||
config.alpn = protocols::xray::defaultAlpn;
|
||||
}
|
||||
|
||||
// XHTTP transport defaults
|
||||
if (config.xhttp.host.isEmpty()) {
|
||||
config.xhttp.host = protocols::xray::defaultXhttpHost;
|
||||
}
|
||||
if (config.xhttp.mode.isEmpty()) {
|
||||
config.xhttp.mode = protocols::xray::defaultXhttpMode;
|
||||
}
|
||||
if (config.xhttp.uplinkMethod.isEmpty()) {
|
||||
config.xhttp.uplinkMethod = protocols::xray::defaultXhttpUplinkMethod;
|
||||
}
|
||||
if (config.xhttp.sessionPlacement.isEmpty()) {
|
||||
config.xhttp.sessionPlacement = protocols::xray::defaultXhttpSessionPlacement;
|
||||
}
|
||||
if (config.xhttp.sessionKey.isEmpty()) {
|
||||
config.xhttp.sessionKey = protocols::xray::defaultXhttpSessionKey;
|
||||
}
|
||||
if (config.xhttp.seqPlacement.isEmpty()) {
|
||||
config.xhttp.seqPlacement = protocols::xray::defaultXhttpSeqPlacement;
|
||||
}
|
||||
if (config.xhttp.uplinkDataPlacement.isEmpty()) {
|
||||
config.xhttp.uplinkDataPlacement = protocols::xray::defaultXhttpUplinkDataPlacement;
|
||||
}
|
||||
|
||||
// xPadding defaults
|
||||
if (config.xhttp.xPadding.placement.isEmpty()) {
|
||||
config.xhttp.xPadding.placement = protocols::xray::defaultXPaddingPlacement;
|
||||
}
|
||||
if (config.xhttp.xPadding.method.isEmpty()) {
|
||||
config.xhttp.xPadding.method = protocols::xray::defaultXPaddingMethod;
|
||||
}
|
||||
config.applyDefaults(fillFlowDefault);
|
||||
}
|
||||
|
||||
amnezia::XrayProtocolConfig XrayConfigModel::getProtocolConfig()
|
||||
{
|
||||
const bool serverSettingsChanged =
|
||||
!m_protocolConfig.serverConfig.hasEqualServerSettings(m_originalProtocolConfig.serverConfig);
|
||||
const bool clientTemplateChanged =
|
||||
m_protocolConfig.clientTemplate.contentFingerprint()
|
||||
!= m_originalProtocolConfig.clientTemplate.contentFingerprint();
|
||||
|
||||
if (serverSettingsChanged) {
|
||||
// A client-only edit (fingerprint, xmux and the rest of the template) no longer applies through a
|
||||
// local rebuild. Like every other protocol, the cached client config is dropped here, and the normal
|
||||
// mechanism rebuilds it through createConfig on the next connect, picking up the new template.
|
||||
if (serverSettingsChanged || clientTemplateChanged) {
|
||||
m_protocolConfig.clearClientConfig();
|
||||
}
|
||||
return m_protocolConfig;
|
||||
}
|
||||
|
||||
amnezia::XrayServerConfig XrayConfigModel::pendingServerConfig(const QString &pendingPort) const
|
||||
{
|
||||
amnezia::XrayServerConfig pending = m_protocolConfig.serverConfig;
|
||||
if (!pendingPort.isEmpty()) {
|
||||
pending.port = pendingPort;
|
||||
}
|
||||
return pending;
|
||||
}
|
||||
|
||||
bool XrayConfigModel::pendingChangeTouchesServer(const QString &pendingPort) const
|
||||
{
|
||||
return !pendingServerConfig(pendingPort).hasEqualServerSettings(m_originalProtocolConfig.serverConfig);
|
||||
}
|
||||
|
||||
bool XrayConfigModel::pendingChangeBreaksIssuedConfigs(const QString &pendingPort) const
|
||||
{
|
||||
return pendingServerConfig(pendingPort).breaksIssuedConfigs(m_originalProtocolConfig.serverConfig);
|
||||
}
|
||||
|
||||
bool XrayConfigModel::pendingChangeRequiresReinstall(const QString &pendingPort) const
|
||||
{
|
||||
const auto effectivePort = [](const QString &port) -> QString {
|
||||
return port.isEmpty() ? QString::fromLatin1(protocols::xray::defaultPort) : port;
|
||||
};
|
||||
const amnezia::XrayServerConfig pending = pendingServerConfig(pendingPort);
|
||||
return effectivePort(pending.port) != effectivePort(m_originalProtocolConfig.serverConfig.port);
|
||||
}
|
||||
|
||||
bool XrayConfigModel::isServerSettingsEqual() const
|
||||
{
|
||||
return m_protocolConfig.serverConfig.hasEqualServerSettings(m_originalProtocolConfig.serverConfig);
|
||||
@@ -375,7 +353,8 @@ bool XrayConfigModel::isServerSettingsEqual() const
|
||||
|
||||
bool XrayConfigModel::hasUnsavedChanges() const
|
||||
{
|
||||
return !isServerSettingsEqual();
|
||||
return m_protocolConfig.serverConfig.toJson() != m_originalProtocolConfig.serverConfig.toJson()
|
||||
|| m_protocolConfig.clientTemplate.toJson() != m_originalProtocolConfig.clientTemplate.toJson();
|
||||
}
|
||||
|
||||
QHash<int, QByteArray> XrayConfigModel::roleNames() const
|
||||
@@ -422,9 +401,9 @@ QHash<int, QByteArray> XrayConfigModel::roleNames() const
|
||||
roles[MkcpTtiRole] = "mkcpTti";
|
||||
roles[MkcpUplinkCapacityRole] = "mkcpUplinkCapacity";
|
||||
roles[MkcpDownlinkCapacityRole] = "mkcpDownlinkCapacity";
|
||||
roles[MkcpReadBufferSizeRole] = "mkcpReadBufferSize";
|
||||
roles[MkcpWriteBufferSizeRole] = "mkcpWriteBufferSize";
|
||||
roles[MkcpCongestionRole] = "mkcpCongestion";
|
||||
roles[MkcpMtuRole] = "mkcpMtu";
|
||||
roles[MkcpCwndMultiplierRole] = "mkcpCwndMultiplier";
|
||||
roles[MkcpMaxSendingWindowRole] = "mkcpMaxSendingWindow";
|
||||
|
||||
// xPadding
|
||||
roles[XPaddingBytesMinRole] = "xPaddingBytesMin";
|
||||
@@ -459,23 +438,35 @@ void XrayConfigModel::resetToDefaults()
|
||||
beginResetModel();
|
||||
m_protocolConfig.serverConfig = amnezia::XrayServerConfig{};
|
||||
applyDefaultsToServerConfig(m_protocolConfig.serverConfig);
|
||||
m_protocolConfig.clientTemplate = amnezia::XrayClientTemplate{};
|
||||
m_protocolConfig.clientTemplate.formatVersion = 1;
|
||||
endResetModel();
|
||||
|
||||
|
||||
if (wasUnsavedChanges != hasUnsavedChanges()) {
|
||||
emit hasUnsavedChangesChanged();
|
||||
}
|
||||
}
|
||||
|
||||
void XrayConfigModel::applyServerConfig(const amnezia::XrayServerConfig &serverConfig)
|
||||
void XrayConfigModel::applyServerConfig(const amnezia::XrayServerConfig &serverConfig,
|
||||
const amnezia::XrayClientTemplate &clientTemplate)
|
||||
{
|
||||
const bool wasUnsavedChanges = hasUnsavedChanges();
|
||||
|
||||
beginResetModel();
|
||||
m_protocolConfig.serverConfig = serverConfig;
|
||||
m_protocolConfig.clientTemplate = clientTemplate;
|
||||
if (m_protocolConfig.clientTemplate.formatVersion == 0) {
|
||||
m_protocolConfig.clientTemplate.formatVersion = 1;
|
||||
}
|
||||
if (!m_protocolConfig.serverConfig.isThirdPartyConfig) {
|
||||
m_protocolConfig.serverConfig.applyDefaults(false);
|
||||
}
|
||||
// Clear client config since server settings changed
|
||||
m_protocolConfig.clearClientConfig();
|
||||
endResetModel();
|
||||
|
||||
|
||||
if (wasUnsavedChanges != hasUnsavedChanges()) {
|
||||
emit hasUnsavedChangesChanged();
|
||||
}
|
||||
@@ -512,7 +503,7 @@ QStringList XrayConfigModel::alpnOptions()
|
||||
|
||||
QStringList XrayConfigModel::xhttpModeOptions()
|
||||
{
|
||||
return { "Auto", "Packet-up", "Stream-up", "Stream-one" };
|
||||
return { "Stream-up", "Stream-one" };
|
||||
}
|
||||
|
||||
QStringList XrayConfigModel::xhttpUplinkMethodOptions()
|
||||
@@ -532,8 +523,7 @@ QStringList XrayConfigModel::xhttpSeqPlacementOptions()
|
||||
|
||||
QStringList XrayConfigModel::xhttpUplinkDataPlacementOptions()
|
||||
{
|
||||
// Matches splithttp uplink payload placement (packet-up / advanced)
|
||||
return { "Body", "Auto", "Header", "Cookie" };
|
||||
return { "Body", "Auto" };
|
||||
}
|
||||
|
||||
QStringList XrayConfigModel::xPaddingPlacementOptions()
|
||||
@@ -562,14 +552,14 @@ QString XrayConfigModel::mkcpDefaultDownlinkCapacity()
|
||||
return QString::fromLatin1(protocols::xray::defaultMkcpDownlinkCapacity);
|
||||
}
|
||||
|
||||
QString XrayConfigModel::mkcpDefaultReadBufferSize()
|
||||
QString XrayConfigModel::mkcpDefaultMtu()
|
||||
{
|
||||
return QString::fromLatin1(protocols::xray::defaultMkcpReadBufferSize);
|
||||
return QString::fromLatin1(protocols::xray::defaultMkcpMtu);
|
||||
}
|
||||
|
||||
QString XrayConfigModel::mkcpDefaultWriteBufferSize()
|
||||
QString XrayConfigModel::mkcpDefaultCwndMultiplier()
|
||||
{
|
||||
return QString::fromLatin1(protocols::xray::defaultMkcpWriteBufferSize);
|
||||
return QString::fromLatin1(protocols::xray::defaultMkcpCwndMultiplier);
|
||||
}
|
||||
|
||||
QString XrayConfigModel::portDefault()
|
||||
|
||||
@@ -57,11 +57,11 @@ public:
|
||||
|
||||
// ── Transport — mKCP ──────────────────────────────────────────
|
||||
MkcpTtiRole,
|
||||
MkcpMtuRole,
|
||||
MkcpUplinkCapacityRole,
|
||||
MkcpDownlinkCapacityRole,
|
||||
MkcpReadBufferSizeRole,
|
||||
MkcpWriteBufferSizeRole,
|
||||
MkcpCongestionRole,
|
||||
MkcpCwndMultiplierRole,
|
||||
MkcpMaxSendingWindowRole,
|
||||
|
||||
// ── xPadding ──────────────────────────────────────────────────
|
||||
XPaddingBytesMinRole,
|
||||
@@ -112,8 +112,8 @@ public:
|
||||
Q_INVOKABLE static QString mkcpDefaultTti();
|
||||
Q_INVOKABLE static QString mkcpDefaultUplinkCapacity();
|
||||
Q_INVOKABLE static QString mkcpDefaultDownlinkCapacity();
|
||||
Q_INVOKABLE static QString mkcpDefaultReadBufferSize();
|
||||
Q_INVOKABLE static QString mkcpDefaultWriteBufferSize();
|
||||
Q_INVOKABLE static QString mkcpDefaultMtu();
|
||||
Q_INVOKABLE static QString mkcpDefaultCwndMultiplier();
|
||||
|
||||
Q_INVOKABLE static QString portDefault();
|
||||
Q_INVOKABLE static QString sniDefault();
|
||||
@@ -135,13 +135,20 @@ public:
|
||||
Q_INVOKABLE static bool isValidPath(const QString &path);
|
||||
Q_INVOKABLE QStringList validationErrors() const;
|
||||
|
||||
Q_INVOKABLE bool pendingChangeTouchesServer(const QString &pendingPort) const;
|
||||
Q_INVOKABLE bool pendingChangeBreaksIssuedConfigs(const QString &pendingPort) const;
|
||||
Q_INVOKABLE bool pendingChangeRequiresReinstall(const QString &pendingPort) const;
|
||||
|
||||
public slots:
|
||||
void updateModel(amnezia::DockerContainer container, const amnezia::XrayProtocolConfig& protocolConfig);
|
||||
amnezia::XrayProtocolConfig getProtocolConfig();
|
||||
amnezia::XrayServerConfig pendingServerConfig(const QString &pendingPort) const;
|
||||
|
||||
bool isServerSettingsEqual() const;
|
||||
bool hasUnsavedChanges() const;
|
||||
void resetToDefaults();
|
||||
void applyServerConfig(const amnezia::XrayServerConfig &serverConfig);
|
||||
void applyServerConfig(const amnezia::XrayServerConfig &serverConfig,
|
||||
const amnezia::XrayClientTemplate &clientTemplate);
|
||||
|
||||
signals:
|
||||
void hasUnsavedChangesChanged();
|
||||
|
||||
@@ -13,6 +13,7 @@ QJsonObject XrayConfigSnapshot::toJson() const
|
||||
obj["displayName"] = displayName;
|
||||
obj["createdAt"] = createdAt.toString(Qt::ISODate);
|
||||
obj["serverConfig"] = serverConfig.toJson();
|
||||
obj["clientTemplate"] = clientTemplate.toJson();
|
||||
return obj;
|
||||
}
|
||||
|
||||
@@ -23,6 +24,11 @@ XrayConfigSnapshot XrayConfigSnapshot::fromJson(const QJsonObject &json)
|
||||
s.displayName = json.value("displayName").toString();
|
||||
s.createdAt = QDateTime::fromString(json.value("createdAt").toString(), Qt::ISODate);
|
||||
s.serverConfig = amnezia::XrayServerConfig::fromJson(json.value("serverConfig").toObject());
|
||||
if (json.contains("clientTemplate")) {
|
||||
s.clientTemplate = amnezia::XrayClientTemplate::fromJson(json.value("clientTemplate").toObject());
|
||||
} else {
|
||||
s.clientTemplate.materializeFromLegacy(json.value("serverConfig").toObject());
|
||||
}
|
||||
return s;
|
||||
}
|
||||
|
||||
@@ -100,13 +106,15 @@ void XrayConfigSnapshotsModel::reload()
|
||||
endResetModel();
|
||||
}
|
||||
|
||||
void XrayConfigSnapshotsModel::createFromCurrent(const amnezia::XrayServerConfig &serverConfig)
|
||||
void XrayConfigSnapshotsModel::createFromCurrent(const amnezia::XrayServerConfig &serverConfig,
|
||||
const amnezia::XrayClientTemplate &clientTemplate)
|
||||
{
|
||||
XrayConfigSnapshot snapshot;
|
||||
snapshot.id = QUuid::createUuid().toString(QUuid::WithoutBraces);
|
||||
snapshot.displayName = buildDisplayName(serverConfig);
|
||||
snapshot.createdAt = QDateTime::currentDateTime();
|
||||
snapshot.serverConfig = serverConfig;
|
||||
snapshot.clientTemplate = clientTemplate;
|
||||
|
||||
beginInsertRows(QModelIndex(), m_configs.size(), m_configs.size());
|
||||
m_configs.append(snapshot);
|
||||
@@ -200,7 +208,8 @@ void XrayConfigSnapshotsModel::createFromCurrentModel()
|
||||
if (!m_xrayConfigModel) {
|
||||
return;
|
||||
}
|
||||
createFromCurrent(m_xrayConfigModel->getProtocolConfig().serverConfig);
|
||||
const amnezia::XrayProtocolConfig current = m_xrayConfigModel->getProtocolConfig();
|
||||
createFromCurrent(current.serverConfig, current.clientTemplate);
|
||||
}
|
||||
|
||||
void XrayConfigSnapshotsModel::applyConfigToCurrentModel(int index)
|
||||
@@ -208,9 +217,12 @@ void XrayConfigSnapshotsModel::applyConfigToCurrentModel(int index)
|
||||
if (!m_xrayConfigModel) {
|
||||
return;
|
||||
}
|
||||
amnezia::XrayServerConfig cfg = applyConfig(index);
|
||||
if (cfg.port.isEmpty()) {
|
||||
return; // guard against invalid index
|
||||
if (index < 0 || index >= m_configs.size()) {
|
||||
return;
|
||||
}
|
||||
m_xrayConfigModel->applyServerConfig(cfg);
|
||||
const XrayConfigSnapshot &snapshot = m_configs.at(index);
|
||||
if (snapshot.serverConfig.port.isEmpty()) {
|
||||
return;
|
||||
}
|
||||
m_xrayConfigModel->applyServerConfig(snapshot.serverConfig, snapshot.clientTemplate);
|
||||
}
|
||||
|
||||
@@ -19,6 +19,7 @@ struct XrayConfigSnapshot
|
||||
QString displayName; // auto-generated: "XHTTP TLS Reality", "RAW Reality", etc.
|
||||
QDateTime createdAt;
|
||||
amnezia::XrayServerConfig serverConfig;
|
||||
amnezia::XrayClientTemplate clientTemplate;
|
||||
|
||||
QJsonObject toJson() const;
|
||||
static XrayConfigSnapshot fromJson(const QJsonObject &json);
|
||||
@@ -44,7 +45,8 @@ public:
|
||||
public slots:
|
||||
void reload();
|
||||
|
||||
Q_INVOKABLE void createFromCurrent(const amnezia::XrayServerConfig &serverConfig);
|
||||
Q_INVOKABLE void createFromCurrent(const amnezia::XrayServerConfig &serverConfig,
|
||||
const amnezia::XrayClientTemplate &clientTemplate = {});
|
||||
Q_INVOKABLE amnezia::XrayServerConfig applyConfig(int index) const;
|
||||
Q_INVOKABLE void removeConfig(int index);
|
||||
|
||||
|
||||
@@ -79,6 +79,7 @@ PageType {
|
||||
Layout.leftMargin: 16
|
||||
Layout.rightMargin: 16
|
||||
text: "xtls-rprx-vision-udp443"
|
||||
descriptionText: qsTr("For apps that require QUIC. Browsers may stop loading.")
|
||||
enabled: visionAllowed
|
||||
checked: flow === "xtls-rprx-vision-udp443" && visionAllowed
|
||||
onClicked: flow = "xtls-rprx-vision-udp443"
|
||||
@@ -118,7 +119,25 @@ PageType {
|
||||
text: qsTr("Save")
|
||||
clickedFunc: function () {
|
||||
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 touchesServer = XrayConfigModel.pendingChangeTouchesServer("")
|
||||
var breaksIssued = XrayConfigModel.pendingChangeBreaksIssuedConfigs("")
|
||||
var requiresReinstall = XrayConfigModel.pendingChangeRequiresReinstall("")
|
||||
var descriptionText
|
||||
if (requiresReinstall) {
|
||||
if (breaksIssued) {
|
||||
descriptionText = qsTr("All users with whom you shared a connection with will no longer be able to connect to it. You will need to share the connection again.")
|
||||
} else {
|
||||
descriptionText = qsTr("The server will be recreated. This takes up to a minute, and connections that were already shared keep working.")
|
||||
}
|
||||
} else if (touchesServer) {
|
||||
if (breaksIssued) {
|
||||
descriptionText = qsTr("The server configuration will be updated. All users with whom you shared a connection with will no longer be able to connect to it. You will need to share the connection again.")
|
||||
} else {
|
||||
descriptionText = qsTr("The server configuration will be updated. The container will not be recreated.")
|
||||
}
|
||||
} else {
|
||||
descriptionText = qsTr("The server will not be changed now. The new settings apply the next time you connect.")
|
||||
}
|
||||
var yesButtonText = qsTr("Continue")
|
||||
var noButtonText = qsTr("Cancel")
|
||||
var yesButtonFunction = function () {
|
||||
|
||||
@@ -307,13 +307,32 @@ PageType {
|
||||
enabled: visible
|
||||
text: qsTr("Save")
|
||||
clickedFunc: function () {
|
||||
saveButton.forceActiveFocus()
|
||||
var errs = XrayConfigModel.validationErrors()
|
||||
if (errs.length > 0) {
|
||||
PageController.showErrorMessage(errs.join("\n"))
|
||||
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 touchesServer = XrayConfigModel.pendingChangeTouchesServer("")
|
||||
var breaksIssued = XrayConfigModel.pendingChangeBreaksIssuedConfigs("")
|
||||
var requiresReinstall = XrayConfigModel.pendingChangeRequiresReinstall("")
|
||||
var descriptionText
|
||||
if (requiresReinstall) {
|
||||
if (breaksIssued) {
|
||||
descriptionText = qsTr("All users with whom you shared a connection with will no longer be able to connect to it. You will need to share the connection again.")
|
||||
} else {
|
||||
descriptionText = qsTr("The server will be recreated. This takes up to a minute, and connections that were already shared keep working.")
|
||||
}
|
||||
} else if (touchesServer) {
|
||||
if (breaksIssued) {
|
||||
descriptionText = qsTr("The server configuration will be updated. All users with whom you shared a connection with will no longer be able to connect to it. You will need to share the connection again.")
|
||||
} else {
|
||||
descriptionText = qsTr("The server configuration will be updated. The container will not be recreated.")
|
||||
}
|
||||
} else {
|
||||
descriptionText = qsTr("The server will not be changed now. The new settings apply the next time you connect.")
|
||||
}
|
||||
var yesButtonText = qsTr("Continue")
|
||||
var noButtonText = qsTr("Cancel")
|
||||
var yesButtonFunction = function () {
|
||||
|
||||
@@ -219,8 +219,28 @@ PageType {
|
||||
PageController.showErrorMessage(errs.join("\n"))
|
||||
return
|
||||
}
|
||||
var pendingPort = textFieldWithHeaderType.textField.text
|
||||
var touchesServer = XrayConfigModel.pendingChangeTouchesServer(pendingPort)
|
||||
var breaksIssued = XrayConfigModel.pendingChangeBreaksIssuedConfigs(pendingPort)
|
||||
var requiresReinstall = XrayConfigModel.pendingChangeRequiresReinstall(pendingPort)
|
||||
|
||||
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 descriptionText
|
||||
if (requiresReinstall) {
|
||||
if (breaksIssued) {
|
||||
descriptionText = qsTr("All users with whom you shared a connection with will no longer be able to connect to it. You will need to share the connection again.")
|
||||
} else {
|
||||
descriptionText = qsTr("The server will be recreated. This takes up to a minute, and connections that were already shared keep working.")
|
||||
}
|
||||
} else if (touchesServer) {
|
||||
if (breaksIssued) {
|
||||
descriptionText = qsTr("The server configuration will be updated. All users with whom you shared a connection with will no longer be able to connect to it. You will need to share the connection again.")
|
||||
} else {
|
||||
descriptionText = qsTr("The server configuration will be updated. The container will not be recreated.")
|
||||
}
|
||||
} else {
|
||||
descriptionText = qsTr("The server will not be changed now. The new settings apply the next time you connect.")
|
||||
}
|
||||
var yesButtonText = qsTr("Continue")
|
||||
var noButtonText = qsTr("Cancel")
|
||||
var yesButtonFunction = function() {
|
||||
|
||||
@@ -182,16 +182,42 @@ PageType {
|
||||
Layout.leftMargin: 16
|
||||
Layout.rightMargin: 16
|
||||
Layout.topMargin: 8
|
||||
headerText: qsTr("readBufferSize")
|
||||
hintText: qsTr("Read buffer size (MB). Range: 1–2147483647.")
|
||||
placeholderText: XrayConfigModel.mkcpDefaultReadBufferSize()
|
||||
textField.text: mkcpReadBufferSize
|
||||
headerText: qsTr("mtu")
|
||||
hintText: qsTr("Maximum packet size in bytes. Range: 576–1460.")
|
||||
placeholderText: XrayConfigModel.mkcpDefaultMtu()
|
||||
textField.text: mkcpMtu
|
||||
textField.maximumLength: 4
|
||||
textField.validator: RegularExpressionValidator { regularExpression: /^\d*$/ }
|
||||
textField.onTextEdited: root.editDirty = (textField.text !== mkcpMtu)
|
||||
textField.onEditingFinished: {
|
||||
var v = root.clampInt(textField.text, 576, 1460)
|
||||
if (v !== mkcpMtu) mkcpMtu = v
|
||||
else if (textField.text !== v) textField.text = v
|
||||
if (mkcpMaxSendingWindow !== "") {
|
||||
var floorNow = parseInt(v !== "" ? v : XrayConfigModel.mkcpDefaultMtu(), 10)
|
||||
if (parseInt(mkcpMaxSendingWindow, 10) < floorNow) {
|
||||
mkcpMaxSendingWindow = String(floorNow)
|
||||
}
|
||||
}
|
||||
root.editDirty = false
|
||||
}
|
||||
}
|
||||
|
||||
TextFieldWithHeaderType {
|
||||
Layout.fillWidth: true
|
||||
Layout.leftMargin: 16
|
||||
Layout.rightMargin: 16
|
||||
Layout.topMargin: 8
|
||||
headerText: qsTr("cwndMultiplier")
|
||||
hintText: qsTr("Congestion window multiplier. Minimum: 1.")
|
||||
placeholderText: XrayConfigModel.mkcpDefaultCwndMultiplier()
|
||||
textField.text: mkcpCwndMultiplier
|
||||
textField.maximumLength: 10
|
||||
textField.validator: RegularExpressionValidator { regularExpression: /^\d*$/ }
|
||||
textField.onTextEdited: root.editDirty = (textField.text !== mkcpReadBufferSize)
|
||||
textField.onTextEdited: root.editDirty = (textField.text !== mkcpCwndMultiplier)
|
||||
textField.onEditingFinished: {
|
||||
var v = root.clampInt(textField.text, 1, 2147483647)
|
||||
if (v !== mkcpReadBufferSize) mkcpReadBufferSize = v
|
||||
if (v !== mkcpCwndMultiplier) mkcpCwndMultiplier = v
|
||||
else if (textField.text !== v) textField.text = v
|
||||
root.editDirty = false
|
||||
}
|
||||
@@ -202,29 +228,20 @@ PageType {
|
||||
Layout.leftMargin: 16
|
||||
Layout.rightMargin: 16
|
||||
Layout.topMargin: 8
|
||||
headerText: qsTr("writeBufferSize")
|
||||
hintText: qsTr("Write buffer size (MB). Range: 1–2147483647.")
|
||||
placeholderText: XrayConfigModel.mkcpDefaultWriteBufferSize()
|
||||
textField.text: mkcpWriteBufferSize
|
||||
headerText: qsTr("maxSendingWindow")
|
||||
hintText: qsTr("Send window in bytes. Must not be smaller than mtu. Leave empty to let Xray decide.")
|
||||
textField.text: mkcpMaxSendingWindow
|
||||
textField.maximumLength: 10
|
||||
textField.validator: RegularExpressionValidator { regularExpression: /^\d*$/ }
|
||||
textField.onTextEdited: root.editDirty = (textField.text !== mkcpWriteBufferSize)
|
||||
textField.onTextEdited: root.editDirty = (textField.text !== mkcpMaxSendingWindow)
|
||||
textField.onEditingFinished: {
|
||||
var v = root.clampInt(textField.text, 1, 2147483647)
|
||||
if (v !== mkcpWriteBufferSize) mkcpWriteBufferSize = v
|
||||
var mtuFloor = parseInt(mkcpMtu !== "" ? mkcpMtu : XrayConfigModel.mkcpDefaultMtu(), 10)
|
||||
var v = root.clampInt(textField.text, mtuFloor, 2147483647)
|
||||
if (v !== mkcpMaxSendingWindow) mkcpMaxSendingWindow = v
|
||||
else if (textField.text !== v) textField.text = v
|
||||
root.editDirty = false
|
||||
}
|
||||
}
|
||||
|
||||
SwitcherType {
|
||||
Layout.fillWidth: true
|
||||
Layout.margins: 16
|
||||
Layout.topMargin: 8
|
||||
text: qsTr("Congestion")
|
||||
checked: mkcpCongestion
|
||||
onToggled: mkcpCongestion = checked
|
||||
}
|
||||
}
|
||||
|
||||
// ══════════════════════════════════════════════════════════
|
||||
@@ -542,7 +559,7 @@ PageType {
|
||||
Layout.leftMargin: 16
|
||||
Layout.rightMargin: 16
|
||||
text: xhttpUplinkDataPlacement
|
||||
descriptionText: qsTr("Header/Cookie apply only in Packet-up mode")
|
||||
descriptionText: qsTr("Where the uploaded data is carried in the request")
|
||||
headerText: qsTr("UplinkDataPlacement")
|
||||
drawerParent: root
|
||||
listView: ListViewWithRadioButtonType {
|
||||
@@ -769,13 +786,32 @@ PageType {
|
||||
enabled: visible
|
||||
text: qsTr("Save")
|
||||
clickedFunc: function () {
|
||||
saveButton.forceActiveFocus()
|
||||
var errs = XrayConfigModel.validationErrors()
|
||||
if (errs.length > 0) {
|
||||
PageController.showErrorMessage(errs.join("\n"))
|
||||
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 touchesServer = XrayConfigModel.pendingChangeTouchesServer("")
|
||||
var breaksIssued = XrayConfigModel.pendingChangeBreaksIssuedConfigs("")
|
||||
var requiresReinstall = XrayConfigModel.pendingChangeRequiresReinstall("")
|
||||
var descriptionText
|
||||
if (requiresReinstall) {
|
||||
if (breaksIssued) {
|
||||
descriptionText = qsTr("All users with whom you shared a connection with will no longer be able to connect to it. You will need to share the connection again.")
|
||||
} else {
|
||||
descriptionText = qsTr("The server will be recreated. This takes up to a minute, and connections that were already shared keep working.")
|
||||
}
|
||||
} else if (touchesServer) {
|
||||
if (breaksIssued) {
|
||||
descriptionText = qsTr("The server configuration will be updated. All users with whom you shared a connection with will no longer be able to connect to it. You will need to share the connection again.")
|
||||
} else {
|
||||
descriptionText = qsTr("The server configuration will be updated. The container will not be recreated.")
|
||||
}
|
||||
} else {
|
||||
descriptionText = qsTr("The server will not be changed now. The new settings apply the next time you connect.")
|
||||
}
|
||||
var yesButtonText = qsTr("Continue")
|
||||
var noButtonText = qsTr("Cancel")
|
||||
var yesButtonFunction = function () {
|
||||
|
||||
@@ -90,8 +90,27 @@ PageType {
|
||||
enabled: visible
|
||||
text: qsTr("Save")
|
||||
clickedFunc: function () {
|
||||
saveButton.forceActiveFocus()
|
||||
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 touchesServer = XrayConfigModel.pendingChangeTouchesServer("")
|
||||
var breaksIssued = XrayConfigModel.pendingChangeBreaksIssuedConfigs("")
|
||||
var requiresReinstall = XrayConfigModel.pendingChangeRequiresReinstall("")
|
||||
var descriptionText
|
||||
if (requiresReinstall) {
|
||||
if (breaksIssued) {
|
||||
descriptionText = qsTr("All users with whom you shared a connection with will no longer be able to connect to it. You will need to share the connection again.")
|
||||
} else {
|
||||
descriptionText = qsTr("The server will be recreated. This takes up to a minute, and connections that were already shared keep working.")
|
||||
}
|
||||
} else if (touchesServer) {
|
||||
if (breaksIssued) {
|
||||
descriptionText = qsTr("The server configuration will be updated. All users with whom you shared a connection with will no longer be able to connect to it. You will need to share the connection again.")
|
||||
} else {
|
||||
descriptionText = qsTr("The server configuration will be updated. The container will not be recreated.")
|
||||
}
|
||||
} else {
|
||||
descriptionText = qsTr("The server will not be changed now. The new settings apply the next time you connect.")
|
||||
}
|
||||
var yesButtonText = qsTr("Continue")
|
||||
var noButtonText = qsTr("Cancel")
|
||||
var yesButtonFunction = function () {
|
||||
|
||||
@@ -219,8 +219,27 @@ PageType {
|
||||
enabled: visible
|
||||
text: qsTr("Save")
|
||||
clickedFunc: function () {
|
||||
saveButton.forceActiveFocus()
|
||||
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 touchesServer = XrayConfigModel.pendingChangeTouchesServer("")
|
||||
var breaksIssued = XrayConfigModel.pendingChangeBreaksIssuedConfigs("")
|
||||
var requiresReinstall = XrayConfigModel.pendingChangeRequiresReinstall("")
|
||||
var descriptionText
|
||||
if (requiresReinstall) {
|
||||
if (breaksIssued) {
|
||||
descriptionText = qsTr("All users with whom you shared a connection with will no longer be able to connect to it. You will need to share the connection again.")
|
||||
} else {
|
||||
descriptionText = qsTr("The server will be recreated. This takes up to a minute, and connections that were already shared keep working.")
|
||||
}
|
||||
} else if (touchesServer) {
|
||||
if (breaksIssued) {
|
||||
descriptionText = qsTr("The server configuration will be updated. All users with whom you shared a connection with will no longer be able to connect to it. You will need to share the connection again.")
|
||||
} else {
|
||||
descriptionText = qsTr("The server configuration will be updated. The container will not be recreated.")
|
||||
}
|
||||
} else {
|
||||
descriptionText = qsTr("The server will not be changed now. The new settings apply the next time you connect.")
|
||||
}
|
||||
var yesButtonText = qsTr("Continue")
|
||||
var noButtonText = qsTr("Cancel")
|
||||
var yesButtonFunction = function () {
|
||||
|
||||
@@ -232,8 +232,27 @@ PageType {
|
||||
enabled: visible
|
||||
text: qsTr("Save")
|
||||
clickedFunc: function () {
|
||||
saveButton.forceActiveFocus()
|
||||
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 touchesServer = XrayConfigModel.pendingChangeTouchesServer("")
|
||||
var breaksIssued = XrayConfigModel.pendingChangeBreaksIssuedConfigs("")
|
||||
var requiresReinstall = XrayConfigModel.pendingChangeRequiresReinstall("")
|
||||
var descriptionText
|
||||
if (requiresReinstall) {
|
||||
if (breaksIssued) {
|
||||
descriptionText = qsTr("All users with whom you shared a connection with will no longer be able to connect to it. You will need to share the connection again.")
|
||||
} else {
|
||||
descriptionText = qsTr("The server will be recreated. This takes up to a minute, and connections that were already shared keep working.")
|
||||
}
|
||||
} else if (touchesServer) {
|
||||
if (breaksIssued) {
|
||||
descriptionText = qsTr("The server configuration will be updated. All users with whom you shared a connection with will no longer be able to connect to it. You will need to share the connection again.")
|
||||
} else {
|
||||
descriptionText = qsTr("The server configuration will be updated. The container will not be recreated.")
|
||||
}
|
||||
} else {
|
||||
descriptionText = qsTr("The server will not be changed now. The new settings apply the next time you connect.")
|
||||
}
|
||||
var yesButtonText = qsTr("Continue")
|
||||
var noButtonText = qsTr("Cancel")
|
||||
var yesButtonFunction = function () {
|
||||
|
||||
Reference in New Issue
Block a user