🏅 Sync 2026-08-07 03:28:35

This commit is contained in:
github-actions[bot]
2026-08-07 03:28:35 +08:00
parent ccaa53e2e9
commit e5abd5d15c
31 changed files with 733 additions and 296 deletions
+2 -2
View File
@@ -1,8 +1,8 @@
include $(TOPDIR)/rules.mk
PKG_NAME:=7z
PKG_VERSION:=26.01
PKG_RELEASE:=2
PKG_VERSION:=26.02
PKG_RELEASE:=3
PKG_SOURCE:=$(PKG_NAME)$(subst .,,$(PKG_VERSION))-src.tar.xz
PKG_SOURCE_URL:=https://7-zip.org/a/
+2 -2
View File
@@ -10,8 +10,8 @@ include $(TOPDIR)/rules.mk
PKG_ARCH_BAIDUDRIVE:=$(ARCH)
PKG_NAME:=baidudrive
PKG_VERSION:=linkease-runtime-v1.7.5
PKG_RELEASE:=6
PKG_VERSION:=linkeasefull-runtime-v3.0.5
PKG_RELEASE:=7
PKG_SOURCE:=$(PKG_NAME)-binary-$(PKG_VERSION).tar.gz
PKG_SOURCE_URL:=https://github.com/istoreos/istoreos-app-hub/releases/download/baidudrive-runtime-v$(PKG_VERSION)/
PKG_HASH:=skip
+2 -2
View File
@@ -2,9 +2,9 @@ include $(TOPDIR)/rules.mk
PKG_NAME:=gecoosac
PKG_VERSION:=2.2.20251015
PKG_RELEASE:=14
PKG_RELEASE:=15
PKG_MAINTAINER:=lwb1978 <lwb1978@gmail.com>
PKG_MAINTAINER:=Roc Lai <laipeng668@qq.com>
PKG_LICENSE:=AGPL-3.0-only
PKG_LICENSE_FILES:=LICENSE
+1
View File
@@ -1,4 +1,5 @@
config gecoosac 'config'
option config_compat '2'
option enabled '0'
option port '60650'
option isonlyoneprot '1'
+211 -54
View File
@@ -101,6 +101,49 @@ is_path_in_dir() {
[ "${path#"$root"/}" != "$path" ]
}
is_secure_dir() {
local allow_sticky="$2" owner permissions metadata
[ -d "$1" ] && [ ! -L "$1" ] || return 1
metadata="$(ls -ldn "$1" 2>/dev/null)" || return 1
set -- $metadata
permissions="$1"
owner="$3"
[ "$owner" = "0" ] || return 1
case "$permissions" in
d?????????) ;;
*) return 1 ;;
esac
if [ "$(printf '%s' "$permissions" | cut -c6)" = "w" ] || \
[ "$(printf '%s' "$permissions" | cut -c9)" = "w" ]; then
[ "$allow_sticky" = "1" ] && [ "$(printf '%s' "$permissions" | cut -c10)" = "t" ] || return 1
fi
}
is_secure_upload_dir() {
local path current part rest
path="$(normalize_path "$1")" || return 1
[ -d "$path" ] && [ ! -L "$path" ] || return 1
current="/"
rest="${path#/}"
while [ -n "$rest" ]; do
part="${rest%%/*}"
if [ "$part" = "$rest" ]; then
rest=""
else
rest="${rest#*/}"
fi
current="${current%/}/$part"
case "$current" in
/tmp) is_secure_dir "$current" 1 || return 1 ;;
*) is_secure_dir "$current" || return 1 ;;
esac
done
}
is_safe_db_dir() {
local path upload_root
@@ -154,7 +197,6 @@ run_with_timeout() {
kill "$pid" >/dev/null 2>&1
sleep 1
kill -9 "$pid" >/dev/null 2>&1
wait "$pid" 2>/dev/null
return 1
fi
sleep 1
@@ -164,6 +206,42 @@ run_with_timeout() {
wait "$pid"
}
run_with_timeout_output() {
local timeout output pid i
timeout="$1"
output="$2"
shift 2
"$@" >"$output" 2>/dev/null &
pid="$!"
i=0
while kill -0 "$pid" >/dev/null 2>&1; do
if [ "$i" -ge "$timeout" ]; then
kill "$pid" >/dev/null 2>&1
kill -9 "$pid" >/dev/null 2>&1
return 1
fi
sleep 1
i=$((i + 1))
done
wait "$pid"
}
is_readable_regular_file() {
local path="$1" tmp_dir status
tmp_dir="$(mktemp -d /tmp/gecoosac-file.XXXXXX)" || return 1
run_with_timeout_output "$CERT_TIMEOUT" "$tmp_dir/check" \
/bin/sh -c '[ -f "$1" ] && [ -r "$1" ] && [ -s "$1" ]' \
gecoosac-file-check "$path" </dev/null
status="$?"
rm -rf "$tmp_dir"
return "$status"
}
is_ipv4() {
local value="$1"
local part count
@@ -194,13 +272,19 @@ san_has_entry() {
}
cert_matches_san() {
local cert_file="$1"
local cert_host="$2"
local cert_ip="$3"
local san
local cert_file="$1" cert_host="$2" cert_ip="$3"
local san tmp_dir
[ -s "$cert_file" ] || return 1
san="$(openssl x509 -in "$cert_file" -noout -ext subjectAltName 2>/dev/null)" || return 1
is_readable_regular_file "$cert_file" || return 1
tmp_dir="$(mktemp -d /tmp/gecoosac-cert.XXXXXX)" || return 1
if ! run_with_timeout_output "$CERT_TIMEOUT" "$tmp_dir/san" \
openssl x509 -in "$cert_file" -noout -ext subjectAltName </dev/null; then
rm -rf "$tmp_dir"
return 1
fi
san="$(cat "$tmp_dir/san" 2>/dev/null)"
rm -rf "$tmp_dir"
[ -n "$san" ] || return 1
san_has_entry "$san" "DNS:${cert_host}" || return 1
[ -z "$cert_ip" ] || san_has_entry "$san" "IP Address:${cert_ip}" || return 1
@@ -208,13 +292,22 @@ cert_matches_san() {
}
cert_matches_key() {
local cert_file="$1"
local key_file="$2"
local cert_pub key_pub
local cert_file="$1" key_file="$2"
local cert_pub key_pub tmp_dir
[ -s "$cert_file" ] && [ -s "$key_file" ] || return 1
cert_pub="$(openssl x509 -in "$cert_file" -noout -pubkey 2>/dev/null)" || return 1
key_pub="$(openssl pkey -in "$key_file" -pubout 2>/dev/null)" || return 1
is_readable_regular_file "$cert_file" || return 1
is_readable_regular_file "$key_file" || return 1
tmp_dir="$(mktemp -d /tmp/gecoosac-cert.XXXXXX)" || return 1
if ! run_with_timeout_output "$CERT_TIMEOUT" "$tmp_dir/cert.pub" \
openssl x509 -in "$cert_file" -noout -pubkey </dev/null || \
! run_with_timeout_output "$CERT_TIMEOUT" "$tmp_dir/key.pub" \
openssl pkey -in "$key_file" -pubout </dev/null; then
rm -rf "$tmp_dir"
return 1
fi
cert_pub="$(cat "$tmp_dir/cert.pub" 2>/dev/null)"
key_pub="$(cat "$tmp_dir/key.pub" 2>/dev/null)"
rm -rf "$tmp_dir"
[ -n "$cert_pub" ] && [ "$cert_pub" = "$key_pub" ]
}
@@ -235,7 +328,7 @@ generate_default_cert() {
cert_ip="$(uci -q get network.lan.ipaddr)"
is_ipv4 "$cert_ip" || cert_ip=""
if [ -s "$DEFAULT_KEY_FILE" ] && cert_matches_san "$DEFAULT_CRT_FILE" "$cert_host" "$cert_ip" && cert_matches_key "$DEFAULT_CRT_FILE" "$DEFAULT_KEY_FILE"; then
if is_readable_regular_file "$DEFAULT_KEY_FILE" && cert_matches_san "$DEFAULT_CRT_FILE" "$cert_host" "$cert_ip" && cert_matches_key "$DEFAULT_CRT_FILE" "$DEFAULT_KEY_FILE"; then
return 0
fi
@@ -262,7 +355,7 @@ generate_default_cert() {
-addext "basicConstraints=critical,CA:FALSE" \
-addext "keyUsage=digitalSignature" \
-addext "extendedKeyUsage=serverAuth" \
-addext "subjectAltName=$cert_san"
-addext "subjectAltName=$cert_san" </dev/null
if [ -s "$tmp_crt" ] && [ -s "$tmp_key" ] && cert_matches_san "$tmp_crt" "$cert_host" "$cert_ip" && cert_matches_key "$tmp_crt" "$tmp_key"; then
mv "$tmp_key" "$DEFAULT_KEY_FILE"
@@ -281,22 +374,37 @@ normalize_conf() {
if is_safe_upload_dir "$upload_dir"; then
upload_dir="$(normalize_path "$upload_dir")"
else
upload_dir="$DEFAULT_UPLOAD_DIR"
logger -t gecoosac "refusing unsupported upload directory: $upload_dir"
return 1
fi
if is_safe_db_dir "$db_dir" "$upload_dir"; then
db_dir="$(normalize_path "$db_dir")"
else
db_dir="$DEFAULT_DB_DIR"
logger -t gecoosac "refusing unsupported database directory: $db_dir"
return 1
fi
is_abs_path "$crt_file" || crt_file="$DEFAULT_CRT_FILE"
is_abs_path "$key_file" || key_file="$DEFAULT_KEY_FILE"
is_abs_path "$crt_file" || {
logger -t gecoosac "refusing non-absolute certificate path: $crt_file"
return 1
}
is_abs_path "$key_file" || {
logger -t gecoosac "refusing non-absolute key path: $key_file"
return 1
}
if is_safe_pid_dir "$piddir" "$upload_dir"; then
piddir="$(normalize_path "$piddir")"
else
piddir="$DEFAULT_PID_DIR"
logger -t gecoosac "refusing unsupported PID directory: $piddir"
return 1
fi
is_port "$port" || port="60650"
is_port "$m_port" || m_port="8080"
is_port "$port" || {
logger -t gecoosac "refusing invalid interface port: $port"
return 1
}
is_port "$m_port" || {
logger -t gecoosac "refusing invalid management port: $m_port"
return 1
}
[ "$enabled" = "1" ] || enabled="0"
[ "$isonlyoneprot" = "0" ] || isonlyoneprot="1"
@@ -311,50 +419,79 @@ normalize_conf() {
}
ensure_dirs() {
if ! mkdir -p "$upload_dir" "$db_dir" "$piddir" /etc/gecoosac/tls; then
local path
path="$(normalize_path "$upload_dir")" || return 1
if ! ensure_dir_tree "$path" || ! mkdir -p "$db_dir" "$piddir" /etc/gecoosac/tls; then
logger -t gecoosac "failed to create runtime directories"
return 1
fi
chmod go-w "$path" || return 1
is_secure_upload_dir "$path" || {
logger -t gecoosac "upload directory or its parent is not root-owned and private: $path"
return 1
}
}
ensure_dir_tree() {
local path current part rest
path="$(normalize_path "$1")" || return 1
current="/"
rest="${path#/}"
while [ -n "$rest" ]; do
part="${rest%%/*}"
if [ "$part" = "$rest" ]; then
rest=""
else
rest="${rest#*/}"
fi
current="${current%/}/$part"
[ ! -L "$current" ] || return 1
if [ -e "$current" ]; then
[ -d "$current" ] || return 1
else
mkdir "$current" || return 1
fi
done
}
prepare_service() {
init_conf
[ "$enabled" = "1" ] || return 0
normalize_conf || return 1
if [ ! -x "$PROG" ]; then
logger -t gecoosac "program not found: $PROG"
return 1
fi
if [ "$isonlyoneprot" = "0" ] && [ "$port" -eq "$m_port" ] 2>/dev/null; then
logger -t gecoosac "interface port and management port must be different"
return 1
fi
ensure_dirs || return 1
if [ "$isonlyoneprot" = "0" ] && [ "$https" = "1" ]; then
if [ "$crt_file" = "$DEFAULT_CRT_FILE" ] && [ "$key_file" = "$DEFAULT_KEY_FILE" ]; then
generate_default_cert || return 1
fi
if ! cert_matches_key "$crt_file" "$key_file"; then
logger -t gecoosac "HTTPS certificate and key do not match or cannot be read"
return 1
fi
fi
}
start_service() {
local runtime_upload_dir runtime_db_dir runtime_piddir
init_conf
normalize_conf
prepare_service || return 1
[ "$enabled" = "1" ] || return 0
if [ ! -x "$PROG" ]; then
logger -t gecoosac "program not found: $PROG"
return 1
fi
if [ "$isonlyoneprot" = "0" ] && [ "$port" = "$m_port" ]; then
logger -t gecoosac "interface port and management port must be different"
return 1
fi
ensure_dirs || return 1
runtime_upload_dir="${upload_dir%/}/"
runtime_db_dir="${db_dir%/}/"
runtime_piddir="${piddir%/}/"
if [ "$isonlyoneprot" = "0" ] && [ "$https" = "1" ]; then
if [ "$crt_file" = "$DEFAULT_CRT_FILE" ] && [ "$key_file" = "$DEFAULT_KEY_FILE" ]; then
generate_default_cert || return 1
fi
if [ ! -r "$crt_file" ] || [ ! -r "$key_file" ]; then
logger -t gecoosac "HTTPS is enabled but certificate or key file is missing"
return 1
fi
if ! cert_matches_key "$crt_file" "$key_file"; then
logger -t gecoosac "HTTPS certificate and key do not match"
return 1
fi
fi
procd_open_instance gecoosac
procd_set_param command "$PROG"
procd_append_param command -f "$runtime_upload_dir"
@@ -387,8 +524,28 @@ start_service() {
procd_close_instance
}
wait_service_stopped() {
local i
if ! type service_running >/dev/null 2>&1; then
return 0
fi
i=0
while [ "$i" -lt 5 ]; do
service_running gecoosac || return 0
sleep 1
i=$((i + 1))
done
return 1
}
reload_service() {
stop
prepare_service || return 1
if ! stop || ! wait_service_stopped; then
logger -t gecoosac "unable to stop the existing service for reload"
return 1
fi
start
}
+55 -14
View File
@@ -8,6 +8,7 @@ DEFAULT_KEY_FILE=/etc/gecoosac/tls/gecoosac.key
DEFAULT_PID_DIR=/var/run
OLD_CRT_FILE=/etc/gecoosac/tls/1.crt
OLD_KEY_FILE=/etc/gecoosac/tls/1.key
CONFIG_COMPAT=2
ensure_section() {
uci -q get gecoosac.config >/dev/null && return 0
@@ -128,7 +129,7 @@ normalize_upload_dir() {
if is_safe_upload_dir "$upload_dir"; then
normalized="$(normalize_path "$upload_dir")"
else
normalized="$DEFAULT_UPLOAD_DIR"
return 0
fi
[ "$upload_dir" = "$normalized" ] && return 0
@@ -138,7 +139,6 @@ normalize_upload_dir() {
normalize_dir_option() {
local option="$1"
local default="$2"
local validator="$3"
local value normalized upload_dir
@@ -150,7 +150,7 @@ normalize_dir_option() {
if "$validator" "$value" "$upload_dir"; then
normalized="$(normalize_path "$value")"
else
normalized="$default"
return 0
fi
[ "$value" = "$normalized" ] && return 0
@@ -159,30 +159,71 @@ normalize_dir_option() {
}
migrate_legacy_cert_paths() {
local crt_file key_file
local migrate
local crt_file key_file migrate
crt_file="$(uci -q get gecoosac.config.crt_file)"
key_file="$(uci -q get gecoosac.config.key_file)"
migrate=0
if [ "$crt_file" = "$OLD_CRT_FILE" ]; then
if [ -z "$key_file" ] || [ "$key_file" = "$OLD_KEY_FILE" ]; then
migrate=1
fi
if [ "$crt_file" = "$OLD_CRT_FILE" ] && [ -z "$key_file" ]; then
uci -q set "gecoosac.config.key_file=${OLD_KEY_FILE}" || return 1
key_file="$OLD_KEY_FILE"
changed=1
elif [ -z "$crt_file" ] && [ "$key_file" = "$OLD_KEY_FILE" ]; then
uci -q set "gecoosac.config.crt_file=${OLD_CRT_FILE}" || return 1
crt_file="$OLD_CRT_FILE"
changed=1
fi
if [ "$crt_file" = "$OLD_CRT_FILE" ] && [ "$key_file" = "$OLD_KEY_FILE" ]; then
migrate=1
elif [ -z "$crt_file" ] && [ -z "$key_file" ]; then
[ -f "$OLD_CRT_FILE" ] && [ -f "$OLD_KEY_FILE" ] || return 0
migrate=1
fi
if [ "$migrate" = "1" ]; then
uci -q set "gecoosac.config.crt_file=${DEFAULT_CRT_FILE}"
uci -q set "gecoosac.config.key_file=${DEFAULT_KEY_FILE}"
changed=1
[ "$migrate" = "1" ] || return 0
[ -f "$OLD_CRT_FILE" ] && [ ! -L "$OLD_CRT_FILE" ] || return 0
[ -f "$OLD_KEY_FILE" ] && [ ! -L "$OLD_KEY_FILE" ] || return 0
[ ! -e "$DEFAULT_CRT_FILE" ] && [ ! -L "$DEFAULT_CRT_FILE" ] || return 0
[ ! -e "$DEFAULT_KEY_FILE" ] && [ ! -L "$DEFAULT_KEY_FILE" ] || return 0
mkdir -p /etc/gecoosac/tls || {
logger -t gecoosac "unable to prepare TLS directory for legacy certificate migration"
return 1
}
if ! mv "$OLD_CRT_FILE" "$DEFAULT_CRT_FILE"; then
logger -t gecoosac "unable to migrate legacy certificate"
return 1
fi
if ! mv "$OLD_KEY_FILE" "$DEFAULT_KEY_FILE"; then
mv "$DEFAULT_CRT_FILE" "$OLD_CRT_FILE" 2>/dev/null
logger -t gecoosac "unable to migrate legacy private key"
return 1
fi
if ! chmod 644 "$DEFAULT_CRT_FILE" || ! chmod 600 "$DEFAULT_KEY_FILE" || \
! uci -q set "gecoosac.config.crt_file=${DEFAULT_CRT_FILE}" || \
! uci -q set "gecoosac.config.key_file=${DEFAULT_KEY_FILE}"; then
mv "$DEFAULT_KEY_FILE" "$OLD_KEY_FILE" 2>/dev/null
mv "$DEFAULT_CRT_FILE" "$OLD_CRT_FILE" 2>/dev/null
logger -t gecoosac "unable to complete legacy certificate migration"
return 1
fi
changed=1
}
migrate_config() {
local compat
compat="$(uci -q get gecoosac.config.config_compat)"
[ "$compat" = "$CONFIG_COMPAT" ] && return 0
migrate_legacy_cert_paths || return 1
uci -q set "gecoosac.config.config_compat=${CONFIG_COMPAT}" || return 1
changed=1
}
ensure_section
migrate_legacy_cert_paths
migrate_config || exit 1
normalize_upload_dir
normalize_dir_option db_dir "$DEFAULT_DB_DIR" is_safe_db_dir
normalize_dir_option piddir "$DEFAULT_PID_DIR" is_safe_pid_dir
+2 -2
View File
@@ -5,8 +5,8 @@
include $(TOPDIR)/rules.mk
PKG_NAME:=hysteria
PKG_VERSION:=2.11.0
PKG_RELEASE:=13
PKG_VERSION:=2.12.0
PKG_RELEASE:=14
PKG_SOURCE:=$(PKG_NAME)-$(PKG_VERSION).tar.gz
PKG_SOURCE_URL:=https://codeload.github.com/apernet/hysteria/tar.gz/app/v$(PKG_VERSION)?
+4 -4
View File
@@ -10,9 +10,9 @@ include $(TOPDIR)/rules.mk
PKG_ARCH_LINKEASE:=$(ARCH)
PKG_NAME:=linkease-common-bin
PKG_VERSION:=linkease-runtime-v1.7.5
PKG_SOURCE_DATE:=$(PKG_VERSION)
PKG_RELEASE:=2
# use PKG_SOURCE_DATE instead of PKG_VERSION for compitable
PKG_SOURCE_DATE:=1.7.5
PKG_RELEASE:=3
ARCH_HEXCODE:=
ifeq ($(ARCH),x86_64)
@@ -28,7 +28,7 @@ else ifeq ($(ARCH),mipsel)
ARCH_HEXCODE=1b0c
endif
PKG_SOURCE_VERSION:=f6d705f77dade7d57c1bb24334da4028279689b9
PKG_SOURCE_VERSION:=8895348606dc6cab9b25a75576e5142f553dfa82
PKG_SOURCE:=linkease-common-bin-$(PKG_SOURCE_DATE)-linux-$(PKG_ARCH_LINKEASE).tar.gz
PKG_SOURCE_URL:=https://github.com/istoreos/istoreos-app-hub/releases/download/linkease-runtime-v$(PKG_SOURCE_DATE)/
PKG_BUILD_DIR:=$(BUILD_DIR)/linkease-common-bin-$(PKG_SOURCE_DATE)-linux-$(PKG_ARCH_LINKEASE)
+4 -4
View File
@@ -10,9 +10,9 @@ include $(TOPDIR)/rules.mk
PKG_ARCH_LINKEASE:=$(ARCH)
PKG_NAME:=linkease
PKG_VERSION:=linkease-runtime-v1.7.5
PKG_SOURCE_DATE:=$(PKG_VERSION)
PKG_RELEASE:=5
# use PKG_SOURCE_DATE instead of PKG_VERSION for compitable
PKG_SOURCE_DATE:=1.7.5
PKG_RELEASE:=6
ARCH_HEXCODE:=
ifeq ($(ARCH),x86_64)
@@ -28,7 +28,7 @@ else ifeq ($(ARCH),mipsel)
ARCH_HEXCODE=1b0c
endif
PKG_SOURCE_VERSION:=f6d705f77dade7d57c1bb24334da4028279689b9
PKG_SOURCE_VERSION:=8895348606dc6cab9b25a75576e5142f553dfa82
PKG_SOURCE:=linkease-bin-$(PKG_SOURCE_DATE)-linux-$(PKG_ARCH_LINKEASE).tar.gz
PKG_SOURCE_URL:=https://github.com/istoreos/istoreos-app-hub/releases/download/linkease-runtime-v$(PKG_SOURCE_DATE)/
PKG_BUILD_DIR:=$(BUILD_DIR)/linkease-bin-$(PKG_SOURCE_DATE)-linux-$(PKG_ARCH_LINKEASE)
+11 -4
View File
@@ -6,19 +6,25 @@
include $(TOPDIR)/rules.mk
PKG_NAME:=linkeasefull
PKG_VERSION:=linkease-runtime-v1.7.5
PKG_SOURCE_DATE:=$(PKG_VERSION)
PKG_RELEASE:=4
PKG_ARCH_LINKEASE:=$(ARCH)
PKG_NAME:=linkeasefull
# use PKG_SOURCE_DATE instead of PKG_VERSION for compitable
PKG_SOURCE_DATE:=3.0.5
PKG_RELEASE:=5
ARCH_HEXCODE:=
ifeq ($(ARCH),x86_64)
ARCH_HEXCODE=8664
LINKEASE_RUNTIME_ARCH:=amd64
PKG_HASH:=skip
else ifeq ($(ARCH),aarch64)
ARCH_HEXCODE=aa64
LINKEASE_RUNTIME_ARCH:=arm64
PKG_HASH:=skip
endif
PKG_SOURCE_VERSION:=8895348606dc6cab9b25a75576e5142f553dfa82
PKG_SOURCE:=linkease-runtime-$(PKG_SOURCE_DATE)-linux-$(LINKEASE_RUNTIME_ARCH).tar.gz
PKG_SOURCE_URL:=https://github.com/istoreos/istoreos-app-hub/releases/download/linkeasefull-runtime-v$(PKG_SOURCE_DATE)/
PKG_BUILD_DIR:=$(BUILD_DIR)/linkease-runtime-$(PKG_SOURCE_DATE)-linux-$(LINKEASE_RUNTIME_ARCH)
@@ -34,6 +40,7 @@ define Package/$(PKG_NAME)
SUBMENU:=Web Servers/Proxies
TITLE:=LinkEase Full - the local web desktop
DEPENDS:=@(x86_64||aarch64) +linkease-common-bin +ca-bundle
PKGARCH:=all
URL:=https://www.linkease.com/
endef
+1 -1
View File
@@ -7,7 +7,7 @@ include $(TOPDIR)/rules.mk
PKG_NAME:=luci-app-gecoosac
PKG_VERSION:=2.2
PKG_RELEASE:=14
PKG_RELEASE:=15
LUCI_TITLE:=LuCI Support for gecoosac
LUCI_DEPENDS:=+luci-base +gecoosac
@@ -20,7 +20,8 @@ let statusPollRegistered = false;
const callServiceStatus = rpc.declare({
object: 'luci.gecoosac',
method: 'status',
expect: { '': {} }
expect: { '': {} },
reject: true
});
const callClearUpload = rpc.declare({
@@ -34,6 +35,26 @@ function validPort(value, defaultValue) {
return Number.isInteger(port) && port >= 1 && port <= 65535 ? String(port) : defaultValue;
}
function validPortValue(value) {
const text = String(value || '');
const port = Number(text);
return /^[0-9]+$/.test(text) && Number.isSafeInteger(port) && port >= 1 && port <= 65535;
}
function validatePortValue(section_id, value, otherOption, singlePortOption) {
if (!validPortValue(value))
return _('Port must be an integer between 1 and 65535.');
const singlePort = singlePortOption.formvalue(section_id);
const otherValue = otherOption.formvalue(section_id);
if (singlePort === '0' && validPortValue(otherValue) && Number(value) === Number(otherValue))
return _('Interface port and management port must be different.');
return true;
}
function normalizePath(value) {
const path = String(value || '');
@@ -99,6 +120,9 @@ function serviceRunning(status) {
const service = status && status.gecoosac;
const instances = service && service.instances;
if (status && status.ok === false)
return false;
if (status && status.running === true)
return true;
@@ -112,6 +136,13 @@ function serviceRunning(status) {
return false;
}
function statusFailure() {
return {
ok: false,
error: _('Unable to query service status')
};
}
function clientHost() {
let host = window.location.hostname;
@@ -132,6 +163,9 @@ function clientUrl() {
}
function renderStatusContent(status) {
if (status && status.error)
return E('p', { 'class': 'gecoosac-stopped' }, _('Service status unavailable') + ': ' + _(status.error));
const running = serviceRunning(status);
const text = running
? _('The GecoosAC service is running.')
@@ -174,12 +208,15 @@ return view.extend({
load() {
return Promise.all([
uci.load('gecoosac'),
L.resolveDefault(callServiceStatus(), {})
callServiceStatus().catch(function() {
return statusFailure();
})
]);
},
render(data) {
let m, s, o, uploadDirOption;
let portOption, managementPortOption, singlePortOption;
m = new form.Map('gecoosac', _('Gecoos AC'),
_('Only supports Gecoos AP firmware 7.6 and above.') + '<br />' +
@@ -190,7 +227,9 @@ return view.extend({
s.render = function() {
if (!statusPollRegistered) {
poll.add(function() {
return L.resolveDefault(callServiceStatus(), {}).then(updateStatus);
return callServiceStatus().then(updateStatus).catch(function() {
updateStatus(statusFailure());
});
}, 3);
statusPollRegistered = true;
}
@@ -212,23 +251,55 @@ return view.extend({
o = s.option(form.Flag, 'enabled', _('Enabled AC'));
o.rmempty = false;
o = s.option(form.Value, 'port', _('Set interface port'));
portOption = s.option(form.Value, 'port', _('Set interface port'));
o = portOption;
o.placeholder = '60650';
o.default = '60650';
o.datatype = 'port';
o.rmempty = false;
o = s.option(form.Flag, 'isonlyoneprot', _('Single Port Mode'),
singlePortOption = s.option(form.Flag, 'isonlyoneprot', _('Single Port Mode'),
_('Do not enable the independent management port, only use one port for management.'));
o = singlePortOption;
o.default = '1';
o.rmempty = false;
o = s.option(form.Value, 'm_port', _('Set management port'));
managementPortOption = s.option(form.Value, 'm_port', _('Set management port'));
o = managementPortOption;
o.placeholder = '8080';
o.default = '8080';
o.datatype = 'port';
o.depends('isonlyoneprot', '0');
portOption.validate = function(section_id, value) {
return validatePortValue(section_id, value, managementPortOption, singlePortOption);
};
managementPortOption.validate = function(section_id, value) {
return validatePortValue(section_id, value, portOption, singlePortOption);
};
singlePortOption.validate = function(section_id, value) {
if (value === '0') {
const port = portOption.formvalue(section_id);
const managementPort = managementPortOption.formvalue(section_id);
if (validPortValue(port) && validPortValue(managementPort) && Number(port) === Number(managementPort))
return _('Interface port and management port must be different.');
}
return true;
};
const revalidatePorts = function(_event, section_id) {
for (const option of [ portOption, managementPortOption, singlePortOption ]) {
const element = option.getUIElement(section_id);
if (element)
element.triggerValidation();
}
};
portOption.onchange = revalidatePorts;
managementPortOption.onchange = revalidatePorts;
singlePortOption.onchange = revalidatePorts;
o = s.option(form.Flag, 'https', _('Enable HTTPS service'),
_('Default certificate files are generated when HTTPS starts; custom paths must point to a readable certificate and matching key.'));
o.default = '0';
@@ -320,11 +391,11 @@ return view.extend({
if (!confirm(_('Really clear the saved upload directory?')))
return Promise.resolve();
return callClearUpload().then(function(res) {
if (res && res.result === true)
return callClearUpload().then(function() {
if (arguments[0] && arguments[0].result === true)
ui.addNotification(null, E('p', {}, _('Saved upload directory cleared')));
else
ui.addNotification(null, E('p', {}, clearUploadError(res)), 'danger');
ui.addNotification(null, E('p', {}, clearUploadError(arguments[0])), 'danger');
});
};
+33
View File
@@ -147,3 +147,36 @@ msgstr "无法删除上传目录内容"
msgid "Upload directory contains configured runtime paths"
msgstr "上传目录包含已配置的运行目录"
msgid "Port must be an integer between 1 and 65535."
msgstr "端口必须是 1 到 65535 之间的整数。"
msgid "Interface port and management port must be different."
msgstr "接口端口和管理端口必须不同。"
msgid "Unable to query service status"
msgstr "无法查询服务状态"
msgid "Service status unavailable"
msgstr "服务状态不可用"
msgid "Invalid service status response"
msgstr "服务状态响应无效"
msgid "Unable to resolve upload directory"
msgstr "无法解析上传目录"
msgid "Upload directory contains a configured protected path"
msgstr "上传目录包含已配置的受保护路径"
msgid "Unable to validate configured paths"
msgstr "无法验证已配置的路径"
msgid "Upload directory or its parent is not root-owned and private"
msgstr "上传目录或其父目录不是 root 所有且为私有目录"
msgid "Unable to prepare upload directory cleanup"
msgstr "无法准备上传目录清理"
msgid "Unable to recreate upload directory"
msgstr "无法重新创建上传目录"
+33
View File
@@ -147,3 +147,36 @@ msgstr "無法移除上傳目錄內容"
msgid "Upload directory contains configured runtime paths"
msgstr "上傳目錄包含已設定的執行時路徑"
msgid "Port must be an integer between 1 and 65535."
msgstr "連接埠必須是 1 到 65535 之間的整數。"
msgid "Interface port and management port must be different."
msgstr "介面連接埠和管理連接埠必須不同。"
msgid "Unable to query service status"
msgstr "無法查詢服務狀態"
msgid "Service status unavailable"
msgstr "服務狀態無法使用"
msgid "Invalid service status response"
msgstr "服務狀態回應無效"
msgid "Unable to resolve upload directory"
msgstr "無法解析上傳目錄"
msgid "Upload directory contains a configured protected path"
msgstr "上傳目錄包含已設定的受保護路徑"
msgid "Unable to validate configured paths"
msgstr "無法驗證已設定的路徑"
msgid "Upload directory or its parent is not root-owned and private"
msgstr "上傳目錄或其父目錄不是 root 所有且為私有目錄"
msgid "Unable to prepare upload directory cleanup"
msgstr "無法準備上傳目錄清理"
msgid "Unable to recreate upload directory"
msgstr "無法重新建立上傳目錄"
@@ -80,31 +80,96 @@ path_in_dir() {
[ "${path#"$root"/}" != "$path" ]
}
is_secure_dir() {
local allow_sticky="$2" owner permissions metadata
[ -d "$1" ] && [ ! -L "$1" ] || return 1
metadata="$(ls -ldn "$1" 2>/dev/null)" || return 1
set -- $metadata
permissions="$1"
owner="$3"
[ "$owner" = "0" ] || return 1
case "$permissions" in
d?????????) ;;
*) return 1 ;;
esac
if [ "$(printf '%s' "$permissions" | cut -c6)" = "w" ] || \
[ "$(printf '%s' "$permissions" | cut -c9)" = "w" ]; then
[ "$allow_sticky" = "1" ] && [ "$(printf '%s' "$permissions" | cut -c10)" = "t" ] || return 1
fi
}
is_secure_upload_dir() {
local path current part rest
path="$(normalize_path "$1")" || return 1
[ -d "$path" ] && [ ! -L "$path" ] || return 1
current="/"
rest="${path#/}"
while [ -n "$rest" ]; do
part="${rest%%/*}"
if [ "$part" = "$rest" ]; then
rest=""
else
rest="${rest#*/}"
fi
current="${current%/}/$part"
case "$current" in
/tmp) is_secure_dir "$current" 1 || return 1 ;;
*) is_secure_dir "$current" || return 1 ;;
esac
done
}
configured_path_in_upload() {
local option="$1"
local upload_path="$2"
local path real_path
local upload_path="$2" path real_path
path="$(uci -q get "gecoosac.config.${option}")"
[ -n "$path" ] || return 1
case "$path" in
/*) ;;
*) return 1 ;;
esac
path="$(normalize_path "$path")" || return 2
path_in_dir "$path" "$upload_path" && return 0
real_path="$(readlink -f "$path" 2>/dev/null)"
[ -n "$real_path" ] || real_path="$(normalize_path "$path")" || return 1
real_path="$(readlink -f "$path" 2>/dev/null)" || return 2
[ -n "$real_path" ] || return 2
real_path="$(normalize_path "$real_path")" || return 2
path_in_dir "$real_path" "$upload_path"
}
status_result() {
local ok="$1" running="$2" message="$3"
json_init
json_add_boolean ok "$ok"
json_add_boolean running "$running"
[ -n "$message" ] && json_add_string error "$message"
json_dump
json_cleanup
}
service_status() {
local data instances instance running state
running=0
data="$(ubus call service list '{"name":"gecoosac"}' 2>/dev/null)"
if json_load "$data" 2>/dev/null && json_select gecoosac 2>/dev/null && json_select instances 2>/dev/null; then
data="$(ubus call service list '{"name":"gecoosac"}' 2>/dev/null)" || {
status_result 0 0 "Unable to query service status"
return
}
json_load "$data" 2>/dev/null || {
status_result 0 0 "Invalid service status response"
return
}
if json_select gecoosac 2>/dev/null; then
if ! json_select instances 2>/dev/null; then
json_cleanup
status_result 0 0 "Invalid service status response"
return
fi
json_get_keys instances
for instance in $instances; do
json_select "$instance" 2>/dev/null || continue
@@ -117,14 +182,12 @@ service_status() {
done
fi
json_init
json_add_boolean running "$running"
json_dump
json_cleanup
status_result 1 "$running"
}
clear_upload() {
local path real entry
local path real parent stage option
path="$(uci -q get gecoosac.config.upload_dir)"
[ -n "$path" ] || path="$DEFAULT_UPLOAD_DIR"
@@ -134,31 +197,69 @@ clear_upload() {
*) json_result 0 "Expecting an absolute path"; return ;;
esac
path="$(normalize_path "$path")"
path="$(normalize_path "$path")" || { json_result 0 "Expecting an absolute path"; return; }
real="$(readlink -f "$path" 2>/dev/null)"
[ -n "$real" ] || real="$path"
[ -n "$real" ] || { json_result 0 "Unable to resolve upload directory" "$path"; return; }
real="$(normalize_path "$real")" || { json_result 0 "Expecting an absolute path"; return; }
if ! safe_upload_path "$real"; then
if [ "$real" != "$path" ] || ! safe_upload_path "$real"; then
json_result 0 "Only Gecoos upload directories can be cleared" "$real"
return
fi
if configured_path_in_upload db_dir "$real" || configured_path_in_upload piddir "$real"; then
json_result 0 "Upload directory contains configured runtime paths" "$real"
if [ ! -e "$real" ] && [ ! -L "$real" ]; then
json_result 1 "" "$real"
return
fi
if ! is_secure_upload_dir "$real"; then
json_result 0 "Upload directory or its parent is not root-owned and private" "$real"
return
fi
[ -d "$real" ] || { json_result 1 "" "$real"; return; }
for option in db_dir piddir crt_file key_file; do
configured_path_in_upload "$option" "$real"
case "$?" in
0) json_result 0 "Upload directory contains a configured protected path" "$real"; return ;;
1) ;;
*) json_result 0 "Unable to validate configured paths" "$real"; return ;;
esac
done
for entry in "$real"/* "$real"/.[!.]* "$real"/..?*; do
[ -e "$entry" ] || [ -L "$entry" ] || continue
parent="${real%/*}"
stage="$(mktemp -d "$parent/.gecoosac-clear.XXXXXX" 2>/dev/null)" || {
json_result 0 "Unable to prepare upload directory cleanup" "$real"
return
}
if ! chmod 0700 "$stage"; then
rm -rf "$stage"
json_result 0 "Unable to prepare upload directory cleanup" "$real"
return
fi
if ! rm -rf "$entry"; then
json_result 0 "Unable to remove upload directory contents" "$real"
if ! mv "$real" "$stage/upload"; then
rm -rf "$stage"
json_result 0 "Unable to prepare upload directory cleanup" "$real"
return
fi
if ! rm -rf "$stage/upload"; then
if [ ! -e "$real" ] && [ ! -L "$real" ]; then
mkdir "$real" 2>/dev/null && chmod 0750 "$real" 2>/dev/null
fi
logger -t gecoosac "upload cleanup retained staged data at $stage"
json_result 0 "Unable to remove upload directory contents" "$real"
return
fi
if [ ! -d "$real" ]; then
if ! mkdir "$real" && { [ ! -d "$real" ] || [ -L "$real" ]; }; then
json_result 0 "Unable to recreate upload directory" "$real"
return
fi
done
fi
if [ -L "$real" ] || ! chmod 0750 "$real" || ! is_secure_upload_dir "$real" || ! rmdir "$stage"; then
json_result 0 "Unable to recreate upload directory" "$real"
return
fi
json_result 1 "" "$real"
}
+36 -5
View File
@@ -1,15 +1,46 @@
# Copyright (C) 2018-2022 Lienol <lawlienol@gmail.com>
# Copyright (C) 2018-2026 Lienol <lawlienol@gmail.com>
#
# This is free software, licensed under the GNU General Public License v3.
#
include $(TOPDIR)/rules.mk
LUCI_TITLE:=LuCI support for KodExplorer
LUCI_DEPENDS:=+nginx-ssl +unzip +zoneinfo-asia +php8 +php8-fastcgi +php8-fpm +php8-mod-curl +php8-mod-dom +php8-mod-gd +php8-mod-iconv +php8-mod-mbstring +php8-mod-opcache +php8-mod-session +php8-mod-zip +php8-mod-sqlite3 +php8-mod-pdo +php8-mod-pdo-sqlite +php8-mod-pdo-mysql +php8-mod-xml +php8-mod-xmlreader +php8-mod-xmlwriter
LUCI_PKGARCH:=all
PKG_NAME:=luci-app-kodexplorer
PKG_VERSION:=20220109
PKG_RELEASE:=3
PKG_RELEASE:=4
LUCI_TITLE:=LuCI support for KodExplorer
LUCI_PKGARCH:=all
define Package/$(PKG_NAME)/config
config PACKAGE_$(PKG_NAME)_depends
depends on PACKAGE_$(PKG_NAME)
bool
default y
select PACKAGE_nginx-ssl
select PACKAGE_unzip
select PACKAGE_zoneinfo-asia
select PACKAGE_php8
select PACKAGE_php8-fastcgi
select PACKAGE_php8-fpm
select PACKAGE_php8-mod-curl
select PACKAGE_php8-mod-dom
select PACKAGE_php8-mod-gd
select PACKAGE_php8-mod-iconv
select PACKAGE_php8-mod-mbstring
select PACKAGE_php8-mod-opcache
select PACKAGE_php8-mod-pdo
select PACKAGE_php8-mod-pdo-mysql
select PACKAGE_php8-mod-pdo-sqlite
select PACKAGE_php8-mod-session
select PACKAGE_php8-mod-sqlite3
select PACKAGE_php8-mod-xml
select PACKAGE_php8-mod-xmlreader
select PACKAGE_php8-mod-xmlwriter
select PACKAGE_php8-mod-zip
endef
include $(TOPDIR)/feeds/luci/luci.mk
-18
View File
@@ -1,18 +0,0 @@
# Copyright (C) 2016 Openwrt.org
#
# This is free software, licensed under the Apache License, Version 2.0 .
#
include $(TOPDIR)/rules.mk
LUCI_TITLE:=LuCI support for linkeaselite
LUCI_DEPENDS:=+linkeaselite
LUCI_PKGARCH:=all
PKG_VERSION:=1.0.0
PKG_RELEASE:=3
LUCI_MINIFY_CSS:=0
LUCI_MINIFY_JS:=0
include $(TOPDIR)/feeds/luci/luci.mk
# call BuildPackage - OpenWrt buildroot signature
@@ -1,31 +0,0 @@
module("luci.controller.linkeaselite", package.seeall)
function index()
if not nixio.fs.access("/etc/config/linkeaselite") then
return
end
local page = entry({"admin", "services", "linkeaselite"}, firstchild(), _("LinkEaseLite"), 20)
page.dependent = true
entry({"admin", "services", "linkeaselite", "config"}, cbi("linkeaselite"), _("Settings"), 10).leaf = true
entry({"admin", "services", "linkeaselite_status"}, call("linkeaselite_status"))
entry({"admin", "services", "linkeaselite", "file"}, call("linkeaselite_file_removed")).leaf = true
end
function linkeaselite_status()
local sys = require "luci.sys"
local uci = require "luci.model.uci".cursor()
local port = tonumber(uci:get_first("linkeaselite", "linkeaselite", "port"))
local status = {
running = (sys.call("pidof linkease-lite >/dev/null") == 0),
port = (port or 8897)
}
luci.http.prepare_content("application/json")
luci.http.write_json(status)
end
function linkeaselite_file_removed()
luci.http.status(404, "Not Found")
end
@@ -1,24 +0,0 @@
local m, s
local sys = require "luci.sys"
m = Map("linkeaselite", translate("LinkEaseLite"), translate("LinkEaseLite is an efficient data transfer tool for small-memory devices."))
m:section(SimpleSection).template = "linkeaselite_status"
m.on_after_commit = function(self)
sys.call("/etc/init.d/linkeaselite restart >/dev/null 2>&1")
end
s = m:section(TypedSection, "linkeaselite", translate("Global settings"))
s.addremove = false
s.anonymous = true
s:option(Flag, "enabled", translate("Enable")).rmempty = false
local port = s:option(Value, "port", translate("Port"))
port.rmempty = false
port.datatype = "port"
port.default = "8897"
s:option(Flag, "allowPublic", translate("AllowPublic"), translate("Allowing access via public IP addresses can lead to insufficient security.")).rmempty = false
return m
@@ -1,42 +0,0 @@
<script type="text/javascript">//<![CDATA[
XHR.poll(5, '<%=url("admin/services/linkeaselite_status")%>', null,
function(x, st)
{
var tb = document.getElementById('linkeaselite_status');
if (st && tb)
{
var legacyUrl = "http://" + window.location.hostname + ":" + (st.port || 8897) + "/";
var overallStatus = st.running
? '<br/><em style=\"color:green\"><%:The LinkEaseLite service is running.%></em>'
: '<br/><em style=\"color:red\"><%:The LinkEaseLite service is not running.%></em>';
tb.innerHTML = overallStatus;
function appendBreak()
{
tb.appendChild(document.createElement("br"));
}
function appendButton(value, action)
{
var button = document.createElement("input");
button.className = "btn cbi-button cbi-button-apply";
button.type = "button";
button.value = value;
button.onclick = action;
tb.appendChild(button);
}
appendBreak();
appendBreak();
appendButton(" <%:Click to open LinkEaseLite%> ", function() { window.open(legacyUrl); });
}
}
);
//]]></script>
<fieldset class="cbi-section">
<legend><%:LinkEaseLite Status%></legend>
<p id="linkeaselite_status">
<em><%:Collecting data...%></em>
</p>
</fieldset>
@@ -1,35 +0,0 @@
msgid "LinkEaseLite"
msgstr "易有云Lite"
msgid "LinkEaseLite is an efficient data transfer tool for small-memory devices."
msgstr "易有云Lite是面向小内存设备的轻量数据传输工具。"
msgid "Global settings"
msgstr "全局设置"
msgid "Enable"
msgstr "启用"
msgid "Port"
msgstr "端口"
msgid "AllowPublic"
msgstr "公网访问"
msgid "Allowing access via public IP addresses can lead to insufficient security."
msgstr "允许公网IP访问,会导致不够安全。"
msgid "Click to open LinkEaseLite"
msgstr "点击打开易有云Lite"
msgid "The LinkEaseLite service is running."
msgstr "易有云Lite服务已启动"
msgid "The LinkEaseLite service is not running."
msgstr "易有云Lite服务未启动"
msgid "LinkEaseLite Status"
msgstr "易有云Lite服务状态"
msgid "Collecting data..."
msgstr "收集数据..."
-1
View File
@@ -1 +0,0 @@
zh-cn
@@ -1,4 +0,0 @@
#!/bin/sh
rm -f /tmp/luci-indexcache /tmp/luci-indexcache.*
exit 0
+1 -1
View File
@@ -8,7 +8,7 @@ include $(TOPDIR)/rules.mk
PKG_NAME:=luci-app-passwall
PKG_VERSION:=26.8.1
PKG_RELEASE:=202
PKG_RELEASE:=203
PKG_PO_VERSION:=$(PKG_VERSION)
PKG_CONFIG_DEPENDS:= \
@@ -1105,6 +1105,9 @@ function gen_config(var)
local dns_socks_address = var["dns_socks_address"]
local dns_socks_port = var["dns_socks_port"]
local no_run = var["no_run"]
local use_proxy_list = var["use_proxy_list"]
local use_gfw_list = var["use_gfw_list"]
local chn_list = var["chn_list"]
local dns_domain_rules = {}
local dns = nil
@@ -1552,7 +1555,50 @@ function gen_config(var)
end
--shunt rule
uci:foreach(appname, "shunt_rules", function(e)
local function foreach_shunt_rule(callback)
uci:foreach(appname, "shunt_rules", callback)
if use_gfw_list ~= "1" or chn_list ~= "0" then return end
-- GFW 模式下使用分流节点时添加特定规则
local function read_proxy_list(path)
if use_proxy_list ~= "1" then return "" end
local map, list = {}, {}
local f = io.open(path)
if f then
for line in f:lines() do
if line ~= "" and not line:find("#", 1, true) and not map[line] then
map[line] = 1
list[#list + 1] = line
end
end
f:close()
end
return table.concat(list, "\n")
end
local domain_list = read_proxy_list("/usr/share/passwall/rules/proxy_host")
local ip_list = read_proxy_list("/usr/share/passwall/rules/proxy_ip")
local bin = api.finded_com("geoview")
if bin then
local geo_file = (uci:get(appname, "@global_rules[0]", "v2ray_location_asset") or "/usr/share/v2ray/"):match("^(.*)/") .. "/geosite.dat"
if luci.sys.call('"' .. bin .. '" -type geosite -input "' .. geo_file .. '" | grep -q "^GFW$"') == 0 then
domain_list = (domain_list == "") and "geosite:gfw" or domain_list .. "\ngeosite:gfw"
end
end
if domain_list ~= "" or ip_list ~= "" then
node["GFW_Mode_List"] = "_default"
callback({
[".name"] = "GFW_Mode_List",
remarks = "GFW_Mode_List",
domain_list = (domain_list ~= "") and domain_list or nil,
ip_list = (ip_list ~= "") and ip_list or nil
})
end
end
foreach_shunt_rule(function(e)
local outboundTag = gen_shunt_node(e[".name"])
if outboundTag and e.remarks then
if outboundTag == "default" then
@@ -1755,6 +1801,14 @@ function gen_config(var)
table.insert(rules, rule)
end
end)
if use_gfw_list == "1" and chn_list == "0" then -- GFW 模式下使用分流节点时添加兜底规则
table.insert(rules, {
action = "route",
port_range = { "0:65535" },
outbound = "direct"
})
end
else
COMMON.default_outbound_tag = gen_outbound_get_tag(flag, node or node_id, nil, {
fragment = singbox_settings.fragment == "1" or nil,
@@ -868,6 +868,9 @@ function gen_config(var)
local dns_socks_port = var["dns_socks_port"]
local loglevel = var["loglevel"] or "warning"
local no_run = var["no_run"]
local use_proxy_list = var["use_proxy_list"]
local use_gfw_list = var["use_gfw_list"]
local chn_list = var["chn_list"]
local dns_domain_rules = {}
local dns = nil
@@ -1363,7 +1366,50 @@ function gen_config(var)
end
--shunt rule
uci:foreach(appname, "shunt_rules", function(e)
local function foreach_shunt_rule(callback)
uci:foreach(appname, "shunt_rules", callback)
if use_gfw_list ~= "1" or chn_list ~= "0" then return end
-- GFW 模式下使用分流节点时添加特定规则
local function read_proxy_list(path)
if use_proxy_list ~= "1" then return "" end
local map, list = {}, {}
local f = io.open(path)
if f then
for line in f:lines() do
if line ~= "" and not line:find("#", 1, true) and not map[line] then
map[line] = 1
list[#list + 1] = line
end
end
f:close()
end
return table.concat(list, "\n")
end
local domain_list = read_proxy_list("/usr/share/passwall/rules/proxy_host")
local ip_list = read_proxy_list("/usr/share/passwall/rules/proxy_ip")
local bin = api.finded_com("geoview")
if bin then
local geo_file = (uci:get(appname, "@global_rules[0]", "v2ray_location_asset") or "/usr/share/v2ray/"):match("^(.*)/") .. "/geosite.dat"
if luci.sys.call('"' .. bin .. '" -type geosite -input "' .. geo_file .. '" | grep -q "^GFW$"') == 0 then
domain_list = (domain_list == "") and "geosite:gfw" or domain_list .. "\ngeosite:gfw"
end
end
if domain_list ~= "" or ip_list ~= "" then
node["GFW_Mode_List"] = "_default"
callback({
[".name"] = "GFW_Mode_List",
remarks = "GFW_Mode_List",
domain_list = (domain_list ~= "") and domain_list or nil,
ip_list = (ip_list ~= "") and ip_list or nil
})
end
end
foreach_shunt_rule(function(e)
local outbound_tag = gen_shunt_node(e[".name"])
if outbound_tag and e.remarks then
if outbound_tag == "default" then
@@ -1463,6 +1509,15 @@ function gen_config(var)
end
end)
if use_gfw_list == "1" and chn_list == "0" then -- GFW 模式下使用分流节点时添加兜底规则
table.insert(rules, {
ruleTag = "GFW_Mode_Default",
outboundTag = "direct",
port = (node.domainStrategy == "IPIfNonMatch") and "1-65535" or nil,
network = (node.domainStrategy ~= "IPIfNonMatch") and "tcp,udp" or nil
})
end
table.insert(rules, {
outboundTag = "direct",
ip = { "geoip:private" }
@@ -99,7 +99,7 @@ run_ipt2socks() {
run_singbox() {
local flag type node tcp_redir_port tcp_proxy_way udp_redir_port socks_address socks_port socks_username socks_password http_address http_port http_username http_password
local dns_listen_port direct_dns_query_strategy direct_dns_port direct_dns_udp_server direct_dns_tcp_server remote_dns_protocol remote_dns_udp_server remote_dns_tcp_server remote_dns_doh remote_dns_client_ip remote_fakedns remote_dns_query_strategy dns_cache dns_socks_address dns_socks_port
local loglevel log_file config_file server_host server_port no_run
local loglevel log_file config_file server_host server_port no_run use_proxy_list use_gfw_list chn_list
eval_set_val "$@"
[ -z "$type" ] && {
type=$(echo $(config_n_get $node type) | tr 'A-Z' 'a-z')
@@ -120,6 +120,9 @@ run_singbox() {
[ -n "$flag" ] && json_add_string "flag" "$flag"
[ -n "$node" ] && json_add_string "node" "$node"
[ -n "$use_proxy_list" ] && json_add_string "use_proxy_list" "$use_proxy_list"
[ -n "$use_gfw_list" ] && json_add_string "use_gfw_list" "$use_gfw_list"
[ -n "$chn_list" ] && json_add_string "chn_list" "$chn_list"
[ -n "$server_host" ] && json_add_string "server_host" "$server_host"
[ -n "$server_port" ] && json_add_string "server_port" "$server_port"
[ -n "$tcp_redir_port" ] && json_add_string "tcp_redir_port" "$tcp_redir_port"
@@ -197,7 +200,7 @@ run_singbox() {
run_xray() {
local flag type node tcp_redir_port tcp_proxy_way udp_redir_port socks_address socks_port socks_username socks_password http_address http_port http_username http_password
local dns_listen_port direct_dns_query_strategy direct_dns_port direct_dns_udp_server direct_dns_tcp_server remote_dns_protocol remote_dns_udp_server remote_dns_tcp_server remote_dns_doh remote_dns_client_ip remote_fakedns remote_dns_query_strategy dns_cache dns_socks_address dns_socks_port
local loglevel log_file config_file server_host server_port no_run
local loglevel log_file config_file server_host server_port no_run use_proxy_list use_gfw_list chn_list
eval_set_val "$@"
[ -z "$type" ] && {
type=$(echo $(config_n_get $node type) | tr 'A-Z' 'a-z')
@@ -209,6 +212,9 @@ run_xray() {
[ -z "$loglevel" ] && local loglevel=$(config_t_get global loglevel "warning")
[ -n "$flag" ] && json_add_string "flag" "$flag"
[ -n "$node" ] && json_add_string "node" "$node"
[ -n "$use_proxy_list" ] && json_add_string "use_proxy_list" "$use_proxy_list"
[ -n "$use_gfw_list" ] && json_add_string "use_gfw_list" "$use_gfw_list"
[ -n "$chn_list" ] && json_add_string "chn_list" "$chn_list"
[ -n "$server_host" ] && json_add_string "server_host" "$server_host"
[ -n "$server_port" ] && json_add_string "server_port" "$server_port"
[ -n "$tcp_redir_port" ] && json_add_string "tcp_redir_port" "$tcp_redir_port"
@@ -760,6 +766,7 @@ run_redir() {
}
NEXT_DNS_LISTEN_PORT=$(expr $NEXT_DNS_LISTEN_PORT + 1)
}
_args="${_args} use_proxy_list=$USE_PROXY_LIST use_gfw_list=$USE_GFW_LIST chn_list=$CHN_LIST"
run_singbox flag=$_flag node=$node tcp_redir_port=$local_port tcp_proxy_way=$TCP_PROXY_WAY config_file=$config_file log_file=$log_file ${_args}
;;
xray)
@@ -846,6 +853,7 @@ run_redir() {
}
NEXT_DNS_LISTEN_PORT=$(expr $NEXT_DNS_LISTEN_PORT + 1)
}
_args="${_args} use_proxy_list=$USE_PROXY_LIST use_gfw_list=$USE_GFW_LIST chn_list=$CHN_LIST"
run_xray flag=$_flag node=$node tcp_redir_port=$local_port tcp_proxy_way=$TCP_PROXY_WAY config_file=$config_file log_file=$log_file ${_args}
;;
naiveproxy)
@@ -1751,6 +1759,7 @@ acl_app() {
}
config_file="$TMP_PATH/$config_file"
[ "${type}" = "sing-box" ] && type="singbox"
_extra_param="${_extra_param} use_proxy_list=$use_proxy_list use_gfw_list=$use_gfw_list chn_list=$chn_list"
run_${type} flag=$tcp_node node=$tcp_node tcp_redir_port=$redir_port ${_extra_param} config_file=$config_file log_file=$log_file loglevel=$loglevel
else
config_file="acl/${tcp_node}_SOCKS_${socks_port}.json"
@@ -1398,8 +1398,8 @@ del_firewall_rule() {
done
for ipt in "$ipt_f" "$ip6t_f"; do
for chain in "FORWARD" "INPUT" "OUTPUT"; do
for i in $(seq 1 $($ipt -nL $chain | grep -c PSW)); do
local index=$($ipt --line-number -nL $chain | grep PSW | head -1 | awk '{print $1}')
for i in $(seq 1 $($ipt -nL $chain | grep -c PSW_REJECT)); do
local index=$($ipt --line-number -nL $chain | grep PSW_REJECT | head -1 | awk '{print $1}')
$ipt -D $chain $index 2>/dev/null
done
done
-1
View File
@@ -8,7 +8,6 @@ include $(TOPDIR)/rules.mk
LUCI_TITLE:=LuCI based ipk/apk store
LUCI_DESCRIPTION:=luci-app-store is a ipk/apk store developed by LinkEase team
LUCI_DEPENDS:=@(x86_64||aarch64) +curl +tar +libuci-lua +mount-utils +luci-lib-taskd
LUCI_DEPENDS+=$(if $(CONFIG_USE_APK),+apk +luci-compat,+opkg)
LUCI_EXTRA_DEPENDS:=luci-lib-taskd (>=1.0.19)
LUCI_PKGARCH:=all
+2 -2
View File
@@ -10,12 +10,12 @@ include $(INCLUDE_DIR)/kernel.mk
PKG_NAME:=natflow
PKG_VERSION:=20260531
PKG_RELEASE:=60
PKG_RELEASE:=61
PKG_SOURCE:=$(PKG_VERSION).tar.xz
PKG_SOURCE_URL:=https://github.com/ptpt52/natflow.git
PKG_SOURCE_PROTO:=git
PKG_SOURCE_VERSION:=c4c0370953045bac23728fbeff456fc584cd9c80
PKG_SOURCE_VERSION:=4e62e176dee1ee5d2bea09c40f5d515d6b8a3655
PKG_SOURCE_SUBDIR:=$(PKG_NAME)-$(PKG_VERSION)
PKG_MAINTAINER:=Chen Minqiang <ptpt52@gmail.com>
PKG_LICENSE:=GPL-2.0
+2 -2
View File
@@ -5,8 +5,8 @@
include $(TOPDIR)/rules.mk
PKG_NAME:=fastfetch
PKG_VERSION:=2.66.0
PKG_RELEASE:=12
PKG_VERSION:=2.67.0
PKG_RELEASE:=13
PKG_SOURCE:=$(PKG_NAME)-$(PKG_VERSION).tar.gz
PKG_SOURCE_URL:=https://codeload.github.com/fastfetch-cli/fastfetch/tar.gz/$(PKG_VERSION)?