#include #include #include #include #include "w_ConnectionEditWindow.h" #include "w_MainWindow.h" ConnectionEditWindow::ConnectionEditWindow(QWidget *parent) : QDialog(parent), _alias(), ui(new Ui::ConnectionEditWindow), stream(), vmess(), shadowsocks() { ui->setupUi(this); ui->portLineEdit->setValidator(new QIntValidator()); ui->alterLineEdit->setValidator(new QIntValidator()); shadowsocks = ShadowSocksServer(); socks = SocksServerObject(); socks.users.push_back(SocksServerObject::UserObject()); vmess = VMessServerObject(); vmess.users.push_back(VMessServerObject::UserObject()); stream = StreamSettingsObject(); OutboundType = "vmess"; ReLoad_GUI_JSON_ModelContent(); } ConnectionEditWindow::ConnectionEditWindow(QJsonObject editRootObject, QString alias, QWidget *parent) : ConnectionEditWindow(parent) { _alias = alias; originalRoot = editRootObject; auto outBoundRoot = originalRoot["outbounds"].toArray().first().toObject(); OutboundType = outBoundRoot["protocol"].toString(); if (OutboundType == "vmess") { vmess = StructFromJsonString(JsonToString(outBoundRoot["settings"].toObject()["vnext"].toArray().first().toObject())); stream = StructFromJsonString(JsonToString(outBoundRoot["streamSettings"].toObject())); shadowsocks.port = vmess.port; shadowsocks.address = vmess.address; socks.address = vmess.address; socks.port = vmess.port; } else if (OutboundType == "shadowsocks") { shadowsocks = StructFromJsonString(JsonToString(outBoundRoot["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(JsonToString(outBoundRoot["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(); } ConnectionEditWindow::~ConnectionEditWindow() { delete ui; } void ConnectionEditWindow::ReLoad_GUI_JSON_ModelContent() { if (OutboundType == "vmess") { ui->outBoundTypeCombo->setCurrentIndex(0); ui->ipLineEdit->setText(QSTRING(vmess.address)); ui->portLineEdit->setText(QString::number(vmess.port)); ui->idLineEdit->setText(QSTRING(vmess.users.front().id)); ui->alterLineEdit->setText(QString::number(vmess.users.front().alterId)); ui->securityCombo->setCurrentText(QSTRING(vmess.users.front().security)); ui->tranportCombo->setCurrentText(QSTRING(stream.network)); ui->tlsCB->setChecked(stream.security == "tls"); // TCP ui->tcpHeaderTypeCB->setCurrentText(QSTRING(stream.tcpSettings.header.type)); ui->tcpRequestTxt->setPlainText(StructToJsonString(stream.tcpSettings.header.request)); ui->tcpRespTxt->setPlainText(StructToJsonString(stream.tcpSettings.header.response)); // HTTP QString allHosts; foreach (auto host, stream.httpSettings.host) { allHosts = allHosts + QSTRING(host) + "\r\n"; } ui->httpHostTxt->setPlainText(allHosts); ui->httpPathTxt->setText(QSTRING(stream.httpSettings.path)); // WS ui->wsPathTxt->setText(QSTRING(stream.wsSettings.path)); QString wsHeaders; foreach (auto _, stream.wsSettings.headers) { wsHeaders = wsHeaders + QSTRING(_.first + "|" + _.second) + "\r\n"; } ui->wsHeadersTxt->setPlainText(wsHeaders); // mKCP ui->kcpMTU->setValue(stream.kcpSettings.mtu); ui->kcpTTI->setValue(stream.kcpSettings.tti); ui->kcpHeaderType->setCurrentText(QSTRING(stream.kcpSettings.header.type)); ui->kcpCongestionCB->setChecked(stream.kcpSettings.congestion); ui->kcpReadBufferSB->setValue(stream.kcpSettings.readBufferSize); ui->kcpUploadCapacSB->setValue(stream.kcpSettings.uplinkCapacity); ui->kcpDownCapacitySB->setValue(stream.kcpSettings.downlinkCapacity); ui->kcpWriteBufferSB->setValue(stream.kcpSettings.writeBufferSize); // DS ui->dsPathTxt->setText(QSTRING(stream.dsSettings.path)); // QUIC ui->quicKeyTxt->setText(QSTRING(stream.quicSettings.key)); ui->quicSecurityCB->setCurrentText(QSTRING(stream.quicSettings.security)); ui->quicHeaderTypeCB->setCurrentText(QSTRING(stream.quicSettings.header.type)); // SOCKOPT ui->tProxyCB->setCurrentText(QSTRING(stream.sockopt.tproxy)); ui->tcpFastOpenCB->setChecked(stream.sockopt.tcpFastOpen); ui->soMarkSpinBox->setValue(stream.sockopt.mark); } else if (OutboundType == "shadowsocks") { ui->outBoundTypeCombo->setCurrentIndex(1); // ShadowSocks Configs ui->ipLineEdit->setText(QSTRING(shadowsocks.address)); ui->portLineEdit->setText(QString::number(shadowsocks.port)); ui->ss_emailTxt->setText(QSTRING(shadowsocks.email)); ui->ss_levelSpin->setValue(shadowsocks.level); ui->ss_otaCheckBox->setChecked(shadowsocks.ota); ui->ss_passwordTxt->setText(QSTRING(shadowsocks.password)); ui->ss_encryptionMethod->setCurrentText(QSTRING(shadowsocks.method)); } else if (OutboundType == "socks") { ui->outBoundTypeCombo->setCurrentIndex(2); ui->ipLineEdit->setText(QSTRING(socks.address)); ui->portLineEdit->setText(QString::number(socks.port)); ui->socks_PasswordTxt->setText(QSTRING(socks.users.front().pass)); ui->socks_UserNameTxt->setText(QSTRING(socks.users.front().user)); } } void ConnectionEditWindow::on_buttonBox_accepted() { bool is_new_config = _alias == ""; auto alias = is_new_config ? (ui->ipLineEdit->text() + "_" + ui->portLineEdit->text()) : _alias; // auto outbound = GenerateConnectionJson(); QJsonArray outbounds; outbounds.append(outbound); // We want to replace because it's connection edit window. if (originalRoot.contains("outbounds")) { originalRoot.remove("outbounds"); } originalRoot.insert("outbounds", outbounds); originalRoot.insert(QV2RAY_CONFIG_TYPE_JSON_KEY, QV2RAY_CONFIG_TYPE_MANUAL); SaveConnectionConfig(originalRoot, &alias); auto globalConf = GetGlobalConfig(); if (is_new_config) { // New config... globalConf.configs.push_back(alias.toStdString()); } SetGlobalConfig(globalConf); emit s_reload_config(!is_new_config); } void ConnectionEditWindow::on_ipLineEdit_textEdited(const QString &arg1) { vmess.address = arg1.toStdString(); shadowsocks.address = arg1.toStdString(); socks.address = arg1.toStdString(); // // No thanks. //if (ui->httpHostTxt->toPlainText() == "") { // ui->httpHostTxt->setPlainText(arg1); // on_httpHostTxt_textChanged(); //} // //if (ui->wsHeadersTxt->toPlainText() == "") { // ui->wsHeadersTxt->setPlainText("Host|" + arg1); // on_wsHeadersTxt_textChanged(); //} } void ConnectionEditWindow::on_portLineEdit_textEdited(const QString &arg1) { if (arg1 != "") { vmess.port = stoi(arg1.toStdString()); shadowsocks.port = stoi(arg1.toStdString()); socks.port = stoi(arg1.toStdString()); } } void ConnectionEditWindow::on_idLineEdit_textEdited(const QString &arg1) { if (vmess.users.size() == 0) vmess.users.push_back(VMessServerObject::UserObject()); vmess.users.front().id = arg1.toStdString(); } void ConnectionEditWindow::on_alterLineEdit_textEdited(const QString &arg1) { if (vmess.users.size() == 0) vmess.users.push_back(VMessServerObject::UserObject()); vmess.users.front().alterId = stoi(arg1.toStdString()); } void ConnectionEditWindow::on_securityCombo_currentIndexChanged(const QString &arg1) { if (vmess.users.size() == 0) vmess.users.push_back(VMessServerObject::UserObject()); vmess.users.front().security = arg1.toStdString(); } void ConnectionEditWindow::on_tranportCombo_currentIndexChanged(const QString &arg1) { stream.network = arg1.toStdString(); } void ConnectionEditWindow::on_httpPathTxt_textEdited(const QString &arg1) { stream.httpSettings.path = arg1.toStdString(); } void ConnectionEditWindow::on_httpHostTxt_textChanged() { try { QStringList hosts = ui->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 ConnectionEditWindow::on_wsHeadersTxt_textChanged() { try { QStringList headers = ui->wsHeadersTxt->toPlainText().replace("\n", "").split("\r"); stream.wsSettings.headers.clear(); foreach (auto header, headers) { auto content = header.split("|"); if (content.length() < 2) throw "fast fail."; stream.wsSettings.headers.insert(make_pair(content[0].toStdString(), content[1].toStdString())); } BLACK(wsHeadersTxt) } catch (...) { RED(wsHeadersTxt) } } void ConnectionEditWindow::on_tcpRequestDefBtn_clicked() { ui->tcpRequestTxt->clear(); ui->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 ConnectionEditWindow::on_tcpRespDefBtn_clicked() { ui->tcpRespTxt->clear(); ui->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\"}}"); } void ConnectionEditWindow::on_tcpRequestTxt_textChanged() { try { auto tcpReqObject = StructFromJsonString(ui->tcpRequestTxt->toPlainText()); stream.tcpSettings.header.request = tcpReqObject; BLACK(tcpRequestTxt) } catch (...) { RED(tcpRequestTxt) } } void ConnectionEditWindow::on_tcpRespTxt_textChanged() { try { auto tcpRspObject = StructFromJsonString(ui->tcpRespTxt->toPlainText()); stream.tcpSettings.header.response = tcpRspObject; BLACK(tcpRespTxt) } catch (...) { RED(tcpRespTxt) } } void ConnectionEditWindow::on_genJsonBtn_clicked() { auto json = GenerateConnectionJson(); } QJsonObject ConnectionEditWindow::GenerateConnectionJson() { // VMess is only a ServerObject, and we need an array { "vnext": [] } QJsonObject settings; auto mux = JsonFromString(StructToJsonString(GetGlobalConfig().mux)); auto streaming = JsonFromString(StructToJsonString(stream)); if (OutboundType == "vmess") { 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", OUTBOUND_TAG_PROXY); return root; } void ConnectionEditWindow::on_tlsCB_stateChanged(int arg1) { stream.security = arg1 == Qt::Checked ? "tls" : "none"; } void ConnectionEditWindow::on_soMarkSpinBox_valueChanged(int arg1) { stream.sockopt.mark = arg1; } void ConnectionEditWindow::on_tcpFastOpenCB_stateChanged(int arg1) { stream.sockopt.tcpFastOpen = arg1 == Qt::Checked; } void ConnectionEditWindow::on_tProxyCB_currentIndexChanged(const QString &arg1) { stream.sockopt.tproxy = arg1.toStdString(); } void ConnectionEditWindow::on_quicSecurityCB_currentTextChanged(const QString &arg1) { stream.quicSettings.security = arg1.toStdString(); } void ConnectionEditWindow::on_quicKeyTxt_textEdited(const QString &arg1) { stream.quicSettings.key = arg1.toStdString(); } void ConnectionEditWindow::on_quicHeaderTypeCB_currentIndexChanged(const QString &arg1) { stream.quicSettings.header.type = arg1.toStdString(); } void ConnectionEditWindow::on_tcpRequestPrettifyBtn_clicked() { try { auto tcpReqObject = StructFromJsonString(ui->tcpRequestTxt->toPlainText()); auto tcpReqObjectStr = StructToJsonString(tcpReqObject); ui->tcpRequestTxt->setPlainText(tcpReqObjectStr); } catch (...) { QvMessageBox(this, tr("#JsonPrettify"), tr("#JsonContainsError")); } } void ConnectionEditWindow::on_tcpRespPrettifyBtn_clicked() { try { auto tcpRspObject = StructFromJsonString(ui->tcpRespTxt->toPlainText()); auto tcpRspObjectStr = StructToJsonString(tcpRspObject); ui->tcpRespTxt->setPlainText(tcpRspObjectStr); } catch (...) { QvMessageBox(this, tr("#JsonPrettify"), tr("#JsonContainsError")); } } void ConnectionEditWindow::on_tcpHeaderTypeCB_currentIndexChanged(const QString &arg1) { stream.tcpSettings.header.type = arg1.toStdString(); } void ConnectionEditWindow::on_wsPathTxt_textEdited(const QString &arg1) { stream.wsSettings.path = arg1.toStdString(); } void ConnectionEditWindow::on_kcpMTU_valueChanged(int arg1) { stream.kcpSettings.mtu = arg1; } void ConnectionEditWindow::on_kcpTTI_valueChanged(int arg1) { stream.kcpSettings.tti = arg1; } void ConnectionEditWindow::on_kcpUploadCapacSB_valueChanged(int arg1) { stream.kcpSettings.uplinkCapacity = arg1; } void ConnectionEditWindow::on_kcpCongestionCB_stateChanged(int arg1) { stream.kcpSettings.congestion = arg1 == Qt::Checked; } void ConnectionEditWindow::on_kcpDownCapacitySB_valueChanged(int arg1) { stream.kcpSettings.downlinkCapacity = arg1; } void ConnectionEditWindow::on_kcpReadBufferSB_valueChanged(int arg1) { stream.kcpSettings.readBufferSize = arg1; } void ConnectionEditWindow::on_kcpWriteBufferSB_valueChanged(int arg1) { stream.kcpSettings.writeBufferSize = arg1; } void ConnectionEditWindow::on_kcpHeaderType_currentTextChanged(const QString &arg1) { stream.kcpSettings.header.type = arg1.toStdString(); } void ConnectionEditWindow::on_tranportCombo_currentIndexChanged(int index) { ui->v2rayStackView->setCurrentIndex(index); } void ConnectionEditWindow::on_dsPathTxt_textEdited(const QString &arg1) { stream.dsSettings.path = arg1.toStdString(); } void ConnectionEditWindow::on_finalJson_textChanged() { //try { // auto jsonRoot = JSONFromString(ui->finalJson->toPlainText()); // vmess = StructFromJSONString(JSONToString(jsonRoot["settings"].toObject())); // stream = StructFromJSONString(JSONToString(jsonRoot["streamSettings"].toObject())); // BLACK(finalJson) // rootJsonCursorPos = ui->finalJson->textCursor().position(); // ReLoad_GUI_JSON_ModelContent(); // ui->finalJson->textCursor().setPosition(rootJsonCursorPos); //} catch (...) { // RED(finalJson) //} } void ConnectionEditWindow::on_outBoundTypeCombo_currentIndexChanged(int index) { ui->outboundTypeStackView->setCurrentIndex(index); OutboundType = ui->outBoundTypeCombo->currentText().toLower(); } void ConnectionEditWindow::on_ss_emailTxt_textEdited(const QString &arg1) { shadowsocks.email = arg1.toStdString(); } void ConnectionEditWindow::on_ss_passwordTxt_textEdited(const QString &arg1) { shadowsocks.password = arg1.toStdString(); } void ConnectionEditWindow::on_ss_encryptionMethod_currentIndexChanged(const QString &arg1) { shadowsocks.method = arg1.toStdString(); } void ConnectionEditWindow::on_ss_levelSpin_valueChanged(int arg1) { shadowsocks.level = arg1; } void ConnectionEditWindow::on_ss_otaCheckBox_stateChanged(int arg1) { shadowsocks.ota = arg1 == Qt::Checked; } void ConnectionEditWindow::on_socks_UserNameTxt_textEdited(const QString &arg1) { socks.users.front().user = arg1.toStdString(); } void ConnectionEditWindow::on_socks_PasswordTxt_textEdited(const QString &arg1) { socks.users.front().pass = arg1.toStdString(); }