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

This commit is contained in:
github-actions[bot] 2026-06-19 08:54:48 +08:00
parent 5e3fdcdde2
commit ce48633b46
15 changed files with 189 additions and 46 deletions

View File

@ -7,7 +7,7 @@
include $(TOPDIR)/rules.mk
PKG_NAME:=filebrowser
PKG_VERSION:=1.3.3-stable
PKG_VERSION:=1.4.0-stable
PKG_RELEASE=1
ifeq ($(ARCH),aarch64)

View File

@ -2,7 +2,7 @@ include $(TOPDIR)/rules.mk
PKG_NAME:=gecoosac
PKG_VERSION:=2.2.20251015
PKG_RELEASE:=8
PKG_RELEASE:=9
ifeq ($(ARCH),aarch64)
PKG_ARCH:=ac_linux_arm64
@ -49,6 +49,11 @@ define Package/$(PKG_NAME)/conffiles
/etc/gecoosac/
endef
define Build/Prepare
$(call Build/Prepare/Default)
$(CP) ../LICENSE $(PKG_BUILD_DIR)/LICENSE
endef
define Build/Compile
endef

View File

@ -43,6 +43,29 @@ is_abs_path() {
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() {
case "$1" in
""|*[!0-9]*) return 1 ;;
@ -175,7 +198,11 @@ generate_default_cert() {
}
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 "$crt_file" || crt_file="$DEFAULT_CRT_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 stdout "$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
}

View File

@ -1,6 +1,7 @@
#!/bin/sh
changed=0
DEFAULT_UPLOAD_DIR=/tmp/gecoosac/upload/
DEFAULT_CRT_FILE=/etc/gecoosac/tls/gecoosac.crt
DEFAULT_KEY_FILE=/etc/gecoosac/tls/gecoosac.key
OLD_CRT_FILE=/etc/gecoosac/tls/1.crt
@ -21,6 +22,53 @@ set_default() {
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() {
local crt_file key_file
local migrate
@ -46,6 +94,7 @@ migrate_legacy_cert_paths() {
ensure_section
migrate_legacy_cert_paths
normalize_upload_dir
set_default enabled 0
set_default port 60650
set_default isonlyoneprot 1
@ -53,7 +102,7 @@ set_default m_port 8080
set_default https 0
set_default crt_file "$DEFAULT_CRT_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 piddir /var/run/
set_default lang zh

View File

@ -6,7 +6,7 @@ include $(TOPDIR)/rules.mk
PKG_NAME:=luci-app-daede
PKG_VERSION:=1.13.0
PKG_RELEASE:=16
PKG_RELEASE:=17
PKG_MAINTAINER:=kenzok8
PKG_BUILD_DIR:=$(BUILD_DIR)/$(PKG_NAME)

View File

@ -377,10 +377,21 @@ return view.extend({
poll.add(refresh);
refresh();
// First paint reads the cached index (fast). Refresh the index, then
// re-probe once it's current so a freshly published version shows
// without waiting for a poll tick. refresh-index.sh self-throttles.
fs.exec('/usr/share/luci-app-daede/refresh-index.sh', []).then(refresh).catch(function() {});
// Start the potentially slow index refresh without holding a LuCI RPC
// request open, then re-probe promptly when its status changes to done.
const waitIndexRefresh = function(tries) {
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) ===
const geoSettings = (function() {

View File

@ -1,20 +1,28 @@
#!/bin/sh
# Refresh the apk/opkg index for the Updates view. Runs in the FOREGROUND so
# the caller can re-probe once the index is current; throttled to 90s.
# Refresh the apk/opkg index for the Updates view without holding the LuCI RPC
# request open. The view watches STATUS and re-probes as soon as it reads done.
LOCK=/tmp/luci-app-daede.idx.lock
STATUS=/tmp/luci-app-daede.idx.status
if [ -f "$LOCK" ]; then
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
: > "$LOCK"
printf '%s\n' running > "$STATUS"
# -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
elif command -v opkg >/dev/null 2>&1; then
opkg update
fi >/dev/null 2>&1
(
if command -v apk >/dev/null 2>&1; then
flock -n /tmp/luci-app-daede.apk.lock apk update
elif command -v opkg >/dev/null 2>&1; then
opkg update
fi
printf '%s\n' done > "$STATUS"
) >/dev/null 2>&1 </dev/null &
exit 0

View File

@ -20,6 +20,7 @@
"/tmp/luci-app-daede.pkg-daed.log": [ "read" ],
"/tmp/luci-app-daede.pkg-luci-app-daede.log": [ "read" ],
"/tmp/luci-app-daede.backup.log": [ "read" ],
"/tmp/luci-app-daede.idx.status": [ "read" ],
"/bin/pidof dae": [ "exec" ],
"/bin/pidof daed": [ "exec" ],
"/usr/bin/dae validate -c /tmp/dae-validate.dae": [ "exec" ],

View File

@ -6,8 +6,8 @@
include $(TOPDIR)/rules.mk
PKG_NAME:=luci-app-gecoosac
PKG_VERSION:=2.2
PKG_RELEASE:=9
PKG_VERSION:=2.3
PKG_RELEASE:=10
LUCI_TITLE:=LuCI Support for gecoosac
LUCI_DEPENDS:=+gecoosac

View File

@ -30,6 +30,21 @@ function validPort(value, 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) {
const service = status && status.gecoosac;
const instances = service && service.instances;
@ -167,19 +182,25 @@ return view.extend({
o.placeholder = DEFAULT_CRT_FILE;
o.default = DEFAULT_CRT_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.placeholder = DEFAULT_KEY_FILE;
o.default = DEFAULT_KEY_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.default = DEFAULT_UPLOAD_DIR;
o.datatype = 'directory';
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.placeholder = DEFAULT_DB_DIR;

View File

@ -51,8 +51,11 @@ msgstr "指定 key 证书文件"
msgid "Upload dir path"
msgstr "上传目录"
msgid "The path to upload AP upgrade firmware"
msgstr "存放AP升级固件的路径"
msgid "Upload AP upgrade firmware here. For safe cleanup, use an absolute path ending with /gecoosac/upload, for example /tmp/gecoosac/upload/."
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"
msgstr "数据库目录"

View File

@ -9,7 +9,7 @@ include $(TOPDIR)/rules.mk
PKG_NAME:=luci-app-xwan
PKG_VERSION:=1.0.0
PKG_RELEASE:=1
PKG_RELEASE:=2
PKG_LICENSE:=GPLv3
PKG_LICENSE_FILES:=LICENSE

View File

@ -5,7 +5,7 @@ module("luci.controller.xwan", package.seeall)
function index()
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.acl_depends = { "luci-app-xwan" }
end

View File

@ -1,20 +1,38 @@
msgid ""
msgstr "Content-Type: text/plain; charset=UTF-8\n"
msgid "Xwan"
msgstr "多拨"
msgid "Multi-WAN Dialing"
msgstr "单线多拨"
msgid "Xwan Settings"
msgstr "多拨设置"
msgid "Multi-WAN Dialing Settings"
msgstr "单线多拨设置"
msgid "Enable xwan"
msgstr "启多拨"
msgid "Enable multi-WAN dialing"
msgstr "启多拨"
msgid "multiwan on single interface"
msgstr "单网口多拨号"
msgid "Create multiple WAN connections on a single physical interface."
msgstr "在同一个物理接口上创建多个 WAN 连接。"
msgid "Number of xwan"
msgstr "多拨"
msgid "Number of WAN instances"
msgstr "多拨数量"
msgid "Auto balanced setup"
msgstr "自动负载均衡和叠加"
msgid "Configure load balancing automatically"
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"

View File

@ -1,29 +1,29 @@
-- 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.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.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.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.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.default = ""
e.placeholder = "gateway"
e = s:option(ListValue, 'family', translate("Internet Protocol"))
e = s:option(ListValue, 'family', translate("IP family"))
e.default = ''
e:value('', translate('IPv4 and IPv6'))
e:value('ipv4', translate('IPv4'))