Qv2ray/src/ui/w_OutboundEditor.cpp
Leroy.H.Y 22ecbe25a3 [fix] Several further fixes
Former-commit-id: 12fb3bcd29
2019-11-27 10:39:04 +08:00

450 lines
15 KiB
C++

#include <QDebug>
#include <QFile>
#include <QIntValidator>
#include <iostream>
#include "w_OutboundEditor.hpp"
#include "w_MainWindow.hpp"
#include "w_JsonEditor.hpp"
#include "w_RoutesEditor.hpp"
OutboundEditor::OutboundEditor(QWidget *parent)
: QDialog(parent),
Tag(""),
Mux(),
stream(),
vmess(),
shadowsocks()
{
setupUi(this);
shadowsocks = ShadowSocksServerObject();
socks = SocksServerObject();
socks.users.push_back(SocksServerObject::UserObject());
vmess = VMessServerObject();
vmess.users.push_back(VMessServerObject::UserObject());
stream = StreamSettingsObject();
OutboundType = "vmess";
Tag = OUTBOUND_TAG_PROXY;
ReLoad_GUI_JSON_ModelContent();
Result = GenerateConnectionJson();
}
OutboundEditor::OutboundEditor(QJsonObject outboundEntry, QWidget *parent)
: OutboundEditor(parent)
{
Original = outboundEntry;
Tag = outboundEntry["tag"].toString();
tagTxt->setText(Tag);
OutboundType = outboundEntry["protocol"].toString();
Mux = outboundEntry["mux"].toObject();
if (OutboundType == "vmess") {
vmess = StructFromJsonString<VMessServerObject>(JsonToString(outboundEntry["settings"].toObject()["vnext"].toArray().first().toObject()));
stream = StructFromJsonString<StreamSettingsObject>(JsonToString(outboundEntry["streamSettings"].toObject()));
shadowsocks.port = vmess.port;
shadowsocks.address = vmess.address;
socks.address = vmess.address;
socks.port = vmess.port;
} else if (OutboundType == "shadowsocks") {
shadowsocks = StructFromJsonString<ShadowSocksServerObject>(JsonToString(outboundEntry["settings"].toObject()["servers"].toArray().first().toObject()));
vmess.address = shadowsocks.address;
vmess.port = shadowsocks.port;
socks.address = shadowsocks.address;
socks.port = shadowsocks.port;
} else if (OutboundType == "socks") {
socks = StructFromJsonString<SocksServerObject>(JsonToString(outboundEntry["settings"].toObject()["servers"].toArray().first().toObject()));
vmess.address = socks.address;
vmess.port = socks.port;
shadowsocks.address = socks.address;
shadowsocks.port = socks.port;
}
ReLoad_GUI_JSON_ModelContent();
Result = GenerateConnectionJson();
}
OutboundEditor::~OutboundEditor()
{
}
QJsonObject OutboundEditor::OpenEditor()
{
int resultCode = this->exec();
return resultCode == QDialog::Accepted ? Result : Original;
}
QString OutboundEditor::GetFriendlyName()
{
auto host = ipLineEdit->text().replace(":", "-").replace("/", "_").replace("\\", "_");
auto port = portLineEdit->text().replace(":", "-").replace("/", "_").replace("\\", "_");
auto type = OutboundType;
QString name = Tag.isEmpty() ? host + "-[" + port + "]-" + type : Tag;
return name;
}
void OutboundEditor::ReLoad_GUI_JSON_ModelContent()
{
if (OutboundType == "vmess") {
outBoundTypeCombo->setCurrentIndex(0);
ipLineEdit->setText(QSTRING(vmess.address));
portLineEdit->setText(QString::number(vmess.port));
idLineEdit->setText(QSTRING(vmess.users.front().id));
alterLineEdit->setValue(vmess.users.front().alterId);
securityCombo->setCurrentText(QSTRING(vmess.users.front().security));
tranportCombo->setCurrentText(QSTRING(stream.network));
tlsCB->setChecked(stream.security == "tls");
// TCP
tcpHeaderTypeCB->setCurrentText(QSTRING(stream.tcpSettings.header.type));
tcpRequestTxt->setPlainText(StructToJsonString(stream.tcpSettings.header.request));
tcpRespTxt->setPlainText(StructToJsonString(stream.tcpSettings.header.response));
// HTTP
QString allHosts;
foreach (auto host, stream.httpSettings.host) {
allHosts = allHosts + QSTRING(host) + "\r\n";
}
httpHostTxt->setPlainText(allHosts);
httpPathTxt->setText(QSTRING(stream.httpSettings.path));
// WS
wsPathTxt->setText(QSTRING(stream.wsSettings.path));
QString wsHeaders = std::accumulate(stream.wsSettings.headers.begin(), stream.wsSettings.headers.end(), QString(), [](QString in1, const pair<string, string> &in2) {
in1 += QSTRING(in2.first + "|" + in2.second) + "\r\n";
return in1;
});
wsHeadersTxt->setPlainText(wsHeaders);
// mKCP
kcpMTU->setValue(stream.kcpSettings.mtu);
kcpTTI->setValue(stream.kcpSettings.tti);
kcpHeaderType->setCurrentText(QSTRING(stream.kcpSettings.header.type));
kcpCongestionCB->setChecked(stream.kcpSettings.congestion);
kcpReadBufferSB->setValue(stream.kcpSettings.readBufferSize);
kcpUploadCapacSB->setValue(stream.kcpSettings.uplinkCapacity);
kcpDownCapacitySB->setValue(stream.kcpSettings.downlinkCapacity);
kcpWriteBufferSB->setValue(stream.kcpSettings.writeBufferSize);
// DS
dsPathTxt->setText(QSTRING(stream.dsSettings.path));
// QUIC
quicKeyTxt->setText(QSTRING(stream.quicSettings.key));
quicSecurityCB->setCurrentText(QSTRING(stream.quicSettings.security));
quicHeaderTypeCB->setCurrentText(QSTRING(stream.quicSettings.header.type));
// SOCKOPT
tProxyCB->setCurrentText(QSTRING(stream.sockopt.tproxy));
tcpFastOpenCB->setChecked(stream.sockopt.tcpFastOpen);
soMarkSpinBox->setValue(stream.sockopt.mark);
} else if (OutboundType == "shadowsocks") {
outBoundTypeCombo->setCurrentIndex(1);
// ShadowSocks Configs
ipLineEdit->setText(QSTRING(shadowsocks.address));
portLineEdit->setText(QString::number(shadowsocks.port));
ss_emailTxt->setText(QSTRING(shadowsocks.email));
ss_levelSpin->setValue(shadowsocks.level);
ss_otaCheckBox->setChecked(shadowsocks.ota);
ss_passwordTxt->setText(QSTRING(shadowsocks.password));
ss_encryptionMethod->setCurrentText(QSTRING(shadowsocks.method));
} else if (OutboundType == "socks") {
outBoundTypeCombo->setCurrentIndex(2);
ipLineEdit->setText(QSTRING(socks.address));
portLineEdit->setText(QString::number(socks.port));
if (socks.users.empty()) socks.users.push_back(SocksServerObject::UserObject());
socks_PasswordTxt->setText(QSTRING(socks.users.front().pass));
socks_UserNameTxt->setText(QSTRING(socks.users.front().user));
}
muxEnabledCB->setChecked(Mux["enabled"].toBool());
muxConcurrencyTxt->setValue(Mux["concurrency"].toInt());
}
void OutboundEditor::on_buttonBox_accepted()
{
Result = GenerateConnectionJson();
}
void OutboundEditor::on_ipLineEdit_textEdited(const QString &arg1)
{
vmess.address = arg1.toStdString();
shadowsocks.address = arg1.toStdString();
socks.address = arg1.toStdString();
}
void OutboundEditor::on_portLineEdit_textEdited(const QString &arg1)
{
if (arg1 != "") {
vmess.port = stoi(arg1.toStdString());
shadowsocks.port = stoi(arg1.toStdString());
socks.port = stoi(arg1.toStdString());
}
}
void OutboundEditor::on_idLineEdit_textEdited(const QString &arg1)
{
if (vmess.users.empty()) vmess.users.push_back(VMessServerObject::UserObject());
vmess.users.front().id = arg1.toStdString();
}
void OutboundEditor::on_securityCombo_currentIndexChanged(const QString &arg1)
{
if (vmess.users.empty()) vmess.users.push_back(VMessServerObject::UserObject());
vmess.users.front().security = arg1.toStdString();
}
void OutboundEditor::on_tranportCombo_currentIndexChanged(const QString &arg1)
{
stream.network = arg1.toStdString();
}
void OutboundEditor::on_httpPathTxt_textEdited(const QString &arg1)
{
stream.httpSettings.path = arg1.toStdString();
}
void OutboundEditor::on_httpHostTxt_textChanged()
{
try {
QStringList hosts = httpHostTxt->toPlainText().replace("\r", "").split("\n");
stream.httpSettings.host.clear();
foreach (auto host, hosts) {
if (host.trimmed() != "")
stream.httpSettings.host.push_back(host.trimmed().toStdString());
}
BLACK(httpHostTxt)
} catch (...) {
RED(httpHostTxt)
}
}
void OutboundEditor::on_wsHeadersTxt_textChanged()
{
try {
QStringList headers = wsHeadersTxt->toPlainText().replace("\r", "").split("\n");
stream.wsSettings.headers.clear();
foreach (auto header, headers) {
if (header.isEmpty()) continue;
auto content = header.split("|");
if (content.length() < 2) throw "fast fail to set RED color";
stream.wsSettings.headers.insert(make_pair(content[0].toStdString(), content[1].toStdString()));
}
BLACK(wsHeadersTxt)
} catch (...) {
RED(wsHeadersTxt)
}
}
void OutboundEditor::on_tcpRequestDefBtn_clicked()
{
tcpRequestTxt->clear();
tcpRequestTxt->insertPlainText("{\"version\":\"1.1\",\"method\":\"GET\",\"path\":[\"/\"],\"headers\":"
"{\"Host\":[\"www.baidu.com\",\"www.bing.com\"],\"User-Agent\":"
"[\"Mozilla/5.0 (Windows NT 10.0; WOW64) "
"AppleWebKit/537.36 (KHTML, like Gecko) Chrome/53.0.2785.143 Safari/537.36\","
"\"Mozilla/5.0 (iPhone; CPU iPhone OS 10_0_2 like Mac OS X) "
"AppleWebKit/601.1 (KHTML, like Gecko) CriOS/53.0.2785.109 Mobile/14A456 "
"Safari/601.1.46\"],\"Accept-Encoding\":[\"gzip, deflate\"],"
"\"Connection\":[\"keep-alive\"],\"Pragma\":\"no-cache\"}}");
}
void OutboundEditor::on_tcpRespDefBtn_clicked()
{
tcpRespTxt->clear();
tcpRespTxt->insertPlainText("{\"version\":\"1.1\",\"status\":\"200\",\"reason\":\"OK\",\"headers\":{\"Content-Type\":[\"application/octet-stream\",\"video/mpeg\"],\"Transfer-Encoding\":[\"chunked\"],\"Connection\":[\"keep-alive\"],\"Pragma\":\"no-cache\"}}");
}
QJsonObject OutboundEditor::GenerateConnectionJson()
{
QJsonObject settings;
auto streaming = JsonFromString(StructToJsonString(stream));
if (OutboundType == "vmess") {
// VMess is only a ServerObject, and we need an array { "vnext": [] }
QJsonArray vnext;
vnext.append(GetRootObject(vmess));
settings.insert("vnext", vnext);
} else if (OutboundType == "shadowsocks") {
streaming = QJsonObject();
QJsonArray servers;
servers.append(GetRootObject(shadowsocks));
settings["servers"] = servers;
} else if (OutboundType == "socks") {
streaming = QJsonObject();
QJsonArray servers;
servers.append(GetRootObject(socks));
settings["servers"] = servers;
}
auto root = GenerateOutboundEntry(OutboundType, settings, streaming, Mux, "0.0.0.0", Tag);
return root;
}
void OutboundEditor::on_tlsCB_stateChanged(int arg1)
{
stream.security = arg1 == Qt::Checked ? "tls" : "none";
}
void OutboundEditor::on_soMarkSpinBox_valueChanged(int arg1)
{
stream.sockopt.mark = arg1;
}
void OutboundEditor::on_tcpFastOpenCB_stateChanged(int arg1)
{
stream.sockopt.tcpFastOpen = arg1 == Qt::Checked;
}
void OutboundEditor::on_tProxyCB_currentIndexChanged(const QString &arg1)
{
stream.sockopt.tproxy = arg1.toStdString();
}
void OutboundEditor::on_quicSecurityCB_currentTextChanged(const QString &arg1)
{
stream.quicSettings.security = arg1.toStdString();
}
void OutboundEditor::on_quicKeyTxt_textEdited(const QString &arg1)
{
stream.quicSettings.key = arg1.toStdString();
}
void OutboundEditor::on_quicHeaderTypeCB_currentIndexChanged(const QString &arg1)
{
stream.quicSettings.header.type = arg1.toStdString();
}
void OutboundEditor::on_tcpHeaderTypeCB_currentIndexChanged(const QString &arg1)
{
stream.tcpSettings.header.type = arg1.toStdString();
}
void OutboundEditor::on_wsPathTxt_textEdited(const QString &arg1)
{
stream.wsSettings.path = arg1.toStdString();
}
void OutboundEditor::on_kcpMTU_valueChanged(int arg1)
{
stream.kcpSettings.mtu = arg1;
}
void OutboundEditor::on_kcpTTI_valueChanged(int arg1)
{
stream.kcpSettings.tti = arg1;
}
void OutboundEditor::on_kcpUploadCapacSB_valueChanged(int arg1)
{
stream.kcpSettings.uplinkCapacity = arg1;
}
void OutboundEditor::on_kcpCongestionCB_stateChanged(int arg1)
{
stream.kcpSettings.congestion = arg1 == Qt::Checked;
}
void OutboundEditor::on_kcpDownCapacitySB_valueChanged(int arg1)
{
stream.kcpSettings.downlinkCapacity = arg1;
}
void OutboundEditor::on_kcpReadBufferSB_valueChanged(int arg1)
{
stream.kcpSettings.readBufferSize = arg1;
}
void OutboundEditor::on_kcpWriteBufferSB_valueChanged(int arg1)
{
stream.kcpSettings.writeBufferSize = arg1;
}
void OutboundEditor::on_kcpHeaderType_currentTextChanged(const QString &arg1)
{
stream.kcpSettings.header.type = arg1.toStdString();
}
void OutboundEditor::on_tranportCombo_currentIndexChanged(int index)
{
v2rayStackView->setCurrentIndex(index);
}
void OutboundEditor::on_dsPathTxt_textEdited(const QString &arg1)
{
stream.dsSettings.path = arg1.toStdString();
}
void OutboundEditor::on_outBoundTypeCombo_currentIndexChanged(int index)
{
outboundTypeStackView->setCurrentIndex(index);
OutboundType = outBoundTypeCombo->currentText().toLower();
}
void OutboundEditor::on_ss_emailTxt_textEdited(const QString &arg1)
{
shadowsocks.email = arg1.toStdString();
}
void OutboundEditor::on_ss_passwordTxt_textEdited(const QString &arg1)
{
shadowsocks.password = arg1.toStdString();
}
void OutboundEditor::on_ss_encryptionMethod_currentIndexChanged(const QString &arg1)
{
shadowsocks.method = arg1.toStdString();
}
void OutboundEditor::on_ss_levelSpin_valueChanged(int arg1)
{
shadowsocks.level = arg1;
}
void OutboundEditor::on_ss_otaCheckBox_stateChanged(int arg1)
{
shadowsocks.ota = arg1 == Qt::Checked;
}
void OutboundEditor::on_socks_UserNameTxt_textEdited(const QString &arg1)
{
socks.users.front().user = arg1.toStdString();
}
void OutboundEditor::on_socks_PasswordTxt_textEdited(const QString &arg1)
{
socks.users.front().pass = arg1.toStdString();
}
void OutboundEditor::on_tcpRequestEditBtn_clicked()
{
JsonEditor *w = new JsonEditor(JsonFromString(tcpRequestTxt->toPlainText()), this);
auto rString = JsonToString(w->OpenEditor());
tcpRequestTxt->setPlainText(rString);
auto tcpReqObject = StructFromJsonString<TSObjects::HTTPRequestObject>(rString);
stream.tcpSettings.header.request = tcpReqObject;
delete w;
}
void OutboundEditor::on_tcpResponseEditBtn_clicked()
{
JsonEditor *w = new JsonEditor(JsonFromString(tcpRespTxt->toPlainText()), this);
auto rString = JsonToString(w->OpenEditor());
tcpRespTxt->setPlainText(rString);
auto tcpRspObject = StructFromJsonString<TSObjects::HTTPResponseObject>(rString);
stream.tcpSettings.header.response = tcpRspObject;
delete w;
}
void OutboundEditor::on_tagTxt_textEdited(const QString &arg1)
{
Tag = arg1;
}
void OutboundEditor::on_muxEnabledCB_stateChanged(int arg1)
{
Mux["enabled"] = arg1 == Qt::Checked;
}
void OutboundEditor::on_muxConcurrencyTxt_valueChanged(int arg1)
{
Mux["concurrency"] = arg1;
}
void OutboundEditor::on_alterLineEdit_valueChanged(int arg1)
{
if (vmess.users.empty()) vmess.users.push_back(VMessServerObject::UserObject());
vmess.users.front().alterId = arg1;
}