Files
EZ4Connect/infrastructure/coreprocess/corecommandbuilder.cpp
2026-08-25 02:25:29 +08:00

247 lines
7.4 KiB
C++

#include "corecommandbuilder.h"
namespace
{
QString quoteArgumentForLog(const QString &argument)
{
bool requiresQuotes = argument.isEmpty();
for (const QChar character : argument)
{
if (character.isSpace() || character == '"')
{
requiresQuotes = true;
break;
}
}
if (!requiresQuotes)
{
return argument;
}
QString quoted;
quoted.reserve(argument.size() + 2);
quoted += '"';
for (const QChar character : argument)
{
switch (character.unicode())
{
case '\\':
quoted += "\\\\";
break;
case '"':
quoted += "\\\"";
break;
case '\n':
quoted += "\\n";
break;
case '\r':
quoted += "\\r";
break;
case '\t':
quoted += "\\t";
break;
default:
quoted += character;
break;
}
}
quoted += '"';
return quoted;
}
void appendOption(QStringList &arguments, const QString &name, const QString &value)
{
if (!value.isEmpty())
{
arguments << name << value;
}
}
QString environmentVariableName(const QString &option)
{
QString name = option;
while (name.startsWith('-'))
{
name.remove(0, 1);
}
return "ZJU_CONNECT_" + name.replace('-', '_').toUpper();
}
void appendSensitiveOption(
CoreCommand &command,
const QString &name,
const QString &value
)
{
const QString environmentName = environmentVariableName(name);
if (!value.isEmpty())
{
command.environmentVariables.insert(environmentName, value);
}
}
}
QString CoreCommand::loggableCommandLine() const
{
QStringList quotedArguments;
quotedArguments.reserve(loggableArguments.size());
for (const QString &argument : loggableArguments)
{
quotedArguments.append(quoteArgumentForLog(argument));
}
return quotedArguments.join(' ');
}
CoreCommand CoreCommandBuilder::build(const ConnectionProfile &profile, const CoreRuntimePaths &runtimePaths)
{
QStringList arguments;
QStringList credentialArguments;
CoreCommand command;
command.clearedEnvironmentVariables = {
environmentVariableName("-username"),
environmentVariableName("-password"),
environmentVariableName("-totp-secret"),
environmentVariableName("-cert-file"),
environmentVariableName("-cert-password")
};
if (profile.credentials.passAsArguments)
{
if (profile.endpoint.protocol == "easyconnect")
{
appendOption(credentialArguments, "-cert-file", profile.credentials.certFile);
appendOption(credentialArguments, "-cert-password", profile.credentials.certPassword);
}
appendOption(credentialArguments, "-username", profile.credentials.username);
appendOption(credentialArguments, "-password", profile.credentials.password);
appendOption(credentialArguments, "-totp-secret", profile.credentials.totpSecret);
}
else
{
appendSensitiveOption(command, "-username", profile.credentials.username);
appendSensitiveOption(command, "-password", profile.credentials.password);
appendSensitiveOption(command, "-totp-secret", profile.credentials.totpSecret);
if (profile.endpoint.protocol == "easyconnect")
{
appendSensitiveOption(command, "-cert-file", profile.credentials.certFile);
appendSensitiveOption(command, "-cert-password", profile.credentials.certPassword);
}
}
appendOption(arguments, "-protocol", profile.endpoint.protocol);
appendOption(arguments, "-graph-code-file", runtimePaths.graphCodeFile);
if (profile.endpoint.protocol == "atrust")
{
if (!profile.endpoint.authType.isEmpty())
{
arguments << "-auth-type" << "auth/" + profile.endpoint.authType;
}
appendOption(arguments, "-client-data-file", runtimePaths.clientDataFile);
appendOption(arguments, "-login-domain", profile.endpoint.loginDomain);
appendOption(arguments, "-phone", profile.endpoint.phone);
if (profile.behavior.updateBestNodesInterval != 300)
{
arguments << "-update-best-nodes-interval" << QString::number(profile.behavior.updateBestNodesInterval);
}
}
else if (profile.endpoint.protocol == "easyconnect")
{
if (profile.behavior.disableMultiLine)
{
arguments << "-disable-multi-line";
}
if (profile.behavior.disableZjuConfig)
{
arguments << "-disable-zju-config";
}
if (profile.behavior.skipDomainResource)
{
arguments << "-skip-domain-resource";
}
appendOption(arguments, "-custom-proxy-domain", profile.proxy.customDomains);
}
appendOption(arguments, "-server", profile.endpoint.server);
if (profile.endpoint.port != 0)
{
arguments << "-port" << QString::number(profile.endpoint.port);
}
if (!profile.dns.primary.isEmpty() || profile.dns.automatic)
{
arguments << "-zju-dns-server" << (profile.dns.automatic ? "auto" : profile.dns.primary);
}
if (profile.dns.ttl != 3600)
{
arguments << "-dns-ttl" << QString::number(profile.dns.ttl);
}
appendOption(arguments, "-secondary-dns-server", profile.dns.secondary);
if (profile.behavior.disableKeepAlive)
{
arguments << "-disable-keep-alive";
}
appendOption(arguments, "-keep-alive-url", profile.behavior.keepAliveUrl);
appendOption(arguments, "-bind-interface", profile.behavior.bindInterface);
if (profile.behavior.autoDetectInterface)
{
arguments << "-auto-detect-interface";
}
if (profile.dns.disableZjuDns)
{
arguments << "-disable-zju-dns";
}
if (profile.behavior.disableServerConfig)
{
arguments << "-disable-server-config";
}
if (profile.proxy.proxyAll)
{
arguments << "-proxy-all";
}
if (profile.tunnel.tunMode)
{
arguments << "-tun-mode";
if (profile.tunnel.dnsHijack)
{
arguments << "-dns-hijack";
if (profile.tunnel.fakeIp)
{
arguments << "-fake-ip";
}
}
if (profile.tunnel.addRoute)
{
arguments << "-add-route";
}
}
if (profile.tunnel.tcpTunnelMode)
{
arguments << "-tcp-tunnel-mode";
}
if (profile.debug.detailedOutput)
{
arguments << "-debug-dump";
}
appendOption(arguments, "-debug-pcap-file", runtimePaths.debugPcapFile);
appendOption(arguments, "-debug-tls-log-file", runtimePaths.debugTlsLogFile);
appendOption(arguments, "-socks-bind", profile.proxy.socksBind);
appendOption(arguments, "-http-bind", profile.proxy.httpBind);
appendOption(arguments, "-shadowsocks-url", profile.proxy.shadowsocksUrl);
appendOption(arguments, "-dial-direct-proxy", profile.proxy.dialDirectProxy);
appendOption(arguments, "-tcp-port-forwarding", profile.tunnel.tcpPortForwarding);
appendOption(arguments, "-udp-port-forwarding", profile.tunnel.udpPortForwarding);
appendOption(arguments, "-custom-dns", profile.dns.custom);
if (!profile.extraArguments.isEmpty())
{
arguments.append(profile.extraArguments.split(" "));
}
command.loggableArguments = arguments;
command.arguments = credentialArguments + arguments;
return command;
}