🐶 Sync 2026-06-19 08:54:48

This commit is contained in:
github-actions[bot] committed 2026-06-19 08:54:48 +08:00
1 parent e6800e389f
commit 9699fa4ed9
15 files changed
+189 -46

No files matched your search

+1 -1
View File
@@ -7,7 +7,7 @@
include $(TOPDIR)/rules.mk include $(TOPDIR)/rules.mk
PKG_NAME:=filebrowser PKG_NAME:=filebrowser
PKG_VERSION:=1.3.3-stable PKG_VERSION:=1.4.0-stable
PKG_RELEASE=1 PKG_RELEASE=1
ifeq ($(ARCH),aarch64) ifeq ($(ARCH),aarch64)
+6 -1
View File
@@ -2,7 +2,7 @@ include $(TOPDIR)/rules.mk
PKG_NAME:=gecoosac PKG_NAME:=gecoosac
PKG_VERSION:=2.2.20251015 PKG_VERSION:=2.2.20251015
PKG_RELEASE:=8 PKG_RELEASE:=9
ifeq ($(ARCH),aarch64) ifeq ($(ARCH),aarch64)
PKG_ARCH:=ac_linux_arm64 PKG_ARCH:=ac_linux_arm64
@@ -49,6 +49,11 @@ define Package/$(PKG_NAME)/conffiles
/etc/gecoosac/ /etc/gecoosac/
endef endef
define Build/Prepare
$(call Build/Prepare/Default)
$(CP) ../LICENSE $(PKG_BUILD_DIR)/LICENSE
endef
define Build/Compile define Build/Compile
endef endef
+29 -2
View File
@@ -43,6 +43,29 @@ is_abs_path() {
esac esac
} }
strip_trailing_slashes() {
local path="$1"
while [ "$path" != "/" ] && [ "${path%/}" != "$path" ]; do
path="${path%/}"
done
printf '%s\n' "$path"
}
is_safe_upload_dir() {
local path
is_abs_path "$1" || return 1
path="$(strip_trailing_slashes "$1")"
case "$path" in
*/gecoosac/upload) return 0 ;;
esac
return 1
}
is_port() { is_port() {
case "$1" in case "$1" in
""|*[!0-9]*) return 1 ;; ""|*[!0-9]*) return 1 ;;
@@ -175,7 +198,11 @@ generate_default_cert() {
} }
normalize_conf() { normalize_conf() {
is_abs_path "$upload_dir" || upload_dir="$DEFAULT_UPLOAD_DIR" if is_safe_upload_dir "$upload_dir"; then
upload_dir="$(strip_trailing_slashes "$upload_dir")/"
else
upload_dir="$DEFAULT_UPLOAD_DIR"
fi
is_abs_path "$db_dir" || db_dir="$DEFAULT_DB_DIR" is_abs_path "$db_dir" || db_dir="$DEFAULT_DB_DIR"
is_abs_path "$crt_file" || crt_file="$DEFAULT_CRT_FILE" is_abs_path "$crt_file" || crt_file="$DEFAULT_CRT_FILE"
is_abs_path "$key_file" || key_file="$DEFAULT_KEY_FILE" is_abs_path "$key_file" || key_file="$DEFAULT_KEY_FILE"
@@ -250,7 +277,7 @@ start_service() {
procd_set_param pidfile "${piddir%/}/gecoosac.pid" procd_set_param pidfile "${piddir%/}/gecoosac.pid"
procd_set_param stdout "$log" procd_set_param stdout "$log"
procd_set_param stderr "$log" procd_set_param stderr "$log"
procd_set_param respawn ${respawn_threshold:-3600} ${respawn_timeout:-5} ${respawn_retry:-5} procd_set_param respawn "${respawn_threshold:-3600}" "${respawn_timeout:-5}" "${respawn_retry:-5}"
procd_close_instance procd_close_instance
} }
+50 -1
View File
@@ -1,6 +1,7 @@
#!/bin/sh #!/bin/sh
changed=0 changed=0
DEFAULT_UPLOAD_DIR=/tmp/gecoosac/upload/
DEFAULT_CRT_FILE=/etc/gecoosac/tls/gecoosac.crt DEFAULT_CRT_FILE=/etc/gecoosac/tls/gecoosac.crt
DEFAULT_KEY_FILE=/etc/gecoosac/tls/gecoosac.key DEFAULT_KEY_FILE=/etc/gecoosac/tls/gecoosac.key
OLD_CRT_FILE=/etc/gecoosac/tls/1.crt OLD_CRT_FILE=/etc/gecoosac/tls/1.crt
@@ -21,6 +22,53 @@ set_default() {
changed=1 changed=1
} }
strip_trailing_slashes() {
local path="$1"
while [ "$path" != "/" ] && [ "${path%/}" != "$path" ]; do
path="${path%/}"
done
printf '%s\n' "$path"
}
is_abs_path() {
case "$1" in
/*) return 0 ;;
*) return 1 ;;
esac
}
is_safe_upload_dir() {
local path
is_abs_path "$1" || return 1
path="$(strip_trailing_slashes "$1")"
case "$path" in
*/gecoosac/upload) return 0 ;;
esac
return 1
}
normalize_upload_dir() {
local upload_dir normalized
upload_dir="$(uci -q get gecoosac.config.upload_dir)"
[ -n "$upload_dir" ] || return 0
if is_safe_upload_dir "$upload_dir"; then
normalized="$(strip_trailing_slashes "$upload_dir")/"
else
normalized="$DEFAULT_UPLOAD_DIR"
fi
[ "$upload_dir" = "$normalized" ] && return 0
uci -q set "gecoosac.config.upload_dir=${normalized}"
changed=1
}
migrate_legacy_cert_paths() { migrate_legacy_cert_paths() {
local crt_file key_file local crt_file key_file
local migrate local migrate
@@ -46,6 +94,7 @@ migrate_legacy_cert_paths() {
ensure_section ensure_section
migrate_legacy_cert_paths migrate_legacy_cert_paths
normalize_upload_dir
set_default enabled 0 set_default enabled 0
set_default port 60650 set_default port 60650
set_default isonlyoneprot 1 set_default isonlyoneprot 1
@@ -53,7 +102,7 @@ set_default m_port 8080
set_default https 0 set_default https 0
set_default crt_file "$DEFAULT_CRT_FILE" set_default crt_file "$DEFAULT_CRT_FILE"
set_default key_file "$DEFAULT_KEY_FILE" set_default key_file "$DEFAULT_KEY_FILE"
set_default upload_dir /tmp/gecoosac/upload/ set_default upload_dir "$DEFAULT_UPLOAD_DIR"
set_default db_dir /etc/gecoosac/ set_default db_dir /etc/gecoosac/
set_default piddir /var/run/ set_default piddir /var/run/
set_default lang zh set_default lang zh
+1 -1
View File
@@ -6,7 +6,7 @@ include $(TOPDIR)/rules.mk
PKG_NAME:=luci-app-daede PKG_NAME:=luci-app-daede
PKG_VERSION:=1.13.0 PKG_VERSION:=1.13.0
PKG_RELEASE:=16 PKG_RELEASE:=17
PKG_MAINTAINER:=kenzok8 PKG_MAINTAINER:=kenzok8
PKG_BUILD_DIR:=$(BUILD_DIR)/$(PKG_NAME) PKG_BUILD_DIR:=$(BUILD_DIR)/$(PKG_NAME)
@@ -377,10 +377,21 @@ return view.extend({
poll.add(refresh); poll.add(refresh);
refresh(); refresh();
// First paint reads the cached index (fast). Refresh the index, then // Start the potentially slow index refresh without holding a LuCI RPC
// re-probe once it's current so a freshly published version shows // request open, then re-probe promptly when its status changes to done.
// without waiting for a poll tick. refresh-index.sh self-throttles. const waitIndexRefresh = function(tries) {
fs.exec('/usr/share/luci-app-daede/refresh-index.sh', []).then(refresh).catch(function() {}); return L.resolveDefault(fs.read_direct('/tmp/luci-app-daede.idx.status', 'text'), '').then(function(status) {
if (String(status).trim() === 'done')
return refresh();
if (tries <= 0)
return;
return new Promise(function(resolve) { setTimeout(resolve, 1000); })
.then(function() { return waitIndexRefresh(tries - 1); });
});
};
fs.exec('/usr/share/luci-app-daede/refresh-index.sh', [])
.then(function() { return waitIndexRefresh(30); })
.catch(function() {});
// === Geo data source (preset / custom URL + auto-update) === // === Geo data source (preset / custom URL + auto-update) ===
const geoSettings = (function() { const geoSettings = (function() {
@@ -1,20 +1,28 @@
#!/bin/sh #!/bin/sh
# Refresh the apk/opkg index for the Updates view. Runs in the FOREGROUND so # Refresh the apk/opkg index for the Updates view without holding the LuCI RPC
# the caller can re-probe once the index is current; throttled to 90s. # request open. The view watches STATUS and re-probes as soon as it reads done.
LOCK=/tmp/luci-app-daede.idx.lock LOCK=/tmp/luci-app-daede.idx.lock
STATUS=/tmp/luci-app-daede.idx.status
if [ -f "$LOCK" ]; then if [ -f "$LOCK" ]; then
mtime=$(date -r "$LOCK" +%s 2>/dev/null || echo 0) mtime=$(date -r "$LOCK" +%s 2>/dev/null || echo 0)
[ "$(( $(date +%s) - mtime ))" -lt 90 ] && exit 0 if [ "$(( $(date +%s) - mtime ))" -lt 90 ]; then
[ -f "$STATUS" ] || printf '%s\n' done > "$STATUS"
exit 0
fi
fi fi
: > "$LOCK" : > "$LOCK"
printf '%s\n' running > "$STATUS"
# -n: skip if a package op holds the shared apk lock (no need to refresh then) # -n: skip if a package op holds the shared apk lock (no need to refresh then)
if command -v apk >/dev/null 2>&1; then (
flock -n /tmp/luci-app-daede.apk.lock apk update if command -v apk >/dev/null 2>&1; then
elif command -v opkg >/dev/null 2>&1; then flock -n /tmp/luci-app-daede.apk.lock apk update
opkg update elif command -v opkg >/dev/null 2>&1; then
fi >/dev/null 2>&1 opkg update
fi
printf '%s\n' done > "$STATUS"
) >/dev/null 2>&1 </dev/null &
exit 0 exit 0
@@ -20,6 +20,7 @@
"/tmp/luci-app-daede.pkg-daed.log": [ "read" ], "/tmp/luci-app-daede.pkg-daed.log": [ "read" ],
"/tmp/luci-app-daede.pkg-luci-app-daede.log": [ "read" ], "/tmp/luci-app-daede.pkg-luci-app-daede.log": [ "read" ],
"/tmp/luci-app-daede.backup.log": [ "read" ], "/tmp/luci-app-daede.backup.log": [ "read" ],
"/tmp/luci-app-daede.idx.status": [ "read" ],
"/bin/pidof dae": [ "exec" ], "/bin/pidof dae": [ "exec" ],
"/bin/pidof daed": [ "exec" ], "/bin/pidof daed": [ "exec" ],
"/usr/bin/dae validate -c /tmp/dae-validate.dae": [ "exec" ], "/usr/bin/dae validate -c /tmp/dae-validate.dae": [ "exec" ],
+2 -2
View File
@@ -6,8 +6,8 @@
include $(TOPDIR)/rules.mk include $(TOPDIR)/rules.mk
PKG_NAME:=luci-app-gecoosac PKG_NAME:=luci-app-gecoosac
PKG_VERSION:=2.2 PKG_VERSION:=2.3
PKG_RELEASE:=9 PKG_RELEASE:=10
LUCI_TITLE:=LuCI Support for gecoosac LUCI_TITLE:=LuCI Support for gecoosac
LUCI_DEPENDS:=+gecoosac LUCI_DEPENDS:=+gecoosac
@@ -30,6 +30,21 @@ function validPort(value, defaultValue) {
return Number.isInteger(port) && port >= 1 && port <= 65535 ? String(port) : defaultValue; return Number.isInteger(port) && port >= 1 && port <= 65535 ? String(port) : defaultValue;
} }
function stripTrailingSlashes(value) {
let path = String(value || '');
while (path.length > 1 && path.endsWith('/'))
path = path.slice(0, -1);
return path;
}
function validUploadDir(value) {
const path = stripTrailingSlashes(value);
return path.charAt(0) === '/' && path.endsWith('/gecoosac/upload');
}
function serviceRunning(status) { function serviceRunning(status) {
const service = status && status.gecoosac; const service = status && status.gecoosac;
const instances = service && service.instances; const instances = service && service.instances;
@@ -167,19 +182,25 @@ return view.extend({
o.placeholder = DEFAULT_CRT_FILE; o.placeholder = DEFAULT_CRT_FILE;
o.default = DEFAULT_CRT_FILE; o.default = DEFAULT_CRT_FILE;
o.datatype = 'file'; o.datatype = 'file';
o.depends('https', '1'); o.depends({ isonlyoneprot: '0', https: '1' });
o = s.option(form.Value, 'key_file', _('Specify key certificate file')); o = s.option(form.Value, 'key_file', _('Specify key certificate file'));
o.placeholder = DEFAULT_KEY_FILE; o.placeholder = DEFAULT_KEY_FILE;
o.default = DEFAULT_KEY_FILE; o.default = DEFAULT_KEY_FILE;
o.datatype = 'file'; o.datatype = 'file';
o.depends('https', '1'); o.depends({ isonlyoneprot: '0', https: '1' });
o = s.option(form.Value, 'upload_dir', _('Upload dir path'), _('The path to upload AP upgrade firmware')); o = s.option(form.Value, 'upload_dir', _('Upload dir path'),
_('Upload AP upgrade firmware here. For safe cleanup, use an absolute path ending with /gecoosac/upload, for example /tmp/gecoosac/upload/.'));
o.placeholder = DEFAULT_UPLOAD_DIR; o.placeholder = DEFAULT_UPLOAD_DIR;
o.default = DEFAULT_UPLOAD_DIR; o.default = DEFAULT_UPLOAD_DIR;
o.datatype = 'directory'; o.datatype = 'directory';
o.rmempty = false; o.rmempty = false;
o.validate = function(section_id, value) {
return validUploadDir(value)
? true
: _('Upload directory must be an absolute path ending with /gecoosac/upload.');
};
o = s.option(form.Value, 'db_dir', _('Database dir path'), _('The path to store the config database')); o = s.option(form.Value, 'db_dir', _('Database dir path'), _('The path to store the config database'));
o.placeholder = DEFAULT_DB_DIR; o.placeholder = DEFAULT_DB_DIR;
+5 -2
View File
@@ -51,8 +51,11 @@ msgstr "指定 key 证书文件"
msgid "Upload dir path" msgid "Upload dir path"
msgstr "上传目录" msgstr "上传目录"
msgid "The path to upload AP upgrade firmware" msgid "Upload AP upgrade firmware here. For safe cleanup, use an absolute path ending with /gecoosac/upload, for example /tmp/gecoosac/upload/."
msgstr "存放AP升级固件的路径" msgstr "AP 升级固件会上传到此目录。为确保安全清理,请使用以 /gecoosac/upload 结尾的绝对路径,例如 /tmp/gecoosac/upload/。"
msgid "Upload directory must be an absolute path ending with /gecoosac/upload."
msgstr "上传目录必须是以 /gecoosac/upload 结尾的绝对路径。"
msgid "Database dir path" msgid "Database dir path"
msgstr "数据库目录" msgstr "数据库目录"
+1 -1
View File
@@ -9,7 +9,7 @@ include $(TOPDIR)/rules.mk
PKG_NAME:=luci-app-xwan PKG_NAME:=luci-app-xwan
PKG_VERSION:=1.0.0 PKG_VERSION:=1.0.0
PKG_RELEASE:=1 PKG_RELEASE:=2
PKG_LICENSE:=GPLv3 PKG_LICENSE:=GPLv3
PKG_LICENSE_FILES:=LICENSE PKG_LICENSE_FILES:=LICENSE
+1 -1
View File
@@ -5,7 +5,7 @@ module("luci.controller.xwan", package.seeall)
function index() function index()
local page local page
page = entry({"admin", "network", "xwan"}, cbi("xwan/xwan"), _("Xwan")) page = entry({"admin", "network", "xwan"}, cbi("xwan/xwan"), _("Multi-WAN Dialing"))
page.leaf = true page.leaf = true
page.acl_depends = { "luci-app-xwan" } page.acl_depends = { "luci-app-xwan" }
end end
+30 -12
View File
@@ -1,20 +1,38 @@
msgid "" msgid ""
msgstr "Content-Type: text/plain; charset=UTF-8\n" msgstr "Content-Type: text/plain; charset=UTF-8\n"
msgid "Xwan" msgid "Multi-WAN Dialing"
msgstr "多拨" msgstr "单线多拨"
msgid "Xwan Settings" msgid "Multi-WAN Dialing Settings"
msgstr "多拨设置" msgstr "单线多拨设置"
msgid "Enable xwan" msgid "Enable multi-WAN dialing"
msgstr "开启多拨" msgstr "启用多拨"
msgid "multiwan on single interface" msgid "Create multiple WAN connections on a single physical interface."
msgstr "单网口多拨号" msgstr "在同一个物理接口上创建多个 WAN 连接。"
msgid "Number of xwan" msgid "Number of WAN instances"
msgstr "多少拨" msgstr "多拨数量"
msgid "Auto balanced setup" msgid "Configure load balancing automatically"
msgstr "自动负载均衡和叠加" msgstr "自动配置负载均衡"
msgid "Health check hostnames or IP addresses"
msgstr "健康检查主机名或 IP 地址"
msgid "Ping these hosts to determine whether each WAN link is up. Leave empty to treat the links as always online."
msgstr "通过 ping 这些主机判断每条 WAN 链路是否在线。留空则视为链路始终在线。"
msgid "IP family"
msgstr "IP 协议族"
msgid "IPv4 and IPv6"
msgstr "IPv4 和 IPv6"
msgid "IPv4"
msgstr "IPv4"
msgid "IPv6"
msgstr "IPv6"
@@ -1,29 +1,29 @@
-- Copyright 2019 X-WRT <dev@x-wrt.com> -- Copyright 2019 X-WRT <dev@x-wrt.com>
m = Map("xwan", translate("Xwan")) m = Map("xwan", translate("Multi-WAN Dialing"))
s = m:section(TypedSection, "xwan", translate("Xwan Settings")) s = m:section(TypedSection, "xwan", translate("Multi-WAN Dialing Settings"))
s.addremove = false s.addremove = false
s.anonymous = true s.anonymous = true
e = s:option(Flag, "enabled", translate("Enable xwan"), translate("multiwan on single interface")) e = s:option(Flag, "enabled", translate("Enable multi-WAN dialing"), translate("Create multiple WAN connections on a single physical interface."))
e.default = e.disabled e.default = e.disabled
e.rmempty = false e.rmempty = false
e = s:option(Value, "number", translate("Number of xwan")) e = s:option(Value, "number", translate("Number of WAN instances"))
e.datatype = "and(uinteger,min(1),max(60))" e.datatype = "and(uinteger,min(1),max(60))"
e.rmempty = false e.rmempty = false
e = s:option(Flag, "balanced", translate("Auto balanced setup")) e = s:option(Flag, "balanced", translate("Configure load balancing automatically"))
e.default = e.disabled e.default = e.disabled
e.rmempty = false e.rmempty = false
e = s:option(DynamicList, "track_ip", translate("Tracking hostname or IP address"), translate("This hostname or IP address will be pinged to determine if the link is up or down. Leave blank to assume interface is always online")) e = s:option(DynamicList, "track_ip", translate("Health check hostnames or IP addresses"), translate("Ping these hosts to determine whether each WAN link is up. Leave empty to treat the links as always online."))
e.datatype = 'host' e.datatype = 'host'
e.default = "" e.default = ""
e.placeholder = "gateway" e.placeholder = "gateway"
e = s:option(ListValue, 'family', translate("Internet Protocol")) e = s:option(ListValue, 'family', translate("IP family"))
e.default = '' e.default = ''
e:value('', translate('IPv4 and IPv6')) e:value('', translate('IPv4 and IPv6'))
e:value('ipv4', translate('IPv4')) e:value('ipv4', translate('IPv4'))