mirror of
https://github.com/roacn/openwrt-packages.git
synced 2025-01-05 10:27:05 +08:00
🎨 Sync 2023-09-17 12:51
This commit is contained in:
parent
4abee4d7e7
commit
78b247ea8d
77
aliyundrive-fuse/Makefile
Normal file
77
aliyundrive-fuse/Makefile
Normal file
@ -0,0 +1,77 @@
|
||||
include $(TOPDIR)/rules.mk
|
||||
|
||||
PKG_NAME:=aliyundrive-fuse
|
||||
PKG_VERSION:=0.1.14
|
||||
PKG_RELEASE:=1
|
||||
|
||||
PKG_LICENSE:=MIT
|
||||
PKG_MAINTAINER:=messense <messense@icloud.com>
|
||||
|
||||
PKG_LIBC:=musl
|
||||
ifeq ($(ARCH),arm)
|
||||
PKG_LIBC:=musleabi
|
||||
|
||||
ARM_CPU_FEATURES:=$(word 2,$(subst +,$(space),$(call qstrip,$(CONFIG_CPU_TYPE))))
|
||||
ifneq ($(filter $(ARM_CPU_FEATURES),vfp vfpv2),)
|
||||
PKG_LIBC:=musleabihf
|
||||
endif
|
||||
endif
|
||||
|
||||
PKG_ARCH=$(ARCH)
|
||||
ifeq ($(ARCH),i386)
|
||||
PKG_ARCH:=i686
|
||||
endif
|
||||
|
||||
PKG_SOURCE:=aliyundrive-fuse-v$(PKG_VERSION).$(PKG_ARCH)-unknown-linux-$(PKG_LIBC).tar.gz
|
||||
PKG_SOURCE_URL:=https://github.com/messense/aliyundrive-fuse/releases/download/v$(PKG_VERSION)/
|
||||
PKG_HASH:=skip
|
||||
|
||||
include $(INCLUDE_DIR)/package.mk
|
||||
|
||||
define Package/aliyundrive-fuse
|
||||
SECTION:=multimedia
|
||||
CATEGORY:=Multimedia
|
||||
DEPENDS:=+fuse-utils
|
||||
TITLE:=FUSE for AliyunDrive
|
||||
URL:=https://github.com/messense/aliyundrive-fuse
|
||||
endef
|
||||
|
||||
define Package/aliyundrive-fuse/description
|
||||
FUSE for AliyunDrive.
|
||||
endef
|
||||
|
||||
define Package/aliyundrive-fuse/conffiles
|
||||
/etc/config/aliyundrive-fuse
|
||||
endef
|
||||
|
||||
define Download/sha256sum
|
||||
FILE:=$(PKG_SOURCE).sha256
|
||||
URL_FILE:=$(FILE)
|
||||
URL:=$(PKG_SOURCE_URL)
|
||||
HASH:=skip
|
||||
endef
|
||||
$(eval $(call Download,sha256sum))
|
||||
|
||||
define Build/Prepare
|
||||
mv $(DL_DIR)/$(PKG_SOURCE).sha256 .
|
||||
cp $(DL_DIR)/$(PKG_SOURCE) .
|
||||
shasum -a 256 -c $(PKG_SOURCE).sha256
|
||||
rm $(PKG_SOURCE).sha256 $(PKG_SOURCE)
|
||||
|
||||
tar -C $(PKG_BUILD_DIR)/ -zxf $(DL_DIR)/$(PKG_SOURCE)
|
||||
endef
|
||||
|
||||
define Build/Compile
|
||||
echo "aliyundrive-fuse using precompiled binary."
|
||||
endef
|
||||
|
||||
define Package/aliyundrive-fuse/install
|
||||
$(INSTALL_DIR) $(1)/usr/bin
|
||||
$(INSTALL_BIN) $(PKG_BUILD_DIR)/aliyundrive-fuse $(1)/usr/bin/aliyundrive-fuse
|
||||
$(INSTALL_DIR) $(1)/etc/init.d
|
||||
$(INSTALL_BIN) ./files/aliyundrive-fuse.init $(1)/etc/init.d/aliyundrive-fuse
|
||||
$(INSTALL_DIR) $(1)/etc/config
|
||||
$(INSTALL_CONF) ./files/aliyundrive-fuse.config $(1)/etc/config/aliyundrive-fuse
|
||||
endef
|
||||
|
||||
$(eval $(call BuildPackage,aliyundrive-fuse))
|
7
aliyundrive-fuse/files/aliyundrive-fuse.config
Normal file
7
aliyundrive-fuse/files/aliyundrive-fuse.config
Normal file
@ -0,0 +1,7 @@
|
||||
config default
|
||||
option enable '0'
|
||||
option debug '0'
|
||||
option refresh_token ''
|
||||
option mount_point '/mnt/aliyundrive'
|
||||
option read_buffer_size '10485760'
|
||||
option allow_other '1'
|
48
aliyundrive-fuse/files/aliyundrive-fuse.init
Executable file
48
aliyundrive-fuse/files/aliyundrive-fuse.init
Executable file
@ -0,0 +1,48 @@
|
||||
#!/bin/sh /etc/rc.common
|
||||
|
||||
USE_PROCD=1
|
||||
|
||||
START=99
|
||||
STOP=15
|
||||
|
||||
NAME=aliyundrive-fuse
|
||||
|
||||
uci_get_by_type() {
|
||||
local ret=$(uci get $NAME.@$1[0].$2 2>/dev/null)
|
||||
echo ${ret:=$3}
|
||||
}
|
||||
|
||||
start_service() {
|
||||
local enable=$(uci_get_by_type default enable)
|
||||
case "$enable" in
|
||||
1|on|true|yes|enabled)
|
||||
local refresh_token=$(uci_get_by_type default refresh_token)
|
||||
local mount_point=$(uci_get_by_type default mount_point)
|
||||
local read_buf_size=$(uci_get_by_type default read_buffer_size 10485760)
|
||||
local allow_other=$(uci_get_by_type default allow_other 0)
|
||||
|
||||
local extra_options=""
|
||||
|
||||
if [ "$allow_other" = "1" ]; then
|
||||
extra_options="$extra_options --allow-other"
|
||||
fi
|
||||
|
||||
mkdir -p "$mount_point"
|
||||
procd_open_instance
|
||||
procd_set_param command /bin/sh -c "/usr/bin/$NAME $extra_options -S $read_buf_size --workdir /var/run/$NAME $mount_point >>/var/log/$NAME.log 2>&1"
|
||||
procd_set_param pidfile /var/run/$NAME.pid
|
||||
procd_set_param env REFRESH_TOKEN="$refresh_token"
|
||||
case $(uci_get_by_type default debug) in
|
||||
1|on|true|yes|enabled)
|
||||
procd_append_param env RUST_LOG="aliyundrive_fuse=debug" ;;
|
||||
*) ;;
|
||||
esac
|
||||
procd_close_instance ;;
|
||||
*)
|
||||
stop_service ;;
|
||||
esac
|
||||
}
|
||||
|
||||
service_triggers() {
|
||||
procd_add_reload_trigger "aliyundrive-fuse"
|
||||
}
|
45
brook/Makefile
Normal file
45
brook/Makefile
Normal file
@ -0,0 +1,45 @@
|
||||
# SPDX-License-Identifier: GPL-3.0-only
|
||||
#
|
||||
# Copyright (C) 2021 ImmortalWrt.org
|
||||
|
||||
include $(TOPDIR)/rules.mk
|
||||
|
||||
PKG_NAME:=brook
|
||||
PKG_VERSION:=20230606
|
||||
PKG_RELEASE:=$(AUTORELEASE)
|
||||
|
||||
PKG_SOURCE:=$(PKG_NAME)-$(PKG_VERSION).tar.gz
|
||||
PKG_SOURCE_URL:=https://codeload.github.com/txthinking/brook/tar.gz/v$(PKG_VERSION)?
|
||||
PKG_HASH:=4490f203973b59e5bbaa4cbfb8835232f9671dac1b82ab4de882d32a2ad6b612
|
||||
|
||||
PKG_MAINTAINER:=Tianling Shen <cnsztl@immortalwrt.org>
|
||||
PKG_LICENSE:=GPL-3.0
|
||||
PKG_LICENSE_FILES:=LICENSE
|
||||
|
||||
PKG_BUILD_DEPENDS:=golang/host
|
||||
PKG_BUILD_PARALLEL:=1
|
||||
PKG_USE_MIPS16:=0
|
||||
PKG_BUILD_FLAGS:=no-mips16
|
||||
|
||||
GO_PKG:=github.com/txthinking/brook
|
||||
GO_PKG_BUILD_PKG:=$(GO_PKG)/cli/brook
|
||||
|
||||
include $(INCLUDE_DIR)/package.mk
|
||||
include $(TOPDIR)/feeds/packages/lang/golang/golang-package.mk
|
||||
|
||||
define Package/brook
|
||||
SECTION:=net
|
||||
CATEGORY:=Network
|
||||
SUBMENU:=Web Servers/Proxies
|
||||
TITLE:=A cross-platform proxy software
|
||||
DEPENDS:=$(GO_ARCH_DEPENDS) +ca-bundle
|
||||
URL:=https://github.com/txthinking/brook
|
||||
endef
|
||||
|
||||
define Package/brook/description
|
||||
Brook is a cross-platform strong encryption and not detectable proxy.
|
||||
Zero-Configuration.
|
||||
endef
|
||||
|
||||
$(eval $(call GoBinPackage,brook))
|
||||
$(eval $(call BuildPackage,brook))
|
@ -0,0 +1,41 @@
|
||||
From 934fd3f3d7c5602020850298443a08af6bbc3771 Mon Sep 17 00:00:00 2001
|
||||
From: MoetaYuko <loli@yuko.moe>
|
||||
Date: Tue, 6 Jun 2023 17:49:59 +0800
|
||||
Subject: [PATCH] update iploc to fix build for riscv64
|
||||
|
||||
---
|
||||
go.mod | 2 +-
|
||||
go.sum | 4 ++--
|
||||
2 files changed, 3 insertions(+), 3 deletions(-)
|
||||
|
||||
diff --git a/go.mod b/go.mod
|
||||
index 7aaac17..ab71685 100644
|
||||
--- a/go.mod
|
||||
+++ b/go.mod
|
||||
@@ -8,7 +8,7 @@ require (
|
||||
github.com/krolaw/dhcp4 v0.0.0-20190909130307-a50d88189771
|
||||
github.com/miekg/dns v1.1.51
|
||||
github.com/patrickmn/go-cache v2.1.0+incompatible
|
||||
- github.com/phuslu/iploc v1.0.20230201
|
||||
+ github.com/phuslu/iploc v1.0.20230606
|
||||
github.com/prometheus/client_golang v1.14.0
|
||||
github.com/quic-go/quic-go v0.32.0
|
||||
github.com/refraction-networking/utls v1.3.2
|
||||
diff --git a/go.sum b/go.sum
|
||||
index ee5c8bf..cecdb21 100644
|
||||
--- a/go.sum
|
||||
+++ b/go.sum
|
||||
@@ -180,8 +180,8 @@ github.com/onsi/ginkgo/v2 v2.2.0/go.mod h1:MEH45j8TBi6u9BMogfbp0stKC5cdGjumZj5Y7
|
||||
github.com/onsi/gomega v1.20.1 h1:PA/3qinGoukvymdIDV8pii6tiZgC8kbmJO6Z5+b002Q=
|
||||
github.com/patrickmn/go-cache v2.1.0+incompatible h1:HRMgzkcYKYpi3C8ajMPV8OFXaaRUnok+kx1WdO15EQc=
|
||||
github.com/patrickmn/go-cache v2.1.0+incompatible/go.mod h1:3Qf8kWWT7OJRJbdiICTKqZju1ZixQ/KpMGzzAfe6+WQ=
|
||||
-github.com/phuslu/iploc v1.0.20230201 h1:AMhy7j8z0N5iI0jaqh514KTDEB7wVdQJ4Y4DJPCvKBU=
|
||||
-github.com/phuslu/iploc v1.0.20230201/go.mod h1:gsgExGWldwv1AEzZm+Ki9/vGfyjkL33pbSr9HGpt2Xg=
|
||||
+github.com/phuslu/iploc v1.0.20230606 h1:7DcZSXuvVAlNbvGjKWOuXgpvDoUmECp8rlVEGaAydUg=
|
||||
+github.com/phuslu/iploc v1.0.20230606/go.mod h1:gsgExGWldwv1AEzZm+Ki9/vGfyjkL33pbSr9HGpt2Xg=
|
||||
github.com/pkg/errors v0.8.0/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
|
||||
github.com/pkg/errors v0.8.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
|
||||
github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
|
||||
--
|
||||
2.41.0
|
||||
|
@ -6,7 +6,7 @@ include $(TOPDIR)/rules.mk
|
||||
|
||||
PKG_NAME:=dns2tcp
|
||||
PKG_VERSION:=1.1.0
|
||||
PKG_RELEASE:=1
|
||||
PKG_RELEASE:=$(AUTORELEASE)
|
||||
|
||||
PKG_SOURCE_PROTO:=git
|
||||
PKG_SOURCE_URL:=https://github.com/zfl9/dns2tcp.git
|
||||
@ -20,6 +20,7 @@ PKG_LICENSE_FILES:=LICENSE
|
||||
|
||||
PKG_BUILD_PARALLEL:=1
|
||||
PKG_USE_MIPS16:=0
|
||||
PKG_BUILD_FLAGS:=no-mips16
|
||||
|
||||
include $(INCLUDE_DIR)/package.mk
|
||||
|
||||
|
122
gn/Makefile
122
gn/Makefile
@ -1,61 +1,61 @@
|
||||
# SPDX-License-Identifier: GPL-3.0-only
|
||||
#
|
||||
# Copyright (C) 2022 ImmortalWrt.org
|
||||
|
||||
include $(TOPDIR)/rules.mk
|
||||
|
||||
PKG_NAME:=gn
|
||||
PKG_RELEASE:=1
|
||||
|
||||
PKG_SOURCE_PROTO:=git
|
||||
PKG_SOURCE_URL:=https://gn.googlesource.com/gn.git
|
||||
PKG_SOURCE_DATE:=2023-04-05
|
||||
PKG_SOURCE_VERSION:=28b7b6c507eb808567e3aea446cd259f7691fddc
|
||||
PKG_MIRROR_HASH:=5b112442eabea4b906cc409237fac13b8efb4f5acb25989b1883d5ce96deebd2
|
||||
|
||||
PKG_LICENSE:=BSD 3-Clause
|
||||
PKG_LICENSE_FILES:=LICENSE
|
||||
PKG_MAINTAINER:=Tianling Shen <cnsztl@immortalwrt.org>
|
||||
|
||||
ifneq ($(wildcard $(TOPDIR)/feeds/packages/devel/ninja/ninja.mk),)
|
||||
PKG_BUILD_DEPENDS+= ninja/host
|
||||
endif
|
||||
PKG_HOST_ONLY:=1
|
||||
HOST_BUILD_PARALLEL:=1
|
||||
|
||||
include $(INCLUDE_DIR)/host-build.mk
|
||||
include $(INCLUDE_DIR)/package.mk
|
||||
|
||||
define Package/gn
|
||||
SECTION:=devel
|
||||
CATEGORY:=Development
|
||||
TITLE:=A meta-build system that generates build files for Ninja
|
||||
URL:=https://gn.googlesource.com/gn/
|
||||
BUILDONLY:=1
|
||||
endef
|
||||
|
||||
define Package/gn/description
|
||||
GN can generate Ninja build files for C, C++, Rust, Objective C,
|
||||
and Swift source on most popular platforms.
|
||||
endef
|
||||
|
||||
define Host/Configure
|
||||
$(PYTHON) $(HOST_BUILD_DIR)/build/gen.py \
|
||||
--no-last-commit-position
|
||||
endef
|
||||
|
||||
define Host/Compile
|
||||
ninja -C $(HOST_BUILD_DIR)/out
|
||||
endef
|
||||
|
||||
define Host/Install
|
||||
$(INSTALL_DIR) $(STAGING_DIR_HOSTPKG)/bin/
|
||||
$(INSTALL_BIN) $(HOST_BUILD_DIR)/out/gn $(STAGING_DIR_HOSTPKG)/bin/
|
||||
endef
|
||||
|
||||
define Host/Clean
|
||||
$(RM) $(STAGING_DIR_HOSTPKG)/bin/gn
|
||||
endef
|
||||
|
||||
$(eval $(call HostBuild))
|
||||
$(eval $(call BuildPackage,gn))
|
||||
# SPDX-License-Identifier: GPL-3.0-only
|
||||
#
|
||||
# Copyright (C) 2022 ImmortalWrt.org
|
||||
|
||||
include $(TOPDIR)/rules.mk
|
||||
|
||||
PKG_NAME:=gn
|
||||
PKG_RELEASE:=1
|
||||
|
||||
PKG_SOURCE_PROTO:=git
|
||||
PKG_SOURCE_URL:=https://gn.googlesource.com/gn.git
|
||||
PKG_SOURCE_DATE:=2023-04-05
|
||||
PKG_SOURCE_VERSION:=28b7b6c507eb808567e3aea446cd259f7691fddc
|
||||
PKG_MIRROR_HASH:=5b112442eabea4b906cc409237fac13b8efb4f5acb25989b1883d5ce96deebd2
|
||||
|
||||
PKG_LICENSE:=BSD 3-Clause
|
||||
PKG_LICENSE_FILES:=LICENSE
|
||||
PKG_MAINTAINER:=Tianling Shen <cnsztl@immortalwrt.org>
|
||||
|
||||
ifneq ($(wildcard $(TOPDIR)/feeds/packages/devel/ninja/ninja.mk),)
|
||||
PKG_BUILD_DEPENDS+= ninja/host
|
||||
endif
|
||||
PKG_HOST_ONLY:=1
|
||||
HOST_BUILD_PARALLEL:=1
|
||||
|
||||
include $(INCLUDE_DIR)/host-build.mk
|
||||
include $(INCLUDE_DIR)/package.mk
|
||||
|
||||
define Package/gn
|
||||
SECTION:=devel
|
||||
CATEGORY:=Development
|
||||
TITLE:=A meta-build system that generates build files for Ninja
|
||||
URL:=https://gn.googlesource.com/gn/
|
||||
BUILDONLY:=1
|
||||
endef
|
||||
|
||||
define Package/gn/description
|
||||
GN can generate Ninja build files for C, C++, Rust, Objective C,
|
||||
and Swift source on most popular platforms.
|
||||
endef
|
||||
|
||||
define Host/Configure
|
||||
$(PYTHON) $(HOST_BUILD_DIR)/build/gen.py \
|
||||
--no-last-commit-position
|
||||
endef
|
||||
|
||||
define Host/Compile
|
||||
ninja -C $(HOST_BUILD_DIR)/out
|
||||
endef
|
||||
|
||||
define Host/Install
|
||||
$(INSTALL_DIR) $(STAGING_DIR_HOSTPKG)/bin/
|
||||
$(INSTALL_BIN) $(HOST_BUILD_DIR)/out/gn $(STAGING_DIR_HOSTPKG)/bin/
|
||||
endef
|
||||
|
||||
define Host/Clean
|
||||
$(RM) $(STAGING_DIR_HOSTPKG)/bin/gn
|
||||
endef
|
||||
|
||||
$(eval $(call HostBuild))
|
||||
$(eval $(call BuildPackage,gn))
|
||||
|
@ -1,11 +1,11 @@
|
||||
--- a/build/gen.py
|
||||
+++ b/build/gen.py
|
||||
@@ -368,7 +368,7 @@ def WriteGNNinja(path, platform, host, o
|
||||
cxx = os.environ.get('CXX', 'g++')
|
||||
ld = os.environ.get('LD', 'g++')
|
||||
ar = os.environ.get('AR', 'ar -X64')
|
||||
- elif platform.is_msys() or platform.is_mingw():
|
||||
+ elif platform.is_msys() or platform.is_mingw() or platform.is_linux():
|
||||
cxx = os.environ.get('CXX', 'g++')
|
||||
ld = os.environ.get('LD', 'g++')
|
||||
ar = os.environ.get('AR', 'ar')
|
||||
--- a/build/gen.py
|
||||
+++ b/build/gen.py
|
||||
@@ -368,7 +368,7 @@ def WriteGNNinja(path, platform, host, o
|
||||
cxx = os.environ.get('CXX', 'g++')
|
||||
ld = os.environ.get('LD', 'g++')
|
||||
ar = os.environ.get('AR', 'ar -X64')
|
||||
- elif platform.is_msys() or platform.is_mingw():
|
||||
+ elif platform.is_msys() or platform.is_mingw() or platform.is_linux():
|
||||
cxx = os.environ.get('CXX', 'g++')
|
||||
ld = os.environ.get('LD', 'g++')
|
||||
ar = os.environ.get('AR', 'ar')
|
||||
|
@ -1,9 +1,9 @@
|
||||
// Generated by build/gen.py.
|
||||
|
||||
#ifndef OUT_LAST_COMMIT_POSITION_H_
|
||||
#define OUT_LAST_COMMIT_POSITION_H_
|
||||
|
||||
#define LAST_COMMIT_POSITION_NUM 2085
|
||||
#define LAST_COMMIT_POSITION "2085 (28b7b6c507eb)"
|
||||
|
||||
#endif // OUT_LAST_COMMIT_POSITION_H_
|
||||
// Generated by build/gen.py.
|
||||
|
||||
#ifndef OUT_LAST_COMMIT_POSITION_H_
|
||||
#define OUT_LAST_COMMIT_POSITION_H_
|
||||
|
||||
#define LAST_COMMIT_POSITION_NUM 2085
|
||||
#define LAST_COMMIT_POSITION "2085 (28b7b6c507eb)"
|
||||
|
||||
#endif // OUT_LAST_COMMIT_POSITION_H_
|
||||
|
@ -1,16 +1,16 @@
|
||||
# SPDX-License-Identifier: GPL-3.0-only
|
||||
#
|
||||
# Copyright (C) 2022 ImmortalWrt.org
|
||||
# Copyright (C) 2021 ImmortalWrt.org
|
||||
|
||||
include $(TOPDIR)/rules.mk
|
||||
|
||||
PKG_NAME:=hysteria
|
||||
PKG_VERSION:=2.0.0
|
||||
PKG_VERSION:=2.0.2
|
||||
PKG_RELEASE:=1
|
||||
|
||||
PKG_SOURCE:=$(PKG_NAME)-$(PKG_VERSION).tar.gz
|
||||
PKG_SOURCE_URL:=https://codeload.github.com/apernet/hysteria/tar.gz/app/v$(PKG_VERSION)?
|
||||
PKG_HASH:=06f86cf466cbe08e7aaea68914263780ed4474cd73df9a591676779535d330d5
|
||||
PKG_HASH:=eec86966a533cb4bae8e0e7b5a1c9b231a0a7a587ebc07a2a2e1e8cdb3f555f6
|
||||
PKG_BUILD_DIR:=$(BUILD_DIR)/$(PKG_NAME)-app-v$(PKG_VERSION)
|
||||
|
||||
PKG_LICENSE:=MIT
|
||||
@ -20,6 +20,7 @@ PKG_MAINTAINER:=Tianling Shen <cnsztl@immortalwrt.org>
|
||||
PKG_BUILD_DEPENDS:=golang/host
|
||||
PKG_BUILD_PARALLEL:=1
|
||||
PKG_USE_MIPS16:=0
|
||||
PKG_BUILD_FLAGS:=no-mips16
|
||||
|
||||
GO_PKG:=github.com/apernet/hysteria
|
||||
GO_PKG_BUILD_PKG:=$(GO_PKG)/app
|
||||
@ -50,7 +51,7 @@ endef
|
||||
define Package/hysteria/install
|
||||
$(call GoPackage/Package/Install/Bin,$(PKG_INSTALL_DIR))
|
||||
|
||||
$(INSTALL_DIR) $(1)/usr/bin
|
||||
$(INSTALL_DIR) $(1)/usr/bin/
|
||||
$(INSTALL_BIN) $(PKG_INSTALL_DIR)/usr/bin/app $(1)/usr/bin/hysteria
|
||||
endef
|
||||
|
||||
|
@ -14,6 +14,7 @@ PKG_HASH:=5279eb1cb7555cf9292423cc9f672dc43e6e214b3411a6df26a6a1cfa59d88b7
|
||||
|
||||
PKG_BUILD_PARALLEL:=1
|
||||
PKG_USE_MIPS16:=0
|
||||
PKG_BUILD_FLAGS:=no-mips16
|
||||
|
||||
PKG_LICENSE:=AGPL-3.0
|
||||
PKG_LICENSE_FILE:=LICENSE
|
||||
|
17
luci-app-aliyundrive-fuse/Makefile
Normal file
17
luci-app-aliyundrive-fuse/Makefile
Normal file
@ -0,0 +1,17 @@
|
||||
include $(TOPDIR)/rules.mk
|
||||
|
||||
PKG_NAME:=luci-app-aliyundrive-fuse
|
||||
PKG_VERSION:=0.1.14
|
||||
PKG_RELEASE:=1
|
||||
PKG_PO_VERSION:=$(PKG_VERSION)-$(PKG_RELEASE)
|
||||
|
||||
PKG_LICENSE:=MIT
|
||||
PKG_MAINTAINER:=messense <messense@icloud.com>
|
||||
|
||||
LUCI_TITLE:=LuCI Support for aliyundrive-fuse
|
||||
LUCI_PKGARCH:=all
|
||||
LUCI_DEPENDS:=+aliyundrive-fuse
|
||||
|
||||
include $(TOPDIR)/feeds/luci/luci.mk
|
||||
|
||||
# call BuildPackage - OpenWrt buildroot signature
|
@ -0,0 +1,40 @@
|
||||
module("luci.controller.aliyundrive-fuse", package.seeall)
|
||||
|
||||
function index()
|
||||
if not nixio.fs.access("/etc/config/aliyundrive-fuse") then
|
||||
return
|
||||
end
|
||||
|
||||
local page
|
||||
page = entry({"admin", "services", "aliyundrive-fuse"}, alias("admin", "services", "aliyundrive-fuse", "client"), _("AliyunDrive FUSE"), 10) -- 首页
|
||||
page.dependent = true
|
||||
page.acl_depends = { "luci-app-aliyundrive-fuse" }
|
||||
|
||||
entry({"admin", "services", "aliyundrive-fuse", "client"}, cbi("aliyundrive-fuse/client"), _("Settings"), 10).leaf = true -- 客户端配置
|
||||
entry({"admin", "services", "aliyundrive-fuse", "log"}, form("aliyundrive-fuse/log"), _("Log"), 30).leaf = true -- 日志页面
|
||||
|
||||
entry({"admin", "services", "aliyundrive-fuse", "status"}, call("action_status")).leaf = true
|
||||
entry({"admin", "services", "aliyundrive-fuse", "logtail"}, call("action_logtail")).leaf = true
|
||||
end
|
||||
|
||||
function action_status()
|
||||
local e = {}
|
||||
e.running = luci.sys.call("pidof aliyundrive-fuse >/dev/null") == 0
|
||||
e.application = luci.sys.exec("aliyundrive-fuse --version")
|
||||
luci.http.prepare_content("application/json")
|
||||
luci.http.write_json(e)
|
||||
end
|
||||
|
||||
function action_logtail()
|
||||
local fs = require "nixio.fs"
|
||||
local log_path = "/var/log/aliyundrive-fuse.log"
|
||||
local e = {}
|
||||
e.running = luci.sys.call("pidof aliyundrive-fuse >/dev/null") == 0
|
||||
if fs.access(log_path) then
|
||||
e.log = luci.sys.exec("tail -n 100 %s | sed 's/\\x1b\\[[0-9;]*m//g'" % log_path)
|
||||
else
|
||||
e.log = ""
|
||||
end
|
||||
luci.http.prepare_content("application/json")
|
||||
luci.http.write_json(e)
|
||||
end
|
@ -0,0 +1,30 @@
|
||||
m = Map("aliyundrive-fuse")
|
||||
m.title = translate("AliyunDrive FUSE")
|
||||
m.description = translate("<a href=\"https://github.com/messense/aliyundrive-fuse\" target=\"_blank\">Project GitHub URL</a>")
|
||||
|
||||
m:section(SimpleSection).template = "aliyundrive-fuse/aliyundrive-fuse_status"
|
||||
|
||||
e = m:section(TypedSection, "default")
|
||||
e.anonymous = true
|
||||
|
||||
enable = e:option(Flag, "enable", translate("Enable"))
|
||||
enable.rmempty = false
|
||||
|
||||
refresh_token = e:option(Value, "refresh_token", translate("Refresh Token"))
|
||||
refresh_token.description = translate("<a href=\"https://github.com/messense/aliyundrive-webdav#%E8%8E%B7%E5%8F%96-refresh_token\" target=\"_blank\">How to get refresh token</a>")
|
||||
|
||||
mount_point = e:option(Value, "mount_point", translate("Mount Point"))
|
||||
mount_point.default = "/mnt/aliyundrive"
|
||||
|
||||
read_buffer_size = e:option(Value, "read_buffer_size", translate("Read Buffer Size"))
|
||||
read_buffer_size.default = "10485760"
|
||||
read_buffer_size.datatype = "uinteger"
|
||||
|
||||
allow_other = e:option(Flag, "allow_other", translate("Allow Other users Access"))
|
||||
allow_other.description = translate("Allow other users to access the drive, enable this if you share with samba")
|
||||
allow_other.rmempty = false
|
||||
|
||||
debug = e:option(Flag, "debug", translate("Debug Mode"))
|
||||
debug.rmempty = false
|
||||
|
||||
return m
|
@ -0,0 +1,9 @@
|
||||
log = SimpleForm("logview")
|
||||
log.submit = false
|
||||
log.reset = false
|
||||
|
||||
t = log:field(DummyValue, '', '')
|
||||
t.rawhtml = true
|
||||
t.template = 'aliyundrive-fuse/aliyundrive-fuse_log'
|
||||
|
||||
return log
|
@ -0,0 +1,15 @@
|
||||
<%+cbi/valueheader%>
|
||||
<textarea id="logview" class="cbi-input-textarea" style="width: 100%" rows="30" readonly="readonly"></textarea>
|
||||
|
||||
<script type="text/javascript">
|
||||
const LOG_URL = '<%=luci.dispatcher.build_url("admin", "services", "aliyundrive-fuse", "logtail")%>';
|
||||
XHR.poll(1, LOG_URL, null, (x, d) => {
|
||||
let logview = document.getElementById("logview");
|
||||
if (!d.running) {
|
||||
XHR.halt();
|
||||
}
|
||||
logview.value = d.log;
|
||||
logview.scrollTop = logview.scrollHeight;
|
||||
});
|
||||
</script>
|
||||
<%+cbi/valuefooter%>
|
@ -0,0 +1,21 @@
|
||||
<script type="text/javascript">//<![CDATA[
|
||||
XHR.poll(3, '<%=url([[admin]], [[services]], [[aliyundrive-fuse]], [[status]])%>', null,
|
||||
function(x, data) {
|
||||
var tb = document.getElementById('aliyundrive-fuse_status');
|
||||
if (data && tb) {
|
||||
if (data.running) {
|
||||
tb.innerHTML = '<em><b style=color:green>' + data.application + '<%:RUNNING%></b></em>';
|
||||
} else {
|
||||
tb.innerHTML = '<em><b style=color:red>' + data.application + '<%:NOT RUNNING%></b></em>';
|
||||
}
|
||||
}
|
||||
}
|
||||
);
|
||||
//]]>
|
||||
</script>
|
||||
<style>.mar-10 {margin-left: 50px; margin-right: 10px;}</style>
|
||||
<fieldset class="cbi-section">
|
||||
<p id="aliyundrive-fuse_status">
|
||||
<em><%:Collecting data...%></em>
|
||||
</p>
|
||||
</fieldset>
|
50
luci-app-aliyundrive-fuse/po/zh-cn/aliyundrive-fuse.po
Normal file
50
luci-app-aliyundrive-fuse/po/zh-cn/aliyundrive-fuse.po
Normal file
@ -0,0 +1,50 @@
|
||||
msgid ""
|
||||
msgstr "Content-Type: text/plain; charset=UTF-8\n"
|
||||
|
||||
msgid "AliyunDrive"
|
||||
msgstr "阿里云盘"
|
||||
|
||||
msgid "AliyunDrive FUSE"
|
||||
msgstr "阿里云盘 FUSE"
|
||||
|
||||
msgid "Enable"
|
||||
msgstr "启用"
|
||||
|
||||
msgid "Refresh Token"
|
||||
msgstr "Refresh Token"
|
||||
|
||||
msgid "Mount Point"
|
||||
msgstr "挂载点"
|
||||
|
||||
msgid "Read Buffer Size"
|
||||
msgstr "下载缓冲大小(bytes)"
|
||||
|
||||
msgid "Collecting data..."
|
||||
msgstr "获取数据中..."
|
||||
|
||||
msgid "RUNNING"
|
||||
msgstr "运行中"
|
||||
|
||||
msgid "NOT RUNNING"
|
||||
msgstr "未运行"
|
||||
|
||||
msgid "Settings"
|
||||
msgstr "设置"
|
||||
|
||||
msgid "Log"
|
||||
msgstr "日志"
|
||||
|
||||
msgid "Debug Mode"
|
||||
msgstr "调试模式"
|
||||
|
||||
msgid "<a href=\"https://github.com/messense/aliyundrive-fuse\" target=\"_blank\">Project GitHub URL</a>"
|
||||
msgstr "<a href=\"https://github.com/messense/aliyundrive-fuse\" target=\"_blank\">GitHub 项目地址</a>"
|
||||
|
||||
msgid "<a href=\"https://github.com/messense/aliyundrive-webdav#%E8%8E%B7%E5%8F%96-refresh_token\" target=\"_blank\">How to get refresh token</a>"
|
||||
msgstr "<a href=\"https://github.com/messense/aliyundrive-webdav#%E8%8E%B7%E5%8F%96-refresh_token\" target=\"_blank\">查看获取 refresh token 的方法</a>"
|
||||
|
||||
msgid "Allow Other users Access"
|
||||
msgstr "允许其他用户访问"
|
||||
|
||||
msgid "Allow other users to access the drive, enable this if you share with samba"
|
||||
msgstr "允许其他用户访问此驱动,如果你想用Samba分享请开启此开关"
|
11
luci-app-aliyundrive-fuse/root/etc/uci-defaults/luci-aliyundrive-fuse
Executable file
11
luci-app-aliyundrive-fuse/root/etc/uci-defaults/luci-aliyundrive-fuse
Executable file
@ -0,0 +1,11 @@
|
||||
#!/bin/sh
|
||||
|
||||
uci -q batch <<-EOF >/dev/null
|
||||
delete ucitrack.@aliyundrive-fuse[-1]
|
||||
add ucitrack aliyundrive-fuse
|
||||
set ucitrack.@aliyundrive-fuse[-1].init=aliyundrive-fuse
|
||||
commit ucitrack
|
||||
EOF
|
||||
|
||||
rm -f /tmp/luci-indexcache
|
||||
exit 0
|
@ -0,0 +1,11 @@
|
||||
{
|
||||
"luci-app-aliyundrive-fuse": {
|
||||
"description": "Grant UCI access for luci-app-aliyundrive-fuse",
|
||||
"read": {
|
||||
"uci": [ "aliyundrive-fuse" ]
|
||||
},
|
||||
"write": {
|
||||
"uci": [ "aliyundrive-fuse" ]
|
||||
}
|
||||
}
|
||||
}
|
17
luci-app-aliyundrive-webdav/Makefile
Normal file
17
luci-app-aliyundrive-webdav/Makefile
Normal file
@ -0,0 +1,17 @@
|
||||
include $(TOPDIR)/rules.mk
|
||||
|
||||
PKG_NAME:=luci-app-aliyundrive-webdav
|
||||
PKG_VERSION:=2.3.2
|
||||
PKG_RELEASE:=1
|
||||
PKG_PO_VERSION:=$(PKG_VERSION)-$(PKG_RELEASE)
|
||||
|
||||
PKG_LICENSE:=MIT
|
||||
PKG_MAINTAINER:=messense <messense@icloud.com>
|
||||
|
||||
LUCI_TITLE:=LuCI Support for aliyundrive-webdav
|
||||
LUCI_PKGARCH:=all
|
||||
LUCI_DEPENDS:=+aliyundrive-webdav
|
||||
|
||||
include $(TOPDIR)/feeds/luci/luci.mk
|
||||
|
||||
# call BuildPackage - OpenWrt buildroot signature
|
@ -0,0 +1,66 @@
|
||||
module("luci.controller.aliyundrive-webdav", package.seeall)
|
||||
|
||||
function index()
|
||||
if not nixio.fs.access("/etc/config/aliyundrive-webdav") then
|
||||
return
|
||||
end
|
||||
|
||||
local page
|
||||
page = entry({ "admin", "services", "aliyundrive-webdav" }, alias("admin", "services", "aliyundrive-webdav", "client"),
|
||||
_("AliyunDrive WebDAV"), 10) -- 首页
|
||||
page.dependent = true
|
||||
page.acl_depends = { "luci-app-aliyundrive-webdav" }
|
||||
|
||||
entry({ "admin", "services", "aliyundrive-webdav", "client" }, cbi("aliyundrive-webdav/client"), _("Settings"), 10).leaf = true -- 客户端配置
|
||||
entry({ "admin", "services", "aliyundrive-webdav", "log" }, form("aliyundrive-webdav/log"), _("Log"), 30).leaf = true -- 日志页面
|
||||
|
||||
entry({ "admin", "services", "aliyundrive-webdav", "status" }, call("action_status")).leaf = true -- 运行状态
|
||||
entry({ "admin", "services", "aliyundrive-webdav", "logtail" }, call("action_logtail")).leaf = true -- 日志采集
|
||||
entry({ "admin", "services", "aliyundrive-webdav", "qrcode" }, call("action_generate_qrcode")).leaf = true -- 生成扫码登录二维码地址和参数
|
||||
entry({ "admin", "services", "aliyundrive-webdav", "query" }, call("action_query_qrcode")).leaf = true -- 查询扫码登录结果
|
||||
entry({ "admin", "services", "aliyundrive-webdav", "invalidate-cache" }, call("action_invalidate_cache")).leaf = true -- 清除缓存
|
||||
end
|
||||
|
||||
function action_status()
|
||||
local e = {}
|
||||
e.running = luci.sys.call("pidof aliyundrive-webdav >/dev/null") == 0
|
||||
e.application = luci.sys.exec("aliyundrive-webdav --version")
|
||||
luci.http.prepare_content("application/json")
|
||||
luci.http.write_json(e)
|
||||
end
|
||||
|
||||
function action_logtail()
|
||||
local fs = require "nixio.fs"
|
||||
local log_path = "/var/log/aliyundrive-webdav.log"
|
||||
local e = {}
|
||||
e.running = luci.sys.call("pidof aliyundrive-webdav >/dev/null") == 0
|
||||
if fs.access(log_path) then
|
||||
e.log = luci.sys.exec("tail -n 100 %s | sed 's/\\x1b\\[[0-9;]*m//g'" % log_path)
|
||||
else
|
||||
e.log = ""
|
||||
end
|
||||
luci.http.prepare_content("application/json")
|
||||
luci.http.write_json(e)
|
||||
end
|
||||
|
||||
function action_generate_qrcode()
|
||||
local output = luci.sys.exec("aliyundrive-webdav qr generate")
|
||||
luci.http.prepare_content("application/json")
|
||||
luci.http.write(output)
|
||||
end
|
||||
|
||||
function action_query_qrcode()
|
||||
local data = luci.http.formvalue()
|
||||
local sid = data.sid
|
||||
local output = {}
|
||||
output.refresh_token = luci.sys.exec("aliyundrive-webdav qr query --sid " .. sid)
|
||||
luci.http.prepare_content("application/json")
|
||||
luci.http.write_json(output)
|
||||
end
|
||||
|
||||
function action_invalidate_cache()
|
||||
local e = {}
|
||||
e.ok = luci.sys.call("kill -HUP `pidof aliyundrive-webdav`") == 0
|
||||
luci.http.prepare_content("application/json")
|
||||
luci.http.write_json(e)
|
||||
end
|
@ -0,0 +1,83 @@
|
||||
m = Map("aliyundrive-webdav")
|
||||
m.title = translate("AliyunDrive WebDAV")
|
||||
m.description = translate("<a href=\"https://github.com/messense/aliyundrive-webdav\" target=\"_blank\">Project GitHub URL</a>")
|
||||
|
||||
m:section(SimpleSection).template = "aliyundrive-webdav/aliyundrive-webdav_status"
|
||||
|
||||
e = m:section(TypedSection, "server")
|
||||
e.anonymous = true
|
||||
|
||||
enable = e:option(Flag, "enable", translate("Enable"))
|
||||
enable.rmempty = false
|
||||
|
||||
refresh_token = e:option(Value, "refresh_token", translate("Refresh Token"))
|
||||
refresh_token.description = translate("Double click the input box above to get refresh token by scanning qrcode")
|
||||
|
||||
qrcode = e:option(DummyValue, '', '')
|
||||
qrcode.rawhtml = true
|
||||
qrcode.template = 'aliyundrive-webdav/aliyundrive-webdav_qrcode'
|
||||
|
||||
root = e:option(Value, "root", translate("Root Directory"))
|
||||
root.description = translate("Restrict access to a folder of aliyundrive, defaults to / which means no restrictions")
|
||||
root.default = "/"
|
||||
|
||||
host = e:option(Value, "host", translate("Host"))
|
||||
host.default = "0.0.0.0"
|
||||
host.datatype = "ipaddr"
|
||||
|
||||
port = e:option(Value, "port", translate("Port"))
|
||||
port.default = "8080"
|
||||
port.datatype = "port"
|
||||
|
||||
drive_type = e:option(ListValue, "drive_type", translate("Aliyun drive type"))
|
||||
drive_type.description = translate("Supports drive type: resource, backup")
|
||||
drive_type:value("resource", "resource");
|
||||
drive_type:value("backup", "backup");
|
||||
drive_type.default = "backup"
|
||||
|
||||
tls_cert = e:option(Value, "tls_cert", translate("TLS certificate file path"))
|
||||
tls_key = e:option(Value, "tls_key", translate("TLS private key file path"))
|
||||
|
||||
auth_user = e:option(Value, "auth_user", translate("Username"))
|
||||
auth_password = e:option(Value, "auth_password", translate("Password"))
|
||||
auth_password.password = true
|
||||
|
||||
read_buffer_size = e:option(Value, "read_buffer_size", translate("Read Buffer Size"))
|
||||
read_buffer_size.default = "10485760"
|
||||
read_buffer_size.datatype = "uinteger"
|
||||
|
||||
prefer_http_download = e:option(Flag, "prefer_http_download", translate("Prefer HTTP Download"))
|
||||
prefer_http_download.description = translate("Prefer downloading files using HTTP instead of HTTPS protocol")
|
||||
prefer_http_download.rmempty = false
|
||||
|
||||
redirect = e:option(Flag, "redirect", translate("Enable 302 Redirect"))
|
||||
redirect.description = translate("Enable 302 redirect when possible")
|
||||
redirect.rmempty = false
|
||||
|
||||
upload_buffer_size = e:option(Value, "upload_buffer_size", translate("Upload Buffer Size"))
|
||||
upload_buffer_size.default = "16777216"
|
||||
upload_buffer_size.datatype = "uinteger"
|
||||
|
||||
skip_upload_same_size = e:option(Flag, "skip_upload_same_size", translate("Skip uploading same size files"))
|
||||
skip_upload_same_size.description = translate("Reduce the upload traffic by skipping uploading files with the same size")
|
||||
skip_upload_same_size.rmempty = false
|
||||
|
||||
cache_size = e:option(Value, "cache_size", translate("Cache Size"))
|
||||
cache_size.default = "1000"
|
||||
cache_size.datatype = "uinteger"
|
||||
|
||||
cache_ttl = e:option(Value, "cache_ttl", translate("Cache Expiration Time (seconds)"))
|
||||
cache_ttl.default = "600"
|
||||
cache_ttl.datatype = "uinteger"
|
||||
|
||||
no_trash = e:option(Flag, "no_trash", translate("Delete file permanently instead of trashing"))
|
||||
no_trash.rmempty = false
|
||||
|
||||
read_only = e:option(Flag, "read_only", translate("Enable read only mode"))
|
||||
read_only.description = translate("Disallow upload, modify and delete file operations")
|
||||
read_only.rmempty = false
|
||||
|
||||
debug = e:option(Flag, "debug", translate("Debug Mode"))
|
||||
debug.rmempty = false
|
||||
|
||||
return m
|
@ -0,0 +1,9 @@
|
||||
log = SimpleForm("logview")
|
||||
log.submit = false
|
||||
log.reset = false
|
||||
|
||||
t = log:field(DummyValue, '', '')
|
||||
t.rawhtml = true
|
||||
t.template = 'aliyundrive-webdav/aliyundrive-webdav_log'
|
||||
|
||||
return log
|
@ -0,0 +1,15 @@
|
||||
<%+cbi/valueheader%>
|
||||
<textarea id="logview" class="cbi-input-textarea" style="width: 100%" rows="30" readonly="readonly"></textarea>
|
||||
|
||||
<script type="text/javascript">
|
||||
const LOG_URL = '<%=luci.dispatcher.build_url("admin", "services", "aliyundrive-webdav", "logtail")%>';
|
||||
XHR.poll(1, LOG_URL, null, (x, d) => {
|
||||
let logview = document.getElementById("logview");
|
||||
if (!d.running) {
|
||||
XHR.halt();
|
||||
}
|
||||
logview.value = d.log;
|
||||
logview.scrollTop = logview.scrollHeight;
|
||||
});
|
||||
</script>
|
||||
<%+cbi/valuefooter%>
|
File diff suppressed because one or more lines are too long
@ -0,0 +1,36 @@
|
||||
<script type="text/javascript">//<![CDATA[
|
||||
XHR.poll(3, '<%=url([[admin]], [[services]], [[aliyundrive-webdav]], [[status]])%>', null,
|
||||
function(x, data) {
|
||||
var tb = document.getElementById('aliyundrive-webdav_status');
|
||||
if (data && tb) {
|
||||
if (data.running) {
|
||||
tb.innerHTML = '<em><b style=color:green>' + data.application + '<%:RUNNING%></b></em>';
|
||||
} else {
|
||||
tb.innerHTML = '<em><b style=color:red>' + data.application + '<%:NOT RUNNING%></b></em>';
|
||||
}
|
||||
}
|
||||
}
|
||||
);
|
||||
|
||||
function invalidateCache(button) {
|
||||
XHR.get('<%=url([[admin]], [[services]], [[aliyundrive-webdav]], [[invalidate-cache]])%>', null,
|
||||
function(x, data) {
|
||||
if (data.ok) {
|
||||
alert("缓存已清除.");
|
||||
} else {
|
||||
alert("清除缓存失败!");
|
||||
}
|
||||
}
|
||||
);
|
||||
}
|
||||
//]]>
|
||||
</script>
|
||||
<style>.mar-10 {margin-left: 50px; margin-right: 10px;}</style>
|
||||
<fieldset class="cbi-section">
|
||||
<p id="aliyundrive-webdav_status" style="float: left; width: 60%; margin-top: 12px;">
|
||||
<em><%:Collecting data...%></em>
|
||||
</p>
|
||||
<p class="right" style="float: right; width: 40%;">
|
||||
<button class="cbi-button" onclick="event.stopPropagation(); invalidateCache(this);"><%:Invalidate cache%></button>
|
||||
</p>
|
||||
</fieldset>
|
110
luci-app-aliyundrive-webdav/po/zh-cn/aliyundrive-webdav.po
Normal file
110
luci-app-aliyundrive-webdav/po/zh-cn/aliyundrive-webdav.po
Normal file
@ -0,0 +1,110 @@
|
||||
msgid ""
|
||||
msgstr "Content-Type: text/plain; charset=UTF-8\n"
|
||||
|
||||
msgid "AliyunDrive"
|
||||
msgstr "阿里云盘"
|
||||
|
||||
msgid "AliyunDrive WebDAV"
|
||||
msgstr "阿里云盘 WebDAV"
|
||||
|
||||
msgid "Enable"
|
||||
msgstr "启用"
|
||||
|
||||
msgid "Refresh Token"
|
||||
msgstr "Refresh Token"
|
||||
|
||||
msgid "Root Directory"
|
||||
msgstr "云盘根目录"
|
||||
|
||||
msgid "Host"
|
||||
msgstr "监听主机"
|
||||
|
||||
msgid "Port"
|
||||
msgstr "监听端口"
|
||||
|
||||
msgid "Aliyun drive type"
|
||||
msgstr "云盘驱动类型"
|
||||
|
||||
msgid "Supports drive type: resource, backup"
|
||||
msgstr "支持驱动器类型:resource, backup"
|
||||
|
||||
msgid "TLS certificate file path"
|
||||
msgstr "TLS 证书文件路径"
|
||||
|
||||
msgid "TLS private key file path"
|
||||
msgstr "TLS 私钥文件路径"
|
||||
|
||||
msgid "Username"
|
||||
msgstr "用户名"
|
||||
|
||||
msgid "Password"
|
||||
msgstr "密码"
|
||||
|
||||
msgid "Read Buffer Size"
|
||||
msgstr "下载缓冲大小(bytes)"
|
||||
|
||||
msgid "Upload Buffer Size"
|
||||
msgstr "上传缓冲大小(bytes)"
|
||||
|
||||
msgid "Cache Size"
|
||||
msgstr "目录缓存大小"
|
||||
|
||||
msgid "Cache Expiration Time (seconds)"
|
||||
msgstr "目录缓存过期时间(单位为秒)"
|
||||
|
||||
msgid "Collecting data..."
|
||||
msgstr "获取数据中..."
|
||||
|
||||
msgid "Invalidate cache"
|
||||
msgstr "清除缓存"
|
||||
|
||||
msgid "RUNNING"
|
||||
msgstr "运行中"
|
||||
|
||||
msgid "NOT RUNNING"
|
||||
msgstr "未运行"
|
||||
|
||||
msgid "Settings"
|
||||
msgstr "设置"
|
||||
|
||||
msgid "Log"
|
||||
msgstr "日志"
|
||||
|
||||
msgid "Debug Mode"
|
||||
msgstr "调试模式"
|
||||
|
||||
msgid "<a href=\"https://github.com/messense/aliyundrive-webdav\" target=\"_blank\">Project GitHub URL</a>"
|
||||
msgstr "<a href=\"https://github.com/messense/aliyundrive-webdav\" target=\"_blank\">GitHub 项目地址</a> | <a href=\"https://t.zsxq.com/0c9sq6Ca8\" target=\"_blank\">加入知识星球</a>"
|
||||
|
||||
msgid "Double click the input box above to get refresh token by scanning qrcode"
|
||||
msgstr "鼠标双击上面的输入框扫码登录自动获取 refresh token"
|
||||
|
||||
msgid "Restrict access to a folder of aliyundrive, defaults to / which means no restrictions"
|
||||
msgstr "限制只能访问该云盘目录,默认为 / 表示不限制,注意这个参数不是本地磁盘路径"
|
||||
|
||||
msgid "Delete file permanently instead of trashing"
|
||||
msgstr "删除文件不放入回收站"
|
||||
|
||||
msgid "Enable read only mode"
|
||||
msgstr "启用只读模式"
|
||||
|
||||
msgid "Disallow upload, modify and delete file operations"
|
||||
msgstr "禁止上传、修改和删除文件操作"
|
||||
|
||||
msgid "Skip uploading same size files"
|
||||
msgstr "跳过上传相同大小的文件"
|
||||
|
||||
msgid "Reduce the upload traffic by skipping uploading files with the same size"
|
||||
msgstr "跳过上传相同大小的文件减少上传流量消耗,但可能会导致修改过的同样大小的文件不会被上传"
|
||||
|
||||
msgid "Prefer HTTP Download"
|
||||
msgstr "使用 HTTP 下载"
|
||||
|
||||
msgid "Prefer downloading files using HTTP instead of HTTPS protocol"
|
||||
msgstr "优先使用 HTTP 而不是 HTTPS 协议下载,低端设备上降低 CPU 占用"
|
||||
|
||||
msgid "Enable 302 Redirect"
|
||||
msgstr "启用 302 重定向"
|
||||
|
||||
msgid "Enable 302 redirect when possible"
|
||||
msgstr "在可能的情况下启用 302 重定向"
|
1
luci-app-aliyundrive-webdav/po/zh_Hans
Symbolic link
1
luci-app-aliyundrive-webdav/po/zh_Hans
Symbolic link
@ -0,0 +1 @@
|
||||
zh-cn
|
11
luci-app-aliyundrive-webdav/root/etc/uci-defaults/luci-aliyundrive-webdav
Executable file
11
luci-app-aliyundrive-webdav/root/etc/uci-defaults/luci-aliyundrive-webdav
Executable file
@ -0,0 +1,11 @@
|
||||
#!/bin/sh
|
||||
|
||||
uci -q batch <<-EOF >/dev/null
|
||||
delete ucitrack.@aliyundrive-webdav[-1]
|
||||
add ucitrack aliyundrive-webdav
|
||||
set ucitrack.@aliyundrive-webdav[-1].init=aliyundrive-webdav
|
||||
commit ucitrack
|
||||
EOF
|
||||
|
||||
rm -f /tmp/luci-indexcache
|
||||
exit 0
|
@ -0,0 +1,11 @@
|
||||
{
|
||||
"luci-app-aliyundrive-webdav": {
|
||||
"description": "Grant UCI access for luci-app-aliyundrive-webdav",
|
||||
"read": {
|
||||
"uci": [ "aliyundrive-webdav" ]
|
||||
},
|
||||
"write": {
|
||||
"uci": [ "aliyundrive-webdav" ]
|
||||
}
|
||||
}
|
||||
}
|
@ -1,191 +0,0 @@
|
||||
# Copyright (C) 2018-2020 L-WRT Team
|
||||
# Copyright (C) 2021-2023 xiaorouji
|
||||
#
|
||||
# This is free software, licensed under the GNU General Public License v3.
|
||||
|
||||
include $(TOPDIR)/rules.mk
|
||||
|
||||
PKG_NAME:=luci-app-passwall
|
||||
PKG_VERSION:=4.70-8
|
||||
PKG_RELEASE:=
|
||||
|
||||
PKG_CONFIG_DEPENDS:= \
|
||||
CONFIG_PACKAGE_$(PKG_NAME)_Iptables_Transparent_Proxy \
|
||||
CONFIG_PACKAGE_$(PKG_NAME)_Nftables_Transparent_Proxy \
|
||||
CONFIG_PACKAGE_$(PKG_NAME)_INCLUDE_Brook \
|
||||
CONFIG_PACKAGE_$(PKG_NAME)_INCLUDE_Haproxy \
|
||||
CONFIG_PACKAGE_$(PKG_NAME)_INCLUDE_Hysteria \
|
||||
CONFIG_PACKAGE_$(PKG_NAME)_INCLUDE_NaiveProxy \
|
||||
CONFIG_PACKAGE_$(PKG_NAME)_INCLUDE_Shadowsocks_Libev_Client \
|
||||
CONFIG_PACKAGE_$(PKG_NAME)_INCLUDE_Shadowsocks_Libev_Server \
|
||||
CONFIG_PACKAGE_$(PKG_NAME)_INCLUDE_Shadowsocks_Rust_Client \
|
||||
CONFIG_PACKAGE_$(PKG_NAME)_INCLUDE_Shadowsocks_Rust_Server \
|
||||
CONFIG_PACKAGE_$(PKG_NAME)_INCLUDE_ShadowsocksR_Libev_Client \
|
||||
CONFIG_PACKAGE_$(PKG_NAME)_INCLUDE_ShadowsocksR_Libev_Server \
|
||||
CONFIG_PACKAGE_$(PKG_NAME)_INCLUDE_Simple_Obfs \
|
||||
CONFIG_PACKAGE_$(PKG_NAME)_INCLUDE_SingBox \
|
||||
CONFIG_PACKAGE_$(PKG_NAME)_INCLUDE_Trojan_GO \
|
||||
CONFIG_PACKAGE_$(PKG_NAME)_INCLUDE_Trojan_Plus \
|
||||
CONFIG_PACKAGE_$(PKG_NAME)_INCLUDE_tuic_client \
|
||||
CONFIG_PACKAGE_$(PKG_NAME)_INCLUDE_V2ray_Geodata \
|
||||
CONFIG_PACKAGE_$(PKG_NAME)_INCLUDE_V2ray_Plugin \
|
||||
CONFIG_PACKAGE_$(PKG_NAME)_INCLUDE_Xray \
|
||||
CONFIG_PACKAGE_$(PKG_NAME)_INCLUDE_Xray_Plugin
|
||||
|
||||
LUCI_TITLE:=LuCI support for PassWall
|
||||
LUCI_PKGARCH:=all
|
||||
LUCI_DEPENDS:=+coreutils +coreutils-base64 +coreutils-nohup +curl \
|
||||
+chinadns-ng +dns2socks +dns2tcp +ip-full +libuci-lua +lua +luci-compat +luci-lib-jsonc \
|
||||
+microsocks +resolveip +tcping +unzip \
|
||||
+PACKAGE_$(PKG_NAME)_INCLUDE_Brook:brook \
|
||||
+PACKAGE_$(PKG_NAME)_INCLUDE_Haproxy:haproxy \
|
||||
+PACKAGE_$(PKG_NAME)_INCLUDE_Hysteria:hysteria \
|
||||
+PACKAGE_$(PKG_NAME)_INCLUDE_NaiveProxy:naiveproxy \
|
||||
+PACKAGE_$(PKG_NAME)_INCLUDE_Shadowsocks_Libev_Client:shadowsocks-libev-ss-local \
|
||||
+PACKAGE_$(PKG_NAME)_INCLUDE_Shadowsocks_Libev_Client:shadowsocks-libev-ss-redir \
|
||||
+PACKAGE_$(PKG_NAME)_INCLUDE_Shadowsocks_Libev_Server:shadowsocks-libev-ss-server \
|
||||
+PACKAGE_$(PKG_NAME)_INCLUDE_Shadowsocks_Rust_Client:shadowsocks-rust-sslocal \
|
||||
+PACKAGE_$(PKG_NAME)_INCLUDE_Shadowsocks_Rust_Server:shadowsocks-rust-ssserver \
|
||||
+PACKAGE_$(PKG_NAME)_INCLUDE_ShadowsocksR_Libev_Client:shadowsocksr-libev-ssr-local \
|
||||
+PACKAGE_$(PKG_NAME)_INCLUDE_ShadowsocksR_Libev_Client:shadowsocksr-libev-ssr-redir \
|
||||
+PACKAGE_$(PKG_NAME)_INCLUDE_ShadowsocksR_Libev_Server:shadowsocksr-libev-ssr-server \
|
||||
+PACKAGE_$(PKG_NAME)_INCLUDE_Simple_Obfs:simple-obfs \
|
||||
+PACKAGE_$(PKG_NAME)_INCLUDE_SingBox:sing-box \
|
||||
+PACKAGE_$(PKG_NAME)_INCLUDE_Trojan_GO:trojan-go \
|
||||
+PACKAGE_$(PKG_NAME)_INCLUDE_Trojan_Plus:trojan-plus \
|
||||
+PACKAGE_$(PKG_NAME)_INCLUDE_tuic_client:tuic-client \
|
||||
+PACKAGE_$(PKG_NAME)_INCLUDE_V2ray_Geodata:v2ray-geoip \
|
||||
+PACKAGE_$(PKG_NAME)_INCLUDE_V2ray_Geodata:v2ray-geosite \
|
||||
+PACKAGE_$(PKG_NAME)_INCLUDE_V2ray_Plugin:v2ray-plugin \
|
||||
+PACKAGE_$(PKG_NAME)_INCLUDE_Xray:xray-core \
|
||||
+PACKAGE_$(PKG_NAME)_INCLUDE_Xray_Plugin:xray-plugin
|
||||
|
||||
define Package/$(PKG_NAME)/config
|
||||
menu "Configuration"
|
||||
|
||||
config PACKAGE_$(PKG_NAME)_Iptables_Transparent_Proxy
|
||||
bool "Iptables Transparent Proxy"
|
||||
select PACKAGE_dnsmasq-full
|
||||
select PACKAGE_ipset
|
||||
select PACKAGE_ipt2socks
|
||||
select PACKAGE_iptables
|
||||
select PACKAGE_iptables-zz-legacy
|
||||
select PACKAGE_iptables-mod-conntrack-extra
|
||||
select PACKAGE_iptables-mod-iprange
|
||||
select PACKAGE_iptables-mod-socket
|
||||
select PACKAGE_iptables-mod-tproxy
|
||||
select PACKAGE_kmod-ipt-nat
|
||||
depends on PACKAGE_$(PKG_NAME)
|
||||
default y if ! PACKAGE_firewall4
|
||||
|
||||
config PACKAGE_$(PKG_NAME)_Nftables_Transparent_Proxy
|
||||
bool "Nftables Transparent Proxy"
|
||||
select PACKAGE_dnsmasq-full
|
||||
select PACKAGE_ipt2socks
|
||||
select PACKAGE_nftables
|
||||
select PACKAGE_kmod-nft-socket
|
||||
select PACKAGE_kmod-nft-tproxy
|
||||
select PACKAGE_kmod-nft-nat
|
||||
depends on PACKAGE_$(PKG_NAME)
|
||||
default y if PACKAGE_firewall4
|
||||
|
||||
config PACKAGE_$(PKG_NAME)_INCLUDE_Brook
|
||||
bool "Include Brook"
|
||||
default n
|
||||
|
||||
config PACKAGE_$(PKG_NAME)_INCLUDE_Haproxy
|
||||
bool "Include Haproxy"
|
||||
default y if aarch64||arm||i386||x86_64
|
||||
|
||||
config PACKAGE_$(PKG_NAME)_INCLUDE_Hysteria
|
||||
bool "Include Hysteria"
|
||||
default n
|
||||
|
||||
config PACKAGE_$(PKG_NAME)_INCLUDE_NaiveProxy
|
||||
bool "Include NaiveProxy"
|
||||
depends on !(arc||(arm&&TARGET_gemini)||armeb||mips||mips64||powerpc)
|
||||
default n
|
||||
|
||||
config PACKAGE_$(PKG_NAME)_INCLUDE_Shadowsocks_Libev_Client
|
||||
bool "Include Shadowsocks Libev Client"
|
||||
default y
|
||||
|
||||
config PACKAGE_$(PKG_NAME)_INCLUDE_Shadowsocks_Libev_Server
|
||||
bool "Include Shadowsocks Libev Server"
|
||||
default y if aarch64||arm||i386||x86_64
|
||||
|
||||
config PACKAGE_$(PKG_NAME)_INCLUDE_Shadowsocks_Rust_Client
|
||||
bool "Include Shadowsocks Rust Client"
|
||||
depends on aarch64||arm||i386||mips||mipsel||x86_64
|
||||
default y if aarch64
|
||||
|
||||
config PACKAGE_$(PKG_NAME)_INCLUDE_Shadowsocks_Rust_Server
|
||||
bool "Include Shadowsocks Rust Server"
|
||||
depends on aarch64||arm||i386||mips||mipsel||x86_64
|
||||
default n
|
||||
|
||||
config PACKAGE_$(PKG_NAME)_INCLUDE_ShadowsocksR_Libev_Client
|
||||
bool "Include ShadowsocksR Libev Client"
|
||||
default y
|
||||
|
||||
config PACKAGE_$(PKG_NAME)_INCLUDE_ShadowsocksR_Libev_Server
|
||||
bool "Include ShadowsocksR Libev Server"
|
||||
default n
|
||||
|
||||
config PACKAGE_$(PKG_NAME)_INCLUDE_Simple_Obfs
|
||||
bool "Include Simple-Obfs (Shadowsocks Plugin)"
|
||||
default y
|
||||
|
||||
config PACKAGE_$(PKG_NAME)_INCLUDE_SingBox
|
||||
bool "Include Sing-Box"
|
||||
default y if aarch64||arm||i386||x86_64
|
||||
|
||||
config PACKAGE_$(PKG_NAME)_INCLUDE_Trojan_GO
|
||||
bool "Include Trojan-GO"
|
||||
default n
|
||||
|
||||
config PACKAGE_$(PKG_NAME)_INCLUDE_Trojan_Plus
|
||||
bool "Include Trojan-Plus"
|
||||
default y
|
||||
|
||||
config PACKAGE_$(PKG_NAME)_INCLUDE_tuic_client
|
||||
bool "Include tuic-client"
|
||||
depends on aarch64||arm||i386||x86_64
|
||||
default n
|
||||
|
||||
config PACKAGE_$(PKG_NAME)_INCLUDE_V2ray_Geodata
|
||||
bool "Include V2ray_Geodata"
|
||||
default n
|
||||
|
||||
config PACKAGE_$(PKG_NAME)_INCLUDE_V2ray_Plugin
|
||||
bool "Include V2ray-Plugin (Shadowsocks Plugin)"
|
||||
default y if aarch64||arm||i386||x86_64
|
||||
|
||||
config PACKAGE_$(PKG_NAME)_INCLUDE_Xray
|
||||
bool "Include Xray"
|
||||
default y if aarch64||arm||i386||x86_64
|
||||
|
||||
config PACKAGE_$(PKG_NAME)_INCLUDE_Xray_Plugin
|
||||
bool "Include Xray-Plugin (Shadowsocks Plugin)"
|
||||
default n
|
||||
|
||||
endmenu
|
||||
endef
|
||||
|
||||
define Package/$(PKG_NAME)/conffiles
|
||||
/etc/config/passwall
|
||||
/etc/config/passwall_server
|
||||
/usr/share/passwall/rules/direct_host
|
||||
/usr/share/passwall/rules/direct_ip
|
||||
/usr/share/passwall/rules/proxy_host
|
||||
/usr/share/passwall/rules/proxy_ip
|
||||
/usr/share/passwall/rules/block_host
|
||||
/usr/share/passwall/rules/block_ip
|
||||
/usr/share/passwall/rules/lanlist_ipv4
|
||||
/usr/share/passwall/rules/lanlist_ipv6
|
||||
/usr/share/passwall/rules/domains_excluded
|
||||
endef
|
||||
|
||||
include $(TOPDIR)/feeds/luci/luci.mk
|
||||
|
||||
# call BuildPackage - OpenWrt buildroot signature
|
@ -1,431 +0,0 @@
|
||||
-- Copyright (C) 2018-2020 L-WRT Team
|
||||
-- Copyright (C) 2021-2023 xiaorouji
|
||||
|
||||
module("luci.controller.passwall", package.seeall)
|
||||
local api = require "luci.passwall.api"
|
||||
local appname = api.appname
|
||||
local ucic = luci.model.uci.cursor()
|
||||
local http = require "luci.http"
|
||||
local util = require "luci.util"
|
||||
local i18n = require "luci.i18n"
|
||||
|
||||
function index()
|
||||
appname = require "luci.passwall.api".appname
|
||||
entry({"admin", "services", appname}).dependent = true
|
||||
entry({"admin", "services", appname, "reset_config"}, call("reset_config")).leaf = true
|
||||
entry({"admin", "services", appname, "show"}, call("show_menu")).leaf = true
|
||||
entry({"admin", "services", appname, "hide"}, call("hide_menu")).leaf = true
|
||||
if not nixio.fs.access("/etc/config/passwall") then return end
|
||||
if nixio.fs.access("/etc/config/passwall_show") then
|
||||
e = entry({"admin", "services", appname}, alias("admin", "services", appname, "settings"), _("Pass Wall"), -1)
|
||||
e.dependent = true
|
||||
e.acl_depends = { "luci-app-passwall" }
|
||||
end
|
||||
--[[ Client ]]
|
||||
entry({"admin", "services", appname, "settings"}, cbi(appname .. "/client/global"), _("Basic Settings"), 1).dependent = true
|
||||
entry({"admin", "services", appname, "node_list"}, cbi(appname .. "/client/node_list"), _("Node List"), 2).dependent = true
|
||||
entry({"admin", "services", appname, "node_subscribe"}, cbi(appname .. "/client/node_subscribe"), _("Node Subscribe"), 3).dependent = true
|
||||
entry({"admin", "services", appname, "other"}, cbi(appname .. "/client/other", {autoapply = true}), _("Other Settings"), 92).leaf = true
|
||||
if nixio.fs.access("/usr/sbin/haproxy") then
|
||||
entry({"admin", "services", appname, "haproxy"}, cbi(appname .. "/client/haproxy"), _("Load Balancing"), 93).leaf = true
|
||||
end
|
||||
entry({"admin", "services", appname, "app_update"}, cbi(appname .. "/client/app_update"), _("App Update"), 95).leaf = true
|
||||
entry({"admin", "services", appname, "rule"}, cbi(appname .. "/client/rule"), _("Rule Manage"), 96).leaf = true
|
||||
entry({"admin", "services", appname, "rule_list"}, cbi(appname .. "/client/rule_list"), _("Rule List"), 97).leaf = true
|
||||
entry({"admin", "services", appname, "node_subscribe_config"}, cbi(appname .. "/client/node_subscribe_config")).leaf = true
|
||||
entry({"admin", "services", appname, "node_config"}, cbi(appname .. "/client/node_config")).leaf = true
|
||||
entry({"admin", "services", appname, "shunt_rules"}, cbi(appname .. "/client/shunt_rules")).leaf = true
|
||||
entry({"admin", "services", appname, "socks_config"}, cbi(appname .. "/client/socks_config")).leaf = true
|
||||
entry({"admin", "services", appname, "acl"}, cbi(appname .. "/client/acl"), _("Access control"), 98).leaf = true
|
||||
entry({"admin", "services", appname, "acl_config"}, cbi(appname .. "/client/acl_config")).leaf = true
|
||||
entry({"admin", "services", appname, "log"}, form(appname .. "/client/log"), _("Watch Logs"), 999).leaf = true
|
||||
|
||||
--[[ Server ]]
|
||||
entry({"admin", "services", appname, "server"}, cbi(appname .. "/server/index"), _("Server-Side"), 99).leaf = true
|
||||
entry({"admin", "services", appname, "server_user"}, cbi(appname .. "/server/user")).leaf = true
|
||||
|
||||
--[[ API ]]
|
||||
entry({"admin", "services", appname, "server_user_status"}, call("server_user_status")).leaf = true
|
||||
entry({"admin", "services", appname, "server_user_log"}, call("server_user_log")).leaf = true
|
||||
entry({"admin", "services", appname, "server_get_log"}, call("server_get_log")).leaf = true
|
||||
entry({"admin", "services", appname, "server_clear_log"}, call("server_clear_log")).leaf = true
|
||||
entry({"admin", "services", appname, "link_add_node"}, call("link_add_node")).leaf = true
|
||||
entry({"admin", "services", appname, "socks_autoswitch_add_node"}, call("socks_autoswitch_add_node")).leaf = true
|
||||
entry({"admin", "services", appname, "socks_autoswitch_remove_node"}, call("socks_autoswitch_remove_node")).leaf = true
|
||||
entry({"admin", "services", appname, "get_now_use_node"}, call("get_now_use_node")).leaf = true
|
||||
entry({"admin", "services", appname, "get_redir_log"}, call("get_redir_log")).leaf = true
|
||||
entry({"admin", "services", appname, "get_log"}, call("get_log")).leaf = true
|
||||
entry({"admin", "services", appname, "clear_log"}, call("clear_log")).leaf = true
|
||||
entry({"admin", "services", appname, "status"}, call("status")).leaf = true
|
||||
entry({"admin", "services", appname, "haproxy_status"}, call("haproxy_status")).leaf = true
|
||||
entry({"admin", "services", appname, "socks_status"}, call("socks_status")).leaf = true
|
||||
entry({"admin", "services", appname, "connect_status"}, call("connect_status")).leaf = true
|
||||
entry({"admin", "services", appname, "ping_node"}, call("ping_node")).leaf = true
|
||||
entry({"admin", "services", appname, "urltest_node"}, call("urltest_node")).leaf = true
|
||||
entry({"admin", "services", appname, "set_node"}, call("set_node")).leaf = true
|
||||
entry({"admin", "services", appname, "copy_node"}, call("copy_node")).leaf = true
|
||||
entry({"admin", "services", appname, "clear_all_nodes"}, call("clear_all_nodes")).leaf = true
|
||||
entry({"admin", "services", appname, "delete_select_nodes"}, call("delete_select_nodes")).leaf = true
|
||||
entry({"admin", "services", appname, "update_rules"}, call("update_rules")).leaf = true
|
||||
|
||||
--[[Components update]]
|
||||
entry({"admin", "services", appname, "check_passwall"}, call("app_check")).leaf = true
|
||||
local coms = require "luci.passwall.com"
|
||||
local com
|
||||
for com, _ in pairs(coms) do
|
||||
entry({"admin", "services", appname, "check_" .. com}, call("com_check", com)).leaf = true
|
||||
entry({"admin", "services", appname, "update_" .. com}, call("com_update", com)).leaf = true
|
||||
end
|
||||
end
|
||||
|
||||
local function http_write_json(content)
|
||||
http.prepare_content("application/json")
|
||||
http.write_json(content or {code = 1})
|
||||
end
|
||||
|
||||
function reset_config()
|
||||
luci.sys.call('/etc/init.d/passwall stop')
|
||||
luci.sys.call('[ -f "/usr/share/passwall/0_default_config" ] && cp -f /usr/share/passwall/0_default_config /etc/config/passwall')
|
||||
luci.http.redirect(api.url())
|
||||
end
|
||||
|
||||
function show_menu()
|
||||
luci.sys.call("touch /etc/config/passwall_show")
|
||||
luci.sys.call("rm -rf /tmp/luci-*")
|
||||
luci.sys.call("/etc/init.d/rpcd restart >/dev/null")
|
||||
luci.http.redirect(api.url())
|
||||
end
|
||||
|
||||
function hide_menu()
|
||||
luci.sys.call("rm -rf /etc/config/passwall_show")
|
||||
luci.sys.call("rm -rf /tmp/luci-*")
|
||||
luci.sys.call("/etc/init.d/rpcd restart >/dev/null")
|
||||
luci.http.redirect(luci.dispatcher.build_url("admin", "status", "overview"))
|
||||
end
|
||||
|
||||
function link_add_node()
|
||||
local lfile = "/tmp/links.conf"
|
||||
local link = luci.http.formvalue("link")
|
||||
luci.sys.call('echo \'' .. link .. '\' > ' .. lfile)
|
||||
luci.sys.call("lua /usr/share/passwall/subscribe.lua add log")
|
||||
end
|
||||
|
||||
function socks_autoswitch_add_node()
|
||||
local id = luci.http.formvalue("id")
|
||||
local key = luci.http.formvalue("key")
|
||||
if id and id ~= "" and key and key ~= "" then
|
||||
local new_list = ucic:get(appname, id, "autoswitch_backup_node") or {}
|
||||
for i = #new_list, 1, -1 do
|
||||
if (ucic:get(appname, new_list[i], "remarks") or ""):find(key) then
|
||||
table.remove(new_list, i)
|
||||
end
|
||||
end
|
||||
for k, e in ipairs(api.get_valid_nodes()) do
|
||||
if e.node_type == "normal" and e["remark"]:find(key) then
|
||||
table.insert(new_list, e.id)
|
||||
end
|
||||
end
|
||||
ucic:set_list(appname, id, "autoswitch_backup_node", new_list)
|
||||
ucic:commit(appname)
|
||||
end
|
||||
luci.http.redirect(api.url("socks_config", id))
|
||||
end
|
||||
|
||||
function socks_autoswitch_remove_node()
|
||||
local id = luci.http.formvalue("id")
|
||||
local key = luci.http.formvalue("key")
|
||||
if id and id ~= "" and key and key ~= "" then
|
||||
local new_list = ucic:get(appname, id, "autoswitch_backup_node") or {}
|
||||
for i = #new_list, 1, -1 do
|
||||
if (ucic:get(appname, new_list[i], "remarks") or ""):find(key) then
|
||||
table.remove(new_list, i)
|
||||
end
|
||||
end
|
||||
ucic:set_list(appname, id, "autoswitch_backup_node", new_list)
|
||||
ucic:commit(appname)
|
||||
end
|
||||
luci.http.redirect(api.url("socks_config", id))
|
||||
end
|
||||
|
||||
function get_now_use_node()
|
||||
local e = {}
|
||||
local data, code, msg = nixio.fs.readfile("/tmp/etc/passwall/id/TCP")
|
||||
if data then
|
||||
e["TCP"] = util.trim(data)
|
||||
end
|
||||
local data, code, msg = nixio.fs.readfile("/tmp/etc/passwall/id/UDP")
|
||||
if data then
|
||||
e["UDP"] = util.trim(data)
|
||||
end
|
||||
luci.http.prepare_content("application/json")
|
||||
luci.http.write_json(e)
|
||||
end
|
||||
|
||||
function get_redir_log()
|
||||
local proto = luci.http.formvalue("proto")
|
||||
proto = proto:upper()
|
||||
if proto == "UDP" and (ucic:get(appname, "@global[0]", "udp_node") or "nil") == "tcp" and not nixio.fs.access("/tmp/etc/passwall/" .. proto .. ".log") then
|
||||
proto = "TCP"
|
||||
end
|
||||
if nixio.fs.access("/tmp/etc/passwall/" .. proto .. ".log") then
|
||||
local content = luci.sys.exec("cat /tmp/etc/passwall/" .. proto .. ".log")
|
||||
content = content:gsub("\n", "<br />")
|
||||
luci.http.write(content)
|
||||
else
|
||||
luci.http.write(string.format("<script>alert('%s');window.close();</script>", i18n.translate("Not enabled log")))
|
||||
end
|
||||
end
|
||||
|
||||
function get_log()
|
||||
-- luci.sys.exec("[ -f /tmp/log/passwall.log ] && sed '1!G;h;$!d' /tmp/log/passwall.log > /tmp/log/passwall_show.log")
|
||||
luci.http.write(luci.sys.exec("[ -f '/tmp/log/passwall.log' ] && cat /tmp/log/passwall.log"))
|
||||
end
|
||||
|
||||
function clear_log()
|
||||
luci.sys.call("echo '' > /tmp/log/passwall.log")
|
||||
end
|
||||
|
||||
function status()
|
||||
-- local dns_mode = ucic:get(appname, "@global[0]", "dns_mode")
|
||||
local e = {}
|
||||
e.dns_mode_status = luci.sys.call("netstat -apn | grep ':15353 ' >/dev/null") == 0
|
||||
e.haproxy_status = luci.sys.call(string.format("top -bn1 | grep -v grep | grep '%s/bin/' | grep haproxy >/dev/null", appname)) == 0
|
||||
e["tcp_node_status"] = luci.sys.call(string.format("top -bn1 | grep -v -E 'grep|acl/|acl_' | grep '%s/bin/' | grep -i 'TCP' >/dev/null", appname)) == 0
|
||||
|
||||
if (ucic:get(appname, "@global[0]", "udp_node") or "nil") == "tcp" then
|
||||
e["udp_node_status"] = e["tcp_node_status"]
|
||||
else
|
||||
e["udp_node_status"] = luci.sys.call(string.format("top -bn1 | grep -v -E 'grep|acl/|acl_' | grep '%s/bin/' | grep -i 'UDP' >/dev/null", appname)) == 0
|
||||
end
|
||||
luci.http.prepare_content("application/json")
|
||||
luci.http.write_json(e)
|
||||
end
|
||||
|
||||
function haproxy_status()
|
||||
local e = luci.sys.call(string.format("top -bn1 | grep -v grep | grep '%s/bin/' | grep haproxy >/dev/null", appname)) == 0
|
||||
luci.http.prepare_content("application/json")
|
||||
luci.http.write_json(e)
|
||||
end
|
||||
|
||||
function socks_status()
|
||||
local e = {}
|
||||
local index = luci.http.formvalue("index")
|
||||
local id = luci.http.formvalue("id")
|
||||
e.index = index
|
||||
e.socks_status = luci.sys.call(string.format("top -bn1 | grep -v -E 'grep|acl/|acl_' | grep '%s/bin/' | grep '%s' | grep 'SOCKS_' > /dev/null", appname, id)) == 0
|
||||
local use_http = ucic:get(appname, id, "http_port") or 0
|
||||
e.use_http = 0
|
||||
if tonumber(use_http) > 0 then
|
||||
e.use_http = 1
|
||||
e.http_status = luci.sys.call(string.format("top -bn1 | grep -v -E 'grep|acl/|acl_' | grep '%s/bin/' | grep '%s' | grep -E 'HTTP_|HTTP2SOCKS' > /dev/null", appname, id)) == 0
|
||||
end
|
||||
luci.http.prepare_content("application/json")
|
||||
luci.http.write_json(e)
|
||||
end
|
||||
|
||||
function connect_status()
|
||||
local e = {}
|
||||
e.use_time = ""
|
||||
local url = luci.http.formvalue("url")
|
||||
local result = luci.sys.exec('curl --connect-timeout 3 -o /dev/null -I -sk -w "%{http_code}:%{time_starttransfer}" ' .. url)
|
||||
local code = tonumber(luci.sys.exec("echo -n '" .. result .. "' | awk -F ':' '{print $1}'") or "0")
|
||||
if code ~= 0 then
|
||||
local use_time = luci.sys.exec("echo -n '" .. result .. "' | awk -F ':' '{print $2}'")
|
||||
if use_time:find("%.") then
|
||||
e.use_time = string.format("%.2f", use_time * 1000)
|
||||
else
|
||||
e.use_time = string.format("%.2f", use_time / 1000)
|
||||
end
|
||||
e.ping_type = "curl"
|
||||
end
|
||||
luci.http.prepare_content("application/json")
|
||||
luci.http.write_json(e)
|
||||
end
|
||||
|
||||
function ping_node()
|
||||
local index = luci.http.formvalue("index")
|
||||
local address = luci.http.formvalue("address")
|
||||
local port = luci.http.formvalue("port")
|
||||
local e = {}
|
||||
e.index = index
|
||||
local nodes_ping = ucic:get(appname, "@global_other[0]", "nodes_ping") or ""
|
||||
if nodes_ping:find("tcping") and luci.sys.exec("echo -n $(command -v tcping)") ~= "" then
|
||||
if api.is_ipv6(address) then
|
||||
address = api.get_ipv6_only(address)
|
||||
end
|
||||
e.ping = luci.sys.exec(string.format("echo -n $(tcping -q -c 1 -i 1 -t 2 -p %s %s 2>&1 | grep -o 'time=[0-9]*' | awk -F '=' '{print $2}') 2>/dev/null", port, address))
|
||||
end
|
||||
if e.ping == nil or tonumber(e.ping) == 0 then
|
||||
e.ping = luci.sys.exec("echo -n $(ping -c 1 -W 1 %q 2>&1 | grep -o 'time=[0-9]*' | awk -F '=' '{print $2}') 2>/dev/null" % address)
|
||||
end
|
||||
luci.http.prepare_content("application/json")
|
||||
luci.http.write_json(e)
|
||||
end
|
||||
|
||||
function urltest_node()
|
||||
local index = luci.http.formvalue("index")
|
||||
local id = luci.http.formvalue("id")
|
||||
local e = {}
|
||||
e.index = index
|
||||
local result = luci.sys.exec(string.format("/usr/share/passwall/test.sh url_test_node %s %s", id, "urltest_node"))
|
||||
local code = tonumber(luci.sys.exec("echo -n '" .. result .. "' | awk -F ':' '{print $1}'") or "0")
|
||||
if code ~= 0 then
|
||||
local use_time = luci.sys.exec("echo -n '" .. result .. "' | awk -F ':' '{print $2}'")
|
||||
if use_time:find("%.") then
|
||||
e.use_time = string.format("%.2f", use_time * 1000)
|
||||
else
|
||||
e.use_time = string.format("%.2f", use_time / 1000)
|
||||
end
|
||||
end
|
||||
luci.http.prepare_content("application/json")
|
||||
luci.http.write_json(e)
|
||||
end
|
||||
|
||||
function set_node()
|
||||
local protocol = luci.http.formvalue("protocol")
|
||||
local section = luci.http.formvalue("section")
|
||||
ucic:set(appname, "@global[0]", protocol .. "_node", section)
|
||||
ucic:commit(appname)
|
||||
luci.sys.call("/etc/init.d/passwall restart > /dev/null 2>&1 &")
|
||||
luci.http.redirect(api.url("log"))
|
||||
end
|
||||
|
||||
function copy_node()
|
||||
local section = luci.http.formvalue("section")
|
||||
local uuid = api.gen_short_uuid()
|
||||
ucic:section(appname, "nodes", uuid)
|
||||
for k, v in pairs(ucic:get_all(appname, section)) do
|
||||
local filter = k:find("%.")
|
||||
if filter and filter == 1 then
|
||||
else
|
||||
xpcall(function()
|
||||
ucic:set(appname, uuid, k, v)
|
||||
end,
|
||||
function(e)
|
||||
end)
|
||||
end
|
||||
end
|
||||
ucic:delete(appname, uuid, "add_from")
|
||||
ucic:set(appname, uuid, "add_mode", 1)
|
||||
ucic:commit(appname)
|
||||
luci.http.redirect(api.url("node_config", uuid))
|
||||
end
|
||||
|
||||
function clear_all_nodes()
|
||||
ucic:set(appname, '@global[0]', "enabled", "0")
|
||||
ucic:set(appname, '@global[0]', "tcp_node", "nil")
|
||||
ucic:set(appname, '@global[0]', "udp_node", "nil")
|
||||
ucic:foreach(appname, "socks", function(t)
|
||||
ucic:delete(appname, t[".name"])
|
||||
ucic:set_list(appname, t[".name"], "autoswitch_backup_node", {})
|
||||
end)
|
||||
ucic:foreach(appname, "haproxy_config", function(t)
|
||||
ucic:delete(appname, t[".name"])
|
||||
end)
|
||||
ucic:foreach(appname, "acl_rule", function(t)
|
||||
ucic:set(appname, t[".name"], "tcp_node", "default")
|
||||
ucic:set(appname, t[".name"], "udp_node", "default")
|
||||
end)
|
||||
ucic:foreach(appname, "nodes", function(node)
|
||||
ucic:delete(appname, node['.name'])
|
||||
end)
|
||||
|
||||
ucic:commit(appname)
|
||||
luci.sys.call("/etc/init.d/" .. appname .. " stop")
|
||||
end
|
||||
|
||||
function delete_select_nodes()
|
||||
local ids = luci.http.formvalue("ids")
|
||||
string.gsub(ids, '[^' .. "," .. ']+', function(w)
|
||||
if (ucic:get(appname, "@global[0]", "tcp_node") or "nil") == w then
|
||||
ucic:set(appname, '@global[0]', "tcp_node", "nil")
|
||||
end
|
||||
if (ucic:get(appname, "@global[0]", "udp_node") or "nil") == w then
|
||||
ucic:set(appname, '@global[0]', "udp_node", "nil")
|
||||
end
|
||||
ucic:foreach(appname, "socks", function(t)
|
||||
if t["node"] == w then
|
||||
ucic:delete(appname, t[".name"])
|
||||
end
|
||||
local auto_switch_node_list = ucic:get(appname, t[".name"], "autoswitch_backup_node") or {}
|
||||
for i = #auto_switch_node_list, 1, -1 do
|
||||
if w == auto_switch_node_list[i] then
|
||||
table.remove(auto_switch_node_list, i)
|
||||
end
|
||||
end
|
||||
ucic:set_list(appname, t[".name"], "autoswitch_backup_node", auto_switch_node_list)
|
||||
end)
|
||||
ucic:foreach(appname, "haproxy_config", function(t)
|
||||
if t["lbss"] == w then
|
||||
ucic:delete(appname, t[".name"])
|
||||
end
|
||||
end)
|
||||
ucic:foreach(appname, "acl_rule", function(t)
|
||||
if t["tcp_node"] == w then
|
||||
ucic:set(appname, t[".name"], "tcp_node", "default")
|
||||
end
|
||||
if t["udp_node"] == w then
|
||||
ucic:set(appname, t[".name"], "udp_node", "default")
|
||||
end
|
||||
end)
|
||||
ucic:delete(appname, w)
|
||||
end)
|
||||
ucic:commit(appname)
|
||||
luci.sys.call("/etc/init.d/" .. appname .. " restart > /dev/null 2>&1 &")
|
||||
end
|
||||
|
||||
function update_rules()
|
||||
local update = luci.http.formvalue("update")
|
||||
luci.sys.call("lua /usr/share/passwall/rule_update.lua log '" .. update .. "' > /dev/null 2>&1 &")
|
||||
http_write_json()
|
||||
end
|
||||
|
||||
function server_user_status()
|
||||
local e = {}
|
||||
e.index = luci.http.formvalue("index")
|
||||
e.status = luci.sys.call(string.format("top -bn1 | grep -v 'grep' | grep '%s/bin/' | grep -i '%s' >/dev/null", appname .. "_server", luci.http.formvalue("id"))) == 0
|
||||
http_write_json(e)
|
||||
end
|
||||
|
||||
function server_user_log()
|
||||
local id = luci.http.formvalue("id")
|
||||
if nixio.fs.access("/tmp/etc/passwall_server/" .. id .. ".log") then
|
||||
local content = luci.sys.exec("cat /tmp/etc/passwall_server/" .. id .. ".log")
|
||||
content = content:gsub("\n", "<br />")
|
||||
luci.http.write(content)
|
||||
else
|
||||
luci.http.write(string.format("<script>alert('%s');window.close();</script>", i18n.translate("Not enabled log")))
|
||||
end
|
||||
end
|
||||
|
||||
function server_get_log()
|
||||
luci.http.write(luci.sys.exec("[ -f '/tmp/log/passwall_server.log' ] && cat /tmp/log/passwall_server.log"))
|
||||
end
|
||||
|
||||
function server_clear_log()
|
||||
luci.sys.call("echo '' > /tmp/log/passwall_server.log")
|
||||
end
|
||||
|
||||
function app_check()
|
||||
local json = api.to_check_self()
|
||||
http_write_json(json)
|
||||
end
|
||||
|
||||
function com_check(comname)
|
||||
local json = api.to_check("",comname)
|
||||
http_write_json(json)
|
||||
end
|
||||
|
||||
function com_update(comname)
|
||||
local json = nil
|
||||
local task = http.formvalue("task")
|
||||
if task == "extract" then
|
||||
json = api.to_extract(comname, http.formvalue("file"), http.formvalue("subfix"))
|
||||
elseif task == "move" then
|
||||
json = api.to_move(comname, http.formvalue("file"))
|
||||
else
|
||||
json = api.to_download(comname, http.formvalue("url"), http.formvalue("size"))
|
||||
end
|
||||
|
||||
http_write_json(json)
|
||||
end
|
@ -1,130 +0,0 @@
|
||||
local api = require "luci.passwall.api"
|
||||
local appname = api.appname
|
||||
local sys = api.sys
|
||||
local has_chnlist = api.fs.access("/usr/share/passwall/rules/chnlist")
|
||||
|
||||
m = Map(appname)
|
||||
|
||||
s = m:section(TypedSection, "global", translate("ACLs"), "<font color='red'>" .. translate("ACLs is a tools which used to designate specific IP proxy mode.") .. "</font>")
|
||||
s.anonymous = true
|
||||
|
||||
o = s:option(Flag, "acl_enable", translate("Main switch"))
|
||||
o.rmempty = false
|
||||
o.default = false
|
||||
|
||||
local global_proxy_mode = (m:get("@global[0]", "tcp_proxy_mode") or "") .. (m:get("@global[0]", "udp_proxy_mode") or "")
|
||||
|
||||
-- [[ ACLs Settings ]]--
|
||||
s = m:section(TypedSection, "acl_rule")
|
||||
s.template = "cbi/tblsection"
|
||||
s.sortable = true
|
||||
s.anonymous = true
|
||||
s.addremove = true
|
||||
s.extedit = api.url("acl_config", "%s")
|
||||
function s.create(e, t)
|
||||
t = TypedSection.create(e, t)
|
||||
luci.http.redirect(e.extedit:format(t))
|
||||
end
|
||||
function s.remove(e, t)
|
||||
sys.call("rm -rf /tmp/etc/passwall_tmp/dns_" .. t .. "*")
|
||||
TypedSection.remove(e, t)
|
||||
end
|
||||
|
||||
---- Enable
|
||||
o = s:option(Flag, "enabled", translate("Enable"))
|
||||
o.default = 1
|
||||
o.rmempty = false
|
||||
|
||||
---- Remarks
|
||||
o = s:option(Value, "remarks", translate("Remarks"))
|
||||
o.rmempty = true
|
||||
|
||||
local mac_t = {}
|
||||
sys.net.mac_hints(function(e, t)
|
||||
mac_t[e] = {
|
||||
ip = t,
|
||||
mac = e
|
||||
}
|
||||
end)
|
||||
|
||||
o = s:option(DummyValue, "sources", translate("Source"))
|
||||
o.rawhtml = true
|
||||
o.cfgvalue = function(t, n)
|
||||
local e = ''
|
||||
local v = Value.cfgvalue(t, n) or ''
|
||||
string.gsub(v, '[^' .. " " .. ']+', function(w)
|
||||
local a = w
|
||||
if mac_t[w] then
|
||||
a = a .. ' (' .. mac_t[w].ip .. ')'
|
||||
end
|
||||
if #e > 0 then
|
||||
e = e .. "<br />"
|
||||
end
|
||||
e = e .. a
|
||||
end)
|
||||
return e
|
||||
end
|
||||
|
||||
---- TCP Proxy Mode
|
||||
tcp_proxy_mode = s:option(ListValue, "tcp_proxy_mode", "TCP " .. translate("Proxy Mode"))
|
||||
tcp_proxy_mode.default = "default"
|
||||
tcp_proxy_mode.rmempty = false
|
||||
tcp_proxy_mode:value("default", translate("Default"))
|
||||
tcp_proxy_mode:value("disable", translate("No Proxy"))
|
||||
tcp_proxy_mode:value("global", translate("Global Proxy"))
|
||||
if has_chnlist and global_proxy_mode:find("returnhome") then
|
||||
tcp_proxy_mode:value("returnhome", translate("China List"))
|
||||
else
|
||||
tcp_proxy_mode:value("gfwlist", translate("GFW List"))
|
||||
tcp_proxy_mode:value("chnroute", translate("Not China List"))
|
||||
end
|
||||
tcp_proxy_mode:value("direct/proxy", translate("Only use direct/proxy list"))
|
||||
|
||||
---- UDP Proxy Mode
|
||||
udp_proxy_mode = s:option(ListValue, "udp_proxy_mode", "UDP " .. translate("Proxy Mode"))
|
||||
udp_proxy_mode.default = "default"
|
||||
udp_proxy_mode.rmempty = false
|
||||
udp_proxy_mode:value("default", translate("Default"))
|
||||
udp_proxy_mode:value("disable", translate("No Proxy"))
|
||||
udp_proxy_mode:value("global", translate("Global Proxy"))
|
||||
if has_chnlist and global_proxy_mode:find("returnhome") then
|
||||
udp_proxy_mode:value("returnhome", translate("China List"))
|
||||
else
|
||||
udp_proxy_mode:value("gfwlist", translate("GFW List"))
|
||||
udp_proxy_mode:value("chnroute", translate("Not China List"))
|
||||
end
|
||||
udp_proxy_mode:value("direct/proxy", translate("Only use direct/proxy list"))
|
||||
|
||||
--[[
|
||||
---- TCP No Redir Ports
|
||||
o = s:option(Value, "tcp_no_redir_ports", translate("TCP No Redir Ports"))
|
||||
o.default = "default"
|
||||
o:value("disable", translate("No patterns are used"))
|
||||
o:value("default", translate("Default"))
|
||||
o:value("1:65535", translate("All"))
|
||||
|
||||
---- UDP No Redir Ports
|
||||
o = s:option(Value, "udp_no_redir_ports", translate("UDP No Redir Ports"))
|
||||
o.default = "default"
|
||||
o:value("disable", translate("No patterns are used"))
|
||||
o:value("default", translate("Default"))
|
||||
o:value("1:65535", translate("All"))
|
||||
|
||||
---- TCP Redir Ports
|
||||
o = s:option(Value, "tcp_redir_ports", translate("TCP Redir Ports"))
|
||||
o.default = "default"
|
||||
o:value("default", translate("Default"))
|
||||
o:value("1:65535", translate("All"))
|
||||
o:value("80,443", "80,443")
|
||||
o:value("80:65535", "80 " .. translate("or more"))
|
||||
o:value("1:443", "443 " .. translate("or less"))
|
||||
|
||||
---- UDP Redir Ports
|
||||
o = s:option(Value, "udp_redir_ports", translate("UDP Redir Ports"))
|
||||
o.default = "default"
|
||||
o:value("default", translate("Default"))
|
||||
o:value("1:65535", translate("All"))
|
||||
o:value("53", "53")
|
||||
]]--
|
||||
|
||||
return m
|
@ -1,336 +0,0 @@
|
||||
local api = require "luci.passwall.api"
|
||||
local appname = api.appname
|
||||
local sys = api.sys
|
||||
local has_singbox = api.finded_com("singbox")
|
||||
local has_xray = api.finded_com("xray")
|
||||
local has_chnlist = api.fs.access("/usr/share/passwall/rules/chnlist")
|
||||
|
||||
m = Map(appname)
|
||||
|
||||
local nodes_table = {}
|
||||
for k, e in ipairs(api.get_valid_nodes()) do
|
||||
nodes_table[#nodes_table + 1] = e
|
||||
end
|
||||
|
||||
local global_proxy_mode = (m:get("@global[0]", "tcp_proxy_mode") or "") .. (m:get("@global[0]", "udp_proxy_mode") or "")
|
||||
|
||||
local dynamicList_write = function(self, section, value)
|
||||
local t = {}
|
||||
local t2 = {}
|
||||
if type(value) == "table" then
|
||||
local x
|
||||
for _, x in ipairs(value) do
|
||||
if x and #x > 0 then
|
||||
if not t2[x] then
|
||||
t2[x] = x
|
||||
t[#t+1] = x
|
||||
end
|
||||
end
|
||||
end
|
||||
else
|
||||
t = { value }
|
||||
end
|
||||
t = table.concat(t, " ")
|
||||
return DynamicList.write(self, section, t)
|
||||
end
|
||||
|
||||
-- [[ ACLs Settings ]]--
|
||||
s = m:section(NamedSection, arg[1], translate("ACLs"), translate("ACLs"))
|
||||
s.addremove = false
|
||||
s.dynamic = false
|
||||
|
||||
---- Enable
|
||||
o = s:option(Flag, "enabled", translate("Enable"))
|
||||
o.default = 1
|
||||
o.rmempty = false
|
||||
|
||||
---- Remarks
|
||||
o = s:option(Value, "remarks", translate("Remarks"))
|
||||
o.default = arg[1]
|
||||
o.rmempty = true
|
||||
|
||||
local mac_t = {}
|
||||
sys.net.mac_hints(function(e, t)
|
||||
mac_t[#mac_t + 1] = {
|
||||
ip = t,
|
||||
mac = e
|
||||
}
|
||||
end)
|
||||
table.sort(mac_t, function(a,b)
|
||||
if #a.ip < #b.ip then
|
||||
return true
|
||||
elseif #a.ip == #b.ip then
|
||||
if a.ip < b.ip then
|
||||
return true
|
||||
else
|
||||
return #a.ip < #b.ip
|
||||
end
|
||||
end
|
||||
return false
|
||||
end)
|
||||
|
||||
---- Source
|
||||
sources = s:option(DynamicList, "sources", translate("Source"))
|
||||
sources.description = "<ul><li>" .. translate("Example:")
|
||||
.. "</li><li>" .. translate("MAC") .. ": 00:00:00:FF:FF:FF"
|
||||
.. "</li><li>" .. translate("IP") .. ": 192.168.1.100"
|
||||
.. "</li><li>" .. translate("IP CIDR") .. ": 192.168.1.0/24"
|
||||
.. "</li><li>" .. translate("IP range") .. ": 192.168.1.100-192.168.1.200"
|
||||
.. "</li><li>" .. translate("IPSet") .. ": ipset:lanlist"
|
||||
.. "</li></ul>"
|
||||
sources.cast = "string"
|
||||
for _, key in pairs(mac_t) do
|
||||
sources:value(key.mac, "%s (%s)" % {key.mac, key.ip})
|
||||
end
|
||||
sources.cfgvalue = function(self, section)
|
||||
local value
|
||||
if self.tag_error[section] then
|
||||
value = self:formvalue(section)
|
||||
else
|
||||
value = self.map:get(section, self.option)
|
||||
if type(value) == "string" then
|
||||
local value2 = {}
|
||||
string.gsub(value, '[^' .. " " .. ']+', function(w) table.insert(value2, w) end)
|
||||
value = value2
|
||||
end
|
||||
end
|
||||
return value
|
||||
end
|
||||
sources.validate = function(self, value, t)
|
||||
local err = {}
|
||||
for _, v in ipairs(value) do
|
||||
local flag = false
|
||||
if v:find("ipset:") and v:find("ipset:") == 1 then
|
||||
local ipset = v:gsub("ipset:", "")
|
||||
if ipset and ipset ~= "" then
|
||||
flag = true
|
||||
end
|
||||
end
|
||||
|
||||
if flag == false and datatypes.macaddr(v) then
|
||||
flag = true
|
||||
end
|
||||
|
||||
if flag == false and datatypes.ip4addr(v) then
|
||||
flag = true
|
||||
end
|
||||
|
||||
if flag == false and api.iprange(v) then
|
||||
flag = true
|
||||
end
|
||||
|
||||
if flag == false then
|
||||
err[#err + 1] = v
|
||||
end
|
||||
end
|
||||
|
||||
if #err > 0 then
|
||||
self:add_error(t, "invalid", translate("Not true format, please re-enter!"))
|
||||
for _, v in ipairs(err) do
|
||||
self:add_error(t, "invalid", v)
|
||||
end
|
||||
end
|
||||
|
||||
return value
|
||||
end
|
||||
sources.write = dynamicList_write
|
||||
|
||||
---- TCP No Redir Ports
|
||||
o = s:option(Value, "tcp_no_redir_ports", translate("TCP No Redir Ports"))
|
||||
o.default = "default"
|
||||
o:value("disable", translate("No patterns are used"))
|
||||
o:value("default", translate("Default"))
|
||||
o:value("1:65535", translate("All"))
|
||||
|
||||
---- UDP No Redir Ports
|
||||
o = s:option(Value, "udp_no_redir_ports", translate("UDP No Redir Ports"))
|
||||
o.default = "default"
|
||||
o:value("disable", translate("No patterns are used"))
|
||||
o:value("default", translate("Default"))
|
||||
o:value("1:65535", translate("All"))
|
||||
|
||||
---- TCP Proxy Drop Ports
|
||||
o = s:option(Value, "tcp_proxy_drop_ports", translate("TCP Proxy Drop Ports"))
|
||||
o.default = "default"
|
||||
o:value("disable", translate("No patterns are used"))
|
||||
o:value("default", translate("Default"))
|
||||
|
||||
---- UDP Proxy Drop Ports
|
||||
o = s:option(Value, "udp_proxy_drop_ports", translate("UDP Proxy Drop Ports"))
|
||||
o.default = "default"
|
||||
o:value("disable", translate("No patterns are used"))
|
||||
o:value("default", translate("Default"))
|
||||
o:value("80,443", translate("QUIC"))
|
||||
|
||||
---- TCP Redir Ports
|
||||
o = s:option(Value, "tcp_redir_ports", translate("TCP Redir Ports"))
|
||||
o.default = "default"
|
||||
o:value("default", translate("Default"))
|
||||
o:value("1:65535", translate("All"))
|
||||
o:value("80,443", "80,443")
|
||||
o:value("80:65535", "80 " .. translate("or more"))
|
||||
o:value("1:443", "443 " .. translate("or less"))
|
||||
|
||||
---- UDP Redir Ports
|
||||
o = s:option(Value, "udp_redir_ports", translate("UDP Redir Ports"))
|
||||
o.default = "default"
|
||||
o:value("default", translate("Default"))
|
||||
o:value("1:65535", translate("All"))
|
||||
o:value("53", "53")
|
||||
|
||||
---- TCP Proxy Mode
|
||||
tcp_proxy_mode = s:option(ListValue, "tcp_proxy_mode", "TCP " .. translate("Proxy Mode"))
|
||||
tcp_proxy_mode.default = "default"
|
||||
tcp_proxy_mode.rmempty = false
|
||||
tcp_proxy_mode:value("default", translate("Default"))
|
||||
tcp_proxy_mode:value("disable", translate("No Proxy"))
|
||||
tcp_proxy_mode:value("global", translate("Global Proxy"))
|
||||
if has_chnlist and global_proxy_mode:find("returnhome") then
|
||||
tcp_proxy_mode:value("returnhome", translate("China List"))
|
||||
else
|
||||
tcp_proxy_mode:value("gfwlist", translate("GFW List"))
|
||||
tcp_proxy_mode:value("chnroute", translate("Not China List"))
|
||||
end
|
||||
tcp_proxy_mode:value("direct/proxy", translate("Only use direct/proxy list"))
|
||||
|
||||
---- UDP Proxy Mode
|
||||
udp_proxy_mode = s:option(ListValue, "udp_proxy_mode", "UDP " .. translate("Proxy Mode"))
|
||||
udp_proxy_mode.default = "default"
|
||||
udp_proxy_mode.rmempty = false
|
||||
udp_proxy_mode:value("default", translate("Default"))
|
||||
udp_proxy_mode:value("disable", translate("No Proxy"))
|
||||
udp_proxy_mode:value("global", translate("Global Proxy"))
|
||||
if has_chnlist and global_proxy_mode:find("returnhome") then
|
||||
udp_proxy_mode:value("returnhome", translate("China List"))
|
||||
else
|
||||
udp_proxy_mode:value("gfwlist", translate("GFW List"))
|
||||
udp_proxy_mode:value("chnroute", translate("Not China List"))
|
||||
end
|
||||
udp_proxy_mode:value("direct/proxy", translate("Only use direct/proxy list"))
|
||||
|
||||
tcp_node = s:option(ListValue, "tcp_node", "<a style='color: red'>" .. translate("TCP Node") .. "</a>")
|
||||
tcp_node.default = "default"
|
||||
tcp_node:value("default", translate("Default"))
|
||||
|
||||
udp_node = s:option(ListValue, "udp_node", "<a style='color: red'>" .. translate("UDP Node") .. "</a>")
|
||||
udp_node.default = "default"
|
||||
udp_node:value("default", translate("Default"))
|
||||
udp_node:value("tcp", translate("Same as the tcp node"))
|
||||
|
||||
for k, v in pairs(nodes_table) do
|
||||
tcp_node:value(v.id, v["remark"])
|
||||
udp_node:value(v.id, v["remark"])
|
||||
end
|
||||
|
||||
o = s:option(Flag, "filter_proxy_ipv6", translate("Filter Proxy Host IPv6"), translate("Experimental feature."))
|
||||
o.default = "0"
|
||||
o:depends({ tcp_node = "default", ['!reverse'] = true })
|
||||
|
||||
---- DNS Forward Mode
|
||||
o = s:option(ListValue, "dns_mode", translate("Filter Mode"))
|
||||
o:depends({ tcp_node = "default", ['!reverse'] = true })
|
||||
if api.is_finded("dns2socks") then
|
||||
o:value("dns2socks", "dns2socks")
|
||||
end
|
||||
if has_singbox then
|
||||
o:value("sing-box", "Sing-Box")
|
||||
end
|
||||
if has_xray then
|
||||
o:value("xray", "Xray")
|
||||
end
|
||||
|
||||
o = s:option(ListValue, "v2ray_dns_mode", " ")
|
||||
o:value("tcp", "TCP")
|
||||
o:value("doh", "DoH")
|
||||
o:depends("dns_mode", "sing-box")
|
||||
o:depends("dns_mode", "xray")
|
||||
|
||||
---- DNS Forward
|
||||
o = s:option(Value, "remote_dns", translate("Remote DNS"))
|
||||
o.default = "1.1.1.1"
|
||||
o:value("1.1.1.1", "1.1.1.1 (CloudFlare)")
|
||||
o:value("1.1.1.2", "1.1.1.2 (CloudFlare-Security)")
|
||||
o:value("8.8.4.4", "8.8.4.4 (Google)")
|
||||
o:value("8.8.8.8", "8.8.8.8 (Google)")
|
||||
o:value("9.9.9.9", "9.9.9.9 (Quad9-Recommended)")
|
||||
o:value("208.67.220.220", "208.67.220.220 (OpenDNS)")
|
||||
o:value("208.67.222.222", "208.67.222.222 (OpenDNS)")
|
||||
o:depends("dns_mode", "dns2socks")
|
||||
o:depends("v2ray_dns_mode", "tcp")
|
||||
|
||||
if has_singbox or has_xray then
|
||||
o = s:option(Value, "remote_dns_doh", translate("Remote DNS DoH"))
|
||||
o:value("https://1.1.1.1/dns-query", "CloudFlare")
|
||||
o:value("https://1.1.1.2/dns-query", "CloudFlare-Security")
|
||||
o:value("https://8.8.4.4/dns-query", "Google 8844")
|
||||
o:value("https://8.8.8.8/dns-query", "Google 8888")
|
||||
o:value("https://9.9.9.9/dns-query", "Quad9-Recommended")
|
||||
o:value("https://208.67.222.222/dns-query", "OpenDNS")
|
||||
o:value("https://dns.adguard.com/dns-query,176.103.130.130", "AdGuard")
|
||||
o:value("https://doh.libredns.gr/dns-query,116.202.176.26", "LibreDNS")
|
||||
o:value("https://doh.libredns.gr/ads,116.202.176.26", "LibreDNS (No Ads)")
|
||||
o.default = "https://1.1.1.1/dns-query"
|
||||
o.validate = function(self, value, t)
|
||||
if value ~= "" then
|
||||
value = api.trim(value)
|
||||
local flag = 0
|
||||
local util = require "luci.util"
|
||||
local val = util.split(value, ",")
|
||||
local url = val[1]
|
||||
val[1] = nil
|
||||
for i = 1, #val do
|
||||
local v = val[i]
|
||||
if v then
|
||||
if not api.datatypes.ipmask4(v) then
|
||||
flag = 1
|
||||
end
|
||||
end
|
||||
end
|
||||
if flag == 0 then
|
||||
return value
|
||||
end
|
||||
end
|
||||
return nil, translate("DoH request address") .. " " .. translate("Format must be:") .. " URL,IP"
|
||||
end
|
||||
o:depends("v2ray_dns_mode", "doh")
|
||||
|
||||
if has_xray then
|
||||
o = s:option(Value, "dns_client_ip", translate("EDNS Client Subnet"))
|
||||
o.datatype = "ipaddr"
|
||||
o:depends({dns_mode = "xray", v2ray_dns_mode = "tcp"})
|
||||
o:depends({dns_mode = "xray", v2ray_dns_mode = "doh"})
|
||||
end
|
||||
end
|
||||
|
||||
if api.is_finded("chinadns-ng") then
|
||||
o = s:option(Flag, "chinadns_ng", translate("ChinaDNS-NG"), translate("The effect is better, but will increase the memory."))
|
||||
o.default = "0"
|
||||
o:depends({ tcp_proxy_mode = "gfwlist", dns_mode = "dns2socks"})
|
||||
o:depends({ tcp_proxy_mode = "gfwlist", dns_mode = "xray"})
|
||||
o:depends({ tcp_proxy_mode = "chnroute", dns_mode = "dns2socks"})
|
||||
o:depends({ tcp_proxy_mode = "chnroute", dns_mode = "xray"})
|
||||
end
|
||||
|
||||
if has_chnlist then
|
||||
when_chnroute_default_dns = s:option(ListValue, "when_chnroute_default_dns", translate("When using the chnroute list the default DNS"))
|
||||
when_chnroute_default_dns.default = "direct"
|
||||
when_chnroute_default_dns:value("remote", translate("Remote DNS"))
|
||||
when_chnroute_default_dns:value("direct", translate("Direct DNS"))
|
||||
when_chnroute_default_dns.description = "<ul>"
|
||||
.. "<li>" .. translate("Remote DNS can avoid more DNS leaks, but some domestic domain names maybe to proxy!") .. "</li>"
|
||||
.. "<li>" .. translate("Direct DNS Internet experience may be better, but DNS will be leaked!") .. "</li>"
|
||||
.. "</ul>"
|
||||
local _depends = {
|
||||
{ dns_mode = "dns2socks" },
|
||||
{ dns_mode = "xray" }
|
||||
}
|
||||
for i, d in ipairs(_depends) do
|
||||
d["tcp_proxy_mode"] = "chnroute"
|
||||
if api.is_finded("chinadns-ng") then
|
||||
d["chinadns_ng"] = false
|
||||
end
|
||||
when_chnroute_default_dns:depends(d)
|
||||
end
|
||||
end
|
||||
|
||||
return m
|
@ -1,28 +0,0 @@
|
||||
local api = require "luci.passwall.api"
|
||||
local appname = api.appname
|
||||
|
||||
m = Map(appname)
|
||||
|
||||
-- [[ App Settings ]]--
|
||||
s = m:section(TypedSection, "global_app", translate("App Update"),
|
||||
"<font color='red'>" ..
|
||||
translate("Please confirm that your firmware supports FPU.") ..
|
||||
"</font>")
|
||||
s.anonymous = true
|
||||
s:append(Template(appname .. "/app_update/app_version"))
|
||||
|
||||
local k, v
|
||||
local com = require "luci.passwall.com"
|
||||
for k, v in pairs(com) do
|
||||
o = s:option(Value, k:gsub("%-","_") .. "_file", translatef("%s App Path", v.name))
|
||||
o.default = v.default_path or ("/usr/bin/" .. k)
|
||||
o.rmempty = false
|
||||
end
|
||||
|
||||
o = s:option(DummyValue, "tips", " ")
|
||||
o.rawhtml = true
|
||||
o.cfgvalue = function(t, n)
|
||||
return string.format('<font color="red">%s</font>', translate("if you want to run from memory, change the path, /tmp beginning then save the application and update it manually."))
|
||||
end
|
||||
|
||||
return m
|
@ -1,573 +0,0 @@
|
||||
local api = require "luci.passwall.api"
|
||||
local appname = api.appname
|
||||
local uci = api.uci
|
||||
local datatypes = api.datatypes
|
||||
local has_singbox = api.finded_com("singbox")
|
||||
local has_xray = api.finded_com("xray")
|
||||
local has_chnlist = api.fs.access("/usr/share/passwall/rules/chnlist")
|
||||
|
||||
m = Map(appname)
|
||||
|
||||
local nodes_table = {}
|
||||
for k, e in ipairs(api.get_valid_nodes()) do
|
||||
nodes_table[#nodes_table + 1] = e
|
||||
end
|
||||
|
||||
local tcp_socks_server = "127.0.0.1" .. ":" .. (uci:get(appname, "@global[0]", "tcp_node_socks_port") or "1070")
|
||||
local socks_table = {}
|
||||
socks_table[#socks_table + 1] = {
|
||||
id = tcp_socks_server,
|
||||
remarks = tcp_socks_server .. " - " .. translate("TCP Node")
|
||||
}
|
||||
uci:foreach(appname, "socks", function(s)
|
||||
if s.enabled == "1" and s.node then
|
||||
local id, remarks
|
||||
for k, n in pairs(nodes_table) do
|
||||
if (s.node == n.id) then
|
||||
remarks = n["remark"]; break
|
||||
end
|
||||
end
|
||||
id = "127.0.0.1" .. ":" .. s.port
|
||||
socks_table[#socks_table + 1] = {
|
||||
id = id,
|
||||
remarks = id .. " - " .. (remarks or translate("Misconfigured"))
|
||||
}
|
||||
end
|
||||
end)
|
||||
|
||||
local doh_validate = function(self, value, t)
|
||||
if value ~= "" then
|
||||
value = api.trim(value)
|
||||
local flag = 0
|
||||
local util = require "luci.util"
|
||||
local val = util.split(value, ",")
|
||||
local url = val[1]
|
||||
val[1] = nil
|
||||
for i = 1, #val do
|
||||
local v = val[i]
|
||||
if v then
|
||||
if not datatypes.ipmask4(v) then
|
||||
flag = 1
|
||||
end
|
||||
end
|
||||
end
|
||||
if flag == 0 then
|
||||
return value
|
||||
end
|
||||
end
|
||||
return nil, translate("DoH request address") .. " " .. translate("Format must be:") .. " URL,IP"
|
||||
end
|
||||
|
||||
local redir_mode_validate = function(self, value, t)
|
||||
local tcp_proxy_mode_v = tcp_proxy_mode:formvalue(t) or ""
|
||||
local udp_proxy_mode_v = udp_proxy_mode:formvalue(t) or ""
|
||||
local localhost_tcp_proxy_mode_v = localhost_tcp_proxy_mode:formvalue(t) or ""
|
||||
local localhost_udp_proxy_mode_v = localhost_udp_proxy_mode:formvalue(t) or ""
|
||||
local s = tcp_proxy_mode_v .. udp_proxy_mode_v .. localhost_tcp_proxy_mode_v .. localhost_udp_proxy_mode_v
|
||||
if s:find("returnhome") then
|
||||
if s:find("chnroute") or s:find("gfwlist") then
|
||||
return nil, translate("China list or gfwlist cannot be used together with outside China list!")
|
||||
end
|
||||
end
|
||||
return value
|
||||
end
|
||||
|
||||
m:append(Template(appname .. "/global/status"))
|
||||
|
||||
s = m:section(TypedSection, "global")
|
||||
s.anonymous = true
|
||||
s.addremove = false
|
||||
|
||||
s:tab("Main", translate("Main"))
|
||||
|
||||
-- [[ Global Settings ]]--
|
||||
o = s:taboption("Main", Flag, "enabled", translate("Main switch"))
|
||||
o.rmempty = false
|
||||
|
||||
---- TCP Node
|
||||
tcp_node = s:taboption("Main", ListValue, "tcp_node", "<a style='color: red'>" .. translate("TCP Node") .. "</a>")
|
||||
tcp_node:value("nil", translate("Close"))
|
||||
|
||||
---- UDP Node
|
||||
udp_node = s:taboption("Main", ListValue, "udp_node", "<a style='color: red'>" .. translate("UDP Node") .. "</a>")
|
||||
udp_node:value("nil", translate("Close"))
|
||||
udp_node:value("tcp", translate("Same as the tcp node"))
|
||||
|
||||
-- 分流
|
||||
if (has_singbox or has_xray) and #nodes_table > 0 then
|
||||
local normal_list = {}
|
||||
local balancing_list = {}
|
||||
local shunt_list = {}
|
||||
local iface_list = {}
|
||||
for k, v in pairs(nodes_table) do
|
||||
if v.node_type == "normal" then
|
||||
normal_list[#normal_list + 1] = v
|
||||
end
|
||||
if v.protocol and v.protocol == "_balancing" then
|
||||
balancing_list[#balancing_list + 1] = v
|
||||
end
|
||||
if v.protocol and v.protocol == "_shunt" then
|
||||
shunt_list[#shunt_list + 1] = v
|
||||
end
|
||||
if v.protocol and v.protocol == "_iface" then
|
||||
iface_list[#iface_list + 1] = v
|
||||
end
|
||||
end
|
||||
|
||||
local function get_cfgvalue(shunt_node_id, option)
|
||||
return function(self, section)
|
||||
return m:get(shunt_node_id, option) or "nil"
|
||||
end
|
||||
end
|
||||
local function get_write(shunt_node_id, option)
|
||||
return function(self, section, value)
|
||||
m:set(shunt_node_id, option, value)
|
||||
end
|
||||
end
|
||||
if #normal_list > 0 then
|
||||
for k, v in pairs(shunt_list) do
|
||||
local vid = v.id
|
||||
-- shunt node type, Sing-Box or Xray
|
||||
local type = s:taboption("Main", ListValue, vid .. "-type", translate("Type"))
|
||||
if has_singbox then
|
||||
type:value("sing-box", "Sing-Box")
|
||||
end
|
||||
if has_xray then
|
||||
type:value("Xray", translate("Xray"))
|
||||
end
|
||||
type.cfgvalue = get_cfgvalue(v.id, "type")
|
||||
type.write = get_write(v.id, "type")
|
||||
|
||||
-- pre-proxy
|
||||
o = s:taboption("Main", Flag, vid .. "-preproxy_enabled", translate("Preproxy"))
|
||||
o:depends("tcp_node", v.id)
|
||||
o.rmempty = false
|
||||
o.cfgvalue = get_cfgvalue(v.id, "preproxy_enabled")
|
||||
o.write = get_write(v.id, "preproxy_enabled")
|
||||
|
||||
o = s:taboption("Main", Value, vid .. "-main_node", string.format('<a style="color:red">%s</a>', translate("Preproxy Node")), translate("Set the node to be used as a pre-proxy. Each rule (including <code>Default</code>) has a separate switch that controls whether this rule uses the pre-proxy or not."))
|
||||
o:depends(vid .. "-preproxy_enabled", "1")
|
||||
for k1, v1 in pairs(balancing_list) do
|
||||
o:value(v1.id, v1.remark)
|
||||
end
|
||||
for k1, v1 in pairs(iface_list) do
|
||||
o:value(v1.id, v1.remark)
|
||||
end
|
||||
for k1, v1 in pairs(normal_list) do
|
||||
o:value(v1.id, v1.remark)
|
||||
end
|
||||
o.cfgvalue = get_cfgvalue(v.id, "main_node")
|
||||
o.write = get_write(v.id, "main_node")
|
||||
|
||||
if (has_singbox and has_xray) or (v.type == "sing-box" and not has_singbox) or (v.type == "Xray" and not has_xray) then
|
||||
type:depends("tcp_node", v.id)
|
||||
else
|
||||
type:depends("tcp_node", "hide") --不存在的依赖,即始终隐藏
|
||||
end
|
||||
|
||||
uci:foreach(appname, "shunt_rules", function(e)
|
||||
local id = e[".name"]
|
||||
local node_option = vid .. "-" .. id .. "_node"
|
||||
if id and e.remarks then
|
||||
o = s:taboption("Main", Value, node_option, string.format('* <a href="%s" target="_blank">%s</a>', api.url("shunt_rules", id), e.remarks))
|
||||
o.cfgvalue = get_cfgvalue(v.id, id)
|
||||
o.write = get_write(v.id, id)
|
||||
o:depends("tcp_node", v.id)
|
||||
o:value("nil", translate("Close"))
|
||||
o:value("_default", translate("Default"))
|
||||
o:value("_direct", translate("Direct Connection"))
|
||||
o:value("_blackhole", translate("Blackhole"))
|
||||
|
||||
local pt = s:taboption("Main", ListValue, vid .. "-".. id .. "_proxy_tag", string.format('* <a style="color:red">%s</a>', e.remarks .. " " .. translate("Preproxy")))
|
||||
pt.cfgvalue = get_cfgvalue(v.id, id .. "_proxy_tag")
|
||||
pt.write = get_write(v.id, id .. "_proxy_tag")
|
||||
pt:value("nil", translate("Close"))
|
||||
pt:value("main", translate("Preproxy Node"))
|
||||
pt.default = "nil"
|
||||
for k1, v1 in pairs(balancing_list) do
|
||||
o:value(v1.id, v1.remark)
|
||||
end
|
||||
for k1, v1 in pairs(iface_list) do
|
||||
o:value(v1.id, v1.remark)
|
||||
end
|
||||
for k1, v1 in pairs(normal_list) do
|
||||
o:value(v1.id, v1.remark)
|
||||
pt:depends({ [node_option] = v1.id, [vid .. "-preproxy_enabled"] = "1" })
|
||||
end
|
||||
end
|
||||
end)
|
||||
|
||||
local id = "default_node"
|
||||
o = s:taboption("Main", Value, vid .. "-" .. id, string.format('* <a style="color:red">%s</a>', translate("Default")))
|
||||
o.cfgvalue = get_cfgvalue(v.id, id)
|
||||
o.write = get_write(v.id, id)
|
||||
o:depends("tcp_node", v.id)
|
||||
o:value("_direct", translate("Direct Connection"))
|
||||
o:value("_blackhole", translate("Blackhole"))
|
||||
for k1, v1 in pairs(balancing_list) do
|
||||
o:value(v1.id, v1.remark)
|
||||
end
|
||||
for k1, v1 in pairs(iface_list) do
|
||||
o:value(v1.id, v1.remark)
|
||||
end
|
||||
for k1, v1 in pairs(normal_list) do
|
||||
o:value(v1.id, v1.remark)
|
||||
end
|
||||
|
||||
local id = "default_proxy_tag"
|
||||
o = s:taboption("Main", ListValue, vid .. "-" .. id, string.format('* <a style="color:red">%s</a>', translate("Default Preproxy")), translate("When using, localhost will connect this node first and then use this node to connect the default node."))
|
||||
o.cfgvalue = get_cfgvalue(v.id, id)
|
||||
o.write = get_write(v.id, id)
|
||||
o:value("nil", translate("Close"))
|
||||
o:value("main", translate("Preproxy Node"))
|
||||
for k1, v1 in pairs(normal_list) do
|
||||
if v1.protocol ~= "_balancing" then
|
||||
o:depends({ [vid .. "-default_node"] = v1.id, [vid .. "-preproxy_enabled"] = "1" })
|
||||
end
|
||||
end
|
||||
end
|
||||
else
|
||||
local tips = s:taboption("Main", DummyValue, "tips", " ")
|
||||
tips.rawhtml = true
|
||||
tips.cfgvalue = function(t, n)
|
||||
return string.format('<a style="color: red">%s</a>', translate("There are no available nodes, please add or subscribe nodes first."))
|
||||
end
|
||||
tips:depends({ tcp_node = "nil", ["!reverse"] = true })
|
||||
for k, v in pairs(shunt_list) do
|
||||
tips:depends("udp_node", v.id)
|
||||
end
|
||||
for k, v in pairs(balancing_list) do
|
||||
tips:depends("udp_node", v.id)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
tcp_node_socks_port = s:taboption("Main", Value, "tcp_node_socks_port", translate("TCP Node") .. " Socks " .. translate("Listen Port"))
|
||||
tcp_node_socks_port.default = 1070
|
||||
tcp_node_socks_port.datatype = "port"
|
||||
tcp_node_socks_port:depends({ tcp_node = "nil", ["!reverse"] = true })
|
||||
--[[
|
||||
if has_singbox or has_xray then
|
||||
tcp_node_http_port = s:taboption("Main", Value, "tcp_node_http_port", translate("TCP Node") .. " HTTP " .. translate("Listen Port") .. " " .. translate("0 is not use"))
|
||||
tcp_node_http_port.default = 0
|
||||
tcp_node_http_port.datatype = "port"
|
||||
end
|
||||
]]--
|
||||
|
||||
|
||||
s:tab("DNS", translate("DNS"))
|
||||
|
||||
o = s:taboption("DNS", Flag, "filter_proxy_ipv6", translate("Filter Proxy Host IPv6"), translate("Experimental feature."))
|
||||
o.default = "0"
|
||||
|
||||
---- DNS Forward Mode
|
||||
dns_mode = s:taboption("DNS", ListValue, "dns_mode", translate("Filter Mode"))
|
||||
dns_mode.rmempty = false
|
||||
dns_mode:reset_values()
|
||||
if api.is_finded("dns2tcp") then
|
||||
dns_mode:value("dns2tcp", translatef("Requery DNS By %s", "TCP"))
|
||||
end
|
||||
if api.is_finded("dns2socks") then
|
||||
dns_mode:value("dns2socks", "dns2socks")
|
||||
end
|
||||
if has_singbox then
|
||||
dns_mode:value("sing-box", "Sing-Box")
|
||||
end
|
||||
if has_xray then
|
||||
dns_mode:value("xray", "Xray")
|
||||
end
|
||||
dns_mode:value("udp", translatef("Requery DNS By %s", "UDP"))
|
||||
|
||||
o = s:taboption("DNS", ListValue, "xray_dns_mode", " ")
|
||||
o:value("tcp", "TCP")
|
||||
o:value("tcp+doh", "TCP + DoH (" .. translate("A/AAAA type") .. ")")
|
||||
o:depends("dns_mode", "xray")
|
||||
o.cfgvalue = function(self, section)
|
||||
return m:get(section, "v2ray_dns_mode")
|
||||
end
|
||||
o.write = function(self, section, value)
|
||||
if dns_mode:formvalue(section) == "xray" then
|
||||
return m:set(section, "v2ray_dns_mode", value)
|
||||
end
|
||||
end
|
||||
|
||||
o = s:taboption("DNS", ListValue, "singbox_dns_mode", " ")
|
||||
o:value("tcp", "TCP")
|
||||
o:value("doh", "DoH")
|
||||
o:depends("dns_mode", "sing-box")
|
||||
o.cfgvalue = function(self, section)
|
||||
return m:get(section, "v2ray_dns_mode")
|
||||
end
|
||||
o.write = function(self, section, value)
|
||||
if dns_mode:formvalue(section) == "sing-box" then
|
||||
return m:set(section, "v2ray_dns_mode", value)
|
||||
end
|
||||
end
|
||||
|
||||
o = s:taboption("DNS", Value, "socks_server", translate("Socks Server"), translate("Make sure socks service is available on this address."))
|
||||
for k, v in pairs(socks_table) do o:value(v.id, v.remarks) end
|
||||
o.default = socks_table[1].id
|
||||
o.validate = function(self, value, t)
|
||||
if not datatypes.ipaddrport(value) then
|
||||
return nil, translate("Socks Server") .. " " .. translate("Not valid IP format, please re-enter!")
|
||||
end
|
||||
return value
|
||||
end
|
||||
o:depends({dns_mode = "dns2socks"})
|
||||
|
||||
---- DNS Forward
|
||||
o = s:taboption("DNS", Value, "remote_dns", translate("Remote DNS"))
|
||||
o.datatype = "or(ipaddr,ipaddrport)"
|
||||
o.default = "1.1.1.1"
|
||||
o:value("1.1.1.1", "1.1.1.1 (CloudFlare)")
|
||||
o:value("1.1.1.2", "1.1.1.2 (CloudFlare-Security)")
|
||||
o:value("8.8.4.4", "8.8.4.4 (Google)")
|
||||
o:value("8.8.8.8", "8.8.8.8 (Google)")
|
||||
o:value("9.9.9.9", "9.9.9.9 (Quad9-Recommended)")
|
||||
o:value("208.67.220.220", "208.67.220.220 (OpenDNS)")
|
||||
o:value("208.67.222.222", "208.67.222.222 (OpenDNS)")
|
||||
o:depends({dns_mode = "dns2socks"})
|
||||
o:depends({dns_mode = "dns2tcp"})
|
||||
o:depends({dns_mode = "udp"})
|
||||
o:depends({xray_dns_mode = "tcp"})
|
||||
o:depends({xray_dns_mode = "tcp+doh"})
|
||||
o:depends({singbox_dns_mode = "tcp"})
|
||||
|
||||
---- DoH
|
||||
o = s:taboption("DNS", Value, "remote_dns_doh", translate("Remote DNS DoH"))
|
||||
o.default = "https://1.1.1.1/dns-query"
|
||||
o:value("https://1.1.1.1/dns-query", "CloudFlare")
|
||||
o:value("https://1.1.1.2/dns-query", "CloudFlare-Security")
|
||||
o:value("https://8.8.4.4/dns-query", "Google 8844")
|
||||
o:value("https://8.8.8.8/dns-query", "Google 8888")
|
||||
o:value("https://9.9.9.9/dns-query", "Quad9-Recommended")
|
||||
o:value("https://208.67.222.222/dns-query", "OpenDNS")
|
||||
o:value("https://dns.adguard.com/dns-query,176.103.130.130", "AdGuard")
|
||||
o:value("https://doh.libredns.gr/dns-query,116.202.176.26", "LibreDNS")
|
||||
o:value("https://doh.libredns.gr/ads,116.202.176.26", "LibreDNS (No Ads)")
|
||||
o.validate = doh_validate
|
||||
o:depends({xray_dns_mode = "tcp+doh"})
|
||||
o:depends({singbox_dns_mode = "doh"})
|
||||
|
||||
o = s:taboption("DNS", Value, "dns_client_ip", translate("EDNS Client Subnet"))
|
||||
o.description = translate("Notify the DNS server when the DNS query is notified, the location of the client (cannot be a private IP address).") .. "<br />" ..
|
||||
translate("This feature requires the DNS server to support the Edns Client Subnet (RFC7871).")
|
||||
o.datatype = "ipaddr"
|
||||
o:depends({dns_mode = "xray"})
|
||||
|
||||
o = s:taboption("DNS", Flag, "remote_fakedns", "FakeDNS", translate("Use FakeDNS work in the shunt domain that proxy."))
|
||||
o.default = "0"
|
||||
o:depends({dns_mode = "sing-box"})
|
||||
o.validate = function(self, value, t)
|
||||
if value and value == "1" then
|
||||
local _dns_mode = dns_mode:formvalue(t)
|
||||
local _tcp_node = tcp_node:formvalue(t)
|
||||
if _dns_mode and _tcp_node and _tcp_node ~= "nil" then
|
||||
if m:get(_tcp_node, "type"):lower() ~= _dns_mode then
|
||||
return nil, translatef("TCP node must be '%s' type to use FakeDNS.", _dns_mode)
|
||||
end
|
||||
end
|
||||
end
|
||||
return value
|
||||
end
|
||||
|
||||
o = s:taboption("DNS", Flag, "dns_cache", translate("Cache Resolved"))
|
||||
o.default = "1"
|
||||
o:depends({dns_mode = "dns2socks"})
|
||||
o:depends({dns_mode = "sing-box", remote_fakedns = false})
|
||||
o:depends({dns_mode = "xray"})
|
||||
o.rmempty = false
|
||||
|
||||
if api.is_finded("chinadns-ng") then
|
||||
o = s:taboption("DNS", Flag, "chinadns_ng", translate("ChinaDNS-NG"), translate("The effect is better, but will increase the memory."))
|
||||
o.default = "0"
|
||||
o:depends({dns_mode = "dns2socks"})
|
||||
o:depends({dns_mode = "dns2tcp"})
|
||||
o:depends({dns_mode = "sing-box", remote_fakedns = false})
|
||||
o:depends({dns_mode = "xray"})
|
||||
o:depends({dns_mode = "udp"})
|
||||
end
|
||||
|
||||
if has_chnlist then
|
||||
when_chnroute_default_dns = s:taboption("DNS", ListValue, "when_chnroute_default_dns", translate("When using the chnroute list the default DNS"))
|
||||
when_chnroute_default_dns.default = "direct"
|
||||
when_chnroute_default_dns:value("remote", translate("Remote DNS"))
|
||||
when_chnroute_default_dns:value("direct", translate("Direct DNS"))
|
||||
when_chnroute_default_dns.description = "<ul>"
|
||||
.. "<li>" .. translate("Remote DNS can avoid more DNS leaks, but some domestic domain names maybe to proxy!") .. "</li>"
|
||||
.. "<li>" .. translate("Direct DNS Internet experience may be better, but DNS will be leaked!") .. "</li>"
|
||||
.. "</ul>"
|
||||
if api.is_finded("chinadns-ng") then
|
||||
when_chnroute_default_dns:depends("chinadns_ng", false)
|
||||
end
|
||||
end
|
||||
|
||||
o = s:taboption("DNS", Button, "clear_ipset", translate("Clear IPSET"), translate("Try this feature if the rule modification does not take effect."))
|
||||
o.inputstyle = "remove"
|
||||
function o.write(e, e)
|
||||
luci.sys.call("[ -n \"$(nft list sets 2>/dev/null | grep \"passwall_\")\" ] && sh /usr/share/" .. appname .. "/nftables.sh flush_nftset || sh /usr/share/" .. appname .. "/iptables.sh flush_ipset > /dev/null 2>&1 &")
|
||||
luci.http.redirect(api.url("log"))
|
||||
end
|
||||
|
||||
s:tab("Proxy", translate("Mode"))
|
||||
|
||||
---- TCP Default Proxy Mode
|
||||
tcp_proxy_mode = s:taboption("Proxy", ListValue, "tcp_proxy_mode", "TCP " .. translate("Default Proxy Mode"))
|
||||
tcp_proxy_mode:value("disable", translate("No Proxy"))
|
||||
tcp_proxy_mode:value("global", translate("Global Proxy"))
|
||||
tcp_proxy_mode:value("gfwlist", translate("GFW List"))
|
||||
tcp_proxy_mode:value("chnroute", translate("Not China List"))
|
||||
if has_chnlist then
|
||||
tcp_proxy_mode:value("returnhome", translate("China List"))
|
||||
end
|
||||
tcp_proxy_mode:value("direct/proxy", translate("Only use direct/proxy list"))
|
||||
tcp_proxy_mode.default = "chnroute"
|
||||
--tcp_proxy_mode.validate = redir_mode_validate
|
||||
|
||||
---- UDP Default Proxy Mode
|
||||
udp_proxy_mode = s:taboption("Proxy", ListValue, "udp_proxy_mode", "UDP " .. translate("Default Proxy Mode"))
|
||||
udp_proxy_mode:value("disable", translate("No Proxy"))
|
||||
udp_proxy_mode:value("global", translate("Global Proxy"))
|
||||
udp_proxy_mode:value("gfwlist", translate("GFW List"))
|
||||
udp_proxy_mode:value("chnroute", translate("Not China List"))
|
||||
if has_chnlist then
|
||||
udp_proxy_mode:value("returnhome", translate("China List"))
|
||||
end
|
||||
udp_proxy_mode:value("direct/proxy", translate("Only use direct/proxy list"))
|
||||
udp_proxy_mode.default = "chnroute"
|
||||
--udp_proxy_mode.validate = redir_mode_validate
|
||||
|
||||
---- Localhost TCP Proxy Mode
|
||||
localhost_tcp_proxy_mode = s:taboption("Proxy", ListValue, "localhost_tcp_proxy_mode", translate("Router Localhost") .. " TCP " .. translate("Proxy Mode"))
|
||||
localhost_tcp_proxy_mode:value("default", translatef("Same as the %s default proxy mode", "TCP"))
|
||||
localhost_tcp_proxy_mode:value("global", translate("Global Proxy"))
|
||||
localhost_tcp_proxy_mode:value("gfwlist", translate("GFW List"))
|
||||
localhost_tcp_proxy_mode:value("chnroute", translate("Not China List"))
|
||||
if has_chnlist then
|
||||
localhost_tcp_proxy_mode:value("returnhome", translate("China List"))
|
||||
end
|
||||
localhost_tcp_proxy_mode:value("disable", translate("No Proxy"))
|
||||
localhost_tcp_proxy_mode:value("direct/proxy", translate("Only use direct/proxy list"))
|
||||
localhost_tcp_proxy_mode.default = "default"
|
||||
--localhost_tcp_proxy_mode.validate = redir_mode_validate
|
||||
|
||||
---- Localhost UDP Proxy Mode
|
||||
localhost_udp_proxy_mode = s:taboption("Proxy", ListValue, "localhost_udp_proxy_mode", translate("Router Localhost") .. " UDP " .. translate("Proxy Mode"))
|
||||
localhost_udp_proxy_mode:value("default", translatef("Same as the %s default proxy mode", "UDP"))
|
||||
localhost_udp_proxy_mode:value("global", translate("Global Proxy"))
|
||||
localhost_udp_proxy_mode:value("gfwlist", translate("GFW List"))
|
||||
localhost_udp_proxy_mode:value("chnroute", translate("Not China List"))
|
||||
if has_chnlist then
|
||||
localhost_udp_proxy_mode:value("returnhome", translate("China List"))
|
||||
end
|
||||
localhost_udp_proxy_mode:value("disable", translate("No Proxy"))
|
||||
localhost_udp_proxy_mode:value("direct/proxy", translate("Only use direct/proxy list"))
|
||||
localhost_udp_proxy_mode.default = "default"
|
||||
localhost_udp_proxy_mode.validate = redir_mode_validate
|
||||
|
||||
tips = s:taboption("Proxy", DummyValue, "tips", " ")
|
||||
tips.rawhtml = true
|
||||
tips.cfgvalue = function(t, n)
|
||||
return string.format('<a style="color: red" href="%s">%s</a>', api.url("acl"), translate("Want different devices to use different proxy modes/ports/nodes? Please use access control."))
|
||||
end
|
||||
|
||||
s:tab("log", translate("Log"))
|
||||
o = s:taboption("log", Flag, "close_log_tcp", translatef("%s Node Log Close", "TCP"))
|
||||
o.rmempty = false
|
||||
|
||||
o = s:taboption("log", Flag, "close_log_udp", translatef("%s Node Log Close", "UDP"))
|
||||
o.rmempty = false
|
||||
|
||||
loglevel = s:taboption("log", ListValue, "loglevel", "Sing-Box/Xray " .. translate("Log Level"))
|
||||
loglevel.default = "warning"
|
||||
loglevel:value("debug")
|
||||
loglevel:value("info")
|
||||
loglevel:value("warning")
|
||||
loglevel:value("error")
|
||||
|
||||
trojan_loglevel = s:taboption("log", ListValue, "trojan_loglevel", "Trojan " .. translate("Log Level"))
|
||||
trojan_loglevel.default = "2"
|
||||
trojan_loglevel:value("0", "all")
|
||||
trojan_loglevel:value("1", "info")
|
||||
trojan_loglevel:value("2", "warn")
|
||||
trojan_loglevel:value("3", "error")
|
||||
trojan_loglevel:value("4", "fatal")
|
||||
|
||||
o = s:taboption("log", Flag, "advanced_log_feature", translate("Advanced log feature"), translate("For professionals only."))
|
||||
o.default = "0"
|
||||
o.rmempty = false
|
||||
local syslog = s:taboption("log", Flag, "sys_log", translate("Logging to system log"), translate("Logging to the system log for more advanced functions. For example, send logs to a dedicated log server."))
|
||||
syslog:depends("advanced_log_feature", "1")
|
||||
syslog.default = "0"
|
||||
syslog.rmempty = false
|
||||
local logpath = s:taboption("log", Value, "persist_log_path", translate("Persist log file directory"), translate("The path to the directory used to store persist log files, the \"/\" at the end can be omitted. Leave it blank to disable this feature."))
|
||||
logpath:depends({ ["advanced_log_feature"] = 1, ["sys_log"] = 0 })
|
||||
|
||||
s:tab("faq", "FAQ")
|
||||
|
||||
o = s:taboption("faq", DummyValue, "")
|
||||
o.template = appname .. "/global/faq"
|
||||
|
||||
-- [[ Socks Server ]]--
|
||||
o = s:taboption("Main", Flag, "socks_enabled", "Socks " .. translate("Main switch"))
|
||||
o.rmempty = false
|
||||
|
||||
s = m:section(TypedSection, "socks", translate("Socks Config"))
|
||||
s.template = "cbi/tblsection"
|
||||
s.anonymous = true
|
||||
s.addremove = true
|
||||
s.extedit = api.url("socks_config", "%s")
|
||||
function s.create(e, t)
|
||||
local uuid = api.gen_short_uuid()
|
||||
t = uuid
|
||||
TypedSection.create(e, t)
|
||||
luci.http.redirect(e.extedit:format(t))
|
||||
end
|
||||
|
||||
o = s:option(DummyValue, "status", translate("Status"))
|
||||
o.rawhtml = true
|
||||
o.cfgvalue = function(t, n)
|
||||
return string.format('<div class="_status" socks_id="%s"></div>', n)
|
||||
end
|
||||
|
||||
---- Enable
|
||||
o = s:option(Flag, "enabled", translate("Enable"))
|
||||
o.default = 1
|
||||
o.rmempty = false
|
||||
|
||||
socks_node = s:option(ListValue, "node", translate("Socks Node"))
|
||||
|
||||
local n = 1
|
||||
uci:foreach(appname, "socks", function(s)
|
||||
if s[".name"] == section then
|
||||
return false
|
||||
end
|
||||
n = n + 1
|
||||
end)
|
||||
|
||||
o = s:option(Value, "port", "Socks " .. translate("Listen Port"))
|
||||
o.default = n + 1080
|
||||
o.datatype = "port"
|
||||
o.rmempty = false
|
||||
|
||||
if has_singbox or has_xray then
|
||||
o = s:option(Value, "http_port", "HTTP " .. translate("Listen Port") .. " " .. translate("0 is not use"))
|
||||
o.default = 0
|
||||
o.datatype = "port"
|
||||
end
|
||||
|
||||
for k, v in pairs(nodes_table) do
|
||||
tcp_node:value(v.id, v["remark"])
|
||||
udp_node:value(v.id, v["remark"])
|
||||
if v.type == "Socks" then
|
||||
if has_singbox or has_xray then
|
||||
socks_node:value(v.id, v["remark"])
|
||||
end
|
||||
else
|
||||
socks_node:value(v.id, v["remark"])
|
||||
end
|
||||
end
|
||||
|
||||
m:append(Template(appname .. "/global/footer"))
|
||||
|
||||
return m
|
@ -1,140 +0,0 @@
|
||||
local api = require "luci.passwall.api"
|
||||
local appname = api.appname
|
||||
local sys = api.sys
|
||||
local net = require "luci.model.network".init()
|
||||
local datatypes = api.datatypes
|
||||
|
||||
local nodes_table = {}
|
||||
for k, e in ipairs(api.get_valid_nodes()) do
|
||||
if e.node_type == "normal" then
|
||||
nodes_table[#nodes_table + 1] = {
|
||||
id = e[".name"],
|
||||
obj = e,
|
||||
remarks = e["remark"]
|
||||
}
|
||||
end
|
||||
end
|
||||
|
||||
m = Map(appname)
|
||||
|
||||
-- [[ Haproxy Settings ]]--
|
||||
s = m:section(TypedSection, "global_haproxy")
|
||||
s.anonymous = true
|
||||
|
||||
s:append(Template(appname .. "/haproxy/status"))
|
||||
|
||||
---- Balancing Enable
|
||||
o = s:option(Flag, "balancing_enable", translate("Enable Load Balancing"))
|
||||
o.rmempty = false
|
||||
o.default = false
|
||||
|
||||
---- Console Username
|
||||
o = s:option(Value, "console_user", translate("Console Username"))
|
||||
o.default = ""
|
||||
o:depends("balancing_enable", true)
|
||||
|
||||
---- Console Password
|
||||
o = s:option(Value, "console_password", translate("Console Password"))
|
||||
o.password = true
|
||||
o.default = ""
|
||||
o:depends("balancing_enable", true)
|
||||
|
||||
---- Console Port
|
||||
o = s:option(Value, "console_port", translate("Console Port"), translate(
|
||||
"In the browser input routing IP plus port access, such as:192.168.1.1:1188"))
|
||||
o.default = "1188"
|
||||
o:depends("balancing_enable", true)
|
||||
|
||||
---- Health Check Type
|
||||
o = s:option(ListValue, "health_check_type", translate("Health Check Type"))
|
||||
o.default = "passwall_logic"
|
||||
o:value("tcp", "TCP")
|
||||
o:value("passwall_logic", translate("Availability test") .. string.format("(passwall %s)", translate("Inner implement")))
|
||||
o:depends("balancing_enable", true)
|
||||
|
||||
---- Health Check Inter
|
||||
o = s:option(Value, "health_check_inter", translate("Health Check Inter"), translate("Units:seconds"))
|
||||
o.default = "60"
|
||||
o:depends("balancing_enable", true)
|
||||
|
||||
o = s:option(DummyValue, "health_check_tips", " ")
|
||||
o.rawhtml = true
|
||||
o.cfgvalue = function(t, n)
|
||||
return string.format('<span style="color: red">%s</span>', translate("When the availability test is used, the load balancing node will be converted into a Socks node. when node list set customizing, must be a Socks node, otherwise the health check will be invalid."))
|
||||
end
|
||||
o:depends("health_check_type", "passwall_logic")
|
||||
|
||||
-- [[ Balancing Settings ]]--
|
||||
s = m:section(TypedSection, "haproxy_config", "",
|
||||
"<font color='red'>" ..
|
||||
translate("Add a node, Export Of Multi WAN Only support Multi Wan. Load specific gravity range 1-256. Multiple primary servers can be load balanced, standby will only be enabled when the primary server is offline! Multiple groups can be set, Haproxy port same one for each group.") ..
|
||||
"\n" .. translate("Note that the node configuration parameters for load balancing must be consistent when use TCP health check type, otherwise it cannot be used normally!") ..
|
||||
"</font>")
|
||||
s.template = "cbi/tblsection"
|
||||
s.sortable = true
|
||||
s.anonymous = true
|
||||
s.addremove = true
|
||||
|
||||
s.create = function(e, t)
|
||||
TypedSection.create(e, api.gen_short_uuid())
|
||||
end
|
||||
|
||||
s.remove = function(self, section)
|
||||
for k, v in pairs(self.children) do
|
||||
v.rmempty = true
|
||||
v.validate = nil
|
||||
end
|
||||
TypedSection.remove(self, section)
|
||||
end
|
||||
|
||||
---- Enable
|
||||
o = s:option(Flag, "enabled", translate("Enable"))
|
||||
o.default = 1
|
||||
o.rmempty = false
|
||||
|
||||
---- Node Address
|
||||
o = s:option(Value, "lbss", translate("Node Address"))
|
||||
for k, v in pairs(nodes_table) do o:value(v.id, v.remarks) end
|
||||
o.rmempty = false
|
||||
o.validate = function(self, value)
|
||||
if not value then return nil end
|
||||
local t = m:get(value) or nil
|
||||
if t and t[".type"] == "nodes" then
|
||||
return value
|
||||
end
|
||||
if datatypes.hostport(value) or datatypes.ip4addrport(value) then
|
||||
return value
|
||||
end
|
||||
if api.is_ipv6addrport(value) then
|
||||
return value
|
||||
end
|
||||
return nil, value
|
||||
end
|
||||
|
||||
---- Haproxy Port
|
||||
o = s:option(Value, "haproxy_port", translate("Haproxy Port"))
|
||||
o.datatype = "port"
|
||||
o.default = 1181
|
||||
o.rmempty = false
|
||||
|
||||
---- Node Weight
|
||||
o = s:option(Value, "lbweight", translate("Node Weight"))
|
||||
o.datatype = "uinteger"
|
||||
o.default = 5
|
||||
o.rmempty = false
|
||||
|
||||
---- Export
|
||||
o = s:option(ListValue, "export", translate("Export Of Multi WAN"))
|
||||
o:value(0, translate("Auto"))
|
||||
local wa = require "luci.tools.webadmin"
|
||||
wa.cbi_add_networks(o)
|
||||
o.default = 0
|
||||
o.rmempty = false
|
||||
|
||||
---- Mode
|
||||
o = s:option(ListValue, "backup", translate("Mode"))
|
||||
o:value(0, translate("Primary"))
|
||||
o:value(1, translate("Standby"))
|
||||
o.rmempty = false
|
||||
|
||||
return m
|
@ -1,8 +0,0 @@
|
||||
local api = require "luci.passwall.api"
|
||||
local appname = api.appname
|
||||
|
||||
f = SimpleForm(appname)
|
||||
f.reset = false
|
||||
f.submit = false
|
||||
f:append(Template(appname .. "/log/log"))
|
||||
return f
|
@ -1,82 +0,0 @@
|
||||
local api = require "luci.passwall.api"
|
||||
local appname = api.appname
|
||||
local uci = api.uci
|
||||
local fs = require "nixio.fs"
|
||||
local types_dir = "/usr/lib/lua/luci/model/cbi/passwall/client/type/"
|
||||
|
||||
if not arg[1] or not uci:get(appname, arg[1]) then
|
||||
luci.http.redirect(api.url("node_list"))
|
||||
end
|
||||
|
||||
m = Map(appname, translate("Node Config"))
|
||||
m.redirect = api.url()
|
||||
|
||||
s = m:section(NamedSection, arg[1], "nodes", "")
|
||||
s.addremove = false
|
||||
s.dynamic = false
|
||||
|
||||
o = s:option(DummyValue, "passwall", " ")
|
||||
o.rawhtml = true
|
||||
o.template = "passwall/node_list/link_share_man"
|
||||
o.value = arg[1]
|
||||
|
||||
o = s:option(Value, "remarks", translate("Node Remarks"))
|
||||
o.default = translate("Remarks")
|
||||
o.rmempty = false
|
||||
|
||||
o = s:option(ListValue, "type", translate("Type"))
|
||||
|
||||
if api.is_finded("ipt2socks") then
|
||||
s.fields["type"]:value("Socks", translate("Socks"))
|
||||
|
||||
o = s:option(Value, "socks_address", translate("Address (Support Domain Name)"))
|
||||
o:depends("type", "Socks")
|
||||
function o.cfgvalue(self, section)
|
||||
return m:get(section, "address")
|
||||
end
|
||||
function o.write(self, section, value)
|
||||
m:set(section, "address", value)
|
||||
end
|
||||
|
||||
o = s:option(Value, "socks_port", translate("Port"))
|
||||
o.datatype = "port"
|
||||
o:depends("type", "Socks")
|
||||
function o.cfgvalue(self, section)
|
||||
return m:get(section, "port")
|
||||
end
|
||||
function o.write(self, section, value)
|
||||
m:set(section, "port", value)
|
||||
end
|
||||
|
||||
o = s:option(Value, "socks_username", translate("Username"))
|
||||
o:depends("type", "Socks")
|
||||
function o.cfgvalue(self, section)
|
||||
return m:get(section, "username")
|
||||
end
|
||||
function o.write(self, section, value)
|
||||
m:set(section, "username", value)
|
||||
end
|
||||
|
||||
o = s:option(Value, "socks_password", translate("Password"))
|
||||
o.password = true
|
||||
o:depends("type", "Socks")
|
||||
function o.cfgvalue(self, section)
|
||||
return m:get(section, "password")
|
||||
end
|
||||
function o.write(self, section, value)
|
||||
m:set(section, "password", value)
|
||||
end
|
||||
end
|
||||
|
||||
local type_table = {}
|
||||
for filename in fs.dir(types_dir) do
|
||||
table.insert(type_table, filename)
|
||||
end
|
||||
table.sort(type_table)
|
||||
|
||||
for index, value in ipairs(type_table) do
|
||||
local p_func = loadfile(types_dir .. value)
|
||||
setfenv(p_func, getfenv(1))(m, s)
|
||||
end
|
||||
|
||||
return m
|
@ -1,151 +0,0 @@
|
||||
local api = require "luci.passwall.api"
|
||||
local appname = api.appname
|
||||
local sys = api.sys
|
||||
local datatypes = api.datatypes
|
||||
|
||||
m = Map(appname)
|
||||
|
||||
-- [[ Other Settings ]]--
|
||||
s = m:section(TypedSection, "global_other")
|
||||
s.anonymous = true
|
||||
|
||||
o = s:option(MultiValue, "nodes_ping", " ")
|
||||
o:value("auto_ping", translate("Auto Ping"), translate("This will automatically ping the node for latency"))
|
||||
o:value("tcping", translate("Tcping"), translate("This will use tcping replace ping detection of node"))
|
||||
o:value("info", translate("Show server address and port"), translate("Show server address and port"))
|
||||
|
||||
-- [[ Add the node via the link ]]--
|
||||
s:append(Template(appname .. "/node_list/link_add_node"))
|
||||
|
||||
local nodes_ping = m:get("@global_other[0]", "nodes_ping") or ""
|
||||
|
||||
-- [[ Node List ]]--
|
||||
s = m:section(TypedSection, "nodes")
|
||||
s.anonymous = true
|
||||
s.addremove = true
|
||||
s.template = "cbi/tblsection"
|
||||
s.extedit = api.url("node_config", "%s")
|
||||
function s.create(e, t)
|
||||
local uuid = api.gen_short_uuid()
|
||||
t = uuid
|
||||
TypedSection.create(e, t)
|
||||
luci.http.redirect(e.extedit:format(t))
|
||||
end
|
||||
|
||||
function s.remove(e, t)
|
||||
m.uci:foreach(appname, "socks", function(s)
|
||||
if s["node"] == t then
|
||||
m:del(s[".name"])
|
||||
end
|
||||
for k, v in ipairs(m:get(s[".name"], "autoswitch_backup_node") or {}) do
|
||||
if v and v == t then
|
||||
sys.call(string.format("uci -q del_list %s.%s.autoswitch_backup_node='%s'", appname, s[".name"], v))
|
||||
end
|
||||
end
|
||||
end)
|
||||
m.uci:foreach(appname, "haproxy_config", function(s)
|
||||
if s["lbss"] and s["lbss"] == t then
|
||||
m:del(s[".name"])
|
||||
end
|
||||
end)
|
||||
m.uci:foreach(appname, "acl_rule", function(s)
|
||||
if s["tcp_node"] and s["tcp_node"] == t then
|
||||
m:set(s[".name"], "tcp_node", "default")
|
||||
end
|
||||
if s["udp_node"] and s["udp_node"] == t then
|
||||
m:set(s[".name"], "udp_node", "default")
|
||||
end
|
||||
end)
|
||||
TypedSection.remove(e, t)
|
||||
local new_node = "nil"
|
||||
local node0 = m:get("@nodes[0]") or nil
|
||||
if node0 then
|
||||
new_node = node0[".name"]
|
||||
end
|
||||
if (m:get("@global[0]", "tcp_node") or "nil") == t then
|
||||
m:set('@global[0]', "tcp_node", new_node)
|
||||
end
|
||||
if (m:get("@global[0]", "udp_node") or "nil") == t then
|
||||
m:set('@global[0]', "udp_node", new_node)
|
||||
end
|
||||
end
|
||||
|
||||
s.sortable = true
|
||||
-- 简洁模式
|
||||
o = s:option(DummyValue, "add_from", "")
|
||||
o.cfgvalue = function(t, n)
|
||||
local v = Value.cfgvalue(t, n)
|
||||
if v and v ~= '' then
|
||||
local group = m:get(n, "group") or ""
|
||||
if group ~= "" then
|
||||
v = v .. " " .. group
|
||||
end
|
||||
return v
|
||||
else
|
||||
return ''
|
||||
end
|
||||
end
|
||||
o = s:option(DummyValue, "remarks", translate("Remarks"))
|
||||
o.rawhtml = true
|
||||
o.cfgvalue = function(t, n)
|
||||
local str = ""
|
||||
local is_sub = m:get(n, "is_sub") or ""
|
||||
local group = m:get(n, "group") or ""
|
||||
local remarks = m:get(n, "remarks") or ""
|
||||
local type = m:get(n, "type") or ""
|
||||
str = str .. string.format("<input type='hidden' id='cbid.%s.%s.type' value='%s'/>", appname, n, type)
|
||||
if type == "sing-box" or type == "Xray" then
|
||||
local protocol = m:get(n, "protocol")
|
||||
if protocol == "_balancing" then
|
||||
protocol = translate("Balancing")
|
||||
elseif protocol == "_shunt" then
|
||||
protocol = translate("Shunt")
|
||||
elseif protocol == "vmess" then
|
||||
protocol = "VMess"
|
||||
elseif protocol == "vless" then
|
||||
protocol = "VLESS"
|
||||
else
|
||||
protocol = protocol:gsub("^%l",string.upper)
|
||||
end
|
||||
type = type .. " " .. protocol
|
||||
end
|
||||
local address = m:get(n, "address") or ""
|
||||
local port = m:get(n, "port") or ""
|
||||
str = str .. translate(type) .. ":" .. remarks
|
||||
if address ~= "" and port ~= "" then
|
||||
if nodes_ping:find("info") then
|
||||
if datatypes.ip6addr(address) then
|
||||
str = str .. string.format("([%s]:%s)", address, port)
|
||||
else
|
||||
str = str .. string.format("(%s:%s)", address, port)
|
||||
end
|
||||
end
|
||||
str = str .. string.format("<input type='hidden' id='cbid.%s.%s.address' value='%s'/>", appname, n, address)
|
||||
str = str .. string.format("<input type='hidden' id='cbid.%s.%s.port' value='%s'/>", appname, n, port)
|
||||
end
|
||||
return str
|
||||
end
|
||||
|
||||
---- Ping
|
||||
o = s:option(DummyValue, "ping")
|
||||
o.width = "8%"
|
||||
o.rawhtml = true
|
||||
o.cfgvalue = function(t, n)
|
||||
local result = "---"
|
||||
if not nodes_ping:find("auto_ping") then
|
||||
result = string.format('<span class="ping"><a href="javascript:void(0)" onclick="javascript:ping_node(\'%s\',this)">Ping</a></span>', n)
|
||||
else
|
||||
result = string.format('<span class="ping_value" cbiid="%s">---</span>', n)
|
||||
end
|
||||
return result
|
||||
end
|
||||
|
||||
o = s:option(DummyValue, "_url_test")
|
||||
o.rawhtml = true
|
||||
o.cfgvalue = function(t, n)
|
||||
return string.format('<input type="button" class="cbi-button" value="%s" onclick="javascript:urltest_node(\'%s\',this)"', translate("Availability test"), n)
|
||||
end
|
||||
|
||||
m:append(Template(appname .. "/node_list/node_list"))
|
||||
|
||||
return m
|
@ -1,137 +0,0 @@
|
||||
local api = require "luci.passwall.api"
|
||||
local appname = api.appname
|
||||
local has_ss = api.is_finded("ss-redir")
|
||||
local has_ss_rust = api.is_finded("sslocal")
|
||||
local has_trojan_plus = api.is_finded("trojan-plus")
|
||||
local has_singbox = api.finded_com("singbox")
|
||||
local has_xray = api.finded_com("xray")
|
||||
local has_trojan_go = api.finded_com("trojan-go")
|
||||
local ss_aead_type = {}
|
||||
local trojan_type = {}
|
||||
if has_ss then
|
||||
ss_aead_type[#ss_aead_type + 1] = "shadowsocks-libev"
|
||||
end
|
||||
if has_ss_rust then
|
||||
ss_aead_type[#ss_aead_type + 1] = "shadowsocks-rust"
|
||||
end
|
||||
if has_trojan_plus then
|
||||
trojan_type[#trojan_type + 1] = "trojan-plus"
|
||||
end
|
||||
if has_singbox then
|
||||
trojan_type[#trojan_type + 1] = "sing-box"
|
||||
ss_aead_type[#ss_aead_type + 1] = "sing-box"
|
||||
end
|
||||
if has_xray then
|
||||
trojan_type[#trojan_type + 1] = "xray"
|
||||
ss_aead_type[#ss_aead_type + 1] = "xray"
|
||||
end
|
||||
if has_trojan_go then
|
||||
trojan_type[#trojan_type + 1] = "trojan-go"
|
||||
end
|
||||
|
||||
m = Map(appname)
|
||||
|
||||
-- [[ Subscribe Settings ]]--
|
||||
s = m:section(TypedSection, "global_subscribe", "")
|
||||
s.anonymous = true
|
||||
|
||||
o = s:option(ListValue, "filter_keyword_mode", translate("Filter keyword Mode"))
|
||||
o:value("0", translate("Close"))
|
||||
o:value("1", translate("Discard List"))
|
||||
o:value("2", translate("Keep List"))
|
||||
o:value("3", translate("Discard List,But Keep List First"))
|
||||
o:value("4", translate("Keep List,But Discard List First"))
|
||||
|
||||
o = s:option(DynamicList, "filter_discard_list", translate("Discard List"))
|
||||
|
||||
o = s:option(DynamicList, "filter_keep_list", translate("Keep List"))
|
||||
|
||||
if #ss_aead_type > 0 then
|
||||
o = s:option(ListValue, "ss_aead_type", translate("SS AEAD Node Use Type"))
|
||||
for key, value in pairs(ss_aead_type) do
|
||||
o:value(value, translate(value:gsub("^%l",string.upper)))
|
||||
end
|
||||
end
|
||||
|
||||
if #trojan_type > 0 then
|
||||
o = s:option(ListValue, "trojan_type", translate("Trojan Node Use Type"))
|
||||
for key, value in pairs(trojan_type) do
|
||||
o:value(value, translate(value:gsub("^%l",string.upper)))
|
||||
end
|
||||
end
|
||||
|
||||
---- Subscribe Delete All
|
||||
o = s:option(Button, "_stop", translate("Delete All Subscribe Node"))
|
||||
o.inputstyle = "remove"
|
||||
function o.write(e, e)
|
||||
luci.sys.call("lua /usr/share/" .. appname .. "/subscribe.lua truncate > /dev/null 2>&1")
|
||||
end
|
||||
|
||||
o = s:option(Button, "_update", translate("Manual subscription All"))
|
||||
o.inputstyle = "apply"
|
||||
function o.write(t, n)
|
||||
luci.sys.call("lua /usr/share/" .. appname .. "/subscribe.lua start > /dev/null 2>&1 &")
|
||||
luci.http.redirect(api.url("log"))
|
||||
end
|
||||
|
||||
s = m:section(TypedSection, "subscribe_list", "", "<font color='red'>" .. translate("Please input the subscription url first, save and submit before manual subscription.") .. "</font>")
|
||||
s.addremove = true
|
||||
s.anonymous = true
|
||||
s.sortable = true
|
||||
s.template = "cbi/tblsection"
|
||||
s.extedit = api.url("node_subscribe_config", "%s")
|
||||
function s.create(e, t)
|
||||
local id = TypedSection.create(e, t)
|
||||
luci.http.redirect(e.extedit:format(id))
|
||||
end
|
||||
|
||||
o = s:option(Value, "remark", translate("Remarks"))
|
||||
o.width = "auto"
|
||||
o.rmempty = false
|
||||
o.validate = function(self, value, t)
|
||||
if value then
|
||||
local count = 0
|
||||
m.uci:foreach(appname, "subscribe_list", function(e)
|
||||
if e[".name"] ~= t and e["remark"] == value then
|
||||
count = count + 1
|
||||
end
|
||||
end)
|
||||
if count > 0 then
|
||||
return nil, translate("This remark already exists, please change a new remark.")
|
||||
end
|
||||
return value
|
||||
end
|
||||
end
|
||||
|
||||
o = s:option(DummyValue, "_node_count")
|
||||
o.rawhtml = true
|
||||
o.cfgvalue = function(t, n)
|
||||
local remark = m:get(n, "remark") or ""
|
||||
local num = 0
|
||||
m.uci:foreach(appname, "nodes", function(s)
|
||||
if s["add_from"] ~= "" and s["add_from"] == remark then
|
||||
num = num + 1
|
||||
end
|
||||
end)
|
||||
return string.format("<span title='%s' style='color:red'>%s</span>", remark .. " " .. translate("Node num") .. ": " .. num, num)
|
||||
end
|
||||
|
||||
o = s:option(Value, "url", translate("Subscribe URL"))
|
||||
o.width = "auto"
|
||||
o.rmempty = false
|
||||
|
||||
o = s:option(Button, "_remove", translate("Delete the subscribed node"))
|
||||
o.inputstyle = "remove"
|
||||
function o.write(t, n)
|
||||
local remark = m:get(n, "remark") or ""
|
||||
luci.sys.call("lua /usr/share/" .. appname .. "/subscribe.lua truncate " .. remark .. " > /dev/null 2>&1")
|
||||
end
|
||||
|
||||
o = s:option(Button, "_update", translate("Manual subscription"))
|
||||
o.inputstyle = "apply"
|
||||
function o.write(t, n)
|
||||
luci.sys.call("lua /usr/share/" .. appname .. "/subscribe.lua start " .. n .. " > /dev/null 2>&1 &")
|
||||
luci.http.redirect(api.url("log"))
|
||||
end
|
||||
|
||||
return m
|
@ -1,110 +0,0 @@
|
||||
local api = require "luci.passwall.api"
|
||||
local appname = api.appname
|
||||
local sys = api.sys
|
||||
local has_ss = api.is_finded("ss-redir")
|
||||
local has_ss_rust = api.is_finded("sslocal")
|
||||
local has_trojan_plus = api.is_finded("trojan-plus")
|
||||
local has_singbox = api.finded_com("singbox")
|
||||
local has_xray = api.finded_com("xray")
|
||||
local has_trojan_go = api.finded_com("trojan-go")
|
||||
local ss_aead_type = {}
|
||||
local trojan_type = {}
|
||||
if has_ss then
|
||||
ss_aead_type[#ss_aead_type + 1] = "shadowsocks-libev"
|
||||
end
|
||||
if has_ss_rust then
|
||||
ss_aead_type[#ss_aead_type + 1] = "shadowsocks-rust"
|
||||
end
|
||||
if has_trojan_plus then
|
||||
trojan_type[#trojan_type + 1] = "trojan-plus"
|
||||
end
|
||||
if has_singbox then
|
||||
trojan_type[#trojan_type + 1] = "sing-box"
|
||||
ss_aead_type[#ss_aead_type + 1] = "sing-box"
|
||||
end
|
||||
if has_xray then
|
||||
trojan_type[#trojan_type + 1] = "xray"
|
||||
ss_aead_type[#ss_aead_type + 1] = "xray"
|
||||
end
|
||||
if has_trojan_go then
|
||||
trojan_type[#trojan_type + 1] = "trojan-go"
|
||||
end
|
||||
|
||||
m = Map(appname)
|
||||
m.redirect = api.url("node_subscribe")
|
||||
|
||||
s = m:section(NamedSection, arg[1])
|
||||
s.addremove = false
|
||||
s.dynamic = false
|
||||
|
||||
o = s:option(Value, "remark", translate("Subscribe Remark"))
|
||||
o.rmempty = false
|
||||
|
||||
o = s:option(TextValue, "url", translate("Subscribe URL"))
|
||||
o.rows = 5
|
||||
o.rmempty = false
|
||||
|
||||
o = s:option(Flag, "allowInsecure", translate("allowInsecure"), translate("Whether unsafe connections are allowed. When checked, Certificate validation will be skipped."))
|
||||
o.default = "0"
|
||||
o.rmempty = false
|
||||
|
||||
o = s:option(ListValue, "filter_keyword_mode", translate("Filter keyword Mode"))
|
||||
o.default = "5"
|
||||
o:value("0", translate("Close"))
|
||||
o:value("1", translate("Discard List"))
|
||||
o:value("2", translate("Keep List"))
|
||||
o:value("3", translate("Discard List,But Keep List First"))
|
||||
o:value("4", translate("Keep List,But Discard List First"))
|
||||
o:value("5", translate("Use global config"))
|
||||
|
||||
o = s:option(DynamicList, "filter_discard_list", translate("Discard List"))
|
||||
o:depends("filter_keyword_mode", "1")
|
||||
o:depends("filter_keyword_mode", "3")
|
||||
o:depends("filter_keyword_mode", "4")
|
||||
|
||||
o = s:option(DynamicList, "filter_keep_list", translate("Keep List"))
|
||||
o:depends("filter_keyword_mode", "2")
|
||||
o:depends("filter_keyword_mode", "3")
|
||||
o:depends("filter_keyword_mode", "4")
|
||||
|
||||
if #ss_aead_type > 0 then
|
||||
o = s:option(ListValue, "ss_aead_type", translate("SS AEAD Node Use Type"))
|
||||
o.default = "global"
|
||||
o:value("global", translate("Use global config"))
|
||||
for key, value in pairs(ss_aead_type) do
|
||||
o:value(value, translate(value:gsub("^%l",string.upper)))
|
||||
end
|
||||
end
|
||||
|
||||
if #trojan_type > 0 then
|
||||
o = s:option(ListValue, "trojan_type", translate("Trojan Node Use Type"))
|
||||
o.default = "global"
|
||||
o:value("global", translate("Use global config"))
|
||||
for key, value in pairs(trojan_type) do
|
||||
o:value(value, translate(value:gsub("^%l",string.upper)))
|
||||
end
|
||||
end
|
||||
|
||||
---- Enable auto update subscribe
|
||||
o = s:option(Flag, "auto_update", translate("Enable auto update subscribe"))
|
||||
o.default = 0
|
||||
o.rmempty = false
|
||||
|
||||
---- Week update rules
|
||||
o = s:option(ListValue, "week_update", translate("Week update rules"))
|
||||
o:value(7, translate("Every day"))
|
||||
for e = 1, 6 do o:value(e, translate("Week") .. e) end
|
||||
o:value(0, translate("Week") .. translate("day"))
|
||||
o.default = 0
|
||||
o:depends("auto_update", true)
|
||||
|
||||
---- Day update rules
|
||||
o = s:option(ListValue, "time_update", translate("Day update rules"))
|
||||
for e = 0, 23 do o:value(e, e .. translate("oclock")) end
|
||||
o.default = 0
|
||||
o:depends("auto_update", true)
|
||||
|
||||
o = s:option(Value, "user_agent", translate("User-Agent"))
|
||||
o.default = "Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/80.0.3987.122 Safari/537.36"
|
||||
|
||||
return m
|
@ -1,204 +0,0 @@
|
||||
local api = require "luci.passwall.api"
|
||||
local appname = api.appname
|
||||
local fs = api.fs
|
||||
local has_singbox = api.finded_com("singbox")
|
||||
local has_xray = api.finded_com("xray")
|
||||
local has_fw3 = api.is_finded("fw3")
|
||||
local has_fw4 = api.is_finded("fw4")
|
||||
|
||||
m = Map(appname)
|
||||
|
||||
-- [[ Delay Settings ]]--
|
||||
s = m:section(TypedSection, "global_delay", translate("Delay Settings"))
|
||||
s.anonymous = true
|
||||
s.addremove = false
|
||||
|
||||
---- Delay Start
|
||||
o = s:option(Value, "start_delay", translate("Delay Start"),
|
||||
translate("Units:seconds"))
|
||||
o.default = "1"
|
||||
o.rmempty = true
|
||||
|
||||
---- Open and close Daemon
|
||||
o = s:option(Flag, "start_daemon", translate("Open and close Daemon"))
|
||||
o.default = 1
|
||||
o.rmempty = false
|
||||
|
||||
--[[
|
||||
---- Open and close automatically
|
||||
o = s:option(Flag, "auto_on", translate("Open and close automatically"))
|
||||
o.default = 0
|
||||
o.rmempty = false
|
||||
|
||||
---- Automatically turn off time
|
||||
o = s:option(ListValue, "time_off", translate("Automatically turn off time"))
|
||||
o.default = nil
|
||||
o:depends("auto_on", true)
|
||||
o:value(nil, translate("Disable"))
|
||||
for e = 0, 23 do o:value(e, e .. translate("oclock")) end
|
||||
|
||||
---- Automatically turn on time
|
||||
o = s:option(ListValue, "time_on", translate("Automatically turn on time"))
|
||||
o.default = nil
|
||||
o:depends("auto_on", true)
|
||||
o:value(nil, translate("Disable"))
|
||||
for e = 0, 23 do o:value(e, e .. translate("oclock")) end
|
||||
|
||||
---- Automatically restart time
|
||||
o = s:option(ListValue, "time_restart", translate("Automatically restart time"))
|
||||
o.default = nil
|
||||
o:depends("auto_on", true)
|
||||
o:value(nil, translate("Disable"))
|
||||
for e = 0, 23 do o:value(e, e .. translate("oclock")) end
|
||||
--]]
|
||||
|
||||
-- [[ Forwarding Settings ]]--
|
||||
s = m:section(TypedSection, "global_forwarding",
|
||||
translate("Forwarding Settings"))
|
||||
s.anonymous = true
|
||||
s.addremove = false
|
||||
|
||||
---- TCP No Redir Ports
|
||||
o = s:option(Value, "tcp_no_redir_ports", translate("TCP No Redir Ports"))
|
||||
o.default = "disable"
|
||||
o:value("disable", translate("No patterns are used"))
|
||||
o:value("1:65535", translate("All"))
|
||||
|
||||
---- UDP No Redir Ports
|
||||
o = s:option(Value, "udp_no_redir_ports", translate("UDP No Redir Ports"),
|
||||
"<font color='red'>" .. translate(
|
||||
"Fill in the ports you don't want to be forwarded by the agent, with the highest priority.") ..
|
||||
"</font>")
|
||||
o.default = "disable"
|
||||
o:value("disable", translate("No patterns are used"))
|
||||
o:value("1:65535", translate("All"))
|
||||
|
||||
---- TCP Proxy Drop Ports
|
||||
o = s:option(Value, "tcp_proxy_drop_ports", translate("TCP Proxy Drop Ports"))
|
||||
o.default = "disable"
|
||||
o:value("disable", translate("No patterns are used"))
|
||||
|
||||
---- UDP Proxy Drop Ports
|
||||
o = s:option(Value, "udp_proxy_drop_ports", translate("UDP Proxy Drop Ports"))
|
||||
o.default = "443"
|
||||
o:value("disable", translate("No patterns are used"))
|
||||
o:value("443", translate("QUIC"))
|
||||
|
||||
---- TCP Redir Ports
|
||||
o = s:option(Value, "tcp_redir_ports", translate("TCP Redir Ports"))
|
||||
o.default = "22,25,53,143,465,587,853,993,995,80,443"
|
||||
o:value("1:65535", translate("All"))
|
||||
o:value("22,25,53,143,465,587,853,993,995,80,443", translate("Common Use"))
|
||||
o:value("80,443", translate("Only Web"))
|
||||
|
||||
---- UDP Redir Ports
|
||||
o = s:option(Value, "udp_redir_ports", translate("UDP Redir Ports"))
|
||||
o.default = "1:65535"
|
||||
o:value("1:65535", translate("All"))
|
||||
o:value("53", "DNS")
|
||||
|
||||
---- Use nftables
|
||||
o = s:option(ListValue, "use_nft", translate("Firewall tools"))
|
||||
o.default = "0"
|
||||
if has_fw3 then
|
||||
o:value("0", "IPtables")
|
||||
end
|
||||
if has_fw4 then
|
||||
o:value("1", "NFtables")
|
||||
end
|
||||
|
||||
if (os.execute("lsmod | grep -i REDIRECT >/dev/null") == 0 and os.execute("lsmod | grep -i TPROXY >/dev/null") == 0) or (os.execute("lsmod | grep -i nft_redir >/dev/null") == 0 and os.execute("lsmod | grep -i nft_tproxy >/dev/null") == 0) then
|
||||
o = s:option(ListValue, "tcp_proxy_way", translate("TCP Proxy Way"))
|
||||
o.default = "redirect"
|
||||
o:value("redirect", "REDIRECT")
|
||||
o:value("tproxy", "TPROXY")
|
||||
o:depends("ipv6_tproxy", false)
|
||||
|
||||
o = s:option(ListValue, "_tcp_proxy_way", translate("TCP Proxy Way"))
|
||||
o.default = "tproxy"
|
||||
o:value("tproxy", "TPROXY")
|
||||
o:depends("ipv6_tproxy", true)
|
||||
o.write = function(self, section, value)
|
||||
return self.map:set(section, "tcp_proxy_way", value)
|
||||
end
|
||||
|
||||
if os.execute("lsmod | grep -i ip6table_mangle >/dev/null") == 0 or os.execute("lsmod | grep -i nft_tproxy >/dev/null") == 0 then
|
||||
---- IPv6 TProxy
|
||||
o = s:option(Flag, "ipv6_tproxy", translate("IPv6 TProxy"),
|
||||
"<font color='red'>" .. translate(
|
||||
"Experimental feature. Make sure that your node supports IPv6.") ..
|
||||
"</font>")
|
||||
o.default = 0
|
||||
o.rmempty = false
|
||||
end
|
||||
end
|
||||
|
||||
o = s:option(Flag, "accept_icmp", translate("Hijacking ICMP (PING)"))
|
||||
o.default = 0
|
||||
|
||||
o = s:option(Flag, "accept_icmpv6", translate("Hijacking ICMPv6 (IPv6 PING)"))
|
||||
o:depends("ipv6_tproxy", true)
|
||||
o.default = 0
|
||||
|
||||
if has_xray then
|
||||
s_xray = m:section(TypedSection, "global_xray", "Xray " .. translate("Settings"))
|
||||
s_xray.anonymous = true
|
||||
s_xray.addremove = false
|
||||
|
||||
o = s_xray:option(Flag, "sniffing", translate("Sniffing"), translate("When using the shunt, must be enabled, otherwise the shunt will invalid."))
|
||||
o.default = 1
|
||||
o.rmempty = false
|
||||
|
||||
if has_xray then
|
||||
o = s_xray:option(Flag, "route_only", translate("Sniffing Route Only"))
|
||||
o.default = 0
|
||||
o:depends("sniffing", true)
|
||||
|
||||
local domains_excluded = string.format("/usr/share/%s/rules/domains_excluded", appname)
|
||||
o = s_xray:option(TextValue, "no_sniffing_hosts", translate("No Sniffing Lists"), translate("Hosts added into No Sniffing Lists will not resolve again on server."))
|
||||
o.rows = 15
|
||||
o.wrap = "off"
|
||||
o.cfgvalue = function(self, section) return fs.readfile(domains_excluded) or "" end
|
||||
o.write = function(self, section, value) fs.writefile(domains_excluded, value:gsub("\r\n", "\n")) end
|
||||
o.remove = function(self, section)
|
||||
local route_only_value = s_xray.fields["route_only"]:formvalue(section)
|
||||
if not route_only_value or route_only_value == "0" then
|
||||
fs.writefile(domains_excluded, "")
|
||||
end
|
||||
end
|
||||
o:depends({sniffing = true, route_only = false})
|
||||
|
||||
o = s_xray:option(Value, "buffer_size", translate("Buffer Size"), translate("Buffer size for every connection (kB)"))
|
||||
o.datatype = "uinteger"
|
||||
end
|
||||
end
|
||||
|
||||
if has_singbox then
|
||||
s = m:section(TypedSection, "global_singbox", "Sing-Box " .. translate("Settings"))
|
||||
s.anonymous = true
|
||||
s.addremove = false
|
||||
|
||||
o = s:option(Flag, "sniff_override_destination", translate("Override the connection destination address"), translate("Override the connection destination address with the sniffed domain."))
|
||||
o.default = 1
|
||||
o.rmempty = false
|
||||
|
||||
o = s:option(Value, "geoip_path", translate("Custom geoip Path"))
|
||||
o.default = "/usr/share/singbox/geoip.db"
|
||||
o.rmempty = false
|
||||
|
||||
o = s:option(Value, "geoip_url", translate("Custom geoip URL"))
|
||||
o.default = "https://github.com/SagerNet/sing-geoip/releases/latest/download/geoip.db"
|
||||
o:value("https://github.com/SagerNet/sing-geoip/releases/latest/download/geoip.db")
|
||||
o.rmempty = false
|
||||
|
||||
o = s:option(Value, "geosite_path", translate("Custom geosite Path"))
|
||||
o.default = "/usr/share/singbox/geosite.db"
|
||||
o.rmempty = false
|
||||
|
||||
o = s:option(Value, "geosite_url", translate("Custom geosite URL"))
|
||||
o.default = "https://github.com/SagerNet/sing-geosite/releases/latest/download/geosite.db"
|
||||
o:value("https://github.com/SagerNet/sing-geosite/releases/latest/download/geosite.db")
|
||||
o.rmempty = false
|
||||
end
|
||||
|
||||
return m
|
@ -1,90 +0,0 @@
|
||||
local api = require "luci.passwall.api"
|
||||
local appname = api.appname
|
||||
local has_xray = api.finded_com("xray")
|
||||
|
||||
m = Map(appname)
|
||||
-- [[ Rule Settings ]]--
|
||||
s = m:section(TypedSection, "global_rules", translate("Rule status"))
|
||||
s.anonymous = true
|
||||
|
||||
--[[
|
||||
o = s:option(Flag, "adblock", translate("Enable adblock"))
|
||||
o.rmempty = false
|
||||
]]--
|
||||
|
||||
---- gfwlist URL
|
||||
o = s:option(DynamicList, "gfwlist_url", translate("GFW domains(gfwlist) Update URL"))
|
||||
o:value("https://fastly.jsdelivr.net/gh/YW5vbnltb3Vz/domain-list-community@release/gfwlist.txt", translate("v2fly/domain-list-community"))
|
||||
o:value("https://fastly.jsdelivr.net/gh/Loyalsoldier/v2ray-rules-dat@release/gfw.txt", translate("Loyalsoldier/v2ray-rules-dat"))
|
||||
o:value("https://fastly.jsdelivr.net/gh/Loukky/gfwlist-by-loukky/gfwlist.txt", translate("Loukky/gfwlist-by-loukky"))
|
||||
o:value("https://fastly.jsdelivr.net/gh/gfwlist/gfwlist/gfwlist.txt", translate("gfwlist/gfwlist"))
|
||||
o.default = "https://fastly.jsdelivr.net/gh/Loyalsoldier/v2ray-rules-dat@release/gfw.txt"
|
||||
|
||||
----chnroute URL
|
||||
o = s:option(DynamicList, "chnroute_url", translate("China IPs(chnroute) Update URL"))
|
||||
o:value("https://fastly.jsdelivr.net/gh/gaoyifan/china-operator-ip@ip-lists/china.txt", translate("gaoyifan/china-operator-ip/china"))
|
||||
o:value("https://ispip.clang.cn/all_cn.txt", translate("Clang.CN"))
|
||||
o:value("https://ispip.clang.cn/all_cn_cidr.txt", translate("Clang.CN.CIDR"))
|
||||
o:value("https://fastly.jsdelivr.net/gh/soffchen/GeoIP2-CN@release/CN-ip-cidr.txt", translate("soffchen/GeoIP2-CN"))
|
||||
o:value("https://fastly.jsdelivr.net/gh/Hackl0us/GeoIP2-CN@release/CN-ip-cidr.txt", translate("Hackl0us/GeoIP2-CN"))
|
||||
|
||||
----chnroute6 URL
|
||||
o = s:option(DynamicList, "chnroute6_url", translate("China IPv6s(chnroute6) Update URL"))
|
||||
o:value("https://fastly.jsdelivr.net/gh/gaoyifan/china-operator-ip@ip-lists/china6.txt", translate("gaoyifan/china-operator-ip/china6"))
|
||||
o:value("https://ispip.clang.cn/all_cn_ipv6.txt", translate("Clang.CN.IPv6"))
|
||||
|
||||
----chnlist URL
|
||||
o = s:option(DynamicList, "chnlist_url", translate("China List(Chnlist) Update URL"))
|
||||
o:value("https://fastly.jsdelivr.net/gh/felixonmars/dnsmasq-china-list/accelerated-domains.china.conf", translate("felixonmars/domains.china"))
|
||||
o:value("https://fastly.jsdelivr.net/gh/felixonmars/dnsmasq-china-list/apple.china.conf", translate("felixonmars/apple.china"))
|
||||
o:value("https://fastly.jsdelivr.net/gh/felixonmars/dnsmasq-china-list/google.china.conf", translate("felixonmars/google.china"))
|
||||
|
||||
s:append(Template(appname .. "/rule/rule_version"))
|
||||
|
||||
---- Auto Update
|
||||
o = s:option(Flag, "auto_update", translate("Enable auto update rules"))
|
||||
o.default = 0
|
||||
o.rmempty = false
|
||||
|
||||
---- Week Update
|
||||
o = s:option(ListValue, "week_update", translate("Week update rules"))
|
||||
o:value(7, translate("Every day"))
|
||||
for e = 1, 6 do o:value(e, translate("Week") .. e) end
|
||||
o:value(0, translate("Week") .. translate("day"))
|
||||
o.default = 0
|
||||
o:depends("auto_update", true)
|
||||
|
||||
---- Time Update
|
||||
o = s:option(ListValue, "time_update", translate("Day update rules"))
|
||||
for e = 0, 23 do o:value(e, e .. translate("oclock")) end
|
||||
o.default = 0
|
||||
o:depends("auto_update", true)
|
||||
|
||||
if has_xray then
|
||||
o = s:option(Value, "v2ray_location_asset", translate("Location of V2ray/Xray asset"), translate("This variable specifies a directory where geoip.dat and geosite.dat files are."))
|
||||
o.default = "/usr/share/v2ray/"
|
||||
o.rmempty = false
|
||||
|
||||
s = m:section(TypedSection, "shunt_rules", "Xray " .. translate("Shunt Rule"), "<a style='color: red'>" .. translate("Please note attention to the priority, the higher the order, the higher the priority.") .. "</a>")
|
||||
s.template = "cbi/tblsection"
|
||||
s.anonymous = false
|
||||
s.addremove = true
|
||||
s.sortable = true
|
||||
s.extedit = api.url("shunt_rules", "%s")
|
||||
function s.create(e, t)
|
||||
TypedSection.create(e, t)
|
||||
luci.http.redirect(e.extedit:format(t))
|
||||
end
|
||||
function s.remove(e, t)
|
||||
m.uci:foreach(appname, "nodes", function(s)
|
||||
if s["protocol"] and s["protocol"] == "_shunt" then
|
||||
m:del(s[".name"], t)
|
||||
end
|
||||
end)
|
||||
TypedSection.remove(e, t)
|
||||
end
|
||||
|
||||
o = s:option(DummyValue, "remarks", translate("Remarks"))
|
||||
end
|
||||
|
||||
return m
|
@ -1,271 +0,0 @@
|
||||
local api = require "luci.passwall.api"
|
||||
local appname = api.appname
|
||||
local fs = api.fs
|
||||
local sys = api.sys
|
||||
local datatypes = api.datatypes
|
||||
local path = string.format("/usr/share/%s/rules/", appname)
|
||||
local route_hosts_path = "/etc/"
|
||||
|
||||
m = Map(appname)
|
||||
|
||||
-- [[ Rule List Settings ]]--
|
||||
s = m:section(TypedSection, "global_rules")
|
||||
s.anonymous = true
|
||||
|
||||
s:tab("direct_list", translate("Direct List"))
|
||||
s:tab("proxy_list", translate("Proxy List"))
|
||||
s:tab("block_list", translate("Block List"))
|
||||
s:tab("lan_ip_list", translate("Lan IP List"))
|
||||
s:tab("route_hosts", translate("Route Hosts"))
|
||||
|
||||
---- Direct Hosts
|
||||
local direct_host = path .. "direct_host"
|
||||
o = s:taboption("direct_list", TextValue, "direct_host", "", "<font color='red'>" .. translate("Join the direct hosts list of domain names will not proxy.") .. "</font>")
|
||||
o.rows = 15
|
||||
o.wrap = "off"
|
||||
o.cfgvalue = function(self, section)
|
||||
return fs.readfile(direct_host) or ""
|
||||
end
|
||||
o.write = function(self, section, value)
|
||||
fs.writefile(direct_host, value:gsub("\r\n", "\n"))
|
||||
sys.call("rm -rf /tmp/etc/passwall_tmp/dns_*")
|
||||
end
|
||||
o.remove = function(self, section, value)
|
||||
fs.writefile(direct_host, "")
|
||||
sys.call("rm -rf /tmp/etc/passwall_tmp/dns_*")
|
||||
end
|
||||
o.validate = function(self, value)
|
||||
local hosts= {}
|
||||
string.gsub(value, '[^' .. "\r\n" .. ']+', function(w) table.insert(hosts, w) end)
|
||||
for index, host in ipairs(hosts) do
|
||||
if host:find("#") and host:find("#") == 1 then
|
||||
return value
|
||||
end
|
||||
if not datatypes.hostname(host) then
|
||||
return nil, host .. " " .. translate("Not valid domain name, please re-enter!")
|
||||
end
|
||||
end
|
||||
return value
|
||||
end
|
||||
|
||||
---- Direct IP
|
||||
local direct_ip = path .. "direct_ip"
|
||||
o = s:taboption("direct_list", TextValue, "direct_ip", "", "<font color='red'>" .. translate("These had been joined ip addresses will not proxy. Please input the ip address or ip address segment,every line can input only one ip address. For example: 192.168.0.0/24 or 223.5.5.5.") .. "</font>")
|
||||
o.rows = 15
|
||||
o.wrap = "off"
|
||||
o.cfgvalue = function(self, section)
|
||||
return fs.readfile(direct_ip) or ""
|
||||
end
|
||||
o.write = function(self, section, value)
|
||||
fs.writefile(direct_ip, value:gsub("\r\n", "\n"))
|
||||
end
|
||||
o.remove = function(self, section, value)
|
||||
fs.writefile(direct_ip, "")
|
||||
end
|
||||
o.validate = function(self, value)
|
||||
local ipmasks= {}
|
||||
string.gsub(value, '[^' .. "\r\n" .. ']+', function(w) table.insert(ipmasks, w) end)
|
||||
for index, ipmask in ipairs(ipmasks) do
|
||||
if ipmask:find("#") and ipmask:find("#") == 1 then
|
||||
return value
|
||||
end
|
||||
if not ( datatypes.ipmask4(ipmask) or datatypes.ipmask6(ipmask) ) then
|
||||
return nil, ipmask .. " " .. translate("Not valid IP format, please re-enter!")
|
||||
end
|
||||
end
|
||||
return value
|
||||
end
|
||||
|
||||
---- Proxy Hosts
|
||||
local proxy_host = path .. "proxy_host"
|
||||
o = s:taboption("proxy_list", TextValue, "proxy_host", "", "<font color='red'>" .. translate("These had been joined websites will use proxy. Please input the domain names of websites, every line can input only one website domain. For example: google.com.") .. "</font>")
|
||||
o.rows = 15
|
||||
o.wrap = "off"
|
||||
o.cfgvalue = function(self, section)
|
||||
return fs.readfile(proxy_host) or ""
|
||||
end
|
||||
o.write = function(self, section, value)
|
||||
fs.writefile(proxy_host, value:gsub("\r\n", "\n"))
|
||||
sys.call("rm -rf /tmp/etc/passwall_tmp/dns_*")
|
||||
end
|
||||
o.remove = function(self, section, value)
|
||||
fs.writefile(proxy_host, "")
|
||||
sys.call("rm -rf /tmp/etc/passwall_tmp/dns_*")
|
||||
end
|
||||
o.validate = function(self, value)
|
||||
local hosts= {}
|
||||
string.gsub(value, '[^' .. "\r\n" .. ']+', function(w) table.insert(hosts, w) end)
|
||||
for index, host in ipairs(hosts) do
|
||||
if host:find("#") and host:find("#") == 1 then
|
||||
return value
|
||||
end
|
||||
if not datatypes.hostname(host) then
|
||||
return nil, host .. " " .. translate("Not valid domain name, please re-enter!")
|
||||
end
|
||||
end
|
||||
return value
|
||||
end
|
||||
|
||||
---- Proxy IP
|
||||
local proxy_ip = path .. "proxy_ip"
|
||||
o = s:taboption("proxy_list", TextValue, "proxy_ip", "", "<font color='red'>" .. translate("These had been joined ip addresses will use proxy. Please input the ip address or ip address segment, every line can input only one ip address. For example: 35.24.0.0/24 or 8.8.4.4.") .. "</font>")
|
||||
o.rows = 15
|
||||
o.wrap = "off"
|
||||
o.cfgvalue = function(self, section)
|
||||
return fs.readfile(proxy_ip) or ""
|
||||
end
|
||||
o.write = function(self, section, value)
|
||||
fs.writefile(proxy_ip, value:gsub("\r\n", "\n"))
|
||||
end
|
||||
o.remove = function(self, section, value)
|
||||
fs.writefile(proxy_ip, "")
|
||||
end
|
||||
o.validate = function(self, value)
|
||||
local ipmasks= {}
|
||||
string.gsub(value, '[^' .. "\r\n" .. ']+', function(w) table.insert(ipmasks, w) end)
|
||||
for index, ipmask in ipairs(ipmasks) do
|
||||
if ipmask:find("#") and ipmask:find("#") == 1 then
|
||||
return value
|
||||
end
|
||||
if not ( datatypes.ipmask4(ipmask) or datatypes.ipmask6(ipmask) ) then
|
||||
return nil, ipmask .. " " .. translate("Not valid IP format, please re-enter!")
|
||||
end
|
||||
end
|
||||
return value
|
||||
end
|
||||
|
||||
---- Block Hosts
|
||||
local block_host = path .. "block_host"
|
||||
o = s:taboption("block_list", TextValue, "block_host", "", "<font color='red'>" .. translate("These had been joined websites will be block. Please input the domain names of websites, every line can input only one website domain. For example: twitter.com.") .. "</font>")
|
||||
o.rows = 15
|
||||
o.wrap = "off"
|
||||
o.cfgvalue = function(self, section)
|
||||
return fs.readfile(block_host) or ""
|
||||
end
|
||||
o.write = function(self, section, value)
|
||||
fs.writefile(block_host, value:gsub("\r\n", "\n"))
|
||||
end
|
||||
o.remove = function(self, section, value)
|
||||
fs.writefile(block_host, "")
|
||||
end
|
||||
o.validate = function(self, value)
|
||||
local hosts= {}
|
||||
string.gsub(value, '[^' .. "\r\n" .. ']+', function(w) table.insert(hosts, w) end)
|
||||
for index, host in ipairs(hosts) do
|
||||
if host:find("#") and host:find("#") == 1 then
|
||||
return value
|
||||
end
|
||||
if not datatypes.hostname(host) then
|
||||
return nil, host .. " " .. translate("Not valid domain name, please re-enter!")
|
||||
end
|
||||
end
|
||||
return value
|
||||
end
|
||||
|
||||
---- Block IP
|
||||
local block_ip = path .. "block_ip"
|
||||
o = s:taboption("block_list", TextValue, "block_ip", "", "<font color='red'>" .. translate("These had been joined ip addresses will be block. Please input the ip address or ip address segment, every line can input only one ip address.") .. "</font>")
|
||||
o.rows = 15
|
||||
o.wrap = "off"
|
||||
o.cfgvalue = function(self, section)
|
||||
return fs.readfile(block_ip) or ""
|
||||
end
|
||||
o.write = function(self, section, value)
|
||||
fs.writefile(block_ip, value:gsub("\r\n", "\n"))
|
||||
end
|
||||
o.remove = function(self, section, value)
|
||||
fs.writefile(block_ip, "")
|
||||
end
|
||||
o.validate = function(self, value)
|
||||
local ipmasks= {}
|
||||
string.gsub(value, '[^' .. "\r\n" .. ']+', function(w) table.insert(ipmasks, w) end)
|
||||
for index, ipmask in ipairs(ipmasks) do
|
||||
if ipmask:find("#") and ipmask:find("#") == 1 then
|
||||
return value
|
||||
end
|
||||
if not ( datatypes.ipmask4(ipmask) or datatypes.ipmask6(ipmask) ) then
|
||||
return nil, ipmask .. " " .. translate("Not valid IP format, please re-enter!")
|
||||
end
|
||||
end
|
||||
return value
|
||||
end
|
||||
|
||||
---- Lan IPv4
|
||||
local lanlist_ipv4 = path .. "lanlist_ipv4"
|
||||
o = s:taboption("lan_ip_list", TextValue, "lanlist_ipv4", "", "<font color='red'>" .. translate("The list is the IPv4 LAN IP list, which represents the direct connection IP of the LAN. If you need the LAN IP in the proxy list, please clear it from the list. Do not modify this list by default.") .. "</font>")
|
||||
o.rows = 15
|
||||
o.wrap = "off"
|
||||
o.cfgvalue = function(self, section)
|
||||
return fs.readfile(lanlist_ipv4) or ""
|
||||
end
|
||||
o.write = function(self, section, value)
|
||||
fs.writefile(lanlist_ipv4, value:gsub("\r\n", "\n"))
|
||||
end
|
||||
o.remove = function(self, section, value)
|
||||
fs.writefile(lanlist_ipv4, "")
|
||||
end
|
||||
o.validate = function(self, value)
|
||||
local ipmasks= {}
|
||||
string.gsub(value, '[^' .. "\r\n" .. ']+', function(w) table.insert(ipmasks, w) end)
|
||||
for index, ipmask in ipairs(ipmasks) do
|
||||
if ipmask:find("#") and ipmask:find("#") == 1 then
|
||||
return value
|
||||
end
|
||||
if not datatypes.ipmask4(ipmask) then
|
||||
return nil, ipmask .. " " .. translate("Not valid IPv4 format, please re-enter!")
|
||||
end
|
||||
end
|
||||
return value
|
||||
end
|
||||
|
||||
---- Lan IPv6
|
||||
local lanlist_ipv6 = path .. "lanlist_ipv6"
|
||||
o = s:taboption("lan_ip_list", TextValue, "lanlist_ipv6", "", "<font color='red'>" .. translate("The list is the IPv6 LAN IP list, which represents the direct connection IP of the LAN. If you need the LAN IP in the proxy list, please clear it from the list. Do not modify this list by default.") .. "</font>")
|
||||
o.rows = 15
|
||||
o.wrap = "off"
|
||||
o.cfgvalue = function(self, section)
|
||||
return fs.readfile(lanlist_ipv6) or ""
|
||||
end
|
||||
o.write = function(self, section, value)
|
||||
fs.writefile(lanlist_ipv6, value:gsub("\r\n", "\n"))
|
||||
end
|
||||
o.remove = function(self, section, value)
|
||||
fs.writefile(lanlist_ipv6, "")
|
||||
end
|
||||
o.validate = function(self, value)
|
||||
local ipmasks= {}
|
||||
string.gsub(value, '[^' .. "\r\n" .. ']+', function(w) table.insert(ipmasks, w) end)
|
||||
for index, ipmask in ipairs(ipmasks) do
|
||||
if ipmask:find("#") and ipmask:find("#") == 1 then
|
||||
return value
|
||||
end
|
||||
if not datatypes.ipmask6(ipmask) then
|
||||
return nil, ipmask .. " " .. translate("Not valid IPv6 format, please re-enter!")
|
||||
end
|
||||
end
|
||||
return value
|
||||
end
|
||||
|
||||
---- Route Hosts
|
||||
local hosts = route_hosts_path .. "hosts"
|
||||
o = s:taboption("route_hosts", TextValue, "hosts", "", "<font color='red'>" .. translate("Configure routing etc/hosts file, if you don't know what you are doing, please don't change the content.") .. "</font>")
|
||||
o.rows = 15
|
||||
o.wrap = "off"
|
||||
o.cfgvalue = function(self, section)
|
||||
return fs.readfile(hosts) or ""
|
||||
end
|
||||
o.write = function(self, section, value)
|
||||
fs.writefile(hosts, value:gsub("\r\n", "\n"))
|
||||
end
|
||||
o.remove = function(self, section, value)
|
||||
fs.writefile(hosts, "")
|
||||
end
|
||||
|
||||
if sys.call('[ -f "/www/luci-static/resources/uci.js" ]') == 0 then
|
||||
m.apply_on_parse = true
|
||||
function m.on_apply(self)
|
||||
luci.sys.call("/etc/init.d/passwall reload > /dev/null 2>&1 &")
|
||||
end
|
||||
end
|
||||
|
||||
return m
|
@ -1,79 +0,0 @@
|
||||
local api = require "luci.passwall.api"
|
||||
local appname = api.appname
|
||||
local datatypes = api.datatypes
|
||||
|
||||
m = Map(appname, "Xray " .. translate("Shunt Rule"))
|
||||
m.redirect = api.url()
|
||||
|
||||
s = m:section(NamedSection, arg[1], "shunt_rules", "")
|
||||
s.addremove = false
|
||||
s.dynamic = false
|
||||
|
||||
remarks = s:option(Value, "remarks", translate("Remarks"))
|
||||
remarks.default = arg[1]
|
||||
remarks.rmempty = false
|
||||
|
||||
protocol = s:option(MultiValue, "protocol", translate("Protocol"))
|
||||
protocol:value("http")
|
||||
protocol:value("tls")
|
||||
protocol:value("bittorrent")
|
||||
|
||||
domain_list = s:option(TextValue, "domain_list", translate("Domain"))
|
||||
domain_list.rows = 10
|
||||
domain_list.wrap = "off"
|
||||
domain_list.validate = function(self, value)
|
||||
local hosts= {}
|
||||
string.gsub(value, '[^' .. "\r\n" .. ']+', function(w) table.insert(hosts, w) end)
|
||||
for index, host in ipairs(hosts) do
|
||||
local flag = 1
|
||||
local tmp_host = host
|
||||
if host:find("regexp:") and host:find("regexp:") == 1 then
|
||||
flag = 0
|
||||
elseif host:find("domain:.") and host:find("domain:.") == 1 then
|
||||
tmp_host = host:gsub("domain:", "")
|
||||
elseif host:find("full:.") and host:find("full:.") == 1 then
|
||||
tmp_host = host:gsub("full:", "")
|
||||
elseif host:find("geosite:") and host:find("geosite:") == 1 then
|
||||
flag = 0
|
||||
elseif host:find("ext:") and host:find("ext:") == 1 then
|
||||
flag = 0
|
||||
end
|
||||
if flag == 1 then
|
||||
if not datatypes.hostname(tmp_host) then
|
||||
return nil, tmp_host .. " " .. translate("Not valid domain name, please re-enter!")
|
||||
end
|
||||
end
|
||||
end
|
||||
return value
|
||||
end
|
||||
domain_list.description = "<br /><ul><li>" .. translate("Plaintext: If this string matches any part of the targeting domain, this rule takes effet. Example: rule 'sina.com' matches targeting domain 'sina.com', 'sina.com.cn' and 'www.sina.com', but not 'sina.cn'.")
|
||||
.. "</li><li>" .. translate("Regular expression: Begining with 'regexp:', the rest is a regular expression. When the regexp matches targeting domain, this rule takes effect. Example: rule 'regexp:\\.goo.*\\.com$' matches 'www.google.com' and 'fonts.googleapis.com', but not 'google.com'.")
|
||||
.. "</li><li>" .. translate("Subdomain (recommended): Begining with 'domain:' and the rest is a domain. When the targeting domain is exactly the value, or is a subdomain of the value, this rule takes effect. Example: rule 'domain:v2ray.com' matches 'www.v2ray.com', 'v2ray.com', but not 'xv2ray.com'.")
|
||||
.. "</li><li>" .. translate("Full domain: Begining with 'full:' and the rest is a domain. When the targeting domain is exactly the value, the rule takes effect. Example: rule 'domain:v2ray.com' matches 'v2ray.com', but not 'www.v2ray.com'.")
|
||||
.. "</li><li>" .. translate("Pre-defined domain list: Begining with 'geosite:' and the rest is a name, such as geosite:google or geosite:cn.")
|
||||
.. "</li><li>" .. translate("Domains from file: Such as 'ext:file:tag'. The value must begin with ext: (lowercase), and followed by filename and tag. The file is placed in resource directory, and has the same format of geosite.dat. The tag must exist in the file.")
|
||||
.. "</li></ul>"
|
||||
ip_list = s:option(TextValue, "ip_list", "IP")
|
||||
ip_list.rows = 10
|
||||
ip_list.wrap = "off"
|
||||
ip_list.validate = function(self, value)
|
||||
local ipmasks= {}
|
||||
string.gsub(value, '[^' .. "\r\n" .. ']+', function(w) table.insert(ipmasks, w) end)
|
||||
for index, ipmask in ipairs(ipmasks) do
|
||||
if ipmask:find("geoip:") and ipmask:find("geoip:") == 1 then
|
||||
elseif ipmask:find("ext:") and ipmask:find("ext:") == 1 then
|
||||
else
|
||||
if not (datatypes.ipmask4(ipmask) or datatypes.ipmask6(ipmask)) then
|
||||
return nil, ipmask .. " " .. translate("Not valid IP format, please re-enter!")
|
||||
end
|
||||
end
|
||||
end
|
||||
return value
|
||||
end
|
||||
ip_list.description = "<br /><ul><li>" .. translate("IP: such as '127.0.0.1'.")
|
||||
.. "</li><li>" .. translate("CIDR: such as '127.0.0.0/8'.")
|
||||
.. "</li><li>" .. translate("GeoIP: such as 'geoip:cn'. It begins with geoip: (lower case) and followed by two letter of country code.")
|
||||
.. "</li><li>" .. translate("IPs from file: Such as 'ext:file:tag'. The value must begin with ext: (lowercase), and followed by filename and tag. The file is placed in resource directory, and has the same format of geoip.dat. The tag must exist in the file.")
|
||||
.. "</li></ul>"
|
||||
|
||||
return m
|
@ -1,118 +0,0 @@
|
||||
local api = require "luci.passwall.api"
|
||||
local appname = api.appname
|
||||
local uci = api.uci
|
||||
local has_xray = api.finded_com("xray")
|
||||
|
||||
m = Map(appname)
|
||||
|
||||
local nodes_table = {}
|
||||
for k, e in ipairs(api.get_valid_nodes()) do
|
||||
nodes_table[#nodes_table + 1] = e
|
||||
end
|
||||
|
||||
s = m:section(NamedSection, arg[1], translate("Socks Config"), translate("Socks Config"))
|
||||
s.addremove = false
|
||||
s.dynamic = false
|
||||
|
||||
---- Enable
|
||||
o = s:option(Flag, "enabled", translate("Enable"))
|
||||
o.default = 1
|
||||
o.rmempty = false
|
||||
|
||||
local auto_switch_tip
|
||||
local current_node_file = string.format("/tmp/etc/%s/id/socks_%s", appname, arg[1])
|
||||
local current_node = luci.sys.exec(string.format("[ -f '%s' ] && echo -n $(cat %s)", current_node_file, current_node_file))
|
||||
if current_node and current_node ~= "" and current_node ~= "nil" then
|
||||
local n = uci:get_all(appname, current_node)
|
||||
if n then
|
||||
if tonumber(m:get(arg[1], "enable_autoswitch") or 0) == 1 then
|
||||
if n then
|
||||
local remarks = api.get_node_remarks(n)
|
||||
local url = api.url("node_config", n[".name"])
|
||||
auto_switch_tip = translatef("Current node: %s", string.format('<a href="%s">%s</a>', url, remarks)) .. "<br />"
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
socks_node = s:option(ListValue, "node", translate("Node"))
|
||||
if auto_switch_tip then
|
||||
socks_node.description = auto_switch_tip
|
||||
end
|
||||
|
||||
local n = 1
|
||||
uci:foreach(appname, "socks", function(s)
|
||||
if s[".name"] == section then
|
||||
return false
|
||||
end
|
||||
n = n + 1
|
||||
end)
|
||||
|
||||
o = s:option(Value, "port", "Socks " .. translate("Listen Port"))
|
||||
o.default = n + 1080
|
||||
o.datatype = "port"
|
||||
o.rmempty = false
|
||||
|
||||
if has_xray then
|
||||
o = s:option(Value, "http_port", "HTTP " .. translate("Listen Port") .. " " .. translate("0 is not use"))
|
||||
o.default = 0
|
||||
o.datatype = "port"
|
||||
end
|
||||
|
||||
o = s:option(Flag, "enable_autoswitch", translate("Auto Switch"))
|
||||
o.default = 0
|
||||
o.rmempty = false
|
||||
|
||||
o = s:option(Value, "autoswitch_testing_time", translate("How often to test"), translate("Units:seconds"))
|
||||
o.datatype = "min(10)"
|
||||
o.default = 30
|
||||
o:depends("enable_autoswitch", true)
|
||||
|
||||
o = s:option(Value, "autoswitch_connect_timeout", translate("Timeout seconds"), translate("Units:seconds"))
|
||||
o.datatype = "min(1)"
|
||||
o.default = 3
|
||||
o:depends("enable_autoswitch", true)
|
||||
|
||||
o = s:option(Value, "autoswitch_retry_num", translate("Timeout retry num"))
|
||||
o.datatype = "min(1)"
|
||||
o.default = 1
|
||||
o:depends("enable_autoswitch", true)
|
||||
|
||||
autoswitch_backup_node = s:option(DynamicList, "autoswitch_backup_node", translate("List of backup nodes"))
|
||||
autoswitch_backup_node:depends("enable_autoswitch", true)
|
||||
function o.write(self, section, value)
|
||||
local t = {}
|
||||
local t2 = {}
|
||||
if type(value) == "table" then
|
||||
local x
|
||||
for _, x in ipairs(value) do
|
||||
if x and #x > 0 then
|
||||
if not t2[x] then
|
||||
t2[x] = x
|
||||
t[#t+1] = x
|
||||
end
|
||||
end
|
||||
end
|
||||
else
|
||||
t = { value }
|
||||
end
|
||||
return DynamicList.write(self, section, t)
|
||||
end
|
||||
|
||||
o = s:option(Flag, "autoswitch_restore_switch", translate("Restore Switch"), translate("When detects main node is available, switch back to the main node."))
|
||||
o:depends("enable_autoswitch", true)
|
||||
|
||||
o = s:option(Value, "autoswitch_probe_url", translate("Probe URL"), translate("The URL used to detect the connection status."))
|
||||
o.default = "https://www.google.com/generate_204"
|
||||
o:depends("enable_autoswitch", true)
|
||||
|
||||
for k, v in pairs(nodes_table) do
|
||||
if v.node_type == "normal" then
|
||||
autoswitch_backup_node:value(v.id, v["remark"])
|
||||
socks_node:value(v.id, v["remark"])
|
||||
end
|
||||
end
|
||||
|
||||
m:append(Template(appname .. "/socks_auto_switch/footer"))
|
||||
|
||||
return m
|
@ -1,40 +0,0 @@
|
||||
local m, s = ...
|
||||
|
||||
local api = require "luci.passwall.api"
|
||||
|
||||
if not api.finded_com("brook") then
|
||||
return
|
||||
end
|
||||
|
||||
local type_name = "Brook"
|
||||
|
||||
local option_prefix = "brook_"
|
||||
|
||||
local function option_name(name)
|
||||
return option_prefix .. name
|
||||
end
|
||||
|
||||
-- [[ Brook ]]
|
||||
|
||||
s.fields["type"]:value(type_name, translate("Brook"))
|
||||
|
||||
o = s:option(ListValue, option_name("protocol"), translate("Protocol"))
|
||||
o:value("client", translate("Brook"))
|
||||
o:value("wsclient", translate("WebSocket"))
|
||||
|
||||
o = s:option(Value, option_name("address"), translate("Address (Support Domain Name)"))
|
||||
|
||||
o = s:option(Value, option_name("port"), translate("Port"))
|
||||
o.datatype = "port"
|
||||
|
||||
o = s:option(Value, option_name("ws_path"), translate("WebSocket Path"))
|
||||
o.placeholder = "/"
|
||||
o:depends({ [option_name("protocol")] = "wsclient" })
|
||||
|
||||
o = s:option(Flag, option_name("tls"), translate("Use TLS"))
|
||||
o:depends({ [option_name("protocol")] = "wsclient" })
|
||||
|
||||
o = s:option(Value, option_name("password"), translate("Password"))
|
||||
o.password = true
|
||||
|
||||
api.luci_types(arg[1], m, s, type_name, option_prefix)
|
@ -1,71 +0,0 @@
|
||||
local m, s = ...
|
||||
|
||||
local api = require "luci.passwall.api"
|
||||
|
||||
if not api.finded_com("hysteria") then
|
||||
return
|
||||
end
|
||||
|
||||
local type_name = "Hysteria2"
|
||||
|
||||
local option_prefix = "hysteria2_"
|
||||
|
||||
local function option_name(name)
|
||||
return option_prefix .. name
|
||||
end
|
||||
|
||||
-- [[ Hysteria2 ]]
|
||||
|
||||
s.fields["type"]:value(type_name, "Hysteria2")
|
||||
|
||||
o = s:option(ListValue, option_name("protocol"), translate("Protocol"))
|
||||
o:value("udp", "UDP")
|
||||
|
||||
o = s:option(Value, option_name("address"), translate("Address (Support Domain Name)"))
|
||||
|
||||
o = s:option(Value, option_name("port"), translate("Port"))
|
||||
o.datatype = "port"
|
||||
|
||||
o = s:option(Value, option_name("hop"), translate("Additional ports for hysteria hop"))
|
||||
o.rewrite_option = o.option
|
||||
|
||||
o = s:option(Value, option_name("obfs"), translate("Obfs Password"))
|
||||
o.rewrite_option = o.option
|
||||
|
||||
o = s:option(Value, option_name("auth_password"), translate("Auth Password"))
|
||||
o.password = true
|
||||
o.rewrite_option = o.option
|
||||
|
||||
o = s:option(Flag, option_name("fast_open"), translate("Fast Open"))
|
||||
o.default = "0"
|
||||
|
||||
o = s:option(Value, option_name("tls_serverName"), translate("Domain"))
|
||||
|
||||
o = s:option(Flag, option_name("tls_allowInsecure"), translate("allowInsecure"), translate("Whether unsafe connections are allowed. When checked, Certificate validation will be skipped."))
|
||||
o.default = "0"
|
||||
|
||||
o = s:option(Value, option_name("up_mbps"), translate("Max upload Mbps"))
|
||||
o.default = "100"
|
||||
o.rewrite_option = o.option
|
||||
|
||||
o = s:option(Value, option_name("down_mbps"), translate("Max download Mbps"))
|
||||
o.default = "100"
|
||||
o.rewrite_option = o.option
|
||||
|
||||
o = s:option(Value, option_name("hop_interval"), translate("Hop Interval"))
|
||||
o.rewrite_option = o.option
|
||||
|
||||
o = s:option(Value, option_name("recv_window_conn"), translate("QUIC stream receive window"))
|
||||
o.rewrite_option = o.option
|
||||
|
||||
o = s:option(Value, option_name("recv_window"), translate("QUIC connection receive window"))
|
||||
o.rewrite_option = o.option
|
||||
|
||||
o = s:option(Value, option_name("idle_timeout"), translate("Idle Timeout"))
|
||||
o.rewrite_option = o.option
|
||||
|
||||
o = s:option(Flag, option_name("disable_mtu_discovery"), translate("Disable MTU detection"))
|
||||
o.default = "0"
|
||||
o.rewrite_option = o.option
|
||||
|
||||
api.luci_types(arg[1], m, s, type_name, option_prefix)
|
@ -1,35 +0,0 @@
|
||||
local m, s = ...
|
||||
|
||||
local api = require "luci.passwall.api"
|
||||
|
||||
if not api.is_finded("naive") then
|
||||
return
|
||||
end
|
||||
|
||||
local type_name = "Naiveproxy"
|
||||
|
||||
local option_prefix = "naive_"
|
||||
|
||||
local function option_name(name)
|
||||
return option_prefix .. name
|
||||
end
|
||||
|
||||
-- [[ Naive ]]
|
||||
|
||||
s.fields["type"]:value(type_name, translate("NaiveProxy"))
|
||||
|
||||
o = s:option(ListValue, option_name("protocol"), translate("Protocol"))
|
||||
o:value("https", translate("HTTPS"))
|
||||
o:value("quic", translate("QUIC"))
|
||||
|
||||
o = s:option(Value, option_name("address"), translate("Address (Support Domain Name)"))
|
||||
|
||||
o = s:option(Value, option_name("port"), translate("Port"))
|
||||
o.datatype = "port"
|
||||
|
||||
o = s:option(Value, option_name("username"), translate("Username"))
|
||||
|
||||
o = s:option(Value, option_name("password"), translate("Password"))
|
||||
o.password = true
|
||||
|
||||
api.luci_types(arg[1], m, s, type_name, option_prefix)
|
@ -1,519 +0,0 @@
|
||||
local m, s = ...
|
||||
|
||||
local api = require "luci.passwall.api"
|
||||
|
||||
if not api.finded_com("xray") then
|
||||
return
|
||||
end
|
||||
|
||||
local appname = api.appname
|
||||
local uci = api.uci
|
||||
|
||||
local type_name = "Xray"
|
||||
|
||||
local option_prefix = "xray_"
|
||||
|
||||
local function option_name(name)
|
||||
return option_prefix .. name
|
||||
end
|
||||
|
||||
local x_ss_encrypt_method_list = {
|
||||
"aes-128-gcm", "aes-256-gcm", "chacha20-poly1305", "xchacha20-poly1305", "2022-blake3-aes-128-gcm", "2022-blake3-aes-256-gcm", "2022-blake3-chacha20-poly1305"
|
||||
}
|
||||
|
||||
local security_list = { "none", "auto", "aes-128-gcm", "chacha20-poly1305", "zero" }
|
||||
|
||||
local header_type_list = {
|
||||
"none", "srtp", "utp", "wechat-video", "dtls", "wireguard"
|
||||
}
|
||||
|
||||
-- [[ Xray ]]
|
||||
|
||||
s.fields["type"]:value(type_name, "Xray")
|
||||
|
||||
o = s:option(ListValue, option_name("protocol"), translate("Protocol"))
|
||||
o:value("vmess", translate("Vmess"))
|
||||
o:value("vless", translate("VLESS"))
|
||||
o:value("http", translate("HTTP"))
|
||||
o:value("socks", translate("Socks"))
|
||||
o:value("shadowsocks", translate("Shadowsocks"))
|
||||
o:value("trojan", translate("Trojan"))
|
||||
o:value("wireguard", translate("WireGuard"))
|
||||
o:value("_balancing", translate("Balancing"))
|
||||
o:value("_shunt", translate("Shunt"))
|
||||
o:value("_iface", translate("Custom Interface") .. " (Only Support Xray)")
|
||||
|
||||
o = s:option(Value, option_name("iface"), translate("Interface"))
|
||||
o.default = "eth1"
|
||||
o:depends({ [option_name("protocol")] = "_iface" })
|
||||
|
||||
local nodes_table = {}
|
||||
local balancers_table = {}
|
||||
local iface_table = {}
|
||||
for k, e in ipairs(api.get_valid_nodes()) do
|
||||
if e.node_type == "normal" then
|
||||
nodes_table[#nodes_table + 1] = {
|
||||
id = e[".name"],
|
||||
remarks = e["remark"]
|
||||
}
|
||||
end
|
||||
if e.protocol == "_balancing" then
|
||||
balancers_table[#balancers_table + 1] = {
|
||||
id = e[".name"],
|
||||
remarks = e["remark"]
|
||||
}
|
||||
end
|
||||
if e.protocol == "_iface" then
|
||||
iface_table[#iface_table + 1] = {
|
||||
id = e[".name"],
|
||||
remarks = e["remark"]
|
||||
}
|
||||
end
|
||||
end
|
||||
|
||||
-- 负载均衡列表
|
||||
local o = s:option(DynamicList, option_name("balancing_node"), translate("Load balancing node list"), translate("Load balancing node list, <a target='_blank' href='https://toutyrater.github.io/routing/balance2.html'>document</a>"))
|
||||
o:depends({ [option_name("protocol")] = "_balancing" })
|
||||
for k, v in pairs(nodes_table) do o:value(v.id, v.remarks) end
|
||||
|
||||
local o = s:option(ListValue, option_name("balancingStrategy"), translate("Balancing Strategy"))
|
||||
o:depends({ [option_name("protocol")] = "_balancing" })
|
||||
o:value("random")
|
||||
o:value("leastPing")
|
||||
o.default = "random"
|
||||
|
||||
-- 探测地址
|
||||
local o = s:option(Flag, option_name("useCustomProbeUrl"), translate("Use Custome Probe URL"), translate("By default the built-in probe URL will be used, enable this option to use a custom probe URL."))
|
||||
o:depends({ [option_name("balancingStrategy")] = "leastPing" })
|
||||
|
||||
local o = s:option(Value, option_name("probeUrl"), translate("Probe URL"))
|
||||
o:depends({ [option_name("useCustomProbeUrl")] = true })
|
||||
o.default = "https://www.google.com/generate_204"
|
||||
o.description = translate("The URL used to detect the connection status.")
|
||||
|
||||
-- 探测间隔
|
||||
local o = s:option(Value, option_name("probeInterval"), translate("Probe Interval"))
|
||||
o:depends({ [option_name("balancingStrategy")] = "leastPing" })
|
||||
o.default = "1m"
|
||||
o.description = translate("The interval between initiating probes. Every time this time elapses, a server status check is performed on a server. The time format is numbers + units, such as '10s', '2h45m', and the supported time units are <code>ns</code>, <code>us</code>, <code>ms</code>, <code>s</code>, <code>m</code>, <code>h</code>, which correspond to nanoseconds, microseconds, milliseconds, seconds, minutes, and hours, respectively.")
|
||||
|
||||
-- [[ 分流模块 ]]
|
||||
if #nodes_table > 0 then
|
||||
o = s:option(Flag, option_name("preproxy_enabled"), translate("Preproxy"))
|
||||
o:depends({ [option_name("protocol")] = "_shunt" })
|
||||
|
||||
o = s:option(Value, option_name("main_node"), string.format('<a style="color:red">%s</a>', translate("Preproxy Node")), translate("Set the node to be used as a pre-proxy. Each rule (including <code>Default</code>) has a separate switch that controls whether this rule uses the pre-proxy or not."))
|
||||
o:depends({ [option_name("protocol")] = "_shunt", [option_name("preproxy_enabled")] = true })
|
||||
for k, v in pairs(balancers_table) do
|
||||
o:value(v.id, v.remarks)
|
||||
end
|
||||
for k, v in pairs(iface_table) do
|
||||
o:value(v.id, v.remarks)
|
||||
end
|
||||
for k, v in pairs(nodes_table) do
|
||||
o:value(v.id, v.remarks)
|
||||
end
|
||||
o.default = "nil"
|
||||
end
|
||||
uci:foreach(appname, "shunt_rules", function(e)
|
||||
if e[".name"] and e.remarks then
|
||||
o = s:option(Value, option_name(e[".name"]), string.format('* <a href="%s" target="_blank">%s</a>', api.url("shunt_rules", e[".name"]), e.remarks))
|
||||
o:value("nil", translate("Close"))
|
||||
o:value("_default", translate("Default"))
|
||||
o:value("_direct", translate("Direct Connection"))
|
||||
o:value("_blackhole", translate("Blackhole"))
|
||||
o:depends({ [option_name("protocol")] = "_shunt" })
|
||||
|
||||
if #nodes_table > 0 then
|
||||
for k, v in pairs(balancers_table) do
|
||||
o:value(v.id, v.remarks)
|
||||
end
|
||||
for k, v in pairs(iface_table) do
|
||||
o:value(v.id, v.remarks)
|
||||
end
|
||||
local pt = s:option(ListValue, option_name(e[".name"] .. "_proxy_tag"), string.format('* <a style="color:red">%s</a>', e.remarks .. " " .. translate("Preproxy")))
|
||||
pt:value("nil", translate("Close"))
|
||||
pt:value("main", translate("Preproxy Node"))
|
||||
pt.default = "nil"
|
||||
for k, v in pairs(nodes_table) do
|
||||
o:value(v.id, v.remarks)
|
||||
pt:depends({ [option_name("protocol")] = "_shunt", [option_name("preproxy_enabled")] = true, [option_name(e[".name"])] = v.id })
|
||||
end
|
||||
end
|
||||
end
|
||||
end)
|
||||
|
||||
o = s:option(DummyValue, option_name("shunt_tips"), " ")
|
||||
o.not_rewrite = true
|
||||
o.rawhtml = true
|
||||
o.cfgvalue = function(t, n)
|
||||
return string.format('<a style="color: red" href="../rule">%s</a>', translate("No shunt rules? Click me to go to add."))
|
||||
end
|
||||
o:depends({ [option_name("protocol")] = "_shunt" })
|
||||
|
||||
local o = s:option(Value, option_name("default_node"), string.format('* <a style="color:red">%s</a>', translate("Default")))
|
||||
o:depends({ [option_name("protocol")] = "_shunt" })
|
||||
o:value("_direct", translate("Direct Connection"))
|
||||
o:value("_blackhole", translate("Blackhole"))
|
||||
|
||||
if #nodes_table > 0 then
|
||||
for k, v in pairs(balancers_table) do
|
||||
o:value(v.id, v.remarks)
|
||||
end
|
||||
for k, v in pairs(iface_table) do
|
||||
o:value(v.id, v.remarks)
|
||||
end
|
||||
local dpt = s:option(ListValue, option_name("default_proxy_tag"), string.format('* <a style="color:red">%s</a>', translate("Default Preproxy")), translate("When using, localhost will connect this node first and then use this node to connect the default node."))
|
||||
dpt:value("nil", translate("Close"))
|
||||
dpt:value("main", translate("Preproxy Node"))
|
||||
dpt.default = "nil"
|
||||
for k, v in pairs(nodes_table) do
|
||||
o:value(v.id, v.remarks)
|
||||
dpt:depends({ [option_name("protocol")] = "_shunt", [option_name("preproxy_enabled")] = true, [option_name("default_node")] = v.id })
|
||||
end
|
||||
end
|
||||
|
||||
o = s:option(ListValue, option_name("domainStrategy"), translate("Domain Strategy"))
|
||||
o:value("AsIs")
|
||||
o:value("IPIfNonMatch")
|
||||
o:value("IPOnDemand")
|
||||
o.default = "IPOnDemand"
|
||||
o.description = "<br /><ul><li>" .. translate("'AsIs': Only use domain for routing. Default value.")
|
||||
.. "</li><li>" .. translate("'IPIfNonMatch': When no rule matches current domain, resolves it into IP addresses (A or AAAA records) and try all rules again.")
|
||||
.. "</li><li>" .. translate("'IPOnDemand': As long as there is a IP-based rule, resolves the domain into IP immediately.")
|
||||
.. "</li></ul>"
|
||||
o:depends({ [option_name("protocol")] = "_shunt" })
|
||||
|
||||
o = s:option(ListValue, option_name("domainMatcher"), translate("Domain matcher"))
|
||||
o:value("hybrid")
|
||||
o:value("linear")
|
||||
o:depends({ [option_name("protocol")] = "_shunt" })
|
||||
|
||||
-- [[ 分流模块 End ]]
|
||||
|
||||
o = s:option(Value, option_name("address"), translate("Address (Support Domain Name)"))
|
||||
|
||||
o = s:option(Value, option_name("port"), translate("Port"))
|
||||
o.datatype = "port"
|
||||
|
||||
local protocols = s.fields[option_name("protocol")].keylist
|
||||
if #protocols > 0 then
|
||||
for index, value in ipairs(protocols) do
|
||||
if not value:find("_") then
|
||||
s.fields[option_name("address")]:depends({ [option_name("protocol")] = value })
|
||||
s.fields[option_name("port")]:depends({ [option_name("protocol")] = value })
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
o = s:option(Value, option_name("username"), translate("Username"))
|
||||
o:depends({ [option_name("protocol")] = "http" })
|
||||
o:depends({ [option_name("protocol")] = "socks" })
|
||||
|
||||
o = s:option(Value, option_name("password"), translate("Password"))
|
||||
o.password = true
|
||||
o:depends({ [option_name("protocol")] = "http" })
|
||||
o:depends({ [option_name("protocol")] = "socks" })
|
||||
o:depends({ [option_name("protocol")] = "shadowsocks" })
|
||||
o:depends({ [option_name("protocol")] = "trojan" })
|
||||
|
||||
o = s:option(ListValue, option_name("security"), translate("Encrypt Method"))
|
||||
for a, t in ipairs(security_list) do o:value(t) end
|
||||
o:depends({ [option_name("protocol")] = "vmess" })
|
||||
|
||||
o = s:option(Value, option_name("encryption"), translate("Encrypt Method"))
|
||||
o.default = "none"
|
||||
o:value("none")
|
||||
o:depends({ [option_name("protocol")] = "vless" })
|
||||
|
||||
o = s:option(ListValue, option_name("x_ss_encrypt_method"), translate("Encrypt Method"))
|
||||
o.rewrite_option = "method"
|
||||
for a, t in ipairs(x_ss_encrypt_method_list) do o:value(t) end
|
||||
o:depends({ [option_name("protocol")] = "shadowsocks" })
|
||||
|
||||
o = s:option(Flag, option_name("iv_check"), translate("IV Check"))
|
||||
o:depends({ [option_name("protocol")] = "shadowsocks", [option_name("x_ss_encrypt_method")] = "aes-128-gcm" })
|
||||
o:depends({ [option_name("protocol")] = "shadowsocks", [option_name("x_ss_encrypt_method")] = "aes-256-gcm" })
|
||||
o:depends({ [option_name("protocol")] = "shadowsocks", [option_name("x_ss_encrypt_method")] = "chacha20-poly1305" })
|
||||
o:depends({ [option_name("protocol")] = "shadowsocks", [option_name("x_ss_encrypt_method")] = "xchacha20-poly1305" })
|
||||
|
||||
o = s:option(Flag, option_name("uot"), translate("UDP over TCP"), translate("Need Xray-core or sing-box as server side."))
|
||||
o:depends({ [option_name("protocol")] = "shadowsocks", [option_name("x_ss_encrypt_method")] = "2022-blake3-aes-128-gcm" })
|
||||
o:depends({ [option_name("protocol")] = "shadowsocks", [option_name("x_ss_encrypt_method")] = "2022-blake3-aes-256-gcm" })
|
||||
o:depends({ [option_name("protocol")] = "shadowsocks", [option_name("x_ss_encrypt_method")] = "2022-blake3-chacha20-poly1305" })
|
||||
|
||||
o = s:option(Value, option_name("uuid"), translate("ID"))
|
||||
o.password = true
|
||||
o:depends({ [option_name("protocol")] = "vmess" })
|
||||
o:depends({ [option_name("protocol")] = "vless" })
|
||||
|
||||
o = s:option(ListValue, option_name("flow"), translate("flow"))
|
||||
o.default = ""
|
||||
o:value("", translate("Disable"))
|
||||
o:value("xtls-rprx-vision")
|
||||
o:depends({ [option_name("protocol")] = "vless", [option_name("tls")] = true, [option_name("transport")] = "tcp" })
|
||||
|
||||
o = s:option(Flag, option_name("tls"), translate("TLS"))
|
||||
o.default = 0
|
||||
o:depends({ [option_name("protocol")] = "vmess" })
|
||||
o:depends({ [option_name("protocol")] = "vless" })
|
||||
o:depends({ [option_name("protocol")] = "socks" })
|
||||
o:depends({ [option_name("protocol")] = "trojan" })
|
||||
o:depends({ [option_name("protocol")] = "shadowsocks" })
|
||||
|
||||
o = s:option(Flag, option_name("reality"), translate("REALITY"), translate("Only recommend to use with VLESS-TCP-XTLS-Vision."))
|
||||
o.default = 0
|
||||
o:depends({ [option_name("tls")] = true, [option_name("transport")] = "tcp" })
|
||||
o:depends({ [option_name("tls")] = true, [option_name("transport")] = "h2" })
|
||||
o:depends({ [option_name("tls")] = true, [option_name("transport")] = "grpc" })
|
||||
|
||||
o = s:option(ListValue, option_name("alpn"), translate("alpn"))
|
||||
o.default = "default"
|
||||
o:value("default", translate("Default"))
|
||||
o:value("h2,http/1.1")
|
||||
o:value("h2")
|
||||
o:value("http/1.1")
|
||||
o:depends({ [option_name("tls")] = true, [option_name("reality")] = false })
|
||||
|
||||
-- o = s:option(Value, option_name("minversion"), translate("minversion"))
|
||||
-- o.default = "1.3"
|
||||
-- o:value("1.3")
|
||||
-- o:depends({ [option_name("tls")] = true })
|
||||
|
||||
o = s:option(Value, option_name("tls_serverName"), translate("Domain"))
|
||||
o:depends({ [option_name("tls")] = true })
|
||||
|
||||
o = s:option(Flag, option_name("tls_allowInsecure"), translate("allowInsecure"), translate("Whether unsafe connections are allowed. When checked, Certificate validation will be skipped."))
|
||||
o.default = "0"
|
||||
o:depends({ [option_name("tls")] = true, [option_name("reality")] = false })
|
||||
|
||||
-- [[ REALITY部分 ]] --
|
||||
o = s:option(Value, option_name("reality_publicKey"), translate("Public Key"))
|
||||
o:depends({ [option_name("tls")] = true, [option_name("reality")] = true })
|
||||
|
||||
o = s:option(Value, option_name("reality_shortId"), translate("Short Id"))
|
||||
o:depends({ [option_name("tls")] = true, [option_name("reality")] = true })
|
||||
|
||||
o = s:option(Value, option_name("reality_spiderX"), translate("Spider X"))
|
||||
o.placeholder = "/"
|
||||
o:depends({ [option_name("tls")] = true, [option_name("reality")] = true })
|
||||
|
||||
o = s:option(Flag, option_name("utls"), translate("uTLS"))
|
||||
o.default = "0"
|
||||
o:depends({ [option_name("tls")] = true, [option_name("reality")] = false })
|
||||
|
||||
o = s:option(ListValue, option_name("fingerprint"), translate("Finger Print"))
|
||||
o:value("chrome")
|
||||
o:value("firefox")
|
||||
o:value("edge")
|
||||
o:value("safari")
|
||||
o:value("360")
|
||||
o:value("qq")
|
||||
o:value("ios")
|
||||
o:value("android")
|
||||
o:value("random")
|
||||
o:value("randomized")
|
||||
o.default = "chrome"
|
||||
o:depends({ [option_name("tls")] = true, [option_name("utls")] = true })
|
||||
o:depends({ [option_name("tls")] = true, [option_name("reality")] = true })
|
||||
|
||||
o = s:option(ListValue, option_name("transport"), translate("Transport"))
|
||||
o:value("tcp", "TCP")
|
||||
o:value("mkcp", "mKCP")
|
||||
o:value("ws", "WebSocket")
|
||||
o:value("h2", "HTTP/2")
|
||||
o:value("ds", "DomainSocket")
|
||||
o:value("quic", "QUIC")
|
||||
o:value("grpc", "gRPC")
|
||||
o:depends({ [option_name("protocol")] = "vmess" })
|
||||
o:depends({ [option_name("protocol")] = "vless" })
|
||||
o:depends({ [option_name("protocol")] = "socks" })
|
||||
o:depends({ [option_name("protocol")] = "shadowsocks" })
|
||||
o:depends({ [option_name("protocol")] = "trojan" })
|
||||
|
||||
--[[
|
||||
o = s:option(ListValue, option_name("ss_transport"), translate("Transport"))
|
||||
o:value("ws", "WebSocket")
|
||||
o:value("h2", "HTTP/2")
|
||||
o:value("h2+ws", "HTTP/2 & WebSocket")
|
||||
o:depends({ [option_name("protocol")] = "shadowsocks" })
|
||||
]]--
|
||||
|
||||
o = s:option(Value, option_name("wireguard_public_key"), translate("Public Key"))
|
||||
o:depends({ [option_name("protocol")] = "wireguard" })
|
||||
|
||||
o = s:option(Value, option_name("wireguard_secret_key"), translate("Private Key"))
|
||||
o:depends({ [option_name("protocol")] = "wireguard" })
|
||||
|
||||
o = s:option(Value, option_name("wireguard_preSharedKey"), translate("Pre shared key"))
|
||||
o:depends({ [option_name("protocol")] = "wireguard" })
|
||||
|
||||
o = s:option(DynamicList, option_name("wireguard_local_address"), translate("Local Address"))
|
||||
o:depends({ [option_name("protocol")] = "wireguard" })
|
||||
|
||||
o = s:option(Value, option_name("wireguard_mtu"), translate("MTU"))
|
||||
o.default = "1420"
|
||||
o:depends({ [option_name("protocol")] = "wireguard" })
|
||||
|
||||
if api.compare_versions(api.get_app_version("xray"), ">=", "1.8.0") then
|
||||
o = s:option(Value, option_name("wireguard_reserved"), translate("Reserved"), translate("Decimal numbers separated by \",\" or Base64-encoded strings."))
|
||||
o:depends({ [option_name("protocol")] = "wireguard" })
|
||||
end
|
||||
|
||||
o = s:option(Value, option_name("wireguard_keepAlive"), translate("Keep Alive"))
|
||||
o.default = "0"
|
||||
o:depends({ [option_name("protocol")] = "wireguard" })
|
||||
|
||||
-- [[ TCP部分 ]]--
|
||||
|
||||
-- TCP伪装
|
||||
o = s:option(ListValue, option_name("tcp_guise"), translate("Camouflage Type"))
|
||||
o:value("none", "none")
|
||||
o:value("http", "http")
|
||||
o:depends({ [option_name("transport")] = "tcp" })
|
||||
|
||||
-- HTTP域名
|
||||
o = s:option(DynamicList, option_name("tcp_guise_http_host"), translate("HTTP Host"))
|
||||
o:depends({ [option_name("tcp_guise")] = "http" })
|
||||
|
||||
-- HTTP路径
|
||||
o = s:option(DynamicList, option_name("tcp_guise_http_path"), translate("HTTP Path"))
|
||||
o.placeholder = "/"
|
||||
o:depends({ [option_name("tcp_guise")] = "http" })
|
||||
|
||||
-- [[ mKCP部分 ]]--
|
||||
|
||||
o = s:option(ListValue, option_name("mkcp_guise"), translate("Camouflage Type"), translate('<br />none: default, no masquerade, data sent is packets with no characteristics.<br />srtp: disguised as an SRTP packet, it will be recognized as video call data (such as FaceTime).<br />utp: packets disguised as uTP will be recognized as bittorrent downloaded data.<br />wechat-video: packets disguised as WeChat video calls.<br />dtls: disguised as DTLS 1.2 packet.<br />wireguard: disguised as a WireGuard packet. (not really WireGuard protocol)'))
|
||||
for a, t in ipairs(header_type_list) do o:value(t) end
|
||||
o:depends({ [option_name("transport")] = "mkcp" })
|
||||
|
||||
o = s:option(Value, option_name("mkcp_mtu"), translate("KCP MTU"))
|
||||
o.default = "1350"
|
||||
o:depends({ [option_name("transport")] = "mkcp" })
|
||||
|
||||
o = s:option(Value, option_name("mkcp_tti"), translate("KCP TTI"))
|
||||
o.default = "20"
|
||||
o:depends({ [option_name("transport")] = "mkcp" })
|
||||
|
||||
o = s:option(Value, option_name("mkcp_uplinkCapacity"), translate("KCP uplinkCapacity"))
|
||||
o.default = "5"
|
||||
o:depends({ [option_name("transport")] = "mkcp" })
|
||||
|
||||
o = s:option(Value, option_name("mkcp_downlinkCapacity"), translate("KCP downlinkCapacity"))
|
||||
o.default = "20"
|
||||
o:depends({ [option_name("transport")] = "mkcp" })
|
||||
|
||||
o = s:option(Flag, option_name("mkcp_congestion"), translate("KCP Congestion"))
|
||||
o:depends({ [option_name("transport")] = "mkcp" })
|
||||
|
||||
o = s:option(Value, option_name("mkcp_readBufferSize"), translate("KCP readBufferSize"))
|
||||
o.default = "1"
|
||||
o:depends({ [option_name("transport")] = "mkcp" })
|
||||
|
||||
o = s:option(Value, option_name("mkcp_writeBufferSize"), translate("KCP writeBufferSize"))
|
||||
o.default = "1"
|
||||
o:depends({ [option_name("transport")] = "mkcp" })
|
||||
|
||||
o = s:option(Value, option_name("mkcp_seed"), translate("KCP Seed"))
|
||||
o:depends({ [option_name("transport")] = "mkcp" })
|
||||
|
||||
-- [[ WebSocket部分 ]]--
|
||||
o = s:option(Value, option_name("ws_host"), translate("WebSocket Host"))
|
||||
o:depends({ [option_name("transport")] = "ws" })
|
||||
o:depends({ [option_name("ss_transport")] = "ws" })
|
||||
|
||||
o = s:option(Value, option_name("ws_path"), translate("WebSocket Path"))
|
||||
o.placeholder = "/"
|
||||
o:depends({ [option_name("transport")] = "ws" })
|
||||
o:depends({ [option_name("ss_transport")] = "ws" })
|
||||
|
||||
-- [[ HTTP/2部分 ]]--
|
||||
o = s:option(Value, option_name("h2_host"), translate("HTTP/2 Host"))
|
||||
o:depends({ [option_name("transport")] = "h2" })
|
||||
o:depends({ [option_name("ss_transport")] = "h2" })
|
||||
|
||||
o = s:option(Value, option_name("h2_path"), translate("HTTP/2 Path"))
|
||||
o.placeholder = "/"
|
||||
o:depends({ [option_name("transport")] = "h2" })
|
||||
o:depends({ [option_name("ss_transport")] = "h2" })
|
||||
|
||||
o = s:option(Flag, option_name("h2_health_check"), translate("Health check"))
|
||||
o:depends({ [option_name("transport")] = "h2" })
|
||||
|
||||
o = s:option(Value, option_name("h2_read_idle_timeout"), translate("Idle timeout"))
|
||||
o.default = "10"
|
||||
o:depends({ [option_name("h2_health_check")] = true })
|
||||
|
||||
o = s:option(Value, option_name("h2_health_check_timeout"), translate("Health check timeout"))
|
||||
o.default = "15"
|
||||
o:depends({ [option_name("h2_health_check")] = true })
|
||||
|
||||
-- [[ DomainSocket部分 ]]--
|
||||
o = s:option(Value, option_name("ds_path"), "Path", translate("A legal file path. This file must not exist before running."))
|
||||
o:depends({ [option_name("transport")] = "ds" })
|
||||
|
||||
-- [[ QUIC部分 ]]--
|
||||
o = s:option(ListValue, option_name("quic_security"), translate("Encrypt Method"))
|
||||
o:value("none")
|
||||
o:value("aes-128-gcm")
|
||||
o:value("chacha20-poly1305")
|
||||
o:depends({ [option_name("transport")] = "quic" })
|
||||
|
||||
o = s:option(Value, option_name("quic_key"), translate("Encrypt Method") .. translate("Key"))
|
||||
o:depends({ [option_name("transport")] = "quic" })
|
||||
|
||||
o = s:option(ListValue, option_name("quic_guise"), translate("Camouflage Type"))
|
||||
for a, t in ipairs(header_type_list) do o:value(t) end
|
||||
o:depends({ [option_name("transport")] = "quic" })
|
||||
|
||||
-- [[ gRPC部分 ]]--
|
||||
o = s:option(Value, option_name("grpc_serviceName"), "ServiceName")
|
||||
o:depends({ [option_name("transport")] = "grpc" })
|
||||
|
||||
o = s:option(ListValue, option_name("grpc_mode"), "gRPC " .. translate("Transfer mode"))
|
||||
o:value("gun")
|
||||
o:value("multi")
|
||||
o:depends({ [option_name("transport")] = "grpc" })
|
||||
|
||||
o = s:option(Flag, option_name("grpc_health_check"), translate("Health check"))
|
||||
o:depends({ [option_name("transport")] = "grpc" })
|
||||
|
||||
o = s:option(Value, option_name("grpc_idle_timeout"), translate("Idle timeout"))
|
||||
o.default = "10"
|
||||
o:depends({ [option_name("grpc_health_check")] = true })
|
||||
|
||||
o = s:option(Value, option_name("grpc_health_check_timeout"), translate("Health check timeout"))
|
||||
o.default = "20"
|
||||
o:depends({ [option_name("grpc_health_check")] = true })
|
||||
|
||||
o = s:option(Flag, option_name("grpc_permit_without_stream"), translate("Permit without stream"))
|
||||
o.default = "0"
|
||||
o:depends({ [option_name("grpc_health_check")] = true })
|
||||
|
||||
o = s:option(Value, option_name("grpc_initial_windows_size"), translate("Initial Windows Size"))
|
||||
o.default = "0"
|
||||
o:depends({ [option_name("transport")] = "grpc" })
|
||||
|
||||
-- [[ Mux ]]--
|
||||
o = s:option(Flag, option_name("mux"), translate("Mux"))
|
||||
o:depends({ [option_name("protocol")] = "vmess" })
|
||||
o:depends({ [option_name("protocol")] = "vless", [option_name("flow")] = "" })
|
||||
o:depends({ [option_name("protocol")] = "http" })
|
||||
o:depends({ [option_name("protocol")] = "socks" })
|
||||
o:depends({ [option_name("protocol")] = "shadowsocks" })
|
||||
o:depends({ [option_name("protocol")] = "trojan" })
|
||||
|
||||
o = s:option(Value, option_name("mux_concurrency"), translate("Mux concurrency"))
|
||||
o.default = 8
|
||||
o:depends({ [option_name("mux")] = true })
|
||||
|
||||
-- [[ XUDP Mux ]]--
|
||||
o = s:option(Flag, option_name("xmux"), translate("xMux"))
|
||||
o.default = 1
|
||||
o:depends({ [option_name("protocol")] = "vless", [option_name("flow")] = "xtls-rprx-vision" })
|
||||
|
||||
o = s:option(Value, option_name("xudp_concurrency"), translate("XUDP Mux concurrency"))
|
||||
o.default = 8
|
||||
o:depends({ [option_name("xmux")] = true })
|
||||
|
||||
api.luci_types(arg[1], m, s, type_name, option_prefix)
|
@ -1,545 +0,0 @@
|
||||
local m, s = ...
|
||||
|
||||
local api = require "luci.passwall.api"
|
||||
|
||||
local singbox_bin = api.finded_com("singbox")
|
||||
|
||||
if not singbox_bin then
|
||||
return
|
||||
end
|
||||
|
||||
local singbox_tags = luci.sys.exec(singbox_bin .. " version | grep 'Tags:' | awk '{print $2}'")
|
||||
|
||||
local appname = api.appname
|
||||
local uci = api.uci
|
||||
|
||||
local type_name = "sing-box"
|
||||
|
||||
local option_prefix = "singbox_"
|
||||
|
||||
local function option_name(name)
|
||||
return option_prefix .. name
|
||||
end
|
||||
|
||||
local ss_method_new_list = {
|
||||
"none", "aes-128-gcm", "aes-192-gcm", "aes-256-gcm", "chacha20-ietf-poly1305", "xchacha20-ietf-poly1305", "2022-blake3-aes-128-gcm", "2022-blake3-aes-256-gcm", "2022-blake3-chacha20-poly1305"
|
||||
}
|
||||
|
||||
local ss_method_old_list = {
|
||||
"aes-128-ctr", "aes-192-ctr", "aes-256-ctr", "aes-128-cfb", "aes-192-cfb", "aes-256-cfb", "rc4-md5", "chacha20-ietf", "xchacha20",
|
||||
}
|
||||
|
||||
local security_list = { "none", "auto", "aes-128-gcm", "chacha20-poly1305", "zero" }
|
||||
|
||||
-- [[ sing-box ]]
|
||||
|
||||
s.fields["type"]:value(type_name, "Sing-Box")
|
||||
|
||||
o = s:option(ListValue, option_name("protocol"), translate("Protocol"))
|
||||
o:value("socks", "Socks")
|
||||
o:value("http", "HTTP")
|
||||
o:value("shadowsocks", "Shadowsocks")
|
||||
if singbox_tags:find("with_shadowsocksr") then
|
||||
o:value("shadowsocksr", "ShadowsocksR")
|
||||
end
|
||||
o:value("vmess", "Vmess")
|
||||
o:value("trojan", "Trojan")
|
||||
if singbox_tags:find("with_wireguard") then
|
||||
o:value("wireguard", "WireGuard")
|
||||
end
|
||||
if singbox_tags:find("with_quic") then
|
||||
o:value("hysteria", "Hysteria")
|
||||
end
|
||||
o:value("shadowtls", "ShadowTLS")
|
||||
o:value("vless", "VLESS")
|
||||
if singbox_tags:find("with_quic") then
|
||||
o:value("tuic", "TUIC")
|
||||
end
|
||||
if singbox_tags:find("with_quic") then
|
||||
o:value("hysteria2", "Hysteria2")
|
||||
end
|
||||
o:value("_shunt", translate("Shunt"))
|
||||
o:value("_iface", translate("Custom Interface") .. " (Only Support Xray)")
|
||||
|
||||
o = s:option(Value, option_name("iface"), translate("Interface"))
|
||||
o.default = "eth1"
|
||||
o:depends({ [option_name("protocol")] = "_iface" })
|
||||
|
||||
local nodes_table = {}
|
||||
local balancers_table = {}
|
||||
local iface_table = {}
|
||||
for k, e in ipairs(api.get_valid_nodes()) do
|
||||
if e.node_type == "normal" then
|
||||
nodes_table[#nodes_table + 1] = {
|
||||
id = e[".name"],
|
||||
remarks = e["remark"]
|
||||
}
|
||||
end
|
||||
if e.protocol == "_iface" then
|
||||
iface_table[#iface_table + 1] = {
|
||||
id = e[".name"],
|
||||
remarks = e["remark"]
|
||||
}
|
||||
end
|
||||
end
|
||||
|
||||
-- [[ 分流模块 ]]
|
||||
if #nodes_table > 0 then
|
||||
o = s:option(Flag, option_name("preproxy_enabled"), translate("Preproxy"))
|
||||
o:depends({ [option_name("protocol")] = "_shunt" })
|
||||
|
||||
o = s:option(Value, option_name("main_node"), string.format('<a style="color:red">%s</a>', translate("Preproxy Node")), translate("Set the node to be used as a pre-proxy. Each rule (including <code>Default</code>) has a separate switch that controls whether this rule uses the pre-proxy or not."))
|
||||
o:depends({ [option_name("protocol")] = "_shunt", [option_name("preproxy_enabled")] = true })
|
||||
for k, v in pairs(balancers_table) do
|
||||
o:value(v.id, v.remarks)
|
||||
end
|
||||
for k, v in pairs(iface_table) do
|
||||
o:value(v.id, v.remarks)
|
||||
end
|
||||
for k, v in pairs(nodes_table) do
|
||||
o:value(v.id, v.remarks)
|
||||
end
|
||||
o.default = "nil"
|
||||
end
|
||||
uci:foreach(appname, "shunt_rules", function(e)
|
||||
if e[".name"] and e.remarks then
|
||||
o = s:option(Value, option_name(e[".name"]), string.format('* <a href="%s" target="_blank">%s</a>', api.url("shunt_rules", e[".name"]), e.remarks))
|
||||
o:value("nil", translate("Close"))
|
||||
o:value("_default", translate("Default"))
|
||||
o:value("_direct", translate("Direct Connection"))
|
||||
o:value("_blackhole", translate("Blackhole"))
|
||||
o:depends({ [option_name("protocol")] = "_shunt" })
|
||||
|
||||
if #nodes_table > 0 then
|
||||
for k, v in pairs(balancers_table) do
|
||||
o:value(v.id, v.remarks)
|
||||
end
|
||||
for k, v in pairs(iface_table) do
|
||||
o:value(v.id, v.remarks)
|
||||
end
|
||||
local pt = s:option(ListValue, option_name(e[".name"] .. "_proxy_tag"), string.format('* <a style="color:red">%s</a>', e.remarks .. " " .. translate("Preproxy")))
|
||||
pt:value("nil", translate("Close"))
|
||||
pt:value("main", translate("Preproxy Node"))
|
||||
pt.default = "nil"
|
||||
for k, v in pairs(nodes_table) do
|
||||
o:value(v.id, v.remarks)
|
||||
pt:depends({ [option_name("protocol")] = "_shunt", [option_name("preproxy_enabled")] = true, [option_name(e[".name"])] = v.id })
|
||||
end
|
||||
end
|
||||
end
|
||||
end)
|
||||
|
||||
o = s:option(DummyValue, option_name("shunt_tips"), " ")
|
||||
o.not_rewrite = true
|
||||
o.rawhtml = true
|
||||
o.cfgvalue = function(t, n)
|
||||
return string.format('<a style="color: red" href="../rule">%s</a>', translate("No shunt rules? Click me to go to add."))
|
||||
end
|
||||
o:depends({ [option_name("protocol")] = "_shunt" })
|
||||
|
||||
local o = s:option(Value, option_name("default_node"), string.format('* <a style="color:red">%s</a>', translate("Default")))
|
||||
o:depends({ [option_name("protocol")] = "_shunt" })
|
||||
o:value("_direct", translate("Direct Connection"))
|
||||
o:value("_blackhole", translate("Blackhole"))
|
||||
|
||||
if #nodes_table > 0 then
|
||||
for k, v in pairs(balancers_table) do
|
||||
o:value(v.id, v.remarks)
|
||||
end
|
||||
for k, v in pairs(iface_table) do
|
||||
o:value(v.id, v.remarks)
|
||||
end
|
||||
local dpt = s:option(ListValue, option_name("default_proxy_tag"), string.format('* <a style="color:red">%s</a>', translate("Default Preproxy")), translate("When using, localhost will connect this node first and then use this node to connect the default node."))
|
||||
dpt:value("nil", translate("Close"))
|
||||
dpt:value("main", translate("Preproxy Node"))
|
||||
dpt.default = "nil"
|
||||
for k, v in pairs(nodes_table) do
|
||||
o:value(v.id, v.remarks)
|
||||
dpt:depends({ [option_name("protocol")] = "_shunt", [option_name("preproxy_enabled")] = true, [option_name("default_node")] = v.id })
|
||||
end
|
||||
end
|
||||
|
||||
-- [[ 分流模块 End ]]
|
||||
|
||||
o = s:option(Value, option_name("address"), translate("Address (Support Domain Name)"))
|
||||
|
||||
o = s:option(Value, option_name("port"), translate("Port"))
|
||||
o.datatype = "port"
|
||||
|
||||
local protocols = s.fields[option_name("protocol")].keylist
|
||||
if #protocols > 0 then
|
||||
for index, value in ipairs(protocols) do
|
||||
if not value:find("_") then
|
||||
s.fields[option_name("address")]:depends({ [option_name("protocol")] = value })
|
||||
s.fields[option_name("port")]:depends({ [option_name("protocol")] = value })
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
o = s:option(ListValue, option_name("shadowtls_version"), translate("Version"))
|
||||
o.default = "1"
|
||||
o:value("1", "ShadowTLS v1")
|
||||
o:value("2", "ShadowTLS v2")
|
||||
o:value("3", "ShadowTLS v3")
|
||||
o:depends({ [option_name("protocol")] = "shadowtls" })
|
||||
|
||||
o = s:option(Value, option_name("username"), translate("Username"))
|
||||
o:depends({ [option_name("protocol")] = "http" })
|
||||
o:depends({ [option_name("protocol")] = "socks" })
|
||||
|
||||
o = s:option(Value, option_name("password"), translate("Password"))
|
||||
o.password = true
|
||||
o:depends({ [option_name("protocol")] = "http" })
|
||||
o:depends({ [option_name("protocol")] = "socks" })
|
||||
o:depends({ [option_name("protocol")] = "shadowsocks" })
|
||||
o:depends({ [option_name("protocol")] = "shadowsocksr" })
|
||||
o:depends({ [option_name("protocol")] = "trojan" })
|
||||
o:depends({ [option_name("protocol")] = "shadowtls", [option_name("shadowtls_version")] = "2" })
|
||||
o:depends({ [option_name("protocol")] = "shadowtls", [option_name("shadowtls_version")] = "3" })
|
||||
o:depends({ [option_name("protocol")] = "tuic" })
|
||||
|
||||
o = s:option(ListValue, option_name("security"), translate("Encrypt Method"))
|
||||
for a, t in ipairs(security_list) do o:value(t) end
|
||||
o:depends({ [option_name("protocol")] = "vmess" })
|
||||
|
||||
o = s:option(ListValue, option_name("ss_method"), translate("Encrypt Method"))
|
||||
o.rewrite_option = "method"
|
||||
for a, t in ipairs(ss_method_new_list) do o:value(t) end
|
||||
for a, t in ipairs(ss_method_old_list) do o:value(t) end
|
||||
o:depends({ [option_name("protocol")] = "shadowsocks" })
|
||||
|
||||
if singbox_tags:find("with_shadowsocksr") then
|
||||
o = s:option(ListValue, option_name("ssr_method"), translate("Encrypt Method"))
|
||||
o.rewrite_option = "method"
|
||||
for a, t in ipairs(ss_method_old_list) do o:value(t) end
|
||||
o:depends({ [option_name("protocol")] = "shadowsocksr" })
|
||||
|
||||
local ssr_protocol_list = {
|
||||
"origin", "verify_simple", "verify_deflate", "verify_sha1", "auth_simple",
|
||||
"auth_sha1", "auth_sha1_v2", "auth_sha1_v4", "auth_aes128_md5",
|
||||
"auth_aes128_sha1", "auth_chain_a", "auth_chain_b", "auth_chain_c",
|
||||
"auth_chain_d", "auth_chain_e", "auth_chain_f"
|
||||
}
|
||||
|
||||
o = s:option(ListValue, option_name("ssr_protocol"), translate("Protocol"))
|
||||
for a, t in ipairs(ssr_protocol_list) do o:value(t) end
|
||||
o:depends({ [option_name("protocol")] = "shadowsocksr" })
|
||||
|
||||
o = s:option(Value, option_name("ssr_protocol_param"), translate("Protocol_param"))
|
||||
o:depends({ [option_name("protocol")] = "shadowsocksr" })
|
||||
|
||||
local ssr_obfs_list = {
|
||||
"plain", "http_simple", "http_post", "random_head", "tls_simple",
|
||||
"tls1.0_session_auth", "tls1.2_ticket_auth"
|
||||
}
|
||||
|
||||
o = s:option(ListValue, option_name("ssr_obfs"), translate("Obfs"))
|
||||
for a, t in ipairs(ssr_obfs_list) do o:value(t) end
|
||||
o:depends({ [option_name("protocol")] = "shadowsocksr" })
|
||||
|
||||
o = s:option(Value, option_name("ssr_obfs_param"), translate("Obfs_param"))
|
||||
o:depends({ [option_name("protocol")] = "shadowsocksr" })
|
||||
end
|
||||
|
||||
o = s:option(Flag, option_name("uot"), translate("UDP over TCP"), translate("Need Xray-core or sing-box as server side."))
|
||||
o:depends({ [option_name("protocol")] = "shadowsocks", [option_name("ss_method")] = "2022-blake3-aes-128-gcm" })
|
||||
o:depends({ [option_name("protocol")] = "shadowsocks", [option_name("ss_method")] = "2022-blake3-aes-256-gcm" })
|
||||
o:depends({ [option_name("protocol")] = "shadowsocks", [option_name("ss_method")] = "2022-blake3-chacha20-poly1305" })
|
||||
|
||||
o = s:option(Value, option_name("uuid"), translate("ID"))
|
||||
o.password = true
|
||||
o:depends({ [option_name("protocol")] = "vmess" })
|
||||
o:depends({ [option_name("protocol")] = "vless" })
|
||||
o:depends({ [option_name("protocol")] = "tuic" })
|
||||
|
||||
o = s:option(Value, option_name("alter_id"), "Alter ID")
|
||||
o.datatype = "uinteger"
|
||||
o.default = "0"
|
||||
o:depends({ [option_name("protocol")] = "vmess" })
|
||||
|
||||
o = s:option(Flag, option_name("global_padding"), "global_padding", translate("Protocol parameter. Will waste traffic randomly if enabled."))
|
||||
o.default = "0"
|
||||
o:depends({ [option_name("protocol")] = "vmess" })
|
||||
|
||||
o = s:option(Flag, option_name("authenticated_length"), "authenticated_length", translate("Protocol parameter. Enable length block encryption."))
|
||||
o.default = "0"
|
||||
o:depends({ [option_name("protocol")] = "vmess" })
|
||||
|
||||
o = s:option(ListValue, option_name("flow"), translate("flow"))
|
||||
o.default = ""
|
||||
o:value("", translate("Disable"))
|
||||
o:value("xtls-rprx-vision")
|
||||
o:depends({ [option_name("protocol")] = "vless", [option_name("tls")] = true })
|
||||
|
||||
if singbox_tags:find("with_quic") then
|
||||
o = s:option(Value, option_name("hysteria_obfs"), translate("Obfs Password"))
|
||||
o:depends({ [option_name("protocol")] = "hysteria" })
|
||||
|
||||
o = s:option(ListValue, option_name("hysteria_auth_type"), translate("Auth Type"))
|
||||
o:value("disable", translate("Disable"))
|
||||
o:value("string", translate("STRING"))
|
||||
o:value("base64", translate("BASE64"))
|
||||
o:depends({ [option_name("protocol")] = "hysteria" })
|
||||
|
||||
o = s:option(Value, option_name("hysteria_auth_password"), translate("Auth Password"))
|
||||
o.password = true
|
||||
o:depends({ [option_name("protocol")] = "hysteria", [option_name("hysteria_auth_type")] = "string"})
|
||||
o:depends({ [option_name("protocol")] = "hysteria", [option_name("hysteria_auth_type")] = "base64"})
|
||||
|
||||
o = s:option(Value, option_name("hysteria_up_mbps"), translate("Max upload Mbps"))
|
||||
o.default = "10"
|
||||
o:depends({ [option_name("protocol")] = "hysteria" })
|
||||
|
||||
o = s:option(Value, option_name("hysteria_down_mbps"), translate("Max download Mbps"))
|
||||
o.default = "50"
|
||||
o:depends({ [option_name("protocol")] = "hysteria" })
|
||||
|
||||
o = s:option(Value, option_name("hysteria_recv_window_conn"), translate("QUIC stream receive window"))
|
||||
o:depends({ [option_name("protocol")] = "hysteria" })
|
||||
|
||||
o = s:option(Value, option_name("hysteria_recv_window"), translate("QUIC connection receive window"))
|
||||
o:depends({ [option_name("protocol")] = "hysteria" })
|
||||
|
||||
o = s:option(Flag, option_name("hysteria_disable_mtu_discovery"), translate("Disable MTU detection"))
|
||||
o:depends({ [option_name("protocol")] = "hysteria" })
|
||||
|
||||
o = s:option(Value, option_name("hysteria_alpn"), translate("QUIC TLS ALPN"))
|
||||
o:depends({ [option_name("protocol")] = "hysteria" })
|
||||
end
|
||||
|
||||
if singbox_tags:find("with_quic") then
|
||||
o = s:option(ListValue, option_name("tuic_congestion_control"), translate("Congestion control algorithm"))
|
||||
o.default = "cubic"
|
||||
o:value("bbr", translate("BBR"))
|
||||
o:value("cubic", translate("CUBIC"))
|
||||
o:value("new_reno", translate("New Reno"))
|
||||
o:depends({ [option_name("protocol")] = "tuic" })
|
||||
|
||||
o = s:option(ListValue, option_name("tuic_udp_relay_mode"), translate("UDP relay mode"))
|
||||
o.default = "native"
|
||||
o:value("native", translate("native"))
|
||||
o:value("quic", translate("QUIC"))
|
||||
o:depends({ [option_name("protocol")] = "tuic" })
|
||||
|
||||
--[[
|
||||
o = s:option(Flag, option_name("tuic_udp_over_stream"), translate("UDP over stream"))
|
||||
o:depends({ [option_name("protocol")] = "tuic" })
|
||||
]]--
|
||||
|
||||
o = s:option(Flag, option_name("tuic_zero_rtt_handshake"), translate("Enable 0-RTT QUIC handshake"))
|
||||
o.default = 0
|
||||
o:depends({ [option_name("protocol")] = "tuic" })
|
||||
|
||||
o = s:option(Value, option_name("tuic_heartbeat"), translate("Heartbeat interval(second)"))
|
||||
o.datatype = "uinteger"
|
||||
o.default = "3"
|
||||
o:depends({ [option_name("protocol")] = "tuic" })
|
||||
|
||||
o = s:option(Value, option_name("tuic_alpn"), translate("QUIC TLS ALPN"))
|
||||
o:depends({ [option_name("protocol")] = "tuic" })
|
||||
end
|
||||
|
||||
if singbox_tags:find("with_quic") then
|
||||
o = s:option(Value, option_name("hysteria2_up_mbps"), translate("Max upload Mbps"))
|
||||
o:depends({ [option_name("protocol")] = "hysteria2" })
|
||||
|
||||
o = s:option(Value, option_name("hysteria2_down_mbps"), translate("Max download Mbps"))
|
||||
o:depends({ [option_name("protocol")] = "hysteria2" })
|
||||
|
||||
o = s:option(ListValue, option_name("hysteria2_obfs_type"), translate("Obfs Type"))
|
||||
o:value("", translate("Disable"))
|
||||
o:value("salamander")
|
||||
o:depends({ [option_name("protocol")] = "hysteria2" })
|
||||
|
||||
o = s:option(Value, option_name("hysteria2_obfs_password"), translate("Obfs Password"))
|
||||
o:depends({ [option_name("protocol")] = "hysteria2" })
|
||||
|
||||
o = s:option(Value, option_name("hysteria2_auth_password"), translate("Auth Password"))
|
||||
o.password = true
|
||||
o:depends({ [option_name("protocol")] = "hysteria2"})
|
||||
end
|
||||
|
||||
o = s:option(Flag, option_name("tls"), translate("TLS"))
|
||||
o.default = 0
|
||||
o:depends({ [option_name("protocol")] = "vmess" })
|
||||
o:depends({ [option_name("protocol")] = "vless" })
|
||||
o:depends({ [option_name("protocol")] = "socks" })
|
||||
o:depends({ [option_name("protocol")] = "trojan" })
|
||||
o:depends({ [option_name("protocol")] = "shadowsocks" })
|
||||
o:depends({ [option_name("protocol")] = "shadowtls" })
|
||||
|
||||
o = s:option(ListValue, option_name("alpn"), translate("alpn"))
|
||||
o.default = "default"
|
||||
o:value("default", translate("Default"))
|
||||
o:value("h2,http/1.1")
|
||||
o:value("h2")
|
||||
o:value("http/1.1")
|
||||
o:depends({ [option_name("tls")] = true })
|
||||
|
||||
o = s:option(Value, option_name("tls_serverName"), translate("Domain"))
|
||||
o:depends({ [option_name("tls")] = true })
|
||||
o:depends({ [option_name("protocol")] = "hysteria"})
|
||||
o:depends({ [option_name("protocol")] = "tuic" })
|
||||
o:depends({ [option_name("protocol")] = "hysteria2" })
|
||||
|
||||
o = s:option(Flag, option_name("tls_allowInsecure"), translate("allowInsecure"), translate("Whether unsafe connections are allowed. When checked, Certificate validation will be skipped."))
|
||||
o.default = "0"
|
||||
o:depends({ [option_name("tls")] = true })
|
||||
o:depends({ [option_name("protocol")] = "hysteria"})
|
||||
o:depends({ [option_name("protocol")] = "tuic" })
|
||||
o:depends({ [option_name("protocol")] = "hysteria2" })
|
||||
|
||||
if singbox_tags:find("with_utls") then
|
||||
o = s:option(Flag, option_name("utls"), translate("uTLS"))
|
||||
o.default = "0"
|
||||
o:depends({ [option_name("tls")] = true })
|
||||
|
||||
o = s:option(ListValue, option_name("fingerprint"), translate("Finger Print"))
|
||||
o:value("chrome")
|
||||
o:value("firefox")
|
||||
o:value("edge")
|
||||
o:value("safari")
|
||||
-- o:value("360")
|
||||
o:value("qq")
|
||||
o:value("ios")
|
||||
-- o:value("android")
|
||||
o:value("random")
|
||||
-- o:value("randomized")
|
||||
o.default = "chrome"
|
||||
o:depends({ [option_name("tls")] = true, [option_name("utls")] = true })
|
||||
|
||||
-- [[ REALITY部分 ]] --
|
||||
o = s:option(Flag, option_name("reality"), translate("REALITY"))
|
||||
o.default = 0
|
||||
o:depends({ [option_name("protocol")] = "vless", [option_name("utls")] = true })
|
||||
o:depends({ [option_name("protocol")] = "vmess", [option_name("utls")] = true })
|
||||
o:depends({ [option_name("protocol")] = "shadowsocks", [option_name("utls")] = true })
|
||||
o:depends({ [option_name("protocol")] = "socks", [option_name("utls")] = true })
|
||||
o:depends({ [option_name("protocol")] = "trojan", [option_name("utls")] = true })
|
||||
|
||||
o = s:option(Value, option_name("reality_publicKey"), translate("Public Key"))
|
||||
o:depends({ [option_name("utls")] = true, [option_name("reality")] = true })
|
||||
|
||||
o = s:option(Value, option_name("reality_shortId"), translate("Short Id"))
|
||||
o:depends({ [option_name("utls")] = true, [option_name("reality")] = true })
|
||||
end
|
||||
|
||||
o = s:option(ListValue, option_name("transport"), translate("Transport"))
|
||||
o:value("tcp", "TCP")
|
||||
o:value("http", "HTTP")
|
||||
o:value("ws", "WebSocket")
|
||||
if singbox_tags:find("with_quic") then
|
||||
o:value("quic", "QUIC")
|
||||
end
|
||||
if singbox_tags:find("with_grpc") then
|
||||
o:value("grpc", "gRPC")
|
||||
else o:value("grpc", "gRPC-lite")
|
||||
end
|
||||
o:depends({ [option_name("protocol")] = "vmess" })
|
||||
o:depends({ [option_name("protocol")] = "vless" })
|
||||
o:depends({ [option_name("protocol")] = "socks" })
|
||||
o:depends({ [option_name("protocol")] = "shadowsocks" })
|
||||
o:depends({ [option_name("protocol")] = "trojan" })
|
||||
|
||||
if singbox_tags:find("with_wireguard") then
|
||||
o = s:option(Value, option_name("wireguard_public_key"), translate("Public Key"))
|
||||
o:depends({ [option_name("protocol")] = "wireguard" })
|
||||
|
||||
o = s:option(Value, option_name("wireguard_secret_key"), translate("Private Key"))
|
||||
o:depends({ [option_name("protocol")] = "wireguard" })
|
||||
|
||||
o = s:option(Value, option_name("wireguard_preSharedKey"), translate("Pre shared key"))
|
||||
o:depends({ [option_name("protocol")] = "wireguard" })
|
||||
|
||||
o = s:option(DynamicList, option_name("wireguard_local_address"), translate("Local Address"))
|
||||
o:depends({ [option_name("protocol")] = "wireguard" })
|
||||
|
||||
o = s:option(Value, option_name("wireguard_mtu"), translate("MTU"))
|
||||
o.default = "1420"
|
||||
o:depends({ [option_name("protocol")] = "wireguard" })
|
||||
|
||||
o = s:option(Value, option_name("wireguard_reserved"), translate("Reserved"), translate("Decimal numbers separated by \",\" or Base64-encoded strings."))
|
||||
o:depends({ [option_name("protocol")] = "wireguard" })
|
||||
end
|
||||
|
||||
-- [[ HTTP部分 ]]--
|
||||
o = s:option(Value, option_name("http_host"), translate("HTTP Host"))
|
||||
o:depends({ [option_name("transport")] = "http" })
|
||||
|
||||
o = s:option(Value, option_name("http_path"), translate("HTTP Path"))
|
||||
o.placeholder = "/"
|
||||
o:depends({ [option_name("transport")] = "http" })
|
||||
|
||||
o = s:option(Flag, option_name("http_h2_health_check"), translate("Health check"))
|
||||
o:depends({ [option_name("tls")] = true, [option_name("transport")] = "http" })
|
||||
|
||||
o = s:option(Value, option_name("http_h2_read_idle_timeout"), translate("Idle timeout"))
|
||||
o.default = "10"
|
||||
o:depends({ [option_name("tls")] = true, [option_name("transport")] = "http", [option_name("http_h2_health_check")] = true })
|
||||
|
||||
o = s:option(Value, option_name("http_h2_health_check_timeout"), translate("Health check timeout"))
|
||||
o.default = "15"
|
||||
o:depends({ [option_name("tls")] = true, [option_name("transport")] = "http", [option_name("http_h2_health_check")] = true })
|
||||
|
||||
-- [[ WebSocket部分 ]]--
|
||||
o = s:option(Value, option_name("ws_host"), translate("WebSocket Host"))
|
||||
o:depends({ [option_name("transport")] = "ws" })
|
||||
|
||||
o = s:option(Value, option_name("ws_path"), translate("WebSocket Path"))
|
||||
o.placeholder = "/"
|
||||
o:depends({ [option_name("transport")] = "ws" })
|
||||
|
||||
o = s:option(Flag, option_name("ws_enableEarlyData"), translate("Enable early data"))
|
||||
o:depends({ [option_name("transport")] = "ws" })
|
||||
|
||||
o = s:option(Value, option_name("ws_maxEarlyData"), translate("Early data length"))
|
||||
o.default = "1024"
|
||||
o:depends({ [option_name("ws_enableEarlyData")] = true })
|
||||
|
||||
o = s:option(Value, option_name("ws_earlyDataHeaderName"), translate("Early data header name"), translate("Recommended value: Sec-WebSocket-Protocol"))
|
||||
o:depends({ [option_name("ws_enableEarlyData")] = true })
|
||||
|
||||
-- [[ gRPC部分 ]]--
|
||||
o = s:option(Value, option_name("grpc_serviceName"), "ServiceName")
|
||||
o:depends({ [option_name("transport")] = "grpc" })
|
||||
|
||||
o = s:option(Flag, option_name("grpc_health_check"), translate("Health check"))
|
||||
o:depends({ [option_name("transport")] = "grpc" })
|
||||
|
||||
o = s:option(Value, option_name("grpc_idle_timeout"), translate("Idle timeout"))
|
||||
o.default = "10"
|
||||
o:depends({ [option_name("grpc_health_check")] = true })
|
||||
|
||||
o = s:option(Value, option_name("grpc_health_check_timeout"), translate("Health check timeout"))
|
||||
o.default = "20"
|
||||
o:depends({ [option_name("grpc_health_check")] = true })
|
||||
|
||||
o = s:option(Flag, option_name("grpc_permit_without_stream"), translate("Permit without stream"))
|
||||
o.default = "0"
|
||||
o:depends({ [option_name("grpc_health_check")] = true })
|
||||
|
||||
-- [[ Mux ]]--
|
||||
o = s:option(Flag, option_name("mux"), translate("Mux"))
|
||||
o.rmempty = false
|
||||
o:depends({ [option_name("protocol")] = "vmess" })
|
||||
o:depends({ [option_name("protocol")] = "vless", [option_name("flow")] = "" })
|
||||
o:depends({ [option_name("protocol")] = "http" })
|
||||
o:depends({ [option_name("protocol")] = "socks" })
|
||||
o:depends({ [option_name("protocol")] = "shadowsocks", [option_name("uot")] = "" })
|
||||
o:depends({ [option_name("protocol")] = "trojan" })
|
||||
|
||||
o = s:option(ListValue, option_name("mux_type"), translate("Mux"))
|
||||
o:value("smux")
|
||||
o:value("yamux")
|
||||
o:value("h2mux")
|
||||
o:depends({ [option_name("mux")] = true })
|
||||
|
||||
o = s:option(Value, option_name("mux_concurrency"), translate("Mux concurrency"))
|
||||
o.default = 8
|
||||
o:depends({ [option_name("mux")] = true })
|
||||
|
||||
o = s:option(Flag, option_name("mux_padding"), translate("Padding"))
|
||||
o.default = 0
|
||||
o:depends({ [option_name("mux")] = true })
|
||||
|
||||
api.luci_types(arg[1], m, s, type_name, option_prefix)
|
@ -1,57 +0,0 @@
|
||||
local m, s = ...
|
||||
|
||||
local api = require "luci.passwall.api"
|
||||
|
||||
if not api.is_finded("sslocal") then
|
||||
return
|
||||
end
|
||||
|
||||
local type_name = "SS-Rust"
|
||||
|
||||
local option_prefix = "ssrust_"
|
||||
|
||||
local function option_name(name)
|
||||
return option_prefix .. name
|
||||
end
|
||||
|
||||
local ssrust_encrypt_method_list = {
|
||||
"plain", "none",
|
||||
"aes-128-gcm", "aes-256-gcm", "chacha20-ietf-poly1305",
|
||||
"2022-blake3-aes-128-gcm", "2022-blake3-aes-256-gcm", "2022-blake3-chacha20-poly1305"
|
||||
}
|
||||
|
||||
-- [[ Shadowsocks Rust ]]
|
||||
|
||||
s.fields["type"]:value(type_name, translate("Shadowsocks Rust"))
|
||||
|
||||
o = s:option(Value, option_name("address"), translate("Address (Support Domain Name)"))
|
||||
|
||||
o = s:option(Value, option_name("port"), translate("Port"))
|
||||
o.datatype = "port"
|
||||
|
||||
o = s:option(Value, option_name("password"), translate("Password"))
|
||||
o.password = true
|
||||
|
||||
o = s:option(Value, option_name("method"), translate("Encrypt Method"))
|
||||
for a, t in ipairs(ssrust_encrypt_method_list) do o:value(t) end
|
||||
|
||||
o = s:option(Value, option_name("timeout"), translate("Connection Timeout"))
|
||||
o.datatype = "uinteger"
|
||||
o.default = 300
|
||||
|
||||
o = s:option(ListValue, option_name("tcp_fast_open"), "TCP " .. translate("Fast Open"), translate("Need node support required"))
|
||||
o:value("false")
|
||||
o:value("true")
|
||||
|
||||
o = s:option(ListValue, option_name("plugin"), translate("plugin"))
|
||||
o:value("none", translate("none"))
|
||||
if api.is_finded("xray-plugin") then o:value("xray-plugin") end
|
||||
if api.is_finded("v2ray-plugin") then o:value("v2ray-plugin") end
|
||||
if api.is_finded("obfs-local") then o:value("obfs-local") end
|
||||
|
||||
o = s:option(Value, option_name("plugin_opts"), translate("opts"))
|
||||
o:depends({ [option_name("plugin")] = "xray-plugin"})
|
||||
o:depends({ [option_name("plugin")] = "v2ray-plugin"})
|
||||
o:depends({ [option_name("plugin")] = "obfs-local"})
|
||||
|
||||
api.luci_types(arg[1], m, s, type_name, option_prefix)
|
@ -1,58 +0,0 @@
|
||||
local m, s = ...
|
||||
|
||||
local api = require "luci.passwall.api"
|
||||
|
||||
if not api.is_finded("ss-local") and not api.is_finded("ss-redir") then
|
||||
return
|
||||
end
|
||||
|
||||
local type_name = "SS"
|
||||
|
||||
local option_prefix = "ss_"
|
||||
|
||||
local function option_name(name)
|
||||
return option_prefix .. name
|
||||
end
|
||||
|
||||
local ss_encrypt_method_list = {
|
||||
"rc4-md5", "aes-128-cfb", "aes-192-cfb", "aes-256-cfb", "aes-128-ctr",
|
||||
"aes-192-ctr", "aes-256-ctr", "bf-cfb", "salsa20", "chacha20", "chacha20-ietf",
|
||||
"aes-128-gcm", "aes-192-gcm", "aes-256-gcm", "chacha20-ietf-poly1305",
|
||||
"xchacha20-ietf-poly1305"
|
||||
}
|
||||
|
||||
-- [[ Shadowsocks Libev ]]
|
||||
|
||||
s.fields["type"]:value(type_name, translate("Shadowsocks Libev"))
|
||||
|
||||
o = s:option(Value, option_name("address"), translate("Address (Support Domain Name)"))
|
||||
|
||||
o = s:option(Value, option_name("port"), translate("Port"))
|
||||
o.datatype = "port"
|
||||
|
||||
o = s:option(Value, option_name("password"), translate("Password"))
|
||||
o.password = true
|
||||
|
||||
o = s:option(Value, option_name("method"), translate("Encrypt Method"))
|
||||
for a, t in ipairs(ss_encrypt_method_list) do o:value(t) end
|
||||
|
||||
o = s:option(Value, option_name("timeout"), translate("Connection Timeout"))
|
||||
o.datatype = "uinteger"
|
||||
o.default = 300
|
||||
|
||||
o = s:option(ListValue, option_name("tcp_fast_open"), "TCP " .. translate("Fast Open"), translate("Need node support required"))
|
||||
o:value("false")
|
||||
o:value("true")
|
||||
|
||||
o = s:option(ListValue, option_name("plugin"), translate("plugin"))
|
||||
o:value("none", translate("none"))
|
||||
if api.is_finded("xray-plugin") then o:value("xray-plugin") end
|
||||
if api.is_finded("v2ray-plugin") then o:value("v2ray-plugin") end
|
||||
if api.is_finded("obfs-local") then o:value("obfs-local") end
|
||||
|
||||
o = s:option(Value, option_name("plugin_opts"), translate("opts"))
|
||||
o:depends({ [option_name("plugin")] = "xray-plugin"})
|
||||
o:depends({ [option_name("plugin")] = "v2ray-plugin"})
|
||||
o:depends({ [option_name("plugin")] = "obfs-local"})
|
||||
|
||||
api.luci_types(arg[1], m, s, type_name, option_prefix)
|
@ -1,69 +0,0 @@
|
||||
local m, s = ...
|
||||
|
||||
local api = require "luci.passwall.api"
|
||||
|
||||
if not api.is_finded("ssr-local") and not api.is_finded("ssr-redir")then
|
||||
return
|
||||
end
|
||||
|
||||
local type_name = "SSR"
|
||||
|
||||
local option_prefix = "ssr_"
|
||||
|
||||
local function option_name(name)
|
||||
return option_prefix .. name
|
||||
end
|
||||
|
||||
local ssr_encrypt_method_list = {
|
||||
"none", "table", "rc2-cfb", "rc4", "rc4-md5", "rc4-md5-6", "aes-128-cfb",
|
||||
"aes-192-cfb", "aes-256-cfb", "aes-128-ctr", "aes-192-ctr", "aes-256-ctr",
|
||||
"bf-cfb", "camellia-128-cfb", "camellia-192-cfb", "camellia-256-cfb",
|
||||
"cast5-cfb", "des-cfb", "idea-cfb", "seed-cfb", "salsa20", "chacha20",
|
||||
"chacha20-ietf"
|
||||
}
|
||||
|
||||
local ssr_protocol_list = {
|
||||
"origin", "verify_simple", "verify_deflate", "verify_sha1", "auth_simple",
|
||||
"auth_sha1", "auth_sha1_v2", "auth_sha1_v4", "auth_aes128_md5",
|
||||
"auth_aes128_sha1", "auth_chain_a", "auth_chain_b", "auth_chain_c",
|
||||
"auth_chain_d", "auth_chain_e", "auth_chain_f"
|
||||
}
|
||||
local ssr_obfs_list = {
|
||||
"plain", "http_simple", "http_post", "random_head", "tls_simple",
|
||||
"tls1.0_session_auth", "tls1.2_ticket_auth"
|
||||
}
|
||||
|
||||
-- [[ ShadowsocksR Libev ]]
|
||||
|
||||
s.fields["type"]:value(type_name, translate("ShadowsocksR Libev"))
|
||||
|
||||
o = s:option(Value, option_name("address"), translate("Address (Support Domain Name)"))
|
||||
|
||||
o = s:option(Value, option_name("port"), translate("Port"))
|
||||
o.datatype = "port"
|
||||
|
||||
o = s:option(Value, option_name("password"), translate("Password"))
|
||||
o.password = true
|
||||
|
||||
o = s:option(ListValue, option_name("method"), translate("Encrypt Method"))
|
||||
for a, t in ipairs(ssr_encrypt_method_list) do o:value(t) end
|
||||
|
||||
o = s:option(ListValue, option_name("protocol"), translate("Protocol"))
|
||||
for a, t in ipairs(ssr_protocol_list) do o:value(t) end
|
||||
|
||||
o = s:option(Value, option_name("protocol_param"), translate("Protocol_param"))
|
||||
|
||||
o = s:option(ListValue, option_name("obfs"), translate("Obfs"))
|
||||
for a, t in ipairs(ssr_obfs_list) do o:value(t) end
|
||||
|
||||
o = s:option(Value, option_name("obfs_param"), translate("Obfs_param"))
|
||||
|
||||
o = s:option(Value, option_name("timeout"), translate("Connection Timeout"))
|
||||
o.datatype = "uinteger"
|
||||
o.default = 300
|
||||
|
||||
o = s:option(ListValue, option_name("tcp_fast_open"), "TCP " .. translate("Fast Open"), translate("Need node support required"))
|
||||
o:value("false")
|
||||
o:value("true")
|
||||
|
||||
api.luci_types(arg[1], m, s, type_name, option_prefix)
|
@ -1,119 +0,0 @@
|
||||
local m, s = ...
|
||||
|
||||
local api = require "luci.passwall.api"
|
||||
|
||||
if not api.finded_com("trojan-go") then
|
||||
return
|
||||
end
|
||||
|
||||
local type_name = "Trojan-Go"
|
||||
|
||||
local option_prefix = "trojan_go_"
|
||||
|
||||
local function option_name(name)
|
||||
return option_prefix .. name
|
||||
end
|
||||
|
||||
local encrypt_methods_ss_aead = {
|
||||
"chacha20-ietf-poly1305",
|
||||
"aes-128-gcm",
|
||||
"aes-256-gcm",
|
||||
}
|
||||
|
||||
-- [[ Trojan Go ]]
|
||||
|
||||
s.fields["type"]:value(type_name, "Trojan-Go")
|
||||
|
||||
o = s:option(Value, option_name("address"), translate("Address (Support Domain Name)"))
|
||||
|
||||
o = s:option(Value, option_name("port"), translate("Port"))
|
||||
o.datatype = "port"
|
||||
|
||||
o = s:option(Value, option_name("password"), translate("Password"))
|
||||
o.password = true
|
||||
|
||||
o = s:option(ListValue, option_name("tcp_fast_open"), "TCP " .. translate("Fast Open"), translate("Need node support required"))
|
||||
o:value("false")
|
||||
o:value("true")
|
||||
|
||||
o = s:option(Flag, option_name("tls"), translate("TLS"))
|
||||
o.default = 1
|
||||
|
||||
o = s:option(Flag, option_name("tls_allowInsecure"), translate("allowInsecure"), translate("Whether unsafe connections are allowed. When checked, Certificate validation will be skipped."))
|
||||
o.default = "0"
|
||||
o:depends({ [option_name("tls")] = true })
|
||||
|
||||
o = s:option(Value, option_name("tls_serverName"), translate("Domain"))
|
||||
o:depends({ [option_name("tls")] = true })
|
||||
|
||||
o = s:option(Flag, option_name("tls_sessionTicket"), translate("Session Ticket"))
|
||||
o.default = "0"
|
||||
o:depends({ [option_name("tls")] = true })
|
||||
|
||||
o = s:option(ListValue, option_name("fingerprint"), translate("Finger Print"))
|
||||
o:value("disable", translate("Disable"))
|
||||
o:value("firefox")
|
||||
o:value("chrome")
|
||||
o:value("ios")
|
||||
o.default = "disable"
|
||||
o:depends({ [option_name("tls")] = true })
|
||||
|
||||
o = s:option(ListValue, option_name("transport"), translate("Transport"))
|
||||
o:value("original", translate("Original"))
|
||||
o:value("ws", "WebSocket")
|
||||
o.default = "original"
|
||||
o.rewrite_option = "trojan_transport"
|
||||
|
||||
o = s:option(ListValue, option_name("plugin_type"), translate("Transport Plugin"))
|
||||
o:value("plaintext", "Plain Text")
|
||||
o:value("shadowsocks", "ShadowSocks")
|
||||
o:value("other", "Other")
|
||||
o.default = "plaintext"
|
||||
o:depends({ [option_name("tls")] = false, [option_name("transport")] = "original" })
|
||||
|
||||
o = s:option(Value, option_name("plugin_cmd"), translate("Plugin Binary"))
|
||||
o.placeholder = "eg: /usr/bin/v2ray-plugin"
|
||||
o:depends({ [option_name("plugin_type")] = "shadowsocks" })
|
||||
o:depends({ [option_name("plugin_type")] = "other" })
|
||||
|
||||
o = s:option(Value, option_name("plugin_option"), translate("Plugin Option"))
|
||||
o.placeholder = "eg: obfs=http;obfs-host=www.baidu.com"
|
||||
o:depends({ [option_name("plugin_type")] = "shadowsocks" })
|
||||
o:depends({ [option_name("plugin_type")] = "other" })
|
||||
|
||||
o = s:option(DynamicList, option_name("plugin_arg"), translate("Plugin Option Args"))
|
||||
o.placeholder = "eg: [\"-config\", \"test.json\"]"
|
||||
o:depends({ [option_name("plugin_type")] = "shadowsocks" })
|
||||
o:depends({ [option_name("plugin_type")] = "other" })
|
||||
|
||||
o = s:option(Value, option_name("ws_host"), translate("WebSocket Host"))
|
||||
o:depends({ [option_name("transport")] = "ws" })
|
||||
|
||||
o = s:option(Value, option_name("ws_path"), translate("WebSocket Path"))
|
||||
o.placeholder = "/"
|
||||
o:depends({ [option_name("transport")] = "ws" })
|
||||
|
||||
-- [[ Shadowsocks2 ]] --
|
||||
o = s:option(Flag, option_name("ss_aead"), translate("Shadowsocks secondary encryption"))
|
||||
o.default = "0"
|
||||
|
||||
o = s:option(ListValue, option_name("ss_aead_method"), translate("Encrypt Method"))
|
||||
for _, v in ipairs(encrypt_methods_ss_aead) do o:value(v, v) end
|
||||
o.default = "aes-128-gcm"
|
||||
o:depends({ [option_name("ss_aead")] = true })
|
||||
|
||||
o = s:option(Value, option_name("ss_aead_pwd"), translate("Password"))
|
||||
o.password = true
|
||||
o:depends({ [option_name("ss_aead")] = true })
|
||||
|
||||
o = s:option(Flag, option_name("smux"), translate("Smux"))
|
||||
|
||||
o = s:option(Value, option_name("mux_concurrency"), translate("Mux concurrency"))
|
||||
o.default = 8
|
||||
o:depends({ [option_name("smux")] = true })
|
||||
|
||||
o = s:option(Value, option_name("smux_idle_timeout"), translate("Mux idle timeout"))
|
||||
o.default = 60
|
||||
o:depends({ [option_name("smux")] = true })
|
||||
|
||||
api.luci_types(arg[1], m, s, type_name, option_prefix)
|
@ -1,56 +0,0 @@
|
||||
local m, s = ...
|
||||
|
||||
local api = require "luci.passwall.api"
|
||||
|
||||
if not api.is_finded("trojan-plus") then
|
||||
return
|
||||
end
|
||||
|
||||
local type_name = "Trojan-Plus"
|
||||
|
||||
local option_prefix = "trojan_plus_"
|
||||
|
||||
local function option_name(name)
|
||||
return option_prefix .. name
|
||||
end
|
||||
|
||||
-- [[ Trojan Plus ]]
|
||||
|
||||
s.fields["type"]:value(type_name, "Trojan-Plus")
|
||||
|
||||
o = s:option(Value, option_name("address"), translate("Address (Support Domain Name)"))
|
||||
|
||||
o = s:option(Value, option_name("port"), translate("Port"))
|
||||
o.datatype = "port"
|
||||
|
||||
o = s:option(Value, option_name("password"), translate("Password"))
|
||||
o.password = true
|
||||
|
||||
o = s:option(ListValue, option_name("tcp_fast_open"), "TCP " .. translate("Fast Open"), translate("Need node support required"))
|
||||
o:value("false")
|
||||
o:value("true")
|
||||
|
||||
o = s:option(Flag, option_name("tls"), translate("TLS"))
|
||||
o.default = 0
|
||||
o.validate = function(self, value, t)
|
||||
if value then
|
||||
local type = s.fields["type"]:formvalue(t) or ""
|
||||
if value == "0" and type == type_name then
|
||||
return nil, translate("Original Trojan only supported 'tls', please choose 'tls'.")
|
||||
end
|
||||
return value
|
||||
end
|
||||
end
|
||||
|
||||
o = s:option(Flag, option_name("tls_allowInsecure"), translate("allowInsecure"), translate("Whether unsafe connections are allowed. When checked, Certificate validation will be skipped."))
|
||||
o.default = "0"
|
||||
o:depends({ [option_name("tls")] = true })
|
||||
|
||||
o = s:option(Value, option_name("tls_serverName"), translate("Domain"))
|
||||
o:depends({ [option_name("tls")] = true })
|
||||
|
||||
o = s:option(Flag, option_name("tls_sessionTicket"), translate("Session Ticket"))
|
||||
o.default = "0"
|
||||
o:depends({ [option_name("tls")] = true })
|
||||
|
||||
api.luci_types(arg[1], m, s, type_name, option_prefix)
|
@ -1,133 +0,0 @@
|
||||
local m, s = ...
|
||||
|
||||
local api = require "luci.passwall.api"
|
||||
|
||||
if not api.is_finded("tuic-client") then
|
||||
return
|
||||
end
|
||||
|
||||
local type_name = "TUIC"
|
||||
|
||||
local option_prefix = "tuic_"
|
||||
|
||||
local function option_name(name)
|
||||
return option_prefix .. name
|
||||
end
|
||||
|
||||
-- [[ TUIC ]]
|
||||
|
||||
s.fields["type"]:value(type_name, translate("TUIC"))
|
||||
|
||||
o = s:option(Value, option_name("address"), translate("Address (Support Domain Name)"))
|
||||
|
||||
o = s:option(Value, option_name("port"), translate("Port"))
|
||||
o.datatype = "port"
|
||||
|
||||
o = s:option(Value, option_name("uuid"), translate("ID"))
|
||||
o.password = true
|
||||
|
||||
-- Tuic Password for remote server connect
|
||||
o = s:option(Value, option_name("password"), translate("TUIC User Password For Connect Remote Server"))
|
||||
o.password = true
|
||||
o.rmempty = true
|
||||
o.default = ""
|
||||
o.rewrite_option = o.option
|
||||
|
||||
--[[
|
||||
-- Tuic username for local socks connect
|
||||
o = s:option(Value, option_name("socks_username"), translate("TUIC UserName For Local Socks"))
|
||||
o.rmempty = true
|
||||
o.default = ""
|
||||
o.rewrite_option = o.option
|
||||
|
||||
-- Tuic Password for local socks connect
|
||||
o = s:option(Value, option_name("socks_password"), translate("TUIC Password For Local Socks"))
|
||||
o.password = true
|
||||
o.rmempty = true
|
||||
o.default = ""
|
||||
o.rewrite_option = o.option
|
||||
--]]
|
||||
|
||||
o = s:option(Value, option_name("ip"), translate("Set the TUIC proxy server ip address"))
|
||||
o.datatype = "ipaddr"
|
||||
o.rmempty = true
|
||||
o.rewrite_option = o.option
|
||||
|
||||
o = s:option(ListValue, option_name("udp_relay_mode"), translate("UDP relay mode"))
|
||||
o:value("native", translate("native"))
|
||||
o:value("quic", translate("QUIC"))
|
||||
o.default = "native"
|
||||
o.rmempty = true
|
||||
o.rewrite_option = o.option
|
||||
|
||||
o = s:option(ListValue, option_name("congestion_control"), translate("Congestion control algorithm"))
|
||||
o:value("bbr", translate("BBR"))
|
||||
o:value("cubic", translate("CUBIC"))
|
||||
o:value("new_reno", translate("New Reno"))
|
||||
o.default = "cubic"
|
||||
o.rmempty = true
|
||||
o.rewrite_option = o.option
|
||||
|
||||
o = s:option(Value, option_name("heartbeat"), translate("Heartbeat interval(second)"))
|
||||
o.datatype = "uinteger"
|
||||
o.default = "3"
|
||||
o.rmempty = true
|
||||
o.rewrite_option = o.option
|
||||
|
||||
o = s:option(Value, option_name("timeout"), translate("Timeout for establishing a connection to server(second)"))
|
||||
o.datatype = "uinteger"
|
||||
o.default = "8"
|
||||
o.rmempty = true
|
||||
o.rewrite_option = o.option
|
||||
|
||||
o = s:option(Value, option_name("gc_interval"), translate("Garbage collection interval(second)"))
|
||||
o.datatype = "uinteger"
|
||||
o.default = "3"
|
||||
o.rmempty = true
|
||||
o.rewrite_option = o.option
|
||||
|
||||
o = s:option(Value, option_name("gc_lifetime"), translate("Garbage collection lifetime(second)"))
|
||||
o.datatype = "uinteger"
|
||||
o.default = "15"
|
||||
o.rmempty = true
|
||||
o.rewrite_option = o.option
|
||||
|
||||
o = s:option(Value, option_name("send_window"), translate("TUIC send window"))
|
||||
o.datatype = "uinteger"
|
||||
o.default = 20971520
|
||||
o.rmempty = true
|
||||
o.rewrite_option = o.option
|
||||
|
||||
o = s:option(Value, option_name("receive_window"), translate("TUIC receive window"))
|
||||
o.datatype = "uinteger"
|
||||
o.default = 10485760
|
||||
o.rmempty = true
|
||||
o.rewrite_option = o.option
|
||||
|
||||
o = s:option(Value, option_name("max_package_size"), translate("TUIC Maximum packet size the socks5 server can receive from external, in bytes"))
|
||||
o.datatype = "uinteger"
|
||||
o.default = 1500
|
||||
o.rmempty = true
|
||||
o.rewrite_option = o.option
|
||||
|
||||
--Tuic settings for the local inbound socks5 server
|
||||
o = s:option(Flag, option_name("dual_stack"), translate("Set if the listening socket should be dual-stack"))
|
||||
o.default = 0
|
||||
o.rmempty = true
|
||||
o.rewrite_option = o.option
|
||||
|
||||
o = s:option(Flag, option_name("disable_sni"), translate("Disable SNI"))
|
||||
o.default = 0
|
||||
o.rmempty = true
|
||||
o.rewrite_option = o.option
|
||||
|
||||
o = s:option(Flag, option_name("zero_rtt_handshake"), translate("Enable 0-RTT QUIC handshake"))
|
||||
o.default = 0
|
||||
o.rmempty = true
|
||||
o.rewrite_option = o.option
|
||||
|
||||
o = s:option(DynamicList, option_name("tls_alpn"), translate("TLS ALPN"))
|
||||
o.rmempty = true
|
||||
o.rewrite_option = o.option
|
||||
|
||||
api.luci_types(arg[1], m, s, type_name, option_prefix)
|
@ -1,65 +0,0 @@
|
||||
local api = require "luci.passwall.api"
|
||||
|
||||
m = Map("passwall_server", translate("Server-Side"))
|
||||
|
||||
t = m:section(NamedSection, "global", "global")
|
||||
t.anonymous = true
|
||||
t.addremove = false
|
||||
|
||||
e = t:option(Flag, "enable", translate("Enable"))
|
||||
e.rmempty = false
|
||||
|
||||
t = m:section(TypedSection, "user", translate("Users Manager"))
|
||||
t.anonymous = true
|
||||
t.addremove = true
|
||||
t.sortable = true
|
||||
t.template = "cbi/tblsection"
|
||||
t.extedit = api.url("server_user", "%s")
|
||||
function t.create(e, t)
|
||||
local uuid = api.gen_uuid()
|
||||
t = uuid
|
||||
TypedSection.create(e, t)
|
||||
luci.http.redirect(e.extedit:format(t))
|
||||
end
|
||||
function t.remove(e, t)
|
||||
e.map.proceed = true
|
||||
e.map:del(t)
|
||||
luci.http.redirect(api.url("server"))
|
||||
end
|
||||
|
||||
e = t:option(Flag, "enable", translate("Enable"))
|
||||
e.width = "5%"
|
||||
e.rmempty = false
|
||||
|
||||
e = t:option(DummyValue, "status", translate("Status"))
|
||||
e.rawhtml = true
|
||||
e.cfgvalue = function(t, n)
|
||||
return string.format('<font class="_users_status">%s</font>', translate("Collecting data..."))
|
||||
end
|
||||
|
||||
e = t:option(DummyValue, "remarks", translate("Remarks"))
|
||||
e.width = "15%"
|
||||
|
||||
---- Type
|
||||
e = t:option(DummyValue, "type", translate("Type"))
|
||||
e.cfgvalue = function(t, n)
|
||||
local v = Value.cfgvalue(t, n)
|
||||
if v then
|
||||
if v == "sing-box" or v == "Xray" then
|
||||
local protocol = m:get(n, "protocol")
|
||||
return v .. " -> " .. protocol
|
||||
end
|
||||
return v
|
||||
end
|
||||
end
|
||||
|
||||
e = t:option(DummyValue, "port", translate("Port"))
|
||||
|
||||
e = t:option(Flag, "log", translate("Log"))
|
||||
e.default = "1"
|
||||
e.rmempty = false
|
||||
|
||||
m:append(Template("passwall/server/log"))
|
||||
|
||||
m:append(Template("passwall/server/users_list_status"))
|
||||
return m
|
@ -1,41 +0,0 @@
|
||||
local m, s = ...
|
||||
|
||||
local api = require "luci.passwall.api"
|
||||
|
||||
if not api.finded_com("brook") then
|
||||
return
|
||||
end
|
||||
|
||||
local type_name = "Brook"
|
||||
|
||||
local option_prefix = "brook_"
|
||||
|
||||
local function option_name(name)
|
||||
return option_prefix .. name
|
||||
end
|
||||
|
||||
-- [[ Brook ]]
|
||||
|
||||
s.fields["type"]:value(type_name, translate("Brook"))
|
||||
|
||||
o = s:option(Value, option_name("port"), translate("Listen Port"))
|
||||
o.datatype = "port"
|
||||
|
||||
o = s:option(ListValue, option_name("protocol"), translate("Protocol"))
|
||||
o:value("server", "Brook")
|
||||
o:value("wsserver", "WebSocket")
|
||||
|
||||
--o = s:option(Flag, option_name("tls"), translate("Use TLS"))
|
||||
--o:depends({ [option_name("protocol")] = "wsserver" })
|
||||
|
||||
o = s:option(Value, option_name("password"), translate("Password"))
|
||||
o.password = true
|
||||
|
||||
o = s:option(Value, option_name("ws_path"), translate("WebSocket Path"))
|
||||
o:depends({ [option_name("protocol")] = "wsserver" })
|
||||
|
||||
o = s:option(Flag, option_name("log"), translate("Log"))
|
||||
o.default = "1"
|
||||
o.rmempty = false
|
||||
|
||||
api.luci_types(arg[1], m, s, type_name, option_prefix)
|
@ -1,77 +0,0 @@
|
||||
local m, s = ...
|
||||
|
||||
local api = require "luci.passwall.api"
|
||||
|
||||
if not api.finded_com("hysteria") then
|
||||
return
|
||||
end
|
||||
|
||||
local type_name = "Hysteria2"
|
||||
|
||||
local option_prefix = "hysteria2_"
|
||||
|
||||
local function option_name(name)
|
||||
return option_prefix .. name
|
||||
end
|
||||
|
||||
-- [[ Hysteria2 ]]
|
||||
|
||||
s.fields["type"]:value(type_name, "Hysteria2")
|
||||
|
||||
o = s:option(Value, option_name("port"), translate("Listen Port"))
|
||||
o.datatype = "port"
|
||||
|
||||
o = s:option(Value, option_name("obfs"), translate("Obfs Password"))
|
||||
o.rewrite_option = o.option
|
||||
|
||||
o = s:option(Value, option_name("auth_password"), translate("Auth Password"))
|
||||
o.password = true
|
||||
o.rewrite_option = o.option
|
||||
|
||||
o = s:option(Flag, option_name("udp"), translate("UDP"))
|
||||
o.default = "1"
|
||||
o.rewrite_option = o.option
|
||||
|
||||
o = s:option(Value, option_name("up_mbps"), translate("Max upload Mbps"))
|
||||
o.default = "100"
|
||||
o.rewrite_option = o.option
|
||||
|
||||
o = s:option(Value, option_name("down_mbps"), translate("Max download Mbps"))
|
||||
o.default = "100"
|
||||
o.rewrite_option = o.option
|
||||
|
||||
o = s:option(Flag, option_name("ignoreClientBandwidth"), translate("ignoreClientBandwidth"))
|
||||
o.default = "0"
|
||||
o.rewrite_option = o.option
|
||||
|
||||
o = s:option(FileUpload, option_name("tls_certificateFile"), translate("Public key absolute path"), translate("as:") .. "/etc/ssl/fullchain.pem")
|
||||
o.default = m:get(s.section, "tls_certificateFile") or "/etc/config/ssl/" .. arg[1] .. ".pem"
|
||||
o.validate = function(self, value, t)
|
||||
if value and value ~= "" then
|
||||
if not nixio.fs.access(value) then
|
||||
return nil, translate("Can't find this file!")
|
||||
else
|
||||
return value
|
||||
end
|
||||
end
|
||||
return nil
|
||||
end
|
||||
|
||||
o = s:option(FileUpload, option_name("tls_keyFile"), translate("Private key absolute path"), translate("as:") .. "/etc/ssl/private.key")
|
||||
o.default = m:get(s.section, "tls_keyFile") or "/etc/config/ssl/" .. arg[1] .. ".key"
|
||||
o.validate = function(self, value, t)
|
||||
if value and value ~= "" then
|
||||
if not nixio.fs.access(value) then
|
||||
return nil, translate("Can't find this file!")
|
||||
else
|
||||
return value
|
||||
end
|
||||
end
|
||||
return nil
|
||||
end
|
||||
|
||||
o = s:option(Flag, option_name("log"), translate("Log"))
|
||||
o.default = "1"
|
||||
o.rmempty = false
|
||||
|
||||
api.luci_types(arg[1], m, s, type_name, option_prefix)
|
@ -1,386 +0,0 @@
|
||||
local m, s = ...
|
||||
|
||||
local api = require "luci.passwall.api"
|
||||
|
||||
if not api.finded_com("xray") then
|
||||
return
|
||||
end
|
||||
|
||||
local type_name = "Xray"
|
||||
|
||||
local option_prefix = "xray_"
|
||||
|
||||
local function option_name(name)
|
||||
return option_prefix .. name
|
||||
end
|
||||
|
||||
local x_ss_method_list = {
|
||||
"aes-128-gcm", "aes-256-gcm", "chacha20-poly1305", "xchacha20-poly1305", "2022-blake3-aes-128-gcm", "2022-blake3-aes-256-gcm", "2022-blake3-chacha20-poly1305"
|
||||
}
|
||||
|
||||
local header_type_list = {
|
||||
"none", "srtp", "utp", "wechat-video", "dtls", "wireguard"
|
||||
}
|
||||
|
||||
-- [[ Xray ]]
|
||||
|
||||
s.fields["type"]:value(type_name, "Xray")
|
||||
|
||||
o = s:option(ListValue, option_name("protocol"), translate("Protocol"))
|
||||
o:value("vmess", "Vmess")
|
||||
o:value("vless", "VLESS")
|
||||
o:value("http", "HTTP")
|
||||
o:value("socks", "Socks")
|
||||
o:value("shadowsocks", "Shadowsocks")
|
||||
o:value("trojan", "Trojan")
|
||||
o:value("dokodemo-door", "dokodemo-door")
|
||||
|
||||
o = s:option(Value, option_name("port"), translate("Listen Port"))
|
||||
o.datatype = "port"
|
||||
|
||||
o = s:option(Flag, option_name("auth"), translate("Auth"))
|
||||
o.validate = function(self, value, t)
|
||||
if value and value == "1" then
|
||||
local user_v = s.fields[option_name("username")]:formvalue(t) or ""
|
||||
local pass_v = s.fields[option_name("password")]:formvalue(t) or ""
|
||||
if user_v == "" or pass_v == "" then
|
||||
return nil, translate("Username and Password must be used together!")
|
||||
end
|
||||
end
|
||||
return value
|
||||
end
|
||||
o:depends({ [option_name("protocol")] = "socks" })
|
||||
o:depends({ [option_name("protocol")] = "http" })
|
||||
|
||||
o = s:option(Value, option_name("username"), translate("Username"))
|
||||
o:depends({ [option_name("auth")] = true })
|
||||
|
||||
o = s:option(Value, option_name("password"), translate("Password"))
|
||||
o.password = true
|
||||
o:depends({ [option_name("auth")] = true })
|
||||
o:depends({ [option_name("protocol")] = "shadowsocks" })
|
||||
|
||||
o = s:option(ListValue, option_name("d_protocol"), translate("Destination protocol"))
|
||||
o:value("tcp", "TCP")
|
||||
o:value("udp", "UDP")
|
||||
o:value("tcp,udp", "TCP,UDP")
|
||||
o:depends({ [option_name("protocol")] = "dokodemo-door" })
|
||||
|
||||
o = s:option(Value, option_name("d_address"), translate("Destination address"))
|
||||
o:depends({ [option_name("protocol")] = "dokodemo-door" })
|
||||
|
||||
o = s:option(Value, option_name("d_port"), translate("Destination port"))
|
||||
o.datatype = "port"
|
||||
o:depends({ [option_name("protocol")] = "dokodemo-door" })
|
||||
|
||||
o = s:option(Value, option_name("decryption"), translate("Encrypt Method"))
|
||||
o.default = "none"
|
||||
o:depends({ [option_name("protocol")] = "vless" })
|
||||
|
||||
o = s:option(ListValue, option_name("x_ss_method"), translate("Encrypt Method"))
|
||||
o.rewrite_option = "method"
|
||||
for a, t in ipairs(x_ss_method_list) do o:value(t) end
|
||||
o:depends({ [option_name("protocol")] = "shadowsocks" })
|
||||
|
||||
o = s:option(Flag, option_name("iv_check"), translate("IV Check"))
|
||||
o:depends({ [option_name("protocol")] = "shadowsocks" })
|
||||
|
||||
o = s:option(ListValue, option_name("ss_network"), translate("Transport"))
|
||||
o.default = "tcp,udp"
|
||||
o:value("tcp", "TCP")
|
||||
o:value("udp", "UDP")
|
||||
o:value("tcp,udp", "TCP,UDP")
|
||||
o:depends({ [option_name("protocol")] = "shadowsocks" })
|
||||
|
||||
o = s:option(Flag, option_name("udp_forward"), translate("UDP Forward"))
|
||||
o.default = "1"
|
||||
o.rmempty = false
|
||||
o:depends({ [option_name("protocol")] = "socks" })
|
||||
|
||||
o = s:option(DynamicList, option_name("uuid"), translate("ID") .. "/" .. translate("Password"))
|
||||
for i = 1, 3 do
|
||||
o:value(api.gen_uuid(1))
|
||||
end
|
||||
o:depends({ [option_name("protocol")] = "vmess" })
|
||||
o:depends({ [option_name("protocol")] = "vless" })
|
||||
o:depends({ [option_name("protocol")] = "trojan" })
|
||||
|
||||
o = s:option(ListValue, option_name("flow"), translate("flow"))
|
||||
o.default = ""
|
||||
o:value("", translate("Disable"))
|
||||
o:value("xtls-rprx-vision")
|
||||
o:depends({ [option_name("protocol")] = "vless", [option_name("tls")] = true, [option_name("transport")] = "tcp" })
|
||||
|
||||
o = s:option(Flag, option_name("tls"), translate("TLS"))
|
||||
o.default = 0
|
||||
o.validate = function(self, value, t)
|
||||
if value then
|
||||
local reality = s.fields[option_name("reality")]:formvalue(t)
|
||||
if reality and reality == "1" then return value end
|
||||
if value == "1" then
|
||||
local ca = s.fields[option_name("tls_certificateFile")]:formvalue(t) or ""
|
||||
local key = s.fields[option_name("tls_keyFile")]:formvalue(t) or ""
|
||||
if ca == "" or key == "" then
|
||||
return nil, translate("Public key and Private key path can not be empty!")
|
||||
end
|
||||
end
|
||||
return value
|
||||
end
|
||||
end
|
||||
o:depends({ [option_name("protocol")] = "vmess" })
|
||||
o:depends({ [option_name("protocol")] = "vless" })
|
||||
o:depends({ [option_name("protocol")] = "socks" })
|
||||
o:depends({ [option_name("protocol")] = "shadowsocks" })
|
||||
o:depends({ [option_name("protocol")] = "trojan" })
|
||||
|
||||
-- [[ REALITY部分 ]] --
|
||||
o = s:option(Flag, option_name("reality"), translate("REALITY"))
|
||||
o.default = 0
|
||||
o:depends({ [option_name("tls")] = true })
|
||||
|
||||
o = s:option(Value, option_name("reality_private_key"), translate("Private Key"))
|
||||
o:depends({ [option_name("reality")] = true })
|
||||
|
||||
o = s:option(Value, option_name("reality_shortId"), translate("Short Id"))
|
||||
o:depends({ [option_name("reality")] = true })
|
||||
|
||||
o = s:option(Value, option_name("reality_dest"), translate("Dest"))
|
||||
o.default = "google.com:443"
|
||||
o:depends({ [option_name("reality")] = true })
|
||||
|
||||
o = s:option(Value, option_name("reality_serverNames"), translate("serverNames"))
|
||||
o:depends({ [option_name("reality")] = true })
|
||||
|
||||
o = s:option(ListValue, option_name("alpn"), translate("alpn"))
|
||||
o.default = "h2,http/1.1"
|
||||
o:value("h2,http/1.1")
|
||||
o:value("h2")
|
||||
o:value("http/1.1")
|
||||
o:depends({ [option_name("tls")] = true })
|
||||
|
||||
-- o = s:option(Value, option_name("minversion"), translate("minversion"))
|
||||
-- o.default = "1.3"
|
||||
-- o:value("1.3")
|
||||
--o:depends({ [option_name("tls")] = true })
|
||||
|
||||
-- [[ TLS部分 ]] --
|
||||
|
||||
o = s:option(FileUpload, option_name("tls_certificateFile"), translate("Public key absolute path"), translate("as:") .. "/etc/ssl/fullchain.pem")
|
||||
o.default = m:get(s.section, "tls_certificateFile") or "/etc/config/ssl/" .. arg[1] .. ".pem"
|
||||
o:depends({ [option_name("tls")] = true, [option_name("reality")] = false })
|
||||
o.validate = function(self, value, t)
|
||||
if value and value ~= "" then
|
||||
if not nixio.fs.access(value) then
|
||||
return nil, translate("Can't find this file!")
|
||||
else
|
||||
return value
|
||||
end
|
||||
end
|
||||
return nil
|
||||
end
|
||||
|
||||
o = s:option(FileUpload, option_name("tls_keyFile"), translate("Private key absolute path"), translate("as:") .. "/etc/ssl/private.key")
|
||||
o.default = m:get(s.section, "tls_keyFile") or "/etc/config/ssl/" .. arg[1] .. ".key"
|
||||
o:depends({ [option_name("tls")] = true, [option_name("reality")] = false })
|
||||
o.validate = function(self, value, t)
|
||||
if value and value ~= "" then
|
||||
if not nixio.fs.access(value) then
|
||||
return nil, translate("Can't find this file!")
|
||||
else
|
||||
return value
|
||||
end
|
||||
end
|
||||
return nil
|
||||
end
|
||||
|
||||
o = s:option(ListValue, option_name("transport"), translate("Transport"))
|
||||
o:value("tcp", "TCP")
|
||||
o:value("mkcp", "mKCP")
|
||||
o:value("ws", "WebSocket")
|
||||
o:value("h2", "HTTP/2")
|
||||
o:value("ds", "DomainSocket")
|
||||
o:value("quic", "QUIC")
|
||||
o:value("grpc", "gRPC")
|
||||
o:depends({ [option_name("protocol")] = "vmess" })
|
||||
o:depends({ [option_name("protocol")] = "vless" })
|
||||
o:depends({ [option_name("protocol")] = "socks" })
|
||||
o:depends({ [option_name("protocol")] = "shadowsocks" })
|
||||
o:depends({ [option_name("protocol")] = "trojan" })
|
||||
|
||||
-- [[ WebSocket部分 ]]--
|
||||
|
||||
o = s:option(Value, option_name("ws_host"), translate("WebSocket Host"))
|
||||
o:depends({ [option_name("transport")] = "ws" })
|
||||
|
||||
o = s:option(Value, option_name("ws_path"), translate("WebSocket Path"))
|
||||
o:depends({ [option_name("transport")] = "ws" })
|
||||
|
||||
-- [[ HTTP/2部分 ]]--
|
||||
|
||||
o = s:option(Value, option_name("h2_host"), translate("HTTP/2 Host"))
|
||||
o:depends({ [option_name("transport")] = "h2" })
|
||||
|
||||
o = s:option(Value, option_name("h2_path"), translate("HTTP/2 Path"))
|
||||
o:depends({ [option_name("transport")] = "h2" })
|
||||
|
||||
-- [[ TCP部分 ]]--
|
||||
|
||||
-- TCP伪装
|
||||
o = s:option(ListValue, option_name("tcp_guise"), translate("Camouflage Type"))
|
||||
o:value("none", "none")
|
||||
o:value("http", "http")
|
||||
o:depends({ [option_name("transport")] = "tcp" })
|
||||
|
||||
-- HTTP域名
|
||||
o = s:option(DynamicList, option_name("tcp_guise_http_host"), translate("HTTP Host"))
|
||||
o:depends({ [option_name("tcp_guise")] = "http" })
|
||||
|
||||
-- HTTP路径
|
||||
o = s:option(DynamicList, option_name("tcp_guise_http_path"), translate("HTTP Path"))
|
||||
o:depends({ [option_name("tcp_guise")] = "http" })
|
||||
|
||||
-- [[ mKCP部分 ]]--
|
||||
|
||||
o = s:option(ListValue, option_name("mkcp_guise"), translate("Camouflage Type"), translate('<br />none: default, no masquerade, data sent is packets with no characteristics.<br />srtp: disguised as an SRTP packet, it will be recognized as video call data (such as FaceTime).<br />utp: packets disguised as uTP will be recognized as bittorrent downloaded data.<br />wechat-video: packets disguised as WeChat video calls.<br />dtls: disguised as DTLS 1.2 packet.<br />wireguard: disguised as a WireGuard packet. (not really WireGuard protocol)'))
|
||||
for a, t in ipairs(header_type_list) do o:value(t) end
|
||||
o:depends({ [option_name("transport")] = "mkcp" })
|
||||
|
||||
o = s:option(Value, option_name("mkcp_mtu"), translate("KCP MTU"))
|
||||
o.default = "1350"
|
||||
o:depends({ [option_name("transport")] = "mkcp" })
|
||||
|
||||
o = s:option(Value, option_name("mkcp_tti"), translate("KCP TTI"))
|
||||
o.default = "20"
|
||||
o:depends({ [option_name("transport")] = "mkcp" })
|
||||
|
||||
o = s:option(Value, option_name("mkcp_uplinkCapacity"), translate("KCP uplinkCapacity"))
|
||||
o.default = "5"
|
||||
o:depends({ [option_name("transport")] = "mkcp" })
|
||||
|
||||
o = s:option(Value, option_name("mkcp_downlinkCapacity"), translate("KCP downlinkCapacity"))
|
||||
o.default = "20"
|
||||
o:depends({ [option_name("transport")] = "mkcp" })
|
||||
|
||||
o = s:option(Flag, option_name("mkcp_congestion"), translate("KCP Congestion"))
|
||||
o:depends({ [option_name("transport")] = "mkcp" })
|
||||
|
||||
o = s:option(Value, option_name("mkcp_readBufferSize"), translate("KCP readBufferSize"))
|
||||
o.default = "1"
|
||||
o:depends({ [option_name("transport")] = "mkcp" })
|
||||
|
||||
o = s:option(Value, option_name("mkcp_writeBufferSize"), translate("KCP writeBufferSize"))
|
||||
o.default = "1"
|
||||
o:depends({ [option_name("transport")] = "mkcp" })
|
||||
|
||||
o = s:option(Value, option_name("mkcp_seed"), translate("KCP Seed"))
|
||||
o:depends({ [option_name("transport")] = "mkcp" })
|
||||
|
||||
-- [[ DomainSocket部分 ]]--
|
||||
|
||||
o = s:option(Value, option_name("ds_path"), "Path", translate("A legal file path. This file must not exist before running."))
|
||||
o:depends({ [option_name("transport")] = "ds" })
|
||||
|
||||
-- [[ QUIC部分 ]]--
|
||||
o = s:option(ListValue, option_name("quic_security"), translate("Encrypt Method"))
|
||||
o:value("none")
|
||||
o:value("aes-128-gcm")
|
||||
o:value("chacha20-poly1305")
|
||||
o:depends({ [option_name("transport")] = "quic" })
|
||||
|
||||
o = s:option(Value, option_name("quic_key"), translate("Encrypt Method") .. translate("Key"))
|
||||
o:depends({ [option_name("transport")] = "quic" })
|
||||
|
||||
o = s:option(ListValue, option_name("quic_guise"), translate("Camouflage Type"))
|
||||
for a, t in ipairs(header_type_list) do o:value(t) end
|
||||
o:depends({ [option_name("transport")] = "quic" })
|
||||
|
||||
-- [[ gRPC部分 ]]--
|
||||
o = s:option(Value, option_name("grpc_serviceName"), "ServiceName")
|
||||
o:depends({ [option_name("transport")] = "grpc" })
|
||||
|
||||
o = s:option(Flag, option_name("acceptProxyProtocol"), translate("acceptProxyProtocol"), translate("Whether to receive PROXY protocol, when this node want to be fallback or forwarded by proxy, it must be enable, otherwise it cannot be used."))
|
||||
o:depends({ [option_name("transport")] = "tcp" })
|
||||
o:depends({ [option_name("transport")] = "ws" })
|
||||
|
||||
-- [[ Fallback部分 ]]--
|
||||
o = s:option(Flag, option_name("fallback"), translate("Fallback"))
|
||||
o:depends({ [option_name("protocol")] = "vless", [option_name("transport")] = "tcp" })
|
||||
o:depends({ [option_name("protocol")] = "trojan", [option_name("transport")] = "tcp" })
|
||||
|
||||
--[[
|
||||
o = s:option(Value, option_name("fallback_alpn"), "Fallback alpn")
|
||||
o:depends({ [option_name("fallback")] = true })
|
||||
|
||||
o = s:option(Value, option_name("fallback_path"), "Fallback path")
|
||||
o:depends({ [option_name("fallback")] = true })
|
||||
|
||||
o = s:option(Value, option_name("fallback_dest"), "Fallback dest")
|
||||
o:depends({ [option_name("fallback")] = true })
|
||||
|
||||
o = s:option(Value, option_name("fallback_xver"), "Fallback xver")
|
||||
o.default = 0
|
||||
o:depends({ [option_name("fallback")] = true })
|
||||
]]--
|
||||
|
||||
o = s:option(DynamicList, option_name("fallback_list"), "Fallback", translate("dest,path"))
|
||||
o:depends({ [option_name("fallback")] = true })
|
||||
|
||||
o = s:option(Flag, option_name("bind_local"), translate("Bind Local"), translate("When selected, it can only be accessed locally, It is recommended to turn on when using reverse proxies or be fallback."))
|
||||
o.default = "0"
|
||||
|
||||
o = s:option(Flag, option_name("accept_lan"), translate("Accept LAN Access"), translate("When selected, it can accessed lan , this will not be safe!"))
|
||||
o.default = "0"
|
||||
|
||||
local nodes_table = {}
|
||||
for k, e in ipairs(api.get_valid_nodes()) do
|
||||
if e.node_type == "normal" and e.type == type_name then
|
||||
nodes_table[#nodes_table + 1] = {
|
||||
id = e[".name"],
|
||||
remarks = e["remark"]
|
||||
}
|
||||
end
|
||||
end
|
||||
|
||||
o = s:option(ListValue, option_name("outbound_node"), translate("outbound node"))
|
||||
o:value("nil", translate("Close"))
|
||||
o:value("_socks", translate("Custom Socks"))
|
||||
o:value("_http", translate("Custom HTTP"))
|
||||
o:value("_iface", translate("Custom Interface") .. " (Only Support Xray)")
|
||||
for k, v in pairs(nodes_table) do o:value(v.id, v.remarks) end
|
||||
o.default = "nil"
|
||||
|
||||
o = s:option(Value, option_name("outbound_node_address"), translate("Address (Support Domain Name)"))
|
||||
o:depends({ [option_name("outbound_node")] = "_socks"})
|
||||
o:depends({ [option_name("outbound_node")] = "_http"})
|
||||
|
||||
o = s:option(Value, option_name("outbound_node_port"), translate("Port"))
|
||||
o.datatype = "port"
|
||||
o:depends({ [option_name("outbound_node")] = "_socks"})
|
||||
o:depends({ [option_name("outbound_node")] = "_http"})
|
||||
|
||||
o = s:option(Value, option_name("outbound_node_username"), translate("Username"))
|
||||
o:depends({ [option_name("outbound_node")] = "_socks"})
|
||||
o:depends({ [option_name("outbound_node")] = "_http"})
|
||||
|
||||
o = s:option(Value, option_name("outbound_node_password"), translate("Password"))
|
||||
o.password = true
|
||||
o:depends({ [option_name("outbound_node")] = "_socks"})
|
||||
o:depends({ [option_name("outbound_node")] = "_http"})
|
||||
|
||||
o = s:option(Value, option_name("outbound_node_iface"), translate("Interface"))
|
||||
o.default = "eth1"
|
||||
o:depends({ [option_name("outbound_node")] = "_iface"})
|
||||
|
||||
o = s:option(Flag, option_name("log"), translate("Log"))
|
||||
o.default = "1"
|
||||
o.rmempty = false
|
||||
|
||||
o = s:option(ListValue, option_name("loglevel"), translate("Log Level"))
|
||||
o.default = "warning"
|
||||
o:value("debug")
|
||||
o:value("info")
|
||||
o:value("warning")
|
||||
o:value("error")
|
||||
o:depends({ [option_name("log")] = true })
|
||||
|
||||
api.luci_types(arg[1], m, s, type_name, option_prefix)
|
@ -1,376 +0,0 @@
|
||||
local m, s = ...
|
||||
|
||||
local api = require "luci.passwall.api"
|
||||
|
||||
local singbox_bin = api.finded_com("singbox")
|
||||
|
||||
if not singbox_bin then
|
||||
return
|
||||
end
|
||||
|
||||
local singbox_tags = luci.sys.exec(singbox_bin .. " version | grep 'Tags:' | awk '{print $2}'")
|
||||
|
||||
local type_name = "sing-box"
|
||||
|
||||
local option_prefix = "singbox_"
|
||||
|
||||
local function option_name(name)
|
||||
return option_prefix .. name
|
||||
end
|
||||
|
||||
local ss_method_list = {
|
||||
"none", "aes-128-gcm", "aes-192-gcm", "aes-256-gcm", "chacha20-ietf-poly1305", "xchacha20-ietf-poly1305",
|
||||
"2022-blake3-aes-128-gcm", "2022-blake3-aes-256-gcm", "2022-blake3-chacha20-poly1305"
|
||||
}
|
||||
|
||||
-- [[ Sing-Box ]]
|
||||
|
||||
s.fields["type"]:value(type_name, "Sing-Box")
|
||||
|
||||
o = s:option(ListValue, option_name("protocol"), translate("Protocol"))
|
||||
o:value("mixed", "Mixed")
|
||||
o:value("socks", "Socks")
|
||||
o:value("http", "HTTP")
|
||||
o:value("shadowsocks", "Shadowsocks")
|
||||
o:value("vmess", "Vmess")
|
||||
o:value("vless", "VLESS")
|
||||
o:value("trojan", "Trojan")
|
||||
o:value("naive", "Naive")
|
||||
if singbox_tags:find("with_quic") then
|
||||
o:value("hysteria", "Hysteria")
|
||||
end
|
||||
if singbox_tags:find("with_quic") then
|
||||
o:value("tuic", "TUIC")
|
||||
end
|
||||
if singbox_tags:find("with_quic") then
|
||||
o:value("hysteria2", "Hysteria2")
|
||||
end
|
||||
o:value("direct", "Direct")
|
||||
|
||||
o = s:option(Value, option_name("port"), translate("Listen Port"))
|
||||
o.datatype = "port"
|
||||
|
||||
o = s:option(Flag, option_name("auth"), translate("Auth"))
|
||||
o.validate = function(self, value, t)
|
||||
if value and value == "1" then
|
||||
local user_v = s.fields[option_name("username")]:formvalue(t) or ""
|
||||
local pass_v = s.fields[option_name("password")]:formvalue(t) or ""
|
||||
if user_v == "" or pass_v == "" then
|
||||
return nil, translate("Username and Password must be used together!")
|
||||
end
|
||||
end
|
||||
return value
|
||||
end
|
||||
o:depends({ [option_name("protocol")] = "mixed" })
|
||||
o:depends({ [option_name("protocol")] = "socks" })
|
||||
o:depends({ [option_name("protocol")] = "http" })
|
||||
|
||||
o = s:option(Value, option_name("username"), translate("Username"))
|
||||
o:depends({ [option_name("auth")] = true })
|
||||
o:depends({ [option_name("protocol")] = "naive" })
|
||||
|
||||
o = s:option(Value, option_name("password"), translate("Password"))
|
||||
o.password = true
|
||||
o:depends({ [option_name("auth")] = true })
|
||||
o:depends({ [option_name("protocol")] = "shadowsocks" })
|
||||
o:depends({ [option_name("protocol")] = "naive" })
|
||||
o:depends({ [option_name("protocol")] = "tuic" })
|
||||
|
||||
if singbox_tags:find("with_quic") then
|
||||
o = s:option(Value, option_name("hysteria_up_mbps"), translate("Max upload Mbps"))
|
||||
o.default = "100"
|
||||
o:depends({ [option_name("protocol")] = "hysteria" })
|
||||
|
||||
o = s:option(Value, option_name("hysteria_down_mbps"), translate("Max download Mbps"))
|
||||
o.default = "100"
|
||||
o:depends({ [option_name("protocol")] = "hysteria" })
|
||||
|
||||
o = s:option(Value, option_name("hysteria_obfs"), translate("Obfs Password"))
|
||||
o:depends({ [option_name("protocol")] = "hysteria" })
|
||||
|
||||
o = s:option(ListValue, option_name("hysteria_auth_type"), translate("Auth Type"))
|
||||
o:value("disable", translate("Disable"))
|
||||
o:value("string", translate("STRING"))
|
||||
o:value("base64", translate("BASE64"))
|
||||
o:depends({ [option_name("protocol")] = "hysteria" })
|
||||
|
||||
o = s:option(Value, option_name("hysteria_auth_password"), translate("Auth Password"))
|
||||
o.password = true
|
||||
o:depends({ [option_name("protocol")] = "hysteria", [option_name("hysteria_auth_type")] = "string"})
|
||||
o:depends({ [option_name("protocol")] = "hysteria", [option_name("hysteria_auth_type")] = "base64"})
|
||||
|
||||
o = s:option(Value, option_name("hysteria_recv_window_conn"), translate("QUIC stream receive window"))
|
||||
o:depends({ [option_name("protocol")] = "hysteria" })
|
||||
|
||||
o = s:option(Value, option_name("hysteria_recv_window_client"), translate("QUIC connection receive window"))
|
||||
o:depends({ [option_name("protocol")] = "hysteria" })
|
||||
|
||||
o = s:option(Value, option_name("hysteria_max_conn_client"), translate("QUIC concurrent bidirectional streams"))
|
||||
o.default = "1024"
|
||||
o:depends({ [option_name("protocol")] = "hysteria" })
|
||||
|
||||
o = s:option(Flag, option_name("hysteria_disable_mtu_discovery"), translate("Disable MTU detection"))
|
||||
o:depends({ [option_name("protocol")] = "hysteria" })
|
||||
|
||||
o = s:option(Value, option_name("hysteria_alpn"), translate("QUIC TLS ALPN"))
|
||||
o:depends({ [option_name("protocol")] = "hysteria" })
|
||||
end
|
||||
|
||||
if singbox_tags:find("with_quic") then
|
||||
o = s:option(ListValue, option_name("tuic_congestion_control"), translate("Congestion control algorithm"))
|
||||
o.default = "cubic"
|
||||
o:value("bbr", translate("BBR"))
|
||||
o:value("cubic", translate("CUBIC"))
|
||||
o:value("new_reno", translate("New Reno"))
|
||||
o:depends({ [option_name("protocol")] = "tuic" })
|
||||
|
||||
o = s:option(Flag, option_name("tuic_zero_rtt_handshake"), translate("Enable 0-RTT QUIC handshake"))
|
||||
o.default = 0
|
||||
o:depends({ [option_name("protocol")] = "tuic" })
|
||||
|
||||
o = s:option(Value, option_name("tuic_heartbeat"), translate("Heartbeat interval(second)"))
|
||||
o.datatype = "uinteger"
|
||||
o.default = "3"
|
||||
o:depends({ [option_name("protocol")] = "tuic" })
|
||||
|
||||
o = s:option(Value, option_name("tuic_alpn"), translate("QUIC TLS ALPN"))
|
||||
o:depends({ [option_name("protocol")] = "tuic" })
|
||||
end
|
||||
|
||||
if singbox_tags:find("with_quic") then
|
||||
o = s:option(Flag, option_name("hysteria2_ignore_client_bandwidth"), translate("Commands the client to use the BBR flow control algorithm"))
|
||||
o.default = 0
|
||||
o:depends({ [option_name("protocol")] = "hysteria2" })
|
||||
|
||||
o = s:option(Value, option_name("hysteria2_up_mbps"), translate("Max upload Mbps"))
|
||||
o:depends({ [option_name("protocol")] = "hysteria2", [option_name("hysteria2_ignore_client_bandwidth")] = false })
|
||||
|
||||
o = s:option(Value, option_name("hysteria2_down_mbps"), translate("Max download Mbps"))
|
||||
o:depends({ [option_name("protocol")] = "hysteria2", [option_name("hysteria2_ignore_client_bandwidth")] = false })
|
||||
|
||||
o = s:option(ListValue, option_name("hysteria2_obfs_type"), translate("Obfs Type"))
|
||||
o:value("", translate("Disable"))
|
||||
o:value("salamander")
|
||||
o:depends({ [option_name("protocol")] = "hysteria2" })
|
||||
|
||||
o = s:option(Value, option_name("hysteria2_obfs_password"), translate("Obfs Password"))
|
||||
o:depends({ [option_name("protocol")] = "hysteria2" })
|
||||
|
||||
o = s:option(Value, option_name("hysteria2_auth_password"), translate("Auth Password"))
|
||||
o.password = true
|
||||
o:depends({ [option_name("protocol")] = "hysteria2"})
|
||||
end
|
||||
|
||||
o = s:option(ListValue, option_name("d_protocol"), translate("Destination protocol"))
|
||||
o:value("tcp", "TCP")
|
||||
o:value("udp", "UDP")
|
||||
o:value("tcp,udp", "TCP,UDP")
|
||||
o:depends({ [option_name("protocol")] = "direct" })
|
||||
|
||||
o = s:option(Value, option_name("d_address"), translate("Destination address"))
|
||||
o:depends({ [option_name("protocol")] = "direct" })
|
||||
|
||||
o = s:option(Value, option_name("d_port"), translate("Destination port"))
|
||||
o.datatype = "port"
|
||||
o:depends({ [option_name("protocol")] = "direct" })
|
||||
|
||||
o = s:option(Value, option_name("decryption"), translate("Encrypt Method"))
|
||||
o.default = "none"
|
||||
o:depends({ [option_name("protocol")] = "vless" })
|
||||
|
||||
o = s:option(ListValue, option_name("ss_method"), translate("Encrypt Method"))
|
||||
o.rewrite_option = "method"
|
||||
for a, t in ipairs(ss_method_list) do o:value(t) end
|
||||
o:depends({ [option_name("protocol")] = "shadowsocks" })
|
||||
|
||||
o = s:option(DynamicList, option_name("uuid"), translate("ID") .. "/" .. translate("Password"))
|
||||
for i = 1, 3 do
|
||||
o:value(api.gen_uuid(1))
|
||||
end
|
||||
o:depends({ [option_name("protocol")] = "vmess" })
|
||||
o:depends({ [option_name("protocol")] = "vless" })
|
||||
o:depends({ [option_name("protocol")] = "trojan" })
|
||||
o:depends({ [option_name("protocol")] = "tuic" })
|
||||
|
||||
o = s:option(ListValue, option_name("flow"), translate("flow"))
|
||||
o.default = ""
|
||||
o:value("", translate("Disable"))
|
||||
o:value("xtls-rprx-vision")
|
||||
o:depends({ [option_name("protocol")] = "vless" })
|
||||
|
||||
o = s:option(Flag, option_name("tls"), translate("TLS"))
|
||||
o.default = 0
|
||||
o.validate = function(self, value, t)
|
||||
if value then
|
||||
local reality = s.fields[option_name("reality")]:formvalue(t)
|
||||
if reality and reality == "1" then return value end
|
||||
if value == "1" then
|
||||
local ca = s.fields[option_name("tls_certificateFile")]:formvalue(t) or ""
|
||||
local key = s.fields[option_name("tls_keyFile")]:formvalue(t) or ""
|
||||
if ca == "" or key == "" then
|
||||
return nil, translate("Public key and Private key path can not be empty!")
|
||||
end
|
||||
end
|
||||
return value
|
||||
end
|
||||
end
|
||||
o:depends({ [option_name("protocol")] = "http" })
|
||||
o:depends({ [option_name("protocol")] = "shadowsocks" })
|
||||
o:depends({ [option_name("protocol")] = "vmess" })
|
||||
o:depends({ [option_name("protocol")] = "vless" })
|
||||
o:depends({ [option_name("protocol")] = "trojan" })
|
||||
|
||||
if singbox_tags:find("with_reality_server") then
|
||||
-- [[ REALITY部分 ]] --
|
||||
o = s:option(Flag, option_name("reality"), translate("REALITY"))
|
||||
o.default = 0
|
||||
o:depends({ [option_name("protocol")] = "vless", [option_name("tls")] = true })
|
||||
o:depends({ [option_name("protocol")] = "vmess", [option_name("tls")] = true })
|
||||
o:depends({ [option_name("protocol")] = "shadowsocks", [option_name("tls")] = true })
|
||||
o:depends({ [option_name("protocol")] = "http", [option_name("tls")] = true })
|
||||
o:depends({ [option_name("protocol")] = "trojan", [option_name("tls")] = true })
|
||||
|
||||
o = s:option(Value, option_name("reality_private_key"), translate("Private Key"))
|
||||
o:depends({ [option_name("reality")] = true })
|
||||
|
||||
o = s:option(Value, option_name("reality_shortId"), translate("Short Id"))
|
||||
o:depends({ [option_name("reality")] = true })
|
||||
|
||||
o = s:option(Value, option_name("reality_handshake_server"), translate("Handshake Server"))
|
||||
o.default = "google.com"
|
||||
o:depends({ [option_name("reality")] = true })
|
||||
|
||||
o = s:option(Value, option_name("reality_handshake_server_port"), translate("Handshake Server Port"))
|
||||
o.datatype = "port"
|
||||
o.default = "443"
|
||||
o:depends({ [option_name("reality")] = true })
|
||||
end
|
||||
|
||||
-- [[ TLS部分 ]] --
|
||||
|
||||
o = s:option(FileUpload, option_name("tls_certificateFile"), translate("Public key absolute path"), translate("as:") .. "/etc/ssl/fullchain.pem")
|
||||
o.default = m:get(s.section, "tls_certificateFile") or "/etc/config/ssl/" .. arg[1] .. ".pem"
|
||||
o:depends({ [option_name("tls")] = true, [option_name("reality")] = false })
|
||||
o:depends({ [option_name("protocol")] = "naive" })
|
||||
o:depends({ [option_name("protocol")] = "hysteria" })
|
||||
o:depends({ [option_name("protocol")] = "tuic" })
|
||||
o:depends({ [option_name("protocol")] = "hysteria2" })
|
||||
o.validate = function(self, value, t)
|
||||
if value and value ~= "" then
|
||||
if not nixio.fs.access(value) then
|
||||
return nil, translate("Can't find this file!")
|
||||
else
|
||||
return value
|
||||
end
|
||||
end
|
||||
return nil
|
||||
end
|
||||
|
||||
o = s:option(FileUpload, option_name("tls_keyFile"), translate("Private key absolute path"), translate("as:") .. "/etc/ssl/private.key")
|
||||
o.default = m:get(s.section, "tls_keyFile") or "/etc/config/ssl/" .. arg[1] .. ".key"
|
||||
o:depends({ [option_name("tls")] = true, [option_name("reality")] = false })
|
||||
o:depends({ [option_name("protocol")] = "naive" })
|
||||
o:depends({ [option_name("protocol")] = "hysteria" })
|
||||
o:depends({ [option_name("protocol")] = "tuic" })
|
||||
o:depends({ [option_name("protocol")] = "hysteria2" })
|
||||
o.validate = function(self, value, t)
|
||||
if value and value ~= "" then
|
||||
if not nixio.fs.access(value) then
|
||||
return nil, translate("Can't find this file!")
|
||||
else
|
||||
return value
|
||||
end
|
||||
end
|
||||
return nil
|
||||
end
|
||||
|
||||
o = s:option(ListValue, option_name("transport"), translate("Transport"))
|
||||
o:value("tcp", "TCP")
|
||||
o:value("http", "HTTP")
|
||||
o:value("ws", "WebSocket")
|
||||
o:value("quic", "QUIC")
|
||||
o:value("grpc", "gRPC")
|
||||
o:depends({ [option_name("protocol")] = "shadowsocks" })
|
||||
o:depends({ [option_name("protocol")] = "vmess" })
|
||||
o:depends({ [option_name("protocol")] = "vless" })
|
||||
o:depends({ [option_name("protocol")] = "trojan" })
|
||||
|
||||
-- [[ HTTP部分 ]]--
|
||||
|
||||
o = s:option(Value, option_name("http_host"), translate("HTTP Host"))
|
||||
o:depends({ [option_name("transport")] = "http" })
|
||||
|
||||
o = s:option(Value, option_name("http_path"), translate("HTTP Path"))
|
||||
o:depends({ [option_name("transport")] = "http" })
|
||||
|
||||
-- [[ WebSocket部分 ]]--
|
||||
|
||||
o = s:option(Value, option_name("ws_host"), translate("WebSocket Host"))
|
||||
o:depends({ [option_name("transport")] = "ws" })
|
||||
|
||||
o = s:option(Value, option_name("ws_path"), translate("WebSocket Path"))
|
||||
o:depends({ [option_name("transport")] = "ws" })
|
||||
|
||||
-- [[ gRPC部分 ]]--
|
||||
o = s:option(Value, option_name("grpc_serviceName"), "ServiceName")
|
||||
o:depends({ [option_name("transport")] = "grpc" })
|
||||
|
||||
o = s:option(Flag, option_name("bind_local"), translate("Bind Local"), translate("When selected, it can only be accessed locally, It is recommended to turn on when using reverse proxies or be fallback."))
|
||||
o.default = "0"
|
||||
|
||||
o = s:option(Flag, option_name("accept_lan"), translate("Accept LAN Access"), translate("When selected, it can accessed lan , this will not be safe!"))
|
||||
o.default = "0"
|
||||
|
||||
local nodes_table = {}
|
||||
for k, e in ipairs(api.get_valid_nodes()) do
|
||||
if e.node_type == "normal" and e.type == type_name then
|
||||
nodes_table[#nodes_table + 1] = {
|
||||
id = e[".name"],
|
||||
remarks = e["remark"]
|
||||
}
|
||||
end
|
||||
end
|
||||
|
||||
o = s:option(ListValue, option_name("outbound_node"), translate("outbound node"))
|
||||
o:value("nil", translate("Close"))
|
||||
o:value("_socks", translate("Custom Socks"))
|
||||
o:value("_http", translate("Custom HTTP"))
|
||||
o:value("_iface", translate("Custom Interface"))
|
||||
for k, v in pairs(nodes_table) do o:value(v.id, v.remarks) end
|
||||
o.default = "nil"
|
||||
|
||||
o = s:option(Value, option_name("outbound_node_address"), translate("Address (Support Domain Name)"))
|
||||
o:depends({ [option_name("outbound_node")] = "_socks" })
|
||||
o:depends({ [option_name("outbound_node")] = "_http" })
|
||||
|
||||
o = s:option(Value, option_name("outbound_node_port"), translate("Port"))
|
||||
o.datatype = "port"
|
||||
o:depends({ [option_name("outbound_node")] = "_socks" })
|
||||
o:depends({ [option_name("outbound_node")] = "_http" })
|
||||
|
||||
o = s:option(Value, option_name("outbound_node_username"), translate("Username"))
|
||||
o:depends({ [option_name("outbound_node")] = "_socks" })
|
||||
o:depends({ [option_name("outbound_node")] = "_http" })
|
||||
|
||||
o = s:option(Value, option_name("outbound_node_password"), translate("Password"))
|
||||
o.password = true
|
||||
o:depends({ [option_name("outbound_node")] = "_socks" })
|
||||
o:depends({ [option_name("outbound_node")] = "_http" })
|
||||
|
||||
o = s:option(Value, option_name("outbound_node_iface"), translate("Interface"))
|
||||
o.default = "eth1"
|
||||
o:depends({ [option_name("outbound_node")] = "_iface" })
|
||||
|
||||
o = s:option(Flag, option_name("log"), translate("Log"))
|
||||
o.default = "1"
|
||||
o.rmempty = false
|
||||
|
||||
o = s:option(ListValue, option_name("loglevel"), translate("Log Level"))
|
||||
o.default = "info"
|
||||
o:value("debug")
|
||||
o:value("info")
|
||||
o:value("warn")
|
||||
o:value("error")
|
||||
o:depends({ [option_name("log")] = true })
|
||||
|
||||
api.luci_types(arg[1], m, s, type_name, option_prefix)
|
@ -1,46 +0,0 @@
|
||||
local m, s = ...
|
||||
|
||||
local api = require "luci.passwall.api"
|
||||
|
||||
if not api.is_finded("microsocks") then
|
||||
return
|
||||
end
|
||||
|
||||
local type_name = "Socks"
|
||||
|
||||
local option_prefix = "socks_"
|
||||
|
||||
local function option_name(name)
|
||||
return option_prefix .. name
|
||||
end
|
||||
|
||||
-- [[ microsocks ]]
|
||||
|
||||
s.fields["type"]:value(type_name, "Socks")
|
||||
|
||||
o = s:option(Value, option_name("port"), translate("Listen Port"))
|
||||
o.datatype = "port"
|
||||
|
||||
o = s:option(Flag, option_name("auth"), translate("Auth"))
|
||||
o.validate = function(self, value, t)
|
||||
if value and value == "1" then
|
||||
local user_v = s.fields[option_name("username")]:formvalue(t) or ""
|
||||
local pass_v = s.fields[option_name("password")]:formvalue(t) or ""
|
||||
if user_v == "" or pass_v == "" then
|
||||
return nil, translate("Username and Password must be used together!")
|
||||
end
|
||||
end
|
||||
return value
|
||||
end
|
||||
|
||||
o = s:option(Value, option_name("username"), translate("Username"))
|
||||
o:depends({ [option_name("auth")] = true })
|
||||
|
||||
o = s:option(Value, option_name("password"), translate("Password"))
|
||||
o.password = true
|
||||
o:depends({ [option_name("auth")] = true })
|
||||
|
||||
o = s:option(Flag, option_name("log"), translate("Log"))
|
||||
o.default = "1"
|
||||
|
||||
api.luci_types(arg[1], m, s, type_name, option_prefix)
|
@ -1,47 +0,0 @@
|
||||
local m, s = ...
|
||||
|
||||
local api = require "luci.passwall.api"
|
||||
|
||||
if not api.is_finded("ssserver") then
|
||||
return
|
||||
end
|
||||
|
||||
local type_name = "SS-Rust"
|
||||
|
||||
local option_prefix = "ssrust_"
|
||||
|
||||
local function option_name(name)
|
||||
return option_prefix .. name
|
||||
end
|
||||
|
||||
local ssrust_encrypt_method_list = {
|
||||
"plain", "none",
|
||||
"aes-128-gcm", "aes-256-gcm", "chacha20-ietf-poly1305",
|
||||
"2022-blake3-aes-128-gcm", "2022-blake3-aes-256-gcm", "2022-blake3-chacha20-poly1305"
|
||||
}
|
||||
|
||||
-- [[ Shadowsocks Rust ]]
|
||||
|
||||
s.fields["type"]:value(type_name, translate("Shadowsocks Rust"))
|
||||
|
||||
o = s:option(Value, option_name("port"), translate("Listen Port"))
|
||||
o.datatype = "port"
|
||||
|
||||
o = s:option(Value, option_name("password"), translate("Password"))
|
||||
o.password = true
|
||||
|
||||
o = s:option(ListValue, option_name("method"), translate("Encrypt Method"))
|
||||
for a, t in ipairs(ssrust_encrypt_method_list) do o:value(t) end
|
||||
|
||||
o = s:option(Value, option_name("timeout"), translate("Connection Timeout"))
|
||||
o.datatype = "uinteger"
|
||||
o.default = 300
|
||||
|
||||
o = s:option(Flag, option_name("tcp_fast_open"), "TCP " .. translate("Fast Open"))
|
||||
o.default = "0"
|
||||
|
||||
o = s:option(Flag, option_name("log"), translate("Log"))
|
||||
o.default = "1"
|
||||
o.rmempty = false
|
||||
|
||||
api.luci_types(arg[1], m, s, type_name, option_prefix)
|
@ -1,50 +0,0 @@
|
||||
local m, s = ...
|
||||
|
||||
local api = require "luci.passwall.api"
|
||||
|
||||
if not api.is_finded("ss-server") then
|
||||
return
|
||||
end
|
||||
|
||||
local type_name = "SS"
|
||||
|
||||
local option_prefix = "ss_"
|
||||
|
||||
local function option_name(name)
|
||||
return option_prefix .. name
|
||||
end
|
||||
|
||||
local ss_encrypt_method_list = {
|
||||
"rc4-md5", "aes-128-cfb", "aes-192-cfb", "aes-256-cfb", "aes-128-ctr",
|
||||
"aes-192-ctr", "aes-256-ctr", "bf-cfb", "camellia-128-cfb",
|
||||
"camellia-192-cfb", "camellia-256-cfb", "salsa20", "chacha20",
|
||||
"chacha20-ietf", -- aead
|
||||
"aes-128-gcm", "aes-192-gcm", "aes-256-gcm", "chacha20-ietf-poly1305",
|
||||
"xchacha20-ietf-poly1305"
|
||||
}
|
||||
|
||||
-- [[ Shadowsocks ]]
|
||||
|
||||
s.fields["type"]:value(type_name, translate("Shadowsocks"))
|
||||
|
||||
o = s:option(Value, option_name("port"), translate("Listen Port"))
|
||||
o.datatype = "port"
|
||||
|
||||
o = s:option(Value, option_name("password"), translate("Password"))
|
||||
o.password = true
|
||||
|
||||
o = s:option(ListValue, option_name("method"), translate("Encrypt Method"))
|
||||
for a, t in ipairs(ss_encrypt_method_list) do o:value(t) end
|
||||
|
||||
o = s:option(Value, option_name("timeout"), translate("Connection Timeout"))
|
||||
o.datatype = "uinteger"
|
||||
o.default = 300
|
||||
|
||||
o = s:option(Flag, option_name("tcp_fast_open"), "TCP " .. translate("Fast Open"))
|
||||
o.default = "0"
|
||||
|
||||
o = s:option(Flag, option_name("log"), translate("Log"))
|
||||
o.default = "1"
|
||||
o.rmempty = false
|
||||
|
||||
api.luci_types(arg[1], m, s, type_name, option_prefix)
|
@ -1,74 +0,0 @@
|
||||
local m, s = ...
|
||||
|
||||
local api = require "luci.passwall.api"
|
||||
|
||||
if not api.is_finded("ssr-server") then
|
||||
return
|
||||
end
|
||||
|
||||
local type_name = "SSR"
|
||||
|
||||
local option_prefix = "ssr_"
|
||||
|
||||
local function option_name(name)
|
||||
return option_prefix .. name
|
||||
end
|
||||
|
||||
local ssr_encrypt_method_list = {
|
||||
"none", "table", "rc2-cfb", "rc4", "rc4-md5", "rc4-md5-6", "aes-128-cfb",
|
||||
"aes-192-cfb", "aes-256-cfb", "aes-128-ctr", "aes-192-ctr", "aes-256-ctr",
|
||||
"bf-cfb", "camellia-128-cfb", "camellia-192-cfb", "camellia-256-cfb",
|
||||
"cast5-cfb", "des-cfb", "idea-cfb", "seed-cfb", "salsa20", "chacha20",
|
||||
"chacha20-ietf"
|
||||
}
|
||||
|
||||
local ssr_protocol_list = {
|
||||
"origin", "verify_simple", "verify_deflate", "verify_sha1", "auth_simple",
|
||||
"auth_sha1", "auth_sha1_v2", "auth_sha1_v4", "auth_aes128_md5",
|
||||
"auth_aes128_sha1", "auth_chain_a", "auth_chain_b", "auth_chain_c",
|
||||
"auth_chain_d", "auth_chain_e", "auth_chain_f"
|
||||
}
|
||||
local ssr_obfs_list = {
|
||||
"plain", "http_simple", "http_post", "random_head", "tls_simple",
|
||||
"tls1.0_session_auth", "tls1.2_ticket_auth"
|
||||
}
|
||||
|
||||
-- [[ ShadowsocksR ]]
|
||||
|
||||
s.fields["type"]:value(type_name, translate("ShadowsocksR"))
|
||||
|
||||
o = s:option(Value, option_name("port"), translate("Listen Port"))
|
||||
o.datatype = "port"
|
||||
|
||||
o = s:option(Value, option_name("password"), translate("Password"))
|
||||
o.password = true
|
||||
|
||||
o = s:option(ListValue, option_name("method"), translate("Encrypt Method"))
|
||||
for a, t in ipairs(ssr_encrypt_method_list) do o:value(t) end
|
||||
|
||||
o = s:option(ListValue, option_name("protocol"), translate("Protocol"))
|
||||
for a, t in ipairs(ssr_protocol_list) do o:value(t) end
|
||||
|
||||
o = s:option(Value, option_name("protocol_param"), translate("Protocol_param"))
|
||||
|
||||
o = s:option(ListValue, option_name("obfs"), translate("Obfs"))
|
||||
for a, t in ipairs(ssr_obfs_list) do o:value(t) end
|
||||
|
||||
o = s:option(Value, option_name("obfs_param"), translate("Obfs_param"))
|
||||
|
||||
o = s:option(Value, option_name("timeout"), translate("Connection Timeout"))
|
||||
o.datatype = "uinteger"
|
||||
o.default = 300
|
||||
|
||||
o = s:option(Flag, option_name("tcp_fast_open"), "TCP " .. translate("Fast Open"))
|
||||
o.default = "0"
|
||||
|
||||
o = s:option(Flag, option_name("udp_forward"), translate("UDP Forward"))
|
||||
o.default = "1"
|
||||
o.rmempty = false
|
||||
|
||||
o = s:option(Flag, option_name("log"), translate("Log"))
|
||||
o.default = "1"
|
||||
o.rmempty = false
|
||||
|
||||
api.luci_types(arg[1], m, s, type_name, option_prefix)
|
@ -1,159 +0,0 @@
|
||||
local m, s = ...
|
||||
|
||||
local api = require "luci.passwall.api"
|
||||
|
||||
if not api.finded_com("trojan-go") then
|
||||
return
|
||||
end
|
||||
|
||||
local type_name = "Trojan-Go"
|
||||
|
||||
local option_prefix = "trojan_go_"
|
||||
|
||||
local function option_name(name)
|
||||
return option_prefix .. name
|
||||
end
|
||||
|
||||
local encrypt_methods_ss_aead = {
|
||||
"chacha20-ietf-poly1305",
|
||||
"aes-128-gcm",
|
||||
"aes-256-gcm",
|
||||
}
|
||||
|
||||
-- [[ Trojan-Go ]]
|
||||
|
||||
s.fields["type"]:value(type_name, "Trojan-Go")
|
||||
|
||||
o = s:option(Value, option_name("port"), translate("Listen Port"))
|
||||
o.datatype = "port"
|
||||
|
||||
o = s:option(DynamicList, option_name("uuid"), translate("ID") .. "/" .. translate("Password"))
|
||||
for i = 1, 3 do
|
||||
o:value(api.gen_uuid(1))
|
||||
end
|
||||
|
||||
o = s:option(Flag, option_name("tls"), translate("TLS"))
|
||||
o.default = 0
|
||||
o.validate = function(self, value, t)
|
||||
if value then
|
||||
local type = s.fields["type"]:formvalue(t) or ""
|
||||
if value == "0" and type == type_name then
|
||||
return nil, translate("Original Trojan only supported 'tls', please choose 'tls'.")
|
||||
end
|
||||
if value == "1" then
|
||||
local ca = s.fields[option_name("tls_certificateFile")]:formvalue(t) or ""
|
||||
local key = s.fields[option_name("tls_keyFile")]:formvalue(t) or ""
|
||||
if ca == "" or key == "" then
|
||||
return nil, translate("Public key and Private key path can not be empty!")
|
||||
end
|
||||
end
|
||||
return value
|
||||
end
|
||||
end
|
||||
|
||||
o = s:option(FileUpload, option_name("tls_certificateFile"), translate("Public key absolute path"), translate("as:") .. "/etc/ssl/fullchain.pem")
|
||||
o.default = m:get(s.section, "tls_certificateFile") or "/etc/config/ssl/" .. arg[1] .. ".pem"
|
||||
o:depends({ [option_name("tls")] = true })
|
||||
o.validate = function(self, value, t)
|
||||
if value and value ~= "" then
|
||||
if not nixio.fs.access(value) then
|
||||
return nil, translate("Can't find this file!")
|
||||
else
|
||||
return value
|
||||
end
|
||||
end
|
||||
return nil
|
||||
end
|
||||
|
||||
o = s:option(FileUpload, option_name("tls_keyFile"), translate("Private key absolute path"), translate("as:") .. "/etc/ssl/private.key")
|
||||
o.default = m:get(s.section, "tls_keyFile") or "/etc/config/ssl/" .. arg[1] .. ".key"
|
||||
o:depends({ [option_name("tls")] = true })
|
||||
o.validate = function(self, value, t)
|
||||
if value and value ~= "" then
|
||||
if not nixio.fs.access(value) then
|
||||
return nil, translate("Can't find this file!")
|
||||
else
|
||||
return value
|
||||
end
|
||||
end
|
||||
return nil
|
||||
end
|
||||
|
||||
o = s:option(Flag, option_name("tls_sessionTicket"), translate("Session Ticket"))
|
||||
o.default = "0"
|
||||
o:depends({ [option_name("tls")] = true })
|
||||
|
||||
o = s:option(ListValue, option_name("transport"), translate("Transport"))
|
||||
o:value("original", translate("Original"))
|
||||
o:value("ws", "WebSocket")
|
||||
o.default = "original"
|
||||
|
||||
o = s:option(ListValue, option_name("plugin_type"), translate("Transport Plugin"))
|
||||
o:value("plaintext", "Plain Text")
|
||||
o:value("shadowsocks", "ShadowSocks")
|
||||
o:value("other", "Other")
|
||||
o.default = "plaintext"
|
||||
o:depends({ [option_name("tls")] = false, [option_name("transport")] = "original" })
|
||||
|
||||
o = s:option(Value, option_name("plugin_cmd"), translate("Plugin Binary"))
|
||||
o.placeholder = "eg: /usr/bin/v2ray-plugin"
|
||||
o:depends({ [option_name("plugin_type")] = "shadowsocks" })
|
||||
o:depends({ [option_name("plugin_type")] = "other" })
|
||||
|
||||
o = s:option(Value, option_name("plugin_option"), translate("Plugin Option"))
|
||||
o.placeholder = "eg: obfs=http;obfs-host=www.baidu.com"
|
||||
o:depends({ [option_name("plugin_type")] = "shadowsocks" })
|
||||
o:depends({ [option_name("plugin_type")] = "other" })
|
||||
|
||||
o = s:option(DynamicList, option_name("plugin_arg"), translate("Plugin Option Args"))
|
||||
o.placeholder = "eg: [\"-config\", \"test.json\"]"
|
||||
o:depends({ [option_name("plugin_type")] = "shadowsocks" })
|
||||
o:depends({ [option_name("plugin_type")] = "other" })
|
||||
|
||||
o = s:option(Value, option_name("ws_host"), translate("WebSocket Host"))
|
||||
o:depends({ [option_name("transport")] = "ws" })
|
||||
|
||||
o = s:option(Value, option_name("ws_path"), translate("WebSocket Path"))
|
||||
o:depends({ [option_name("transport")] = "ws" })
|
||||
|
||||
o = s:option(Flag, option_name("ss_aead"), translate("Shadowsocks secondary encryption"))
|
||||
o.default = "0"
|
||||
|
||||
o = s:option(ListValue, option_name("ss_aead_method"), translate("Encrypt Method"))
|
||||
for _, v in ipairs(encrypt_methods_ss_aead) do o:value(v, v) end
|
||||
o.default = "aes-128-gcm"
|
||||
o:depends({ [option_name("ss_aead")] = true })
|
||||
|
||||
o = s:option(Value, option_name("ss_aead_pwd"), translate("Password"))
|
||||
o.password = true
|
||||
o:depends({ [option_name("ss_aead")] = true })
|
||||
|
||||
o = s:option(Flag, option_name("tcp_fast_open"), translate("TCP Fast Open"))
|
||||
o.default = "0"
|
||||
|
||||
o = s:option(Flag, option_name("remote_enable"), translate("Enable Remote"), translate("You can forward to Nginx/Caddy/V2ray/Xray WebSocket and more."))
|
||||
o.default = "1"
|
||||
o.rmempty = false
|
||||
|
||||
o = s:option(Value, option_name("remote_address"), translate("Remote Address"))
|
||||
o.default = "127.0.0.1"
|
||||
o:depends({ [option_name("remote_enable")] = true })
|
||||
|
||||
o = s:option(Value, option_name("remote_port"), translate("Remote Port"))
|
||||
o.datatype = "port"
|
||||
o.default = "80"
|
||||
o:depends({ [option_name("remote_enable")] = true })
|
||||
|
||||
o = s:option(Flag, option_name("log"), translate("Log"))
|
||||
o.default = "1"
|
||||
|
||||
o = s:option(ListValue, option_name("loglevel"), translate("Log Level"))
|
||||
o.default = "2"
|
||||
o:value("0", "all")
|
||||
o:value("1", "info")
|
||||
o:value("2", "warn")
|
||||
o:value("3", "error")
|
||||
o:value("4", "fatal")
|
||||
o:depends({ [option_name("log")] = true })
|
||||
|
||||
api.luci_types(arg[1], m, s, type_name, option_prefix)
|
@ -1,108 +0,0 @@
|
||||
local m, s = ...
|
||||
|
||||
local api = require "luci.passwall.api"
|
||||
|
||||
if not api.is_finded("trojan-plus") then
|
||||
return
|
||||
end
|
||||
|
||||
local type_name = "Trojan-Plus"
|
||||
|
||||
local option_prefix = "trojan_plus_"
|
||||
|
||||
local function option_name(name)
|
||||
return option_prefix .. name
|
||||
end
|
||||
|
||||
-- [[ Trojan-Plus ]]
|
||||
|
||||
s.fields["type"]:value(type_name, "Trojan-Plus")
|
||||
|
||||
o = s:option(Value, option_name("port"), translate("Listen Port"))
|
||||
o.datatype = "port"
|
||||
|
||||
o = s:option(DynamicList, option_name("uuid"), translate("ID") .. "/" .. translate("Password"))
|
||||
for i = 1, 3 do
|
||||
o:value(api.gen_uuid(1))
|
||||
end
|
||||
|
||||
o = s:option(Flag, option_name("tls"), translate("TLS"))
|
||||
o.default = 0
|
||||
o.validate = function(self, value, t)
|
||||
if value then
|
||||
local type = s.fields["type"]:formvalue(t) or ""
|
||||
if value == "0" and type == type_name then
|
||||
return nil, translate("Original Trojan only supported 'tls', please choose 'tls'.")
|
||||
end
|
||||
if value == "1" then
|
||||
local ca = s.fields[option_name("tls_certificateFile")]:formvalue(t) or ""
|
||||
local key = s.fields[option_name("tls_keyFile")]:formvalue(t) or ""
|
||||
if ca == "" or key == "" then
|
||||
return nil, translate("Public key and Private key path can not be empty!")
|
||||
end
|
||||
end
|
||||
return value
|
||||
end
|
||||
end
|
||||
|
||||
o = s:option(FileUpload, option_name("tls_certificateFile"), translate("Public key absolute path"), translate("as:") .. "/etc/ssl/fullchain.pem")
|
||||
o.default = m:get(s.section, "tls_certificateFile") or "/etc/config/ssl/" .. arg[1] .. ".pem"
|
||||
o:depends({ [option_name("tls")] = true })
|
||||
o.validate = function(self, value, t)
|
||||
if value and value ~= "" then
|
||||
if not nixio.fs.access(value) then
|
||||
return nil, translate("Can't find this file!")
|
||||
else
|
||||
return value
|
||||
end
|
||||
end
|
||||
return nil
|
||||
end
|
||||
|
||||
o = s:option(FileUpload, option_name("tls_keyFile"), translate("Private key absolute path"), translate("as:") .. "/etc/ssl/private.key")
|
||||
o.default = m:get(s.section, "tls_keyFile") or "/etc/config/ssl/" .. arg[1] .. ".key"
|
||||
o:depends({ [option_name("tls")] = true })
|
||||
o.validate = function(self, value, t)
|
||||
if value and value ~= "" then
|
||||
if not nixio.fs.access(value) then
|
||||
return nil, translate("Can't find this file!")
|
||||
else
|
||||
return value
|
||||
end
|
||||
end
|
||||
return nil
|
||||
end
|
||||
|
||||
o = s:option(Flag, option_name("tls_sessionTicket"), translate("Session Ticket"))
|
||||
o.default = "0"
|
||||
o:depends({ [option_name("tls")] = true })
|
||||
|
||||
o = s:option(Flag, option_name("tcp_fast_open"), translate("TCP Fast Open"))
|
||||
o.default = "0"
|
||||
|
||||
o = s:option(Flag, option_name("remote_enable"), translate("Enable Remote"), translate("You can forward to Nginx/Caddy/V2ray/Xray WebSocket and more."))
|
||||
o.default = "1"
|
||||
o.rmempty = false
|
||||
|
||||
o = s:option(Value, option_name("remote_address"), translate("Remote Address"))
|
||||
o.default = "127.0.0.1"
|
||||
o:depends({ [option_name("remote_enable")] = true })
|
||||
|
||||
o = s:option(Value, option_name("remote_port"), translate("Remote Port"))
|
||||
o.datatype = "port"
|
||||
o.default = "80"
|
||||
o:depends({ [option_name("remote_enable")] = true })
|
||||
|
||||
o = s:option(Flag, option_name("log"), translate("Log"))
|
||||
o.default = "1"
|
||||
|
||||
o = s:option(ListValue, option_name("loglevel"), translate("Log Level"))
|
||||
o.default = "2"
|
||||
o:value("0", "all")
|
||||
o:value("1", "info")
|
||||
o:value("2", "warn")
|
||||
o:value("3", "error")
|
||||
o:value("4", "fatal")
|
||||
o:depends({ [option_name("log")] = true })
|
||||
|
||||
api.luci_types(arg[1], m, s, type_name, option_prefix)
|
@ -1,33 +0,0 @@
|
||||
local api = require "luci.passwall.api"
|
||||
local fs = require "nixio.fs"
|
||||
local types_dir = "/usr/lib/lua/luci/model/cbi/passwall/server/type/"
|
||||
|
||||
m = Map("passwall_server", translate("Server Config"))
|
||||
m.redirect = api.url("server")
|
||||
|
||||
s = m:section(NamedSection, arg[1], "user", "")
|
||||
s.addremove = false
|
||||
s.dynamic = false
|
||||
|
||||
o = s:option(Flag, "enable", translate("Enable"))
|
||||
o.default = "1"
|
||||
o.rmempty = false
|
||||
|
||||
o = s:option(Value, "remarks", translate("Remarks"))
|
||||
o.default = translate("Remarks")
|
||||
o.rmempty = false
|
||||
|
||||
o = s:option(ListValue, "type", translate("Type"))
|
||||
|
||||
local type_table = {}
|
||||
for filename in fs.dir(types_dir) do
|
||||
table.insert(type_table, filename)
|
||||
end
|
||||
table.sort(type_table)
|
||||
|
||||
for index, value in ipairs(type_table) do
|
||||
local p_func = loadfile(types_dir .. value)
|
||||
setfenv(p_func, getfenv(1))(m, s)
|
||||
end
|
||||
|
||||
return m
|
File diff suppressed because it is too large
Load Diff
@ -1,103 +0,0 @@
|
||||
local _M = {}
|
||||
|
||||
local function gh_release_url(self)
|
||||
return "https://api.github.com/repos/" .. self.repo .. "/releases/latest"
|
||||
end
|
||||
|
||||
local function gh_pre_release_url(self)
|
||||
return "https://api.github.com/repos/" .. self.repo .. "/releases?per_page=1"
|
||||
end
|
||||
|
||||
_M.brook = {
|
||||
name = "Brook",
|
||||
repo = "txthinking/brook",
|
||||
get_url = gh_release_url,
|
||||
cmd_version = "-v | awk '{print $3}'",
|
||||
zipped = false,
|
||||
default_path = "/usr/bin/brook",
|
||||
match_fmt_str = "linux_%s$",
|
||||
file_tree = {}
|
||||
}
|
||||
|
||||
_M.hysteria = {
|
||||
name = "Hysteria",
|
||||
repo = "HyNetwork/hysteria",
|
||||
get_url = gh_release_url,
|
||||
cmd_version = "version | awk '/^Version:/ {print $2}'",
|
||||
remote_version_str_replace = "app/",
|
||||
zipped = false,
|
||||
default_path = "/usr/bin/hysteria",
|
||||
match_fmt_str = "linux%%-%s$",
|
||||
file_tree = {
|
||||
armv6 = "arm",
|
||||
armv7 = "arm"
|
||||
}
|
||||
}
|
||||
|
||||
_M["trojan-go"] = {
|
||||
name = "Trojan-Go",
|
||||
repo = "p4gefau1t/trojan-go",
|
||||
get_url = gh_release_url,
|
||||
cmd_version = "-version | awk '{print $2}' | sed -n 1P",
|
||||
zipped = true,
|
||||
default_path = "/usr/bin/trojan-go",
|
||||
match_fmt_str = "linux%%-%s%%.zip",
|
||||
file_tree = {
|
||||
aarch64 = "armv8",
|
||||
armv8 = "armv8",
|
||||
mips = "mips%-hardfloat",
|
||||
mipsel = "mipsle%-hardfloat"
|
||||
}
|
||||
}
|
||||
|
||||
_M.singbox = {
|
||||
name = "Sing-Box",
|
||||
repo = "SagerNet/sing-box",
|
||||
get_url = gh_pre_release_url,
|
||||
cmd_version = "version | awk '{print $3}' | sed -n 1P",
|
||||
zipped = true,
|
||||
zipped_suffix = "tar.gz",
|
||||
default_path = "/usr/bin/sing-box",
|
||||
match_fmt_str = "linux%%-%s",
|
||||
file_tree = {
|
||||
x86_64 = "amd64"
|
||||
}
|
||||
}
|
||||
|
||||
_M.xray = {
|
||||
name = "Xray",
|
||||
repo = "XTLS/Xray-core",
|
||||
get_url = gh_pre_release_url,
|
||||
cmd_version = "version | awk '{print $2}' | sed -n 1P",
|
||||
zipped = true,
|
||||
default_path = "/usr/bin/xray",
|
||||
match_fmt_str = "linux%%-%s",
|
||||
file_tree = {
|
||||
x86_64 = "64",
|
||||
x86 = "32",
|
||||
mips = "mips32",
|
||||
mipsel = "mips32le"
|
||||
}
|
||||
}
|
||||
|
||||
_M["chinadns-ng"] = {
|
||||
name = "ChinaDNS-NG",
|
||||
repo = "zfl9/chinadns-ng",
|
||||
get_url = gh_release_url,
|
||||
cmd_version = "-V | awk '{print $2}'",
|
||||
zipped = false,
|
||||
default_path = "/usr/bin/chinadns-ng",
|
||||
match_fmt_str = "%s$",
|
||||
file_tree = {
|
||||
x86_64 = "x86_64",
|
||||
x86 = "i686",
|
||||
mipsel = "mipsel",
|
||||
aarch64 = "aarch64",
|
||||
armv5 = "arm%-eabi",
|
||||
armv6 = "armv6%-eabihf",
|
||||
armv7 = "armv7l%-eabihf",
|
||||
armv8 = "aarch64"
|
||||
}
|
||||
}
|
||||
|
||||
return _M
|
@ -1,235 +0,0 @@
|
||||
#!/usr/bin/lua
|
||||
|
||||
local action = arg[1]
|
||||
local api = require "luci.passwall.api"
|
||||
local sys = api.sys
|
||||
local uci = api.uci
|
||||
local jsonc = api.jsonc
|
||||
|
||||
local CONFIG = "passwall_server"
|
||||
local CONFIG_PATH = "/tmp/etc/" .. CONFIG
|
||||
local NFT_INCLUDE_FILE = CONFIG_PATH .. "/" .. CONFIG .. ".nft"
|
||||
local LOG_APP_FILE = "/tmp/log/" .. CONFIG .. ".log"
|
||||
local TMP_BIN_PATH = CONFIG_PATH .. "/bin"
|
||||
local require_dir = "luci.passwall."
|
||||
|
||||
local ipt_bin = sys.exec("echo -n $(/usr/share/passwall/iptables.sh get_ipt_bin)")
|
||||
local ip6t_bin = sys.exec("echo -n $(/usr/share/passwall/iptables.sh get_ip6t_bin)")
|
||||
|
||||
local nft_flag = api.is_finded("fw4") and "1" or "0"
|
||||
|
||||
local function log(...)
|
||||
local f, err = io.open(LOG_APP_FILE, "a")
|
||||
if f and err == nil then
|
||||
local str = os.date("%Y-%m-%d %H:%M:%S: ") .. table.concat({...}, " ")
|
||||
f:write(str .. "\n")
|
||||
f:close()
|
||||
end
|
||||
end
|
||||
|
||||
local function cmd(cmd)
|
||||
sys.call(cmd)
|
||||
end
|
||||
|
||||
local function ipt(arg)
|
||||
cmd(ipt_bin .. " -w " .. arg)
|
||||
end
|
||||
|
||||
local function ip6t(arg)
|
||||
cmd(ip6t_bin .. " -w " .. arg)
|
||||
end
|
||||
|
||||
local function ln_run(s, d, command, output)
|
||||
if not output then
|
||||
output = "/dev/null"
|
||||
end
|
||||
d = TMP_BIN_PATH .. "/" .. d
|
||||
cmd(string.format('[ ! -f "%s" ] && ln -s %s %s 2>/dev/null', d, s, d))
|
||||
return string.format("%s >%s 2>&1 &", d .. " " .. command, output)
|
||||
end
|
||||
|
||||
local function gen_include()
|
||||
cmd(string.format("echo '#!/bin/sh' > /tmp/etc/%s.include", CONFIG))
|
||||
local function extract_rules(n, a)
|
||||
local _ipt = ipt_bin
|
||||
if n == "6" then
|
||||
_ipt = ip6t_bin
|
||||
end
|
||||
local result = "*" .. a
|
||||
result = result .. "\n" .. sys.exec(_ipt .. '-save -t ' .. a .. ' | grep "PSW-SERVER" | sed -e "s/^-A \\(INPUT\\)/-I \\1 1/"')
|
||||
result = result .. "COMMIT"
|
||||
return result
|
||||
end
|
||||
local f, err = io.open("/tmp/etc/" .. CONFIG .. ".include", "a")
|
||||
if f and err == nil then
|
||||
if nft_flag == "0" then
|
||||
f:write(ipt_bin .. '-save -c | grep -v "PSW-SERVER" | ' .. ipt_bin .. '-restore -c' .. "\n")
|
||||
f:write(ipt_bin .. '-restore -n <<-EOT' .. "\n")
|
||||
f:write(extract_rules("4", "filter") .. "\n")
|
||||
f:write("EOT" .. "\n")
|
||||
f:write(ip6t_bin .. '-save -c | grep -v "PSW-SERVER" | ' .. ip6t_bin .. '-restore -c' .. "\n")
|
||||
f:write(ip6t_bin .. '-restore -n <<-EOT' .. "\n")
|
||||
f:write(extract_rules("6", "filter") .. "\n")
|
||||
f:write("EOT" .. "\n")
|
||||
f:close()
|
||||
else
|
||||
f:write("nft -f " .. NFT_INCLUDE_FILE .. "\n")
|
||||
f:close()
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
local function start()
|
||||
local enabled = tonumber(uci:get(CONFIG, "@global[0]", "enable") or 0)
|
||||
if enabled == nil or enabled == 0 then
|
||||
return
|
||||
end
|
||||
cmd(string.format("mkdir -p %s %s", CONFIG_PATH, TMP_BIN_PATH))
|
||||
cmd(string.format("touch %s", LOG_APP_FILE))
|
||||
if nft_flag == "0" then
|
||||
ipt("-N PSW-SERVER")
|
||||
ipt("-I INPUT -j PSW-SERVER")
|
||||
ip6t("-N PSW-SERVER")
|
||||
ip6t("-I INPUT -j PSW-SERVER")
|
||||
else
|
||||
nft_file, err = io.open(NFT_INCLUDE_FILE, "w")
|
||||
nft_file:write('#!/usr/sbin/nft -f\n')
|
||||
nft_file:write('add chain inet fw4 PSW-SERVER\n')
|
||||
nft_file:write('flush chain inet fw4 PSW-SERVER\n')
|
||||
nft_file:write('insert rule inet fw4 input position 0 jump PSW-SERVER comment "PSW-SERVER"\n')
|
||||
end
|
||||
uci:foreach(CONFIG, "user", function(user)
|
||||
local id = user[".name"]
|
||||
local enable = user.enable
|
||||
if enable and tonumber(enable) == 1 then
|
||||
local enable_log = user.log
|
||||
local log_path = nil
|
||||
if enable_log and enable_log == "1" then
|
||||
log_path = CONFIG_PATH .. "/" .. id .. ".log"
|
||||
else
|
||||
log_path = nil
|
||||
end
|
||||
local remarks = user.remarks
|
||||
local port = tonumber(user.port)
|
||||
local bin
|
||||
local config = {}
|
||||
local config_file = CONFIG_PATH .. "/" .. id .. ".json"
|
||||
local udp_forward = 1
|
||||
local type = user.type or ""
|
||||
if type == "Socks" then
|
||||
local auth = ""
|
||||
if user.auth and user.auth == "1" then
|
||||
local username = user.username or ""
|
||||
local password = user.password or ""
|
||||
if username ~= "" and password ~= "" then
|
||||
username = "-u " .. username
|
||||
password = "-P " .. password
|
||||
auth = username .. " " .. password
|
||||
end
|
||||
end
|
||||
bin = ln_run("/usr/bin/microsocks", "microsocks_" .. id, string.format("-i :: -p %s %s", port, auth), log_path)
|
||||
elseif type == "SS" or type == "SSR" then
|
||||
config = require(require_dir .. "util_shadowsocks").gen_config_server(user)
|
||||
local udp_param = ""
|
||||
udp_forward = tonumber(user.udp_forward) or 1
|
||||
if udp_forward == 1 then
|
||||
udp_param = "-u"
|
||||
end
|
||||
type = type:lower()
|
||||
bin = ln_run("/usr/bin/" .. type .. "-server", type .. "-server", "-c " .. config_file .. " " .. udp_param, log_path)
|
||||
elseif type == "SS-Rust" then
|
||||
config = require(require_dir .. "util_shadowsocks").gen_config_server(user)
|
||||
bin = ln_run("/usr/bin/ssserver", "ssserver", "-c " .. config_file, log_path)
|
||||
elseif type == "sing-box" then
|
||||
config = require(require_dir .. "util_sing-box").gen_config_server(user)
|
||||
bin = ln_run(api.get_app_path("singbox"), "sing-box", "run -c " .. config_file, log_path)
|
||||
elseif type == "Xray" then
|
||||
config = require(require_dir .. "util_xray").gen_config_server(user)
|
||||
bin = ln_run(api.get_app_path("xray"), "xray", "run -c " .. config_file, log_path)
|
||||
elseif type == "Trojan" then
|
||||
config = require(require_dir .. "util_trojan").gen_config_server(user)
|
||||
bin = ln_run("/usr/sbin/trojan", "trojan", "-c " .. config_file, log_path)
|
||||
elseif type == "Trojan-Plus" then
|
||||
config = require(require_dir .. "util_trojan").gen_config_server(user)
|
||||
bin = ln_run("/usr/sbin/trojan-plus", "trojan-plus", "-c " .. config_file, log_path)
|
||||
elseif type == "Trojan-Go" then
|
||||
config = require(require_dir .. "util_trojan").gen_config_server(user)
|
||||
bin = ln_run(api.get_app_path("trojan-go"), "trojan-go", "-config " .. config_file, log_path)
|
||||
elseif type == "Brook" then
|
||||
local brook_protocol = user.protocol
|
||||
local brook_password = user.password
|
||||
local brook_path = user.ws_path or "/ws"
|
||||
local brook_path_arg = ""
|
||||
if brook_protocol == "wsserver" and brook_path then
|
||||
brook_path_arg = " --path " .. brook_path
|
||||
end
|
||||
bin = ln_run(api.get_app_path("brook"), "brook_" .. id, string.format("--debug %s -l :%s -p %s%s", brook_protocol, port, brook_password, brook_path_arg), log_path)
|
||||
elseif type == "Hysteria2" then
|
||||
config = require(require_dir .. "util_hysteria2").gen_config_server(user)
|
||||
bin = ln_run(api.get_app_path("hysteria"), "hysteria", "-c " .. config_file .. " server", log_path)
|
||||
end
|
||||
|
||||
if next(config) then
|
||||
local f, err = io.open(config_file, "w")
|
||||
if f and err == nil then
|
||||
f:write(jsonc.stringify(config, 1))
|
||||
f:close()
|
||||
end
|
||||
log(string.format("%s %s 生成配置文件并运行 - %s", remarks, port, config_file))
|
||||
end
|
||||
|
||||
if bin then
|
||||
cmd(bin)
|
||||
end
|
||||
|
||||
local bind_local = user.bind_local or 0
|
||||
if bind_local and tonumber(bind_local) ~= 1 then
|
||||
if nft_flag == "0" then
|
||||
ipt(string.format('-A PSW-SERVER -p tcp --dport %s -m comment --comment "%s" -j ACCEPT', port, remarks))
|
||||
ip6t(string.format('-A PSW-SERVER -p tcp --dport %s -m comment --comment "%s" -j ACCEPT', port, remarks))
|
||||
if udp_forward == 1 then
|
||||
ipt(string.format('-A PSW-SERVER -p udp --dport %s -m comment --comment "%s" -j ACCEPT', port, remarks))
|
||||
ip6t(string.format('-A PSW-SERVER -p udp --dport %s -m comment --comment "%s" -j ACCEPT', port, remarks))
|
||||
end
|
||||
else
|
||||
nft_file:write(string.format('add rule inet fw4 PSW-SERVER meta l4proto tcp tcp dport {%s} counter accept comment "%s"\n', port, remarks))
|
||||
if udp_forward == 1 then
|
||||
nft_file:write(string.format('add rule inet fw4 PSW-SERVER meta l4proto udp udp dport {%s} counter accept comment "%s"\n', port, remarks))
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end)
|
||||
if nft_flag == "1" then
|
||||
nft_file:write("add rule inet fw4 PSW-SERVER return\n")
|
||||
nft_file:close()
|
||||
cmd("nft -f " .. NFT_INCLUDE_FILE)
|
||||
end
|
||||
gen_include()
|
||||
end
|
||||
|
||||
local function stop()
|
||||
cmd(string.format("top -bn1 | grep -v 'grep' | grep '%s/' | awk '{print $1}' | xargs kill -9 >/dev/null 2>&1", CONFIG_PATH))
|
||||
if nft_flag == "0" then
|
||||
ipt("-D INPUT -j PSW-SERVER 2>/dev/null")
|
||||
ipt("-F PSW-SERVER 2>/dev/null")
|
||||
ipt("-X PSW-SERVER 2>/dev/null")
|
||||
ip6t("-D INPUT -j PSW-SERVER 2>/dev/null")
|
||||
ip6t("-F PSW-SERVER 2>/dev/null")
|
||||
ip6t("-X PSW-SERVER 2>/dev/null")
|
||||
else
|
||||
local nft_cmd = "handles=$(nft -a list chain inet fw4 input | grep -E \"PSW-SERVER\" | awk -F '# handle ' '{print$2}')\n for handle in $handles; do\n nft delete rule inet fw4 input handle ${handle} 2>/dev/null\n done"
|
||||
cmd(nft_cmd)
|
||||
cmd("nft flush chain inet fw4 PSW-SERVER 2>/dev/null")
|
||||
cmd("nft delete chain inet fw4 PSW-SERVER 2>/dev/null")
|
||||
end
|
||||
cmd(string.format("rm -rf %s %s /tmp/etc/%s.include", CONFIG_PATH, LOG_APP_FILE, CONFIG))
|
||||
end
|
||||
|
||||
if action then
|
||||
if action == "start" then
|
||||
start()
|
||||
elseif action == "stop" then
|
||||
stop()
|
||||
end
|
||||
end
|
@ -1,126 +0,0 @@
|
||||
module("luci.passwall.util_hysteria2", package.seeall)
|
||||
local api = require "luci.passwall.api"
|
||||
local uci = api.uci
|
||||
local jsonc = api.jsonc
|
||||
|
||||
function gen_config_server(node)
|
||||
local config = {
|
||||
listen = ":" .. node.port,
|
||||
tls = {
|
||||
cert = node.tls_certificateFile,
|
||||
key = node.tls_keyFile,
|
||||
},
|
||||
obfs = (node.hysteria2_obfs) and {
|
||||
type = "salamander",
|
||||
salamander = {
|
||||
password = node.hysteria2_obfs
|
||||
}
|
||||
} or nil,
|
||||
auth = {
|
||||
type = "password",
|
||||
password = node.hysteria2_auth_password
|
||||
},
|
||||
bandwidth = {
|
||||
up = node.hysteria2_up_mbps and node.hysteria2_up_mbps .. " mbps" or "1 gbps",
|
||||
down = node.hysteria2_down_mbps and node.hysteria2_down_mbps .. " mbps" or "1 gbps",
|
||||
},
|
||||
ignoreClientBandwidth = (node.hysteria2_ignoreClientBandwidth == "1") and true or false,
|
||||
disableUDP = (node.hysteria2_udp == "0") and true or false,
|
||||
}
|
||||
return config
|
||||
end
|
||||
|
||||
function gen_config(var)
|
||||
local node_id = var["-node"]
|
||||
if not node_id then
|
||||
print("-node 不能为空")
|
||||
return
|
||||
end
|
||||
local node = uci:get_all("passwall", node_id)
|
||||
local local_tcp_redir_port = var["-local_tcp_redir_port"]
|
||||
local local_udp_redir_port = var["-local_udp_redir_port"]
|
||||
local local_socks_address = var["-local_socks_address"] or "0.0.0.0"
|
||||
local local_socks_port = var["-local_socks_port"]
|
||||
local local_socks_username = var["-local_socks_username"]
|
||||
local local_socks_password = var["-local_socks_password"]
|
||||
local local_http_address = var["-local_http_address"] or "0.0.0.0"
|
||||
local local_http_port = var["-local_http_port"]
|
||||
local local_http_username = var["-local_http_username"]
|
||||
local local_http_password = var["-local_http_password"]
|
||||
local tcp_proxy_way = var["-tcp_proxy_way"]
|
||||
local server_host = var["-server_host"] or node.address
|
||||
local server_port = var["-server_port"] or node.port
|
||||
|
||||
if api.is_ipv6(server_host) then
|
||||
server_host = api.get_ipv6_full(server_host)
|
||||
end
|
||||
local server = server_host .. ":" .. server_port
|
||||
|
||||
if (node.hysteria2_hop) then
|
||||
server = server .. "," .. node.hysteria2_hop
|
||||
end
|
||||
|
||||
local config = {
|
||||
server = server,
|
||||
transport = {
|
||||
type = node.protocol or "udp",
|
||||
udp = {
|
||||
hopInterval = node.hysteria2_hop_interval and node.hysteria2_hop_interval .. "s" or "30s"
|
||||
}
|
||||
},
|
||||
obfs = (node.hysteria2_obfs) and {
|
||||
type = "salamander",
|
||||
salamander = {
|
||||
password = node.hysteria2_obfs
|
||||
}
|
||||
} or nil,
|
||||
auth = node.hysteria2_auth_password,
|
||||
tls = {
|
||||
sni = node.tls_serverName,
|
||||
insecure = (node.tls_allowInsecure == "1") and true or false
|
||||
},
|
||||
quic = {
|
||||
initStreamReceiveWindow = (node.hysteria2_recv_window) and tonumber(node.hysteria2_recv_window) or nil,
|
||||
initConnReceiveWindow = (node.hysteria2_recv_window_conn) and tonumber(node.hysteria2_recv_window_conn) or nil,
|
||||
maxIdleTimeout = (node.hysteria2_idle_timeout) and tonumber(node.hysteria2_idle_timeout) or nil,
|
||||
disablePathMTUDiscovery = (node.hysteria2_disable_mtu_discovery) and true or false,
|
||||
},
|
||||
bandwidth = {
|
||||
up = node.hysteria2_up_mbps and node.hysteria2_up_mbps .. " mbps" or "100 mbps",
|
||||
down = node.hysteria2_down_mbps and node.hysteria2_down_mbps .. " mbps" or "100 mbps"
|
||||
},
|
||||
fast_open = (node.fast_open == "1") and true or false,
|
||||
lazy = true,
|
||||
socks5 = (local_socks_address and local_socks_port) and {
|
||||
listen = local_socks_address .. ":" .. local_socks_port,
|
||||
username = (local_socks_username and local_socks_password) and local_socks_username or nil,
|
||||
password = (local_socks_username and local_socks_password) and local_socks_password or nil,
|
||||
disableUDP = false,
|
||||
} or nil,
|
||||
http = (local_http_address and local_http_port) and {
|
||||
listen = local_http_address .. ":" .. local_http_port,
|
||||
username = (local_http_username and local_http_password) and local_http_username or nil,
|
||||
password = (local_http_username and local_http_password) and local_http_password or nil,
|
||||
} or nil,
|
||||
tcpRedirect = ("redirect" == tcp_proxy_way and local_tcp_redir_port) and {
|
||||
listen = "0.0.0.0:" .. local_tcp_redir_port
|
||||
} or nil,
|
||||
tcpTProxy = ("tproxy" == tcp_proxy_way and local_tcp_redir_port) and {
|
||||
listen = "0.0.0.0:" .. local_tcp_redir_port
|
||||
} or nil,
|
||||
udpTProxy = (local_udp_redir_port) and {
|
||||
listen = "0.0.0.0:" .. local_udp_redir_port
|
||||
} or nil
|
||||
}
|
||||
|
||||
return jsonc.stringify(config, 1)
|
||||
end
|
||||
|
||||
_G.gen_config = gen_config
|
||||
|
||||
if arg[1] then
|
||||
local func =_G[arg[1]]
|
||||
if func then
|
||||
print(func(api.get_function_args(arg)))
|
||||
end
|
||||
end
|
@ -1,39 +0,0 @@
|
||||
module("luci.passwall.util_naiveproxy", package.seeall)
|
||||
local api = require "luci.passwall.api"
|
||||
local uci = api.uci
|
||||
local jsonc = api.jsonc
|
||||
|
||||
function gen_config(var)
|
||||
local node_id = var["-node"]
|
||||
if not node_id then
|
||||
print("-node 不能为空")
|
||||
return
|
||||
end
|
||||
local node = uci:get_all("passwall", node_id)
|
||||
local run_type = var["-run_type"]
|
||||
local local_addr = var["-local_addr"]
|
||||
local local_port = var["-local_port"]
|
||||
local server_host = var["-server_host"] or node.address
|
||||
local server_port = var["-server_port"] or node.port
|
||||
|
||||
if api.is_ipv6(server_host) then
|
||||
server_host = api.get_ipv6_full(server_host)
|
||||
end
|
||||
local server = server_host .. ":" .. server_port
|
||||
|
||||
local config = {
|
||||
listen = run_type .. "://" .. local_addr .. ":" .. local_port,
|
||||
proxy = node.protocol .. "://" .. node.username .. ":" .. node.password .. "@" .. server
|
||||
}
|
||||
|
||||
return jsonc.stringify(config, 1)
|
||||
end
|
||||
|
||||
_G.gen_config = gen_config
|
||||
|
||||
if arg[1] then
|
||||
local func =_G[arg[1]]
|
||||
if func then
|
||||
print(func(api.get_function_args(arg)))
|
||||
end
|
||||
end
|
@ -1,144 +0,0 @@
|
||||
module("luci.passwall.util_shadowsocks", package.seeall)
|
||||
local api = require "luci.passwall.api"
|
||||
local uci = api.uci
|
||||
local jsonc = api.jsonc
|
||||
|
||||
function gen_config_server(node)
|
||||
local config = {}
|
||||
config.server_port = tonumber(node.port)
|
||||
config.password = node.password
|
||||
config.timeout = tonumber(node.timeout)
|
||||
config.fast_open = (node.tcp_fast_open and node.tcp_fast_open == "1") and true or false
|
||||
config.method = node.method
|
||||
|
||||
if node.type == "SS-Rust" then
|
||||
config.server = "::"
|
||||
config.mode = "tcp_and_udp"
|
||||
else
|
||||
config.server = {"[::0]", "0.0.0.0"}
|
||||
end
|
||||
|
||||
if node.type == "SSR" then
|
||||
config.protocol = node.protocol
|
||||
config.protocol_param = node.protocol_param
|
||||
config.obfs = node.obfs
|
||||
config.obfs_param = node.obfs_param
|
||||
end
|
||||
|
||||
return config
|
||||
end
|
||||
|
||||
function gen_config(var)
|
||||
local node_id = var["-node"]
|
||||
if not node_id then
|
||||
print("-node 不能为空")
|
||||
return
|
||||
end
|
||||
local node = uci:get_all("passwall", node_id)
|
||||
local server_host = var["-server_host"] or node.address
|
||||
local server_port = var["-server_port"] or node.port
|
||||
local local_addr = var["-local_addr"]
|
||||
local local_port = var["-local_port"]
|
||||
local mode = var["-mode"]
|
||||
local local_socks_address = var["-local_socks_address"] or "0.0.0.0"
|
||||
local local_socks_port = var["-local_socks_port"]
|
||||
local local_socks_username = var["-local_socks_username"]
|
||||
local local_socks_password = var["-local_socks_password"]
|
||||
local local_http_address = var["-local_http_address"] or "0.0.0.0"
|
||||
local local_http_port = var["-local_http_port"]
|
||||
local local_http_username = var["-local_http_username"]
|
||||
local local_http_password = var["-local_http_password"]
|
||||
local local_tcp_redir_port = var["-local_tcp_redir_port"]
|
||||
local local_tcp_redir_address = var["-local_tcp_redir_address"] or "0.0.0.0"
|
||||
local local_udp_redir_port = var["-local_udp_redir_port"]
|
||||
local local_udp_redir_address = var["-local_udp_redir_address"] or "0.0.0.0"
|
||||
|
||||
if api.is_ipv6(server_host) then
|
||||
server_host = api.get_ipv6_only(server_host)
|
||||
end
|
||||
local server = server_host
|
||||
|
||||
local config = {
|
||||
server = server,
|
||||
server_port = tonumber(server_port),
|
||||
local_address = local_addr,
|
||||
local_port = tonumber(local_port),
|
||||
password = node.password,
|
||||
method = node.method,
|
||||
timeout = tonumber(node.timeout),
|
||||
fast_open = (node.tcp_fast_open and node.tcp_fast_open == "true") and true or false,
|
||||
reuse_port = true,
|
||||
tcp_tproxy = var["-tcp_tproxy"] and true or nil
|
||||
}
|
||||
|
||||
if node.type == "SS" then
|
||||
if node.plugin and node.plugin ~= "none" then
|
||||
config.plugin = node.plugin
|
||||
config.plugin_opts = node.plugin_opts or nil
|
||||
end
|
||||
config.mode = mode
|
||||
elseif node.type == "SSR" then
|
||||
config.protocol = node.protocol
|
||||
config.protocol_param = node.protocol_param
|
||||
config.obfs = node.obfs
|
||||
config.obfs_param = node.obfs_param
|
||||
elseif node.type == "SS-Rust" then
|
||||
config = {
|
||||
servers = {
|
||||
{
|
||||
address = server,
|
||||
port = tonumber(server_port),
|
||||
method = node.method,
|
||||
password = node.password,
|
||||
timeout = tonumber(node.timeout),
|
||||
plugin = (node.plugin and node.plugin ~= "none") and node.plugin or nil,
|
||||
plugin_opts = (node.plugin and node.plugin ~= "none") and node.plugin_opts or nil
|
||||
}
|
||||
},
|
||||
locals = {},
|
||||
fast_open = (node.tcp_fast_open and node.tcp_fast_open == "true") and true or false
|
||||
}
|
||||
if local_socks_address and local_socks_port then
|
||||
table.insert(config.locals, {
|
||||
local_address = local_socks_address,
|
||||
local_port = tonumber(local_socks_port),
|
||||
mode = "tcp_and_udp"
|
||||
})
|
||||
end
|
||||
if local_http_address and local_http_port then
|
||||
table.insert(config.locals, {
|
||||
protocol = "http",
|
||||
local_address = local_http_address,
|
||||
local_port = tonumber(local_http_port)
|
||||
})
|
||||
end
|
||||
if local_tcp_redir_address and local_tcp_redir_port then
|
||||
table.insert(config.locals, {
|
||||
protocol = "redir",
|
||||
mode = "tcp_only",
|
||||
tcp_redir = var["-tcp_tproxy"] and "tproxy" or nil,
|
||||
local_address = local_tcp_redir_address,
|
||||
local_port = tonumber(local_tcp_redir_port)
|
||||
})
|
||||
end
|
||||
if local_udp_redir_address and local_udp_redir_port then
|
||||
table.insert(config.locals, {
|
||||
protocol = "redir",
|
||||
mode = "udp_only",
|
||||
local_address = local_udp_redir_address,
|
||||
local_port = tonumber(local_udp_redir_port)
|
||||
})
|
||||
end
|
||||
end
|
||||
|
||||
return jsonc.stringify(config, 1)
|
||||
end
|
||||
|
||||
_G.gen_config = gen_config
|
||||
|
||||
if arg[1] then
|
||||
local func =_G[arg[1]]
|
||||
if func then
|
||||
print(func(api.get_function_args(arg)))
|
||||
end
|
||||
end
|
File diff suppressed because it is too large
Load Diff
@ -1,158 +0,0 @@
|
||||
module("luci.passwall.util_trojan", package.seeall)
|
||||
local api = require "luci.passwall.api"
|
||||
local uci = api.uci
|
||||
local json = api.jsonc
|
||||
|
||||
function gen_config_server(node)
|
||||
local cipher = "ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES128-GCM-SHA256:ECDHE-ECDSA-CHACHA20-POLY1305:ECDHE-RSA-CHACHA20-POLY1305:ECDHE-ECDSA-AES256-GCM-SHA384:ECDHE-RSA-AES256-GCM-SHA384:ECDHE-ECDSA-AES256-SHA:ECDHE-ECDSA-AES128-SHA:ECDHE-RSA-AES128-SHA:ECDHE-RSA-AES256-SHA:DHE-RSA-AES128-SHA:DHE-RSA-AES256-SHA:AES128-SHA:AES256-SHA:DES-CBC3-SHA"
|
||||
local cipher13 = "TLS_AES_128_GCM_SHA256:TLS_CHACHA20_POLY1305_SHA256:TLS_AES_256_GCM_SHA384"
|
||||
local config = {
|
||||
run_type = "server",
|
||||
local_addr = "::",
|
||||
local_port = tonumber(node.port),
|
||||
remote_addr = (node.remote_enable == "1" and node.remote_address) and node.remote_address or nil,
|
||||
remote_port = (node.remote_enable == "1" and node.remote_port) and tonumber(node.remote_port) or nil,
|
||||
password = node.uuid,
|
||||
log_level = (node.log and node.log == "1") and tonumber(node.loglevel) or 5,
|
||||
ssl = {
|
||||
cert = node.tls_certificateFile,
|
||||
key = node.tls_keyFile,
|
||||
key_password = "",
|
||||
cipher = cipher,
|
||||
cipher_tls13 = cipher13,
|
||||
prefer_server_cipher = true,
|
||||
reuse_session = true,
|
||||
session_ticket = (node.tls_sessionTicket == "1") and true or false,
|
||||
session_timeout = 600,
|
||||
plain_http_response = "",
|
||||
curves = "",
|
||||
dhparam = ""
|
||||
},
|
||||
tcp = {
|
||||
prefer_ipv4 = false,
|
||||
no_delay = true,
|
||||
keep_alive = true,
|
||||
reuse_port = false,
|
||||
fast_open = (node.tcp_fast_open and node.tcp_fast_open == "1") and true or false,
|
||||
fast_open_qlen = 20
|
||||
}
|
||||
}
|
||||
if node.type == "Trojan-Go" then
|
||||
config.ssl.cipher = nil
|
||||
config.ssl.cipher_tls13 = nil
|
||||
config.udp_timeout = 60
|
||||
config.disable_http_check = true
|
||||
config.transport_plugin = ((node.tls == nil or node.tls ~= "1") and node.trojan_transport == "original") and {
|
||||
enabled = node.plugin_type ~= nil,
|
||||
type = node.plugin_type or "plaintext",
|
||||
command = node.plugin_type ~= "plaintext" and node.plugin_cmd or nil,
|
||||
option = node.plugin_type ~= "plaintext" and node.plugin_option or nil,
|
||||
arg = node.plugin_type ~= "plaintext" and { node.plugin_arg } or nil,
|
||||
env = {}
|
||||
} or nil
|
||||
config.websocket = (node.trojan_transport == 'ws') and {
|
||||
enabled = true,
|
||||
path = node.ws_path or "/",
|
||||
host = node.ws_host or ""
|
||||
} or nil
|
||||
config.shadowsocks = (node.ss_aead == "1") and {
|
||||
enabled = true,
|
||||
method = node.ss_aead_method or "aes_128_gcm",
|
||||
password = node.ss_aead_pwd or ""
|
||||
} or nil
|
||||
end
|
||||
return config
|
||||
end
|
||||
|
||||
function gen_config(var)
|
||||
local node_id = var["-node"]
|
||||
if not node_id then
|
||||
print("-node 不能为空")
|
||||
return
|
||||
end
|
||||
local node = uci:get_all("passwall", node_id)
|
||||
local run_type = var["-run_type"]
|
||||
local local_addr = var["-local_addr"]
|
||||
local local_port = var["-local_port"]
|
||||
local server_host = var["-server_host"] or node.address
|
||||
local server_port = var["-server_port"] or node.port
|
||||
local loglevel = var["-loglevel"] or 2
|
||||
local cipher = "ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES128-GCM-SHA256:ECDHE-ECDSA-CHACHA20-POLY1305:ECDHE-RSA-CHACHA20-POLY1305:ECDHE-ECDSA-AES256-GCM-SHA384:ECDHE-RSA-AES256-GCM-SHA384:ECDHE-ECDSA-AES256-SHA:ECDHE-ECDSA-AES128-SHA:ECDHE-RSA-AES128-SHA:ECDHE-RSA-AES256-SHA:DHE-RSA-AES128-SHA:DHE-RSA-AES256-SHA:AES128-SHA:AES256-SHA:DES-CBC3-SHA"
|
||||
local cipher13 = "TLS_AES_128_GCM_SHA256:TLS_CHACHA20_POLY1305_SHA256:TLS_AES_256_GCM_SHA384"
|
||||
|
||||
if api.is_ipv6(server_host) then
|
||||
server_host = api.get_ipv6_only(server_host)
|
||||
end
|
||||
local server = server_host
|
||||
|
||||
local trojan = {
|
||||
run_type = run_type,
|
||||
local_addr = local_addr,
|
||||
local_port = tonumber(local_port),
|
||||
remote_addr = server,
|
||||
remote_port = tonumber(server_port),
|
||||
password = {node.password},
|
||||
log_level = tonumber(loglevel),
|
||||
ssl = {
|
||||
verify = (node.tls_allowInsecure ~= "1") and true or false,
|
||||
verify_hostname = true,
|
||||
cert = nil,
|
||||
cipher = cipher,
|
||||
cipher_tls13 = cipher13,
|
||||
sni = node.tls_serverName or server,
|
||||
alpn = {"h2", "http/1.1"},
|
||||
reuse_session = true,
|
||||
session_ticket = (node.tls_sessionTicket and node.tls_sessionTicket == "1") and true or false,
|
||||
curves = ""
|
||||
},
|
||||
udp_timeout = 60,
|
||||
tcp = {
|
||||
use_tproxy = (node.type == "Trojan-Plus" and var["-use_tproxy"]) and true or nil,
|
||||
no_delay = true,
|
||||
keep_alive = true,
|
||||
reuse_port = true,
|
||||
fast_open = (node.tcp_fast_open == "true") and true or false,
|
||||
fast_open_qlen = 20
|
||||
}
|
||||
}
|
||||
if node.type == "Trojan-Go" then
|
||||
trojan.ssl.cipher = nil
|
||||
trojan.ssl.cipher_tls13 = nil
|
||||
trojan.ssl.fingerprint = (node.fingerprint ~= "disable") and node.fingerprint or ""
|
||||
trojan.ssl.alpn = (node.trojan_transport == 'ws') and {} or {"h2", "http/1.1"}
|
||||
if node.tls ~= "1" and node.trojan_transport == "original" then trojan.ssl = nil end
|
||||
trojan.transport_plugin = ((not node.tls or node.tls ~= "1") and node.trojan_transport == "original") and {
|
||||
enabled = node.plugin_type ~= nil,
|
||||
type = node.plugin_type or "plaintext",
|
||||
command = node.plugin_type ~= "plaintext" and node.plugin_cmd or nil,
|
||||
option = node.plugin_type ~= "plaintext" and node.plugin_option or nil,
|
||||
arg = node.plugin_type ~= "plaintext" and { node.plugin_arg } or nil,
|
||||
env = {}
|
||||
} or nil
|
||||
trojan.websocket = (node.trojan_transport == 'ws') and {
|
||||
enabled = true,
|
||||
path = node.ws_path or "/",
|
||||
host = node.ws_host or (node.tls_serverName or server)
|
||||
} or nil
|
||||
trojan.shadowsocks = (node.ss_aead == "1") and {
|
||||
enabled = true,
|
||||
method = node.ss_aead_method or "aes_128_gcm",
|
||||
password = node.ss_aead_pwd or ""
|
||||
} or nil
|
||||
trojan.mux = (node.smux == "1") and {
|
||||
enabled = true,
|
||||
concurrency = tonumber(node.mux_concurrency),
|
||||
idle_timeout = tonumber(node.smux_idle_timeout)
|
||||
} or nil
|
||||
end
|
||||
return json.stringify(trojan, 1)
|
||||
end
|
||||
|
||||
_G.gen_config = gen_config
|
||||
|
||||
if arg[1] then
|
||||
local func =_G[arg[1]]
|
||||
if func then
|
||||
print(func(api.get_function_args(arg)))
|
||||
end
|
||||
end
|
@ -1,57 +0,0 @@
|
||||
module("luci.passwall.util_tuic", package.seeall)
|
||||
local api = require "luci.passwall.api"
|
||||
local uci = api.uci
|
||||
local json = api.jsonc
|
||||
|
||||
function gen_config(var)
|
||||
local node_id = var["-node"]
|
||||
if not node_id then
|
||||
print("-node 不能为空")
|
||||
return
|
||||
end
|
||||
local node = uci:get_all("passwall", node_id)
|
||||
local local_addr = var["-local_addr"]
|
||||
local local_port = var["-local_port"]
|
||||
local server_host = var["-server_host"] or node.address
|
||||
local server_port = var["-server_port"] or node.port
|
||||
local loglevel = var["-loglevel"] or "warn"
|
||||
|
||||
local tuic= {
|
||||
relay = {
|
||||
server = server_host .. ":" .. server_port,
|
||||
ip = node.tuic_ip,
|
||||
uuid = node.uuid,
|
||||
password = node.tuic_password,
|
||||
-- certificates = node.tuic_certificate and { node.tuic_certpath } or nil,
|
||||
udp_relay_mode = node.tuic_udp_relay_mode,
|
||||
congestion_control = node.tuic_congestion_control,
|
||||
heartbeat = node.tuic_heartbeat .. "s",
|
||||
timeout = node.tuic_timeout .. "s",
|
||||
gc_interval = node.tuic_gc_interval .. "s",
|
||||
gc_lifetime = node.tuic_gc_lifetime .. "s",
|
||||
alpn = node.tuic_tls_alpn,
|
||||
disable_sni = (node.tuic_disable_sni == "1"),
|
||||
zero_rtt_handshake = (node.tuic_zero_rtt_handshake == "1"),
|
||||
send_window = tonumber(node.tuic_send_window),
|
||||
receive_window = tonumber(node.tuic_receive_window)
|
||||
},
|
||||
["local"] = {
|
||||
server = "[::]:" .. local_port,
|
||||
username = node.tuic_socks_username,
|
||||
password = node.tuic_socks_password,
|
||||
dual_stack = (node.tuic_dual_stack == "1") and true or false,
|
||||
max_packet_size = tonumber(node.tuic_max_package_size)
|
||||
},
|
||||
log_level = loglevel
|
||||
}
|
||||
return json.stringify(tuic, 1)
|
||||
end
|
||||
|
||||
_G.gen_config = gen_config
|
||||
|
||||
if arg[1] then
|
||||
local func =_G[arg[1]]
|
||||
if func then
|
||||
print(func(api.get_function_args(arg)))
|
||||
end
|
||||
end
|
File diff suppressed because it is too large
Load Diff
@ -1,204 +0,0 @@
|
||||
<%
|
||||
local api = require "luci.passwall.api"
|
||||
local com = require "luci.passwall.com"
|
||||
local version = {}
|
||||
-%>
|
||||
|
||||
<script type="text/javascript">
|
||||
//<![CDATA[
|
||||
var appInfoList = new Array();
|
||||
var inProgressCount = 0;
|
||||
var tokenStr = '<%=token%>';
|
||||
var checkUpdateText = '<%:Check update%>';
|
||||
var noUpdateText = '<%:It is the latest version%>';
|
||||
var updateSuccessText = '<%:Update successful%>';
|
||||
var clickToUpdateText = '<%:Click to update%>';
|
||||
var inProgressText = '<%:Updating...%>';
|
||||
var unexpectedErrorText = '<%:Unexpected error%>';
|
||||
var updateInProgressNotice = '<%:Updating, are you sure to close?%>';
|
||||
var downloadingText = '<%:Downloading...%>';
|
||||
var decompressioningText = '<%:Unpacking...%>';
|
||||
var movingText = '<%:Moving...%>';
|
||||
|
||||
//window.onload = function () {};
|
||||
|
||||
function addPageNotice() {
|
||||
if (inProgressCount === 0) {
|
||||
window.onbeforeunload = function (e) {
|
||||
e.returnValue = updateInProgressNotice;
|
||||
return updateInProgressNotice;
|
||||
};
|
||||
}
|
||||
inProgressCount++;
|
||||
}
|
||||
|
||||
function removePageNotice() {
|
||||
inProgressCount--;
|
||||
if (inProgressCount === 0) {
|
||||
window.onbeforeunload = undefined;
|
||||
}
|
||||
}
|
||||
|
||||
function onUpdateSuccess(btn) {
|
||||
if (btn) {
|
||||
btn.value = updateSuccessText;
|
||||
btn.placeholder = updateSuccessText;
|
||||
btn.disabled = true;
|
||||
}
|
||||
|
||||
if (inProgressCount === 0) {
|
||||
window.setTimeout(function () {
|
||||
window.location.reload();
|
||||
}, 1000);
|
||||
}
|
||||
}
|
||||
|
||||
function onRequestError(btn, errorMessage) {
|
||||
btn.disabled = false;
|
||||
btn.value = checkUpdateText;
|
||||
|
||||
var ckeckDetailElm = document.getElementById(btn.id + '-detail');
|
||||
if (errorMessage && ckeckDetailElm) {
|
||||
ckeckDetailElm.textContent = errorMessage
|
||||
}
|
||||
}
|
||||
|
||||
function onBtnClick(btn, app) {
|
||||
if (appInfoList[app] === undefined) {
|
||||
checkUpdate(btn, app);
|
||||
} else {
|
||||
doUpdate(btn, app);
|
||||
}
|
||||
}
|
||||
|
||||
function checkUpdate(btn, app) {
|
||||
btn.disabled = true;
|
||||
btn.value = inProgressText;
|
||||
|
||||
addPageNotice();
|
||||
|
||||
var ckeckDetailElm = document.getElementById(btn.id + '-detail');
|
||||
if (ckeckDetailElm) {
|
||||
ckeckDetailElm.textContent = "";
|
||||
}
|
||||
XHR.get('<%=api.url("check_")%>' + app, {
|
||||
token: tokenStr,
|
||||
arch: ''
|
||||
}, function (x, json) {
|
||||
removePageNotice();
|
||||
if (json.code) {
|
||||
appInfoList[app] = undefined;
|
||||
onRequestError(btn, json.error);
|
||||
} else {
|
||||
if (json.has_update) {
|
||||
appInfoList[app] = json;
|
||||
btn.disabled = false;
|
||||
btn.value = clickToUpdateText;
|
||||
btn.placeholder = clickToUpdateText;
|
||||
|
||||
if (ckeckDetailElm) {
|
||||
var urlNode = '';
|
||||
if (json.remote_version) {
|
||||
urlNode = '<em style="color:red;">' + json.remote_version + '</em>';
|
||||
if (json.html_url) {
|
||||
urlNode = '<a href="' + json.html_url + '" target="_blank">' + urlNode + '</a>';
|
||||
}
|
||||
}
|
||||
ckeckDetailElm.innerHTML = urlNode;
|
||||
}
|
||||
} else {
|
||||
btn.disabled = true;
|
||||
btn.value = noUpdateText;
|
||||
}
|
||||
}
|
||||
}, 300);
|
||||
}
|
||||
|
||||
function doUpdate(btn, app) {
|
||||
btn.disabled = true;
|
||||
btn.value = downloadingText;
|
||||
|
||||
addPageNotice();
|
||||
|
||||
var appUpdateUrl = '<%=api.url("update_")%>' + app;
|
||||
var appInfo = appInfoList[app];
|
||||
// Download file
|
||||
XHR.get(appUpdateUrl, {
|
||||
token: tokenStr,
|
||||
url: appInfo ? appInfo.data.browser_download_url : '',
|
||||
size: appInfo ? appInfo.data.size / 1024 : null
|
||||
}, function (x, json) {
|
||||
if (json.code) {
|
||||
removePageNotice();
|
||||
onRequestError(btn, json.error);
|
||||
} else if (json.zip) {
|
||||
btn.value = decompressioningText;
|
||||
|
||||
// Extract file
|
||||
XHR.get(appUpdateUrl, {
|
||||
token: tokenStr,
|
||||
task: 'extract',
|
||||
file: json.file,
|
||||
subfix: appInfo ? appInfo.type : ''
|
||||
}, function (x, json) {
|
||||
if (json.code) {
|
||||
removePageNotice();
|
||||
onRequestError(btn, json.error);
|
||||
} else {
|
||||
move(btn, appUpdateUrl, json.file);
|
||||
}
|
||||
}, 300)
|
||||
} else {
|
||||
move(btn, appUpdateUrl, json.file);
|
||||
}
|
||||
}, 300)
|
||||
}
|
||||
|
||||
function move(btn, url, file) {
|
||||
btn.value = movingText;
|
||||
|
||||
// Move file to target dir
|
||||
XHR.get(url, {
|
||||
token: tokenStr,
|
||||
task: 'move',
|
||||
file: file
|
||||
}, function (x, json) {
|
||||
removePageNotice();
|
||||
if (json.code) {
|
||||
onRequestError(btn, json.error);
|
||||
} else {
|
||||
onUpdateSuccess(btn);
|
||||
}
|
||||
}, 300)
|
||||
}
|
||||
//]]>
|
||||
</script>
|
||||
|
||||
<div class="cbi-value">
|
||||
<label class="cbi-value-title">Passwall <%:Version%></label>
|
||||
<div class="cbi-value-field">
|
||||
<div class="cbi-value-description">
|
||||
<span>【 <%=api.get_version()%> 】</span>
|
||||
<input class="btn cbi-button cbi-button-apply" type="button" id="passwall-check_btn"
|
||||
onclick="onBtnClick(this,'passwall');" value="<%:Check update%>" />
|
||||
<span id="passwall-check_btn-detail"></span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<%for k, v in pairs(com) do
|
||||
version[k] = api.get_app_version(k)%>
|
||||
<div class="cbi-value">
|
||||
<label class="cbi-value-title"><%=v.name%>
|
||||
<%:Version%>
|
||||
</label>
|
||||
<div class="cbi-value-field">
|
||||
<div class="cbi-value-description">
|
||||
<span>【 <%=version[k] ~="" and version[k] or translate("Null") %> 】</span>
|
||||
<input class="btn cbi-button cbi-button-apply" type="button" id="_<%=k%>-check_btn"
|
||||
onclick="onBtnClick(this,'<%=k%>');" value="<%:Check update%>" />
|
||||
<span id="_<%=k%>-check_btn-detail"></span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<%end%>
|
@ -1,43 +0,0 @@
|
||||
<%
|
||||
local api = require "luci.passwall.api"
|
||||
-%>
|
||||
<div class="cbi-section cbi-tblsection">
|
||||
<div id="dns_div">
|
||||
<ul><b style="color:red"><%:About DNS issues:%></b>
|
||||
<li style="color:red">1. <span><%:Some browsers may have built-in DNS, be sure to close. Example: Chrome. Settings - Security and Privacy - Security - Use secure DNS disabled.%></span></li>
|
||||
<li style="color:red">2. <span><%:Sometimes after restart, you can not internet, especially the GFW mode. At this time, close all browsers (important), Windows Client, please `ipconfig /flushdns`. Please close the WiFi on the phone, cut the flight mode and then cut back.%></span></li>
|
||||
<li style="color:red">3. <span><%:The client DNS and the default gateway must point to this router.%></span></li>
|
||||
<li style="color:red">4. <span><%:If you have a wrong DNS process, the consequences are at your own risk!%></span></li>
|
||||
</ul>
|
||||
</div>
|
||||
<div id="div2"></div>
|
||||
</div>
|
||||
|
||||
<script>
|
||||
var origin = window.location.origin;
|
||||
var reset_url = origin + "<%=api.url("reset_config")%>";
|
||||
var hide_url = origin + "<%=api.url("hide")%>";
|
||||
var show_url = origin + "<%=api.url("show")%>";
|
||||
|
||||
function reset(url) {
|
||||
if (confirm('<%:Are you sure to reset?%>') == true) {
|
||||
window.location.href = reset_url;
|
||||
}
|
||||
}
|
||||
|
||||
function hide(url) {
|
||||
if (confirm('<%:Are you sure to hide?%>') == true) {
|
||||
window.location.href = hide_url;
|
||||
}
|
||||
}
|
||||
|
||||
var dom = document.getElementById("div2");
|
||||
if (dom) {
|
||||
var li = "";
|
||||
li += "<%:You can use load balancing for failover.%>" + "<br />";
|
||||
li += "<%:Restore the default configuration method. Input example in the address bar:%>" + "<a href='#' onclick='reset()'>" + reset_url + "</a>" + "<br />";
|
||||
li += "<%:Hide menu method, input example in the address bar:%>" + "<a href='#' onclick='hide()'>" + hide_url + "</a>" + "<br />";
|
||||
li += "<%:After the hidden to the display, input example in the address bar:%>" + "<a href='#'>" + show_url + "</a>" + "<br />";
|
||||
dom.innerHTML = li;
|
||||
}
|
||||
</script>
|
@ -1,136 +0,0 @@
|
||||
<%
|
||||
local api = require "luci.passwall.api"
|
||||
-%>
|
||||
<script type="text/javascript">
|
||||
//<![CDATA[
|
||||
function go() {
|
||||
var _status = document.getElementsByClassName('_status');
|
||||
for (var i = 0; i < _status.length; i++) {
|
||||
var id = _status[i].getAttribute("socks_id");
|
||||
XHR.get('<%=api.url("socks_status")%>', {
|
||||
index: i,
|
||||
id: id
|
||||
},
|
||||
function(x, result) {
|
||||
var index = result.index;
|
||||
var div = '';
|
||||
var div1 = '<font style="font-weight:bold;" color="green">✓</font> ';
|
||||
var div2 = '<font style="font-weight:bold;" color="red">X</font> ';
|
||||
|
||||
if (result.socks_status) {
|
||||
div += div1;
|
||||
} else {
|
||||
div += div2;
|
||||
}
|
||||
if (result.use_http) {
|
||||
if (result.http_status) {
|
||||
div += div1;
|
||||
} else {
|
||||
div += div2;
|
||||
}
|
||||
}
|
||||
_status[index].innerHTML = div;
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
var global_id = null;
|
||||
var global = document.getElementById("cbi-passwall-global");
|
||||
if (global) {
|
||||
var node = global.getElementsByClassName("cbi-section-node")[0];
|
||||
var node_id = node.getAttribute("id");
|
||||
global_id = node_id;
|
||||
var reg1 = new RegExp("(?<=" + node_id + "-).*?(?=(_node))")
|
||||
for (var i = 0; i < node.childNodes.length; i++) {
|
||||
if (node.childNodes[i].childNodes && node.childNodes[i].childNodes.length > 0) {
|
||||
for (var k = 0; k < node.childNodes[i].childNodes.length; k++) {
|
||||
try {
|
||||
var dom = node.childNodes[i].childNodes[k];
|
||||
if (dom.id) {
|
||||
var s = dom.id.match(reg1);
|
||||
if (s) {
|
||||
var cbi_id = global_id + "-"
|
||||
var dom_id = dom.id.split(cbi_id).join(cbi_id.split("-").join(".")).split("cbi.").join("cbid.")
|
||||
var node_select = document.getElementsByName(dom_id)[0];
|
||||
var node_select_value = node_select.value;
|
||||
if (node_select_value && node_select_value != "nil" && node_select_value.indexOf("socks://") != 0 && node_select_value.indexOf("_default") != 0 && node_select_value.indexOf("_direct") != 0 && node_select_value.indexOf("_blackhole") != 0) {
|
||||
if (global_id != null && node_select_value.indexOf("tcp") == 0) {
|
||||
var d = global_id + "-tcp_node";
|
||||
d = d.replace("cbi-", "cbid-").replace(new RegExp("-", 'g'), ".");
|
||||
var dom = document.getElementsByName(d)[0];
|
||||
var _node_select_value = dom.value;
|
||||
if (_node_select_value && _node_select_value != "nil") {
|
||||
node_select_value = _node_select_value;
|
||||
}
|
||||
}
|
||||
|
||||
if (node_select.tagName == "INPUT") {
|
||||
node_select = document.getElementById("cbi.combobox." + dom_id);
|
||||
}
|
||||
|
||||
var new_a = document.createElement("a");
|
||||
new_a.innerHTML = "<%:Edit%>";
|
||||
new_a.href = "#";
|
||||
new_a.setAttribute("onclick", "location.href='" + '<%=api.url("node_config")%>' + "/" + node_select_value + "'");
|
||||
var new_html = new_a.outerHTML;
|
||||
|
||||
if (s[0] == "tcp" || s[0] == "udp") {
|
||||
var log_a = document.createElement("a");
|
||||
log_a.innerHTML = "<%:Log%>";
|
||||
log_a.href = "#";
|
||||
log_a.setAttribute("onclick", "window.open('" + '<%=api.url("get_redir_log")%>' + "?proto=" + s[0] + "', '_blank')");
|
||||
new_html += "  " + log_a.outerHTML;
|
||||
}
|
||||
|
||||
node_select.insertAdjacentHTML("afterend", "  " + new_html);
|
||||
}
|
||||
}
|
||||
}
|
||||
} catch(err) {
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
var socks = document.getElementById("cbi-passwall-socks");
|
||||
if (socks) {
|
||||
var socks_enabled_dom = document.getElementById(global_id + "-socks_enabled");
|
||||
socks_enabled_dom.parentNode.removeChild(socks_enabled_dom);
|
||||
var descr = socks.getElementsByClassName("cbi-section-descr")[0];
|
||||
descr.outerHTML = socks_enabled_dom.outerHTML;
|
||||
rows = socks.getElementsByClassName("cbi-section-table-row");
|
||||
for (var i = 0; i < rows.length; i++) {
|
||||
try {
|
||||
var row = rows[i];
|
||||
var id = row.id;
|
||||
if (!id) continue;
|
||||
var dom_id = id + "-node";
|
||||
var node = document.getElementById(dom_id);
|
||||
var dom_id = dom_id.replace("cbi-", "cbid-").replace(new RegExp("-", 'g'), ".");
|
||||
var node_select = document.getElementsByName(dom_id)[0];
|
||||
var node_select_value = node_select.value;
|
||||
if (node_select_value && node_select_value != "nil") {
|
||||
var v = document.getElementById(dom_id + "-" + node_select_value);
|
||||
if (v) {
|
||||
node_select.title = v.text;
|
||||
} else {
|
||||
node_select.title = node_select.options[node_select.options.selectedIndex].text;
|
||||
}
|
||||
|
||||
var new_a = document.createElement("a");
|
||||
new_a.innerHTML = "<%:Edit%>";
|
||||
new_a.href = "#";
|
||||
new_a.setAttribute("onclick","location.href='" + '<%=api.url("node_config")%>' + "/" + node_select_value + "'");
|
||||
|
||||
node_select.insertAdjacentHTML("afterend", "  " + new_a.outerHTML);
|
||||
}
|
||||
} catch(err) {
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
setTimeout("go()", 1000);
|
||||
|
||||
//]]>
|
||||
</script>
|
File diff suppressed because one or more lines are too long
@ -1,26 +0,0 @@
|
||||
<%
|
||||
local api = require "luci.passwall.api"
|
||||
local console_port = api.uci_get_type("global_haproxy", "console_port", "")
|
||||
-%>
|
||||
<p id="_status"></p>
|
||||
|
||||
<script type="text/javascript">//<![CDATA[
|
||||
XHR.poll(3, '<%=api.url("haproxy_status")%>', null,
|
||||
function(x, result) {
|
||||
if (x && x.status == 200) {
|
||||
var _status = document.getElementById('_status');
|
||||
if (_status) {
|
||||
if (result) {
|
||||
_status.innerHTML = '<input type="button" class="btn cbi-button cbi-button-apply" value="<%:Enter interface%>" onclick="openwebui()" />';
|
||||
} else {
|
||||
_status.innerHTML = '';
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
function openwebui(){
|
||||
var url = window.location.hostname + ":<%=console_port%>";
|
||||
window.open('http://' + url, 'target', '');
|
||||
}
|
||||
//]]></script>
|
@ -1,31 +0,0 @@
|
||||
<%
|
||||
local api = require "luci.passwall.api"
|
||||
-%>
|
||||
<script type="text/javascript">
|
||||
//<![CDATA[
|
||||
function clearlog(btn) {
|
||||
XHR.get('<%=api.url("clear_log")%>', null,
|
||||
function(x, data) {
|
||||
if(x && x.status == 200) {
|
||||
var log_textarea = document.getElementById('log_textarea');
|
||||
log_textarea.innerHTML = "";
|
||||
log_textarea.scrollTop = log_textarea.scrollHeight;
|
||||
}
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
XHR.poll(5, '<%=api.url("get_log")%>', null,
|
||||
function(x, data) {
|
||||
if(x && x.status == 200) {
|
||||
var log_textarea = document.getElementById('log_textarea');
|
||||
log_textarea.innerHTML = x.responseText;
|
||||
}
|
||||
}
|
||||
);
|
||||
//]]>
|
||||
</script>
|
||||
<fieldset class="cbi-section" id="_log_fieldset">
|
||||
<input class="btn cbi-button cbi-button-remove" type="button" onclick="clearlog()" value="<%:Clear logs%>" />
|
||||
<textarea id="log_textarea" class="cbi-input-textarea" style="width: 100%;margin-top: 10px;" data-update="change" rows="40" wrap="off" readonly="readonly"></textarea>
|
||||
</fieldset>
|
@ -1,108 +0,0 @@
|
||||
<%
|
||||
local api = require "luci.passwall.api"
|
||||
-%>
|
||||
|
||||
<style>
|
||||
#add_link_div{
|
||||
display: none;
|
||||
width: auto;
|
||||
position: absolute;
|
||||
left:50%;
|
||||
top:50%;
|
||||
transform: translate(-50%, -50%);
|
||||
z-index: 99;
|
||||
text-align: center;
|
||||
background: white;
|
||||
box-shadow: darkgrey 10px 10px 30px 5px;
|
||||
padding: 30px 15px;
|
||||
}
|
||||
</style>
|
||||
|
||||
<script type="text/javascript">
|
||||
//<![CDATA[
|
||||
function ajax_add_node(link) {
|
||||
if (link) {
|
||||
XHR.get('<%=api.url("link_add_node")%>', {
|
||||
'link': link
|
||||
},
|
||||
function(x, data) {
|
||||
if(x && x.status == 200) {
|
||||
window.location.href = '<%=api.url("node_list")%>';
|
||||
}
|
||||
else {
|
||||
alert("<%:Error%>");
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
function open_add_link_div() {
|
||||
document.getElementById("add_link_div").style.display = "block";
|
||||
document.getElementById("nodes_link").focus();
|
||||
}
|
||||
|
||||
function close_add_link_div() {
|
||||
document.getElementById("add_link_div").style.display = "none";
|
||||
}
|
||||
|
||||
function add_node() {
|
||||
var nodes_link = document.getElementById("nodes_link").value;
|
||||
if (nodes_link.trim() != "") {
|
||||
var supports = "ss ssr vmess vless trojan trojan-go hysteria";
|
||||
var itype = nodes_link.split('://')[0];
|
||||
if (itype.trim() != "" && supports.indexOf(itype) >= 0) {
|
||||
ajax_add_node(nodes_link);
|
||||
}
|
||||
else {
|
||||
alert("<%:Please enter the correct link.%>");
|
||||
}
|
||||
}
|
||||
else {
|
||||
document.getElementById("nodes_link").focus();
|
||||
}
|
||||
}
|
||||
|
||||
function clear_all_nodes() {
|
||||
if (confirm('<%:Are you sure to clear all nodes?%>') == true){
|
||||
XHR.get('<%=api.url("clear_all_nodes")%>', null,
|
||||
function(x, data) {
|
||||
if(x && x.status == 200) {
|
||||
window.location.href = '<%=api.url("node_list")%>';
|
||||
}
|
||||
else {
|
||||
alert("<%:Error%>");
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
//]]>
|
||||
</script>
|
||||
|
||||
<div id="add_link_div">
|
||||
<div class="cbi-value">
|
||||
<label class="cbi-value-title"><%:SS/SSR/Vmess/VLESS/Trojan/Hysteria Link%></label>
|
||||
<div class="cbi-value-field">
|
||||
<textarea id="nodes_link" rows="5" cols="50"></textarea>
|
||||
</div>
|
||||
</div>
|
||||
<div class="cbi-value">
|
||||
<div class="cbi-value-field" style="display: unset">
|
||||
<input class="btn cbi-button cbi-button-add" type="button" onclick="add_node()" value="<%:Add%>" />
|
||||
<input class="btn cbi-button cbi-button-remove" type="button" onclick="close_add_link_div()" value="<%:Close%>" />
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="cbi-value">
|
||||
<label class="cbi-value-title"></label>
|
||||
<div class="cbi-value-field">
|
||||
<input class="btn cbi-button cbi-button-add" type="submit" name="cbi.cts.<%=api.appname%>.nodes." value="<%:Add%>" />
|
||||
<input class="btn cbi-button cbi-button-add" type="button" onclick="open_add_link_div()" value="<%:Add the node via the link%>" />
|
||||
<input class="btn cbi-button cbi-button-remove" type="button" onclick="clear_all_nodes()" value="<%:Clear all nodes%>" />
|
||||
<input class="btn cbi-button cbi-button-remove" type="button" onclick="delete_select_nodes()" value="<%:Delete select nodes%>" />
|
||||
<input class="btn cbi-button" type="button" onclick="checked_all_node(this)" value="<%:Select all%>" />
|
||||
<input class="btn cbi-button cbi-button-apply" type="submit" name="cbi.apply" value="<%:Save & Apply%>" />
|
||||
<div id="div_node_count"></div>
|
||||
</div>
|
||||
</div>
|
File diff suppressed because it is too large
Load Diff
@ -1,475 +0,0 @@
|
||||
<%
|
||||
local api = require "luci.passwall.api"
|
||||
-%>
|
||||
|
||||
<style>
|
||||
table th, .table .th {
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
table td, .table .td {
|
||||
text-align: center;
|
||||
/* white-space: nowrap; */
|
||||
word-break: keep-all;
|
||||
}
|
||||
|
||||
#set_node_div {
|
||||
display: none;
|
||||
width: 30rem;
|
||||
position: fixed;
|
||||
top:50%;
|
||||
padding-top: 30px;
|
||||
z-index: 99;
|
||||
text-align: center;
|
||||
background: white;
|
||||
box-shadow: darkgrey 10px 10px 30px 5px;
|
||||
}
|
||||
|
||||
._now_use {
|
||||
background: #94e1ff !important;
|
||||
}
|
||||
|
||||
.ping a:hover{
|
||||
text-decoration : underline;
|
||||
}
|
||||
</style>
|
||||
|
||||
<script type="text/javascript">
|
||||
//<![CDATA[
|
||||
var node_list = {};
|
||||
var node_count = 0;
|
||||
|
||||
var ajax = {
|
||||
post: function(url, data, fn_success, timeout, fn_timeout) {
|
||||
var xhr = new XMLHttpRequest();
|
||||
var code = ajax.encode(data);
|
||||
xhr.open("POST", url, true);
|
||||
xhr.setRequestHeader("Content-Type", "application/x-www-form-urlencoded");
|
||||
|
||||
if (timeout && timeout > 1000) {
|
||||
xhr.timeout = timeout;
|
||||
}
|
||||
if (fn_timeout) {
|
||||
xhr.ontimeout = function() {
|
||||
fn_timeout(xhr);
|
||||
}
|
||||
}
|
||||
xhr.onreadystatechange = function() {
|
||||
if(xhr.readyState == 4 && (xhr.status == 200 || xhr.status == 304)) {
|
||||
var json = null;
|
||||
if (xhr.getResponseHeader("Content-Type") == "application/json") {
|
||||
try {
|
||||
json = eval('(' + xhr.responseText + ')');
|
||||
}
|
||||
catch(e) {
|
||||
json = null;
|
||||
}
|
||||
}
|
||||
fn_success(xhr, json);
|
||||
}
|
||||
};
|
||||
xhr.send(code);
|
||||
},
|
||||
encode: function(obj) {
|
||||
obj = obj ? obj : { };
|
||||
obj['_'] = Math.random();
|
||||
|
||||
if (typeof obj == 'object')
|
||||
{
|
||||
var code = '';
|
||||
var self = this;
|
||||
|
||||
for (var k in obj)
|
||||
code += (code ? '&' : '') +
|
||||
k + '=' + encodeURIComponent(obj[k]);
|
||||
|
||||
return code;
|
||||
}
|
||||
|
||||
return obj;
|
||||
}
|
||||
}
|
||||
|
||||
function copy_node(cbi_id) {
|
||||
window.location.href = '<%=api.url("copy_node")%>' + "?section=" + cbi_id;
|
||||
}
|
||||
|
||||
var section = "";
|
||||
function open_set_node_div(cbi_id) {
|
||||
section = cbi_id;
|
||||
document.getElementById("set_node_div").style.display="block";
|
||||
var node_name = document.getElementById("cbid.passwall." + cbi_id + ".remarks").value;
|
||||
document.getElementById("set_node_name").innerHTML = node_name;
|
||||
}
|
||||
|
||||
function close_set_node_div() {
|
||||
document.getElementById("set_node_div").style.display="none";
|
||||
document.getElementById("set_node_name").innerHTML = "";
|
||||
}
|
||||
|
||||
function _cbi_row_top(id) {
|
||||
var dom = document.getElementById("cbi-passwall-" + id);
|
||||
if (dom) {
|
||||
var trs = document.getElementById("cbi-passwall-nodes").getElementsByClassName("cbi-section-table-row");
|
||||
if (trs && trs.length > 0) {
|
||||
for (var i = 0; i < trs.length; i++) {
|
||||
var up = dom.getElementsByClassName("cbi-button-up");
|
||||
if (up) {
|
||||
cbi_row_swap(up[0], true, 'cbi.sts.passwall.nodes');
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function checked_all_node(btn) {
|
||||
var doms = document.getElementById("cbi-passwall-nodes").getElementsByClassName("nodes_select");
|
||||
if (doms && doms.length > 0) {
|
||||
for (var i = 0 ; i < doms.length; i++) {
|
||||
doms[i].checked = true;
|
||||
}
|
||||
btn.value = "<%:DeSelect all%>";
|
||||
btn.setAttribute("onclick", "dechecked_all_node(this)");
|
||||
}
|
||||
}
|
||||
|
||||
function dechecked_all_node(btn) {
|
||||
var doms = document.getElementById("cbi-passwall-nodes").getElementsByClassName("nodes_select");
|
||||
if (doms && doms.length > 0) {
|
||||
for (var i = 0 ; i < doms.length; i++) {
|
||||
doms[i].checked = false;
|
||||
}
|
||||
btn.value = "<%:Select all%>";
|
||||
btn.setAttribute("onclick", "checked_all_node(this)");
|
||||
}
|
||||
}
|
||||
|
||||
function delete_select_nodes() {
|
||||
var ids = [];
|
||||
var doms = document.getElementById("cbi-passwall-nodes").getElementsByClassName("nodes_select");
|
||||
if (doms && doms.length > 0) {
|
||||
for (var i = 0 ; i < doms.length; i++) {
|
||||
if (doms[i].checked) {
|
||||
ids.push(doms[i].getAttribute("cbid"))
|
||||
}
|
||||
}
|
||||
if (ids.length > 0) {
|
||||
if (confirm('<%:Are you sure to delete select nodes?%>') == true){
|
||||
XHR.get('<%=api.url("delete_select_nodes")%>', {
|
||||
ids: ids.join()
|
||||
},
|
||||
function(x, data) {
|
||||
if (x && x.status == 200) {
|
||||
/*
|
||||
for (var i = 0 ; i < ids.length; i++) {
|
||||
var box = document.getElementById("cbi-passwall-" + ids[i]);
|
||||
box.remove();
|
||||
}
|
||||
*/
|
||||
window.location.href = '<%=api.url("node_list")%>';
|
||||
}
|
||||
else {
|
||||
alert("<%:Error%>");
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
if (ids.length <= 0) {
|
||||
alert("<%:You no select nodes !%>");
|
||||
}
|
||||
}
|
||||
|
||||
function set_node(protocol) {
|
||||
if (confirm('<%:Are you sure set to%> ' + protocol.toUpperCase() + '<%:the server?%>')==true){
|
||||
window.location.href = '<%=api.url("set_node")%>?protocol=' + protocol + '§ion=' + section;
|
||||
}
|
||||
}
|
||||
|
||||
function get_address_full(id) {
|
||||
try {
|
||||
var address = document.getElementById("cbid.passwall." + id + ".address").value;
|
||||
var port = document.getElementById("cbid.passwall." + id + ".port").value;
|
||||
}
|
||||
catch(err){}
|
||||
//判断是否含有汉字
|
||||
var reg = new RegExp("[\\u4E00-\\u9FFF]+","g");
|
||||
if ((address != null && address != "") && (port != null && port != "") && reg.test(address) == false) {
|
||||
return { address: address, port: port };
|
||||
} else {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
//获取当前使用的节点
|
||||
function get_now_use_node() {
|
||||
XHR.get('<%=api.url("get_now_use_node")%>', null,
|
||||
function(x, result) {
|
||||
var id = result["TCP"];
|
||||
if (id) {
|
||||
var dom = document.getElementById("cbi-passwall-" + id);
|
||||
if (dom) {
|
||||
dom.classList.add("_now_use");
|
||||
dom.title = "当前TCP节点";
|
||||
//var v = "<a style='color: red'>当前TCP节点:</a>" + document.getElementById("cbid.passwall." + id + ".remarks").value;
|
||||
//document.getElementById("cbi-passwall-" + id + "-remarks").innerHTML = v;
|
||||
}
|
||||
}
|
||||
id = result["UDP"];
|
||||
if (id) {
|
||||
var dom = document.getElementById("cbi-passwall-" + id);
|
||||
if (dom) {
|
||||
dom.classList.add("_now_use");
|
||||
dom.title = "当前UDP节点";
|
||||
}
|
||||
}
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
function urltest_node(cbi_id, dom) {
|
||||
if (cbi_id != null) {
|
||||
dom.disabled = true;
|
||||
dom.value = "<%:Check...%>";
|
||||
XHR.get('<%=api.url("urltest_node")%>', {
|
||||
id: cbi_id
|
||||
},
|
||||
function(x, result) {
|
||||
if(x && x.status == 200) {
|
||||
if (result.use_time == null || result.use_time.trim() == "") {
|
||||
dom.outerHTML = "<font style='color:red'><%:Timeout%></font>";
|
||||
} else {
|
||||
var color = "red";
|
||||
var use_time = result.use_time;
|
||||
if (use_time < 1000) {
|
||||
color = "green";
|
||||
} else if (use_time < 2000) {
|
||||
color = "#fb9a05";
|
||||
} else {
|
||||
color = "red";
|
||||
}
|
||||
dom.outerHTML = "<font style='color:" + color + "'>" + result.use_time + " ms" + "</font>";
|
||||
}
|
||||
}
|
||||
}
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
function ping_node(cbi_id, dom) {
|
||||
var full = get_address_full(cbi_id);
|
||||
if (full != null) {
|
||||
XHR.get('<%=api.url("ping_node")%>', {
|
||||
address: full.address,
|
||||
port: full.port
|
||||
},
|
||||
function(x, result) {
|
||||
if(x && x.status == 200) {
|
||||
if (result.ping == null || result.ping.trim() == "") {
|
||||
dom.outerHTML = "<font style='color:red'><%:Timeout%></font>";
|
||||
} else {
|
||||
var ping = parseInt(result.ping);
|
||||
if (ping < 100)
|
||||
dom.outerHTML = "<font style='color:green'>" + result.ping + " ms" + "</font>";
|
||||
else if (ping < 200)
|
||||
dom.outerHTML = "<font style='color:#fb9a05'>" + result.ping + " ms" + "</font>";
|
||||
else if (ping >= 200)
|
||||
dom.outerHTML = "<font style='color:red'>" + result.ping + " ms" + "</font>";
|
||||
}
|
||||
}
|
||||
}
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
/* 自动Ping */
|
||||
var nodes = [];
|
||||
const ping_value = document.getElementsByClassName('ping_value');
|
||||
for (var i = 0; i < ping_value.length; i++) {
|
||||
var cbi_id = ping_value[i].getAttribute("cbiid");
|
||||
var full = get_address_full(cbi_id);
|
||||
if (full != null) {
|
||||
var flag = false;
|
||||
//当有多个相同地址和端口时合在一起
|
||||
for (var j = 0; j < nodes.length; j++) {
|
||||
if (nodes[j].address == full.address && nodes[j].port == full.port) {
|
||||
nodes[j].indexs = nodes[j].indexs + "," + i;
|
||||
flag = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (flag)
|
||||
continue;
|
||||
nodes.push({
|
||||
indexs: i + "",
|
||||
address: full.address,
|
||||
port: full.port
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
get_now_use_node();
|
||||
|
||||
const _xhr = (index) => {
|
||||
return new Promise((res) => {
|
||||
const dom = nodes[index];
|
||||
if (!dom) res()
|
||||
ajax.post('<%=api.url("ping_node")%>', {
|
||||
index: dom.indexs,
|
||||
address: dom.address,
|
||||
port: dom.port
|
||||
},
|
||||
function(x, result) {
|
||||
if (x && x.status == 200) {
|
||||
var strs = dom.indexs.split(",");
|
||||
for (var i = 0; i < strs.length; i++) {
|
||||
if (result.ping == null || result.ping.trim() == "") {
|
||||
ping_value[strs[i]].innerHTML = "<font style='color:red'><%:Timeout%></font>";
|
||||
} else {
|
||||
var ping = parseInt(result.ping);
|
||||
if (ping < 100)
|
||||
ping_value[strs[i]].innerHTML = "<font style='color:green'>" + result.ping + " ms" + "</font>";
|
||||
else if (ping < 200)
|
||||
ping_value[strs[i]].innerHTML = "<font style='color:#fb9a05'>" + result.ping + " ms" + "</font>";
|
||||
else if (ping >= 200)
|
||||
ping_value[strs[i]].innerHTML = "<font style='color:red'>" + result.ping + " ms" + "</font>";
|
||||
}
|
||||
}
|
||||
}
|
||||
res();
|
||||
},
|
||||
5000,
|
||||
function(x) {
|
||||
var strs = dom.indexs.split(",");
|
||||
for (var i = 0; i < strs.length; i++) {
|
||||
ping_value[strs[i]].innerHTML = "<font style='color:red'><%:Timeout%></font>";
|
||||
}
|
||||
res();
|
||||
}
|
||||
);
|
||||
})
|
||||
}
|
||||
|
||||
let task = -1;
|
||||
const thread = () => {
|
||||
task = task + 1
|
||||
if (nodes[task]) {
|
||||
_xhr(task).then(thread);
|
||||
}
|
||||
}
|
||||
for (let i = 0; i < 20; i++) {
|
||||
thread()
|
||||
}
|
||||
|
||||
/* 递归单请求方法
|
||||
var index = 0;
|
||||
function auto_ping() {
|
||||
if (index >= nodes.length) {
|
||||
return;
|
||||
}
|
||||
var indexs = nodes[index].indexs;
|
||||
var address = nodes[index].address;
|
||||
var port = nodes[index].port;
|
||||
ajax.post('<%=api.url("ping_node")%>', {
|
||||
index: indexs,
|
||||
address: address,
|
||||
port: port
|
||||
},
|
||||
function(x, result) {
|
||||
if (x && x.status == 200) {
|
||||
var strs = indexs.split(",");
|
||||
for (var i = 0; i < strs.length; i++) {
|
||||
if (result.ping == null || result.ping.trim() == "") {
|
||||
ping_value[strs[i]].innerHTML = "<font style='color:red'><%:Timeout%></font>";
|
||||
} else {
|
||||
var ping = parseInt(result.ping);
|
||||
if (ping < 100)
|
||||
ping_value[strs[i]].innerHTML = "<font style='color:green'>" + result.ping + " ms" + "</font>";
|
||||
else if (ping < 200)
|
||||
ping_value[strs[i]].innerHTML = "<font style='color:#fb9a05'>" + result.ping + " ms" + "</font>";
|
||||
else if (ping >= 200)
|
||||
ping_value[strs[i]].innerHTML = "<font style='color:red'>" + result.ping + " ms" + "</font>";
|
||||
}
|
||||
}
|
||||
}
|
||||
index++;
|
||||
return auto_ping();
|
||||
},
|
||||
function(x) {
|
||||
var strs = indexs.split(",");
|
||||
for (var i = 0; i < strs.length; i++) {
|
||||
ping_value[strs[i]].innerHTML = "<font style='color:red'><%:Timeout%></font>";
|
||||
}
|
||||
index++;
|
||||
return auto_ping();
|
||||
},
|
||||
);
|
||||
}
|
||||
auto_ping();
|
||||
*/
|
||||
|
||||
var edit_btn = document.getElementById("cbi-passwall-nodes").getElementsByClassName("cbi-button cbi-button-edit");
|
||||
for (var i = 0; i < edit_btn.length; i++) {
|
||||
try {
|
||||
var onclick_str = edit_btn[i].getAttribute("onclick");
|
||||
var id = onclick_str.substring(onclick_str.lastIndexOf('/') + 1, onclick_str.length - 1);
|
||||
var td = edit_btn[i].parentNode;
|
||||
var new_div = "";
|
||||
//添加"勾选"框
|
||||
new_div += '<input class="cbi-input-checkbox nodes_select" type="checkbox" cbid="' + id + '" /> ';
|
||||
//添加"置顶"按钮
|
||||
new_div += '<input class="btn cbi-button" type="button" value="<%:To Top%>" onclick="_cbi_row_top(\'' + id + '\')"/> ';
|
||||
//添加"应用"按钮
|
||||
new_div += '<input class="btn cbi-button cbi-button-apply" type="button" value="<%:Use%>" id="apply_' + id + '" onclick="open_set_node_div(\'' + id + '\')"/> ';
|
||||
//添加"复制"按钮
|
||||
new_div += '<input class="btn cbi-button cbi-button-add" type="button" value="<%:Copy%>" onclick="copy_node(\'' + id + '\')"/> ';
|
||||
td.innerHTML = new_div + td.innerHTML;
|
||||
|
||||
var obj = {};
|
||||
obj.id = id;
|
||||
obj.type = document.getElementById("cbid.passwall." + id + ".type").value;
|
||||
var address_dom = document.getElementById("cbid.passwall." + id + ".address");
|
||||
var port_dom = document.getElementById("cbid.passwall." + id + ".port");
|
||||
if (address_dom && port_dom) {
|
||||
obj.address = address_dom.value;
|
||||
obj.port = port_dom.value;
|
||||
}
|
||||
|
||||
node_count++;
|
||||
var add_from = document.getElementById("cbid.passwall." + id + ".add_from").value;
|
||||
if (node_list[add_from])
|
||||
node_list[add_from].push(obj);
|
||||
else
|
||||
node_list[add_from] = [];
|
||||
|
||||
}
|
||||
catch(err) {
|
||||
console.error(err);
|
||||
}
|
||||
}
|
||||
|
||||
if (true) {
|
||||
var str = "";
|
||||
for (var add_from in node_list) {
|
||||
var num = node_list[add_from].length + 1;
|
||||
if (add_from == "") {
|
||||
add_from = "<%:Self add%>";
|
||||
}
|
||||
str += add_from + " " + "<%:Node num%>: <a style='color: red'>" + num + "</a>   ";
|
||||
}
|
||||
document.getElementById("div_node_count").innerHTML = "<div style='margin-top:5px'>" + str + "</div>";
|
||||
}
|
||||
|
||||
//]]>
|
||||
</script>
|
||||
|
||||
<div style="display: -webkit-flex; display: flex; -webkit-align-items: center; align-items: center; -webkit-justify-content: center; justify-content: center;">
|
||||
<div id="set_node_div">
|
||||
<div class="cbi-value"><%:You choose node is:%><a style="color: red" id="set_node_name"></a></div>
|
||||
<div class="cbi-value">
|
||||
<input class="btn cbi-button cbi-button-edit" type="button" onclick="set_node('tcp')" value="TCP" />
|
||||
<input class="btn cbi-button cbi-button-edit" type="button" onclick="set_node('udp')" value="UDP" />
|
||||
<input class="btn cbi-button cbi-button-remove" type="button" onclick="close_set_node_div()" value="<%:Close%>" />
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
@ -1,76 +0,0 @@
|
||||
<%
|
||||
local api = require "luci.passwall.api"
|
||||
|
||||
local gfwlist_update = api.uci_get_type("global_rules", "gfwlist_update", "1") == "1" and "checked='checked'" or ""
|
||||
local chnroute_update = api.uci_get_type("global_rules", "chnroute_update", "1") == "1" and "checked='checked'" or ""
|
||||
local chnroute6_update = api.uci_get_type("global_rules", "chnroute6_update", "1") == "1" and "checked='checked'" or ""
|
||||
local chnlist_update = api.uci_get_type("global_rules", "chnlist_update", "1") == "1" and "checked='checked'" or ""
|
||||
local geoip_update = api.uci_get_type("global_rules", "geoip_update", "1") == "1" and "checked='checked'" or ""
|
||||
local geosite_update = api.uci_get_type("global_rules", "geosite_update", "1") == "1" and "checked='checked'" or ""
|
||||
-%>
|
||||
|
||||
<script type="text/javascript">
|
||||
//<![CDATA[
|
||||
function update_rules(btn) {
|
||||
btn.disabled = true;
|
||||
btn.value = '<%:Updating...%>';
|
||||
var div = document.getElementById('_rule_div');
|
||||
var domList = div.getElementsByTagName('input');
|
||||
var checkBoxList = [];
|
||||
var len = domList.length;
|
||||
while(len--) {
|
||||
var dom = domList[len];
|
||||
if(dom.type == 'checkbox' && dom.checked) {
|
||||
checkBoxList.push(dom.name);
|
||||
}
|
||||
}
|
||||
XHR.get('<%=api.url("update_rules")%>', {
|
||||
update: checkBoxList.join(",")
|
||||
},
|
||||
function(x, data) {
|
||||
if(x && x.status == 200) {
|
||||
window.location.href = '<%=api.url("log")%>';
|
||||
} else {
|
||||
alert("<%:Error%>");
|
||||
btn.disabled = false;
|
||||
btn.value = '<%:Manually update%>';
|
||||
}
|
||||
}
|
||||
);
|
||||
}
|
||||
//]]>
|
||||
</script>
|
||||
<div class="cbi-value" id="_rule_div">
|
||||
<label class="cbi-value-title">
|
||||
<%:Manually update%>
|
||||
</label>
|
||||
<div class="cbi-value-field">
|
||||
<div>
|
||||
<label>
|
||||
<input class="cbi-input-checkbox" type="checkbox" name="gfwlist" value="1" <%=gfwlist_update%> />
|
||||
gfwlist
|
||||
</label>
|
||||
<label>
|
||||
<input class="cbi-input-checkbox" type="checkbox" name="chnroute" value="1" <%=chnroute_update%> />
|
||||
chnroute
|
||||
</label>
|
||||
<label>
|
||||
<input class="cbi-input-checkbox" type="checkbox" name="chnroute6" value="1" <%=chnroute6_update%> />
|
||||
chnroute6
|
||||
</label>
|
||||
<label>
|
||||
<input class="cbi-input-checkbox" type="checkbox" name="chnlist" value="1" <%=chnlist_update%> />
|
||||
chnlist
|
||||
</label>
|
||||
<label>
|
||||
<input class="cbi-input-checkbox" type="checkbox" name="geoip" value="1" <%=geoip_update%> />
|
||||
geoip
|
||||
</label>
|
||||
<label>
|
||||
<input class="cbi-input-checkbox" type="checkbox" name="geosite" value="1" <%=geosite_update%> />
|
||||
geosite
|
||||
</label>
|
||||
<input class="btn cbi-button cbi-button-apply" type="button" id="update_rules_btn" onclick="update_rules(this)" value="<%:Manually update%>" />
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
@ -1,35 +0,0 @@
|
||||
<%
|
||||
local api = require "luci.passwall.api"
|
||||
-%>
|
||||
<script type="text/javascript">
|
||||
//<![CDATA[
|
||||
function clear_log(btn) {
|
||||
XHR.get('<%=api.url("server_clear_log")%>', null,
|
||||
function(x, data) {
|
||||
if(x && x.status == 200) {
|
||||
var log_textarea = document.getElementById('log_textarea');
|
||||
log_textarea.innerHTML = "";
|
||||
log_textarea.scrollTop = log_textarea.scrollHeight;
|
||||
}
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
XHR.poll(3, '<%=api.url("server_get_log")%>', null,
|
||||
function(x, data) {
|
||||
if(x && x.status == 200) {
|
||||
var log_textarea = document.getElementById('log_textarea');
|
||||
log_textarea.innerHTML = x.responseText;
|
||||
log_textarea.scrollTop = log_textarea.scrollHeight;
|
||||
}
|
||||
}
|
||||
);
|
||||
//]]>
|
||||
</script>
|
||||
<fieldset class="cbi-section" id="_log_fieldset">
|
||||
<legend>
|
||||
<%:Logs%>
|
||||
</legend>
|
||||
<input class="btn cbi-button cbi-button-remove" type="button" onclick="clear_log()" value="<%:Clear logs%>" />
|
||||
<textarea id="log_textarea" class="cbi-input-textarea" style="width: 100%;margin-top: 10px;" data-update="change" rows="20" wrap="off" readonly="readonly"></textarea>
|
||||
</fieldset>
|
@ -1,38 +0,0 @@
|
||||
<%
|
||||
local api = require "luci.passwall.api"
|
||||
-%>
|
||||
<script type="text/javascript">
|
||||
//<![CDATA[
|
||||
var _users_status = document.getElementsByClassName('_users_status');
|
||||
for(var i = 0; i < _users_status.length; i++) {
|
||||
var id = _users_status[i].parentElement.parentElement.parentElement.id;
|
||||
id = id.substr(id.lastIndexOf("-") + 1);
|
||||
XHR.get('<%=api.url("server_user_status")%>', {
|
||||
index: i,
|
||||
id: id
|
||||
},
|
||||
function(x, result) {
|
||||
_users_status[result.index].setAttribute("style","font-weight:bold;");
|
||||
_users_status[result.index].setAttribute("color",result.status ? "green":"red");
|
||||
_users_status[result.index].innerHTML = (result.status ? '✓' : 'X');
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
var edit_btn = document.getElementById("cbi-passwall_server-user").getElementsByClassName("cbi-button cbi-button-edit");
|
||||
for (var i = 0; i < edit_btn.length; i++) {
|
||||
try {
|
||||
var onclick_str = edit_btn[i].getAttribute("onclick");
|
||||
var id = onclick_str.substring(onclick_str.lastIndexOf('/') + 1, onclick_str.length - 1);
|
||||
var td = edit_btn[i].parentNode;
|
||||
var new_div = "";
|
||||
//添加"日志"按钮
|
||||
new_div += '<input class="btn cbi-button cbi-button-add" type="button" value="<%:Log%>" onclick="window.open(\'' + '<%=api.url("server_user_log")%>' + '?id=' + id + '\', \'_blank\')"/> ';
|
||||
td.innerHTML = new_div + td.innerHTML;
|
||||
}
|
||||
catch(err) {
|
||||
console.error(err);
|
||||
}
|
||||
}
|
||||
//]]>
|
||||
</script>
|
@ -1,23 +0,0 @@
|
||||
<%
|
||||
local api = require "luci.passwall.api"
|
||||
-%>
|
||||
|
||||
<script type="text/javascript">
|
||||
//<![CDATA[
|
||||
let socks_id = window.location.pathname.substring(window.location.pathname.lastIndexOf("/") + 1)
|
||||
function add_node_by_key() {
|
||||
var key = prompt("<%:Please enter the node keyword, pay attention to distinguish between spaces, uppercase and lowercase.%>", "");
|
||||
if (key) {
|
||||
window.location.href = '<%=api.url("socks_autoswitch_add_node")%>' + "?id=" + socks_id + "&key=" + key;
|
||||
}
|
||||
}
|
||||
function remove_node_by_key() {
|
||||
var key = prompt("<%:Please enter the node keyword, pay attention to distinguish between spaces, uppercase and lowercase.%>", "");
|
||||
if (key) {
|
||||
window.location.href = '<%=api.url("socks_autoswitch_remove_node")%>' + "?id=" + socks_id + "&key=" + key;
|
||||
}
|
||||
}
|
||||
//]]>
|
||||
</script>
|
||||
<input class="btn cbi-button cbi-button-add" type="button" onclick="add_node_by_key()" value="<%:Add nodes to the standby node list by keywords%>" />
|
||||
<input class="btn cbi-button cbi-button-remove" type="button" onclick="remove_node_by_key()" value="<%:Delete nodes in the standby node list by keywords%>" />
|
File diff suppressed because it is too large
Load Diff
@ -1,4 +0,0 @@
|
||||
|
||||
config global 'global'
|
||||
option enable '0'
|
||||
|
@ -1,23 +0,0 @@
|
||||
#!/bin/sh
|
||||
|
||||
[[ "$ACTION" == "ifup" && $(uci get "passwall.@global[0].enabled") == "1" ]] && [ -f /var/lock/passwall_ready.lock ] && {
|
||||
default_device=$(ip route | grep default | awk -F 'dev ' '{print $2}' | awk '{print $1}')
|
||||
[ "$default_device" == "$DEVICE" ] && {
|
||||
LOCK_FILE_DIR=/var/lock
|
||||
[ ! -d ${LOCK_FILE_DIR} ] && mkdir -p ${LOCK_FILE_DIR}
|
||||
LOCK_FILE="${LOCK_FILE_DIR}/passwall_ifup.lock"
|
||||
if [ -s ${LOCK_FILE} ]; then
|
||||
SPID=$(cat ${LOCK_FILE})
|
||||
if [ -e /proc/${SPID}/status ]; then
|
||||
exit 1
|
||||
fi
|
||||
cat /dev/null > ${LOCK_FILE}
|
||||
fi
|
||||
echo $$ > ${LOCK_FILE}
|
||||
|
||||
/etc/init.d/passwall restart
|
||||
echo "passwall: restart when $INTERFACE ifup" > /dev/kmsg
|
||||
|
||||
rm -rf ${LOCK_FILE}
|
||||
}
|
||||
}
|
@ -1,66 +0,0 @@
|
||||
#!/bin/sh /etc/rc.common
|
||||
|
||||
START=99
|
||||
STOP=15
|
||||
|
||||
CONFIG=passwall
|
||||
APP_FILE=/usr/share/${CONFIG}/app.sh
|
||||
LOCK_FILE_DIR=/var/lock
|
||||
LOCK_FILE=${LOCK_FILE_DIR}/${CONFIG}.lock
|
||||
|
||||
set_lock() {
|
||||
[ ! -d "$LOCK_FILE_DIR" ] && mkdir -p $LOCK_FILE_DIR
|
||||
exec 999>"$LOCK_FILE"
|
||||
flock -xn 999
|
||||
}
|
||||
|
||||
unset_lock() {
|
||||
flock -u 999
|
||||
rm -rf "$LOCK_FILE"
|
||||
}
|
||||
|
||||
unlock() {
|
||||
failcount=1
|
||||
while [ "$failcount" -le 10 ]; do
|
||||
if [ -f "$LOCK_FILE" ]; then
|
||||
let "failcount++"
|
||||
sleep 1s
|
||||
[ "$failcount" -ge 10 ] && unset_lock
|
||||
else
|
||||
break
|
||||
fi
|
||||
done
|
||||
}
|
||||
|
||||
boot() {
|
||||
local delay=$(uci -q get ${CONFIG}.@global_delay[0].start_delay || echo 1)
|
||||
if [ "$delay" -gt 0 ]; then
|
||||
$APP_FILE echolog "执行启动延时 $delay 秒后再启动!"
|
||||
sleep $delay
|
||||
fi
|
||||
restart
|
||||
touch ${LOCK_FILE_DIR}/${CONFIG}_ready.lock
|
||||
}
|
||||
|
||||
start() {
|
||||
set_lock
|
||||
[ $? == 1 ] && $APP_FILE echolog "脚本已经在运行,不重复运行,退出." && exit 0
|
||||
$APP_FILE start
|
||||
unset_lock
|
||||
}
|
||||
|
||||
stop() {
|
||||
unlock
|
||||
set_lock
|
||||
[ $? == 1 ] && $APP_FILE echolog "停止脚本等待超时,不重复运行,退出." && exit 0
|
||||
$APP_FILE stop
|
||||
unset_lock
|
||||
}
|
||||
|
||||
restart() {
|
||||
set_lock
|
||||
[ $? == 1 ] && $APP_FILE echolog "脚本已经在运行,不重复运行,退出." && exit 0
|
||||
$APP_FILE stop
|
||||
$APP_FILE start
|
||||
unset_lock
|
||||
}
|
@ -1,16 +0,0 @@
|
||||
#!/bin/sh /etc/rc.common
|
||||
|
||||
START=99
|
||||
|
||||
start() {
|
||||
lua /usr/lib/lua/luci/passwall/server_app.lua start
|
||||
}
|
||||
|
||||
stop() {
|
||||
lua /usr/lib/lua/luci/passwall/server_app.lua stop
|
||||
}
|
||||
|
||||
restart() {
|
||||
stop
|
||||
start
|
||||
}
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue
Block a user