Compare commits

...

23 Commits

Author SHA1 Message Date
armv9
adef6cd4af 4.0.1 2024-12-12 17:03:36 +09:00
armv9
399b171adf misc change 2024-12-12 17:03:32 +09:00
armv9
6e4c180428 fix: dns outbound 2024-12-12 17:02:37 +09:00
armv9
75c6496151 change: domain rule use domain_suffix 2024-12-12 17:02:14 +09:00
Integral
62c59f6fd3
refactor: replace non-empty QString constructors with QStringLiteral() 2024-11-03 12:50:41 +08:00
armv9
12d6fc24e7 4.0-beta4 2024-10-09 13:32:41 +09:00
armv9
6de7c588b6 update core 2024-10-09 13:32:41 +09:00
armv9
99c8d50943 add url test button on main window 2024-10-09 13:32:41 +09:00
极速蜗牛
2a177256ce
Add /usr/share/sing-box to core asset search path (#1350) 2024-07-20 13:23:24 +08:00
Chi_Tang
b1d1674912
fixed pkgbuild for 4.0 (#1348) 2024-07-13 17:36:39 +08:00
armv9
2dd9cf45eb update readme 2024-07-13 15:57:07 +09:00
armv9
96a6586c5e 4.0-beta3 2024-07-13 15:39:11 +09:00
armv9
375ffec58d remove v2ray_asset_dir 2024-07-13 15:37:07 +09:00
armv9
7aa863b881 remove log high light 2024-07-13 15:26:01 +09:00
armv9
79838d8679 urltest: use dns 2024-07-07 15:25:15 +09:00
armv9
61e27f4014 fix appimage 2024-07-05 11:48:51 +09:00
armv9
e868de0209 4.0-beta2 2024-07-05 11:34:06 +09:00
armv9
6f81ba7773 change exe name 2024-07-05 11:34:06 +09:00
armv9
be0eae662b update qt 2024-07-05 11:16:26 +09:00
armv9
f6cf1414bf hysteria -> hysteria2 2024-07-05 10:29:22 +09:00
armv9
7c783308a7 fix: linux external tun 2024-07-03 16:55:16 +09:00
armv9
cd9bb8f72d v2ray format migration 2024-07-03 16:55:14 +09:00
armv9
df141f9079 fix: win32 gui 2024-07-02 13:26:54 +09:00
83 changed files with 599 additions and 2019 deletions

View File

@ -4,20 +4,20 @@ on:
workflow_dispatch: workflow_dispatch:
inputs: inputs:
tag: tag:
description: 'Release Tag' description: "Release Tag"
required: true required: true
publish: publish:
description: 'Publish: If want ignore' description: "Publish: If want ignore"
required: false required: false
artifact-pack: artifact-pack:
description: 'artifact-pack: If want ignore' description: "artifact-pack: If want ignore"
required: false required: false
jobs: jobs:
build-go: build-go:
strategy: strategy:
matrix: matrix:
cross_os: [ windows, linux ] cross_os: [windows, linux]
cross_arch: [ amd64 ] cross_arch: [amd64]
include: include:
- cross_os: public_res - cross_os: public_res
cross_arch: public_res cross_arch: public_res
@ -38,7 +38,7 @@ jobs:
if: steps.cache-common.outputs.cache-hit != 'true' if: steps.cache-common.outputs.cache-hit != 'true'
uses: actions/setup-go@v3 uses: actions/setup-go@v3
with: with:
go-version: ^1.21 go-version: ^1.22
- name: Build golang parts - name: Build golang parts
if: steps.cache-common.outputs.cache-hit != 'true' if: steps.cache-common.outputs.cache-hit != 'true'
shell: bash shell: bash
@ -61,7 +61,7 @@ jobs:
include: include:
- platform: windows-2022 - platform: windows-2022
arch: x64 arch: x64
qt_version: "6.5" qt_version: "6.7"
- platform: ubuntu-20.04 - platform: ubuntu-20.04
arch: x64 arch: x64
qt_version: "5.12" qt_version: "5.12"
@ -196,7 +196,7 @@ jobs:
cp -r public_res/* linux64 cp -r public_res/* linux64
#### ####
bash ../libs/package_appimage.sh bash ../libs/package_appimage.sh
mv nekoray-x86_64.AppImage $version_standalone-linux-x64.AppImage mv nekobox-x86_64.AppImage $version_standalone-linux-x64.AppImage
- name: Clean Up - name: Clean Up
run: | run: |
cd deployment cd deployment

18
.github/workflows/update-pkgbuild.yml vendored Normal file
View File

@ -0,0 +1,18 @@
name: AUR CI
on:
push:
branches:
- main
paths-ignore:
- '**.md'
- 'LICENSE'
- '!.github/workflows/**'
jobs:
update:
runs-on: ubuntu-latest
steps:
- uses: chitang233/aur-pkgbuild-builder@main
with:
deploy_key: ${{ secrets.DEPLOY_KEY }}
package_name: 'nekoray-git'

View File

@ -353,7 +353,7 @@ namespace Qv2ray::components::proxy {
// execute and get the code // execute and get the code
const auto returnCode = QProcess::execute(action.first, action.second); const auto returnCode = QProcess::execute(action.first, action.second);
// print out the commands and result codes // print out the commands and result codes
DEBUG(QString("[%1] Program: %2, Args: %3").arg(returnCode).arg(action.first).arg(action.second.join(";"))); DEBUG(QStringLiteral("[%1] Program: %2, Args: %3").arg(returnCode).arg(action.first).arg(action.second.join(";")));
// give the code back // give the code back
results << (returnCode == QProcess::NormalExit); results << (returnCode == QProcess::NormalExit);
} }
@ -423,7 +423,7 @@ namespace Qv2ray::components::proxy {
// execute and get the code // execute and get the code
const auto returnCode = QProcess::execute(action.first, action.second); const auto returnCode = QProcess::execute(action.first, action.second);
// print out the commands and result codes // print out the commands and result codes
DEBUG(QString("[%1] Program: %2, Args: %3").arg(returnCode).arg(action.first).arg(action.second.join(";"))); DEBUG(QStringLiteral("[%1] Program: %2, Args: %3").arg(returnCode).arg(action.first).arg(action.second.join(";")));
} }
#else #else

View File

@ -1,132 +0,0 @@
#include "LogHighlighter.hpp"
#define TO_EOL "(([\\s\\S]*)|([\\d\\D]*)|([\\w\\W]*))$"
#define REGEX_IPV6_ADDR \
R"(\[\s*((([0-9A-Fa-f]{1,4}:){7}([0-9A-Fa-f]{1,4}|:))|(([0-9A-Fa-f]{1,4}:){6}(:[0-9A-Fa-f]{1,4}|((25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)(\.(25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)){3})|:))|(([0-9A-Fa-f]{1,4}:){5}(((:[0-9A-Fa-f]{1,4}){1,2})|:((25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)(\.(25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)){3})|:))|(([0-9A-Fa-f]{1,4}:){4}(((:[0-9A-Fa-f]{1,4}){1,3})|((:[0-9A-Fa-f]{1,4})?:((25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)(\.(25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)){3}))|:))|(([0-9A-Fa-f]{1,4}:){3}(((:[0-9A-Fa-f]{1,4}){1,4})|((:[0-9A-Fa-f]{1,4}){0,2}:((25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)(\.(25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)){3}))|:))|(([0-9A-Fa-f]{1,4}:){2}(((:[0-9A-Fa-f]{1,4}){1,5})|((:[0-9A-Fa-f]{1,4}){0,3}:((25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)(\.(25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)){3}))|:))|(([0-9A-Fa-f]{1,4}:){1}(((:[0-9A-Fa-f]{1,4}){1,6})|((:[0-9A-Fa-f]{1,4}){0,4}:((25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)(\.(25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)){3}))|:))|(:(((:[0-9A-Fa-f]{1,4}){1,7})|((:[0-9A-Fa-f]{1,4}){0,5}:((25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)(\.(25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)){3}))|:)))(%.+)?\s*\])"
#define REGEX_IPV4_ADDR \
R"((\d{1,2}|1\d\d|2[0-4]\d|25[0-5])\.(\d{1,2}|1\d\d|2[0-4]\d|25[0-5])\.(\d{1,2}|1\d\d|2[0-4]\d|25[0-5])\.(\d{1,2}|1\d\d|2[0-4]\d|25[0-5]))"
#define REGEX_PORT_NUMBER R"(([0-9]|[1-9]\d{1,3}|[1-5]\d{4}|6[0-5]{2}[0-3][0-5])*)"
namespace Qv2ray::ui {
SyntaxHighlighter::SyntaxHighlighter(bool darkMode, QTextDocument *parent) : QSyntaxHighlighter(parent) {
HighlightingRule rule;
if (darkMode) {
tcpudpFormat.setForeground(QColor(0, 200, 230));
ipHostFormat.setForeground(Qt::yellow);
warningFormat.setForeground(QColor(255, 160, 15));
warningFormat2.setForeground(Qt::cyan);
} else {
ipHostFormat.setForeground(QColor(0, 52, 130));
tcpudpFormat.setForeground(QColor(0, 52, 130));
warningFormat.setBackground(QColor(255, 160, 15));
warningFormat.setForeground(Qt::white);
warningFormat2.setForeground(Qt::darkCyan);
}
const static QColor darkGreenColor(10, 180, 0);
acceptedFormat.setForeground(darkGreenColor);
acceptedFormat.setFontItalic(true);
acceptedFormat.setFontWeight(QFont::Bold);
rule.pattern = QRegularExpression("\\saccepted\\s");
rule.format = acceptedFormat;
highlightingRules.append(rule);
//
rejectedFormat.setFontWeight(QFont::Bold);
rejectedFormat.setBackground(Qt::red);
rejectedFormat.setForeground(Qt::white);
rejectedFormat.setFontWeight(QFont::Bold);
rule.pattern = QRegularExpression("\\srejected\\s" TO_EOL);
rule.format = rejectedFormat;
highlightingRules.append(rule);
//
dateFormat.setForeground(darkMode ? Qt::cyan : Qt::darkCyan);
rule.pattern = QRegularExpression("\\d\\d\\d\\d/\\d\\d/\\d\\d");
rule.format = dateFormat;
highlightingRules.append(rule);
//
timeFormat.setForeground(darkMode ? Qt::cyan : Qt::darkCyan);
rule.pattern = QRegularExpression("\\d\\d:\\d\\d:\\d\\d");
rule.format = timeFormat;
highlightingRules.append(rule);
//
debugFormat.setForeground(Qt::darkGray);
rule.pattern = QRegularExpression("\\[D[Ee][Bb][Uu].*?\\]");
rule.format = debugFormat;
highlightingRules.append(rule);
//
infoFormat.setForeground(darkMode ? Qt::lightGray : Qt::darkCyan);
rule.pattern = QRegularExpression("\\[I[Nn][Ff][Oo].*?\\]");
rule.format = infoFormat;
highlightingRules.append(rule);
//
warningFormat.setFontWeight(QFont::Bold);
warningFormat2.setFontWeight(QFont::Bold);
rule.pattern = QRegularExpression("\\[W[Aa][Rr][Nn].*?\\]");
rule.format = warningFormat2;
highlightingRules.append(rule);
//
rule.pattern = QRegularExpression("\\[E[Rr][Rr][Oo].*?\\]");
rule.format = rejectedFormat;
highlightingRules.append(rule);
//
v2rayComponentFormat.setForeground(darkMode ? darkGreenColor : Qt::darkYellow);
rule.pattern = QRegularExpression(R"( (\w+\/)+\w+: )");
rule.format = v2rayComponentFormat;
highlightingRules.append(rule);
//
failedFormat.setFontWeight(QFont::Bold);
failedFormat.setBackground(Qt::red);
failedFormat.setForeground(Qt::white);
rule.pattern = QRegularExpression("failed");
rule.format = failedFormat;
highlightingRules.append(rule);
//
rule.pattern = QRegularExpression(">>>>+");
rule.format = warningFormat;
highlightingRules.append(rule);
//
rule.pattern = QRegularExpression("<<<<+");
rule.format = warningFormat;
highlightingRules.append(rule);
{
// IP IPv6 Host;
rule.pattern = QRegularExpression(REGEX_IPV4_ADDR ":" REGEX_PORT_NUMBER);
rule.pattern.setPatternOptions(QRegularExpression::ExtendedPatternSyntaxOption);
rule.format = ipHostFormat;
highlightingRules.append(rule);
//
rule.pattern = QRegularExpression(REGEX_IPV6_ADDR ":" REGEX_PORT_NUMBER);
rule.pattern.setPatternOptions(QRegularExpression::ExtendedPatternSyntaxOption);
rule.format = ipHostFormat;
highlightingRules.append(rule);
//
rule.pattern = QRegularExpression("([a-zA-Z0-9]([a-zA-Z0-9\\-]{0,61}[a-zA-Z0-9])?\\.)+[a-zA-Z]{2,6}(/|):" REGEX_PORT_NUMBER);
rule.pattern.setPatternOptions(QRegularExpression::PatternOption::ExtendedPatternSyntaxOption);
rule.format = ipHostFormat;
highlightingRules.append(rule);
}
for (const auto &pattern: {"tcp:", "udp:"}) {
tcpudpFormat.setFontWeight(QFont::Bold);
rule.pattern = QRegularExpression(pattern);
rule.format = tcpudpFormat;
highlightingRules.append(rule);
}
}
void SyntaxHighlighter::highlightBlock(const QString &text) {
for (const HighlightingRule &rule: highlightingRules) {
QRegularExpressionMatchIterator matchIterator = rule.pattern.globalMatch(text);
while (matchIterator.hasNext()) {
QRegularExpressionMatch match = matchIterator.next();
setFormat(match.capturedStart(), match.capturedLength(), rule.format);
}
}
setCurrentBlockState(0);
}
} // namespace Qv2ray::ui

View File

@ -1,92 +0,0 @@
/****************************************************************************
**
** Copyright (C) 2016 The Qt Company Ltd.
** Contact: https://www.qt.io/licensing/
**
** This file is part of the examples of the Qt Toolkit.
**
** $QT_BEGIN_LICENSE:BSD$
** Commercial License Usage
** Licensees holding valid commercial Qt licenses may use this file in
** accordance with the commercial license agreement provided with the
** Software or, alternatively, in accordance with the terms contained in
** a written agreement between you and The Qt Company. For licensing terms
** and conditions see https://www.qt.io/terms-conditions. For further
** information use the contact form at https://www.qt.io/contact-us.
**
** BSD License Usage
** Alternatively, you may use this file under the terms of the BSD license
** as follows:
**
** "Redistribution and use in source and binary forms, with or without
** modification, are permitted provided that the following conditions are
** met:
** * Redistributions of source code must retain the above copyright
** notice, this list of conditions and the following disclaimer.
** * Redistributions in binary form must reproduce the above copyright
** notice, this list of conditions and the following disclaimer in
** the documentation and/or other materials provided with the
** distribution.
** * Neither the name of The Qt Company Ltd nor the names of its
** contributors may be used to endorse or promote products derived
** from this software without specific prior written permission.
**
**
** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE."
**
** $QT_END_LICENSE$
**
****************************************************************************/
#pragma once
#include <QRegularExpression>
#include <QSyntaxHighlighter>
#include <QTextCharFormat>
#include <QTextDocument>
namespace Qv2ray {
namespace ui {
class SyntaxHighlighter : public QSyntaxHighlighter {
Q_OBJECT
public:
explicit SyntaxHighlighter(bool darkMode, QTextDocument *parent = nullptr);
protected:
void highlightBlock(const QString &text) override;
private:
struct HighlightingRule {
QRegularExpression pattern;
QTextCharFormat format;
};
QVector<HighlightingRule> highlightingRules;
QTextCharFormat tcpudpFormat;
QTextCharFormat dateFormat;
QTextCharFormat acceptedFormat;
QTextCharFormat rejectedFormat;
QTextCharFormat failedFormat;
QTextCharFormat warningFormat;
QTextCharFormat warningFormat2;
QTextCharFormat infoFormat;
QTextCharFormat debugFormat;
QTextCharFormat timeFormat;
QTextCharFormat ipHostFormat;
QTextCharFormat v2rayComponentFormat;
};
} // namespace ui
} // namespace Qv2ray
using namespace Qv2ray::ui;

View File

@ -191,13 +191,13 @@ QVariant QJsonModel::data(const QModelIndex &index, int role) const {
if (role == Qt::DisplayRole) { if (role == Qt::DisplayRole) {
if (index.column() == 0) if (index.column() == 0)
return QString("%1").arg(item->key()); return QStringLiteral("%1").arg(item->key());
if (index.column() == 1) if (index.column() == 1)
return QString("%1").arg(item->value()); return QStringLiteral("%1").arg(item->value());
} else if (Qt::EditRole == role) { } else if (Qt::EditRole == role) {
if (index.column() == 1) { if (index.column() == 1) {
return QString("%1").arg(item->value()); return QStringLiteral("%1").arg(item->value());
} }
} }

View File

@ -1,6 +1,6 @@
cmake_minimum_required(VERSION 3.5) cmake_minimum_required(VERSION 3.5)
project(nekoray VERSION 0.1 LANGUAGES CXX) project(nekobox VERSION 0.1 LANGUAGES CXX)
set(CMAKE_INCLUDE_CURRENT_DIR ON) set(CMAKE_INCLUDE_CURRENT_DIR ON)
@ -131,7 +131,6 @@ set(PROJECT_SOURCES
3rdparty/qrcodegen.cpp 3rdparty/qrcodegen.cpp
3rdparty/QtExtKeySequenceEdit.cpp 3rdparty/QtExtKeySequenceEdit.cpp
3rdparty/qv2ray/v2/ui/LogHighlighter.cpp
3rdparty/qv2ray/v2/ui/QvAutoCompleteTextEdit.cpp 3rdparty/qv2ray/v2/ui/QvAutoCompleteTextEdit.cpp
3rdparty/qv2ray/v2/components/proxy/QvProxyConfigurator.cpp 3rdparty/qv2ray/v2/components/proxy/QvProxyConfigurator.cpp
3rdparty/qv2ray/v2/ui/widgets/common/QJsonModel.cpp 3rdparty/qv2ray/v2/ui/widgets/common/QJsonModel.cpp
@ -150,7 +149,6 @@ set(PROJECT_SOURCES
db/ConfigBuilder.cpp db/ConfigBuilder.cpp
fmt/AbstractBean.cpp fmt/AbstractBean.cpp
fmt/Bean2CoreObj_ray.cpp
fmt/Bean2CoreObj_box.cpp fmt/Bean2CoreObj_box.cpp
fmt/Bean2External.cpp fmt/Bean2External.cpp
fmt/Bean2Link.cpp fmt/Bean2Link.cpp
@ -239,23 +237,23 @@ set(PROJECT_SOURCES
# Qt exe # Qt exe
if (${QT_VERSION_MAJOR} GREATER_EQUAL 6) if (${QT_VERSION_MAJOR} GREATER_EQUAL 6)
qt_add_executable(nekoray qt_add_executable(nekobox
MANUAL_FINALIZATION MANUAL_FINALIZATION
${PROJECT_SOURCES} ${PROJECT_SOURCES}
) )
# Define target properties for Android with Qt 6 as: # Define target properties for Android with Qt 6 as:
# set_property(TARGET nekoray APPEND PROPERTY QT_ANDROID_PACKAGE_SOURCE_DIR # set_property(TARGET nekobox APPEND PROPERTY QT_ANDROID_PACKAGE_SOURCE_DIR
# ${CMAKE_CURRENT_SOURCE_DIR}/android) # ${CMAKE_CURRENT_SOURCE_DIR}/android)
# For more information, see https://doc.qt.io/qt-6/qt-add-executable.html#target-creation # For more information, see https://doc.qt.io/qt-6/qt-add-executable.html#target-creation
else () else ()
if (ANDROID) if (ANDROID)
add_library(nekoray SHARED add_library(nekobox SHARED
${PROJECT_SOURCES} ${PROJECT_SOURCES}
) )
# Define properties for Android with Qt 5 after find_package() calls as: # Define properties for Android with Qt 5 after find_package() calls as:
# set(ANDROID_PACKAGE_SOURCE_DIR "${CMAKE_CURRENT_SOURCE_DIR}/android") # set(ANDROID_PACKAGE_SOURCE_DIR "${CMAKE_CURRENT_SOURCE_DIR}/android")
else () else ()
add_executable(nekoray add_executable(nekobox
${PROJECT_SOURCES} ${PROJECT_SOURCES}
) )
endif () endif ()
@ -263,9 +261,13 @@ endif ()
# Target # Target
set_property(TARGET nekoray PROPERTY AUTOUIC ON) set_property(TARGET nekobox PROPERTY AUTOUIC ON)
set_property(TARGET nekoray PROPERTY AUTOMOC ON) set_property(TARGET nekobox PROPERTY AUTOMOC ON)
set_property(TARGET nekoray PROPERTY AUTORCC ON) set_property(TARGET nekobox PROPERTY AUTORCC ON)
set_target_properties(nekobox PROPERTIES
WIN32_EXECUTABLE TRUE
)
# Target Source Translations # Target Source Translations
@ -278,17 +280,17 @@ set(LUPDATE_OPTIONS
-locations none -no-obsolete -locations none -no-obsolete
) )
if (${QT_VERSION_MAJOR} GREATER_EQUAL 6) if (${QT_VERSION_MAJOR} GREATER_EQUAL 6)
qt_add_lupdate(nekoray TS_FILES ${TS_FILES} OPTIONS ${LUPDATE_OPTIONS}) qt_add_lupdate(nekobox TS_FILES ${TS_FILES} OPTIONS ${LUPDATE_OPTIONS})
qt_add_lrelease(nekoray TS_FILES ${TS_FILES} QM_FILES_OUTPUT_VARIABLE QM_FILES) qt_add_lrelease(nekobox TS_FILES ${TS_FILES} QM_FILES_OUTPUT_VARIABLE QM_FILES)
else () else ()
qt5_create_translation(QM_FILES ${PROJECT_SOURCES} ${TS_FILES} OPTIONS ${LUPDATE_OPTIONS}) qt5_create_translation(QM_FILES ${PROJECT_SOURCES} ${TS_FILES} OPTIONS ${LUPDATE_OPTIONS})
endif () endif ()
configure_file(translations/translations.qrc ${CMAKE_BINARY_DIR} COPYONLY) configure_file(translations/translations.qrc ${CMAKE_BINARY_DIR} COPYONLY)
target_sources(nekoray PRIVATE ${CMAKE_BINARY_DIR}/translations.qrc) target_sources(nekobox PRIVATE ${CMAKE_BINARY_DIR}/translations.qrc)
# Target Link # Target Link
target_link_libraries(nekoray PRIVATE target_link_libraries(nekobox PRIVATE
Qt${QT_VERSION_MAJOR}::Widgets Qt${QT_VERSION_MAJOR}::Network Qt${QT_VERSION_MAJOR}::Svg Qt${QT_VERSION_MAJOR}::Widgets Qt${QT_VERSION_MAJOR}::Network Qt${QT_VERSION_MAJOR}::Svg
Threads::Threads Threads::Threads
${NKR_EXTERNAL_TARGETS} ${NKR_EXTERNAL_TARGETS}
@ -296,5 +298,5 @@ target_link_libraries(nekoray PRIVATE
) )
if (QT_VERSION_MAJOR EQUAL 6) if (QT_VERSION_MAJOR EQUAL 6)
qt_finalize_executable(nekoray) qt_finalize_executable(nekobox)
endif () endif ()

View File

@ -8,16 +8,6 @@ Support Windows / Linux out of the box now.
目前支持 Windows / Linux 开箱即用 目前支持 Windows / Linux 开箱即用
## 4.x 开发计划
软件定位:电脑端节点调试软件。更新频率随机,可用性无保证。机场订阅用户建议使用 Clash Verge Rev 等。
1. 移除 Xray 核心,更新 sing-box。
2. 移除一些没用的功能。
3. 更新文档。
4. 更新部分依赖
5. 移除 macos 遗留
## 下载 / Download ## 下载 / Download
### GitHub Releases (Portable ZIP) ### GitHub Releases (Portable ZIP)
@ -64,7 +54,6 @@ https://matsuridayo.github.io
- Trojan - Trojan
- TUIC ( sing-box ) - TUIC ( sing-box )
- NaïveProxy ( Custom Core ) - NaïveProxy ( Custom Core )
- Hysteria ( Custom Core or sing-box )
- Hysteria2 ( Custom Core or sing-box ) - Hysteria2 ( Custom Core or sing-box )
- Custom Outbound - Custom Outbound
- Custom Config - Custom Config

View File

@ -1,18 +0,0 @@
{
"title": "nekoray",
"icon": "res/nekoray.icns",
"contents": [
{
"x": 448,
"y": 344,
"type": "link",
"path": "/Applications"
},
{
"x": 192,
"y": 344,
"type": "file",
"path": "build/nekoray.app"
}
]
}

View File

@ -4,12 +4,12 @@ set(PLATFORM_LIBRARIES wininet wsock32 ws2_32 user32 rasapi32 iphlpapi)
include(cmake/windows/generate_product_version.cmake) include(cmake/windows/generate_product_version.cmake)
generate_product_version( generate_product_version(
QV2RAY_RC QV2RAY_RC
ICON "${CMAKE_SOURCE_DIR}/res/nekoray.ico" ICON "${CMAKE_SOURCE_DIR}/res/nekobox.ico"
NAME "nekoray" NAME "nekobox"
BUNDLE "nekoray" BUNDLE "nekobox"
COMPANY_NAME "nekoray" COMPANY_NAME "nekobox"
COMPANY_COPYRIGHT "nekoray" COMPANY_COPYRIGHT "nekobox"
FILE_DESCRIPTION "nekoray" FILE_DESCRIPTION "nekobox"
) )
add_definitions(-DUNICODE -D_UNICODE -DNOMINMAX) add_definitions(-DUNICODE -D_UNICODE -DNOMINMAX)
set(GUI_TYPE WIN32) set(GUI_TYPE WIN32)

View File

@ -22,30 +22,48 @@ namespace NekoGui {
} }
QString genTunName() { QString genTunName() {
auto tun_name = "nekoray-tun"; auto tun_name = "neko-tun";
#ifdef Q_OS_MACOS #ifdef Q_OS_MACOS
tun_name = "utun9"; tun_name = "utun9";
#endif #endif
return tun_name; return tun_name;
} }
void MergeJson(const QJsonObject &custom, QJsonObject &outbound) { void MergeJson(QJsonObject &dst, const QJsonObject &src) {
// 合并 // 合并
if (custom.isEmpty()) return; if (src.isEmpty()) return;
for (const auto &key: custom.keys()) { for (const auto &key: src.keys()) {
if (outbound.contains(key)) { auto v_src = src[key];
auto v = custom[key]; if (dst.contains(key)) {
auto v_orig = outbound[key]; auto v_dst = dst[key];
if (v.isObject() && v_orig.isObject()) { // isObject 则合并? if (v_src.isObject() && v_dst.isObject()) { // isObject 则合并?
auto vo = v.toObject(); auto v_src_obj = v_src.toObject();
QJsonObject vo_orig = v_orig.toObject(); auto v_dst_obj = v_dst.toObject();
MergeJson(vo, vo_orig); MergeJson(v_dst_obj, v_src_obj);
outbound[key] = vo_orig; dst[key] = v_dst_obj;
} else { } else {
outbound[key] = v; dst[key] = v_src;
}
} else if (v_src.isArray()) {
if (key.startsWith("+")) {
auto key2 = SubStrAfter(key, "+");
auto v_dst = dst[key2];
auto v_src_arr = v_src.toArray();
auto v_dst_arr = v_dst.toArray();
QJSONARRAY_ADD(v_src_arr, v_dst_arr)
dst[key2] = v_src_arr;
} else if (key.endsWith("+")) {
auto key2 = SubStrBefore(key, "+");
auto v_dst = dst[key2];
auto v_src_arr = v_src.toArray();
auto v_dst_arr = v_dst.toArray();
QJSONARRAY_ADD(v_dst_arr, v_src_arr)
dst[key2] = v_dst_arr;
} else {
dst[key] = v_src;
} }
} else { } else {
outbound[key] = custom[key]; dst[key] = v_src;
} }
} }
} }
@ -64,15 +82,11 @@ namespace NekoGui {
if (customBean != nullptr && customBean->core == "internal-full") { if (customBean != nullptr && customBean->core == "internal-full") {
result->coreConfig = QString2QJsonObject(customBean->config_simple); result->coreConfig = QString2QJsonObject(customBean->config_simple);
} else { } else {
if (IS_NEKO_BOX) { BuildConfigSingBox(status);
BuildConfigSingBox(status);
} else {
BuildConfigV2Ray(status);
}
} }
// apply custom config // apply custom config
MergeJson(QString2QJsonObject(ent->bean->custom_config), result->coreConfig); MergeJson(result->coreConfig, QString2QJsonObject(ent->bean->custom_config));
return result; return result;
} }
@ -80,7 +94,7 @@ namespace NekoGui {
QString BuildChain(int chainId, const std::shared_ptr<BuildConfigStatus> &status) { QString BuildChain(int chainId, const std::shared_ptr<BuildConfigStatus> &status) {
auto group = profileManager->GetGroup(status->ent->gid); auto group = profileManager->GetGroup(status->ent->gid);
if (group == nullptr) { if (group == nullptr) {
status->result->error = QString("This profile is not in any group, your data may be corrupted."); status->result->error = QStringLiteral("This profile is not in any group, your data may be corrupted.");
return {}; return {};
} }
@ -92,11 +106,11 @@ namespace NekoGui {
for (auto id: list) { for (auto id: list) {
resolved += profileManager->GetProfile(id); resolved += profileManager->GetProfile(id);
if (resolved.last() == nullptr) { if (resolved.last() == nullptr) {
status->result->error = QString("chain missing ent: %1").arg(id); status->result->error = QStringLiteral("chain missing ent: %1").arg(id);
break; break;
} }
if (resolved.last()->type == "chain") { if (resolved.last()->type == "chain") {
status->result->error = QString("chain in chain is not allowed: %1").arg(id); status->result->error = QStringLiteral("chain in chain is not allowed: %1").arg(id);
break; break;
} }
} }
@ -113,7 +127,7 @@ namespace NekoGui {
if (group->front_proxy_id >= 0) { if (group->front_proxy_id >= 0) {
auto fEnt = profileManager->GetProfile(group->front_proxy_id); auto fEnt = profileManager->GetProfile(group->front_proxy_id);
if (fEnt == nullptr) { if (fEnt == nullptr) {
status->result->error = QString("front proxy ent not found."); status->result->error = QStringLiteral("front proxy ent not found.");
return {}; return {};
} }
ents += resolveChain(fEnt); ents += resolveChain(fEnt);
@ -157,254 +171,6 @@ namespace NekoGui {
status->ipListDirect += line; \ status->ipListDirect += line; \
} }
// V2Ray
void BuildConfigV2Ray(const std::shared_ptr<BuildConfigStatus> &status) {
// Log
auto logObj = QJsonObject{{"loglevel", dataStore->log_level}};
status->result->coreConfig.insert("log", logObj);
// Inbounds
QJsonObject sniffing{
{"destOverride", QJsonArray{"http", "tls", "quic"}},
{"enabled", true},
{"metadataOnly", false},
{"routeOnly", dataStore->routing->sniffing_mode == SniffingMode::FOR_ROUTING},
};
// socks-in
if (IsValidPort(dataStore->inbound_socks_port) && !status->forTest) {
QJsonObject inboundObj;
inboundObj["tag"] = "socks-in";
inboundObj["protocol"] = "socks";
inboundObj["listen"] = dataStore->inbound_address;
inboundObj["port"] = dataStore->inbound_socks_port;
QJsonObject socksSettings = {{"udp", true}};
if (dataStore->routing->sniffing_mode != SniffingMode::DISABLE) {
inboundObj["sniffing"] = sniffing;
}
if (dataStore->inbound_auth->NeedAuth()) {
socksSettings["auth"] = "password";
socksSettings["accounts"] = QJsonArray{
QJsonObject{
{"user", dataStore->inbound_auth->username},
{"pass", dataStore->inbound_auth->password},
},
};
}
inboundObj["settings"] = socksSettings;
status->inbounds += inboundObj;
}
// http-in
if (IsValidPort(dataStore->inbound_http_port) && !status->forTest) {
QJsonObject inboundObj;
inboundObj["tag"] = "http-in";
inboundObj["protocol"] = "http";
inboundObj["listen"] = dataStore->inbound_address;
inboundObj["port"] = dataStore->inbound_http_port;
if (dataStore->routing->sniffing_mode != SniffingMode::DISABLE) {
inboundObj["sniffing"] = sniffing;
}
if (dataStore->inbound_auth->NeedAuth()) {
inboundObj["settings"] = QJsonObject{
{"accounts", QJsonArray{
QJsonObject{
{"user", dataStore->inbound_auth->username},
{"pass", dataStore->inbound_auth->password},
},
}},
};
}
status->inbounds += inboundObj;
}
// Outbounds
auto tagProxy = BuildChain(0, status);
if (!status->result->error.isEmpty()) return;
// direct & bypass & block
status->outbounds += QJsonObject{
{"protocol", "freedom"},
{"domainStrategy", dataStore->core_ray_freedom_domainStrategy},
{"tag", "direct"},
};
status->outbounds += QJsonObject{
{"protocol", "freedom"},
{"domainStrategy", dataStore->core_ray_freedom_domainStrategy},
{"tag", "bypass"},
};
status->outbounds += QJsonObject{
{"protocol", "blackhole"},
{"tag", "block"},
};
// DNS out
if (!status->forTest) {
QJsonObject dnsOut;
dnsOut["protocol"] = "dns";
dnsOut["tag"] = "dns-out";
QJsonObject dnsOut_settings;
dnsOut_settings["network"] = "tcp";
dnsOut_settings["port"] = 53;
dnsOut_settings["address"] = "8.8.8.8";
dnsOut_settings["userLevel"] = 1;
dnsOut["settings"] = dnsOut_settings;
dnsOut["proxySettings"] = QJsonObject{{"tag", tagProxy},
{"transportLayer", true}};
status->outbounds += dnsOut;
status->routingRules += QJsonObject{
{"type", "field"},
{"port", "53"},
{"inboundTag", QJsonArray{"socks-in", "http-in"}},
{"outboundTag", "dns-out"},
};
}
// custom inbound
if (!status->forTest) QJSONARRAY_ADD(status->inbounds, QString2QJsonObject(dataStore->custom_inbound)["inbounds"].toArray())
status->result->coreConfig.insert("inbounds", status->inbounds);
status->result->coreConfig.insert("outbounds", status->outbounds);
// user rule
if (!status->forTest) {
DOMAIN_USER_RULE
IP_USER_RULE
}
// final add DNS
QJsonObject dns;
QJsonArray dnsServers;
// Remote or FakeDNS
QJsonObject dnsServerRemote;
dnsServerRemote["address"] = dataStore->routing->remote_dns;
dnsServerRemote["domains"] = QList2QJsonArray<QString>(status->domainListDNSRemote);
dnsServerRemote["queryStrategy"] = dataStore->routing->remote_dns_strategy;
if (!status->forTest) dnsServers += dnsServerRemote;
// Direct
auto directDnsAddress = dataStore->routing->direct_dns;
if (directDnsAddress.contains("://")) {
auto directDnsIp = SubStrBefore(SubStrAfter(directDnsAddress, "://"), "/");
if (IsIpAddress(directDnsIp)) {
status->routingRules.push_front(QJsonObject{
{"type", "field"},
{"ip", QJsonArray{directDnsIp}},
{"outboundTag", "direct"},
});
} else {
status->routingRules.push_front(QJsonObject{
{"type", "field"},
{"domain", QJsonArray{directDnsIp}},
{"outboundTag", "direct"},
});
}
} else if (directDnsAddress != "localhost") {
status->routingRules.push_front(QJsonObject{
{"type", "field"},
{"ip", QJsonArray{directDnsAddress}},
{"outboundTag", "direct"},
});
}
QJsonObject directObj{
{"address", directDnsAddress.replace("https://", "https+local://")},
{"queryStrategy", dataStore->routing->direct_dns_strategy},
{"domains", QList2QJsonArray<QString>(status->domainListDNSDirect)},
};
if (dataStore->routing->dns_final_out == "bypass") {
dnsServers.prepend(directObj);
} else {
dnsServers.append(directObj);
}
dns["disableFallback"] = true;
dns["servers"] = dnsServers;
dns["tag"] = "dns";
if (dataStore->routing->use_dns_object) {
dns = QString2QJsonObject(dataStore->routing->dns_object);
}
status->result->coreConfig.insert("dns", dns);
// Routing
QJsonObject routing;
routing["domainStrategy"] = dataStore->routing->domain_strategy;
if (status->forTest) routing["domainStrategy"] = "AsIs";
// final add user rule (block)
QJsonObject routingRule_tmp;
routingRule_tmp["type"] = "field";
routingRule_tmp["outboundTag"] = "block";
if (!status->ipListBlock.isEmpty()) {
auto tmp = routingRule_tmp;
tmp["ip"] = QList2QJsonArray<QString>(status->ipListBlock);
status->routingRules += tmp;
}
if (!status->domainListBlock.isEmpty()) {
auto tmp = routingRule_tmp;
tmp["domain"] = QList2QJsonArray<QString>(status->domainListBlock);
status->routingRules += tmp;
}
// final add user rule (proxy)
routingRule_tmp["outboundTag"] = "proxy";
if (!status->ipListRemote.isEmpty()) {
auto tmp = routingRule_tmp;
tmp["ip"] = QList2QJsonArray<QString>(status->ipListRemote);
status->routingRules += tmp;
}
if (!status->domainListRemote.isEmpty()) {
auto tmp = routingRule_tmp;
tmp["domain"] = QList2QJsonArray<QString>(status->domainListRemote);
status->routingRules += tmp;
}
// final add user rule (bypass)
routingRule_tmp["outboundTag"] = "bypass";
if (!status->ipListDirect.isEmpty()) {
auto tmp = routingRule_tmp;
tmp["ip"] = QList2QJsonArray<QString>(status->ipListDirect);
status->routingRules += tmp;
}
if (!status->domainListDirect.isEmpty()) {
auto tmp = routingRule_tmp;
tmp["domain"] = QList2QJsonArray<QString>(status->domainListDirect);
status->routingRules += tmp;
}
// def_outbound
if (!status->forTest) status->routingRules += QJsonObject{
{"type", "field"},
{"port", "0-65535"},
{"outboundTag", dataStore->routing->def_outbound},
};
// final add routing rule
auto routingRules = QString2QJsonObject(dataStore->routing->custom)["rules"].toArray();
if (status->forTest) routingRules = {};
if (!status->forTest) QJSONARRAY_ADD(routingRules, QString2QJsonObject(dataStore->custom_route_global)["rules"].toArray())
QJSONARRAY_ADD(routingRules, status->routingRules)
routing["rules"] = routingRules;
status->result->coreConfig.insert("routing", routing);
// Policy & stats
QJsonObject policy;
QJsonObject levels;
QJsonObject level1;
level1["connIdle"] = 30;
levels["1"] = level1;
policy["levels"] = levels;
QJsonObject policySystem;
policySystem["statsOutboundDownlink"] = true;
policySystem["statsOutboundUplink"] = true;
policy["system"] = policySystem;
status->result->coreConfig.insert("policy", policy);
status->result->coreConfig.insert("stats", QJsonObject());
}
QString BuildChainInternal(int chainId, const QList<std::shared_ptr<ProxyEntity>> &ents, QString BuildChainInternal(int chainId, const QList<std::shared_ptr<ProxyEntity>> &ents,
const std::shared_ptr<BuildConfigStatus> &status) { const std::shared_ptr<BuildConfigStatus> &status) {
QString chainTag = "c-" + Int2String(chainId); QString chainTag = "c-" + Int2String(chainId);
@ -454,29 +220,14 @@ namespace NekoGui {
// chain rules: past // chain rules: past
if (pastExternalStat == 0) { if (pastExternalStat == 0) {
auto replaced = status->outbounds.last().toObject(); auto replaced = status->outbounds.last().toObject();
if (IS_NEKO_BOX) { replaced["detour"] = tagOut;
replaced["detour"] = tagOut;
} else {
replaced["proxySettings"] = QJsonObject{
{"tag", tagOut},
{"transportLayer", true},
};
}
status->outbounds.removeLast(); status->outbounds.removeLast();
status->outbounds += replaced; status->outbounds += replaced;
} else { } else {
if (IS_NEKO_BOX) { status->routingRules += QJsonObject{
status->routingRules += QJsonObject{ {"inbound", QJsonArray{pastTag + "-mapping"}},
{"inbound", QJsonArray{pastTag + "-mapping"}}, {"outbound", tagOut},
{"outbound", tagOut}, };
};
} else {
status->routingRules += QJsonObject{
{"type", "field"},
{"inboundTag", QJsonArray{pastTag + "-mapping"}},
{"outboundTag", tagOut},
};
}
} }
} else { } else {
// index == 0 means last profile in chain / not chain // index == 0 means last profile in chain / not chain
@ -515,43 +266,20 @@ namespace NekoGui {
if (thisExternalStat == 2) dataStore->need_keep_vpn_off = true; if (thisExternalStat == 2) dataStore->need_keep_vpn_off = true;
if (thisExternalStat == 1) { if (thisExternalStat == 1) {
// mapping // mapping
if (IS_NEKO_BOX) { status->inbounds += QJsonObject{
status->inbounds += QJsonObject{ {"type", "direct"},
{"type", "direct"}, {"tag", tagOut + "-mapping"},
{"tag", tagOut + "-mapping"}, {"listen", "127.0.0.1"},
{"listen", "127.0.0.1"}, {"listen_port", ext_mapping_port},
{"listen_port", ext_mapping_port}, {"override_address", ent->bean->serverAddress},
{"override_address", ent->bean->serverAddress}, {"override_port", ent->bean->serverPort},
{"override_port", ent->bean->serverPort}, };
};
} else {
status->inbounds += QJsonObject{
{"protocol", "dokodemo-door"},
{"tag", tagOut + "-mapping"},
{"listen", "127.0.0.1"},
{"port", ext_mapping_port},
{"settings", QJsonObject{
// to
{"address", ent->bean->serverAddress},
{"port", ent->bean->serverPort},
{"network", "tcp,udp"},
}},
};
}
// no chain rule and not outbound, so need to set to direct // no chain rule and not outbound, so need to set to direct
if (isFirstProfile) { if (isFirstProfile) {
if (IS_NEKO_BOX) { status->routingRules += QJsonObject{
status->routingRules += QJsonObject{ {"inbound", QJsonArray{tagOut + "-mapping"}},
{"inbound", QJsonArray{tagOut + "-mapping"}}, {"outbound", "direct"},
{"outbound", "direct"}, };
};
} else {
status->routingRules += QJsonObject{
{"type", "field"},
{"inboundTag", QJsonArray{tagOut + "-mapping"}},
{"outboundTag", "direct"},
};
}
} }
} }
@ -574,23 +302,11 @@ namespace NekoGui {
status->result->extRs.emplace_back(std::make_shared<NekoGui_fmt::ExternalBuildResult>(extR)); status->result->extRs.emplace_back(std::make_shared<NekoGui_fmt::ExternalBuildResult>(extR));
// SOCKS OUTBOUND // SOCKS OUTBOUND
if (IS_NEKO_BOX) { outbound["type"] = "socks";
outbound["type"] = "socks"; outbound["server"] = "127.0.0.1";
outbound["server"] = "127.0.0.1"; outbound["server_port"] = ext_socks_port;
outbound["server_port"] = ext_socks_port;
} else {
outbound["protocol"] = "socks";
QJsonObject settings;
QJsonArray servers;
QJsonObject server;
server["address"] = "127.0.0.1";
server["port"] = ext_socks_port;
servers.push_back(server);
settings["servers"] = servers;
outbound["settings"] = settings;
}
} else { } else {
const auto coreR = IS_NEKO_BOX ? ent->bean->BuildCoreObjSingBox() : ent->bean->BuildCoreObjV2Ray(); const auto coreR = ent->bean->BuildCoreObjSingBox();
if (coreR.outbound.isEmpty()) { if (coreR.outbound.isEmpty()) {
status->result->error = "unsupported outbound"; status->result->error = "unsupported outbound";
return {}; return {};
@ -613,14 +329,8 @@ namespace NekoGui {
needMux &= dataStore->mux_concurrency > 0; needMux &= dataStore->mux_concurrency > 0;
if (stream != nullptr) { if (stream != nullptr) {
if (IS_NEKO_BOX) { if (stream->network == "grpc" || stream->network == "quic" || (stream->network == "http" && stream->security == "tls")) {
if (stream->network == "grpc" || stream->network == "quic" || (stream->network == "http" && stream->security == "tls")) { needMux = false;
needMux = false;
}
} else {
if (stream->network == "grpc" || stream->network == "quic") {
needMux = false;
}
} }
if (stream->multiplex_status == 0) { if (stream->multiplex_status == 0) {
if (!dataStore->mux_default_on) needMux = false; if (!dataStore->mux_default_on) needMux = false;
@ -635,36 +345,22 @@ namespace NekoGui {
} }
// common // common
if (IS_NEKO_BOX) { // apply domain_strategy
// apply domain_strategy outbound["domain_strategy"] = dataStore->routing->outbound_domain_strategy;
outbound["domain_strategy"] = dataStore->routing->outbound_domain_strategy; // apply mux
// apply mux if (!muxApplied && needMux) {
if (!muxApplied && needMux) { auto muxObj = QJsonObject{
auto muxObj = QJsonObject{ {"enabled", true},
{"enabled", true}, {"protocol", dataStore->mux_protocol},
{"protocol", dataStore->mux_protocol}, {"padding", dataStore->mux_padding},
{"padding", dataStore->mux_padding}, {"max_streams", dataStore->mux_concurrency},
{"max_streams", dataStore->mux_concurrency}, };
}; outbound["multiplex"] = muxObj;
outbound["multiplex"] = muxObj; muxApplied = true;
muxApplied = true;
}
} else {
// apply domain_strategy
if (!status->forTest) outbound["domainStrategy"] = dataStore->routing->outbound_domain_strategy;
// apply mux
if (!muxApplied && needMux) {
auto muxObj = QJsonObject{
{"enabled", true},
{"concurrency", dataStore->mux_concurrency},
};
outbound["mux"] = muxObj;
muxApplied = true;
}
} }
// apply custom outbound settings // apply custom outbound settings
MergeJson(QString2QJsonObject(ent->bean->custom_outbound), outbound); MergeJson(outbound, QString2QJsonObject(ent->bean->custom_outbound));
// Bypass Lookup for the first profile // Bypass Lookup for the first profile
auto serverAddress = ent->bean->serverAddress; auto serverAddress = ent->bean->serverAddress;
@ -720,7 +416,7 @@ namespace NekoGui {
} }
// tun-in // tun-in
if (IS_NEKO_BOX_INTERNAL_TUN && dataStore->spmode_vpn && !status->forTest) { if (dataStore->vpn_internal_tun && dataStore->spmode_vpn && !status->forTest) {
QJsonObject inboundObj; QJsonObject inboundObj;
inboundObj["tag"] = "tun-in"; inboundObj["tag"] = "tun-in";
inboundObj["type"] = "tun"; inboundObj["type"] = "tun";
@ -808,7 +504,7 @@ namespace NekoGui {
} else if (item.startsWith("keyword:")) { } else if (item.startsWith("keyword:")) {
domain_keyword += item.replace("keyword:", "").toLower(); domain_keyword += item.replace("keyword:", "").toLower();
} else { } else {
domain_full += item.toLower(); domain_subdomain += item.toLower();
} }
} }
} }
@ -845,21 +541,22 @@ namespace NekoGui {
}; };
// Direct // Direct
auto directDNSAddress = dataStore->routing->direct_dns; QJsonObject directObj{
if (!status->forTest) { {"tag", "dns-direct"},
QJsonObject directObj{ {"address_resolver", "dns-local"},
{"tag", "dns-direct"}, {"strategy", dataStore->routing->direct_dns_strategy},
{"address_resolver", "dns-local"}, {"address", dataStore->routing->direct_dns},
{"strategy", dataStore->routing->direct_dns_strategy}, {"detour", "direct"},
{"address", directDNSAddress.replace("+local://", "://")}, };
{"detour", "direct"}, if (dataStore->routing->dns_final_out == "bypass") {
}; dnsServers.prepend(directObj);
if (dataStore->routing->dns_final_out == "bypass") { } else {
dnsServers.prepend(directObj); dnsServers.append(directObj);
} else {
dnsServers.append(directObj);
}
} }
dnsRules.append(QJsonObject{
{"outbound", "any"},
{"server", "dns-direct"},
});
// block // block
if (!status->forTest) if (!status->forTest)
@ -869,7 +566,7 @@ namespace NekoGui {
}; };
// Fakedns // Fakedns
if (dataStore->fake_dns && IS_NEKO_BOX_INTERNAL_TUN && dataStore->spmode_vpn && !status->forTest) { if (dataStore->fake_dns && dataStore->vpn_internal_tun && dataStore->spmode_vpn && !status->forTest) {
dnsServers += QJsonObject{ dnsServers += QJsonObject{
{"tag", "dns-fake"}, {"tag", "dns-fake"},
{"address", "fakeip"}, {"address", "fakeip"},
@ -911,7 +608,7 @@ namespace NekoGui {
} }
// fakedns rule // fakedns rule
if (dataStore->fake_dns && IS_NEKO_BOX_INTERNAL_TUN && dataStore->spmode_vpn && !status->forTest) { if (dataStore->fake_dns && dataStore->vpn_internal_tun && dataStore->spmode_vpn && !status->forTest) {
dnsRules += QJsonObject{ dnsRules += QJsonObject{
{"inbound", "tun-in"}, {"inbound", "tun-in"},
{"server", "dns-fake"}, {"server", "dns-fake"},
@ -969,7 +666,7 @@ namespace NekoGui {
}; };
// tun user rule // tun user rule
if (IS_NEKO_BOX_INTERNAL_TUN && dataStore->spmode_vpn && !status->forTest) { if (dataStore->vpn_internal_tun && dataStore->spmode_vpn && !status->forTest) {
auto match_out = dataStore->vpn_rule_white ? "proxy" : "bypass"; auto match_out = dataStore->vpn_rule_white ? "proxy" : "bypass";
QString process_name_rule = dataStore->vpn_rule_process.trimmed(); QString process_name_rule = dataStore->vpn_rule_process.trimmed();
@ -1009,7 +706,7 @@ namespace NekoGui {
QJSONARRAY_ADD(routingRules, status->routingRules) QJSONARRAY_ADD(routingRules, status->routingRules)
auto routeObj = QJsonObject{ auto routeObj = QJsonObject{
{"rules", routingRules}, {"rules", routingRules},
{"auto_detect_interface", dataStore->spmode_vpn}, {"auto_detect_interface", dataStore->spmode_vpn}, // TODO force enable?
{ {
"geoip", "geoip",
QJsonObject{ QJsonObject{
@ -1047,8 +744,8 @@ namespace NekoGui {
QString WriteVPNSingBoxConfig() { QString WriteVPNSingBoxConfig() {
// tun user rule // tun user rule
auto match_out = dataStore->vpn_rule_white ? "nekoray-socks" : "direct"; auto match_out = dataStore->vpn_rule_white ? "neko-socks" : "direct";
auto no_match_out = dataStore->vpn_rule_white ? "direct" : "nekoray-socks"; auto no_match_out = dataStore->vpn_rule_white ? "direct" : "neko-socks";
QString process_name_rule = dataStore->vpn_rule_process.trimmed(); QString process_name_rule = dataStore->vpn_rule_process.trimmed();
if (!process_name_rule.isEmpty()) { if (!process_name_rule.isEmpty()) {
@ -1099,7 +796,7 @@ namespace NekoGui {
return QFileInfo(file).absoluteFilePath(); return QFileInfo(file).absoluteFilePath();
} }
QString WriteVPNLinuxScript(const QString &protectPath, const QString &configPath) { QString WriteVPNLinuxScript(const QString &configPath) {
#ifdef Q_OS_WIN #ifdef Q_OS_WIN
return {}; return {};
#endif #endif
@ -1108,9 +805,7 @@ namespace NekoGui {
if (QFile::exists("vpn/vpn-run-root.sh")) scriptFn = "vpn/vpn-run-root.sh"; if (QFile::exists("vpn/vpn-run-root.sh")) scriptFn = "vpn/vpn-run-root.sh";
auto script = ReadFileText(scriptFn) auto script = ReadFileText(scriptFn)
.replace("./nekobox_core", QApplication::applicationDirPath() + "/nekobox_core") .replace("./nekobox_core", QApplication::applicationDirPath() + "/nekobox_core")
.replace("$PROTECT_LISTEN_PATH", protectPath) .replace("$CONFIG_PATH", configPath);
.replace("$CONFIG_PATH", configPath)
.replace("$TABLE_FWMARK", "514");
// write script // write script
QFile file2; QFile file2;
file2.setFileName(QFileInfo(scriptFn).fileName()); file2.setFileName(QFileInfo(scriptFn).fileName());
@ -1120,4 +815,4 @@ namespace NekoGui {
return QFileInfo(file2).absoluteFilePath(); return QFileInfo(file2).absoluteFilePath();
} }
} // namespace NekoGui } // namespace NekoGui

View File

@ -46,8 +46,6 @@ namespace NekoGui {
std::shared_ptr<BuildConfigResult> BuildConfig(const std::shared_ptr<ProxyEntity> &ent, bool forTest, bool forExport); std::shared_ptr<BuildConfigResult> BuildConfig(const std::shared_ptr<ProxyEntity> &ent, bool forTest, bool forExport);
void BuildConfigV2Ray(const std::shared_ptr<BuildConfigStatus> &status);
void BuildConfigSingBox(const std::shared_ptr<BuildConfigStatus> &status); void BuildConfigSingBox(const std::shared_ptr<BuildConfigStatus> &status);
QString BuildChain(int chainId, const std::shared_ptr<BuildConfigStatus> &status); QString BuildChain(int chainId, const std::shared_ptr<BuildConfigStatus> &status);
@ -57,5 +55,5 @@ namespace NekoGui {
QString WriteVPNSingBoxConfig(); QString WriteVPNSingBoxConfig();
QString WriteVPNLinuxScript(const QString &protectPath, const QString &configPath); QString WriteVPNLinuxScript(const QString &configPath);
} // namespace NekoGui } // namespace NekoGui

View File

@ -42,7 +42,7 @@ namespace NekoGui {
// Load Proxys // Load Proxys
QList<int> delProfile; QList<int> delProfile;
for (auto id: profilesIdOrder) { for (auto id: profilesIdOrder) {
auto ent = LoadProxyEntity(QString("profiles/%1.json").arg(id)); auto ent = LoadProxyEntity(QStringLiteral("profiles/%1.json").arg(id));
// Corrupted profile? // Corrupted profile?
if (ent == nullptr || ent->bean == nullptr || ent->bean->version == -114514) { if (ent == nullptr || ent->bean == nullptr || ent->bean->version == -114514) {
delProfile << id; delProfile << id;
@ -58,7 +58,7 @@ namespace NekoGui {
auto loadedOrder = groupsTabOrder; auto loadedOrder = groupsTabOrder;
groupsTabOrder = {}; groupsTabOrder = {};
for (auto id: groupsIdOrder) { for (auto id: groupsIdOrder) {
auto ent = LoadGroup(QString("groups/%1.json").arg(id)); auto ent = LoadGroup(QStringLiteral("groups/%1.json").arg(id));
// Corrupted group? // Corrupted group?
if (ent->id != id) { if (ent->id != id) {
continue; continue;
@ -103,7 +103,7 @@ namespace NekoGui {
auto newId = i++; auto newId = i++;
profile->id = newId; profile->id = newId;
profile->gid = gidOld2New[gid]; profile->gid = gidOld2New[gid];
profile->fn = QString("profiles/%1.json").arg(newId); profile->fn = QStringLiteral("profiles/%1.json").arg(newId);
profile->Save(); profile->Save();
newProfiles[newId] = profile; newProfiles[newId] = profile;
newProfilesIdOrder << newId; newProfilesIdOrder << newId;
@ -122,7 +122,7 @@ namespace NekoGui {
auto group = groups[oldGid]; auto group = groups[oldGid];
QFile::remove(group->fn); QFile::remove(group->fn);
group->id = newId; group->id = newId;
group->fn = QString("groups/%1.json").arg(newId); group->fn = QStringLiteral("groups/%1.json").arg(newId);
group->Save(); group->Save();
newGroups[newId] = group; newGroups[newId] = group;
newGroupsIdOrder << newId; newGroupsIdOrder << newId;
@ -184,8 +184,6 @@ namespace NekoGui {
bean = new NekoGui_fmt::TrojanVLESSBean(NekoGui_fmt::TrojanVLESSBean::proxy_VLESS); bean = new NekoGui_fmt::TrojanVLESSBean(NekoGui_fmt::TrojanVLESSBean::proxy_VLESS);
} else if (type == "naive") { } else if (type == "naive") {
bean = new NekoGui_fmt::NaiveBean(); bean = new NekoGui_fmt::NaiveBean();
} else if (type == "hysteria") {
bean = new NekoGui_fmt::QUICBean(NekoGui_fmt::QUICBean::proxy_Hysteria);
} else if (type == "hysteria2") { } else if (type == "hysteria2") {
bean = new NekoGui_fmt::QUICBean(NekoGui_fmt::QUICBean::proxy_Hysteria2); bean = new NekoGui_fmt::QUICBean(NekoGui_fmt::QUICBean::proxy_Hysteria2);
} else if (type == "tuic") { } else if (type == "tuic") {
@ -229,7 +227,7 @@ namespace NekoGui {
if (latency < 0) { if (latency < 0) {
return QObject::tr("Unavailable"); return QObject::tr("Unavailable");
} else if (latency > 0) { } else if (latency > 0) {
return UNICODE_LRO + QString("%1 ms").arg(latency); return UNICODE_LRO + QStringLiteral("%1 ms").arg(latency);
} else { } else {
return ""; return "";
} }
@ -270,7 +268,7 @@ namespace NekoGui {
profiles[ent->id] = ent; profiles[ent->id] = ent;
profilesIdOrder.push_back(ent->id); profilesIdOrder.push_back(ent->id);
ent->fn = QString("profiles/%1.json").arg(ent->id); ent->fn = QStringLiteral("profiles/%1.json").arg(ent->id);
ent->Save(); ent->Save();
return true; return true;
} }
@ -280,7 +278,7 @@ namespace NekoGui {
if (dataStore->started_id == id) return; if (dataStore->started_id == id) return;
profiles.erase(id); profiles.erase(id);
profilesIdOrder.removeAll(id); profilesIdOrder.removeAll(id);
QFile(QString("profiles/%1.json").arg(id)).remove(); QFile(QStringLiteral("profiles/%1.json").arg(id)).remove();
} }
void ProfileManager::MoveProfile(const std::shared_ptr<ProxyEntity> &ent, int gid) { void ProfileManager::MoveProfile(const std::shared_ptr<ProxyEntity> &ent, int gid) {
@ -344,7 +342,7 @@ namespace NekoGui {
groupsIdOrder.push_back(ent->id); groupsIdOrder.push_back(ent->id);
groupsTabOrder.push_back(ent->id); groupsTabOrder.push_back(ent->id);
ent->fn = QString("groups/%1.json").arg(ent->id); ent->fn = QStringLiteral("groups/%1.json").arg(ent->id);
ent->Save(); ent->Save();
return true; return true;
} }
@ -361,7 +359,7 @@ namespace NekoGui {
groups.erase(gid); groups.erase(gid);
groupsIdOrder.removeAll(gid); groupsIdOrder.removeAll(gid);
groupsTabOrder.removeAll(gid); groupsTabOrder.removeAll(gid);
QFile(QString("groups/%1.json").arg(gid)).remove(); QFile(QStringLiteral("groups/%1.json").arg(gid)).remove();
} }
std::shared_ptr<Group> ProfileManager::GetGroup(int id) { std::shared_ptr<Group> ProfileManager::GetGroup(int id) {
@ -393,4 +391,4 @@ namespace NekoGui {
} }
} }
} // namespace NekoGui } // namespace NekoGui

View File

@ -29,12 +29,12 @@ namespace NekoGui_traffic {
} }
[[nodiscard]] QString DisplaySpeed() const { [[nodiscard]] QString DisplaySpeed() const {
return UNICODE_LRO + QString("%1↑ %2↓").arg(ReadableSize(uplink_rate), ReadableSize(downlink_rate)); return UNICODE_LRO + QStringLiteral("%1↑ %2↓").arg(ReadableSize(uplink_rate), ReadableSize(downlink_rate));
} }
[[nodiscard]] QString DisplayTraffic() const { [[nodiscard]] QString DisplayTraffic() const {
if (downlink + uplink == 0) return ""; if (downlink + uplink == 0) return "";
return UNICODE_LRO + QString("%1↑ %2↓").arg(ReadableSize(uplink), ReadableSize(downlink)); return UNICODE_LRO + QStringLiteral("%1↑ %2↓").arg(ReadableSize(uplink), ReadableSize(downlink));
} }
}; };
} // namespace NekoGui_traffic } // namespace NekoGui_traffic

View File

@ -22,9 +22,9 @@ cmake -GNinja ..
ninja ninja
``` ```
编译完成后得到 `nekoray` 编译完成后得到 `nekobox`
解压 Release 的压缩包,替换其中的 `nekoray`,删除 `launcher` 即可使用。 解压 Release 的压缩包,替换其中的 `nekobox`,删除 `launcher` 即可使用。
## 复杂编译法 ## 复杂编译法
@ -69,7 +69,7 @@ cmake -GNinja ..
ninja ninja
``` ```
编译完成后得到 `nekoray` 编译完成后得到 `nekobox`
### Go 部分编译 ### Go 部分编译

View File

@ -55,9 +55,9 @@ cmake -GNinja -DCMAKE_BUILD_TYPE=Release -DCMAKE_PREFIX_PATH=D:/path/to/qt/5.15.
ninja ninja
``` ```
编译完成后得到 `nekoray.exe` 编译完成后得到 `nekobox.exe`
最后运行 `windeployqt nekoray.exe` 自动复制所需 DLL 等文件到当前目录 最后运行 `windeployqt nekobox.exe` 自动复制所需 DLL 等文件到当前目录
### Go 部分编译 ### Go 部分编译

View File

@ -38,7 +38,7 @@ namespace NekoGui_fmt {
} }
QString AbstractBean::DisplayTypeAndName() { QString AbstractBean::DisplayTypeAndName() {
return QString("[%1] %2").arg(DisplayType(), DisplayName()); return QStringLiteral("[%1] %2").arg(DisplayType(), DisplayName());
} }
void AbstractBean::ResolveDomainToIP(const std::function<void()> &onFinished) { void AbstractBean::ResolveDomainToIP(const std::function<void()> &onFinished) {

View File

@ -59,8 +59,6 @@ namespace NekoGui_fmt {
virtual int NeedExternal(bool isFirstProfile) { return 0; }; virtual int NeedExternal(bool isFirstProfile) { return 0; };
virtual CoreObjOutboundBuildResult BuildCoreObjV2Ray() { return {}; };
virtual CoreObjOutboundBuildResult BuildCoreObjSingBox() { return {}; }; virtual CoreObjOutboundBuildResult BuildCoreObjSingBox() { return {}; };
virtual ExternalBuildResult BuildExternal(int mapping_port, int socks_port, int external_stat) { return {}; }; virtual ExternalBuildResult BuildExternal(int mapping_port, int socks_port, int external_stat) { return {}; };

View File

@ -191,27 +191,12 @@ namespace NekoGui_fmt {
{"tls", coreTlsObj}, {"tls", coreTlsObj},
}; };
if (proxy_type == proxy_Hysteria) { if (proxy_type == proxy_Hysteria2) {
outbound["type"] = "hysteria";
outbound["obfs"] = obfsPassword;
outbound["disable_mtu_discovery"] = disableMtuDiscovery;
outbound["recv_window"] = streamReceiveWindow;
outbound["recv_window_conn"] = connectionReceiveWindow;
outbound["up_mbps"] = uploadMbps;
outbound["down_mbps"] = downloadMbps;
if (!hopPort.trimmed().isEmpty()) {
outbound["hop_ports"] = hopPort;
outbound["hop_interval"] = hopInterval;
}
if (authPayloadType == hysteria_auth_base64) outbound["auth"] = authPayload;
if (authPayloadType == hysteria_auth_string) outbound["auth_str"] = authPayload;
} else if (proxy_type == proxy_Hysteria2) {
outbound["type"] = "hysteria2"; outbound["type"] = "hysteria2";
outbound["password"] = password; outbound["password"] = password;
outbound["up_mbps"] = uploadMbps; outbound["up_mbps"] = uploadMbps;
outbound["down_mbps"] = downloadMbps; outbound["down_mbps"] = downloadMbps;
if (!hopPort.trimmed().isEmpty()) { if (!hopPort.trimmed().isEmpty()) {
outbound["hop_ports"] = hopPort; outbound["hop_ports"] = hopPort;
outbound["hop_interval"] = hopInterval; outbound["hop_interval"] = hopInterval;

View File

@ -1,211 +0,0 @@
#include "db/ProxyEntity.hpp"
#include "fmt/includes.h"
#define MAKE_SETTINGS_STREAM_SETTINGS \
outbound["settings"] = settings; \
auto streamSettings = stream->BuildStreamSettingsV2Ray(); \
outbound["streamSettings"] = streamSettings;
namespace NekoGui_fmt {
QJsonObject V2rayStreamSettings::BuildStreamSettingsV2Ray() {
QJsonObject streamSettings{{"network", network}};
if (network == "ws") {
QJsonObject ws;
if (!host.isEmpty()) ws["headers"] = QJsonObject{{"Host", host}};
// ws path & ed
if (!path.isEmpty()) ws["path"] = path;
streamSettings["wsSettings"] = ws;
} else if (network == "http") {
QJsonObject http;
if (!path.isEmpty()) http["path"] = path;
if (!host.isEmpty()) http["host"] = QList2QJsonArray(host.split(","));
streamSettings["httpSettings"] = http;
} else if (network == "grpc") {
QJsonObject grpc;
if (!path.isEmpty()) grpc["serviceName"] = path;
streamSettings["grpcSettings"] = grpc;
} else if (network == "quic") {
QJsonObject quic;
if (!header_type.isEmpty()) quic["header"] = QJsonObject{{"type", header_type}};
if (!path.isEmpty()) quic["key"] = path;
if (!host.isEmpty()) quic["security"] = host;
streamSettings["quicSettings"] = quic;
} else if (network == "tcp" && !header_type.isEmpty()) {
QJsonObject header{{"type", header_type}};
if (header_type == "http") {
header["request"] = QJsonObject{
{"path", QList2QJsonArray(path.split(","))},
{"headers", QJsonObject{{"Host", QList2QJsonArray(host.split(","))}}},
};
}
streamSettings["tcpSettings"] = QJsonObject{{"header", header}};
}
if (security == "tls") {
QJsonObject tls;
if (!utlsFingerprint.isEmpty()) tls["fingerprint"] = utlsFingerprint;
if (!sni.trimmed().isEmpty()) tls["serverName"] = sni;
if (reality_pbk.trimmed().isEmpty()) {
if (allow_insecure || NekoGui::dataStore->skip_cert) tls["allowInsecure"] = true;
if (!alpn.trimmed().isEmpty()) tls["alpn"] = QList2QJsonArray(alpn.split(","));
if (!certificate.trimmed().isEmpty()) {
tls["disableSystemRoot"] = true;
tls["certificates"] = QJsonArray{
QJsonObject{
{"usage", "verify"},
{"certificate", QList2QJsonArray(SplitLines(certificate.trimmed()))},
},
};
}
streamSettings["tlsSettings"] = tls;
streamSettings["security"] = "tls";
} else {
tls["publicKey"] = reality_pbk;
tls["shortId"] = reality_sid;
tls["spiderX"] = reality_spx;
if (utlsFingerprint.isEmpty()) tls["fingerprint"] = "chrome";
streamSettings["realitySettings"] = tls;
streamSettings["security"] = "reality";
}
}
return streamSettings;
}
CoreObjOutboundBuildResult SocksHttpBean::BuildCoreObjV2Ray() {
CoreObjOutboundBuildResult result;
QJsonObject outbound;
outbound["protocol"] = socks_http_type == type_HTTP ? "http" : "socks";
QJsonObject settings;
QJsonArray servers;
QJsonObject server;
server["address"] = serverAddress;
server["port"] = serverPort;
QJsonArray users;
QJsonObject user;
user["user"] = username;
user["pass"] = password;
users.push_back(user);
if (!username.isEmpty() && !password.isEmpty()) server["users"] = users;
servers.push_back(server);
settings["servers"] = servers;
MAKE_SETTINGS_STREAM_SETTINGS
result.outbound = outbound;
return result;
}
CoreObjOutboundBuildResult ShadowSocksBean::BuildCoreObjV2Ray() {
CoreObjOutboundBuildResult result;
QJsonObject outbound{{"protocol", "shadowsocks"}};
QJsonObject settings;
QJsonArray servers;
QJsonObject server;
server["address"] = serverAddress;
server["port"] = serverPort;
server["method"] = method;
server["password"] = password;
if (uot != 0) {
server["uot"] = true;
server["UoTVersion"] = uot;
} else {
server["uot"] = false;
}
servers.push_back(server);
settings["servers"] = servers;
if (!plugin.trimmed().isEmpty()) {
settings["plugin"] = SubStrBefore(plugin, ";");
settings["pluginOpts"] = SubStrAfter(plugin, ";");
}
MAKE_SETTINGS_STREAM_SETTINGS
result.outbound = outbound;
return result;
}
CoreObjOutboundBuildResult VMessBean::BuildCoreObjV2Ray() {
CoreObjOutboundBuildResult result;
QJsonObject outbound{{"protocol", "vmess"}};
QJsonObject settings{
{"vnext", QJsonArray{
QJsonObject{
{"address", serverAddress},
{"port", serverPort},
{"users", QJsonArray{
QJsonObject{
{"id", uuid.trimmed()},
{"alterId", aid},
{"security", security},
}}},
}}}};
MAKE_SETTINGS_STREAM_SETTINGS
result.outbound = outbound;
return result;
}
CoreObjOutboundBuildResult TrojanVLESSBean::BuildCoreObjV2Ray() {
CoreObjOutboundBuildResult result;
QJsonObject outbound{
{"protocol", proxy_type == proxy_VLESS ? "vless" : "trojan"},
};
QJsonObject settings;
if (proxy_type == proxy_VLESS) {
if (flow == "none") {
flow = "";
}
settings = QJsonObject{
{"vnext", QJsonArray{
QJsonObject{
{"address", serverAddress},
{"port", serverPort},
{"users", QJsonArray{
QJsonObject{
{"id", password.trimmed()},
{"encryption", "none"},
{"flow", flow},
}}},
}}}};
} else {
settings = QJsonObject{
{"servers", QJsonArray{
QJsonObject{
{"address", serverAddress},
{"port", serverPort},
{"password", password},
}}}};
}
MAKE_SETTINGS_STREAM_SETTINGS
result.outbound = outbound;
return result;
}
CoreObjOutboundBuildResult CustomBean::BuildCoreObjV2Ray() {
CoreObjOutboundBuildResult result;
if (core == "internal") {
result.outbound = QString2QJsonObject(config_simple);
}
return result;
}
} // namespace NekoGui_fmt

View File

@ -9,7 +9,7 @@
#define WriteTempFile(fn, data) \ #define WriteTempFile(fn, data) \
QDir dir; \ QDir dir; \
if (!dir.exists("temp")) dir.mkdir("temp"); \ if (!dir.exists("temp")) dir.mkdir("temp"); \
QFile f(QString("temp/") + fn); \ QFile f(QStringLiteral("temp/") + fn); \
bool ok = f.open(QIODevice::WriteOnly | QIODevice::Truncate); \ bool ok = f.open(QIODevice::WriteOnly | QIODevice::Truncate); \
if (ok) { \ if (ok) { \
f.write(data); \ f.write(data); \
@ -36,54 +36,26 @@ namespace NekoGui_fmt {
} }
int QUICBean::NeedExternal(bool isFirstProfile) { int QUICBean::NeedExternal(bool isFirstProfile) {
auto hysteriaCore = [=] { auto extCore = [=] {
if (isFirstProfile) { if (isFirstProfile) {
if (NekoGui::dataStore->spmode_vpn && hyProtocol != hysteria_protocol_facktcp && hopPort.trimmed().isEmpty()) { if (NekoGui::dataStore->spmode_vpn && hopPort.trimmed().isEmpty()) {
return 1; return 1;
} }
return 2; return 2;
} else { } else {
if (hyProtocol == hysteria_protocol_facktcp || !hopPort.trimmed().isEmpty()) { if (!hopPort.trimmed().isEmpty()) {
return -1; return -1;
} }
} }
return 1; return 1;
}; };
auto hysteria2Core = [=] { if (!forceExternal) {
if (isFirstProfile) { // sing-box support
if (NekoGui::dataStore->spmode_vpn) { return 0;
return 1;
}
return 2;
}
return 1;
};
auto tuicCore = [=] {
if (isFirstProfile) {
if (NekoGui::dataStore->spmode_vpn) {
return 1;
}
return 2;
}
return 1;
};
if (IS_NEKO_BOX) {
if (!forceExternal && (proxy_type == proxy_TUIC || hyProtocol == hysteria_protocol_udp)) {
// sing-box support
return 0;
} else {
// hysteria core support
return hysteriaCore();
}
} else if (proxy_type == proxy_TUIC) {
return tuicCore();
} else if (proxy_type == proxy_Hysteria2) {
return hysteria2Core();
} else { } else {
return hysteriaCore(); // external core support
return extCore();
} }
} }
@ -241,68 +213,11 @@ namespace NekoGui_fmt {
WriteTempFile("hysteria2_" + GetRandomString(10) + ".json", result.config_export.toUtf8()); WriteTempFile("hysteria2_" + GetRandomString(10) + ".json", result.config_export.toUtf8());
result.arguments = QStringList{"-c", TempFile}; result.arguments = QStringList{"-c", TempFile};
return result;
} else { // Hysteria
ExternalBuildResult result{NekoGui::dataStore->extraCore->Get("hysteria")};
QJsonObject config;
// determine server format
auto is_direct = external_stat == 2;
auto sniGen = sni;
if (sni.isEmpty() && !IsIpAddress(serverAddress)) sniGen = serverAddress;
auto server = serverAddress;
if (!hopPort.trimmed().isEmpty()) {
server = WrapIPV6Host(server) + ":" + hopPort;
} else {
server = WrapIPV6Host(server) + ":" + Int2String(serverPort);
}
config["server"] = is_direct ? server : "127.0.0.1:" + Int2String(mapping_port);
// listen
config["socks5"] = QJsonObject{
{"listen", "127.0.0.1:" + Int2String(socks_port)},
};
// misc
config["retry"] = 5;
config["fast_open"] = true;
config["lazy_start"] = true;
config["obfs"] = obfsPassword;
config["up_mbps"] = uploadMbps;
config["down_mbps"] = downloadMbps;
if (authPayloadType == hysteria_auth_base64) config["auth"] = authPayload;
if (authPayloadType == hysteria_auth_string) config["auth_str"] = authPayload;
if (hyProtocol == hysteria_protocol_facktcp) config["protocol"] = "faketcp";
if (hyProtocol == hysteria_protocol_wechat_video) config["protocol"] = "wechat-video";
if (!sniGen.isEmpty()) config["server_name"] = sniGen;
if (!alpn.isEmpty()) config["alpn"] = alpn;
if (!caText.trimmed().isEmpty()) {
WriteTempFile("hysteria_" + GetRandomString(10) + ".crt", caText.toUtf8());
config["ca"] = TempFile;
}
if (allowInsecure) config["insecure"] = true;
if (streamReceiveWindow > 0) config["recv_window_conn"] = streamReceiveWindow;
if (connectionReceiveWindow > 0) config["recv_window"] = connectionReceiveWindow;
if (disableMtuDiscovery) config["disable_mtu_discovery"] = true;
config["hop_interval"] = hopInterval;
//
result.config_export = QJsonObject2QString(config, false);
WriteTempFile("hysteria_" + GetRandomString(10) + ".json", result.config_export.toUtf8());
result.arguments = QStringList{"--no-check", "-c", TempFile};
return result; return result;
} }
ExternalBuildResult e;
e.error = "unknown type";
return e;
} }
ExternalBuildResult CustomBean::BuildExternal(int mapping_port, int socks_port, int external_stat) { ExternalBuildResult CustomBean::BuildExternal(int mapping_port, int socks_port, int external_stat) {

View File

@ -13,7 +13,7 @@ namespace NekoGui_fmt {
url.setScheme("http"); url.setScheme("http");
} }
} else { } else {
url.setScheme(QString("socks%1").arg(socks_http_type)); url.setScheme(QStringLiteral("socks%1").arg(socks_http_type));
} }
if (!name.isEmpty()) url.setFragment(name); if (!name.isEmpty()) url.setFragment(name);
if (!username.isEmpty()) url.setUserName(username); if (!username.isEmpty()) url.setUserName(username);
@ -182,29 +182,7 @@ namespace NekoGui_fmt {
QString QUICBean::ToShareLink() { QString QUICBean::ToShareLink() {
QUrl url; QUrl url;
if (proxy_type == proxy_Hysteria) { if (proxy_type == proxy_TUIC) {
url.setScheme("hysteria");
url.setHost(serverAddress);
url.setPort(serverPort);
QUrlQuery q;
q.addQueryItem("upmbps", Int2String(uploadMbps));
q.addQueryItem("downmbps", Int2String(downloadMbps));
if (!obfsPassword.isEmpty()) {
q.addQueryItem("obfs", "xplus");
q.addQueryItem("obfsParam", obfsPassword);
}
if (authPayloadType == hysteria_auth_string) q.addQueryItem("auth", authPayload);
if (hyProtocol == hysteria_protocol_facktcp) q.addQueryItem("protocol", "faketcp");
if (hyProtocol == hysteria_protocol_wechat_video) q.addQueryItem("protocol", "wechat-video");
if (!hopPort.trimmed().isEmpty()) q.addQueryItem("mport", hopPort);
if (allowInsecure) q.addQueryItem("insecure", "1");
if (!sni.isEmpty()) q.addQueryItem("peer", sni);
if (!alpn.isEmpty()) q.addQueryItem("alpn", alpn);
if (connectionReceiveWindow > 0) q.addQueryItem("recv_window", Int2String(connectionReceiveWindow));
if (streamReceiveWindow > 0) q.addQueryItem("recv_window_conn", Int2String(streamReceiveWindow));
if (!q.isEmpty()) url.setQuery(q);
if (!name.isEmpty()) url.setFragment(name);
} else if (proxy_type == proxy_TUIC) {
url.setScheme("tuic"); url.setScheme("tuic");
url.setUserName(uuid); url.setUserName(uuid);
url.setPassword(password); url.setPassword(password);
@ -244,4 +222,4 @@ namespace NekoGui_fmt {
return url.toString(QUrl::FullyEncoded); return url.toString(QUrl::FullyEncoded);
} }
} // namespace NekoGui_fmt } // namespace NekoGui_fmt

View File

@ -24,7 +24,7 @@ namespace NekoGui_fmt {
QString DisplayType() override { QString DisplayType() override {
if (core == "internal") { if (core == "internal") {
auto obj = QString2QJsonObject(config_simple); auto obj = QString2QJsonObject(config_simple);
return obj[IS_NEKO_BOX ? "type" : "protocol"].toString(); return obj["type"].toString();
} else if (core == "internal-full") { } else if (core == "internal-full") {
return software_core_name + " config"; return software_core_name + " config";
} }
@ -36,11 +36,7 @@ namespace NekoGui_fmt {
QString DisplayAddress() override { QString DisplayAddress() override {
if (core == "internal") { if (core == "internal") {
auto obj = QString2QJsonObject(config_simple); auto obj = QString2QJsonObject(config_simple);
if (IS_NEKO_BOX) { return ::DisplayAddress(obj["server"].toString(), obj["server_port"].toInt());
return ::DisplayAddress(obj["server"].toString(), obj["server_port"].toInt());
} else {
return {};
}
} else if (core == "internal-full") { } else if (core == "internal-full") {
return {}; return {};
} }
@ -52,7 +48,5 @@ namespace NekoGui_fmt {
ExternalBuildResult BuildExternal(int mapping_port, int socks_port, int external_stat) override; ExternalBuildResult BuildExternal(int mapping_port, int socks_port, int external_stat) override;
CoreObjOutboundBuildResult BuildCoreObjSingBox() override; CoreObjOutboundBuildResult BuildCoreObjSingBox() override;
CoreObjOutboundBuildResult BuildCoreObjV2Ray() override;
}; };
} // namespace NekoGui_fmt } // namespace NekoGui_fmt

View File

@ -55,7 +55,7 @@ namespace NekoGui_fmt {
// security // security
auto type = GetQueryValue(query, "type", "tcp"); auto type = GetQueryValue(query, "type", "tcp");
if (type == "h2") { if (type == "h2") {
type = "http"; type = "http";
} }
@ -256,37 +256,7 @@ namespace NekoGui_fmt {
auto query = QUrlQuery(url.query()); auto query = QUrlQuery(url.query());
if (url.host().isEmpty() || url.port() == -1) return false; if (url.host().isEmpty() || url.port() == -1) return false;
if (url.scheme() == "hysteria") { if (url.scheme() == "tuic") {
// https://hysteria.network/docs/uri-scheme/
if (!query.hasQueryItem("upmbps") || !query.hasQueryItem("downmbps")) return false;
name = url.fragment(QUrl::FullyDecoded);
serverAddress = url.host();
serverPort = url.port();
hopPort = query.queryItemValue("mport");
obfsPassword = query.queryItemValue("obfsParam");
allowInsecure = QStringList{"1", "true"}.contains(query.queryItemValue("insecure"));
uploadMbps = query.queryItemValue("upmbps").toInt();
downloadMbps = query.queryItemValue("downmbps").toInt();
auto protocolStr = (query.hasQueryItem("protocol") ? query.queryItemValue("protocol") : "udp").toLower();
if (protocolStr == "faketcp") {
hyProtocol = NekoGui_fmt::QUICBean::hysteria_protocol_facktcp;
} else if (protocolStr.startsWith("wechat")) {
hyProtocol = NekoGui_fmt::QUICBean::hysteria_protocol_wechat_video;
}
if (query.hasQueryItem("auth")) {
authPayload = query.queryItemValue("auth");
authPayloadType = NekoGui_fmt::QUICBean::hysteria_auth_string;
}
alpn = query.queryItemValue("alpn");
sni = FIRST_OR_SECOND(query.queryItemValue("peer"), query.queryItemValue("sni"));
connectionReceiveWindow = query.queryItemValue("recv_window").toInt();
streamReceiveWindow = query.queryItemValue("recv_window_conn").toInt();
} else if (url.scheme() == "tuic") {
// by daeuniverse // by daeuniverse
// https://github.com/daeuniverse/dae/discussions/182 // https://github.com/daeuniverse/dae/discussions/182

View File

@ -1,15 +1,6 @@
#pragma once #pragma once
namespace Preset { namespace Preset {
namespace Xray {
inline QStringList UtlsFingerPrint = {"", "chrome", "firefox", "edge", "safari", "360", "qq", "ios", "android", "random", "randomized"};
inline QStringList ShadowsocksMethods = {"aes-128-gcm", "aes-256-gcm", "aes-192-gcm", "chacha20-ietf-poly1305", "xchacha20-ietf-poly1305",
"2022-blake3-aes-128-gcm", "2022-blake3-aes-256-gcm", "2022-blake3-chacha20-poly1305",
"aes-128-ctr", "aes-192-ctr", "aes-256-ctr", "aes-128-cfb", "aes-192-cfb", "aes-256-cfb",
"rc4", "rc4-md5", "bf-cfb", "chacha20", "chacha20-ietf", "xchacha20", "none"};
inline QStringList Flows = {"xtls-rprx-vision", "xtls-rprx-vision-udp443"};
} // namespace Xray
namespace SingBox { namespace SingBox {
inline QStringList VpnImplementation = {"gvisor", "system", "mixed"}; inline QStringList VpnImplementation = {"gvisor", "system", "mixed"};
inline QStringList DomainStrategy = {"", "ipv4_only", "ipv6_only", "prefer_ipv4", "prefer_ipv6"}; inline QStringList DomainStrategy = {"", "ipv4_only", "ipv6_only", "prefer_ipv4", "prefer_ipv6"};

View File

@ -5,32 +5,19 @@
namespace NekoGui_fmt { namespace NekoGui_fmt {
class QUICBean : public AbstractBean { class QUICBean : public AbstractBean {
public: public:
static constexpr int proxy_Hysteria = 0; // static constexpr int proxy_Hysteria = 0;
static constexpr int proxy_TUIC = 1; static constexpr int proxy_TUIC = 1;
static constexpr int proxy_Hysteria2 = 3; static constexpr int proxy_Hysteria2 = 3;
int proxy_type = proxy_Hysteria; int proxy_type = proxy_Hysteria2;
bool forceExternal = false; bool forceExternal = false;
// Hysteria 1 // Hysteria 2
static constexpr int hysteria_protocol_udp = 0;
static constexpr int hysteria_protocol_facktcp = 1;
static constexpr int hysteria_protocol_wechat_video = 2;
int hyProtocol = 0;
static constexpr int hysteria_auth_none = 0;
static constexpr int hysteria_auth_string = 1;
static constexpr int hysteria_auth_base64 = 2;
int authPayloadType = 0;
QString authPayload = "";
// Hysteria 1&2
QString obfsPassword = ""; QString obfsPassword = "";
int uploadMbps = 100; int uploadMbps = 0;
int downloadMbps = 100; int downloadMbps = 0;
qint64 streamReceiveWindow = 0; qint64 streamReceiveWindow = 0;
qint64 connectionReceiveWindow = 0; qint64 connectionReceiveWindow = 0;
@ -62,8 +49,7 @@ namespace NekoGui_fmt {
explicit QUICBean(int _proxy_type) : AbstractBean(0) { explicit QUICBean(int _proxy_type) : AbstractBean(0) {
proxy_type = _proxy_type; proxy_type = _proxy_type;
if (proxy_type == proxy_Hysteria || proxy_type == proxy_Hysteria2) { if (proxy_type == proxy_Hysteria2) {
_add(new configItem("authPayload", &authPayload, itemType::string));
_add(new configItem("obfsPassword", &obfsPassword, itemType::string)); _add(new configItem("obfsPassword", &obfsPassword, itemType::string));
_add(new configItem("uploadMbps", &uploadMbps, itemType::integer)); _add(new configItem("uploadMbps", &uploadMbps, itemType::integer));
_add(new configItem("downloadMbps", &downloadMbps, itemType::integer)); _add(new configItem("downloadMbps", &downloadMbps, itemType::integer));
@ -72,14 +58,7 @@ namespace NekoGui_fmt {
_add(new configItem("disableMtuDiscovery", &disableMtuDiscovery, itemType::boolean)); _add(new configItem("disableMtuDiscovery", &disableMtuDiscovery, itemType::boolean));
_add(new configItem("hopInterval", &hopInterval, itemType::integer)); _add(new configItem("hopInterval", &hopInterval, itemType::integer));
_add(new configItem("hopPort", &hopPort, itemType::string)); _add(new configItem("hopPort", &hopPort, itemType::string));
if (proxy_type == proxy_Hysteria) { // hy1 _add(new configItem("password", &password, itemType::string));
_add(new configItem("authPayloadType", &authPayloadType, itemType::integer));
_add(new configItem("protocol", &hyProtocol, itemType::integer));
} else { // hy2
uploadMbps = 0;
downloadMbps = 0;
_add(new configItem("password", &password, itemType::string));
}
} else if (proxy_type == proxy_TUIC) { } else if (proxy_type == proxy_TUIC) {
_add(new configItem("uuid", &uuid, itemType::string)); _add(new configItem("uuid", &uuid, itemType::string));
_add(new configItem("password", &password, itemType::string)); _add(new configItem("password", &password, itemType::string));
@ -108,8 +87,6 @@ namespace NekoGui_fmt {
return software_core_name; return software_core_name;
} else if (proxy_type == proxy_TUIC) { } else if (proxy_type == proxy_TUIC) {
return "tuic"; return "tuic";
} else if (proxy_type == proxy_Hysteria) {
return "hysteria";
} else { } else {
return "hysteria2"; return "hysteria2";
} }
@ -118,8 +95,6 @@ namespace NekoGui_fmt {
QString DisplayType() override { QString DisplayType() override {
if (proxy_type == proxy_TUIC) { if (proxy_type == proxy_TUIC) {
return "TUIC"; return "TUIC";
} else if (proxy_type == proxy_Hysteria) {
return "Hysteria1";
} else { } else {
return "Hysteria2"; return "Hysteria2";
} }

View File

@ -23,8 +23,6 @@ namespace NekoGui_fmt {
QString DisplayType() override { return "Shadowsocks"; }; QString DisplayType() override { return "Shadowsocks"; };
CoreObjOutboundBuildResult BuildCoreObjV2Ray() override;
CoreObjOutboundBuildResult BuildCoreObjSingBox() override; CoreObjOutboundBuildResult BuildCoreObjSingBox() override;
bool TryParseLink(const QString &link); bool TryParseLink(const QString &link);

View File

@ -26,8 +26,6 @@ namespace NekoGui_fmt {
QString DisplayType() override { return socks_http_type == type_HTTP ? "HTTP" : "Socks"; }; QString DisplayType() override { return socks_http_type == type_HTTP ? "HTTP" : "Socks"; };
CoreObjOutboundBuildResult BuildCoreObjV2Ray() override;
CoreObjOutboundBuildResult BuildCoreObjSingBox() override; CoreObjOutboundBuildResult BuildCoreObjSingBox() override;
bool TryParseLink(const QString &link); bool TryParseLink(const QString &link);

View File

@ -24,8 +24,6 @@ namespace NekoGui_fmt {
QString DisplayType() override { return proxy_type == proxy_VLESS ? "VLESS" : "Trojan"; }; QString DisplayType() override { return proxy_type == proxy_VLESS ? "VLESS" : "Trojan"; };
CoreObjOutboundBuildResult BuildCoreObjV2Ray() override;
CoreObjOutboundBuildResult BuildCoreObjSingBox() override; CoreObjOutboundBuildResult BuildCoreObjSingBox() override;
bool TryParseLink(const QString &link); bool TryParseLink(const QString &link);

View File

@ -49,8 +49,6 @@ namespace NekoGui_fmt {
_add(new configItem("mux_s", &multiplex_status, itemType::integer)); _add(new configItem("mux_s", &multiplex_status, itemType::integer));
} }
QJsonObject BuildStreamSettingsV2Ray();
void BuildStreamSettingsSingBox(QJsonObject *outbound); void BuildStreamSettingsSingBox(QJsonObject *outbound);
}; };

View File

@ -21,8 +21,6 @@ namespace NekoGui_fmt {
QString DisplayType() override { return "VMess"; }; QString DisplayType() override { return "VMess"; };
CoreObjOutboundBuildResult BuildCoreObjV2Ray() override;
CoreObjOutboundBuildResult BuildCoreObjSingBox() override; CoreObjOutboundBuildResult BuildCoreObjSingBox() override;
bool TryParseLink(const QString &link); bool TryParseLink(const QString &link);

View File

@ -40,6 +40,7 @@ require (
github.com/libdns/cloudflare v0.1.1 // indirect github.com/libdns/cloudflare v0.1.1 // indirect
github.com/libdns/libdns v0.2.2 // indirect github.com/libdns/libdns v0.2.2 // indirect
github.com/logrusorgru/aurora v2.0.3+incompatible // indirect github.com/logrusorgru/aurora v2.0.3+incompatible // indirect
github.com/metacubex/tfo-go v0.0.0-20240821025650-e9be0afd5e7d // indirect
github.com/mholt/acmez v1.2.0 // indirect github.com/mholt/acmez v1.2.0 // indirect
github.com/miekg/dns v1.1.59 // indirect github.com/miekg/dns v1.1.59 // indirect
github.com/onsi/ginkgo/v2 v2.9.7 // indirect github.com/onsi/ginkgo/v2 v2.9.7 // indirect
@ -52,19 +53,18 @@ require (
github.com/sagernet/cloudflare-tls v0.0.0-20231208171750-a4483c1b7cd1 // indirect github.com/sagernet/cloudflare-tls v0.0.0-20231208171750-a4483c1b7cd1 // indirect
github.com/sagernet/gvisor v0.0.0-20240428053021-e691de28565f // indirect github.com/sagernet/gvisor v0.0.0-20240428053021-e691de28565f // indirect
github.com/sagernet/netlink v0.0.0-20240523065131-45e60152f9ba // indirect github.com/sagernet/netlink v0.0.0-20240523065131-45e60152f9ba // indirect
github.com/sagernet/quic-go v0.45.1-beta.2 // indirect github.com/sagernet/quic-go v0.47.0-beta.2 // indirect
github.com/sagernet/reality v0.0.0-20230406110435-ee17307e7691 // indirect github.com/sagernet/reality v0.0.0-20230406110435-ee17307e7691 // indirect
github.com/sagernet/sing v0.4.1 // indirect github.com/sagernet/sing v0.4.3 // indirect
github.com/sagernet/sing-dns v0.2.1-0.20240624030536-ca4a5f7afb65 // indirect github.com/sagernet/sing-dns v0.2.3 // indirect
github.com/sagernet/sing-mux v0.2.0 // indirect github.com/sagernet/sing-mux v0.2.0 // indirect
github.com/sagernet/sing-quic v0.2.0-beta.12 // indirect github.com/sagernet/sing-quic v0.2.2 // indirect
github.com/sagernet/sing-shadowsocks v0.2.6 // indirect github.com/sagernet/sing-shadowsocks v0.2.7 // indirect
github.com/sagernet/sing-shadowsocks2 v0.2.0 // indirect github.com/sagernet/sing-shadowsocks2 v0.2.0 // indirect
github.com/sagernet/sing-shadowtls v0.1.4 // indirect github.com/sagernet/sing-shadowtls v0.1.4 // indirect
github.com/sagernet/sing-tun v0.3.2 // indirect github.com/sagernet/sing-tun v0.3.3 // indirect
github.com/sagernet/sing-vmess v0.1.8 // indirect github.com/sagernet/sing-vmess v0.1.12 // indirect
github.com/sagernet/smux v0.0.0-20231208180855-7041f6ea79e7 // indirect github.com/sagernet/smux v0.0.0-20231208180855-7041f6ea79e7 // indirect
github.com/sagernet/tfo-go v0.0.0-20231209031829-7b5343ac1dc6 // indirect
github.com/sagernet/utls v1.5.4 // indirect github.com/sagernet/utls v1.5.4 // indirect
github.com/sagernet/wireguard-go v0.0.0-20231215174105-89dec3b2f3e8 // indirect github.com/sagernet/wireguard-go v0.0.0-20231215174105-89dec3b2f3e8 // indirect
github.com/sagernet/ws v0.0.0-20231204124109-acfe8907c854 // indirect github.com/sagernet/ws v0.0.0-20231204124109-acfe8907c854 // indirect
@ -80,16 +80,16 @@ require (
golang.org/x/exp v0.0.0-20240416160154-fe59bbe5cc7f // indirect golang.org/x/exp v0.0.0-20240416160154-fe59bbe5cc7f // indirect
golang.org/x/mod v0.18.0 // indirect golang.org/x/mod v0.18.0 // indirect
golang.org/x/net v0.25.0 // indirect golang.org/x/net v0.25.0 // indirect
golang.org/x/sync v0.7.0 // indirect golang.org/x/sync v0.8.0 // indirect
golang.org/x/sys v0.21.0 // indirect golang.org/x/sys v0.25.0 // indirect
golang.org/x/text v0.16.0 // indirect golang.org/x/text v0.18.0 // indirect
golang.org/x/time v0.5.0 // indirect golang.org/x/time v0.5.0 // indirect
golang.org/x/tools v0.21.1-0.20240508182429-e35e4ccd0d2d // indirect golang.org/x/tools v0.21.1-0.20240508182429-e35e4ccd0d2d // indirect
golang.zx2c4.com/wireguard/wgctrl v0.0.0-20230429144221-925a1e7659e6 // indirect golang.zx2c4.com/wireguard/wgctrl v0.0.0-20230429144221-925a1e7659e6 // indirect
google.golang.org/genproto/googleapis/rpc v0.0.0-20240227224415-6ceb2ff114de // indirect google.golang.org/genproto/googleapis/rpc v0.0.0-20240227224415-6ceb2ff114de // indirect
google.golang.org/grpc v1.63.2 // indirect google.golang.org/grpc v1.63.2 // indirect
google.golang.org/protobuf v1.33.0 // indirect google.golang.org/protobuf v1.33.0 // indirect
lukechampine.com/blake3 v1.2.1 // indirect lukechampine.com/blake3 v1.3.0 // indirect
) )
replace grpc_server => ../../grpc_server replace grpc_server => ../../grpc_server
@ -98,7 +98,7 @@ replace github.com/matsuridayo/libneko => ../../../../libneko
replace github.com/sagernet/sing-box => ../../../../sing-box replace github.com/sagernet/sing-box => ../../../../sing-box
// replace github.com/sagernet/sing-quic => ../../../../sing-quic replace github.com/sagernet/sing-quic => ../../../../sing-quic
// replace github.com/sagernet/sing => ../../../../sing // replace github.com/sagernet/sing => ../../../../sing

View File

@ -94,6 +94,8 @@ github.com/libdns/libdns v0.2.2 h1:O6ws7bAfRPaBsgAYt8MDe2HcNBGC29hkZ9MX2eUSX3s=
github.com/libdns/libdns v0.2.2/go.mod h1:4Bj9+5CQiNMVGf87wjX4CY3HQJypUHRuLvlsfsZqLWQ= github.com/libdns/libdns v0.2.2/go.mod h1:4Bj9+5CQiNMVGf87wjX4CY3HQJypUHRuLvlsfsZqLWQ=
github.com/logrusorgru/aurora v2.0.3+incompatible h1:tOpm7WcpBTn4fjmVfgpQq0EfczGlG91VSDkswnjF5A8= github.com/logrusorgru/aurora v2.0.3+incompatible h1:tOpm7WcpBTn4fjmVfgpQq0EfczGlG91VSDkswnjF5A8=
github.com/logrusorgru/aurora v2.0.3+incompatible/go.mod h1:7rIyQOR62GCctdiQpZ/zOJlFyk6y+94wXzv6RNZgaR4= github.com/logrusorgru/aurora v2.0.3+incompatible/go.mod h1:7rIyQOR62GCctdiQpZ/zOJlFyk6y+94wXzv6RNZgaR4=
github.com/metacubex/tfo-go v0.0.0-20240821025650-e9be0afd5e7d h1:j9LtzkYstLFoNvXW824QQeN7Y26uPL5249kzWKbzO9U=
github.com/metacubex/tfo-go v0.0.0-20240821025650-e9be0afd5e7d/go.mod h1:c7bVFM9f5+VzeZ/6Kg77T/jrg1Xp8QpqlSHvG/aXVts=
github.com/mholt/acmez v1.2.0 h1:1hhLxSgY5FvH5HCnGUuwbKY2VQVo8IU7rxXKSnZ7F30= github.com/mholt/acmez v1.2.0 h1:1hhLxSgY5FvH5HCnGUuwbKY2VQVo8IU7rxXKSnZ7F30=
github.com/mholt/acmez v1.2.0/go.mod h1:VT9YwH1xgNX1kmYY89gY8xPJC84BFAisjo8Egigt4kE= github.com/mholt/acmez v1.2.0/go.mod h1:VT9YwH1xgNX1kmYY89gY8xPJC84BFAisjo8Egigt4kE=
github.com/miekg/dns v1.1.59 h1:C9EXc/UToRwKLhK5wKU/I4QVsBUc8kE6MkHBkeypWZs= github.com/miekg/dns v1.1.59 h1:C9EXc/UToRwKLhK5wKU/I4QVsBUc8kE6MkHBkeypWZs=
@ -125,33 +127,29 @@ github.com/sagernet/gvisor v0.0.0-20240428053021-e691de28565f h1:NkhuupzH5ch7b/Y
github.com/sagernet/gvisor v0.0.0-20240428053021-e691de28565f/go.mod h1:KXmw+ouSJNOsuRpg4wgwwCQuunrGz4yoAqQjsLjc6N0= github.com/sagernet/gvisor v0.0.0-20240428053021-e691de28565f/go.mod h1:KXmw+ouSJNOsuRpg4wgwwCQuunrGz4yoAqQjsLjc6N0=
github.com/sagernet/netlink v0.0.0-20240523065131-45e60152f9ba h1:EY5AS7CCtfmARNv2zXUOrsEMPFDGYxaw65JzA2p51Vk= github.com/sagernet/netlink v0.0.0-20240523065131-45e60152f9ba h1:EY5AS7CCtfmARNv2zXUOrsEMPFDGYxaw65JzA2p51Vk=
github.com/sagernet/netlink v0.0.0-20240523065131-45e60152f9ba/go.mod h1:xLnfdiJbSp8rNqYEdIW/6eDO4mVoogml14Bh2hSiFpM= github.com/sagernet/netlink v0.0.0-20240523065131-45e60152f9ba/go.mod h1:xLnfdiJbSp8rNqYEdIW/6eDO4mVoogml14Bh2hSiFpM=
github.com/sagernet/quic-go v0.45.1-beta.2 h1:zkEeCbhdFFkrxKcuIRBtXNKci/1t2J/39QSG/sPvlmc= github.com/sagernet/quic-go v0.47.0-beta.2 h1:1tCGWFOSaXIeuQaHrwOMJIYvlupjTcaVInGQw5ArULU=
github.com/sagernet/quic-go v0.45.1-beta.2/go.mod h1:+N3FqM9DAzOWfe64uxXuBejVJwX7DeW7BslzLO6N/xI= github.com/sagernet/quic-go v0.47.0-beta.2/go.mod h1:bLVKvElSEMNv7pu7SZHscW02TYigzQ5lQu3Nh4wNh8Q=
github.com/sagernet/reality v0.0.0-20230406110435-ee17307e7691 h1:5Th31OC6yj8byLGkEnIYp6grlXfo1QYUfiYFGjewIdc= github.com/sagernet/reality v0.0.0-20230406110435-ee17307e7691 h1:5Th31OC6yj8byLGkEnIYp6grlXfo1QYUfiYFGjewIdc=
github.com/sagernet/reality v0.0.0-20230406110435-ee17307e7691/go.mod h1:B8lp4WkQ1PwNnrVMM6KyuFR20pU8jYBD+A4EhJovEXU= github.com/sagernet/reality v0.0.0-20230406110435-ee17307e7691/go.mod h1:B8lp4WkQ1PwNnrVMM6KyuFR20pU8jYBD+A4EhJovEXU=
github.com/sagernet/sing v0.2.18/go.mod h1:OL6k2F0vHmEzXz2KW19qQzu172FDgSbUSODylighuVo= github.com/sagernet/sing v0.2.18/go.mod h1:OL6k2F0vHmEzXz2KW19qQzu172FDgSbUSODylighuVo=
github.com/sagernet/sing v0.4.1 h1:zVlpE+7k7AFoC2pv6ReqLf0PIHjihL/jsBl5k05PQFk= github.com/sagernet/sing v0.4.3 h1:Ty/NAiNnVd6844k7ujlL5lkzydhcTH5Psc432jXA4Y8=
github.com/sagernet/sing v0.4.1/go.mod h1:ieZHA/+Y9YZfXs2I3WtuwgyCZ6GPsIR7HdKb1SdEnls= github.com/sagernet/sing v0.4.3/go.mod h1:ieZHA/+Y9YZfXs2I3WtuwgyCZ6GPsIR7HdKb1SdEnls=
github.com/sagernet/sing-dns v0.2.1-0.20240624030536-ca4a5f7afb65 h1:lcCe7E1csuyUA3RCvpFcIYOy6FIifDthKaCrUjLG4xA= github.com/sagernet/sing-dns v0.2.3 h1:YzeBUn2tR38F7HtvGEQ0kLRLmZWMEgi/+7wqa4Twb1k=
github.com/sagernet/sing-dns v0.2.1-0.20240624030536-ca4a5f7afb65/go.mod h1:dArgyPZmK8+zDBVRMjV3r12zHgnTara0ahrWwSe/eQE= github.com/sagernet/sing-dns v0.2.3/go.mod h1:BJpJv6XLnrUbSyIntOT6DG9FW0f4fETmPAHvNjOprLg=
github.com/sagernet/sing-mux v0.2.0 h1:4C+vd8HztJCWNYfufvgL49xaOoOHXty2+EAjnzN3IYo= github.com/sagernet/sing-mux v0.2.0 h1:4C+vd8HztJCWNYfufvgL49xaOoOHXty2+EAjnzN3IYo=
github.com/sagernet/sing-mux v0.2.0/go.mod h1:khzr9AOPocLa+g53dBplwNDz4gdsyx/YM3swtAhlkHQ= github.com/sagernet/sing-mux v0.2.0/go.mod h1:khzr9AOPocLa+g53dBplwNDz4gdsyx/YM3swtAhlkHQ=
github.com/sagernet/sing-quic v0.2.0-beta.12 h1:BhvA5mmrDFEyDUQB5eeu+9UhF+ieyuNJ5Rsb0dAG3QY= github.com/sagernet/sing-shadowsocks v0.2.7 h1:zaopR1tbHEw5Nk6FAkM05wCslV6ahVegEZaKMv9ipx8=
github.com/sagernet/sing-quic v0.2.0-beta.12/go.mod h1:YVpLfVi8BvYM7NMrjmnvcRm3E8iMETf1gFQmTQDN9jI= github.com/sagernet/sing-shadowsocks v0.2.7/go.mod h1:0rIKJZBR65Qi0zwdKezt4s57y/Tl1ofkaq6NlkzVuyE=
github.com/sagernet/sing-shadowsocks v0.2.6 h1:xr7ylAS/q1cQYS8oxKKajhuQcchd5VJJ4K4UZrrpp0s=
github.com/sagernet/sing-shadowsocks v0.2.6/go.mod h1:j2YZBIpWIuElPFL/5sJAj470bcn/3QQ5lxZUNKLDNAM=
github.com/sagernet/sing-shadowsocks2 v0.2.0 h1:wpZNs6wKnR7mh1wV9OHwOyUr21VkS3wKFHi+8XwgADg= github.com/sagernet/sing-shadowsocks2 v0.2.0 h1:wpZNs6wKnR7mh1wV9OHwOyUr21VkS3wKFHi+8XwgADg=
github.com/sagernet/sing-shadowsocks2 v0.2.0/go.mod h1:RnXS0lExcDAovvDeniJ4IKa2IuChrdipolPYWBv9hWQ= github.com/sagernet/sing-shadowsocks2 v0.2.0/go.mod h1:RnXS0lExcDAovvDeniJ4IKa2IuChrdipolPYWBv9hWQ=
github.com/sagernet/sing-shadowtls v0.1.4 h1:aTgBSJEgnumzFenPvc+kbD9/W0PywzWevnVpEx6Tw3k= github.com/sagernet/sing-shadowtls v0.1.4 h1:aTgBSJEgnumzFenPvc+kbD9/W0PywzWevnVpEx6Tw3k=
github.com/sagernet/sing-shadowtls v0.1.4/go.mod h1:F8NBgsY5YN2beQavdgdm1DPlhaKQlaL6lpDdcBglGK4= github.com/sagernet/sing-shadowtls v0.1.4/go.mod h1:F8NBgsY5YN2beQavdgdm1DPlhaKQlaL6lpDdcBglGK4=
github.com/sagernet/sing-tun v0.3.2 h1:z0bLUT/YXH9RrJS9DsIpB0Bb9afl2hVJOmHd0zA3HJY= github.com/sagernet/sing-tun v0.3.3 h1:LZnQNmfGcNG2KPTPkLgc+Lo7k606QJVkPp2DnjriwUk=
github.com/sagernet/sing-tun v0.3.2/go.mod h1:DxLIyhjWU/HwGYoX0vNGg2c5QgTQIakphU1MuERR5tQ= github.com/sagernet/sing-tun v0.3.3/go.mod h1:DxLIyhjWU/HwGYoX0vNGg2c5QgTQIakphU1MuERR5tQ=
github.com/sagernet/sing-vmess v0.1.8 h1:XVWad1RpTy9b5tPxdm5MCU8cGfrTGdR8qCq6HV2aCNc= github.com/sagernet/sing-vmess v0.1.12 h1:2gFD8JJb+eTFMoa8FIVMnknEi+vCSfaiTXTfEYAYAPg=
github.com/sagernet/sing-vmess v0.1.8/go.mod h1:vhx32UNzTDUkNwOyIjcZQohre1CaytquC5mPplId8uA= github.com/sagernet/sing-vmess v0.1.12/go.mod h1:luTSsfyBGAc9VhtCqwjR+dt1QgqBhuYBCONB/POhF8I=
github.com/sagernet/smux v0.0.0-20231208180855-7041f6ea79e7 h1:DImB4lELfQhplLTxeq2z31Fpv8CQqqrUwTbrIRumZqQ= github.com/sagernet/smux v0.0.0-20231208180855-7041f6ea79e7 h1:DImB4lELfQhplLTxeq2z31Fpv8CQqqrUwTbrIRumZqQ=
github.com/sagernet/smux v0.0.0-20231208180855-7041f6ea79e7/go.mod h1:FP9X2xjT/Az1EsG/orYYoC+5MojWnuI7hrffz8fGwwo= github.com/sagernet/smux v0.0.0-20231208180855-7041f6ea79e7/go.mod h1:FP9X2xjT/Az1EsG/orYYoC+5MojWnuI7hrffz8fGwwo=
github.com/sagernet/tfo-go v0.0.0-20231209031829-7b5343ac1dc6 h1:z3SJQhVyU63FT26Wn/UByW6b7q8QKB0ZkPqsyqcz2PI=
github.com/sagernet/tfo-go v0.0.0-20231209031829-7b5343ac1dc6/go.mod h1:73xRZuxwkFk4aiLw28hG8W6o9cr2UPrGL9pdY2UTbvY=
github.com/sagernet/utls v1.5.4 h1:KmsEGbB2dKUtCNC+44NwAdNAqnqQ6GA4pTO0Yik56co= github.com/sagernet/utls v1.5.4 h1:KmsEGbB2dKUtCNC+44NwAdNAqnqQ6GA4pTO0Yik56co=
github.com/sagernet/utls v1.5.4/go.mod h1:CTGxPWExIloRipK3XFpYv0OVyhO8kk3XCGW/ieyTh1s= github.com/sagernet/utls v1.5.4/go.mod h1:CTGxPWExIloRipK3XFpYv0OVyhO8kk3XCGW/ieyTh1s=
github.com/sagernet/wireguard-go v0.0.0-20231215174105-89dec3b2f3e8 h1:R0OMYAScomNAVpTfbHFpxqJpvwuhxSRi+g6z7gZhABs= github.com/sagernet/wireguard-go v0.0.0-20231215174105-89dec3b2f3e8 h1:R0OMYAScomNAVpTfbHFpxqJpvwuhxSRi+g6z7gZhABs=
@ -229,8 +227,8 @@ golang.org/x/sync v0.0.0-20181108010431-42b317875d0f/go.mod h1:RxMgew5VJxzue5/jJ
golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.0.0-20190911185100-cd5d95a43a6e/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20190911185100-cd5d95a43a6e/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.0.0-20201020160332-67f06af15bc9/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20201020160332-67f06af15bc9/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.7.0 h1:YsImfSBoP9QPYL0xyKJPq0gcaJdG3rInoqxTWbfQu9M= golang.org/x/sync v0.8.0 h1:3NFvSEYkUoMifnESzZl15y791HH1qU2xm6eCJU5ZPXQ=
golang.org/x/sync v0.7.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk= golang.org/x/sync v0.8.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk=
golang.org/x/sys v0.0.0-20180830151530-49385e6e1522/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20180830151530-49385e6e1522/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
golang.org/x/sys v0.0.0-20190403152447-81d4e9dc473e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190403152447-81d4e9dc473e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
@ -245,15 +243,15 @@ golang.org/x/sys v0.1.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.5.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.5.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.14.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= golang.org/x/sys v0.14.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
golang.org/x/sys v0.21.0 h1:rF+pYz3DAGSQAxAu1CbC7catZg4ebC4UIeIhKxBZvws= golang.org/x/sys v0.25.0 h1:r+8e+loiHxRqhXVl6ML1nO3l1+oFoWbnlu2Ehimmi34=
golang.org/x/sys v0.21.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= golang.org/x/sys v0.25.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo= golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo=
golang.org/x/term v0.20.0 h1:VnkxpohqXaOBYJtBmEppKUG6mXpi+4O6purfc2+sMhw= golang.org/x/term v0.20.0 h1:VnkxpohqXaOBYJtBmEppKUG6mXpi+4O6purfc2+sMhw=
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
golang.org/x/text v0.3.6/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= golang.org/x/text v0.3.6/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
golang.org/x/text v0.16.0 h1:a94ExnEXNtEwYLGJSIUxnWoxoRz/ZcCsV63ROupILh4= golang.org/x/text v0.18.0 h1:XvMDiNzPAl0jr17s6W9lcaIhGUfUORdGCNsuLmPG224=
golang.org/x/text v0.16.0/go.mod h1:GhwF1Be+LQoKShO3cGOHzqOgRrGaYc9AvblQOmPVHnI= golang.org/x/text v0.18.0/go.mod h1:BuEKDfySbSR4drPmRPG/7iBdf8hvFMuRexcpahXilzY=
golang.org/x/time v0.5.0 h1:o7cqy6amK/52YcAKIPlM3a+Fpj35zvRj2TP+e1xFSfk= golang.org/x/time v0.5.0 h1:o7cqy6amK/52YcAKIPlM3a+Fpj35zvRj2TP+e1xFSfk=
golang.org/x/time v0.5.0/go.mod h1:3BpzKBy/shNhVucY/MWOyx10tF3SFh9QdLuxbVysPQM= golang.org/x/time v0.5.0/go.mod h1:3BpzKBy/shNhVucY/MWOyx10tF3SFh9QdLuxbVysPQM=
golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
@ -296,5 +294,5 @@ gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA=
gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
honnef.co/go/tools v0.0.0-20190102054323-c2f93a96b099/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= honnef.co/go/tools v0.0.0-20190102054323-c2f93a96b099/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=
honnef.co/go/tools v0.0.0-20190523083050-ea95bdfd59fc/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= honnef.co/go/tools v0.0.0-20190523083050-ea95bdfd59fc/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=
lukechampine.com/blake3 v1.2.1 h1:YuqqRuaqsGV71BV/nm9xlI0MKUv4QC54jQnBChWbGnI= lukechampine.com/blake3 v1.3.0 h1:sJ3XhFINmHSrYCgl958hscfIa3bw8x4DqMP3u1YvoYE=
lukechampine.com/blake3 v1.2.1/go.mod h1:0OFRp7fBtAylGVCO40o87sbupkyIGgbpv1+M1k1LM6k= lukechampine.com/blake3 v1.3.0/go.mod h1:0OFRp7fBtAylGVCO40o87sbupkyIGgbpv1+M1k1LM6k=

View File

@ -17,7 +17,7 @@ func Launcher() {
_debug := flag.Bool("debug", false, "Debug mode") _debug := flag.Bool("debug", false, "Debug mode")
flag.Parse() flag.Parse()
cmd := exec.Command("./nekoray", flag.Args()...) cmd := exec.Command("./nekobox", flag.Args()...)
ld_env := "LD_LIBRARY_PATH=" + filepath.Join(wd, "./usr/lib") ld_env := "LD_LIBRARY_PATH=" + filepath.Join(wd, "./usr/lib")
qt_plugin_env := "QT_PLUGIN_PATH=" + filepath.Join(wd, "./usr/plugins") qt_plugin_env := "QT_PLUGIN_PATH=" + filepath.Join(wd, "./usr/plugins")

View File

@ -30,9 +30,9 @@ func main() {
time.Sleep(time.Second) time.Sleep(time.Second)
Updater() Updater()
// 3. start // 3. start
exec.Command("./nekoray.exe").Start() exec.Command("./nekobox.exe").Start()
} else { } else {
// 1. nekoray stop it self and run "updater.exe" // 1. main prog quit and run "updater.exe"
Copy("./updater.exe", "./updater.old") Copy("./updater.exe", "./updater.old")
exec.Command("./updater.old", os.Args[1:]...).Start() exec.Command("./updater.old", os.Args[1:]...).Start()
} }
@ -43,7 +43,7 @@ func main() {
if os.Getenv("NKR_FROM_LAUNCHER") == "1" { if os.Getenv("NKR_FROM_LAUNCHER") == "1" {
Launcher() Launcher()
} else { } else {
exec.Command("./nekoray").Start() exec.Command("./nekobox").Start()
} }
} }
return return

View File

@ -71,6 +71,11 @@ func Updater() {
os.RemoveAll("./nekoray_update") os.RemoveAll("./nekoray_update")
os.RemoveAll("./nekoray.zip") os.RemoveAll("./nekoray.zip")
os.RemoveAll("./nekoray.tar.gz") os.RemoveAll("./nekoray.tar.gz")
// nekoray -> nekobox
os.Remove("./nekoray.exe")
os.Remove("./nekoray.png")
os.Remove("./nekoray_core.exe")
} }
func Exist(path string) bool { func Exist(path string) bool {

View File

@ -53,10 +53,6 @@ func (s *BaseServer) Update(ctx context.Context, in *gen.UpdateReq) (*gen.Update
var search string var search string
if runtime.GOOS == "windows" && runtime.GOARCH == "amd64" { if runtime.GOOS == "windows" && runtime.GOARCH == "amd64" {
search = "windows64" search = "windows64"
// check Qt5 update after nekoray v3.3
if _, err := os.Stat("../Qt5Core.dll"); err == nil {
search = "windows7-x64"
}
} else if runtime.GOOS == "linux" && runtime.GOARCH == "amd64" { } else if runtime.GOOS == "linux" && runtime.GOARCH == "amd64" {
search = "linux64" search = "linux64"
} else if runtime.GOOS == "darwin" { } else if runtime.GOOS == "darwin" {

View File

@ -23,5 +23,5 @@ popd
#### Go: nekobox_core #### #### Go: nekobox_core ####
pushd go/cmd/nekobox_core pushd go/cmd/nekobox_core
go build -v -o $DEST -trimpath -ldflags "-w -s -X $neko_common.Version_neko=$version_standalone" -tags "with_clash_api,with_gvisor,with_quic,with_wireguard,with_utls,with_ech" go build -v -o $DEST -trimpath -ldflags "-w -s -X github.com/matsuridayo/libneko/neko_common.Version_neko=$version_standalone" -tags "with_clash_api,with_gvisor,with_quic,with_wireguard,with_utls,with_ech"
popd popd

View File

@ -7,7 +7,7 @@ rm -rf $DEST
mkdir -p $DEST mkdir -p $DEST
#### copy binary #### #### copy binary ####
cp $BUILD/nekoray $DEST cp $BUILD/nekobox $DEST
#### Download: prebuilt runtime #### #### Download: prebuilt runtime ####
curl -Lso usr.zip https://github.com/MatsuriDayo/nekoray_qt_runtime/releases/download/20220503/20230202-5.12.8-ubuntu20.04-linux64.zip curl -Lso usr.zip https://github.com/MatsuriDayo/nekoray_qt_runtime/releases/download/20220503/20230202-5.12.8-ubuntu20.04-linux64.zip

View File

@ -2,20 +2,16 @@
set -e set -e
source libs/env_deploy.sh source libs/env_deploy.sh
if [ "$DL_QT_VER" == "5.15" ]; then DEST=$DEPLOYMENT/windows64
DEST=$DEPLOYMENT/windows7-x64
else
DEST=$DEPLOYMENT/windows64
fi
rm -rf $DEST rm -rf $DEST
mkdir -p $DEST mkdir -p $DEST
#### copy exe #### #### copy exe ####
cp $BUILD/nekoray.exe $DEST cp $BUILD/nekobox.exe $DEST
#### deploy qt & DLL runtime #### #### deploy qt & DLL runtime ####
pushd $DEST pushd $DEST
windeployqt nekoray.exe --no-compiler-runtime --no-system-d3d-compiler --no-opengl-sw --verbose 2 windeployqt nekobox.exe --no-compiler-runtime --no-system-d3d-compiler --no-opengl-sw --verbose 2
rm -rf translations rm -rf translations
rm -rf libEGL.dll libGLESv2.dll Qt6Pdf.dll rm -rf libEGL.dll libGLESv2.dll Qt6Pdf.dll

View File

@ -3,7 +3,7 @@ cd qtsdk
if [ "$DL_QT_VER" == "5.15" ]; then if [ "$DL_QT_VER" == "5.15" ]; then
curl -LSO https://github.com/MatsuriDayo/nekoray_qt_runtime/releases/download/20220503/Qt5.15.7-Windows-x86_64-VS2019-16.11.20-20221103.7z curl -LSO https://github.com/MatsuriDayo/nekoray_qt_runtime/releases/download/20220503/Qt5.15.7-Windows-x86_64-VS2019-16.11.20-20221103.7z
else else
curl -LSO https://github.com/MatsuriDayo/nekoray_qt_runtime/releases/download/20220503/Qt6.5.2-Windows-x86_64-VS2022-17.6.5-20230803.7z curl -LSO https://github.com/MatsuriDayo/nekoray_qt_runtime/releases/download/20220503/Qt6.7.2-Windows-x86_64-VS2022-17.10.3-20240621.7z
fi fi
7z x *.7z 7z x *.7z
rm *.7z rm *.7z

View File

@ -1,4 +1,4 @@
SRC_ROOT="$PWD" SRC_ROOT="$PWD"
DEPLOYMENT="$SRC_ROOT/deployment" DEPLOYMENT="$SRC_ROOT/deployment"
BUILD="$SRC_ROOT/build" BUILD="$SRC_ROOT/build"
version_standalone="nekoray-"$(cat nekoray_version.txt) version_standalone="nekoray-"$(cat nekoray_version.txt) # 下次改

View File

@ -18,6 +18,16 @@ popd
#### ####
if [ ! -d "sing-quic" ]; then
git clone --no-checkout https://github.com/MatsuriDayo/sing-quic.git
fi
pushd sing-quic
git checkout "$COMMIT_SING_QUIC"
popd
####
if [ ! -d "libneko" ]; then if [ ! -d "libneko" ]; then
git clone --no-checkout https://github.com/MatsuriDayo/libneko.git git clone --no-checkout https://github.com/MatsuriDayo/libneko.git
fi fi

View File

@ -1,2 +1,3 @@
export COMMIT_SING_BOX="cf36758f11b7c144e1211801753cc91f06ff2906" export COMMIT_SING_BOX="06557f6cef23160668122a17a818b378b5a216b5"
export COMMIT_SING_QUIC="b49ce60d9b3622d5238fee96bfd3c5f6e3915b42"
export COMMIT_LIBNEKO="1c47a3af71990a7b2192e03292b4d246c308ef0b" export COMMIT_LIBNEKO="1c47a3af71990a7b2192e03292b4d246c308ef0b"

View File

@ -2,37 +2,37 @@
sudo apt-get install fuse -y sudo apt-get install fuse -y
cp -r linux64 nekoray.AppDir cp -r linux64 nekobox.AppDir
# The file for Appimage # The file for Appimage
rm nekoray.AppDir/launcher rm nekobox.AppDir/launcher
cat >nekoray.AppDir/nekoray.desktop <<-EOF cat >nekobox.AppDir/nekobox.desktop <<-EOF
[Desktop Entry] [Desktop Entry]
Name=nekoray Name=nekobox
Exec=echo "NekoRay started" Exec=echo "nekobox started"
Icon=nekoray Icon=nekobox
Type=Application Type=Application
Categories=Network Categories=Network
EOF EOF
cat >nekoray.AppDir/AppRun <<-EOF cat >nekobox.AppDir/AppRun <<-EOF
#!/bin/bash #!/bin/bash
echo "PATH: \${PATH}" echo "PATH: \${PATH}"
echo "NekoRay runing on: \$APPDIR" echo "nekobox runing on: \$APPDIR"
LD_LIBRARY_PATH=\${APPDIR}/usr/lib QT_PLUGIN_PATH=\${APPDIR}/usr/plugins \${APPDIR}/nekoray -appdata "\$@" LD_LIBRARY_PATH=\${APPDIR}/usr/lib QT_PLUGIN_PATH=\${APPDIR}/usr/plugins \${APPDIR}/nekobox -appdata "\$@"
EOF EOF
chmod +x nekoray.AppDir/AppRun chmod +x nekobox.AppDir/AppRun
# build # build
curl -fLSO https://github.com/AppImage/AppImageKit/releases/latest/download/appimagetool-x86_64.AppImage curl -fLSO https://github.com/AppImage/AppImageKit/releases/latest/download/appimagetool-x86_64.AppImage
chmod +x appimagetool-x86_64.AppImage chmod +x appimagetool-x86_64.AppImage
./appimagetool-x86_64.AppImage nekoray.AppDir ./appimagetool-x86_64.AppImage nekobox.AppDir
# clean # clean
rm appimagetool-x86_64.AppImage rm appimagetool-x86_64.AppImage
rm -rf nekoray.AppDir rm -rf nekobox.AppDir

View File

@ -25,8 +25,8 @@ if [ ! -s /usr/share/applications/nekoray.desktop ]; then
[Desktop Entry] [Desktop Entry]
Name=nekoray Name=nekoray
Comment=Qt based cross-platform GUI proxy configuration manager (backend: sing-box) Comment=Qt based cross-platform GUI proxy configuration manager (backend: sing-box)
Exec=sh -c "PATH=/opt/nekoray:\$PATH /opt/nekoray/nekoray -appdata" Exec=sh -c "PATH=/opt/nekoray:\$PATH /opt/nekoray/nekobox -appdata"
Icon=/opt/nekoray/nekoray.png Icon=/opt/nekoray/nekobox.png
Terminal=false Terminal=false
Type=Application Type=Application
Categories=Network;Application; Categories=Network;Application;

View File

@ -18,7 +18,7 @@ namespace NekoGui {
namespace CoreType { namespace CoreType {
enum CoreType { enum CoreType {
V2RAY, V2RAY, // DO NOT USE
SING_BOX, SING_BOX,
}; };
} }

View File

@ -18,7 +18,7 @@ namespace NekoGui_network {
if (NekoGui::dataStore->sub_use_proxy) { if (NekoGui::dataStore->sub_use_proxy) {
QNetworkProxy p; QNetworkProxy p;
// Note: sing-box mixed socks5 protocol error // Note: sing-box mixed socks5 protocol error
p.setType(IS_NEKO_BOX ? QNetworkProxy::HttpProxy : QNetworkProxy::Socks5Proxy); p.setType(QNetworkProxy::HttpProxy);
p.setHostName("127.0.0.1"); p.setHostName("127.0.0.1");
p.setPort(NekoGui::dataStore->inbound_socks_port); p.setPort(NekoGui::dataStore->inbound_socks_port);
if (NekoGui::dataStore->inbound_auth->NeedAuth()) { if (NekoGui::dataStore->inbound_auth->NeedAuth()) {
@ -51,7 +51,7 @@ namespace NekoGui_network {
for (const auto &err: errors) { for (const auto &err: errors) {
error_str << err.errorString(); error_str << err.errorString();
} }
MW_show_log(QString("SSL Errors: %1 %2").arg(error_str.join(","), NekoGui::dataStore->sub_insecure ? "(Ignored)" : "")); MW_show_log(QStringLiteral("SSL Errors: %1 %2").arg(error_str.join(","), NekoGui::dataStore->sub_insecure ? "(Ignored)" : ""));
}); });
// Wait for response // Wait for response
auto abortTimer = new QTimer; auto abortTimer = new QTimer;

View File

@ -237,7 +237,6 @@ namespace NekoGui {
_add(new configItem("current_group", &current_group, itemType::integer)); _add(new configItem("current_group", &current_group, itemType::integer));
_add(new configItem("inbound_address", &inbound_address, itemType::string)); _add(new configItem("inbound_address", &inbound_address, itemType::string));
_add(new configItem("inbound_socks_port", &inbound_socks_port, itemType::integer)); _add(new configItem("inbound_socks_port", &inbound_socks_port, itemType::integer));
_add(new configItem("inbound_http_port", &inbound_http_port, itemType::integer));
_add(new configItem("log_level", &log_level, itemType::string)); _add(new configItem("log_level", &log_level, itemType::string));
_add(new configItem("mux_protocol", &mux_protocol, itemType::string)); _add(new configItem("mux_protocol", &mux_protocol, itemType::string));
_add(new configItem("mux_concurrency", &mux_concurrency, itemType::integer)); _add(new configItem("mux_concurrency", &mux_concurrency, itemType::integer));
@ -248,7 +247,6 @@ namespace NekoGui {
_add(new configItem("theme", &theme, itemType::string)); _add(new configItem("theme", &theme, itemType::string));
_add(new configItem("custom_inbound", &custom_inbound, itemType::string)); _add(new configItem("custom_inbound", &custom_inbound, itemType::string));
_add(new configItem("custom_route", &custom_route_global, itemType::string)); _add(new configItem("custom_route", &custom_route_global, itemType::string));
_add(new configItem("v2ray_asset_dir", &v2ray_asset_dir, itemType::string));
_add(new configItem("sub_use_proxy", &sub_use_proxy, itemType::boolean)); _add(new configItem("sub_use_proxy", &sub_use_proxy, itemType::boolean));
_add(new configItem("remember_id", &remember_id, itemType::integer)); _add(new configItem("remember_id", &remember_id, itemType::integer));
_add(new configItem("remember_enable", &remember_enable, itemType::boolean)); _add(new configItem("remember_enable", &remember_enable, itemType::boolean));
@ -284,12 +282,7 @@ namespace NekoGui {
_add(new configItem("core_box_clash_api", &core_box_clash_api, itemType::integer)); _add(new configItem("core_box_clash_api", &core_box_clash_api, itemType::integer));
_add(new configItem("core_box_clash_api_secret", &core_box_clash_api_secret, itemType::string)); _add(new configItem("core_box_clash_api_secret", &core_box_clash_api_secret, itemType::string));
_add(new configItem("core_box_underlying_dns", &core_box_underlying_dns, itemType::string)); _add(new configItem("core_box_underlying_dns", &core_box_underlying_dns, itemType::string));
_add(new configItem("core_ray_direct_dns", &core_ray_direct_dns, itemType::boolean));
_add(new configItem("core_ray_freedom_domainStrategy", &core_ray_freedom_domainStrategy, itemType::string));
_add(new configItem("vpn_internal_tun", &vpn_internal_tun, itemType::boolean)); _add(new configItem("vpn_internal_tun", &vpn_internal_tun, itemType::boolean));
#ifdef Q_OS_WIN
_add(new configItem("core_ray_windows_disable_auto_interface", &core_ray_windows_disable_auto_interface, itemType::boolean));
#endif
} }
void DataStore::UpdateStartedId(int id) { void DataStore::UpdateStartedId(int id) {
@ -310,11 +303,7 @@ namespace NekoGui {
if (isDefault) { if (isDefault) {
QString version = SubStrBefore(NKR_VERSION, "-"); QString version = SubStrBefore(NKR_VERSION, "-");
if (!version.contains(".")) version = "2.0"; if (!version.contains(".")) version = "2.0";
if (IS_NEKO_BOX) { return "NekoBox/PC/" + version + " (Prefer ClashMeta Format)";
return "NekoBox/PC/" + version + " (Prefer ClashMeta Format)";
} else {
return "NekoRay/PC/" + version + " (Prefer ClashMeta Format)";
}
} }
return user_agent; return user_agent;
} }
@ -335,10 +324,8 @@ namespace NekoGui {
"domain:firebase.io\n" "domain:firebase.io\n"
"domain:crashlytics.com\n"; "domain:crashlytics.com\n";
} }
if (IS_NEKO_BOX) { if (!Preset::SingBox::DomainStrategy.contains(domain_strategy)) domain_strategy = "";
if (!Preset::SingBox::DomainStrategy.contains(domain_strategy)) domain_strategy = ""; if (!Preset::SingBox::DomainStrategy.contains(outbound_domain_strategy)) outbound_domain_strategy = "";
if (!Preset::SingBox::DomainStrategy.contains(outbound_domain_strategy)) outbound_domain_strategy = "";
}
_add(new configItem("direct_ip", &this->direct_ip, itemType::string)); _add(new configItem("direct_ip", &this->direct_ip, itemType::string));
_add(new configItem("direct_domain", &this->direct_domain, itemType::string)); _add(new configItem("direct_domain", &this->direct_domain, itemType::string));
_add(new configItem("proxy_ip", &this->proxy_ip, itemType::string)); _add(new configItem("proxy_ip", &this->proxy_ip, itemType::string));
@ -362,7 +349,7 @@ namespace NekoGui {
} }
QString Routing::DisplayRouting() const { QString Routing::DisplayRouting() const {
return QString("[Proxy] %1\n[Proxy] %2\n[Direct] %3\n[Direct] %4\n[Block] %5\n[Block] %6\n[Default Outbound] %7\n[DNS] %8") return QStringLiteral("[Proxy] %1\n[Proxy] %2\n[Direct] %3\n[Direct] %4\n[Block] %5\n[Block] %6\n[Default Outbound] %7\n[DNS] %8")
.arg(SplitLinesSkipSharp(proxy_domain).join(","), 10) .arg(SplitLinesSkipSharp(proxy_domain).join(","), 10)
.arg(SplitLinesSkipSharp(proxy_ip).join(","), 10) .arg(SplitLinesSkipSharp(proxy_ip).join(","), 10)
.arg(SplitLinesSkipSharp(direct_domain).join(","), 10) .arg(SplitLinesSkipSharp(direct_domain).join(","), 10)
@ -428,16 +415,13 @@ namespace NekoGui {
// System Utils // System Utils
QString FindCoreAsset(const QString &name) { QString FindCoreAsset(const QString &name) {
QStringList search{NekoGui::dataStore->v2ray_asset_dir}; QStringList search{};
search << QApplication::applicationDirPath(); search << QApplication::applicationDirPath();
search << "/usr/share/sing-geoip"; search << "/usr/share/sing-geoip";
search << "/usr/share/sing-geosite"; search << "/usr/share/sing-geosite";
search << "/usr/share/xray"; search << "/usr/share/sing-box";
search << "/usr/local/share/xray"; search << "/usr/lib/nekobox";
search << "/opt/xray"; search << "/usr/share/nekobox";
search << "/usr/share/v2ray";
search << "/usr/local/share/v2ray";
search << "/opt/v2ray";
for (const auto &dir: search) { for (const auto &dir: search) {
if (dir.isEmpty()) continue; if (dir.isEmpty()) continue;
QFileInfo asset(dir + "/" + name); QFileInfo asset(dir + "/" + name);

View File

@ -17,7 +17,5 @@ namespace NekoGui {
bool IsAdmin(); bool IsAdmin();
} // namespace NekoGui } // namespace NekoGui
#define IS_NEKO_BOX (NekoGui::coreType == NekoGui::CoreType::SING_BOX) #define ROUTES_PREFIX_NAME QStringLiteral("routes_box")
#define IS_NEKO_BOX_INTERNAL_TUN (IS_NEKO_BOX && NekoGui::dataStore->vpn_internal_tun)
#define ROUTES_PREFIX_NAME QString(IS_NEKO_BOX ? "routes_box" : "routes")
#define ROUTES_PREFIX QString(ROUTES_PREFIX_NAME + "/") #define ROUTES_PREFIX QString(ROUTES_PREFIX_NAME + "/")

View File

@ -93,7 +93,7 @@ namespace NekoGui {
// Saved // Saved
// Misc // Misc
QString log_level = "warning"; QString log_level = "info";
QString test_latency_url = "http://cp.cloudflare.com/"; QString test_latency_url = "http://cp.cloudflare.com/";
QString test_download_url = "http://cachefly.cachefly.net/10mb.test"; QString test_download_url = "http://cachefly.cachefly.net/10mb.test";
int test_download_timeout = 30; int test_download_timeout = 30;
@ -102,12 +102,11 @@ namespace NekoGui {
int traffic_loop_interval = 1000; int traffic_loop_interval = 1000;
bool connection_statistics = false; bool connection_statistics = false;
int current_group = 0; // group id int current_group = 0; // group id
QString mux_protocol = ""; QString mux_protocol = "h2mux";
bool mux_padding = false; bool mux_padding = false;
int mux_concurrency = 8; int mux_concurrency = 8;
bool mux_default_on = false; bool mux_default_on = false;
QString theme = "0"; QString theme = "0";
QString v2ray_asset_dir = "";
int language = 0; int language = 0;
QString mw_size = ""; QString mw_size = "";
bool check_include_pre = false; bool check_include_pre = false;
@ -136,7 +135,6 @@ namespace NekoGui {
// Socks & HTTP Inbound // Socks & HTTP Inbound
QString inbound_address = "127.0.0.1"; QString inbound_address = "127.0.0.1";
int inbound_socks_port = 2080; // or Mixed int inbound_socks_port = 2080; // or Mixed
int inbound_http_port = 2081;
InboundAuthorization *inbound_auth = new InboundAuthorization; InboundAuthorization *inbound_auth = new InboundAuthorization;
QString custom_inbound = "{\"inbounds\": []}"; QString custom_inbound = "{\"inbounds\": []}";
@ -166,9 +164,6 @@ namespace NekoGui {
int core_box_clash_api = -9090; int core_box_clash_api = -9090;
QString core_box_clash_api_secret = ""; QString core_box_clash_api_secret = "";
QString core_box_underlying_dns = ""; QString core_box_underlying_dns = "";
bool core_ray_direct_dns = false;
bool core_ray_windows_disable_auto_interface = false;
QString core_ray_freedom_domainStrategy = "";
// Other Core // Other Core
ExtraCore *extraCore = new ExtraCore; ExtraCore *extraCore = new ExtraCore;

View File

@ -8,8 +8,8 @@
// //
inline QString software_name = "NekoRay"; inline QString software_name = "NekoBox";
inline QString software_core_name = "Xray"; inline QString software_core_name = "sing-box";
// Main Functions // Main Functions

View File

@ -140,7 +140,7 @@ int main(int argc, char* argv[]) {
return 0; return 0;
} }
// Some Bad System // Some Bad System
QMessageBox::warning(nullptr, "NekoRay", "RunGuard disallow to run, use -many to force start."); QMessageBox::warning(nullptr, "NekoGui", "RunGuard disallow to run, use -many to force start.");
return 0; return 0;
} }
MF_release_runguard = [&] { guard.release(); }; MF_release_runguard = [&] { guard.release(); };
@ -148,7 +148,7 @@ int main(int argc, char* argv[]) {
// icons // icons
#if (QT_VERSION >= QT_VERSION_CHECK(5, 11, 0)) #if (QT_VERSION >= QT_VERSION_CHECK(5, 11, 0))
QIcon::setFallbackSearchPaths(QStringList{ QIcon::setFallbackSearchPaths(QStringList{
":/nekoray", ":/neko",
":/icon", ":/icon",
}); });
#endif #endif
@ -177,9 +177,6 @@ int main(int argc, char* argv[]) {
// Load dataStore // Load dataStore
switch (NekoGui::coreType) { switch (NekoGui::coreType) {
case NekoGui::CoreType::V2RAY:
NekoGui::dataStore->fn = "groups/nekoray.json";
break;
case NekoGui::CoreType::SING_BOX: case NekoGui::CoreType::SING_BOX:
NekoGui::dataStore->fn = "groups/nekobox.json"; NekoGui::dataStore->fn = "groups/nekobox.json";
break; break;

View File

@ -1 +1 @@
4.0-beta1-2024-07-02 4.0.1-2024-12-12

View File

@ -4,7 +4,7 @@
<body> <body>
<h3> <h3>
<p>Please put your clash dashboard files to "nekoray/config/dashboard" dir.</p> <p>Please put your clash dashboard files to "./config/dashboard" dir.</p>
<p>For example, you can download from the following URL.</p> <p>For example, you can download from the following URL.</p>
<p> <p>
<a href="https://github.com/MetaCubeX/Yacd-meta/archive/refs/heads/gh-pages.zip">Download Yacd-meta</a> <a href="https://github.com/MetaCubeX/Yacd-meta/archive/refs/heads/gh-pages.zip">Download Yacd-meta</a>

View File

@ -16,7 +16,6 @@
</qresource> </qresource>
<qresource prefix="/neko"> <qresource prefix="/neko">
<file alias="nekobox.png">public/nekobox.png</file> <file alias="nekobox.png">public/nekobox.png</file>
<file alias="nekoray.png">public/nekoray.png</file>
<file>neko.css</file> <file>neko.css</file>
<file>vpn/vpn-run-root.sh</file> <file>vpn/vpn-run-root.sh</file>
<file>vpn/sing-box-vpn.json</file> <file>vpn/sing-box-vpn.json</file>

View File

Before

Width:  |  Height:  |  Size: 66 KiB

After

Width:  |  Height:  |  Size: 66 KiB

Binary file not shown.

Binary file not shown.

Before

Width:  |  Height:  |  Size: 60 KiB

View File

@ -12,7 +12,7 @@
{ {
"tag": "dns-remote", "tag": "dns-remote",
"address": "8.8.8.8", "address": "8.8.8.8",
"detour": "nekoray-socks" "detour": "neko-socks"
}, },
{ {
"tag": "dns-direct", "tag": "dns-direct",
@ -75,7 +75,7 @@
"outbounds": [ "outbounds": [
{ {
"type": "socks", "type": "socks",
"tag": "nekoray-socks", "tag": "neko-socks",
"udp_fragment": true, "udp_fragment": true,
//%SOCKS_USER_PASS% //%SOCKS_USER_PASS%
"server": "127.0.0.1", "server": "127.0.0.1",

View File

@ -6,40 +6,25 @@ if [ "$EUID" -ne 0 ]; then
echo "[Warning] Tun script not running as root" echo "[Warning] Tun script not running as root"
fi fi
if [ "$(uname)" == "Darwin" ]; then
IS_MACOS=1
fi
[ -z $TABLE_FWMARK ] && echo "Please set env TABLE_FWMARK" && exit
command -v pkill >/dev/null 2>&1 || echo "[Warning] pkill not found" command -v pkill >/dev/null 2>&1 || echo "[Warning] pkill not found"
BASEDIR=$(dirname "$0") BASEDIR=$(dirname "$0")
cd $BASEDIR cd $BASEDIR
pre_start_linux() { pre_start_linux() {
# set bypass: fwmark
ip rule add pref 8999 fwmark $TABLE_FWMARK table main || return
ip -6 rule add pref 8999 fwmark $TABLE_FWMARK table main || return
# for Tun2Socket # for Tun2Socket
iptables -I INPUT -s 172.19.0.2 -d 172.19.0.1 -p tcp -j ACCEPT iptables -I INPUT -s 172.19.0.2 -d 172.19.0.1 -p tcp -j ACCEPT
ip6tables -I INPUT -s fdfe:dcba:9876::2 -d fdfe:dcba:9876::1 -p tcp -j ACCEPT ip6tables -I INPUT -s fdfe:dcba:9876::2 -d fdfe:dcba:9876::1 -p tcp -j ACCEPT
} }
start() { start() {
[ -z $IS_MACOS ] && pre_start_linux pre_start_linux
"./nekobox_core" run -c "$CONFIG_PATH" --protect-listen-path "$PROTECT_LISTEN_PATH" --protect-fwmark $TABLE_FWMARK "./nekobox_core" run -c "$CONFIG_PATH"
} }
stop() { stop() {
[ -z $IS_MACOS ] || return
for local in $BYPASS_IPS; do
ip rule del to $local table main
done
iptables -D INPUT -s 172.19.0.2 -d 172.19.0.1 -p tcp -j ACCEPT iptables -D INPUT -s 172.19.0.2 -d 172.19.0.1 -p tcp -j ACCEPT
ip6tables -D INPUT -s fdfe:dcba:9876::2 -d fdfe:dcba:9876::1 -p tcp -j ACCEPT ip6tables -D INPUT -s fdfe:dcba:9876::2 -d fdfe:dcba:9876::1 -p tcp -j ACCEPT
ip rule del fwmark $TABLE_FWMARK
ip -6 rule del fwmark $TABLE_FWMARK
} }
if [ "$1" != "stop" ]; then if [ "$1" != "stop" ]; then

View File

@ -205,7 +205,7 @@ namespace NekoGui_rpc {
#define NOT_OK \ #define NOT_OK \
*rpcOK = false; \ *rpcOK = false; \
onError(QString("QNetworkReply::NetworkError code: %1\n").arg(status)); onError(QStringLiteral("QNetworkReply::NetworkError code: %1\n").arg(status));
void Client::Exit() { void Client::Exit() {
libcore::EmptyReq request; libcore::EmptyReq request;

View File

@ -122,14 +122,6 @@ namespace NekoGui_sub {
if (!ok) return; if (!ok) return;
} }
// Hysteria1
if (str.startsWith("hysteria://")) {
needFix = false;
ent = NekoGui::ProfileManager::NewProxyEntity("hysteria");
auto ok = ent->QUICBean()->TryParseLink(str);
if (!ok) return;
}
// Hysteria2 // Hysteria2
if (str.startsWith("hysteria2://") || str.startsWith("hy2://")) { if (str.startsWith("hysteria2://") || str.startsWith("hy2://")) {
needFix = false; needFix = false;
@ -200,7 +192,7 @@ namespace NekoGui_sub {
try { try {
return n.as<int>(); return n.as<int>();
} catch (const YAML::Exception &ex2) { } catch (const YAML::Exception &ex2) {
ex2.what(); qDebug() << ex2.what();
} }
qDebug() << ex.what(); qDebug() << ex.what();
return def; return def;
@ -413,37 +405,6 @@ namespace NekoGui_sub {
break; break;
} }
} }
} else if (type == "hysteria") {
auto bean = ent->QUICBean();
bean->hopPort = Node2QString(proxy["ports"]);
bean->allowInsecure = Node2Bool(proxy["skip-cert-verify"]);
auto alpn = Node2QStringList(proxy["alpn"]);
bean->caText = Node2QString(proxy["ca-str"]);
if (!alpn.isEmpty()) bean->alpn = alpn[0];
bean->sni = Node2QString(proxy["sni"]);
auto auth_str = FIRST_OR_SECOND(Node2QString(proxy["auth_str"]), Node2QString(proxy["auth-str"]));
auto auth = Node2QString(proxy["auth"]);
if (!auth_str.isEmpty()) {
bean->authPayloadType = NekoGui_fmt::QUICBean::hysteria_auth_string;
bean->authPayload = auth_str;
}
if (!auth.isEmpty()) {
bean->authPayloadType = NekoGui_fmt::QUICBean::hysteria_auth_base64;
bean->authPayload = auth;
}
bean->obfsPassword = Node2QString(proxy["obfs"]);
if (Node2Bool(proxy["disable_mtu_discovery"]) || Node2Bool(proxy["disable-mtu-discovery"])) bean->disableMtuDiscovery = true;
bean->streamReceiveWindow = Node2Int(proxy["recv-window"]);
bean->connectionReceiveWindow = Node2Int(proxy["recv-window-conn"]);
auto upMbps = Node2QString(proxy["up"]).split(" ")[0].toInt();
auto downMbps = Node2QString(proxy["down"]).split(" ")[0].toInt();
if (upMbps > 0) bean->uploadMbps = upMbps;
if (downMbps > 0) bean->downloadMbps = downMbps;
} else if (type == "hysteria2") { } else if (type == "hysteria2") {
auto bean = ent->QUICBean(); auto bean = ent->QUICBean();

View File

@ -141,15 +141,7 @@ namespace NekoGui_sys {
void CoreProcess::Start() { void CoreProcess::Start() {
show_stderr = false; show_stderr = false;
// set extra env // cwd: same as GUI, at ./config
auto v2ray_asset_dir = NekoGui::FindCoreAsset("geoip.dat");
if (!v2ray_asset_dir.isEmpty()) {
v2ray_asset_dir = QFileInfo(v2ray_asset_dir).absolutePath();
env << "XRAY_LOCATION_ASSET=" + v2ray_asset_dir;
}
if (NekoGui::dataStore->core_ray_direct_dns) env << "NKR_CORE_RAY_DIRECT_DNS=1";
if (NekoGui::dataStore->core_ray_windows_disable_auto_interface) env << "NKR_CORE_RAY_WINDOWS_DISABLE_AUTO_INTERFACE=1";
//
ExternalProcess::Start(); ExternalProcess::Start();
write((NekoGui::dataStore->core_token + "\n").toUtf8()); write((NekoGui::dataStore->core_token + "\n").toUtf8());
} }

View File

@ -56,7 +56,7 @@ LONG __stdcall CreateCrashHandler(EXCEPTION_POINTERS *pException) {
} }
// 创建消息提示 // 创建消息提示
QMessageBox::warning(NULL, "Application crashed", QMessageBox::warning(NULL, "Application crashed",
QString("ErrorCode: %1 ErrorAddr:%2 ErrorFlag: %3 ErrorPara: %4\nVersion: %5\nDump file at %6") QStringLiteral("ErrorCode: %1 ErrorAddr:%2 ErrorFlag: %3 ErrorPara: %4\nVersion: %5\nDump file at %6")
.arg(errCode) .arg(errCode)
.arg(errAddr) .arg(errAddr)
.arg(errFlag) .arg(errFlag)

View File

@ -11,18 +11,10 @@
<source>Enable</source> <source>Enable</source>
<translation>فعال کردن</translation> <translation>فعال کردن</translation>
</message> </message>
<message>
<source>HTTP Listen Port</source>
<translation>پورت HTTP درحال شنود</translation>
</message>
<message> <message>
<source>Listen Address</source> <source>Listen Address</source>
<translation>آدرس درحال شنود</translation> <translation>آدرس درحال شنود</translation>
</message> </message>
<message>
<source>Socks Listen Port</source>
<translation>پورت ساکس درحال شنود</translation>
</message>
<message> <message>
<source>concurrency</source> <source>concurrency</source>
<translation>همزمانی</translation> <translation>همزمانی</translation>
@ -71,14 +63,6 @@
<source>Custom Inbound</source> <source>Custom Inbound</source>
<translation>ورودی سفارشی</translation> <translation>ورودی سفارشی</translation>
</message> </message>
<message>
<source>Asset Location</source>
<translation>مکان دارایی</translation>
</message>
<message>
<source>Default: dir of &quot;nekoray&quot;</source>
<translation type="unfinished">مسیر پیش فرض &quot;nekoray&quot;</translation>
</message>
<message> <message>
<source>Concurrent</source> <source>Concurrent</source>
<translation>هم زمان</translation> <translation>هم زمان</translation>
@ -197,16 +181,6 @@
<source>Override underlying DNS</source> <source>Override underlying DNS</source>
<translation type="unfinished">لغو دی ان اس زیربنایی</translation> <translation type="unfinished">لغو دی ان اس زیربنایی</translation>
</message> </message>
<message>
<source>It is recommended to leave it blank, but it sometimes does not work, at this time you can set this option.
For NekoRay, this rewrites the underlying(localhost) DNS in Tun Mode.
For NekoBox, this rewrites the underlying(localhost) DNS in Tun Mode, normal mode, and also URL Test.</source>
<translation type="unfinished">پیشنهاد میشود که این گزینه را انتخاب نشده باقی بگذارید ، اما گاهی اوقات کار نمیکند در این مواقع شما میتوانید این گزینه را انتخاب کنید ، برای Nekoray این گزینه دی ان اس زیربنایی را در حالت تونل بازنویسی میکند ، و برای NekoBox این گزینه دی ان اس زیربنایی را هم در حالت تونل و هم در حالت معمولی و تست آدرس بازنویسی میکند</translation>
</message>
<message>
<source>If you Tun Mode is not working, try to change this option.</source>
<translation type="unfinished">اگر حالت تونل برای شما کار نمیکند ، این گزینه را تغییر دهید</translation>
</message>
<message> <message>
<source>Default On</source> <source>Default On</source>
<translation type="unfinished">به صورت پیشفرض فعال</translation> <translation type="unfinished">به صورت پیشفرض فعال</translation>
@ -243,6 +217,10 @@ For NekoBox, this rewrites the underlying(localhost) DNS in Tun Mode, normal mod
<source>Old Share Link Format</source> <source>Old Share Link Format</source>
<translation type="unfinished"></translation> <translation type="unfinished"></translation>
</message> </message>
<message>
<source>Mixed (SOCKS+HTTP) Listen Port</source>
<translation type="unfinished"></translation>
</message>
</context> </context>
<context> <context>
<name>DialogEditGroup</name> <name>DialogEditGroup</name>
@ -871,14 +849,6 @@ This needs to be run NekoBox with administrator privileges.</source>
<source>Certificate</source> <source>Certificate</source>
<translation type="unfinished">گواهی</translation> <translation type="unfinished">گواهی</translation>
</message> </message>
<message>
<source>Auth Type</source>
<translation type="unfinished"></translation>
</message>
<message>
<source>Protocol</source>
<translation type="unfinished">پروتکل</translation>
</message>
<message> <message>
<source>Download (Mbps)</source> <source>Download (Mbps)</source>
<translation type="unfinished">دانلود (مگابیت بر ثانیه)</translation> <translation type="unfinished">دانلود (مگابیت بر ثانیه)</translation>
@ -911,10 +881,6 @@ This needs to be run NekoBox with administrator privileges.</source>
<source>SNI</source> <source>SNI</source>
<translation type="unfinished"></translation> <translation type="unfinished"></translation>
</message> </message>
<message>
<source>Auth Payload</source>
<translation type="unfinished"></translation>
</message>
<message> <message>
<source>Disable SNI</source> <source>Disable SNI</source>
<translation type="unfinished"></translation> <translation type="unfinished"></translation>
@ -1368,14 +1334,6 @@ This needs to be run NekoBox with administrator privileges.</source>
<source>Imported %1 profile(s)</source> <source>Imported %1 profile(s)</source>
<translation type="unfinished"></translation> <translation type="unfinished"></translation>
</message> </message>
<message>
<source>Http inbound is not enabled, can&apos;t set system proxy.</source>
<translation type="unfinished"></translation>
</message>
<message>
<source>Settings</source>
<translation>تنظیمات</translation>
</message>
<message> <message>
<source>Current server is incompatible with Tun. Please stop the server first, enable Tun Mode, and then restart.</source> <source>Current server is incompatible with Tun. Please stop the server first, enable Tun Mode, and then restart.</source>
<translation type="unfinished"></translation> <translation type="unfinished"></translation>
@ -1384,11 +1342,6 @@ This needs to be run NekoBox with administrator privileges.</source>
<source>Not Running</source> <source>Not Running</source>
<translation>در حال اجرا نیست</translation> <translation>در حال اجرا نیست</translation>
</message> </message>
<message>
<source>None</source>
<translatorcomment>هیچ یک</translatorcomment>
<translation>هیچ یک</translation>
</message>
<message> <message>
<source>Select</source> <source>Select</source>
<translation>انتخاب</translation> <translation>انتخاب</translation>
@ -1539,6 +1492,10 @@ End: %2</source>
<source>Stop Testing</source> <source>Stop Testing</source>
<translation type="unfinished"></translation> <translation type="unfinished"></translation>
</message> </message>
<message>
<source>URL Test</source>
<translation type="unfinished"></translation>
</message>
</context> </context>
<context> <context>
<name>ProxyItem</name> <name>ProxyItem</name>
@ -1679,6 +1636,10 @@ Direct: %2</source>
<source>Default</source> <source>Default</source>
<translation type="unfinished">پیش فرض</translation> <translation type="unfinished">پیش فرض</translation>
</message> </message>
<message>
<source>The last speed test did not exit completely, please wait. If it persists, please restart the program.</source>
<translation type="unfinished"></translation>
</message>
</context> </context>
<context> <context>
<name>Qv2ray::ui::widgets::AutoCompleteTextEdit</name> <name>Qv2ray::ui::widgets::AutoCompleteTextEdit</name>

View File

@ -23,14 +23,6 @@
<source>Edit</source> <source>Edit</source>
<translation>Изменить</translation> <translation>Изменить</translation>
</message> </message>
<message>
<source>Socks Listen Port</source>
<translation>Адрес входящих SOCKS</translation>
</message>
<message>
<source>HTTP Listen Port</source>
<translation>Адрес входящих HTTP</translation>
</message>
<message> <message>
<source>Enable</source> <source>Enable</source>
<translation>Вкл</translation> <translation>Вкл</translation>
@ -115,14 +107,6 @@
<source>Core</source> <source>Core</source>
<translation>Ядро</translation> <translation>Ядро</translation>
</message> </message>
<message>
<source>Asset Location</source>
<translation>Расположение файлов</translation>
</message>
<message>
<source>Default: dir of &quot;nekoray&quot;</source>
<translation>По умолчанию: текущая папка nekoray</translation>
</message>
<message> <message>
<source>Select</source> <source>Select</source>
<translation>Выбрать</translation> <translation>Выбрать</translation>
@ -211,18 +195,6 @@
<source>Override underlying DNS</source> <source>Override underlying DNS</source>
<translation>Переопределить нижестоящий DNS</translation> <translation>Переопределить нижестоящий DNS</translation>
</message> </message>
<message>
<source>It is recommended to leave it blank, but it sometimes does not work, at this time you can set this option.
For NekoRay, this rewrites the underlying(localhost) DNS in Tun Mode.
For NekoBox, this rewrites the underlying(localhost) DNS in Tun Mode, normal mode, and also URL Test.</source>
<translation>Рекомендуется оставить параметр пустым, но иногда это не срабатывает как надо, и в таком случае можно использовать эту опцию.
Для NekoRay это переопределяет нижестоящий (localhost) DNS в Tun режиме.
Для NekoBox это переопределяет нижестоящий (localhost) DNS в Tun режиме, нормальном режиме, а также при URL тесте.</translation>
</message>
<message>
<source>If you Tun Mode is not working, try to change this option.</source>
<translation>Если TUN-режим не работает, попробуйте изменить эту опцию.</translation>
</message>
<message> <message>
<source>Timeout (s)</source> <source>Timeout (s)</source>
<translation>Таймаут (с)</translation> <translation>Таймаут (с)</translation>
@ -243,6 +215,10 @@ For NekoBox, this rewrites the underlying(localhost) DNS in Tun Mode, normal mod
<source>Old Share Link Format</source> <source>Old Share Link Format</source>
<translation>Поделиться ссылкой в старом формате</translation> <translation>Поделиться ссылкой в старом формате</translation>
</message> </message>
<message>
<source>Mixed (SOCKS+HTTP) Listen Port</source>
<translation type="unfinished"></translation>
</message>
</context> </context>
<context> <context>
<name>DialogEditGroup</name> <name>DialogEditGroup</name>
@ -872,14 +848,6 @@ https://matsuridayo.github.io/n-configuration/#vpn-tun</translation>
</context> </context>
<context> <context>
<name>EditQUIC</name> <name>EditQUIC</name>
<message>
<source>Auth Type</source>
<translation>Тип авторизации</translation>
</message>
<message>
<source>Protocol</source>
<translation>Протокол</translation>
</message>
<message> <message>
<source>Download (Mbps)</source> <source>Download (Mbps)</source>
<translation>Скорость приема (Mbps)</translation> <translation>Скорость приема (Mbps)</translation>
@ -916,10 +884,6 @@ https://matsuridayo.github.io/n-configuration/#vpn-tun</translation>
<source>SNI</source> <source>SNI</source>
<translation>SNI</translation> <translation>SNI</translation>
</message> </message>
<message>
<source>Auth Payload</source>
<translation>Полезная нагрузка в режиме авторизации</translation>
</message>
<message> <message>
<source>Disable SNI</source> <source>Disable SNI</source>
<translation>Отключить SNI</translation> <translation>Отключить SNI</translation>
@ -1394,14 +1358,6 @@ https://matsuridayo.github.io/n-configuration/#vpn-tun</translation>
<source>Imported %1 profile(s)</source> <source>Imported %1 profile(s)</source>
<translation>Импортирован(ы) %1 профиль(ей)</translation> <translation>Импортирован(ы) %1 профиль(ей)</translation>
</message> </message>
<message>
<source>Http inbound is not enabled, can&apos;t set system proxy.</source>
<translation>HTTP inbound не включен в настройках, невозможно установить системный прокси.</translation>
</message>
<message>
<source>Settings</source>
<translation>Настройки</translation>
</message>
<message> <message>
<source>Please run NekoBox as admin</source> <source>Please run NekoBox as admin</source>
<translation>Пожалуйста, запустите NekoBox с правами администратора</translation> <translation>Пожалуйста, запустите NekoBox с правами администратора</translation>
@ -1414,10 +1370,6 @@ https://matsuridayo.github.io/n-configuration/#vpn-tun</translation>
<source>Not Running</source> <source>Not Running</source>
<translation>Не запущен</translation> <translation>Не запущен</translation>
</message> </message>
<message>
<source>None</source>
<translation>Нет</translation>
</message>
<message> <message>
<source>Select</source> <source>Select</source>
<translation>Выбор</translation> <translation>Выбор</translation>
@ -1546,6 +1498,10 @@ End: %2</source>
<source>Stop Testing</source> <source>Stop Testing</source>
<translation type="unfinished"></translation> <translation type="unfinished"></translation>
</message> </message>
<message>
<source>URL Test</source>
<translation type="unfinished"></translation>
</message>
</context> </context>
<context> <context>
<name>ProxyItem</name> <name>ProxyItem</name>
@ -1693,6 +1649,10 @@ Release note:
<source>Default</source> <source>Default</source>
<translation>По умолчанию</translation> <translation>По умолчанию</translation>
</message> </message>
<message>
<source>The last speed test did not exit completely, please wait. If it persists, please restart the program.</source>
<translation type="unfinished"></translation>
</message>
</context> </context>
<context> <context>
<name>Qv2ray::ui::widgets::AutoCompleteTextEdit</name> <name>Qv2ray::ui::widgets::AutoCompleteTextEdit</name>

View File

@ -11,18 +11,10 @@
<source>Enable</source> <source>Enable</source>
<translation></translation> <translation></translation>
</message> </message>
<message>
<source>HTTP Listen Port</source>
<translation>HTTP </translation>
</message>
<message> <message>
<source>Listen Address</source> <source>Listen Address</source>
<translation></translation> <translation></translation>
</message> </message>
<message>
<source>Socks Listen Port</source>
<translation>Socks </translation>
</message>
<message> <message>
<source>concurrency</source> <source>concurrency</source>
<translation></translation> <translation></translation>
@ -71,14 +63,6 @@
<source>Custom Inbound</source> <source>Custom Inbound</source>
<translation></translation> <translation></translation>
</message> </message>
<message>
<source>Asset Location</source>
<translation></translation>
</message>
<message>
<source>Default: dir of &quot;nekoray&quot;</source>
<translation> nekoray </translation>
</message>
<message> <message>
<source>Concurrent</source> <source>Concurrent</source>
<translation></translation> <translation></translation>
@ -203,18 +187,6 @@
<source>Override underlying DNS</source> <source>Override underlying DNS</source>
<translation> DNS</translation> <translation> DNS</translation>
</message> </message>
<message>
<source>It is recommended to leave it blank, but it sometimes does not work, at this time you can set this option.
For NekoRay, this rewrites the underlying(localhost) DNS in Tun Mode.
For NekoBox, this rewrites the underlying(localhost) DNS in Tun Mode, normal mode, and also URL Test.</source>
<translation>
NekoRay Tun underlying(localhost) DNS
NekoBox Tun URL underlying(localhost) DNS</translation>
</message>
<message>
<source>If you Tun Mode is not working, try to change this option.</source>
<translation> Tun </translation>
</message>
<message> <message>
<source>Default On</source> <source>Default On</source>
<translation></translation> <translation></translation>
@ -243,6 +215,10 @@ For NekoBox, this rewrites the underlying(localhost) DNS in Tun Mode, normal mod
<source>Interval (minute, invalid if less than 30)</source> <source>Interval (minute, invalid if less than 30)</source>
<translation> 30 </translation> <translation> 30 </translation>
</message> </message>
<message>
<source>Mixed (SOCKS+HTTP) Listen Port</source>
<translation>Mixed (SOCKS+HTTP) </translation>
</message>
</context> </context>
<context> <context>
<name>DialogEditGroup</name> <name>DialogEditGroup</name>
@ -877,14 +853,6 @@ This needs to be run NekoBox with administrator privileges.</source>
<source>Certificate</source> <source>Certificate</source>
<translation></translation> <translation></translation>
</message> </message>
<message>
<source>Auth Type</source>
<translation></translation>
</message>
<message>
<source>Protocol</source>
<translation></translation>
</message>
<message> <message>
<source>Download (Mbps)</source> <source>Download (Mbps)</source>
<translation> (Mbps)</translation> <translation> (Mbps)</translation>
@ -917,10 +885,6 @@ This needs to be run NekoBox with administrator privileges.</source>
<source>SNI</source> <source>SNI</source>
<translation>SNI</translation> <translation>SNI</translation>
</message> </message>
<message>
<source>Auth Payload</source>
<translation></translation>
</message>
<message> <message>
<source>Generate UUID</source> <source>Generate UUID</source>
<translation> UUID</translation> <translation> UUID</translation>
@ -1210,10 +1174,6 @@ This needs to be run NekoBox with administrator privileges.</source>
<source>Imported %1 profile(s)</source> <source>Imported %1 profile(s)</source>
<translation> %1 </translation> <translation> %1 </translation>
</message> </message>
<message>
<source>None</source>
<translation></translation>
</message>
<message> <message>
<source>Unavailable</source> <source>Unavailable</source>
<translation></translation> <translation></translation>
@ -1242,10 +1202,6 @@ This needs to be run NekoBox with administrator privileges.</source>
<source>Testing</source> <source>Testing</source>
<translation></translation> <translation></translation>
</message> </message>
<message>
<source>Http inbound is not enabled, can&apos;t set system proxy.</source>
<translation>HTTP </translation>
</message>
<message> <message>
<source>Update</source> <source>Update</source>
<translation></translation> <translation></translation>
@ -1316,10 +1272,6 @@ End: %2</source>
<source>Remove Unavailable</source> <source>Remove Unavailable</source>
<translation></translation> <translation></translation>
</message> </message>
<message>
<source>Settings</source>
<translation></translation>
</message>
<message> <message>
<source>New profile</source> <source>New profile</source>
<translation></translation> <translation></translation>
@ -1536,7 +1488,7 @@ Split by line.</source>
</message> </message>
<message> <message>
<source>In and Out IP</source> <source>In and Out IP</source>
<translation>IP</translation> <translation> IP</translation>
</message> </message>
<message> <message>
<source>Test Options</source> <source>Test Options</source>
@ -1546,6 +1498,10 @@ Split by line.</source>
<source>Stop Testing</source> <source>Stop Testing</source>
<translation></translation> <translation></translation>
</message> </message>
<message>
<source>URL Test</source>
<translation>URL </translation>
</message>
</context> </context>
<context> <context>
<name>ProxyItem</name> <name>ProxyItem</name>
@ -1693,6 +1649,10 @@ Release note:
<source>Default</source> <source>Default</source>
<translation></translation> <translation></translation>
</message> </message>
<message>
<source>The last speed test did not exit completely, please wait. If it persists, please restart the program.</source>
<translation>退</translation>
</message>
</context> </context>
<context> <context>
<name>Qv2ray::ui::widgets::AutoCompleteTextEdit</name> <name>Qv2ray::ui::widgets::AutoCompleteTextEdit</name>

View File

@ -59,16 +59,8 @@ DialogBasicSettings::DialogBasicSettings(QWidget *parent)
// Common // Common
if (IS_NEKO_BOX) { ui->log_level->addItems(QStringLiteral("trace debug info warn error fatal panic").split(" "));
ui->groupBox_http->hide(); ui->mux_protocol->addItems({"h2mux", "smux", "yamux"});
ui->inbound_socks_port_l->setText(ui->inbound_socks_port_l->text().replace("Socks", "Mixed (SOCKS+HTTP)"));
ui->log_level->addItems(QString("trace debug info warn error fatal panic").split(" "));
ui->mux_protocol->addItems({"h2mux", "smux", "yamux"});
} else {
ui->log_level->addItems({"debug", "info", "warning", "none"});
ui->mux_protocol->hide();
ui->mux_padding->hide();
}
refresh_auth(); refresh_auth();
@ -76,7 +68,6 @@ DialogBasicSettings::DialogBasicSettings(QWidget *parent)
D_LOAD_COMBO_STRING(log_level) D_LOAD_COMBO_STRING(log_level)
CACHE.custom_inbound = NekoGui::dataStore->custom_inbound; CACHE.custom_inbound = NekoGui::dataStore->custom_inbound;
D_LOAD_INT(inbound_socks_port) D_LOAD_INT(inbound_socks_port)
D_LOAD_INT_ENABLE(inbound_http_port, http_enable)
D_LOAD_INT(test_concurrent) D_LOAD_INT(test_concurrent)
D_LOAD_INT(test_download_timeout) D_LOAD_INT(test_download_timeout)
D_LOAD_STRING(test_latency_url) D_LOAD_STRING(test_latency_url)
@ -102,9 +93,7 @@ DialogBasicSettings::DialogBasicSettings(QWidget *parent)
#endif #endif
// Style // Style
if (IS_NEKO_BOX) { ui->connection_statistics_box->setDisabled(true);
ui->connection_statistics_box->setDisabled(true);
}
// //
D_LOAD_BOOL(check_include_pre) D_LOAD_BOOL(check_include_pre)
D_LOAD_BOOL(connection_statistics) D_LOAD_BOOL(connection_statistics)
@ -166,11 +155,9 @@ DialogBasicSettings::DialogBasicSettings(QWidget *parent)
// Core // Core
ui->groupBox_core->setTitle(software_core_name); ui->groupBox_core->setTitle(software_core_name);
ui->core_v2ray_asset->setText(NekoGui::dataStore->v2ray_asset_dir);
// //
CACHE.extraCore = QString2QJsonObject(NekoGui::dataStore->extraCore->core_map); CACHE.extraCore = QString2QJsonObject(NekoGui::dataStore->extraCore->core_map);
if (!CACHE.extraCore.contains("naive")) CACHE.extraCore.insert("naive", ""); if (!CACHE.extraCore.contains("naive")) CACHE.extraCore.insert("naive", "");
if (!CACHE.extraCore.contains("hysteria")) CACHE.extraCore.insert("hysteria", "");
if (!CACHE.extraCore.contains("hysteria2")) CACHE.extraCore.insert("hysteria2", ""); if (!CACHE.extraCore.contains("hysteria2")) CACHE.extraCore.insert("hysteria2", "");
if (!CACHE.extraCore.contains("tuic")) CACHE.extraCore.insert("tuic", ""); if (!CACHE.extraCore.contains("tuic")) CACHE.extraCore.insert("tuic", "");
// //
@ -179,16 +166,6 @@ DialogBasicSettings::DialogBasicSettings(QWidget *parent)
extra_core_layout->addWidget(new ExtraCoreWidget(&CACHE.extraCore, s)); extra_core_layout->addWidget(new ExtraCoreWidget(&CACHE.extraCore, s));
} }
// //
connect(ui->core_v2ray_asset, &QLineEdit::textChanged, this, [=] {
CACHE.needRestart = true;
});
connect(ui->core_v2ray_asset_pick, &QPushButton::clicked, this, [=] {
auto fn = QFileDialog::getExistingDirectory(this, tr("Select"), QDir::currentPath(),
QFileDialog::Option::ShowDirsOnly | QFileDialog::Option::ReadOnly);
if (!fn.isEmpty()) {
ui->core_v2ray_asset->setText(fn);
}
});
connect(ui->extra_core_add, &QPushButton::clicked, this, [=] { connect(ui->extra_core_add, &QPushButton::clicked, this, [=] {
bool ok; bool ok;
auto s = QInputDialog::getText(nullptr, tr("Add"), auto s = QInputDialog::getText(nullptr, tr("Add"),
@ -225,7 +202,7 @@ DialogBasicSettings::DialogBasicSettings(QWidget *parent)
// Security // Security
ui->utlsFingerprint->addItems(IS_NEKO_BOX ? Preset::SingBox::UtlsFingerPrint : Preset::Xray::UtlsFingerPrint); ui->utlsFingerprint->addItems(Preset::SingBox::UtlsFingerPrint);
D_LOAD_BOOL(skip_cert) D_LOAD_BOOL(skip_cert)
ui->utlsFingerprint->setCurrentText(NekoGui::dataStore->utlsFingerprint); ui->utlsFingerprint->setCurrentText(NekoGui::dataStore->utlsFingerprint);
@ -242,7 +219,6 @@ void DialogBasicSettings::accept() {
D_SAVE_COMBO_STRING(log_level) D_SAVE_COMBO_STRING(log_level)
NekoGui::dataStore->custom_inbound = CACHE.custom_inbound; NekoGui::dataStore->custom_inbound = CACHE.custom_inbound;
D_SAVE_INT(inbound_socks_port) D_SAVE_INT(inbound_socks_port)
D_SAVE_INT_ENABLE(inbound_http_port, http_enable)
D_SAVE_INT(test_concurrent) D_SAVE_INT(test_concurrent)
D_SAVE_INT(test_download_timeout) D_SAVE_INT(test_download_timeout)
D_SAVE_STRING(test_latency_url) D_SAVE_STRING(test_latency_url)
@ -291,7 +267,6 @@ void DialogBasicSettings::accept() {
// Core // Core
NekoGui::dataStore->v2ray_asset_dir = ui->core_v2ray_asset->text();
NekoGui::dataStore->extraCore->core_map = QJsonObject2QString(CACHE.extraCore, true); NekoGui::dataStore->extraCore->core_map = QJsonObject2QString(CACHE.extraCore, true);
// Mux // Mux
@ -306,7 +281,7 @@ void DialogBasicSettings::accept() {
NekoGui::dataStore->utlsFingerprint = ui->utlsFingerprint->currentText(); NekoGui::dataStore->utlsFingerprint = ui->utlsFingerprint->currentText();
// 关闭连接统计,停止刷新前清空记录。 // 关闭连接统计,停止刷新前清空记录。
if (NekoGui::dataStore->traffic_loop_interval == 0 || NekoGui::dataStore->connection_statistics == false) { if (NekoGui::dataStore->traffic_loop_interval == 0 || !NekoGui::dataStore->connection_statistics) {
MW_dialog_message("", "ClearConnectionList"); MW_dialog_message("", "ClearConnectionList");
} }
@ -395,80 +370,39 @@ void DialogBasicSettings::on_core_settings_clicked() {
MyLineEdit *core_box_clash_api; MyLineEdit *core_box_clash_api;
MyLineEdit *core_box_clash_api_secret; MyLineEdit *core_box_clash_api_secret;
MyLineEdit *core_box_underlying_dns; MyLineEdit *core_box_underlying_dns;
QCheckBox *core_ray_direct_dns;
QCheckBox *core_ray_windows_disable_auto_interface;
QComboBox *core_ray_freedom_domainStrategy;
// //
auto core_box_underlying_dns_l = new QLabel(tr("Override underlying DNS")); auto core_box_underlying_dns_l = new QLabel(tr("Override underlying DNS"));
core_box_underlying_dns_l->setToolTip(tr(
"It is recommended to leave it blank, but it sometimes does not work, at this time you can set this option.\n"
"For NekoRay, this rewrites the underlying(localhost) DNS in Tun Mode.\n"
"For NekoBox, this rewrites the underlying(localhost) DNS in Tun Mode, normal mode, and also URL Test."));
core_box_underlying_dns = new MyLineEdit; core_box_underlying_dns = new MyLineEdit;
core_box_underlying_dns->setText(NekoGui::dataStore->core_box_underlying_dns); core_box_underlying_dns->setText(NekoGui::dataStore->core_box_underlying_dns);
core_box_underlying_dns->setMinimumWidth(300); core_box_underlying_dns->setMinimumWidth(300);
layout->addWidget(core_box_underlying_dns_l, ++line, 0); layout->addWidget(core_box_underlying_dns_l, ++line, 0);
layout->addWidget(core_box_underlying_dns, line, 1); layout->addWidget(core_box_underlying_dns, line, 1);
// //
if (IS_NEKO_BOX) { auto core_box_enable_clash_api_l = new QLabel("Enable Clash API");
auto core_box_enable_clash_api_l = new QLabel("Enable Clash API"); core_box_enable_clash_api = new QCheckBox;
core_box_enable_clash_api = new QCheckBox; core_box_enable_clash_api->setChecked(NekoGui::dataStore->core_box_clash_api > 0);
core_box_enable_clash_api->setChecked(NekoGui::dataStore->core_box_clash_api > 0); layout->addWidget(core_box_enable_clash_api_l, ++line, 0);
layout->addWidget(core_box_enable_clash_api_l, ++line, 0); layout->addWidget(core_box_enable_clash_api, line, 1);
layout->addWidget(core_box_enable_clash_api, line, 1); //
// auto core_box_clash_api_l = new QLabel("Clash API Listen Port");
auto core_box_clash_api_l = new QLabel("Clash API Listen Port"); core_box_clash_api = new MyLineEdit;
core_box_clash_api = new MyLineEdit; core_box_clash_api->setText(Int2String(std::abs(NekoGui::dataStore->core_box_clash_api)));
core_box_clash_api->setText(Int2String(std::abs(NekoGui::dataStore->core_box_clash_api))); layout->addWidget(core_box_clash_api_l, ++line, 0);
layout->addWidget(core_box_clash_api_l, ++line, 0); layout->addWidget(core_box_clash_api, line, 1);
layout->addWidget(core_box_clash_api, line, 1); //
// auto core_box_clash_api_secret_l = new QLabel("Clash API Secret");
auto core_box_clash_api_secret_l = new QLabel("Clash API Secret"); core_box_clash_api_secret = new MyLineEdit;
core_box_clash_api_secret = new MyLineEdit; core_box_clash_api_secret->setText(NekoGui::dataStore->core_box_clash_api_secret);
core_box_clash_api_secret->setText(NekoGui::dataStore->core_box_clash_api_secret); layout->addWidget(core_box_clash_api_secret_l, ++line, 0);
layout->addWidget(core_box_clash_api_secret_l, ++line, 0); layout->addWidget(core_box_clash_api_secret, line, 1);
layout->addWidget(core_box_clash_api_secret, line, 1);
} else {
auto core_ray_direct_dns_l = new QLabel("NKR_CORE_RAY_DIRECT_DNS");
core_ray_direct_dns_l->setToolTip(tr("If you Tun Mode is not working, try to change this option."));
core_ray_direct_dns = new QCheckBox;
core_ray_direct_dns->setChecked(NekoGui::dataStore->core_ray_direct_dns);
connect(core_ray_direct_dns, &QCheckBox::clicked, this, [&] { CACHE.needRestart = true; });
layout->addWidget(core_ray_direct_dns_l, ++line, 0);
layout->addWidget(core_ray_direct_dns, line, 1);
//
auto core_ray_freedom_domainStrategy_l = new QLabel("Freedom Strategy");
core_ray_freedom_domainStrategy = new QComboBox;
core_ray_freedom_domainStrategy->addItems({"", "AsIs", "UseIP", "UseIPv4", "UseIPv6"});
core_ray_freedom_domainStrategy->setCurrentText(NekoGui::dataStore->core_ray_freedom_domainStrategy);
layout->addWidget(core_ray_freedom_domainStrategy_l, ++line, 0);
layout->addWidget(core_ray_freedom_domainStrategy, line, 1);
#ifdef Q_OS_WIN
auto core_ray_windows_disable_auto_interface_l = new QLabel("NKR_CORE_RAY_WINDOWS_DISABLE_AUTO_INTERFACE");
core_ray_windows_disable_auto_interface_l->setToolTip(tr("If you Tun Mode is not working, try to change this option."));
core_ray_windows_disable_auto_interface = new QCheckBox;
core_ray_windows_disable_auto_interface->setChecked(NekoGui::dataStore->core_ray_windows_disable_auto_interface);
connect(core_ray_windows_disable_auto_interface, &QCheckBox::clicked, this, [&] { CACHE.needRestart = true; });
layout->addWidget(core_ray_windows_disable_auto_interface_l, ++line, 0);
layout->addWidget(core_ray_windows_disable_auto_interface, line, 1);
#endif
}
// //
auto box = new QDialogButtonBox; auto box = new QDialogButtonBox;
box->setOrientation(Qt::Horizontal); box->setOrientation(Qt::Horizontal);
box->setStandardButtons(QDialogButtonBox::Cancel | QDialogButtonBox::Ok); box->setStandardButtons(QDialogButtonBox::Cancel | QDialogButtonBox::Ok);
connect(box, &QDialogButtonBox::accepted, w, [=] { connect(box, &QDialogButtonBox::accepted, w, [=] {
NekoGui::dataStore->core_box_underlying_dns = core_box_underlying_dns->text(); NekoGui::dataStore->core_box_underlying_dns = core_box_underlying_dns->text();
if (IS_NEKO_BOX) { NekoGui::dataStore->core_box_clash_api = core_box_clash_api->text().toInt() * (core_box_enable_clash_api->isChecked() ? 1 : -1);
NekoGui::dataStore->core_box_clash_api = core_box_clash_api->text().toInt() * (core_box_enable_clash_api->isChecked() ? 1 : -1); NekoGui::dataStore->core_box_clash_api_secret = core_box_clash_api_secret->text();
NekoGui::dataStore->core_box_clash_api_secret = core_box_clash_api_secret->text();
} else {
NekoGui::dataStore->core_ray_direct_dns = core_ray_direct_dns->isChecked();
NekoGui::dataStore->core_ray_freedom_domainStrategy = core_ray_freedom_domainStrategy->currentText();
#ifdef Q_OS_WIN
NekoGui::dataStore->core_ray_windows_disable_auto_interface = core_ray_windows_disable_auto_interface->isChecked();
#endif
}
MW_dialog_message(Dialog_DialogBasicSettings, "UpdateDataStore"); MW_dialog_message(Dialog_DialogBasicSettings, "UpdateDataStore");
w->accept(); w->accept();
}); });

View File

@ -95,7 +95,7 @@
<item> <item>
<widget class="QLabel" name="inbound_socks_port_l"> <widget class="QLabel" name="inbound_socks_port_l">
<property name="text"> <property name="text">
<string>Socks Listen Port</string> <string>Mixed (SOCKS+HTTP) Listen Port</string>
</property> </property>
</widget> </widget>
</item> </item>
@ -112,36 +112,6 @@
</layout> </layout>
</widget> </widget>
</item> </item>
<item>
<widget class="QGroupBox" name="groupBox_http">
<layout class="QHBoxLayout" name="horizontalLayout_16">
<item>
<widget class="QLabel" name="label_5">
<property name="text">
<string>HTTP Listen Port</string>
</property>
</widget>
</item>
<item>
<widget class="QLineEdit" name="inbound_http_port">
<property name="sizePolicy">
<sizepolicy hsizetype="Preferred" vsizetype="Fixed">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
</widget>
</item>
<item>
<widget class="QCheckBox" name="http_enable">
<property name="text">
<string>Enable</string>
</property>
</widget>
</item>
</layout>
</widget>
</item>
</layout> </layout>
</item> </item>
<item> <item>
@ -596,39 +566,7 @@
<item> <item>
<widget class="QWidget" name="assest_group" native="true"> <widget class="QWidget" name="assest_group" native="true">
<layout class="QGridLayout" name="gridLayout_2"> <layout class="QGridLayout" name="gridLayout_2">
<item row="0" column="0">
<widget class="QLabel" name="label_12">
<property name="text">
<string>Asset Location</string>
</property>
</widget>
</item>
<item row="0" column="1"> <item row="0" column="1">
<layout class="QGridLayout" name="gridLayout_4">
<item row="0" column="0">
<widget class="MyLineEdit" name="core_v2ray_asset">
<property name="placeholderText">
<string>Default: dir of &quot;nekoray&quot;</string>
</property>
</widget>
</item>
<item row="0" column="1">
<widget class="QPushButton" name="core_v2ray_asset_pick">
<property name="text">
<string>Select</string>
</property>
</widget>
</item>
</layout>
</item>
<item row="1" column="0">
<widget class="QLabel" name="label_3">
<property name="text">
<string notr="true">Loglevel</string>
</property>
</widget>
</item>
<item row="1" column="1">
<widget class="QComboBox" name="log_level"> <widget class="QComboBox" name="log_level">
<property name="sizePolicy"> <property name="sizePolicy">
<sizepolicy hsizetype="Maximum" vsizetype="Fixed"> <sizepolicy hsizetype="Maximum" vsizetype="Fixed">
@ -638,14 +576,21 @@
</property> </property>
</widget> </widget>
</item> </item>
<item row="2" column="0"> <item row="1" column="0">
<widget class="QLabel" name="label_6"> <widget class="QLabel" name="label_6">
<property name="text"> <property name="text">
<string>Multiplex (mux)</string> <string>Multiplex (mux)</string>
</property> </property>
</widget> </widget>
</item> </item>
<item row="2" column="1"> <item row="0" column="0">
<widget class="QLabel" name="label_3">
<property name="text">
<string notr="true">Loglevel</string>
</property>
</widget>
</item>
<item row="1" column="1">
<layout class="QHBoxLayout" name="horizontalLayout"> <layout class="QHBoxLayout" name="horizontalLayout">
<item> <item>
<widget class="QComboBox" name="mux_protocol"/> <widget class="QComboBox" name="mux_protocol"/>
@ -709,8 +654,8 @@
<rect> <rect>
<x>0</x> <x>0</x>
<y>0</y> <y>0</y>
<width>198</width> <width>632</width>
<height>58</height> <height>299</height>
</rect> </rect>
</property> </property>
<layout class="QVBoxLayout" name="verticalLayout_6"> <layout class="QVBoxLayout" name="verticalLayout_6">

View File

@ -22,19 +22,13 @@ DialogManageRoutes::DialogManageRoutes(QWidget *parent) : QDialog(parent), ui(ne
QStringList qsValue = {""}; QStringList qsValue = {""};
QString dnsHelpDocumentUrl; QString dnsHelpDocumentUrl;
if (IS_NEKO_BOX) { //
ui->outbound_domain_strategy->addItems(Preset::SingBox::DomainStrategy); ui->outbound_domain_strategy->addItems(Preset::SingBox::DomainStrategy);
ui->domainStrategyCombo->addItems(Preset::SingBox::DomainStrategy); ui->domainStrategyCombo->addItems(Preset::SingBox::DomainStrategy);
qsValue += QString("prefer_ipv4 prefer_ipv6 ipv4_only ipv6_only").split(" "); qsValue += QStringLiteral("prefer_ipv4 prefer_ipv6 ipv4_only ipv6_only").split(" ");
ui->dns_object->setPlaceholderText(DecodeB64IfValid("ewogICJzZXJ2ZXJzIjogW10sCiAgInJ1bGVzIjogW10sCiAgImZpbmFsIjogIiIsCiAgInN0cmF0ZWd5IjogIiIsCiAgImRpc2FibGVfY2FjaGUiOiBmYWxzZSwKICAiZGlzYWJsZV9leHBpcmUiOiBmYWxzZSwKICAiaW5kZXBlbmRlbnRfY2FjaGUiOiBmYWxzZSwKICAicmV2ZXJzZV9tYXBwaW5nIjogZmFsc2UsCiAgImZha2VpcCI6IHt9Cn0=")); ui->dns_object->setPlaceholderText(DecodeB64IfValid("ewogICJzZXJ2ZXJzIjogW10sCiAgInJ1bGVzIjogW10sCiAgImZpbmFsIjogIiIsCiAgInN0cmF0ZWd5IjogIiIsCiAgImRpc2FibGVfY2FjaGUiOiBmYWxzZSwKICAiZGlzYWJsZV9leHBpcmUiOiBmYWxzZSwKICAiaW5kZXBlbmRlbnRfY2FjaGUiOiBmYWxzZSwKICAicmV2ZXJzZV9tYXBwaW5nIjogZmFsc2UsCiAgImZha2VpcCI6IHt9Cn0="));
dnsHelpDocumentUrl = "https://sing-box.sagernet.org/configuration/dns/"; dnsHelpDocumentUrl = "https://sing-box.sagernet.org/configuration/dns/";
} else { //
ui->outbound_domain_strategy->addItems({"AsIs", "UseIPv4", "UseIPv6", "PreferIPv4", "PreferIPv6"});
ui->domainStrategyCombo->addItems({"AsIs", "IPIfNonMatch", "IPOnDemand"});
qsValue += QString("use_ip use_ip4 use_ip6").split(" ");
ui->dns_object->setPlaceholderText(DecodeB64IfValid("ewogICJzZXJ2ZXJzIjogW10KfQ=="));
dnsHelpDocumentUrl = "https://www.v2fly.org/config/dns.html";
}
ui->direct_dns_strategy->addItems(qsValue); ui->direct_dns_strategy->addItems(qsValue);
ui->remote_dns_strategy->addItems(qsValue); ui->remote_dns_strategy->addItems(qsValue);
// //

View File

@ -20,7 +20,6 @@ DialogVPNSettings::DialogVPNSettings(QWidget *parent) : QDialog(parent), ui(new
ui->hide_console->setVisible(false); ui->hide_console->setVisible(false);
#endif #endif
ui->strict_route->setChecked(NekoGui::dataStore->vpn_strict_route); ui->strict_route->setChecked(NekoGui::dataStore->vpn_strict_route);
ui->single_core->setVisible(IS_NEKO_BOX);
ui->single_core->setChecked(NekoGui::dataStore->vpn_internal_tun); ui->single_core->setChecked(NekoGui::dataStore->vpn_internal_tun);
// //
D_LOAD_STRING_PLAIN(vpn_rule_cidr) D_LOAD_STRING_PLAIN(vpn_rule_cidr)

View File

@ -62,7 +62,7 @@ DialogEditProfile::DialogEditProfile(const QString &_type, int profileOrGroupId,
ui->host_l->setVisible(false); ui->host_l->setVisible(false);
} }
// 传输设置 ED // 传输设置 ED
if (txt == "ws" && IS_NEKO_BOX) { if (txt == "ws") {
ui->ws_early_data_length->setVisible(true); ui->ws_early_data_length->setVisible(true);
ui->ws_early_data_length_l->setVisible(true); ui->ws_early_data_length_l->setVisible(true);
ui->ws_early_data_name->setVisible(true); ui->ws_early_data_name->setVisible(true);
@ -74,11 +74,7 @@ DialogEditProfile::DialogEditProfile(const QString &_type, int profileOrGroupId,
ui->ws_early_data_name_l->setVisible(false); ui->ws_early_data_name_l->setVisible(false);
} }
// 传输设置 for NekoBox // 传输设置 for NekoBox
if (IS_NEKO_BOX) { if (!ui->utlsFingerprint->count()) ui->utlsFingerprint->addItems(Preset::SingBox::UtlsFingerPrint);
if (!ui->utlsFingerprint->count()) ui->utlsFingerprint->addItems(Preset::SingBox::UtlsFingerPrint);
} else {
if (!ui->utlsFingerprint->count()) ui->utlsFingerprint->addItems(Preset::Xray::UtlsFingerPrint);
}
// 传输设置 是否可见 // 传输设置 是否可见
int networkBoxVisible = 0; int networkBoxVisible = 0;
for (auto label: ui->network_box->findChildren<QLabel *>()) { for (auto label: ui->network_box->findChildren<QLabel *>()) {
@ -89,19 +85,13 @@ DialogEditProfile::DialogEditProfile(const QString &_type, int profileOrGroupId,
}); });
ui->network->removeItem(0); ui->network->removeItem(0);
// if (IS_NEKO_BOX) {
// ui->network->addItem("httpupgrade");
// }
// security changed // security changed
connect(ui->security, &QComboBox::currentTextChanged, this, [=](const QString &txt) { connect(ui->security, &QComboBox::currentTextChanged, this, [=](const QString &txt) {
if (txt == "tls") { if (txt == "tls") {
ui->security_box->setVisible(true); ui->security_box->setVisible(true);
ui->tls_camouflage_box->setVisible(true); ui->tls_camouflage_box->setVisible(true);
if (IS_NEKO_BOX) { ui->reality_spx->hide();
ui->reality_spx->hide(); ui->reality_spx_l->hide();
ui->reality_spx_l->hide();
}
} else { } else {
ui->security_box->setVisible(false); ui->security_box->setVisible(false);
ui->tls_camouflage_box->setVisible(false); ui->tls_camouflage_box->setVisible(false);
@ -124,7 +114,6 @@ DialogEditProfile::DialogEditProfile(const QString &_type, int profileOrGroupId,
LOAD_TYPE("vmess") LOAD_TYPE("vmess")
LOAD_TYPE("vless") LOAD_TYPE("vless")
LOAD_TYPE("naive") LOAD_TYPE("naive")
LOAD_TYPE("hysteria")
LOAD_TYPE("hysteria2") LOAD_TYPE("hysteria2")
LOAD_TYPE("tuic") LOAD_TYPE("tuic")
ui->type->addItem(tr("Custom (%1 outbound)").arg(software_core_name), "internal"); ui->type->addItem(tr("Custom (%1 outbound)").arg(software_core_name), "internal");
@ -182,7 +171,7 @@ void DialogEditProfile::typeSelected(const QString &newType) {
auto _innerWidget = new EditNaive(this); auto _innerWidget = new EditNaive(this);
innerWidget = _innerWidget; innerWidget = _innerWidget;
innerEditor = _innerWidget; innerEditor = _innerWidget;
} else if (type == "hysteria" || type == "hysteria2" || type == "tuic") { } else if (type == "hysteria2" || type == "tuic") {
auto _innerWidget = new EditQUIC(this); auto _innerWidget = new EditQUIC(this);
innerWidget = _innerWidget; innerWidget = _innerWidget;
innerEditor = _innerWidget; innerEditor = _innerWidget;
@ -286,47 +275,43 @@ void DialogEditProfile::typeSelected(const QString &newType) {
ADD_ASTERISK(this) ADD_ASTERISK(this)
// 设置 for NekoBox // 设置 for NekoBox
if (IS_NEKO_BOX) { if (type == "vmess" || type == "vless") {
if (type == "vmess" || type == "vless") { ui->packet_encoding->setVisible(true);
ui->packet_encoding->setVisible(true); ui->packet_encoding_l->setVisible(true);
ui->packet_encoding_l->setVisible(true);
} else {
ui->packet_encoding->setVisible(false);
ui->packet_encoding_l->setVisible(false);
}
if (type == "vmess" || type == "vless" || type == "trojan") {
ui->network_l->setVisible(true);
ui->network->setVisible(true);
ui->network_box->setVisible(true);
} else {
ui->network_l->setVisible(false);
ui->network->setVisible(false);
ui->network_box->setVisible(false);
}
if (type == "vmess" || type == "vless" || type == "trojan" || type == "http") {
ui->security->setVisible(true);
ui->security_l->setVisible(true);
} else {
ui->security->setVisible(false);
ui->security_l->setVisible(false);
}
if (type == "vmess" || type == "vless" || type == "trojan" || type == "shadowsocks") {
ui->multiplex->setVisible(true);
ui->multiplex_l->setVisible(true);
} else {
ui->multiplex->setVisible(false);
ui->multiplex_l->setVisible(false);
}
// 设置 是否可见
int streamBoxVisible = 0;
for (auto label: ui->stream_box->findChildren<QLabel *>()) {
if (!label->isHidden()) streamBoxVisible++;
}
ui->stream_box->setVisible(streamBoxVisible);
} else { } else {
ui->packet_encoding->setVisible(false); ui->packet_encoding->setVisible(false);
ui->packet_encoding_l->setVisible(false); ui->packet_encoding_l->setVisible(false);
} }
if (type == "vmess" || type == "vless" || type == "trojan") {
ui->network_l->setVisible(true);
ui->network->setVisible(true);
ui->network_box->setVisible(true);
} else {
ui->network_l->setVisible(false);
ui->network->setVisible(false);
ui->network_box->setVisible(false);
}
if (type == "vmess" || type == "vless" || type == "trojan" || type == "http") {
ui->security->setVisible(true);
ui->security_l->setVisible(true);
} else {
ui->security->setVisible(false);
ui->security_l->setVisible(false);
}
if (type == "vmess" || type == "vless" || type == "trojan" || type == "shadowsocks") {
ui->multiplex->setVisible(true);
ui->multiplex_l->setVisible(true);
} else {
ui->multiplex->setVisible(false);
ui->multiplex_l->setVisible(false);
}
// 设置 是否可见
int streamBoxVisible = 0;
for (auto label: ui->stream_box->findChildren<QLabel *>()) {
if (!label->isHidden()) streamBoxVisible++;
}
ui->stream_box->setVisible(streamBoxVisible);
// 载入 type 之后,有些类型没有右边的设置 // 载入 type 之后,有些类型没有右边的设置
auto rightNoBox = (ui->stream_box->isHidden() && ui->network_box->isHidden() && ui->security_box->isHidden()); auto rightNoBox = (ui->stream_box->isHidden() && ui->network_box->isHidden() && ui->security_box->isHidden());

View File

@ -245,6 +245,11 @@
<string notr="true">ws</string> <string notr="true">ws</string>
</property> </property>
</item> </item>
<item>
<property name="text">
<string notr="true">httpupgrade</string>
</property>
</item>
<item> <item>
<property name="text"> <property name="text">
<string notr="true">http</string> <string notr="true">http</string>

View File

@ -40,7 +40,6 @@ void EditCustom::onStart(std::shared_ptr<NekoGui::ProxyEntity> _ent) {
// load known core // load known core
auto core_map = QString2QJsonObject(NekoGui::dataStore->extraCore->core_map); auto core_map = QString2QJsonObject(NekoGui::dataStore->extraCore->core_map);
for (const auto &key: core_map.keys()) { for (const auto &key: core_map.keys()) {
if (key == "naive" || key == "hysteria") continue;
ui->core->addItem(key); ui->core->addItem(key);
} }
if (preset_core == "internal") { if (preset_core == "internal") {
@ -119,7 +118,7 @@ void EditCustom::onStart(std::shared_ptr<NekoGui::ProxyEntity> _ent) {
auto command = QStringList{extR->program}; auto command = QStringList{extR->program};
command += extR->arguments; command += extR->arguments;
auto btn = QMessageBox::information(this, tr("Preview config"), auto btn = QMessageBox::information(this, tr("Preview config"),
QString("Command: %1\n\n%2").arg(QStringList2Command(command), extR->config_export), QStringLiteral("Command: %1\n\n%2").arg(QStringList2Command(command), extR->config_export),
"OK", "Copy", "", 0, 0); "OK", "Copy", "", 0, 0);
if (btn == 1) { if (btn == 1) {
QApplication::clipboard()->setText(extR->config_export); QApplication::clipboard()->setText(extR->config_export);

View File

@ -25,13 +25,10 @@ void EditQUIC::onStart(std::shared_ptr<NekoGui::ProxyEntity> _ent) {
P_LOAD_INT(downloadMbps); P_LOAD_INT(downloadMbps);
P_LOAD_BOOL(disableMtuDiscovery) P_LOAD_BOOL(disableMtuDiscovery)
P_LOAD_STRING(obfsPassword); P_LOAD_STRING(obfsPassword);
P_LOAD_STRING(authPayload);
P_LOAD_INT(streamReceiveWindow); P_LOAD_INT(streamReceiveWindow);
P_LOAD_INT(connectionReceiveWindow); P_LOAD_INT(connectionReceiveWindow);
P_LOAD_BOOL(forceExternal); P_LOAD_BOOL(forceExternal);
P_LOAD_COMBO_INT(hyProtocol);
P_LOAD_COMBO_INT(authPayloadType);
P_LOAD_STRING(uuid); P_LOAD_STRING(uuid);
P_LOAD_STRING(password); P_LOAD_STRING(password);
@ -48,7 +45,7 @@ void EditQUIC::onStart(std::shared_ptr<NekoGui::ProxyEntity> _ent) {
P_LOAD_BOOL(allowInsecure); P_LOAD_BOOL(allowInsecure);
P_LOAD_BOOL(disableSni); P_LOAD_BOOL(disableSni);
if (bean->proxy_type == NekoGui_fmt::QUICBean::proxy_Hysteria || bean->proxy_type == NekoGui_fmt::QUICBean::proxy_Hysteria2) { if (bean->proxy_type == NekoGui_fmt::QUICBean::proxy_Hysteria2) {
ui->uuid->hide(); ui->uuid->hide();
ui->uuid_l->hide(); ui->uuid_l->hide();
ui->uuidgen->hide(); ui->uuidgen->hide();
@ -60,31 +57,15 @@ void EditQUIC::onStart(std::shared_ptr<NekoGui::ProxyEntity> _ent) {
ui->heartbeat->hide(); ui->heartbeat->hide();
ui->heartbeat_l->hide(); ui->heartbeat_l->hide();
ui->uos->hide(); ui->uos->hide();
if (!IS_NEKO_BOX) ui->forceExternal->hide();
if (bean->proxy_type == NekoGui_fmt::QUICBean::proxy_Hysteria) { // hy1 ui->alpn->hide();
ui->password->hide(); ui->alpn_l->hide();
ui->password_l->hide(); ui->TLS->removeItem(ui->alpn_sp);
} else { // hy2 ui->disableMtuDiscovery->hide();
ui->hyProtocol->hide(); ui->connectionReceiveWindow->hide();
ui->hyProtocol_l->hide(); ui->connectionReceiveWindow_l->hide();
ui->hyProtocol->hide(); ui->streamReceiveWindow->hide();
ui->hyProtocol_l->hide(); ui->streamReceiveWindow_l->hide();
ui->authPayload->hide();
ui->authPayload_l->hide();
ui->authPayloadType->hide();
ui->authPayloadType_l->hide();
ui->alpn->hide();
ui->alpn_l->hide();
ui->TLS->removeItem(ui->alpn_sp);
if (IS_NEKO_BOX) {
ui->disableMtuDiscovery->hide();
ui->connectionReceiveWindow->hide();
ui->connectionReceiveWindow_l->hide();
ui->streamReceiveWindow->hide();
ui->streamReceiveWindow_l->hide();
}
}
} else if (bean->proxy_type == NekoGui_fmt::QUICBean::proxy_TUIC) { } else if (bean->proxy_type == NekoGui_fmt::QUICBean::proxy_TUIC) {
ui->hopPort->hide(); ui->hopPort->hide();
ui->hopPort_l->hide(); ui->hopPort_l->hide();
@ -94,22 +75,14 @@ void EditQUIC::onStart(std::shared_ptr<NekoGui::ProxyEntity> _ent) {
ui->uploadMbps_l->hide(); ui->uploadMbps_l->hide();
ui->downloadMbps->hide(); ui->downloadMbps->hide();
ui->downloadMbps_l->hide(); ui->downloadMbps_l->hide();
ui->hyProtocol->hide();
ui->hyProtocol_l->hide();
ui->disableMtuDiscovery->hide(); ui->disableMtuDiscovery->hide();
ui->obfsPassword->hide(); ui->obfsPassword->hide();
ui->obfsPassword_l->hide(); ui->obfsPassword_l->hide();
ui->authPayload->hide();
ui->authPayload_l->hide();
ui->authPayloadType->hide();
ui->authPayloadType_l->hide();
ui->streamReceiveWindow->hide(); ui->streamReceiveWindow->hide();
ui->streamReceiveWindow_l->hide(); ui->streamReceiveWindow_l->hide();
ui->connectionReceiveWindow->hide(); ui->connectionReceiveWindow->hide();
ui->connectionReceiveWindow_l->hide(); ui->connectionReceiveWindow_l->hide();
if (!IS_NEKO_BOX) { ui->uos->hide();
ui->uos->hide();
}
} }
} }
@ -118,16 +91,13 @@ bool EditQUIC::onEnd() {
P_SAVE_BOOL(forceExternal); P_SAVE_BOOL(forceExternal);
// Hysteria // Hysteria 2
P_SAVE_STRING(hopPort); P_SAVE_STRING(hopPort);
P_SAVE_INT(hopInterval); P_SAVE_INT(hopInterval);
P_SAVE_INT(uploadMbps); P_SAVE_INT(uploadMbps);
P_SAVE_INT(downloadMbps); P_SAVE_INT(downloadMbps);
P_SAVE_COMBO_INT(hyProtocol);
P_SAVE_BOOL(disableMtuDiscovery) P_SAVE_BOOL(disableMtuDiscovery)
P_SAVE_STRING(obfsPassword); P_SAVE_STRING(obfsPassword);
P_SAVE_COMBO_INT(authPayloadType);
P_SAVE_STRING(authPayload);
P_SAVE_INT(streamReceiveWindow); P_SAVE_INT(streamReceiveWindow);
P_SAVE_INT(connectionReceiveWindow); P_SAVE_INT(connectionReceiveWindow);

View File

@ -16,6 +16,48 @@
<layout class="QVBoxLayout" name="verticalLayout"> <layout class="QVBoxLayout" name="verticalLayout">
<item> <item>
<layout class="QGridLayout" name="upBox"> <layout class="QGridLayout" name="upBox">
<item row="1" column="1">
<layout class="QHBoxLayout" name="downloadMbpsLay">
<item>
<widget class="QLabel" name="downloadMbps_l">
<property name="text">
<string>Download (Mbps)</string>
</property>
</widget>
</item>
<item>
<widget class="MyLineEdit" name="downloadMbps"/>
</item>
</layout>
</item>
<item row="0" column="0">
<layout class="QHBoxLayout" name="hopPortLay">
<item>
<widget class="QLabel" name="hopPort_l">
<property name="text">
<string>Hop Port</string>
</property>
</widget>
</item>
<item>
<widget class="MyLineEdit" name="hopPort"/>
</item>
</layout>
</item>
<item row="0" column="1">
<layout class="QHBoxLayout" name="hopIntervalLay">
<item>
<widget class="QLabel" name="hopInterval_l">
<property name="text">
<string>Hop Interval (s)</string>
</property>
</widget>
</item>
<item>
<widget class="MyLineEdit" name="hopInterval"/>
</item>
</layout>
</item>
<item row="3" column="0"> <item row="3" column="0">
<layout class="QHBoxLayout" name="heartbeatLay"> <layout class="QHBoxLayout" name="heartbeatLay">
<item> <item>
@ -37,20 +79,27 @@
</item> </item>
</layout> </layout>
</item> </item>
<item row="0" column="0"> <item row="1" column="0">
<layout class="QHBoxLayout" name="hopPortLay"> <layout class="QHBoxLayout" name="uploadMbpsLay">
<item> <item>
<widget class="QLabel" name="hopPort_l"> <widget class="QLabel" name="uploadMbps_l">
<property name="text"> <property name="text">
<string>Hop Port</string> <string>Upload (Mbps)</string>
</property> </property>
</widget> </widget>
</item> </item>
<item> <item>
<widget class="MyLineEdit" name="hopPort"/> <widget class="MyLineEdit" name="uploadMbps"/>
</item> </item>
</layout> </layout>
</item> </item>
<item row="3" column="1">
<widget class="QCheckBox" name="zeroRttHandshake">
<property name="text">
<string>Zero Rtt Handshake</string>
</property>
</widget>
</item>
<item row="2" column="0"> <item row="2" column="0">
<layout class="QHBoxLayout" name="congestionControlLay"> <layout class="QHBoxLayout" name="congestionControlLay">
<item> <item>
@ -81,48 +130,6 @@
</item> </item>
</layout> </layout>
</item> </item>
<item row="1" column="1">
<layout class="QHBoxLayout" name="downloadMbpsLay">
<item>
<widget class="QLabel" name="downloadMbps_l">
<property name="text">
<string>Download (Mbps)</string>
</property>
</widget>
</item>
<item>
<widget class="MyLineEdit" name="downloadMbps"/>
</item>
</layout>
</item>
<item row="0" column="1">
<layout class="QHBoxLayout" name="hopIntervalLay">
<item>
<widget class="QLabel" name="hopInterval_l">
<property name="text">
<string>Hop Interval (s)</string>
</property>
</widget>
</item>
<item>
<widget class="MyLineEdit" name="hopInterval"/>
</item>
</layout>
</item>
<item row="1" column="0">
<layout class="QHBoxLayout" name="uploadMbpsLay">
<item>
<widget class="QLabel" name="uploadMbps_l">
<property name="text">
<string>Upload (Mbps)</string>
</property>
</widget>
</item>
<item>
<widget class="MyLineEdit" name="uploadMbps"/>
</item>
</layout>
</item>
<item row="2" column="1"> <item row="2" column="1">
<layout class="QHBoxLayout" name="udpRelayModeLay"> <layout class="QHBoxLayout" name="udpRelayModeLay">
<item> <item>
@ -148,14 +155,18 @@
</item> </item>
</layout> </layout>
</item> </item>
<item row="3" column="1"> </layout>
<widget class="QCheckBox" name="zeroRttHandshake"> </item>
<item>
<layout class="QHBoxLayout" name="horizontalLayout">
<item>
<widget class="QCheckBox" name="forceExternal">
<property name="text"> <property name="text">
<string>Zero Rtt Handshake</string> <string>Force use external core</string>
</property> </property>
</widget> </widget>
</item> </item>
<item row="4" column="1"> <item>
<widget class="QCheckBox" name="uos"> <widget class="QCheckBox" name="uos">
<property name="toolTip"> <property name="toolTip">
<string notr="true">Requires sing-box server</string> <string notr="true">Requires sing-box server</string>
@ -165,10 +176,16 @@
</property> </property>
</widget> </widget>
</item> </item>
<item row="4" column="0"> <item>
<widget class="QCheckBox" name="forceExternal"> <widget class="QCheckBox" name="disableMtuDiscovery">
<property name="sizePolicy">
<sizepolicy hsizetype="Maximum" vsizetype="Fixed">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="text"> <property name="text">
<string>Force use external core</string> <string>Disable MTU Discovery</string>
</property> </property>
</widget> </widget>
</item> </item>
@ -176,93 +193,38 @@
</item> </item>
<item> <item>
<layout class="QGridLayout" name="obfuscation"> <layout class="QGridLayout" name="obfuscation">
<item row="1" column="0"> <item row="0" column="1">
<widget class="MyLineEdit" name="obfsPassword"/>
</item>
<item row="0" column="0">
<widget class="QLabel" name="obfsPassword_l"> <widget class="QLabel" name="obfsPassword_l">
<property name="text"> <property name="text">
<string>Obfs Password</string> <string>Obfs Password</string>
</property> </property>
</widget> </widget>
</item> </item>
<item row="0" column="0">
<widget class="QLabel" name="hyProtocol_l">
<property name="text">
<string>Protocol</string>
</property>
</widget>
</item>
<item row="0" column="1">
<layout class="QHBoxLayout" name="horizontalLayout_2">
<item>
<widget class="QComboBox" name="hyProtocol">
<item>
<property name="text">
<string notr="true">QUIC</string>
</property>
</item>
<item>
<property name="text">
<string notr="true">FakeTCP</string>
</property>
</item>
<item>
<property name="text">
<string notr="true">wechat-video</string>
</property>
</item>
</widget>
</item>
<item>
<widget class="QCheckBox" name="disableMtuDiscovery">
<property name="sizePolicy">
<sizepolicy hsizetype="Maximum" vsizetype="Fixed">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="text">
<string>Disable MTU Discovery</string>
</property>
</widget>
</item>
</layout>
</item>
<item row="1" column="1">
<widget class="MyLineEdit" name="obfsPassword"/>
</item>
</layout> </layout>
</item> </item>
<item> <item>
<layout class="QGridLayout" name="authentication"> <layout class="QGridLayout" name="authentication">
<item row="2" column="1"> <item row="0" column="2">
<widget class="MyLineEdit" name="uuid"/> <widget class="QPushButton" name="uuidgen">
<property name="text">
<string>Generate UUID</string>
</property>
</widget>
</item> </item>
<item row="0" column="0"> <item row="0" column="0">
<widget class="QLabel" name="authPayloadType_l"> <widget class="QLabel" name="uuid_l">
<property name="sizePolicy">
<sizepolicy hsizetype="Maximum" vsizetype="Preferred">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="text"> <property name="text">
<string>Auth Type</string> <string notr="true">UUID</string>
</property> </property>
</widget> </widget>
</item> </item>
<item row="0" column="1">
<widget class="MyLineEdit" name="uuid"/>
</item>
<item row="1" column="0"> <item row="1" column="0">
<widget class="QLabel" name="authPayload_l">
<property name="sizePolicy">
<sizepolicy hsizetype="Maximum" vsizetype="Preferred">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="text">
<string>Auth Payload</string>
</property>
</widget>
</item>
<item row="3" column="0">
<widget class="QLabel" name="password_l"> <widget class="QLabel" name="password_l">
<property name="sizePolicy"> <property name="sizePolicy">
<sizepolicy hsizetype="Maximum" vsizetype="Preferred"> <sizepolicy hsizetype="Maximum" vsizetype="Preferred">
@ -275,44 +237,8 @@
</property> </property>
</widget> </widget>
</item> </item>
<item row="2" column="0">
<widget class="QLabel" name="uuid_l">
<property name="text">
<string notr="true">UUID</string>
</property>
</widget>
</item>
<item row="2" column="2">
<widget class="QPushButton" name="uuidgen">
<property name="text">
<string>Generate UUID</string>
</property>
</widget>
</item>
<item row="3" column="1" colspan="2">
<widget class="MyLineEdit" name="password"/>
</item>
<item row="1" column="1" colspan="2"> <item row="1" column="1" colspan="2">
<widget class="MyLineEdit" name="authPayload"/> <widget class="MyLineEdit" name="password"/>
</item>
<item row="0" column="1" colspan="2">
<widget class="QComboBox" name="authPayloadType">
<item>
<property name="text">
<string notr="true">NONE</string>
</property>
</item>
<item>
<property name="text">
<string notr="true">STRING</string>
</property>
</item>
<item>
<property name="text">
<string notr="true">BASE64</string>
</property>
</item>
</widget>
</item> </item>
</layout> </layout>
</item> </item>
@ -428,11 +354,8 @@
<tabstop>zeroRttHandshake</tabstop> <tabstop>zeroRttHandshake</tabstop>
<tabstop>forceExternal</tabstop> <tabstop>forceExternal</tabstop>
<tabstop>uos</tabstop> <tabstop>uos</tabstop>
<tabstop>hyProtocol</tabstop>
<tabstop>disableMtuDiscovery</tabstop> <tabstop>disableMtuDiscovery</tabstop>
<tabstop>obfsPassword</tabstop> <tabstop>obfsPassword</tabstop>
<tabstop>authPayloadType</tabstop>
<tabstop>authPayload</tabstop>
<tabstop>uuid</tabstop> <tabstop>uuid</tabstop>
<tabstop>uuidgen</tabstop> <tabstop>uuidgen</tabstop>
<tabstop>password</tabstop> <tabstop>password</tabstop>

View File

@ -7,7 +7,7 @@
EditShadowSocks::EditShadowSocks(QWidget *parent) : QWidget(parent), EditShadowSocks::EditShadowSocks(QWidget *parent) : QWidget(parent),
ui(new Ui::EditShadowSocks) { ui(new Ui::EditShadowSocks) {
ui->setupUi(this); ui->setupUi(this);
ui->method->addItems(IS_NEKO_BOX ? Preset::SingBox::ShadowsocksMethods : Preset::Xray::ShadowsocksMethods); ui->method->addItems(Preset::SingBox::ShadowsocksMethods);
} }
EditShadowSocks::~EditShadowSocks() { EditShadowSocks::~EditShadowSocks() {

View File

@ -23,7 +23,7 @@ void EditTrojanVLESS::onStart(std::shared_ptr<NekoGui::ProxyEntity> _ent) {
ui->flow_l->hide(); ui->flow_l->hide();
} }
ui->password->setText(bean->password); ui->password->setText(bean->password);
ui->flow->addItems(IS_NEKO_BOX ? Preset::SingBox::Flows : Preset::Xray::Flows); ui->flow->addItems(Preset::SingBox::Flows);
ui->flow->setCurrentText(bean->flow); ui->flow->setCurrentText(bean->flow);
} }

View File

@ -21,7 +21,6 @@
#include "3rdparty/qrcodegen.hpp" #include "3rdparty/qrcodegen.hpp"
#include "3rdparty/VT100Parser.hpp" #include "3rdparty/VT100Parser.hpp"
#include "3rdparty/qv2ray/v2/components/proxy/QvProxyConfigurator.hpp" #include "3rdparty/qv2ray/v2/components/proxy/QvProxyConfigurator.hpp"
#include "3rdparty/qv2ray/v2/ui/LogHighlighter.hpp"
#ifndef NKR_NO_ZXING #ifndef NKR_NO_ZXING
#include "3rdparty/ZxingQtReader.hpp" #include "3rdparty/ZxingQtReader.hpp"
@ -91,18 +90,9 @@ MainWindow::MainWindow(QWidget *parent) : QMainWindow(parent), ui(new Ui::MainWi
} }
} }
// software_name if (QDir("dashboard").count() == 0) {
if (IS_NEKO_BOX) { QDir().mkdir("dashboard");
software_name = "NekoBox"; QFile::copy(":/neko/dashboard-notice.html", "dashboard/index.html");
software_core_name = "sing-box";
// replace default values
if (NekoGui::dataStore->log_level == "warning") NekoGui::dataStore->log_level = "info";
if (NekoGui::dataStore->mux_protocol.isEmpty()) NekoGui::dataStore->mux_protocol = "h2mux";
//
if (QDir("dashboard").count() == 0) {
QDir().mkdir("dashboard");
QFile::copy(":/neko/dashboard-notice.html", "dashboard/index.html");
}
} }
// top bar // top bar
@ -111,12 +101,12 @@ MainWindow::MainWindow(QWidget *parent) : QMainWindow(parent), ui(new Ui::MainWi
ui->toolButton_server->setMenu(ui->menu_server); ui->toolButton_server->setMenu(ui->menu_server);
ui->menubar->setVisible(false); ui->menubar->setVisible(false);
connect(ui->toolButton_document, &QToolButton::clicked, this, [=] { QDesktopServices::openUrl(QUrl("https://matsuridayo.github.io/")); }); connect(ui->toolButton_document, &QToolButton::clicked, this, [=] { QDesktopServices::openUrl(QUrl("https://matsuridayo.github.io/")); });
connect(ui->toolButton_ads, &QToolButton::clicked, this, [=] { QDesktopServices::openUrl(QUrl("https://matsuricom.pages.dev/")); }); connect(ui->toolButton_ads, &QToolButton::clicked, this, [=] { QDesktopServices::openUrl(QUrl("https://neko-box.pages.dev/喵")); });
connect(ui->toolButton_update, &QToolButton::clicked, this, [=] { runOnNewThread([=] { CheckUpdate(); }); }); connect(ui->toolButton_update, &QToolButton::clicked, this, [=] { runOnNewThread([=] { CheckUpdate(); }); });
connect(ui->toolButton_url_test, &QToolButton::clicked, this, [=] { speedtest_current_group(1, true); });
// Setup log UI // Setup log UI
ui->splitter->restoreState(DecodeB64IfValid(NekoGui::dataStore->splitter_state)); ui->splitter->restoreState(DecodeB64IfValid(NekoGui::dataStore->splitter_state));
new SyntaxHighlighter(false, qvLogDocument);
qvLogDocument->setUndoRedoEnabled(false); qvLogDocument->setUndoRedoEnabled(false);
ui->masterLogBrowser->setUndoRedoEnabled(false); ui->masterLogBrowser->setUndoRedoEnabled(false);
ui->masterLogBrowser->setDocument(qvLogDocument); ui->masterLogBrowser->setDocument(qvLogDocument);
@ -344,10 +334,10 @@ MainWindow::MainWindow(QWidget *parent) : QMainWindow(parent), ui(new Ui::MainWi
neko_set_spmode_vpn(false); neko_set_spmode_vpn(false);
}); });
connect(ui->menu_qr, &QAction::triggered, this, [=]() { display_qr_link(false); }); connect(ui->menu_qr, &QAction::triggered, this, [=]() { display_qr_link(false); });
connect(ui->menu_tcp_ping, &QAction::triggered, this, [=]() { speedtest_current_group(0); }); connect(ui->menu_tcp_ping, &QAction::triggered, this, [=]() { speedtest_current_group(0, false); });
connect(ui->menu_url_test, &QAction::triggered, this, [=]() { speedtest_current_group(1); }); connect(ui->menu_url_test, &QAction::triggered, this, [=]() { speedtest_current_group(1, false); });
connect(ui->menu_full_test, &QAction::triggered, this, [=]() { speedtest_current_group(2); }); connect(ui->menu_full_test, &QAction::triggered, this, [=]() { speedtest_current_group(2, false); });
connect(ui->menu_stop_testing, &QAction::triggered, this, [=]() { speedtest_current_group(114514); }); connect(ui->menu_stop_testing, &QAction::triggered, this, [=]() { speedtest_current_group(114514, false); });
// //
auto set_selected_or_group = [=](int mode) { auto set_selected_or_group = [=](int mode) {
// 0=group 1=select 2=unknown(menu is hide) // 0=group 1=select 2=unknown(menu is hide)
@ -398,10 +388,10 @@ MainWindow::MainWindow(QWidget *parent) : QMainWindow(parent), ui(new Ui::MainWi
if (NekoGui::dataStore->core_port <= 0) NekoGui::dataStore->core_port = 19810; if (NekoGui::dataStore->core_port <= 0) NekoGui::dataStore->core_port = 19810;
auto core_path = QApplication::applicationDirPath() + "/"; auto core_path = QApplication::applicationDirPath() + "/";
core_path += IS_NEKO_BOX ? "nekobox_core" : "nekoray_core"; core_path += "nekobox_core";
QStringList args; QStringList args;
args.push_back(IS_NEKO_BOX ? "nekobox" : "nekoray"); args.push_back("nekobox");
args.push_back("-port"); args.push_back("-port");
args.push_back(Int2String(NekoGui::dataStore->core_port)); args.push_back(Int2String(NekoGui::dataStore->core_port));
if (NekoGui::dataStore->flag_debug) args.push_back("-debug"); if (NekoGui::dataStore->flag_debug) args.push_back("-debug");
@ -488,7 +478,7 @@ void MainWindow::show_group(int gid) {
auto group = NekoGui::profileManager->GetGroup(gid); auto group = NekoGui::profileManager->GetGroup(gid);
if (group == nullptr) { if (group == nullptr) {
MessageBoxWarning(tr("Error"), QString("No such group: %1").arg(gid)); MessageBoxWarning(tr("Error"), QStringLiteral("No such group: %1").arg(gid));
NekoGui::dataStore->refreshing_group = false; NekoGui::dataStore->refreshing_group = false;
return; return;
} }
@ -639,7 +629,7 @@ void MainWindow::on_commitDataRequest() {
// //
if (!isMaximized()) { if (!isMaximized()) {
auto olds = NekoGui::dataStore->mw_size; auto olds = NekoGui::dataStore->mw_size;
auto news = QString("%1x%2").arg(size().width()).arg(size().height()); auto news = QStringLiteral("%1x%2").arg(size().width()).arg(size().height());
if (olds != news) { if (olds != news) {
NekoGui::dataStore->mw_size = news; NekoGui::dataStore->mw_size = news;
} }
@ -726,20 +716,8 @@ void MainWindow::on_menu_exit_triggered() {
void MainWindow::neko_set_spmode_system_proxy(bool enable, bool save) { void MainWindow::neko_set_spmode_system_proxy(bool enable, bool save) {
if (enable != NekoGui::dataStore->spmode_system_proxy) { if (enable != NekoGui::dataStore->spmode_system_proxy) {
if (enable) { if (enable) {
#if defined(Q_OS_WIN)
if (!IS_NEKO_BOX && !IsValidPort(NekoGui::dataStore->inbound_http_port)) {
auto btn = QMessageBox::warning(this, software_name,
tr("Http inbound is not enabled, can't set system proxy."),
"OK", tr("Settings"), "", 0, 0);
if (btn == 1) {
on_menu_basic_settings_triggered();
}
return;
}
#endif
auto socks_port = NekoGui::dataStore->inbound_socks_port; auto socks_port = NekoGui::dataStore->inbound_socks_port;
auto http_port = NekoGui::dataStore->inbound_http_port; auto http_port = NekoGui::dataStore->inbound_socks_port;
if (IS_NEKO_BOX) http_port = socks_port;
SetSystemProxy(http_port, socks_port); SetSystemProxy(http_port, socks_port);
} else { } else {
ClearSystemProxy(); ClearSystemProxy();
@ -761,7 +739,7 @@ void MainWindow::neko_set_spmode_system_proxy(bool enable, bool save) {
void MainWindow::neko_set_spmode_vpn(bool enable, bool save) { void MainWindow::neko_set_spmode_vpn(bool enable, bool save) {
if (enable != NekoGui::dataStore->spmode_vpn) { if (enable != NekoGui::dataStore->spmode_vpn) {
if (enable) { if (enable) {
if (IS_NEKO_BOX_INTERNAL_TUN) { if (NekoGui::dataStore->vpn_internal_tun) {
bool requestPermission = !NekoGui::IsAdmin(); bool requestPermission = !NekoGui::IsAdmin();
if (requestPermission) { if (requestPermission) {
#ifdef Q_OS_LINUX #ifdef Q_OS_LINUX
@ -799,7 +777,7 @@ void MainWindow::neko_set_spmode_vpn(bool enable, bool save) {
} }
} }
} else { } else {
if (IS_NEKO_BOX_INTERNAL_TUN) { if (NekoGui::dataStore->vpn_internal_tun) {
// current core is sing-box // current core is sing-box
} else { } else {
if (!StopVPNProcess()) { if (!StopVPNProcess()) {
@ -820,7 +798,7 @@ void MainWindow::neko_set_spmode_vpn(bool enable, bool save) {
NekoGui::dataStore->spmode_vpn = enable; NekoGui::dataStore->spmode_vpn = enable;
refresh_status(); refresh_status();
if (IS_NEKO_BOX_INTERNAL_TUN && NekoGui::dataStore->started_id >= 0) neko_start(NekoGui::dataStore->started_id); if (NekoGui::dataStore->vpn_internal_tun && NekoGui::dataStore->started_id >= 0) neko_start(NekoGui::dataStore->started_id);
} }
void MainWindow::refresh_status(const QString &traffic_update) { void MainWindow::refresh_status(const QString &traffic_update) {
@ -854,17 +832,12 @@ void MainWindow::refresh_status(const QString &traffic_update) {
if (last_test_time.addSecs(2) < QTime::currentTime()) { if (last_test_time.addSecs(2) < QTime::currentTime()) {
auto txt = running == nullptr ? tr("Not Running") auto txt = running == nullptr ? tr("Not Running")
: QString("[%1] %2").arg(group_name, running->bean->DisplayName()).left(30); : QStringLiteral("[%1] %2").arg(group_name, running->bean->DisplayName()).left(30);
ui->label_running->setText(txt); ui->label_running->setText(txt);
} }
// //
auto display_http = tr("None");
if (IsValidPort(NekoGui::dataStore->inbound_http_port)) {
display_http = DisplayAddress(NekoGui::dataStore->inbound_address, NekoGui::dataStore->inbound_http_port);
}
auto display_socks = DisplayAddress(NekoGui::dataStore->inbound_address, NekoGui::dataStore->inbound_socks_port); auto display_socks = DisplayAddress(NekoGui::dataStore->inbound_address, NekoGui::dataStore->inbound_socks_port);
auto inbound_txt = QString("Socks: %1\nHTTP: %2").arg(display_socks, display_http); auto inbound_txt = QStringLiteral("Mixed: %1").arg(display_socks);
if (IS_NEKO_BOX) inbound_txt = QString("Mixed: %1").arg(display_socks);
ui->label_inbound->setText(inbound_txt); ui->label_inbound->setText(inbound_txt);
// //
ui->checkBox_VPN->setChecked(NekoGui::dataStore->spmode_vpn); ui->checkBox_VPN->setChecked(NekoGui::dataStore->spmode_vpn);
@ -1194,7 +1167,7 @@ void MainWindow::on_menu_profile_debug_info_triggered() {
if (ents.count() != 1) return; if (ents.count() != 1) return;
auto btn = QMessageBox::information(this, software_name, ents.first()->ToJsonBytes(), "OK", "Edit", "Reload", 0, 0); auto btn = QMessageBox::information(this, software_name, ents.first()->ToJsonBytes(), "OK", "Edit", "Reload", 0, 0);
if (btn == 1) { if (btn == 1) {
QDesktopServices::openUrl(QUrl::fromLocalFile(QFileInfo(QString("profiles/%1.json").arg(ents.first()->id)).absoluteFilePath())); QDesktopServices::openUrl(QUrl::fromLocalFile(QFileInfo(QStringLiteral("profiles/%1.json").arg(ents.first()->id)).absoluteFilePath()));
} else if (btn == 2) { } else if (btn == 2) {
NekoGui::dataStore->Load(); NekoGui::dataStore->Load();
NekoGui::profileManager->LoadManager(); NekoGui::profileManager->LoadManager();
@ -1235,23 +1208,23 @@ void MainWindow::on_menu_export_config_triggered() {
if (ent->bean->DisplayCoreType() != software_core_name) return; if (ent->bean->DisplayCoreType() != software_core_name) return;
auto result = BuildConfig(ent, false, true); auto result = BuildConfig(ent, false, true);
QString config_core = QJsonObject2QString(result->coreConfig, true); QString config_core = QJsonObject2QString(result->coreConfig, false);
QApplication::clipboard()->setText(config_core); QApplication::clipboard()->setText(config_core);
QMessageBox msg(QMessageBox::Information, tr("Config copied"), config_core); QMessageBox msg(QMessageBox::Information, tr("Config copied"), tr("Config copied"));
msg.addButton("Copy core config", QMessageBox::YesRole); msg.addButton("Copy core config", QMessageBox::YesRole);
msg.addButton("Copy test config", QMessageBox::YesRole); msg.addButton("Copy test config", QMessageBox::NoRole);
msg.addButton(QMessageBox::Ok); msg.addButton(QMessageBox::Ok);
msg.setEscapeButton(QMessageBox::Ok); msg.setEscapeButton(QMessageBox::Ok);
msg.setDefaultButton(QMessageBox::Ok); msg.setDefaultButton(QMessageBox::Ok);
auto ret = msg.exec(); auto ret = msg.exec();
if (ret == 0) { if (ret == 2) {
result = BuildConfig(ent, false, false); result = BuildConfig(ent, false, false);
config_core = QJsonObject2QString(result->coreConfig, true); config_core = QJsonObject2QString(result->coreConfig, false);
QApplication::clipboard()->setText(config_core); QApplication::clipboard()->setText(config_core);
} else if (ret == 1) { } else if (ret == 3) {
result = BuildConfig(ent, true, false); result = BuildConfig(ent, true, false);
config_core = QJsonObject2QString(result->coreConfig, true); config_core = QJsonObject2QString(result->coreConfig, false);
QApplication::clipboard()->setText(config_core); QApplication::clipboard()->setText(config_core);
} }
} }
@ -1802,9 +1775,8 @@ bool MainWindow::StartVPNProcess() {
return true; return true;
} }
// //
auto protectPath = QDir::currentPath() + "/protect";
auto configPath = NekoGui::WriteVPNSingBoxConfig(); auto configPath = NekoGui::WriteVPNSingBoxConfig();
auto scriptPath = NekoGui::WriteVPNLinuxScript(protectPath, configPath); auto scriptPath = NekoGui::WriteVPNLinuxScript(configPath);
// //
#ifdef Q_OS_WIN #ifdef Q_OS_WIN
runOnNewThread([=] { runOnNewThread([=] {
@ -1816,11 +1788,6 @@ bool MainWindow::StartVPNProcess() {
runOnUiThread([=] { neko_set_spmode_vpn(false); }); runOnUiThread([=] { neko_set_spmode_vpn(false); });
}); });
#else #else
QFile::remove(protectPath);
if (QFile::exists(protectPath)) {
MessageBoxWarning("Error", "protect cannot be removed");
return false;
}
// //
auto vpn_process = new QProcess; auto vpn_process = new QProcess;
QProcess::connect(vpn_process, &QProcess::stateChanged, this, [=](QProcess::ProcessState state) { QProcess::connect(vpn_process, &QProcess::stateChanged, this, [=](QProcess::ProcessState state) {
@ -1833,7 +1800,7 @@ bool MainWindow::StartVPNProcess() {
// //
vpn_process->setProcessChannelMode(QProcess::ForwardedChannels); vpn_process->setProcessChannelMode(QProcess::ForwardedChannels);
#ifdef Q_OS_MACOS #ifdef Q_OS_MACOS
vpn_process->start("osascript", {"-e", QString("do shell script \"%1\" with administrator privileges") vpn_process->start("osascript", {"-e", QStringLiteral("do shell script \"%1\" with administrator privileges")
.arg("bash " + scriptPath)}); .arg("bash " + scriptPath)});
#else #else
vpn_process->start("pkexec", {"bash", scriptPath}); vpn_process->start("pkexec", {"bash", scriptPath});
@ -1856,7 +1823,7 @@ bool MainWindow::StopVPNProcess(bool unconditional) {
#else #else
QProcess p; QProcess p;
#ifdef Q_OS_MACOS #ifdef Q_OS_MACOS
p.start("osascript", {"-e", QString("do shell script \"%1\" with administrator privileges") p.start("osascript", {"-e", QStringLiteral("do shell script \"%1\" with administrator privileges")
.arg("pkill -2 -U 0 nekobox_core")}); .arg("pkill -2 -U 0 nekobox_core")});
#else #else
if (unconditional) { if (unconditional) {

View File

@ -185,7 +185,7 @@ private:
static void setup_grpc(); static void setup_grpc();
void speedtest_current_group(int mode); void speedtest_current_group(int mode, bool test_group);
void speedtest_current(); void speedtest_current();

View File

@ -205,6 +205,19 @@
</property> </property>
</widget> </widget>
</item> </item>
<item>
<widget class="QToolButton" name="toolButton_url_test">
<property name="text">
<string>URL Test</string>
</property>
<property name="popupMode">
<enum>QToolButton::InstantPopup</enum>
</property>
<property name="toolButtonStyle">
<enum>Qt::ToolButtonTextUnderIcon</enum>
</property>
</widget>
</item>
</layout> </layout>
</item> </item>
<item> <item>
@ -665,7 +678,7 @@
<string notr="true">Tcp Ping</string> <string notr="true">Tcp Ping</string>
</property> </property>
<property name="shortcut"> <property name="shortcut">
<string notr="true">Ctrl+Shift+T</string> <string notr="true">Ctrl+Alt+T</string>
</property> </property>
</action> </action>
<action name="menu_url_test"> <action name="menu_url_test">
@ -673,7 +686,7 @@
<string notr="true">Url Test</string> <string notr="true">Url Test</string>
</property> </property>
<property name="shortcut"> <property name="shortcut">
<string notr="true">Ctrl+Shift+U</string> <string notr="true">Ctrl+Alt+U</string>
</property> </property>
</action> </action>
<action name="menu_clear_test_result"> <action name="menu_clear_test_result">
@ -681,7 +694,7 @@
<string>Clear Test Result</string> <string>Clear Test Result</string>
</property> </property>
<property name="shortcut"> <property name="shortcut">
<string notr="true">Ctrl+Shift+C</string> <string notr="true">Ctrl+Alt+C</string>
</property> </property>
</action> </action>
<action name="menu_export_config"> <action name="menu_export_config">
@ -726,7 +739,7 @@
<string>Remove Duplicates</string> <string>Remove Duplicates</string>
</property> </property>
<property name="shortcut"> <property name="shortcut">
<string notr="true">Ctrl+Shift+D</string> <string notr="true">Ctrl+Alt+D</string>
</property> </property>
</action> </action>
<action name="actionfake"> <action name="actionfake">
@ -774,7 +787,7 @@
<string>Remove Unavailable</string> <string>Remove Unavailable</string>
</property> </property>
<property name="shortcut"> <property name="shortcut">
<string notr="true">Ctrl+Shift+R</string> <string notr="true">Ctrl+Alt+R</string>
</property> </property>
</action> </action>
<action name="menu_full_test"> <action name="menu_full_test">
@ -782,7 +795,7 @@
<string>Full Test</string> <string>Full Test</string>
</property> </property>
<property name="shortcut"> <property name="shortcut">
<string notr="true">Ctrl+Shift+F</string> <string notr="true">Ctrl+Alt+F</string>
</property> </property>
</action> </action>
<action name="menu_hotkey_settings"> <action name="menu_hotkey_settings">
@ -803,7 +816,7 @@
<string>Copy links of selected (Neko Links)</string> <string>Copy links of selected (Neko Links)</string>
</property> </property>
<property name="shortcut"> <property name="shortcut">
<string notr="true">Ctrl+Alt+C</string> <string notr="true">Ctrl+N</string>
</property> </property>
</action> </action>
<action name="actionfake_2"> <action name="actionfake_2">
@ -859,7 +872,7 @@
<string>Resolve domain</string> <string>Resolve domain</string>
</property> </property>
<property name="shortcut"> <property name="shortcut">
<string notr="true">Ctrl+Shift+I</string> <string notr="true">Ctrl+Alt+I</string>
</property> </property>
</action> </action>
<action name="menu_vpn_settings"> <action name="menu_vpn_settings">
@ -902,6 +915,9 @@
<property name="text"> <property name="text">
<string>Stop Testing</string> <string>Stop Testing</string>
</property> </property>
<property name="shortcut">
<string notr="true">Ctrl+Alt+S</string>
</property>
</action> </action>
</widget> </widget>
<customwidgets> <customwidgets>

View File

@ -58,8 +58,14 @@ void MainWindow::setup_grpc() {
inline bool speedtesting = false; inline bool speedtesting = false;
inline QList<QThread *> speedtesting_threads = {}; inline QList<QThread *> speedtesting_threads = {};
void MainWindow::speedtest_current_group(int mode) { void MainWindow::speedtest_current_group(int mode, bool test_group) {
if (speedtesting) {
MessageBoxWarning(software_name, QObject::tr("The last speed test did not exit completely, please wait. If it persists, please restart the program."));
return;
}
auto profiles = get_selected_or_group(); auto profiles = get_selected_or_group();
if (test_group) profiles = NekoGui::profileManager->CurrentGroup()->ProfilesWithOrder();
if (profiles.isEmpty()) return; if (profiles.isEmpty()) return;
auto group = NekoGui::profileManager->CurrentGroup(); auto group = NekoGui::profileManager->CurrentGroup();
if (group->archive) return; if (group->archive) return;
@ -75,11 +81,6 @@ void MainWindow::speedtest_current_group(int mode) {
} }
#ifndef NKR_NO_GRPC #ifndef NKR_NO_GRPC
if (speedtesting) {
MessageBoxWarning(software_name, "The last speed test did not exit completely, please wait. If it persists, please restart the program.");
return;
}
QStringList full_test_flags; QStringList full_test_flags;
if (mode == libcore::FullTest) { if (mode == libcore::FullTest) {
auto w = new QDialog(this); auto w = new QDialog(this);
@ -150,7 +151,7 @@ void MainWindow::speedtest_current_group(int mode) {
// //
libcore::TestReq req; libcore::TestReq req;
req.set_mode((libcore::TestMode) mode); req.set_mode((libcore::TestMode) mode);
req.set_timeout(5000); req.set_timeout(10 * 1000);
req.set_url(NekoGui::dataStore->test_latency_url.toStdString()); req.set_url(NekoGui::dataStore->test_latency_url.toStdString());
// //
@ -181,7 +182,7 @@ void MainWindow::speedtest_current_group(int mode) {
} }
// //
auto config = new libcore::LoadConfigReq; auto config = new libcore::LoadConfigReq;
config->set_core_config(QJsonObject2QString(c->coreConfig, true).toStdString()); config->set_core_config(QJsonObject2QString(c->coreConfig, false).toStdString());
req.set_allocated_config(config); req.set_allocated_config(config);
req.set_in_address(profile->bean->serverAddress.toStdString()); req.set_in_address(profile->bean->serverAddress.toStdString());
@ -238,6 +239,7 @@ void MainWindow::speedtest_current_group(int mode) {
lock_return.lock(); lock_return.lock();
lock_return.unlock(); lock_return.unlock();
speedtesting = false; speedtesting = false;
MW_show_log(QObject::tr("Speedtest finished."));
}); });
#endif #endif
} }
@ -250,7 +252,7 @@ void MainWindow::speedtest_current() {
runOnNewThread([=] { runOnNewThread([=] {
libcore::TestReq req; libcore::TestReq req;
req.set_mode(libcore::UrlTest); req.set_mode(libcore::UrlTest);
req.set_timeout(5000); req.set_timeout(10 * 1000);
req.set_url(NekoGui::dataStore->test_latency_url.toStdString()); req.set_url(NekoGui::dataStore->test_latency_url.toStdString());
bool rpcOK; bool rpcOK;
@ -262,12 +264,12 @@ void MainWindow::speedtest_current() {
runOnUiThread([=] { runOnUiThread([=] {
if (!result.error().empty()) { if (!result.error().empty()) {
MW_show_log(QString("UrlTest error: %1").arg(result.error().c_str())); MW_show_log(QStringLiteral("UrlTest error: %1").arg(result.error().c_str()));
} }
if (latency <= 0) { if (latency <= 0) {
ui->label_running->setText(tr("Test Result") + ": " + tr("Unavailable")); ui->label_running->setText(tr("Test Result") + ": " + tr("Unavailable"));
} else if (latency > 0) { } else if (latency > 0) {
ui->label_running->setText(tr("Test Result") + ": " + QString("%1 ms").arg(latency)); ui->label_running->setText(tr("Test Result") + ": " + QStringLiteral("%1 ms").arg(latency));
} }
}); });
}); });
@ -306,7 +308,7 @@ void MainWindow::neko_start(int _id) {
auto neko_start_stage2 = [=] { auto neko_start_stage2 = [=] {
#ifndef NKR_NO_GRPC #ifndef NKR_NO_GRPC
libcore::LoadConfigReq req; libcore::LoadConfigReq req;
req.set_core_config(QJsonObject2QString(result->coreConfig, true).toStdString()); req.set_core_config(QJsonObject2QString(result->coreConfig, false).toStdString());
req.set_enable_nekoray_connections(NekoGui::dataStore->connection_statistics); req.set_enable_nekoray_connections(NekoGui::dataStore->connection_statistics);
if (NekoGui::dataStore->traffic_loop_interval > 0) { if (NekoGui::dataStore->traffic_loop_interval > 0) {
req.add_stats_outbounds("proxy"); req.add_stats_outbounds("proxy");